147 lines
6.4 KiB
C++
Raw Normal View History

2024-02-07 20:59:24 +08:00
#include"FocasLens.h"
/** jichi 2/6/2015 FocasLens (Touhou)
* Sample game: [141227] [FocasLens] <EFBFBD>
*
* Debugging method:
* 1. Find first matched text, which has stable address
* 2. Insert WRITE hw break point
* 3. Find where the text is assigned
*
* The game also invokes GDI functions (GetGlyphOutlineA), where the access is cached and looped.
*
* Issues:
* - This hook cannot find name thread
* - Selected character name is hard-coded to the thread
*
* 001faaed cc int3
* 001faaee cc int3
* 001faaef cc int3
* 001faaf0 55 push ebp
* 001faaf1 8bec mov ebp,esp
* 001faaf3 51 push ecx
* 001faaf4 53 push ebx
* 001faaf5 56 push esi
* 001faaf6 57 push edi
* 001faaf7 8bf0 mov esi,eax
* 001faaf9 e8 98281500 call .0034d396
* 001faafe 50 push eax
* 001faaff a1 b08bb100 mov eax,dword ptr ds:[0xb18bb0]
* 001fab04 03c6 add eax,esi
* 001fab06 50 push eax
* 001fab07 e8 9b241500 call .0034cfa7
* 001fab0c 8b0d e88bb100 mov ecx,dword ptr ds:[0xb18be8]
* 001fab12 8b3d b08bb100 mov edi,dword ptr ds:[0xb18bb0]
* 001fab18 83c1 f7 add ecx,-0x9
* 001fab1b 83c4 08 add esp,0x8
* 001fab1e 8bd8 mov ebx,eax
* 001fab20 390d ec8bb100 cmp dword ptr ds:[0xb18bec],ecx
* 001fab26 7c 65 jl short .001fab8d
* 001fab28 803c37 20 cmp byte ptr ds:[edi+esi],0x20
* 001fab2c 74 41 je short .001fab6f
* 001fab2e 803c37 81 cmp byte ptr ds:[edi+esi],0x81
* 001fab32 75 4d jnz short .001fab81
* 001fab34 807c37 01 42 cmp byte ptr ds:[edi+esi+0x1],0x42
* 001fab39 74 34 je short .001fab6f
* 001fab3b 803c37 81 cmp byte ptr ds:[edi+esi],0x81
* 001fab3f 75 40 jnz short .001fab81
* 001fab41 807c37 01 41 cmp byte ptr ds:[edi+esi+0x1],0x41
* 001fab46 74 27 je short .001fab6f
* 001fab48 803c37 81 cmp byte ptr ds:[edi+esi],0x81
* 001fab4c 75 33 jnz short .001fab81
* 001fab4e 807c37 01 48 cmp byte ptr ds:[edi+esi+0x1],0x48
* 001fab53 74 1a je short .001fab6f
* 001fab55 803c37 81 cmp byte ptr ds:[edi+esi],0x81
* 001fab59 75 26 jnz short .001fab81
* 001fab5b 807c37 01 49 cmp byte ptr ds:[edi+esi+0x1],0x49
* 001fab60 74 0d je short .001fab6f
* 001fab62 803c37 81 cmp byte ptr ds:[edi+esi],0x81
* 001fab66 75 19 jnz short .001fab81
* 001fab68 807c37 01 40 cmp byte ptr ds:[edi+esi+0x1],0x40
* 001fab6d 75 12 jnz short .001fab81
* 001fab6f 803d c58bb100 00 cmp byte ptr ds:[0xb18bc5],0x0
* 001fab76 75 09 jnz short .001fab81
* 001fab78 c605 c58bb100 01 mov byte ptr ds:[0xb18bc5],0x1
* 001fab7f eb 0c jmp short .001fab8d
* 001fab81 e8 7a000000 call .001fac00
* 001fab86 c605 c58bb100 00 mov byte ptr ds:[0xb18bc5],0x0
* 001fab8d 8b0d e48bb100 mov ecx,dword ptr ds:[0xb18be4]
* 001fab93 33c0 xor eax,eax
* 001fab95 85db test ebx,ebx
* 001fab97 7e 2b jle short .001fabc4
* 001fab99 8d1437 lea edx,dword ptr ds:[edi+esi]
* 001fab9c 8b35 ec8bb100 mov esi,dword ptr ds:[0xb18bec]
* 001faba2 8955 fc mov dword ptr ss:[ebp-0x4],edx
* 001faba5 8bd1 mov edx,ecx
* 001faba7 0faf15 e88bb100 imul edx,dword ptr ds:[0xb18be8]
* 001fabae 0315 bc8bb100 add edx,dword ptr ds:[0xb18bbc] ; .00b180f8
* 001fabb4 03f2 add esi,edx
* 001fabb6 8b55 fc mov edx,dword ptr ss:[ebp-0x4]
* 001fabb9 8a1402 mov dl,byte ptr ds:[edx+eax]
* 001fabbc 881406 mov byte ptr ds:[esi+eax],dl ; jichi: text is in dl in byte
* 001fabbf 40 inc eax
* 001fabc0 3bc3 cmp eax,ebx
* 001fabc2 ^7c f2 jl short .001fabb6
* 001fabc4 0faf0d e88bb100 imul ecx,dword ptr ds:[0xb18be8]
* 001fabcb 030d bc8bb100 add ecx,dword ptr ds:[0xb18bbc] ; .00b180f8
* 001fabd1 a1 ec8bb100 mov eax,dword ptr ds:[0xb18bec]
* 001fabd6 03fb add edi,ebx
* 001fabd8 893d b08bb100 mov dword ptr ds:[0xb18bb0],edi
* 001fabde 5f pop edi
* 001fabdf 03c8 add ecx,eax
* 001fabe1 03c3 add eax,ebx
* 001fabe3 5e pop esi
* 001fabe4 c60419 00 mov byte ptr ds:[ecx+ebx],0x0
* 001fabe8 a3 ec8bb100 mov dword ptr ds:[0xb18bec],eax
* 001fabed 5b pop ebx
* 001fabee 8be5 mov esp,ebp
* 001fabf0 5d pop ebp
* 001fabf1 c3 retn
* 001fabf2 cc int3
* 001fabf3 cc int3
* 001fabf4 cc int3
* 001fabf5 cc int3
* 001fabf6 cc int3
* 001fabf7 cc int3
*/
static void SpecialHookFocasLens(hook_stack* stack, HookParam *, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD addr = (DWORD)stack->base + get_reg(regs::edx);
if (*(char *)addr) {
*data = addr;
*len = 1;
*split = FIXED_SPLIT_VALUE;
}
}
bool InsertFocasLensHook()
{
const BYTE bytes[] = {
0x8a,0x14,0x02, // 001fabb9 8a1402 mov dl,byte ptr ds:[edx+eax]
0x88,0x14,0x06, // 001fabbc 881406 mov byte ptr ds:[esi+eax],dl ; jichi: text is in dl in byte
0x40, // 001fabbf 40 inc eax
0x3b,0xc3 // 001fabc0 3bc3 cmp eax,ebx
};
enum { addr_offset = 0x001fabbc - 0x001fabb9 };
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
//GROWL(addr);
if (!addr) {
ConsoleOutput("FocasLens: pattern not found");
return false;
}
HookParam hp;
hp.address = addr + addr_offset;
hp.text_fun = SpecialHookFocasLens; // use special hook to force byte access
hp.type = USING_STRING|USING_SPLIT|FIXING_SPLIT|NO_CONTEXT; // no context to get rid of relative function address
ConsoleOutput("INSERT FocasLens");
// GDI functions are kept in case the font is not cached
//
return NewHook(hp, "FocasLens");
}
bool FocasLens::attach_function() {
return InsertFocasLensHook();
}