Analysis of Equation Group’s nls_933w.dll: Revealing Core Tactics and Technical Mindset

 

 

Analysis of Equation Group’s nls_933w.dll Revealing Core Tactics and Technical Mindset

Though over a decade old, nls_933w.dll reflects not just complicated technical mastery but firmware resource related and still very big challenges for analysts today

 

 

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

 

By Seeker(李标明) China

Independent Malware Analyst & Researcher

2025.6 – 2025.8

 Download the Full Report (PDF)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Summary
This report documents my firsthand experience, observations, and technical findings in order to capture the underlying mindset and intent behind the firmware research. It combines narrative context with in-depth malware analysis, organized as follows:

  1. Prologue
  2. Sample Choice
  3. First Impression
  4. What is nls_933w.dll
  5. Technical Analysis
  6. The Core Anti-Analysis Policies for Malware
  7. Limitations & Unresolved Questions
  8. Conclusion
  9. References
  10. Epilogue

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Prologue: The Temple and the Kernel and the E-book

Recently, I published my new e-book called “The Path of Clarity”. To be honest, I had no plan for that. I’m happy for the decision, and the process also encouraged me to go forward.

 

On my e-book I wrote down and shared my feeling: “To truly understand an adversary, you must rise to — or beyond — their depth. Because only depth reveals intent.”, which is the key when I deeper dive into nation-state-level malware research. And something to research malware without any fear, but to understand deeply what they are.

 

I’m very special thanks to Jiddu Krishnamurti; he is a great figure. I did research on how he saw the world with spiritual vision and insight more than 12 years ago. One of the important things is to observe the world with one's own eyes, not from a conclusion. I learned a lot from him and beyond my pass with understanding and the real action, not only malware research. Thanks again, no other words.

 

I did not go to the temple frequently; it seems that my brain has already adapted to the kernel knowledge and mindset.

 

At the same time, I continue to learn more about the malware of history, and I start to notice low-level threats based on firmware, but without any knowledge for that. Strongly driven by curiosity, I take weeks to learn about “Persistence Storage” and build the basic mindset. After that, I tried to look for malware related to the firmware sample to do analysis. That’s why I come back again and beyond limited knowledge. and it is an important and a good sample that makes me learn more and satisfies my strong curiosity.

 

 

 

 

 

 

 

 

 

 

 

 

 

Sample choice: nls_933w.dll

First of all, many thanks to Kaspersky for sharing the IOC about the malware sample from its report and their contribution, which gave me the chance to study more and do research. And also, including the IOC about Turla’s Uroboros, I did analysis before. I appreciated it.

Yeah, I tracked back to the history and learned from media that in 2015, the NSA-linked equation group developed an HDD reprogramming module. This is a very deep persistence mechanism and extremely difficult to detect.

And I looked for some stuff about the event and malware’s report, but without the detail of nls_933w.dll, I was very curious about what happened inside, so here I go.

nls_933w.dll 
md5: 11fb08b9126cdb4668b3f5135cf7a6c5

WIN32M.sys
md5: 2b444ac5209a8b4140dd6b747a996653

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

First impression: sophisticated and shocking

To be honest, this is my first time touching such a shocking thing; it is very sophisticated, not only about software malware but also related to hardware. I realize nls_933w.dll should be a rare and good sample to do research on, but there is a very limited analysis report online, so I have to start from scratch and learn “Persistence Storage” first, as I did before, and it’s a pity I have a limited source without the compromised firmware, but it did not stop me from going forward.

 

What is nls_933w.dll?

nls_933w.dll is an advanced malware that can issue custom IOCTLs requests to the embedded driver WIN32.sys, which embedded a binary drive-level malware that used to interact with the hard drive from the kernel level and can send custom ATA commands to compromised firmware on the victim machine. It does persist very deeply and makes it hard to detect.

Figure 1: Embedded a binary driver-level malware.

 

 

It embedded a binary drive-level malware named WIN32M that can be dumped manually from nls_933w.dll, which is a classic situation in malware where a dropped driver is embedded as a binary blob (short for binary large object) as follows.

Figure 2: Dump an embedded binary driver malware.

 

