【问题标题】:The meaning of RET 2 in assemblyRET 2在汇编中的含义
【发布时间】:2022-12-10 00:09:41
【问题描述】:

我对汇编很陌生,我不明白在过程结束时用 ret 语句写一个数字的确切含义。

像这样:

Function Proc
push ax cx
.
...body...
.
pop cx ax
ret 2 
Function endp

我知道这与堆栈指针在函数结束时应该返回到哪里有关?

它有什么作用?

【问题讨论】:

  • 汇编不是一种语言——每个处理器都有自己的语言。您应该询问特定的体系结构(似乎是 x86)。
  • 题外话:ret 是一个功能强大的小指令,长期以来一直是利用漏洞软件的中心:它根据调用堆栈的内存内容来指导程序的控制流。如果你控制了内存(strcpy,我在看着你),你就控制了程序执行流程。

标签: assembly x86


【解决方案1】:

是的,但是ret 2 还从堆栈中删除了 2 个字节的参数。据推测,您的函数被称为:

push some_parameter
call Function

此时,cdecl 函数 - 一个“调用者清理”函数(通常由 C 使用) - 将需要 add sp, 2 来“清理堆栈”,删除参数。这样的函数将以普通的ret 结尾。

stdcall 函数,这是你所拥有的,是一个“被调用者清理”函数(例如,由 Windows API 使用)不需要 add sp, 2 - 它已由 ret 2 完成。

如果您没有意识到,call 会将返回地址放在堆栈上(ret 将其弹出),因此您不能仅通过pop 获取函数中的参数。

【讨论】:

【解决方案2】:

假设我有一个程序可以添加两个单词并将总和保留在EAX 中。这些词是我想传递给堆栈上的过程的参数。 IE:

push word1
push word2
call addtwob

该过程类似于:

addtwob proc

push ebp
mov  ebp,esp
mov  eax, [ebp+6]    
add  eax, [ebp+8]
pop ebp
ret 4

Endp

[ebp+6][ebp+8] 在堆栈上地址word2word1ret 4 只是像往常一样返回,但随后将 4 添加到堆栈指针(esp),因此您不必在从调用返回后将 pop word2 pop word1 从堆栈中移除,因此它清理/平衡堆栈而无需需要弹出以前的推送。

【讨论】:

  • 因此 pop 清除已设置的 ebp,ret 清除返回地址并在 ret 清除额外的 4 个字节(即两个字)后设置“4”。这个对吗?
  • 32 位代码(使用 EBP 和 ESP)通常会为其 args 使用 DWORD(4 字节)堆栈槽。此外,原始调用将推送一个 4 字节的返回地址。所以mov eax, [ebp+8]/add eax, [ebp+12]
【解决方案3】:

正如亚历克斯所说,这意味着返回。 在 x86 汇编中,当编译器到达这一行时(例如,在子例程的末尾),它会弹出最后的从堆栈中取出值,这应该是返回地址,并将其分配给 IP 寄存器。您可以通过编写简单的汇编代码并使用 Turbo Debugger 对其进行编译来更好地理解这一点。如果您不熟悉汇编程序,则有一个 GUI。您可以找到 GUI here

当您在子例程中将值从堆栈弹出和推入堆栈时,您应该存储返回地址,因为在子例程结束时,您需要将它推回到堆栈中 return 行之前。

祝你好运!

【讨论】:

    【解决方案4】:

    它的意思是返回,就像高级语言中的return

    在大多数机器上,它会在进入子程序之前从堆栈中弹出程序计数器的先前值,并将其复制到 PC 的寄存器中。

    对于 x86,参数是堆栈上参数的数量。这仅适用于使用的约定是让子例程处理重置堆栈的情况。

    【讨论】:

    • 那么旁边的数字是什么意思呢?
    • 小更正:立即操作数指定了额外的数量字节返回时从堆栈中“弹出”。
    • @Michael 谢谢,这就是我的意思,但可能并不明显。
    【解决方案5】:

    对于 x86 32 位“ret 的可选数字(16 位或 32 位)参数指定从堆栈弹出返回地址后要释放的堆栈字节数或字数。通常,这些字节或字用作输入被调用过程的参数。“--https://docs.oracle.com/cd/E19455-01/806-3773/instructionset-67/index.html

    所以首先它弹出返回地址,然后可选数字指的是在弹出返回地址后递增堆栈的字节数。

    ret 4 在 32 位模式下总共是 esp+=8,包括弹出 4 字节返回地址和调用者压入的 4 字节。

    【讨论】:

    • 从堆栈中删除字节会增加 ESP,而不是 dec。所以 ret N 就像一个普通的 ret,然后是 add esp, N(但没有修改 FLAGS)。
    【解决方案6】:

    你似乎在问一个用x86_64的操作数接近返回. Intel instruction set reference manual中处理器遇到near RET时硬件遵循的算法如下;

    (* Near return *)
    IF instruction = near return
        THEN;
        IF OperandSize = 32
            THEN
            IF top 4 bytes of stack not within stack limits
                THEN #SS(0); FI; //throw protected mode exception
            EIP ← Pop(); 
            ELSE
            IF OperandSize = 64
                THEN
                IF top 8 bytes of stack not within stack limits
                    THEN #SS(0); FI; //throw protected mode exception
                RIP ← Pop();
                ELSE (* OperandSize = 16 *)
                IF top 2 bytes of stack not within stack limits
                    THEN #SS(0); FI; //throw protected mode exception
                tempEIP ← Pop();
                tempEIP ← tempEIP AND 0000FFFFH;
                IF tempEIP not within code segment limits
                    THEN #GP(0); FI; //throw protected mode exception
                EIP ← tempEIP;
            FI;
        FI;
        IF instruction has immediate operand
            THEN (* Release parameters from stack *)
            IF StackAddressSize = 32
                THEN
                ESP ← ESP + SRC;
                ELSE
                IF StackAddressSize = 64
                    THEN
                    RSP ← RSP + SRC;
                    ELSE (* StackAddressSize = 16 *)
                SP ← SP + SRC;
                FI;
            FI;
        FI;
    FI;
    
    • 根据此算法,每当遇到接近返回时,都会检查返回地址是否在 SS 限制内。如果返回地址有效,则根据操作数大小将栈顶弹出到 RIP 或 EIP。

    • 如果操作数大小为 16 位,则临时位置保存弹出的返回地址,该地址与值 0x0000FFFF 进行与运算,并在检查 CS 限制后加载到 EIP 中。

    • 正如您的问题所问,如果附近的 RET 指令操作码有一个操作数会发生什么。这取决于堆栈地址大小。根据该大小,RSP ESP 或 SP 增加操作数,并且在所有 near RET 指令完成后在硬件上执行。

    【讨论】:

    • pop cx 是一个非常明显的信号,表明 OP 正在查看 16 位代码。出于某种原因,人们会问很多关于 16 位代码的 Stack Overflow 问题。他们中的一些人正在制作玩具操作系统,出于某种疯狂的原因,他们中的大多数人正在学习使用 emu8086 教授 8086 的大学课程。
    猜你喜欢
    • 2013-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-20
    • 1970-01-01
    • 1970-01-01
    • 2015-09-04
    • 2013-10-18
    相关资源
    最近更新 更多