mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-12-26 13:14:13 +08:00
147 lines
5.6 KiB
C++
147 lines
5.6 KiB
C++
#include"ApricoT.h"
|
||
|
||
/********************************************************************************************
|
||
Apricot hook:
|
||
Game folder contains arc.a*.
|
||
This engine is heavily based on new DirectX interfaces.
|
||
I can't find a good place where text is clean and not repeating.
|
||
The game processes script encoded in UTF32-like format.
|
||
I reversed the parsing algorithm of the game and implemented it partially.
|
||
Only name and text data is needed.
|
||
|
||
********************************************************************************************/
|
||
|
||
/** jichi 2/15/2015: ApricoT
|
||
*
|
||
* Sample game: イセカイ・ラヴァーズ<E383BC>体験版
|
||
* Issue of the old game is that it uses esp as split, and hence has relative address
|
||
*
|
||
* 00978100 5b pop ebx
|
||
* 00978101 83c4 2c add esp,0x2c
|
||
* 00978104 c2 0400 retn 0x4
|
||
* 00978107 33c0 xor eax,eax ; jichi: hook here
|
||
* 00978109 bb 03000000 mov ebx,0x3
|
||
* 0097810e 895c24 30 mov dword ptr ss:[esp+0x30],ebx
|
||
* 00978112 894424 2c mov dword ptr ss:[esp+0x2c],eax
|
||
* 00978116 894424 1c mov dword ptr ss:[esp+0x1c],eax
|
||
* 0097811a 8b4e 34 mov ecx,dword ptr ds:[esi+0x34]
|
||
* 0097811d 3b4e 3c cmp ecx,dword ptr ds:[esi+0x3c]
|
||
* 00978120 894424 3c mov dword ptr ss:[esp+0x3c],eax
|
||
* 00978124 7e 3b jle short .00978161
|
||
* 00978126 8b7e 3c mov edi,dword ptr ds:[esi+0x3c]
|
||
* 00978129 3b7e 34 cmp edi,dword ptr ds:[esi+0x34]
|
||
* 0097812c 76 05 jbe short .00978133
|
||
* 0097812e e8 01db1500 call .00ad5c34
|
||
* 00978133 837e 38 04 cmp dword ptr ds:[esi+0x38],0x4
|
||
* 00978137 72 05 jb short .0097813e
|
||
* 00978139 8b46 24 mov eax,dword ptr ds:[esi+0x24]
|
||
* 0097813c eb 03 jmp short .00978141
|
||
* 0097813e 8d46 24 lea eax,dword ptr ds:[esi+0x24]
|
||
* 00978141 8b3cb8 mov edi,dword ptr ds:[eax+edi*4]
|
||
* 00978144 016e 3c add dword ptr ds:[esi+0x3c],ebp
|
||
* 00978147 57 push edi
|
||
* 00978148 55 push ebp
|
||
* 00978149 8d4c24 20 lea ecx,dword ptr ss:[esp+0x20]
|
||
* 0097814d e8 de05feff call .00958730
|
||
*
|
||
* Sample stack: baseaddr = 0c90000
|
||
* 001aec2c ede50fbb
|
||
* 001aec30 0886064c
|
||
* 001aec34 08860bd0
|
||
* 001aec38 08860620
|
||
* 001aec3c 00000000
|
||
* 001aec40 00000000
|
||
* 001aec44 08860bd0
|
||
* 001aec48 001aee18
|
||
* 001aec4c 08860620
|
||
* 001aec50 00000000
|
||
* 001aec54 00cb4408 return to .00cb4408 from .00c973e0
|
||
* 001aec58 08860bd8
|
||
* 001aec5c 00000000
|
||
* 001aec60 001aefd8 pointer to next seh record
|
||
* 001aec64 00e47d88 se handler
|
||
* 001aec68 ffffffff
|
||
* 001aec6c 00cb9f40 return to .00cb9f40 from .00cc8030 ; jichi: split here
|
||
*/
|
||
static void SpecialHookApricoT(hook_stack* stack, HookParam *, uintptr_t *data, uintptr_t *split, size_t *len)
|
||
{
|
||
DWORD reg_esi = stack->esi;
|
||
DWORD base = *(DWORD *)(reg_esi + 0x24);
|
||
DWORD index = *(DWORD *)(reg_esi + 0x3c);
|
||
DWORD *script = (DWORD *)(base + index * 4);
|
||
// jichi 2/14/2015
|
||
// Change reg_esp to the return address
|
||
//DWORD reg_esp = regof(esp, esp_base);
|
||
//*split = reg_esp;
|
||
//*split = regof(esp, esp_base);
|
||
DWORD arg = stack->stack[16]; // return address
|
||
*split = arg > processStartAddress ? arg - processStartAddress : arg; // use relative split value
|
||
//*split = argof(1, esp_base);
|
||
if (script[0] == L'<') {
|
||
DWORD *end;
|
||
for (end = script; *end != L'>'; end++); // jichi 2/14/2015: i.e. = ::wcschr(script) or script
|
||
switch (script[1]) {
|
||
case L'N':
|
||
if (script[2] == L'a' && script[3] == L'm' && script[4] == L'e') {
|
||
buffer_index = 0;
|
||
for (script += 5; script < end; script++)
|
||
if (*script > 0x20)
|
||
wc_buffer[buffer_index++] = *script & 0xFFFF;
|
||
*len = buffer_index<<1;
|
||
*data = (DWORD)wc_buffer;
|
||
// jichi 1/4/2014: The way I save subconext is not able to distinguish the split value
|
||
// Change to shift 16
|
||
//*split |= 1 << 31;
|
||
*split |= 1 << 16; // jichi: differentiate name and text script
|
||
} break;
|
||
case L'T':
|
||
if (script[2] == L'e' && script[3] == L'x' && script[4] == L't') {
|
||
buffer_index = 0;
|
||
for (script += 5; script < end; script++) {
|
||
if (*script > 0x40) {
|
||
while (*script == L'{') {
|
||
script++;
|
||
while (*script!=L'\\') {
|
||
wc_buffer[buffer_index++] = *script & 0xffff;
|
||
script++;
|
||
}
|
||
while (*script++!=L'}');
|
||
}
|
||
wc_buffer[buffer_index++] = *script & 0xffff;
|
||
}
|
||
}
|
||
*len = buffer_index << 1;
|
||
*data = (DWORD)wc_buffer;
|
||
} break;
|
||
}
|
||
}
|
||
}
|
||
|
||
bool InsertApricoTHook()
|
||
{
|
||
for (DWORD i = processStartAddress + 0x1000; i < processStopAddress - 4; i++)
|
||
if ((*(DWORD *)i & 0xfff8fc) == 0x3cf880) // cmp reg,0x3c
|
||
for (DWORD j = i + 3, k = i + 0x100; j < k; j++)
|
||
if ((*(DWORD *)j & 0xffffff) == 0x4c2) { // retn 4
|
||
HookParam hp;
|
||
hp.address = j + 3;
|
||
hp.text_fun = SpecialHookApricoT;
|
||
hp.type = USING_STRING|NO_CONTEXT|CODEC_UTF16;
|
||
ConsoleOutput("INSERT ApricoT");
|
||
//GROWL_DWORD3(hp.address, processStartAddress, processStopAddress);
|
||
|
||
//RegisterEngineType(ENGINE_APRICOT);
|
||
// jichi 2/14/2015: disable cached GDI functions
|
||
ConsoleOutput("ApRicoT: disable GDI hooks");
|
||
|
||
return NewHook(hp, "ApRicoT");
|
||
}
|
||
|
||
ConsoleOutput("ApricoT: failed");
|
||
return false;
|
||
}
|
||
|
||
bool ApricoT::attach_function() {
|
||
|
||
return InsertApricoTHook();
|
||
}
|