您的位置:首页 > 编程语言

系统引导 - MBR引导代码研究(1)

2011-08-31 17:17 260 查看
这篇文章说了啥:
MBR基础知识及笔者电脑上的MBR的引导代码研究。
基础背景:
系统引导-引导记录和LOADER
汇编、C语言
有用搜索引擎的能力
正文:
MBR结构(C语言风格):
typedef struct _DPT
{
BYTE type; //分区类型:00表示非活动分区;80表示活动分区;其他为无效分区
BYTE start[3]; //该分区的起始磁头号,扇区号,柱面号;磁头号-1字节, 扇区号-2字节低
6位,柱面号-2字节高2位+3字节
BYTE fs; /*分区文件系统标志: 分区未用: 0x00H.
扩展分区: 0x05H, 0x0FH.
FAT16分区: 0x06H.
FAT32分区: 0x0BH, 0x1BH, 0x0CH, 0x1CH.
NTFS分区: 0x07H.*/
BYTE end[3]; //该分区的结束磁头号,扇区号,柱面号;结构同起始~
DWORD startSector; /*逻辑起始扇区号。表示分区起点之前已用了的扇区数.
如果是主分区表,则这4 个字节表示该分区起始逻辑扇区号与逻辑
0扇区(0柱面,0磁头,1扇区)之差。如果非主分区表,则这4个
字节要么表示该分区起始逻辑扇区号与扩展分区起始逻辑扇区号之差,要么为63。*/
DWORD sectors;//该分区占用的总扇区数
}DPT;
typedef struct MBR
{
BYTE loader[446];
DPT dpt[4];//磁盘分区表
WORD signature;//签名:0xAA55
}MBR;
这个结构有文章介绍了:深入浅出硬盘分区表
我要介绍的就是那个loader[446]了,下面的代码是用IDA反汇编的,二进制代码是我自己写程序读出来的。
这里是入口处的代码:
seg000:7C00 start proc far

seg000:7C00 33 C0 xor ax, ax

seg000:7C02 8E D0 mov ss, ax ; 设置堆栈

seg000:7C04 BC 00 7C mov sp, 7C00h

seg000:7C07 FB sti ; 关中断

seg000:7C08 50 push ax

seg000:7C09 07 pop es

seg000:7C0A 50 push ax

seg000:7C0B 1F pop ds

seg000:7C0C FC cld

seg000:7C0D BE 1B 7C mov si, 7C1Bh

seg000:7C10 BF 1B 06 mov di, 61Bh

seg000:7C13 50 push ax

seg000:7C14 57 push di

seg000:7C15 B9 E5 01 mov cx, 1E5h

seg000:7C18 F3 A4 rep movsb ; 把7C1Bh处的长1E5h的代码拷贝到61Bh处

seg000:7C1A CB retf

seg000:7C1A

seg000:7C1A start endp ;

seg000:7C1A

要说两点:
1. MBR的loader(本文的loader是指MBR的引导代码)是被加载到7C00h处的。7C1Bh开始的长为1E5h的代码其实是loader[1Bh]~loader[200]。你会发现代码段1的长度正好是1Bh…… 所以这段代码就是把MBR剩下的部分复制到61Bh处。
2. 代码复制过去后是如何将控制权交过去的?秘密就在最后一条指令retf。
函数调用有普通调用和长调用。普通调用时call指令只压入下一条指令的地址,函数执行结束后用ret指令返回,将堆栈顶部的返回地址送入ip。而长调用时call要先压入段地址然后再压入下一条指令偏移地址,函数返回使用retf指令,retf不仅修改ip还会修改cs。
而这里用了retf,我们只要找到执行这条指令时堆栈顶部的两个数据就可以了。注意到
push ax ;ax = 00h
push di ;di = 61Bh
于是,执行retf后,cs=00h ip=61Bh,也就是说程序转到了刚才复制过去的代码的开头继续执行了。这不是三十六计第一计 - “瞒天过海”么。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: