mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-12-25 12:44:13 +08:00
936 lines
33 KiB
C++
936 lines
33 KiB
C++
#include"QLIE.h"
|
||
#include"embed_util.h"
|
||
/**
|
||
* jichi 8/18/2013: QLIE identified by GameData/data0.pack
|
||
*
|
||
* The old hook cannot recognize new games.
|
||
*/
|
||
|
||
namespace { // unnamed QLIE
|
||
|
||
/**
|
||
* Artikash 8/1/2018: new QLIE hook. old one misses on https://vndb.org/v22308 and https://vndb.org/v19182
|
||
* ExtTextOut hook misses characters because of font caching
|
||
* Method to find H-code: trace call stack from ExtTextOut until missing characters from default hook are found
|
||
* /HW-1C*0:-20@base address of pattern
|
||
* characterizing pattern:
|
||
kimimeza.exe+100D9C - 55 - push ebp
|
||
kimimeza.exe+100D9D - 8B EC - mov ebp,esp
|
||
kimimeza.exe+100D9F - 83 C4 E4 - add esp,-1C { 228 }
|
||
kimimeza.exe+100DA2 - 53 - push ebx
|
||
kimimeza.exe+100DA3 - 56 - push esi
|
||
kimimeza.exe+100DA4 - 57 - push edi
|
||
kimimeza.exe+100DA5 - 33 D2 - xor edx,edx
|
||
kimimeza.exe+100DA7 - 89 55 FC - mov [ebp-04],edx
|
||
*/
|
||
bool InsertQLIE3Hook()
|
||
{
|
||
const BYTE bytes[] =
|
||
{
|
||
0x55,
|
||
0x8b, 0xec,
|
||
0x83, 0xc4, 0xe4,
|
||
0x53,
|
||
0x56,
|
||
0x57,
|
||
0x33, 0xd2,
|
||
0x89, 0x55, 0xfc
|
||
};
|
||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||
if (!addr) {
|
||
ConsoleOutput("QLIE3: pattern not found");
|
||
//ConsoleOutput("Not QLIE2");
|
||
return false;
|
||
}
|
||
|
||
HookParam hp;
|
||
hp.type = CODEC_UTF16 | DATA_INDIRECT | USING_SPLIT;
|
||
hp.offset=get_reg(regs::esi);
|
||
hp.split=get_reg(regs::edi);
|
||
hp.address = addr;
|
||
|
||
ConsoleOutput("INSERT QLIE3");
|
||
return NewHook(hp, "QLiE3");
|
||
}
|
||
/**
|
||
* jichi 8/18/2013: new QLIE hook
|
||
* See: http://www.hongfire.com/forum/showthread.php/420362-QLIE-engine-Hcode
|
||
*
|
||
* Ins:
|
||
* 55 8B EC 53 8B 5D 1C
|
||
* - 55 push ebp ; hook here
|
||
* - 8bec mov ebp, esp
|
||
* - 53 push ebx
|
||
* - 8B5d 1c mov ebx, dword ptr ss:[ebp+1c]
|
||
*
|
||
* /HBN14*0@4CC2C4
|
||
* - addr: 5030596 (0x4cc2c4)
|
||
* - text_fun: 0x0
|
||
* - function: 0
|
||
* - hook_len: 0
|
||
* - ind: 0
|
||
* - length_offset: 1
|
||
* - module: 0
|
||
* - off: 20 (0x14)
|
||
* - recover_len: 0
|
||
* - split: 0
|
||
* - split_ind: 0
|
||
* - type: 1032 (0x408)
|
||
*/
|
||
bool InsertQLIE2Hook()
|
||
{
|
||
const BYTE bytes[] = { // size = 7
|
||
0x55, // 55 push ebp ; hook here
|
||
0x8b,0xec, // 8bec mov ebp, esp
|
||
0x53, // 53 push ebx
|
||
0x8b,0x5d, 0x1c // 8b5d 1c mov ebx, dword ptr ss:[ebp+1c]
|
||
};
|
||
//enum { addr_offset = 0 }; // current instruction is the first one
|
||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||
if (!addr) {
|
||
ConsoleOutput("QLIE2: pattern not found");
|
||
//ConsoleOutput("Not QLIE2");
|
||
return false;
|
||
}
|
||
|
||
HookParam hp;
|
||
hp.type = DATA_INDIRECT|NO_CONTEXT; // 0x408
|
||
hp.offset=get_stack(5);
|
||
hp.address = addr;
|
||
|
||
ConsoleOutput("INSERT QLIE2");
|
||
return NewHook(hp, "QLiE2");
|
||
}
|
||
|
||
// jichi: 8/18/2013: Change return type to bool
|
||
bool InsertQLIE1Hook()
|
||
{
|
||
for (DWORD i = processStartAddress + 0x1000; i < processStopAddress - 4; i++)
|
||
if (*(DWORD *)i == 0x7ffe8347) { // inc edi, cmp esi,7f
|
||
DWORD t = 0;
|
||
for (DWORD j = i; j < i + 0x10; j++) {
|
||
if (*(DWORD *)j == 0xa0) { // cmp esi,a0
|
||
t = 1;
|
||
break;
|
||
}
|
||
}
|
||
if (t)
|
||
for (DWORD j = i; j > i - 0x100; j--)
|
||
if (*(DWORD *)j == 0x83ec8b55) { // push ebp, mov ebp,esp, sub esp,*
|
||
HookParam hp;
|
||
hp.address = j;
|
||
hp.offset =get_stack(6);
|
||
hp.split =get_reg(regs::esp);
|
||
hp.type = DATA_INDIRECT|USING_SPLIT;
|
||
ConsoleOutput("INSERT QLIE1");
|
||
return NewHook(hp, "QLiE");
|
||
}
|
||
}
|
||
|
||
ConsoleOutput("QLIE1: failed");
|
||
//ConsoleOutput("Unknown QLIE engine");
|
||
return false;
|
||
}
|
||
|
||
} // unnamed QLIE
|
||
namespace{
|
||
bool _4(){
|
||
//シスターシスター
|
||
//https://vndb.org/v653
|
||
const BYTE bytes[] = {
|
||
0x81,0xFB,0x80,0x00,0x00,0x00,
|
||
XX2,
|
||
0x81,0xFB,0xa0,0x00,0x00,0x00,
|
||
XX2,
|
||
0x81,0xFB,0xdf,0x00,0x00,0x00,
|
||
XX2,
|
||
0x81,0xFB,0xff,0x00,0x00,0x00,
|
||
XX2,
|
||
};
|
||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||
|
||
if (addr == 0)return false;
|
||
const BYTE funcstart[] = {
|
||
0x90,0x55,0x8b,0xec
|
||
};
|
||
addr = reverseFindBytes(funcstart, sizeof(funcstart), addr-0x100, addr);
|
||
if (addr == 0)return false;
|
||
HookParam hp;
|
||
hp.address = addr+1 ;
|
||
hp.offset = get_stack(6);
|
||
hp.type = USING_STRING ;
|
||
return NewHook(hp, "QLIE4");
|
||
}
|
||
bool _5(){
|
||
//おしかけおさなづま3(3乗)
|
||
//School Festa-スクールフェスタ-
|
||
const BYTE bytes[] = {
|
||
0x83,0xFF,0x7F,
|
||
XX2,
|
||
0x81,0xFf,0xa0,0x00,0x00,0x00,
|
||
XX2,
|
||
0x81,0xFf,0xdf,0x00,0x00,0x00,
|
||
XX2,
|
||
0x81,0xFf,0xff,0x00,0x00,0x00,
|
||
XX2,
|
||
};
|
||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||
|
||
if (addr == 0)return false;
|
||
addr = findfuncstart(addr);
|
||
if (addr == 0)return false;
|
||
HookParam hp;
|
||
hp.address = addr;
|
||
hp.offset=get_reg(regs::ecx);
|
||
hp.type = USING_STRING ;
|
||
return NewHook(hp, "QLIE5");
|
||
}
|
||
}
|
||
// jichi 8/18/2013: Add new hook
|
||
bool InsertQLIEHook()
|
||
{
|
||
bool _=_4()||_5();
|
||
return InsertQLIE1Hook() || InsertQLIE2Hook() || InsertQLIE3Hook()||_;
|
||
|
||
}
|
||
|
||
namespace { // unnamed
|
||
|
||
namespace ScenarioHook {
|
||
namespace Private {
|
||
|
||
template <typename strT>
|
||
strT trim(strT text, int *size)
|
||
{
|
||
//int length = ::strlen(text);
|
||
int length = *size;
|
||
if (text[0] == '[') {
|
||
if (all_ascii(text))
|
||
return nullptr;
|
||
if (text[length - 1] == ']' && ::CharPrevA(text, text + length) == text + length - 1) {
|
||
length--;
|
||
if (text[length - 1] == 'n' && text[length - 2] == '[')
|
||
length -= 2;
|
||
}
|
||
for (int i = 1; i < length; i++)
|
||
if ((signed char)text[i] <= 0) {
|
||
text += i;
|
||
length -= i - 1;
|
||
break;
|
||
}
|
||
length--; // skip the leading '['
|
||
}
|
||
*size = length;
|
||
return text;
|
||
}
|
||
|
||
/**
|
||
* Sample game: 月に寄りそう乙女の作法2
|
||
*
|
||
*
|
||
* Name:
|
||
*
|
||
* 019D7688 5B 66 2C 31 5D 5B 72 66 2C 31 5D 5B 73 2C 32 30 [f,1][rf,1][s,20
|
||
* 019D7698 2C 32 30 5D 5B 63 2C 24 46 46 46 46 46 46 46 46 ,20][c,$FFFFFFFF
|
||
* 019D76A8 5D 5B 72 63 2C 24 46 46 46 46 46 46 46 46 5D 81 ][rc,$FFFFFFFF]・
|
||
* 019D76B8 79 8D F7 8F AC 98 48 83 41 83 67 83 8C 81 7A 00 y桜小路アトレ】.
|
||
*
|
||
* 0012FBCC 0055553D RETURN to .0055553D from .00513234
|
||
* 0012FBD0 0012FDB8 Pointer to next SEH record
|
||
* 0012FBD4 005555A5 SE handler
|
||
* 0012FBD8 0012FD90
|
||
* 0012FBDC 0E9F72D0
|
||
* 0012FBE0 0E9F72D0
|
||
* 0012FBE4 0A24AA90
|
||
* 0012FBE8 00000000
|
||
* 0012FBEC 00000000
|
||
* 0012FBF0 0C7AE0C8 ASCII "st+cc+tt"
|
||
* 0012FBF4 00000000
|
||
* 0012FBF8 00000000
|
||
* 0012FBFC 00000000
|
||
* 0012FC00 00000000
|
||
* 0012FC04 00000000
|
||
* 0012FC08 00000000
|
||
*
|
||
* EAX 0E3885A0
|
||
* ECX 00000002
|
||
* EDX 019D7688
|
||
* EBX 0041D17C .0041D17C
|
||
* ESP 0012FBCC
|
||
* EBP 0012FD90
|
||
* ESI 0A24AA90
|
||
* EDI 0E9F72D0
|
||
* EIP 00513234 .00513234
|
||
*
|
||
*
|
||
* Dialog's arg4:
|
||
*
|
||
* 04A9BAD0 48 DB 51 00 B8 BA A9 04 F8 BA A9 04 07 02 00 00 HロQ.クコゥゥ..
|
||
* 04A9BAE0 B8 67 66 00 D0 AF A6 04 00 00 00 00 90 AC A9 04 クgf.ミッヲ....成ゥ
|
||
* 04A9BAF0 01 00 00 00 11 00 00 00 30 5F 64 69 61 6C 6F 67 ......0_dialog
|
||
* 04A9BB00 6D 65 73 73 61 67 65 2C 30 00 00 00 90 AC A9 04 message,0...成ゥ
|
||
*
|
||
* Scenario:
|
||
*
|
||
* 058DC708 5B 66 2C 30 5D 5B 72 66 2C 30 5D 5B 73 2C 32 34 [f,0][rf,0][s,24
|
||
* 058DC718 2C 32 34 5D 5B 63 2C 24 46 46 46 46 46 46 46 46 ,24][c,$FFFFFFFF
|
||
* 058DC728 5D 5B 72 63 2C 24 46 46 46 46 46 46 46 46 5D 81 ][rc,$FFFFFFFF]・
|
||
* 058DC738 75 82 CD 82 A2 81 41 82 B1 82 B1 82 CD 93 FA 96 uはい、ここは日・
|
||
* 058DC748 7B 82 C5 82 B7 81 42 8B F3 8D 60 82 CC 90 45 88 {です。空港の職・
|
||
* 058DC758 F5 82 E0 81 41 83 56 83 87 83 62 83 76 82 CC 93 焉Aショップの・
|
||
* 058DC768 58 88 F5 82 E0 81 41 83 8D 83 72 81 5B 82 C9 8D X員も、ロビーに・
|
||
* 058DC778 C0 82 E9 90 6C 82 E0 81 41 93 FA 96 7B 90 6C 82 タる人も、日本人・
|
||
* 058DC788 E7 82 B5 82 AB 90 6C 82 CE 82 A9 82 E8 82 C5 82 轤オき人ばかりで・
|
||
* 058DC798 B7 81 76 00 00 8E 8D 05 01 00 00 00 8C 00 00 00 キ」..詩...・..
|
||
* 058DC7A8 81 75 8D A1 93 FA 82 CD 90 E2 8D 44 82 CC 93 DC 「今日は絶好の曇
|
||
* 058DC7B8 82 E8 8B F3 82 BE 82 E6 81 41 82 C8 82 F1 82 C4 り空だよ、なんて
|
||
* 058DC7C8 91 66 93 47 82 C8 96 E9 8B F3 82 BE 82 EB 82 A4 素敵な夜空だろう
|
||
* 058DC7D8 81 49 81 40 96 6C 82 CC 8B 41 8D 91 82 C9 8D 87 ! 僕の帰国に合
|
||
* 058DC7E8 82 ED 82 B9 82 C4 91 BE 97 7A 82 F0 89 42 82 B5 わせて太陽を隠し
|
||
*
|
||
* 0012FBCC 0055553D RETURN to .0055553D from .00513234
|
||
* 0012FBD0 0012FDB8 Pointer to next SEH record
|
||
* 0012FBD4 005555A5 SE handler
|
||
* 0012FBD8 0012FD90
|
||
* 0012FBDC 0E9F7110
|
||
* 0012FBE0 0E9F7110
|
||
* 0012FBE4 0A24AA90
|
||
* 0012FBE8 00000000
|
||
* 0012FBEC 00000000
|
||
* 0012FBF0 0EA33460 ASCII "st+cc+tt"
|
||
* 0012FBF4 00000000
|
||
* 0012FBF8 00000000
|
||
* 0012FBFC 00000000
|
||
* 0012FC00 00000000
|
||
*
|
||
* EAX 0E9AD230
|
||
* ECX 00000002
|
||
* EDX 058DC708
|
||
* EBX 0041D17C .0041D17C
|
||
* ESP 0012FBCC
|
||
* EBP 0012FD90
|
||
* ESI 0A24AA90
|
||
* EDI 0E9F7110
|
||
* EIP 00513234 .00513234
|
||
*
|
||
* Backlog:
|
||
* FIXME: I don't have a way to distinguish Backlog out.
|
||
*
|
||
* 0A9775D8 5B 66 2C 32 5D 5B 63 2C 24 46 46 65 64 64 31 66 [f,2][c,$FFedd1f
|
||
* 0A9775E8 66 5D 5B 72 63 2C 24 46 46 65 64 64 31 66 66 5D f][rc,$FFedd1ff]
|
||
* 0A9775F8 81 75 82 CD 82 A2 81 41 82 B1 82 B1 82 CD 93 FA 「はい、ここは日
|
||
* 0A977608 96 7B 82 C5 82 B7 81 42 8B F3 8D 60 82 CC 90 45 本です。空港の職
|
||
* 0A977618 88 F5 82 E0 81 41 83 56 83 87 83 62 83 76 82 CC 員も、ショップの
|
||
* 0A977628 93 58 88 F5 82 E0 81 41 83 8D 83 72 81 5B 82 C9 店員も、ロビーに
|
||
*
|
||
* EAX 0FF32FE0
|
||
* ECX 00000002
|
||
* EDX 0A9775D8
|
||
* EBX 0041D17C .0041D17C
|
||
* ESP 0012FBCC
|
||
* EBP 0012FD90
|
||
* ESI 0A909350
|
||
* EDI 0B843690
|
||
* EIP 00513234 .00513234
|
||
*
|
||
* 0012FBCC 0055553D RETURN to .0055553D from .00513234
|
||
* 0012FBD0 0012FDB8 Pointer to next SEH record
|
||
* 0012FBD4 005555A5 SE handler
|
||
* 0012FBD8 0012FD90
|
||
* 0012FBDC 0B843690
|
||
* 0012FBE0 0B843690
|
||
* 0012FBE4 0A909350
|
||
* 0012FBE8 00000000
|
||
* 0012FBEC 00000000
|
||
* 0012FBF0 0FF25558 ASCII ""[f,2][c,$FFedd1ff][rc,$FFedd1ff]"+text"
|
||
* 0012FBF4 00000000
|
||
* 0012FBF8 00000000
|
||
* 0012FBFC 00000000
|
||
*
|
||
* Sample game ワルキューレロマンツェ more&more (QLiE2):
|
||
* Name:
|
||
* 0012FB84 00546877 RETURN to .00546877 from .00504AD0
|
||
* 0012FB88 0012FDBC Pointer to next SEH record
|
||
* 0012FB8C 00546B1B SE handler
|
||
* 0012FB90 0012FD94
|
||
* 0012FB94 11832DC0
|
||
* 0012FB98 11832DC0
|
||
* 0012FB9C 09278EA0
|
||
* 0012FBA0 00000000
|
||
* 0012FBA4 00000000
|
||
* 0012FBA8 00000000
|
||
* 0012FBAC 00000000
|
||
* 0012FBB0 00000000
|
||
* 0012FBB4 00000000
|
||
*
|
||
* 0A702400 5B 70 63 2C 94 FC 8D F7 5D 00 00 00 70 B6 6F 0A [pc,美桜]...pカo.
|
||
*
|
||
* EAX 0C2763E0 ASCII "HHP"
|
||
* ECX 00000003
|
||
* EDX 0A702400
|
||
* EBX 0041D168 .0041D168
|
||
* ESP 0012FB84 ASCII "whT"
|
||
* EBP 0012FD94
|
||
* ESI 09278EA0
|
||
* EDI 11832DC0
|
||
* EIP 00504AD0 .00504AD0
|
||
*
|
||
* Scenario:
|
||
* 09E0D7C8 5B 63 2C 24 46 46 46 46 46 46 44 44 5D 5B 72 63 [c,$FFFFFFDD][rc
|
||
* 09E0D7D8 2C 24 46 46 46 46 46 46 44 44 5D 81 75 82 A4 82 ,$FFFFFFDD]「う・
|
||
*
|
||
* 0012FB84 00546877 RETURN to .00546877 from .00504AD0
|
||
* 0012FB88 0012FDBC Pointer to next SEH record
|
||
* 0012FB8C 00546B1B SE handler
|
||
* 0012FB90 0012FD94
|
||
* 0012FB94 118314E0
|
||
* 0012FB98 118314E0
|
||
* 0012FB9C 09278EA0
|
||
* 0012FBA0 00000000
|
||
*
|
||
* EAX 0A72D820 ASCII "HHP"
|
||
* ECX 00000002
|
||
* EDX 09E0D7C8
|
||
* EBX 0041D168 .0041D168
|
||
* ESP 0012FB84 ASCII "whT"
|
||
* EBP 0012FD94
|
||
* ESI 09278EA0
|
||
* EDI 118314E0
|
||
* EIP 00504AD0 .00504AD0
|
||
*
|
||
* Sample game ワルキューレロマンツェ (QLiE1):
|
||
* Garbage:
|
||
* 0A5115D0 83 56 83 69 83 8A 83 49 5C 8B A4 92 CA 5C 6B 79 シナリオ\共通\ky
|
||
* 0A5115E0 6F 5F 30 30 31 5F 30 30 2E 73 00 00 50 FF 50 0A o_001_00.s..PP.
|
||
*
|
||
* Name:
|
||
* 0012FB84 00544913 RETURN to .00544913 from .004FFB04
|
||
* 0012FB88 0012FDBC Pointer to next SEH record
|
||
* 0012FB8C 00544BB1 SE handler
|
||
* 0012FB90 0012FD94
|
||
* 0012FB94 01A139A8
|
||
* 0012FB98 01A139A8
|
||
* 0012FB9C 07D35D00
|
||
* 0012FBA0 00000000
|
||
*
|
||
* EAX 0C303340
|
||
* ECX 00000003
|
||
* EDX 0ED8A620
|
||
* EBX 0041D6A8 .0041D6A8
|
||
* ESP 0012FB84
|
||
* EBP 0012FD94
|
||
* ESI 07D35D00
|
||
* EDI 01A139A8
|
||
* EIP 004FFB04 .004FFB04
|
||
*
|
||
* 01A139A8 60 27 52 00 00 00 00 00 00 00 00 00 00 00 80 3F `'R...........?
|
||
* 01A139B8 00 00 80 3F 00 00 00 00 00 00 00 00 00 00 80 3F ..?..........?
|
||
* 01A139C8 00 00 00 00 48 D9 14 0A 68 D9 14 0A 07 02 00 00 ....Hル.hル...
|
||
* 01A139D8 3C F1 07 00 93 9A 5C 00 1C 01 00 00 F4 01 00 00 <・.答\...・..
|
||
* 01A139E8 40 33 30 0C A0 D9 A0 01 C0 29 52 00 00 00 00 00 @30.ルタ)R.....
|
||
* 01A139F8 00 00 00 00 00 00 80 3F 00 00 80 3F 00 00 00 00 ......?..?....
|
||
*
|
||
* Scenario:
|
||
* 0012FB84 00544913 RETURN to .00544913 from .004FFB04
|
||
* 0012FB88 0012FDBC Pointer to next SEH record
|
||
* 0012FB8C 00544BB1 SE handler
|
||
* 0012FB90 0012FD94
|
||
* 0012FB94 01A13960 ; jichi: type string is saved here in edi and arg4/arg5
|
||
* 0012FB98 01A13960
|
||
* 0012FB9C 07D35D00
|
||
* 0012FBA0 00000000
|
||
*
|
||
* 0A14D7C8 30 5F 4D 65 73 73 61 67 65 54 65 78 74 2C 30 00 0_MessageText,0.
|
||
*
|
||
* EAX 0C308500
|
||
* ECX 00000006
|
||
* EDX 0B100590
|
||
* EBX 0041D6A8 .0041D6A8
|
||
* ESP 0012FB84
|
||
* EBP 0012FD94
|
||
* ESI 07D35D00
|
||
* EDI 01A13960
|
||
* EIP 004FFB04 .004FFB04
|
||
*
|
||
*
|
||
* 01A13960 60 27 52 00 00 00 00 00 00 00 00 00 00 00 80 3F `'R...........?
|
||
* 01A13970 00 00 80 3F 00 00 00 00 00 00 00 00 00 00 80 3F ..?..........?
|
||
* 01A13980 00 00 00 00 C8 D7 14 0A A8 D8 14 0A 07 02 00 00 ....ネラ.ィリ...
|
||
* 01A13990 34 90 3F 00 BE 0A 5B 00 D3 02 00 00 EC 01 00 00 4・.セ.[.モ..・..
|
||
* 01A139A0 00 85 30 0C A0 D9 A0 01 60 27 52 00 00 00 00 00 .・.ル`'R.....
|
||
* 01A139B0 00 00 00 00 00 00 80 3F 00 00 80 3F 00 00 00 00 ......?..?....
|
||
*
|
||
* 0A14D948 30 5F 4E 61 6D 65 54 65 78 74 2C 30 00 00 00 00 0_NameText,0....
|
||
*/
|
||
|
||
/**
|
||
* Known Type strings
|
||
* These strings seems to be different for different games
|
||
*
|
||
* ワルキューレロマンツェ(QLiE1)
|
||
* 七つのふしぎの終わるとき (QLiE1)
|
||
*
|
||
* 0_NameText,0
|
||
* 0_MessageText,0
|
||
* 0_Message,0
|
||
*
|
||
* ワルキューレロマンツェ More&More (QLiE2)
|
||
* 0_nametext,0
|
||
* 0_imo_message,0
|
||
*
|
||
* 月に寄りそう乙女の作法2 (QLiE2):
|
||
* 0_dialogmessage,0
|
||
* $windowapril
|
||
* fontsize:30:30
|
||
*
|
||
*/
|
||
|
||
struct TextArgument // root at [edx - 4]
|
||
{
|
||
DWORD size; // in [edx-4]
|
||
char text[1]; // in edx
|
||
|
||
bool isValid() const
|
||
{
|
||
return text && size
|
||
&& Engine::isAddressReadable(text, size)
|
||
&& ::strlen(text) == size;
|
||
}
|
||
};
|
||
|
||
struct TypeArgument
|
||
{
|
||
DWORD unknown[8]; // 0x20
|
||
|
||
DWORD textFlag; // +0x20, 0 for QLiE1, 1 for QLie2
|
||
LPCSTR textAddress; // for QLiE1
|
||
char textData[1]; // for QLiE2
|
||
|
||
LPCSTR text() const
|
||
{
|
||
if (textFlag == 0) // QLiE1
|
||
return Engine::isAddressReadable(textAddress) ? textAddress : nullptr;
|
||
else // QLiE2
|
||
return textData;
|
||
}
|
||
|
||
// Return UnknownRole(0) if not sure
|
||
Engine::TextRole role() const
|
||
{
|
||
if (textFlag > 0xff)
|
||
return Engine::OtherRole;
|
||
LPCSTR t = text();
|
||
if (!t || !*t)
|
||
return Engine::UnknownRole;
|
||
for (int i = 0; t[i]; i++) {
|
||
if (i > 0x40) // text too large
|
||
return Engine::OtherRole;
|
||
BYTE ch = t[0];
|
||
if (ch <= 32 || ch > 127) // non-printable or not ascii
|
||
return Engine::OtherRole;
|
||
}
|
||
|
||
// Convert to lower case
|
||
std::string s = stolower(std::string(t));
|
||
t = s.c_str();
|
||
|
||
if (::strchr(t, '_')) {
|
||
// QLiE2
|
||
if (::strstr(t, "_imo_message,"))
|
||
return Engine::ScenarioRole;
|
||
if (::strstr(t, "_dialogmessage,"))
|
||
return Engine::OtherRole;
|
||
|
||
// QLiE1
|
||
if (::strstr(t, "_messagetext,"))
|
||
return Engine::ScenarioRole;
|
||
|
||
if (::strstr(t, "_nametext,"))
|
||
return Engine::NameRole;
|
||
if (::strstr(t, "_message,") || // this is ambiguous and will overwrite imo_message
|
||
::strstr(t, "_statetext,") ||
|
||
//::strstr(t, "_databutton,") ||
|
||
//::strstr(t, "_selectbutton,") ||
|
||
::strstr(t, "button,"))
|
||
return Engine::OtherRole;
|
||
}
|
||
|
||
if (s.find_first_of(".[!@*\\") != std::string::npos)
|
||
return Engine::OtherRole;
|
||
|
||
//DOUT("unknown text type:" << t);
|
||
return Engine::UnknownRole;
|
||
}
|
||
};
|
||
int trimmedSize;char*trimmedText;
|
||
int endtype;
|
||
bool hookBefore(hook_stack*s,void* data1, size_t* len,uintptr_t*role)
|
||
{
|
||
|
||
auto arg = (TextArgument *)(s->edx - 4);
|
||
if (!arg->isValid())
|
||
return false;
|
||
trimmedSize = arg->size;
|
||
trimmedText = trim(arg->text, &trimmedSize);
|
||
if (trimmedSize <= 0 || !trimmedText || !*trimmedText)
|
||
return false;
|
||
|
||
if (::strstr(arg->text, "\x82\xa0\x82\xa0\x82\xa0\x82\xa0\x82\xa0")) /* Skip text containing あああああ */
|
||
return false;
|
||
|
||
if (all_ascii(trimmedText)) // This is optional, but I don't want to translate English
|
||
return false;
|
||
//role = Engine::OtherRole;
|
||
|
||
enum { sig = 0 };
|
||
* role = Engine::ScenarioRole;
|
||
|
||
enum : uint16_t {
|
||
w_name_open = 0x7981, /* 【 */
|
||
w_name_close = 0x7a81 /* 】 */
|
||
};
|
||
|
||
// if (trimmedText[trimmedSize]) // text ending withb ']' is other text
|
||
// *role = Engine::OtherRole;
|
||
{
|
||
std::string oldData(trimmedText, trimmedSize);
|
||
endtype=0;
|
||
if(oldData.size()>3&&oldData.substr(oldData.size()-3)=="[n]"){
|
||
endtype=1;trimmedSize-=3;
|
||
|
||
}else if(oldData.size()>3&&oldData.substr(oldData.size()-3)=="[c]"){
|
||
endtype=2;trimmedSize-=3;
|
||
}
|
||
}
|
||
|
||
if (trimmedSize > 4
|
||
&& w_name_open == *(uint16_t *)trimmedText
|
||
&& w_name_close == *(uint16_t *)(trimmedText + trimmedSize - 2)) {
|
||
trimmedText += 2;
|
||
trimmedSize -= 4;
|
||
if (*role == Engine::ScenarioRole)
|
||
*role = Engine::NameRole; // FIXME: This name recognition logic does not work for ワルキューレロマンツェ
|
||
}
|
||
|
||
|
||
// Skip sjis 名前 = 96bc914f
|
||
if (0 == ::strncmp(trimmedText, "\x96\xbc\x91\x4f", trimmedSize))
|
||
return false;
|
||
/*
|
||
if (s->stack[4] == s->stack[5]) { // && s->edi == s->stack[4]
|
||
auto t = (TypeArgument *)s->stack[4];
|
||
if (Engine::isAddressReadable(t)) {
|
||
//if (!t->isValid())
|
||
// return true;
|
||
if (auto r = t->role())
|
||
*role = r;
|
||
}
|
||
}
|
||
*/
|
||
//auto split = s->stack[0]; // retaddr is always the same anyway
|
||
std::string oldData(trimmedText, trimmedSize);
|
||
|
||
strcpy((char*)data1,oldData.c_str());
|
||
*len=oldData.size();
|
||
return true;
|
||
}
|
||
void hookafter(hook_stack*s,void* data1, size_t len)
|
||
{
|
||
std::string newData=std::string((char*)data1,len);
|
||
|
||
auto arg = (TextArgument *)(s->edx - 4);
|
||
int prefixSize = trimmedText - arg->text,
|
||
suffixSize = arg->size - prefixSize - trimmedSize;
|
||
if (prefixSize)
|
||
newData.insert(0,std::string(arg->text, prefixSize));
|
||
if (suffixSize)
|
||
newData.append(trimmedText + trimmedSize, suffixSize);
|
||
if(endtype==1)
|
||
newData=newData+"[n]";
|
||
else if(endtype==2)
|
||
newData=newData+"[c]";
|
||
static std::string data_;
|
||
data_ = newData;
|
||
s->edx = (ULONG)data_.c_str(); // reset arg1
|
||
*(DWORD *)(s->edx - 4) = data_.size();
|
||
//arg->size = data_.size(); // no idea why this will crash ...
|
||
|
||
//*(DWORD *)(s->edx - 4) = newData.size() + trimmedText - text;
|
||
//::strcpy(trimmedText, newData.constData());
|
||
}
|
||
} // namespace Private
|
||
|
||
/**
|
||
* Sample game: 月に寄りそう乙女の作法2
|
||
* See: http://capita.tistory.com/m/post/236
|
||
*
|
||
* This function is not aligned.
|
||
* Text in edx. Length in [edx - 4]
|
||
*
|
||
* 00513234 55 PUSH EBP
|
||
* 00513235 8BEC MOV EBP,ESP
|
||
* 00513237 6A 00 PUSH 0x0
|
||
* 00513239 53 PUSH EBX
|
||
* 0051323A 56 PUSH ESI
|
||
* 0051323B 8BF2 MOV ESI,EDX
|
||
* 0051323D 8BD8 MOV EBX,EAX
|
||
* 0051323F 33C0 XOR EAX,EAX
|
||
* 00513241 55 PUSH EBP
|
||
* 00513242 68 AD325100 PUSH .005132AD
|
||
* 00513247 64:FF30 PUSH DWORD PTR FS:[EAX]
|
||
* 0051324A 64:8920 MOV DWORD PTR FS:[EAX],ESP
|
||
* 0051324D 80BB 0A160000 00 CMP BYTE PTR DS:[EBX+0x160A],0x0 ; jichi: can be used as pattern to distinguish QLiE1/2
|
||
* 00513254 74 07 JE SHORT .0051325D
|
||
* 00513256 8BC3 MOV EAX,EBX
|
||
* 00513258 8B10 MOV EDX,DWORD PTR DS:[EAX]
|
||
* 0051325A FF52 24 CALL DWORD PTR DS:[EDX+0x24]
|
||
* 0051325D 8BC3 MOV EAX,EBX
|
||
* 0051325F E8 98C1FFFF CALL .0050F3FC
|
||
* 00513264 84C0 TEST AL,AL
|
||
* 00513266 74 07 JE SHORT .0051326F
|
||
* 00513268 8BC3 MOV EAX,EBX
|
||
* 0051326A 8B10 MOV EDX,DWORD PTR DS:[EAX]
|
||
* 0051326C FF52 24 CALL DWORD PTR DS:[EDX+0x24]
|
||
* 0051326F 8D4D FC LEA ECX,DWORD PTR SS:[EBP-0x4]
|
||
* 00513272 8BD6 MOV EDX,ESI
|
||
* 00513274 8BC3 MOV EAX,EBX
|
||
* 00513276 E8 5D310000 CALL .005163D8
|
||
* 0051327B 8B55 FC MOV EDX,DWORD PTR SS:[EBP-0x4]
|
||
* 0051327E 8BC3 MOV EAX,EBX
|
||
* 00513280 E8 1B100000 CALL .005142A0
|
||
* 00513285 8BC3 MOV EAX,EBX
|
||
* 00513287 E8 5C300000 CALL .005162E8
|
||
* 0051328C 85C0 TEST EAX,EAX
|
||
* 0051328E 75 07 JNZ SHORT .00513297
|
||
* 00513290 8BC3 MOV EAX,EBX
|
||
* 00513292 E8 B1070000 CALL .00513A48
|
||
* 00513297 33C0 XOR EAX,EAX
|
||
* 00513299 5A POP EDX
|
||
* 0051329A 59 POP ECX
|
||
* 0051329B 59 POP ECX
|
||
* 0051329C 64:8910 MOV DWORD PTR FS:[EAX],EDX
|
||
* 0051329F 68 B4325100 PUSH .005132B4
|
||
* 005132A4 8D45 FC LEA EAX,DWORD PTR SS:[EBP-0x4]
|
||
* 005132A7 E8 F421EFFF CALL .004054A0
|
||
* 005132AC C3 RETN
|
||
* 005132AD ^E9 A21AEFFF JMP .00404D54
|
||
* 005132B2 ^EB F0 JMP SHORT .005132A4
|
||
* 005132B4 5E POP ESI
|
||
* 005132B5 5B POP EBX
|
||
* 005132B6 59 POP ECX
|
||
* 005132B7 5D POP EBP
|
||
* 005132B8 C3 RETN
|
||
* 005132B9 8D40 00 LEA EAX,DWORD PTR DS:[EAX]
|
||
* 005132BC 55 PUSH EBP
|
||
* 005132BD 8BEC MOV EBP,ESP
|
||
* 005132BF 8B45 08 MOV EAX,DWORD PTR SS:[EBP+0x8]
|
||
* 005132C2 8B40 FC MOV EAX,DWORD PTR DS:[EAX-0x4]
|
||
* 005132C5 80B8 6F180000 00 CMP BYTE PTR DS:[EAX+0x186F],0x0
|
||
* 005132CC 74 23 JE SHORT .005132F1
|
||
* 005132CE A1 C8EA5700 MOV EAX,DWORD PTR DS:[0x57EAC8]
|
||
* 005132D3 8B80 FC020000 MOV EAX,DWORD PTR DS:[EAX+0x2FC]
|
||
* 005132D9 8B15 C8EA5700 MOV EDX,DWORD PTR DS:[0x57EAC8] ; .00586178
|
||
* 005132DF 8B92 E8020000 MOV EDX,DWORD PTR DS:[EDX+0x2E8]
|
||
* 005132E5 3BD0 CMP EDX,EAX
|
||
* 005132E7 7C 02 JL SHORT .005132EB
|
||
* 005132E9 8BC2 MOV EAX,EDX
|
||
* 005132EB 0105 B8E45700 ADD DWORD PTR DS:[0x57E4B8],EAX
|
||
* 005132F1 5D POP EBP
|
||
* 005132F2 C3 RETN
|
||
* 005132F3 90 NOP
|
||
* 005132F4 55 PUSH EBP
|
||
* 005132F5 8BEC MOV EBP,ESP
|
||
* 005132F7 53 PUSH EBX
|
||
* 005132F8 8B5D 08 MOV EBX,DWORD PTR SS:[EBP+0x8]
|
||
* ...
|
||
*
|
||
* {00528988(E9 73 FC 04 00 90),00578600(8D 45 FC 8B 4D FC 66 81 39 81 79 74 05 90 90 90 90 90 E9 77 03 FB FF)}
|
||
* {00528988(E9 73 FC 04 00 90),005785FE(EB 27 8D 45 FC 8B 4D FC 66 81 39 81 79 74 0A 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 68 8E 89 52 00 C3)}
|
||
*
|
||
* FORCEFONT(5),FONT(Gulim,-13),ENCODEKOR,HOOK(0x00513234,TRANS(EDX,LEN(-4),PTRCHEAT),RETNPOS(COPY)),HOOK(0x0057860D,TRANS(ECX,LEN(-4),PTRCHEAT),RETNPOS(SOURCE))
|
||
*
|
||
* Character handled here, which is not used:
|
||
* 00528969 74 28 JE SHORT .00528993
|
||
* 0052896B 3C 09 CMP AL,0x9
|
||
* 0052896D 74 24 JE SHORT .00528993
|
||
* 0052896F 3C 2F CMP AL,0x2F
|
||
* 00528971 74 20 JE SHORT .00528993
|
||
* 00528973 3C 40 CMP AL,0x40
|
||
* 00528975 74 1C JE SHORT .00528993
|
||
* 00528977 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-0x18]
|
||
* 0052897A 8D93 49010000 LEA EDX,DWORD PTR DS:[EBX+0x149]
|
||
* 00528980 E8 7FCDEDFF CALL .00405704
|
||
* 00528985 8B55 E8 MOV EDX,DWORD PTR SS:[EBP-0x18]
|
||
* 00528988 8D45 FC LEA EAX,DWORD PTR SS:[EBP-0x4] ; jichi: 2-byte character in ecx
|
||
* 0052898B 8B4D FC MOV ECX,DWORD PTR SS:[EBP-0x4]
|
||
* 0052898E E8 25CEEDFF CALL .004057B8
|
||
* 00528993 8D83 4C020000 LEA EAX,DWORD PTR DS:[EBX+0x24C]
|
||
* 00528999 8B55 FC MOV EDX,DWORD PTR SS:[EBP-0x4]
|
||
* 0052899C E8 53CBEDFF CALL .004054F4
|
||
* 005289A1 8B83 4C020000 MOV EAX,DWORD PTR DS:[EBX+0x24C]
|
||
* 005289A7 85C0 TEST EAX,EAX
|
||
* 005289A9 74 05 JE SHORT .005289B0
|
||
* 005289AB 83E8 04 SUB EAX,0x4
|
||
* 005289AE 8B00 MOV EAX,DWORD PTR DS:[EAX]
|
||
* 005289B0 8983 50020000 MOV DWORD PTR DS:[EBX+0x250],EAX
|
||
* 005289B6 C645 F7 01 MOV BYTE PTR SS:[EBP-0x9],0x1
|
||
* 005289BA 33C0 XOR EAX,EAX
|
||
* 005289BC 5A POP EDX
|
||
* 005289BD 59 POP ECX
|
||
* 005289BE 59 POP ECX
|
||
* 005289BF 64:8910 MOV DWORD PTR FS:[EAX],EDX
|
||
* 005289C2 68 E4895200 PUSH .005289E4
|
||
* 005289C7 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-0x18]
|
||
* 005289CA BA 03000000 MOV EDX,0x3
|
||
* 005289CF E8 F0CAEDFF CALL .004054C4
|
||
* 005289D4 8D45 FC LEA EAX,DWORD PTR SS:[EBP-0x4]
|
||
* 005289D7 E8 C4CAEDFF CALL .004054A0
|
||
* 005289DC C3 RETN
|
||
* 005289DD ^E9 72C3EDFF JMP .00404D54
|
||
* 005289E2 ^EB E3 JMP SHORT .005289C7
|
||
* 005289E4 0FB645 F7 MOVZX EAX,BYTE PTR SS:[EBP-0x9]
|
||
* 005289E8 5F POP EDI
|
||
* 005289E9 5E POP ESI
|
||
* 005289EA 5B POP EBX
|
||
* 005289EB 8BE5 MOV ESP,EBP
|
||
* 005289ED 5D POP EBP
|
||
* 005289EE C3 RETN
|
||
* 005289EF 90 NOP
|
||
* 005289F0 55 PUSH EBP
|
||
* 005289F1 8BEC MOV EBP,ESP
|
||
* 005289F3 83C4 F8 ADD ESP,-0x8
|
||
* 005289F6 53 PUSH EBX
|
||
*
|
||
* Sample game: ワルキューレロマンツェ (QLiE1)
|
||
*
|
||
* This function is found by looking all all matches of the following pattern
|
||
* And then lookup up for push ebp
|
||
* 005132E5 3BD0 CMP EDX,EAX
|
||
* 005132E7 7C 02 JL SHORT .005132EB
|
||
* 005132E9 8BC2 MOV EAX,EDX
|
||
*
|
||
* 004FFB04 55 PUSH EBP
|
||
* 004FFB05 8BEC MOV EBP,ESP
|
||
* 004FFB07 6A 00 PUSH 0x0
|
||
* 004FFB09 53 PUSH EBX
|
||
* 004FFB0A 56 PUSH ESI
|
||
* 004FFB0B 8BF2 MOV ESI,EDX
|
||
* 004FFB0D 8BD8 MOV EBX,EAX
|
||
* 004FFB0F 33C0 XOR EAX,EAX
|
||
* 004FFB11 55 PUSH EBP
|
||
* 004FFB12 68 7DFB4F00 PUSH .004FFB7D
|
||
* 004FFB17 64:FF30 PUSH DWORD PTR FS:[EAX]
|
||
* 004FFB1A 64:8920 MOV DWORD PTR FS:[EAX],ESP
|
||
* 004FFB1D 80BB FA150000 00 CMP BYTE PTR DS:[EBX+0x15FA],0x0
|
||
* 004FFB24 74 07 JE SHORT .004FFB2D
|
||
* 004FFB26 8BC3 MOV EAX,EBX
|
||
* 004FFB28 8B10 MOV EDX,DWORD PTR DS:[EAX]
|
||
* 004FFB2A FF52 1C CALL DWORD PTR DS:[EDX+0x1C]
|
||
* 004FFB2D 8BC3 MOV EAX,EBX
|
||
* 004FFB2F E8 04CFFFFF CALL .004FCA38
|
||
* 004FFB34 84C0 TEST AL,AL
|
||
* 004FFB36 74 07 JE SHORT .004FFB3F
|
||
* 004FFB38 8BC3 MOV EAX,EBX
|
||
* 004FFB3A 8B10 MOV EDX,DWORD PTR DS:[EAX]
|
||
* 004FFB3C FF52 1C CALL DWORD PTR DS:[EDX+0x1C]
|
||
* 004FFB3F 8D4D FC LEA ECX,DWORD PTR SS:[EBP-0x4]
|
||
* 004FFB42 8BD6 MOV EDX,ESI
|
||
* 004FFB44 8BC3 MOV EAX,EBX
|
||
* 004FFB46 E8 69320000 CALL .00502DB4
|
||
* 004FFB4B 8B55 FC MOV EDX,DWORD PTR SS:[EBP-0x4]
|
||
* 004FFB4E 8BC3 MOV EAX,EBX
|
||
* 004FFB50 E8 23120000 CALL .00500D78
|
||
* 004FFB55 8BC3 MOV EAX,EBX
|
||
* 004FFB57 E8 58310000 CALL .00502CB4
|
||
* 004FFB5C 85C0 TEST EAX,EAX
|
||
* 004FFB5E 75 07 JNZ SHORT .004FFB67
|
||
* 004FFB60 8BC3 MOV EAX,EBX
|
||
* 004FFB62 E8 5D070000 CALL .005002C4
|
||
* 004FFB67 33C0 XOR EAX,EAX
|
||
* 004FFB69 5A POP EDX
|
||
* 004FFB6A 59 POP ECX
|
||
* 004FFB6B 59 POP ECX
|
||
* 004FFB6C 64:8910 MOV DWORD PTR FS:[EAX],EDX
|
||
* 004FFB6F 68 84FB4F00 PUSH .004FFB84
|
||
* 004FFB74 8D45 FC LEA EAX,DWORD PTR SS:[EBP-0x4]
|
||
* 004FFB77 E8 5859F0FF CALL .004054D4
|
||
* 004FFB7C C3 RETN
|
||
* 004FFB7D ^E9 0652F0FF JMP .00404D88
|
||
* 004FFB82 ^EB F0 JMP SHORT .004FFB74
|
||
* 004FFB84 5E POP ESI
|
||
* 004FFB85 5B POP EBX
|
||
* 004FFB86 59 POP ECX
|
||
* 004FFB87 5D POP EBP
|
||
* 004FFB88 C3 RETN
|
||
* 004FFB89 8D40 00 LEA EAX,DWORD PTR DS:[EAX]
|
||
* 004FFB8C 55 PUSH EBP
|
||
* 004FFB8D 8BEC MOV EBP,ESP
|
||
* 004FFB8F 8B45 08 MOV EAX,DWORD PTR SS:[EBP+0x8]
|
||
* 004FFB92 8B40 FC MOV EAX,DWORD PTR DS:[EAX-0x4]
|
||
* 004FFB95 80B8 4F180000 00 CMP BYTE PTR DS:[EAX+0x184F],0x0
|
||
* 004FFB9C 74 23 JE SHORT .004FFBC1
|
||
* 004FFB9E A1 E4CA5600 MOV EAX,DWORD PTR DS:[0x56CAE4]
|
||
* 004FFBA3 8B80 CC020000 MOV EAX,DWORD PTR DS:[EAX+0x2CC]
|
||
* 004FFBA9 8B15 E4CA5600 MOV EDX,DWORD PTR DS:[0x56CAE4] ; .005740E8
|
||
* 004FFBAF 8B92 B8020000 MOV EDX,DWORD PTR DS:[EDX+0x2B8]
|
||
* 004FFBB5 3BD0 CMP EDX,EAX
|
||
* 004FFBB7 7C 02 JL SHORT .004FFBBB
|
||
* 004FFBB9 8BC2 MOV EAX,EDX
|
||
* 004FFBBB 0105 64C45600 ADD DWORD PTR DS:[0x56C464],EAX
|
||
* 004FFBC1 5D POP EBP
|
||
* 004FFBC2 C3 RETN
|
||
* 004FFBC3 90 NOP
|
||
*/
|
||
bool attach(ULONG startAddress, ULONG stopAddress)
|
||
{
|
||
// QLiE1
|
||
// 004FFB1D 80BB FA150000 00 CMP BYTE PTR DS:[EBX+0x15FA],0x0
|
||
// QLiE2
|
||
// 0051324D 80BB 0A160000 00 CMP BYTE PTR DS:[EBX+0x160A],0x0 ; jichi: instruction used as pattern
|
||
|
||
const uint8_t bytes[] = { // i.e. 3BD0 7C 02 8BC2 0105
|
||
0x3B,0xD0, // 004FFBB5 3BD0 CMP EDX,EAX
|
||
0x7C, 0x02, // 004FFBB7 7C 02 JL SHORT .004FFBBB
|
||
0x8B,0xC2, // 004FFBB9 8BC2 MOV EAX,EDX
|
||
0x01,0x05 //64C45600 // 004FFBBB 0105 64C45600 ADD DWORD PTR DS:[0x56C464],EAX
|
||
};
|
||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
|
||
if (!addr)
|
||
return false;
|
||
// 00513234 55 PUSH EBP ; jichi: hook here
|
||
// 00513235 8BEC MOV EBP,ESP
|
||
// 00513237 6A 00 PUSH 0x0
|
||
// 00513239 53 PUSH EBX
|
||
// 0051323A 56 PUSH ESI
|
||
enum : DWORD { sig = 0x6aec8b55 };
|
||
enum { AlignedStep = 1 }; // function not aligned
|
||
addr = MemDbg::findEnclosingFunctionBeforeDword(sig, addr, MemDbg::MaximumFunctionSize, AlignedStep);
|
||
if (!addr)
|
||
return false;
|
||
HookParam hp;
|
||
hp.address=addr;
|
||
hp.hook_before=Private::hookBefore;
|
||
hp.hook_after=Private::hookafter;
|
||
hp.newlineseperator=L"[n]";
|
||
hp.type=EMBED_ABLE|EMBED_DYNA_SJIS|USING_STRING;
|
||
hp.hook_font=F_ExtTextOutA|F_GetTextExtentPoint32A;
|
||
hp.filter_fun=[](void* data, size_t* len, HookParam* hp){
|
||
|
||
static std::regex rx("\\[rb,(.*?),.+\\]");
|
||
auto _=std::regex_replace(std::string((char*)data,*len), rx, "$1");
|
||
|
||
strcpy((char*)data,_.c_str());*len=_.size();
|
||
return true;
|
||
};
|
||
return NewHook(hp,"EmbedQLIE");
|
||
}
|
||
|
||
} // namespace ScenarioHook
|
||
|
||
} // unnamed namespace
|
||
|
||
bool QLIE::attach_function() {
|
||
auto embed=ScenarioHook::attach(processStartAddress, processStopAddress);
|
||
return InsertQLIEHook()||embed;
|
||
}
|