我们将在逆向工程中进行的大部分工作将使用汇编语言。这种简单且有时乏味的语言可以揭示源代码中的大量信息。当我们无法查看或恢复恶意软件或其他软件的源代码时,我们可以使用反汇编器和调试器等工具来恢复软件的底层汇编器。当然,我们可以从那里破译软件试图做什么。
原文链接:https://www.hackers-arise.com/post/2017/02/27/Reverse-Engineering-Malware-Part-2-Assembler-Language-Basics
在本教程中,我将简单地列出最基本的汇编指令。我怀疑你们中的大多数人会在我们完成这项研究的过程中将其作为参考,因此请务必将此页面添加为书签,以便您可以轻松地回到它。
部件
让我们开始一些基本概念。希望这一切都为您复习,但如果没有,您需要在继续学习本课程之前了解这些基本概念。
位(bit)- 这是最小的数据。它可以是 0 或 1 或 Off 或 ON。
字节(Byte)- 一个字节是 8 位。它的等效十进制值范围为 0 到 255
字(Word)- 一个字是两个字节或 16 位
双字(Double Word)- 双字是两个字或 32 位
千字节(Kilobyte)- 千字节是 1024 (32 * 32) 字节
兆字节(Megabyte)- 兆字节是 1,048,578 字节 (1024 x 1024)。
寄存器
寄存器是计算机内存中存储数据的地方。在汇编程序中工作时,我们通常使用这些寄存器来移动和操作信息,因此您应该熟悉它们。
这些寄存器是;
EAX – 扩展累加器寄存器
EBX – 扩展基址寄存器
ECX – 扩展计数器寄存器
EDX – 扩展数据寄存器
ESI – 扩展源索引
EDI – 扩展目的地索引
EBP – 扩展基指针
ESP – 扩展堆栈指针
EIP – 扩展指令指针
标志(Flags)
标志是指示寄存器状态的单个位。现代 32 位 CPU 上的标志寄存器是 32 位长。有32个标志。在我们这里的研究中,我们只需要其中三个;(1) Z 标志、O 标志和 C 标志。
标志只能是 SET 或 NOT SET
Z-Flag
Z-flag(零标志)是破解最有用的标志。它用于大约 90% 的所有情况。当执行的最后一条指令结果为 0 时,可以通过多个操作码设置或清除它
O-Flag
大约 4% 的破解尝试使用 O 标志(溢出标志)。它在最后一次操作更改获得操作结果的寄存器的最高位时设置。
C-Flag
C-Flag(携带标志)用于大约 1% 的破解尝试。如果您向寄存器添加一个值,则它被设置为大于 FFFFFFFF 或者您减去一个值,从而使寄存器值小于零。
堆栈(Stack)
堆栈是内存的一部分,您可以在其中存储不同的东西以备后用。就像桌子上的一摞书,最后一个(后进或 LI)最先离开(后进先出)。
命令 PUSH 将寄存器的内容保存在堆栈中。命令 POP 从堆栈中获取寄存器最后保存的内容,然后将其放入特定寄存器中。
指令(Instructions)
汇编语言有少量的基本命令。这些包括;
ADD – ADD 指令将一个值添加到寄存器或内存地址。
句法:
1 |
ADD destination, source |
AND – AND 指令在两个值上使用逻辑和
句法:
1 |
AND destination, source |
CALL – CALL 指令将后面的指令的相对虚拟地址 (RVA) 压入堆栈并调用子程序或子过程
句法:
1 |
CALL something |
CDQ – 将 DWORD 转换为 QWORD( C将D转换为Q)
句法:
1 |
CDQ |
CMP – 比较
CMP 指令比较两个东西,如果比较结果合适,可以设置 C/O/Z 标志
句法:
1 |
CMP destination, source |
DEC – 递减
递减命令用于减少一个值
减少一个值(值= 值 -1 )
句法:
1 |
DEC something |
DIV – 除法
DIV 命令用于通过除数除 EAX。被除数始终为 EAX,结果存储在 EAX 中,模数存储在 EDX 中。
句法:
1 |
DIV divisor |
IDIV – 整数除法。有符号除法,可以设置 C/O/Z 标志
句法:
1 |
IDIV divisor |
IMUL – 整数乘法
句法:
1 2 3 4 5 |
IMUL value IMUL dest, value, value IMUL dest, value |
INC – 增量,与 DEC 指令相反(值 = 值 +1)
句法:
1 |
INC register |
INT – INT 命令产生对中断处理程序的调用
JUMPS – 有多种跳跃,但最常见和最重要的跳跃是;
LEA – 加载有效地址
句法:
1 2 3 4 5 6 7 8 9 |
JE - jump if equal JG - jump if greater JGE - jump if greater or equal JL - jump if lesser JLE - jump if less or equal JMP - jump always JNE - jump if not equal JNZ - jump if not zero JZ - jump if zero |
LEA 加载有效地址
句法:
1 |
LEA destination, source |
MOV – move 将值从源复制到目标
句法:
1 |
MOV destination, source |
MUL – 乘法与 IMUL 相同,但它乘以无符号数
句法:
1 |
MUL value |
NOP – 没有操作什么都不做
句法:
1 |
NOP |
OR – 逻辑包含 OR
句法:
1 |
MOV destination, source |
POP – POP 指令加载字节/字/双字指针 (ESP) 的值并将其放入目的地。
句法:
1 |
POP destination |
PUSH – PUSH 指令在堆栈上存储一个值,并将其减少被压入的操作数的大小,以便 ESP 指向被压入的值。
句法:
1 |
PUSH operand |
REP – 重复以下字符串指令。常见用途是 REPE(相等时重复)、REPZ(零时重复)、REPNE(不相等时重复)和 REPNZ(非零时重复)
语法:
1 |
REP ins |
其中 ins 是字符串操作
RET – 返回
句法:
1 |
RET digit |
SUB – 减法。与 ADD 命令相反。从目标的值中减去源的值并将结果存储在目标中
句法:
1 |
SUB destination, source |
TEST –它执行逻辑 AND 但不存储值
句法:
1 |
TEST operand1 , operand2 |
XOR – XOR 指令使用逻辑异或连接两个值
句法:
1 |
XOR destination, source |
逻辑运算
下表总结了当源或目标为 1 或 0 时显示 AND、OR、NOT 和 XOR 结果的逻辑运算。