1

1

Update PPSSPP.cpp

Update PPSSPP.cpp
This commit is contained in:
恍兮惚兮 2024-03-26 23:14:04 +08:00
parent 271aa43cee
commit c031c40521
9 changed files with 409 additions and 340 deletions

View File

@ -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<uintptr_t,emfuncinfo> 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<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 {};
}
}
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;
auto succ=InsertPPSSPPcommonhooks();
//succ|=InsertPPSSPPHooks(); // Artikash 8/4/2018: removed for now as doesn't work for non ancient ppsspp versions
return succ;
}

View File

@ -1,90 +1,9 @@
#include"PPSSPP.h"
#include"ppsspp/psputils.hpp"
#include<queue>
/** 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<BYTE>{ 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_map<uintptr_t,emfuncinfo>emfunctionhooks;
std::unordered_set<uintptr_t>breakpoints;
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<int index,int offset=0>
void simple932getter(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
@ -105,54 +24,20 @@ 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;
}
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 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();
}
bool ULJS00403_filter(void* data, size_t* len, HookParam* hp){
std::string result = std::string((char*)data,*len);
std::regex newlinePattern(R"((\\n)+)");
@ -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<uintptr_t,emfuncinfo> 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;
}();
}
}
bool PPSSPP::attach_function()
{
return InsertPPSSPPcommonhooks();
}

View File

@ -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)

View File

@ -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

View File

@ -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<end;_addr+=1)
{
auto lea=(*(WORD*)_addr);
if(lea!=0x8d4c&&lea!=0x8d48)
continue;
auto offset=*(DWORD*)(_addr+3);
auto refaddr=(offset)+_addr+7;
if(refaddr==addr)
return _addr;
}
return 0;
}
bool InsertPPSSPPHLEHooks()
{
auto functions=std::vector<PPSSPPFunction>{
//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<BYTE>{ 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<BYTE>{ 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_set<uintptr_t>breakpoints;
std::unordered_map<uintptr_t,emfuncinfo>emfunctionhooks=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;
}

View File

@ -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<uintptr_t,emfuncinfo> loademfunctionhooks();
}
bool InsertPPSSPPcommonhooks();
#ifndef _WIN64
namespace{
int PPSSPP_VERSION[4] = { 0, 9, 8, 0 }; // 0.9.8 by default
@ -40,3 +56,5 @@ ULONG SafeMatchBytesInPS2Memory(LPCVOID pattern, DWORD patternSize)
}
}
#endif
#endif

View File

@ -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

View File

@ -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<length;i++){
@ -451,7 +451,15 @@ uintptr_t reverseFindBytes(const BYTE* pattern, int length, uintptr_t start, uin
success=false;break;
}
}
if(success)return end;
if(success)
{
auto ret=end+offset;
if(checkalign && ret&0xf)
continue;
return ret;
}
// if (memcmp(pattern, (const BYTE*)(end), length) == 0) {
// return end;
// }

View File

@ -45,10 +45,10 @@ uintptr_t FindFunction(const char* function);
} // namespace Util
uintptr_t SafeFindEnclosingAlignedFunction(uintptr_t addr, uintptr_t range);
uintptr_t SafeFindBytes(LPCVOID pattern, size_t patternSize, uintptr_t lowerBound, uintptr_t upperBound);
#ifndef _WIN64
ULONG SafeFindEnclosingAlignedFunction(DWORD addr, DWORD range);
ULONG SafeFindBytes(LPCVOID pattern, DWORD patternSize, DWORD lowerBound, DWORD upperBound);
ULONG _SafeMatchBytesInMappedMemory(LPCVOID pattern, DWORD patternSize, BYTE wildcard,
ULONG start, ULONG stop, ULONG step);
ULONG SafeMatchBytesInGCMemory(LPCVOID pattern, DWORD patternSize);
@ -60,7 +60,7 @@ uintptr_t findfuncstart(uintptr_t addr,uintptr_t range=0x100);
#endif
uintptr_t find_pattern(const char* pattern,uintptr_t start,uintptr_t end);
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=0,bool checkalign=false);
std::vector<uintptr_t> findxref_reverse(uintptr_t addr, uintptr_t from, uintptr_t to);