c++winapisystem-callsntdll

Calling NtCreateProcessEx fails without exception


I want to call NtCreateProcessEx, But i get no exception and error and nothing happens. Also i don't want to use CreateProcess. My intention is to create and run a process from a file with this specific function.

This what i have tried so far:

#include <Windows.h>
#include <bcrypt.h>
#include "winternl.h"
#pragma comment(lib, "ntdll")

NTSTATUS NTAPI NtCreateProcessEx(
    OUT HANDLE ProcessHandle,
    IN ACCESS_MASK DesiredAccess,
    IN OBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
    IN HANDLE ParentProcess,
    IN BOOLEAN InheritObjectTable,
    IN HANDLE SectionHandle OPTIONAL,
    IN HANDLE DebugPort OPTIONAL,
    IN HANDLE ExceptionPort OPTIONAL,
    IN BOOLEAN InJob);

int main()
{
    const HANDLE ph = nullptr;
    OBJECT_ATTRIBUTES oa;
    UNICODE_STRING fileName;
    RtlInitUnicodeString(&fileName, PCWSTR(L"\\??\\C:\\Windows\\System32\\calc.exe"));
    (&oa)->Length = sizeof(OBJECT_ATTRIBUTES);
    (&oa)->RootDirectory = nullptr;
    (&oa)->Attributes = 0x00000040L;
    (&oa)->ObjectName = &fileName;
    (&oa)->SecurityDescriptor = nullptr;
    (&oa)->SecurityQualityOfService = nullptr;;
    NtCreateProcessEx(ph, PROCESS_ALL_ACCESS, oa, nullptr, FALSE, nullptr, nullptr, nullptr, FALSE);

    return 0;
}

There is no document and example on whole internet about this specific function. I am able to do something somewhat similar to this for NtCreateFile, But this is my closest try for NtCreateProcessEx and no luck.

I work with Visual Studio 2019 and windows 10 1909.

These are some resources that i tried:

  1. NtCreateProcess(Ex) - Can I have a child process inherit the parents address space while running under a different process name?
  2. http://www.rohitab.com/discuss/topic/40191-ntcreateuserprocess/
  3. https://github.com/Microwave89/createuserprocess/blob/master/createuserprocess/main.c
  4. http://www.rohitab.com/discuss/topic/42229-start-a-process-using-ntcreateprocessex-usermode/
  5. https://hshrzd.wordpress.com/2017/12/18/process-doppelganging-a-new-way-to-impersonate-a-process/

