LunaHook-mirror/LunaHook/engine64/rpcs3.cpp

268 lines
9.9 KiB
C++
Raw Normal View History

2024-04-07 18:35:50 +08:00
#include"rpcs3.h"
#include"engines/emujitarg.hpp"
namespace{
#if 0 //only support0.0.20-0.0.27
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;
}
#endif
uintptr_t getDoJitAddress() {
//rpcs3/Emu/Cell/PPUThread.cpp
/*
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;
}
*/
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);
return addr;
}
struct emfuncinfo{
uint64_t type;
int argidx;int padding;
void* hookfunc;
void* filterfun;
const char* _id;
};
std::unordered_map<uintptr_t,emfuncinfo>emfunctionhooks;
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;
}
static std::set<std::pair<uintptr_t,uintptr_t>> timeoutbreaks;
void dohookemaddr(uintptr_t em_address,uintptr_t ret){
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);
}
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;
}
*/
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");
}
}
bool rpcs3::attach_function()
{
ConsoleOutput("[Compatibility] RPCS3");
auto DoJitPtr=getDoJitAddress();
if(DoJitPtr==0)return false;
unsafeinithooks();
spDefault.jittype=JITTYPE::RPCS3;
spDefault.minAddress = 0;
spDefault.maxAddress = -1;
HookParam hp;
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);
delayinsertNewHook(em_address);
};
return NewHook(hp,"vita3kjit");
}
namespace{
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"}},
};
return 1;
}();
}