溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

發(fā)布時(shí)間:2020-03-30 16:07:14 來源:億速云 閱讀:1287 作者:三月 欄目:系統(tǒng)運(yùn)維

 億速云服務(wù)器與全球多個(gè)國(guó)家頂級(jí)機(jī)房直接合作,提供包括香港、美國(guó)、日本等國(guó)家和地區(qū)的服務(wù)器,需要的請(qǐng)聯(lián)系億速云官方客服! 優(yōu)質(zhì)的服務(wù)器租用!      

我們?cè)谇懊嬷v解了主引導(dǎo)程序的基礎(chǔ)知識(shí),今天我們就來講講主引導(dǎo)程序的擴(kuò)展。 不過主引導(dǎo)程序有個(gè)限制,那便是主引導(dǎo)程序的代碼量不能超過 512 字節(jié)!那么我們?nèi)绾蝸硗黄七@個(gè)限制呢?

        我們現(xiàn)在的基本思路是在主引導(dǎo)程序中做如下工作:

        1、完成最基本的初始化工作;

        2、從存儲(chǔ)介質(zhì)中加載程序到內(nèi)存中;

        3、將控制權(quán)交由新加載的程序執(zhí)行;

        4、......


        那么我們具體該如何做呢?思路如下圖所示

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        那么主引導(dǎo)程序應(yīng)如何來加載存儲(chǔ)介質(zhì)中的其他程序呢?通過一定的文件系統(tǒng)的格式。那么什么是文件系統(tǒng)呢?它是指存儲(chǔ)介質(zhì)上組織文件數(shù)據(jù)的方法(數(shù)據(jù)組織的方式)。我們?cè)诖颂幰?FAT12 文件格式為例來進(jìn)行講解,為什么選用它呢?因?yàn)樗奈募袷阶顬楹?jiǎn)單,也最適用于用來學(xué)習(xí)。FAT12 文件格式如下圖所示

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        FAT12 是 DOS 時(shí)代的早期文件系統(tǒng);它的結(jié)構(gòu)非常簡(jiǎn)單,一直沿用于軟盤;它的基本組織單位有 3 個(gè):字節(jié)(Byte)是基本的數(shù)據(jù)單位,扇區(qū)(Sector)是磁盤中的最小數(shù)據(jù)單元,簇(Cluster)是一個(gè)或多個(gè)扇區(qū)。我們的解決方案便是:1、使用 FAT12 對(duì)軟盤(data.img)進(jìn)行格式化;2、編寫可執(zhí)行程序(Loader),并將其拷貝到軟盤中;3、主引導(dǎo)程序(boot)在文件系統(tǒng)中查找 Loader;4、將 Loader 復(fù)制到內(nèi)存中,并跳轉(zhuǎn)到入口地址處執(zhí)行。

        我們下來要進(jìn)行的實(shí)驗(yàn)是:往虛擬軟盤中寫入文件。原材料有 FreeDos,Bochs,bximage。步驟是:1、創(chuàng)建虛擬軟盤(data.img);2、在 FreeDos 中進(jìn)行格式化(FAT12);3、將 data.img 掛載到 Linux 中,并寫入文件。

        我們先在 Linux 中創(chuàng)建一張?zhí)摂M軟盤,然后將其掛載到 /mnt/hgfs/ 目錄下(命令是 mount -o loop data.img /mnt/hgfs/),然后在 Linux 中創(chuàng)建兩個(gè)文件 test.txt 和 loader.bin。test.txt 的內(nèi)容是 This is test for virtual floopy ...,loader.bin 中的內(nèi)容是很多行的 D.T.Software. ;然后將他們兩個(gè)拷貝到虛擬軟盤中(拷貝到 /mnt/hgfs/ 目錄下),最后進(jìn)行虛擬軟盤的卸載(umount /mnt/hgfs/)。我們看看虛擬軟盤中的文件

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        我們看到在虛擬軟盤中已經(jīng)有兩個(gè)文件了,再來看看他們的內(nèi)容

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        我們看到已經(jīng)出現(xiàn)了我們所寫的文件內(nèi)容。那么我們現(xiàn)在已經(jīng)有了一張?zhí)摂M軟盤,里面包含有我們自己寫的文件內(nèi)容。那么我們現(xiàn)在已經(jīng)做完了前兩步了,下來我們的工作是 boot 查找目標(biāo)文件(Loader),并讀取文件的內(nèi)容!下來我們來深入看看 FAT12 文件系統(tǒng),F(xiàn)AT12 文件系統(tǒng)由引導(dǎo)區(qū)、FAT 表、根目錄項(xiàng)表和文件數(shù)據(jù)組成。如下圖所示

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        FAT12 的主引導(dǎo)區(qū)存儲(chǔ)的比較重要的信息是文件系統(tǒng)的類型,文件系統(tǒng)邏輯扇區(qū)總數(shù),每簇包含的扇區(qū)數(shù)等。主引導(dǎo)區(qū)最后以 0x55AA 拉你個(gè)字節(jié)作為結(jié)束,共占用一個(gè)扇區(qū)。它的信息如下圖所示

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        下一步的是實(shí)驗(yàn)是讀取 data.img 中的文件系統(tǒng)信息。步驟:1、創(chuàng)建 Fat12Header 結(jié)構(gòu)體類型;2、使用文件流讀取前 512 字節(jié)的內(nèi)容;3、解析并打印相關(guān)的信息。下來我們進(jìn)行相關(guān)的實(shí)驗(yàn),我們以 C++ 語言來寫出一個(gè)解析 Fat12Header 的程序,源碼如下所示

