This commit is contained in:
恍兮惚兮 2024-11-01 16:41:23 +08:00
parent 552f76b43e
commit a744bd2fdb
2 changed files with 493 additions and 401 deletions

View File

@ -63,34 +63,45 @@ struct PPSSPPFunction
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;
if (!addr)
return NULL;
addr = SafeFindEnclosingAlignedFunction(addr, 0x200);
#else
addr = MemDbg::findleaaddr(addr, processStartAddress, processStopAddress);
if(!addr)return NULL;
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;
@ -145,18 +156,22 @@ bool InsertPPSSPPHLEHooks()
//, { "sysclib_strcmp", 2, USING_STRING, 0, "Untested sysclib_strcmp(" }
};
auto succ = false;
for (auto&& function :functions) {
for (auto &&function : functions)
{
auto addr = MemDbg::findBytes(function.pattern, ::strlen(function.pattern), processStartAddress, processStopAddress);
if(!addr)continue;
if (!addr)
continue;
addr = findleapushaddr(addr);
if(!addr)continue;
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;
if (hp.split)
hp.type |= USING_SPLIT;
succ |= NewHook(hp, function.hookName);
}
return succ;
@ -208,36 +223,44 @@ bool PPSSPPinithooksearch(){
return found;
}
#endif
uintptr_t getDoJitAddress() {
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;
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;
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;
if (addr1 == 0 || addr2 == 0 || addr1 != addr2)
return 0;
auto xrefs = findxref_reverse_checkcallop(addr1, processStartAddress, processStopAddress, 0xe8);
if(xrefs.size()<28)return 0;
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 || 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) {
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){
if (subs)
{
return subs;
}
}
@ -246,7 +269,8 @@ uintptr_t getDoJitAddress() {
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) {
if (first)
{
first = MemDbg::findEnclosingAlignedFunction_strict(first, 0x400);
return first;
}
@ -255,35 +279,52 @@ uintptr_t getDoJitAddress() {
return 0;
}
namespace ppsspp{
namespace ppsspp
{
bool checkiscurrentgame(const emfuncinfo& em){
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;
for (auto &&info : wininfos)
{
if (info.title.find(acastw(em._id)) != info.title.npos)
return true;
}
return false;
}
std::unordered_set<uintptr_t> breakpoints;
inline bool IsValidAddress(const uintptr_t address) {
if ((address & 0x3E000000) == 0x08000000) {
inline bool IsValidAddress(const uintptr_t address)
{
if ((address & 0x3E000000) == 0x08000000)
{
return true;
} else if ((address & 0x3F800000) == 0x04000000) {
}
else if ((address & 0x3F800000) == 0x04000000)
{
return true;
} else if ((address & 0xBFFFC000) == 0x00010000) {
}
else if ((address & 0xBFFFC000) == 0x00010000)
{
return true;
} else if ((address & 0x3F000000) >= 0x08000000){// && (address & 0x3F000000) < 0x08000000 + g_MemorySize) {
}
else if ((address & 0x3F000000) >= 0x08000000)
{ // && (address & 0x3F000000) < 0x08000000 + g_MemorySize) {
return true;
} else {
}
else
{
return false;
}
}
void dohookemaddr(uintptr_t em_address,uintptr_t ret){
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;
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);
@ -314,32 +355,41 @@ void dohookemaddr(uintptr_t em_address,uintptr_t ret){
hpinternal.jittype = JITTYPE::PPSSPP;
NewHook(hpinternal, op._id);
}
namespace{
namespace
{
typedef DWORD u32;
typedef BYTE u8;
typedef WORD u16;
const int MAX_JIT_BLOCK_EXITS = 8;
namespace Memory {
struct Opcode {
Opcode() {
namespace Memory
{
struct Opcode
{
Opcode()
{
}
explicit Opcode(u32 v) : encoding(v) {
explicit Opcode(u32 v) : encoding(v)
{
}
u32 operator & (const u32& arg) const {
u32 operator&(const u32 &arg) const
{
return encoding & arg;
}
u32 operator >> (const u32& arg) const {
u32 operator>>(const u32 &arg) const
{
return encoding >> arg;
}
bool operator == (const u32& arg) const {
bool operator==(const u32 &arg) const
{
return encoding == arg;
}
bool operator != (const u32& arg) const {
bool operator!=(const u32 &arg) const
{
return encoding != arg;
}
@ -350,7 +400,8 @@ namespace{
typedef Memory::Opcode MIPSOpcode;
struct JitBlock {
struct JitBlock
{
bool ContainsAddress(u32 em_address) const;
const u8 *checkedEntry; // const, we have to translate to writable.
@ -377,17 +428,20 @@ namespace{
// performance in debug.
std::vector<u32> *proxyFor;
bool IsPureProxy() const {
bool IsPureProxy() const
{
return originalFirstOpcode.encoding == 0x68FF0000;
}
void SetPureProxy() {
void SetPureProxy()
{
// Magic number that won't be a real opcode.
originalFirstOpcode.encoding = 0x68FF0000;
}
};
}
void unsafeoncegetJitBlockCache(hook_stack* stack){
void unsafeoncegetJitBlockCache(hook_stack *stack)
{
// class JitBlockCache : public JitBlockCacheDebugInterface {
//...
@ -403,14 +457,18 @@ void unsafeoncegetJitBlockCache(hook_stack* stack){
#endif
int checkvalid = 0;
num_blocks_ -= 1; // last one is now dojiting
for(int i=0;i<num_blocks_;i++){
for (int i = 0; i < num_blocks_; i++)
{
if (IsValidAddress(blocks_[i].originalAddress) && blocks_[i].normalEntry)
checkvalid += 1;
}
if(checkvalid<num_blocks_/2)return;
if (checkvalid < num_blocks_ / 2)
return;
for(int i=0;i<num_blocks_;i++){
if(IsValidAddress(blocks_[i].originalAddress) && blocks_[i].normalEntry){
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);
}
@ -418,17 +476,24 @@ void unsafeoncegetJitBlockCache(hook_stack* stack){
return;
}
bool oncegetJitBlockCache(hook_stack* stack){
bool oncegetJitBlockCache(hook_stack *stack)
{
// 在游戏中途hook获取已compiled jit
// 虽然只有在每次进行jit时才会触发不过测试后续触发的也挺频繁的。
__try{
__try
{
unsafeoncegetJitBlockCache(stack);
}__except (EXCEPTION_EXECUTE_HANDLER) {}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
return true;
}
bool hookPPSSPPDoJit(){
bool hookPPSSPPDoJit()
{
auto DoJitPtr = getDoJitAddress();
if(DoJitPtr==0)return false;
if (DoJitPtr == 0)
return false;
spDefault.jittype = JITTYPE::PPSSPP;
spDefault.minAddress = 0;
spDefault.maxAddress = -1;
@ -436,7 +501,8 @@ bool hookPPSSPPDoJit(){
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){
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;
@ -445,12 +511,16 @@ bool hookPPSSPPDoJit(){
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){
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;
[&](){
if (!IsValidAddress(em_address))
return;
[&]()
{
auto ret = stack->LASTRETVAL;
if(breakpoints.find(ret)!=breakpoints.end())return;
if (breakpoints.find(ret) != breakpoints.end())
return;
breakpoints.insert(ret);
dohookemaddr(em_address, ret);
@ -463,61 +533,72 @@ bool hookPPSSPPDoJit(){
return NewHook(hp, "PPSSPPDoJit");
}
}
namespace{
namespace
{
// ULJS00035 ULJS00149 流行り神
void* findGetPointer(){
void *findGetPointer()
{
char GetPointer[] = "Unknown GetPointer %08x PC %08x LR %08x";
auto addr = MemDbg::findBytes(GetPointer, sizeof(GetPointer), processStartAddress, processStopAddress);
if(!addr)return nullptr;
if (!addr)
return nullptr;
addr = findleapushaddr(addr);
return (void *)addr;
}
bool Replace_memcpy(){
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;
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;
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)){
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;
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)){
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
};
0x48, 0x8b, XX, XX4};
addr = reverseFindBytes(sig1, sizeof(sig1), addr - 0x200, addr);
if(!addr)continue;
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){
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));
@ -538,8 +619,8 @@ namespace{
bool InsertPPSSPPcommonhooks()
{
auto succ=InsertPPSSPPHLEHooks();
succ|=ppsspp::hookPPSSPPDoJit();
auto succ = ppsspp::hookPPSSPPDoJit();
succ |= InsertPPSSPPHLEHooks();
succ |= Replace_memcpy();
return succ;
}

View File

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