While testing malware recently, we got some logs from our automated analysis system showing a few samples that are only partially replicated. We have heuristics that predict the behavior of a sample; but if that prediction fails, then the heuristics identify the state of a sample and decide if it is worth sending to our second level of analysis. We took a close look at all the samples that were sent to the second level and found some interesting and strange behavior. We noticed that some samples behave differently when executed by a process that runs in background, without a window, compared with a process that execute samples with a visible window. To demonstrate, let’s take a look at the following example.
We executed the sample manually by double-clicking the executable as well as using the command prompt. Everything worked fine; we can see the running process in Process Explorer.
However, when we ran the same malware sample via a console-based application that started the malware process in suspended mode, it injected a DLL into the malware and terminated itself after resuming the malware process. Although we assume the malware is supposed to do more, it simply terminated without an error.
We further investigated the malware sample and suspect that it may need to check its parent process window before doing further activities. This behavior may not be intentional and seems to be an accidental event.
We ran the same sample again in a console-based application, but this time we made some minor modifications, such as adding sleep for couple of seconds after the ResumeThread. The malware sample ran accordingly:
Looking at the code, we saw a deviation in execution flow when the malware sample was executed by a process with a window or without a window.
The following code is responsible for the deviation. In each case, the sample used different arguments to CallWindowProcA API.
Loop:
RETURN ADDRESS: 0x00431962 CALL FUNCTION: USER32!CallNextHookEx
RETURN ADDRESS: 0x004391e7 CALL FUNCTION: KERNEL32!EnterCriticalSection
RETURN ADDRESS: 0x004391fb CALL FUNCTION: KERNEL32!TlsGetValue
RETURN ADDRESS: 0x00439211 CALL FUNCTION: KERNEL32!LeaveCriticalSection
RETURN ADDRESS: 0x004391e7 CALL FUNCTION: KERNEL32!EnterCriticalSection
RETURN ADDRESS: 0x004391fb CALL FUNCTION: KERNEL32!TlsGetValue
RETURN ADDRESS: 0x00439211 CALL FUNCTION: KERNEL32!LeaveCriticalSection
RETURN ADDRESS: 0x004391e7 CALL FUNCTION: KERNEL32!EnterCriticalSection
RETURN ADDRESS: 0x004391fb CALL FUNCTION: KERNEL32!TlsGetValue
RETURN ADDRESS: 0x00439211 CALL FUNCTION: KERNEL32!LeaveCriticalSection
RETURN ADDRESS: 0x0043a215 CALL FUNCTION: KERNEL32!EnterCriticalSection
RETURN ADDRESS: 0x0043a22b CALL FUNCTION: KERNEL32!InitializeCriticalSection
RETURN ADDRESS: 0x0043a238 CALL FUNCTION: KERNEL32!LeaveCriticalSection
RETURN ADDRESS: 0x0043a244 CALL FUNCTION: KERNEL32!EnterCriticalSection
RETURN ADDRESS: 0x0043a26c CALL FUNCTION: KERNEL32!LeaveCriticalSection
RETURN ADDRESS: 0x0042e009 CALL FUNCTION: USER32!CallWindowProcA
The message argument to CallWindowProcA when the sample was executed by a background process (without a window):
0012F088 00000081 |Message = WM_NCCREATE
0012F0D4 00000083 |Message = WM_NCCALCSIZE
0012F088 00000001 |Message = WM_CREATE
0012F0E0 00000005 |Message = WM_SIZE
0012F0E0 00000003 |Message = WM_MOVE
0012F548 00000030 |Message = WM_SETFONT
0012EE98 00000002 |Message = WM_DESTROY
0012EE98 00000082 |Message = WM_NCDESTROY
After the foregoing, the sample process terminated itself.
The message argument to CallWindowProcA when the sample was executed by a process with a visible window:
0012F088 00000081 |Message = WM_NCCREATE
0012F0D4 00000083 |Message = WM_NCCALCSIZE
0012F088 00000001 |Message = WM_CREATE
0012F0E0 00000005 |Message = WM_SIZE
0012F0E0 00000003 |Message = WM_MOVE
0012F548 00000030 |Message = WM_SETFONT
0012EE98 00000055 |Message = WM_NOTIFYFORMAT
0012EE98 00000129 |Message = WM_QUERYUISTATE
This sample runs nicely, without any problems.
We have not seen this type of behavior in any medium- or high-severity malware. The samples we analyzed showing this behavior are mostly installers for adware or spyware.
I thank my colleagues Benjamin Cruz and Vikas Taneja for their advice and assistance.