LunaHook-mirror/LunaHook/engine32/Mink.cpp
2024-02-07 20:59:24 +08:00

219 lines
8.4 KiB
C++
Raw Blame History

#include"Mink.h"
/** 12/23/2014 jichi: Mink games (not sure the engine name)
* Sample game:
* - [130111] [Mink EGO] お<>ちも<E381A1>にはぜったい言えなぁ<E381AA><EFBFBD>つなこと<E38193>-- /HB-4*0:64@45164A
* - [141219] [Mink] しすた<E38199>・すきーむ3
*
* Observations from sisters3:
* - GetGlyphOutlineA can get text, but it is cached.
* - It's caller's first argument is the correct text, but I failed to find where it is called
* - Debugging text in memory caused looping
*
* /HB-4*0:64@45164A
* - addr: 0x45164a
* - length_offset: 1
* - split: 0x64
* - off: 0xfffffff8 = -8
* - type: 0x18
*
* Observations from Onechan:
* - There are lots of threads
* - The one with -1 split value is correct, but not sure for all games
* - The result texts still contain garbage, but can be split using return values.
*
* 00451611 e9 ee000000 jmp .00451704
* 00451616 8b45 0c mov eax,dword ptr ss:[ebp+0xc]
* 00451619 3bc3 cmp eax,ebx
* 0045161b 75 2b jnz short .00451648
* 0045161d e8 a9340000 call .00454acb
* 00451622 53 push ebx
* 00451623 53 push ebx
* 00451624 53 push ebx
* 00451625 53 push ebx
* 00451626 53 push ebx
* 00451627 c700 16000000 mov dword ptr ds:[eax],0x16
* 0045162d e8 16340000 call .00454a48
* 00451632 83c4 14 add esp,0x14
* 00451635 385d f4 cmp byte ptr ss:[ebp-0xc],bl
* 00451638 74 07 je short .00451641
* 0045163a 8b45 f0 mov eax,dword ptr ss:[ebp-0x10]
* 0045163d 8360 70 fd and dword ptr ds:[eax+0x70],0xfffffffd
* 00451641 33c0 xor eax,eax
* 00451643 e9 bc000000 jmp .00451704
* 00451648 3818 cmp byte ptr ds:[eax],bl
* 0045164a 75 14 jnz short .00451660 ; jichi: hook here
* 0045164c 385d f4 cmp byte ptr ss:[ebp-0xc],bl
* 0045164f 74 07 je short .00451658
* 00451651 8b45 f0 mov eax,dword ptr ss:[ebp-0x10]
* 00451654 8360 70 fd and dword ptr ds:[eax+0x70],0xfffffffd
* 00451658 8b45 08 mov eax,dword ptr ss:[ebp+0x8]
* 0045165b e9 a4000000 jmp .00451704
* 00451660 56 push esi
* 00451661 8b75 08 mov esi,dword ptr ss:[ebp+0x8]
* 00451664 3bf3 cmp esi,ebx
* 00451666 75 28 jnz short .00451690
* 00451668 e8 5e340000 call .00454acb
* 0045166d 53 push ebx
* 0045166e 53 push ebx
* 0045166f 53 push ebx
* 00451670 53 push ebx
* 00451671 53 push ebx
* 00451672 c700 16000000 mov dword ptr ds:[eax],0x16
* 00451678 e8 cb330000 call .00454a48
* 0045167d 83c4 14 add esp,0x14
* 00451680 385d f4 cmp byte ptr ss:[ebp-0xc],bl
* 00451683 74 07 je short .0045168c
* 00451685 8b45 f0 mov eax,dword ptr ss:[ebp-0x10]
* 00451688 8360 70 fd and dword ptr ds:[eax+0x70],0xfffffffd
* 0045168c 33c0 xor eax,eax
* 0045168e eb 73 jmp short .00451703
* 00451690 57 push edi
* 00451691 50 push eax
* 00451692 8bfe mov edi,esi
* 00451694 e8 a7600000 call .00457740
* 00451699 8975 f8 mov dword ptr ss:[ebp-0x8],esi
* 0045169c 2945 f8 sub dword ptr ss:[ebp-0x8],eax
* 0045169f 56 push esi
* 004516a0 e8 9b600000 call .00457740
* 004516a5 0345 f8 add eax,dword ptr ss:[ebp-0x8]
* 004516a8 59 pop ecx
* 004516a9 59 pop ecx
* 004516aa 381e cmp byte ptr ds:[esi],bl
* 004516ac 74 46 je short .004516f4
* 004516ae 2b75 0c sub esi,dword ptr ss:[ebp+0xc]
* 004516b1 3bf8 cmp edi,eax
* 004516b3 77 3f ja short .004516f4
* 004516b5 8a17 mov dl,byte ptr ds:[edi]
* 004516b7 8b4d 0c mov ecx,dword ptr ss:[ebp+0xc]
* 004516ba 8855 ff mov byte ptr ss:[ebp-0x1],dl
* 004516bd 3ad3 cmp dl,bl
* 004516bf 74 11 je short .004516d2
* 004516c1 8a11 mov dl,byte ptr ds:[ecx]
* 004516c3 3ad3 cmp dl,bl
* 004516c5 74 40 je short .00451707
* 004516c7 38140e cmp byte ptr ds:[esi+ecx],dl
* 004516ca 75 06 jnz short .004516d2
* 004516cc 41 inc ecx
* 004516cd 381c0e cmp byte ptr ds:[esi+ecx],bl
* 004516d0 ^75 ef jnz short .004516c1
* 004516d2 3819 cmp byte ptr ds:[ecx],bl
* 004516d4 74 31 je short .00451707
* 004516d6 0fb64d ff movzx ecx,byte ptr ss:[ebp-0x1]
* 004516da 8b55 ec mov edx,dword ptr ss:[ebp-0x14]
* 004516dd 8a4c11 1d mov cl,byte ptr ds:[ecx+edx+0x1d]
*/
#if 0 // hook to the caller of dynamic GetGlyphOutlineA
/**
* @param addr function address
* @param frame real address of the function, supposed to be the same as addr
* @param stack address of current stack - 4
* @return If suceess
*/
static bool InsertMinkDynamicHook(LPVOID fun, DWORD frame, DWORD stack)
{
CC_UNUSED(frame);
if (fun != ::GetGlyphOutlineA)
return false;
DWORD addr = *(DWORD *)(stack + 4);
if (!addr) {
ConsoleOutput("Mink: missing function return addr, this should never happen");
return true;
}
addr = MemDbg::findEnclosingAlignedFunction(addr, 0x200); // range is around 0x120
if (!addr) {
ConsoleOutput("Mink: failed to caller address");
return true;
}
HookParam hp;
hp.address = addr; // hook to the beginning of the caller function
hp.offset =get_stack(1);
hp.type = CODEC_ANSI_BE;
return NewHook(hp, "Mink");
}
#endif // 0
static void SpecialHookMink(hook_stack* stack, HookParam *, uintptr_t *data, uintptr_t *split, size_t*len)
{
//DWORD addr = *(DWORD *)(esp_base + hp->offset); // default value
DWORD addr = stack->eax;
if (!IthGetMemoryRange((LPVOID)(addr), 0, 0))
return;
DWORD ch = *(DWORD *)addr;
DWORD size = LeadByteTable[ch & 0xff]; // Slightly faster than IsDBCSLeadByte
if (size == 1 && ::ispunct(ch & 0xff)) // skip ascii punctuations, since garbage is like ":text:"
return;
*len = size;
*data = ch;
// Issue: still have lots of garbage
*split = stack->stack[25];
//*split = *(DWORD *)(esp_base + 0x48);
}
bool InsertMinkHook()
{
const BYTE bytes[] = {
0x38,0x18, // 00451648 3818 cmp byte ptr ds:[eax],bl
0x75, 0x14, // 0045164a 75 14 jnz short .00451660 ; jichi: hook here
0x38,0x5d, 0xf4, // 0045164c 385d f4 cmp byte ptr ss:[ebp-0xc],bl
0x74, 0x07, // 0045164f 74 07 je short .00451658
0x8b,0x45, 0xf0, // 00451651 8b45 f0 mov eax,dword ptr ss:[ebp-0x10]
0x83,0x60, 0x70, 0xfd, // 00451654 8360 70 fd and dword ptr ds:[eax+0x70],0xfffffffd
0x8b,0x45, 0x08 // 00451658 8b45 08 mov eax,dword ptr ss:[ebp+0x8]
};
enum { addr_offset = 2 };
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
//ULONG addr = 0x45164a;
//ULONG addr = 0x451648;
//ULONG addr = 0x4521a8;
//GROWL_DWORD(addr);
if (!addr) {
ConsoleOutput("Mink: pattern not found");
return false;
}
HookParam hp;
hp.address = addr + addr_offset;
hp.offset=get_reg(regs::eax); // -8
hp.split = 0x64;
hp.type = USING_SPLIT|DATA_INDIRECT|USING_CHAR; // 0x18
hp.text_fun = SpecialHookMink;
ConsoleOutput("INSERT Mink");
return NewHook(hp, "Mink");
//ConsoleOutput("Mink: disable GDI hooks");
//
}
bool Mink2::attach_function() {
const BYTE pattern[] = {
//破談屋
//https://vndb.org/v2719
0xF7,0xC7,0x03,0x00,0x00,0x00,
0x75,XX,
0xC1,0xE9,0x02,
0x83,0xE2,0x03,
0x83,0xF9,0x08,
0x72,XX
};
bool found=false;
for (auto addr : Util::SearchMemory(pattern, sizeof(pattern), PAGE_EXECUTE, processStartAddress, processStopAddress))
{
addr = MemDbg::findEnclosingAlignedFunction(addr,0x100);
if (addr == 0)return false;
HookParam hp;
hp.address = addr;
hp.offset=get_stack(2);
hp.length_offset=3;
hp.type = USING_STRING;
found|=NewHook(hp, "Mink");
}
return found;
}
bool Mink::attach_function() {
return InsertMinkHook();
}