#include <QtCore/QCoreApplication>
#include <QFile>
#include <QDataStream>
#include <QDebug>

#pragma pack(push)
#pragma pack(1)

struct Fat12Header
{
    char BS_OEMName[8];
    ushort BPB_BytsPerSec;
    uchar BPB_SecPerClus;
    ushort BPB_RsvdSecCnt;
    uchar BPB_NumFATs;
    ushort BPB_RootEntCnt;
    ushort BPB_TotSec16;
    uchar BPB_Media;
    ushort BPB_FATSz16;
    ushort BPB_SecPerTrk;
    ushort BPB_NumHeads;
    uint BPB_HiddSec;
    uint BPB_TotSec32;
    uchar BS_DrvNum;
    uchar BS_Reserved1;
    uchar BS_BootSig;
    uint BS_VolID;
    char BS_VolLab[11];
    char BS_FileSysType[8];
};

#pragma pack(pop)

void PrintHeader(Fat12Header& rf, QString p)
{
    QFile file(p);

    if( file.open(QIODevice::ReadOnly) )
    {
        QDataStream in(&file);

        file.seek(3);    // 偏移 3 個(gè)字節(jié),因?yàn)榕c文件系統(tǒng)相關(guān)的東西都是從這開始的(上面表格中)

        in.readRawData(reinterpret_cast<char*>(&rf), sizeof(rf));

        rf.BS_OEMName[7] = 0;    // 將數(shù)組的最后一個(gè)成員賦 0 值,將他們?cè)诤筮吙梢钥醋鍪亲址幚?
        rf.BS_VolLab[10] = 0;
        rf.BS_FileSysType[7] = 0;

        qDebug() << "BS_OEMName: " << rf.BS_OEMName;
        qDebug() << "BPB_BytsPerSec: " << hex << rf.BPB_BytsPerSec;
        qDebug() << "BPB_SecPerClus: " << hex << rf.BPB_SecPerClus;
        qDebug() << "BPB_RsvdSecCnt: " << hex << rf.BPB_RsvdSecCnt;
        qDebug() << "BPB_NumFATs: " << hex << rf.BPB_NumFATs;
        qDebug() << "BPB_RootEntCnt: " << hex << rf.BPB_RootEntCnt;
        qDebug() << "BPB_TotSec16: " << hex << rf.BPB_TotSec16;
        qDebug() << "BPB_Media: " << hex << rf.BPB_Media;
        qDebug() << "BPB_FATSz16: " << hex << rf.BPB_FATSz16;
        qDebug() << "BPB_SecPerTrk: " << hex << rf.BPB_SecPerTrk;
        qDebug() << "BPB_NumHeads: " << hex << rf.BPB_NumHeads;
        qDebug() << "BPB_HiddSec: " << hex << rf.BPB_HiddSec;
        qDebug() << "BPB_TotSec32: " << hex << rf.BPB_TotSec32;
        qDebug() << "BS_DrvNum: " << hex << rf.BS_DrvNum;
        qDebug() << "BS_Reserved1: " << hex << rf.BS_Reserved1;
        qDebug() << "BS_BootSig: " << hex << rf.BS_BootSig;
        qDebug() << "BS_VolID: " << hex << rf.BS_VolID;
        qDebug() << "BS_VolLab: " << rf.BS_VolLab;
        qDebug() << "BS_FileSysType: " << rf.BS_FileSysType;
    }

    file.close();
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Fat12Header f12;

    PrintHeader(f12, "E:\\data.img");
    
    return a.exec();
}

        編譯結(jié)果如下

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        我們看到輸出信息和上面的表格是一一對(duì)應(yīng)的,下來我們?cè)?PrintHeader 函數(shù)中添加幾行代碼,如下

