This commit is contained in:
恍兮惚兮 2024-12-21 01:25:43 +08:00
parent 91bbdde9b2
commit cb44b53259
33 changed files with 797 additions and 462 deletions

View File

@ -1,7 +1,7 @@
include_directories(. util engines)
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
set(enginessrc
BGI MKXPZ Ryujinx livecaptions Kincaid vita3k rpcs3 yuzu TYPEMOON UnrealEngine AGES7 mono
BGI MKXPZ Ryujinx livecaptions Kincaid vita3k rpcs3 yuzu TYPEMOON UnrealEngine AGES7
Godot 5pb lucasystem LightVN V8 Artemis KiriKiri YOX CMVS Suika2)
set(enginepath "engine64")
set(collector "enginecollection64.cpp")
@ -14,7 +14,7 @@ else()
BKEngine Overflow SRPGStudio Suika2 FVP LCScript Ohgetsu RPGMakerRGSS3 ONScripterru OVERDRIVE
HXP Palette Purple Ruf RUNE Tarte Tomato Sakuradog Troy VitaminSoft UnknownEngine TSSystem
Xbangbang Anisetta Nijyuei Interheart LovaGame Giga Jisatu101 EntisGLS Ciel ACTGS TerraLunar
jukujojidai VanillawareGC cef V8 mono PONScripter Bishop sakanagl Lightvn KiriKiri SideB BGI
jukujojidai VanillawareGC cef V8 PONScripter Bishop sakanagl Lightvn KiriKiri SideB BGI
Bootup morning shyakunage Regista NNNConfig Eushully Majiro littlecheese Elf Silkys CMVS Wolf
Circus1 Circus2 Cotopha Artemis CatSystem Atelier Tenco QLIE Pal AIL NeXAS LunaSoft Unicorn
Rejet Interlude AdobeAir Retouch Malie Live Nexton Lucifen Waffle TinkerBell SystemAoi Yuris

View File

@ -10,7 +10,7 @@ class ENGINE
public:
const char *enginename;
bool is_engine_certain; // stop when match a engine ,even if not attached
JITTYPE jittype;
enum class CHECK_BY
{
ALL_TRUE,
@ -36,7 +36,7 @@ public:
return enginename;
return typeid(*this).name() + 6;
}
ENGINE() : enginename(nullptr), is_engine_certain(true), check_by(CHECK_BY::ALL_TRUE){};
ENGINE() : enginename(nullptr), is_engine_certain(true), check_by(CHECK_BY::ALL_TRUE), jittype(JITTYPE::PC) {};
bool check_function();
};

View File

@ -1,58 +0,0 @@
#include "mono.h"
#include "mono/monocommon.hpp"
bool monobdwgc()
{
HMODULE module = GetModuleHandleW(L"mono-2.0-bdwgc.dll");
if (module == 0)
return false;
auto [minAddress, maxAddress] = Util::QueryModuleLimits(module);
BYTE bytes[] = {
0x3D, 0x00, 0x00, 0x01, 0x00,
0x73, XX,
0xb8, 0x03, 0x00, 0x00, 0x00,
0xEB, XX};
auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, minAddress, maxAddress);
auto succ = false;
for (auto addr : addrs)
{
ConsoleOutput("monobdwgcdll %p", addr);
HookParam hp;
hp.address = (DWORD)addr;
hp.offset = regoffset(eax);
hp.type = CODEC_UTF16 | NO_CONTEXT;
succ |= NewHook(hp, "monobdwgcdll");
}
return succ;
}
bool monodll()
{
HMODULE module = GetModuleHandleW(L"mono.dll");
if (module == 0)
return false;
auto [minAddress, maxAddress] = Util::QueryModuleLimits(module);
BYTE bytes[] = {
0x81, 0xFB, XX4,
0x73};
auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, minAddress, maxAddress);
auto succ = false;
for (auto addr : addrs)
{
ConsoleOutput("monodll %p", addr);
HookParam hp;
hp.address = (DWORD)addr;
hp.offset = regoffset(ebx);
hp.type = CODEC_UTF16 | NO_CONTEXT;
succ |= NewHook(hp, "monodll");
}
return succ;
}
bool mono::attach_function_()
{
bool common = monocommon::hook_mono_il2cpp();
return common;
}

View File

@ -1,15 +0,0 @@
class mono : public ENGINE
{
public:
mono()
{
check_by = CHECK_BY::CUSTOM;
check_by_target = [this]()
{ return attach_function_(); };
};
bool attach_function_();
bool attach_function() { return true; }
};

View File

@ -241,9 +241,6 @@ bool rpcs3::attach_function()
if (DoJitPtr == 0)
return false;
unsafeinithooks();
spDefault.isjithook = true;
spDefault.minAddress = 0;
spDefault.maxAddress = -1;
HookParam hp;
hp.address = DoJitPtr;
hp.text_fun = [](hook_context *context, HookParam *hp, TextBuffer *buffer, uintptr_t *split)

View File

