计算机底层——二进制到汇编学习
1.概述
语言
机制
进制如何计算
二进制
数据宽度
有符号和无符号数
原码和反码
位运算
位运算计算
汇编
寄存器
内存
汇编指令
内存复制
堆栈的指令
汇编如何写函数
堆栈传参
堆栈平衡
外挂
2.机器语言
人和人的沟通?语言
和计算机的沟通?–>学习计算机的语言
什么是机器语言?
# 我们目前主流的计算机
状态 :0和1
# 最早的程序员:穿孔卡带
加 0100 0000
减 0100 1000
乘 0100 1000 0100 1000
除 0100 1000 1100 1000
这些复杂的机器语言,能够简化吗?
助记符!---->汇编语言
把人能够理解的语言转换成机器能够理解的语言
加 INC -编译器-> 0100 0000
减 DEC -编译器-> 0100 1000
乘 MUL -编译器-> 0100 1000 0100 1000
除 DIV -编译器-> 0100 1000 1100 1000
离程序的本质:隔阂!
汇编一般用于底层的编写、单片机…
C语言
加 A+B -编译器-> 0100 0000
减 A-B -编译器-> 0100 1000
乘 A*B -编译器-> 0100 1000 0100 1000
除 A/B -编译器-> 0100 1000 1100 1000
暴破
底层: VC6
3.进制
二进制?0 1
学习进制的障碍?——10进制
人类天然的选择就是10进制,10个手指头,跳出固有的思维方法!
思想:每一种进制都是完美的,都有自己的计算方式!
进制?
1进制:一进一,结绳记事,1 1
2进制:二进一,计算机,0 1
8进制:八进一,8个符号组成,0 1 2 3 4 5 6 7
19进制:十进一,10个符号组成,0 1 2 3 4 5 6 7 8 9
16进制:十六进一,16个符号组成,0 1 2 3 4 5 6 7 8 9 a b c d e f
进制的本质:就是一组符号,逢几进几。
测试:
# 一进制的1-20
1
1 1
1 1 1
1 1 1 1
1 1 1 1 1
......
# 三进制的1-20
0 1 2
10 11 12
20 21 22
100 101 102
110 111 112
120 121 122
......
# 七进制的1-20
0 1 2 3 4 5 6
10 11 12 23 24 25 26
20 21 22 23 24 25 26
100 101 102 103 104 105 106
110 111 112 113 114 115 116
......
问题:1 + 1 = 3?对吗?如何用进制来解决这个问题
答:自定义进制 1代表1,3代表2,此时1+1=3
进制的本质就是一组符号,逢几进几。
正常十进制: 0 1 2 3 4 5 6 7 8 9
自定义的十进制:0 2 4 7 8 a b r d f (是可以随便定义的,从学习别人的,到自己创造)
加密解密:程序员,破解程序的人!—> 进制的加密
数字量一大,总有规律。
4.进制的运算
# 八进制计算下面的结果
2+3=
2*3=
4+5=
4*5=
# 运算的本质就是查数
0 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 20 21 22 23 24 25 26 27 30 31...
2+3 = 2往后数3位=5
2*3 = 3个2位=6
4+5 = 4往后数5位=11
4*5 = 5个4位=24
# 八进制计算 乘法表 进位和计算
277+333 =
276*54 =
237-54 =
234/4 =
八进制的乘法表和加法表:
277
333 +
---------------
632
276
54 *
---------------
1370
1666 +
---------------
20250
# 减法的本质就是加法
237
54 -
-----------
163
# 除法的本质就是乘法的倒数,除数乘哪个数最接近结果即可
234
4 /
------
47
结论:无论什么进制,本身都是有一套完美的运算体系的,我们都可以通过列表的方式将它计算出来。
5.二进制
计算机使用二进制 0 1!
电子计算机:使用电子模拟0和1
物理极限:摩尔定律!硬操作!
追求语言的极限,并发语言!软操作!
量子计算机:可以实现量子计算的机器
传统的计算机:集成电路! 0 1,硅晶片!
量子计算机的单位:昆比特(量子比特),量子的两态来表示。
光子:正交偏振方向
磁场:电子的自旋方向
结:不一定只能使用电子来模拟0和1
21世纪,传统的计算力快到尽头了,纳米级!【落伍】本质问题
量子计算机—提高计算机的计算力
计算机的发展到了21世纪20年代,计算力是永远无法避开的话题。许多编程语言因为计算力无法再提高而“落伍”,而一些“并发”的编程语言也因此而备受青睐。但是,针对编程语言去提高计算力的效果是很微弱的。这就好比你有一块牛肉,你想通过烹饪想去将它做的好吃。
量子计算机和这些都不同,它的核心是提高计算机的计算力,甚至让计算机做一些现在人类无法想象的事情,例如量子方程式等。这就好比你有一块原料更好的牛肉,或许你就不需要在烹饪下面下功夫了。
量子比特、量子叠加态、量子纠缠、量子并行原理…
量子计算机(quantum computer),是一种全新的基于量子理论的计算机,遵循量子力学规律进行高速数学和逻辑运算、存储及处理量子信息的物理装置。量子计算机的概念源于对可逆计算机的研究。量子计算机应用的是量子比特,可以同时处在多个状态,而不像传统计算机那样只能处于0或1的二进制状态。
2019年,Google研究人员展示其最新54比特量子计算机,该计算机只用200秒便可计算完毕当前世界最大的超级计算机需1万年进行的运算。
2020.6.18,霍尼韦尔的量子计算机的量子体积是64,并且霍尼韦尔称,未来五年内能够实现量子体积每年以一个数量级的速度增长。霍尼韦尔还表示,将在一年之内得到至少10个有效量子比特,相当于1024个量子体积。
电子计算机---->量子计算机
现在的电子计算机:
二进制 0 -1111的16个状态
0 1 10 11 100 101 110 111 1000 1001 1010 1011 1100 1101 1110 1111
二进制这么写很麻烦,二进制能否简写?
# 用十六进制简写二进制
0 1 2 3 4 5 6 7 8 9 a b c d e f
这就是十六进制!
为什么要学习二进制?
寄存器、内存、位!底层的每一位都是有含义的(每一个0,1都有自己的状态)。汇编入门的基础!
汇编高级:了解程序的深层!操作系统的内核?
6.数据宽度
计算机内存有限度,要给数据增加数据宽度
C、C++和Java都需要定义数据的类型,计算机底层需要我们给这些数据定义宽度。
- 位 0 1
- 字节 8bit 0-0xFF
- 字 16bit 0-0xFFFF
- 双字 32bit 0-0xFFFFFFFF
在计算机中,每个数据都需要给它定义类型,给它定义宽度,在内存中的宽度。
7.有符号数无符号数
数据都是有宽度的,每个数据代表什么意思?
二进制前面的0 是可以省略的。
0 1 0 1 0 1 0 1
**规则:**二进制解码增加一个规则?
(对于数字而言,正数还是负数?)
无符号数规则:
数字是什么,那就是什么
10011010 十六进制:0x9A 十进制:154
有符号数规则
最高位是符号位:1(负数) 0(正数)
10011010 如何转换?
8.原码反码补码
编码规则:
有符号数的编码规则:
- 原码:最高位符号位,对其它位取绝对值即可
- 反码:
- 正数:反码和原码相同
- 负数:符号位一定是1,其余位对原码取反
- 补码:
- 正数:补码和原码相同
- 负数:符号位一定是1,对反码+1
测试:
# 现在用的都是8位的
# 如果是正数,原码、反码、补码都相同
1
# 原码 0 0 0 0 0 0 0 1
# 反码 0 0 0 0 0 0 0 1
# 补码 0 0 0 0 0 0 0 1
-1
# 原码 1 0 0 0 0 0 0 1
# 反码 1 1 1 1 1 1 1 0
# 补码 1 1 1 1 1 1 1 1
-7
# 原码 1 0 0 0 0 1 1 1
# 反码 1 1 1 1 1 0 0 0
# 补码 1 1 1 1 1 0 0 1
3 + 5 = 8(10进制)
3 + 5 = 11 + 101 = 1000(二进制)
2 10
4 100
8 1000
16 10000
如果看到一个数字,二进制的,需要了解它是有符号数还是无符号数。
寄存器:mov寄存器 32位寄存器 存值
计算机中如何存值?
- 正数直接存(原码、反码、补码都是一样的)
- 负数是以补码方式存。
9.位运算
计算机可以存储所有的数字、运算。
0 1
位运算的规则?
2*8的最高效计算方式——通过位运算 2<<3 左移三位,3次 乘2
很多的底层调试器,需要通过位运算来判断CPU的状态
与运算(and &)
(电子计算机的本质:通过电位来控制)
1011 0001
1101 1000 &
-------------- 与运算结果
1001 0000
或运算(or |)
1011 0001
1101 1000 |
-------------- 或运算结果
1111 1001
异或运算(xor ^)
相同为0,不同为1
1011 0001
1101 1000 ^
-------------- 异或运算结果
0110 1001
非运算(单目运算符 not ~)
1就是0,0就是1
1101 1000
------------- 非运算
0010 0111
通过以上可以完成加减乘除,位运算来实现加减乘除!
位运算(移动位 单目运算符)
左移 *2;右移 /2
左移:(shl <<)
# 所有的二进制位全部左移若干位,高位就丢弃,低位补0
0000 0001
0000 0010
右移:(shr >>)
# 所有的二进制位全部右移若干位,低位就丢弃,高位补0还是1由符号位决定
0000 0001
0000 0000
0000 0001 1
0000 0010 2(上面左移1位)
0000 0100 4(上面左移1位)
0000 1000 4(上面左移1位)
汇编的本质就是直接操作二进制!
10.位运算的加减乘除
计算机只认0 1
基本数学是建立在加减乘除。(加法)
4+5?
# 计算机是怎么操作的
0000 0100
0000 0101
----------(加法,计算机是不会直接加的)
0000 1001
# 计算机的实现原理
# 第一步,异或,如果不考虑进位,异或可以直接获得结果
0000 0100
0000 0101
----------
0000 0001
# 第二步,与运算,判断进位(如果与运算结果为0,没有进位)
0000 0100
0000 0101
----------
0000 0100
# 第三步,将与运算的记过左移一位,获得进位的结果
0000 0100
----------
0000 1000
# 第四步,异或运算,将第一步异或的结果与进位的结果,进行异或运算
0000 0001
0000 1000
----------
0000 1001
# 第五步,与运算(判断进位,如果与运算结果为0,则没有进位)
0000 0001
0000 1000
---------
0000 0000
# 所以最终结果就是与运算为0的结果的上一个异或运算结果
# 整体过程就是 :
# 异或运算-与运算判断进位- 进位则左移获得进位结果-异或运算结果与进位结果异或运算-与运算判断进位......
# - 结果为0 则没有进位,上一个异或运算的结果就是最终计算结果
4 + 5 = 9
0000 0100 + 0000 1000 = 0000 1001
4-5?
# 计算机是怎么操作的?
4-5=4+(-5)
0000 0100
1111 1011 -5的补码 1111 1011【计算机保存的都是补码形式,只是正数补发与原码相同】
----------(减法法,计算机是不会直接减的)
1111 1111 ff(-1)
# 第一步,异或运算
0000 0100
1111 1011
----------
1111 1111
# 第二步,与运算,判断进位
0000 0100
1111 1011
---------
0000 0000
# 与运算结果为0,没有进位,最终结果就是1111 1111 16 ff -1
乘法:x*y,就是y个x相加,还是加法
除法:x/y,本质就是减法,就是x能减去多少个y
计算机只会做加法!
机器语言就是位运算,都是电路来实现的,这就是计算机最底层的本质。
通过机器语言实现加法运算,设计电路。
11.汇编语言环境说明
通过指令来实现加法运算,设计电路。
通过汇编指令可以给计算机发出一些操作,然后让计算机执行,编译器的发展,底层的大佬,几乎都是原始的IDE。
在学习汇编之前,大家需要先掌握环境的配置:
-
Vc6 (程序到汇编的理解)
-
OD (吾爱破解)
-
抓包工具
-
加密解密工具
**学汇编不是为了写代码!**是为了理解程序的本质。懂汇编,可以理解一切!
《汇编语言》 16位的汇编 32位 32位(本质架构区别不大,只是寻址能力增加)
汇编入门:了解汇编和程序的对应关系,程序的本质即可!
汇编的基本:寄存器、内存、汇编指令
12.通用寄存器
寄存器:
存储数据:CPU>内存>硬盘
32位 CPU 8 16 32
64位 CPU 8 16 32 64
通用寄存器:可以存储任意的值
# 32位的通用寄存器只有8个
EAX
ECX
EDX
EBX
ESP
EBP
ESI
EDI
存值的范围:0-FFFFFFFF
对于二进制来说,直接修改值。
计算机如何向寄存器存值?
mov指令
mov 存的地址,存的数
mov 存的地址1,存的地址2
可以将数字写入寄存器,可以将寄存器中的值写到寄存器
计算机:计算力
不同的寄存器
8个F 4个F 2个F
32位 16位 8位(8位:L低8位,H高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
除了这些通用寄存器之外,那么其他的寄存器每一位都有自己特定的功能!
13.内存
寄存器很小,不够用,所以说,要把数据放到内存!
平时买的内存条。
每个应用程序进程都有4G的内存空间。空头支票(虚拟内存)
程序真正运行的时候,才会用到物理内存。
1B = 8bit
1KB = 1024B
1MB = 1024KB
1GB = 1024MB
4G的内存,4096MB–>最终计算为位,就是这个可以存储的最大容量。
计算机中内存地址很多,空间很大。
内存地址
存一个数:占用的大小,数据宽度!存到哪里?
计算机中内存地址很多,空间很大,为每个空间分配一个地址,取名字
给内存起的编号,就是我们的内存地址,32位 8个16进制的值。
32位:寻址能力!4GB
FFFFFFFF + 1 = 100000000,最大的值。(除了FFFFFFFF,还有最开始的0,故一共100000000个)
位是怎么限制内存大小的?
1000000000 (内存地址有100000000个) * 8(一个地址存8位) = 位 800000000(即能存800000000位,800000000个0/1)
转换为10进制/8 得到字节B 4294967296字节
按照规则/1024,最终得到的就是4GB!
64位,绰绰有余!
每个内存地址都有一个编号!可以通过这些编号向里面存值。
内存如何存值?要知道:
- 数据宽度:byte word dword
- 地址的位置:0xFFFFFFFF
不是任意的地址都可以些东西的,申请使用的。只有程序申请使用过的内存能看到
# 汇编语言如何向内存中写值
move 数据宽度 内存地址,值
move byte/word/dward/qword,1
move byte ptr ds:[0x0019FF74],1(会自动把值转成16进制)
move dword ptr ds:[0x0019FF78],1
传递的值的大小一定要和数据宽度相等,不能超出限制!
内存地址的多种写法
ds:[0x0019FF74]
ds:[0x0019FF0+4] //+4 表示内存地址偏移
ds:[eax] // 表示将寄存器EAX中的值,写入到内存??
ds:[eax+4] // 表示寄存器偏移
数组[]
# 数组开辟空间,是通过寄存器*一个数字{1,2,4,8}其中一个
ds:[reg+reg*{1,2,4,8}]
ds:[reg+reg*{1,2,4,8}+4] //偏移