/// <summary> /// We use a few tricks here to obfuscate the Auto_Open Lbl BIFF records. /// 1) By default the Lbl Auto_Open record is marked as fBuiltin = true with a single byte 0x01 to represent AUTO_OPEN /// We avoid this easily sig-able series of bytes by using a string instead - which Excel will also process. /// We can use labels like AuTo_OpEn and Excel will still use it - some analyst tools are case sensitive and don't /// detect this. /// 2) The string we use for the Lbl can be Unicode, which will further break signatures expecting an ASCII Auto_Open string /// 3) We can inject null bytes into the label name and Excel will ignore them when hunting for Auto_Open labels. /// The name manager will only display up to the first null byte - and most excel label parsers will also break on this. /// 4) The Unicode BOM character (0xFEFF/0xFFEF) is also disregarded by Excel. We can use this to break detections that will drop /// nulls and look for Auto_Open without being case sensitive. By injecting this with nulls we break most detection. /// </summary> /// <returns></returns> public WorkbookStream ObfuscateAutoOpen(string localizedLabel) { Random randomUnicodeChar = new Random(); string[] badUnicodeChars = { "\ufefe", "\uffff", "\ufeff", "\ufffe", "\uffef", "\ufff0", "\ufff1", "\ufff6", "\ufefd", "\u0000", "\udddd" }; int indexLabel = 0; string unicodeLabelWithBadChars = ""; List <Lbl> labels = GetAllRecordsByType <Lbl>(); Lbl autoOpenLbl = labels.First(l => l.fBuiltin && l.Name.Value.Equals("\u0001") || l.Name.Value.ToLower().StartsWith(localizedLabel)); Lbl replaceLabelStringLbl = ((BiffRecord)autoOpenLbl.Clone()).AsRecordType <Lbl>(); //Characters that work //fefe, ffff, feff, fffe, ffef, fff0, fff1, fff6, fefd, 0000, dddd //Pretty much any character that is invalid unicode - though \ucccc doesn't seem to work - need better criteria for parsing foreach (char localizedLabelChar in localizedLabel) { indexLabel = randomUnicodeChar.Next(localizedLabel.Length); unicodeLabelWithBadChars += badUnicodeChars[indexLabel] + localizedLabelChar; } replaceLabelStringLbl.SetName(new XLUnicodeStringNoCch(unicodeLabelWithBadChars, true)); replaceLabelStringLbl.fBuiltin = false; // Hidden removes from the label manager entirely, but doesn't seem to work if fBuiltin is false // replaceLabelStringLbl.fHidden = true; WorkbookStream obfuscatedStream = ReplaceRecord(autoOpenLbl, replaceLabelStringLbl); obfuscatedStream = obfuscatedStream.FixBoundSheetOffsets(); return(obfuscatedStream); }
public WorkbookStream NormalizeAutoOpenLabels() { List <Lbl> autoOpenLabels = WbStream.GetAutoOpenLabels(); foreach (var label in autoOpenLabels) { Lbl fixedLabel = ((BiffRecord)label.Clone()).AsRecordType <Lbl>(); fixedLabel.SetName(new XLUnicodeStringNoCch("Auto_Open")); WbStream = WbStream.ReplaceRecord(label, fixedLabel); } WbStream = WbStream.FixBoundSheetOffsets(); return(WbStream); }
/// <summary> /// We use a few tricks here to obfuscate the Auto_Open Lbl BIFF records. /// 1) By default the Lbl Auto_Open record is marked as fBuiltin = true with a single byte 0x01 to represent AUTO_OPEN /// We avoid this easily sig-able series of bytes by using a string instead - which Excel will also process. /// We can use labels like AuTo_OpEn and Excel will still use it - some analyst tools are case sensitive and don't /// detect this. /// 2) The string we use for the Lbl can be Unicode, which will further break signatures expecting an ASCII Auto_Open string /// 3) We can inject null bytes into the label name and Excel will ignore them when hunting for Auto_Open labels. /// The name manager will only display up to the first null byte - and most excel label parsers will also break on this. /// 4) The Unicode BOM character (0xFEFF/0xFFEF) is also disregarded by Excel. We can use this to break detections that will drop /// nulls and look for Auto_Open without being case sensitive. By injecting this with nulls we break most detection. /// </summary> /// <returns></returns> public WorkbookStream ObfuscateAutoOpen() { List <Lbl> labels = GetAllRecordsByType <Lbl>(); Lbl autoOpenLbl = labels.First(l => l.fBuiltin && l.Name.Value.Equals("\u0001") || l.Name.Value.ToLower().StartsWith("auto_open")); Lbl replaceLabelStringLbl = ((BiffRecord)autoOpenLbl.Clone()).AsRecordType <Lbl>(); //Characters that work //fefe, ffff, feff, fffe, ffef, fff0, fff1, fff6, fefd, 0000, dddd //Pretty much any character that is invalid unicode - though \ucccc doesn't seem to work - need better criteria for parsing //TODO [Stealth] Randomize which invalid unicode characters are injected into this string replaceLabelStringLbl.SetName(new XLUnicodeStringNoCch("\u0000A\uffffu\u0000\ufefft\ufffeo\uffef_\ufff0O\ufff1p\ufff6e\ufefdn\udddd", true)); replaceLabelStringLbl.fBuiltin = false; // Hidden removes from the label manager entirely, but doesn't seem to work if fBuiltin is false // replaceLabelStringLbl.fHidden = true; WorkbookStream obfuscatedStream = ReplaceRecord(autoOpenLbl, replaceLabelStringLbl); obfuscatedStream = obfuscatedStream.FixBoundSheetOffsets(); return(obfuscatedStream); }
public void TestChangeLabel() { WorkbookStream macroWorkbookStream = new WorkbookStream(TestHelpers.GetMacroTestBytes()); List <Lbl> labels = macroWorkbookStream.GetAllRecordsByType <Lbl>(); Lbl autoOpenLbl = labels.First(l => l.fBuiltin && l.Name.Value.Equals("\u0001")); Lbl replaceLabelStringLbl = ((BiffRecord)autoOpenLbl.Clone()).AsRecordType <Lbl>(); replaceLabelStringLbl.SetName(new XLUnicodeStringNoCch("Auto_Open", true)); replaceLabelStringLbl.fBuiltin = false; var cloneLabel = ((BiffRecord)replaceLabelStringLbl.Clone()).AsRecordType <Lbl>(); var cBytes = cloneLabel.GetBytes(); var rLabelBytes = replaceLabelStringLbl.GetBytes(); Assert.AreEqual(rLabelBytes, cBytes); macroWorkbookStream = macroWorkbookStream.ReplaceRecord(autoOpenLbl, replaceLabelStringLbl); macroWorkbookStream = macroWorkbookStream.FixBoundSheetOffsets(); ExcelDocWriter writer = new ExcelDocWriter(); writer.WriteDocument(TestHelpers.AssemblyDirectory + Path.DirectorySeparatorChar + "changedLabel.xls", macroWorkbookStream.ToBytes()); }
public WorkbookStream AddLabel(string label, Stack <AbstractPtg> rgce, bool isHidden = false, bool isUnicode = false, bool isMacroStack = false) { /* * Labels require a reference to an XTI index which is used to say which * BoundSheet8 record maps to the appropriate tab. In order to make this * record we need a SupBook record, and ExternSheet record to specify * which BoundSheet8 record to use. * * Currently this assumes there are no SupBook or ExternSheet records in * use, handling of these cases for complex decoy docs is coming * in the future. * * TODO handle existing SupBook/ExternSheet records when adding Lbl entries */ List <SupBook> supBooksExisting = WbStream.GetAllRecordsByType <SupBook>(); List <ExternSheet> externSheetsExisting = WbStream.GetAllRecordsByType <ExternSheet>(); List <Lbl> existingLbls = WbStream.GetAllRecordsByType <Lbl>(); ExternSheet lastExternSheet; if (supBooksExisting.Count > 0 || externSheetsExisting.Count > 0) { lastExternSheet = externSheetsExisting.Last(); } else { InitializeGlobalStreamLabels(); lastExternSheet = WbStream.GetAllRecordsByType <ExternSheet>().Last();; } Lbl newLbl = new Lbl(label, 0); if (isUnicode) { newLbl.SetName(new XLUnicodeStringNoCch(label, true)); } if (isMacroStack) { newLbl.fProc = true; newLbl.fFunc = true; } if (isHidden) { newLbl.fHidden = true; } if (rgce != null) { newLbl.SetRgce(rgce); } else { newLbl.cce = 0; } if (existingLbls.Count > 0) { WbStream = WbStream.InsertRecord(newLbl, existingLbls.Last()); } else { WbStream = WbStream.InsertRecord(newLbl, lastExternSheet); } WbStream = WbStream.FixBoundSheetOffsets(); return(WbStream); }
public WorkbookStream AddLabel(string label, Stack <AbstractPtg> rgce, bool isHidden = false, bool isUnicode = false, bool isMacroStack = false) { /* * Labels require a reference to an XTI index which is used to say which * BoundSheet8 record maps to the appropriate tab. In order to make this * record we need a SupBook record, and ExternSheet record to specify * which BoundSheet8 record to use. */ List <SupBook> supBooksExisting = WbStream.GetAllRecordsByType <SupBook>(); List <ExternSheet> externSheetsExisting = WbStream.GetAllRecordsByType <ExternSheet>(); List <Lbl> existingLbls = WbStream.GetAllRecordsByType <Lbl>(); ExternSheet lastExternSheet; if (supBooksExisting.Count > 0 || externSheetsExisting.Count > 0) { lastExternSheet = externSheetsExisting.Last(); } else { InitializeGlobalStreamLabels(); lastExternSheet = WbStream.GetAllRecordsByType <ExternSheet>().Last();; } // For now we assume that any labels being added belong to the last BoundSheet8 we added Lbl newLbl = new Lbl(label, (ushort)(WbStream.GetAllRecordsByType <BoundSheet8>().Count)); if (isUnicode) { newLbl.SetName(new XLUnicodeStringNoCch(label, true)); } if (isMacroStack) { newLbl.fProc = true; newLbl.fFunc = true; } if (isHidden) { newLbl.fHidden = true; } if (rgce != null) { newLbl.SetRgce(rgce); } else { newLbl.cce = 0; } if (existingLbls.Count > 0) { WbStream = WbStream.InsertRecord(newLbl, existingLbls.Last()); } else { WbStream = WbStream.InsertRecord(newLbl, lastExternSheet); } WbStream = WbStream.FixBoundSheetOffsets(); return(WbStream); }