Translated ['src/generic-methodologies-and-resources/basic-forensic-meth

This commit is contained in:
Translator 2025-09-04 02:38:19 +00:00
parent 8246afa30b
commit 4fea614268
3 changed files with 205 additions and 116 deletions

View File

@ -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}}

View File

@ -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* 工具改进20232025这些改进使得逆向 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
# 或从 APKzip
# 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或更高版本——早期版本无法找到内联钩子的填充。 citeturn5search2turn5search0
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`时,检查其版本并尝试利用或修补。| citeturn2search0|
|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混淆器不透明谓词控制流扁平化** 商业打包工具例如BangcleSecNeo越来越多地保护*本地*代码而不仅仅是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/) citeturn5search0
- `libwebp`溢出CVE-2023-4863的NVD公告 [nvd.nist.gov](https://nvd.nist.gov/vuln/detail/CVE-2023-4863) citeturn2search0
- Frida 16.x 更新日志Android hookingtiny-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}}

View File

@ -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
使用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}}