From a744bd2fdb6257734544bd21e8b4f8579d5b14b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=81=8D=E5=85=AE=E6=83=9A=E5=85=AE?= <1173718158@qq.com> Date: Fri, 1 Nov 2024 16:41:23 +0800 Subject: [PATCH] psp --- LunaHook/engines/ppsspp/ppsspp.cpp | 865 +++++++++++++---------- LunaHook/engines/ppsspp/specialgames.hpp | 29 +- 2 files changed, 493 insertions(+), 401 deletions(-) diff --git a/LunaHook/engines/ppsspp/ppsspp.cpp b/LunaHook/engines/ppsspp/ppsspp.cpp index eecbd17..f23286d 100644 --- a/LunaHook/engines/ppsspp/ppsspp.cpp +++ b/LunaHook/engines/ppsspp/ppsspp.cpp @@ -1,6 +1,6 @@ -#include"psputils.hpp" -#include"specialgames.hpp" +#include "psputils.hpp" +#include "specialgames.hpp" // See: https://github.com/hrydgard/ppsspp // Core/HLE (High Level Emulator) @@ -56,108 +56,123 @@ struct PPSSPPFunction { - const char *hookName; // hook name - int argIndex; // argument index - uint64_t hookType; // hook parameter type - int hookSplit; // hook parameter split, positive: stack, negative: registers - const char *pattern; // debug string used within the function -}; + const char *hookName; // hook name + int argIndex; // argument index + uint64_t hookType; // hook parameter type + int hookSplit; // hook parameter split, positive: stack, negative: registers + const char *pattern; // debug string used within the function +}; -namespace{ +namespace +{ uintptr_t findleapushaddr(uintptr_t addr) { - #ifndef _WIN64 - addr=MemDbg::findPushAddress(addr, processStartAddress, processStopAddress); - if(!addr)return NULL; - addr=SafeFindEnclosingAlignedFunction(addr, 0x200); - #else - addr=MemDbg::findleaaddr(addr, processStartAddress, processStopAddress); - - if(!addr)return NULL; - - BYTE sig1[]={ - 0xCC, - 0x48,0x89,XX,0x24,XX, - }; - - BYTE sig2[]={ - 0xC3, - 0x48,0x89,XX,0x24,XX, - }; - BYTE sig3[]={ - 0xCC, - 0x89,XX,0x24,XX, - }; - BYTE sig4[]={ - 0xC3, - 0x89,XX,0x24,XX, - }; - int idx=0; - uintptr_t maxaddr=0; - for(auto sig:{sig1,sig2,sig3,sig4}) - { - idx+=1; - maxaddr=max(maxaddr,reverseFindBytes(sig,(idx>2)?5:6,addr-0x500,addr,1,true)); - } - maxaddr=max(maxaddr,MemDbg::findEnclosingAlignedFunction_strict(addr,0x500)); +#ifndef _WIN64 + addr = MemDbg::findPushAddress(addr, processStartAddress, processStopAddress); + if (!addr) + return NULL; + addr = SafeFindEnclosingAlignedFunction(addr, 0x200); +#else + addr = MemDbg::findleaaddr(addr, processStartAddress, processStopAddress); - addr=maxaddr; - #endif + if (!addr) + return NULL; + + BYTE sig1[] = { + //clang-format off + 0xCC, + 0x48, 0x89, XX, 0x24, XX, + //clang-format on + }; + + BYTE sig2[] = { + //clang-format off + 0xC3, + 0x48, 0x89, XX, 0x24, XX, + //clang-format on + }; + BYTE sig3[] = { + //clang-format off + 0xCC, + 0x89, XX, 0x24, XX, + //clang-format on + }; + BYTE sig4[] = { + //clang-format off + 0xC3, + 0x89, XX, 0x24, XX, + //clang-format on + }; + int idx = 0; + uintptr_t maxaddr = 0; + for (auto sig : {sig1, sig2, sig3, sig4}) + { + idx += 1; + maxaddr = max(maxaddr, reverseFindBytes(sig, (idx > 2) ? 5 : 6, addr - 0x500, addr, 1, true)); + } + maxaddr = max(maxaddr, MemDbg::findEnclosingAlignedFunction_strict(addr, 0x500)); + + addr = maxaddr; +#endif return addr; } } bool InsertPPSSPPHLEHooks() { - auto functions=std::vector{ - -//https://github.com/hrydgard/ppsspp/blob/master/Core/HLE/sceCcc.cpp - { "sceCccStrlenSJIS", GETARG1, USING_STRING, 0, "sceCccStrlenSJIS(" } , - { "sceCccStrlenUTF8", GETARG1, CODEC_UTF8|USING_STRING, 0, "sceCccStrlenUTF8(" } , - { "sceCccStrlenUTF16", GETARG1, CODEC_UTF16|USING_STRING, 0, "sceCccStrlenUTF16(" } , + auto functions = std::vector{ - { "sceCccSJIStoUTF8", GETARG3, USING_STRING, 0, "sceCccSJIStoUTF8(" } , - { "sceCccSJIStoUTF16", GETARG3, USING_STRING, 0, "sceCccSJIStoUTF16(" } , - { "sceCccUTF8toSJIS", GETARG3, CODEC_UTF8|USING_STRING, 0, "sceCccUTF8toSJIS(" } , - { "sceCccUTF8toUTF16", GETARG3, CODEC_UTF8|USING_STRING, 0, "sceCccUTF8toUTF16(" } , - { "sceCccUTF16toSJIS", GETARG3, CODEC_UTF16|USING_STRING, 0, "sceCccUTF16toSJIS(" } , - { "sceCccUTF16toUTF8", GETARG3, CODEC_UTF16|USING_STRING, 0, "sceCccUTF16toUTF8(" } , + // https://github.com/hrydgard/ppsspp/blob/master/Core/HLE/sceCcc.cpp + {"sceCccStrlenSJIS", GETARG1, USING_STRING, 0, "sceCccStrlenSJIS("}, + {"sceCccStrlenUTF8", GETARG1, CODEC_UTF8 | USING_STRING, 0, "sceCccStrlenUTF8("}, + {"sceCccStrlenUTF16", GETARG1, CODEC_UTF16 | USING_STRING, 0, "sceCccStrlenUTF16("}, -//https://github.com/hrydgard/ppsspp/blob/master/Core/HLE/sceFont.cpp - { "sceFontGetCharInfo", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetCharInfo(" } , - { "sceFontGetShadowInfo", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetShadowInfo("} , - { "sceFontGetCharImageRect", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetCharImageRect(" } , - { "sceFontGetShadowImageRect", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetShadowImageRect(" } , - { "sceFontGetCharGlyphImage", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetCharGlyphImage(" } , - { "sceFontGetCharGlyphImage_Clip", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetCharGlyphImage_Clip(" } , - { "sceFontGetShadowGlyphImage", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetShadowGlyphImage(" } , - { "sceFontGetShadowGlyphImage_Clip", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetShadowGlyphImage_Clip(" } , + {"sceCccSJIStoUTF8", GETARG3, USING_STRING, 0, "sceCccSJIStoUTF8("}, + {"sceCccSJIStoUTF16", GETARG3, USING_STRING, 0, "sceCccSJIStoUTF16("}, + {"sceCccUTF8toSJIS", GETARG3, CODEC_UTF8 | USING_STRING, 0, "sceCccUTF8toSJIS("}, + {"sceCccUTF8toUTF16", GETARG3, CODEC_UTF8 | USING_STRING, 0, "sceCccUTF8toUTF16("}, + {"sceCccUTF16toSJIS", GETARG3, CODEC_UTF16 | USING_STRING, 0, "sceCccUTF16toSJIS("}, + {"sceCccUTF16toUTF8", GETARG3, CODEC_UTF16 | USING_STRING, 0, "sceCccUTF16toUTF8("}, -//https://github.com/hrydgard/ppsspp/blob/master/Core/HLE/sceKernelInterrupt.cpp - { "sysclib_strcat", GETARG2, USING_STRING, 0, "Untested sysclib_strcat(" } , - { "sysclib_strcpy", GETARG2, USING_STRING, 0, "Untested sysclib_strcpy(" } , - { "sysclib_strlen", GETARG1, USING_STRING, 0, "Untested sysclib_strlen(" } + // https://github.com/hrydgard/ppsspp/blob/master/Core/HLE/sceFont.cpp + {"sceFontGetCharInfo", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetCharInfo("}, + {"sceFontGetShadowInfo", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetShadowInfo("}, + {"sceFontGetCharImageRect", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetCharImageRect("}, + {"sceFontGetShadowImageRect", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetShadowImageRect("}, + {"sceFontGetCharGlyphImage", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetCharGlyphImage("}, + {"sceFontGetCharGlyphImage_Clip", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetCharGlyphImage_Clip("}, + {"sceFontGetShadowGlyphImage", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetShadowGlyphImage("}, + {"sceFontGetShadowGlyphImage_Clip", GETARG2, CODEC_UTF16, GETARG1, "sceFontGetShadowGlyphImage_Clip("}, - // Disabled as I am not sure how to deal with the source string - //, { "sceCccEncodeSJIS", 2, USING_STRING, 0, "sceCccEncodeSJIS(" } - //, { "sceCccEncodeUTF8", 2, CODEC_UTF8, 0, "sceCccEncodeUTF8(" } - //, { "sceCccEncodeUTF16", 2, CODEC_UTF16, 0, "sceCccEncodeUTF16(" } - //, { "sysclib_strcmp", 2, USING_STRING, 0, "Untested sysclib_strcmp(" } - }; - auto succ=false; - for (auto&& function :functions) { + // https://github.com/hrydgard/ppsspp/blob/master/Core/HLE/sceKernelInterrupt.cpp + {"sysclib_strcat", GETARG2, USING_STRING, 0, "Untested sysclib_strcat("}, + {"sysclib_strcpy", GETARG2, USING_STRING, 0, "Untested sysclib_strcpy("}, + {"sysclib_strlen", GETARG1, USING_STRING, 0, "Untested sysclib_strlen("} + + // Disabled as I am not sure how to deal with the source string + //, { "sceCccEncodeSJIS", 2, USING_STRING, 0, "sceCccEncodeSJIS(" } + //, { "sceCccEncodeUTF8", 2, CODEC_UTF8, 0, "sceCccEncodeUTF8(" } + //, { "sceCccEncodeUTF16", 2, CODEC_UTF16, 0, "sceCccEncodeUTF16(" } + //, { "sysclib_strcmp", 2, USING_STRING, 0, "Untested sysclib_strcmp(" } + }; + auto succ = false; + for (auto &&function : functions) + { auto addr = MemDbg::findBytes(function.pattern, ::strlen(function.pattern), processStartAddress, processStopAddress); - if(!addr)continue; - addr=findleapushaddr(addr); - - if(!addr)continue; + if (!addr) + continue; + addr = findleapushaddr(addr); + + if (!addr) + continue; HookParam hp; - hp.address=addr; + hp.address = addr; hp.type = function.hookType; - hp.offset=function.argIndex; + hp.offset = function.argIndex; hp.split = function.hookSplit; - if (hp.split)hp.type |= USING_SPLIT; - succ|=NewHook(hp, function.hookName); + if (hp.split) + hp.type |= USING_SPLIT; + succ |= NewHook(hp, function.hookName); } return succ; } @@ -179,13 +194,13 @@ bool PPSSPPinithooksearch(){ { found = true; ConsoleOutput("PPSSPP memory found: searching for hooks should yield working hook codes"); - #ifndef _WIN64 +#ifndef _WIN64 // PPSSPP 1.8.0 compiles jal to sub dword ptr [ebp+0x360],?? memcpy(spDefault.pattern, Array{ 0x83, 0xAD, 0x60, 0x03, 0x00, 0x00 }, spDefault.length = 6); - #else +#else // PPSSPP 1.8.0 compiles jal to sub dword ptr [r14+0x360],?? memcpy(spDefault.pattern, Array{ 0x41, 0x83, 0xae, 0x60, 0x03, 0x00, 0x00 }, spDefault.length = 7); - #endif +#endif spDefault.offset = 0; spDefault.minAddress = 0; spDefault.maxAddress = -1ULL; @@ -193,13 +208,13 @@ bool PPSSPPinithooksearch(){ spDefault.hookPostProcessor = [](HookParam& hp) { hp.type |= NO_CONTEXT | USING_SPLIT | SPLIT_INDIRECT; - #ifndef _WIN64 +#ifndef _WIN64 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 - #else +#else hp.split = get_reg(regs::r14); hp.split_index = -8; // this is where PPSSPP 1.8.0 stores its return address stack - #endif +#endif }; } probe += info.RegionSize; @@ -208,338 +223,404 @@ bool PPSSPPinithooksearch(){ return found; } #endif -uintptr_t getDoJitAddress() { - #ifndef _WIN64 - auto string1="Jump target too far away, needs indirect register"; - auto string2="Jump target too far away, needs force5Bytes = true"; +uintptr_t getDoJitAddress() +{ +#ifndef _WIN64 + auto string1 = "Jump target too far away, needs indirect register"; + auto string2 = "Jump target too far away, needs force5Bytes = true"; auto addr1 = MemDbg::findBytes(string1, ::strlen(string1), processStartAddress, processStopAddress); auto addr2 = MemDbg::findBytes(string2, ::strlen(string2), processStartAddress, processStopAddress); - - if(addr1==0||addr2==0)return 0; - //都是被push两次,但是都是第一个 - addr1=MemDbg::findPushAddress(addr1, processStartAddress, processStopAddress); - addr2=MemDbg::findPushAddress(addr2, processStartAddress, processStopAddress); - if(addr1==0||addr2==0)return 0; - addr1=MemDbg::findEnclosingAlignedFunction_strict(addr1,0x100); - addr2=MemDbg::findEnclosingAlignedFunction_strict(addr2,0x100); - if(addr1==0||addr2==0||addr1!=addr2)return 0; - auto xrefs=findxref_reverse_checkcallop(addr1,processStartAddress,processStopAddress,0xe8); - if(xrefs.size()<28)return 0; - addr1=MemDbg::findEnclosingAlignedFunction_strict(xrefs[xrefs.size()-1-3],0x400); - addr2=MemDbg::findEnclosingAlignedFunction_strict(xrefs[xrefs.size()-1-4],0x400); - if(addr1==0||addr2==0||addr1!=addr2)return 0; + + if (addr1 == 0 || addr2 == 0) + return 0; + // 都是被push两次,但是都是第一个 + addr1 = MemDbg::findPushAddress(addr1, processStartAddress, processStopAddress); + addr2 = MemDbg::findPushAddress(addr2, processStartAddress, processStopAddress); + if (addr1 == 0 || addr2 == 0) + return 0; + addr1 = MemDbg::findEnclosingAlignedFunction_strict(addr1, 0x100); + addr2 = MemDbg::findEnclosingAlignedFunction_strict(addr2, 0x100); + if (addr1 == 0 || addr2 == 0 || addr1 != addr2) + return 0; + auto xrefs = findxref_reverse_checkcallop(addr1, processStartAddress, processStopAddress, 0xe8); + if (xrefs.size() < 28) + return 0; + addr1 = MemDbg::findEnclosingAlignedFunction_strict(xrefs[xrefs.size() - 1 - 3], 0x400); + addr2 = MemDbg::findEnclosingAlignedFunction_strict(xrefs[xrefs.size() - 1 - 4], 0x400); + if (addr1 == 0 || addr2 == 0 || addr1 != addr2) + return 0; return addr1; - #else +#else auto DoJitSig1 = "C7 83 ?? 0? 00 00 11 00 00 00 F6 83 ?? 0? 00 00 01 C7 83 ?? 0? 00 00 E4 00 00 00"; - auto first=find_pattern(DoJitSig1,processStartAddress,processStopAddress); - if (first) { + auto first = find_pattern(DoJitSig1, processStartAddress, processStopAddress); + if (first) + { auto beginSubSig1 = "55 41 ?? 41 ?? 41"; auto lookbackSize = 0x400; - auto address=first-lookbackSize; - auto subs=find_pattern(beginSubSig1,address,address+lookbackSize); - if(subs){ + auto address = first - lookbackSize; + auto subs = find_pattern(beginSubSig1, address, address + lookbackSize); + if (subs) + { return subs; } } - else - { - - auto DoJitSig2 = "C7 83 ?? 0? 00 00 11 00 00 00 F6 83 ?? 0? 00 00 01 ?? ?? ?? ?? ?? ?? ?? C7 83 ?? 0? 00 00 E4 00 00 00"; - first=find_pattern(DoJitSig2,processStartAddress,processStopAddress); - if (first) { - first=MemDbg::findEnclosingAlignedFunction_strict(first,0x400); - return first; - } - } - #endif + else + { + + auto DoJitSig2 = "C7 83 ?? 0? 00 00 11 00 00 00 F6 83 ?? 0? 00 00 01 ?? ?? ?? ?? ?? ?? ?? C7 83 ?? 0? 00 00 E4 00 00 00"; + first = find_pattern(DoJitSig2, processStartAddress, processStopAddress); + if (first) + { + first = MemDbg::findEnclosingAlignedFunction_strict(first, 0x400); + return first; + } + } +#endif return 0; } -namespace ppsspp{ +namespace ppsspp +{ -bool checkiscurrentgame(const emfuncinfo& em){ - auto wininfos=get_proc_windows(); - for(auto&& info:wininfos){ - if(info.title.find(acastw(em._id))!=info.title.npos)return true; + bool checkiscurrentgame(const emfuncinfo &em) + { + auto wininfos = get_proc_windows(); + for (auto &&info : wininfos) + { + if (info.title.find(acastw(em._id)) != info.title.npos) + return true; + } + return false; } - return false; -} -std::unordered_setbreakpoints; + std::unordered_set breakpoints; -inline bool IsValidAddress(const uintptr_t address) { - if ((address & 0x3E000000) == 0x08000000) { - return true; - } else if ((address & 0x3F800000) == 0x04000000) { - return true; - } else if ((address & 0xBFFFC000) == 0x00010000) { - return true; - } else if ((address & 0x3F000000) >= 0x08000000){// && (address & 0x3F000000) < 0x08000000 + g_MemorySize) { - return true; - } else { - return false; - } -} -void dohookemaddr(uintptr_t em_address,uintptr_t ret){ - jitaddraddr(em_address,ret,JITTYPE::PPSSPP); + inline bool IsValidAddress(const uintptr_t address) + { + if ((address & 0x3E000000) == 0x08000000) + { + return true; + } + else if ((address & 0x3F800000) == 0x04000000) + { + return true; + } + else if ((address & 0xBFFFC000) == 0x00010000) + { + return true; + } + else if ((address & 0x3F000000) >= 0x08000000) + { // && (address & 0x3F000000) < 0x08000000 + g_MemorySize) { + return true; + } + else + { + return false; + } + } + void dohookemaddr(uintptr_t em_address, uintptr_t ret) + { + jitaddraddr(em_address, ret, JITTYPE::PPSSPP); - if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return; - if(!(checkiscurrentgame(emfunctionhooks.at(em_address))))return; - - auto op=emfunctionhooks.at(em_address); - ConsoleOutput("jit function addr %p",ret); - #ifndef _WIN64 - BYTE sig[]={ - 0x8b,XX2,//mov reg,[ebp-off] - 0x8b,0xc6,//mov eax,esi - 0x25,0xff,0xff,0xff,0x3f,//and eax,0x3fffffff - 0x89,XX,XX4,//mov [eax+base+off],reg + if (emfunctionhooks.find(em_address) == emfunctionhooks.end()) + return; + if (!(checkiscurrentgame(emfunctionhooks.at(em_address)))) + return; - }; - auto findbase=MemDbg::findBytes(sig,sizeof(sig),ret,ret+0x20); - if(!findbase) - findbase=MemDbg::findBytes(sig,sizeof(sig),ret-0x1000,ret+0x1000); - if(!findbase) - ConsoleOutput("can't find emu_baseaddr"); - PPSSPP::x86_baseaddr=(*(DWORD*)(findbase+12))&0xffff0000; - ConsoleOutput("x86 base addr %p",PPSSPP::x86_baseaddr); - #endif - HookParam hpinternal; - hpinternal.address=ret; - hpinternal.emu_addr=em_address;//用于生成hcode - hpinternal.type=USING_STRING|NO_CONTEXT|BREAK_POINT|op.type; - hpinternal.text_fun=(decltype(hpinternal.text_fun))op.hookfunc; - hpinternal.filter_fun=(decltype(hpinternal.filter_fun))op.filterfun; - hpinternal.argidx=op.argidx; - hpinternal.padding=op.padding; - hpinternal.jittype=JITTYPE::PPSSPP; - NewHook(hpinternal,op._id); -} -namespace{ - typedef DWORD u32; - typedef BYTE u8; - typedef WORD u16; - const int MAX_JIT_BLOCK_EXITS = 8; - namespace Memory { - struct Opcode { - Opcode() { + auto op = emfunctionhooks.at(em_address); + ConsoleOutput("jit function addr %p", ret); +#ifndef _WIN64 + BYTE sig[] = { + 0x8b, XX2, // mov reg,[ebp-off] + 0x8b, 0xc6, // mov eax,esi + 0x25, 0xff, 0xff, 0xff, 0x3f, // and eax,0x3fffffff + 0x89, XX, XX4, // mov [eax+base+off],reg + + }; + auto findbase = MemDbg::findBytes(sig, sizeof(sig), ret, ret + 0x20); + if (!findbase) + findbase = MemDbg::findBytes(sig, sizeof(sig), ret - 0x1000, ret + 0x1000); + if (!findbase) + ConsoleOutput("can't find emu_baseaddr"); + PPSSPP::x86_baseaddr = (*(DWORD *)(findbase + 12)) & 0xffff0000; + ConsoleOutput("x86 base addr %p", PPSSPP::x86_baseaddr); +#endif + HookParam hpinternal; + hpinternal.address = ret; + hpinternal.emu_addr = em_address; // 用于生成hcode + hpinternal.type = USING_STRING | NO_CONTEXT | BREAK_POINT | op.type; + hpinternal.text_fun = (decltype(hpinternal.text_fun))op.hookfunc; + hpinternal.filter_fun = (decltype(hpinternal.filter_fun))op.filterfun; + hpinternal.argidx = op.argidx; + hpinternal.padding = op.padding; + hpinternal.jittype = JITTYPE::PPSSPP; + NewHook(hpinternal, op._id); + } + namespace + { + typedef DWORD u32; + typedef BYTE u8; + typedef WORD u16; + const int MAX_JIT_BLOCK_EXITS = 8; + namespace Memory + { + struct Opcode + { + Opcode() + { + } + + explicit Opcode(u32 v) : encoding(v) + { + } + + u32 operator&(const u32 &arg) const + { + return encoding & arg; + } + + u32 operator>>(const u32 &arg) const + { + return encoding >> arg; + } + + bool operator==(const u32 &arg) const + { + return encoding == arg; + } + + bool operator!=(const u32 &arg) const + { + return encoding != arg; + } + + u32 encoding; + }; + + } + + typedef Memory::Opcode MIPSOpcode; + + struct JitBlock + { + bool ContainsAddress(u32 em_address) const; + + const u8 *checkedEntry; // const, we have to translate to writable. + const u8 *normalEntry; + + u8 *exitPtrs[MAX_JIT_BLOCK_EXITS]; // to be able to rewrite the exit jump + u32 exitAddress[MAX_JIT_BLOCK_EXITS]; // 0xFFFFFFFF == unknown + + u32 originalAddress; + MIPSOpcode originalFirstOpcode; // to be able to restore + uint64_t compiledHash; + u16 codeSize; + u16 originalSize; + u16 blockNum; + + bool invalid; + bool linkStatus[MAX_JIT_BLOCK_EXITS]; + +#ifdef USE_VTUNE + char blockName[32]; +#endif + + // By having a pointer, we avoid a constructor/destructor being generated and dog slow + // performance in debug. + std::vector *proxyFor; + + bool IsPureProxy() const + { + return originalFirstOpcode.encoding == 0x68FF0000; } - - explicit Opcode(u32 v) : encoding(v) { + void SetPureProxy() + { + // Magic number that won't be a real opcode. + originalFirstOpcode.encoding = 0x68FF0000; } + }; + } - u32 operator & (const u32& arg) const { - return encoding & arg; + void unsafeoncegetJitBlockCache(hook_stack *stack) + { + +// class JitBlockCache : public JitBlockCacheDebugInterface { +//... +// JitBlock *blocks_ = nullptr; +// std::unordered_multimap proxyBlockMap_; ->64 +// int num_blocks_ = 0; +#ifdef _WIN64 + auto num_blocks_ = *(uint32_t *)(stack->rcx + 72 + 16 + 88); + auto blocks_ = (JitBlock *)*(uintptr_t *)(stack->rcx + 72 + 16 + 88 - 64 - 8); +#else + auto num_blocks_ = *(uint32_t *)(stack->ecx + 88); + auto blocks_ = (JitBlock *)*(uintptr_t *)(stack->ecx + 88 - 32 - 4); +#endif + int checkvalid = 0; + num_blocks_ -= 1; // last one is now dojiting + for (int i = 0; i < num_blocks_; i++) + { + if (IsValidAddress(blocks_[i].originalAddress) && blocks_[i].normalEntry) + checkvalid += 1; + } + if (checkvalid < num_blocks_ / 2) + return; + + for (int i = 0; i < num_blocks_; i++) + { + if (IsValidAddress(blocks_[i].originalAddress) && blocks_[i].normalEntry) + { + dohookemaddr(blocks_[i].originalAddress, (uintptr_t)blocks_[i].normalEntry); + delayinsertNewHook(blocks_[i].originalAddress); } + } - u32 operator >> (const u32& arg) const { - return encoding >> arg; - } + return; + } + bool oncegetJitBlockCache(hook_stack *stack) + { + // 在游戏中途hook,获取已compiled jit + // 虽然只有在每次进行jit时才会触发,不过测试后续触发的也挺频繁的。 + __try + { + unsafeoncegetJitBlockCache(stack); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } + return true; + } + bool hookPPSSPPDoJit() + { + auto DoJitPtr = getDoJitAddress(); + if (DoJitPtr == 0) + return false; + spDefault.jittype = JITTYPE::PPSSPP; + spDefault.minAddress = 0; + spDefault.maxAddress = -1; + HookParam hp; + hp.address = DoJitPtr; // Jit::DoJit + ConsoleOutput("DoJitPtr %p", DoJitPtr); + hp.user_value = (uintptr_t) new uintptr_t; + hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + static auto once1 = oncegetJitBlockCache(stack); + auto em_address = stack->THISCALLARG1; - bool operator == (const u32& arg) const { - return encoding == arg; - } + *(uintptr_t *)(hp->user_value) = em_address; - bool operator != (const u32& arg) const { - return encoding != arg; - } + HookParam hpinternal; + hpinternal.user_value = hp->user_value; + hpinternal.address = stack->retaddr; + hpinternal.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto em_address = *(uintptr_t *)(hp->user_value); + if (!IsValidAddress(em_address)) + return; + [&]() + { + auto ret = stack->LASTRETVAL; + if (breakpoints.find(ret) != breakpoints.end()) + return; + breakpoints.insert(ret); - u32 encoding; + dohookemaddr(em_address, ret); + }(); + delayinsertNewHook(em_address); + }; + static auto once = NewHook(hpinternal, "DoJitPtrRet"); }; + return NewHook(hp, "PPSSPPDoJit"); } +} +namespace +{ + // ULJS00035 ULJS00149 流行り神 + void *findGetPointer() + { + char GetPointer[] = "Unknown GetPointer %08x PC %08x LR %08x"; + auto addr = MemDbg::findBytes(GetPointer, sizeof(GetPointer), processStartAddress, processStopAddress); + if (!addr) + return nullptr; + addr = findleapushaddr(addr); + return (void *)addr; + } + bool Replace_memcpy() + { + // static int Replace_memcpy() { + // u32 destPtr = PARAM(0); + // u32 srcPtr = PARAM(1); + // u32 bytes = PARAM(2); + static auto GetPointer = (uintptr_t(*)(uintptr_t))findGetPointer(); + if (!GetPointer) + return false; + ConsoleOutput("GetPointer %p", GetPointer); + char ReplaceMemcpy_VideoDecodeRange[] = "ReplaceMemcpy/VideoDecodeRange"; + auto addr = MemDbg::findBytes(ReplaceMemcpy_VideoDecodeRange, sizeof(ReplaceMemcpy_VideoDecodeRange), processStartAddress, processStopAddress); + if (!addr) + return false; + ConsoleOutput("ReplaceMemcpy/VideoDecodeRange %p", addr); +#ifndef _WIN64 + BYTE sig[] = {0xb9, XX4}; + *(uintptr_t *)(sig + 1) = addr; + bool succ = false; + for (auto addr : Util::SearchMemory(sig, sizeof(sig), PAGE_EXECUTE, processStartAddress, processStopAddress)) + { + BYTE sig1[] = { + //clang-format off + 0x55, 0x8b, 0xec, + 0x81, 0xec, XX4, + 0x8b, 0x0d, XX4, + //clang-format on + }; + addr = reverseFindBytes(sig1, sizeof(sig1), addr - 0x200, addr); + if (!addr) + continue; + DWORD off_106D180 = *(DWORD *)(addr + sizeof(sig1) - 4); + HookParam hp; + hp.user_value = *(DWORD *)off_106D180; +#else + bool succ = false; + for (auto addr : MemDbg::findleaaddr_all(addr, processStartAddress, processStopAddress)) + { + BYTE sig1[] = { + 0x48, 0x89, XX, 0x24, 0x18, + 0x48, 0x89, XX, 0x24, 0x20, + 0x57, + 0x48, 0x81, 0xec, XX4, + 0x48, 0x8b, XX, XX4}; + addr = reverseFindBytes(sig1, sizeof(sig1), addr - 0x200, addr); + if (!addr) + continue; + DWORD off_140F4C810 = *(DWORD *)(addr + sizeof(sig1) - 4); + HookParam hp; + hp.user_value = *(uintptr_t *)(off_140F4C810 + addr + sizeof(sig1)); +#endif + hp.address = addr; + hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto bytes = *((DWORD *)hp->user_value + 6); + auto srcPtr = GetPointer(*((DWORD *)hp->user_value + 5)); - typedef Memory::Opcode MIPSOpcode; - - struct JitBlock { - bool ContainsAddress(u32 em_address) const; - - const u8* checkedEntry; // const, we have to translate to writable. - const u8* normalEntry; - - u8* exitPtrs[MAX_JIT_BLOCK_EXITS]; // to be able to rewrite the exit jump - u32 exitAddress[MAX_JIT_BLOCK_EXITS]; // 0xFFFFFFFF == unknown - - u32 originalAddress; - MIPSOpcode originalFirstOpcode; //to be able to restore - uint64_t compiledHash; - u16 codeSize; - u16 originalSize; - u16 blockNum; - - bool invalid; - bool linkStatus[MAX_JIT_BLOCK_EXITS]; - - #ifdef USE_VTUNE - char blockName[32]; - #endif - - // By having a pointer, we avoid a constructor/destructor being generated and dog slow - // performance in debug. - std::vector* proxyFor; - - bool IsPureProxy() const { - return originalFirstOpcode.encoding == 0x68FF0000; + if (!IsDBCSLeadByteEx(932, *(BYTE *)srcPtr)) + return; + if (bytes != 2) + return; + if (bytes != strnlen((char *)srcPtr, TEXT_BUFFER_SIZE)) + return; + *data = (uintptr_t)srcPtr; + *len = bytes; + }; + succ |= NewHook(hp, "Replace_memcpy"); } - void SetPureProxy() { - // Magic number that won't be a real opcode. - originalFirstOpcode.encoding = 0x68FF0000; - } - }; -} - -void unsafeoncegetJitBlockCache(hook_stack* stack){ - - //class JitBlockCache : public JitBlockCacheDebugInterface { - //... - //JitBlock *blocks_ = nullptr; - //std::unordered_multimap proxyBlockMap_; ->64 - //int num_blocks_ = 0; - #ifdef _WIN64 - auto num_blocks_=*(uint32_t*)(stack->rcx+72+16+88); - auto blocks_=(JitBlock*)*(uintptr_t*)(stack->rcx+72+16+88-64-8); - #else - auto num_blocks_=*(uint32_t*)(stack->ecx+88); - auto blocks_=(JitBlock*)*(uintptr_t*)(stack->ecx+88-32-4); - #endif - int checkvalid=0; - num_blocks_-=1;//last one is now dojiting - for(int i=0;iTHISCALLARG1; - - *(uintptr_t*)(hp->user_value)=em_address; - - HookParam hpinternal; - hpinternal.user_value=hp->user_value; - hpinternal.address=stack->retaddr; - hpinternal.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto em_address=*(uintptr_t*)(hp->user_value); - if(!IsValidAddress(em_address))return; - [&](){ - auto ret=stack->LASTRETVAL; - if(breakpoints.find(ret)!=breakpoints.end())return; - breakpoints.insert(ret); - - dohookemaddr(em_address,ret); - }(); - delayinsertNewHook(em_address); - }; - static auto once=NewHook(hpinternal,"DoJitPtrRet"); - }; - - return NewHook(hp,"PPSSPPDoJit"); -} -} -namespace{ - //ULJS00035 ULJS00149 流行り神 - void* findGetPointer(){ - char GetPointer[]="Unknown GetPointer %08x PC %08x LR %08x"; - auto addr=MemDbg::findBytes(GetPointer,sizeof(GetPointer),processStartAddress,processStopAddress); - if(!addr)return nullptr; - addr=findleapushaddr(addr); - return (void*)addr; - } - bool Replace_memcpy(){ -// static int Replace_memcpy() { -// u32 destPtr = PARAM(0); -// u32 srcPtr = PARAM(1); -// u32 bytes = PARAM(2); - static auto GetPointer=(uintptr_t(*)(uintptr_t))findGetPointer(); - if(!GetPointer)return false; - ConsoleOutput("GetPointer %p",GetPointer); - char ReplaceMemcpy_VideoDecodeRange[] ="ReplaceMemcpy/VideoDecodeRange"; - auto addr=MemDbg::findBytes(ReplaceMemcpy_VideoDecodeRange,sizeof(ReplaceMemcpy_VideoDecodeRange),processStartAddress,processStopAddress); - if(!addr)return false; - ConsoleOutput("ReplaceMemcpy/VideoDecodeRange %p",addr); - #ifndef _WIN64 - BYTE sig[]={0xb9,XX4}; - *(uintptr_t*)(sig+1)=addr; - bool succ=false; - for(auto addr:Util::SearchMemory(sig,sizeof(sig),PAGE_EXECUTE,processStartAddress,processStopAddress)){ - BYTE sig1[]={ - 0x55,0x8b,0xec, - 0x81,0xec,XX4, - 0x8b,0x0d,XX4, - }; - addr=reverseFindBytes(sig1,sizeof(sig1),addr-0x200,addr); - if(!addr)continue; - DWORD off_106D180=*(DWORD*)(addr+sizeof(sig1)-4); - HookParam hp; - hp.user_value=*(DWORD*)off_106D180; - #else - bool succ=false; - for(auto addr:MemDbg::findleaaddr_all(addr,processStartAddress,processStopAddress)){ - BYTE sig1[]={ - 0x48,0x89,XX,0x24,0x18, - 0x48,0x89,XX,0x24,0x20, - 0x57, - 0x48,0x81,0xec,XX4, - 0x48,0x8b,XX,XX4 - }; - addr=reverseFindBytes(sig1,sizeof(sig1),addr-0x200,addr); - if(!addr)continue; - DWORD off_140F4C810=*(DWORD*)(addr+sizeof(sig1)-4); - HookParam hp; - hp.user_value=*(uintptr_t*)(off_140F4C810+addr+sizeof(sig1)); - #endif - hp.address=addr; - hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - - auto bytes = *((DWORD *)hp->user_value + 6); - auto srcPtr = GetPointer(*((DWORD *)hp->user_value + 5)); - - if(!IsDBCSLeadByteEx(932,*(BYTE*)srcPtr)) - return; - if(bytes!=2) - return; - if(bytes!=strnlen((char*)srcPtr,TEXT_BUFFER_SIZE)) - return; - *data=(uintptr_t)srcPtr; - *len=bytes; - }; - succ|=NewHook(hp,"Replace_memcpy"); - } - return succ; - } } bool InsertPPSSPPcommonhooks() { - - auto succ=InsertPPSSPPHLEHooks(); - succ|=ppsspp::hookPPSSPPDoJit(); - succ|=Replace_memcpy(); - return succ; + + auto succ = ppsspp::hookPPSSPPDoJit(); + succ |= InsertPPSSPPHLEHooks(); + succ |= Replace_memcpy(); + return succ; } \ No newline at end of file diff --git a/LunaHook/engines/ppsspp/specialgames.hpp b/LunaHook/engines/ppsspp/specialgames.hpp index f046dfa..edec89b 100644 --- a/LunaHook/engines/ppsspp/specialgames.hpp +++ b/LunaHook/engines/ppsspp/specialgames.hpp @@ -210,13 +210,9 @@ namespace ppsspp bool ULJM05943F(void *data, size_t *len, HookParam *hp) { auto s = std::string((char *)data, *len); - std::regex pattern1("#n+"); - std::string replacement1 = " "; - std::string result1 = std::regex_replace(s, pattern1, replacement1); - std::regex pattern2("#[A-Za-z]+\\[(\\d*\\.)?\\d+\\]+"); - std::string replacement2 = ""; - std::string result2 = std::regex_replace(result1, pattern2, replacement2); - return write_string_overwrite(data, len, result2); + strReplace(s, "#n", ""); + s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*\\.)?\\d+\\]+"), ""); + return write_string_overwrite(data, len, s); } bool FULJM05603(LPVOID data, size_t *size, HookParam *) @@ -262,11 +258,20 @@ namespace ppsspp StringCharReplacer((char *)data, len, "\\n", 2, '\n'); return true; } + bool ULJM06145(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(R"(#Ruby\[(.*?),(.*?)\])"), "$1"); + s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*\\.)?\\d+\\]+"), ""); + strReplace(s, "#n", ""); + strReplace(s, "\x84\xbd", "!?"); + return write_string_overwrite(data, len, s); + } bool FULJM05690(void *data, size_t *len, HookParam *hp) { auto s = std::string((char *)data, *len); - s = std::regex_replace(s, std::regex("#Kana[(.*?),(.*?)]"), ""); - strReplace(s, "#n", "\n"); + s = std::regex_replace(s, std::regex(R"(#Kana\[(.*?),(.*?)\])"), "$1"); + strReplace(s, "#n", ""); return write_string_overwrite(data, len, s); } bool FULJM05889(LPVOID data, size_t *size, HookParam *) @@ -410,6 +415,12 @@ namespace ppsspp {0x88719dc, {0, 1, 0, 0, FNPJH50127, "NPJH50127"}}, // オメルタ~沈黙の掟~ THE LEGACY {0x88861C8, {0, 3, 0, 0, 0, "ULJM06393"}}, + // L.G.S~新説 封神演義~ + {0x888A358, {0, 0, 0, 0, ULJM05943F, "ULJM06131"}}, // NAME+TEXT + {0x88DB214, {0, 0, 0, 0, ULJM05943F, "ULJM06131"}}, // TEXT + {0x889E970, {0, 0, 0, 0, ULJM05943F, "ULJM06131"}}, // NAME + // 源狼 GENROH + {0x8940DA8, {0, 1, 0, 0, ULJM06145, "ULJM06145"}}, // TEXT }; } \ No newline at end of file