Reflective Unloader

This is code that can be used within a PE file to allow it to reflectively reconstruct itself in memory at runtime. The result is a byte for byte copy of the original PE file. This can be combined with Reflective DLL Injection to allow code to reconstruct itself after being loaded through an arbitrary means.

The original PE file will not be modified in memory, this code makes a new copy of the unloaded target module.

Usage

  1. The build environment is Visual Studio 2017.
  2. Add the following files to the project:
    • ReflectivePolymorphism.c
    • ReflectivePolymorphism.h
    • ReflectiveUnloader.c
    • ReflectiveUnloader.h
  3. Once the necessary files have been added, call ReflectiveUnloader() with a handle to the module to unload and reconstruct.
    • For an executable this could be GetModuleHandle(NULL)1
    • For a DLL this could be hinstDLL from DllMain
  4. After compiling the project, run pe_patch.py to patch in the necessary shadow section data to the PE file. Without this step, the writable sections of the PE file will be corrupted in the unloaded copy. (See below for how to automate this.)

Shadow Section

It’s necessary to patch a reflectively unloadable PE file to get a perfect byte-for-byte copy when it is reconstructed. The patching process creates a shadow copy of all writable sections in a new section named .restore. This shadow section is then used when the ReflectiveUnloader function is called to restore the original contents of the writable sections. Reflectively unloadable PE files should be patched once after being compiled.

If the shadow section is not present, the unloader will simply skip this step. This allows the unloader to perform the same task for arbitrary unpatched PE files, however any modifications to segments made at runtime will be present in the unloaded PE file.

The shadow section is composed of a null-terminated list of IMAGE_SECTION_HEADER strcutures. The final, null-termination entry has no name and is sizeof(IMAGE_SECTION_HEADER) null bytes. Each section header’s PointerToRawData field is updated to point to the associated data. Following the list of section headers is the data for each section.

Shadow Section Contents

The following is a diagram illustrating an example layout of the shadow section’s contents which includes a backup of a single section (the .data section).

IMAGE_SECTION_HEADER (Name: .data\x00)
IMAGE_SECTION_HEADER (Name: \x00)
[ .data section contents ]

Visual Studio Build Event

The pe_patch.py script can be executed automatically for every build using a build event. Right click the project in Solution Explorer, then navigate to Configuration Properties > Build Events > Post Build Event and adjust the settings as follows:

Setting Name Setting Value
Command Line python $(SolutionDir)pe_patch.py "$(TargetPath)" "$(TargetPath)"
Description Patch in the .restore section
Use In Build Yes

API Reference

PVOID ReflectiveUnloader(HINSTANCE hInstance, PSIZE_T pdwSize)

Unload the module indicated by hInstance and return a pointer to it’s location in memory. If this function fails, NULL is returned.

Parameters:
  • hInstance (HINSTANCE) – Handle to the module instance to unload from memory.
  • pdwSize (PSIZE_T) – The size of the returned PE image.
Returns:

A pointer to a blob of the unloaded PE image.

Return type:

PVOID

VOID ReflectiveUnloaderFree(PVOID pAddress, SIZE_T dwSize)

Free memory that was previously allocated by ReflectiveUnloader().

Parameters:
  • pAddress (PVOID) – Pointer to the blob returned by ReflectiveUnloader.
  • dwSize (SIZE_T) – Size of the blob returned by ReflectiveUnloader.