executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
,一般落在 .sdata 段内,12 位有符号偏移(±2048)覆盖 .sdata/.sbss 小数据区\n - 访问形态:启动时 `lui gp, %hi(...)` + `addi gp, gp, %lo(...)` 一次设置 → 后续 `lw/ld aN, off(gp)` 小偏移数据访问(-msmall-data-limit 默认 8 字节以内的全局变量走 gp)\n - 符号剥离后:从 _start/crt0 序言的 lui+addi 序列计算 gp 实际值 → 反编译器中标注 → 数据引用恢复;有 ELF 时 `readelf -s` 查 `__global_pointer
re-riscvRISC-V 架构逆向:RV32/RV64、压缩指令(RVC)、gp 相对寻址、ABI 与 ecall 系统调用约定、工具链指纹。 触发词:RISC-V、riscv、RV32、RV64、RVC、压缩指令、ecall、ESP32-C3、GD32V。
Independent GitHub snapshot · Automated classification · Original documentation governs
所有工具先验证再使用。静态分析可免沙箱;qemu 动态执行默认沙箱 + 网络隔离([[re-analyze/platform-tips]] 最高原则)。
apt install ghidra / pacman -S ghidrabrew install --cask ghidra;Windows: 官方 zipanalyzeHeadless -help(headless 模式)或 GUI 导入 RISC-V ELFapt install binutils 等);macOS: brew install binutils 或 LLVM 系 readelf;Windows: WSL 内readelf --versionapt install binutils-riscv64-linux-gnu(提供 riscv64-linux-gnu-objdump;编译链加 gcc-riscv64-linux-gnu,gcc 依赖带入 binutils 包)dnf install binutils-riscv64-linux-gnu gcc-riscv64-linux-gnu(cross-binutils / cross-gcc 源包,提供 riscv64-linux-gnu-objdump;官方仓库无 riscv64-unknown-elf 裸机工具链,裸机反汇编用 riscv64-linux-gnu-objdump,RVC 支持一致)pacman -S riscv64-elf-binutils riscv64-elf-gcc(裸机,提供 riscv64-unknown-elf-objdump)或 pacman -S riscv64-linux-gnu-binutils riscv64-linux-gnu-gcc(用户态)brew install riscv64-elf-binutils riscv64-elf-gcc(homebrew-core,提供 riscv64-unknown-elf-objdump);Windows/WSL: WSL 内 Linux 版binutils-riscv64-linux-gnu → riscv64-linux-gnu-objdump --version(Debian/Ubuntu/Fedora);binutils-riscv64-unknown-elf → riscv64-unknown-elf-objdump --version(Arch/brew,Debian/Ubuntu 需裸机 triplet 时单列该包);objdump 对 RVC 混编流自动识别(2/4 字节)apt install qemu-user / dnf install qemu-user / pacman -S qemu-userbrew install qemu(含用户态);Windows/WSL: WSL 内 Linux 版qemu-riscv64、32 位为 qemu-riscv32;-L <rootfs> 指定动态库/链接器来源,-strace 跟踪系统调用qemu-riscv64 --version、qemu-riscv32 --versionqemu-system-riscv64/32(Debian trixie 起 / Ubuntu 25.10 起独立包 apt install qemu-system-riscv,Ubuntu 24.04 及更早、Debian bookworm 在 qemu-system-misc 内;Fedora / Arch dnf install qemu-system-riscv / pacman -S qemu-system-riscv)-machine virt 或板级模型(-s -S 接 gdb),或 [[re-emulation]] 用 Unicorn 逐指令apt install gdb-multiarch(riscv32/riscv64 目标内置);Fedora dnf install gdb(官方 gdb 支持多目标);Arch pacman -S gdb(内置 multiarch)brew install gdb(需 Developer Tools 授权,见 [[re-analyze/platform-tips]] macOS 分支)或 WSL 内 Linux 版;Windows/WSL: WSL 内 Linux 版gdb-multiarch --version;Fedora/Arch gdb --version;载入固件后 set architecture riscv:rv64(或 riscv:rv32)再 info registers 确认按顺序执行,每步结果存档;动态执行默认沙箱。
架构确认(RV32/RV64 + 字节序):
file target.bin # "RISC-V" + 32-bit/64-bit + little-endian 提示
file target.elf
readelf -h target.elf # Machine=RISC-V (243);Data=little-endian;Flags 含 RVC/浮点 ABI 位
readelf -A target.elf | head # Tag_RISCV_arch 属性,如 rv64imafdc
EF_RISCV_RVC(0x1)=含压缩指令;浮点 ABI 位掩码 0x6(0=软浮点、2=单精度 F、4=双精度 D、6=四精度 Q);EF_RISCV_RVE(0x8)=RV32E 精简寄存器入口定位(reset / 启动代码):
readelf -h 的 Entry point)= _start;动态链接程序先经 ld.so(PT_INTERP),断点/分析从 _start 起0x1000(reset stub 再跳 start_addr,默认 DRAM 0x80000000,pflash 固件场景为 0x20000000)——别把 DRAM 基址当 reset 入口;部分 MCU flash 基址形如 0x08000000;异常/中断向量基址在 mtvec(M 态)/ stvec(S 态)CSR,trap 处理代码按 CSR 值定位la sp, ...)→ 拷贝 .data / 清零 .bss → 跳 main(裸机)或 __libc_start_main(Linux)RVC 压缩指令识别(2/4 字节混合,勿固定宽度切割):
gp 相对寻址恢复(lui+addi 对、.sdata/.sbss):
__global_pointer$,一般落在 .sdata 段内,12 位有符号偏移(±2048)覆盖 .sdata/.sbss 小数据区lui gp, %hi(...) + addi gp, gp, %lo(...) 一次设置 → 后续 lw/ld aN, off(gp) 小偏移数据访问(-msmall-data-limit 默认 8 字节以内的全局变量走 gp)readelf -s 查 __global_pointer$ 符号值ABI 识别(整数/浮点 ABI、a0-a7 约定):
e_flags & EF_RISCV_FLOAT_ABI(掩码 0x6) 为准——它是整个 object 的 Float ABI 字段。不能靠浮点指令出现与否反推 soft/hard-float:-march=rv64ifd -mabi=lp64 是合法组合,产物照用 fld/fmul 等硬件浮点指令,但函数参数仍走整数寄存器(实测:lp64 产物用 fmv.d.x fa5, a1 把 a0/a1 搬进浮点寄存器,lp64d 产物直接用 fsd fa0 收浮点寄存器)。浮点指令密度只能佐证 ISA 含 F/D/Q 扩展,不能佐证参数 ABIcannot link object files with different floating-point ABI,标准流程下不存在"按单元确认"的软硬混编产物。逆向中若观察到局部调用约定不同,先考虑手写汇编、非标准 ABI、STO_RISCV_VARIANT_CC、FFI/thunk、或被错误识别的函数边界系统调用边界(ecall + a7 号):
ecall 触发系统调用,号在 a7(x17)、参数 a0-a5、返回 a0;RISC-V 用 asm-generic 编号(read=63、write=64、openat=56、exit=93、mmap=222)——与 x86/ARM 编号不同,别拿其他架构的号套ecall(0x73),往回找 li a7, imm 立即数;Ghidra 反编译中识别系统调用点qemu-riscv64 -strace 直接打印系统调用序列(联动 [[re-tracing]])生态指纹(工具链/库函数特征):
lw/ld off(gp) 数据访问解不出地址,全局变量互不关联、逻辑碎片化;原因——符号剥离后 __global_pointer$ 丢失,或反编译器未推导 gp;对策——从 _start/crt0 的 lui gp+addi gp 序列计算实际 gp 值并在反编译器中标注;有 ELF 时 readelf -s 查 __global_pointer$