0x01 寄存器
通常存储数据可以放在三个地方
- CPU
- 内存
- 硬盘
CPU
可以分为32
位和64
位CPU
,64
位的CPU
是从32
位扩展上来的。
- 32位,支持8,16,32
- 64位,支持8,16,32,64
寄存器位于CPU
当中,通用寄存器
,指的是可以放任意数据的寄存器,有许多寄存器只能存储特定类型的数据,比如EIP
就只能存放CPU
下一次执行的命令
MOV
指令关于寄存器有两个功能
- 立即数到寄存器
- 寄存器到寄存器
通用寄存器又分32
、16
、8
位,分别对应着dword
、word
、byte
的数据宽度
这里寄存器的名称其实挺有意思,16
位的名称,其实是32
位去掉E
,其实也是32
位寄存器的取值拿出一半来给存数据其实就是16
位的,那8
位呢?8
位的区别在一点,没有了SP,BP,SI,DI
四个,就变成了AL,AH
这种,这里的L
是低(low)
的意思,H
是高(high)
的意思,也就是说AL
其实是AX
的低位,AH
是AX
的高位。具体的可以看下面的例子。
例子1,立即数到32位寄存器
mov eax,1
F8
单步运行后,看到结果成功
例子2,寄存器到寄存器
mov eax,1
mov ecx,eax
例子3,立即数到16
位寄存器
首先双击右侧eax
,将值改为-1
,即FFFFFFFF
接着使用
mov ax,1
观察现象
改变了两个字节,即16
位。
例子4,立即数到8
位寄存器
一样的,修改eax
的值为-1
后,输入指令
mov al,1
mov ah,2
先按第一次f8
低位变成了01
,变化一个字节,再按第二次f8
高位变成了02
,变化了另外一个字节。
看到这应该能明白之前那段总结的话语了吧。
另外要注意,不同位数的寄存值的值是不能直接mov
的
0x02 内存
基本概念
每一个应用程序都有自己独立的4G
内存空间。这句话中的内存空间并不是真实存在的,而物理内存也不是硬件设备,其实就是在一些工具中可以看到的内存地址和硬件地址了。
那为什么使用内存地址,而不像寄存器一样起名字,因为内存空间32
位,起名字太难太多了,所以用编号来命名,一般就是0xFFFFFFFF
这种类似的格式了。
MOV
指令关于内存的功能一般有三个
- 立即数到内存
- 寄存器到内存
- 内存到寄存器
在汇编中,绝大数指令是不允许到内存到内存中的。
要注意内存数据宽度的问题,写入的数值和内存必须要一样
例子1,立即数到内存
MOV BYTE PTR DS:[12FFCC],1
f8
修改成功
例子2,寄存器到内存
首先将eax
值改为-1
,然后执行指令
MOV DWORD PTR DS:[12FFCC],EAX
例子3,内存到寄存器
首先将eax
的值设置为0
,然后将[12ffcc]
的值写入到eax
中
MOV EAX,DWORD PTR DS:[12FFCC]
内存地址的5种形式
- 立即数
- [reg]寄存器,8个32位寄存器中的任意一个
- [reg+立即数]
- [reg+reg*{1,2,4,8}]
- [reg+reg*{1,2,4,8}+立即数]
能够认识就可以,但是这里没想明白为什么比例因子一定得是{1,2,4,8}
数据的存储模式
- 大端模式,数据高位在低位,数据低位在高位,手机arm架构通常是这种
- 小端模式,数据低位在低位,数据高位在高位,x86应用通常是这种
但是大端模式和小端模式是可以调整的,到不用纠结这个,能理解即可。
看个例子,内存地址[0012ffcc]
的值为FFFFFFFF
,使用指令进行赋值
MOV DWORD PTR DS:[12FFCC],1
成功赋值后,接着看左下角的内存展示区间
在框框中输入db 12ffcc
可以看到设定的对应值
注意
- db 以字节为单位看
- dw 以双字节为单位看
- dd 以四字节为单位看
设置内存值为1a2b
后,再次查看
发现2b
在1a
的前面,2b
的地址是12ffcc
,1a
的地址是12ffcd
,即在低位,写入数据时,2b
也是在低位的,即数据的低位在内存的低位,所以此程序的数据存储模式是使用小端模式的。