dustland

dustball in dustland

起来,不愿作板儿砖的计算机

起来,不愿作板儿砖的计算机

"pull oneself up by one's bootstraps"拉着自己的鞋带站起来

BIOS

BIOS做的事情

  1. Power is turned on.
  2. The CPU hands control over to the BIOS.
  3. The BIOS runs a program called Power-On Self Test, which determines how much memory the computer has and then confirms that critical low-level hardware is operating correctly. Any errors are indicated by sequences of audible beeps. After this, the BIOS disables all configurable devices.
  4. The BIOS identifies all of the computer's peripheral devices, such as hard drives and expansion cards. It first looks for plug-and-play devices and assigns a number to each, but it doesn't enable the devices at this time.
  5. The BIOS locates the primary boot or initial program load (IPL) device. This is usually a storage device such as a hard drive, floppy drive or CD-ROM that holds the operating system, but it can be a network card connected to a server. The BIOS also locates all of the system's secondary IPL devices.
  6. The BIOS builds a system resource table, assigning conflict-free resources according to which devices it found and the configuration data stored in nonvolatile RAM.
  7. It selects and enables the primary input (keyboard) and output (monitor) devices, so that if trouble occurs during the boot process, the BIOS can display a recovery screen and allow the user to select a stored configuration of system settings that are known to work. The BIOS captured these settings the last time the computer booted successfully, and it stores them in nonvolatile RAM.
  8. It scans for non-plug-and-play devices, including the Peripheral Component Interconnect (PCI) bus, and adds data from their ROMs to its resource table.
  9. The BIOS resolves device conflicts and configures the chosen boot device.
  10. It enables plug-and-play devices by calling their option ROMs with appropriate parameters.
  11. It starts the bootstrap loader. If, for some reason, the default IPL fails to load the operating system, the BIOS tries the next IPL device in the list.
  12. The IPL device loads the operating system into memory.
  13. The BIOS hands over control to the operating system, which may make other resource assignments.

1.上电

2.CPU将控制交给BIOS

3.BIOS开始上电自检,用来检查计算机内存大小,检查底层硬件是否正常运作.

只要有错就用蜂鸣器发出相应的叫声.

此后,BIOS禁用所有可配置设备(刚才检查的时候算是暂时启用了一下)

我装在commando上的kali物理机每次开机都会用最大声音"Bee"一下,不太聪明的亚子

4.BIOS识别计算机的所有外设,比如硬件驱动器和拓展卡(比如独立网卡独立显卡).

BIOS首先搜索所有即插即用式设备并为每个设备编号,但是此时并不将这些设备使能

5.BIOS定位主引导程序或者初始化加载程序设备.这种设备通常是一个存储设备比如硬盘,软盘,或者光驱,该设备上应当编程有操作系统,该设备甚至还可以是连接到一台服务器的网卡(这个有点离谱了)

6.BIOS 建立一张系统资源表,根据它找到的设备和存储在非易失性 RAM 中的配置数据分配无冲突资源。

7.BIOS使能基本输入(键盘)和输出(显示器)设备,如此当此后的启动过程中万一发生错误,BIOS可以打印打印恢复选项屏幕,并且让用户选择一个系统设定,然后BIOS遵旨继续执行.

BIOS会保存最后一次计算机成功启动时的设定,用那一次的设定进行恢复,这些设置被保存在非易失性RAM中

8.BIOS扫描所有即插即用式设备,包括外设总线,并将这些设备的ROM中的数据添加到刚才建立的资源表中

9.BIOS解决设备冲突,确定boot所在的设备

10.BIOS通过使用适当参数,调用即插即用式设备的选项ROM,使能这些设备

11.BIOS启动bootstrap loader.

如果默认的IPL(InitialProgramLoader)(第9步设置的设备)不能装载操作系统,则BIOS尝试列表中的下一个IPL设备

12.IPL设备将操作系统装载进入内存

13.控制权交给操作系统,操作系统将进行其他资源分配

到此计算机启动完毕,BIOS完成使命

BIOS设置

Main视图

在我的ubuntu10.04 虚拟机上,开机的时候根据提示按下F2就可以进入BIOS选择阶段

image-20220613140700106

可见BIOS这么小的系统也已经图形化了

在Main视图下,可以修改系统日期时间

Legacy Diskette

设置软驱,都2202年了,不会有人还在用软驱吧,不管他了

Primary/Second Master/Slave

Primary Master/Slave不是"主要大师/奴隶",是设置主IDE的主从通道

image-20220613141246521

IDE是啥?Integrated Drive Electronics,"把控制器和盘体集成的硬盘驱动器"

我不想下到硬件看看接口是什么样的了,就认为IDE是接硬盘的

如果IDE硬盘接到IDE通道的主通道(Primary)则BIOS将其作为引导盘

Keyboard Features

"键盘特性"

image-20220613142143514

NumLock

里面有一个NumLock,数字锁,也就是键盘上最右边的数字小键盘锁,Off则开机自动关闭,不让用数字键,On则开机自动开启.即使这里是Off,也可以在开机时自己按键盘上的NumLock改变状态

Keyboard auto-repeat delay: [1/2 sec]

