首页 > 未分类 > 使用 Native API 创建进程 (Vista+)

使用 Native API 创建进程 (Vista+)

Vista+ 把很多事情都挪到内核里面去了,好像是因为“受保护的进程”的原因。

#include <Windows.h>

//
// 用到的各种宏、类型、函数的声明。
//

#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL)

typedef __success(return >= 0) LONG NTSTATUS;
typedef NTSTATUS *PNTSTATUS;

#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)

typedef struct _STRING
{
    USHORT Length;
    USHORT MaximumLength;
    __field_bcount_part_opt(MaximumLength, Length) PCHAR Buffer;
} STRING, *PSTRING, ANSI_STRING, *PANSI_STRING, OEM_STRING, *POEM_STRING;

typedef struct _UNICODE_STRING
{
    USHORT Length;
    USHORT MaximumLength;
    __field_bcount_part(MaximumLength, Length) PWCH Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

#define RTL_CONSTANT_STRING(s) { sizeof(s) - sizeof((s)[0]), sizeof(s), s }

typedef struct _OBJECT_ATTRIBUTES
{
    ULONG Length;
    HANDLE RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;
    PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;

#define DOS_MAX_COMPONENT_LENGTH 255
#define DOS_MAX_PATH_LENGTH (DOS_MAX_COMPONENT_LENGTH + 5)

typedef struct _CURDIR
{
    UNICODE_STRING DosPath;
    HANDLE Handle;
} CURDIR, *PCURDIR;

#define RTL_USER_PROC_CURDIR_CLOSE 0x00000002
#define RTL_USER_PROC_CURDIR_INHERIT 0x00000003

typedef struct _RTL_DRIVE_LETTER_CURDIR
{
    USHORT Flags;
    USHORT Length;
    ULONG TimeStamp;
    STRING DosPath;
} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;

#define RTL_MAX_DRIVE_LETTERS 32
#define RTL_DRIVE_LETTER_VALID (USHORT)0x0001

typedef struct _RTL_USER_PROCESS_PARAMETERS
{
    ULONG MaximumLength;
    ULONG Length;

    ULONG Flags;
    ULONG DebugFlags;

    HANDLE ConsoleHandle;
    ULONG ConsoleFlags;
    HANDLE StandardInput;
    HANDLE StandardOutput;
    HANDLE StandardError;

    CURDIR CurrentDirectory;
    UNICODE_STRING DllPath;
    UNICODE_STRING ImagePathName;
    UNICODE_STRING CommandLine;
    PVOID Environment;

    ULONG StartingX;
    ULONG StartingY;
    ULONG CountX;
    ULONG CountY;
    ULONG CountCharsX;
    ULONG CountCharsY;
    ULONG FillAttribute;

    ULONG WindowFlags;
    ULONG ShowWindowFlags;
    UNICODE_STRING WindowTitle;
    UNICODE_STRING DesktopInfo;
    UNICODE_STRING ShellInfo;
    UNICODE_STRING RuntimeData;
    RTL_DRIVE_LETTER_CURDIR CurrentDirectories[RTL_MAX_DRIVE_LETTERS];

    ULONG EnvironmentSize;
    ULONG EnvironmentVersion;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

#define RTL_USER_PROC_PARAMS_NORMALIZED 0x00000001

// begin_rev
#define PS_ATTRIBUTE_NUMBER_MASK 0x0000ffff
#define PS_ATTRIBUTE_THREAD 0x00010000 // can be used with threads
#define PS_ATTRIBUTE_INPUT 0x00020000 // input only
#define PS_ATTRIBUTE_UNKNOWN 0x00040000
// end_rev

// private
typedef enum _PS_ATTRIBUTE_NUM
{
    PsAttributeParentProcess, // in HANDLE
    PsAttributeDebugPort, // in HANDLE
    PsAttributeToken, // in HANDLE
    PsAttributeClientId, // out PCLIENT_ID
    PsAttributeTebAddress, // out PTEB *
    PsAttributeImageName, // in PWSTR
    PsAttributeImageInfo, // out PSECTION_IMAGE_INFORMATION
    PsAttributeMemoryReserve, // in PPS_MEMORY_RESERVE
    PsAttributePriorityClass, // in UCHAR
    PsAttributeErrorMode, // in ULONG
    PsAttributeStdHandleInfo, // 10, in PPS_STD_HANDLE_INFO
    PsAttributeHandleList, // in PHANDLE
    PsAttributeGroupAffinity, // in PGROUP_AFFINITY
    PsAttributePreferredNode, // in PUSHORT
    PsAttributeIdealProcessor, // in PPROCESSOR_NUMBER
    PsAttributeUmsThread, // ? in PUMS_CREATE_THREAD_ATTRIBUTES
    PsAttributeMitigationOptions, // in UCHAR
    PsAttributeMax
} PS_ATTRIBUTE_NUM;

// begin_rev

#define PsAttributeValue(Number, Thread, Input, Unknown) \
    (((Number) & PS_ATTRIBUTE_NUMBER_MASK) | \
    ((Thread) ? PS_ATTRIBUTE_THREAD : 0) | \
    ((Input) ? PS_ATTRIBUTE_INPUT : 0) | \
    ((Unknown) ? PS_ATTRIBUTE_UNKNOWN : 0))

#define PS_ATTRIBUTE_PARENT_PROCESS \
    PsAttributeValue(PsAttributeParentProcess, FALSE, TRUE, TRUE)
#define PS_ATTRIBUTE_DEBUG_PORT \
    PsAttributeValue(PsAttributeDebugPort, FALSE, TRUE, TRUE)
#define PS_ATTRIBUTE_TOKEN \
    PsAttributeValue(PsAttributeToken, FALSE, TRUE, TRUE)
#define PS_ATTRIBUTE_CLIENT_ID \
    PsAttributeValue(PsAttributeClientId, TRUE, FALSE, FALSE)
#define PS_ATTRIBUTE_TEB_ADDRESS \
    PsAttributeValue(PsAttributeTebAddress, TRUE, FALSE, FALSE)
#define PS_ATTRIBUTE_IMAGE_NAME \
    PsAttributeValue(PsAttributeImageName, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_IMAGE_INFO \
    PsAttributeValue(PsAttributeImageInfo, FALSE, FALSE, FALSE)
#define PS_ATTRIBUTE_MEMORY_RESERVE \
    PsAttributeValue(PsAttributeMemoryReserve, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_PRIORITY_CLASS \
    PsAttributeValue(PsAttributePriorityClass, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_ERROR_MODE \
    PsAttributeValue(PsAttributeErrorMode, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_STD_HANDLE_INFO \
    PsAttributeValue(PsAttributeStdHandleInfo, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_HANDLE_LIST \
    PsAttributeValue(PsAttributeHandleList, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_GROUP_AFFINITY \
    PsAttributeValue(PsAttributeGroupAffinity, TRUE, TRUE, FALSE)
#define PS_ATTRIBUTE_PREFERRED_NODE \
    PsAttributeValue(PsAttributePreferredNode, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_IDEAL_PROCESSOR \
    PsAttributeValue(PsAttributeIdealProcessor, TRUE, TRUE, FALSE)
#define PS_ATTRIBUTE_MITIGATION_OPTIONS \
    PsAttributeValue(PsAttributeMitigationOptions, FALSE, TRUE, TRUE)

// end_rev

// begin_private

typedef struct _PS_ATTRIBUTE
{
    ULONG Attribute;
    SIZE_T Size;
    union
    {
        ULONG Value;
        PVOID ValuePtr;
    };
    PSIZE_T ReturnLength;
} PS_ATTRIBUTE, *PPS_ATTRIBUTE;

typedef struct _PS_ATTRIBUTE_LIST
{
    SIZE_T TotalLength;
    PS_ATTRIBUTE Attributes[1];
} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST;

typedef struct _PS_MEMORY_RESERVE
{
    PVOID ReserveAddress;
    SIZE_T ReserveSize;
} PS_MEMORY_RESERVE, *PPS_MEMORY_RESERVE;

typedef enum _PS_STD_HANDLE_STATE
{
    PsNeverDuplicate,
    PsRequestDuplicate, // duplicate standard handles specified by PseudoHandleMask, and only if StdHandleSubsystemType matches the image subsystem
    PsAlwaysDuplicate, // always duplicate standard handles
    PsMaxStdHandleStates
} PS_STD_HANDLE_STATE;

// begin_rev
#define PS_STD_INPUT_HANDLE 0x1
#define PS_STD_OUTPUT_HANDLE 0x2
#define PS_STD_ERROR_HANDLE 0x4
// end_rev

typedef struct _PS_STD_HANDLE_INFO
{
    union
    {
        ULONG Flags;
        struct
        {
            ULONG StdHandleState : 2; // PS_STD_HANDLE_STATE
            ULONG PseudoHandleMask : 3; // PS_STD_*
        };
    };
    ULONG StdHandleSubsystemType;
} PS_STD_HANDLE_INFO, *PPS_STD_HANDLE_INFO;

// windows-internals-book:"Chapter 5"
typedef enum _PS_CREATE_STATE
{
    PsCreateInitialState,
    PsCreateFailOnFileOpen,
    PsCreateFailOnSectionCreate,
    PsCreateFailExeFormat,
    PsCreateFailMachineMismatch,
    PsCreateFailExeName, // Debugger specified
    PsCreateSuccess,
    PsCreateMaximumStates
} PS_CREATE_STATE;

typedef enum _PS_IFEO_KEY_STATE
{
    PsReadIFEOAllValues,
    PsSkipIFEODebugger,
    PsSkipAllIFEO,
    PsMaxIFEOKeyStates
} PS_IFEO_KEY_STATE, *PPS_IFEO_KEY_STATE;

typedef struct _PS_CREATE_INFO
{
    SIZE_T Size;
    PS_CREATE_STATE State;
    union
    {
        // PsCreateInitialState
        struct
        {
            union
            {
                ULONG InitFlags;
                struct
                {
                    UCHAR WriteOutputOnExit : 1;
                    UCHAR DetectManifest : 1;
                    UCHAR SpareBits1 : 6;
                    UCHAR IFEOKeyState : 2; // PS_IFEO_KEY_STATE
                    UCHAR SpareBits2 : 6;
                    USHORT ProhibitedImageCharacteristics : 16;
                };
            };
            ACCESS_MASK AdditionalFileAccess;
        } InitState;

        // PsCreateFailOnSectionCreate
        struct
        {
            HANDLE FileHandle;
        } FailSection;

        // PsCreateFailExeName
        struct
        {
            HANDLE IFEOKey;
        } ExeName;

        // PsCreateSuccess
        struct
        {
            union
            {
                ULONG OutputFlags;
                struct
                {
                    UCHAR ProtectedProcess : 1;
                    UCHAR AddressSpaceOverride : 1;
                    UCHAR DevOverrideEnabled : 1; // from Image File Execution Options
                    UCHAR ManifestDetected : 1;
                    UCHAR SpareBits1 : 4;
                    UCHAR SpareBits2 : 8;
                    USHORT SpareBits3 : 16;
                };
            };
            HANDLE FileHandle;
            HANDLE SectionHandle;
            ULONGLONG UserProcessParametersNative;
            ULONG UserProcessParametersWow64;
            ULONG CurrentParameterFlags;
            ULONGLONG PebAddressNative;
            ULONG PebAddressWow64;
            ULONGLONG ManifestAddress;
            ULONG ManifestSize;
        } SuccessState;
    };
} PS_CREATE_INFO, *PPS_CREATE_INFO;

extern "C"
NTSYSCALLAPI
NTSTATUS
NTAPI
ZwCreateUserProcess(
    __out PHANDLE ProcessHandle,
    __out PHANDLE ThreadHandle,
    __in ACCESS_MASK ProcessDesiredAccess,
    __in ACCESS_MASK ThreadDesiredAccess,
    __in_opt POBJECT_ATTRIBUTES ProcessObjectAttributes,
    __in_opt POBJECT_ATTRIBUTES ThreadObjectAttributes,
    __in ULONG ProcessFlags,
    __in ULONG ThreadFlags,
    __in_opt PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
    __inout PPS_CREATE_INFO CreateInfo,
    __in_opt PPS_ATTRIBUTE_LIST AttributeList
    );;

#define IMAGE_PATH L"\\??\\C:\\Windows\\System32\\cmd.exe"

#define PointerAdd(Pointer, Increment, ResultType) ((ResultType)((ULONG_PTR)(Pointer) \
  + (ULONG_PTR)(Increment)))

#define RoundUp(Value, Alignment) (((Value) + (Alignment) - 1) / (Alignment) * (Alignment))

//
// 创建用户进程参数。
//

static NTSTATUS PsCreateProcessParameters(
  OUT PRTL_USER_PROCESS_PARAMETERS *ProcessParameters,
  IN PUNICODE_STRING ImagePath,
  IN PUNICODE_STRING CurrentDirectory,
  IN PWSTR Environment,
  IN ULONG EnvironmentSize
  )
{
  static UNICODE_STRING EmptyUnicodeString = RTL_CONSTANT_STRING(L"");
  static UNICODE_STRING DefaultDesktop = RTL_CONSTANT_STRING(L"Winsta0\\Default");

  PRTL_USER_PROCESS_PARAMETERS LocalProcessParameters;
  PUNICODE_STRING CommandLine, WindowTitle, DesktopInfo, ShellInfo, RuntimeData, DllPath;
  ULONG ProcessParametersSize;
  PWSTR CurrentString;

  CommandLine = ImagePath;
  DllPath = &EmptyUnicodeString;
  WindowTitle = &EmptyUnicodeString;
  DesktopInfo = &DefaultDesktop;
  ShellInfo = &EmptyUnicodeString;
  RuntimeData = &EmptyUnicodeString;

  //
  // 计算用户进程参数的大小。
  //

  ProcessParametersSize = sizeof(RTL_USER_PROCESS_PARAMETERS) + 
    RoundUp(ImagePath->Length + sizeof(UNICODE_NULL), sizeof(ULONG)) +
    RoundUp(CommandLine->Length + sizeof(UNICODE_NULL), sizeof(ULONG)) +
    RoundUp(DllPath->MaximumLength, sizeof(ULONG)) +
    RoundUp(WindowTitle->MaximumLength, sizeof(ULONG)) +
    RoundUp(DesktopInfo->MaximumLength, sizeof(ULONG)) +
    RoundUp(ShellInfo->MaximumLength, sizeof(ULONG)) +
    RoundUp(RuntimeData->MaximumLength, sizeof(ULONG)) +
    RoundUp(DOS_MAX_PATH_LENGTH / sizeof(CHAR) * sizeof(WCHAR), sizeof(ULONG));

  //
  // 为用户进程参数分配内存。
  //

  LocalProcessParameters = (PRTL_USER_PROCESS_PARAMETERS)malloc(ProcessParametersSize);

  if (!LocalProcessParameters) {
    return STATUS_INSUFFICIENT_RESOURCES;
  }

  //
  // 初始化用户进程参数。
  //

  RtlZeroMemory(LocalProcessParameters, ProcessParametersSize);

  LocalProcessParameters->Length = LocalProcessParameters->MaximumLength = 
    ProcessParametersSize;
  LocalProcessParameters->Flags = RTL_USER_PROC_PARAMS_NORMALIZED;
  LocalProcessParameters->DebugFlags = 0;
  LocalProcessParameters->Environment = (PVOID)Environment;
  LocalProcessParameters->EnvironmentSize = EnvironmentSize;
  LocalProcessParameters->CurrentDirectory.Handle = 0;
  LocalProcessParameters->ConsoleFlags = 0;
  
  //
  // 复制字符串。
  //

#define PspCopyUnicodeString(BufferPointer, Destination, Source, AllocationSize) \
  (Destination)->Buffer = BufferPointer; \
  (Destination)->Length = (Source)->Length; \
  (Destination)->MaximumLength = AllocationSize; \
  RtlCopyMemory(BufferPointer, (PVOID)(Source)->Buffer, Source->Length); \
  BufferPointer = PointerAdd(BufferPointer, RoundUp( \
    AllocationSize, sizeof(ULONG)), PWSTR);

  CurrentString = (PWCHAR)(LocalProcessParameters + 1);

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->ImagePathName, 
    ImagePath, ImagePath->Length + sizeof(UNICODE_NULL));

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->CommandLine, 
    CommandLine, CommandLine->Length + sizeof(UNICODE_NULL));

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->DllPath, 
    DllPath, DllPath->MaximumLength);

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->WindowTitle, 
    WindowTitle, WindowTitle->MaximumLength);

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->DesktopInfo, 
    DesktopInfo, DesktopInfo->MaximumLength);

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->ShellInfo, 
    ShellInfo, ShellInfo->MaximumLength);

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->RuntimeData, 
    RuntimeData, RuntimeData->MaximumLength);

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->CurrentDirectory.DosPath,
    CurrentDirectory, DOS_MAX_PATH_LENGTH / sizeof(CHAR) * sizeof(WCHAR));

#undef PspCopyUnicodeString

  //
  // 返回结果给调用方。
  //

  *ProcessParameters = LocalProcessParameters;

  return STATUS_SUCCESS;
}

