汇编语言学习 上

本文是介绍汇编语言的基本组成和基本齐全的指令,以及帮助理解这些的背景知识

包括寄存器汇编语言基本组成部分数据传送指令,寻址指令,加减法指令堆栈过程条件处理整数运算

帮助读者在很短的时间内对汇编语言有一个总体的认知,学会查看汇编代码和掌握学习编写汇编程序的能力,深入学习汇编语言的相关知识可以查阅《汇编语言 基于x86处理器》

下一篇文章汇编语言学习笔记 下

目录

汇编语言

汇编语言的特点

汇编语言的使用领域

基本微机设计

总线

时钟

寄存器

四类寄存器

32位机

64位机

补充

汇编语言基本组成部分

整数常量

整数常量表达式

浮点数常量

字符常量

字符串常量

保留字

标识符

伪指令

作用

定义段

指令

标号

指令助记符

注释

汇编语言内部数据类型

数据传送指令,寻址指令,加减法指令

数据传送指令

MOV指令

XCHG指令

偏移量操作数

NOP指令

加法指令和减法指令

INC指令

DEC指令

ADD指令

SUB指令

NEG指令

与数据有关的运算符和伪指令

OFFSET运算符

ALIGN伪指令

PTR运算符

TYPE运算符

LENGTHOF运算符

SIZEOF运算符

JMP和LOOP指令

JMP指令

LOOP指令

汇编语言程序范例

堆栈

堆栈数据结构

运行时堆栈

ESP寄存器

入栈操作

出栈操作

PUSH指令

POP指令

PUSHFD指令

POPFD指令

PUSHAD指令

POPAD指令

过程

定义主过程

其他过程

全局标号

CALL指令

RET指令

向过程传递寄存器参数

条件处理

布尔操作和比较指令

AND指令,OR指令,XOR指令,NOT指令

TEST指令

CMP指令

条件跳转

Jcond指令

基于相等性的跳转,基于无符号数的跳转指令,基于有符号数比较的跳转

基于相等性的跳转

基于无符号数的跳转指令

基于有符号数比较的跳转

整数运算

移位指令

算术移位和逻辑移位

SHL指令

SHR指令

SAL指令

SAR指令

ROL指令

ROR指令

RCL指令

RCR指令

SHLD指令

SHRD指令

乘法指令

MUL指令(32位模式)

MUL指令(64位模式)

IMUL指令(32位模式)

IMUL指令(64位模式)

DIV指令(32位模式)

DIV指令(64位模式)

IDIV指令指令


汇编语言

MASM是Microsoft Macro Assembler的缩写,Microsoft宏汇编器

汇编语言的特点

1.与机器语言很接近

2.需要了解计算机架构和操作系统,直接访问计算机硬件

3.学习汇编语言的基本语法,不需要深入了解操作系统和计算机架构,最好使用过一门编程语言进行编程,逻辑是相通的

4.汇编器将汇编语言转换成机器语言

5.链接器将汇编器生成的单个文件组合成一个可执行文件

6.汇编语言不可移植

汇编语言的使用领域

1.C或C++开发者需要了解汇编,很多编程错误在高级语言难以识别,需要深入到程序内部,理解内存,地址和指令是如何在底层工作的

2.编写嵌入式程序,例如显卡,声卡,打印机,硬盘驱动器

3.高级语言嵌入汇编,可以对程序进行优化

4.帮助理解计算机硬件,操作系统,应用程序之间的交互关系

5.进行逆向分析时候,分析反汇编器生成的汇编代码

汇编语言与机器语言,C++,Java,Python

汇编语言与机器语言

汇编语言和机器语言是一一对应的关系(one-to-one)

一句汇编语言对应一句机器语言

机器语言用数字编写,汇编语言使用助记符ADD,MOV,PUSH

汇编语言与C++,Java,Python

Java,Java,Python与汇编语言是一对多的关系(one-to-many)

高级语言是可以移植的,汇编语言不可移植

