My favorites | Sign in
Project Home Downloads Wiki Issues Source
Checkout   Browse   Changes    
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# Volatility
#
# Authors:
# Michael Hale Ligh <michael.ligh@mnin.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#

import os, sys
import volatility.obj as obj
import volatility.utils as utils
import volatility.plugins.filescan as filescan
import volatility.plugins.modscan as modscan
import volatility.plugins.procdump as procdump
import volatility.win32.tasks as tasks

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")

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()

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)

def render_text(self, outfd, data):
"""nothing"""





Change log

r110 by michael.hale on Oct 13, 2011   Diff
add zeroaccess plugin
Go to: 
Project members, sign in to write a code review

Older revisions

All revisions of this file

File info

Size: 5043 bytes, 135 lines
Powered by Google Project Hosting