This commit is contained in:
恍兮惚兮 2024-07-21 21:04:12 +08:00
parent 0fe834dd27
commit b0b1fe4417
21 changed files with 2114 additions and 1802 deletions

View File

@ -92,7 +92,7 @@
#define HS_SEARCH_FOR_TEXT L"Search for specific text"
#define VersionLatest L"Latest version"
#define VersionCurrent L"Current version"
#define ProjectHomePage L"Github: https://github.com/HIllya51/LunaHook\nHomepage: https://lunatranslator.xyz\npatreon: https://patreon.com/HIllya51\nDiscord: https://discord.gg/f8NSvaDU\n\nThis program is a core submodule of LunaTranslator and is fully integrated in Lunatranslator. This program contains only some simple functions, if you need more functions, please use LunaTranslator.\n\nIf you find unsupported games, please submit an issue\nhttps://github.com/HIllya51/LunaHook/issues/new?assignees=&labels=enhancement&projects=&template=01_game_request.yaml"
#define ProjectHomePage L"Github: https://github.com/HIllya51/LunaHook\nHomepage: https://lunatranslator.xyz\npatreon: https://patreon.com/HIllya51\nDiscord: https://discord.gg/f8NSvaDU\n\nThis program is a core submodule of LunaTranslator and is fully integrated in Lunatranslator. This program contains only some simple functions, if you need more functions, please use LunaTranslator.\nIf you find unsupported games, please submit an issue\nhttps://github.com/HIllya51/LunaHook/issues"
#define LIST_HOOK L"Hook"
#define LIST_TEXT L"Text"
#define PROC_CONN L"process connected %d"

View File

@ -92,7 +92,7 @@
#define HS_SEARCH_FOR_TEXT L"Искать определенный текст"
#define VersionLatest L"Последняя версия"
#define VersionCurrent L"Текущая версия"
#define ProjectHomePage L"Github: https://github.com/HIllya51/LunaHook\nСтраница проекта: https://lunatranslator.xyz\npatreon: https://patreon.com/HIllya51\nDiscord: https://discord.gg/f8NSvaDU\nПеревод на русский: https://github.com/NekoIriyaRu\n\nЭта программа является основным подмодулем LunaTranslator и полностью интегрирована в Lunatranslator. Эта программа содержит только некоторые простые функции. Если вам нужны дополнительные функции, используйте LunaTranslator.\n\nЕсли вы обнаружите какие-либо неподдерживаемые игры, сообщите о проблеме.\nhttps://github.com/HIllya51/LunaHook/issues/new?assignees=&labels=enhancement&projects=&template=01_game_request.yaml"
#define ProjectHomePage L"Github: https://github.com/HIllya51/LunaHook\nСтраница проекта: https://lunatranslator.xyz\npatreon: https://patreon.com/HIllya51\nDiscord: https://discord.gg/f8NSvaDU\nПеревод на русский: https://github.com/NekoIriyaRu\n\nЭта программа является основным подмодулем LunaTranslator и полностью интегрирована в Lunatranslator. Эта программа содержит только некоторые простые функции. Если вам нужны дополнительные функции, используйте LunaTranslator.\nЕсли вы обнаружите какие-либо неподдерживаемые игры, сообщите о проблеме.\nhttps://github.com/HIllya51/LunaHook/issues"
#define LIST_HOOK L"Хук"
#define LIST_TEXT L"Текст"
#define PROC_CONN L"Процесс подключен %d"

View File

@ -92,7 +92,7 @@
#define HS_SEARCH_FOR_TEXT L"搜索指定文本"
#define VersionLatest L"最新版本"
#define VersionCurrent L"当前版本"
#define ProjectHomePage L"Github https://github.com/HIllya51/LunaHook\n项目主页 https://lunatranslator.xyz\npatreonhttps://patreon.com/HIllya51\nDiscordhttps://discord.gg/f8NSvaDU\n\n本程序是LunaTranslator 的核心子模块并完全集成在Lunatranslator中。本程序仅包含一些简单功能如果您需要更多功能请使用 LunaTranslator。\n\n如果你发现有不支持的游戏请提交issue\nhttps://github.com/HIllya51/LunaHook/issues/new?assignees=&labels=enhancement&projects=&template=01_game_request.yaml"
#define ProjectHomePage L"Github https://github.com/HIllya51/LunaHook\n项目主页 https://lunatranslator.xyz\npatreonhttps://patreon.com/HIllya51\nDiscordhttps://discord.gg/f8NSvaDU\n\n本程序是LunaTranslator 的核心子模块并完全集成在Lunatranslator中。本程序仅包含一些简单功能如果您需要更多功能请使用 LunaTranslator。\n如果你发现有不支持的游戏请提交issue\nhttps://github.com/HIllya51/LunaHook/issues"
#define LIST_HOOK L"Hook"
#define LIST_TEXT L"文本"
#define PROC_CONN L"进程已连接 %d"

View File

