Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ The table below shows which release corresponds to each branch, and what date th
- [#2574][2574] Allow creating an ELF from in-memory bytes
- [#2575][2575] Detect when Terminator is being used as terminal
- [#2578][2578] Add gnome-terminal, Alacritty, Ttilix for run_in_new_terminal
- [#2583][2583] Add new `ROP` feature: relative stack offset

[2583]: https://github.com/Gallopsled/pwntools/pull/2583
[2419]: https://github.com/Gallopsled/pwntools/pull/2419
[2551]: https://github.com/Gallopsled/pwntools/pull/2551
[2519]: https://github.com/Gallopsled/pwntools/pull/2519
Expand Down
30 changes: 30 additions & 0 deletions pwnlib/rop/call.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,36 @@ class StackAdjustment(Unresolved):
"""
pass

class StackRelative(Unresolved):
"""
During the parsing process, it will be replaced with the relative offset
of the stack position where the current slot is located.

Examples

>>> context.clear()
>>> context.arch = 'amd64'
>>> u = StackRelative(+8)
>>> u.resolve(1000)
1008
>>> u = StackRelative(-8)
>>> u.resolve(1000)
992
"""
def __init__(self, offset):
self.offset = offset

def resolve(self, base):
"""
Resolve the stack-relative address based on the given base address.

Arguments:
base(int): The base address to resolve against.

Returns:
int: The resolved address.
"""
return base + self.offset

class AppendedArgument(Unresolved):
r"""
Expand Down
34 changes: 33 additions & 1 deletion pwnlib/rop/rop.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,32 @@
>>> p.sendline(b'echo hello; exit')
>>> p.recvline()
b'hello\n'

ROP + StackRelative
-----------------------

In certain situations, you might prefer to use a stack-relative address.
For this purpose, you can use :class:`StackRelative` as a placeholder for a stack-relative address.

>>> context.clear(arch='amd64')
>>> assembly = 'pop rdi; ret; pop rsi; ret; pop rdx; ret; pop rbp; ret'
>>> binary = ELF.from_assembly(assembly)
>>> binary.symbols['funcname'] = binary.entry + 0x1000
>>> rop = ROP(binary)
>>> rop.base = 0xdead0000
>>> from pwnlib.rop.call import StackRelative
>>> rop.call("funcname", [b"hello", b"StackRelative"])
>>> rop.rbp = StackRelative(-0x8)
>>> print(rop.dump())
0xdead0000: 0x10000002 pop rsi; ret
0xdead0008: 0xdead0038 [arg1] rsi = AppendedArgument([b'StackRelative'], 0x0) (+0x30)
0xdead0010: 0x10000000 pop rdi; ret
0xdead0018: 0xdead0048 [arg0] rdi = AppendedArgument([b'hello'], 0x0) (+0x30)
0xdead0020: 0x10001000 funcname
0xdead0028: 0x10000006 pop rbp; ret
0xdead0030: 0xdead0028 (-0x8)
0xdead0038: b'StackRelative\x00$$'
0xdead0048: b'hello\x00$$'
"""
from __future__ import absolute_import
from __future__ import division
Expand Down Expand Up @@ -385,6 +411,7 @@
from pwnlib.rop.call import CurrentStackPointer
from pwnlib.rop.call import NextGadgetAddress
from pwnlib.rop.call import StackAdjustment
from pwnlib.rop.call import StackRelative
from pwnlib.rop.call import Unresolved
from pwnlib.rop.gadgets import Gadget
from pwnlib.util import lists
Expand Down Expand Up @@ -464,7 +491,7 @@ def dump(self):
if desc:
line += ' %s' % desc
if off is not None:
line += ' (+%#x)' % off
line += (' (+%#x)' % off) if off >= 0 else ' (-%#x)' % -off
rv.append(line)
addr += _slot_len(data)

Expand Down Expand Up @@ -1029,6 +1056,11 @@ def build(self, base = None, description = None):
stack[i] = slot.address
stack.describe(self.describe(slot), slot_address)

elif isinstance(slot, StackRelative):
address = slot.resolve(slot_address)
stack[i] = address
stack.describe(self.describe(address), slot_address)

# Everything else we can just leave in place.
# Maybe the user put in something on purpose?
# Also, it may work in pwnlib.util.packing.flat()
Expand Down
Loading