zoukankan      html  css  js  c++  java
  • [磁盘数据分析] 实现解析特定分区体系(DOS分区体系)的主引导记录扇区

      近期学习了硬盘的结构以及分区体系,以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的职责,实践出真知,这个过程中也是学到了不少其他的东西,注意到了很多细节的地方。真的是受益匪浅!

  • 相关阅读:
    跨域上传文件
    算法
    websocket
    Bottle
    爬虫一
    RabbitMQ
    git&github快速入门
    centos6安装SaltStack
    ajax
    Django之Model操作
  • 原文地址:https://www.cnblogs.com/kirai/p/5003041.html
Copyright © 2011-2022 走看看