| Trees | Indices | Help |
|
|---|
|
|
1 # Rekall Memory Forensics
2 #
3 # Copyright 2016 Google Inc. All Rights Reserved.
4 #
5 # Authors:
6 # Michael Cohen <scudette@google.com>
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or (at
11 # your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful, but
14 # WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #
22
23 """ Shimcache plugin.
24
25 This code is based on work by:
26
27 # Authors:
28 # Volatility Plugin Development
29 # * Fred House - Mandiant, a FireEye Company
30 # Twitter: @0xF2EDCA5A
31 #
32 # Windows Shimcache Analysis
33 # * Andrew Davis - Mandiant, a FireEye Company
34 # * Claudiu Teodorescu - FireEye Inc.
35 # - Twitter: @cteo1
36
37 https://github.com/fireeye/Volatility-Plugins.git
38
39 and the paper:
40 https://www.fireeye.com/blog/threat-research/2015/10/shim_shady_live_inv/shim-shady-part-2.html
41 """
42 import itertools
43
44 from rekall import plugin
45 from rekall.plugins.windows import common
46
47
48 # Add overlays
49 shimcache_xp_x86 = {
50 "SHIM_CACHE_HEADER": [None, {
51 "Magic": [0, ["unsigned int"]],
52 "MaxEntries": [0x4, ["unsigned int"]],
53 "TotalEntries": [0x8, ["unsigned int"]],
54
55 "LRU": [0x10, ["Array", dict(
56 target="unsigned int",
57 count=lambda x: x.TotalEntries
58 )]],
59
60 "Entries": [0x190, ["Array", dict(
61 count=lambda x: x.TotalEntries,
62 target="SHIM_CACHE_ENTRY",
63 )]],
64 }],
65
66 "SHIM_CACHE_ENTRY" : [0x228, {
67 "Path" : [0x0, ["UnicodeString", dict(length=0x208)]],
68 "LastModified" : [0x210, ["WinFileTime"]],
69 "FileSize": [0x218, ["long long"]],
70 "LastUpdate" : [0x220, ["WinFileTime"]],
71 }],
72 }
73
74 shimcache_win7_x64 = {
75 "SHIM_CACHE_ENTRY": [None, {
76 "ListEntry" : [0x0, ["_LIST_ENTRY"]],
77 "Path" : [0x10, ["_UNICODE_STRING"]],
78 "LastModified": [0x20, ["WinFileTime"]],
79 "InsertFlags": [0x28, ["unsigned int"]],
80 "ShimFlags": [0x2c, ["unsigned int"]],
81 "BlobSize": [0x30, ["unsigned long long"]],
82 "BlobBuffer" : [0x38, ["unsigned long"]],
83 }],
84 }
85
86 shimcache_win7_x86 = {
87 "SHIM_CACHE_ENTRY": [None, {
88 "ListEntry" :[0x0, ["_LIST_ENTRY"]],
89 "Path" : [0x08, ["_UNICODE_STRING"]],
90 "LastModified" : [0x10, ["WinFileTime"]],
91 "InsertFlags": [0x18, ["unsigned int"]],
92 "ShimFlags": [0x1c, ["unsigned int"]],
93 "BlobSize": [0x20, ["unsigned long long"]],
94 "BlobBuffer" : [0x24, ["unsigned long"]],
95 }],
96 }
97
98 shimcache_win8_x64 = {
99 "SHIM_CACHE_ENTRY_DETAIL": [None, {
100 "LastModified": [0x0, ["WinFileTime"]],
101 "InsertFlags": [0x08, ["unsigned int"]],
102 "ShimFlags": [0x0c, ["unsigned int"]],
103 "BlobSize": [0x10, ["unsigned long long"]],
104 "Padding": [0x18, ["unsigned long long"]],
105 "BlobBuffer": [0x20, ["unsigned long long"]],
106 }],
107
108 "SHIM_CACHE_ENTRY": [None, {
109 "ListEntry" : [0x0, ["_LIST_ENTRY"]],
110 "Path": [0x18, ["_UNICODE_STRING"]],
111 "ListEntryDetail": [0x38, ["Pointer", dict(
112 target="SHIM_CACHE_ENTRY_DETAIL"
113 )]],
114 }],
115 }
116
117 shimcache_win8_x86 = {
118 "SHIM_CACHE_ENTRY_DETAIL": [None, {
119 "LastModified": [0x0, ["WinFileTime"]],
120 "InsertFlags": [0x08, ["unsigned int"]],
121 "ShimFlags": [0x0c, ["unsigned int"]],
122 "BlobSize": [0x10, ["unsigned long"]],
123 "BlobBuffer": [0x14, ["unsigned long"]],
124 }],
125
126 "SHIM_CACHE_ENTRY": [None, {
127 "ListEntry": [0x0, ["_LIST_ENTRY"]],
128 "Path": [0x10, ["_UNICODE_STRING"]],
129 "ListEntryDetail": [0x20, ["Pointer", dict(
130 target="SHIM_CACHE_ENTRY_DETAIL"
131 )]],
132 }],
133 }
134
135 shimcache_win10_x86 = {
136 "SHIM_CACHE_ENTRY": [None, {
137 "ListEntry" : [0x0, ["_LIST_ENTRY"]],
138 "Path": [0xc, ["_UNICODE_STRING"]],
139 "ListEntryDetail" : [0x14, ["Pointer", dict(
140 target="SHIM_CACHE_ENTRY_DETAIL"
141 )]],
142 }],
143
144 "SHIM_CACHE_ENTRY_DETAIL" : [None, {
145 "LastModified": [0x08, ["WinFileTime"]],
146 "BlobSize": [0x10, ["unsigned long"]],
147 "BlobBuffer": [0x14, ["unsigned long long"]],
148 }],
149
150 "SHIM_CACHE_HANDLE": [0x10, {
151 "eresource": [0x0, ["Pointer", dict(target="_ERESOURCE")]],
152 "avl_table": [0x8, ["Pointer", dict(target="_RTL_AVL_TABLE")]],
153 }],
154 }
155
156 shimcache_win10_x64 = {
157 "SHIM_CACHE_ENTRY": [None, {
158 "ListEntry" : [0x0, ["_LIST_ENTRY"]],
159 "Path": [0x18, ["_UNICODE_STRING"]],
160 "ListEntryDetail" : [0x28, ["Pointer", dict(
161 target="SHIM_CACHE_ENTRY_DETAIL"
162 )]],
163 }],
164
165 "SHIM_CACHE_ENTRY_DETAIL" : [None, {
166 "LastModified": [0x08, ["WinFileTime"]],
167 "BlobSize": [0x10, ["unsigned long"]],
168 "BlobBuffer": [0x18, ["unsigned long long"]],
169 }],
170
171 "SHIM_CACHE_HANDLE": [0x10, {
172 "eresource": [0x0, ["Pointer", dict(target="_ERESOURCE")]],
173 "avl_table": [0x8, ["Pointer", dict(target="_RTL_AVL_TABLE")]],
174 }],
175 }
176
177
179 profile = profile.copy()
180
181 # Windows XP 32bit
182 if 5 < profile.metadata("version") < 6:
183 if profile.metadata("arch") == "I386":
184 profile.add_overlay(shimcache_xp_x86)
185
186 # Windows 7 uses this constant to store the shimcache.
187 elif profile.get_constant("g_ShimCache"):
188 if profile.metadata("arch") == "AMD64":
189 profile.add_overlay(shimcache_win7_x64)
190 else:
191 profile.add_overlay(shimcache_win7_x86)
192
193 # Windows 8 uses a special driver to hold the cache.
194 elif profile.get_constant("AhcCacheHandle"):
195 if profile.metadata("arch") == "AMD64":
196 profile.add_overlay(shimcache_win8_x64)
197 else:
198 profile.add_overlay(shimcache_win8_x86)
199
200 # Windows 8.1 and 10 use a special driver to hold the cache.
201 elif profile.session.address_resolver.get_address_by_name("ahcache"):
202 if profile.metadata("version") < 7:
203 if profile.metadata("arch") == "AMD64":
204 profile.add_overlay(shimcache_win8_x64)
205 else:
206 profile.add_overlay(shimcache_win8_x86)
207 else:
208 if profile.metadata("arch") == "AMD64":
209 profile.add_overlay(shimcache_win10_x64)
210 else:
211 profile.add_overlay(shimcache_win10_x86)
212 else:
213 raise plugin.PluginError("Unable to identify windows version.")
214
215 return profile
216
217
219 """Extract the Application Compatibility Shim Cache from kernel memory."""
220
221 name = "shimcachemem"
222
223 table_header = [
224 dict(name="Shim", style="address"),
225 dict(name="last_mod", width=30),
226 dict(name="last_update", hidden=True),
227 dict(name="size", width=10),
228 dict(name="Path")
229 ]
230
232 """Fetch the shimcache from XP.
233
234 According to the paper, on XP the cache is in shared memory inside the
235 process winlogon.exe. The cache begins with a header and a magic value
236 of 0xDEADBEEF.
237
238 For some reason the algorithm explained in the paper seems unnecessarily
239 complex. In Rekall we just search for a handle to the ShimCacheMemory
240 section object and use it.
241 """
242 for row in self.session.plugins.handles(proc_regex="winlogon",
243 object_types="Section"):
244 if "ShimSharedMemory" in row["details"]:
245 # Found the section object.
246 section = row["_OBJECT_HEADER"].Object
247
248 # This is the process that created the shared object.
249 process_owner = section.Segment.u1.CreatingProcess.deref()
250 va = section.Segment.u2.FirstMappedVa.v()
251
252 if unicode(process_owner.name).lower() != u"winlogon.exe":
253 continue
254
255 # Switch to that process's context.
256 with self.session.plugins.cc() as cc:
257 cc.SwitchProcessContext(process_owner)
258
259 header = self.profile.SHIM_CACHE_HEADER(va)
260 return header.Entries
261
262 return []
263
265 seen = set()
266 for node in avl_table.BalancedRoot.traverse_children():
267 entry = node.payload("SHIM_CACHE_ENTRY")
268 if entry.obj_offset in seen:
269 continue
270
271 seen.add(entry.obj_offset)
272 yield entry
273
274 # Sometimes there are some entries in the linked lists too.
275 for subentry in entry.ListEntry.list_of_type(
276 "SHIM_CACHE_ENTRY", "ListEntry"):
277 if subentry.obj_offset in seen:
278 continue
279
280 seen.add(subentry.obj_offset)
281 yield subentry
282
284 avl_table = self.profile.get_constant_object(
285 "g_ShimCache", "_RTL_AVL_TABLE")
286 return self.collect_from_avl_table(avl_table)
287
289 header_pointer = self.session.address_resolver.get_constant_object(
290 "nt!AhcCacheHandle", "Pointer")
291
292 avl_table = header_pointer.dereference_as("_RTL_AVL_TABLE",
293 profile=self.profile)
294 return self.collect_from_avl_table(avl_table)
295
297 header_pointer = self.session.address_resolver.get_constant_object(
298 "ahcache!AhcCacheHandle", "Pointer")
299
300 header = header_pointer.dereference_as("SHIM_CACHE_HANDLE",
301 profile=self.profile)
302 return self.collect_from_avl_table(header.avl_table)
303
305 header_pointer = self.session.address_resolver.get_constant_object(
306 "ahcache!AhcCacheHandle", "Pointer")
307
308 header = header_pointer.dereference_as("SHIM_CACHE_HANDLE",
309 profile=self.profile)
310 return self.collect_from_avl_table(header.avl_table)
311
313 # We need this module's symbols.
314 self.session.address_resolver.track_modules("ahcache")
315
316 self.profile = AddShimProfiles(self.session.profile)
317 for entry in itertools.chain(self.collect_win10(),
318 self.collect_win8(),
319 self.collect_win8_1(),
320 self.collect_win7(),
321 self.collect_xp()):
322
323 # This field has moved around a bit between versions.
324 last_modified = entry.multi_m(
325 "LastModified",
326 "ListEntryDetail.LastModified"
327 )
328
329 yield dict(Shim=entry,
330 last_mod=last_modified,
331 last_update=entry.m("LastUpdate"),
332 size=entry.m("FileSize"),
333 Path=entry.Path)
334
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Oct 9 03:29:49 2017 | http://epydoc.sourceforge.net |