码迷,mamicode.com
首页 > 其他好文 > 详细

[磁盘数据分析] 实现解析特定分区体系(DOS分区体系)的主引导记录扇区

时间:2015-11-28 18:29:08      阅读:284      评论:0      收藏:0      [点我收藏+]

标签:

  近期学习了硬盘的结构以及分区体系,以DOS分区体系为例。磁盘的第一个扇区(0-512字节)被称为引导扇区(Boot Sector)。内含有主引导记录(MBR)。ji计算机启动并完成自检后,首先会寻找磁盘的MBR扇区并读取其中的引导记录,然后将系统控制权交给它。

  我的任务是初步解析MBR的内容、判断分区类型、定位所有主分区以及它们的大小。

  通过阅读数据取证入门名著"File System Forensic Analysis"获取DOS分区体系下的MBR的数据结构:

技术分享

  数据结构以及类的声明如下:

 1 typedef struct $DOS {
 2 
 3     __uint32_t Starting_CHS_Address;
 4     __uint32_t Ending_CHS_Address;
 5     __uint64_t Starting_LBA_Address;
 6     __uint64_t Size_In_Sectors;
 7 
 8 
 9     __uint16_t Bootable_Flag;
10     __uint16_t Partition_Type;
11 
12     $DOS() { Starting_CHS_Address = 0; Ending_CHS_Address = 0; Starting_LBA_Address =0;
13              Size_In_Sectors = 0; Bootable_Flag = 0; Partition_Type = 0; }
14 
15 }$DOS;
16 
17 typedef class $MBR {
18 
19 public:
20     $MBR() { Partition_Table_Number = 0; };
21     ~$MBR() = default;
22 
23 public:
24     void GO(char*);
25 
26 protected:
27     void Analyse();
28     void Get_Row_MBR(const char*);
29     void Convert_MBR();
30 
31 protected:
32     void $_Convert_MBR(std::vector<__uint64_t>&);
33     char* $_Type_Judge(const __uint16_t);
34 
35 private:
36     __int32_t Partition_Table_Number;
37     std::string Disk_ISO;
38     std::vector<$DOS> DOS_Partition;
39 
40 }MBR;

 

 

  获取信息通过dd命令,并将返回值通过管道给xxd命令进行处理,获得想要的数据格式:

  如:

技术分享
80 20 21 00 07 fe ff ff 00 08 00 00 00 00 40 06 00 fe ff ff 0f fe ff ff fe 0f 40 06 02 18 eb 2b 00 fe ff ff 83 fe ff ff 00 28 2b 32 00 30 0d 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa
Data

  实现此功能的函数如下:

技术分享
 1 void MBR::Get_Row_MBR(const char* tmp) {
 2     using namespace std;
 3 
 4     Disk_ISO = tmp;
 5     char cmd[1024];
 6     char buffer[1024];
 7 
 8     sprintf(cmd,"sudo dd if=‘%s‘ bs=1 skip=446 count=66 2> log | xxd -p -c 66 > MBR.dat", tmp);
 9     system(cmd);
10 
11     ifstream read_dat("MBR.dat");
12     if(!read_dat) {
13         cerr << "Open MBR.dat Error" <<endl;
14         system("echo ‘Open MBR.dat Error‘ > MBR_Error");
15         exit(1);
16     }
17 
18     while(!read_dat.eof()) {
19         read_dat >> buffer;
20     }
21     read_dat.close();
22 
23     ofstream write_dat("MBR.dat");
24     if(!write_dat) {
25         cerr << "Open MBR.dat Error" <<endl;
26         system("echo ‘Open MBR.dat Error‘ > MBR_Error");
27         exit(1);
28     }
29 
30     for(int i = 0; buffer[i]; i++) {
31         if(i % 2 == 0 && i != 0) {
32             write_dat << " ";
33         }
34         write_dat << buffer[i];
35     }
36     write_dat.close();
37 }
Get_Row_MBR

 

  首先可以确定的是,前446个字节是Boot Code,这是用于引导系统启动的一小段代码。我们在这里不做深入的研究。我们关注的是446-511这66字节所包含的信息。

  Partition Table Entry不仅标识出分区表的入口(每个分区表的第一个字节在硬盘中所处的位置)。从书中也获取到了相应的数据结构:

