为什么堆栈的顶部有我们的输入?

发布于 2025-02-08 01:05:32 字数 6612 浏览 3 评论 0原文

对于上下文,这是汇编代码和所需的知识。然后,我将分解组件,看看我的理解是否正确。

我的主要问题是:为什么堆栈的顶部具有我们的输入?

这是main哪个调用phase_2

   0x00000000000014b9 <+112>:   call   0x1200 <puts@plt>
   0x00000000000014be <+117>:   call   0x1c56 <read_line>
   0x00000000000014c3 <+122>:   mov    rdi,rax
   0x00000000000014c6 <+125>:   call   0x15cb <phase_2>
   0x00000000000014cb <+130>:   call   0x1d9e <phase_defused>

这是phase_2是从main调用的。 phase_2函数调用read_six_numbers

; phase_2
   0x00000000000015cb <+0>: endbr64 
   0x00000000000015cf <+4>: push   rbp
   0x00000000000015d0 <+5>: push   rbx
   0x00000000000015d1 <+6>: sub    rsp,0x28
   0x00000000000015d5 <+10>:    mov    rax,QWORD PTR fs:0x28
   0x00000000000015de <+19>:    mov    QWORD PTR [rsp+0x18],rax
   0x00000000000015e3 <+24>:    xor    eax,eax
   0x00000000000015e5 <+26>:    mov    rsi,rsp
   0x00000000000015e8 <+29>:    call   0x1c11 <read_six_numbers>
   0x00000000000015ed <+34>:    cmp    DWORD PTR [rsp],0x1
   0x00000000000015f1 <+38>:    jne    0x15fd <phase_2+50>
   0x00000000000015f3 <+40>:    mov    rbx,rsp
   0x00000000000015f6 <+43>:    lea    rbp,[rsp+0x14]
   0x00000000000015fb <+48>:    jmp    0x1612 <phase_2+71>
   0x00000000000015fd <+50>:    call   0x1be5 <explode_bomb>
   0x0000000000001602 <+55>:    jmp    0x15f3 <phase_2+40>
   0x0000000000001604 <+57>:    call   0x1be5 <explode_bomb>
   0x0000000000001609 <+62>:    add    rbx,0x4
   0x000000000000160d <+66>:    cmp    rbx,rbp
   0x0000000000001610 <+69>:    je     0x161d <phase_2+82>
   0x0000000000001612 <+71>:    mov    eax,DWORD PTR [rbx]
   0x0000000000001614 <+73>:    add    eax,eax
   0x0000000000001616 <+75>:    cmp    DWORD PTR [rbx+0x4],eax
   0x0000000000001619 <+78>:    je     0x1609 <phase_2+62>
   0x000000000000161b <+80>:    jmp    0x1604 <phase_2+57>
   0x000000000000161d <+82>:    mov    rax,QWORD PTR [rsp+0x18]
   0x0000000000001622 <+87>:    xor    rax,QWORD PTR fs:0x28
   0x000000000000162b <+96>:    jne    0x1634 <phase_2+105>
   0x000000000000162d <+98>:    add    rsp,0x28
   0x0000000000001631 <+102>:   pop    rbx
   0x0000000000001632 <+103>:   pop    rbp
   0x0000000000001633 <+104>:   ret    
   0x0000000000001634 <+105>:   call   0x1220 <__stack_chk_fail@plt>

这是read_six_numbers,在sthep_2中称为。

; read_six_numbers
   0x0000000000001c11 <+0>: endbr64 
   0x0000000000001c15 <+4>: sub    rsp,0x8
   0x0000000000001c19 <+8>: mov    rdx,rsi
   0x0000000000001c1c <+11>:    lea    rcx,[rsi+0x4]
   0x0000000000001c20 <+15>:    lea    rax,[rsi+0x14]
   0x0000000000001c24 <+19>:    push   rax
   0x0000000000001c25 <+20>:    lea    rax,[rsi+0x10]
   0x0000000000001c29 <+24>:    push   rax
   0x0000000000001c2a <+25>:    lea    r9,[rsi+0xc]
   0x0000000000001c2e <+29>:    lea    r8,[rsi+0x8]
   0x0000000000001c32 <+33>:    lea    rsi,[rip+0x16ca]        # 0x3303
   0x0000000000001c39 <+40>:    mov    eax,0x0
   0x0000000000001c3e <+45>:    call   0x12c0 <__isoc99_sscanf@plt>
   0x0000000000001c43 <+50>:    add    rsp,0x10
   0x0000000000001c47 <+54>:    cmp    eax,0x5
   0x0000000000001c4a <+57>:    jle    0x1c51 <read_six_numbers+64>
   0x0000000000001c4c <+59>:    add    rsp,0x8
   0x0000000000001c50 <+63>:    ret    
   0x0000000000001c51 <+64>:    call   0x1be5 <explode_bomb>

这是我对phase_2的理解:

   0x00000000000015cb <+0>:     endbr64 
   0x00000000000015cf <+4>:     push   rbp
   0x00000000000015d0 <+5>:     push   rbx
   0x00000000000015d1 <+6>:     sub    rsp,0x28