@ -1,19 +1,23 @@
class NoEngine:public ENGINE{
public:
bool attach_function(){
ConsoleOutput("IGNORE %s",getenginename());
//ConsoleOutput("IGNORE engine");
class NoEngine : public ENGINE
{
public:
bool attach_function()
{
ConsoleOutput("IGNORE %s", getenginename());
// ConsoleOutput("IGNORE engine");
return true;
}
};
class oldSystem40ini:public NoEngine{
public:
oldSystem40ini(){
class oldSystem40ini : public NoEngine
{
public:
oldSystem40ini()
{
// jichi 1/19/2015: Disable inserting Lstr for System40
// See: http://sakuradite.com/topic/618
check_by=CHECK_BY::FILE;
check_by_target=L"System40.ini";
check_by = CHECK_BY::FILE;
check_by_target = L"System40.ini";
};
};
// class RPGMakerRGSS3:public NoEngine{
@ -26,7 +30,6 @@ class oldSystem40ini:public NoEngine{
// };
// };
// class FVP:public NoEngine{
// public:
// FVP(){
@ -37,63 +40,68 @@ class oldSystem40ini:public NoEngine{
// };
// };
class AdvPlayerHD:public NoEngine{
public:
AdvPlayerHD(){
class AdvPlayerHD : public NoEngine
{
public:
AdvPlayerHD()
{
// supposed to be WillPlus
check_by=CHECK_BY::FILE_ANY;
check_by_target=check_by_list{L"AdvHD.exe",L"AdvHD.dll"};
check_by = CHECK_BY::FILE_ANY;
check_by_target = check_by_list{L"AdvHD.exe", L"AdvHD.dll"};
};
};
class DPM:public NoEngine{
public:
DPM(){
class DPM : public NoEngine
{
public:
DPM()
{
// jichi 4/30/2015: Skip games made from らすこう, such as とある人妻のネトラレ事情
// It has garbage from lstrlenW. Correct text is supposed to be in TabbedTextOutA.
check_by=CHECK_BY::FILE;
check_by_target=L"data_cg.dpm";
check_by = CHECK_BY::FILE;
check_by_target = L"data_cg.dpm";
};
};
class Escude_ignore:public NoEngine{
public:
Escude_ignore(){
class Escude_ignore : public NoEngine
{
public:
Escude_ignore()
{
// jichi 3/19/2014: Escude game
// Example: bgm.bin gfx.bin maou.bin script.bin snd.bin voc.bin
check_by=CHECK_BY::FILE_ANY;
check_by_target=check_by_list{L"gfx.bin",L"snd.bin",L"voc.bin"};
check_by = CHECK_BY::FILE_ANY;
check_by_target = check_by_list{L"gfx.bin", L"snd.bin", L"voc.bin"};
};
};
class Chartreux:public NoEngine{
public:
Chartreux(){
class Chartreux : public NoEngine
{
public:
Chartreux()
{
// jichi 12/28/2014: "Chartreux Inc." in Copyright.
// Sublimary brands include Rosebleu, MORE, etc.
// GetGlyphOutlineA already works.
check_by=CHECK_BY::RESOURCE_STR;
check_by_target=L"Chartreux";
check_by = CHECK_BY::RESOURCE_STR;
check_by_target = L"Chartreux";
};
};
class lcsebody:public NoEngine{
public:
lcsebody(){
class lcsebody : public NoEngine
{
public:
lcsebody()
{
check_by=CHECK_BY::CUSTOM;
check_by = CHECK_BY::CUSTOM;
// jichi 3/19/2014: LC-ScriptEngine, GetGlyphOutlineA
check_by_target=[](){
check_by_target = []()
{
return (wcsstr(processName, L"lcsebody") || !wcsncmp(processName, L"lcsebo~", 7) || Util::CheckFile(L"lcsebody*"));
};
};
@ -106,7 +114,6 @@ class lcsebody:public NoEngine{
// // jichi 3/19/2014: LC-ScriptEngine, GetGlyphOutlineA
// check_by_target=[](){
// wchar_t str[MAX_PATH];
// DWORD i;
// for (i = 0; processName[i]; i++) {
@ -122,16 +129,15 @@ class lcsebody:public NoEngine{
// };
// };
//if (Util::CheckFile(L"AGERC.DLL")) { // jichi 3/17/2014: Eushully, AGE.EXE
// ConsoleOutput("IGNORE Eushully");
// return true;
//}
//if (Util::CheckFile(L"*\\Managed\\UnityEngine.dll")) { // jichi 12/3/2013: Unity (BALDRSKY ZERO)
// ConsoleOutput("IGNORE Unity");
// return true;
//}
//if (Util::CheckFile(L"bsz_Data\\Managed\\UnityEngine.dll") || Util::CheckFile(L"bsz2_Data\\Managed\\UnityEngine.dll")) {
// ConsoleOutput("IGNORE Unity");
// return true;
//}
// if (Util::CheckFile(L"AGERC.DLL")) { // jichi 3/17/2014: Eushully, AGE.EXE
// ConsoleOutput("IGNORE Eushully");
// return true;
// }
// if (Util::CheckFile(L"*\\Managed\\UnityEngine.dll")) { // jichi 12/3/2013: Unity (BALDRSKY ZERO)
// ConsoleOutput("IGNORE Unity");
// return true;
// }
// if (Util::CheckFile(L"bsz_Data\\Managed\\UnityEngine.dll") || Util::CheckFile(L"bsz2_Data\\Managed\\UnityEngine.dll")) {
// ConsoleOutput("IGNORE Unity");
// return true;
// }

View File

@ -1,40 +1,45 @@
DynamicShiftJISCodec *dynamiccodec=new DynamicShiftJISCodec(932);
DynamicShiftJISCodec *dynamiccodec = new DynamicShiftJISCodec(932);
void cast_back(const HookParam &hp, void *data, size_t *len, const std::wstring &trans, bool normal)
{
void cast_back(const HookParam& hp,void*data ,size_t *len,const std::wstring& trans,bool normal){
if((hp.type&EMBED_CODEC_UTF16)||(hp.type&CODEC_UTF16)){//renpy
write_string_overwrite(data,len,trans);
if ((hp.type & EMBED_CODEC_UTF16) || (hp.type & CODEC_UTF16))
{ // renpy
write_string_overwrite(data, len, trans);
}
else{
else
{
std::string astr;
if(hp.type&EMBED_DYNA_SJIS&&!normal){
astr=dynamiccodec->encodeSTD(trans,0);
if (hp.type & EMBED_DYNA_SJIS && !normal)
{
astr = dynamiccodec->encodeSTD(trans, 0);
}
else{
astr=WideStringToString(trans,hp.codepage?hp.codepage:((hp.type&CODEC_UTF8)?CP_UTF8:embedsharedmem->codepage));
else
{
astr = WideStringToString(trans, hp.codepage ? hp.codepage : ((hp.type & CODEC_UTF8) ? CP_UTF8 : embedsharedmem->codepage));
}
write_string_overwrite(data,len,astr);
write_string_overwrite(data, len, astr);
}
}
struct FunctionInfo {
struct FunctionInfo
{
const char *name; // for debugging purpose
uintptr_t *oldFunction,
newFunction;
bool attached ;
bool attached;
uintptr_t addr;
explicit FunctionInfo(const uintptr_t _addr=0,const char *name = "", uintptr_t *oldFunction = nullptr, uintptr_t newFunction = 0,
bool attached = false )
: name(name), oldFunction(oldFunction), newFunction(newFunction)
, attached(attached),addr(_addr)
{}
};
explicit FunctionInfo(const uintptr_t _addr = 0, const char *name = "", uintptr_t *oldFunction = nullptr, uintptr_t newFunction = 0,
bool attached = false)
: name(name), oldFunction(oldFunction), newFunction(newFunction), attached(attached), addr(_addr)
{
}
};
std::unordered_map<uintptr_t, FunctionInfo> funcs; // attached functions
std::vector<uintptr_t > replacedfuns; // attached functions
std::vector<uintptr_t> replacedfuns; // attached functions
bool _1f()
{
#define ADD_FUN(_f) funcs[F_##_f] = FunctionInfo((uintptr_t)_f,#_f, (uintptr_t *)&Hijack::old##_f, (uintptr_t)Hijack::new##_f);
#define ADD_FUN(_f) funcs[F_##_f] = FunctionInfo((uintptr_t)_f, #_f, (uintptr_t *)&Hijack::old##_f, (uintptr_t)Hijack::new##_f);
ADD_FUN(CreateFontA)
ADD_FUN(CreateFontW)
ADD_FUN(CreateFontIndirectA)
@ -45,8 +50,8 @@ bool _1f()
ADD_FUN(GetTextExtentPoint32W)
ADD_FUN(GetTextExtentExPointA)
ADD_FUN(GetTextExtentExPointW)
//ADD_FUN(GetCharABCWidthsA)
//ADD_FUN(GetCharABCWidthsW)
// ADD_FUN(GetCharABCWidthsA)
// ADD_FUN(GetCharABCWidthsW)
ADD_FUN(TextOutA)
ADD_FUN(TextOutW)
ADD_FUN(ExtTextOutA)
@ -56,107 +61,121 @@ bool _1f()
ADD_FUN(DrawTextExA)
ADD_FUN(DrawTextExW)
ADD_FUN(CharNextA)
//ADD_FUN(CharNextW)
//ADD_FUN(CharNextExA)
//ADD_FUN(CharNextExW)
// ADD_FUN(CharNextW)
// ADD_FUN(CharNextExA)
// ADD_FUN(CharNextExW)
ADD_FUN(CharPrevA)
//ADD_FUN(CharPrevW)
// ADD_FUN(CharPrevW)
ADD_FUN(MultiByteToWideChar)
ADD_FUN(WideCharToMultiByte)
#undef ADD_FUN
return 0;
return 0;
}
bool _1=_1f();
void ReplaceFunction(PVOID* oldf,PVOID newf){
bool _1 = _1f();
void ReplaceFunction(PVOID *oldf, PVOID newf)
{
RemoveHook((uintptr_t)*oldf);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach((PVOID*)oldf, (PVOID)newf);
DetourAttach((PVOID *)oldf, (PVOID)newf);
DetourTransactionCommit();
}
void attachFunction(uintptr_t _hook_font_flag)
{
for(auto & _func:funcs){
if(_func.first&_hook_font_flag){
if(_func.second.attached)continue;
for (auto &_func : funcs)
{
if (_func.first & _hook_font_flag)
{
if (_func.second.attached)
continue;
_func.second.attached = true;
*_func.second.oldFunction=_func.second.addr;
*_func.second.oldFunction = _func.second.addr;
replacedfuns.push_back(_func.first);
ReplaceFunction((PVOID*)_func.second.oldFunction,(PVOID)_func.second.newFunction);
ReplaceFunction((PVOID *)_func.second.oldFunction, (PVOID)_func.second.newFunction);
}
}
}
void detachall( )
void detachall()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
for(auto _flag:replacedfuns){
auto info=funcs.at(_flag);
DetourDetach((PVOID*)info.oldFunction, (PVOID)info.newFunction);
for (auto _flag : replacedfuns)
{
auto info = funcs.at(_flag);
DetourDetach((PVOID *)info.oldFunction, (PVOID)info.newFunction);
}
DetourTransactionCommit();
}
void solvefont(HookParam hp){
if(hp.hook_font){
void solvefont(HookParam hp)
{
if (hp.hook_font)
{
attachFunction(hp.hook_font);
}
if(hp.hook_font&F_MultiByteToWideChar)
disable_mbwc=true;
if(hp.hook_font&F_WideCharToMultiByte)
disable_wcmb=true;
if (hp.hook_font & F_MultiByteToWideChar)
disable_mbwc = true;
if (hp.hook_font & F_WideCharToMultiByte)
disable_wcmb = true;
if (auto current_patch_fun = patch_fun.exchange(nullptr)){
if (auto current_patch_fun = patch_fun.exchange(nullptr))
{
current_patch_fun();
dont_detach=true;
dont_detach = true;
}
}
static std::wstring alwaysInsertSpacesSTD(const std::wstring& text)
{
static std::wstring alwaysInsertSpacesSTD(const std::wstring &text)
{
std::wstring ret;
for(auto c: text) {
for (auto c : text)
{
ret.push_back(c);
if (c >= 32) // ignore non-printable characters
ret.push_back(L' '); // or insert \u3000 if needed
}
return ret;
}
bool charEncodableSTD(const wchar_t& ch, UINT codepage)
}
bool charEncodableSTD(const wchar_t &ch, UINT codepage)
{
if (ch <= 127) // ignore ascii characters
return true;
std::wstring s ;
std::wstring s;
s.push_back(ch);
return StringToWideString(WideStringToString(s, codepage), codepage).value() == s;
}
static std::wstring insertSpacesAfterUnencodableSTD(const std::wstring& text, HookParam hp)
{
static std::wstring insertSpacesAfterUnencodableSTD(const std::wstring &text, HookParam hp)
{
std::wstring ret;
for(const wchar_t & c: text) {
for (const wchar_t &c : text)
{
ret.push_back(c);
if (!charEncodableSTD(c, hp.codepage?hp.codepage:embedsharedmem->codepage))
if (!charEncodableSTD(c, hp.codepage ? hp.codepage : embedsharedmem->codepage))
ret.push_back(L' ');
}
return ret;
}
std::wstring adjustSpacesSTD(const std::wstring& text,HookParam hp)
}
std::wstring adjustSpacesSTD(const std::wstring &text, HookParam hp)
{
switch (embedsharedmem->spaceadjustpolicy)
{
case 0: return text;
case 1:return alwaysInsertSpacesSTD(text);
case 2:return insertSpacesAfterUnencodableSTD(text, hp);
default:return text;
case 0:
return text;
case 1:
return alwaysInsertSpacesSTD(text);
case 2:
return insertSpacesAfterUnencodableSTD(text, hp);
default:
return text;
}
}
std::wstring limitTextWidth(const std::wstring& text, int size)
std::wstring limitTextWidth(const std::wstring &text, int size)
{
auto lines=strSplit(text,L"\n");
std::for_each(lines.begin(),lines.end(),[=](auto &line){
auto lines = strSplit(text, L"\n");
std::for_each(lines.begin(), lines.end(), [=](auto &line)
{
if(line.size()<=size)
return;
std::wstring ret;
@ -166,106 +185,128 @@ std::wstring limitTextWidth(const std::wstring& text, int size)
ret+=L'\n';
}
}
line=ret;
});
line=ret; });
std::wstring ret;
for(int i=0;i<lines.size();i++){
ret+=lines[i];
if(i<lines.size()-1)ret+=L'\n';
for (int i = 0; i < lines.size(); i++)
{
ret += lines[i];
if (i < lines.size() - 1)
ret += L'\n';
}
return ret;
}
bool isPauseKeyPressed()
{
return WinKey::isKeyControlPressed()
|| WinKey::isKeyShiftPressed() && !WinKey::isKeyReturnPressed();
return WinKey::isKeyControlPressed() || WinKey::isKeyShiftPressed() && !WinKey::isKeyReturnPressed();
}
inline UINT64 djb2_n2(const unsigned char * str, size_t len, UINT64 hash = 5381)
inline UINT64 djb2_n2(const unsigned char *str, size_t len, UINT64 hash = 5381)
{
int i=0;
while (len--){
int i = 0;
while (len--)
{
hash = ((hash << 5) + hash) + (*str++); // hash * 33 + c
}
return hash;
}
std::unordered_map<UINT64,std::wstring>translatecache;
bool check_is_thread_selected(const ThreadParam& tp){
for(int i=0;i<10;i++)
if(embedsharedmem->use[i])
if((embedsharedmem->addr[i]==tp.addr)&&(embedsharedmem->ctx1[i]==tp.ctx)&&(embedsharedmem->ctx2[i]==tp.ctx2))
std::unordered_map<UINT64, std::wstring> translatecache;
bool check_is_thread_selected(const ThreadParam &tp)
{
for (int i = 0; i < 10; i++)
if (embedsharedmem->use[i])
if ((embedsharedmem->addr[i] == tp.addr) && (embedsharedmem->ctx1[i] == tp.ctx) && (embedsharedmem->ctx2[i] == tp.ctx2))
return true;
return false;
}
bool check_embed_able(const ThreadParam& tp){
return host_connected&&check_is_thread_selected(tp)&&((isPauseKeyPressed()==false)?true:!embedsharedmem->fastskipignore);
bool check_embed_able(const ThreadParam &tp)
{
return host_connected && check_is_thread_selected(tp) && ((isPauseKeyPressed() == false) ? true : !embedsharedmem->fastskipignore);
}
bool waitforevent(UINT32 timems,const ThreadParam& tp,const std::wstring &origin){
bool waitforevent(UINT32 timems, const ThreadParam &tp, const std::wstring &origin)
{
char eventname[1000];
sprintf(eventname,LUNA_EMBED_notify_event,GetCurrentProcessId(),djb2_n2((const unsigned char*)(origin.c_str()),origin.size()*2));
auto event=win_event(eventname);
while(timems){
if(check_embed_able(tp)==false)return false;
auto sleepstep=min(100,timems);
if(event.wait(sleepstep))return true;
timems-=sleepstep;
sprintf(eventname, LUNA_EMBED_notify_event, GetCurrentProcessId(), djb2_n2((const unsigned char *)(origin.c_str()), origin.size() * 2));
auto event = win_event(eventname);
while (timems)
{
if (check_embed_able(tp) == false)
return false;
auto sleepstep = min(100, timems);
if (event.wait(sleepstep))
return true;
timems -= sleepstep;
}
return false;
}
void TextHook::parsenewlineseperator(void*data ,size_t*len)
void TextHook::parsenewlineseperator(void *data, size_t *len)
{
if(!(hp.newlineseperator))return;
if (!(hp.newlineseperator))
return;
if (hp.type & CODEC_UTF16)
{
StringReplacer((wchar_t*)data,len,hp.newlineseperator,wcslen(hp.newlineseperator),L"\n",1);
StringReplacer((wchar_t *)data, len, hp.newlineseperator, wcslen(hp.newlineseperator), L"\n", 1);
}
else if(hp.type&CODEC_UTF32) return;
else if (hp.type & CODEC_UTF32)
return;
else
{
//ansi/utf8newlineseperator都是简单字符
// ansi/utf8newlineseperator都是简单字符
std::string newlineseperatorA;
for(int i=0;i<wcslen(hp.newlineseperator);i++)newlineseperatorA+=(char)hp.newlineseperator[i];
StringReplacer((char*)data,len,newlineseperatorA.c_str(),newlineseperatorA.size(),"\n",1);
for (int i = 0; i < wcslen(hp.newlineseperator); i++)
newlineseperatorA += (char)hp.newlineseperator[i];
StringReplacer((char *)data, len, newlineseperatorA.c_str(), newlineseperatorA.size(), "\n", 1);
}
}
UINT64 texthash(void*data,size_t len)
UINT64 texthash(void *data, size_t len)
{
UINT64 sum=0;
auto u8data=(UINT8*)data;
for(int i=0;i< len;i++){
sum+=u8data[i];
sum=sum<<1;
UINT64 sum = 0;
auto u8data = (UINT8 *)data;
for (int i = 0; i < len; i++)
{
sum += u8data[i];
sum = sum << 1;
}
return sum;
}
bool checktranslatedok(void*data ,size_t len)
bool checktranslatedok(void *data, size_t len)
{
ZeroMemory(embedsharedmem->text,sizeof(embedsharedmem->text));//clear trans before call
if(len>1000)return true;
return(translatecache.find(texthash(data,len))!=translatecache.end());
ZeroMemory(embedsharedmem->text, sizeof(embedsharedmem->text)); // clear trans before call
if (len > 1000)
return true;
return (translatecache.find(texthash(data, len)) != translatecache.end());
}
bool TextHook::waitfornotify(TextOutput_T* buffer,void*data ,size_t*len,ThreadParam tp){
bool TextHook::waitfornotify(TextOutput_T *buffer, void *data, size_t *len, ThreadParam tp)
{
std::wstring origin;
if (auto t=commonparsestring(data,*len,&hp,embedsharedmem->codepage)) origin=t.value();
else return false;
if (auto t = commonparsestring(data, *len, &hp, embedsharedmem->codepage))
origin = t.value();
else
return false;
std::wstring translate;
auto hash=texthash(data,*len);
if(translatecache.find(hash)!=translatecache.end()){
translate=translatecache.at(hash);
auto hash = texthash(data, *len);
if (translatecache.find(hash) != translatecache.end())
{
translate = translatecache.at(hash);
}
else{
if(waitforevent(embedsharedmem->waittime,tp,origin)==false)return false;
translate=embedsharedmem->text;
if((translate.size()==0))return false;
translatecache.insert(std::make_pair(hash,translate));
else
{
if (waitforevent(embedsharedmem->waittime, tp, origin) == false)
return false;
translate = embedsharedmem->text;
if ((translate.size() == 0))
return false;
translatecache.insert(std::make_pair(hash, translate));
}
if(embedsharedmem->line_text_length_limit)translate=limitTextWidth(translate,embedsharedmem->line_text_length_limit);
if(hp.newlineseperator)strReplace(translate,L"\n",hp.newlineseperator);
translate=adjustSpacesSTD(translate,hp);
if(embedsharedmem->keeprawtext)translate=origin+L" "+translate;
if (embedsharedmem->line_text_length_limit)
translate = limitTextWidth(translate, embedsharedmem->line_text_length_limit);
if (hp.newlineseperator)
strReplace(translate, L"\n", hp.newlineseperator);
translate = adjustSpacesSTD(translate, hp);
if (embedsharedmem->keeprawtext)
translate = origin + L" " + translate;
solvefont(hp);
cast_back(hp,data,len,translate,false);
cast_back(hp, data, len, translate, false);
return true;
}

View File

@ -2,9 +2,10 @@
#define __LUNA_EMBED_ENGINE_H
extern EmbedSharedMem *embedsharedmem;
extern DynamicShiftJISCodec *dynamiccodec ;
extern DynamicShiftJISCodec *dynamiccodec;
namespace WinKey {
namespace WinKey
{
inline bool isKeyPressed(int vk) { return ::GetKeyState(vk) & 0xf0; }
inline bool isKeyToggled(int vk) { return ::GetKeyState(vk) & 0x0f; }
@ -12,14 +13,22 @@ namespace WinKey {
inline bool isKeyControlPressed() { return isKeyPressed(VK_CONTROL); }
inline bool isKeyShiftPressed() { return isKeyPressed(VK_SHIFT); }
inline bool isKeyAltPressed() { return isKeyPressed(VK_MENU); }
}
namespace Engine{
enum TextRole { UnknownRole = 0, ScenarioRole, NameRole, OtherRole,
ChoiceRole = OtherRole, HistoryRole = OtherRole,
RoleCount };
}
inline std::atomic<void(*)()> patch_fun = nullptr;
void ReplaceFunction(PVOID* oldf,PVOID newf);
bool check_embed_able(const ThreadParam& tp);
bool checktranslatedok(void*data ,size_t len);
namespace Engine
{
enum TextRole
{
UnknownRole = 0,
ScenarioRole,
NameRole,
OtherRole,
ChoiceRole = OtherRole,
HistoryRole = OtherRole,
RoleCount
};
}
inline std::atomic<void (*)()> patch_fun = nullptr;
void ReplaceFunction(PVOID *oldf, PVOID newf);
bool check_embed_able(const ThreadParam &tp);
bool checktranslatedok(void *data, size_t len);
#endif

View File

@ -1,20 +1,23 @@
#ifndef __LUNA_ENGINE_H
#define __LUNA_ENGINE_H
extern WCHAR* processName, processPath[MAX_PATH],processName_lower[MAX_PATH]; // cached
extern WCHAR *processName, processPath[MAX_PATH], processName_lower[MAX_PATH]; // cached
extern uintptr_t processStartAddress, processStopAddress;
extern uintptr_t processStartAddress, processStopAddress;
class ENGINE{
public:
const char* enginename;
bool dontstop;//dont stop even if attached a engine
bool is_engine_certain; //stop when match a engine ,even if not attached
class ENGINE
{
public:
const char *enginename;
bool dontstop; // dont stop even if attached a engine
bool is_engine_certain; // stop when match a engine ,even if not attached
enum class CHECK_BY {
enum class CHECK_BY
{
ALL_TRUE,
FILE, FILE_ALL,FILE_ANY,
FILE,
FILE_ALL,
FILE_ANY,
RESOURCE_STR,
CUSTOM,
};
@ -23,16 +26,18 @@ class ENGINE{
// std::vector<const wchar_t*>check_by_list;
// std::function<bool()>check_by_custom_function;
typedef std::function<bool()> check_by_custom_function;
typedef std::vector<const wchar_t*> check_by_list;
typedef const wchar_t* check_by_single;
std::variant<check_by_single,check_by_list,check_by_custom_function>check_by_target;
//virtual bool check_by_target(){return false;};
virtual bool attach_function()=0;
virtual const char* getenginename(){
if(enginename)return enginename;
return typeid(*this).name()+6;
typedef std::vector<const wchar_t *> check_by_list;
typedef const wchar_t *check_by_single;
std::variant<check_by_single, check_by_list, check_by_custom_function> check_by_target;
// virtual bool check_by_target(){return false;};
virtual bool attach_function() = 0;
virtual const char *getenginename()
{
if (enginename)
return enginename;
return typeid(*this).name() + 6;
}
ENGINE():enginename(nullptr),dontstop(false),is_engine_certain(true),check_by(CHECK_BY::ALL_TRUE){};
ENGINE() : enginename(nullptr), dontstop(false), is_engine_certain(true), check_by(CHECK_BY::ALL_TRUE){};
bool check_function();
};

View File

@ -1,179 +1,180 @@
#include"engine32/PPSSPP.h"
#include"engine32/LovaGame.h"
#include"engine32/PCSX2.h"
#include"engine32/VanillawareGC.h"
#include"engine32/V8.h"
#include"engine32/cef.h"
#include"engine32/KISS.h"
#include"engine32/mono.h"
#include"engine32/Tarte.h"
#include"engine32/sakanagl.h"
#include"engine32/LCScript.h"
#include"engine32/ONScripterru.h"
#include"engine32/CoffeeMaker.h"
#include"engine32/splushwave.h"
#include"engine32/FrontWing.h"
#include"engine32/GSX.h"
#include"engine32/pchooks.h"
#include"engine32/VALKYRIA.h"
#include"engine32/mirage.h"
#include"engine32/Sprite.h"
#include"engine32/PONScripter.h"
#include"engine32/Fizz.h"
#include"engine32/Ruf.h"
#include"engine32/SYSD.h"
#include"engine32/Diskdream.h"
#include"engine32/RPGMakerRGSS3.h"
#include"engine32/RUNE.h"
#include"engine32/Lightvn.h"
#include"engine32/KiriKiri.h"
#include"engine32/ransel.h"
#include"engine32/Bishop.h"
#include"engine32/HXP.h"
#include"engine32/morning.h"
#include"engine32/IGScript.h"
#include"engine32/TSSystem.h"
#include"engine32/ScrPlayer.h"
#include"engine32/Aksys.h"
#include"engine32/utawarerumono.h"
#include"engine32/SideB.h"
#include"engine32/BGI.h"
#include"engine32/Bootup.h"
#include"engine32/Troy.h"
#include"engine32/Tomato.h"
#include"engine32/shyakunage.h"
#include"engine32/Eushully.h"
#include"engine32/Majiro.h"
#include"engine32/Elf.h"
#include"engine32/Silkys.h"
#include"engine32/Speed.h"
#include"engine32/FVP.h"
#include"engine32/Interlude.h"
#include"engine32/CMVS.h"
#include"engine32/Wolf.h"
#include"engine32/Circus1.h"
#include"engine32/Circus2.h"
#include"engine32/Cotopha.h"
#include"engine32/Xbangbang.h"
#include"engine32/TeethingRing.h"
#include"engine32/Unknown.h"
#include"engine32/Artemis.h"
#include"engine32/CatSystem.h"
#include"engine32/Atelier.h"
#include"engine32/BKEngine.h"
#include"engine32/VitaminSoft.h"
#include"engine32/Abalone.h"
#include"engine32/Tenco.h"
#include"engine32/QLIE.h"
#include"engine32/sakusesu.h"
#include"engine32/Anisetta.h"
#include"engine32/Regista.h"
#include"engine32/Pal.h"
#include"engine32/Footy2.h"
#include"engine32/NeXAS.h"
#include"engine32/Interheart.h"
#include"engine32/LunaSoft.h"
#include"engine32/Unicorn.h"
#include"engine32/Rejet.h"
#include"engine32/tamasoft.h"
#include"engine32/AdobeAir.h"
#include"engine32/Retouch.h"
#include"engine32/Malie.h"
#include"engine32/Live.h"
#include"engine32/Jellyfish.h"
#include"engine32/Nexton.h"
#include"engine32/Lucifen.h"
#include"engine32/Waffle.h"
#include"engine32/Sakuradog.h"
#include"engine32/TinkerBell.h"
#include"engine32/Jisatu101.h"
#include"engine32/TerraLunar.h"
#include"engine32/Palette.h"
#include"engine32/SystemAoi.h"
#include"engine32/Nijyuei.h"
#include"engine32/MBLMED.h"
#include"engine32/NNNConfig.h"
#include"engine32/Erogos.h"
#include"engine32/godot.h"
#include"engine32/Yuris.h"
#include"engine32/Nitroplus.h"
#include"engine32/Bruns.h"
#include"engine32/XUSE.h"
#include"engine32/EME.h"
#include"engine32/RRE.h"
#include"engine32/Candy.h"
#include"engine32/AIL2.h"
#include"engine32/ApricoT.h"
#include"engine32/Triangle.h"
#include"engine32/GASTRO.h"
#include"engine32/akatombo.h"
#include"engine32/AB2Try.h"
#include"engine32/GameMaker.h"
#include"engine32/DxLib.h"
#include"engine32/CodeX.h"
#include"engine32/Purple.h"
#include"engine32/Minori.h"
#include"engine32/SRPGStudio.h"
#include"engine32/RpgmXP.h"
#include"engine32/littlecheese.h"
#include"engine32/Eagls.h"
#include"engine32/Debonosu.h"
#include"engine32/C4.h"
#include"engine32/WillPlus.h"
#include"engine32/Tanuki.h"
#include"engine32/hibiki.h"
#include"engine32/GXP.h"
#include"engine32/Giga.h"
#include"engine32/AOS.h"
#include"engine32/Mink.h"
#include"engine32/AGS.h"
#include"engine32/YukaSystem2.h"
#include"engine32/Exp.h"
#include"engine32/Syuntada.h"
#include"engine32/Pensil.h"
#include"engine32/solfasys.h"
#include"engine32/Anim.h"
#include"engine32/Nitroplus2.h"
#include"engine32/Reallive.h"
#include"engine32/jukujojidai.h"
#include"engine32/Siglus.h"
#include"engine32/Taskforce2.h"
#include"engine32/RUGP.h"
#include"engine32/IronGameSystem.h"
#include"engine32/Anex86.h"
#include"engine32/ShinyDaysGame.h"
#include"engine32/MarineHeart.h"
#include"engine32/ShinaRio.h"
#include"engine32/CaramelBox.h"
#include"engine32/Escude.h"
#include"engine32/Ryokucha.h"
#include"engine32/Alice.h"
#include"engine32/System4x.h"
#include"engine32/Abel.h"
#include"engine32/5pb.h"
#include"engine32/HorkEye.h"
#include"engine32/Ohgetsu.h"
#include"engine32/OVERDRIVE.h"
#include"engine32/Leaf.h"
#include"engine32/Nekopack.h"
#include"engine32/AdobeFlash10.h"
#include"engine32/FocasLens.h"
#include"engine32/Tamamo.h"
#include"engine32/Suika2.h"
#include"engine32/Overflow.h"
#include"engine32/Ages3ResT.h"
#include"engine32/AXL.h"
#include"engine32/UnisonShift.h"
#include"engine32/EntisGLS.h"
#include"engine32/Ciel.h"
#include"engine32/CisLugI.h"
#include"engine32/A98SYS.h"
#include"engine32/ACTGS.h"
#include"engine32/GuruGuruSMF4.h"
#include"NoEngine.h"
#include"engines/lua/lua51.h"
#include"engines/python/Renpy.h"
std::vector<ENGINE*> check_engines(){
#include "engine32/PPSSPP.h"
#include "engine32/LovaGame.h"
#include "engine32/PCSX2.h"
#include "engine32/VanillawareGC.h"
#include "engine32/V8.h"
#include "engine32/cef.h"
#include "engine32/KISS.h"
#include "engine32/mono.h"
#include "engine32/Tarte.h"
#include "engine32/sakanagl.h"
#include "engine32/LCScript.h"
#include "engine32/ONScripterru.h"
#include "engine32/CoffeeMaker.h"
#include "engine32/splushwave.h"
#include "engine32/FrontWing.h"
#include "engine32/GSX.h"
#include "engine32/pchooks.h"
#include "engine32/VALKYRIA.h"
#include "engine32/mirage.h"
#include "engine32/Sprite.h"
#include "engine32/PONScripter.h"
#include "engine32/Fizz.h"
#include "engine32/Ruf.h"
#include "engine32/SYSD.h"
#include "engine32/Diskdream.h"
#include "engine32/RPGMakerRGSS3.h"
#include "engine32/RUNE.h"
#include "engine32/Lightvn.h"
#include "engine32/KiriKiri.h"
#include "engine32/ransel.h"
#include "engine32/Bishop.h"
#include "engine32/HXP.h"
#include "engine32/morning.h"
#include "engine32/IGScript.h"
#include "engine32/TSSystem.h"
#include "engine32/ScrPlayer.h"
#include "engine32/Aksys.h"
#include "engine32/utawarerumono.h"
#include "engine32/SideB.h"
#include "engine32/BGI.h"
#include "engine32/Bootup.h"
#include "engine32/Troy.h"
#include "engine32/Tomato.h"
#include "engine32/shyakunage.h"
#include "engine32/Eushully.h"
#include "engine32/Majiro.h"
#include "engine32/Elf.h"
#include "engine32/Silkys.h"
#include "engine32/Speed.h"
#include "engine32/FVP.h"
#include "engine32/Interlude.h"
#include "engine32/CMVS.h"
#include "engine32/Wolf.h"
#include "engine32/Circus1.h"
#include "engine32/Circus2.h"
#include "engine32/Cotopha.h"
#include "engine32/Xbangbang.h"
#include "engine32/TeethingRing.h"
#include "engine32/Unknown.h"
#include "engine32/Artemis.h"
#include "engine32/CatSystem.h"
#include "engine32/Atelier.h"
#include "engine32/BKEngine.h"
#include "engine32/VitaminSoft.h"
#include "engine32/Abalone.h"
#include "engine32/Tenco.h"
#include "engine32/QLIE.h"
#include "engine32/sakusesu.h"
#include "engine32/Anisetta.h"
#include "engine32/Regista.h"
#include "engine32/Pal.h"
#include "engine32/Footy2.h"
#include "engine32/NeXAS.h"
#include "engine32/Interheart.h"
#include "engine32/LunaSoft.h"
#include "engine32/Unicorn.h"
#include "engine32/Rejet.h"
#include "engine32/tamasoft.h"
#include "engine32/AdobeAir.h"
#include "engine32/Retouch.h"
#include "engine32/Malie.h"
#include "engine32/Live.h"
#include "engine32/Jellyfish.h"
#include "engine32/Nexton.h"
#include "engine32/Lucifen.h"
#include "engine32/Waffle.h"
#include "engine32/Sakuradog.h"
#include "engine32/TinkerBell.h"
#include "engine32/Jisatu101.h"
#include "engine32/TerraLunar.h"
#include "engine32/Palette.h"
#include "engine32/SystemAoi.h"
#include "engine32/Nijyuei.h"
#include "engine32/MBLMED.h"
#include "engine32/NNNConfig.h"
#include "engine32/Erogos.h"
#include "engine32/godot.h"
#include "engine32/Yuris.h"
#include "engine32/Nitroplus.h"
#include "engine32/Bruns.h"
#include "engine32/XUSE.h"
#include "engine32/EME.h"
#include "engine32/RRE.h"
#include "engine32/Candy.h"
#include "engine32/AIL2.h"
#include "engine32/ApricoT.h"
#include "engine32/Triangle.h"
#include "engine32/GASTRO.h"
#include "engine32/akatombo.h"
#include "engine32/AB2Try.h"
#include "engine32/GameMaker.h"
#include "engine32/DxLib.h"
#include "engine32/CodeX.h"
#include "engine32/Purple.h"
#include "engine32/Minori.h"
#include "engine32/SRPGStudio.h"
#include "engine32/RpgmXP.h"
#include "engine32/littlecheese.h"
#include "engine32/Eagls.h"
#include "engine32/Debonosu.h"
#include "engine32/C4.h"
#include "engine32/WillPlus.h"
#include "engine32/Tanuki.h"
#include "engine32/hibiki.h"
#include "engine32/GXP.h"
#include "engine32/Giga.h"
#include "engine32/AOS.h"
#include "engine32/Mink.h"
#include "engine32/AGS.h"
#include "engine32/YukaSystem2.h"
#include "engine32/Exp.h"
#include "engine32/Syuntada.h"
#include "engine32/Pensil.h"
#include "engine32/solfasys.h"
#include "engine32/Anim.h"
#include "engine32/Nitroplus2.h"
#include "engine32/Reallive.h"
#include "engine32/jukujojidai.h"
#include "engine32/Siglus.h"
#include "engine32/Taskforce2.h"
#include "engine32/RUGP.h"
#include "engine32/IronGameSystem.h"
#include "engine32/Anex86.h"
#include "engine32/ShinyDaysGame.h"
#include "engine32/MarineHeart.h"
#include "engine32/ShinaRio.h"
#include "engine32/CaramelBox.h"
#include "engine32/Escude.h"
#include "engine32/Ryokucha.h"
#include "engine32/Alice.h"
#include "engine32/System4x.h"
#include "engine32/Abel.h"
#include "engine32/5pb.h"
#include "engine32/HorkEye.h"
#include "engine32/Ohgetsu.h"
#include "engine32/OVERDRIVE.h"
#include "engine32/Leaf.h"
#include "engine32/Nekopack.h"
#include "engine32/AdobeFlash10.h"
#include "engine32/FocasLens.h"
#include "engine32/Tamamo.h"
#include "engine32/Suika2.h"
#include "engine32/Overflow.h"
#include "engine32/Ages3ResT.h"
#include "engine32/AXL.h"
#include "engine32/UnisonShift.h"
#include "engine32/EntisGLS.h"
#include "engine32/Ciel.h"
#include "engine32/CisLugI.h"
#include "engine32/A98SYS.h"
#include "engine32/ACTGS.h"
#include "engine32/GuruGuruSMF4.h"
#include "NoEngine.h"
#include "engines/lua/lua51.h"
#include "engines/python/Renpy.h"
std::vector<ENGINE *> check_engines()
{
return {
new LovaGame,
new PPSSPPengine,
@ -344,13 +345,12 @@ std::vector<ENGINE*> check_engines(){
new A98SYS,
new godot,
new Erogos,
new Silkysveryveryold
};
new Silkysveryveryold};
}
std::vector<ENGINE*> ignore_engines(){
return{
std::vector<ENGINE *> ignore_engines()
{
return {
new oldSystem40ini,
new AdvPlayerHD,
@ -359,10 +359,11 @@ std::vector<ENGINE*> ignore_engines(){
new Chartreux,
};
}
std::vector<ENGINE*> unsafe_check_atlast(){
std::vector<ENGINE *> unsafe_check_atlast()
{
// Put the patterns that might break other games at last
return{
return {
new UnisonShift,
new Interheart,
new Abalone,
@ -395,7 +396,5 @@ std::vector<ENGINE*> unsafe_check_atlast(){
new ShinaRio,
new Suika2,
new KISS,
new EntisGLS
};
new EntisGLS};
}

View File

@ -1,30 +1,31 @@
#include"engine64/PPSSPP.h"
#include"engine64/Godot.h"
#include"engine64/V8.h"
#include"engine64/mono.h"
#include"engine64/AGES7.h"
#include"engine64/pchooks.h"
#include"engine64/Artemis.h"
#include"engine64/KiriKiri.h"
#include"engine64/YOX.h"
#include"engine64/Suika2.h"
#include"engine64/livecaptions.h"
#include"engine64/CMVS.h"
#include"engine64/5pb.h"
#include"engine64/lucasystem.h"
#include"engine64/ENTERGRAM.h"
#include"engine64/TYPEMOON.h"
#include"engine64/Kincaid.h"
#include"engine64/LightVN.h"
#include"engine64/yuzusuyu.h"
#include"engine64/vita3k.h"
#include"engine64/rpcs3.h"
#include"engines/lua/lua51.h"
#include"engines/python/Renpy.h"
std::vector<ENGINE*> ignore_engines(){ return{ }; }
std::vector<ENGINE*> unsafe_check_atlast(){ return{ }; }
#include "engine64/PPSSPP.h"
#include "engine64/Godot.h"
#include "engine64/V8.h"
#include "engine64/mono.h"
#include "engine64/AGES7.h"
#include "engine64/pchooks.h"
#include "engine64/Artemis.h"
#include "engine64/KiriKiri.h"
#include "engine64/YOX.h"
#include "engine64/Suika2.h"
#include "engine64/livecaptions.h"
#include "engine64/CMVS.h"
#include "engine64/5pb.h"
#include "engine64/lucasystem.h"
#include "engine64/ENTERGRAM.h"
#include "engine64/TYPEMOON.h"
#include "engine64/Kincaid.h"
#include "engine64/LightVN.h"
#include "engine64/yuzusuyu.h"
#include "engine64/vita3k.h"
#include "engine64/rpcs3.h"
#include "engines/lua/lua51.h"
#include "engines/python/Renpy.h"
std::vector<ENGINE *> ignore_engines() { return {}; }
std::vector<ENGINE *> unsafe_check_atlast() { return {}; }
std::vector<ENGINE*> check_engines(){
std::vector<ENGINE *> check_engines()
{
return {
new Godot,
new V8,
@ -50,5 +51,4 @@ std::vector<ENGINE*> check_engines(){
new livecaptions,
new lua51,
};
}

View File

@ -1,104 +1,119 @@
WCHAR* processName, // cached
processPath[MAX_PATH]; // cached
WCHAR *processName, // cached
processPath[MAX_PATH]; // cached
WCHAR processName_lower[MAX_PATH];
uintptr_t processStartAddress, processStopAddress;
std::vector<ENGINE *> check_engines();
std::vector<ENGINE *> ignore_engines();
std::vector<ENGINE *> unsafe_check_atlast();
std::vector<ENGINE*> check_engines();
std::vector<ENGINE*> ignore_engines();
std::vector<ENGINE*> unsafe_check_atlast();
bool ENGINE::check_function(){
bool ENGINE::check_function()
{
switch (check_by)
{
case CHECK_BY::ALL_TRUE:{
is_engine_certain=false;
case CHECK_BY::ALL_TRUE:
{
is_engine_certain = false;
return true;
}
case CHECK_BY::FILE:{
return (Util::CheckFile(std::get<check_by_single>(check_by_target))) ;
case CHECK_BY::FILE:
{
return (Util::CheckFile(std::get<check_by_single>(check_by_target)));
}
case CHECK_BY::FILE_ALL:{
auto _list=std::get<check_by_list>(check_by_target);
return std::all_of(_list.begin(),_list.end(),Util::CheckFile);
case CHECK_BY::FILE_ALL:
{
auto _list = std::get<check_by_list>(check_by_target);
return std::all_of(_list.begin(), _list.end(), Util::CheckFile);
}
case CHECK_BY::FILE_ANY:{
auto _list=std::get<check_by_list>(check_by_target);
return std::any_of(_list.begin(),_list.end(),Util::CheckFile);
case CHECK_BY::FILE_ANY:
{
auto _list = std::get<check_by_list>(check_by_target);
return std::any_of(_list.begin(), _list.end(), Util::CheckFile);
}
case CHECK_BY::RESOURCE_STR:{
return (Util::SearchResourceString(std::get<check_by_single>(check_by_target))) ;
case CHECK_BY::RESOURCE_STR:
{
return (Util::SearchResourceString(std::get<check_by_single>(check_by_target)));
}
case CHECK_BY::CUSTOM:{
case CHECK_BY::CUSTOM:
{
return std::get<check_by_custom_function>(check_by_target)();
}
default:
return false;
}
}
bool safematch(ENGINE* m){
bool matched=false;
__try {
matched=m->check_function();
bool safematch(ENGINE *m)
{
bool matched = false;
__try
{
matched = m->check_function();
}
__except (EXCEPTION_EXECUTE_HANDLER) {
ConsoleOutput(Match_Error,m->getenginename());
//ConsoleOutput("match ERROR");
__except (EXCEPTION_EXECUTE_HANDLER)
{
ConsoleOutput(Match_Error, m->getenginename());
// ConsoleOutput("match ERROR");
}
return matched;
}
bool safeattach(ENGINE* m){
bool attached=false;
__try {
attached=m->attach_function();
bool safeattach(ENGINE *m)
{
bool attached = false;
__try
{
attached = m->attach_function();
}
__except (EXCEPTION_EXECUTE_HANDLER) {
ConsoleOutput(Attach_Error,m->getenginename());
//ConsoleOutput("attach ERROR");
__except (EXCEPTION_EXECUTE_HANDLER)
{
ConsoleOutput(Attach_Error, m->getenginename());
// ConsoleOutput("attach ERROR");
}
return attached;
}
bool checkengine(){
bool checkengine()
{
auto engines=check_engines();
auto engineatlast=unsafe_check_atlast();
auto engineignore=ignore_engines();
std::vector<const char*> infomations={
auto engines = check_engines();
auto engineatlast = unsafe_check_atlast();
auto engineignore = ignore_engines();
std::vector<const char *> infomations = {
"match failed",
"attach failed",
"attach success"
};
auto allengines={engines,engineignore,engineatlast};
int total=[allengines](){int _=0;for(auto eng:allengines)_+=eng.size();return _;}();
int current=0;
for(auto eng:allengines){
for(auto m:eng) {
current+=1;
"attach success"};
auto allengines = {engines, engineignore, engineatlast};
int total = [allengines]()
{int _=0;for(auto eng:allengines)_+=eng.size();return _; }();
int current = 0;
for (auto eng : allengines)
{
for (auto m : eng)
{
current += 1;
bool matched=safematch(m);
bool attached=matched&&safeattach(m);
bool matched = safematch(m);
bool attached = matched && safeattach(m);
//ConsoleOutput("Progress %d/%d, checked engine %s, %s",current,total,m->getenginename(),infomations[matched+attached]);
//ConsoleOutput("Progress %d/%d, %s",current,total,infomations[matched+attached]);
if(matched==false)continue;
ConsoleOutput(MatchedEngine,m->getenginename());
if(m->dontstop){
// ConsoleOutput("Progress %d/%d, checked engine %s, %s",current,total,m->getenginename(),infomations[matched+attached]);
// ConsoleOutput("Progress %d/%d, %s",current,total,infomations[matched+attached]);
if (matched == false)
continue;
ConsoleOutput(MatchedEngine, m->getenginename());
if (m->dontstop)
{
continue;
}
if(m->is_engine_certain){
ConsoleOutput(ConfirmStop,m->getenginename());
if (m->is_engine_certain)
{
ConsoleOutput(ConfirmStop, m->getenginename());
return attached;
}
if(attached){
ConsoleOutput(Attach_Stop,m->getenginename());
if (attached)
{
ConsoleOutput(Attach_Stop, m->getenginename());
return true;
}
}
@ -106,32 +121,38 @@ bool checkengine(){
return false;
}
void HIJACK(){
void HIJACK()
{
static bool once = false;
if(once)return;
once=true;
if (once)
return;
once = true;
GetModuleFileNameW(nullptr, processPath, MAX_PATH);
processName = wcsrchr(processPath, L'\\') + 1;
wcscpy_s(processName_lower, processName);
_wcslwr_s(processName_lower); // lower case
std::tie(processStartAddress,processStopAddress)=Util::QueryModuleLimits(GetModuleHandleW(nullptr),0,1+PAGE_NOACCESS);
std::tie(processStartAddress, processStopAddress) = Util::QueryModuleLimits(GetModuleHandleW(nullptr), 0, 1 + PAGE_NOACCESS);
spDefault.minAddress = processStartAddress;
spDefault.maxAddress = processStopAddress;
ConsoleOutput(ProcessRange, processStartAddress, processStopAddress);
if (processStartAddress + 0x40000 > processStopAddress) ConsoleOutput(WarningDummy);
if (processStartAddress + 0x40000 > processStopAddress)
ConsoleOutput(WarningDummy);
bool result=false;
__try {
bool result = false;
__try
{
result = checkengine();
}
__except (EXCEPTION_EXECUTE_HANDLER) { ConsoleOutput(HIJACK_ERROR); }
__except (EXCEPTION_EXECUTE_HANDLER)
{
ConsoleOutput(HIJACK_ERROR);
}
if(result==false){
if (result == false)
{
PcHooks::hookOtherPcFunctions();
}
}

View File

@ -2,86 +2,115 @@
#pragma intrinsic(_ReturnAddress)
// Disable only for debugging purpose
//#define HIJACK_GDI_FONT
//#define HIJACK_GDI_TEXT
// #define HIJACK_GDI_FONT
// #define HIJACK_GDI_TEXT
#define DEF_FUN(_f) Hijack::_f##_fun_t Hijack::old##_f = ::_f;
DEF_FUN(CreateFontA)
DEF_FUN(CreateFontW)
DEF_FUN(CreateFontIndirectA)
DEF_FUN(CreateFontIndirectW)
DEF_FUN(GetGlyphOutlineA)
DEF_FUN(GetGlyphOutlineW)
DEF_FUN(GetTextExtentPoint32A)
DEF_FUN(GetTextExtentPoint32W)
DEF_FUN(GetTextExtentExPointA)
DEF_FUN(GetTextExtentExPointW)
DEF_FUN(GetCharABCWidthsA)
DEF_FUN(GetCharABCWidthsW)
DEF_FUN(TextOutA)
DEF_FUN(TextOutW)
DEF_FUN(ExtTextOutA)
DEF_FUN(ExtTextOutW)
DEF_FUN(DrawTextA)
DEF_FUN(DrawTextW)
DEF_FUN(DrawTextExA)
DEF_FUN(DrawTextExW)
DEF_FUN(CharNextA)
//DEF_FUN(CharNextW)
//DEF_FUN(CharNextExA)
//DEF_FUN(CharNextExW)
DEF_FUN(CharPrevA)
//DEF_FUN(CharPrevW)
DEF_FUN(MultiByteToWideChar)
DEF_FUN(WideCharToMultiByte)
DEF_FUN(CreateFontA)
DEF_FUN(CreateFontW)
DEF_FUN(CreateFontIndirectA)
DEF_FUN(CreateFontIndirectW)
DEF_FUN(GetGlyphOutlineA)
DEF_FUN(GetGlyphOutlineW)
DEF_FUN(GetTextExtentPoint32A)
DEF_FUN(GetTextExtentPoint32W)
DEF_FUN(GetTextExtentExPointA)
DEF_FUN(GetTextExtentExPointW)
DEF_FUN(GetCharABCWidthsA)
DEF_FUN(GetCharABCWidthsW)
DEF_FUN(TextOutA)
DEF_FUN(TextOutW)
DEF_FUN(ExtTextOutA)
DEF_FUN(ExtTextOutW)
DEF_FUN(DrawTextA)
DEF_FUN(DrawTextW)
DEF_FUN(DrawTextExA)
DEF_FUN(DrawTextExW)
DEF_FUN(CharNextA)
// DEF_FUN(CharNextW)
// DEF_FUN(CharNextExA)
// DEF_FUN(CharNextExW)
DEF_FUN(CharPrevA)
// DEF_FUN(CharPrevW)
DEF_FUN(MultiByteToWideChar)
DEF_FUN(WideCharToMultiByte)
#undef DEF_FUN
/** Helper */
namespace { // unnamed
UINT8 systemCharSet(){
enum CodePage {
NullCodePage = 0
, Utf8CodePage = 65001 // UTF-8
, Utf16CodePage = 1200 // UTF-16
, SjisCodePage = 932 // SHIFT-JIS
, GbkCodePage = 936 // GB2312
, KscCodePage = 949 // EUC-KR
, Big5CodePage = 950 // BIG5
, TisCodePage = 874 // TIS-620
, Koi8CodePage = 866 // KOI8-R
};
namespace
{ // unnamed
UINT8 systemCharSet()
{
enum CodePage
{
NullCodePage = 0,
Utf8CodePage = 65001 // UTF-8
,
Utf16CodePage = 1200 // UTF-16
,
SjisCodePage = 932 // SHIFT-JIS
,
GbkCodePage = 936 // GB2312
,
KscCodePage = 949 // EUC-KR
,
Big5CodePage = 950 // BIG5
,
TisCodePage = 874 // TIS-620
,
Koi8CodePage = 866 // KOI8-R
};
auto systemCodePage = ::GetACP();
switch (systemCodePage) {
case TisCodePage: return THAI_CHARSET;
case Koi8CodePage: return RUSSIAN_CHARSET;
case SjisCodePage: return SHIFTJIS_CHARSET;
case GbkCodePage: return GB2312_CHARSET;
case Big5CodePage: return CHINESEBIG5_CHARSET;
switch (systemCodePage)
{
case TisCodePage:
return THAI_CHARSET;
case Koi8CodePage:
return RUSSIAN_CHARSET;
case SjisCodePage:
return SHIFTJIS_CHARSET;
case GbkCodePage:
return GB2312_CHARSET;
case Big5CodePage:
return CHINESEBIG5_CHARSET;
case KscCodePage: return HANGUL_CHARSET;
case 1361: return JOHAB_CHARSET; // alternative Korean character set
case KscCodePage:
return HANGUL_CHARSET;
case 1361:
return JOHAB_CHARSET; // alternative Korean character set
case 1250: return EASTEUROPE_CHARSET;
case 1251: return RUSSIAN_CHARSET; // cyrillic
case 1253: return GREEK_CHARSET;
case 1254: return TURKISH_CHARSET;
case 1250:
return EASTEUROPE_CHARSET;
case 1251:
return RUSSIAN_CHARSET; // cyrillic
case 1253:
return GREEK_CHARSET;
case 1254:
return TURKISH_CHARSET;
case 862: return HEBREW_CHARSET; // obsolete
case 1255: return HEBREW_CHARSET;
case 862:
return HEBREW_CHARSET; // obsolete
case 1255:
return HEBREW_CHARSET;
case 1256: return ARABIC_CHARSET;
case 1257: return BALTIC_CHARSET;
case 1258: return VIETNAMESE_CHARSET;
case 1256:
return ARABIC_CHARSET;
case 1257:
return BALTIC_CHARSET;
case 1258:
return VIETNAMESE_CHARSET;
//default: return DEFAULT_CHARSET;
default: return 0;
// default: return DEFAULT_CHARSET;
default:
return 0;
}
}
void customizeLogFontA(LOGFONTA *lplf)
{
}
void customizeLogFontA(LOGFONTA *lplf)
{
if (embedsharedmem->fontCharSetEnabled) {
if (embedsharedmem->fontCharSetEnabled)
{
auto charSet = embedsharedmem->fontCharSet;
if (!charSet)
charSet = systemCharSet();
@ -96,101 +125,103 @@ void customizeLogFontA(LOGFONTA *lplf)
lplf->lfHeight *= s->fontScale;
}
*/
}
}
void customizeLogFontW(LOGFONTW *lplf)
{
void customizeLogFontW(LOGFONTW *lplf)
{
customizeLogFontA((LOGFONTA *)lplf);
std::wstring s=embedsharedmem->fontFamily;
if (! s.empty()) {
std::wstring s = embedsharedmem->fontFamily;
if (!s.empty())
{
lplf->lfFaceName[s.size()] = 0;
//s->fontFamily.toWCharArray(lplf->lfFaceName);
// s->fontFamily.toWCharArray(lplf->lfFaceName);
memcpy(lplf->lfFaceName, s.c_str(), s.size());
}
}
}
// LogFont manager
// LogFont manager
class LogFontManager
{
class LogFontManager
{
typedef std::pair<HFONT, LOGFONTW> font_pair;
std::list<font_pair> fonts_;
static bool eq(const LOGFONTW &x, const LOGFONTW&y);
static bool eq(const LOGFONTW &x, const LOGFONTW &y);
public:
public:
HFONT get(const LOGFONTW &lf) const;
void add(HFONT hf, const LOGFONTW &lf);
void remove(HFONT hf);
void remove(const LOGFONTW &lf);
};
};
bool LogFontManager::eq(const LOGFONTW &x, const LOGFONTW &y)
{ // I assume there is no padding
return ::wcscmp(x.lfFaceName, y.lfFaceName) == 0
&& ::memcmp(&x, &y, sizeof(x) - sizeof(x.lfFaceName)) == 0;
}
bool LogFontManager::eq(const LOGFONTW &x, const LOGFONTW &y)
{ // I assume there is no padding
return ::wcscmp(x.lfFaceName, y.lfFaceName) == 0 && ::memcmp(&x, &y, sizeof(x) - sizeof(x.lfFaceName)) == 0;
}
void LogFontManager::add(HFONT hf, const LOGFONTW &lf)
{ fonts_.push_back(std::make_pair(hf, lf)); }
void LogFontManager::add(HFONT hf, const LOGFONTW &lf)
{
fonts_.push_back(std::make_pair(hf, lf));
}
void LogFontManager::remove(HFONT hf)
{
auto _=std::remove_if(fonts_.begin(), fonts_.end(), [&hf](const font_pair &it) {
return it.first == hf;
});
}
void LogFontManager::remove(HFONT hf)
{
auto _ = std::remove_if(fonts_.begin(), fonts_.end(), [&hf](const font_pair &it)
{ return it.first == hf; });
}
void LogFontManager::remove(const LOGFONTW &lf)
{
auto _=std::remove_if(fonts_.begin(), fonts_.end(), [&lf](const font_pair &it) {
return eq(it.second, lf);
});
}
void LogFontManager::remove(const LOGFONTW &lf)
{
auto _ = std::remove_if(fonts_.begin(), fonts_.end(), [&lf](const font_pair &it)
{ return eq(it.second, lf); });
}
HFONT LogFontManager::get(const LOGFONTW &lf) const
{
HFONT LogFontManager::get(const LOGFONTW &lf) const
{
for each (const font_pair &it in fonts_)
if (eq(it.second, lf))
return it.first;
return nullptr;
}
}
// GDI font switcher
// GDI font switcher
class DCFontSwitcher
{
class DCFontSwitcher
{
static LogFontManager fonts_;
HDC hdc_;
HFONT oldFont_,
newFont_;
std::wstring newfontname;
public:
std::wstring newfontname;
public:
explicit DCFontSwitcher(HDC hdc); // pass 0 to disable this class
~DCFontSwitcher();
};
};
LogFontManager DCFontSwitcher::fonts_;
LogFontManager DCFontSwitcher::fonts_;
DCFontSwitcher::~DCFontSwitcher()
{
DCFontSwitcher::~DCFontSwitcher()
{
// No idea why selecting old font will crash Mogeko Castle
//if (oldFont_ && oldFont_ != HGDI_ERROR)
// if (oldFont_ && oldFont_ != HGDI_ERROR)
// ::SelectObject(hdc_, oldFont_);
// Never delete new font but cache them
// This could result in bad font after game is reset and deleted my font
//if (newFont_)
// if (newFont_)
// ::DeleteObject(newFont_);
}
bool isFontCustomized(){
return embedsharedmem->fontCharSetEnabled||wcslen(embedsharedmem->fontFamily);
}
DCFontSwitcher::DCFontSwitcher(HDC hdc)
: hdc_(hdc), oldFont_(nullptr), newFont_(nullptr),newfontname(L"")
{
}
bool isFontCustomized()
{
return embedsharedmem->fontCharSetEnabled || wcslen(embedsharedmem->fontFamily);
}
DCFontSwitcher::DCFontSwitcher(HDC hdc)
: hdc_(hdc), oldFont_(nullptr), newFont_(nullptr), newfontname(L"")
{
if (!hdc_)
return;
/*
@ -218,18 +249,19 @@ DCFontSwitcher::DCFontSwitcher(HDC hdc)
if (std::wstring(embedsharedmem->fontFamily).empty())
::GetTextFaceW(hdc_, LF_FACESIZE, lf.lfFaceName);
else{
wcscpy(lf.lfFaceName,embedsharedmem->fontFamily);
else
{
wcscpy(lf.lfFaceName, embedsharedmem->fontFamily);
}
newFont_ = fonts_.get(lf);
if ((!newFont_ )||(newfontname!=std::wstring(embedsharedmem->fontFamily))) {
if ((!newFont_) || (newfontname != std::wstring(embedsharedmem->fontFamily)))
{
newFont_ = Hijack::oldCreateFontIndirectW(&lf);
fonts_.add(newFont_, lf);
newfontname=std::wstring(embedsharedmem->fontFamily);
newfontname = std::wstring(embedsharedmem->fontFamily);
}
oldFont_ = (HFONT)SelectObject(hdc_, newFont_);
}
}
} // unnamed namespace
@ -240,22 +272,26 @@ DCFontSwitcher::DCFontSwitcher(HDC hdc)
HFONT WINAPI Hijack::newCreateFontIndirectA(const LOGFONTA *lplf)
{
//DOUT("width:" << lplf->lfWidth << ", height:" << lplf->lfHeight << ", weight:" << lplf->lfWeight);
// DOUT("width:" << lplf->lfWidth << ", height:" << lplf->lfHeight << ", weight:" << lplf->lfWeight);
// if (auto p = HijackHelper::instance()) {
// auto s = p->settings();
std::wstring fontFamily=embedsharedmem->fontFamily;
if (lplf && isFontCustomized()) {
union {
std::wstring fontFamily = embedsharedmem->fontFamily;
if (lplf && isFontCustomized())
{
union
{
LOGFONTA a;
LOGFONTW w;
} lf = {*lplf}; // only initialize the first member of LOGFONTA
customizeLogFontA(&lf.a);
if (!fontFamily.empty()) {
if (all_ascii(fontFamily.c_str(),fontFamily.size()))
::strcpy(lf.a.lfFaceName, WideStringToString(fontFamily,CP_ACP).c_str());
else {
if (!fontFamily.empty())
{
if (all_ascii(fontFamily.c_str(), fontFamily.size()))
::strcpy(lf.a.lfFaceName, WideStringToString(fontFamily, CP_ACP).c_str());
else
{
lf.w.lfFaceName[fontFamily.size()] = 0;
//s->fontFamily.toWCharArray(lf.w.lfFaceName);
// s->fontFamily.toWCharArray(lf.w.lfFaceName);
memcpy(lf.w.lfFaceName, fontFamily.c_str(), fontFamily.size());
return oldCreateFontIndirectW(&lf.w);
}
@ -269,10 +305,11 @@ HFONT WINAPI Hijack::newCreateFontIndirectA(const LOGFONTA *lplf)
HFONT WINAPI Hijack::newCreateFontIndirectW(const LOGFONTW *lplf)
{
//DOUT("width:" << lplf->lfWidth << ", height:" << lplf->lfHeight << ", weight:" << lplf->lfWeight);
// DOUT("width:" << lplf->lfWidth << ", height:" << lplf->lfHeight << ", weight:" << lplf->lfWeight);
// if (auto p = HijackHelper::instance()) {
// auto s = p->settings();
if (lplf && isFontCustomized()) {
if (lplf && isFontCustomized())
{
LOGFONTW lf(*lplf);
customizeLogFontW(&lf);
return oldCreateFontIndirectW(&lf);
@ -285,10 +322,10 @@ HFONT WINAPI Hijack::newCreateFontIndirectW(const LOGFONTW *lplf)
HFONT WINAPI Hijack::newCreateFontA(int nHeight, int nWidth, int nEscapement, int nOrientation, int fnWeight, DWORD fdwItalic, DWORD fdwUnderline, DWORD fdwStrikeOut, DWORD fdwCharSet, DWORD fdwOutputPrecision, DWORD fdwClipPrecision, DWORD fdwQuality, DWORD fdwPitchAndFamily, LPCSTR lpszFace)
{
if ( isFontCustomized()) {
if (embedsharedmem->fontCharSetEnabled) {
if (isFontCustomized())
{
if (embedsharedmem->fontCharSetEnabled)
{
auto charSet = embedsharedmem->fontCharSet;
if (!charSet)
charSet = systemCharSet();
@ -303,12 +340,16 @@ HFONT WINAPI Hijack::newCreateFontA(int nHeight, int nWidth, int nEscapement, in
nHeight *= s->fontScale;
}
*/
std::wstring fontFamily=embedsharedmem->fontFamily;
if (!fontFamily.empty()) {
if (all_ascii(fontFamily.c_str(),fontFamily.size())) {
lpszFace =WideStringToString(fontFamily,CP_ACP).c_str();
std::wstring fontFamily = embedsharedmem->fontFamily;
if (!fontFamily.empty())
{
if (all_ascii(fontFamily.c_str(), fontFamily.size()))
{
lpszFace = WideStringToString(fontFamily, CP_ACP).c_str();
return oldCreateFontA(CREATE_FONT_ARGS);
} else {
}
else
{
auto lpszFace = (LPCWSTR)fontFamily.c_str();
return oldCreateFontW(CREATE_FONT_ARGS);
}
@ -320,9 +361,10 @@ HFONT WINAPI Hijack::newCreateFontA(int nHeight, int nWidth, int nEscapement, in
HFONT WINAPI Hijack::newCreateFontW(int nHeight, int nWidth, int nEscapement, int nOrientation, int fnWeight, DWORD fdwItalic, DWORD fdwUnderline, DWORD fdwStrikeOut, DWORD fdwCharSet, DWORD fdwOutputPrecision, DWORD fdwClipPrecision, DWORD fdwQuality, DWORD fdwPitchAndFamily, LPCWSTR lpszFace)
{
if (isFontCustomized()) {
if (embedsharedmem->fontCharSetEnabled) {
if (isFontCustomized())
{
if (embedsharedmem->fontCharSetEnabled)
{
auto charSet = embedsharedmem->fontCharSet;
if (!charSet)
charSet = systemCharSet();
@ -348,19 +390,19 @@ HFONT WINAPI Hijack::newCreateFontW(int nHeight, int nWidth, int nEscapement, in
LPSTR WINAPI Hijack::newCharNextA(LPCSTR lpString)
{
//if (::GetACP() == 932)
// if (::GetACP() == 932)
return const_cast<char *>(dynsjis::nextchar(lpString));
//return oldCharNextA(lpString);
// return oldCharNextA(lpString);
}
LPSTR WINAPI Hijack::newCharPrevA(LPCSTR lpStart, LPCSTR lpCurrent)
{
//if (::GetACP() == 932)
// if (::GetACP() == 932)
return const_cast<char *>(dynsjis::prevchar(lpCurrent, lpStart));
//return oldCharNextA(lpStart, lpCurrent);
// return oldCharNextA(lpStart, lpCurrent);
}
extern DynamicShiftJISCodec *dynamiccodec ;
extern DynamicShiftJISCodec *dynamiccodec;
int WINAPI Hijack::newMultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar)
{
//
@ -372,14 +414,16 @@ int WINAPI Hijack::newMultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR l
if (CodePage == CP_THREAD_ACP || CodePage == CP_OEMCP)
CodePage = CP_ACP;
// CP_ACP(0), CP_MACCP(1), CP_OEMCP(2), CP_THREAD_ACP(3)
if ((CodePage <= 3 || CodePage == 932) && cchWideChar > 0 && cbMultiByte > 1) {
if ((CodePage <= 3 || CodePage == 932) && cchWideChar > 0 && cbMultiByte > 1)
{
bool dynamic;
std::string data(lpMultiByteStr, cbMultiByte);
auto text = dynamiccodec->decode(data, &dynamic);
if (dynamic && !text.empty()) {
if (dynamic && !text.empty())
{
int size = min(text.size() + 1, cchWideChar);
::memcpy(lpWideCharStr, text.c_str(), size * 2);
//lpWideCharStr[size - 1] = 0; // enforce trailing zero
// lpWideCharStr[size - 1] = 0; // enforce trailing zero
return size - 1;
}
}
@ -392,17 +436,19 @@ int WINAPI Hijack::newWideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR
if (CodePage == CP_THREAD_ACP || CodePage == CP_OEMCP)
CodePage = CP_ACP;
if ((CodePage <= 3 || CodePage == 932) && cchWideChar > 0 && cbMultiByte >= 0) {
if ((CodePage <= 3 || CodePage == 932) && cchWideChar > 0 && cbMultiByte >= 0)
{
bool dynamic;
auto text = std::wstring(lpWideCharStr, cchWideChar);
auto data = dynamiccodec->encodeSTD(text, &dynamic);
if (dynamic && !data.empty()) {
if (dynamic && !data.empty())
{
int size = data.size() + 1;
if (cbMultiByte && cbMultiByte < size)
size = cbMultiByte;
::memcpy(lpMultiByteStr, data.c_str(), size);
//lpMultiByteStr[size - 1] = 0; // enforce trailing zero
// lpMultiByteStr[size - 1] = 0; // enforce trailing zero
return size - 1;
}
}
@ -414,72 +460,90 @@ UINT decodeChar(UINT ch, bool *dynamic)
{
if (dynamic)
*dynamic = false;
if (ch > 0xff) {
if (ch > 0xff)
{
bool t;
char data[3] = {(BYTE)(ch>>8)&0xff, (BYTE)ch&0xff, 0};
char data[3] = {(BYTE)(ch >> 8) & 0xff, (BYTE)ch & 0xff, 0};
auto text = dynamiccodec->decode(data, &t);
if (t && text.size() == 1) {
if (t && text.size() == 1)
{
if (dynamic)
*dynamic= true;
return text[0] ;
*dynamic = true;
return text[0];
}
}
return ch;
}
#define DECODE_CHAR(uChar, ...) \
{ \
{ \
if (uChar > 0xff) \
if (1) { \
if (1) \
{ \
bool dynamic; \
UINT ch = decodeChar(uChar, &dynamic); \
if (dynamic && ch) { \
if (dynamic && ch) \
{ \
uChar = ch; \
return (__VA_ARGS__); \
} \
} \
}
}
#define DECODE_TEXT(lpString, cchString, ...) \
{ \
if(cchString == -1 || cchString > 1) \
if (1) { \
{ \
if (cchString == -1 || cchString > 1) \
if (1) \
{ \
bool dynamic; \
auto data = std::string(lpString, cchString == -1 ? ::strlen(lpString) : cchString); \
if (data.size() > 1) { \
if (data.size() > 1) \
{ \
auto text = dynamiccodec->decode(data, &dynamic); \
if (dynamic && !text.empty()) { \
if (dynamic && !text.empty()) \
{ \
LPCWSTR lpString = (LPCWSTR)text.c_str(); \
cchString = text.size(); \
return (__VA_ARGS__); \
} \
} \
} \
}
}
#define TRANSLATE_TEXT_A(lpString, cchString, ...) \
{ \
if (auto q = EngineController::instance()) { \
{ \
if (auto q = EngineController::instance()) \
{ \
auto data = std::string(lpString, cchString == -1 ? ::strlen(lpString) : cchString); \
std::wstring oldText = q->decode(data); \
if (!oldText.empty()) { \
enum { role = Engine::OtherRole }; \
if (!oldText.empty()) \
{ \
enum \
{ \
role = Engine::OtherRole \
}; \
ULONG split = (ULONG)_ReturnAddress(); \
auto sig = Engine::hashThreadSignature(role, split); \
auto newText = q->dispatchTextWSTD(oldText, role, sig); \
if (newText != oldText) { \
if (newText != oldText) \
{ \
LPCWSTR lpString = (LPCWSTR)newText.c_str(); \
cchString = newText.size(); \
return (__VA_ARGS__); \
} \
} \
} \
}
}
#define TRANSLATE_TEXT_W(lpString, cchString, ...) \
{ \
if (auto q = EngineController::instance()) { \
{ \
if (auto q = EngineController::instance()) \
{ \
auto text = std::wstring(lpString, cchString); \
if (!text.empty()) { \
enum { role = Engine::OtherRole }; \
if (!text.empty()) \
{ \
enum \
{ \
role = Engine::OtherRole \
}; \
ULONG split = (ULONG)_ReturnAddress(); \
auto sig = Engine::hashThreadSignature(role, split); \
text = q->dispatchTextWSTD(text, role, sig); \
@ -488,7 +552,7 @@ UINT decodeChar(UINT ch, bool *dynamic)
return (__VA_ARGS__); \
} \
} \
}
}
DWORD WINAPI Hijack::newGetGlyphOutlineA(HDC hdc, UINT uChar, UINT uFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpvBuffer, const MAT2 *lpmat2)
{
@ -508,9 +572,8 @@ DWORD WINAPI Hijack::newGetGlyphOutlineW(HDC hdc, UINT uChar, UINT uFormat, LPGL
BOOL WINAPI Hijack::newGetTextExtentPoint32A(HDC hdc, LPCSTR lpString, int cchString, LPSIZE lpSize)
{
DCFontSwitcher fs(hdc);
//TRANSLATE_TEXT_A(lpString, cchString, oldGetTextExtentPoint32W(hdc, lpString, cchString, lpSize))
// TRANSLATE_TEXT_A(lpString, cchString, oldGetTextExtentPoint32W(hdc, lpString, cchString, lpSize))
DECODE_TEXT(lpString, cchString, oldGetTextExtentPoint32W(hdc, lpString, cchString, lpSize))
return oldGetTextExtentPoint32A(hdc, lpString, cchString, lpSize);
}
@ -519,7 +582,7 @@ BOOL WINAPI Hijack::newGetTextExtentPoint32W(HDC hdc, LPCWSTR lpString, int cchS
{
DCFontSwitcher fs(hdc);
//TRANSLATE_TEXT_W(lpString, cchString, oldGetTextExtentPoint32W(hdc, lpString, cchString, lpSize))
// TRANSLATE_TEXT_W(lpString, cchString, oldGetTextExtentPoint32W(hdc, lpString, cchString, lpSize))
return oldGetTextExtentPoint32W(hdc, lpString, cchString, lpSize);
}
@ -527,7 +590,7 @@ BOOL WINAPI Hijack::newGetTextExtentExPointA(HDC hdc, LPCSTR lpString, int cchSt
{
// DCFontSwitcher fs(hdc);
//TRANSLATE_TEXT_A(lpString, cchString, oldGetTextExtentExPointW(hdc, lpString, cchString, nMaxExtent, lpnFit, alpDx, lpSize))
// TRANSLATE_TEXT_A(lpString, cchString, oldGetTextExtentExPointW(hdc, lpString, cchString, nMaxExtent, lpnFit, alpDx, lpSize))
DECODE_TEXT(lpString, cchString, oldGetTextExtentExPointW(hdc, lpString, cchString, nMaxExtent, lpnFit, alpDx, lpSize))
return oldGetTextExtentExPointA(hdc, lpString, cchString, nMaxExtent, lpnFit, alpDx, lpSize);
}
@ -536,7 +599,7 @@ BOOL WINAPI Hijack::newGetTextExtentExPointW(HDC hdc, LPCWSTR lpString, int cchS
{
DCFontSwitcher fs(hdc);
//TRANSLATE_TEXT_W(lpString, cchString, oldGetTextExtentExPointW(hdc, lpString, cchString, nMaxExtent, lpnFit, alpDx, lpSize))
// TRANSLATE_TEXT_W(lpString, cchString, oldGetTextExtentExPointW(hdc, lpString, cchString, nMaxExtent, lpnFit, alpDx, lpSize))
return oldGetTextExtentExPointW(hdc, lpString, cchString, nMaxExtent, lpnFit, alpDx, lpSize);
}
@ -564,7 +627,8 @@ int WINAPI Hijack::newDrawTextExA(HDC hdc, LPSTR lpString, int cchString, LPRECT
{
DCFontSwitcher fs(hdc);
if (!(dwDTFormat & DT_MODIFYSTRING)) {
if (!(dwDTFormat & DT_MODIFYSTRING))
{
// if (HijackManager::instance()->isFunctionTranslated((uintptr_t)::DrawTextExA))
// TRANSLATE_TEXT_A(lpString, cchString, oldDrawTextExW(hdc, const_cast<LPWSTR>(lpString), cchString, lpRect, dwDTFormat, lpDTParams))
// else
@ -622,6 +686,4 @@ BOOL WINAPI Hijack::newExtTextOutW(HDC hdc, int X, int Y, UINT fuOptions, const
return oldExtTextOutW(hdc, X, Y, fuOptions, lprc, lpString, cchString, lpDx);
}
// EOF

View File

@ -1,10 +1,10 @@
#pragma once
namespace Hijack {
namespace Hijack
{
#define DEF_FUN(_fun, _return, ...) \
typedef _return (WINAPI *_fun##_fun_t)(__VA_ARGS__); \
typedef _return(WINAPI *_fun##_fun_t)(__VA_ARGS__); \
extern _fun##_fun_t old##_fun; \
_return WINAPI new##_fun(__VA_ARGS__);
@ -35,7 +35,6 @@ namespace Hijack {
DEF_FUN(ExtTextOutA, BOOL, HDC hdc, int X, int Y, UINT fuOptions, const RECT *lprc, LPCSTR lpString, UINT cbCount, const INT *lpDx)
DEF_FUN(ExtTextOutW, BOOL, HDC hdc, int X, int Y, UINT fuOptions, const RECT *lprc, LPCWSTR lpString, UINT cbCount, const INT *lpDx)
DEF_FUN(DrawTextA, int, HDC hdc, LPCSTR lpString, int nCount, LPRECT lpRect, UINT uFormat)
DEF_FUN(DrawTextW, int, HDC hdc, LPCWSTR lpString, int nCount, LPRECT lpRect, UINT uFormat)
@ -43,14 +42,14 @@ namespace Hijack {
DEF_FUN(DrawTextExW, int, HDC hdc, LPWSTR lpString, int nCount, LPRECT lpRect, UINT dwDTFormat, LPDRAWTEXTPARAMS lpDTParams)
DEF_FUN(CharNextA, LPSTR, LPCSTR lpString)
//DEF_FUN(CharNextW, LPWSTR, LPCWSTR lpString)
//DEF_FUN(CharNextExA, LPSTR, WORD COdePage, LPCSTR lpString, DWORD dwFlags)
//DEF_FUN(CharNextExW, LPWSTR, WORD COdePage, LPCWSTR lpString, DWORD dwFlags)
// DEF_FUN(CharNextW, LPWSTR, LPCWSTR lpString)
// DEF_FUN(CharNextExA, LPSTR, WORD COdePage, LPCSTR lpString, DWORD dwFlags)
// DEF_FUN(CharNextExW, LPWSTR, WORD COdePage, LPCWSTR lpString, DWORD dwFlags)
DEF_FUN(CharPrevA, LPSTR, LPCSTR lpStart, LPCSTR lpCurrent)
//DEF_FUN(CharNextW, LPWSTR, LPCWSTR lpStart, LPCWSTR lpCurrent)
// DEF_FUN(CharNextW, LPWSTR, LPCWSTR lpStart, LPCWSTR lpCurrent)
#undef DEF_FUN
// Global variables
// Global variables
} // namespace Hijack

View File

@ -8,8 +8,8 @@ namespace
struct HookRecord
{
uint64_t address = 0;
uint64_t em_addr=0;
int argidx=0;
uint64_t em_addr = 0;
int argidx = 0;
uintptr_t padding = 0;
int offset = 0;
JITTYPE jittype;
@ -26,15 +26,15 @@ namespace
{
0x9c, // pushfd
0x60, // pushad
0x68, 0,0,0,0, // push @addr ; after this a total of 0x28 bytes are pushed
0x68, 0, 0, 0, 0, // push @addr ; after this a total of 0x28 bytes are pushed
0x8d, 0x44, 0x24, 0x28, // lea eax,[esp+0x28]
0x50, // push eax ; stack
0xbb, 0,0,0,0, // mov ebx,@Send
0xbb, 0, 0, 0, 0, // mov ebx,@Send
0xff, 0xd3, // call ebx
0x83, 0xc4, 0x08, // add esp, 0x8 ; doesn't matter which register
0x61, // popad
0x9d, // popfd
0x68, 0,0,0,0, // push @original
0x68, 0, 0, 0, 0, // push @original
0xc3 // ret ; basically absolute jmp to @original
};
constexpr int addr_offset = 3, send_offset = 13, original_offset = 25, registers = 8;
@ -63,8 +63,8 @@ namespace
0xf3, 0x0f, 0x7f, 0x24, 0x24, // movdqu [rsp],xmm4
0xf3, 0x0f, 0x7f, 0x6c, 0x24, 0x10, // movdqu [rsp+0x10],xmm5
0x48, 0x8d, 0x8c, 0x24, 0xa8, 0x00, 0x00, 0x00, // lea rcx,[rsp+0xa8]
0x48, 0xba, 0,0,0,0,0,0,0,0, // mov rcx,@addr
0x48, 0xb8, 0,0,0,0,0,0,0,0, // mov rax,@Send
0x48, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, // mov rcx,@addr
0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, // mov rax,@Send
0x48, 0x89, 0xe3, // mov rbx,rsp
0x48, 0x83, 0xe4, 0xf0, // and rsp,0xfffffffffffffff0 ; align stack
0xff, 0xd0, // call rax
@ -90,23 +90,26 @@ namespace
0x58, // pop rax
0x9d, // pop rflags
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip]
0,0,0,0,0,0,0,0 // @original
0, 0, 0, 0, 0, 0, 0, 0 // @original
};
constexpr int addr_offset = 50, send_offset = 60, original_offset = 126, registers = 16;
#endif
}
bool IsBadReadPtr(void* data)
bool IsBadReadPtr(void *data)
{
if (data > records.get() && data < records.get() + sp.maxRecords) return true;
if (data > records.get() && data < records.get() + sp.maxRecords)
return true;
uintptr_t BAD_PAGE = (uintptr_t)data >> 12;
auto& cacheEntry = pageCache[BAD_PAGE % CACHE_SIZE];
if (cacheEntry == BAD_PAGE) return true;
if (cacheEntry == GOOD_PAGE) return false;
auto &cacheEntry = pageCache[BAD_PAGE % CACHE_SIZE];
if (cacheEntry == BAD_PAGE)
return true;
if (cacheEntry == GOOD_PAGE)
return false;
__try
{
volatile char _ = *(char*)data;
volatile char _ = *(char *)data;
cacheEntry = GOOD_PAGE;
}
__except (EXCEPTION_EXECUTE_HANDLER)
@ -121,40 +124,45 @@ 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)
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;
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);
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;
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;
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)
if (jittype == JITTYPE::PC)
{
records[n].address = address;
records[n].offset = i * sizeof(char*);
records[n].offset = i * sizeof(char *);
}
else
{
records[n].em_addr=em_addr;
records[n].argidx=i;
records[n].em_addr = em_addr;
records[n].argidx = i;
}
for (int j = 0; j < length; ++j) records[n].text[j] = str[j];
for (int j = 0; j < length; ++j)
records[n].text[j] = str[j];
records[n].text[length] = 0;
}
if (n == sp.maxRecords)
@ -164,122 +172,152 @@ void DoSend(int i,uintptr_t address,char* str,uintptr_t padding,JITTYPE jittype=
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
}
void Send(char** stack, uintptr_t address)
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)
// the exceptions are compiler intrinsics like _InterlockedDecrement
if (recordsAvailable <= 0) return;
for (int i = -registers; i < 10; ++i) for (auto padding : { uintptr_t{}, sp.padding })
if (recordsAvailable <= 0)
return;
for (int i = -registers; i < 10; ++i)
for (auto padding : {uintptr_t{}, sp.padding})
{
DoSend(i,address,stack[i],padding);
DoSend(i, address, stack[i], padding);
}
}
void SafeSendJitVeh(hook_stack* stack,uintptr_t address,uintptr_t em_addr,JITTYPE jittype){
void SafeSendJitVeh(hook_stack *stack, uintptr_t address, uintptr_t em_addr, JITTYPE jittype)
{
__try
{
for (int i = 0;i<16;i++)
for (int i = 0; i < 16; i++)
{
char* str=0;
char *str = 0;
switch (jittype)
{
#ifdef _WIN64
#ifdef _WIN64
case JITTYPE::YUZU:
str=(char*)YUZU::emu_arg(stack)[i];
str = (char *)YUZU::emu_arg(stack)[i];
break;
case JITTYPE::VITA3K:
str=(char*)VITA3K::emu_arg(stack)[i];
str = (char *)VITA3K::emu_arg(stack)[i];
break;
case JITTYPE::RPCS3:
str=(char*)RPCS3::emu_arg(stack)[i];
str = (char *)RPCS3::emu_arg(stack)[i];
break;
#endif
#endif
case JITTYPE::PPSSPP:
str=(char*)PPSSPP::emu_arg(stack)[i];
str = (char *)PPSSPP::emu_arg(stack)[i];
break;
default:
return;
}
DoSend(i,address,str,0,jittype,em_addr);
DoSend(i, address, str, 0, jittype, em_addr);
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
}__except (EXCEPTION_EXECUTE_HANDLER) {}
}
std::unordered_map<uintptr_t,uint64_t>addresscalledtime;
bool safeautoleaveveh=false;
bool SendJitVeh(PCONTEXT context,uintptr_t address,uintptr_t em_addr,JITTYPE jittype){
if(safeautoleaveveh)return true;
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);
std::unordered_map<uintptr_t, uint64_t> addresscalledtime;
bool safeautoleaveveh = false;
bool SendJitVeh(PCONTEXT context, uintptr_t address, uintptr_t em_addr, JITTYPE jittype)
{
if (safeautoleaveveh)
return true;
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 {};
IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)module;
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) return {};
IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)(module + dosHeader->e_lfanew);
if (ntHeader->Signature != IMAGE_NT_SIGNATURE) return {};
if (!module)
return {};
IMAGE_DOS_HEADER *dosHeader = (IMAGE_DOS_HEADER *)module;
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
return {};
IMAGE_NT_HEADERS *ntHeader = (IMAGE_NT_HEADERS *)(module + dosHeader->e_lfanew);
if (ntHeader->Signature != IMAGE_NT_SIGNATURE)
return {};
DWORD exportAddress = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (!exportAddress) return {};
IMAGE_EXPORT_DIRECTORY* exportDirectory = (IMAGE_EXPORT_DIRECTORY*)(module + exportAddress);
if (!exportAddress)
return {};
IMAGE_EXPORT_DIRECTORY *exportDirectory = (IMAGE_EXPORT_DIRECTORY *)(module + exportAddress);
std::vector<uintptr_t> functions;
for (int i = 0; i < exportDirectory->NumberOfNames; ++i)
//char* funcName = (char*)(module + *(DWORD*)(module + exportDirectory->AddressOfNames + i * sizeof(DWORD)));
functions.push_back(module + *(DWORD*)(module + exportDirectory->AddressOfFunctions +
sizeof(DWORD) * *(WORD*)(module + exportDirectory->AddressOfNameOrdinals + i * sizeof(WORD))));
// char* funcName = (char*)(module + *(DWORD*)(module + exportDirectory->AddressOfNames + i * sizeof(DWORD)));
functions.push_back(module + *(DWORD *)(module + exportDirectory->AddressOfFunctions +
sizeof(DWORD) * *(WORD *)(module + exportDirectory->AddressOfNameOrdinals + i * sizeof(WORD))));
return functions;
}
void mergevector(std::vector<uintptr_t> &v1,std::vector<uintptr_t> &v2){
for(auto addr:v2){
void mergevector(std::vector<uintptr_t> &v1, std::vector<uintptr_t> &v2)
{
for (auto addr : v2)
{
auto it = std::find(v1.begin(), v1.end(), addr);
if (it == v1.end()) {
if (it == v1.end())
{
v1.push_back(addr);
}
}
}
void SearchForHooks_Return(){
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.jittype = records[i].jittype;
hp.padding = records[i].padding;
if(records[i].jittype==JITTYPE::PC)
if (records[i].jittype == JITTYPE::PC)
{
if (!records[i].address) continue;
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 (!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;
}
NotifyHookFound(hp, (wchar_t*)records[i].text);
if (++results % 100'000 == 0) ConsoleOutput(ResultsNum, results);
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;
for (int i = 0; i < CACHE_SIZE; ++i)
signatureCache[i] = sumCache[i] = 0;
}
void initrecords(){
void initrecords()
{
do
try { records = std::make_unique<HookRecord[]>(recordsAvailable = sp.maxRecords); }
catch (std::bad_alloc) { ConsoleOutput(SearchForHooks_ERROR, sp.maxRecords /= 2); }
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)
{
@ -421,27 +459,28 @@ void SearchForHooks(SearchParam spUser)
// }
safeautoleaveveh=true;
SearchForHooks_Return();
}
}).detach();
} })
.detach();
}
void SearchForText(wchar_t* text, UINT codepage)
void SearchForText(wchar_t *text, UINT codepage)
{
bool found = false;
char utf8Text[PATTERN_SIZE * 4] = {};
WideCharToMultiByte(CP_UTF8, 0, text, PATTERN_SIZE, utf8Text, PATTERN_SIZE * 4, nullptr, nullptr);
char codepageText[PATTERN_SIZE * 4] = {};
if(codepage!=CP_UTF8)
if (codepage != CP_UTF8)
WideCharToMultiByte(codepage, 0, text, PATTERN_SIZE, codepageText, PATTERN_SIZE * 4, nullptr, nullptr);
if (strlen(utf8Text) < 4 || ((codepage!=CP_UTF8)&&(strlen(codepageText) < 4)) || wcslen(text) < 4) return ConsoleOutput(NOT_ENOUGH_TEXT);
if (strlen(utf8Text) < 4 || ((codepage != CP_UTF8) && (strlen(codepageText) < 4)) || wcslen(text) < 4)
return ConsoleOutput(NOT_ENOUGH_TEXT);
ConsoleOutput(HOOK_SEARCH_STARTING);
auto GenerateHooks = [&](std::vector<uintptr_t> addresses, HookParamType type)
{
for (auto addr : addresses)
{
if (abs((long long)(utf8Text - addr)) < 20000) continue; // don't add read code if text is on this thread's stack
if (abs((long long)(utf8Text - addr)) < 20000)
continue; // don't add read code if text is on this thread's stack
found = true;
HookParam hp;
hp.type = DIRECT_READ | type;
@ -451,8 +490,9 @@ void SearchForText(wchar_t* text, UINT codepage)
}
};
GenerateHooks(Util::SearchMemory(utf8Text, strlen(utf8Text), PAGE_READWRITE), CODEC_UTF8);
if(codepage!=CP_UTF8)
if (codepage != CP_UTF8)
GenerateHooks(Util::SearchMemory(codepageText, strlen(codepageText), PAGE_READWRITE), USING_STRING);
GenerateHooks(Util::SearchMemory(text, wcslen(text) * sizeof(wchar_t), PAGE_READWRITE), CODEC_UTF16);
if (!found) ConsoleOutput(COULD_NOT_FIND);
if (!found)
ConsoleOutput(COULD_NOT_FIND);
}

View File

@ -1,4 +1,4 @@
#pragma once
void SearchForText(wchar_t* text, UINT codepage);
void SearchForText(wchar_t *text, UINT codepage);
void SearchForHooks(SearchParam sp);

View File

@ -9,8 +9,8 @@ namespace
{
AutoHandle<> hookPipe = INVALID_HANDLE_VALUE,
mappedFile = INVALID_HANDLE_VALUE,
mappedFile3=INVALID_HANDLE_VALUE;
TextHook(*hooks)[MAX_HOOK];
mappedFile3 = INVALID_HANDLE_VALUE;
TextHook (*hooks)[MAX_HOOK];
int currentHook = 0;
}
DWORD WINAPI Pipe(LPVOID)
@ -25,40 +25,42 @@ DWORD WINAPI Pipe(LPVOID)
{
// WinMutex connectionMutex(CONNECTING_MUTEX, &allAccess);
// std::scoped_lock lock(connectionMutex);
WaitForSingleObject(AutoHandle<>(CreateEventW(&allAccess, FALSE, FALSE, (std::wstring(PIPE_AVAILABLE_EVENT)+std::to_wstring(GetCurrentProcessId())).c_str())), INFINITE);
hostPipe = CreateFileW((std::wstring(HOST_PIPE)+std::to_wstring(GetCurrentProcessId())).c_str(), GENERIC_READ | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
hookPipe = CreateFileW((std::wstring(HOOK_PIPE)+std::to_wstring(GetCurrentProcessId())).c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
WaitForSingleObject(AutoHandle<>(CreateEventW(&allAccess, FALSE, FALSE, (std::wstring(PIPE_AVAILABLE_EVENT) + std::to_wstring(GetCurrentProcessId())).c_str())), INFINITE);
hostPipe = CreateFileW((std::wstring(HOST_PIPE) + std::to_wstring(GetCurrentProcessId())).c_str(), GENERIC_READ | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
hookPipe = CreateFileW((std::wstring(HOOK_PIPE) + std::to_wstring(GetCurrentProcessId())).c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
}
DWORD mode = PIPE_READMODE_MESSAGE;
SetNamedPipeHandleState(hostPipe, &mode, NULL, NULL);
*(DWORD*)buffer = GetCurrentProcessId();
*(DWORD *)buffer = GetCurrentProcessId();
WriteFile(hookPipe, buffer, sizeof(DWORD), &count, nullptr);
ConsoleOutput(PIPE_CONNECTED);
HIJACK();
host_connected=true;
host_connected = true;
while (running && ReadFile(hostPipe, buffer, PIPE_BUFFER_SIZE, &count, nullptr))
switch (*(HostCommandType*)buffer)
switch (*(HostCommandType *)buffer)
{
case HOST_COMMAND_NEW_HOOK:
{
auto info = *(InsertHookCmd*)buffer;
auto info = *(InsertHookCmd *)buffer;
static int userHooks = 0;
NewHook(info.hp, ("UserHook" + std::to_string(userHooks += 1)).c_str());
}
break;
case HOST_COMMAND_REMOVE_HOOK:
{
auto info = *(RemoveHookCmd*)buffer;
auto info = *(RemoveHookCmd *)buffer;
RemoveHook(info.address, 0);
}
break;
case HOST_COMMAND_FIND_HOOK:
{
auto info = *(FindHookCmd*)buffer;
if (*info.sp.text) SearchForText(info.sp.text, info.sp.codepage);
else SearchForHooks(info.sp);
auto info = *(FindHookCmd *)buffer;
if (*info.sp.text)
SearchForText(info.sp.text, info.sp.codepage);
else
SearchForHooks(info.sp);
}
break;
case HOST_COMMAND_DETACH:
@ -69,21 +71,25 @@ DWORD WINAPI Pipe(LPVOID)
}
}
if(dont_detach){
host_connected=false;
if (dont_detach)
{
host_connected = false;
return Pipe(0);
}else{
}
else
{
MH_Uninitialize();
for (auto& hook : *hooks) hook.Clear();
for (auto &hook : *hooks)
hook.Clear();
FreeLibraryAndExitThread(GetModuleHandleW(LUNA_HOOK_DLL), 0);
}
}
void TextOutput(const ThreadParam& tp, const HookParam& hp, TextOutput_T*buffer, int len)
void TextOutput(const ThreadParam &tp, const HookParam &hp, TextOutput_T *buffer, int len)
{
memcpy(&buffer->tp,&tp,sizeof(tp));
memcpy(&buffer->hp,&hp,sizeof(hp));
memcpy(&buffer->tp, &tp, sizeof(tp));
memcpy(&buffer->hp, &hp, sizeof(hp));
WriteFile(hookPipe, buffer, sizeof(TextOutput_T) + len, DUMMY, nullptr);
}
@ -96,22 +102,23 @@ void ConsoleOutput(LPCSTR text, ...)
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
void NotifyHookFound(HookParam hp,wchar_t*text)
void NotifyHookFound(HookParam hp, wchar_t *text)
{
wcscpy_s(hp.hookcode,HOOKCODE_LEN, HookCode::Generate(hp, GetCurrentProcessId()).c_str());
wcscpy_s(hp.hookcode, HOOKCODE_LEN, HookCode::Generate(hp, GetCurrentProcessId()).c_str());
HookFoundNotif buffer(hp, text);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
void NotifyHookRemove(uint64_t addr, LPCSTR name)
{
if (name) ConsoleOutput(REMOVING_HOOK, name);
if (name)
ConsoleOutput(REMOVING_HOOK, name);
HookRemovedNotif buffer(addr);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
void NotifyHookInserting(uint64_t addr,wchar_t hookcode[])
void NotifyHookInserting(uint64_t addr, wchar_t hookcode[])
{
HookInsertingNotif buffer(addr);
wcscpy(buffer.hookcode,hookcode);
wcscpy(buffer.hookcode, hookcode);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID)
@ -120,19 +127,21 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID)
{
case DLL_PROCESS_ATTACH:
{
hLUNAHOOKDLL=hModule;
hLUNAHOOKDLL = hModule;
viewMutex = WinMutex(ITH_HOOKMAN_MUTEX_ + std::to_wstring(GetCurrentProcessId()), &allAccess);
if (GetLastError() == ERROR_ALREADY_EXISTS) return FALSE;
if (GetLastError() == ERROR_ALREADY_EXISTS)
return FALSE;
DisableThreadLibraryCalls(hModule);
auto createfm=[](AutoHandle<> &handle,void**ptr,DWORD sz,std::wstring&name ){
handle=CreateFileMappingW(INVALID_HANDLE_VALUE, &allAccess, PAGE_EXECUTE_READWRITE, 0, sz, (name).c_str());
*ptr=MapViewOfFile(handle, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, sz);
auto createfm = [](AutoHandle<> &handle, void **ptr, DWORD sz, std::wstring &name)
{
handle = CreateFileMappingW(INVALID_HANDLE_VALUE, &allAccess, PAGE_EXECUTE_READWRITE, 0, sz, (name).c_str());
*ptr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, sz);
memset(*ptr, 0, sz);
};
hooks=(decltype(hooks))new TextHook[MAX_HOOK];
VirtualProtect((LPVOID)hooks,sizeof(TextHook) *MAX_HOOK,PAGE_EXECUTE_READWRITE,DUMMY);
createfm(mappedFile3,(void**)&embedsharedmem, sizeof(EmbedSharedMem),EMBED_SHARED_MEM + std::to_wstring(GetCurrentProcessId()));
hooks = (decltype(hooks))new TextHook[MAX_HOOK];
VirtualProtect((LPVOID)hooks, sizeof(TextHook) * MAX_HOOK, PAGE_EXECUTE_READWRITE, DUMMY);
createfm(mappedFile3, (void **)&embedsharedmem, sizeof(EmbedSharedMem), EMBED_SHARED_MEM + std::to_wstring(GetCurrentProcessId()));
MH_Initialize();
@ -142,183 +151,199 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID)
case DLL_PROCESS_DETACH:
{
MH_Uninitialize();
detachall( );
delete []hooks;
detachall();
delete[] hooks;
UnmapViewOfFile(embedsharedmem);
}
break;
}
return TRUE;
}
int HookStrLen(HookParam* hp,BYTE* data){
if(data==0)return 0;
int HookStrLen(HookParam *hp, BYTE *data)
{
if (data == 0)
return 0;
if(hp->type&CODEC_UTF16)
return wcsnlen((wchar_t*)data,TEXT_BUFFER_SIZE)*2;
else if(hp->type&CODEC_UTF32)
return u32strlen((uint32_t*)data)*4;
if (hp->type & CODEC_UTF16)
return wcsnlen((wchar_t *)data, TEXT_BUFFER_SIZE) * 2;
else if (hp->type & CODEC_UTF32)
return u32strlen((uint32_t *)data) * 4;
else
return strnlen((char*)data,TEXT_BUFFER_SIZE);
return strnlen((char *)data, TEXT_BUFFER_SIZE);
}
static std::mutex maplock;
void jitaddraddr(uintptr_t em_addr,uintptr_t jitaddr,JITTYPE jittype){
std::lock_guard _(maplock);
emuaddr2jitaddr[em_addr]={jittype,jitaddr};
jitaddr2emuaddr[jitaddr]={jittype,em_addr};
}
bool NewHook_1(HookParam& hp, LPCSTR lpname)
void jitaddraddr(uintptr_t em_addr, uintptr_t jitaddr, JITTYPE jittype)
{
if(hp.emu_addr)
ConsoleOutput("%p => %p",hp.emu_addr,hp.address);
std::lock_guard _(maplock);
emuaddr2jitaddr[em_addr] = {jittype, 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){
if (++currentHook >= MAX_HOOK)
{
ConsoleOutput(TOO_MANY_HOOKS);
return false;
}
if (lpname && *lpname) strncpy_s(hp.name, lpname, HOOK_NAME_SIZE - 1);
if (lpname && *lpname)
strncpy_s(hp.name, lpname, HOOK_NAME_SIZE - 1);
wcscpy_s(hp.hookcode,HOOKCODE_LEN,HookCode::Generate(hp, GetCurrentProcessId()).c_str());
wcscpy_s(hp.hookcode, HOOKCODE_LEN, HookCode::Generate(hp, GetCurrentProcessId()).c_str());
if (!(*hooks)[currentHook].Insert(hp))
{
ConsoleOutput(InsertHookFailed,WideStringToString(hp.hookcode).c_str());
ConsoleOutput(InsertHookFailed, WideStringToString(hp.hookcode).c_str());
(*hooks)[currentHook].Clear();
return false;
}
else{
NotifyHookInserting(hp.address,hp.hookcode);
else
{
NotifyHookInserting(hp.address, hp.hookcode);
return true;
}
}
static std::mutex delayinsertlock;
void delayinsertadd(HookParam hp,std::string name){
void delayinsertadd(HookParam hp, std::string name)
{
std::lock_guard _(maplock);
delayinserthook[hp.emu_addr]={name,hp};
ConsoleOutput(INSERTING_HOOK, name.c_str(),hp.emu_addr);
delayinserthook[hp.emu_addr] = {name, hp};
ConsoleOutput(INSERTING_HOOK, name.c_str(), hp.emu_addr);
}
void delayinsertNewHook(uintptr_t em_address){
if(delayinserthook.find(em_address)==delayinserthook.end())return;
void delayinsertNewHook(uintptr_t em_address)
{
if (delayinserthook.find(em_address) == delayinserthook.end())
return;
std::lock_guard _(maplock);
auto h=delayinserthook[em_address];
auto h = delayinserthook[em_address];
delayinserthook.erase(em_address);
NewHook(h.second,h.first.c_str());
NewHook(h.second, h.first.c_str());
}
bool NewHook(HookParam hp, LPCSTR name){
if(hp.address||hp.jittype==JITTYPE::PC)
return NewHook_1(hp,name);
if(hp.jittype==JITTYPE::UNITY){
auto spls=strSplit(hp.unityfunctioninfo,":");
if(spls.size()!=5){
bool NewHook(HookParam hp, LPCSTR name)
{
if (hp.address || hp.jittype == JITTYPE::PC)
return NewHook_1(hp, name);
if (hp.jittype == JITTYPE::UNITY)
{
auto spls = strSplit(hp.unityfunctioninfo, ":");
if (spls.size() != 5)
{
ConsoleOutput("invalid");
return false;
}
hp.address = tryfindmonoil2cpp(spls[0].c_str(),spls[1].c_str() ,spls[2].c_str(),spls[3].c_str(),std::stoi(spls[4]));
hp.address = tryfindmonoil2cpp(spls[0].c_str(), spls[1].c_str(), spls[2].c_str(), spls[3].c_str(), std::stoi(spls[4]));
if(!hp.address){
if (!hp.address)
{
ConsoleOutput("not find");
return false;
}
return NewHook_1(hp,name);
return NewHook_1(hp, name);
}
//下面的是手动插入
if(emuaddr2jitaddr.find(hp.emu_addr)==emuaddr2jitaddr.end()){
delayinsertadd(hp,name);
// 下面的是手动插入
if (emuaddr2jitaddr.find(hp.emu_addr) == emuaddr2jitaddr.end())
{
delayinsertadd(hp, name);
return true;
}
strcpy(hp.function,"");
wcscpy(hp.module,L"");
strcpy(hp.function, "");
wcscpy(hp.module, L"");
hp.type &= ~MODULE_OFFSET;
hp.address=emuaddr2jitaddr[hp.emu_addr].second;
hp.jittype=emuaddr2jitaddr[hp.emu_addr].first;
return NewHook_1(hp,name);
hp.address = emuaddr2jitaddr[hp.emu_addr].second;
hp.jittype = emuaddr2jitaddr[hp.emu_addr].first;
return NewHook_1(hp, name);
}
void RemoveHook(uint64_t addr, int maxOffset)
{
for (auto& hook : *hooks) if (abs((long long)(hook.address - addr)) <= maxOffset) return hook.Clear();
for (auto &hook : *hooks)
if (abs((long long)(hook.address - addr)) <= maxOffset)
return hook.Clear();
}
std::string LoadResData(LPCWSTR pszResID,LPCWSTR _type)
std::string LoadResData(LPCWSTR pszResID, LPCWSTR _type)
{
HMODULE hModule=hLUNAHOOKDLL;
HRSRC hRsrc = ::FindResourceW (hModule, pszResID,_type);
HMODULE hModule = hLUNAHOOKDLL;
HRSRC hRsrc = ::FindResourceW(hModule, pszResID, _type);
if (!hRsrc)
return "";
DWORD len = SizeofResource(hModule, hRsrc);
BYTE* lpRsrc = (BYTE*)LoadResource(hModule, hRsrc);
BYTE *lpRsrc = (BYTE *)LoadResource(hModule, hRsrc);
if (!lpRsrc)
return "";
HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
BYTE* pmem = (BYTE*)GlobalLock(m_hMem);
memcpy(pmem,lpRsrc,len);
auto data=std::string((char*)pmem,len);
BYTE *pmem = (BYTE *)GlobalLock(m_hMem);
memcpy(pmem, lpRsrc, len);
auto data = std::string((char *)pmem, len);
GlobalUnlock(m_hMem);
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_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
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

@ -4,31 +4,29 @@
// 8/23/2013 jichi
// Branch: ITH/IHF_DLL.h, rev 66
void TextOutput(const ThreadParam& tp, const HookParam& hp,TextOutput_T (*buffer), int len);
void TextOutput(const ThreadParam &tp, const HookParam &hp, TextOutput_T(*buffer), int len);
void ConsoleOutput(LPCSTR text, ...);
void NotifyHookFound(HookParam hp, wchar_t* 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);
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,uintptr_t>>emuaddr2jitaddr;
inline std::unordered_map<uintptr_t,std::pair<JITTYPE,uintptr_t>>jitaddr2emuaddr;
void jitaddraddr(uintptr_t em_addr,uintptr_t jitaddr,JITTYPE);
int HookStrLen(HookParam *, BYTE *data);
inline std::unordered_map<uintptr_t, std::pair<JITTYPE, uintptr_t>> emuaddr2jitaddr;
inline std::unordered_map<uintptr_t, std::pair<JITTYPE, uintptr_t>> jitaddr2emuaddr;
void jitaddraddr(uintptr_t em_addr, uintptr_t jitaddr, JITTYPE);
void context_get(hook_stack*,PCONTEXT);
void context_set(hook_stack*,PCONTEXT);
void context_get(hook_stack *, PCONTEXT);
void context_set(hook_stack *, PCONTEXT);
inline std::map<uintptr_t,std::pair<std::string,HookParam>>delayinserthook;
void delayinsertadd(HookParam,std::string);
inline std::map<uintptr_t, std::pair<std::string, HookParam>> delayinserthook;
void delayinsertadd(HookParam, std::string);
void delayinsertNewHook(uintptr_t);
inline bool dont_detach=false;
inline bool host_connected=false;
inline bool dont_detach = false;
inline bool host_connected = false;

View File

@ -1,31 +1,33 @@
#include"../include/pch.h"
#include "../include/pch.h"
enum { TEXT_BUFFER_SIZE = PIPE_BUFFER_SIZE - sizeof(TextOutput_T) };
enum
{
TEXT_BUFFER_SIZE = PIPE_BUFFER_SIZE - sizeof(TextOutput_T)
};
//#define wcslen(XX) wcsnlen((XX), TEXT_BUFFER_SIZE*2)
//#define strlen(XX) strnlen((XX), TEXT_BUFFER_SIZE*2)
// #define wcslen(XX) wcsnlen((XX), TEXT_BUFFER_SIZE*2)
// #define strlen(XX) strnlen((XX), TEXT_BUFFER_SIZE*2)
#include"main.h"
#include"stackoffset.hpp"
#include"util/stringfilters.h"
#include"memdbg/memsearch.h"
#include "main.h"
#include "stackoffset.hpp"
#include "util/stringfilters.h"
#include "memdbg/memsearch.h"
#include "util/util.h"
#include "ithsys/ithsys.h"
#include"pchooks/pchooks.h"
#include "pchooks/pchooks.h"
#include "cpputil/cppcstring.h"
#include"dyncodec/dynsjiscodec.h"
#include"dyncodec/dynsjis.h"
#include "dyncodec/dynsjiscodec.h"
#include "dyncodec/dynsjis.h"
#include "disasm/disasm.h"
#include"engine.h"
#include"embed_util.h"
#include"detours.h"
#include"hijackfuns.h"
#include "engine.h"
#include "embed_util.h"
#include "detours.h"
#include "hijackfuns.h"
#include"Lang/Lang.h"
#include"veh_hook.h"
#include"engines/emujitarg.hpp"
#include"engines/mono/monoil2cpp.h"
#include "Lang/Lang.h"
#include "veh_hook.h"
#include "engines/emujitarg.hpp"
#include "engines/mono/monoil2cpp.h"
#include "hookfinder.h"
#include"util/textunion.h"
#include"util/ntxpundef.h"
#include "util/textunion.h"
#include "util/ntxpundef.h"

View File

@ -33,52 +33,78 @@ enum class regs
invalid
};
inline int get_stack(int s){
#ifdef _WIN64
return s*8;
#else
return s*4;
#endif
inline int get_stack(int s)
{
#ifdef _WIN64
return s * 8;
#else
return s * 4;
#endif
}
inline int get_reg(regs reg){
#ifdef _WIN64
return -8*(int)reg-8;
#else
return -4-(int)reg*4;
#endif
inline int get_reg(regs reg)
{
#ifdef _WIN64
return -8 * (int)reg - 8;
#else
return -4 - (int)reg * 4;
#endif
}
inline uintptr_t regof(regs reg,hook_stack* stack){
inline uintptr_t regof(regs reg, hook_stack *stack)
{
switch (reg)
{
#ifndef _WIN64
case regs::eax:return stack->eax;
case regs::ecx:return stack->ecx;
case regs::edx:return stack->edx;
case regs::ebx:return stack->ebx;
case regs::esp:return stack->esp;
case regs::ebp:return stack->ebp;
case regs::esi:return stack->esi;
case regs::edi:return stack->edi;
#else
case regs::rax:return stack->rax;
case regs::rbx:return stack->rbx;
case regs::rcx:return stack->rcx;
case regs::rdx:return stack->rdx;
case regs::rsp:return stack->rsp;
case regs::rbp:return stack->rbp;
case regs::rsi:return stack->rsi;
case regs::rdi:return stack->rdi;
case regs::r8:return stack->r8;
case regs::r9:return stack->r9;
case regs::r10:return stack->r10;
case regs::r11:return stack->r11;
case regs::r12:return stack->r12;
case regs::r13:return stack->r13;
case regs::r14:return stack->r14;
case regs::r15:return stack->r15;
#endif
#ifndef _WIN64
case regs::eax:
return stack->eax;
case regs::ecx:
return stack->ecx;
case regs::edx:
return stack->edx;
case regs::ebx:
return stack->ebx;
case regs::esp:
return stack->esp;
case regs::ebp:
return stack->ebp;
case regs::esi:
return stack->esi;
case regs::edi:
return stack->edi;
#else
case regs::rax:
return stack->rax;
case regs::rbx:
return stack->rbx;
case regs::rcx:
return stack->rcx;
case regs::rdx:
return stack->rdx;
case regs::rsp:
return stack->rsp;
case regs::rbp:
return stack->rbp;
case regs::rsi:
return stack->rsi;
case regs::rdi:
return stack->rdi;
case regs::r8:
return stack->r8;
case regs::r9:
return stack->r9;
case regs::r10:
return stack->r10;
case regs::r11:
return stack->r11;
case regs::r12:
return stack->r12;
case regs::r13:
return stack->r13;
case regs::r14:
return stack->r14;
case regs::r15:
return stack->r15;
#endif
}
return 0;
}
@ -110,20 +136,29 @@ inline uintptr_t regof(regs reg,hook_stack* stack){
#endif
inline uintptr_t *argidx(hook_stack* stack,int idx){
#ifdef _WIN64
auto offset=0;
inline uintptr_t *argidx(hook_stack *stack, int idx)
{
#ifdef _WIN64
auto offset = 0;
switch (idx)
{
case 1:offset=get_reg(regs::rcx);break;
case 2:offset=get_reg(regs::rdx);break;
case 3:offset=get_reg(regs::r8);break;
case 4:offset=get_reg(regs::r9);break;
default:offset=get_stack(idx);
case 1:
offset = get_reg(regs::rcx);
break;
case 2:
offset = get_reg(regs::rdx);
break;
case 3:
offset = get_reg(regs::r8);
break;
case 4:
offset = get_reg(regs::r9);
break;
default:
offset = get_stack(idx);
}
return (uintptr_t*)((uintptr_t)stack+sizeof(hook_stack)-sizeof(uintptr_t)+offset);
#else
return (uintptr_t*)((uintptr_t)stack+sizeof(hook_stack)-sizeof(uintptr_t)+get_stack(idx));
#endif
return (uintptr_t *)((uintptr_t)stack + sizeof(hook_stack) - sizeof(uintptr_t) + offset);
#else
return (uintptr_t *)((uintptr_t)stack + sizeof(hook_stack) - sizeof(uintptr_t) + get_stack(idx));
#endif
}

View File

@ -4,7 +4,8 @@ extern WinMutex viewMutex;
// - Unnamed helpers -
namespace { // unnamed
namespace
{ // unnamed
#ifndef _WIN64
BYTE common_hook[] = {
0x9c, // pushfd
@ -12,13 +13,13 @@ namespace { // unnamed
0x9c, // pushfd ; Artikash 11/4/2018: not sure why pushfd happens twice. Anyway, after this a total of 0x28 bytes are pushed
0x8d, 0x44, 0x24, 0x28, // lea eax,[esp+0x28]
0x50, // push eax ; lpDatabase
0xb9, 0,0,0,0, // mov ecx,@this
0xbb, 0,0,0,0, // mov ebx,@TextHook::Send
0xb9, 0, 0, 0, 0, // mov ecx,@this
0xbb, 0, 0, 0, 0, // mov ebx,@TextHook::Send
0xff, 0xd3, // call ebx
0x9d, // popfd
0x61, // popad
0x9d, // popfd
0x68, 0,0,0,0, // push @original
0x68, 0, 0, 0, 0, // push @original
0xc3 // ret ; basically absolute jmp to @original
};
int this_offset = 9, send_offset = 14, original_offset = 24;
@ -47,8 +48,8 @@ namespace { // unnamed
0xf3, 0x0f, 0x7f, 0x24, 0x24, // movdqu [rsp],xmm4
0xf3, 0x0f, 0x7f, 0x6c, 0x24, 0x10, // movdqu [rsp+0x10],xmm5
0x48, 0x8d, 0x94, 0x24, 0xa8, 0x00, 0x00, 0x00, // lea rdx,[rsp+0xa8]
0x48, 0xb9, 0,0,0,0,0,0,0,0, // mov rcx,@this
0x48, 0xb8, 0,0,0,0,0,0,0,0, // mov rax,@TextHook::Send
0x48, 0xb9, 0, 0, 0, 0, 0, 0, 0, 0, // mov rcx,@this
0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, // mov rax,@TextHook::Send
0x48, 0x89, 0xe3, // mov rbx,rsp
0x48, 0x83, 0xe4, 0xf0, // and rsp,0xfffffffffffffff0 ; align stack
0xff, 0xd0, // call rax
@ -74,30 +75,35 @@ namespace { // unnamed
0x58, // pop rax
0x9d, // pop rflags
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip]
0,0,0,0,0,0,0,0 // @original
0, 0, 0, 0, 0, 0, 0, 0 // @original
};
int this_offset = 50, send_offset = 60, original_offset = 126;
#endif
//thread_local BYTE buffer[PIPE_BUFFER_SIZE];
//thread_local will crush on windowsxp
// thread_local BYTE buffer[PIPE_BUFFER_SIZE];
// thread_local will crush on windowsxp
} // unnamed namespace
// - TextHook methods -
uintptr_t getasbaddr(const HookParam &hp){
auto address=hp.address;
uintptr_t getasbaddr(const HookParam &hp)
{
auto address = hp.address;
if (hp.type & MODULE_OFFSET)
{
if (hp.type & FUNCTION_OFFSET)
{
if (FARPROC function = GetProcAddress(GetModuleHandleW(hp.module), hp.function)) address += (uint64_t)function;
else return ConsoleOutput(FUNC_MISSING), 0;
if (FARPROC function = GetProcAddress(GetModuleHandleW(hp.module), hp.function))
address += (uint64_t)function;
else
return ConsoleOutput(FUNC_MISSING), 0;
}
else
{
if (HMODULE moduleBase = GetModuleHandleW(hp.module)) address += (uint64_t)moduleBase;
else return ConsoleOutput(MODULE_MISSING), 0;
if (HMODULE moduleBase = GetModuleHandleW(hp.module))
address += (uint64_t)moduleBase;
else
return ConsoleOutput(MODULE_MISSING), 0;
}
}
return address;
@ -105,261 +111,303 @@ uintptr_t getasbaddr(const HookParam &hp){
bool TextHook::Insert(HookParam hp)
{
auto addr=getasbaddr(hp);
if(!addr)return false;
auto addr = getasbaddr(hp);
if (!addr)
return false;
RemoveHook(addr, 0);
ConsoleOutput(INSERTING_HOOK, hp.name,addr);
local_buffer=new BYTE[PIPE_BUFFER_SIZE];
ConsoleOutput(INSERTING_HOOK, hp.name, addr);
local_buffer = new BYTE[PIPE_BUFFER_SIZE];
{
std::scoped_lock lock(viewMutex);
this->hp = hp;
address = addr;
}
savetypeforremove=hp.type;
if (hp.type & DIRECT_READ) return InsertReadCode();
if (hp.type & BREAK_POINT) return InsertBreakPoint();
savetypeforremove = hp.type;
if (hp.type & DIRECT_READ)
return InsertReadCode();
if (hp.type & BREAK_POINT)
return InsertBreakPoint();
return InsertHookCode();
}
uintptr_t win64find0000(uintptr_t addr){
uintptr_t win64find0000(uintptr_t addr)
{
uintptr_t r = 0;
__try{
__try
{
addr &= ~0xf;
for (uintptr_t i = addr, j = addr - 0x10000; i > j; i-=0x10) {
DWORD k = *(DWORD *)(i-4);
if (k == 0x00000000
)
for (uintptr_t i = addr, j = addr - 0x10000; i > j; i -= 0x10)
{
DWORD k = *(DWORD *)(i - 4);
if (k == 0x00000000)
return i;
}
return 0;
}__except(EXCEPTION_EXECUTE_HANDLER) {}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
return r;
}
Synchronized<std::unordered_map<uintptr_t, uintptr_t>> retaddr2relative;//很奇怪这个放到函数里用static在xp上会报错。
uintptr_t queryrelativeret(HookParam&hp, uintptr_t retaddr){
//不需要区分是相对于哪个module的偏移只需要得到偏移就可以了用来确保重启程序后ret值恒定
auto &re=retaddr2relative.Acquire().contents;
if(re.find(retaddr)!=re.end())return re.at(retaddr);
uintptr_t relative=retaddr;
if(hp.jittype==JITTYPE::UNITY){
#ifndef _WIN64
relative=retaddr-SafeFindEnclosingAlignedFunction(retaddr,0x10000);
#else
relative=retaddr-win64find0000(retaddr);
#endif
Synchronized<std::unordered_map<uintptr_t, uintptr_t>> retaddr2relative; // 很奇怪这个放到函数里用static在xp上会报错。
uintptr_t queryrelativeret(HookParam &hp, uintptr_t retaddr)
{
// 不需要区分是相对于哪个module的偏移只需要得到偏移就可以了用来确保重启程序后ret值恒定
auto &re = retaddr2relative.Acquire().contents;
if (re.find(retaddr) != re.end())
return re.at(retaddr);
uintptr_t relative = retaddr;
if (hp.jittype == JITTYPE::UNITY)
{
#ifndef _WIN64
relative = retaddr - SafeFindEnclosingAlignedFunction(retaddr, 0x10000);
#else
relative = retaddr - win64find0000(retaddr);
#endif
}
else{
else
{
if (MEMORY_BASIC_INFORMATION info = {}; VirtualQuery((LPCVOID)retaddr, &info, sizeof(info)))
relative-=(uintptr_t)info.AllocationBase;
relative -= (uintptr_t)info.AllocationBase;
}
re.insert(std::make_pair(retaddr,relative));
re.insert(std::make_pair(retaddr, relative));
return relative;
}
uintptr_t jitgetaddr(hook_stack* stack, HookParam* hp){
uintptr_t jitgetaddr(hook_stack *stack, HookParam *hp)
{
switch (hp->jittype)
{
#ifdef _WIN64
#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:
return YUZU::emu_arg(stack)[hp->argidx];
#endif
#endif
case JITTYPE::PPSSPP:
return PPSSPP::emu_arg(stack)[hp->argidx];
default:
return 0;
}
}
bool checklengthembedable(const HookParam&hp,size_t size){
bool checklengthembedable(const HookParam &hp, size_t size)
{
size_t len;
if (hp.type & CODEC_UTF16)
len = 2;
else if(hp.type&CODEC_UTF32)
else if (hp.type & CODEC_UTF32)
len = 4;
else
{
len = 1;
}
return size>len;
return size > len;
}
bool commonfilter(void* data, size_t* len, HookParam* hp){
bool commonfilter(void *data, size_t *len, HookParam *hp)
{
if(hp->type & CODEC_UTF16);
else if(hp->type & CODEC_UTF32);
else if(hp->type & CODEC_UTF8);
else{
if(*len==2){
StringFilter((char*)data,len,"\x81\xa4",2);
StringFilter((char*)data,len,"\x81\xa5",2);
if (hp->type & CODEC_UTF16)
;
else if (hp->type & CODEC_UTF32)
;
else if (hp->type & CODEC_UTF8)
;
else
{
if (*len == 2)
{
StringFilter((char *)data, len, "\x81\xa4", 2);
StringFilter((char *)data, len, "\x81\xa5", 2);
}
}
return true;
}
void TextHook::Send(uintptr_t lpDataBase)
{
auto buffer =(TextOutput_T*) local_buffer;
auto buffer = (TextOutput_T *)local_buffer;
auto pbData = buffer->data;
_InterlockedIncrement((long*)&useCount);
_InterlockedIncrement((long *)&useCount);
__try
{
auto stack=get_hook_stack(lpDataBase);
auto stack = get_hook_stack(lpDataBase);
if (auto current_trigger_fun = trigger_fun.exchange(nullptr))
if (!current_trigger_fun(location, stack)) trigger_fun = current_trigger_fun;
if (!current_trigger_fun(location, stack))
trigger_fun = current_trigger_fun;
if(hp.type&HOOK_RETURN){
hp.type&=~HOOK_RETURN;
hp.address=stack->retaddr;
strcat(hp.name,"_Return");
//清除jit hook特征防止手动插入
strcpy(hp.unityfunctioninfo,"");
hp.emu_addr=0;
//清除module
if (hp.type & HOOK_RETURN)
{
hp.type &= ~HOOK_RETURN;
hp.address = stack->retaddr;
strcat(hp.name, "_Return");
// 清除jit hook特征防止手动插入
strcpy(hp.unityfunctioninfo, "");
hp.emu_addr = 0;
// 清除module
hp.type &= ~MODULE_OFFSET;
hp.type &= ~FUNCTION_OFFSET;
strcpy(hp.function,"");
wcscpy(hp.module,L"");
strcpy(hp.function, "");
wcscpy(hp.module, L"");
NewHook(hp,hp.name);
hp.type|=HOOK_EMPTY;
NewHook(hp, hp.name);
hp.type |= HOOK_EMPTY;
__leave;
}
if (hp.type & HOOK_EMPTY) __leave; // jichi 10/24/2014: dummy hook only for dynamic hook
if (hp.type & HOOK_EMPTY)
__leave; // jichi 10/24/2014: dummy hook only for dynamic hook
size_t lpCount = 0;
uintptr_t lpSplit = 0,
lpRetn = stack->retaddr,
plpdatain=(lpDataBase + hp.offset),
lpDataIn=*(uintptr_t*)plpdatain;
bool isstring=false;
if(hp.jittype!=JITTYPE::PC&&hp.jittype!=JITTYPE::UNITY)
plpdatain = (lpDataBase + hp.offset),
lpDataIn = *(uintptr_t *)plpdatain;
bool isstring = false;
if (hp.jittype != JITTYPE::PC && hp.jittype != JITTYPE::UNITY)
{
lpDataIn=jitgetaddr(stack,&hp);
plpdatain=(uintptr_t)&lpDataIn;
lpDataIn = jitgetaddr(stack, &hp);
plpdatain = (uintptr_t)&lpDataIn;
}
else if(hp.jittype==JITTYPE::UNITY){
plpdatain=(uintptr_t)argidx(stack,hp.argidx);
lpDataIn=*(uintptr_t*)plpdatain;
else if (hp.jittype == JITTYPE::UNITY)
{
plpdatain = (uintptr_t)argidx(stack, hp.argidx);
lpDataIn = *(uintptr_t *)plpdatain;
}
auto use_custom_embed_fun=(hp.type&EMBED_ABLE)&&!(hp.type&EMBED_BEFORE_SIMPLE);
if(use_custom_embed_fun)
auto use_custom_embed_fun = (hp.type & EMBED_ABLE) && !(hp.type & EMBED_BEFORE_SIMPLE);
if (use_custom_embed_fun)
{
isstring=true;
lpSplit=Engine::ScenarioRole;lpRetn=0;
if(hp.hook_before(stack,pbData,&lpCount,&lpSplit)==false)__leave;
isstring = true;
lpSplit = Engine::ScenarioRole;
lpRetn = 0;
if (hp.hook_before(stack, pbData, &lpCount, &lpSplit) == false)
__leave;
}
else if (hp.text_fun)
{
isstring=true;
isstring = true;
hp.text_fun(stack, &hp, &lpDataIn, &lpSplit, &lpCount);
}
else if(hp.type&SPECIAL_JIT_STRING)
else if (hp.type & SPECIAL_JIT_STRING)
{
if(hp.jittype==JITTYPE::UNITY)
commonsolvemonostring(lpDataIn,&lpDataIn,&lpCount);
if (hp.jittype == JITTYPE::UNITY)
commonsolvemonostring(lpDataIn, &lpDataIn, &lpCount);
}
else
{
if (hp.type & FIXING_SPLIT) lpSplit = FIXED_SPLIT_VALUE; // fuse all threads, and prevent floating
else if (hp.type & USING_SPLIT) {
if (hp.type & FIXING_SPLIT)
lpSplit = FIXED_SPLIT_VALUE; // fuse all threads, and prevent floating
else if (hp.type & USING_SPLIT)
{
lpSplit = *(uintptr_t *)(lpDataBase + hp.split);
if (hp.type & SPLIT_INDIRECT) lpSplit = *(uintptr_t *)(lpSplit + hp.split_index);
if (hp.type & SPLIT_INDIRECT)
lpSplit = *(uintptr_t *)(lpSplit + hp.split_index);
}
if (hp.type & DATA_INDIRECT) {
plpdatain=(lpDataIn + hp.index);
if (hp.type & DATA_INDIRECT)
{
plpdatain = (lpDataIn + hp.index);
lpDataIn = *(uintptr_t *)plpdatain;
}
lpDataIn += hp.padding;
lpCount = GetLength(stack, lpDataIn);
}
if (lpCount <= 0) __leave;
if (lpCount <= 0)
__leave;
if (lpCount > TEXT_BUFFER_SIZE)
{
ConsoleOutput(InvalidLength, lpCount, hp.name);
lpCount = TEXT_BUFFER_SIZE;
}
if(!use_custom_embed_fun)
if (!use_custom_embed_fun)
{
if ((!(hp.type&USING_CHAR))&&(isstring||(hp.type&USING_STRING)))
if ((!(hp.type & USING_CHAR)) && (isstring || (hp.type & USING_STRING)))
{
if(lpDataIn == 0)__leave;
::memcpy(pbData, (void*)lpDataIn, lpCount);
if (lpDataIn == 0)
__leave;
::memcpy(pbData, (void *)lpDataIn, lpCount);
}
else
{
if(hp.type &CODEC_UTF32)
if (hp.type & CODEC_UTF32)
{
*(uint32_t*)pbData=lpDataIn&0xffffffff;
*(uint32_t *)pbData = lpDataIn & 0xffffffff;
}
else
{//CHAR_LITTEL_ENDIAN,CODEC_ANSI_BE,CODEC_UTF16
{ // CHAR_LITTEL_ENDIAN,CODEC_ANSI_BE,CODEC_UTF16
lpDataIn &= 0xffff;
if ((hp.type & CODEC_ANSI_BE) && (lpDataIn >> 8)) lpDataIn = _byteswap_ushort(lpDataIn & 0xffff);
if (lpCount == 1) lpDataIn &= 0xff;
*(WORD*)pbData = lpDataIn & 0xffff;
if ((hp.type & CODEC_ANSI_BE) && (lpDataIn >> 8))
lpDataIn = _byteswap_ushort(lpDataIn & 0xffff);
if (lpCount == 1)
lpDataIn &= 0xff;
*(WORD *)pbData = lpDataIn & 0xffff;
}
}
}
if(!commonfilter(pbData, &lpCount, &hp) ||lpCount <= 0) __leave;
if (hp.filter_fun && !hp.filter_fun(pbData, &lpCount, &hp) || lpCount <= 0) __leave;
if (!commonfilter(pbData, &lpCount, &hp) || lpCount <= 0)
__leave;
if (hp.filter_fun && !hp.filter_fun(pbData, &lpCount, &hp) || lpCount <= 0)
__leave;
if (hp.type & (NO_CONTEXT | FIXING_SPLIT)) lpRetn = 0;
if (hp.type & (NO_CONTEXT | FIXING_SPLIT))
lpRetn = 0;
buffer->type=hp.type;
buffer->type = hp.type;
lpRetn=queryrelativeret(hp,lpRetn);
ThreadParam tp{ GetCurrentProcessId(), address, lpRetn, lpSplit };
lpRetn = queryrelativeret(hp, lpRetn);
ThreadParam tp{GetCurrentProcessId(), address, lpRetn, lpSplit};
parsenewlineseperator(pbData, &lpCount);
bool canembed;;
if(hp.type&EMBED_ABLE){
if(!checklengthembedable(hp,lpCount)){
buffer->type&=(~EMBED_ABLE);
canembed=false;
bool canembed;
;
if (hp.type & EMBED_ABLE)
{
if (!checklengthembedable(hp, lpCount))
{
buffer->type &= (~EMBED_ABLE);
canembed = false;
}
else if(checktranslatedok(pbData,lpCount)){
buffer->type&=(~EMBED_ABLE);
canembed=true;
else if (checktranslatedok(pbData, lpCount))
{
buffer->type &= (~EMBED_ABLE);
canembed = true;
}
else{
canembed=true;
else
{
canembed = true;
}
}
TextOutput(tp, hp,buffer, lpCount);
TextOutput(tp, hp, buffer, lpCount);
if(canembed&&(check_embed_able(tp)))
if (canembed && (check_embed_able(tp)))
{
auto lpCountsave=lpCount;
if(waitfornotify(buffer,pbData,&lpCount,tp))
auto lpCountsave = lpCount;
if (waitfornotify(buffer, pbData, &lpCount, tp))
{
if(hp.type&EMBED_AFTER_NEW)
if (hp.type & EMBED_AFTER_NEW)
{
auto _ = new char[max(lpCountsave,lpCount)+10];
memcpy(_,pbData,lpCount);
for(int i=lpCount;i<max(lpCountsave,lpCount)+10;i++)
_[i]=0;
*(uintptr_t*)plpdatain=(uintptr_t)_;
auto _ = new char[max(lpCountsave, lpCount) + 10];
memcpy(_, pbData, lpCount);
for (int i = lpCount; i < max(lpCountsave, lpCount) + 10; i++)
_[i] = 0;
*(uintptr_t *)plpdatain = (uintptr_t)_;
}
else if(hp.type&EMBED_AFTER_OVERWRITE)
else if (hp.type & EMBED_AFTER_OVERWRITE)
{
memcpy((void*)lpDataIn,pbData,lpCount);
for(int i=lpCount;i<lpCountsave;i++)
((BYTE*)(lpDataIn))[i]=0;
memcpy((void *)lpDataIn, pbData, lpCount);
for (int i = lpCount; i < lpCountsave; i++)
((BYTE *)(lpDataIn))[i] = 0;
}
else if(hp.hook_after)
hp.hook_after(stack,pbData,lpCount);
else if(hp.type&SPECIAL_JIT_STRING){
if(hp.jittype==JITTYPE::UNITY)
unity_ui_string_hook_after(argidx(stack,hp.argidx),pbData,lpCount);
else if (hp.hook_after)
hp.hook_after(stack, pbData, lpCount);
else if (hp.type & SPECIAL_JIT_STRING)
{
if (hp.jittype == JITTYPE::UNITY)
unity_ui_string_hook_after(argidx(stack, hp.argidx), pbData, lpCount);
}
}
}
@ -373,20 +421,21 @@ void TextHook::Send(uintptr_t lpDataBase)
}
}
_InterlockedDecrement((long*) & useCount);
_InterlockedDecrement((long *)&useCount);
}
bool TextHook::breakpointcontext(PCONTEXT context){
auto stack=std::make_unique<hook_stack>();
context_get(stack.get(),context);
auto lpDataBase=stack->get_base();
bool TextHook::breakpointcontext(PCONTEXT context)
{
auto stack = std::make_unique<hook_stack>();
context_get(stack.get(), context);
auto lpDataBase = stack->get_base();
Send(lpDataBase);
context_set(stack.get(),context);
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));
// MH_CreateHook 64位unity/yuzu-emu经常 MH_ERROR_MEMORY_ALLOC
return add_veh_hook(location, std::bind(&TextHook::breakpointcontext, this, std::placeholders::_1));
}
bool TextHook::RemoveBreakPoint()
{
@ -395,17 +444,18 @@ bool TextHook::RemoveBreakPoint()
bool TextHook::InsertHookCode()
{
VirtualProtect(location, 10, PAGE_EXECUTE_READWRITE, DUMMY);
void* original;
void *original;
MH_STATUS error;
while ((error = MH_CreateHook(location, trampoline, &original)) != MH_OK)
if (error == MH_ERROR_ALREADY_CREATED) RemoveHook(address);
else return ConsoleOutput(MH_StatusToString(error)), false;
if (error == MH_ERROR_ALREADY_CREATED)
RemoveHook(address);
else
return ConsoleOutput(MH_StatusToString(error)), false;
*(TextHook**)(common_hook + this_offset) = this;
*(TextHook **)(common_hook + this_offset) = this;
*(void(TextHook::**)(uintptr_t))(common_hook + send_offset) = &TextHook::Send;
*(void**)(common_hook + original_offset) = original;
*(void **)(common_hook + original_offset) = original;
memcpy(trampoline, common_hook, sizeof(common_hook));
return MH_EnableHook(location) == MH_OK;
}
@ -413,36 +463,37 @@ bool TextHook::InsertHookCode()
void TextHook::Read()
{
size_t dataLen = 1;
//BYTE(*buffer)[PIPE_BUFFER_SIZE] = &::buffer, *pbData = *buffer + sizeof(ThreadParam);
// BYTE(*buffer)[PIPE_BUFFER_SIZE] = &::buffer, *pbData = *buffer + sizeof(ThreadParam);
auto buffer =(TextOutput_T*) local_buffer;
auto buffer = (TextOutput_T *)local_buffer;
auto pbData = buffer->data;
buffer->type=hp.type;
buffer->type = hp.type;
__try
{
if(hp.text_fun)
if (hp.text_fun)
{
while (WaitForSingleObject(readerEvent, 500) == WAIT_TIMEOUT)
hp.text_fun(0,0,0,0,0);
hp.text_fun(0, 0, 0, 0, 0);
}
else
{
while (WaitForSingleObject(readerEvent, 500) == WAIT_TIMEOUT)
{
if(!location)continue;
int currentLen = HookStrlen((BYTE*)location);
bool changed=memcmp(pbData, location, dataLen) != 0;
if(changed ||(currentLen!=dataLen))
if (!location)
continue;
int currentLen = HookStrlen((BYTE *)location);
bool changed = memcmp(pbData, location, dataLen) != 0;
if (changed || (currentLen != dataLen))
{
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 },hp, buffer, dataLen);
if (hp.filter_fun && !hp.filter_fun(pbData, &dataLen, &hp) || dataLen <= 0)
continue;
TextOutput({GetCurrentProcessId(), address, 0, 0}, hp, buffer, dataLen);
memcpy(pbData, location, dataLen);
}
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
@ -453,7 +504,8 @@ void TextHook::Read()
bool TextHook::InsertReadCode()
{
readerThread = CreateThread(nullptr, 0, [](void* This) { ((TextHook*)This)->Read(); return 0UL; }, this, 0, nullptr);
readerThread = CreateThread(nullptr, 0, [](void *This)
{ ((TextHook*)This)->Read(); return 0UL; }, this, 0, nullptr);
readerEvent = CreateEventW(nullptr, FALSE, FALSE, NULL);
return true;
}
@ -461,69 +513,74 @@ bool TextHook::InsertReadCode()
void TextHook::RemoveHookCode()
{
MH_DisableHook(location);
while (useCount != 0);
while (useCount != 0)
;
MH_RemoveHook(location);
}
void TextHook::RemoveReadCode()
{
SetEvent(readerEvent);
if (GetThreadId(readerThread) != GetCurrentThreadId()) WaitForSingleObject(readerThread, 1000);
if (GetThreadId(readerThread) != GetCurrentThreadId())
WaitForSingleObject(readerThread, 1000);
CloseHandle(readerEvent);
CloseHandle(readerThread);
}
void TextHook::Clear()
{
if (address == 0) return;
if (savetypeforremove & DIRECT_READ) RemoveReadCode();
else if (savetypeforremove & BREAK_POINT) RemoveBreakPoint();
else RemoveHookCode();
if (address == 0)
return;
if (savetypeforremove & DIRECT_READ)
RemoveReadCode();
else if (savetypeforremove & BREAK_POINT)
RemoveBreakPoint();
else
RemoveHookCode();
NotifyHookRemove(address, hp.name);
std::scoped_lock lock(viewMutex);
memset(&hp, 0, sizeof(HookParam));
address = 0;
if(local_buffer)delete []local_buffer;
if (local_buffer)
delete[] local_buffer;
}
int TextHook::GetLength(hook_stack* stack, uintptr_t in)
int TextHook::GetLength(hook_stack *stack, uintptr_t in)
{
int len;
if(hp.type&USING_STRING)
if (hp.type & USING_STRING)
{
if(hp.length_offset)
if (hp.length_offset)
{
len = *((uintptr_t*)stack->base + hp.length_offset);
len = *((uintptr_t *)stack->base + hp.length_offset);
if (len >= 0)
{
if (hp.type & CODEC_UTF16)
len <<= 1;
else if(hp.type & CODEC_UTF32)
else if (hp.type & CODEC_UTF32)
len <<= 2;
}
else if (len != -1)
{
}
else
{//len==-1
len = HookStrlen((BYTE*)in);
{ // len==-1
len = HookStrlen((BYTE *)in);
}
}
else
{
len = HookStrlen((BYTE*)in);
len = HookStrlen((BYTE *)in);
}
}
else
{
if (hp.type & CODEC_UTF16)
len = 2;
else if(hp.type&CODEC_UTF32)
else if (hp.type & CODEC_UTF32)
len = 4;
else
{ //CODEC_ANSI_BE,CHAR_LITTLE_ENDIAN
{ // CODEC_ANSI_BE,CHAR_LITTLE_ENDIAN
if (hp.type & CODEC_ANSI_BE)
in >>= 8;
len = !!IsDBCSLeadByteEx(hp.codepage, in & 0xff) + 1;
@ -532,9 +589,9 @@ int TextHook::GetLength(hook_stack* stack, uintptr_t in)
return max(0, len);
}
int TextHook::HookStrlen(BYTE* data)
int TextHook::HookStrlen(BYTE *data)
{
return HookStrLen(&hp,data);
return HookStrLen(&hp, data);
}
// EOF

View File

@ -6,98 +6,107 @@ Version: 24-March-2008
// #define _WIN32_WINNT 0x0501
#include <windows.h>
#include "veh_hook.h"
#include<mutex>
static veh_list_t* list = NULL;
#include <mutex>
static veh_list_t *list = NULL;
char int3bp[] = "\xCC";
std::mutex vehlistlock;
bool add_veh_hook(void* origFunc, newFuncType newFunc, DWORD hook_type)
bool add_veh_hook(void *origFunc, newFuncType newFunc, DWORD hook_type)
{
std::lock_guard _(vehlistlock);
//static veh_list_t* list = NULL;
// static veh_list_t* list = NULL;
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);
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);
auto newnode = create_veh_node(origFunc, newFunc, handle, hook_type);
if(newnode==NULL)return false;
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;
if(!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));
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){
void repair_origin(veh_node_t *node)
{
DWORD _p;
if(!VirtualProtect(node->origFunc, sizeof(int), PAGE_EXECUTE_READWRITE, &_p))
if (!VirtualProtect(node->origFunc, sizeof(int), PAGE_EXECUTE_READWRITE, &_p))
return;
memcpy((void*)node->origFunc, (const void*)(&node->origBaseByte), sizeof(char));
memcpy((void *)node->origFunc, (const void *)(&node->origBaseByte), sizeof(char));
VirtualProtect(node->origFunc, sizeof(int), node->OldProtect, &_p);
}
bool remove_veh_hook(void* origFunc)
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;
if (list == NULL)
return false;
veh_node_t *node = get_veh_node(list, origFunc);
if (node == NULL)
return false;
repair_origin(node);
RemoveVectoredExceptionHandler(node->handle);
return remove_veh_node(list, origFunc) , true;
return remove_veh_node(list, origFunc), true;
}
void remove_veh_node(veh_list_t* list, void* origFunc)
void remove_veh_node(veh_list_t *list, void *origFunc)
{
veh_node_t* searchnode = list->head;
veh_node_t *searchnode = list->head;
while (searchnode != NULL)
{
if (searchnode->origFunc == origFunc)
{
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;
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 ;
return;
}
searchnode = searchnode->next;
}
return ;
return;
}
LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo)
{
DWORD oldProtect;
void* Addr = ExceptionInfo->ExceptionRecord->ExceptionAddress;
void *Addr = ExceptionInfo->ExceptionRecord->ExceptionAddress;
ULONG Code = ExceptionInfo->ExceptionRecord->ExceptionCode;
if (Code != STATUS_BREAKPOINT && Code != STATUS_SINGLE_STEP) return EXCEPTION_CONTINUE_SEARCH;
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;
if (Code == STATUS_BREAKPOINT )//&& hooktype == VEH_HK_INT3)
if (Code == STATUS_BREAKPOINT) //&& hooktype == VEH_HK_INT3)
{
veh_node_t* currnode ;
veh_node_t *currnode;
{
std::lock_guard _(vehlistlock);
currnode = get_veh_node(list, Addr);
}
if (currnode == NULL) return EXCEPTION_CONTINUE_SEARCH;
if (currnode == NULL)
return EXCEPTION_CONTINUE_SEARCH;
if(currnode->newFunc(ExceptionInfo->ContextRecord))
if (currnode->newFunc(ExceptionInfo->ContextRecord))
{
repair_origin(currnode);
ExceptionInfo->ContextRecord->EFlags |= 0x100;
@ -107,17 +116,17 @@ LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo)
remove_veh_hook(Addr);
}
}
else if (Code == STATUS_SINGLE_STEP )//&& hooktype == VEH_HK_INT3)
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;
veh_node_t *currnode = get_veh_node(list, Addr, 0x10);
if (currnode == NULL)
return EXCEPTION_CONTINUE_SEARCH;
VirtualProtect(Addr, sizeof(int), PAGE_EXECUTE_READWRITE, &currnode->OldProtect);
memcpy((void*)currnode->origFunc, (const void*)&int3bp, sizeof (BYTE));
memcpy((void *)currnode->origFunc, (const void *)&int3bp, sizeof(BYTE));
VirtualProtect(Addr, sizeof(int), currnode->OldProtect, &oldProtect);
ExceptionInfo->ContextRecord->EFlags &= ~0x00000100; // Remove TRACE from EFLAGS
}
// else if (Code == STATUS_SINGLE_STEP && hooktype == VEH_HK_HW)
// {
@ -131,30 +140,33 @@ LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo)
return EXCEPTION_CONTINUE_EXECUTION;
}
veh_list_t* new_veh_list()
veh_list_t *new_veh_list()
{
veh_list_t* newlist = (veh_list_t*)malloc(sizeof(veh_list_t));
if (newlist == NULL) return NULL;
veh_list_t *newlist = (veh_list_t *)malloc(sizeof(veh_list_t));
if (newlist == NULL)
return NULL;
newlist->head = NULL;
newlist->tail = NULL;
return newlist;
}
veh_node_t* create_veh_node(void* origFunc, newFuncType newFunc, void* handle, DWORD hook_type)
veh_node_t *create_veh_node(void *origFunc, newFuncType newFunc, void *handle, DWORD hook_type)
{
veh_node_t* newnode = new veh_node_t;
if (newnode == NULL) return NULL;
newnode->last=NULL;
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;
newnode->hooktype = hook_type;
return newnode;
}
void insert_veh_node(veh_list_t* list, veh_node_t* newnode)
void insert_veh_node(veh_list_t *list, veh_node_t *newnode)
{
if (list == NULL) return;
if (list == NULL)
return;
if (list->head == NULL)
{
list->head = newnode;
@ -163,23 +175,25 @@ void insert_veh_node(veh_list_t* list, veh_node_t* newnode)
else
{
list->tail->next = newnode;
newnode->last=list->tail;
newnode->last = list->tail;
list->tail = newnode;
}
}
veh_node_t* get_veh_node(veh_list_t* list, void* origFunc, int range)
veh_node_t *get_veh_node(veh_list_t *list, void *origFunc, int range)
{
veh_node_t* newnode;
veh_node_t* closestnode = NULL;
if (list == NULL) return NULL;
veh_node_t *newnode;
veh_node_t *closestnode = NULL;
if (list == NULL)
return NULL;
newnode = list->head;
while (newnode != NULL)
{
if(((uintptr_t)origFunc-(uintptr_t)newnode->origFunc)<=range)
if (((uintptr_t)origFunc - (uintptr_t)newnode->origFunc) <= range)
{
closestnode=newnode;
if(range==0)break;
range=((uintptr_t)origFunc-(uintptr_t)newnode->origFunc);
closestnode = newnode;
if (range == 0)
break;
range = ((uintptr_t)origFunc - (uintptr_t)newnode->origFunc);
}
newnode = newnode->next;
}

View File

@ -8,7 +8,7 @@ Version: 24-March-2008
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include<functional>
#include <functional>
// VEH Hooking types
#define VEH_HK_INT3 0
#define VEH_HK_MEM 1
@ -17,43 +17,42 @@ Version: 24-March-2008
#define OPCODE_INT3 "\xCC"
//typedef void (*pfvoid)();
//typedef void (*newFuncType)(PCONTEXT);
// typedef void (*pfvoid)();
// typedef void (*newFuncType)(PCONTEXT);
using newFuncType = std::function<bool(PCONTEXT)>;
typedef struct veh_node
{
struct veh_node* last;
struct veh_node* next;
void* origFunc;
struct veh_node *last;
struct veh_node *next;
void *origFunc;
newFuncType newFunc;
void* handle;
void *handle;
DWORD hooktype;
void* baseAddr; // Address of the page in which origFunc resides.
void *baseAddr; // Address of the page in which origFunc resides.
BYTE origBaseByte;
DWORD OldProtect;
} veh_node_t;
typedef struct
{
veh_node_t* head;
veh_node_t* tail;
veh_node_t *head;
veh_node_t *tail;
} veh_list_t;
// VEH hook interface functions for creating and removing hooks.
bool add_veh_hook(void* origFunc, newFuncType newFunc, DWORD hook_type=VEH_HK_INT3);
bool remove_veh_hook(void* origFunc);
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.
// the function dispatches calls to the correct inctercept function.
LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo);
// Functions used internally by the library.
veh_list_t* new_veh_list();
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*);
void remove_veh_node(veh_list_t* list, void* origFunc);
veh_node_t* get_veh_node(veh_list_t* list, void* origFunc, int range=0);
veh_list_t *new_veh_list();
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 *);
void remove_veh_node(veh_list_t *list, void *origFunc);
veh_node_t *get_veh_node(veh_list_t *list, void *origFunc, int range = 0);
#endif // LIST_T_H_INCLUDED