技术分享

  接下来的工作很简单,那就是逐条解析信息了。由于书作者推荐了(自己写的)开源软件“The Sleuth Kit",所以拿来运行并对照结果。

 

  因为CHS对地址的标记方式局限性过大(仅能寻址8GB),因此后来又有了LBA。且对兼容问题进行了很好的处理(换算公式可根据LBA和CHS不同寻址模式的特点轻易推出:LBA=(C–CS)×PH×PS+(H–HS)×PS+(S–SS)),所以解析过程中不再列出CHS的起始和终止地址(但也做分析,目的也是为了与The Sleuth Kit软件进行清晰对比)。

 

  此外,Partition Type需要有额外的信息来识别,书中给出了表格。因此有了如下识别函数:

技术分享
 1 char* MBR::$_Type_Judge(const __uint16_t type) {
 2     std::string ans;
 3     switch(type) {
 4         case 0x00: ans = "Empty"; break;
 5         case 0x01: ans = "FAT12, CHS"; break;
 6         case 0x04: ans = "FAT16, 16-32MB, CHS"; break;
 7         case 0x05: ans = "Microsoft Extended, CHS"; break;
 8         case 0x06: ans = "FAT16, 32MB-2GB, CHS"; break;
 9         case 0x07: ans = "NTFS"; break;
10         case 0x0b: ans = "FAT32, CHS"; break;
11         case 0x0c: ans = "FAT32, LBA"; break;
12         case 0x0e: ans = "FAT16, 32MB-2GB, LBA"; break;
13         case 0x0f: ans = "Microsoft Extended, LBA"; break;
14         case 0x11: ans = "Hidden FAT12, CHS"; break;
15         case 0x14: ans = "Hidden FAT16, 16-32MB, CHS"; break;
16         case 0x16: ans = "Hidden FAT16, 32MB-2GB, CHS"; break;
17         case 0x1b: ans = "Hidden FAT32, CHS"; break;
18         case 0x1c: ans = "Hidden FAT32, LBA"; break;
19         case 0x1e: ans = "Hidden FAT16, 32MB-2GB, LBA"; break;
20         case 0x42: ans = "Microsoft MBR. Dynamic Disk"; break;
21         case 0x82: ans = "Solaris x86"; break;
22         case 0x83: ans = "Linux"; break;
23         case 0x84: ans = "Hibernation"; break;
24         case 0x85: ans = "Linux Extended"; break;
25         case 0x86: ans = "NTFS Volume Set"; break;
26         case 0x87: ans = "NTFS Volume Set"; break;
27         case 0xa0: ans = "Hibernation"; break;
28         case 0xa1: ans = "Hibernation"; break;
29         case 0xa5: ans = "FreeBSD"; break;
30         case 0xa6: ans = "OpenBSD"; break;
31         default : ans = "No Match";
32     }
33     return const_cast<char*>(ans.c_str());
34 }
Type_Judge

  扇区的大小也给出,因此直接读就可以了。

  特别要注意的是,我使用的是Intel的处理器,该处理器系统采用小端方式进行数据存放。所以要进行大小端的转换处理。

技术分享
 1 void MBR::Convert_MBR() {
 2     using namespace std;
 3 
 4     freopen("MBR.dat", "r", stdin);
 5     vector<__uint64_t> data;
 6     __uint64_t Get_Data_From_MBR;
 7     int Time = 4;
 8 
 9     while(~scanf("%x", &Get_Data_From_MBR)) {
10         data.push_back(Get_Data_From_MBR);
11     }
12 
13     while(Time--) {
14         $_Convert_MBR(data);
15     }
16 }
Convert_MBR

  以及它的辅助函数:

