Analysing a supplied WannaCry sample
I completed this investigation for CMP320 / Advanced Ethical Hacking in 2022/23. The task was to analyse a supplied suspicious Windows executable, determine whether it was malicious, identify its purpose and behaviour, and produce indicators that could support detection and incident response.
I treated the sample as untrusted throughout. Analysis took place in an isolated virtual machine with separate working copies and no connection to production systems. The public page documents the investigative method and findings, not the sample itself.
I set five questions for the investigation:
- Was the supplied program malicious?
- What function or malware family did it belong to?
- How did it prepare and execute its main behaviour?
- What impact did it have on the Windows system?
- Which file, host, process, memory, and network observations could support detection?
The work used three complementary views:
- static analysis to inspect the executable without running it
- dynamic and memory analysis to observe what changed during execution
- network analysis to examine the traffic produced by the infected system
Each view answered different questions. Static analysis exposed structure and likely capability. Dynamic analysis showed which paths actually executed. Memory and network evidence then provided context that was not visible in the file on disk.
Analysis plan
I used the initial static findings to decide what to watch during execution rather than running three disconnected exercises.
| Stage | Questions | Evidence and tools |
|---|---|---|
| File identification | Was the sample already classified, and did its metadata agree with that identity? | VirusTotal history, hashes, PE metadata |
| PE inspection | What sections, resources, strings, and imports suggested capability? | CFF Explorer, PE-Bear, Cerbero Suite, string extraction |
| Decompilation | How did the launcher move from its entry point into resource extraction, persistence, and encryption setup? | Ghidra call flow, renamed functions, cross-references |
| Live execution | Which processes and files actually appeared, and what visible impact occurred? | Disposable VMware guest, Process Hacker, before-and-after observations |
| Memory capture | Which process relationships, handles, arguments, and connections survived in RAM? | FTK Imager and Volatility |
| Network capture | Which destinations were contacted, on which ports, and how did each connection end? | Wireshark, TCP stream review, historical DNS and service context |
This gave me a correlation chain from code to observed behaviour. For example, resource APIs in the import table led to the embedded-resource routines in Ghidra, then to dropped files during execution. Registry APIs led to a persistence function, then to registry handles in memory. Tor-related sandbox observations led to selected packet streams, but I still checked the local capture before accepting the sandbox interpretation.
Static triage and executable structure
The first pass established file identity and structure. A historical VirusTotal check returned 67 positive identifications and classified the sample as WannaCry. That result answered the initial classification question, but it did not replace analysis of the binary.
CFF Explorer, PE-Bear, and Cerbero Suite were used to inspect Portable Executable metadata, sections, resources, and imported functions. The metadata presented the program as diskpart.exe, although its structure and behaviour did not match the legitimate Windows disk-management utility. The executable appeared to have been compiled with Microsoft Visual C++ 6.0 and carried additional resources inside the binary.
The import table included Windows functions associated with:
- locating and loading embedded resources
- allocating and changing memory protections
- copying and querying files
- reading and writing registry keys
- loading libraries and resolving function addresses
- using Windows cryptographic services
An imported API is not evidence of malware by itself. The combination of resource extraction, registry modification, memory-management functions, file operations, and misleading metadata provided a stronger basis for investigation.
The imports supplied useful hypotheses:
| API group | Examples observed | Investigative question |
|---|---|---|
| Resource handling | FindResourceA, LoadResource, LockResource |
Was the executable carrying secondary files or configuration inside its resource section? |
| Memory handling | VirtualAlloc, VirtualProtect |
Did the program prepare or transform material in memory before use? |
| File and module handling | CopyFile, GetModuleFileName, GetModuleHandle |
Did it copy itself or supporting files and derive paths relative to the running module? |
| Registry handling | RegCreateKey, RegSetValueEx, RegQueryValueEx, RegCloseKey |
Did it save state or establish persistence through the registry? |
| Dynamic resolution | LoadLibraryA, GetProcAddress |
Were additional functions selected only at runtime? |
| Cryptographic context | CryptReleaseContext |
Did later code use Windows cryptographic services? |
Following the code in Ghidra
I loaded the binary into Ghidra and worked outwards from the entry point. The decompiler’s generated function names were replaced with descriptive labels as their purpose became clearer. This made it easier to follow the call flow without pretending that every branch had been fully recovered.
The main routine established local state, located its working directory, checked command-line arguments, and called into the functions responsible for copying files, extracting resources, and starting the encryption workflow.
The resource section contained supporting components, including compression utilities and an encrypted archive. String analysis exposed a hard-coded archive password, which helped explain how the bundled files were unpacked at runtime. The sample was therefore not one self-contained routine; it acted as a launcher and resource carrier for several parts of the ransomware.
The embedded strings identified inflate 1.1.3 and unzip 0.15. The archive password WNcry@2017 was passed into the routine I labelled DecryptZipFile. Those details linked the resource section to a concrete unpacking mechanism rather than leaving the embedded data unexplained.
Main routine and execution setup
The entry path set up exception handling and local variables, located the current working directory, examined command-line arguments, and called a function originally labelled FUN_00401fe7. That path led into file copying, embedded-resource extraction, and preparation of the encryption process.
I renamed functions according to the behaviour I could support from their control flow. The labels were analytical aids, not recovered source-level names:
ExtractResourcesdescribed the resource lookup, loading, locking, extraction, and cleanup pathBitcoinAddressdescribed selection and persistence of one value from three embedded addressesDecryptZipFiledescribed process creation around the bundled extraction and permission-changing commandsEncryptionProcessdescribed the function-pointer preparation immediately before the encryption stage
This naming made the call graph readable while preserving uncertainty about details that were not completely recovered.
Persistence and file placement
The function originally labelled FUN_004010fd accepted one integer argument and selected either the machine or current-user registry context. In one branch it retrieved a stored path and set the process working directory from that value. In the other it obtained the current directory and wrote it back to the registry. It returned success only when the key and value operation completed.
The same path copied tasksche.exe into the working directory and queried its file attributes. The registry value therefore provided retained location state, while the copied executable formed part of the later execution and persistence behaviour.
The static analysis also identified:
- resource lookup through
FindResourceA - loading and locking resource data in memory
- extraction of embedded files to disk
- changes to file permissions
- selection from several embedded payment addresses
- runtime resolution of selected Windows functions
The runtime lookup pattern reduced reliance on a completely explicit static import table. It did not make the behaviour invisible, but it shifted part of the analysis from file structure to execution telemetry.
Extracting embedded components
The ExtractResources routine took a module handle and attempted to locate a specific embedded resource. When found, it loaded and locked the resource, passed its address and size into a subordinate extraction function, and checked the resulting data for an expected string. It then used file attributes to decide whether the component already existed before writing it to disk, followed by cleanup of the allocated material.
That sequence explained several later observations:
locate resource
-> load and lock bytes
-> pass bytes and size to extraction code
-> inspect expected output
-> check whether the target file exists
-> write missing component
-> free temporary material
It also separated unpacking from file encryption. The launcher first assembled the tools and resources it needed; the ransomware activity followed from that prepared working set.
Payment-address state
The function I labelled BitcoinAddress contained three embedded address strings and called a separate file-input/output routine. If no retained value was available, it generated a number, selected an address using the remainder after division by three, copied the selected value into a buffer, and persisted it.
The supporting file routine changed behaviour according to its second parameter: one branch opened the state file for writing, while the other read existing data back into the supplied buffer. This showed how the displayed payment state could be selected once and then reused rather than chosen independently at every invocation.
Process creation and file permissions
DecryptZipFile prepared process and startup structures, launched a command through CreateProcessA, optionally waited for completion, collected an exit code, and closed the process and thread handles. I observed two call sites around the setup path. One invoked the bundled extraction command; the other changed permissions recursively on the prepared working files.
The report’s label reflected how the function was used in that path, but the routine itself was a more general process-launching wrapper. Distinguishing the wrapper from its call-site arguments prevented the implementation from being described too narrowly.
Immediately before the encryption stage, another function loaded kernel32.dll, resolved several APIs through GetProcAddress, stored the resulting pointers in global variables, and checked that every required address had been populated. Static imports therefore described only part of the execution surface.
Encryption workflow
The decompiled code showed a sequence that prepared bundled resources, unpacked supporting components, and then entered the file-processing stage. The report focused on how the program assembled its working environment rather than attempting to reproduce the ransomware’s encryption against real data.
The archive password, embedded tools, registry changes, and resource-extraction routines showed how the sample carried what it needed inside the executable. This helped distinguish the outer launcher from the files and processes that appeared after execution.
Dynamic analysis in an isolated Windows VM
I executed the sample in a disposable Windows virtual machine and recorded the machine before and after detonation. Process Hacker was used to watch process creation, resource use, and visible file-system changes.
The executable launched under the misleading DiskPart identity and generated two WannaDecryptor processes. The system then showed the familiar ransomware interface and a changed desktop background. Files and supporting executables appeared in the working directory as the embedded resources were unpacked.
The before-and-after comparison provided several distinct forms of evidence:
- the original executable remained visible under the DiskPart-style identity
- two WannaDecryptor processes appeared beneath the execution chain
- sustained disk input/output accompanied the file changes
- the desktop background and GUI changed
- ransomware support files, key-related files, and encrypted extensions appeared
- the process tree tied the visual result back to the original launcher
The process tree gave the first clear runtime relationship between the initial launcher and the decryptor components. Visual changes confirmed impact, but the process and file evidence was more useful for explaining how that impact was produced.
I also compared the observed behaviour with a historical Intezer sandbox result. The sandbox mapped activity to techniques including:
- modifying the ransom message and desktop
- creating startup persistence
- deleting or attempting to delete volume shadow copies
- dropping supporting files
- preparing Tor-related communication
Sandbox output was treated as another source to verify, not as an unquestioned answer. I checked the file changes and network observations independently where the local lab evidence allowed it.
Capturing and examining memory
FTK Imager captured the VM’s memory after execution. I transferred the capture to a separate analysis environment and examined it with Volatility.
Process-list and process-tree analysis showed the original executable and the two WannaDecryptor instances. Handle inspection exposed access to registry keys and files associated with the ransomware’s encryption state. Command-line analysis showed that most components ran without extensive arguments, while one decryptor instance received a short mode argument.
Handle output included access to the 0000000.ekey file and relevant registry state. Command-line output showed the short co argument on one decryptor process. Network-state analysis found a localhost connection associated with process ID 2308. The memory capture therefore connected process identity, open handles, command-line state, and network activity at a particular point in execution.
I used several Volatility views together:
| View | Evidence recovered |
|---|---|
| Process list | The original process and two WannaDecryptor instances |
| Process tree | Parent and child relationships between the active components |
| Handle inspection | Registry and key-related file access, including 0000000.ekey |
| Command lines | Mostly argument-free execution plus the co mode argument |
| Network state | A local connection associated with one active process |
This stage was especially valuable because disk inspection could not show every runtime relationship. Memory preserved:
- processes that had been created
- parent and child relationships
- open files and registry handles
- command-line arguments
- active or recently active network state
The capture was only a snapshot. Activity that completed before acquisition or started afterwards would not necessarily be present, so I compared it with the live monitoring and packet capture rather than treating it as a complete record.
Network traffic and Tor-related connections
Wireshark captured traffic from the test VM during execution. I used the sandbox observations to identify connections worth reviewing, then followed the corresponding TCP streams and TLS handshakes in the local packet capture.
Five outbound destinations received individual review. These are historical observations from the 2023 lab capture, not current reputation claims.
| Historical destination | Observed traffic | Context recorded during the investigation |
|---|---|---|
176.123.9.169 |
Connection to port 9001 and a TLS handshake | Followed TCP data contained several domain-like values; reverse lookup returned no record, and historical service data showed port 9001 |
142.132.254.39 |
Connection to port 8999 and a TLS handshake | Reverse DNS resolved into Hetzner-hosted infrastructure |
212.47.233.86 |
Connections associated with ports 9001 and 9030 | Historical service information identified the host as a Tor relay |
128.31.0.39 |
SYN followed by RST, ACK, repeated before termination |
Reverse DNS identified an MIT CSAIL host; the capture showed failed contact rather than a completed session |
5.9.159.14 |
Connection attempt with no response | Reverse DNS pointed to hosting infrastructure, but the capture did not establish what role the host played |
Several outbound connections therefore used ports and hosts associated at the time with Tor relay infrastructure. Some attempts completed a TLS handshake, while others were reset or received no response. Reverse-DNS and historical service information provided context, but the destination addresses alone were not reliable long-term indicators. Tor relay membership changes, shared infrastructure can serve legitimate users, and old addresses lose value quickly.
The network evidence supported the behavioural finding that the sample attempted to establish Tor-based communication. It also demonstrated the limits of relying on a single data source:
- encryption concealed application content from simple packet inspection
- failed connections still revealed intent and retry behaviour
- domain and IP reputation was time-dependent
- process context was needed to connect traffic to the ransomware
For detection, the sequence was more useful than a static blocklist: a newly executed binary dropped resources, created related processes, changed the host, and then initiated unusual encrypted outbound connections.
Indicators as an investigative set
The assignment included host, string, import, and hash indicators. I grouped them by what they represented rather than treating every value as equally durable.
File and host indicators included tasksche.exe, taskdl.exe, taskse.exe, 0000000000.ekey, 0000000000.pky, 0000000000.res, the *.wnry extension, ransom-note components, registry persistence, desktop changes, and the WannaDecryptor process family.
Static indicators included the sample hashes, the WNcry@2017 archive string, unzip 0.15, inflate 1.1.3, misleading DiskPart metadata, resource structure, and imported APIs.
Behavioural indicators included resource extraction, startup persistence, file-permission changes, shadow-copy deletion, process creation, file encryption activity, and Tor-related network connections.
I did not treat the indicators as interchangeable. A sample hash gives high-confidence identification for one exact file but is easy to change. A filename or string is useful but can collide or be altered. The resource-extraction, process-creation, registry, file-encryption, and network sequence is harder to reduce to one value and gives an analyst more context.
The exact sample hashes remain in the academic report. The public portfolio includes selected historical observations with their analysis rather than presenting an unexplained indicator dump.
Detection opportunities across the evidence
The investigation supported detections at several points in the execution chain:
| Data source | Detection opportunity |
|---|---|
| File scanning | Known sample hashes, misleading metadata, unusual resource content, and archive or tool strings |
| Process telemetry | A DiskPart-labelled executable spawning WannaDecryptor components and bundled utilities |
| Registry telemetry | Creation or modification of retained working-path and startup state |
| File-system telemetry | Dropped tools, key-related files, ransomware extensions, and widespread write activity |
| Memory telemetry | The parent-child process tree, key-file handles, dynamically resolved functions, and local process communication |
| Network telemetry | New processes initiating repeated encrypted connections to unusual infrastructure and Tor-associated ports |
| Recovery telemetry | Attempts to remove volume shadow copies alongside ransomware file activity |
No single observation carried the whole classification. The confidence came from correlation: the executable’s structure predicted resource and registry behaviour; live execution produced the related process and file changes; memory preserved handles and arguments; and the packet capture showed the corresponding outbound attempts.
Findings
The combined analysis classified the sample as WannaCry ransomware and reconstructed the following behaviour:
- The initial executable presented itself as a Windows utility.
- It located and unpacked embedded resources, including an encrypted archive and supporting tools.
- Registry and file operations established working state and persistence.
- The launcher created WannaDecryptor processes and changed the desktop and file system.
- Memory artefacts recorded the process tree, open handles, command-line state, and local network activity.
- Packet analysis showed attempts to communicate over encrypted connections associated with Tor relay infrastructure.
Static analysis explained what the program appeared capable of doing. Dynamic evidence showed which components ran. Memory and network analysis then connected the host changes to active processes and communication attempts.
Further analysis identified at the time
The next stage I proposed was deeper debugging of the encryption and communication routines. That would have included tracing the sample instruction by instruction in memory, mapping decrypted values to their use, and examining how keys and control messages moved between components.
I also identified value in:
- mapping observed behaviour more precisely to endpoint telemetry
- comparing the process and registry sequence with modern detection rules
- recovering additional configuration from memory
- examining the encryption implementation without operating on real data
- separating durable behavioural detections from short-lived hashes and addresses
This is a historical 2023 university analysis of a supplied sample. Malware-analysis tooling, threat intelligence, and WannaCry infrastructure have changed since the work was completed, but the investigative workflow remains representative: establish identity, inspect structure, observe execution, preserve memory, analyse traffic, and correlate the evidence before drawing conclusions.
