NanoCore RAT 1.2.2.0 — Secrets of Commercial RATs

NanoCore RAT 1.2.2.0 analysis

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:

  1. Contacts the malicious domain stonecold.ddns.net
  2. Multiple TCP packets following the DNS query
  3. Socket connection on port 2502

Wireshark capture showing the C2 DNS query and TCP traffic

Host-based indicators:

  1. Creates multiple files in %temp%
  2. Extracts cmdkuqqy, cckgcf.exe and ka9zcqw3l6l48a1uuba

Procmon log showing files extracted to the temp folder

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:

Process tree showing stage 2 launched from the temp folder


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:

  1. Starts itself as a child process
  2. Sends continuous SYN packets to the C2 on port 2502
  3. Creates run.dat in %AppData%
  4. Establishes persistence via Registry Run keys

Stage 2 network indicators

Stage 2 host indicators

Advanced static analysis

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

Stage 2 checking for a command line argument in IDA

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:

Dynamic API resolution in stage 2

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:

Injected buffer beginning with MZ header

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:

RWX memory region in Process Hacker matching the injected bytes

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 2 Registry Run key persistence


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.

Stage 3 extracting its embedded resource

Stage 3 performing process injection

Locating and dumping the next payload was mechanical:

SizeofResource returning the shellcode length in EAX

Shellcode start address in memory

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:

ExeInfoPE identifying Eazfuscator obfuscation

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

NanoCore extracting its encrypted resource

The GUID-keyed decryption routine

This is the most interesting part of the sample. The scheme is two-layer and self-keyed:

  1. 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.
  2. Take the next 16 bytes as the encrypted key.
  3. Generate the GUID of the executing PE itself.
  4. Decrypt those 16 bytes with Rijndael, using the GUID as the key.

Stage 4 decryption routine

Decrypting the key bytes with Rijndael

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

Decrypted 8-byte DES key

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:

DES decryption of the remaining 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:

Decrypted NanoCore RAT configuration

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:

NanoCore working directory named with the machine GUID

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:

run.dat creation with DateTime bytes

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:

LOLBin name masquerading table

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:

Resolving the C2 server

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:

Asynchronous socket setup

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:

Netcat listener receiving heartbeat packets

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:

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:


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 the gswccl / ratotpvvsmo.exe names 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.

← Back to all analyses