技术分享
 1 void MBR::$_Convert_MBR(std::vector<__uint64_t>& d) {
 2     using namespace std;
 3 
 4     const __int32_t Offset = 16 * Partition_Table_Number;
 5     $DOS tmp;
 6 
 7     tmp.Starting_CHS_Address = d[Offset+3] << 16 | d[Offset+2] << 8 | d[Offset+1];
 8     if(tmp.Starting_CHS_Address == 0) { //Does not exist
 9         return ;
10     }
11 
12     tmp.Bootable_Flag = d[Offset+0];
13     tmp.Partition_Type = d[Offset+4];
14     tmp.Ending_CHS_Address = d[Offset+7] << 16 | d[Offset+6] << 8 | d[Offset+5];
15     tmp.Starting_LBA_Address = d[Offset+11] << 24 | d[Offset+10] << 16 | d[Offset+9] << 8 | d[Offset+8];
16     tmp.Size_In_Sectors = d[Offset+15] << 24 | d[Offset+14] << 16 | d[Offset+13] << 8 | d[Offset+12];
17 
18     Partition_Table_Number++;
19     DOS_Partition.push_back(tmp);
20 }
$_Convert_MBR

 

 至此已经可以初步分析这一块DOS分区体系的硬盘了,完整mbr_analyse.hpp代码如下:

  1 #pragma once
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <vector>
  5 #include <string>
  6 #include <cstring>
  7 #include <fstream>
  8 
  9 typedef struct $DOS {
 10 // essential
 11     __uint32_t Starting_CHS_Address;
 12     __uint32_t Ending_CHS_Address;
 13     __uint64_t Starting_LBA_Address;
 14     __uint64_t Size_In_Sectors;
 15 
 16 // not essential
 17     __uint16_t Bootable_Flag;
 18     __uint16_t Partition_Type;
 19 
 20     $DOS() { Starting_CHS_Address = 0; Ending_CHS_Address = 0; Starting_LBA_Address =0;
 21              Size_In_Sectors = 0; Bootable_Flag = 0; Partition_Type = 0; }
 22 
 23 }$DOS;
 24 
 25 typedef class $MBR {
 26 
 27 public:
 28     $MBR() { Partition_Table_Number = 0; };
 29     ~$MBR() = default;
 30 
 31 public:
 32     void GO(char*);
 33 
 34 protected:
 35     void Analyse();
 36     void Get_Row_MBR(const char*);
 37     void Convert_MBR();
 38 
 39 protected:
 40     void $_Convert_MBR(std::vector<__uint64_t>&);
 41     char* $_Type_Judge(const __uint16_t);
 42 
 43 private:
 44     __int32_t Partition_Table_Number;
 45     std::string Disk_ISO;
 46     std::vector<$DOS> DOS_Partition;
 47 
 48 }MBR;
 49 
 50 void MBR::$_Convert_MBR(std::vector<__uint64_t>& d) {
 51     using namespace std;
 52 
 53     const __int32_t Offset = 16 * Partition_Table_Number;
 54     $DOS tmp;
 55 
 56     tmp.Starting_CHS_Address = d[Offset+3] << 16 | d[Offset+2] << 8 | d[Offset+1];
 57     if(tmp.Starting_CHS_Address == 0) { //Does not exist
 58         return ;
 59     }
 60 
 61     tmp.Bootable_Flag = d[Offset+0];
 62     tmp.Partition_Type = d[Offset+4];
 63     tmp.Ending_CHS_Address = d[Offset+7] << 16 | d[Offset+6] << 8 | d[Offset+5];
 64     tmp.Starting_LBA_Address = d[Offset+11] << 24 | d[Offset+10] << 16 | d[Offset+9] << 8 | d[Offset+8];
 65     tmp.Size_In_Sectors = d[Offset+15] << 24 | d[Offset+14] << 16 | d[Offset+13] << 8 | d[Offset+12];
 66 
 67     Partition_Table_Number++;
 68     DOS_Partition.push_back(tmp);
 69 }
 70 
 71 void MBR::Get_Row_MBR(const char* tmp) {
 72     using namespace std;
 73 
 74     Disk_ISO = tmp;
 75     char cmd[1024];
 76     char buffer[1024];
 77 
 78     sprintf(cmd,"sudo dd if=‘%s‘ bs=1 skip=446 count=66 2> log | xxd -p -c 66 > MBR.dat", tmp);
 79     system(cmd);
 80 
 81     ifstream read_dat("MBR.dat");
 82     if(!read_dat) {
 83         cerr << "Open MBR.dat Error" <<endl;
 84         system("echo ‘Open MBR.dat Error‘ > MBR_Error");
 85         exit(1);
 86     }
 87 
 88     while(!read_dat.eof()) {
 89         read_dat >> buffer;
 90     }
 91     read_dat.close();
 92 
 93     ofstream write_dat("MBR.dat");
 94     if(!write_dat) {
 95         cerr << "Open MBR.dat Error" <<endl;
 96         system("echo ‘Open MBR.dat Error‘ > MBR_Error");
 97         exit(1);
 98     }
 99 
100     for(int i = 0; buffer[i]; i++) {
101         if(i % 2 == 0 && i != 0) {
102             write_dat << " ";
103         }
104         write_dat << buffer[i];
105     }
106     write_dat.close();
107 }
108 
109 void MBR::Convert_MBR() {
110     using namespace std;
111 
112     freopen("MBR.dat", "r", stdin);
113     vector<__uint64_t> data;
114     __uint64_t Get_Data_From_MBR;
115     int Time = 4;
116 
117     while(~scanf("%x", &Get_Data_From_MBR)) {
118         data.push_back(Get_Data_From_MBR);
119     }
120 
121     while(Time--) {
122         $_Convert_MBR(data);
123     }
124 }
125 
126 char* MBR::$_Type_Judge(const __uint16_t type) {
127     std::string ans;
128     switch(type) {
129         case 0x00: ans = "Empty"; break;
130         case 0x01: ans = "FAT12, CHS"; break;
131         case 0x04: ans = "FAT16, 16-32MB, CHS"; break;
132         case 0x05: ans = "Microsoft Extended, CHS"; break;
133         case 0x06: ans = "FAT16, 32MB-2GB, CHS"; break;
134         case 0x07: ans = "NTFS"; break;
135         case 0x0b: ans = "FAT32, CHS"; break;
136         case 0x0c: ans = "FAT32, LBA"; break;
137         case 0x0e: ans = "FAT16, 32MB-2GB, LBA"; break;
138         case 0x0f: ans = "Microsoft Extended, LBA"; break;
139         case 0x11: ans = "Hidden FAT12, CHS"; break;
140         case 0x14: ans = "Hidden FAT16, 16-32MB, CHS"; break;
141         case 0x16: ans = "Hidden FAT16, 32MB-2GB, CHS"; break;
142         case 0x1b: ans = "Hidden FAT32, CHS"; break;
143         case 0x1c: ans = "Hidden FAT32, LBA"; break;
144         case 0x1e: ans = "Hidden FAT16, 32MB-2GB, LBA"; break;
145         case 0x42: ans = "Microsoft MBR. Dynamic Disk"; break;
146         case 0x82: ans = "Solaris x86"; break;
147         case 0x83: ans = "Linux"; break;
148         case 0x84: ans = "Hibernation"; break;
149         case 0x85: ans = "Linux Extended"; break;
150         case 0x86: ans = "NTFS Volume Set"; break;
151         case 0x87: ans = "NTFS Volume Set"; break;
152         case 0xa0: ans = "Hibernation"; break;
153         case 0xa1: ans = "Hibernation"; break;
154         case 0xa5: ans = "FreeBSD"; break;
155         case 0xa6: ans = "OpenBSD"; break;
156         default : ans = "No Match";
157     }
158     return const_cast<char*>(ans.c_str());
159 }
160 
161 void MBR::Analyse() {
162     using namespace std;
163     cout << "There are " << Partition_Table_Number << " partition(s) in this disk iso" << endl << endl;
164     cout << "------------------MBR------------------" << endl;
165     cout << "-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-" << endl << endl;
166     cout << endl << endl;
167     int cnt = 1;
168     for(vector<$DOS>::iterator it = DOS_Partition.begin(); it != DOS_Partition.end(); it++, cnt++) {
169         cout << "------------- Partition " << cnt << " -------------" << endl << endl;
170         cout << "Partition Type: " << $_Type_Judge((*it).Partition_Type) << endl;
171         // cout << "Starting_CHS_Address : " << (*it).Starting_CHS_Address << endl;
172         // cout << "Ending_CHS_Address : " << (*it).Ending_CHS_Address << endl;
173         cout << "Starting_LBA_Address : " << (*it).Starting_LBA_Address << endl;
174         cout << "Size_In_Sectors : " << (*it).Size_In_Sectors << endl;
175         cout << "Bootable_Flag : " << (*it).Bootable_Flag << endl;
176         cout << endl << endl;
177     }
178 }
179 
180 
181 void MBR::GO(char* nm) {
182     Get_Row_MBR((nm));
183     Convert_MBR();
184     Analyse();
185 }

 

  对比分析结果,首先是从TSK官网上获取的镜像:

  mmls命令获取的信息:

     Slot    Start        End          Length       Description
