Ghidra

Lets use the binary from the following challenge as an example:

1. Listing view

1.1 Variables

  • Lets take a look at the local_20 and local_28 variables:

  • Leftmost portion: type

  • Middle portion:

    • Stack[-0x28], 0x28 bytes relative to the function's stack frame (typically rbp)

    • :8, size in bytes

  • Right portion:

    • XREF[1,2]:

      • 1 reference from outside the function

      • 2 references inside the function

    • 0040066f(W): value written to @0x0040066f

    • 0040067e(W): value written to @0040067e

    • 004006a5(R): value read at @004006a5

2. Decompile view

  • As we can see, there are a few issues with the decompiled code:

  1. Some of the types are not defined properly (eg. undefined8)

  2. Variables have no useful meaning

  3. Values used in comparisons and assignments are not easily understood

Example

  • The following shows a basic example of how to better understand the decompiled code

1. Rename variables

  • The read function reads 0x18 bytes from stdin into the address pointed by local_38

  • Its hard to understand what the variable local_38 is used for when reading the other parts of the code

  • To make it easier for ourselves, we can rename it to, for instance: input

    • In Ghidra: right-click on variable -> Rename variable

2. Retrieve actual values used by variables

  • We can see that Ghidra interprets these variables as signed integers and therefore displays the constants as negative values

  • At the assembly level, the raw 32-bit value is used instead. Hence, we can retrieve the exact value stored in memory from analysis of the assembly code

  • We can use the assembly code in the listings view to understood the unsigned values being used

  • From here, we can understand that the assignment and comparison code uses 0xdeadbeef and 0xcaf3baee respectively

Last updated