ZeroAccess, Volatility, and Kernel Timers

CODEDRAGON Security/DigitalForensics

반응형

 

 

ZeroAccess, Volatility, and Kernel Timers

http://mnin.blogspot.kr/2011/10/zeroaccess-volatility-and-kernel-timers.html

   

As today is Volatility Friday, we'll discuss how to hunt ZeroAccess in memory by following the lead of several others and then writing our own custom plugin. I first want to recognize the work done on this topic by Frank Boldewin, Giuseppe Bonfa, and Marco Giuliani. They are the ones doing the reverse engineering here - I am just translating their findings and showing how to do things "the Volatility way."

   

The First Sample: e6823f932c2b40d2025d78bb78d64458

   

This is the same sample Frank used in his analysis (see link above) so you will want to read that post first. Frank's course of actions to find ZeroAccess were:

   

1) Find the DEVICE_OBJECT that starts with ACPI#PNP[...]

2) Find the DRIVER_OBJECT to which the device belongs (note the driver is unnamed)

3) Take the DriverStart and DriverSize members of the DRIVER_OBJECT to dump the rootkit's kernel code

4) Search for threads executing in the same space as the rootkit's kernel code

5) Find the process with a fake usermode ADS name (i.e. a colon ':' in the name)

6) Dump the malicious process

   

Okay so let's get to work with Volatility! We'll follow nearly the same order of operations that Frank used, however to start instead of looking in the \global?? directory for the DEVICE_OBJECT, we'll just use the devicetree plugin.

$ python vol.py -f zeroaccess1.vmem devicetree
Volatile Systems Volatility Framework 2.1_alpha
DRV 0x022dba18 '\\Driver\\NetBT'
---| DEV 0x81dc7d30 NetBT_Tcpip_{9B5A1EAD-7852-455F-9740-5E1FCD05D812} FILE_DEVICE_NETWORK
---| DEV 0x82251ca0 NetBt_Wins_Export FILE_DEVICE_NETWORK
---| DEV 0x81eb3030 NetbiosSmb FILE_DEVICE_NETWORK
DRV 0x022e1c08 '\\FileSystem\\MRxDAV'
---| DEV 0x81caca58 WebDavRedirector FILE_DEVICE_NETWORK_FILE_SYSTEM
DRV 0x022e3880
---| DEV 0x81f3ee48 ACPI#PNP0303#2&da1a3ff&0 FILE_DEVICE_UNKNOWN
DRV 0x022f9f38 '\\Driver\\intelppm'
---| DEV 0x81c8cdd8 (unnamed) FILE_DEVICE_UNKNOWN

There's a unnamed DRIVER_OBJECT at physical offset 0x022e3880 that has a DEVICE_OBJECT at virtual address 0x81f3ee48 with name ACPI#PNP[...]. That seems to correlate with Frank's findings, so it feels like we're on the right track. The next thing I want to do is figure out the DriverStart and DriverSize of the DRIVER_OBJECT. One could easily modify the devicetree plugin to print this information (we'll show how to do it programatically in a minute) but for the time being I'll just use volshell. The values displayed will be in decimal.

$ python vol.py -f zeroaccess1.vmem volshell
Volatile Systems Volatility Framework 2.1_alpha
Current context: process System, pid=4, ppid=0 DTB=0x319000
To get help, type 'hh()'

In [1]: dt("_DEVICE_OBJECT", 0x81f3ee48)
[CType _DEVICE_OBJECT] @ 0x81F3EE48
0x0 : Type 3
0x2 : Size 184
0x4 : ReferenceCount 3
0x8 : DriverObject 2181970048

In [2]: dt("_DRIVER_OBJECT", 2181970048)
[CType _DRIVER_OBJECT] @ 0x820E3880
0x0 : Type 4
0x2 : Size 168
0x4 : DeviceObject 2180247112
0x8 : Flags 18
0xc : DriverStart 2987057152
0x10 : DriverSize 126976
0x14 : DriverSection 2180702128
0x18 : DriverExtension 2181970216

In [3]: hex(2987057152)
Out[3]: '0xb20ae000'

In [4]: hex(126976)
Out[4]: '0x1f000'

Now that we know the driver's kernel code exists at 0xb20ae000, we can dump it with moddump.