The embedded driver name called WIN32M in the nls_933w.dll can be decoded by the Custom XOR algorithm; the constant name is unk_1002F1B4 for user-mode evasion. And the suffix “.sys” also did like that, but it will be decoded on other sub-branches of logic like sub_10003470.

Figure 3: the process of decoding unk_1002F1B4.

 

Technical Analysis

About the version of WIN32M.sys

After I installed WIN32M.sys manually and analyzed it with IOCTLs like 0x870021C0 (custom IOCTLs). Diving deeper into the logic to debug and finally get the result “3.0.0.0”, this strongly indicates that the driver returned a version string; the IOCTLs like 0x870021C0 are version query commands.

 

Figure 4: return the version by sending custom IOCTLs like 0x870021C0.

 

 

Possible supporting multiple drive categories

Combining static and automatic analysis, it seems that nls_933w.dll shows it supporting multiple drive “classes” for vendors; they are strings about “SAMSUNG, ST, Maxtor STM, Maxtor, and WDC WD,” which can be decoded by the custom XOR algorithm too. But here I have limited resources to confirm them.

 

Figure 5: supporting multiple drives in plugin version 3

 

 

The process of understanding how to interact with the kernel
nls_933w.dll embedded a driver, which seems to have been designed to drop to a certain directory of the system. But the logic doesn’t work well on Windows XP or Windows 7. To be honest, at the beginning, I was not sure about this; it seemed that I missed something.

It uses GetSystemDirectoryA to get the correct directory “c:\windows\system32” but concatenates the invalid strings. Both the constant “Source” and the “Str” design from the .data segment don’t even plan to decode. But at the beginning, I couldn't even understand it completely.

Figure 6: invalid path from concatenating the constant “Source” and the “Str”.

 

It designs a serial function like FindResourceA, LoadResource, and CreateFileA to write the embedded driver to an existing path. Because the invalid path is passed as an address parameter to the function CreateFileA, the address is “0012F410,” including the invalid value “0012F52C” and the logic design doesn’t work well. it will explain more detail on the part of “The core anti-analysis policies for malware”.

 

Figure 7: Design an invalid path passed as an address parameter.

 

 

 

Custom XOR Algorithm Obfuscated NtDll.dll

The strings “NtDll.dll” are deobfuscated by the Custom XOR algorithm. And then it uses LoadLibraryA to load it.

Figure 8: automatically deobfuscated the ntdll.dll and loaded it.

 

 

The API NtLoadDriver for loading WIN32M.sys

The API “NtLoadDriver” also was designed stealthily to load the embedded driver and prevents static detection of strings, bypassing SC and SCM detection.

The API NtLoadDriver loads a driver by the value of the registry that is the key "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\WIN32M" mapped to C:\Windows\System32\drivers\WIN32M.sys, and then the embedded driver is loaded into kernel memory and executed. But here the path is invalid and can't work.

Figure 9: the NtLoadDriver for loading the embedded WIN32M.sys.

 

 

 

 

 

 


I continue to debug nls_933w.dll without enough knowledge about the flowchart of “DeviceIoControl” that interacts with the kernel. Because of dropping failures, I have to frequently change the status of “EFLAGS” to observe what’s happening. I reserve and share the process of analysis and learning here. To be honest, it looks a bit blind, and it failed, but it is my real analysis process.


 

Without installing WIN32M.sys to understand DeviceIoControl

When I did static analysis I noted “DeviceIoControl” as an import function, it is a Windows API used by user-mode applications to send I/O control codes (IOCTLs) to kernel-mode drivers or devices. Malware often abuses DeviceIoControl to use custom or undocumented IOCTLs to control malicious drivers.

nls_933w.dll supports custom IOCTLs such as 0x870021C0, 0x870021C4, 0x870021C8, 0x870021CC, 0x870021D0 and 0x870021D4.

Taking 0x870021D0 as an example, stepping into the function sub_10007090 and finding the strings “WDC WD” which is the drive “class” for the vendor, it shows after “call sub_1000A6B0” executes.

Figure 10: Supporting drive class “WDC WD”.

 

