This program creates the service MalService
to ensure that
it runs every time the computer is started.
The program uses a mutex to ensure that only one copy of the program is running at a time.
We could search for a mutex named HGL345
and for the
service MalService
.
The malware uses the user-agent Internet Explorer 8.0 and communicates with www.malwareanalysisbook.com.
This program waits until midnight on January 1, 2100, and then sends many requests to http://www.malwareanalysisbook.com/, presumably to conduct a distributed denial-of-service (DDoS) attack against the site.
This program will never finish. It waits on a timer until the year 2100, and then creates 20 threads, each of which runs in an infinite loop.
The first step in analyzing this malware in depth is to open it with IDA Pro or a similar tool
to examine the imported function list. Many functions in the list provide little information because
they are commonly imported by all Windows executables, but a few stand out. Specifically OpenSCManager
and Crea
teService
indicate that this malware probably creates a service to ensure that it will
run when the computer is restarted.
The import of StartServiceCtrlDispatcherA
hints that this
file actually is a service. The calls to InternetOpen
and
InternetOpenUrl
tell us that this program might connect to a URL
to download content.
Next, we jump to the main function, which IDA Pro has identified and labeled _wmain
at location 0x401000. A quick glance at the code shows that
it’s short enough to analyze completely. The _wmain
function calls only one other function, as shown in the following listing. If the code were longer,
we would need to focus on only the most interesting function calls based on our review of the import
table.
00401003 lea eax, [esp+10h+ServiceStartTable] 00401007 mov [esp+10h+ServiceStartTable.lpServiceName], offset aMalservice ; "MalService" 0040100F push eax ; lpServiceStartTable 00401010 mov [esp+14h+ServiceStartTable.lpServiceProc], offset ❶sub_401040 00401018 mov [esp+14h+var_8], 0 00401020 mov [esp+14h+var_4], 0 00401028 call ❷ds:StartServiceCtrlDispatcherA 0040102E push 0 00401030 push 0 00401032 call sub_401040
This code begins with a call to StartServiceCtrlDispatcherA
at ❷. According to the MSDN documentation, this function
is used by a program to implement a service, and it is usually called immediately. The function
specifies the service control function that the service control manager will call. Here, it
specifies sub_401040
at ❶, which will be called after the call to StartServiceCtrlDispatcherA
.
This first portion of code, including the call to StartServiceCtrlDispatcherA
, is bookkeeping code that is necessary for programs that are
run as services. It doesn’t tell us what the program is doing, but it does tell us that it
expects to be run as a service.
Next, we examine the sub_401040
function, as shown in the
following listing.
00401040 sub esp, 400h 00401046 push offset Name ; ❷"HGL345" 0040104B push 0 ; bInheritHandle 0040104D push 1F0001h ; dwDesiredAccess 00401052 call ❶ds:OpenMutexA 00401058 test eax, eax 0040105A jz short loc_401064 0040105C push 0 ; uExitCode 0040105E call ds:ExitProcess
The first function call is to OpenMutexA
at ❶. The only thing of note is that this call is attempting to
obtain a handle to the named mutex HGL345
at ❷. If the call succeeds, the program exits.
The next call is shown in the following listing.
00401064 push esi 00401065 push offset Name ; ❷"HGL345" 0040106A push 0 ; bInitialOwner 0040106C push 0 ; lpMutexAttributes 0040106E call ❶ds:CreateMutexA
This code creates a mutex at ❶ named HGL345
❷. The combination of these two mutex calls is designed
to ensure that only one copy of this executable is running on a system at any given time. If a copy
was already running, then the first call to OpenMutexA
would have
been successful, and the program would have exited.
Next, the code calls OpenSCManager
, which opens a handle to
the service control manager so that the program can add or modify services. The next call is to the
GetModuleFileName
function, which returns the full pathname to
the currently running executable or a loaded DLL. The first parameter is a handle to the module for
which the name should be retrieved, or it is NULL to get the full pathname of the executable.
The full pathname is used by CreateServiceA
to create a new
service. The CreateServiceA
call has many parameters, but the key
ones are noted in the following listing.
0040109A push 0 ; lpPassword 0040109C push 0 ; lpServiceStartName 0040109E push 0 ; lpDependencies 004010A0 push 0 ; lpdwTagId 004010A2 lea ecx, [esp+414h+BinaryPathName] 004010A6 push 0 ; lpLoadOrderGroup 004010A8 push ❶ecx ; lpBinaryPathName 004010A9 push 0 ; dwErrorControl 004010AB push ❷2 ; dwStartType 004010AD push ❸10h ; dwServiceType 004010AF push 2 ; dwDesiredAccess 004010B1 push offset DisplayName ; "Malservice" 004010B6 push offset DisplayName ; "Malservice" 004010BB push esi ; hSCManager 004010BC call ds:CreateServiceA
The key CreateServiceA
parameters are BinaryPathName
at ❶, dwStartType
at ❷, and dwServiceType
at ❸. The binary
path to the executable is the same as the path to the currently running executable retrieved by the
GetModuleFileName
call. The GetModuleFileName
call is needed because the malware may not know its directory or
filename. By dynamically obtaining this information, it can install the service no matter which
executable is called or where it is stored.
The MSDN documentation lists valid entries for the dwServiceType
and dwStartType
parameters. For dwStartType
, the possibilities are SERVICE_BOOT_START
(0x00
), SERVICE_SYSTEM_START
(0x01
), SERVICE_AUTO_START
(0x02
), SERVICE_DEMAND_START
(0x03
), and SERVICE_DISABLED
(0x04
). The malware passed 0x02
, which corresponds to SERVICE_AUTO_START
, indicating that the service runs automatically on system
startup.
A lot of code manipulates time-related structures. IDA Pro has labeled a structure to be a
SYSTEMTIME
structure, which is one of several Windows time
structures. According to MSDN, the SYSTEMTIME
structure has
separate fields for the second, minute, hour, day, and so on, for use in specifying time. In this
case, all values are first set to 0, and then the value for the year is set to 0x0834
at ❶, or 2100 in
decimal. This time represents midnight on January 1, 2100. The program then calls SystemTimeToFileTime
between time formats.
004010C2 xor edx, edx
004010C4 lea eax, [esp+404h+DueTime]
004010C8 mov dword ptr [esp+404h+SystemTime.wYear], edx
004010CC lea ecx, [esp+404h+SystemTime]
004010D0 mov dword ptr [esp+404h+SystemTime.wDayOfWeek], edx
004010D4 push eax ; lpFileTime
004010D5 mov dword ptr [esp+408h+SystemTime.wHour], edx
004010D9 push ecx ; lpSystemTime
004010DA mov dword ptr [esp+40Ch+SystemTime.wSecond], edx
004010DE mov ❶[esp+40Ch+SystemTime.wYear], 834h
004010E5 call ds:SystemTimeToFileTime
Next, the program calls CreateWaitableTimer
, SetWaitableTimer
, and WaitForSingleObject
. The most important argument for our purposes is the lpDueTime
argument to SetWaitableTimer
.
The argument is the FileTime
returned by SystemTimeToFileTime
, as shown in the preceding listing. The code then uses WaitForSingleObject
to wait until January 1, 2100.
The code then loops 20 times, as shown in the following listing.
00401121 mov ❶esi, 14h 00401126 push 0 ; lpThreadId 00401128 push 0 ; dwCreationFlags 0040112A push 0 ; lpParameter 0040112C push ❺offset StartAddress ; lpStartAddress 00401131 push 0 ; dwStackSize 00401133 push 0 ; lpThreadAttributes 00401135 call ❹edi ; CreateThread 00401137 dec ❷esi 00401138 jnz ❸short loc_401126
Here, ESI is set at ❶ as the counter to 0x14 (20
in decimal). At the end of the loop, ESI is decremented at ❷, and when it hits zero at ❸, the loop
exits. A call to CreateThread
at ❹ has several parameters, but only one is important to us. The lpStartAddress
parameter at ❺ tells us which
function will be used as the start address for the thread—labeled StartAddress
in this case.
We double-click StartAddress
. We see that this function
calls InternetOpen
to initialize a connection to the Internet,
and then calls InternetOpenUrlA
from within a loop, which is
shown in the following code.
0040116D push 0 ; dwContext 0040116F push 80000000h ; dwFlags 00401174 push 0 ; dwHeadersLength 00401176 push 0 ; lpszHeaders 00401178 push offset szUrl ; ❸"http://www.malwareanalysisbook.com" 0040117D push esi ; hInternet 0040117E ❷call edi ; InternetOpenUrlA 00401180 ❶jmp short loc_40116D
The jmp
instruction at the end of the loop at
❶ is an unconditional jump, which means that the code
will never end; it will call InternetOpenUrlA
❷ and download the home page of www.malwareanalysisbook.com
❸ forever. And because CreateThread
is called 20 times, 20 threads will call InternetOpenUrlA
forever. Clearly, this malware is designed to launch a DDoS attack by
installing itself on many machines. If all of the infected machines connect to the server at the
same time (January 1, 2100), they may overload the server and make it impossible to access the
site.
In summary, this malware uses mutexes to ensure that only one copy is running at a time, creates a service to ensure that it runs again when the system reboots, waits until January 1, 2100, and then continues to download www.malwareanalysisbook.com indefinitely.
Note that this malware doesn’t perform all of the functions required of a service.
Normally, a service must implement functions to be stopped or paused, and it must change its status
to let the user and OS know that the service has started. Because this malware does none of this,
its service’s status will always display START_PENDING
, and
the service cannot be stopped while it is running. Malware often implements just enough
functionality to achieve the author’s goals, without bothering to implement the entire
functionality required by the specification.