$ python vol.py -f zeroaccess1.vmem moddump -o 0xb20ae000 -D zeroaccess/
Volatile Systems Volatility Framework 2.1_alpha
Dumping Unknown, Base: b20ae000 output: driver.b20ae000.sys

$ strings zeroaccess/driver.b20ae000.sys
!This program cannot be run in DOS mode.
X6Rich
.text
`.rdata
@.data
.reloc

PVVV
Ul;Upw
!This program cannot be run in DOS mode.
Rich
.text

RSA1
A8C,
!This program cannot be run in DOS mode.
Rich
.text
PPPTh
ZwCreateFile
ZwTestAlert
ntdll.dll
ExitProcess
KERNEL32.dll
1234567890123456789012345678901234567890123456789012345678901234

CryptAcquireContextW
CryptImportKey
CryptCreateHash
CryptHashData
CryptVerifySignatureW
CryptDestroyHash
CryptReleaseContext
MD5Init
MD5Update

ntp2.usno.navy.mil
ntp.adc.am
tock.usask.ca
ntp.crifo.org
ntp1.arnes.si
ntp.ucsd.edu
ntp.duckcorp.org
wwv.nist.gov
clock.isc.org

Based on the "This program cannot[...]" strings, the driver has multiple embedded PE files, so you can already begin to expect code injection or at least a user mode presence. Hold that thought.

   

The 4th step in Frank's analysis was to check for suspicious threads based on their starting or current IP location. You can do this easily with the threads plugin by filtering for orphan threads (-F OrphanThread).

$ python vol.py -f zeroaccess1.vmem threads -F OrphanThread
Volatile Systems Volatility Framework 2.1_alpha
------
ETHREAD: 0x81c6b4a0 Pid: 4 Tid: 908
Tags: OrphanThread,SystemThread
Created: 2011-10-13 14:26:18
Exited: -
Owning Process: 0x823c8830 'System'
Attached Process: 0x823c8830 'System'
State: Waiting:WrQueue
BasePriority: 0x8
Priority: 0x8
TEB: 0x00000000
StartAddress: 0xb20b6105
ServiceTable: 0x80552fa0
[0] 0x80501b8c
[1] -
[2] -
[3] -
Win32Thread: 0x00000000
CrossThreadFlags: PS_CROSS_THREAD_FLAGS_SYSTEM
b20b6105: 58 POP EAX
b20b6106: 870424 XCHG [ESP], EAX
b20b6109: ffd0 CALL EAX
b20b610b: 8b0df8bb0bb2 MOV ECX, [0xb20bbbf8]
b20b6111: ff2500920bb2 JMP DWORD [0xb20b9200]
b20b6117: 64a118000000 MOV EAX, [FS:0x18]

As you can see, this thread's StartAddress is 0xb20b6105 - well within range of the ZeroAccess driver. By using the callbacks plugin, you can also see there's a suspicious IoRegisterShutdownNotification routine pointing at approximately the same range in kernel memory.

$ python vol.py -f zeroaccess1.vmem callbacks
Volatile Systems Volatility Framework 2.1_alpha
Type Callback Owner
PsSetCreateProcessNotifyRoutine 0xf87ad194 vmci.sys
KeBugCheckCallbackListHead 0xf83e65ef NDIS.sys (Ndis miniport)
KeBugCheckCallbackListHead 0x806d77cc hal.dll (ACPI 1.0 - APIC platform UP)
KeRegisterBugCheckReasonCallback 0xf8b7aab8 mssmbios.sys (SMBiosData)
KeRegisterBugCheckReasonCallback 0xf8b7aa70 mssmbios.sys (SMBiosRegistry)
KeRegisterBugCheckReasonCallback 0xf8b7aa28 mssmbios.sys (SMBiosDataACPI)
KeRegisterBugCheckReasonCallback 0xf82e01be USBPORT.SYS (USBPORT)
KeRegisterBugCheckReasonCallback 0xf82e011e USBPORT.SYS (USBPORT)
KeRegisterBugCheckReasonCallback 0xf82f7522 VIDEOPRT.SYS (Videoprt)
IoRegisterShutdownNotification 0xf88ddc74 Cdfs.SYS (\FileSystem\Cdfs)
IoRegisterShutdownNotification 0xf8bb05be Fs_Rec.SYS (\FileSystem\Fs_Rec)
IoRegisterShutdownNotification 0xf8303c6a VIDEOPRT.SYS (\Driver\VgaSave)
IoRegisterShutdownNotification 0xb2d108fa vmhgfs.sys (\FileSystem\vmhgfs)
IoRegisterShutdownNotification 0xf8bb05be Fs_Rec.SYS (\FileSystem\Fs_Rec)
IoRegisterShutdownNotification 0xf8303c6a VIDEOPRT.SYS (\Driver\mnmdd)
IoRegisterShutdownNotification 0xf8303c6a VIDEOPRT.SYS (\Driver\vmx_svga)
IoRegisterShutdownNotification 0xf8303c6a VIDEOPRT.SYS (\Driver\RDPCDD)
IoRegisterShutdownNotification 0xb20b49d0
IoRegisterShutdownNotification 0xf86aa73a MountMgr.sys (\Driver\MountMgr)
IoRegisterShutdownNotification 0xf8bb05be Fs_Rec.SYS (\FileSystem\Fs_Rec)

Next we'll try and locate ZeroAccess in user mode based on Frank's findings. At first I didn't understand what "Fake Usermode ADS" meant, but when I used the pslist and dlllist commands it all started to make sense. The image name from pslist comes from EPROCESS.ImageFileName (in kernel memory) and the info from dlllist comes from the PEB (in user memory). In normal cases, output from the two plugins will match, but in this case you can see the discrepancy:

$ python vol.py -f zeroaccess1.vmem pslist
Volatile Systems Volatility Framework 2.1_alpha
Offset(V) Name PID PPID Thds Hnds Time
---------- -------------------- ------ ------ ------ ------ -------------------
0x823c8830 System 4 0 57 398 1970-01-01 00:00:00
0x820df020 smss.exe 376 4 3 19 2010-10-29 17:08:53
0x821a2da0 csrss.exe 600 376 11 342 2010-10-29 17:08:54
[snip]
0x820d4b28 3418651033 1148 668 1 5 2011-10-13 14:26:18
0x81c6ada0 cmd.exe 1244 1664 0 ------ 2011-10-13 14:37:07

$ python vol.py -f zeroaccess1.vmem dlllist -p 1148
Volatile Systems Volatility Framework 2.1_alpha
************************************************************************
3418651033 pid: 1148
Command line : 3418651033:1720073012.exe
Service Pack 3

Base Size Path
0x00400000 0x000330 C:\WINDOWS\3418651033:1720073012.exe
0x7c900000 0x0af000 C:\WINDOWS\system32\ntdll.dll
0x7c800000 0x0f6000 C:\WINDOWS\system32\kernel32.dll

Kernel memory says the image name is 3418651033 but user memory says its 3418651033:1720073012.exe. Either way, you can dump it with procexedump.

$ python vol.py -f zeroaccess1.vmem procexedump -p 1148 -D zeroaccess/
Volatile Systems Volatility Framework 2.1_alpha
************************************************************************
Dumping 3418651033, pid: 1148 output: executable.1148.exe

$ strings zeroaccess/executable.1148.exe
!This program cannot be run in DOS mode.
Rich
.text
PPPTh
ZwCreateFile
ZwTestAlert
ntdll.dll
ExitProcess
KERNEL32.dll

If you recall the embedded PE strings we viewed from the extracted kernel driver, you'll recognize that this is one of them. One down, one to go. How can we locate the other one - with our only bit of knowledge being that we expect it to be somewhere in user mode memory? How about malfind?

$ python vol.py -f zeroaccess1.vmem malfind -D zeroaccess/
Process: services.exe Pid 668
VAD: 0x950000-0x954fff Vad PAGE_EXECUTE_READWRITE
0x00950000 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 MZ..............
0x00950010 b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ........@.......
0x00950020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00950030 00 00 00 00 00 00 00 00 00 00 00 00 d0 00 00 00 ................
0x00950040 0e 1f ba 0e 00 b4 09 cd 21 b8 01 4c cd 21 54 68 ........!..L.!Th
0x00950050 69 73 20 70 72 6f 67 72 61 6d 20 63 61 6e 6e 6f is.program.canno
0x00950060 74 20 62 65 20 72 75 6e 20 69 6e 20 44 4f 53 20 t.be.run.in.DOS.
0x00950070 6d 6f 64 65 2e 0d 0d 0a 24 00 00 00 00 00 00 00 mode....$.......
Dumped to services.exe.82073020.950000.954fff.dmp

$ strings zeroaccess/services.exe.82073020.950000.954fff.dmp
!This program cannot be run in DOS mode.
Rich
.text
`.rdata
@.data