上面是函数序言。 我们保存以前的基础指针。 我们还拥有Callee保存的寄存器rbx - 我们正在推动保存rbx。 请注意pop rbx最后,我们还原RBX的值,因为我们在功能中覆盖rbxRBX是系统v Callee保存的寄存器 如果Callee希望使用寄存器rbxrsprbpr12 - r15代码>,它必须在将控件返回到呼叫者之前还原其原始值。

   0x00000000000015d5 <+10>:    mov    rax,QWORD PTR fs:0x28

以上是堆栈金丝雀。如果修改后,程序结束,

   0x00000000000015de <+19>:    mov    QWORD PTR [rsp+0x18],rax

我们将返回值移动并将其放入本地var中。 上一个值是read_line的返回值。

   0x00000000000015e3 <+24>:    xor    eax,eax

然后,我们清除eax。 我们清除rax,因为清除值还取消了rax的最高值。

   0x00000000000015e5 <+26>:    mov    rsi,rsp

为什么要移动堆栈顶部的地址,即rsp并将其放入rsi中? 我猜堆栈的顶部是我们6位数字的开始,但是 我们的6位数字是如何从堆栈开始的?

   0x00000000000015ed <+34>:    cmp    DWORD PTR [rsp],0x1

我们验证rsp点的值是0x1

   0x00000000000015f1 <+38>:    jne    0x15fd <phase_2+50>

如果没有,我们结束功能。

   0x00000000000015f3 <+40>:    mov    rbx,rsp

我们将堆栈顶部地址的rsp的内容移至rbx中。

有什么原因吗?

   0x00000000000015f6 <+43>:    lea    rbp,[rsp+0x14]

我们将本地变量移至rbp中。

为什么这样做?这个本地变量从未初始化?我是否将随机变量移动到rbp中,为什么RBP

与我们移动RSP + 0x18时有关。 它更大4个字节,所以我们要访问数组 + 1吗?

   0x0000000000001609 <+62>:    add    rbx,0x4

