汇编|汇编基础-2

上回给大家介绍了32位通用寄存器的概念,也收到了一些大佬的不同响应,感谢各位大佬在百忙之中指点不足,然后呢这一期依然是接着上回的继续讲解。
废话不多说,今天带来的内容主要为以下四个方面:

基于64位的通用寄存器以及16位段寄存器的简单介绍?
内存与内存地址的简单介绍
mov指令以及其他汇编指令?
堆栈指令等?
16位段寄存器以及64位通用寄存器 首先还是声明一点,我这里主要介绍的是继续x86的32位的汇编指令,64位的汇编指令以及用法我这里无法为大家做太过于详细的介绍,原因无它,笔者还没能融会贯通。所以为了不给大家引入一个错误的道路,这里仅做简单的介绍以及补充
首先什么是16位段寄存器呢?
在实地址模式中,16位段寄存器表示的是预先分配的内存区域的基址,这个内存区域被称为段。保护模式中,段寄存器存放的是段描述符表指针。一些段中存放程序的指令或代码,其它段存放变量或数据,还有一个堆栈段存放的是局部函数变量和函数参数。?
?
16位段寄存器上节内容并没有单独的拿出来介绍,这次作为补充做简单介绍
GS 002B未使用,80386 之后定义的 FS 0053分段机制,80386 之后定义的 ES 002B扩展段,在串操作时(比如cmovs)目标操作数的基址是ES,源操作数是DS DS 002B数据段,默认的都是DS CS 0023代码段,配合EIP使用 SS 002B堆栈段,凡是基址是EBP或ESP的,段前缀就是SS

这里我们先介绍简单的概念,我们后续主要遇到的还是 DS以及SS; 这里不做过多的介绍。
?EAX是默认使用的乘除指令。它常常被称为扩展累加器寄存器 ECX为CPU默认使用的循环计数器 ESP用于寻址堆栈(一种系统内存结构)数据。它极少用于一般算术运算和数据传输,通常被称为扩展堆栈指针寄存器 ESI和EDI用于高速存储器传输指令,有时也被称为扩展源变址寄存器和扩展目的变址寄存器 EBP在高级语言中用来引用堆栈中的函数参数和局部变量。除了高级编程,它不用于一般算术运算和数据传输。它常常被称为扩展帧指针寄存器。 实地址模式中,16位段寄存器表示的是预先分配的内存区域的基址,这个内存区域称为段。保护模式中,段寄存器中存放的是段描述符表指针。一些段中存放程序指令(代码),其他段存放变量(数据),还有一个堆栈段存放的是局部函数变量和函数参数。 EIP为指令指针寄存器,包含下一条将要执行指令的地址。某些机器指令能控制EIP,使得程序分支转向到一个新位置 FFLAGS寄存器包含了独立的二进制位。用干控制CPU的操作,或是反映一些CPU操作的结果。有些指令可以测试和控制这些单独的处理器标志位 状态标志位状态标志位反映了CPU执行的算术和逻辑操作的结果。其中包括:溢出位、符号位、零标志位、辅助进位标志位、奇偶校验位和进位标志位。 进位标志位(CF),与目标位置相比,无符号算术运算结果太大时,设置该标志位。 溢出标志位(OF),与目标位置相比,有符号算术运算结果太大或太小时,设置该标志位 符号标志位(SF),算术或逻辑操作产生负结果时,设置该标志位。 零标志位(ZF),算术或逻辑操作产生的结果为零时,设置该标志位。 辅助进位标志位(AF),算术操作在8位操作数中产生了位3向位4的进位时,设置该标志位。 奇偶校验标志位(PF),结果的最低有效字节包含偶数个1时,设置该标志位,否则清除该标志位。一般情况下,如果数据有可能被修改或损坏时,该标志位用于进行错误检测。 方向标志位(DF),控制了串操作指令(MOVS,CMPSSCASLODS与STOS)设置DF标志位将使得串操作指令地址自动递减(从高地址向低地址处理串)。清除DF标志位将使得串操作指令自动递增(从低地址向高地址处理串)。 中断允许标志位(IF),控制处理器对干可屏蔽中断的处理,设置该标志位位可使处理器响应可屏蔽中断;清除则禁止响应可屏蔽中断。 跟踪标志位(TF),设置可启用单步运行模式来调试程序,清除则禁用单步运行模式。

汇编|汇编基础-2
文章图片

后续在第三篇内容我会详细的为大家说明标志寄存器的用法,这里不做过多介绍。
状态标志位的第几位第几位是怎么来的呢?
汇编|汇编基础-2
文章图片

