5. 逆向分析技术(下)

一、前言

前面一章节主要介绍了逆向方面的基础知识点,并且介绍的都是32位的逆向。

但如今的程序大部分都已经过渡到了64位,所以只学习32位肯定是不够的。

而本章要介绍的便是64位逆向基础内容,当然,这是在前文基础之上的,已经讲解过的知识点不会再重复赘述。

二、寄存器

首先一个不同之处就是寄存器的不同,64位程序的寄存器与32位程序的寄存器相差很大。

前面我们一直看到过:EAXEBX等寄存器的名字,前面的E实际上就是扩展的意思(extend),在16位上,就是AXBX等寄存器名字,因为扩展到了32位,所以前面添加了一个E

而64位则是将这个E改为了R,并将其大小扩展到了64位,此时寄存器的名字就为RAXRBX等等

并且数量还增加了8个(R8-R15),并且还扩展了8个128位的XMM寄存器。

64位程序中,XMM寄存器经常被用来优化代码。

而64位程序是可以与32位寄存器兼容的:

  • RAX:占64位
  • EAX:使用RAX的低32位
  • AX:使用EAX的低32位
  • AL、AH:分别为AX的低8位与高八位

这就是一个寄存器的分布情况,就目前来说,我们一般用到的只有RAXEAX了。

比如当你使用x64的64位调试器时,就可以从右边的寄存器窗口看到所有可用的寄存器,非常之多:

image-20231023094214615

三、函数

对于函数的内容,上一章节已经介绍的非常详细了,所以这里只介绍一些存在的不同之处。

首先是传递参数问题。

注意:此时要将vs项目更改为x64模式,并在属性中关闭优化,具体步骤不再赘述。

由于64位程序的寄存器比32位要多很多,而寄存器的速度又比内存快,所以此时,它只有一种约定:寄存器快速调用约定

image-20231023095158611

此时我给函数传递了5个参数,但可以看到,前面4个参数都直接使用的寄存器来传递:ecxedxr8dr9d,只有第五个参数才使用的栈来传递。

传递方向仍然是从右向左,所以最下面的ecx是第一个参数。

之所以这里使用的ecx而不是rcx,是由于我们这里是int类型,只占32位,所以只需要rcx寄存器低32位就能存放了,如果为64位的long long,就是rcx了。

这是整数的情况,如果是小数:

image-20231023100200064

那么其用的是xmm0xmm1xmm2xmm3这四个寄存器,如果还有更多的参数,就使用栈传递。

总结如下:

image-20231023102329346

虽然此时使用的是寄存器传参,但这会导致可用寄存器数量减少,在某些复杂的计算中,可能会存在寄存器数量不够用的情况。

所以一般,调用者依旧会预留出相应的栈空间:

image-20231023100816306

比如我这里,虽然已经使用的是4个寄存器来传递参数,但它依旧预留出了28h大小的栈空间交给这个函数内部去使用,即40字节,5个8字节,即5个数据的大小(4个参数+1个call指令压入的地址值):

image-20231023101042410

如果进入函数后,你还会看到,它又把这四个参数复制到栈空间来使用,看起来有点多此一举了,但在没有优化的情况下,确实会出现这种情况。

并且还可以看到,即使传递参数的时候只是32位的int类型,但这里依旧用的每个参数占8位来传递。

如果你将这个生成的64位可执行文件放到IDA中,还可以直接找到入口点函数:

image-20231023102044997

也就是这个start函数,它就是启动函数,并在这个函数中调用了我们的main函数:

image-20231023102208774

它基本就把我们整个程序还原的差不多了,是不是非常的强大!

函数参数除了普通参数外,有时候还可能直接传递结构体:

image-20231023102842654

它是直接将结构体t当作了两个int给其赋值,也就是第一个红框中的内容,每个数据占4位,即dword

而传递参数时,它仅仅只传递了第一个参数的值进入,因此此时它是qword,即8位,它一次性把两个参数通过一个rcx寄存器给传递到函数内部去了!

作者:余识
全部文章:0
会员文章:0
总阅读量:0
c/c++pythonrustJavaScriptwindowslinux