file.seek(510);

uchar b510 = 0;
uchar b511 = 0;

in.readRawData(reinterpret_cast<char*>(&b510), sizeof(b510));
in.readRawData(reinterpret_cast<char*>(&b511), sizeof(b511));

qDebug() << "Byte 510: " << hex << b510;
qDebug() << "Byte 511: " << hex << b511;

        我們定位到 510 字節(jié)處,看看 510 字節(jié)和 511 字節(jié)處是什么內(nèi)容

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        是最后的兩個(gè)字節(jié) 55 和 aa。我們?cè)賮砜纯丛趧?chuàng)建的虛擬軟盤中啟動(dòng)的時(shí)候,它會(huì)打印出什么,如下

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        我們看到這個(gè)空的虛擬軟盤在開機(jī)時(shí)輸出的是這一行字符串,那么這行字符串是哪來的呢?通過上面的實(shí)驗(yàn),我們可以得出下面的結(jié)論:1、在 FreeDos 中的 format 程序在格式化軟盤的時(shí)候自動(dòng)在第 0 扇區(qū)生成了一個(gè)主引導(dǎo)程序,這個(gè)主引導(dǎo)程序只打印一個(gè)字符串;2、文件格式和文件系統(tǒng)都是用于定義數(shù)據(jù)如何存放的規(guī)則,只要遵循這個(gè)規(guī)則就能成功讀寫目標(biāo)數(shù)據(jù)。我們下來的問題就是如何在 FAT12 根目錄中查找是否存在目標(biāo)文件呢?我們首先來看看根目錄區(qū)的大小和位置,如下

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        我們看到根目錄區(qū)中的第19個(gè)扇區(qū)中存放的是目錄文件項(xiàng),它的大小為 7168 個(gè)字節(jié),計(jì)算公式如上圖所示。FAT12 文件系統(tǒng)中的根目錄區(qū)是由目錄項(xiàng)構(gòu)成,每一個(gè)目錄項(xiàng)代表根目錄中的一個(gè)文件索引。一些數(shù)據(jù)成員如下圖所示

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        下來我們就進(jìn)行一個(gè)實(shí)驗(yàn):讀取 FAT12 文件系統(tǒng)的根目錄信息。

        步驟如下:

        1、創(chuàng)建 RootEntry 結(jié)構(gòu)體類型;

        2、使用文件流順序讀取每個(gè)項(xiàng)的內(nèi)容;

        3、解析并打印相關(guān)的信息。


        我們?cè)谶M(jìn)行實(shí)驗(yàn)之前,還是先來介紹下目錄項(xiàng)中的一些關(guān)鍵成員吧。a> DIR_Name 文件名(用于判斷是否為目標(biāo)文件);b> DIR_FstClus 文件數(shù)據(jù)起始存儲(chǔ)位置(用于確定讀取位置);c> DIR_FileSize 文件大?。ㄓ糜诖_定讀取的字節(jié)數(shù))。

        我們還是基于 C++ 語言來寫這個(gè)程序,源碼如下