@ -5,7 +5,7 @@ class rpcs3 : public ENGINE
public:
rpcs3()
{
jittype = JITTYPE::RPCS3;
check_by = CHECK_BY::FILE;
is_engine_certain = false;
check_by_target = L"rpcs3.exe";

View File

@ -91,9 +91,6 @@ bool vita3k::attach_function()
if (DoJitPtr == 0)
return false;
trygetgameinwindowtitle();
spDefault.isjithook = true;
spDefault.minAddress = 0;
spDefault.maxAddress = -1;
HookParam hp;
hp.address = DoJitPtr;
hp.text_fun = [](hook_context *context, HookParam *hp, TextBuffer *buffer, uintptr_t *split)

View File

@ -5,7 +5,7 @@ class vita3k : public ENGINE
public:
vita3k()
{
jittype = JITTYPE::VITA3K;
check_by = CHECK_BY::FILE;
is_engine_certain = false;
check_by_target = L"Vita3K.exe";

View File

@ -175,9 +175,6 @@ bool yuzu::attach_function()
return false;
trygetgameinwindowtitle();
Hook_Network_RoomMember_SendGameInfo();
spDefault.isjithook = true;
spDefault.minAddress = 0;
spDefault.maxAddress = -1;
HookParam hp;
hp.address = DoJitPtr;
hp.text_fun = [](hook_context *context, HookParam *hp, TextBuffer *buffer, uintptr_t *split)

View File

@ -5,7 +5,7 @@ class yuzu : public ENGINE
public:
yuzu()
{
jittype = JITTYPE::YUZU;
is_engine_certain = false;
check_by = CHECK_BY::CUSTOM;
check_by_target = []()

View File

@ -3,7 +3,6 @@
#include "engine32/V8.h"
#include "engine32/cef.h"
#include "engine32/KISS.h"
#include "engine32/mono.h"
#include "engine32/Tarte.h"
#include "engine32/sakanagl.h"
#include "engine32/H_do_C.h"
@ -187,6 +186,7 @@
#include "engine32/e_Erekiteru.h"
#include "engine32/GuruGuruSMF4.h"
#include "NoEngine.h"
#include "engines/mono/mono.h"
#include "engines/lua/lua51.h"
#include "engines/python/Renpy.h"
#include "engines/ppsspp/ppsspp.h"

View File

@ -1,6 +1,5 @@
#include "engine64/Godot.h"
#include "engine64/V8.h"
#include "engine64/mono.h"
#include "engine64/AGES7.h"
#include "engine64/Artemis.h"
#include "engine64/KiriKiri.h"
@ -20,6 +19,7 @@
#include "engine64/vita3k.h"
#include "engine64/rpcs3.h"
#include "engine64/MKXPZ.h"
#include "engines/mono/mono.h"
#include "engines/lua/lua51.h"
#include "engines/python/Renpy.h"
#include "engines/ppsspp/ppsspp.h"

View File

@ -86,14 +86,18 @@ bool checkengine()
bool matched = safematch(m);
bool attached = matched && safeattach(m);
//ConsoleOutput("Progress %d/%d, checked engine %s, %s",current,engines.size(),m->getenginename(),infomations[matched+attached]);
//ConsoleOutput("Progress %d/%d, %s",current,engines.size(),infomations[matched+attached]);
// ConsoleOutput("Progress %d/%d, checked engine %s, %s",current,engines.size(),m->getenginename(),infomations[matched+attached]);
// ConsoleOutput("Progress %d/%d, %s",current,engines.size(),infomations[matched+attached]);
if (matched == false)
continue;
ConsoleOutput(TR[MatchedEngine], m->getenginename());
if (m->is_engine_certain)
{
ConsoleOutput(TR[ConfirmStop], m->getenginename());
jittypedefault = m->jittype;
spDefault.isjithook = true;
spDefault.minAddress = 0;
spDefault.maxAddress = -1;
return attached;
}

View File

@ -1,4 +1,4 @@
add_library(commonengine mono/impl_mono.cpp mono/monoil2cpp.cpp mono/impl_il2cpp.cpp ppsspp/ppsspp.cpp mages/mages.cpp v8/v8.cpp v8/httpserver.cpp python/python2.cpp python/python3.cpp python/python.cpp pchooks/pchooks.cpp lua/lua51.cpp)
add_library(commonengine mono/impl_mono.cpp mono/monoil2cpp.cpp mono/mono.cpp mono/impl_il2cpp.cpp ppsspp/ppsspp.cpp mages/mages.cpp v8/v8.cpp v8/httpserver.cpp python/python2.cpp python/python3.cpp python/python.cpp pchooks/pchooks.cpp lua/lua51.cpp)
target_precompile_headers(commonengine REUSE_FROM pchhook)

View File

@ -369,7 +369,9 @@ struct Il2CppObject
};
void *monitor;
};
struct Il2CppDomain;
struct Il2CppAssembly;
struct Il2CppImage;
// not real Il2CppString class
struct Il2CppString
{
@ -519,12 +521,13 @@ struct Il2CppReflectionType
const Il2CppType *type;
};
inline void **(*il2cpp_domain_get_assemblies)(void *domain, std::size_t *size);
inline Il2CppClass *(*il2cpp_class_from_name)(void *image, const char *namespaze, const char *name);
inline MethodInfo *(*il2cpp_class_get_methods)(Il2CppClass *klass, void **iter);
inline MethodInfo *(*il2cpp_class_get_method_from_name)(Il2CppClass *klass, const char *name, int argsCount);
inline Il2CppAssembly **(*il2cpp_domain_get_assemblies)(const Il2CppDomain *domain, std::size_t *size);
inline const Il2CppClass *(*il2cpp_class_from_name)(const Il2CppImage *image, const char *namespaze, const char *name);
inline MethodInfo *(*il2cpp_class_get_methods)(const Il2CppClass *klass, void **iter);
inline const MethodInfo *(*il2cpp_class_get_method_from_name)(const Il2CppClass *klass, const char *name, int argsCount);
inline MethodInfo *(*il2cpp_method_get_from_reflection)(Il2CppObject *ref);
inline const Il2CppType *(*il2cpp_method_get_param)(const MethodInfo *method, uint32_t index);
inline char* (*il2cpp_type_get_name)(const Il2CppType *type);
inline Il2CppObject *(*il2cpp_object_new)(Il2CppClass *klass);
inline void (*il2cpp_add_internal_call)(const char *name, uintptr_t pointer);
inline Il2CppArraySize *(*il2cpp_array_new)(Il2CppClass *klass, uintptr_t count);
@ -537,14 +540,12 @@ inline void (*il2cpp_field_static_get_value)(FieldInfo *field, void *value);
inline void (*il2cpp_field_static_set_value)(FieldInfo *field, void *value);
inline const Il2CppType *(*il2cpp_field_get_type)(FieldInfo *field);
inline Il2CppObject *(*il2cpp_type_get_object)(const Il2CppType *type);
inline const char *(*il2cpp_image_get_name)(void *image);
inline size_t (*il2cpp_image_get_class_count)(void *image);
inline const Il2CppClass *(*il2cpp_image_get_class)(void *image, size_t index);
inline const char *(*il2cpp_image_get_name)(const Il2CppImage *image);
inline bool (*il2cpp_type_is_byref)(const Il2CppType *type);
inline uint32_t (*il2cpp_method_get_flags)(const MethodInfo *mehod, uint32_t *iflags);
inline const Il2CppType *(*il2cpp_method_get_return_type)(const MethodInfo *method);
inline Il2CppClass *(*il2cpp_class_from_type)(const Il2CppType *type);
inline const char *(*il2cpp_class_get_name)(Il2CppClass *klass);
inline const char *(*il2cpp_class_get_name)(const Il2CppClass *klass);
inline const PropertyInfo *(*il2cpp_class_get_properties)(Il2CppClass *klass, void **iter);
inline bool (*il2cpp_class_is_enum)(const Il2CppClass *klass);
inline FieldInfo *(*il2cpp_class_get_fields)(Il2CppClass *klass, void **iter);
@ -553,8 +554,8 @@ inline uint32_t (*il2cpp_method_get_param_count)(const MethodInfo *method);
inline const char *(*il2cpp_method_get_param_name)(const MethodInfo *method, uint32_t index);
inline Il2CppClass *(*il2cpp_class_get_parent)(Il2CppClass *klass);
inline Il2CppClass *(*il2cpp_class_get_interfaces)(Il2CppClass *klass, void **iter);
inline const char *(*il2cpp_class_get_namespace)(Il2CppClass *klass);
inline void *(*il2cpp_class_get_image)(Il2CppClass *klass);
inline const char *(*il2cpp_class_get_namespace)(const Il2CppClass *klass);
inline const Il2CppImage *(*il2cpp_class_get_image)(const Il2CppClass *klass);
inline int (*il2cpp_class_get_flags)(const Il2CppClass *klass);
inline bool (*il2cpp_class_is_valuetype)(const Il2CppClass *klass);
inline uint32_t (*il2cpp_property_get_flags)(PropertyInfo *prop);
@ -572,9 +573,9 @@ inline Il2CppObject *(*il2cpp_value_box)(Il2CppClass *klass, void *data);
inline void *(*il2cpp_object_unbox)(Il2CppObject *obj);
inline Il2CppString *(*il2cpp_string_new_utf16)(const wchar_t *str, unsigned int len);
inline Il2CppString *(*il2cpp_string_new)(const char *str);
inline void *(*il2cpp_domain_get)();
inline void *(*il2cpp_domain_assembly_open)(void *domain, const char *name);
inline void *(*il2cpp_assembly_get_image)(void *assembly);
inline Il2CppDomain *(*il2cpp_domain_get)();
inline Il2CppAssembly *(*il2cpp_domain_assembly_open)(Il2CppDomain *domain, const char *name);
inline const Il2CppImage *(*il2cpp_assembly_get_image)(const Il2CppAssembly *assembly);
inline void *(*il2cpp_resolve_icall)(const char *name);
inline void *(*il2cpp_thread_attach)(void *domain);
inline void (*il2cpp_thread_detach)(void *thread);
@ -588,12 +589,15 @@ inline void (*il2cpp_runtime_class_init)(void *klass);
inline void *(*il2cpp_runtime_invoke)(MethodInfo *method, void *obj, void **params, Il2CppObject **exc);
inline Il2CppChar *(*il2cpp_string_chars)(Il2CppString *str);
inline int (*il2cpp_string_length)(Il2CppString *str);
inline const Il2CppClass *(*il2cpp_image_get_class)(const Il2CppImage *image, size_t index);
inline size_t (*il2cpp_image_get_class_count)(const Il2CppImage *image);
namespace il2cppfunctions
{
inline HMODULE game_dll;
void init(HMODULE dll);
uintptr_t get_method_pointer(const char *assemblyName, const char *namespaze,
const char *klassName, const char *name, int argsCount, bool strict);
std::optional<std::wstring_view> get_string(void *);
void *create_string(std::wstring_view ws);
il2cpploopinfo loop_all_methods(bool show);
}

View File

@ -415,7 +415,6 @@ inline MonoTableInfo *(*mono_image_get_table_info)(MonoImage *, int);
inline int (*mono_table_info_get_rows)(MonoTableInfo *);
inline gunichar2 *(*mono_string_chars)(MonoString *str);
inline int (*mono_string_length)(MonoString *str);
namespace monofunctions
{
void init(HMODULE dll);
@ -424,4 +423,5 @@ namespace monofunctions
std::optional<std::wstring_view> get_string(void *);
void *create_string(std::wstring_view ws);
monoloopinfo loop_all_methods(bool show);
}

View File

@ -2,16 +2,15 @@
namespace
{
Il2CppClass *get_il2cppclass1(const char *assemblyName, const char *namespaze,
const char *klassName, bool strict)
const Il2CppClass *get_il2cppclass1(const char *assemblyName, const char *namespaze,
const char *klassName, bool strict)
{
auto il2cpp_domain = (SafeFptr(il2cpp_domain_get))();
if (!il2cpp_domain)
return NULL;
void *assembly = 0;
do
{
assembly = (SafeFptr(il2cpp_domain_assembly_open))(il2cpp_domain, assemblyName);
auto assembly = (SafeFptr(il2cpp_domain_assembly_open))(il2cpp_domain, assemblyName);
if (!assembly)
break;
auto image = (SafeFptr(il2cpp_assembly_get_image))(assembly);
@ -44,13 +43,39 @@ namespace
auto st = (std::vector<Il2CppClass *> *)userData;
st->push_back(klass);
}
std::vector<Il2CppClass *> get_il2cppclass2(const char *namespaze,
const char *klassName)
std::vector<const Il2CppClass *> loopclass()
{
std::vector<Il2CppClass *> maybes;
std::vector<Il2CppClass *> klasses;
std::vector<const Il2CppClass *> klasses;
(SafeFptr(il2cpp_class_for_each))(foreach_func, &klasses);
if (klasses.size())
return klasses;
auto domain = (SafeFptr(il2cpp_domain_get))();
if (!domain)
return klasses;
size_t assemblyCount = 0;
Il2CppAssembly **assemblies = SafeFptr(il2cpp_domain_get_assemblies)(domain, &assemblyCount);
for (size_t i = 0; i < assemblyCount; i++)
{
Il2CppAssembly *assembly = assemblies[i];
auto image = SafeFptr(il2cpp_assembly_get_image)(assembly);
if (!image)
continue;
auto classcount = SafeFptr(il2cpp_image_get_class_count)(image);
for (auto ci = 0; ci < classcount; ci++)
{
auto klass = SafeFptr(il2cpp_image_get_class)(image, ci);
if (!klass)
continue;
klasses.push_back(klass);
}
}
return klasses;
}
std::vector<const Il2CppClass *> get_il2cppclass2(const char *namespaze, const char *klassName)
{
std::vector<const Il2CppClass *> maybes;
auto klasses = loopclass();
for (auto klass : klasses)
{
auto classname = (SafeFptr(il2cpp_class_get_name))(klass);
@ -86,29 +111,116 @@ namespace
(SafeFptr(il2cpp_thread_detach))(thread);
}
};
void tryprintimage(Il2CppClass *klass)
std::optional<std::string> getclassinfo(const Il2CppClass *klass)
{
auto image = (SafeFptr(il2cpp_class_get_image))(klass);
if (!image)
return;
return {};
auto imagen = (SafeFptr(il2cpp_image_get_name))(image);
auto names = (SafeFptr(il2cpp_class_get_namespace))(klass);
if (imagen && names)
ConsoleOutput("%s:%s", imagen, names);
auto classname = (SafeFptr(il2cpp_class_get_name))(klass);
if (imagen && names && classname)
{
std::string _ = imagen;
_ += ":";
_ += names;
_ += ":";
_ += classname;
return _;
}
return {};
}
uintptr_t getmethodofklass(Il2CppClass *klass, const char *name, int argsCount)
std::string getmethodinfo(const MethodInfo *method)
{
const char *methodName = SafeFptr(il2cpp_method_get_name)(method);
std::stringstream info;
if (method->methodPointer)
info << std::hex << (method->methodPointer - (uintptr_t)il2cppfunctions::game_dll);
else
info << "??";
if (methodName) // il2cpp似乎没办法从method查询name
info << " " << methodName;
info << " (";
for (uint32_t i = 0; i < SafeFptr(il2cpp_method_get_param_count)(method); i++)
{
if (i != 0)
info << ", ";
if (auto rt = SafeFptr(il2cpp_method_get_param)(method, i))
if (auto tp = SafeFptr(il2cpp_type_get_name)(rt))
info << tp;
}
info << ")";
if (auto rt = SafeFptr(il2cpp_method_get_return_type)(method))
if (auto returntype = SafeFptr(il2cpp_type_get_name)(rt))
{
info << " -> " << returntype;
}
return info.str();
}
uintptr_t getmethodofklass(const Il2CppClass *klass, const char *name, int argsCount)
{
if (!klass)
return NULL;
auto ret = (SafeFptr(il2cpp_class_get_method_from_name))(klass, name, argsCount);
if (!ret)
return NULL;
tryprintimage(klass);
if (auto s = getclassinfo(klass))
{
ConsoleOutput(s.value().c_str());
ConsoleOutput(getmethodinfo(ret).c_str());
}
return ret->methodPointer;
}
}
il2cpploopinfo il2cppfunctions::loop_all_methods(bool show)
{
auto thread = AutoThread();
if (!thread.thread)
return {};
auto klasses = loopclass();
il2cpploopinfo hps;
for (auto klass : klasses)
{
auto s = getclassinfo(klass);
if (!s)
continue;
if (show)
ConsoleOutput(s.value().c_str());
void *iter = nullptr;
while (auto method = SafeFptr(il2cpp_class_get_methods)(klass, &iter))
{
if (show)
ConsoleOutput(getmethodinfo(method).c_str());
else
{
if (method->methodPointer)
{
for (uint32_t i = 0; i < SafeFptr(il2cpp_method_get_param_count)(method); i++)
{
if (auto rt = SafeFptr(il2cpp_method_get_param)(method, i))
if (auto tp = SafeFptr(il2cpp_type_get_name)(rt))
if (strcmp(tp, "System.String") == 0)
{
hps.push_back({i + 1, method->methodPointer});
break;
}
}
}
}
}
}
if (show && klasses.size())
return {{0, 0}};
return hps;
}
void il2cppfunctions::init(HMODULE game_module)
{
game_dll = game_module;
RESOLVE_IMPORT(il2cpp_type_get_name);
RESOLVE_IMPORT(il2cpp_method_get_param_count);
RESOLVE_IMPORT(il2cpp_string_new_utf16);
RESOLVE_IMPORT(il2cpp_string_chars);
RESOLVE_IMPORT(il2cpp_string_length);
@ -119,6 +231,8 @@ void il2cppfunctions::init(HMODULE game_module)
RESOLVE_IMPORT(il2cpp_domain_get);
RESOLVE_IMPORT(il2cpp_domain_assembly_open);
RESOLVE_IMPORT(il2cpp_assembly_get_image);
RESOLVE_IMPORT(il2cpp_image_get_class);
RESOLVE_IMPORT(il2cpp_image_get_class_count);
RESOLVE_IMPORT(il2cpp_class_from_name);
RESOLVE_IMPORT(il2cpp_class_get_methods);
RESOLVE_IMPORT(il2cpp_class_get_method_from_name);
@ -142,6 +256,7 @@ void il2cppfunctions::init(HMODULE game_module)
RESOLVE_IMPORT(il2cpp_runtime_invoke);
RESOLVE_IMPORT(il2cpp_class_get_name);
RESOLVE_IMPORT(il2cpp_class_get_namespace);
RESOLVE_IMPORT(il2cpp_method_get_return_type);
RESOLVE_IMPORT(il2cpp_domain_get_assemblies);
}
uintptr_t il2cppfunctions::get_method_pointer(const char *assemblyName, const char *namespaze,

View File

@ -37,9 +37,8 @@ namespace
return NULL;
return maybe;
}
std::vector<MonoClass *> mono_findklassby_class(std::vector<MonoImage *> &images, const char *_namespace, const char *_class)
std::vector<MonoClass *> loopclass(std::vector<MonoImage *> &images)
{
std::vector<MonoClass *> maybes;
for (auto image : images)
{
@ -54,32 +53,59 @@ namespace
auto klass = (MonoClass *)(SafeFptr(mono_class_get))(image, MONO_TOKEN_TYPE_DEF | i + 1);
if (!klass)
continue;
auto name = (SafeFptr(mono_class_get_name))(klass);
if (!name)
continue;
if (strcmp(name, _class) != 0)
continue;
maybes.push_back(klass);
auto namespacename = (SafeFptr(mono_class_get_namespace))(klass);
if (!namespacename)
continue;
if (strlen(_namespace) && (strcmp(namespacename, _namespace) == 0))
{
return {klass};
}
}
}
return maybes;
}
void tryprintimage(MonoClass *klass)
std::vector<MonoClass *> mono_findklassby_class(std::vector<MonoImage *> &images, const char *_namespace, const char *_class)
{
std::vector<MonoClass *> maybes;
for (auto klass : loopclass(images))
{
auto name = (SafeFptr(mono_class_get_name))(klass);
if (!name)
continue;
if (strcmp(name, _class) != 0)
continue;
maybes.push_back(klass);
auto namespacename = (SafeFptr(mono_class_get_namespace))(klass);
if (!namespacename)
continue;
if (strlen(_namespace) && (strcmp(namespacename, _namespace) == 0))
{
return {klass};
}
}
return maybes;
}
std::optional<std::string> getclassinfo(MonoClass *klass)
{
auto image = (SafeFptr(mono_class_get_image))(klass);
if (!image)
return;
return {};
auto imagen = (SafeFptr(mono_image_get_name))(image);
auto names = (SafeFptr(mono_class_get_namespace))(klass);
if (imagen && names)
ConsoleOutput("%s:%s", imagen, names);
auto classname = (SafeFptr(mono_class_get_name))(klass);
if (imagen && names && classname)
{
std::string _ = imagen;
_ += ":";
_ += names;
_ += ":";
_ += classname;
return _;
}
return {};
}
std::string getmethodinfo(MonoMethod *method)
{
const char *methodName = SafeFptr(mono_method_get_name)(method); // 谜之没有输出
if (!methodName)
methodName = SafeFptr(mono_method_full_name)(method, true);
if (methodName)
return methodName;
return "";
}
uintptr_t getmethodofklass(MonoClass *klass, const char *name, int argsCount)
{
@ -88,7 +114,11 @@ namespace
auto MonoClassMethod = (SafeFptr(mono_class_get_method_from_name))(klass, name, argsCount);
if (!MonoClassMethod)
return NULL;
tryprintimage(klass);
if (auto s = getclassinfo(klass))
{
ConsoleOutput(s.value().c_str());
ConsoleOutput(getmethodinfo(MonoClassMethod).c_str());
}
return (uintptr_t)(SafeFptr(mono_compile_method))(MonoClassMethod);
}
struct AutoThread
@ -108,9 +138,102 @@ namespace
(SafeFptr(mono_thread_detach))(thread);
}
};
void __safe_getxx(monoloopinfo *hps, MonoMethod *method, MonoClass *klass)
{
if (auto methodName = SafeFptr(mono_method_full_name)(method, true))
{
if (auto sig = SafeFptr(mono_method_signature)(method))
{
if (auto cnt = SafeFptr(mono_signature_get_param_count)(sig))
{
gpointer itertype = nullptr;
while (auto type = SafeFptr(mono_signature_get_params)(sig, &itertype))
{
if (auto tp = SafeFptr(mono_type_get_name)(type))
{
if (strcmp(tp, "System.String") == 0)
{
if (auto ptr = (uintptr_t)(SafeFptr(mono_compile_method))(method))
{
std::string meth = methodName;
if (meth.find(" (") != meth.npos)
{
meth = meth.substr(0, meth.find(" ("));
auto _ = strSplit(meth, ":");
if (_.size() >= 2)
{
auto m = _[_.size() - 1];
auto image = (SafeFptr(mono_class_get_image))(klass);
auto imagen = (SafeFptr(mono_image_get_name))(image);
auto names = (SafeFptr(mono_class_get_namespace))(klass);
auto classname = (SafeFptr(mono_class_get_name))(klass);
std::string s;
s = imagen;
s += ":";
s += names;
s += ":";
s += classname;
s += ":";
s += m;
s += ":";
s += std::to_string(cnt);
hps->push_back({ptr, s});
}
}
break;
}
}
}
}
}
}
}
}
void safe_getxx(monoloopinfo *hps, MonoMethod *method, MonoClass *klass)
{
__try
{
__safe_getxx(hps, method, klass);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
}
}
monoloopinfo monofunctions::loop_all_methods(bool show)
{
auto thread = AutoThread();
if (!thread.thread)
return {};
monoloopinfo hps;
auto klasses = loopclass(mono_loop_images());
for (auto klass : klasses)
{
auto s = getclassinfo(klass);
if (!s)
continue;
if (show)
ConsoleOutput(s.value().c_str());
gpointer iter = nullptr;
while (auto method = SafeFptr(mono_class_get_methods)(klass, &iter))
{
if (show)
ConsoleOutput(getmethodinfo(method).c_str());
else
{
safe_getxx(&hps, method, klass);
}
}
}
if (show && klasses.size())
return {{0, ""}};
return hps;
}
void monofunctions::init(HMODULE game_module)
{
RESOLVE_IMPORT(mono_class_get_methods);
RESOLVE_IMPORT(mono_string_chars);
RESOLVE_IMPORT(mono_string_length);
RESOLVE_IMPORT(mono_table_info_get_rows);

View File

@ -1,6 +1,6 @@
#include "mono.h"
#include "mono/monocommon.hpp"
#if 0
namespace
{
bool monobdwgc()
@ -81,8 +81,59 @@ namespace
return suc;
}
}
#endif
#if 0
bool monobdwgc()
{
HMODULE module = GetModuleHandleW(L"mono-2.0-bdwgc.dll");
if (module == 0)
return false;
auto [minAddress, maxAddress] = Util::QueryModuleLimits(module);
BYTE bytes[] = {
0x3D, 0x00, 0x00, 0x01, 0x00,
0x73, XX,
0xb8, 0x03, 0x00, 0x00, 0x00,
0xEB, XX};
auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, minAddress, maxAddress);
auto succ = false;
for (auto addr : addrs)
{
ConsoleOutput("monobdwgcdll %p", addr);
HookParam hp;
hp.address = (DWORD)addr;
hp.offset = regoffset(eax);
hp.type = CODEC_UTF16 | NO_CONTEXT;
succ |= NewHook(hp, "monobdwgcdll");
}
return succ;
}
bool monodll()
{
HMODULE module = GetModuleHandleW(L"mono.dll");
if (module == 0)
return false;
auto [minAddress, maxAddress] = Util::QueryModuleLimits(module);
BYTE bytes[] = {
0x81, 0xFB, XX4,
0x73};
auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, minAddress, maxAddress);
auto succ = false;
for (auto addr : addrs)
{
ConsoleOutput("monodll %p", addr);
HookParam hp;
hp.address = (DWORD)addr;
hp.offset = regoffset(ebx);
hp.type = CODEC_UTF16 | NO_CONTEXT;
succ |= NewHook(hp, "monodll");
}
return succ;
}
#endif
bool mono::attach_function_()
{
bool common = monocommon::hook_mono_il2cpp();
return common;
return monocommon::hook_mono_il2cpp();
}

