【废弃】
可以运行 可以hook 可以得到哪些东西
目前这个并没有啥稀奇的,基本没啥用。
il2cpp相关的
起始地址和大小
const m = Process.getModuleByName("libil2cpp.so");
console.log("name =", m.name);
console.log("base =", m.base);
console.log("size =", m.size);
console.log("path =", m.path);
========
name = libil2cpp.so
base = 0x8000000
size = 42426368
path = /data/app/com.oakever.jigsawcard-1/lib/arm/libil2cpp.so
2.获取到il2cpp的
const il2cpp = "libil2cpp.so";
[//]: # (打印的是:libil2cpp.so 这个动态库的“导出符号(exported symbols)列表”。)
const exps = Module.enumerateExportsSync(il2cpp)
.filter(e => e.type === "function" && e.name.startsWith("il2cpp_"))
.map(e => e.name);
console.log("il2cpp exports count =", exps.length);
// 只看你关心的几个关键词
["class_get_methods", "method_get_", "class_get_name", "class_get_namespace", "method_get_name"].forEach(k => {
const hit = exps.filter(n => n.includes(k));
console.log("\n== contains:", k, "==");
hit.slice(0, 50).forEach(n => console.log(" ", n));
});
运行结果:
il2cpp exports count = 240 == contains: class_get_methods == il2cpp_class_get_methods == contains: method_get_ == il2cpp_method_get_flags il2cpp_method_get_declaring_type il2cpp_method_get_object il2cpp_method_get_from_reflection il2cpp_method_get_param il2cpp_method_get_class il2cpp_method_get_return_type il2cpp_method_get_param_count il2cpp_method_get_name il2cpp_method_get_token il2cpp_method_get_param_name == contains: class_get_name == il2cpp_class_get_name il2cpp_class_get_namespace == contains: class_get_namespace == il2cpp_class_get_namespace == contains: method_get_name == il2cpp_method_get_name
3.查看调用的方法,来推断有哪些类名和方法
这个计没有用,不能提供什么东西。
'use strict';
(function () {
console.log("🚀 il2cpp Invoke resolver starting...");
const il2cpp = Process.findModuleByName("libil2cpp.so");
if (!il2cpp) {
console.log("❌ libil2cpp.so not found");
throw new Error("abort");
}
console.log("✅ libil2cpp.so @", il2cpp.base, "size =", il2cpp.size);
function mustExport(name) {
const p = Module.findExportByName("libil2cpp.so", name);
if (!p) {
console.log("❌ missing export:", name);
throw new Error("abort");
}
return p;
}
const f_getMethodName = new NativeFunction(
mustExport("il2cpp_method_get_name"),
'pointer',
['pointer']
);
const f_getMethodClass = new NativeFunction(
mustExport("il2cpp_method_get_class"),
'pointer',
['pointer']
);
const f_getClassName = new NativeFunction(
mustExport("il2cpp_class_get_name"),
'pointer',
['pointer']
);
const f_getClassNamespace = new NativeFunction(
mustExport("il2cpp_class_get_namespace"),
'pointer',
['pointer']
);
const invoke = Module.findExportByName("libil2cpp.so", "il2cpp_runtime_invoke");
if (!invoke) {
console.log("❌ il2cpp_runtime_invoke not found");
throw new Error("abort");
}
console.log("✅ hook il2cpp_runtime_invoke @", invoke);
const seen = {};
Interceptor.attach(invoke, {
onEnter(args) {
try {
const method = args[0];
const obj = args[1];
if (obj.isNull()) return;
const key = method.toString();
if (seen[key]) return;
seen[key] = true;
const namePtr = f_getMethodName(method);
const klass = f_getMethodClass(method);
const classNamePtr = f_getClassName(klass);
const nsPtr = f_getClassNamespace(klass);
const methodName = namePtr.readCString();
const className = classNamePtr.readCString();
const ns = nsPtr.readCString();
console.log(
`🎯 FOUND → ${ns}.${className}::${methodName}`,
"method =", method
);
} catch (e) {
// 静默,防止影响运行
}
}
});
})();
4.通过他们来获取整个类的信息
通过上面推断来的信息,我们推断出整个类
//🎯 FOUND → .UI_LoadingBar::.ctor method = 0x7b22aab8
'use strict';
const IL2CPP = "libil2cpp.so";
const addrX = "0x7b22aab8";
const TARGET_METHODINFO = ptr(addrX);
// ================= helpers =================
function cstr(p) { return p.isNull() ? "" : p.readCString(); }
function normalizeArm32Thumb(p) {
if (Process.arch === "arm" && !p.isNull() && p.and(1).toInt32() === 1) {
return p.and(ptr("0xfffffffe"));
}
return p;
}
function isExecutableCodePtr(p) {
if (p.isNull()) return false;
const r = Process.findRangeByAddress(p);
if (!r) return false;
return r.protection.indexOf("x") !== -1;
}
function exp(name) {
const p = Module.findExportByName(IL2CPP, name);
if (!p) throw new Error("missing export: " + name);
return p;
}
// ================= module =================
const il2cppMod = Process.getModuleByName(IL2CPP);
const IL2CPP_BASE = il2cppMod.base;
console.log("[*] libil2cpp.so base =", IL2CPP_BASE);
console.log("[*] libil2cpp.so path =", il2cppMod.path);
// ================= il2cpp API =================
const il2cpp_class_get_methods =
new NativeFunction(exp("il2cpp_class_get_methods"), "pointer", ["pointer", "pointer"]);
const il2cpp_class_get_name =
new NativeFunction(exp("il2cpp_class_get_name"), "pointer", ["pointer"]);
const il2cpp_class_get_namespace =
new NativeFunction(exp("il2cpp_class_get_namespace"), "pointer", ["pointer"]);
const il2cpp_method_get_name =
new NativeFunction(exp("il2cpp_method_get_name"), "pointer", ["pointer"]);
const il2cpp_method_get_class =
new NativeFunction(exp("il2cpp_method_get_class"), "pointer", ["pointer"]);
const il2cpp_class_get_nested_types =
new NativeFunction(exp("il2cpp_class_get_nested_types"), "pointer", ["pointer", "pointer"]);
// ================= MethodInfo impl resolver =================
function getMethodImplFromMethodInfo(methodInfo) {
methodInfo = ptr(methodInfo);
const candidates = [
0x0, 0x4, 0x8, 0xC,
0x10, 0x14, 0x18, 0x1C,
0x20, 0x24, 0x28, 0x2C,
0x30, 0x34, 0x38, 0x3C
];
for (const off of candidates) {
let p;
try {
p = methodInfo.add(off).readPointer();
} catch (e) {
continue;
}
const real = normalizeArm32Thumb(p);
if (isExecutableCodePtr(real)) return real;
}
return NULL;
}
function toIl2cppOffset(codePtr) {
const real = normalizeArm32Thumb(ptr(codePtr));
return real.sub(IL2CPP_BASE);
}
// ================= nested dumper (recursive) =================
function dumpNestedRecursive(klass, depth) {
const iter = Memory.alloc(Process.pointerSize);
iter.writePointer(NULL);
let nested;
while (!(nested = il2cpp_class_get_nested_types(klass, iter)).isNull()) {
const ns = cstr(il2cpp_class_get_namespace(nested));
const name = cstr(il2cpp_class_get_name(nested));
const indent = " ".repeat(depth);
console.log(`\n${indent}--- Nested: ${ns}.${name} ---`);
// dump its methods
const it2 = Memory.alloc(Process.pointerSize);
it2.writePointer(NULL);
let m;
while (!(m = il2cpp_class_get_methods(nested, it2)).isNull()) {
const methodName = cstr(il2cpp_method_get_name(m));
const impl = getMethodImplFromMethodInfo(m);
if (!impl.isNull()) {
const off = toIl2cppOffset(impl);
console.log(`${indent} ${methodName} -> ${impl} (offset ${off})`);
} else {
console.log(`${indent} ${methodName} -> NULL`);
}
}
// 递归继续查嵌套
dumpNestedRecursive(nested, depth + 1);
}
}
// ================= main class dump =================
function dumpClassMethodsFromMethodInfo(methodInfo) {
const mi = ptr(methodInfo);
const klass = il2cpp_method_get_class(mi);
const ns = cstr(il2cpp_class_get_namespace(klass));
const cn = cstr(il2cpp_class_get_name(klass));
console.log("\n==============================");
console.log(`Class: ${ns}.${cn}`);
console.log("MethodInfo* =", mi);
console.log("klass =", klass);
console.log("==============================\n");
const iter = Memory.alloc(Process.pointerSize);
iter.writePointer(NULL);
let idx = 0;
let m;
while (!(m = il2cpp_class_get_methods(klass, iter)).isNull()) {
const name = cstr(il2cpp_method_get_name(m));
const impl = getMethodImplFromMethodInfo(m);
idx++;
if (!impl.isNull()) {
const off = toIl2cppOffset(impl);
console.log(`${String(idx).padStart(3)} ${name} -> ${impl} (offset ${off})`);
} else {
console.log(`${String(idx).padStart(3)} ${name} -> NULL`);
}
}
// ⭐ 自动打印 nested classes(包括协程类)
dumpNestedRecursive(klass, 1);
console.log("\n[*] Tip: offset 可直接在 IDA 中跳转(imagebase=0)");
return { klass, ns, cn };
}
// ================= run =================
dumpClassMethodsFromMethodInfo(TARGET_METHODINFO);
console.log("[+] done.");