逆向入门(4)汇编学习————80X86 cpu编程模型


一.概述

要在ARM架构下进行安全问题的分析,需要知道ARM汇编的基础知识。同时,构建ARM架构的shellcode,ROP链,以及调试ARM应用,这些都要求先懂得ARM汇编。

二.寄存器

1.概念

寄存器,即register,是cpu内部用来存放数据和指令的一种基本逻辑部件。cpu内部寄存器包含:通用寄存器,段寄存器,指令寄存器,标志寄存器,控制寄存器,系统寄存器,调试寄存器以及测试寄存器共7类。在汇编语言设计中,程序可以于右腹案的寄存器直接进行数据交换。cpu根据有关的寄存器提供的取值执行程序。有关的寄存器的取值规定了cpu的工作模式。

2.寄存器兼容

IA-32cpu中寄存器的位数一般为32位。IA-16cpu中所有寄存器位数为16位。在所有的cpu,段寄存器的位数都为16位。IA-32cpu新增加两个段寄存器(FS和GS)。IA-32cpu(80386)寄存器向下兼容,包含了IA-16cpu(8086、8088、80286)中所有的寄存器。IA-32cpu新增加控制寄存器,系统寄存器,测试寄存器。
在这里插入图片描述

3.通用寄存器

(1)EAX:累加寄存器,保存运算数据,在乘法和除法指令中被自动调用。
(2)EBX:基址寄存器,保存运算数据,在操作数寻址方式中可以提供一个基地址指针类型数据。
(3)ECX:计数寄存器,保存运算数据,在程序循环结构中默认用作计数器。
(4)EDX:数据寄存器,保存运算数据,默认保存某些指令高位运算结果。
(5)EBP:帧指针寄存器,一般不用做普通算术运算和数据传输。
(6)ESP:堆栈指针寄存器,极少用于普通的算数运算和数据传输。
(7)ESI和EDI:扩展源指针和扩展目的指针,用于高速内存数据传输指令使用。
在这里插入图片描述

4.通用寄存器的兼容性

(1)32位EAX->低16位AX->低高8位AH+低低8位AL
在这里插入图片描述
同理除了EAX,还有EBX.ECX,EDX都具有一定的兼容性。
在这里插入图片描述
(2)32位ESI->低16位SI:
在这里插入图片描述
EDI,EBP,ESP类似,如表:
在这里插入图片描述

5.通用寄存器说明

(1)在IA-32cpu中,所有通用寄存器既可以保存运算数据,又可以用于操作数寻址方式,保存指针数据。
(2)在IA-16cpu中:AX,CX,DX只能保存运算数据,不能保存指针数据。BX,SI,DI既可以保存运算数据,又可以用于操作数寻址方式,保存指针数据。BP,SP只能保存指针数据。

以EAX为例,举例说明通用寄存器的使用:
cpu中有一个保存32位数据的设备,这个设备对应多个名字:
(1)EAX:表示设备中的全部32位数据。
(2)AX:表示设备中的低16位数据。
(3)AH:表示设备中的低16位中的高8位数据。
(4)AL:表示设备中的低16位中的低8位数据。
在程序中修改某一个名字对应的数据,其他名字对应的数据也可能会改变。

6.标志寄存器

EFLAGS/FLAGS标志寄存器

(1)标志寄存器,用于反映cpu的工作状态和执行指令后运算结果的某些特征,提供状态标志(条件标志)、控制标志和系统标志。
(2)条件标志:OF,SF,ZF,AF,PF,CF。
(3)控制标志:DF,IF,TF。
(4)系统标志:IOPL,NT,RF,VM,AC,VIF,VIP,ID。
(5)每个标志位一般使用寄存器中的1位二进制取值表示某个含义。

注意:EFLAGS/FLAGS不是关键字,不能出现在程序中表示标志寄存器。

标志寄存器的兼容性

cpu中有一个保存32位数据的设备,这个设备对应2个名字:
EFLAG:表示设备中的全部32位数据;
FLAG:表示设备中的低16位数据。
在IA-32中程序中,可以使用EFLAGS中全部32位数据提供的标志;
在IA-16中,只能使用FLAGS中16位数据提供标志;
在这里插入图片描述

