简体   繁体   中英

What exactly happens in this minimalistic C code on assembly level?

I am currently trying to understand Writing buffer overflow exploits - a tutorial for beginners .

The C code, compiled with cc -ggdb exploitable.c -o exploitable

#include <stdio.h>

void exploitableFunction (void) {
    char small[30];
    gets (small);
    printf("%s\n", small);
}

main() {
    exploitableFunction();
    return 0;
}

seems to have the assembly code

0x000000000040063b <+0>:    push   %rbp
0x000000000040063c <+1>:    mov    %rsp,%rbp
0x000000000040063f <+4>:    callq  0x4005f6 <exploitableFunction>
0x0000000000400644 <+9>:    mov    $0x0,%eax
0x0000000000400649 <+14>:   pop    %rbp
0x000000000040064a <+15>:   retq

I think it does the following, but I'm really not sure about it and I would like to hear from somebody who is experienced with assembly code if I'm right / what is right.

  • 40063b: Put the address which is currently in the base pointer register into the stack segment (How is this register initialized? Why is that done?)
  • 40063c: Copy the value from the stack pointer register into the base pointer register (why?)
  • 40063f: Call exploitableFunction (What exactly does it mean to "call" a function in assembly? What happens here?)
  • 400644: Copy the value from the address $0x0 to the EAX register
  • 400649: Copy the value from the top of the stack (determined by the value in %rsp) into the base pointer register (seems to be confirmed by Assembler: Push / pop registers? )
  • 40064a: Return (the OS uses what is in %EAX as return code - so I guess the address $0x0 contains the constant 0? Or is that not an address but the constant?)

40063b: Put the address which is currently in the base pointer register into the stack segment (How is this register initialized? Why is that done?)

You want to save the base pointer because it is probably used by the calling function.

40063c: Copy the value from the stack pointer register into the base pointer register (why?)

This gives you a fixed position into the stack, which might contain parameters for the function. It can also be used as a base address for any local variables.

40063f: Call exploitableFunction (What exactly does it mean to "call" a function in assembly? What happens here?)

"call" means pushing the return address (address of the next instruction) onto the stack, and then jumping to the start of the called function.

400644: Copy the value from the address $0x0 to the EAX register

It is actually the value 0 from the return statement.

400649: Copy the value from the top of the stack (determined by the value in %rsp) into the base pointer register (seems to be confirmed by Assembler: Push / pop registers?)

This restores the base pointer we saved at the top. The calling function might assume that we do.

40064a: Return (the OS uses what is in %EAX as return code - so I guess the address $0x0 contains the constant 0? Or is that not an address but the constant?)

It was the constant from return 0 . Using EAX for a small return value is a common convention.

I found a Link which have similar code to your own with full explenation.

  • 40063b: push the old base pointer onto the stack to save it for later. It's pushed because this is not the only process in the code. some other process call it.
  • 40063c: copy the value of the stack pointer to the base pointer. After this, %rbp points to the base of main 's stack frame.
  • 40063f: call the function in address 0x4005f6 which push the program counter into stack and load address 0x4005f6 into program conter, when the function returns, pop operation is happened to return the saved address in the stack to program counter which is 0x400644 here
  • 400644: This instruction copies 0 into %eax , The x86 calling convention dictates that a function's return value is stored in %eax
  • 400649: We pop the old base pointer off the stack and store it back in %rbp
  • 40064a: jumps back to return address, which is also stored in the stack frame. which specify the end of the program.

Also you didn't mention the assembly code for the function exploitableFunction . here is only main function

The function entry saves bp and moves sp into bp. All parameters of the function will now be addressed using bp. This is a standard cdecl convention (in Intel assembler):

; int example(char *s, int i)
    push        bp                    ; save the caller's value of bp
    mov         bp,sp                 ; set-up our base pointer to the stack-frame
    sub         sp, 16                ; room for automatic variables
    mov         ax,dword ptr [bp+8]   ; ax has *s
    mov         bx,dword ptr [bp+12]  ; bx has i
    ...                               ; do your thing
    mov         ax, dword ptr[result] ; function return in ax
    pop         bp                    ; restore caller's base-pointer
    ret

When calling this function, the compiler pushes the parameters onto the stack and then calls the function. Upon return, it cleans up the stack:

; i= example(myString, k);
    mov         ax, [bp+16]        ; this gets a parameter of the curent function
    push        ax                 ; this will be parameter i
    mov         ax, [bp-16]        ; this gets a local variable
    push        ax                 ; this is parameter s
    call        example
    add         sp,8               ; remove the pushed parameters from the stack
    mov         dword ptr [i], ax  ; save return value - always in ax

Different compilers can use different conventions about passing parameters in registers, but I think the above is the basics of calls in C (using cdecl).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM