mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/generic-methodologies-and-resources/basic-forensic-meth
This commit is contained in:
parent
8246afa30b
commit
4fea614268
@ -2,7 +2,7 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## 取证备忘单
|
||||
## 取证速查表
|
||||
|
||||
[https://www.jaiminton.com/cheatsheet/DFIR/#](https://www.jaiminton.com/cheatsheet/DFIR/)
|
||||
|
||||
@ -24,8 +24,8 @@ sudo apt-get install -y yara
|
||||
```
|
||||
#### 准备规则
|
||||
|
||||
使用此脚本从github下载并合并所有yara恶意软件规则: [https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9](https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9)\
|
||||
创建_**rules**_目录并执行它。这将创建一个名为_**malware_rules.yar**_的文件,其中包含所有恶意软件的yara规则。
|
||||
使用此脚本从 github 下载并合并所有 yara malware rules: [https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9](https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9)\
|
||||
创建 _**rules**_ 目录并执行它。 这将创建一个名为 _**malware_rules.yar**_ 的文件,包含所有 yara malware rules。
|
||||
```bash
|
||||
wget https://gist.githubusercontent.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9/raw/4ec711d37f1b428b63bed1f786b26a0654aa2f31/malware_yara_rules.py
|
||||
mkdir rules
|
||||
@ -36,9 +36,9 @@ python malware_yara_rules.py
|
||||
yara -w malware_rules.yar image #Scan 1 file
|
||||
yara -w malware_rules.yar folder #Scan the whole folder
|
||||
```
|
||||
#### YaraGen: 检查恶意软件并创建规则
|
||||
#### YaraGen: 检查 malware 并创建 yara rules
|
||||
|
||||
您可以使用工具 [**YaraGen**](https://github.com/Neo23x0/yarGen) 从二进制文件生成 yara 规则。查看这些教程: [**第 1 部分**](https://www.nextron-systems.com/2015/02/16/write-simple-sound-yara-rules/), [**第 2 部分**](https://www.nextron-systems.com/2015/10/17/how-to-write-simple-but-sound-yara-rules-part-2/), [**第 3 部分**](https://www.nextron-systems.com/2016/04/15/how-to-write-simple-but-sound-yara-rules-part-3/)
|
||||
你可以使用工具 [**YaraGen**](https://github.com/Neo23x0/yarGen) 从 binary 生成 yara rules。查看这些教程:[**Part 1**](https://www.nextron-systems.com/2015/02/16/write-simple-sound-yara-rules/), [**Part 2**](https://www.nextron-systems.com/2015/10/17/how-to-write-simple-but-sound-yara-rules-part-2/), [**Part 3**](https://www.nextron-systems.com/2016/04/15/how-to-write-simple-but-sound-yara-rules-part-3/)
|
||||
```bash
|
||||
python3 yarGen.py --update
|
||||
python3.exe yarGen.py --excludegood -m ../../mals/
|
||||
@ -57,25 +57,25 @@ clamscan folderpath #Scan the whole folder
|
||||
```
|
||||
### [Capa](https://github.com/mandiant/capa)
|
||||
|
||||
**Capa** 检测可执行文件中的潜在恶意 **能力**:PE、ELF、.NET。因此,它会找到诸如 Att\&ck 策略或可疑能力,例如:
|
||||
**Capa** 在可执行文件:PE、ELF、.NET 中检测潜在恶意的 **能力**。因此它会发现诸如 Att\&ck tactics 的条目,或以下可疑能力:
|
||||
|
||||
- 检查 OutputDebugString 错误
|
||||
- 作为服务运行
|
||||
- 创建进程
|
||||
- check for OutputDebugString error
|
||||
- run as a service
|
||||
- create process
|
||||
|
||||
在 [**Github repo**](https://github.com/mandiant/capa) 中获取它。
|
||||
可在 [**Github repo**](https://github.com/mandiant/capa) 获取。
|
||||
|
||||
### IOCs
|
||||
|
||||
IOC 代表妥协指标。IOC 是一组 **条件,用于识别** 一些潜在的不需要的软件或确认的 **恶意软件**。蓝队使用这种定义来 **搜索这种恶意文件** 在他们的 **系统** 和 **网络** 中。\
|
||||
共享这些定义非常有用,因为当恶意软件在计算机中被识别并为该恶意软件创建 IOC 时,其他蓝队可以使用它更快地识别恶意软件。
|
||||
IOC 表示入侵指标。IOC 是一组 **用于识别** 某些潜在不受欢迎软件或已确认 **malware** 的 **条件**。Blue Teams 使用这种定义在其 **系统** 和 **网络** 中 **搜索此类恶意文件**。\
|
||||
共享这些定义非常有用,因为当在一台计算机中识别出 malware 并为其创建 IOC 后,其他 Blue Teams 可以使用该 IOC 更快地识别该 malware。
|
||||
|
||||
创建或修改 IOCs 的工具是 [**IOC Editor**](https://www.fireeye.com/services/freeware/ioc-editor.html)**.**\
|
||||
您可以使用 [**Redline**](https://www.fireeye.com/services/freeware/redline.html) 等工具来 **搜索设备中的定义 IOC**。
|
||||
用于创建或修改 IOCs 的工具有 [**IOC Editor**](https://www.fireeye.com/services/freeware/ioc-editor.html)**.**\
|
||||
你可以使用诸如 [**Redline**](https://www.fireeye.com/services/freeware/redline.html) 的工具来 **在设备中搜索已定义的 IOCs**。
|
||||
|
||||
### Loki
|
||||
|
||||
[**Loki**](https://github.com/Neo23x0/Loki) 是一个简单妥协指标的扫描器。\
|
||||
[**Loki**](https://github.com/Neo23x0/Loki) 是一个用于扫描简单入侵指标的扫描器。\
|
||||
检测基于四种检测方法:
|
||||
```
|
||||
1. File Name IOC
|
||||
@ -92,41 +92,41 @@ Compares process connection endpoints with C2 IOCs (new since version v.10)
|
||||
```
|
||||
### Linux Malware Detect
|
||||
|
||||
[**Linux Malware Detect (LMD)**](https://www.rfxn.com/projects/linux-malware-detect/) 是一个针对Linux的恶意软件扫描器,发布于GNU GPLv2许可证,旨在应对共享托管环境中面临的威胁。它使用来自网络边缘入侵检测系统的威胁数据,提取正在攻击中积极使用的恶意软件,并生成检测签名。此外,威胁数据还来自用户提交的LMD结账功能和恶意软件社区资源。
|
||||
[**Linux Malware Detect (LMD)**](https://www.rfxn.com/projects/linux-malware-detect/) 是一个面向 Linux 的 malware 扫描器,基于 GNU GPLv2 许可发布,专为共享托管环境所面临的威胁而设计。它使用来自 network edge intrusion detection systems 的威胁数据来提取正在被用于攻击的 malware 并生成用于检测的签名。此外,威胁数据也来自用户通过 LMD checkout 功能提交的样本以及 malware community resources。
|
||||
|
||||
### rkhunter
|
||||
|
||||
像[**rkhunter**](http://rkhunter.sourceforge.net)这样的工具可以用来检查文件系统中可能存在的**rootkits**和恶意软件。
|
||||
像 [**rkhunter**](http://rkhunter.sourceforge.net) 这样的工具可用于检查文件系统以查找可能的 **rootkits** 和 malware。
|
||||
```bash
|
||||
sudo ./rkhunter --check -r / -l /tmp/rkhunter.log [--report-warnings-only] [--skip-keypress]
|
||||
```
|
||||
### FLOSS
|
||||
|
||||
[**FLOSS**](https://github.com/mandiant/flare-floss) 是一个工具,尝试使用不同的技术在可执行文件中查找混淆字符串。
|
||||
[**FLOSS**](https://github.com/mandiant/flare-floss) 是一个工具,会尝试使用不同的技术在可执行文件中查找混淆的字符串。
|
||||
|
||||
### PEpper
|
||||
|
||||
[PEpper](https://github.com/Th3Hurrican3/PEpper) 检查可执行文件中的一些基本内容(如二进制数据、熵、URLs 和 IPs,以及一些 yara 规则)。
|
||||
[PEpper ](https://github.com/Th3Hurrican3/PEpper) 会检查可执行文件中的一些基本内容(二进制数据、熵、URLs 和 IPs、一些 yara 规则)。
|
||||
|
||||
### PEstudio
|
||||
|
||||
[PEstudio](https://www.winitor.com/download) 是一个工具,可以获取 Windows 可执行文件的信息,如导入、导出、头部信息,同时还会检查病毒总数并找到潜在的 Att\&ck 技术。
|
||||
[PEstudio](https://www.winitor.com/download) 是一个可以获取 Windows 可执行文件信息的工具,例如 imports、exports、headers,同时也会检查 VirusTotal 并发现潜在的 Att\&ck 技术。
|
||||
|
||||
### Detect It Easy(DiE)
|
||||
|
||||
[**DiE**](https://github.com/horsicq/Detect-It-Easy/) 是一个工具,用于检测文件是否 **加密**,并找到 **打包器**。
|
||||
[**DiE**](https://github.com/horsicq/Detect-It-Easy/) 是一个用于检测文件是否 **encrypted** 并查找 **packers** 的工具。
|
||||
|
||||
### NeoPI
|
||||
|
||||
[**NeoPI**](https://github.com/CiscoCXSecurity/NeoPI) 是一个 Python 脚本,使用多种 **统计方法** 来检测文本/脚本文件中的 **混淆** 和 **加密** 内容。NeoPI 的预期目的是帮助 **检测隐藏的 web shell 代码**。
|
||||
[**NeoPI** ](https://github.com/CiscoCXSecurity/NeoPI) 是一个 Python 脚本,使用多种 **statistical methods** 来检测文本/脚本文件中 **obfuscated** 和 **encrypted** 的内容。NeoPI 的目的是帮助 **detection of hidden web shell code**。
|
||||
|
||||
### **php-malware-finder**
|
||||
|
||||
[**PHP-malware-finder**](https://github.com/nbs-system/php-malware-finder) 尽力检测 **混淆**/**可疑代码** 以及使用 **PHP** 函数的文件,这些函数通常用于 **恶意软件**/webshells。
|
||||
[**PHP-malware-finder**](https://github.com/nbs-system/php-malware-finder) 尽其所能检测 **obfuscated**/**dodgy code**,以及使用常见于 **malwares**/webshells 的 **PHP** 函数的文件。
|
||||
|
||||
### Apple Binary Signatures
|
||||
|
||||
在检查某些 **恶意软件样本** 时,您应该始终 **检查二进制文件的签名**,因为签名的 **开发者** 可能已经与 **恶意软件** **相关**。
|
||||
在检查某些 **malware sample** 时,你应始终 **check the signature** 二进制,因为签名的 **developer** 可能已经与 **malware** 有关联。
|
||||
```bash
|
||||
#Get signer
|
||||
codesign -vv -d /bin/ls 2>&1 | grep -E "Authority|TeamIdentifier"
|
||||
@ -139,27 +139,39 @@ spctl --assess --verbose /Applications/Safari.app
|
||||
```
|
||||
## 检测技术
|
||||
|
||||
### 文件堆叠
|
||||
### File Stacking
|
||||
|
||||
如果你知道某个包含**文件**的文件夹**最后更新于某个日期**。**检查**所有**文件**在**web 服务器**中的**创建和修改日期**,如果有任何日期是**可疑的**,请检查该文件。
|
||||
如果你知道某个包含 web 服务器 **文件** 的文件夹在某个 **日期被最后更新**。请**检查**该 web 服务器中所有 **文件** 的创建和修改 **日期**,如果有任何日期 **可疑**,就检查那个文件。
|
||||
|
||||
### 基线
|
||||
### Baselines
|
||||
|
||||
如果一个文件夹的文件**不应该被修改**,你可以计算该文件夹**原始文件**的**哈希**并与**当前**文件进行**比较**。任何被修改的文件都将是**可疑的**。
|
||||
如果一个文件夹的文件 **不应该被修改**,你可以计算该文件夹原始文件的 **hash** 并将其与当前文件 **比较**。任何被修改的文件都应视为 **可疑**。
|
||||
|
||||
### 统计分析
|
||||
### Statistical Analysis
|
||||
|
||||
当信息保存在日志中时,你可以**检查统计数据,比如每个web服务器的文件被访问的次数,因为web shell可能是其中之一**。
|
||||
当信息记录在日志中时,你可以**检查统计信息**,例如每个 web 服务器文件被访问的次数,因为 web shell 可能是被访问次数最多的之一。
|
||||
|
||||
---
|
||||
|
||||
## 反混淆动态控制流 (JMP/CALL RAX 调度器)
|
||||
### Android in-app native telemetry (no root)
|
||||
|
||||
现代恶意软件家族严重滥用控制流图 (CFG) 混淆:它们不是直接跳转/调用,而是在运行时计算目标并执行`jmp rax`或`call rax`。一个小型*调度器*(通常九条指令)根据CPU的`ZF`/`CF`标志设置最终目标,完全破坏静态CFG恢复。
|
||||
在 Android 上,你可以通过在其他 JNI 库初始化之前预加载一个小型 logger 库,在目标应用进程内对 native 代码进行 instrument。这样可以在不依赖系统范围 hook 或 root 的情况下,尽早观察 native 行为。一种常用方法是 SoTap:将 libsotap.so 放到 APK 的对应 ABI 路径下,并尽早注入一个 System.loadLibrary("sotap") 调用(例如静态初始化器或 Application.onCreate),然后从内部/外部路径收集日志,或使用 Logcat 作为回退。
|
||||
|
||||
该技术 - 由SLOW#TEMPEST加载器展示 - 可以通过一个仅依赖于IDAPython和Unicorn CPU模拟器的三步工作流程来击败。
|
||||
查看 Android native reversing 页面以获取设置细节和日志路径:
|
||||
|
||||
### 1. 定位每个间接跳转/调用
|
||||
{{#ref}}
|
||||
../../../mobile-pentesting/android-app-pentesting/reversing-native-libraries.md
|
||||
{{#endref}}
|
||||
|
||||
---
|
||||
|
||||
## Deobfuscating Dynamic Control-Flow (JMP/CALL RAX Dispatchers)
|
||||
|
||||
现代恶意软件家族大量滥用 Control-Flow Graph (CFG) 混淆:它们不是直接跳转/调用,而是在运行时计算目标并执行 `jmp rax` 或 `call rax`。一个小的 *dispatcher*(通常九条指令)会根据 CPU 的 `ZF`/`CF` flags 设置最终目标,这会完全破坏静态 CFG 恢复。
|
||||
|
||||
该技术 —— 由 SLOW#TEMPEST loader 展示 —— 可以通过一个仅依赖 IDAPython 和 Unicorn CPU emulator 的三步工作流来破解。
|
||||
|
||||
### 1. Locate every indirect jump / call
|
||||
```python
|
||||
import idautils, idc
|
||||
|
||||
@ -168,7 +180,7 @@ mnem = idc.print_insn_mnem(ea)
|
||||
if mnem in ("jmp", "call") and idc.print_operand(ea, 0) == "rax":
|
||||
print(f"[+] Dispatcher found @ {ea:X}")
|
||||
```
|
||||
### 2. 提取调度程序字节码
|
||||
### 2. 提取 dispatcher 字节码
|
||||
```python
|
||||
import idc
|
||||
|
||||
@ -183,7 +195,7 @@ size = jmp_ea + idc.get_item_size(jmp_ea) - start
|
||||
code = idc.get_bytes(start, size)
|
||||
open(f"{start:X}.bin", "wb").write(code)
|
||||
```
|
||||
### 3. 使用Unicorn模拟两次
|
||||
### 3. 使用 Unicorn 对其进行两次模拟
|
||||
```python
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
@ -201,7 +213,7 @@ return mu.reg_read(UC_X86_REG_RAX)
|
||||
```
|
||||
运行 `run(code,0,0)` 和 `run(code,1,1)` 以获取 *false* 和 *true* 分支目标。
|
||||
|
||||
### 4. 修补直接跳转 / 调用
|
||||
### 4. 将其修补回直接 jump / call
|
||||
```python
|
||||
import struct, ida_bytes
|
||||
|
||||
@ -210,27 +222,28 @@ op = 0xE8 if is_call else 0xE9 # CALL rel32 or JMP rel32
|
||||
disp = target - (ea + 5) & 0xFFFFFFFF
|
||||
ida_bytes.patch_bytes(ea, bytes([op]) + struct.pack('<I', disp))
|
||||
```
|
||||
在打补丁后,强制 IDA 重新分析该函数,以恢复完整的 CFG 和 Hex-Rays 输出:
|
||||
在打补丁之后,强制 IDA 重新分析该函数,以恢复完整的 CFG 和 Hex-Rays 输出:
|
||||
```python
|
||||
import ida_auto, idaapi
|
||||
idaapi.reanalyze_function(idc.get_func_attr(ea, idc.FUNCATTR_START))
|
||||
```
|
||||
### 5. 标记间接 API 调用
|
||||
### 5. 标注间接 API 调用
|
||||
|
||||
一旦每个 `call rax` 的真实目标被确定,你可以告诉 IDA 它是什么,以便参数类型和变量名称能够自动恢复:
|
||||
一旦每个 `call rax` 的真实目标已知,你就可以告诉 IDA 那是什么,这样参数类型 & 变量名会被自动恢复:
|
||||
```python
|
||||
idc.set_callee_name(call_ea, resolved_addr, 0) # IDA 8.3+
|
||||
```
|
||||
### 实际好处
|
||||
|
||||
* 恢复真实的CFG → 反编译从*10*行变为数千行。
|
||||
* 使字符串交叉引用和xrefs成为可能,行为重建变得简单。
|
||||
* 脚本可重用:将它们放入任何受相同技巧保护的加载器中。
|
||||
* 恢复真实的 CFG → 反编译结果从 *10* 行变成数千行。
|
||||
* 启用 string-cross-reference & xrefs,使行为重建变得轻而易举。
|
||||
* 脚本可复用:将它们放入受相同技巧保护的任何 loader 中。
|
||||
|
||||
---
|
||||
|
||||
## 参考文献
|
||||
## 参考资料
|
||||
|
||||
- [Unit42 – Evolving Tactics of SLOW#TEMPEST: A Deep Dive Into Advanced Malware Techniques](https://unit42.paloaltonetworks.com/slow-tempest-malware-obfuscation/)
|
||||
- SoTap: Lightweight in-app JNI (.so) behavior logger – [github.com/RezaArbabBot/SoTap](https://github.com/RezaArbabBot/SoTap)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
@ -1,47 +1,50 @@
|
||||
# 反向工程本地库
|
||||
# Reversing Native Libraries
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
**更多信息请查看:** [**https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html**](https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html)
|
||||
|
||||
Android 应用可以使用本地库,通常用 C 或 C++ 编写,以满足性能关键任务的需求。恶意软件创建者也滥用这些库,因为 ELF 共享对象仍然比 DEX/OAT 字节码更难以反编译。此页面专注于 *实用* 工作流程和 *近期* 工具改进(2023-2025),使反向工程 Android `.so` 文件变得更容易。
|
||||
**欲了解更多信息请参阅:** [**https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html**](https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html)
|
||||
|
||||
Android 应用可以使用 native libraries,通常用 C 或 C++ 编写,以处理性能关键的任务。恶意软件作者也滥用这些库,因为 ELF shared objects 仍然比 DEX/OAT byte-code 更难反编译。
|
||||
本页侧重于 *practical* 工作流程和 *recent* 工具改进(2023–2025),这些改进使得逆向 Android `.so` 文件更容易。
|
||||
|
||||
---
|
||||
|
||||
### 新提取的 `libfoo.so` 的快速分类工作流程
|
||||
### Quick triage-workflow for a freshly pulled `libfoo.so`
|
||||
|
||||
1. **提取库**
|
||||
1. **Extract the library**
|
||||
```bash
|
||||
# 从已安装的应用程序
|
||||
# From an installed application
|
||||
adb shell "run-as <pkg> cat lib/arm64-v8a/libfoo.so" > libfoo.so
|
||||
# 或从 APK(zip)
|
||||
# Or from the APK (zip)
|
||||
unzip -j target.apk "lib/*/libfoo.so" -d extracted_libs/
|
||||
```
|
||||
2. **识别架构和保护**
|
||||
2. **Identify architecture & protections**
|
||||
```bash
|
||||
file libfoo.so # arm64 或 arm32 / x86
|
||||
readelf -h libfoo.so # OS ABI, PIE, NX, RELRO 等
|
||||
file libfoo.so # arm64 or arm32 / x86
|
||||
readelf -h libfoo.so # OS ABI, PIE, NX, RELRO, etc.
|
||||
checksec --file libfoo.so # (peda/pwntools)
|
||||
```
|
||||
3. **列出导出符号和 JNI 绑定**
|
||||
3. **List exported symbols & JNI bindings**
|
||||
```bash
|
||||
readelf -s libfoo.so | grep ' Java_' # 动态链接的 JNI
|
||||
strings libfoo.so | grep -i "RegisterNatives" -n # 静态注册的 JNI
|
||||
readelf -s libfoo.so | grep ' Java_' # dynamic-linked JNI
|
||||
strings libfoo.so | grep -i "RegisterNatives" -n # static-registered JNI
|
||||
```
|
||||
4. **加载到反编译器中**(Ghidra ≥ 11.0, IDA Pro, Binary Ninja, Hopper 或 Cutter/Rizin)并运行自动分析。更新的 Ghidra 版本引入了一个 AArch64 反编译器,能够识别 PAC/BTI 存根和 MTE 标签,极大地改善了对使用 Android 14 NDK 构建的库的分析。
|
||||
5. **决定静态反向工程还是动态反向工程:** 被剥离和混淆的代码通常需要 *插桩*(Frida, ptrace/gdbserver, LLDB)。
|
||||
4. **Load in a decompiler** (Ghidra ≥ 11.0, IDA Pro, Binary Ninja, Hopper or Cutter/Rizin) 并运行自动分析。
|
||||
较新的 Ghidra 版本引入了 AArch64 decompiler,能识别 PAC/BTI stubs 和 MTE tags,极大改善了使用 Android 14 NDK 构建的库的分析效果。
|
||||
5. **Decide on static vs dynamic reversing:** 已剥离或混淆的代码通常需要 *instrumentation*(Frida、ptrace/gdbserver、LLDB)。
|
||||
|
||||
---
|
||||
|
||||
### 动态插桩(Frida ≥ 16)
|
||||
### Dynamic Instrumentation (Frida ≥ 16)
|
||||
|
||||
Frida 的 16 系列带来了几个 Android 特定的改进,帮助在目标使用现代 Clang/LLD 优化时:
|
||||
Frida 的 16 系列带来了若干 Android 专用的改进,这些改进在目标使用现代 Clang/LLD 优化时非常有帮助:
|
||||
|
||||
* `thumb-relocator` 现在可以 *挂钩由 LLD 的激进对齐(`--icf=all`)生成的小型 ARM/Thumb 函数*。
|
||||
* 枚举和重新绑定 *ELF 导入槽* 在 Android 上有效,使得在内联钩子被拒绝时能够进行按模块的 `dlopen()`/`dlsym()` 修补。
|
||||
* Java 钩子已针对在 Android 14 上使用 `--enable-optimizations` 编译的应用程序的新 **ART 快速入口点** 进行了修复。
|
||||
* `thumb-relocator` 现在可以 *hook tiny ARM/Thumb functions*,这些函数由 LLD 的激进对齐(`--icf=all`)生成。
|
||||
* 在 Android 上可以枚举并重新绑定 *ELF import slots*,当 inline hooks 被拒绝时,这使得可以按模块进行 `dlopen()`/`dlsym()` 修补。
|
||||
* 修复了 Java hooking,以适配在 Android 14 上使用 `--enable-optimizations` 编译时的 **ART quick-entrypoint**。
|
||||
|
||||
示例:枚举通过 `RegisterNatives` 注册的所有函数并在运行时转储它们的地址:
|
||||
Example: enumerating all functions registered through `RegisterNatives` and dumping their addresses at runtime:
|
||||
```javascript
|
||||
Java.perform(function () {
|
||||
var Runtime = Java.use('java.lang.Runtime');
|
||||
@ -58,38 +61,76 @@ console.log('[+] RegisterNatives on ' + clazz.getName() + ' -> ' + count + ' met
|
||||
});
|
||||
});
|
||||
```
|
||||
Frida将在启用PAC/BTI的设备(Pixel 8/Android 14+)上开箱即用,只要使用frida-server 16.2或更高版本——早期版本无法找到内联钩子的填充。 citeturn5search2turn5search0
|
||||
Frida 在启用 PAC/BTI 的设备上(Pixel 8/Android 14+)开箱即可工作,只要你使用 frida-server 16.2 或更高版本 —— 早期版本无法定位 inline hooks 的 padding。
|
||||
|
||||
### Process-local JNI telemetry via preloaded .so (SoTap)
|
||||
|
||||
当完整的 instrumentation 过于繁重或被阻止时,你仍然可以通过在目标进程内预加载一个小型 logger 来获取本地级别的可见性。SoTap 是一个轻量级的 Android native (.so) 库,它记录同一应用进程内其他 JNI (.so) 库的运行时行为(不需要 root)。
|
||||
|
||||
Key properties:
|
||||
- 在加载它的进程中尽早初始化并观察 JNI/native 交互。
|
||||
- 使用多个可写路径持久化日志,在存储受限时优雅地回退到 Logcat。
|
||||
- 源码可定制:编辑 sotap.c 以扩展/调整记录内容,并按 ABI 重新构建。
|
||||
|
||||
Setup (repack the APK):
|
||||
1) 将对应 ABI 的构建放入 APK 中以便加载器可以解析 libsotap.so:
|
||||
- lib/arm64-v8a/libsotap.so (for arm64)
|
||||
- lib/armeabi-v7a/libsotap.so (for arm32)
|
||||
2) 确保 SoTap 在其他 JNI 库之前加载。尽早注入一次调用(例如,在 Application 子类的 static initializer 或 onCreate 中),以便 logger 先被初始化。Smali 代码示例:
|
||||
```smali
|
||||
const-string v0, "sotap"
|
||||
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
|
||||
```
|
||||
3) 重建/签名/安装,运行应用,然后收集日志。
|
||||
|
||||
Log paths (checked in order):
|
||||
```
|
||||
/data/user/0/%s/files/sotap.log
|
||||
/data/data/%s/files/sotap.log
|
||||
/sdcard/Android/data/%s/files/sotap.log
|
||||
/sdcard/Download/sotap-%s.log
|
||||
# If all fail: fallback to Logcat only
|
||||
```
|
||||
注意事项与故障排除:
|
||||
- ABI 对齐是必须的。对齐不匹配会抛出 UnsatisfiedLinkError,导致 logger 无法加载。
|
||||
- 现代 Android 常见存储限制;如果文件写入失败,SoTap 仍会通过 Logcat 输出。
|
||||
- 行为/冗长度(verbosity)可按需定制;在编辑 sotap.c 后请从源码重新构建。
|
||||
|
||||
该方法适用于 malware 分析和 JNI 调试,特别是在需要从进程启动阶段观察 native 调用流程且无法使用 root/系统范围 hook 时。
|
||||
|
||||
---
|
||||
|
||||
### 最近值得在APK中寻找的漏洞
|
||||
### 值得在 APK 中寻找的近期漏洞
|
||||
|
||||
| 年份 | CVE | 受影响的库 | 备注 |
|
||||
|------|-----|------------------|-------|
|
||||
|2023|CVE-2023-4863|`libwebp` ≤ 1.3.1|从解码WebP图像的本地代码可达的堆缓冲区溢出。多个Android应用程序捆绑了易受攻击的版本。当你在APK中看到`libwebp.so`时,检查其版本并尝试利用或修补。| citeturn2search0|
|
||||
|2024|多个|OpenSSL 3.x系列|多个内存安全和填充预言机问题。许多Flutter和ReactNative捆绑包自带`libcrypto.so`。|
|
||||
|2023|CVE-2023-4863|`libwebp` ≤ 1.3.1|本地代码在解码 WebP 图像时可能触发堆缓冲区溢出。若干 Android 应用捆绑了易受影响的版本。当你在 APK 中看到 `libwebp.so` 时,应检查其版本并尝试利用或修补。| |
|
||||
|2024|Multiple|OpenSSL 3.x series|存在多种内存安全问题和 padding-oracle 漏洞。许多 Flutter 与 ReactNative 包会随附自家的 `libcrypto.so`。|
|
||||
|
||||
当你在APK中发现*第三方* `.so`文件时,始终交叉检查它们的哈希与上游公告。SCA(软件组成分析)在移动设备上不常见,因此过时的易受攻击构建普遍存在。
|
||||
当你在 APK 内发现第三方 `.so` 文件时,务必将其哈希与上游通告核对。移动端很少做 SCA (Software Composition Analysis),因此过期的易受影响构建非常普遍。
|
||||
|
||||
---
|
||||
|
||||
### 反逆向与加固趋势(Android 13-15)
|
||||
|
||||
* **指针认证(PAC)和分支目标识别(BTI):** Android 14在支持的ARMv8.3+硅片上启用PAC/BTI。反编译器现在显示与PAC相关的伪指令;对于动态分析,Frida在去除PAC后注入跳板,但你的自定义跳板应在必要时调用`pacda`/`autibsp`。
|
||||
* **MTE和Scudo加固分配器:** 内存标记是可选的,但许多Play-Integrity感知的应用程序使用`-fsanitize=memtag`构建;使用`setprop arm64.memtag.dump 1`加上`adb shell am start ...`来捕获标记故障。
|
||||
* **LLVM混淆器(不透明谓词,控制流扁平化):** 商业打包工具(例如Bangcle,SecNeo)越来越多地保护*本地*代码,而不仅仅是Java;预计在`.rodata`中会出现虚假的控制流和加密字符串块。
|
||||
* **Pointer Authentication (PAC) & Branch Target Identification (BTI):** Android 14 在支持的 ARMv8.3+ 芯片上在系统库中启用 PAC/BTI。反编译器现在会显示与 PAC 相关的伪指令;用于动态分析时,Frida 会在去除 PAC 后注入 trampolines,但自定义的 trampolines 在必要时应调用 `pacda`/`autibsp`。
|
||||
* **MTE & Scudo hardened allocator:** memory-tagging 是可选的,但许多启用 Play-Integrity 的应用会使用 `-fsanitize=memtag` 构建;可用 `setprop arm64.memtag.dump 1` 加上 `adb shell am start ...` 来捕获 tag fault。
|
||||
* **LLVM Obfuscator (opaque predicates, control-flow flattening):** 商业加壳器(例如 Bangcle、SecNeo)越来越多地保护 *native* 代码,而不仅仅是 Java;在 `.rodata` 中会看到伪造的控制流和加密的字符串 blob。
|
||||
|
||||
---
|
||||
|
||||
### 资源
|
||||
|
||||
- **学习ARM汇编:** [Azeria Labs – ARM汇编基础](https://azeria-labs.com/writing-arm-assembly-part-1/)
|
||||
- **JNI和NDK文档:** [Oracle JNI规范](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html) · [Android JNI技巧](https://developer.android.com/training/articles/perf-jni) · [NDK指南](https://developer.android.com/ndk/guides/)
|
||||
- **调试本地库:** [使用JEB反编译器调试Android本地库](https://medium.com/@shubhamsonani/how-to-debug-android-native-libraries-using-jeb-decompiler-eec681a22cf3)
|
||||
- **学习 ARM 汇编:** [Azeria Labs – ARM Assembly Basics](https://azeria-labs.com/writing-arm-assembly-part-1/)
|
||||
- **JNI 与 NDK 文档:** [Oracle JNI Spec](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html) · [Android JNI Tips](https://developer.android.com/training/articles/perf-jni) · [NDK Guides](https://developer.android.com/ndk/guides/)
|
||||
- **调试 Native 库:** [Debug Android Native Libraries Using JEB Decompiler](https://medium.com/@shubhamsonani/how-to-debug-android-native-libraries-using-jeb-decompiler-eec681a22cf3)
|
||||
|
||||
### 参考
|
||||
|
||||
- Frida 16.x变更日志(Android钩子,微型函数重定位) – [frida.re/news](https://frida.re/news/) citeturn5search0
|
||||
- `libwebp`溢出CVE-2023-4863的NVD公告 – [nvd.nist.gov](https://nvd.nist.gov/vuln/detail/CVE-2023-4863) citeturn2search0
|
||||
- Frida 16.x 更新日志(Android hooking,tiny-function relocation) – [frida.re/news](https://frida.re/news/)
|
||||
- 关于 `libwebp` 溢出的 NVD 咨询 CVE-2023-4863 – [nvd.nist.gov](https://nvd.nist.gov/vuln/detail/CVE-2023-4863)
|
||||
- SoTap: 轻量级的应用内 JNI (.so) 行为记录器 – [github.com/RezaArbabBot/SoTap](https://github.com/RezaArbabBot/SoTap)
|
||||
- SoTap 发布 – [github.com/RezaArbabBot/SoTap/releases](https://github.com/RezaArbabBot/SoTap/releases)
|
||||
- 如何使用 SoTap? – [t.me/ForYouTillEnd/13](https://t.me/ForYouTillEnd/13)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
@ -1,85 +1,86 @@
|
||||
# Smali - 反编译/\[修改]/编译
|
||||
# Smali - 反编译/[修改]/编译
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
有时修改应用程序代码以访问隐藏信息(可能是经过良好混淆的密码或标志)是很有趣的。然后,反编译apk,修改代码并重新编译可能会很有趣。
|
||||
|
||||
**操作码参考:** [http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html](http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html)
|
||||
有时修改应用代码以访问隐藏信息(例如高度混淆的密码或 flags)会很有用。此时,反编译 apk、修改代码并重新编译可能很有价值。
|
||||
|
||||
**Opcodes 参考:** [http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html](http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html)
|
||||
|
||||
## 快速方法
|
||||
|
||||
使用 **Visual Studio Code** 和 [APKLab](https://github.com/APKLab/APKLab) 扩展,您可以 **自动反编译**、修改、**重新编译**、签名并安装应用程序,而无需执行任何命令。
|
||||
使用 **Visual Studio Code** 和 [APKLab](https://github.com/APKLab/APKLab) 扩展,你可以 **自动反编译**、修改、**重新编译**、签名并安装应用,而无需执行任何命令。
|
||||
|
||||
另一个大大简化此任务的 **脚本** 是 [**https://github.com/ax/apk.sh**](https://github.com/ax/apk.sh)
|
||||
另一个极大简化此任务的 **script** 是 [**https://github.com/ax/apk.sh**](https://github.com/ax/apk.sh)
|
||||
|
||||
## 反编译APK
|
||||
## 反编译 APK
|
||||
|
||||
使用APKTool,您可以访问 **smali代码和资源**:
|
||||
使用 APKTool 可以访问 **smali 代码和资源**:
|
||||
```bash
|
||||
apktool d APP.apk
|
||||
```
|
||||
如果 **apktool** 给你任何错误,尝试[安装 **最新版本**](https://ibotpeaches.github.io/Apktool/install/)
|
||||
如果 **apktool** 给你任何错误,尝试[ installing the **latest version**](https://ibotpeaches.github.io/Apktool/install/)
|
||||
|
||||
一些 **你应该查看的有趣文件**:
|
||||
一些**你应该查看的有趣文件**:
|
||||
|
||||
- _res/values/strings.xml_(以及 res/values/* 中的所有 xml)
|
||||
- _res/values/strings.xml_ (以及 res/values/* 中的所有 xml)
|
||||
- _AndroidManifest.xml_
|
||||
- 任何扩展名为 _.sqlite_ 或 _.db_ 的文件
|
||||
|
||||
如果 `apktool` 在 **解码应用程序时遇到问题**,请查看 [https://ibotpeaches.github.io/Apktool/documentation/#framework-files](https://ibotpeaches.github.io/Apktool/documentation/#framework-files) 或尝试使用参数 **`-r`**(不解码资源)。然后,如果问题出在资源而不是源代码中,你就不会有这个问题(你也不会反编译资源)。
|
||||
如果 `apktool` 在**解码应用**时有问题,请查看 [https://ibotpeaches.github.io/Apktool/documentation/#framework-files](https://ibotpeaches.github.io/Apktool/documentation/#framework-files) 或尝试使用参数 **`-r`**(不要解码资源)。然后,如果问题出在资源而不是源代码,你就不会遇到这个问题(你也不会反编译这些资源)。
|
||||
|
||||
## 更改 smali 代码
|
||||
|
||||
你可以 **更改** **指令**,更改某些变量的 **值** 或 **添加** 新指令。我使用 [**VS Code**](https://code.visualstudio.com) 更改 Smali 代码,然后安装 **smalise 扩展**,编辑器会告诉你是否有任何 **指令不正确**。\
|
||||
一些 **示例** 可以在这里找到:
|
||||
你可以**更改****指令**、修改某些变量的**值**或**添加**新的指令。我使用 [**VS Code**](https://code.visualstudio.com) 来修改 Smali 代码,安装 **smalise extension** 后,编辑器会告诉你是否有任何**指令不正确**。\
|
||||
一些**示例**可以在这里找到:
|
||||
|
||||
- [Smali 更改示例](smali-changes.md)
|
||||
- [Smali changes examples](smali-changes.md)
|
||||
- [Google CTF 2018 - Shall We Play a Game?](google-ctf-2018-shall-we-play-a-game.md)
|
||||
|
||||
或者你可以 [**查看下面一些 Smali 更改的解释**](smali-changes.md#modifying-smali)。
|
||||
Or you can [**check below some Smali changes explained**](smali-changes.md#modifying-smali).
|
||||
|
||||
## 重新编译 APK
|
||||
|
||||
在修改代码后,你可以使用 **重新编译** 代码:
|
||||
修改代码后,你可以使用以下方式**重新编译**代码:
|
||||
```bash
|
||||
apktool b . #In the folder generated when you decompiled the application
|
||||
```
|
||||
它将**编译**新的APK**在**_**dist**_文件夹中。
|
||||
它会在 _**dist**_ 文件夹中 **compile** 新的 APK。
|
||||
|
||||
如果**apktool**抛出**错误**,请尝试[安装**最新版本**](https://ibotpeaches.github.io/Apktool/install/)
|
||||
如果 **apktool** 抛出 **error**,尝试[ installing the **latest version**](https://ibotpeaches.github.io/Apktool/install/)
|
||||
|
||||
### **签署新的APK**
|
||||
### **为新的 APK 签名**
|
||||
|
||||
然后,您需要**生成一个密钥**(系统会要求您输入密码和一些您可以随机填写的信息):
|
||||
然后,你需要 **generate a key**(会要求你输入密码以及一些可以随机填写的信息):
|
||||
```bash
|
||||
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias <your-alias>
|
||||
```
|
||||
最后,**签名**新的APK:
|
||||
最后,**sign** 新的 APK:
|
||||
```bash
|
||||
jarsigner -keystore key.jks path/to/dist/* <your-alias>
|
||||
```
|
||||
### 优化新应用程序
|
||||
### 优化新应用
|
||||
|
||||
**zipalign** 是一个归档对齐工具,为 Android 应用程序 (APK) 文件提供重要的优化。[More information here](https://developer.android.com/studio/command-line/zipalign).
|
||||
**zipalign** 是一个归档对齐工具,可为 Android 应用 (APK) 文件提供重要的优化。 [更多信息](https://developer.android.com/studio/command-line/zipalign).
|
||||
```bash
|
||||
zipalign [-f] [-v] <alignment> infile.apk outfile.apk
|
||||
zipalign -v 4 infile.apk
|
||||
```
|
||||
### **再次签署新的APK(再一次?)**
|
||||
### **Sign the new APK (again?)**
|
||||
|
||||
如果您**更喜欢**使用 [**apksigner**](https://developer.android.com/studio/command-line/) 而不是 jarsigner,**您应该在应用** zipalign **优化后签署apk**。但请注意,您只需**使用 jarsigner 签署应用一次**(在 zipalign 之前)或使用 aspsigner(在 zipalign 之后)。
|
||||
如果你 **更愿意** 使用 [**apksigner**](https://developer.android.com/studio/command-line/) 而不是 jarsigner,**你应该对 apk 进行签名**,在应用 **使用 zipaling 的优化** 之后。但请注意,你只需要使用 jarsigner(在 zipalign 之前)或使用 aspsigner(在 zipaling 之后)**对应用签名一次**。
|
||||
```bash
|
||||
apksigner sign --ks key.jks ./dist/mycompiled.apk
|
||||
```
|
||||
## 修改 Smali
|
||||
|
||||
对于以下 Hello World Java 代码:
|
||||
对于下面的 Hello World Java 代码:
|
||||
```java
|
||||
public static void printHelloWorld() {
|
||||
System.out.println("Hello World")
|
||||
}
|
||||
```
|
||||
Smali 代码将是:
|
||||
Smali 代码如下:
|
||||
```java
|
||||
.method public static printHelloWorld()V
|
||||
.registers 2
|
||||
@ -89,13 +90,13 @@ invoke-virtual {v0,v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
|
||||
return-void
|
||||
.end method
|
||||
```
|
||||
Smali 指令集可在 [这里](https://source.android.com/devices/tech/dalvik/dalvik-bytecode#instructions) 获取。
|
||||
Smali 指令集可在 [here](https://source.android.com/devices/tech/dalvik/dalvik-bytecode#instructions).
|
||||
|
||||
### 轻微更改
|
||||
|
||||
### 修改函数内部变量的初始值
|
||||
|
||||
某些变量在函数开始时使用操作码 _const_ 定义,您可以修改其值,或者可以定义新的值:
|
||||
有些变量在函数开始处使用操作码 _const_ 定义,你可以修改它们的值,或者定义新的变量:
|
||||
```bash
|
||||
#Number
|
||||
const v9, 0xf4240
|
||||
@ -126,7 +127,7 @@ iput v0, p0, Lcom/google/ctf/shallweplayagame/GameActivity;->o:I #Save v0 inside
|
||||
if-ne v0, v9, :goto_6 #If not equals, go to: :goto_6
|
||||
goto :goto_6 #Always go to: :goto_6
|
||||
```
|
||||
### 更大的变化
|
||||
### 重大更改
|
||||
|
||||
### 日志记录
|
||||
```bash
|
||||
@ -139,17 +140,17 @@ invoke-static {v5, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/Strin
|
||||
```
|
||||
建议:
|
||||
|
||||
- 如果您打算在函数内部使用声明的变量(声明为 v0, v1, v2...),请将这些行放在 _.local \<number>_ 和变量声明 (_const v0, 0x1_) 之间。
|
||||
- 如果您想在函数的代码中间放置日志记录代码:
|
||||
- 将声明的变量数量加 2:例如,从 _.locals 10_ 到 _.locals 12_。
|
||||
- 新变量应为已声明变量的下一个数字(在此示例中应为 _v10_ 和 _v11_,请记住它从 v0 开始)。
|
||||
- 更改日志记录函数的代码,并使用 _v10_ 和 _v11_ 代替 _v5_ 和 _v1_。
|
||||
- 如果你打算在函数内部使用已声明的变量 (declared v0,v1,v2...),将这些行放在 _.local <number>_ 和变量声明 (_const v0, 0x1_) 之间
|
||||
- 如果你想把日志代码放在函数代码的中间:
|
||||
- 把已声明变量的数量加 2:例如:从 _.locals 10_ 到 _.locals 12_
|
||||
- 新变量应为已声明变量之后的连续编号(在此例中应为 _v10_ 和 _v11_,记住编号从 v0 开始)。
|
||||
- 更改日志函数的代码,使用 _v10_ 和 _v11_ 替换 _v5_ 和 _v1_。
|
||||
|
||||
### Toasting
|
||||
### Toast 提示
|
||||
|
||||
请记得在函数开始时将 _.locals 的数量加 3。
|
||||
记得在函数开头将 _.locals_ 的数量增加 3。
|
||||
|
||||
此代码准备插入到 **函数的中间**(**根据需要更改** **变量** 的 **数量**)。它将获取 **this.o** 的 **值**,**转换** 为 **String**,然后 **制作** 一个 **toast** 以显示其值。
|
||||
此代码准备插入到函数的 **中间**(**根据需要更改变量的数量**)。它会获取 **this.o 的值**,将其 **转换** 为 **String**,然后用该值显示一个 **toast**。
|
||||
```bash
|
||||
const/4 v10, 0x1
|
||||
const/4 v11, 0x1
|
||||
@ -161,4 +162,38 @@ invoke-static {p0, v11, v12}, Landroid/widget/Toast;->makeText(Landroid/content/
|
||||
move-result-object v12
|
||||
invoke-virtual {v12}, Landroid/widget/Toast;->show()V
|
||||
```
|
||||
### 在启动时加载本地库 (System.loadLibrary)
|
||||
|
||||
有时需要预先加载本地库,以便在其他 JNI 库之前完成初始化(例如,用于启用进程本地的遥测/日志记录)。你可以在静态初始化器或在 Application.onCreate() 的早期注入对 System.loadLibrary() 的调用。下面是用于静态类初始化器 (<clinit>) 的 smali 示例:
|
||||
```smali
|
||||
.class public Lcom/example/App;
|
||||
.super Landroid/app/Application;
|
||||
|
||||
.method static constructor <clinit>()V
|
||||
.registers 1
|
||||
const-string v0, "sotap" # library name without lib...so prefix
|
||||
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
|
||||
return-void
|
||||
.end method
|
||||
```
|
||||
或者,将相同的两条指令放在你的 Application.onCreate() 开始处,以确保该库尽早加载:
|
||||
```smali
|
||||
.method public onCreate()V
|
||||
.locals 1
|
||||
|
||||
const-string v0, "sotap"
|
||||
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
|
||||
|
||||
invoke-super {p0}, Landroid/app/Application;->onCreate()V
|
||||
return-void
|
||||
.end method
|
||||
```
|
||||
注意:
|
||||
- 确保库的正确 ABI 变体存在于 lib/<abi>/ 下(例如 arm64-v8a/armeabi-v7a),以避免 UnsatisfiedLinkError。
|
||||
- 尽早加载(class static initializer)可以保证 native logger 能观察到后续的 JNI 活动。
|
||||
|
||||
## 参考
|
||||
|
||||
- SoTap:轻量级应用内 JNI (.so) 行为 logger – [github.com/RezaArbabBot/SoTap](https://github.com/RezaArbabBot/SoTap)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user