恍兮惚兮 6a43cd5b86 pch
2024-05-06 23:31:54 +08:00

3646 lines
175 KiB
C++
Raw Blame History

#include"PPSSPP.h"
#include"ppsspp/psputils.hpp"
#if 0
namespace { // unnamed
inline bool _bandaigarbage_ch(char c)
{
return c == ' ' || c == '/' || c == '#' || c == '.' || c == ':'
|| c >= '0' && c <= '9'
|| c >= 'A' && c <= 'z'; // also ignore ASCII 91-96: [ \ ] ^ _ `
}
// Remove trailing /L/P or #n garbage
size_t _bandaistrlen(LPCSTR text)
{
size_t len = ::strlen(text);
size_t ret = len;
while (len && _bandaigarbage_ch(text[len - 1])) {
len--;
if (text[len] == '/' || text[len] == '#') // in case trim UTF-8 trailing bytes
ret = len;
}
return ret;
}
// Trim leading garbage
LPCSTR _bandailtrim(LPCSTR p)
{
enum { MAX_LENGTH = VNR_TEXT_CAPACITY };
if (p)
for (int count = 0; *p && count < MAX_LENGTH; count++, p++)
if (!_bandaigarbage_ch(*p))
return p;
return nullptr;
}
} // unnamed namespae
static void SpecialPSPHookBandai(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD eax = stack->eax;
LPCSTR text = LPCSTR(eax + hp->user_value);
if (*text) {
//lasttext = text;
text = _bandailtrim(text);
*data = (DWORD)text;
*len = _bandaistrlen(text);
// Issue: The split value will create lots of threads for Shining Hearts
//*split = regof(ecx, esp_base); // works for Shool Rumble, but mix character name for Shining Hearts
*split = stack->edi; // works for Shining Hearts to split character name
}
}
// 7/22/2014 jichi: This engine works for multiple game?
// It is also observed in Broccoli game ぁ<><EFBFBD>リンスさまっ.
bool InsertBandaiPSPHook()
{
ConsoleOutput("BANDAI PSP: enter");
const BYTE bytes[] = {
0x77, 0x0f, // 13400560 77 0f ja short 13400571
0xc7,0x05, XX8, // 13400562 c705 a8aa1001 cc>mov dword ptr ds:[0x110aaa8],0x883decc
0xe9, XX4, // 1340056c -e9 93fa54f0 jmp 03950004
0x8b,0x35, XX4, // 13400571 8b35 78a71001 mov esi,dword ptr ds:[0x110a778]
0x81,0xc6, 0x01,0x00,0x00,0x00, // 13400577 81c6 01000000 add esi,0x1
0x8b,0x05, XX4, // 1340057d 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13400583 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb6,0xb8, XX4, // 13400589 0fb6b8 00004007 movzx edi,byte ptr ds:[eax+0x7400000] ; jichi: hook here
0x8b,0x2d, XX4, // 13400590 8b2d 78a71001 mov ebp,dword ptr ds:[0x110a778]
0x8d,0x6d, 0x01, // 13400596 8d6d 01 lea ebp,dword ptr ss:[ebp+0x1]
0x81,0xff, 0x00,0x00,0x00,0x00 // 13400599 81ff 00000000 cmp edi,0x0
};
enum { memory_offset = 3 }; // 13400589 0fb6b8 00004007 movzx edi,byte ptr ds:[eax+0x7400000]
enum { addr_offset = 0x13400589 - 0x13400560 };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("BANDAI PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|USING_SPLIT|NO_CONTEXT;
//hp.offset=get_reg(regs::eax);
hp.text_fun = SpecialPSPHookBandai;
ConsoleOutput("BANDAI PSP: INSERT");
succ|=NewHook(hp, "BANDAI PSP");
}
ConsoleOutput("BANDAI PSP: leave");
return succ;
}
/** 7/29/2014 jichi Otomate PPSSPP 0.9.9
* Sample game: Amnesia Crowd
* Sample game: Amnesia Later
*
* 006db4af cc int3
* 006db4b0 8b15 b8ebaf00 mov edx,dword ptr ds:[0xafebb8] ; ppssppwi.01134988
* 006db4b6 56 push esi
* 006db4b7 8b42 10 mov eax,dword ptr ds:[edx+0x10]
* 006db4ba 25 ffffff3f and eax,0x3fffffff
* 006db4bf 0305 94411301 add eax,dword ptr ds:[0x1134194]
* 006db4c5 8d70 01 lea esi,dword ptr ds:[eax+0x1]
* 006db4c8 8a08 mov cl,byte ptr ds:[eax] ; jichi: hook here, get text in [eax]
* 006db4ca 40 inc eax
* 006db4cb 84c9 test cl,cl
* 006db4cd ^75 f9 jnz short ppssppwi.006db4c8
* 006db4cf 2bc6 sub eax,esi
* 006db4d1 8942 08 mov dword ptr ds:[edx+0x8],eax
* 006db4d4 5e pop esi
* 006db4d5 8d0485 07000000 lea eax,dword ptr ds:[eax*4+0x7]
* 006db4dc c3 retn
* 006db4dd cc int3
*/
static void SpecialPPSSPPHookOtomate(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
// 006db4b7 8b42 10 mov eax,dword ptr ds:[edx+0x10] ; jichi: hook here
// 006db4ba 25 ffffff3f and eax,0x3fffffff
// 006db4bf 0305 94411301 add eax,dword ptr ds:[0x1134194]; jichi: ds offset
// 006db4c5 8d70 01 lea esi,dword ptr ds:[eax+0x1]
DWORD edx = stack->edx;
DWORD eax = *(DWORD *)(edx + 0x10);
eax &= 0x3fffffff;
eax += *(DWORD *)hp->user_value;
//DWORD eax = regof(eax, esp_base);
LPCSTR text = LPCSTR(eax);
if (*text) {
text = _bandailtrim(text); // the same as bandai PSP
*data = (DWORD)text;
*len = _bandaistrlen(text);
*split = stack->ecx; // the same as Otomate PSP hook
//DWORD ecx = regof(ecx, esp_base); // the same as Otomate PSP hook
//*split = ecx ? ecx : (FIXED_SPLIT_VALUE << 2);
//*split = ecx & 0xffffff00; // skip cl which is used
}
}
bool InsertOtomatePPSSPPHook()
{
ConsoleOutput("Otomate PPSSPP: enter");
const BYTE bytes[] = {
0x8b,0x15, XX4, // 006db4b0 8b15 b8ebaf00 mov edx,dword ptr ds:[0xafebb8] ; ppssppwi.01134988
0x56, // 006db4b6 56 push esi
0x8b,0x42, 0x10, // 006db4b7 8b42 10 mov eax,dword ptr ds:[edx+0x10] ; jichi: hook here
0x25, 0xff,0xff,0xff,0x3f, // 006db4ba 25 ffffff3f and eax,0x3fffffff
0x03,0x05, XX4, // 006db4bf 0305 94411301 add eax,dword ptr ds:[0x1134194]; jichi: ds offset
0x8d,0x70, 0x01, // 006db4c5 8d70 01 lea esi,dword ptr ds:[eax+0x1]
0x8a,0x08, // 006db4c8 8a08 mov cl,byte ptr ds:[eax] ; jichi: hook here
0x40, // 006db4ca 40 inc eax
0x84,0xc9, // 006db4cb 84c9 test cl,cl
0x75, 0xf9, // 006db4cd ^75 f9 jnz short ppssppwi.006db4c8
0x2b,0xc6, // 006db4cf 2bc6 sub eax,esi
0x89,0x42, 0x08, // 006db4d1 8942 08 mov dword ptr ds:[edx+0x8],eax
0x5e, // 006db4d4 5e pop esi
0x8d,0x04,0x85, 0x07,0x00,0x00,0x00 // 006db4d5 8d0485 07000000 lea eax,dword ptr ds:[eax*4+0x7]
};
//enum { addr_offset = 0x006db4c8 - 0x006db4b0 };
enum { addr_offset = 0x006db4b7 - 0x006db4b0 };
enum { ds_offset = 0x006db4bf - 0x006db4b0 + 2 };
auto succ=false;
DWORD addr = SafeFindBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
//GROWL_DWORD(addr);
if (!addr)
ConsoleOutput("Otomate PPSSPP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(addr + ds_offset); // this is the address after ds:[]
hp.type = USING_STRING|NO_CONTEXT;
hp.text_fun = SpecialPPSSPPHookOtomate;
ConsoleOutput("Otomate PPSSPP: INSERT");
succ|=NewHook(hp, "Otomate PPSSPP");
}
ConsoleOutput("Otomate PPSSPP: leave");
return succ;
}
/** jichi 7/12/2014 PPSSPP
* Tested with PPSSPP 0.9.8.
*/
void SpecialPSPHook(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD offset = *(DWORD *)(stack->base + hp->offset);
LPCSTR text = LPCSTR(offset + hp->user_value);
static LPCSTR lasttext;
if (*text) {
*data = (DWORD)text;
// I only considered SHIFT-JIS/UTF-8 case
if (hp->length_offset == 1)
*len = 1; // only read 1 byte
else if (hp->length_offset)
*len = *(DWORD *)(stack->base + hp->length_offset);
else
*len = ::strlen(text); // should only be applied to hp->type|USING_STRING
if (hp->type & USING_SPLIT) {
if (hp->type & FIXING_SPLIT)
*split = FIXED_SPLIT_VALUE;
else
*split = *(DWORD *)(stack->base + hp->split);
}
}
}
/** 8/9/2014 jichi imageepoch.co.jp PSP engine, 0.9.8, 0.9.9
* Sample game: Sol Trigger (0.9.8, 0.9.9)
*
* Though Imageepoch1 also exists, it cannot find scenario text.
*
* FIXED memory addresses (different from Imageepoch1): two matches, UTF-8
*
* Debug method: find current text and add breakpoint.
*
* There a couple of good functions. The first one is used.
* There is only one text threads. But it cannot extract character names.
*
* 135fd497 cc int3
* 135fd498 77 0f ja short 135fd4a9
* 135fd49a c705 a8aa1001 20>mov dword ptr ds:[0x110aaa8],0x8952d20
* 135fd4a4 -e9 5b2b2ef0 jmp 038e0004
* 135fd4a9 8b35 dca71001 mov esi,dword ptr ds:[0x110a7dc]
* 135fd4af 81c6 04000000 add esi,0x4
* 135fd4b5 8b05 a8a71001 mov eax,dword ptr ds:[0x110a7a8]
* 135fd4bb 81e0 ffffff3f and eax,0x3fffffff
* 135fd4c1 0fb6b8 00004007 movzx edi,byte ptr ds:[eax+0x7400000] ; jichi: hook here
* 135fd4c8 813d 68a71001 00>cmp dword ptr ds:[0x110a768],0x0
* 135fd4d2 893d 78a71001 mov dword ptr ds:[0x110a778],edi
* 135fd4d8 c705 aca71001 23>mov dword ptr ds:[0x110a7ac],0x23434623
* 135fd4e2 c705 b0a71001 30>mov dword ptr ds:[0x110a7b0],0x30303030
* 135fd4ec 8935 b4a71001 mov dword ptr ds:[0x110a7b4],esi
* 135fd4f2 c705 b8a71001 00>mov dword ptr ds:[0x110a7b8],0x0
* 135fd4fc 0f85 16000000 jnz 135fd518
* 135fd502 832d c4aa1001 08 sub dword ptr ds:[0x110aac4],0x8
* 135fd509 e9 22000000 jmp 135fd530
* 135fd50e 01642d 95 add dword ptr ss:[ebp+ebp-0x6b],esp
* 135fd512 08e9 or cl,ch
* 135fd514 0b2b or ebp,dword ptr ds:[ebx]
* 135fd516 2e:f0:832d c4aa1>lock sub dword ptr cs:[0x110aac4],0x8 ; lock prefix
* 135fd51f c705 a8aa1001 40>mov dword ptr ds:[0x110aaa8],0x8952d40
* 135fd529 -e9 f52a2ef0 jmp 038e0023
* 135fd52e 90 nop
* 135fd52f cc int3
*/
bool InsertImageepoch2PSPHook()
{
ConsoleOutput("Imageepoch2 PSP: enter");
const BYTE bytes[] = {
// 135fd497 cc int3
0x77, 0x0f, // 135fd498 77 0f ja short 135fd4a9
0xc7,0x05, XX8, // 135fd49a c705 a8aa1001 20>mov dword ptr ds:[0x110aaa8],0x8952d20
0xe9, XX4, // 135fd4a4 -e9 5b2b2ef0 jmp 038e0004
0x8b,0x35, XX4, // 135fd4a9 8b35 dca71001 mov esi,dword ptr ds:[0x110a7dc]
0x81,0xc6, 0x04,0x00,0x00,0x00, // 135fd4af 81c6 04000000 add esi,0x4
0x8b,0x05, XX4, // 135fd4b5 8b05 a8a71001 mov eax,dword ptr ds:[0x110a7a8]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 135fd4bb 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb6,0xb8, XX4, // 135fd4c1 0fb6b8 00004007 movzx edi,byte ptr ds:[eax+0x7400000] ; jichi: hook here
0x81,0x3d, XX4, 0x00,0x00,0x00,0x00, // 135fd4c8 813d 68a71001 00>cmp dword ptr ds:[0x110a768],0x0
0x89,0x3d, XX4, // 135fd4d2 893d 78a71001 mov dword ptr ds:[0x110a778],edi
0xc7,0x05, XX8, // 135fd4d8 c705 aca71001 23>mov dword ptr ds:[0x110a7ac],0x23434623
0xc7,0x05, XX8, // 135fd4e2 c705 b0a71001 30>mov dword ptr ds:[0x110a7b0],0x30303030
0x89,0x35, XX4, // 135fd4ec 8935 b4a71001 mov dword ptr ds:[0x110a7b4],esi
0xc7,0x05, XX4, 0x00,0x00,0x00,0x00, // 135fd4f2 c705 b8a71001 00>mov dword ptr ds:[0x110a7b8],0x0
0x0f,0x85 //, XX4, // 135fd4fc 0f85 16000000 jnz 135fd518
};
enum { memory_offset = 3 }; // 1346d381 0fb6a8 00004007 movzx ebp,byte ptr ds:[eax+0x7400000]
enum { addr_offset = 0x135fd4c1 - 0x135fd498 };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("Imageepoch2 PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|USING_SPLIT|NO_CONTEXT; // UTF-8, though
hp.offset=get_reg(regs::eax);
hp.split = get_reg(regs::ecx);
hp.text_fun = SpecialPSPHook;
ConsoleOutput("Imageepoch2 PSP: INSERT");
succ|=NewHook(hp, "Imageepoch2 PSP");
}
ConsoleOutput("Imageepoch2 PSP: leave");
return succ;
}
/** 7/22/2014 jichi BANDAI PSP engine, 0.9.8 only
* Replaced by Otomate PPSSPP on 0.9.9.
* Sample game: School Rumble PSP 姉さん事件で<E4BBB6>(SHIFT-JIS)
* See: http://sakuradite.com/topic/333
*
* Sample game: 寮<>のサクリファイス work on 0.9.8, not 0.9.9
*
*
* Sample game: Shining Hearts (UTF-8)
* See: http://sakuradite.com/topic/346
*
* The encoding could be either UTF-8 or SHIFT-JIS
*
* Debug method: breakpoint the memory address
* There are two matched memory address to the current text
*
* Only one function is accessing the text address.
*
* Character name:
*
* 1346c122 cc int3
* 1346c123 cc int3
* 1346c124 77 0f ja short 1346c135
* 1346c126 c705 a8aa1001 a4>mov dword ptr ds:[0x110aaa8],0x882f2a4
* 1346c130 -e9 cf3e2cf0 jmp 03730004
* 1346c135 8b05 a8a71001 mov eax,dword ptr ds:[0x110a7a8]
* 1346c13b 81e0 ffffff3f and eax,0x3fffffff
* 1346c141 8bb0 14004007 mov esi,dword ptr ds:[eax+0x7400014]
* 1346c147 8b3d 70a71001 mov edi,dword ptr ds:[0x110a770]
* 1346c14d c1e7 02 shl edi,0x2
* 1346c150 8b05 a8a71001 mov eax,dword ptr ds:[0x110a7a8]
* 1346c156 81e0 ffffff3f and eax,0x3fffffff
* 1346c15c 8ba8 18004007 mov ebp,dword ptr ds:[eax+0x7400018]
* 1346c162 03fe add edi,esi
* 1346c164 8bc7 mov eax,edi
* 1346c166 81e0 ffffff3f and eax,0x3fffffff
* 1346c16c 0fb790 02004007 movzx edx,word ptr ds:[eax+0x7400002]
* 1346c173 8bc2 mov eax,edx
* 1346c175 8bd5 mov edx,ebp
* 1346c177 03d0 add edx,eax
* 1346c179 8bc2 mov eax,edx
* 1346c17b 81e0 ffffff3f and eax,0x3fffffff
* 1346c181 0fb6b8 00004007 movzx edi,byte ptr ds:[eax+0x7400000] ; jichi: hook here
* 1346c188 8bcf mov ecx,edi
* 1346c18a 81e7 ff000000 and edi,0xff
* 1346c190 8935 74a71001 mov dword ptr ds:[0x110a774],esi
* 1346c196 8b35 b8a71001 mov esi,dword ptr ds:[0x110a7b8]
* 1346c19c 81c6 bc82ffff add esi,0xffff82bc
* 1346c1a2 81ff 00000000 cmp edi,0x0
* 1346c1a8 893d 70a71001 mov dword ptr ds:[0x110a770],edi
* 1346c1ae 8915 78a71001 mov dword ptr ds:[0x110a778],edx
* 1346c1b4 892d 7ca71001 mov dword ptr ds:[0x110a77c],ebp
* 1346c1ba 890d 80a71001 mov dword ptr ds:[0x110a780],ecx
* 1346c1c0 8935 84a71001 mov dword ptr ds:[0x110a784],esi
* 1346c1c6 0f85 16000000 jnz 1346c1e2
* 1346c1cc 832d c4aa1001 0b sub dword ptr ds:[0x110aac4],0xb
* 1346c1d3 e9 3c050000 jmp 1346c714
* 1346c1d8 014cf3 82 add dword ptr ds:[ebx+esi*8-0x7e],ecx
* 1346c1dc 08e9 or cl,ch
* 1346c1de 41 inc ecx
* 1346c1df 3e:2c f0 sub al,0xf0 ; superfluous prefix
* 1346c1e2 832d c4aa1001 0b sub dword ptr ds:[0x110aac4],0xb
* 1346c1e9 e9 0e000000 jmp 1346c1fc
* 1346c1ee 01d0 add eax,edx
* 1346c1f0 f2: prefix repne: ; superfluous prefix
* 1346c1f1 8208 e9 or byte ptr ds:[eax],0xffffffe9
* 1346c1f4 2b3e sub edi,dword ptr ds:[esi]
* 1346c1f6 2c f0 sub al,0xf0
* 1346c1f8 90 nop
* 1346c1f9 cc int3
* 1346c1fa cc int3
* 1346c1fb cc int3
*
* Scenario:
*
* 1340055d cc int3
* 1340055e cc int3
* 1340055f cc int3
* 13400560 77 0f ja short 13400571
* 13400562 c705 a8aa1001 cc>mov dword ptr ds:[0x110aaa8],0x883decc
* 1340056c -e9 93fa54f0 jmp 03950004
* 13400571 8b35 78a71001 mov esi,dword ptr ds:[0x110a778]
* 13400577 81c6 01000000 add esi,0x1
* 1340057d 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
* 13400583 81e0 ffffff3f and eax,0x3fffffff
* 13400589 0fb6b8 00004007 movzx edi,byte ptr ds:[eax+0x7400000] ; jichi: hook here
* 13400590 8b2d 78a71001 mov ebp,dword ptr ds:[0x110a778]
* 13400596 8d6d 01 lea ebp,dword ptr ss:[ebp+0x1]
* 13400599 81ff 00000000 cmp edi,0x0
* 1340059f 8935 70a71001 mov dword ptr ds:[0x110a770],esi
* 134005a5 893d 74a71001 mov dword ptr ds:[0x110a774],edi
* 134005ab 892d 78a71001 mov dword ptr ds:[0x110a778],ebp
* 134005b1 0f84 16000000 je 134005cd
* 134005b7 832d c4aa1001 04 sub dword ptr ds:[0x110aac4],0x4
* 134005be e9 21000000 jmp 134005e4
* 134005c3 01d0 add eax,edx
* 134005c5 de83 08e956fa fiadd word ptr ds:[ebx+0xfa56e908]
* 134005cb 54 push esp
* 134005cc f0:832d c4aa1001>lock sub dword ptr ds:[0x110aac4],0x4 ; lock prefix
* 134005d4 e9 7f000000 jmp 13400658
* 134005d9 01dc add esp,ebx
* 134005db de83 08e940fa fiadd word ptr ds:[ebx+0xfa40e908]
* 134005e1 54 push esp
* 134005e2 f0:90 lock nop ; lock prefix is not allowed
* 134005e4 77 0f ja short 134005f5
* 134005e6 c705 a8aa1001 d0>mov dword ptr ds:[0x110aaa8],0x883ded0
* 134005f0 -e9 0ffa54f0 jmp 03950004
* 134005f5 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
* 134005fb 81e0 ffffff3f and eax,0x3fffffff
* 13400601 0fb6b0 00004007 movzx esi,byte ptr ds:[eax+0x7400000]
* 13400608 8b3d 78a71001 mov edi,dword ptr ds:[0x110a778]
* 1340060e 8d7f 01 lea edi,dword ptr ds:[edi+0x1]
* 13400611 81fe 00000000 cmp esi,0x0
* 13400617 8935 74a71001 mov dword ptr ds:[0x110a774],esi
* 1340061d 893d 78a71001 mov dword ptr ds:[0x110a778],edi
* 13400623 0f84 16000000 je 1340063f
* 13400629 832d c4aa1001 03 sub dword ptr ds:[0x110aac4],0x3
* 13400630 ^e9 afffffff jmp 134005e4
* 13400635 01d0 add eax,edx
* 13400637 de83 08e9e4f9 fiadd word ptr ds:[ebx+0xf9e4e908]
* 1340063d 54 push esp
* 1340063e f0:832d c4aa1001>lock sub dword ptr ds:[0x110aac4],0x3 ; lock prefix
* 13400646 e9 0d000000 jmp 13400658
* 1340064b 01dc add esp,ebx
* 1340064d de83 08e9cef9 fiadd word ptr ds:[ebx+0xf9cee908]
* 13400653 54 push esp
* 13400654 f0:90 lock nop ; lock prefix is not allowed
* 13400656 cc int3
* 13400657 cc int3
*/
bool InsertBandaiNamePSPHook()
{
ConsoleOutput("BANDAI Name PSP: enter");
const BYTE bytes[] = {
//0xcc, // 1346c122 cc int3
//0xcc, // 1346c123 cc int3
0x77, 0x0f, // 1346c124 77 0f ja short 1346c135
0xc7,0x05, XX8, // 1346c126 c705 a8aa1001 a4>mov dword ptr ds:[0x110aaa8],0x882f2a4
0xe9, XX4, // 1346c130 -e9 cf3e2cf0 jmp 03730004
0x8b,0x05, XX4, // 1346c135 8b05 a8a71001 mov eax,dword ptr ds:[0x110a7a8]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1346c13b 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xb0, XX4, // 1346c141 8bb0 14004007 mov esi,dword ptr ds:[eax+0x7400014]
0x8b,0x3d, XX4, // 1346c147 8b3d 70a71001 mov edi,dword ptr ds:[0x110a770]
0xc1,0xe7, 0x02, // 1346c14d c1e7 02 shl edi,0x2
0x8b,0x05, XX4, // 1346c150 8b05 a8a71001 mov eax,dword ptr ds:[0x110a7a8]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1346c156 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xa8, XX4, // 1346c15c 8ba8 18004007 mov ebp,dword ptr ds:[eax+0x7400018]
0x03,0xfe, // 1346c162 03fe add edi,esi
0x8b,0xc7, // 1346c164 8bc7 mov eax,edi
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1346c166 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb7,0x90, XX4, // 1346c16c 0fb790 02004007 movzx edx,word ptr ds:[eax+0x7400002]
0x8b,0xc2, // 1346c173 8bc2 mov eax,edx
0x8b,0xd5, // 1346c175 8bd5 mov edx,ebp
0x03,0xd0, // 1346c177 03d0 add edx,eax
0x8b,0xc2, // 1346c179 8bc2 mov eax,edx
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1346c17b 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb6,0xb8 //, XX4 // 1346c181 0fb6b8 00004007 movzx edi,byte ptr ds:[eax+0x7400000] ; jichi: hook here
};
enum { memory_offset = 3 }; // 1346c181 0fb6b8 00004007 movzx edi,byte ptr ds:[eax+0x7400000]
enum { addr_offset = sizeof(bytes) - memory_offset };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("BANDAI Name PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|USING_SPLIT|NO_CONTEXT;
hp.offset=get_reg(regs::eax);
hp.split = get_reg(regs::ebx);
hp.text_fun = SpecialPSPHook;
ConsoleOutput("BANDAI Name PSP: INSERT");
succ|=NewHook(hp, "BANDAI Name PSP");
}
ConsoleOutput("BANDAI Name PSP: leave");
return succ;
}
/** 7/26/2014 jichi Otomate PSP engine, 0.9.8 only, 0.9.9 not work
* Replaced by Otomate PPSSPP on 0.9.9.
*
* Sample game: クロノスタシア
* Sample game: フォトカ<E38388>(repetition)
*
* Not work on 0.9.9: Amnesia Crowd
*
* The instruction pattern also exist in 0.9.9. But the function is not called.
*
* Memory address is FIXED.
* Debug method: breakpoint the memory address
*
* The memory access of the function below is weird that the accessed value is 2 bytes after the real text.
*
* PPSSPP 0.9.8, クロノスタシア
* 13c00fe1 cc int3
* 13c00fe2 cc int3
* 13c00fe3 cc int3
* 13c00fe4 77 0f ja short 13c00ff5
* 13c00fe6 c705 a8aa1001 30>mov dword ptr ds:[0x110aaa8],0x884b330
* 13c00ff0 -e9 0ff0edf2 jmp 06ae0004
* 13c00ff5 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
* 13c00ffb 81e0 ffffff3f and eax,0x3fffffff
* 13c01001 0fbeb0 0000c007 movsx esi,byte ptr ds:[eax+0x7c00000] ; jichi: hook here
* 13c01008 81fe 00000000 cmp esi,0x0 ; jichi: hook here, get the esi value
* 13c0100e 8935 80a71001 mov dword ptr ds:[0x110a780],esi
* 13c01014 0f84 25000000 je 13c0103f
* 13c0101a 8b35 78a71001 mov esi,dword ptr ds:[0x110a778]
* 13c01020 8d76 01 lea esi,dword ptr ds:[esi+0x1]
* 13c01023 8935 78a71001 mov dword ptr ds:[0x110a778],esi
* 13c01029 832d c4aa1001 03 sub dword ptr ds:[0x110aac4],0x3
* 13c01030 ^e9 afffffff jmp 13c00fe4
* 13c01035 0130 add dword ptr ds:[eax],esi
* 13c01037 b3 84 mov bl,0x84
* 13c01039 08e9 or cl,ch
* 13c0103b e4 ef in al,0xef ; i/o command
* 13c0103d ed in eax,dx ; i/o command
* 13c0103e f2: prefix repne: ; superfluous prefix
* 13c0103f 832d c4aa1001 03 sub dword ptr ds:[0x110aac4],0x3
* 13c01046 e9 0d000000 jmp 13c01058
* 13c0104b 013cb3 add dword ptr ds:[ebx+esi*4],edi
* 13c0104e 8408 test byte ptr ds:[eax],cl
* 13c01050 -e9 ceefedf2 jmp 06ae0023
* 13c01055 90 nop
* 13c01056 cc int3
* 13c01057 cc int3
*/
// TODO: is reverse_strlen a better choice?
// Read text from esi
static void SpecialPSPHookOtomate(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
//static uniquemap uniq;
DWORD eax = stack->eax;
LPCSTR text = LPCSTR(eax + hp->user_value - 2); // -2 to read 1 word more from previous location
if (*text) {
*split = stack->ecx; // this would cause lots of texts, but it works for all games
//*split = regof(ecx, esp_base) & 0xff00; // only use higher bits
*data = (DWORD)text;
size_t sz = ::strlen(text);
*len = sz == 3 ? 3 : 1; // handling the last two bytes
}
}
bool InsertOtomatePSPHook()
{
ConsoleOutput("Otomate PSP: enter");
const BYTE bytes[] = {
0x77, 0x0f, // 13c00fe4 77 0f ja short 13c00ff5
0xc7,0x05, XX8, // 13c00fe6 c705 a8aa1001 30>mov dword ptr ds:[0x110aaa8],0x884b330
0xe9, XX4, // 13c00ff0 -e9 0ff0edf2 jmp 06ae0004
0x8b,0x05, XX4, // 13c00ff5 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13c00ffb 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xbe,0xb0, XX4, // 13c01001 0fbeb0 0000c007 movsx esi,byte ptr ds:[eax+0x7c00000] ; jichi: hook here
0x81,0xfe, 0x00,0x00,0x00,0x00, // 13c01008 81fe 00000000 cmp esi,0x0
0x89,0x35, XX4, // 13c0100e 8935 80a71001 mov dword ptr ds:[0x110a780],esi
0x0f,0x84, 0x25,0x00,0x00,0x00, // 13c01014 0f84 25000000 je 13c0103f
0x8b,0x35, XX4, // 13c0101a 8b35 78a71001 mov esi,dword ptr ds:[0x110a778]
0x8d,0x76, 0x01, // 13c01020 8d76 01 lea esi,dword ptr ds:[esi+0x1]
0x89,0x35, XX4, // 13c01023 8935 78a71001 mov dword ptr ds:[0x110a778],esi
0x83,0x2d, XX4, 0x03 // 13c01029 832d c4aa1001 03 sub dword ptr ds:[0x110aac4],0x3
};
enum { memory_offset = 3 };
//enum { addr_offset = 0x13c01008 - 0x13c00fe4 };
enum { addr_offset = 0x13c01001- 0x13c00fe4 };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
//GROWL_DWORD(addr);
if (!addr)
ConsoleOutput("Otomate PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|NO_CONTEXT;
hp.text_fun = SpecialPSPHookOtomate;
ConsoleOutput("Otomate PSP: INSERT");
succ|=NewHook(hp, "Otomate PSP");
}
ConsoleOutput("Otomate PSP: leave");
return succ;
}
/** 7/27/2014 jichi Intense.jp PSP engine, 0.9.8, 0.9.9,
* Though Otomate can work, it cannot work line by line.
*
* Sample game: 寮<>のサクリファイス work on 0.9.8 & 0.9.9
* This hook is only for intro graphic painting
*
* Memory address is FIXED.
* Debug method: predict and breakpoint the memory address
*
* There are two matches in the memory, and only one function accessing them.
* The memory is accessed by words.
*
* The memory and hooked function is as follows.
*
* 09dfee77 88 c3 82 a2 95 a3 82 cc 89 9c 92 ea 82 c5 81 41 暗い淵の奥底で<E5BA95> * 09dfee87 92 e1 82 ad 81 41 8f ac 82 b3 82 ad 81 41 8b bf 低く、小さく〟<E3818F>
* 09dfee97 82 ad 81 42 2a 70 0a 82 b1 82 ea 82 cd 81 41 8c く<>p.これは、<E381AF>
* 09dfeea7 db 93 ae 81 63 81 48 2a 70 0a 82 c6 82 e0 82 b7 <20>動…p.ともす
* 09dfeeb7 82 ea 82 ce 95 b7 82 ab 93 a6 82 b5 82 c4 82 b5 れ<>聞き送<E3818D><EFBFBD> * 09dfeec7 82 dc 82 a2 82 bb 82 a4 82 c8 81 41 2a 70 0a 8f まぁ<E381BE><EFBFBD><E38181>p.・
* 09dfeed7 ac 82 b3 82 ad 81 41 8e e3 81 58 82 b5 82 ad 81 <20>さく、弱、<E5BCB1><EFBFBD>
* 09dfeee7 41 95 73 8a 6d 82 a9 82 c8 89 b9 81 42 00 00 00 a不確かな音<E381AA>..
* 09dfeef7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
* 09dfee07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
*
* 13472227 90 nop
* 13472228 77 0f ja short 13472239
* 1347222a c705 a8aa1001 20>mov dword ptr ds:[0x110aaa8],0x884ce20
* 13472234 -e9 cbdd16f0 jmp 035e0004
* 13472239 8b05 a8a71001 mov eax,dword ptr ds:[0x110a7a8]
* 1347223f 81e0 ffffff3f and eax,0x3fffffff
* 13472245 8bb0 30004007 mov esi,dword ptr ds:[eax+0x7400030]
* 1347224b 8b3d 84a71001 mov edi,dword ptr ds:[0x110a784]
* 13472251 81c7 01000000 add edi,0x1
* 13472257 8bee mov ebp,esi
* 13472259 032d 84a71001 add ebp,dword ptr ds:[0x110a784]
* 1347225f 8bc5 mov eax,ebp
* 13472261 81e0 ffffff3f and eax,0x3fffffff
* 13472267 0fbe90 00004007 movsx edx,byte ptr ds:[eax+0x7400000] ; jichi: hook here
* 1347226e 8b05 a8a71001 mov eax,dword ptr ds:[0x110a7a8]
* 13472274 81e0 ffffff3f and eax,0x3fffffff
* 1347227a 89b8 38004007 mov dword ptr ds:[eax+0x7400038],edi
* 13472280 8bea mov ebp,edx
* 13472282 81e5 ff000000 and ebp,0xff
* 13472288 81fa 0a000000 cmp edx,0xa
* 1347228e c705 70a71001 0a>mov dword ptr ds:[0x110a770],0xa
* 13472298 8915 74a71001 mov dword ptr ds:[0x110a774],edx
* 1347229e 893d 78a71001 mov dword ptr ds:[0x110a778],edi
* 134722a4 892d 7ca71001 mov dword ptr ds:[0x110a77c],ebp
* 134722aa 8935 80a71001 mov dword ptr ds:[0x110a780],esi
* 134722b0 0f85 16000000 jnz 134722cc
* 134722b6 832d c4aa1001 08 sub dword ptr ds:[0x110aac4],0x8
* 134722bd e9 02680000 jmp 13478ac4
* 134722c2 01ec add esp,ebp
* 134722c4 ce into
* 134722c5 8408 test byte ptr ds:[eax],cl
* 134722c7 -e9 57dd16f0 jmp 035e0023
* 134722cc 832d c4aa1001 08 sub dword ptr ds:[0x110aac4],0x8
* 134722d3 e9 0c000000 jmp 134722e4
* 134722d8 0140 ce add dword ptr ds:[eax-0x32],eax
* 134722db 8408 test byte ptr ds:[eax],cl
* 134722dd -e9 41dd16f0 jmp 035e0023
* 134722e2 90 nop
* 134722e3 cc int3
*/
// Read text from esi
static void SpecialPSPHookIntense(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD eax = stack->eax;
DWORD text = eax + hp->user_value;
if (BYTE c = *(BYTE *)text) { // unsigned char
*data = text;
*len = ::LeadByteTable[c]; // 1 or 2
//*split = regof(ecx, esp_base); // cause scenario text to split
//*split = regof(edx, esp_base); // cause scenario text to split
//*split = regof(ebx, esp_base); // works, but floating value
*split = FIXED_SPLIT_VALUE * 3;
}
}
bool InsertIntensePSPHook()
{
ConsoleOutput("Intense PSP: enter");
const BYTE bytes[] = {
0x77, 0x0f, // 13472228 77 0f ja short 13472239
0xc7,0x05, XX8, // 1347222a c705 a8aa1001 20>mov dword ptr ds:[0x110aaa8],0x884ce20
0xe9, XX4, // 13472234 -e9 cbdd16f0 jmp 035e0004
0x8b,0x05, XX4, // 13472239 8b05 a8a71001 mov eax,dword ptr ds:[0x110a7a8]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1347223f 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xb0, XX4, // 13472245 8bb0 30004007 mov esi,dword ptr ds:[eax+0x7400030]
0x8b,0x3d, XX4, // 1347224b 8b3d 84a71001 mov edi,dword ptr ds:[0x110a784]
0x81,0xc7, 0x01,0x00,0x00,0x00, // 13472251 81c7 01000000 add edi,0x1
0x8b,0xee, // 13472257 8bee mov ebp,esi
0x03,0x2d, XX4, // 13472259 032d 84a71001 add ebp,dword ptr ds:[0x110a784]
0x8b,0xc5, // 1347225f 8bc5 mov eax,ebp
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13472261 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xbe,0x90, XX4, // 13472267 0fbe90 00004007 movsx edx,byte ptr ds:[eax+0x7400000] ; jichi: hook here
0x8b,0x05, XX4, // 1347226e 8b05 a8a71001 mov eax,dword ptr ds:[0x110a7a8]
0x81,0xe0, 0xff,0xff,0xff,0x3f // 13472274 81e0 ffffff3f and eax,0x3fffffff
};
enum { memory_offset = 3 };
enum { addr_offset = 0x13472267 - 0x13472228 };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("Intense PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|NO_CONTEXT;
hp.text_fun = SpecialPSPHookIntense;
ConsoleOutput("Intense PSP: INSERT");
succ|=NewHook(hp, "Intense PSP");
}
ConsoleOutput("Intense PSP: leave");
return succ;
}
/** 7/26/2014 jichi Broccoli PSP engine, 0.9.8, 0.9.9
* Sample game: 明治東亰恋伽 (works on both 0.9.8, 0.9.9)
*
* Memory address is FIXED.
* Debug method: breakpoint the memory address
*
* The data is in (WORD)dl in bytes.
*
* There are two text threads.
* Only one is correct.
*
* 13d26cab cc int3
* 13d26cac 77 0f ja short 13d26cbd
* 13d26cae c705 a8aa1001 24>mov dword ptr ds:[0x110aaa8],0x886a724
* 13d26cb8 -e9 4793ccef jmp 039f0004
* 13d26cbd 8b35 dca71001 mov esi,dword ptr ds:[0x110a7dc]
* 13d26cc3 8db6 60feffff lea esi,dword ptr ds:[esi-0x1a0]
* 13d26cc9 8b3d e4a71001 mov edi,dword ptr ds:[0x110a7e4]
* 13d26ccf 8bc6 mov eax,esi
* 13d26cd1 81e0 ffffff3f and eax,0x3fffffff
* 13d26cd7 89b8 9001c007 mov dword ptr ds:[eax+0x7c00190],edi
* 13d26cdd 8b2d 80a71001 mov ebp,dword ptr ds:[0x110a780]
* 13d26ce3 0fbfed movsx ebp,bp
* 13d26ce6 8bd6 mov edx,esi
* 13d26ce8 8bce mov ecx,esi
* 13d26cea 03cd add ecx,ebp
* 13d26cec 8935 dca71001 mov dword ptr ds:[0x110a7dc],esi
* 13d26cf2 33c0 xor eax,eax
* 13d26cf4 3bd1 cmp edx,ecx
* 13d26cf6 0f92c0 setb al
* 13d26cf9 8bf0 mov esi,eax
* 13d26cfb 81fe 00000000 cmp esi,0x0
* 13d26d01 8935 70a71001 mov dword ptr ds:[0x110a770],esi
* 13d26d07 890d 74a71001 mov dword ptr ds:[0x110a774],ecx
* 13d26d0d 892d 80a71001 mov dword ptr ds:[0x110a780],ebp
* 13d26d13 8915 8ca71001 mov dword ptr ds:[0x110a78c],edx
* 13d26d19 0f85 16000000 jnz 13d26d35
* 13d26d1f 832d c4aa1001 08 sub dword ptr ds:[0x110aac4],0x8
* 13d26d26 e9 b9000000 jmp 13d26de4
* 13d26d2b 0158 a7 add dword ptr ds:[eax-0x59],ebx
* 13d26d2e 8608 xchg byte ptr ds:[eax],cl
* 13d26d30 -e9 ee92ccef jmp 039f0023
* 13d26d35 832d c4aa1001 08 sub dword ptr ds:[0x110aac4],0x8
* 13d26d3c e9 0b000000 jmp 13d26d4c
* 13d26d41 0144a7 86 add dword ptr ds:[edi-0x7a],eax
* 13d26d45 08e9 or cl,ch
* 13d26d47 d892 ccef9077 fcom dword ptr ds:[edx+0x7790efcc]
* 13d26d4d 0fc7 ??? ; unknown command
* 13d26d4f 05 a8aa1001 add eax,0x110aaa8
* 13d26d54 44 inc esp
* 13d26d55 a7 cmps dword ptr ds:[esi],dword ptr es:[ed>
* 13d26d56 8608 xchg byte ptr ds:[eax],cl
* 13d26d58 -e9 a792ccef jmp 039f0004
* 13d26d5d 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
* 13d26d63 81e0 ffffff3f and eax,0x3fffffff
* 13d26d69 0fb6b0 0000c007 movzx esi,byte ptr ds:[eax+0x7c00000]
* 13d26d70 8b3d 7ca71001 mov edi,dword ptr ds:[0x110a77c]
* 13d26d76 8d7f 01 lea edi,dword ptr ds:[edi+0x1]
* 13d26d79 8b05 8ca71001 mov eax,dword ptr ds:[0x110a78c]
* 13d26d7f 81e0 ffffff3f and eax,0x3fffffff
* 13d26d85 8bd6 mov edx,esi
* 13d26d87 8890 0000c007 mov byte ptr ds:[eax+0x7c00000],dl ; jichi: hook here, get byte from dl
* 13d26d8d 8b2d 8ca71001 mov ebp,dword ptr ds:[0x110a78c]
* 13d26d93 8d6d 01 lea ebp,dword ptr ss:[ebp+0x1]
* 13d26d96 81fe 00000000 cmp esi,0x0
* 13d26d9c 893d 7ca71001 mov dword ptr ds:[0x110a77c],edi
* 13d26da2 8935 88a71001 mov dword ptr ds:[0x110a788],esi
* 13d26da8 892d 8ca71001 mov dword ptr ds:[0x110a78c],ebp
* 13d26dae 0f84 16000000 je 13d26dca
* 13d26db4 832d c4aa1001 05 sub dword ptr ds:[0x110aac4],0x5
* 13d26dbb e9 f48b0100 jmp 13d3f9b4
* 13d26dc0 0138 add dword ptr ds:[eax],edi
* 13d26dc2 a7 cmps dword ptr ds:[esi],dword ptr es:[ed>
* 13d26dc3 8608 xchg byte ptr ds:[eax],cl
* 13d26dc5 -e9 5992ccef jmp 039f0023
* 13d26dca 832d c4aa1001 05 sub dword ptr ds:[0x110aac4],0x5
* 13d26dd1 e9 0e000000 jmp 13d26de4
* 13d26dd6 0158 a7 add dword ptr ds:[eax-0x59],ebx
* 13d26dd9 8608 xchg byte ptr ds:[eax],cl
* 13d26ddb -e9 4392ccef jmp 039f0023
* 13d26de0 90 nop
* 13d26de1 cc int3
*/
// New line character for Broccoli games is '^'
static inline bool _broccoligarbage_ch(char c) { return c == '^'; }
// Read text from dl
static void SpecialPSPHookBroccoli(hook_stack* stack, HookParam *, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD text = stack->edx; // edx address
char c = *(LPCSTR)text;
if (c && !_broccoligarbage_ch(c)) {
*data = text;
*len = 1;
*split = stack->ecx;
}
}
bool InsertBroccoliPSPHook()
{
ConsoleOutput("Broccoli PSP: enter");
const BYTE bytes[] = {
0x0f,0xc7, // 13d26d4d 0fc7 ??? ; unknown command
0x05, XX4, // 13d26d4f 05 a8aa1001 add eax,0x110aaa8
0x44, // 13d26d54 44 inc esp
0xa7, // 13d26d55 a7 cmps dword ptr ds:[esi],dword ptr es:[ed>
0x86,0x08, // 13d26d56 8608 xchg byte ptr ds:[eax],cl
0xe9, XX4, // 13d26d58 -e9 a792ccef jmp 039f0004
0x8b,0x05, XX4, // 13d26d5d 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
// Following pattern is not sufficient
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13d26d63 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb6,0xb0, XX4, // 13d26d69 0fb6b0 0000c007 movzx esi,byte ptr ds:[eax+0x7c00000]
0x8b,0x3d, XX4, // 13d26d70 8b3d 7ca71001 mov edi,dword ptr ds:[0x110a77c]
0x8d,0x7f, 0x01, // 13d26d76 8d7f 01 lea edi,dword ptr ds:[edi+0x1]
0x8b,0x05, XX4, // 13d26d79 8b05 8ca71001 mov eax,dword ptr ds:[0x110a78c]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13d26d7f 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xd6, // 13d26d85 8bd6 mov edx,esi
0x88,0x90, XX4, // 13d26d87 8890 0000c007 mov byte ptr ds:[eax+0x7c00000],dl ; jichi: hook here, get byte from dl
0x8b,0x2d, XX4, // 13d26d8d 8b2d 8ca71001 mov ebp,dword ptr ds:[0x110a78c]
0x8d,0x6d, 0x01, // 13d26d93 8d6d 01 lea ebp,dword ptr ss:[ebp+0x1]
0x81,0xfe, 0x00,0x00,0x00,0x00 // 13d26d96 81fe 00000000 cmp esi,0x0
};
enum { addr_offset = 0x13d26d87 - 0x13d26d4d };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("Broccoli PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.type = USING_STRING|USING_SPLIT|NO_CONTEXT;
hp.text_fun = SpecialPSPHookBroccoli;
//GROWL_DWORD(hp.address);
ConsoleOutput("Broccoli PSP: INSERT");
succ|=NewHook(hp, "Broccoli PSP");
}
ConsoleOutput("Broccoli PSP: leave");
return succ;
}
/** 9/5/2014 jichi felistella.co.jp PSP engine, 0.9.8, 0.9.9
* Sample game: Summon Night 5 0.9.8/0.9.9
*
* Encoding: utf8
* Fixed memory addresses: two matches
*
* Debug method: predict the text and add break-points.
*
* There are two good functions
* The second is used as it contains fewer garbage
*
* // Not used
* 14081173 cc int3
* 14081174 77 0f ja short 14081185
* 14081176 c705 c84c1301 40>mov dword ptr ds:[0x1134cc8],0x8989540
* 14081180 -e9 7feef5f3 jmp 07fe0004
* 14081185 8b35 9c491301 mov esi,dword ptr ds:[0x113499c]
* 1408118b 8bc6 mov eax,esi
* 1408118d 81e0 ffffff3f and eax,0x3fffffff
* 14081193 0fb6b8 00000008 movzx edi,byte ptr ds:[eax+0x8000000] ; jichi: hook here
* 1408119a 8bef mov ebp,edi
* 1408119c 81e5 80000000 and ebp,0x80
* 140811a2 8d76 01 lea esi,dword ptr ds:[esi+0x1]
* 140811a5 81fd 00000000 cmp ebp,0x0
* 140811ab c705 90491301 00>mov dword ptr ds:[0x1134990],0x0
* 140811b5 893d 9c491301 mov dword ptr ds:[0x113499c],edi
* 140811bb 8935 a0491301 mov dword ptr ds:[0x11349a0],esi
* 140811c1 892d a4491301 mov dword ptr ds:[0x11349a4],ebp
* 140811c7 0f85 16000000 jnz 140811e3
* 140811cd 832d e44c1301 06 sub dword ptr ds:[0x1134ce4],0x6
* 140811d4 e9 fbf71200 jmp 141b09d4
* 140811d9 01dc add esp,ebx
* 140811db 95 xchg eax,ebp
* 140811dc 98 cwde
* 140811dd 08e9 or cl,ch
* 140811df 40 inc eax
*
* // Used
* 141be92f cc int3
* 141be930 77 0f ja short 141be941
* 141be932 c705 c84c1301 0c>mov dword ptr ds:[0x1134cc8],0x8988f0c
* 141be93c -e9 c316e2f3 jmp 07fe0004
* 141be941 8b35 98491301 mov esi,dword ptr ds:[0x1134998]
* 141be947 8bc6 mov eax,esi
* 141be949 81e0 ffffff3f and eax,0x3fffffff
* 141be94f 0fb6b8 00000008 movzx edi,byte ptr ds:[eax+0x8000000] ; jichi: hook here
* 141be956 81ff 00000000 cmp edi,0x0
* 141be95c c705 90491301 00>mov dword ptr ds:[0x1134990],0x0
* 141be966 893d 98491301 mov dword ptr ds:[0x1134998],edi
* 141be96c 8935 9c491301 mov dword ptr ds:[0x113499c],esi
* 141be972 0f85 16000000 jnz 141be98e
* 141be978 832d e44c1301 04 sub dword ptr ds:[0x1134ce4],0x4
* 141be97f e9 e4020000 jmp 141bec68
* 141be984 01748f 98 add dword ptr ds:[edi+ecx*4-0x68],esi
* 141be988 08e9 or cl,ch
* 141be98a 95 xchg eax,ebp
* 141be98b 16 push ss
* 141be98c ^e2 f3 loopd short 141be981
* 141be98e 832d e44c1301 04 sub dword ptr ds:[0x1134ce4],0x4
* 141be995 e9 0e000000 jmp 141be9a8
* 141be99a 011c8f add dword ptr ds:[edi+ecx*4],ebx
* 141be99d 98 cwde
* 141be99e 08e9 or cl,ch
* 141be9a0 7f 16 jg short 141be9b8
* 141be9a2 ^e2 f3 loopd short 141be997
* 141be9a4 90 nop
* 141be9a5 cc int3
*/
// Only split text when edi is eax
// The value of edi is either eax or 0
static void SpecialPSPHookFelistella(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD eax = stack->eax;
LPCSTR text = LPCSTR(eax + hp->user_value);
if (text) {
*len = ::strlen(text); // utf8
*data = (DWORD)text;
DWORD edi = stack->edi;
*split = FIXED_SPLIT_VALUE * (edi == eax ? 4 : 5);
}
}
bool InsertFelistellaPSPHook()
{
ConsoleOutput("FELISTELLA PSP: enter");
const BYTE bytes[] = {
//0xcc, // 141be92f cc int3
0x77, 0x0f, // 141be930 77 0f ja short 141be941
0xc7,0x05, XX8, // 141be932 c705 c84c1301 0c>mov dword ptr ds:[0x1134cc8],0x8988f0c
0xe9, XX4, // 141be93c -e9 c316e2f3 jmp 07fe0004
0x8b,0x35, XX4, // 141be941 8b35 98491301 mov esi,dword ptr ds:[0x1134998]
0x8b,0xc6, // 141be947 8bc6 mov eax,esi
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 141be949 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb6,0xb8, XX4, // 141be94f 0fb6b8 00000008 movzx edi,byte ptr ds:[eax+0x8000000] ; jichi: hook here
0x81,0xff, 0x00,0x00,0x00,0x00, // 141be956 81ff 00000000 cmp edi,0x0
0xc7,0x05, XX4, 0x00,0x00,0x00,0x00, // 141be95c c705 90491301 00>mov dword ptr ds:[0x1134990],0x0
0x89,0x3d, XX4, // 141be966 893d 98491301 mov dword ptr ds:[0x1134998],edi
0x89,0x35, XX4, // 141be96c 8935 9c491301 mov dword ptr ds:[0x113499c],esi
0x0f,0x85, XX4, // 141be972 0f85 16000000 jnz 141be98e
0x83,0x2d, XX4, 0x04, // 141be978 832d e44c1301 04 sub dword ptr ds:[0x1134ce4],0x4
// Above is not sufficient
0xe9, XX4, // 141be97f e9 e4020000 jmp 141bec68
0x01,0x74,0x8f, 0x98 // 141be984 01748f 98 add dword ptr ds:[edi+ecx*4-0x68],esi
//0x08,0xe9, // 141be988 08e9 or cl,ch
// Below could be changed for different run
//0x95, // 141be98a 95 xchg eax,ebp
//0x16 // 141be98b 16 push ss
};
enum { memory_offset = 3 };
enum { addr_offset = 0x141be94f - 0x141be930 };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
//GROWL_DWORD(addr);
if (!addr)
ConsoleOutput("FELISTELLA PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|CODEC_UTF8|USING_SPLIT|NO_CONTEXT; // Fix the split value to merge all threads
//hp.text_fun = SpecialPSPHook;
hp.text_fun = SpecialPSPHookFelistella;
hp.offset=get_reg(regs::eax);
ConsoleOutput("FELISTELLA PSP: INSERT");
succ|=NewHook(hp, "FELISTELLA PSP");
}
ConsoleOutput("FELISTELLA PSP: leave");
return succ;
}
/** 7/13/2014 jichi alchemist-net.co.jp PSP engine, 0.9.8 only, not work on 0.9.9
* Sample game: your diary+ (moe-ydp.iso)
* The memory address is fixed.
* Note: This pattern seems to be common that not only exists in Alchemist games.
*
* Not work on 0.9.9: Amnesia Crowd
*
* Debug method: simply add hardware break points to the matched memory
*
* PPSSPP 0.9.8, your diary+
* 134076f2 cc int3
* 134076f3 cc int3
* 134076f4 77 0f ja short 13407705
* 134076f6 c705 a8aa1001 40>mov dword ptr ds:[0x110aaa8],0x8931040
* 13407700 -e9 ff88f2f3 jmp 07330004
* 13407705 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
* 1340770b 81e0 ffffff3f and eax,0x3fffffff
* 13407711 0fbeb0 00004007 movsx esi,byte ptr ds:[eax+0x7400000] // jichi: hook here
* 13407718 8b3d 78a71001 mov edi,dword ptr ds:[0x110a778]
* 1340771e 8b2d 7ca71001 mov ebp,dword ptr ds:[0x110a77c]
* 13407724 81c5 01000000 add ebp,0x1
* 1340772a 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
* 13407730 81e0 ffffff3f and eax,0x3fffffff
* 13407736 8bd6 mov edx,esi
* 13407738 8890 00004007 mov byte ptr ds:[eax+0x7400000],dl // jichi: alternatively hook here
* 1340773e 8b15 78a71001 mov edx,dword ptr ds:[0x110a778]
* 13407744 81c2 01000000 add edx,0x1
* 1340774a 8bcd mov ecx,ebp
* 1340774c 8935 88a71001 mov dword ptr ds:[0x110a788],esi
* 13407752 8bf2 mov esi,edx
* 13407754 813d 88a71001 00>cmp dword ptr ds:[0x110a788],0x0
* 1340775e 893d 70a71001 mov dword ptr ds:[0x110a770],edi
* 13407764 8935 78a71001 mov dword ptr ds:[0x110a778],esi
* 1340776a 890d 7ca71001 mov dword ptr ds:[0x110a77c],ecx
* 13407770 8915 80a71001 mov dword ptr ds:[0x110a780],edx
* 13407776 892d 84a71001 mov dword ptr ds:[0x110a784],ebp
* 1340777c 0f85 16000000 jnz 13407798
* 13407782 832d c4aa1001 08 sub dword ptr ds:[0x110aac4],0x8
* 13407789 e9 ce000000 jmp 1340785c
* 1340778e 017c10 93 add dword ptr ds:[eax+edx-0x6d],edi
* 13407792 08e9 or cl,ch
* 13407794 8b88 f2f3832d mov ecx,dword ptr ds:[eax+0x2d83f3f2]
* 1340779a c4aa 100108e9 les ebp,fword ptr ds:[edx+0xe9080110] ; modification of segment register
* 134077a0 0c 00 or al,0x0
* 134077a2 0000 add byte ptr ds:[eax],al
* 134077a4 0160 10 add dword ptr ds:[eax+0x10],esp
* 134077a7 93 xchg eax,ebx
* 134077a8 08e9 or cl,ch
* 134077aa ^75 88 jnz short 13407734
* 134077ac f2: prefix repne: ; superfluous prefix
* 134077ad f3: prefix rep: ; superfluous prefix
* 134077ae 90 nop
* 134077af cc int3
*/
namespace { // unnamed
// Return true if the text is a garbage character
inline bool _alchemistgarbage_ch(char c)
{
return c == '.' || c == '/'
|| c == '#' || c == ':' // garbage in alchemist2 hook
|| c >= '0' && c <= '9'
|| c >= 'A' && c <= 'z' // also ignore ASCII 91-96: [ \ ] ^ _ `
;
}
// Return true if the text is full of garbage characters
bool _alchemistgarbage(LPCSTR p)
{
enum { MAX_LENGTH = VNR_TEXT_CAPACITY };
for (int count = 0; *p && count < MAX_LENGTH; count++, p++)
if (!_alchemistgarbage_ch(*p))
return false;
return true;
}
// 7/20/2014 jichi: Trim Rejet garbage. Sample game: 月華繚乱ROMANCE
// Such as: #Pos[1,2]
inline bool _rejetgarbage_ch(char c)
{
return c == '#' || c == ' ' || c == '[' || c == ']' || c == ','
|| c >= 'A' && c <= 'z' // also ignore ASCII 91-96: [ \ ] ^ _ `
|| c >= '0' && c <= '9';
}
bool _rejetgarbage(LPCSTR p)
{
enum { MAX_LENGTH = VNR_TEXT_CAPACITY };
for (int count = 0; *p && count < MAX_LENGTH; count++, p++)
if (!_rejetgarbage_ch(*p))
return false;
return true;
}
// Trim leading garbage
LPCSTR _rejetltrim(LPCSTR p)
{
enum { MAX_LENGTH = VNR_TEXT_CAPACITY };
if (p)
for (int count = 0; *p && count < MAX_LENGTH; count++, p++)
if (!_rejetgarbage_ch(*p))
return p;
return nullptr;
}
// Trim trailing garbage
size_t _rejetstrlen(LPCSTR text)
{
if (!text)
return 0;
size_t len = ::strlen(text),
ret = len;
while (len && _rejetgarbage_ch(text[len - 1])) {
len--;
if (text[len] == '#') // in case trim UTF-8 trailing bytes
ret = len;
}
return ret;
}
} // unnamed namespace
static void SpecialPSPHookAlchemist(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD eax = stack->eax;
LPCSTR text = LPCSTR(eax + hp->user_value);
if (*text && !_alchemistgarbage(text)) {
text = _rejetltrim(text);
*data = (DWORD)text;
*len = _rejetstrlen(text);
*split = stack->ecx;
}
}
bool InsertAlchemistPSPHook()
{
ConsoleOutput("Alchemist PSP: enter");
const BYTE bytes[] = {
//0xcc, // 134076f2 cc int3
//0xcc, // 134076f3 cc int3
0x77, 0x0f, // 134076f4 77 0f ja short 13407705
0xc7,0x05, XX8, // 134076f6 c705 a8aa1001 40>mov dword ptr ds:[0x110aaa8],0x8931040
0xe9, XX4, // 13407700 -e9 ff88f2f3 jmp 07330004
0x8b,0x05, XX4, // 13407705 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1340770b 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xbe,0xb0, XX4, // 13407711 0fbeb0 00004007 movsx esi,byte ptr ds:[eax+0x7400000] // jichi: hook here
0x8b,0x3d, XX4, // 13407718 8b3d 78a71001 mov edi,dword ptr ds:[0x110a778]
0x8b,0x2d, XX4, // 1340771e 8b2d 7ca71001 mov ebp,dword ptr ds:[0x110a77c]
0x81,0xc5, 0x01,0x00,0x00,0x00, // 13407724 81c5 01000000 add ebp,0x1
0x8b,0x05, XX4, // 1340772a 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13407730 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xd6, // 13407736 8bd6 mov edx,esi
0x88,0x90 //, XX4 // 13407738 8890 00004007 mov byte ptr ds:[eax+0x7400000],dl // jichi: alternatively hook here
};
enum { memory_offset = 3 }; // 13407711 0fbeb0 00004007 movsx esi,byte ptr ds:[eax+0x7400000]
enum { addr_offset = 0x13407711 - 0x134076f4 };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
//GROWL_DWORD(addr);
if (!addr)
ConsoleOutput("Alchemist PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.text_fun = SpecialPSPHookAlchemist;
hp.type = USING_STRING|NO_CONTEXT; // no context is needed to get rid of variant retaddr
ConsoleOutput("Alchemist PSP: INSERT");
succ|=NewHook(hp, "Alchemist PSP");
}
ConsoleOutput("Alchemist PSP: leave");
return succ;
}
/** 8/12/2014 jichi Konami.jp PSP engine, 0.9.8, 0.9.9,
* Though Alchemist/Otomate can work, it has bad split that creates too many threads.
*
* Sample game: 幻想水滸<E6B0B4>紡がれし百年の<E5B9B4>on 0.9.8, 0.9.9
*
* Memory address is FIXED.
* But hardware accesses are looped.
* Debug method: predict and breakpoint the memory address
*
* There are two matches in the memory.
* Three looped functions are as follows.
* I randomply picked the first one.
*
* It cannot extract character names.
*
* 14178f73 cc int3
* 14178f74 77 0f ja short 14178f85
* 14178f76 c705 c84c1301 a4>mov dword ptr ds:[0x1134cc8],0x88129a4
* 14178f80 -e9 7f7071ef jmp 03890004
* 14178f85 8b05 c8491301 mov eax,dword ptr ds:[0x11349c8]
* 14178f8b 81e0 ffffff3f and eax,0x3fffffff
* 14178f91 0fbeb0 00000008 movsx esi,byte ptr ds:[eax+0x8000000] ; jichi: hook here, loop
* 14178f98 81fe 40000000 cmp esi,0x40
* 14178f9e 8935 98491301 mov dword ptr ds:[0x1134998],esi
* 14178fa4 c705 9c491301 40>mov dword ptr ds:[0x113499c],0x40
* 14178fae 0f85 2f000000 jnz 14178fe3
* 14178fb4 8b05 c8491301 mov eax,dword ptr ds:[0x11349c8]
* 14178fba 81e0 ffffff3f and eax,0x3fffffff
* 14178fc0 0fbeb0 01000008 movsx esi,byte ptr ds:[eax+0x8000001]
* 14178fc7 8935 98491301 mov dword ptr ds:[0x1134998],esi
* 14178fcd 832d e44c1301 04 sub dword ptr ds:[0x1134ce4],0x4
* 14178fd4 c705 c84c1301 d0>mov dword ptr ds:[0x1134cc8],0x88129d0
* 14178fde -e9 407071ef jmp 03890023
* 14178fe3 832d e44c1301 04 sub dword ptr ds:[0x1134ce4],0x4
* 14178fea e9 0d000000 jmp 14178ffc
* 14178fef 01b429 8108e92a add dword ptr ds:[ecx+ebp+0x2ae90881],es>
* 14178ff6 70 71 jo short 14179069
* 14178ff8 ef out dx,eax ; i/o command
* 14178ff9 90 nop
* 14178ffa cc int3
*
* 1417a18c 77 0f ja short 1417a19d
* 1417a18e c705 c84c1301 78>mov dword ptr ds:[0x1134cc8],0x8818378
* 1417a198 -e9 675e71ef jmp 03890004
* 1417a19d 8b05 c8491301 mov eax,dword ptr ds:[0x11349c8]
* 1417a1a3 81e0 ffffff3f and eax,0x3fffffff
* 1417a1a9 0fbeb0 00000008 movsx esi,byte ptr ds:[eax+0x8000000] ; jichi: hook here, loop
* 1417a1b0 81fe 0a000000 cmp esi,0xa
* 1417a1b6 8935 98491301 mov dword ptr ds:[0x1134998],esi
* 1417a1bc c705 9c491301 0a>mov dword ptr ds:[0x113499c],0xa
* 1417a1c6 0f84 2e000000 je 1417a1fa
* 1417a1cc 8b05 fc491301 mov eax,dword ptr ds:[0x11349fc]
* 1417a1d2 81e0 ffffff3f and eax,0x3fffffff
* 1417a1d8 8bb0 18000008 mov esi,dword ptr ds:[eax+0x8000018]
* 1417a1de 8935 98491301 mov dword ptr ds:[0x1134998],esi
* 1417a1e4 832d e44c1301 04 sub dword ptr ds:[0x1134ce4],0x4
* 1417a1eb e9 24000000 jmp 1417a214
* 1417a1f0 01b0 838108e9 add dword ptr ds:[eax+0xe9088183],esi
* 1417a1f6 295e 71 sub dword ptr ds:[esi+0x71],ebx
* 1417a1f9 ef out dx,eax ; i/o command
* 1417a1fa 832d e44c1301 04 sub dword ptr ds:[0x1134ce4],0x4
* 1417a201 e9 1e660000 jmp 14180824
* 1417a206 0188 838108e9 add dword ptr ds:[eax+0xe9088183],ecx
* 1417a20c 135e 71 adc ebx,dword ptr ds:[esi+0x71]
* 1417a20f ef out dx,eax ; i/o command
* 1417a210 90 nop
* 1417a211 cc int3
* 1417a212 cc int3
*
* 1417a303 90 nop
* 1417a304 77 0f ja short 1417a315
* 1417a306 c705 c84c1301 48>mov dword ptr ds:[0x1134cc8],0x8818448
* 1417a310 -e9 ef5c71ef jmp 03890004
* 1417a315 8b35 dc491301 mov esi,dword ptr ds:[0x11349dc]
* 1417a31b 8b3d 98491301 mov edi,dword ptr ds:[0x1134998]
* 1417a321 33c0 xor eax,eax
* 1417a323 3bf7 cmp esi,edi
* 1417a325 0f9cc0 setl al
* 1417a328 8bf8 mov edi,eax
* 1417a32a 81ff 00000000 cmp edi,0x0
* 1417a330 893d 98491301 mov dword ptr ds:[0x1134998],edi
* 1417a336 0f84 2f000000 je 1417a36b
* 1417a33c 8b05 c8491301 mov eax,dword ptr ds:[0x11349c8]
* 1417a342 81e0 ffffff3f and eax,0x3fffffff
* 1417a348 0fbeb0 00000008 movsx esi,byte ptr ds:[eax+0x8000000] ; jichi: hook here, loop
* 1417a34f 8935 98491301 mov dword ptr ds:[0x1134998],esi
* 1417a355 832d e44c1301 03 sub dword ptr ds:[0x1134ce4],0x3
* 1417a35c e9 23000000 jmp 1417a384
* 1417a361 018484 8108e9b8 add dword ptr ss:[esp+eax*4+0xb8e90881],>
* 1417a368 5c pop esp
* 1417a369 ^71 ef jno short 1417a35a
* 1417a36b 832d e44c1301 03 sub dword ptr ds:[0x1134ce4],0x3
* 1417a372 c705 c84c1301 54>mov dword ptr ds:[0x1134cc8],0x8818454
* 1417a37c -e9 a25c71ef jmp 03890023
* 1417a381 90 nop
* 1417a382 cc int3
*/
// Read text from looped address word by word
// Use reverse search to avoid looping issue assume the text is at fixed address.
static void SpecialPSPHookKonami(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
//static LPCSTR lasttext; // this value should be the same for the same game
static size_t lastsize;
DWORD eax = stack->eax;
LPCSTR cur = LPCSTR(eax + hp->user_value);
if (!*cur)
return;
LPCSTR text = reverse_search_begin(cur);
if (!text)
return;
//if (lasttext != text) {
// lasttext = text;
// lastsize = 0; // reset last size
//}
size_t size = ::strlen(text);
if (size == lastsize)
return;
*len = lastsize = size;
*data = (DWORD)text;
*split = stack->ebx; // ecx changes for each character, ebx is an address, edx is stable, but very large
}
bool InsertKonamiPSPHook()
{
ConsoleOutput("KONAMI PSP: enter");
const BYTE bytes[] = {
// 14178f73 cc int3
0x77, 0x0f, // 14178f74 77 0f ja short 14178f85
0xc7,0x05, XX8, // 14178f76 c705 c84c1301 a4>mov dword ptr ds:[0x1134cc8],0x88129a4
0xe9, XX4, // 14178f80 -e9 7f7071ef jmp 03890004
0x8b,0x05, XX4, // 14178f85 8b05 c8491301 mov eax,dword ptr ds:[0x11349c8]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 14178f8b 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xbe,0xb0, XX4, // 14178f91 0fbeb0 00000008 movsx esi,byte ptr ds:[eax+0x8000000] ; jichi: hook here, loop
0x81,0xfe, 0x40,0x00,0x00,0x00, // 14178f98 81fe 40000000 cmp esi,0x40
0x89,0x35 //, XX4, // 14178f9e 8935 98491301 mov dword ptr ds:[0x1134998],esi
//0xc7,0x05, XX4, 0x40,0x00,0x00,0x00, // 14178fa4 c705 9c491301 40>mov dword ptr ds:[0x113499c],0x40
//0x0f,0x85, 0x2f,0x00,0x00,0x00,0x00, // 14178fae 0f85 2f000000 jnz 14178fe3
//0x8b,0x05, XX4 // 14178fb4 8b05 c8491301 mov eax,dword ptr ds:[0x11349c8]
};
enum { memory_offset = 3 };
enum { addr_offset = 0x14178f91 - 0x14178f74 };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("KONAMI PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|NO_CONTEXT;
hp.text_fun = SpecialPSPHookKonami;
ConsoleOutput("KONAMI PSP: INSERT");
succ|=NewHook(hp, "KONAMI PSP");
}
ConsoleOutput("KONAMI PSP: leave");
return succ;
}
/** 7/13/2014 jichi 5pb.jp PSP engine, 0.9.8, 0.9.9
* Sample game: STEINS;GATE
*
* FIXME: The current pattern could crash VNR
*
* Note: searching after 0x15000000 would found a wrong address on 0.9.9.
* Hooking to it would crash PPSSPP.
*
* Float memory addresses: two matches
*
* Debug method: precompute memory address and set break points, then navigate to that scene
*
* Attach to this function for wrong game might cause BEX (buffer overflow) exception.
*
* 135752c7 90 nop
* 135752c8 77 0f ja short 135752d9
* 135752ca c705 a8aa1001 d4>mov dword ptr ds:[0x110aaa8],0x8888ed4
* 135752d4 -e9 2badf3ef jmp 034b0004
* 135752d9 8b35 dca71001 mov esi,dword ptr ds:[0x110a7dc]
* 135752df 8d76 a0 lea esi,dword ptr ds:[esi-0x60]
* 135752e2 8b3d e4a71001 mov edi,dword ptr ds:[0x110a7e4]
* 135752e8 8bc6 mov eax,esi
* 135752ea 81e0 ffffff3f and eax,0x3fffffff
* 135752f0 89b8 1c004007 mov dword ptr ds:[eax+0x740001c],edi
* 135752f6 8b2d bca71001 mov ebp,dword ptr ds:[0x110a7bc]
* 135752fc 8bc6 mov eax,esi
* 135752fe 81e0 ffffff3f and eax,0x3fffffff
* 13575304 89a8 18004007 mov dword ptr ds:[eax+0x7400018],ebp
* 1357530a 8b15 b8a71001 mov edx,dword ptr ds:[0x110a7b8]
* 13575310 8bc6 mov eax,esi
* 13575312 81e0 ffffff3f and eax,0x3fffffff
* 13575318 8990 14004007 mov dword ptr ds:[eax+0x7400014],edx
* 1357531e 8b0d b4a71001 mov ecx,dword ptr ds:[0x110a7b4]
* 13575324 8bc6 mov eax,esi
* 13575326 81e0 ffffff3f and eax,0x3fffffff
* 1357532c 8988 10004007 mov dword ptr ds:[eax+0x7400010],ecx
* 13575332 8b3d b0a71001 mov edi,dword ptr ds:[0x110a7b0]
* 13575338 8bc6 mov eax,esi
* 1357533a 81e0 ffffff3f and eax,0x3fffffff
* 13575340 89b8 0c004007 mov dword ptr ds:[eax+0x740000c],edi
* 13575346 8b3d aca71001 mov edi,dword ptr ds:[0x110a7ac]
* 1357534c 8bc6 mov eax,esi
* 1357534e 81e0 ffffff3f and eax,0x3fffffff
* 13575354 89b8 08004007 mov dword ptr ds:[eax+0x7400008],edi
* 1357535a 8b3d a8a71001 mov edi,dword ptr ds:[0x110a7a8]
* 13575360 8bc6 mov eax,esi
* 13575362 81e0 ffffff3f and eax,0x3fffffff
* 13575368 89b8 04004007 mov dword ptr ds:[eax+0x7400004],edi
* 1357536e 8b15 78a71001 mov edx,dword ptr ds:[0x110a778]
* 13575374 8935 dca71001 mov dword ptr ds:[0x110a7dc],esi
* 1357537a 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
* 13575380 81e0 ffffff3f and eax,0x3fffffff
* 13575386 0fbeb0 00004007 movsx esi,byte ptr ds:[eax+0x7400000] ; jichi: hook here
* 1357538d 8935 78a71001 mov dword ptr ds:[0x110a778],esi
* 13575393 8b35 80a71001 mov esi,dword ptr ds:[0x110a780]
* 13575399 8935 b0a71001 mov dword ptr ds:[0x110a7b0],esi
* 1357539f 8b35 84a71001 mov esi,dword ptr ds:[0x110a784]
* 135753a5 8b0d 7ca71001 mov ecx,dword ptr ds:[0x110a77c]
* 135753ab 813d 78a71001 00>cmp dword ptr ds:[0x110a778],0x0
* 135753b5 c705 a8a71001 00>mov dword ptr ds:[0x110a7a8],0x0
* 135753bf 8935 aca71001 mov dword ptr ds:[0x110a7ac],esi
* 135753c5 890d b4a71001 mov dword ptr ds:[0x110a7b4],ecx
* 135753cb 8915 b8a71001 mov dword ptr ds:[0x110a7b8],edx
* 135753d1 0f85 16000000 jnz 135753ed
* 135753d7 832d c4aa1001 0f sub dword ptr ds:[0x110aac4],0xf
* 135753de e9 e5010000 jmp 135755c8
* 135753e3 01f0 add eax,esi
* 135753e5 90 nop
* 135753e6 8808 mov byte ptr ds:[eax],cl
* 135753e8 -e9 36acf3ef jmp 034b0023
* 135753ed 832d c4aa1001 0f sub dword ptr ds:[0x110aac4],0xf
* 135753f4 e9 0b000000 jmp 13575404
* 135753f9 0110 add dword ptr ds:[eax],edx
* 135753fb 8f ??? ; unknown command
* 135753fc 8808 mov byte ptr ds:[eax],cl
* 135753fe -e9 20acf3ef jmp 034b0023
* 13575403 90 nop
* 13575404 77 0f ja short 13575415
* 13575406 c705 a8aa1001 10>mov dword ptr ds:[0x110aaa8],0x8888f10
* 13575410 -e9 efabf3ef jmp 034b0004
* 13575415 8b35 a8a71001 mov esi,dword ptr ds:[0x110a7a8]
* 1357541b 33c0 xor eax,eax
* 1357541d 3b35 b0a71001 cmp esi,dword ptr ds:[0x110a7b0]
* 13575423 0f9cc0 setl al
* 13575426 8bf8 mov edi,eax
* 13575428 81ff 00000000 cmp edi,0x0
* 1357542e 893d 74a71001 mov dword ptr ds:[0x110a774],edi
* 13575434 0f84 22000000 je 1357545c
* 1357543a 8b35 b4a71001 mov esi,dword ptr ds:[0x110a7b4]
* 13575440 8935 78a71001 mov dword ptr ds:[0x110a778],esi
* 13575446 832d c4aa1001 03 sub dword ptr ds:[0x110aac4],0x3
* 1357544d c705 a8aa1001 2c>mov dword ptr ds:[0x110aaa8],0x8888f2c
* 13575457 -e9 c7abf3ef jmp 034b0023
* 1357545c 832d c4aa1001 03 sub dword ptr ds:[0x110aac4],0x3
* 13575463 e9 0c000000 jmp 13575474
* 13575468 011c8f add dword ptr ds:[edi+ecx*4],ebx
* 1357546b 8808 mov byte ptr ds:[eax],cl
* 1357546d -e9 b1abf3ef jmp 034b0023
* 13575472 90 nop
* 13575473 cc int3
* 13575474 77 0f ja short 13575485
* 13575476 c705 a8aa1001 1c>mov dword ptr ds:[0x110aaa8],0x8888f1c
* 13575480 -e9 7fabf3ef jmp 034b0004
* 13575485 8b35 78a71001 mov esi,dword ptr ds:[0x110a778]
* 1357548b 8b05 b8a71001 mov eax,dword ptr ds:[0x110a7b8]
* 13575491 81e0 ffffff3f and eax,0x3fffffff
* 13575497 8bd6 mov edx,esi
* 13575499 8890 00004007 mov byte ptr ds:[eax+0x7400000],dl
* 1357549f 8b3d b4a71001 mov edi,dword ptr ds:[0x110a7b4]
* 135754a5 8d7f 01 lea edi,dword ptr ds:[edi+0x1]
* 135754a8 8b2d b8a71001 mov ebp,dword ptr ds:[0x110a7b8]
* 135754ae 8d6d 01 lea ebp,dword ptr ss:[ebp+0x1]
* 135754b1 813d 68a71001 00>cmp dword ptr ds:[0x110a768],0x0
* 135754bb 893d b4a71001 mov dword ptr ds:[0x110a7b4],edi
* 135754c1 892d b8a71001 mov dword ptr ds:[0x110a7b8],ebp
* 135754c7 0f85 16000000 jnz 135754e3
* 135754cd 832d c4aa1001 04 sub dword ptr ds:[0x110aac4],0x4
* 135754d4 e9 23000000 jmp 135754fc
* 135754d9 01e4 add esp,esp
* 135754db 90 nop
* 135754dc 8808 mov byte ptr ds:[eax],cl
* 135754de -e9 40abf3ef jmp 034b0023
* 135754e3 832d c4aa1001 04 sub dword ptr ds:[0x110aac4],0x4
* 135754ea c705 a8aa1001 2c>mov dword ptr ds:[0x110aaa8],0x8888f2c
* 135754f4 -e9 2aabf3ef jmp 034b0023
* 135754f9 90 nop
* 135754fa cc int3
* 135754fb cc int3
*/
namespace { // unnamed
// Characters to ignore: [%0-9A-Z]
inline bool _5pbgarbage_ch(char c)
{ return c == '%' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9'; }
// Trim leading garbage
LPCSTR _5pbltrim(LPCSTR p)
{
enum { MAX_LENGTH = VNR_TEXT_CAPACITY };
if (p)
for (int count = 0; *p && count < MAX_LENGTH; count++, p++)
if (!_5pbgarbage_ch(*p))
return p;
return nullptr;
}
// Trim trailing garbage
size_t _5pbstrlen(LPCSTR text)
{
if (!text)
return 0;
size_t len = ::strlen(text),
ret = len;
while (len && _5pbgarbage_ch(text[len - 1])) {
len--;
if (text[len] == '%') // in case trim UTF-8 trailing bytes
ret = len;
}
return ret;
}
} // unnamed namespace
static void SpecialPSPHook5pb(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD eax = stack->eax;
LPCSTR text = LPCSTR(eax + hp->user_value);
if (*text) {
text = _5pbltrim(text);
*data = (DWORD)text;
*len = _5pbstrlen(text);
*split = stack->ecx;
//*split = FIXED_SPLIT_VALUE; // there is only one thread, no split used
}
}
bool Insert5pbPSPHook()
{
ConsoleOutput("5pb PSP: enter");
const BYTE bytes[] = {
//0x90, // 135752c7 90 nop
0x77, 0x0f, // 135752c8 77 0f ja short 135752d9
0xc7,0x05, XX8, // 135752ca c705 a8aa1001 d4>mov dword ptr ds:[0x110aaa8],0x8888ed4
0xe9, XX4, // 135752d4 -e9 2badf3ef jmp 034b0004
0x8b,0x35, XX4, // 135752d9 8b35 dca71001 mov esi,dword ptr ds:[0x110a7dc]
0x8d,0x76, 0xa0, // 135752df 8d76 a0 lea esi,dword ptr ds:[esi-0x60]
0x8b,0x3d, XX4, // 135752e2 8b3d e4a71001 mov edi,dword ptr ds:[0x110a7e4]
0x8b,0xc6, // 135752e8 8bc6 mov eax,esi
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 135752ea 81e0 ffffff3f and eax,0x3fffffff
0x89,0xb8, XX4, // 135752f0 89b8 1c004007 mov dword ptr ds:[eax+0x740001c],edi
0x8b,0x2d, XX4, // 135752f6 8b2d bca71001 mov ebp,dword ptr ds:[0x110a7bc]
0x8b,0xc6, // 135752fc 8bc6 mov eax,esi
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 135752fe 81e0 ffffff3f and eax,0x3fffffff
0x89,0xa8, XX4, // 13575304 89a8 18004007 mov dword ptr ds:[eax+0x7400018],ebp
0x8b,0x15, XX4, // 1357530a 8b15 b8a71001 mov edx,dword ptr ds:[0x110a7b8]
0x8b,0xc6, // 13575310 8bc6 mov eax,esi
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13575312 81e0 ffffff3f and eax,0x3fffffff
0x89,0x90, XX4, // 13575318 8990 14004007 mov dword ptr ds:[eax+0x7400014],edx
0x8b,0x0d, XX4, // 1357531e 8b0d b4a71001 mov ecx,dword ptr ds:[0x110a7b4]
0x8b,0xc6, // 13575324 8bc6 mov eax,esi
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13575326 81e0 ffffff3f and eax,0x3fffffff
0x89,0x88, XX4, // 1357532c 8988 10004007 mov dword ptr ds:[eax+0x7400010],ecx
0x8b,0x3d, XX4, // 13575332 8b3d b0a71001 mov edi,dword ptr ds:[0x110a7b0]
0x8b,0xc6, // 13575338 8bc6 mov eax,esi
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1357533a 81e0 ffffff3f and eax,0x3fffffff
0x89,0xb8, XX4, // 13575340 89b8 0c004007 mov dword ptr ds:[eax+0x740000c],edi
0x8b,0x3d, XX4, // 13575346 8b3d aca71001 mov edi,dword ptr ds:[0x110a7ac]
0x8b,0xc6, // 1357534c 8bc6 mov eax,esi
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1357534e 81e0 ffffff3f and eax,0x3fffffff
0x89,0xb8, XX4, // 13575354 89b8 08004007 mov dword ptr ds:[eax+0x7400008],edi
0x8b,0x3d, XX4, // 1357535a 8b3d a8a71001 mov edi,dword ptr ds:[0x110a7a8]
0x8b,0xc6, // 13575360 8bc6 mov eax,esi
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13575362 81e0 ffffff3f and eax,0x3fffffff
0x89,0xb8, XX4, // 13575368 89b8 04004007 mov dword ptr ds:[eax+0x7400004],edi
0x8b,0x15, XX4, // 1357536e 8b15 78a71001 mov edx,dword ptr ds:[0x110a778]
0x89,0x35, XX4, // 13575374 8935 dca71001 mov dword ptr ds:[0x110a7dc],esi
0x8b,0x05, XX4, // 1357537a 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13575380 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xbe,0xb0 //, XX4 // 13575386 0fbeb0 00004007 movsx esi,byte ptr ds:[eax+0x7400000] ; jichi: hook here
};
enum { memory_offset = 3 }; // 13575386 0fbeb0 00004007 movsx esi,byte ptr ds:[eax+0x7400000]
enum { addr_offset = sizeof(bytes) - memory_offset };
enum : DWORD { start = MemDbg::MappedMemoryStartAddress };
DWORD stop = PPSSPP_VERSION[1] == 9 && PPSSPP_VERSION[2] == 8 ? MemDbg::MemoryStopAddress : 0x15000000;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes), start, stop);
//GROWL_DWORD(addr);
auto succ=false;
if (!addr)
ConsoleOutput("5pb PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.text_fun = SpecialPSPHook5pb;
hp.type = USING_STRING|NO_CONTEXT; // no context is needed to get rid of variant retaddr
ConsoleOutput("5pb PSP: INSERT");
succ|=NewHook(hp, "5pb PSP");
}
ConsoleOutput("5pb PSP: leave");
return succ;
}
/** 7/19/2014 jichi kid-game.co.jp PSP engine, 0,9.8, 0.9.9
* Sample game: Monochrome
*
* Note: sceFontGetCharInfo, sceFontGetCharGlyphImage_Clip also works
*
* Debug method: breakpoint the memory address
* There are two matched memory address to the current text
*
* == Second run ==
* 13973a7b 90 nop
* 13973a7c 77 0f ja short 13973a8d
* 13973a7e c705 a8aa1001 90>mov dword ptr ds:[0x110aaa8],0x885c290
* 13973a88 -e9 77c5ecef jmp 03840004
* 13973a8d 8b05 90a71001 mov eax,dword ptr ds:[0x110a790]
* 13973a93 81e0 ffffff3f and eax,0x3fffffff
* 13973a99 0fb6b0 00008007 movzx esi,byte ptr ds:[eax+0x7800000]
* 13973aa0 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
* 13973aa6 81e0 ffffff3f and eax,0x3fffffff
* 13973aac 0fb6b8 00008007 movzx edi,byte ptr ds:[eax+0x7800000] ; jichi: hook here
* 13973ab3 81fe 00000000 cmp esi,0x0
* 13973ab9 c705 8ca71001 00>mov dword ptr ds:[0x110a78c],0x0
* 13973ac3 893d 9ca71001 mov dword ptr ds:[0x110a79c],edi
* 13973ac9 8935 a0a71001 mov dword ptr ds:[0x110a7a0],esi
* 13973acf 0f85 16000000 jnz 13973aeb
* 13973ad5 832d c4aa1001 04 sub dword ptr ds:[0x110aac4],0x4
* 13973adc c705 a8aa1001 d0>mov dword ptr ds:[0x110aaa8],0x885c2d0
* 13973ae6 -e9 38c5ecef jmp 03840023
* 13973aeb 832d c4aa1001 04 sub dword ptr ds:[0x110aac4],0x4
* 13973af2 e9 0d000000 jmp 13973b04
* 13973af7 01a0 c28508e9 add dword ptr ds:[eax+0xe90885c2],esp
* 13973afd 22c5 and al,ch
* 13973aff ec in al,dx ; i/o command
* 13973b00 ef out dx,eax ; i/o command
* 13973b01 90 nop
* 13973b02 cc int3
* 13973b03 cc int3
*
* == First run ==
* 1087394a cc int3
* 1087394b cc int3
* 1087394c 77 0f ja short 1087395d
* 1087394e c705 a8aa1001 78>mov dword ptr ds:[0x110aaa8],0x885c278
* 10873958 -e9 a7c6bff2 jmp 03470004
* 1087395d 8b35 80d0da12 mov esi,dword ptr ds:[0x12dad080]
* 10873963 8bc6 mov eax,esi
* 10873965 81e0 ffffff3f and eax,0x3fffffff
* 1087396b 8bb8 0000000a mov edi,dword ptr ds:[eax+0xa000000]
* 10873971 81ff 00000000 cmp edi,0x0
* 10873977 c705 70a71001 00>mov dword ptr ds:[0x110a770],0x8db0000
* 10873981 c705 74a71001 00>mov dword ptr ds:[0x110a774],0x0
* 1087398b 893d 90a71001 mov dword ptr ds:[0x110a790],edi
* 10873991 8935 94a71001 mov dword ptr ds:[0x110a794],esi
* 10873997 c705 98a71001 00>mov dword ptr ds:[0x110a798],0x0
* 108739a1 0f85 16000000 jnz 108739bd
* 108739a7 832d c4aa1001 06 sub dword ptr ds:[0x110aac4],0x6
* 108739ae e9 75c20100 jmp 1088fc28
* 108739b3 0148 c3 add dword ptr ds:[eax-0x3d],ecx
* 108739b6 8508 test dword ptr ds:[eax],ecx
* 108739b8 -e9 66c6bff2 jmp 03470023
* 108739bd 832d c4aa1001 06 sub dword ptr ds:[0x110aac4],0x6
* 108739c4 e9 0b000000 jmp 108739d4
* 108739c9 0190 c28508e9 add dword ptr ds:[eax+0xe90885c2],edx
* 108739cf 50 push eax
* 108739d0 c6 ??? ; unknown command
* 108739d1 bf f290770f mov edi,0xf7790f2
* 108739d6 c705 a8aa1001 90>mov dword ptr ds:[0x110aaa8],0x885c290
* 108739e0 -e9 1fc6bff2 jmp 03470004
* 108739e5 8b05 90a71001 mov eax,dword ptr ds:[0x110a790]
* 108739eb 81e0 ffffff3f and eax,0x3fffffff
* 108739f1 0fb6b0 0000000a movzx esi,byte ptr ds:[eax+0xa000000] ; jichi: hook here
* 108739f8 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
* 108739fe 81e0 ffffff3f and eax,0x3fffffff
* 10873a04 0fb6b8 0000000a movzx edi,byte ptr ds:[eax+0xa000000] ; jichi: hook here
* 10873a0b 81fe 00000000 cmp esi,0x0
* 10873a11 c705 8ca71001 00>mov dword ptr ds:[0x110a78c],0x0
* 10873a1b 893d 9ca71001 mov dword ptr ds:[0x110a79c],edi
* 10873a21 8935 a0a71001 mov dword ptr ds:[0x110a7a0],esi
* 10873a27 0f85 16000000 jnz 10873a43
* 10873a2d 832d c4aa1001 04 sub dword ptr ds:[0x110aac4],0x4
* 10873a34 c705 a8aa1001 d0>mov dword ptr ds:[0x110aaa8],0x885c2d0
* 10873a3e -e9 e0c5bff2 jmp 03470023
* 10873a43 832d c4aa1001 04 sub dword ptr ds:[0x110aac4],0x4
* 10873a4a e9 0d000000 jmp 10873a5c
* 10873a4f 01a0 c28508e9 add dword ptr ds:[eax+0xe90885c2],esp
* 10873a55 ca c5bf retf 0xbfc5 ; far return
* 10873a58 f2: prefix repne: ; superfluous prefix
* 10873a59 90 nop
* 10873a5a cc int3
* 10873a5b cc int3
*/
static void SpecialPSPHookKid(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD eax = stack->eax;
LPCSTR text = LPCSTR(eax + hp->user_value);
static LPCSTR lasttext; // Prevent reading the same address multiple times
if (text != lasttext && *text) {
lasttext = text;
text = _5pbltrim(text);
*data = (DWORD)text;
*len = _5pbstrlen(text);
*split = stack->ecx;
}
}
bool InsertKidPSPHook()
{
ConsoleOutput("KID PSP: enter");
const BYTE bytes[] = {
//0x90, // 13973a7b 90 nop
0x77, 0x0f, // 13973a7c 77 0f ja short 13973a8d
0xc7,0x05, XX8, // 13973a7e c705 a8aa1001 90>mov dword ptr ds:[0x110aaa8],0x885c290
0xe9, XX4, // 13973a88 -e9 77c5ecef jmp 03840004
0x8b,0x05, XX4, // 13973a8d 8b05 90a71001 mov eax,dword ptr ds:[0x110a790]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13973a93 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb6,0xb0, XX4, // 13973a99 0fb6b0 00008007 movzx esi,byte ptr ds:[eax+0x7800000]
0x8b,0x05, XX4, // 13973aa0 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13973aa6 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb6,0xb8, XX4, // 13973aac 0fb6b8 00008007 movzx edi,byte ptr ds:[eax+0x7800000] ; jichi: hook here
0x81,0xfe, 0x00,0x00,0x00,0x00 // 13973ab3 81fe 00000000 cmp esi,0x0
};
enum { memory_offset = 3 }; // 13973aac 0fb6b8 00008007 movzx edi,byte ptr ds:[eax+0x7800000]
enum { addr_offset = 0x13973aac - 0x13973a7c };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("KID PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.text_fun = SpecialPSPHookKid;
hp.type = USING_STRING|NO_CONTEXT; // no context is needed to get rid of variant retaddr
//HookParam hp;
//hp.address = addr + addr_offset;
//hp.user_value = *(DWORD *)(hp.address + memory_offset);
//hp.type = USING_STRING|USING_SPLIT|NO_CONTEXT; // Fix the split value to merge all threads
//hp.offset=get_reg(regs::eax);
//hp.split = get_reg(regs::ecx);
//hp.text_fun = SpecialPSPHook;
ConsoleOutput("KID PSP: INSERT");
succ|=NewHook(hp, "KID PSP");
}
ConsoleOutput("KID PSP: leave");
return succ;
}
/** 7/13/2014 jichi imageepoch.co.jp PSP engine, 0.9.8, 0.9.9
* Sample game: BLACK<43>OCK SHOOTER
*
* Float memory addresses: two matches, UTF-8
*
* 7/29/2014: seems to work on 0.9.9
*
* Debug method: find current sentence, then find next sentence in the memory
* and add break-points
*
* 1346d34b f0:90 lock nop ; lock prefix is not allowed
* 1346d34d cc int3
* 1346d34e cc int3
* 1346d34f cc int3
* 1346d350 77 0f ja short 1346d361
* 1346d352 c705 a8aa1001 e4>mov dword ptr ds:[0x110aaa8],0x89609e4
* 1346d35c -e9 a32c27f0 jmp 036e0004
* 1346d361 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
* 1346d367 81e0 ffffff3f and eax,0x3fffffff
* 1346d36d 8bb0 00004007 mov esi,dword ptr ds:[eax+0x7400000] ; jichi: or hook here
* 1346d373 8b3d 78a71001 mov edi,dword ptr ds:[0x110a778]
* 1346d379 8bc6 mov eax,esi
* 1346d37b 81e0 ffffff3f and eax,0x3fffffff
* 1346d381 0fb6a8 00004007 movzx ebp,byte ptr ds:[eax+0x7400000] ; jichi: hook here
* 1346d388 8d56 01 lea edx,dword ptr ds:[esi+0x1]
* 1346d38b 8bc5 mov eax,ebp
* 1346d38d 0fbec8 movsx ecx,al
* 1346d390 8935 70a71001 mov dword ptr ds:[0x110a770],esi
* 1346d396 8bf5 mov esi,ebp
* 1346d398 81f9 00000000 cmp ecx,0x0
* 1346d39e 892d 74a71001 mov dword ptr ds:[0x110a774],ebp
* 1346d3a4 8935 78a71001 mov dword ptr ds:[0x110a778],esi
* 1346d3aa 8915 7ca71001 mov dword ptr ds:[0x110a77c],edx
* 1346d3b0 890d 80a71001 mov dword ptr ds:[0x110a780],ecx
* 1346d3b6 893d 84a71001 mov dword ptr ds:[0x110a784],edi
* 1346d3bc 0f8d 16000000 jge 1346d3d8
* 1346d3c2 832d c4aa1001 07 sub dword ptr ds:[0x110aac4],0x7
* 1346d3c9 e9 22000000 jmp 1346d3f0
* 1346d3ce 010c0a add dword ptr ds:[edx+ecx],ecx
* 1346d3d1 96 xchg eax,esi
* 1346d3d2 08e9 or cl,ch
* 1346d3d4 4b dec ebx
* 1346d3d5 2c 27 sub al,0x27
* 1346d3d7 f0:832d c4aa1001>lock sub dword ptr ds:[0x110aac4],0x7 ; lock prefix
* 1346d3df e9 bc380000 jmp 13470ca0
* 1346d3e4 0100 add dword ptr ds:[eax],eax
* 1346d3e6 0a96 08e9352c or dl,byte ptr ds:[esi+0x2c35e908]
* 1346d3ec 27 daa
* 1346d3ed f0:90 lock nop ; lock prefix is not allowed
* 1346d3ef cc int3
*/
static void SpecialPSPHookImageepoch(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
// 7/25/2014: I tried using uniquemap to eliminate duplication, which does not work
DWORD eax = stack->eax;
DWORD text = eax + hp->user_value;
static DWORD lasttext; // Prevent reading the same address multiple times
if (text != lasttext && *(LPCSTR)text) {
*data = lasttext = text;
*len = ::strlen((LPCSTR)text); // UTF-8 is null-terminated
*split = stack->ecx; // use ecx = "this" to split?
}
}
bool InsertImageepochPSPHook()
{
ConsoleOutput("Imageepoch PSP: enter");
const BYTE bytes[] = {
//0xcc, // 1346d34f cc int3
0x77, 0x0f, // 1346d350 77 0f ja short 1346d361
0xc7,0x05, XX8, // 1346d352 c705 a8aa1001 e4>mov dword ptr ds:[0x110aaa8],0x89609e4
0xe9, XX4, // 1346d35c -e9 a32c27f0 jmp 036e0004
0x8b,0x05, XX4, // 1346d361 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1346d367 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xb0, XX4, // 1346d36d 8bb0 00004007 mov esi,dword ptr ds:[eax+0x7400000] ; jichi: or hook here
0x8b,0x3d, XX4, // 1346d373 8b3d 78a71001 mov edi,dword ptr ds:[0x110a778]
0x8b,0xc6, // 1346d379 8bc6 mov eax,esi
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1346d37b 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb6,0xa8, XX4, // 1346d381 0fb6a8 00004007 movzx ebp,byte ptr ds:[eax+0x7400000] ; jichi: hook here
0x8d,0x56, 0x01, // 1346d388 8d56 01 lea edx,dword ptr ds:[esi+0x1]
0x8b,0xc5, // 1346d38b 8bc5 mov eax,ebp
0x0f,0xbe,0xc8 // 1346d38d 0fbec8 movsx ecx,al
};
enum { memory_offset = 3 }; // 1346d381 0fb6a8 00004007 movzx ebp,byte ptr ds:[eax+0x7400000]
enum { addr_offset = 0x1346d381 - 0x1346d350 };
//enum { addr_offset = sizeof(bytes) - memory_offset };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("Imageepoch PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|USING_SPLIT|NO_CONTEXT; // UTF-8, though
hp.offset=get_reg(regs::eax);
hp.split = get_reg(regs::ecx);
//hp.text_fun = SpecialPSPHook;
hp.text_fun = SpecialPSPHookImageepoch; // since this function is common, use its own static lasttext for HPF_IgnoreSameAddress
ConsoleOutput("Imageepoch PSP: INSERT");
succ|=NewHook(hp, "Imageepoch PSP");
}
ConsoleOutput("Imageepoch PSP: leave");
return succ;
}
/** 7/20/2014 jichi alchemist-net.co.jp PSP engine, 0.9.8, 0.9.9
* An alternative alchemist hook for old alchemist games.
* Sample game: のーふぁ<E381B5>と (No Fate)
* The memory address is fixed.
*
* Also work on 0.9.9 Otoboku PSP
*
* Debug method: simply add hardware break points to the matched memory
*
* Two candidate functions are seems OK.
*
* Instruction pattern: 81e580808080 // and ebp,0x80808080
*
* 0.9.8 のーふぁ<E381B5>
* 13400ef3 90 nop
* 13400ef4 77 0f ja short 13400f05
* 13400ef6 c705 a8aa1001 d0>mov dword ptr ds:[0x110aaa8],0x889aad0
* 13400f00 -e9 fff050f0 jmp 03910004
* 13400f05 8b35 78a71001 mov esi,dword ptr ds:[0x110a778]
* 13400f0b 8bc6 mov eax,esi
* 13400f0d 81e0 ffffff3f and eax,0x3fffffff
* 13400f13 8bb8 00004007 mov edi,dword ptr ds:[eax+0x7400000] ; jichi
* 13400f19 8bef mov ebp,edi
* 13400f1b 81ed 01010101 sub ebp,0x1010101
* 13400f21 f7d7 not edi
* 13400f23 23ef and ebp,edi
* 13400f25 81e5 80808080 and ebp,0x80808080
* 13400f2b 81fd 00000000 cmp ebp,0x0
* 13400f31 c705 78a71001 80>mov dword ptr ds:[0x110a778],0x80808080
* 13400f3b c705 7ca71001 01>mov dword ptr ds:[0x110a77c],0x1010101
* 13400f45 8935 80a71001 mov dword ptr ds:[0x110a780],esi
* 13400f4b 892d 88a71001 mov dword ptr ds:[0x110a788],ebp
* 13400f51 0f84 22000000 je 13400f79
* 13400f57 8b35 80a71001 mov esi,dword ptr ds:[0x110a780]
* 13400f5d 8935 78a71001 mov dword ptr ds:[0x110a778],esi
* 13400f63 832d c4aa1001 0c sub dword ptr ds:[0x110aac4],0xc
* 13400f6a e9 35ba0000 jmp 1340c9a4
* 13400f6f 0124ab add dword ptr ds:[ebx+ebp*4],esp
* 13400f72 8908 mov dword ptr ds:[eax],ecx
* 13400f74 -e9 aaf050f0 jmp 03910023
* 13400f79 832d c4aa1001 0c sub dword ptr ds:[0x110aac4],0xc
* 13400f80 e9 0b000000 jmp 13400f90
* 13400f85 0100 add dword ptr ds:[eax],eax
* 13400f87 ab stos dword ptr es:[edi]
* 13400f88 8908 mov dword ptr ds:[eax],ecx
* 13400f8a -e9 94f050f0 jmp 03910023
* 13400f8f 90 nop
*/
static void SpecialPSPHookAlchemist2(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD eax = stack->eax;
LPCSTR text = LPCSTR(eax + hp->user_value);
if (*text && !_alchemistgarbage(text)) {
*data = (DWORD)text;
*len = ::strlen(text);
*split = stack->ecx;
}
}
bool InsertAlchemist2PSPHook()
{
ConsoleOutput("Alchemist2 PSP: enter");
const BYTE bytes[] = {
0x77, 0x0f, // 13400ef4 77 0f ja short 13400f05
0xc7,0x05, XX8, // 13400ef6 c705 a8aa1001 d0>mov dword ptr ds:[0x110aaa8],0x889aad0
0xe9, XX4, // 13400f00 -e9 fff050f0 jmp 03910004
0x8b,0x35, XX4, // 13400f05 8b35 78a71001 mov esi,dword ptr ds:[0x110a778]
0x8b,0xc6, // 13400f0b 8bc6 mov eax,esi
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13400f0d 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xb8, XX4, // 13400f13 8bb8 00004007 mov edi,dword ptr ds:[eax+0x7400000] ; jichi: hook here
0x8b,0xef, // 13400f19 8bef mov ebp,edi
0x81,0xed, 0x01,0x01,0x01,0x01, // 13400f1b 81ed 01010101 sub ebp,0x1010101
0xf7,0xd7, // 13400f21 f7d7 not edi
0x23,0xef, // 13400f23 23ef and ebp,edi
0x81,0xe5, 0x80,0x80,0x80,0x80, // 13400f25 81e5 80808080 and ebp,0x80808080
0x81,0xfd, 0x00,0x00,0x00,0x00 // 13400f2b 81fd 00000000 cmp ebp,0x0
};
enum { memory_offset = 2 }; // 13400f13 8bb8 00004007 mov edi,dword ptr ds:[eax+0x7400000]
enum { addr_offset = 0x13400f13 - 0x13400ef4 };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
//GROWL_DWORD(addr);
if (!addr)
ConsoleOutput("Alchemist2 PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.text_fun = SpecialPSPHookAlchemist2;
hp.type = USING_STRING|NO_CONTEXT; // no context is needed to get rid of variant retaddr
ConsoleOutput("Alchemist2 PSP: INSERT");
succ|=NewHook(hp, "Alchemist2 PSP");
}
ConsoleOutput("Alchemist2 PSP: leave");
return succ;
}
/** 7/19/2014 jichi CYBERFRONT PSP engine, 0,9.8, 0.9.9
* Sample game: 想<>かけ<E3818B>クローストゥ (0.9.9)
*
* Debug method: breakpoint the memory address
* There are two matched memory address to the current text
*
* The second is used.
* The #1 is missing text.
*
* #1 The text is written word by word
*
* 0ed8be86 90 nop
* 0ed8be87 cc int3
* 0ed8be88 77 0f ja short 0ed8be99
* 0ed8be8a c705 c84c1301 dc>mov dword ptr ds:[0x1134cc8],0x88151dc
* 0ed8be94 -e9 6b41b4f4 jmp 038d0004
* 0ed8be99 8b35 cc491301 mov esi,dword ptr ds:[0x11349cc]
* 0ed8be9f 8d76 02 lea esi,dword ptr ds:[esi+0x2]
* 0ed8bea2 8b3d 94491301 mov edi,dword ptr ds:[0x1134994]
* 0ed8bea8 8b05 d0491301 mov eax,dword ptr ds:[0x11349d0]
* 0ed8beae 81e0 ffffff3f and eax,0x3fffffff
* 0ed8beb4 8bd7 mov edx,edi
* 0ed8beb6 8890 00008009 mov byte ptr ds:[eax+0x9800000],dl ; jichi: hook here, write text here
* 0ed8bebc 8b05 c8491301 mov eax,dword ptr ds:[0x11349c8]
* 0ed8bec2 81e0 ffffff3f and eax,0x3fffffff
* 0ed8bec8 0fb6a8 00008009 movzx ebp,byte ptr ds:[eax+0x9800000]
* 0ed8becf 8b05 d0491301 mov eax,dword ptr ds:[0x11349d0]
* 0ed8bed5 81e0 ffffff3f and eax,0x3fffffff
* 0ed8bedb 8bd5 mov edx,ebp
* 0ed8bedd 8890 01008009 mov byte ptr ds:[eax+0x9800001],dl
* 0ed8bee3 8b15 d0491301 mov edx,dword ptr ds:[0x11349d0]
* 0ed8bee9 8d52 02 lea edx,dword ptr ds:[edx+0x2]
* 0ed8beec 892d 90491301 mov dword ptr ds:[0x1134990],ebp
* 0ed8bef2 8935 cc491301 mov dword ptr ds:[0x11349cc],esi
* 0ed8bef8 8915 d0491301 mov dword ptr ds:[0x11349d0],edx
* 0ed8befe 832d e44c1301 06 sub dword ptr ds:[0x1134ce4],0x6
* 0ed8bf05 e9 0e000000 jmp 0ed8bf18
* 0ed8bf0a 013451 add dword ptr ds:[ecx+edx*2],esi
* 0ed8bf0d 8108 e90f41b4 or dword ptr ds:[eax],0xb4410fe9
* 0ed8bf13 f4 hlt ; privileged command
* 0ed8bf14 90 nop
* 0ed8bf15 cc int3
*
* #2 The text is read
*
* Issue: the text is read multiple times.
* Only esp > 0xfff is kept.
*
* 0ed8cf13 90 nop
* 0ed8cf14 77 0f ja short 0ed8cf25
* 0ed8cf16 c705 c84c1301 b8>mov dword ptr ds:[0x1134cc8],0x888d1b8
* 0ed8cf20 -e9 df30b4f4 jmp 038d0004
* 0ed8cf25 8b05 98491301 mov eax,dword ptr ds:[0x1134998]
* 0ed8cf2b 81e0 ffffff3f and eax,0x3fffffff
* 0ed8cf31 0fb6b0 00008009 movzx esi,byte ptr ds:[eax+0x9800000] ; jichi: hook here
* 0ed8cf38 81fe 00000000 cmp esi,0x0
* 0ed8cf3e 8935 90491301 mov dword ptr ds:[0x1134990],esi
* 0ed8cf44 0f85 2f000000 jnz 0ed8cf79
* 0ed8cf4a 8b05 9c491301 mov eax,dword ptr ds:[0x113499c]
* 0ed8cf50 81e0 ffffff3f and eax,0x3fffffff
* 0ed8cf56 0fbeb0 00008009 movsx esi,byte ptr ds:[eax+0x9800000]
* 0ed8cf5d 8935 90491301 mov dword ptr ds:[0x1134990],esi
* 0ed8cf63 832d e44c1301 03 sub dword ptr ds:[0x1134ce4],0x3
* 0ed8cf6a c705 c84c1301 18>mov dword ptr ds:[0x1134cc8],0x888d218
* 0ed8cf74 -e9 aa30b4f4 jmp 038d0023
* 0ed8cf79 832d e44c1301 03 sub dword ptr ds:[0x1134ce4],0x3
* 0ed8cf80 e9 0b000000 jmp 0ed8cf90
* 0ed8cf85 01c4 add esp,eax
* 0ed8cf87 d188 08e99430 ror dword ptr ds:[eax+0x3094e908],1
* 0ed8cf8d b4 f4 mov ah,0xf4
* 0ed8cf8f 90 nop
*/
static void SpecialPSPHookCyberfront(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD splitvalue = stack->edi;
if (splitvalue < 0x0fff)
return;
DWORD eax = stack->eax;
LPCSTR text = LPCSTR(eax + hp->user_value);
if (*text) {
*data = (DWORD)text;
*len = ::strlen(text);
*split = splitvalue;
}
}
bool InsertCyberfrontPSPHook()
{
ConsoleOutput("CYBERFRONT PSP: enter");
const BYTE bytes[] = {
// 0ed8cf13 90 nop
0x77, 0x0f, // 0ed8cf14 77 0f ja short 0ed8cf25
0xc7,0x05, XX8, // 0ed8cf16 c705 c84c1301 b8>mov dword ptr ds:[0x1134cc8],0x888d1b8
0xe9, XX4, // 0ed8cf20 -e9 df30b4f4 jmp 038d0004
0x8b,0x05, XX4, // 0ed8cf25 8b05 98491301 mov eax,dword ptr ds:[0x1134998]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 0ed8cf2b 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb6,0xb0, XX4, // 0ed8cf31 0fb6b0 00008009 movzx esi,byte ptr ds:[eax+0x9800000] ; jichi: hook here
0x81,0xfe, 0x00,0x00,0x00,0x00, // 0ed8cf38 81fe 00000000 cmp esi,0x0
0x89,0x35, XX4, // 0ed8cf3e 8935 90491301 mov dword ptr ds:[0x1134990],esi
0x0f,0x85, 0x2f,0x00,0x00,0x00, // 0ed8cf44 0f85 2f000000 jnz 0ed8cf79
0x8b,0x05, XX4, // 0ed8cf4a 8b05 9c491301 mov eax,dword ptr ds:[0x113499c]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 0ed8cf50 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xbe,0xb0, XX4, // 0ed8cf56 0fbeb0 00008009 movsx esi,byte ptr ds:[eax+0x9800000]
0x89,0x35, XX4, // 0ed8cf5d 8935 90491301 mov dword ptr ds:[0x1134990],esi
0x83,0x2d, XX4, 0x03, // 0ed8cf63 832d e44c1301 03 sub dword ptr ds:[0x1134ce4],0x3
0xc7,0x05 //, XX8 // 0ed8cf6a c705 c84c1301 18>mov dword ptr ds:[0x1134cc8],0x888d218
};
enum { memory_offset = 3 }; // 13909a51 8890 00008007 mov byte ptr ds:[eax+0x7800000],dl
enum { addr_offset = 0x0ed8cf31 - 0x0ed8cf14 };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
//GROWL_DWORD(addr);
if (!addr)
ConsoleOutput("CYBERFRONT PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|USING_SPLIT|NO_CONTEXT;
//hp.offset=get_reg(regs::eax);
hp.text_fun = SpecialPSPHookCyberfront;
ConsoleOutput("CYBERFRONT PSP: INSERT");
succ|=NewHook(hp, "CYBERFRONT PSP");
}
ConsoleOutput("CYBERFRONT PSP: leave");
return succ;
}
/** 7/19/2014 jichi yetigame.jp PSP engine, 0.9.8, 0.9.9
* Sample game: Secret Game Portable 0.9.8/0.9.9
*
* Float memory addresses: two matches
*
* Debug method: find current sentence, then find next sentence in the memory
* and add break-points. Need to patch 1 leading \u3000 space.
*
* It seems that each time I ran the game, the instruction pattern would change?!
* == The second time I ran the game ==
*
* 14e49ed9 90 nop
* 14e49eda cc int3
* 14e49edb cc int3
* 14e49edc 77 0f ja short 14e49eed
* 14e49ede c705 a8aa1001 98>mov dword ptr ds:[0x110aaa8],0x885ff98
* 14e49ee8 -e9 17619eee jmp 03830004
* 14e49eed 8b35 70a71001 mov esi,dword ptr ds:[0x110a770]
* 14e49ef3 c1ee 1f shr esi,0x1f
* 14e49ef6 8b05 b4a71001 mov eax,dword ptr ds:[0x110a7b4]
* 14e49efc 81e0 ffffff3f and eax,0x3fffffff
* 14e49f02 8bb8 14deff07 mov edi,dword ptr ds:[eax+0x7ffde14]
* 14e49f08 0335 70a71001 add esi,dword ptr ds:[0x110a770]
* 14e49f0e d1fe sar esi,1
* 14e49f10 8b05 b0a71001 mov eax,dword ptr ds:[0x110a7b0]
* 14e49f16 81e0 ffffff3f and eax,0x3fffffff
* 14e49f1c 89b8 00000008 mov dword ptr ds:[eax+0x8000000],edi
* 14e49f22 8b05 dca71001 mov eax,dword ptr ds:[0x110a7dc]
* 14e49f28 81e0 ffffff3f and eax,0x3fffffff
* 14e49f2e 89b0 30000008 mov dword ptr ds:[eax+0x8000030],esi
* 14e49f34 8b05 b4a71001 mov eax,dword ptr ds:[0x110a7b4]
* 14e49f3a 81e0 ffffff3f and eax,0x3fffffff
* 14e49f40 8ba8 14deff07 mov ebp,dword ptr ds:[eax+0x7ffde14]
* 14e49f46 8bc5 mov eax,ebp
* 14e49f48 81e0 ffffff3f and eax,0x3fffffff
* 14e49f4e 0fb6b0 00000008 movzx esi,byte ptr ds:[eax+0x8000000] ; jichi: hook here
* 14e49f55 8d6d 01 lea ebp,dword ptr ss:[ebp+0x1]
* 14e49f58 8b05 b4a71001 mov eax,dword ptr ds:[0x110a7b4]
*
* == The first time I ran the game ==
* There are a couple of good break-points, as follows.
* Only the second function is hooked.
*
* 138cf7a2 cc int3
* 138cf7a3 cc int3
* 138cf7a4 77 0f ja short 138cf7b5
* 138cf7a6 c705 a8aa1001 90>mov dword ptr ds:[0x110aaa8],0x885ff90
* 138cf7b0 -e9 4f08a9f3 jmp 07360004
* 138cf7b5 8b05 b4a71001 mov eax,dword ptr ds:[0x110a7b4]
* 138cf7bb 81e0 ffffff3f and eax,0x3fffffff
* 138cf7c1 8bb0 14de7f07 mov esi,dword ptr ds:[eax+0x77fde14]
* 138cf7c7 8935 78a71001 mov dword ptr ds:[0x110a778],esi
* 138cf7cd c705 e4a71001 98>mov dword ptr ds:[0x110a7e4],0x885ff98
* 138cf7d7 832d c4aa1001 02 sub dword ptr ds:[0x110aac4],0x2
* 138cf7de e9 0d000000 jmp 138cf7f0
* 138cf7e3 015c48 85 add dword ptr ds:[eax+ecx*2-0x7b],ebx
* 138cf7e7 08e9 or cl,ch
* 138cf7e9 36:08a9 f390cccc or byte ptr ss:[ecx+0xcccc90f3],ch
* 138cf7f0 77 0f ja short 138cf801
* 138cf7f2 c705 a8aa1001 5c>mov dword ptr ds:[0x110aaa8],0x885485c
* 138cf7fc -e9 0308a9f3 jmp 07360004
* 138cf801 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
* 138cf807 81e0 ffffff3f and eax,0x3fffffff
* 138cf80d 0fb6b0 00008007 movzx esi,byte ptr ds:[eax+0x7800000] ; jichi: hook here
* 138cf814 81fe 00000000 cmp esi,0x0
* 138cf81a 8935 74a71001 mov dword ptr ds:[0x110a774],esi
* 138cf820 c705 80a71001 00>mov dword ptr ds:[0x110a780],0x0
* 138cf82a c705 84a71001 25>mov dword ptr ds:[0x110a784],0x25
* 138cf834 c705 88a71001 4e>mov dword ptr ds:[0x110a788],0x4e
* 138cf83e c705 8ca71001 6e>mov dword ptr ds:[0x110a78c],0x6e
* 138cf848 0f85 16000000 jnz 138cf864
* 138cf84e 832d c4aa1001 06 sub dword ptr ds:[0x110aac4],0x6
* 138cf855 e9 b6010000 jmp 138cfa10
* 138cf85a 01bc48 8508e9bf add dword ptr ds:[eax+ecx*2+0xbfe90885],>
* 138cf861 07 pop es ; modification of segment register
* 138cf862 a9 f3832dc4 test eax,0xc42d83f3
* 138cf867 aa stos byte ptr es:[edi]
* 138cf868 1001 adc byte ptr ds:[ecx],al
* 138cf86a 06 push es
* 138cf86b e9 0c000000 jmp 138cf87c
* 138cf870 017448 85 add dword ptr ds:[eax+ecx*2-0x7b],esi
* 138cf874 08e9 or cl,ch
* 138cf876 a9 07a9f390 test eax,0x90f3a907
* 138cf87b cc int3
*
* This function is used.
* 138cfa46 cc int3
* 138cfa47 cc int3
* 138cfa48 77 0f ja short 138cfa59
* 138cfa4a c705 a8aa1001 98>mov dword ptr ds:[0x110aaa8],0x885ff98
* 138cfa54 -e9 ab05a9f3 jmp 07360004
* 138cfa59 8b35 70a71001 mov esi,dword ptr ds:[0x110a770]
* 138cfa5f c1ee 1f shr esi,0x1f
* 138cfa62 8b05 b4a71001 mov eax,dword ptr ds:[0x110a7b4]
* 138cfa68 81e0 ffffff3f and eax,0x3fffffff
* 138cfa6e 8bb8 14de7f07 mov edi,dword ptr ds:[eax+0x77fde14]
* 138cfa74 0335 70a71001 add esi,dword ptr ds:[0x110a770]
* 138cfa7a d1fe sar esi,1
* 138cfa7c 8b05 b0a71001 mov eax,dword ptr ds:[0x110a7b0]
* 138cfa82 81e0 ffffff3f and eax,0x3fffffff
* 138cfa88 89b8 00008007 mov dword ptr ds:[eax+0x7800000],edi
* 138cfa8e 8b05 dca71001 mov eax,dword ptr ds:[0x110a7dc]
* 138cfa94 81e0 ffffff3f and eax,0x3fffffff
* 138cfa9a 89b0 30008007 mov dword ptr ds:[eax+0x7800030],esi
* 138cfaa0 8b05 b4a71001 mov eax,dword ptr ds:[0x110a7b4]
* 138cfaa6 81e0 ffffff3f and eax,0x3fffffff
* 138cfaac 8ba8 14de7f07 mov ebp,dword ptr ds:[eax+0x77fde14]
* 138cfab2 8bc5 mov eax,ebp
* 138cfab4 81e0 ffffff3f and eax,0x3fffffff
* 138cfaba 0fb6b0 00008007 movzx esi,byte ptr ds:[eax+0x7800000] ; jichi: hook here
* 138cfac1 8d6d 01 lea ebp,dword ptr ss:[ebp+0x1]
* 138cfac4 8b05 b4a71001 mov eax,dword ptr ds:[0x110a7b4]
* 138cfaca 81e0 ffffff3f and eax,0x3fffffff
* 138cfad0 89a8 14de7f07 mov dword ptr ds:[eax+0x77fde14],ebp
* 138cfad6 81fe 00000000 cmp esi,0x0
* 138cfadc 892d 70a71001 mov dword ptr ds:[0x110a770],ebp
* 138cfae2 8935 74a71001 mov dword ptr ds:[0x110a774],esi
* 138cfae8 893d aca71001 mov dword ptr ds:[0x110a7ac],edi
* 138cfaee 0f84 16000000 je 138cfb0a
* 138cfaf4 832d c4aa1001 0b sub dword ptr ds:[0x110aac4],0xb
* 138cfafb e9 24000000 jmp 138cfb24
* 138cfb00 01b0 ff8508e9 add dword ptr ds:[eax+0xe90885ff],esi
* 138cfb06 1905 a9f3832d sbb dword ptr ds:[0x2d83f3a9],eax
* 138cfb0c c4aa 10010be9 les ebp,fword ptr ds:[edx+0xe90b0110] ; modification of segment register
* 138cfb12 9a 00000001 c4ff call far ffc4:01000000 ; far call
* 138cfb19 8508 test dword ptr ds:[eax],ecx
* 138cfb1b -e9 0305a9f3 jmp 07360023
* 138cfb20 90 nop
* 138cfb21 cc int3
* 138cfb22 cc int3
*
* 138cfb22 cc int3
* 138cfb23 cc int3
* 138cfb24 77 0f ja short 138cfb35
* 138cfb26 c705 a8aa1001 b0>mov dword ptr ds:[0x110aaa8],0x885ffb0
* 138cfb30 -e9 cf04a9f3 jmp 07360004
* 138cfb35 8b05 b4a71001 mov eax,dword ptr ds:[0x110a7b4]
* 138cfb3b 81e0 ffffff3f and eax,0x3fffffff
* 138cfb41 8bb0 14de7f07 mov esi,dword ptr ds:[eax+0x77fde14]
* 138cfb47 8bc6 mov eax,esi
* 138cfb49 81e0 ffffff3f and eax,0x3fffffff
* 138cfb4f 0fb6b8 00008007 movzx edi,byte ptr ds:[eax+0x7800000] ; jichi: hook here
* 138cfb56 8d76 01 lea esi,dword ptr ds:[esi+0x1]
* 138cfb59 8b05 b4a71001 mov eax,dword ptr ds:[0x110a7b4]
* 138cfb5f 81e0 ffffff3f and eax,0x3fffffff
* 138cfb65 89b0 14de7f07 mov dword ptr ds:[eax+0x77fde14],esi
* 138cfb6b 81ff 00000000 cmp edi,0x0
* 138cfb71 8935 70a71001 mov dword ptr ds:[0x110a770],esi
* 138cfb77 893d 74a71001 mov dword ptr ds:[0x110a774],edi
* 138cfb7d 0f84 16000000 je 138cfb99
* 138cfb83 832d c4aa1001 05 sub dword ptr ds:[0x110aac4],0x5
* 138cfb8a ^e9 95ffffff jmp 138cfb24
* 138cfb8f 01b0 ff8508e9 add dword ptr ds:[eax+0xe90885ff],esi
* 138cfb95 8a04a9 mov al,byte ptr ds:[ecx+ebp*4]
* 138cfb98 f3: prefix rep: ; superfluous prefix
* 138cfb99 832d c4aa1001 05 sub dword ptr ds:[0x110aac4],0x5
* 138cfba0 e9 0b000000 jmp 138cfbb0
* 138cfba5 01c4 add esp,eax
* 138cfba7 ff85 08e97404 inc dword ptr ss:[ebp+0x474e908]
* 138cfbad a9 f390770f test eax,0xf7790f3
* 138cfbb2 c705 a8aa1001 c4>mov dword ptr ds:[0x110aaa8],0x885ffc4
* 138cfbbc -e9 4304a9f3 jmp 07360004
* 138cfbc1 f3:0f1015 6c1609>movss xmm2,dword ptr ds:[0x1009166c]
* 138cfbc9 8b05 b0a71001 mov eax,dword ptr ds:[0x110a7b0]
* 138cfbcf 81e0 ffffff3f and eax,0x3fffffff
* 138cfbd5 8bb0 00008007 mov esi,dword ptr ds:[eax+0x7800000]
* 138cfbdb f3:0f101d 641609>movss xmm3,dword ptr ds:[0x10091664]
* 138cfbe3 c7c7 00000000 mov edi,0x0
* 138cfbe9 893d f4b12b11 mov dword ptr ds:[0x112bb1f4],edi
* 138cfbef 8bc6 mov eax,esi
* 138cfbf1 81e0 ffffff3f and eax,0x3fffffff
* 138cfbf7 0fb6a8 00008007 movzx ebp,byte ptr ds:[eax+0x7800000] ; jichi: hook here
* 138cfbfe 81fd 00000000 cmp ebp,0x0
* 138cfc04 c705 70a71001 00>mov dword ptr ds:[0x110a770],0x9ac0000
* 138cfc0e c705 74a71001 00>mov dword ptr ds:[0x110a774],0x8890000
* 138cfc18 892d a8a71001 mov dword ptr ds:[0x110a7a8],ebp
* 138cfc1e 8935 aca71001 mov dword ptr ds:[0x110a7ac],esi
* 138cfc24 c705 b4a71001 00>mov dword ptr ds:[0x110a7b4],0x8890000
* 138cfc2e c705 b8a71001 80>mov dword ptr ds:[0x110a7b8],0x80
* 138cfc38 c705 bca71001 00>mov dword ptr ds:[0x110a7bc],0x0
* 138cfc42 c705 e0a71001 00>mov dword ptr ds:[0x110a7e0],0x0
* 138cfc4c f3:0f111d 3ca810>movss dword ptr ds:[0x110a83c],xmm3
* 138cfc54 f3:0f1115 40a810>movss dword ptr ds:[0x110a840],xmm2
* 138cfc5c 0f85 16000000 jnz 138cfc78
* 138cfc62 832d c4aa1001 0d sub dword ptr ds:[0x110aac4],0xd
* 138cfc69 e9 32270000 jmp 138d23a0
* 138cfc6e 0158 00 add dword ptr ds:[eax],ebx
* 138cfc71 8608 xchg byte ptr ds:[eax],cl
* 138cfc73 -e9 ab03a9f3 jmp 07360023
* 138cfc78 832d c4aa1001 0d sub dword ptr ds:[0x110aac4],0xd
* 138cfc7f e9 0c000000 jmp 138cfc90
* 138cfc84 01f8 add eax,edi
* 138cfc86 ff85 08e99503 inc dword ptr ss:[ebp+0x395e908]
* 138cfc8c a9 f390cc77 test eax,0x77cc90f3
* 138cfc91 0fc7 ??? ; unknown command
* 138cfc93 05 a8aa1001 add eax,0x110aaa8
* 138cfc98 f8 clc
* 138cfc99 ff85 08e96303 inc dword ptr ss:[ebp+0x363e908]
* 138cfc9f a9 f38b35ac test eax,0xac358bf3
* 138cfca4 a7 cmps dword ptr ds:[esi],dword ptr es:[ed>
* 138cfca5 1001 adc byte ptr ds:[ecx],al
* 138cfca7 8b3d b4a71001 mov edi,dword ptr ds:[0x110a7b4]
* 138cfcad 81c7 48d6ffff add edi,-0x29b8
* 138cfcb3 8935 78a71001 mov dword ptr ds:[0x110a778],esi
* 138cfcb9 893d 7ca71001 mov dword ptr ds:[0x110a77c],edi
* 138cfcbf c705 80a71001 02>mov dword ptr ds:[0x110a780],0x2
* 138cfcc9 c705 e4a71001 08>mov dword ptr ds:[0x110a7e4],0x8860008
* 138cfcd3 832d c4aa1001 04 sub dword ptr ds:[0x110aac4],0x4
* 138cfcda ^e9 4914f4ff jmp 13811128
* 138cfcdf 90 nop
* 138cfce0 77 0f ja short 138cfcf1
* 138cfce2 c705 a8aa1001 74>mov dword ptr ds:[0x110aaa8],0x8844574
* 138cfcec -e9 1303a9f3 jmp 07360004
* 138cfcf1 8b35 84a71001 mov esi,dword ptr ds:[0x110a784]
* 138cfcf7 81c6 ffffffff add esi,-0x1
* 138cfcfd 813d 84a71001 00>cmp dword ptr ds:[0x110a784],0x0
* 138cfd07 8935 8ca71001 mov dword ptr ds:[0x110a78c],esi
* 138cfd0d 0f85 16000000 jnz 138cfd29
* 138cfd13 832d c4aa1001 02 sub dword ptr ds:[0x110aac4],0x2
* 138cfd1a c705 a8aa1001 e0>mov dword ptr ds:[0x110aaa8],0x88445e0
* 138cfd24 -e9 fa02a9f3 jmp 07360023
* 138cfd29 832d c4aa1001 02 sub dword ptr ds:[0x110aac4],0x2
* 138cfd30 ^e9 ab15f4ff jmp 138112e0
* 138cfd35 90 nop
* 138cfd36 cc int3
* 138cfd37 cc int3
*
* 13811266 cc int3
* 13811267 cc int3
* 13811268 77 0f ja short 13811279
* 1381126a c705 a8aa1001 b0>mov dword ptr ds:[0x110aaa8],0x88445b0
* 13811274 -e9 8bedb4f3 jmp 07360004
* 13811279 8b35 8ca71001 mov esi,dword ptr ds:[0x110a78c]
* 1381127f 8b3d 88a71001 mov edi,dword ptr ds:[0x110a788]
* 13811285 8b2d 84a71001 mov ebp,dword ptr ds:[0x110a784]
* 1381128b 81c5 ffffffff add ebp,-0x1
* 13811291 813d 84a71001 00>cmp dword ptr ds:[0x110a784],0x0
* 1381129b 8935 78a71001 mov dword ptr ds:[0x110a778],esi
* 138112a1 893d 7ca71001 mov dword ptr ds:[0x110a77c],edi
* 138112a7 892d 8ca71001 mov dword ptr ds:[0x110a78c],ebp
* 138112ad 0f84 16000000 je 138112c9
* 138112b3 832d c4aa1001 04 sub dword ptr ds:[0x110aac4],0x4
* 138112ba e9 21000000 jmp 138112e0
* 138112bf 017c45 84 add dword ptr ss:[ebp+eax*2-0x7c],edi
* 138112c3 08e9 or cl,ch
* 138112c5 5a pop edx
* 138112c6 ed in eax,dx ; i/o command
* 138112c7 b4 f3 mov ah,0xf3
* 138112c9 832d c4aa1001 04 sub dword ptr ds:[0x110aac4],0x4
* 138112d0 c705 a8aa1001 c0>mov dword ptr ds:[0x110aaa8],0x88445c0
* 138112da -e9 44edb4f3 jmp 07360023
* 138112df 90 nop
* 138112e0 77 0f ja short 138112f1
* 138112e2 c705 a8aa1001 7c>mov dword ptr ds:[0x110aaa8],0x884457c
* 138112ec -e9 13edb4f3 jmp 07360004
* 138112f1 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
* 138112f7 81e0 ffffff3f and eax,0x3fffffff
* 138112fd 0fb6b0 00008007 movzx esi,byte ptr ds:[eax+0x7800000] ; jichi: hook here
* 13811304 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
* 1381130a 81e0 ffffff3f and eax,0x3fffffff
* 13811310 0fbeb8 00008007 movsx edi,byte ptr ds:[eax+0x7800000] ; jichi: hook here
* 13811317 8bc6 mov eax,esi
* 13811319 0fbee8 movsx ebp,al
* 1381131c 3bef cmp ebp,edi
* 1381131e 893d 70a71001 mov dword ptr ds:[0x110a770],edi
* 13811324 892d 74a71001 mov dword ptr ds:[0x110a774],ebp
* 1381132a 8935 80a71001 mov dword ptr ds:[0x110a780],esi
* 13811330 0f85 16000000 jnz 1381134c
* 13811336 832d c4aa1001 05 sub dword ptr ds:[0x110aac4],0x5
* 1381133d e9 56110000 jmp 13812498
* 13811342 01c8 add eax,ecx
* 13811344 45 inc ebp
* 13811345 8408 test byte ptr ds:[eax],cl
* 13811347 -e9 d7ecb4f3 jmp 07360023
* 1381134c 832d c4aa1001 05 sub dword ptr ds:[0x110aac4],0x5
* 13811353 e9 0c000000 jmp 13811364
* 13811358 0190 458408e9 add dword ptr ds:[eax+0xe9088445],edx
* 1381135e c1ec b4 shr esp,0xb4 ; shift constant out of range 1..31
* 13811361 f3: prefix rep: ; superfluous prefix
* 13811362 90 nop
* 13811363 cc int3
*
* 13811362 90 nop
* 13811363 cc int3
* 13811364 77 0f ja short 13811375
* 13811366 c705 a8aa1001 90>mov dword ptr ds:[0x110aaa8],0x8844590
* 13811370 -e9 8fecb4f3 jmp 07360004
* 13811375 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
* 1381137b 81e0 ffffff3f and eax,0x3fffffff
* 13811381 0fb6b0 00008007 movzx esi,byte ptr ds:[eax+0x7800000] ; jichi: hook here
* 13811388 81e6 ff000000 and esi,0xff
* 1381138e 8b3d 80a71001 mov edi,dword ptr ds:[0x110a780]
* 13811394 81e7 ff000000 and edi,0xff
* 1381139a 8bc7 mov eax,edi
* 1381139c 8bfe mov edi,esi
* 1381139e 2bf8 sub edi,eax
* 138113a0 8b05 e4a71001 mov eax,dword ptr ds:[0x110a7e4]
* 138113a6 893d 70a71001 mov dword ptr ds:[0x110a770],edi
* 138113ac 8935 74a71001 mov dword ptr ds:[0x110a774],esi
* 138113b2 8905 a8aa1001 mov dword ptr ds:[0x110aaa8],eax
* 138113b8 832d c4aa1001 05 sub dword ptr ds:[0x110aac4],0x5
* 138113bf -e9 5fecb4f3 jmp 07360023
* 138113c4 90 nop
* 138113c5 cc int3
* 138113c6 cc int3
* 138113c7 cc int3
*
* 138124f2 cc int3
* 138124f3 cc int3
* 138124f4 77 0f ja short 13812505
* 138124f6 c705 a8aa1001 d0>mov dword ptr ds:[0x110aaa8],0x88445d0
* 13812500 -e9 ffdab4f3 jmp 07360004
* 13812505 813d 74a71001 00>cmp dword ptr ds:[0x110a774],0x0
* 1381250f c705 90a71001 00>mov dword ptr ds:[0x110a790],0x0
* 13812519 0f84 16000000 je 13812535
* 1381251f 832d c4aa1001 02 sub dword ptr ds:[0x110aac4],0x2
* 13812526 e9 21000000 jmp 1381254c
* 1381252b 018446 8408e9ee add dword ptr ds:[esi+eax*2+0xeee90884],>
* 13812532 dab4f3 832dc4aa fidiv dword ptr ds:[ebx+esi*8+0xaac42d83>
* 13812539 1001 adc byte ptr ds:[ecx],al
* 1381253b 02e9 add ch,cl
* 1381253d 3302 xor eax,dword ptr ds:[edx]
* 1381253f 0000 add byte ptr ds:[eax],al
* 13812541 01d8 add eax,ebx
* 13812543 45 inc ebp
* 13812544 8408 test byte ptr ds:[eax],cl
* 13812546 -e9 d8dab4f3 jmp 07360023
* 1381254b 90 nop
* 1381254c 77 0f ja short 1381255d
* 1381254e c705 a8aa1001 84>mov dword ptr ds:[0x110aaa8],0x8844684
* 13812558 -e9 a7dab4f3 jmp 07360004
* 1381255d 8b35 78a71001 mov esi,dword ptr ds:[0x110a778]
* 13812563 0335 8ca71001 add esi,dword ptr ds:[0x110a78c]
* 13812569 8b3d 88a71001 mov edi,dword ptr ds:[0x110a788]
* 1381256f 8d7f 01 lea edi,dword ptr ds:[edi+0x1]
* 13812572 8b2d 7ca71001 mov ebp,dword ptr ds:[0x110a77c]
* 13812578 8d6d 01 lea ebp,dword ptr ss:[ebp+0x1]
* 1381257b 8b15 90a71001 mov edx,dword ptr ds:[0x110a790]
* 13812581 3b15 8ca71001 cmp edx,dword ptr ds:[0x110a78c]
* 13812587 892d 7ca71001 mov dword ptr ds:[0x110a77c],ebp
* 1381258d 893d 88a71001 mov dword ptr ds:[0x110a788],edi
* 13812593 8935 94a71001 mov dword ptr ds:[0x110a794],esi
* 13812599 0f85 16000000 jnz 138125b5
* 1381259f 832d c4aa1001 04 sub dword ptr ds:[0x110aac4],0x4
* 138125a6 c705 a8aa1001 c4>mov dword ptr ds:[0x110aaa8],0x88446c4
* 138125b0 -e9 6edab4f3 jmp 07360023
* 138125b5 832d c4aa1001 04 sub dword ptr ds:[0x110aac4],0x4
* 138125bc e9 0b000000 jmp 138125cc
* 138125c1 019446 8408e958 add dword ptr ds:[esi+eax*2+0x58e90884],>
* 138125c8 dab4f3 90770fc7 fidiv dword ptr ds:[ebx+esi*8+0xc70f7790>
* 138125cf 05 a8aa1001 add eax,0x110aaa8
* 138125d4 94 xchg eax,esp
* 138125d5 46 inc esi
* 138125d6 8408 test byte ptr ds:[eax],cl
* 138125d8 -e9 27dab4f3 jmp 07360004
* 138125dd 8b05 88a71001 mov eax,dword ptr ds:[0x110a788]
* 138125e3 81e0 ffffff3f and eax,0x3fffffff
* 138125e9 0fb6b0 00008007 movzx esi,byte ptr ds:[eax+0x7800000] ; jichi: hook here
* 138125f0 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
* 138125f6 81e0 ffffff3f and eax,0x3fffffff
* 138125fc 0fb6b8 00008007 movzx edi,byte ptr ds:[eax+0x7800000]
* 13812603 8bc6 mov eax,esi
* 13812605 0fbee8 movsx ebp,al
* 13812608 8bc7 mov eax,edi
* 1381260a 0fbed0 movsx edx,al
* 1381260d 8b0d 90a71001 mov ecx,dword ptr ds:[0x110a790]
* 13812613 8d49 01 lea ecx,dword ptr ds:[ecx+0x1]
* 13812616 3bd5 cmp edx,ebp
* 13812618 892d 70a71001 mov dword ptr ds:[0x110a770],ebp
* 1381261e 8935 74a71001 mov dword ptr ds:[0x110a774],esi
* 13812624 893d 80a71001 mov dword ptr ds:[0x110a780],edi
* 1381262a 8915 84a71001 mov dword ptr ds:[0x110a784],edx
* 13812630 890d 90a71001 mov dword ptr ds:[0x110a790],ecx
* 13812636 0f84 16000000 je 13812652
* 1381263c 832d c4aa1001 06 sub dword ptr ds:[0x110aac4],0x6
* 13812643 e9 98d70b00 jmp 138cfde0
* 13812648 019445 8408e9d1 add dword ptr ss:[ebp+eax*2+0xd1e90884],>
* 1381264f d9b4f3 832dc4aa fstenv (28-byte) ptr ds:[ebx+esi*8+0xaac>
* 13812656 1001 adc byte ptr ds:[ecx],al
* 13812658 06 push es
* 13812659 e9 0e000000 jmp 1381266c
* 1381265e 01ac46 8408e9bb add dword ptr ds:[esi+eax*2+0xbbe90884],>
* 13812665 d9b4f3 90cccccc fstenv (28-byte) ptr ds:[ebx+esi*8+0xccc>
* 1381266c 77 0f ja short 1381267d
* 1381266e c705 a8aa1001 ac>mov dword ptr ds:[0x110aaa8],0x88446ac
* 13812678 -e9 87d9b4f3 jmp 07360004
* 1381267d 8b35 88a71001 mov esi,dword ptr ds:[0x110a788]
* 13812683 3b35 94a71001 cmp esi,dword ptr ds:[0x110a794]
* 13812689 0f85 16000000 jnz 138126a5
* 1381268f 832d c4aa1001 02 sub dword ptr ds:[0x110aac4],0x2
* 13812696 e9 d9000000 jmp 13812774
* 1381269b 01d8 add eax,ebx
* 1381269d 45 inc ebp
* 1381269e 8408 test byte ptr ds:[eax],cl
* 138126a0 -e9 7ed9b4f3 jmp 07360023
* 138126a5 832d c4aa1001 02 sub dword ptr ds:[0x110aac4],0x2
* 138126ac e9 0b000000 jmp 138126bc
* 138126b1 01b446 8408e968 add dword ptr ds:[esi+eax*2+0x68e90884],>
* 138126b8 d9b4f3 90770fc7 fstenv (28-byte) ptr ds:[ebx+esi*8+0xc70>
* 138126bf 05 a8aa1001 add eax,0x110aaa8
* 138126c4 b4 46 mov ah,0x46
* 138126c6 8408 test byte ptr ds:[eax],cl
* 138126c8 -e9 37d9b4f3 jmp 07360004
* 138126cd 8b35 88a71001 mov esi,dword ptr ds:[0x110a788]
* 138126d3 8d76 01 lea esi,dword ptr ds:[esi+0x1]
* 138126d6 813d 84a71001 00>cmp dword ptr ds:[0x110a784],0x0
* 138126e0 8935 88a71001 mov dword ptr ds:[0x110a788],esi
* 138126e6 0f84 16000000 je 13812702
* 138126ec 832d c4aa1001 02 sub dword ptr ds:[0x110aac4],0x2
* 138126f3 e9 24000000 jmp 1381271c
* 138126f8 018c46 8408e921 add dword ptr ds:[esi+eax*2+0x21e90884],>
* 138126ff d9b4f3 832dc4aa fstenv (28-byte) ptr ds:[ebx+esi*8+0xaac>
* 13812706 1001 adc byte ptr ds:[ecx],al
* 13812708 02c7 add al,bh
* 1381270a 05 a8aa1001 add eax,0x110aaa8
* 1381270f bc 468408e9 mov esp,0xe9088446
* 13812714 0bd9 or ebx,ecx
* 13812716 b4 f3 mov ah,0xf3
* 13812718 90 nop
* 13812719 cc int3
* 1381271a cc int3
* 1381271b cc int3
*
* This function is very similar to Imageepoch, and can have duplicate text
* 138d1486 cc int3
* 138d1487 cc int3
* 138d1488 77 0f ja short 138d1499
* 138d148a c705 a8aa1001 2c>mov dword ptr ds:[0x110aaa8],0x884452c
* 138d1494 -e9 6beba8f3 jmp 07360004
* 138d1499 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
* 138d149f 81e0 ffffff3f and eax,0x3fffffff
* 138d14a5 0fbeb0 00008007 movsx esi,byte ptr ds:[eax+0x7800000] ; jichi: hook here
* 138d14ac 8b3d 7ca71001 mov edi,dword ptr ds:[0x110a77c]
* 138d14b2 8d7f 01 lea edi,dword ptr ds:[edi+0x1]
* 138d14b5 8b05 74a71001 mov eax,dword ptr ds:[0x110a774]
* 138d14bb 81e0 ffffff3f and eax,0x3fffffff
* 138d14c1 8bd6 mov edx,esi
* 138d14c3 8890 00008007 mov byte ptr ds:[eax+0x7800000],dl
* 138d14c9 8b2d 74a71001 mov ebp,dword ptr ds:[0x110a774]
* 138d14cf 8d6d 01 lea ebp,dword ptr ss:[ebp+0x1]
* 138d14d2 81fe 00000000 cmp esi,0x0
* 138d14d8 8935 70a71001 mov dword ptr ds:[0x110a770],esi
* 138d14de 892d 74a71001 mov dword ptr ds:[0x110a774],ebp
* 138d14e4 893d 7ca71001 mov dword ptr ds:[0x110a77c],edi
* 138d14ea 0f85 16000000 jnz 138d1506
* 138d14f0 832d c4aa1001 05 sub dword ptr ds:[0x110aac4],0x5
* 138d14f7 e9 e8000000 jmp 138d15e4
* 138d14fc 015445 84 add dword ptr ss:[ebp+eax*2-0x7c],edx
* 138d1500 08e9 or cl,ch
* 138d1502 1d eba8f383 sbb eax,0x83f3a8eb
* 138d1507 2d c4aa1001 sub eax,0x110aac4
* 138d150c 05 e90e0000 add eax,0xee9
* 138d1511 0001 add byte ptr ds:[ecx],al
* 138d1513 40 inc eax
* 138d1514 45 inc ebp
* 138d1515 8408 test byte ptr ds:[eax],cl
* 138d1517 -e9 07eba8f3 jmp 07360023
* 138d151c 90 nop
* 138d151d cc int3
* 138d151e cc int3
* 138d151f cc int3
*/
//static void SpecialPSPHookYeti(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
//{
// //enum { base = 0x7400000 };
// DWORD eax = regof(eax, esp_base);
// LPCSTR text = LPCSTR(eax + hp->user_value);
// if (*text) {
// *data = (DWORD)text;
// *len = ::strlen(text); // SHIFT-JIS
// //*split = regof(ecx, esp_base); // ecx is bad that will split text threads
// //*split = FIXED_SPLIT_VALUE; // Similar to 5pb, it only has one thread?
// //*split = regof(ebx, esp_base); // value of ebx is splitting
// *split = FIXED_SPLIT_VALUE << 1; // * 2 to make it unique
// }
//}
bool InsertYetiPSPHook()
{
ConsoleOutput("Yeti PSP: enter");
const BYTE bytes[] = {
//0xcc, // 14e49edb cc int3
0x77, 0x0f, // 14e49edc 77 0f ja short 14e49eed
0xc7,0x05, XX8, // 14e49ede c705 a8aa1001 98>mov dword ptr ds:[0x110aaa8],0x885ff98
0xe9, XX4, // 14e49ee8 -e9 17619eee jmp 03830004
0x8b,0x35, XX4, // 14e49eed 8b35 70a71001 mov esi,dword ptr ds:[0x110a770]
0xc1,0xee, 0x1f, // 14e49ef3 c1ee 1f shr esi,0x1f
0x8b,0x05, XX4, // 14e49ef6 8b05 b4a71001 mov eax,dword ptr ds:[0x110a7b4]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 14e49efc 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xb8, XX4, // 14e49f02 8bb8 14deff07 mov edi,dword ptr ds:[eax+0x7ffde14]
0x03,0x35, XX4, // 14e49f08 0335 70a71001 add esi,dword ptr ds:[0x110a770]
0xd1,0xfe, // 14e49f0e d1fe sar esi,1
0x8b,0x05, XX4, // 14e49f10 8b05 b0a71001 mov eax,dword ptr ds:[0x110a7b0]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 14e49f16 81e0 ffffff3f and eax,0x3fffffff
0x89,0xb8, XX4, // 14e49f1c 89b8 00000008 mov dword ptr ds:[eax+0x8000000],edi
0x8b,0x05, XX4, // 14e49f22 8b05 dca71001 mov eax,dword ptr ds:[0x110a7dc]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 14e49f28 81e0 ffffff3f and eax,0x3fffffff
0x89,0xb0, XX4, // 14e49f2e 89b0 30000008 mov dword ptr ds:[eax+0x8000030],esi
0x8b,0x05, XX4, // 14e49f34 8b05 b4a71001 mov eax,dword ptr ds:[0x110a7b4]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 14e49f3a 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xa8, XX4, // 14e49f40 8ba8 14deff07 mov ebp,dword ptr ds:[eax+0x7ffde14]
0x8b,0xc5, // 14e49f46 8bc5 mov eax,ebp
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 14e49f48 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb6,0xb0 //, XX4, // 14e49f4e 0fb6b0 00000008 movzx esi,byte ptr ds:[eax+0x8000000] ; jichi: hook here
};
enum { memory_offset = 3 }; // 14e49f4e 0fb6b0 00000008 movzx esi,byte ptr ds:[eax+0x8000000]
enum { addr_offset = sizeof(bytes) - memory_offset };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("Yeti PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|USING_SPLIT|FIXING_SPLIT|NO_CONTEXT; // Fix the split value to merge all threads
hp.text_fun = SpecialPSPHook;
hp.offset=get_reg(regs::eax);
ConsoleOutput("Yeti PSP: INSERT");
succ|=NewHook(hp, "Yeti PSP");
}
ConsoleOutput("Yeti PSP: leave");
return succ;
}
/** 7/19/2014 jichi Alternative Yeti PSP engine, 0.9.8, 0.9.9
* Sample game: Never 7, 0.9.8 & 0.9.9
* Sample game: ひまわり
*
* Do not work on 0.9.9 Ever17 (7/27/2014)
*
*
* This hook does not work for 12River.
* However, sceFont functions work.
*
* Memory address is FIXED.
* Debug method: breakpoint the memory address
* There are two matched memory address to the current text
*
* There are several functions. The first one is used.
*
* The text also has 5pb-like garbage, but it is difficult to trim.
*
* PPSSPP 0.9.8:
*
* 14289802 cc int3
* 14289803 cc int3
* 14289804 77 0f ja short 14289815
* 14289806 c705 a8aa1001 58>mov dword ptr ds:[0x110aaa8],0x881ab58
* 14289810 -e9 ef6767ef jmp 03900004
* 14289815 8b35 74a71001 mov esi,dword ptr ds:[0x110a774]
* 1428981b 0335 78a71001 add esi,dword ptr ds:[0x110a778]
* 14289821 8b05 dca71001 mov eax,dword ptr ds:[0x110a7dc]
* 14289827 81e0 ffffff3f and eax,0x3fffffff
* 1428982d 8bb8 28004007 mov edi,dword ptr ds:[eax+0x7400028]
* 14289833 8bc6 mov eax,esi
* 14289835 81e0 ffffff3f and eax,0x3fffffff
* 1428983b 8bd7 mov edx,edi
* 1428983d 8890 10044007 mov byte ptr ds:[eax+0x7400410],dl
* 14289843 8b05 b0a71001 mov eax,dword ptr ds:[0x110a7b0]
* 14289849 81e0 ffffff3f and eax,0x3fffffff
* 1428984f 8bb8 84004007 mov edi,dword ptr ds:[eax+0x7400084]
* 14289855 8b05 aca71001 mov eax,dword ptr ds:[0x110a7ac]
* 1428985b 81e0 ffffff3f and eax,0x3fffffff
* 14289861 0fb6a8 00004007 movzx ebp,byte ptr ds:[eax+0x7400000] ; jichi: hook here
* 14289868 81ff 00000000 cmp edi,0x0
* 1428986e 8935 70a71001 mov dword ptr ds:[0x110a770],esi
* 14289874 893d 74a71001 mov dword ptr ds:[0x110a774],edi
* 1428987a 892d 78a71001 mov dword ptr ds:[0x110a778],ebp
* 14289880 0f85 16000000 jnz 1428989c
* 14289886 832d c4aa1001 06 sub dword ptr ds:[0x110aac4],0x6
* 1428988d c705 a8aa1001 ac>mov dword ptr ds:[0x110aaa8],0x881aeac
* 14289897 -e9 876767ef jmp 03900023
* 1428989c 832d c4aa1001 06 sub dword ptr ds:[0x110aac4],0x6
* 142898a3 e9 0c000000 jmp 142898b4
* 142898a8 0170 ab add dword ptr ds:[eax-0x55],esi
* 142898ab 8108 e9716767 or dword ptr ds:[eax],0x676771e9
* 142898b1 ef out dx,eax ; i/o command
* 142898b2 90 nop
*
* 142878ed cc int3
* 142878ee cc int3
* 142878ef cc int3
* 142878f0 77 0f ja short 14287901
* 142878f2 c705 a8aa1001 44>mov dword ptr ds:[0x110aaa8],0x8811e44
* 142878fc -e9 038767ef jmp 03900004
* 14287901 8b35 70a71001 mov esi,dword ptr ds:[0x110a770]
* 14287907 8b05 b0a71001 mov eax,dword ptr ds:[0x110a7b0]
* 1428790d 81e0 ffffff3f and eax,0x3fffffff
* 14287913 8bd6 mov edx,esi
* 14287915 8890 00004007 mov byte ptr ds:[eax+0x7400000],dl ; jichi: hook here
* 1428791b 8b05 a8a71001 mov eax,dword ptr ds:[0x110a7a8]
* 14287921 81e0 ffffff3f and eax,0x3fffffff
* 14287927 0fb6b8 00004007 movzx edi,byte ptr ds:[eax+0x7400000]
* 1428792e 8b2d aca71001 mov ebp,dword ptr ds:[0x110a7ac]
* 14287934 81c5 02000000 add ebp,0x2
* 1428793a 8bd5 mov edx,ebp
* 1428793c 8915 aca71001 mov dword ptr ds:[0x110a7ac],edx
* 14287942 8b05 b0a71001 mov eax,dword ptr ds:[0x110a7b0]
* 14287948 81e0 ffffff3f and eax,0x3fffffff
* 1428794e 8bd7 mov edx,edi
* 14287950 8890 01004007 mov byte ptr ds:[eax+0x7400001],dl
* 14287956 8b15 b0a71001 mov edx,dword ptr ds:[0x110a7b0]
* 1428795c 8d52 02 lea edx,dword ptr ds:[edx+0x2]
* 1428795f 893d 74a71001 mov dword ptr ds:[0x110a774],edi
* 14287965 892d a8a71001 mov dword ptr ds:[0x110a7a8],ebp
* 1428796b 8915 b0a71001 mov dword ptr ds:[0x110a7b0],edx
* 14287971 832d c4aa1001 07 sub dword ptr ds:[0x110aac4],0x7
* 14287978 e9 0b000000 jmp 14287988
* 1428797d 01a8 1d8108e9 add dword ptr ds:[eax+0xe908811d],ebp
* 14287983 9c pushfd
* 14287984 8667 ef xchg byte ptr ds:[edi-0x11],ah
* 14287987 90 nop
*
* 14289a2a 90 nop
* 14289a2b cc int3
* 14289a2c 77 0f ja short 14289a3d
* 14289a2e c705 a8aa1001 b4>mov dword ptr ds:[0x110aaa8],0x881abb4
* 14289a38 -e9 c76567ef jmp 03900004
* 14289a3d 8b05 dca71001 mov eax,dword ptr ds:[0x110a7dc]
* 14289a43 81e0 ffffff3f and eax,0x3fffffff
* 14289a49 8bb0 18004007 mov esi,dword ptr ds:[eax+0x7400018]
* 14289a4f 8b05 dca71001 mov eax,dword ptr ds:[0x110a7dc]
* 14289a55 81e0 ffffff3f and eax,0x3fffffff
* 14289a5b 8bb8 24004007 mov edi,dword ptr ds:[eax+0x7400024]
* 14289a61 8b2d 70a71001 mov ebp,dword ptr ds:[0x110a770]
* 14289a67 03ee add ebp,esi
* 14289a69 8b05 dca71001 mov eax,dword ptr ds:[0x110a7dc]
* 14289a6f 81e0 ffffff3f and eax,0x3fffffff
* 14289a75 8bb0 20004007 mov esi,dword ptr ds:[eax+0x7400020]
* 14289a7b 8bc5 mov eax,ebp
* 14289a7d 81e0 ffffff3f and eax,0x3fffffff
* 14289a83 66:89b8 c2034007 mov word ptr ds:[eax+0x74003c2],di
* 14289a8a 8bc5 mov eax,ebp
* 14289a8c 81e0 ffffff3f and eax,0x3fffffff
* 14289a92 66:89b0 c0034007 mov word ptr ds:[eax+0x74003c0],si
* 14289a99 8b05 aca71001 mov eax,dword ptr ds:[0x110a7ac]
* 14289a9f 81e0 ffffff3f and eax,0x3fffffff
* 14289aa5 0fb6b0 00004007 movzx esi,byte ptr ds:[eax+0x7400000] ; jichi: hook here
* 14289aac 81e6 ff000000 and esi,0xff
* 14289ab2 892d 70a71001 mov dword ptr ds:[0x110a770],ebp
* 14289ab8 893d 74a71001 mov dword ptr ds:[0x110a774],edi
* 14289abe 8935 78a71001 mov dword ptr ds:[0x110a778],esi
* 14289ac4 c705 e4a71001 d8>mov dword ptr ds:[0x110a7e4],0x881abd8
* 14289ace 832d c4aa1001 09 sub dword ptr ds:[0x110aac4],0x9
* 14289ad5 ^e9 d6c6f8ff jmp 142161b0
* 14289ada 90 nop
*
* 14289adb cc int3
* 14289adc 77 0f ja short 14289aed
* 14289ade c705 a8aa1001 d8>mov dword ptr ds:[0x110aaa8],0x881abd8
* 14289ae8 -e9 176567ef jmp 03900004
* 14289aed 813d 70a71001 00>cmp dword ptr ds:[0x110a770],0x0
* 14289af7 0f85 2f000000 jnz 14289b2c
* 14289afd 8b05 aca71001 mov eax,dword ptr ds:[0x110a7ac]
* 14289b03 81e0 ffffff3f and eax,0x3fffffff
* 14289b09 0fb6b0 00004007 movzx esi,byte ptr ds:[eax+0x7400000] ; jichi: hook here
* 14289b10 8935 70a71001 mov dword ptr ds:[0x110a770],esi
* 14289b16 832d c4aa1001 02 sub dword ptr ds:[0x110aac4],0x2
* 14289b1d e9 22000000 jmp 14289b44
* 14289b22 0110 add dword ptr ds:[eax],edx
* 14289b24 af scas dword ptr es:[edi]
* 14289b25 8108 e9f76467 or dword ptr ds:[eax],0x6764f7e9
* 14289b2b ef out dx,eax ; i/o command
* 14289b2c 832d c4aa1001 02 sub dword ptr ds:[0x110aac4],0x2
* 14289b33 c705 a8aa1001 e0>mov dword ptr ds:[0x110aaa8],0x881abe0
* 14289b3d -e9 e16467ef jmp 03900023
*
* PPSSPP 0.9.9 (7/27/2014)
*
* 0ed85942 cc int3
* 0ed85943 cc int3
* 0ed85944 77 0f ja short 0ed85955
* 0ed85946 c705 c84c1301 58>mov dword ptr ds:[0x1134cc8],0x881ab58
* 0ed85950 -e9 afa6aef4 jmp 03870004
* 0ed85955 8b35 94491301 mov esi,dword ptr ds:[0x1134994]
* 0ed8595b 0335 98491301 add esi,dword ptr ds:[0x1134998]
* 0ed85961 8b05 fc491301 mov eax,dword ptr ds:[0x11349fc]
* 0ed85967 81e0 ffffff3f and eax,0x3fffffff
* 0ed8596d 8bb8 28008009 mov edi,dword ptr ds:[eax+0x9800028]
* 0ed85973 8bc6 mov eax,esi
* 0ed85975 81e0 ffffff3f and eax,0x3fffffff
* 0ed8597b 8bd7 mov edx,edi
* 0ed8597d 8890 10048009 mov byte ptr ds:[eax+0x9800410],dl
* 0ed85983 8b05 d0491301 mov eax,dword ptr ds:[0x11349d0]
* 0ed85989 81e0 ffffff3f and eax,0x3fffffff
* 0ed8598f 8bb8 84008009 mov edi,dword ptr ds:[eax+0x9800084]
* 0ed85995 8b05 cc491301 mov eax,dword ptr ds:[0x11349cc]
* 0ed8599b 81e0 ffffff3f and eax,0x3fffffff
* 0ed859a1 0fb6a8 00008009 movzx ebp,byte ptr ds:[eax+0x9800000] ; jichi: hook here
* 0ed859a8 81ff 00000000 cmp edi,0x0
* 0ed859ae 8935 90491301 mov dword ptr ds:[0x1134990],esi
* 0ed859b4 893d 94491301 mov dword ptr ds:[0x1134994],edi
* 0ed859ba 892d 98491301 mov dword ptr ds:[0x1134998],ebp
* 0ed859c0 0f85 16000000 jnz 0ed859dc
* 0ed859c6 832d e44c1301 06 sub dword ptr ds:[0x1134ce4],0x6
* 0ed859cd c705 c84c1301 ac>mov dword ptr ds:[0x1134cc8],0x881aeac
* 0ed859d7 -e9 47a6aef4 jmp 03870023
* 0ed859dc 832d e44c1301 06 sub dword ptr ds:[0x1134ce4],0x6
* 0ed859e3 e9 0c000000 jmp 0ed859f4
* 0ed859e8 0170 ab add dword ptr ds:[eax-0x55],esi
* 0ed859eb 8108 e931a6ae or dword ptr ds:[eax],0xaea631e9
* 0ed859f1 f4 hlt ; privileged command
* 0ed859f2 90 nop
*/
// TODO: Is reverse_strlen a better choice?
static void SpecialPSPHookYeti2(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD eax = stack->eax;
LPCSTR text = LPCSTR(eax + hp->user_value);
if (BYTE c = *(BYTE *)text) {
*data = (DWORD)text;
//*len = text[1] ? 2 : 1;
*len = ::LeadByteTable[c];
*split = stack->edx;
//DWORD ecx = regof(ecx, esp_base);
//*split = ecx ? (FIXED_SPLIT_VALUE << 1) : 0; // << 1 to be unique, non-zero ecx is what I want
}
}
bool InsertYeti2PSPHook()
{
ConsoleOutput("Yeti2 PSP: enter");
const BYTE bytes[] = {
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 14289827 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xb8, XX4, // 1428982d 8bb8 28004007 mov edi,dword ptr ds:[eax+0x7400028]
0x8b,0xc6, // 14289833 8bc6 mov eax,esi
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 14289835 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xd7, // 1428983b 8bd7 mov edx,edi
0x88,0x90, XX4, // 1428983d 8890 10044007 mov byte ptr ds:[eax+0x7400410],dl
0x8b,0x05, XX4, // 14289843 8b05 b0a71001 mov eax,dword ptr ds:[0x110a7b0]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 14289849 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xb8, XX4, // 1428984f 8bb8 84004007 mov edi,dword ptr ds:[eax+0x7400084]
0x8b,0x05, XX4, // 14289855 8b05 aca71001 mov eax,dword ptr ds:[0x110a7ac]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1428985b 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb6,0xa8 //, XX4 // 14289861 0fb6a8 00004007 movzx ebp,byte ptr ds:[eax+0x7400000] ; jichi: hook here
// 14289b10 8935 70a71001 mov dword ptr ds:[0x110a770],esi
// 14289b16 832d c4aa1001 02 sub dword ptr ds:[0x110aac4],0x2
};
enum { memory_offset = 3 };
enum { addr_offset = sizeof(bytes) - memory_offset };
//enum { addr_offset = sizeof(bytes) + 4 }; // point to next statement after ebp is assigned
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("Yeti2 PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|NO_CONTEXT;
hp.text_fun = SpecialPSPHookYeti2;
ConsoleOutput("Yeti2 PSP: INSERT");
succ|=NewHook(hp, "Yeti2 PSP");
}
ConsoleOutput("Yeti2 PSP: leave");
return succ;
}
/** 7/22/2014 jichi: Nippon1 PSP engine, 0.9.8 only
* Sample game: ぁ<><EFBFBD>リンスさまっ♪ (0.9.8 only)
*
* Memory address is FIXED.
* Debug method: breakpoint the precomputed address
*
* The data is in (WORD)bp instead of eax.
* bp contains SHIFT-JIS CODEC_ANSI_BE data.
*
* There is only one text thread.
*
* 134e0553 cc int3
* 134e0554 77 0f ja short 134e0565
* 134e0556 c705 a8aa1001 34>mov dword ptr ds:[0x110aaa8],0x8853a34
* 134e0560 -e9 9ffa03f0 jmp 03520004
* 134e0565 8b35 74a71001 mov esi,dword ptr ds:[0x110a774]
* 134e056b d1e6 shl esi,1
* 134e056d c7c7 987db708 mov edi,0x8b77d98
* 134e0573 03fe add edi,esi
* 134e0575 8b2d 78a71001 mov ebp,dword ptr ds:[0x110a778]
* 134e057b 8bc7 mov eax,edi
* 134e057d 81e0 ffffff3f and eax,0x3fffffff
* 134e0583 66:89a8 00004007 mov word ptr ds:[eax+0x7400000],bp ; jichi: hook here
* 134e058a 8b2d 8c7df70f mov ebp,dword ptr ds:[0xff77d8c]
* 134e0590 8d6d 01 lea ebp,dword ptr ss:[ebp+0x1]
* 134e0593 892d 8c7df70f mov dword ptr ds:[0xff77d8c],ebp
* 134e0599 8b05 e4a71001 mov eax,dword ptr ds:[0x110a7e4]
* 134e059f c705 74a71001 00>mov dword ptr ds:[0x110a774],0x8b70000
* 134e05a9 892d 78a71001 mov dword ptr ds:[0x110a778],ebp
* 134e05af 8935 7ca71001 mov dword ptr ds:[0x110a77c],esi
* 134e05b5 8905 a8aa1001 mov dword ptr ds:[0x110aaa8],eax
* 134e05bb 832d c4aa1001 0c sub dword ptr ds:[0x110aac4],0xc
* 134e05c2 -e9 5cfa03f0 jmp 03520023
*/
// Read text from bp
// TODO: This should be expressed as general hook without extern fun
static void SpecialPSPHookNippon1(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
LPCSTR text = LPCSTR(stack->base + hp->offset); // dynamic offset, ebp or esi
if (*text) {
*data = (DWORD)text;
*len = !text[0] ? 0 : !text[1] ? 1 : 2; // bp or si has at most two bytes
//*len = ::LeadByteTable[*(BYTE *)text] // TODO: Test leadbytetable
*split = stack->ecx;
}
}
bool InsertNippon1PSPHook()
{
ConsoleOutput("Nippon1 PSP: enter");
const BYTE bytes[] = {
//0xcc, // 134e0553 cc int3
0x77, 0x0f, // 134e0554 77 0f ja short 134e0565
0xc7,0x05, XX8, // 134e0556 c705 a8aa1001 34>mov dword ptr ds:[0x110aaa8],0x8853a34
0xe9, XX4, // 134e0560 -e9 9ffa03f0 jmp 03520004
0x8b,0x35, XX4, // 134e0565 8b35 74a71001 mov esi,dword ptr ds:[0x110a774]
0xd1,0xe6, // 134e056b d1e6 shl esi,1
0xc7,0xc7, XX4, // 134e056d c7c7 987db708 mov edi,0x8b77d98
0x03,0xfe, // 134e0573 03fe add edi,esi
0x8b,0x2d, XX4, // 134e0575 8b2d 78a71001 mov ebp,dword ptr ds:[0x110a778]
0x8b,0xc7, // 134e057b 8bc7 mov eax,edi
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 134e057d 81e0 ffffff3f and eax,0x3fffffff
0x66,0x89,0xa8, XX4, // 134e0583 66:89a8 00004007 mov word ptr ds:[eax+0x7400000],bp ; jichi: hook here
0x8b,0x2d, XX4, // 134e058a 8b2d 8c7df70f mov ebp,dword ptr ds:[0xff77d8c]
0x8d,0x6d, 0x01 // 134e0590 8d6d 01 lea ebp,dword ptr ss:[ebp+0x1]
};
enum { memory_offset = 3 };
enum { addr_offset = 0x134e0583 - 0x134e0554 };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("Nippon1 PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.offset=get_reg(regs::ebp);
hp.type = USING_STRING|NO_CONTEXT;
hp.text_fun = SpecialPSPHookNippon1;
ConsoleOutput("Nippon1 PSP: INSERT");
succ|=NewHook(hp, "Nippon1 PSP");
}
ConsoleOutput("Nippon1 PSP: leave");
return succ;
}
/** 7/26/2014 jichi: Alternative Nippon1 PSP engine, 0.9.8 only
* Sample game: 神<>悪戯 (0.9.8 only)
* Issue: character name cannot be extracted
*
* Memory address is FIXED.
* Debug method: breakpoint the precomputed address
*
* This function is the one that write the text into the memory.
*
* 13d13e8b 0f92c0 setb al
* 13d13e8e 8bf8 mov edi,eax
* 13d13e90 81ff 00000000 cmp edi,0x0
* 13d13e96 893d 78a71001 mov dword ptr ds:[0x110a778],edi
* 13d13e9c 8935 dca71001 mov dword ptr ds:[0x110a7dc],esi
* 13d13ea2 0f85 16000000 jnz 13d13ebe
* 13d13ea8 832d c4aa1001 0a sub dword ptr ds:[0x110aac4],0xa
* 13d13eaf c705 a8aa1001 cc>mov dword ptr ds:[0x110aaa8],0x887c2cc
* 13d13eb9 -e9 65c1a3ef jmp 03750023
* 13d13ebe 832d c4aa1001 0a sub dword ptr ds:[0x110aac4],0xa
* 13d13ec5 e9 0e000000 jmp 13d13ed8
* 13d13eca 01a8 c28708e9 add dword ptr ds:[eax+0xe90887c2],ebp
* 13d13ed0 4f dec edi
* 13d13ed1 c1a3 ef90cccc cc shl dword ptr ds:[ebx+0xcccc90ef],0xcc ; shift constant out of range 1..31
* 13d13ed8 77 0f ja short 13d13ee9
* 13d13eda c705 a8aa1001 a8>mov dword ptr ds:[0x110aaa8],0x887c2a8
* 13d13ee4 -e9 1bc1a3ef jmp 03750004
* 13d13ee9 8b05 dca71001 mov eax,dword ptr ds:[0x110a7dc]
* 13d13eef 81e0 ffffff3f and eax,0x3fffffff
* 13d13ef5 0fb7b0 0000c007 movzx esi,word ptr ds:[eax+0x7c00000]
* 13d13efc 8b3d fccd5a10 mov edi,dword ptr ds:[0x105acdfc]
* 13d13f02 8bef mov ebp,edi
* 13d13f04 d1e5 shl ebp,1
* 13d13f06 81c5 e8cd9a08 add ebp,0x89acde8
* 13d13f0c 8bc5 mov eax,ebp
* 13d13f0e 81e0 ffffff3f and eax,0x3fffffff
* 13d13f14 66:89b0 2000c007 mov word ptr ds:[eax+0x7c00020],si ; jichi: hook here
* 13d13f1b 8d7f 01 lea edi,dword ptr ds:[edi+0x1]
* 13d13f1e 893d fccd5a10 mov dword ptr ds:[0x105acdfc],edi
* 13d13f24 8b15 dca71001 mov edx,dword ptr ds:[0x110a7dc]
* 13d13f2a 8d52 10 lea edx,dword ptr ds:[edx+0x10]
* 13d13f2d 8b05 e4a71001 mov eax,dword ptr ds:[0x110a7e4]
* 13d13f33 893d 78a71001 mov dword ptr ds:[0x110a778],edi
* 13d13f39 c705 7ca71001 e8>mov dword ptr ds:[0x110a77c],0x89acde8
* 13d13f43 8935 80a71001 mov dword ptr ds:[0x110a780],esi
* 13d13f49 892d 84a71001 mov dword ptr ds:[0x110a784],ebp
* 13d13f4f 8915 dca71001 mov dword ptr ds:[0x110a7dc],edx
* 13d13f55 8905 a8aa1001 mov dword ptr ds:[0x110aaa8],eax
* 13d13f5b 832d c4aa1001 0b sub dword ptr ds:[0x110aac4],0xb
* 13d13f62 -e9 bcc0a3ef jmp 03750023
* 13d13f67 90 nop
*/
// 8/13/2014: 5pb might crash on 0.9.9.
bool InsertNippon2PSPHook()
{
ConsoleOutput("Nippon2 PSP: enter");
const BYTE bytes[] = {
0xe9, XX4, // 13d13ee4 -e9 1bc1a3ef jmp 03750004
0x8b,0x05, XX4, // 13d13ee9 8b05 dca71001 mov eax,dword ptr ds:[0x110a7dc]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13d13eef 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb7,0xb0, XX4, // 13d13ef5 0fb7b0 0000c007 movzx esi,word ptr ds:[eax+0x7c00000]
0x8b,0x3d, XX4, // 13d13efc 8b3d fccd5a10 mov edi,dword ptr ds:[0x105acdfc]
0x8b,0xef, // 13d13f02 8bef mov ebp,edi
0xd1,0xe5, // 13d13f04 d1e5 shl ebp,1
0x81,0xc5, XX4, // 13d13f06 81c5 e8cd9a08 add ebp,0x89acde8
0x8b,0xc5, // 13d13f0c 8bc5 mov eax,ebp
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13d13f0e 81e0 ffffff3f and eax,0x3fffffff
0x66,0x89,0xb0 //, XX4 // 13d13f14 66:89b0 2000c007 mov word ptr ds:[eax+0x7c00020],si ; jichi: hook here
};
enum { memory_offset = 3 };
enum { addr_offset = sizeof(bytes) - memory_offset };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("Nippon2 PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.offset=get_reg(regs::esi);
hp.type = USING_STRING|NO_CONTEXT;
hp.text_fun = SpecialPSPHookNippon1;
ConsoleOutput("Nippon2 PSP: INSERT");
succ|=NewHook(hp, "Nippon2 PSP");
}
ConsoleOutput("Nippon2 PSP: leave");
return succ;
}
#if 0 // 8/9/2014 jichi: cannot find a good function
/** 8/9/2014 jichi Typemoon.com PSP engine, 0.9.8, 0.9.9,
*
* Sample game: Fate CCC
* This game is made by both TYPE-MOON and Imageepoch
* But the encoding is SHIFT-JIS than UTF-8 like other Imageepoch games.
* Otomate hook will produce significant amount of garbage.
*
* Memory address is FIXED.
* There are two matches in the memory.
*
* Debug method: breakpoint the memory address
* The hooked functions were looping which made it difficult to debug.
*
* Two looped functions are as follows. The first one is used
* The second function is tested as bad.
*
* Registers: (all of them are fixed except eax)
* EAX 08C91373
* ECX 00000016
* EDX 00000012
* EBX 0027A580
* ESP 0353E6D0
* EBP 0000000B
* ESI 0000001E
* EDI 00000001
* EIP 1351E14D
*
* 1351e12d f0:90 lock nop ; lock prefix is not allowed
* 1351e12f cc int3
* 1351e130 77 0f ja short 1351e141
* 1351e132 c705 a8aa1001 b8>mov dword ptr ds:[0x110aaa8],0x88ed7b8
* 1351e13c -e9 c31e27f0 jmp 03790004
* 1351e141 8b05 aca71001 mov eax,dword ptr ds:[0x110a7ac]
* 1351e147 81e0 ffffff3f and eax,0x3fffffff
* 1351e14d 0fbeb0 01004007 movsx esi,byte ptr ds:[eax+0x7400001] ; or jichi: hook here
* 1351e154 8b05 dca71001 mov eax,dword ptr ds:[0x110a7dc]
* 1351e15a 81e0 ffffff3f and eax,0x3fffffff
* 1351e160 8bb8 50004007 mov edi,dword ptr ds:[eax+0x7400050]
* 1351e166 81e6 ff000000 and esi,0xff
* 1351e16c 8bc6 mov eax,esi
* 1351e16e 8b35 a8a71001 mov esi,dword ptr ds:[0x110a7a8]
* 1351e174 0bf0 or esi,eax
* 1351e176 c1e6 10 shl esi,0x10
* 1351e179 c1fe 10 sar esi,0x10
* 1351e17c 893d 78a71001 mov dword ptr ds:[0x110a778],edi
* 1351e182 8935 7ca71001 mov dword ptr ds:[0x110a77c],esi
* 1351e188 c705 e4a71001 d4>mov dword ptr ds:[0x110a7e4],0x88ed7d4
* 1351e192 832d c4aa1001 07 sub dword ptr ds:[0x110aac4],0x7
* 1351e199 e9 0e000000 jmp 1351e1ac
* 1351e19e 01ac3e 8e08e97b add dword ptr ds:[esi+edi+0x7be9088e],eb>
* 1351e1a5 1e push ds
* 1351e1a6 27 daa
* 1351e1a7 f0:90 lock nop ; lock prefix is not allowed
* 1351e1a9 cc int3
*
* 13513f23 cc int3
* 13513f24 77 0f ja short 13513f35
* 13513f26 c705 a8aa1001 d4>mov dword ptr ds:[0x110aaa8],0x88e7bd4
* 13513f30 -e9 cfc027f0 jmp 03790004
* 13513f35 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
* 13513f3b 81e0 ffffff3f and eax,0x3fffffff
* 13513f41 0fbeb0 00004007 movsx esi,byte ptr ds:[eax+0x7400000]
* 13513f48 8b3d 84a71001 mov edi,dword ptr ds:[0x110a784]
* 13513f4e 8d7f 01 lea edi,dword ptr ds:[edi+0x1]
* 13513f51 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
* 13513f57 81e0 ffffff3f and eax,0x3fffffff
* 13513f5d 8bd6 mov edx,esi
* 13513f5f 8890 00004007 mov byte ptr ds:[eax+0x7400000],dl ; jichi: bad hook
* 13513f65 8b2d 78a71001 mov ebp,dword ptr ds:[0x110a778]
* 13513f6b 8d6d 01 lea ebp,dword ptr ss:[ebp+0x1]
* 13513f6e 33c0 xor eax,eax
* 13513f70 3b3d 80a71001 cmp edi,dword ptr ds:[0x110a780]
* 13513f76 0f9cc0 setl al
* 13513f79 8bf0 mov esi,eax
* 13513f7b 8b15 7ca71001 mov edx,dword ptr ds:[0x110a77c]
* 13513f81 8d52 01 lea edx,dword ptr ds:[edx+0x1]
* 13513f84 81fe 00000000 cmp esi,0x0
* 13513f8a 892d 78a71001 mov dword ptr ds:[0x110a778],ebp
* 13513f90 8915 7ca71001 mov dword ptr ds:[0x110a77c],edx
* 13513f96 893d 84a71001 mov dword ptr ds:[0x110a784],edi
* 13513f9c 8935 88a71001 mov dword ptr ds:[0x110a788],esi
* 13513fa2 0f84 16000000 je 13513fbe
* 13513fa8 832d c4aa1001 07 sub dword ptr ds:[0x110aac4],0x7
* 13513faf ^e9 70ffffff jmp 13513f24
* 13513fb4 01d4 add esp,edx
* 13513fb6 7b 8e jpo short 13513f46
* 13513fb8 08e9 or cl,ch
* 13513fba 65:c027 f0 shl byte ptr gs:[edi],0xf0 ; shift constant out of range 1..31
* 13513fbe 832d c4aa1001 07 sub dword ptr ds:[0x110aac4],0x7
* 13513fc5 e9 0e000000 jmp 13513fd8
* 13513fca 01f0 add eax,esi
* 13513fcc 7b 8e jpo short 13513f5c
* 13513fce 08e9 or cl,ch
* 13513fd0 4f dec edi
* 13513fd1 c027 f0 shl byte ptr ds:[edi],0xf0 ; shift constant out of range 1..31
* 13513fd4 90 nop
* 13513fd5 cc int3
* 13513fd6 cc int3
*/
// Read text from dl
static void SpecialPSPHookTypeMoon(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD eax = regof(eax, esp_base);
DWORD text = eax + hp->user_value - 1; // the text is in the previous byte
if (BYTE c = *(BYTE *)text) { // unsigned char
*data = text;
*len = ::LeadByteTable[c]; // 1 or 2
//*split = regof(ecx, esp_base);
//*split = regof(edx, esp_base);
*split = regof(ebx, esp_base);
}
}
bool InsertTypeMoonPSPHook()
{
ConsoleOutput("TypeMoon PSP: enter");
const BYTE bytes[] = {
0x77, 0x0f, // 1351e130 77 0f ja short 1351e141
0xc7,0x05, XX8, // 1351e132 c705 a8aa1001 b8>mov dword ptr ds:[0x110aaa8],0x88ed7b8
0xe9, XX4, // 1351e13c -e9 c31e27f0 jmp 03790004
0x8b,0x05, XX4, // 1351e141 8b05 aca71001 mov eax,dword ptr ds:[0x110a7ac]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1351e147 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xbe,0xb0, XX4, // 1351e14d 0fbeb0 01004007 movsx esi,byte ptr ds:[eax+0x7400001] ; jichi: hook here
0x8b,0x05, XX4, // 1351e154 8b05 dca71001 mov eax,dword ptr ds:[0x110a7dc]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1351e15a 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xb8, XX4, // 1351e160 8bb8 50004007 mov edi,dword ptr ds:[eax+0x7400050]
0x81,0xe6, 0xff,0x00,0x00,0x00, // 1351e166 81e6 ff000000 and esi,0xff
0x8b,0xc6, // 1351e16c 8bc6 mov eax,esi
0x8b,0x35, XX4, // 1351e16e 8b35 a8a71001 mov esi,dword ptr ds:[0x110a7a8]
0x0b,0xf0, // 1351e174 0bf0 or esi,eax
0xc1,0xe6, 0x10, // 1351e176 c1e6 10 shl esi,0x10
0xc1,0xfe, 0x10 // 1351e179 c1fe 10 sar esi,0x10
};
enum { memory_offset = 3 };
enum { addr_offset = 0x1351e14d - 0x1351e130 };
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("TypeMoon PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|NO_CONTEXT;
hp.text_fun = SpecialPSPHookTypeMoon;
ConsoleOutput("TypeMoon PSP: INSERT");
NewHook(hp, "TypeMoon PSP");
}
ConsoleOutput("TypeMoon PSP: leave");
return addr;
}
#endif // 0
#if 0 // 7/25/2014: This function is not invoked? Why?
/** 7/22/2014 jichi: KOEI TECMO PSP, 0.9.8
* Sample game: 金色のコルダ3
*
* 134598e2 cc int3
* 134598e3 cc int3
* 134598e4 77 0f ja short 134598f5
* 134598e6 c705 a8aa1001 8c>mov dword ptr ds:[0x110aaa8],0x880f08c
* 134598f0 -e9 0f67fbef jmp 03410004
* 134598f5 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
* 134598fb 81e0 ffffff3f and eax,0x3fffffff
* 13459901 8bb0 00004007 mov esi,dword ptr ds:[eax+0x7400000] ; jichi: hook here
* 13459907 8b3d 7ca71001 mov edi,dword ptr ds:[0x110a77c]
* 1345990d 8d7f 04 lea edi,dword ptr ds:[edi+0x4]
* 13459910 8b05 84a71001 mov eax,dword ptr ds:[0x110a784]
* 13459916 81e0 ffffff3f and eax,0x3fffffff
* 1345991c 89b0 00004007 mov dword ptr ds:[eax+0x7400000],esi
* 13459922 8b2d 84a71001 mov ebp,dword ptr ds:[0x110a784]
* 13459928 8d6d 04 lea ebp,dword ptr ss:[ebp+0x4]
* 1345992b 8b15 78a71001 mov edx,dword ptr ds:[0x110a778]
* 13459931 81fa 01000000 cmp edx,0x1
* 13459937 8935 70a71001 mov dword ptr ds:[0x110a770],esi
* 1345993d 893d 7ca71001 mov dword ptr ds:[0x110a77c],edi
* 13459943 892d 84a71001 mov dword ptr ds:[0x110a784],ebp
* 13459949 c705 88a71001 01>mov dword ptr ds:[0x110a788],0x1
* 13459953 0f84 16000000 je 1345996f
* 13459959 832d c4aa1001 09 sub dword ptr ds:[0x110aac4],0x9
* 13459960 e9 17000000 jmp 1345997c
* 13459965 0190 f08008e9 add dword ptr ds:[eax+0xe90880f0],edx
* 1345996b b4 66 mov ah,0x66
* 1345996d fb sti
* 1345996e ef out dx,eax ; i/o command
* 1345996f 832d c4aa1001 09 sub dword ptr ds:[0x110aac4],0x9
* 13459976 ^e9 ddc1ffff jmp 13455b58
* 1345997b 90 nop
*/
bool InsertTecmoPSPHook()
{
ConsoleOutput("Tecmo PSP: enter");
const BYTE bytes[] = {
0x77, 0x0f, // 134598e4 77 0f ja short 134598f5
0xc7,0x05, XX8, // 134598e6 c705 a8aa1001 8c>mov dword ptr ds:[0x110aaa8],0x880f08c
0xe9, XX4, // 134598f0 -e9 0f67fbef jmp 03410004
0x8b,0x05, XX4, // 134598f5 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 134598fb 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xb0, XX4, // 13459901 8bb0 00004007 mov esi,dword ptr ds:[eax+0x7400000] ; jichi: hook here
0x8b,0x3d, XX4, // 13459907 8b3d 7ca71001 mov edi,dword ptr ds:[0x110a77c]
0x8d,0x7f, 0x04, // 1345990d 8d7f 04 lea edi,dword ptr ds:[edi+0x4]
0x8b,0x05, XX4, // 13459910 8b05 84a71001 mov eax,dword ptr ds:[0x110a784]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13459916 81e0 ffffff3f and eax,0x3fffffff
0x89,0xb0 //, XX4, // 1345991c 89b0 00004007 mov dword ptr ds:[eax+0x7400000],esi
//0x8b,0x2d, XX4, // 13459922 8b2d 84a71001 mov ebp,dword ptr ds:[0x110a784]
//0x8d,0x6d, 0x04, // 13459928 8d6d 04 lea ebp,dword ptr ss:[ebp+0x4]
//0x8b,0x15, XX4, // 1345992b 8b15 78a71001 mov edx,dword ptr ds:[0x110a778]
//0x81,0xfa, 0x01,0x00,0x00,0x00 // 13459931 81fa 01000000 cmp edx,0x1
};
enum { memory_offset = 2 };
enum { addr_offset = 0x13459901 - 0x134598e4 };
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("Tecmo PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|USING_SPLIT|NO_CONTEXT;
hp.offset=get_reg(regs::eax);
hp.split = get_reg(regs::ecx);
hp.text_fun = SpecialPSPHook;
ConsoleOutput("Tecmo PSP: INSERT");
NewHook(hp, "Tecmo PSP");
}
ConsoleOutput("Tecmo PSP: leave");
return addr;
}
#endif // 0
#if 0 // 8/9/2014 jichi: does not work
bool InsertKadokawaPSPHook()
{
ConsoleOutput("Kadokawa PSP: enter");
const BYTE bytes[] = {
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 134844f3 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb6,0xb0, XX4, // 134844f9 0fb6b0 00004007 movzx esi,byte ptr ds:[eax+0x7400000] ; jichi: hook here, byte by byte
0x8b,0x05, XX4, // 13484500 8b05 84a71001 mov eax,dword ptr ds:[0x110a784]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 13484506 81e0 ffffff3f and eax,0x3fffffff
0x8b,0xd6, // 1348450c 8bd6 mov edx,esi
0x88,0x90, XX4, // 1348450e 8890 00004007 mov byte ptr ds:[eax+0x7400000],dl
0x8b,0x3d, XX4, // 13484514 8b3d 84a71001 mov edi,dword ptr ds:[0x110a784]
0x8d,0x7f, 0x01, // 1348451a 8d7f 01 lea edi,dword ptr ds:[edi+0x1]
0x8b,0x2d, XX4, // 1348451d 8b2d 7ca71001 mov ebp,dword ptr ds:[0x110a77c]
0x8d,0x6d, 0x01, // 13484523 8d6d 01 lea ebp,dword ptr ss:[ebp+0x1]
0x3b,0x3d, XX4, // 13484526 3b3d 74a71001 cmp edi,dword ptr ds:[0x110a774]
0x89,0x35, XX4, // 1348452c 8935 70a71001 mov dword ptr ds:[0x110a770],esi
0x89,0x2d, XX4, // 13484532 892d 7ca71001 mov dword ptr ds:[0x110a77c],ebp
0x89,0x3d, XX4, // 13484538 893d 84a71001 mov dword ptr ds:[0x110a784],edi
// Above is not sufficient
//0x0f,0x84, XX4, // 1348453e 0f84 16000000 je 1348455a
//0x83,0x2d, XX4, 0x05, // 13484544 832d c4aa1001 05 sub dword ptr ds:[0x110aac4],0x5
//0xe9, XX4, // 1348454b ^e9 8cffffff jmp 134844dc
//0x01,0x38, // 13484550 0138 add dword ptr ds:[eax],edi
//0xb0, 0x84, // 13484552 b0 84 mov al,0x84
//0x08,0xe9 // 13484554 08e9 or cl,ch
// Below will change at runtime
};
enum { memory_offset = 3 };
enum { addr_offset = 0x134844f9 - 0x134844f3 };
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr) {
ConsoleOutput("Kadokawa PSP: pattern not found");
return false;
}
addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes), addr);
addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes), addr);
if (!addr)
ConsoleOutput("Kadokawa PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|USING_SPLIT|NO_CONTEXT;
hp.offset=get_reg(regs::eax);
hp.split = get_reg(regs::ecx);
hp.length_offset = 1; // byte by byte
hp.text_fun = SpecialPSPHook;
//GROWL_DWORD2(hp.address, hp.user_value);
ConsoleOutput("Kadokawa PSP: INSERT");
NewHook(hp, "Kadokawa PSP");
}
ConsoleOutput("Kadokawa PSP: leave");
return addr;
}
#endif // 0
#if 0 // FIXME: I am not able to find stable pattern in PSP 0.9.9.1
/** 9/21/2014 jichi Otomate PPSSPP 0.9.9.1
* Sample game: Amnesia Later
*
* There are four fixed memory addresses.
* The two out of four can be used.
* (The other twos have loops or cannot be debugged).
*
* This function is the same as PPSSPP 0.9.9.1 (?).
*
* 14039126 cc int3
* 14039127 cc int3
* 14039128 77 0f ja short 14039139
* 1403912a c705 988e1301 3c>mov dword ptr ds:[0x1138e98],0x8922c3c
* 14039134 -e9 cb6e83ef jmp 03870004
* 14039139 8b05 688b1301 mov eax,dword ptr ds:[0x1138b68]
* 1403913f 81e0 ffffff3f and eax,0x3fffffff
* 14039145 0fbeb0 00000008 movsx esi,byte ptr ds:[eax+0x8000000] ; jichi: text accessed, but looped
* 1403914c 8b05 6c8b1301 mov eax,dword ptr ds:[0x1138b6c]
* 14039152 81e0 ffffff3f and eax,0x3fffffff
* 14039158 0fbeb8 00000008 movsx edi,byte ptr ds:[eax+0x8000000]
* 1403915f 3bf7 cmp esi,edi
* 14039161 8935 748b1301 mov dword ptr ds:[0x1138b74],esi
* 14039167 893d 7c8b1301 mov dword ptr ds:[0x1138b7c],edi
* 1403916d 0f84 2f000000 je 140391a2
* 14039173 8b05 688b1301 mov eax,dword ptr ds:[0x1138b68]
* 14039179 81e0 ffffff3f and eax,0x3fffffff
* 1403917f 0fb6b0 00000008 movzx esi,byte ptr ds:[eax+0x8000000] ; jichi: hook here
* 14039186 8935 608b1301 mov dword ptr ds:[0x1138b60],esi
* 1403918c 832d b48e1301 04 sub dword ptr ds:[0x1138eb4],0x4
* 14039193 e9 24000000 jmp 140391bc
* 14039198 0170 2c add dword ptr ds:[eax+0x2c],esi
* 1403919b 92 xchg eax,edx
* 1403919c 08e9 or cl,ch
* 1403919e 816e 83 ef832db4 sub dword ptr ds:[esi-0x7d],0xb42d83ef
* 140391a5 8e13 mov ss,word ptr ds:[ebx] ; modification of segment register
* 140391a7 0104e9 add dword ptr ds:[ecx+ebp*8],eax
* 140391aa b2 59 mov dl,0x59
* 140391ac 0000 add byte ptr ds:[eax],al
* 140391ae 014c2c 92 add dword ptr ss:[esp+ebp-0x6e],ecx
* 140391b2 08e9 or cl,ch
* 140391b4 6b6e 83 ef imul ebp,dword ptr ds:[esi-0x7d],-0x11
* 140391b8 90 nop
* 140391b9 cc int3
* 140391ba cc int3
*/
// Get bytes in esi
static void SpecialPSPHookOtomate2(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
//static uniquemap uniq;
DWORD text = esp_base + get_reg(regs::esi);
if (*(LPCSTR *)text) {
*split = regof(ecx, esp_base); // this would cause lots of texts, but it works for all games
*data = text;
*len = 1;
}
}
bool InsertOtomate2PSPHook()
{
ConsoleOutput("Otomate2 PSP: enter");
const BYTE bytes[] = {
0x77, 0x0f, // 14039128 77 0f ja short 14039139
0xc7,0x05, XX8, // 1403912a c705 988e1301 3c>mov dword ptr ds:[0x1138e98],0x8922c3c
0xe9, XX4, // 14039134 -e9 cb6e83ef jmp 03870004
0x8b,0x05, XX4, // 14039139 8b05 688b1301 mov eax,dword ptr ds:[0x1138b68]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1403913f 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xbe,0xb0, XX4, // 14039145 0fbeb0 00000008 movsx esi,byte ptr ds:[eax+0x8000000] ; jichi: text accessed, but looped
0x8b,0x05, XX4, // 1403914c 8b05 6c8b1301 mov eax,dword ptr ds:[0x1138b6c]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 14039152 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xbe,0xb8, XX4, // 14039158 0fbeb8 00000008 movsx edi,byte ptr ds:[eax+0x8000000]
0x3b,0xf7, // 1403915f 3bf7 cmp esi,edi
0x89,0x35, XX4, // 14039161 8935 748b1301 mov dword ptr ds:[0x1138b74],esi
0x89,0x3d, XX4, // 14039167 893d 7c8b1301 mov dword ptr ds:[0x1138b7c],edi
0x0f,0x84, 0x2f,0x00,0x00,0x00, // 1403916d 0f84 2f000000 je 140391a2
//0x8b,0x05, XX4, // 14039173 8b05 688b1301 mov eax,dword ptr ds:[0x1138b68]
//0x81,0xe0, 0xff,0xff,0xff,0x3f, // 14039179 81e0 ffffff3f and eax,0x3fffffff
//0x0f,0xb6,0xb0, XX4, // 1403917f 0fb6b0 00000008 movzx esi,byte ptr ds:[eax+0x8000000] ; jichi: text accessed
//0x89,0x35, XX4, // 14039186 8935 608b1301 mov dword ptr ds:[0x1138b60],esi ; jichi: hook here, get lower bytes in esi
//0x83,0x2d, XX4, 0x04 // 1403918c 832d b48e1301 04 sub dword ptr ds:[0x1138eb4],0x4
};
enum { addr_offset = 0x14039186 - 0x14039128 };
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr) {
ConsoleOutput("Otomate2 PSP: leave: first pattern not found");
return false;
}
addr += addr_offset;
//0x89,0x35, XX4, // 14039186 8935 608b1301 mov dword ptr ds:[0x1138b60],esi ; jichi: hook here, get lower bytes in esi
enum : WORD { mov_esi = 0x3589 };
if (*(WORD *)addr != mov_esi) {
ConsoleOutput("Otomate2 PSP: leave: second pattern not found");
return false;
}
HookParam hp;
hp.address = addr;
hp.type = USING_STRING|NO_CONTEXT;
hp.text_fun = SpecialPSPHookOtomate2;
ConsoleOutput("Otomate2 PSP: INSERT");
NewHook(hp, "Otomate PSP");
ConsoleOutput("Otomate2 PSP: leave");
return addr;
}
#endif // 0
/** 8/9/2014 jichi Kadokawa.co.jp PSP engine, 0.9.8, ?,
*
* Sample game: 未来日<E69DA5>work on 0.9.8, not tested on 0.9.9
*
* FIXME: Currently, only the character name works
*
* Memory address is FIXED.
* Debug method: predict and breakpoint the memory address
*
* There are two matches in the memory, and only one function accessing them.
*
* Character name function is as follows.
* The scenario is the text after the name.
*
* 1348d79f cc int3
* 1348d7a0 77 0f ja short 1348d7b1
* 1348d7a2 c705 a8aa1001 fc>mov dword ptr ds:[0x110aaa8],0x884c6fc
* 1348d7ac -e9 532844f0 jmp 038d0004
* 1348d7b1 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
* 1348d7b7 81e0 ffffff3f and eax,0x3fffffff
* 1348d7bd 0fb6b0 00004007 movzx esi,byte ptr ds:[eax+0x7400000] ; jichi: hook here
* 1348d7c4 81fe 00000000 cmp esi,0x0
* 1348d7ca 8935 70a71001 mov dword ptr ds:[0x110a770],esi
* 1348d7d0 0f85 2f000000 jnz 1348d805
* 1348d7d6 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
* 1348d7dc 81e0 ffffff3f and eax,0x3fffffff
* 1348d7e2 0fbeb0 00004007 movsx esi,byte ptr ds:[eax+0x7400000]
* 1348d7e9 8935 70a71001 mov dword ptr ds:[0x110a770],esi
* 1348d7ef 832d c4aa1001 03 sub dword ptr ds:[0x110aac4],0x3
* 1348d7f6 c705 a8aa1001 5c>mov dword ptr ds:[0x110aaa8],0x884c75c
* 1348d800 -e9 1e2844f0 jmp 038d0023
* 1348d805 832d c4aa1001 03 sub dword ptr ds:[0x110aac4],0x3
* 1348d80c e9 0b000000 jmp 1348d81c
* 1348d811 0108 add dword ptr ds:[eax],ecx
* 1348d813 c78408 e9082844 >mov dword ptr ds:[eax+ecx+0x442808e9],0x>
* 1348d81e c705 a8aa1001 08>mov dword ptr ds:[0x110aaa8],0x884c708
* 1348d828 -e9 d72744f0 jmp 038d0004
* 1348d82d 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
* 1348d833 81e0 ffffff3f and eax,0x3fffffff
* 1348d839 0fbeb0 00004007 movsx esi,byte ptr ds:[eax+0x7400000]
* 1348d840 81fe 00000000 cmp esi,0x0
* 1348d846 8935 88a71001 mov dword ptr ds:[0x110a788],esi
* 1348d84c 0f85 16000000 jnz 1348d868
* 1348d852 832d c4aa1001 03 sub dword ptr ds:[0x110aac4],0x3
* 1348d859 e9 aa030000 jmp 1348dc08
* 1348d85e 0154c7 84 add dword ptr ds:[edi+eax*8-0x7c],edx
* 1348d862 08e9 or cl,ch
* 1348d864 bb 2744f083 mov ebx,0x83f04427
* 1348d869 2d c4aa1001 sub eax,0x110aac4
* 1348d86e 03e9 add ebp,ecx
* 1348d870 0c 00 or al,0x0
* 1348d872 0000 add byte ptr ds:[eax],al
* 1348d874 0114c7 add dword ptr ds:[edi+eax*8],edx
* 1348d877 8408 test byte ptr ds:[eax],cl
* 1348d879 -e9 a52744f0 jmp 038d0023
* 1348d87e 90 nop
* 1348d87f cc int3
*
* Scenario function is as follows.
* But I am not able to find it at runtime.
*
* 13484483 90 nop
* 13484484 77 0f ja short 13484495
* 13484486 c705 a8aa1001 30>mov dword ptr ds:[0x110aaa8],0x884b030
* 13484490 -e9 6fbb59f3 jmp 06a20004
* 13484495 8b35 74a71001 mov esi,dword ptr ds:[0x110a774]
* 1348449b 81fe 00000000 cmp esi,0x0
* 134844a1 9c pushfd
* 134844a2 8bc6 mov eax,esi
* 134844a4 8b35 84a71001 mov esi,dword ptr ds:[0x110a784]
* 134844aa 03f0 add esi,eax
* 134844ac 8935 74a71001 mov dword ptr ds:[0x110a774],esi
* 134844b2 9d popfd
* 134844b3 0f8f 0c000000 jg 134844c5
* 134844b9 832d c4aa1001 02 sub dword ptr ds:[0x110aac4],0x2
* 134844c0 ^e9 23b0f9ff jmp 1341f4e8
* 134844c5 832d c4aa1001 02 sub dword ptr ds:[0x110aac4],0x2
* 134844cc e9 0b000000 jmp 134844dc
* 134844d1 0138 add dword ptr ds:[eax],edi
* 134844d3 b0 84 mov al,0x84
* 134844d5 08e9 or cl,ch
* 134844d7 48 dec eax
* 134844d8 bb 59f39077 mov ebx,0x7790f359
* 134844dd 0fc7 ??? ; unknown command
* 134844df 05 a8aa1001 add eax,0x110aaa8
* 134844e4 38b0 8408e917 cmp byte ptr ds:[eax+0x17e90884],dh
* 134844ea bb 59f38b05 mov ebx,0x58bf359
* 134844ef ^7c a7 jl short 13484498
* 134844f1 1001 adc byte ptr ds:[ecx],al
* 134844f3 81e0 ffffff3f and eax,0x3fffffff
* 134844f9 0fb6b0 00004007 movzx esi,byte ptr ds:[eax+0x7400000] ; jichi: hook here, byte by byte
* 13484500 8b05 84a71001 mov eax,dword ptr ds:[0x110a784]
* 13484506 81e0 ffffff3f and eax,0x3fffffff
* 1348450c 8bd6 mov edx,esi
* 1348450e 8890 00004007 mov byte ptr ds:[eax+0x7400000],dl
* 13484514 8b3d 84a71001 mov edi,dword ptr ds:[0x110a784]
* 1348451a 8d7f 01 lea edi,dword ptr ds:[edi+0x1]
* 1348451d 8b2d 7ca71001 mov ebp,dword ptr ds:[0x110a77c]
* 13484523 8d6d 01 lea ebp,dword ptr ss:[ebp+0x1]
* 13484526 3b3d 74a71001 cmp edi,dword ptr ds:[0x110a774]
* 1348452c 8935 70a71001 mov dword ptr ds:[0x110a770],esi
* 13484532 892d 7ca71001 mov dword ptr ds:[0x110a77c],ebp
* 13484538 893d 84a71001 mov dword ptr ds:[0x110a784],edi
* 1348453e 0f84 16000000 je 1348455a
* 13484544 832d c4aa1001 05 sub dword ptr ds:[0x110aac4],0x5
* 1348454b ^e9 8cffffff jmp 134844dc
* 13484550 0138 add dword ptr ds:[eax],edi
* 13484552 b0 84 mov al,0x84
* 13484554 08e9 or cl,ch
* 13484556 c9 leave
* 13484557 ba 59f3832d mov edx,0x2d83f359
* 1348455c c4aa 100105e9 les ebp,fword ptr ds:[edx+0xe9050110] ; modification of segment register
* 13484562 0e push cs
* 13484563 0000 add byte ptr ds:[eax],al
* 13484565 0001 add byte ptr ds:[ecx],al
* 13484567 4c dec esp
* 13484568 b0 84 mov al,0x84
* 1348456a 08e9 or cl,ch
* 1348456c b3 ba mov bl,0xba
* 1348456e 59 pop ecx
* 1348456f f3: prefix rep: ; superfluous prefix
* 13484570 90 nop
* 13484571 cc int3
* 13484572 cc int3
* 13484573 cc int3
*/
bool InsertKadokawaNamePSPHook()
{
ConsoleOutput("Kadokawa Name PSP: enter");
const BYTE bytes[] = {
0x77, 0x0f, // 1348d7a0 77 0f ja short 1348d7b1
0xc7,0x05, XX8, // 1348d7a2 c705 a8aa1001 fc>mov dword ptr ds:[0x110aaa8],0x884c6fc
0xe9, XX4, // 1348d7ac -e9 532844f0 jmp 038d0004
0x8b,0x05, XX4, // 1348d7b1 8b05 78a71001 mov eax,dword ptr ds:[0x110a778]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1348d7b7 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xb6,0xb0, XX4, // 1348d7bd 0fb6b0 00004007 movzx esi,byte ptr ds:[eax+0x7400000] ; jichi: hook here
0x81,0xfe, 0x00,0x00,0x00,0x00, // 1348d7c4 81fe 00000000 cmp esi,0x0
0x89,0x35, XX4, // 1348d7ca 8935 70a71001 mov dword ptr ds:[0x110a770],esi
0x0f,0x85, 0x2f,0x00,0x00,0x00, // 1348d7d0 0f85 2f000000 jnz 1348d805
0x8b,0x05, XX4, // 1348d7d6 8b05 7ca71001 mov eax,dword ptr ds:[0x110a77c]
0x81,0xe0, 0xff,0xff,0xff,0x3f, // 1348d7dc 81e0 ffffff3f and eax,0x3fffffff
0x0f,0xbe,0xb0, XX4, // 1348d7e2 0fbeb0 00004007 movsx esi,byte ptr ds:[eax+0x7400000]
0x89,0x35 //, XX4, // 1348d7e9 8935 70a71001 mov dword ptr ds:[0x110a770],esi
};
enum { memory_offset = 3 };
enum { addr_offset = 0x1348d7bd - 0x1348d7a0 };
auto succ=false;
DWORD addr = SafeMatchBytesInPSPMemory(bytes, sizeof(bytes));
if (!addr)
ConsoleOutput("Kadokawa Name PSP: pattern not found");
else {
HookParam hp;
hp.address = addr + addr_offset;
hp.user_value = *(DWORD *)(hp.address + memory_offset);
hp.type = USING_STRING|USING_SPLIT|NO_CONTEXT;
hp.offset=get_reg(regs::eax);
hp.split = get_reg(regs::edx);
hp.text_fun = SpecialPSPHook;
//GROWL_DWORD2(hp.address, hp.user_value);
ConsoleOutput("Kadokawa Name PSP: INSERT");
succ|=NewHook(hp, "Kadokawa Name PSP");
}
ConsoleOutput("Kadokawa Name PSP: leave");
return succ;
}
bool InsertPPSSPPHooks()
{
//if (PPSSPP_VERSION[1] == 9 && (PPSSPP_VERSION[2] > 9 || PPSSPP_VERSION[2] == 9 && PPSSPP_VERSION[3] >= 1)) // >= 0.9.9.1
ConsoleOutput("PPSSPP: enter");
// http://stackoverflow.com/questions/940707/how-do-i-programatically-get-the-version-of-a-dll-or-exe-file
// get the version info for the file requested
// if (DWORD dwSize = ::GetFileVersionInfoSizeW(processPath, nullptr)) {
// UINT len = 0;
// BYTE * buf = new BYTE[dwSize];
// VS_FIXEDFILEINFO * info = nullptr;
// if (::GetFileVersionInfoW(processPath, 0, dwSize, buf)
// && ::VerQueryValueW(buf, L"\\", (LPVOID*)&info, &len)
// && info)
// {
// PPSSPP_VERSION[0] = HIWORD(info->dwFileVersionMS),
// PPSSPP_VERSION[1] = LOWORD(info->dwFileVersionMS),
// PPSSPP_VERSION[2] = HIWORD(info->dwFileVersionLS),
// PPSSPP_VERSION[3] = LOWORD(info->dwFileVersionLS);
//
// }
// else
// ConsoleOutput("failed to get PPSSPP version");
// delete[] buf;
//
//}
if (PPSSPP_VERSION[1] == 9 && PPSSPP_VERSION[2] == 9 && PPSSPP_VERSION[3] == 0) // 0.9.9.0
InsertOtomatePPSSPPHook();
//bool engineFound = false;
Insert5pbPSPHook();
InsertCyberfrontPSPHook();
InsertImageepoch2PSPHook();
InsertFelistellaPSPHook();
InsertBroccoliPSPHook();
InsertIntensePSPHook();
//InsertKadokawaNamePSPHook(); // disabled
InsertKonamiPSPHook();
if (PPSSPP_VERSION[1] == 9 && PPSSPP_VERSION[2] == 8) { // only works for 0.9.8 anyway
InsertNippon1PSPHook();
InsertNippon2PSPHook(); // This could crash PPSSPP 099 just like 5pb
}
//InsertTecmoPSPHook();
// Generic hooks
bool bandaiFound = InsertBandaiPSPHook();
InsertBandaiNamePSPHook();
// Hooks whose pattern is not generic enouph
InsertYetiPSPHook();
InsertYeti2PSPHook();
InsertAlchemistPSPHook();
InsertAlchemist2PSPHook();
//InsertTypeMoonPSPHook() // otomate is creating too many garbage
//|| InsertOtomatePSPHook();
InsertOtomatePSPHook();
if (!bandaiFound) {
// KID pattern is a subset of BANDAI, and hence MUST NOT be together with BANDAI
// Sample BANDAI game that could be broken by KID: 寮<>のサクリファイス
InsertKidPSPHook(); // KID could lose text, could exist in multiple game
InsertImageepochPSPHook(); // Imageepoch could crash vnrcli for School Rumble PSP
}
ConsoleOutput("PPSSPP: leave");
return true;
}
#endif
bool PPSSPPengine::attach_function() {
return InsertPPSSPPcommonhooks();
}