//
// 释放用户进程参数。
//

static VOID PsFreeProcessParameters(
  IN PRTL_USER_PROCESS_PARAMETERS ProcessParameters
  )
{
  free((PVOID)ProcessParameters);

  return;
}

//
// 创建环境变量信息。
//

static NTSTATUS PsCreateEnvironment(
  OUT PWSTR *Environment,
  OUT ULONG *EnvironmentSize
  )
{
  static PWSTR LocalEnvironment = L"\0";

  //
  // FIX: 目前只是返回一个空的环境变量信息。应改为从注册表(
  // Registry\Machine\System\CurrentControlSet\Control\Session Manager\Environment)
  // 查询。
  //
  // 环境变量信息也可以从 PEB 中获取。
  //

  *Environment = LocalEnvironment;
  *EnvironmentSize = sizeof(LocalEnvironment);

  return STATUS_SUCCESS;
}

//
// 释放环境变量信息。
//

static VOID PsFreeEnvironment(
  IN PWSTR Environment
  )
{
  //
  // 因为目前环境变量信息是一个静态变量,因此不需释放。
  //

  UNREFERENCED_PARAMETER(Environment);

  return;
}

//
// 创建进程。
//

NTSTATUS PsCreateProcess(
  OUT HANDLE *ProcessHandle,
  OUT HANDLE *ThreadHandle,
  IN PUNICODE_STRING ImagePath
  )
{
  static UNICODE_STRING CurrentDirectory = RTL_CONSTANT_STRING(L"C:\\");

  PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
  PWSTR Environment;
  ULONG EnvironmentSize;
  PS_CREATE_INFO CreateInfo = {0};
  PS_ATTRIBUTE_LIST AttributeList = {0};
  NTSTATUS Status;

  //
  // 创建环境变量。
  //

  Status = PsCreateEnvironment(&Environment, &EnvironmentSize);
  
  if (!NT_SUCCESS(Status)) {
    return Status;
  }

  //
  // 创建进程参数。
  //

  Status = PsCreateProcessParameters(&ProcessParameters, ImagePath, &CurrentDirectory,
    Environment, EnvironmentSize);

  if (!NT_SUCCESS(Status)) {
    PsFreeEnvironment(Environment);

    return Status;
  }
   
  //
  // 初始化 PS_CREATE_INFO 结构体。
  //

  CreateInfo.Size = sizeof(PS_CREATE_INFO);
  CreateInfo.State = PsCreateInitialState;

  //
  // 将文件名通过 PS_ATTRIBUTE_LIST 传给 ZwCreateUserProcess。
  //

  AttributeList.TotalLength = sizeof(PS_ATTRIBUTE_LIST);
  AttributeList.Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME;
  AttributeList.Attributes[0].Size = ImagePath->Length;
  AttributeList.Attributes[0].ValuePtr = (PVOID)ImagePath->Buffer;

  //
  // 创建进程。
  //

  Status = ZwCreateUserProcess(ProcessHandle, ThreadHandle, MAXIMUM_ALLOWED, MAXIMUM_ALLOWED,
    NULL, NULL, 0, 0, ProcessParameters, &CreateInfo, &AttributeList);

  PsFreeProcessParameters(ProcessParameters);
  PsFreeEnvironment(Environment);

  if (!NT_SUCCESS(Status)) {
    return Status;
  }

  return Status;
}

int main() {
  static UNICODE_STRING strImagePath = RTL_CONSTANT_STRING(IMAGE_PATH);

  HANDLE hProcess, hThread;
  NTSTATUS Status;

  Status = PsCreateProcess(&hThread, &hProcess, &strImagePath);

  if (NT_SUCCESS(Status)) {
    CloseHandle(hThread);
    CloseHandle(hProcess);
  }
   
  return 0;
}

  1. 本文目前尚无任何评论.