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

这篇文章说了啥:

    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,也就是说程序转到了刚才复制过去的代码的开头继续执行了。这不是三十六计第一计 - “瞒天过海”么。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值