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

作者:

在

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

#include

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

#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;
}

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注