概述:windows CreateProcess 调用过程详解
CreateProcess 的系统调用流程参考:
Making NtCreateUserProcess Work - Hack.Learn.Share CreateProcess 内部实现-CSDN博客
使用说明
函数原型
WINBASEAPI
BOOL
WINAPI
CreateProcessW(
_In_opt_ LPCWSTR lpApplicationName,
_Inout_opt_ LPWSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCWSTR lpCurrentDirectory,
_In_ LPSTARTUPINFOW lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
);以上原型是我们在用户层调用时的接口。
参数说明
参数说明直接看官网说明就行 CreateProcessA 函数 (processthreadsapi.h) - Win32 apps | Microsoft Learn
Demo
【DbgHelp】通过PDB在PE中查找函数|通过PDB在PE中查找函数 【WinFile】credwiz|credwiz
调用流程
用户层的 CreateProcess 调用并不是直接调用的 ntdll 中的接口。而是经过多次转发,最后通过 ntdll 向内核发起调用,调用堆栈大致如下所示,这里了解即可。
[0x0] ntdll!NtCreateUserProcess 0xdf231fc698 0x7ff9da72b473
[0x1] KERNELBASE!CreateProcessInternalW+0xfe3 0xdf231fc6a0 0x7ff9da728a03
[0x2] KERNELBASE!CreateProcessAsUserW+0x63 0xdf231fdc70 0x7ff9daa4de30
[0x3] KERNEL32!CreateProcessAsUserWStub+0x60 0xdf231fdce0 0x7ff9d4a4526b 在 syscall 之前,最终调用到 ntdll 中的 NtCrteateUserProcess。
nt层调用代码
可以看到系统调用表的 ID 为 0x2E。
__int64 NtCreateProcess()
{
__int64 result; // rax
result = 186i64;
if ( (MEMORY[0x7FFE0308] & 1) != 0 )
__asm { int 2Eh; DOS 2+ internal - EXECUTE COMMAND }
else
__asm { syscall; Low latency system call } // syscall 发起系统调用
return result;
}这里也补充下 Kernel32 和 kernelBase 中的调用 从用户层 CreateProcess 调用开始:
Kernel32
BOOL __stdcall CreateProcessAsUserWStub(
HANDLE hToken,
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation)
{
return CreateProcessAsUserW(
hToken,
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
}KernelBase
- CreateProcessAsUserW
BOOL __stdcall CreateProcessAsUserW( HANDLE hToken, LPCWSTR lpAPPLicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { return CreateProcessInternalW( (_DWORD)hToken, (_DWORD)lpApplicationName, (_DWORD)lpCommandLine, (_DWORD)lpProcessAttributes, (__int64)lpThreadAttributes, bInheritHandles, dwCreationFlags, (__int64)lpEnvironment, (__int64)lpCurrentDirectory, (__int64)lpStartupInfo, (__int64)lpProcessInformation); } - CreateProcessInternalW 有点长,截图看下调用即可,感兴趣的可以自己去看下

有什么区别 🤔
看到这里不仅要问,为什么要绕这么一圈,而不是直接调用 ntdll 的 createprocess。可能是为了安全的前提下又能方便调用?
补充一个从 kernel32 调用 CreateProcess 的 Demo
void GetKernel32Proc()
{
typedef BOOL WINAPI func_CreateProcessW(
LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD,
LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION);
HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
if (kernel32)
{
func_CreateProcessW* fCreateProcessW =
(func_CreateProcessW*)GetProcAddress(kernel32, "CreateProcessW");
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
WCHAR szCommandLine[] = L"calc";
if (fCreateProcessW)
{
fCreateProcessW(0, szCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
}
}
}