Skip to content

Commit

Permalink
update readme / fix HookReflect
Browse files Browse the repository at this point in the history
  • Loading branch information
axhlzy committed Aug 20, 2024
1 parent 5d3b2b2 commit 2d9a834
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 44 deletions.
10 changes: 5 additions & 5 deletions Il2cppHook/agent/base/breaker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Il2Cpp.Method, InvocationListener> = new Map()
private static map_methodInfo_callTimes: Map<Il2Cpp.Method, number> = new Map()
private static array_methodInfo_detached: Array<Il2Cpp.Method> = new Array<Il2Cpp.Method>()
Expand Down Expand Up @@ -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") {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -562,10 +562,10 @@ globalThis.BFA = (filterStr: string, allImg: boolean = true): void => {
globalThis.getPlatformCtxWithArgV = <T extends CpuContext>(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
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
76 changes: 45 additions & 31 deletions Il2cppHook/agent/java/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
})
Expand Down Expand Up @@ -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 {
Expand Down
6 changes: 2 additions & 4 deletions Il2cppHook/agent/utils/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 }
globalThis.printCtx = printCtx
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
123 changes: 123 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -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] <package-name?>

选项:
-h, --help 打印使用信息。
-r, --runtime [engine] 指定 JS 引擎(qjs, v8)。默认:v8
-t,--timeout [ms] 以毫秒为单位指定调用函数前的时间。
-f,--functions[名称] 指定启动时要调用的函数,例如:-f getApkInfo();
-l, --log [path] 指定保存日志的路径。
-c,--vscode 使用 vscode 打开项目。
-v,--版本 打印版本信息。

报告错误:
axhlzy <[email protected]> (https://github.com/axhlzy/Il2CppHookScripts/)

```

-------

[<img src=“https://github.com/codespaces/badge.svg” title=“在 Github 代码空间打开”>](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.` 以查找更多用法

-------

请作者喝杯咖啡 (^_^)

<img src=https://github.com/axhlzy/Il2CppHookScripts/assets/20512058/618a0674-e5ad-4c0f-9435-f7e133d4b293 width=“300” height=“400”>

<!-- qq:597290673 -->
<!-- wx:axhlzy0922 -->
<!-- tg:axhlzy -->

0 comments on commit 2d9a834

Please sign in to comment.