考虑这么一长串字符你会怎么输入aaaaaaaaaaaaaaaaaaa,是不是按住a一直不放.

有没有注意过,但是按一下a,只会输出一个a,即使手稍微慢一点,也是只会输出一个a,并没有趁机写好几个a,从单输入第一个a到计算机认为需要连续获取输入之间的时间就是这个设置,

这里设为1/2秒,即按下a之后不松开,过半秒之后就获取一长串输入

Keyboard auto-repeat rate: [30/sec]

这个是啥呢?在键盘开始一长串输入后,每秒内输入几个a呢?100个?10个?1000个?

如果是1000,那么一旦Keyboard auto-repeat delay开关被打开,则眨眼间写入了百八十个a,写太多了,又要长按Backspace退格删除,Keyboard auto-repeat delay开关又被打开,呼哧一下删了百八十个a,甚至之前写的东西也退掉了.

显然1000这个数灵敏度太高,在我的windows上大约是20个左右,确切是多少我也不知道,重新开机看看吗,那个时候又没法截图

在这个ubuntu虚拟机上可以看见是30个

这里三个设置是根据用户习惯设置的,为人性化设置的

Memory

然后展示了两个内存

image-20220613143304212

就让看看,根本不让改

两个内存分别是啥呢?

去中文站点儿查,就给说"System Memory是系统内存",这傻子都会翻译还tm用你说,什么系统的内存啊?

Boot-time Diagnositc Screen

启动时诊断屏幕,这是个啥呢?

给他改成Enable然后重启看看,开机的时候会有一两秒的这个页面

image-20220613151050418

没有错误的就"Passed"或者"initialized"

Advanced视图

"高级"

image-20220613151239709
Multiprocessor Specification

"多处理器规范"

参考

MultiProcessor Specification - Wikipedia

MultiProcessor Specification (mit.edu)

The MultiProcessor Specification (MPS) for the x86 architecture is an open standard describing enhancements to both operating systems and firmware, which will allow them to work with x86-compatible processors in a multi-processor configuration. MPS covers Advanced Programmable Interrupt Controller (APIC) architectures.

Version 1.1 of the specification was released on April 11, 1994. Version 1.4 of the specification was released on July 1, 1995, which added extended configuration tables to improve support for multiple PCI bus configurations and improve expandability.

The Linux kernel and FreeBSD are known to support the Intel MPS. Windows NT are known to support MPS 1.1 and Windows 2000 or higher are known to support MPS 1.4. OS/2 are known to support MPS 1.1 only. Mac OS X are known to support MPS 1.4 only.

针对 x86架构的 MultiProcessor 规范(MPS)是一个开放标准,描述了对操作系统和固件的增强,这将允许它们在多处理器配置中与 x86兼容的处理器一起工作。

1.1版本于1994年4月11日发布。1.4版本于1995年7月1日发布,它添加了扩展配置表,以改进对多个 PCI 总线配置的支持,并提高可扩展性。

Linux内核和FreeBSD都是支持英特尔MPS的,

WindowsNT支持1.1版本

Windows2000以及更高版本系统支持1.4版本

多处理器规定,推测和解决多处理器对总线的竞争等等事务有关,还需要进一步阅读intel官方文件

Installed O/S
image-20220613153315480

计算机启动到此时,并没有装载操作系统,如果有多系统的话,是时候做出选择了

Reset Configuration Data:
image-20220613153439605

重设,在BIOS上做出的修改全都改回去?

如果真的是这个功能,那么Exit是干啥用的

image-20220613210834456
Cache Memory

内存的高速缓存

image-20220613153550753

第一个选项是选择启动还是关闭内存到CPU之间的高速缓存

第二个选项是系统总线的高速缓存,

...

I/O Device Configuration

"输入输出设备配置"

image-20220613204029245

Serial port:串行通信接口,通过该接口,信息只能按顺序,一个一个比特传输

比如

DE-9 公口

Parallel port:并行通信接口,一次性并行传送多个比特

比如

DB-25 母口

Floppy disk controller,软盘控制器

I/O Device Configuration就是修改这些接口是否使能,信息传送方向等

Large Disk Access Mode

大硬盘访问模式

关于硬盘模式

参考BIOS设置硬盘工作模式 - 木子杰软件教程 (muzijie.com)

NORMAL普通模式是最早的IDE方式。在此方式下对硬盘访问时,BIOS和IDE控制器对参数不作任何转换。

该模式支持的最大柱面数为1024,最大磁头数为16,最大扇区数为63,每扇区字节数为 512。因此支持最大硬盘容量为:\(512×63×16×1024=528MB\)

在此模式下即使硬盘的实际物理容量更大,但可访问的硬盘空间也只能是528MB。

LBA(Logical Block Addressing)逻辑块寻址模式。

这种模式所管理的硬盘空间突破了528KB 的瓶颈,可达8.4GB。

在LBA模式下,设置的柱面、磁头、扇区等参数并不是实际硬盘的物理参数。

在访问硬盘时,由IDE控制器把由柱面、磁头、扇区等参数确定的逻辑地址转换为实际硬盘的物理地址。

