diff --git a/LunaHook/CMakeLists.txt b/LunaHook/CMakeLists.txt index d61826c..f2d2f1f 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 yuzusuyu TYPEMOON ENTERGRAM AGES7 mono Godot Renpy 5pb lucasystem LightVN V8 pchooks Artemis KiriKiri YOX PPSSPP CMVS Suika2 ) + set(enginessrc vita3k 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/vita3k.cpp b/LunaHook/engine64/vita3k.cpp new file mode 100644 index 0000000..cbc2627 --- /dev/null +++ b/LunaHook/engine64/vita3k.cpp @@ -0,0 +1,256 @@ +#include"vita3k.h" +#include"engines/emujitarg.hpp" +namespace{ + auto isVirtual = true; + auto idxDescriptor = isVirtual == true ? 2 : 1; + auto idxEntrypoint = idxDescriptor + 1; + uintptr_t getDoJitAddress() { + auto RegisterBlockSig1 = "40 55 53 56 57 41 54 41 56 41 57 48 8D 6C 24 E9 48 81 EC 90 00 00 00 48 8B ?? ?? ?? ?? ?? 48 33 C4 48 89 45 07 4D 8B F1 49 8B F0 48 8B FA 48 8B D9 4C 8B 7D 77 48 8B 01 48 8D 55 C7 FF 50 10"; + auto first=find_pattern(RegisterBlockSig1,processStartAddress,processStopAddress); + if (first) return first; + /* + // DebugSymbol: RegisterBlock + // ?RegisterBlock@EmitX64@X64@Backend@Dynarmic@@IEAA?AUBlockDescriptor@1234@AEBVLocationDescriptor@IR@4@PEBX_K@Z <- new + // ?RegisterBlock@EmitX64@X64@Backend@Dynarmic@@IEAA?AUBlockDescriptor@1234@AEBVLocationDescriptor@IR@4@PEBX1_K@Z + const symbols = DebugSymbol.findFunctionsMatching( + 'Dynarmic::Backend::X64::EmitX64::RegisterBlock' + ); + if (symbols.length !== 0) { + console.warn('Sym RegisterBlock'); + return symbols[0]; + } + */ + auto PatchBlockSig1 = "4C 8B DC 49 89 5B 10 49 89 6B 18 56 57 41 54 41 56 41 57";// "4C 8B DC 49 89 5B ?? 49 89 6B ?? 56 57 41 54 41 56 41 57"; + first = find_pattern(PatchBlockSig1,processStartAddress,processStopAddress); + if (first) { + idxDescriptor = 1; + idxEntrypoint = 2; + return first; + } + return 0; + } +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; +} +} + +bool vita3k::attach_function() +{ + ConsoleOutput("[Compatibility] Vita3k 0.1.9 3520+"); + auto DoJitPtr=getDoJitAddress(); + if(DoJitPtr==0)return false; + ConsoleOutput("DoJitPtr %p",DoJitPtr); + spDefault.jittype=JITTYPE::VITA3K; + 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 descriptor = *argidx(stack,idxDescriptor); // r8 + auto entrypoint = *argidx(stack,idxEntrypoint); // r9 + auto em_address = *(uint32_t*)descriptor; + if(!entrypoint)return; + // ConsoleOutput("%p",em_address); + jitaddraddr(em_address,entrypoint,JITTYPE::VITA3K); + [&](){ + if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return; + auto op=emfunctionhooks.at(em_address); + if(!(checkiscurrentgame(op)))return; + + HookParam hpinternal; + hpinternal.address=entrypoint; + 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::VITA3K; + NewHook(hpinternal,op._id); + }(); + delayinsertNewHook(em_address); + }; + return NewHook(hp,"vita3kjit"); +} + + +bool FPCSG01023(void* data, size_t* len, HookParam* hp){ + auto s = std::string((char*)data,*len); + s = std::regex_replace(s, std::regex("
"), ""); + s = std::regex_replace(s, std::regex("%CF11F"), ""); + s = std::regex_replace(s, std::regex("%CFFFF"), ""); + s = std::regex_replace(s, std::regex("%K%P"), ""); + s = std::regex_replace(s, std::regex("%K%N"), ""); + s = std::regex_replace(s, std::regex("\n"), ""); + return write_string_overwrite(data,len,s); +} +template +bool FPCSG01282(void* data, size_t* len, HookParam* hp){ + auto s = std::string((char*)data,*len); + s = std::regex_replace(s, std::regex("(\\n)+"), " "); + s = std::regex_replace(s, std::regex("\\d$|^@[a-z]+|#.*?#|\\$"), ""); + static std::string last; + if(last==s)return false; + last=s; + return write_string_overwrite(data,len,s); +} + + +template +void ReadU16TextAndLenDW(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ + auto address=VITA3K::emu_arg(stack)[index]; + *len=(*(DWORD*)(address+0x8))*2; + *data=address+0xC; +} + +bool FPCSG00410(void* data, size_t* len, HookParam* hp){ + auto s = std::string((char*)data,*len); + s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); + s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), ""); + s = std::regex_replace(s, std::regex("#n"), " "); + // .replaceAll("④", "!?").replaceAll("②", "!!").replaceAll("⑥", "。").replaceAll("⑪", "【") + // .replaceAll("⑫", "】").replaceAll("⑤", "、").replaceAll("①", "・・・") + strReplace(s,"\x87\x43","!?");strReplace(s,"\x87\x41","!!");strReplace(s,"\x87\x45","\x81\x42");strReplace(s,"\x87\x4a","\x81\x79"); + strReplace(s,"\x87\x4b","\x81\x7a");strReplace(s,"\x87\x44","\x81\x41");strReplace(s,"\x87\x40","\x81\x45\x81\x45\x81\x45"); + return write_string_overwrite(data,len,s); +} +bool FPCSG00448(void* data, size_t* len, HookParam* hp){ + auto s = std::string((char*)data,*len); + s = std::regex_replace(s, std::regex("[\\s]"), ""); + s = std::regex_replace(s, std::regex("(#n)+"), ""); + s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); + s = std::regex_replace(s, std::regex("#Pos[\\s\\S]*?\\]"), ""); + return write_string_overwrite(data,len,s); +} +bool FPCSG01008(void* data, size_t* len, HookParam* hp){ + auto s = std::string((char*)data,*len); + s = std::regex_replace(s, std::regex("#Ruby\\[([^,]+)\\.([^\\]]+)\\]."), "$1"); + s = std::regex_replace(s, std::regex("(#n)+"), " "); + s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); + return write_string_overwrite(data,len,s); +} +void TPCSG00903(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ + auto address=VITA3K::emu_arg(stack)[0]; + *len=(*(DWORD*)(address+0x14)); + *data=address+0x1C; +} +bool FPCSG00903(void* data, size_t* len, HookParam* hp){ + auto s = std::string((char*)data,*len); + s = std::regex_replace(s, std::regex("\\\\n"), " "); + return write_string_overwrite(data,len,s); +} +bool FPCSG00839(void* data, size_t* len, HookParam* hp){ + auto s = std::wstring((wchar_t*)data,*len/2); + s = std::regex_replace(s, std::wregex(L"\\[[^\\]]+."), L""); + s = std::regex_replace(s, std::wregex(L"\\\\k|\\\\x|%C|%B|%p-1;"), L""); + s = std::regex_replace(s, std::wregex(L"#[0-9a-fA-F]+;([^%#]+)(%r)?"), L"$1"); + s = std::regex_replace(s, std::wregex(L"\\\\n"), L""); + static std::wstring last; + if(last.find(s)!=last.npos)return false; + last=s; + return write_string_overwrite(data,len,s); +} +bool FPCSG00751(void* data, size_t* len, HookParam* hp){ + auto s = std::string((char*)data,*len); + s = std::regex_replace(s, std::regex("[\\s]"), ""); + s = std::regex_replace(s, std::regex("@[a-z]"), ""); + //s = std::regex_replace(s, std::regex("$"), ""); + strReplace(s,"\x81\x90",""); + return write_string_overwrite(data,len,s); +} +bool FPCSG00706(void* data, size_t* len, HookParam* hp){ + auto s = std::wstring((wchar_t*)data,*len/2); + s = std::regex_replace(s, std::wregex(L"
"), L""); + return write_string_overwrite(data,len,s); +} +bool FPCSG00696(void* data, size_t* len, HookParam* hp){ + auto s = std::string((char*)data,*len); + //.replace(/㌔/g, '⁉') + //.replace(/㍉/g, '!!') + strReplace(s,"\x87\x60",""); + strReplace(s,"\x87\x5f",""); + return write_string_overwrite(data,len,s); +} +bool FPCSG00389(void* data, size_t* len, HookParam* hp){ + auto s = std::string((char*)data,*len); + s = std::regex_replace(s, std::regex("[\\s]"), ""); + s = std::regex_replace(s, std::regex("(#n)+"), ""); + s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); + s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), ""); + return write_string_overwrite(data,len,s); +} +bool FPCSG00216(void* data, size_t* len, HookParam* hp){ + auto s = std::string((char*)data,*len); + s = std::regex_replace(s, std::regex("[\\s]"), ""); + s = std::regex_replace(s, std::regex("(#n)+"), ""); + s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); + s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), ""); + return write_string_overwrite(data,len,s); +} +namespace{ +auto _=[](){ + emfunctionhooks={ + //Tsuihou Senkyo + {0x8002e176,{0,0,0,0,FPCSG01023,"PCSG01023"}},//dialogue+name,sjis + //死神と少女 Shinigami to Shoujo + {0x800204ba,{0,2,0,0,FPCSG01282<0>,"PCSG01282"}},//dialogueNVL,sjis + {0x8000f00e,{0,1,0,0,FPCSG01282<1>,"PCSG01282"}},//dialogue main + {0x80011f1a,{0,0,0,0,FPCSG01282<2>,"PCSG01282"}},//Name + {0x8001ebac,{0,1,0,0,FPCSG01282<3>,"PCSG01282"}},//choices + //神凪ノ杜 Kannagi no Mori Satsukiame Tsuzuri + {0x828bb50c,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,0,"PCSG01268"}},//dialogue + {0x828ba9b6,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,0,"PCSG01268"}},//name + {0x8060D376,{CODEC_UTF8,0,0,0,0,"PCSG01268"}},//vita3k v0.2.0 can't find 0x828bb50c && 0x828ba9b6, unknown reason. + //Sanzen Sekai Yuugi ~MultiUniverse Myself~ + {0x8005ae24,{0,0,0,0,0,"PCSG01194"}},//dialouge+name,sjis,need remap jis char,to complex + // Marginal #4 Road to Galaxy + {0x8002ff90,{CODEC_UTF8,0,0,0,FPCSG01008,"PCSG01008"}},//text + //BLACK WOLVES SAGA -Weiβ und Schwarz- + {0x8004ed22,{CODEC_UTF8,0,0,0,FPCSG01008,"PCSG00935"}},//name + {0x8006d202,{CODEC_UTF8,1,2,0,FPCSG01008,"PCSG00935"}},//text + //New Game! The Challenge Stage! + {0x8012674c,{CODEC_UTF8,0,0,TPCSG00903,FPCSG00903,"PCSG00903"}}, + //Kenka Banchou Otome + {0x80009722,{CODEC_UTF16,0,0,0,FPCSG00839,"PCSG00839"}}, + //Arcana famiglia -La storia della Arcana Famiglia- + {0x80070e30,{0,2,0,0,FPCSG00751,"PCSG00751"}},//all,sjis + {0x80070cdc,{0,1,0,0,FPCSG00751,"PCSG00751"}},//text + //もし、この世界に神様がいるとするならば。 Moshi, Kono Sekai ni Kami-sama ga Iru to Suru Naraba. + {0x80c1f270,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,FPCSG00706,"PCSG00706"}},//dialogue + {0x80d48bfc,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<1>,FPCSG00706,"PCSG00706"}},//Dictionary1 + {0x80d48c20,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,FPCSG00706,"PCSG00706"}},//Dictionary2 + //Angelique Retour + {0x8008bd1a,{0,1,0,0,FPCSG00696,"PCSG00696"}},//text1,sjis + {0x8008cd48,{0,0,0,0,FPCSG00696,"PCSG00696"}},//text2 + {0x8008f75a,{0,0,0,0,FPCSG00696,"PCSG00696"}},//choice + //Tsuki ni Yorisou Otome no Sahou + {0x8002aefa,{0,2,0,0,0,"PCSG00648"}},//dialogue,sjis + //MARGINAL#4 IDOL OF SUPERNOVA + {0x800718f8,{0,0,0,0,FPCSG00448,"PCSG00448"}},//dialogue,sjis + //Nekketsu Inou Bukatsu-tan Trigger Kiss + {0x8004e44a,{0,0,0,0,FPCSG00410,"PCSG00410"}},//dialogue,sjis + //バイナリースター Binary Star + {0x80058608,{0,1,0,0,FPCSG00389,"PCSG00389"}},//dialogue,sjis + {0x80021292,{0,0,0,0,FPCSG00389,"PCSG00389"}},//name + //Amagami + //to complex. + //Rui wa Tomo o Yobu + {0x81003db0,{CODEC_UTF8,1,0,0,FPCSG00839,"PCSG00216"}},//dialogue + + }; + return 1; +}(); +} \ No newline at end of file diff --git a/LunaHook/engine64/vita3k.h b/LunaHook/engine64/vita3k.h new file mode 100644 index 0000000..60b58c7 --- /dev/null +++ b/LunaHook/engine64/vita3k.h @@ -0,0 +1,13 @@ +#include"engine.h" + +class vita3k:public ENGINE{ + public: + vita3k(){ + + check_by=CHECK_BY::FILE; + is_engine_certain=false; + check_by_target=L"Vita3K.exe"; + }; + bool attach_function(); +}; + \ No newline at end of file diff --git a/LunaHook/engine64/yuzusuyu.cpp b/LunaHook/engine64/yuzusuyu.cpp index a466566..c2ceb07 100644 --- a/LunaHook/engine64/yuzusuyu.cpp +++ b/LunaHook/engine64/yuzusuyu.cpp @@ -57,17 +57,6 @@ uintptr_t getDoJitAddress() { */ } -uintptr_t* argidx(hook_stack* stack,int idx){ - auto offset=0; - switch (idx) - { - case 0:offset=get_reg(regs::rcx);break; - case 1:offset=get_reg(regs::rdx);break; - case 2:offset=get_reg(regs::r8);break; - case 3:offset=get_reg(regs::r9);break; - } - return (uintptr_t*)((uintptr_t)stack+sizeof(hook_stack)-sizeof(uintptr_t)+offset); -} struct emfuncinfo{ uint64_t type; diff --git a/LunaHook/enginecollection64.cpp b/LunaHook/enginecollection64.cpp index 9393585..1f64bbf 100644 --- a/LunaHook/enginecollection64.cpp +++ b/LunaHook/enginecollection64.cpp @@ -16,6 +16,7 @@ #include"engine64/TYPEMOON.h" #include"engine64/LightVN.h" #include"engine64/yuzusuyu.h" +#include"engine64/vita3k.h" std::vector ignore_engines(){ return{ }; } std::vector unsafe_check_atlast(){ return{ }; } @@ -39,6 +40,7 @@ std::vector check_engines(){ new ENTERGRAM, new yuzusuyu, new PPSSPP, + new vita3k }; } diff --git a/LunaHook/engines/emujitarg.hpp b/LunaHook/engines/emujitarg.hpp index 7066561..c933eb2 100644 --- a/LunaHook/engines/emujitarg.hpp +++ b/LunaHook/engines/emujitarg.hpp @@ -13,6 +13,19 @@ public: } }; } +namespace VITA3K +{ +class emu_arg{ + hook_stack* stack; +public: + emu_arg(hook_stack* stack_):stack(stack_){}; + uintptr_t operator [](int idx){ + auto base=stack->r13; + auto args=(uint32_t*)stack->r15; + return base+args[idx]; + } +}; +} #endif namespace PPSSPP{ inline DWORD x86_baseaddr; diff --git a/LunaHook/hookfinder.cc b/LunaHook/hookfinder.cc index e7f34be..8c4a88c 100644 --- a/LunaHook/hookfinder.cc +++ b/LunaHook/hookfinder.cc @@ -195,6 +195,9 @@ void SafeSendJitVeh(hook_stack* stack,uintptr_t address,uintptr_t em_addr,JITTYP case JITTYPE::YUZU: str=(char*)YUZU::emu_arg(stack)[i]; break; + case JITTYPE::VITA3K: + str=(char*)VITA3K::emu_arg(stack)[i]; + break; #endif case JITTYPE::PPSSPP: str=(char*)PPSSPP::emu_arg(stack)[i]; diff --git a/LunaHook/stackoffset.hpp b/LunaHook/stackoffset.hpp index 11cc81c..e9e1bf4 100644 --- a/LunaHook/stackoffset.hpp +++ b/LunaHook/stackoffset.hpp @@ -107,4 +107,17 @@ inline uintptr_t regof(regs reg,hook_stack* stack){ #define GETARG2 get_reg(regs::rdx) #define GETARG3 get_reg(regs::r8) #define GETARG4 get_reg(regs::r9) + + +inline uintptr_t* argidx(hook_stack* stack,int idx){ + auto offset=0; + switch (idx) + { + case 0:offset=get_reg(regs::rcx);break; + case 1:offset=get_reg(regs::rdx);break; + case 2:offset=get_reg(regs::r8);break; + case 3:offset=get_reg(regs::r9);break; + } + return (uintptr_t*)((uintptr_t)stack+sizeof(hook_stack)-sizeof(uintptr_t)+offset); +} #endif \ No newline at end of file diff --git a/LunaHook/texthook.cc b/LunaHook/texthook.cc index 65fea59..535b45d 100644 --- a/LunaHook/texthook.cc +++ b/LunaHook/texthook.cc @@ -149,6 +149,8 @@ uintptr_t jitgetaddr(hook_stack* stack, HookParam* hp){ switch (hp->jittype) { #ifdef _WIN64 + case JITTYPE::VITA3K: + return VITA3K::emu_arg(stack)[hp->argidx]; case JITTYPE::YUZU: return YUZU::emu_arg(stack)[hp->argidx]; #endif diff --git a/include/hookcode.cpp b/include/hookcode.cpp index e44e4e9..9012729 100644 --- a/include/hookcode.cpp +++ b/include/hookcode.cpp @@ -61,7 +61,8 @@ namespace hp.jittype=JITTYPE::YUZU; else if(endWith(HCode,L":JIT:PPSSPP")) hp.jittype=JITTYPE::PPSSPP; - + else if(endWith(HCode,L":JIT:VITA3K")) + hp.jittype=JITTYPE::VITA3K; // {A|B|W|H|S|Q|V|M} switch (HCode[0]) @@ -184,7 +185,6 @@ namespace if(hp.jittype!=JITTYPE::PC){ hp.emu_addr=hp.address; hp.argidx=hp.offset; - hp.padding=0; hp.offset=0; hp.address=0; hp.type &= ~MODULE_OFFSET; @@ -353,6 +353,10 @@ namespace break; case JITTYPE::PPSSPP: HCode+=L":JIT:PPSSPP"; + break; + case JITTYPE::VITA3K: + HCode+=L":JIT:VITA3K"; + break; } } diff --git a/include/types.h b/include/types.h index bcaacde..b3f6d18 100644 --- a/include/types.h +++ b/include/types.h @@ -80,7 +80,8 @@ inline hook_stack* get_hook_stack(uintptr_t lpDataBase){ enum class JITTYPE{ PC,//not a jit YUZU, - PPSSPP + PPSSPP, + VITA3K }; struct HookParam {