LunaHook-mirror/LunaHook/engine32/ApricoT.cpp
恍兮惚兮 edc5efec99 format
2024-11-02 15:49:09 +08:00

161 lines
5.7 KiB
C++
Raw Blame History

#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();
}