ZwCreateFile
ZwTestAlert
ntdll.dll
ExitProcess
KERNEL32.dll
1234567890123456789012345678901234567890123456789012345678901234
RtlImageDirectoryEntryToData
RtlAddressInSectionTable
RtlImageNtHeader
ZwOpenFile

Bingo! There's the other embedded PE that the kernel driver must inject into services.exe.

   

Building a Custom ZeroAccess Volatility Plugin

   

I'm sure many readers are wondering, how hard is it to automate the actions that we've done. Well, you're in luck...its not too difficult at all. In fact, I've written a sample plugin to assist with your understanding of the Volatility API. Let's get started. First define a class with the name of your plugin. Mine will be "ZeroAccess" and it will inherit from DriverScan (since we want to scan for DRIVER_OBJECTs) and ProcExeDump (since we want to rebuild/dump PE files).

class ZeroAccess(filescan.DriverScan, procdump.ProcExeDump):
"""Dump the ZeroAccess Driver and Files"""

def __init__(self, config, *args):
# remove all of procdump's options except DUMP_DIR
procdump.ProcExeDump.__init__(self, config, *args)
config.remove_option("UNSAFE")
config.remove_option("PID")
config.remove_option("OFFSET")

Then we add a function to the class that can handle the rebuilding of PE files - most of which was taken from the dlldump source code.

