mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-12-27 13:44:11 +08:00
229 lines
10 KiB
C++
229 lines
10 KiB
C++
|
#include"Exp.h"
|
|||
|
|
|||
|
/** jichi 9/8/2014 EXP, http://www.exp-inc.jp
|
|||
|
* Maker: EXP, 5pb
|
|||
|
* Sample game: 剣の街<EFBFBD>異邦人
|
|||
|
*
|
|||
|
* There are three matched memory addresses with SHIFT-JIS.
|
|||
|
* The middle one is used as it is aligned with zeros.
|
|||
|
* The memory address is fixed.
|
|||
|
*
|
|||
|
* There are three functions found using hardware breakpoints.
|
|||
|
* The last one is used as the first two are looped.
|
|||
|
*
|
|||
|
* reladdr = 0x138020
|
|||
|
*
|
|||
|
* baseaddr = 0x00120000
|
|||
|
*
|
|||
|
* 0025801d cc int3
|
|||
|
* 0025801e cc int3
|
|||
|
* 0025801f cc int3
|
|||
|
* 00258020 55 push ebp ; jichi: hook here
|
|||
|
* 00258021 8bec mov ebp,esp
|
|||
|
* 00258023 8b45 08 mov eax,dword ptr ss:[ebp+0x8]
|
|||
|
* 00258026 83ec 08 sub esp,0x8
|
|||
|
* 00258029 85c0 test eax,eax
|
|||
|
* 0025802b 0f84 d8000000 je .00258109
|
|||
|
* 00258031 837d 10 00 cmp dword ptr ss:[ebp+0x10],0x0
|
|||
|
* 00258035 0f84 ce000000 je .00258109
|
|||
|
* 0025803b 8b10 mov edx,dword ptr ds:[eax] ; jichi: edx is the text
|
|||
|
* 0025803d 8b45 0c mov eax,dword ptr ss:[ebp+0xc]
|
|||
|
* 00258040 53 push ebx
|
|||
|
* 00258041 56 push esi
|
|||
|
* 00258042 c745 f8 00000000 mov dword ptr ss:[ebp-0x8],0x0
|
|||
|
* 00258049 8945 fc mov dword ptr ss:[ebp-0x4],eax
|
|||
|
* 0025804c 57 push edi
|
|||
|
* 0025804d 8d49 00 lea ecx,dword ptr ds:[ecx]
|
|||
|
* 00258050 8a0a mov cl,byte ptr ds:[edx] jichi: text in accessed in edx
|
|||
|
* 00258052 8a45 14 mov al,byte ptr ss:[ebp+0x14]
|
|||
|
* 00258055 3ac1 cmp al,cl
|
|||
|
* 00258057 74 7a je short .002580d3
|
|||
|
* 00258059 8b7d 10 mov edi,dword ptr ss:[ebp+0x10]
|
|||
|
* 0025805c 8b5d fc mov ebx,dword ptr ss:[ebp-0x4]
|
|||
|
* 0025805f 33f6 xor esi,esi
|
|||
|
* 00258061 8bc2 mov eax,edx
|
|||
|
* 00258063 80f9 81 cmp cl,0x81
|
|||
|
* 00258066 72 05 jb short .0025806d
|
|||
|
* 00258068 80f9 9f cmp cl,0x9f
|
|||
|
* 0025806b 76 0a jbe short .00258077
|
|||
|
* 0025806d 80f9 e0 cmp cl,0xe0
|
|||
|
* 00258070 72 1d jb short .0025808f
|
|||
|
* 00258072 80f9 fc cmp cl,0xfc
|
|||
|
* 00258075 77 18 ja short .0025808f
|
|||
|
* 00258077 8b45 fc mov eax,dword ptr ss:[ebp-0x4]
|
|||
|
* 0025807a 85c0 test eax,eax
|
|||
|
* 0025807c 74 05 je short .00258083
|
|||
|
* 0025807e 8808 mov byte ptr ds:[eax],cl
|
|||
|
* 00258080 8d58 01 lea ebx,dword ptr ds:[eax+0x1]
|
|||
|
* 00258083 8b7d 10 mov edi,dword ptr ss:[ebp+0x10]
|
|||
|
* 00258086 8d42 01 lea eax,dword ptr ds:[edx+0x1]
|
|||
|
* 00258089 be 01000000 mov esi,0x1
|
|||
|
* 0025808e 4f dec edi
|
|||
|
* 0025808f 85ff test edi,edi
|
|||
|
* 00258091 74 36 je short .002580c9
|
|||
|
* 00258093 85db test ebx,ebx
|
|||
|
* 00258095 74 04 je short .0025809b
|
|||
|
* 00258097 8a08 mov cl,byte ptr ds:[eax]
|
|||
|
* 00258099 880b mov byte ptr ds:[ebx],cl
|
|||
|
* 0025809b 46 inc esi
|
|||
|
* 0025809c 33c0 xor eax,eax
|
|||
|
* 0025809e 66:3bc6 cmp ax,si
|
|||
|
* 002580a1 7f 47 jg short .002580ea
|
|||
|
* 002580a3 0fbfce movsx ecx,si
|
|||
|
* 002580a6 03d1 add edx,ecx
|
|||
|
* 002580a8 3945 fc cmp dword ptr ss:[ebp-0x4],eax
|
|||
|
* 002580ab 74 03 je short .002580b0
|
|||
|
* 002580ad 014d fc add dword ptr ss:[ebp-0x4],ecx
|
|||
|
* 002580b0 294d 10 sub dword ptr ss:[ebp+0x10],ecx
|
|||
|
* 002580b3 014d f8 add dword ptr ss:[ebp-0x8],ecx
|
|||
|
* 002580b6 8a0a mov cl,byte ptr ds:[edx]
|
|||
|
* 002580b8 80f9 0a cmp cl,0xa
|
|||
|
* 002580bb 74 20 je short .002580dd
|
|||
|
* 002580bd 80f9 0d cmp cl,0xd
|
|||
|
* 002580c0 74 1b je short .002580dd
|
|||
|
* 002580c2 3945 10 cmp dword ptr ss:[ebp+0x10],eax
|
|||
|
* 002580c5 ^75 89 jnz short .00258050
|
|||
|
* 002580c7 eb 21 jmp short .002580ea
|
|||
|
* 002580c9 85db test ebx,ebx
|
|||
|
* 002580cb 74 1d je short .002580ea
|
|||
|
* 002580cd c643 ff 00 mov byte ptr ds:[ebx-0x1],0x0
|
|||
|
* 002580d1 eb 17 jmp short .002580ea
|
|||
|
* 002580d3 84c0 test al,al
|
|||
|
* 002580d5 74 13 je short .002580ea
|
|||
|
* 002580d7 42 inc edx
|
|||
|
* 002580d8 ff45 f8 inc dword ptr ss:[ebp-0x8]
|
|||
|
* 002580db eb 0d jmp short .002580ea
|
|||
|
* 002580dd 8a42 01 mov al,byte ptr ds:[edx+0x1]
|
|||
|
* 002580e0 42 inc edx
|
|||
|
* 002580e1 3c 0a cmp al,0xa
|
|||
|
* 002580e3 74 04 je short .002580e9
|
|||
|
* 002580e5 3c 0d cmp al,0xd
|
|||
|
* 002580e7 75 01 jnz short .002580ea
|
|||
|
* 002580e9 42 inc edx
|
|||
|
* 002580ea 8b45 fc mov eax,dword ptr ss:[ebp-0x4]
|
|||
|
* 002580ed 5f pop edi
|
|||
|
* 002580ee 5e pop esi
|
|||
|
* 002580ef 5b pop ebx
|
|||
|
* 002580f0 85c0 test eax,eax
|
|||
|
* 002580f2 74 09 je short .002580fd
|
|||
|
* 002580f4 837d 10 00 cmp dword ptr ss:[ebp+0x10],0x0
|
|||
|
* 002580f8 74 03 je short .002580fd
|
|||
|
* 002580fa c600 00 mov byte ptr ds:[eax],0x0
|
|||
|
* 002580fd 8b4d 08 mov ecx,dword ptr ss:[ebp+0x8]
|
|||
|
* 00258100 8b45 f8 mov eax,dword ptr ss:[ebp-0x8]
|
|||
|
* 00258103 8911 mov dword ptr ds:[ecx],edx
|
|||
|
* 00258105 8be5 mov esp,ebp
|
|||
|
* 00258107 5d pop ebp
|
|||
|
* 00258108 c3 retn
|
|||
|
* 00258109 33c0 xor eax,eax
|
|||
|
* 0025810b 8be5 mov esp,ebp
|
|||
|
* 0025810d 5d pop ebp
|
|||
|
* 0025810e c3 retn
|
|||
|
* 0025810f cc int3
|
|||
|
*
|
|||
|
* Stack:
|
|||
|
* 0f14f87c 00279177 return to .00279177 from .00258020
|
|||
|
* 0f14f880 0f14f8b0 ; arg1 address of the text's pointer
|
|||
|
* 0f14f884 0f14f8c0 ; arg2 pointed to zero, maybe a buffer
|
|||
|
* 0f14f888 00000047 ; arg3 it is zero if no text, this value might be text size + 1
|
|||
|
* 0f14f88c ffffff80 ; constant, used as split
|
|||
|
* 0f14f890 005768c8 .005768c8
|
|||
|
* 0f14f894 02924340 ; text is at 02924350
|
|||
|
* 0f14f898 00000001 ; this might also be a good split
|
|||
|
* 0f14f89c 1b520020
|
|||
|
* 0f14f8a0 00000000
|
|||
|
* 0f14f8a4 00000000
|
|||
|
* 0f14f8a8 029245fc
|
|||
|
* 0f14f8ac 0004bfd3
|
|||
|
* 0f14f8b0 0f14fae0
|
|||
|
* 0f14f8b4 00000000
|
|||
|
* 0f14f8b8 00000000
|
|||
|
* 0f14f8bc 02924340
|
|||
|
* 0f14f8c0 00000000
|
|||
|
*
|
|||
|
* Registers:
|
|||
|
* eax 0f14f8c0 ; floating at runtime
|
|||
|
* ecx 0f14f8b0; floating at runtime
|
|||
|
* edx 00000000
|
|||
|
* ebx 0f14fae0; floating at runtime
|
|||
|
* esp 0f14f87c; floating at runtime
|
|||
|
* ebp 0f14facc; floating at runtime
|
|||
|
* esi 00000047
|
|||
|
* edi 02924340 ; text is in 02924350
|
|||
|
* eip 00258020 .00258020
|
|||
|
*
|
|||
|
* Memory access pattern:
|
|||
|
* For long sentences, it first render the first line, then the second line, and so on.
|
|||
|
* So, the second line is a subtext of the entire dialog.
|
|||
|
*/
|
|||
|
static void SpecialHookExp(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
|
|||
|
{
|
|||
|
static DWORD lasttext;
|
|||
|
// 00258020 55 push ebp ; jichi: hook here
|
|||
|
// 00258021 8bec mov ebp,esp
|
|||
|
// 00258023 8b45 08 mov eax,dword ptr ss:[ebp+0x8] ; jichi: move arg1 to eax
|
|||
|
// 00258029 85c0 test eax,eax ; check if text is null
|
|||
|
// 0025802b 0f84 d8000000 je .00258109
|
|||
|
// 00258031 837d 10 00 cmp dword ptr ss:[ebp+0x10],0x0 ; jichi: compare 0 with arg3, which is size+1
|
|||
|
// 00258035 0f84 ce000000 je .00258109
|
|||
|
// 0025803b 8b10 mov edx,dword ptr ds:[eax] ; move text address to edx
|
|||
|
DWORD arg1 = stack->stack[1], // mov eax,dword ptr ss:[ebp+0x8]
|
|||
|
arg3 = stack->stack[3]; // size - 1
|
|||
|
if (arg1 && arg3)
|
|||
|
if (DWORD text = *(DWORD *)arg1)
|
|||
|
if (!(text > lasttext && text < lasttext + VNR_TEXT_CAPACITY)) { // text is not a subtext of lastText
|
|||
|
*data = lasttext = text; // mov edx,dword ptr ds:[eax]
|
|||
|
//*len = arg3 - 1; // the last char is the '\0', so -1, but this value is not reliable
|
|||
|
*len = ::strlen((LPCSTR)text);
|
|||
|
// Registers are not used as split as all of them are floating at runtime
|
|||
|
//*split = argof(4, esp_base); // arg4, always -8, this will merge all threads and result in repetition
|
|||
|
*split = stack->stack[7]; // reduce repetition, but still have sub-text repeat
|
|||
|
}
|
|||
|
}
|
|||
|
bool InsertExpHook()
|
|||
|
{
|
|||
|
const BYTE bytes[] = {
|
|||
|
0x55, // 00258020 55 push ebp ; jichi: hook here, function starts, text in [arg1], size+1 in arg3
|
|||
|
0x8b,0xec, // 00258021 8bec mov ebp,esp
|
|||
|
0x8b,0x45, 0x08, // 00258023 8b45 08 mov eax,dword ptr ss:[ebp+0x8]
|
|||
|
0x83,0xec, 0x08, // 00258026 83ec 08 sub esp,0x8
|
|||
|
0x85,0xc0, // 00258029 85c0 test eax,eax
|
|||
|
0x0f,0x84, XX4, // 0025802b 0f84 d8000000 je .00258109
|
|||
|
0x83,0x7d, 0x10, 0x00, // 00258031 837d 10 00 cmp dword ptr ss:[ebp+0x10],0x0
|
|||
|
0x0f,0x84, XX4, // 00258035 0f84 ce000000 je .00258109
|
|||
|
0x8b,0x10, // 0025803b 8b10 mov edx,dword ptr ds:[eax] ; jichi: edx is the text
|
|||
|
0x8b,0x45, 0x0c, // 0025803d 8b45 0c mov eax,dword ptr ss:[ebp+0xc]
|
|||
|
0x53, // 00258040 53 push ebx
|
|||
|
0x56, // 00258041 56 push esi
|
|||
|
0xc7,0x45, 0xf8, 0x00,0x00,0x00,0x00, // 00258042 c745 f8 00000000 mov dword ptr ss:[ebp-0x8],0x0
|
|||
|
0x89,0x45, 0xfc, // 00258049 8945 fc mov dword ptr ss:[ebp-0x4],eax
|
|||
|
0x57, // 0025804c 57 push edi
|
|||
|
0x8d,0x49, 0x00, // 0025804d 8d49 00 lea ecx,dword ptr ds:[ecx]
|
|||
|
0x8a,0x0a // 00258050 8a0a mov cl,byte ptr ds:[edx] ; jichi: text accessed in edx
|
|||
|
};
|
|||
|
enum { addr_offset = 0 };
|
|||
|
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
|||
|
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
|||
|
//GROWL_DWORD(addr);
|
|||
|
if (!addr) {
|
|||
|
ConsoleOutput("EXP: pattern not found");
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
HookParam hp;
|
|||
|
hp.address = addr + addr_offset;
|
|||
|
hp.type = NO_CONTEXT|USING_STRING; // NO_CONTEXT to get rid of floating address
|
|||
|
hp.text_fun = SpecialHookExp;
|
|||
|
ConsoleOutput("INSERT EXP");
|
|||
|
|
|||
|
|
|||
|
ConsoleOutput("EXP: disable GDI hooks"); // There are no GDI functions hooked though
|
|||
|
|
|||
|
return NewHook(hp, "EXP"); // FIXME: text displayed line by line
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
bool Exp::attach_function() {
|
|||
|
|
|||
|
return InsertExpHook();
|
|||
|
}
|