#include <QtCore/QCoreApplication>
#include <QFile>
#include <QDataStream>
#include <QDebug>
#include <QVector>
#include <QByteArray>

#pragma pack(push)
#pragma pack(1)

struct Fat12Header
{
    char BS_OEMName[8];
    ushort BPB_BytsPerSec;
    uchar BPB_SecPerClus;
    ushort BPB_RsvdSecCnt;
    uchar BPB_NumFATs;
    ushort BPB_RootEntCnt;
    ushort BPB_TotSec16;
    uchar BPB_Media;
    ushort BPB_FATSz16;
    ushort BPB_SecPerTrk;
    ushort BPB_NumHeads;
    uint BPB_HiddSec;
    uint BPB_TotSec32;
    uchar BS_DrvNum;
    uchar BS_Reserved1;
    uchar BS_BootSig;
    uint BS_VolID;
    char BS_VolLab[11];
    char BS_FileSysType[8];
};

struct RootEntry
{
    char DIR_Name[11];
    uchar DIR_Attr;
    uchar reserve[10];
    ushort DIR_WrtTime;
    ushort DIR_WrtDate;
    ushort DIR_FstClus;
    uint DIR_FileSize;
};

#pragma pack(pop)

void PrintHeader(Fat12Header& rf, QString p)
{
    QFile file(p);

    if( file.open(QIODevice::ReadOnly) )
    {
        QDataStream in(&file);

        file.seek(3);

        in.readRawData(reinterpret_cast<char*>(&rf), sizeof(rf));

        rf.BS_OEMName[7] = 0;
        rf.BS_VolLab[10] = 0;
        rf.BS_FileSysType[7] = 0;

        qDebug() << "BS_OEMName: " << rf.BS_OEMName;
        qDebug() << "BPB_BytsPerSec: " << hex << rf.BPB_BytsPerSec;
        qDebug() << "BPB_SecPerClus: " << hex << rf.BPB_SecPerClus;
        qDebug() << "BPB_RsvdSecCnt: " << hex << rf.BPB_RsvdSecCnt;
        qDebug() << "BPB_NumFATs: " << hex << rf.BPB_NumFATs;
        qDebug() << "BPB_RootEntCnt: " << hex << rf.BPB_RootEntCnt;
        qDebug() << "BPB_TotSec16: " << hex << rf.BPB_TotSec16;
        qDebug() << "BPB_Media: " << hex << rf.BPB_Media;
        qDebug() << "BPB_FATSz16: " << hex << rf.BPB_FATSz16;
        qDebug() << "BPB_SecPerTrk: " << hex << rf.BPB_SecPerTrk;
        qDebug() << "BPB_NumHeads: " << hex << rf.BPB_NumHeads;
        qDebug() << "BPB_HiddSec: " << hex << rf.BPB_HiddSec;
        qDebug() << "BPB_TotSec32: " << hex << rf.BPB_TotSec32;
        qDebug() << "BS_DrvNum: " << hex << rf.BS_DrvNum;
        qDebug() << "BS_Reserved1: " << hex << rf.BS_Reserved1;
        qDebug() << "BS_BootSig: " << hex << rf.BS_BootSig;
        qDebug() << "BS_VolID: " << hex << rf.BS_VolID;
        qDebug() << "BS_VolLab: " << rf.BS_VolLab;
        qDebug() << "BS_FileSysType: " << rf.BS_FileSysType;

        file.seek(510);

        uchar b510 = 0;
        uchar b511 = 0;

        in.readRawData(reinterpret_cast<char*>(&b510), sizeof(b510));
        in.readRawData(reinterpret_cast<char*>(&b511), sizeof(b511));

        qDebug() << "Byte 510: " << hex << b510;
        qDebug() << "Byte 511: " << hex << b511;
    }

    file.close();
}

