我刚开始修补ASM,我不确定我对程序调用的理解是否正确。
在代码中的某个时刻说有一个过程调用
call dword ptr[123]
并且该过程只包含一个命令ret:
ret 0004
此过程调用会产生什么影响,返回值将存储在何处?我在某处读到了一个2字节的返回值将存储在AX中,但当我用
替换过程调用时mov AX, 0004
(连同必要的NOP)程序崩溃。
答案 0 :(得分:12)
在x86汇编程序中,ret
指令的参数表示:
RET immediate
返回调用过程并从堆栈中弹出 immediate 字节。
(引自Intel® 64 and IA-32 Architectures Software Developer's Manuals Vol 2B)
所以当你输入:
ret 0004
你告诉CPU在call
之后立即返回指令,并从堆栈中弹出4个字节。如果你在调用之前将 4个字节压入堆栈,那就太棒了。
push eax
call dword ptr[123]
请注意,这与返回值无关。实际上,Assembly中的过程无法指定值是 return 值。这都是按惯例完成的。我所知道的大多数编译器都会使用EAX
来保存返回值,但这只是因为调用函数会在那里得到结果。
所以你的主叫代码是:
call dword ptr [123]
mov dword ptr [result], eax
并且返回值4的函数将是:
mov eax, 4
ret
答案 1 :(得分:2)
这完全取决于所使用的calling convention。我不会在这里重复维基百科的文章,只需阅读定义。
例如,在C calling convention中,返回值将在EAX / AX / AL中。你的单指令没有一个:它是一个void函数,占用大约4个字节的参数(可能是一个int),什么都不做。因为被调用者有责任在这个调用约定中清理堆栈,忽略这样做并用'mov ax'替换调用不起作用。
此外,我怀疑您在阅读16位文档时可能正在修补32位程序集。这不是一个大问题,但你应该意识到这些差异。
答案 2 :(得分:1)
// possibly there are arguments pushed here
...
call dword ptr[123] // push next OP code offset in the stack and jump to procedure
// procedure
...
ret 0004 // pop offset, set EIP to that offset and decrease ESP by 4
如果我们在调用过程之前在堆栈中推送了参数,那么我们另外减少ESP。
如果存在推送参数,则程序崩溃,因为您没有弹出它们。当前过程的返回偏移量将是错误的,因为它将从其中一个推送的参数中获取一个值作为偏移量。
答案 3 :(得分:-1)
我认为返回值不存储在寄存器AX
中