基本微机设计

CPU包含了有限数量的寄存器,一个高频时钟,一个控制单元CU,一个算数逻辑单元ALU

CPU通过主板上CPU插座的引脚和计算机其他部分相连

大部分引脚连接的是数据总线,控制总线和地址总线

总线

总线是一组并行线

分为四类总线:
数据类,I/O类,控制类,地址类

时钟

机器指令的时间单位是时钟周期

一个时钟周期是一个完整脉冲所需要的时间

一个机器指令最少需要一个时钟周期

内存

 

ROM   永久烧录在芯片上,不能擦除

EPROM  只能用强紫外线照射来擦除,可以重新编程

DRAM 最常用的一种电脑内存。它通常使用一个晶体管和一个电容器来代表一个比特。价格便宜,每毫秒需要刷新,避免丢失内容。

 

SRAM 静态随机存取存储器,所谓的“静态”,是指这种存储器只要保持通电,里面储存的数据就可以恒常保持,不需要刷新。CPU的cache就是SRAM构成的。

VRAM 影像随机接达记忆器,作为影像绘图卡、显卡所使用的DRAM,就是广义上说的显存。

CMOS RAM 在系统主板,保存系统设置信息。由电池供电。计算机关闭后,CMOS RAM中的内容仍然能保留。

虚拟内存

虚拟内存是计算机系统内存管理的一种技术,他使计算机认为拥有连续的可用的内存。通常有多个物理内存碎片,还有部分在外部磁盘存储器上。大多数操作系统都使用了虚拟内存。虚拟内存可看作是一个存放在磁盘上的N个连续的字节大小的单元组成的数组。每个字节都有一个虚拟地址,作为到数组的索引。

寄存器

四类寄存器

通用寄存器

段寄存器

程序与控制寄存器

指令指针寄存器

32位机

通用寄存器
EAX(针对操作数和结果数据的)累加器
EBX(DS段的数据指针)基址寄存器
ECX(字符串和操作循环的)计数器
EDX(I/O)指针数据寄存器
ESI(字符串操作源指针)源变址寄存器
EDI  (字符串操作目标指针)目的变址寄存器
EBP  (SS段中栈内数据指针)扩展基址指针寄存器
ESP(SS段中栈指针)栈指针寄存器

通用型的寄存器,用于传送和暂存数据

ESP   PUSH,POP,CALL,RET可以直接用来操作ESP

EBP  函数调用存储ESP,函数返回把值返回ESP

段寄存器
CS代码段寄存器
SS栈段寄存器
DS数据段寄存器
ES附加数据段寄存器
FS数据段寄存器
GS数据段寄存器

每个16位

程序状态与控制寄存器
EFLAGS标志寄存器

32位,每个位置记录一种状态

指令指针寄存器
EIP指令指针寄存器

CPU从中读取一条指令的地址,指令传送到缓存区后,EIP地址自动增加

64位机

十六位机中E改为R,增加了R8~R15八个通用寄存器

通用寄存器
RAX(针对操作数和结果数据的)累加器
RBX(DS段的数据指针)基址寄存器
RCX(字符串和操作循环的)计数器
RDX(I/O)指针数据寄存器
RSI(字符串操作源指针)源变址寄存器
RDI  (字符串操作目标指针)目的变址寄存器
RBP  (SS段中栈内数据指针)扩展基址指针寄存器
RSP(SS段中栈指针)栈指针寄存器
R8~R15

补充

AL是AX寄存器的低八位

AH是AX寄存器的高八位

AX是EAX的低16位

汇编语言基本组成部分

整数常量

由三部分组成

可选前置符号(+/-)一个或多个数字可选基数字符(指明基数)

可选基数字符是指明进制类型,可选是因为没有基数的情况默认为十进制

基数值
十六进制h
八进制q/o
十进制d
二进制b
实数r

例如:

26  ;十进制

3Ah ;十六进制

17o ;八进制

 如图反汇编器生成的汇编代码中h基数结尾的表示16进制整数