在LBA模式下,可设置的最大磁头数为255,其余参数与普通模式相同。

由此可计算出可访问的硬盘容量为:\(512×63×255×1024=8.4GB\)

LARGE大硬盘模式。当硬盘的柱面超过1024而又不为LBA支持时可采用此种模式。

LARGE模式采取的方法是把柱面数除以2,把磁头数乘以2,其结果总容量不变。

例如,在NORMAL模式下柱面数为1220,磁头数为16,进入LARGE模式则柱面数为610,磁头数为32。

这样在DOS看来柱面数小于1024,即可正常工作。目前基本上只有LBA有实际意义了。

Local Bus IDE adapter

局部总线IDE适配器

随着CPU的飞速发展, 总线的低传输速率与微处理器的高处理速度不能同步,

造成硬盘、图形卡和其它高速外设只能通过一个狭窄而缓慢的瓶颈发送和接收数据,

从而严重影响了CPU高性能的充分发挥, 工业界因此又发展了局域总线(Local Bus)的新技术.

局域总线是在CPU总线与ISA或EISA总线之间新增加的一级总线.

它独立于CPU的结构, 与CPU的时钟频率无关, 使总线形成了一种独特的中间缓冲器.

一些高速外设, 如网卡和硬盘适配器等, 可以从ISA总线上卸下,

通过局域总线直接挂接到CPU总线上, 从而解决了低速总线在高速微处理器和高速外设之间形成的瓶颈.

什么是总线、总线的类型、局部总线、局部总线类型和什么是接口方式?什么是IDE?什么是SCSI?

Advanced Chipset Control

"高级芯片控制"

image-20220613210006072

我是真的一点儿看不懂了

Security视图

image-20220613210213455

设置密码用的

Boot

image-20220613210249009

用+或者-调整设备顺序

这里就是"9.BIOS解决设备冲突,确定boot所在的设备"需要设置的

如果使用U盘作为安装盘,则BOOT中USB串行通用接口设置到最前

在物理机上如果U盘设置到磁盘的后面,BIOS会从磁盘启动,如果磁盘中之前有装好的操作系统,则BIOS将会唤醒那个操作系统

如果磁盘中没有操作系统则BIOS重新尝试从U盘启动

主引导记录MBR

在BIOS boot视图下,我们设置了启动顺序

现在,BIOS按照该顺序给控制权

控制交给第一个存储设备,CPU读取该设备最前面512字节

如果该设备的最后两个字节为0x55 AA则表明这个设备可以用于启动操作系统.

否则这个设备白搭,控制交给下一个设备

磁盘上的主引导记录

MOS-磁盘文件系统布局

整个磁盘只有一个MBR(master boot record)主引导记录,一个分区表(分区表是MBR的一部分)

MBR结构最开始的218个字节就是Bootstrap code area

后面有多个磁盘分区,每个分区在分区表中都有一条记录,记录该分区的开始与结束

这里"分区"在我们小打小闹儿的笔记本子上就是指卷(简单卷)

image-20220613113439425

比如我的电脑512G的固态硬盘被分成三个卷

MOS上关于这部分的描述十分滴珍贵,写的是汉字但是就是不说人话

image-20220613113524034

从"表中的一个分区被标记为活动分区"这句开始,我就不知道它在说什么了

活动分区是什么,不给说,查了百科才知道

活动分区是计算机系统分区,启动操作系统的文件都装在这个分区,Windows 系统下一般被默认为C盘。

image-20220613113709933

在我的linux虚拟机上观察磁盘的前512个字节

image-20220613211928369

使用dd命令将磁盘的前512个字节备份到虚拟机和Executor本机的共享文件夹下面,然后在本机上用010editor打开刚才导出的备份文件

MBR on Linux

最后两个字节是0x 55 AA表明该512个字节为MBR

从右侧的Hex视图可以看出有一些有意义的字节比如

GRUB,Hard Disk.Read.Error等等

猜测MBR在执行的时候会说一些话,可能就会说这里的ASCII编码

MBR的前466个字节是机器码,boot loader,启动引导程序,在我的虚拟机上即grub程序

第447到510字节是分区表,作用是将硬盘分成不同卷

511到512是标志主引导记录的魔数(0x55 AA)

启动管理程序的菜单功能与控制权转交功能示意图

在MOS给出的磁盘文件系统布局图上,可以发现每个磁盘分区最开始都有一个引导块,这个引导块中也可以有grub程序

主引导块之所以叫做"主",是因为它是BIOS默认调用的引导块,并且主引导块可以选择让权,即把引导工作让给其他磁盘分区中的引导块完成

一般windows系统的主引导块没有这个作用,linux有,而安装多系统的时候主引导块会相互覆盖

因此应该首先安装windows系统然后安装linux系统,如此主引导块就可以选择让权或者直接引导了

Grub

一是满足我对MBR干了什么的好奇心,而是复习一下计组8086上的汇编语言,我们对Grub进行反汇编分析

我太想知道这短短的466字节机器码,都干了什么了,他们是不是汇编语言或者C语言编译成的机器码呢?

两个阶段

第一阶段:

boot loader的主程序需要写在主引导分区或者其他磁盘分区的引导块里.

