经验分享,仅适用于小白!
今天尝试用自动更新来重写之前的菜单,发现了一些BUG,这里分享给大家避坑。
1.用新的UtilS.h和Struct.h替换到单目录app/src/main/jni/Includes/目录下
2.新的Utils.h删除了findlibray()和getAbsoluteAddress()函数,这将意味着菜单原始的寻址方式将失效。原因是自动更新函数和这个两个函数共存时会导致一些错误,使Hook函数替换指令时找不到正确函数地址,表现为功能概率有效,多数闪退。(“经观察两者共存时cd内存中的函数头几个字节不会被替换,hook功能失效”)
3.仅适用于适用于il2cpp游戏,支持32位和64位,可根据函数名和字段名自动查找函数地址和字段偏移,只需打包一次,日后游戏更新可继续使用,节省精力。
4.自动更新代码来自Github,已做修复,这里给出使用示例,和注意事项。
5.新Utils.h地址
#pragma once#include <jni.h>#include <unistd.h>#include <cstdio>#include <cstring>#include <string>#include <cstdlib>#include "Logger.h"#include "Struct.h"#include <dlfcn.h>typedef unsigned long DWORD;static uintptr_t libBase;bool libLoaded = false;bool isLibraryLoaded(const char *libraryName) {//libLoaded = true;char line[512] = {0};FILE *fp = fopen(OBFUSCATE("/proc/self/maps"), OBFUSCATE("rt"));if (fp != NULL) {while (fgets(line, sizeof(line), fp)) {std::string a = line;if (strstr(line, libraryName)) {libLoaded = true;return true;}}fclose(fp);}return false;}uintptr_t string2Offset(const char *c) {int base = 16;// See if this function catches all possibilities.// If it doesn't, the function would have to be amended// whenever you add a combination of architecture and// compiler that is not yet addressed.static_assert(sizeof(uintptr_t) == sizeof(unsigned long)|| sizeof(uintptr_t) == sizeof(unsigned long long),"Please add string to handle conversion for this architecture.");// Now choose the correct function ...if (sizeof(uintptr_t) == sizeof(unsigned long)) {return strtoul(c, nullptr, base);}// All other options exhausted, sizeof(uintptr_t) == sizeof(unsigned long long))return strtoull(c, nullptr, base);}namespace ToastLength {inline const int LENGTH_LONG = 1;inline const int LENGTH_SHORT = 0;}typedef Il2CppClass *(*class_from_name_t)(const Il2CppImage *assembly, const char *name_space,const char *name);typedef MethodInfo *(*class_get_method_from_name_t)(Il2CppClass *klass, const char *name,int paramcount);typedef Il2CppDomain *(*domain_get_t)();typedef const Il2CppAssembly **(*domain_get_assemblies_t)(const Il2CppDomain *domain, size_t *size);typedef const Il2CppImage *(*assembly_get_image_t)(const Il2CppAssembly *assembly);typedef const Il2CppAssembly *(*domain_assembly_open_t)(Il2CppDomain *domain, const char *name);typedef FieldInfo *(*class_get_field_from_name_t)(Il2CppClass *klass, const char *name);template<typename T>class Field : FieldInfo {bool statik;bool CheckStatic() {if ((type->attrs & 0x10) == 0)return false;if ((type->attrs & 0x40) != 0)return false;if (thread_static = offset == -1)LOGI(OBFUSCATE("thread static fields is not supported!"));return true;}bool CheckStaticFieldInfo(FieldInfo *fieldInfo) {if ((fieldInfo->type->attrs & 0x10) == 0)return false;if ((fieldInfo->type->attrs & 0x40) != 0)return false;if (fieldInfo->offset == -1)LOGI(OBFUSCATE("thread static fields is not supported!"));return true;}public:bool init;bool thread_static;void *clazz;Field(FieldInfo *thiz, void *clas = NULL) {if (!CheckStaticFieldInfo(thiz))clazz = clas;init = (thiz != NULL);if (init) {parent = thiz->parent;offset = thiz->offset;name = thiz->name;token = thiz->token;type = thiz->type;statik = CheckStatic();}}DWORD get_offset() {return offset;}T get() {if (!init || thread_static) return T();if (statik) {return *(T *) ((uint64_t) parent->static_fields + offset);}return *(T *) ((uint64_t) clazz + offset);}void set(T val) {if (!init || thread_static) return;if (statik) {*(T *) ((uint64_t) parent->static_fields + offset) = val;return;}*(T *) ((uint64_t) clazz + offset) = val;}operator T() {return get();}void operator=(T val) {set(val);}bool operator==(Field other) {if (!init) return false;return (type == other.type && parent == other.parent &&offset == other.offset && name == other.name && token == other.token);}T operator()() {return get();}};class LoadClass {void *get_il2cpp() {void *mod = 0;while (!mod) {mod = dlopen(OBFUSCATE("libil2cpp.so"), 4);}return mod;}Il2CppClass *GetClassFromName(const char *name_space, const char *type_name) {auto domain_get = (domain_get_t) dlsym(get_il2cpp(), OBFUSCATE("il2cpp_domain_get"));auto dom = domain_get();if (!dom) {return nullptr;}size_t assemb_count;auto domain_get_assemblies = (domain_get_assemblies_t) dlsym(get_il2cpp(), OBFUSCATE("il2cpp_domain_get_assemblies"));const Il2CppAssembly **allAssemb = domain_get_assemblies(dom, &assemb_count);auto assembly_get_image = (assembly_get_image_t) dlsym(get_il2cpp(), OBFUSCATE("il2cpp_assembly_get_image"));auto class_from_name = (class_from_name_t) dlsym(get_il2cpp(),OBFUSCATE("il2cpp_class_from_name"));for (int i = 0; i < assemb_count; i++) {auto assemb = allAssemb[i];auto img = assembly_get_image(assemb);if (!img) {continue;}auto klass = class_from_name(img, name_space, type_name);if (klass) {namespaze_txt = name_space;clazz_txt = type_name;dllname_txt = img->name;dll = img;return klass;}}return nullptr;}public:const Il2CppImage *dll;Il2CppClass *thisclass;const char *namespaze_txt;const char *clazz_txt;const char *dllname_txt;LoadClass(const char *namespaze, const char *clazz) {thisclass = nullptr;do {thisclass = GetClassFromName(namespaze, clazz);} while (!thisclass);}LoadClass(const char *namespaze, const char *clazz, const char *dllname) {auto domain_assembly_open = (domain_assembly_open_t) dlsym(get_il2cpp(), OBFUSCATE("il2cpp_domain_assembly_open"));auto assembly_get_image = (assembly_get_image_t) dlsym(get_il2cpp(), OBFUSCATE("il2cpp_assembly_get_image"));auto domain_get = (domain_get_t) dlsym(get_il2cpp(), OBFUSCATE("il2cpp_domain_get"));auto class_from_name = (class_from_name_t) dlsym(get_il2cpp(),OBFUSCATE("il2cpp_class_from_name"));dll = assembly_get_image(domain_assembly_open(domain_get(), dllname));thisclass = nullptr;do {thisclass = class_from_name(dll, namespaze, clazz);} while (!thisclass);}FieldInfo *GetFieldInfoByName(const char *name) {auto class_get_field_from_name = (class_get_field_from_name_t) dlsym(get_il2cpp(),OBFUSCATE("il2cpp_class_get_field_from_name"));return class_get_field_from_name(thisclass, name);}template<typename T>Field<T> GetFieldByName(const char *name) {return Field<T>(GetFieldInfoByName(name), (void *) thisclass);}DWORD GetFieldOffset(const char *name) {return GetFieldInfoByName(name)->offset;}DWORD GetFieldOffset(FieldInfo *filed) {return filed->offset;}MethodInfo *GetMethodInfoByName(const char *name, int paramcount) {auto class_get_method_from_name = (class_get_method_from_name_t) dlsym(get_il2cpp(),OBFUSCATE("il2cpp_class_get_method_from_name"));if (thisclass)return class_get_method_from_name(thisclass, name, paramcount);elsereturn nullptr;}DWORD GetMethodOffsetByName(const char *name, int paramcount) {auto res = GetMethodInfoByName(name, paramcount);if (res)return (DWORD) GetMethodInfoByName(name, paramcount)->methodPointer;elsereturn 0;}};void *get_Method(const char *str) {void *(*il2cpp_resolve_icall_0)(const char *str) = nullptr;void *h = nullptr;while (!h) {h = dlopen(OBFUSCATE("libil2cpp.so"), 4);}do {il2cpp_resolve_icall_0 = (void *(*)(const char *)) dlsym(h,OBFUSCATE("il2cpp_resolve_icall"));} while (!il2cpp_resolve_icall_0);return il2cpp_resolve_icall_0(str);}#define InitResolveFunc(x, y) *reinterpret_cast<void **>(&x) = get_Method(y)#define InitFunc(x, y) if (y != 0) *reinterpret_cast<void **>(&x) = (void *)(y)#define FieldBN(myfield, type, inst, nameSpacec, clazzz, fieldName, key) Field<type> myfield = (new LoadClass(OBFUSCATE_KEY(nameSpacec, key), OBFUSCATE_KEY(clazzz, key)))->GetFieldByName<type>(OBFUSCATE_KEY(fieldName, key)); myfield.clazz = inst#pragma once #include <jni.h> #include <unistd.h> #include <cstdio> #include <cstring> #include <string> #include <cstdlib> #include "Logger.h" #include "Struct.h" #include <dlfcn.h> typedef unsigned long DWORD; static uintptr_t libBase; bool libLoaded = false; bool isLibraryLoaded(const char *libraryName) { //libLoaded = true; char line[512] = {0}; FILE *fp = fopen(OBFUSCATE("/proc/self/maps"), OBFUSCATE("rt")); if (fp != NULL) { while (fgets(line, sizeof(line), fp)) { std::string a = line; if (strstr(line, libraryName)) { libLoaded = true; return true; } } fclose(fp); } return false; } uintptr_t string2Offset(const char *c) { int base = 16; // See if this function catches all possibilities. // If it doesn't, the function would have to be amended // whenever you add a combination of architecture and // compiler that is not yet addressed. static_assert(sizeof(uintptr_t) == sizeof(unsigned long) || sizeof(uintptr_t) == sizeof(unsigned long long), "Please add string to handle conversion for this architecture."); // Now choose the correct function ... if (sizeof(uintptr_t) == sizeof(unsigned long)) { return strtoul(c, nullptr, base); } // All other options exhausted, sizeof(uintptr_t) == sizeof(unsigned long long)) return strtoull(c, nullptr, base); } namespace ToastLength { inline const int LENGTH_LONG = 1; inline const int LENGTH_SHORT = 0; } typedef Il2CppClass *(*class_from_name_t)(const Il2CppImage *assembly, const char *name_space, const char *name); typedef MethodInfo *(*class_get_method_from_name_t)(Il2CppClass *klass, const char *name, int paramcount); typedef Il2CppDomain *(*domain_get_t)(); typedef const Il2CppAssembly **(*domain_get_assemblies_t)(const Il2CppDomain *domain, size_t *size); typedef const Il2CppImage *(*assembly_get_image_t)(const Il2CppAssembly *assembly); typedef const Il2CppAssembly *(*domain_assembly_open_t)(Il2CppDomain *domain, const char *name); typedef FieldInfo *(*class_get_field_from_name_t)(Il2CppClass *klass, const char *name); template<typename T> class Field : FieldInfo { bool statik; bool CheckStatic() { if ((type->attrs & 0x10) == 0) return false; if ((type->attrs & 0x40) != 0) return false; if (thread_static = offset == -1) LOGI(OBFUSCATE("thread static fields is not supported!")); return true; } bool CheckStaticFieldInfo(FieldInfo *fieldInfo) { if ((fieldInfo->type->attrs & 0x10) == 0) return false; if ((fieldInfo->type->attrs & 0x40) != 0) return false; if (fieldInfo->offset == -1) LOGI(OBFUSCATE("thread static fields is not supported!")); return true; } public: bool init; bool thread_static; void *clazz; Field(FieldInfo *thiz, void *clas = NULL) { if (!CheckStaticFieldInfo(thiz)) clazz = clas; init = (thiz != NULL); if (init) { parent = thiz->parent; offset = thiz->offset; name = thiz->name; token = thiz->token; type = thiz->type; statik = CheckStatic(); } } DWORD get_offset() { return offset; } T get() { if (!init || thread_static) return T(); if (statik) { return *(T *) ((uint64_t) parent->static_fields + offset); } return *(T *) ((uint64_t) clazz + offset); } void set(T val) { if (!init || thread_static) return; if (statik) { *(T *) ((uint64_t) parent->static_fields + offset) = val; return; } *(T *) ((uint64_t) clazz + offset) = val; } operator T() { return get(); } void operator=(T val) { set(val); } bool operator==(Field other) { if (!init) return false; return (type == other.type && parent == other.parent && offset == other.offset && name == other.name && token == other.token); } T operator()() { return get(); } }; class LoadClass { void *get_il2cpp() { void *mod = 0; while (!mod) { mod = dlopen(OBFUSCATE("libil2cpp.so"), 4); } return mod; } Il2CppClass *GetClassFromName(const char *name_space, const char *type_name) { auto domain_get = (domain_get_t) dlsym(get_il2cpp(), OBFUSCATE("il2cpp_domain_get")); auto dom = domain_get(); if (!dom) { return nullptr; } size_t assemb_count; auto domain_get_assemblies = (domain_get_assemblies_t) dlsym(get_il2cpp(), OBFUSCATE( "il2cpp_domain_get_assemblies")); const Il2CppAssembly **allAssemb = domain_get_assemblies(dom, &assemb_count); auto assembly_get_image = (assembly_get_image_t) dlsym(get_il2cpp(), OBFUSCATE( "il2cpp_assembly_get_image")); auto class_from_name = (class_from_name_t) dlsym(get_il2cpp(), OBFUSCATE("il2cpp_class_from_name")); for (int i = 0; i < assemb_count; i++) { auto assemb = allAssemb[i]; auto img = assembly_get_image(assemb); if (!img) { continue; } auto klass = class_from_name(img, name_space, type_name); if (klass) { namespaze_txt = name_space; clazz_txt = type_name; dllname_txt = img->name; dll = img; return klass; } } return nullptr; } public: const Il2CppImage *dll; Il2CppClass *thisclass; const char *namespaze_txt; const char *clazz_txt; const char *dllname_txt; LoadClass(const char *namespaze, const char *clazz) { thisclass = nullptr; do { thisclass = GetClassFromName(namespaze, clazz); } while (!thisclass); } LoadClass(const char *namespaze, const char *clazz, const char *dllname) { auto domain_assembly_open = (domain_assembly_open_t) dlsym(get_il2cpp(), OBFUSCATE( "il2cpp_domain_assembly_open")); auto assembly_get_image = (assembly_get_image_t) dlsym(get_il2cpp(), OBFUSCATE( "il2cpp_assembly_get_image")); auto domain_get = (domain_get_t) dlsym(get_il2cpp(), OBFUSCATE("il2cpp_domain_get")); auto class_from_name = (class_from_name_t) dlsym(get_il2cpp(), OBFUSCATE("il2cpp_class_from_name")); dll = assembly_get_image(domain_assembly_open(domain_get(), dllname)); thisclass = nullptr; do { thisclass = class_from_name(dll, namespaze, clazz); } while (!thisclass); } FieldInfo *GetFieldInfoByName(const char *name) { auto class_get_field_from_name = (class_get_field_from_name_t) dlsym(get_il2cpp(), OBFUSCATE( "il2cpp_class_get_field_from_name")); return class_get_field_from_name(thisclass, name); } template<typename T> Field<T> GetFieldByName(const char *name) { return Field<T>(GetFieldInfoByName(name), (void *) thisclass); } DWORD GetFieldOffset(const char *name) { return GetFieldInfoByName(name)->offset; } DWORD GetFieldOffset(FieldInfo *filed) { return filed->offset; } MethodInfo *GetMethodInfoByName(const char *name, int paramcount) { auto class_get_method_from_name = (class_get_method_from_name_t) dlsym(get_il2cpp(), OBFUSCATE( "il2cpp_class_get_method_from_name")); if (thisclass) return class_get_method_from_name(thisclass, name, paramcount); else return nullptr; } DWORD GetMethodOffsetByName(const char *name, int paramcount) { auto res = GetMethodInfoByName(name, paramcount); if (res) return (DWORD) GetMethodInfoByName(name, paramcount)->methodPointer; else return 0; } }; void *get_Method(const char *str) { void *(*il2cpp_resolve_icall_0)(const char *str) = nullptr; void *h = nullptr; while (!h) { h = dlopen(OBFUSCATE("libil2cpp.so"), 4); } do { il2cpp_resolve_icall_0 = (void *(*)(const char *)) dlsym(h, OBFUSCATE("il2cpp_resolve_icall")); } while (!il2cpp_resolve_icall_0); return il2cpp_resolve_icall_0(str); } #define InitResolveFunc(x, y) *reinterpret_cast<void **>(&x) = get_Method(y) #define InitFunc(x, y) if (y != 0) *reinterpret_cast<void **>(&x) = (void *)(y) #define FieldBN(myfield, type, inst, nameSpacec, clazzz, fieldName, key) Field<type> myfield = (new LoadClass(OBFUSCATE_KEY(nameSpacec, key), OBFUSCATE_KEY(clazzz, key)))->GetFieldByName<type>(OBFUSCATE_KEY(fieldName, key)); myfield.clazz = inst#pragma once #include <jni.h> #include <unistd.h> #include <cstdio> #include <cstring> #include <string> #include <cstdlib> #include "Logger.h" #include "Struct.h" #include <dlfcn.h> typedef unsigned long DWORD; static uintptr_t libBase; bool libLoaded = false; bool isLibraryLoaded(const char *libraryName) { //libLoaded = true; char line[512] = {0}; FILE *fp = fopen(OBFUSCATE("/proc/self/maps"), OBFUSCATE("rt")); if (fp != NULL) { while (fgets(line, sizeof(line), fp)) { std::string a = line; if (strstr(line, libraryName)) { libLoaded = true; return true; } } fclose(fp); } return false; } uintptr_t string2Offset(const char *c) { int base = 16; // See if this function catches all possibilities. // If it doesn't, the function would have to be amended // whenever you add a combination of architecture and // compiler that is not yet addressed. static_assert(sizeof(uintptr_t) == sizeof(unsigned long) || sizeof(uintptr_t) == sizeof(unsigned long long), "Please add string to handle conversion for this architecture."); // Now choose the correct function ... if (sizeof(uintptr_t) == sizeof(unsigned long)) { return strtoul(c, nullptr, base); } // All other options exhausted, sizeof(uintptr_t) == sizeof(unsigned long long)) return strtoull(c, nullptr, base); } namespace ToastLength { inline const int LENGTH_LONG = 1; inline const int LENGTH_SHORT = 0; } typedef Il2CppClass *(*class_from_name_t)(const Il2CppImage *assembly, const char *name_space, const char *name); typedef MethodInfo *(*class_get_method_from_name_t)(Il2CppClass *klass, const char *name, int paramcount); typedef Il2CppDomain *(*domain_get_t)(); typedef const Il2CppAssembly **(*domain_get_assemblies_t)(const Il2CppDomain *domain, size_t *size); typedef const Il2CppImage *(*assembly_get_image_t)(const Il2CppAssembly *assembly); typedef const Il2CppAssembly *(*domain_assembly_open_t)(Il2CppDomain *domain, const char *name); typedef FieldInfo *(*class_get_field_from_name_t)(Il2CppClass *klass, const char *name); template<typename T> class Field : FieldInfo { bool statik; bool CheckStatic() { if ((type->attrs & 0x10) == 0) return false; if ((type->attrs & 0x40) != 0) return false; if (thread_static = offset == -1) LOGI(OBFUSCATE("thread static fields is not supported!")); return true; } bool CheckStaticFieldInfo(FieldInfo *fieldInfo) { if ((fieldInfo->type->attrs & 0x10) == 0) return false; if ((fieldInfo->type->attrs & 0x40) != 0) return false; if (fieldInfo->offset == -1) LOGI(OBFUSCATE("thread static fields is not supported!")); return true; } public: bool init; bool thread_static; void *clazz; Field(FieldInfo *thiz, void *clas = NULL) { if (!CheckStaticFieldInfo(thiz)) clazz = clas; init = (thiz != NULL); if (init) { parent = thiz->parent; offset = thiz->offset; name = thiz->name; token = thiz->token; type = thiz->type; statik = CheckStatic(); } } DWORD get_offset() { return offset; } T get() { if (!init || thread_static) return T(); if (statik) { return *(T *) ((uint64_t) parent->static_fields + offset); } return *(T *) ((uint64_t) clazz + offset); } void set(T val) { if (!init || thread_static) return; if (statik) { *(T *) ((uint64_t) parent->static_fields + offset) = val; return; } *(T *) ((uint64_t) clazz + offset) = val; } operator T() { return get(); } void operator=(T val) { set(val); } bool operator==(Field other) { if (!init) return false; return (type == other.type && parent == other.parent && offset == other.offset && name == other.name && token == other.token); } T operator()() { return get(); } }; class LoadClass { void *get_il2cpp() { void *mod = 0; while (!mod) { mod = dlopen(OBFUSCATE("libil2cpp.so"), 4); } return mod; } Il2CppClass *GetClassFromName(const char *name_space, const char *type_name) { auto domain_get = (domain_get_t) dlsym(get_il2cpp(), OBFUSCATE("il2cpp_domain_get")); auto dom = domain_get(); if (!dom) { return nullptr; } size_t assemb_count; auto domain_get_assemblies = (domain_get_assemblies_t) dlsym(get_il2cpp(), OBFUSCATE( "il2cpp_domain_get_assemblies")); const Il2CppAssembly **allAssemb = domain_get_assemblies(dom, &assemb_count); auto assembly_get_image = (assembly_get_image_t) dlsym(get_il2cpp(), OBFUSCATE( "il2cpp_assembly_get_image")); auto class_from_name = (class_from_name_t) dlsym(get_il2cpp(), OBFUSCATE("il2cpp_class_from_name")); for (int i = 0; i < assemb_count; i++) { auto assemb = allAssemb[i]; auto img = assembly_get_image(assemb); if (!img) { continue; } auto klass = class_from_name(img, name_space, type_name); if (klass) { namespaze_txt = name_space; clazz_txt = type_name; dllname_txt = img->name; dll = img; return klass; } } return nullptr; } public: const Il2CppImage *dll; Il2CppClass *thisclass; const char *namespaze_txt; const char *clazz_txt; const char *dllname_txt; LoadClass(const char *namespaze, const char *clazz) { thisclass = nullptr; do { thisclass = GetClassFromName(namespaze, clazz); } while (!thisclass); } LoadClass(const char *namespaze, const char *clazz, const char *dllname) { auto domain_assembly_open = (domain_assembly_open_t) dlsym(get_il2cpp(), OBFUSCATE( "il2cpp_domain_assembly_open")); auto assembly_get_image = (assembly_get_image_t) dlsym(get_il2cpp(), OBFUSCATE( "il2cpp_assembly_get_image")); auto domain_get = (domain_get_t) dlsym(get_il2cpp(), OBFUSCATE("il2cpp_domain_get")); auto class_from_name = (class_from_name_t) dlsym(get_il2cpp(), OBFUSCATE("il2cpp_class_from_name")); dll = assembly_get_image(domain_assembly_open(domain_get(), dllname)); thisclass = nullptr; do { thisclass = class_from_name(dll, namespaze, clazz); } while (!thisclass); } FieldInfo *GetFieldInfoByName(const char *name) { auto class_get_field_from_name = (class_get_field_from_name_t) dlsym(get_il2cpp(), OBFUSCATE( "il2cpp_class_get_field_from_name")); return class_get_field_from_name(thisclass, name); } template<typename T> Field<T> GetFieldByName(const char *name) { return Field<T>(GetFieldInfoByName(name), (void *) thisclass); } DWORD GetFieldOffset(const char *name) { return GetFieldInfoByName(name)->offset; } DWORD GetFieldOffset(FieldInfo *filed) { return filed->offset; } MethodInfo *GetMethodInfoByName(const char *name, int paramcount) { auto class_get_method_from_name = (class_get_method_from_name_t) dlsym(get_il2cpp(), OBFUSCATE( "il2cpp_class_get_method_from_name")); if (thisclass) return class_get_method_from_name(thisclass, name, paramcount); else return nullptr; } DWORD GetMethodOffsetByName(const char *name, int paramcount) { auto res = GetMethodInfoByName(name, paramcount); if (res) return (DWORD) GetMethodInfoByName(name, paramcount)->methodPointer; else return 0; } }; void *get_Method(const char *str) { void *(*il2cpp_resolve_icall_0)(const char *str) = nullptr; void *h = nullptr; while (!h) { h = dlopen(OBFUSCATE("libil2cpp.so"), 4); } do { il2cpp_resolve_icall_0 = (void *(*)(const char *)) dlsym(h, OBFUSCATE("il2cpp_resolve_icall")); } while (!il2cpp_resolve_icall_0); return il2cpp_resolve_icall_0(str); } #define InitResolveFunc(x, y) *reinterpret_cast<void **>(&x) = get_Method(y) #define InitFunc(x, y) if (y != 0) *reinterpret_cast<void **>(&x) = (void *)(y) #define FieldBN(myfield, type, inst, nameSpacec, clazzz, fieldName, key) Field<type> myfield = (new LoadClass(OBFUSCATE_KEY(nameSpacec, key), OBFUSCATE_KEY(clazzz, key)))->GetFieldByName<type>(OBFUSCATE_KEY(fieldName, key)); myfield.clazz = inst
Struct地址
https://www.123pan.com/s/SIoAjv-8T1Jv.html
6.hook的基本方法没变,只是换了一种寻址方式,由于比较简单,不再具体描述,下面几张图片给出了一些示例。

THE END
暂无评论内容