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/ gdbinfo 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
-
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)
-
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
-
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+: staticModule.findBaseAddress/Module.getBaseAddresshas 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 runtime0x1000 + 0x7f0000000000)
-
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'sobj.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 fridaProcess.getModuleByName("libfoo.so").findExportByName("func")plus offset
- Ghidra: by default imports by link base (Image Base for PIE programs is often 0); the difference from the runtime address = load bias——
-
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
filereported 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