经验分享,仅适用于小白!
今天尝试用自动更新来重写之前的菜单,发现了一些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);
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
暂无评论内容