rendered paste body#include <vector>typedef unsigned long ULONG; // 4 Bytestypedef unsigned short USHORT; // 2 Bytestypedef short OFFSET; // 2 Bytestypedef ULONG SECT; // 4 Bytestypedef ULONG FSINDEX; // 4 Bytestypedef USHORT FSOFFSET; // 2 Bytestypedef USHORT WCHAR; // 2 Bytestypedef ULONG DFSIGNATURE; // 4 Bytestypedef unsigned char BYTE; // 1 Bytetypedef unsigned short WORD; // 2 Bytestypedef unsigned long DWORD; // 4 Bytestypedef ULONG SID; // 4 Bytestypedef __int64 TMSTMP; // 8 bytestypedef struct _GUID { unsigned long Data1; unsigned short Data2; unsigned short Data3; unsigned char Data4[ 8 ];} GUID;typedef GUID CLSID; // 16 Bytesenum E_DIRECTORY_TYPE{ EDT_EMPTY = 0, EDT_USER_STORAGE=1, EDT_USER_STREAM=2, EDT_LOCK_BYTES=3, EDT_PROPERTY=4, EDT_ROOT_STORAGE=5};struct StructuredStorageHeader { // [offset from start (bytes), length (bytes)] BYTE _abSig[8]; // [00H,08] {0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, // 0x1a, 0xe1} for current version CLSID _clsid; // [08H,16] reserved must be zero (WriteClassStg/ // GetClassFile uses root directory class id) USHORT _uMinorVersion; // [18H,02] minor version of the format: 33 is // written by reference implementation USHORT _uDllVersion; // [1AH,02] major version of the dll/format: 3 for // 512-byte sectors, 4 for 4 KB sectors USHORT _uByteOrder; // [1CH,02] 0xFFFE: indicates Intel byte-ordering USHORT _uSectorShift; // [1EH,02] size of sectors in power-of-two; // typically 9 indicating 512-byte sectors USHORT _uMiniSectorShift; // [20H,02] size of mini-sectors in power-of-two; // typically 6 indicating 64-byte mini-sectors USHORT _usReserved; // [22H,02] reserved, must be zero ULONG _ulReserved1; // [24H,04] reserved, must be zero FSINDEX _csectDir; // [28H,04] must be zero for 512-byte sectors, // number of SECTs in directory chain for 4 KB // sectors FSINDEX _csectFat; // [2CH,04] number of SECTs in the FAT chain SECT _sectDirStart; // [30H,04] first SECT in the directory chain DFSIGNATURE _signature; // [34H,04] signature used for transactions; must // be zero. The reference implementation // does not support transactions ULONG _ulMiniSectorCutoff; // [38H,04] maximum size for a mini stream; // typically 4096 bytes SECT _sectMiniFatStart; // [3CH,04] first SECT in the MiniFAT chain FSINDEX _csectMiniFat; // [40H,04] number of SECTs in the MiniFAT chain SECT _sectDifStart; // [44H,04] first SECT in the DIFAT chain FSINDEX _csectDif; // [48H,04] number of SECTs in the DIFAT chain SECT _sectFat[109]; // [4CH,436] the SECTs of first 109 FAT sectors void dump() { printf("Header is %s\n", isValid() ? "valid" : "invalid" ); printf("%d bytes long\n", sizeof(StructuredStorageHeader)); if (isValid()) { printf("Microsoft Compound File Binary Format v%d.%d (%s)\n", _uDllVersion, _uMinorVersion, (_uByteOrder == 0xFFFE) ? "Intel" : "Big Endian"); printf("Sector size: %d (%db)\n", _uSectorShift, 1<<_uSectorShift ); printf("Mini sector size: %d (%db)\n", _uMiniSectorShift, 1<<_uMiniSectorShift ); if (_ulReserved1 != 0 || _usReserved != 0 || _signature != 0) printf("Should be 0: %d, %d, %d\n", _ulReserved1, _usReserved, _signature); printf("SECTs in directory chain: %d\nFirst directory SECT: #%d\n", _csectDir, _sectDirStart); printf("Size of SAT in sectors: %d\n", _csectFat); printf("Max mini-stream size: %d\n", _ulMiniSectorCutoff); printf("First mini-SAT SECT: %d\nMini SAT count: %d\n", _sectMiniFatStart, _csectMiniFat); printf("DIFAT SECT start: %d\nDIFAT SECT count: %d\n\n", _sectDifStart, _csectDif); } } bool isValid() { return(_abSig[0] == 0xd0 && _abSig[1] == 0xcf && _abSig[2] == 0x11 && _abSig[3] == 0xe0 && _abSig[4] == 0xa1 && _abSig[5] == 0xb1 && _abSig[6] == 0x1a && _abSig[7] == 0xe1); }};struct DirectoryStructureNode{ wchar_t Name[32]; // name of the entry USHORT NameSize; // size of name in bytes not chars BYTE Type; // type of the entry: 0=empty, 1=user storage (dir), // 2=user stream (file) 3=lock bytes // 4=property 5=root storage BYTE Colour; // Node colour in tree: 0=red, 1=black DWORD LeftChild; // Left child in the tree, or -1 DWORD RightChild; // Left child in the tree, or -1 DWORD RootNode; // ID of the root CLSID UniqueID; // GUID DWORD UserFlags; // 0 TMSTMP Created; // usually 0s TMSTMP Modified; // usually 0s SECT StreamStart; // sector id of stream or short stream DWORD StreamLength;// length of the stream in bytes DWORD NotUsed; // 0 void dump() { wprintf(L"Name: %s\n", Name); }};struct Sector{ Sector( char *data, unsigned int index, unsigned int size) : Start(data), Data(data+index*size), Index(index), Size(size) { } char& operator[](unsigned int idx) { return (char&)(Data[Index*Size + idx]); } union { char *Data; SECT *SectorList; DirectoryStructureNode* DirectoryList; }; char *Start; // start of all sectors unsigned int Index; // index of this sector unsigned int Size; // size of sector};// list of sectorsstruct SStream{ SStream() : Data() { } char& getChar(int idx) { int i=0; int max = Data[0]->Size; while (idx > max) idx -= Data[i++]->Size; return Data[i]->Data[idx]; } int size() { if (!Data.size()) return 0; else return int(Data.size()) * Data[0]->Size; } std::vector<Sector*> Data;};struct SAllocationTable : public SStream{ SAllocationTable() : SStream() { } ~SAllocationTable() { // delete streams } void dump() { } SECT& operator [](int idx) { int i=0; int max = Data[0]->Size / 4; while (idx > max) idx -= Data[i++]->Size / 4; return Data[i]->SectorList[idx]; } void buildStream( SStream* stream, SECT start) { Data.push_back(); }};class MSCFBFFile{public: MSCFBFFile(char* data, unsigned int size) : Data(data), DataSize(size), Header((StructuredStorageHeader*)data), Sector0(&Data[0x204]), SectorSize(1<<(Header->_uSectorShift)) { Header->dump(); SAT = new SAllocationTable(); int i=0; //while MSAT[i] != //Sector s(Data[512], , ); //SAT.push_back(Sector(Sector0, i, SectorSize)); // add all sectors to AllSectors array int count=0; for (i=0x204; i<int(DataSize)-0x204; i += SectorSize) { AllSectors.push_back( new Sector(Sector0, count, SectorSize)); count++; } // build sat from header for (i=0; i<109; ++i) { if (Header->_sectFat[i] != -1) SAT->Data.push_back( AllSectors[ Header->_sectFat[i] ] ); } // continue adding from fragmented sectors int nextSect = Header->_sectFat[i]; while (nextSect != -3) { Sector *s = AllSectors[nextSect]; for (i=0; i < (s->Size/4)-1; ++i) { int sec = s->SectorList[i]; if (sec != -1) SAT->Data.push_back( AllSectors[sec] ); } nextSect = AllSectors[nextSect]->SectorList[i]; } // build the mini sat MiniSAT = new SAllocationTable(); MiniSat->buildStream(MiniSat RootDirectory = (DirectoryStructureNode*)(&AllSectors[Header->_sectDirStart]); } ~MSCFBFFile() { // destroy sat delete SAT; // destroy mini-sat delete MiniSAT; // destroy filesystem // destroy all sectors for (int i=0; i<AllSectors.size(); ++i) delete AllSectors[i]; }private: char *Data; unsigned int DataSize; StructuredStorageHeader *Header; DirectoryStructureNode *RootDirectory; SAllocationTable *SAT; SAllocationTable *MiniSAT; char *Sector0; unsigned int SectorSize; std::vector<Sector*> AllSectors;};