ARM --chain execve: ArchitectureArm previously raised "does not have
support for execve chain generation". This adds ARM gadget categories
(pop/ldm pop-pc LOAD_REG, WRITE_MEM, LOAD_MEM, SYSCALL) and the svc 0
SYS ending, plus a generator that discovers terminal pop-pc / ldm
dispatch gadgets, fills r0/r1/r2/r7 with a re-loading-aware register
cover planner, writes the command into .data, and emits clearly-labelled
placeholders when a gadget (svc 0, an r0 pop, ...) is missing.
New --chain spawn_shell for x86, x86_64 and ARM: a ret2libc
system("/bin/sh") generator emitting the correct per-arch calling
convention -- x86 cdecl (stack arg), x86_64 System V (rdi + a movaps
stack-alignment ret), ARM AAPCS (r0 + pc dispatch). Options: cmd
(default /bin/sh, any path), address (libc system), string (&cmd),
align (x86_64).
system() resolution: address= > a system symbol defined in the binary
(rebased) > verified system@plt > import hint > placeholder. _findPltStub
disassembles .plt/.plt.sec/.plt.got and returns the stub whose indirect
jump provably dereferences system's GOT slot (x86_64 jmp [rip+disp],
x86 jmp [abs], ARM add ip,pc,#imm[,#rot] ; ... ; ldr pc,[ip,#imm]!),
verified against the relocation, so it never emits a silently-wrong
address; x86 PIE jmp [ebx+off] and stripped PLTs fall back to the hint.
"/bin/sh" resolution: string= > an existing copy already in the binary
(no write) > write the string into a writable scratch section, .bss
preferred, via write-what-where gadgets > placeholder. _findWritableSection
reads ELF section headers directly (SHF_WRITE|SHF_ALLOC, not TLS,
sh_size >= needed) so writability and free space are verified natively;
it avoids getSection('.bss') because .bss is SHT_NOBITS (raw is None,
size comes from sh_size).
Correctness fixes:
- The scratch-buffer pointer was double-imageBase-subtracted (pointer !=
written bytes); it now uses the same rebase_N(offset) convention as the
write.
- x86_64 _paddingNeededFor's ^pop (...)$ regex dropped pop r8/pop r9
(2-char regs), under-padding chains; broadened to \w{2,3} (also hardens
execve/mprotect).
- _useBinaryForRebase registers the binary with the gadgets' own
(fileName, section) identity, so a later gadget registration reuses the
entry instead of emitting a duplicate IMAGE_BASE.
- The written string is always NUL-terminated: the shared
_nulTerminateAndPad appends the NUL unconditionally before word-aligning
(ARM previously skipped it for cmd lengths that were a multiple of 4).
Help text (--help epilog in options.py, README.md, interactive ropchain
help in console.py) lists spawn_shell, the .bss write and cmd=, and marks
execve as ARM-capable. Tests: testcases/test_chain_arm.py and
testcases/test_chain_spawn_shell.py; full suite 58/58.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>