但引导块太小了,只能放下boot loader的最小主程序,相关配置在第二阶段完成

第二阶段:

grub的相关配置都在/boot/grub下面放着

image-20220615000440311

该目录下面是grub配置文件grub.cfg以及各种文件系统定义

grub的配置文件不光有grub.cfg

redhat,ubuntu等等各种系统的grub配置文件叫法不一样

在我的ubuntu10.04虚拟机上配置文件是grub.cfg

反汇编分析

查阅了万能的网友的博客之后,linux上的nasm可以反编译

用我本机上的kali子系统反编译一下就得到了非常像计组课本上的8086汇编语言

1
2
┌──(root㉿Executor)-[/mnt/e/share]
└─# ndisasm mbr.bak > mbr.asm

然后怎么分析?一共223行的汇编指令,属实高估自己的逆向能力了,与其摸着石头过河,不如先了解MBR有什么行为,然后看反汇编去取证

MBR总览
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
00000000  EB63              jmp short 0x65
00000002 90 nop
00000003 108ED0BC adc [bp-0x4330],cl
00000007 00B0B800 add [bx+si+0xb8],dh
0000000B 008ED88E add [bp-0x7128],cl
0000000F C0FBBE sar bl,byte 0xbe
00000012 007CBF add [si-0x41],bh
00000015 0006B900 add [0xb9],al
00000019 02F3 add dh,bl
0000001B A4 movsb
0000001C EA21060000 jmp 0x0:0x621
00000021 BEBE07 mov si,0x7be
00000024 3804 cmp [si],al
00000026 750B jnz 0x33
00000028 83C610 add si,byte +0x10
0000002B 81FEFE07 cmp si,0x7fe
0000002F 75F3 jnz 0x24
00000031 EB16 jmp short 0x49
00000033 B402 mov ah,0x2
00000035 B001 mov al,0x1
00000037 BB007C mov bx,0x7c00
0000003A B280 mov dl,0x80
0000003C 8A7401 mov dh,[si+0x1]
0000003F 8B4C02 mov cx,[si+0x2]
00000042 CD13 int 0x13
00000044 EA007C0000 jmp 0x0:0x7c00
00000049 EBFE jmp short 0x49
0000004B 0000 add [bx+si],al
0000004D 0000 add [bx+si],al
0000004F 0000 add [bx+si],al
00000051 0000 add [bx+si],al
00000053 0000 add [bx+si],al
00000055 0000 add [bx+si],al
00000057 0000 add [bx+si],al
00000059 0000 add [bx+si],al
0000005B 800100 add byte [bx+di],0x0
0000005E 0000 add [bx+si],al
00000060 0000 add [bx+si],al
00000062 0000 add [bx+si],al
00000064 FF db 0xff
00000065 FA cli
00000066 90 nop
00000067 90 nop
00000068 F6C280 test dl,0x80
0000006B 7502 jnz 0x6f
0000006D B280 mov dl,0x80
0000006F EA747C0000 jmp 0x0:0x7c74
00000074 31C0 xor ax,ax
00000076 8ED8 mov ds,ax
00000078 8ED0 mov ss,ax
0000007A BC0020 mov sp,0x2000
0000007D FB sti
0000007E A0647C mov al,[0x7c64]
00000081 3CFF cmp al,0xff
00000083 7402 jz 0x87
00000085 88C2 mov dl,al
00000087 52 push dx
00000088 BB1704 mov bx,0x417
0000008B 802703 and byte [bx],0x3
0000008E 7406 jz 0x96
00000090 BE887D mov si,0x7d88
00000093 E81C01 call 0x1b2
00000096 BE057C mov si,0x7c05
00000099 F6C280 test dl,0x80
0000009C 7448 jz 0xe6
0000009E B441 mov ah,0x41
000000A0 BBAA55 mov bx,0x55aa
000000A3 CD13 int 0x13
000000A5 5A pop dx
000000A6 52 push dx
000000A7 723D jc 0xe6
000000A9 81FB55AA cmp bx,0xaa55
000000AD 7537 jnz 0xe6
000000AF 83E101 and cx,byte +0x1
000000B2 7432 jz 0xe6
000000B4 31C0 xor ax,ax
000000B6 894404 mov [si+0x4],ax
000000B9 40 inc ax
000000BA 8844FF mov [si-0x1],al
000000BD 894402 mov [si+0x2],ax
000000C0 C7041000 mov word [si],0x10
000000C4 668B1E5C7C mov ebx,[0x7c5c]
000000C9 66895C08 mov [si+0x8],ebx
000000CD 668B1E607C mov ebx,[0x7c60]
000000D2 66895C0C mov [si+0xc],ebx
000000D6 C744060070 mov word [si+0x6],0x7000
000000DB B442 mov ah,0x42
000000DD CD13 int 0x13
000000DF 7205 jc 0xe6
000000E1 BB0070 mov bx,0x7000
000000E4 EB76 jmp short 0x15c
000000E6 B408 mov ah,0x8
000000E8 CD13 int 0x13
000000EA 730D jnc 0xf9
000000EC F6C280 test dl,0x80
000000EF 0F84D000 jz near 0x1c3
000000F3 BE937D mov si,0x7d93
000000F6 E98200 jmp 0x17b
000000F9 660FB6C6 movzx eax,dh
000000FD 8864FF mov [si-0x1],ah
00000100 40 inc ax
00000101 66894404 mov [si+0x4],eax
00000105 0FB6D1 movzx dx,cl
00000108 C1E202 shl dx,byte 0x2
0000010B 88E8 mov al,ch
0000010D 88F4 mov ah,dh
0000010F 40 inc ax
00000110 894408 mov [si+0x8],ax
00000113 0FB6C2 movzx ax,dl
00000116 C0E802 shr al,byte 0x2
00000119 668904 mov [si],eax
0000011C 66A1607C mov eax,[0x7c60]
00000120 6609C0 or eax,eax
00000123 754E jnz 0x173
00000125 66A15C7C mov eax,[0x7c5c]
00000129 6631D2 xor edx,edx
0000012C 66F734 div dword [si]
0000012F 88D1 mov cl,dl
00000131 31D2 xor dx,dx
00000133 66F77404 div dword [si+0x4]
00000137 3B4408 cmp ax,[si+0x8]
0000013A 7D37 jnl 0x173
0000013C FEC1 inc cl
0000013E 88C5 mov ch,al
00000140 30C0 xor al,al
00000142 C1E802 shr ax,byte 0x2
00000145 08C1 or cl,al
00000147 88D0 mov al,dl
00000149 5A pop dx
0000014A 88C6 mov dh,al
0000014C BB0070 mov bx,0x7000
0000014F 8EC3 mov es,bx
00000151 31DB xor bx,bx
00000153 B80102 mov ax,0x201
00000156 CD13 int 0x13
00000158 721E jc 0x178
0000015A 8CC3 mov bx,es
0000015C 60 pusha
0000015D 1E push ds
0000015E B90001 mov cx,0x100
00000161 8EDB mov ds,bx
00000163 31F6 xor si,si
00000165 BF0080 mov di,0x8000
00000168 8EC6 mov es,si
0000016A FC cld
0000016B F3A5 rep movsw
0000016D 1F pop ds
0000016E 61 popa
0000016F FF265A7C jmp [0x7c5a]
00000173 BE8E7D mov si,0x7d8e
00000176 EB03 jmp short 0x17b
00000178 BE9D7D mov si,0x7d9d
0000017B E83400 call 0x1b2
0000017E BEA27D mov si,0x7da2
00000181 E82E00 call 0x1b2
00000184 CD18 int 0x18
00000186 EBFE jmp short 0x186
00000188 47 inc di
00000189 52 push dx
0000018A 55 push bp
0000018B 42 inc dx
0000018C 2000 and [bx+si],al
0000018E 47 inc di
0000018F 656F gs outsw
00000191 6D insw
00000192 004861 add [bx+si+0x61],cl
00000195 7264 jc 0x1fb
00000197 204469 and [si+0x69],al
0000019A 736B jnc 0x207
0000019C 005265 add [bp+si+0x65],dl
0000019F 61 popa
000001A0 640020 add [fs:bx+si],ah
000001A3 45 inc bp
000001A4 7272 jc 0x218
000001A6 6F outsw
000001A7 720D jc 0x1b6
000001A9 0A00 or al,[bx+si]
000001AB BB0100 mov bx,0x1
000001AE B40E mov ah,0xe
000001B0 CD10 int 0x10
000001B2 AC lodsb
000001B3 3C00 cmp al,0x0
000001B5 75F4 jnz 0x1ab
000001B7 C3 ret
000001B8 21BF0E00 and [bx+0xe],di
000001BC 0000 add [bx+si],al
000001BE 802021 and byte [bx+si],0x21
000001C1 0083FEFF add [bp+di-0x2],al
000001C5 FF00 inc word [bx+si]
000001C7 0800 or [bx+si],al
000001C9 0000 add [bx+si],al
000001CB 48 dec ax
000001CC 6308 arpl [bx+si],cx
000001CE 00FE add dh,bh
000001D0 FF db 0xff
000001D1 FF05 inc word [di]
000001D3 FE db 0xfe
000001D4 FF db 0xff
000001D5 FF db 0xff
000001D6 FE db 0xfe
000001D7 57 push di
000001D8 6308 arpl [bx+si],cx
000001DA 02A05C00 add ah,[bx+si+0x5c]
000001DE 0000 add [bx+si],al
000001E0 0000 add [bx+si],al
000001E2 0000 add [bx+si],al
000001E4 0000 add [bx+si],al
000001E6 0000 add [bx+si],al
000001E8 0000 add [bx+si],al
000001EA 0000 add [bx+si],al
000001EC 0000 add [bx+si],al
000001EE 0000 add [bx+si],al
000001F0 0000 add [bx+si],al
000001F2 0000 add [bx+si],al
000001F4 0000 add [bx+si],al
000001F6 0000 add [bx+si],al
000001F8 0000 add [bx+si],al
000001FA 0000 add [bx+si],al
000001FC 0000 add [bx+si],al
000001FE 55 push bp
000001FF AA stosb

