From c031c40521c27a824b7a2581ddfbda9dd9afe941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=81=8D=E5=85=AE=E6=83=9A=E5=85=AE?= <101191390+HIllya51@users.noreply.github.com> Date: Tue, 26 Mar 2024 23:14:04 +0800 Subject: [PATCH] ppsspp 1 1 Update PPSSPP.cpp Update PPSSPP.cpp --- LunaHook/engine32/PPSSPP.cpp | 94 +------- LunaHook/engine64/PPSSPP.cpp | 167 +++----------- LunaHook/engines/CMakeLists.txt | 2 +- LunaHook/engines/ppsspp/funcinfo.h | 105 --------- LunaHook/engines/ppsspp/ppsspp.cpp | 329 +++++++++++++++++++++++++++ LunaHook/engines/ppsspp/psputils.hpp | 18 ++ LunaHook/stackoffset.hpp | 6 + LunaHook/util/util.cc | 22 +- LunaHook/util/util.h | 6 +- 9 files changed, 409 insertions(+), 340 deletions(-) delete mode 100644 LunaHook/engines/ppsspp/funcinfo.h create mode 100644 LunaHook/engines/ppsspp/ppsspp.cpp diff --git a/LunaHook/engine32/PPSSPP.cpp b/LunaHook/engine32/PPSSPP.cpp index 3467616..fd33ff0 100644 --- a/LunaHook/engine32/PPSSPP.cpp +++ b/LunaHook/engine32/PPSSPP.cpp @@ -2,7 +2,6 @@ #include"PPSSPP.h" #include"ppsspp/psputils.hpp" -#include "ppsspp/funcinfo.h" namespace { // unnamed inline bool _bandaigarbage_ch(char c) @@ -210,43 +209,6 @@ void SpecialPSPHook(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_ } } -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) @@ -3625,7 +3587,6 @@ bool InsertPPSSPPHooks() // //} - InsertPPSSPPHLEHooks(); if (PPSSPP_VERSION[1] == 9 && PPSSPP_VERSION[2] == 9 && PPSSPP_VERSION[3] == 0) // 0.9.9.0 InsertOtomatePPSSPPHook(); @@ -3677,54 +3638,19 @@ bool InsertPPSSPPHooks() 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() +namespace ppsspp{ +std::unordered_map loademfunctionhooks() { - 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{ 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; + return {}; +} } + 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; + auto succ=InsertPPSSPPcommonhooks(); + + //succ|=InsertPPSSPPHooks(); // Artikash 8/4/2018: removed for now as doesn't work for non ancient ppsspp versions + + return succ; } \ No newline at end of file diff --git a/LunaHook/engine64/PPSSPP.cpp b/LunaHook/engine64/PPSSPP.cpp index 1aaa1d7..f730047 100644 --- a/LunaHook/engine64/PPSSPP.cpp +++ b/LunaHook/engine64/PPSSPP.cpp @@ -1,91 +1,10 @@ #include"PPSSPP.h" +#include"ppsspp/psputils.hpp" #include -/** 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 PPSSPPinithooksearch(){ - 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 [r14+0x360],?? - memcpy(spDefault.pattern, Array{ 0x41, 0x83, 0xae, 0x60, 0x03, 0x00, 0x00 }, spDefault.length = 7); - 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::r14); - hp.split_index = -8; // this is where PPSSPP 1.8.0 stores its return address stack - }; - } - probe += info.RegionSize; - } - } - return found; -} -namespace{ -uintptr_t getDoJitAddress() { - 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 beginSubSig1 = "55 41 ?? 41 ?? 41"; - auto lookbackSize = 0x400; - auto address=first-lookbackSize; - auto subs=find_pattern(beginSubSig1,address,address+lookbackSize); - if(subs){ - return subs; - } - } - return 0; -} - -class emu_arg{ - hook_stack* stack; -public: - emu_arg(hook_stack* stack_):stack(stack_){}; - uintptr_t operator [](int idx){ - auto base=stack->rbx; - auto args=stack->r14; - auto offR = -0x80; - auto offset = offR + 0x10 + idx * 4; - return base+*(uint32_t*)(args+offset); - } -}; -struct emfuncinfo{ - const char* hookname; - void* hookfunc; - void* filterfun; - const wchar_t* _id; -}; -std::unordered_mapemfunctionhooks; -std::unordered_setbreakpoints; - -bool checkiscurrentgame(const emfuncinfo& em){ - auto wininfos=get_proc_windows(); - for(auto&& info:wininfos){ - if(info.title.find(em._id)!=info.title.npos)return true; - } - return false; -} +namespace +{ + template void simple932getter(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ hp->type=USING_STRING|NO_CONTEXT; @@ -105,53 +24,19 @@ void simpleutf16getter(hook_stack* stack, HookParam* hp, uintptr_t* data, uintpt hp->type=USING_STRING|CODEC_UTF16|NO_CONTEXT|_type; *data=address;*len=wcslen((wchar_t*)address)*2; } -} -bool hookPPSSPPDoJit(){ - ConsoleOutput("[Compatibility] PPSSPP 1.12.3-867 -> v1.16.1-35"); - auto DoJitPtr=getDoJitAddress(); - if(DoJitPtr==0)return false; - HookParam hp; - hp.address=DoJitPtr;//Jit::DoJit - ConsoleOutput("DoJitPtr %p",DoJitPtr); - - hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto em_address=stack->ARG2; - - if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return; - - if(!(checkiscurrentgame(emfunctionhooks.at(em_address))))return; - - HookParam hpinternal; - hpinternal.user_value=em_address; - hpinternal.address=stack->retaddr; - hpinternal.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - hp->text_fun=nullptr;hp->type=HOOK_EMPTY; - - auto ret=stack->rax; - if(breakpoints.find(ret)!=breakpoints.end())return; - breakpoints.insert(ret); - - auto em_address=hp->user_value; - auto op=emfunctionhooks.at(em_address); - - HookParam hpinternal; - hpinternal.address=ret; - hpinternal.user_value=em_address; - hpinternal.text_fun=(decltype(hpinternal.text_fun))op.hookfunc; - hpinternal.filter_fun=(decltype(hpinternal.filter_fun))op.filterfun; - NewHook(hpinternal,op.hookname); - }; - NewHook(hpinternal,"DoJitPtrRet"); - }; - - return NewHook(hp,"PPSSPPDoJit"); -} - -bool PPSSPP::attach_function() -{ - return PPSSPPinithooksearch()| hookPPSSPPDoJit(); -} - +class emu_arg{ + hook_stack* stack; +public: + emu_arg(hook_stack* stack_):stack(stack_){}; + uintptr_t operator [](int idx){ + auto base=stack->rbx; + auto args=stack->r14; + auto offR = -0x80; + auto offset = offR + 0x10 + idx * 4; + return base+*(uint32_t*)(args+offset); + } +}; +} bool ULJS00403_filter(void* data, size_t* len, HookParam* hp){ std::string result = std::string((char*)data,*len); @@ -402,11 +287,10 @@ void QNPJH50909(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* sp if(0x6e87==*(WORD*)*data)*len=0; if(0x000a==*(WORD*)*data)*len=0; } - - -namespace{ -auto _=[](){ - emfunctionhooks={ +namespace ppsspp{ +std::unordered_map loademfunctionhooks() +{ + return { /* 0x883b0bc: mainHandler.bind_(null, 2), // a2 - choices (un-formated) 0x883cf04: mainHandler.bind_(null, 3), // a3 - choices + nameX2 @@ -436,6 +320,9 @@ auto _=[](){ {0x88eeba4,{"Gekka Ryouran Romance",simple932getter<0,0>,ULJM05943F,L"ULJM05943"}},// a0 - monologue text {0x8875e0c,{"Gekka Ryouran Romance",simple932getter<1,6>,ULJM05943F,L"ULJM05943"}},// a1 - dialogue text }; - return 1; -}(); -} \ No newline at end of file +} +} +bool PPSSPP::attach_function() +{ + return InsertPPSSPPcommonhooks(); +} diff --git a/LunaHook/engines/CMakeLists.txt b/LunaHook/engines/CMakeLists.txt index 7c79051..f950ae6 100644 --- a/LunaHook/engines/CMakeLists.txt +++ b/LunaHook/engines/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(commonengine mages/mages.cpp v8/v8.cpp python/python2.cpp python/python3.cpp python/python.cpp pchooks/pchooks.cpp) +add_library(commonengine ppsspp/ppsspp.cpp mages/mages.cpp v8/v8.cpp python/python2.cpp python/python3.cpp python/python.cpp pchooks/pchooks.cpp) target_precompile_headers(commonengine REUSE_FROM pch) diff --git a/LunaHook/engines/ppsspp/funcinfo.h b/LunaHook/engines/ppsspp/funcinfo.h deleted file mode 100644 index d074163..0000000 --- a/LunaHook/engines/ppsspp/funcinfo.h +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -// ppsspp/funcinfo.h -// 12/26/2014 -// See: https://github.com/hrydgard/ppsspp - -// Core/HLE (High Level Emulator) -// - sceCcc -// #void sceCccSetTable(u32 jis2ucs, u32 ucs2jis) -// int sceCccUTF8toUTF16(u32 dstAddr, u32 dstSize, u32 srcAddr) -// int sceCccUTF8toSJIS(u32 dstAddr, u32 dstSize, u32 srcAddr) -// int sceCccUTF16toUTF8(u32 dstAddr, u32 dstSize, u32 srcAddr) -// int sceCccUTF16toSJIS(u32 dstAddr, u32 dstSize, u32 srcAddr) -// int sceCccSJIStoUTF8(u32 dstAddr, u32 dstSize, u32 srcAddr) -// int sceCccSJIStoUTF16(u32 dstAddr, u32 dstSize, u32 srcAddr) -// int sceCccStrlenUTF8(u32 strAddr) -// int sceCccStrlenUTF16(u32 strAddr) -// int sceCccStrlenSJIS(u32 strAddr) -// u32 sceCccEncodeUTF8(u32 dstAddrAddr, u32 ucs) -// void sceCccEncodeUTF16(u32 dstAddrAddr, u32 ucs) -// u32 sceCccEncodeSJIS(u32 dstAddrAddr, u32 jis) -// u32 sceCccDecodeUTF8(u32 dstAddrAddr) -// u32 sceCccDecodeUTF16(u32 dstAddrAddr) -// u32 sceCccDecodeSJIS(u32 dstAddrAddr) -// int sceCccIsValidUTF8(u32 c) -// int sceCccIsValidUTF16(u32 c) -// int sceCccIsValidSJIS(u32 c) -// int sceCccIsValidUCS2(u32 c) -// int sceCccIsValidUCS4(u32 c) -// int sceCccIsValidJIS(u32 c) -// int sceCccIsValidUnicode(u32 c) -// #u32 sceCccSetErrorCharUTF8(u32 c) -// #u32 sceCccSetErrorCharUTF16(u32 c) -// #u32 sceCccSetErrorCharSJIS(u32 c) -// u32 sceCccUCStoJIS(u32 c, u32 alt) -// u32 sceCccJIStoUCS(u32 c, u32 alt) -// - sceFont: search charCode -// int sceFontGetCharInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr) -// int sceFontGetShadowInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr) -// int sceFontGetCharImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr) -// int sceFontGetShadowImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr) -// int sceFontGetCharGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr) -// int sceFontGetCharGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight) -// #int sceFontSetAltCharacterCode(u32 fontLibHandle, u32 charCode) -// int sceFontGetShadowGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr) -// int sceFontGetShadowGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight) -// - sceKernelInterrupt -// u32 sysclib_strcat(u32 dst, u32 src) -// int sysclib_strcmp(u32 dst, u32 src) -// u32 sysclib_strcpy(u32 dst, u32 src) -// u32 sysclib_strlen(u32 src) -// -// Sample debug string: -// 006EFD8E PUSH PPSSPPWi.00832188 ASCII "sceCccEncodeSJIS(%08x, U+%04x)" -// Corresponding source code in sceCcc: -// ERROR_LOG(HLE, "sceCccEncodeSJIS(%08x, U+%04x): invalid pointer", dstAddrAddr, jis); - -struct PPSSPPFunction -{ - const char *hookName; // hook name - size_t argIndex; // argument index - unsigned long hookType; // hook parameter type - unsigned long hookSplit; // hook parameter split, positive: stack, negative: registers - const char *pattern; // debug string used within the function -}; - -// jichi 7/14/2014: UTF-8 is treated as STRING -// http://867258173.diandian.com/post/2014-06-26/40062099618 -// sceFontGetCharGlyphImage_Clip -// Sample game: [KID] Monochrome: sceFontGetCharInfo, sceFontGetCharGlyphImage_Clip -// -// Example: { L"sceFontGetCharInfo", 2, CODEC_UTF16, 4, "sceFontGetCharInfo(" } -// Text is at arg2, using arg1 as split -#define PPSSPP_FUNCTIONS_INITIALIZER \ - { "sceCccStrlenSJIS", 1, USING_STRING, 0, "sceCccStrlenSJIS(" } \ - , { "sceCccStrlenUTF8", 1, CODEC_UTF8, 0, "sceCccStrlenUTF8(" } \ - , { "sceCccStrlenUTF16", 1, CODEC_UTF16, 0, "sceCccStrlenUTF16(" } \ -\ - , { "sceCccSJIStoUTF8", 3, CODEC_UTF8, 0, "sceCccSJIStoUTF8(" } \ - , { "sceCccSJIStoUTF16", 3, USING_STRING, 0, "sceCccSJIStoUTF16(" } \ - , { "sceCccUTF8toSJIS", 3, CODEC_UTF8, 0, "sceCccUTF8toSJIS(" } \ - , { "sceCccUTF8toUTF16", 3, CODEC_UTF8, 0, "sceCccUTF8toUTF16(" } \ - , { "sceCccUTF16toSJIS", 3, CODEC_UTF16, 0, "sceCccUTF16toSJIS(" } \ - , { "sceCccUTF16toUTF8", 3, CODEC_UTF16, 0, "sceCccUTF16toUTF8(" } \ -\ - , { "sceFontGetCharInfo", 2, CODEC_UTF16, 4, "sceFontGetCharInfo(" } \ - , { "sceFontGetShadowInfo", 2, CODEC_UTF16, 4, "sceFontGetShadowInfo("} \ - , { "sceFontGetCharImageRect", 2, CODEC_UTF16, 4, "sceFontGetCharImageRect(" } \ - , { "sceFontGetShadowImageRect", 2, CODEC_UTF16, 4, "sceFontGetShadowImageRect(" } \ - , { "sceFontGetCharGlyphImage", 2, CODEC_UTF16, 4, "sceFontGetCharGlyphImage(" } \ - , { "sceFontGetCharGlyphImage_Clip", 2, CODEC_UTF16, 4, "sceFontGetCharGlyphImage_Clip(" } \ - , { "sceFontGetShadowGlyphImage", 2, CODEC_UTF16, 4, "sceFontGetShadowGlyphImage(" } \ - , { "sceFontGetShadowGlyphImage_Clip", 2, CODEC_UTF16, 4, "sceFontGetShadowGlyphImage_Clip(" } \ -\ - , { "sysclib_strcat", 2, USING_STRING, 0, "Untested sysclib_strcat(" } \ - , { "sysclib_strcpy", 2, USING_STRING, 0, "Untested sysclib_strcpy(" } \ - , { "sysclib_strlen", 1, 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(" } - -// EOF diff --git a/LunaHook/engines/ppsspp/ppsspp.cpp b/LunaHook/engines/ppsspp/ppsspp.cpp new file mode 100644 index 0000000..52b63cd --- /dev/null +++ b/LunaHook/engines/ppsspp/ppsspp.cpp @@ -0,0 +1,329 @@ + +#include"engine.h" +#include"util/util.h" +#include"psputils.hpp" +// See: https://github.com/hrydgard/ppsspp + +// Core/HLE (High Level Emulator) +// - sceCcc +// #void sceCccSetTable(u32 jis2ucs, u32 ucs2jis) +// int sceCccUTF8toUTF16(u32 dstAddr, u32 dstSize, u32 srcAddr) +// int sceCccUTF8toSJIS(u32 dstAddr, u32 dstSize, u32 srcAddr) +// int sceCccUTF16toUTF8(u32 dstAddr, u32 dstSize, u32 srcAddr) +// int sceCccUTF16toSJIS(u32 dstAddr, u32 dstSize, u32 srcAddr) +// int sceCccSJIStoUTF8(u32 dstAddr, u32 dstSize, u32 srcAddr) +// int sceCccSJIStoUTF16(u32 dstAddr, u32 dstSize, u32 srcAddr) +// int sceCccStrlenUTF8(u32 strAddr) +// int sceCccStrlenUTF16(u32 strAddr) +// int sceCccStrlenSJIS(u32 strAddr) +// u32 sceCccEncodeUTF8(u32 dstAddrAddr, u32 ucs) +// void sceCccEncodeUTF16(u32 dstAddrAddr, u32 ucs) +// u32 sceCccEncodeSJIS(u32 dstAddrAddr, u32 jis) +// u32 sceCccDecodeUTF8(u32 dstAddrAddr) +// u32 sceCccDecodeUTF16(u32 dstAddrAddr) +// u32 sceCccDecodeSJIS(u32 dstAddrAddr) +// int sceCccIsValidUTF8(u32 c) +// int sceCccIsValidUTF16(u32 c) +// int sceCccIsValidSJIS(u32 c) +// int sceCccIsValidUCS2(u32 c) +// int sceCccIsValidUCS4(u32 c) +// int sceCccIsValidJIS(u32 c) +// int sceCccIsValidUnicode(u32 c) +// #u32 sceCccSetErrorCharUTF8(u32 c) +// #u32 sceCccSetErrorCharUTF16(u32 c) +// #u32 sceCccSetErrorCharSJIS(u32 c) +// u32 sceCccUCStoJIS(u32 c, u32 alt) +// u32 sceCccJIStoUCS(u32 c, u32 alt) +// - sceFont: search charCode +// int sceFontGetCharInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr) +// int sceFontGetShadowInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr) +// int sceFontGetCharImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr) +// int sceFontGetShadowImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr) +// int sceFontGetCharGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr) +// int sceFontGetCharGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight) +// #int sceFontSetAltCharacterCode(u32 fontLibHandle, u32 charCode) +// int sceFontGetShadowGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr) +// int sceFontGetShadowGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight) +// - sceKernelInterrupt +// u32 sysclib_strcat(u32 dst, u32 src) +// int sysclib_strcmp(u32 dst, u32 src) +// u32 sysclib_strcpy(u32 dst, u32 src) +// u32 sysclib_strlen(u32 src) +// +// Sample debug string: +// 006EFD8E PUSH PPSSPPWi.00832188 ASCII "sceCccEncodeSJIS(%08x, U+%04x)" +// Corresponding source code in sceCcc: +// ERROR_LOG(HLE, "sceCccEncodeSJIS(%08x, U+%04x): invalid pointer", dstAddrAddr, jis); + +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 +}; + +uint64_t findleaaddr(uint64_t addr,uint64_t start,uint64_t end) +{ + for(auto _addr=start;_addr{ + +//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(" } , + + { "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/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(" } , + +//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; + #ifndef _WIN64 + addr=MemDbg::findPushAddress(addr, processStartAddress, processStopAddress); + if(!addr)continue; + addr=SafeFindEnclosingAlignedFunction(addr, 0x200); + #else + addr=findleaaddr(addr, processStartAddress, processStopAddress); + + if(!addr)continue; + + 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)); + + addr=maxaddr; + #endif + + if(!addr)continue; + HookParam hp; + hp.address=addr; + hp.type = function.hookType; + hp.offset=function.argIndex; + hp.split = function.hookSplit; + if (hp.split)hp.type |= USING_SPLIT; + succ|=NewHook(hp, function.hookName); + } + return succ; +} + +bool PPSSPPinithooksearch(){ + 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"); + #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 + // 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 + 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; + #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 + hp.split = get_reg(regs::r14); + hp.split_index = -8; // this is where PPSSPP 1.8.0 stores its return address stack + #endif + }; + } + probe += info.RegionSize; + } + } + return found; +} + +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[28-1-3],0x400); + addr2=MemDbg::findEnclosingAlignedFunction_strict(xrefs[28-1-4],0x400); + + if(addr1==0||addr2==0||addr1!=addr2)return 0; + return addr1; + #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 beginSubSig1 = "55 41 ?? 41 ?? 41"; + auto lookbackSize = 0x400; + 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 + return 0; +} + +namespace ppsspp{ + +bool checkiscurrentgame(const emfuncinfo& em){ + auto wininfos=get_proc_windows(); + for(auto&& info:wininfos){ + if(info.title.find(em._id)!=info.title.npos)return true; + } + return false; +} +std::unordered_setbreakpoints; +std::unordered_mapemfunctionhooks=loademfunctionhooks(); + +bool hookPPSSPPDoJit(){ + auto DoJitPtr=getDoJitAddress(); + if(DoJitPtr==0)return false; + HookParam hp; + hp.address=DoJitPtr;//Jit::DoJit + ConsoleOutput("DoJitPtr %p",DoJitPtr); + + hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ + auto em_address=stack->ARG2; + + if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return; + + if(!(checkiscurrentgame(emfunctionhooks.at(em_address))))return; + + HookParam hpinternal; + hpinternal.user_value=em_address; + hpinternal.address=stack->retaddr; + hpinternal.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ + hp->text_fun=nullptr;hp->type=HOOK_EMPTY; + + auto ret=stack->RETADDR; + if(breakpoints.find(ret)!=breakpoints.end())return; + breakpoints.insert(ret); + + auto em_address=hp->user_value; + auto op=emfunctionhooks.at(em_address); + + HookParam hpinternal; + hpinternal.address=ret; + hpinternal.user_value=em_address; + hpinternal.text_fun=(decltype(hpinternal.text_fun))op.hookfunc; + hpinternal.filter_fun=(decltype(hpinternal.filter_fun))op.filterfun; + NewHook(hpinternal,op.hookname); + }; + NewHook(hpinternal,"DoJitPtrRet"); + }; + + return NewHook(hp,"PPSSPPDoJit"); +} +} +bool InsertPPSSPPcommonhooks() +{ + + auto succ=InsertPPSSPPHLEHooks(); + succ|=PPSSPPinithooksearch(); + succ|=ppsspp::hookPPSSPPDoJit(); + return succ; +} \ No newline at end of file diff --git a/LunaHook/engines/ppsspp/psputils.hpp b/LunaHook/engines/ppsspp/psputils.hpp index 59db375..efc3310 100644 --- a/LunaHook/engines/ppsspp/psputils.hpp +++ b/LunaHook/engines/ppsspp/psputils.hpp @@ -1,6 +1,22 @@ #ifndef __LUNA_PSPUILTS_H #define __LUNA_PSPUILTS_H +namespace ppsspp +{ + + struct emfuncinfo{ + const char* hookname; + void* hookfunc; + void* filterfun; + const wchar_t* _id; + }; + std::unordered_map loademfunctionhooks(); +} + +bool InsertPPSSPPcommonhooks(); + + +#ifndef _WIN64 namespace{ int PPSSPP_VERSION[4] = { 0, 9, 8, 0 }; // 0.9.8 by default @@ -39,4 +55,6 @@ ULONG SafeMatchBytesInPS2Memory(LPCVOID pattern, DWORD patternSize) return _SafeMatchBytesInMappedMemory(pattern, patternSize, XX, start, stop, step); } } +#endif + #endif \ No newline at end of file diff --git a/LunaHook/stackoffset.hpp b/LunaHook/stackoffset.hpp index e6e8864..1c216a9 100644 --- a/LunaHook/stackoffset.hpp +++ b/LunaHook/stackoffset.hpp @@ -87,16 +87,22 @@ inline uintptr_t regof(regs reg,hook_stack* stack){ #define ARG1 stack[1] #define ARG2 stack[2] #define ARG3 stack[3] +#define RETADDR eax #define THISCALL __thiscall #define THISCALLTHIS ecx #define GETARG1 get_stack(1) #define GETARG2 get_stack(2) +#define GETARG3 get_stack(3) +#define GETARG4 get_stack(4) #else #define ARG1 rcx #define ARG2 rdx #define ARG3 r8 +#define RETADDR rax #define THISCALLTHIS rcx #define THISCALL #define GETARG1 get_reg(regs::rcx) #define GETARG2 get_reg(regs::rdx) +#define GETARG3 get_reg(regs::r8) +#define GETARG4 get_reg(regs::r9) #endif \ No newline at end of file diff --git a/LunaHook/util/util.cc b/LunaHook/util/util.cc index 54f77d8..06e15ce 100644 --- a/LunaHook/util/util.cc +++ b/LunaHook/util/util.cc @@ -328,18 +328,16 @@ uintptr_t FindFunction(const char* function) } -#ifndef _WIN64 - -ULONG SafeFindEnclosingAlignedFunction(DWORD addr, DWORD range) +uintptr_t SafeFindEnclosingAlignedFunction(uintptr_t addr, uintptr_t range) { - ULONG r = 0; + uintptr_t r = 0; __try{ r = MemDbg::findEnclosingAlignedFunction(addr, range); // this function might raise if failed }__except(EXCEPTION_EXECUTE_HANDLER) {} return r; } -ULONG SafeFindBytes(LPCVOID pattern, DWORD patternSize, DWORD lowerBound, DWORD upperBound) +uintptr_t SafeFindBytes(LPCVOID pattern, size_t patternSize, uintptr_t lowerBound, uintptr_t upperBound) { ULONG r = 0; __try{ @@ -347,6 +345,8 @@ ULONG SafeFindBytes(LPCVOID pattern, DWORD patternSize, DWORD lowerBound, DWORD }__except(EXCEPTION_EXECUTE_HANDLER) {} return r; } +#ifndef _WIN64 + // jichi 7/17/2014: Search mapped memory for emulators ULONG _SafeMatchBytesInMappedMemory(LPCVOID pattern, DWORD patternSize, BYTE wildcard, ULONG start, ULONG stop, ULONG step) @@ -443,7 +443,7 @@ uintptr_t findfuncstart(uintptr_t addr,uintptr_t range){ #endif -uintptr_t reverseFindBytes(const BYTE* pattern, int length, uintptr_t start, uintptr_t end) { +uintptr_t reverseFindBytes(const BYTE* pattern, int length, uintptr_t start, uintptr_t end,int offset,bool checkalign) { for (end -= length; end >= start; end -= 1) { bool success=true; for(int i=0;i findxref_reverse(uintptr_t addr, uintptr_t from, uintptr_t to);