← Learn

Load Resources

Author
Moise Medici
Updated
22 Jan 2026 · Completed

Loading the resource

The resource management process is more involved than simply accessing the resource. The following steps are required:

  • find the address of the resource and load it (FindResourceW 2 and LoadResource 3)
  • get a pointer to the resource with LockResource 4
  • get the size of the resource so that it can be allocated in memory or written to a file with SizeofResource 5
load_resource.c
#include <windows.h>
#include <stdio.h>
#define RET_SUCCESS 0
#define RET_ERROR -1
int main() {
HRSRC hRsrc = NULL;
HGLOBAL hRes = NULL;
HANDLE hFile = NULL;
PVOID pData = NULL;
SIZE_T resSize = 0;
DWORD bytesWritten = 0;
hRsrc = FindResourceW(NULL, L"CALCICO", MAKEINTRESOURCEW(10));
if (hRsrc == NULL) {
printf("Cannot locate resource, error: %lu \n", GetLastError());
return RET_ERROR;
}
resSize = SizeofResource(NULL, hRsrc);
if (resSize == 0) {
printf("Cannot get the size of resource, error: %lu \n", GetLastError());
return RET_ERROR;
}
hRes = LoadResource(NULL, hRsrc);
if (hRes == NULL) {
printf("Cannot load resource, error: %lu \n", GetLastError());
return RET_ERROR;
}
pData = LockResource(hRes);
hFile = CreateFileW(
L"example.bin",
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
printf("Cannot create file, error %lu\n", GetLastError());
return RET_ERROR;
}
BOOL ok = WriteFile(hFile, pData, resSize, &bytesWritten, NULL);
if (!ok) {
printf("Cannot write file, error %lu\n", GetLastError());
CloseHandle(hFile);
return RET_ERROR;
}
CloseHandle(hFile);
return RET_SUCCESS;
}

To compile the above code, the commands below are used. In both languages they have the same roles: the first builds a COFF file from the .rc specification 6 and the second bundles together the .exe that will be produced from the compilation and the calc.ico file.

Terminal window
i686-w64-mingw32-windres load_resource.rc -O coff -o load_resource.res
i686-w64-mingw32-gcc -o load_resource.exe -Os -s -ffunction-sections -fdata-sections -Wl,--gc-sections -fno-ident load_resource.c load_resource.res

Note that since the payload returned by msfvenom is 32-bit, the sample might crash, especially in the second example below, if compiled as a 64-bit application.

The function signatures for each of these calls are all pretty similar and rather straightforward. The first is FindResource:

HRSRC FindResourceA(
[in, optional] HMODULE hModule,
[in] LPCSTR lpName,
[in] LPCSTR lpType
);

The purpose of this function is to determine the location of a resource with a specific name (lpName) and module (hModule). In the example, the hModule is always set to NULL since, per the documentation: “If this parameter is NULL, the function searches the module used to create the current process.” The second parameter is the name of the resource, which is populated with the value “CALCICO”. This value is defined in the .rc file:

CALCICO RCDATA "calc.ico"

which can be read as: “the resource with name CALCICO contains raw data (RCDATA) from the calc.ico file”. The name “CALCICO” is completely arbitrary. RCDATA is also the value of the lpType, which indicates the type of data contained in the resource. The list of possible values is defined in appendix 7, and in this case, since it is raw data, MAKEINTRESOURCE(10) is used.

Note that MAKEINTRESOURCE is a macro defined in the C winuser.h library, which converts an integer, like 10, to a resource type, and 10 means RT_RCDATA. In the Go code, this macro is not defined, so the RT_RCDATA value is used directly 8.

What is returned by FindResourceA is an HRSRC, which is a handle to a resource.

Next, SizeofResource is used:

DWORD SizeofResource(
[in, optional] HMODULE hModule,
[in] HRSRC hResInfo
);

Very simply, the hModule is still NULL for the same reason as above, and the hResInfo handle is the value returned by FindResourceA. The function returns a number.

LoadResource has the same signature as SizeofResource, and it is used to get a second handle, this time to the data themselves. Lastly, to obtain a pointer to the first byte of the resource data, LockResource is used; it takes a single argument, which is the value returned by LoadResource.

LPVOID LockResource(
[in] HGLOBAL hResData
);

Note that LockResource does not actually lock the resource, but only returns the address of the first byte of data.

This address is then used in WriteFile. Since the function requires both an address to the data to write and the size of the data to write, all the needed information is already available to call the function and write the content to a file.

After execution, a new file called example.bin is created in the same directory as the .exe file.