Exemple #1
0
        /// <summary>
        /// Estimates the number of input parameters of each funciton.
        /// </summary>
        /// <param name="retList">Return instruction list.</param>
        public static void estimateFunctionParameters(oAsmRetList retList, oEbpArgumentList ebpAddresses, Form parent)
        {
            if (functions == null)
            {
                functions = new List <oFunction>();
            }

            // Estimate the number of parameters for each function return
            int          count    = 0;
            formProgress progress = new formProgress(parent);

            progress.Show(parent);
            progress.setMin(0);
            progress.setMax(oFunctionMaster.numFunctions / 273);
            progress.setTitle("Estimating Number Parameter Counts...");
            progress.setLabel1("Estimating Function Input Parameter Counts: " + count.ToString() + "0 of " + oFunctionMaster.numFunctions.ToString());
            progress.setLabel2("");

            // Loop through each function, estimating the number of parameters
            List <oFunction> invalidFunctions = new List <oFunction>(0);

            foreach (oFunction function in functions)
            {
                // Estimate parameters
                function.estimateNumParameters(retList, ebpAddresses);

                // Check the number of parameters is valid
                if (function.getNumParams() > 50)
                {
                    // Invalid function
                    invalidFunctions.Add(function);
                }

                count++;
                if (count % 273 == 0)
                {
                    progress.setLabel1("Estimating Function Input Parameter Counts: " + count.ToString() + "0 of " + oFunctionMaster.numFunctions.ToString());
                    progress.increment();
                }
            }

            // Remove the invalid functions
            foreach (oFunction function in invalidFunctions)
            {
                functions.Remove(function);
            }


            progress.Dispose();
        }
