diff --git a/LunaHook/CMakeLists.txt b/LunaHook/CMakeLists.txt index f2d2f1f..8cb84fd 100644 --- a/LunaHook/CMakeLists.txt +++ b/LunaHook/CMakeLists.txt @@ -1,6 +1,6 @@ include_directories(. util engines) if(${CMAKE_SIZEOF_VOID_P} EQUAL 8) - set(enginessrc vita3k yuzusuyu TYPEMOON ENTERGRAM AGES7 mono Godot Renpy 5pb lucasystem LightVN V8 pchooks Artemis KiriKiri YOX PPSSPP CMVS Suika2 ) + set(enginessrc vita3k rpcs3 yuzusuyu TYPEMOON ENTERGRAM AGES7 mono Godot Renpy 5pb lucasystem LightVN V8 pchooks Artemis KiriKiri YOX PPSSPP CMVS Suika2 ) set(enginepath "engine64") set(collector "enginecollection64.cpp") else() diff --git a/LunaHook/engine64/rpcs3.cpp b/LunaHook/engine64/rpcs3.cpp new file mode 100644 index 0000000..d8d273b --- /dev/null +++ b/LunaHook/engine64/rpcs3.cpp @@ -0,0 +1,268 @@ +#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((reinterpret_cast(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_mapemfunctionhooks; + +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> 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; +}(); +} \ No newline at end of file diff --git a/LunaHook/engine64/rpcs3.h b/LunaHook/engine64/rpcs3.h new file mode 100644 index 0000000..fee7494 --- /dev/null +++ b/LunaHook/engine64/rpcs3.h @@ -0,0 +1,13 @@ +#include"engine.h" + +class rpcs3:public ENGINE{ + public: + rpcs3(){ + + check_by=CHECK_BY::FILE; + is_engine_certain=false; + check_by_target=L"rpcs3.exe"; + }; + bool attach_function(); +}; + \ No newline at end of file diff --git a/LunaHook/enginecollection64.cpp b/LunaHook/enginecollection64.cpp index 1f64bbf..1797f49 100644 --- a/LunaHook/enginecollection64.cpp +++ b/LunaHook/enginecollection64.cpp @@ -17,6 +17,7 @@ #include"engine64/LightVN.h" #include"engine64/yuzusuyu.h" #include"engine64/vita3k.h" +#include"engine64/rpcs3.h" std::vector ignore_engines(){ return{ }; } std::vector unsafe_check_atlast(){ return{ }; } @@ -40,7 +41,8 @@ std::vector check_engines(){ new ENTERGRAM, new yuzusuyu, new PPSSPP, - new vita3k + new vita3k, + new rpcs3 }; } diff --git a/LunaHook/engines/emujitarg.hpp b/LunaHook/engines/emujitarg.hpp index ffd8903..5e541d6 100644 --- a/LunaHook/engines/emujitarg.hpp +++ b/LunaHook/engines/emujitarg.hpp @@ -1,5 +1,18 @@ #pragma once #ifdef _WIN64 +namespace RPCS3 +{ +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=(uintptr_t*)(stack->rbp+0x18+8*3); + return base+args[idx]; + } +}; +} namespace YUZU { class emu_arg{ diff --git a/LunaHook/engines/ppsspp/ppsspp.cpp b/LunaHook/engines/ppsspp/ppsspp.cpp index 3a21767..779e74a 100644 --- a/LunaHook/engines/ppsspp/ppsspp.cpp +++ b/LunaHook/engines/ppsspp/ppsspp.cpp @@ -65,22 +65,6 @@ struct PPSSPPFunction 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;_addrjittype) { #ifdef _WIN64 + case JITTYPE::RPCS3: + return RPCS3::emu_arg(stack)[hp->argidx]; case JITTYPE::VITA3K: return VITA3K::emu_arg(stack)[hp->argidx]; case JITTYPE::YUZU: @@ -341,14 +343,23 @@ void TextHook::Read() buffer->type=hp.type; __try { - while (WaitForSingleObject(readerEvent, 500) == WAIT_TIMEOUT) if (location&&(memcmp(pbData, location, dataLen) != 0)) if (int currentLen = HookStrlen((BYTE*)location)) + if(hp.text_fun) { - dataLen = min(currentLen, TEXT_BUFFER_SIZE); - memcpy(pbData, location, dataLen); - if (hp.filter_fun && !hp.filter_fun(pbData, &dataLen, &hp) || dataLen <= 0) continue; - TextOutput({ GetCurrentProcessId(), address, 0, 0 }, buffer, dataLen); - memcpy(pbData, location, dataLen); + while (WaitForSingleObject(readerEvent, 500) == WAIT_TIMEOUT) + hp.text_fun(0,0,0,0,0); } + else + { + while (WaitForSingleObject(readerEvent, 500) == WAIT_TIMEOUT) if (location&&(memcmp(pbData, location, dataLen) != 0)) if (int currentLen = HookStrlen((BYTE*)location)) + { + dataLen = min(currentLen, TEXT_BUFFER_SIZE); + memcpy(pbData, location, dataLen); + if (hp.filter_fun && !hp.filter_fun(pbData, &dataLen, &hp) || dataLen <= 0) continue; + TextOutput({ GetCurrentProcessId(), address, 0, 0 }, buffer, dataLen); + memcpy(pbData, location, dataLen); + } + } + } __except (EXCEPTION_EXECUTE_HANDLER) { diff --git a/LunaHook/util/memdbg/memsearch.cc b/LunaHook/util/memdbg/memsearch.cc index d32834c..84c6a43 100644 --- a/LunaHook/util/memdbg/memsearch.cc +++ b/LunaHook/util/memdbg/memsearch.cc @@ -478,6 +478,24 @@ DWORD findEnclosingFunctionAfterInt3(DWORD start, DWORD back_range, DWORD step) DWORD findEnclosingFunctionAfterNop(DWORD start, DWORD back_range, DWORD step) { return findEnclosingFunctionAfterDword(0x90909090,start, back_range, step); } +#else + +uint64_t findleaaddr(uint64_t addr,uint64_t start,uint64_t end) +{ + for(auto _addr=start;_addr