如果使用ida反汇编分析

将mbr.bak改成mbr.exe之后使用ida打开,ida默认Segment bitness为32位,需要改成16位

image-20220613232353523

一开始ida会把所有指令当作数据,只需要按一下c就可以变为指令

ida提供了交叉引用跳转提示和注释,他真的,我哭死

以下反汇编分析过程参考了

MBR引导程序源码理解

和鸟哥的Linux私房菜第19章

首先记住,BIOS将MBR中的Grub加载到主存的0x7c00处,段寄存器cs存放的是0x7c00

00000000 EB63 jmp short 0x65

第一条指令,可以看出其反汇编的格式为

内存偏移量,机器码,汇编指令

关于8086内存寻址的实现:

段寄存器对内存分段实现,8086上的跳转指令有段跳转和跨段跳转两种

CPU当前执行的指令是由CS:IP两个寄存器共同决定的,物理地址=段寄存器*16+偏移地址, \[ Addr=CS\times 16+IP \] 实际上就是CS的二进制表示左移4位,十六进制表示左移一位,然后加上IP

如果CS保持不变则为段内跳转,如果CS改变就是跨段跳转了

段内跳转:jmp short artx

artx就是要跳转到的绝对地址

artx是计算得到的,怎么算的呢?

在执行本条指令的时候,IP已经指向下一条指令的地址,