00:  Meta    0000000000   0000000000   0000000001   Primary Table (#0)
01:  -----   0000000000   0000000062   0000000063   Unallocated
02:  00:00   0000000063   0000052415   0000052353   DOS FAT16 (0x04)
03:  00:01   0000052416   0000104831   0000052416   DOS FAT16 (0x04)
04:  00:02   0000104832   0000157247   0000052416   DOS FAT16 (0x04)
05:  Meta    0000157248   0000312479   0000155232   DOS Extended (0x05)
06:  Meta    0000157248   0000157248   0000000001   Extended Table (#1)
07:  -----   0000157248   0000157310   0000000063   Unallocated
08:  01:00   0000157311   0000209663   0000052353   DOS FAT16 (0x04)
09:  -----   0000209664   0000209726   0000000063   Unallocated
10:  01:01   0000209727   0000262079   0000052353   DOS FAT16 (0x04)
11:  Meta    0000262080   0000312479   0000050400   DOS Extended (0x05)
12:  Meta    0000262080   0000262080   0000000001   Extended Table (#2)
13:  -----   0000262080   0000262142   0000000063   Unallocated
14:  02:00   0000262143   0000312479   0000050337   DOS FAT16 (0x06)

 

  接着是我的分析结果:

There are 4 partition(s) in this disk iso

------------------MBR------------------
-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-

------------- Partition 1 -------------

Partition Type: FAT16, 16-32MB, CHS
Starting_LBA_Address : 63
Size_In_Sectors : 52353
Bootable_Flag : 0

------------- Partition 2 -------------

Partition Type: FAT16, 16-32MB, CHS
Starting_LBA_Address : 52416
Size_In_Sectors : 52416
Bootable_Flag : 0

------------- Partition 3 -------------

Partition Type: FAT16, 16-32MB, CHS
Starting_LBA_Address : 104832
Size_In_Sectors : 52416
Bootable_Flag : 0

------------- Partition 4 -------------

Partition Type: Microsoft Extended, CHS
Starting_LBA_Address : 157248
Size_In_Sectors : 155232
Bootable_Flag : 0

  两个结果吻合。

 

  再对本机的/dev/sda进行分析:

 

  mmls命令获取的信息:

     Slot    Start        End          Length       Description
00:  Meta    0000000000   0000000000   0000000001   Primary Table (#0)
01:  -----   0000000000   0000002047   0000002048   Unallocated
02:  00:00   0000002048   0104859647   0104857600   NTFS (0x07)
03:  -----   0104859648   0104861695   0000002048   Unallocated
04:  Meta    0104861694   0841689087   0736827394   Win95 Extended (0x0F)
05:  Meta    0104861694   0104861694   0000000001   Extended Table (#1)
06:  01:00   0104861696   0396365823   0291504128   NTFS (0x07)
07:  -----   0396365824   0396369919   0000004096   Unallocated
08:  Meta    0396367872   0687876095   0291508224   DOS Extended (0x05)
09:  Meta    0396367872   0396367872   0000000001   Extended Table (#2)
10:  02:00   0396369920   0687876095   0291506176   NTFS (0x07)
11:  Meta    0687876096   0837783551   0149907456   DOS Extended (0x05)
12:  Meta    0687876096   0687876096   0000000001   Extended Table (#3)
13:  -----   0687876096   0687878143   0000002048   Unallocated
14:  03:00   0687878144   0837783551   0149905408   NTFS (0x07)
15:  Meta    0837783552   0841689087   0003905536   DOS Extended (0x05)
16:  Meta    0837783552   0837783552   0000000001   Extended Table (#4)
17:  -----   0837783552   0837785599   0000002048   Unallocated
18:  04:00   0837785600   0841689087   0003903488   Linux Swap / Solaris x86 (0x82)
19:  00:02   0841689088   0976771071   0135081984   Linux (0x83)
20:  -----   0976771072   0976773167   0000002096   Unallocated

 

  我的分析结果:

 

There are 3 partition(s) in this disk iso

------------------MBR------------------
-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-

------------- Partition 1 -------------

Partition Type: NTFS
Starting_LBA_Address : 2048
Size_In_Sectors : 104857600
Bootable_Flag : 128

------------- Partition 2 -------------

Partition Type: Microsoft Extended, LBA
Starting_LBA_Address : 104861694
Size_In_Sectors : 736827394
Bootable_Flag : 0

------------- Partition 3 -------------

Partition Type: Linux
Starting_LBA_Address : 841689088
Size_In_Sectors : 135081984
Bootable_Flag : 0

  结果也是一致的。

 

  这件事请很简单,但是可以辅助我更好地理解磁盘的工作原理和MBR的职责,实践出真知,这个过程中也是学到了不少其他的东西,注意到了很多细节的地方。真的是受益匪浅!

[磁盘数据分析] 实现解析特定分区体系(DOS分区体系)的主引导记录扇区

标签:

原文地址:http://www.cnblogs.com/vincentX/p/5003041.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!