RootEntry FindRootEntry(Fat12Header& rf, QString p, int i)
{
    RootEntry ret = {{0}};

    QFile file(p);

    if( file.open(QIODevice::ReadOnly) && (0 <= i) && (i < rf.BPB_RootEntCnt) )
    {
        QDataStream in(&file);

        file.seek(19 * rf.BPB_BytsPerSec + i * sizeof(RootEntry));

        in.readRawData(reinterpret_cast<char*>(&ret), sizeof(ret));
    }

    file.close();

    return ret;
}

void PrintRootEntry(Fat12Header& rf, QString p)
{
    for(int i=0; i<rf.BPB_RootEntCnt; i++)
    {
        RootEntry re = FindRootEntry(rf, p, i);

        if( re.DIR_Name[0] != '\0' )
        {
            qDebug() << i << ":";
            qDebug() << "DIR_Name: " << hex << re.DIR_Name;
            qDebug() << "DIR_Attr: " << hex << re.DIR_Attr;
            qDebug() << "DIR_WrtDate: " << hex << re.DIR_WrtDate;
            qDebug() << "DIR_WrtTime: " << hex << re.DIR_WrtTime;
            qDebug() << "DIR_FstClus: " << hex << re.DIR_FstClus;
            qDebug() << "DIR_FileSize: " << hex << re.DIR_FileSize;
        }
    }
}

RootEntry FindRootEntry(Fat12Header& rf, QString p, QString fn)
{
    RootEntry ret = {{0}};

    for(int i=0; i<rf.BPB_RootEntCnt; i++)
    {
        RootEntry re = FindRootEntry(rf, p, i);

        if( re.DIR_Name[0] != '\0' )
        {
            int d = fn.lastIndexOf(".");
            QString name = QString(re.DIR_Name).trimmed();

            if( d >= 0 )
            {
                QString n = fn.mid(0, d);
                QString p = fn.mid(d + 1);

                if( name.startsWith(n) && name.endsWith(p) )
                {
                    ret = re;
                    break;
                }
            }
            else
            {
                if( fn == name )
                {
                    ret = re;
                    break;
                }
            }
        }
    }

    return ret;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QString img = "E:\\data.img";
    Fat12Header f12;

    qDebug() << "Read Header:";

    PrintHeader(f12, img);

    qDebug() << endl;

    qDebug() << "Print Root Entry:";

    PrintRootEntry(f12, img);

    return a.exec();
}

        我們來看看輸出信息

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        我們看到在輸出的信息中就有我們自己寫的 test.txt 文件和 loader.bin 文件。下來我們來使用下 FindRootEntry 這個(gè)函數(shù)來進(jìn)行文件的查找,在 main.cpp 中添加如下代碼

    RootEntry re = FindRootEntry(f12, img, "LOADER.BIN");
    
    qDebug() << "DIR_Name: " << hex << re.DIR_Name;
    qDebug() << "DIR_Attr: " << hex << re.DIR_Attr;
    qDebug() << "DIR_WrtDate: " << hex << re.DIR_WrtDate;
    qDebug() << "DIR_WrtTime: " << hex << re.DIR_WrtTime;
    qDebug() << "DIR_FstClus: " << hex << re.DIR_FstClus;
    qDebug() << "DIR_FileSize: " << hex << re.DIR_FileSize;

        我們來看看會(huì)輸出什么信息

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        我們看到輸出的是 loader.bin 文件的相關(guān)信息,我們將其換成 test.txt 呢,看看結(jié)果

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        我們?cè)賮黼S便寫個(gè)文件名試試呢

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        我們看到打印的全是 0。下來我們來看看 FAT 表中的先后關(guān)系,它是以簇(扇區(qū))為單位存儲(chǔ)文件數(shù)據(jù),每個(gè)表項(xiàng)(vec[i])表示文件數(shù)據(jù)的實(shí)際位置(簇)。即 DIR_FstClus 表示文件第 0 簇(扇區(qū))的位置,vec[DIR_FstClus] 表示文件第 1 簇(扇區(qū))的位置;vec[vec[DIR_FstClus]] 表示文件第 2 簇(扇區(qū))的位置。下面來看看 FAT12 數(shù)據(jù)物理組織示意圖,如下如所示

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        即比如它的起始為 C,然后下一個(gè)表項(xiàng)為 O,O 指向的下一個(gè)表項(xiàng)又是 Z,以此類推直至最后的 S 指向的表項(xiàng)為 NULL。其實(shí)它的數(shù)據(jù)組織方式和我們之前所接觸的單鏈表是有點(diǎn)類似的,它的邏輯組織示意圖如下圖所示

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        下來我們?cè)賮磉M(jìn)行一個(gè)實(shí)驗(yàn),加載 FAT12 中的文件數(shù)據(jù)。

        步驟如下:

        1、在根目錄區(qū)查找目標(biāo)文件對(duì)應(yīng)的項(xiàng);

        2、獲取目標(biāo)文件的起始簇號(hào)和文件大??;

        3、根據(jù) FAT 表中記錄的邏輯先后關(guān)系讀取數(shù)據(jù)。


        值得注意的是:FAT 表中的每個(gè)表只占用 12 比特(1.5字節(jié));FAT 表一共記錄了 BPB_BytsPerSec * 9 * 2 / 3 個(gè)表項(xiàng);可以使用一個(gè) short 表示一個(gè)表項(xiàng)的值;如果表項(xiàng)值大于等于 0xFF8,這說明已經(jīng)到達(dá)最后一個(gè)簇;如果表項(xiàng)值等于 0xFF7,則說明當(dāng)前簇已經(jīng)損壞;數(shù)據(jù)區(qū)起始簇(扇區(qū))號(hào)為 33,地址為 0x4200;數(shù)據(jù)區(qū)起始地址所對(duì)應(yīng)的標(biāo)號(hào)為 2 (不為 0);因此,DIR_FstClus 對(duì)應(yīng)的地址為:0x4200 + (DIR_FstClus - 2) * 512。

        我們基于前面編寫的代碼再次編寫。源碼如下

