Vector35 / Vector35/binaryninja-api
Arm64: Incorrect return address handling when the link register (x30)'s value is known
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 1.3k
- Forks
- 298
- Avg merge
- 5d 5h
- Merged PRs (30d)
- 19
Description
A user reported a bug that BN does not handle the return address properly when the x30 value is known. The sample is obfuscated, and it is using the ret instruction to do a jump. At the end of the function, it first calculates the jump target in x30, and then returns. BN is unaware of the trick and during LLIL->MLIL translation, the information is lost and the code is treated as a regular return.
The user does not wish to share the binary in public, so I recreated the issue on a different binary. helloworld_bug.zip For comparison, the original binary is attached as well: helloworld.zip
100003f54 mov x30, #0x1234
100003f58 add sp, sp, #0x40
100003f5c ret
Given the above function epilog, it loads 0x1234 into x30. After the ret instruction, the pc will become 0x1234. The code effectively does a b 0x1234. The LLIL is fine:
25 @ 100003f54 x30 = 0x1234
26 @ 100003f58 sp = sp + 0x40
27 @ 100003f5c <return> jump(x30)
However, things are screwed up in MLIL:
18 @ 100003f5c return 0xa
To deal with this, we need to do the following things:
- When the x30 value is a known constant, translate the ret instruction into a jump
- When the x30 value is undetermined, check its value is actually the value of x30 at the function start. For example, if we look at the original binary, we can see that the x30 value is the
__saved_x30.

- (what should we do if it is not the entry value of x30?)
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the Arm64 ret handling during LLIL-to-MLIL translation and compare the provided LLIL and MLIL examples. Reproduce the behavior with helloworld_bug.zip, then verify that a known x30 constant becomes a jump and determine how an undetermined x30 value should be handled, including the unresolved non-entry-value case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers, reverse-engineering
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100