mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-10-22 23:18:16 +08:00
fmt
This commit is contained in:
parent
0fe834dd27
commit
b0b1fe4417
@ -92,7 +92,7 @@
|
|||||||
#define HS_SEARCH_FOR_TEXT L"Search for specific text"
|
#define HS_SEARCH_FOR_TEXT L"Search for specific text"
|
||||||
#define VersionLatest L"Latest version"
|
#define VersionLatest L"Latest version"
|
||||||
#define VersionCurrent L"Current 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_HOOK L"Hook"
|
||||||
#define LIST_TEXT L"Text"
|
#define LIST_TEXT L"Text"
|
||||||
#define PROC_CONN L"process connected %d"
|
#define PROC_CONN L"process connected %d"
|
||||||
|
@ -92,7 +92,7 @@
|
|||||||
#define HS_SEARCH_FOR_TEXT L"Искать определенный текст"
|
#define HS_SEARCH_FOR_TEXT L"Искать определенный текст"
|
||||||
#define VersionLatest L"Последняя версия"
|
#define VersionLatest L"Последняя версия"
|
||||||
#define VersionCurrent 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_HOOK L"Хук"
|
||||||
#define LIST_TEXT L"Текст"
|
#define LIST_TEXT L"Текст"
|
||||||
#define PROC_CONN L"Процесс подключен %d"
|
#define PROC_CONN L"Процесс подключен %d"
|
||||||
|
@ -92,7 +92,7 @@
|
|||||||
#define HS_SEARCH_FOR_TEXT L"搜索指定文本"
|
#define HS_SEARCH_FOR_TEXT L"搜索指定文本"
|
||||||
#define VersionLatest L"最新版本"
|
#define VersionLatest L"最新版本"
|
||||||
#define VersionCurrent 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\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\npatreon:https://patreon.com/HIllya51\nDiscord:https://discord.gg/f8NSvaDU\n\n本程序是LunaTranslator 的核心子模块,并完全集成在Lunatranslator中。本程序仅包含一些简单功能,如果您需要更多功能,请使用 LunaTranslator。\n如果你发现有不支持的游戏,请提交issue\nhttps://github.com/HIllya51/LunaHook/issues"
|
||||||
#define LIST_HOOK L"Hook"
|
#define LIST_HOOK L"Hook"
|
||||||
#define LIST_TEXT L"文本"
|
#define LIST_TEXT L"文本"
|
||||||
#define PROC_CONN L"进程已连接 %d"
|
#define PROC_CONN L"进程已连接 %d"
|
||||||
|
@ -1,111 +1,118 @@
|
|||||||
class NoEngine:public ENGINE{
|
class NoEngine : public ENGINE
|
||||||
public:
|
{
|
||||||
bool attach_function(){
|
public:
|
||||||
ConsoleOutput("IGNORE %s",getenginename());
|
bool attach_function()
|
||||||
//ConsoleOutput("IGNORE engine");
|
{
|
||||||
|
ConsoleOutput("IGNORE %s", getenginename());
|
||||||
|
// ConsoleOutput("IGNORE engine");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
class oldSystem40ini:public NoEngine{
|
class oldSystem40ini : public NoEngine
|
||||||
public:
|
{
|
||||||
oldSystem40ini(){
|
public:
|
||||||
// jichi 1/19/2015: Disable inserting Lstr for System40
|
oldSystem40ini()
|
||||||
// See: http://sakuradite.com/topic/618
|
{
|
||||||
|
// jichi 1/19/2015: Disable inserting Lstr for System40
|
||||||
check_by=CHECK_BY::FILE;
|
// See: http://sakuradite.com/topic/618
|
||||||
check_by_target=L"System40.ini";
|
|
||||||
};
|
check_by = CHECK_BY::FILE;
|
||||||
|
check_by_target = L"System40.ini";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
// class RPGMakerRGSS3:public NoEngine{
|
// class RPGMakerRGSS3:public NoEngine{
|
||||||
// public:
|
// public:
|
||||||
// RPGMakerRGSS3(){
|
// RPGMakerRGSS3(){
|
||||||
// // jichi 6/7/2015: RPGMaker v3
|
// // jichi 6/7/2015: RPGMaker v3
|
||||||
|
|
||||||
// check_by=CHECK_BY::FILE;
|
// check_by=CHECK_BY::FILE;
|
||||||
// check_by_target=L"*.rgss3a";
|
// check_by_target=L"*.rgss3a";
|
||||||
// };
|
// };
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
|
||||||
// class FVP:public NoEngine{
|
// class FVP:public NoEngine{
|
||||||
// public:
|
// public:
|
||||||
// FVP(){
|
// FVP(){
|
||||||
// // 7/28/2015 jichi: Favorite games
|
// // 7/28/2015 jichi: Favorite games
|
||||||
|
|
||||||
// check_by=CHECK_BY::FILE;
|
// check_by=CHECK_BY::FILE;
|
||||||
// check_by_target=L"*.hcb";
|
// check_by_target=L"*.hcb";
|
||||||
// };
|
// };
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
class AdvPlayerHD : public NoEngine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AdvPlayerHD()
|
||||||
|
{
|
||||||
|
// supposed to be WillPlus
|
||||||
|
|
||||||
|
check_by = CHECK_BY::FILE_ANY;
|
||||||
class AdvPlayerHD:public NoEngine{
|
check_by_target = check_by_list{L"AdvHD.exe", L"AdvHD.dll"};
|
||||||
public:
|
};
|
||||||
AdvPlayerHD(){
|
|
||||||
// supposed to be WillPlus
|
|
||||||
|
|
||||||
check_by=CHECK_BY::FILE_ANY;
|
|
||||||
check_by_target=check_by_list{L"AdvHD.exe",L"AdvHD.dll"};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
class DPM:public NoEngine{
|
check_by_target = L"data_cg.dpm";
|
||||||
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";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
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"};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
class Chartreux:public NoEngine{
|
check_by = CHECK_BY::FILE_ANY;
|
||||||
public:
|
check_by_target = check_by_list{L"gfx.bin", L"snd.bin", L"voc.bin"};
|
||||||
Chartreux(){
|
};
|
||||||
|
};
|
||||||
// jichi 12/28/2014: "Chartreux Inc." in Copyright.
|
|
||||||
// Sublimary brands include Rosebleu, MORE, etc.
|
class Chartreux : public NoEngine
|
||||||
// GetGlyphOutlineA already works.
|
{
|
||||||
|
public:
|
||||||
check_by=CHECK_BY::RESOURCE_STR;
|
Chartreux()
|
||||||
check_by_target=L"Chartreux";
|
{
|
||||||
};
|
|
||||||
};
|
// jichi 12/28/2014: "Chartreux Inc." in Copyright.
|
||||||
class lcsebody:public NoEngine{
|
// Sublimary brands include Rosebleu, MORE, etc.
|
||||||
public:
|
// GetGlyphOutlineA already works.
|
||||||
lcsebody(){
|
|
||||||
|
check_by = CHECK_BY::RESOURCE_STR;
|
||||||
check_by=CHECK_BY::CUSTOM;
|
check_by_target = L"Chartreux";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
class lcsebody : public NoEngine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
lcsebody()
|
||||||
|
{
|
||||||
|
|
||||||
|
check_by = CHECK_BY::CUSTOM;
|
||||||
// jichi 3/19/2014: LC-ScriptEngine, GetGlyphOutlineA
|
// 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*"));
|
{
|
||||||
|
return (wcsstr(processName, L"lcsebody") || !wcsncmp(processName, L"lcsebo~", 7) || Util::CheckFile(L"lcsebody*"));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
// class FVP2:public NoEngine{
|
// class FVP2:public NoEngine{
|
||||||
// public:
|
// public:
|
||||||
// FVP2(){
|
// FVP2(){
|
||||||
|
|
||||||
// check_by=CHECK_BY::CUSTOM;
|
// check_by=CHECK_BY::CUSTOM;
|
||||||
// // jichi 3/19/2014: LC-ScriptEngine, GetGlyphOutlineA
|
// // jichi 3/19/2014: LC-ScriptEngine, GetGlyphOutlineA
|
||||||
// check_by_target=[](){
|
// check_by_target=[](){
|
||||||
|
|
||||||
|
|
||||||
// wchar_t str[MAX_PATH];
|
// wchar_t str[MAX_PATH];
|
||||||
// DWORD i;
|
// DWORD i;
|
||||||
@ -119,19 +126,18 @@ class lcsebody:public NoEngine{
|
|||||||
// // jichi 10/3/2013: such like アトリエかぐや
|
// // jichi 10/3/2013: such like アトリエかぐや
|
||||||
// return (Util::CheckFile(str));
|
// return (Util::CheckFile(str));
|
||||||
// };
|
// };
|
||||||
// };
|
// };
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
|
||||||
//if (Util::CheckFile(L"AGERC.DLL")) { // jichi 3/17/2014: Eushully, AGE.EXE
|
// if (Util::CheckFile(L"AGERC.DLL")) { // jichi 3/17/2014: Eushully, AGE.EXE
|
||||||
// ConsoleOutput("IGNORE Eushully");
|
// ConsoleOutput("IGNORE Eushully");
|
||||||
// return true;
|
// return true;
|
||||||
//}
|
// }
|
||||||
//if (Util::CheckFile(L"*\\Managed\\UnityEngine.dll")) { // jichi 12/3/2013: Unity (BALDRSKY ZERO)
|
// if (Util::CheckFile(L"*\\Managed\\UnityEngine.dll")) { // jichi 12/3/2013: Unity (BALDRSKY ZERO)
|
||||||
// ConsoleOutput("IGNORE Unity");
|
// ConsoleOutput("IGNORE Unity");
|
||||||
// return true;
|
// return true;
|
||||||
//}
|
// }
|
||||||
//if (Util::CheckFile(L"bsz_Data\\Managed\\UnityEngine.dll") || Util::CheckFile(L"bsz2_Data\\Managed\\UnityEngine.dll")) {
|
// if (Util::CheckFile(L"bsz_Data\\Managed\\UnityEngine.dll") || Util::CheckFile(L"bsz2_Data\\Managed\\UnityEngine.dll")) {
|
||||||
// ConsoleOutput("IGNORE Unity");
|
// ConsoleOutput("IGNORE Unity");
|
||||||
// return true;
|
// return true;
|
||||||
//}
|
// }
|
||||||
|
@ -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
|
||||||
if((hp.type&EMBED_CODEC_UTF16)||(hp.type&CODEC_UTF16)){//renpy
|
write_string_overwrite(data, len, trans);
|
||||||
write_string_overwrite(data,len,trans);
|
}
|
||||||
}
|
else
|
||||||
else{
|
{
|
||||||
std::string astr;
|
std::string astr;
|
||||||
if(hp.type&EMBED_DYNA_SJIS&&!normal){
|
if (hp.type & EMBED_DYNA_SJIS && !normal)
|
||||||
astr=dynamiccodec->encodeSTD(trans,0);
|
{
|
||||||
|
astr = dynamiccodec->encodeSTD(trans, 0);
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
astr=WideStringToString(trans,hp.codepage?hp.codepage:((hp.type&CODEC_UTF8)?CP_UTF8:embedsharedmem->codepage));
|
{
|
||||||
|
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,
|
const char *name; // for debugging purpose
|
||||||
newFunction;
|
uintptr_t *oldFunction,
|
||||||
bool attached ;
|
newFunction;
|
||||||
uintptr_t addr;
|
bool attached;
|
||||||
explicit FunctionInfo(const uintptr_t _addr=0,const char *name = "", uintptr_t *oldFunction = nullptr, uintptr_t newFunction = 0,
|
uintptr_t addr;
|
||||||
bool attached = false )
|
explicit FunctionInfo(const uintptr_t _addr = 0, const char *name = "", uintptr_t *oldFunction = nullptr, uintptr_t newFunction = 0,
|
||||||
: name(name), oldFunction(oldFunction), newFunction(newFunction)
|
bool attached = false)
|
||||||
, attached(attached),addr(_addr)
|
: name(name), oldFunction(oldFunction), newFunction(newFunction), attached(attached), addr(_addr)
|
||||||
{}
|
{
|
||||||
};
|
}
|
||||||
|
};
|
||||||
std::unordered_map<uintptr_t, FunctionInfo> funcs; // attached functions
|
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()
|
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(CreateFontA)
|
||||||
ADD_FUN(CreateFontW)
|
ADD_FUN(CreateFontW)
|
||||||
ADD_FUN(CreateFontIndirectA)
|
ADD_FUN(CreateFontIndirectA)
|
||||||
@ -45,8 +50,8 @@ bool _1f()
|
|||||||
ADD_FUN(GetTextExtentPoint32W)
|
ADD_FUN(GetTextExtentPoint32W)
|
||||||
ADD_FUN(GetTextExtentExPointA)
|
ADD_FUN(GetTextExtentExPointA)
|
||||||
ADD_FUN(GetTextExtentExPointW)
|
ADD_FUN(GetTextExtentExPointW)
|
||||||
//ADD_FUN(GetCharABCWidthsA)
|
// ADD_FUN(GetCharABCWidthsA)
|
||||||
//ADD_FUN(GetCharABCWidthsW)
|
// ADD_FUN(GetCharABCWidthsW)
|
||||||
ADD_FUN(TextOutA)
|
ADD_FUN(TextOutA)
|
||||||
ADD_FUN(TextOutW)
|
ADD_FUN(TextOutW)
|
||||||
ADD_FUN(ExtTextOutA)
|
ADD_FUN(ExtTextOutA)
|
||||||
@ -56,107 +61,121 @@ bool _1f()
|
|||||||
ADD_FUN(DrawTextExA)
|
ADD_FUN(DrawTextExA)
|
||||||
ADD_FUN(DrawTextExW)
|
ADD_FUN(DrawTextExW)
|
||||||
ADD_FUN(CharNextA)
|
ADD_FUN(CharNextA)
|
||||||
//ADD_FUN(CharNextW)
|
// ADD_FUN(CharNextW)
|
||||||
//ADD_FUN(CharNextExA)
|
// ADD_FUN(CharNextExA)
|
||||||
//ADD_FUN(CharNextExW)
|
// ADD_FUN(CharNextExW)
|
||||||
ADD_FUN(CharPrevA)
|
ADD_FUN(CharPrevA)
|
||||||
//ADD_FUN(CharPrevW)
|
// ADD_FUN(CharPrevW)
|
||||||
ADD_FUN(MultiByteToWideChar)
|
ADD_FUN(MultiByteToWideChar)
|
||||||
ADD_FUN(WideCharToMultiByte)
|
ADD_FUN(WideCharToMultiByte)
|
||||||
#undef ADD_FUN
|
#undef ADD_FUN
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
bool _1=_1f();
|
bool _1 = _1f();
|
||||||
void ReplaceFunction(PVOID* oldf,PVOID newf){
|
void ReplaceFunction(PVOID *oldf, PVOID newf)
|
||||||
|
{
|
||||||
|
|
||||||
RemoveHook((uintptr_t)*oldf);
|
RemoveHook((uintptr_t)*oldf);
|
||||||
DetourTransactionBegin();
|
DetourTransactionBegin();
|
||||||
DetourUpdateThread(GetCurrentThread());
|
DetourUpdateThread(GetCurrentThread());
|
||||||
DetourAttach((PVOID*)oldf, (PVOID)newf);
|
DetourAttach((PVOID *)oldf, (PVOID)newf);
|
||||||
DetourTransactionCommit();
|
DetourTransactionCommit();
|
||||||
}
|
}
|
||||||
void attachFunction(uintptr_t _hook_font_flag)
|
void attachFunction(uintptr_t _hook_font_flag)
|
||||||
{
|
{
|
||||||
for(auto & _func:funcs){
|
for (auto &_func : funcs)
|
||||||
if(_func.first&_hook_font_flag){
|
{
|
||||||
if(_func.second.attached)continue;
|
if (_func.first & _hook_font_flag)
|
||||||
_func.second.attached = true;
|
{
|
||||||
*_func.second.oldFunction=_func.second.addr;
|
if (_func.second.attached)
|
||||||
|
continue;
|
||||||
|
_func.second.attached = true;
|
||||||
|
*_func.second.oldFunction = _func.second.addr;
|
||||||
replacedfuns.push_back(_func.first);
|
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();
|
DetourTransactionBegin();
|
||||||
DetourUpdateThread(GetCurrentThread());
|
DetourUpdateThread(GetCurrentThread());
|
||||||
for(auto _flag:replacedfuns){
|
for (auto _flag : replacedfuns)
|
||||||
auto info=funcs.at(_flag);
|
{
|
||||||
DetourDetach((PVOID*)info.oldFunction, (PVOID)info.newFunction);
|
auto info = funcs.at(_flag);
|
||||||
|
DetourDetach((PVOID *)info.oldFunction, (PVOID)info.newFunction);
|
||||||
}
|
|
||||||
DetourTransactionCommit();
|
|
||||||
}
|
|
||||||
void solvefont(HookParam hp){
|
|
||||||
if(hp.hook_font){
|
|
||||||
attachFunction(hp.hook_font);
|
|
||||||
}
|
}
|
||||||
if(hp.hook_font&F_MultiByteToWideChar)
|
DetourTransactionCommit();
|
||||||
disable_mbwc=true;
|
}
|
||||||
if(hp.hook_font&F_WideCharToMultiByte)
|
void solvefont(HookParam hp)
|
||||||
disable_wcmb=true;
|
{
|
||||||
|
if (hp.hook_font)
|
||||||
if (auto current_patch_fun = patch_fun.exchange(nullptr)){
|
{
|
||||||
|
attachFunction(hp.hook_font);
|
||||||
|
}
|
||||||
|
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))
|
||||||
|
{
|
||||||
current_patch_fun();
|
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) {
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
std::wstring ret;
|
||||||
if (ch <= 127) // ignore ascii characters
|
for (auto c : text)
|
||||||
return true;
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
ret.push_back(c);
|
||||||
std::wstring ret;
|
if (c >= 32) // ignore non-printable characters
|
||||||
for(const wchar_t & c: text) {
|
ret.push_back(L' '); // or insert \u3000 if needed
|
||||||
ret.push_back(c);
|
|
||||||
if (!charEncodableSTD(c, hp.codepage?hp.codepage:embedsharedmem->codepage))
|
|
||||||
ret.push_back(L' ');
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
std::wstring adjustSpacesSTD(const std::wstring& text,HookParam hp)
|
return ret;
|
||||||
|
}
|
||||||
|
bool charEncodableSTD(const wchar_t &ch, UINT codepage)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (ch <= 127) // ignore ascii characters
|
||||||
|
return true;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
|
||||||
|
std::wstring ret;
|
||||||
|
for (const wchar_t &c : text)
|
||||||
|
{
|
||||||
|
ret.push_back(c);
|
||||||
|
if (!charEncodableSTD(c, hp.codepage ? hp.codepage : embedsharedmem->codepage))
|
||||||
|
ret.push_back(L' ');
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
std::wstring adjustSpacesSTD(const std::wstring &text, HookParam hp)
|
||||||
|
{
|
||||||
|
|
||||||
switch (embedsharedmem->spaceadjustpolicy)
|
switch (embedsharedmem->spaceadjustpolicy)
|
||||||
{
|
{
|
||||||
case 0: return text;
|
case 0:
|
||||||
case 1:return alwaysInsertSpacesSTD(text);
|
return text;
|
||||||
case 2:return insertSpacesAfterUnencodableSTD(text, hp);
|
case 1:
|
||||||
default:return text;
|
return alwaysInsertSpacesSTD(text);
|
||||||
}
|
case 2:
|
||||||
}
|
return insertSpacesAfterUnencodableSTD(text, hp);
|
||||||
std::wstring limitTextWidth(const std::wstring& text, int size)
|
default:
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::wstring limitTextWidth(const std::wstring &text, int size)
|
||||||
{
|
{
|
||||||
auto lines=strSplit(text,L"\n");
|
auto lines = strSplit(text, L"\n");
|
||||||
std::for_each(lines.begin(),lines.end(),[=](auto &line){
|
std::for_each(lines.begin(), lines.end(), [=](auto &line)
|
||||||
|
{
|
||||||
if(line.size()<=size)
|
if(line.size()<=size)
|
||||||
return;
|
return;
|
||||||
std::wstring ret;
|
std::wstring ret;
|
||||||
@ -166,106 +185,128 @@ std::wstring limitTextWidth(const std::wstring& text, int size)
|
|||||||
ret+=L'\n';
|
ret+=L'\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
line=ret;
|
line=ret; });
|
||||||
});
|
|
||||||
std::wstring ret;
|
std::wstring ret;
|
||||||
for(int i=0;i<lines.size();i++){
|
for (int i = 0; i < lines.size(); i++)
|
||||||
ret+=lines[i];
|
{
|
||||||
if(i<lines.size()-1)ret+=L'\n';
|
ret += lines[i];
|
||||||
|
if (i < lines.size() - 1)
|
||||||
|
ret += L'\n';
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
bool isPauseKeyPressed()
|
bool isPauseKeyPressed()
|
||||||
{
|
{
|
||||||
return WinKey::isKeyControlPressed()
|
return WinKey::isKeyControlPressed() || WinKey::isKeyShiftPressed() && !WinKey::isKeyReturnPressed();
|
||||||
|| 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;
|
int i = 0;
|
||||||
while (len--){
|
while (len--)
|
||||||
hash = ((hash << 5) + hash) + (*str++); // hash * 33 + c
|
{
|
||||||
}
|
hash = ((hash << 5) + hash) + (*str++); // hash * 33 + c
|
||||||
return hash;
|
}
|
||||||
|
return hash;
|
||||||
}
|
}
|
||||||
std::unordered_map<UINT64,std::wstring>translatecache;
|
std::unordered_map<UINT64, std::wstring> translatecache;
|
||||||
bool check_is_thread_selected(const ThreadParam& tp){
|
bool check_is_thread_selected(const ThreadParam &tp)
|
||||||
for(int i=0;i<10;i++)
|
{
|
||||||
if(embedsharedmem->use[i])
|
for (int i = 0; i < 10; i++)
|
||||||
if((embedsharedmem->addr[i]==tp.addr)&&(embedsharedmem->ctx1[i]==tp.ctx)&&(embedsharedmem->ctx2[i]==tp.ctx2))
|
if (embedsharedmem->use[i])
|
||||||
|
if ((embedsharedmem->addr[i] == tp.addr) && (embedsharedmem->ctx1[i] == tp.ctx) && (embedsharedmem->ctx2[i] == tp.ctx2))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool check_embed_able(const ThreadParam& tp){
|
bool check_embed_able(const ThreadParam &tp)
|
||||||
return host_connected&&check_is_thread_selected(tp)&&((isPauseKeyPressed()==false)?true:!embedsharedmem->fastskipignore);
|
{
|
||||||
|
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));
|
char eventname[1000];
|
||||||
auto event=win_event(eventname);
|
sprintf(eventname, LUNA_EMBED_notify_event, GetCurrentProcessId(), djb2_n2((const unsigned char *)(origin.c_str()), origin.size() * 2));
|
||||||
while(timems){
|
auto event = win_event(eventname);
|
||||||
if(check_embed_able(tp)==false)return false;
|
while (timems)
|
||||||
auto sleepstep=min(100,timems);
|
{
|
||||||
if(event.wait(sleepstep))return true;
|
if (check_embed_able(tp) == false)
|
||||||
timems-=sleepstep;
|
return false;
|
||||||
}
|
auto sleepstep = min(100, timems);
|
||||||
return false;
|
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)
|
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
|
else
|
||||||
{
|
{
|
||||||
//ansi/utf8,newlineseperator都是简单字符
|
// ansi/utf8,newlineseperator都是简单字符
|
||||||
std::string newlineseperatorA;
|
std::string newlineseperatorA;
|
||||||
for(int i=0;i<wcslen(hp.newlineseperator);i++)newlineseperatorA+=(char)hp.newlineseperator[i];
|
for (int i = 0; i < wcslen(hp.newlineseperator); i++)
|
||||||
StringReplacer((char*)data,len,newlineseperatorA.c_str(),newlineseperatorA.size(),"\n",1);
|
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;
|
UINT64 sum = 0;
|
||||||
auto u8data=(UINT8*)data;
|
auto u8data = (UINT8 *)data;
|
||||||
for(int i=0;i< len;i++){
|
for (int i = 0; i < len; i++)
|
||||||
sum+=u8data[i];
|
{
|
||||||
sum=sum<<1;
|
sum += u8data[i];
|
||||||
|
sum = sum << 1;
|
||||||
}
|
}
|
||||||
return sum;
|
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
|
ZeroMemory(embedsharedmem->text, sizeof(embedsharedmem->text)); // clear trans before call
|
||||||
if(len>1000)return true;
|
if (len > 1000)
|
||||||
return(translatecache.find(texthash(data,len))!=translatecache.end());
|
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;
|
std::wstring origin;
|
||||||
if (auto t=commonparsestring(data,*len,&hp,embedsharedmem->codepage)) origin=t.value();
|
if (auto t = commonparsestring(data, *len, &hp, embedsharedmem->codepage))
|
||||||
else return false;
|
origin = t.value();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
std::wstring translate;
|
std::wstring translate;
|
||||||
auto hash=texthash(data,*len);
|
auto hash = texthash(data, *len);
|
||||||
if(translatecache.find(hash)!=translatecache.end()){
|
if (translatecache.find(hash) != translatecache.end())
|
||||||
translate=translatecache.at(hash);
|
{
|
||||||
|
translate = translatecache.at(hash);
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
if(waitforevent(embedsharedmem->waittime,tp,origin)==false)return false;
|
{
|
||||||
translate=embedsharedmem->text;
|
if (waitforevent(embedsharedmem->waittime, tp, origin) == false)
|
||||||
if((translate.size()==0))return false;
|
return false;
|
||||||
translatecache.insert(std::make_pair(hash,translate));
|
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 (embedsharedmem->line_text_length_limit)
|
||||||
if(hp.newlineseperator)strReplace(translate,L"\n",hp.newlineseperator);
|
translate = limitTextWidth(translate, embedsharedmem->line_text_length_limit);
|
||||||
translate=adjustSpacesSTD(translate,hp);
|
if (hp.newlineseperator)
|
||||||
if(embedsharedmem->keeprawtext)translate=origin+L" "+translate;
|
strReplace(translate, L"\n", hp.newlineseperator);
|
||||||
|
translate = adjustSpacesSTD(translate, hp);
|
||||||
|
if (embedsharedmem->keeprawtext)
|
||||||
|
translate = origin + L" " + translate;
|
||||||
solvefont(hp);
|
solvefont(hp);
|
||||||
cast_back(hp,data,len,translate,false);
|
cast_back(hp, data, len, translate, false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
@ -2,9 +2,10 @@
|
|||||||
#define __LUNA_EMBED_ENGINE_H
|
#define __LUNA_EMBED_ENGINE_H
|
||||||
|
|
||||||
extern EmbedSharedMem *embedsharedmem;
|
extern EmbedSharedMem *embedsharedmem;
|
||||||
extern DynamicShiftJISCodec *dynamiccodec ;
|
extern DynamicShiftJISCodec *dynamiccodec;
|
||||||
|
|
||||||
namespace WinKey {
|
namespace WinKey
|
||||||
|
{
|
||||||
inline bool isKeyPressed(int vk) { return ::GetKeyState(vk) & 0xf0; }
|
inline bool isKeyPressed(int vk) { return ::GetKeyState(vk) & 0xf0; }
|
||||||
inline bool isKeyToggled(int vk) { return ::GetKeyState(vk) & 0x0f; }
|
inline bool isKeyToggled(int vk) { return ::GetKeyState(vk) & 0x0f; }
|
||||||
|
|
||||||
@ -12,14 +13,22 @@ namespace WinKey {
|
|||||||
inline bool isKeyControlPressed() { return isKeyPressed(VK_CONTROL); }
|
inline bool isKeyControlPressed() { return isKeyPressed(VK_CONTROL); }
|
||||||
inline bool isKeyShiftPressed() { return isKeyPressed(VK_SHIFT); }
|
inline bool isKeyShiftPressed() { return isKeyPressed(VK_SHIFT); }
|
||||||
inline bool isKeyAltPressed() { return isKeyPressed(VK_MENU); }
|
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;
|
namespace Engine
|
||||||
void ReplaceFunction(PVOID* oldf,PVOID newf);
|
{
|
||||||
bool check_embed_able(const ThreadParam& tp);
|
enum TextRole
|
||||||
bool checktranslatedok(void*data ,size_t len);
|
{
|
||||||
|
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
|
#endif
|
@ -1,38 +1,43 @@
|
|||||||
#ifndef __LUNA_ENGINE_H
|
#ifndef __LUNA_ENGINE_H
|
||||||
#define __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;
|
||||||
extern uintptr_t processStartAddress, processStopAddress;
|
extern uintptr_t processStartAddress, processStopAddress;
|
||||||
|
|
||||||
class ENGINE{
|
class ENGINE
|
||||||
public:
|
{
|
||||||
const char* enginename;
|
public:
|
||||||
bool dontstop;//dont stop even if attached a engine
|
const char *enginename;
|
||||||
bool is_engine_certain; //stop when match a engine ,even if not attached
|
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,
|
ALL_TRUE,
|
||||||
FILE, FILE_ALL,FILE_ANY,
|
FILE,
|
||||||
|
FILE_ALL,
|
||||||
|
FILE_ANY,
|
||||||
RESOURCE_STR,
|
RESOURCE_STR,
|
||||||
CUSTOM,
|
CUSTOM,
|
||||||
};
|
};
|
||||||
CHECK_BY check_by;
|
CHECK_BY check_by;
|
||||||
// const wchar_t* check_by_single;
|
// const wchar_t* check_by_single;
|
||||||
// std::vector<const wchar_t*>check_by_list;
|
// std::vector<const wchar_t*>check_by_list;
|
||||||
// std::function<bool()>check_by_custom_function;
|
// std::function<bool()>check_by_custom_function;
|
||||||
typedef 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 std::vector<const wchar_t *> check_by_list;
|
||||||
typedef const wchar_t* check_by_single;
|
typedef const wchar_t *check_by_single;
|
||||||
std::variant<check_by_single,check_by_list,check_by_custom_function>check_by_target;
|
std::variant<check_by_single, check_by_list, check_by_custom_function> check_by_target;
|
||||||
//virtual bool check_by_target(){return false;};
|
// virtual bool check_by_target(){return false;};
|
||||||
virtual bool attach_function()=0;
|
virtual bool attach_function() = 0;
|
||||||
virtual const char* getenginename(){
|
virtual const char *getenginename()
|
||||||
if(enginename)return enginename;
|
{
|
||||||
return typeid(*this).name()+6;
|
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();
|
bool check_function();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,180 +1,181 @@
|
|||||||
#include"engine32/PPSSPP.h"
|
#include "engine32/PPSSPP.h"
|
||||||
#include"engine32/LovaGame.h"
|
#include "engine32/LovaGame.h"
|
||||||
#include"engine32/PCSX2.h"
|
#include "engine32/PCSX2.h"
|
||||||
#include"engine32/VanillawareGC.h"
|
#include "engine32/VanillawareGC.h"
|
||||||
#include"engine32/V8.h"
|
#include "engine32/V8.h"
|
||||||
#include"engine32/cef.h"
|
#include "engine32/cef.h"
|
||||||
#include"engine32/KISS.h"
|
#include "engine32/KISS.h"
|
||||||
#include"engine32/mono.h"
|
#include "engine32/mono.h"
|
||||||
#include"engine32/Tarte.h"
|
#include "engine32/Tarte.h"
|
||||||
#include"engine32/sakanagl.h"
|
#include "engine32/sakanagl.h"
|
||||||
#include"engine32/LCScript.h"
|
#include "engine32/LCScript.h"
|
||||||
#include"engine32/ONScripterru.h"
|
#include "engine32/ONScripterru.h"
|
||||||
#include"engine32/CoffeeMaker.h"
|
#include "engine32/CoffeeMaker.h"
|
||||||
#include"engine32/splushwave.h"
|
#include "engine32/splushwave.h"
|
||||||
#include"engine32/FrontWing.h"
|
#include "engine32/FrontWing.h"
|
||||||
#include"engine32/GSX.h"
|
#include "engine32/GSX.h"
|
||||||
#include"engine32/pchooks.h"
|
#include "engine32/pchooks.h"
|
||||||
#include"engine32/VALKYRIA.h"
|
#include "engine32/VALKYRIA.h"
|
||||||
#include"engine32/mirage.h"
|
#include "engine32/mirage.h"
|
||||||
#include"engine32/Sprite.h"
|
#include "engine32/Sprite.h"
|
||||||
#include"engine32/PONScripter.h"
|
#include "engine32/PONScripter.h"
|
||||||
#include"engine32/Fizz.h"
|
#include "engine32/Fizz.h"
|
||||||
#include"engine32/Ruf.h"
|
#include "engine32/Ruf.h"
|
||||||
#include"engine32/SYSD.h"
|
#include "engine32/SYSD.h"
|
||||||
#include"engine32/Diskdream.h"
|
#include "engine32/Diskdream.h"
|
||||||
#include"engine32/RPGMakerRGSS3.h"
|
#include "engine32/RPGMakerRGSS3.h"
|
||||||
#include"engine32/RUNE.h"
|
#include "engine32/RUNE.h"
|
||||||
#include"engine32/Lightvn.h"
|
#include "engine32/Lightvn.h"
|
||||||
#include"engine32/KiriKiri.h"
|
#include "engine32/KiriKiri.h"
|
||||||
#include"engine32/ransel.h"
|
#include "engine32/ransel.h"
|
||||||
#include"engine32/Bishop.h"
|
#include "engine32/Bishop.h"
|
||||||
#include"engine32/HXP.h"
|
#include "engine32/HXP.h"
|
||||||
#include"engine32/morning.h"
|
#include "engine32/morning.h"
|
||||||
#include"engine32/IGScript.h"
|
#include "engine32/IGScript.h"
|
||||||
#include"engine32/TSSystem.h"
|
#include "engine32/TSSystem.h"
|
||||||
#include"engine32/ScrPlayer.h"
|
#include "engine32/ScrPlayer.h"
|
||||||
#include"engine32/Aksys.h"
|
#include "engine32/Aksys.h"
|
||||||
#include"engine32/utawarerumono.h"
|
#include "engine32/utawarerumono.h"
|
||||||
#include"engine32/SideB.h"
|
#include "engine32/SideB.h"
|
||||||
#include"engine32/BGI.h"
|
#include "engine32/BGI.h"
|
||||||
#include"engine32/Bootup.h"
|
#include "engine32/Bootup.h"
|
||||||
#include"engine32/Troy.h"
|
#include "engine32/Troy.h"
|
||||||
#include"engine32/Tomato.h"
|
#include "engine32/Tomato.h"
|
||||||
#include"engine32/shyakunage.h"
|
#include "engine32/shyakunage.h"
|
||||||
#include"engine32/Eushully.h"
|
#include "engine32/Eushully.h"
|
||||||
#include"engine32/Majiro.h"
|
#include "engine32/Majiro.h"
|
||||||
#include"engine32/Elf.h"
|
#include "engine32/Elf.h"
|
||||||
#include"engine32/Silkys.h"
|
#include "engine32/Silkys.h"
|
||||||
#include"engine32/Speed.h"
|
#include "engine32/Speed.h"
|
||||||
#include"engine32/FVP.h"
|
#include "engine32/FVP.h"
|
||||||
#include"engine32/Interlude.h"
|
#include "engine32/Interlude.h"
|
||||||
#include"engine32/CMVS.h"
|
#include "engine32/CMVS.h"
|
||||||
#include"engine32/Wolf.h"
|
#include "engine32/Wolf.h"
|
||||||
#include"engine32/Circus1.h"
|
#include "engine32/Circus1.h"
|
||||||
#include"engine32/Circus2.h"
|
#include "engine32/Circus2.h"
|
||||||
#include"engine32/Cotopha.h"
|
#include "engine32/Cotopha.h"
|
||||||
#include"engine32/Xbangbang.h"
|
#include "engine32/Xbangbang.h"
|
||||||
#include"engine32/TeethingRing.h"
|
#include "engine32/TeethingRing.h"
|
||||||
#include"engine32/Unknown.h"
|
#include "engine32/Unknown.h"
|
||||||
#include"engine32/Artemis.h"
|
#include "engine32/Artemis.h"
|
||||||
#include"engine32/CatSystem.h"
|
#include "engine32/CatSystem.h"
|
||||||
#include"engine32/Atelier.h"
|
#include "engine32/Atelier.h"
|
||||||
#include"engine32/BKEngine.h"
|
#include "engine32/BKEngine.h"
|
||||||
#include"engine32/VitaminSoft.h"
|
#include "engine32/VitaminSoft.h"
|
||||||
#include"engine32/Abalone.h"
|
#include "engine32/Abalone.h"
|
||||||
#include"engine32/Tenco.h"
|
#include "engine32/Tenco.h"
|
||||||
#include"engine32/QLIE.h"
|
#include "engine32/QLIE.h"
|
||||||
#include"engine32/sakusesu.h"
|
#include "engine32/sakusesu.h"
|
||||||
#include"engine32/Anisetta.h"
|
#include "engine32/Anisetta.h"
|
||||||
#include"engine32/Regista.h"
|
#include "engine32/Regista.h"
|
||||||
#include"engine32/Pal.h"
|
#include "engine32/Pal.h"
|
||||||
#include"engine32/Footy2.h"
|
#include "engine32/Footy2.h"
|
||||||
#include"engine32/NeXAS.h"
|
#include "engine32/NeXAS.h"
|
||||||
#include"engine32/Interheart.h"
|
#include "engine32/Interheart.h"
|
||||||
#include"engine32/LunaSoft.h"
|
#include "engine32/LunaSoft.h"
|
||||||
#include"engine32/Unicorn.h"
|
#include "engine32/Unicorn.h"
|
||||||
#include"engine32/Rejet.h"
|
#include "engine32/Rejet.h"
|
||||||
#include"engine32/tamasoft.h"
|
#include "engine32/tamasoft.h"
|
||||||
#include"engine32/AdobeAir.h"
|
#include "engine32/AdobeAir.h"
|
||||||
#include"engine32/Retouch.h"
|
#include "engine32/Retouch.h"
|
||||||
#include"engine32/Malie.h"
|
#include "engine32/Malie.h"
|
||||||
#include"engine32/Live.h"
|
#include "engine32/Live.h"
|
||||||
#include"engine32/Jellyfish.h"
|
#include "engine32/Jellyfish.h"
|
||||||
#include"engine32/Nexton.h"
|
#include "engine32/Nexton.h"
|
||||||
#include"engine32/Lucifen.h"
|
#include "engine32/Lucifen.h"
|
||||||
#include"engine32/Waffle.h"
|
#include "engine32/Waffle.h"
|
||||||
#include"engine32/Sakuradog.h"
|
#include "engine32/Sakuradog.h"
|
||||||
#include"engine32/TinkerBell.h"
|
#include "engine32/TinkerBell.h"
|
||||||
#include"engine32/Jisatu101.h"
|
#include "engine32/Jisatu101.h"
|
||||||
#include"engine32/TerraLunar.h"
|
#include "engine32/TerraLunar.h"
|
||||||
#include"engine32/Palette.h"
|
#include "engine32/Palette.h"
|
||||||
#include"engine32/SystemAoi.h"
|
#include "engine32/SystemAoi.h"
|
||||||
#include"engine32/Nijyuei.h"
|
#include "engine32/Nijyuei.h"
|
||||||
#include"engine32/MBLMED.h"
|
#include "engine32/MBLMED.h"
|
||||||
#include"engine32/NNNConfig.h"
|
#include "engine32/NNNConfig.h"
|
||||||
#include"engine32/Erogos.h"
|
#include "engine32/Erogos.h"
|
||||||
#include"engine32/godot.h"
|
#include "engine32/godot.h"
|
||||||
#include"engine32/Yuris.h"
|
#include "engine32/Yuris.h"
|
||||||
#include"engine32/Nitroplus.h"
|
#include "engine32/Nitroplus.h"
|
||||||
#include"engine32/Bruns.h"
|
#include "engine32/Bruns.h"
|
||||||
#include"engine32/XUSE.h"
|
#include "engine32/XUSE.h"
|
||||||
#include"engine32/EME.h"
|
#include "engine32/EME.h"
|
||||||
#include"engine32/RRE.h"
|
#include "engine32/RRE.h"
|
||||||
#include"engine32/Candy.h"
|
#include "engine32/Candy.h"
|
||||||
#include"engine32/AIL2.h"
|
#include "engine32/AIL2.h"
|
||||||
#include"engine32/ApricoT.h"
|
#include "engine32/ApricoT.h"
|
||||||
#include"engine32/Triangle.h"
|
#include "engine32/Triangle.h"
|
||||||
#include"engine32/GASTRO.h"
|
#include "engine32/GASTRO.h"
|
||||||
#include"engine32/akatombo.h"
|
#include "engine32/akatombo.h"
|
||||||
#include"engine32/AB2Try.h"
|
#include "engine32/AB2Try.h"
|
||||||
#include"engine32/GameMaker.h"
|
#include "engine32/GameMaker.h"
|
||||||
#include"engine32/DxLib.h"
|
#include "engine32/DxLib.h"
|
||||||
#include"engine32/CodeX.h"
|
#include "engine32/CodeX.h"
|
||||||
#include"engine32/Purple.h"
|
#include "engine32/Purple.h"
|
||||||
#include"engine32/Minori.h"
|
#include "engine32/Minori.h"
|
||||||
#include"engine32/SRPGStudio.h"
|
#include "engine32/SRPGStudio.h"
|
||||||
#include"engine32/RpgmXP.h"
|
#include "engine32/RpgmXP.h"
|
||||||
#include"engine32/littlecheese.h"
|
#include "engine32/littlecheese.h"
|
||||||
#include"engine32/Eagls.h"
|
#include "engine32/Eagls.h"
|
||||||
#include"engine32/Debonosu.h"
|
#include "engine32/Debonosu.h"
|
||||||
#include"engine32/C4.h"
|
#include "engine32/C4.h"
|
||||||
#include"engine32/WillPlus.h"
|
#include "engine32/WillPlus.h"
|
||||||
#include"engine32/Tanuki.h"
|
#include "engine32/Tanuki.h"
|
||||||
#include"engine32/hibiki.h"
|
#include "engine32/hibiki.h"
|
||||||
#include"engine32/GXP.h"
|
#include "engine32/GXP.h"
|
||||||
#include"engine32/Giga.h"
|
#include "engine32/Giga.h"
|
||||||
#include"engine32/AOS.h"
|
#include "engine32/AOS.h"
|
||||||
#include"engine32/Mink.h"
|
#include "engine32/Mink.h"
|
||||||
#include"engine32/AGS.h"
|
#include "engine32/AGS.h"
|
||||||
#include"engine32/YukaSystem2.h"
|
#include "engine32/YukaSystem2.h"
|
||||||
#include"engine32/Exp.h"
|
#include "engine32/Exp.h"
|
||||||
#include"engine32/Syuntada.h"
|
#include "engine32/Syuntada.h"
|
||||||
#include"engine32/Pensil.h"
|
#include "engine32/Pensil.h"
|
||||||
#include"engine32/solfasys.h"
|
#include "engine32/solfasys.h"
|
||||||
#include"engine32/Anim.h"
|
#include "engine32/Anim.h"
|
||||||
#include"engine32/Nitroplus2.h"
|
#include "engine32/Nitroplus2.h"
|
||||||
#include"engine32/Reallive.h"
|
#include "engine32/Reallive.h"
|
||||||
#include"engine32/jukujojidai.h"
|
#include "engine32/jukujojidai.h"
|
||||||
#include"engine32/Siglus.h"
|
#include "engine32/Siglus.h"
|
||||||
#include"engine32/Taskforce2.h"
|
#include "engine32/Taskforce2.h"
|
||||||
#include"engine32/RUGP.h"
|
#include "engine32/RUGP.h"
|
||||||
#include"engine32/IronGameSystem.h"
|
#include "engine32/IronGameSystem.h"
|
||||||
#include"engine32/Anex86.h"
|
#include "engine32/Anex86.h"
|
||||||
#include"engine32/ShinyDaysGame.h"
|
#include "engine32/ShinyDaysGame.h"
|
||||||
#include"engine32/MarineHeart.h"
|
#include "engine32/MarineHeart.h"
|
||||||
#include"engine32/ShinaRio.h"
|
#include "engine32/ShinaRio.h"
|
||||||
#include"engine32/CaramelBox.h"
|
#include "engine32/CaramelBox.h"
|
||||||
#include"engine32/Escude.h"
|
#include "engine32/Escude.h"
|
||||||
#include"engine32/Ryokucha.h"
|
#include "engine32/Ryokucha.h"
|
||||||
#include"engine32/Alice.h"
|
#include "engine32/Alice.h"
|
||||||
#include"engine32/System4x.h"
|
#include "engine32/System4x.h"
|
||||||
#include"engine32/Abel.h"
|
#include "engine32/Abel.h"
|
||||||
#include"engine32/5pb.h"
|
#include "engine32/5pb.h"
|
||||||
#include"engine32/HorkEye.h"
|
#include "engine32/HorkEye.h"
|
||||||
#include"engine32/Ohgetsu.h"
|
#include "engine32/Ohgetsu.h"
|
||||||
#include"engine32/OVERDRIVE.h"
|
#include "engine32/OVERDRIVE.h"
|
||||||
#include"engine32/Leaf.h"
|
#include "engine32/Leaf.h"
|
||||||
#include"engine32/Nekopack.h"
|
#include "engine32/Nekopack.h"
|
||||||
#include"engine32/AdobeFlash10.h"
|
#include "engine32/AdobeFlash10.h"
|
||||||
#include"engine32/FocasLens.h"
|
#include "engine32/FocasLens.h"
|
||||||
#include"engine32/Tamamo.h"
|
#include "engine32/Tamamo.h"
|
||||||
#include"engine32/Suika2.h"
|
#include "engine32/Suika2.h"
|
||||||
#include"engine32/Overflow.h"
|
#include "engine32/Overflow.h"
|
||||||
#include"engine32/Ages3ResT.h"
|
#include "engine32/Ages3ResT.h"
|
||||||
#include"engine32/AXL.h"
|
#include "engine32/AXL.h"
|
||||||
#include"engine32/UnisonShift.h"
|
#include "engine32/UnisonShift.h"
|
||||||
#include"engine32/EntisGLS.h"
|
#include "engine32/EntisGLS.h"
|
||||||
#include"engine32/Ciel.h"
|
#include "engine32/Ciel.h"
|
||||||
#include"engine32/CisLugI.h"
|
#include "engine32/CisLugI.h"
|
||||||
#include"engine32/A98SYS.h"
|
#include "engine32/A98SYS.h"
|
||||||
#include"engine32/ACTGS.h"
|
#include "engine32/ACTGS.h"
|
||||||
#include"engine32/GuruGuruSMF4.h"
|
#include "engine32/GuruGuruSMF4.h"
|
||||||
#include"NoEngine.h"
|
#include "NoEngine.h"
|
||||||
#include"engines/lua/lua51.h"
|
#include "engines/lua/lua51.h"
|
||||||
#include"engines/python/Renpy.h"
|
#include "engines/python/Renpy.h"
|
||||||
std::vector<ENGINE*> check_engines(){
|
std::vector<ENGINE *> check_engines()
|
||||||
return {
|
{
|
||||||
|
return {
|
||||||
new LovaGame,
|
new LovaGame,
|
||||||
new PPSSPPengine,
|
new PPSSPPengine,
|
||||||
new PCSX2,
|
new PCSX2,
|
||||||
@ -225,7 +226,7 @@ std::vector<ENGINE*> check_engines(){
|
|||||||
new Malie,
|
new Malie,
|
||||||
new Live,
|
new Live,
|
||||||
new Nexton,
|
new Nexton,
|
||||||
new Lucifen,
|
new Lucifen,
|
||||||
new Waffle,
|
new Waffle,
|
||||||
new TinkerBell,
|
new TinkerBell,
|
||||||
new TinkerBellold,
|
new TinkerBellold,
|
||||||
@ -344,25 +345,25 @@ std::vector<ENGINE*> check_engines(){
|
|||||||
new A98SYS,
|
new A98SYS,
|
||||||
new godot,
|
new godot,
|
||||||
new Erogos,
|
new Erogos,
|
||||||
new Silkysveryveryold
|
new Silkysveryveryold};
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ENGINE*> ignore_engines(){
|
std::vector<ENGINE *> ignore_engines()
|
||||||
return{
|
{
|
||||||
|
return {
|
||||||
|
|
||||||
new oldSystem40ini,
|
new oldSystem40ini,
|
||||||
new AdvPlayerHD,
|
new AdvPlayerHD,
|
||||||
new DPM,
|
new DPM,
|
||||||
new Escude_ignore,
|
new Escude_ignore,
|
||||||
new Chartreux,
|
new Chartreux,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
std::vector<ENGINE*> unsafe_check_atlast(){
|
std::vector<ENGINE *> unsafe_check_atlast()
|
||||||
|
{
|
||||||
// Put the patterns that might break other games at last
|
// Put the patterns that might break other games at last
|
||||||
|
|
||||||
return{
|
return {
|
||||||
new UnisonShift,
|
new UnisonShift,
|
||||||
new Interheart,
|
new Interheart,
|
||||||
new Abalone,
|
new Abalone,
|
||||||
@ -395,7 +396,5 @@ std::vector<ENGINE*> unsafe_check_atlast(){
|
|||||||
new ShinaRio,
|
new ShinaRio,
|
||||||
new Suika2,
|
new Suika2,
|
||||||
new KISS,
|
new KISS,
|
||||||
new EntisGLS
|
new EntisGLS};
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
@ -1,31 +1,32 @@
|
|||||||
#include"engine64/PPSSPP.h"
|
#include "engine64/PPSSPP.h"
|
||||||
#include"engine64/Godot.h"
|
#include "engine64/Godot.h"
|
||||||
#include"engine64/V8.h"
|
#include "engine64/V8.h"
|
||||||
#include"engine64/mono.h"
|
#include "engine64/mono.h"
|
||||||
#include"engine64/AGES7.h"
|
#include "engine64/AGES7.h"
|
||||||
#include"engine64/pchooks.h"
|
#include "engine64/pchooks.h"
|
||||||
#include"engine64/Artemis.h"
|
#include "engine64/Artemis.h"
|
||||||
#include"engine64/KiriKiri.h"
|
#include "engine64/KiriKiri.h"
|
||||||
#include"engine64/YOX.h"
|
#include "engine64/YOX.h"
|
||||||
#include"engine64/Suika2.h"
|
#include "engine64/Suika2.h"
|
||||||
#include"engine64/livecaptions.h"
|
#include "engine64/livecaptions.h"
|
||||||
#include"engine64/CMVS.h"
|
#include "engine64/CMVS.h"
|
||||||
#include"engine64/5pb.h"
|
#include "engine64/5pb.h"
|
||||||
#include"engine64/lucasystem.h"
|
#include "engine64/lucasystem.h"
|
||||||
#include"engine64/ENTERGRAM.h"
|
#include "engine64/ENTERGRAM.h"
|
||||||
#include"engine64/TYPEMOON.h"
|
#include "engine64/TYPEMOON.h"
|
||||||
#include"engine64/Kincaid.h"
|
#include "engine64/Kincaid.h"
|
||||||
#include"engine64/LightVN.h"
|
#include "engine64/LightVN.h"
|
||||||
#include"engine64/yuzusuyu.h"
|
#include "engine64/yuzusuyu.h"
|
||||||
#include"engine64/vita3k.h"
|
#include "engine64/vita3k.h"
|
||||||
#include"engine64/rpcs3.h"
|
#include "engine64/rpcs3.h"
|
||||||
#include"engines/lua/lua51.h"
|
#include "engines/lua/lua51.h"
|
||||||
#include"engines/python/Renpy.h"
|
#include "engines/python/Renpy.h"
|
||||||
std::vector<ENGINE*> ignore_engines(){ return{ }; }
|
std::vector<ENGINE *> ignore_engines() { return {}; }
|
||||||
std::vector<ENGINE*> unsafe_check_atlast(){ return{ }; }
|
std::vector<ENGINE *> unsafe_check_atlast() { return {}; }
|
||||||
|
|
||||||
std::vector<ENGINE*> check_engines(){
|
std::vector<ENGINE *> check_engines()
|
||||||
return {
|
{
|
||||||
|
return {
|
||||||
new Godot,
|
new Godot,
|
||||||
new V8,
|
new V8,
|
||||||
new Renpy,
|
new Renpy,
|
||||||
@ -50,5 +51,4 @@ std::vector<ENGINE*> check_engines(){
|
|||||||
new livecaptions,
|
new livecaptions,
|
||||||
new lua51,
|
new lua51,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,137 +1,158 @@
|
|||||||
|
|
||||||
WCHAR* processName, // cached
|
WCHAR *processName, // cached
|
||||||
processPath[MAX_PATH]; // cached
|
processPath[MAX_PATH]; // cached
|
||||||
WCHAR processName_lower[MAX_PATH];
|
WCHAR processName_lower[MAX_PATH];
|
||||||
uintptr_t processStartAddress, processStopAddress;
|
uintptr_t processStartAddress, processStopAddress;
|
||||||
|
|
||||||
|
std::vector<ENGINE *> check_engines();
|
||||||
|
std::vector<ENGINE *> ignore_engines();
|
||||||
|
std::vector<ENGINE *> unsafe_check_atlast();
|
||||||
|
|
||||||
|
bool ENGINE::check_function()
|
||||||
std::vector<ENGINE*> check_engines();
|
{
|
||||||
std::vector<ENGINE*> ignore_engines();
|
|
||||||
std::vector<ENGINE*> unsafe_check_atlast();
|
|
||||||
|
|
||||||
bool ENGINE::check_function(){
|
|
||||||
switch (check_by)
|
switch (check_by)
|
||||||
{
|
{
|
||||||
case CHECK_BY::ALL_TRUE:{
|
case CHECK_BY::ALL_TRUE:
|
||||||
is_engine_certain=false;
|
{
|
||||||
return 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);
|
case CHECK_BY::FILE_ALL:
|
||||||
return std::all_of(_list.begin(),_list.end(),Util::CheckFile);
|
{
|
||||||
|
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);
|
case CHECK_BY::FILE_ANY:
|
||||||
return std::any_of(_list.begin(),_list.end(),Util::CheckFile);
|
{
|
||||||
|
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:{
|
}
|
||||||
return std::get<check_by_custom_function>(check_by_target)();
|
|
||||||
}
|
case CHECK_BY::CUSTOM:
|
||||||
default:
|
{
|
||||||
return false;
|
return std::get<check_by_custom_function>(check_by_target)();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool safematch(ENGINE* m){
|
bool safematch(ENGINE *m)
|
||||||
bool matched=false;
|
{
|
||||||
__try {
|
bool matched = false;
|
||||||
matched=m->check_function();
|
__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;
|
return matched;
|
||||||
}
|
}
|
||||||
bool safeattach(ENGINE* m){
|
bool safeattach(ENGINE *m)
|
||||||
bool attached=false;
|
{
|
||||||
__try {
|
bool attached = false;
|
||||||
attached=m->attach_function();
|
__try
|
||||||
|
{
|
||||||
|
attached = m->attach_function();
|
||||||
}
|
}
|
||||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
ConsoleOutput(Attach_Error,m->getenginename());
|
{
|
||||||
//ConsoleOutput("attach ERROR");
|
ConsoleOutput(Attach_Error, m->getenginename());
|
||||||
|
// ConsoleOutput("attach ERROR");
|
||||||
}
|
}
|
||||||
return attached;
|
return attached;
|
||||||
}
|
}
|
||||||
bool checkengine(){
|
bool checkengine()
|
||||||
|
{
|
||||||
|
|
||||||
auto engines=check_engines();
|
auto engines = check_engines();
|
||||||
auto engineatlast=unsafe_check_atlast();
|
auto engineatlast = unsafe_check_atlast();
|
||||||
auto engineignore=ignore_engines();
|
auto engineignore = ignore_engines();
|
||||||
std::vector<const char*> infomations={
|
std::vector<const char *> infomations = {
|
||||||
"match failed",
|
"match failed",
|
||||||
"attach failed",
|
"attach failed",
|
||||||
"attach success"
|
"attach success"};
|
||||||
};
|
auto allengines = {engines, engineignore, engineatlast};
|
||||||
auto allengines={engines,engineignore,engineatlast};
|
int total = [allengines]()
|
||||||
int total=[allengines](){int _=0;for(auto eng:allengines)_+=eng.size();return _;}();
|
{int _=0;for(auto eng:allengines)_+=eng.size();return _; }();
|
||||||
int current=0;
|
int current = 0;
|
||||||
for(auto eng:allengines){
|
for (auto eng : allengines)
|
||||||
for(auto m:eng) {
|
{
|
||||||
current+=1;
|
for (auto m : eng)
|
||||||
|
{
|
||||||
bool matched=safematch(m);
|
current += 1;
|
||||||
bool attached=matched&&safeattach(m);
|
|
||||||
|
|
||||||
//ConsoleOutput("Progress %d/%d, checked engine %s, %s",current,total,m->getenginename(),infomations[matched+attached]);
|
bool matched = safematch(m);
|
||||||
//ConsoleOutput("Progress %d/%d, %s",current,total,infomations[matched+attached]);
|
bool attached = matched && safeattach(m);
|
||||||
if(matched==false)continue;
|
|
||||||
ConsoleOutput(MatchedEngine,m->getenginename());
|
// ConsoleOutput("Progress %d/%d, checked engine %s, %s",current,total,m->getenginename(),infomations[matched+attached]);
|
||||||
if(m->dontstop){
|
// ConsoleOutput("Progress %d/%d, %s",current,total,infomations[matched+attached]);
|
||||||
|
if (matched == false)
|
||||||
|
continue;
|
||||||
|
ConsoleOutput(MatchedEngine, m->getenginename());
|
||||||
|
if (m->dontstop)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m->is_engine_certain){
|
if (m->is_engine_certain)
|
||||||
ConsoleOutput(ConfirmStop,m->getenginename());
|
{
|
||||||
|
ConsoleOutput(ConfirmStop, m->getenginename());
|
||||||
return attached;
|
return attached;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(attached){
|
if (attached)
|
||||||
ConsoleOutput(Attach_Stop,m->getenginename());
|
{
|
||||||
return true;
|
ConsoleOutput(Attach_Stop, m->getenginename());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
void HIJACK(){
|
void HIJACK()
|
||||||
|
{
|
||||||
static bool once = false;
|
static bool once = false;
|
||||||
if(once)return;
|
if (once)
|
||||||
once=true;
|
return;
|
||||||
|
once = true;
|
||||||
GetModuleFileNameW(nullptr, processPath, MAX_PATH);
|
GetModuleFileNameW(nullptr, processPath, MAX_PATH);
|
||||||
processName = wcsrchr(processPath, L'\\') + 1;
|
processName = wcsrchr(processPath, L'\\') + 1;
|
||||||
|
|
||||||
wcscpy_s(processName_lower, processName);
|
wcscpy_s(processName_lower, processName);
|
||||||
_wcslwr_s(processName_lower); // lower case
|
_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.minAddress = processStartAddress;
|
||||||
spDefault.maxAddress = processStopAddress;
|
spDefault.maxAddress = processStopAddress;
|
||||||
ConsoleOutput(ProcessRange, processStartAddress, processStopAddress);
|
ConsoleOutput(ProcessRange, processStartAddress, processStopAddress);
|
||||||
|
|
||||||
if (processStartAddress + 0x40000 > processStopAddress) ConsoleOutput(WarningDummy);
|
|
||||||
|
|
||||||
bool result=false;
|
if (processStartAddress + 0x40000 > processStopAddress)
|
||||||
__try {
|
ConsoleOutput(WarningDummy);
|
||||||
result = checkengine();
|
|
||||||
|
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();
|
PcHooks::hookOtherPcFunctions();
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
@ -1,11 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
namespace Hijack
|
||||||
|
{
|
||||||
|
|
||||||
namespace Hijack {
|
#define DEF_FUN(_fun, _return, ...) \
|
||||||
|
typedef _return(WINAPI *_fun##_fun_t)(__VA_ARGS__); \
|
||||||
#define DEF_FUN(_fun, _return, ...) \
|
extern _fun##_fun_t old##_fun; \
|
||||||
typedef _return (WINAPI *_fun##_fun_t)(__VA_ARGS__); \
|
|
||||||
extern _fun##_fun_t old##_fun; \
|
|
||||||
_return WINAPI new##_fun(__VA_ARGS__);
|
_return WINAPI new##_fun(__VA_ARGS__);
|
||||||
|
|
||||||
DEF_FUN(MultiByteToWideChar, int, UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar)
|
DEF_FUN(MultiByteToWideChar, int, UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar)
|
||||||
@ -26,8 +26,8 @@ namespace Hijack {
|
|||||||
DEF_FUN(GetTextExtentExPointA, BOOL, HDC hdc, LPCSTR lpszStr, int cchString, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize)
|
DEF_FUN(GetTextExtentExPointA, BOOL, HDC hdc, LPCSTR lpszStr, int cchString, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize)
|
||||||
DEF_FUN(GetTextExtentExPointW, BOOL, HDC hdc, LPCWSTR lpszStr, int cchString, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize)
|
DEF_FUN(GetTextExtentExPointW, BOOL, HDC hdc, LPCWSTR lpszStr, int cchString, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize)
|
||||||
|
|
||||||
DEF_FUN(GetCharABCWidthsA, BOOL, HDC hdc, UINT uFirstChar, UINT uLastChar, LPABC lpabc)
|
DEF_FUN(GetCharABCWidthsA, BOOL, HDC hdc, UINT uFirstChar, UINT uLastChar, LPABC lpabc)
|
||||||
DEF_FUN(GetCharABCWidthsW, BOOL, HDC hdc, UINT uFirstChar, UINT uLastChar, LPABC lpabc)
|
DEF_FUN(GetCharABCWidthsW, BOOL, HDC hdc, UINT uFirstChar, UINT uLastChar, LPABC lpabc)
|
||||||
|
|
||||||
DEF_FUN(TextOutA, BOOL, HDC hdc, int nXStart, int nYStart, LPCSTR lpString, int cchString)
|
DEF_FUN(TextOutA, BOOL, HDC hdc, int nXStart, int nYStart, LPCSTR lpString, int cchString)
|
||||||
DEF_FUN(TextOutW, BOOL, HDC hdc, int nXStart, int nYStart, LPCWSTR lpString, int cchString)
|
DEF_FUN(TextOutW, BOOL, HDC hdc, int nXStart, int nYStart, LPCWSTR lpString, int cchString)
|
||||||
@ -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(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(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(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)
|
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(DrawTextExW, int, HDC hdc, LPWSTR lpString, int nCount, LPRECT lpRect, UINT dwDTFormat, LPDRAWTEXTPARAMS lpDTParams)
|
||||||
|
|
||||||
DEF_FUN(CharNextA, LPSTR, LPCSTR lpString)
|
DEF_FUN(CharNextA, LPSTR, LPCSTR lpString)
|
||||||
//DEF_FUN(CharNextW, LPWSTR, LPCWSTR lpString)
|
// DEF_FUN(CharNextW, LPWSTR, LPCWSTR lpString)
|
||||||
//DEF_FUN(CharNextExA, LPSTR, WORD COdePage, LPCSTR lpString, DWORD dwFlags)
|
// DEF_FUN(CharNextExA, LPSTR, WORD COdePage, LPCSTR lpString, DWORD dwFlags)
|
||||||
//DEF_FUN(CharNextExW, LPWSTR, WORD COdePage, LPCWSTR lpString, DWORD dwFlags)
|
// DEF_FUN(CharNextExW, LPWSTR, WORD COdePage, LPCWSTR lpString, DWORD dwFlags)
|
||||||
DEF_FUN(CharPrevA, LPSTR, LPCSTR lpStart, LPCSTR lpCurrent)
|
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
|
#undef DEF_FUN
|
||||||
|
|
||||||
// Global variables
|
// Global variables
|
||||||
|
|
||||||
} // namespace Hijack
|
} // namespace Hijack
|
||||||
|
|
||||||
|
@ -8,8 +8,8 @@ namespace
|
|||||||
struct HookRecord
|
struct HookRecord
|
||||||
{
|
{
|
||||||
uint64_t address = 0;
|
uint64_t address = 0;
|
||||||
uint64_t em_addr=0;
|
uint64_t em_addr = 0;
|
||||||
int argidx=0;
|
int argidx = 0;
|
||||||
uintptr_t padding = 0;
|
uintptr_t padding = 0;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
JITTYPE jittype;
|
JITTYPE jittype;
|
||||||
@ -23,32 +23,32 @@ namespace
|
|||||||
|
|
||||||
#ifndef _WIN64
|
#ifndef _WIN64
|
||||||
BYTE trampoline[] =
|
BYTE trampoline[] =
|
||||||
{
|
{
|
||||||
0x9c, // pushfd
|
0x9c, // pushfd
|
||||||
0x60, // pushad
|
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]
|
0x8d, 0x44, 0x24, 0x28, // lea eax,[esp+0x28]
|
||||||
0x50, // push eax ; stack
|
0x50, // push eax ; stack
|
||||||
0xbb, 0,0,0,0, // mov ebx,@Send
|
0xbb, 0, 0, 0, 0, // mov ebx,@Send
|
||||||
0xff, 0xd3, // call ebx
|
0xff, 0xd3, // call ebx
|
||||||
0x83, 0xc4, 0x08, // add esp, 0x8 ; doesn't matter which register
|
0x83, 0xc4, 0x08, // add esp, 0x8 ; doesn't matter which register
|
||||||
0x61, // popad
|
0x61, // popad
|
||||||
0x9d, // popfd
|
0x9d, // popfd
|
||||||
0x68, 0,0,0,0, // push @original
|
0x68, 0, 0, 0, 0, // push @original
|
||||||
0xc3 // ret ; basically absolute jmp to @original
|
0xc3 // ret ; basically absolute jmp to @original
|
||||||
};
|
};
|
||||||
constexpr int addr_offset = 3, send_offset = 13, original_offset = 25, registers = 8;
|
constexpr int addr_offset = 3, send_offset = 13, original_offset = 25, registers = 8;
|
||||||
#else
|
#else
|
||||||
BYTE trampoline[] = {
|
BYTE trampoline[] = {
|
||||||
0x9c, // push rflags
|
0x9c, // push rflags
|
||||||
0x50, // push rax
|
0x50, // push rax
|
||||||
0x53, // push rbx
|
0x53, // push rbx
|
||||||
0x51, // push rcx
|
0x51, // push rcx
|
||||||
0x52, // push rdx
|
0x52, // push rdx
|
||||||
0x54, // push rsp
|
0x54, // push rsp
|
||||||
0x55, // push rbp
|
0x55, // push rbp
|
||||||
0x56, // push rsi
|
0x56, // push rsi
|
||||||
0x57, // push rdi
|
0x57, // push rdi
|
||||||
0x41, 0x50, // push r8
|
0x41, 0x50, // push r8
|
||||||
0x41, 0x51, // push r9
|
0x41, 0x51, // push r9
|
||||||
0x41, 0x52, // push r10
|
0x41, 0x52, // push r10
|
||||||
@ -59,54 +59,57 @@ namespace
|
|||||||
0x41, 0x57, // push r15
|
0x41, 0x57, // push r15
|
||||||
// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
|
// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
|
||||||
// https://stackoverflow.com/questions/43358429/save-value-of-xmm-registers
|
// https://stackoverflow.com/questions/43358429/save-value-of-xmm-registers
|
||||||
0x48, 0x83, 0xec, 0x20, // sub rsp,0x20
|
0x48, 0x83, 0xec, 0x20, // sub rsp,0x20
|
||||||
0xf3, 0x0f, 0x7f, 0x24, 0x24, // movdqu [rsp],xmm4
|
0xf3, 0x0f, 0x7f, 0x24, 0x24, // movdqu [rsp],xmm4
|
||||||
0xf3, 0x0f, 0x7f, 0x6c, 0x24, 0x10, // movdqu [rsp+0x10],xmm5
|
0xf3, 0x0f, 0x7f, 0x6c, 0x24, 0x10, // movdqu [rsp+0x10],xmm5
|
||||||
0x48, 0x8d, 0x8c, 0x24, 0xa8, 0x00, 0x00, 0x00, // lea rcx,[rsp+0xa8]
|
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, 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, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, // mov rax,@Send
|
||||||
0x48, 0x89, 0xe3, // mov rbx,rsp
|
0x48, 0x89, 0xe3, // mov rbx,rsp
|
||||||
0x48, 0x83, 0xe4, 0xf0, // and rsp,0xfffffffffffffff0 ; align stack
|
0x48, 0x83, 0xe4, 0xf0, // and rsp,0xfffffffffffffff0 ; align stack
|
||||||
0xff, 0xd0, // call rax
|
0xff, 0xd0, // call rax
|
||||||
0x48, 0x89, 0xdc, // mov rsp,rbx
|
0x48, 0x89, 0xdc, // mov rsp,rbx
|
||||||
0xf3, 0x0f, 0x6f, 0x6c, 0x24, 0x10, // movdqu xmm5,XMMWORD PTR[rsp + 0x10]
|
0xf3, 0x0f, 0x6f, 0x6c, 0x24, 0x10, // movdqu xmm5,XMMWORD PTR[rsp + 0x10]
|
||||||
0xf3, 0x0f, 0x6f, 0x24, 0x24, // movdqu xmm4,XMMWORD PTR[rsp]
|
0xf3, 0x0f, 0x6f, 0x24, 0x24, // movdqu xmm4,XMMWORD PTR[rsp]
|
||||||
0x48, 0x83, 0xc4, 0x20, // add rsp,0x20
|
0x48, 0x83, 0xc4, 0x20, // add rsp,0x20
|
||||||
0x41, 0x5f, // pop r15
|
0x41, 0x5f, // pop r15
|
||||||
0x41, 0x5e, // pop r14
|
0x41, 0x5e, // pop r14
|
||||||
0x41, 0x5d, // pop r13
|
0x41, 0x5d, // pop r13
|
||||||
0x41, 0x5c, // pop r12
|
0x41, 0x5c, // pop r12
|
||||||
0x41, 0x5b, // pop r11
|
0x41, 0x5b, // pop r11
|
||||||
0x41, 0x5a, // pop r10
|
0x41, 0x5a, // pop r10
|
||||||
0x41, 0x59, // pop r9
|
0x41, 0x59, // pop r9
|
||||||
0x41, 0x58, // pop r8
|
0x41, 0x58, // pop r8
|
||||||
0x5f, // pop rdi
|
0x5f, // pop rdi
|
||||||
0x5e, // pop rsi
|
0x5e, // pop rsi
|
||||||
0x5d, // pop rbp
|
0x5d, // pop rbp
|
||||||
0x5c, // pop rsp
|
0x5c, // pop rsp
|
||||||
0x5a, // pop rdx
|
0x5a, // pop rdx
|
||||||
0x59, // pop rcx
|
0x59, // pop rcx
|
||||||
0x5b, // pop rbx
|
0x5b, // pop rbx
|
||||||
0x58, // pop rax
|
0x58, // pop rax
|
||||||
0x9d, // pop rflags
|
0x9d, // pop rflags
|
||||||
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip]
|
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;
|
constexpr int addr_offset = 50, send_offset = 60, original_offset = 126, registers = 16;
|
||||||
#endif
|
#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;
|
uintptr_t BAD_PAGE = (uintptr_t)data >> 12;
|
||||||
auto& cacheEntry = pageCache[BAD_PAGE % CACHE_SIZE];
|
auto &cacheEntry = pageCache[BAD_PAGE % CACHE_SIZE];
|
||||||
if (cacheEntry == BAD_PAGE) return true;
|
if (cacheEntry == BAD_PAGE)
|
||||||
if (cacheEntry == GOOD_PAGE) return false;
|
return true;
|
||||||
|
if (cacheEntry == GOOD_PAGE)
|
||||||
|
return false;
|
||||||
|
|
||||||
__try
|
__try
|
||||||
{
|
{
|
||||||
volatile char _ = *(char*)data;
|
volatile char _ = *(char *)data;
|
||||||
cacheEntry = GOOD_PAGE;
|
cacheEntry = GOOD_PAGE;
|
||||||
}
|
}
|
||||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
@ -121,40 +124,45 @@ bool IsBadReadPtr(void* data)
|
|||||||
}
|
}
|
||||||
return cacheEntry == BAD_PAGE;
|
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;
|
str += padding;
|
||||||
if (IsBadReadPtr(str) || IsBadReadPtr(str + MAX_STRING_SIZE)) return;
|
if (IsBadReadPtr(str) || IsBadReadPtr(str + MAX_STRING_SIZE))
|
||||||
|
return;
|
||||||
__try
|
__try
|
||||||
{
|
{
|
||||||
int length = 0, sum = 0;
|
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)
|
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
|
// 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;
|
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;
|
signatureCache[signature % CACHE_SIZE] = signature;
|
||||||
// if there are huge amount of strings that are the same, it's probably garbage: filter them out
|
// 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
|
// 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);
|
long n = sp.maxRecords - _InterlockedDecrement(&recordsAvailable);
|
||||||
if (n < sp.maxRecords)
|
if (n < sp.maxRecords)
|
||||||
{
|
{
|
||||||
records[n].jittype = jittype;
|
records[n].jittype = jittype;
|
||||||
records[n].padding = padding;
|
records[n].padding = padding;
|
||||||
if(jittype==JITTYPE::PC)
|
if (jittype == JITTYPE::PC)
|
||||||
{
|
{
|
||||||
records[n].address = address;
|
records[n].address = address;
|
||||||
records[n].offset = i * sizeof(char*);
|
records[n].offset = i * sizeof(char *);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
records[n].em_addr=em_addr;
|
records[n].em_addr = em_addr;
|
||||||
records[n].argidx=i;
|
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;
|
records[n].text[length] = 0;
|
||||||
}
|
}
|
||||||
if (n == sp.maxRecords)
|
if (n == sp.maxRecords)
|
||||||
@ -164,127 +172,157 @@ 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)
|
// 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
|
// the exceptions are compiler intrinsics like _InterlockedDecrement
|
||||||
if (recordsAvailable <= 0) return;
|
if (recordsAvailable <= 0)
|
||||||
for (int i = -registers; i < 10; ++i) for (auto padding : { uintptr_t{}, sp.padding })
|
return;
|
||||||
{
|
for (int i = -registers; i < 10; ++i)
|
||||||
DoSend(i,address,stack[i],padding);
|
for (auto padding : {uintptr_t{}, sp.padding})
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
void SafeSendJitVeh(hook_stack* stack,uintptr_t address,uintptr_t em_addr,JITTYPE jittype){
|
|
||||||
__try
|
|
||||||
{
|
|
||||||
for (int i = 0;i<16;i++)
|
|
||||||
{
|
{
|
||||||
char* str=0;
|
DoSend(i, address, stack[i], padding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SafeSendJitVeh(hook_stack *stack, uintptr_t address, uintptr_t em_addr, JITTYPE jittype)
|
||||||
|
{
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
char *str = 0;
|
||||||
switch (jittype)
|
switch (jittype)
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
case JITTYPE::YUZU:
|
case JITTYPE::YUZU:
|
||||||
str=(char*)YUZU::emu_arg(stack)[i];
|
str = (char *)YUZU::emu_arg(stack)[i];
|
||||||
break;
|
break;
|
||||||
case JITTYPE::VITA3K:
|
case JITTYPE::VITA3K:
|
||||||
str=(char*)VITA3K::emu_arg(stack)[i];
|
str = (char *)VITA3K::emu_arg(stack)[i];
|
||||||
break;
|
break;
|
||||||
case JITTYPE::RPCS3:
|
case JITTYPE::RPCS3:
|
||||||
str=(char*)RPCS3::emu_arg(stack)[i];
|
str = (char *)RPCS3::emu_arg(stack)[i];
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case JITTYPE::PPSSPP:
|
case JITTYPE::PPSSPP:
|
||||||
str=(char*)PPSSPP::emu_arg(stack)[i];
|
str = (char *)PPSSPP::emu_arg(stack)[i];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
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;
|
std::unordered_map<uintptr_t, uint64_t> addresscalledtime;
|
||||||
bool safeautoleaveveh=false;
|
bool safeautoleaveveh = false;
|
||||||
bool SendJitVeh(PCONTEXT context,uintptr_t address,uintptr_t em_addr,JITTYPE jittype){
|
bool SendJitVeh(PCONTEXT context, uintptr_t address, uintptr_t em_addr, JITTYPE jittype)
|
||||||
if(safeautoleaveveh)return true;
|
{
|
||||||
if (recordsAvailable <= 0) return false;
|
if (safeautoleaveveh)
|
||||||
if(addresscalledtime.find(address)==addresscalledtime.end())addresscalledtime[address]=0;
|
return true;
|
||||||
auto tm=GetTickCount64();
|
if (recordsAvailable <= 0)
|
||||||
if(tm-addresscalledtime[address]<100)return false;
|
return false;
|
||||||
addresscalledtime[address]=tm;
|
if (addresscalledtime.find(address) == addresscalledtime.end())
|
||||||
auto stack=std::make_unique<hook_stack>();
|
addresscalledtime[address] = 0;
|
||||||
context_get(stack.get(),context);
|
auto tm = GetTickCount64();
|
||||||
SafeSendJitVeh(stack.get(),address,em_addr,jittype);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
std::vector<uintptr_t> GetFunctions(uintptr_t module)
|
std::vector<uintptr_t> GetFunctions(uintptr_t module)
|
||||||
{
|
{
|
||||||
if (!module) return {};
|
if (!module)
|
||||||
IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)module;
|
return {};
|
||||||
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) return {};
|
IMAGE_DOS_HEADER *dosHeader = (IMAGE_DOS_HEADER *)module;
|
||||||
IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)(module + dosHeader->e_lfanew);
|
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
|
||||||
if (ntHeader->Signature != IMAGE_NT_SIGNATURE) return {};
|
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;
|
DWORD exportAddress = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||||
if (!exportAddress) return {};
|
if (!exportAddress)
|
||||||
IMAGE_EXPORT_DIRECTORY* exportDirectory = (IMAGE_EXPORT_DIRECTORY*)(module + exportAddress);
|
return {};
|
||||||
|
IMAGE_EXPORT_DIRECTORY *exportDirectory = (IMAGE_EXPORT_DIRECTORY *)(module + exportAddress);
|
||||||
std::vector<uintptr_t> functions;
|
std::vector<uintptr_t> functions;
|
||||||
for (int i = 0; i < exportDirectory->NumberOfNames; ++i)
|
for (int i = 0; i < exportDirectory->NumberOfNames; ++i)
|
||||||
//char* funcName = (char*)(module + *(DWORD*)(module + exportDirectory->AddressOfNames + i * sizeof(DWORD)));
|
// char* funcName = (char*)(module + *(DWORD*)(module + exportDirectory->AddressOfNames + i * sizeof(DWORD)));
|
||||||
functions.push_back(module + *(DWORD*)(module + exportDirectory->AddressOfFunctions +
|
functions.push_back(module + *(DWORD *)(module + exportDirectory->AddressOfFunctions +
|
||||||
sizeof(DWORD) * *(WORD*)(module + exportDirectory->AddressOfNameOrdinals + i * sizeof(WORD))));
|
sizeof(DWORD) * *(WORD *)(module + exportDirectory->AddressOfNameOrdinals + i * sizeof(WORD))));
|
||||||
return functions;
|
return functions;
|
||||||
}
|
}
|
||||||
void mergevector(std::vector<uintptr_t> &v1,std::vector<uintptr_t> &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);
|
for (auto addr : v2)
|
||||||
if (it == v1.end()) {
|
{
|
||||||
|
auto it = std::find(v1.begin(), v1.end(), addr);
|
||||||
|
if (it == v1.end())
|
||||||
|
{
|
||||||
v1.push_back(addr);
|
v1.push_back(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void SearchForHooks_Return(){
|
void SearchForHooks_Return()
|
||||||
|
{
|
||||||
ConsoleOutput(HOOK_SEARCH_FINISHED, sp.maxRecords - recordsAvailable);
|
ConsoleOutput(HOOK_SEARCH_FINISHED, sp.maxRecords - recordsAvailable);
|
||||||
for (int i = 0, results = 0; i < sp.maxRecords; ++i)
|
for (int i = 0, results = 0; i < sp.maxRecords; ++i)
|
||||||
{
|
{
|
||||||
HookParam hp;
|
HookParam hp;
|
||||||
hp.codepage = sp.codepage;
|
hp.codepage = sp.codepage;
|
||||||
hp.jittype=records[i].jittype;
|
hp.jittype = records[i].jittype;
|
||||||
hp.padding = records[i].padding;
|
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.offset = records[i].offset;
|
||||||
hp.type = CODEC_UTF16 | USING_STRING;
|
hp.type = CODEC_UTF16 | USING_STRING;
|
||||||
hp.address = records[i].address;
|
hp.address = records[i].address;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!records[i].em_addr) continue;
|
if (!records[i].em_addr)
|
||||||
hp.emu_addr=records[i].em_addr;
|
continue;
|
||||||
hp.type = CODEC_UTF16 | USING_STRING|BREAK_POINT;
|
hp.emu_addr = records[i].em_addr;
|
||||||
hp.argidx=records[i].argidx;
|
hp.type = CODEC_UTF16 | USING_STRING | BREAK_POINT;
|
||||||
|
hp.argidx = records[i].argidx;
|
||||||
}
|
}
|
||||||
NotifyHookFound(hp, (wchar_t*)records[i].text);
|
NotifyHookFound(hp, (wchar_t *)records[i].text);
|
||||||
if (++results % 100'000 == 0) ConsoleOutput(ResultsNum, results);
|
if (++results % 100'000 == 0)
|
||||||
|
ConsoleOutput(ResultsNum, results);
|
||||||
}
|
}
|
||||||
records.reset();
|
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
|
do
|
||||||
try { records = std::make_unique<HookRecord[]>(recordsAvailable = sp.maxRecords); }
|
try
|
||||||
catch (std::bad_alloc) { ConsoleOutput(SearchForHooks_ERROR, sp.maxRecords /= 2); }
|
{
|
||||||
|
records = std::make_unique<HookRecord[]>(recordsAvailable = sp.maxRecords);
|
||||||
|
}
|
||||||
|
catch (std::bad_alloc)
|
||||||
|
{
|
||||||
|
ConsoleOutput(SearchForHooks_ERROR, sp.maxRecords /= 2);
|
||||||
|
}
|
||||||
while (!records && sp.maxRecords);
|
while (!records && sp.maxRecords);
|
||||||
|
|
||||||
}
|
}
|
||||||
void SearchForHooks(SearchParam spUser)
|
void SearchForHooks(SearchParam spUser)
|
||||||
{
|
{
|
||||||
std::thread([=]
|
std::thread([=]
|
||||||
{
|
{
|
||||||
static std::mutex m;
|
static std::mutex m;
|
||||||
std::scoped_lock lock(m);
|
std::scoped_lock lock(m);
|
||||||
*(void**)(trampoline + send_offset) = Send;
|
*(void**)(trampoline + send_offset) = Send;
|
||||||
@ -421,27 +459,28 @@ void SearchForHooks(SearchParam spUser)
|
|||||||
// }
|
// }
|
||||||
safeautoleaveveh=true;
|
safeautoleaveveh=true;
|
||||||
SearchForHooks_Return();
|
SearchForHooks_Return();
|
||||||
}
|
} })
|
||||||
}).detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchForText(wchar_t* text, UINT codepage)
|
void SearchForText(wchar_t *text, UINT codepage)
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
char utf8Text[PATTERN_SIZE * 4] = {};
|
char utf8Text[PATTERN_SIZE * 4] = {};
|
||||||
WideCharToMultiByte(CP_UTF8, 0, text, PATTERN_SIZE, utf8Text, PATTERN_SIZE * 4, nullptr, nullptr);
|
WideCharToMultiByte(CP_UTF8, 0, text, PATTERN_SIZE, utf8Text, PATTERN_SIZE * 4, nullptr, nullptr);
|
||||||
char codepageText[PATTERN_SIZE * 4] = {};
|
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);
|
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)
|
||||||
if (strlen(utf8Text) < 4 || ((codepage!=CP_UTF8)&&(strlen(codepageText) < 4)) || wcslen(text) < 4) return ConsoleOutput(NOT_ENOUGH_TEXT);
|
return ConsoleOutput(NOT_ENOUGH_TEXT);
|
||||||
ConsoleOutput(HOOK_SEARCH_STARTING);
|
ConsoleOutput(HOOK_SEARCH_STARTING);
|
||||||
auto GenerateHooks = [&](std::vector<uintptr_t> addresses, HookParamType type)
|
auto GenerateHooks = [&](std::vector<uintptr_t> addresses, HookParamType type)
|
||||||
{
|
{
|
||||||
for (auto addr : addresses)
|
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;
|
found = true;
|
||||||
HookParam hp;
|
HookParam hp;
|
||||||
hp.type = DIRECT_READ | type;
|
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);
|
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(codepageText, strlen(codepageText), PAGE_READWRITE), USING_STRING);
|
||||||
GenerateHooks(Util::SearchMemory(text, wcslen(text) * sizeof(wchar_t), PAGE_READWRITE), CODEC_UTF16);
|
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);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
void SearchForText(wchar_t* text, UINT codepage);
|
void SearchForText(wchar_t *text, UINT codepage);
|
||||||
void SearchForHooks(SearchParam sp);
|
void SearchForHooks(SearchParam sp);
|
||||||
|
365
LunaHook/main.cc
365
LunaHook/main.cc
@ -7,10 +7,10 @@ WinMutex viewMutex;
|
|||||||
EmbedSharedMem *embedsharedmem;
|
EmbedSharedMem *embedsharedmem;
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
AutoHandle<> hookPipe = INVALID_HANDLE_VALUE,
|
AutoHandle<> hookPipe = INVALID_HANDLE_VALUE,
|
||||||
mappedFile = INVALID_HANDLE_VALUE,
|
mappedFile = INVALID_HANDLE_VALUE,
|
||||||
mappedFile3=INVALID_HANDLE_VALUE;
|
mappedFile3 = INVALID_HANDLE_VALUE;
|
||||||
TextHook(*hooks)[MAX_HOOK];
|
TextHook (*hooks)[MAX_HOOK];
|
||||||
int currentHook = 0;
|
int currentHook = 0;
|
||||||
}
|
}
|
||||||
DWORD WINAPI Pipe(LPVOID)
|
DWORD WINAPI Pipe(LPVOID)
|
||||||
@ -20,45 +20,47 @@ DWORD WINAPI Pipe(LPVOID)
|
|||||||
DWORD count = 0;
|
DWORD count = 0;
|
||||||
BYTE buffer[PIPE_BUFFER_SIZE] = {};
|
BYTE buffer[PIPE_BUFFER_SIZE] = {};
|
||||||
AutoHandle<> hostPipe = INVALID_HANDLE_VALUE;
|
AutoHandle<> hostPipe = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
while (!hostPipe || !hookPipe)
|
while (!hostPipe || !hookPipe)
|
||||||
{
|
{
|
||||||
// WinMutex connectionMutex(CONNECTING_MUTEX, &allAccess);
|
// WinMutex connectionMutex(CONNECTING_MUTEX, &allAccess);
|
||||||
// std::scoped_lock lock(connectionMutex);
|
// std::scoped_lock lock(connectionMutex);
|
||||||
WaitForSingleObject(AutoHandle<>(CreateEventW(&allAccess, FALSE, FALSE, (std::wstring(PIPE_AVAILABLE_EVENT)+std::to_wstring(GetCurrentProcessId())).c_str())), INFINITE);
|
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);
|
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);
|
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;
|
DWORD mode = PIPE_READMODE_MESSAGE;
|
||||||
SetNamedPipeHandleState(hostPipe, &mode, NULL, NULL);
|
SetNamedPipeHandleState(hostPipe, &mode, NULL, NULL);
|
||||||
|
|
||||||
*(DWORD*)buffer = GetCurrentProcessId();
|
*(DWORD *)buffer = GetCurrentProcessId();
|
||||||
WriteFile(hookPipe, buffer, sizeof(DWORD), &count, nullptr);
|
WriteFile(hookPipe, buffer, sizeof(DWORD), &count, nullptr);
|
||||||
|
|
||||||
ConsoleOutput(PIPE_CONNECTED);
|
ConsoleOutput(PIPE_CONNECTED);
|
||||||
HIJACK();
|
HIJACK();
|
||||||
host_connected=true;
|
host_connected = true;
|
||||||
while (running && ReadFile(hostPipe, buffer, PIPE_BUFFER_SIZE, &count, nullptr))
|
while (running && ReadFile(hostPipe, buffer, PIPE_BUFFER_SIZE, &count, nullptr))
|
||||||
switch (*(HostCommandType*)buffer)
|
switch (*(HostCommandType *)buffer)
|
||||||
{
|
{
|
||||||
case HOST_COMMAND_NEW_HOOK:
|
case HOST_COMMAND_NEW_HOOK:
|
||||||
{
|
{
|
||||||
auto info = *(InsertHookCmd*)buffer;
|
auto info = *(InsertHookCmd *)buffer;
|
||||||
static int userHooks = 0;
|
static int userHooks = 0;
|
||||||
NewHook(info.hp, ("UserHook" + std::to_string(userHooks += 1)).c_str());
|
NewHook(info.hp, ("UserHook" + std::to_string(userHooks += 1)).c_str());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HOST_COMMAND_REMOVE_HOOK:
|
case HOST_COMMAND_REMOVE_HOOK:
|
||||||
{
|
{
|
||||||
auto info = *(RemoveHookCmd*)buffer;
|
auto info = *(RemoveHookCmd *)buffer;
|
||||||
RemoveHook(info.address, 0);
|
RemoveHook(info.address, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HOST_COMMAND_FIND_HOOK:
|
case HOST_COMMAND_FIND_HOOK:
|
||||||
{
|
{
|
||||||
auto info = *(FindHookCmd*)buffer;
|
auto info = *(FindHookCmd *)buffer;
|
||||||
if (*info.sp.text) SearchForText(info.sp.text, info.sp.codepage);
|
if (*info.sp.text)
|
||||||
else SearchForHooks(info.sp);
|
SearchForText(info.sp.text, info.sp.codepage);
|
||||||
|
else
|
||||||
|
SearchForHooks(info.sp);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HOST_COMMAND_DETACH:
|
case HOST_COMMAND_DETACH:
|
||||||
@ -69,21 +71,25 @@ DWORD WINAPI Pipe(LPVOID)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dont_detach){
|
if (dont_detach)
|
||||||
host_connected=false;
|
{
|
||||||
|
host_connected = false;
|
||||||
return Pipe(0);
|
return Pipe(0);
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
MH_Uninitialize();
|
MH_Uninitialize();
|
||||||
for (auto& hook : *hooks) hook.Clear();
|
for (auto &hook : *hooks)
|
||||||
|
hook.Clear();
|
||||||
FreeLibraryAndExitThread(GetModuleHandleW(LUNA_HOOK_DLL), 0);
|
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->tp, &tp, sizeof(tp));
|
||||||
memcpy(&buffer->hp,&hp,sizeof(hp));
|
memcpy(&buffer->hp, &hp, sizeof(hp));
|
||||||
WriteFile(hookPipe, buffer, sizeof(TextOutput_T) + len, DUMMY, nullptr);
|
WriteFile(hookPipe, buffer, sizeof(TextOutput_T) + len, DUMMY, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,229 +102,248 @@ void ConsoleOutput(LPCSTR text, ...)
|
|||||||
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
|
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);
|
HookFoundNotif buffer(hp, text);
|
||||||
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
|
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
|
||||||
}
|
}
|
||||||
void NotifyHookRemove(uint64_t addr, LPCSTR name)
|
void NotifyHookRemove(uint64_t addr, LPCSTR name)
|
||||||
{
|
{
|
||||||
if (name) ConsoleOutput(REMOVING_HOOK, name);
|
if (name)
|
||||||
|
ConsoleOutput(REMOVING_HOOK, name);
|
||||||
HookRemovedNotif buffer(addr);
|
HookRemovedNotif buffer(addr);
|
||||||
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
|
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);
|
HookInsertingNotif buffer(addr);
|
||||||
wcscpy(buffer.hookcode,hookcode);
|
wcscpy(buffer.hookcode, hookcode);
|
||||||
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
|
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
|
||||||
}
|
}
|
||||||
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID)
|
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID)
|
||||||
{
|
{
|
||||||
switch (fdwReason)
|
switch (fdwReason)
|
||||||
{
|
{
|
||||||
case DLL_PROCESS_ATTACH:
|
case DLL_PROCESS_ATTACH:
|
||||||
{
|
{
|
||||||
hLUNAHOOKDLL=hModule;
|
hLUNAHOOKDLL = hModule;
|
||||||
viewMutex = WinMutex(ITH_HOOKMAN_MUTEX_ + std::to_wstring(GetCurrentProcessId()), &allAccess);
|
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);
|
DisableThreadLibraryCalls(hModule);
|
||||||
|
|
||||||
auto createfm=[](AutoHandle<> &handle,void**ptr,DWORD sz,std::wstring&name ){
|
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);
|
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);
|
memset(*ptr, 0, sz);
|
||||||
};
|
};
|
||||||
hooks=(decltype(hooks))new TextHook[MAX_HOOK];
|
hooks = (decltype(hooks))new TextHook[MAX_HOOK];
|
||||||
VirtualProtect((LPVOID)hooks,sizeof(TextHook) *MAX_HOOK,PAGE_EXECUTE_READWRITE,DUMMY);
|
VirtualProtect((LPVOID)hooks, sizeof(TextHook) * MAX_HOOK, PAGE_EXECUTE_READWRITE, DUMMY);
|
||||||
createfm(mappedFile3,(void**)&embedsharedmem, sizeof(EmbedSharedMem),EMBED_SHARED_MEM + std::to_wstring(GetCurrentProcessId()));
|
createfm(mappedFile3, (void **)&embedsharedmem, sizeof(EmbedSharedMem), EMBED_SHARED_MEM + std::to_wstring(GetCurrentProcessId()));
|
||||||
|
|
||||||
MH_Initialize();
|
MH_Initialize();
|
||||||
|
|
||||||
CloseHandle(CreateThread(nullptr, 0, Pipe, nullptr, 0, nullptr)); // Using std::thread here = deadlock
|
CloseHandle(CreateThread(nullptr, 0, Pipe, nullptr, 0, nullptr)); // Using std::thread here = deadlock
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
{
|
{
|
||||||
MH_Uninitialize();
|
MH_Uninitialize();
|
||||||
detachall( );
|
detachall();
|
||||||
delete []hooks;
|
delete[] hooks;
|
||||||
UnmapViewOfFile(embedsharedmem);
|
UnmapViewOfFile(embedsharedmem);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
int HookStrLen(HookParam* hp,BYTE* data){
|
int HookStrLen(HookParam *hp, BYTE *data)
|
||||||
if(data==0)return 0;
|
{
|
||||||
|
if (data == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if(hp->type&CODEC_UTF16)
|
if (hp->type & CODEC_UTF16)
|
||||||
return wcsnlen((wchar_t*)data,TEXT_BUFFER_SIZE)*2;
|
return wcsnlen((wchar_t *)data, TEXT_BUFFER_SIZE) * 2;
|
||||||
else if(hp->type&CODEC_UTF32)
|
else if (hp->type & CODEC_UTF32)
|
||||||
return u32strlen((uint32_t*)data)*4;
|
return u32strlen((uint32_t *)data) * 4;
|
||||||
else
|
else
|
||||||
return strnlen((char*)data,TEXT_BUFFER_SIZE);
|
return strnlen((char *)data, TEXT_BUFFER_SIZE);
|
||||||
|
|
||||||
}
|
}
|
||||||
static std::mutex maplock;
|
static std::mutex maplock;
|
||||||
void jitaddraddr(uintptr_t em_addr,uintptr_t jitaddr,JITTYPE jittype){
|
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)
|
|
||||||
{
|
{
|
||||||
if(hp.emu_addr)
|
std::lock_guard _(maplock);
|
||||||
ConsoleOutput("%p => %p",hp.emu_addr,hp.address);
|
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);
|
ConsoleOutput(TOO_MANY_HOOKS);
|
||||||
return false;
|
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))
|
if (!(*hooks)[currentHook].Insert(hp))
|
||||||
{
|
{
|
||||||
ConsoleOutput(InsertHookFailed,WideStringToString(hp.hookcode).c_str());
|
ConsoleOutput(InsertHookFailed, WideStringToString(hp.hookcode).c_str());
|
||||||
(*hooks)[currentHook].Clear();
|
(*hooks)[currentHook].Clear();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
NotifyHookInserting(hp.address,hp.hookcode);
|
{
|
||||||
|
NotifyHookInserting(hp.address, hp.hookcode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static std::mutex delayinsertlock;
|
static std::mutex delayinsertlock;
|
||||||
void delayinsertadd(HookParam hp,std::string name){
|
void delayinsertadd(HookParam hp, std::string name)
|
||||||
|
{
|
||||||
std::lock_guard _(maplock);
|
std::lock_guard _(maplock);
|
||||||
delayinserthook[hp.emu_addr]={name,hp};
|
delayinserthook[hp.emu_addr] = {name, hp};
|
||||||
ConsoleOutput(INSERTING_HOOK, name.c_str(),hp.emu_addr);
|
ConsoleOutput(INSERTING_HOOK, name.c_str(), hp.emu_addr);
|
||||||
}
|
}
|
||||||
void delayinsertNewHook(uintptr_t em_address){
|
void delayinsertNewHook(uintptr_t em_address)
|
||||||
if(delayinserthook.find(em_address)==delayinserthook.end())return;
|
{
|
||||||
|
if (delayinserthook.find(em_address) == delayinserthook.end())
|
||||||
|
return;
|
||||||
std::lock_guard _(maplock);
|
std::lock_guard _(maplock);
|
||||||
auto h=delayinserthook[em_address];
|
auto h = delayinserthook[em_address];
|
||||||
delayinserthook.erase(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){
|
bool NewHook(HookParam hp, LPCSTR name)
|
||||||
if(hp.address||hp.jittype==JITTYPE::PC)
|
{
|
||||||
return NewHook_1(hp,name);
|
if (hp.address || hp.jittype == JITTYPE::PC)
|
||||||
if(hp.jittype==JITTYPE::UNITY){
|
return NewHook_1(hp, name);
|
||||||
auto spls=strSplit(hp.unityfunctioninfo,":");
|
if (hp.jittype == JITTYPE::UNITY)
|
||||||
if(spls.size()!=5){
|
{
|
||||||
|
auto spls = strSplit(hp.unityfunctioninfo, ":");
|
||||||
|
if (spls.size() != 5)
|
||||||
|
{
|
||||||
ConsoleOutput("invalid");
|
ConsoleOutput("invalid");
|
||||||
return false;
|
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");
|
ConsoleOutput("not find");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return NewHook_1(hp,name);
|
return NewHook_1(hp, name);
|
||||||
}
|
}
|
||||||
//下面的是手动插入
|
// 下面的是手动插入
|
||||||
if(emuaddr2jitaddr.find(hp.emu_addr)==emuaddr2jitaddr.end()){
|
if (emuaddr2jitaddr.find(hp.emu_addr) == emuaddr2jitaddr.end())
|
||||||
delayinsertadd(hp,name);
|
{
|
||||||
|
delayinsertadd(hp, name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
strcpy(hp.function,"");
|
strcpy(hp.function, "");
|
||||||
wcscpy(hp.module,L"");
|
wcscpy(hp.module, L"");
|
||||||
hp.type &= ~MODULE_OFFSET;
|
hp.type &= ~MODULE_OFFSET;
|
||||||
|
|
||||||
hp.address=emuaddr2jitaddr[hp.emu_addr].second;
|
hp.address = emuaddr2jitaddr[hp.emu_addr].second;
|
||||||
hp.jittype=emuaddr2jitaddr[hp.emu_addr].first;
|
hp.jittype = emuaddr2jitaddr[hp.emu_addr].first;
|
||||||
return NewHook_1(hp,name);
|
return NewHook_1(hp, name);
|
||||||
}
|
}
|
||||||
void RemoveHook(uint64_t addr, int maxOffset)
|
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;
|
HMODULE hModule = hLUNAHOOKDLL;
|
||||||
HRSRC hRsrc = ::FindResourceW (hModule, pszResID,_type);
|
HRSRC hRsrc = ::FindResourceW(hModule, pszResID, _type);
|
||||||
if (!hRsrc)
|
if (!hRsrc)
|
||||||
return "";
|
return "";
|
||||||
DWORD len = SizeofResource(hModule, hRsrc);
|
DWORD len = SizeofResource(hModule, hRsrc);
|
||||||
BYTE* lpRsrc = (BYTE*)LoadResource(hModule, hRsrc);
|
BYTE *lpRsrc = (BYTE *)LoadResource(hModule, hRsrc);
|
||||||
if (!lpRsrc)
|
if (!lpRsrc)
|
||||||
return "";
|
return "";
|
||||||
HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
|
HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
|
||||||
BYTE* pmem = (BYTE*)GlobalLock(m_hMem);
|
BYTE *pmem = (BYTE *)GlobalLock(m_hMem);
|
||||||
memcpy(pmem,lpRsrc,len);
|
memcpy(pmem, lpRsrc, len);
|
||||||
auto data=std::string((char*)pmem,len);
|
auto data = std::string((char *)pmem, len);
|
||||||
GlobalUnlock(m_hMem);
|
GlobalUnlock(m_hMem);
|
||||||
GlobalFree(m_hMem);
|
GlobalFree(m_hMem);
|
||||||
FreeResource(lpRsrc);
|
FreeResource(lpRsrc);
|
||||||
return data;
|
return data;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void context_get(hook_stack* stack,PCONTEXT context){
|
|
||||||
#ifndef _WIN64
|
|
||||||
stack->eax=context->Eax;
|
|
||||||
stack->ecx=context->Ecx;
|
|
||||||
stack->edx=context->Edx;
|
|
||||||
stack->ebx=context->Ebx;
|
|
||||||
stack->esp=context->Esp;
|
|
||||||
stack->ebp=context->Ebp;
|
|
||||||
stack->esi=context->Esi;
|
|
||||||
stack->edi=context->Edi;
|
|
||||||
stack->eflags=context->EFlags;
|
|
||||||
stack->retaddr=*(DWORD*)context->Esp;
|
|
||||||
#else
|
|
||||||
stack->rax=context->Rax;
|
|
||||||
stack->rbx=context->Rbx;
|
|
||||||
stack->rcx=context->Rcx;
|
|
||||||
stack->rdx=context->Rdx;
|
|
||||||
stack->rsp=context->Rsp;
|
|
||||||
stack->rbp=context->Rbp;
|
|
||||||
stack->rsi=context->Rsi;
|
|
||||||
stack->rdi=context->Rdi;
|
|
||||||
stack->r8=context->R8;
|
|
||||||
stack->r9=context->R9;
|
|
||||||
stack->r10=context->R10;
|
|
||||||
stack->r11=context->R11;
|
|
||||||
stack->r12=context->R12;
|
|
||||||
stack->r13=context->R13;
|
|
||||||
stack->r14=context->R14;
|
|
||||||
stack->r15=context->R15;
|
|
||||||
stack->eflags=context->EFlags;
|
|
||||||
stack->retaddr=*(DWORD64*)context->Rsp;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
void context_set(hook_stack* stack,PCONTEXT context){
|
|
||||||
#ifndef _WIN64
|
void context_get(hook_stack *stack, PCONTEXT context)
|
||||||
context->Eax=stack->eax;
|
{
|
||||||
context->Ecx=stack->ecx;
|
#ifndef _WIN64
|
||||||
context->Edx=stack->edx;
|
stack->eax = context->Eax;
|
||||||
context->Ebx=stack->ebx;
|
stack->ecx = context->Ecx;
|
||||||
context->Esp=stack->esp;
|
stack->edx = context->Edx;
|
||||||
context->Ebp=stack->ebp;
|
stack->ebx = context->Ebx;
|
||||||
context->Esi=stack->esi;
|
stack->esp = context->Esp;
|
||||||
context->Edi=stack->edi;
|
stack->ebp = context->Ebp;
|
||||||
context->EFlags=stack->eflags;
|
stack->esi = context->Esi;
|
||||||
#else
|
stack->edi = context->Edi;
|
||||||
context->Rax=stack->rax;
|
stack->eflags = context->EFlags;
|
||||||
context->Rbx=stack->rbx;
|
stack->retaddr = *(DWORD *)context->Esp;
|
||||||
context->Rcx=stack->rcx;
|
#else
|
||||||
context->Rdx=stack->rdx;
|
stack->rax = context->Rax;
|
||||||
context->Rsp=stack->rsp;
|
stack->rbx = context->Rbx;
|
||||||
context->Rbp=stack->rbp;
|
stack->rcx = context->Rcx;
|
||||||
context->Rsi=stack->rsi;
|
stack->rdx = context->Rdx;
|
||||||
context->Rdi=stack->rdi;
|
stack->rsp = context->Rsp;
|
||||||
context->R8=stack->r8;
|
stack->rbp = context->Rbp;
|
||||||
context->R9=stack->r9;
|
stack->rsi = context->Rsi;
|
||||||
context->R10=stack->r10;
|
stack->rdi = context->Rdi;
|
||||||
context->R11=stack->r11;
|
stack->r8 = context->R8;
|
||||||
context->R12=stack->r12;
|
stack->r9 = context->R9;
|
||||||
context->R13=stack->r13;
|
stack->r10 = context->R10;
|
||||||
context->R14=stack->r14;
|
stack->r11 = context->R11;
|
||||||
context->R15=stack->r15;
|
stack->r12 = context->R12;
|
||||||
context->EFlags=stack->eflags;
|
stack->r13 = context->R13;
|
||||||
#endif
|
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
|
||||||
}
|
}
|
||||||
|
@ -4,31 +4,29 @@
|
|||||||
// 8/23/2013 jichi
|
// 8/23/2013 jichi
|
||||||
// Branch: ITH/IHF_DLL.h, rev 66
|
// 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 ConsoleOutput(LPCSTR text, ...);
|
||||||
void NotifyHookFound(HookParam hp, wchar_t* text);
|
void NotifyHookFound(HookParam hp, wchar_t *text);
|
||||||
void NotifyHookRemove(uint64_t addr, LPCSTR name);
|
void NotifyHookRemove(uint64_t addr, LPCSTR name);
|
||||||
bool NewHook(HookParam hp, LPCSTR name);
|
bool NewHook(HookParam hp, LPCSTR name);
|
||||||
bool NewHookJit(HookParam hp, LPCSTR name);
|
bool NewHookJit(HookParam hp, LPCSTR name);
|
||||||
|
|
||||||
void RemoveHook(uint64_t addr, int maxOffset = 9);
|
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;
|
inline SearchParam spDefault;
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
int HookStrLen(HookParam*,BYTE* data);
|
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>> emuaddr2jitaddr;
|
||||||
inline std::unordered_map<uintptr_t,std::pair<JITTYPE,uintptr_t>>jitaddr2emuaddr;
|
inline std::unordered_map<uintptr_t, std::pair<JITTYPE, uintptr_t>> jitaddr2emuaddr;
|
||||||
void jitaddraddr(uintptr_t em_addr,uintptr_t jitaddr,JITTYPE);
|
void jitaddraddr(uintptr_t em_addr, uintptr_t jitaddr, JITTYPE);
|
||||||
|
|
||||||
void context_get(hook_stack*,PCONTEXT);
|
void context_get(hook_stack *, PCONTEXT);
|
||||||
void context_set(hook_stack*,PCONTEXT);
|
void context_set(hook_stack *, PCONTEXT);
|
||||||
|
|
||||||
inline std::map<uintptr_t,std::pair<std::string,HookParam>>delayinserthook;
|
inline std::map<uintptr_t, std::pair<std::string, HookParam>> delayinserthook;
|
||||||
void delayinsertadd(HookParam,std::string);
|
void delayinsertadd(HookParam, std::string);
|
||||||
void delayinsertNewHook(uintptr_t);
|
void delayinsertNewHook(uintptr_t);
|
||||||
|
|
||||||
|
inline bool dont_detach = false;
|
||||||
inline bool dont_detach=false;
|
inline bool host_connected = false;
|
||||||
inline bool host_connected=false;
|
|
@ -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 wcslen(XX) wcsnlen((XX), TEXT_BUFFER_SIZE*2)
|
||||||
//#define strlen(XX) strnlen((XX), TEXT_BUFFER_SIZE*2)
|
// #define strlen(XX) strnlen((XX), TEXT_BUFFER_SIZE*2)
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
#include"main.h"
|
#include "stackoffset.hpp"
|
||||||
#include"stackoffset.hpp"
|
#include "util/stringfilters.h"
|
||||||
#include"util/stringfilters.h"
|
#include "memdbg/memsearch.h"
|
||||||
#include"memdbg/memsearch.h"
|
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
#include "ithsys/ithsys.h"
|
#include "ithsys/ithsys.h"
|
||||||
#include"pchooks/pchooks.h"
|
#include "pchooks/pchooks.h"
|
||||||
#include "cpputil/cppcstring.h"
|
#include "cpputil/cppcstring.h"
|
||||||
#include"dyncodec/dynsjiscodec.h"
|
#include "dyncodec/dynsjiscodec.h"
|
||||||
#include"dyncodec/dynsjis.h"
|
#include "dyncodec/dynsjis.h"
|
||||||
#include "disasm/disasm.h"
|
#include "disasm/disasm.h"
|
||||||
#include"engine.h"
|
#include "engine.h"
|
||||||
#include"embed_util.h"
|
#include "embed_util.h"
|
||||||
#include"detours.h"
|
#include "detours.h"
|
||||||
#include"hijackfuns.h"
|
#include "hijackfuns.h"
|
||||||
|
|
||||||
#include"Lang/Lang.h"
|
#include "Lang/Lang.h"
|
||||||
#include"veh_hook.h"
|
#include "veh_hook.h"
|
||||||
#include"engines/emujitarg.hpp"
|
#include "engines/emujitarg.hpp"
|
||||||
#include"engines/mono/monoil2cpp.h"
|
#include "engines/mono/monoil2cpp.h"
|
||||||
#include "hookfinder.h"
|
#include "hookfinder.h"
|
||||||
#include"util/textunion.h"
|
#include "util/textunion.h"
|
||||||
#include"util/ntxpundef.h"
|
#include "util/ntxpundef.h"
|
||||||
|
@ -33,97 +33,132 @@ enum class regs
|
|||||||
invalid
|
invalid
|
||||||
};
|
};
|
||||||
|
|
||||||
inline int get_stack(int s){
|
inline int get_stack(int s)
|
||||||
#ifdef _WIN64
|
{
|
||||||
return s*8;
|
#ifdef _WIN64
|
||||||
#else
|
return s * 8;
|
||||||
return s*4;
|
#else
|
||||||
#endif
|
return s * 4;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
inline int get_reg(regs reg){
|
inline int get_reg(regs reg)
|
||||||
#ifdef _WIN64
|
{
|
||||||
return -8*(int)reg-8;
|
#ifdef _WIN64
|
||||||
#else
|
return -8 * (int)reg - 8;
|
||||||
return -4-(int)reg*4;
|
#else
|
||||||
#endif
|
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)
|
switch (reg)
|
||||||
{
|
{
|
||||||
#ifndef _WIN64
|
#ifndef _WIN64
|
||||||
case regs::eax:return stack->eax;
|
case regs::eax:
|
||||||
case regs::ecx:return stack->ecx;
|
return stack->eax;
|
||||||
case regs::edx:return stack->edx;
|
case regs::ecx:
|
||||||
case regs::ebx:return stack->ebx;
|
return stack->ecx;
|
||||||
case regs::esp:return stack->esp;
|
case regs::edx:
|
||||||
case regs::ebp:return stack->ebp;
|
return stack->edx;
|
||||||
case regs::esi:return stack->esi;
|
case regs::ebx:
|
||||||
case regs::edi:return stack->edi;
|
return stack->ebx;
|
||||||
#else
|
case regs::esp:
|
||||||
case regs::rax:return stack->rax;
|
return stack->esp;
|
||||||
case regs::rbx:return stack->rbx;
|
case regs::ebp:
|
||||||
case regs::rcx:return stack->rcx;
|
return stack->ebp;
|
||||||
case regs::rdx:return stack->rdx;
|
case regs::esi:
|
||||||
case regs::rsp:return stack->rsp;
|
return stack->esi;
|
||||||
case regs::rbp:return stack->rbp;
|
case regs::edi:
|
||||||
case regs::rsi:return stack->rsi;
|
return stack->edi;
|
||||||
case regs::rdi:return stack->rdi;
|
#else
|
||||||
case regs::r8:return stack->r8;
|
case regs::rax:
|
||||||
case regs::r9:return stack->r9;
|
return stack->rax;
|
||||||
case regs::r10:return stack->r10;
|
case regs::rbx:
|
||||||
case regs::r11:return stack->r11;
|
return stack->rbx;
|
||||||
case regs::r12:return stack->r12;
|
case regs::rcx:
|
||||||
case regs::r13:return stack->r13;
|
return stack->rcx;
|
||||||
case regs::r14:return stack->r14;
|
case regs::rdx:
|
||||||
case regs::r15:return stack->r15;
|
return stack->rdx;
|
||||||
#endif
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN64
|
#ifndef _WIN64
|
||||||
#define ARG1 stack[1]
|
#define ARG1 stack[1]
|
||||||
#define ARG2 stack[2]
|
#define ARG2 stack[2]
|
||||||
#define ARG3 stack[3]
|
#define ARG3 stack[3]
|
||||||
#define LASTRETVAL eax
|
#define LASTRETVAL eax
|
||||||
#define THISCALL __thiscall
|
#define THISCALL __thiscall
|
||||||
#define THISCALLTHIS ecx
|
#define THISCALLTHIS ecx
|
||||||
#define THISCALLARG1 stack[1]
|
#define THISCALLARG1 stack[1]
|
||||||
#define GETARG1 get_stack(1)
|
#define GETARG1 get_stack(1)
|
||||||
#define GETARG2 get_stack(2)
|
#define GETARG2 get_stack(2)
|
||||||
#define GETARG3 get_stack(3)
|
#define GETARG3 get_stack(3)
|
||||||
#define GETARG4 get_stack(4)
|
#define GETARG4 get_stack(4)
|
||||||
#else
|
#else
|
||||||
#define ARG1 rcx
|
#define ARG1 rcx
|
||||||
#define ARG2 rdx
|
#define ARG2 rdx
|
||||||
#define ARG3 r8
|
#define ARG3 r8
|
||||||
#define LASTRETVAL rax
|
#define LASTRETVAL rax
|
||||||
#define THISCALLTHIS rcx
|
#define THISCALLTHIS rcx
|
||||||
#define THISCALLARG1 rdx
|
#define THISCALLARG1 rdx
|
||||||
#define THISCALL
|
#define THISCALL
|
||||||
#define GETARG1 get_reg(regs::rcx)
|
#define GETARG1 get_reg(regs::rcx)
|
||||||
#define GETARG2 get_reg(regs::rdx)
|
#define GETARG2 get_reg(regs::rdx)
|
||||||
#define GETARG3 get_reg(regs::r8)
|
#define GETARG3 get_reg(regs::r8)
|
||||||
#define GETARG4 get_reg(regs::r9)
|
#define GETARG4 get_reg(regs::r9)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
inline uintptr_t *argidx(hook_stack *stack, int idx)
|
||||||
inline uintptr_t *argidx(hook_stack* stack,int idx){
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
auto offset=0;
|
auto offset = 0;
|
||||||
switch (idx)
|
switch (idx)
|
||||||
{
|
{
|
||||||
case 1:offset=get_reg(regs::rcx);break;
|
case 1:
|
||||||
case 2:offset=get_reg(regs::rdx);break;
|
offset = get_reg(regs::rcx);
|
||||||
case 3:offset=get_reg(regs::r8);break;
|
break;
|
||||||
case 4:offset=get_reg(regs::r9);break;
|
case 2:
|
||||||
default:offset=get_stack(idx);
|
offset = get_reg(regs::rdx);
|
||||||
}
|
break;
|
||||||
return (uintptr_t*)((uintptr_t)stack+sizeof(hook_stack)-sizeof(uintptr_t)+offset);
|
case 3:
|
||||||
#else
|
offset = get_reg(regs::r8);
|
||||||
return (uintptr_t*)((uintptr_t)stack+sizeof(hook_stack)-sizeof(uintptr_t)+get_stack(idx));
|
break;
|
||||||
#endif
|
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
|
||||||
}
|
}
|
@ -4,35 +4,36 @@ extern WinMutex viewMutex;
|
|||||||
|
|
||||||
// - Unnamed helpers -
|
// - Unnamed helpers -
|
||||||
|
|
||||||
namespace { // unnamed
|
namespace
|
||||||
|
{ // unnamed
|
||||||
#ifndef _WIN64
|
#ifndef _WIN64
|
||||||
BYTE common_hook[] = {
|
BYTE common_hook[] = {
|
||||||
0x9c, // pushfd
|
0x9c, // pushfd
|
||||||
0x60, // pushad
|
0x60, // pushad
|
||||||
0x9c, // pushfd ; Artikash 11/4/2018: not sure why pushfd happens twice. Anyway, after this a total of 0x28 bytes are pushed
|
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]
|
0x8d, 0x44, 0x24, 0x28, // lea eax,[esp+0x28]
|
||||||
0x50, // push eax ; lpDatabase
|
0x50, // push eax ; lpDatabase
|
||||||
0xb9, 0,0,0,0, // mov ecx,@this
|
0xb9, 0, 0, 0, 0, // mov ecx,@this
|
||||||
0xbb, 0,0,0,0, // mov ebx,@TextHook::Send
|
0xbb, 0, 0, 0, 0, // mov ebx,@TextHook::Send
|
||||||
0xff, 0xd3, // call ebx
|
0xff, 0xd3, // call ebx
|
||||||
0x9d, // popfd
|
0x9d, // popfd
|
||||||
0x61, // popad
|
0x61, // popad
|
||||||
0x9d, // popfd
|
0x9d, // popfd
|
||||||
0x68, 0,0,0,0, // push @original
|
0x68, 0, 0, 0, 0, // push @original
|
||||||
0xc3 // ret ; basically absolute jmp to @original
|
0xc3 // ret ; basically absolute jmp to @original
|
||||||
};
|
};
|
||||||
int this_offset = 9, send_offset = 14, original_offset = 24;
|
int this_offset = 9, send_offset = 14, original_offset = 24;
|
||||||
#else
|
#else
|
||||||
BYTE common_hook[] = {
|
BYTE common_hook[] = {
|
||||||
0x9c, // push rflags
|
0x9c, // push rflags
|
||||||
0x50, // push rax
|
0x50, // push rax
|
||||||
0x53, // push rbx
|
0x53, // push rbx
|
||||||
0x51, // push rcx
|
0x51, // push rcx
|
||||||
0x52, // push rdx
|
0x52, // push rdx
|
||||||
0x54, // push rsp
|
0x54, // push rsp
|
||||||
0x55, // push rbp
|
0x55, // push rbp
|
||||||
0x56, // push rsi
|
0x56, // push rsi
|
||||||
0x57, // push rdi
|
0x57, // push rdi
|
||||||
0x41, 0x50, // push r8
|
0x41, 0x50, // push r8
|
||||||
0x41, 0x51, // push r9
|
0x41, 0x51, // push r9
|
||||||
0x41, 0x52, // push r10
|
0x41, 0x52, // push r10
|
||||||
@ -43,323 +44,370 @@ namespace { // unnamed
|
|||||||
0x41, 0x57, // push r15
|
0x41, 0x57, // push r15
|
||||||
// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
|
// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
|
||||||
// https://stackoverflow.com/questions/43358429/save-value-of-xmm-registers
|
// https://stackoverflow.com/questions/43358429/save-value-of-xmm-registers
|
||||||
0x48, 0x83, 0xec, 0x20, // sub rsp,0x20
|
0x48, 0x83, 0xec, 0x20, // sub rsp,0x20
|
||||||
0xf3, 0x0f, 0x7f, 0x24, 0x24, // movdqu [rsp],xmm4
|
0xf3, 0x0f, 0x7f, 0x24, 0x24, // movdqu [rsp],xmm4
|
||||||
0xf3, 0x0f, 0x7f, 0x6c, 0x24, 0x10, // movdqu [rsp+0x10],xmm5
|
0xf3, 0x0f, 0x7f, 0x6c, 0x24, 0x10, // movdqu [rsp+0x10],xmm5
|
||||||
0x48, 0x8d, 0x94, 0x24, 0xa8, 0x00, 0x00, 0x00, // lea rdx,[rsp+0xa8]
|
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, 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, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, // mov rax,@TextHook::Send
|
||||||
0x48, 0x89, 0xe3, // mov rbx,rsp
|
0x48, 0x89, 0xe3, // mov rbx,rsp
|
||||||
0x48, 0x83, 0xe4, 0xf0, // and rsp,0xfffffffffffffff0 ; align stack
|
0x48, 0x83, 0xe4, 0xf0, // and rsp,0xfffffffffffffff0 ; align stack
|
||||||
0xff, 0xd0, // call rax
|
0xff, 0xd0, // call rax
|
||||||
0x48, 0x89, 0xdc, // mov rsp,rbx
|
0x48, 0x89, 0xdc, // mov rsp,rbx
|
||||||
0xf3, 0x0f, 0x6f, 0x6c, 0x24, 0x10, // movdqu xmm5,XMMWORD PTR[rsp + 0x10]
|
0xf3, 0x0f, 0x6f, 0x6c, 0x24, 0x10, // movdqu xmm5,XMMWORD PTR[rsp + 0x10]
|
||||||
0xf3, 0x0f, 0x6f, 0x24, 0x24, // movdqu xmm4,XMMWORD PTR[rsp]
|
0xf3, 0x0f, 0x6f, 0x24, 0x24, // movdqu xmm4,XMMWORD PTR[rsp]
|
||||||
0x48, 0x83, 0xc4, 0x20, // add rsp,0x20
|
0x48, 0x83, 0xc4, 0x20, // add rsp,0x20
|
||||||
0x41, 0x5f, // pop r15
|
0x41, 0x5f, // pop r15
|
||||||
0x41, 0x5e, // pop r14
|
0x41, 0x5e, // pop r14
|
||||||
0x41, 0x5d, // pop r13
|
0x41, 0x5d, // pop r13
|
||||||
0x41, 0x5c, // pop r12
|
0x41, 0x5c, // pop r12
|
||||||
0x41, 0x5b, // pop r11
|
0x41, 0x5b, // pop r11
|
||||||
0x41, 0x5a, // pop r10
|
0x41, 0x5a, // pop r10
|
||||||
0x41, 0x59, // pop r9
|
0x41, 0x59, // pop r9
|
||||||
0x41, 0x58, // pop r8
|
0x41, 0x58, // pop r8
|
||||||
0x5f, // pop rdi
|
0x5f, // pop rdi
|
||||||
0x5e, // pop rsi
|
0x5e, // pop rsi
|
||||||
0x5d, // pop rbp
|
0x5d, // pop rbp
|
||||||
0x5c, // pop rsp
|
0x5c, // pop rsp
|
||||||
0x5a, // pop rdx
|
0x5a, // pop rdx
|
||||||
0x59, // pop rcx
|
0x59, // pop rcx
|
||||||
0x5b, // pop rbx
|
0x5b, // pop rbx
|
||||||
0x58, // pop rax
|
0x58, // pop rax
|
||||||
0x9d, // pop rflags
|
0x9d, // pop rflags
|
||||||
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip]
|
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;
|
int this_offset = 50, send_offset = 60, original_offset = 126;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//thread_local BYTE buffer[PIPE_BUFFER_SIZE];
|
// thread_local BYTE buffer[PIPE_BUFFER_SIZE];
|
||||||
//thread_local will crush on windowsxp
|
// thread_local will crush on windowsxp
|
||||||
} // unnamed namespace
|
} // unnamed namespace
|
||||||
|
|
||||||
// - TextHook methods -
|
// - TextHook methods -
|
||||||
|
|
||||||
uintptr_t getasbaddr(const HookParam &hp){
|
uintptr_t getasbaddr(const HookParam &hp)
|
||||||
auto address=hp.address;
|
{
|
||||||
|
auto address = hp.address;
|
||||||
if (hp.type & MODULE_OFFSET)
|
if (hp.type & MODULE_OFFSET)
|
||||||
{
|
{
|
||||||
if (hp.type & FUNCTION_OFFSET)
|
if (hp.type & FUNCTION_OFFSET)
|
||||||
{
|
{
|
||||||
if (FARPROC function = GetProcAddress(GetModuleHandleW(hp.module), hp.function)) address += (uint64_t)function;
|
if (FARPROC function = GetProcAddress(GetModuleHandleW(hp.module), hp.function))
|
||||||
else return ConsoleOutput(FUNC_MISSING), 0;
|
address += (uint64_t)function;
|
||||||
|
else
|
||||||
|
return ConsoleOutput(FUNC_MISSING), 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (HMODULE moduleBase = GetModuleHandleW(hp.module)) address += (uint64_t)moduleBase;
|
if (HMODULE moduleBase = GetModuleHandleW(hp.module))
|
||||||
else return ConsoleOutput(MODULE_MISSING), 0;
|
address += (uint64_t)moduleBase;
|
||||||
}
|
else
|
||||||
|
return ConsoleOutput(MODULE_MISSING), 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
bool TextHook::Insert(HookParam hp)
|
bool TextHook::Insert(HookParam hp)
|
||||||
{
|
{
|
||||||
|
|
||||||
auto addr=getasbaddr(hp);
|
auto addr = getasbaddr(hp);
|
||||||
if(!addr)return false;
|
if (!addr)
|
||||||
|
return false;
|
||||||
|
|
||||||
RemoveHook(addr, 0);
|
RemoveHook(addr, 0);
|
||||||
ConsoleOutput(INSERTING_HOOK, hp.name,addr);
|
ConsoleOutput(INSERTING_HOOK, hp.name, addr);
|
||||||
local_buffer=new BYTE[PIPE_BUFFER_SIZE];
|
local_buffer = new BYTE[PIPE_BUFFER_SIZE];
|
||||||
{
|
{
|
||||||
std::scoped_lock lock(viewMutex);
|
std::scoped_lock lock(viewMutex);
|
||||||
this->hp = hp;
|
this->hp = hp;
|
||||||
address = addr;
|
address = addr;
|
||||||
}
|
}
|
||||||
savetypeforremove=hp.type;
|
savetypeforremove = hp.type;
|
||||||
if (hp.type & DIRECT_READ) return InsertReadCode();
|
if (hp.type & DIRECT_READ)
|
||||||
if (hp.type & BREAK_POINT) return InsertBreakPoint();
|
return InsertReadCode();
|
||||||
|
if (hp.type & BREAK_POINT)
|
||||||
|
return InsertBreakPoint();
|
||||||
return InsertHookCode();
|
return InsertHookCode();
|
||||||
}
|
}
|
||||||
uintptr_t win64find0000(uintptr_t addr){
|
uintptr_t win64find0000(uintptr_t addr)
|
||||||
uintptr_t r = 0;
|
{
|
||||||
__try{
|
uintptr_t r = 0;
|
||||||
addr &= ~0xf;
|
__try
|
||||||
for (uintptr_t i = addr, j = addr - 0x10000; i > j; i-=0x10) {
|
{
|
||||||
DWORD k = *(DWORD *)(i-4);
|
addr &= ~0xf;
|
||||||
if (k == 0x00000000
|
for (uintptr_t i = addr, j = addr - 0x10000; i > j; i -= 0x10)
|
||||||
)
|
{
|
||||||
return i;
|
DWORD k = *(DWORD *)(i - 4);
|
||||||
|
if (k == 0x00000000)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
}__except(EXCEPTION_EXECUTE_HANDLER) {}
|
{
|
||||||
return r;
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
Synchronized<std::unordered_map<uintptr_t, uintptr_t>> retaddr2relative;//很奇怪,这个放到函数里用static在xp上会报错。
|
Synchronized<std::unordered_map<uintptr_t, uintptr_t>> retaddr2relative; // 很奇怪,这个放到函数里用static在xp上会报错。
|
||||||
uintptr_t queryrelativeret(HookParam&hp, uintptr_t retaddr){
|
uintptr_t queryrelativeret(HookParam &hp, uintptr_t retaddr)
|
||||||
//不需要区分是相对于哪个module的偏移,只需要得到偏移就可以了,用来确保重启程序后ret值恒定
|
{
|
||||||
auto &re=retaddr2relative.Acquire().contents;
|
// 不需要区分是相对于哪个module的偏移,只需要得到偏移就可以了,用来确保重启程序后ret值恒定
|
||||||
if(re.find(retaddr)!=re.end())return re.at(retaddr);
|
auto &re = retaddr2relative.Acquire().contents;
|
||||||
uintptr_t relative=retaddr;
|
if (re.find(retaddr) != re.end())
|
||||||
if(hp.jittype==JITTYPE::UNITY){
|
return re.at(retaddr);
|
||||||
#ifndef _WIN64
|
uintptr_t relative = retaddr;
|
||||||
relative=retaddr-SafeFindEnclosingAlignedFunction(retaddr,0x10000);
|
if (hp.jittype == JITTYPE::UNITY)
|
||||||
#else
|
{
|
||||||
relative=retaddr-win64find0000(retaddr);
|
#ifndef _WIN64
|
||||||
#endif
|
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;
|
if (MEMORY_BASIC_INFORMATION info = {}; VirtualQuery((LPCVOID)retaddr, &info, sizeof(info)))
|
||||||
|
relative -= (uintptr_t)info.AllocationBase;
|
||||||
}
|
}
|
||||||
re.insert(std::make_pair(retaddr,relative));
|
re.insert(std::make_pair(retaddr, relative));
|
||||||
return relative;
|
return relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t jitgetaddr(hook_stack* stack, HookParam* hp){
|
uintptr_t jitgetaddr(hook_stack *stack, HookParam *hp)
|
||||||
|
{
|
||||||
switch (hp->jittype)
|
switch (hp->jittype)
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
case JITTYPE::RPCS3:
|
case JITTYPE::RPCS3:
|
||||||
return RPCS3::emu_arg(stack)[hp->argidx];
|
return RPCS3::emu_arg(stack)[hp->argidx];
|
||||||
case JITTYPE::VITA3K:
|
case JITTYPE::VITA3K:
|
||||||
return VITA3K::emu_arg(stack)[hp->argidx];
|
return VITA3K::emu_arg(stack)[hp->argidx];
|
||||||
case JITTYPE::YUZU:
|
case JITTYPE::YUZU:
|
||||||
return YUZU::emu_arg(stack)[hp->argidx];
|
return YUZU::emu_arg(stack)[hp->argidx];
|
||||||
#endif
|
#endif
|
||||||
case JITTYPE::PPSSPP:
|
case JITTYPE::PPSSPP:
|
||||||
return PPSSPP::emu_arg(stack)[hp->argidx];
|
return PPSSPP::emu_arg(stack)[hp->argidx];
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool checklengthembedable(const HookParam&hp,size_t size){
|
bool checklengthembedable(const HookParam &hp, size_t size)
|
||||||
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
if (hp.type & CODEC_UTF16)
|
if (hp.type & CODEC_UTF16)
|
||||||
len = 2;
|
len = 2;
|
||||||
else if(hp.type&CODEC_UTF32)
|
else if (hp.type & CODEC_UTF32)
|
||||||
len = 4;
|
len = 4;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
len = 1;
|
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);
|
if (hp->type & CODEC_UTF16)
|
||||||
else if(hp->type & CODEC_UTF32);
|
;
|
||||||
else if(hp->type & CODEC_UTF8);
|
else if (hp->type & CODEC_UTF32)
|
||||||
else{
|
;
|
||||||
if(*len==2){
|
else if (hp->type & CODEC_UTF8)
|
||||||
StringFilter((char*)data,len,"\x81\xa4",2);
|
;
|
||||||
StringFilter((char*)data,len,"\x81\xa5",2);
|
else
|
||||||
|
{
|
||||||
|
if (*len == 2)
|
||||||
|
{
|
||||||
|
StringFilter((char *)data, len, "\x81\xa4", 2);
|
||||||
|
StringFilter((char *)data, len, "\x81\xa5", 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void TextHook::Send(uintptr_t lpDataBase)
|
void TextHook::Send(uintptr_t lpDataBase)
|
||||||
{
|
{
|
||||||
auto buffer =(TextOutput_T*) local_buffer;
|
auto buffer = (TextOutput_T *)local_buffer;
|
||||||
auto pbData = buffer->data;
|
auto pbData = buffer->data;
|
||||||
_InterlockedIncrement((long*)&useCount);
|
_InterlockedIncrement((long *)&useCount);
|
||||||
__try
|
__try
|
||||||
{
|
{
|
||||||
auto stack=get_hook_stack(lpDataBase);
|
auto stack = get_hook_stack(lpDataBase);
|
||||||
|
|
||||||
if (auto current_trigger_fun = trigger_fun.exchange(nullptr))
|
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;
|
if (hp.type & HOOK_RETURN)
|
||||||
hp.address=stack->retaddr;
|
{
|
||||||
strcat(hp.name,"_Return");
|
hp.type &= ~HOOK_RETURN;
|
||||||
//清除jit hook特征,防止手动插入
|
hp.address = stack->retaddr;
|
||||||
strcpy(hp.unityfunctioninfo,"");
|
strcat(hp.name, "_Return");
|
||||||
hp.emu_addr=0;
|
// 清除jit hook特征,防止手动插入
|
||||||
//清除module
|
strcpy(hp.unityfunctioninfo, "");
|
||||||
|
hp.emu_addr = 0;
|
||||||
|
// 清除module
|
||||||
hp.type &= ~MODULE_OFFSET;
|
hp.type &= ~MODULE_OFFSET;
|
||||||
hp.type &= ~FUNCTION_OFFSET;
|
hp.type &= ~FUNCTION_OFFSET;
|
||||||
strcpy(hp.function,"");
|
strcpy(hp.function, "");
|
||||||
wcscpy(hp.module,L"");
|
wcscpy(hp.module, L"");
|
||||||
|
|
||||||
NewHook(hp,hp.name);
|
NewHook(hp, hp.name);
|
||||||
hp.type|=HOOK_EMPTY;
|
hp.type |= HOOK_EMPTY;
|
||||||
__leave;
|
__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;
|
size_t lpCount = 0;
|
||||||
uintptr_t lpSplit = 0,
|
uintptr_t lpSplit = 0,
|
||||||
lpRetn = stack->retaddr,
|
lpRetn = stack->retaddr,
|
||||||
plpdatain=(lpDataBase + hp.offset),
|
plpdatain = (lpDataBase + hp.offset),
|
||||||
lpDataIn=*(uintptr_t*)plpdatain;
|
lpDataIn = *(uintptr_t *)plpdatain;
|
||||||
bool isstring=false;
|
bool isstring = false;
|
||||||
if(hp.jittype!=JITTYPE::PC&&hp.jittype!=JITTYPE::UNITY)
|
if (hp.jittype != JITTYPE::PC && hp.jittype != JITTYPE::UNITY)
|
||||||
{
|
{
|
||||||
lpDataIn=jitgetaddr(stack,&hp);
|
lpDataIn = jitgetaddr(stack, &hp);
|
||||||
plpdatain=(uintptr_t)&lpDataIn;
|
plpdatain = (uintptr_t)&lpDataIn;
|
||||||
}
|
}
|
||||||
else if(hp.jittype==JITTYPE::UNITY){
|
else if (hp.jittype == JITTYPE::UNITY)
|
||||||
plpdatain=(uintptr_t)argidx(stack,hp.argidx);
|
{
|
||||||
lpDataIn=*(uintptr_t*)plpdatain;
|
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);
|
auto use_custom_embed_fun = (hp.type & EMBED_ABLE) && !(hp.type & EMBED_BEFORE_SIMPLE);
|
||||||
if(use_custom_embed_fun)
|
if (use_custom_embed_fun)
|
||||||
{
|
{
|
||||||
isstring=true;
|
isstring = true;
|
||||||
lpSplit=Engine::ScenarioRole;lpRetn=0;
|
lpSplit = Engine::ScenarioRole;
|
||||||
if(hp.hook_before(stack,pbData,&lpCount,&lpSplit)==false)__leave;
|
lpRetn = 0;
|
||||||
|
if (hp.hook_before(stack, pbData, &lpCount, &lpSplit) == false)
|
||||||
|
__leave;
|
||||||
}
|
}
|
||||||
else if (hp.text_fun)
|
else if (hp.text_fun)
|
||||||
{
|
{
|
||||||
isstring=true;
|
isstring = true;
|
||||||
hp.text_fun(stack, &hp, &lpDataIn, &lpSplit, &lpCount);
|
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)
|
if (hp.jittype == JITTYPE::UNITY)
|
||||||
commonsolvemonostring(lpDataIn,&lpDataIn,&lpCount);
|
commonsolvemonostring(lpDataIn, &lpDataIn, &lpCount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (hp.type & FIXING_SPLIT) lpSplit = FIXED_SPLIT_VALUE; // fuse all threads, and prevent floating
|
if (hp.type & FIXING_SPLIT)
|
||||||
else if (hp.type & USING_SPLIT) {
|
lpSplit = FIXED_SPLIT_VALUE; // fuse all threads, and prevent floating
|
||||||
|
else if (hp.type & USING_SPLIT)
|
||||||
|
{
|
||||||
lpSplit = *(uintptr_t *)(lpDataBase + hp.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) {
|
if (hp.type & DATA_INDIRECT)
|
||||||
plpdatain=(lpDataIn + hp.index);
|
{
|
||||||
|
plpdatain = (lpDataIn + hp.index);
|
||||||
lpDataIn = *(uintptr_t *)plpdatain;
|
lpDataIn = *(uintptr_t *)plpdatain;
|
||||||
}
|
}
|
||||||
lpDataIn += hp.padding;
|
lpDataIn += hp.padding;
|
||||||
lpCount = GetLength(stack, lpDataIn);
|
lpCount = GetLength(stack, lpDataIn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lpCount <= 0)
|
||||||
if (lpCount <= 0) __leave;
|
__leave;
|
||||||
if (lpCount > TEXT_BUFFER_SIZE)
|
if (lpCount > TEXT_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
ConsoleOutput(InvalidLength, lpCount, hp.name);
|
ConsoleOutput(InvalidLength, lpCount, hp.name);
|
||||||
lpCount = TEXT_BUFFER_SIZE;
|
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;
|
if (lpDataIn == 0)
|
||||||
::memcpy(pbData, (void*)lpDataIn, lpCount);
|
__leave;
|
||||||
|
::memcpy(pbData, (void *)lpDataIn, lpCount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(hp.type &CODEC_UTF32)
|
if (hp.type & CODEC_UTF32)
|
||||||
{
|
{
|
||||||
*(uint32_t*)pbData=lpDataIn&0xffffffff;
|
*(uint32_t *)pbData = lpDataIn & 0xffffffff;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{//CHAR_LITTEL_ENDIAN,CODEC_ANSI_BE,CODEC_UTF16
|
{ // CHAR_LITTEL_ENDIAN,CODEC_ANSI_BE,CODEC_UTF16
|
||||||
lpDataIn &= 0xffff;
|
lpDataIn &= 0xffff;
|
||||||
if ((hp.type & CODEC_ANSI_BE) && (lpDataIn >> 8)) lpDataIn = _byteswap_ushort(lpDataIn & 0xffff);
|
if ((hp.type & CODEC_ANSI_BE) && (lpDataIn >> 8))
|
||||||
if (lpCount == 1) lpDataIn &= 0xff;
|
lpDataIn = _byteswap_ushort(lpDataIn & 0xffff);
|
||||||
*(WORD*)pbData = lpDataIn & 0xffff;
|
if (lpCount == 1)
|
||||||
|
lpDataIn &= 0xff;
|
||||||
|
*(WORD *)pbData = lpDataIn & 0xffff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!commonfilter(pbData, &lpCount, &hp) ||lpCount <= 0) __leave;
|
if (!commonfilter(pbData, &lpCount, &hp) || lpCount <= 0)
|
||||||
if (hp.filter_fun && !hp.filter_fun(pbData, &lpCount, &hp) || lpCount <= 0) __leave;
|
__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);
|
parsenewlineseperator(pbData, &lpCount);
|
||||||
|
|
||||||
bool canembed;;
|
bool canembed;
|
||||||
if(hp.type&EMBED_ABLE){
|
;
|
||||||
if(!checklengthembedable(hp,lpCount)){
|
if (hp.type & EMBED_ABLE)
|
||||||
buffer->type&=(~EMBED_ABLE);
|
{
|
||||||
canembed=false;
|
if (!checklengthembedable(hp, lpCount))
|
||||||
|
{
|
||||||
|
buffer->type &= (~EMBED_ABLE);
|
||||||
|
canembed = false;
|
||||||
}
|
}
|
||||||
else if(checktranslatedok(pbData,lpCount)){
|
else if (checktranslatedok(pbData, lpCount))
|
||||||
buffer->type&=(~EMBED_ABLE);
|
{
|
||||||
canembed=true;
|
buffer->type &= (~EMBED_ABLE);
|
||||||
|
canembed = true;
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
canembed=true;
|
{
|
||||||
|
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;
|
auto lpCountsave = lpCount;
|
||||||
if(waitfornotify(buffer,pbData,&lpCount,tp))
|
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];
|
auto _ = new char[max(lpCountsave, lpCount) + 10];
|
||||||
memcpy(_,pbData,lpCount);
|
memcpy(_, pbData, lpCount);
|
||||||
for(int i=lpCount;i<max(lpCountsave,lpCount)+10;i++)
|
for (int i = lpCount; i < max(lpCountsave, lpCount) + 10; i++)
|
||||||
_[i]=0;
|
_[i] = 0;
|
||||||
*(uintptr_t*)plpdatain=(uintptr_t)_;
|
*(uintptr_t *)plpdatain = (uintptr_t)_;
|
||||||
}
|
}
|
||||||
else if(hp.type&EMBED_AFTER_OVERWRITE)
|
else if (hp.type & EMBED_AFTER_OVERWRITE)
|
||||||
{
|
{
|
||||||
memcpy((void*)lpDataIn,pbData,lpCount);
|
memcpy((void *)lpDataIn, pbData, lpCount);
|
||||||
for(int i=lpCount;i<lpCountsave;i++)
|
for (int i = lpCount; i < lpCountsave; i++)
|
||||||
((BYTE*)(lpDataIn))[i]=0;
|
((BYTE *)(lpDataIn))[i] = 0;
|
||||||
}
|
}
|
||||||
else if(hp.hook_after)
|
else if (hp.hook_after)
|
||||||
hp.hook_after(stack,pbData,lpCount);
|
hp.hook_after(stack, pbData, lpCount);
|
||||||
else if(hp.type&SPECIAL_JIT_STRING){
|
else if (hp.type & SPECIAL_JIT_STRING)
|
||||||
if(hp.jittype==JITTYPE::UNITY)
|
{
|
||||||
unity_ui_string_hook_after(argidx(stack,hp.argidx),pbData,lpCount);
|
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){
|
bool TextHook::breakpointcontext(PCONTEXT context)
|
||||||
auto stack=std::make_unique<hook_stack>();
|
{
|
||||||
context_get(stack.get(),context);
|
auto stack = std::make_unique<hook_stack>();
|
||||||
auto lpDataBase=stack->get_base();
|
context_get(stack.get(), context);
|
||||||
|
auto lpDataBase = stack->get_base();
|
||||||
Send(lpDataBase);
|
Send(lpDataBase);
|
||||||
context_set(stack.get(),context);
|
context_set(stack.get(), context);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool TextHook::InsertBreakPoint()
|
bool TextHook::InsertBreakPoint()
|
||||||
{
|
{
|
||||||
//MH_CreateHook 64位unity/yuzu-emu经常 MH_ERROR_MEMORY_ALLOC
|
// MH_CreateHook 64位unity/yuzu-emu经常 MH_ERROR_MEMORY_ALLOC
|
||||||
return add_veh_hook(location,std::bind(&TextHook::breakpointcontext,this,std::placeholders::_1));
|
return add_veh_hook(location, std::bind(&TextHook::breakpointcontext, this, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
bool TextHook::RemoveBreakPoint()
|
bool TextHook::RemoveBreakPoint()
|
||||||
{
|
{
|
||||||
@ -394,18 +443,19 @@ bool TextHook::RemoveBreakPoint()
|
|||||||
}
|
}
|
||||||
bool TextHook::InsertHookCode()
|
bool TextHook::InsertHookCode()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
VirtualProtect(location, 10, PAGE_EXECUTE_READWRITE, DUMMY);
|
VirtualProtect(location, 10, PAGE_EXECUTE_READWRITE, DUMMY);
|
||||||
void* original;
|
void *original;
|
||||||
MH_STATUS error;
|
MH_STATUS error;
|
||||||
while ((error = MH_CreateHook(location, trampoline, &original)) != MH_OK)
|
while ((error = MH_CreateHook(location, trampoline, &original)) != MH_OK)
|
||||||
if (error == MH_ERROR_ALREADY_CREATED) RemoveHook(address);
|
if (error == MH_ERROR_ALREADY_CREATED)
|
||||||
else return ConsoleOutput(MH_StatusToString(error)), false;
|
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(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));
|
memcpy(trampoline, common_hook, sizeof(common_hook));
|
||||||
return MH_EnableHook(location) == MH_OK;
|
return MH_EnableHook(location) == MH_OK;
|
||||||
}
|
}
|
||||||
@ -413,36 +463,37 @@ bool TextHook::InsertHookCode()
|
|||||||
void TextHook::Read()
|
void TextHook::Read()
|
||||||
{
|
{
|
||||||
size_t dataLen = 1;
|
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;
|
auto pbData = buffer->data;
|
||||||
buffer->type=hp.type;
|
buffer->type = hp.type;
|
||||||
__try
|
__try
|
||||||
{
|
{
|
||||||
if(hp.text_fun)
|
if (hp.text_fun)
|
||||||
{
|
{
|
||||||
while (WaitForSingleObject(readerEvent, 500) == WAIT_TIMEOUT)
|
while (WaitForSingleObject(readerEvent, 500) == WAIT_TIMEOUT)
|
||||||
hp.text_fun(0,0,0,0,0);
|
hp.text_fun(0, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (WaitForSingleObject(readerEvent, 500) == WAIT_TIMEOUT)
|
while (WaitForSingleObject(readerEvent, 500) == WAIT_TIMEOUT)
|
||||||
{
|
{
|
||||||
if(!location)continue;
|
if (!location)
|
||||||
int currentLen = HookStrlen((BYTE*)location);
|
continue;
|
||||||
bool changed=memcmp(pbData, location, dataLen) != 0;
|
int currentLen = HookStrlen((BYTE *)location);
|
||||||
if(changed ||(currentLen!=dataLen))
|
bool changed = memcmp(pbData, location, dataLen) != 0;
|
||||||
|
if (changed || (currentLen != dataLen))
|
||||||
{
|
{
|
||||||
dataLen = min(currentLen, TEXT_BUFFER_SIZE);
|
dataLen = min(currentLen, TEXT_BUFFER_SIZE);
|
||||||
memcpy(pbData, location, dataLen);
|
memcpy(pbData, location, dataLen);
|
||||||
if (hp.filter_fun && !hp.filter_fun(pbData, &dataLen, &hp) || dataLen <= 0) continue;
|
if (hp.filter_fun && !hp.filter_fun(pbData, &dataLen, &hp) || dataLen <= 0)
|
||||||
TextOutput({ GetCurrentProcessId(), address, 0, 0 },hp, buffer, dataLen);
|
continue;
|
||||||
|
TextOutput({GetCurrentProcessId(), address, 0, 0}, hp, buffer, dataLen);
|
||||||
memcpy(pbData, location, dataLen);
|
memcpy(pbData, location, dataLen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
{
|
{
|
||||||
@ -453,7 +504,8 @@ void TextHook::Read()
|
|||||||
|
|
||||||
bool TextHook::InsertReadCode()
|
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);
|
readerEvent = CreateEventW(nullptr, FALSE, FALSE, NULL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -461,80 +513,85 @@ bool TextHook::InsertReadCode()
|
|||||||
void TextHook::RemoveHookCode()
|
void TextHook::RemoveHookCode()
|
||||||
{
|
{
|
||||||
MH_DisableHook(location);
|
MH_DisableHook(location);
|
||||||
while (useCount != 0);
|
while (useCount != 0)
|
||||||
|
;
|
||||||
MH_RemoveHook(location);
|
MH_RemoveHook(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHook::RemoveReadCode()
|
void TextHook::RemoveReadCode()
|
||||||
{
|
{
|
||||||
SetEvent(readerEvent);
|
SetEvent(readerEvent);
|
||||||
if (GetThreadId(readerThread) != GetCurrentThreadId()) WaitForSingleObject(readerThread, 1000);
|
if (GetThreadId(readerThread) != GetCurrentThreadId())
|
||||||
|
WaitForSingleObject(readerThread, 1000);
|
||||||
CloseHandle(readerEvent);
|
CloseHandle(readerEvent);
|
||||||
CloseHandle(readerThread);
|
CloseHandle(readerThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHook::Clear()
|
void TextHook::Clear()
|
||||||
{
|
{
|
||||||
if (address == 0) return;
|
if (address == 0)
|
||||||
if (savetypeforremove & DIRECT_READ) RemoveReadCode();
|
return;
|
||||||
else if (savetypeforremove & BREAK_POINT) RemoveBreakPoint();
|
if (savetypeforremove & DIRECT_READ)
|
||||||
else RemoveHookCode();
|
RemoveReadCode();
|
||||||
|
else if (savetypeforremove & BREAK_POINT)
|
||||||
|
RemoveBreakPoint();
|
||||||
|
else
|
||||||
|
RemoveHookCode();
|
||||||
NotifyHookRemove(address, hp.name);
|
NotifyHookRemove(address, hp.name);
|
||||||
std::scoped_lock lock(viewMutex);
|
std::scoped_lock lock(viewMutex);
|
||||||
memset(&hp, 0, sizeof(HookParam));
|
memset(&hp, 0, sizeof(HookParam));
|
||||||
address = 0;
|
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;
|
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 (len >= 0)
|
||||||
{
|
{
|
||||||
if (hp.type & CODEC_UTF16)
|
if (hp.type & CODEC_UTF16)
|
||||||
len <<= 1;
|
len <<= 1;
|
||||||
else if(hp.type & CODEC_UTF32)
|
else if (hp.type & CODEC_UTF32)
|
||||||
len <<= 2;
|
len <<= 2;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (len != -1)
|
else if (len != -1)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{//len==-1
|
{ // len==-1
|
||||||
len = HookStrlen((BYTE*)in);
|
len = HookStrlen((BYTE *)in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
len = HookStrlen((BYTE*)in);
|
len = HookStrlen((BYTE *)in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (hp.type & CODEC_UTF16)
|
if (hp.type & CODEC_UTF16)
|
||||||
len = 2;
|
len = 2;
|
||||||
else if(hp.type&CODEC_UTF32)
|
else if (hp.type & CODEC_UTF32)
|
||||||
len = 4;
|
len = 4;
|
||||||
else
|
else
|
||||||
{ //CODEC_ANSI_BE,CHAR_LITTLE_ENDIAN
|
{ // CODEC_ANSI_BE,CHAR_LITTLE_ENDIAN
|
||||||
if (hp.type & CODEC_ANSI_BE)
|
if (hp.type & CODEC_ANSI_BE)
|
||||||
in >>= 8;
|
in >>= 8;
|
||||||
len = !!IsDBCSLeadByteEx(hp.codepage, in & 0xff) + 1;
|
len = !!IsDBCSLeadByteEx(hp.codepage, in & 0xff) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return max(0, len);
|
return max(0, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int TextHook::HookStrlen(BYTE* data)
|
int TextHook::HookStrlen(BYTE *data)
|
||||||
{
|
{
|
||||||
return HookStrLen(&hp,data);
|
return HookStrLen(&hp, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
@ -6,98 +6,107 @@ Version: 24-March-2008
|
|||||||
// #define _WIN32_WINNT 0x0501
|
// #define _WIN32_WINNT 0x0501
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include "veh_hook.h"
|
#include "veh_hook.h"
|
||||||
#include<mutex>
|
#include <mutex>
|
||||||
static veh_list_t* list = NULL;
|
static veh_list_t *list = NULL;
|
||||||
char int3bp[] = "\xCC";
|
char int3bp[] = "\xCC";
|
||||||
std::mutex vehlistlock;
|
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);
|
std::lock_guard _(vehlistlock);
|
||||||
//static veh_list_t* list = NULL;
|
// static veh_list_t* list = NULL;
|
||||||
DWORD oldProtect;
|
DWORD oldProtect;
|
||||||
if (list == NULL) list = new_veh_list();
|
if (list == NULL)
|
||||||
if (list == NULL) return false;
|
list = new_veh_list();
|
||||||
if(get_veh_node(list,origFunc))return false;
|
if (list == NULL)
|
||||||
void* handle = AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)veh_dispatch);
|
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);
|
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.
|
// For memory hooks especially, we need to know the address of the start of the relevant page.
|
||||||
MEMORY_BASIC_INFORMATION mem_info;
|
MEMORY_BASIC_INFORMATION mem_info;
|
||||||
VirtualQuery(origFunc, &mem_info, sizeof(MEMORY_BASIC_INFORMATION));
|
VirtualQuery(origFunc, &mem_info, sizeof(MEMORY_BASIC_INFORMATION));
|
||||||
newnode->baseAddr = mem_info.BaseAddress;
|
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;
|
delete newnode;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memcpy((void*)(&newnode->origBaseByte), (const void*)origFunc, sizeof (BYTE));
|
memcpy((void *)(&newnode->origBaseByte), (const void *)origFunc, sizeof(BYTE));
|
||||||
memcpy((void*)origFunc, (const void*)&int3bp, sizeof (BYTE));
|
memcpy((void *)origFunc, (const void *)&int3bp, sizeof(BYTE));
|
||||||
VirtualProtect(origFunc, sizeof(int), newnode->OldProtect, &oldProtect);
|
VirtualProtect(origFunc, sizeof(int), newnode->OldProtect, &oldProtect);
|
||||||
insert_veh_node(list, newnode);
|
insert_veh_node(list, newnode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void repair_origin(veh_node_t *node){
|
void repair_origin(veh_node_t *node)
|
||||||
|
{
|
||||||
DWORD _p;
|
DWORD _p;
|
||||||
if(!VirtualProtect(node->origFunc, sizeof(int), PAGE_EXECUTE_READWRITE, &_p))
|
if (!VirtualProtect(node->origFunc, sizeof(int), PAGE_EXECUTE_READWRITE, &_p))
|
||||||
return;
|
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);
|
VirtualProtect(node->origFunc, sizeof(int), node->OldProtect, &_p);
|
||||||
}
|
}
|
||||||
bool remove_veh_hook(void* origFunc)
|
bool remove_veh_hook(void *origFunc)
|
||||||
{
|
{
|
||||||
std::lock_guard _(vehlistlock);
|
std::lock_guard _(vehlistlock);
|
||||||
if (list == NULL) return false;
|
if (list == NULL)
|
||||||
veh_node_t* node = get_veh_node(list, origFunc);
|
return false;
|
||||||
if (node == NULL) return false;
|
veh_node_t *node = get_veh_node(list, origFunc);
|
||||||
|
if (node == NULL)
|
||||||
|
return false;
|
||||||
repair_origin(node);
|
repair_origin(node);
|
||||||
RemoveVectoredExceptionHandler(node->handle);
|
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)
|
while (searchnode != NULL)
|
||||||
{
|
{
|
||||||
if (searchnode->origFunc == origFunc)
|
if (searchnode->origFunc == origFunc)
|
||||||
{
|
{
|
||||||
if(list->tail==searchnode)
|
if (list->tail == searchnode)
|
||||||
list->tail=searchnode->last;
|
list->tail = searchnode->last;
|
||||||
if(list->head==searchnode)
|
if (list->head == searchnode)
|
||||||
list->head=searchnode->next;
|
list->head = searchnode->next;
|
||||||
if(searchnode->last)
|
if (searchnode->last)
|
||||||
searchnode->last->next=searchnode->next;
|
searchnode->last->next = searchnode->next;
|
||||||
if(searchnode->next)
|
if (searchnode->next)
|
||||||
searchnode->next->last=searchnode->last;
|
searchnode->next->last = searchnode->last;
|
||||||
|
|
||||||
delete (searchnode);
|
delete (searchnode);
|
||||||
return ;
|
return;
|
||||||
}
|
}
|
||||||
searchnode = searchnode->next;
|
searchnode = searchnode->next;
|
||||||
}
|
}
|
||||||
return ;
|
return;
|
||||||
}
|
}
|
||||||
LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo)
|
LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo)
|
||||||
{
|
{
|
||||||
|
|
||||||
DWORD oldProtect;
|
DWORD oldProtect;
|
||||||
void* Addr = ExceptionInfo->ExceptionRecord->ExceptionAddress;
|
void *Addr = ExceptionInfo->ExceptionRecord->ExceptionAddress;
|
||||||
ULONG Code = ExceptionInfo->ExceptionRecord->ExceptionCode;
|
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;
|
// 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);
|
std::lock_guard _(vehlistlock);
|
||||||
currnode = get_veh_node(list, Addr);
|
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);
|
repair_origin(currnode);
|
||||||
ExceptionInfo->ContextRecord->EFlags |= 0x100;
|
ExceptionInfo->ContextRecord->EFlags |= 0x100;
|
||||||
@ -107,17 +116,17 @@ LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo)
|
|||||||
remove_veh_hook(Addr);
|
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);
|
std::lock_guard _(vehlistlock);
|
||||||
veh_node_t* currnode = get_veh_node(list, Addr, 0x10);
|
veh_node_t *currnode = get_veh_node(list, Addr, 0x10);
|
||||||
if (currnode == NULL) return EXCEPTION_CONTINUE_SEARCH;
|
if (currnode == NULL)
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
|
||||||
VirtualProtect(Addr, sizeof(int), PAGE_EXECUTE_READWRITE, &currnode->OldProtect);
|
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);
|
VirtualProtect(Addr, sizeof(int), currnode->OldProtect, &oldProtect);
|
||||||
ExceptionInfo->ContextRecord->EFlags &= ~0x00000100; // Remove TRACE from EFLAGS
|
ExceptionInfo->ContextRecord->EFlags &= ~0x00000100; // Remove TRACE from EFLAGS
|
||||||
|
|
||||||
}
|
}
|
||||||
// else if (Code == STATUS_SINGLE_STEP && hooktype == VEH_HK_HW)
|
// 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;
|
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));
|
veh_list_t *newlist = (veh_list_t *)malloc(sizeof(veh_list_t));
|
||||||
if (newlist == NULL) return NULL;
|
if (newlist == NULL)
|
||||||
|
return NULL;
|
||||||
newlist->head = NULL;
|
newlist->head = NULL;
|
||||||
newlist->tail = NULL;
|
newlist->tail = NULL;
|
||||||
return newlist;
|
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;
|
veh_node_t *newnode = new veh_node_t;
|
||||||
if (newnode == NULL) return NULL;
|
if (newnode == NULL)
|
||||||
newnode->last=NULL;
|
return NULL;
|
||||||
|
newnode->last = NULL;
|
||||||
newnode->origFunc = origFunc;
|
newnode->origFunc = origFunc;
|
||||||
newnode->newFunc = newFunc;
|
newnode->newFunc = newFunc;
|
||||||
newnode->handle = handle;
|
newnode->handle = handle;
|
||||||
newnode->OldProtect = PAGE_EXECUTE_READWRITE;
|
newnode->OldProtect = PAGE_EXECUTE_READWRITE;
|
||||||
newnode->next = NULL;
|
newnode->next = NULL;
|
||||||
newnode->hooktype=hook_type;
|
newnode->hooktype = hook_type;
|
||||||
return newnode;
|
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)
|
if (list->head == NULL)
|
||||||
{
|
{
|
||||||
list->head = newnode;
|
list->head = newnode;
|
||||||
@ -163,23 +175,25 @@ void insert_veh_node(veh_list_t* list, veh_node_t* newnode)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
list->tail->next = newnode;
|
list->tail->next = newnode;
|
||||||
newnode->last=list->tail;
|
newnode->last = list->tail;
|
||||||
list->tail = newnode;
|
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 *newnode;
|
||||||
veh_node_t* closestnode = NULL;
|
veh_node_t *closestnode = NULL;
|
||||||
if (list == NULL) return NULL;
|
if (list == NULL)
|
||||||
|
return NULL;
|
||||||
newnode = list->head;
|
newnode = list->head;
|
||||||
while (newnode != NULL)
|
while (newnode != NULL)
|
||||||
{
|
{
|
||||||
if(((uintptr_t)origFunc-(uintptr_t)newnode->origFunc)<=range)
|
if (((uintptr_t)origFunc - (uintptr_t)newnode->origFunc) <= range)
|
||||||
{
|
{
|
||||||
closestnode=newnode;
|
closestnode = newnode;
|
||||||
if(range==0)break;
|
if (range == 0)
|
||||||
range=((uintptr_t)origFunc-(uintptr_t)newnode->origFunc);
|
break;
|
||||||
|
range = ((uintptr_t)origFunc - (uintptr_t)newnode->origFunc);
|
||||||
}
|
}
|
||||||
newnode = newnode->next;
|
newnode = newnode->next;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ Version: 24-March-2008
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include<functional>
|
#include <functional>
|
||||||
// VEH Hooking types
|
// VEH Hooking types
|
||||||
#define VEH_HK_INT3 0
|
#define VEH_HK_INT3 0
|
||||||
#define VEH_HK_MEM 1
|
#define VEH_HK_MEM 1
|
||||||
@ -17,43 +17,42 @@ Version: 24-March-2008
|
|||||||
|
|
||||||
#define OPCODE_INT3 "\xCC"
|
#define OPCODE_INT3 "\xCC"
|
||||||
|
|
||||||
|
// typedef void (*pfvoid)();
|
||||||
//typedef void (*pfvoid)();
|
// typedef void (*newFuncType)(PCONTEXT);
|
||||||
//typedef void (*newFuncType)(PCONTEXT);
|
|
||||||
using newFuncType = std::function<bool(PCONTEXT)>;
|
using newFuncType = std::function<bool(PCONTEXT)>;
|
||||||
|
|
||||||
typedef struct veh_node
|
typedef struct veh_node
|
||||||
{
|
{
|
||||||
struct veh_node* last;
|
struct veh_node *last;
|
||||||
struct veh_node* next;
|
struct veh_node *next;
|
||||||
void* origFunc;
|
void *origFunc;
|
||||||
newFuncType newFunc;
|
newFuncType newFunc;
|
||||||
void* handle;
|
void *handle;
|
||||||
DWORD hooktype;
|
DWORD hooktype;
|
||||||
void* baseAddr; // Address of the page in which origFunc resides.
|
void *baseAddr; // Address of the page in which origFunc resides.
|
||||||
BYTE origBaseByte;
|
BYTE origBaseByte;
|
||||||
DWORD OldProtect;
|
DWORD OldProtect;
|
||||||
} veh_node_t;
|
} veh_node_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
veh_node_t* head;
|
veh_node_t *head;
|
||||||
veh_node_t* tail;
|
veh_node_t *tail;
|
||||||
} veh_list_t;
|
} veh_list_t;
|
||||||
|
|
||||||
// VEH hook interface functions for creating and removing hooks.
|
// VEH hook interface functions for creating and removing hooks.
|
||||||
bool add_veh_hook(void* origFunc, newFuncType newFunc, DWORD hook_type=VEH_HK_INT3);
|
bool add_veh_hook(void *origFunc, newFuncType newFunc, DWORD hook_type = VEH_HK_INT3);
|
||||||
bool remove_veh_hook(void* origFunc);
|
bool remove_veh_hook(void *origFunc);
|
||||||
|
|
||||||
// The VEH dispathing function is called by Windows every time an exception is encountered.
|
// The VEH dispathing function is called by Windows every time an exception is encountered.
|
||||||
// the function dispatches calls to the correct inctercept function.
|
// the function dispatches calls to the correct inctercept function.
|
||||||
LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo);
|
LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo);
|
||||||
|
|
||||||
// Functions used internally by the library.
|
// Functions used internally by the library.
|
||||||
veh_list_t* new_veh_list();
|
veh_list_t *new_veh_list();
|
||||||
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);
|
||||||
void insert_veh_node(veh_list_t* list, veh_node_t*);
|
void insert_veh_node(veh_list_t *list, veh_node_t *);
|
||||||
void remove_veh_node(veh_list_t* list, void* origFunc);
|
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_node_t *get_veh_node(veh_list_t *list, void *origFunc, int range = 0);
|
||||||
|
|
||||||
#endif // LIST_T_H_INCLUDED
|
#endif // LIST_T_H_INCLUDED
|
||||||
|
Loading…
Reference in New Issue
Block a user