#include <QtCore/QCoreApplication>
#include <QFile>
#include <QDataStream>
#include <QDebug>
#include <QVector>
#include <QByteArray>

#pragma pack(push)
#pragma pack(1)

struct Fat12Header
{
    char BS_OEMName[8];
    ushort BPB_BytsPerSec;
    uchar BPB_SecPerClus;
    ushort BPB_RsvdSecCnt;
    uchar BPB_NumFATs;
    ushort BPB_RootEntCnt;
    ushort BPB_TotSec16;
    uchar BPB_Media;
    ushort BPB_FATSz16;
    ushort BPB_SecPerTrk;
    ushort BPB_NumHeads;
    uint BPB_HiddSec;
    uint BPB_TotSec32;
    uchar BS_DrvNum;
    uchar BS_Reserved1;
    uchar BS_BootSig;
    uint BS_VolID;
    char BS_VolLab[11];
    char BS_FileSysType[8];
};

struct RootEntry
{
    char DIR_Name[11];
    uchar DIR_Attr;
    uchar reserve[10];
    ushort DIR_WrtTime;
    ushort DIR_WrtDate;
    ushort DIR_FstClus;
    uint DIR_FileSize;
};

#pragma pack(pop)

void PrintHeader(Fat12Header& rf, QString p)
{
    QFile file(p);

    if( file.open(QIODevice::ReadOnly) )
    {
        QDataStream in(&file);

        file.seek(3);

        in.readRawData(reinterpret_cast<char*>(&rf), sizeof(rf));

        rf.BS_OEMName[7] = 0;
        rf.BS_VolLab[10] = 0;
        rf.BS_FileSysType[7] = 0;

        qDebug() << "BS_OEMName: " << rf.BS_OEMName;
        qDebug() << "BPB_BytsPerSec: " << hex << rf.BPB_BytsPerSec;
        qDebug() << "BPB_SecPerClus: " << hex << rf.BPB_SecPerClus;
        qDebug() << "BPB_RsvdSecCnt: " << hex << rf.BPB_RsvdSecCnt;
        qDebug() << "BPB_NumFATs: " << hex << rf.BPB_NumFATs;
        qDebug() << "BPB_RootEntCnt: " << hex << rf.BPB_RootEntCnt;
        qDebug() << "BPB_TotSec16: " << hex << rf.BPB_TotSec16;
        qDebug() << "BPB_Media: " << hex << rf.BPB_Media;
        qDebug() << "BPB_FATSz16: " << hex << rf.BPB_FATSz16;
        qDebug() << "BPB_SecPerTrk: " << hex << rf.BPB_SecPerTrk;
        qDebug() << "BPB_NumHeads: " << hex << rf.BPB_NumHeads;
        qDebug() << "BPB_HiddSec: " << hex << rf.BPB_HiddSec;
        qDebug() << "BPB_TotSec32: " << hex << rf.BPB_TotSec32;
        qDebug() << "BS_DrvNum: " << hex << rf.BS_DrvNum;
        qDebug() << "BS_Reserved1: " << hex << rf.BS_Reserved1;
        qDebug() << "BS_BootSig: " << hex << rf.BS_BootSig;
        qDebug() << "BS_VolID: " << hex << rf.BS_VolID;
        qDebug() << "BS_VolLab: " << rf.BS_VolLab;
        qDebug() << "BS_FileSysType: " << rf.BS_FileSysType;

        file.seek(510);

        uchar b510 = 0;
        uchar b511 = 0;

        in.readRawData(reinterpret_cast<char*>(&b510), sizeof(b510));
        in.readRawData(reinterpret_cast<char*>(&b511), sizeof(b511));

        qDebug() << "Byte 510: " << hex << b510;
        qDebug() << "Byte 511: " << hex << b511;
    }

    file.close();
}

