From 2d9a8346a124c682e4f0538d7e099c19aa16d57a Mon Sep 17 00:00:00 2001 From: axhlzy Date: Tue, 20 Aug 2024 10:35:11 +0800 Subject: [PATCH] update readme / fix HookReflect --- Il2cppHook/agent/base/breaker.ts | 10 +- .../mscorlibObj/Object/GameObject/export.ts | 8 +- .../TypeExtends/mscorlibObj/Object/export.ts | 1 + Il2cppHook/agent/java/hooks.ts | 76 ++++++----- Il2cppHook/agent/utils/context.ts | 6 +- README.md | 2 + README.zh-CN.md | 123 ++++++++++++++++++ 7 files changed, 182 insertions(+), 44 deletions(-) create mode 100644 README.zh-CN.md diff --git a/Il2cppHook/agent/base/breaker.ts b/Il2cppHook/agent/base/breaker.ts index 3803fb78..e891327e 100644 --- a/Il2cppHook/agent/base/breaker.ts +++ b/Il2cppHook/agent/base/breaker.ts @@ -16,7 +16,7 @@ export class Breaker { private static _maxCallTimes: number = 10 // 出现 ${maxCallTimes} 次后不再显示 private static _detachTimes: number = 500 // 出现 ${detachTimes} 次后取消 hook - private static _callTimesInline: number = 0 // log行间暂时的编号 + private static _callTimesInline: number = 0 // log行间暂时的编号 public static map_attachedMethodInfos: Map = new Map() private static map_methodInfo_callTimes: Map = new Map() private static array_methodInfo_detached: Array = new Array() @@ -99,7 +99,7 @@ export class Breaker { FC.printTitile(`Found : ClassName: ${clsTmp.name} @ ${clsTmp.handle}`) innerImage(clsTmp.handle) // innerImage(Il2Cpp.Domain.assembly("UnityEngine.AndroidJNIModule").image.class("UnityEngine.AndroidJNIHelper").handle) - } else if ("AUI") { + } else if (type == "AUI") { innerImage(Il2Cpp.Domain.assembly("Assembly-CSharp").image.handle) setTimeout(() => h("Update"), 3000) } else if (type == "Soon") { @@ -214,7 +214,7 @@ export class Breaker { } catch { catchError(method) } function catchError(method: Il2Cpp.Method): void { - LOGE(methodToString(method, false, '[-]')) + LOGE(methodToString(method, false, '[!]')) if (Process.arch == "arm") { let ins = method.virtualAddress.readPointer() if (ins != null && ins.equals(0xE12FFF1E)) showErrorLog(ins) @@ -562,10 +562,10 @@ globalThis.BFA = (filterStr: string, allImg: boolean = true): void => { globalThis.getPlatformCtxWithArgV = (ctx: T, argIndex: number): NativePointer | undefined => { if ((ctx as ArmCpuContext).r0 != undefined) { if (argIndex > 15 || argIndex < 0) throw new Error(`ARM32 -> argIndex ${argIndex} is out of range`) - return eval(`(ctx as ArmCpuContext).r${argIndex}`) as NativePointer + return eval(`((ctx as ArmCpuContext).r${argIndex})`) as NativePointer } else { if (argIndex > 32 || argIndex < 0) throw new Error(`ARM64 -> argIndex ${argIndex} is out of range`) - return eval(`(ctx as Arm64CpuContext).x${argIndex}`) as NativePointer + return eval(`((ctx as Arm64CpuContext).x${argIndex})`) as NativePointer } } diff --git a/Il2cppHook/agent/expand/TypeExtends/mscorlibObj/Object/GameObject/export.ts b/Il2cppHook/agent/expand/TypeExtends/mscorlibObj/Object/GameObject/export.ts index 8589b05a..b50e2057 100644 --- a/Il2cppHook/agent/expand/TypeExtends/mscorlibObj/Object/GameObject/export.ts +++ b/Il2cppHook/agent/expand/TypeExtends/mscorlibObj/Object/GameObject/export.ts @@ -5,7 +5,7 @@ import { setActiveT, setActiveTChange } from "../Component/export" import { checkExtends } from "../../ValueType/exports" import { allocP } from "../../../../../utils/alloc" -enum activeStatus { +export enum activeStatus { active = 1, inactive = 0, all = -1 @@ -28,9 +28,9 @@ globalThis.HookSetActive = (defaltActive: activeStatus | boolean = activeStatus. function innerSetActive(mPtr: GobjPtr, ctx: CpuContext) { if (mPtr.isNull()) return - let gameObject = new Il2Cpp.GameObject(ptr(mPtr as unknown as number)) + const gameObject = new Il2Cpp.GameObject(ptr(mPtr as unknown as number)) const currentActive: boolean = getPlatformCtxWithArgV(ctx, 1)!.isNull() ? false : true - const activeSelf: boolean = gameObject.get_activeSelf() + const _activeSelf: boolean = gameObject.get_activeSelf() if (filterString != "") { if (filterString instanceof Array) { let isPass = false @@ -66,7 +66,7 @@ globalThis.HookSetActive = (defaltActive: activeStatus | boolean = activeStatus. function printMsg() { if (!mPtr.isNull()) { - let strTmp = "public extern void SetActive( " + (currentActive ? 'true' : 'false') + " ); LR:" + checkCtx(ctx) + const strTmp = "public extern void SetActive( " + (currentActive ? 'true' : 'false') + " ); LR:" + checkCtx(ctx) LOGW("\n" + getLine(strTmp.length)) LOGD(strTmp) LOGO(getLine(strTmp.length / 2)) diff --git a/Il2cppHook/agent/expand/TypeExtends/mscorlibObj/Object/export.ts b/Il2cppHook/agent/expand/TypeExtends/mscorlibObj/Object/export.ts index b98ef39c..ac70b820 100644 --- a/Il2cppHook/agent/expand/TypeExtends/mscorlibObj/Object/export.ts +++ b/Il2cppHook/agent/expand/TypeExtends/mscorlibObj/Object/export.ts @@ -18,6 +18,7 @@ globalThis.getObjName = (mPtr: NativePointer): string => { globalThis.getObjClass = (mPtr: NativePointer): NativePointer => { if (typeof mPtr == "number") mPtr = ptr(mPtr) + if (typeof mPtr == "string" && (mPtr as string).startsWith("0x")) mPtr = ptr(mPtr) let obj = new UnityEngine_Object(mPtr) return obj.class.handle } diff --git a/Il2cppHook/agent/java/hooks.ts b/Il2cppHook/agent/java/hooks.ts index 42fee93a..7cb5a14d 100644 --- a/Il2cppHook/agent/java/hooks.ts +++ b/Il2cppHook/agent/java/hooks.ts @@ -3,12 +3,22 @@ import { getThreadName } from "../base/extends" export function HookReflect(bt: boolean = true) { Java.perform(() => { let Method = Java.use('java.lang.reflect.Method') - Method.invoke.overload('java.lang.Object', '[Ljava.lang.Object;').implementation = function (obj: any, args: any) { - if (Hooks_value_hideJavaLog) return this.invoke(obj, args) - let params: string = args.length == 0 ? '' : JSON.stringify(args) - LOGW(`CALLED -> ${this.toString()}`) - LOGZ(`\tPARAMS[${args.length}] -> ${params}`) - if (bt) PrintStackTraceJava() + Method.invoke.overload('java.lang.Object', '[Ljava.lang.Object;').implementation = function (obj: any, args: string | any[]) { + const thisName = this.toString() + LOGW(`CALLED -> ${thisName}`) + if (thisName.includes('com.google.android.gms') + ||thisName.includes('com.google.firebase') + ||thisName.includes('com.adjust.sdk') + ||thisName.includes('java.util.ArrayList') + ||thisName.includes('java.util.HashMap') + ||thisName.includes('android.security.net') + ||thisName.includes('java.security.spec') + ||thisName.includes('javax.net.ssl') + ||thisName.includes('sun.misc.Unsafe') + ){ + return this.invoke(obj, args) + } + PrintStackTraceJava() return this.invoke(obj, args) } }) @@ -815,31 +825,35 @@ const HookExit = (bt: boolean = true) => { LOGE(`ERROR Hook libc.so::abort @ ${Module.findExportByName("libc.so", "abort")!}`) } - Il2Cpp.perform(() => { - try { - // UnityEngine.CoreModule UnityEngine.Application Quit(Int32) : Void - R(Il2Cpp.Domain.assembly("UnityEngine.CoreModule").image.class("UnityEngine.Application").method("Quit", 1).virtualAddress, (_srcCall: Function, arg0: NativePointer) => { - // srcCall(arg0, arg1, arg2, arg3) - LOGE("called UnityEngine.Application.Quit(" + arg0.toInt32() + ")") - return ptr(0) - }) - LOGW(`Hook UnityEngine.Application.Quit(Int32) @ ${Il2Cpp.Domain.assembly("UnityEngine.CoreModule").image.class("UnityEngine.Application").method("Quit", 1).virtualAddress}`) - } catch (error) { - LOGE(`ERROR Hook UnityEngine.Application.Quit(Int32)`) - } - - try { - // UnityEngine.CoreModule UnityEngine.Application Quit() : Void - R(Il2Cpp.Domain.assembly("UnityEngine.CoreModule").image.class("UnityEngine.Application").method("Quit").virtualAddress, (_srcCall: Function) => { - // srcCall(arg0, arg1, arg2, arg3) - LOGE("called UnityEngine.Application.Quit()") - return ptr(0) - }) - LOGW(`Hook UnityEngine.Application.Quit() @ ${Il2Cpp.Domain.assembly("UnityEngine.CoreModule").image.class("UnityEngine.Application").method("Quit").virtualAddress}`) - } catch (error) { - LOGE(`ERROR Hook UnityEngine.Application.Quit()`) - } - }) + try { + Il2Cpp.perform(() => { + try { + // UnityEngine.CoreModule UnityEngine.Application Quit(Int32) : Void + R(Il2Cpp.Domain.assembly("UnityEngine.CoreModule").image.class("UnityEngine.Application").method("Quit", 1).virtualAddress, (_srcCall: Function, arg0: NativePointer) => { + // srcCall(arg0, arg1, arg2, arg3) + LOGE("called UnityEngine.Application.Quit(" + arg0.toInt32() + ")") + return ptr(0) + }) + LOGW(`Hook UnityEngine.Application.Quit(Int32) @ ${Il2Cpp.Domain.assembly("UnityEngine.CoreModule").image.class("UnityEngine.Application").method("Quit", 1).virtualAddress}`) + } catch (error) { + LOGE(`ERROR Hook UnityEngine.Application.Quit(Int32)`) + } + + try { + // UnityEngine.CoreModule UnityEngine.Application Quit() : Void + R(Il2Cpp.Domain.assembly("UnityEngine.CoreModule").image.class("UnityEngine.Application").method("Quit").virtualAddress, (_srcCall: Function) => { + // srcCall(arg0, arg1, arg2, arg3) + LOGE("called UnityEngine.Application.Quit()") + return ptr(0) + }) + LOGW(`Hook UnityEngine.Application.Quit() @ ${Il2Cpp.Domain.assembly("UnityEngine.CoreModule").image.class("UnityEngine.Application").method("Quit").virtualAddress}`) + } catch (error) { + LOGE(`ERROR Hook UnityEngine.Application.Quit()`) + } + }) + } catch (error) { + LOGE(error) + } } declare global { diff --git a/Il2cppHook/agent/utils/context.ts b/Il2cppHook/agent/utils/context.ts index 29521415..2fbd08f4 100644 --- a/Il2cppHook/agent/utils/context.ts +++ b/Il2cppHook/agent/utils/context.ts @@ -6,7 +6,7 @@ import { LogColor } from "../base/enum" * @param {Int} range 展示的范围 * @param {Int} type 1:正向 2:反向(小端存储,同IDA) 不填写着以当前pointer为中心位置打印信息 */ -var printCtx = (mPtr: NativePointer | number, range: number = 5, type: number = 0, redLine: LogColor = LogColor.WHITE, space: number = 0) => { +export const printCtx = (mPtr: NativePointer | number, range: number = 5, type: number = 0, redLine: LogColor = LogColor.WHITE, space: number = 0) => { if (Process.arch != "arm") return mPtr = checkPointer(mPtr) if (mPtr.isNull()) return @@ -36,10 +36,8 @@ var printCtx = (mPtr: NativePointer | number, range: number = 5, type: number = } } -globalThis.printCtx = printCtx - declare global { var printCtx: (mPtr: NativePointer | number, range?: number, type?: number, redLine?: number, space?: number) => void } -export { printCtx } \ No newline at end of file +globalThis.printCtx = printCtx \ No newline at end of file diff --git a/README.md b/README.md index 9ec382c6..fff4e4a3 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ ### frida-based libil2cpp.so runtime parsing script +[**简体中文**](README.zh-CN.md) + [![npm license](https://img.shields.io/npm/l/il2cpp-hooker.svg)](https://www.npmjs.com/package/il2cpp-hooker) ![Build Status](https://github.com/axhlzy/Il2CppHookScripts/actions/workflows/Auto-build.yml/badge.svg) [![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/axhlzy/Il2CppHookScripts) diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 00000000..c32cd94f --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,123 @@ +### Il2cppHook + +### 基于 frida 的 libil2cpp.so 运行时解析脚本 + +[![npm license](https://img.shields.io/npm/l/il2cpp-hooker.svg)](https://www.npmjs.com/package/il2cpp-hooker) +![Build Status](https://github.com/axhlzy/Il2CppHookScripts/actions/workflows/Auto-build.yml/badge.svg) +[![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/axhlzy/Il2CppHookScripts) +[![npm version](https://img.shields.io/npm/v/il2cpp-hooker.svg)](https://www.npmjs.com/package/il2cpp-hooker) +[![npm downloads](https://img.shields.io/npm/dm/il2cpp-hooker.svg)](https://www.npmjs.com/package/il2cpp-hooker) + +#### 功能 + +- 解析 Unity 的 方法`m` | 类`c` | 字段`f` | 实例`lfs`/`lfp` +- 解析运行时方法参数 `b` / `bt` | nop 函数 `n` | detachAll 和清理缓存 `D` +- 批量HOOK常用函数 `B/BF/BN`, 修改函数返回值 `setFunctionXXX`, `setActive` 设置游戏对象的活动状态 +- 封装 “Interceptor.attach”,使其更易于从命令行使用 `A(ptr,(args)=>{},(ret)=>{})` +- 更方便地查找函数 `findMethods` / `findClasses` 并调用函数 `callFunction` / `findExport` 查找导出函数 +- `showMethodInfo` 帮助我们简单地获取 Il2cppMethod* 的详细信息,获取游戏对象的详细信息使用`showGameObject` +- 对象层次结构 `PrintHierarchy` / 类型层次结构 `showTypeParent` +- 用frida和方法信息反汇编`showAsm`,`seeHexA`表示十六进制转储 +- `breakWithStack` 为 il2cpp 提供更多符号解析,`breakWithArgs` 只显示 args +- 常用HOOK封装 `HookOnPointerClick` / `HookSetActive` / `B_Button` / `HookPlayerPrefs` ... +- 解析挂载脚本 `showComponents` | `PrintHierarchyWithComponents` +- JNI RegisterNatives 挂钩(在 JNIHelper 中植入,默认关闭 [不稳定]),使用 JNIHelper.cacheRegisterNativeItem 获取信息 !测试! +- 使用 QBDI 模拟函数的执行,使用 t(methoinfo) 或 traceFunction(mPtr) 启用替换钩子!测试! +- :confused: :confused: :confused: + +------- + +#### 安装 +```sh +$ npm install il2cpp-hooker -g +``` + +然后你可以像这样使用 ↓ + +1. frida attch current app +```sh +$ fat + +``` +2. frida spawn app of ${PackageName} +```sh +$ fat ${PackageName} +``` + +3. 命令行选项 +```sh +$ fat -h + + _ _ ______ _ _ + | | |(_____ \ | | | | + | | | ____) )____ ____ ____ _____| |__ ___ ___ | | _ _____ ____ + | | | / ____// ___) _ \| _ (_____) _ \ / _ \ / _ \| |_/ ) ___ |/ ___) + | | || (____( (___| |_| | |_| | | | | | |_| | |_| | _ (| ____| | + |_|_|\______)____) __/| __/ |_| |_|\___/ \___/|_| \_)_____)_| + |_| |_| + +用法: fat [options] + +选项: + -h, --help 打印使用信息。 + -r, --runtime [engine] 指定 JS 引擎(qjs, v8)。默认:v8 + -t,--timeout [ms] 以毫秒为单位指定调用函数前的时间。 + -f,--functions[名称] 指定启动时要调用的函数,例如:-f getApkInfo(); + -l, --log [path] 指定保存日志的路径。 + -c,--vscode 使用 vscode 打开项目。 + -v,--版本 打印版本信息。 + +报告错误: + axhlzy (https://github.com/axhlzy/Il2CppHookScripts/) + +``` + +------- + +[](https://codespaces.new/axhlzy/Il2CppHookScripts) + +#### 编译 +```sh +$ git clone https://github.com/axhlzy/Il2CppHookScripts.git +$ cd Il2cppHook/ + +$ npm install + +$ npm run build & npm run compress + +$ frida -U -f com.xxx.xxx -l ../_Ufunc.js +或者 +$ frida -FU -l ../_Ufunc.js +``` + +------- + +#### 或者是这样使用(未及时更新) +`frida --codeshare axhlzy/il2cpphookscripts -U -f ${PackageName}` + +> 需要科学上网 + +------- + +> [!] +> npm 软件包可能无法及时更新,因此您可以考虑使用 `fat -c` 打开项目,并使用 `github action` [Artifacts](https://github.com/axhlzy/Il2CppHookScripts/actions) 替换 _Ufunc.js 文件。 :hushed: + +------- + +#### API + +[更多详情](https://github.com/axhlzy/Il2CppHookScripts/wiki) + +或 + +使用 vscode 打开并搜索 `globalthis.` 以查找更多用法 + +------- + +请作者喝杯咖啡 (^_^) + + + + + + \ No newline at end of file