View File

@ -5,7 +5,7 @@ class mono : public ENGINE
public:
mono()
{
jittype = JITTYPE::UNITY;
check_by = CHECK_BY::CUSTOM;
check_by_target = [this]()
{ return attach_function_(); };

View File

@ -24,7 +24,8 @@ namespace
*/
void SpecialHookMonoString(hook_context *context, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
{
commonsolvemonostring(context->argof(1), buffer);
if (auto sw = commonsolvemonostring(context->argof(1)))
buffer->from(sw.value());
#ifndef _WIN64
auto s = context->ecx;
@ -99,7 +100,7 @@ namespace monocommon
{
hp.type = USING_STRING | CODEC_UTF16 | FULL_STRING;
if (!hp.text_fun)
hp.type |= SPECIAL_JIT_STRING;
hp.type |= CSHARP_STRING;
if (hook.Embed)
hp.type |= EMBED_ABLE;
}
@ -171,7 +172,9 @@ namespace monocommon
succ |= NewHook_check(addr, hook);
}
if (succ)
{
return true;
}
}
return false;
}

View File

@ -24,7 +24,7 @@ namespace
return newstring;
}
}
void commonsolvemonostring(uintptr_t arg, TextBuffer *buffer)
std::optional<std::wstring_view> commonsolvemonostring(uintptr_t arg)
{
auto sw = il2cppfunctions::get_string((void *)arg);
if (!sw)
@ -32,10 +32,10 @@ void commonsolvemonostring(uintptr_t arg, TextBuffer *buffer)
if (!sw)
sw = readmonostring((void *)arg);
if (!sw)
return;
return {};
if (sw.value().size() > TEXT_BUFFER_SIZE)
return;
buffer->from(sw.value());
return {};
return sw;
}
void unity_ui_string_embed_fun(uintptr_t &arg, TextBuffer buff)
@ -55,4 +55,11 @@ uintptr_t tryfindmonoil2cpp(const char *_dll, const char *_namespace, const char
if (addr)
return addr;
return monofunctions::get_method_pointer(_dll, _namespace, _class, _method, paramCoun, strict);
}
std::variant<monoloopinfo, il2cpploopinfo> loop_all_methods(bool show)
{
auto ms = il2cppfunctions::loop_all_methods(show);
if (ms.size())
return ms;
return monofunctions::loop_all_methods(show);
}

