最近发现底层原理知识匮乏,故而重故一下汇编, 以便对系统攻防技术有更好的理解
寄存器总览:
4个数据寄存器(EAX、EBX、ECX和EDX)
2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP)
6个段寄存器(ES、CS、SS、DS、FS和GS)
1个指令指针寄存器(EIP) 1个标志寄存器(EFlags)
作用:寄存器是中央处理器内的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。在中央处理器的控制部件中,包含的寄存器有指令寄存器(IR)和程序计数器(PC)。在中央处理器的算术及逻辑部件中,寄存器有累加器(ACC)
下面对各类寄存器进行介绍:
1. 数据寄存器
作用:数据寄存器主要用来保存操作数和运算结果等信息,从而节省读取操作数所需占用总线和访问存储器的时间
寄存器中数据存储:
在内存中时,由于内存单元是字节单元,刚一个字要用2个地址连续的内存单元来存放,字的低位字节存在低地址单元.
0地址单元中存放的字节型数据为20H,0地址单元中存放的字型数据为4E20H,2地址单元中存放的字节型数据为12H,2地址单元中存放的字型数据为0012H
汇编命令:
2.段寄存器
作用:段寄存器是因为对内存的分段管理而设置的。计算机需要对内存分段,以分配给不同的程序使用(类似于硬盘分页)
处理方式:8086CPU有20根地址线,最大可寻址内存空间为1MB。而8086的寄存器只有16位,指令指针(IP)和变址寄存器(SI、DI)也是16位的。用16位的地址寻址1MB空间是不可能的。所以就要把内存分段,
也就是把1MB空间分为2^4,即16个段,每段不超过64KB(2^16,16位数据线就可以寻址)
各个寄存器介绍:
段寄存器CS:指向存放程序的内存段,IP是用来存放下条待执行的指令在该段的偏移量,把它们合在一起可在该内存段内取到下次要执行的指令
段寄存器SS:指向用于堆栈的内存段,SP是用来指向该堆栈的栈顶,把它们合在一起可访问栈顶单元。另外,当偏移量用到了指针寄存器BP,则其缺省的段寄存器也是SS,并且用BP可访问整个堆栈,不仅仅是只访问栈顶
段寄存器DS:指向数据段,ES指向附加段,在存取操作数时,二者之一和一个偏移量合并就可得到存储单元的物理地址。该偏移量可以是具体数值、符号地址和指针寄存器的值等之一,具体情况将由指令的寻址方式来决定
通常,缺省的数据段寄存器是DS,只有一个例外,即:在进行串操作时,其目的地址的段寄存器规定为ES。当然,在一般指令中,我们还可以通过改变前缀中的“段取代”字段来改变操作数的段寄存器
“可选用的段寄存器”即是可以用强置说明这些段寄存器的值来作为其操作数地址的段地址
3. 指针寄存器
SS, SP, BP 三个寄存器
SS:存放栈的段地址;
SP:堆栈寄存器SP(stack pointer)存放栈的偏移地址;
BP: 基数指针寄存器BP(base pointer)是一个寄存器,它的用途有点特殊,是和堆栈指针SP联合使用的,作为SP校准使用的,只有在寻找堆栈里的数据和使用个别的寻址方式时候才能用到
SP,BP一般与段寄存器SS 联用,以确定堆栈寄存器中某一单元的地址,SP用以指示栈顶的偏移地址,而BP可 作为堆栈区中的一个基地址,用以确定在堆栈中的操作数地址
(引用)
举个栗子:
调用函数test(int p1,int p2)的汇编代码
;假设执行函数前堆栈指针ESP为NN
push p2 ;参数2入栈, ESP -= 4h , ESP = NN - 4h
push p1 ;参数1入栈, ESP -= 4h , ESP = NN - 8h
call test ;压入返回地址 ESP -= 4h, ESP = NN - 0Ch (注意CALL指令会把返回地址压入堆栈)
;//进入函数内
{
push ebp ; 保护先前EBP指针, EBP入栈, ESP-=4h, ESP = NN - 10h
mov ebp, esp ; 设置EBP指针指向栈顶 NN-10h
mov eax, dword ptr [ebp+0ch] ;ebp+0ch为NN-4h, 即参数2的位置 这里可以看到了BP的作用了
mov ebx, dword ptr [ebp+08h] ;ebp+08h为NN-8h, 即参数1的位置 这里可以看到了BP的作用了
ub esp, 8 ;局部变量所占空间ESP-=8, ESP = NN-18h (栈底的地址大)
;这里就是为局部变量申请空间.
...
add esp, 8 ;释放局部变量, ESP+=8, ESP = NN-10h
;(假设在上面的指令中EBP没变的话, 直接MOV ESP, EBP即可达到堆栈平衡,
; 事实上也经常这么用)
pop ebp ;出栈,恢复EBP, ESP+=4, ESP = NN-0Ch
ret 8 ;ret返回,弹出返回地址,ESP+=4, ESP=NN-08h,
; 后面加操作数8为平衡堆栈,ESP+=8,ESP=NN, 恢复进入函数前的堆栈
; 为什么是8? 因为Test子函数有两个参数, 8就是对应了两个参数入栈时SP减少了8
}
原来ESP就是一直指向栈顶的指针,而EBP只是存取某时刻的栈顶指针,以方便对栈的操作,如获取函数参数、局部变量等
4.控制寄存器
FLAG寄存器如下图:
下面我们就按不同的位来分别介绍这些位所描述的状态,以及它们代表的意义:
CF(Carry FLag) - 进位标志(第 0 位):
CF: 进位标志是用来反映计算时是否产生了由低位向高位的进位,或者产生了从高位到低位的借位 。
if(运算过程中产生了进位或者借位)
{
CF = 1;
}
else
{
CF = 0;
}
PF(Parity FLag) - 奇偶标志(第 2 位):
PF: 奇偶标志是用来记录相关指令执行后,其结果的所有的 Bit 位中 1 的个数是否为偶数 。
if(运算结果中 1 的个数为偶数)
{
PF = 1;
}
else
{
PF = 0;
}
AF(Auxiliary Carry FLag) - 辅助进位标志(第 4 位):
AF: 用来辅助进位标志 。
if(字节操作中发生低半个字节向高半个字节借位或者进位 || 字操作中发生低字节向高字节借位或者进位)
{
AF = 1;
}
else
{
AF = 0;
}
ZF(Zero FLag) – 零标志(第 6 位):
ZF: 记录的是相关的指令执行完毕后,其执行的结果是否为 0 。
if(执行的结果 == 0)
{
ZF = 1;
}
else
{
ZF = 0;
}
SF(Sign FLag) - 符号标志(第 7 位):
SF: 符号标志,其记录相关指令执行完以后,其结果是否为负数 。
if(运算结果为负数)
{
SF = 1;
}
else
{
SF = 0;
}
TF(Trap FLag) - 追踪标志(第 8 位):
TF: 追踪标志,主要是用于调试时使用 。
if(TF == 1)
{
CPU 进入单步方式;
}
IF(Interrupt-Enable FLag) - 中断允许标志(第 9 位):
IF: 中断允许标志,其决定 CPU 是否能够响应外部可屏蔽中断请求(以后会做详细介绍) 。
if(IF == 1)
{
CPU 能够响应外部的可屏蔽中断请求;
}
else
{
CPU 不能够响应外部的可屏蔽中断请求;
}
DF(Direction FLag) - 方向标志(第 10 位):
DF: 方向标志,其用于在串处理指令中,用来控制每次操作后 SI 和 DI 是自增还是自减 。
if(DF == 0)
{
SI++;
DI++;
}
else
{
SI--;
DI--;
}
OF(OverFlow FLag) - 溢出标志(第 11 位):
OF: 溢出标志,其通常记录了有符号数运算的结果是否发生了溢出 。
if(运算发生溢出)
{
OF = 1;
}
else
{
OF = 0;
}
总结:
汇编之旅就此开始了, 自己看了一下,写的多有不足之处,日后慢慢改正向前辈学习了,此次想学习汇编并不是要从事汇编
编程,更多的是提升一下内功,对计算机理解更透彻一些,另外也是想能看懂别的有深度一点的书