Skip to content

Commit 76dd789

Browse files
author
Michael Ligh
committed
push some of the 2016 contest submissions
1 parent 4abee87 commit 76dd789

31 files changed

+3656
-0
lines changed

BartoszInglot/rdpkeys.py

Lines changed: 425 additions & 0 deletions
Large diffs are not rendered by default.

DimaPshoul/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Author: Dima Pshoul
2+
3+
See https://github.com/papadp for updates and license information.

DimaPshoul/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

DimaPshoul/callstacks.py

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
import sys, pydoc, struct
2+
import volatility.utils as utils
3+
import volatility.registry as registry
4+
import volatility.obj as obj
5+
import volatility.win32.modules as modules
6+
import volatility.win32.tasks as tasks
7+
import volatility.plugins.ssdt as ssdt
8+
import volatility.plugins.taskmods as taskmods
9+
import volatility.plugins.modscan as modscan
10+
import volatility.plugins.malware.malfind as malfind
11+
import volatility.debug as debug
12+
import volatility.plugins.malware.threads as threads
13+
14+
enumerated_processes = {}
15+
kernel_modules = {}
16+
17+
class CallstackItem():
18+
""" a class that describes an item retreived from the callstack"""
19+
def __init__(self, ret_address, frame_address):
20+
self.ret_address = ret_address
21+
self.frame_address = frame_address
22+
self.owning_module_name = None
23+
self.owning_module_address = None
24+
self.function = None
25+
self.comment = ""
26+
27+
class ThreadModule():
28+
""" a class that describes a loaded module"""
29+
def __init__(self, ldr_object):
30+
self.ldr_object = ldr_object
31+
self.functions = None
32+
33+
class ModuleFunction():
34+
""" a class that describes an exported function"""
35+
def __init__(self, name, address):
36+
self.name = name
37+
self.address = address
38+
39+
class ThreadCallstack():
40+
""" a class that describes a threads callstack"""
41+
def __init__(self, thread):
42+
self.callstack = []
43+
self.eip = False
44+
self.bit32 = True
45+
self.thread = thread
46+
self.mal_pattern = []
47+
48+
def add_callstack_item(self, item):
49+
# adds a CallstackItem to the threads list
50+
self.callstack.append(item)
51+
return True
52+
53+
def set_bits(self, s):
54+
if s == "32":
55+
self.bits32 = True
56+
elif s == "64":
57+
self.bits32 = False
58+
59+
def parse_callstack(thread, bits32, config):
60+
# extract the threads callstack by walking saved frames
61+
62+
## ---------- 0x00001234
63+
## /--| ebp |
64+
## | ----------
65+
## | |ret_addr|
66+
## | ----------
67+
## | | data |
68+
## | ----------
69+
## | | data |
70+
## | ----------
71+
## \->| ebp |-----\
72+
## ---------- |
73+
## |ret_addr| |
74+
## ---------- |
75+
## | data | |
76+
## ---------- |
77+
## | data | |
78+
## ---------- |
79+
## | ebp |<----/
80+
## ----------
81+
## |ret_addr|
82+
## ---------- 0x0000125c
83+
84+
# for each ebp that is retreived the function saves the
85+
# data at [ebp+4] which is the return address and continues
86+
# to the next ebp.
87+
88+
# this function does not work for 64bit since building frames on the stack by pushing
89+
# rbp is not a must in the _fastcall
90+
91+
thread_callstack = ThreadCallstack(thread)
92+
trapframe = thread.Tcb.TrapFrame.dereference_as("_KTRAP_FRAME")
93+
current_ebp = 0
94+
call_address = 0
95+
ip_added = False
96+
97+
if bits32:
98+
pointer_size = 4
99+
unpack_size = "I"
100+
else:
101+
pointer_size = 8
102+
unpack_size = "Q"
103+
104+
if trapframe:
105+
address_space = thread.owning_process().get_process_address_space()
106+
if bits32:
107+
thread_callstack.set_bits("32")
108+
current_ebp = trapframe.Ebp
109+
thread_callstack.add_callstack_item(CallstackItem(trapframe.Eip, trapframe.Eip))
110+
thread_callstack.eip = True
111+
112+
113+
while current_ebp:
114+
if address_space.is_valid_address(current_ebp) and address_space.is_valid_address(current_ebp + pointer_size):
115+
call_address = struct.unpack(unpack_size, address_space.zread(current_ebp + pointer_size, pointer_size))[0]
116+
current_ebp = struct.unpack(unpack_size, address_space.zread(current_ebp, pointer_size))[0]
117+
118+
if len(thread_callstack.callstack) > 1:
119+
if current_ebp == thread_callstack.callstack[-1].frame_address:
120+
break
121+
if call_address:
122+
thread_callstack.add_callstack_item(CallstackItem(call_address, current_ebp))
123+
else:
124+
call_address = None
125+
current_ebp = None
126+
thread_callstack.callstack = parse_callstack_items_address(thread, thread_callstack.callstack, config)
127+
else:
128+
129+
thread_callstack.set_bits("64")
130+
current_ebp = trapframe.Rbp
131+
thread_callstack.add_callstack_item(CallstackItem(trapframe.Rip, trapframe.Rip))
132+
thread_callstack.eip = True
133+
134+
while current_ebp:
135+
if address_space.is_valid_address(current_ebp) and address_space.is_valid_address(current_ebp + pointer_size):
136+
call_address = struct.unpack(unpack_size, address_space.zread(current_ebp + pointer_size, pointer_size))[0]
137+
current_ebp = struct.unpack(unpack_size, address_space.zread(current_ebp, pointer_size))[0]
138+
139+
if len(thread_callstack.callstack) > 1:
140+
if current_ebp == thread_callstack.callstack[-1].frame_address:
141+
break
142+
if call_address:
143+
thread_callstack.callstack.add_callstack_item(CallstackItem(call_address, current_ebp))
144+
else:
145+
call_address = None
146+
current_ebp = None
147+
thread_callstack.callstack = parse_callstack_items_address(thread, thread_callstack.callstack, config)
148+
149+
return thread_callstack
150+
151+
def parse_callstack_items_address(thread, callstack, config):
152+
# for each callstack item eg. 0x7f801234 figure out in
153+
# which module and function the address resides
154+
155+
modules = get_thread_modules(thread, config)
156+
157+
for item in callstack:
158+
current_module = None
159+
current_function = None
160+
161+
for mod in modules:
162+
163+
if mod.ldr_object.DllBase < item.ret_address:
164+
if item.ret_address > mod.ldr_object.DllBase and item.ret_address < (mod.ldr_object.DllBase + mod.ldr_object.SizeOfImage):
165+
current_module = mod
166+
else:
167+
break
168+
169+
if current_module:
170+
item.owning_module_name = current_module.ldr_object.BaseDllName
171+
item.owning_module_address = current_module.ldr_object.DllBase
172+
173+
for function in current_module.functions:
174+
if function.address < item.ret_address:
175+
current_function = function
176+
else:
177+
break
178+
else:
179+
item.owning_module_name = "Unknown"
180+
item.owning_module_address = 0
181+
182+
if current_function:
183+
item.function = current_function
184+
else:
185+
item.function = ModuleFunction("Unknown", item.ret_address)
186+
return callstack
187+
188+
def get_module_exports(thread, mod):
189+
# retreive exports from module
190+
191+
functions = []
192+
if mod:
193+
for _, f, n in mod.exports():
194+
if n:
195+
functions.append(ModuleFunction(str(n), mod.DllBase + f))
196+
else:
197+
functions.append(ModuleFunction("Unknown", mod.DllBase + f))
198+
return functions
199+
200+
def get_thread_modules(thread, config):
201+
# get the loaded modules of the process containing the thread
202+
# this function also pays respect to already gathered modules
203+
# for increased performance
204+
205+
global kernel_modules
206+
global enumerated_processes
207+
208+
thread_modules = []
209+
user_modules = []
210+
211+
addr_space = utils.load_as(config)
212+
system_range = tasks.get_kdbg(addr_space).MmSystemRangeStart.dereference_as("Pointer")
213+
214+
if len(kernel_modules) == 0:
215+
for mod in modules.lsmod(addr_space):
216+
if mod:
217+
thread_modules.append(ThreadModule(mod))
218+
thread_modules[-1].functions = get_module_exports(thread, thread_modules[-1].ldr_object)
219+
thread_modules[-1].functions = sorted(thread_modules[-1].functions, key = lambda item: item.address)
220+
thread_modules = sorted(thread_modules, key = lambda item: item.ldr_object.DllBase)
221+
kernel_modules = thread_modules
222+
else:
223+
pass
224+
225+
owning_process = thread.owning_process()
226+
if not owning_process.is_valid():
227+
owner = None
228+
else:
229+
try:
230+
user_modules = enumerated_processes[owning_process.obj_offset]
231+
except KeyError:
232+
for mod in owning_process.get_load_modules():
233+
if mod:
234+
user_modules.append(ThreadModule(mod))
235+
user_modules[-1].functions = get_module_exports(thread, user_modules[-1].ldr_object)
236+
user_modules[-1].functions = sorted(user_modules[-1].functions, key = lambda item: item.address)
237+
user_modules = sorted(user_modules, key = lambda item: item.ldr_object.DllBase)
238+
enumerated_processes[owning_process.obj_offset] = user_modules
239+
240+
thread_modules = user_modules + kernel_modules
241+
return thread_modules
242+
243+
244+
class Callstacks(taskmods.DllList):
245+
""" this is the plugin class for callstacks """
246+
def __init__(self, config, *args, **kwargs):
247+
taskmods.DllList.__init__(self, config, *args, **kwargs)
248+
self.pidlist = None
249+
if self._config.PID is not None:
250+
try:
251+
self.pidlist = map(int, self._config.PID.split(','))
252+
except ValueError:
253+
return
254+
255+
self.bits32 = None
256+
257+
def calculate(self):
258+
thread_start_module = None
259+
thread_start_function = None
260+
# Checks that subclass AbstractThreadCheck
261+
checks = registry.get_plugin_classes(threads.AbstractThreadCheck)
262+
263+
addr_space = utils.load_as(self._config)
264+
265+
# Are we on x86 or x64. Save this for render_text
266+
self.bits32 = addr_space.profile.metadata.\
267+
get("memory_model", "32bit") == "32bit"
268+
269+
seen_threads = dict()
270+
271+
# Gather threads by list traversal of active/linked processes
272+
for task in taskmods.DllList(self._config).calculate():
273+
for thread in task.ThreadListHead.\
274+
list_of_type("_ETHREAD", "ThreadListEntry"):
275+
seen_threads[thread.obj_vm.vtop(thread.obj_offset)] = (False, thread)
276+
277+
# Now scan for threads and save any that haven't been seen
278+
for thread in modscan.ThrdScan(self._config).calculate():
279+
if not seen_threads.has_key(thread.obj_offset):
280+
seen_threads[thread.obj_offset] = (True, thread)
281+
282+
# Keep a record of processes whose DLLs we've already enumerated
283+
process_dll_info = {}
284+
285+
for _offset, (found_by_scanner, thread) in seen_threads.items():
286+
if self.pidlist:
287+
if not thread.attached_process().UniqueProcessId in self.pidlist:
288+
continue
289+
thread_callstack = parse_callstack(thread, self.bits32, self._config)
290+
291+
yield thread, addr_space, \
292+
thread_start_function, thread_callstack
293+
294+
def render_text(self, outfd, data):
295+
for thread, addr_space, \
296+
thread_start_function, thread_callstack in data:
297+
298+
s = "\n------\n\n"
299+
300+
s += "ETHREAD: {0:#010x} Pid: {1} Tid: {2}\n".format(
301+
thread.obj_offset,
302+
thread.Cid.UniqueProcess, thread.Cid.UniqueThread)
303+
304+
s += "Owning Process: {0}\n".format(
305+
thread.owning_process().ImageFileName)
306+
307+
s += "Attached Process: {0}\n".format(
308+
thread.attached_process().ImageFileName)
309+
310+
s += "Thread Flags: {0}\n".format(str(thread.CrossThreadFlags))
311+
312+
313+
314+
315+
if len(thread_callstack.callstack) > 0:
316+
317+
s += "\nCallstack:\n"
318+
if thread_callstack.eip:
319+
s += "\t{0:<8} {3:<8} {1:<8} {2}\n".format("No.", "RetAddr", "Function", "Ebp")
320+
s += "\t{0:<8} 0x{5:08x} 0x{1:08x} {2}!{3}+0x{4:<8x}\n".format("[eip]", thread_callstack.callstack[0].function.address,
321+
thread_callstack.callstack[0].owning_module_name, thread_callstack.callstack[0].function.name,
322+
thread_callstack.callstack[0].ret_address - thread_callstack.callstack[0].function.address, 0)
323+
thread_callstack.callstack.remove(thread_callstack.callstack[0])
324+
325+
i = 0
326+
for item in thread_callstack.callstack:
327+
s += "\t{0:<8} 0x{5:08x} 0x{1:08x} {2}!{3}+0x{4:<8x}\n".format("[" + str(i) + "]", item.function.address,
328+
item.owning_module_name, item.function.name,
329+
item.ret_address - item.function.address, item.frame_address)
330+
i += 1
331+
else:
332+
s += "Couldn't acquire threads _KTRAP_FRAME\n"
333+
334+
outfd.write("{0}\n".format(s))
335+

0 commit comments

Comments
 (0)