RootEntry FindRootEntry(Fat12Header& rf, QString p, int i)
{
    RootEntry ret = {{0}};

    QFile file(p);

    if( file.open(QIODevice::ReadOnly) && (0 <= i) && (i < rf.BPB_RootEntCnt) )
    {
        QDataStream in(&file);

        file.seek(19 * rf.BPB_BytsPerSec + i * sizeof(RootEntry));

        in.readRawData(reinterpret_cast<char*>(&ret), sizeof(ret));
    }

    file.close();

    return ret;
}

void PrintRootEntry(Fat12Header& rf, QString p)
{
    for(int i=0; i<rf.BPB_RootEntCnt; i++)
    {
        RootEntry re = FindRootEntry(rf, p, i);

        if( re.DIR_Name[0] != '\0' )
        {
            qDebug() << i << ":";
            qDebug() << "DIR_Name: " << hex << re.DIR_Name;
            qDebug() << "DIR_Attr: " << hex << re.DIR_Attr;
            qDebug() << "DIR_WrtDate: " << hex << re.DIR_WrtDate;
            qDebug() << "DIR_WrtTime: " << hex << re.DIR_WrtTime;
            qDebug() << "DIR_FstClus: " << hex << re.DIR_FstClus;
            qDebug() << "DIR_FileSize: " << hex << re.DIR_FileSize;
        }
    }
}

RootEntry FindRootEntry(Fat12Header& rf, QString p, QString fn)
{
    RootEntry ret = {{0}};

    for(int i=0; i<rf.BPB_RootEntCnt; i++)
    {
        RootEntry re = FindRootEntry(rf, p, i);

        if( re.DIR_Name[0] != '\0' )
        {
            int d = fn.lastIndexOf(".");
            QString name = QString(re.DIR_Name).trimmed();

            if( d >= 0 )
            {
                QString n = fn.mid(0, d);
                QString p = fn.mid(d + 1);

                if( name.startsWith(n) && name.endsWith(p) )
                {
                    ret = re;
                    break;
                }
            }
            else
            {
                if( fn == name )
                {
                    ret = re;
                    break;
                }
            }
        }
    }

    return ret;
}

