进行任意软件的汇编补丁开发,需要对汇编语言有一定程度的了解,本人在补丁开发过程中,经常遇到各类问题,究其根本还是源于对汇编的一些规则了解不够,本文整理X64位汇编,为大家做参考。
1.32位指令区别
64位指令集是在32位指令集上的扩展和发展,EIP扩展为RIP,EFLAGS扩展为RFLAGS。浮点栈寄存器没有变化,多媒体寄存器多个8个寄存器。如下图所示:
64位模式下对通用寄存器的高低位访问,对于通用寄存器分别在8位,16位,32位和64位下其访问的名称,这里主要重点提一下R8-R15的寄存器,分别在尾部加入B,W,D来表示高低位,(B - byte //1字节,W - word //2字节,D - dword //4字节)如下图所示:
如果操作数是8位或者16位,其高位不修改,当使用32位时则会零扩展,也就是高4字节默认会被影响修改为0:
zero-extend for 32-bit operands //32位操作数使用了零扩展
not modified for 16-bit operands //16位操作不影响
not modified for 8-bit operands //8位操作不影响
2.64位指令文件执行
比如在VS2015 64位命令行环境,输入如下指令,进行编译和链接:
ml64 /c HelloWord64.asm
link /subsystem:windows /entry:start HelloWord64.obj
3.64位调用约定
使用四寄存器的fastcall调用约定,堆栈平衡由调用者处理,同时为了保证程序的正常运行,需要预留32(4*8)字节的空间,如果函数内部,其寄存器如果不够用了,那么一定会需要将寄存器中的参数保存到堆栈中。
RCX - 参数一
RDX - 参数二
R8 - 参数三
R9 - 参数四
剩余的参数依次入栈
返回值使用RAX寄存器
函数内部:
sub rsp,20h ;开辟空间用于保存参数
mov [rsp+0],rcx
mov [rsp+8],rdx
mov [rsp+10h],r8
mov [rsp+18h],r9
;.... 函数内部逻辑
add rsp,20h
相对于自己开辟空间保存寄存器,这里rcx保存的位置是[rsp+8],因为[rsp+0]的位置的返回地址。当有函数调用时,必须要提供这个预留空间(就算没有参数传递),否则不遵守这个规则,程序有空崩溃,因为函数调用者不提供这个预留空间,当函数内部有使用时很容易就蹦,没使用就又会一切正常。
4.当调用子函数时,堆栈指针RSP必须在16字节边界对齐上
64位CPU规定,把一个n字节的数据放到栈里面,栈地址必须模n,而现在16字节的话意味着需要模16,如何判断一个地址是模16呢,其实就看最低位是不是0就可以。每进入一个函数,Call指令自动抬了一个8位空间用于保存返回指令,再抬一个8位空间,RSP就是16位对齐了,如果不这么遵守,那么当遇到多媒体指令的时候就很容易蹦了。
5.子函数开始预留空间计算
以六参数为例,预留空间是0x20字节,额外参数空间0x10字节,临时变量参数空间0x10字节,如下所示:
预留空间 0x20字节
调用参数空间 0x10字节 //预留空间4个参数,如果某函数最多需要传递6个参数,那么还需开辟2个参数的空间
局部参数空间 0x10字节 //两个参数
-------------------------
0x40 字节 -对齐-> 0x48字节
参数五和参数六,这里不能使用push来压栈,因为这里使用push来压栈,那么其参数数值就会在预留空间的上面,而我们需要的是在预留空间的下面,所以此时只能自己手动进行mov。
6.总结
1.传递给函数的前四个参数放在RCX,RDX,R8和R9寄存器中
2.调用者的职责是在运行时分配至少32字节的预留空间,以便调用的函数可以选择在此区域保存寄存器参数
3.当调用子函数时,堆栈指针RSP必须在16字节边界对齐上
本文参考https://blog.csdn.net/Wang_1997/article/details/106718533
合理的脚本代码可以有效的提高工作效率,减少重复劳动。
欢迎光临知了软件开发网络平台,本公司定制开发各类软件,主要方向为桌面专业软件开发和插件定制开发,桌面软件主要包括文字图形识别类软件,信息管理类软件,3D打印类软件,视频类软件以及其它涉及专业的各类图形图像处理软件。插件包含AE插件,AI插件,PS插件,PDF插件,3DMAX插件以及Word,Excel等Office插件开发。详情请咨询,微信QQ:312117271,手机:18928899728,邮箱: anjingzhi_sea@163.com.
公司网址:http://www.zhiliaos.com