整数常量表达式

算术运算符
运算符名称优先级
()圆括号1
+,-一元加减2
*,/乘除3
MOD取模4
+,-一元加减2

浮点数常量

real number literial

一个可选符号一个整数小数点表示小数部分的一个整数一个可选的指数

例如

5.

+2.0

26.E5

-78.2E+05

x86指令集是针对整数处理的,浮点数用的少

字符常量

用单引号和双引号包含的一个字符

"A"

'a'

使用ASCLL编码

"A"在内存中存放的形式65,41h

字符串常量

用单引号和双引号包含的一个字符串

"Hello world"

"Peter"

'Good'

可以用单引号嵌套双引号,也可以双引号嵌套单引号

"That's good"

'Say"Hello"'

保留字

有特殊意义并且只能在正确的上下文使用

  • 指令助记符 例如ADD
  • 寄存器名称
  • 伪指令
  • 属性  例如BYTE,DWORD
  • 运算符 
  • 预定义符号

标识符

不区分大小写

第一个字符必须是字母,下划线,@,?,$

后面的字符可以是数字

伪指令

作用

定义宏,变量,子程序

由汇编器识别和运行,不在运行时执行

var dword 66  ;伪指令,为一个双字变量保留空间

mov eax,var ;指令,含义后面会讲

定义段

定义程序的段

例如

.data   ;数据段,定义变量

.code    ;code段包含了可执行的指令

.stack 100h    ;定义了运行时的堆栈和大小

指令


标号

是一种标识符,是指令和数据的位置标记
数据标号

var DWORD 89   ;定义了一个变量var

代码标号

target:

        mov     ebp, esp
        sub     esp, 68h
        push    ebx
        push    esi

L1:mov     ebp, esp

代码标号用于跳转和循环和目标

指令助记符

是标记一个指令的单词

例如ADD,MOV,JMP

注释

单行注释   使用;

;注释内容

块注释   使用COMMENT伪指令和一个用户定义的符号开始,相同的符号结束

COMMENT @

     注释内容

@

汇编语言内部数据类型


BYTE    8 位无符号整数,B 代表字节
SBYTE    8 位有符号整数,S 代表有符号
WORD    16 位无符号整数
SWORD    16 位有符号整数
DWORD    32 位无符号整数,D 代表双(字)
SDWORD    32 位有符号整数,SD 代表有符号双(字)
FWORD    48 位整数(保护模式中的远指针)
QWORD    64 位整数,Q 代表四(字)
TBYTE    80 位(10 字节)整数,T 代表 10 字节
REAL4    32 位(4 字节)IEEE 短实数
REAL8    64 位(8 字节)IEEE 长实数
REAL10    80 位(10 字节)IEEE 扩展实数

数据定义语句例:count BYTE 10

数据传送指令,寻址指令,加减法指令

数据传送指令

MOV指令

将源操作数复制到目的操作数

MOV 目的操作数,源操作数

mov     ebp, esp

逻辑相当于高级语言中的ebp=esp

XCHG指令

XCHG指令交换两个操作数的内容

XCHG eax,ebx

偏移量操作数

array BYTE 10h,20h,30h,40h,50h

mov eax,array          ;eax=10h

mov eax,[array+1]    ;eax=20h

mov eax,[array+2]    ;eax=30h

NOP指令

是一个空操作

占用一个字节,不做任何操作,用于将代码对齐到有效的地址边界


加法指令和减法指令

INC指令

表示寄存器或内存操作数自减1

INC reg/men

DEC指令

表示寄存器或内存操作数自减1

DEC reg/men

ADD指令

将源操作数加在目的操作数上(可以是寄存器或者变量)

ADD eax,var1

SUB指令

将目的操作数减去源操作数,存在目的操作数中(可以是寄存器或者变量)

SUB eax,var1

NEG指令

取操作数的补码,存在操作数中

NEG eax

NEG var

