x86架构的64位汇编语言(通常称为x86-64或AMD64汇编)是x86体系的现代形态,自2003年AMD推出AMD64架构、2005年Intel引入EM64T后成为主流。相较于32位汇编,64位汇编在寄存器数量、寻址能力、调用约定、内存管理等方面进行了革命性扩展,为高性能计算、安全分析(如逆向工程、漏洞挖掘)和系统编程提供了更强大的底层支持。

本文章仅提供学习,切勿将其用于不法手段!

一、核心寄存器组(64位扩展)​

64位x86在32位寄存器基础上新增8个64位通用寄存器,并将所有寄存器扩展至64位,同时保留低32/16/8位的兼容访问。

1. 通用寄存器(64位)​

共16个64位通用寄存器,可分为“原始8个”和“新增8个”,支持灵活的64位、32位、16位、8位访问:

64位寄存器 低32位 低16位 低8位 高8位(直接访问) 主要用途
RAX EAX AX AL AH(AX高8位) 累加器(函数返回值、算术运算、系统调用号)
RBX EBX BX BL BH(BX高8位) 基址寄存器(常用作内存地址基址,Linux内核指向全局数据区)
RCX ECX CX CL CH(CX高8位) 计数寄存器(循环计数、字符串操作长度,System V调用传递第三个参数)
RDX EDX DX DL DH(DX高8位) 数据寄存器(乘法/除法辅助、I/O端口地址,System V调用传递第二个参数)
RSI ESI SI SIL - 源变址寄存器(字符串操作源地址、数组遍历)
RDI EDI DI DIL - 目的变址寄存器(字符串操作目的地址、数组写入)
RBP EBP BP BPL - 基址指针(函数栈帧基址,访问参数和局部变量)
RSP ESP SP SPL - 栈指针(指向栈顶,随PUSH/POP自动增减)
R8 R8D R8W R8B - 新增寄存器(System V调用传递第四个参数,临时存储)
R9 R9D R9W R9B - 新增寄存器(System V调用传递第五个参数,临时存储)
R10 R10D R10W R10B - 新增寄存器(临时存储,系统调用时保存RSP
R11 R11D R11W R11B - 新增寄存器(临时存储,syscall指令修改)
R12 R12D R12W R12B - 新增寄存器(被调用者保存寄存器,跨函数调用需保存)
R13 R13D R13W R13B - 新增寄存器(被调用者保存寄存器,跨函数调用需保存)
R14 R14D R14W R14B - 新增寄存器(被调用者保存寄存器,跨函数调用需保存)
R15 R15D R15W R15B - 新增寄存器(被调用者保存寄存器,跨函数调用需保存)
  • 关键扩展​:
    • 16个通用寄存器(vs 32位的8个)大幅减少内存访问次数,提升性能(尤其循环和复杂函数)。
    • 新增寄存器(R8-R15)在系统调用、参数传递、临时存储中发挥重要作用。
2. 段寄存器(64位模式下的弱化)​

64位保护模式(Long Mode)中,段寄存器作用进一步弱化,主要用于兼容32位程序:

  • CS(代码段):基址固定为0,限长=2^64(平坦模型),支持64位代码执行。
  • DS/ES/SS/FS/GS(数据段):基址可通过MSR(模型特定寄存器)设置(如Linux用GS存储线程本地存储TLS),但多数场景下程序直接通过64位偏移访问内存。
3. 状态寄存器(RFLAGS,64位)​

RFLAGS是32位EFLAGS的扩展,新增标志位,关键标志如下:

标志位 全称 含义
CF/OF/SF/ZF/AF/PF 同32位 进位、溢出、符号、零、辅助进位、奇偶标志(兼容32位运算)
IF 中断允许标志 控制外部中断响应(CLI/STI)
DF 方向标志 控制字符串操作方向(DF=0递增,DF=1递减)
AC 对齐检查标志 Ring 3启用内存对齐检查(未对齐访问触发异常)
IOPL I/O特权级 Ring 0-3的I/O权限(Ring 0可访问所有I/O端口)
RF 恢复标志 调试时忽略断点(单步执行自动置位)
VM 虚拟8086模式 64位模式下无效

二、64位模式(Long Mode)——核心运行环境

64位程序运行在64位模式​(Long Mode)下,是保护模式的扩展,支持64位地址空间、RIP相对寻址、新增指令等。

1. 核心特性
  • 64位地址空间​:线性地址=64位(理论支持16EB内存,实际受操作系统限制,如Windows 10家庭版48位地址,Linux默认48位)。
  • RIP相对寻址​:指令中直接使用相对RIP(指令指针)的偏移访问数据,支持位置无关代码(PIC),是动态链接库(DLL/so)和系统调用的基础。
    • 示例:MOV RAX, [RIP + 0x20](访问RIP+0x20处的内存数据)。
  • 平坦内存模型​:代码/数据段基址=0,线性地址=64位偏移,简化内存访问。
2. 系统调用与特权级切换

64位下通过专用指令实现用户态(Ring 3)到内核态(Ring 0)的切换,替代32位的int 0x80

  • ​**syscall(Linux)​**​:快速系统调用,通过MSR_LSTAR寄存器指定内核入口。
  • ​**sysenter(Windows/Linux兼容)​**​:早期64位系统调用指令,现逐渐被syscall取代。
  • 参数传递​:系统调用号存RAX,参数按调用约定存寄存器(如System V通过RCX/RDX/R8/R9传递前4个参数)。

三、核心指令集扩展

64位汇编在32位基础上新增指令,优化寄存器访问、内存操作和SIMD性能。

1. 数据传输指令
  • MOVABS​:加载64位绝对地址(32位MOV EAX, addr仅支持32位偏移,MOVABS RAX, addr支持64位绝对地址)。
    • 示例:MOVABS RAX, 0x123456789ABCDEF0(RAX ← 64位绝对地址)。
  • 64位MOV​:支持64位寄存器/内存与寄存器/立即数传输(如MOV RAX, RBXMOV [RDI], RAX)。
  • PUSHQ/POPQ​:64位栈操作(PUSHQ RAX等价于SUB RSP, 8; MOV [RSP], RAXPOPQ RBX反之)。
2. 算术与逻辑指令
  • 64位运算​:ADD RAX, RBX(RAX += RBX,结果存RAX,进位到CF);SUB RCX, RDX(RCX -= RDX)。
  • 乘法/除法​:
    • MUL r/m64:无符号乘法,RDX:RAX = RAX × r/m64(结果128位,RDX存高64位)。
    • IMUL r64, r/m64:有符号乘法,r64 = r64 × r/m64(支持64位结果)。
  • 移位与旋转​:支持64位操作数,如SHL RAX, 3(RAX左移3位,CF=移出的最高位);ROL RDX, CL(RDX循环左移CL指定的位数)。
3. 控制流指令
  • JMP​:无条件跳转(修改RIP或CS:RIP)。
    • 近跳转(64位偏移):JMP near label(跳转范围相对于当前RIP±2GB)。
    • 远跳转(段间跳转):JMP far ptr label(修改CS和RIP,跳转到其他段)。
  • 条件跳转​:基于RFLAGS标志位(新增部分64位指令依赖的标志):
    指令 含义 依赖标志
    JE/JZ 等于/零跳转 ZF=1
    JNE/JNZ 不等/非零跳转 ZF=0
    JG/JNLE 大于跳转(有符号) ZF=0且SF=OF
    JO 溢出跳转 OF=1
    JC 进位跳转 CF=1
4. RIP相对寻址指令

64位特有,指令中直接使用[RIP + offset]访问数据,地址=当前RIP + offset,支持位置无关代码:

  • 示例:LEA RAX, [RIP + 0x10](RAX ← 下一条指令地址+0x10);CALL [RIP + 0x20](调用动态链接库函数)。

四、函数调用约定与栈平衡

64位调用约定大幅简化参数传递(通过寄存器而非栈),不同操作系统有差异,主流为System V AMD64 ABI​(Linux/macOS)和Windows x64调用约定

1. System V AMD64 ABI(Linux/macOS默认)​
  • 参数传递​:前6个整型/指针参数按顺序通过RCXRDXR8R9R10R11传递;浮点参数通过XMM0-XMM7传递。
  • 栈平衡责任​:​调用者(Caller)负责清理栈​(被调用者Callee不修改RSP)。
  • 寄存器保存​:Callee需保存RBXRBPR12-R15(“被调用者保存寄存器”),调用者保存其他寄存器(如RAXRCXRDX等)。
  • 栈对齐​:调用时RSP需16字节对齐(call指令压入返回地址后RSP-8,对齐到16字节边界)。

示例​:func(a,b,c,d,e,f)的参数传递:

; 调用者代码
MOV RCX, a        ; 第一个参数→RCX
MOV RDX, b        ; 第二个参数→RDX
MOV R8, c         ; 第三个参数→R8
MOV R9, d         ; 第四个参数→R9
MOV [rsp + 8], e  ; 第五个参数(栈传递,因RSP对齐需预留8字节)
MOV [rsp + 16], f ; 第六个参数(栈传递)
CALL func         ; 调用者清理栈(若有栈参数)
2. Windows x64调用约定
  • 参数传递​:前4个整型/指针参数通过RCXRDXR8R9传递;浮点参数通过XMM0-XMM3传递。
  • 栈平衡责任​:​被调用者(Callee)负责清理栈​(返回前通过RET n清理参数)。
  • 寄存器保存​:Callee需保存RBXRBPRDIRSIR12-R15XMM6-XMM15
  • 栈对齐​:调用时RSP需16字节对齐(call指令压入返回地址后RSP-8,对齐到16字节边界)。

示例​:Windows API MessageBoxA调用:

; 调用者代码(无需清理栈)
MOV RCX, title    ; 参数1→RCX
MOV RDX, text     ; 参数2→RDX
MOV R8, MB_OK     ; 参数3→R8
XOR R9, R9        ; 参数4→R9(NULL)
CALL MessageBoxA  ; 被调用者内部RET n清理参数
3. 函数序言与尾声
  • 序言(Prologue)​​:保存上下文,建立栈帧。
    func PROC
      PUSH RBP        ; 保存调用者RBP(RSP-=8)
      MOV RBP, RSP    ; RBP指向当前栈帧基址
      PUSH RBX        ; 保存被调用者保存寄存器(RBX)
      PUSH R12        ; 保存R12
      SUB RSP, 16     ; 分配16字节栈空间(局部变量,16字节对齐)
  • 尾声(Epilogue)​​:恢复上下文,返回。
      MOV RSP, RBP    ; 释放局部变量空间(RSP=EBP)
      POP R12         ; 恢复R12(RSP+=8)
      POP RBX         ; 恢复RBX(RSP+=8)
      POP RBP         ; 恢复调用者RBP(RSP+=8)
      RET             ; 弹出返回地址,RSP+=8(返回到CALL下一条指令)
    func ENDP

五、内存管理与分页机制

64位模式下,​分页机制扩展至4级页表,支持更大的地址空间和更灵活的内存保护:

  • 4级页表​:线性地址分为PML4索引(9位)、PDP索引(9位)、PD索引(9位)、PT索引(9位)、页内偏移(12位),共48位。
  • 大页支持​:通过页表项标志启用2MB/1GB大页,减少页表项数量,提升TLB命中率。

六、内存对齐(Memory Alignment)​

64位下以16字节对齐为主,尤其针对SSE/AVX指令处理的数据,提升访问效率并避免硬件错误。

1. 栈与全局数据的对齐
  • 栈上变量​:函数内定义的16字节数据(如__m128 SSE寄存器变量)需16字节对齐,地址=RBP-偏移(RBP对齐,偏移为16的倍数)。
  • 全局变量​:编译器通过ALIGN 16伪指令确保结构体、数组等对齐到16字节边界。

示例​:栈上16字节变量的对齐:

func PROC
  PUSH RBP
  MOV RBP, RSP
  SUB RSP, 16     ; 分配16字节(对齐到16字节边界)
  MOVAPS [RBP-16], XMM0 ; SSE寄存器存入16字节对齐内存
  MOV RSP, RBP
  POP RBP
  RET
func ENDP
2. 结构体的16字节对齐

结构体成员按最大成员大小对齐,编译器插入填充字节:

// C结构体(对应汇编)
struct Example {
  char a;      // 1字节,地址0x0000
  // 填充15字节(使下一个double对齐到8字节,整个结构体对齐到16字节)
  double b;    // 8字节,地址0x0010
  __m128 c;    // 16字节,地址0x0018(16字节对齐)
};             // 总大小=1+15+8+16=40字节(16字节对齐)

七、应用场景与学习意义

  1. 逆向工程​:分析64位恶意软件(如勒索病毒、APT工具)、破解软件保护(如VMProtect 64位)、理解二进制漏洞(如栈溢出、堆溢出在64位下的利用)。
  2. 漏洞挖掘​:掌握64位程序的栈溢出(如ret2libc、ROP链构造)、堆溢出(如fastbin attack)、UAF等漏洞利用技术。
  3. 系统编程​:开发64位操作系统内核(如Linux驱动、Windows内核模块)、高性能服务端程序(如Nginx/Redis 64位优化)。

总结​:64位x86汇编的核心是16个通用寄存器、RIP相对寻址、简化的参数传递(寄存器优先)、16字节栈对齐。掌握寄存器组、调用约定(System V/Windows)、栈帧管理和内存对齐,结合64位模式的内存管理和指令集扩展,即可深入分析64位程序的二进制行为,为信息安全领域的底层分析和高级漏洞利用奠定坚实基础。

注:本文仅用于教育目的,实际渗透测试必须获得合法授权。未经授权的黑客行为是违法的。

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