The Slingshot APT – kernel injecting trojan found in the wild by kaspersky

originally taken from her:



Ring0 loader This loader is compressed in module_id 0xBF000001. Actually, there might be more than one, so in case the first loader fails, there may be a second loader in the binary with module_id 0xBF000002. At this stage, Slingshot uses its internal logging system actively:

Slingshot checks if there is any kernel-mode payload and any loader available, and then the loaders are run one after the other. Upon starting, this loader gets SeLoadDriverPrivilege for installing malicious drivers into the system that it will later abuse for obtaining kernel privileges. In order to avoid leaving any traces of this activity in system logs, it renames the ETW-logs, and for the Security and System logs adds the .tmp extension. After execution, the loader removes the extensions. The final goal of this module is to load the Cahnadr module (kernel mode main payload, described below) into kernel mode. As previously stated, Slingshot has different ways to load code into kernel mode, each using its own loader. The simplest loader is used for 32-bit systems where Driver Signature Enforcement (DSE), which requires signed drivers, does not apply. This loader simply saves the driver on disk and loads it. When the driver is loaded, the loader shares the malicious payload with it by calling DeviceIoControl with control code 0x222000. This driver receives commands from the user-mode loader via DeviceIoControl. The only available command in this case allows running this code as a WorkItem into the System Worker Threads pool, which is a pool used by legitimate software for running quick tasks


In cases where the operating system supports DSE, the loader exploits a couple of legitimate but vulnerable drivers that allow writing in MSR registers. Successful exploitation of the drivers would allow to set in the MSR_LSTAR register a handler that, after running Sleep, calls Cahnadr


In order to prevent patch protection, the handler restores the original MSR register. This loader leverages the following drivers: 312E31851E0FC2072DBF9A128557D6EF Goad.sys – driver for x86 systems 5F9785E7535F8F602CB294A54962C9E7 SpeedFan.sys – CVE-2007-5633 9a237fa07ce3ed06ea924a9bed4a6b99 Sandra.sys – CVE-2010-1592 978CD6D9666627842340EF774FD9E2AC ElbyCDIO.sys – CVE-2009-0824 It is important to mention that the digital signatures in these drivers are still not revoked. All the drivers above are loaded into the kernel directly by creating the required keys in the registry and calling the ntdll!NtLoadDriver function. The service key name in the registry starts with the PCX* prefix.


Cahnadr – main kernel-mode payload This payload can be considered the main orchestrator, running in kernel mode and providing the necessary capabilities for all the other, user-mode payloads. This component is responsible for different features, including: 1. Anti-debugging actions and checking if the kernel is patched or not 2. Calling system services directly to hide malicious activities 3. Hooks KTHREAD.ServiceTable for threads 4. Rootkit actions for hiding traffic 5. Injecting user-mode payload (main malicious payload) into services.exe 6. Providing malicious API for user-mode modules 7. Providing communications via network 8. Notifying GollumApp payload about process-related events, providing interfaces for manipulating their memory 9. Monitoring all network devices 10. Providing sniffer functionality on the following protocols: ARP, TCP, UDP, DNS, ICMP, HTTP Anti-debug techniques include: • If kernel is already being debugged, it calls KdDisableDebugger() terminating the debugging process • It hooks LiveKd debugger driver’s routines IRP_MJ_CREATE, IRP_MJ_READ, FastIoDeviceControl • Installs notifiers to monitor PsSetLoadImageNotifyRoutine. If the LoadImageNotify event happens when LiveKdD.sys is loaded, the module patches the entry point that leads to error STATUS_FAILED_DRIVER_ENTRY In order to detect if the kernel is patched, it checks the kernel image in memory with the following kernel files on disk: • \\SystemRoot\\system32\\kernel_name • \\SystemRoot\\LastGood\\system32\\kernel_name • \\SystemRoot\\$*\\system32\\kernel_name For newer x32 versions it also checks win32k.sys at the same paths. It is important to note that Cahnadr checks only CheckSum and TimeStamp values for the kernel image in memory. If one of them is different, it means that the kernel was patched, and it terminates its execution. Actually, it needs an unpatched kernel and win32k.sys to get the origin function from KeServiceDescriptorTable and KeServiceDescriptorTableShadow, which will be used to directly interact with system services and hooking the KTHREAD.ServiceTable on x32 systems. In order to hide calls, it can associate system services to some Zw*, Rtl*, Nt* functions. Instead of taking the addresses for these functions from SSDT, Cahnadr extracts them from the kernel image on disk for unpatched kernels. It also implements code to find a function address by its name by comparing exported routines from ntdll and ntoskrnl addresses: if the address of the exported functions is the same as the system service address, it means the address was correctly found. Ntdll.dll exported functions addresses are also taken from the image stored on disk to avoid hooks set by other programs.


