SuperAPI AI Directory

re-address-space

General & other

View repository

Updated 10-15 21:34

About this skill

Address space conversion (PIE / ASLR / base address / RVA-VA)

Entry decision (Decision Gate)

地址相关问题
├── 静态文件(无运行态): VA/RVA/文件偏移换算 ──→ 本技能(步骤 1-2)
├── 运行态(进程/内存): 基址确定(PIE/ASLR)──→ 本技能(步骤 3)+ /proc/pid/maps
├── 跨工具对齐(Ghidra 显示 vs 运行时 vs angr)──→ 本技能(步骤 4)
└── 固件加载地址 vs 链接地址差 ──→ 本技能(步骤 5)

When to use / when not to use

  • Use: any "this address doesn't match" problem—decompiler-displayed address ≠ runtime address ≠ the address found by find
  • Use: PIE/ASLR binaries need runtime base address conversion (frida Process.getModuleByName(...).base / gdb info proc mappings / maps file)
  • Use: RVA/VA interconversion, file offset and virtual address interconversion, difference between firmware load address and link address
  • Don't use: just reading ELF header/section table (use [[re-format-elf]])
  • Don't use: detailed runtime memory layout inspection (use [[re-memdump]] / [[re-gdb]])

Tool preparation

Verify all tools before use. All are static/lightweight commands, sandbox can be skipped.

readelf / objdump (binutils) — file-side base address and segment information

  • Linux: apt install binutils / dnf install binutils / pacman -S binutils(mostly preinstalled)
  • Verify: readelf --version;objdump --version

gdb — runtime base address (cross-OS, see [[re-gdb]])

  • Installation and verification see [[re-gdb]] tool preparation

python3 — conversion script

  • Installation and verification see [[re-python]] tool preparation

Operation steps

  1. Determine file-side base address (static):

    readelf -l target | grep LOAD        # 首个 LOAD 段 p_vaddr 即链接基址(ET_EXEC 固定;ET_DYN/PIE 为 0 起相对)
    readelf -h target | grep Type        # EXEC(固定基址)/ DYN(PIE,运行时才定基址)
    
    • Link-time base: takep_vaddr of the lowest PT_LOAD(page-aligned) — do not assume p_vaddr of PIE/ET_DYN must be 0; the format has no such requirement; under PIE it is commonly 0, but may also be non-0 (e.g. layouts starting at 0x1000). load_bias = runtime mapping start − lowest p_vaddr (see step 3)
    • File offset ↔ VA:VA = p_vaddr + (file_offset - p_offset)(match by segment, don't use whole-file linear conversion)
  2. RVA / VA conversion:

    RVA = VA - ImageBase(PE 语境)
    VA  = RVA + ImageBase
    
    • ELF has no unified ImageBase concept—use "link base + segment offset"; PE uses the section table (RVA → file offset by section)
    • 32/64-bit width affects address representation, not conversion logic
  3. Runtime base address (PIE / ASLR):

    cat /proc/<pid>/maps | head -5        # 加载基址 = 首个映射(r--p,file offset 0x0)起点(Linux)
    gdb -p <pid> -ex 'info proc mappings' -ex detach   # 或 gdb 侧(跨平台)
    
    • Layout difference (separate-code): under gcc default PIE the first LOAD is an R-- segment (p_vaddr=0), and the code segment follows it (starting at p_vaddr=0x1000); in the old layout (no separate-code) the first LOAD is R E (p_vaddr=0)—to get the load base usethe start of the first mapping (r--p); if using the start of the first r-xp, you must subtract that segment's own p_vaddr, so that the results are consistent between the two layouts
    • frida:Process.getModuleByName("libtarget.so").base(Frida 17+: static Module.findBaseAddress / Module.getBaseAddress has been removed, for older-version syntax see [[re-frida-script-author]])
    • Runtime address = link address + load bias—bias = runtime base − link base; under PIE the bias differs on every run (ASLR), the script must fetch it dynamically
    • Conversion:runtime_addr = link_addr + bias(e.g. a symbol linked at 0x1000 at runtime 0x1000 + 0x7f0000000000)
  4. Cross-tool alignment:

    • Ghidra: by default imports by link base (Image Base for PIE programs is often 0); the difference from the runtime address = load bias——Ghidra 地址 + bias = 运行时地址
    • angr:proj.loader.main_object.mapped_base(base address after rebase); for rebasing use the backend object's obj.rebase(new_base)(e.g. proj.loader.main_object.rebase(...),cle Backend.rebase)
    • gdb/frida: use the runtime base address (step 3); decompiler addresses need the bias added to align
    • Breakpoint alignment:gdb b *<链接地址> + <bias> or frida Process.getModuleByName("libfoo.so").findExportByName("func") plus offset
  5. Firmware loader offset:

    • Firmware image link address vs actual load address (after flash mapping/decompression) difference = loader offset—first read the firmware header/boot code to confirm the load address (linked with [[re-fw-extract]] / [[re-arm]])
    • Conversion:实际地址 = 链接地址 + loader_offset; when uncertain, infer backward from references to its own address in the boot code

Cross-domain joint

  • [[re-binary-core]]: This skill is its sub-skill—the general foundation for binary analysis (address conversion is consumed domain-wide)
  • [[re-format-elf]] / [[re-format-pe]]: Source of segments/sections (input to steps 1-2)
  • [[re-frida]] / [[re-gdb]] / [[re-memdump]]: Source of runtime base address (step 3)
  • [[re-ghidra]] / [[re-angr]]: Cross-tool address alignment (step 4)
  • [[re-fw-extract]] / [[re-arm]]: Firmware load address (step 5)
  • [[re-analyze/analysis-contract]]: Address conversion conclusions go into the data contract'sfile domain field base_addr (see [[re-analyze/analysis-contract]] §3.2)

Common pitfalls and traps

  • Misuse of PIE static base address: Symptom—treating the PIE link base address (0 or the ELF header value) as a runtime address, so breakpoints/lookups all fail; Cause—the ET_DYN runtime base address is determined by ASLR; Countermeasure—dynamically obtain the bias in step 3, don't guess statically
  • File offset as virtual address: Symptom—find 0x1234(file offset) cannot be found in Ghidra/runtime; Cause—confusing the two coordinate systems of offset and VA; Countermeasure—convert according to the step 1 segment mapping, first confirm which system you're reading
  • Firmware link address ≠ load address: Symptom—in the firmware, the file reported entry differs from the actual runtime entry by a constant; Cause—the linker links according to flash/ROM addresses, while at runtime it is decompressed/remapped to RAM; Countermeasure—infer the loader offset backward in step 5, don't force it
  • Different tools give different addresses: Symptom—Ghidra says 0x401000, angr says 0x400000, frida says 0x7f...—the same symbol has three different numbers; Cause—each tool has a different default base address (link/mapping/rebase); Countermeasure—unify to the same coordinate system in step 4 (with the runtime base address as the anchor) before comparing