diff --git a/cpp/LunaHook/LunaHook/CMakeLists.txt b/cpp/LunaHook/LunaHook/CMakeLists.txt index 8fe8713a..5dda722e 100644 --- a/cpp/LunaHook/LunaHook/CMakeLists.txt +++ b/cpp/LunaHook/LunaHook/CMakeLists.txt @@ -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 diff --git a/cpp/LunaHook/LunaHook/engine.h b/cpp/LunaHook/LunaHook/engine.h index fe5f1a63..e71f0ed1 100644 --- a/cpp/LunaHook/LunaHook/engine.h +++ b/cpp/LunaHook/LunaHook/engine.h @@ -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(); }; diff --git a/cpp/LunaHook/LunaHook/engine32/mono.cpp b/cpp/LunaHook/LunaHook/engine32/mono.cpp deleted file mode 100644 index 336c2b55..00000000 --- a/cpp/LunaHook/LunaHook/engine32/mono.cpp +++ /dev/null @@ -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; -} \ No newline at end of file diff --git a/cpp/LunaHook/LunaHook/engine64/mono.h b/cpp/LunaHook/LunaHook/engine64/mono.h deleted file mode 100644 index e180a0c2..00000000 --- a/cpp/LunaHook/LunaHook/engine64/mono.h +++ /dev/null @@ -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; } -}; diff --git a/cpp/LunaHook/LunaHook/engine64/rpcs3.cpp b/cpp/LunaHook/LunaHook/engine64/rpcs3.cpp index d1ce5b70..6f07f6c5 100644 --- a/cpp/LunaHook/LunaHook/engine64/rpcs3.cpp +++ b/cpp/LunaHook/LunaHook/engine64/rpcs3.cpp @@ -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) diff --git a/cpp/LunaHook/LunaHook/engine64/rpcs3.h b/cpp/LunaHook/LunaHook/engine64/rpcs3.h index fc8ae091..20d72cf1 100644 --- a/cpp/LunaHook/LunaHook/engine64/rpcs3.h +++ b/cpp/LunaHook/LunaHook/engine64/rpcs3.h @@ -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"; diff --git a/cpp/LunaHook/LunaHook/engine64/vita3k.cpp b/cpp/LunaHook/LunaHook/engine64/vita3k.cpp index 15ac8f0e..a06099dd 100644 --- a/cpp/LunaHook/LunaHook/engine64/vita3k.cpp +++ b/cpp/LunaHook/LunaHook/engine64/vita3k.cpp @@ -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) diff --git a/cpp/LunaHook/LunaHook/engine64/vita3k.h b/cpp/LunaHook/LunaHook/engine64/vita3k.h index 20162d07..f642d2f2 100644 --- a/cpp/LunaHook/LunaHook/engine64/vita3k.h +++ b/cpp/LunaHook/LunaHook/engine64/vita3k.h @@ -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"; diff --git a/cpp/LunaHook/LunaHook/engine64/yuzu.cpp b/cpp/LunaHook/LunaHook/engine64/yuzu.cpp index 80b98628..d27843ed 100644 --- a/cpp/LunaHook/LunaHook/engine64/yuzu.cpp +++ b/cpp/LunaHook/LunaHook/engine64/yuzu.cpp @@ -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) diff --git a/cpp/LunaHook/LunaHook/engine64/yuzu.h b/cpp/LunaHook/LunaHook/engine64/yuzu.h index 2e45b37e..19081b32 100644 --- a/cpp/LunaHook/LunaHook/engine64/yuzu.h +++ b/cpp/LunaHook/LunaHook/engine64/yuzu.h @@ -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 = []() diff --git a/cpp/LunaHook/LunaHook/enginecollection32.cpp b/cpp/LunaHook/LunaHook/enginecollection32.cpp index 4ce023cf..e7b9bdef 100644 --- a/cpp/LunaHook/LunaHook/enginecollection32.cpp +++ b/cpp/LunaHook/LunaHook/enginecollection32.cpp @@ -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" diff --git a/cpp/LunaHook/LunaHook/enginecollection64.cpp b/cpp/LunaHook/LunaHook/enginecollection64.cpp index 7bfd7ce6..cdcd156b 100644 --- a/cpp/LunaHook/LunaHook/enginecollection64.cpp +++ b/cpp/LunaHook/LunaHook/enginecollection64.cpp @@ -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" diff --git a/cpp/LunaHook/LunaHook/enginecontrol.cpp b/cpp/LunaHook/LunaHook/enginecontrol.cpp index cd319978..a77c674e 100644 --- a/cpp/LunaHook/LunaHook/enginecontrol.cpp +++ b/cpp/LunaHook/LunaHook/enginecontrol.cpp @@ -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; } diff --git a/cpp/LunaHook/LunaHook/engines/CMakeLists.txt b/cpp/LunaHook/LunaHook/engines/CMakeLists.txt index 63c0e162..c8185182 100644 --- a/cpp/LunaHook/LunaHook/engines/CMakeLists.txt +++ b/cpp/LunaHook/LunaHook/engines/CMakeLists.txt @@ -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) diff --git a/cpp/LunaHook/LunaHook/engines/mono/def_il2cpp.hpp b/cpp/LunaHook/LunaHook/engines/mono/def_il2cpp.hpp index 7ca2b2d9..57245507 100644 --- a/cpp/LunaHook/LunaHook/engines/mono/def_il2cpp.hpp +++ b/cpp/LunaHook/LunaHook/engines/mono/def_il2cpp.hpp @@ -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 get_string(void *); void *create_string(std::wstring_view ws); + il2cpploopinfo loop_all_methods(bool show); } \ No newline at end of file diff --git a/cpp/LunaHook/LunaHook/engines/mono/def_mono.hpp b/cpp/LunaHook/LunaHook/engines/mono/def_mono.hpp index c2b40926..b300a9ea 100644 --- a/cpp/LunaHook/LunaHook/engines/mono/def_mono.hpp +++ b/cpp/LunaHook/LunaHook/engines/mono/def_mono.hpp @@ -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 get_string(void *); void *create_string(std::wstring_view ws); + monoloopinfo loop_all_methods(bool show); } \ No newline at end of file diff --git a/cpp/LunaHook/LunaHook/engines/mono/impl_il2cpp.cpp b/cpp/LunaHook/LunaHook/engines/mono/impl_il2cpp.cpp index 58932d83..b152dc3e 100644 --- a/cpp/LunaHook/LunaHook/engines/mono/impl_il2cpp.cpp +++ b/cpp/LunaHook/LunaHook/engines/mono/impl_il2cpp.cpp @@ -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 *)userData; st->push_back(klass); } - std::vector get_il2cppclass2(const char *namespaze, - const char *klassName) + std::vector loopclass() { - std::vector maybes; - std::vector klasses; + std::vector 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 get_il2cppclass2(const char *namespaze, const char *klassName) + { + std::vector 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 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, diff --git a/cpp/LunaHook/LunaHook/engines/mono/impl_mono.cpp b/cpp/LunaHook/LunaHook/engines/mono/impl_mono.cpp index bab33980..3e4dfa0c 100644 --- a/cpp/LunaHook/LunaHook/engines/mono/impl_mono.cpp +++ b/cpp/LunaHook/LunaHook/engines/mono/impl_mono.cpp @@ -37,9 +37,8 @@ namespace return NULL; return maybe; } - std::vector mono_findklassby_class(std::vector &images, const char *_namespace, const char *_class) + std::vector loopclass(std::vector &images) { - std::vector 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 mono_findklassby_class(std::vector &images, const char *_namespace, const char *_class) + { + std::vector 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 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); diff --git a/cpp/LunaHook/LunaHook/engine64/mono.cpp b/cpp/LunaHook/LunaHook/engines/mono/mono.cpp similarity index 66% rename from cpp/LunaHook/LunaHook/engine64/mono.cpp rename to cpp/LunaHook/LunaHook/engines/mono/mono.cpp index e5b2f588..d8154a5b 100644 --- a/cpp/LunaHook/LunaHook/engine64/mono.cpp +++ b/cpp/LunaHook/LunaHook/engines/mono/mono.cpp @@ -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(); } \ No newline at end of file diff --git a/cpp/LunaHook/LunaHook/engine32/mono.h b/cpp/LunaHook/LunaHook/engines/mono/mono.h similarity index 88% rename from cpp/LunaHook/LunaHook/engine32/mono.h rename to cpp/LunaHook/LunaHook/engines/mono/mono.h index e180a0c2..d3dc0cf8 100644 --- a/cpp/LunaHook/LunaHook/engine32/mono.h +++ b/cpp/LunaHook/LunaHook/engines/mono/mono.h @@ -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_(); }; diff --git a/cpp/LunaHook/LunaHook/engines/mono/monocommon.hpp b/cpp/LunaHook/LunaHook/engines/mono/monocommon.hpp index cddd8f49..60a8f378 100644 --- a/cpp/LunaHook/LunaHook/engines/mono/monocommon.hpp +++ b/cpp/LunaHook/LunaHook/engines/mono/monocommon.hpp @@ -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; } diff --git a/cpp/LunaHook/LunaHook/engines/mono/monoil2cpp.cpp b/cpp/LunaHook/LunaHook/engines/mono/monoil2cpp.cpp index 36d7df92..18a5466c 100644 --- a/cpp/LunaHook/LunaHook/engines/mono/monoil2cpp.cpp +++ b/cpp/LunaHook/LunaHook/engines/mono/monoil2cpp.cpp @@ -24,7 +24,7 @@ namespace return newstring; } } -void commonsolvemonostring(uintptr_t arg, TextBuffer *buffer) +std::optional 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 loop_all_methods(bool show) +{ + auto ms = il2cppfunctions::loop_all_methods(show); + if (ms.size()) + return ms; + return monofunctions::loop_all_methods(show); } \ No newline at end of file diff --git a/cpp/LunaHook/LunaHook/engines/mono/monoil2cpp.h b/cpp/LunaHook/LunaHook/engines/mono/monoil2cpp.h index 3db949c9..2346482b 100644 --- a/cpp/LunaHook/LunaHook/engines/mono/monoil2cpp.h +++ b/cpp/LunaHook/LunaHook/engines/mono/monoil2cpp.h @@ -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 commonsolvemonostring(uintptr_t arg); void unity_ui_string_embed_fun(uintptr_t &arg, TextBuffer buff); - +typedef std::vector> il2cpploopinfo; +typedef std::vector> monoloopinfo; +std::variant 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); \ No newline at end of file diff --git a/cpp/LunaHook/LunaHook/engines/ppsspp/ppsspp.cpp b/cpp/LunaHook/LunaHook/engines/ppsspp/ppsspp.cpp index 67bdc665..7d6487dc 100644 --- a/cpp/LunaHook/LunaHook/engines/ppsspp/ppsspp.cpp +++ b/cpp/LunaHook/LunaHook/engines/ppsspp/ppsspp.cpp @@ -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; diff --git a/cpp/LunaHook/LunaHook/engines/ppsspp/ppsspp.h b/cpp/LunaHook/LunaHook/engines/ppsspp/ppsspp.h index 32751d88..517de6f4 100644 --- a/cpp/LunaHook/LunaHook/engines/ppsspp/ppsspp.h +++ b/cpp/LunaHook/LunaHook/engines/ppsspp/ppsspp.h @@ -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(); }; diff --git a/cpp/LunaHook/LunaHook/hookfinder.cc b/cpp/LunaHook/LunaHook/hookfinder.cc index f2b4ab49..72864663 100644 --- a/cpp/LunaHook/LunaHook/hookfinder.cc +++ b/cpp/LunaHook/LunaHook/hookfinder.cc @@ -14,13 +14,14 @@ namespace int offset = 0; JITTYPE jittype; char text[MAX_STRING_SIZE] = {}; + bool csstring; }; std::unique_ptr records; long recordsAvailable; uint64_t signatureCache[CACHE_SIZE] = {}; long sumCache[CACHE_SIZE] = {}; uintptr_t pageCache[CACHE_SIZE] = {}; - + std::unordered_map 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 +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 &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 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 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 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; + std::vector addrs; + for (auto [_, addr] : std::get(methods)) + addrs.push_back(addr); + inlinehookpipeline(addrs); + } + catch (std::bad_variant_access const &ex) + { + + *(void **)(trampoline + send_offset) = SendCSharpString; + auto functions = std::get(methods); + std::vector addrs; + for (auto [addr, func] : functions) + { + addrs.push_back(addr); + remapunityjit[addr] = func; + } + inlinehookpipeline(addrs); + } + } + else + { + safeautoleaveveh = false; + + std::vector 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 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 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;addrfuncaddr){ - 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::vectormherroridx; - 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;isuccessaddr; - 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.secondargof(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); } } } diff --git a/cpp/LunaHook/LunaHost/host.cpp b/cpp/LunaHook/LunaHost/host.cpp index 89278e0c..1aa2c3b3 100644 --- a/cpp/LunaHook/LunaHost/host.cpp +++ b/cpp/LunaHook/LunaHost/host.cpp @@ -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(); } } diff --git a/cpp/LunaHook/include/const.h b/cpp/LunaHook/include/const.h index 4bf26c45..20f44044 100644 --- a/cpp/LunaHook/include/const.h +++ b/cpp/LunaHook/include/const.h @@ -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), diff --git a/cpp/LunaHook/include/hookcode.cpp b/cpp/LunaHook/include/hookcode.cpp index c247da0c..ccfb791a 100644 --- a/cpp/LunaHook/include/hookcode.cpp +++ b/cpp/LunaHook/include/hookcode.cpp @@ -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'; diff --git a/cpp/version.cmake b/cpp/version.cmake index 2ff26ea3..c494be4e 100644 --- a/cpp/version.cmake +++ b/cpp/version.cmake @@ -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)