Not all functions are mandatory to be found, there is a flag for each of them. All listed routines are used for injecting malicious code into user-mode processes. For newer x32 versions this list was highly extended, adding debug-related functions and functions for suspending and resuming threads and processes. For x32 systems, Cahnadr hooks KTHREAD.ServiceTable. It copies the KeServiceDescriptorTable and KeServiceDescriptorTableShadow, then fills it with the original handlers restored from disk and changes the address in KTHREAD.ServiceTable to pointer to a new structure. This is used to inject threads into user mode: once a component is injected as a separate thread, Cahnadr patches its KTHREAD.ServiceTable with the original handlers in order to hide its malicious functionality and avoid possible installed hooks. Cahnadr also provides the following API functionality: • Direct disk access: read/write by raw-offset, defragmentation ban, etc. These routines are used for working with the virtual file system • Read/write into memory by raw address • Routines for injecting code into a process as a separate thread. It is possible to set the thread state and choose the preferred routine for creating the thread (NtCreateThreadEx or NtCreateThread). For GollumApp it is obligatory to use NtCreateThread • Get the access token by process_id • Get the SERVICE_DESCRIPTOR_TABLE address • Get the DRIVER_OBJECT object pointer by driver name • Get detailed information about processes opened in csrss.exe (start time, time in kernel mode, time in user mode, number of calls ZwRead and ZwWrite, among of data received/sent via ZwRead/ZwWrite) • Get handle for process_1 in process_2. In other words, opens process_1 from process_2. This way process_2 gets the handle of process_1 • Close handle that belongs to any process • Provides network functionality: add a new network-related task, delete an old one, turn on/off a network task, send information about all active network tasks to GollumApp • Hooks the ServiceTable in KTHREAD in the specified thread or process (only on x32), providing: setting/deleting a hook by ThreadID, setting/deleting hook for all threads by PID, checking if thread/process was hooked • Sets time to sleep before shutdown Cahnadr calls PsSetCreateProcessNotifyRoutine, PsSetCreateThreadNotifyRoutine routines in order to automate installing hooks. Created processes will be hooked if their parent process was hooked, as will threads if their process was hooked. Shutdown notifications are detected by calling the IoRegisterShutdownNotification routine. When a notification is received, it is sent to GollumApp with the time that GollumApp can spend for completion. While GollumApp works, Cahnadr sleeps. It installs bugcheck notifications by calling the KeRegisterBugCheckReasonCallback routine. When a notification is received it calls KeBugCheck with the undocumented POWER_FAILURE_SIMULATE parameter, which is a way to reboot from kernel mode without BSOD and crush dump. This way, in case a fatal error occurs, Cahnadr reboots the system without creating a memory dump on disk. The communication between kernel and user mode modules is implemented in different ways for x32 and x64 components. In x64 components Cahnadr sets IRP-requests handlers for the ‘null.sys’ driver. Each handler contains a ‘jmp’ operation to the malicious code located in the ‘null.sys’ image in memory. This is how hooks are typically set in this APT, making them harder to detect.


However malicious and legitimate IRP-handlers have a conflicting component, as both null.sys and Cahnadr can process requests to IRP-MJ-CLOSE. That’s why only one hook and three ordinary handlers are set. After that, user mode modules can send data to Cahnadr by calling CreateFile(\\\\.\\NUL, …) + DeviceIoControl. In x32 components another approach was used. Cahnadr registers a RegistryCallback routine by calling CmRegisterCallback to monitor all operations in the registry. When any user mode module sends something to Cahnadr it sets the ArbitraryUserPointer field of the TIB pointer to the related data, starting with 0x2BADDOOD, and then calls RegEnumKeyW which triggers the kernel mode callback..