00000246
0000 0000 0000 0000 0000 0010 0100 0110
DF位为方向位,为EFL寄存器转换为2进制后低位下标为10的数(下标从0开始),当该位置为0时,movs指令每执行一次,EDI/ESI寄存器地址值增加1或2或4位,取决于是byte还是word还是dword; 当DF方向位的值为1时,则会递减1/2/4
【汇编|汇编基础-2】64位通用寄存器仅为了解,大家感兴趣的可以自己私底下去学习哈
8位AL BL CL DL DIL SIL BPL SPL R8L R9L R10L R11L R12L R13L R14L R15L 16 位AX BX CX DX DI SI BP SP R8W R9W R10W R11W R12W R13W R14W R15W 32 位 EAX EBX ECX EDX EDI ESI EBP ESP R8D R9D R10D R11D R12D R13D R14D R15D 64 位 RAX RBX RCX RDX RDI RSI RBP RSP R8 R9 R10 R11 R12 R13 R14 R15

内存和内存地址的简单介绍 每个程序在运行之前都会分配一个4GB的虚拟的内存空间,如下图
汇编|汇编基础-2
文章图片

32位?内存地址示例:
?0X00000001?
宽度是32位指的是2进制 32位,一个0代表4位0000,这里是16进制展示,所以是8位;一个字节是8位
?宽度是32位指的是2进制 32位,一个0代表4位0000,这里是16进制展示,所以是8位;一个字节是8位
因为内存太大没有办法取名字,所以使用编号来表示。当我们向内存中存储数据,或者从内存中读取数据的时候,必须使用这个编号。?
一个程序被分配4GB内存是如何计算的呢?
地址能找到多少块内存,按照16进制表示如下(一个0代表二进制的4个0)
ffffffff+1=100000000
每一块内存占8位,因为一个字节占8位
100000000 * 8 = 800000000
转成十进制
34359738368
整个内存能找到多少个字节
34359738368 / 8 = 4294967296
32位地址能寻找的内存有多少k
4294967296 / 1024 = 4194304
32位地址能寻找的内存有多少M
4194304 / 1024 = 4096
32位地址能寻找的内存有多少G
4096 / 1024 = 4
汇编指令 mov指令
mov指令是我们在汇编中最常见的指令,所以这里需要较为详细的讲解
mov 指令
从立即数到内存
从寄存器到内存
从内存到寄存器
汇编|汇编基础-2
文章图片

例1:
把一个立即数写到内存
byte这里指的是数据宽度
mov byte ptr ds:[地址]
一个字节是byte 对应8位(AL/AH…)
两个字节是 word 对应16位(AX/CX…)
四个字节是 dword 对应32位(EAX/ECX…)
mov dword ptr ds:[0X0019FA20], 0X12345678

汇编|汇编基础-2
文章图片

f8运行后,0X0019FA20内存地址的值已发生改变
汇编|汇编基础-2
文章图片

例2:
把寄存器的值写入内存(偷个懒,运行前的就不截图了,直接截运行后的图)
mov dword ptr ds:[0019B000],ecx

汇编|汇编基础-2
文章图片

例3:
把内存的值写入寄存器
mov eax, dword ptr ds:[0019B000]

汇编|汇编基础-2
文章图片

从内存到寄存器,从寄存器到寄存器,从寄存器到内存可以,但是不能内存到内存或者内存/寄存器到立即数,立即数只是一个数,无法存储
大端存储与小端存储
汇编|汇编基础-2
文章图片

对于数据而言,0x1A2C 1A是数据高位,2C是数据低位;对于内存而言,0x00000000是低位,0x00000001是高位(内存地址里有ffffffff个字节,每个字节仅能存储1个byte)
在ollydbg中,可以使用 db dw dd命令获取内存地址
汇编|汇编基础-2
文章图片

在 xdbg中,可以ctrl+g 输入内存地址
汇编|汇编基础-2
文章图片

汇编|汇编基础-2
文章图片

或者直接命令 dump 缺点就是不能指定数据长度
汇编|汇编基础-2
文章图片

汇编|汇编基础-2
文章图片

采用小端存储
每个字节占一个位,数据低位占内存低位,所以是小端存储,exe基本都是小端存储
汇编|汇编基础-2
文章图片

add指令(加法)
汇编|汇编基础-2
文章图片

执行前:
汇编|汇编基础-2
文章图片

执行后,eax变成eax与ecx的和
汇编|汇编基础-2
文章图片

sub指令(减法)
汇编|汇编基础-2
文章图片

sub al,byte ptr ds:[0019fa30]

al - 0019fa30内存地址的值的值而后将结果放入 al里
汇编|汇编基础-2
文章图片

运行后
汇编|汇编基础-2
文章图片

and指令(与运算)
汇编|汇编基础-2
文章图片

and dword ptr ds:[0019fa30],eax

