NanoCore RAT 1.2.2.0 — Secrets of Commercial RATs
NanoCore is a commercial Remote Access Trojan sold cheaply on the black market, complete with its own client builder and multiple delivery options. What makes it worth dissecting is not any single exotic technique but the layering: the sample unwraps through four distinct stages, each one extracting, decrypting and injecting the next, before the real .NET RAT client ever appears in memory. Its configuration is protected by a two-step Rijndael → DES scheme keyed on the binary’s own GUID, and its surveillance plugin carries a full keylogging, clipboard and DNS-logging stack.
This post walks the whole chain end to end — from the stage 1 dropper through the hollowed stages to the decrypted RAT configuration and the SurveillanceEx plugin — with the debugger screenshots taken during the analysis. Delivery (malicious attachment or spear phishing) is out of scope; the analysis starts at the first-stage sample.
⚠️ Note: This is a re-write by AI, but have been vetted by Author.
📄 The original report is also available as a PDF. Samples (password
infected), recreated TTP code and helper scripts are in the GitHub repository.
Sample
| Field | Value |
|---|---|
| SHA-256 | 1605F0E74C7088B8A2CA7190B71C83F8DC0381E57D817DF3530BDA4AC5737511 |
| Build | x86 and .NET (multiple stages) |
| Category | RAT (Remote Access Trojan) |
| Family | NanoCore |
| Version | 1.2.2.0 |
Analysis environment: FLARE-VM as the detonation host, with a REMnux box acting as DNS server and network simulator.
Tools: IDA Freeware, dnSpy, INetSim, Process Hacker, Procmon, TCPView, Wireshark, HxD, CFF Explorer, Resource Hacker, Netcat, DIE, de4dot, FLOSS, PE Studio, ExeInfoPE.
Key findings
| # | Finding |
|---|---|
| 1 | Four-stage unpacking chain — each stage extracts, decrypts and injects the next, purely to exhaust analysts and defeat static detection. |
| 2 | Process hollowing, twice — stages 2 and 3 both hollow a suspended copy of themselves and resume into injected shellcode. |
| 3 | Dynamic API resolution — every API in stage 2 is resolved at run-time via LoadLibraryA + GetProcAddress, so static analysis yields nothing. |
| 4 | GUID-keyed two-layer config crypto — the encrypted resource is unlocked with Rijndael using the binary’s own GUID, yielding an 8-byte DES key that decrypts the remainder. |
| 5 | Configuration and plugins in one resource — the decrypted blob splits into two arrays: the plugin DLLs (ClientPlugin, SurveillanceExClientPlugin) and the settings. |
| 6 | LOLBin masquerading — filenames and service names are assembled at run-time from an internal table of legitimate-looking names (DNS Monitor / dnsmon.exe, NTFS Manager / ntfsmgr.exe). |
| 7 | Dynamic DNS C2 — stonecold.ddns.net on port 2502, using a free DDNS provider to stay mobile and resist takedowns. |
| 8 | Custom DNS servers — the config pins 8.8.8.8 / 8.8.4.4, bypassing local DNS-based blocking and monitoring. |
| 9 | SurveillanceEx plugin — keylogging via RAW input devices, clipboard capture, DNS cache theft, and its own embedded process-hollowing code. |
| 10 | Config-gated behaviour — many aggressive features (RunOnStartup, RequestElevation, BypassUserAccountControl, SetCriticalProcess) were disabled in this build, so they never executed and had to be patched on to observe them. |
Stage 1: the dropper
The methodology here is the usual three passes: basic static analysis, basic dynamic analysis (initial detonation), then advanced static and dynamic analysis for TTP extraction.
FLOSS surfaces the interesting strings, and PE Studio flags the notable imports:
Software\Microsoft\Windows\CurrentVersion
CreateProcessA ShellExecuteA RegSetValueExA RegCreateKeyExA
That combination already tells the story: RegCreateKeyExA + RegSetValueExA against
CurrentVersion points at Registry Run key persistence, while CreateProcessA /
ShellExecuteA suggests a next-stage payload being launched.
Initial detonation
Detonated under Procmon (host indicators) with Wireshark capturing on the REMnux box (network indicators, simulated by INetSim).
Network indicators:
- Contacts the malicious domain
stonecold.ddns.net - Multiple TCP packets following the DNS query
- Socket connection on port 2502

Host-based indicators:
- Creates multiple files in
%temp% - Extracts
cmdkuqqy,cckgcf.exeandka9zcqw3l6l48a1uuba

So stage 1 extracts three files from its resources and executes the second stage with a file passed as a parameter. The process tree confirms it:

Stage 2: the loader
Stage 2 is cckgcf.exe, which consumes the encrypted files cmdkuqqy and
ka9zcqw3l6l48a1uuba. Notably it launches another instance of itself — the classic shape
of a loader that decrypts its payload at run-time.
Stage 2 indicators:
- Starts itself as a child process
- Sends continuous SYN packets to the C2 on port 2502
- Creates
run.datin%AppData% - Establishes persistence via Registry Run keys


Advanced static analysis
In IDA, stage 2 immediately checks for a command line argument — with no argument, it simply exits:

Beyond that, static analysis stalls: every API call is resolved dynamically.
Advanced dynamic analysis
Debugging reveals modules loaded at run-time that are absent from the import table —
shlwapi.dll and wininet.dll among them. API resolution uses the classic
LoadLibraryA + GetProcAddress pair to keep names out of the binary:

Following the resolved calls leads to shellcode being decrypted and injected into the
malware’s own process space. The buffer starts with 4D 5A (MZ) — it is a complete PE,
not position-independent shellcode:

The technique is process hollowing: start a process (here, itself) suspended, allocate memory in it, write the shellcode, repoint the image base to the shellcode’s start address, and resume. Execution then continues from the injected code.
Process Hacker confirms it from the memory side — hunting for RWX protections finds the injected region, matching the bytes seen in IDA:

Because the injected buffer is a full PE rather than raw shellcode, it can be dumped straight out of memory and analysed independently as stage 3.
Persistence
Stage 2 persists by writing a Run key value named gswccl pointing at
ratotpvvsmo.exe in %AppData%:

Stage 3: another wrapper
Stage 3 turns out to be another resource extractor — it repeats the same cycle: pull encrypted bytes from its resources, decode them, and inject into itself again. This exists purely to add one more layer of defense evasion.


Locating and dumping the next payload was mechanical:
- Inspect the registers to find the handle to the shellcode memory
- Determine the length to copy — the value returned by
SizeofResourceinEAXgives0x32A00 - Add that size to the shellcode’s start address to get the full range


Dumping from IDA’s hex view produces another PE — the final stage.
Practical note: extracting the payload from resources with IDA Freeware sometimes causes odd downstream failures, such as configurations not decrypting in the final stage. Dumping the last stage with Resource Hacker instead avoided the problem.
Stage 4: NanoCore v1.2.2.0 client
The final payload is a .NET binary — the NanoCore Client v1.2.2.0 — and it is heavily obfuscated. ExeInfoPE identifies Eazfuscator, for which open-source deobfuscators exist:

Like most RATs, NanoCore keeps its configuration and plugins in an encrypted resource:

The GUID-keyed decryption routine
This is the most interesting part of the sample. The scheme is two-layer and self-keyed:
- Read the first 4 bytes of the resource — this is the length of the encrypted key.
In this sample:
10 00 00 00=0x00000010= 16 bytes. - Take the next 16 bytes as the encrypted key.
- Generate the GUID of the executing PE itself.
- Decrypt those 16 bytes with Rijndael, using the GUID as the key.


The result is an 8-byte DES key, used as both key and salt to decrypt the rest of the resource:

The pattern then repeats: read the next 4 bytes as a length — 0x15D08 = 89,352 bytes
— and DES-decrypt that many bytes, running to the end of the resource:

In short: the malware uses its own GUID to unlock the key that unlocks everything else.
The decrypted payload
The decrypted resource splits into two arrays — binaries and settings. Two DLLs come out:
ClientPluginSurveillanceExClientPlugin

Recovered configuration
| Setting | Value |
|---|---|
| BuildTime | 3/23/2022 12:26:29 AM |
| Version | 1.2.2.0 |
| Mutex | 639f1c3f-4bc5-44fa-9234-8471b84f363c |
| DefaultGroup | EDGE |
| PrimaryConnectionHost | stonecold.ddns.net |
| BackupConnectionHost | stonecold.ddns.net |
| ConnectionPort | 0x09C6 (2502) |
| RunOnStartup | false |
| RequestElevation | false |
| BypassUserAccountControl | false |
| ClearZoneIdentifier | true |
| ClearAccessControl | false |
| SetCriticalProcess | false |
| PreventSystemSleep | true |
| ActivateAwayMode | false |
| EnableDebugMode | false |
| RunDelay | 0x00000000 |
| ConnectionDelay | 0x00000FA0 |
| RestartDelay | 0x00001388 |
| TimeoutInterval | 0x00001388 |
| KeepAliveTimeout | 0x00007530 |
| MutexTimeout | 0x00001388 |
| LanTimeout | 0x000009C4 |
| WanTimeout | 0x00001F40 |
| BufferSize | 0x0000FFFF |
| MaxPacketSize | 0x00A00000 |
| GCThreshold | 0x00A00000 |
| UseCustomDnsServer | true |
| PrimaryDnsServer | 8.8.8.8 |
| BackupDnsServer | 8.8.4.4 |
Working directory and run.dat
After applying the configuration, NanoCore creates its mutex, queries the machine GUID
from the registry, and creates a folder in %AppData% named with that GUID — its main working
directory:

The run.dat file seen during detonation is written here: the current DateTime stored as
bytes. It most likely records when the infection started, and is presumed to be sent as
part of the heartbeat traffic to the C2:

LOLBin masquerading
NanoCore builds almost all of its strings at run-time, combining fragments to avoid static detection. It carries an internal table of living-off-the-land binary names and paths, and assembles its own filenames and process names to impersonate legitimate Windows components.
In this run it selected DNS Monitor / dnsmon.exe; on the next it could equally pick
NTFS Manager / ntfsmgr.exe:

Config-gated behaviour
Because this build ships with most aggressive options disabled, the corresponding code paths are skipped entirely at run-time:
RunOnStartup: false RequestElevation: false
BypassUserAccountControl: false ClearAccessControl: false
SetCriticalProcess: false ActivateAwayMode: false
EnableDebugMode: false
Those steps were later reached by patching the malware so the behaviours could be observed and recreated for TTP extraction — which is where the recreated code below comes from.
C2 resolution and heartbeat
After configuring plugins, connection values, IPs and timeouts, NanoCore resolves its C2 —
domain stonecold.ddns.net, port 2502:

It then creates asynchronous sockets and repeatedly sends heartbeat messages until a connection is established. The live C2 was down during analysis, so execution stalls here:

INetSim can make the C2 appear live, but NanoCore has an authentication mechanism and waits for a valid server response before completing the socket. A netcat listener on port 2502 shows the heartbeat packets arriving:

The C2 is a DuckDNS domain. Dynamic DNS is a legitimate service for reaching devices on changing IPs, but it is equally useful to an operator who wants to hide the server’s location, stay anonymous, evade detection and re-point quickly after a takedown.
SurveillanceEx plugin
The second decrypted DLL, SurveillanceExClientPlugin, is where the spying lives. Dumped
and analysed separately, it contains notably well-organised malicious code:
- Extracts further resources —
Lzma(a custom LZMA compression plugin) andTLD(undetermined). - Process hollowing — an entire embedded implementation, separate from the loader stages.
- Keylogging — structured recording of keystrokes, clipboard contents, DNS records and more.
- Command & control — handles commands to enable/disable keylogging, application logging and DNS logging, plus get, delete, export and view logs.
- Exfiltration — recorded logs are sent to hosts defined dynamically by the malware.
The keylogging implementation was recreated: it registers a RAW input device, receives RAW
input data, maps it to Unicode characters and logs to a .dat file. DNS records are harvested
using the DnsGetCacheDataTable API.
MITRE ATT&CK mapping and recreated TTPs
Every technique below was identified during analysis; most have working recreated code, and links point to the write-up first, with the raw source on GitHub.
| Tactic | Technique | ID | Write-up · Detection · Code |
|---|---|---|---|
| Credential Access | Input Capture: Keylogging | T1056.001 | Write-up · Detection · Code |
| Privilege Escalation | Scheduled Task/Job: Scheduled Task | T1053.005 | Write-up · Detection · Code |
| Persistence | Boot or Logon Autostart: Registry Run Keys | T1547.001 | Write-up · Detection · Code |
| Collection | Clipboard Data | T1115 | Write-up · Detection · Code |
| Collection | Data from Local System (DNS cache) | T1005 | Write-up · Detection · Code |
| Defense Evasion | Impair Defenses: Disable or Modify Tools | T1562.001 | Write-up · Detection · Code |
| Defense Evasion | Subvert Trust Controls: Mark-of-the-Web Bypass | T1553.005 | Write-up · Detection · Code |
| Defense Evasion | Process Injection: Process Hollowing · Software Packing | T1055.012 · T1027.002 | Write-up · Detection · Code |
| Command & Control | Non-Application Layer Protocol (raw socket C2) | T1095 | Write-up · Detection · Reference code ReverseShell_NC |
Additional techniques observed but not yet recreated:
| Tactic | Technique | ID |
|---|---|---|
| Defense Evasion | Obfuscated Files or Information: Dynamic API Resolution | T1027.007 |
| Defense Evasion | Hide Artifacts: Resource Forking | T1564.009 |
| Defense Evasion | Hide Artifacts: Hidden Window | T1564.003 |
| Defense Evasion | Masquerading: Masquerade Task or Service | T1036.004 |
| Defense Evasion | File and Directory Permissions Modification | T1222.001 |
| Collection | Automated Collection | T1119 |
| Exfiltration | Exfiltration Over C2 Channel | T1041 |
See the full project matrix on the ATT&CK coverage page.
Detection opportunities
NanoCore morphs its strings and filenames at run-time, so signature matching is weak here. Behaviour is where it is catchable:
- A process launching a suspended copy of itself, followed by an RWX allocation whose
contents begin with
MZ, thenSetThreadContext+ResumeThread— the hollowing signature, and it fires twice in this chain. - Executables dropped to
%temp%with random lowercase names and no extension (cmdkuqqy,ka9zcqw3l6l48a1uuba), immediately executed with a file passed as a parameter. - A folder in
%AppData%named exactly like the machine GUID, containing arun.datfile. - Run key values pointing at random-named executables in
%AppData%. - Outbound connections to dynamic DNS domains (
*.ddns.net,*.duckdns.org) on non-standard high ports such as 2502, especially with a regular heartbeat cadence. - Processes issuing DNS queries directly to
8.8.8.8/8.8.4.4, bypassing the configured local resolver — a strong signal when enterprise DNS is mandatory. DnsGetCacheDataTablecalls from a non-system process — rare and hard to explain benignly.- RAW input device registration (
RegisterRawInputDevices) by a process with no UI, the hallmark of the keylogger. - Zone.Identifier deletion on downloaded files (
ClearZoneIdentifier: truein this config). - Binaries masquerading as
dnsmon.exe,ntfsmgr.exeand similar outsideSystem32.
Indicators of compromise
Hash (SHA-256)
1605f0e74c7088b8a2ca7190b71c83f8dc0381e57d817df3530bda4ac5737511 stage 1 dropper
Network
stonecold.ddns.net C2 (primary and backup), DuckDNS
2502 C2 port (0x09C6)
8.8.8.8 / 8.8.4.4 hardcoded custom DNS resolvers
Host artefacts
%TEMP%\cmdkuqqy encrypted stage 2 component
%TEMP%\cckgcf.exe stage 2 loader
%TEMP%\ka9zcqw3l6l48a1uuba encrypted stage 2 component
%AppData%\ratotpvvsmo.exe persistence target
%AppData%\<machine GUID>\ working directory
%AppData%\run.dat infection timestamp
HKCU\...\CurrentVersion\Run value "gswccl"
Mutex 639f1c3f-4bc5-44fa-9234-8471b84f363c
Note: the
%temp%filenames and thegswccl/ratotpvvsmo.exenames are generated per build and per run — treat them as pattern examples rather than fixed indicators. The mutex, domain and port are the durable ones.
⚠️ The samples in this repository are live malware, stored in archives with the password
infected. Detonate only inside an isolated, network-controlled VM. See SECURITY.md.
Closing thoughts
NanoCore’s capability set — remote control, keylogging, file manipulation, data exfiltration — makes it a serious threat to individuals and organisations alike. But the real lesson from this analysis is about detection strategy. Four layers of packing, run-time string assembly, dynamic API resolution and GUID-derived configuration keys mean that signature-based detection is fighting a losing battle: the observable bytes change with every build.
Behavioural detection is what holds up. Watching for the shape of the activity — self-hollowing, RAW input registration, DNS cache reads, heartbeat traffic to dynamic DNS — will catch this family and its variants long after any hash or string signature has gone stale.
Disclaimer
The artifacts, code and analysis in this repository are provided strictly for educational and research purposes. I do not condone or support any malicious use of this material.