public WorkbookStream(string filePath) { using (var fs = new FileStream(filePath, FileMode.Open)) { StructuredStorageReader ssr = new StructuredStorageReader(fs); try { var wbStream = ssr.GetStream("Workbook"); byte[] wbBytes = new byte[wbStream.Length]; wbStream.Read(wbBytes, 0, wbBytes.Length, 0); _biffRecords = RecordHelper.ParseBiffStreamBytes(wbBytes); } catch (StreamNotFoundException) { var wbStream = ssr.GetStream("Book"); Console.WriteLine("WARNING: Main stream is in a Book record indicating legacy Excel 5 BIFF format. This may not parse correctly."); byte[] wbBytes = new byte[wbStream.Length]; wbStream.Read(wbBytes, 0, wbBytes.Length, 0); try { _biffRecords = RecordHelper.ParseBiffStreamBytes(wbBytes); } catch (Exception) { throw new NotImplementedException("Error parsing Book stream: Macrome currently doesn't support the Excel 5 BIFF format."); } } } }
public static string GetRelevantRecordDumpString(WorkbookStream wbs, bool dumpHexBytes = false, bool showAttrInfo = false) { int numBytesToDump = 0; if (dumpHexBytes) { numBytesToDump = 0x1000; } List <BiffRecord> relevantRecords = wbs.Records.Where(rec => RecordHelper.RelevantTypes.Contains(rec.Id)).ToList(); relevantRecords = RecordHelper.ConvertToSpecificRecords(relevantRecords); relevantRecords = PtgHelper.UpdateGlobalsStreamReferences(relevantRecords); string dumpString = ""; foreach (var record in relevantRecords) { dumpString += record.ToHexDumpString(numBytesToDump, showAttrInfo); dumpString += "\n"; } return(dumpString); }
public static string GetRelevantRecordDumpString(WorkbookStream wbs, bool dumpHexBytes = false, bool showAttrInfo = false) { int numBytesToDump = 0; if (dumpHexBytes) { numBytesToDump = 0x1000; } bool hasPassword = wbs.HasPasswordToOpen(); List <BiffRecord> relevantRecords = wbs.Records.Where(rec => RecordHelper.RelevantTypes.Contains(rec.Id)).ToList(); //We can only interpret the data of these records if they are not encrypted if (!hasPassword) { relevantRecords = RecordHelper.ConvertToSpecificRecords(relevantRecords); relevantRecords = PtgHelper.UpdateGlobalsStreamReferences(relevantRecords); } string dumpString = ""; foreach (var record in relevantRecords) { dumpString += record.ToHexDumpString(numBytesToDump, showAttrInfo); dumpString += "\n"; } return(dumpString); }
public WorkbookStream(string filePath) { using (var fs = new FileStream(filePath, FileMode.Open)) { StructuredStorageReader ssr = new StructuredStorageReader(fs); var wbStream = ssr.GetStream("Workbook"); byte[] wbBytes = new byte[wbStream.Length]; wbStream.Read(wbBytes, 0, wbBytes.Length, 0); _biffRecords = RecordHelper.ParseBiffStreamBytes(wbBytes); } }
/// <summary> /// Dumps information about BIFF records that are relevant for analysis. Defaults to sheet, label, and formula data. /// </summary> /// <param name="path">Path to the XLS file to dump</param> /// <param name="dumpAll">Dump all BIFF records, not the most commonly used by maldocs</param> /// <param name="showAttrInfo">Explicitly display PtgAttr information in Formula strings. Defaults to False.</param> /// <param name="dumpHexBytes">Dump the byte content of each BIFF record in addition to its content summary. Defaults to False.</param> public static void Dump(FileInfo path, bool dumpAll = false, bool showAttrInfo = false, bool dumpHexBytes = false) { if (path == null) { Console.WriteLine("path argument must be specified in Dump mode. Run dump -h for usage instructions."); return; } if (path.Exists == false) { Console.WriteLine("path file does not exist."); return; } WorkbookStream wbs = new WorkbookStream(path.FullName); List <RecordType> relevantTypes = new List <RecordType>() { RecordType.BoundSheet8, //Sheet definitions (Defines macro sheets + hides them) RecordType.Lbl, //Named Cells (Contains Auto_Start) RecordType.Formula, //The meat of most cell content RecordType.SupBook, //Contains information for cross-sheet references RecordType.ExternSheet //Contains the XTI records mapping ixti values to BoundSheet8 }; int numBytesToDump = 0; if (dumpHexBytes) { numBytesToDump = 0x1000; } if (dumpAll) { WorkbookStream fullStream = new WorkbookStream(PtgHelper.UpdateGlobalsStreamReferences(wbs.Records)); foreach (var record in fullStream.Records) { Console.WriteLine(record.ToHexDumpString(numBytesToDump, showAttrInfo)); } } else { List <BiffRecord> relevantRecords = wbs.Records.Where(rec => relevantTypes.Contains(rec.Id)).ToList(); relevantRecords = RecordHelper.ConvertToSpecificRecords(relevantRecords); relevantRecords = PtgHelper.UpdateGlobalsStreamReferences(relevantRecords); foreach (var record in relevantRecords) { string dumpString = ""; dumpString += record.ToHexDumpString(numBytesToDump, showAttrInfo); Console.WriteLine(dumpString); } } }
/// <summary> /// Dumps information about BIFF records that are relevant for analysis. Defaults to sheet, label, and formula data. /// </summary> /// <param name="path">Path to the XLS file to dump</param> /// <param name="dumpAll">Dump all BIFF records, not the most commonly used by maldocs</param> /// <param name="showAttrInfo">Explicitly display PtgAttr information in Formula strings. Defaults to False.</param> /// <param name="dumpHexBytes">Dump the byte content of each BIFF record in addition to its content summary.</param> /// <param name="password">XOR Obfuscation decryption password to try. Defaults to VelvetSweatshop if FilePass record is found.</param> /// <param name="disableDecryption">Use this flag in order to skip decryption of the file before dumping.</param> public static void Dump(FileInfo path, bool dumpAll = false, bool showAttrInfo = false, bool dumpHexBytes = false, string password = "******", bool disableDecryption = false) { if (path == null) { Console.WriteLine("path argument must be specified in Dump mode. Run dump -h for usage instructions."); return; } if (path.Exists == false) { Console.WriteLine("path file does not exist."); return; } WorkbookStream wbs = new WorkbookStream(path.FullName); if (wbs.HasPasswordToOpen() && !disableDecryption) { Console.WriteLine("FilePass record found - attempting to decrypt with password " + password); XorObfuscation xorObfuscation = new XorObfuscation(); try { wbs = xorObfuscation.DecryptWorkbookStream(wbs, password); } catch (ArgumentException argEx) { Console.WriteLine("Password " + password + " does not match the verifier value of the document FilePass. Try a different password."); return; } } int numBytesToDump = 0; if (dumpHexBytes) { numBytesToDump = 0x1000; } if (dumpAll) { List <BiffRecord> records; WorkbookStream fullStream = new WorkbookStream(PtgHelper.UpdateGlobalsStreamReferences(wbs.Records)); records = fullStream.Records; foreach (var record in records) { Console.WriteLine(record.ToHexDumpString(numBytesToDump, showAttrInfo)); } } else { string dumpString = RecordHelper.GetRelevantRecordDumpString(wbs, dumpHexBytes, showAttrInfo); Console.WriteLine(dumpString); } }
public WorkbookStream AddSheet(BoundSheet8 sheetHeader, byte[] sheetBytes) { WorkbookStream newStream = new WorkbookStream(Records); List <BoundSheet8> existingBoundSheets = newStream.GetAllRecordsByType <BoundSheet8>(); BoundSheet8 lastSheet8 = existingBoundSheets.Last(); newStream = newStream.InsertRecord(sheetHeader, lastSheet8); List <BiffRecord> sheetRecords = RecordHelper.ParseBiffStreamBytes(sheetBytes); newStream = newStream.InsertRecords(sheetRecords); newStream = newStream.FixBoundSheetOffsets(); return(newStream); }
/// <summary> /// Dumps information about BIFF records that are relevant for analysis. Defaults to sheet, label, and formula data. /// </summary> /// <param name="path">Path to the XLS file to dump</param> /// <param name="dumpAll">Dump all BIFF records, not the most commonly used by maldocs</param> /// <param name="showAttrInfo">Explicitly display PtgAttr information in Formula strings. Defaults to False.</param> /// <param name="dumpHexBytes">Dump the byte content of each BIFF record in addition to its content summary. Defaults to False.</param> public static void Dump(FileInfo path, bool dumpAll = false, bool showAttrInfo = false, bool dumpHexBytes = false) { if (path == null) { Console.WriteLine("path argument must be specified in Dump mode. Run dump -h for usage instructions."); return; } if (path.Exists == false) { Console.WriteLine("path file does not exist."); return; } WorkbookStream wbs = new WorkbookStream(path.FullName); int numBytesToDump = 0; if (dumpHexBytes) { numBytesToDump = 0x1000; } if (dumpAll) { WorkbookStream fullStream = new WorkbookStream(PtgHelper.UpdateGlobalsStreamReferences(wbs.Records)); foreach (var record in fullStream.Records) { Console.WriteLine(record.ToHexDumpString(numBytesToDump, showAttrInfo)); } } else { string dumpString = RecordHelper.GetRelevantRecordDumpString(wbs, dumpHexBytes, showAttrInfo); Console.WriteLine(dumpString); } }
public WorkbookStream(byte[] workbookBytes) { _biffRecords = RecordHelper.ParseBiffStreamBytes(workbookBytes); }
public byte[] ToBytes() { return(RecordHelper.ConvertBiffRecordsToBytes(_biffRecords)); }
public WorkbookStream AddSheet(BoundSheet8 sheetHeader, List <BiffRecord> records) { return(AddSheet(sheetHeader, RecordHelper.ConvertBiffRecordsToBytes(records))); }
/// <summary> /// Dumps information about BIFF records that are relevant for analysis. Defaults to sheet, label, and formula data. /// </summary> /// <param name="path">Path to the XLS file to dump</param> /// <param name="dumpAll">Dump all BIFF records, not the most commonly used by maldocs</param> /// <param name="showAttrInfo">Explicitly display PtgAttr information in Formula strings. Defaults to False.</param> /// <param name="dumpHexBytes">Dump the byte content of each BIFF record in addition to its content summary.</param> /// <param name="password">XOR Obfuscation decryption password to try. Defaults to VelvetSweatshop if FilePass record is found.</param> /// <param name="disableDecryption">Use this flag in order to skip decryption of the file before dumping.</param> public static void Dump(FileInfo path, bool dumpAll = false, bool showAttrInfo = false, bool dumpHexBytes = false, string password = "******", bool disableDecryption = false) { if (path == null) { Console.WriteLine("path argument must be specified in Dump mode. Run dump -h for usage instructions."); return; } if (path.Exists == false) { Console.WriteLine("path file does not exist."); return; } WorkbookStream wbs = new WorkbookStream(path.FullName); if (wbs.HasPasswordToOpen() && !disableDecryption) { FilePass fpRecord = wbs.GetAllRecordsByType <FilePass>().First(); if (fpRecord.wEncryptionType == 0 && fpRecord.xorObfuscationKey != 0) { XorObfuscation xorObfuscation = new XorObfuscation(); Console.WriteLine("FilePass record found - attempting to decrypt with password " + password); try { wbs = xorObfuscation.DecryptWorkbookStream(wbs, password); } catch (ArgumentException argEx) { Console.WriteLine("Password " + password + " does not match the verifier value of the document FilePass. Try a different password."); return; } } else if (fpRecord.wEncryptionType == 1 && fpRecord.vMajor > 1) { Console.WriteLine("FilePass record for CryptoAPI Found - Currently Unsupported."); string verifierSalt = BitConverter.ToString(fpRecord.encryptionVerifier.Salt).Replace("-", ""); string verifier = BitConverter.ToString(fpRecord.encryptionVerifier.EncryptedVerifier).Replace("-", ""); string verifierHash = BitConverter.ToString(fpRecord.encryptionVerifier.EncryptedVerifierHash).Replace("-", ""); Console.WriteLine("Salt is: " + verifierSalt); Console.WriteLine("Vrfy is: " + verifier); Console.WriteLine("vHsh is: " + verifierHash); Console.WriteLine("Algo is: " + string.Format("{0:x8}", fpRecord.encryptionHeader.AlgID)); } else if (fpRecord.wEncryptionType == 1 && fpRecord.vMajor == 1) { Console.WriteLine("FilePass record for RC4 Binary Document Encryption Found - Currently Unsupported."); } } int numBytesToDump = 0; if (dumpHexBytes) { numBytesToDump = 0x1000; } if (dumpAll) { List <BiffRecord> records; WorkbookStream fullStream = new WorkbookStream(PtgHelper.UpdateGlobalsStreamReferences(wbs.Records)); records = fullStream.Records; foreach (var record in records) { Console.WriteLine(record.ToHexDumpString(numBytesToDump, showAttrInfo)); } } else { string dumpString = RecordHelper.GetRelevantRecordDumpString(wbs, dumpHexBytes, showAttrInfo); Console.WriteLine(dumpString); } }