View File

@ -1,6 +1,8 @@
#define RESOLVE_IMPORT(name) name = (decltype(name))(GetProcAddress(game_module, #name))
#pragma once
void commonsolvemonostring(uintptr_t arg, TextBuffer *buffer);
std::optional<std::wstring_view> commonsolvemonostring(uintptr_t arg);
void unity_ui_string_embed_fun(uintptr_t &arg, TextBuffer buff);
typedef std::vector<std::pair<int, uintptr_t>> il2cpploopinfo;
typedef std::vector<std::pair<uintptr_t, std::string>> monoloopinfo;
std::variant<monoloopinfo, il2cpploopinfo> loop_all_methods(bool show);
uintptr_t tryfindmonoil2cpp(const char *_dll, const char *_namespace, const char *_class, const char *_method, int paramCoun, bool strict = false);

View File

@ -549,9 +549,6 @@ namespace ppsspp
return false;
trygetgameinwindowtitle();
Load_PSP_ISO_StringFromFormat();
spDefault.isjithook = true;
spDefault.minAddress = 0;
spDefault.maxAddress = -1;
HookParam hp;
hp.address = DoJitPtr; // Jit::DoJit
hp.user_value = (uintptr_t) new uintptr_t;

View File

@ -7,6 +7,7 @@ public:
check_by = CHECK_BY::FILE;
is_engine_certain = false;
check_by_target = L"PPSSPP*.exe";
jittype = JITTYPE::PPSSPP;
};
bool attach_function();
};

