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: #CSM, #MoonBounce, #UEFI