在实际的机器码指令中保存的是相对偏移量DISP,用这个相对偏移量加上更新了的IP得到的就是要跳转到的绝对地址

short表示为一个8位带符号数(范围\([-128,127]\)),意思是限制相对偏移量DISP的范围

在执行本条指令00000000 EB63 jmp short 0x65时,IP=0x2,

机器码EB63告诉我们相对偏移量DISP=0x63,

IP=IP+DISP=0x2+0x63=0x65

至于为什么上来就要跳转到中间,越过好多字节,这个问题在00000096 BE057C mov si,0x7c05我们会恍然大悟,现在看来是越过了好多"指令"没有执行,实际上不是"指令",是反汇编器将数据也反汇编成指令了

由于该跳转无条件执行,我们跟随该跳转,看看发生了什么

00000065 FA cli

关于处理器控制指令

image-20220614112455326

CLI之后,IF置0,CPU不允许中断

信号量的机制应该也是这样

此处的CLI指令和后面0000007D FB sti相互匹配

进行了一个CPU的中断关开

00000066 90 nop

空操作指令 NOP 执行该指令并不产生任何结果,仅仅消耗 3 个时钟周期的时间,常用于程序的延时等。

00000067 90 nop

同样啥也不干,耗时

00000068 F6C280 test dl,0x80

测试一下dl是否为0x80

如果dl==0x80ZF=1否则ZF=0,设置标志位之后方便后续的条件转移等

回顾一下grub干了啥

1
2
3
4
5
6
7
8
9
10
11
12
13
1 将程序代码由0:7C00H移动到0:0600H(注,BIOS把MBR放在0:7C00H处)
2 搜索可引导分区,即80H标志
成功:goto 3
失败:跳入ROM BASIC
无效分区表:goto 5
3 读引导扇区
失败:goto 5
成功:goto 4
4 验证引导扇区最后是否为55AAH
失败:goto 5
成功:goto 6
5 打印错误进入无穷循环
6 跳到0:7C00H进行下一步启动工作

80H是可引导分区的标志

硬盘的驱动器号从0x80开始编号,这里测试dl是不是80开头的,目的是判断是否是硬盘驱动

奇怪的是,在此之前的指令中并没有设置dl值的指令,因此dl此时为0,本次测试必然不通过

0000006B 7502 jnz 0x6f

关于条件跳转指令

条件转移指令的目的地址必须在现行的代码段(CS)内,并且以 当前指令指针寄存器 IP 内容为基准,转移范围内在+127~-128 的范围之内。

如果刚才判断的dl是0x80则跳转0x6f,

我们按照某些工作都没做,dl还没有被置为0x80,暂且不跟随跳转,顺序执行

0000006D B280 mov dl,0x80

说曹操,曹操到,现在将dl置为0x80标志某些工作已经进行了

0000006F EA747C0000 jmp 0x0:0x7c74

绝对跳转,跳转到0x7c74,也就是0x74位置,笑死,就在下一行

00000074 31C0 xor ax,ax

ax寄存器置零,没有用mov ax,0是因为mov指令编码长,用xor指令优化

00000076 8ED8 mov ds,ax

0->ax->ds

ds段寄存器置0,

00000078 8ED0 mov ss,ax

ss寄存器置0

ss为stack segment,堆栈段寄存器,栈顶指针的段地址在ss寄存器中,段内偏移量在sp中,ss:sp指向栈顶

0000007A BC0020 mov sp,0x2000

本步和上一步正式建立了栈空间

0000007D FB sti

关于处理器控制指令

image-20220614111629831

标志位指令,STI是开中断标志,该指令执行之后IF=1,意思是允许CPU发生中断了,

本指令和00000065 FA cli之间的指令会被CPU一直执行不被中断,这保证了各种寄存器和堆栈等一直有效

