LunaHook-mirror/LunaHook/engine32/SystemAoi.cpp
2024-05-13 18:28:08 +08:00

789 lines
33 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include"SystemAoi.h"
/* 7/8/2014: The engine name is supposed to be: AoiGameSystem Engine
* See: http://capita.tistory.com/m/post/205
*
* BUNNYBLACK Trial2 (SystemAoi4)
* baseaddr: 0x01d0000
*
* 1002472e cc int3
* 1002472f cc int3
* 10024730 55 push ebp ; jichi: hook here
* 10024731 8bec mov ebp,esp
* 10024733 51 push ecx
* 10024734 c745 fc 00000000 mov dword ptr ss:[ebp-0x4],0x0
* 1002473b 8b45 08 mov eax,dword ptr ss:[ebp+0x8]
* 1002473e 0fb708 movzx ecx,word ptr ds:[eax]
* 10024741 85c9 test ecx,ecx
* 10024743 74 34 je short _8.10024779
* 10024745 6a 00 push 0x0
* 10024747 6a 00 push 0x0
* 10024749 6a 01 push 0x1
* 1002474b 8b55 14 mov edx,dword ptr ss:[ebp+0x14]
* 1002474e 52 push edx
* 1002474f 0fb645 10 movzx eax,byte ptr ss:[ebp+0x10]
* 10024753 50 push eax
* 10024754 0fb74d 0c movzx ecx,word ptr ss:[ebp+0xc]
* 10024758 51 push ecx
* 10024759 8b55 08 mov edx,dword ptr ss:[ebp+0x8]
* 1002475c 52 push edx
* 1002475d e8 8eddffff call _8.100224f0
* 10024762 83c4 1c add esp,0x1c
* 10024765 8945 fc mov dword ptr ss:[ebp-0x4],eax
* 10024768 8b45 1c mov eax,dword ptr ss:[ebp+0x1c]
* 1002476b 50 push eax
* 1002476c 8b4d 18 mov ecx,dword ptr ss:[ebp+0x18]
* 1002476f 51 push ecx
* 10024770 8b55 fc mov edx,dword ptr ss:[ebp-0x4]
* 10024773 52 push edx
* 10024774 e8 77c6ffff call _8.10020df0
* 10024779 8b45 fc mov eax,dword ptr ss:[ebp-0x4]
* 1002477c 8be5 mov esp,ebp
* 1002477e 5d pop ebp
* 1002477f c2 1800 retn 0x18
* 10024782 cc int3
* 10024783 cc int3
* 10024784 cc int3
*
* 2/12/2015 jichi: SystemAoi5
*
* Note that BUNNYBLACK 3 also has SystemAoi5 version 4.1
*
* Hooked to PgsvTd.dll for all SystemAoi engine, which contains GDI functions.
* - Old: AoiLib.dll from DrawTextExA
* - SystemAoi4: Aoi4.dll from DrawTextExW
* - SystemAoi5: Aoi5.dll from GetGlyphOutlineW
*
* Logic:
* - Find GDI function (DrawTextExW, etc.) used to paint text in PgsvTd.dll
* - Then search the function call stack, to find where the exe module invoke PgsvTd
* - Finally insert to the call address, and text is on the top of the stack.
*
* Sample hooked call in 悪魔娘<E9AD94>看板料理 Aoi5
*
* 00B6D085 56 PUSH ESI
* 00B6D086 52 PUSH EDX
* 00B6D087 51 PUSH ECX
* 00B6D088 68 9E630000 PUSH 0x639E
* 00B6D08D 50 PUSH EAX
* 00B6D08E FF15 54D0BC00 CALL DWORD PTR DS:[0xBCD054] ; _12.0039E890, jichi: hook here
* 00B6D094 8B57 20 MOV EDX,DWORD PTR DS:[EDI+0x20]
* 00B6D097 89049A MOV DWORD PTR DS:[EDX+EBX*4],EAX
* 00B6D09A 8B4F 20 MOV ECX,DWORD PTR DS:[EDI+0x20]
* 00B6D09D 8B1499 MOV EDX,DWORD PTR DS:[ECX+EBX*4]
* 00B6D0A0 8D85 50FDFFFF LEA EAX,DWORD PTR SS:[EBP-0x2B0]
* 00B6D0A6 50 PUSH EAX
* 00B6D0A7 52 PUSH EDX
* 00B6D0A8 FF15 18D0BC00 CALL DWORD PTR DS:[0xBCD018] ; _12.003A14A0
*
* Special hook is needed, since the utf16 text is like this:
* [f9S30e0u] が、それ<E3819D>人間相手<E79BB8><EFBFBD><E8A9B1> */
namespace { // unnamed
void SpecialHookSystemAoi(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
*split = 0; // 8/3/2014 jichi: split is zero, so return address is used as split
if (hp->type & CODEC_UTF16) {
LPCWSTR wcs = (LPWSTR)stack->stack[1]; // jichi: text on the top of the stack
size_t size = ::wcslen(wcs);
for (DWORD i = 0; i < size; i++)
if (wcs[i] == L'>' || wcs[i] == L']') { // skip leading ] for scenario and > for name threads
i++;
if (wcs[i] == 0x3000) // \u3000
i++;
*data = (DWORD)(wcs + i);
size -= i;
*len = size * 2; // * 2 for wstring
return;
}
} else {
LPCSTR cs = (LPCSTR)stack->stack[1]; // jichi: text on the top of the stack
size_t size = ::strlen(cs);
for (DWORD i = 0; i < size; i++)
if (cs[i] == '>' || cs[i] == ']') {
i++;
if ((unsigned char)cs[i] == 0x81 && cs[i+1] == 0x40) // \u3000
i += 2;
*data = (DWORD)(cs + i);
size -= i;
*len = size;
return;
}
}
}
int GetSystemAoiVersion() // return result is cached
{
static int ret = 0;
if (!ret) {
if (Util::CheckFile(L"Aoi4.dll"))
ret = 4;
else if (Util::CheckFile(L"Aoi5.dll"))
ret = 5;
else if (Util::CheckFile(L"Aoi6.dll")) // not exist yet, for future version
ret = 6;
else if (Util::CheckFile(L"Aoi7.dll")) // not exist yet, for future version
ret = 7;
else // AoiLib.dll, etc
ret = 3;
}
return ret;
}
bool InsertSystemAoiDynamicHook(LPVOID addr, hook_stack* stack)
{
int version = GetSystemAoiVersion();
bool utf16 = true;
if (addr == ::DrawTextExA) // < 4
utf16 = false;
if (addr == ::DrawTextExW) // 4~5
; // pass
else if (addr == ::GetGlyphOutlineW && version >= 5)
; // pass
else
return false;
DWORD high, low;
Util::GetCodeRange(processStartAddress, &low, &high);
// jichi 2/15/2015: Traverse the stack to dynamically find the ancestor call from the main module
const DWORD stop = (stack->esp & 0xffff0000) + 0x10000; // range to traverse the stack
for (DWORD i = stack->esp; i < stop; i += 4) {
DWORD k = *(DWORD *)i;
if (k > low && k < high && // jichi: if the stack address falls into the code region of the main exe module
((*(WORD *)(k - 6) == 0x15ff) || *(BYTE *)(k - 5) == 0xe8)) { // jichi 10/20/2014: call dword ptr ds
HookParam hp;
hp.offset=get_stack(1);
hp.text_fun = SpecialHookSystemAoi; // need to remove garbage
hp.type = utf16 ? (USING_STRING|CODEC_UTF16) : USING_STRING;
i = *(DWORD *)(k - 4); // get function call address
if (*(DWORD *)(k - 5) == 0xe8) // short jump
hp.address = i + k;
else
hp.address = *(DWORD *)i; // jichi: long jump, this is what is happening in Aoi5
//NewHook(hp, "SofthouseChara");
//GROWL_DWORD(hp.address); // BUNNYBLACK: 0x10024730, base 0x01d0000
auto succ=false;
if (hp.address) {
ConsoleOutput("INSERT SystemAoi");
if (addr == ::GetGlyphOutlineW)
succ|=NewHook(hp, "SystemAoi2"); // jichi 2/12/2015
else
succ|=NewHook(hp, "SystemAoi"); // jichi 7/8/2014: renamed, see: ja.wikipedia.org/wiki/ソフトハウスキャラ
ConsoleOutput("SystemAoi: disable GDI hooks");
} else
ConsoleOutput("failed to detect SystemAoi");
//RegisterEngineType(ENGINE_SOFTHOUSE);
return succ;
}
}
ConsoleOutput("SystemAoi: failed");
return true; // jichi 12/25/2013: return true
}
bool InsertSystemAoiDynamic()
{
ConsoleOutput("DYNAMIC SystemAoi");
//ConsoleOutput("Probably SoftHouseChara. Wait for text.");
trigger_fun = InsertSystemAoiDynamicHook;
return true;
}
ULONG findAoiProc(HMODULE hModule, LPCSTR functionName, int minParamNum = 0, int maxParamNum = 10)
{
for (int i = minParamNum; i < maxParamNum; i++) {
std::string sig; // function signature name, such as _AgsSpriteCreateText@20
sig.push_back('_');
sig += functionName;
sig.push_back('@');
sig += std::to_string(4ll * i);
if (auto proc = ::GetProcAddress(hModule, sig.c_str()))
return (ULONG)proc;
}
return 0;
}
namespace{
template<typename wstrT>
wstrT ltrimA(wstrT text)
{
static const char *quotes[] = { "<>", "[]" }; // skip leading quotes
for each (const char *q in quotes)
while (text[0] == q[0]) {
if (auto p = ::strchr(text, q[1])) {
text = p + 1;
if ((UINT8)text[0] == 0x81 && (UINT8)text[1] == 0x40) // skip \u3000 leading space, assuming sjis encoding
text += 2;
} else
break;
}
return text;
}
template<typename wstrT>
wstrT ltrimW(wstrT text)
{
static const char *quotes[] = { "<>", "[]" }; // skip leading quotes
for each (const char *q in quotes)
while (text[0] == q[0]) {
if (auto p = ::wcschr(text, q[1])) {
text = p + 1;
if (*text == 0x3000) // skip \u3000 leading space
text++;
} else
break;
}
return text;
}
bool beforeAgsSpriteCreateTextExW(hook_stack*s,void* data, size_t* len,uintptr_t*role)
{
auto text = (LPWSTR)s->stack[2]; // arg2
if (!text || !*text || !Engine::isAddressWritable(text))
return false;
text = ltrimW(text);
if (!*text)
return false;
*role = Engine::OtherRole ;
write_string_overwrite(data,len,text);
return true;
}
void afterAgsSpriteCreateTextExW(hook_stack*s,void* data1, size_t len)
{
auto text = (LPWSTR)s->stack[2];
text = ltrimW(text);
std::wstring _=std::wstring((LPWSTR)data1,len);
wcscpy((LPWSTR)text,_.c_str());
}
bool beforeAgsSpriteCreateTextW(hook_stack*s,void* data, size_t* len,uintptr_t*role)
{
// All threads including character names are linked together
auto text = (LPWSTR)s->stack[1]; // arg1
if (!text || !*text || !Engine::isAddressWritable(text)) // skip modifying readonly text in code region
return false;
bool containsTags = ::wcsstr(text, L"[u]");
text = ltrimW(text);
if (!*text)
return false;
* role = Engine::OtherRole;
//ULONG split = s->stack[0]; // retaddr
ULONG split = s->stack[2]; // arg2
if (!containsTags)
switch (split) {
case 0x63a1:
*role = Engine::NameRole;
break;
case 0x639e:
*role = Engine::ScenarioRole;
break;
}
write_string_overwrite(data,len,text);
return true;
}
void afterAgsSpriteCreateTextW(hook_stack*s,void* data1, size_t len)
{
auto text = (LPWSTR)s->stack[1];
text = ltrimW(text);
std::wstring _=std::wstring((LPWSTR)data1,len);
wcscpy((LPWSTR)text,_.c_str());
}
void afterAgsSpriteCreateTextA(hook_stack*s,void* data1, size_t len)
{
auto text = (LPSTR)s->stack[1]; // arg1
text = ltrimA(text);
std::string _=std::string((char*)data1,len);
strcpy((char*)text,_.c_str());
}
bool beforeAgsSpriteCreateTextA(hook_stack*s,void* data, size_t* len,uintptr_t*role)
{
// All threads including character names are linked together
auto text = (LPSTR)s->stack[1]; // arg1
if (!text || !*text || !Engine::isAddressWritable(text)) // skip modifying readonly text in code region
return false;
bool containsTags = ::strstr(text, "[u]");
text = ltrimA(text);
if (!*text)
return false;
* role = Engine::OtherRole;
//ULONG split = s->stack[0]; // retaddr
ULONG split = s->stack[2]; // arg2
if (!containsTags)
switch (split) {
case 0x639d:
*role = Engine::NameRole;
break;
case 0x639c:
*role = Engine::ScenarioRole;
break;
}
return write_string_overwrite(data,len,text);
}
}
// jichi 7/26/2015: Backport logic in vnragent to vnrhook
namespace AgsPatchA {
namespace Private {
struct HookArgument {
ULONG unknown[13]; // + 0x34
LPCSTR text;
};
HookArgument *arg_;
LPCSTR text_;
bool hookBefore(hook_stack*s,void* data, size_t* len,uintptr_t*role)
{
LPCSTR src = (LPCSTR)s->stack[6]; // original text in arg7
//LPSTR dest = *(LPSTR *)(s->stack[0] + 0x34); // bad text in arg1+0x34
arg_ = (HookArgument *)s->stack[0];
text_ = arg_->text;
arg_->text = src;
return false;
}
bool hookAfter(hook_stack*s,void* data, size_t* len,uintptr_t*role)
{
if (arg_) {
arg_->text = text_;
arg_ = nullptr;
}
return false;
}
} // namespace Private
/**
* Sample game: 王賊
*
* Prevent Aoi engine from modifying illegal characters.
*
* Function found by hijack DrawTextExA.
*
* 100173BD CC INT3
* 100173BE CC INT3
* 100173BF CC INT3
* 100173C0 83EC 28 SUB ESP,0x28
* 100173C3 53 PUSH EBX
* 100173C4 33DB XOR EBX,EBX
* 100173C6 55 PUSH EBP
* 100173C7 8B6C24 34 MOV EBP,DWORD PTR SS:[ESP+0x34]
* 100173CB 56 PUSH ESI
* 100173CC 57 PUSH EDI
* 100173CD 8BF8 MOV EDI,EAX
* 100173CF C745 30 18000000 MOV DWORD PTR SS:[EBP+0x30],0x18
* 100173D6 381F CMP BYTE PTR DS:[EDI],BL
* 100173D8 895C24 28 MOV DWORD PTR SS:[ESP+0x28],EBX
* 100173DC C74424 2C FFFFFF>MOV DWORD PTR SS:[ESP+0x2C],0x7FFFFFFF
* 100173E4 895C24 1C MOV DWORD PTR SS:[ESP+0x1C],EBX
* 100173E8 895C24 20 MOV DWORD PTR SS:[ESP+0x20],EBX
* 100173EC 895C24 30 MOV DWORD PTR SS:[ESP+0x30],EBX
* 100173F0 895C24 34 MOV DWORD PTR SS:[ESP+0x34],EBX
* 100173F4 895C24 24 MOV DWORD PTR SS:[ESP+0x24],EBX
* 100173F8 895C24 14 MOV DWORD PTR SS:[ESP+0x14],EBX
* 100173FC 895C24 18 MOV DWORD PTR SS:[ESP+0x18],EBX
* 10017400 8BF7 MOV ESI,EDI
* 10017402 74 12 JE SHORT Ags.10017416
* 10017404 56 PUSH ESI
* 10017405 FF15 90A00210 CALL DWORD PTR DS:[<&AoiLib._AoiString2B>; AoiLib._AoiString2ByteIs@4
* 1001740B 85C0 TEST EAX,EAX
* 1001740D 74 7D JE SHORT Ags.1001748C
* 1001740F 83C6 02 ADD ESI,0x2
* 10017412 381E CMP BYTE PTR DS:[ESI],BL
* 10017414 ^75 EE JNZ SHORT Ags.10017404
* 10017416 57 PUSH EDI
* 10017417 FF15 94A00210 CALL DWORD PTR DS:[<&AoiLib._AoiStrlen@4>; AoiLib._AoiStrlen@4
* 1001741D 8BC8 MOV ECX,EAX
* 1001741F 83C1 02 ADD ECX,0x2
* 10017422 395C24 1C CMP DWORD PTR SS:[ESP+0x1C],EBX
* 10017426 74 0C JE SHORT Ags.10017434
* 10017428 8BC1 MOV EAX,ECX
* 1001742A 33D2 XOR EDX,EDX
* 1001742C F77424 2C DIV DWORD PTR SS:[ESP+0x2C]
* 10017430 8D4C01 01 LEA ECX,DWORD PTR DS:[ECX+EAX+0x1]
* 10017434 395C24 28 CMP DWORD PTR SS:[ESP+0x28],EBX
* 10017438 74 07 JE SHORT Ags.10017441
* 1001743A 8B4424 24 MOV EAX,DWORD PTR SS:[ESP+0x24]
* 1001743E 8D0C41 LEA ECX,DWORD PTR DS:[ECX+EAX*2]
* 10017441 51 PUSH ECX
* 10017442 FF15 18A00210 CALL DWORD PTR DS:[<&AoiLib._AoiMemoryAl>; AoiLib._AoiMemoryAlloc@4
* 10017448 8945 34 MOV DWORD PTR SS:[EBP+0x34],EAX
* 1001744B 381F CMP BYTE PTR DS:[EDI],BL
* 1001744D 8BF0 MOV ESI,EAX
* 1001744F 0F84 6C020000 JE Ags.100176C1
* 10017455 8B2D 50A10210 MOV EBP,DWORD PTR DS:[<&AoiLib._AoiStrin>; AoiLib._AoiString1to2Byte@8
* 1001745B EB 03 JMP SHORT Ags.10017460
* 1001745D 8D49 00 LEA ECX,DWORD PTR DS:[ECX]
* 10017460 57 PUSH EDI
* 10017461 FF15 90A00210 CALL DWORD PTR DS:[<&AoiLib._AoiString2B>; AoiLib._AoiString2ByteIs@4
* 10017467 85C0 TEST EAX,EAX
* 10017469 0F84 99010000 JE Ags.10017608
* 1001746F 8A0F MOV CL,BYTE PTR DS:[EDI]
* 10017471 880E MOV BYTE PTR DS:[ESI],CL
* 10017473 8A57 01 MOV DL,BYTE PTR DS:[EDI+0x1]
* 10017476 83C7 01 ADD EDI,0x1
* 10017479 83C6 01 ADD ESI,0x1
* 1001747C 8816 MOV BYTE PTR DS:[ESI],DL
* 1001747E 83C6 01 ADD ESI,0x1
* 10017481 83C7 01 ADD EDI,0x1
* 10017484 83C3 02 ADD EBX,0x2
* 10017487 E9 F8010000 JMP Ags.10017684
* 1001748C 803E 3C CMP BYTE PTR DS:[ESI],0x3C
* 1001748F 74 0D JE SHORT Ags.1001749E
* 10017491 83C6 01 ADD ESI,0x1
* 10017494 834424 24 01 ADD DWORD PTR SS:[ESP+0x24],0x1
* 10017499 ^E9 74FFFFFF JMP Ags.10017412
* 1001749E 8A46 01 MOV AL,BYTE PTR DS:[ESI+0x1]
* 100174A1 83C6 01 ADD ESI,0x1
* 100174A4 84C0 TEST AL,AL
* 100174A6 ^0F84 6AFFFFFF JE Ags.10017416
* 100174AC 8D6424 00 LEA ESP,DWORD PTR SS:[ESP]
* 100174B0 3C 3E CMP AL,0x3E
* 100174B2 ^0F84 5AFFFFFF JE Ags.10017412
* 100174B8 0FBEC0 MOVSX EAX,AL
* 100174BB 83C0 B5 ADD EAX,-0x4B
* 100174BE 83F8 2A CMP EAX,0x2A
* 100174C1 77 52 JA SHORT Ags.10017515
* 100174C3 0FB680 70770110 MOVZX EAX,BYTE PTR DS:[EAX+0x10017770]
* 100174CA FF2485 50770110 JMP DWORD PTR DS:[EAX*4+0x10017750]
* 100174D1 8A46 01 MOV AL,BYTE PTR DS:[ESI+0x1]
* 100174D4 83C6 01 ADD ESI,0x1
* 100174D7 33C9 XOR ECX,ECX
* 100174D9 3C 30 CMP AL,0x30
* 100174DB 7C 1A JL SHORT Ags.100174F7
* 100174DD 8D49 00 LEA ECX,DWORD PTR DS:[ECX]
* 100174E0 3C 39 CMP AL,0x39
* 100174E2 7F 13 JG SHORT Ags.100174F7
* 100174E4 83C6 01 ADD ESI,0x1
* 100174E7 0FBED0 MOVSX EDX,AL
* 100174EA 8A06 MOV AL,BYTE PTR DS:[ESI]
* 100174EC 3C 30 CMP AL,0x30
* 100174EE 8D0C89 LEA ECX,DWORD PTR DS:[ECX+ECX*4]
* 100174F1 8D4C4A D0 LEA ECX,DWORD PTR DS:[EDX+ECX*2-0x30]
* 100174F5 ^7D E9 JGE SHORT Ags.100174E0
* 100174F7 6A 0A PUSH 0xA
* 100174F9 53 PUSH EBX
* 100174FA 51 PUSH ECX
* 100174FB FF15 88A00210 CALL DWORD PTR DS:[<&AoiLib._AoiMathLimi>; AoiLib._AoiMathLimit@12
* 10017501 8B0485 08CB0210 MOV EAX,DWORD PTR DS:[EAX*4+0x1002CB08]
* 10017508 8945 30 MOV DWORD PTR SS:[EBP+0x30],EAX
* 1001750B EB 0B JMP SHORT Ags.10017518
* 1001750D C74424 28 010000>MOV DWORD PTR SS:[ESP+0x28],0x1
* 10017515 83C6 01 ADD ESI,0x1
* 10017518 8A06 MOV AL,BYTE PTR DS:[ESI]
* 1001751A 84C0 TEST AL,AL
* 1001751C ^75 92 JNZ SHORT Ags.100174B0
* 1001751E ^E9 F3FEFFFF JMP Ags.10017416
* 10017523 8A46 01 MOV AL,BYTE PTR DS:[ESI+0x1]
* 10017526 83C6 01 ADD ESI,0x1
* 10017529 33C9 XOR ECX,ECX
* 1001752B 3C 30 CMP AL,0x30
* 1001752D C74424 1C 010000>MOV DWORD PTR SS:[ESP+0x1C],0x1
* 10017535 ^7C E1 JL SHORT Ags.10017518
* 10017537 3C 39 CMP AL,0x39
* 10017539 7F 13 JG SHORT Ags.1001754E
* 1001753B 83C6 01 ADD ESI,0x1
* 1001753E 0FBED0 MOVSX EDX,AL
* 10017541 8A06 MOV AL,BYTE PTR DS:[ESI]
* 10017543 3C 30 CMP AL,0x30
* 10017545 8D0C89 LEA ECX,DWORD PTR DS:[ECX+ECX*4]
* 10017548 8D4C4A D0 LEA ECX,DWORD PTR DS:[EDX+ECX*2-0x30]
* 1001754C ^7D E9 JGE SHORT Ags.10017537
* 1001754E 3BCB CMP ECX,EBX
* 10017550 ^74 C6 JE SHORT Ags.10017518
* 10017552 894C24 2C MOV DWORD PTR SS:[ESP+0x2C],ECX
* 10017556 ^EB C0 JMP SHORT Ags.10017518
* 10017558 8A46 01 MOV AL,BYTE PTR DS:[ESI+0x1]
* 1001755B 83C6 01 ADD ESI,0x1
* 1001755E 3C 30 CMP AL,0x30
* 10017560 ^7C B6 JL SHORT Ags.10017518
* 10017562 3C 39 CMP AL,0x39
* 10017564 ^7F B2 JG SHORT Ags.10017518
* 10017566 0FBEC0 MOVSX EAX,AL
* 10017569 66:8B0C45 94CA02>MOV CX,WORD PTR DS:[EAX*2+0x1002CA94]
* 10017571 66:81C9 0080 OR CX,0x8000
* 10017576 0FB7D1 MOVZX EDX,CX
* 10017579 895424 20 MOV DWORD PTR SS:[ESP+0x20],EDX
* 1001757D ^EB 96 JMP SHORT Ags.10017515
* 1001757F 8A46 01 MOV AL,BYTE PTR DS:[ESI+0x1]
* 10017582 83C6 01 ADD ESI,0x1
* 10017585 3C 30 CMP AL,0x30
* 10017587 ^7C 8F JL SHORT Ags.10017518
* 10017589 3C 39 CMP AL,0x39
* 1001758B ^7F 8B JG SHORT Ags.10017518
* 1001758D 0FBEC0 MOVSX EAX,AL
* 10017590 0FB70C45 94CA021>MOVZX ECX,WORD PTR DS:[EAX*2+0x1002CA94]
* 10017598 894C24 20 MOV DWORD PTR SS:[ESP+0x20],ECX
* 1001759C ^E9 74FFFFFF JMP Ags.10017515
* 100175A1 8A46 01 MOV AL,BYTE PTR DS:[ESI+0x1]
* 100175A4 83C6 01 ADD ESI,0x1
* 100175A7 3C 30 CMP AL,0x30
* 100175A9 ^0F8C 69FFFFFF JL Ags.10017518
* 100175AF 3C 39 CMP AL,0x39
* 100175B1 ^0F8F 61FFFFFF JG Ags.10017518
* 100175B7 0FBED0 MOVSX EDX,AL
* 100175BA 0FB70455 94CA021>MOVZX EAX,WORD PTR DS:[EDX*2+0x1002CA94]
* 100175C2 894424 30 MOV DWORD PTR SS:[ESP+0x30],EAX
* 100175C6 ^E9 4AFFFFFF JMP Ags.10017515
* 100175CB 8A46 01 MOV AL,BYTE PTR DS:[ESI+0x1]
* 100175CE 83C6 01 ADD ESI,0x1
* 100175D1 33C9 XOR ECX,ECX
* 100175D3 3C 30 CMP AL,0x30
* 100175D5 ^0F8C 3DFFFFFF JL Ags.10017518
* 100175DB EB 03 JMP SHORT Ags.100175E0
* 100175DD 8D49 00 LEA ECX,DWORD PTR DS:[ECX]
* 100175E0 3C 39 CMP AL,0x39
* 100175E2 7F 13 JG SHORT Ags.100175F7
* 100175E4 83C6 01 ADD ESI,0x1
* 100175E7 0FBED0 MOVSX EDX,AL
* 100175EA 8A06 MOV AL,BYTE PTR DS:[ESI]
* 100175EC 3C 30 CMP AL,0x30
* 100175EE 8D0C89 LEA ECX,DWORD PTR DS:[ECX+ECX*4]
* 100175F1 8D4C4A D0 LEA ECX,DWORD PTR DS:[EDX+ECX*2-0x30]
* 100175F5 ^7D E9 JGE SHORT Ags.100175E0
* 100175F7 3BCB CMP ECX,EBX
* 100175F9 ^0F84 19FFFFFF JE Ags.10017518
* 100175FF 894C24 34 MOV DWORD PTR SS:[ESP+0x34],ECX
* 10017603 ^E9 10FFFFFF JMP Ags.10017518
* 10017608 8A07 MOV AL,BYTE PTR DS:[EDI]
* 1001760A 3C 3C CMP AL,0x3C
* 1001760C 75 2A JNZ SHORT Ags.10017638
* 1001760E 83C7 01 ADD EDI,0x1
* 10017611 8806 MOV BYTE PTR DS:[ESI],AL
* 10017613 8A07 MOV AL,BYTE PTR DS:[EDI]
* 10017615 83C6 01 ADD ESI,0x1
* 10017618 84C0 TEST AL,AL
* 1001761A 74 16 JE SHORT Ags.10017632
* 1001761C 8D6424 00 LEA ESP,DWORD PTR SS:[ESP]
* 10017620 3C 3E CMP AL,0x3E
* 10017622 74 0E JE SHORT Ags.10017632
* 10017624 83C7 01 ADD EDI,0x1
* 10017627 8806 MOV BYTE PTR DS:[ESI],AL
* 10017629 8A07 MOV AL,BYTE PTR DS:[EDI]
* 1001762B 83C6 01 ADD ESI,0x1
* 1001762E 84C0 TEST AL,AL
* 10017630 ^75 EE JNZ SHORT Ags.10017620
* 10017632 8A07 MOV AL,BYTE PTR DS:[EDI]
* 10017634 8806 MOV BYTE PTR DS:[ESI],AL
* 10017636 EB 46 JMP SHORT Ags.1001767E
* 10017638 3C 0A CMP AL,0xA
* 1001763A 74 27 JE SHORT Ags.10017663
* 1001763C 3C 7C CMP AL,0x7C
* 1001763E 74 23 JE SHORT Ags.10017663
* 10017640 837C24 28 00 CMP DWORD PTR SS:[ESP+0x28],0x0
* 10017645 74 0F JE SHORT Ags.10017656
* 10017647 50 PUSH EAX
* 10017648 56 PUSH ESI
* 10017649 FFD5 CALL EBP
* 1001764B 83C6 02 ADD ESI,0x2
* 1001764E 83C7 01 ADD EDI,0x1
* 10017651 83C3 02 ADD EBX,0x2
* 10017654 EB 2E JMP SHORT Ags.10017684
* 10017656 8806 MOV BYTE PTR DS:[ESI],AL
* 10017658 83C6 01 ADD ESI,0x1
* 1001765B 83C7 01 ADD EDI,0x1
* 1001765E 83C3 01 ADD EBX,0x1
* 10017661 EB 21 JMP SHORT Ags.10017684
* 10017663 395C24 14 CMP DWORD PTR SS:[ESP+0x14],EBX
* 10017667 73 04 JNB SHORT Ags.1001766D
* 10017669 895C24 14 MOV DWORD PTR SS:[ESP+0x14],EBX
* 1001766D 837C24 1C 00 CMP DWORD PTR SS:[ESP+0x1C],0x0
* 10017672 74 3D JE SHORT Ags.100176B1
* 10017674 33DB XOR EBX,EBX
* 10017676 834424 18 01 ADD DWORD PTR SS:[ESP+0x18],0x1
* 1001767B C606 0A MOV BYTE PTR DS:[ESI],0xA
* 1001767E 83C6 01 ADD ESI,0x1
* 10017681 83C7 01 ADD EDI,0x1
* 10017684 3B5C24 2C CMP EBX,DWORD PTR SS:[ESP+0x2C]
* 10017688 72 1E JB SHORT Ags.100176A8
* 1001768A 395C24 14 CMP DWORD PTR SS:[ESP+0x14],EBX
* 1001768E 73 04 JNB SHORT Ags.10017694
* 10017690 895C24 14 MOV DWORD PTR SS:[ESP+0x14],EBX
* 10017694 837C24 1C 00 CMP DWORD PTR SS:[ESP+0x1C],0x0
* 10017699 74 16 JE SHORT Ags.100176B1
* 1001769B 834424 18 01 ADD DWORD PTR SS:[ESP+0x18],0x1
* 100176A0 33DB XOR EBX,EBX
* 100176A2 C606 0A MOV BYTE PTR DS:[ESI],0xA
* 100176A5 83C6 01 ADD ESI,0x1
* 100176A8 803F 00 CMP BYTE PTR DS:[EDI],0x0
* 100176AB ^0F85 AFFDFFFF JNZ Ags.10017460
* 100176B1 395C24 14 CMP DWORD PTR SS:[ESP+0x14],EBX
* 100176B5 8B6C24 3C MOV EBP,DWORD PTR SS:[ESP+0x3C]
* 100176B9 73 04 JNB SHORT Ags.100176BF
* 100176BB 895C24 14 MOV DWORD PTR SS:[ESP+0x14],EBX
* 100176BF 33DB XOR EBX,EBX
* 100176C1 8B4C24 18 MOV ECX,DWORD PTR SS:[ESP+0x18]
* 100176C5 83C1 01 ADD ECX,0x1
* 100176C8 807E FF 0A CMP BYTE PTR DS:[ESI-0x1],0xA
* 100176CC 75 03 JNZ SHORT Ags.100176D1
* 100176CE 83C6 FF ADD ESI,-0x1
* 100176D1 C606 00 MOV BYTE PTR DS:[ESI],0x0
* 100176D4 8B45 30 MOV EAX,DWORD PTR SS:[EBP+0x30]
* 100176D7 8BD0 MOV EDX,EAX
* 100176D9 0FAFC1 IMUL EAX,ECX
* 100176DC 0FAF5424 14 IMUL EDX,DWORD PTR SS:[ESP+0x14]
* 100176E1 8945 10 MOV DWORD PTR SS:[EBP+0x10],EAX
* 100176E4 A1 BC3F0310 MOV EAX,DWORD PTR DS:[0x10033FBC]
* 100176E9 D1EA SHR EDX,1
* 100176EB 8955 0C MOV DWORD PTR SS:[EBP+0xC],EDX
* 100176EE 8B88 44010000 MOV ECX,DWORD PTR DS:[EAX+0x144]
* 100176F4 3999 28010000 CMP DWORD PTR DS:[ECX+0x128],EBX
* 100176FA 74 19 JE SHORT Ags.10017715
* 100176FC 8B5424 30 MOV EDX,DWORD PTR SS:[ESP+0x30]
* 10017700 8B4424 20 MOV EAX,DWORD PTR SS:[ESP+0x20]
* 10017704 52 PUSH EDX
* 10017705 50 PUSH EAX
* 10017706 8B4424 3C MOV EAX,DWORD PTR SS:[ESP+0x3C]
* 1001770A 55 PUSH EBP
* 1001770B E8 90F5FFFF CALL Ags.10016CA0 ; jichi: the paint function, bad text address in arg1 + 0x34, good text in arg7
* 10017710 83C4 0C ADD ESP,0xC
* 10017713 EB 1B JMP SHORT Ags.10017730
* 10017715 8B4C24 30 MOV ECX,DWORD PTR SS:[ESP+0x30]
* 10017719 8B5424 20 MOV EDX,DWORD PTR SS:[ESP+0x20]
* 1001771D 8B45 34 MOV EAX,DWORD PTR SS:[EBP+0x34]
* 10017720 51 PUSH ECX
* 10017721 8B4C24 38 MOV ECX,DWORD PTR SS:[ESP+0x38]
* 10017725 52 PUSH EDX
* 10017726 50 PUSH EAX
* 10017727 55 PUSH EBP
* 10017728 E8 33F9FFFF CALL Ags.10017060
* 1001772D 83C4 10 ADD ESP,0x10
* 10017730 8B4D 30 MOV ECX,DWORD PTR SS:[EBP+0x30]
* 10017733 8BC1 MOV EAX,ECX
* 10017735 99 CDQ
* 10017736 2BC2 SUB EAX,EDX
* 10017738 5F POP EDI
* 10017739 D1F8 SAR EAX,1
* 1001773B 5E POP ESI
* 1001773C 8945 1C MOV DWORD PTR SS:[EBP+0x1C],EAX
* 1001773F 894D 20 MOV DWORD PTR SS:[EBP+0x20],ECX
* 10017742 5D POP EBP
* 10017743 B8 01000000 MOV EAX,0x1
* 10017748 5B POP EBX
* 10017749 83C4 28 ADD ESP,0x28
* 1001774C C3 RETN
* 1001774D 8D49 00 LEA ECX,DWORD PTR DS:[ECX]
* 10017750 7F 75 JG SHORT Ags.100177C7
* 10017752 0110 ADD DWORD PTR DS:[EAX],EDX
* 10017754 CB RETF ; Far return
* 10017755 75 01 JNZ SHORT Ags.10017758
* 10017757 1058 75 ADC BYTE PTR DS:[EAX+0x75],BL
* 1001775A 0110 ADD DWORD PTR DS:[EAX],EDX
* 1001775C A1 75011023 MOV EAX,DWORD PTR DS:[0x23100175]
* 10017761 75 01 JNZ SHORT Ags.10017764
* 10017763 10D1 ADC CL,DL
* 10017765 74 01 JE SHORT Ags.10017768
* 10017767 100D 75011015 ADC BYTE PTR DS:[0x15100175],CL
* 1001776D 75 01 JNZ SHORT Ags.10017770
* 1001776F 1000 ADC BYTE PTR DS:[EAX],AL
* 10017771 0107 ADD DWORD PTR DS:[EDI],EAX
* 10017773 07 POP ES ; Modification of segment register
* 10017774 07 POP ES ; Modification of segment register
* 10017775 07 POP ES ; Modification of segment register
* 10017776 07 POP ES ; Modification of segment register
* 10017777 07 POP ES ; Modification of segment register
* 10017778 07 POP ES ; Modification of segment register
* 10017779 07 POP ES ; Modification of segment register
* 1001777A 07 POP ES ; Modification of segment register
* 1001777B 07 POP ES ; Modification of segment register
* 1001777C 07 POP ES ; Modification of segment register
* 1001777D 07 POP ES ; Modification of segment register
*/
bool attach(ULONG startAddress, ULONG stopAddress)
{
const uint8_t bytes[] = {
0x8b,0x44,0x24, 0x3c, // 10017706 8b4424 3c mov eax,dword ptr ss:[esp+0x3c]
0x55, // 1001770a 55 push ebp
0xe8, XX4, // 1001770b e8 90f5ffff call ags.10016ca0 ; jichi: the paint function, bad text address in arg1 + 0x34, good text in arg7
0x83,0xc4, 0x0c, // 10017710 83c4 0c add esp,0xc
0xeb, 0x1b // 10017713 eb 1b jmp short ags.10017730
};
enum { addr_offset = 0x1001770b - 0x10017706 }; // == 5
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
if (!addr)
return false;
HookParam hp;
hp.address=addr;
hp.type=EMBED_ABLE|HOOK_EMPTY;
hp.hook_before=Private::hookBefore;
auto succ=NewHook(hp,"AgsPatchA");
hp.address+=5;
hp.hook_before=Private::hookAfter;
succ|=NewHook(hp,"AgsPatchA");
return succ;
}
} // namespace AgsPatchA
bool InsertSystemAoiStatic(HMODULE hModule, bool wideChar) // attach scenario
{
ULONG addr = findAoiProc(hModule, "AgsSpriteCreateText", 1);
if (!addr) {
ConsoleOutput("SystemAoiStatic: function found");
return false;
}
HookParam hp;
hp.address = addr;
hp.offset=get_stack(1);
hp.text_fun = SpecialHookSystemAoi; //其实已无效在before的lstrim里有一样的功能。但保留。
hp.type=EMBED_ABLE|USING_STRING;//|EMBED_AFTER_OVERWRITE;
//hp.type |= NO_CONTEXT|USING_SPLIT|SPLIT_INDIRECT;
ConsoleOutput("INSERT static SystemAoi");
auto succ=false;
if (wideChar){
hp.type |=CODEC_UTF16 ;
hp.hook_before=beforeAgsSpriteCreateTextW;
hp.hook_after=afterAgsSpriteCreateTextW;
succ|=NewHook(hp, "SystemAoiW");
ULONG addr = findAoiProc(hModule, "AgsSpriteCreateTextEx", 1);
if (addr) {
HookParam hp;
hp.address = addr;
hp.offset=get_stack(2);
hp.type=CODEC_UTF16|EMBED_ABLE;//|EMBED_AFTER_OVERWRITE;
hp.hook_before=beforeAgsSpriteCreateTextExW;
hp.hook_after=afterAgsSpriteCreateTextExW;
succ|=NewHook(hp, "SystemAoiExW");
}
return succ;
}
else{
hp.hook_before=beforeAgsSpriteCreateTextA;
hp.hook_after=afterAgsSpriteCreateTextA;
hp.hook_font=F_DrawTextExA;
if(AgsPatchA::attach(processStartAddress,processStopAddress)==false)
hp.type|=EMBED_DYNA_SJIS;
succ|=NewHook(hp, "SystemAoiA");
}
return succ;
}
} // unnamed namespace
bool InsertSystemAoiHook() // this function always returns true
{
HMODULE hModule = ::GetModuleHandleA("Ags.dll");
bool wideChar = true;
if (hModule) // Aoi <= 3
wideChar = false;
else { // Aoi >= 4
hModule = ::GetModuleHandleA("Ags5.dll");
if (!hModule)
hModule = ::GetModuleHandleA("Ags4.dll");
}
return hModule && InsertSystemAoiStatic(hModule, wideChar)
|| InsertSystemAoiDynamic();
}
bool SystemAoi::attach_function() {
return InsertSystemAoiHook();
}