Skip to content

Fix x86 gadget discovery by decoupling alignment from step size#219

Merged
SweetVishnya merged 2 commits intoJonathanSalwan:masterfrom
iilegacyyii:master
Nov 22, 2025
Merged

Fix x86 gadget discovery by decoupling alignment from step size#219
SweetVishnya merged 2 commits intoJonathanSalwan:masterfrom
iilegacyyii:master

Conversation

@iilegacyyii
Copy link
Contributor

This patch fixes an issue where the --align option prevents discovery of valid x86/x64 gadgets such as pop rdi; ret.

ROPgadget currently uses the alignment value both as:

  1. A constraint on the gadget start address
  2. Step size when walking backward from a matched instruction

This coupling works for fixed-width ISAs (e.g. ARM Thumb, RISC-V compressed) but breaks on x86, where instruction lengths are variable and gadget starts often occur at ref - 1. With --align 2, these byte offsets are never examined, causing valid x86 gadgets to be missed.

Proposed fix:

  1. Walks backward one byte at a time to inspect all possible gadget starts
  2. Applies the alignment value only as a filter on the start address

This preserves the intended behavior for architectures where alignment is meaningful while restoring correct gadget enumeration on x86/x64.

Please note
I am currently unable to test this change on non-x86 architectures, so additional testing would be appreciated to ensure it does not introduce regressions on ARM, Thumb, or RISC-V. I can also provide a test ELF showcasing the issue if required.

ROPgadget previously used the alignment value as the backward step size when scanning for gadget start offsets. This prevents discovery of valid x86 gadgets such as “pop rdi; ret”, when specifying certain alignment values (namely 2-byte alignment).

This patch steps backward one byte at a time on all architectures and applies the alignment constraint only as a filter on the start address. This preserves correct behavior for fixed-width ISAs (ARM Thumb, RISC-V compressed) while restoring correct gadget discovery on x86/x64.
@SweetVishnya
Copy link
Collaborator

@iilegacyyii, could you look into the failing tests, please?

@iilegacyyii
Copy link
Contributor Author

Yep of course. Will take a look after work today.

Reworked `__gadgetsFinding` to restore the original aligned-step logic while keeping the new byte-by-byte fallback. Alignment is attempted first, fallback is used only when alignment is invalid. `expected_size` is now computed correctly for each path, fixing the test failures caused by mixing aligned offsets with byte-step semantics in the previous commit.
@iilegacyyii
Copy link
Contributor Author

iilegacyyii commented Nov 21, 2025

@SweetVishnya hopefully fixed in 8bc16ae. Tested on my end and now the existing tests pass, and I am able to locate 2-byte gadgets with --align 2 set.

py ROPgadget.py --binary test-suite-binaries/elf-x64-bash-v4.1.5.1 --only "pop|ret" --align 2 --all | grep rdi
0x00000000004225ac : pop rdi ; ret
0x0000000000422868 : pop rdi ; ret
0x0000000000423438 : pop rdi ; ret
0x0000000000423d7a : pop rdi ; ret
0x0000000000425ed2 : pop rdi ; ret
0x000000000042ba42 : pop rdi ; ret
0x000000000042e4ca : pop rdi ; ret
0x000000000042e680 : pop rdi ; ret
0x000000000042e918 : pop rdi ; ret
0x00000000004331c4 : pop rdi ; ret
0x00000000004371b6 : pop rdi ; ret
0x0000000000438eac : pop rdi ; ret
0x00000000004390fa : pop rdi ; ret
0x00000000004391fa : pop rdi ; ret
0x0000000000439fa8 : pop rdi ; ret
0x000000000043c36a : pop rdi ; ret
0x000000000043c6e4 : pop rdi ; ret
0x000000000043ca2e : pop rdi ; ret
[...SNIPPED FOR BREVITY...]

@SweetVishnya SweetVishnya merged commit 4d3e297 into JonathanSalwan:master Nov 22, 2025
1 check passed
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.

2 participants