#include"System4x.h" #include"embed_util.h" /** * jichi 12/26/2013: Rance hook * * ランス01 光をもとめて: /HSN4:-14@5506A9 * - addr: 5572265 (0x5596a9) * - off: 4 * - split: 4294967272 (0xffffffe8 = -0x18) * - type: 1041 (0x411) * * the above code has the same pattern except int3. * 005506a9 |. e8 f2fb1600 call Rance01.006c02a0 ; hook here * 005506ae |. 83c4 0c add esp,0xc * 005506b1 |. 5f pop edi * 005506b2 |. 5e pop esi * 005506b3 |. b0 01 mov al,0x1 * 005506b5 |. 5b pop ebx * 005506b6 \. c2 0400 retn 0x4 * 005506b9 cc int3 * * ランス・クエス� /hsn4:-14@42e08a * 0042e08a |. e8 91ed1f00 call Ranceque.0062ce20 ; hook here * 0042e08f |. 83c4 0c add esp,0xc * 0042e092 |. 5f pop edi * 0042e093 |. 5e pop esi * 0042e094 |. b0 01 mov al,0x1 * 0042e096 |. 5b pop ebx * 0042e097 \. c2 0400 retn 0x4 * 0042e09a cc int3 * * 5/7/2015 イブニクル version 1.0.1 * The hooked function is no longer get called after loading AliceRunPatch.dll. * The hooked function is below. * See also ATcode: http://capita.tistory.com/m/post/256 * 005C40AE CC INT3 * 005C40AF CC INT3 * 005C40B0 53 PUSH EBX * 005C40B1 8B5C24 08 MOV EBX,DWORD PTR SS:[ESP+0x8] * 005C40B5 56 PUSH ESI * 005C40B6 57 PUSH EDI * 005C40B7 8B7B 10 MOV EDI,DWORD PTR DS:[EBX+0x10] * 005C40BA 8BF0 MOV ESI,EAX * 005C40BC 47 INC EDI * 005C40BD 3B7E 0C CMP EDI,DWORD PTR DS:[ESI+0xC] * 005C40C0 76 0F JBE SHORT .005C40D1 * 005C40C2 E8 79F8FFFF CALL .005C3940 * 005C40C7 84C0 TEST AL,AL * 005C40C9 75 06 JNZ SHORT .005C40D1 * 005C40CB 5F POP EDI * 005C40CC 5E POP ESI * 005C40CD 5B POP EBX * 005C40CE C2 0400 RETN 0x4 * 005C40D1 837B 14 10 CMP DWORD PTR DS:[EBX+0x14],0x10 * 005C40D5 72 02 JB SHORT .005C40D9 * 005C40D7 8B1B MOV EBX,DWORD PTR DS:[EBX] * 005C40D9 837E 0C 00 CMP DWORD PTR DS:[ESI+0xC],0x0 * 005C40DD 75 15 JNZ SHORT .005C40F4 * 005C40DF 57 PUSH EDI * 005C40E0 33C0 XOR EAX,EAX * 005C40E2 53 PUSH EBX * 005C40E3 50 PUSH EAX * 005C40E4 E8 B7400D00 CALL .006981A0 * 005C40E9 83C4 0C ADD ESP,0xC * 005C40EC 5F POP EDI * 005C40ED 5E POP ESI * 005C40EE B0 01 MOV AL,0x1 * 005C40F0 5B POP EBX * 005C40F1 C2 0400 RETN 0x4 * 005C40F4 8B46 08 MOV EAX,DWORD PTR DS:[ESI+0x8] * 005C40F7 57 PUSH EDI * 005C40F8 53 PUSH EBX * 005C40F9 50 PUSH EAX * 005C40FA E8 A1400D00 CALL .006981A0 ; jichi: call here * 005C40FF 83C4 0C ADD ESP,0xC * 005C4102 5F POP EDI * 005C4103 5E POP ESI * 005C4104 B0 01 MOV AL,0x1 * 005C4106 5B POP EBX * 005C4107 C2 0400 RETN 0x4 * 005C410A CC INT3 * 005C410B CC INT3 * 005C410C CC INT3 * */ static bool InsertSystem43OldHook(ULONG startAddress, ULONG stopAddress, LPCSTR hookName) { // i.e. 83c40c5f5eb0015bc20400cccc without leading 0xe8 //const BYTE ins[] = { // 005506a9 |. e8 f2fb1600 call rance01.006c02a0 ; hook here // 0x83,0xc4, 0x0c, // 005506ae |. 83c4 0c add esp,0xc // 0x5f, // 005506b1 |. 5f pop edi // 0x5e, // 005506b2 |. 5e pop esi // 0xb0, 0x01, // 005506b3 |. b0 01 mov al,0x1 // 0x5b, // 005506b5 |. 5b pop ebx // 0xc2, 0x04,0x00, // 005506b6 \. c2 0400 retn 0x4 // 0xcc, 0xcc // patching a few int3 to make sure that this is at the end of the code block //}; //enum { addr_offset = -5 }; // the function call before the ins //ULONG addr = processStartAddress; //- sizeof(ins); ////addr = 0x5506a9; //enum { near_call = 0xe8 }; // intra-module function call //do { // //addr += sizeof(ins); // so that each time return diff address -- not needed // ULONG range = min(processStopAddress - addr, MAX_REL_ADDR); // addr = MemDbg::findBytes(ins, sizeof(ins), addr, addr + range); // if (!addr) { // //ITH_MSG(L"failed"); // ConsoleOutput("System43: pattern not found"); // return false; // } // addr += addr_offset; //} while(near_call != *(BYTE *)addr); // function call //GROWL_DWORD(addr); // i.e. 83c40c5f5eb0015bc20400cccc without leading 0xe8 const BYTE bytes[] = { 0xe8, XX4, // 005506a9 |. e8 f2fb1600 call rance01.006c02a0 ; hook here 0x83,0xc4, 0x0c, // 005506ae |. 83c4 0c add esp,0xc XX, // 005506b1 |. 5f pop edi ; Artikash 2/9/2019 change these to wildcards: Evenicle 2 has the pops and moves switched order XX, // 005506b2 |. 5e pop esi XX, XX, // 005506b3 |. b0 01 mov al,0x1 0x5b, // 005506b5 |. 5b pop ebx 0xc2, 0x04,0x00, // 005506b6 \. c2 0400 retn 0x4 0xcc, 0xcc // patching a few int3 to make sure that this is at the end of the code block }; enum { addr_offset = 0 }; ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress); //GROWL_DWORD(addr); if (!addr) { ConsoleOutput("System43: pattern not found"); return false; } HookParam hp; hp.address = addr + addr_offset; hp.offset=get_stack(1); hp.split = get_reg(regs::esp); hp.type = NO_CONTEXT|USING_SPLIT|USING_STRING|EMBED_ABLE|EMBED_BEFORE_SIMPLE|EMBED_AFTER_NEW|EMBED_DYNA_SJIS; ConsoleOutput("INSERT System43"); ConsoleOutput("System43: disable GDI hooks"); // disable hooking to TextOutA, which is cached return NewHook(hp, hookName); } /** 5/13/2015 Add new hook for System43 engine that has no garbage threads and can detect character name * Sample game: Evenicle * See: http://capita.tistory.com/m/post/256 * * 004EEA6C CC INT3 * 004EEA6D CC INT3 * 004EEA6E CC INT3 * 004EEA6F CC INT3 * 004EEA70 6A FF PUSH -0x1 * 004EEA72 68 E8267000 PUSH .007026E8 * 004EEA77 64:A1 00000000 MOV EAX,DWORD PTR FS:[0] * 004EEA7D 50 PUSH EAX * 004EEA7E 83EC 20 SUB ESP,0x20 * 004EEA81 A1 DCC47700 MOV EAX,DWORD PTR DS:[0x77C4DC] * 004EEA86 33C4 XOR EAX,ESP * 004EEA88 894424 1C MOV DWORD PTR SS:[ESP+0x1C],EAX * 004EEA8C 53 PUSH EBX * 004EEA8D 55 PUSH EBP * 004EEA8E 56 PUSH ESI * 004EEA8F 57 PUSH EDI * 004EEA90 A1 DCC47700 MOV EAX,DWORD PTR DS:[0x77C4DC] * 004EEA95 33C4 XOR EAX,ESP * 004EEA97 50 PUSH EAX * 004EEA98 8D4424 34 LEA EAX,DWORD PTR SS:[ESP+0x34] * 004EEA9C 64:A3 00000000 MOV DWORD PTR FS:[0],EAX * 004EEAA2 8B4424 44 MOV EAX,DWORD PTR SS:[ESP+0x44] * 004EEAA6 8BF1 MOV ESI,ECX * 004EEAA8 E8 8346FBFF CALL .004A3130 * 004EEAAD 8BE8 MOV EBP,EAX * 004EEAAF 33DB XOR EBX,EBX * 004EEAB1 3BEB CMP EBP,EBX * 004EEAB3 75 07 JNZ SHORT .004EEABC * 004EEAB5 32C0 XOR AL,AL * 004EEAB7 E9 92000000 JMP .004EEB4E * 004EEABC 8B06 MOV EAX,DWORD PTR DS:[ESI] * 004EEABE 8B10 MOV EDX,DWORD PTR DS:[EAX] * 004EEAC0 8BCE MOV ECX,ESI * 004EEAC2 FFD2 CALL EDX * 004EEAC4 8BC8 MOV ECX,EAX * 004EEAC6 C74424 28 0F0000>MOV DWORD PTR SS:[ESP+0x28],0xF * 004EEACE 895C24 24 MOV DWORD PTR SS:[ESP+0x24],EBX * 004EEAD2 885C24 14 MOV BYTE PTR SS:[ESP+0x14],BL * 004EEAD6 8D71 01 LEA ESI,DWORD PTR DS:[ECX+0x1] * 004EEAD9 8DA424 00000000 LEA ESP,DWORD PTR SS:[ESP] * 004EEAE0 8A11 MOV DL,BYTE PTR DS:[ECX] * 004EEAE2 41 INC ECX * 004EEAE3 3AD3 CMP DL,BL * 004EEAE5 ^75 F9 JNZ SHORT .004EEAE0 * 004EEAE7 2BCE SUB ECX,ESI * 004EEAE9 50 PUSH EAX * 004EEAEA 8BF9 MOV EDI,ECX * 004EEAEC 8D7424 18 LEA ESI,DWORD PTR SS:[ESP+0x18] * 004EEAF0 E8 CB27F1FF CALL .004012C0 * 004EEAF5 8B7C24 48 MOV EDI,DWORD PTR SS:[ESP+0x48] * 004EEAF9 895C24 3C MOV DWORD PTR SS:[ESP+0x3C],EBX * 004EEAFD 8B75 3C MOV ESI,DWORD PTR SS:[EBP+0x3C] * 004EEB00 E8 1B4A0100 CALL .00503520 * 004EEB05 8BF8 MOV EDI,EAX * 004EEB07 8DB7 E4000000 LEA ESI,DWORD PTR DS:[EDI+0xE4] * 004EEB0D 8D4424 14 LEA EAX,DWORD PTR SS:[ESP+0x14] * 004EEB11 8BD6 MOV EDX,ESI * 004EEB13 E8 985CF1FF CALL .004047B0 * 004EEB18 BD 10000000 MOV EBP,0x10 * 004EEB1D 84C0 TEST AL,AL * 004EEB1F 75 18 JNZ SHORT .004EEB39 * 004EEB21 895E 10 MOV DWORD PTR DS:[ESI+0x10],EBX * 004EEB24 396E 14 CMP DWORD PTR DS:[ESI+0x14],EBP * 004EEB27 72 02 JB SHORT .004EEB2B * 004EEB29 8B36 MOV ESI,DWORD PTR DS:[ESI] * 004EEB2B 8D4424 14 LEA EAX,DWORD PTR SS:[ESP+0x14] * 004EEB2F 50 PUSH EAX * 004EEB30 8BCF MOV ECX,EDI * 004EEB32 881E MOV BYTE PTR DS:[ESI],BL * 004EEB34 E8 67CB0100 CALL .0050B6A0 ; jichi: ATcode modified here, text is on the top of the stack * 004EEB39 396C24 28 CMP DWORD PTR SS:[ESP+0x28],EBP * 004EEB3D 72 0D JB SHORT .004EEB4C * 004EEB3F 8B4C24 14 MOV ECX,DWORD PTR SS:[ESP+0x14] * 004EEB43 51 PUSH ECX * 004EEB44 E8 42DC1900 CALL .0068C78B * 004EEB49 83C4 04 ADD ESP,0x4 * 004EEB4C B0 01 MOV AL,0x1 * 004EEB4E 8B4C24 34 MOV ECX,DWORD PTR SS:[ESP+0x34] * 004EEB52 64:890D 00000000 MOV DWORD PTR FS:[0],ECX * 004EEB59 59 POP ECX * 004EEB5A 5F POP EDI * 004EEB5B 5E POP ESI * 004EEB5C 5D POP EBP * 004EEB5D 5B POP EBX * 004EEB5E 8B4C24 1C MOV ECX,DWORD PTR SS:[ESP+0x1C] * 004EEB62 33CC XOR ECX,ESP * 004EEB64 E8 9CD61900 CALL .0068C205 * 004EEB69 83C4 2C ADD ESP,0x2C * 004EEB6C C3 RETN * 004EEB6D CC INT3 * 004EEB6E CC INT3 * * Actual binary patch for Evenicle exe: http://capita.tistory.com/m/post/256 * {005E393B(EB), 004EEB34(E9 13 B6 21 00), 005C71E0(E9 48 2F 14 00), 005B6494(E9 10 3D 15 00), 0070A10F(90 90 90 90 90 E8 F7 9F EB FF E9 C7 D0 EB FF 90 90 90 90 90 E8 78 15 E0 FF E9 0C 4A DE FF 50 8B 87 B0 00 00 00 66 81 38 84 00 75 0E 83 78 EA 5B 75 08 E8 A2 00 00 00 58 EB C6 58 EB C8 50 52 BA E0 0B 7A 00 60 89 D7 8B 74 E4 28 B9 06 00 00 00 F3 A5 61 8B 44 E4 08 8B 40 10 85 C0 74 29 8B 44 E4 08 8B 40 14 83 F8 0F 75 08 89 54 E4 08 5A 58 EB 9D 8D 42 20 60 89 C7 8B 32 8B 4A 14 83 C1 09 F3 A4 61 89 02 EB E3 5A 58 EB 89 90 90 90 90 90 E8 6C 9F EB FF E9 F0 C2 EA FF 50 8B 44 E4 04 83 78 0C 01 76 31 8B 87 84 02 00 00 66 83 78 FC 46 75 24 83 78 F8 22 74 16 83 78 F8 13 75 18 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 E8 06 00 00 00 58 EB B5 58 EB B7 60 8B 74 E4 28 BF E0 0B 7A 00 89 7C E4 28 B9 0C 00 00 00 F3 A5 61 C3)} * * ATcode: FORCEFONT(5),ENCODEKOR,FONT(Malgun Gothic,-13),HOOK(0x0070A10F,TRANS([[ESP]+0x8],LEN([ESP]+0XC),PTRCHEAT),RETNPOS(COPY)),HOOK(0x0070A11E,TRANS([ESP],SMSTR(IGNORE)),RETNPOS(COPY)),HOOK(0x0070A19A,TRANS([[ESP]+0x8],LEN([ESP]+0XC),PTRCHEAT),RETNPOS(COPY)) * FilterCode: DenyWord{CUT(2)},FixLine{},KoFilter{},DumpText{},CustomDic{CDic},CustomScript{Write,Pass(-1),Cache} * * The second hooked address pointed to the text address. * The logic here is simplify buffer the read text, and replace the text by zero * Then translate/paint them together. * Several variables near the text address is used to check if the text is finished or not. * * Function immediately before patched code: * 0070A09E CC INT3 * 0070A09F CC INT3 * 0070A0A0 6A FF PUSH -0x1 * 0070A0A2 68 358A7000 PUSH .00708A35 * 0070A0A7 64:A1 00000000 MOV EAX,DWORD PTR FS:[0] * 0070A0AD 50 PUSH EAX * 0070A0AE 51 PUSH ECX * 0070A0AF 56 PUSH ESI * 0070A0B0 A1 DCC47700 MOV EAX,DWORD PTR DS:[0x77C4DC] * 0070A0B5 33C4 XOR EAX,ESP * 0070A0B7 50 PUSH EAX * 0070A0B8 8D4424 0C LEA EAX,DWORD PTR SS:[ESP+0xC] * 0070A0BC 64:A3 00000000 MOV DWORD PTR FS:[0],EAX * 0070A0C2 C74424 14 000000>MOV DWORD PTR SS:[ESP+0x14],0x0 * 0070A0CA A1 54D17900 MOV EAX,DWORD PTR DS:[0x79D154] * 0070A0CF 8B08 MOV ECX,DWORD PTR DS:[EAX] * 0070A0D1 50 PUSH EAX * 0070A0D2 51 PUSH ECX * 0070A0D3 8D7424 10 LEA ESI,DWORD PTR SS:[ESP+0x10] * 0070A0D7 E8 6416F8FF CALL .0068B740 * 0070A0DC A1 54D17900 MOV EAX,DWORD PTR DS:[0x79D154] * 0070A0E1 50 PUSH EAX * 0070A0E2 E8 A426F8FF CALL .0068C78B * 0070A0E7 83C4 04 ADD ESP,0x4 * 0070A0EA 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+0xC] * 0070A0EE 64:890D 00000000 MOV DWORD PTR FS:[0],ECX * 0070A0F5 59 POP ECX * 0070A0F6 5E POP ESI * 0070A0F7 83C4 10 ADD ESP,0x10 * 0070A0FA C3 RETN * 0070A0FB C705 C4C17900 64>MOV DWORD PTR DS:[0x79C1C4],.0070B664 * 0070A105 B9 C4C17900 MOV ECX,.0079C1C4 * 0070A10A ^E9 0722F8FF JMP .0068C316 * * Patched code: * 0070A10F 90 NOP ; jichi: ATcode hooked here * 0070A110 90 NOP * 0070A111 90 NOP * 0070A112 90 NOP * 0070A113 90 NOP * 0070A114 E8 F79FEBFF CALL .005C4110 * 0070A119 ^E9 C7D0EBFF JMP .005C71E5 * 0070A11E 90 NOP * 0070A11F 90 NOP * 0070A120 90 NOP * 0070A121 90 NOP * 0070A122 90 NOP * 0070A123 E8 7815E0FF CALL .0050B6A0 ; jichi: call the original function for hookpoint #2 * 0070A128 ^E9 0C4ADEFF JMP .004EEB39 ; jichi: come back to hookpoint#2 * 0070A12D 50 PUSH EAX ; jichi: this is for hookpoint #3, translate the text before send it to paint * 0070A12E 8B87 B0000000 MOV EAX,DWORD PTR DS:[EDI+0xB0] * 0070A134 66:8138 8400 CMP WORD PTR DS:[EAX],0x84 * 0070A139 75 0E JNZ SHORT .0070A149 * 0070A13B 8378 EA 5B CMP DWORD PTR DS:[EAX-0x16],0x5B * 0070A13F 75 08 JNZ SHORT .0070A149 * 0070A141 E8 A2000000 CALL .0070A1E8 * 0070A146 58 POP EAX * 0070A147 ^EB C6 JMP SHORT .0070A10F * 0070A149 58 POP EAX * 0070A14A ^EB C8 JMP SHORT .0070A114 * 0070A14C 50 PUSH EAX ; jichi: hookpoint#2 jmp here, text address is in [esp] * 0070A14D 52 PUSH EDX * 0070A14E BA E00B7A00 MOV EDX,.007A0BE0 ; jichi: 007A0BE0 points to unused zeroed memory * 0070A153 60 PUSHAD ; jichi esp -= 0x20, now, esp[0x28] is text address, esp[0x24] = eax, and esp[0x20] = edx * 0070A154 89D7 MOV EDI,EDX ; set 007A0BE0 as the target buffer to save text, edx is never modified * 0070A156 8B74E4 28 MOV ESI,DWORD PTR SS:[ESP+0x28] ; set source text as target * 0070A15A B9 06000000 MOV ECX,0x6 ; move for 6 bytes * 0070A15F F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] * 0070A161 61 POPAD ; finished saving text, now [esp] is old edx, esp[0x4] is old eax, esp[0x8] is old text address * 0070A162 8B44E4 08 MOV EAX,DWORD PTR SS:[ESP+0x8] ; eax = original text address * 0070A166 8B40 10 MOV EAX,DWORD PTR DS:[EAX+0x10] ; eax = text[0x10] * 0070A169 85C0 TEST EAX,EAX ; if end of text, * 0070A16B 74 29 JE SHORT .0070A196 ; jump if eax is zero, comeback to hookpoint and ignore it * 0070A16D 8B44E4 08 MOV EAX,DWORD PTR SS:[ESP+0x8] ; otherwise, if eax is not zero * 0070A171 8B40 14 MOV EAX,DWORD PTR DS:[EAX+0x14] ; eax = text[0x14] * 0070A174 83F8 0F CMP EAX,0xF ; jichi: compare text[0x14] with 0xf * 0070A177 75 08 JNZ SHORT .0070A181 ; jump if not zero leaving text not modified, other continue and modify the text * 0070A179 8954E4 08 MOV DWORD PTR SS:[ESP+0x8],EDX ; override esp+8 with edx, i.e. override text address by new text address and do translation * 0070A17D 5A POP EDX * 0070A17E 58 POP EAX ; jichi: restore edx and eax, now esp is back to normal. [esp] is the new text address * 0070A17F ^EB 9D JMP SHORT .0070A11E ; jichi: jump to the top of the hooked place (nop) and do translation before coming back * 0070A181 8D42 20 LEA EAX,DWORD PTR DS:[EDX+0x20] ; text is not modified, esp[0x8] is the text address, edx is the modified buffer, eax = buffer[0x20] address * 0070A184 60 PUSHAD ; jichi: esp[0x28] is now the text address * 0070A185 89C7 MOV EDI,EAX ; jichi: edx[0x20] is the target * 0070A187 8B32 MOV ESI,DWORD PTR DS:[EDX] ; jichi: edx is the source * 0070A189 8B4A 14 MOV ECX,DWORD PTR DS:[EDX+0x14] * 0070A18C 83C1 09 ADD ECX,0x9 ; move for [edx+0x14]+0x9 time * 0070A18F F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] ; jichi: shift text by 0x14 dword ptr * 0070A191 61 POPAD ; jichi: now esp[0x8] is the text address * 0070A192 8902 MOV DWORD PTR DS:[EDX],EAX ; eax is the new text address (edx+0x20), move the address to beginning of buffer ([edx]), i.e. edx is pointed to zero memory now * 0070A194 ^EB E3 JMP SHORT .0070A179 ; come bback to modify the text address * 0070A196 5A POP EDX * 0070A197 58 POP EAX * 0070A198 ^EB 89 JMP SHORT .0070A123 ; jichi: come back to call * 0070A19A 90 NOP * 0070A19B 90 NOP * 0070A19C 90 NOP * 0070A19D 90 NOP * 0070A19E 90 NOP * 0070A19F E8 6C9FEBFF CALL .005C4110 * 0070A1A4 ^E9 F0C2EAFF JMP .005B6499 * 0070A1A9 50 PUSH EAX ; jichi: from hookpoint #4 * 0070A1AA 8B44E4 04 MOV EAX,DWORD PTR SS:[ESP+0x4] ; jichi: move top of the old stack address to eax * 0070A1AE 8378 0C 01 CMP DWORD PTR DS:[EAX+0xC],0x1 * 0070A1B2 76 31 JBE SHORT .0070A1E5 ; jichi: jump to leave if text[0xc] <= 0x1 * 0070A1B4 8B87 84020000 MOV EAX,DWORD PTR DS:[EDI+0x284] * 0070A1BA 66:8378 FC 46 CMP WORD PTR DS:[EAX-0x4],0x46 * 0070A1BF 75 24 JNZ SHORT .0070A1E5 * 0070A1C1 8378 F8 22 CMP DWORD PTR DS:[EAX-0x8],0x22 * 0070A1C5 74 16 JE SHORT .0070A1DD * 0070A1C7 8378 F8 13 CMP DWORD PTR DS:[EAX-0x8],0x13 * 0070A1CB 75 18 JNZ SHORT .0070A1E5 * 0070A1CD 90 NOP * 0070A1CE 90 NOP * 0070A1CF 90 NOP * 0070A1D0 90 NOP * 0070A1D1 90 NOP * 0070A1D2 90 NOP * 0070A1D3 90 NOP * 0070A1D4 90 NOP * 0070A1D5 90 NOP * 0070A1D6 90 NOP * 0070A1D7 90 NOP * 0070A1D8 90 NOP * 0070A1D9 90 NOP * 0070A1DA 90 NOP * 0070A1DB 90 NOP * 0070A1DC 90 NOP * 0070A1DD E8 06000000 CALL .0070A1E8 * 0070A1E2 58 POP EAX * 0070A1E3 ^EB B5 JMP SHORT .0070A19A * 0070A1E5 58 POP EAX * 0070A1E6 ^EB B7 JMP SHORT .0070A19F * 0070A1E8 60 PUSHAD * 0070A1E9 8B74E4 28 MOV ESI,DWORD PTR SS:[ESP+0x28] * 0070A1ED BF E00B7A00 MOV EDI,.007A0BE0 * 0070A1F2 897CE4 28 MOV DWORD PTR SS:[ESP+0x28],EDI * 0070A1F6 B9 0C000000 MOV ECX,0xC * 0070A1FB F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] * 0070A1FD 61 POPAD * 0070A1FE C3 RETN * 0070A1FF 0000 ADD BYTE PTR DS:[EAX],AL * 0070A201 0000 ADD BYTE PTR DS:[EAX],AL * 0070A203 0000 ADD BYTE PTR DS:[EAX],AL * * Modified places: * * 005E391C CC INT3 * 005E391D CC INT3 * 005E391E CC INT3 * 005E391F CC INT3 * 005E3920 55 PUSH EBP * 005E3921 8BEC MOV EBP,ESP * 005E3923 83E4 C0 AND ESP,0xFFFFFFC0 * 005E3926 83EC 34 SUB ESP,0x34 * 005E3929 53 PUSH EBX * 005E392A 8B5D 08 MOV EBX,DWORD PTR SS:[EBP+0x8] * 005E392D 817B 04 00010000 CMP DWORD PTR DS:[EBX+0x4],0x100 * 005E3934 56 PUSH ESI * 005E3935 57 PUSH EDI * 005E3936 8B7D 0C MOV EDI,DWORD PTR SS:[EBP+0xC] * 005E3939 8BF0 MOV ESI,EAX * 005E393B EB 67 JMP SHORT .005E39A4 ; jichi: here modified point#1, change to always jump to 5e39a4, when enabled it will change font size * 005E393D 8D4424 28 LEA EAX,DWORD PTR SS:[ESP+0x28] * 005E3941 50 PUSH EAX * 005E3942 8D4C24 30 LEA ECX,DWORD PTR SS:[ESP+0x30] * * 004EEA6E CC INT3 * 004EEA6F CC INT3 * 004EEA70 6A FF PUSH -0x1 * 004EEA72 68 E8267000 PUSH .007026E8 * 004EEA77 64:A1 00000000 MOV EAX,DWORD PTR FS:[0] * 004EEA7D 50 PUSH EAX * 004EEA7E 83EC 20 SUB ESP,0x20 * 004EEA81 A1 DCC47700 MOV EAX,DWORD PTR DS:[0x77C4DC] * 004EEA86 33C4 XOR EAX,ESP * 004EEA88 894424 1C MOV DWORD PTR SS:[ESP+0x1C],EAX * 004EEA8C 53 PUSH EBX * 004EEA8D 55 PUSH EBP * 004EEA8E 56 PUSH ESI * 004EEA8F 57 PUSH EDI * 004EEA90 A1 DCC47700 MOV EAX,DWORD PTR DS:[0x77C4DC] * 004EEA95 33C4 XOR EAX,ESP * 004EEA97 50 PUSH EAX * 004EEA98 8D4424 34 LEA EAX,DWORD PTR SS:[ESP+0x34] * 004EEA9C 64:A3 00000000 MOV DWORD PTR FS:[0],EAX * 004EEAA2 8B4424 44 MOV EAX,DWORD PTR SS:[ESP+0x44] * 004EEAA6 8BF1 MOV ESI,ECX * 004EEAA8 E8 8346FBFF CALL .004A3130 * 004EEAAD 8BE8 MOV EBP,EAX * 004EEAAF 33DB XOR EBX,EBX * 004EEAB1 3BEB CMP EBP,EBX * 004EEAB3 75 07 JNZ SHORT .004EEABC * 004EEAB5 32C0 XOR AL,AL * 004EEAB7 E9 92000000 JMP .004EEB4E * 004EEABC 8B06 MOV EAX,DWORD PTR DS:[ESI] * 004EEABE 8B10 MOV EDX,DWORD PTR DS:[EAX] * 004EEAC0 8BCE MOV ECX,ESI * 004EEAC2 FFD2 CALL EDX * 004EEAC4 8BC8 MOV ECX,EAX * 004EEAC6 C74424 28 0F0000>MOV DWORD PTR SS:[ESP+0x28],0xF * 004EEACE 895C24 24 MOV DWORD PTR SS:[ESP+0x24],EBX * 004EEAD2 885C24 14 MOV BYTE PTR SS:[ESP+0x14],BL * 004EEAD6 8D71 01 LEA ESI,DWORD PTR DS:[ECX+0x1] * 004EEAD9 8DA424 00000000 LEA ESP,DWORD PTR SS:[ESP] * 004EEAE0 8A11 MOV DL,BYTE PTR DS:[ECX] * 004EEAE2 41 INC ECX * 004EEAE3 3AD3 CMP DL,BL * 004EEAE5 ^75 F9 JNZ SHORT .004EEAE0 * 004EEAE7 2BCE SUB ECX,ESI * 004EEAE9 50 PUSH EAX * 004EEAEA 8BF9 MOV EDI,ECX * 004EEAEC 8D7424 18 LEA ESI,DWORD PTR SS:[ESP+0x18] * 004EEAF0 E8 CB27F1FF CALL .004012C0 * 004EEAF5 8B7C24 48 MOV EDI,DWORD PTR SS:[ESP+0x48] * 004EEAF9 895C24 3C MOV DWORD PTR SS:[ESP+0x3C],EBX * 004EEAFD 8B75 3C MOV ESI,DWORD PTR SS:[EBP+0x3C] * 004EEB00 E8 1B4A0100 CALL .00503520 * 004EEB05 8BF8 MOV EDI,EAX * 004EEB07 8DB7 E4000000 LEA ESI,DWORD PTR DS:[EDI+0xE4] * 004EEB0D 8D4424 14 LEA EAX,DWORD PTR SS:[ESP+0x14] * 004EEB11 8BD6 MOV EDX,ESI * 004EEB13 E8 985CF1FF CALL .004047B0 * 004EEB18 BD 10000000 MOV EBP,0x10 * 004EEB1D 84C0 TEST AL,AL * 004EEB1F 75 18 JNZ SHORT .004EEB39 * 004EEB21 895E 10 MOV DWORD PTR DS:[ESI+0x10],EBX * 004EEB24 396E 14 CMP DWORD PTR DS:[ESI+0x14],EBP * 004EEB27 72 02 JB SHORT .004EEB2B * 004EEB29 8B36 MOV ESI,DWORD PTR DS:[ESI] * 004EEB2B 8D4424 14 LEA EAX,DWORD PTR SS:[ESP+0x14] * 004EEB2F 50 PUSH EAX * 004EEB30 8BCF MOV ECX,EDI * 004EEB32 881E MOV BYTE PTR DS:[ESI],BL * 004EEB34 E9 13B62100 JMP .0070A14C ; jichi: here hookpoint#2, name is modified here, scenario and names are here accessed char by char on the top of the stack * 004EEB39 396C24 28 CMP DWORD PTR SS:[ESP+0x28],EBP * 004EEB3D 72 0D JB SHORT .004EEB4C * 004EEB3F 8B4C24 14 MOV ECX,DWORD PTR SS:[ESP+0x14] * 004EEB43 51 PUSH ECX * 004EEB44 E8 42DC1900 CALL .0068C78B * 004EEB49 83C4 04 ADD ESP,0x4 * 004EEB4C B0 01 MOV AL,0x1 * 004EEB4E 8B4C24 34 MOV ECX,DWORD PTR SS:[ESP+0x34] * 004EEB52 64:890D 00000000 MOV DWORD PTR FS:[0],ECX * 004EEB59 59 POP ECX * 004EEB5A 5F POP EDI * 004EEB5B 5E POP ESI * 004EEB5C 5D POP EBP * 004EEB5D 5B POP EBX * 004EEB5E 8B4C24 1C MOV ECX,DWORD PTR SS:[ESP+0x1C] * 004EEB62 33CC XOR ECX,ESP * 004EEB64 E8 9CD61900 CALL .0068C205 * 004EEB69 83C4 2C ADD ESP,0x2C * 004EEB6C C3 RETN * 004EEB6D CC INT3 * 004EEB6E CC INT3 * * 005C70EE CC INT3 * 005C70EF CC INT3 * 005C70F0 83EC 18 SUB ESP,0x18 * 005C70F3 A1 DCC47700 MOV EAX,DWORD PTR DS:[0x77C4DC] * 005C70F8 33C4 XOR EAX,ESP * 005C70FA 894424 14 MOV DWORD PTR SS:[ESP+0x14],EAX * 005C70FE 53 PUSH EBX * 005C70FF 8B5C24 20 MOV EBX,DWORD PTR SS:[ESP+0x20] * 005C7103 55 PUSH EBP * 005C7104 8B6C24 2C MOV EBP,DWORD PTR SS:[ESP+0x2C] * 005C7108 8B45 1C MOV EAX,DWORD PTR SS:[EBP+0x1C] * 005C710B 56 PUSH ESI * 005C710C 8BF2 MOV ESI,EDX * 005C710E 57 PUSH EDI * 005C710F 8BF9 MOV EDI,ECX * 005C7111 897424 10 MOV DWORD PTR SS:[ESP+0x10],ESI * 005C7115 83F8 44 CMP EAX,0x44 * 005C7118 77 7A JA SHORT .005C7194 * 005C711A 0FB680 7C735C00 MOVZX EAX,BYTE PTR DS:[EAX+0x5C737C] * 005C7121 FF2485 60735C00 JMP DWORD PTR DS:[EAX*4+0x5C7360] * 005C7128 8B4B 0C MOV ECX,DWORD PTR DS:[EBX+0xC] * 005C712B 8B4424 30 MOV EAX,DWORD PTR SS:[ESP+0x30] * 005C712F C1E9 02 SHR ECX,0x2 * 005C7132 3BC1 CMP EAX,ECX * 005C7134 73 5E JNB SHORT .005C7194 * 005C7136 837B 0C 00 CMP DWORD PTR DS:[EBX+0xC],0x0 * 005C713A 75 1C JNZ SHORT .005C7158 * 005C713C 33DB XOR EBX,EBX * 005C713E 5F POP EDI * 005C713F 893483 MOV DWORD PTR DS:[EBX+EAX*4],ESI * 005C7142 5E POP ESI * 005C7143 5D POP EBP * 005C7144 B0 01 MOV AL,0x1 * 005C7146 5B POP EBX * 005C7147 8B4C24 14 MOV ECX,DWORD PTR SS:[ESP+0x14] * 005C714B 33CC XOR ECX,ESP * 005C714D E8 B3500C00 CALL .0068C205 * 005C7152 83C4 18 ADD ESP,0x18 * 005C7155 C2 0C00 RETN 0xC * 005C7158 8B5B 08 MOV EBX,DWORD PTR DS:[EBX+0x8] * 005C715B 5F POP EDI * 005C715C 893483 MOV DWORD PTR DS:[EBX+EAX*4],ESI * 005C715F 5E POP ESI * 005C7160 5D POP EBP * 005C7161 B0 01 MOV AL,0x1 * 005C7163 5B POP EBX * 005C7164 8B4C24 14 MOV ECX,DWORD PTR SS:[ESP+0x14] * 005C7168 33CC XOR ECX,ESP * 005C716A E8 96500C00 CALL .0068C205 * 005C716F 83C4 18 ADD ESP,0x18 * 005C7172 C2 0C00 RETN 0xC * 005C7175 F3:0F104424 10 MOVSS XMM0,DWORD PTR SS:[ESP+0x10] * 005C717B 51 PUSH ECX * 005C717C 8B4C24 34 MOV ECX,DWORD PTR SS:[ESP+0x34] * 005C7180 8BC3 MOV EAX,EBX * 005C7182 F3:0F110424 MOVSS DWORD PTR SS:[ESP],XMM0 * 005C7187 E8 14C7FFFF CALL .005C38A0 * 005C718C 84C0 TEST AL,AL * 005C718E 0F85 B2010000 JNZ .005C7346 * 005C7194 5F POP EDI * 005C7195 5E POP ESI * 005C7196 5D POP EBP * 005C7197 32C0 XOR AL,AL * 005C7199 5B POP EBX * 005C719A 8B4C24 14 MOV ECX,DWORD PTR SS:[ESP+0x14] * 005C719E 33CC XOR ECX,ESP * 005C71A0 E8 60500C00 CALL .0068C205 * 005C71A5 83C4 18 ADD ESP,0x18 * 005C71A8 C2 0C00 RETN 0xC * 005C71AB 8B4C24 30 MOV ECX,DWORD PTR SS:[ESP+0x30] * 005C71AF 8D5424 10 LEA EDX,DWORD PTR SS:[ESP+0x10] * 005C71B3 52 PUSH EDX * 005C71B4 8BC3 MOV EAX,EBX * 005C71B6 E8 25C7FFFF CALL .005C38E0 * 005C71BB 84C0 TEST AL,AL * 005C71BD ^74 D5 JE SHORT .005C7194 * 005C71BF 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+0x10] * 005C71C3 8BC7 MOV EAX,EDI * 005C71C5 E8 D6F0FFFF CALL .005C62A0 * 005C71CA 8BD8 MOV EBX,EAX * 005C71CC 8BCE MOV ECX,ESI * 005C71CE 8BC7 MOV EAX,EDI * 005C71D0 E8 CBF0FFFF CALL .005C62A0 * 005C71D5 85DB TEST EBX,EBX * 005C71D7 ^74 BB JE SHORT .005C7194 * 005C71D9 85C0 TEST EAX,EAX * 005C71DB ^74 B7 JE SHORT .005C7194 * 005C71DD 50 PUSH EAX * 005C71DE 8BC3 MOV EAX,EBX * 005C71E0 E8 2BCFFFFF CALL .005C4110 ; original function call * //005C71E0 E9 482F1400 JMP .0070A12D ; jichi: here hookpoint#3, text is modified here, text in [[esp]+0x8]], length in [esp]+0xc * 005C71E5 ^EB A5 JMP SHORT .005C718C * 005C71E7 8B47 08 MOV EAX,DWORD PTR DS:[EDI+0x8] * 005C71EA 8B4F 0C MOV ECX,DWORD PTR DS:[EDI+0xC] * 005C71ED 2BC8 SUB ECX,EAX * 005C71EF C1F9 02 SAR ECX,0x2 * 005C71F2 3BF1 CMP ESI,ECX * 005C71F4 ^73 9E JNB SHORT .005C7194 * 005C71F6 8B34B0 MOV ESI,DWORD PTR DS:[EAX+ESI*4] * 005C71F9 85F6 TEST ESI,ESI * 005C71FB ^74 97 JE SHORT .005C7194 * * 005B640E CC INT3 * 005B640F CC INT3 * 005B6410 53 PUSH EBX * 005B6411 56 PUSH ESI * 005B6412 B9 FCFFFFFF MOV ECX,-0x4 * 005B6417 57 PUSH EDI * 005B6418 8BF8 MOV EDI,EAX * 005B641A 018F B0020000 ADD DWORD PTR DS:[EDI+0x2B0],ECX * 005B6420 8B87 B0020000 MOV EAX,DWORD PTR DS:[EDI+0x2B0] * 005B6426 8B30 MOV ESI,DWORD PTR DS:[EAX] * 005B6428 018F B0020000 ADD DWORD PTR DS:[EDI+0x2B0],ECX * 005B642E 8B87 B0020000 MOV EAX,DWORD PTR DS:[EDI+0x2B0] * 005B6434 8B08 MOV ECX,DWORD PTR DS:[EAX] * 005B6436 8B87 E0010000 MOV EAX,DWORD PTR DS:[EDI+0x1E0] * 005B643C 2B87 DC010000 SUB EAX,DWORD PTR DS:[EDI+0x1DC] * 005B6442 C1F8 02 SAR EAX,0x2 * 005B6445 3BF0 CMP ESI,EAX * 005B6447 73 0D JNB SHORT .005B6456 * 005B6449 8B87 DC010000 MOV EAX,DWORD PTR DS:[EDI+0x1DC] * 005B644F 8B14B0 MOV EDX,DWORD PTR DS:[EAX+ESI*4] * 005B6452 85D2 TEST EDX,EDX * 005B6454 75 13 JNZ SHORT .005B6469 * 005B6456 68 70757200 PUSH .00727570 * 005B645B 8BCF MOV ECX,EDI * 005B645D E8 AEC9FFFF CALL .005B2E10 * 005B6462 83C4 04 ADD ESP,0x4 * 005B6465 5F POP EDI * 005B6466 5E POP ESI * 005B6467 5B POP EBX * 005B6468 C3 RETN * 005B6469 8B9F E0010000 MOV EBX,DWORD PTR DS:[EDI+0x1E0] * 005B646F 2BD8 SUB EBX,EAX * 005B6471 C1FB 02 SAR EBX,0x2 * 005B6474 3BCB CMP ECX,EBX * 005B6476 73 07 JNB SHORT .005B647F * 005B6478 8B0488 MOV EAX,DWORD PTR DS:[EAX+ECX*4] * 005B647B 85C0 TEST EAX,EAX * 005B647D 75 14 JNZ SHORT .005B6493 * 005B647F 51 PUSH ECX * 005B6480 68 A0757200 PUSH .007275A0 * 005B6485 8BCF MOV ECX,EDI * 005B6487 E8 84C9FFFF CALL .005B2E10 * 005B648C 83C4 08 ADD ESP,0x8 * 005B648F 5F POP EDI * 005B6490 5E POP ESI * 005B6491 5B POP EBX * 005B6492 C3 RETN * 005B6493 52 PUSH EDX * 005B6494 E8 77DC0000 CALL .005C4110 * //005B6494 E9 103D1500 JMP .0070A1A9 ; jichi: here hookpoint#4 * 005B6499 84C0 TEST AL,AL * 005B649B 75 16 JNZ SHORT .005B64B3 * 005B649D 68 D4757200 PUSH .007275D4 * 005B64A2 B9 F0757200 MOV ECX,.007275F0 ; ASCII "S_ASSIGN" * 005B64A7 E8 84C8FFFF CALL .005B2D30 * 005B64AC 83C4 04 ADD ESP,0x4 * 005B64AF 5F POP EDI * 005B64B0 5E POP ESI * 005B64B1 5B POP EBX * 005B64B2 C3 RETN * 005B64B3 8B8F B0020000 MOV ECX,DWORD PTR DS:[EDI+0x2B0] * 005B64B9 8931 MOV DWORD PTR DS:[ECX],ESI * 005B64BB 8387 B0020000 04 ADD DWORD PTR DS:[EDI+0x2B0],0x4 * 005B64C2 5F POP EDI * 005B64C3 5E POP ESI * 005B64C4 5B POP EBX * 005B64C5 C3 RETN * 005B64C6 CC INT3 * 005B64C7 CC INT3 * 005B64C8 CC INT3 * * Slightly modified #4 in AliceRunPatch.dll * 101B6C10 5B POP EBX * 101B6C11 59 POP ECX * 101B6C12 C3 RETN * 101B6C13 52 PUSH EDX * 101B6C14 8BC1 MOV EAX,ECX * 101B6C16 E9 4E7D1600 JMP .1031E969 ; jichi: hook here * 101B6C1B 84C0 TEST AL,AL * 101B6C1D 75 18 JNZ SHORT .101B6C37 * 101B6C1F 68 FCB53310 PUSH .1033B5FC * 101B6C24 B9 18B63310 MOV ECX,.1033B618 ; ASCII "S_ASSIGN" * 101B6C29 E8 92B8FFFF CALL .101B24C0 * 101B6C2E 83C4 04 ADD ESP,0x4 * 101B6C31 5F POP EDI * 101B6C32 5E POP ESI * 101B6C33 5D POP EBP * 101B6C34 5B POP EBX * 101B6C35 59 POP ECX * 101B6C36 C3 RETN * 101B6C37 53 PUSH EBX * 101B6C38 56 PUSH ESI * 101B6C39 E8 E29C0100 CALL .101D0920 * 101B6C3E 5F POP EDI * 101B6C3F 5E POP ESI * 101B6C40 5D POP EBP * 101B6C41 5B POP EBX * 101B6C42 59 POP ECX * 101B6C43 C3 RETN * 101B6C44 CC INT3 * 101B6C45 CC INT3 * 101B6C46 CC INT3 * * The function get called to paint string of names for hookpoint #2, text in arg1: * 0050B69E CC INT3 * 0050B69F CC INT3 * 0050B6A0 55 PUSH EBP * 0050B6A1 8BEC MOV EBP,ESP * 0050B6A3 83E4 F8 AND ESP,0xFFFFFFF8 * 0050B6A6 6A FF PUSH -0x1 * 0050B6A8 68 F8277000 PUSH .007027F8 * 0050B6AD 64:A1 00000000 MOV EAX,DWORD PTR FS:[0] * 0050B6B3 50 PUSH EAX * 0050B6B4 83EC 18 SUB ESP,0x18 * 0050B6B7 53 PUSH EBX * 0050B6B8 56 PUSH ESI * 0050B6B9 57 PUSH EDI * 0050B6BA A1 DCC47700 MOV EAX,DWORD PTR DS:[0x77C4DC] * 0050B6BF 33C4 XOR EAX,ESP * 0050B6C1 50 PUSH EAX * 0050B6C2 8D4424 28 LEA EAX,DWORD PTR SS:[ESP+0x28] * 0050B6C6 64:A3 00000000 MOV DWORD PTR FS:[0],EAX * 0050B6CC 8BF9 MOV EDI,ECX * 0050B6CE 57 PUSH EDI * 0050B6CF E8 5CEAFFFF CALL .0050A130 * 0050B6D4 8B45 08 MOV EAX,DWORD PTR SS:[EBP+0x8] * 0050B6D7 6A FF PUSH -0x1 * 0050B6D9 33DB XOR EBX,EBX * 0050B6DB 53 PUSH EBX * 0050B6DC 8DB7 E4000000 LEA ESI,DWORD PTR DS:[EDI+0xE4] * 0050B6E2 50 PUSH EAX * 0050B6E3 E8 886BEFFF CALL .00402270 * 0050B6E8 895C24 14 MOV DWORD PTR SS:[ESP+0x14],EBX * 0050B6EC 895C24 18 MOV DWORD PTR SS:[ESP+0x18],EBX * 0050B6F0 895C24 1C MOV DWORD PTR SS:[ESP+0x1C],EBX * 0050B6F4 56 PUSH ESI * 0050B6F5 8D4C24 18 LEA ECX,DWORD PTR SS:[ESP+0x18] * 0050B6F9 51 PUSH ECX * 0050B6FA 57 PUSH EDI * 0050B6FB 895C24 3C MOV DWORD PTR SS:[ESP+0x3C],EBX * 0050B6FF E8 6C290000 CALL .0050E070 * 0050B704 8D5424 14 LEA EDX,DWORD PTR SS:[ESP+0x14] * 0050B708 8BCF MOV ECX,EDI * 0050B70A E8 B1010000 CALL .0050B8C0 * 0050B70F 8B7424 14 MOV ESI,DWORD PTR SS:[ESP+0x14] * 0050B713 C687 E0000000 01 MOV BYTE PTR DS:[EDI+0xE0],0x1 * 0050B71A 3BF3 CMP ESI,EBX * 0050B71C 74 14 JE SHORT .0050B732 * 0050B71E 8B7C24 18 MOV EDI,DWORD PTR SS:[ESP+0x18] * 0050B722 8BC6 MOV EAX,ESI * 0050B724 E8 7751F0FF CALL .004108A0 * 0050B729 56 PUSH ESI * 0050B72A E8 5C101800 CALL .0068C78B * 0050B72F 83C4 04 ADD ESP,0x4 * 0050B732 8B4C24 28 MOV ECX,DWORD PTR SS:[ESP+0x28] * 0050B736 64:890D 00000000 MOV DWORD PTR FS:[0],ECX * 0050B73D 59 POP ECX * 0050B73E 5F POP EDI * 0050B73F 5E POP ESI * 0050B740 5B POP EBX * 0050B741 8BE5 MOV ESP,EBP * 0050B743 5D POP EBP * 0050B744 C2 0400 RETN 0x4 * 0050B747 CC INT3 * 0050B748 CC INT3 * 0050B749 CC INT3 * 0050B74A CC INT3 * 0050B74B CC INT3 * 0050B74C CC INT3 * * Function get called for hookpoint #3, text in [arg1+0x10], length in arg1+0xc, only for scenario, function call is looped * 005C410D CC INT3 * 005C410E CC INT3 * 005C410F CC INT3 * 005C4110 53 PUSH EBX * 005C4111 8B5C24 08 MOV EBX,DWORD PTR SS:[ESP+0x8] * 005C4115 837B 0C 00 CMP DWORD PTR DS:[EBX+0xC],0x0 * 005C4119 56 PUSH ESI * 005C411A 57 PUSH EDI * 005C411B 8BF0 MOV ESI,EAX * 005C411D 74 07 JE SHORT .005C4126 * 005C411F 8B43 08 MOV EAX,DWORD PTR DS:[EBX+0x8] * 005C4122 85C0 TEST EAX,EAX * 005C4124 75 04 JNZ SHORT .005C412A * 005C4126 33C0 XOR EAX,EAX * 005C4128 EB 0F JMP SHORT .005C4139 * 005C412A 8D50 01 LEA EDX,DWORD PTR DS:[EAX+0x1] * 005C412D 8D49 00 LEA ECX,DWORD PTR DS:[ECX] * 005C4130 8A08 MOV CL,BYTE PTR DS:[EAX] * 005C4132 40 INC EAX * 005C4133 84C9 TEST CL,CL * 005C4135 ^75 F9 JNZ SHORT .005C4130 * 005C4137 2BC2 SUB EAX,EDX * 005C4139 8D78 01 LEA EDI,DWORD PTR DS:[EAX+0x1] * 005C413C 3B7E 0C CMP EDI,DWORD PTR DS:[ESI+0xC] * 005C413F 76 0F JBE SHORT .005C4150 * 005C4141 E8 FAF7FFFF CALL .005C3940 * 005C4146 84C0 TEST AL,AL * 005C4148 75 06 JNZ SHORT .005C4150 * 005C414A 5F POP EDI * 005C414B 5E POP ESI * 005C414C 5B POP EBX * 005C414D C2 0400 RETN 0x4 * 005C4150 837B 0C 00 CMP DWORD PTR DS:[EBX+0xC],0x0 * 005C4154 75 04 JNZ SHORT .005C415A * 005C4156 33C9 XOR ECX,ECX * 005C4158 EB 03 JMP SHORT .005C415D * 005C415A 8B4B 08 MOV ECX,DWORD PTR DS:[EBX+0x8] * 005C415D 837E 0C 00 CMP DWORD PTR DS:[ESI+0xC],0x0 * 005C4161 75 15 JNZ SHORT .005C4178 * 005C4163 57 PUSH EDI * 005C4164 33C0 XOR EAX,EAX * 005C4166 51 PUSH ECX * 005C4167 50 PUSH EAX * 005C4168 E8 33400D00 CALL .006981A0 * 005C416D 83C4 0C ADD ESP,0xC * 005C4170 5F POP EDI * 005C4171 5E POP ESI * 005C4172 B0 01 MOV AL,0x1 * 005C4174 5B POP EBX * 005C4175 C2 0400 RETN 0x4 * 005C4178 8B46 08 MOV EAX,DWORD PTR DS:[ESI+0x8] * 005C417B 57 PUSH EDI * 005C417C 51 PUSH ECX * 005C417D 50 PUSH EAX * 005C417E E8 1D400D00 CALL .006981A0 * 005C4183 83C4 0C ADD ESP,0xC * 005C4186 5F POP EDI * 005C4187 5E POP ESI * 005C4188 B0 01 MOV AL,0x1 * 005C418A 5B POP EBX * 005C418B C2 0400 RETN 0x4 * 005C418E CC INT3 */ static bool InsertSystem43NewHook(ULONG startAddress, ULONG stopAddress, LPCSTR hookName) { const BYTE bytes[] = { 0xe8, XX4, // 004eeb34 e8 67cb0100 call .0050b6a0 ; jichi: hook here, text on the top of the stack 0x39,0x6c,0x24, 0x28, // 004eeb39 396c24 28 cmp dword ptr ss:[esp+0x28],ebp 0x72, 0x0d, // 004eeb3d 72 0d jb short .004eeb4c 0x8b,0x4c,0x24, 0x14, // 004eeb3f 8b4c24 14 mov ecx,dword ptr ss:[esp+0x14] 0x51, // 004eeb43 51 push ecx 0xe8 //, XX4, // 004eeb44 e8 42dc1900 call .0068c78b }; enum { addr_offset = 0 }; ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress); //GROWL_DWORD(addr); if (!addr) { ConsoleOutput("System43+: pattern not found"); return false; } //addr = *(DWORD *)(addr+1) + addr + 5; // change to hook to the actual address of function being called HookParam hp; hp.address = addr; hp.type = NO_CONTEXT|USING_STRING|USING_SPLIT|SPLIT_INDIRECT; //hp.type = NO_CONTEXT|USING_STRING|FIXING_SPLIT; hp.split_index = 0x10; // use [[esp]+0x10] to differentiate name and thread // Only name can be modified here, where the value of split is 0x6, and text in 0x2 ConsoleOutput("INSERT System43+"); ConsoleOutput("System43+: disable GDI hooks"); // disable hooking to TextOutA, which is cached return NewHook(hp, hookName); } bool System43New2Filter(LPVOID data, size_t *size, HookParam *) { auto text = reinterpret_cast(data); auto len = reinterpret_cast(size); CharReplacer(text, len, '\n', ' '); if (cpp_strnstr(text, "${", *len)) { StringFilterBetween(text, len, "${", 3, "}", 1); } return true; } bool InsertSystem43New2Hook() { /* * Sample games: * https://vndb.org/r84067 */ const BYTE bytes[] = { 0xC7, 0x46, 0x10, XX4, // mov [esi+10],00000000 0x72, 0x02, // jb dohnadohna.exe+1BFA7E 0x8B, 0x36, // mov esi,[esi] 0x8B, 0x4C, 0x24, 0x14, // mov ecx,[esp+14] 0x57, // push edi 0xC6, 0x06, 0x00 // mov byte ptr [esi],00 << hook here }; enum { addr_offset = sizeof(bytes) - 3 }; ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR); ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range); if (!addr) { ConsoleOutput("System43new: pattern not found"); return false; } HookParam hp; hp.address = addr + addr_offset; hp.offset=get_reg(regs::edx); hp.split = get_reg(regs::esp); hp.type = NO_CONTEXT | USING_STRING | USING_SPLIT; hp.filter_fun = System43New2Filter; ConsoleOutput("INSERT System43new"); return NewHook(hp, "System43new"); } bool InsertSystem43Hook() { if (InsertSystem43New2Hook()) return true; //bool patched = Util::CheckFile(L"AliceRunPatch.dll"); bool patched = ::GetModuleHandleA("AliceRunPatch.dll"); // Insert new hook first bool ok = InsertSystem43OldHook(processStartAddress, processStopAddress, patched ? "AliceRunPatch43" : "System43"); ok = InsertSystem43NewHook(processStartAddress, processStopAddress, "System43+") || ok; return ok; } namespace { // unnamed struct TextArgument // first argument of the scenario hook { ULONG *unknown[2]; LPCSTR text; int size; // text data size including '\0', length = size - 1 int capacity; ULONG split; bool isValid() const { return size <= capacity && size >= 4 && text && ::strlen(text) + 1 == size // skip translating single text //&& !Util::allAscii(text) && (UINT8)text[0] > 127 && (UINT8)text[size - 3] > 127 // skip text beginning / ending with ascii && !::strstr(text, "\x81\x5e"); // "/" } }; enum : UINT64 { djb2_hash0 = 5381 }; inline UINT64 djb2(const UINT8 *str, UINT64 hash = djb2_hash0) { UINT8 c; while ((c = *str++)) hash = ((hash << 5) + hash) + c; // hash * 33 + c return hash; }inline UINT64 djb2_n2(const char* str, size_t len, UINT64 hash = djb2_hash0) { while (len--) hash = ((hash << 5) + hash) + (*str++); // hash * 33 + c return hash; } inline UINT64 hashByteArraySTD(const std::string& b, UINT64 h = djb2_hash0) { return djb2_n2(b.c_str(), b.size(), h); } inline UINT64 hashCharArray(const void *lp) { return djb2(reinterpret_cast(lp)); } namespace ScenarioHook { namespace Private { bool isOtherText(LPCSTR text) { static const char *s[] = { "\x82\xa2\x82\xa2\x82\xa6" /* いいえ */ , "\x82\xcd\x82\xa2" /* はい */ }; for (int i = 0; i < sizeof(s)/sizeof(*s); i++) if (::strcmp(text, s[i]) == 0) return true; return false; } TextArgument *arg_, argValue_; /** * Sample game: Rance03 * * Caller that related to load/save, which is the only caller get kept: * 005C68A7 8B86 74010000 MOV EAX,DWORD PTR DS:[ESI+0x174] * 005C68AD 8B1CA8 MOV EBX,DWORD PTR DS:[EAX+EBP*4] * 005C68B0 85DB TEST EBX,EBX * 005C68B2 74 63 JE SHORT Rance03T.005C6917 * 005C68B4 8B86 78010000 MOV EAX,DWORD PTR DS:[ESI+0x178] * 005C68BA 2B86 74010000 SUB EAX,DWORD PTR DS:[ESI+0x174] * 005C68C0 C1F8 02 SAR EAX,0x2 * 005C68C3 3BD0 CMP EDX,EAX * 005C68C5 73 3C JNB SHORT Rance03T.005C6903 * 005C68C7 8B86 74010000 MOV EAX,DWORD PTR DS:[ESI+0x174] * 005C68CD 8B0C90 MOV ECX,DWORD PTR DS:[EAX+EDX*4] * 005C68D0 85C9 TEST ECX,ECX * 005C68D2 74 2F JE SHORT Rance03T.005C6903 * 005C68D4 53 PUSH EBX * 005C68D5 -E9 26976B09 JMP 09C80000 ; jichi: called * 005C68DA 84C0 TEST AL,AL * 005C68DC 75 18 JNZ SHORT Rance03T.005C68F6 * 005C68DE 68 94726E00 PUSH Rance03T.006E7294 * 005C68E3 68 00736E00 PUSH Rance03T.006E7300 ; ASCII "S_ASSIGN" * 005C68E8 56 PUSH ESI * 005C68E9 E8 12BBFFFF CALL Rance03T.005C2400 * 005C68EE 83C4 0C ADD ESP,0xC * 005C68F1 5F POP EDI * 005C68F2 5E POP ESI * * Caller of the scenario thread: * * 005D6F80 ^74 BE JE SHORT Rance03T.005D6F40 * 005D6F82 85C0 TEST EAX,EAX * 005D6F84 ^74 BA JE SHORT Rance03T.005D6F40 * 005D6F86 50 PUSH EAX * 005D6F87 8BCF MOV ECX,EDI * 005D6F89 -E9 72907009 JMP 09CE0000 ; jichi: called here * 005D6F8E ^EB A8 JMP SHORT Rance03T.005D6F38 * 005D6F90 8B46 0C MOV EAX,DWORD PTR DS:[ESI+0xC] * 005D6F93 2B46 08 SUB EAX,DWORD PTR DS:[ESI+0x8] * 005D6F96 C1F8 02 SAR EAX,0x2 * 005D6F99 3BD8 CMP EBX,EAX * 005D6F9B ^73 A3 JNB SHORT Rance03T.005D6F40 * 005D6F9D 8B46 08 MOV EAX,DWORD PTR DS:[ESI+0x8] * 005D6FA0 8B1C98 MOV EBX,DWORD PTR DS:[EAX+EBX*4] */ std::unordered_set hashes_; void hookafter2(hook_stack*s,void* data, size_t len){ auto newData =std::string((char*)data,len); static std::string data_; data_ = newData; auto arg = (TextArgument *)s->stack[0]; // arg1 arg_ = arg; argValue_ = *arg; arg->text = data_.c_str(); arg->size = data_.size() + 1; arg->capacity = arg->size; hashes_.insert(hashCharArray(arg->text)); } bool hookBefore(hook_stack*s,void* data, size_t* len1,uintptr_t*role) { static std::string data_; // persistent storage, which makes this function not thread-safe //auto split = s->stack[5]; // parent function return address //auto split = s->stack[10]; // parent's parent function return address //auto split = *(DWORD *)(s->ecx + 0x10); auto split = *(DWORD *)(s->ecx + 0x34); //auto split = *(DWORD *)(s->ecx + 0x48); // 005C68DA 84C0 TEST AL,AL //if (*(WORD *)retaddr == 0xc084) // otherwise system text will be translated // return true; //if (*(WORD *)retaddr != 0xc084) // only translate one caller // return true; // 005D6F8E ^EB A8 JMP SHORT Rance03T.005D6F38 //if (*(WORD *)retaddr != 0xa8eb) // this function has 7 callers, and only one is kept // return true; if (split > 0xff || split && split < 0xf) return false; auto arg = (TextArgument *)s->stack[0]; // arg1 if (!arg || !arg->isValid() || hashes_.find(hashCharArray(arg->text)) != hashes_.end()) return false; if (arg->size < 0xf && split > 0 && !isOtherText(arg->text)) return false; //auto sig = Engine::hashThreadSignature(role, split); //auto role = Engine::OtherRole; * role = Engine::OtherRole; if (!isOtherText(arg->text)) { if (split == 0 && arg->size <= 0x10) *role = Engine::NameRole; else if (split >= 2 && split <= 0x14 && split != 3 && split != 0xb || split == 0x22) *role = Engine::ScenarioRole; } std::string oldData = arg->text; std::string newData = oldData+"XX"; strcpy((char*)data,oldData.c_str());*len1=oldData.size(); return true; if (*role == Engine::NameRole || oldData == newData) // do not translate name return false; data_ = newData; arg_ = arg; argValue_ = *arg; arg->text = data_.c_str(); arg->size = data_.size() + 1; arg->capacity = arg->size; hashes_.insert(hashCharArray(arg->text)); return true; } bool hookAfter(hook_stack*s,void* data, size_t* len1,uintptr_t*role) { if (arg_) { *arg_ = argValue_; arg_ = nullptr; } return false; } } // namespace Private /** * Sample game: Rance03 * * Function that is similar to memcpy, found by debugging where game text get modified: * * 0069D84F CC INT3 * 0069D850 57 PUSH EDI * 0069D851 56 PUSH ESI * 0069D852 8B7424 10 MOV ESI,DWORD PTR SS:[ESP+0x10] * 0069D856 8B4C24 14 MOV ECX,DWORD PTR SS:[ESP+0x14] * 0069D85A 8B7C24 0C MOV EDI,DWORD PTR SS:[ESP+0xC] * 0069D85E 8BC1 MOV EAX,ECX * 0069D860 8BD1 MOV EDX,ECX * 0069D862 03C6 ADD EAX,ESI * 0069D864 3BFE CMP EDI,ESI * 0069D866 76 08 JBE SHORT Rance03T.0069D870 * 0069D868 3BF8 CMP EDI,EAX * 0069D86A 0F82 68030000 JB Rance03T.0069DBD8 * 0069D870 0FBA25 5CC97500 >BT DWORD PTR DS:[0x75C95C],0x1 * 0069D878 73 07 JNB SHORT Rance03T.0069D881 * 0069D87A F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] * 0069D87C E9 17030000 JMP Rance03T.0069DB98 * 0069D881 81F9 80000000 CMP ECX,0x80 * 0069D887 0F82 CE010000 JB Rance03T.0069DA5B * 0069D88D 8BC7 MOV EAX,EDI * 0069D88F 33C6 XOR EAX,ESI * 0069D891 A9 0F000000 TEST EAX,0xF * 0069D896 75 0E JNZ SHORT Rance03T.0069D8A6 * 0069D898 0FBA25 10A47400 >BT DWORD PTR DS:[0x74A410],0x1 * 0069D8A0 0F82 DA040000 JB Rance03T.0069DD80 * 0069D8A6 0FBA25 5CC97500 >BT DWORD PTR DS:[0x75C95C],0x0 * 0069D8AE 0F83 A7010000 JNB Rance03T.0069DA5B * 0069D8B4 F7C7 03000000 TEST EDI,0x3 * 0069D8BA 0F85 B8010000 JNZ Rance03T.0069DA78 * 0069D8C0 F7C6 03000000 TEST ESI,0x3 * 0069D8C6 0F85 97010000 JNZ Rance03T.0069DA63 * 0069D8CC 0FBAE7 02 BT EDI,0x2 * 0069D8D0 73 0D JNB SHORT Rance03T.0069D8DF * 0069D8D2 8B06 MOV EAX,DWORD PTR DS:[ESI] * 0069D8D4 83E9 04 SUB ECX,0x4 * 0069D8D7 8D76 04 LEA ESI,DWORD PTR DS:[ESI+0x4] * 0069D8DA 8907 MOV DWORD PTR DS:[EDI],EAX * 0069D8DC 8D7F 04 LEA EDI,DWORD PTR DS:[EDI+0x4] * 0069D8DF 0FBAE7 03 BT EDI,0x3 * 0069D8E3 73 11 JNB SHORT Rance03T.0069D8F6 * 0069D8E5 F3: PREFIX REP: ; Superfluous prefix * 0069D8E6 0F7E0E MOVD DWORD PTR DS:[ESI],MM1 * 0069D8E9 83E9 08 SUB ECX,0x8 * 0069D8EC 8D76 08 LEA ESI,DWORD PTR DS:[ESI+0x8] * 0069D8EF 66:0FD6 ??? ; Unknown command * 0069D8F2 -0F8D 7F08F7C6 JGE C760E177 * 0069D8F8 07 POP ES ; Modification of segment register * 0069D8F9 0000 ADD BYTE PTR DS:[EAX],AL * 0069D8FB 007463 0F ADD BYTE PTR DS:[EBX+0xF],DH * 0069D8FF BA E6030F83 MOV EDX,0x830F03E6 * 0069D904 B2 00 MOV DL,0x0 * 0069D906 0000 ADD BYTE PTR DS:[EAX],AL * 0069D908 66:0F6F4E F4 MOVQ MM1,QWORD PTR DS:[ESI-0xC] * 0069D90D 8D76 F4 LEA ESI,DWORD PTR DS:[ESI-0xC] * 0069D910 66:0F6F5E 10 MOVQ MM3,QWORD PTR DS:[ESI+0x10] * 0069D915 83E9 30 SUB ECX,0x30 * 0069D918 66:0F6F46 20 MOVQ MM0,QWORD PTR DS:[ESI+0x20] * 0069D91D 66:0F6F6E 30 MOVQ MM5,QWORD PTR DS:[ESI+0x30] * 0069D922 8D76 30 LEA ESI,DWORD PTR DS:[ESI+0x30] * 0069D925 83F9 30 CMP ECX,0x30 * 0069D928 66:0F6FD3 MOVQ MM2,MM3 * 0069D92C 66:0F3A ??? ; Unknown command * 0069D92F 0FD90C66 PSUBUSW MM1,QWORD PTR DS:[ESI] * 0069D933 0F7F1F MOVQ QWORD PTR DS:[EDI],MM3 * 0069D936 66:0F6FE0 MOVQ MM4,MM0 * 0069D93A 66:0F3A ??? ; Unknown command * 0069D93D 0FC20C66 0F CMPPS XMM1,DQWORD PTR DS:[ESI],0xF * 0069D942 7F 47 JG SHORT Rance03T.0069D98B * 0069D944 1066 0F ADC BYTE PTR DS:[ESI+0xF],AH * 0069D947 6F OUTS DX,DWORD PTR ES:[EDI] ; I/O command * 0069D948 CD 66 INT 0x66 * 0069D94A 0F3A ??? ; Unknown command * 0069D94C 0FEC0C66 PADDSB MM1,QWORD PTR DS:[ESI] * 0069D950 0F7F6F 20 MOVQ QWORD PTR DS:[EDI+0x20],MM5 * 0069D954 8D7F 30 LEA EDI,DWORD PTR DS:[EDI+0x30] * 0069D957 ^7D B7 JGE SHORT Rance03T.0069D910 * 0069D959 8D76 0C LEA ESI,DWORD PTR DS:[ESI+0xC] * 0069D95C E9 AF000000 JMP Rance03T.0069DA10 * 0069D961 66:0F6F4E F8 MOVQ MM1,QWORD PTR DS:[ESI-0x8] * 0069D966 8D76 F8 LEA ESI,DWORD PTR DS:[ESI-0x8] * 0069D969 8D49 00 LEA ECX,DWORD PTR DS:[ECX] * 0069D96C 66:0F6F5E 10 MOVQ MM3,QWORD PTR DS:[ESI+0x10] * 0069D971 83E9 30 SUB ECX,0x30 * 0069D974 66:0F6F46 20 MOVQ MM0,QWORD PTR DS:[ESI+0x20] * 0069D979 66:0F6F6E 30 MOVQ MM5,QWORD PTR DS:[ESI+0x30] * 0069D97E 8D76 30 LEA ESI,DWORD PTR DS:[ESI+0x30] * 0069D981 83F9 30 CMP ECX,0x30 * 0069D984 66:0F6FD3 MOVQ MM2,MM3 * 0069D988 66:0F3A ??? ; Unknown command * 0069D98B 0FD908 PSUBUSW MM1,QWORD PTR DS:[EAX] * 0069D98E 66:0F7F1F MOVQ QWORD PTR DS:[EDI],MM3 * 0069D992 66:0F6FE0 MOVQ MM4,MM0 * 0069D996 66:0F3A ??? ; Unknown command * 0069D999 0FC208 66 CMPPS XMM1,DQWORD PTR DS:[EAX],0x66 * 0069D99D 0F7F47 10 MOVQ QWORD PTR DS:[EDI+0x10],MM0 * 0069D9A1 66:0F6FCD MOVQ MM1,MM5 * 0069D9A5 66:0F3A ??? ; Unknown command * 0069D9A8 0FEC08 PADDSB MM1,QWORD PTR DS:[EAX] * 0069D9AB 66:0F7F6F 20 MOVQ QWORD PTR DS:[EDI+0x20],MM5 * 0069D9B0 8D7F 30 LEA EDI,DWORD PTR DS:[EDI+0x30] * 0069D9B3 ^7D B7 JGE SHORT Rance03T.0069D96C * 0069D9B5 8D76 08 LEA ESI,DWORD PTR DS:[ESI+0x8] * 0069D9B8 EB 56 JMP SHORT Rance03T.0069DA10 * 0069D9BA 66:0F6F4E FC MOVQ MM1,QWORD PTR DS:[ESI-0x4] * 0069D9BF 8D76 FC LEA ESI,DWORD PTR DS:[ESI-0x4] * 0069D9C2 8BFF MOV EDI,EDI * 0069D9C4 66:0F6F5E 10 MOVQ MM3,QWORD PTR DS:[ESI+0x10] * 0069D9C9 83E9 30 SUB ECX,0x30 * 0069D9CC 66:0F6F46 20 MOVQ MM0,QWORD PTR DS:[ESI+0x20] * 0069D9D1 66:0F6F6E 30 MOVQ MM5,QWORD PTR DS:[ESI+0x30] * 0069D9D6 8D76 30 LEA ESI,DWORD PTR DS:[ESI+0x30] * 0069D9D9 83F9 30 CMP ECX,0x30 * 0069D9DC 66:0F6FD3 MOVQ MM2,MM3 * 0069D9E0 66:0F3A ??? ; Unknown command * 0069D9E3 0FD90466 PSUBUSW MM0,QWORD PTR DS:[ESI] * 0069D9E7 0F7F1F MOVQ QWORD PTR DS:[EDI],MM3 * 0069D9EA 66:0F6FE0 MOVQ MM4,MM0 * 0069D9EE 66:0F3A ??? ; Unknown command * 0069D9F1 0FC20466 0F CMPPS XMM0,DQWORD PTR DS:[ESI],0xF * 0069D9F6 7F 47 JG SHORT Rance03T.0069DA3F * 0069D9F8 1066 0F ADC BYTE PTR DS:[ESI+0xF],AH * 0069D9FB 6F OUTS DX,DWORD PTR ES:[EDI] ; I/O command * 0069D9FC CD 66 INT 0x66 * 0069D9FE 0F3A ??? ; Unknown command * 0069DA00 0FEC0466 PADDSB MM0,QWORD PTR DS:[ESI] * 0069DA04 0F7F6F 20 MOVQ QWORD PTR DS:[EDI+0x20],MM5 * 0069DA08 8D7F 30 LEA EDI,DWORD PTR DS:[EDI+0x30] * 0069DA0B ^7D B7 JGE SHORT Rance03T.0069D9C4 * 0069DA0D 8D76 04 LEA ESI,DWORD PTR DS:[ESI+0x4] * 0069DA10 83F9 10 CMP ECX,0x10 * 0069DA13 7C 13 JL SHORT Rance03T.0069DA28 * 0069DA15 F3: PREFIX REP: ; Superfluous prefix * 0069DA16 0F6F0E MOVQ MM1,QWORD PTR DS:[ESI] * 0069DA19 83E9 10 SUB ECX,0x10 * 0069DA1C 8D76 10 LEA ESI,DWORD PTR DS:[ESI+0x10] * 0069DA1F 66:0F7F0F MOVQ QWORD PTR DS:[EDI],MM1 * 0069DA23 8D7F 10 LEA EDI,DWORD PTR DS:[EDI+0x10] * 0069DA26 ^EB E8 JMP SHORT Rance03T.0069DA10 * 0069DA28 0FBAE1 02 BT ECX,0x2 * 0069DA2C 73 0D JNB SHORT Rance03T.0069DA3B * 0069DA2E 8B06 MOV EAX,DWORD PTR DS:[ESI] * 0069DA30 83E9 04 SUB ECX,0x4 * 0069DA33 8D76 04 LEA ESI,DWORD PTR DS:[ESI+0x4] * 0069DA36 8907 MOV DWORD PTR DS:[EDI],EAX * 0069DA38 8D7F 04 LEA EDI,DWORD PTR DS:[EDI+0x4] * 0069DA3B 0FBAE1 03 BT ECX,0x3 * 0069DA3F 73 11 JNB SHORT Rance03T.0069DA52 * 0069DA41 F3: PREFIX REP: ; Superfluous prefix * 0069DA42 0F7E0E MOVD DWORD PTR DS:[ESI],MM1 * 0069DA45 83E9 08 SUB ECX,0x8 * 0069DA48 8D76 08 LEA ESI,DWORD PTR DS:[ESI+0x8] * 0069DA4B 66:0FD6 ??? ; Unknown command * 0069DA4E -0F8D 7F088B04 JGE 04F4E2D3 * 0069DA54 8D88 DB6900FF LEA ECX,DWORD PTR DS:[EAX+0xFF0069DB] * 0069DA5A ^E0 F7 LOOPDNE SHORT Rance03T.0069DA53 * 0069DA5C C703 00000075 MOV DWORD PTR DS:[EBX],0x75000000 * 0069DA62 15 C1E90283 ADC EAX,0x8302E9C1 * 0069DA67 E2 03 LOOPD SHORT Rance03T.0069DA6C * 0069DA69 83F9 08 CMP ECX,0x8 * 0069DA6C 72 2A JB SHORT Rance03T.0069DA98 * 0069DA6E F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI> * 0069DA70 FF2495 88DB6900 JMP DWORD PTR DS:[EDX*4+0x69DB88] * 0069DA77 90 NOP * * 0012F810 0B4D3F30 * 0012F814 06128970 * 0012F818 005D3E12 RETURN to Rance03T.005D3E12 from Rance03T.0069D850 * 0012F81C 06160B98 ; jichi: target text * 0012F820 07F8CA80 ; jichi: source text * 0012F824 00000017 ; jichi: size including \0 * 0012F828 00384460 * 0012F82C 00384240 * 0012F830 0B4D3F30 * 0012F834 005C68DA RETURN to Rance03T.005C68DA from Rance03T.005D3D90 * 0012F838 0B4D3F30 * 0012F83C 0012FAA8 * 0012F840 00384240 * 0012F844 0012F85C * 0012F848 0012FF18 * 0012F84C 005C1693 RETURN to Rance03T.005C1693 from Rance03T.005C6870 * 0012F850 0012FAA8 * 0012F854 00384240 * 0012F858 0000000F * 0012F85C /0012FF3C * * Actual hooked function: * 005D3D8B CC INT3 * 005D3D8C CC INT3 * 005D3D8D CC INT3 * 005D3D8E CC INT3 * 005D3D8F CC INT3 * 005D3D90 53 PUSH EBX * 005D3D91 56 PUSH ESI * 005D3D92 8B7424 0C MOV ESI,DWORD PTR SS:[ESP+0xC] * 005D3D96 57 PUSH EDI * 005D3D97 8BF9 MOV EDI,ECX * 005D3D99 837E 0C 00 CMP DWORD PTR DS:[ESI+0xC],0x0 * 005D3D9D 74 1C JE SHORT Rance03T.005D3DBB * 005D3D9F 8B56 08 MOV EDX,DWORD PTR DS:[ESI+0x8] * 005D3DA2 85D2 TEST EDX,EDX * 005D3DA4 74 15 JE SHORT Rance03T.005D3DBB * 005D3DA6 8D4A 01 LEA ECX,DWORD PTR DS:[EDX+0x1] * 005D3DA9 8DA424 00000000 LEA ESP,DWORD PTR SS:[ESP] * 005D3DB0 8A02 MOV AL,BYTE PTR DS:[EDX] * 005D3DB2 42 INC EDX * 005D3DB3 84C0 TEST AL,AL * 005D3DB5 ^75 F9 JNZ SHORT Rance03T.005D3DB0 * 005D3DB7 2BD1 SUB EDX,ECX * 005D3DB9 EB 02 JMP SHORT Rance03T.005D3DBD * 005D3DBB 33D2 XOR EDX,EDX * 005D3DBD 8D5A 01 LEA EBX,DWORD PTR DS:[EDX+0x1] * 005D3DC0 3B5F 0C CMP EBX,DWORD PTR DS:[EDI+0xC] * 005D3DC3 76 1A JBE SHORT Rance03T.005D3DDF * 005D3DC5 53 PUSH EBX * 005D3DC6 8D4F 04 LEA ECX,DWORD PTR DS:[EDI+0x4] * 005D3DC9 C747 0C 00000000 MOV DWORD PTR DS:[EDI+0xC],0x0 * 005D3DD0 E8 DB700700 CALL Rance03T.0064AEB0 * 005D3DD5 84C0 TEST AL,AL * 005D3DD7 75 06 JNZ SHORT Rance03T.005D3DDF * 005D3DD9 5F POP EDI * 005D3DDA 5E POP ESI * 005D3DDB 5B POP EBX * 005D3DDC C2 0400 RETN 0x4 * 005D3DDF 837E 0C 00 CMP DWORD PTR DS:[ESI+0xC],0x0 * 005D3DE3 75 04 JNZ SHORT Rance03T.005D3DE9 * 005D3DE5 33C9 XOR ECX,ECX * 005D3DE7 EB 03 JMP SHORT Rance03T.005D3DEC * 005D3DE9 8B4E 08 MOV ECX,DWORD PTR DS:[ESI+0x8] * 005D3DEC 837F 0C 00 CMP DWORD PTR DS:[EDI+0xC],0x0 * 005D3DF0 75 15 JNZ SHORT Rance03T.005D3E07 * 005D3DF2 53 PUSH EBX * 005D3DF3 33C0 XOR EAX,EAX * 005D3DF5 51 PUSH ECX * 005D3DF6 50 PUSH EAX * 005D3DF7 E8 549A0C00 CALL Rance03T.0069D850 * 005D3DFC 83C4 0C ADD ESP,0xC * 005D3DFF B0 01 MOV AL,0x1 * 005D3E01 5F POP EDI * 005D3E02 5E POP ESI * 005D3E03 5B POP EBX * 005D3E04 C2 0400 RETN 0x4 * 005D3E07 8B47 08 MOV EAX,DWORD PTR DS:[EDI+0x8] * 005D3E0A 53 PUSH EBX * 005D3E0B 51 PUSH ECX * 005D3E0C 50 PUSH EAX * 005D3E0D -E9 EEC1A201 JMP 02000000 ; jichi: called here * 005D3E12 83C4 0C ADD ESP,0xC * 005D3E15 B0 01 MOV AL,0x1 * 005D3E17 5F POP EDI * 005D3E18 5E POP ESI * 005D3E19 5B POP EBX * 005D3E1A C2 0400 RETN 0x4 * 005D3E1D CC INT3 * 005D3E1E CC INT3 * 005D3E1F CC INT3 * * Arg1 of this function: * 07B743F8 90 7A 70 00 F4 87 70 00 70 0E 27 08 1B 00 00 00 諏p.p.p'... * 07B74408 20 00 00 00 02 00 00 00 01 00 00 00 CC 7F 2D 00 .........フ-. * 07B74418 B3 52 41 00 FF FF FF FF EC 87 70 00 10 E3 1D 08 ウRA.・p.・ * * Caller that preserved: * 005C68A7 8B86 74010000 MOV EAX,DWORD PTR DS:[ESI+0x174] * 005C68AD 8B1CA8 MOV EBX,DWORD PTR DS:[EAX+EBP*4] * 005C68B0 85DB TEST EBX,EBX * 005C68B2 74 63 JE SHORT Rance03T.005C6917 * 005C68B4 8B86 78010000 MOV EAX,DWORD PTR DS:[ESI+0x178] * 005C68BA 2B86 74010000 SUB EAX,DWORD PTR DS:[ESI+0x174] * 005C68C0 C1F8 02 SAR EAX,0x2 * 005C68C3 3BD0 CMP EDX,EAX * 005C68C5 73 3C JNB SHORT Rance03T.005C6903 * 005C68C7 8B86 74010000 MOV EAX,DWORD PTR DS:[ESI+0x174] * 005C68CD 8B0C90 MOV ECX,DWORD PTR DS:[EAX+EDX*4] * 005C68D0 85C9 TEST ECX,ECX * 005C68D2 74 2F JE SHORT Rance03T.005C6903 * 005C68D4 53 PUSH EBX * 005C68D5 E8 B6D40000 CALL Rance03T.005D3D90 ; jichi: called * 005C68DA 84C0 TEST AL,AL ; jichi: retaddr * 005C68DC 75 18 JNZ SHORT Rance03T.005C68F6 * 005C68DE 68 94726E00 PUSH Rance03T.006E7294 * 005C68E3 68 00736E00 PUSH Rance03T.006E7300 ; ASCII "S_ASSIGN" * 005C68E8 56 PUSH ESI * 005C68E9 E8 12BBFFFF CALL Rance03T.005C2400 * 005C68EE 83C4 0C ADD ESP,0xC * 005C68F1 5F POP EDI * 005C68F2 5E POP ESI */ bool attach(ULONG startAddress, ULONG stopAddress) { const uint8_t bytes[] = { 0x53, // 005D3D90 53 PUSH EBX 0x56, // 005D3D91 56 PUSH ESI 0x8B,0x74,0x24, 0x0C, // 005D3D92 8B7424 0C MOV ESI,DWORD PTR SS:[ESP+0xC] 0x57, // 005D3D96 57 PUSH EDI 0x8B,0xF9, // 005D3D97 8BF9 MOV EDI,ECX 0x83,0x7E, 0x0C, 0x00, // 005D3D99 837E 0C 00 CMP DWORD PTR DS:[ESI+0xC],0x0 0x74, 0x1C, // 005D3D9D 74 1C JE SHORT Rance03T.005D3DBB 0x8B,0x56, 0x08, // 005D3D9F 8B56 08 MOV EDX,DWORD PTR DS:[ESI+0x8] 0x85,0xD2, // 005D3DA2 85D2 TEST EDX,EDX 0x74, 0x15, // 005D3DA4 74 15 JE SHORT Rance03T.005D3DBB 0x8D,0x4A, 0x01, // 005D3DA6 8D4A 01 LEA ECX,DWORD PTR DS:[EDX+0x1] 0x8D,0xA4,0x24, 0x00,0x00,0x00,0x00, // 005D3DA9 8DA424 00000000 LEA ESP,DWORD PTR SS:[ESP] 0x8A,0x02, // 005D3DB0 8A02 MOV AL,BYTE PTR DS:[EDX] 0x42, // 005D3DB2 42 INC EDX 0x84,0xC0 // 005D3DB3 84C0 TEST AL,AL }; ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress); if (!addr) return false; //addr = MemDbg::findEnclosingAlignedFunction(addr); //if (!addr) // return false; //addr = 0x005D3D90; //return winhook::hook_before(addr, Private::hookBefore); int count = 0; auto fun = [&count](ULONG addr) -> bool { auto retaddr = addr + 5; // 005C68DA 84C0 TEST AL,AL if (*(WORD *)retaddr == 0xc084) //auto before = std::bind(Private::hookBefore, addr + 5, std::placeholders::_1); count +=1; HookParam hp; hp.address=addr; hp.type=EMBED_ABLE|EMBED_DYNA_SJIS; hp.hook_before=Private::hookBefore; hp.hook_after=Private::hookafter2; auto succ=NewHook(hp,"EmbedSysmtem44"); hp.address=addr+5; hp.hook_before=Private::hookAfter; succ|=NewHook(hp,"EmbedSysmtem44"); return succ; // replace all functions }; MemDbg::iterNearCallAddress(fun, addr, startAddress, stopAddress); return count; } } // namespace ScenarioHook } // unnamed namespace bool attachSystem44(ULONG startAddress, ULONG stopAddress) { return ScenarioHook::attach(startAddress, stopAddress); } namespace { // unnamed // - Search - ULONG searchScenarioAddress(ULONG startAddress, ULONG stopAddress) { const uint8_t bytes[] = { 0xe8, XX4, // 005c71e0 e8 2bcfffff call .005c4110 ; original function call 0xeb, 0xa5, // 005c71e5 ^eb a5 jmp short .005c718c 0x8b,0x47, 0x08, // 005c71e7 8b47 08 mov eax,dword ptr ds:[edi+0x8] 0x8b,0x4f, 0x0c // 005c71ea 8b4f 0c mov ecx,dword ptr ds:[edi+0xc] }; return MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress); } ULONG searchNameAddress(ULONG startAddress, ULONG stopAddress) { const uint8_t bytes[] = { 0xe8, XX4, // 004eeb34 e8 67cb0100 call .0050b6a0 ; jichi: hook here 0x39,0x6c,0x24, 0x28, // 004eeb39 396c24 28 cmp dword ptr ss:[esp+0x28],ebp 0x72, 0x0d, // 004eeb3d 72 0d jb short .004eeb4c 0x8b,0x4c,0x24, 0x14, // 004eeb3f 8b4c24 14 mov ecx,dword ptr ss:[esp+0x14] 0x51, // 004eeb43 51 push ecx 0xe8 //, XX4, // 004eeb44 e8 42dc1900 call .0068c78b }; return MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress); } ULONG searchOtherAddress(ULONG startAddress, ULONG stopAddress) { const char *pattern = "S_ASSIGN"; const uint8_t bytes[] = { //0xc3, // 005b6492 c3 retn //0x52, // 005b6493 52 push edx 0xe8, XX4, // 005b6494 e8 77dc0000 call .005c4110 ; jichi: hook here 0x84,0xc0, // 005b6499 84c0 test al,al 0x75, XX, // 005b649b 75 16 jnz short .005b64b3 0x68, XX4, // 005b649d 68 d4757200 push .007275d4 0xb9 //, XX4, // 005b64a2 b9 f0757200 mov ecx,.007275f0 ; ascii "S_ASSIGN" //0xe8, XX4 // 005b64a7 e8 84c8ffff call .005b2d30 }; for (ULONG addr = startAddress; addr < stopAddress;) { addr = MemDbg::findBytes(bytes, sizeof(bytes), addr, stopAddress); if (!addr) return 0; addr += sizeof(bytes); DWORD ecx = *(DWORD *)addr; if (::strcmp((LPCSTR)ecx, pattern) == 0) return addr - sizeof(bytes); }; return 0; } // - Hook - struct TextHookBase { struct TextArgument // first argument of the scenario hook { DWORD unknown1, unknown2; LPCSTR text; DWORD size; // text data size, length = size - 1 //DWORD split; // not a good split to distinguish translable text out }; bool enabled_, editable_; // for debugging only, whether text is not read-only std::string buffer_; // persistent storage, which makes this function not thread-safe TextArgument *arg_; // last argument LPCSTR text_; // last text DWORD size_; // last size TextHookBase() : enabled_(true) , editable_(true) , arg_(nullptr) , text_(nullptr) , size_(0) {} }; class ScenarioHook43 : protected TextHookBase { public: bool hookBefore(hook_stack*s,void* data, size_t* len,uintptr_t*role) { // See ATcode patch: // 0070A12E 8B87 B0000000 MOV EAX,DWORD PTR DS:[EDI+0xB0] // 0070A134 66:8138 8400 CMP WORD PTR DS:[EAX],0x84 // 0070A139 75 0E JNZ SHORT .0070A149 // 0070A13B 8378 EA 5B CMP DWORD PTR DS:[EAX-0x16],0x5B // 0070A13F 75 08 JNZ SHORT .0070A149 DWORD split = *(WORD *)(s->edi + 0xb0); if (split && split != 0x27f2) // new System43 after Evenicle return false; if (!split) { // old System43 before Evenicle where edi split is zero split = s->stack[1]; if (split != 0x84) return false; // Stack structure observed from 武想少女隊 // 0012F4BC 07EAFD48 ; text address // 0012F4C0 000002EC ; use this value as split // 0012F4C4 00000011 // 0012F4C8 0012F510 // 0012F4CC 00000012 // 0012F4D0 00001BAA // 0012F4D4 00000012 // 0012F4D8 06D2E24C // 0012F4DC 00581125 RETURN to .00581125 from .0057DC30 //if (s->stack[1] != 0x84) // return true; //if (s->stack[2] != 0x3) // return true; } auto arg = (TextArgument *)s->stack[0]; // top of the stack LPCSTR text = arg->text; if (arg->size <= 1 || !text || !*text || all_ascii(text)) return false; *role = Engine::ScenarioRole ; strcpy((char*)data,text);*len=strlen(text); /* auto sig = Engine::hashThreadSignature(role, split); //int size = arg->size; // size not used as not needed buffer_ = EngineController::instance()->dispatchTextASTD(text, role, sig); if (editable_) { arg_ = arg; text_ = arg->text; size_ = arg->size; arg->text = buffer_.c_str(); // reset arg3 arg->size = buffer_.size() + 1; // +1 for the nullptr }*/ return true; } bool hookAfter(hook_stack*s,void* data, size_t* len,uintptr_t*role) { if (arg_) { arg_->text = text_; arg_->size = size_; arg_ = nullptr; } return true; } }; class OtherHook43 : protected TextHookBase { public: bool hookBefore(hook_stack*s,void* data, size_t* len,uintptr_t*role) { if (!enabled_) return false; DWORD splitBase = *(DWORD *)(s->edi + 0x284); // [edi + 0x284] if (!Engine::isAddressReadable(splitBase)) { enabled_ = false; return false; } DWORD split1 = *(WORD *)(splitBase - 0x4), // word [[edi + 0x284] - 0x4] split2 = *(WORD *)(splitBase - 0x8); // word [[edi + 0x284] - 0x8] enum : WORD { OtherSplit = 0x46 }; // 0x440046 if use dword split if (split1 != OtherSplit || split2 <= 2) // split internal system messages return false; auto arg = (TextArgument *)s->stack[0]; // top of the stack // auto g = EngineController::instance(); LPCSTR text = arg->text; if (arg->size <= 1 || !text || !*text || all_ascii(text)) return false; strcpy((char*)data,text);*len=strlen(text); /* enum { role = Engine::OtherRole }; auto sig = Engine::hashThreadSignature(role, split2); buffer_ = g->dispatchTextASTD(text, role, sig); if (editable_) { arg_ = arg; text_ = arg->text; size_ = arg->size; arg->text = buffer_.c_str(); // reset arg3 arg->size = buffer_.size() + 1; // +1 for the nullptr }*/ return true; } bool hookAfter(hook_stack*s,void* data, size_t* len,uintptr_t*role) { if (arg_) { arg_->text = text_; arg_->size = size_; arg_ = nullptr; } return false; } }; // Text with fixed size bool fixedTextHook(hook_stack*s,void* data, size_t* len,uintptr_t*role) { enum { FixedSize = 0x10 }; struct FixedArgument // first argument of the name hook { char text[FixedSize]; // 0x10 DWORD type, // [[esp]+0x10] type2; // [[esp]+0x14] }; auto arg = (FixedArgument *)s->stack[0]; if (arg->type2 != 0xf) // non 0xf is garbage text return false; char *text = arg->text; if (!text || !*text || all_ascii(text)) return false; * role; long sig; if (arg->type == 0x6 || arg->type == 0xc) { *role = Engine::NameRole; } else if (::strlen(text) <= 2) // skip translating very short other text return false; else { *role = Engine::OtherRole; } strcpy((char*)data,text);*len=strlen(text); /*std::string buffer_ = EngineController::instance()->dispatchTextASTD(text, role, sig); ::strncpy(text, buffer_.c_str(), FixedSize - 1); text[FixedSize - 1] = 0;*/ return true; } } // unnamed namespace bool attachSystem43(ULONG startAddress, ULONG stopAddress) { //太麻煩 放棄。 return false; { //ULONG addr = 0x005c71e0; ULONG addr = ::searchScenarioAddress(startAddress, stopAddress); if (!addr) return false; /* static auto h = new ScenarioHook43; // never deleted if (!winhook::hook_both(addr, std::bind(&ScenarioHook43::hookBefore, h, _1), std::bind(&ScenarioHook43::hookAfter, h, _1))) return false; */ } /* if (ULONG addr = ::searchOtherAddress(startAddress, stopAddress)) { static auto h = new OtherHook; // never deleted if (!winhook::hook_both(addr, std::bind(&OtherHook43::hookBefore, h, _1), std::bind(&OtherHook43::hookAfter, h, _1))) DOUT("other text NOT FOUND"); else DOUT("other text address" << QString::number(addr, 16)); } if (ULONG addr = ::searchNameAddress(startAddress, stopAddress)) { if (winhook::hook_before(addr, ::fixedTextHook)) DOUT("name text address" << QString::number(addr, 16)); else DOUT("name text NOT FOUND"); } */ //HijackManager::instance()->attachFunction((ULONG)::MultiByteToWideChar); return true; } namespace{ bool system4X(ULONG startAddress, ULONG stopAddress){ if (attachSystem43(startAddress, stopAddress)) { return true; } else if (attachSystem44(startAddress, stopAddress)) { return true; } else return false; } } namespace{ bool System42Filter(LPVOID data, size_t *size, HookParam *) { auto text = reinterpret_cast(data); auto len = reinterpret_cast(size); if (*len == 1) return false; if (all_ascii(text, *len)) { CharReplacer(text, len, '`', ' '); CharReplacer(text, len, '\x7D', '-'); } return true; } bool InsertSystem42Hook() { /* * Sample games: * https://vndb.org/v1427 */ const BYTE bytes[] = { 0x8B, 0x46, 0x04, // mov eax,[esi+04] 0x57, // push edi 0x52, // push edx 0x50, // push eax 0xE8, XX4 // call Sys42VM.DLL+4B5B0 }; HMODULE module = GetModuleHandleW(L"Sys42VM.dll"); auto [minAddress, maxAddress] = Util::QueryModuleLimits(module); ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), minAddress, maxAddress); if (!addr) return false; HookParam hp; hp.address = addr; hp.offset=get_reg(regs::edx); hp.split =get_reg(regs::esp); hp.type = NO_CONTEXT | USING_STRING | USING_SPLIT; hp.filter_fun = System42Filter; ConsoleOutput("INSERT System42"); return NewHook(hp, "System42"); } } bool System4x::attach_function() { if (Util::CheckFile(L"DLL/Sys42VM.dll")) if (InsertSystem42Hook()) return true; auto _=system4X(processStartAddress,processStopAddress); return InsertSystem43Hook()||_; }