def dump_pe(self, space, start, file_name):
"""Dump a PE file to disk"""

if not self._config.DUMP_DIR:
return

full_path = os.path.join(self._config.DUMP_DIR, file_name)
sys.stdout.write("Dumping PE: {0}\n".format(full_path))
of = open(full_path, 'wb')

try:
for chunk in self.get_image(sys.stdout, space, start):
offset, code = chunk
of.seek(offset)
of.write(code)
except ValueError:
pass

of.close()

Most of the heavy lifting will be done in the calculate function. I won't describe each step individually like I did in the Abstract Memory Analysis: Zeus Encryption Keys post, because its already pretty well commented and we described all the steps above.

def calculate(self):

space = utils.load_as(self._config)

# enumerate system threads (0x00000010 = PS_CROSS_THREAD_FLAGS_SYSTEM)
system_threads = [t for t in modscan.ThrdScan(self._config).calculate() if t.CrossThreadFlags & 0x00000010]

# find and dump the malicious kernel driver
for item in filescan.DriverScan(self._config).calculate():

# unpack the parameters
(object, driver, extension, object_name) = item

# looking for unnamed driver objects
if driver.DriverName.Length != 0:
continue

# the first and only device should be ACPI#PNP[...]
device = obj.Object("_DEVICE_OBJECT",
offset = driver.DeviceObject, vm = space)

# get the device's object header
object = obj.Object("_OBJECT_HEADER", \
offset = device.obj_offset - \
device.obj_vm.profile.get_obj_offset("_OBJECT_HEADER", "Body"), \
vm = space)

object.kas = space
device_name = object.get_object_name()

# did we find zeroaccess?
if not str(device_name).startswith("ACPI#PNP"):
continue

sys.stdout.write("DriverObject: {0:#x}\n".format(device.DriverObject))
sys.stdout.write(" DriverStart: {0:#x}\n".format(driver.DriverStart))
sys.stdout.write(" DriverSize: {0:#x}\n".format(driver.DriverSize))
sys.stdout.write("DeviceObject: {0:#x} {1}\n".format(device.obj_offset, device_name))

# dump the driver
file_name = "Driver.{0:#x}.sys".format(driver.DriverStart)
self.dump_pe(space, driver.DriverStart, file_name)

# now what we know the memory range, look for bad threads
for thread in system_threads:

if thread.StartAddress > driver.DriverStart and \
thread.StartAddress < driver.DriverStart + driver.DriverSize:

