Module: OneGadget::ABI
- Defined in:
- lib/one_gadget/abi.rb
Overview
Defines the ABI of different architectures.
Constant Summary collapse
- X86_32 =
Registers of i386.
%w[eax ebx ecx edx edi esi ebp esp] + 0.upto(7).map { |i| "xmm#{i}" }
- X86_64 =
Registers of x86_64.
X86_32 + %w[rax rbx rcx rdx rdi rsi rbp rsp] + 8.upto(15).map { |i| "r#{i}" } + 8.upto(15).map { |i| "xmm#{i}" }
- AARCH64 =
Registers of AArch64.
%w[xzr wzr sp] + 0.upto(30).map { |i| ["x#{i}", "w#{i}"] }.flatten
- ARM =
Registers of ARM (32-bit). objdump never prints the numbered name of a register that has a role name: +r10+-+r15+ always appear as +sl+/+fp+/+ip+/+sp+/+lr+/+pc+, so those are what this list holds.
%w[sl fp ip sp lr pc] + 0.upto(9).map { |i| "r#{i}" }
- NARROW_VIEWS =
Names that address part of a wider register rather than storage of their own, mapped to the register they name part of. A write through either name is visible through the other, which is what Emulators::RegisterFile keeps them consistent about.
{ amd64: (%w[ax bx cx dx di si bp sp].map { |reg| ["e#{reg}", "r#{reg}"] } + 8.upto(15).map { |i| ["r#{i}d", "r#{i}"] }).to_h, i386: {}, aarch64: 0.upto(30).to_h { |i| ["w#{i}", "x#{i}"] }.merge('wzr' => 'xzr'), arm: {} }.freeze
- CALLER_SAVED =
Registers a call may destroy, per each ABI's calling convention: the return register, the argument registers and the scratch ones. A callee is free to leave anything here in an arbitrary state, so what it holds afterwards is not something the caller of a gadget can choose. Named by their full registers; the narrower views of each go with it (see NARROW_VIEWS).
{ # SysV amd64: return rax, arguments rdi/rsi/rdx/rcx/r8/r9, scratch r10/r11. amd64: %w[rax rcx rdx rsi rdi r8 r9 r10 r11] + 0.upto(15).map { |i| "xmm#{i}" }, # cdecl i386: return eax, scratch ecx/edx; arguments go on the stack. i386: %w[eax ecx edx] + 0.upto(7).map { |i| "xmm#{i}" }, # AAPCS64: x0-x7 arguments and return, x9-x15 temporaries, x16/x17 the # intra-procedure-call scratch, x18 the platform register. aarch64: (0.upto(7).to_a + 9.upto(18).to_a).map { |i| "x#{i}" }, # AAPCS: r0-r3 arguments and return, ip (r12) the intra-procedure scratch, # and lr, which the call itself overwrites with the return address. arm: %w[r0 r1 r2 r3 ip lr] }.freeze
- RETURN_REGISTER =
The register each ABI leaves an integer return value in.
{ amd64: 'rax', i386: 'eax', aarch64: 'x0', arm: 'r0' }.freeze
Class Method Summary collapse
-
.aarch64 ⇒ Array<String>
Registers' name of aarch64.
-
.all ⇒ Array<String>
Returns all names of registers.
-
.amd64 ⇒ Array<String>
Registers' name of amd64.
-
.arm ⇒ Array<String>
Registers' name of arm (32-bit).
-
.i386 ⇒ Array<String>
Registers' name of i386.
-
.stack_register?(reg) ⇒ Boolean
Checks if the register is a stack-related pointer.
Class Method Details
.aarch64 ⇒ Array<String>
Registers' name of aarch64.
74 75 76 |
# File 'lib/one_gadget/abi.rb', line 74 def aarch64 AARCH64 end |
.all ⇒ Array<String>
Returns all names of registers.
86 87 88 |
# File 'lib/one_gadget/abi.rb', line 86 def all amd64 + aarch64 + arm end |
.amd64 ⇒ Array<String>
Registers' name of amd64.
62 63 64 |
# File 'lib/one_gadget/abi.rb', line 62 def amd64 X86_64 end |
.arm ⇒ Array<String>
Registers' name of arm (32-bit).
80 81 82 |
# File 'lib/one_gadget/abi.rb', line 80 def arm ARM end |
.i386 ⇒ Array<String>
Registers' name of i386.
68 69 70 |
# File 'lib/one_gadget/abi.rb', line 68 def i386 X86_32 end |
.stack_register?(reg) ⇒ Boolean
Checks if the register is a stack-related pointer.
94 95 96 |
# File 'lib/one_gadget/abi.rb', line 94 def stack_register?(reg) %w[esp ebp rsp rbp sp x29].include?(reg) end |