To continue to take a deep dive into sub_1000A1D0, and then observe the “call sub_1000A140” and find the special device object “\\.\Global\WIN32M”, the sensitive strings were decoded by the same as “Custom XOR Algorithm”.

Figure 11: user-mode symbolic link that refers to a kernel-mode device object.

 

The function CreateFileW is not to create a new device object but to open a handle to an already existing device; the call finally failed, but it can help me to learn more about what’s happened.

Figure 12: Open a handle to a device object.

 

From the above, I understood a certain driver isn’t present, and EAX is an invalid device handle value. It seems that I need to install an embedded driver.

Figure 13: sending custom IOCTLs code like “870021D0”

 

 


From the many times it failed to interact with the kernel, the process of analysis became clear. I copied the driver WIN32M.sys to the driver directory “c:\windows\system32\drivers” and installed WIN32M.sys manually and tried enough times to keep moving. I have to save large numbers of virtual machine snapshots.


 

 

 

Installed the driver WIN32M.sys and analysis
I installed WIN32M.sys manually and debugged it again in kernel mode and found implemented IRP_MJ_CODE, such as CREATE (00), CLOSE (02), READ (03), WRITE (04), DEVICE_CONTROL (0E), and CLEANUP (12).

They are all dispatched to the same function at f79f258c, which is the custom central dispatch routine that internally switches based on the IRP major function. And many entries are "nt!IopInvalidDeviceRequest" is the default handler used by the OS, but the driver does not implement a dispatch routine for a given IRP major code.

Figure 14: implemented many IRP_MJ_CODE.

 

To continue to dive deep into the custom central dispatch routine with “uf f79f258c” and find custom IOCTLs like “870021D0” and jump to its branch and handle the request with “IofCompleteRequest”.

Figure 15: dispatch routine for custom IOCTLs.

 

 


I’m eager to try my best to dive deep into different logic branches to learn what’s happened, but to be honest, I moved it very slowly. Sometimes I confirmed it on Windows XP and sometimes did it on Windows 7 to check them again and again. And they all failed to send custom IOCTLs through “DeviceIoControl”.


 

To debug the custom “0x870021CC” IOCTLs from the central dispatch routine. It successfully executes “deviceIoControl”. the output buffer as follows:

 

Figure 16: Custom IOCTLs like 870021CC request.


0x0012F048 = F0 01 00 00 → 0x1F0

0x0012F04C = F6 03 00 00 → 0x3F6

0x0012F0AC = 70 01 00 00 → 0x170

0x0012F0B0 = 76 03 00 00 → 0x376

This maps to ATA primary and secondary ports, which refer to the two traditional I/O interfaces used to connect PATA (Parallel ATA) devices.ATA is an older standard for connecting storage devices.

 

 

 

 

 

 

 

 

 

Important milestones finding


The above process is helping me be ready for knowledge about structure. ATA_PASS_THROUGH_EX.

A big change happened: after more than sixty days of analysis and debug practice, I started to understand I need to create a simple wrapper DLL to load nls_933w.dll. it will explain more detail on the part of “The core anti-analysis policies for malware”.


multiple times trying to observe the custom IOCTLs like “0x870021D0” and successfully executes “deviceIoControl”. It sends the standard IDENTIFY DEVICE ATA command 0xEC multiple times, and finally the output buffer returns information about an ATA device which includes things like the serial number and module number as follows:

Figure 17: standard IDENTIFY DEVICE ATA command 0xEC.

 

Figure 18: device information from the output buffer.

 

When setting a breakpoint with “bp f7a0a58c” (Figure 14) and sending custom IOCTLs like “870021D0” in user mode, it will touch the breakpoint. Which indicates DeviceIoControl interacts with the driver WIN32M.sys in kernel mode. And WIN32M.sys was designed to handle IRP. And the ATA IDENTIFY DEVICE storage-specific IOCTLs, which strongly indicate interaction with physical disk devices.

Figure 19: touching breakpoint on windbg.

 

