Windows Hotpatching & Process Injection

March 6, 2023

By: Christopher Vella

Windows Hotpatching & Process Injection | Signal Labs | Advanced Offensive Cybersecurity Training | Self-Paced Trainings | Live Trainings | Virtual Trainings | Custom Private Trainings for Business

Summary

I spent a day reversing syscalls and Kernel entry points to find new ways I could share memory or inject code between threads & processes, during which I decided to dive into Hotpatching on Windows and write a PoC which turned out to be a great exercise in working with the PE format.

Below I talk through Hotpatching, resulting in a PoC & PE32/32+ helper code.

What is hotpatching?

Hotpatching is a method supported throughout Windows for modifying running PE32/32+ objects in memory, including Kernel drivers & processes (even those in the Secure Kernel), usually to permit patching or updating code without requiring restarts. This is documented in a few places, including the PE32/32+ format (see an overview from Microsoft here: https://techcommunity.microsoft.com/t5/windows-os-platform-blog/hotpatching-on-windows/ba-p/2959541).

Enabling Hotpatch Support

Hotpatching is not enabled by default in all versions of the OS, its currently supported in Insider builds and in Azure edition of server builds (Azure editions are downloadable as ISOs or deployable in Azure directly, more information here: https://learn.microsoft.com/en-us/azure/automanage/automanage-hotpatch and here: https://learn.microsoft.com/en-us/windows-server/get-started/enable-hotpatch-azure-edition.

If you’re working with the raw ISO or an Insider build, you may need to set registry keys to turn on Hotpatching (as per the links above). Insider builds only require the registry keys to be set, which are included in the PoC at the end.

Hotpatching also relies on the presence of the Secure Kernel, though you can leverage Hotpatching without the Secure Kernel if you set an additional registry key.

All the information about Hotpatching can be gleamed from public documentation, including PE information here: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/SystemServices/struct.IMAGE_HOT_PATCH_INFO.html, here: https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_load_config_directory64 & through reversing of the NtManageHotPatch syscall in ntdll.dll and ntoskrnl.exe.

Pseudo Overview of the Hotpatching Process

In addition to the documentation above, below is my own general walkthrough of the Hotpatching process based on my PoC development.

Patches are created via the NtManageHotPatch syscall, this syscall takes multiple parameters which determine the operation to call. When we call it to create a patch it will expect to load a PE32/32+ file describing the patch.

These Hotpatch PE32/32+ files are like regular PE32/32+ executable images however they include Hotpatch entries (Including the IMAGE_HOT_PATCH_INFO struct here: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/SystemServices/struct.IMAGE_HOT_PATCH_INFO.html, the IMAGE_HOT_PATCH_BASE here: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/SystemServices/struct.IMAGE_HOT_PATCH_BASE.html & other IMAGE_HOT_PATCH_* structures.

The Hotpatch entries start with the IMAGE_HOT_PATCH_INFO struct which is stored in a section in the PE32/32+ file, pointed to by the HotPatchTableOffset field in the IMAGE_LOAD_CONFIG_DIRECTORY64 DataDirectory entry in the OptionalHeader of the PE32/32+ file.

The PE file is mapped into a system section by the Kernel, which parses the file to determine the offsets of the Hotpatch structures in the file, it then creates a Hotpatch entry in a list.

The Hotpatch will be valid for images of a certain checksum and timedatestamp, which will apply to any image with the corresponding checksum in its OptionalHeader, and its timedatestamp from its IMAGE_FILE_HEADER. This is how a Hotpatch file tells the system which image the Hotpatch is valid for, e.g. if we wanted to patch kernelbase.dll, we’d read the checksum and timedatestamp from kernelbase.dll and set the OriginalCheckSum and OriginalTimeDateStamp fields of our IMAGE_HOT_PATCH_BASE struct to those values.

Additionally, if the patch PE contains the exported function __PatchMainCallout__, it will be automatically invoked after the patch is loaded in a process.

Once the patch is loaded into the Kernel, depending on the type of patch it may automatically be applied to all running processes as the Kernel enumerates processes and calls a notification callback in ntdll.dll to handle checking for patches.

Limitations & Notes

While Hotpatching is a powerful feature, permitting code changes to multiple parts of the system, there are two main limitations (for non-Microsoft users)

  1. Administrator privileges is generally required to enable Hotpatching
  2. To globally apply a Hotpatched PE, the PE is required to be at least Microsoft signed or higher (preventing common injection of unsigned DLLs)

For 2. above, the PE does not need to be signed to be loaded into the Kernel list of Hotpatches, and you can still map the Hotpatch into your process by utilizing NtManageHotPatch, which provides a way to map the section handle of your Hotpatch regardless of its signature.

There are other behaviors of Hotpatching not mentioned here, such as targeting process by user SID, or the fact that processes may continually attempt to load your Hotpatch regardless of validity (which can cause processes to stop launching, or even act as a targeted DoS against certain processes).

Additionally if you target kernelbase the Hotpatched PE can be loaded outside of the typical notification callback, such as in LdrpInitializeKernel32Functions instead, which has its own interesting properties not discussed here.

I could also foresee uses of this by EDRs to supply ntdll & kernelbase patches, instead of their current approach of injecting + hooking.

Code Samples

Code samples (not complete) for Hotpatching (+ partial helper code for working with PE32 files) are included here: https://github.com/Signal-Labs/Hotpatching_PoC, the Hotpatch loader will take the compiled hotpatch_replace_vs file (which is expected to already have a LoadConfig table, which is possible if you compile with /GS for example) and create a new file that’s a clone with a Hotpatch entry (a partially valid entry, just enough to get it loaded as a Hotpatch record in the Kernel). It also includes support for enabling Hotpatching if you run as Admin.

Brand Icon Seperator | Signal Labs | Advanced Offensive Cybersecurity Training | Self-Paced Trainings | Live Trainings | Virtual Trainings | Custom Private Trainings for Business

Empowering Cyber Defense with Advanced Offensive Security Capabilities

Signal Labs provides self-paced and live training solutions, empowering our learners to acquire the latest cutting-edge skills in this rapidly evolving field. Improve your vulnerability research campaigns and adversary simulation capabilities with the latest in offensive research and techniques.

Stay Connected

We'll let you know when our next live training is scheduled.

Stay Connected

We'll let you know when our next live training is scheduled.

Stay Connected

We'll let you know when our next live training is scheduled.

Stay Connected

We'll let you know when our next live training is scheduled.