与数据有关的运算符和伪指令

OFFSET运算符

返回一个变量与其所对在段起始地址之间的距离

ALIGN伪指令

将一个变量对齐到字节边界,字边界,双字边界或者段落边界

ALIGH bound

bound可以取值为1,2,4,8,16

定义后,变量地址将是bound的整数倍

PTR运算符

重写操作数默认的大小类型,必须和一个标准汇编数据类型一起使用

TYPE运算符

返回变量单个元素的大小

var1 BYTE ?

TYPE var1  ;值为1

var2 WORD ?

TYPE var2  ;值为2

LENGTHOF运算符

返回数组中元素的个数

SIZEOF运算符

返回数组占用的字节数

JMP和LOOP指令

JMP指令

无条件跳转到一个地址,这个地址可以使用代码标号

使用JMP可以创建循环

top:

        ...

        jmp top

是一个死循环

LOOP指令

ECX计数器循环

ECX是计数器

第一步,ECX的数值减1

第二步,ECX与0比较,如果等于0循环终止

    mov eax,0
    mov ecx,5
L:
    inc eax
    loop L1

这个汇编程序会循环5次

汇编语言程序范例

;Addtwo.asm  -add two 32-bit integers

.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD

.code
main PROC
    mov eax 3
    add eax 2
    INVOKE ExitProcess,0
main ENDP
END main

.386伪指令表示这是一个32位程序,访问32位寄存器和地址

.model flat,stdcall表示内存模式是flat,子程序的调用规范是stdcall

.stack 4096        运行时堆栈保留了4096字节的存储空间

Exit是一个标准的Windows服务

main PROC表示要执行的第一个指令的位置

main ENDP表示一个过程的结束

END main表示汇编程序的结束

堆栈

堆栈数据结构

堆栈数据结构就是我们数据结构课中学到的栈

 栈顶添加新元素,删除元素在栈顶删除

后进去先出FILO

本文要讲的是运行时堆栈

运行时堆栈

运行时堆栈是内存数组

ESP寄存器

ESP寄存器(extended stack pointer,扩展堆栈指针)

可以理解为抽象数据结构栈中指向栈顶的指针

存放某个位置的32位偏移量

基本上不会被程序员修改

用CALL,RET,PUSH,POP指令间接修改

入栈操作

32位入栈操作是把栈顶指针减4,再将数值复制到栈顶指针指向的位置

运行时堆栈在内存中是向下生长的,从高地址向低地址扩展

出栈操作

从堆栈删除元素,站定指针减小

PUSH指令

首先减少ESP的值,将操作数复制到堆栈

POP指令

将ESP指向的堆栈元素复制到一个操作数当中,增加ESP的值

PUSHFD指令

将32位EFLAGS寄存器的内容压入堆栈

POPFD指令

将栈顶元素弹出到32位EFLAGS寄存器

PUSHAD指令

按照EAX,ECX,EDX,EBX,ESP,EBP,ESI,EBI的顺序

将所有32位通用寄存器压入堆栈

POPAD指令

按照与PUSHAD相反的顺序将其弹出堆栈

过程

有过高级语言编程经验的话,我们知道为了增加一个程序的可读性,便于阅读,调试和合作,应该将程序封装成函数和方法

 这些函数和方法就是一个子程序

在汇编语言中这些子程序叫做过程

过程是可以嵌套调用的

定义主过程

main PROC
.
.
main ENDP

其他过程

pro PROC
    .
    .
    ret
pro ENDP

全局标号

当跳转和循环时候

jmp destination

destination必须和JMP指令位于同一过程中

可以使用全局标号解决这一问题,在名字后面加双冒号::

CALL指令

调用一个过程

将返回地址压入堆栈,将被调用的过程地址复制到指令地址寄存器EIP

RET指令

结束一个过程调用

从堆栈将返回地址复制到指令地址寄存器EIP

向过程传递寄存器参数

在调用过程之前,将数值传递给寄存器

寄存器中保留传递的参数

