private static Stack <AbstractPtg> UpdateSheetReferences(Stack <AbstractPtg> ptgStack, List <BoundSheet8> sheetRecords, ExternSheet externSheetRecord) { List <AbstractPtg> modifiedStack = new List <AbstractPtg>(); foreach (var ptg in ptgStack) { if (ptg is PtgRef3d) { PtgRef3d ref3d = (ptg as PtgRef3d); int index = ref3d.ixti; XTI relevantXti = externSheetRecord.rgXTI[index]; //Make sure this isn't a sheet or workbook level reference if (relevantXti.itabFirst >= 0) { BoundSheet8 relevantSheet = sheetRecords[relevantXti.itabFirst]; string sheetName = relevantSheet.stName.Value; modifiedStack.Add(new PtgRef3d(ref3d.rw, ref3d.col, ref3d.ixti, ref3d.rwRelative, ref3d.colRelative, sheetName)); } else { modifiedStack.Add(ptg); } } else { modifiedStack.Add(ptg); } } modifiedStack.Reverse(); return(new Stack <AbstractPtg>(modifiedStack)); }
public void GenerateVelvetSweatshopMacroSheetSigs() { XorObfuscation xorObfuscation = new XorObfuscation(); BoundSheet8 sheetVersion1 = new BoundSheet8(BoundSheet8.HiddenState.Visible, BoundSheet8.SheetType.Macrosheet, "Sheet"); BoundSheet8 sheetVersion2 = new BoundSheet8(BoundSheet8.HiddenState.Hidden, BoundSheet8.SheetType.Macrosheet, "Sheet1"); BoundSheet8 sheetVersion3 = new BoundSheet8(BoundSheet8.HiddenState.VeryHidden, BoundSheet8.SheetType.Macrosheet, "Sheet2"); BoundSheet8[] sheets = new[] { sheetVersion1, sheetVersion2, sheetVersion3 }; int hiddenState = 0; foreach (BoundSheet8 currentSheet in sheets) { for (int offset = 0; offset < 16; offset += 1) { byte[] header = currentSheet.GetBytes().Take(4).ToArray(); byte[] data = currentSheet.GetBytes().Skip(4).ToArray(); byte[] encryptedData = xorObfuscation.EncryptData_Method1(XorObfuscation.DefaultPassword, data, (byte)offset); string ruleName = string.Format("$boundsheet8_hs{0}_vs_xor_offset{1}", hiddenState, offset); string yaraSig = ruleName + " = { "; yaraSig += BitConverter.ToString(header.Take(2).ToArray()).Replace("-", " "); yaraSig += " [6] "; yaraSig += BitConverter.ToString(encryptedData.Skip(4).Take(2).ToArray()).Replace("-", " "); yaraSig += " }"; Console.WriteLine(yaraSig); } hiddenState += 1; } }
public WorkbookStream InsertBoundSheetRecord(BoundSheet8 boundSheet8) { List <BiffRecord> records = WbStream.Records; List <BoundSheet8> sheets = records.Where(r => r.Id == RecordType.BoundSheet8).Select(sheet => BuildBoundSheetFromBytes(sheet.GetBytes())).ToList(); boundSheet8.lbPlyPos = sheets.First().lbPlyPos; sheets.Add(boundSheet8); foreach (var sheet in sheets) { sheet.lbPlyPos += boundSheet8.Length; } var preSheetRecords = records.TakeWhile(r => r.Id != RecordType.BoundSheet8); var postSheetRecords = records.SkipWhile(r => r.Id != RecordType.BoundSheet8) .SkipWhile(r => r.Id == RecordType.BoundSheet8); List <BiffRecord> newRecordList = preSheetRecords.Concat(sheets).Concat(postSheetRecords).ToList(); WorkbookStream newStream = new WorkbookStream(newRecordList); WbStream = newStream; return(WbStream); }
public WorkbookStream AddMacroSheet(List <BiffRecord> macroSheetRecords, string sheetName, BoundSheet8.HiddenState hiddenState = BoundSheet8.HiddenState.Visible) { BoundSheet8 macroBoundSheet = new BoundSheet8(hiddenState, BoundSheet8.SheetType.Macrosheet, sheetName); WbStream = WbStream.AddSheet(macroBoundSheet, macroSheetRecords); return(WbStream); }
public void TestContainsRecord() { byte[] wbBytes = TestHelpers.GetTemplateMacroBytes(); WorkbookStream wbs = new WorkbookStream(wbBytes); BoundSheet8 notContainedRecord = new BoundSheet8(BoundSheet8.HiddenState.Visible, BoundSheet8.SheetType.Worksheet, "MySheetName"); BoundSheet8 containedRecord = wbs.GetAllRecordsByType <BoundSheet8>().First(); Assert.IsTrue(wbs.ContainsRecord(containedRecord)); Assert.IsFalse(wbs.ContainsRecord(notContainedRecord)); }
public void TestBiffRecordCloneAndGetBytes() { BoundSheet8 bs8 = new BoundSheet8(BoundSheet8.HiddenState.Visible, BoundSheet8.SheetType.Worksheet, "MySheetName"); byte[] bs8bytes = bs8.GetBytes(); BiffRecord bs8CloneRecord = (BiffRecord)bs8.Clone(); byte[] bs8cloneBytes = bs8CloneRecord.GetBytes(); Assert.AreEqual(bs8bytes, bs8cloneBytes); BoundSheet8 bs8Clone = bs8CloneRecord.AsRecordType <BoundSheet8>(); byte[] bs8asRecordBytes = bs8Clone.GetBytes(); Assert.AreEqual(bs8bytes, bs8asRecordBytes); }
public WorkbookStream UnhideSheets() { List <BoundSheet8> sheetRecords = WbStream.GetAllRecordsByType <BoundSheet8>(); foreach (var sheetRecord in sheetRecords) { BoundSheet8 unhiddenRecord = ((BiffRecord)sheetRecord.Clone()).AsRecordType <BoundSheet8>(); unhiddenRecord.hsState = BoundSheet8.HiddenState.Visible; WbStream = WbStream.ReplaceRecord(sheetRecord, unhiddenRecord); } WbStream = WbStream.FixBoundSheetOffsets(); return(WbStream); }
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); }
public void TestAddMacroSheet() { byte[] wbBytes = TestHelpers.GetTemplateMacroBytes(); WorkbookStream wbs = new WorkbookStream(wbBytes); byte[] mtBytes = TestHelpers.GetMacroTestBytes(); WorkbookStream macroWorkbookStream = new WorkbookStream(mtBytes); BoundSheet8 macroSheet = new BoundSheet8(BoundSheet8.HiddenState.Visible, BoundSheet8.SheetType.Macrosheet, "MacroSheet"); List <BOF> macroWorkbookBofs = macroWorkbookStream.GetAllRecordsByType <BOF>(); BOF LastBofRecord = macroWorkbookBofs.Last(); List <BiffRecord> sheetRecords = macroWorkbookStream.GetRecordsForBOFRecord(LastBofRecord); byte[] sheetBytes = RecordHelper.ConvertBiffRecordsToBytes(sheetRecords); wbs = wbs.AddSheet(macroSheet, sheetBytes); ExcelDocWriter writer = new ExcelDocWriter(); writer.WriteDocument(TestHelpers.AssemblyDirectory + Path.DirectorySeparatorChar + "addedsheet.xls", wbs.ToBytes()); }
public void TestReplaceRecord() { byte[] wbBytes = TestHelpers.GetTemplateMacroBytes(); WorkbookStream wbs = new WorkbookStream(wbBytes); BoundSheet8 bs8 = new BoundSheet8(BoundSheet8.HiddenState.Visible, BoundSheet8.SheetType.Worksheet, "MySheetName"); var recordCount = wbs.Records.Count; BoundSheet8 oldSheetRecord = wbs.GetAllRecordsByType <BoundSheet8>().First(); WorkbookStream wbs2 = wbs.ReplaceRecord(oldSheetRecord, bs8); Assert.AreEqual(recordCount, wbs2.Records.Count); BoundSheet8 newSheetRecord = wbs2.GetAllRecordsByType <BoundSheet8>().First(); Assert.AreEqual(newSheetRecord.stName.Value, bs8.stName.Value); Assert.IsFalse(wbs2.ContainsRecord(oldSheetRecord)); Assert.IsTrue(wbs2.ContainsRecord(bs8)); }
/// <summary> /// Needs to be called any time that we add a record that changes the start /// offset of worksheet streams. /// </summary> /// <returns></returns> public WorkbookStream FixBoundSheetOffsets() { List <BoundSheet8> oldSheetBoundRecords = GetAllRecordsByType <BoundSheet8>(); //We ignore the first BOF record for the global/workbook stream List <BOF> bofRecords = GetAllRecordsByType <BOF>().Skip(1).ToList(); WorkbookStream newStream = new WorkbookStream(Records); int sheetOffset = 0; //Assign each offset in order of definition (as per specification) foreach (var boundSheet in oldSheetBoundRecords) { long offset = newStream.GetRecordByteOffset(bofRecords[sheetOffset]); BoundSheet8 newBoundSheet8 = ((BiffRecord)boundSheet.Clone()).AsRecordType <BoundSheet8>(); newBoundSheet8.lbPlyPos = (uint)offset; newStream = newStream.ReplaceRecord(boundSheet, newBoundSheet8); sheetOffset += 1; } return(newStream); }
public void TestAddingSheetRecord() { byte[] wbBytes = TestHelpers.GetTemplateMacroBytes(); WorkbookStream wbs = new WorkbookStream(wbBytes); BoundSheet8 bs8 = new BoundSheet8(BoundSheet8.HiddenState.Visible, BoundSheet8.SheetType.Macrosheet, "MyMacroSheet"); BoundSheet8 correctOffsetBs8 = ((BiffRecord)bs8.Clone()).AsRecordType <BoundSheet8>(); BoundSheet8 oldSheetRecord = wbs.GetAllRecordsByType <BoundSheet8>().First(); BoundSheet8 newSheetRecord = ((BiffRecord)oldSheetRecord.Clone()).AsRecordType <BoundSheet8>(); // bs8.lbPlyPos = (uint) (oldSheetRecord.lbPlyPos + bs8.GetBytes().Length); List <BOF> bofRecords = wbs.GetAllRecordsByType <BOF>(); BOF spreadSheetBOF = bofRecords.Last(); // newSheetRecord.lbPlyPos = bs8.lbPlyPos; long offset = wbs.GetRecordByteOffset(spreadSheetBOF); bs8.lbPlyPos = oldSheetRecord.lbPlyPos; wbs = wbs.InsertRecord(bs8, oldSheetRecord); offset = wbs.GetRecordByteOffset(spreadSheetBOF); correctOffsetBs8.lbPlyPos = (uint)offset; newSheetRecord.lbPlyPos = (uint)offset; wbs = wbs.ReplaceRecord(bs8, correctOffsetBs8); wbs = wbs.ReplaceRecord(oldSheetRecord, newSheetRecord); ExcelDocWriter writer = new ExcelDocWriter(); writer.WriteDocument(TestHelpers.AssemblyDirectory + Path.DirectorySeparatorChar + "testbook.xls", wbs.ToBytes()); }
public WorkbookStream AddSheet(BoundSheet8 sheetHeader, List <BiffRecord> records) { return(AddSheet(sheetHeader, RecordHelper.ConvertBiffRecordsToBytes(records))); }
/// <summary> /// Extracts the data from the stream /// </summary> public override void extractData() { BiffHeader bh; //try //{ while (this.StreamReader.BaseStream.Position < this.StreamReader.BaseStream.Length) { bh.id = (RecordType)this.StreamReader.ReadUInt16(); bh.length = this.StreamReader.ReadUInt16(); // Debugging output TraceLogger.DebugInternal("BIFF {0}\t{1}\t", bh.id, bh.length); switch (bh.id) { case RecordType.BoundSheet8: { // Extracts the Boundsheet data BoundSheet8 bs = new BoundSheet8(this.StreamReader, bh.id, bh.length); TraceLogger.DebugInternal(bs.ToString()); SheetData sheetData = null; switch (bs.dt) { case BoundSheet8.SheetType.Worksheet: sheetData = new WorkSheetData(); this.oldOffset = this.StreamReader.BaseStream.Position; this.StreamReader.BaseStream.Seek(bs.lbPlyPos, SeekOrigin.Begin); WorksheetExtractor se = new WorksheetExtractor(this.StreamReader, sheetData as WorkSheetData); this.StreamReader.BaseStream.Seek(oldOffset, SeekOrigin.Begin); break; case BoundSheet8.SheetType.Chartsheet: ChartSheetData chartSheetData = new ChartSheetData(); this.oldOffset = this.StreamReader.BaseStream.Position; this.StreamReader.BaseStream.Seek(bs.lbPlyPos, SeekOrigin.Begin); chartSheetData.ChartSheetSequence = new ChartSheetSequence(this.StreamReader); this.StreamReader.BaseStream.Seek(oldOffset, SeekOrigin.Begin); sheetData = chartSheetData; break; default: TraceLogger.Info("Unsupported sheet type: {0}", bs.dt); break; } if (sheetData != null) { // add general sheet info sheetData.boundsheetRecord = bs; this.workBookData.addBoundSheetData(sheetData); } } break; case RecordType.Template: { this.workBookData.Template = true; } break; case RecordType.SST: { /* reads the shared string table biff record and following continue records * creates an array of bytes and then puts that into a memory stream * this all is used to create a longer biffrecord then 8224 bytes. If theres a string * beginning in the SST that is then longer then the 8224 bytes, it continues in the * CONTINUE BiffRecord, so the parser has to read over the SST border. * The problem here is, that the parser has to overread the continue biff record header */ //SST sst; //UInt16 length = bh.length; //// save the old offset from this record begin //this.oldOffset = this.StreamReader.BaseStream.Position; //// create a list of bytearrays to store the following continue records //// List<byte[]> byteArrayList = new List<byte[]>(); //byte[] buffer = new byte[length]; //LinkedList<VirtualStreamReader> vsrList = new LinkedList<VirtualStreamReader>(); //buffer = this.StreamReader.ReadBytes((int)length); //// byteArrayList.Add(buffer); //// create a new memory stream and a new virtualstreamreader //MemoryStream bufferstream = new MemoryStream(buffer); //VirtualStreamReader binreader = new VirtualStreamReader(bufferstream); //BiffHeader bh2; //bh2.id = (RecordType)this.StreamReader.ReadUInt16(); //while (bh2.id == RecordType.Continue) //{ // bh2.length = (UInt16)(this.StreamReader.ReadUInt16()); // buffer = new byte[bh2.length]; // // create a buffer with the bytes from the records and put that array into the // // list // buffer = this.StreamReader.ReadBytes((int)bh2.length); // // byteArrayList.Add(buffer); // // create for each continue record a new streamreader !! // MemoryStream contbufferstream = new MemoryStream(buffer); // VirtualStreamReader contreader = new VirtualStreamReader(contbufferstream); // vsrList.AddLast(contreader); // // take next Biffrecord ID // bh2.id = (RecordType)this.StreamReader.ReadUInt16(); //} //// set the old position of the stream //this.StreamReader.BaseStream.Position = this.oldOffset; SST sst = new SST(this.StreamReader, bh.id, bh.length); //this.StreamReader.BaseStream.Position = this.oldOffset + bh.length; this.workBookData.SstData = sst; } break; case RecordType.EOF: { // Reads the end of the internal file !!! this.StreamReader.BaseStream.Seek(0, SeekOrigin.End); } break; case RecordType.ExternSheet: { ExternSheet extsheet = new ExternSheet(this.StreamReader, bh.id, bh.length); this.externSheets.Add(extsheet); this.workBookData.addExternSheetData(extsheet); } break; case RecordType.SupBook: { SupBook supbook = new SupBook(this.StreamReader, bh.id, bh.length); this.supBooks.Add(supbook); this.workBookData.addSupBookData(supbook); } break; case RecordType.XCT: { XCT xct = new XCT(this.StreamReader, bh.id, bh.length); this.XCTList.Add(xct); this.workBookData.addXCT(xct); } break; case RecordType.CRN: { CRN crn = new CRN(this.StreamReader, bh.id, bh.length); this.CRNList.Add(crn); this.workBookData.addCRN(crn); } break; case RecordType.ExternName: { ExternName externname = new ExternName(this.StreamReader, bh.id, bh.length); this.workBookData.addEXTERNNAME(externname); } break; case RecordType.Format: { Format format = new Format(this.StreamReader, bh.id, bh.length); this.workBookData.styleData.addFormatValue(format); } break; case RecordType.XF: { XF xf = new XF(this.StreamReader, bh.id, bh.length); this.workBookData.styleData.addXFDataValue(xf); } break; case RecordType.Style: { Style style = new Style(this.StreamReader, bh.id, bh.length); this.workBookData.styleData.addStyleValue(style); } break; case RecordType.Font: { Font font = new Font(this.StreamReader, bh.id, bh.length); this.workBookData.styleData.addFontData(font); } break; case RecordType.NAME: case RecordType.Lbl: { Lbl name = new Lbl(this.StreamReader, bh.id, bh.length); this.workBookData.addDefinedName(name); } break; case RecordType.BOF: { this.workBookData.BOF = new BOF(this.StreamReader, bh.id, bh.length); } break; case RecordType.CodeName: { this.workBookData.CodeName = new CodeName(this.StreamReader, bh.id, bh.length); } break; case RecordType.FilePass: { throw new ExtractorException(ExtractorException.FILEENCRYPTED); } break; case RecordType.Palette: { Palette palette = new Palette(this.StreamReader, bh.id, bh.length); workBookData.styleData.setColorList(palette.rgbColorList); } break; default: { // this else statement is used to read BiffRecords which aren't implemented byte[] buffer = new byte[bh.length]; buffer = this.StreamReader.ReadBytes(bh.length); TraceLogger.Debug("Unknown record found. ID {0}", bh.id); } break; } } //} //catch (Exception ex) //{ // TraceLogger.Error(ex.Message); // TraceLogger.Debug(ex.ToString()); //} }