Cahnadr hooks the following routines in order to hide its traffic, perform different tasks and provide additional functionality for the user mode components: • ndis!NdisMSendNetBufferListsComplete • ndis!NdisMIndicateReceiveNetBufferLists These routines are callbacks run by network drivers to notify handlers with all data sent or received. The function lists in PNET_BUFFER_LIST all packets and their related event. Cahnadr checks if there are Slingshot-related packets in this list, and if so, removes them. Let´s explain this in more detail: The trick is that all the malware is allocated to a particular pool that allows discriminating it from other benign calls. NdisAllocateNetBufferListPool creates NET_BUFFER_LIST, that is initialized calling NdisAllocateNetBufferAndNetBufferList. When the network driver sends data, it gets into such a NET_BUFFER structure, which in turn, gets into NET_BUFFER_LIST. The callbacks routine NdisMSendNetBufferListsComplete, that gets the NET_BUFFER_LISTs with data successfully sent, is hooked. Malware simply checks if any entry in NET_BUFFER_LIST was allocated from the malware pool and, if so, will simply not return it to the original handler. This sniffer has a list of tasks, each one associated with a list of handlers. Inbound and outbound packets are examined and passed to the appropriate task’s processor, which calls all handlers associated with the task. The result determines whether malware should hide the package. We have seen three types of task: HTTP: This is the only handler that notifies GollumApp (user mode payload, described below) that HTTP data is being transferred. ARPf: (two handlers for this type). The first one notifies GollumApp when an ARP-request is received and/or when an ARP-response is sent. The second one stores this information in its internal storage, collecting information about the network structure. This task is enabled by default. IP2f: (two handlers of this type). The first one checks if the package comes from the malware operators, only to decide whether the package should be hidden. This is decided by XORing two Timestamps values from the Options field in the TCP-header (RFC1323, code 0x080A). If the result is equal to 0xDEADFOOD then this package should be hidden. The second one notifies GollumApp that some TCP/UDP or ICMP packets that suit malicious filters were found. For instance, for TPC traffic this filter uses the same described XOR procedure with the constant 0xDADAE000, sending GollumApp the seqNumber, askNumber and src port values. For UDP, packets with a length of 0x55 bytes containing DNS responses, it checks that the field dns.Identifier equals 0x212. In that case, the packet is hidden and GollumApp is notified with the resolved IP and TTL of the packet. For ICMP, packets containing the «Destination port unreachable» error it checks that the overlying protocol contains the constant 0xE17F (57727). In that case, GollumApp is notified with ip.Destination, ip.identification, ip.length. This task is enabled by default. The malware identifies HTTP traffic by checking the ASK flag in TCP protocol, and by finding the HTTP signature in the TCP package body. This task is disabled by default, however GollumApp can enable it. Additionally, this kernel mode module provides the following functionality for user mode components: • ARP-query: obtains the MAC-address for a specified IP address. Requires network interface as a parameter • ARP-reply: sends its own MAC address as a response to a specified ARP-request, regardless of whether the IP from the request and the infected computer are the same or not • Sends custom network package, where all fields can be customized from the Ethernet-layer • Sends custom IPV4 package Cahnadr supports IEEE 802.11 standard, allowing it to operate with WiFi frames. Network interfaces are traced using Plug-and-Play notifications with EventCategory – PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES. When a network interface change event happens, all hooks listed above apply and Cahnadr checks the category of the new interface (bridge/wan/lan). Depending on the type of interface, it gets different data that is written in thee malware´s storage: • Ethernet: MAC-address and maximum frame size • Wireless (802.11) Access Point MAC-address and authentication state

Zeus Analysis in Volatility 2.0

Well I wanted to post another article about memory forensics with my favorite open source tool right now…. Volatility.  Can’t say enough great things about the documentation (very well written and expansive) and the community is very helpful in answering questions (even noobish ones).  So after I read MHL’s Stuxnet Analysis with Volatility 2.0 it inspired me to do my own sort of analysis with a different piece of malware to see how many artifacts I could come up with.  I’ll be referencing some in-depth deep dives to confirm the analysis.  At the end of the article the links will be given to those reports in full.  I’m going to assume no prior knowledge is known about Zeus.  We can use Volatility to start as well as confirm with multiple artifacts we are in fact infected with Zeus beyond any doubts.

Luckily for us we don’t have to infect a VM, take a memory dump and then analyze it (or have a friend ask for our help to cleanup their computer like here).  The folks at Volatilityhave provided a sample image that’s infected with Zeus for you to practice on.  They are in need of contribution with additional malware if you have any laying around that you’d like to share.  So download the image and follow along.

