2024-10-03 14:53:59 +08:00
|
|
|
|
#include "rpcs3.h"
|
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
#if 0 // only support0.0.20-0.0.27
|
2024-04-07 18:35:50 +08:00
|
|
|
|
int emoffset;
|
|
|
|
|
int jitoffset;
|
|
|
|
|
uintptr_t getDoJitAddress_() {
|
|
|
|
|
auto installFunctionPatt1 = "0F8? ???????? 488D?? ?00?0000 E8 ???????? 4?83C? 68"; // MSVC
|
|
|
|
|
auto DoJitMatch = find_pattern(installFunctionPatt1,processStartAddress,processStopAddress);
|
|
|
|
|
if(DoJitMatch)return DoJitMatch;
|
|
|
|
|
|
|
|
|
|
auto installFunctionPatt2 = "660F 1F440000 488D?? ?00?0000 E8 ???????? 4?83C? 68"; // patched
|
|
|
|
|
DoJitMatch = find_pattern(installFunctionPatt2,processStartAddress,processStopAddress);
|
|
|
|
|
if(DoJitMatch)return DoJitMatch;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
uintptr_t getDoJitAddress() {
|
|
|
|
|
auto DoJitPtr=getDoJitAddress_();
|
|
|
|
|
|
|
|
|
|
ConsoleOutput("DoJitPtr %p",DoJitPtr);
|
|
|
|
|
if(!DoJitPtr)return 0;
|
|
|
|
|
//<--DoJitPtr
|
|
|
|
|
//0f85 1b050000 // jbe 0x00 ; long jump
|
|
|
|
|
//48 8d 8d 40020000 // lea r?x, ss:[rbp+0x1?0]
|
|
|
|
|
//e8 cc39acff //call
|
|
|
|
|
//48 83 c3 68 // add r?x, 0x68
|
|
|
|
|
auto checkaddr=DoJitPtr+0x6+7+5;
|
|
|
|
|
switch (*(BYTE*)checkaddr)
|
|
|
|
|
{
|
|
|
|
|
case 0x48:{
|
|
|
|
|
switch(*(BYTE*)(checkaddr+2)){
|
|
|
|
|
case 0xc0:emoffset=get_reg(regs::rax);break;
|
|
|
|
|
case 0xc3:emoffset=get_reg(regs::rbx);break;
|
|
|
|
|
case 0xc1:emoffset=get_reg(regs::rcx);break;
|
|
|
|
|
case 0xc2:emoffset=get_reg(regs::rdx);break;
|
|
|
|
|
case 0xc4:emoffset=get_reg(regs::rsp);break;
|
|
|
|
|
case 0xc5:emoffset=get_reg(regs::rbp);break;
|
|
|
|
|
case 0xc6:emoffset=get_reg(regs::rsi);break;
|
|
|
|
|
case 0xc7:emoffset=get_reg(regs::rdi);break;
|
|
|
|
|
default:emoffset=0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 0x49:{
|
|
|
|
|
switch(*(BYTE*)(checkaddr+2)){
|
|
|
|
|
case 0xc0:emoffset=get_reg(regs::r8);break;
|
|
|
|
|
case 0xc1:emoffset=get_reg(regs::r9);break;
|
|
|
|
|
case 0xc2:emoffset=get_reg(regs::r10);break;
|
|
|
|
|
case 0xc3:emoffset=get_reg(regs::r11);break;
|
|
|
|
|
case 0xc4:emoffset=get_reg(regs::r12);break;
|
|
|
|
|
case 0xc5:emoffset=get_reg(regs::r13);break;
|
|
|
|
|
case 0xc6:emoffset=get_reg(regs::r14);break;
|
|
|
|
|
case 0xc7:emoffset=get_reg(regs::r15);break;
|
|
|
|
|
default:emoffset=0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:emoffset=0;
|
|
|
|
|
}
|
|
|
|
|
ConsoleOutput("emoffset %d",emoffset);
|
|
|
|
|
if(emoffset==0)return 0;
|
|
|
|
|
|
|
|
|
|
auto isPPUDebugIfPtr = find_pattern("84C0 ???? 8B",DoJitPtr-0x40,DoJitPtr); // je
|
|
|
|
|
//84 c0 //test al,al
|
|
|
|
|
//74 21 //je
|
|
|
|
|
//8b 0b //mov ecx[rbx]
|
|
|
|
|
//48 8b 05 XX4 // mov rax[]
|
|
|
|
|
//4c 8d 34 48 //lea r14,[rax+rcx*2]
|
|
|
|
|
if(isPPUDebugIfPtr==0)return 0;
|
|
|
|
|
|
|
|
|
|
checkaddr= isPPUDebugIfPtr+2+2+2+7;
|
|
|
|
|
switch (*(BYTE*)checkaddr)
|
|
|
|
|
{
|
|
|
|
|
case 0x48:{
|
|
|
|
|
switch(*(BYTE*)(checkaddr+2)){
|
|
|
|
|
case 0x14:jitoffset=get_reg(regs::rdx);break;
|
|
|
|
|
case 0x04:jitoffset=get_reg(regs::rax);break;
|
|
|
|
|
case 0x1c:jitoffset=get_reg(regs::rbx);break;
|
|
|
|
|
case 0x0c:jitoffset=get_reg(regs::rcx);break;
|
|
|
|
|
case 0x24:jitoffset=get_reg(regs::rsp);break;
|
|
|
|
|
case 0x2c:jitoffset=get_reg(regs::rbp);break;
|
|
|
|
|
case 0x34:jitoffset=get_reg(regs::rsi);break;
|
|
|
|
|
case 0x3c:jitoffset=get_reg(regs::rdi);break;
|
|
|
|
|
default:jitoffset=0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 0x4c:{
|
|
|
|
|
switch(*(BYTE*)(checkaddr+2)){
|
|
|
|
|
case 0x04:jitoffset=get_reg(regs::r8);break;
|
|
|
|
|
case 0x0c:jitoffset=get_reg(regs::r9);break;
|
|
|
|
|
case 0x14:jitoffset=get_reg(regs::r10);break;
|
|
|
|
|
case 0x1c:jitoffset=get_reg(regs::r11);break;
|
|
|
|
|
case 0x24:jitoffset=get_reg(regs::r12);break;
|
|
|
|
|
case 0x2c:jitoffset=get_reg(regs::r13);break;
|
|
|
|
|
case 0x34:jitoffset=get_reg(regs::r14);break;
|
|
|
|
|
case 0x3c:jitoffset=get_reg(regs::r15);break;
|
|
|
|
|
default:jitoffset=0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:jitoffset=0;
|
|
|
|
|
}
|
|
|
|
|
ConsoleOutput("jitoffset %d",jitoffset);
|
|
|
|
|
if(jitoffset==0)return 0;
|
|
|
|
|
|
|
|
|
|
DWORD _;
|
|
|
|
|
BYTE bs1[]={0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00};
|
|
|
|
|
VirtualProtect((void*)DoJitPtr,sizeof(bs1),PAGE_EXECUTE_READWRITE,&_);
|
|
|
|
|
memcpy((void*)DoJitPtr,bs1,sizeof(bs1));
|
|
|
|
|
BYTE bs2[]={0x66, 0x90};
|
|
|
|
|
VirtualProtect((void*)(isPPUDebugIfPtr+2),sizeof(bs2),PAGE_EXECUTE_READWRITE,&_);
|
|
|
|
|
memcpy((void*)(isPPUDebugIfPtr+2),bs2,sizeof(bs2));
|
|
|
|
|
|
|
|
|
|
return DoJitPtr+6;
|
|
|
|
|
}
|
2024-10-03 14:53:59 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
uintptr_t getDoJitAddress()
|
|
|
|
|
{
|
|
|
|
|
// rpcs3/Emu/Cell/PPUThread.cpp
|
2024-04-07 18:35:50 +08:00
|
|
|
|
/*
|
|
|
|
|
extern void ppu_register_function_at(u32 addr, u32 size, ppu_intrp_func_t ptr = nullptr)
|
|
|
|
|
{
|
|
|
|
|
// Initialize specific function
|
|
|
|
|
if (ptr)
|
|
|
|
|
{
|
|
|
|
|
ppu_ref(addr) = reinterpret_cast<ppu_intrp_func_t>((reinterpret_cast<uptr>(ptr) & 0xffff'ffff'ffffu) | (uptr(ppu_ref(addr)) & ~0xffff'ffff'ffffu));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!size)
|
|
|
|
|
{
|
|
|
|
|
if (g_cfg.core.ppu_debug)
|
|
|
|
|
{
|
|
|
|
|
ppu_log.error("ppu_register_function_at(0x%x): empty range", addr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
……
|
|
|
|
|
*/
|
2024-10-03 14:53:59 +08:00
|
|
|
|
char log[] = "ppu_register_function_at(0x%x): empty range";
|
|
|
|
|
auto logstrptr = MemDbg::findBytes(log, sizeof(log), processStartAddress, processStopAddress);
|
|
|
|
|
ConsoleOutput("%p", logstrptr);
|
|
|
|
|
if (logstrptr == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
auto addr = MemDbg::findleaaddr(logstrptr, processStartAddress, processStopAddress);
|
|
|
|
|
ConsoleOutput("%p", addr);
|
|
|
|
|
if (addr == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
// ff cc cc cc,find不到。。
|
|
|
|
|
BYTE start[] = {XX, 0xCC, 0xCC, 0xCC};
|
|
|
|
|
addr = reverseFindBytes(start, sizeof(start), addr - 0x200, addr, 4, true);
|
|
|
|
|
ConsoleOutput("%p", addr);
|
2024-04-07 18:35:50 +08:00
|
|
|
|
return addr;
|
|
|
|
|
}
|
2024-10-03 14:53:59 +08:00
|
|
|
|
struct emfuncinfo
|
|
|
|
|
{
|
|
|
|
|
uint64_t type;
|
|
|
|
|
int argidx;
|
|
|
|
|
int padding;
|
|
|
|
|
void *hookfunc;
|
|
|
|
|
void *filterfun;
|
|
|
|
|
const char *_id;
|
|
|
|
|
};
|
|
|
|
|
std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks;
|
2024-04-07 18:35:50 +08:00
|
|
|
|
|
2024-10-03 14:53:59 +08:00
|
|
|
|
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;
|
2024-04-07 18:35:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-10-03 14:53:59 +08:00
|
|
|
|
static std::set<std::pair<uintptr_t, uintptr_t>> timeoutbreaks;
|
2024-04-07 18:35:50 +08:00
|
|
|
|
|
2024-10-03 14:53:59 +08:00
|
|
|
|
void dohookemaddr(uintptr_t em_address, uintptr_t ret)
|
2024-04-07 18:35:50 +08:00
|
|
|
|
{
|
2024-10-03 14:53:59 +08:00
|
|
|
|
jitaddraddr(em_address, ret, JITTYPE::RPCS3);
|
|
|
|
|
if (emfunctionhooks.find(em_address) == emfunctionhooks.end())
|
|
|
|
|
return;
|
|
|
|
|
if (!(checkiscurrentgame(emfunctionhooks.at(em_address))))
|
|
|
|
|
return;
|
|
|
|
|
timeoutbreaks.insert(std::make_pair(em_address, ret));
|
|
|
|
|
auto op = emfunctionhooks.at(em_address);
|
|
|
|
|
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::RPCS3;
|
|
|
|
|
NewHook(hpinternal, op._id);
|
2024-04-07 18:35:50 +08:00
|
|
|
|
}
|
2024-10-03 14:53:59 +08:00
|
|
|
|
|
|
|
|
|
bool unsafeinithooks()
|
|
|
|
|
{
|
|
|
|
|
// rpcs0.0.30,不知道为什么ppu_register_function_at不全。不过看代码得到映射表了,直接弄吧。
|
|
|
|
|
// rpcs3/Emu/Cell/PPUThread.cpp
|
|
|
|
|
// Get pointer to executable cache
|
|
|
|
|
/*
|
|
|
|
|
static inline u8* ppu_ptr(u32 addr)
|
|
|
|
|
{
|
|
|
|
|
return vm::g_exec_addr + u64{addr} * 2;
|
2024-04-07 18:35:50 +08:00
|
|
|
|
}
|
2024-10-03 14:53:59 +08:00
|
|
|
|
*/
|
|
|
|
|
HookParam hp;
|
|
|
|
|
hp.type = DIRECT_READ;
|
|
|
|
|
hp.address = 0x500000000;
|
|
|
|
|
hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
|
|
|
|
{
|
|
|
|
|
for (auto [addr, info] : emfunctionhooks)
|
|
|
|
|
{
|
|
|
|
|
auto table = addr * 2 + 0x500000000;
|
|
|
|
|
if (IsBadReadPtr((void *)table, sizeof(uintptr_t)))
|
|
|
|
|
continue;
|
|
|
|
|
auto funcaddr = *(uintptr_t *)table;
|
|
|
|
|
funcaddr &= 0x0000ffffffffffff;
|
|
|
|
|
if (!funcaddr)
|
|
|
|
|
continue;
|
|
|
|
|
auto p = std::make_pair(addr, funcaddr);
|
|
|
|
|
if (timeoutbreaks.find(p) != timeoutbreaks.end())
|
|
|
|
|
continue;
|
|
|
|
|
dohookemaddr(addr, funcaddr);
|
|
|
|
|
delayinsertNewHook(addr);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
return NewHook(hp, "g_exec_addr");
|
|
|
|
|
}
|
2024-04-07 18:35:50 +08:00
|
|
|
|
}
|
|
|
|
|
bool rpcs3::attach_function()
|
|
|
|
|
{
|
2024-10-03 14:53:59 +08:00
|
|
|
|
ConsoleOutput("[Compatibility] RPCS3");
|
|
|
|
|
auto DoJitPtr = getDoJitAddress();
|
|
|
|
|
if (DoJitPtr == 0)
|
|
|
|
|
return false;
|
2024-04-07 18:35:50 +08:00
|
|
|
|
unsafeinithooks();
|
2024-10-03 14:53:59 +08:00
|
|
|
|
spDefault.jittype = JITTYPE::RPCS3;
|
2024-04-07 18:35:50 +08:00
|
|
|
|
spDefault.minAddress = 0;
|
|
|
|
|
spDefault.maxAddress = -1;
|
|
|
|
|
HookParam hp;
|
2024-10-03 14:53:59 +08:00
|
|
|
|
hp.address = DoJitPtr;
|
|
|
|
|
hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
|
|
|
|
{
|
|
|
|
|
auto em_address = stack->rcx; // *(uint32_t*)*(uintptr_t*)(stack->base+emoffset);
|
|
|
|
|
auto entrypoint = stack->r8; //*(uintptr_t*)*(uintptr_t*)(stack->base+jitoffset)-0x0008000000000000;
|
|
|
|
|
if (!em_address || !entrypoint)
|
|
|
|
|
return;
|
|
|
|
|
dohookemaddr(em_address, entrypoint);
|
2024-04-07 18:35:50 +08:00
|
|
|
|
delayinsertNewHook(em_address);
|
|
|
|
|
};
|
2024-10-03 14:53:59 +08:00
|
|
|
|
return NewHook(hp, "vita3kjit");
|
2024-04-07 18:35:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-10-03 14:53:59 +08:00
|
|
|
|
namespace
|
|
|
|
|
{
|
2024-04-07 18:35:50 +08:00
|
|
|
|
|
2024-10-03 14:53:59 +08:00
|
|
|
|
bool FBLJM61131(void *data, size_t *len, HookParam *hp)
|
|
|
|
|
{
|
|
|
|
|
auto s = std::string((char *)data, *len);
|
|
|
|
|
std::regex pattern("\\[[^\\]]+.");
|
|
|
|
|
s = std::regex_replace(s, pattern, "");
|
|
|
|
|
s = std::regex_replace(s, std::regex("\\\\k|\\\\x|%C|%B"), "");
|
|
|
|
|
s = std::regex_replace(s, std::regex("\\%\\d+\\#[0-9a-fA-F]*\\;"), "");
|
|
|
|
|
s = std::regex_replace(s, std::regex("\\n+"), " ");
|
|
|
|
|
return write_string_overwrite(data, len, s);
|
|
|
|
|
}
|
|
|
|
|
auto _ = []()
|
|
|
|
|
{
|
|
|
|
|
emfunctionhooks = {
|
|
|
|
|
//'&' -Sora no Mukou de Sakimasu you ni-
|
|
|
|
|
{0x46328, {CODEC_UTF8, 1, 0, 0, FBLJM61131, "BLJM61131"}},
|
|
|
|
|
// Dunamis15
|
|
|
|
|
{0x42c90, {CODEC_UTF8, 1, 0, 0, FBLJM61131, "BLJM60347"}},
|
2024-04-07 18:35:50 +08:00
|
|
|
|
|
2024-10-03 14:53:59 +08:00
|
|
|
|
};
|
|
|
|
|
return 1;
|
|
|
|
|
}();
|
2024-04-07 18:35:50 +08:00
|
|
|
|
}
|