func-naming · git:20261108.0f92827 · 2026-11-08 · sha256 82f032c7cecdca5f

func-naming git:20261108.0f92827A

Immutable. This exact content never changes and is served at /api/v1/blob/82f032c7cecdca5f.

---
name: func-naming
description: 已知地址判断函数用途/算法(无符号函数命名):先查 .dynsym,再取字符串/魔数/成对调用特征,最后回填命名。SO 层深挖的单步能力,入口仍在 frida-mobile-security;恢复结构体用 native-analysis §3.7,判漏洞用 native-audit。
---

# func-naming - 无符号函数命名

输入一个地址,输出"它是什么函数 / 什么算法"。

## 何时用 / 何时不用

| 用 | 不用 |
|---|---|
| 已有地址(callers / strref / 崩溃偏移 / hook 栈),函数无符号 | 函数已有符号 → 先查 `.dynsym`,命中直接用 |
| 要判断算法(哈希/编码/压缩/加解密) | 要恢复参数布局 → [native-analysis.md ›「3.7 结构体恢复(偏移聚合)」](../../../references/native-analysis.md#37-结构体恢复偏移聚合) |
| 要给报告/后续 hook 一个可读名字 | 要判漏洞/可达性 → `references/native-audit.md` |

## 前置

0. **先定地址体系**(混用必空 hook):

   | 来源 | 地址类型 |
   |---|---|
   | `so.py` / Frida | ELF **vaddr** → `mod.base.add(vaddr)` |
   | **IDA** | ELF **vaddr**(imagebase 通常 0) |
   | **Ghidra** | vaddr **+ image_base**(默认 `0x100000`,用 `ghidra_get_current_program_info` 确认) |
   | 文件偏移 | 查 PT_LOAD;**vaddr ≠ offset 时不可当 vaddr 用** |

   拿地址先问它来自哪个工具。同一地址 IDA 能跳、Ghidra 打空,是基址差,不是代码问题。
   (`so.py info` 的 `raw=YES/NO` 只表示该段 `vaddr == offset`,不是错误。)

1. `.so` 已拉到本地(`adb pull`)。
2. 记录地址来源(哪条字符串 / 哪个 caller / 哪个崩溃偏移)。
3. `so.py` 可用;`llvm-nm` 在 NDK bin 下(不在 PATH)。
4. 不熟 `so.py` / Ghidra 的完整用法时,先看 [native-analysis.md ›「3.5 SO 分析顺序(tools/so.py 离线工具)」](../../../references/native-analysis.md) 与 [「四、SO 静态分析(Ghidra MCP)」](../../../references/native-analysis.md)。

## 步骤

### 1. 先查符号表(30 秒,最容易漏)

```bash
python3 tools/so.py info <so> --json
# NDK: llvm-nm -D --defined-only <so> | findstr /i <addr>
```

命中即用符号名结束。C++ mangled(`_Z...`)用 `llvm-cxxfilt` 还原签名。

### 2. 确认函数起点

地址来自字符串 xref 时,xref 可能落在内联 `assert`/尾部。向上找序言(`stp x29, x30` / `sub sp, sp`)再继续。

### 3. 取特征(离线优先)

```bash
python3 tools/so.py strings <so> --grep <PAT> --min 8   # 找语义字符串
python3 tools/so.py strref  <so> 0x<STR_VADDR>          # 串 → 引用点
python3 tools/so.py disasm  <so> --addr 0x<FUNC> --count 60
python3 tools/so.py callers <so> 0x<FUNC>               # 调用者
```

需要伪代码、数据 xref、改名时上 Ghidra(见下一步)。

### 4. Ghidra 接手(伪代码 / 数据 xref / 改名)

**so.py 是快查,Ghidra 是语义;两者协作,不是替代。**

1. callee 全是 `func_0x…` → 先跑 `tools/ghidra/so_audit_prep.java` 做 PLT 命名(见 [native-audit.md ›「4.1 前置:Ghidra 两件事(不做就无法审)」](../../../references/native-audit.md))
2. 导入:**只传 `file_path`**,不要传 `language`——对 ELF 传 language 会按 **Raw Binary** 导入(0 函数、1 符号)
3. 地址换算:`Ghidra 地址 = so.py 地址 + image_base`(默认 `0x100000`,用 `ghidra_get_current_program_info` 确认)
4. 伪代码:`ghidra_decompile_function`
5. 间接引用:`so.py callers` 为 0 时用 `ghidra_get_function_xrefs`(含 DATA/虚表引用)
6. 改名:`ghidra_rename_function_by_address` → 重反编译调用方,确认新名已传播

> 字符串 xref 用 `so.py strref` 更快;Ghidra 对未定义数据的 xref 可能查不到。
>
> Ghidra 工作流(导入/连接/工具组)见 [native-analysis.md ›「四、SO 静态分析(Ghidra MCP)」](../../../references/native-analysis.md)。

### 5. 特征比对

| 看到 | 结论 |
|---|---|
| `0x67452301` `0xEFCDAB89` `0x98BADCFE` `0x10325476` | MD5 |
| `0xEDB88320` | CRC32 |
| `0x63 0x7C 0x77 0x7B` | AES S-Box |
| Base64 字符表 | Base64 |
| `0x78` / `0x9C` 开头 | zlib |
| `p = A(size)` … `B(p)` | malloc/free |
| `A(lock)` … `B(lock)` | lock/unlock |
| `fd = A(path, flags)` … `B(fd)` | open/close |
| `sub_XXX(2, 1, 0)` | socket(AF_INET, SOCK_STREAM, 0) |
| 错误返回 `-1` / 失败返回 `NULL` / 成功返回 `0` | 文件·分配·状态函数 |

完整表(魔数、成对调用、参数/返回值模式、caller 递归)见手册。

**识别出来之后去哪**(避免在大方向上原地打转):

| 结论 | 下一步 |
|---|---|
| 加解密 / 哈希 / 编码 | [crypto-hook.md ›「一、加密算法分析决策树」](../../../references/crypto-hook.md)(hook 明文/密钥) |
| 参数是对象/结构体 | [native-analysis.md ›「3.7 结构体恢复(偏移聚合)」](../../../references/native-analysis.md#37-结构体恢复偏移聚合)(偏移聚合) |
| 能被外部输入走到 | [native-audit.md ›「SO 漏洞审计(可达面优先)」](../../../references/native-audit.md)(可达性/漏洞) |
| 静态看不清、需要真实参数 | [api-reference.md ›「Frida API 参考手册」](../../../references/api-reference.md) + [native-analysis.md ›「三、SO 动态分析」](../../../references/native-analysis.md) |
| 需要离线复算 | [native-analysis.md ›「3.6 复杂函数离线仿真(emu_run 广度 + setup 助手)」](../../../references/native-analysis.md) 或 skill `so-emulate` |

### 6. 命名 + 回填 + 验证

- 写进 `REPORT.md`:地址 / 建议名 / 置信度 / 依据
- Ghidra 里 `ghidra_rename_function`(可选)
- 重新反编译调用点,看新名字是否自洽;不自洽就降置信度并记录反例

## 卡壳出口

| 症状 | 处理 |
|---|---|
| `strref` 无命中 | 可能经表/重定位引用:Ghidra xrefs 或 `disasm --grep "adrp\|adr"` |
| xref 落在 `assert` 尾段 | 回找 prologue,从函数起点重来 |
| `callers` 返回 0 | 先用 `ghidra_get_function_xrefs`(含 DATA/虚表);再在 `.data`/`.rela.dyn` 搜 8 字节小端地址 |
| 混淆 / 静态链接库 / JNI 动态注册 | 见手册卡壳树 |

详细处理与实例:[references/so-func-naming.md ›「5. 卡壳树(真实场景)」](../../../references/so-func-naming.md#5-卡壳树真实场景)。

## 产出

- `REPORT.md` 命名表(地址 / 名称 / 置信度 / 依据)
- 必要时 Ghidra 重命名