逆向-汇编2

204 阅读2分钟

栈:先进后出,后进先出,栈的开口方向是往低地址的,arm64开始对栈的操作是16字节对齐 d61cbae6c37645f6a4539ab9d0d1ddd2_tplv-k3u1fbpfcp-watermark.png

sp & fp

  • sp在任何时候都会指向栈顶的位置
  • fp寄存器也称为x29寄存器,属于通用寄存器,但在某些时候可以用它来保存栈底的位置 x29(fp)寄存器指向栈低
sub    sp, sp, #0x40             ; 拉伸0x4064字节)空间
stp    x29, x30, [sp, #0x30]     ;x29\x30 寄存器入栈保护
add    x29, sp, #0x30            ; x29指向栈帧的底部
... 
ldp    x29, x30, [sp, #0x30]     ;恢复x29/x30 寄存器的值
add    sp, sp, #0x40             ; 栈平衡
ret

str & ldr

  • str:将数据从寄存器中读出来,存到内存中
  • ldr:将数据从内存中读出来,存到寄存器中
  • ldr 和 str的变种ldp 和 stp 可以操作两个寄存器 ac70ef268a7f461ba32c7125ad62c019_tplv-k3u1fbpfcp-watermark.png

c6deac45494a4b7a92fc974f4c1b1872_tplv-k3u1fbpfcp-watermark.jpg

bl & ret & x30(lr)

  • bl标号
    • 将下一条指令的地址放入lr(x30)寄存器
    • 转到标号处执行指令
  • ret
    • 默认使用lr(x30)寄存器的值,通过底层指令提示CPU此处作为下次指令的地址
  • x30(lr)
    • x30(lr)寄存器存放的是函数的返回地址,当ret指令执行时会寻找x30(lr)寄存器保存的地址的值 24f20cbdd76141c6b3cbd83392b0793c_tplv-k3u1fbpfcp-watermark.png 运行上面这段代码 9df060f1307c48c4a9e4a3af39fdfe26_tplv-k3u1fbpfcp-watermark.jpg 但是当出现函数嵌套时,lr只能保存最里面一层的返回的地址,所以要把每层函数的返回地址都保存在栈区 2068e359ca0d458fac8537a7d886a667_tplv-k3u1fbpfcp-watermark.png

函数

带有参数的函数

5b82a0254127469e92e185051d1d1372_tplv-k3u1fbpfcp-watermark.png 7ef9294a386642eb8499f90d1c09f931_tplv-k3u1fbpfcp-watermark.png arm64下函数的参数是放在x0~x7,或w0~w7,这几个寄存器里,如果超过8个函数,就会入栈

函数的参数超过8个

截屏2021-04-04 下午4.27.51.png codeble2的副本.jpg 也就是说当参数超过8个的时候,可能会把栈顶的位置用来当作参数的传递功能,因为在进入到test方法中可以看到,又去上一个函数的栈顶的位置去取参数。

函数的返回值

codeble277.jpg 在还没有进入getstr方法中时,就先把返回值的空间预留好,在getStr中ldr取出数据,str存入前面预留好的栈空间中,用之前函数的栈来保存返回值是因为用自己的栈的话有可能被释放,所以用其他函数的栈空间

局部变量

codeble2333.jpg3和4在前面已经存入寄存器中在funcA中存入栈中,2在funcA中才存入寄存器,随后也存入了栈中