LunaHook-mirror/LunaHook/engine32/LCScript.cpp

1001 lines
47 KiB
C++
Raw Normal View History

2024-02-07 20:59:24 +08:00
#include"LCScript.h"
namespace { // unnamed
namespace ScenarioHook {
namespace Private {
// Skip trailing 0203
LPCSTR trim(LPCSTR text, int *size)
{
auto length = *size;
while (length && (UINT8)text[0] <= 127) { // remove all leading ASCII characters including zeros
text++;
length--;
}
while (length && (UINT8)text[length - 1] == 0) // remove all trailing zeros
length--;
// remove all trailing illegal double-characters
enum { MinimumByte = 0x6 }; // the same as dynamicEncodingMinimumByte
while (length >= 2 && (UINT8)text[length - 1] < MinimumByte && (UINT8)text[length - 2] < MinimumByte)
length -= 2;
*size = length;
return text;
}
/**
* Sample game:
*
* 067C73FA 8F CD 90 6D 01 81 75 96 7B 93 96 82 C9 82 B1 82 
* 067C740A F1 82 C8 82 C6 82 B1 82 EB 82 AA 82 A0 82 E9 82
* 067C741A F1 82 BE 82 C8 82 9F 81 63 81 63 81 76 02 03 00 .
* 067C742A 38 00 00 00 01 81 40 96 DA 82 CC 91 4F 82 C9 8D 8... 
* 067C743A 4C 82 AA 82 E9 8C F5 8C 69 82 F0 91 4F 82 C9 81 Lがる光景を前に
*
* Name/scenario splitter: 01 ()
* New line splitter: 0203 ()
*/
// 0042FBE8 A1 E8234A00 MOV EAX,DWORD PTR DS:[0x4A23E8] ; jichi: text length here
//
// 0042FC03 8B15 E8234A00 MOV EDX,DWORD PTR DS:[0x4A23E8] ; jichi: text length here
// 0042FC09 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+0x10] ; jichi: count is here
// 0042FC0D 8B76 04 MOV ESI,DWORD PTR DS:[ESI+0x4]
// 0042FC10 894424 14 MOV DWORD PTR SS:[ESP+0x14],EAX
// 0042FC14 8B92 44290000 MOV EDX,DWORD PTR DS:[EDX+0x2944] ; jichi: offset
// 0042FC1A 8BF8 MOV EDI,EAX
// 0042FC1C 8BC1 MOV EAX,ECX
// 0042FC1E 83C4 04 ADD ESP,0x4
// 0042FC21 8D7432 04 LEA ESI,DWORD PTR DS:[EDX+ESI+0x4]
ULONG textBaseAddress_, // 0042FC03 8B15 E8234A00 MOV EDX,DWORD PTR DS:[0x4A23E8]
textOffset_; // 0042FC14 8B92 44290000 MOV EDX,DWORD PTR DS:[EDX+0x2944]
std::string data_;
/**
* Sample game:
* Sample stack when hook1 is invoked:
* 0012FE10 00000003
* 0012FE14 00000008
* 0012FE18 7FFDF000
* 0012FE1C 00000000
* 0012FE20 00000000
* 0012FE24 0012FEB0 Pointer to next SEH record
* 0012FE28 00480918 SE handler
* 0012FE2C 00000000
* 0012FE30 00419B16 RETURN to .00419B16 from .0040169F
* 0012FE34 0012FE4C
* 0012FE38 0012FE70
* 0012FE3C 00000040
* 0012FE40 77032EB2 user32.PeekMessageA
* 0012FE44 00000000
* 0012FE48 00000039
* 0012FE4C 00000002
* 0012FE50 00000039
* 0012FE54 00000000
* 0012FE58 00000000
*
* Scenario thread caller:
*
* 0041C27C E8 D65AFEFF CALL .00401D57
* 0041C281 8D5424 38 LEA EDX,DWORD PTR SS:[ESP+0x38]
* 0041C285 68 00040000 PUSH 0x400
* 0041C28A 8D4424 34 LEA EAX,DWORD PTR SS:[ESP+0x34]
* 0041C28E 52 PUSH EDX
* 0041C28F 50 PUSH EAX
* 0041C290 E8 2354FEFF CALL .004016B8 ; jichi: scenario caller here
* 0041C295 83C4 0C ADD ESP,0xC
* 0041C298 8D4C24 38 LEA ECX,DWORD PTR SS:[ESP+0x38]
* 0041C29C 8B15 B44E4A00 MOV EDX,DWORD PTR DS:[0x4A4EB4]
* 0041C2A2 51 PUSH ECX
* 0041C2A3 8B0D 5C0A4A00 MOV ECX,DWORD PTR DS:[0x4A0A5C]
* 0041C2A9 8BC1 MOV EAX,ECX
*
* Other thread callers:
*
* 00421298 8D8424 B0000000 LEA EAX,DWORD PTR SS:[ESP+0xB0]
* 0042129F 50 PUSH EAX
* 004212A0 51 PUSH ECX
* 004212A1 895424 2C MOV DWORD PTR SS:[ESP+0x2C],EDX
* 004212A5 E8 0E04FEFF CALL .004016B8 ; jichi: other caller
* 004212AA 8D5424 38 LEA EDX,DWORD PTR SS:[ESP+0x38]
* 004212AE 68 80000000 PUSH 0x80
* 004212B3 8D4424 24 LEA EAX,DWORD PTR SS:[ESP+0x24]
* 004212B7 52 PUSH EDX
* 004212B8 50 PUSH EAX
* 004212B9 E8 FA03FEFF CALL .004016B8 ; jichi: other here
* 004212BE 83C4 18 ADD ESP,0x18
* 004212C1 83FF 01 CMP EDI,0x1
* 004212C4 75 68 JNZ SHORT .0042132E
*
*
* Sample game:
* Sample scenario caller:
* 0041C0C4 8D4424 38 LEA EAX,DWORD PTR SS:[ESP+0x38]
* 0041C0C8 68 00040000 PUSH 0x400
* 0041C0CD 8D4C24 34 LEA ECX,DWORD PTR SS:[ESP+0x34]
* 0041C0D1 50 PUSH EAX
* 0041C0D2 51 PUSH ECX
* 0041C0D3 E8 C755FEFF CALL .0040169F ; jichi: called here
* 0041C0D8 8B0D 4CE94900 MOV ECX,DWORD PTR DS:[0x49E94C]
* 0041C0DE 8B35 00244A00 MOV ESI,DWORD PTR DS:[0x4A2400]
* 0041C0E4 8BC1 MOV EAX,ECX
* 0041C0E6 83C4 0C ADD ESP,0xC
*
* 0012FA54 00000001
* 0012FA58 00000006
* 0012FA5C 7707EA71 user32.MessageBoxA
* 0012FA60 00000000
* 0012FA64 00000000
* 0012FA68 0012FF78 Pointer to next SEH record
* 0012FA6C 00480918 SE handler
* 0012FA70 00000000
* 0012FA74 0041C0D8 RETURN to .0041C0D8 from .0040169F
* 0012FA78 0012FAB4
* 0012FA7C 0012FABC
* 0012FA80 00000400 ; jichi: used as split to identify scenario thread
* 0012FA84 00000003
* 0012FA88 77032EB2 user32.PeekMessageA
* 0012FA8C 77033569 user32.DispatchMessageA
* 0012FA90 7FFDF000
* 0012FA94 00000000
* 0012FA98 00000000
*
* Other thread caller:
* 0012FD60 00000001
* 0012FD64 00000001
* 0012FD68 7FFDF000
* 0012FD6C 00000000
* 0012FD70 00000000
* 0012FD74 0012FF78 Pointer to next SEH record
* 0012FD78 00480918 SE handler
* 0012FD7C 00000000
* 0012FD80 0042113A RETURN to .0042113A from .0040169F
* 0012FD84 0012FDAC
* 0012FD88 0012FE3C
* 0012FD8C 00000080 ; jichi: arg3
* 0012FD90 00000003
* 0012FD94 77032EB2 user32.PeekMessageA
* 0012FD98 77033569 user32.DispatchMessageA
* 0012FD9C 00000002
* 0012FDA0 00000034
* 0012FDA4 00000002
* 0012FDA8 0000006D
* 0012FDAC 00000002
* 0012FDB0 00000034
* 0012FDB4 00000000
* 0012FDB8 00000001
* 0012FDBC 001907D0
* 0012FDC0 00000202
*
* Sample game:
* ecx = 0x22
* Sample game text containing zeros
* 01D6B13B 8E A9 8C 52 81 41 05 04 00 00 00 01 81 40 81 40 ...  
* 01D6B14B 81 40 91 CE 01 93 47 8C 52 81 41 05 05 00 00 00  ...
* 01D6B15B 02 00 14 00 00 00 5F 62 74 6C 5F 53 65 74 57 61 ...._btl_SetWa
* 01D6B16B 7A 61 42 74 6E 53 72 63 59 00 0D 00 00 00 5F 62 zaBtnSrcY....._b
* 01D6B17B 74 6C 5F 63 6D 64 63 68 69 70 00 0F 00 00 00 5F tl_cmdchip...._
* 01D6B18B 62 74 6C 5F 63 6D 64 63 68 69 70 5F 6D 00 0D 00 btl_cmdchip_m...
* 01D6B19B 00 00 5F 62 74 6C 5F 6F 6E 6D 6F 75 73 65 00 0E .._btl_onmouse.
* 01D6B1AB 00 00 00 5F 62 74 6C 5F 73 65 6C 65 63 74 65 64 ..._btl_selected
* 01D6B1BB 00 0B 00 00 00 5F 62 74 6C 5F 52 65 74 72 79 00 . ..._btl_Retry.
* 01D6B1CB 13 00 00 00 5F 62 74 6C 5F 43 6C 65 61 6E 75 70 ..._btl_Cleanup
*
* ecx = 0x19
* 01D6B317 81 40 04 6B 00 00 00 82 CC 91 B9 8A 51 82 F0 97  k...
* 01D6B327 5E 82 A6 82 BD 81 42 02 00 10 00 00 00 5F 62 74 ^...._bt
* 01D6B337 6C 5F 57 61 7A 61 5F 43 68 6F 75 6E 00 17 00 00 l_Waza_Choun...
* 01D6B347 00 5F 62 74 6C 5F 57 61 7A 61 45 6E 65 6D 79 5F ._btl_WazaEnemy_
* 01D6B357 42 75 66 66 41 54 4B 00 10 00 00 00 5F 62 74 6C BuffATK...._btl
* 01D6B367 5F 57 61 7A 61 5F 4B 6F 63 68 75 00 1C 00 00 00 _Waza_Kochu....
*/
bool hook1(hook_stack*s,void* data, size_t* len1,uintptr_t*role)
{
data_.clear();
int size = s->eax - 1;
if (size <= 0)
return false;
// 0042FC03 8B15 E8234A00 MOV EDX,DWORD PTR DS:[0x4A23E8] ; jichi: text here
// 0042FC09 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+0x10] ; jichi: count is here
// 0042FC0D 8B76 04 MOV ESI,DWORD PTR DS:[ESI+0x4] ; jichi: [arg1+4]
// 0042FC10 894424 14 MOV DWORD PTR SS:[ESP+0x14],EAX
// 0042FC14 8B92 44290000 MOV EDX,DWORD PTR DS:[EDX+0x2944] ; jichi: base addr, [[0x4A23E8] + 0x2944]
// 0042FC1A 8BF8 MOV EDI,EAX
// 0042FC1C 8BC1 MOV EAX,ECX
// 0042FC1E 83C4 04 ADD ESP,0x4
//
// 0042FC21 8D7432 04 LEA ESI,DWORD PTR DS:[EDX+ESI+0x4] ; jichi: hook2, text in esi
ULONG edx, esi;
{
edx = *(DWORD *)textBaseAddress_; // 0042FC03 8B15 E8234A00 MOV EDX,DWORD PTR DS:[0x4A23E8]
edx = *(DWORD *)(edx + textOffset_); // 0042FC14 8B92 44290000 MOV EDX,DWORD PTR DS:[EDX+0x2944]
esi = *(DWORD *)(s->esi + 0x4); // 0042FC0D 8B76 04 MOV ESI,DWORD PTR DS:[ESI+0x4]
esi = edx + esi + 0x4; // 0042FC21 8D7432 04 LEA ESI,DWORD PTR DS:[EDX+ESI+0x4]
}
auto text = (LPCSTR)esi;
if (!*text
//|| ::strlen(text) != size
|| text[size] // text length not verified since there could be trailing zeros
|| ::isalpha(text[0]) && ::isalpha(text[1]) // Sample system text in 恋姫無双: bcg_剣道場a
||all_ascii(text))
return false;
auto trimmedSize = size;
auto trimmedText = trim(text, &trimmedSize);
if (trimmedSize <= 0)
return false;
//auto size = s->ecx * 4;
//auto dst = (LPSTR)s->edi;
* role = Engine::OtherRole;
auto retaddr = s->stack[8];
//if ((*(DWORD *)retaddr & 0xffffff) == 0x0cc483) // 0041C295 83C4 0C ADD ESP,0xC
// role = Engine::ScenarioRole;
auto arg3 = s->stack[8 + 3];
if (arg3 == 0x400)
*role = Engine::ScenarioRole;
// 8/7/2015: Here, I could also split choice and scenario from the retaddr.
// But I didn't so that choice can also be display the same way asn scenario.
//sig = retaddr;
std::string oldData(trimmedText, trimmedSize);
static const std::string zero_bytes(1, '\0');
const char *zero_str = LCSE_0;
bool containsZeros = false;
if (oldData.find('\0')!=oldData.npos) {
containsZeros = true;
strReplace(oldData, zero_bytes, zero_str);
//oldData.replace(zero_bytes, zero_str);
*role = Engine::OtherRole;
// FIXME: There could be individual ascii letters before zeros (such as "k" and "n")
// They should be escaped here.
// Escaping not implemented since I am lazy.
}
2024-03-21 17:57:04 +08:00
write_string_overwrite(data,len1,oldData);
2024-02-07 20:59:24 +08:00
return true;
}
void hookafter(hook_stack*s,void* data, size_t len1){
int size = s->eax - 1;
if (size <= 0)
return ;
ULONG edx, esi;
{
edx = *(DWORD *)textBaseAddress_; // 0042FC03 8B15 E8234A00 MOV EDX,DWORD PTR DS:[0x4A23E8]
edx = *(DWORD *)(edx + textOffset_); // 0042FC14 8B92 44290000 MOV EDX,DWORD PTR DS:[EDX+0x2944]
esi = *(DWORD *)(s->esi + 0x4); // 0042FC0D 8B76 04 MOV ESI,DWORD PTR DS:[ESI+0x4]
esi = edx + esi + 0x4; // 0042FC21 8D7432 04 LEA ESI,DWORD PTR DS:[EDX+ESI+0x4]
}
auto text = (LPCSTR)esi;
if (!*text
//|| ::strlen(text) != size
|| text[size] // text length not verified since there could be trailing zeros
|| ::isalpha(text[0]) && ::isalpha(text[1]) // Sample system text in 恋姫無双: bcg_剣道場a
||all_ascii(text))
return ;
auto trimmedSize = size;
auto trimmedText = trim(text, &trimmedSize);
if (trimmedSize <= 0)
return ;
auto retaddr = s->stack[8];
//if ((*(DWORD *)retaddr & 0xffffff) == 0x0cc483) // 0041C295 83C4 0C ADD ESP,0xC
// role = Engine::ScenarioRole;
auto arg3 = s->stack[8 + 3];
std::string oldData(trimmedText, trimmedSize);
static const std::string zero_bytes(1, '\0');
const char *zero_str = LCSE_0;
bool containsZeros = false;
if (oldData.find('\0')!=oldData.npos) {
containsZeros = true;
strReplace(oldData, zero_bytes, zero_str);
//oldData.replace(zero_bytes, zero_str);
// FIXME: There could be individual ascii letters before zeros (such as "k" and "n")
// They should be escaped here.
// Escaping not implemented since I am lazy.
}
std::string newData = std::string((char*)data,len1);
if (newData.empty() || newData == oldData)
return ;
if (containsZeros)
strReplace(newData, zero_str, zero_bytes);
//newData.replace(zero_str, zero_bytes);
int prefixSize = trimmedText - text,
suffixSize = size - prefixSize - trimmedSize;
if (prefixSize)
newData.insert(0,std::string(text, prefixSize));
if (suffixSize)
newData.append(trimmedText + trimmedSize, suffixSize);
data_ = newData;
s->eax = data_.size() + 1;
return ;
}
bool hook2(hook_stack*s,void* data, size_t* len1,uintptr_t*role)
{
if (!data_.empty())
s->esi = (ULONG)data_.c_str();
return false;
}
} // namespace Private
/**
* Sample game:
*
* 0042FB1E CC INT3
* 0042FB1F CC INT3
* 0042FB20 6A FF PUSH -0x1
* 0042FB22 68 18094800 PUSH lcsebody.00480918
* 0042FB27 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
* 0042FB2D 50 PUSH EAX
* 0042FB2E 64:8925 00000000 MOV DWORD PTR FS:[0],ESP
* 0042FB35 83EC 08 SUB ESP,0x8
* 0042FB38 53 PUSH EBX
* 0042FB39 33DB XOR EBX,EBX
* 0042FB3B 56 PUSH ESI
* 0042FB3C 57 PUSH EDI
* 0042FB3D 895C24 0C MOV DWORD PTR SS:[ESP+0xC],EBX
* 0042FB41 895C24 10 MOV DWORD PTR SS:[ESP+0x10],EBX
* 0042FB45 8B7424 24 MOV ESI,DWORD PTR SS:[ESP+0x24] ; jichi; arg1
* 0042FB49 895C24 1C MOV DWORD PTR SS:[ESP+0x1C],EBX
* 0042FB4D 8B06 MOV EAX,DWORD PTR DS:[ESI]
* 0042FB4F 83F8 05 CMP EAX,0x5
* 0042FB52 75 2F JNZ SHORT lcsebody.0042FB83
* 0042FB54 8B76 04 MOV ESI,DWORD PTR DS:[ESI+0x4]
* 0042FB57 8B3D E8234A00 MOV EDI,DWORD PTR DS:[0x4A23E8]
* 0042FB5D 3BF3 CMP ESI,EBX
* 0042FB5F 7C 08 JL SHORT lcsebody.0042FB69
* 0042FB61 39B7 54290000 CMP DWORD PTR DS:[EDI+0x2954],ESI
* 0042FB67 7F 12 JG SHORT lcsebody.0042FB7B
* 0042FB69 53 PUSH EBX
* 0042FB6A 68 20F54800 PUSH lcsebody.0048F520 ; ASCII "err"
* 0042FB6F 68 F4F44800 PUSH lcsebody.0048F4F4
* 0042FB74 53 PUSH EBX
* 0042FB75 FF15 EC874A00 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; user32.MessageBoxA
* 0042FB7B 8B87 74290000 MOV EAX,DWORD PTR DS:[EDI+0x2974]
* 0042FB81 EB 32 JMP SHORT lcsebody.0042FBB5
* 0042FB83 83F8 08 CMP EAX,0x8 ; jichi: esi=arg1 jumped here
* 0042FB86 75 57 JNZ SHORT lcsebody.0042FBDF
* 0042FB88 8B76 04 MOV ESI,DWORD PTR DS:[ESI+0x4]
* 0042FB8B 8B3D E8234A00 MOV EDI,DWORD PTR DS:[0x4A23E8]
* 0042FB91 3BF3 CMP ESI,EBX
* 0042FB93 7C 08 JL SHORT lcsebody.0042FB9D
* 0042FB95 39B7 60290000 CMP DWORD PTR DS:[EDI+0x2960],ESI
* 0042FB9B 7F 12 JG SHORT lcsebody.0042FBAF
* 0042FB9D 53 PUSH EBX
* 0042FB9E 68 20F54800 PUSH lcsebody.0048F520 ; ASCII "err"
* 0042FBA3 68 F4F44800 PUSH lcsebody.0048F4F4
* 0042FBA8 53 PUSH EBX
* 0042FBA9 FF15 EC874A00 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; user32.MessageBoxA
* 0042FBAF 8B87 80290000 MOV EAX,DWORD PTR DS:[EDI+0x2980]
* 0042FBB5 8D34F0 LEA ESI,DWORD PTR DS:[EAX+ESI*8]
* 0042FBB8 8B06 MOV EAX,DWORD PTR DS:[ESI]
* 0042FBBA 50 PUSH EAX
* 0042FBBB 894424 10 MOV DWORD PTR SS:[ESP+0x10],EAX
* 0042FBBF E8 5E840000 CALL lcsebody.00438022
* 0042FBC4 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+0x10]
* 0042FBC8 83C4 04 ADD ESP,0x4
* 0042FBCB 8BD1 MOV EDX,ECX
* 0042FBCD 894424 10 MOV DWORD PTR SS:[ESP+0x10],EAX
* 0042FBD1 8B76 04 MOV ESI,DWORD PTR DS:[ESI+0x4]
* 0042FBD4 8BF8 MOV EDI,EAX
* 0042FBD6 C1E9 02 SHR ECX,0x2
* 0042FBD9 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
* 0042FBDB 8BCA MOV ECX,EDX
* 0042FBDD EB 4D JMP SHORT lcsebody.0042FC2C
* 0042FBDF 83F8 02 CMP EAX,0x2 ; jichi: esi=arg1 jumped here
* 0042FBE2 0F85 A2000000 JNZ lcsebody.0042FC8A
* 0042FBE8 A1 E8234A00 MOV EAX,DWORD PTR DS:[0x4A23E8] ; jichi: text length here
* 0042FBED 8B56 04 MOV EDX,DWORD PTR DS:[ESI+0x4]
* 0042FBF0 8B88 44290000 MOV ECX,DWORD PTR DS:[EAX+0x2944]
* 0042FBF6 8B0411 MOV EAX,DWORD PTR DS:[ECX+EDX]
*
* 0042FBF9 50 PUSH EAX ; jichi: hook1, text length pushed, new function
* 0042FBFA 894424 10 MOV DWORD PTR SS:[ESP+0x10],EAX ; jichi: text length, is this the memory allocation
* 0042FBFE E8 1F840000 CALL lcsebody.00438022
*
* 0042FC03 8B15 E8234A00 MOV EDX,DWORD PTR DS:[0x4A23E8] ; jichi: text here
* 0042FC09 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+0x10] ; jichi: count is here
* 0042FC0D 8B76 04 MOV ESI,DWORD PTR DS:[ESI+0x4] ; jichi: [arg1+4]
* 0042FC10 894424 14 MOV DWORD PTR SS:[ESP+0x14],EAX
* 0042FC14 8B92 44290000 MOV EDX,DWORD PTR DS:[EDX+0x2944] ; jichi: base addr, [[0x4A23E8] + 0x2944]
* 0042FC1A 8BF8 MOV EDI,EAX
* 0042FC1C 8BC1 MOV EAX,ECX
* 0042FC1E 83C4 04 ADD ESP,0x4
*
* 0042FC21 8D7432 04 LEA ESI,DWORD PTR DS:[EDX+ESI+0x4] ; jichi: hook2, text in esi
* 0042FC25 C1E9 02 SHR ECX,0x2 ; jichi: ecx is now the count, here, the rep function is blocked by 4 for performance
* 0042FC28 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS[ESI] ; jichi: text accessed here from esi to edi
*
* 0042FC2A 8BC8 MOV ECX,EAX
* 0042FC2C 8B5424 28 MOV EDX,DWORD PTR SS:[ESP+0x28]
* 0042FC30 83E1 03 AND ECX,0x3
* 0042FC33 F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
* 0042FC35 8B4C24 2C MOV ECX,DWORD PTR SS:[ESP+0x2C]
* 0042FC39 8D4424 0C LEA EAX,DWORD PTR SS:[ESP+0xC]
* 0042FC3D 51 PUSH ECX
* 0042FC3E 52 PUSH EDX
* 0042FC3F 50 PUSH EAX
* 0042FC40 E8 AB14FDFF CALL lcsebody.004010F0
* 0042FC45 83C4 0C ADD ESP,0xC
* 0042FC48 C74424 1C FFFFFF>MOV DWORD PTR SS:[ESP+0x1C],-0x1
* 0042FC50 84C0 TEST AL,AL
* 0042FC52 8B4424 10 MOV EAX,DWORD PTR SS:[ESP+0x10]
* 0042FC56 895C24 0C MOV DWORD PTR SS:[ESP+0xC],EBX
* 0042FC5A 74 21 JE SHORT lcsebody.0042FC7D
* 0042FC5C 3BC3 CMP EAX,EBX
* 0042FC5E 74 09 JE SHORT lcsebody.0042FC69
* 0042FC60 50 PUSH EAX
* 0042FC61 E8 467E0000 CALL lcsebody.00437AAC
* 0042FC66 83C4 04 ADD ESP,0x4
* 0042FC69 5F POP EDI
* 0042FC6A 5E POP ESI
* 0042FC6B B0 01 MOV AL,0x1
* 0042FC6D 5B POP EBX
* 0042FC6E 8B4C24 08 MOV ECX,DWORD PTR SS:[ESP+0x8]
* 0042FC72 64:890D 00000000 MOV DWORD PTR FS:[0],ECX
* 0042FC79 83C4 14 ADD ESP,0x14
* 0042FC7C C3 RETN
* 0042FC7D 3BC3 CMP EAX,EBX
* 0042FC7F 74 09 JE SHORT lcsebody.0042FC8A
* 0042FC81 50 PUSH EAX
* 0042FC82 E8 257E0000 CALL lcsebody.00437AAC
* 0042FC87 83C4 04 ADD ESP,0x4
* 0042FC8A 8B4C24 14 MOV ECX,DWORD PTR SS:[ESP+0x14]
* 0042FC8E 5F POP EDI
* 0042FC8F 5E POP ESI
* 0042FC90 32C0 XOR AL,AL
* 0042FC92 5B POP EBX
* 0042FC93 64:890D 00000000 MOV DWORD PTR FS:[0],ECX
* 0042FC9A 83C4 14 ADD ESP,0x14
* 0042FC9D C3 RETN
* 0042FC9E 90 NOP
* 0042FC9F 90 NOP
* 0042FCA0 CC INT3
* 0042FCA1 CC INT3
* 0042FCA2 CC INT3
* 0042FCA3 CC INT3
* 0042FCA4 CC INT3
* 0042FCA5 CC INT3
* 0042FCA6 CC INT3
*
* Sample game:
*
* 00430CAB CC INT3
* 00430CAC CC INT3
* 00430CAD CC INT3
* 00430CAE CC INT3
* 00430CAF CC INT3
* 00430CB0 6A FF PUSH -0x1
* 00430CB2 68 08204800 PUSH .00482008
* 00430CB7 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
* 00430CBD 50 PUSH EAX
* 00430CBE 64:8925 00000000 MOV DWORD PTR FS:[0],ESP
* 00430CC5 83EC 08 SUB ESP,0x8
* 00430CC8 53 PUSH EBX
* 00430CC9 33DB XOR EBX,EBX
* 00430CCB 56 PUSH ESI
* 00430CCC 57 PUSH EDI
* 00430CCD 895C24 0C MOV DWORD PTR SS:[ESP+0xC],EBX
* 00430CD1 895C24 10 MOV DWORD PTR SS:[ESP+0x10],EBX
* 00430CD5 8B7424 24 MOV ESI,DWORD PTR SS:[ESP+0x24]
* 00430CD9 895C24 1C MOV DWORD PTR SS:[ESP+0x1C],EBX
* 00430CDD 8B06 MOV EAX,DWORD PTR DS:[ESI]
* 00430CDF 83F8 05 CMP EAX,0x5
* 00430CE2 75 2F JNZ SHORT .00430D13
* 00430CE4 8B76 04 MOV ESI,DWORD PTR DS:[ESI+0x4]
* 00430CE7 8B3D 9C4E4A00 MOV EDI,DWORD PTR DS:[0x4A4E9C]
* 00430CED 3BF3 CMP ESI,EBX
* 00430CEF 7C 08 JL SHORT .00430CF9
* 00430CF1 39B7 54310000 CMP DWORD PTR DS:[EDI+0x3154],ESI
* 00430CF7 7F 12 JG SHORT .00430D0B
* 00430CF9 53 PUSH EBX
* 00430CFA 68 98154900 PUSH .00491598 ; ASCII "err"
* 00430CFF 68 D8254900 PUSH .004925D8
* 00430D04 53 PUSH EBX
* 00430D05 FF15 2CC84A00 CALL DWORD PTR DS:[0x4AC82C] ; user32.MessageBoxA
* 00430D0B 8B87 74310000 MOV EAX,DWORD PTR DS:[EDI+0x3174]
* 00430D11 EB 32 JMP SHORT .00430D45
* 00430D13 83F8 08 CMP EAX,0x8
* 00430D16 75 57 JNZ SHORT .00430D6F
* 00430D18 8B76 04 MOV ESI,DWORD PTR DS:[ESI+0x4]
* 00430D1B 8B3D 9C4E4A00 MOV EDI,DWORD PTR DS:[0x4A4E9C]
* 00430D21 3BF3 CMP ESI,EBX
* 00430D23 7C 08 JL SHORT .00430D2D
* 00430D25 39B7 60310000 CMP DWORD PTR DS:[EDI+0x3160],ESI
* 00430D2B 7F 12 JG SHORT .00430D3F
* 00430D2D 53 PUSH EBX
* 00430D2E 68 98154900 PUSH .00491598 ; ASCII "err"
* 00430D33 68 AC254900 PUSH .004925AC
* 00430D38 53 PUSH EBX
* 00430D39 FF15 2CC84A00 CALL DWORD PTR DS:[0x4AC82C] ; user32.MessageBoxA
* 00430D3F 8B87 80310000 MOV EAX,DWORD PTR DS:[EDI+0x3180]
* 00430D45 8D34F0 LEA ESI,DWORD PTR DS:[EAX+ESI*8]
* 00430D48 8B06 MOV EAX,DWORD PTR DS:[ESI]
* 00430D4A 50 PUSH EAX
* 00430D4B 894424 10 MOV DWORD PTR SS:[ESP+0x10],EAX
* 00430D4F E8 BE890000 CALL .00439712
* 00430D54 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+0x10]
* 00430D58 83C4 04 ADD ESP,0x4
* 00430D5B 8BD1 MOV EDX,ECX
* 00430D5D 894424 10 MOV DWORD PTR SS:[ESP+0x10],EAX
* 00430D61 8B76 04 MOV ESI,DWORD PTR DS:[ESI+0x4]
* 00430D64 8BF8 MOV EDI,EAX
* 00430D66 C1E9 02 SHR ECX,0x2
* 00430D69 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
* 00430D6B 8BCA MOV ECX,EDX
* 00430D6D EB 4D JMP SHORT .00430DBC
* 00430D6F 83F8 02 CMP EAX,0x2
* 00430D72 0F85 A2000000 JNZ .00430E1A
* 00430D78 A1 9C4E4A00 MOV EAX,DWORD PTR DS:[0x4A4E9C]
* 00430D7D 8B56 04 MOV EDX,DWORD PTR DS:[ESI+0x4]
* 00430D80 8B88 44310000 MOV ECX,DWORD PTR DS:[EAX+0x3144]
* 00430D86 8B0411 MOV EAX,DWORD PTR DS:[ECX+EDX]
* 00430D89 50 PUSH EAX
* 00430D8A 894424 10 MOV DWORD PTR SS:[ESP+0x10],EAX
* 00430D8E E8 7F890000 CALL .00439712
* 00430D93 8B15 9C4E4A00 MOV EDX,DWORD PTR DS:[0x4A4E9C]
* 00430D99 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+0x10]
* 00430D9D 8B76 04 MOV ESI,DWORD PTR DS:[ESI+0x4]
* 00430DA0 894424 14 MOV DWORD PTR SS:[ESP+0x14],EAX
* 00430DA4 8B92 44310000 MOV EDX,DWORD PTR DS:[EDX+0x3144]
* 00430DAA 8BF8 MOV EDI,EAX
* 00430DAC 8BC1 MOV EAX,ECX
* 00430DAE 83C4 04 ADD ESP,0x4
* 00430DB1 8D7432 04 LEA ESI,DWORD PTR DS:[EDX+ESI+0x4] ; jichi: the other game's access point
* 00430DB5 C1E9 02 SHR ECX,0x2
* 00430DB8 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
* 00430DBA 8BC8 MOV ECX,EAX
* 00430DBC 8B5424 28 MOV EDX,DWORD PTR SS:[ESP+0x28]
* 00430DC0 83E1 03 AND ECX,0x3
* 00430DC3 F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
* 00430DC5 8B4C24 2C MOV ECX,DWORD PTR SS:[ESP+0x2C]
* 00430DC9 8D4424 0C LEA EAX,DWORD PTR SS:[ESP+0xC]
* 00430DCD 51 PUSH ECX
* 00430DCE 52 PUSH EDX
* 00430DCF 50 PUSH EAX
* 00430DD0 E8 2503FDFF CALL .004010FA
* 00430DD5 83C4 0C ADD ESP,0xC
* 00430DD8 C74424 1C FFFFFF>MOV DWORD PTR SS:[ESP+0x1C],-0x1
* 00430DE0 84C0 TEST AL,AL
* 00430DE2 8B4424 10 MOV EAX,DWORD PTR SS:[ESP+0x10]
* 00430DE6 895C24 0C MOV DWORD PTR SS:[ESP+0xC],EBX
* 00430DEA 74 21 JE SHORT .00430E0D
* 00430DEC 3BC3 CMP EAX,EBX
* 00430DEE 74 09 JE SHORT .00430DF9
* 00430DF0 50 PUSH EAX
* 00430DF1 E8 A6830000 CALL .0043919C
* 00430DF6 83C4 04 ADD ESP,0x4
* 00430DF9 5F POP EDI
* 00430DFA 5E POP ESI
* 00430DFB B0 01 MOV AL,0x1
* 00430DFD 5B POP EBX
* 00430DFE 8B4C24 08 MOV ECX,DWORD PTR SS:[ESP+0x8]
* 00430E02 64:890D 00000000 MOV DWORD PTR FS:[0],ECX
* 00430E09 83C4 14 ADD ESP,0x14
* 00430E0C C3 RETN
* 00430E0D 3BC3 CMP EAX,EBX
* 00430E0F 74 09 JE SHORT .00430E1A
* 00430E11 50 PUSH EAX
* 00430E12 E8 85830000 CALL .0043919C
* 00430E17 83C4 04 ADD ESP,0x4
* 00430E1A 8B4C24 14 MOV ECX,DWORD PTR SS:[ESP+0x14]
* 00430E1E 5F POP EDI
* 00430E1F 5E POP ESI
* 00430E20 32C0 XOR AL,AL
* 00430E22 5B POP EBX
* 00430E23 64:890D 00000000 MOV DWORD PTR FS:[0],ECX
* 00430E2A 83C4 14 ADD ESP,0x14
* 00430E2D C3 RETN
* 00430E2E 90 NOP
* 00430E2F 90 NOP
* 00430E30 CC INT3
* 00430E31 CC INT3
* 00430E32 CC INT3
* 00430E33 CC INT3
* 00430E34 CC INT3
*/
bool isLeadByteChar(const char *s)
{
return dynsjis::isleadstr(s);
//return ::IsDBCSLeadByte(HIBYTE(testChar));
}
bool attach(ULONG startAddress, ULONG stopAddress,ULONG dyna)
{
const uint8_t bytes[] = {
0x8d,0x74,0x32, 0x04, // 0042fc21 8d7432 04 lea esi,dword ptr ds:[edx+esi+0x4]
0xc1,0xe9, 0x02, // 0042fc25 c1e9 02 shr ecx,0x2
0xf3,0xa5 // 0042fc28 f3:a5 rep movs dword ptr es:[edi],dword ptr ds[esi] ; jichi: text accessed here from esi to edi
};
ULONG addr2 = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
if (!addr2)
return false;
// 0042FBF9 50 PUSH EAX ; jichi: hook1, text length pushed, new function
// 0042FBFA 894424 10 MOV DWORD PTR SS:[ESP+0x10],EAX ; jichi: text length, is this the memory allocation?
// 0042FBFE E8 1F840000 CALL lcsebody.00438022
// 0042FC03 8B15 E8234A00 MOV EDX,DWORD PTR DS:[0x4A23E8] ; jichi: text here
// 0042FC09 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+0x10] ; jichi: count is here
// 0042FC0D 8B76 04 MOV ESI,DWORD PTR DS:[ESI+0x4] ; jichi: [arg1+4]
// 0042FC10 894424 14 MOV DWORD PTR SS:[ESP+0x14],EAX
// 0042FC14 8B92 44290000 MOV EDX,DWORD PTR DS:[EDX+0x2944] ; jichi: base addr, [[0x4A23E8] + 0x2944]
// 0042FC1A 8BF8 MOV EDI,EAX
// 0042FC1C 8BC1 MOV EAX,ECX
// 0042FC1E 83C4 04 ADD ESP,0x4
//
// 0042FC21 8D7432 04 LEA ESI,DWORD PTR DS:[EDX+ESI+0x4] ; jichi: hook2, text in esi
// 0042FC25 C1E9 02 SHR ECX,0x2 ; jichi: ecx is now the count, here, the rep function is blocked by 4 for performance
// 0042FC28 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS[ESI] ; jichi: text accessed here from esi to edi
ULONG addr1 = addr2 + 0x0042fbf9 - 0x0042fc21;
if (*(BYTE *)addr1 != 0x50) // push_eax
return false;
// 0042FC03 8B15 E8234A00 MOV EDX,DWORD PTR DS:[0x4A23E8] ; jichi: text here
// 0042FC09 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+0x10] ; jichi: count is here
// 0042FC0D 8B76 04 MOV ESI,DWORD PTR DS:[ESI+0x4] ; jichi: [arg1+4]
// 0042FC10 894424 14 MOV DWORD PTR SS:[ESP+0x14],EAX
// 0042FC14 8B92 44290000 MOV EDX,DWORD PTR DS:[EDX+0x2944] ; jichi: offset addr, [[0x4A23E8] + 0x2944]
{
ULONG addr = addr2 + 0x0042fc03 - 0x0042fc21;
if (*(WORD *)addr != 0x158b) // 0042FC03 8B15 E8234A00 MOV EDX,DWORD PTR DS:[0x4A23E8]
return false;
addr += 2;
Private::textBaseAddress_ = *(DWORD *)addr;
}
{
ULONG addr = addr2 + 0x0042fc14 - 0x0042fc21;
if (*(WORD *)addr != 0x928b) // 0042FC14 8B92 44290000 MOV EDX,DWORD PTR DS:[EDX+0x2944]
return false;
addr += 2;
Private::textOffset_ = *(DWORD *)addr;
}
HookParam hp;
hp.address=addr1;
hp.hook_before=Private::hook1;
hp.hook_after=Private::hookafter;
hp.type=EMBED_ABLE;
hp.newlineseperator=L"\x01";
hp.hook_font=F_GetGlyphOutlineA;
if(dyna){
static ULONG dynas;
dynas=dyna;
hp.type|=EMBED_DYNA_SJIS;
hp.hook_font=F_GetGlyphOutlineA;
patch_fun=[](){
ReplaceFunction((PVOID*)&dynas, (PVOID)(ULONG)isLeadByteChar);
dynamiccodec->setMinimumSecondByte(6);//// skip 0x1,0x2,0x3 in case dynamic encoding could crash the game
};
}
auto succ=NewHook(hp,"EmbedLCSE");
hp.address=addr2+4;
hp.hook_before=Private::hook2;
hp.type=EMBED_ABLE|HOOK_EMPTY;
succ|=NewHook(hp,"EmbedLCSE");
return succ;
}
} // namespace ScenarioHook
namespace Patch {
namespace Private {
bool isLeadByteChar(const char *s)
{
return dynsjis::isleadstr(s);
//return ::IsDBCSLeadByte(HIBYTE(testChar));
}
} // namespace Private
/**
* Sample game:
*
* Debugging method: Find text in memory, and then insert hardware breakpoint.
* It will be accessed only ONCE in the following function.
*
* This function can also be found by searching the following instruction:
* 0040A389 3C 81 CMP AL,0x81
*
* This function is very similar to that in CatSystem2.
*
* 0040A37E CC INT3
* 0040A37F CC INT3
* 0040A380 8B4C24 04 MOV ECX,DWORD PTR SS:[ESP+0x4]
* 0040A384 8A01 MOV AL,BYTE PTR DS:[ECX] ; jichi: first byte
* 0040A386 8A49 01 MOV CL,BYTE PTR DS:[ECX+0x1] ; jichi: second byte
* 0040A389 3C 81 CMP AL,0x81
* 0040A38B 72 04 JB SHORT lcsebody.0040A391
* 0040A38D 3C 9F CMP AL,0x9F
* 0040A38F 76 08 JBE SHORT lcsebody.0040A399
* 0040A391 3C E0 CMP AL,0xE0
* 0040A393 72 1B JB SHORT lcsebody.0040A3B0
* 0040A395 3C FC CMP AL,0xFC
* 0040A397 77 17 JA SHORT lcsebody.0040A3B0
* 0040A399 80F9 40 CMP CL,0x40
* 0040A39C 72 05 JB SHORT lcsebody.0040A3A3
* 0040A39E 80F9 7E CMP CL,0x7E
* 0040A3A1 76 0A JBE SHORT lcsebody.0040A3AD
* 0040A3A3 80F9 80 CMP CL,0x80
* 0040A3A6 72 08 JB SHORT lcsebody.0040A3B0
* 0040A3A8 80F9 FC CMP CL,0xFC
* 0040A3AB 77 03 JA SHORT lcsebody.0040A3B0
* 0040A3AD B0 01 MOV AL,0x1
* 0040A3AF C3 RETN
* 0040A3B0 32C0 XOR AL,AL
* 0040A3B2 C3 RETN
* 0040A3B3 90 NOP
* 0040A3B4 90 NOP
* 0040A3B5 90 NOP
* 0040A3B6 90 NOP
*
* This function is found by tracing the caller of GetGlyphOutlineA, as follows:
*
* 00416B6B CC INT3
* 00416B6C CC INT3
* 00416B6D CC INT3
* 00416B6E CC INT3
* 00416B6F CC INT3
* 00416B70 83EC 08 SUB ESP,0x8
* 00416B73 53 PUSH EBX
* 00416B74 56 PUSH ESI
* 00416B75 8BF1 MOV ESI,ECX
* 00416B77 33DB XOR EBX,EBX ; jichi: zero ebx
* 00416B79 57 PUSH EDI
* 00416B7A 8B86 EC000000 MOV EAX,DWORD PTR DS:[ESI+0xEC]
* 00416B80 8A9430 08010000 MOV DL,BYTE PTR DS:[EAX+ESI+0x108] ; jichi: byte accessed here
* 00416B87 8D8C30 08010000 LEA ECX,DWORD PTR DS:[EAX+ESI+0x108] ; jichi: byte accessed here
* 00416B8E 3AD3 CMP DL,BL ; jichi: bl is zero, dl is the current byte
* 00416B90 75 0C JNZ SHORT lcsebody.00416B9E
* 00416B92 B8 FF000000 MOV EAX,0xFF
* 00416B97 5F POP EDI
* 00416B98 5E POP ESI
* 00416B99 5B POP EBX
* 00416B9A 83C4 08 ADD ESP,0x8
* 00416B9D C3 RETN
* 00416B9E 8B96 F0000000 MOV EDX,DWORD PTR DS:[ESI+0xF0]
* 00416BA4 4A DEC EDX
* 00416BA5 3BC2 CMP EAX,EDX
* 00416BA7 0F8D 31010000 JGE lcsebody.00416CDE
* 00416BAD 51 PUSH ECX
* 00416BAE E8 31B1FEFF CALL lcsebody.00401CE4 ; jichi: ecx point to the current character, return 0 or 1
* 00416BB3 83C4 04 ADD ESP,0x4
* 00416BB6 84C0 TEST AL,AL
* 00416BB8 0F84 20010000 JE lcsebody.00416CDE ; jichi: wrong here
* 00416BBE 8B86 EC000000 MOV EAX,DWORD PTR DS:[ESI+0xEC]
* 00416BC4 33C9 XOR ECX,ECX
* 00416BC6 03C6 ADD EAX,ESI
* 00416BC8 889E 20050000 MOV BYTE PTR DS:[ESI+0x520],BL
* 00416BCE 8AA8 08010000 MOV CH,BYTE PTR DS:[EAX+0x108] ; jichi: high bits
* 00416BD4 8A88 09010000 MOV CL,BYTE PTR DS:[EAX+0x109]
* 00416BDA 8BF9 MOV EDI,ECX ; jichi: low bits, edi is now the full character
* 00416BDC 8BCE MOV ECX,ESI ; jichi: recover ecx to esi
* 00416BDE E8 13AEFEFF CALL lcsebody.004019F6 ; jichi: eax is zero when edi is legal
* 00416BE3 3BC3 CMP EAX,EBX ; jichi: ebx is always zero as well
* 00416BE5 74 4A JE SHORT lcsebody.00416C31
* 00416BE7 389E 2C050000 CMP BYTE PTR DS:[ESI+0x52C],BL
* 00416BED 0F84 9A020000 JE lcsebody.00416E8D
* 00416BF3 389E 20050000 CMP BYTE PTR DS:[ESI+0x520],BL
* 00416BF9 74 1B JE SHORT lcsebody.00416C16
* 00416BFB B9 34F14800 MOV ECX,lcsebody.0048F134
* 00416C00 3B39 CMP EDI,DWORD PTR DS:[ECX]
* 00416C02 74 2D JE SHORT lcsebody.00416C31
* 00416C04 83C1 04 ADD ECX,0x4
* 00416C07 81F9 50F14800 CMP ECX,lcsebody.0048F150
* 00416C0D ^7C F1 JL SHORT lcsebody.00416C00
* 00416C0F 5F POP EDI
* 00416C10 5E POP ESI
* 00416C11 5B POP EBX
* 00416C12 83C4 08 ADD ESP,0x8
* 00416C15 C3 RETN
* 00416C16 B9 00F14800 MOV ECX,lcsebody.0048F100
* 00416C1B 3B39 CMP EDI,DWORD PTR DS:[ECX]
* 00416C1D 74 12 JE SHORT lcsebody.00416C31
* 00416C1F 83C1 04 ADD ECX,0x4
* 00416C22 81F9 34F14800 CMP ECX,lcsebody.0048F134
* 00416C28 ^7C F1 JL SHORT lcsebody.00416C1B
* 00416C2A 5F POP EDI
* 00416C2B 5E POP ESI
* 00416C2C 5B POP EBX
* 00416C2D 83C4 08 ADD ESP,0x8
* 00416C30 C3 RETN
* 00416C31 8A8E 20050000 MOV CL,BYTE PTR DS:[ESI+0x520]
* 00416C37 3ACB CMP CL,BL
* 00416C39 74 15 JE SHORT lcsebody.00416C50
* 00416C3B B8 70F14800 MOV EAX,lcsebody.0048F170
* 00416C40 3B38 CMP EDI,DWORD PTR DS:[EAX]
* 00416C42 74 21 JE SHORT lcsebody.00416C65
* 00416C44 83C0 04 ADD EAX,0x4
* 00416C47 3D 7CF14800 CMP EAX,lcsebody.0048F17C
* 00416C4C ^7C F2 JL SHORT lcsebody.00416C40
* 00416C4E EB 1B JMP SHORT lcsebody.00416C6B
* 00416C50 B8 50F14800 MOV EAX,lcsebody.0048F150
* 00416C55 3B38 CMP EDI,DWORD PTR DS:[EAX] ; jichi: compare current wide character with a threshold (0x8169 = "")
* 00416C57 74 0C JE SHORT lcsebody.00416C65
* 00416C59 83C0 04 ADD EAX,0x4
* 00416C5C 3D 70F14800 CMP EAX,lcsebody.0048F170
* 00416C61 ^7C F2 JL SHORT lcsebody.00416C55
* 00416C63 EB 06 JMP SHORT lcsebody.00416C6B
* 00416C65 FF86 24050000 INC DWORD PTR DS:[ESI+0x524]
* 00416C6B 3ACB CMP CL,BL
* 00416C6D 74 15 JE SHORT lcsebody.00416C84
* 00416C6F B8 9CF14800 MOV EAX,lcsebody.0048F19C
* 00416C74 3B38 CMP EDI,DWORD PTR DS:[EAX]
* 00416C76 74 21 JE SHORT lcsebody.00416C99
* 00416C78 83C0 04 ADD EAX,0x4
* 00416C7B 3D A8F14800 CMP EAX,lcsebody.0048F1A8
* 00416C80 ^7C F2 JL SHORT lcsebody.00416C74
* 00416C82 EB 2A JMP SHORT lcsebody.00416CAE
* 00416C84 B8 7CF14800 MOV EAX,lcsebody.0048F17C
* 00416C89 3B38 CMP EDI,DWORD PTR DS:[EAX]
* 00416C8B 74 0C JE SHORT lcsebody.00416C99
* 00416C8D 83C0 04 ADD EAX,0x4
* 00416C90 3D 9CF14800 CMP EAX,lcsebody.0048F19C
* 00416C95 ^7C F2 JL SHORT lcsebody.00416C89
* 00416C97 EB 15 JMP SHORT lcsebody.00416CAE
* 00416C99 8B86 24050000 MOV EAX,DWORD PTR DS:[ESI+0x524]
* 00416C9F 48 DEC EAX
* 00416CA0 8986 24050000 MOV DWORD PTR DS:[ESI+0x524],EAX
* 00416CA6 79 06 JNS SHORT lcsebody.00416CAE
* 00416CA8 899E 24050000 MOV DWORD PTR DS:[ESI+0x524],EBX
* 00416CAE 57 PUSH EDI
* 00416CAF 8BCE MOV ECX,ESI
* 00416CB1 E8 20A5FEFF CALL lcsebody.004011D6
* 00416CB6 8B86 EC000000 MOV EAX,DWORD PTR DS:[ESI+0xEC]
* 00416CBC 8A9430 08010000 MOV DL,BYTE PTR DS:[EAX+ESI+0x108]
* 00416CC3 83C0 02 ADD EAX,0x2
* 00416CC6 885424 0C MOV BYTE PTR SS:[ESP+0xC],DL
* 00416CCA 8A8C30 07010000 MOV CL,BYTE PTR DS:[EAX+ESI+0x107]
* 00416CD1 884C24 0D MOV BYTE PTR SS:[ESP+0xD],CL
* 00416CD5 885C24 0E MOV BYTE PTR SS:[ESP+0xE],BL
* 00416CD9 E9 77010000 JMP lcsebody.00416E55
* 00416CDE 8B96 EC000000 MOV EDX,DWORD PTR DS:[ESI+0xEC]
* 00416CE4 C686 20050000 01 MOV BYTE PTR DS:[ESI+0x520],0x1
* 00416CEB 8A8C16 08010000 MOV CL,BYTE PTR DS:[ESI+EDX+0x108]
* 00416CF2 8D8416 08010000 LEA EAX,DWORD PTR DS:[ESI+EDX+0x108]
* 00416CF9 80F9 1F CMP CL,0x1F
* 00416CFC 77 54 JA SHORT lcsebody.00416D52
* 00416CFE 80F9 03 CMP CL,0x3
* 00416D01 75 06 JNZ SHORT lcsebody.00416D09
* 00416D03 899E 28050000 MOV DWORD PTR DS:[ESI+0x528],EBX
* 00416D09 8A00 MOV AL,BYTE PTR DS:[EAX]
* 00416D0B 83EC 0C SUB ESP,0xC
* 00416D0E 8D5424 18 LEA EDX,DWORD PTR SS:[ESP+0x18]
* 00416D12 8BCC MOV ECX,ESP
* 00416D14 896424 1C MOV DWORD PTR SS:[ESP+0x1C],ESP
* 00416D18 8DBE FC000000 LEA EDI,DWORD PTR DS:[ESI+0xFC]
* 00416D1E 52 PUSH EDX
* 00416D1F 51 PUSH ECX
* 00416D20 8BCF MOV ECX,EDI
* 00416D22 884424 20 MOV BYTE PTR SS:[ESP+0x20],AL
* 00416D26 885C24 21 MOV BYTE PTR SS:[ESP+0x21],BL
* 00416D2A E8 D0A8FEFF CALL lcsebody.004015FF
* 00416D2F 8BCF MOV ECX,EDI
* 00416D31 E8 A1A8FEFF CALL lcsebody.004015D7
* 00416D36 8B8E EC000000 MOV ECX,DWORD PTR DS:[ESI+0xEC]
* 00416D3C 0FBE8431 0801000> MOVSX EAX,BYTE PTR DS:[ECX+ESI+0x108]
* 00416D44 41 INC ECX
* 00416D45 898E EC000000 MOV DWORD PTR DS:[ESI+0xEC],ECX
* 00416D4B 5F POP EDI
* 00416D4C 5E POP ESI
* 00416D4D 5B POP EBX
* 00416D4E 83C4 08 ADD ESP,0x8
* 00416D51 C3 RETN
* 00416D52 8BCE MOV ECX,ESI
* 00416D54 E8 9DACFEFF CALL lcsebody.004019F6
* 00416D59 3BC3 CMP EAX,EBX
* 00416D5B 74 4A JE SHORT lcsebody.00416DA7
* 00416D5D 389E 2C050000 CMP BYTE PTR DS:[ESI+0x52C],BL
* 00416D63 0F84 24010000 JE lcsebody.00416E8D
* 00416D69 389E 20050000 CMP BYTE PTR DS:[ESI+0x520],BL
* 00416D6F 74 1B JE SHORT lcsebody.00416D8C
* 00416D71 B9 34F14800 MOV ECX,lcsebody.0048F134
* 00416D76 3919 CMP DWORD PTR DS:[ECX],EBX
* 00416D78 74 2D JE SHORT lcsebody.00416DA7
* 00416D7A 83C1 04 ADD ECX,0x4
* 00416D7D 81F9 50F14800 CMP ECX,lcsebody.0048F150
* 00416D83 ^7C F1 JL SHORT lcsebody.00416D76
* 00416D85 5F POP EDI
* 00416D86 5E POP ESI
* 00416D87 5B POP EBX
* 00416D88 83C4 08 ADD ESP,0x8
* 00416D8B C3 RETN
* 00416D8C B9 00F14800 MOV ECX,lcsebody.0048F100
* 00416D91 3919 CMP DWORD PTR DS:[ECX],EBX
* 00416D93 74 12 JE SHORT lcsebody.00416DA7
* 00416D95 83C1 04 ADD ECX,0x4
* 00416D98 81F9 34F14800 CMP ECX,lcsebody.0048F134
* 00416D9E ^7C F1 JL SHORT lcsebody.00416D91
* 00416DA0 5F POP EDI
* 00416DA1 5E POP ESI
* 00416DA2 5B POP EBX
* 00416DA3 83C4 08 ADD ESP,0x8
* 00416DA6 C3 RETN
* 00416DA7 8B86 EC000000 MOV EAX,DWORD PTR DS:[ESI+0xEC]
* 00416DAD 8A96 20050000 MOV DL,BYTE PTR DS:[ESI+0x520]
* 00416DB3 0FBEBC06 08010000 MOVSX EDI,BYTE PTR DS:[ESI+EAX+0x108] ; jichi: edi get assigned to the illegal character
* 00416DBB 8BCF MOV ECX,EDI
* 00416DBD C1E1 08 SHL ECX,0x8
* 00416DC0 3AD3 CMP DL,BL
* 00416DC2 74 15 JE SHORT lcsebody.00416DD9
* 00416DC4 B8 70F14800 MOV EAX,lcsebody.0048F170
* 00416DC9 3B08 CMP ECX,DWORD PTR DS:[EAX]
* 00416DCB 74 21 JE SHORT lcsebody.00416DEE
* 00416DCD 83C0 04 ADD EAX,0x4
* 00416DD0 3D 7CF14800 CMP EAX,lcsebody.0048F17C
* 00416DD5 ^7C F2 JL SHORT lcsebody.00416DC9
* 00416DD7 EB 1B JMP SHORT lcsebody.00416DF4
* 00416DD9 B8 50F14800 MOV EAX,lcsebody.0048F150
* 00416DDE 3B08 CMP ECX,DWORD PTR DS:[EAX]
* 00416DE0 74 0C JE SHORT lcsebody.00416DEE
* 00416DE2 83C0 04 ADD EAX,0x4
* 00416DE5 3D 70F14800 CMP EAX,lcsebody.0048F170
* 00416DEA ^7C F2 JL SHORT lcsebody.00416DDE
* 00416DEC EB 06 JMP SHORT lcsebody.00416DF4
* 00416DEE FF86 24050000 INC DWORD PTR DS:[ESI+0x524]
* 00416DF4 3AD3 CMP DL,BL
* 00416DF6 74 15 JE SHORT lcsebody.00416E0D
* 00416DF8 B8 9CF14800 MOV EAX,lcsebody.0048F19C
* 00416DFD 3B08 CMP ECX,DWORD PTR DS:[EAX]
* 00416DFF 74 21 JE SHORT lcsebody.00416E22
* 00416E01 83C0 04 ADD EAX,0x4
* 00416E04 3D A8F14800 CMP EAX,lcsebody.0048F1A8
* 00416E09 ^7C F2 JL SHORT lcsebody.00416DFD
* 00416E0B EB 2A JMP SHORT lcsebody.00416E37
* 00416E0D B8 7CF14800 MOV EAX,lcsebody.0048F17C
* 00416E12 3B08 CMP ECX,DWORD PTR DS:[EAX]
* 00416E14 74 0C JE SHORT lcsebody.00416E22
* 00416E16 83C0 04 ADD EAX,0x4
* 00416E19 3D 9CF14800 CMP EAX,lcsebody.0048F19C
* 00416E1E ^7C F2 JL SHORT lcsebody.00416E12
* 00416E20 EB 15 JMP SHORT lcsebody.00416E37
* 00416E22 8B86 24050000 MOV EAX,DWORD PTR DS:[ESI+0x524]
* 00416E28 48 DEC EAX
* 00416E29 8986 24050000 MOV DWORD PTR DS:[ESI+0x524],EAX
* 00416E2F 79 06 JNS SHORT lcsebody.00416E37
* 00416E31 899E 24050000 MOV DWORD PTR DS:[ESI+0x524],EBX
* 00416E37 57 PUSH EDI ; jichi: invalid character
* 00416E38 8BCE MOV ECX,ESI
* 00416E3A E8 97A3FEFF CALL lcsebody.004011D6 ; jichi: char in arg1
* 00416E3F 8B86 EC000000 MOV EAX,DWORD PTR DS:[ESI+0xEC]
*/
ULONG patchEncoding(ULONG startAddress, ULONG stopAddress)
{
const uint8_t bytes[] = {
0x8b,0x4c,0x24, 0x04, // 0040a380 8b4c24 04 mov ecx,dword ptr ss:[esp+0x4]
0x8a,0x01, // 0040a384 8a01 mov al,byte ptr ds:[ecx]
0x8a,0x49, 0x01, // 0040a386 8a49 01 mov cl,byte ptr ds:[ecx+0x1]
0x3c, 0x81 // 0040a389 3c 81 cmp al,0x81
};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
return addr;// && winhook::replace_fun(addr, (ULONG)Private::isLeadByteChar);
}
} // namespace Patch
} // unnamed namespace
bool LCScript::attach_function()
{
if (!ScenarioHook::attach(processStartAddress, processStopAddress,Patch::patchEncoding(processStartAddress, processStopAddress)))
return false;
return true;
}