汇编
1、课程概要
1、什么是机器语言
加:0100 0000 减:0100 1000 乘:1111 0111 1110 0000 除:1111 0111 1111 0000
缺点:不方便记忆
2、汇编语言:
由机器语言发展而来,可用符号表示数值间的运算
加:INC EAX → 0100 0000 减:DEC EAX 0100 1000 乘:MUL EAX 1111 0111 1110 0000 除:DIV EAX 1111 0111 1111 0000
优势:相对于机器语言,更简单 劣势:不符合人类的思维范式
编译器: 可将汇编指令转换为机器语言的工具
3、C语言:
加:A+B 0100 0000 减:A-B 0100 1000 乘:A*B 1111 0111 1110 0000 除:A/B 1111 0111 1111 0000
C语言属于高级语言,更加贴近人类的思维方式
4、C与C++的关系
C与C++其实没有本质区别,只是编译器做的事情越来越多,越来越强大
C语言是C++的基础
5、学习汇编的原因
一个不懂汇编的人,都是不懂原理的
如果从事安全行业,汇编是必须要掌握的基础(外挂开发等)
对于正向开发,懂汇编可以做的更好,潜力更大
6、学习环境
VC6
VS2010,2013,2016
选择VC6的原因:越是新版本的编译器,在编译的时候添加的细节代码会更多,不利于学习
2、进制
1、学习进制的原因
计算机只认识二进制,为了更好理解计算机,就需要深刻理解进制
2、学习进制的障碍
总以十进制为依托,需要运算的时候也是先转换为10进制,这种学习方法是错误的
想要学好进制,就要先忘掉十进制,忘掉进制间的转换
3、进制的定义
进制
组成
规则
八进制
有八个符号组成,0 1 2 3 4 5 6 7
逢八进一
十进制
有十个符号组成,0 1 2 3 4 5 6 7 8 9
逢十进一
N进制
有N个符号组成
逢N进一
4、进制的书写
在进制的运算中,没有必要对进制进行转换,可以直接进行计算
进制
写法
1
0,1,11,111,1111,11111
3
0,1,2,10,11,12,21,22
7
0,1,2,3,4,5,6,10,11,12
5、你能理解1+1=3吗?
学习进制,就要理解进制的深度,而不是表面现象
如果将进制用在加密解密方向,就会给解密的人带来很大的困扰
3、进制的运算
每一种进制的体系都是完美的,不需要转换成其他进制进行运算
1、八进制运算
2+3=?(5) 2*3=?(6) 2+3=?(5) 4+5=?(11) 4*5=?(24) 277+333=?(277+333=7+3(12)+(130)+2+4(6)=632) 276*54=?() 237-54=?() 234/4=?()
0,1,2,3,4,5,6,7,10,11,12,13,14,15,16,17,20,21,22,23,24
2+3为从2开始,往后查3个数,其他相同
制作八进制的加法表与乘法表:
0,1,2,3,4,5,6,7,10,11,12,13,14,15,16,17,20,21,22,23,24,25,26,27
乘法表的本质,也是查询数字
进制总结: 每种进制都是完美的,他自身就是一个完整的体系,可以直接进行各种运算
4、二进制简写形式
1、计算机为什么使用二进制
计算机是需要用电的,电路只有两种状态:1 真(通电),0 假(未通电) 。 计算机中存储的任何文件,接收的任何指令都是由0和1组成的(查看一个.exe程序)
查看EXE文件使用工具为:UltraEdit
其中内容为:
文件的地址位:文件中的内容:UE的注释
2、二进制的简写形式
二进制:从0写到1111 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
这种二进制使用起来太麻烦,改写成更简单一点的符号:
0 1 2 3 4 5 6 7 8 9 A B C D E F 这就是十六进制了,中国古代时候已经开始使用十六进制了
建议:写代码的时候要习惯十六进制,最好不要用十进制
十六进制:可读性更强
3、熟练掌握进制之间的转换
5、数据宽度
1、数据宽度
数学上的数字,是没有大小限制的,可以无限大,但在计算机中,由于的硬件制约,数据都是有长度限制的(数据宽度),超出宽度的数据会被丢弃
2、计算机中常见的数据宽度
单位
宽度
存储范围
位(BIT)
1
0-1
字节(BYTE)
8
0-FF
字(WORD)
16
0-FFFF
双字(DOUBLEWORD)
32
0-FFFFFFFF
位是计算机中存储数据的最小单位 一个字节能存储8个位 字有16位 双字能存储32个位
讲解中的示例代码:
6、有符号数和无符号数
在不同文件中,0和1的含义都是不同的
1、无符号数的编码规则
十六进制显示的话,则是:0x9A,十进制是:154 文件不同,解析方法不同
2、有符号数,正数编码规则:1A
如果最高位是1,则为负数;如果最高位是0,则为正数
如果一个数是有符号数,且最高位是0,那么这个数一定是正数
当数字为正数时,有符号与无符号的显示结果是一样的
7、数字的编码
1、编码规则
不同的文件有不同的编码规则 有符号数与无符号数解析成果是一样的,若首位是0 负数的编码规则与正数不同
2、有符号数的编码规则
原码:最高位为符号位,其余各位是数值本身的绝对值 反码: 正数:反码与原码相同 负数:符号位为1,其余位对原码取反 补码: 正数:补码与原码相同 负数:符号位为1,其余位对原码取反加1
3、举例说明
例子
原码
反码
补码
1
0000-0001
0000-0001
0000-0001
6
0000-0110
0000-0110
0000-0110
-1
1000-0001
1111-1110
1111-1111
-7
1000-0111
1111-1000
1111-1001
总结:
正数原码存储(编码规则)
负数补码存储(编码规则)
4、假设数据宽度为1BYTE(8 BIT)
无符号数:0 1 2 3 4 5 ........ FF (10进制255) 有符号数: 正数:0......7F 负数:FF......80
5、假设数据宽度为DOUBLEWORD(双字)
无符号数:0 1 2 3 4 5 ........ FFFFFFFF 有符号数: 正数:0......7FFFFFFF 负数:FFFFFFFF......80000000
8、计算机的运算
计算机是通过位运算来做的运算
为什么要学习位运算?
有些功能必须通过位运算才能实现:比如写调试器,判断CPU的各种状态位
大公司面试题:比如2*8的效率最高的实现方式
1、与运算 and(&)
两个数都为1时,结果才是1
比如:1011-0001&1011-0000=10010000
2、或运算 or (|)
只要有一个为1就是1
比如:1011-0001|1101-1000=1111-1001
3、异或运算 xor(^)
不一样的时候是1
比如:1011-0001^11011000=01101001
4、非运算 not(~)
0就是1,1就是0 注意:非运算只需要一个数字,单目运算
比如:1101-1000 = 0010-0111
5、移位运算
5-1、左移: 各二进位全部左移若干位,高位丢弃,低位补0 比如: shl(<<) 1101-1000左移2位为: 0110-0000
5-2、右移: 各二进位全部右移若干位,低位丢弃,高位补0或者补符号位
比如:
在C语言中,如果数字是无符号的,那么在移动后会补0;若是有符号的,那就是补符号位
6、总结:计算机只会做位运算
9、位运算之加减乘除
4+5的运算过程:
4:0000-0100,5:0000-0101
4+5的异或运算:0000-0001
如果不考虑进位的情况下,异或的结果与按位加的结果是一样的
异或类似于按位加,此时必须判断有无进位,如果有进位,就要拿出来进位的值再加
判断是都有进位(只有两个数相加的时候才会有进位),进行与运算。若结果不为0,则说明有进位
判断标准:哪个数字是1,那就说明哪里有进位
异或与按位加是一样的结果,只是拿掉了进位的值
继续异或,将(上次异或出来的结果)与(进位得到的数字左移一位后)继续异或预算
使用与运算,判断是否有进位。若得到结果为0,则说明没有进位
得出最终结果
过程简化后:
异或运算:两数字进行异或运算(结果为C)
与运算:判断两数字进行与运算时是否有进位(结果为D)
异或运算,用C与D进行异或运算,得出最终结果(结果为E)
与运算,用C与D进行与运算,若结果为0,则E为最终结果
4-5的运算过程:
4-5=4+(-5)
异或运算:0000-0100 异或 1111-1011=1111-1111
与运算:判断是否有进位:0000-0100与1111-1011=0000-0000
说明第二步的运算结果就是最终结果,1111-1111:FF,-1
乘法的运算过程: X*Y的本质就是加法:Y个X相加
除法的运算过程: X/Y的本质就是减法:X能减去多少个Y
10、汇编学习环境搭建
1、学汇编不是为了写代码
学汇编的目的:了解程序的运行机制,汇编是高手的必经之路
正常应用:需要明白C语言等于汇编的对应关系
安全:做外挂以及反外挂等,需要了解汇编与二进制的关系。PE与硬编码也需要了解
课堂讲的是32位的汇编,不是win32汇编。 笔记程度:可看懂普通的应用程序
若想研究擦做系统之类的,需要了解保护模式等相关内容
2、配置汇编的学习环境
DTDEBUG下载
配置路径
当想使用OD编写汇编代码时,可随便拖拽一个EXE文件进去,可看到如下页面
当左上角显示黄色时,说明程序已暂停,此时可双击右面的汇编代码并打开窗口,并在新开的窗口中编写汇编代码
窗口名称:从左往右依次为:反汇编窗口,寄存器,内存窗口与堆栈
11、通用寄存器
1、寄存器
存储数据: CPU>内存>硬盘 32位CPU:8 16 32 64位CPU:8 16 32 64
寄存器:CPU用来存储数据的地方 若是32位CPU,有提供容器有3种类型,为8位16位,32位 若是64位CPU,有提供容器有4种类型,为8位16位,32位,64位
学习32位汇编的理由:
64位CPU与32位CPU并没有实际的变化,只是增加了新的寄存器,汇编指令都是一样的。若掌握了32位汇编,可以直接看懂64位汇编
绝大多数程序都是32位的
2、通用寄存器
32位通用寄存器: 在32位寄存器中,大多数寄存器有特殊用途 在32位的寄存器中,存储的数据不能超过32位,也就是不能超过32个0和1,否则多余的部分会被丢弃
名称
编号
数据存储范围
EAX
0
0 - 0xFFFFFFFF
ECX
1
0 - 0xFFFFFFFF
EDX
2
0 - 0xFFFFFFFF
EBX
3
0 - 0xFFFFFFFF
ESP
4
0 - 0xFFFFFFFF
EBP
5
0 - 0xFFFFFFFF
ESI
6
0 - 0xFFFFFFFF
EDI
7
0 - 0xFFFFFFFF
不同位数的通用寄存器
32位
16位
8位
EAX
AX
AL
ECX
CX
CL
EDX
DX
DL
EBX
BX
BL
ESP
SP
AH
EBP
BP
CH
ESI
SI
DH
EDI
DI
BH
其中,L代表低八位,H代表高八位
2、MOV指令
作用:移动数据
汇编可理解为:寄存器与寄存器之间,寄存器与内存之间数据的来回流动 想学好汇编需要记住的关键词:寄存器,内存,指令
立即数到寄存器
寄存器到寄存器
若想执行语句,可点击F8,执行后,寄存器的语句会变成红色
也可以将寄存器中的值传到另一个寄存器中,例:
其中,因为eax中的值为1,所以edx的值也是1
八位寄存器:
注意:寄存器之间的数值移动,需要位数相同,若位数不同,会报错,不符合语法
12、内存
当存储数据足够多的时候,可将数据存储到内存中
内存:并不是内存条
1、每个应用程序都会有自己独立的4GB内存空间
其中,每个进程的4GB内存空间并不是真正的物理内存,是假的 当进行读写操作时,会将进程中额内存映射到物理内存中 物理内存与内存条之间,还有一层映射
在编程过程中,提到的内存,往往指的是4GB的虚拟内存
1Byte=8BIT 1KB=1024Byte 1MB=1024KB 1GB=1024MB 1TB=1024GB 1PB=1024TB
2、内存地址
内存太大没办法起名字,所以只能用编号当我们想想内存中存储数据时,或者从内存中读取数据时,必须用到这个编号,就像写信必须要写收信人一样
这个编号又叫内存地址(32位,前面的0可以省略)
对于编程人员来讲,内存与寄存器都是用来存储数据的容器,故内存太大了,就用编号代替
其中:
[0x00000000]称为内存地址,为内存块,是8位一字节
在读和写的时候,必须使用内存地址
内存地址有32位,如果转换成16进制的话,就是8位
因为地址宽度是32位,宽度决定了能查找的最大的范围就是4GB,值最大为100000000
计算过程:
16进制最大寻址范围是FFFF-FFFF,加一后为10000-0000
因为每个字节是8位,乘以8就是1-0000-0000
转换成10进制,得到数字:34359738368
除以8以后得出结果为:4294967296
除以1024后,得出结果为:4194304(能找到的KB的数量)
除以1024后,得出结果为:4096(能找到的MB的数量)
除以1024后,得出结果为:4(能找到的GB的数量)
所以,每个进程都有自己的4GB的内存空间
注意:
内存必须有地址,这个地址的宽度是32位的
每个地址对应的内存有一个字节8位,8个0和1
3、MOV指令
立即数到内存
寄存器到内存
内存到寄存器
语句含义:将1写到内存中,写到1个字节中 ptr ds:[] 为地址编号,方括号中的内容不可以随便写,必须是已经申请了的地址
填入地址后,点击确定即可
其中,宽度为8,点击F8后:
注意:向内存中写数据的时候,一定要告诉他宽度是多少
其中: DWORD代表要写的内存有多大,数据宽度是多少 ptr ds:[]是固定写法 []中的内容,就是地址,也可称为编号 每一个编号对应的是一个字节
编号是连续使用的
可以将立即数写到内存中,也可以将寄存器写到内存中,但前提是:宽度必须是一样的
注意: 在使用MOV指令的时候,要保证两边的宽度是一样的
将内存中的值写入寄存器中:
在汇编中,就大多数指令是不允许从内存到内存的,其中包括MOV指令;必须经过寄存器;也不能从内存到立即数。立即数不是容器,只能往别的东西里放
涉及代码:
内存的五种表示形式:
立即数:
读取内存的值:MOV EAX,DWORD PTR DS:[13FFC4]
向内存中写入数据:MOV DWORD PTR DS:[13FFC4],EAX
[reg] reg代表寄存器,可以是8个寄存器中的任意一个
读取内存的值:MOV EAX,13FFD0 ; MOV EAX,DWORD PTR DS:[ECX]
向内存中写入数据:MOV EDX,13FFD8 ; MOV DWORD PTR DS:[DEX],87654321
[reg+立即数]
读取内存的值:mov ecx,13ffd0 ; mov eax,dword ptr ds:[ecx+4]
向内存中写入数据:mov edx,13FFD8 ; MOV DWORD PTR DS:[EDX+0xC],87654321
[reg+reg*{1,2,4,8}] #在高级语言中对数组赋值,最终生成的汇编语言就是这样的 八个32位的通用寄存器加上八个32位的通用寄存器乘以1或2或4或8
读取内存的值:MOV EAX,13FFC4 ; MOV ECX,2 ; MOV EDX,DWORD PTR DS:[EAX+ECX*4]
向内存中写入数据:MOV EAX,13FFC4 ; MOV ECX,2 ; MOV DWORD PTR DS:[EAX+ECX*4],87654321
[reg+reg*{1,2,4,8}+立即数] #
读取内存的值:MOV EAX,12FFC4 ; MOV ECX,2 ; MOV EDX,DWORD PTR DS:[EAX+ECX*4+4]
向内存中写入数据:MOV EAX,13FFC4 ; MOV ECX,2 ; MOV DWORD PTR DS:[EAX+ECX*4+4],87654321
学习五种形式的作用:看得懂各式编译器反编译出来的汇编代码
13、数据的存储模式
1、存储模式
大端模式:数据高位在低位,数据低位在高位 小端模式:数据低位在低位,数据高位在高位
2、3、4、
14、
15、
16、
17、
18、
19、
20、
21、
22、
23、
24、
25、
26、
最后更新于