请选择 进入手机版 | 继续访问电脑版
查看: 73568|回复: 666

自己动手写操作系统系列之----------加载Loader

[复制链接]
  • TA的每日心情
    奋斗
    2017-1-16 20:03
  • 签到天数: 116 天

    [LV.6]常住居民II

    发表于 2015-10-23 04:20:48 | 显示全部楼层 |阅读模式
    本帖最后由 冰琥珀 于 2015-10-25 03:01 编辑

            上一个帖子:http://www.ihonker.org/thread-6657-1-1.html
            上个帖子我们编写了引导扇区的代码,也说过引导扇区就是为了加载Loader的,但我们只写到在根目录中找到Loader的目录项,并没有把Loader加载到内存中,这次我们来完成把Loader加载到内存的工作。在此之前,我们先写个简单的Loader,代码如下
           
    [AppleScript] 纯文本查看 复制代码
    org 0x100
    	mov ax, cs
    	mov ds, ax
    	mov es, ax
    	mov ss, ax
    
    	call DispMsg
    	jmp $
    
    DispMsg:
    	mov ax, Message
    	mov bp, ax
    	mov cx, 0x0a
    	mov dx, 0x1500
    	mov bx, 0x000c
    	mov ax, 0x1301
    	int 0x10
    	ret
    
    Message:	db	"In the Loader.bin"

            这段代码很简单,就是显示一串字符串,然后程序就停在那,具体的Loader里面该干些啥活,我们下个帖子再写,现在只有把它加载到内存就行。接下来该来完善我们的引导扇区了。上个帖子我们在目录区找到Loader之后,就调用了个jmp $,让程序停在那了,现在我们来接着往下写。
            我们先来理下思路,在找到Loader的目录项之后,要取出Loader在FAT中的起始簇号,然后根据起始簇号找出Loader在FAT表中的偏移,从而找出下一个簇号(如果有的话,没有就是0xfff),同时我们还要根据这个起始簇号来计算处Loader数据的第一个扇区的偏移,然后将该扇区数据读取进内存,再根据下一个簇号计算出下一个扇区的偏移,再将其读进内存,直到所有的数据都读取完毕。思路基本上理清了,现在有两个问题要处理:
            一、怎么根据原始簇号得出Loader在FAT中的偏移。
            我们先把上面的Loader代码编译成bin文件,然后将其拷贝到软盘中,命令如下
           
    [AppleScript] 纯文本查看 复制代码
    $sudo nasm Loader.asm  -o  Loader.bin
    	$sudo mount -o loop boot.img  /mnt/floppy
    	$sudo cp Loader.bin /mnt/floppy
    	$sudo umount /mnt/floppy

            然后我们来看看根目录的数据,如下图
    选区_009.png
            上图中,根目录区的偏移 = 19 * 512,即两个FAT表的扇区数加上引导记录,结果为19个扇区,每个扇区512个字节。通过上图我们可以知道,Loader.bin的初始簇号为0x0003,下面我们先来计算Loader.bin在FAT表中的偏移。因为在FAT12文件系统中,每个簇号在FAT表中占一个半字节,即12位,所以3个字节可以存两个簇号,因此簇号偏移 = 簇号 * 3 / 2,这里得到的偏移是字节为单位,我们还要计算出簇号所在扇区相对于FAT的偏移,这时我们就用上面计算得到的簇号偏移/512,得到的商是相对于FAT的扇区偏移,余数是该簇号在当前扇区的偏移。
            我们把初始簇号0x0003带入上面的公式,得到簇号偏移=0x0003 * 3 / 2 = 4,然后用4 / 512得到商为0,余数为4,也就是说,初始簇号在FAT中的偏移是FAT的第一个扇区,偏移为4字节的地方,我们到FAT表中去看看,如下图
    选区_010.png
            因为FAT表在引导扇区之后,所以偏移为512个字节,通过上面的FAT表数据我们可知,从偏移为4开始,接下去的一个半字节为0xfff,在FAT表中,如果一个文件大小大于512字节(一个扇区),那个当前簇号的位置存放的是下一个簇号,以0xfff表示文件结束,因为我们的Loader.bin文件很小,一个扇区可以装下所有的数据,所以这里就填了0xfff。
            根据初始簇号得出Loader在FAT中的偏移这个问题,我们已经解决了,接下来就是要根据初始簇号来计算Loader.bin所在数据区的偏移了。因为数据区在根目录区之后,而我们要的Loader.bin文件的数据是存放在数据区的,所以数据偏移 = (19 + 14) * ((簇号 - 2) * 每簇扇区数),因为簇号是从2号簇开始算起的,所以我们在计算偏移的时候要用当前簇号-2,这里我们的每簇扇区数为1,所以上面的公式计算出来的数据偏移为33(单位是扇区),转换为字节就是0x4400,下面我们看看在a.img中,偏移为0x4400处的数据,如下图
    选区_011.png
            我们可以对比Loader.bin,看数据是不是一致,下面是Loader.bin的数据
    选区_012.png
            我们可以看出,在0x4400开始处的数据正是Loader.bin。
            好了,现在主要的问题都解决了,接下来就是写代码来加载数据到内存中了,代码如下
    [AppleScript] 纯文本查看 复制代码
    LABEL_FOUND_LOADER:				;找到LOADER.BIN文件
    	xor cx, cx
    	and di, 0xffe0				;这里把di设置为指向目录项的首地址
    	add di, 0x1a				;目录项中偏移0x1a处为初始簇号
    	mov cx, word [es:di]		;将初始簇号存入cx
    	mov word [wReadOffset], OffsetOfLoader
    
    LABEL_GO_ON_LOADING:
    	push ax
    	push bx
    	mov ah, 0x0e
    	mov al, '.'
    	mov bl, 0x0f
    	int 0x10
    	pop bx
    	pop ax
    
    	push cx
    	mov ax, cx
    	sub ax, 2
    	xor cx, cx
    	mov cl, [BPB_SecPerClus]
    	mul cl
    	mov bx, DataOffsetSec
    	add ax, bx						;得到当前簇号的数据偏移(单位:扇区)
    	push ax
    	mov ax, BaseOfLoader
    	mov es, ax					;存放数据的段地址
    	pop ax
    	mov bx, word [wReadOffset]		;存放数据的偏移
    	mov cl, 1
    	call ReadSector				;读取数据
    	
    	pop ax						;取出当前簇号
    	mov bx, 3					
    	mul bx						;簇号 * 3
    	mov bx, 2
    	div bx						;再除2,这里得到簇号的偏移(单位:字节)				
    	test dx, dx
    	jz LABEL_IN_HIGH_BYTE
    	mov byte [bInHighByte], 1	;该簇号的在当前字节的高4位
    
    LABEL_IN_HIGH_BYTE:
    	xor dx, dx
    	mov bx, [BPB_BytePerSec]
    	add word [wReadOffset], bx	
    	div bx
    	inc ax						;FAT	
    	push dx
    	push ax
    	mov ax, BaseOfLoader
    	sub ax, 0x100
    	mov es, ax					;设置读的位置的段地址
    	pop ax						;ax中存放要读取的扇区号
    	xor bx, bx
    	mov cl, 2					;一次读取2个扇区
    	call ReadSector
    	pop dx
    	add bx, dx
    	mov ax, word [es:bx]
    	cmp byte [bInHighByte], 0		;看簇号是不是在当前字节的高4位
    	jz LABEL_EVEN
    	shr ax, 4					;如果是则ax右移4位
    LABEL_EVEN:
    	and ax, 0xfff
    	cmp ax, 0xfff				;如果ax的值为0xfff表示文件结束
    	jz	LABEL_FILE_LOADED
    	mov cx, ax
    	jmp LABEL_GO_ON_LOADING
    
    LABEL_FILE_LOADED:
    	mov dh, 1
    	call DispStr
    	jmp BaseOfLoader:OffsetOfLoader	;跳转到Loader.bin


            代码看着有点长,我们一段一段来分析,在开始处,则需要先从目录项中取出初始簇号,代码如下
           
    [AppleScript] 纯文本查看 复制代码
    xor cx, cx
    	and di, 0xffe0				;这里把di设置为指向目录项的首地址
    	add di, 0x1a				;目录项中偏移0x1a处为初始簇号
    	mov cx, word [es:di]		;将初始簇号存入cx
    	mov word [wReadOffset], OffsetOfLoader

           
            得到了初始簇号之后,我们要通过初始簇号来计算出数据所在的扇区号,代码如下
    [AppleScript] 纯文本查看 复制代码
    LABEL_GO_ON_LOADING:
    	push ax
    	push bx
    	mov ah, 0x0e
    	mov al, '.'
    	mov bl, 0x0f
    	int 0x10	;在屏幕上”Booting”之后显示'.'
    	pop bx
    	pop ax
    
    	push cx
    	mov ax, cx
    	sub ax, 2
    	xor cx, cx
    	mov cl, [BPB_SecPerClus]
    	mul cl
    	mov bx, DataOffsetSec
    	add ax, bx						;得到当前簇号的数据偏移(单位:扇区)


            这段代码主要就是通过簇号来计算出数据所在的扇区号,因为簇号是从2开始算起的,所以我们要先用簇号减2,得到的结果乘以每簇扇区数,就可以得出数据所在扇区相对于数据区的偏移,然后再加上数据区的起始扇区号,就可以得出要加载数据的扇区号,得到扇区号之后,我们就要将数据读入内存了,代码如下
           
    [AppleScript] 纯文本查看 复制代码
    push ax
    	mov ax, BaseOfLoader
    	mov es, ax					;存放数据的段地址
    	pop ax
    	mov bx, word [wReadOffset]		;存放数据的偏移
    	mov cl, 1
    	call ReadSector				;读取数据


            这里设置了加载数据的内存地址,和读取的扇区数,以及扇区号,然后开始读取数据,接下来,我们要判断该文件在其他扇区是否还有数据,这就要通过FAT表来判断,我们先根据初始扇区号来计算出它在FAT表中的偏移,然后读取出该偏移的数据,如果文件还有数据,则这个值是下个簇号,否则这个值为0xfff,我们来看代码
           
    [AppleScript] 纯文本查看 复制代码
    pop ax						;取出当前簇号
    	mov bx, 3					
    	mul bx						;簇号 * 3
    	mov bx, 2
    	div bx						;再除2,这里得到簇号的偏移(单位:字节)				
    	test dx, dx
    	jz LABEL_IN_HIGH_BYTE
    	mov byte [bInHighByte], 1	;该簇号的在当前字节的高4位


            这里因为一个簇号占一个半字节,两个簇号占3个字节,所以我们要用簇号乘以3,然后除以2,就可以得出簇号在该扇区的偏移。因为我们无法从扇区中读取出一个半字节,因此我们每次读取出2个字节数据,然后根据具体情况来获取出这一个半字节。因为我们要从FAT表中读取出簇号,所以接下来我们要读取FAT表,代码如下
    [AppleScript] 纯文本查看 复制代码
    LABEL_IN_HIGH_BYTE:
    	xor dx, dx
    	mov bx, [BPB_BytePerSec]
    	add word [wReadOffset], bx	
    	div bx
    	inc ax				;ax存放的是相对扇区号,dx中存放的是在扇区中的偏移		
    	push dx
    	push ax
    	mov ax, BaseOfLoader
    	sub ax, 0x100
    	mov es, ax					;设置读的位置的段地址
    	pop ax						;ax中存放要读取的扇区号
    	xor bx, bx
    	mov cl, 2					;一次读取2个扇区
    	call ReadSector


            我们已经得出簇号在FAT表中的偏移(字节),所以我们就要根据这个偏移来计算处它所在的扇区号,然后我们将该扇区读出(磁盘的读写都是按照扇区来进行的),然后再根据偏移来从该扇区中取出簇号。得到簇号之后,我们要判断是不是已经结束,如果不是则要继续读取下一个扇区,否则就跳转到加载结束的位置,代码如下
           
    [AppleScript] 纯文本查看 复制代码
    pop dx
    	add bx, dx
    	mov ax, word [es:bx]
    	cmp byte [bInHighByte], 0		;看簇号是不是在当前字节的高4位
    	jz LABEL_EVEN
    	shr ax, 4					;如果是则ax右移4位
    LABEL_EVEN:
    	and ax, 0xfff
    	cmp ax, 0xfff				;如果ax的值为0xfff表示文件结束
    	jz	LABEL_FILE_LOADED
    	mov cx, ax
    	jmp LABEL_GO_ON_LOADING

           
            接下来我们来看文件加载完成之后怎么处理,代码如下
    [AppleScript] 纯文本查看 复制代码
    LABEL_FILE_LOADED:
    	mov dh, 1
    	call DispStr
    	jmp BaseOfLoader:OffsetOfLoader	;跳转到Loader.bin

            这个就很简单了,在屏幕上显示”Ready.”,然后通过jmp指令跳转到Loader.bin中去执行,这样我们的Loader就完成了,Loader.bin加载完成并将控制前转交给它之后,运行的结果如下图
            选区_014.png
    回复

    使用道具 举报

    该用户从未签到

    发表于 2015-10-24 09:30:22 | 显示全部楼层
    感谢楼主的分享~
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2015-10-24 10:34:29 | 显示全部楼层
    还是不错的哦,顶了
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2019-10-17 06:41
  • 签到天数: 182 天

    [LV.7]常住居民III

    发表于 2015-10-24 10:52:14 | 显示全部楼层
    冰大哥太流弊了666666666666666666666666666666
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2015-10-24 12:31:35 | 显示全部楼层
    还是不错的哦,顶了
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2015-10-24 20:22:40 | 显示全部楼层
    支持中国红客联盟(ihonker.org)
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    郁闷
    2016-4-13 21:38
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2015-10-25 04:58:12 | 显示全部楼层
    还是不错的哦,顶了
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2015-10-25 05:33:11 | 显示全部楼层
    支持中国红客联盟(ihonker.org)
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2015-10-25 15:07:24 | 显示全部楼层
    学习学习技术,加油!
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2015-10-25 18:59:32 | 显示全部楼层
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    指导单位

    江苏省公安厅

    江苏省通信管理局

    浙江省台州刑侦支队

    DEFCON GROUP 86025

    旗下站点

    邮箱系统

    应急响应中心

    红盟安全

    联系我们

    官方QQ群:112851260

    官方邮箱:security#ihonker.org(#改成@)

    官方核心成员

    Archiver|手机版|小黑屋| ( 苏ICP备2021031567号 )

    GMT+8, 2024-4-18 08:12 , Processed in 0.039238 second(s), 17 queries , Gzip On, MemCache On.

    Powered by ihonker.com

    Copyright © 2015-现在.

  • 返回顶部