【发布时间】:2017-03-16 13:05:14
【问题描述】:
首先,我想说我有足够的汇编背景,可以理解成为函数式汇编程序员所需了解的大部分内容。不幸的是,我不明白 Windows API 调用在返回地址方面是如何工作的。
这是一些用 GAS 汇编编写的 Windows 示例代码,使用 MinGW 作为汇编器,MinGW 的 ld 作为链接器...
.extern _ExitProcess@4
.text
.globl _main
_main:
pushl $0
call _ExitProcess@4
此代码在汇编后编译运行...
as program.s -o program.o
并链接它...
ld program.o -o program.exe -lkernel32
据我了解,Windows API 调用通过推送指令获取参数,如上所示。然后在通话期间;
call _ExitProcess@4
函数的返回地址被放置在堆栈上。然后,这就是我感到困惑的地方,该函数将所有参数从堆栈中弹出。
我很困惑,因为堆栈是后进先出的,在我看来,当弹出堆栈上的参数时,它会首先弹出返回地址。首先是参数,然后是返回地址,因此从技术上讲,它会首先弹出。
我的问题是,通过推送操作将参数传递给函数调用并将返回地址放在堆栈上后,堆栈的布局是什么样的?函数在执行时如何将参数和返回地址从堆栈中弹出?最后,返回地址如何出栈,函数调用又返回到返回地址中指定的地址?
【问题讨论】:
-
不好的例子,ExitProcess() 根本不应该返回。
-
它没有返回值,但它在堆栈上有一个返回地址。当它使用 ret 指令(我上次检查的 \xc3)返回时,它会从堆栈中弹出返回值并将执行流程定向到 Windows API,然后再次将执行定向到开始函数调用的 call 指令之后的下一条指令第一名。
-
正如 Turbo J 所说,ExitProcess 永远不会返回。堆栈上有一个返回地址,但它从未使用过,并且该函数从不执行 RET 指令。正如函数名所说,函数导致进程退出,这意味着它不能返回给调用者,因为调用者将不再存在。
-
哦,对不起,你是对的。试试GetStdHandle,这是一个可口的功能。它接受一个推入堆栈的参数,实际上返回。