Package rekall :: Package plugins :: Package windows :: Module shimcache
[frames] | no frames]

Source Code for Module rekall.plugins.windows.shimcache

  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   
178 -def AddShimProfiles(profile):
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
218 -class ShimCacheMem(common.AbstractWindowsCommandPlugin):
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
231 - def collect_xp(self):
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
264 - def collect_from_avl_table(self, avl_table):
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
283 - def collect_win7(self):
284 avl_table = self.profile.get_constant_object( 285 "g_ShimCache", "_RTL_AVL_TABLE") 286 return self.collect_from_avl_table(avl_table)
287
288 - def collect_win8(self):
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
296 - def collect_win8_1(self):
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
304 - def collect_win10(self):
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
312 - def collect(self):
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