Solution

  • First of all, the 3rd parameter is a pointer to the OBJECT_ATTRIBUTES:

    typedef NTSTATUS(NTAPI* fpNtCreateProcessEx)
    (
        PHANDLE     ProcessHandle,
        ACCESS_MASK  DesiredAccess,
        POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
        HANDLE   ParentProcess,
        ULONG    Flags,
        HANDLE SectionHandle     OPTIONAL,
        HANDLE DebugPort     OPTIONAL,
        HANDLE ExceptionPort     OPTIONAL,
        BOOLEAN  InJob
        );
    

    A sample to use(remove error checking):

    #include <windows.h>
    #include <iostream>
    using namespace std;
    #define NtCurrentProcess() ( (HANDLE)(LONG_PTR) -1 )
    typedef struct _LSA_UNICODE_STRING {
        USHORT Length;
        USHORT MaximumLength;
        PWSTR  Buffer;
    } LSA_UNICODE_STRING, * PLSA_UNICODE_STRING, UNICODE_STRING, * PUNICODE_STRING;
    
    
    typedef struct _OBJECT_ATTRIBUTES {
        ULONG           Length;
        HANDLE          RootDirectory;
        PUNICODE_STRING ObjectName;
        ULONG           Attributes;
        PVOID           SecurityDescriptor;
        PVOID           SecurityQualityOfService;
    }  OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;
    
    
    typedef NTSTATUS(NTAPI* fpNtCreateProcessEx)
    (
        PHANDLE     ProcessHandle,
        ACCESS_MASK  DesiredAccess,
        POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
        HANDLE   ParentProcess,
        ULONG    Flags,
        HANDLE SectionHandle     OPTIONAL,
        HANDLE DebugPort     OPTIONAL,
        HANDLE ExceptionPort     OPTIONAL,
        BOOLEAN  InJob
    );
    
    typedef NTSTATUS(NTAPI* fpNtCreateTransaction)
    (
        PHANDLE            TransactionHandle,
        ACCESS_MASK        DesiredAccess,
        POBJECT_ATTRIBUTES ObjectAttributes,
        LPGUID             Uow,
        HANDLE             TmHandle,
        ULONG              CreateOptions,
        ULONG              IsolationLevel,
        ULONG              IsolationFlags,
        PLARGE_INTEGER     Timeout,
        PUNICODE_STRING    Description
    );
    
    typedef NTSTATUS (NTAPI *fpNtCreateSection)
    (
        PHANDLE SectionHandle,
        ACCESS_MASK DesiredAccess,
        POBJECT_ATTRIBUTES ObjectAttributes,
        PLARGE_INTEGER MaximumSize,
        ULONG SectionPageProtection,
        ULONG AllocationAttributes,
        HANDLE FileHandle
    );
    typedef NTSTATUS (NTAPI *fpNtClose)
    (
        HANDLE Handle
    );
    #define PS_INHERIT_HANDLES                      4
    
    int main()
    {
        HANDLE hProcess;
        OBJECT_ATTRIBUTES objattr;
        UNICODE_STRING objname;
        NTSTATUS status;
        WCHAR wstrObjName[MAX_PATH];
        lstrcpyW(wstrObjName, L"C:\\test.exe");
    
        HINSTANCE hinst = LoadLibrary(L"ntdll.dll");
        fpNtCreateProcessEx _NtCreateProcessEx = (fpNtCreateProcessEx)GetProcAddress(hinst, "NtCreateProcessEx");
        fpNtCreateTransaction _NtCreateTransaction = (fpNtCreateTransaction)GetProcAddress(hinst, "NtCreateTransaction");
        fpNtCreateSection _NtCreateSection = (fpNtCreateSection)GetProcAddress(hinst, "NtCreateSection");
        fpNtClose _NtClose = (fpNtClose)GetProcAddress(hinst, "NtClose");
    
        // Initialize ObjectName UNICODE_STRING
        objname.Buffer = wstrObjName;
        objname.Length = wcslen(wstrObjName) * sizeof(WCHAR); // Length in bytes of string, without null terminator
        objname.MaximumLength = MAX_PATH * sizeof(WCHAR);
    
    
        // Initialize OBJECT_ATTRIBUTES
        objattr.Length = sizeof(OBJECT_ATTRIBUTES);
        objattr.Attributes = 0x00000040L; //OBJ_CASE_INSENSITIVE 
        objattr.ObjectName = NULL;
        objattr.RootDirectory = NULL;
        objattr.SecurityDescriptor = NULL;
        objattr.SecurityQualityOfService = NULL;
    
    
        HANDLE hTransaction = NULL;
        status = _NtCreateTransaction(&hTransaction,
            TRANSACTION_ALL_ACCESS,
            &objattr,
            NULL,
            NULL,
            0,
            0,
            0,
            NULL,
            NULL);
    
        HANDLE hTransactedFile = CreateFileTransacted(wstrObjName,
            GENERIC_WRITE | GENERIC_READ,
            0,
            NULL,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            NULL,
            hTransaction,
            NULL,
            NULL);
        HANDLE hSection = NULL;
        status = _NtCreateSection(&hSection,
            SECTION_ALL_ACCESS,
            NULL,
            0,
            PAGE_READONLY,
            SEC_IMAGE,
            hTransactedFile);
    
        status = _NtCreateProcessEx(&hProcess, PROCESS_ALL_ACCESS, NULL, NtCurrentProcess(), PS_INHERIT_HANDLES, hSection, NULL, NULL, false);
        DWORD pid = GetProcessId(hProcess);
        printf("Pid = %d\n", pid);
    
        CloseHandle(hTransactedFile);
        _NtClose(hTransaction);
        _NtClose(hSection);
        _NtClose(hProcess);
        return 0;
    }