【问题标题】:How to find the starting value in a for loop in assembly?如何在汇编的for循环中找到起始值?
【发布时间】:2015-06-24 21:07:28
【问题描述】:

当我将下面的汇编代码转换为 C 时,我无法理解它的作用。我知道这是一个循环,但我不知道从哪里开始转换它。

我有点理解输入必须是 6 个数字,并且在循环内它将添加 5 并进行比较。

我主要纠结于我们如何知道起始值?

   0x0000000000400f15 <+9>:     callq  0x4016e5 <read_six_numbers>
   0x0000000000400f1a <+14>:    lea    0x4(%rsp),%rbx
   0x0000000000400f1f <+19>:    lea    0x18(%rsp),%rbp
   0x0000000000400f24 <+24>:    mov    -0x4(%rbx),%eax
   0x0000000000400f27 <+27>:    add    $0x5,%eax
   0x0000000000400f2a <+30>:    cmp    %eax,(%rbx)
   0x0000000000400f2c <+32>:    je     0x400f33 <phase_2+39>
   0x0000000000400f2e <+34>:    callq  0x4016c3 <explode_bomb>
   0x0000000000400f33 <+39>:    add    $0x4,%rbx
   0x0000000000400f37 <+43>:    cmp    %rbp,%rbx
   0x0000000000400f3a <+46>:    jne    0x400f24 <phase_2+24>

【问题讨论】:

  • 请展示一些这样做的尝试。你试过像boomerang这样的反编译器吗?
  • 我已经编辑了您的问题以使其更清楚,请确保我没有改变您的意图。

标签: c assembly converter


【解决方案1】:

函数read_six_numbers 接收数组的地址,用于存储寄存器%rsi 中的数字。 %rsi 设置为指向堆栈底部的某个位置 (%rsp),其中一些空间是用 sub $0x28,%rsp 分配的。 0x400f24 处的循环使用寄存器%rbx 作为指向数组的指针,从开头开始。它检查前一个值 + 5 是否等于当前值。如果不是,它会调用explode_bomb(),不带任何参数。循环迭代 5 次,直到指针指向数组的末尾。

