WlxLoggedOutSAS
export of fsgina.dll.Standard pwdump uses the DLL lsaext.dll. Once it is running inside lsass.exe, pwdump calls GetHash
, which is exported by lsaext.dll in order to perform the hash extraction. This extraction uses undocumented Windows function calls to enumerate the users on a system and get the password hashes in unencrypted form for each user.
When dealing with pwdump variants, you will need to analyze DLLs in order to determine how the hash dumping operates. Start by looking at the DLL’s exports. The default export name for pwdump is GetHash
, but attackers shows the code in the exported function GrabHash
from a pwdump variant DLL. Since this DLL was injected into lsass.exe, it must manually resolve numerous symbols before using them.
LoadLibrary
at ❶ and ❷. Samsrv.dll contains an API to easily access the SAM, and advapi32.dll is resolved to access functions not already imported into lsass.exe. The pwdump variant DLL uses the handles to these libraries to resolve many functions, with the most important five shown in the listing (look for the GetProcAddress
calls and parameters).The interesting imports resolved from samsrv.dll are SamIConnect
, SamrQueryInformationUser
, and SamIGetPrivateData
. Later in the code, SamIConnect
is used to connect to the SAM, followed by calling SamrQueryInformationUser
for each user on the system.
The hashes will be extracted with SamIGetPrivateData
and decrypted by SystemFunction025
and SystemFunction027
, which are imported from advapi32.dll, as seen at ❸ and ❹. None of the API functions in this listing are documented by Microsoft.
shows code from a whosthere-alt variant that exports a function named TestDump
.
We’ll focus on polling keyloggers that use GetAsyncKeyState
and GetForegroundWindow
. The GetAsyncKeyState
function identifies whether a key is pressed or depressed, and whether the key was pressed after the most recent call to GetAsyncKeyState
. The GetForegroundWindow
function identifies the foreground window—the one that has focus—which tells the keylogger which application is being used for keyboard entry (Notepad or Internet Explorer, for example).
illustrates a typical loop structure found in a polling keylogger. The program begins by calling GetForegroundWindow
, which logs the active window. Next, the inner loop iterates through a list of keys on the keyboard. For each key, it calls GetAsyncKeyState
to determine if a key has been pressed. If so, the program checks the SHIFT and CAPS LOCK keys to determine how to log the keystroke properly. Once the inner loop has iterated through the entire list of keys, the GetForegroundWindow
function is called again to ensure the user is still in the same window. This process repeats quickly enough to keep up with a user’s typing. (The keylogger may call the Sleep
function to keep the program from eating up system resources.)
Example 11-4. Disassembly of GetAsyncKeyState
and GetForegroundWindow
keylogger
00401162 call ds:GetForegroundWindow ... 00401272 push 10h ❶ ; nVirtKey Shift 00401274 call ds:GetKeyState 0040127A mov esi, dword_403308[ebx] ❷ 00401280 push esi ; vKey 00401281 movsx edi, ax 00401284 call ds:GetAsyncKeyState 0040128A test ah, 80h 0040128D jz short loc_40130A 0040128F push 14h ; nVirtKey Caps Lock 00401291 call ds:GetKeyState ... 004013EF add ebx, 4 ❸ 004013F2 cmp ebx, 368 004013F8 jl loc_401272
The program calls GetForegroundWindow
before entering the inner loop. The inner loop starts at ❶ and immediately checks the status of the SHIFT key using a call to GetKeyState
. GetKeyState
is a quick way to check a key status, but it does not remember whether or not the key was pressed since the last time it was called, as GetAsyncKeyState
does. Next, at ❷ the keylogger indexes an array of the keys on the keyboard using EBX. If a new key is pressed, then the keystroke is logged after calling GetKeyState
to see if CAPS LOCK is activated. Finally, EBX is incremented at ❸ so that the next key in the list can be checked. Once 92 keys (368/4) have been checked, the inner loop terminates, and GetForegroundWindow
is called again to start the inner loop from the beginning.
You can recognize keylogger functionality in malware by looking at the imports for the API functions, or by examining the strings listing for indicators, which is particularly useful if the imports are obfuscated or the malware is using keylogging functionality that you have not encountered before. For example, the following listing of strings is from the keylogger described in the previous section:
[Up] [Num Lock] [Down] [Right] [UP] [Left] [PageDown]
If a keylogger wants to log all keystrokes, it must have a way to print keys like PAGE DOWN, and must have access to these strings. Working backward from the cross-references to these strings can be a way to recognize keylogging functionality in malware.