How to read embedded data from a resource
In the previous article, I showed you how to embed data into a custom resource in your executable.
In this article, I’m going to show you how to extract the same data using the Win32 API for use in your executable at runtime.
To extract data from a resource in an executable we need some information:
- Executable name.
- Custom resource type name.
- Custom resource name.
In our previous example, the executable name was mvJavaDetective.dll, the custom resource type name was “CLASSFILE” and the custom resource name was “myJavaSpy”.
The API
FindResource
HRSRC FindResource(HMODULE hModule, LPCTSTR lpName, LPCTSTR lpType);
Call FindResource() to find a resource in an executable and return a resource handle. The executable is specified using a module handle that represents a module loaded in the current program. If the module is not currently loaded you can load it with LoadLibrary(). The resource is identified by its custom resource name and custom resource type.
LoadResource
HGLOBAL LoadResource(HMODULE hModule, HRSRC hResInfo);
Call LoadResource() to load the resource specified by the module handle and the resource handle. The returned handle should not be passed to any Global memory function for deallocation.
LockResource
LPVOID LockResource(HGLOBAL hResData);
Call LockResource() to lock the resource in memory. Pass the handle returned by LoadResource() as the input parameter. If the call succeeds a pointer to the data represented by the handle is returned.
SizeofResource
DWORD SizeofResource(HMODULE hModule, HRSRC hResInfo);
Call SizeofResource() to determine the size of a resource. Pass the module handle and the handle returned from FindResource() as input parameters.
Putting it together
In the previous example our example DLL myJavaDetective.dll had a class myJavaSpy.class embedded into a resource with the type “CLASSFILE” and name “myJavaSpy”. I will now show you how to extract the myJavaSpy.class byte codes from the resource.
First we need to get the module handle of the executable (myJavaDetective.dll) containing the myJavaSpy.class. For this example we will assume that myJavaDetective.dll is already loaded into memory.
HMODULE hModJavaDetective; hModJavaDetective = GetModuleHandle("myJavaDetective.dll");
Once we have the module handle we can attempt to find the resource in the executable. We don’t need to check for a NULL module handle as FindResource() handles and will return a NULL resource handle (just as it will if the resource is not embedded in the executable).
jbyte *classBytes = NULL; DWORD classBytesLength = 0; HRSRC hResource; hResource = FindResource(hModJavaDetective, _T("myJavaSpy"), _T("CLASSFILE")); if (hResource != NULL) {
If FindResource() returns a non NULL handle the resource has been found. Now we must load the resource using a LoadResource().
HGLOBAL hResourceMemory; hResourceMemory = LoadResource(hModInjectedJVMTI, hResource); if (hResourceMemory != NULL) {
If LoadResource() returns a non NULL handle the resource has been correctly loaded from the executable. This returns a handle of type HGLOBAL. Caution you must not pass this handle to any HGLOBAL related functions such as GlobalFree() or GlobalRealloc() as this handle does not represent a memory allocation. This type is used for backward compatibility with earlier versions of the Windows API.
Before we can use the data we must convert the returned handle into a pointer to the data by calling LockResource(). We also want to know the size of the data in the resource so we call SizeofResource() to determine the size. The pointer returned by LockResource() must not be passed to any memory deallocation functions – it does not need to be deallocated or unlocked.
void *ptr; DWORD size; ptr = LockResource(hResourceMemory); size = SizeofResource(hModInjectedJVMTI, hResource); if (ptr != NULL) {
If LockResource() returns a non NULL pointer the pointer represents the data embedded in the executable.
Now we have the data we make a copy for our own use and continue as normal. This step is optional, you can use the data directly from the returned pointer if you wish.
classBytes = new jbyte [size]; if (classBytes != NULL) { memcpy(classBytes, ptr, size); classBytesLength = size; } } } // CAUTION! LoadResource() and LockResource() DO NOT allocate handles or locks, // read the documentation }
Now that we have extracted the data from the resource embedded into the executable we can use the data as normal. For this example I will conclude by using the extracted Java class bytescodes to define a Java class in a Java Virtual Machine.
if (classBytes != NULL) { // define our class, must have same name as class file bytes // pass NULL for the class loader - use default class loader jclass klass = 0; klass = jniEnv->DefineClass(SVL_COVERAGE_CLASS, NULL, classBytes, classBytesLength); if (klass != 0) { // class defined correctly } // tidy up delete [] classBytes; }
Wrap up
Now you know how to embed data in an executable at runtime (and after the fact with the utility presented in the previous article) and how to extract data from an executable at runtime. The techniques are quite straightforward to master and allow you to easily embed data for you to use at runtime without worrying about distributing and locating extra data files.