X86 Stack Operation Detail

Caller Rules (main function on example)

To make a subrouting call, the caller should:
  1. Before calling a subroutine, the caller should save the contents of certain registers that are designated caller-saved. The caller-saved registers are EAX, ECX, EDX. Since the called subroutine is allowed to modify these registers, if the caller relies on their values after the subroutine returns, the caller must push the values in these registers onto the stack (so they can be restore after the subroutine returns.(在call subroutin之前會將要傳送的Parameter Push進stack, 在現在是存到ESI EDI register)
  2. To pass parameters to the subroutine, push them onto the stack before the call. The parameters should be pushed in inverted order (i.e. last parameter first). Since the stack grows down, the first parameter will be stored at the lowest address (this inversion of parameters was historically used to allow functions to be passed a variable number of parameters).(在push進stack時是以Invert的順序, 像是例子test(int a,int b)則 push b , push a, 從右到左)
  3. To call the subroutine, use the call instruction. This instruction places the return address on top of the parameters on the stack, and branches to the subroutine code. This invokes the subroutine, which should follow the callee rules below.(在執行call instruction時會將return address(也就是下面的位置400574)放到rbp
main:
400565: mov    $0x3,%esi
40056a: mov    $0x2,%edi
40056f:  callq  400517 <test>
400574: mov    %eax,-0x4(%rbp)








After the subroutine returns (immediately following the call instruction), the caller can expect to find the return value of the subroutine in the register EAX. To restore the machine state, the caller should:
  1. Remove the parameters from stack. This restores the stack to its state before the call was performed.(leave instruction 會restore rbp to previous stack frame , ret 會將return address 存進EIP, 將ESP 目前指向位置Pop 0x30)
  2. Restore the contents of caller-saved registers (EAX, ECX, EDX) by popping them off of the stack. The caller can assume that no other registers were modified by the subroutine.
test:
  400548: mov    $0x1,%eax
  40054d: leaveq 

  40054e: retq   


main:
40056f: callq  400517 <test>
400574: mov    %eax,-0x4(%rbp)
400577: mov    $0x40068a,%eax
40057c: mov    %rax,%rdi
40057f: mov    $0x0,%eax






Callee Rules(int test(int a,int b) function on example)

The definition of the subroutine should adhere to the following rules at the beginning of the subroutine:
  1. Push the value of EBP onto the stack, and then copy the value of ESP into EBP using the following instructions:
        push ebp
        mov  ebp, esp
    
    This initial action maintains the base pointer, EBP. The base pointer is used by convention as a point of reference for finding parameters and local variables on the stack. When a subroutine is executing, the base pointer holds a copy of the stack pointer value from when the subroutine started executing. Parameters and local variables will always be located at known, constant offsets away from the base pointer value. We push the old base pointer value at the beginning of the subroutine so that we can later restore the appropriate base pointer value for the caller when the subroutine returns. Remember, the caller is not expecting the subroutine to change the value of the base pointer. We then move the stack pointer into EBP to obtain our point of reference for accessing parameters and local variables.(可以看到下面的圖, Local Variable and previous BP address會存在對應的地方)
  2. Next, allocate local variables by making space on the stack. Recall, the stack grows down, so to make space on the top of the stack, the stack pointer should be decremented. The amount by which the stack pointer is decremented depends on the number and size of local variables needed. For example, if 3 local integers (4 bytes each) were required, the stack pointer would need to be decremented by 12 to make space for these local variables (i.e., sub esp, 12). As with parameters, local variables will be located at known offsets from the base pointer.(會根據variable需要的大小配置需要的stack size
  3. Next, save the values of the callee-saved registers that will be used by the function must be saved. To save registers, push them onto the stack. The callee-saved registers are EBX, EDI, and ESI (ESP and EBP will also be preserved by the calling convention, but need not be pushed on the stack during this step).
After these three actions are performed, the body of the subroutine may proceed. When the subroutine is returns, it must follow these steps:
  1. Leave the return value in EAX.(要return的數值存在EAX
  2. Restore the old values of any callee-saved registers (EDI and ESI) that were modified. The register contents are restored by popping them from the stack. The registers should be popped in the inverse order that they were pushed.(將數值pop up出來)
  3. Deallocate local variables. The obvious way to do this might be to add the appropriate value to the stack pointer (since the space was allocated by subtracting the needed amount from the stack pointer). In practice, a less error-prone way to deallocate the variables is to move the value in the base pointer into the stack pointer: mov esp, ebp. This works because the base pointer always contains the value that the stack pointer contained immediately prior to the allocation of the local variables.(將SP的值以BP覆蓋掉, 就可以完成Deallocate
  4. Immediately before returning, restore the caller's base pointer value by popping EBP off the stack. Recall that the first thing we did on entry to the subroutine was to push the base pointer to save its old value.
  5. Finally, return to the caller by executing a ret instruction. This instruction will find and remove the appropriate return address from the stack.(透過之前存放的return address跳回該做的code address, 前remove掉它


int test(int a,int b)
{
 int i=0;
 printf("do nothing");
 return 1;
}

void main()
{
 int add,arg1=10,arg2=20;

 add = test(2,3);

 printf("main end");
}


void main()



int test(int a,int b)


參考: 這個非常的Detail 很實用  http://www.tenouk.com/Bufferoverflowc/Bufferoverflow3.html
          http://www.tenouk.com/Bufferoverflowc/Bufferoverflow2.html

留言