sys.stdout.write("Bad Thread: {0:#x} Tid {1}\n".format(\
thread.obj_offset,
thread.Cid.UniqueThread))

# now find and dump the fake usermode ADS process
for proc in tasks.pslist(space):

for dll in proc.Peb.Ldr.InLoadOrderModuleList.list_of_type(\
"_LDR_DATA_TABLE_ENTRY", "InLoadOrderLinks"):

# look for the ADS name
if str(dll.BaseDllName).find(":") != -1:

sys.stdout.write("Fake ADS EXE: {0} pid {1} base {2:#x}\n".format(\
proc.ImageFileName,
proc.UniqueProcessId,
dll.DllBase))

file_name = "Dll.{0:#x}.{1:#x}.dll".format(proc.obj_offset, dll.DllBase)
self.dump_pe(proc.get_process_address_space(), dll.DllBase, file_name)

Testing the ZeroAccess Volatility Plugin

   

Here is some example output from our new plugin:

$ python vol.py -f zeroaccess1.vmem zeroaccess -D zeroaccess/
Volatile Systems Volatility Framework 2.1_alpha
DriverObject: 0x820e3880
DriverStart: 0xb20ae000
DriverSize: 0x1f000
DeviceObject: 0x81f3ee48 ACPI#PNP0303#2&da1a3ff&0
Dumping PE: zeroaccess/Driver.0xb20ae000.sys
Bad Thread: 0x1e6b4a0 Tid 908
Fake ADS EXE: 3418651033 pid 1148 base 0x400000
Dumping PE: zeroaccess/Dll.0x820d4b28.0x400000.dll

$ ls zeroaccess/
Dll.0x820d4b28.0x400000.dll Driver.0xb20ae000.sys

That's it folks! In just a small Python script, we identified the malicious DRIVER_OBJECT, the malicious DEVICE_OBJECT, the Fake Usermode ADS, the "stealth" ETHREAD, and extracted a few of the PE files. Now grab IDA Pro and enjoy reversing the unpacked binaries.

   

The Second Sample: 505b071b3eead7ded32a766c98efb6ef

   

Realizing that there are thousands of ZeroAccess variants floating around, I wanted to try and duplicate the findings on at least one other sample. Here's the output of our new plugin on the next sample we tried:

$ python vol.py -f zeroaccess2.vmem zeroaccess -D zeroaccess/
Volatile Systems Volatility Framework 2.1_alpha
DriverObject: 0x81f523f0
DriverStart: 0xb2158000
DriverSize: 0xd000
DeviceObject: 0x81fc2370 ACPI#PNP0303#2&da1a3ff&0
Dumping PE: zeroaccess/Driver.0xb2158000.sys

As you can see, a few of the artifacts were found and extracted, but not all of them. It turns out this sample is quite different than the first. For one, it doesn't use the Fake Usermode ADS. Instead, you can spot the malicious process because its mapped from a suspicious namespace:

$ python vol.py -f zeroaccess2.vmem dlllist -p 1136
************************************************************************
svchost.exe pid: 1136
Command line : "\\.\globalroot\Device\svchost.exe\svchost.exe"
Service Pack 3

Base Size Path
0x00400000 0x0002d0 \\.\globalroot\Device\svchost.exe\svchost.exe
0x7c900000 0x0af000 C:\WINDOWS\system32\ntdll.dll
0x7c800000 0x0f6000 C:\WINDOWS\system32\kernel32.dll

What is \\.\globalroot\Device\svchost.exe? Surely that device doesn't exist on a clean system. Let's check with devicetree again and see if anything looks different than the first ZeroAccess sample:

$ python vol.py -f zeroaccess2.vmem devicetree
DRV 0x01e109b8 '\\Driver\\03621276'
---| DEV 0x820ec030 svchost.exe FILE_DEVICE_DISK

DRV 0x01df6718 '\\Driver\\kmixer'
---| DEV 0x825347d0 (unnamed) FILE_DEVICE_KS
DRV 0x0214f4c8 '\\Driver\\03621275'
---| DEV 0x81fe8030 (unnamed) FILE_DEVICE_ACPI
DRV 0x021523f0
---| DEV 0x81fc2370 ACPI#PNP0303#2&da1a3ff&0 FILE_DEVICE_UNKNOWN