View File

@ -14,13 +14,14 @@ namespace
int offset = 0;
JITTYPE jittype;
char text[MAX_STRING_SIZE] = {};
bool csstring;
};
std::unique_ptr<HookRecord[]> records;
long recordsAvailable;
uint64_t signatureCache[CACHE_SIZE] = {};
long sumCache[CACHE_SIZE] = {};
uintptr_t pageCache[CACHE_SIZE] = {};
std::unordered_map<uintptr_t, std::string> remapunityjit;
#ifndef _WIN64
BYTE trampoline[] =
{
@ -123,7 +124,7 @@ bool IsBadReadPtr(void *data)
}
return cacheEntry == BAD_PAGE;
}
void DoSend(int i, uintptr_t address, char *str, intptr_t padding, JITTYPE jittype = JITTYPE::PC, uint64_t em_addr = 0)
void DoSend(int i, uintptr_t address, char *str, intptr_t padding, JITTYPE jittype = JITTYPE::PC, uint64_t em_addr = 0, bool csstring = false)
{
str += padding;
if (IsBadReadPtr(str) || IsBadReadPtr(str + MAX_STRING_SIZE))
@ -156,7 +157,13 @@ void DoSend(int i, uintptr_t address, char *str, intptr_t padding, JITTYPE jitty
{
records[n].jittype = jittype;
records[n].padding = padding;
if (jittype == JITTYPE::PC)
records[n].csstring = csstring;
if (csstring)
{
records[n].address = address;
records[n].offset = i;
}
else if (jittype == JITTYPE::PC)
{
records[n].address = address;
records[n].offset = i * sizeof(char *);
@ -195,6 +202,24 @@ void Send(char **strs, uintptr_t address)
DoSend(i, address, strs[i], sp.padding);
}
}
template <JITTYPE t>
void SendCSharpString(char **strs, uintptr_t address)
{
// it is unsafe to call ANY external functions from this, as they may have been hooked (if called the hook would call this function making an infinite loop)
// the exceptions are compiler intrinsics like _InterlockedDecrement
if (recordsAvailable <= 0)
return;
for (int i = 0; i < 10; ++i)
{
__try
{
DoSend(i, address, (char *)commonsolvemonostring(hook_context::fromBase((uintptr_t)strs)->argof(i)).value().data(), 0, t, 0, true);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
}
}
void SafeSendJitVeh(hook_context *context, uintptr_t address, uint64_t em_addr, JITTYPE jittype, intptr_t padding)
{
__try
@ -289,8 +314,18 @@ void SearchForHooks_Return()
hp.jittype = records[i].jittype;
hp.padding = records[i].padding;
hp.offset = records[i].offset;
if (records[i].jittype == JITTYPE::PC)
if (records[i].csstring)
{
if (!records[i].address)
continue;
hp.type = CODEC_UTF16 | USING_STRING | CSHARP_STRING;
hp.address = records[i].address;
if (hp.jittype == JITTYPE::UNITY)
{
strncpy(hp.function, remapunityjit[hp.address].c_str(), sizeof(hp.function));
}
}
else if (records[i].jittype == JITTYPE::PC)
{
if (!records[i].address)
continue;
@ -325,182 +360,235 @@ void initrecords()
}
while (!records && sp.maxRecords);
}
void inlinehookpipeline(std::vector<uintptr_t> &addresses)
{
auto trampolines = (decltype(trampoline) *)VirtualAlloc(NULL, sizeof(trampoline) * addresses.size(), MEM_COMMIT, PAGE_READWRITE);
VirtualProtect(trampolines, addresses.size() * sizeof(trampoline), PAGE_EXECUTE_READWRITE, DUMMY);
std::vector<uintptr_t> mherroridx;
for (int i = 0; i < addresses.size(); ++i)
{
void *original;
// 避免MH_RemoveHook时移除原本已有hook
if (MH_CreateHook((void *)addresses[i], trampolines[i], &original) != MH_OK)
{
mherroridx.push_back(i);
}
MH_QueueEnableHook((void *)addresses[i]);
memcpy(trampolines[i], trampoline, sizeof(trampoline));
*(uintptr_t *)(trampolines[i] + addr_offset) = addresses[i];
*(void **)(trampolines[i] + original_offset) = original;
if (i % 2500 == 0)
ConsoleOutput(TR[HOOK_SEARCH_INITIALIZING], 1 + 98. * i / addresses.size());
}
// 避免MH_RemoveHook时移除原本已有hook
for (int i = 0; i < mherroridx.size(); i++)
{
auto reverseidx = mherroridx[mherroridx.size() - 1 - i];
addresses.erase(addresses.begin() + reverseidx);
}
ConsoleOutput(TR[HOOK_SEARCH_INITIALIZED], addresses.size());
MH_ApplyQueued();
ConsoleOutput(TR[HOOK_SEARCH_STARTING]);
ConsoleOutput(TR[MAKE_GAME_PROCESS_TEXT], sp.searchTime / 1000);
Sleep(sp.searchTime);
for (auto addr : addresses)
MH_QueueDisableHook((void *)addr);
MH_ApplyQueued();
Sleep(1000);
for (auto addr : addresses)
MH_RemoveHook((void *)addr);
VirtualFree(trampolines, 0, MEM_RELEASE);
}
void _SearchForHooks(SearchParam spUser)
{
static std::mutex m;
std::scoped_lock lock(m);
ConsoleOutput(TR[HOOK_SEARCH_INITIALIZING], 0.);
sp = spUser.length == 0 ? spDefault : spUser;
sp.codepage = spUser.codepage;
initrecords();
if ((!sp.isjithook) || (jittypedefault == JITTYPE::PC))
{
*(void **)(trampoline + send_offset) = Send;
std::vector<uintptr_t> addresses;
if (*sp.boundaryModule)
{
auto [minaddr, maxaddr] = Util::QueryModuleLimits(GetModuleHandleW(sp.boundaryModule));
if (sp.address_method == 0)
{
sp.minAddress = min(max(minaddr, sp.minAddress), maxaddr);
sp.maxAddress = max(min(maxaddr, sp.maxAddress), minaddr);
}
else if (sp.address_method == 1)
{
auto maxoff = maxaddr - minaddr;
sp.minAddress = minaddr + min(sp.minAddress, maxoff);
sp.maxAddress = minaddr + min(sp.maxAddress, maxoff);
}
// std::tie(sp.minAddress, sp.maxAddress) = Util::QueryModuleLimits(GetModuleHandleW(sp.boundaryModule));
}
if (*sp.exportModule)
addresses = GetFunctions((uintptr_t)GetModuleHandleW(sp.exportModule));
if (*sp.boundaryModule)
{
auto _addresses = GetFunctions((uintptr_t)GetModuleHandleW(sp.boundaryModule));
mergevector(addresses, _addresses);
}
std::vector<uintptr_t> addresses1;
if (sp.search_method == 0)
{
for (auto &addr : addresses1 = Util::SearchMemory(sp.pattern, sp.length, PAGE_EXECUTE, sp.minAddress, sp.maxAddress))
addr += sp.offset;
}
else if (sp.search_method == 1)
{
auto checklength = 3;
auto checker = [checklength](DWORD k)
{
if (k == 0xcccccccc || k == 0x90909090 || k == 0xccccccc3 || k == 0x909090c3)
return true;
DWORD t = k & 0xff0000ff;
if (t == 0xcc0000c2 || t == 0x900000c2)
return true;
if (checklength == 4)
return false;
k >>= 8;
if (k == 0xccccc3 || k == 0x9090c3)
return true;
if (checklength == 3)
return false;
// t = k & 0xff;
// if (t == 0xc2)
// return true;
k >>= 8;
if (k == 0xccc3 || k == 0x90c3)
return true;
if (checklength == 2)
return false;
k >>= 8;
if (k == 0xc3)
return true;
return false;
};
for (uintptr_t addr = sp.minAddress & ~0xf; addr < sp.maxAddress; addr += 0x10)
{
if (IsBadReadPtr((void *)(addr - 0x10), 0x110))
{
addr += 0x100 - 0x10;
continue;
}
auto need = checker(*(DWORD *)(addr - 4));
if (need)
addresses1.push_back(addr);
}
}
else if (sp.search_method == 2)
{
for (uintptr_t addr = sp.minAddress; addr < sp.maxAddress; addr++)
{
if (IsBadReadPtr((void *)addr, 0x100))
{
addr += 0x100 - 1;
continue;
}
if (((*(BYTE *)addr) == 0xe8))
{
auto off = *(DWORD *)(addr + 1);
auto funcaddr = addr + 5 + off;
if (sp.minAddress < funcaddr && sp.maxAddress > funcaddr)
{
auto it = std::find(addresses1.begin(), addresses1.end(), funcaddr);
addresses1.push_back(funcaddr);
}
}
}
}
mergevector(addresses, addresses1);
auto limits = Util::QueryModuleLimits(GetModuleHandleW(LUNA_HOOK_DLL));
addresses.erase(std::remove_if(addresses.begin(), addresses.end(), [&](auto addr)
{ return addr > limits.first && addr < limits.second; }),
addresses.end());
inlinehookpipeline(addresses);
}
else if (jittypedefault == JITTYPE::UNITY)
{
auto methods = loop_all_methods(false);
try
{
*(void **)(trampoline + send_offset) = SendCSharpString<JITTYPE::PC>;
std::vector<uintptr_t> addrs;
for (auto [_, addr] : std::get<il2cpploopinfo>(methods))
addrs.push_back(addr);
inlinehookpipeline(addrs);
}
catch (std::bad_variant_access const &ex)
{
*(void **)(trampoline + send_offset) = SendCSharpString<JITTYPE::UNITY>;
auto functions = std::get<monoloopinfo>(methods);
std::vector<uintptr_t> addrs;
for (auto [addr, func] : functions)
{
addrs.push_back(addr);
remapunityjit[addr] = func;
}
inlinehookpipeline(addrs);
}
}
else
{
safeautoleaveveh = false;
std::vector<uint64_t> successaddr;
uintptr_t minemaddr = -1, maxemaddr = 0;
ConsoleOutput(TR[HOOK_SEARCH_INITIALIZED], jitaddr2emuaddr.size());
for (auto addr : jitaddr2emuaddr)
{
minemaddr = min(minemaddr, addr.second.second);
maxemaddr = max(maxemaddr, addr.second.second);
}
ConsoleOutput("%p %p", minemaddr, maxemaddr);
ConsoleOutput("%p %p", sp.minAddress, sp.maxAddress);
#if DUMP_JIT_ADDR_MAP
auto f = fopen("1.txt", "a");
for (auto addr : jitaddr2emuaddr)
{
fprintf(f, "%llx => %llx\n", addr.second.second, addr.first);
}
fclose(f);
#endif
for (auto addr : jitaddr2emuaddr)
{
// ConsoleOutput("%llx => %p", addr.second.second ,addr.first);
if (addr.second.second > sp.maxAddress || addr.second.second < sp.minAddress)
continue;
// addresses.push_back(addr.first);
if (add_veh_hook((void *)addr.first, std::bind(SendJitVeh, std::placeholders::_1, addr.first, addr.second.second, addr.second.first, sp.padding)))
successaddr.push_back(addr.first);
if (successaddr.size() % 2500 == 0)
ConsoleOutput(TR[HOOK_SEARCH_INITIALIZING], 1 + 98. * successaddr.size() / jitaddr2emuaddr.size());
}
ConsoleOutput(TR[HOOK_SEARCH_INITIALIZED], successaddr.size());
ConsoleOutput(TR[MAKE_GAME_PROCESS_TEXT], sp.searchTime / 1000);
Sleep(sp.searchTime);
// for(auto addr:successaddr){
// remove_veh_hook((void*)addr);
// }
safeautoleaveveh = true;
}
SearchForHooks_Return();
}
void SearchForHooks(SearchParam spUser)
{
std::thread([=]
{
static std::mutex m;
std::scoped_lock lock(m);
*(void**)(trampoline + send_offset) = Send;
ConsoleOutput(TR[HOOK_SEARCH_INITIALIZING], 0.);
sp = spUser.length == 0 ? spDefault : spUser;
sp.codepage=spUser.codepage;
initrecords();
std::vector<uintptr_t> addresses;
if( !sp.isjithook)
{
if (*sp.boundaryModule) {
auto [minaddr,maxaddr]=Util::QueryModuleLimits(GetModuleHandleW(sp.boundaryModule));
if(sp.address_method==0){
sp.minAddress=min(max(minaddr,sp.minAddress),maxaddr);
sp.maxAddress=max(min(maxaddr,sp.maxAddress),minaddr);
}
else if(sp.address_method==1){
auto maxoff=maxaddr-minaddr;
sp.minAddress=minaddr+min(sp.minAddress,maxoff);
sp.maxAddress=minaddr+min(sp.maxAddress,maxoff);
}
//std::tie(sp.minAddress, sp.maxAddress) = Util::QueryModuleLimits(GetModuleHandleW(sp.boundaryModule));
}
if (*sp.exportModule) addresses = GetFunctions((uintptr_t)GetModuleHandleW(sp.exportModule));
if (*sp.boundaryModule){
auto _addresses = GetFunctions((uintptr_t)GetModuleHandleW(sp.boundaryModule));
mergevector(addresses,_addresses);
}
std::vector<uintptr_t> addresses1;
if(sp.search_method==0){
for (auto& addr : addresses1 = Util::SearchMemory(sp.pattern, sp.length, PAGE_EXECUTE, sp.minAddress, sp.maxAddress))
addr += sp.offset;
}
else if(sp.search_method==1){
auto checklength=3;
auto checker=[checklength](DWORD k){
if (k == 0xcccccccc
|| k == 0x90909090
|| k == 0xccccccc3
|| k == 0x909090c3
)
return true;
DWORD t = k & 0xff0000ff;
if (t == 0xcc0000c2 || t == 0x900000c2)
return true;
if(checklength==4)return false;
k >>= 8;
if (k == 0xccccc3 || k == 0x9090c3)
return true;
if(checklength==3)return false;
// t = k & 0xff;
// if (t == 0xc2)
// return true;
k >>= 8;
if (k == 0xccc3 || k == 0x90c3)
return true;
if(checklength==2)return false;
k >>= 8;
if (k == 0xc3)
return true;
return false;
};
for(uintptr_t addr=sp.minAddress& ~0xf;addr<sp.maxAddress;addr+=0x10){
if(IsBadReadPtr((void*)(addr-0x10),0x110)){
addr+=0x100-0x10;
continue;
}
auto need=checker(*(DWORD *)(addr-4));
if (need)
addresses1.push_back(addr);
}
}
else if(sp.search_method==2){
for(uintptr_t addr=sp.minAddress;addr<sp.maxAddress;addr++){
if(IsBadReadPtr((void*)addr,0x100)){
addr+=0x100-1;
continue;
}
if(((*(BYTE*)addr)==0xe8)){
auto off=*(DWORD*)(addr+1);
auto funcaddr=addr+5+off;
if(sp.minAddress<funcaddr && sp.maxAddress>funcaddr){
auto it = std::find(addresses1.begin(), addresses1.end(), funcaddr);
addresses1.push_back(funcaddr);
}
}
}
}
mergevector(addresses,addresses1);
auto limits = Util::QueryModuleLimits(GetModuleHandleW(LUNA_HOOK_DLL));
addresses.erase(std::remove_if(addresses.begin(), addresses.end(), [&](auto addr) { return addr > limits.first && addr < limits.second; }), addresses.end());
auto trampolines = (decltype(trampoline)*)VirtualAlloc(NULL, sizeof(trampoline) * addresses.size(), MEM_COMMIT, PAGE_READWRITE);
VirtualProtect(trampolines, addresses.size() * sizeof(trampoline), PAGE_EXECUTE_READWRITE, DUMMY);
std::vector<uintptr_t>mherroridx;
for (int i = 0; i < addresses.size(); ++i)
{
void* original;
//避免MH_RemoveHook时移除原本已有hook
if(MH_CreateHook((void*)addresses[i], trampolines[i], &original)!=MH_OK){
mherroridx.push_back(i);
}
MH_QueueEnableHook((void*)addresses[i]);
memcpy(trampolines[i], trampoline, sizeof(trampoline));
*(uintptr_t*)(trampolines[i] + addr_offset) = addresses[i];
*(void**)(trampolines[i] + original_offset) = original;
if (i % 2500 == 0) ConsoleOutput(TR[HOOK_SEARCH_INITIALIZING], 1 + 98. * i / addresses.size());
}
//避免MH_RemoveHook时移除原本已有hook
for(int i=0;i<mherroridx.size();i++){
auto reverseidx=mherroridx[mherroridx.size()-1-i];
addresses.erase(addresses.begin()+reverseidx);
}
ConsoleOutput(TR[HOOK_SEARCH_INITIALIZED], addresses.size());
MH_ApplyQueued();
ConsoleOutput(TR[HOOK_SEARCH_STARTING]);
ConsoleOutput(TR[MAKE_GAME_PROCESS_TEXT], sp.searchTime / 1000);
Sleep(sp.searchTime);
for (auto addr : addresses) MH_QueueDisableHook((void*)addr);
MH_ApplyQueued();
Sleep(1000);
for (auto addr : addresses) MH_RemoveHook((void*)addr);
VirtualFree(trampolines, 0, MEM_RELEASE);
SearchForHooks_Return();
}
else
{
safeautoleaveveh=false;
int i=0;
std::vector<uint64_t>successaddr;
uintptr_t minemaddr=-1,maxemaddr=0;
ConsoleOutput(TR[HOOK_SEARCH_INITIALIZED], jitaddr2emuaddr.size());
for(auto addr:jitaddr2emuaddr){
minemaddr=min(minemaddr,addr.second.second);
maxemaddr=max(maxemaddr,addr.second.second);
}
ConsoleOutput("%p %p",minemaddr,maxemaddr);
ConsoleOutput("%p %p",sp.minAddress,sp.maxAddress);
#if DUMP_JIT_ADDR_MAP
auto f=fopen("1.txt","a");
for(auto addr:jitaddr2emuaddr){
fprintf(f,"%llx => %llx\n", addr.second.second ,addr.first);
}
fclose(f);
#endif
for(auto addr:jitaddr2emuaddr){
//ConsoleOutput("%llx => %p", addr.second.second ,addr.first);
if(addr.second.second>sp.maxAddress||addr.second.second<sp.minAddress)continue;
i+=1;
//addresses.push_back(addr.first);
if(add_veh_hook((void*)addr.first,std::bind(SendJitVeh,std::placeholders::_1,addr.first,addr.second.second,addr.second.first,sp.padding)))
successaddr.push_back(addr.first);
if (i % 2500 == 0) ConsoleOutput(TR[HOOK_SEARCH_INITIALIZING], 1 + 98. * i / jitaddr2emuaddr.size());
}
ConsoleOutput(TR[HOOK_SEARCH_INITIALIZED], i);
ConsoleOutput(TR[MAKE_GAME_PROCESS_TEXT], sp.searchTime / 1000);
Sleep(sp.searchTime);
// for(auto addr:successaddr){
// remove_veh_hook((void*)addr);
// }
safeautoleaveveh=true;
SearchForHooks_Return();
} })
std::thread(_SearchForHooks, spUser)
.detach();
}

View File

@ -278,6 +278,11 @@ bool NewHook(HookParam hp, LPCSTR name)
return NewHook_1(hp, name);
if (hp.jittype == JITTYPE::UNITY)
{
if (strcmp(hp.function, "?") == 0)
{
loop_all_methods(true);
return false;
}
auto spls = strSplit(hp.function, ":");
if (spls.size() != 5)
{

View File

@ -15,6 +15,7 @@ bool NewHookJit(HookParam hp, LPCSTR name);
void RemoveHook(uint64_t addr, int maxOffset = 9);
std::string LoadResData(LPCWSTR pszResID, LPCWSTR _type);
inline SearchParam spDefault;
inline JITTYPE jittypedefault = JITTYPE::PC;
// EOF
int HookStrLen(HookParam *, BYTE *data);

View File

@ -289,7 +289,7 @@ void TextHook::Send(hook_context *context)
lpDataIn = jitgetaddr(context, &hp, true);
plpdatain = &lpDataIn;
}
else if (hp.jittype == JITTYPE::UNITY)
else if (hp.jittype == JITTYPE::UNITY || hp.type & CSHARP_STRING)
{
plpdatain = &context->argof(hp.offset);
lpDataIn = *plpdatain;
@ -299,10 +299,10 @@ void TextHook::Send(hook_context *context)
{
hp.text_fun(context, &hp, &buff, &lpSplit);
}
else if (hp.type & SPECIAL_JIT_STRING)
else if (hp.type & CSHARP_STRING)
{
if (hp.jittype == JITTYPE::UNITY)
commonsolvemonostring(lpDataIn, &buff);
if (auto sw = commonsolvemonostring(lpDataIn))
buff.from(sw.value());
}
else
{
@ -351,7 +351,7 @@ void TextHook::Send(hook_context *context)
*(WORD *)buff.buff = lpDataIn & 0xffff;
}
}
else if ((!hp.text_fun) && (!(hp.type & SPECIAL_JIT_STRING)))
else if ((!hp.text_fun) && (!(hp.type & CSHARP_STRING)))
{
if (lpDataIn == 0)
__leave;
@ -423,10 +423,9 @@ void TextHook::Send(hook_context *context)
}
else if (hp.embed_fun)
hp.embed_fun(context, buff);
else if (hp.type & SPECIAL_JIT_STRING)
else if (hp.type & CSHARP_STRING)
{
if (hp.jittype == JITTYPE::UNITY)
unity_ui_string_embed_fun(context->argof(hp.offset), buff);
unity_ui_string_embed_fun(context->argof(hp.offset), buff);
}
}
}

View File

@ -81,6 +81,135 @@ namespace
}
return f64bitProc;
}
void __handlepipethread(HANDLE hookPipe, HANDLE hostPipe, HANDLE pipeAvailableEvent)
{
ConnectNamedPipe(hookPipe, nullptr);
CloseHandle(pipeAvailableEvent);
WORD hookversion[4];
BYTE buffer[PIPE_BUFFER_SIZE] = {};
DWORD bytesRead, processId;
ReadFile(hookPipe, &processId, sizeof(processId), &bytesRead, nullptr);
ReadFile(hookPipe, hookversion, sizeof(hookversion), &bytesRead, nullptr);
if (memcmp(hookversion, LUNA_VERSION, sizeof(hookversion)) != 0)
Host::InfoOutput(HOSTINFO::Warning, TR[UNMATCHABLEVERSION]);
processRecordsByIds->try_emplace(processId, processId, hostPipe);
processRecordsByIds->at(processId).Send(curr_lang);
OnConnect(processId);
Host::AddConsoleOutput(FormatString(TR[PROC_CONN], processId));
while (ReadFile(hookPipe, buffer, PIPE_BUFFER_SIZE, &bytesRead, nullptr))
switch (*(HostNotificationType *)buffer)
{
case HOST_NOTIFICATION_FOUND_HOOK:
{
auto info = *(HookFoundNotif *)buffer;
auto OnHookFound = processRecordsByIds->at(processId).OnHookFound;
std::wstring wide = info.text;
if (wide.size() > STRING)
{
wcscpy_s(info.hp.hookcode, HOOKCODE_LEN, HookCode::Generate(info.hp, processId).c_str());
OnHookFound(info.hp, std::move(info.text));
}
if (!(info.hp.type & CSHARP_STRING))
{
info.hp.type &= ~CODEC_UTF16;
if (auto converted = StringToWideString((char *)info.text, info.hp.codepage))
#if SEARCH_SJIS_UNSAFE
if (converted->size())
#else
if (converted->size() > STRING)
#endif
{
wcscpy_s(info.hp.hookcode, HOOKCODE_LEN, HookCode::Generate(info.hp, processId).c_str());
OnHookFound(info.hp, std::move(converted.value()));
}
if (auto converted = StringToWideString((char *)info.text, info.hp.codepage = CP_UTF8))
if (converted->size() > STRING)
{
wcscpy_s(info.hp.hookcode, HOOKCODE_LEN, HookCode::Generate(info.hp, processId).c_str());
OnHookFound(info.hp, std::move(converted.value()));
}
}
}
break;
case HOST_NOTIFICATION_RMVHOOK:
{
auto info = *(HookRemovedNotif *)buffer;
auto sm = Host::GetCommonSharedMem(processId);
if (sm)
for (int i = 0; i < ARRAYSIZE(sm->embedtps); i++)
if (sm->embedtps[i].use && (sm->embedtps[i].tp.addr == info.address) && (sm->embedtps[i].tp.processId == processId))
ZeroMemory(sm->embedtps + i, sizeof(sm->embedtps[i]));
RemoveThreads([&](ThreadParam tp)
{ return tp.processId == processId && tp.addr == info.address; });
}
break;
case HOST_NOTIFICATION_INSERTING_HOOK:
{
if (HookInsert)
{
auto info = (HookInsertingNotif *)buffer;
HookInsert(processId, info->addr, info->hookcode);
}
}
break;
case HOST_NOTIFICATION_TEXT:
{
auto info = *(HostInfoNotif *)buffer;
Host::InfoOutput(info.type, StringToWideString(info.message));
}
break;
default:
{
auto data = (TextOutput_T *)buffer;
auto length = bytesRead - sizeof(TextOutput_T);
auto tp = data->tp;
auto hp = data->hp;
auto _textThreadsByParams = textThreadsByParams.Acquire();
auto thread = _textThreadsByParams->find(tp);
if (thread == _textThreadsByParams->end())
{
try
{
thread = _textThreadsByParams->try_emplace(tp, tp, hp).first;
}
catch (std::out_of_range)
{
continue;
} // probably garbage data in pipe, try again
OnCreate(thread->second);
}
thread->second.hp.type = data->type;
thread->second.Push(data->data, length);
if (embedcallback)
{
auto &hp = thread->second.hp;
if (hp.type & EMBED_ABLE && Host::CheckIsUsingEmbed(thread->second.tp))
{
if (auto t = commonparsestring(data->data, length, &hp, Host::defaultCodepage))
{
auto text = t.value();
if (text.size())
{
embedcallback(text, tp);
}
}
}
}
}
break;
}
RemoveThreads([&](ThreadParam tp)
{ return tp.processId == processId; });
OnDisconnect(processId);
Host::AddConsoleOutput(FormatString(TR[PROC_DISCONN], processId));
processRecordsByIds->erase(processId);
}
void CreatePipe(int pid)
{
HANDLE
@ -89,119 +218,7 @@ namespace
HANDLE pipeAvailableEvent = CreateEventW(&allAccess, FALSE, FALSE, (std::wstring(PIPE_AVAILABLE_EVENT) + std::to_wstring(pid)).c_str());
SetEvent(pipeAvailableEvent);
std::thread([hookPipe, hostPipe, pipeAvailableEvent]
{
ConnectNamedPipe(hookPipe, nullptr);
CloseHandle(pipeAvailableEvent);
WORD hookversion[4];
BYTE buffer[PIPE_BUFFER_SIZE] = {};
DWORD bytesRead, processId;
ReadFile(hookPipe, &processId, sizeof(processId), &bytesRead, nullptr);
ReadFile(hookPipe, hookversion, sizeof(hookversion), &bytesRead, nullptr);
if(memcmp(hookversion,LUNA_VERSION,sizeof(hookversion))!=0)
Host::InfoOutput(HOSTINFO::Warning, TR[UNMATCHABLEVERSION]);
processRecordsByIds->try_emplace(processId, processId, hostPipe);
processRecordsByIds->at(processId).Send(curr_lang);
OnConnect(processId);
Host::AddConsoleOutput(FormatString(TR[PROC_CONN],processId));
while (ReadFile(hookPipe, buffer, PIPE_BUFFER_SIZE, &bytesRead, nullptr))
switch (*(HostNotificationType*)buffer)
{
case HOST_NOTIFICATION_FOUND_HOOK:
{
auto info = *(HookFoundNotif*)buffer;
auto OnHookFound = processRecordsByIds->at(processId).OnHookFound;
std::wstring wide = info.text;
if (wide.size() > STRING) {
wcscpy_s(info.hp.hookcode,HOOKCODE_LEN, HookCode::Generate(info.hp, processId).c_str());
OnHookFound(info.hp, std::move(info.text));
}
info.hp.type &= ~CODEC_UTF16;
if (auto converted = StringToWideString((char*)info.text, info.hp.codepage))
#if SEARCH_SJIS_UNSAFE
if (converted->size())
#else
if (converted->size() > STRING)
#endif
{
wcscpy_s(info.hp.hookcode,HOOKCODE_LEN, HookCode::Generate(info.hp, processId).c_str());
OnHookFound(info.hp, std::move(converted.value()));
}
if (auto converted = StringToWideString((char*)info.text, info.hp.codepage = CP_UTF8))
if (converted->size() > STRING)
{
wcscpy_s(info.hp.hookcode,HOOKCODE_LEN, HookCode::Generate(info.hp, processId).c_str());
OnHookFound(info.hp, std::move(converted.value()));
}
}
break;
case HOST_NOTIFICATION_RMVHOOK:
{
auto info = *(HookRemovedNotif*)buffer;
auto sm = Host::GetCommonSharedMem(processId);
if (sm)
for (int i = 0; i < ARRAYSIZE(sm->embedtps); i++)
if (sm->embedtps[i].use && (sm->embedtps[i].tp.addr==info.address)&&(sm->embedtps[i].tp.processId==processId))
ZeroMemory(sm->embedtps + i, sizeof(sm->embedtps[i]));
RemoveThreads([&](ThreadParam tp) { return tp.processId == processId && tp.addr == info.address; });
}
break;
case HOST_NOTIFICATION_INSERTING_HOOK:
{
if(HookInsert){
auto info = (HookInsertingNotif*)buffer;
HookInsert(processId, info->addr,info->hookcode);
}
}
break;
case HOST_NOTIFICATION_TEXT:
{
auto info = *(HostInfoNotif*)buffer;
Host::InfoOutput(info.type, StringToWideString(info.message));
}
break;
default:
{
auto data=(TextOutput_T*)buffer;
auto length= bytesRead - sizeof(TextOutput_T);
auto tp = data->tp;
auto hp=data->hp;
auto _textThreadsByParams=textThreadsByParams.Acquire();
auto thread = _textThreadsByParams->find(tp);
if (thread == _textThreadsByParams->end())
{
try { thread = _textThreadsByParams->try_emplace(tp, tp, hp).first; }
catch (std::out_of_range) { continue; } // probably garbage data in pipe, try again
OnCreate(thread->second);
}
thread->second.hp.type=data->type;
thread->second.Push(data->data, length);
if(embedcallback){
auto & hp=thread->second.hp;
if(hp.type&EMBED_ABLE && Host::CheckIsUsingEmbed(thread->second.tp)){
if (auto t=commonparsestring(data->data,length,&hp,Host::defaultCodepage)){
auto text=t.value();
if(text.size()){
embedcallback(text,tp);
}
}
}
}
}
break;
}
RemoveThreads([&](ThreadParam tp) { return tp.processId == processId; });
OnDisconnect(processId);
Host::AddConsoleOutput(FormatString(TR[PROC_DISCONN],processId));
processRecordsByIds->erase(processId); })
.detach();
std::thread(__handlepipethread, hookPipe, hostPipe, pipeAvailableEvent).detach();
}
}

