Revisiting Stuxnet: Research Notes
Revisiting
Stuxnet: Research Notes
Technical Analysis and Design Insights into the
Loader
“To
understand the immeasurable, the mind must be extraordinarily quiet, still.”
— Jiddu Krishnamurti
Seeker(李标明) ·
@clibm079
China · Independent Malware Analyst &
Researcher
From 2026.03.30 to 2026.05.12
Prologue: Curiosity-driven,
keep moving
I
took a short break and went home for the Sping Festival with family after the last
time I did research about UEFI. In this report I will continue to move back in history;
it’s 15 years ago, a very complicated malware called Stuxnet. According to Wikipedia,
Stuxnet is a malicious computer worm first uncovered on 17 June 2010 and
thought to have been in development since at least 2005. Maybe, as you know,
it’s very complecated components, so my plan is to choose one of them with
limited resources and time and deep dive into the thinking, design, and how it
protects and treats itself as an advanced network weapon.
In
the process of studying and preparing, thanks to all reference stuff, and I mainly
read Symantec’s report and do static and manually debugging and expand my
personal research.
In
this report I try to be focused on the small range on the USB loader ~WTR4141.TMP
and do very limited analysis with curiosity and make a record for it, and the first
thing to note is the follows:
1.
Mainly
do analysis about the loader: ~WTR4141.TMP.
2.
Skip
analyzing ~WTR4141.TMP: How to load the real payload ~WTR4132.TMP and zero-day
vulnerabilities used by ~WTR4132.TMP.
3.
Skip
analyzing the special name pattern KERNEL32.DLL.ASLR.[HEXADECIMAL].
Analysis Tools
#PEbear, #PEsieve, #TinyTracer, #ProcessHacker,
#IDA, and #X32dbg
Stuxnet
~WTR4141.TMP: USB Loader as a userland rootkit
The USB loader: ~WTR4141.TMP
The USB loader ~WTR4141.TMP runs automatically
through triggering the file name “Copy of Shortcut to.lnk” in the USB device,
which is exlointed by the LNK Vulnerability (CVE-2010-2568). And the type of loader
itself is DLL; it was designed deliberately to load the next layer and the real
payload called ~WTR4132.TMP that is rather complicated and powerful.
In this report, I try to understand this loader,
how it hides and protects itself before lateral movement, and also includes the
thinking and design and how this load treats itself as a network weapon.
Figure 1: “Copy of
Shortcut to.lnk” includes strings.
How to load itself
from a removable drive to memory
In order to do precision control of the execution
environment and avoid operation failures like Windows showing a popup, which executes
silently in the background without interrupting the user's work, and to maintain
stealth. The loader is a very deliberate and well-designed pattern
with the API SetErrorMode as part of the
"defensive programming" style of Stuxnet.
It
loads
itself from a removable drive to memory and does the same way to the real
payload ~WTR4132.TMP by reusable design. The APIs are as follows:
From kernel32.dll:
CreateFileW
GetFileSize
VirtualAlloc
ReadFile
Figure 2-1: Loading itself
from a removable drive to memory.
The loader avoids a direct LoadLibraryW
call using a standard path; instead, it uses the specially crafted file name SHELL32.DLL.ASLR.[HEXADECIMAL]
(i.e.,
C:\Windows\SHELL32.DLL.ASLR.3adf9b47) that does not exist on disk, and it is
mapped to a temporary region of memory where the threat previously stored. The techniques
used to avoid security software detection when injecting or loading DLLs into
processes.
Figure 2-2: an
example mapped to a temporary region of memory from base address 0x001D0000.
Stealth File
Hiding: IAT Hooking
In order to hide the files and reduce
attention on the removable drive before the rootkit is installed and the real
payload loaded, it deliberately used skills from the perspective of both human
beings and machines as follows:
1. Social Engineering Evasion Design:
The both ~ prefix and .tmp extension skill. If the API hook fails, the file
appears as ~WTR4141.TMP and ~WTR4132.TMP, which makes such files less likely to
attract user attention. It's a clever little touch in Stuxnet’s social
engineering evasion design.
2. API Chain Hook Both Layers:
Hook both layers, the high-level Windows API layer and the low-level, native
interface to the kernel, which can master full control from the user-mode API
to the real system call and maximum stealth and bypass the high-level
monitoring. It is shown as the following
Figure 2.
kernel32.dll hook API as follows:
FindFirstFileW
FindNextFileW
FindFirstFileExW
ntdll.dll hook API as follows:
NtQueryDirectoryFile
ZwQueryDirectoryFile
Figure 3-1: Hide the
files via API chain hook both layers.
3. IAT Hooking: It hooks the abovementioned functions, which involves redirecting calls
to these functions via import address table (IAT) hooking, and they confirm the
filename, extension, size, and checksum (modulo 10 equals 0) by the specific
design rule; only files that pass this check are filtered.
Figure 3-2: IAT
Hooking Scanning (#PEseive: ~ from hasherezade with love ~).
Figure 3-3: IAT
Hooking Analysis.
APIs obfuscated
for anti-reverse engineering analysis
In order to do anti-reverse engineering
analysis, some key APIs are pre-obfuscated in ~WTR4141.TMP, the even positions
of the pre-obfuscation strings are needed to do deobfuscation via the XOR
algorithm with the magic hexadecimal number “12.”
In
addition, both module names, “kernel32.dll” and “ntdll.dll,” are needed to do
deobfuscation via the XOR algorithm with the magic hexadecimal number “AE12.” The key APIs are as follows:
From Kernel32.dll
lstrcmpiW
VirtualQuery
VirtualProtect
GetProcAddress
MapViewOfFile
UnmapViewOfFile
FlushInstructionCache
LoadLibraryW
FreeLibrary
CreateThread
WaitForSingleObject
GetExitCodeThread
From Ntdll.dll
ZwCreateSection
ZwMapViewOfSection
ZwClose
Figure 4: snippet
code for obfuscation string and do deobfuscation.
Dual Virtual
Address Mappings for Shared Physical Memory
The ZwMapViewOfSection routine is the key
to mapping a shared memory section into a process's address space. The loader uses
two ZwMapViewOfSection routines for creating dual virtual address mappings for
shared physical memory.
When the “rep movsb” wrote to 0x00F00098 (one view), the size is 6478H.The same physical page is also mapped at 0x00100098 (the other view); the data appeared there instantly.
Note: Different instances have different memory addresses.
Figure 5: Creating dual-mapping
Virtual Address Mapping for a process’s address space.
The dual-mapping (two distinct virtual
views of the same physical memory) thinking makes memory operation more
convenient and extremely useful; it is not just efficient to share data
structures between different components of a process without copying but also bypass
user-mode hooks.This design was subsequently reused many times.
When everything is ready, it cleans all
data from the start address 0x00F00000 with the UnMapViewOfFile API.
Figure 6: UnMapViewOfFile the
data in memory.
And then 0x00F00000 operated as as a
temporary region, to check PE structure before the functions hooked. Let’s move
to the next.
What the loader do
before the functions hooked and called
Before the following are functions hooked,
the loader makes rigorous designs.
The first step it does is copy the basic
structure of a PE file header from memory C to memory B and then confirm #1 and
#2 of the structure of the PE, including the following:
1. Confirm
the magic number of the legacy DOS header.
2. Confirm
the signature of the PE header.
Figure 7: Confirm the structure
of PE, including both “MZ” and “PE”.
The second step is to confirm the sections
count of the loader’s File header and copy each section repeatedly by “Raw
size”.
Figure 8: snippet
code for confirming the section “.rdata”.
When confirming the abovementioned, the
Windows API FlushInstructionCache is
used to flush the CPU instruction cache for a given process and then be ready to
load the real payload ~WTR4132.TMP. Obviousely, which implies the designer
understands CPU execution behavior and OS-level memory management very well.
When the above two steps are confirmed, it
moves to do the hook logic via the functions in ntdll.dll as follows:
ZwMapViewOfSection
ZwCreateSection
ZwOpenFile
ZwCloseFile
ZwQueryAttributesFile
ZwQuerySection
The
Functions Hooked Design: The “shellcode A” is designed for
the above the functions hooked. GetProcAddress is used to find the address of a
specific export from the .DLL file loaded and finally redirects execution to
shellcode B.
Figure 9: shellcode A for the functions hooked.
The
Functions Hooked Called: When that above function is
called, it will transfer control to the trusted space of ntdll.dll in memory.
An example for ZwCreateSection hooked as follows:
Figure 10: The process of ZwCreateSection hooked was called.
The Loader’s
Mindset: A Simplified Flow Technical Summary
From the above analysis process, first it
loads the .DLL file “~WTR4141.TMP” from USB to memory A, and then hide
malicious files.
In order to better operate data in memory and
then creates dual virtual address “Temp Memory B” and “Memory C” mappings for
shared physical memory and then reads key data in memory to progressively confirm
the size and PE structure before the functions hooked are used via both
shellcode A and shellcode B, and then transfer control to the space of the trusted
ntdll.dll.
When a new .DLL file “~WTR4132.TMP” loads
normally, finally it will move forward to handle control to the new .DLL file,
but this report doesn’t deep dive into that part.
The following simplified loader mindset
model doesn’t include complete details.
Figure 11: Simplified
loader mindset model.
To delete the
files on the removable drive
In order to protect the loader and the other
weaponized network tools, it destroys them with the design of a “robust delete”
routine and tries 8 times to delete a file reliably, even if something blocks
it and even if DeleteFile fails. Without this logic, deletion may fail due to file
in use, antivirus scanning,race conditions, and so on. Especially, they do
lateral movement between different environments and devices. It's not just
clever but extremely well-engineered and defensive programming.
Figure 12: Snippet
code for deleting the files with the design of “robust delete”.
Observation on my
personal perspective
From the process of analysis, there are
some main thoughts and techniques about the loader used, as follows:
1.
Obfuscation Technique: APIs strings are obfuscated
for anit-analysis and debug.
2.
Shellcode Abilities: Multiple shellcodes design
embedded for different purpose and abilities.
3.
Reusable
Design: Dual-mapping
shows that the designer masters memory operation very well, especially mastery
of mental models and reusable design.
4.
Rigor
Design: Rigorous designs not just for a singe API like SetErrorMode
but also safety awareness and progressive confirming PE structure before the
functions are hooked.
5.
Protection
Themself: The mindset “robust delete” routine tries
8 times to delete a file and hide malicious files via IAT hooking in the
infected, removable drive.
6.
Deep Knowledge: Using FlushInstructionCache
implies a deep understanding of system architecture.
7.
Maturity:
Modular design: vulnerability trigger, USB loader as a userland rootkit, and
the real payload; in addition, about the details: from “delete
a file” in a removable drive to “UnmapViewOfFile” in memory to “FlushInstructionCache”
in the cache of the CPU, it shows that the design is very comprehensive
thinking.
From
the above limited observation and personal view, the first impression is: professionalism,
depth, rigor, maturity, architectural and engineering thinking. And that
mindset was almost 20 years ago. So what's happening nowadays?
As
you know, here it’s just about the loader not including the real payload ~WTR4132.TMP,
but the loader that has the ability to hide files as userland rootkit. Clearly,
at its own execution layer, it employs a defensive and confrontational strategy
to thwart reverse engineering.
Again,
here it’s a very, very, very limited analysis and still incomplete and not
covering all details; the analysis is my observation, not a conclusion. Thanks to
all reference sources, especially Symantec’s report. Given my limited
foundation, it’s hard to imagine the time and effort I would have needed to
expand my research without their research findings, viewpoints, and sharing. For
more technique details, please check them out.
And finally, in the process of analyzing,
I used the tools #PEbear, #PEsieve, #TinyTracer, #ProcessHacker, #IDA, and #X32dbg,
which helped me expand my observing and understanding from different
perspectives. Thank you very much!
References
[1]. https://en.wikipedia.org/wiki/Stuxnet
[2]. https://docs.broadcom.com/doc/security-response-w32-stuxnet-dossier-11-en
[3]. https://web-assets.esetstatic.com/wls/en/papers/white-papers/Stuxnet_Under_the_Microscope.pdf
[4]. https://www.antiy.com/response/stuxnet/Report_on_the_Worm_Stuxnet_Attack.pdf
[5]. https://www.rising.com.cn/about/news/rising/2010-09-27/8239.html
[6]. https://attack.mitre.org/techniques/T0874/
[7]. https://medium.com/@s12deff/import-address-table-hooking-68d519a1da43
[8].
https://www.adlice.com/userland-rootkits-part-1-iat-hooks/
Acknowledgements
To be honest, I collected some stuff, and they told me
that Stuxnet used IAT hooking, but I failed many times. In fact, I have very
limited hooking technique and didn’t even know IAT hooking before, so I had a
terrible idea and wanted to ignore the part in this report, but curiosity drove
me to know more…
Here’s special thanks to #PEseive, which made me deep
dive into the detail of IAT Hooking, and finally I confirmed this observation
via techniques analysis.
In addition, thanks again, Hasherezade; she gave me a tip
on the X platform, “I don't have to convert a DLL to EXE to trace it with
TinyTracer," and TinyTracer helped me grasp the clue of tracing API calls;
if not, maybe I missed something important.
Epilogue:
What This Exploration Taught Me
1.
Such
rigorous programming is rare, demonstrating highly professional systematic
knowledge and engineering capabilities.
2.
High-level samples often demand prolonged focus, yet the greater challenge
is cognitive.
3.
In
this world, there will always be people who do things that require
"long-term focus and cognitive understanding."
4.
For
some samples, I genuinely just need a quick analysis, but for others, especially
those related to the high-level malware samples, I must adopt a researcher's
attitude.
5.
Spending long periods focusing on reverse analysis of high-level malware
samples, listening to light music sometimes helps me relieve stress.
6.
To
be honest, from a purely technical design perspective rather than an attack or
destruction perspective, I really appreciate this way of thinking and mindset;
it conveys another layer of meaning to me: time, patience, calmness, and
restraint.
7.
The
analysis is just the observation, not a conclusion.
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

















0 Comments:
Post a Comment
Subscribe to Post Comments [Atom]
<< Home