LunaHook-mirror/LunaHook/engine32/PPSSPP.cpp

3730 lines
178 KiB
C++
Raw Normal View History

2024-02-07 20:59:24 +08:00
#include"PPSSPP.h"
#include"ppsspp/psputils.hpp"
#include "ppsspp/funcinfo.h"
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);
}
}
}
bool InsertPPSSPPHLEHooks()
{
ConsoleOutput("PPSSPP HLE: enter");
// 0x400000 - 0x139f000
//GROWL_DWORD2(processStartAddress, processStopAddress);
HookParam hp;
hp.length_offset = 1; // determine string length at runtime
auto succ=false;
const PPSSPPFunction funcs[] = { PPSSPP_FUNCTIONS_INITIALIZER };
enum { FunctionCount = sizeof(funcs) / sizeof(*funcs) };
for (size_t i = 0; i < FunctionCount; i++) {
const auto &it = funcs[i];
ULONG addr = MemDbg::findBytes(it.pattern, ::strlen(it.pattern), processStartAddress, processStopAddress);
if (addr
&& (addr = MemDbg::findPushAddress(addr, processStartAddress, processStopAddress))
&& (addr = SafeFindEnclosingAlignedFunction(addr, 0x200)) // range = 0x200, use the safe version or it might raise
) {
hp.address = addr;
hp.type = USING_STRING|it.hookType;
hp.offset=get_stack(it.argIndex);
hp.split = it.hookSplit;
if (hp.split)
hp.type |= USING_SPLIT;
succ|=NewHook(hp, it.hookName);
}
if (addr)
ConsoleOutput("PPSSPP HLE: found pattern");
else
ConsoleOutput("PPSSPP HLE: not found pattern");
//ConsoleOutput(it.hookName); // wchar_t not supported
ConsoleOutput(it.pattern);
}
ConsoleOutput("PPSSPP HLE: leave");
return succ;
}
/** 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 <EFBFBD>(SHIFT-JIS)
* See: http://sakuradite.com/topic/333
*
* Sample game: <EFBFBD> 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: <EFBFBD>(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: <EFBFBD> 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 <EFBFBD> * 09dfee87 92 e1 82 ad 81 41 8f ac 82 b3 82 ad 81 41 8b bf <EFBFBD>
* 09dfee97 82 ad 81 42 2a 70 0a 82 b1 82 ea 82 cd 81 41 8c <EFBFBD>p.<EFBFBD>
* 09dfeea7 db 93 ae 81 63 81 48 2a 70 0a 82 c6 82 e0 82 b7 <EFBFBD>p.
* 09dfeeb7 82 ea 82 ce 95 b7 82 ab 93 a6 82 b5 82 c4 82 b5 <EFBFBD><EFBFBD><EFBFBD> * 09dfeec7 82 dc 82 a2 82 bb 82 a4 82 c8 81 41 2a 70 0a 8f <EFBFBD><EFBFBD><EFBFBD>p.
* 09dfeed7 ac 82 b3 82 ad 81 41 8e e3 81 58 82 b5 82 ad 81 <EFBFBD><EFBFBD><EFBFBD>
* 09dfeee7 41 95 73 8a 6d 82 a9 82 c8 89 b9 81 42 00 00 00 a不確かな音<EFBFBD>..
* 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: <EFBFBD><EFBFBD>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<EFBFBD>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: <EFBFBD> (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 <EFBFBD>
* 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: <EFBFBD><EFBFBD> (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><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: <EFBFBD> (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: <EFBFBD>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;
//
//}
InsertPPSSPPHLEHooks();
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;
}
/** Artikash 6/7/2019
* PPSSPP JIT code has pointers, but they are all added to an offset before being used.
Find that offset so that hook searching works properly.
To find the offset, find a page of mapped memory with size 0x1f00000, read and write permissions, take its address and subtract 0x8000000.
The above is useful for emulating PSP hardware, so unlikely to change between versions.
*/
bool FindPPSSPP()
{
bool found = false;
SYSTEM_INFO systemInfo;
GetNativeSystemInfo(&systemInfo);
for (BYTE* probe = NULL; probe < systemInfo.lpMaximumApplicationAddress;)
{
MEMORY_BASIC_INFORMATION info;
if (!VirtualQuery(probe, &info, sizeof(info)))
{
probe += systemInfo.dwPageSize;
}
else
{
if (info.RegionSize == 0x1f00000 && info.Protect == PAGE_READWRITE && info.Type == MEM_MAPPED)
{
found = true;
ConsoleOutput("PPSSPP memory found: searching for hooks should yield working hook codes");
// PPSSPP 1.8.0 compiles jal to sub dword ptr [ebp+0x360],??
memcpy(spDefault.pattern, Array<BYTE>{ 0x83, 0xAD, 0x60, 0x03, 0x00, 0x00 }, spDefault.length = 6);
spDefault.offset = 0;
spDefault.minAddress = 0;
spDefault.maxAddress = -1ULL;
spDefault.padding = (uintptr_t)probe - 0x8000000;
spDefault.hookPostProcessor = [](HookParam& hp)
{
hp.type |= NO_CONTEXT | USING_SPLIT | SPLIT_INDIRECT;
hp.split = get_reg(regs::ebp);
hp.split_index =get_reg(regs::eax); // this is where PPSSPP 1.8.0 stores its return address stack
};
}
probe += info.RegionSize;
}
}
return found;
}
bool PPSSPP::attach_function() {
bool _b1=InsertPPSSPPHooks(); // Artikash 8/4/2018: removed for now as doesn't work for non ancient ppsspp versions
bool _b2=FindPPSSPP();
if(_b1||_b2)
return true;
return false;
}