Beispiel #1
0
 public void GetDecodedToken(out uint distance, out uint length)
 {
     if (TokenDecoder != null)
     {
         uint token = TokenDecoder.DecodeSymbol();
         length   = token / (ActualMaxDistance + 1) + ActualMinLength;
         distance = token % (ActualMaxDistance + 1);
     }
     else
     {
         distance = DistanceDecoder.DecodeSymbol();
         length   = LengthDecoder.DecodeSymbol() + ActualMinLength;
     }
 }
Beispiel #2
0
        private static bool isValidCodeBlock(Process process, HEAP_INFO heap, uint address, List <jmpInstruction> jmps, List <retAddress> rets, uint maxLength)
        {
            // Convert this block to a linear block
            byte[] block = getLinearCodeToRet(process, heap, address, jmps, rets, maxLength);

            // Check if this is a valid code block
            //byte[] block = oMemoryFunctions.readMemory(process, address, addressEnd - address);
            int warnings = LengthDecoder.CountWarnings(block);

            if (warnings > 0)
            {
                return(false);
            }

            return(true);
        }
Beispiel #3
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);
        }