Wednesday, January 28, 2026

Revisiting MoonBounce: Research Notes


Revisiting MoonBounce: Research Notes

Technical Analysis and Design Insights into the DXE Core

 

 

“To understand the immeasurable, the mind must be extraordinarily quiet, still.”
— Jiddu Krishnamurti

 

 

Seeker(李标明) · @clibm079    

China · Independent Malware Analyst & Researcher 

From 2026.01.17 to 2026.01.28


Prologue: Ever climbing, more deeper

Last time, I shared the report “Revisiting LoJax Supplementary Analysis and Research Notes,” and here, to go further on a personal firmware study, I move to the next APT group’s sample, like MoonBounce, which Kaspersky’s global research team documents as the 'MoonBounce' UEFI firmware implant and its connection to APT41 (also known as Winnti). When I started to analyze, I suddenly was aware that I had very limited knowledge and experience to do that, so like before making research notes, the first thing I need to do is to embrace “slow down” and build a minimal mental model for that as follows:

1.      to read "UEFI Platform Initialization Specification."

2.      to read others’ reports about ‘MoonBounce.’

 

In the process of studying and preparing, I created a basic mental model for understanding what it is, which helped me build solid confidence and a foundation to dive deep into Kaspersky’s research and expand my personal research to do more.

 

But here, I just try to be focused on doing CORE_DXE image research and doing very limited analysis and making a record for it.

 

 

An interesting thing is that as I immerse myself in security research, my desire for material things has diminished. Very little is needed now to make me feel satisfied. :-)

 

 

CORE_DXE

MD5: d94962550b90ddb3f80f62bd96bd9858
SHA1: 6bfb3634f6b6c5a114121fe53279331ff821ee1e

 

 

MoonBounce vs. the DXE Core

The DXE Core, also referred to as the DXE Foundation, is the executive component that initiates the DXE phase. It is located and loaded by the PEI phase, and its execution marks the end of PEI and the beginning of DXE. All subsequent DXE components depend on the DXE Core.

 

The DXE Core provides boot services and initializes runtime services, and it contains the DXE Dispatcher, which is responsible for discovering, loading, and dispatching DXE drivers from firmware volumes based on dependency expressions (DEPEX). DXE drivers are independent firmware modules that execute under the services and infrastructure provided by the DXE Core.

 

CORE_DXE is the heart of the DXE phase; conceptually, it can be viewed as the “operating system” of the firmware environment.

Figure 1: MoonBounce Inline Hooking Method (PEI → DXE).

 

MoonBounce directly patches the DXE Core’s executable code, installs inline hooks at critical internal execution points, and runs its own shellcode inside the DXE Core’s control flow, and for this observation, let’s move to the next.

 

 

 

Inline Hooking Method Analysis

 

Inline Hooking Method

MoonBounce uses an inline hooking mechanism, the hooked functions in the underlying EFI_BOOT_SERVICES table, namely AllocatePool, CreateEventEx, and ExitBootServices. EFI_BOOT_SERVICES contains a table header and pointers to all of the boot services, so just check them out one by one according to related definitions as follows:

Figure 2: Inline hooking of AllocatePool, CreateEventEx, and ExitBootServices.

 

 

Tracing Boot Services Inline Hooks to a Central Dispatcher

In this report, I do the thinking perspective and design, not repeating technique details. When diving deep into the functions such as AllocatePool, CreateEventEx, and ExitBootServices, and discovered that they all point to the same instruction, “call sub_180157700,” so let’s move to the inline hooking function sub_180157700 with curiosity.

 

According to binarly.io’s report “A deeper UEFI dive into MoonBounce,” recently I searched on Google for the string constant "E7846IMS.M30" to download the image, but it did not work. Proving a DXE Core inline hooking requires locating and comparing a clean vendor CORE_DXE image, which seems impossible; without that reference, I had to use the original allocatePool of Kaspersky’s report on the left as the source.

 

Yes, picking one of the aforementioned methods, like AllocatePool, the first 5 bytes, "48 89 5C 24 08," are replaced with a call instruction. It really indicates an inline hooking rather than a boot services table replacement. Of course, the 5 bytes modified restore the original prologue bytes of the AllocatePool instruction carefully, instruction by instruction.

Figure 3: an inline hook installed at the beginning of the AllocatePool boot services and restored.

 

 

Continued to dive deep into the inline hooking function “sub_180157700,” and we can see that it triggers different logic branches by deliberating design and comparing instruction bytes to identify AllocatePool, CreateEventEx, and ExitBootServices, and it hooked and also behaved like a dispatcher, which really performs advanced opcode-level instruction operation.

Figure 4: example of dispatcher behavior by instruction indentify.

 

 

AllocatePool Hook and Shellcode Deployment

Preparation phase: The code first restores the original AllocatePool implementation to ensure normal execution, then copies the driver-mapping shellcode into the allocated buffer, preparing it for future execution.

Figure 5: code snippet for AllocatePool’s hook logic.

 

 

CreateEventEx Hook Usage for Legacy Boot Control Transfer

This code restores CreateEventEx and uses it to register a callback for gEfiEventLegacyBootGuid, ensuring reliable transfer of execution to the shellcode previously staged via the AllocatePool hook when the system enters the legacy boot path and firmware signals the event.

 

