The program is a keylogger.
The program uses hook injection to steal keystrokes.
The program creates the file practicalmalwareanalysis.log to store the keystrokes.
Since we’ve already analyzed this binary in the labs for Chapter 3, and it was extracted as part of Lab 12-2 Solutions, let’s begin by opening the file with IDA Pro to examine the
function imports. The most interesting of the imports is SetWindowsHookExA, an API that allows an application to hook or monitor events within
Microsoft Windows.
In Example C-76, we see that SetWindowsHookExA is called from main at ❶. The MSDN documentation shows that the first parameter, 0Dh, corresponds to WH_KEYBOARD_LL,
which enables monitoring of keyboard events using the hook function IDA Pro labeled fn at ❷. The program is
probably doing something with keystrokes. The fn function will
receive keystrokes.
Example C-76. SetWindowsHookEx called from main
00401053 push eax ; hmod 00401054 push offset fn ❷ ; lpfn 00401059 push 0Dh ; idHook 0040105B call ds:SetWindowsHookExA ❶ 00401061 mov [ebp+hhk], eax
After registering to receive keyboard events, the program calls GetMessageA in a loop that starts at 0x00401076. The program must call GetMessageA; otherwise, Windows would not deliver the messages to the
process’s hook function. The loop runs until it produces an error.
Navigating to the function fn, we begin to see what the
program is doing with the keystrokes it captures. fn is a generic
function with three parameters. It has a prototype defined by HOOKPROC. Using the MSDN documentation, we determine that WH_KEYBOARD_LL callbacks are actually LowLevelKeyboardProc callbacks. We use this information to resolve the parameters to
actual data structures, which makes our job easier by allowing us to read names rather than numeric
offsets.
To change the IDA display from offsets to names, put the cursor at 0x00401086 and press the Y
key, and then change lParam’s type to KBDLLHOOKSTRUCT *. You can now go to 0x4010a4, and hit the T key and select
KBDLLHOOKSTRUCT.vkCode. The references to lParam should now show structure variable names rather than numeric
offsets. For example, [eax] at 0x004010A4 becomes [eax+KBDLLHOOKSSTRUCT.vkCode], as shown in Example C-77
at ❸.
Example C-77. Hook function
0040108F cmp [ebp+wParam], WM_SYSKEYDOWN ❶
00401096 jz short loc_4010A1
00401098 cmp [ebp+wParam], WM_KEYDOWN ❷
0040109F jnz short loc_4010AF
004010A1
004010A1 loc_4010A1: ; CODE XREF: fn+10j
004010A1 mov eax, [ebp+lParam]
004010A4 mov ecx, [eax+KBDLLHOOKSTRUCT.vkCode] ❸
004010A6 push ecx ; Buffer
004010A7 call sub_4010C7In Example C-77, we see at ❶
and ❷ that the program checks the type of keypress with
cmp, in order to process each keypress once. At ❸, the program passes (mov) the
virtual key code to the function sub_4010C7 shown later in
bold.
Examining sub_4010C7, we see that first the program opens a
file, practicalmalwareanalysis.log. After this, the malware calls GetForegroundWindow followed by GetWindowTextA, as shown in Example C-78.
First, GetForegroundWindow selects the active window when the key
was pressed, and then it grabs the title of the window using GetWindowTextA. This helps the program provide context for where the keystrokes
originated.
Example C-78. Opening the log file and getting the window title
004010E6 push offset FileName ; "practicalmalwareanalysis.log" 004010EB call ds:CreateFileA ... 0040110F push 400h ; nMaxCount 00401114 push offset String ; lpString 00401119 call ds:GetForegroundWindow0040111F push eax ; hWnd 00401120 call ds:GetWindowTextA00401126 push offset String ; Str2 0040112B push offset Dest ; Str1 00401130 call _strcmp
Once the program writes the window title to the log file, it enters a large jump table, as
shown in Example C-79 at ❶. Recognizing that var_C contains the virtual key
code that was passed into the function, we see the virtual key code used as an index to a lookup
table at ❷. The value received from the lookup table is
used as an index into the jump table off_401441 at ❶.
Example C-79. Virtual key code jump table
0040120B sub eax, 8 ❸ ... 0040121B mov edx, [ebp+var_C] 0040121E xor ecx, ecx 00401220 mov cl, ds:byte_40148D[edx]❷ 00401226 jmp ds:off_401441[ecx*4] ❶ ; switch jump
We follow the lookup process by choosing a value like VK_SHIFT (0x10). At ❸, 8 is subtracted from
the value, leaving us with 0x8 (0x10 – 0x8).
Looking at offset 0x8 into byte_40148D, as shown in Example C-80, provides the value 3, which is stored in ECX. ECX
is then multiplied by 4 at ❶, yielding 0xC, which is
used as an offset into off_401441. This returns the location
loc_401249, where we find the string [SHIFT] written to the log file.
Example C-80. The offset table for byte_40148D
byte_40148D db 0, 1, 12h, 12h
db 12h, 2, 12h, 12h
db 3, 4, 12h, 12hWe are able to conclude that this malware is a keylogger that logs keystrokes to the file
practicalmalwareanalysis.log. This keylogger uses SetWindowsHookEx to implement its keylogging functionality.