用 0019fa30内存地址的值与 eax的值进行与运算,将结果存放入内存地址0019fa30中
汇编|汇编基础-2
文章图片

and dword ptr ds:[0019fa30],eax
汇编|汇编基础-2
文章图片

or指令(或运算)
汇编|汇编基础-2
文章图片

or dword ptr ds:[0019fa30],eax

汇编|汇编基础-2
文章图片

或运算,将内存地址的值与eax的值进行或运算,而后将值存入值内存地址里
汇编|汇编基础-2
文章图片

xor指令(异或运算)
汇编|汇编基础-2
文章图片

xor dword ptr ds:[0019fa30],eax

汇编|汇编基础-2
文章图片

异或运算只有不一样的才是真,一样的就为0
汇编|汇编基础-2
文章图片

not指令(非指令)
汇编|汇编基础-2
文章图片

not dword ptr ds:[0019fa30]

汇编|汇编基础-2
文章图片

执行结束后,取反,0为1,1为0,所以变成 FFFFFFFF
汇编|汇编基础-2
文章图片

movs指令
默认的就用ESI和EDI;ESI和EDI存储的是内存地址的编号
汇编|汇编基础-2
文章图片

汇编|汇编基础-2
文章图片

运行后,
汇编|汇编基础-2
文章图片

stos指令
汇编|汇编基础-2
文章图片

汇编|汇编基础-2
文章图片

执行后,成功将AL的值(EAX的后两位)存储到EDI寄存地的内存地址中,变成986D344
rep指令
ecx相当于计数器,执行一次减一
汇编|汇编基础-2
文章图片

mov ecx,10 这里是16进制的10,会重复执行16次
rep movsd
汇编|汇编基础-2
文章图片

运行第一次,ECX变成00000010
汇编|汇编基础-2
文章图片

继续运行,会重复执行将ESI的值赋给EDI,执行16次,
汇编|汇编基础-2
文章图片

堆栈的使用
运行程序后,堆栈内存地址如何寻找?运行程序后,ESP寄存器的值即为当前堆栈的地址值
汇编|汇编基础-2
文章图片

push指令
汇编|汇编基础-2
文章图片

使用push相当于执行了三步,本来需要指定当前堆栈的位置,使用PUSH指令后,程序会自动执行到当前位置,esp会自动跟进。栈顶指针esp从大值到小值,如果不知道堆栈位置,那么数据可能会被覆盖
push指令可以push立即数、eax寄存器、甚至是内存地址
push 3 push eax push dword ptr ds:[0019fa20]

汇编|汇编基础-2
文章图片

pop指令
汇编|汇编基础-2
文章图片

push 1 //将1值存储至堆栈内
push 2 //…
push 3 //…
push ecx //ECX计数器此时有初始值,我需要使用ECX,但是为了不影响后续,只能将他的初始值存储到堆栈中,使用完后再进行恢复
mov ecx,10 //更改ECX的值
mov ecx, dword ptr ds:[esp] //使用完ECX后,再将存储在堆栈(esp的值就是初始ecx的堆栈地址,因为Mov ecx,10的时候并没有对堆栈地址进行修改sub指令,所以ecx的堆栈地址依然是push ecx的地址,里面存储的值也是ecx初始的值)
add esp,4 //由于esp堆栈地址的值是递减的,所以不使用堆栈地址后应恢复,将ecx占用的地址覆盖掉,使用add 4命令会将堆栈地址往前移动4位,下次使用会直接覆盖
汇编|汇编基础-2
文章图片

执行一部分后
汇编|汇编基础-2
文章图片

使用pop指令可直接达到这个效果,
pop eax 将堆栈当前地址的值存储到eax里,同时esp(堆栈地址)的值递增4个
pop ebx
汇编|汇编基础-2
文章图片

EIP指令?
EIP存储的值是CPU下一次执行的地址(就是汇编里的地址)
EIP寄存器是32位,所以执行写地址的时候只能是dword
JMP指令
JMP指令相当于mov指令,只是他是专门用来修改EIP寄存器的
JMP 1
JMP EAX
JMP dword ptr ds:[0019fa20]
运行结束后,EIP地址会跳转至77891005
汇编|汇编基础-2
文章图片

汇编|汇编基础-2
文章图片

call指令(普通指令f8执行,call指令f7执行)
call指令会将当前的cpu执行地址传入EIP寄存器当中,同时ESP会减少四个,会将call指令的下一个指令的内存地址写入到ESP(堆栈)当中
汇编|汇编基础-2
文章图片

ret指令
ret执行前
汇编|汇编基础-2
文章图片

ret执行后
汇编|汇编基础-2
文章图片

INT 3 指令
相当于CC 断点,F2

    推荐阅读