0000007E A0647C mov al,[0x7c64]

一个直接寻址,将内存上0x7c64这个单元中的东西放在al寄存器中

0x7c64所指位置代表启动盘,内核存放其中

这个单元放了啥呢? 00000064 FF db 0xff

0xff表示使用启动盘

00000081 3CFF cmp al,0xff

蜜汁操作,刚刚把M[0x7c64]=0xff放进al,就要检查al是不是0xff

猜测是后来M[0x7c64]会有改变,现在是第一次执行,尚且没变

这应该是一个指针

00000083 7402 jz 0x87

如果刚才的检查通过,则跳转0x87

由于0x870x83之间(即刚才的检查没通过时),只有一条指令,我们不跟随跳转

这里检查我们是否有强制磁盘引用

00000085 88C2 mov dl,al

0x81处的检查没有通过,即al中不是0xff,是多少现在不知道,先放在dl

在此之前涉及到dl寄存器的有一个0000006D B280 mov dl,0x80

dl置0x80是可引导分区的标志,现在把他改了,推测为后面引导失败埋下伏笔

首次执行,本条指令不会被执行

00000087 52 push dx

dx寄存器中的东西压栈

dx中是啥呢?dh高位啃腚为0,低位有两种情况

如果00000081 3CFF cmp al,0xff处的判断通过,则dl=0x80

否则就不是第一次执行到这里了,M[0x7c64]已经发生过改变

我们按照第一次执行的逻辑,dx就是0xff

此时栈中状态

image-20220614160219999

00000088 BB1704 mov bx,0x417

0x417->bx

0000008B 802703 and byte [bx],0x3

关于属性运算符

image-20220614114636880

bx在上一条指令中已经置为0x417

本条指令的意思是,首先进行一个寄存器间接寻址,取M[R[bx]]=M[0x417]

取出该内存单元的最低字节的内容,看看最低位是不是两个1,如果是则置标志位ZF=1

0000008E 7406 jz 0x96

如果刚才的判断通过,则跳转0x96

跳转越过了0x90,0x93两条指令,这是一个函数调用

00000090 BE887D mov si,0x7d88

0x7d88放在si寄存器,作为串操作的源头

0x7d88上放的是啥呢?

0x7d88相对于本文件基地址的偏移量为0x7d88-0x7c00=0x188

去这个地方看一下

1
2
3
4
00000188  47                inc di
00000189 52 push dx
0000018A 55 push bp
0000018B 42 inc dx

都是指令?这就奇怪了,串操作的源头是一些指令,而不是一个连续的数组.

目前我们只是看出了串操作的一点雏形,将"源"放在si寄存器中,但是用串操作干了什么,尚不可知,

我们暂且保持懵逼的状态,继续向后看,我保证后面有一刻,会恍然大悟

00000093 E81C01 call 0x1b2

调用位于0x1b2的函数

我们跟随该函数

进入循环

该调用指令,实际上进入了一个循环,但是现在看不出来

000001B2 AC lodsb

关于串装入指令

image-20220614151353806

说了个什么事情呢?

1
2
mov al, [esi]    ;将字节送入AL
inc esi ;指向下一个字节

在调用函数之前,si<-0x7d88

mov al, [esi]执行之后,M[0x7d88]=M[0x188]->al

inc esi ;执行之后,0x7d89->si

000001B3 3C00 cmp al,0x0

比较al是不是0

000001B5 75F4 jnz 0x1ab

如果al不是0则跳转0x1ab

000001AB BB0100 mov bx,0x1

1->bx,给后面的int指令设置参数

000001AE B40E mov ah,0xe

0xe->ah,给后面的int指令设置参数

000001B0 CD10 int 0x10

此处的中断参考使用汇编语言触发BIOS中断INT 0x10进行屏幕输出 (zoxoy.club)

image-20220614152209611

0x1AE中ah已经被置为0xe,那么此中断就触发了屏幕输出,输出的是啥呢?

要显示的字符在AL上

可以看出来,从0x1AB0x1B5是一个循环,循环打印字符到屏幕,循环停止的条件是碰见\0结束标志

字符来源是0x1B2lodsb,是从0x93处的调用指令00000093 E81C01 call 0x1b2转移过来的

lodsb操作串的来源是00000090 BE887D mov si,0x7d88,即内存中0x7d88这个位置

现在我们必须要考虑清楚串操作的源头为啥是一伙子指令了

1
2
3
4
5
00000188  47                inc di
00000189 52 push dx
0000018A 55 push bp
0000018B 42 inc dx
0000018C 2000 and [bx+si],al

观察机器码,0x47,0x52,0x55,0x42,0x00,0x20(最后小端模式拆开)

好像前面几个都是ASCII可打印字符,尝试打印一下

image-20220614153820258

竟然打印出了"GRUB"字样,这绝对不是巧合,就应该是这个字符串

原来是nasm软件无法区分指令和数据,将数据也反汇编成指令了

那么0x188到0x18c对应G,R,U,B,\0

0x18d上放了一个20不应该和0x18c合起来分析

这意味着后面的反汇编很可能都是错误的,暂且不管后面的错误,我们刚才调用函数打印grub字符串的逻辑是没有错误的

