JonathanSalwan / Triton

Triton is a dynamic binary analysis library. Build your own program analysis tools, automate your reverse engineering, perform software verification or just emulate code.
https://triton-library.github.io
Apache License 2.0
3.39k stars 524 forks source link

ARM32 - `ADR` Instruction incorrect behaviour #1299

Closed m4drat closed 6 months ago

m4drat commented 6 months ago

Hi! While playing with an ARM32 target I encountered a weird behaviour with ADR R0, 0x20 instruction. This instruction should form a pc-relative result, however, it seems not to be the case.

In this example I'm setting concrete value for the pc register and then executing this instruction. While expected result should be 0x2D74, triton sets the r0 register to be 0x20.

To reproduce:

from triton import *
ctx = TritonContext(ARCH.ARM32)
ctx.setConcreteRegisterValue(ctx.registers.pc, 0x2D51)  # Thumb-mode execution
ctx.setConcreteRegisterValue(ctx.registers.r0, 0x00)    # Set r0
ctx.processing(Instruction(b"\x08\xA0"))                # ADR R0, 0x20
ctx.getConcreteRegisterValue(ctx.registers.r0)          # Return 0x20, and not the 0x2D74

Qemu output:

# Before executing the instruction
pwndbg> p/x $pc
$1 = 0x2d50
pwndbg> p/x $r0
$2 = 0x9b3088

pwndbg> x/i $pc+1
   0x2d51 <XXX+7504>:    add     r0, pc, #32
pwndbg> hexdump 0x2d50
+0000 0x002d50  08 a0 00 f0  47 f9 0d b1  38 2c 06 d2  14 a0 00 f0 │....│G...│8,..│....│

# After
pwndbg> p/x $pc
$3 = 0x2d52
pwndbg> p/x $r0
$4 = 0x2d74

There is a comment in the adr_s function that says that capstone should encode the result into the source operand: https://github.com/JonathanSalwan/Triton/blob/d27d4b8f66111fae004b6726d0fd5e4ef6c546a9/src/libtriton/arch/arm/arm32/arm32Semantics.cpp#L1087-L1090

I also checked the code for ARM64, and it looks like it should have the same problem.

cnheitman commented 6 months ago

Hi @m4drat !

It seems the issue comes from the fact that the instruction is decoded differently by Capstone depending on the mode. In ARM mode, it includes the pc among its operands (this is where the comment you pointed out comes from) while in Thumb mode it doesn't, as shown below:

$ cstool -d thumb "08 A0"       # ADR R0, 0x20
 0  08 a0  adr  r0, #0x20
    ID: 4 (adr)
    op_count: 2
        operands[0].type: REG = r0
        operands[0].access: WRITE
        operands[1].type: IMM = 0x20
    Registers modified: r0
    Groups: thumb thumb1only
$ cstool -d arm "20 00 8F E2"   # ADR R0, 0x20
 0  20 00 8f e2  add    r0, pc, #0x20
    ID: 2 (add)
    op_count: 3
        operands[0].type: REG = r0
        operands[0].access: WRITE
        operands[1].type: REG = pc
        operands[1].access: READ
        operands[2].type: IMM = 0x20
    Registers read: pc
    Registers modified: r0
    Groups: arm

I will update the semantics (function adr_s) to fix the behavior when in Thumb mode.

This issue does not seem to affect the instruction for the ARM64 arch.

cnheitman commented 6 months ago

Hi @m4drat ! I fixed this issue in the following PR: https://github.com/JonathanSalwan/Triton/pull/1300.

Could you confirm it fixes the issue?

m4drat commented 6 months ago

Hi! Thanks for a quick fix :) Now everything seems to work correctly!

image