【讨论】:

    【解决方案2】:

    这里有一些您的问题中未指定的事项需要考虑(ABI、处理器架构、可执行文件格式等)。并非所有这些都是回答您的问题所必需的,但理解这一点可能会提高您对如何在各种可执行上下文中调用函数、方法或过程的总体理解。

    ABI

    特别是,不同的 CPU 架构、操作系统,甚至可执行的二进制格式可能具有不同的签名来处理程序输入。因为很明显您使用的是 AMD64 架构 CPU,所以您可能会发现 this wikipedia page 很有用。特别是,您似乎正在使用基于您的 sn-p 中的某些上下文的“System V x86-64 ABI”。 (稍后我们将对您的 sn-p 进行全面分析。)

    堆栈

    C 编程语言确实有任何堆栈的概念,因此尽管这与您的 sn-p 相关,但它不是 C 程序的要求,并且您的程序的可移植版本可能不会使用堆栈。事实上,虽然介绍性编译器课程似乎仍然倾向于使用堆栈在调用帧之间传递状态,但堆栈通常不用于 AMD64 上的 SysV ABI。

    (在 x86 上执行此操作更为常见,因为 32 位架构受寄存器限制。在此类架构上使用寄存器传递状态的开销可能会更高,因为寄存器可能需要被复制到堆栈中以便它们可以被重用,因为很可能额外的函数调用需要它们保留。)

    你的片段

    SysV ABI 按顺序特别使用%rdi%rsi%rdx%rcx%r8%r9%xmm0-7

    0x0000000000400f0c <+0>:     push   %rbp
    0x0000000000400f0d <+1>:     push   %rbx
    

    这通过将代表堆栈帧的寄存器推到堆栈顶部来保留调用者的堆栈帧。 %rbp%rbx 是“被调用者保存”寄存器,这意味着被调用的函数必须保留它们的值,因为调用者需要它们的值来保持其状态。

    0x0000000000400f0e <+2>:     sub    $0x28,%rsp
    

    这会在堆栈上分配 40 字节的空间。为什么是 40 字节?我们已经将 16 个字节压入堆栈,保留 %rbp%rbx。对于read_six_numbers,我们需要额外的 24 字节作为暂存空间,因此 16 + 24 == 40。

    0x0000000000400f12 <+6>:     mov    %rsp,%rsi
    

    这会将堆栈的基地址移动到%rsi。现在,因为我假设 SysV ABI,这意味着地址实际上是我们将要调用的函数的 second 参数。这个空间的内容是未定义的,很可能是随机值。这是read_six_numbers 使用的暂存空间。

    0x0000000000400f15 <+9>:     callq  0x4016e5 <read_six_numbers>
    

    这会调用函数read_six_numbers。由于我们的暂存空间是第二个参数(根据 SysV ABI),这意味着我们的调用函数在 %rdi 中有一个值,它未经修改就被传递给 read_six_numbers。如果我不得不猜测,我会说这个值回答了你的问题,所以我们需要查看这个 phase_2 函数的调用者以获得进一步的了解。

    0x0000000000400f1a <+14>:    lea    0x4(%rsp),%rbx
    

    read_six_numbers 读取 6 个 32 位数字,总共 24 个字节。起始编号为0x0(%rsp)lea 为我们提供了特定值的地址。因此,这给了我们一个指向数组中第二个值的指针,并将其放入%rbx

    0x0000000000400f1f <+19>:    lea    0x18(%rsp),%rbp
    

    数组的第一个值在0x0(%rsp),第6个在0x14(%rsp)0x18(%rbp) 是我们数组末尾的第一个大小对齐地址。

    0x0000000000400f24 <+24>:    mov    -0x4(%rbx),%eax
    0x0000000000400f27 <+27>:    add    $0x5,%eax
    0x0000000000400f2a <+30>:    cmp    %eax,(%rbx)
    0x0000000000400f2c <+32>:    je     0x400f33 <phase_2+39>
    0x0000000000400f2e <+34>:    callq  0x4016c3 <explode_bomb>
    0x0000000000400f33 <+39>:    add    $0x4,%rbx
    0x0000000000400f37 <+43>:    cmp    %rbp,%rbx
    0x0000000000400f3a <+46>:    jne    0x400f24 <phase_2+24>
    

    用户 chqrlie 很好地解释了这个循环。如果前一个 (-0x4(%rbx)) 和 current + 5 相等,我们继续循环。否则我们调用explode_bomb。我要补充一点,虽然 chqrlie 说它不需要参数,但不能保证它不需要。我们实际上还没有接触过%rdi%rsi,所以它仍然可以使用上下文。要断言explode_bomb 不带参数,我们必须查看它的反汇编;这个上下文并不能证明它不需要参数。

    但是,正在比较的实际值在此上下文中未定义。我们只是在这里循环内存。

    0x0000000000400f3c <+48>:    add    $0x28,%rsp
    0x0000000000400f40 <+52>:    pop    %rbx
    0x0000000000400f41 <+53>:    pop    %rbp
    

    这会恢复调用者上下文(请记住,我们在开始时保存了调用者堆栈的状态)并且...

    0x0000000000400f42 <+54>:    retq
    

    返回调用者的下一个IP。

    也许这里有一些你不知道的东西。否则,只是一个冗长的解释来告诉你 chqrlie 已经做了什么:循环的起始值是 read_six_numbers 填充的数组基数之后的 4 个字节。

    【讨论】:

    • 还是谢谢你。但是我选择的答案足够清楚,让我明白了这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-20
    • 1970-01-01
    • 2020-02-26
    • 1970-01-01
    • 1970-01-01
    • 2011-02-25
    相关资源
    最近更新 更多