C:\RE\volatility2.0\py\volatility-2.0>python -f zeus.vmem imageinfo
Volatile Systems Volatility Framework 2.0
Suggested Profile(s) : WinXPSP3x86, WinXPSP2x86 (Instantiated with Win
AS Layer1 : JKIA32PagedMemoryPae (Kernel AS)
AS Layer2 : FileAddressSpace (C:\RE\volatility2.0\py\volatility-2.0\zeus.vmem)
PAE type : PAE
DTB : 0x319000
KDBG : 0x80544ce0L
KPCR : 0xffdff000L
Image date and time : 2010-08-15 19:17:56
Image local date and time : 2010-08-15 19:17:56
Number of Processors : 1
Image Type : Service Pack 2

So we can tell this is a XP SP2 image, no big surprise here.  Let’s grab a process listing.

C:\RE\volatility2.0\py\volatility-2.0>python -f zeus.vmem pslist
Volatile Systems Volatility Framework 2.0
Offset(V)  Name                 PID    PPID   Thds   Hnds   Time
---------- -------------------- ------ ------ ------ ------ -------------------
0x810b1660 System                    4      0     58    379 1970-01-01 00:00:00
0xff2ab020 smss.exe                544      4      3     21 2010-08-11 06:06:21
0xff1ecda0 csrss.exe               608    544     10    410 2010-08-11 06:06:23
0xff1ec978 winlogon.exe            632    544     24    536 2010-08-11 06:06:23
0xff247020 services.exe            676    632     16    288 2010-08-11 06:06:24
0xff255020 lsass.exe               688    632     21    405 2010-08-11 06:06:24
0xff218230 vmacthlp.exe            844    676      1     37 2010-08-11 06:06:24
0x80ff88d8 svchost.exe             856    676     29    336 2010-08-11 06:06:24
0xff217560 svchost.exe             936    676     11    288 2010-08-11 06:06:24
0x80fbf910 svchost.exe            1028    676     88   1424 2010-08-11 06:06:24
0xff22d558 svchost.exe            1088    676      7     93 2010-08-11 06:06:25
0xff203b80 svchost.exe            1148    676     15    217 2010-08-11 06:06:26
0xff1d7da0 spoolsv.exe            1432    676     14    145 2010-08-11 06:06:26
0xff1b8b28 vmtoolsd.exe           1668    676      5    225 2010-08-11 06:06:35
0xff1fdc88 VMUpgradeHelper        1788    676      5    112 2010-08-11 06:06:38
0xff143b28 TPAutoConnSvc.e        1968    676      5    106 2010-08-11 06:06:39
0xff25a7e0 alg.exe                 216    676      8    120 2010-08-11 06:06:39
0xff364310 wscntfy.exe             888   1028      1     40 2010-08-11 06:06:49
0xff38b5f8 TPAutoConnect.e        1084   1968      1     68 2010-08-11 06:06:52
0x80f60da0 wuauclt.exe            1732   1028      7    189 2010-08-11 06:07:44
0xff3865d0 explorer.exe           1724   1708     13    326 2010-08-11 06:09:29
0xff3667e8 VMwareTray.exe          432   1724      1     60 2010-08-11 06:09:31
0xff374980 VMwareUser.exe          452   1724      8    207 2010-08-11 06:09:32
0x80f94588 wuauclt.exe             468   1028      4    142 2010-08-11 06:09:37
0xff224020 cmd.exe                 124   1668      0 ------ 2010-08-15 19:17:55

Nothing immediately stands out to me as they all look like legitimate processes that are running on the box.  Let’s see if any of them are hiding with a new command fresh out of 2.0 which is psxview.

C:\RE\volatility2.0\py\volatility-2.0>python -f zeus.vmem psxview
Volatile Systems Volatility Framework 2.0
Offset       Name                 Pid      pslist     psscan     thrdproc   psp
id     csr_hnds   csr_list
0x80fbf910L  svchost.exe          1028     1          1          1          1
1          0
0x80ff88d8L  svchost.exe          856      1          1          1          1
1          0
0xff1d7da0L  spoolsv.exe          1432     1          1          1          1
1          0
0x80f60da0L  wuauclt.exe          1732     1          1          1          1
1          0
0xff2ab020L  smss.exe             544      1          1          1          1
0          0
0xff3667e8L  VMwareTray.exe       432      1          1          1          1
1          0
0xff247020L  services.exe         676      1          1          1          1
1          0
0xff217560L  svchost.exe          936      1          1          1          1
1          0
0xff143b28L  TPAutoConnSvc.e      1968     1          1          1          1
1          0
0xff203b80L  svchost.exe          1148     1          1          1          1
1          0
0xff1b8b28L  vmtoolsd.exe         1668     1          1          1          1
1          0
0xff255020L  lsass.exe            688      1          1          1          1
1          0
0xff3865d0L  explorer.exe         1724     1          1          1          1
1          0
0xff22d558L  svchost.exe          1088     1          1          1          1
1          0
0xff374980L  VMwareUser.exe       452      1          1          1          1
1          0
0xff1fdc88L  VMUpgradeHelper      1788     1          1          1          1
1          0
0xff218230L  vmacthlp.exe         844      1          1          1          1
1          0
0xff364310L  wscntfy.exe          888      1          1          1          1
1          0
0x80f94588L  wuauclt.exe          468      1          1          1          1
1          0
0xff25a7e0L  alg.exe              216      1          1          1          1
1          0
0xff1ecda0L  csrss.exe            608      1          1          1          1
0          0
0xff38b5f8L  TPAutoConnect.e      1084     1          1          1          1
1          0
0xff1ec978L  winlogon.exe         632      1          1          1          1
1          0
0xff224020L  cmd.exe              124      1          0          0          1
0          0
0x810b1660L  System               4        1          1          1          1
0          0

This uses multiple methods for looking at processes artifacts in memory.  If you see any that are 0’s for psscan, pslist and thrdproc it’s an attempt to hide the process by DKOM (Direct Kernel Object Manipulation).  Nothing interesting here so let’s see about some network connections.

C:\RE\volatility2.0\py\volatility-2.0>python -f zeus.vmem connections
Volatile Systems Volatility Framework 2.0
Offset(V)  Local Address             Remote Address            Pid
---------- ------------------------- ------------------------- ------

Well that’s disappointing.  No active connections at the time the memory dump was taken.  Let’s go a little deeper and scan for connections that may have been previously closed with connscan.

C:\RE\volatility2.0\py\volatility-2.0>python -f zeus.vmem connscan
Volatile Systems Volatility Framework 2.0
Offset     Local Address             Remote Address            Pid
---------- ------------------------- ------------------------- ------
0x02214988             856
0x06015ab0                 856

Bingo!  We have 2 connections here that look to be listed to PID 856.  That’s SVChost which is odd.  Let’s see where these connections are located.  A whois report reveals that the IP is located in Moldova.

IP Address
Location MD MD, Moldova, Republic of
City -, – –
Organization PE Voronov Evgen Sergiyovich
ISP PE Voronov Evgen Sergiyovich

It’s well known that a lot of malware calls Eastern Europe and Asia home.  So this is pretty suspicious but since it looks like all our processes appear legitimate we might be facing some malware that utilizes code injection.  To detect these types of processes MHL has released a great plugin here that utilizes malfind.  It will detect injected processes so let’s run that on our target image.

C:\RE\volatility2.0\py\volatility-2.0>python -f zeus.vmem malfind --dump-dir c:\re\zeus_demo
VMwareTray.exe       432    0x00d70000 0xd95fff00 VadS     0      PAGE_EXECUTE_R
Dumped to: c:\re\zeus_demo\VMwareTray.exe.4be97e8.00d70000-00d95fff.dmp
0x00d70000   4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00    MZ..............

0x00d70010   b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00    ……..@…….

0x00d70020   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    …………….

0x00d70030   00 00 00 00 00 00 00 00 00 00 00 00 d0 00 00 00    …………….

0x00d70040   0e 1f ba 0e 00 b4 09 cd 21 b8 01 4c cd 21 54 68    ……..!..L.!Th

0x00d70050   69 73 20 70 72 6f 67 72 61 6d 20 63 61 6e 6e 6f    is program canno

0x00d70060   74 20 62 65 20 72 75 6e 20 69 6e 20 44 4f 53 20    t be run in DOS

0x00d70070   6d 6f 64 65 2e 0d 0d 0a 24 00 00 00 00 00 00 00    mode….$…….

VMwareTray.exe       432    0x00e30000 0xe30fff00 VadS     0      PAGE_EXECUTE_R
Dumped to: c:\re\zeus_demo\VMwareTray.exe.4be97e8.00e30000-00e30fff.dmp
0x00e30000   b8 35 00 00 00 e9 cd d7 ad 7b b8 91 00 00 00 e9    .5…….{……

0x00e30010   4f df ad 7b 8b ff 55 8b ec e9 ef 17 3e 76 8b ff    O..{..U…..>v..

0x00e30020   55 8b ec e9 95 76 39 76 8b ff 55 8b ec e9 be 53    U….v9v..U….S

0x00e30030   3a 76 8b ff 55 8b ec e9 d6 18 3e 76 8b ff 55 8b    :v..U…..>v..U.

0x00e30040   ec e9 14 95 39 76 8b ff 55 8b ec e9 4f 7e 3c 76    ….9v..U…O~<v

0x00e30050   8b ff 55 8b ec e9 0a 32 3a 76 8b ff 55 8b ec e9    ..U….2:v..U…

0x00e30060   7d 61 39 76 6a 2c 68 b8 8d 1c 77 e9 01 8c 39 76    }a9vj,h…w…9v

0x00e30070   8b ff 55 8b ec e9 c4 95 c8 70 8b ff 55 8b ec e9    ..U……p..U…

00e30000: b835000000                       MOV EAX, 0x35
00e30005: e9cdd7ad7b                       JMP 0x7c90d7d7
00e3000a: b891000000                       MOV EAX, 0x91
00e3000f: e94fdfad7b                       JMP 0x7c90df63
00e30014: 8bff                             MOV EDI, EDI
00e30016: 55                               PUSH EBP
00e30017: 8bec                             MOV EBP, ESP
00e30019: e9ef173e76                       JMP 0x7721180d
00e3001e: 8bff                             MOV EDI, EDI
00e30020: 55                               PUSH EBP

Well we have a lot of output so looks like a lot of our processes are injected with malcode.  The reason this plugin can find it is due to the fact of looking for kernel memory structures that work very closely with VirtualAlloc.  These memory structures are in a VAD tree and work closely with memory management aspects of the kernel.    There’s a lot more detailed explanation in the references section if you care to read further on the subject.  The plugin outputs hexdumps as well as assembly code at the base location of where the injected code was detected.  You can also pipe this output to a text file if it won’t fit in your console.

With all this output from our plugin let’s revisit our pstree command so we can get a hierarchical view on how the code injection may have cascaded.

C:\RE\volatility2.0\py\volatility-2.0>python -f zeus.vmem pstree
Volatile Systems Volatility Framework 2.0
Name                                        Pid    PPid   Thds   Hnds   Time
0x810B1660:System                               4      0     58    379 1970-01-
01 00:00:00
. 0xFF2AB020:smss.exe                          544      4      3     21 2010-08-
11 06:06:21
.. 0xFF1EC978:winlogon.exe                     632    544     24    536 2010-08-
11 06:06:23
... 0xFF255020:lsass.exe                       688    632     21    405 2010-08-
11 06:06:24
... 0xFF247020:services.exe                    676    632     16    288 2010-08-
11 06:06:24
.... 0xFF1B8B28:vmtoolsd.exe                  1668    676      5    225 2010-08-
11 06:06:35
..... 0xFF224020:cmd.exe                       124   1668      0 ------ 2010-08-
15 19:17:55
.... 0x80FF88D8:svchost.exe                    856    676     29    336 2010-08-
11 06:06:24
.... 0xFF1D7DA0:spoolsv.exe                   1432    676     14    145 2010-08-
11 06:06:26
.... 0x80FBF910:svchost.exe                   1028    676     88   1424 2010-08-
11 06:06:24
..... 0x80F60DA0:wuauclt.exe                  1732   1028      7    189 2010-08-
11 06:07:44
..... 0x80F94588:wuauclt.exe                   468   1028      4    142 2010-08-
11 06:09:37
..... 0xFF364310:wscntfy.exe                   888   1028      1     40 2010-08-
11 06:06:49
.... 0xFF217560:svchost.exe                    936    676     11    288 2010-08-
11 06:06:24
.... 0xFF143B28:TPAutoConnSvc.e               1968    676      5    106 2010-08-
11 06:06:39
..... 0xFF38B5F8:TPAutoConnect.e              1084   1968      1     68 2010-08-
11 06:06:52
.... 0xFF22D558:svchost.exe                   1088    676      7     93 2010-08-
11 06:06:25
.... 0xFF218230:vmacthlp.exe                   844    676      1     37 2010-08-
11 06:06:24
.... 0xFF25A7E0:alg.exe                        216    676      8    120 2010-08-
11 06:06:39
.... 0xFF203B80:svchost.exe                   1148    676     15    217 2010-08-
11 06:06:26
.... 0xFF1FDC88:VMUpgradeHelper               1788    676      5    112 2010-08-
11 06:06:38
.. 0xFF1ECDA0:csrss.exe                        608    544     10    410 2010-08-
11 06:06:23
0xFF3865D0:explorer.exe                      1724   1708     13    326 2010-08-
11 06:09:29
. 0xFF374980:VMwareUser.exe                    452   1724      8    207 2010-08-
11 06:09:32
. 0xFF3667E8:VMwareTray.exe                    432   1724      1     60 2010-08-
11 06:09:31

We did notice that services.exe looked to have some code injected into it.  Let’s take the parent process (winlogon.dmp that was dumped by malfind) and submit it to virustotal as PID 676 seems to be where the code injection is originating from in a hierarchical sense.

Sure enough 26/44 say it’s malicious.  Seems most of the scans detect it as Zbot.   So let’s Google around find some reports and see if we can verify it’s presence elsewhere.  Now that we’re armed with some reports let’s verify some other artifacts on the system just to make sure this is Zbot.

“The install function searches for the “winlogon.exe” process, allocates some memory within it and decrypts itself into the process.”

Well what do you know it looks like Zbot/Zeus injects it’s code into winlogon.exe This was apparent after we did our malfind as it detected injected code into other processes. If you would use procexedump through volatility it would be fine if you submitted to an avscan as it uses the pe header to dump the memory image. The new code sections that were allocated and later written to will not be reflected in the original pe header that was loaded into memory. This is the exact reason why we had to use malfind (Thanks again MHL!) above and couldn’t just procdump based on pid.

“The bot executable is written to the hard drive as “C:\WINDOWS\system32\sdra64.exe”.”

Volatility has a useful plugin here that allows us to identify file handles that are still hanging around in memory filescan.

C:\RE\volatility2.0\py\volatility-2.0>python -f zeus.vmem filescan
Volatile Systems Volatility Framework 2.0
Offset(V) Obj Type #Ptr #Hnd Access Name
0x01090778 0x8109d560 1 0 R--r-d '\\WINDOWS\\system32\\winrnr.dll'
0x010915b0 0x8109d560 1 0 R--rwd '\\WINDOWS\\system32\\oleaut32.dll'
0x01091648 0x8109d560 1 0 R--rwd '\\WINDOWS\\system32\\rpcrt4.dll'
0x01091810 0x8109d560 1 0 R--rwd '\\WINDOWS\\system32\\csrss.exe'
0x01092270 0x8109d560 1 1 RW-rw- '\\WINDOWS\\WindowsUpdate.log'
0x029d9b28 0x8109d560 1 1 R----- '\\WINDOWS\\system32\\sdra64.exe'
0x029d9cd8 0x8109d560 1 0 -WD--- '\\WINDOWS\\system32\\sdra64.exe'

“The directory “C:\WINDOWS\system32\lowsec\” is created. This directory is not visible in Windows Explorer but can be seen from the command line. Its purpose is to contain the following files:

local.ds: Contains the most recently downloaded DynamicConfig file.
user.ds: Contains logged information.
user.ds.lll: Temporarily created if transmission of logs to the drop server fails.

These artifacts can also be found in the above file scan to further bolster the case that this is definitely Zeus.

“The Winlogon (“HKLM/SOFTWARE/Microsoft/WindowsNT/CurrentVersion/Winlogon”) registry key’s value is appended with the path of the bot executable: C:/WINDOWS/system32/sdra64.exe. This will cause the bot to execute when the computer restarts.”

Volatility sure enough has a feature to allow us to investigate registry entries. Namely the printkey command. So let’s check the reg key from our Zbot analysis to see that this is here too.

C:\RE\volatility2.0\py\volatility-2.0>python -f zeus.vmem printkey -K "Mi
crosoft\Windows NT\CurrentVersion\Winlogon"
Volatile Systems Volatility Framework 2.0
Legend: (S) = Stable (V) = Volatile
Registry: \Device\HarddiskVolume1\WINDOWS\system32\config\software
Key name: Winlogon (S)
Last updated: 2010-08-15 19:17:23
(S) GPExtensions
(S) Notify
(S) SpecialAccounts
(V) Credentials

REG_DWORD AutoRestartShell : (S) 1
REG_SZ DefaultDomainName : (S) BILLY-DB5B96DD3
REG_SZ DefaultUserName : (S) Administrator
REG_SZ LegalNoticeCaption : (S)
REG_SZ LegalNoticeText : (S)
REG_SZ PowerdownAfterShutdown : (S) 0
REG_SZ ReportBootOk : (S) 1
REG_SZ Shell : (S) Explorer.exe
REG_SZ ShutdownWithoutLogon : (S) 0
REG_SZ System : (S)
REG_SZ Userinit : (S) C:\WINDOWS\system32\userinit.exe,C:\WINDOWS\
REG_SZ VmApplet : (S) rundll32 shell32,Control_RunDLL “sysdm.cpl

REG_DWORD SfcQuota : (S) 4294967295
REG_SZ allocatecdroms : (S) 0
REG_SZ allocatedasd : (S) 0
REG_SZ allocatefloppies : (S) 0
REG_SZ cachedlogonscount : (S) 10
REG_DWORD forceunlocklogon : (S) 0
REG_DWORD passwordexpirywarning : (S) 14
REG_SZ scremoveoption : (S) 0
REG_DWORD AllowMultipleTSSessions : (S) 1
REG_EXPAND_SZ UIHost : (S) logonui.exe
REG_DWORD LogonType : (S) 1
REG_SZ Background : (S) 0 0 0
REG_SZ AutoAdminLogon : (S) 0
REG_SZ DebugServerCommand : (S) no
REG_DWORD SFCDisable : (S) 0
REG_SZ WinStationsDisabled : (S) 0
REG_DWORD HibernationPreviouslyEnabled : (S) 1
REG_DWORD ShowLogonOptions : (S) 0
REG_SZ AltDefaultUserName : (S) Administrator
REG_SZ AltDefaultDomainName : (S) BILLY-DB5B96DD3

Well that key is certainly apparent and this is our persistence mechanism. So the Zeus/Zbot injector process is called at start-up to insert it’s hooks and malicious code in our legitimate looking processes to evade detection. This would be something you’d want to clean up if you were re-mediating the system as well.

“The Windows XP firewall is disabled. This causes a Windows Security Center warning icon to appear in the system tray, the only visible indication that the computer has been infected.”

It looks like Zeus/Zbot also takes care of disabling the Windows Firewall so your not annoyed with any popups while it’s pilfering through your banking data. Googling around there are some registry forensics blogs that keep track of the location for windows firewall settings. Using our command printkey we can detect if this is enabled or disabled in this specific image.

C:\RE\volatility2.0\py\volatility-2.0>python -f zeus.vmem printkey -K "Co
Volatile Systems Volatility Framework 2.0
Legend: (S) = Stable (V) = Volatile
Registry: \Device\HarddiskVolume1\WINDOWS\system32\config\system
Key name: StandardProfile (S)
Last updated: 2010-08-15 19:17:24

(S) AuthorizedApplications

REG_DWORD EnableFirewall : (S) 0

So the firewall is currently disabled and if you notice the timestamp on the key as well. It looks like this was last updated at 2010-8-15 at 19:17:24. This is tidbit of information that you could use in a timeline analysis if you had to document to this level of detail. The specific Zeus/Zbot may not modify this key every time but check if its set according to it’s specifications. I’m not sure as I don’t have the file but it would be a reasonable assumption. Also the EnableFirewall key was not in the DomainProfile but only the StandardProfile for you registry pros out there.

“A closer look at its binary file reveals that the spyware was designed to monitor known ZBOT mutexes, _AVIRA_ and __SYSTEM__.”

C:\RE\volatility2.0\py\volatility-2.0>python -f zeus.vmem mutantscan
Volatile Systems Volatility Framework 2.0
0x05ca17e8 0x810ae5e0 2 1 1 0x00000000 '_AVIRA_2108'

Well there is certainly a mutex that has been recent in memory for AVIRA which ironically enough is the name of an antivirus engine. It was sent to poke fun at the anti-virus companies by the programmer’s of Zeus. It also looks from the above mutex that we have a 1.x version of Zeus/Zbot as in 2.x versions they use randomly generated GUID’s over mutexes to communicate.

So there we have it using Volatility we can get a look at a Zeus/Zbot infection and determine steps here for possible remediation just based on a memory dump. We’d have more resources if we were able to have access to the system as well so we could study the injector process to see if it has any other persistence mechanisms. It’s doubtful since this matches so closely to the typical Zeus/Zbot signature. I hope you enjoyed reading this article!

Edit: Looks like another Zeus article was written and is linked here to give you another viewpoint on this piece of malware.


[1] –

[2] –

[3] –

[4] –

[5] –

Nice DLL Injection LIB


Windows memory hacking library


  • x86 and x64 support

Process interaction

  • Manage PEB32/PEB64
  • Manage process through WOW64 barrier

Process Memory

  • Allocate and free virtual memory
  • Change memory protection
  • Read/Write virtual memory

Process modules

  • Enumerate all (32/64 bit) modules loaded. Enumerate modules using Loader list/Section objects/PE headers methods.
  • Get exported function address
  • Get the main module
  • Unlink module from loader lists
  • Inject and eject modules (including pure IL images)
  • Inject 64bit modules into WOW64 processes
  • Manually map native PE images


  • Enumerate threads
  • Create and terminate threads. Support for cross-session thread creation.
  • Get thread exit code
  • Get main thread
  • Manage TEB32/TEB64
  • Join threads
  • Suspend and resume threads
  • Set/Remove hardware breakpoints

Pattern search

  • Search for arbitrary pattern in local or remote process

Remote code execution

  • Execute functions in remote process
  • Assemble own code and execute it remotely
  • Support for cdecl/stdcall/thiscall/fastcall conventions
  • Support for arguments passed by value, pointer or reference, including structures
  • FPU types are supported
  • Execute code in new thread or any existing one

Remote hooking

  • Hook functions in remote process using int3 or hardware breakpoints
  • Hook functions upon return

Manual map features

  • x86 and x64 image support
  • Mapping into any arbitrary unprotected process
  • Section mapping with proper memory protection flags
  • Image relocations (only 2 types supported. I haven’t seen a single PE image with some other relocation types)
  • Imports and Delayed imports are resolved
  • Bound import is resolved as a side effect, I think
  • Module exports
  • Loading of forwarded export images
  • Api schema name redirection
  • SxS redirection and isolation
  • Activation context support
  • Dll path resolving similar to native load order
  • TLS callbacks. Only for one thread and only with PROCESS_ATTACH/PROCESS_DETACH reasons.
  • Static TLS
  • Exception handling support (SEH and C++)
  • Adding module to some native loader structures(for basic module api support: GetModuleHandle, GetProcAdress, etc.)
  • Security cookie initialization
  • C++/CLI images are supported
  • Image unloading
  • Increase reference counter for import libraries in case of manual import mapping
  • Cyclic dependencies are handled properly

Driver features

  • Allocate/free/protect user memory
  • Read/write user and kernel memory
  • Disable permanent DEP for WOW64 processes
  • Change process protection flag
  • Change handle access rights
  • Remap process memory
  • Hiding allocated user-mode memory
  • User-mode dll injection and manual mapping
  • Manual mapping of drivers