/////////////////////////////////////////////////////
            //                                                 //
            // GetKernelModeProcessListingZwq()                //
            //                                                 //
            /////////////////////////////////////////////////////
            //Description:  Queries the cw driver to return a list
            //              of processes using ZwQuerySystemInformation().
            //
            //Returns:      a CWPROCESS_RECORD struct
            /////////////////////////////////////////////////////
            internal static CwStructures.PROCESS_LISTING_ZWQ GetKernelModeProcessListingZwq()
            {
                //-----------------------------
                //      SEND COMMAND
                //-----------------------------
                //build the IOCTL to send to driver
                uint ioctl = Win32Helper.GetIOCTL(CwConstants.CW_DRIVER_PROCESS_LISTING_ZWQ, Win32Helper.METHOD_OUT_DIRECT);

                //build our buffers
                int InBufSize = 0;
                int OutBufSize = Marshal.SizeOf(typeof(CwStructures.PROCESS_LISTING_ZWQ));
                IntPtr lpInBuf = IntPtr.Zero;
                IntPtr lpOutBuf = Marshal.AllocHGlobal(OutBufSize);
                int bytesReturned = 0;

                //send the IOCTL
                try
                {
                    bytesReturned = DriverHelper.SendDriverCommand(ioctl, lpInBuf, InBufSize, ref lpOutBuf, OutBufSize);
                }
                catch (Exception ex)
                {
                    throw new Exception("SendDriverCommand() failed:  " + ex.Message);
                }

                if (bytesReturned == 0)
                    throw new Exception("A 0-length buffer was returned from the driver.");

                //-----------------------------
                //      PROCESS RESULTS
                //-----------------------------
                CwStructures.PROCESS_LISTING_ZWQ processListing = new CwStructures.PROCESS_LISTING_ZWQ();

                //try to marshal the ptr
                try
                {
                    processListing = (CwStructures.PROCESS_LISTING_ZWQ)Marshal.PtrToStructure(lpOutBuf, typeof(CwStructures.PROCESS_LISTING_ZWQ));
                }
                catch (Exception ex)
                {
                    throw new Exception("Failed to marshal lpOutBuf pointer to processListing structure:  " + ex.Message);
                }

                Marshal.FreeHGlobal(lpOutBuf);

                return processListing;
            }
            /////////////////////////////////////////////////////
            //                                                 //
            // IsProcessPidInZwqKMList()                       //
            //                                                 //
            /////////////////////////////////////////////////////
            //Description:  Determines whether or not the given pid
            //              exists in the process list obtained from
            //              the ZwQuerySystemInformation() in kernel mode.
            //
            //Returns:      true if it was found in the list
            /////////////////////////////////////////////////////
            internal static bool IsProcessPidInZwqKMList(uint pid)
            {
                CwStructures.PROCESS_LISTING_ZWQ ZwQueryKmList = new CwStructures.PROCESS_LISTING_ZWQ();
                try
                {
                    ZwQueryKmList = HeuristicsUserModeHelper.GetKernelModeProcessListingZwq();
                }
                catch (Exception ex)
                {
                    AgentScanLog.AppendLine("SCAN:  Failed to get process list using ZwQuerySystemInformation() from kernel mode:  " + ex.Message);
                }

                for (int i = 0; i < ZwQueryKmList.numProcesses; i++)
                {
                    CwStructures.CW_PROCESS_ENTRY process = ZwQueryKmList.ProcessList[i];
                    if (pid == process.UniqueProcessId)
                        return true;
                }
                return false;
            }
            /////////////////////////////////////////////////////
            //                                                 //
            // CrossViewAnalysisWithTrustedProcessList()       //
            //                                                 //
            /////////////////////////////////////////////////////
            //Description:  This cross-view analysis approach uses
            //              a "trusted list" it obtains from PspCidTable
            //              and diffs that across the 3 user mode
            //              methods.
            //
            //Returns:      an array of CWPROCESS_RECORD structs
            /////////////////////////////////////////////////////
            /*internal static CwStructures.CWPROCESS_RECORD[] CrossViewAnalysisWithTrustedProcessList()
            {
                //
                //
                //  TODO:  THIS FUNCTION IS INCOMPLETE!
                //
                //
                //

                //1.  GET TRUSTED PROCESS LIST
                //
                //we will get a listing of processes from kernel mode using the PspCidTable
                uint[] trustedPidList = new uint[256];

                try
                {
                    trustedPidList = HeuristicsUserModeHelper.GetKernelModeProcessListingPspCidTable();
                }
                catch (Exception ex)
                {
                    AgentHeuristicMatches.UserModeMatches.ProcessListing = new CwStructures.CWPROCESS_RECORD[0];
                    AgentScanLog.AppendLine("Failed to get trusted process listing using PspCidTable:  " + ex.Message);
                    return false;
                }

                //build a CWPROCESS_RECORD array for storing hidden processes
                CwStructures.CWPROCESS_RECORD[] hiddenProcesses = new CwStructures.CWPROCESS_RECORD[trustedPidList.Length];

                //take the "trusted" listing and create a process entry for each process
                //we will shortly enumerate processes from user mode in 3 ways and then fill
                //the boolean field of each process in this structure
                for (int i = 0; i < trustedPidList.Length; i++)
                {
                    hiddenProcesses[i] = new CwStructures.CWPROCESS_RECORD();
                    hiddenProcesses[i].pid = trustedPidList[i];
                    hiddenProcesses[i].IsInUserModePsapiList = false;
                    hiddenProcesses[i].IsInUserModeToolhelp32List = false;
                    hiddenProcesses[i].IsInUserModeZwqList = false;
                }
            }*/
            /////////////////////////////////////////////////////
            //                                                 //
            // CrossViewAnalysis()                             //
            //                                                 //
            /////////////////////////////////////////////////////
            //Description:  This cross-view analysis approach creates
            //              four different process listings using
            //              various process enumeration methods and then
            //              diffs all those lists to see if there are
            //              any discrepancies.
            //
            //Returns:      an array of CWPROCESS_RECORD structs
            /////////////////////////////////////////////////////
            internal static CwStructures.CWPROCESS_RECORD[] CrossViewAnalysis()
            {
                //*************************************
                //Cross-view analysis
                //*************************************
                //user mode enumeration methods:
                //  (1)PSAPI
                //  (2)Toolhelp32
                //  (3)ZwQuerySystemInformation
                //
                //kernel mode enumeration methods:
                //  (1)PspCidTable (TODO)
                //  (2)ZwQuerySystemInformation
                //
                //*************************************
                //           GET DATA POINTS
                //*************************************
                //1.  PSAPI
                Process[] PsapiList = Process.GetProcesses();
                //
                //2.  TOOLHELP32
                ArrayList Toolhelp32List = HeuristicsUserModeHelper.GetUserModeProcessListingToolHelp32();
                //3.  ZWQUERYSYSTEMINFORMATION (KERNEL MODE)
                CwStructures.PROCESS_LISTING_ZWQ ZwQueryKmList = new CwStructures.PROCESS_LISTING_ZWQ();
                try
                {
                    ZwQueryKmList = HeuristicsUserModeHelper.GetKernelModeProcessListingZwq();
                }
                catch (Exception ex)
                {
                    AgentScanLog.AppendLine("SCAN:  Failed to get process list using ZwQuerySystemInformation() from kernel mode:  " + ex.Message);
                }
                //4.  ZWQUERYSYSTEMINFORMATION (USER MODE)
                Win32Helper.SYSTEM_PROCESS_INFORMATION[] ZwQueryUmList = new Win32Helper.SYSTEM_PROCESS_INFORMATION[0];
                try
                {
                    ZwQueryUmList = Win32Helper.GetActiveProcessList();
                }
                catch (Exception ex)
                {
                    AgentScanLog.AppendLine("SCAN:  Failed to get process list using ZwQuerySystemInformation from user mode:  " + ex.Message);
                }

                //prepare return structure - initialize our list of processes to the obvious ones
                //in the psapi library (using .NET's Process class)
                ArrayList hiddenProcesses = new ArrayList();
                foreach (Process p in Process.GetProcesses())
                {
                    string pname = "";
                    try
                    {
                        pname = p.MainModule.ModuleName;
                    }
                    catch (Exception) { }

                    AddPidToList(ref hiddenProcesses, (uint)p.Id, GetPsapiParentProcessId(p.ProcessName), pname, "");
                }

                //*************************************
                //  DIFF EACH LIST AGAINST ALL LISTS
                //*************************************
                //
                //1.  PSAPI
                foreach (Process p in PsapiList)
                {
                    if (p.Id == 0)
                        continue;

                    string pname = "";
                    try
                    {
                        pname = p.MainModule.ModuleName;
                    }
                    catch (Exception) { }

                    if (Toolhelp32List != null)
                        if (!HeuristicsUserModeHelper.IsProcessPidInToolhelp32List((uint)p.Id))
                            AddPidToList(ref hiddenProcesses, (uint)p.Id, GetPsapiParentProcessId(p.ProcessName), pname, "Toolhelp32");
                    if (ZwQueryKmList.numProcesses > 0)
                        if (!HeuristicsUserModeHelper.IsProcessPidInZwqKMList((uint)p.Id))
                            AddPidToList(ref hiddenProcesses, (uint)p.Id, GetPsapiParentProcessId(p.ProcessName), pname, "ZwQueryUM");
                    if (ZwQueryUmList.Length > GetPsapiParentProcessId(p.ProcessName))
                        if (!HeuristicsUserModeHelper.IsProcessPidInZwqUMList((uint)p.Id))
                            AddPidToList(ref hiddenProcesses, (uint)p.Id, GetPsapiParentProcessId(p.ProcessName), pname, "ZwQueryKM");
                }
                //2.  Toolhelp32
                if (Toolhelp32List != null)
                {
                    foreach (Win32Helper.PROCESSENTRY32 process in (Win32Helper.PROCESSENTRY32[])Toolhelp32List.ToArray(typeof(Win32Helper.PROCESSENTRY32)))
                    {
                        if (process.th32ProcessID == 0)
                            continue;

                        if (PsapiList != null)
                            if (!HeuristicsUserModeHelper.IsProcessPidInPsapiList(process.th32ProcessID))
                                AddPidToList(ref hiddenProcesses, process.th32ProcessID, process.th32ParentProcessID, process.szExeFile, "Psapi");
                        if (ZwQueryKmList.numProcesses > 0)
                            if (!HeuristicsUserModeHelper.IsProcessPidInZwqKMList(process.th32ProcessID))
                                AddPidToList(ref hiddenProcesses, process.th32ProcessID, process.th32ParentProcessID, process.szExeFile, "ZwQueryUM");
                        if (ZwQueryUmList.Length > 0)
                            if (!HeuristicsUserModeHelper.IsProcessPidInZwqUMList(process.th32ProcessID))
                                AddPidToList(ref hiddenProcesses, process.th32ProcessID, process.th32ParentProcessID, process.szExeFile, "ZwQueryKM");
                    }
                }
                //3.  ZwQuerySystemInformation USER MODE
                if (ZwQueryUmList != null)
                {
                    foreach (Win32Helper.SYSTEM_PROCESS_INFORMATION process in ZwQueryUmList)
                    {
                        if (process.UniqueProcessId == 0)
                            continue;

                        if (PsapiList != null)
                            if (!HeuristicsUserModeHelper.IsProcessPidInPsapiList(process.UniqueProcessId))
                                AddPidToList(ref hiddenProcesses, process.UniqueProcessId, process.InheritedFromUniqueProcessId, process.ImageName.Buffer, "Psapi");
                        if (Toolhelp32List != null)
                            if (!HeuristicsUserModeHelper.IsProcessPidInToolhelp32List(process.UniqueProcessId))
                                AddPidToList(ref hiddenProcesses, process.UniqueProcessId, process.InheritedFromUniqueProcessId, process.ImageName.Buffer, "Toolhelp32");
                        if (ZwQueryKmList.numProcesses > 0)
                            if (!HeuristicsUserModeHelper.IsProcessPidInZwqKMList(process.UniqueProcessId))
                                AddPidToList(ref hiddenProcesses, process.UniqueProcessId, process.InheritedFromUniqueProcessId, process.ImageName.Buffer, "ZwQueryKM");
                    }
                }
                //4.  ZwQuerySystemInformation KERNEL MODE
                if (ZwQueryKmList.numProcesses > 0)
                {
                    for(int i=0;i<ZwQueryKmList.numProcesses;i++)
                    {
                        CwStructures.CW_PROCESS_ENTRY process = ZwQueryKmList.ProcessList[i];

                        if (process.UniqueProcessId == 0)
                            continue;

                        if (PsapiList != null)
                            if (!HeuristicsUserModeHelper.IsProcessPidInPsapiList(process.UniqueProcessId))
                                AddPidToList(ref hiddenProcesses, process.UniqueProcessId, process.InheritedFromUniqueProcessId, process.ImageName, "Psapi");
                        if (Toolhelp32List != null)
                            if (!HeuristicsUserModeHelper.IsProcessPidInToolhelp32List(process.UniqueProcessId))
                                AddPidToList(ref hiddenProcesses, process.UniqueProcessId, process.InheritedFromUniqueProcessId, process.ImageName, "Toolhelp32");
                        if (ZwQueryUmList != null && ZwQueryUmList.Length > 0)
                            if (!HeuristicsUserModeHelper.IsProcessPidInZwqUMList(process.UniqueProcessId))
                                AddPidToList(ref hiddenProcesses, process.UniqueProcessId, process.InheritedFromUniqueProcessId, process.ImageName, "ZwQueryUM");
                    }
                }

                return (CwStructures.CWPROCESS_RECORD[])hiddenProcesses.ToArray(typeof(CwStructures.CWPROCESS_RECORD));
            }