233 lines
5.3 KiB
Markdown
233 lines
5.3 KiB
Markdown
# Disassembler
|
||
|
||
> Sucessful reverse engineers do not evaluate each instruction individually unless they must. The process is too tedious.
|
||
|
||
### Global vs Local Variables
|
||
|
||
*Globbal variables* can be accessed and used by any function in the program.
|
||
|
||
*Local variables* can be accessed only by the function in which they are defined.
|
||
|
||
Both types of variables are declared similarly in `c` but completely differently in assembly.
|
||
|
||
> **Global** variables are referenced by **memory addresses**
|
||
>
|
||
> **Local** variables are referenced by **stack addresses**
|
||
|
||
### Recognising if Statements
|
||
|
||
In IDA, branches will be represented as such:
|
||
|
||
```c
|
||
int x = 1;
|
||
int y = 2;
|
||
|
||
if (x == y){
|
||
printf("x equals y\n");
|
||
} else {
|
||
printf("x does not equals y\n");
|
||
}
|
||
```
|
||
|
||
```assembly
|
||
00401006 mov [ebp+var_8], 1
|
||
0040100D mov [ebp+var_4], 2
|
||
00401014 mov eax, [ebp+var_8]
|
||
00401017 cmp eax, [ebp+var_4]
|
||
0040101A jnz short loc_40102B
|
||
0040101C push offset aXEqualsY_ ; "x equals y.\n"
|
||
00401021 call printf
|
||
00401026 add esp, 4
|
||
00401029 jmp short loc_401038
|
||
0040102B loc_40102B:
|
||
0040102B push offset aXIsNotEqualToY ; "x is not equal to y.\n"
|
||
00401030 call printf
|
||
```
|
||
|
||
Here the instruction `jnz` on line 5 causes the branch. A `cmp` is done between `ebp+var_8` (y) and `ebp+var_4`(x). If the values are not equal, then we jump to “x is not equal to y”
|
||
|
||
This is what that looks like in IDA
|
||
|
||

|
||
|
||
### Recognising Loops
|
||
|
||
##### Finding for loops
|
||
|
||
For loops have 4 basic components:
|
||
|
||
1. initialisation
|
||
2. comparison
|
||
3. execution instructions
|
||
4. increment/decrement
|
||
|
||
```c
|
||
int i;
|
||
|
||
for (i=0; i<100; i++)
|
||
{
|
||
printf("i equals %d\n", i);
|
||
}
|
||
```
|
||
|
||
```assembly
|
||
mov [ebp+var_4], 0 ; INITIALISATION
|
||
jmp short loc_401016
|
||
loc_40100D:
|
||
mov eax, [ebp+var_4] ; INCREMENT START
|
||
add eax, 1
|
||
mov [ebp+var_4], eax ; INCREMENT STOP
|
||
loc_401016:
|
||
cmp [ebp+var_4], 64h ; COMPARISON
|
||
jge short loc_40102F ; COMPARISON
|
||
mov ecx, [ebp+var_4]
|
||
push ecx
|
||
push offset aID ; "i equals %d\n"
|
||
call printf
|
||
add esp, 8
|
||
jmp short loc_40100D ; UNCONDITIONAL JUMP
|
||
```
|
||
|
||