Exemple #2
0
        /// <summary>
        /// This disassmebles all the modules
        /// </summary>
        public static void disassembleProcess(Form parent, List <HEAP_INFO> selectedHeaps)
        {
            // Create the progress bar
            formProgress progress = new formProgress(parent);

            progress.Show(parent);
            progress.setMin(0);
            progress.setMax(selectedHeaps.Count);
            progress.setTitle("Disassembling Modules...");
            progress.setLabel1("Generating Memory Map");
            progress.setLabel2("Total Discovered Internal Calls: 0");

            // Reset the function master
            oFunctionMaster.reset();

            // Create the return instruction list, for parameter count estimation usage later on
            oAsmRetList      returnAddresses = new oAsmRetList();
            oEbpArgumentList ebpAddresses    = new oEbpArgumentList();

            // Process the selected heaps
            ulong        count        = 0;
            HeaderReader headerReader = null;

            for (int i = 0; i < selectedHeaps.Count; i++)
            {
                HEAP_INFO heap = selectedHeaps[i];

                // Check if it is a PE Header
                if (heap.extra.Contains("PE"))
                {
                    // Process the PE import table
                    headerReader = new HeaderReader(activeProcess, heap.heapAddress);


                    // Set the access rights to this heap so that we can edit the header
                    if (headerReader.importTable.Count > 0)
                    {
                        HEAP_INFO tmpHeapInfo = oMemoryFunctions.LookupAddressInMap(map, headerReader.optHeader.DataDirectory13.VirtualAddress + (uint)heap.heapAddress);

                        if (tmpHeapInfo.heapProtection.Contains("EXECUTE"))
                        {
                            oMemoryFunctions.SetMemoryProtection(activeProcess,
                                                                 (uint)tmpHeapInfo.heapAddress,
                                                                 (uint)tmpHeapInfo.heapLength,
                                                                 MEMORY_PROTECT.PAGE_EXECUTE_READWRITE);
                        }
                        else
                        {
                            oMemoryFunctions.SetMemoryProtection(activeProcess,
                                                                 (uint)tmpHeapInfo.heapAddress,
                                                                 (uint)tmpHeapInfo.heapLength,
                                                                 MEMORY_PROTECT.PAGE_READWRITE);
                        }
                    }


                    // Add all the imported functions
                    foreach (IMPORT_FUNCTION importFunction in headerReader.importTable)
                    {
                        // Lookup the destination address
                        HEAP_INFO destinationHeap = oMemoryFunctions.LookupAddressInMap(map,
                                                                                        (uint)importFunction.targetAddress);

                        // Add this function if it is valid
                        if (destinationHeap.heapProtection.Contains("EXECUTE") && destinationHeap.heapLength > 0)
                        {
                            // Valid destination
                            oFunctionMaster.addCall((uint)importFunction.memoryAddress, (uint)importFunction.targetAddress,
                                                    oFunction.CALL_TYPE.PE_TABLE, importFunction.name);

                            // Disasemble only one function and find return (needed for parametar count estimation)
                            uint length =
                                (uint)
                                (destinationHeap.heapLength -
                                 (importFunction.targetAddress - destinationHeap.heapAddress));
                            if (length > 0x1000)
                            {
                                length = 0x1000;
                            }
                            byte[] block = oMemoryFunctions.ReadMemory(activeProcess, importFunction.targetAddress,
                                                                       length);

                            // Process the function only
                            LengthDecoder.AddFirstRet(block, (int)importFunction.targetAddress, 0, ref returnAddresses);
                        }
                    }

                    // Add all the exported functions
                    if (headerReader.exports.Count > 0)
                    {
                        // Read in this heap
                        HEAP_INFO   tmpHeap;
                        byte[]      block      = null;
                        IEnumerator exportEnum = headerReader.exports.Values.GetEnumerator();
                        if (exportEnum.MoveNext())
                        {
                            tmpHeap = oMemoryFunctions.LookupAddressInMap(map, (uint)((export)exportEnum.Current).Address);
                            block   = oMemoryFunctions.ReadMemory(activeProcess, tmpHeap.heapAddress, (uint)tmpHeap.heapLength);

                            // We need to add all the exported functions from this library
                            foreach (export exportFunction in headerReader.exports.Values)
                            {
                                if ((exportFunction.Address >= tmpHeap.heapAddress) && (exportFunction.Address <= tmpHeap.heapAddress + tmpHeap.heapLength))
                                {
                                    // Add this call
                                    oFunctionMaster.addCall(0, (uint)exportFunction.Address,
                                                            oFunction.CALL_TYPE.PE_EXPORT, exportFunction.Name);

                                    // Disasemble only one function and find return (needed for parameter count estimation)

                                    // Process the function only
                                    LengthDecoder.AddFirstRet(block, (int)tmpHeap.heapAddress,
                                                              (int)(exportFunction.Address - tmpHeap.heapAddress),
                                                              ref returnAddresses);
                                }
                            }
                        }
                    }
                }

                // If this contains EXECUTE privileges, instrument this heap even if it is a PE header.
                // Instrument this heap if it has been selected, but not if it is a PE header region without EXECUTE privileges.
                if (!heap.extra.Contains("PE") || heap.heapProtection.Contains("EXECUTE"))
                {
                    // Disassemble this heap as a code region
                    List <jmpInstruction> jmpAddresses = new List <jmpInstruction>(10000);

                    // Let's process this data region
                    if (heap.associatedModule != null)
                    {
                        progress.setLabel1("Analyzing code region for module " +
                                           heap.associatedModule.ModuleName + " heap at address 0x" +
                                           heap.heapAddress.ToString("X"));
                    }
                    else
                    {
                        progress.setLabel1(
                            "Analyzing code region associated with an unknown module at address 0x" +
                            heap.heapAddress.ToString("X"));
                    }

                    // Read in the heap
                    byte[] block = oMemoryFunctions.ReadMemory(activeProcess, heap.heapAddress, (uint)heap.heapLength);

                    // Process the heap
                    List <SIMPLE_INSTRUCTION> instructions = LengthDecoder.DisassembleBlockCallsOnly(block,
                                                                                                     (int)heap.heapAddress,
                                                                                                     ref returnAddresses,
                                                                                                     ref ebpAddresses,
                                                                                                     ref jmpAddresses);

                    // Get a list of the return instruction addresses for this heap
                    List <retAddress> retAddresses = returnAddresses.getRets((uint)heap.heapAddress, (uint)(heap.heapAddress + heap.heapLength));

                    // Generate a list of call source-destination pairs.
                    List <SOURCE_DEST_PAIR> callPairs = new List <SOURCE_DEST_PAIR>(1000);
                    for (int n = 0; n < instructions.Count; n++)
                    {
                        HEAP_INFO destinationHeap = oMemoryFunctions.LookupAddressInMap(map,
                                                                                        (uint)
                                                                                        instructions[n].jmp_target);


                        if (destinationHeap.heapLength > 0 &&
                            destinationHeap.heapAddress == heap.heapAddress &&
                            isValidCodePointer(activeProcess, instructions[n].address, (uint)instructions[n].jmp_target, headerReader) &&
                            isValidCodeBlock(activeProcess, heap, instructions[n].address, jmpAddresses, retAddresses, 500) &&
                            isValidCodeBlock(activeProcess, heap, instructions[n].jmp_target, jmpAddresses, retAddresses, 500))
                        {
                            // Add this call, it may be filtered out later.
                            callPairs.Add(new SOURCE_DEST_PAIR((uint)instructions[n].address,
                                                               (uint)instructions[n].jmp_target,
                                                               oFunction.CALL_TYPE.FIXED_OFFSET,
                                                               null,
                                                               ""));
                        }
                    }


                    // -----------------------------------
                    // PROPER CALLBACK TABLE CONDITION
                    // -----------------------------------
                    // The start of the callback table is defined as:
                    // 1. 4 dwords in a row that point to within this heap.
                    // 2. Must point to at least 2 different addresses.
                    // 3. All 4 pointers must point to valid code regions.
                    //
                    // The end of the callback table is defined as:
                    // 1. first not heap-internal pointer
                    // 2. or first heap-internal pointer that fails the
                    //    valid function test.
                    //
                    bool inCallbackTable = false;
                    for (int n = 0; n < block.Length - 4 * 4; n += 4)
                    {
                        // Check if this could be the start of a callback table.
                        uint value1 = oMemoryFunctions.ByteArrayToUint(block, n);
                        if (inCallbackTable)
                        {
                            // Check is this value should be added onto the callback table
                            if (value1 >= heap.heapAddress && value1 <= heap.heapAddress + heap.heapLength &&
                                isValidCodePointer(activeProcess, ((uint)n) + (uint)heap.heapAddress, value1, headerReader) &&
                                isValidCodeBlock(activeProcess, heap, value1, jmpAddresses, retAddresses, 500))
                            {
                                // Another valid callback entry
                                callPairs.Add(new SOURCE_DEST_PAIR(((uint)n) + (uint)heap.heapAddress,
                                                                   value1,
                                                                   oFunction.CALL_TYPE.CALLBACK_TABLE,
                                                                   callPairs[callPairs.Count - 1],
                                                                   "vtable"));
                            }
                            else
                            {
                                // End of callback table.
                                inCallbackTable = false;
                            }
                        }
                        else if (value1 >= heap.heapAddress && value1 <= heap.heapAddress + heap.heapLength)
                        {
                            // Check second pointer
                            uint value2 = oMemoryFunctions.ByteArrayToUint(block, n + 4);
                            if (value2 >= heap.heapAddress && value2 <= heap.heapAddress + heap.heapLength)
                            {
                                // Check third pointer
                                uint value3 = oMemoryFunctions.ByteArrayToUint(block, n + 4 * 2);
                                if (value3 >= heap.heapAddress && value3 <= heap.heapAddress + heap.heapLength)
                                {
                                    // Check fourth pointer
                                    uint value4 = oMemoryFunctions.ByteArrayToUint(block, n + 4 * 3);
                                    if (value4 >= heap.heapAddress && value4 <= heap.heapAddress + heap.heapLength)
                                    {
                                        // We found four internal pointers in a row. Check that condition #2 is met.
                                        if (!((value1 == value2 && value1 == value3) ||
                                              (value1 == value2 && value1 == value4) ||
                                              (value2 == value3 && value2 == value4)))
                                        {
                                            // At least two of the values are different

                                            // Check condition #3, all valid code poitners
                                            if (isValidCodePointer(activeProcess, ((uint)n) + (uint)heap.heapAddress, value1, headerReader) &&
                                                isValidCodeBlock(activeProcess, heap, value1, jmpAddresses, retAddresses, 500) &&
                                                isValidCodePointer(activeProcess, ((uint)n + 4 * 1) + (uint)heap.heapAddress, value2, headerReader) &&
                                                isValidCodeBlock(activeProcess, heap, value2, jmpAddresses, retAddresses, 500) &&
                                                isValidCodePointer(activeProcess, ((uint)n + 4 * 2) + (uint)heap.heapAddress, value3, headerReader) &&
                                                isValidCodeBlock(activeProcess, heap, value3, jmpAddresses, retAddresses, 500) &&
                                                isValidCodePointer(activeProcess, ((uint)n + 4 * 3) + (uint)heap.heapAddress, value4, headerReader) &&
                                                isValidCodeBlock(activeProcess, heap, value4, jmpAddresses, retAddresses, 500))
                                            {
                                                // All pointers are valid, start of callback table
                                                inCallbackTable = true;

                                                // Add these function calls
                                                callPairs.Add(new SOURCE_DEST_PAIR(((uint)n) + (uint)heap.heapAddress,
                                                                                   value1,
                                                                                   oFunction.CALL_TYPE.CALLBACK_TABLE,
                                                                                   null,
                                                                                   "vtable"));
                                                callPairs.Add(new SOURCE_DEST_PAIR(((uint)n + 4 * 1) + (uint)heap.heapAddress,
                                                                                   value2,
                                                                                   oFunction.CALL_TYPE.CALLBACK_TABLE,
                                                                                   callPairs[callPairs.Count - 1],
                                                                                   "vtable"));
                                                callPairs.Add(new SOURCE_DEST_PAIR(((uint)n + 4 * 2) + (uint)heap.heapAddress,
                                                                                   value3,
                                                                                   oFunction.CALL_TYPE.CALLBACK_TABLE,
                                                                                   callPairs[callPairs.Count - 1],
                                                                                   "vtable"));
                                                callPairs.Add(new SOURCE_DEST_PAIR(((uint)n + 4 * 3) + (uint)heap.heapAddress,
                                                                                   value4,
                                                                                   oFunction.CALL_TYPE.CALLBACK_TABLE,
                                                                                   callPairs[callPairs.Count - 1],
                                                                                   "vtable"));

                                                // Move on to the next callback
                                                n += 4 * 3; // because n+=4
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }



                    // -----------------------------------
                    // PROPER SUBROUTINE ENTER FILTER CONDITION:
                    // -----------------------------------
                    // Condition Description:
                    // - each subroutine is only called from the start of the subroutine, and no call
                    //   can enter the subroutine in the middle of the function. I have yet to see a
                    //   function that violates rule even under obfuscation (except rarely the skipping
                    //   of hotpatching bytes).
                    //
                    // Condition Implementation:
                    // - only smallest call destination in range (retAddress[i-1], retAddress[i]] is valid
                    //   for funcion i.
                    // - a destination of min destionation + const, where  0 <= const <= 2 is allowed to support
                    //   some obfuscation methods that skip the hotpatching useless bytes.
                    //

                    // Sort the array by the destination
                    SOURCE_DEST_PAIR.COMPARER_DEST comparerDest = new SOURCE_DEST_PAIR.COMPARER_DEST();
                    callPairs.Sort(comparerDest);

                    // Loop through each return instruction
                    for (int n = 0; n < retAddresses.Count; n++)
                    {
                        // Find all destination addresses associated with this function

                        // Find the start destination pair index
                        int indexStart = (n > 0 ? callPairs.BinarySearch(new SOURCE_DEST_PAIR(0, retAddresses[n - 1].address, oFunction.CALL_TYPE.FIXED_OFFSET, null, ""),
                                                                         comparerDest) : 0);
                        if (indexStart < 0)
                        {
                            indexStart = ~indexStart;
                        }

                        // Find the end destination pair index
                        int indexEnd = callPairs.BinarySearch(new SOURCE_DEST_PAIR(0, retAddresses[n].address, oFunction.CALL_TYPE.FIXED_OFFSET, null, ""),
                                                              comparerDest);
                        if (indexEnd < 0)
                        {
                            indexEnd = ~indexEnd - 1;
                        }

                        // If we have more than one call to this procedure, loop through them and maybe filter them out
                        if (indexEnd - indexStart + 1 > 1)
                        {
                            // Find the start of the subroutine
                            uint minDestination = uint.MaxValue;
                            for (int m = indexStart; m <= indexEnd; m++)
                            {
                                if (callPairs[m].dest < minDestination)
                                {
                                    minDestination = callPairs[m].dest;
                                }
                            }

                            // Loop through these call destinations to make sure they are not entering in the middle of the subroutine
                            for (int m = indexStart; m <= indexEnd; m++)
                            {
                                if (callPairs[m].dest > minDestination + 2)
                                {
                                    // This is entering the subrouting in the middle! Remove this call as invalid.
                                    callPairs.RemoveAt(m);
                                    m--;
                                    indexEnd--;
                                }
                            }
                        }
                    }

                    // Add the calls to the function list)
                    for (int n = 0; n < callPairs.Count; n++)
                    {
                        // Add this function call
                        if (disassemblyMode.recordIntramodular)
                        {
                            oFunctionMaster.addCall(callPairs[n].source, callPairs[n].dest, callPairs[n].type, callPairs[n].name);
                        }
                    }
                    count = count + (ulong)instructions.Count;
                }

                progress.setLabel2("Total Discovered Internal Calls: " + count);

                progress.increment();
            }
            progress.Dispose();

            // Estimate number of parameters for each function
            oFunctionMaster.estimateFunctionParameters(returnAddresses, ebpAddresses, parent);
        }
Exemple #3
0
        /// <summary>
        /// This function injects the instrumentation code and
        /// redirects the call instructions and pe tables.
        /// </summary>
        public static bool inject(uint bufferSize, uint maxCallCount, List <HEAP_INFO> invalidCallSourceHeaps, Form parent)
        {
            if (functions.Count > 0)
            {
                // Create the progress bar
                formProgress progress = new formProgress(parent);
                progress.Show();
                progress.setMin(0);
                progress.setMax(functions.Count / 457);
                progress.setTitle("Injecting Function Instrumentation Code...");
                progress.setLabel1("Allocating buffer space...");
                progress.setLabel2("");

                // Create and setup the circular buffer recording buffer for the visualizations.
                uint visualizationAddress = (uint)oMemoryFunctions.VirtualAllocEx(oProcess.activeProcess.Handle,
                                                                                  (IntPtr)0,
                                                                                  20000000 + 1000,
                                                                                  (uint)(MEMORY_STATE.COMMIT),
                                                                                  (uint)MEMORY_PROTECT.PAGE_READWRITE
                                                                                  );
                injectedHeapAddress1 = visualizationAddress;
                injectedHeapSize1    = 20000000 + 1000;


                oMemoryFunctions.WriteMemoryDword(oProcess.activeProcess, visualizationAddress + 4, 0);
                oAssemblyGenerator.addCommonAddress(visualizationAddress + 4, "VIS_AD_CIRCULAR_OFFSET");
                oAssemblyGenerator.addCommonAddress(bufferSize * 1000000 - 8 - 4, "VIS_CIRCULAR_SIZE");
                oAssemblyGenerator.addCommonAddress(visualizationAddress + 16 + 4, "VIS_AD_CIRCULAR_BASE");
                oAssemblyGenerator.addCommonAddress(0, "mainRecordFunction");



                //MessageBox.Show((visualizationAddress + 16).ToString("X"));

                // Create the visualization buffer reader
                reader_visualization = new oCircularBufferReader(visualizationAddress + 16 + 4, bufferSize * 1000000 - 4, visualizationAddress + 4);

                // Set the global buffer parameters
                oMemoryFunctions.WriteMemoryDword(oProcess.activeProcess, visualizationAddress, maxCallCount);
                oAssemblyGenerator.addCommonAddress(visualizationAddress, "MAXCALLS");


                // Determine the size per function
                int sizePerFunc = ((oFunction)functions[0]).generateInstrumentation(10000).Length;

                // Allocate the memory heap for the funciton code injections
                uint currentAddress = (uint)oMemoryFunctions.VirtualAllocEx(oProcess.activeProcess.Handle,
                                                                            (IntPtr)0,
                                                                            functions.Count * sizePerFunc + 1000 + 2 * 0x80000, // 1000 + 2*0x80000 bytes for the mainRecordFunction
                                                                            (uint)(MEMORY_STATE.COMMIT),
                                                                            (uint)MEMORY_PROTECT.PAGE_EXECUTE_READWRITE
                                                                            );
                injectedHeapAddress2 = currentAddress;
                injectedHeapSize2    = (uint)(functions.Count * sizePerFunc + 1000 + 2 * 0x80000);

                if (currentAddress == 0)
                {
                    oConsole.printMessageShow("ERROR: Could not allocate memory space in target process for code injections.");
                    progress.Dispose();
                    return(false);
                }



                progress.setLabel1("Injecting common base functions.");

                // Inject the common function
                oAssemblyGenerator.addCommonAddress(currentAddress, "mainRecordFunction");
                uint size = (uint)oFunction.injectCommonCode(currentAddress);

                // Generate and write the valid read pointer table
                progress.setLabel1("Generating and injecting the read pointer dereference lookup table.");

                // Get the address of the table
                table_addressValidReadTable = UInt32.Parse(oMemoryFunctions.ReverseString(oAssemblyGenerator.evaluateCommonAddress("sLOOKUPVALIDPOINTER", 0, currentAddress)), NumberStyles.HexNumber);
                updateValidReadPointerTable();

                // Generate and write the excluded call source table
                progress.setLabel1("Generating and injecting the exclusion source lookup table.");

                // Get the address of the table
                table_addressInvalidSourceTable = UInt32.Parse(oMemoryFunctions.ReverseString(oAssemblyGenerator.evaluateCommonAddress("sLOOKUPINVALIDSOURCE", 0, currentAddress)), NumberStyles.HexNumber);
                updateInvalidCallSourceTable(invalidCallSourceHeaps);

                // Set the size to dereference option
                dereferenceSizeAddress = UInt32.Parse(oMemoryFunctions.ReverseString(oAssemblyGenerator.evaluateCommonAddress("sSTRINGDEREFERENCESIZE", 0, currentAddress)), NumberStyles.HexNumber);
                oMemoryFunctions.WriteMemoryDword(oProcess.activeProcess, dereferenceSizeAddress, (uint)Properties.Settings.Default.NumDereferencedBytes);

                currentAddress += size;

                // Perform the intecept function code injection
                int count = 0;
                progress.setLabel1("Injecting instrumentation functions and redirecting functions: " + count.ToString() + " of " + functions.Count.ToString());
                foreach (oFunction function in functions)
                {
                    // Inject the instrumentation functions
                    uint injectionAddress = currentAddress;
                    size = (uint)function.injectInstrumentation(currentAddress);

                    // Update the function parameters
                    function.addressCount  = UInt32.Parse(oMemoryFunctions.ReverseString(oAssemblyGenerator.evaluateCommonAddress("sCOUNT", 0, currentAddress)), NumberStyles.HexNumber);
                    function.addressRecord = UInt32.Parse(oMemoryFunctions.ReverseString(oAssemblyGenerator.evaluateCommonAddress("sSAVEDATA", 0, currentAddress)), NumberStyles.HexNumber);

                    // Redirect the function calls
                    function.redirect(injectionAddress);
                    currentAddress += size;

                    // Update the progress bar
                    count++;
                    if ((count % 457) == 0)
                    {
                        progress.setLabel1("Injecting instrumentation functions and redirecting functions: " + count.ToString() + " of " + functions.Count.ToString());
                        progress.increment();
                    }
                }

                progress.Dispose();
            }
            return(true);
        }