条件标志位

进位标志CF:运算过程是否有进/借位?有,=1,否则=0;
奇偶标志PF:运算结果最低字节中有偶/奇数个1?偶数,=1,否则=0;
辅助进位标志AF:运算是否有辅助 进/借位?有,=1,否则=0;
辅助进/借位:低半字节向高半字节的进位或借位
零标志ZF :运算结果是否为0?是,=1,否则=0;
符号标志SF:运算结果是正/负数?正数,=0,负数, =1;
溢出标志OF:运算是否溢出?是,=1,否则=0;

讨论OF与CF

保存加法/减法运算结果的位数由最大运算数据位数相同;
8/16/32位数据加/减运算结果,也是8/16/32位数据表示;
CF=1:表示运算过程有进/借位;运算结果是正确的。
将CF取值作为无符号8/16/32位数据加/减法运算结果的第9/17/33位取值,运算结果一定正确;
OF=1:表示结果产生溢出;运算结果是错误的。
溢出:在确定了运算的字长和数据的表示方法后,当运算结果超出所能表示的数据范围后,就产生溢出。
运算字长8位,补码表示,结果范围-128~+127;结果在这个范围之外,产生溢出。
正溢:结果为正且大于所能表示的最大正数。
负溢:结果为负且小于所能表示的最小负数。

7.段寄存器

源程序中的符号指令,数据,资源等经过编译后,在可执行程序中,以段/节/section的形式为单位分类保存程序中的指令,数据,资源等。一般指令保存在.text段中,数据保存在.data段中,资源保存在.rsrc中。在实模式中,一个段的大小是≤64K。在保护模式中,一个段的大小是≤4GB。段寄存器用于提供所关联段的段基址(实模式)或段描述符(保护模式)。
CS: 代码段(Code Segment)寄存器
SS: 堆栈段(Stack Segment)寄存器
DS: 数据段(Data Segment)寄存器
ES/FS/GS: 附加段(Extra Segment)寄存器
用来保存当前代码段、堆栈段、数据段 段地址(段基址/段描述符) 的值;实地址模式下,用于存放段的段基址(段起始位置),可以使用4个CS/SS/DS/ES;保护模式下用于存放段选择子,可以使用全部6个;段寄存器不能分解使用;在所有cpu中,段寄存器都是16位。

8.控制寄存器

提供要执行的下一条指令在代码段中的保存位置,同时控制寄存器也具有兼容性,32位EIP->低16位IP。在IA-32程序中,可以使用EIP,IP;在IA-16的程序中,只能使用IP。

三.内存管理

1.基本概念

内存:保存计算机正在使用数据的设备;
内存空间划分:整个内存空间划分为字节存储单元,每个存储单元保存1个8位的数据,即1个byte/字节数据。
内存单元地址:每个内存单元有一个唯一的标号,是内存单元的物理地址;
编号/物理地址 从0开始,依次+1;
一个物理地址唯一确定一个字节存储单元,按字节编址;
一个多字节数据要分字节保存到连续的多个内存单元中,高字节保存到地址大的内存单元,低字节保存到地址小的内存单元;
多字节数据的保存地址用最小地址表示;

内存容量:整个内存空间可以保存的数据量;
cpu地址线数量决定内存地址空间范围和内存容量:
n位地址,物理地址空间的范围是02n-1 ,对应的内存容量是2n字节。
8086cpu有20位地址,物理地址空间的范围是0
FFFFF,内存容量是1M字节,即1MB。
80386cpu有32位地址,物理地址空间的范围是0~FFFFFFFF ,内存容量是4G字节,即4GB。

内存访问:
读:将内存单元的内容读入cpu中,原单元内容不改变。
写:cpu将信息写入内存单元,单元中原来的内容被覆盖。
注意多字节数据的读写:
读: (10000H)B=CD (10000H)W=ABCD
写: (80000H)B=5678
在这里插入图片描述

2.实模式内存管理中的分段管理模式

