jit hook search

1

1

Update texthook.cc

1

Update hookfinder.cc

yuzu/ppsspp hook search

Update hookfinder.cc

Update hookfinder.cc

1

1

1
This commit is contained in:
恍兮惚兮 2024-03-31 19:00:26 +08:00
parent eaf7fa6e6a
commit 964868b2d2
18 changed files with 755 additions and 484 deletions

View File

@ -1,7 +1,8 @@
#include"yuzusuyu.h"
#include"mages/mages.h"
#include"hookfinder.h"
#include"emujitarg.hpp"
namespace{
auto isFastMem = true;
auto isVirtual = true;//Process.arch === 'x64' && Process.platform === 'windows';
@ -68,18 +69,10 @@ uintptr_t* argidx(hook_stack* stack,int idx){
return (uintptr_t*)((uintptr_t)stack+sizeof(hook_stack)-sizeof(uintptr_t)+offset);
}
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=(uintptr_t*)stack->r15;
return base+args[idx];
}
};
struct emfuncinfo{
const char* hookname;
uint64_t type;
int argidx;int padding;
void* hookfunc;
void* filterfun;
const wchar_t* _id;
@ -95,49 +88,35 @@ bool checkiscurrentgame(const emfuncinfo& em){
}
return false;
}
template<int index>
void simpleutf32getter(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
auto address=emu_arg(stack)[index];
auto s=utf32_to_utf16((uint32_t*)address,u32strlen((uint32_t*)address));
write_string_new(data,len,s);
}
template<int index,int offset=0>
void simpleutf8getter(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
auto address=emu_arg(stack)[index]+offset;
hp->type=USING_STRING|CODEC_UTF8|NO_CONTEXT|BREAK_POINT;
*data=address;*len=strlen((char*)address);
}
template<int index,DWORD _type=0>
void simpleutf16getter(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
auto address=emu_arg(stack)[index];
hp->type=USING_STRING|CODEC_UTF16|NO_CONTEXT|BREAK_POINT|_type;
*data=address;*len=wcslen((wchar_t*)address)*2;
}
}
bool yuzusuyu::attach_function()
{
ConsoleOutput("[Compatibility] Yuzu 1616+");
ConsoleOutput("[Compatibility] Yuzu 1616+");
auto DoJitPtr=getDoJitAddress();
if(DoJitPtr==0)return false;
ConsoleOutput("DoJitPtr %p",DoJitPtr);
jitaddrclear();
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 = *(uintptr_t*)descriptor;
em_address-=0x80004000;
if(emfunctionhooks.find(em_address)==emfunctionhooks.end() || !entrypoint)return;
auto op=emfunctionhooks.at(em_address);
jitaddraddr(em_address,entrypoint,JITTYPE::YUZU);
auto em_address_off=em_address- 0x80004000;
if(emfunctionhooks.find(em_address_off)==emfunctionhooks.end() || !entrypoint)return;
auto op=emfunctionhooks.at(em_address_off);
if(!(checkiscurrentgame(op)))return;
HookParam hpinternal;
hpinternal.address=entrypoint;
hpinternal.type=CODEC_UTF16|USING_STRING|NO_CONTEXT|BREAK_POINT;
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::YUZU;
NewHook(hpinternal,op.hookname);
};
@ -145,7 +124,7 @@ bool yuzusuyu::attach_function()
}
void _0100978013276000(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
auto s=mages::readString(emu_arg(stack)[0],0);
auto s=mages::readString(YUZU::emu_arg(stack)[0],0);
write_string_new(data,len,s);
}
@ -174,7 +153,7 @@ bool F010045C0109F2000(void* data, size_t* len, HookParam* hp){
template<int index>
void T0100A1E00BFEA000(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
auto address=emu_arg(stack)[index];
auto address=YUZU::emu_arg(stack)[index];
*len=(*(WORD*)(address+0x10))*2;
*data=address+0x14;
}
@ -365,7 +344,7 @@ bool F01000200194AE000(void* data, size_t* len, HookParam* hp){
return write_string_overwrite(data,len,s);
}
bool F0100EA001A626000(void* data, size_t* len, HookParam* hp){
auto s=std::wstring((wchar_t*)data,*len/2);
auto s=utf32_to_utf16((uint32_t*)data,*len/4);
if (s == L"  ") {
return false;
}
@ -377,20 +356,22 @@ bool F0100EA001A626000(void* data, size_t* len, HookParam* hp){
s = std::regex_replace(s, std::wregex(L"#T2[^#]+"), L"");
s = std::regex_replace(s, std::wregex(L"#T\\d"), L"");
}
return write_string_overwrite(data,len,s);
auto u32=utf16_to_utf32(s.c_str(),s.size());
return write_string_overwrite(data,len,u32);
}
bool F0100F7E00DFC8000(void* data, size_t* len, HookParam* hp){
auto s=std::wstring((wchar_t*)data,*len/2);
auto s=utf32_to_utf16((uint32_t*)data,*len/4);
s = std::regex_replace(s, std::wregex(L"[\\s]"), L" ");
s = std::regex_replace(s, std::wregex(L"#KW"), L"");
s = std::regex_replace(s, std::wregex(L"#C\\(TR,0xff0000ff\\)"), L"");
s = std::regex_replace(s, std::wregex(L"#P\\(.*\\)"), L"");
return write_string_overwrite(data,len,s);
auto u32=utf16_to_utf32(s.c_str(),s.size());
return write_string_overwrite(data,len,u32);
}
void T0100982015606000(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
auto address=emu_arg(stack)[1];
auto address=YUZU::emu_arg(stack)[1];
*len=(*(DWORD*)(address+0x10))*2;
*data=address+0x14;
}
@ -410,79 +391,80 @@ bool F0100925014864000(void* data, size_t* len, HookParam* hp){
}
bool F0100936018EB4000(void* data, size_t* len, HookParam* hp){
auto s=std::wstring((wchar_t*)data,*len/2);
auto s=utf32_to_utf16((uint32_t*)data,*len/4);
s = std::regex_replace(s, std::wregex(L"<[^>]+>"), L"");
s = std::regex_replace(s, std::wregex(L"\n+"), L" ");
return write_string_overwrite(data,len,s);
auto u32=utf16_to_utf32(s.c_str(),s.size());
return write_string_overwrite(data,len,u32);
}
namespace{
auto _=[](){
emfunctionhooks={
{0x8003eeac - 0x80004000,{"Memories Off",_0100978013276000,0,L"0100978013276000",L"1.0.0"}},
{0x8003eebc - 0x80004000,{"Memories Off",_0100978013276000,0,L"0100978013276000",L"1.0.1"}},
{0x8003eeac - 0x80004000,{"Memories Off",CODEC_UTF16,0,0,_0100978013276000,0,L"0100978013276000",L"1.0.0"}},
{0x8003eebc - 0x80004000,{"Memories Off",CODEC_UTF16,0,0,_0100978013276000,0,L"0100978013276000",L"1.0.1"}},
// Shiro to Kuro no Alice
{0x80013f20 - 0x80004000,{"Shiro to Kuro no Alice",simpleutf8getter<0>,NewLineCharFilterW,L"0100A460141B8000",L"1.0.0"}},
{0x80013f94 - 0x80004000,{"Shiro to Kuro no Alice",simpleutf8getter<0>,NewLineCharFilterW,L"0100A460141B8000",L"1.0.0"}},
{0x8001419c - 0x80004000,{"Shiro to Kuro no Alice",simpleutf8getter<0>,NewLineCharFilterW,L"0100A460141B8000",L"1.0.0"}},
{0x80013f20 - 0x80004000,{"Shiro to Kuro no Alice",CODEC_UTF8,0,0,0,NewLineCharFilterW,L"0100A460141B8000",L"1.0.0"}},
{0x80013f94 - 0x80004000,{"Shiro to Kuro no Alice",CODEC_UTF8,0,0,0,NewLineCharFilterW,L"0100A460141B8000",L"1.0.0"}},
{0x8001419c - 0x80004000,{"Shiro to Kuro no Alice",CODEC_UTF8,0,0,0,NewLineCharFilterW,L"0100A460141B8000",L"1.0.0"}},
// Shiro to Kuro no Alice -Twilight line-
{0x80014260 - 0x80004000,{"Shiro to Kuro no Alice -Twilight line-",simpleutf8getter<0>,NewLineCharFilterW,L"0100A460141B8000",L"1.0.0"}},
{0x800142d4 - 0x80004000,{"Shiro to Kuro no Alice -Twilight line-",simpleutf8getter<0>,NewLineCharFilterW,L"0100A460141B8000",L"1.0.0"}},
{0x800144dc - 0x80004000,{"Shiro to Kuro no Alice -Twilight line-",simpleutf8getter<0>,NewLineCharFilterW,L"0100A460141B8000",L"1.0.0"}},
{0x80014260 - 0x80004000,{"Shiro to Kuro no Alice -Twilight line-",CODEC_UTF8,0,0,0,NewLineCharFilterW,L"0100A460141B8000",L"1.0.0"}},
{0x800142d4 - 0x80004000,{"Shiro to Kuro no Alice -Twilight line-",CODEC_UTF8,0,0,0,NewLineCharFilterW,L"0100A460141B8000",L"1.0.0"}},
{0x800144dc - 0x80004000,{"Shiro to Kuro no Alice -Twilight line-",CODEC_UTF8,0,0,0,NewLineCharFilterW,L"0100A460141B8000",L"1.0.0"}},
{0x80072d00 - 0x80004000,{"CLANNAD",simpleutf16getter<1,FULL_STRING>,F0100A3A00CC7E000,L"0100A3A00CC7E000",L"1.0.0"}},
{0x80072d30 - 0x80004000,{"CLANNAD",simpleutf16getter<1,FULL_STRING>,F0100A3A00CC7E000,L"0100A3A00CC7E000",L"1.0.7"}},
{0x80072d00 - 0x80004000,{"CLANNAD",CODEC_UTF16|FULL_STRING,1,0,0, F0100A3A00CC7E000,L"0100A3A00CC7E000",L"1.0.0"}},
{0x80072d30 - 0x80004000,{"CLANNAD",CODEC_UTF16|FULL_STRING,1,0,0,F0100A3A00CC7E000,L"0100A3A00CC7E000",L"1.0.7"}},
{0x800e3424 - 0x80004000,{"VARIABLE BARRICADE NS",simpleutf8getter<0>,F010045C0109F2000,L"010045C0109F2000",L"1.0.1"}},//"System Messages + Choices"), //Also includes the names of characters,
{0x800fb080 - 0x80004000,{"VARIABLE BARRICADE NS",simpleutf8getter<3>,F010045C0109F2000,L"010045C0109F2000",L"1.0.1"}},//Main Text
{0x800e3424 - 0x80004000,{"VARIABLE BARRICADE NS",CODEC_UTF8,0,0,0,F010045C0109F2000,L"010045C0109F2000",L"1.0.1"}},//"System Messages + Choices"), //Also includes the names of characters,
{0x800fb080 - 0x80004000,{"VARIABLE BARRICADE NS",CODEC_UTF8,3,0,0,F010045C0109F2000,L"010045C0109F2000",L"1.0.1"}},//Main Text
{0x805bba5c - 0x80004000,{"AMNESIA for Nintendo Switch",T0100A1E00BFEA000<2>,F0100A1E00BFEA000,L"0100A1E00BFEA000",L"1.0.1"}},//dialogue
{0x805e9930 - 0x80004000,{"AMNESIA for Nintendo Switch",T0100A1E00BFEA000<2>,F0100A1E00BFEA000,L"0100A1E00BFEA000",L"1.0.1"}},//choice
{0x805e7fd8 - 0x80004000,{"AMNESIA for Nintendo Switch",T0100A1E00BFEA000<2>,F0100A1E00BFEA000,L"0100A1E00BFEA000",L"1.0.1"}},//name
{0x805bba5c - 0x80004000,{"AMNESIA for Nintendo Switch",CODEC_UTF16,0,0,T0100A1E00BFEA000<2>,F0100A1E00BFEA000,L"0100A1E00BFEA000",L"1.0.1"}},//dialogue
{0x805e9930 - 0x80004000,{"AMNESIA for Nintendo Switch",CODEC_UTF16,0,0,T0100A1E00BFEA000<2>,F0100A1E00BFEA000,L"0100A1E00BFEA000",L"1.0.1"}},//choice
{0x805e7fd8 - 0x80004000,{"AMNESIA for Nintendo Switch",CODEC_UTF16,0,0,T0100A1E00BFEA000<2>,F0100A1E00BFEA000,L"0100A1E00BFEA000",L"1.0.1"}},//name
{0x80095010 - 0x80004000,{"Chou no Doku Hana no Kusari Taishou Tsuya Koi Ibun",simpleutf16getter<1>,F0100A1200CA3C000,L"0100A1200CA3C000",L"2.0.1"}},//Main Text + Names
{0x80095010 - 0x80004000,{"Chou no Doku Hana no Kusari Taishou Tsuya Koi Ibun",CODEC_UTF16,1,0,0,F0100A1200CA3C000,L"0100A1200CA3C000",L"2.0.1"}},//Main Text + Names
{0x80a05170 - 0x80004000,{"Live a Live",simpleutf16getter<0>,F0100C29017106000,L"0100C29017106000",L"1.0.0"}},
{0x80a05170 - 0x80004000,{"Live a Live",CODEC_UTF16,0,0,0,F0100C29017106000,L"0100C29017106000",L"1.0.0"}},
{0x8049d968 - 0x80004000,{"Sakura no Kumo * Scarlet no Koi",simpleutf8getter<0,1>,F01006590155AC000,L"01006590155AC000",L"1.0.0"}},//name
{0x8049d980 - 0x80004000,{"Sakura no Kumo * Scarlet no Koi",simpleutf8getter<0>,F01006590155AC000,L"01006590155AC000",L"1.0.0"}},//dialogue
{0x8049d968 - 0x80004000,{"Sakura no Kumo * Scarlet no Koi",CODEC_UTF8,0,1,0,F01006590155AC000,L"01006590155AC000",L"1.0.0"}},//name
{0x8049d980 - 0x80004000,{"Sakura no Kumo * Scarlet no Koi",CODEC_UTF8,0,0,0,F01006590155AC000,L"01006590155AC000",L"1.0.0"}},//dialogue
{0x80557408 - 0x80004000,{"Majestic Majolical",simpleutf8getter<0>,F01000200194AE000,L"01000200194AE000",L"1.0.0"}},//name
{0x8059ee94 - 0x80004000,{"Majestic Majolical",simpleutf8getter<3>,F01000200194AE000,L"01000200194AE000",L"1.0.0"}},//player name
{0x80557420 - 0x80004000,{"Majestic Majolical",simpleutf8getter<0>,F01000200194AE000,L"01000200194AE000",L"1.0.0"}},//dialogue
{0x80557408 - 0x80004000,{"Majestic Majolical",CODEC_UTF8,0,0,0,F01000200194AE000,L"01000200194AE000",L"1.0.0"}},//name
{0x8059ee94 - 0x80004000,{"Majestic Majolical",CODEC_UTF8,3,0,0,F01000200194AE000,L"01000200194AE000",L"1.0.0"}},//player name
{0x80557420 - 0x80004000,{"Majestic Majolical",CODEC_UTF8,0,0,0,F01000200194AE000,L"01000200194AE000",L"1.0.0"}},//dialogue
{0x8017ad54 - 0x80004000,{"Matsurika no Kei",simpleutf32getter<1>,F0100EA001A626000,L"0100EA001A626000",L"1.0.0"}},// text
{0x80174d4c - 0x80004000,{"Matsurika no Kei",simpleutf32getter<1>,F0100EA001A626000,L"0100EA001A626000",L"1.0.0"}},// name
{0x8017ad54 - 0x80004000,{"Matsurika no Kei",CODEC_UTF32,1,0,0,F0100EA001A626000,L"0100EA001A626000",L"1.0.0"}},// text
{0x80174d4c - 0x80004000,{"Matsurika no Kei",CODEC_UTF32,1,0,0,F0100EA001A626000,L"0100EA001A626000",L"1.0.0"}},// name
{0x80057910 - 0x80004000,{"Cupid Parasite",simpleutf32getter<2>,F0100F7E00DFC8000,L"0100F7E00DFC8000",L"1.0.1"}},// name + text
{0x80169df0 - 0x80004000,{"Cupid Parasite",simpleutf32getter<0>,F0100F7E00DFC8000,L"0100F7E00DFC8000",L"1.0.1"}},// choice
{0x80057910 - 0x80004000,{"Cupid Parasite",CODEC_UTF32,2,0,0,F0100F7E00DFC8000,L"0100F7E00DFC8000",L"1.0.1"}},// name + text
{0x80169df0 - 0x80004000,{"Cupid Parasite",CODEC_UTF32,0,0,0,F0100F7E00DFC8000,L"0100F7E00DFC8000",L"1.0.1"}},// choice
{0x80075190 - 0x80004000,{"Radiant Tale",simpleutf8getter<1>,F0100925014864000,L"0100925014864000",L"1.0.0"}},// prompt
{0x8002fb18 - 0x80004000,{"Radiant Tale",simpleutf8getter<0>,F0100925014864000,L"0100925014864000",L"1.0.0"}},// name
{0x8002fd7c - 0x80004000,{"Radiant Tale",simpleutf8getter<0>,F0100925014864000,L"0100925014864000",L"1.0.0"}},// text
{0x80075190 - 0x80004000,{"Radiant Tale",CODEC_UTF8,1,0,0,F0100925014864000,L"0100925014864000",L"1.0.0"}},// prompt
{0x8002fb18 - 0x80004000,{"Radiant Tale",CODEC_UTF8,0,0,0,F0100925014864000,L"0100925014864000",L"1.0.0"}},// name
{0x8002fd7c - 0x80004000,{"Radiant Tale",CODEC_UTF8,0,0,0,F0100925014864000,L"0100925014864000",L"1.0.0"}},// text
{0x80462DD4 - 0x80004000,{"MUSICUS",simpleutf8getter<0,1>,F01006590155AC000,L"01000130150FA000",L"1.0.0"}},// name
{0x80462DEC - 0x80004000,{"MUSICUS",simpleutf8getter<0>,F01006590155AC000,L"01000130150FA000",L"1.0.0"}},// dialogue 1
{0x80480d4c - 0x80004000,{"MUSICUS",simpleutf8getter<0>,F01006590155AC000,L"01000130150FA000",L"1.0.0"}},// dialogue 2
{0x804798e0 - 0x80004000,{"MUSICUS",simpleutf8getter<0>,F01006590155AC000,L"01000130150FA000",L"1.0.0"}},// choice
{0x80462DD4 - 0x80004000,{"MUSICUS",CODEC_UTF8,0,1,0,F01006590155AC000,L"01000130150FA000",L"1.0.0"}},// name
{0x80462DEC - 0x80004000,{"MUSICUS",CODEC_UTF8,0,0,0,F01006590155AC000,L"01000130150FA000",L"1.0.0"}},// dialogue 1
{0x80480d4c - 0x80004000,{"MUSICUS",CODEC_UTF8,0,0,0,F01006590155AC000,L"01000130150FA000",L"1.0.0"}},// dialogue 2
{0x804798e0 - 0x80004000,{"MUSICUS",CODEC_UTF8,0,0,0,F01006590155AC000,L"01000130150FA000",L"1.0.0"}},// choice
{0x80046700 - 0x80004000,{"CHAOS;HEAD NOAH",_0100978013276000,0,L"0100957016B90000",L"1.0.0"}},
{0x8003A2c0 - 0x80004000,{"CHAOS;HEAD NOAH",_0100978013276000,0,L"0100957016B90000",L"1.0.0"}},// choice
{0x8003EAB0 - 0x80004000,{"CHAOS;HEAD NOAH",_0100978013276000,0,L"0100957016B90000",L"1.0.0"}},// TIPS list (menu)
{0x8004C648 - 0x80004000,{"CHAOS;HEAD NOAH",_0100978013276000,0,L"0100957016B90000",L"1.0.0"}},// system message
{0x80050374 - 0x80004000,{"CHAOS;HEAD NOAH",_0100978013276000,0,L"0100957016B90000",L"1.0.0"}},// TIPS (red)
{0x80046700 - 0x80004000,{"CHAOS;HEAD NOAH",CODEC_UTF16,0,0,_0100978013276000,0,L"0100957016B90000",L"1.0.0"}},
{0x8003A2c0 - 0x80004000,{"CHAOS;HEAD NOAH",CODEC_UTF16,0,0,_0100978013276000,0,L"0100957016B90000",L"1.0.0"}},// choice
{0x8003EAB0 - 0x80004000,{"CHAOS;HEAD NOAH",CODEC_UTF16,0,0,_0100978013276000,0,L"0100957016B90000",L"1.0.0"}},// TIPS list (menu)
{0x8004C648 - 0x80004000,{"CHAOS;HEAD NOAH",CODEC_UTF16,0,0,_0100978013276000,0,L"0100957016B90000",L"1.0.0"}},// system message
{0x80050374 - 0x80004000,{"CHAOS;HEAD NOAH",CODEC_UTF16,0,0,_0100978013276000,0,L"0100957016B90000",L"1.0.0"}},// TIPS (red)
{0x80ac4d88 - 0x80004000,{"Story of Seasons a Wonderful Life",simpleutf32getter<0>,F0100936018EB4000,L"0100936018EB4000",L"1.0.3"}},// Main text
{0x808f7e84 - 0x80004000,{"Story of Seasons a Wonderful Life",simpleutf32getter<0>,F0100936018EB4000,L"0100936018EB4000",L"1.0.3"}},// Item name
{0x80bdf804 - 0x80004000,{"Story of Seasons a Wonderful Life",simpleutf32getter<0>,F0100936018EB4000,L"0100936018EB4000",L"1.0.3"}},// Item description
{0x80ac4d88 - 0x80004000,{"Story of Seasons a Wonderful Life",CODEC_UTF32,0,0,F0100936018EB4000,L"0100936018EB4000",L"1.0.3"}},// Main text
{0x808f7e84 - 0x80004000,{"Story of Seasons a Wonderful Life",CODEC_UTF32,0,0,F0100936018EB4000,L"0100936018EB4000",L"1.0.3"}},// Item name
{0x80bdf804 - 0x80004000,{"Story of Seasons a Wonderful Life",CODEC_UTF32,0,0,F0100936018EB4000,L"0100936018EB4000",L"1.0.3"}},// Item description
{0x81e75940 - 0x80004000,{"Hamefura Pirates",T0100982015606000,F0100982015606000,L"0100982015606000",L"1.0.0"}},// Hamekai.TalkPresenter$$AddMessageBacklog
{0x81c9ae60 - 0x80004000,{"Hamefura Pirates",T0100982015606000,F0100982015606000,L"0100982015606000",L"1.0.0"}},// Hamekai.ChoicesText$$SetText
{0x81eb7dc0 - 0x80004000,{"Hamefura Pirates",T0100982015606000,F0100982015606000,L"0100982015606000",L"1.0.0"}},// Hamekai.ShortStoryTextView$$AddText
{0x81e75940 - 0x80004000,{"Hamefura Pirates",CODEC_UTF16,0,0,T0100982015606000,F0100982015606000,L"0100982015606000",L"1.0.0"}},// Hamekai.TalkPresenter$$AddMessageBacklog
{0x81c9ae60 - 0x80004000,{"Hamefura Pirates",CODEC_UTF16,0,0,T0100982015606000,F0100982015606000,L"0100982015606000",L"1.0.0"}},// Hamekai.ChoicesText$$SetText
{0x81eb7dc0 - 0x80004000,{"Hamefura Pirates",CODEC_UTF16,0,0,T0100982015606000,F0100982015606000,L"0100982015606000",L"1.0.0"}},// Hamekai.ShortStoryTextView$$AddText
};
return 1;

View File

@ -0,0 +1,52 @@
#pragma once
#ifdef _WIN64
namespace YUZU
{
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=(uintptr_t*)stack->r15;
return base+args[idx];
}
};
}
#endif
namespace PPSSPP{
inline DWORD x86_baseaddr;
class emu_addr{
hook_stack* stack;
DWORD addr;
public:
emu_addr(hook_stack* stack_,DWORD addr_):stack(stack_),addr(addr_){};
operator uintptr_t(){
#ifndef _WIN64
auto base=x86_baseaddr;
#else
auto base=stack->rbx;
#endif
return base+addr;
}
operator DWORD*(){
return (DWORD*)(uintptr_t)*this;
}
};
class emu_arg{
hook_stack* stack;
public:
emu_arg(hook_stack* stack_):stack(stack_){};
uintptr_t operator [](int idx){
#ifndef _WIN64
auto args=stack->ebp;
#else
auto args=stack->r14;
#endif
auto offR = -0x80;
auto offset = offR + 0x10 + idx * 4;
return (uintptr_t)emu_addr(stack,*(uint32_t*)(args+offset));
}
};
}

View File

@ -283,25 +283,29 @@ bool hookPPSSPPDoJit(){
HookParam hp;
hp.address=DoJitPtr;//Jit::DoJit
ConsoleOutput("DoJitPtr %p",DoJitPtr);
jitaddrclear();
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){
auto em_address=stack->THISCALLARG1;
if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return;
if(!(checkiscurrentgame(emfunctionhooks.at(em_address))))return;
*(uintptr_t*)(hp->user_value)=em_address;
HookParam hpinternal;
hpinternal.user_value=em_address;
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){
hp->text_fun=nullptr;hp->type=HOOK_EMPTY;
auto ret=stack->RETADDR;
if(breakpoints.find(ret)!=breakpoints.end())return;
breakpoints.insert(ret);
auto em_address=hp->user_value;
auto em_address=*(uintptr_t*)(hp->user_value);
jitaddraddr(em_address,ret,JITTYPE::PPSSPP);
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);
#ifndef _WIN64
@ -317,17 +321,21 @@ bool hookPPSSPPDoJit(){
findbase=MemDbg::findBytes(sig,sizeof(sig),ret-0x1000,ret+0x1000);
if(!findbase)
ConsoleOutput("can't find emu_baseaddr");
ppsspp::x86_baseaddr=(*(DWORD*)(findbase+12))&0xffff0000;
ConsoleOutput("x86 base addr %p",x86_baseaddr);
PPSSPP::x86_baseaddr=(*(DWORD*)(findbase+12))&0xffff0000;
ConsoleOutput("x86 base addr %p",PPSSPP::x86_baseaddr);
#endif
HookParam hpinternal;
hpinternal.address=ret;
hpinternal.user_value=em_address;
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::PPSSPP;
NewHook(hpinternal,op.hookname);
};
NewHook(hpinternal,"DoJitPtrRet");
static auto once=NewHook(hpinternal,"DoJitPtrRet");
};
return NewHook(hp,"PPSSPPDoJit");

