Porting original C implementation of Hells/Halos gate to C++

As a fairly new C++ malware dev several issues arose when simply trying to copy and paste the C project into a C++ project. I was more of a C# dev until I discovered DLL sideloading, also known as DLL proxying. DLL sideloading has become more prevalent in the wild and red teaming, and I can see why, it can achieve a level of persistence, the malicious DLL is executed by a signed and certified executable, and DLL loading is native to the Windows OS. This can all look benign to EDRs, AVs, and blue teamers. Once this was discovered, I had to learn C++ so I could create a malicious DLL. My goal was to take the original C source code of HellsGate and make it functional in C++, and that’s what this post is about. In this example I created a control panel applet file that performs process injection into a notepad process. A cpl file is a DLL that exports the “CplApplet” function and is renamed to have a “.cpl” extension. It can be executed by simply double clicking on it. When the cpl is doubleclicked, a rundll32 process is spawned and loads the cpl into memory, and executes it.

The issue I encountered when trying to port the C code to C++ was the HellDescent function.

This small assembly function is responsible for executing the syscall to the kernel. The global variable wSystemCall is retrieved by the other assembly function HellsGate.
HellsGate assembly function.

In the C code the HellDescent function required no parameters or arguments in the function prototype to be passed to it. And yet it was able to perform process injection with the following functions: NtOpenProcess, NtAllocateVirtualMemory, NtWriteProcess, NtVirtualProtect, NtCreateThreadEx, and NtWaitForSingleObject.

function prototype of HellDescent in the original C code.
example of the HellDescent function with parameters used in the NtOpenProcess function.

This was not the case in C++, the error returned by the compiler was that the HellDescent function does not take 4 arguments, 6 arguments, and so on. At first, I was not aware that optional parameters and function overloading is not possible in C, so I tried to do that until I discovered that this solution would not work. The solution I came up with was to add assembly functions in the asm file, each of these functions will have a prototype declared with parameters that pertains to each ntdll function.

I do this for every Nt function I need. You can notice that the code in the Nt functions is the same as HellDescent.
Function prototype declarations. The extern “C” is important, it allows us to call the external assembly functions in the asm file. It also has to be of type NTSTATUS. This process will have to be completed for each Nt function, I used a tool on github named SysWhispers to find the correct parameters and data types that the Nt function needs.
example of NtOpenProcess. The hellsgate function is called as usual.
As you can see, the code works as intended.

That is it for this small blog post, I hope this post can help save time to anyone new to C/C++ or red teaming in general. Stay tuned for more blog post from me, I believe my next one will be about DLL sideloading, in depth.

The source code is on my github repo:

Original C implentation of HellsGate can be found here:




Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store

Cybersec researcher/Malware Dev/Aspiring Red Teamer/Reverse Engineer/<3 Windows internals