一、内存概述
-
寄存器与内存的区别:
- 寄存器位于CPU内部,执行速度快,但比较贵;内存速度相对较慢,但成本较低,所以可以做的很大
- 寄存器和内存没有本质区别,都是用于存储数据的容器,都是定宽的(都有最大的存储范围)
-
计算机常用的计量单位:
- BYTE 字节 = 8(bit)
- WORD 字 = 16(bit)
- DWORD 双字 = 32(bit)
-
生活中常用的计量单位:
- 1KB = 1024 BYTE
- 1MB = 1024 KB
- 1GB = 1024 MB
-
计算机的32位和64位内存是什么意思?
-
误区:不是说32位计算机寄存器或者内存的最大宽度为32bit!!而是CPU的最大寻址范围为32bit!其实32位计算机中也有很多寄存器是大于32位的,但是给一个地址让CPU去寻找比如二进制111010101、010101、1、…,只要不超过32位,CPU就可以根据地址来寻找内存活寄存器中编号是这个中的值
-
为内存编号:寄存器个数比较少,所以可以给每一个寄存器命名,比如eax,bx,ah等。内存的数量特别庞大,无法让每个内存单元都有名字,所以用编号来代替,编号就是地址,每一块内存单元都有编号(地址)
-
编号是怎么编的:32位,可以想成CPU上有32根线路,每根线路有0和1两个种状态,32根线每根线有两种情况,那么32个根线变化一次,可以代表一个值(二进制数),这个值就是一个编号。通过编号,就可以找到对应的内存!这些编号加在一起所有的情况就是能寻找的内存的范围
-
32位用十六进制表示:可以表示为8个十六进制数,计算机中以字节为最小单位,所以内存中每一个字节单位会有一个编号,即内存中以8bit为一个单位,为其编号。每一个编号对应内存中一个字节,即一个编号中可以存储8个0或者1组合
-
计算机内存编号一共有多少种可能:0xFFFFFFFF - 0x00000000 + 1 = 0x100000000种可能(也可以用十进制算32位,每一位都有0和1两种可能,组合起来232 = 4,294,967,296种可能),而我们说过一个内存编号对应8位即一个字节BYTE,那么现在算一算计算机可以识别多大的内存呢,先将BYTE化成KB:4,294,967,296 / 1024 = 4,194,304再换算成MB:4,194,304 / 1024 = 4,096;最后化成GB:4,096 / 1024 = 4GB。所以32位计算机能识别出4GB的内存。但是现在由于计算机有些硬件会占用一些内存,所以实际上显示的内存肯定小于4GB,你如果让CPU去找被硬件占用的内存,会找不到。
-
同理64位计算机能识别多大的内存:264 = 18,446,744,073,709,551,616(BYTE)。换算成TB为18,446,744,073,709,551,616 / 1024 /1024 /1024 /1024 = 16,777,216(TB)。但是会受到物理硬件的限制,实际能使用的到不了这么大
-
总结:32位还是64位的计算机由什么决定?跟寄存器的宽度没有关系,而是跟寻址宽度有关系,即CPU能寻找的内存编号的范围,每一个内存编号对应1字节,所以32位计算机能查找的最大内存范围4GB
-
-
扩展:32位计算机能识别的内存大小为4GB正确;但是32位计算机能识别的内存最多是4GB是不一定的!!!因为有些操作系统可以打补丁拓展寻址范围。但是一般情况下就是4GB
-
哪些地址可以访问:任何一个.exe程序在计算机上都有自己独立的4GB空间,但是这个是虚拟的,后面会讲到。我们使用汇编语言如果想访问这个程序的某地址,有些地址是无法访问的,程序不允许访问;那么怎么确定
-
我们在反汇编窗口、寄存器区域和堆栈窗口,写的和显示的十六进制数都是从高位写到低位,挨着顺序写;但是数据窗口中显示的是反着的,从低位显示到高位。比如我们写十六进制数b6 b3 7c e4,但是在数据窗口中会显示为e4 7c b3 b6。注意因为计算机中以字节为单位,也就是以内存块为单位,两个十六进制数刚好一个字节,所以每两个十六进制数当做一个整体,顺序是不变的,但是字节与字节之间(内存块与内存之间)的循序发生变化。所以**如果数据窗口中显示的数据为60 1a 82 7c,那么我们读到的数应该为7c 82 1a 60!**但是要注意:下图中堆栈一个地址可以表示4字节值,也就是4个内存块用一个地址表示。虽然0019ff74中存的数据要反,但是不能把0019ff78与0019ff74也弄反,因为不管在哪里,地址都是要挨着顺序写的
-
插件显示的命令的窗口的使用:
db 0x0019ff74 dd 0x0019ff74
d表示数据,b表示byte,后面的0x0019ff74表示内存地址。整命令的意思为为以一个字节为单位显示0x0019ff74地址对应内存块中的值,如果这个地址为栈中的地址,因为下面提到过,堆栈中用0x0019ff74可以表示0x0019ff74到0x0019ff77这四个内存块,所以一个0x0019ff74可以存4字节值,但是其实还是由4块内存存的,此时用此命令显示db 0x0019ff74会显示4字节的内容
dd 0x0019ff74显示如下:(注意,如果软件以4字节为一个单位显示数据窗口(跟堆栈一样),那么此时的顺序是不变的,软件自动帮你做反转)
二、内存地址格式
-
一般在汇编中,内存编号也用16进制数表示,立即数也有用十六进制的数写。那么我们怎么才能让计算机区分开呢?只要在内存编号的两侧加
[]
,如[0x12345678]
就表示一个内存编号,即地址 -
每个内存单位的宽度为8bit,
[编号]
称为地址,地址的作用是:当我们想从内存中读取数据或者想向内存中写入数据,首先应该找到要读、写的位置 -
内存编号是连续的。比如从上到下是[0x00000000]一直连续到[0xffffffff]。也可以从下到上,是自己决定的
三、内存相关汇编指令
-
格式:
mov dword ptr ds:[0x0012ff34],0x12345678
-
解释:
dword
表示要使用的内存大小为4个字节,即要读/写多少;还可以是byte和word等ptr
就表示代表后面是一个指针,即后面要跟内存编号(固定写法);DS
是段寄存器,32位汇编中段寄存器和内存的属性有关系:如果后面地址直接用数表示,则用DS
;如果后面写ESP或者EBP,就写SS
;如果EDI的话就用ES
。所以32位汇编中段寄存器就是后面内存属性的一个标识。[0x0012ff34]
表示后面的立即数存入内存的(起始)地址,如果前面是dword,表示从这个内存地址对应的一字节内存块开始存储(或读取),一共要存储(或读取)4字节内存,即4个内存块(因为一个地址对应一字节大小内存,那么一个编号可能不够存),即从[0x0012ff34]这个单元块开始存(或读),再往高地址存,依次往下,直到占用了4字节的内存,即从[0x0012ff34]
到[0x0012ff37]
都是用来存这个指令后面的数值的!0x12345678
就是存入内存的数值,称为立即数。如果立即数的宽度比前面指定的内存宽度大,则从低位开始取,取到指定的宽度,高位多余的部分就被丢弃,比如要写入dword,但是立即数为0x123456789,则最终写入的内存的值为0x23456789,一共4字节
-
注意:地址编号不要随便写,因为内存是有保护的,并不是所有的内存都可以直接读写。建议写表示栈的地址范围内的地址,即esp到ebp中存的地址之间的地址,一般建议要测试的话esp中存的地址值肯定可以使用
-
我们此时可能有疑问:前面不是说一个地址编号对应一个字节的内存块,但是上面0x0019ff74地址对应的内存中存的数为0x769dfa29,这个值大于一个字节,已经4个字节大小了,怎么能用一个地址编号表示?其实是因为,这里是用0x0019ff74到0x0019ff77来存储后面的4字节的值,但是这四块内存块用一个地址编号0x0019ff74(起始地址)表示,相当于一个用0x0019ff74表示0x0019ff74到0x0019ff77这四个内存块,这样看起来更整洁一些!
-
我们分开来看:0x0019ff74表示了四个内存块,四个内存块中的值一起显示为0x769dfa29。分开来看:0x0019ff74地址中的值为0x29;0x0019ff75地址中的值为0xfa;0x0019ff76地址中的值为0x9d;0x0019ff77地址中的值为0x76!(因为地址从低到高对应存的数也是从低位到高位,一个字节为一个整体,即小端存储)。所以可以发现OD其实已经帮我们把栈中的数据反过来了,用我们平时读写的顺序显示。这里要和VC6++中的内存分开,VC6++没有帮我们把数据反过来。
四、小作业
练习下面的指令,深刻理解寄存器、内存以及数据的宽度
1.MOV指令
-
MOV r/m8,r8
mov ah, ch mov byte ptr ds:[19FF78], dl
未执行前ah的值为FF,0x0019ff78中的值为0x003cf000;执行两条语句后,eax中的值变为0x001911CC,0x19ff78中的值变为0x003cf050
-
MOV r/m16,r16
mov ax,bx mov word ptr ds:[0x0019ff74],bp
eax中值变为0019f000;0x0019ff74中的值变为769dff80
-
MOV r/m32,r32
mov esp,esi mov dword ptr ds:[0x0019ff78],esp
esp中的值变为00401150;0x0019ff78中的值变为0019ff74
-
MOV r8,r/m8
mov bl,cl mov bl,byte ptr ds:[0x19ff74]
ebx中的值变为00306050;ebx中的值变为00306029
-
MOV r16,r/m16
mov sp,bp mov di,word ptr ds:[0x19ff7c]
-
MOV r32,r/m32
mov eax,ecx mov esp,dword ptr ds:[0x19ff80]
-
MOV r8, imm8
mov dh,0xaa
-
MOV r16, imm16
mov sp,0xaaaa
esp中的值变为0019aaaa
-
MOV r32, imm32
mov ecx,0xaaaaaaaa
2.ADD指令
-
ADD AL, imm8
ADD AL,0x11
-
ADD AX, imm16
ADD AX,0x1111
如果ax中的值与0x1111加完后值大于2字节,则高位部分舍弃,取低位的2字节值
-
ADD EAX, imm32
ADD EAX,0x10000000
-
ADD r/m8, imm8
ADD al,0x11 add byte ptr ds:[0x0019ff78],0x11
-
ADD r/m16,imm16
ADD AX,0x1111 add word ptr ds:[0x0019ff78],0x1111
-
ADD r/m32,imm32
ADD eax,0x12345678 add dword ptr ds:[0x19ff78],0x11111111
-
ADD r/m16, imm8
add ax,0x11 add word ptr ds:[0x19ff78],0x11
该怎么加怎么加,加完超过宽度的值,高位舍弃;这是前面的值宽度比后面值宽度大的情况;如果后面的值宽度比前面的容器宽度大,则后面的值在计算前就会舍弃多出来的高位
-
ADD r/m32, imm8
add edi,0x11 add dword ptr ds:[0x0019ff78],0x11
-
ADD r/m8, r8
add cl,0x11 add byte ptr ds:[0x19ff78],0x11
-
ADD r/m16, r16
add cx,0x1111 add word ptr ds:[0x19ff78],0x1111
-
ADD r/m32, r32
add eax,0x11111111 add dword ptr ds:[0x19ff78],0x10000000
-
ADD r8, r/m8
add bh,ch add bh,byte ptr ds:[0x11]
-
ADD r16, r/m16
add si,di add si,word ptr ds:[0x1111]
-
ADD r32, r/m32
add ebx,eax add edx,dword ptr ds:[0x10000000]
3.SUB指令
-
SUB AL, imm8
-
SUB AX, imm16
-
SUB EAX, imm32
sub eax,0xabcd1234
如果减出来后是负数,还是从低位到高位去取前面寄存器或者内存的宽度,高位舍弃
-
SUB r/m8, imm8
-
SUB r/m16,imm16
-
SUB r/m32,imm32
-
SUB r/m16, imm8
sub ax,0x1111 sub word ptr ds:[0x19ff78],0x1111
-
SUB r/m32, imm8
sub eax,0x1000 sub dword ptr ds:[0x19ff78],0x1000
-
SUB r/m8, r8
-
SUB r/m16, r16
-
SUB r/m32, r32
-
SUB r8, r/m8
-
SUB r16, r/m16
-
SUB r32, r/m32
4.AND指令
-
AND AL, imm8
-
AND AX, imm16
-
AND EAX, imm32
and eax,0x1a7c7771
自己算的话就先把十六进制换成二进制,再做运算
-
AND r/m8, imm8
-
AND r/m16,imm16
and si,0x1122
-
AND r/m32,imm32
-
AND r/m16, imm8
and ax,0xf8 and word ptr ds:[0x19ff78],0xf8
把低位对齐后再同1为1,不同为0做and运算
-
AND r/m32, imm8
-
AND r/m8, r8
-
AND r/m16, r16
-
AND r/m32, r32
-
AND r8, r/m8
-
AND r16, r/m16
-
AND r32, r/m32
5.OR指令
语法和and类似
- OR AL, imm8
- OR AX, imm16
- OR EAX, imm32
- OR r/m8, imm8
- OR r/m16,imm16
- OR r/m32,imm32
- OR r/m16, imm8
- OR r/m32, imm8
- OR r/m8, r8
- OR r/m16, r16
- OR r/m32, r32
- OR r8, r/m8
- OR r16, r/m16
- OR r32, r/m32
6. XOR指令
与and类似
- XOR AL, imm8
- XOR AX, imm16
- XOR EAX, imm32
- XOR r/m8, imm8
- XOR r/m16,imm16
- XOR r/m32,imm32
- XOR r/m16, imm8
- XOR r/m32, imm8
- XOR r/m8, r8
- XOR r/m16, r16
- XOR r/m32, r32
- XOR r8, r/m8
- XOR r16, r/m16
- XOR r32, r/m32
7.NOT指令
全部取反即可
-
NOT r/m8
-
NOT r/m16
-
NOT r/m32