I've highlighted almost all of the output in red, because...well, almost all if it is malicious. This variant of ZeroAccess creates 3 DRIVER_OBJECTs and 3 DEVICE_OBJECTs. The patterns can be expressed as the following:

   

1) a DRIVER_OBJECT with all numbers in the name (03621276) with a DEVICE_OBJECT named svchost.exe and type FILE_DEVICE_DISK

   

2) a DRIVER_OBJECT with all numbers in the name (03621275) with an unnamed DEVICE_OBJECT and type FILE_DEVICE_ACPI

   

3) an unnamed DRIVER_OBJECT with DEVICE_OBJECT named ACPI#PNP[...] (this is the one we already explored)

   

Modifying our new plugin to handle these additional cases is trivial, thus I'll leave it as an exercise to the reader. However, the one thing you may run into is that the DriverStart and DriverSize for the first two DRIVER_OBJECTs has been zeroed out:

$ python vol.py -f zeroaccess2.vmem volshell
Volatile Systems Volatility Framework 2.1_alpha
Current context: process System, pid=4, ppid=0 DTB=0x319000
To get help, type 'hh()'

In [1]: dt("_DEVICE_OBJECT", 0x820ec030)
[CType _DEVICE_OBJECT] @ 0x820EC030
0x0 : Type 3
0x2 : Size 184
0x4 : ReferenceCount 2
0x8 : DriverObject 2176911800

In [2]: dt("_DRIVER_OBJECT", 2176911800)
[CType _DRIVER_OBJECT] @ 0x81C109B8
0x0 : Type 4
0x2 : Size 168
0x4 : DeviceObject 2182004784
0x8 : Flags 4
0xc : DriverStart 0
0x10 : DriverSize 0
0x14 : DriverSection 0
0x18 : DriverExtension 2176911968
0x1c : DriverName \Driver\03621276
0x24 : HardwareDatabase 0
0x28 : FastIoDispatch 0
0x2c : DriverInit 2176398992

In [3]: hex(2176398992)
Out[3]: '0x81b93690'

So although the DriverStart and DriverSize members are zero, making it difficult to dump the driver's code, we can still get a hint of where the code exists because the DriverInit value is not zero. We're looking around kernel addresses 0x81b93690. Cross reference that with orphan threads:

$ python vol.py -f zeroaccess2.vmem threads -F OrphanThread
Volatile Systems Volatility Framework 2.1_alpha
------
ETHREAD: 0x81fa4bc8 Pid: 4 Tid: 416
Tags: OrphanThread,SystemThread
Created: 2011-10-13 04:29:10
Exited: -
Owning Process: 0x823c8830 'System'
Attached Process: 0x823c8830 'System'
State: Waiting:DelayExecution
BasePriority: 0x8
Priority: 0x8
TEB: 0x00000000
StartAddress: 0x81b9a505
ServiceTable: 0x80552fa0
[0] 0x80501b8c
[1] -
[2] -
[3] -
Win32Thread: 0x00000000
CrossThreadFlags: PS_CROSS_THREAD_FLAGS_SYSTEM
81b9a505: 58 POP EAX
81b9a506: 870424 XCHG [ESP], EAX
81b9a509: ffd0 CALL EAX
81b9a50b: 8b0d8cf7b981 MOV ECX, [0x81b9f78c]
81b9a511: ff25a4cdb981 JMP DWORD [0x81b9cda4]
81b9a517: 64a118000000 MOV EAX, [FS:0x18]

The last thing I wanted to point out is the callbacks output. This version of ZeroAccess not only installs the IoRegisterShutdownNotification, but also a CmRegisterCallback - for monitoring or preventing access to certain registry keys.

