map exe decompilation back to C language - c

Im pretty new to assembly, and am trying my best to learn it. Im taking a course to learn it and they mentioned a very remedial Hello World example, that I decomplied.
original c file:
#include <stdio.h>
int main()
{
printf("Hello Students!");
return 0;
}
This was decompiled using the following command:
C:> objdump -d -Mintel HelloStudents.exe > disasm.txt
decompliation (assembly):
push ebp
mov ebp, esp
and esp, 0xfffffff0
sub esp, 0x10
call 401e80 <__main>
mov DWORD PTR [esp], 0x404000
call 4025f8 <_puts>
mov eax, 0x0
leave
ret
Im having issues mapping this output from the decompliation, to the original C file can someone help?
Thank you very much!

The technical term for decompiling assembly back into C is "turning hamburger back into cows". The generated assembly will not be a 1-to-1 translation of the source, and depending on the level of optimization may be radically different. You will get something functionally equivalent to the original source, but how closely it resembles that source in structure is heavily variable.
push ebp
mov ebp, esp
and esp, 0xfffffff0
sub esp, 0x10
This is all preamble, setting up the stack frame for the main function. It aligns the stack pointer (ESP) by 16 bytes then reserves another 16 bytes of space for outgoing function args.
call 401e80, <___main>
This function call to ___main is how MinGW arranges for libc initialization functions to run at the start of the program, making sure stdio buffers are allocated and stuff like that.
That's the end of the pre-amble; the part of the function that implements the C statements in your source starts with:
mov DWORD PTR [esp], 0x404000
This writes the address of the string literal "Hello Students!" onto the stack. Combined with the earliersub esp, 16, this is like apush` instruction. In this 32-bit calling convention, function args are passed on the stack, not registers, so that's where the compiler has to put them before function calls.
call 4025f8 <_puts>
This calls the puts function. The compiler realized that you weren't doing any format processing in the printf call and replaced it with the simpler puts call.
mov eax, 0x0
The return value of main is loaded into the eax register
leave
ret
Restore the previous EBP value, and tear down the stack frame, then exit the function. ret pops a return address off the stack, which can only work when ESP is pointing at the return address.

Related

Assembly: Purpose of loading the effective address before a call to a function?

Source C Code:
int main()
{
int i;
for(i=0, i < 10; i++)
{
printf("Hello World!\n");
}
}
Dump of Intel syntax x86 assembler code for function main:
1. 0x000055555555463a <+0>: push rbp
2. 0x000055555555463b <+1>: mov rbp,rsp
3. 0x000055555555463e <+4>: sub rsp,0x10
4. 0x0000555555554642 <+8>: mov DWORD PTR [rbp-0x4],0x0
5. 0x0000555555554649 <+15>: jmp 0x55555555465b <main+33>
6. 0x000055555555464b <+17>: lea rdi,[rip+0xa2] # 0x5555555546f4
7. 0x0000555555554652 <+24>: call 0x555555554510 <puts#plt>
8. 0x0000555555554657 <+29>: add DWORD PTR [rbp-0x4],0x1
9. 0x000055555555465b <+33>: cmp DWORD PTR [rbp-0x4],0x9
10. 0x000055555555465f <+37>: jle 0x55555555464b <main+17>
11. 0x0000555555554661 <+39>: mov eax,0x0
12. 0x0000555555554666 <+44>: leave
13. 0x0000555555554667 <+45>: ret
I'm currently working through "Hacking, The Art of Exploitation 2nd Edition by Jon Erickson", and I'm just starting to tackle assembly.
I have a few questions about the translation of the provided C code to Assembly, but I am mainly wondering about my first question.
1st Question: What is the purpose of line 6? (lea rdi,[rip+0xa2]).
My current working theory, is that this is used to save where the next instructions will jump to in order to track what is going on. I believe this line correlates with the printf function in the source C code.
So essentially, its loading the effective address of rip+0xa2 (0x5555555546f4) into the register rdi, to simply track where it will jump to for the printf function?
2nd Question: What is the purpose of line 11? (mov eax,0x0?)
I do not see a prior use of the register, EAX and am not sure why it needs to be set to 0.
The LEA puts a pointer to the string literal into a register, as the first arg for puts. The search term you're looking for is "calling convention" and/or ABI. (And also RIP-relative addressing). Why is the address of static variables relative to the Instruction Pointer?
The small offset between code and data (only +0xa2) is because the .rodata section gets linked into the same ELF segment as .text, and your program is tiny. (Newer gcc + ld versions will put it in a separate page so it can be non-executable.)
The compiler can't use a shorter more efficient mov edi, address in position-independent code in your Linux PIE executable. It would do that with gcc -fno-pie -no-pie
mov eax,0 implements the implicit return 0 at the end of main that C99 and C++ guarantee. EAX is the return-value register in all calling conventions.
If you don't use gcc -O2 or higher, you won't get peephole optimizations like xor-zeroing (xor eax,eax).
This:
lea rdi,[rip+0xa2]
Is a typical position independent LEA, putting the string address into a register (instead of loading from that memory address).
Your executable is position independent, meaning that it can be loaded at runtime at any address. Therefore, the real address of the argument to be passed to puts() needs to be calculated at runtime every single time, since the base address of the program could be different each time. Also, puts() is used instead of printf() because the compiler optimized the call since there is no need to format anything.
In this case, the binary was most probably loaded with the base address 0x555555554000. The string to use is stored in your binary at offset 0x6f4. Since the next instruction is at offset 0x652, you know that, no matter where the binary is loaded in memory, the address you want will be rip + (0x6f4 - 0x652) = rip + 0xa2, which is what you see above. See this answer of mine for another example.
The purpose of:
mov eax,0x0
Is to set the return value of main(). In Intel x86, the calling convention is to return values in the rax register (eax if the value is 32 bits, which is true in this case since main returns an int). See the table entry for x86-64 at the end of this page.
Even if you don't add an explicit return statement, main() is a special function, and the compiler will add a default return 0 for you.
If you add some debug data and symbols to the assembly everything will be easier. It is also easier to read the code if you add some optimizations.
There is a very useful tool godbolt and your example https://godbolt.org/z/9sRFmU
On the asm listing there you can clearly see that that lines loads the address of the string literal which will be then printed by the function.
EAX is considered volatile and main by default returns zero and thats the reason why it is zeroed.
The calling convention is explained here: https://en.wikipedia.org/wiki/X86_calling_conventions
Here you have more interesting cases https://godbolt.org/z/M4MeGk

How to pass variables to a external assembly function

How to pass a variable from a C program to a assembly function.
Example:
main.c:
void main() {
unsigned int passthis = 42
extern asm_function();
asm_function(passthis)
}
main.asm:
bits 32
global start
section .text
asm_function:
...
How do I access passthis within asm_function.
Edit: Probably should've mentioned i'm not using a OS, i'm compiling using a i686-elf cross compiler and am going to use it as a kernel.
If you compile your C into 32-bit code with the default GCC options (not -mregparm=3 like the Linux kernel uses), then on function entry the first argument is on the stack just above the return address (at [esp+4]), but that offset changes after you push anything or move ESP around.
You can use [ebp+8] after setting up a traditional stack pointer (which doesn't change during the function even when ESP does).
For example, int asm_function(int) can be implemented as:
;bits 32 ; unneeded, nasm -felf32 implies this.
global asm_function ; include asm_function in ELF .o symbol table for linking
section .text
asm_function:
push ebp
mov ebp, esp
mov eax, [ebp+8] ; return the first argument
mov esp, ebp
pop ebp
ret
For each parameter after this, just simply add another 4 (i.e. for the 2nd parameter, use [ebp+12]). As you can see, setting up EBP as a frame pointer adds a lot of overhead for tiny functions.
Some non-ELF systems/ABIs prepend a leading underscore to C symbol names, so you should declare both asm_function and _asm_function for your code to be roughly equivalent across these ABIs, like so:
global _asm_function
global asm_function ; make both names of the function global
section .text
_asm_function:
asm_function: ; make both symbols point to the same place
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov esp, ebp
pop ebp
ret
x86 has probably a handful of different calling conventions. It depends on a number of things, like windows vs. linux, and on what compiler environment you're using, 32-bit vs. 64-bit, etc..
Best probably to look at the output of the compiler you're using to see how the parameter is being passed, and do the corresponding appropriate way of accepting the parameter in your assembly. So if it is pushed on the stack then expect it there, if it is passed in a register, expect it there...
You can look at the output using a disassembler, or using a debugger.

Why is there no "sub rsp" instruction in this function prologue and why are function parameters stored at negative rbp offsets?

That's what I understood by reading some memory segmentation documents: when a function is called, there are a few instructions (called function prologue) that save the frame pointer on the stack, copy the value of the stack pointer into the base pointer and save some memory for local variables.
Here's a trivial code I am trying to debug using GDB:
void test_function(int a, int b, int c, int d) {
int flag;
char buffer[10];
flag = 31337;
buffer[0] = 'A';
}
int main() {
test_function(1, 2, 3, 4);
}
The purpose of debugging this code was to understand what happens in the stack when a function is called: so I had to examine the memory at various step of the execution of the program (before calling the function and during its execution). Although I managed to see things like the return address and the saved frame pointer by examining the base pointer, I really can't understand what I'm going to write after the disassembled code.
Disassembling:
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400509 <+0>: push rbp
0x000000000040050a <+1>: mov rbp,rsp
0x000000000040050d <+4>: mov ecx,0x4
0x0000000000400512 <+9>: mov edx,0x3
0x0000000000400517 <+14>: mov esi,0x2
0x000000000040051c <+19>: mov edi,0x1
0x0000000000400521 <+24>: call 0x4004ec <test_function>
0x0000000000400526 <+29>: pop rbp
0x0000000000400527 <+30>: ret
End of assembler dump.
(gdb) disassemble test_function
Dump of assembler code for function test_function:
0x00000000004004ec <+0>: push rbp
0x00000000004004ed <+1>: mov rbp,rsp
0x00000000004004f0 <+4>: mov DWORD PTR [rbp-0x14],edi
0x00000000004004f3 <+7>: mov DWORD PTR [rbp-0x18],esi
0x00000000004004f6 <+10>: mov DWORD PTR [rbp-0x1c],edx
0x00000000004004f9 <+13>: mov DWORD PTR [rbp-0x20],ecx
0x00000000004004fc <+16>: mov DWORD PTR [rbp-0x4],0x7a69
0x0000000000400503 <+23>: mov BYTE PTR [rbp-0x10],0x41
0x0000000000400507 <+27>: pop rbp
0x0000000000400508 <+28>: ret
End of assembler dump.
I understand that "saving the frame pointer on the stack" is done by " push rbp", "copying the value of the stack pointer into the base pointer" is done by "mov rbp, rsp" but what is getting me confused is the lack of a "sub rsp $n_bytes" for "saving some memory for local variables". I've seen that in a lot of exhibits (even in some topics here on stackoverflow).
I also read that arguments should have a positive offset from the base pointer (after it's filled with the stack pointer value), since if they are located in the caller function and the stack grows toward lower addresses it makes perfect sense that when the base pointer is updated with the stack pointer value the compiler goes back in the stack by adding some positive numbers. But my code seems to store them in a negative offset, just like local variables.. I also can't understand why they are put in those registers (in the main).. shouldn't they be saved directly in the rsp "offsetted"?
Maybe these differences are due to the fact that I'm using a 64 bit system, but my researches didn't lead me to anything that would explain what I am facing.
The System V ABI for x86-64 specifies a red zone of 128 bytes below %rsp. These 128 bytes belong to the function as long as it doesn't call any other function (it is a leaf function).
Signal handlers (and functions called by a debugger) need to respect the red zone, since they are effectively involuntary function calls. All of the local variables of your test_function, which is a leaf function, fit into the red zone, thus no adjustment of %rsp is needed. (Also, the function has no visible side-effects and would be optimized out on any reasonable optimization setting).
You can compile with -mno-red-zone to stop the compiler from using space below the stack pointer. Kernel code has to do this because hardware interrupts don't implement a red-zone.
But my code seems to store them in a negative offset, just like local variables
The first x86_64 arguments are passed on registers, not on the stack. So when rbp is set to rsp, they are not on the stack, and cannot be on a positive offset.
They are being pushed only to:
save register state for a second function call.
In this case, this is not required since it is a leaf function.
make register allocation easier.
But an optimized allocator could do a better job without memory spill here.
The situation would be different if you had:
x86_64 function with lots of arguments. Those that don't fit on registers go on the stack.
IA-32, where every argument goes on the stack.
the lack of a "sub rsp $n_bytes" for "saving some memory for local variables".
The missing sub rsp on red zone of leaf function part of the question had already been asked at: Why does the x86-64 GCC function prologue allocate less stack than the local variables?

why to use ebp in function prologue/epilogue?

Some time ago I was experimenting with writing assembly
routines and linking it with C programs and I found that
I just can skip standard C-call prologue epilogue
push ebp
mov ebp, esp
(sub esp, 4
...
mov esp, ebp)
pop ebp
just skip it all and adress just by esp, like
mov eax, [esp+4] ;; take argument
mov [esp-4], eax ;; use some local variable storage
It seem to work quite good. Why this ebp is used - is maybe
addressing through ebp faster or what ?
There's no requirement to use a stack frame, but there are certainly some advantages:
Firstly, if every function has uses this same process, we can use this knowledge to easily determine a sequence of calls (the call stack) by reversing the process. We know that after a call instruction, ESP points to the return address, and that the first thing the called function will do is push the current EBP and then copy ESP into EBP. So, at any point we can look at the data pointed to by EBP which will be the previous EBP and that EBP+4 will be the return address of the last function call. We can therefore print the call stack (assuming 32bit) using something like (excuse the rusty C++):
void LogStack(DWORD ebp)
{
DWORD prevEBP = *((DWORD*)ebp);
DWORD retAddr = *((DWORD*)(ebp+4));
if (retAddr == 0) return;
HMODULE module;
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*)retAddr, &module);
char* fileName = new char[256];
fileName[255] = 0;
GetModuleFileNameA(module, fileName, 255);
printf("0x%08x: %s\n", retAddr, fileName);
delete [] fileName;
if (prevEBP != 0) LogStack(prevEBP);
}
This will then print out the entire sequence of calls (well, their return addresses) up until that point.
Furthermore, since EBP doesn't change unless you explicitly update it (unlike ESP, which changes when you push/pop), it's usually easier to reference data on the stack relative to EBP, rather than relative to ESP, since with the latter, you have to be aware of any push/pop instructions that might have been called between the start of the function and the reference.
As others have mentioned, you should avoid using stack addresses below ESP as any calls you make to other functions are likely to overwrite the data at these addresses. You should instead reserve space on the stack for use by your function by the usual:
sub esp, [number of bytes to reserve]
After this, the region of the stack between the initial ESP and ESP - [number of bytes reserved] is safe to use.
Before exiting your function you must release the reserved stack space using a matching:
add esp, [number of bytes reserved]
The use of EBP is of great help when debugging code, as it allows debuggers to traverse the stack frames in a call chain.
It [creates] a singly linked list that linked the frame pointer for each of the callers to a function. From the EBP for a routine, you could recover the entire call stack for a function.
See http://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames
And in particular the page it links to which covers your question: http://blogs.msdn.com/b/larryosterman/archive/2007/03/12/fpo.aspx
It works, However, once you'll get an interrupt, the processor will push all it's registers and flags into the stack, overwriting your value.
The stack is there for a reason, use it...

Explanation of the disassembly of the simplest program (x86)

The following code
int _main() {return 0;}
Compiled using the command:
gcc -s -nostdlib -nostartfiles 01-simple.c -o01-simple.exe
gcc version 4.4.1 (TDM-1 mingw32)
OllyDbg produced this output:
Can you explain what happens here?
Analysis so far:
// these two seems to be an idiom:
PUSH EBP // places EBP on stack
MOV EBP, ESP // overwrites EBP with ESP
MOV EAX, 0 // EAX = 0
LEAVE // == mov esp, ebp
// pop ebp
// according to
// http://en.wikipedia.org/wiki/X86_instruction_listings
What is the meaning of all this?
This creates a stack frame.
PUSH EBP
MOV EBP, ESP
In the calling convention being used, the return value is sent back via EAX (so the 0 is there because you wrote return 0; - try changing that to return 1; and see how that affects the code).
MOV EAX, 0
And this tells the processor to clean up the stack frame (it's the equivalent of MOV ESP, EBP followed by POP EBP which is the opposite of what was done when creating the stack frame):
LEAVE
The instructions sets up the stack frame upon the runtime loader entering the int _main() function,
PUSH EBP
MOV EBP, ESP
Stack frame is set up and to access the parameters if any were supplied would be offset from EBP + the size of the parameter (WORD, BYTE, LONG, etc).
Usually the EAX register is the normal register to return an exit status from the runtime environment to the operating system loader,
MOV EAX, 0
LEAVE
in other words, to say the program has exited successfully returning a 0 to the Operating system.
Where a return is used, the stack frame is restored upon runtime execution prior to handing control back to the Operating system.
POP EBP
The general consensus is, if an error has occurred, the value would be non-zero, and can be used both from batch files (harking back to the old DOS days) and unix scripts where it checks if the program ran successfully or not and proceed onwards depending on the nature of the batch file or script.
The 'MOV EAX,0' instruction is the body of your function. The header code is for setting up space for your code to run in.
The 'LEAVE' instruction returns your code to where it came. Even though you said no standard libraries, there is plenty of other code in there that the linker puts into place.

Resources