View File

@ -64,7 +64,7 @@ enum HookParamType : uint64_t
NEXT_MASK(USING_CHAR), // text_fun!=nullptr && (CODE_ANSI_BE||CODE_UTF16)
NEXT_MASK(USING_STRING),
NEXT_MASK(SPECIAL_JIT_STRING),
NEXT_MASK(CSHARP_STRING),
NEXT_MASK(FULL_STRING),

View File

@ -96,7 +96,7 @@ namespace
hp.type |= USING_STRING | CODEC_UTF16;
break;
case L'M':
hp.type |= USING_STRING | CODEC_UTF16 | SPECIAL_JIT_STRING;
hp.type |= USING_STRING | CODEC_UTF16 | CSHARP_STRING;
break;
case L'U':
hp.type |= USING_STRING | CODEC_UTF32;
@ -313,7 +313,7 @@ namespace
if (hp.type & USING_STRING)
{
if (hp.type & SPECIAL_JIT_STRING)
if (hp.type & CSHARP_STRING)
HCode += L'M';
else if (hp.type & CODEC_UTF16)
HCode += L'Q';

View File

@ -1,7 +1,7 @@
set(VERSION_MAJOR 6)
set(VERSION_MINOR 14)
set(VERSION_PATCH 4)
set(VERSION_PATCH 5)
set(VERSION_REVISION 0)
set(LUNA_VERSION "{${VERSION_MAJOR},${VERSION_MINOR},${VERSION_PATCH},${VERSION_REVISION}}")
add_library(VERSION_DEF ${CMAKE_CURRENT_LIST_DIR}/version_def.cpp)