条件处理

布尔操作和比较指令

AND指令,OR指令,XOR指令,NOT指令

分别将目的操作数与源操作数进行与,或,异或,非操作

将结果存放在目的操作数当中

TEST指令

进行与操作,更新CPU标志位

CMP指令

比较两个数字

隐含减法操作,但是不修改任何操作数

比较两个无符号数]

标志位在EFLAGS寄存器上

ZF是零标志位,CF是进位标志位,OF是溢出标志位

CMP结果ZFCF
目的操作数<源操作数01
目的操作数>源操作数00
目的操作数=源操作数10

比较两个有符号数

CMP结果标志位结果
目的操作数<源操作数SF不等于OF
目的操作数>源操作数SF=OF
目的操作数=源操作数ZF=1

我们可以看出当两个数字相等的时候,ZF是1

条件跳转

Jcond指令

JZ 为零跳转 ZF=1 JNO 无溢出跳转 OF=0
JNZ 非零跳转 ZF=0 JS 有符号跳转 SF=1
JC 进位跳转 CF=1 JNS 无符号跳转 SF=0
JNC 无进位跳转 CF=0 JP 偶校验跳转 PF=1
JO 溢出跳转 OF=1 JNP 奇校验跳转 PF=0

    cmp eax,0
    jz L1        ;当ZF是1时候跳转
    .
    .
L1:
    .
    .

基于相等性的跳转,基于无符号数的跳转指令,基于有符号数比较的跳转

cmp leftOp,reghtOp

基于相等性的跳转

JE 相等跳转(leftOp = reghtOp)

JNE 不相等跳转(leftOp ≠ reghtOp)

JCXZ CX = 0 跳转

JECXZ ECX = 0 跳转

JRCXZ RCX = 0 跳转(64位模式)

基于无符号数的跳转指令


JA    大于跳转(若leftOp > reghtOp)
JNBE    不小于或不等于跳转(同JA)
JAE    大于或等于跳转(若leftOp ≥ rightOp)
JNB    不小于跳转(同JAE)
JB    小于跳转(若leftOp < reght)
JNAE    不大于或不等于跳转(同JB)
JBE    小于或等于跳转(若leftOp ≤ rightOp)
JNA    不大于跳转(同JBE)

基于有符号数比较的跳转


JG    大于跳转(若leftOp > reghtOp)
JNLE    不小于或不等于跳转(同JG)
JGE    大于或等于跳转(若leftOp ≥ rightOp)
JNL    不小于跳转(同JGE)
JL    小于跳转(若leftOp < reght)
JNGE    不大于或不等于跳转(同JL)
JLE    小于或等于跳转(若leftOp ≤ rightOp)
JNG    不大于跳转(同JLE)

整数运算

移位指令

算术移位和逻辑移位

逻辑移位是对无符号数进行的,左移和右移都是补零

算术移位是对有符号数进行的,空出来的符号位用原数据的符号位填充

SHL指令

逻辑左移指令,将目的操作数顺序左移1位或CL寄存器中指定的位数。左移一位时,操作数的最高位移入进位标志位CF,最低位补零。

SHR指令

逻辑右移指令,SHR指令将目的操作数顺序右移1位或CL寄存器指定的位数。逻辑右移1位时,目的操作数的最低位移到进位标志位CF,最高位补零。

SAL指令

算术左移指令,最高位移入CF,最低位补0。

SAR指令

算术右移指令

ROL指令

所有位都向左移,最高位复制到CF和空出来的最低位

ROR指令

所有位都向右移,最低位复制到CF和空出来的最低位

RCL指令

带进位循环左移,CF移动到空出来的最低位,最高位移动到CF

RCR指令

带进位循环右移,最低位移动到CF,CF移动到空出来的最高位

SHLD指令

双精度左移

SHLD dest,source,count

源操作数的最高位移动到目的操作数的最低位,目的操作数都左移,目的操作数的最高位移动到CF