MoonBounce leverages gEfiEventLegacyBootGuid as an execution trigger, rendering this attack path conditional on CSM availability; on pure‑UEFI systems the event is never signaled and the callback does not execute unless alternative triggers are present.

Figure 6: code snippet for CreateEventEx’s hook logic.

 

But MoonBounce is not “CSM‑dependent”; it is a very mature firmware‑malware design. Let's move to the next path via ExitBootServices‑based interception.

 

 

Inline Hook Installation at the ExitBootServices Boundary

The code scans the OS loader (winload.efi) in memory using a distinctive instruction pattern (signature-based scanning, e.g., 0xCB485541, corresponding to push r13 ; retfq), copies an embedded shellcode (sub_18015787E) into low, persistently accessible memory, and installs an inline hook on OslArchTransferToKernel during ExitBootServices, hijacking execution at the exact firmware-to-kernel transition point.

Figure 7: code snippet for ExitBootServices’ hook logic.

 

 

Kernel-Resident Shellcode Deployment and ExAllocatePool Hooking

Diving deep into the shellcode (sub_18015787E), The code locates the in‑memory image base of ntoskrnl.exe, resolves critical kernel APIs via a name‑hashing algorithm, modifies kernel section permissions, deploys a 0xCC‑byte kernel‑resident shellcode, and installs an inline hook on ExAllocatePool, enabling stealthy kernel‑mode execution at the firmware‑to‑kernel transition.

Figure 8: Code that set up a hook in the ExAllocatePool function within ntoskrnl.exe.

 

ExAllocatePool Hook Shellcode Analysis

Diving deep into the loc_18015791C, an embedded machine code was found when doing “convert to instruction” with loc_18015791C, not a real “DWORD variable.” The executive context, flow code, and control logic indicate an embedded shellcode rather than a normal data structure.

Figure 9: indicating an embedded shellcode rather than a normal data structure.

 

Kernel Shellcode Activation via ExAllocatePool

The ExAllocatePool hook activates kernel-resident shellcode that was staged earlier during the preparation phase, marking the transition from payload setup to active execution.

Figure 10: jmp to the early shellcode during the AllocatePool hook.

 

 

 

A Boot-Path-Adaptive UEFI Firmware Implant

From the above analysis, MoonBounce leverages precise inline hooking and minimal shellcode to reliably position execution during the DXE phase and seize control at the firmware-to-kernel transition, supporting both legacy (CSM) and pure UEFI boot paths.

Figure 11: boot-path-adaptive for both legacy (CSM) and pure UEFI boot paths.

 

 

 

 

Observation on my personal perspective

From my perspective, MoonBounce can be described as “patching the firmware execution core,” as it directly modifies the DXE Core’s executable code and embeds its logic into the core execution path. By doing so, it functions as an inline hook that executes before—and beneath—all DXE drivers, rather than existing as a separate driver or module.

 

This represents a highly advanced and powerful boot-path-adaptive UEFI implant that supports both legacy (CSM) and pure UEFI boot paths, demonstrating a deep and precise understanding of the DXE internal execution flow, timing, and trust boundaries of the UEFI boot process.

 

I would like to thank Kaspersky for their in-depth MoonBounce analysis and Binarly for their related contributions. Their shared research, built through long-term expert effort, made further study and understanding possible. And here’s comments  are interesting between them.

 

In these research notes, I just do very limited research based on Kaspersky's report; for more technique details, please check it out.

 

Finally, it tells me, “Stay hungry—not for more, but for deeper.”

 

 

 

 

References

[1]. UEFI MemoryForensics: A Framework for UEFI Threat Analysi https://arxiv.org/pdf/2501.16962
[2]. MoonBounce: the dark side of UEFI firmware: https://securelist.com/moonbounce-the-dark-side-of-uefi-firmware/105468/
[3]. Technical details of MoonBounce’s implementation:
 https://media.Kasperskycontenthub.com/wp-content/uploads/sites/43/2022/01/19115831/MoonBounce_technical-details_eng.pdf

[4]. A deeper UEFI dive into MoonBounce: https://www.binarly.io/blog/a-deeper-uefi-dive-into-moonbounce
[5]. EFI System Table: https://uefi.org/specs/UEFI/2.10/04_EFI_System_Table.html#id4

[6]. A deeper UEFI dive into MoonBounce: https://www.binarly.io/blog/a-deeper-uefi-dive-into-moonbounce

 

 

 

 

Epilogue: What This Exploration Taught Me

1.      In firmware analysis, the opcode is the API.

2.      If you are doing real research, the system rewards you late.

3.      Malware analyst mental model: Malware analysis relies on different trusted abstractions at each layer: user mode trusts APIs and semantics, kernel mode trusts data structures and control flow, and firmware ultimately trusts raw instruction execution.

4.      I choose to approach research with deliberate patience. I call this my discipline.

Annotation: In all the sentences I wrote and used the word “you or your or yourself” in, it talked to me or “the malware sample itself, especially in my poem I did”, not the reader. I must clarify my motivation.



End of Report

──────────────────────

Seeker(李标明) · @clibm079    

China · Independent Malware Analyst & Researcher

Labels: , ,

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home