概述: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 有点长,截图看下调用即可,感兴趣的可以自己去看下 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);
        }
    }
 
}