1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """Analyzes User handles registered with the Win32k Subsystem.
20
21 Windows allows user applications to register handles with the GUI subsystem. The
22 GUI subsystem can then call back into the user code for various purposes. The
23 Win32k allocates tag* structures for each user object that is registered. These
24 allocations exist on the win32k heap.
25
26 In this module we enumerate the heap and extract the tag* objects which
27 correspond to each heap allocation. This allows us to examine these allocations
28 in more detail.
29
30 One of the user handles is tagEVENTHOOK. A user application can register a hook
31 callback with SetWindowsHookEx(). This invokes a callback when an event is seen
32 (e.g. keyboard press - for a key logger) or desktop switch. Since tagEVENTHOOK
33 is just another user object, we can leverage the yser handles plugin to retrieve
34 all hooks.
35
36 References:
37 http://mista.nu/research/mandt-win32k-paper.pdf
38
39 http://volatility-labs.blogspot.de/2012/09/movp-31-detecting-malware-hooks-in.html
40 """
41
42 from rekall import obj
43 from rekall.plugins.windows import common
44 from rekall.plugins.windows.gui import constants
45 from rekall.plugins.windows.gui import win32k_core
46
47
48 -class UserHandles(win32k_core.Win32kPluginMixin,
49 common.WinProcessFilter):
50 """Dump the USER handle tables"""
51
52 name = "userhandles"
53
54 __args = [
55 dict(name="type", default=".", type="RegEx",
56 help="Filter handle type by this Regular Expression."),
57
58 dict(name="free", type="Boolean",
59 help="Also include free handles.")
60 ]
61
62 table_header = [
63 dict(name="divider", type="Divider"),
64 dict(name="SessionId", hidden=True),
65 dict(name="SharedInfo", hidden=True),
66 dict(name="_HANDLEENTRY", style="address"),
67 dict(name="_HEAD", style="address"),
68 dict(name="handle", style="address"),
69 dict(name="type", width=20),
70 dict(name="flags", width=8, align="c"),
71 dict(name="thread", width=8, align="c"),
72 dict(name="process"),
73 ]
74
102
104 current_session = None
105 for session, shared_info, handle in self.handles():
106 if current_session != session.SessionId:
107 current_session = session.SessionId
108
109 divider = (
110 "SharedInfo: {0:#x}, SessionId: {1} "
111 "Shared delta: {2}\n".format(
112 shared_info, session.SessionId,
113 shared_info.ulSharedDelta))
114
115 divider += (
116 "aheList: {0:#x}, Table size: {1:#x}, "
117 "Entry size: {2:#x}".format(
118 shared_info.aheList,
119 shared_info.psi.cbHandleTable,
120 shared_info.m("HeEntrySize") or
121 shared_info.obj_vm.profile.get_obj_size("_HANDLEENTRY")
122 ))
123
124 yield dict(divider=divider)
125
126 yield dict(SessionId=session.SessionId,
127 SharedInfo=shared_info,
128 _HANDLEENTRY=handle,
129 _HEAD=handle.phead.deref(),
130 handle=handle.phead.h or 0,
131 type=handle.bType,
132 flags=handle.bFlags,
133 thread=handle.Thread.Cid.UniqueThread,
134 process=handle.Process)
135
136
137 -class WinEventHooks(win32k_core.Win32kPluginMixin,
138 common.WinProcessFilter):
139 """Print details on windows event hooks"""
140
141 name = "eventhooks"
142
144 handle_plugin = self.session.plugins.userhandles(type="WINEVENTHOOK")
145 for session, _, handle in handle_plugin.handles():
146 renderer.section()
147
148 renderer.format(
149 "Handle: {0:#x}, Object: {1:#x}, Session: {2}\n",
150 handle.phead.h,
151 handle.phead,
152 session.SessionId)
153
154 renderer.format(
155 "Type: {0}, Flags: {1}, Thread: {2}, Process: {3} ({4})\n",
156 handle.bType,
157 handle.bFlags,
158 handle.Thread.Cid.UniqueThread,
159 handle.Process.UniqueProcessId,
160 handle.Process.name,
161 )
162
163 event_hook = handle.reference_object()
164 renderer.format(
165 "eventMin: {0:#x} {1}\neventMax: {2:#x} {3}\n",
166 event_hook.eventMin,
167 event_hook.eventMin,
168 event_hook.eventMax,
169 event_hook.eventMax,
170 )
171
172 renderer.format(
173 "Flags: {0}, offPfn: {1:#x}, idProcess: {2}, idThread: {3}\n",
174 event_hook.dwFlags,
175 event_hook.offPfn,
176 event_hook.idProcess,
177 event_hook.idThread,
178 )
179
180
181
182
183 renderer.format("ihmod: {0}\n", event_hook.ihmod)
184
185
186 -class Gahti(win32k_core.Win32kPluginMixin,
187 common.WindowsCommandPlugin):
188 """Dump the USER handle type information."""
189
190 name = "gahti"
191
192 - def gahti(self, session):
203
205 renderer.table_header(
206 [("Session", "session", ">8"),
207 ("Type", "type", "20"),
208 ("Tag", "tag", "8"),
209 ("fnDestroy", "fnDestroy", "[addrpad]"),
210 ("Flags", "flags", ""),
211 ])
212
213 for session in self.session.plugins.sessions().session_spaces():
214 for handle in self.gahti(session):
215 renderer.table_row(
216 session.SessionId,
217 handle.obj_name,
218 handle.dwAllocTag,
219 handle.fnDestroy,
220 handle.bObjectCreateFlags)
221
222
223
224 -class WinMessageHooks(win32k_core.Win32kPluginMixin,
225 common.WindowsCommandPlugin):
226 """List desktop and thread window message hooks."""
227
228 name = "messagehooks"
229
230 table_header = [
231 dict(name="tagHOOK", style="address"),
232 dict(name="session"),
233 dict(name="owner", width=30),
234 dict(name="thread", width=30),
235 dict(name="filter", width=15),
236 dict(name="flags", width=10),
237 dict(name="function", style="address"),
238 dict(name="module"),
239 ]
240
245
247 """Resolve the module name from the ihmod field.
248
249 The ihmod is an index into the array located at
250 "win32k!aatomSysLoaded". This array contains the atom number. We need to
251 use the atom number to resolve the string which is the module name.
252 """
253 atom_list = self.win32k_profile.get_constant_object(
254 "aatomSysLoaded",
255 target="Array",
256 target_args=dict(
257 target="unsigned short",
258 ),
259 vm=session.obj_vm
260 )
261
262 return atom_list[ihmod]
263
285
300
305
313
315 atoms_plugin = self.session.plugins.atoms()
316 for session in self.session.plugins.sessions().session_spaces():
317
318 global_atom_table = dict(
319 (x.Atom, x) for _, x in atoms_plugin.session_atoms(session))
320
321
322 windows_stations_plugin = self.session.plugins.windows_stations()
323 for station in windows_stations_plugin.stations_in_session(session):
324 for desktop in station.desktops():
325
326
327 for hook_name, hook in desktop.hooks():
328 module_name = self.module_name_from_hook(
329 global_atom_table, session, hook)
330
331 yield dict(tagHOOK=hook,
332 session=station.dwSessionId,
333 owner=self.get_owner_string(session, hook),
334 thread="<any>",
335 filter=hook_name,
336 flags=hook.flags,
337 function=hook.offPfn,
338 module=module_name,
339 )
340
341
342 for thrd in desktop.threads():
343 info = "{0} ({1} {2})".format(
344 thrd.pEThread.Cid.UniqueThread,
345 thrd.ppi.Process.ImageFileName,
346 thrd.ppi.Process.UniqueProcessId
347 )
348
349 for name, hook in thrd.hooks():
350 module_name = self.module_name_from_hook(
351 global_atom_table, session, hook)
352
353 yield dict(tagHOOK=hook,
354 session=session.SessionId,
355 owner=self.get_owner_string(session, hook),
356 thread=info,
357 filter=name,
358 flags=hook.flags,
359 function=hook.offPfn,
360 module=module_name,
361 )
362