mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-11-30 17:15:38 +08:00
790 lines
33 KiB
C++
790 lines
33 KiB
C++
#include"SystemAoi.h"
|
||
#include"embed_util.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, uintptr_t frame, uintptr_t 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 & 0xffff0000) + 0x10000; // range to traverse the stack
|
||
for (DWORD i = stack; 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();
|
||
}
|