Files
reverse-skills-max/vendor-new/rev-skills/.claude/skills/re-fw-emulate/references/commands.md

5.8 KiB
Raw Blame History

QEMU 仿真命令速查与操作序列(用户态 / 全系统)

分工:qemu-user(用户态,跑单程序最轻)→ qemu-system(全系统,启动完整固件)→ binfmt_misc(直接执行交叉程序)→ gdb-multiarch(交叉调试)。参数以本机 qemu-<arch> --help / qemu-system-<arch> --help 为准(版本差异见 gotchas)。

命令族速查

qemu-user —— 用户态仿真

用途 命令
架构对应 qemu-arm(32 位)/ qemu-aarch64 / qemu-mips(大端)/ qemu-mipsel(小端)/ qemu-riscv64 等
基本运行 qemu-arm -L <rootfs> <rootfs>/usr/sbin/httpd
sysroot -L <path>(动态库/链接器从 rootfs 加载;缺 -L 报 ld-linux 找不到)
环境变量 -E VAR=value(可多个;Web 服务常传 -E LD_LIBRARY_PATH=...)
伪造 argv[0] -0 <argv0>(程序按调用名分支时用)
系统调用日志 -strace(等效仿真内 strace,排查 mmap/ioctl 崩溃点)
gdbstub -g <port>(等 gdb 连接,配合 gdb-multiarch)
指定 CPU -cpu <型号>(-cpu help 列全部,如 cortex-a9)
限定地址空间 -B <size>(guest 地址空间大小,老内核小空间时用)
启动即暂停 -g 之外可用 -d in_asm 反汇编日志(调试/取证)

qemu-system —— 全系统仿真

用途 命令
平台选择 -M vexpress-a9(ARM)/ -M malta(MIPS)/ -M virt(通用)——-M help 列全部
内核与 initramfs -kernel vmlinuz -initrd initramfs.img
挂磁盘镜像 -drive file=rootfs.ext2,format=raw
串口到终端 -nographic(-serial mon:stdio 变体)
内核参数 -append "console=ttyAMA0 root=/dev/ram rdinit=/sbin/init"
网络(显式添加) -netdev user,id=n0 -device e1000,netdev=n0(用户态 NAT,仅出站)
网络简写 -nic user,model=e1000(新版推荐;-net 旧语法已标记弃用)
完全断网 显式 -nic none(或 -nodefaults)——不加网络参数会默认建 NIC + user 后端
虚拟外设 -device virtio-net-pci,netdev=n0 / -device e1000 等(-device help 列全部)
固定时钟 -rtc base=utc(避免时间怪异,见 gotchas)
内存 -m 256(按固件需求,常见 64-256MB)
gdbstub -s(1234 端口)/ -S(启动即暂停等 gdb)

binfmt_misc —— 直接执行交叉程序

# Debian/Ubuntu:apt install binfmt-support qemu-user-static 后自动注册
# 手动注册:update-binfmts --enable qemu-arm(或 /etc/binfmt.d/ 配置文件)
ls /proc/sys/fs/binfmt_misc/        # 可见 qemu-arm 等条目
./rootfs_out/usr/sbin/httpd          # 之后可直接执行(等效 qemu-arm -L rootfs_out ...)
# 注意:binfmt 直接执行不带 -L sysroot,动态链接程序仍需设置 QEMU_LD_PREFIX 或先解出依赖

gdb-multiarch + gdbserver —— 交叉调试

qemu-arm -g 1234 -L rootfs_out rootfs_out/usr/sbin/httpd &   # 用户态 gdbstub
gdb-multiarch rootfs_out/usr/sbin/httpd
(gdb) target remote :1234
# 全系统内:rootfs 里放 gdbserver,gdbserver :1234 /usr/sbin/httpd
# 宿主 (gdb) target remote <qemu_guest_ip>:1234

常用操作序列

1. 用户态跑单个固件程序(最轻,优先)

file 确认架构与字节序 → qemu-<arch> -L <rootfs> <程序>
→ 缺库:readelf -d 看依赖,从 rootfs 补(或 -E LD_LIBRARY_PATH)
→ 崩溃:加 -strace 看系统调用,定位到 mmap/ioctl 访问点再决定 stub(序列 4)

2. 全系统启动(initramfs 与磁盘镜像两式)

式一(initramfs):cpio 打包 rootfs_out → -kernel vmlinuz -initrd initramfs.img -append "rdinit=/sbin/init"
式二(磁盘镜像):dd/ext2 制作 rootfs.ext2 → -kernel vmlinuz -drive file=rootfs.ext2,format=raw -append "root=/dev/<设备>"
→ 串口看不到输出先核对 console= 参数与 -M 平台(ttyAMA0=ttyS0 因平台而异)

3. 仿真内交叉调试(用户态 / 全系统)

用户态:qemu-arm -g 1234 → gdb-multiarch target remote :1234
全系统:gdbserver 放进 rootfs → 在固件里启动 gdbserver → 宿主 target remote <guest_ip>:1234
→ 调试手法(断点/内存/单步)按 [[re-gdb]]

4. 外设缺失 stub(GPIO/UART 寄存器崩溃)

qemu-<arch> -strace 定位首个崩溃访问(如 mmap 固定地址后读 [addr])
→ LD_PRELOAD 提供 stub 库:该地址返回模拟值(用户态)
→ 全系统:-device 挂虚拟外设(e1000/virtio);真实芯片外设打补丁跳过初始化
→ 先确认程序初始化到哪一步崩(串口输出/日志),再决定 stub 范围

5. 网络隔离下仿真

全系统先 -nic none(不加网络参数会默认建 NIC + user 后端)确认行为 → 需要受控网络再加 -nic user,model=e1000,restrict=on
→ 回连/协议分析前按 [[re-analyze/platform-tips]] 隔离;抓包与协议重建转 [[re-protocol]]
→ firmadyne 默认带网卡,同样先隔离再跑

实现教训(内化)

  • 用户态先行:单程序 80% 场景 qemu-user 足够,别一上来搭全系统
  • -L 不匹配的典型症状是 ld-linux 报错——先把 sysroot 指对再谈其他
  • -strace 是仿真内排障第一工具:崩溃/挂起先看系统调用流
  • 全系统串口无输出先查 console= 与 -M 平台匹配(console 设备名因平台/内核而异)
  • 仿真是验证手段不是目的:跑不动且静态可分析就回退静态(re-fw-rootfs / re-binary-core)

使用注意