QVector<ushort> ReadFat(Fat12Header& rf, QString p)
{
    QFile file(p);
    int size = rf.BPB_BytsPerSec * 9;
    uchar* fat = new uchar[size];
    QVector<ushort> ret(size * 2 / 3, 0xFFFF);

    if( file.open(QIODevice::ReadOnly) )
  {
        QDataStream in(&file);

        file.seek(rf.BPB_BytsPerSec * 1);

        in.readRawData(reinterpret_cast<char*>(fat), size);

        for(int i=0, j=0; i<size; i+=3, j+=2)
        {
            ret[j] = static_cast<ushort>((fat[i+1] & 0x0F) << 8) | fat[i];
            ret[j+1] = static_cast<ushort>(fat[i+2] << 4) | ((fat[i+1] >> 4) & 0x0F);
        }
    }

    file.close();

    delete[] fat;

    return ret;
}

QByteArray ReadFileContent(Fat12Header& rf, QString p, QString fn)
{
    QByteArray ret;
    RootEntry re = FindRootEntry(rf, p, fn);

    if( re.DIR_Name[0] != '\0' )
    {
        QVector<ushort> vec = ReadFat(rf, p);
        QFile file(p);

        if( file.open(QIODevice::ReadOnly) )
        {
            char buf[512] = {0};
            QDataStream in(&file);
            int count = 0;

            ret.resize(re.DIR_FileSize);

            for(int i=0, j=re.DIR_FstClus; j<0xFF7; i+=512, j=vec[j])
            {
                file.seek(rf.BPB_BytsPerSec * (33 + j - 2));

                in.readRawData(buf, sizeof(buf));

                for(uint k=0; k<sizeof(buf); k++)
                {
                    if( count < ret.size() )
                    {
                        ret[i+k] = buf[k];
                        count++;
                    }
                }
            }
        }

        file.close();
    }

    return ret;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QString img = "E:\\data.img";
    Fat12Header f12;

    qDebug() << "Read Header:";

    PrintHeader(f12, img);

    qDebug() << endl;

    qDebug() << "Print File Content:";

    QString content = QString(ReadFileContent(f12, img, "TEST.TXT"));

    qDebug() << content;

    return a.exec();
}

        我們來看看打印信息

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        這便是我們之前自己寫的內(nèi)容,說明已經(jīng)成功獲取到了。我們?cè)賮黼S便寫個(gè)文件的名字,看看會(huì)獲取到什么

簡(jiǎn)單介紹主引導(dǎo)程序的擴(kuò)展知識(shí)

        我們看到是空的,什么也沒有。直到現(xiàn)在,我們已經(jīng)對(duì)主引導(dǎo)程序中的文件成功的進(jìn)行了加載并解析內(nèi)容。通過今天對(duì)主引導(dǎo)程序擴(kuò)展的學(xué)習(xí),總結(jié)如下:1、主引導(dǎo)程序的代碼量不超過 512 字節(jié),可以通過主引導(dǎo)程序加載新程序的方式突破限制;2、加載新程序需要依賴于文件系統(tǒng);3、FAT12 是一種早期用于軟盤的簡(jiǎn)單文件系統(tǒng),它的重要信息存儲(chǔ)于 0 扇區(qū);4、FAT12 根目錄區(qū)記錄了文件的起始簇號(hào)和長(zhǎng)度;5、通過查找根目錄區(qū)能夠確定是否存在目標(biāo)文件;6、FAT12 文件數(shù)據(jù)的組織使用了單鏈表的思想,文件數(shù)據(jù)離散的分布于存儲(chǔ)介質(zhì)中,文件數(shù)據(jù)通過 FAT 項(xiàng)進(jìn)行關(guān)聯(lián)。

億速云的服務(wù)器不僅具有高穩(wěn)定性,高速訪問,而且易于管理,安全和輕松使用,以減少用戶在服務(wù)器維護(hù)中的能量和時(shí)間成本,并專注于自己的業(yè)務(wù)的開發(fā)和推廣。億速云服務(wù)器,致力于為用戶提供性價(jià)比最高的服務(wù)器!



向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI