Tuesday, May 12, 2026

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

Labels: ,

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home