|
||
|
||
Note: the box on the bottom right is the function’s epilogue
|
||
|
||
##### Finding While Loops
|
||
|
||
While loops look similar to for loops in assembly, but are easier to understand.
|
||
|
||
```c
|
||
int status = 0;
|
||
int result = 0;
|
||
|
||
while (status == 0)
|
||
{
|
||
result = performAction();
|
||
status = checkResult(result);
|
||
}
|
||
```
|
||
|
||
The assembly for this code will look similar from before however it lacks the *increment* section.
|
||
|
||
```assembly
|
||
mov [ebp+var_4], 0
|
||
mov [ebp+var_8], 0
|
||
loc_401044:
|
||
cmp [ebp+var_4], 0
|
||
jnz short loc_401063 ; CONDITIONAL JUMP
|
||
call performAction
|
||
mov [ebp+var_8], eax
|
||
mov eax, [ebp+var_8]
|
||
push eax
|
||
call checkResult
|
||
add esp, 4
|
||
mov [ebp+var_4], eax
|
||
jmp short loc_401044 ; UNCONDITIONAL JUMP
|
||
```
|
||
|
||
A conditional jump occurs on line 5 and an unconditional jump at line 13, but the only way for this code to stop executing repeatedly is for that conditional jump to occur.
|
||
|
||
#### Understanding Function Call Conventions
|
||
|
||
Function call conventions govern:
|
||
|
||
- The order in which parameters are placed on the stack or in registers
|
||
- Whether the caller or callee is responsible for cleaning up the stack
|
||
|
||
Calling convention depends on the compiler used
|
||
|
||
```c
|
||
int adder(int a, int b)
|
||
{
|
||
return a+b;
|
||
}
|
||
|
||
void main()
|
||
{
|
||
int x=1;
|
||
int y=2;
|
||
|
||
printf("adder(1,2): %d", adder(x,y));
|
||
}
|
||
```
|
||
|
||
|
||
|
||

|
||
|
||
### Switch Statements
|
||
|
||
Switch statements are compiled in two different ways: if style or using jump tables
|
||
|
||
```c
|
||
switch(i)
|
||
{
|
||
case 1:
|
||
printf("i = %d", i+1);
|
||
break;
|
||
case 2:
|
||
printf("i = %d", i+2);
|
||
break;
|
||
case 3:
|
||
printf("i = %d", i+3);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
```
|
||
|
||
##### If Style
|
||
|
||

|
||
|
||
##### Jump Table
|
||
|
||
This example is usually found with large contiguous `switch` statements. The compiler optimises the code to avoid needing to make so many comparisons
|
||
|
||

|
||
|
||
This assembly uses a jump table which defines offsets to additional memory locations. The switch variable (stored in `ecx`) is used as an index into the jump table.
|
||
|
||
`edx` is multiplied by 4 and added to the base of the jump table to determine which case code block to jump to.
|
||
|
||
It is multiplied by 4 because each entry in the jump table is an address that is 4 bytes in size.
|
||
|
||
### Disassembling Arrays
|
||
|
||
```c
|
||
int b[5] = {123, 87, 487, 7, 978};
|
||
void main()
|
||
{
|
||
int i;
|
||
int a[5];
|
||
for(i = 0; i<5; i++)
|
||
{
|
||
a[i] = i;
|
||
b[i] = i;
|
||
}
|
||
}
|
||
```
|
||
|
||
In assembly, arrays are accessed using a base address as a starting point. The size of each element is not always obvious, but can be determined by seeing how the array is being indexed.
|
||
|
||
```assembly
|
||
00401006 mov [ebp+var_18], 0
|
||
0040100D jmp short loc_401018
|
||
0040100F loc_40100F:
|
||
0040100F mov eax, [ebp+var_18]
|
||
00401012 add eax, 1
|
||
00401015 mov [ebp+var_18], eax
|
||
00401018 loc_401018:
|
||
00401018 cmp [ebp+var_18], 5
|
||
0040101C jge short loc_401037
|
||
0040101E mov ecx, [ebp+var_18]
|
||
00401021 mov edx, [ebp+var_18]
|
||
00401024 mov [ebp+ecx*4+var_14], edx ; LOCAL
|
||
00401028 mov eax, [ebp+var_18]
|
||
0040102B mov ecx, [ebp+var_18]
|
||
0040102E mov dword_40A000[ecx*4], eax ; GLOBAL
|
||
00401035 jmp short loc_40100F
|
||
```
|
||
|
||
In both cases `ecx` is used as the index, which is multiplied by 4 to account for the size of the elements. This is added onto the base address of the array to access the proper array element.
|