在一开始我们使用010editor观察时,

image-20220614160458438

后面还有好多具有实际意义的字符串

Error的ASCII编码为0x45 72 72 6f 72

确实后面的"指令"中,有这个字符串

1
2
3
4
000001A3  45                inc bp
000001A4 7272 jc 0x218
000001A6 6F outsw
000001A7 720D jc 0x1b6

由此可见这一大块都是字符串

退出循环

实际上"循环"就是指循环打印0x188上存好的grub字符串

跳出循环的条件是

1
2
3
000001B2  AC                lodsb
000001B3 3C00 cmp al,0x0
000001B5 75F4 jnz 0x1ab

这里al为0,即指向grub\0最后这个\0

跳出循环即执行000001B7 C3 ret

000001B7 C3 ret

函数调用返回,返回到00000093 E81C01 call 0x1b2的下一句00000096 BE057C mov si,0x7c05

00000096 BE057C mov si,0x7c05

0x7c05作为串的源头,0x7c05上是什么呢?

1
2
00000003  108ED0BC          adc [bp-0x4330],cl
00000007 00B0B800 add [bx+si+0xb8],dh

M[0x3]=BC

M[0x4]=D0

M[0x5]=8E

M[0x6]=10

M[0x7]=00

00000099 F6C280 test dl,0x80

检查dl上是否还是0x80

0000009C 7448 jz 0xe6

如果dl上是0x80则跳转0xe6,如果不是则继续执行

不跟随跳转,继续执行

0000009E B441 mov ah,0x41

ah高位置0x41,是为了给int 0x13指令设置参数

000000A0 BBAA55 mov bx,0x55aa

0x55aa->bx,0x55aa是主引导记录的魔数,这里应该是要进行某些判断了

000000A3 CD13 int 0x13

image-20220614161620001

000000A5 5A pop dx

恢复dx=0x80

000000A6 52 push dx

0x80压栈

这两步显得很迷,退出来又放进去

%dl 可能已被 INT 13 破坏,AH=41H。 例如,在 AST BIOS 1.04 中会发生这种情况。所以通过重复出入栈来纠正。

000000A7 723D jc 0xe6

如果标志位CF=1则跳转

哪里置的标志位呢?

jc指令与上面的int 13H ah=41H中断例程形成配合。后者的作用是判断 BIOS 是否支持扩展int13中断,如果支持,则CF=0,否则CF=1,那么jc指令就可以根据 BIOS 是否支持扩展int13中断来执行不同位置的“子程序指令”。

一般现在新的支持LBA模式的主板和Win98自带的DOS7操作系统是支持扩展INT 13的。

000000A9 81FB55AA cmp bx,0xaa55

显然之前bx置过0xaa55,此处零标志置1

000000AD 7537 jnz 0xe6

此时标志位ZF不等于0,所以jnz 0xd8不进行跳转。

谨慎起见,这条指令和上一条指令配合使用,继jc 0xd8之后,再次对int 13H ah=41H中断指令的结果进行确认。确认BIOS支持扩展int13。

0xd8 处的指令是 CHS 寻址模式的,即是说如果不支持 LBA 寻址模式,则使用 CHS。

000000AF 83E101 and cx,byte +0x1

image-20220614162458403

000000B2 7432 jz 0xe6

不跳转

000000B4 31C0 xor ax,ax

ax寄存器置0

000000B6 894404 mov [si+0x4],ax

此前si寄存器被置为0x7c05,现在将0放到0x7c09,0x7c0A上

image-20220614162653873

000000B9 40 inc ax

ax=0x1

000000BA 8844FF mov [si-0x1],al

si-0x1指向0x7c04,将al的第字节0x1放进去

image-20220614162805804

000000BD 894402 mov [si+0x2],ax

1放到0x7c07

image-20220614162856400

000000C0 C7041000 mov word [si],0x10

0x10看成一个双字(高八位全0)放到0x7c05,0x7c06

image-20220614162933671

0x7c06应该为0

为啥这里要用一个"WORD",前面都没用?

因为这里直接把一个立即数放到内存上,没有经过寄存器,将寄存器搬到内存时,寄存器规格决定占用内存上几个单元

现在立即数0x10可以作为一个字节,可以作为一个字,一个双字等等,要用word规定一下0x10作为什么传送

我太难了, 这暗无天日的反汇编分析什么时候是个头啊,不分析了放一个大佬的博客吧

MBR引导程序源码理解_背风衣人的博客-CSDN博客_mbr启动代码

Kernel

不管Grub干了啥,总之,它最后加载了Kernel并把控制交给了Kernel

从哪里加载的kernel呢?在硬盘中,文件系统的/boot/下面,vmlinuz文件,比如

image-20220614165129321

问题是,现在的SATA硬盘驱动都是以模块方式添加的设备,在操作系统启起来之前,必然不可能载入模块

这个问题是用Initial RamDisk技术解决的

image-20220614235435725

台湾人把它翻译成"虚拟文件系统",实际上和VFS不是一个东西

到此,操作系统就起来了,后面操作系统(kernel)会检查各种硬件,然后启动各种服务