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); }
/// <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 void TestFormulaToStringConversion() { WorkbookStream wbs = TestHelpers.GetMacroLoopWorkbookStream(); 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 }; List <BiffRecord> relevantRecords = wbs.Records.Where(rec => relevantTypes.Contains(rec.Id)).ToList(); relevantRecords = RecordHelper.ConvertToSpecificRecords(relevantRecords); relevantRecords = PtgHelper.UpdateGlobalsStreamReferences(relevantRecords); List <string> results = relevantRecords.Select(r => r.ToHexDumpString()).ToList(); string b1formula = results.Where(res => res.StartsWith("Formula[B1]")).First(); Assert.AreEqual("Formula[B1]: invokeChar=A11", b1formula); string b2formula = results.Where(res => res.StartsWith("Formula[B2]")).First(); Assert.AreEqual("Formula[B2]: var=999", b2formula); string b5formula = results.Where(res => res.StartsWith("Formula[B5]")).First(); Assert.AreEqual("Formula[B5]: InvokeFormula(\"=HALT()\",A1)", b5formula); string b6formula = results.Where(res => res.StartsWith("Formula[B6]")).First(); Assert.AreEqual("Formula[B6]: WProcessMemory(-1,B2+(D1*255),ACTIVE.CELL(),LEN(ACTIVE.CELL()),0)", b6formula); string a11formula = results.Where(res => res.StartsWith("Formula[A11]")).First(); Assert.AreEqual("Formula[A11]: RETURN(CHAR(var))", a11formula); string a12formula = results.Where(res => res.StartsWith("Formula[A12]")).First(); Assert.AreEqual("Formula[A12]: RETURN(FORMULA(arg1,arg2))", a12formula); string d13formula = results.Where(res => res.StartsWith("Formula[D13]")).First(); Assert.AreEqual("Formula[D13]: stringToBuild=stringToBuild&invokeChar()", d13formula); string d14formula = results.Where(res => res.StartsWith("Formula[D14]")).First(); Assert.AreEqual("Formula[D14]: curCell=ABSREF(\"R[1]C\",curCell)", d14formula); }
/// <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); } }
/// <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); } }