In this blog, we will be examining how, over the course of a couple hours, I wrote a process injection from scratch without any googling or crawling github etc... using just the Assistant at chat.openai.com.

Apologies for the image quality, this blog was moved a couple times...

I am fascinated by machine learning and early AI. I have been particularly interested in programming or coding assistants. I've used Copilot and replit, and a few others. So of course when I got access to chat.openai.com, I quickly began talking to it about code, and in code.

I quickly realized that many restrictions on our dialogue could be bypassed by invoking code. For example, if you ask Assistant specifically how to hack something, it will likely get flagged as a content violation and Assistant will probably give some boilerplate reply about how that is dangerous and potentially illegal. Sometimes you can convince Assistant to tell you anyway through debate, but what I have found is that it is much easier to just go lower level and talk code.

And here we get to the meat of the thing. See, if you want Assistant or Copilot or any coding ML/AI assistant to be possible, then you have to allow it to be used for certain things. Similar to anti-virus and EDR, the problem is essentially the same. If you refuse to let Assistant talk to me about how to use certain Windows API calls, like VirtualProtectEx or CreateRemoteThread, you will have to deny those to everyone. That wouldn't make sense, the documentation is posted by Microsoft and has far more legitimate use cases than malicious. And so you can never really prevent hackers from using a code assistant to write "malicious" code. Same as always.

So what did I do? I decided to have Assistant help me write a process injection. Mostly because I need more help and practice working with memory and Windows APIs.

How did I start? Well one thing I realized early on, is that breaking the project down into pieces allowed Assistant to be much more accurate, and helped avoid some of the issues around the content getting flagged. So I started small. I asked, what are some uncommon ways of obtaining handles to current user processes? After a couple of discussions on some of the more common ways, Assistant suggested I look into EnumWindows function. Interesting, I was not familiar with this one...

After looking at the documentation for EnumWindows on the Microsoft site, I was excited to get started. At first I thought this function would let me grab handles to any process with a visible window, handles that I could pass to other functions for my process injection (this is only slightly true). In the end, you'll see that this is not totally the case, and I had to perform several more steps to get the handles I was after. But even this, at some point I asked Assistant, why I was unable to pass these handles from EnumWindows to certain other functions, and it did explain to me the difference between a handle to a window and a handle to a process.

So after discussing the enumeration portion of the code, I had a program that is able to enumerate all the processes with visible windows on the current user desktop. Except, that right away, I noticed that many processes that do not seem to have visible windows, appear in the list.

After a brief review, I had already picked out some good targets for process injection, namely:

svchost.exe RuntimeBroker.exe OneDrive.exe

These processes seemed like good candidates for my proof-of-concept tool. I wanted something I could hardcode, that would be likely to exist in most cases. My testing across a few different machines confirmed that these were my best candidates for a Windows environment.

During testing, I asked Assistant, who agreed with the selection of svchost.exe (later I changed it to OneDrive, but they all work fine). From our session:

"Kirk Trychel: those are all good points, for the purposes of this exercise, let's use : svchost.exe

Assistant: That's a good choice. svchost.exe is a system process that often hosts multiple services, so there's a good chance that it has the necessary privileges to launch calc.exe. To inject shellcode into the process, you'll need to find its process ID and then use the OpenProcess function to open a handle to the process with the PROCESS_ALL_ACCESS flag. You can then use the VirtualAllocEx function to allocate memory in the process's address space and WriteProcessMemory to write the shellcode to the allocated memory. Finally, you can use the CreateRemoteThread function to create a new thread in the process that will execute the shellcode. This will effectively run the shellcode as if it were part of the svchost.exe process. " (taken from session notes available on github repo)

The next step was to determine how I was going to write my code to these processes. As you can see above, Assistant made the suggestion to use the following : VirtualAllocEx WriteProcessMemory VirtualProtectEx CreateRemoteThread

We also discussed some other options and played with some code around using the Backup and Restore API, QueueUserAPC, and process snapshotting. But for this proof of concept, I wanted something simpler, so we stuck with CreateRemoteThread, etc...

This is where I realized that these window handles were not what I needed. I couldn't properly allocate or write memory to the pages. I checked with Assistant about why that might be, and was informed (see session notes on github) about the fact that I am trying to pass a handle to a window instead of a handle to a process. At first, I was really bummed because I wanted to avoid using OpenProcess or OpenThread, but I did POC some other methods using process snapshotting and NtGetNextProcess, but eventually I decided that I wanted to stick with this method, because at least I was narrowing down my processes to a specific target before opening a handle to it. I felt this was maybe better than opening handles to all processes and frankly I didn't want to deal with process snapshotting in this example. So we stuck with using OpenProcess but using it after our logic that identifies a specific process target.

In order to do this, we set up an if statement inside the callback to EnumWindows which checks our collected vector of process names for a specific target process name. In this case I hardcoded OneDrive.exe, but obviously it would be very easy to add some logic to accept this variable as a commandline argument. In the logic, if the process name being iterated over matches our hardcoded target, a function is called named inject_shellcode, which takes the process handle, shellcode, and shellcode_size as arguments.

Now I really like how Assistant set this part up, because usually I see the actual process injection happening in main, without having its own function setup. It was nice because I was able to debug things more easily this way I felt. It is worth mentioning, that by this point in our discussion and coding session, Assistant didn't seem to mind talking about injecting shellcode into our target process. I simply asked Assistant to set that part up now, based on our previous work, and it spit out the following function (I've had minor changes):

For real, that is pretty nice right? I mean I was pretty happy with it... As I mentioned, I made minor changes. This applies really for all the code I have talked about so far. Assistant was great at laying things out, but sometimes would make mistakes. I would say I probably had to modify 10-20% of the code it gave me overall. But considering that I wrote this process injection, from initial concept of "Hey I wonder what weird ways I could enum user-land processes" and finding out about EnumWindows, to having a working proof of concept process injection (that defender doesn't complain about ;) , in a matter of hours... It is pretty amazing I think.

And with that, we had our program:

And today I am open sourcing the program we wrote together, with author credit for Assistant, as well as including some of our raw session data from building the tool, and some of my research notes. Enjoy! Catch me on Twitter @Teach2Breach and let me know what you think or what amazing stuff you've done with Assistant.

repo: InjectWindow
twitter: Kirk Trychel (@Teach2Breach)
Assistant: chatGPT