As mentioned above, it sends the custom IOCTLs like “0x870021D0” and successfully executes “deviceIoControl”, which returns the strings like module numbers, and it looks like the original scrambled string "MVawerV riutlaI EDH ra drDvi e" changed to "VMware Virtual IDE Hard Drive" by byte-swapping (neighbor-swapping) with even positions to odd positions in memory.

Why does it look "scrambled"? because PC memory is little-endian, but ATA devices store ASCII strings in big-endian word order. It's not intended as obfuscation; it's just a hardware communication convention that persisted.

It further indicates that malware does really have the ability to send ATA commands. Obviously, it is very advanced malware. Here is new knowledge. When reversing firmware or ATA data like IDENTIFY DEVICE responses, incorrect endianness interpretation will scramble strings and values.

Figure 20:  not an obfuscation algorithm but a communication convention.

 

To go forward and notice that it uses the function sub_10027190 to compare one of the vendor likes, “WDC WD” with the module name “VMware Virtual IDE Hard Drive”, which indicates that it uses DeviceIoControl to send the standard IDENTIFY DEVICE ATA command 0xEC to get the module name of the target device and detect the environments and decide to alter its behavior. If it does not match, it will exit. This also gives high confidence that it has the ability to send ATA commands to special firmware vendors, like the one shown in Figure 5 above, but strictly speaking can’t confirm them without devices.

Figure 21: detecting the firmware environment to see if it does match.

 

It’s a great pity that I can’t do further research without the firmware of compromised machines; it is said to be the most complicated part, and I don't think I'll have the chance to analyze such a device. So I have to stop here.

 

 

 

The core anti-analysis policies for malware

 

1.    The hidden functionality name for anti-analysis policy


nls_933w.dll does not support named exports like the address “100013F4”, and most DLL loaders only support named exports, not ordinals directly. It can’t be loaded and executed with the default loader of the system, like “DLLLoader32_*.exe”.

In order to run normally, analysts have to create a simple wrapper DLL that exports a named stub that calls the ordinal function with parameter 1.

The policy aims to protect malware itself and makes more challenges for analysts. Because the first thing analysts need to be aware of is this anti-analysis technique or policy, and they need to have the ability to do static analysis and also have good skills for debugging.

This strongly implies the DLL “nls_933w.dll” is meant to be stealthy—likely not designed for public use, but rather for internal loader logic or malware frameworks. But I hadn’t found that loader.

Figure 22: the hidden functionality without name export.

 

 

2.    The policy of the Custom XOR algorithm: clever thinking and design for evasion and anti-static analysis; the fine-grained algorithm is full of advanced skill

 

Taking the drive category like “WDC WD” shown in the function sub_10007550 executed as an example.

Figure 23: “WDC WD” show after sub_10007550 execute

 

 

Deep dive into the function sub_10007550 and its sub-branch; it calls the same function, sub_1000A6B0, and finally executes the deobfuscation function sub_10005850, which is designed by the Custom XOR Algorithm.

Figure 24: Custom XOR Algorithm for the Name Drive Categories.

 

The thinking of design is to set the constant value obfuscated from the .data segment and then use the Custom XOR Algorithm to deobfuscate. One of the constant values is used for controlling the loop and setting the initial value; the other of the drive category constant values is obfuscated and needs to be deobfuscated.

Figure 25controlling flag for loop and obfuscation constant for “WDC WD”.

 

 

How to think and design for deobfuscation?

The controlling constant value “7E000701h” is in hex format in the .data segment.

1.     “7E” as the initial value, and the character is “~”.

2.     “07” as the length of the loop.

3.     “01” as the start of the loop.

And both “4B658A5h” and “95EC7Eh” need to do deobfuscation with the Custom XOR Algorithm.

 

Figure 26: the thinking of design for the Custom XOR Algorithm.

 

 

The important thing is malware itself using a custom XOR algorithm to hide their sensitive information for anti-static analysis in many places.

 

 

3.    Decoy-style for anti-analysis technique: Supplying intentionally malformed parameters to legit API functions

 

This is a common but APT-style and full of decoy-style anti-analysis technique. The malware is intentionally passing invalid parameters pollution to CreateFileA, and it makes noise in both static and dynamic analysis, which also makes it harder for analysts to do analysis, and analysts might waste time tracing it. They are designed to mislead disassemblers, significantly increasing the manual analysis burden. In other words, they also know how the other analysts think and do.

