/// <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;
        }
        /// <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();
        }