Initial context:
Executive Summary
This report analyzes a suspected Regin Stage 1 kernel-mode loader, a highly stealthy component associated with long-term advanced persistent threat (APT) espionage operations. The sample is a small (11.4 KB), 32-bit native Windows driver compiled in 2007 using Microsoft Visual C++ tooling. Its lack of version metadata, minimal static imports, and deliberate obfuscation indicate a strong emphasis on stealth, stability, and long-term persistence.
The driver’s DriverEntry routine initializes structured exception handling, disables unloading, and decrypts an embedded configuration stored in the .data section using a custom XOR-based routine. This configuration includes a registry path under HKLM\SYSTEM\CurrentControlSet\Control\RestoreList, which is decrypted only once using a runtime control flag to limit execution artifacts. Additional data elements include preallocated buffers, benign-looking Windows directory strings, and registry value names used during early-stage environment preparation.
The malware dynamically resolves critical kernel components by locating loaded modules such as ntoskrnl.exe and hal.dll, and adapts its behavior based on the operating system version using NtBuildNumber. Access to kernel internals, including the System Service Descriptor Table (SSDT), enables OS-independent execution without relying on static imports. Overall, the findings confirm this sample functions as a first-stage Regin kernel loader, focused on secure initialization, environment validation, and preparation for subsequent payload stages, reflecting a level of sophistication consistent with highly targeted espionage activity.
Description
The analyzed sample is a small Win32 PE executable (11.41 KB) compiled for 32-bit Windows systems. The file was built using Microsoft Macro Assembler (MASM) and linked with Microsoft Visual C++ 7.1, suggesting deliberate low-level development rather than standard high-level application code. Multiple cryptographic hashes were generated to uniquely identify the sample. The executable exhibits characteristics consistent with a lightweight loader component, including its minimal size and lack of overt functionality. These traits align with the behavior expected from the first-stage loader of the Regin malware platform, which is designed to operate stealthily and facilitate the decryption and in-memory loading of subsequent stages.
File
| SHA-256 | f1d903251db466d35533c28e3c032b7212aa43c8d64ddf8c5521b43031e69e1e |
|---|---|
| decrypted file SHA-256: | 23115663c967069cb482604700be9f7ed6df4ea1297d453debad1119b0f85b2e |
Findings
| Attribute | Value |
|---|---|
| File Name | 06665b96e293b23acc80451abb413e50 |
| MD5 | 06665b96e293b23acc80451abb413e50 |
| SHA-1 | 9f0dc086875e6b06efe6bb3aadf049ce00f9e486 |
| SHA-256 | f1d903251db466d35533c28e3c032b7212aa43c8d64ddf8c5521b43031e69e1e |
| Vhash | 0140466d7e5519z16z17xz |
| Authentihash | 139c80dde62a325f0ae2e2370b801e91caecef57dcf0ac2be7444e99341b9c92 |
| Imphash | a9c1041cccb87f4a7ba3b7048d4e8ad7 |
| Rich PE Header Hash | 90c92121c7e7a342a64cd5609234ece1 |
| SSDEEP | 192:za3N5H44rW3ias7dUFdELQcsafdPvlw/BZUGJdMr0KqOMwb:zkasBUFuVsafVvlw/BLMcOHb |
| TLSH | T1C5325D22B6C140F5DA59D8F2AD3A7B39247FAD21633FE5D283340D691D6A841A73708F |
| File Type | Win32 EXE executable windows pe peexe |
| Magic | PE32 executable (Intel 80386, MS Windows) |
| Architecture | x86 (32-bit) |
| File Size | 11.41 KB (11,680 bytes) |
| TrID Identification | Win32 DLL (34.3%), Win32 EXE (23.4%), Windows Icons Library (10.7%), OS/2 EXE (10.5%), Generic Win/DOS EXE (10.4%) |
| Detect It Easy | PE32, Compiler: MASM 7.01.4035, Linker: MS Linker 7.10.4035 |
| Magika | PEBIN |
| PEiD Packer | Microsoft Visual C++ v7.1 EXE |
PE Metadata
File Identification and Basic Properties:
| Field | Value |
|---|---|
| SHA-256 | F1D903251DB466D35533C28E3C032B7212AA43C8D64DDF8C5521B43031E69E1E |
| File Name | c:\users\redteam\desktop\regin\06665b96e293b23acc80451abb413e50 |
| File Type | Executable, 32-bit, Native |
| File Size | 11,680 bytes |
| Entropy | 6.524 |
| File Version | N/A |
| File Description | N/A |
| Digital Signature | Microsoft Linker 7.10 / Visual Studio / Microsoft Visual C++ 6.0–8.0 |
PE Headers
| Field | Value |
|---|---|
| DOS Header (Hex) | 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 |
| DOS Header (Text) | MZ............................................@.............. |
| Architecture | Intel x86 (32-bit) |
| Subsystem | Native |
Entry Point Information
| Field | Value |
|---|---|
| Entry Point Offset | 0x00000814 |
| Entry Point Section | .text |
| Entry Point Bytes (Hex) | 6A 0C 68 10 03 01 00 E8 74 00 00 00 83 65 FC 00 8B 45 08 C7 40 34 06 08 01 00 80 3D 68 25 01 00 |
Sections
| Section Name | Virtual Address | Virtual Size (bytes) | Raw Size (bytes) | Entropy | MD5 | Chi-Square (Chi²) |
|---|---|---|---|---|---|---|
.text | 0x00000280 (640) | 8,904 | 8,928 | 6.52 | e9285367382d63f5e65445b78a688b5e | 49,665.19 |
.data | 0x00002560 (9,568) | 824 | 832 | 7.33 | 57db72556a0e508de756687d48351a93 | 1,608.62 |
INIT | 0x000028A0 (10,400) | 586 | 608 | 4.86 | 288e1b4ff839ac154cb20074ca668049 | 13,850.11 |
.reloc | 0x00002B00 (11,008) | 644 | 672 | 3.16 | 8a24633536aa0a73063171a85bac00b4 | 68,508.31 |
Compilation and Time Stamp Information
| Field | Value |
|---|---|
| Compiler Timestamp | Thu Dec 06 01:23:00 2007 (UTC) |
| Debug Timestamp | N/A |
| Resource Timestamp | N/A |
| Import Timestamp | N/A |
| Export Timestamp | N/A |
Description:
When we look at the parts of the program we see that it is put together in an organized way. The part that has the code is pretty mixed up which is what we usually see in code that someone wrote by hand or tried to make very small. This kind of code is often used in the parts of the program that load things. The part that stores data is more mixed up which makes us think that it might have secret or packed up information like settings or another hidden program. There is also a part that starts things up which is not typical and it means that the bad program has its own way of getting started. The part that helps the program move to places on the computer is pretty simple, which is what we expect to see. The program and the bad program are the thing in this case the malware. The malware has its lifecycle. The parts of the malware, like the.text section and the.data section and the INIT section and the.reloc section are all important to understand how the malware works. Overall, the section layout and entropy distribution support the assessment that this sample functions as a minimal first-stage loader designed for stealth and controlled execution rather than direct malicious activity.
Static Analysis
Imports /Resolved / Referenced Kernel APIs
| Function Name | Flag | Resolution Type | Ordinal | Address (RVA) | Thunk Address | Module |
|---|---|---|---|---|---|---|
| wcslen | - | implicit | - | 0x00002A2C | 0x00002A2C | ntoskrnl.exe |
| wcscpy | - | implicit | - | 0x000029F8 | 0x000029F8 | ntoskrnl.exe |
| strrchr | - | implicit | - | 0x00002A4C | 0x00002A4C | ntoskrnl.exe |
| strncpy | - | implicit | - | 0x00002A84 | 0x00002A84 | ntoskrnl.exe |
| strncmp | - | implicit | - | 0x00002A72 | 0x00002A72 | ntoskrnl.exe |
| strchr | - | implicit | - | 0x00002A42 | 0x00002A42 | ntoskrnl.exe |
| atoi | - | implicit | - | 0x00002A7C | 0x00002A7C | ntoskrnl.exe |
| _strnicmp | - | implicit | - | 0x00002A36 | 0x00002A36 | ntoskrnl.exe |
| _snprintf | - | implicit | - | 0x00002A9E | 0x00002A9E | ntoskrnl.exe |
| ZwQueryValueKey | x | implicit | - | 0x00002966 | 0x00002966 | ntoskrnl.exe |
| ZwQuerySystemInformation | x | implicit | - | 0x00002A56 | 0x00002A56 | ntoskrnl.exe |
| ZwQueryInformationFile | x | implicit | - | 0x00002A12 | 0x00002A12 | ntoskrnl.exe |
| ZwOpenKey | - | implicit | - | 0x00002978 | 0x00002978 | ntoskrnl.exe |
| ZwCreateFile | - | implicit | - | 0x00002A02 | 0x00002A02 | ntoskrnl.exe |
| ZwClose | - | implicit | - | 0x0000295C | 0x0000295C | ntoskrnl.exe |
| RtlUnwind | - | implicit | - | 0x000029C6 | 0x000029C6 | ntoskrnl.exe |
| RtlInitAnsiString | - | implicit | - | 0x000029A4 | 0x000029A4 | ntoskrnl.exe |
| RtlFreeUnicodeString | - | implicit | - | 0x00002944 | 0x00002944 | ntoskrnl.exe |
| RtlAnsiStringToUnicodeString | - | implicit | - | 0x00002984 | 0x00002984 | ntoskrnl.exe |
| NtBuildNumber | - | implicit | - | 0x00002A8E | 0x00002A8E | ntoskrnl.exe |
| KeServiceDescriptorTable | x | implicit | - | 0x00002AAA | 0x00002AAA | ntoskrnl.exe |
| KeQueryPerformanceCounter | - | implicit | - | 0x00002AC6 | 0x00002AC6 | HAL.dll |
| ExFreePool | - | implicit | - | 0x000029D2 | 0x000029D2 | ntoskrnl.exe |
| ExAllocatePoolWithTag | - | implicit | - | 0x000029E0 | 0x000029E0 | ntoskrnl.exe |
Hex editor
Fig 1 - MZ header in the beginning
IDA Analysis
IDA recognized the entry point as DriverEntry.
Fig 2 - Entry point
DriverEntry function (mcd.h) - The DriverEntry miniport driver routine is called when the miniport driver is loaded.
Fig 3 - msdn DriverEntry
Beginning of the code goes immediately goes into loop. XORing some bytes that IDA renamed as SourceString.
Fig 4 - xor SourceString
Following SourceString Encrypted data followed by more encrypted data.
Fig 5 - Encrypted data conversion to Array
Going into sub_106C0 next call is using another buffer.
.text:000106E0 push offset unk_12663 at this address
.data:00012663 unk_12663 db 0D3h ; DATA XREF: sub_106C0+20↑o
Fig 6 - address 0x106E0 calling buffer.
Almost every important information in the code is using one or another buffer that looks like encrypted strings.
Decryption
decryption program template:
#!/usr/bin/python3
from decoder_core import *
from Crypto.Cipher import *
class Decoder(TrainingDecoder):
def __init__(self):
# MD5 hash of the correctly decrypted file
super().__init__()
def decode(self):
# self.data is a bytearray with the contents of the file
# 1. Set the proper file offset of the encrypted block
encrypted_block_offset = REPLACE_WITH_THE_SOLUTION
# 2. Set the proper length of the encrypted block
encrypted_block_len = REPLACE_WITH_THE_SOLUTION
# 3. Set the proper file offset of the decryption key
key_offset = REPLACE_WITH_THE_SOLUTION
# 4. Set the proper length of the decryption key
key_len = REPLACE_WITH_THE_SOLUTION
key = self.data[key_offset:key_offset+key_len]
for i in range(0,encrypted_block_len):
self.data[encrypted_block_offset+i] = ( self.data[encrypted_block_offset+i] ^ key[i%key_len] ^ i ) & 0xFF
# Check if the results are correct
self.check_results()
# Create the decryptor object. Automation happens in __init__()
Decoder()
Fig 7 - Counter loop
The register ESI is used as the loop counter, initialized to zero and incremented on each iteration until it reaches the upper bound of 0x2EE, defining the size of the decrypted buffer.
encrypted_block_len = 0x2EE
Convert Virtual address to the file offset
IDA
Fig 8 - encrypted block offset
encrypted_block_offset = 0x2569
The XOR key in this routine is a small rolling key stored at byte_1080A, combined with the loop counter (ESI).
Fig 9 - byte_1080A
Fig 10 - key offset
key_offset = 0x80A
Fig 11 - Converting 7 to binaryis 111b
We’re going to have values starting from 0 and ending in 7, including 7.
So the length of the key is 8.
Fig 12 - Successfully decrypted
File Differences
Fig 13 - First difference
Fig 14 - Second difference
Decrypted File Analysis
Basic Properties
| Attribute | Value |
|---|---|
| File name | 06665b96e293b23acc80451abb413e50.dec |
| MD5 | f8d94c86b15b62d5d76b9846fad5ae59 |
| SHA-1 | 41a24d8697c06890cd0cf96ecb4ee30904ef5087 |
| SHA-256 | 23115663c967069cb482604700be9f7ed6df4ea1297d453debad1119b0f85b2e |
| Vhash | 0140466d1e5519z16z17xz |
| Authentihash | 8ccd332ab1c6585caafbb58fb31f03be285c8342ce32ff4a8df0120e50c72163 |
| Imphash | a9c1041cccb87f4a7ba3b7048d4e8ad7 |
| Rich PE Header Hash | 90c92121c7e7a342a64cd5609234ece1 |
| SSDEEP | 192:za3N5H44rW3ias7dUFdELQcsafdPvlw/BZUGJdMr0KqOMGb:zkasBUFuVsafVvlw/BLMcO9b |
| TLSH | T158325C52B6C040F5DB59D8F29D277B3924BE9E21632BE6D387340D680D9A942A73708F |
| File Type | Win32 EXE |
| Magic | PE32 executable (Intel 80386, MS Windows) |
| Architecture | x86 (32-bit) |
| File Size | 11.41 KB (11,680 bytes) |
| TrID Identification | Win32 DLL (34.3%), Win32 EXE (23.4%), Windows Icons Library (10.7%), OS/2 EXE (10.5%), Generic Win/DOS EXE (10.4%) |
| Detect It Easy | PE32, Compiler: MASM 7.01.4035, Linker: Microsoft Linker 7.10.4035 |
| Magika | PEBIN |
| PEiD Packer | Microsoft Visual C++ v7.1 EXE |
Sections
| Section Name | Virtual Address | Virtual Size (bytes) | Raw Size (bytes) | Entropy | MD5 | Chi-Square (Chi²) |
|---|---|---|---|---|---|---|
.text | 0x00000280 (640) | 8,904 | 8,928 | 6.52 | e9285367382d63f5e65445b78a688b5e | 49,665.19 |
.data | 0x00002560 (9,568) | 824 | 832 | 1.36 | 22b3dd607e91c85ddef807a0441042f4 | 154,013.02 |
INIT | 0x000028A0 (10,400) | 586 | 608 | 4.86 | 288e1b4ff839ac154cb20074ca668049 | 13,850.11 |
.reloc | 0x00002B00 (11,008) | 644 | 672 | 3.16 | 8a24633536aa0a73063171a85bac00b4 | 68,508.31 |
MITRE ATT&CK Tactics and Techniques
Fig 15 - MITRE
Sample Comparison – File Metadata and Hashes
| Attribute | 06665b96e293b23acc80451abb413e50 | 06665b96e293b23acc80451abb413e50.dec |
|---|---|---|
| MD5 | 06665b96e293b23acc80451abb413e50 | f8d94c86b15b62d5d76b9846fad5ae59 |
| SHA-1 | 9f0dc086875e6b06efe6bb3aadf049ce00f9e486 | 41a24d8697c06890cd0cf96ecb4ee30904ef5087 |
| SHA-256 | f1d903251db466d35533c28e3c032b7212aa43c8d64ddf8c5521b43031e69e1e | 23115663c967069cb482604700be9f7ed6df4ea1297d453debad1119b0f85b2e |
| Vhash | 0140466d7e5519z16z17xz | 0140466d1e5519z16z17xz |
| Authentihash | 139c80dde62a325f0ae2e2370b801e91caecef57dcf0ac2be7444e99341b9c92 | 8ccd332ab1c6585caafbb58fb31f03be285c8342ce32ff4a8df0120e50c72163 |
| Imphash | a9c1041cccb87f4a7ba3b7048d4e8ad7 | a9c1041cccb87f4a7ba3b7048d4e8ad7 |
| Rich PE Header Hash | 90c92121c7e7a342a64cd5609234ece1 | 90c92121c7e7a342a64cd5609234ece1 |
| SSDEEP | 192:za3N5H44rW3ias7dUFdELQcsafdPvlw/BZUGJdMr0KqOMwb:zkasBUFuVsafVvlw/BLMcOHb | 192:za3N5H44rW3ias7dUFdELQcsafdPvlw/BZUGJdMr0KqOMGb:zkasBUFuVsafVvlw/BLMcO9b |
| TLSH | T1C5325D22B6C140F5DA59D8F2AD3A7B39247FAD21633FE5D283340D691D6A841A73708F | T158325C52B6C040F5DB59D8F29D277B3924BE9E21632BE6D387340D680D9A942A73708F |
| File Type | Win32 EXE | Win32 EXE |
| Magic | PE32 executable (Intel 80386, MS Windows) | PE32 executable (Intel 80386, MS Windows) |
| Architecture | x86 (32-bit) | x86 (32-bit) |
| File Size | 11.41 KB (11,680 bytes) | 11.41 KB (11,680 bytes) |
| TrID Identification | Win32 DLL (34.3%), Win32 EXE (23.4%), Windows Icons Library (10.7%), OS/2 EXE (10.5%), Generic Win/DOS EXE (10.4%) | Same |
| Compiler / Linker | MASM 7.01.4035 / MS Linker 7.10.4035 | MASM 7.01.4035 / MS Linker 7.10.4035 |
| Magika | PEBIN | PEBIN |
| PEiD Packer | Microsoft Visual C++ v7.1 EXE | Microsoft Visual C++ v7.1 EXE |
Imported Kernel Functions
| Module | Imported Function |
|---|---|
| ntoskrnl.exe | _snprintf |
| ntoskrnl.exe | _strnicmp |
| ntoskrnl.exe | atoi |
| ntoskrnl.exe | ExAllocatePoolWithTag |
| ntoskrnl.exe | ExFreePool |
| ntoskrnl.exe | KeServiceDescriptorTable |
| ntoskrnl.exe | NtBuildNumber |
| ntoskrnl.exe | RtlAnsiStringToUnicodeString |
| ntoskrnl.exe | RtlFreeUnicodeString |
| ntoskrnl.exe | RtlInitAnsiString |
| HAL.dll | KeQueryPerformanceCounter |
IDA Analysis of Decrypted file
Fig 16 - Loading decrypted binary in IDA
Same Function DriverEntry , First block of data that was encrypted is now a readable registry location
Fig 17 - Registry location
We have two folders name supposedly two folder’s name
Fig 18 - recognizable strings
Both strings are used as an arguments to function
Fig 19 - arguments
Several templates like temp, windows
Fig 20 - templates(temp,windows)
This routine dynamically resolves kernel system call addresses by locating the base of ntoskrnl.exe and inspecting the System Service Descriptor Table. Execution is guarded to occur only once and includes explicit operating system version checks using NtBuildNumber, allowing the malware to adapt to different kernel layouts. By resolving system calls such as extended attribute handlers at runtime rather than importing them statically, the loader avoids detection and maintains compatibility across Windows versions. This behavior is characteristic of Regin’s highly defensive kernel-level architecture, where low-level system interaction is carefully abstracted and controlled.
Fig 21 - Function call