Reverse Engineering Assignment
Reverse Engineering Assignment
Prepared By: -
Adane Getnet | GSR/3704/15 [email protected]
Sewalem Alemu | GSR/0198/15
PAGE 1
Abstract
The assignment report focuses on the reverse engineering of compiled C programs using the gdb
debugger to find hidden flags within the memory. This report includes detailed analyses of four
challenges, each increasing in complexity. The challenges involved finding number flags in
RAM, determining if a flag is a number, and tracking variations of changing numbers during
script execution. The report includes a section dedicated to each challenge, detailing the reverse
engineering process, gdb commands used, and identification of the source code.
Introduction
This assignment report explored the process of reverse engineering built C programs using the
gdb debugger. The aim was to employ debugging methodologies to retrieve concealed data from
executable files, offering practical exposure to examining generated code and comprehending the
inner workings of programs at a lower abstraction level. We gained a better understanding of
memory management, program execution, and debugging tools such as gdb by breaking down
and decoding the compiled programs. This report demonstrated how we reversed four tasks with
different levels of difficulty, outlining the procedures followed, gdb commands used, and
discoveries made along the inquiry. We hope to improve our abilities to reverse engineer, debug,
and find hidden information in compiled binaries with this activity.
Assignment Overview
1. We utilized debugging techniques to analyze compiled code and understand program
behavior at a lower level.
2. We extracted hidden information from executable files by dissecting and decoding the
compiled programs.
3. We enhanced our skills in memory management, program execution, and debugging tools
such as gdb.
4. We investigated four challenges of varying complexity to practice reverse engineering
and debugging skills.
PAGE 2
Process Description
We explained the steps followed during the reverse engineering process.
CHALLENGE 1 (EASIEST)
The flag of ex1 is a number, somewhere in the RAM?
Step 2:- Set breakpoints at relevant points. In our case at main methods
Mov BYTE PTR [rbp-0x1], 0x1: Store the value 1 in the memory location [rbp-0x1].
Step 4:- Inspect memory locations for any hidden strings or numbers.
#include <stdio.h>
int main() {
return 0;
Observation: - The function initializes a variable with the value 1 and performs minimal operations.
PAGE 3
CHALLENGE 2:
The flag of ex2 is a number, somewhere in the RAM
Step 1:- Similar to Challenge 1, but with increased complexity.
Load the Target in gdb
Set breakpoints at relevant points where I suspected the flag might be accessed or
manipulated. in my case started by setting a breakpoint at the beginning of the main
function: (gdb) break main
The assembly code initializes a 64-bit variable (QWORD PTR [rbp-0x8]) with the
value 0x10000.
A flag is a number 65536
Step 4:- Write a C program that you think is the source code of the program
#include <stdio.h>
int main() {
long int value = 65536;
return result;
}
PAGE 4
CHALLENGE 3:
The flag of ex3 is a number?
Step 1: Load the compiled C program into GDB.
QWORD PTR is an 8-byte data size of ASCII value so that the flag is “ASD2”, So that the
flag is not a number
Step 4: Equivalent C code
#include <stdio.h>
int main() {
char valu[8]="ASD2";
short a=0;
if(valu[8]){
}
return 0;
PAGE 5
CHALLENGE 4(HARD)
The flag of ex4 is a pair of numbers that changes over the execution of the script.\
Step 1:- disassembling and Assembly instruction interpretation.
This assembly code initializes two variables (V1 and V2), performs a loop, and modifies their values
based on certain conditions. The final result depends on the execution path taken within the loop.
1. mov DWORD PTR [rbp-0x4], 0x3: Store the value 3 in the memory location [rbp-0x4].
2. mov DWORD PTR [rbp-0x8], 0x0: Store the value 0 in the memory location [rbp-0x8].
3. jmp 0x55555555515c: Unconditional jump to the address 0x55555555515c.
4. cmp DWORD PTR [rbp-0x8], 0x0: Compare the value at [rbp-0x8] with 0.
5. je 0x555555555154: If the comparison result is equal (zero), jump to the address 0x555555555154.
6. add DWORD PTR [rbp-0x4], 0x1: Add 1 to the value at [rbp-0x4].
7. jmp 0x555555555158: Unconditional jump to the address 0x555555555158
8. sub DWORD PTR [rbp-0x4], 0x1: Subtract 1 from the value at [rbp-0x4].
9. add DWORD PTR [rbp-0x8], 0x1: Add 1 to the value at [rbp-0x8].
10. cmp DWORD PTR [rbp-0x8], 0x2: Compare the value at [rbp-0x8] with 2.
11. jle 0x555555555141: If the comparison result is less than or equal (non-positive), jump to the
address 0x555555555141.
PAGE 6
loop 1 loop 2
=> 0x000055555555515c <+51>: cmp DWORD PTR [rbp-0x8],0x2 => 0x000055555555515c <+51>: cmp DWORD PTR [rbp-0x8],0x2
=> 0x0000555555555160 <+55>: jle 0x555555555141 <main+24> => 0x0000555555555160 <+55>: jle 0x555555555141 <main+24>
V2<2 //jump V2<2 //jump
=> 0x0000555555555141 <+24>: mov DWORD PTR [rbp-0x8],0x0 => 0x0000555555555141 <+24>: mov DWORD PTR [rbp-0x8],0x0
V2=0 //set v2 =0 V2=0 //Rest V2 to 0
=> 0x0000555555555148 <+31>: cmp DWORD PTR [rbp-0x8],0x0 => 0x0000555555555148 <+31>: cmp DWORD PTR [rbp-0x8],0x0
=> 0x000055555555514c <+35>: je 0x555555555154 <main+43> => 0x000055555555514c <+35>: je 0x555555555154 <main+43>
V2=0 //jump V2=0 //jump
=> 0x0000555555555154 <+43>: sub DWORD PTR [rbp-0x4],0x1 => 0x0000555555555154 <+43>: sub DWORD PTR [rbp-0x4],0x1
V1=2 //V1 decrement by 1 V1=1 //V1 decrement by 1
=> 0x0000555555555158 <+47>: add DWORD PTR [rbp-0x8],0x1 => 0x0000555555555158 <+47>: add DWORD PTR [rbp-0x8],0x1
V2=1 //V2 increment by 1 V2=1 //V2 increment by 1
loop 3 loop 4
=> 0x000055555555515c <+51>: cmp DWORD PTR [rbp-0x8],0x2 => 0x000055555555515c <+51>: cmp DWORD PTR [rbp-0x8],0x2
=> 0x0000555555555160 <+55>: jle 0x555555555141 <main+24> => 0x0000555555555160 <+55>: jle 0x555555555141 <main+24>
V2<2 //jump V2<2 //jump
=> 0x0000555555555141 <+24>: mov DWORD PTR [rbp-0x8],0x0 => 0x0000555555555141 <+24>: mov DWORD PTR [rbp-0x8],0x0
V2=0 //Reset V2 to 0 V2=0 //Reset V2 to 0
=> 0x0000555555555148 <+31>: cmp DWORD PTR [rbp-0x8],0x0 =>0x0000555555555148 <+31>: cmp DWORD PTR [rbp-0x8],0x0
=> 0x000055555555514c <+35>: je 0x555555555154 <main+43> => 0x000055555555514c <+35>: je 0x555555555154 <main+43>
V2=0 //jump V2=0 //jump
=> 0x0000555555555154 <+43>: sub DWORD PTR [rbp-0x4],0x1 =>0x0000555555555154 <+43>: sub DWORD PTR [rbp-0x4],0x1
V1=0 //V1 decrement by 1 V1=-1 //V1 decrement by 1
=> 0x0000555555555158 <+47>: add DWORD PTR [rbp-0x8],0x1 =>0x0000555555555158 <+47>: add DWORD PTR [rbp-0x8],0x1
V2=1 //V2 increment by 1 V2=1 // V1 increment by 1
observation
we observed that there is a loop that changes the value of two numbers (V1 and V2 in our case)
the loop is recursive /non-stop
V1 continuously decrease from the initialized value where V2=0
V2 where rest to zero in each loop
from Assembly instruction code there is else case if V2 >2 V1 and V2 increase by 1
#include <stdio.h>
int main () {
int V1 = 3;
int V2 = 0;
while (V2 <= 2) {
V2=0;
if (V2 != 0) {
V1++;
} else {
V1--;
}
V2++;
}
return 0;
}
PAGE 7