View File

@ -5,6 +5,8 @@ namespace ppsspp
struct emfuncinfo{
const char* hookname;
uint64_t type;
int argidx;int padding;
void* hookfunc;
void* filterfun;
const wchar_t* _id;

View File

@ -1,63 +1,5 @@
#include<queue>
namespace ppsspp{
inline DWORD x86_baseaddr;
}
namespace
{
template<int index,int offset=0>
void simple932getter(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
hp->type=USING_STRING|NO_CONTEXT;
hp->codepage=932;
auto address= emu_arg(stack)[index]+offset;
*data=address;*len=strlen((char*)address);
}
template<int index>
void simpleutf8getter(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
auto address=emu_arg(stack)[index];
hp->type=USING_STRING|CODEC_UTF8|NO_CONTEXT;
*data=address;*len=strlen((char*)address);
}
template<int index,DWORD _type=0>
void simpleutf16getter(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
auto address=emu_arg(stack)[index];
hp->type=USING_STRING|CODEC_UTF16|NO_CONTEXT|_type;
*data=address;*len=wcslen((wchar_t*)address)*2;
}
class emu_addr{
hook_stack* stack;
DWORD addr;
public:
emu_addr(hook_stack* stack_,DWORD addr_):stack(stack_),addr(addr_){};
operator uintptr_t(){
#ifndef _WIN64
auto base=ppsspp::x86_baseaddr;
#else
auto base=stack->rbx;
#endif
return base+addr;
}
operator DWORD*(){
return (DWORD*)(uintptr_t)*this;
}
};
class emu_arg{
hook_stack* stack;
public:
emu_arg(hook_stack* stack_):stack(stack_){};
uintptr_t operator [](int idx){
#ifndef _WIN64
auto args=stack->ebp;
#else
auto args=stack->r14;
#endif
auto offR = -0x80;
auto offset = offR + 0x10 + idx * 4;
return (uintptr_t)emu_addr(stack,*(uint32_t*)(args+offset));
}
};
}
#include"emujitarg.hpp"
bool ULJS00403_filter(void* data, size_t* len, HookParam* hp){
std::string result = std::string((char*)data,*len);
@ -70,21 +12,19 @@ bool ULJS00403_filter(void* data, size_t* len, HookParam* hp){
void ULJS00339(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
hp->type=USING_STRING|NO_CONTEXT;
hp->codepage=932;
auto a2= emu_arg(stack)[0];
auto a2= PPSSPP::emu_arg(stack)[0];
auto vm = *(DWORD*)(a2+(0x28));
vm=*(DWORD*)emu_addr(stack,vm);
vm=*(DWORD*)emu_addr(stack,vm+8);
uintptr_t address=emu_addr(stack,vm);
vm=*(DWORD*)PPSSPP::emu_addr(stack,vm);
vm=*(DWORD*)PPSSPP::emu_addr(stack,vm+8);
uintptr_t address=PPSSPP::emu_addr(stack,vm);
auto len1=*(DWORD*)(address+4);
auto p=address+0x20;
if(len1>4 && *(WORD*)(p+2)==0){
auto p1=*(DWORD*)(address+8);
vm=*(DWORD*)emu_addr(stack,vm);
vm=*(DWORD*)emu_addr(stack,vm+0xC);
p=emu_addr(stack,vm);
vm=*(DWORD*)PPSSPP::emu_addr(stack,vm);
vm=*(DWORD*)PPSSPP::emu_addr(stack,vm+0xC);
p=PPSSPP::emu_addr(stack,vm);
}
static int fm=0;
static std::string pre;
@ -215,9 +155,7 @@ namespace Corda{
}
void ULJM05428(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
hp->type=USING_STRING|NO_CONTEXT;
hp->codepage=932;
auto address= emu_arg(stack)[1];
auto address= PPSSPP::emu_arg(stack)[1];
bool haveNamve;
auto s=Corda::readBinaryString(address,&haveNamve);
*split=haveNamve;
@ -225,14 +163,12 @@ void ULJM05428(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* spl
}
void ULJM05054(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
hp->type=USING_STRING|NO_CONTEXT;
hp->codepage=932;
if (hp->user_value != 0x886162c) {
auto addr=emu_arg(stack)[0]+0x3c;
if (hp->emu_addr != 0x886162c) {
auto addr=PPSSPP::emu_arg(stack)[0]+0x3c;
*data=addr;*len=strlen((char*)addr);
return;
}
auto address= emu_arg(stack)[1];
auto address= PPSSPP::emu_arg(stack)[1];
bool haveNamve;
auto s=Corda::readBinaryString(address,&haveNamve);
*split=haveNamve;
@ -296,9 +232,7 @@ bool NPJH50505F(void* data, size_t* len, HookParam* hp){
}
void QNPJH50909(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
hp->type=USING_STRING|NO_CONTEXT;
hp->codepage=932;
uintptr_t addr = emu_addr(stack,0x08975110);
uintptr_t addr = PPSSPP::emu_addr(stack,0x08975110);
auto adr=addr+0x20;
auto len1=*(DWORD*)(addr+0x14)*2;
@ -308,27 +242,27 @@ void QNPJH50909(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* sp
}
namespace ppsspp{
std::unordered_map<uintptr_t,emfuncinfo>emfunctionhooks= {
{0x883bf34,{"Shinigami to Shoujo",simple932getter<1>,ULJS00403_filter,L"ULJS00403"}},
{0x0886775c,{"Amagami",ULJS00339,0,L"ULJS00339"}},// String.length()
{0x8814adc,{"Sekai de Ichiban Dame na Koi",simple932getter<0>,NPJH50909_filter,L"ULJM05878"}},// name + dialouge
{0x8850b2c,{"Sekai de Ichiban Dame na Koi",simple932getter<0>,NPJH50909_filter,L"ULJM05878"}},// onscreen toast
{0x0891D72C,{"Dunamis15",simpleutf8getter<0>,ULJM06119_filter,L"ULJM06119"}},
{0x88506d0,{"Princess Evangile Portable",simpleutf16getter<2>,ULJM06036_filter,L"ULJM06036"}},// [0x88506d0(2)...0x088507C0(?)] // name text text (line doubled)
{0x89b59dc,{"Kin'iro no Corda 2f",ULJM05428,0,L"ULJM05428"}},
{0x886162c,{"Kin'iro no Corda",ULJM05054,0,L"ULJM05054"}},// dialogue: 0x886162c (x1), 0x889d5fc-0x889d520(a2) fullLine
{0x8899e90,{"Kin'iro no Corda",ULJM05054,0,L"ULJM05054"}},// name 0x88da57c, 0x8899ca4 (x0, oneTime), 0x8899e90
{0x8952cfc,{"Sol Trigger",simpleutf8getter<0>,NPJH50619F,L"NPJH50619"}},//dialog
{0x884aad4,{"Sol Trigger",simpleutf8getter<0>,NPJH50619F,L"NPJH50619"}},//description
{0x882e1b0,{"Sol Trigger",simpleutf8getter<0>,NPJH50619F,L"NPJH50619"}},//system
{0x88bb108,{"Sol Trigger",simpleutf8getter<2>,NPJH50619F,L"NPJH50619"}},//battle tutorial
{0x89526a0,{"Sol Trigger",simpleutf8getter<0>,NPJH50619F,L"NPJH50619"}},//battle info
{0x88bcef8,{"Sol Trigger",simpleutf8getter<1>,NPJH50619F,L"NPJH50619"}},//battle talk
{0x8958490,{"Fate/EXTRA CCC",simple932getter<0>,NPJH50505F,L"NPJH50505"}},
{0x088630f8,{"Kamigami no Asobi InFinite",QNPJH50909,0,L"NPJH50909"}}, // text, choice (debounce trailing 400ms), TODO: better hook
{0x0887813c,{"Kamigami no Asobi InFinite",simple932getter<3,4>,0,L"NPJH50909"}}, // Question YN
{0x883bf34,{"Shinigami to Shoujo",0,1,0,0,ULJS00403_filter,L"ULJS00403"}},
{0x0886775c,{"Amagami",0,0,0,ULJS00339,0,L"ULJS00339"}},// String.length()
{0x8814adc,{"Sekai de Ichiban Dame na Koi",0,0,0,0,NPJH50909_filter,L"ULJM05878"}},// name + dialouge
{0x8850b2c,{"Sekai de Ichiban Dame na Koi",0,0,0,0,NPJH50909_filter,L"ULJM05878"}},// onscreen toast
{0x0891D72C,{"Dunamis15",CODEC_UTF8,0,0,0,ULJM06119_filter,L"ULJM06119"}},
{0x88506d0,{"Princess Evangile Portable",CODEC_UTF16,2,0,0,ULJM06036_filter,L"ULJM06036"}},// [0x88506d0(2)...0x088507C0(?)] // name text text (line doubled)
{0x89b59dc,{"Kin'iro no Corda 2f",0,0,0,ULJM05428,0,L"ULJM05428"}},
{0x886162c,{"Kin'iro no Corda",0,0,0,ULJM05054,0,L"ULJM05054"}},// dialogue: 0x886162c (x1), 0x889d5fc-0x889d520(a2) fullLine
{0x8899e90,{"Kin'iro no Corda",0,0,0,ULJM05054,0,L"ULJM05054"}},// name 0x88da57c, 0x8899ca4 (x0, oneTime), 0x8899e90
{0x8952cfc,{"Sol Trigger",CODEC_UTF8,0,0,0,NPJH50619F,L"NPJH50619"}},//dialog
{0x884aad4,{"Sol Trigger",CODEC_UTF8,0,0,0,NPJH50619F,L"NPJH50619"}},//description
{0x882e1b0,{"Sol Trigger",CODEC_UTF8,0,0,0,NPJH50619F,L"NPJH50619"}},//system
{0x88bb108,{"Sol Trigger",CODEC_UTF8,2,0,0,NPJH50619F,L"NPJH50619"}},//battle tutorial
{0x89526a0,{"Sol Trigger",CODEC_UTF8,0,0,0,NPJH50619F,L"NPJH50619"}},//battle info
{0x88bcef8,{"Sol Trigger",CODEC_UTF8,1,0,0,NPJH50619F,L"NPJH50619"}},//battle talk
{0x8958490,{"Fate/EXTRA CCC",0,0,0,0,NPJH50505F,L"NPJH50505"}},
{0x088630f8,{"Kamigami no Asobi InFinite",0,0,0,QNPJH50909,0,L"NPJH50909"}}, // text, choice (debounce trailing 400ms), TODO: better hook
{0x0887813c,{"Kamigami no Asobi InFinite",0,3,4,0,0,L"NPJH50909"}}, // Question YN
{0x88eeba4,{"Gekka Ryouran Romance",simple932getter<0,0>,ULJM05943F,L"ULJM05943"}},// a0 - monologue text
{0x8875e0c,{"Gekka Ryouran Romance",simple932getter<1,6>,ULJM05943F,L"ULJM05943"}},// a1 - dialogue text
{0x88eeba4,{"Gekka Ryouran Romance",0,0,0,0,ULJM05943F,L"ULJM05943"}},// a0 - monologue text
{0x8875e0c,{"Gekka Ryouran Romance",0,1,6,0,ULJM05943F,L"ULJM05943"}},// a1 - dialogue text
};
}

View File

@ -4,6 +4,8 @@
#include "util.h"
#include "MinHook.h"
#include"Lang/Lang.h"
#include"veh_hook.h"
#include"engines/emujitarg.hpp"
namespace
{
SearchParam sp;
@ -12,8 +14,11 @@ namespace
struct HookRecord
{
uint64_t address = 0;
uint64_t em_addr=0;
int argidx=0;
uintptr_t padding = 0;
int offset = 0;
JITTYPE jittype;
char text[MAX_STRING_SIZE] = {};
};
std::unique_ptr<HookRecord[]> records;
@ -122,7 +127,51 @@ bool IsBadReadPtr(void* data)
}
return cacheEntry == BAD_PAGE;
}
void DoSend(int i,uintptr_t address,char* str,uintptr_t padding,JITTYPE jittype=JITTYPE::PC,uintptr_t em_addr=0)
{
str += padding;
if (IsBadReadPtr(str) || IsBadReadPtr(str + MAX_STRING_SIZE)) return;
__try
{
int length = 0, sum = 0;
for (; (str[length] || str[length + 1]) && length < MAX_STRING_SIZE; length += 2) sum += *(uint16_t*)(str + length);
if (length > STRING && length < MAX_STRING_SIZE - 1)
{
// many duplicate results with same address, offset, and third/fourth character will be found: filter them out
uint64_t signature = ((uint64_t)i << 56) | ((uint64_t)(str[2] + str[3]) << 48) | address;
if (signatureCache[signature % CACHE_SIZE] == signature) return;
signatureCache[signature % CACHE_SIZE] = signature;
// if there are huge amount of strings that are the same, it's probably garbage: filter them out
// can't store all the strings, so use sum as heuristic instead
if (_InterlockedIncrement(sumCache + (sum % CACHE_SIZE)) > 25) return;
long n = sp.maxRecords - _InterlockedDecrement(&recordsAvailable);
if (n < sp.maxRecords)
{
records[n].jittype = jittype;
records[n].padding = padding;
if(jittype==JITTYPE::PC)
{
records[n].address = address;
records[n].offset = i * sizeof(char*);
}
else
{
records[n].em_addr=em_addr;
records[n].argidx=i;
}
for (int j = 0; j < length; ++j) records[n].text[j] = str[j];
records[n].text[length] = 0;
}
if (n == sp.maxRecords)
{
spDefault.maxRecords = sp.maxRecords * 2;
ConsoleOutput(OUT_OF_RECORDS_RETRY);
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {}
}
void Send(char** stack, uintptr_t address)
{
// it is unsafe to call ANY external functions from this, as they may have been hooked (if called the hook would call this function making an infinite loop)
@ -130,41 +179,46 @@ void Send(char** stack, uintptr_t address)
if (recordsAvailable <= 0) return;
for (int i = -registers; i < 10; ++i) for (auto padding : { uintptr_t{}, sp.padding })
{
char* str = stack[i] + padding;
if (IsBadReadPtr(str) || IsBadReadPtr(str + MAX_STRING_SIZE)) continue;
__try
{
int length = 0, sum = 0;
for (; (str[length] || str[length + 1]) && length < MAX_STRING_SIZE; length += 2) sum += *(uint16_t*)(str + length);
if (length > STRING && length < MAX_STRING_SIZE - 1)
{
// many duplicate results with same address, offset, and third/fourth character will be found: filter them out
uint64_t signature = ((uint64_t)i << 56) | ((uint64_t)(str[2] + str[3]) << 48) | address;
if (signatureCache[signature % CACHE_SIZE] == signature) continue;
signatureCache[signature % CACHE_SIZE] = signature;
// if there are huge amount of strings that are the same, it's probably garbage: filter them out
// can't store all the strings, so use sum as heuristic instead
if (_InterlockedIncrement(sumCache + (sum % CACHE_SIZE)) > 25) continue;
long n = sp.maxRecords - _InterlockedDecrement(&recordsAvailable);
if (n < sp.maxRecords)
{
records[n].address = address;
records[n].padding = padding;
records[n].offset = i * sizeof(char*);
for (int j = 0; j < length; ++j) records[n].text[j] = str[j];
records[n].text[length] = 0;
}
if (n == sp.maxRecords)
{
spDefault.maxRecords = sp.maxRecords * 2;
ConsoleOutput(OUT_OF_RECORDS_RETRY);
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {}
DoSend(i,address,stack[i],padding);
}
}
void SafeSendJitVeh(hook_stack* stack,uintptr_t address,uintptr_t em_addr,JITTYPE jittype){
__try
{
for (int i = 0;i<16;i++)
{
char* str=0;
switch (jittype)
{
#ifdef _WIN64
case JITTYPE::YUZU:
str=(char*)YUZU::emu_arg(stack)[i];
break;
#endif
case JITTYPE::PPSSPP:
str=(char*)PPSSPP::emu_arg(stack)[i];
break;
default:
return;
}
DoSend(i,address,str,0,jittype,em_addr);
}
}__except (EXCEPTION_EXECUTE_HANDLER) {}
}
std::unordered_map<uintptr_t,uint64_t>addresscalledtime;
bool SendJitVeh(PCONTEXT context,uintptr_t address,uintptr_t em_addr,JITTYPE jittype){
if (recordsAvailable <= 0) return false;
if(addresscalledtime.find(address)==addresscalledtime.end())addresscalledtime[address]=0;
auto tm=GetTickCount64();
if(tm-addresscalledtime[address]<100)return false;
addresscalledtime[address]=tm;
auto stack=std::make_unique<hook_stack>();
context_get(stack.get(),context);
SafeSendJitVeh(stack.get(),address,em_addr,jittype);
return true;
}
std::vector<uintptr_t> GetFunctions(uintptr_t module)
{
if (!module) return {};
@ -190,6 +244,43 @@ void mergevector(std::vector<uintptr_t> &v1,std::vector<uintptr_t> &v2){
}
}
}
void SearchForHooks_Return(){
ConsoleOutput(HOOK_SEARCH_FINISHED, sp.maxRecords - recordsAvailable);
for (int i = 0, results = 0; i < sp.maxRecords; ++i)
{
HookParam hp;
hp.codepage = sp.codepage;
hp.jittype=records[i].jittype;
hp.padding = records[i].padding;
if(records[i].jittype==JITTYPE::PC)
{
if (!records[i].address) continue;
hp.offset = records[i].offset;
hp.type = CODEC_UTF16 | USING_STRING;
hp.address = records[i].address;
}
else
{
if (!records[i].em_addr) continue;
hp.emu_addr=records[i].em_addr;
hp.type = CODEC_UTF16 | USING_STRING|BREAK_POINT;
hp.argidx=records[i].argidx;
}
if (sp.hookPostProcessor) sp.hookPostProcessor(hp); //actuall useless because of jit
NotifyHookFound(hp, (wchar_t*)records[i].text);
if (++results % 100'000 == 0) ConsoleOutput(ResultsNum, results);
}
records.reset();
for (int i = 0; i < CACHE_SIZE; ++i) signatureCache[i] = sumCache[i] = 0;
}
void initrecords(){
do
try { records = std::make_unique<HookRecord[]>(recordsAvailable = sp.maxRecords); }
catch (std::bad_alloc) { ConsoleOutput(SearchForHooks_ERROR, sp.maxRecords /= 2); }
while (!records && sp.maxRecords);
}
void SearchForHooks(SearchParam spUser)
{
std::thread([=]
@ -197,113 +288,118 @@ void SearchForHooks(SearchParam spUser)
static std::mutex m;
std::scoped_lock lock(m);
*(void**)(trampoline + send_offset) = Send;
ConsoleOutput(HOOK_SEARCH_INITIALIZING, 0.);
sp = spUser.length == 0 ? spDefault : spUser;
sp.codepage=spUser.codepage;
ConsoleOutput(HOOK_SEARCH_INITIALIZING, 0.);
do
try { records = std::make_unique<HookRecord[]>(recordsAvailable = sp.maxRecords); }
catch (std::bad_alloc) { ConsoleOutput(SearchForHooks_ERROR, sp.maxRecords /= 2); }
while (!records && sp.maxRecords);
initrecords();
std::vector<uintptr_t> addresses;
if (*sp.boundaryModule) {
auto [minaddr,maxaddr]=Util::QueryModuleLimits(GetModuleHandleW(sp.boundaryModule));
if(sp.address_method==0){
sp.minAddress=min(max(minaddr,sp.minAddress),maxaddr);
sp.maxAddress=max(min(maxaddr,sp.maxAddress),minaddr);
}
else if(sp.address_method==1){
auto maxoff=maxaddr-minaddr;
sp.minAddress=minaddr+min(sp.minAddress,maxoff);
sp.maxAddress=minaddr+min(sp.maxAddress,maxoff);
}
//std::tie(sp.minAddress, sp.maxAddress) = Util::QueryModuleLimits(GetModuleHandleW(sp.boundaryModule));
}
if (*sp.exportModule) addresses = GetFunctions((uintptr_t)GetModuleHandleW(sp.exportModule));
if (*sp.boundaryModule){
auto _addresses = GetFunctions((uintptr_t)GetModuleHandleW(sp.boundaryModule));
mergevector(addresses,_addresses);
}
std::vector<uintptr_t> addresses1;
if(sp.search_method==0){
for (auto& addr : addresses1 = Util::SearchMemory(sp.pattern, sp.length, PAGE_EXECUTE, sp.minAddress, sp.maxAddress))
addr += sp.offset;
}
else if(sp.search_method==1){
for(uintptr_t addr=sp.minAddress;addr<sp.maxAddress;addr++){
if(((*(DWORD*)addr)==0xCCCCCCCC)||((*(DWORD*)addr)==0x90909090)){
if(((*(BYTE*)(addr+4))!=0xCC)&&(*(BYTE*)(addr+4))!=0x90){
addresses1.push_back(addr+4);
}
}
}
}
else if(sp.search_method==2){
for(uintptr_t addr=sp.minAddress;addr<sp.maxAddress;addr++){
if(((*(BYTE*)addr)==0xe8)){
auto off=*(DWORD*)(addr+1);
auto funcaddr=addr+5+off;
if(sp.minAddress<funcaddr && sp.maxAddress>funcaddr){
auto it = std::find(addresses1.begin(), addresses1.end(), funcaddr);
addresses1.push_back(funcaddr);
}
}
}
}
mergevector(addresses,addresses1);
auto limits = Util::QueryModuleLimits(GetModuleHandleW(LUNA_HOOK_DLL));
addresses.erase(std::remove_if(addresses.begin(), addresses.end(), [&](auto addr) { return addr > limits.first && addr < limits.second; }), addresses.end());
auto trampolines = (decltype(trampoline)*)VirtualAlloc(NULL, sizeof(trampoline) * addresses.size(), MEM_COMMIT, PAGE_READWRITE);
VirtualProtect(trampolines, addresses.size() * sizeof(trampoline), PAGE_EXECUTE_READWRITE, DUMMY);
std::vector<uintptr_t>mherroridx;
for (int i = 0; i < addresses.size(); ++i)
if(jitaddr2emuaddr.empty() || spUser.length !=0)
{
void* original;
if (*sp.boundaryModule) {
auto [minaddr,maxaddr]=Util::QueryModuleLimits(GetModuleHandleW(sp.boundaryModule));
if(sp.address_method==0){
sp.minAddress=min(max(minaddr,sp.minAddress),maxaddr);
sp.maxAddress=max(min(maxaddr,sp.maxAddress),minaddr);
}
else if(sp.address_method==1){
auto maxoff=maxaddr-minaddr;
sp.minAddress=minaddr+min(sp.minAddress,maxoff);
sp.maxAddress=minaddr+min(sp.maxAddress,maxoff);
}
//std::tie(sp.minAddress, sp.maxAddress) = Util::QueryModuleLimits(GetModuleHandleW(sp.boundaryModule));
}
if (*sp.exportModule) addresses = GetFunctions((uintptr_t)GetModuleHandleW(sp.exportModule));
if (*sp.boundaryModule){
auto _addresses = GetFunctions((uintptr_t)GetModuleHandleW(sp.boundaryModule));
mergevector(addresses,_addresses);
}
std::vector<uintptr_t> addresses1;
if(sp.search_method==0){
for (auto& addr : addresses1 = Util::SearchMemory(sp.pattern, sp.length, PAGE_EXECUTE, sp.minAddress, sp.maxAddress))
addr += sp.offset;
}
else if(sp.search_method==1){
for(uintptr_t addr=sp.minAddress;addr<sp.maxAddress;addr++){
if(((*(DWORD*)addr)==0xCCCCCCCC)||((*(DWORD*)addr)==0x90909090)){
if(((*(BYTE*)(addr+4))!=0xCC)&&(*(BYTE*)(addr+4))!=0x90){
addresses1.push_back(addr+4);
}
}
}
}
else if(sp.search_method==2){
for(uintptr_t addr=sp.minAddress;addr<sp.maxAddress;addr++){
if(((*(BYTE*)addr)==0xe8)){
auto off=*(DWORD*)(addr+1);
auto funcaddr=addr+5+off;
if(sp.minAddress<funcaddr && sp.maxAddress>funcaddr){
auto it = std::find(addresses1.begin(), addresses1.end(), funcaddr);
addresses1.push_back(funcaddr);
}
}
}
}
mergevector(addresses,addresses1);
auto limits = Util::QueryModuleLimits(GetModuleHandleW(LUNA_HOOK_DLL));
addresses.erase(std::remove_if(addresses.begin(), addresses.end(), [&](auto addr) { return addr > limits.first && addr < limits.second; }), addresses.end());
auto trampolines = (decltype(trampoline)*)VirtualAlloc(NULL, sizeof(trampoline) * addresses.size(), MEM_COMMIT, PAGE_READWRITE);
VirtualProtect(trampolines, addresses.size() * sizeof(trampoline), PAGE_EXECUTE_READWRITE, DUMMY);
std::vector<uintptr_t>mherroridx;
for (int i = 0; i < addresses.size(); ++i)
{
void* original;
//避免MH_RemoveHook时移除原本已有hook
if(MH_CreateHook((void*)addresses[i], trampolines[i], &original)!=MH_OK){
mherroridx.push_back(i);
}
MH_QueueEnableHook((void*)addresses[i]);
memcpy(trampolines[i], trampoline, sizeof(trampoline));
*(uintptr_t*)(trampolines[i] + addr_offset) = addresses[i];
*(void**)(trampolines[i] + original_offset) = original;
if (i % 2500 == 0) ConsoleOutput(HOOK_SEARCH_INITIALIZING, 1 + 98. * i / addresses.size());
}
//避免MH_RemoveHook时移除原本已有hook
if(MH_CreateHook((void*)addresses[i], trampolines[i], &original)!=MH_OK){
mherroridx.push_back(i);
for(int i=0;i<mherroridx.size();i++){
auto reverseidx=mherroridx[mherroridx.size()-1-i];
addresses.erase(addresses.begin()+reverseidx);
}
MH_QueueEnableHook((void*)addresses[i]);
memcpy(trampolines[i], trampoline, sizeof(trampoline));
*(uintptr_t*)(trampolines[i] + addr_offset) = addresses[i];
*(void**)(trampolines[i] + original_offset) = original;
if (i % 2500 == 0) ConsoleOutput(HOOK_SEARCH_INITIALIZING, 1 + 98. * i / addresses.size());
}
//避免MH_RemoveHook时移除原本已有hook
for(int i=0;i<mherroridx.size();i++){
auto reverseidx=mherroridx[mherroridx.size()-1-i];
addresses.erase(addresses.begin()+reverseidx);
}
ConsoleOutput(HOOK_SEARCH_INITIALIZED, addresses.size());
MH_ApplyQueued();
ConsoleOutput(HOOK_SEARCH_STARTING);
ConsoleOutput(MAKE_GAME_PROCESS_TEXT, sp.searchTime / 1000);
Sleep(sp.searchTime);
for (auto addr : addresses) MH_QueueDisableHook((void*)addr);
MH_ApplyQueued();
Sleep(1000);
for (auto addr : addresses) MH_RemoveHook((void*)addr);
ConsoleOutput(HOOK_SEARCH_FINISHED, sp.maxRecords - recordsAvailable);
for (int i = 0, results = 0; i < sp.maxRecords; ++i)
{
if (!records[i].address) continue;
if (++results % 100'000 == 0) ConsoleOutput(ResultsNum, results);
HookParam hp;
hp.offset = records[i].offset;
hp.type = CODEC_UTF16 | USING_STRING;
hp.address = records[i].address;
hp.padding = records[i].padding;
hp.codepage = sp.codepage;
if (sp.hookPostProcessor) sp.hookPostProcessor(hp);
NotifyHookFound(hp, (wchar_t*)records[i].text);
ConsoleOutput(HOOK_SEARCH_INITIALIZED, addresses.size());
MH_ApplyQueued();
ConsoleOutput(HOOK_SEARCH_STARTING);
ConsoleOutput(MAKE_GAME_PROCESS_TEXT, sp.searchTime / 1000);
Sleep(sp.searchTime);
for (auto addr : addresses) MH_QueueDisableHook((void*)addr);
MH_ApplyQueued();
Sleep(1000);
for (auto addr : addresses) MH_RemoveHook((void*)addr);
VirtualFree(trampolines, 0, MEM_RELEASE);
SearchForHooks_Return();
}
else
{
ConsoleOutput(HOOK_SEARCH_INITIALIZED, jitaddr2emuaddr.size());
std::vector<uint64_t>successaddr;int i=0;
for(auto addr:jitaddr2emuaddr){
i+=1;
//addresses.push_back(addr.first);
if(add_veh_hook((void*)addr.first,std::bind(SendJitVeh,std::placeholders::_1,addr.first,addr.second.second,addr.second.first)))
successaddr.push_back(addr.first);
if (i % 2500 == 0) ConsoleOutput(HOOK_SEARCH_INITIALIZING, 1 + 98. * i / jitaddr2emuaddr.size());
}
ConsoleOutput(MAKE_GAME_PROCESS_TEXT, sp.searchTime / 1000);
Sleep(sp.searchTime);
for(auto addr:successaddr){
remove_veh_hook((void*)addr);
}
SearchForHooks_Return();
}
records.reset();
VirtualFree(trampolines, 0, MEM_RELEASE);
for (int i = 0; i < CACHE_SIZE; ++i) signatureCache[i] = sumCache[i] = 0;
}).detach();
}

View File

@ -161,8 +161,35 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID)
}
return TRUE;
}
bool NewHook(HookParam hp, LPCSTR lpname)
int HookStrLen(HookParam* hp,BYTE* data){
if(data==0)return 0;
if(hp->type&CODEC_UTF16)
return wcslen((wchar_t*)data)*2;
else if(hp->type&CODEC_UTF32)
return u32strlen((uint32_t*)data)*4;
else
return strlen((char*)data);
}
static std::mutex maplock;
void jitaddrclear(){
std::lock_guard _(maplock);
emuaddr2jitaddr.clear();
jitaddr2emuaddr.clear();
}
void jitaddraddr(uintptr_t em_addr,uintptr_t jitaddr,JITTYPE jittype){
std::lock_guard _(maplock);
if(emuaddr2jitaddr.find(em_addr)==emuaddr2jitaddr.end())
emuaddr2jitaddr[em_addr]={jittype,{}};
emuaddr2jitaddr[em_addr].second.insert(jitaddr);
jitaddr2emuaddr[jitaddr]={jittype,em_addr};
}
bool NewHook_1(HookParam& hp, LPCSTR lpname)
{
if(hp.emu_addr)
ConsoleOutput("%p => %p",hp.emu_addr,hp.address);
if (++currentHook >= MAX_HOOK){
ConsoleOutput(TOO_MANY_HOOKS);
return false;
@ -182,7 +209,22 @@ bool NewHook(HookParam hp, LPCSTR lpname)
return true;
}
}
bool NewHook(HookParam hp, LPCSTR name){
if(hp.address)
return NewHook_1(hp,name);
if(emuaddr2jitaddr.find(hp.emu_addr)==emuaddr2jitaddr.end())return false;
strcpy(hp.function,"");
wcscpy(hp.module,L"");
hp.type &= ~MODULE_OFFSET;
hp.type &= ~FUNCTION_OFFSET;
auto succ=false;
for(auto __x: emuaddr2jitaddr[hp.emu_addr].second){
hp.address=__x;
hp.jittype=emuaddr2jitaddr[hp.emu_addr].first;
succ|=NewHook_1(hp,name);
}
return succ;
}
void RemoveHook(uint64_t addr, int maxOffset)
{
for (auto& hook : *hooks) if (abs((long long)(hook.address - addr)) <= maxOffset) return hook.Clear();
@ -205,4 +247,70 @@ std::string LoadResData(LPCWSTR pszResID,LPCWSTR _type)
GlobalFree(m_hMem);
FreeResource(lpRsrc);
return data;
}
}
void context_get(hook_stack* stack,PCONTEXT context){
#ifndef _WIN64
stack->eax=context->Eax;
stack->ecx=context->Ecx;
stack->edx=context->Edx;
stack->ebx=context->Ebx;
stack->esp=context->Esp;
stack->ebp=context->Ebp;
stack->esi=context->Esi;
stack->edi=context->Edi;
stack->eflags=context->EFlags;
stack->retaddr=*(DWORD*)context->Esp;
#else
stack->rax=context->Rax;
stack->rbx=context->Rbx;
stack->rcx=context->Rcx;
stack->rdx=context->Rdx;
stack->rsp=context->Rsp;
stack->rbp=context->Rbp;
stack->rsi=context->Rsi;
stack->rdi=context->Rdi;
stack->r8=context->R8;
stack->r9=context->R9;
stack->r10=context->R10;
stack->r11=context->R11;
stack->r12=context->R12;
stack->r13=context->R13;
stack->r14=context->R14;
stack->r15=context->R15;
stack->eflags=context->EFlags;
stack->retaddr=*(DWORD64*)context->Rsp;
#endif
}
void context_set(hook_stack* stack,PCONTEXT context){
#ifndef _WIN64
context->Eax=stack->eax;
context->Ecx=stack->ecx;
context->Edx=stack->edx;
context->Ebx=stack->ebx;
context->Esp=stack->esp;
context->Ebp=stack->ebp;
context->Esi=stack->esi;
context->Edi=stack->edi;
context->EFlags=stack->eflags;
#else
context->Rax=stack->rax;
context->Rbx=stack->rbx;
context->Rcx=stack->rcx;
context->Rdx=stack->rdx;
context->Rsp=stack->rsp;
context->Rbp=stack->rbp;
context->Rsi=stack->rsi;
context->Rdi=stack->rdi;
context->R8=stack->r8;
context->R9=stack->r9;
context->R10=stack->r10;
context->R11=stack->r11;
context->R12=stack->r12;
context->R13=stack->r13;
context->R14=stack->r14;
context->R15=stack->r15;
context->EFlags=stack->eflags;
#endif
}

View File

@ -11,8 +11,18 @@ void ConsoleOutput(LPCSTR text, ...);
void NotifyHookFound(HookParam hp, wchar_t* text);
void NotifyHookRemove(uint64_t addr, LPCSTR name);
bool NewHook(HookParam hp, LPCSTR name);
bool NewHookJit(HookParam hp, LPCSTR name);
void RemoveHook(uint64_t addr, int maxOffset = 9);
std::string LoadResData(LPCWSTR pszResID,LPCWSTR _type);
inline SearchParam spDefault;
// EOF
int HookStrLen(HookParam*,BYTE* data);
inline std::unordered_map<uintptr_t,std::pair<JITTYPE,std::set<uintptr_t> > >emuaddr2jitaddr;
inline std::unordered_map<uintptr_t,std::pair<JITTYPE,uintptr_t>>jitaddr2emuaddr;
void jitaddrclear();
void jitaddraddr(uintptr_t em_addr,uintptr_t jitaddr,JITTYPE);
void context_get(hook_stack*,PCONTEXT);
void context_set(hook_stack*,PCONTEXT);

View File

@ -9,6 +9,7 @@
#include "MinHook.h"
#include"Lang/Lang.h"
#include"veh_hook.h"
#include"engines/emujitarg.hpp"
extern WinMutex viewMutex;
// - Unnamed helpers -
@ -102,12 +103,12 @@ uintptr_t getasbaddr(const HookParam &hp){
if (hp.type & FUNCTION_OFFSET)
{
if (FARPROC function = GetProcAddress(GetModuleHandleW(hp.module), hp.function)) address += (uint64_t)function;
else return ConsoleOutput(FUNC_MISSING), false;
else return ConsoleOutput(FUNC_MISSING), 0;
}
else
{
if (HMODULE moduleBase = GetModuleHandleW(hp.module)) address += (uint64_t)moduleBase;
else return ConsoleOutput(MODULE_MISSING), false;
else return ConsoleOutput(MODULE_MISSING), 0;
}
}
return address;
@ -116,6 +117,8 @@ bool TextHook::Insert(HookParam hp)
{
auto addr=getasbaddr(hp);
if(!addr)return false;
RemoveHook(addr, 0);
local_buffer=new BYTE[PIPE_BUFFER_SIZE];
@ -124,8 +127,7 @@ bool TextHook::Insert(HookParam hp)
this->hp = hp;
address = addr;
}
savetypeforremove=hp.type;
if (hp.type & DIRECT_READ) return InsertReadCode();
if (hp.type & BREAK_POINT) return InsertBreakPoint();
return InsertHookCode();
@ -142,6 +144,23 @@ uintptr_t queryrelativeret(uintptr_t retaddr){
re.insert(std::make_pair(retaddr,relative));
return relative;
}
void jitfunctiontext_fun(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
switch (hp->jittype)
{
#ifdef _WIN64
case JITTYPE::YUZU:
*data=YUZU::emu_arg(stack)[hp->argidx]+hp->padding;
break;
#endif
case JITTYPE::PPSSPP:
*data=PPSSPP::emu_arg(stack)[hp->argidx]+hp->padding;
break;
default:
*data=0;
}
*len=HookStrLen(hp,(BYTE*)*data);
}
void TextHook::Send(uintptr_t lpDataBase)
{
auto buffer =(TextOutput_T*) local_buffer;
@ -149,7 +168,7 @@ void TextHook::Send(uintptr_t lpDataBase)
_InterlockedIncrement((long*)&useCount);
__try
{
auto stack=(hook_stack*)(lpDataBase-sizeof(hook_stack)+sizeof(uintptr_t));
auto stack=get_hook_stack(lpDataBase);
#ifndef _WIN64
if (auto current_trigger_fun = trigger_fun.exchange(nullptr))
@ -177,6 +196,10 @@ void TextHook::Send(uintptr_t lpDataBase)
isstring=true;
hp.text_fun(stack, &hp, &lpDataIn, &lpSplit, &lpCount);
}
else if(hp.jittype!=JITTYPE::PC){
isstring=true;
jitfunctiontext_fun(stack, &hp, &lpDataIn, &lpSplit, &lpCount);
}
else
{
if (hp.type & FIXING_SPLIT) lpSplit = FIXED_SPLIT_VALUE; // fuse all threads, and prevent floating
@ -273,52 +296,18 @@ void TextHook::Send(uintptr_t lpDataBase)
_InterlockedDecrement((long*) & useCount);
}
void TextHook::breakpointcontext(PCONTEXT context){
#ifdef _WIN64
bool TextHook::breakpointcontext(PCONTEXT context){
auto stack=std::make_unique<hook_stack>();
stack->rax=context->Rax;
stack->rbx=context->Rbx;
stack->rcx=context->Rcx;
stack->rdx=context->Rdx;
stack->rsp=context->Rsp;
stack->rbp=context->Rbp;
stack->rsi=context->Rsi;
stack->rdi=context->Rdi;
stack->r8=context->R8;
stack->r9=context->R9;
stack->r10=context->R10;
stack->r11=context->R11;
stack->r12=context->R12;
stack->r13=context->R13;
stack->r14=context->R14;
stack->r15=context->R15;
stack->eflags=context->EFlags;
stack->retaddr=*(DWORD64*)context->Rsp;
auto lpDataBase=(uintptr_t)stack.get()+sizeof(hook_stack)-sizeof(uintptr_t);
context_get(stack.get(),context);
auto lpDataBase=stack->get_base();
Send(lpDataBase);
context->Rax=stack->rax;
context->Rbx=stack->rbx;
context->Rcx=stack->rcx;
context->Rdx=stack->rdx;
context->Rsp=stack->rsp;
context->Rbp=stack->rbp;
context->Rsi=stack->rsi;
context->Rdi=stack->rdi;
context->R8=stack->r8;
context->R9=stack->r9;
context->R10=stack->r10;
context->R11=stack->r11;
context->R12=stack->r12;
context->R13=stack->r13;
context->R14=stack->r14;
context->R15=stack->r15;
context->EFlags=stack->eflags;
#endif
context_set(stack.get(),context);
return true;
}
bool TextHook::InsertBreakPoint()
{
//MH_CreateHook 64位unity/yuzu-emu经常 MH_ERROR_MEMORY_ALLOC
return add_veh_hook(location,std::bind(&TextHook::breakpointcontext,this,std::placeholders::_1), 0);
return add_veh_hook(location,std::bind(&TextHook::breakpointcontext,this,std::placeholders::_1));
}
bool TextHook::RemoveBreakPoint()
{
@ -393,8 +382,8 @@ void TextHook::RemoveReadCode()
void TextHook::Clear()
{
if (address == 0) return;
if (hp.type & DIRECT_READ) RemoveReadCode();
else if (hp.type & BREAK_POINT) RemoveBreakPoint();
if (savetypeforremove & DIRECT_READ) RemoveReadCode();
else if (savetypeforremove & BREAK_POINT) RemoveBreakPoint();
else RemoveHookCode();
NotifyHookRemove(address, hp.name);
std::scoped_lock lock(viewMutex);
@ -451,15 +440,7 @@ int TextHook::GetLength(hook_stack* stack, uintptr_t in)
int TextHook::HookStrlen(BYTE* data)
{
if(data==0)return 0;
if(hp.type&CODEC_UTF16)
return wcslen((wchar_t*)data)*2;
else if(hp.type&CODEC_UTF32)
return u32strlen((uint32_t*)data)*4;
else
return strlen((char*)data);
return HookStrLen(&hp,data);
}
// EOF

View File

@ -591,6 +591,15 @@ bool Engine::isAddressWritable(const wchar_t *p, size_t count)
namespace{
uint32_t *Xstrcpy(uint32_t *s, const uint32_t *r){
while(*r){
*s=*r;
s+=1;
r+=1;
}
*s=0;
return s;
}
wchar_t *Xstrcpy(wchar_t *s, const wchar_t *r){return wcscpy(s,r);}
char *Xstrcpy(char *s, const char *r){return strcpy(s,r);}
template<class CharT>
@ -611,6 +620,7 @@ namespace{
void write_string_new(uintptr_t* data, size_t* len,const std::wstring& s){write_string_new_impl<wchar_t>(data,len,s);}
void write_string_new(uintptr_t* data, size_t* len,const std::string& s){write_string_new_impl<char>(data,len,s);}
bool write_string_overwrite(void* data, size_t* len,const std::basic_string<uint32_t>& s){return write_string_overwrite_impl<uint32_t>(data,len,s);}
bool write_string_overwrite(void* data, size_t* len,const std::wstring& s){return write_string_overwrite_impl<wchar_t>(data,len,s);}
bool write_string_overwrite(void* data, size_t* len,const std::string& s){return write_string_overwrite_impl<char>(data,len,s);}

View File

@ -81,7 +81,7 @@ void write_string_new(uintptr_t* data, size_t* len,const std::wstring& s);
void write_string_new(uintptr_t* data, size_t* len,const std::string& s);
bool write_string_overwrite(void* data, size_t* len,const std::wstring& s);
bool write_string_overwrite(void* data, size_t* len,const std::string& s);
bool write_string_overwrite(void* data, size_t* len,const std::basic_string<uint32_t>& s);
struct WindowInfo {
HWND handle;

View File

@ -17,58 +17,62 @@ bool add_veh_hook(void* origFunc, newFuncType newFunc, DWORD hook_type)
DWORD oldProtect;
if (list == NULL) list = new_veh_list();
if (list == NULL) return false;
if(get_veh_node(list,origFunc))return false;
void* handle = AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)veh_dispatch);
veh_node_t* newnode = insert_veh_node(list, origFunc, newFunc, handle, hook_type);
auto newnode = create_veh_node(origFunc, newFunc, handle, hook_type);
if(newnode==NULL)return false;
// For memory hooks especially, we need to know the address of the start of the relevant page.
MEMORY_BASIC_INFORMATION mem_info;
VirtualQuery(origFunc, &mem_info, sizeof(MEMORY_BASIC_INFORMATION));
newnode->baseAddr = mem_info.BaseAddress;
VirtualProtect(origFunc, sizeof(int), PAGE_EXECUTE_READWRITE, &newnode->OldProtect);
if(!VirtualProtect(origFunc, sizeof(int), PAGE_EXECUTE_READWRITE, &newnode->OldProtect))
{
delete newnode;
return false;
}
memcpy((void*)(&newnode->origBaseByte), (const void*)origFunc, sizeof (BYTE));
memcpy((void*)origFunc, (const void*)&int3bp, sizeof (BYTE));
VirtualProtect(origFunc, sizeof(int), newnode->OldProtect, &oldProtect);
insert_veh_node(list, newnode);
return true;
}
void repair_origin(veh_node_t *node){
DWORD _p;
VirtualProtect(node->origFunc, sizeof(int), PAGE_EXECUTE_READWRITE, &_p);
memcpy((void*)node->origFunc, (const void*)(&node->origBaseByte), sizeof(char));
VirtualProtect(node->origFunc, sizeof(int), node->OldProtect, &_p);
}
bool remove_veh_hook(void* origFunc)
{
std::lock_guard _(vehlistlock);
if (list == NULL) return false;
veh_node_t* node = get_veh_node(list, origFunc);
if (node == NULL) return false;
DWORD _p;
VirtualProtect(node->origFunc, sizeof(int), PAGE_EXECUTE_READWRITE, &_p);
memcpy((void*)node->origFunc, (const void*)(&node->origBaseByte), sizeof(char));
VirtualProtect(node->origFunc, sizeof(int), node->OldProtect, &_p);
repair_origin(node);
RemoveVectoredExceptionHandler(node->handle);
return remove_veh_node(list, origFunc);
}
bool remove_veh_node(veh_list_t* list, void* origFunc)
{
veh_node_t* searchnode;
veh_node_t* lastsearchnode = NULL;
searchnode = list->head;
veh_node_t* searchnode = list->head;
while (searchnode != NULL)
{
if (searchnode->origFunc == origFunc)
{
if (lastsearchnode == NULL)
{
list->head = searchnode->next;
if (list->tail == searchnode) list->tail = searchnode->next;
}
else
{
lastsearchnode->next = searchnode->next;
}
if(list->tail==searchnode)
list->tail=searchnode->last;
if(list->head==searchnode)
list->head=searchnode->next;
if(searchnode->last)
searchnode->last->next=searchnode->next;
if(searchnode->next)
searchnode->next->last=searchnode->last;
delete (searchnode);
return true;
}
lastsearchnode = searchnode;
searchnode = searchnode->next;
}
return false;
@ -82,21 +86,29 @@ LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo)
if (Code != STATUS_BREAKPOINT && Code != STATUS_SINGLE_STEP) return EXCEPTION_CONTINUE_SEARCH;
// Try to find the node associated with the address of the current exception, continue searching for handlers if not found;
std::lock_guard _(vehlistlock);
if (Code == STATUS_BREAKPOINT )//&& hooktype == VEH_HK_INT3)
{
veh_node_t* currnode = get_veh_node(list, Addr);
veh_node_t* currnode ;
{
std::lock_guard _(vehlistlock);
currnode = get_veh_node(list, Addr);
}
if (currnode == NULL) return EXCEPTION_CONTINUE_SEARCH;
VirtualProtect(Addr, sizeof(int), PAGE_EXECUTE_READWRITE, &currnode->OldProtect);
memcpy((void*)Addr, (const void*)(&currnode->origBaseByte), sizeof (char));
currnode->newFunc(ExceptionInfo->ContextRecord);
VirtualProtect(Addr, sizeof(int), currnode->OldProtect, &oldProtect);
ExceptionInfo->ContextRecord->EFlags |= 0x100;
if(currnode->newFunc(ExceptionInfo->ContextRecord))
{
repair_origin(currnode);
ExceptionInfo->ContextRecord->EFlags |= 0x100;
}
else
{
remove_veh_hook(Addr);
}
}
else if (Code == STATUS_SINGLE_STEP )//&& hooktype == VEH_HK_INT3)
{
std::lock_guard _(vehlistlock);
veh_node_t* currnode = get_veh_node(list, Addr, 0x10);
if (currnode == NULL) return EXCEPTION_CONTINUE_SEARCH;
@ -126,18 +138,22 @@ veh_list_t* new_veh_list()
newlist->tail = NULL;
return newlist;
}
veh_node_t* insert_veh_node(veh_list_t* list, void* origFunc, newFuncType newFunc, void* handle, DWORD hook_type)
veh_node_t* create_veh_node(void* origFunc, newFuncType newFunc, void* handle, DWORD hook_type)
{
if (list == NULL) return NULL;
/* create a new node and fill in the blanks */
veh_node_t* newnode = new veh_node_t;
if (newnode == NULL) return NULL;
newnode->last=NULL;
newnode->origFunc = origFunc;
newnode->newFunc = newFunc;
newnode->handle = handle;
newnode->OldProtect = PAGE_EXECUTE_READWRITE;
newnode->next = NULL;
newnode->hooktype=hook_type;
return newnode;
}
void insert_veh_node(veh_list_t* list, veh_node_t* newnode)
{
if (list == NULL) return;
if (list->head == NULL)
{
list->head = newnode;
@ -146,11 +162,10 @@ veh_node_t* insert_veh_node(veh_list_t* list, void* origFunc, newFuncType newFun
else
{
list->tail->next = newnode;
newnode->last=list->tail;
list->tail = newnode;
}
return newnode;
}
veh_node_t* get_veh_node(veh_list_t* list, void* origFunc, int range)
{
veh_node_t* newnode;

View File

@ -20,10 +20,12 @@ Version: 24-March-2008
//typedef void (*pfvoid)();
//typedef void (*newFuncType)(PCONTEXT);
using newFuncType = std::function<void(PCONTEXT)>;
using newFuncType = std::function<bool(PCONTEXT)>;
typedef struct veh_node
{
struct veh_node* last;
struct veh_node* next;
void* origFunc;
newFuncType newFunc;
void* handle;
@ -31,7 +33,6 @@ typedef struct veh_node
void* baseAddr; // Address of the page in which origFunc resides.
BYTE origBaseByte;
DWORD OldProtect;
struct veh_node* next;
} veh_node_t;
typedef struct
@ -41,7 +42,7 @@ typedef struct
} veh_list_t;
// VEH hook interface functions for creating and removing hooks.
bool add_veh_hook(void* origFunc, newFuncType newFunc, DWORD hook_type);
bool add_veh_hook(void* origFunc, newFuncType newFunc, DWORD hook_type=VEH_HK_INT3);
bool remove_veh_hook(void* origFunc);
// The VEH dispathing function is called by Windows every time an exception is encountered.
@ -50,7 +51,8 @@ LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo);
// Functions used internally by the library.
veh_list_t* new_veh_list();
veh_node_t* insert_veh_node(veh_list_t* list, void* origFunc, newFuncType newFunc, void* handle, DWORD hook_type);
veh_node_t* create_veh_node(void* origFunc, newFuncType newFunc, void* handle, DWORD hook_type);
void insert_veh_node(veh_list_t* list, veh_node_t*);
bool remove_veh_node(veh_list_t* list, void* origFunc);
veh_node_t* get_veh_node(veh_list_t* list, void* origFunc, int range=0);

View File

@ -44,7 +44,12 @@ namespace
{
std::wsmatch match;
HookParam hp;
if(endWith(HCode,L":JIT:YUZU")){
hp.jittype=JITTYPE::YUZU;
}
else if(endWith(HCode,L":JIT:PPSSPP")){
hp.jittype=JITTYPE::PPSSPP;
}
// {A|B|W|H|S|Q|V|M}
switch (HCode[0])
{
@ -161,7 +166,18 @@ namespace
// ITH has registers offset by 4 vs AGTH: need this to correct
if (hp.offset < 0) hp.offset -= 4;
if (hp.split < 0) hp.split -= 4;
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;
hp.type &= ~FUNCTION_OFFSET;
strcpy(hp.function,"");
wcscpy(hp.module,L"");
}
return hp;
}
@ -258,34 +274,31 @@ namespace
else
HCode += L"H";
if (hp.text_fun || hp.filter_fun)
HCode += L'X';
if(hp.type & USING_STRING)
{
if(hp.type&CODEC_UTF16)
HCode += L'Q';
else if(hp.type&CODEC_UTF8)
HCode += L'V';
else if(hp.type&CODEC_UTF32)
HCode += L'U';
else
HCode += L'S';
}
else
{
if(hp.type & USING_STRING)
{
if(hp.type&CODEC_UTF16)
HCode += L'Q';
else if(hp.type&CODEC_UTF8)
HCode += L'V';
else if(hp.type&CODEC_UTF32)
HCode += L'U';
else
HCode += L'S';
}
else
{
if(hp.type&CODEC_UTF16)
HCode += L'W';
else if(hp.type&CODEC_UTF32)
HCode += L'I';
else if (hp.type & CODEC_ANSI_BE)
HCode += L'A';
else
HCode += L'B';
}
if(hp.type&CODEC_UTF16)
HCode += L'W';
else if(hp.type&CODEC_UTF32)
HCode += L'I';
else if (hp.type & CODEC_ANSI_BE)
HCode += L'A';
else
HCode += L'B';
}
if (hp.text_fun || hp.filter_fun) HCode += L'X';
if (hp.type & FULL_STRING) HCode += L'F';
@ -295,31 +308,51 @@ namespace
if (hp.padding) HCode += HexString(hp.padding) + L'+';
if (hp.offset < 0) hp.offset += 4;
if (hp.split < 0) hp.split += 4;
switch (hp.jittype)
{
case JITTYPE::PC:
{
if (hp.offset < 0) hp.offset += 4;
if (hp.split < 0) hp.split += 4;
HCode += HexString(hp.offset);
if (hp.type & DATA_INDIRECT) HCode += L'*' + HexString(hp.index);
if (hp.type & USING_SPLIT) HCode += L':' + HexString(hp.split);
if (hp.type & SPLIT_INDIRECT) HCode += L'*' + HexString(hp.split_index);
HCode += HexString(hp.offset);
if (hp.type & DATA_INDIRECT) HCode += L'*' + HexString(hp.index);
if (hp.type & USING_SPLIT) HCode += L':' + HexString(hp.split);
if (hp.type & SPLIT_INDIRECT) HCode += L'*' + HexString(hp.split_index);
// Attempt to make the address relative
if (processId && !(hp.type & MODULE_OFFSET))
if (AutoHandle<> process = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processId))
if (MEMORY_BASIC_INFORMATION info = {}; VirtualQueryEx(process, (LPCVOID)hp.address, &info, sizeof(info)))
if (auto moduleName = GetModuleFilename(processId, (HMODULE)info.AllocationBase))
{
hp.type |= MODULE_OFFSET;
hp.address -= (uint64_t)info.AllocationBase;
wcsncpy_s(hp.module, moduleName->c_str() + moduleName->rfind(L'\\') + 1, MAX_MODULE_SIZE - 1);
}
HCode += L'@' + HexString(hp.address);
if (hp.type & MODULE_OFFSET) HCode += L':' + std::wstring(hp.module);
if (hp.type & FUNCTION_OFFSET) HCode += L':' + StringToWideString(hp.function);
}
break;
default:
{
HCode += HexString(hp.argidx);
HCode += L'@' + HexString(hp.emu_addr);
switch (hp.jittype)
{
case JITTYPE::YUZU:
HCode+=L":JIT:YUZU";
break;
case JITTYPE::PPSSPP:
HCode+=L":JIT:PPSSPP";
}
}
break;
}
// Attempt to make the address relative
if (processId && !(hp.type & MODULE_OFFSET))
if (AutoHandle<> process = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processId))
if (MEMORY_BASIC_INFORMATION info = {}; VirtualQueryEx(process, (LPCVOID)hp.address, &info, sizeof(info)))
if (auto moduleName = GetModuleFilename(processId, (HMODULE)info.AllocationBase))
{
hp.type |= MODULE_OFFSET;
hp.address -= (uint64_t)info.AllocationBase;
wcsncpy_s(hp.module, moduleName->c_str() + moduleName->rfind(L'\\') + 1, MAX_MODULE_SIZE - 1);
}
HCode += L'@' + HexString(hp.address);
if (hp.type & MODULE_OFFSET) HCode += L':' + std::wstring(hp.module);
if (hp.type & FUNCTION_OFFSET) HCode += L':' + StringToWideString(hp.function);
return HCode;
}
}

View File

@ -151,6 +151,26 @@ inline unsigned int convertUTF32ToUTF16(unsigned int cUTF32, unsigned int& h, un
unsigned int ret = ((h << 16) | (l & 0x0000FFFF));
return ret;
}
std::basic_string<uint32_t> utf16_to_utf32(const wchar_t* u16str,size_t size){
std::basic_string<uint32_t> utf32String;
for (size_t i=0;i<size;i++)
{
auto u16c=u16str[i];
if(u16c-0xd800u<2048u)
if((u16c&0xfffffc00==0xd800)&&(i<size-1)&&(u16str[i+1]&0xfffffc00==0xdc00)){
utf32String+=(u16c << 10) + u16str[i+1] - 0x35fdc00;
i+=1;
}
else{
//error invalid u16 char
}
else
utf32String+=u16str[i];
}
return utf32String;
}
std::wstring utf32_to_utf16(uint32_t* u32str,size_t size){
std::wstring u16str;
for(auto i=0;i<size;i++){

View File

@ -23,6 +23,8 @@ bool endWith(const std::string& s,const std::string& s2);
bool endWith(const std::wstring& s,const std::wstring& s2);
std::wstring utf32_to_utf16(uint32_t* u32str,size_t size);
std::basic_string<uint32_t> utf16_to_utf32(const wchar_t* u16str,size_t size);
std::string WideStringToString(const std::wstring& text,UINT cp=CP_UTF8);
std::wstring StringToWideString(const std::string& text);
std::optional<std::wstring> StringToWideString(const std::string& text, UINT encoding);

View File

@ -42,7 +42,7 @@ class TextHook
public:
HookParam hp;
ALIGNPTR(uint64_t address,void* location);
uint64_t savetypeforremove;
bool Insert(HookParam hp);
void Clear();
@ -52,7 +52,7 @@ private:
bool InsertReadCode();
bool InsertBreakPoint();
bool RemoveBreakPoint();
void breakpointcontext(PCONTEXT);
bool breakpointcontext(PCONTEXT);
void Send(uintptr_t dwDatabase);
int GetLength(hook_stack* stack, uintptr_t in); // jichi 12/25/2013: Return 0 if failed
int HookStrlen(BYTE* data);

View File

@ -61,17 +61,30 @@ struct hook_stack
uintptr_t retaddr;
BYTE base[1];
};
uintptr_t get_base(){
return (uintptr_t)this+sizeof(hook_stack)-sizeof(uintptr_t);
}
};
inline hook_stack* get_hook_stack(uintptr_t lpDataBase){
return (hook_stack*)(lpDataBase-sizeof(hook_stack)+sizeof(uintptr_t));
}
// jichi 3/7/2014: Add guessed comment
#define ALIGNPTR(Y,X) union { \
##Y; \
##X; \
};
enum class JITTYPE{
PC,//not a jit
YUZU,
PPSSPP
};
struct HookParam
{
uint64_t address; // absolute or relative address
ALIGNPTR(uint64_t __11,uintptr_t address); // absolute or relative address
int offset, // offset of the data in the memory
index, // deref_offset1
split, // offset of the split character
@ -96,6 +109,9 @@ struct HookParam
HookParam(){
ZeroMemory(this,sizeof(HookParam));
}
ALIGNPTR(uint64_t __10,uintptr_t emu_addr);
int argidx;
JITTYPE jittype;
};
struct ThreadParam