4. 提取__TEXT段中的代码
任务说明
本案例目标是从一个 Mach-O 文件的 __TEXT 段中提取可执行代码,并在 Ghidra 中将其反汇编为汇编指令。你将学习如何定位 __TEXT 段在文件中的偏移与大小,使用命令行工具抽取原始字节,再通过 Ghidra 的导入与分析功能完成反汇编。
环境准备
- macOS 或 Linux 系统(需能运行
otool或llvm-objdump) - Ghidra 11.x(已安装并配置好 JDK 17+)
- 一个测试用 Mach-O 可执行文件(可用
/bin/ls或任意编译出的二进制)
实现步骤
1. 定位 __TEXT 段偏移与大小
使用 otool -l 查看段信息,找到 __TEXT 段的 fileoff 与 filesize:
otool -l /bin/ls | grep -A 5 "sectname __text"
输出示例(实际值因系统而异):
sectname __text
segname __TEXT
addr 0x0000000100003e50
size 0x0000000000002e52
offset 15824
这里 offset 是 __text 节(section)在文件中的偏移,size 是节大小。若需提取整个 __TEXT 段,则使用段级 fileoff 与 filesize(通常段偏移为 0,大小为所有节之和)。
2. 提取原始字节
用 dd 命令按偏移和大小抽取字节到独立文件:
# 假设 __TEXT 段 fileoff=0, filesize=0x1000(示例值,请用实际值替换)
dd if=/bin/ls of=text_segment.bin bs=1 skip=0 count=4096
若只提取 __text 节,则使用节的 offset 和 size:
dd if=/bin/ls of=text_section.bin bs=1 skip=15824 count=11858
3. 在 Ghidra 中反汇编
- 打开 Ghidra,创建新项目,导入
text_segment.bin(或text_section.bin)。 - 在导入对话框中选择语言为
AARCH64:LE:64:v8A(Apple Silicon)或x86:LE:64:default(Intel Mac),具体取决于你的测试文件架构。 - 双击打开导入的文件,点击“分析”按钮,选择默认分析选项并运行。
- 分析完成后,Ghidra 会自动将原始字节反汇编为指令,在 Listing 窗口中显示汇编代码。
4. 验证反汇编结果
对比 Ghidra 反汇编结果与系统工具输出是否一致:
# 使用 llvm-objdump 反汇编原始 __text 节作为参照
llvm-objdump --macho --disassemble /bin/ls | head -20
观察 Ghidra Listing 窗口中的前几条指令是否与 llvm-objdump 输出匹配。若匹配,说明提取与反汇编流程正确。
关键代码(提取脚本)
以下 Python 脚本自动完成段定位与提取,适用于任意 Mach-O 文件:
import struct
import subprocess
import sys
def extract_text_segment(binary_path, output_path):
# 使用 otool 获取 __TEXT 段信息
result = subprocess.run(['otool', '-l', binary_path], capture_output=True, text=True)
lines = result.stdout.split('\n')
fileoff = None
filesize = None
for i, line in enumerate(lines):
if 'segname __TEXT' in line:
# 向后查找 fileoff 和 filesize
for j in range(i, min(i+10, len(lines))):
if 'fileoff ' in lines[j]:
fileoff = int(lines[j].split()[-1], 16)
if 'filesize ' in lines[j]:
filesize = int(lines[j].split()[-1], 16)
if fileoff is not None and filesize is not None:
break
break
if fileoff is None or filesize is None:
print("未找到 __TEXT 段信息")
sys.exit(1)
# 读取并提取字节
with open(binary_path, 'rb') as f:
f.seek(fileoff)
data = f.read(filesize)
with open(output_path, 'wb') as f:
f.write(data)
print(f"已提取 {filesize} 字节到 {output_path}")
if __name__ == '__main__':
if len(sys.argv) != 3:
print("用法: python extract_text.py <输入二进制> <输出文件>")
sys.exit(1)
extract_text_segment(sys.argv[1], sys.argv[2])
运行与验证
- 保存上述脚本为
extract_text.py,运行:
python3 extract_text.py /bin/ls text_segment.bin
- 将
text_segment.bin导入 Ghidra,选择正确架构后分析。 - 在 Listing 窗口中查看反汇编结果,确认指令序列合理(如
sub sp, sp, #0x30、stp x29, x30, [sp, #0x20]等典型函数序言)。 - 用
llvm-objdump --macho --disassemble /bin/ls对比同一区域的指令,若前 10 条指令一致,则验证通过。
通过条件:Ghidra 成功将提取的 __TEXT 字节反汇编为可读的汇编指令,且与系统反汇编工具输出一致,无“未知指令”或数据误判为代码的情况。