分段:将内存空间划分为以段为单位的内存区域,计算机以段为单位来使用内存空间。
实模式下,可以使用的最大物理内存空间是1MB;每个段最大为64KB;
物理地址是程序执行时候分配的,源程序使用逻辑地址形式来表示内存位置。
逻辑地址组成:
逻辑地址由段基址(16位,存放在段寄存器中)和偏移地址(16位)构成,表示为 段基址:偏移地址 形式。
段基址表示段的起始位置,偏移地址是相当于段起始位置的偏移量。
一般段基址的取值是计算机管理的,是固定的,保存在段寄存器中。偏移地址可以由程序员根据需要指定或用符号表示。
实模式获取物理地址的方法:
程序中的 逻辑地址→物理地址 即:
物理地址=段基址×10H+偏移地址(那么问题来了,这个公式是如何推出来的呢?这是因为在实模式下最大的物理内存空间是1M,并且每个段最大为64KB,则可能有有1M/64kb=16个段,并且一个段对应64KB刚好是16个bit,也就是10H,这也就是为什么段基址要乘以10H,同时,偏移地址为16位)

被执行的程序在存储器中映像一般由三部分组成:
一是代码,代码是要执行的指令序列;
二是数据,数据是要处理加工的内容;
三是堆栈,堆栈是按“先进后出”规则存取的数据区域;
代码、数据和堆栈分别占用不同的存储器段空间,相应的段也就被称为代码段、数据段和堆栈段。其段基址分别在CS、DS、SS寄存器中。
一些逻辑地址搭配:
CS:IP → 下一条要执行指令的逻辑地址;
SS:SP → 堆栈段栈顶逻辑地址;
SS:BP → 堆栈段中某个存储单元逻辑地址;
DS/FS/GS:偏移量 → 保存某个数据的逻辑地址;

段起始位置:内存分段中第一个存储单元的地址必须为:XXXX0 H。段基址是XXXX H,保存在16位的段寄存器中。
段容量:≤64KB,段中存储单元偏移地址使用16位偏移量表示。
段可以重叠,共同使用重叠的内存空间。

3.保护模式内存管理中的分段分页管理模式

分段:将内存空间划分为段空间。
分页:将段空间划分为大小是4KB的页空间。
保护模式下,可以使用的最大物理内存空间是4GB。
物理地址是程序执行时候分配的,源程序使用逻辑地址形式来表示内存位置。
逻辑地址也称为虚拟地址,指向虚拟内存空间。
虚拟内存是计算机系统内存管理的一种技术。为了扩充主存空间而在外存上开辟的一块存储空间。
虚拟内存用来保存实际内存中暂时不用的程序或数据,使实际内存有更多的空闲空间来存放将要执行的程序或访问的数据,当需要执行的程序或访问的数据不在主存时,就从虚拟内存将其调入到主存,以便处理器执行或访问。

逻辑地址组成:
逻辑地址由段选择子(16位,存放在段寄存器中)和偏移地址(32位)构成,表示为 段选择子:偏移地址 形式。
段选择子的取值是计算机管理的,是固定的,保存在段寄存器中。
偏移地址可以由程序员根据需要指定或在源程序中用符号表示。
段基址不表示段起始位置,偏移地址是相当于段起始位置的偏移量。
保护模式获取物理地址的方法:
程序中的 逻辑地址→线性地址→物理地址 如图:
线性地址:32位,指定虚拟内存段中的某个内存单元;
物理地址:32位,指定物理内存空间中的某个内存单元;
在这里插入图片描述

四.寻址方式

1.寻址方式一般有两类:指令寻址方式和操作数寻址方式

指令寻址方式:根据当前执行指令的保存位置和指令功能,获取下一条要执行的执行保存位置的方法。
顺序指令寻址方式:当前指令不是转移指令(四则运算)
转移指令寻址方式:当前指令是转移指令(条件,循环,函数调用等)
操作数寻址方式:根据指令中操作数的编码(地址码),获取实现指令功能需要的操作数的方法。
操作数的保存位置和其源程序中的表示:
cpu内部:某一个寄存器中;寄存器名字表示;寄存器操作数
I/O端口:某一个I/O端口中,标志是端口编号表示;端口操作数
内存单元:某个内存地址指定的空间,逻辑地址表示;内存操作数
一般指令有两个操作数,每个操作数的寻址方式可以不同;