循环的开始。 我们通过一个整数将数组/字符串递增。

   0x0000000000001612 <+71>:    mov    eax,DWORD PTR [rbx

早些时候,我们将堆栈的顶部移至rbx中。 我们解除了指向的内容。 现在,我们将其放入eax中。

   0x0000000000001614 <+73>:    add    eax,eax

我们加倍eax 中的内容是什么,

   0x0000000000001616 <+75>:    cmp    DWORD PTR [rbx+0x4],eax
   0x0000000000001619 <+78>:    je     0x1609 <phase_2+62>

为什么我们要比较我认为的array [i + 1],而不仅仅是array [i]什么 rbx,为什么它保留了我们要比较输入的值?

,其余的就是功能结语,并且检查堆栈金丝雀。

For context, here is the assembly code and the required knowledge. I will then break down the assembly to see if my understanding is correct.

My main question is: Why is that the top of stack has our input?

Here is main which calls phase_2

   0x00000000000014b9 <+112>:   call   0x1200 <puts@plt>
   0x00000000000014be <+117>:   call   0x1c56 <read_line>
   0x00000000000014c3 <+122>:   mov    rdi,rax
   0x00000000000014c6 <+125>:   call   0x15cb <phase_2>
   0x00000000000014cb <+130>:   call   0x1d9e <phase_defused>

Here is the phase_2 which is called from main. The phase_2 function calls read_six_numbers.

; phase_2
   0x00000000000015cb <+0>: endbr64 
   0x00000000000015cf <+4>: push   rbp
   0x00000000000015d0 <+5>: push   rbx
   0x00000000000015d1 <+6>: sub    rsp,0x28
   0x00000000000015d5 <+10>:    mov    rax,QWORD PTR fs:0x28
   0x00000000000015de <+19>:    mov    QWORD PTR [rsp+0x18],rax
   0x00000000000015e3 <+24>:    xor    eax,eax
   0x00000000000015e5 <+26>:    mov    rsi,rsp
   0x00000000000015e8 <+29>:    call   0x1c11 <read_six_numbers>
   0x00000000000015ed <+34>:    cmp    DWORD PTR [rsp],0x1
   0x00000000000015f1 <+38>:    jne    0x15fd <phase_2+50>
   0x00000000000015f3 <+40>:    mov    rbx,rsp
   0x00000000000015f6 <+43>:    lea    rbp,[rsp+0x14]
   0x00000000000015fb <+48>:    jmp    0x1612 <phase_2+71>
   0x00000000000015fd <+50>:    call   0x1be5 <explode_bomb>
   0x0000000000001602 <+55>:    jmp    0x15f3 <phase_2+40>
   0x0000000000001604 <+57>:    call   0x1be5 <explode_bomb>
   0x0000000000001609 <+62>:    add    rbx,0x4
   0x000000000000160d <+66>:    cmp    rbx,rbp
   0x0000000000001610 <+69>:    je     0x161d <phase_2+82>
   0x0000000000001612 <+71>:    mov    eax,DWORD PTR [rbx]
   0x0000000000001614 <+73>:    add    eax,eax
   0x0000000000001616 <+75>:    cmp    DWORD PTR [rbx+0x4],eax
   0x0000000000001619 <+78>:    je     0x1609 <phase_2+62>
   0x000000000000161b <+80>:    jmp    0x1604 <phase_2+57>
   0x000000000000161d <+82>:    mov    rax,QWORD PTR [rsp+0x18]
   0x0000000000001622 <+87>:    xor    rax,QWORD PTR fs:0x28
   0x000000000000162b <+96>:    jne    0x1634 <phase_2+105>
   0x000000000000162d <+98>:    add    rsp,0x28
   0x0000000000001631 <+102>:   pop    rbx
   0x0000000000001632 <+103>:   pop    rbp
   0x0000000000001633 <+104>:   ret    
   0x0000000000001634 <+105>:   call   0x1220 <__stack_chk_fail@plt>

Here is read_six_numbers which is called in phase_2.

; read_six_numbers
   0x0000000000001c11 <+0>: endbr64 
   0x0000000000001c15 <+4>: sub    rsp,0x8
   0x0000000000001c19 <+8>: mov    rdx,rsi
   0x0000000000001c1c <+11>:    lea    rcx,[rsi+0x4]
   0x0000000000001c20 <+15>:    lea    rax,[rsi+0x14]
   0x0000000000001c24 <+19>:    push   rax
   0x0000000000001c25 <+20>:    lea    rax,[rsi+0x10]
   0x0000000000001c29 <+24>:    push   rax
   0x0000000000001c2a <+25>:    lea    r9,[rsi+0xc]
   0x0000000000001c2e <+29>:    lea    r8,[rsi+0x8]
   0x0000000000001c32 <+33>:    lea    rsi,[rip+0x16ca]        # 0x3303
   0x0000000000001c39 <+40>:    mov    eax,0x0
   0x0000000000001c3e <+45>:    call   0x12c0 <__isoc99_sscanf@plt>
   0x0000000000001c43 <+50>:    add    rsp,0x10
   0x0000000000001c47 <+54>:    cmp    eax,0x5
   0x0000000000001c4a <+57>:    jle    0x1c51 <read_six_numbers+64>
   0x0000000000001c4c <+59>:    add    rsp,0x8
   0x0000000000001c50 <+63>:    ret    
   0x0000000000001c51 <+64>:    call   0x1be5 <explode_bomb>

Here is my understanding of that is happening in phase_2:

   0x00000000000015cb <+0>:     endbr64 
   0x00000000000015cf <+4>:     push   rbp
   0x00000000000015d0 <+5>:     push   rbx
   0x00000000000015d1 <+6>:     sub    rsp,0x28

Above is the function prologue.
We save the previous base pointer.
We also have the callee saved register rbx -- we are pushing to save rbx.
Note the pop rbx at the end, we restore the value of rbx because we overwrite rbx in the function.
rbx is a system V callee saved register
If the callee wishes to use registers RBX, RSP, RBP, and R12R15, it must restore their original values before returning control to the caller.

   0x00000000000015d5 <+10>:    mov    rax,QWORD PTR fs:0x28

The above is a stack canary. If modified, the program ends

   0x00000000000015de <+19>:    mov    QWORD PTR [rsp+0x18],rax

We move the return value and put it in a local var.
The previous value is the return value of read_line.

   0x00000000000015e3 <+24>:    xor    eax,eax

We then clear eax.
we clear rax because clearing the values also cancels out the top values of rax.

   0x00000000000015e5 <+26>:    mov    rsi,rsp

Why are moving the address at the top of the stack, i.e., rsp and placing it into rsi?
I'm guessing the top of stack is the beginning of our 6 digits, but
how did our 6 digits get to begin at the of the stack?

   0x00000000000015ed <+34>:    cmp    DWORD PTR [rsp],0x1

We verify that the value where rsp points is 0x1.

   0x00000000000015f1 <+38>:    jne    0x15fd <phase_2+50>

If not, we end the function.

   0x00000000000015f3 <+40>:    mov    rbx,rsp

We move the contents of rsp, the address of the top of the stack, into rbx.

Is there any reason for this?

   0x00000000000015f6 <+43>:    lea    rbp,[rsp+0x14]

We move a local variable into rbp.

Why is this done? This local variable was never initialized? Are me moving a random variable into rbp and why rbp?

Is it related to when we moved rsp + 0x18.
It is 4 bytes larger, so are we accessing an array + 1?

   0x0000000000001609 <+62>:    add    rbx,0x4

Beginning of the loop.
We increment the array/string by one integer.

   0x0000000000001612 <+71>:    mov    eax,DWORD PTR [rbx

Earlier we moved the top of the stack into rbx.
We dereference what was pointed.
We now put that into eax.

   0x0000000000001614 <+73>:    add    eax,eax

We double what is in eax

   0x0000000000001616 <+75>:    cmp    DWORD PTR [rbx+0x4],eax
   0x0000000000001619 <+78>:    je     0x1609 <phase_2+62>

Why are we comparing the what I assume to be array[i + 1] and not just array[i]?
What is rbx and why does it it hold the value we are comparing out input to?

And the rest is function epilogue and the checking the stack canary.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文