虚拟磁盘及文件格式总述

在下列文章中主要讲述了概念:
磁盘及分区
虚拟磁盘格式1:VMDK
虚拟磁盘格式2:VHD
虚拟磁盘格式3:VDI
文件系统1:FAT
文件系统2:EXT
文件系统3:NTFS
现在通过代码实现通过二进制的方式从虚拟磁盘文件中读取其中保存的所有文件内容,以下代码主要针对单个文件的VMDK格式,针对FAT32和EXT4两种文件格式,代码比较烂,只是展示一种思路:虚拟磁盘文件结构如下所示,所以可以像剥洋葱一样,一层层读取,直至实现读取文件的目的

img

完整代码戳此链接,其中入口文件为test.cpp
https://pan.baidu.com/s/1lSAlpyYJ95Nsorp-QlQRmw 提取码:0efu
里面用作提取的Ubuntu 64 位.vmdk太大了不好上传,用的win98.vmdk文件为https://pan.baidu.com/s/1Q5OI5owlEsntffTiarEW9Q 提取码:pnbn

Copy
#include"DescriptorFile.h" #include"Header.h" #include"GrainDirectoryGrainTable.h" #include"MBR.h" #include"DBR.h" #include"FAT32Table.h" #include "RootDirectory.h" #include"SuperBlock.h" #include"Utils.h" #include"GroupDescriptor.h" #include"InodeTable.h" #include"EXTDirectory.h" #include <fstream> #include <iostream> #include<fstream> #include <direct.h> using namespace std; int main() { //FAT ifstream in("F:/win98.vmdk", iostream::binary); //EXT //ifstream in("D:/vm/Ubuntu 64 位.vmdk", iostream::binary); char buffer[512]; in.read(buffer, 512); Header hdr = Header::Read((unsigned char*)buffer, 0); DescriptorFile d(in); long long grainStart = long long(hdr.gdOffset) * 512; cout << grainStart << '\n'; in.seekg(grainStart); long long grainSize = long long(hdr.overHead) * 512; char* buffer2 = new char[grainSize]; in.read(buffer2, grainSize); GrainDirectoryGrainTable gdgt = GrainDirectoryGrainTable::Read((unsigned char*)buffer2, grainStart); long long mbrStart = long long(gdgt.gdTogt.begin()->second[0]) * 512; cout << mbrStart << '\n'; in.seekg(mbrStart); char buffer3[512]; in.read(buffer3, 512); if ((unsigned char)buffer3[510] == 0x55 && (unsigned char)buffer3[511] == 0xAA) { in.seekg(mbrStart); MBR mbr(in,gdgt,hdr); //FAT int gde = mbr.partitions[0].partitionStartSector / hdr.grainSize / hdr.numGTEsPerGT; int gte = mbr.partitions[0].partitionStartSector % (hdr.grainSize * hdr.numGTEsPerGT) / hdr.grainSize; int offset = mbr.partitions[0].partitionStartSector % hdr.grainSize; ////EXT,因为这里第二个分区才是ext //int gde = mbr.partitions[1].partitionStartSector / hdr.grainSize / hdr.numGTEsPerGT; //int gte = mbr.partitions[1].partitionStartSector % (hdr.grainSize * hdr.numGTEsPerGT) / hdr.grainSize; //int offset = mbr.partitions[1].partitionStartSector % hdr.grainSize; auto i = gdgt.gdTogt.begin(); int j = 0; while (j != gde) { ++j; ++i; } int dbrStart = (i->second[gte] + offset) * 512; cout << dbrStart << '\n'; ////EXT //char buffer4[1024]; //int superblockStart = dbrStart + 1024; //cout << superblockStart << '\n'; //in.seekg(superblockStart); //in.read(buffer4, 1024); //SuperBlock superBlock = SuperBlock::Read((unsigned char*)buffer4); ////超块的下一个块位块组描述表 //int groupDescriptorStartSector = mbr.partitions[1].partitionStartSector +pow(2, 10 + superBlock.blockSize)/512; //gde = groupDescriptorStartSector / hdr.grainSize / hdr.numGTEsPerGT; //gte = groupDescriptorStartSector % (hdr.grainSize * hdr.numGTEsPerGT) / hdr.grainSize; //offset = groupDescriptorStartSector % hdr.grainSize; //auto ii = gdgt.gdTogt.begin(); //j = 0; //while (j != gde) //{ // ++j; // ++ii; //} //int groupDescriptorStart = (ii->second[gte] + offset) * 512; //cout << groupDescriptorStart << '\n'; //in.seekg(groupDescriptorStart); //int totalBlocks = (superBlock.blockCountHigh << 32) | superBlock.blockCountLow; //GroupDescriptor gd(in, pow(2, 10 + superBlock.blockSize), ceil(totalBlocks/superBlock.blockPerGroup), gdgt, hdr); // //InodeTable inodeTable(in, gd, pow(2, 10 + superBlock.blockSize), superBlock.inodePerGroup, superBlock.inodeSize, mbr.partitions[1].partitionStartSector, gdgt, hdr); ////这里为了简便,有问题 //int rootDirectorySector = mbr.partitions[1].partitionStartSector + inodeTable.inodeTable[0][1].tree.extenTree2[0].blockNumLow * pow(2, 10 + superBlock.blockSize) / 512; //gde = rootDirectorySector / hdr.grainSize / hdr.numGTEsPerGT; //gte = rootDirectorySector % (hdr.grainSize * hdr.numGTEsPerGT) / hdr.grainSize; //offset = rootDirectorySector % hdr.grainSize; //ii = gdgt.gdTogt.begin(); //j = 0; //while (j != gde) //{ // ++j; // ++ii; //} //int rootDirectoryStart = (ii->second[gte] + offset) * 512; //cout << rootDirectoryStart << '\n'; //in.seekg(rootDirectoryStart); ////要通过节点表的20-23处判断目录是链表格式还是索引格式 //EXTDirectory rootDirectory(in, pow(2, 10 + superBlock.blockSize)); ////读取文件和目录,并保存到"D:\\vm\\extart" //extract(inodeTable, superBlock, rootDirectory, hdr, mbr, gdgt,in, "D:\\vm\\extart"); ////EXT //FAT if (mbr.partitions[0].partitionType == 0x0c) { cout << "windows98 fat32"; char buffer4[512]; in.seekg(dbrStart); in.read(buffer4, 512); DBR dbr = DBR::Read((unsigned char*)buffer4); //相对于分区的FAT表的其实扇区数*512+分区起始字节 int gde = (dbr.reservedSector + mbr.partitions[0].partitionStartSector) / hdr.grainSize / hdr.numGTEsPerGT; int gte = (dbr.reservedSector + mbr.partitions[0].partitionStartSector) % (hdr.grainSize * hdr.numGTEsPerGT) / hdr.grainSize; int offset = (dbr.reservedSector + mbr.partitions[0].partitionStartSector) % hdr.grainSize; auto i = gdgt.gdTogt.begin(); int j = 0; while (j != gde) { ++j; ++i; } int fatStart = (i->second[gte] + offset) * 512; in.seekg(fatStart); int startSector = dbr.reservedSector + mbr.partitions[0].partitionStartSector; FAT32Table fatTable(in, gdgt.gdTogt, startSector, dbr.sectorPerFAT); gde = (dbr.numberOfFat * dbr.sectorPerFAT + dbr.reservedSector + mbr.partitions[0].partitionStartSector) / hdr.grainSize / hdr.numGTEsPerGT; gte = (dbr.numberOfFat * dbr.sectorPerFAT + dbr.reservedSector + mbr.partitions[0].partitionStartSector) % (hdr.grainSize * hdr.numGTEsPerGT) / hdr.grainSize; offset = (dbr.numberOfFat * dbr.sectorPerFAT + dbr.reservedSector + mbr.partitions[0].partitionStartSector) % hdr.grainSize; auto ii = gdgt.gdTogt.begin(); j = 0; while (j != gde) { ++j; ++ii; } int rootdirectoryStart = (ii->second[gte] + offset) * 512; in.seekg(rootdirectoryStart); RootDirectory rootDirectory(in, fatTable); ExtractFile(&rootDirectory, in, "C:/Users/DELL/Desktop/tttest", dbr.rootDirEntry, dbr.numberOfFat * dbr.sectorPerFAT + dbr.reservedSector + mbr.partitions[0].partitionStartSector, gdgt.gdTogt, fatTable); } //FAT } }
posted @   启林O_o  阅读(243)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示