x64汇编语言与逆向工程基础指南(四)

简介: x64汇编语言与逆向工程基础指南(四)

1. 数组的存储与遍历

1.1 编写数组数据写入内存

  • 首先选中某部分地址编辑数据,这里以x64架构的 " long "类型数组为例,即每个元素占据8字节(qword)。

类比如图


  • 构造数组元素如下图:
  • 易知,数组结构如下表


Index Address Data
0 0x7FF68FE80050 0x11
1 0x7FF68FE80058 0x22
2 0x7FF68FE80060 0x33
3 0x7FF68FE80068 0x44
4 0x7FF68FE80070 0x55

1.2 汇编循环遍历数组元素

  mov rbx,0x7FF68FE80050               //将数组基地址(首地址)赋给 rbx寄存器保存
  mov rcx,0                           // 将 rcx寄存器作为index
loop_start:                             //循环体
  mov rax,qword ptr[rbx+rcx*8]        // 取出数组元素放入rax寄存器
  inc rcx                             //索引值自增
  cmp rcx,5                           //跳出循环判断
  jl loop_start                      //  如果 rcx < 5 ,则执行跳转

  • 执行结果如下:

3. Lea指令

  • lea(Load Effective Address)指令用于计算内存地址而不进行内存访问。它将地址表达式的结果加载到寄存器中。比如:
lea rax, [rbx + 4*rcx]
  • 这条指令计算 (rbx + 4*rcx) 的地址,并将结果存储到 rax 寄存器中。lea 可以用来进行地址计算、实现指针算术或调整寄存器值,但不会访问内存中的数据。

示例:

lea rdx, [rbx+rcx*8]
mov r9, qword ptr [rdx]
  • 执行前状态
  • 执行结果


lea 指令也可以作为计算器存储计算结果

如:仅使用 lea rax, [rbx+rdx * 3] 指令将会把 rbx+rdx*3 式子的结果存储到 rbx寄存器。

4. mul指令与imul指令

mulimul 指令用于执行乘法操作,但它们在处理有符号数和无符号数、以及结果存储方面有所不同。

4.1 mul 指令

mul 指令用于执行无符号乘法。它有不同的操作数形式和结果存储方式:

8位操作数

mul al  ; AL 寄存器中的值与操作数(AL)相乘,结果存储在 AX 中。
  • 操作数:AL(8位寄存器)
  • 结果:AX(16位寄存器)
  • AX = AL * 操作数
  • 如果结果超过16位,则 AX 中高字节的值将反映结果的高位部分。
  1. 16位操作数
mul ax  ; AX 寄存器中的值与操作数(AX)相乘,结果存储在 DX:AX 中。
  • 操作数:AX(16位寄存器)
  • 结果:DX:AX(32位结果)
  • DX:AX = AX * 操作数
  • 如果结果超过16位,则 DX 中的高16位包含结果的高位部分,AX 中的低16位包含结果的低位部分。
  1. 32位操作数
mul eax  ; EAX 寄存器中的值与操作数(EAX)相乘,结果存储在 EDX:EAX 中。
  • 操作数:EAX(32位寄存器)
  • 结果:EDX:EAX(64位结果)
  • EDX:EAX = EAX * 操作数
  • 如果结果超过32位,则 EDX 中的高32位包含结果的高位部分,EAX 中的低32位包含结果的低位部分。


mul 指令的特点

  • mul 指令始终是无符号乘法。
  • 结果存储在特定的寄存器对中,以便捕获可能的溢出。
  • 操作数通常是寄存器中的值,但也可以是内存中的值。


4.2 imul 指令

imul 指令用于执行有符号乘法。它有几种不同的操作数形式:

  1. 单操作数形式
imul ax  ; AX 寄存器中的值与操作数(AX)相乘,结果存储在 AX 中。
  • 操作数:AX(16位寄存器)
  • 结果:AX(16位寄存器)
  • AX = AX * 操作数
  • 如果结果溢出,结果会被截断,只保留低位部分。

2.双操作数形式

imul eax, ebx  ; EAX 寄存器中的值与 EBX 寄存器中的值相乘,结果存储在 EAX 中。
  • 操作数:EAX(32位寄存器)、EBX(32位寄存器)
  • 结果:EAX(32位寄存器)
  • EAX = EAX * EBX
  • 如果结果超出32位范围,则结果会被截断,只保留低32位部分。

3.三操作数形式

imul eax, ebx, 5  ; EAX 寄存器中的值与 EBX 寄存器中的值和 5 相乘,结果存储在 EAX 中。
  • 操作数:EAX(32位寄存器)、EBX(32位寄存器)、5(立即数)
  • 结果:EAX(32位寄存器)
  • EAX = EBX * 5
  • 这里,EBX 乘以 5,结果存储在 EAX 中。


imul 指令的特点

  • imul 指令是有符号乘法。
  • imul 的结果是有符号的,考虑了符号位。
  • 当使用多操作数形式时,imul 可以用来进行更复杂的乘法计算。


总结

  • mul 进行无符号乘法,结果存储在特定的寄存器对中(例如,DX:AXEDX:EAX)。
  • imul 进行有符号乘法,支持多种形式,包括单操作数、双操作数和三操作数形式。结果存储在目的寄存器中。
  • mulimul 都会根据操作数的大小选择适当的寄存器对来存储结果,以处理可能的溢出。

5. div指令

div 指令用于执行无符号除法操作。与 mulimul 指令不同,div 指令用于将一个数除以另一个数,并计算商和余数。它的操作方式根据操作数的大小和类型有所不同。

5.1 div 指令的基本原理

div 指令会根据被除数和除数的大小来选择不同的寄存器对,以存储商和余数。操作数是无符号的,所以结果也会是无符号的。

5.2 8 位除法

语法

div byte [memory]  ; 除数在内存中
div al             ; 除数在 AL 寄存器中
  • 被除数AX 寄存器
  • 除数:8 位操作数(如 AL 寄存器中的值或内存中的值)
  • AL 寄存器
  • 余数AH 寄存器

计算

AX / 除数 = 商 (AL)
AX % 除数 = 余数 (AH)
  • AX 寄存器的高字节 AH 和低字节 AL 共同存储被除数。
  • div 指令将 AL 除以操作数,结果存储在 AL 中,余数存储在 AH 中。

示例代码

mov al, 20      ; 被除数
mov bl, 4       ; 除数
div bl           ; AL = AL / BL, AH = AL % BL
; 结果:AL = 5, AH = 0

5.3 16 位除法

语法

div word [memory]  ; 除数在内存中
div ax             ; 除数在 AX 寄存器中
  • 被除数DX:AX 寄存器对
  • 除数:16 位操作数(如 AX 寄存器中的值或内存中的值)
  • AX 寄存器
  • 余数DX 寄存器

计算

DX:AX / 除数 = 商 (AX)
DX:AX % 除数 = 余数 (DX)
  • DX 寄存器存储被除数的高16位,AX 寄存器存储低16位。
  • div 指令将 DX:AX 除以操作数,结果存储在 AX 中,余数存储在 DX 中。

示例代码

mov ax, 1000    ; 被除数
mov bx, 25      ; 除数
div bx           ; DX:AX = AX / BX, DX = AX % BX
; 结果:AX = 40, DX = 0

5.3 32 位除法

语法

div dword [memory]  ; 除数在内存中
div eax             ; 除数在 EAX 寄存器中
  • 被除数EDX:EAX 寄存器对
  • 除数:32 位操作数(如 EAX 寄存器中的值或内存中的值)
  • EAX 寄存器
  • 余数EDX 寄存器

计算

EDX:EAX / 除数 = 商 (EAX)
EDX:EAX % 除数 = 余数 (EDX)
  • EDX 寄存器存储被除数的高32位,EAX 寄存器存储低32位。
  • div 指令将 EDX:EAX 除以操作数,结果存储在 EAX 中,余数存储在 EDX 中。

示例代码

mov eax, 100000 ; 被除数
mov ebx, 200    ; 除数
div ebx          ; EDX:EAX = EAX / EBX, EDX = EAX % EBX
; 结果:EAX = 500, EDX = 0

特点和要求

1.被除数和除数的大小:


div 指令要求被除数必须通过寄存器对来存储,以适应可能的结果范围(AX 对于8位操作数,DX:AX 对于16位操作数,EDX:EAX 对于32位操作数)。

除数的大小必须与被除数的大小相匹配。


2.除数不能为零:


如果除数为零,div 指令会引发除零异常,这是一个运行时错误。


3.结果存储:


商和余数分别存储在特定的寄存器中。如果结果超出寄存器的大小,div 指令会在商寄存器中存储结果的低位部分,而高位部分存储在余数寄存器中。


4.标志位:


div 指令不会影响标志寄存器的标志位(如 ZF、OF、CF、SF)

在使用 div 指令时,请确保被除数的大小和除数匹配,并且除数不能为零,以避免程序异常。

目录
相关文章
|
4月前
|
存储 前端开发 rax
x64汇编语言与逆向工程基础指南(三)
x64汇编语言与逆向工程基础指南(三)
77 1
|
4月前
|
存储 前端开发 rax
x64汇编语言与逆向工程基础指南(二)
x64汇编语言与逆向工程基础指南(二)
85 1
|
4月前
|
数据可视化 前端开发 rax
x64汇编语言与逆向工程实战指南(一)
x64汇编语言与逆向工程实战指南(一)
76 1
|
4月前
|
前端开发 rax 网络协议
x64汇编语言与逆向工程基础指南(一)
x64汇编语言与逆向工程基础指南(一)
282 0
|
7月前
软件体系结构 - 逆向工程
软件体系结构 - 逆向工程
62 1
|
7月前
|
安全 NoSQL Linux
《ARM汇编与逆向工程 蓝狐卷 基础知识》
《ARM汇编与逆向工程 蓝狐卷 基础知识》
111 0
|
7月前
|
存储 Ubuntu 编译器
C与汇编混合编程
C与汇编混合编程
114 0
|
Java 编译器 前端开发
烂尾工程: Java实现的汇编语言编译器
一个半拉子工程, 用Java实现的汇编语言编译器的介绍. 代码中使用中文命名. An unfinished project, an assembler implemented in Java, with naming in Chinese.
1171 0