And the intent is not to drop and load automatically but only to require manual loading or injection by an operator with a loader.

 

 

In a word, it's designed for manual deployment, not automatic self-spreading and loading. The anti-analysis tricks are to hide intent and frustrate analysts and stealthy operation only.

 

Figure 27: The invalid parameters Pollution for anti-analysis technique.

 

 

 

 

Limitations & Unresolved Questions

1.     Very limited analysis without any compromised firmware; can't learn about what’s happened inside in firmware.

2.     Haven't completely confirmed other hidden functionality; other designs or intentions may be missed.

3.     Unknown which loader to be used.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Conclusion

In this report, it’s related only to some primary but limited characteristics. I also shared my process of doing research blindly at the beginning, and just helping me go further, it varies from person to person; don’t copy them.

 

I did not pursue full tracing of all in this report, to be honest. It took me too much time and more than 2 months. It is complex malware, and without completely understanding it, I especially have to face the reality without the compromised firmware.

From the process of analysis, the malware nls_933w.dll uses multiple-layer policies for anti-analysis techniques, the hidden functionality name, the custom XOR algorithm, and the decoy style for misleading, which implies the Equation Group took the protection of malware very seriously and was very full of tricks and skills.

I hold deep respect the Equation group for the depth of technique, both in design and thinking, which gave another different core tactic and technical mindset to the world. obviously, they are very good for algorithms and also know how analysts think, and they did it on a fine-grained algorithm that is full of advanced skill. Which means that analysts have to be calm in the process of analysis and observe carefully.

 

What’s truly remarkable is that this mindset and technical capability were already present over a decade ago. I now do analysis very limited on my own way and a huge unknown to me. A constant reminder: stay humble, learn endlessly, seek without ceasing.

 

It is the art of both patience and time for anti-depth.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

References

[1]. https://threatpost.com/inside-nls_933w-dll-the-equation-apt-persistence-module/111128/
[2]. https://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2018/03/08064459/
Equation_group_questions_and_answers.pdf

[3]. https://www.securityartwork.es/2015/06/09/analisis-de-nls_933w-dll-i/










 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Epilogue: What the Firmware Research Taught Me

1.     Don’t hurry up to make the last conclusion when you’re not sure; different paths imply different logic and intention.

2.     Sometimes it’s normal without any progress; researching and resting need to balance. To be honest, they also belong to you.

3.     To understand what it is that is the real one path you want to.

4.     The process of thinking becomes clear, which makes people happy by nature.

5.     Faced with the depth of malicious code, sometimes you have to face the frustration without any process. Calm down; it’s normal, and life is not just being happy.

6.     There is no real concentration without inner peace.

7.    On the process of research, I have learned and mastered how to sing “Om Ah Hum Vajra Guru Padma Siddhi Hum”, it is known as the Vajra Guru Mantra.

8.    At a quiet moment of inner reflection, I came to a profound realization: to truly analyze malware from the top-elite state-level APTs, one must adopt a scientist's attitude—meticulous, objective, and deeply committed—in the digital world.

 

 

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.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

About me


 Malware Analysis Space
All content is provided strictly for educational and defensive purposes.


 seeker-lee

PDF format malware analysis report for my malware analysis space and my ebook.

 


 clibm079 GitHub Pages.

Specifically designed to showcase research topics for my Malware Analysis Space.


 MalwareBazaar

Follow me



 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

📄 Copyright Notice

© Seeker (李标明), 2025. All rights reserved.
This document may be freely shared for non-commercial purposes, provided that it remains unmodified and proper attribution is given to the author.

Comments

Popular posts from this blog

Deobfuscating APT28’s HTA Trojan: A Deep Dive into VBE Techniques & Multi-Layer Obfuscation

Static Analysis of Turla’s Uroboros: Revealing Core Tactics and Technical Mindset

Unveiling APT28’s Advanced Obfuscated Loader and HTA Trojan: A Deep Dive with x32dbg Debugging