reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
# re-android-native 经验全集
> 条目含来源与日期;入库前 grep 去重。格式: **标题**:现象——…;原因——…;对策——…
## 2026-09-01 · 会话复盘
**JNIEnv 表槽定位法(hook 抓明文/注册表)**:现象——想抓 JNI 层字符串明文或动态注册表,却不知从哪 hook;原因——JNIEnv 是函数表指针(`[env]` = JNINativeInterface 表),各 API 是表槽(偏移 = 槽号×8),关键槽: `NewStringUTF`=0x538(槽167)、`RegisterNatives`=0x6b8(槽215);对策——`memory.pointer([env]).getLong(0)` 拿表基址,读槽值得实现地址,code hook 该地址:NewStringUTF 命中时 x1=明文、LR=调用点;RegisterNatives 命中时读 methods 数组(名称/签名/地址三指针)。调用点静态定位: 全库搜 `ldr xN, [xN, #0x538]`。来源:Android 商业应用 native 层分析实战
**注册表拿不到时的裸调用匹配(重建动态注册函数表)**:现象——动态注册的 native 方法,注册表(方法名+签名+地址)加密存储、strings 搜不到,运行时也不注册(模拟器无 ART);原因——注册表本身被加密,注册依赖真实运行时;对策——绕开注册表: ① 全量扫 `.text` 找函数入口(`stp x29,x30` 序言)② 叶子筛选(函数体内无内部 bl)③ 裸调用 `callFunction(addr, jniEnv, 0)`(每候选独立模拟器防状态污染)④ 按返回特征匹配: 0/1=boolean、小值=long/枚举、指针=String/回调 ⑤ 全局读取特征聚类(adrp 目标页)分组。已验证: 158 个候选零崩溃,14 个 boolean、2 个 long、8 个指针函数确认。来源:Android 商业应用 native 层分析实战
**懒解密/延迟注册的模拟边界**:现象——模拟器里 JNI_OnLoad 全路径执行、注册表槽 hook 零命中,以为漏了逻辑;原因——商业应用把字符串解密/方法注册推迟到 Java 调用链触发(类首次使用),模拟器无 dex 类加载能力,调用链无法构造;对策——先静态验证"启动路径确实不注册"(执行路径追踪+槽 hook),再判断为运行时触发;字符串/注册表的最终获取走真机 frida,模拟器能摸到哪就到哪,不硬啃。来源:Android 商业应用 native 层分析实战

View File

@@ -0,0 +1,52 @@
# JNI 运行探针(Runtime Probes)
易变参数层:ABI 传参寄存器 / libart 内部结构 / runtime 实现细节——**不写进 SKILL.md 核心流程**(NDK / ART 版本变化可能影响实现),以运行时探测与校验为准。`JNIEnv` 函数表的 index 布局属固定 ABI(`RegisterNatives`=215),不在此列。
## RegisterNatives 槽位定位
`RegisterNatives` 位于标准 `JNIEnv` function table index **215**(`UnregisterNatives` 216)——JNI ABI 的固定布局,JDK 8/11/17/27、GraalVM 21、Android NDK 均一致(新增 helper 只追加在尾部,不改动已有 index)。实际 byte offset = index × 目标指针宽度:64 位下 215×8=0x6B8,32 位下 215×4=0x35C。
### 运行时锚点(校验用)
index 固定不代表运行时实现一定符合规范——以下锚点用于**校验**而非推导:
- 从 `JNIEnv*` 取函数表基址,读 index 215 槽值;按签名形态 `(JNIEnv*, jclass, JNINativeMethod*, jint)` 打桩调用确认
- 交叉校验其他固定槽:`NewStringUTF`=167、`GetJavaVM`=219(语义稳定、调用频繁,适合作有效性锚点)
- 槽值异常(为空、指向非 libart/系统库范围、多槽指向同一地址)→ 疑 hook/代理函数表或非标准实现,先还原再继续
### 备选:ART 内部函数 hook(版本绑定)
`art::JNI::RegisterNatives`(libart.so 导出符号,debuggable 进程可见)——符号名跨版本稳定,内部结构随 ART 版本变化,仅作交叉验证,不写死偏移。
## Frida 脚本模板
```js
// hook JNI_OnLoad 后按固定 index 定位 RegisterNatives
var REGISTER_NATIVES_INDEX = 215; // JNI ABI 固定槽位
Interceptor.attach(Module.findGlobalExportByName("JNI_OnLoad"), { // Frida 17+:全局符号静态查找
onEnter: function () {
var env = this.context.x0; // arm64: JNIEnv* 在 x0(ABI 相关,见下)
var table = env.readPointer(); // env[0] = JNINativeInterface 函数表
var RegisterNatives = table.add(REGISTER_NATIVES_INDEX * Process.pointerSize).readPointer();
if (RegisterNatives.isNull()) { console.log("槽位为空——疑非标准实现或 hook 表"); return; }
Interceptor.attach(RegisterNatives, { onEnter: function (a) {
console.log("RegisterNatives:", a[1], a[2].readPointer()); // clazz + methods 数组
}});
}
});
```
**ABI 注记(易变)**:JNIEnv* 传参寄存器随 ABI——arm64 x0、arm32 r0、x86_64 rdi——以 `this.context` 当前架构为准,不写死。
## Runtime 校验清单
hook 生效后逐项校验,防误 hook:
1. **参数形态**:hook 到的方法被调用且参数形态符合 `(JNIEnv*, jclass, JNINativeMethod*, jint)`;形态不符 → 疑非标准实现或调用点误判
2. **函数表有效性**:用 `NewStringUTF`(167) / `GetJavaVM`(219) 等固定槽交叉验证表基址正确、无 hook/代理函数表
3. **多 ABI**:每个 ABI(arm64-v8a / armeabi-v7a / x86_64)独立确认——index 一致,但传参寄存器与指针宽度不同(byte offset 随宽度变化),脚本按 `Process.arch` 分支
## 使用注意
- 函数表 index 是固定 ABI,勿再「按 jni.h 声明序重新推导」;真正易变的是 ABI 传参寄存器、libart 内部结构与 runtime 实现细节,以目标环境实测为准
- 核心流程(SKILL.md 步骤 3)只描述机制与策略,易变数值一律在本文件维护