Skip to content

ROP: Add labels to reference addresses relative to your chain#2734

Merged
peace-maker merged 5 commits into
devfrom
rop_labels
Jul 4, 2026
Merged

ROP: Add labels to reference addresses relative to your chain#2734
peace-maker merged 5 commits into
devfrom
rop_labels

Conversation

@peace-maker

@peace-maker peace-maker commented May 25, 2026

Copy link
Copy Markdown
Member

Allow to assign a name to a point in the ROP chain using ROP.label(name) and reference it somewhere else using ROP.ref(name, offset). This allows to specify addresses relative to your ROP chain payload in your chain.

Sometimes you want to use gadgets which require you to point back into your ROP chain.
This is especially common for gadgets which adjust the stack pointer, but can also be useful for other gadgets.
You have to know the absolute address of the ROP chain in memory for this and pass it as base= into the :class:ROP constructor.

You can use labels to reference other slots in the ROP chain, and the ROP module will resolve them to the correct addresses when the chain is finalized.
Set a label at the current chain position using label, and reference it using ref with an optional offset.

Imagine you want to use a pop rdx; leave; ret gadget to control rdx and continue your rop chain afterwards.
You can use a label in front of your next gadget and reference it in rbp to achieve this.

>>> context.clear(arch='amd64')
>>> assembly = 'special_gadget: pop rdx; leave; ret; pop rdi; ret; pop rsi; ret; pop rbp; ret'
>>> binary = ELF.from_assembly(assembly)
>>> binary.symbols['funcname'] = binary.entry + 0x1000
>>> rop = ROP(binary, base=0xdead0000)
>>> rop.rbp = rop.ref('step1', offset = -8)
>>> rop.raw(binary.sym.special_gadget)
>>> rop.raw(0xdeadbeef)     # control rdx
>>> rop.label('step1')
>>> rop.call("funcname", [b"hello", b"world"])
>>> print(rop.dump())
0xdead0000:       0x10000007 pop rbp; ret
0xdead0008:       0xdead0018 <L:step1>-0x8 (+0x10)
0xdead0010:       0x10000000 special_gadget
0xdead0018:       0xdeadbeef
step1:
0xdead0020:       0x10000005 funcname([b'hello'], [b'world']), pop rsi; ret
0xdead0028:       0xdead0048 [arg1] rsi = AppendedArgument([b'world'], 0x0) (+0x20)
0xdead0030:       0x10000003 pop rdi; ret
0xdead0038:       0xdead0050 [arg0] rdi = AppendedArgument([b'hello'], 0x0) (+0x18)
0xdead0040:       0x10001000 funcname
0xdead0048:   b'world\x00$$'
0xdead0050:   b'hello\x00$$'

The labels are printed in the dump. The label location is printed as labelname: in front of the target address and the references show up as <L:labelname>+offset where they're used. While testing the printing other descriptions started showing up when there were multiple pieces of information attached to a slot, which I like. Only the latest one was shown before, now it shows them all.

Does this work for you @CsomePro? The API names setlabel and uselabel feel clunky, but I couldn't come up with better names.

Supercedes #2583

Allow to assign a name to a point in the ROP chain using `ROP.setlabel(name)`
and reference it somewhere else using `ROP.uselabel(name, offset)`.
You have to know the location of your chain in memory to resolve the
right addresses. This allows to specify addresses relative to your ROP chain payload in your chain.

Refs #2583
@CsomePro

Copy link
Copy Markdown

This works for me, and I like this feature. It should make these stack-relative cases much easier to reason about than manually tracking offsets.

One small API naming suggestion: maybe mark(name) + ref(name, offset=0), or label(name) + ref(name, offset=0), would feel a bit shorter and more natural than setlabel() / uselabel().

Comment thread pwnlib/rop/rop.py
Comment on lines +657 to 661
def __init__(self, elfs: ELF | str | bytes | list[ELF], base: int | None = None, badchars: bytes = b''):
"""
Arguments:
elfs(list): List of :class:`.ELF` objects for mining
base(int): Stack address where the first byte of the ROP chain lies, if known.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type hint does not match the type documentation for elfs.

This is less verbose than `setlabel` and `uselabel` but still descriptive enough to be able to guess what they do.
@peace-maker
peace-maker merged commit cded3cf into dev Jul 4, 2026
16 of 24 checks passed
@peace-maker
peace-maker deleted the rop_labels branch July 4, 2026 16:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants