標籤:
構造以下C程式並在合適位置插入breakpoints
在Visual Studio 2015 CTP6對其反組譯碼。
下面來分析
z = add(1, 2);
009C170E 6A 02 push 2
????int z;
????z = add(1, 2);
009C1710 6A 01 push 1
009C1712 E8 8D FA FF FF call 009C11A4
009C1717 83 C4 08 add esp,8
009C171A 89 45 F8 mov dword ptr [ebp-8],eax
第一二行將參數1,2壓棧,由此可證明C語言函數參數入棧順序是從右向左。逐步執行push 1 和push 2,觀察寄存器的值,可知每將一個參數壓入棧,ESP值都要減4。執行push 1後查看ESP所指記憶體的值。
可以看到剛剛壓入的2和1,ESP是用來儲存棧頂指標的寄存器。
接下來分析下一行 E8 8D FA FF FF
E8為call指令機器碼,由小端機儲存可知e8的值為ff ff fa 8d。
call目標地址=call指令當前地址+5位元組(call指令佔用空間)- e8後指令的補碼。即009C11A4
call指令執行完畢後,跳轉到函數的主體部分。記錄返回地址009C1717。那麼函數如何返回?逐步執行call指令後發現ESP的值由00ACF744變成00ACF664,由於ESP變化較大,筆者猜測函數有可能使用了私人棧。而且00ACF664的內容與返回地址無關。我們直接將call之前ESP的地址減4並查看其內容
恰好為函數的返回地址,即call指令執行後,棧頂指標改變,返回地址被壓入函數執行前的棧。
Call指令作用相當於 1.壓棧返回地址 2.跳轉到目標指令。
Intel官方手冊上的說明:
Prior to branching to the first instruction of the called procedure, the CALL instruction pushes the address in the EIP
register onto the current stack. This address is then called the return-instruction pointer and it points to the
instruction where execution of the calling procedure should resume following a return from the called procedure.
Upon returning from a called procedure, the RET instruction pops the return-instruction pointer from the stack
back into the EIP register. Execution of the calling procedure then resumes.
以及CALL和RET指令的準備工作
Near call
When executing a near call, the processor does the following (see Figure 6-2):
1. Pushes the current value of the EIP register on the stack.
2. Loads the offset of the called procedure in the EIP register.
3. Begins execution of the called procedure.
When executing a near return, the processor performs these actions:
1. Pops the top-of-stack value (the return instruction pointer) into the EIP register.
2. If the RET instruction has an optional n argument, increments the stack pointer by the number of bytes
specified with the n operand to release parameters from the stack.
3. Resumes execution of the calling procedure.
Far call
1. Pushes the current value of the CS register on the stack.
2. Pushes the current value of the EIP register on the stack.
3. Loads the segment selector of the segment that contains the called procedure in the CS register.
4. Loads the offset of the called procedure in the EIP register.
5. Begins execution of the called procedure.
When executing a far return, the processor does the following:
1. Pops the top-of-stack value (the return instruction pointer) into the EIP register.
2. Pops the top-of-stack value (the segment selector for the code segment being returned to) into the CS register.
3. If the RET instruction has an optional n argument, increments the stack pointer by the number of bytes
specified with the n operand to release parameters from the stack.
4. Resumes execution of the calling procedure.
不難看出,far call是帶有segment的跳轉,用到了CS寄存器。
(未完待續)
彙編1 ----C語言函數1