指令 操作数1,操作数2

目的操作数:指令后的第1个操作数,一般保存指令的结果
源操作数:指令后的第2个操作数

2.指令寻址方式

执行程序时,CS:IP/EIP指定的内存单元中保存有要执行的下一条指令编码。执行完当前指令后,cpu根据这个逻辑地址,继续取出下一条指令,继续执行程序。
计算机的工作过程:取指令→执行指令→取指令→…
cpu取出当前要执行的指令后,按照顺序指令寻址方式修改CS:IP/EIP的取值,让其指向下一条期望执行的指令,即:
CS:IP/EIP下一条= CS:IP/EIP当前+当前指令编码字节长度。
执行完当前指令后,如果当前执行的指令是顺序指令,根据CS:IP/EIP的取值可以正确的取到下一条指令,继续指令程序;
如果当前执行的指令是控制转移指令,根据CS:IP/EIP的取值可能不能正确的取到下一条指令;
为了正确的取到到下一条指令,需要根据控制转移指令的执行结果和操作数,计算正确的下一条指令保存在内存中的逻辑地址,并将这个计算得到的逻辑地址传送给CS:IP/EIP 。
根据更新过的CS:IP/EIP取值,实现跳转执行程序。

3.操作数寻址方式

(1)隐含寻址:根据指令隐含规定,操作数可能在某个特定的寄存器或者内存单元中。
xlat ; 操作数隐含规定在al中

(2)堆栈寻址:与堆栈有关的指令,其操作数规定在堆栈的栈顶,即逻辑地址=SS:SP/ESP的内存单元中。
push ax ; 操作数的保存位置=SS:SP

(3)立即寻址:操作数是常数→立即数操作数,常用于初始化操作;只能是源操作数的寻址方式。
操作数是一个8位/16位/32位常数,直接以常数的形式出现在指令操作数的位置,在机器指令中,保存在指令操作码的后面。
以A~F开头的16进制常数,前面必须加0
mov dx,0a250H 机器指令(3个字节) → BA50A2第
一个字节:操作码→BA
第2、3个字节:操作数→A250 (高字节高地址)

(4)寄存器寻址→寄存器操作数
操作数保存在cpu内部的寄存器中,指令中使用寄存器名字表示操作数。
8位寄存器:AH、AL、BH、BL、CH、CL、DH和DL;
16位寄存器:AX、BX、CX、DX、SI、DI、SP、BP和段寄存器;
32位寄存器:EAX、EBX、ECX、EDX、ESI、EDI、ESP和EBP。
注意:cs,ip/eip不能是目的操作数

(5)内存寻址→内存操作数
操作数保存在内存空间中,指令中使用保存操作数内存空间的逻辑地址(段地址:偏移地址)表示操作数。
偏移地址可以由数值地址,寄存器表示,要放在中括号中,与其他寻址方式区分。
段地址一般默认规定保存在某个段寄存器中,只需要提供偏移地址。或在偏移地址前面使用段前缀(段寄存器:)形式提供段地址。
偏移地址由BP/EBP/SP/ESP表示,段寄存器默认是SS;
其他情况段寄存器默认是DS。
mov eax,[100] ;源操作数保存在逻辑地址=DS:100
mov ax,es:[100] ;源操作数保存在逻辑地址=ES:100
mov ax,[bp] ;源操作数保存在逻辑地址=SS:bp
mov ax,ds:[bp] ;源操作数保存在逻辑地址=DS:bp
在这里插入图片描述

(6)I/O寻址→I/O操作数
操作数保存在I/O端口中,指令中使用I/O端口编号表示操作数。
端口编号是1个16位的数据,端口编号0~65535。
每个I/O端口保存一个8位/byte的数据。一个16位的数据,保存在编号连续的两个I/O端口中,高字节高端口,低字节低端口。
直接端口寻址:要访问的端口编号小于256,可以在指令中使用8位二进制立即数表示端口编号。
in al,63h out 63h,ax
间接端口寻址:先使用DX寄存器保存要访问的端口编号,在指令中使用DX寄存器表示端口编号。
mov dx,123h in al,dx out dx,al


评论
  目录