$ python vol.py -f zeroaccess2.vmem callbacks
Volatile Systems Volatility Framework 2.1_alpha
Type Callback Owner
PsSetCreateProcessNotifyRoutine 0xf87ad194 vmci.sys
KeBugCheckCallbackListHead 0xf83e65ef NDIS.sys (Ndis miniport)
KeBugCheckCallbackListHead 0x806d77cc hal.dll (ACPI 1.0 - APIC platform UP)
KeRegisterBugCheckReasonCallback 0xf8b7aab8 mssmbios.sys (SMBiosData)
KeRegisterBugCheckReasonCallback 0xf8b7aa70 mssmbios.sys (SMBiosRegistry)
IoRegisterShutdownNotification 0x81b934e0 UNKNOWN (\Driver\03621276)
[snip]
IoRegisterShutdownNotification 0xf8bb05be Fs_Rec.SYS (\FileSystem\Fs_Rec)
IoRegisterShutdownNotification 0xf853c2be ftdisk.sys (\Driver\Ftdisk)
IoRegisterShutdownNotification 0x805cdef4 ntoskrnl.exe (\FileSystem\RAW)
IoRegisterShutdownNotification 0xf83d98f1 Mup.sys (\FileSystem\Mup)
IoRegisterShutdownNotification 0x805f5d66 ntoskrnl.exe (\Driver\WMIxWDM)
CmRegisterCallback 0x81b92d60 UNKNOWN (--)

ZeroAccess Rogue Kernel Timers

   

In early January 2011, when Frank Boldewin and I were working on finding artifacts of Rustock.B and Rustuck.C in memory, he suggested that a plugin for analyzing kernel timers be added to Volatility. I drafted up a copy and then forgot about it until he reminded me this week, and guess what - just in time to be useful. I will go into depth on kernel timers next Volatility Friday, but for now you can see yet another strong factor in memory that indicates something suspicious is going on.

$ python vol.py -f zeroaccess2.vmem timers
Volatile Systems Volatility Framework 2.1_alpha
Offset DueTime Period(ms) Signaled Routine Module
0x805598e0 0x00000084:0xce8b961c 1000 Yes 0x80523dee ntoskrnl.exe
0x820a1e08 0x00000084:0xdf3c0c1c 30000 Yes 0xb2d2a385 afd.sys
0x81ebf0b8 0x00000084:0xce951f84 0 - 0xf89c23f0 TDI.SYS
0x8055b200 0x00000086:0x1c631c38 0 - 0x80534a2a ntoskrnl.exe
0xf842f270 0x00000084:0xd0fea092 0 - 0xf84111b4 Ntfs.sys
0xb27f3990 0x00000084:0xd36a83fa 0 - 0xb27e4385 srv.sys
0x805516d0 0x00000084:0xda9d7dbc 60000 Yes 0x804f3eae ntoskrnl.exe
0x80550ce0 0x00000084:0xd11d9f24 0 - 0x8053b8fc ntoskrnl.exe
0x80551800 0x00000084:0xcebda77e 1000 Yes 0x804f3716 ntoskrnl.exe
0x82255720 0x80000084:0xb14adbda 0 - 0x80534e48 ntoskrnl.exe
[snip]
0x81dbeb78 0x00000131:0x2e896402 0 - 0xf83faf6f NDIS.sys
0x81e8b4f0 0x00000131:0x2e896402 0 - 0xf83faf6f NDIS.sys
0x81eb8e28 0x00000084:0xe5855f6a 0 - 0x80534e48 ntoskrnl.exe
0xb20bbbb0 0x00000084:0xd4de72d2 60000 Yes 0xb20b5990 UNKNOWN
0x8210d910 0x80000000:0x0a7efa36 0 - 0x80534e48 ntoskrnl.exe
0x82274190 0x80000000:0x711befba 0 - 0x80534e48 ntoskrnl.exe
0x81de9690 0x80000000:0x0d0c3e8a 0 - 0x80534e48 ntoskrnl.exe

Conclusion and Source Code

   

Thanks again to Frank, Guiseppe, and Marco for sharing the results of their analysis and ultimately making this blog post possible (without doing my own RE).

   

Download the ZeroAccess Volatility Plugin here. Play with it, learn from it, enoy it!

Posted 14th October 2011 by Michael Hale Ligh

   

출처: <http://mnin.blogspot.kr/2011/10/zeroaccess-volatility-and-kernel-timers.html>

반응형

'Security > DigitalForensics' 카테고리의 다른 글

Windows Help program (WinHlp32.exe) for Windows 8.1  (0) 2015.05.31
JPEG & PNG Stripper - download  (0) 2015.05.20
Runscanner - 실행  (0) 2015.04.01
Runscanner-startup and hijack analyzer  (0) 2015.03.22
Public process list-Runscanner  (0) 2015.03.15