SHRD指令

双精度右移

SHLD dest,source,count

源操作数最低位移动到目的操作数空出来的最高位,目的操作数最低位移动到CF,其余位右移

乘法指令

MUL指令(32位模式)

32位机中有三种乘法,一种乘法示例:

只有一个操作数,实现一个8位操作数和AL寄存器的乘法,存入AX

AL是AX寄存器的低八位

AH是AX寄存器的高八位

AX是EAX的低16位

范例

mov al 5h
mov bl 10h
mul bl  ;AX=0050  CF=0

当AX的高半部分是0的时候,CF是0

三种类型
被乘数乘数乘积
ALreg/mem8AX
AXreg/mem16DX:AX
EAXreg/mem32EDX:EAX

MUL指令(64位模式)

新增的类型

被乘数乘数乘积
RAXreg/mem64RDX:RDX

IMUL指令(32位模式)

有符号数乘法

X86支持三种类型的IMUL指令:

单操作数,双操作数,三操作数

单操作数格式与MUL一样

三种类型
被乘数乘数乘积
ALreg/mem8AX
AXreg/mem16DX:AX
EAXreg/mem32EDX:EAX

双操作数格式

将两个操作数的乘积放在第一个操作数当中,第一个操作数必须是寄存器

三操作数格式

第一个操作数必须是一个16位寄存器

第二个操作数是一个16位置寄存器或者内存操作数

第三个操作数是一个8位或者16位的立即数

或者

第一个操作数必须是一个32位寄存器

第二个操作数是一个32位置寄存器或者内存操作数

第三个操作数是一个16位或者32位的立即数

IMUL指令(64位模式)

同MUL一样添加了64位数相乘的情况

DIV指令(32位模式)

被除数除数余数
AXreg/mem8ALAH
DX:AXreg/mem16AXDX
EDX:EAXreg/mem32EAXEDX

DIV指令(64位模式)

被除数除数余数
RDX:RAXreg/mem64RAXRDX

IDIV指令指令

有符号数除法

篇幅有点长,后续放在下一篇文章汇编语言学习笔记 下

点击继续阅读

  • 8
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
嗨!对于逆向学习汇编语言学习笔记,我可以给你一些基本的指导。首先,汇编语言是一种低级语言,它与计算机的底层硬件密切相关。逆向工程则是通过分析和理解已编译的程序来获取程序的内部信息。 以下是一些学习汇编语言逆向工程的建议: 1. 学习基础知识:了解计算机体系结构、寄存器、内存和指令集等基础概念是必要的。可以先阅读相关的书籍或在线教程,掌握这些基本概念。 2. 掌握汇编语言的语法和指令集:每种计算机体系结构都有自己的汇编语言语法和指令集。选择一种你感兴趣的体系结构(如x86、ARM等),并学习它的汇编语言。 3. 练习编写和调试汇编代码:通过编写简单的汇编代码来熟悉语法和指令集。使用调试器来单步执行代码并观察寄存器和内存的变化。 4. 分析已编译程序:选择一个目标程序进行逆向分析。使用反汇编器将程序转换为汇编代码,并分析代码的逻辑和功能。这有助于理解程序的结构和运行过程。 5. 使用调试器进行动态分析:通过调试器来动态地执行程序,并观察程序在运行时的行为。使用断点、内存查看器和寄存器查看器等工具来分析程序的状态和数据。 6. 学习逆向工程工具和技术:了解常用的逆向工程工具和技术,如IDA Pro、OllyDbg、Ghidra等。掌握这些工具的使用可以提高你的逆向分析能力。 7. 参考优秀资源:阅读与逆向工程汇编语言相关的书籍、论文和博客,关注相关的社区和论坛。与其他逆向工程师交流经验也是很有帮助的。 记住,逆向工程是一个需要耐心和实践的过程。持续学习和实践将帮助你提高逆向分析的技能。祝你在学习汇编语言逆向工程的过程中取得好成果!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烨鹰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值