Reverese Engineering: Understanding a C program [Part2]
Understanding the IF-ELSE Conditional statements in C program.
In my previous article, I gave few examples on how to understand a basic C program for Reverse Engineering. In this article, I’ll be focusing on how if-else works in assembly.
Let’s understand things step by step.
First step is very simple… I have written a blank main function… Just a block and its definition.
When I add an integer assignment to this block of code as in the below example. The assembly code should change accordingly.
There is a noticeable change in the assembly code now. A new instruction is added to it. From looking at the instruction, we can say that the stack base pointer (
rbp) has increased in downward direction
(-0x4).. 4 bytes to be precise. Interesting fact is the size of an integer is 4 bytes in linux based systems.
Another thing to notice here is that we are moving a HEX value of
0x5 to this newly created memory space. This is how an integer assignment looks like in assembly code.
Let’s verify this by creating another variable in the code and assigning some value to it.
So now it is quite obvious that first we have added
5 and then
6 to our stack. All of 4 byte size. Now what about if i add a
char variable to the stack?
Adding a char moved the stack one byte downward. But it added a
0x61 instead of a “a”. Why? Because C understands only ASCII… and the ASCII code for “a” is 61. So
0x61 it is.
Now since we have understood how a variable effects the stack, let’s give a look to the below code.
This is an example of a simple if-else block. Let’s break the code into segments to understand it.
- initialize an integer variable with a value of 5.
- Compare the value the stored value with 10.
- if the value is not equal then jump to the else section.
- else follow the if section.
Here i have twisted the explanation a little bit so that you can understand the assembly equivalent for it.
<+8>: initiate a variable and store the value of 5.
<+15>: compare the value with
0xa(decimal equivalent is 10)
<+19>: jump if not equal to (jne); jump on line (main+38). (main is the entry point here so its value is +0)
<+21>-<+31>: print “welcome”
<+36>: jump to line +53
<+38>-<+48>: print “invalid value”
Amazing thing to notice is the difference between these values(0x400673–0x400678)
- 0x400673 → W
- 0x400674 → e
- 0x400675 → l
- 0x400676 → c
- 0x400677 → o
- 0x400678 → m
- 0x400679 → e
- 0x40067a → new line char (\n)
It should be a bit easy now. If you are still facing problems in understanding it so draw a flow diagram for how things are working here.
The above workflow is not perfectly drawn but it might give you a slight idea of what is going on here.
Here the variable value was hard coded. But in real life it is very rare that we get a hard coded values like this.. It’s usually something that asks user for the input and then checks its value for comparing. Like one in the example below.
Let’s compile this. And run it.
So if the user input is 10 then the output is
Welcome and for other values the output is
This is how a basic offline password verification works. Now if someone gives you such a file and you don’t know its password. Then you’ll have to reverese engineer its code to know the password.
Disassembled code for the above program looks like this.
Take your time to understand what is happening here. You’ll figure out something how this assembly is associated to the above C program. Broad outlines of the above are:
- take input using the scanf function
- compare the value with 0xa
- take a jump if not equal to
- else follow the path
So after this analysis it is quite obvious that the input value is compared to 10. So I’ll have to enter 10 to see the welcome screen here.
Congratulations… Now you have completed your first ever reverse engineering challenge here.