Package rekall :: Package plugins :: Module guess_profile
[frames] | no frames]

Source Code for Module rekall.plugins.guess_profile

  1  # Rekall Memory Forensics 
  2  # Copyright (C) 2014 Michael Cohen 
  3  # Copyright 2014 Google Inc. All Rights Reserved. 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or (at 
  8  # your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, but 
 11  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 13  # General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU General Public License 
 16  # along with this program; if not, write to the Free Software 
 17  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 18  # 
 19   
 20  """This module guesses the current profile using various heuristics.""" 
 21   
 22  __author__ = "Michael Cohen <scudette@gmail.com>" 
 23   
 24  # pylint: disable=protected-access 
 25  import re 
 26   
 27  from rekall import addrspace 
 28  from rekall import cache 
 29  from rekall import config 
 30  from rekall import kb 
 31  from rekall import obj 
 32  from rekall import scan 
 33  from rekall_lib import registry 
 34  from rekall_lib import utils 
 35   
 36  from rekall.plugins.addrspaces import amd64 
 37  from rekall.plugins.addrspaces import intel 
 38  from rekall.plugins.darwin import common as darwin_common 
 39  from rekall.plugins.linux import common as linux_common 
 40  from rekall.plugins.windows import common as win_common 
 41  from rekall.plugins.overlays.windows import pe_vtypes 
 42   
 43   
44 -class DetectionMethod(object):
45 """A baseclass to implement autodetection methods.""" 46 47 __metaclass__ = registry.MetaclassRegistry 48 name = None 49 50 order = 100 51
52 - def __init__(self, session=None):
53 self.session = session
54
55 - def Offsets(self):
56 """Return a list of offsets we care about.""" 57 return []
58
59 - def Keywords(self):
60 """Returns a list of keywords which will be searched. 61 62 Each time the keyword is matched, this instance will be called to 63 attempt detection. 64 """ 65 return []
66 67 find_dtb_impl = None 68
69 - def VerifyProfile(self, profile_name):
70 """Check that the profile name is valid.""" 71 profile = self.session.LoadProfile(profile_name) 72 73 if profile != None: 74 return self._ApplyFindDTB(self.find_dtb_impl, profile)
75
76 - def _ApplyFindDTB(self, find_dtb_cls, profile):
77 """Verify profile by trying to use it to load the dtb. 78 79 If this succeeds the profile is likely correct. 80 """ 81 self.session.profile = profile 82 83 find_dtb_plugin = find_dtb_cls(session=self.session) 84 85 # Allow the dtb to be specified on the command line. 86 dtb = self.session.GetParameter("dtb") 87 if dtb: 88 # Verify the DTB to make sure it is correct. 89 if not find_dtb_plugin.VerifyHit(dtb): 90 return 91 92 address_space = find_dtb_plugin.CreateAS(dtb) 93 self.session.SetCache( 94 "default_address_space", address_space, volatile=False) 95 96 return profile 97 98 for address_space in find_dtb_plugin.address_space_hits(): 99 # Might as well cache the results of this plugin so we dont need to 100 # run it twice. 101 self.session.kernel_address_space = address_space 102 103 # Start off with a default address space of the kernel. 104 with self.session as session: 105 session.SetCache("default_address_space", address_space, 106 volatile=False) 107 session.SetCache("dtb", address_space.dtb, volatile=False) 108 109 return profile
110
111 - def DetectFromHit(self, hit, file_offset, address_space):
112 """Gets called for each hit. 113 114 If a profile matches, return it, otherwise None. 115 """
116 117 118 # By default use all detection modules. 119 config.DeclareOption("autodetect", group="Autodetection Overrides", 120 type="ChoiceArray", required=True, 121 choices=utils.JITIterator(DetectionMethod), 122 default=utils.JITIterator(DetectionMethod), 123 help="Autodetection method.") 124 125 config.DeclareOption("autodetect_threshold", default=1.0, 126 group="Autodetection Overrides", 127 help="Worst acceptable match for profile autodetection." + 128 " (Default 1.0)", 129 type="Float") 130 131 config.DeclareOption("autodetect_build_local", default="basic", 132 group="Autodetection Overrides", 133 choices=["full", "basic", "none"], 134 help="Attempts to fetch and build profile locally.", 135 type="Choices") 136 137 config.DeclareOption("autodetect_scan_length", default=2**64, 138 group="Autodetection Overrides", 139 help="How much of physical memory to scan before failing", 140 type="IntParser") 141 142
143 -class WindowsIndexDetector(DetectionMethod):
144 """Apply the windows index to detect the profile.""" 145 146 find_dtb_impl = win_common.WinFindDTB 147 148 name = "nt_index" 149
150 - def __init__(self, **kwargs):
151 super(WindowsIndexDetector, self).__init__(**kwargs) 152 153 self.eprocess_index = self.session.LoadProfile("nt/eprocess_index") 154 self.nt_index = self.session.LoadProfile("nt/index")
155
156 - def Keywords(self):
157 """We trigger when we see some common windows processes. 158 159 Since all windows processes also map the kernel we can detect it. 160 """ 161 return ["cmd.exe\x00\x00", "System\x00\x00", "csrss.exe\x00\x00", 162 "svchost.exe\x00\x00", "lsass.exe\x00\x00", 163 "winlogon.exe\x00\x00"]
164
165 - def Offsets(self):
166 return [0]
167
168 - def VerifyAMD64DTB(self, test_as):
169 """Verify this address space. 170 171 Checks that the _KUSER_SHARED_DATA makes sense. This structure is always 172 at a known offset since it must be shared with user space apps. 173 """ 174 kuser_shared = self.eprocess_index._KUSER_SHARED_DATA( 175 offset=0xFFFFF78000000000, vm=test_as) 176 177 # Must be a valid version of windows. 178 if (kuser_shared.NtMajorVersion in [5, 6, 10] and 179 kuser_shared.NtMinorVersion in [0, 1, 2, 3]): 180 return True
181
182 - def VerifyI386DTB(self, test_as):
183 """Verify this address space. 184 185 Checks that the _KUSER_SHARED_DATA makes sense. This structure is always 186 at a known offset since it must be shared with user space apps. 187 """ 188 kuser_shared = self.eprocess_index._KUSER_SHARED_DATA( 189 offset=0xffdf0000, vm=test_as) 190 191 # Must be a valid version of windows. 192 if (kuser_shared.NtMajorVersion in [5, 6, 10] and 193 kuser_shared.NtMinorVersion in [0, 1, 2, 3]): 194 return True
195
196 - def DetectWindowsDTB(self, filename_offset, address_space):
197 """Checks the possible filename hit for a valid DTB address.""" 198 for dtb_rel_offset, arch in self.eprocess_index.filename_to_dtb: 199 # We only apply indexes to 64 bit images. 200 if arch == "AMD64": 201 possible_dtb = self.eprocess_index.Object( 202 "unsigned long", offset=filename_offset - dtb_rel_offset, 203 vm=address_space).v() 204 205 # Discard impossible DTB values immediately. On 64 bit 206 # architectures, the DTB must be page aligned. 207 if not possible_dtb or possible_dtb & 0xFFF: 208 continue 209 210 test_as = amd64.AMD64PagedMemory( 211 session=self.session, base=address_space, dtb=possible_dtb) 212 if self.VerifyAMD64DTB(test_as): 213 yield test_as 214 215 elif arch == "I386": 216 possible_dtb = self.eprocess_index.Object( 217 "unsigned long", offset=filename_offset - dtb_rel_offset, 218 vm=address_space).v() 219 220 # Discard impossible DTB values immediately. On 32 bit 221 # architectures, the DTB must be aligned to 0x20 (with PAE). 222 if not possible_dtb or possible_dtb & 0x1F: 223 continue 224 225 # Only support PAE - we dont really see non PAE images any more. 226 test_as = intel.IA32PagedMemoryPae( 227 session=self.session, base=address_space, dtb=possible_dtb) 228 if self.VerifyI386DTB(test_as): 229 yield test_as
230
231 - def _match_profile_for_kernel_base(self, kernel_base, test_as):
232 threshold = self.session.GetParameter("autodetect_threshold") 233 for profile, match in self.nt_index.LookupIndex( 234 kernel_base, address_space=test_as): 235 236 if match < threshold: 237 break 238 239 profile_obj = self.session.LoadProfile(profile) 240 if profile_obj: 241 return profile_obj
242
243 - def DetectFromHit(self, hit, filename_offset, address_space):
244 # Make use of already known dtb and kernel_base parameters - this speeds 245 # up live analysis significantly since we do not need to search for 246 # anything then. 247 if filename_offset == 0: 248 if (self.session.HasParameter("dtb") and 249 self.session.HasParameter("kernel_base")): 250 test_as = amd64.AMD64PagedMemory( 251 session=self.session, base=address_space, 252 dtb=self.session.GetParameter("dtb")) 253 254 if self.VerifyAMD64DTB(test_as): 255 return self._match_profile_for_kernel_base( 256 self.session.GetParameter("kernel_base"), 257 test_as) 258 259 return 260 261 # Get potential kernel address spaces. 262 for test_as in self.DetectWindowsDTB(filename_offset, address_space): 263 # Try to find the kernel base. This can be improved in future by 264 # taking more than a single search point. 265 scanner = scan.MultiStringScanner( 266 address_space=test_as, needles=[ 267 "This program cannot be run in DOS mode", 268 ]) 269 270 if self.session.HasParameter("kernel_base"): 271 kernel_base = self.session.GetParameter("kernel_base") 272 return self._match_profile_for_kernel_base( 273 kernel_base, test_as) 274 275 for offset, _ in scanner.scan( 276 offset=0xF80000000000, maxlen=0x10000000000): 277 kernel_base = offset & 0xFFFFFFFFFFFFFF000 278 profile_obj = self._match_profile_for_kernel_base( 279 kernel_base, test_as) 280 281 if profile_obj: 282 return profile_obj
283 284
285 -class PEImageFileDetector(DetectionMethod):
286 287 name = "pe" 288 order = 50 289
290 - def __init__(self, **kwargs):
291 super(PEImageFileDetector, self).__init__(**kwargs) 292 self.pe_profile = self.session.LoadProfile("pe")
293
294 - def Offsets(self):
295 # We only care about the first offset in the file. 296 return [0]
297
298 - def DetectFromHit(self, hit, _, address_space):
299 # If the file is a PE file, we simply return the PE address space. 300 if self.pe_profile._IMAGE_DOS_HEADER(vm=address_space).NTHeader: 301 pe_as = pe_vtypes.PEFileAddressSpace( 302 base=address_space, profile=self.pe_profile) 303 304 self.session.kernel_address_space = pe_as 305 self.session.SetCache("default_image_base", pe_as.image_base) 306 307 machine_type = pe_as.nt_header.FileHeader.Machine 308 if machine_type == "IMAGE_FILE_MACHINE_AMD64": 309 self.pe_profile.set_metadata("arch", "AMD64") 310 else: 311 self.pe_profile.set_metadata("arch", "I386") 312 313 return self.pe_profile
314 315
316 -class WindowsRSDSDetector(DetectionMethod):
317 """A detection method based on the scanning for RSDS signatures.""" 318 319 name = "rsds" 320 order = 90 321 322 # Windows kernel pdb files. 323 KERNEL_NAMES = win_common.KERNEL_NAMES 324 325 find_dtb_impl = win_common.WinFindDTB 326
327 - def __init__(self, **kwargs):
328 super(WindowsRSDSDetector, self).__init__(**kwargs) 329 self.pe_profile = self.session.LoadProfile("pe")
330
331 - def Keywords(self):
332 return ["RSDS"]
333
334 - def Offsets(self):
335 return [0]
336
337 - def VerifyProfile(self, profile_name):
338 profile = self.session.LoadProfile(profile_name) 339 340 # If the user allows it we can just try to fetch and build the profile 341 # locally. 342 if profile == None and self.session.GetParameter( 343 "autodetect_build_local") in ("full", "basic"): 344 build_local_profile = self.session.plugins.build_local_profile() 345 try: 346 self.session.logging.debug( 347 "Will build local profile %s", profile_name) 348 build_local_profile.fetch_and_parse(profile_name) 349 profile = self.session.LoadProfile( 350 profile_name, use_cache=False) 351 352 except IOError: 353 pass 354 355 if profile != None: 356 return self._ApplyFindDTB(self.find_dtb_impl, profile)
357
358 - def DetectFromHit(self, hit, offset, address_space):
359 # Make use of already known dtb and kernel_base parameters - this speeds 360 # up live analysis significantly since we do not need to search for 361 # anything then. 362 if (offset == 0 and self.session.HasParameter("dtb") and 363 self.session.HasParameter("kernel_base")): 364 test_as = amd64.AMD64PagedMemory( 365 session=self.session, base=address_space, 366 dtb=self.session.GetParameter("dtb")) 367 368 pe_helper = pe_vtypes.PE( 369 session=self.session, 370 address_space=test_as, 371 image_base=self.session.GetParameter("kernel_base")) 372 373 return self._test_rsds(pe_helper.RSDS) 374 375 # Try Windows by GUID: 376 rsds = self.pe_profile.CV_RSDS_HEADER(offset=offset, vm=address_space) 377 return self._test_rsds(rsds)
378
379 - def _test_rsds(self, rsds):
380 if (rsds.Signature.is_valid() and 381 str(rsds.Filename) in self.KERNEL_NAMES): 382 profile = self.VerifyProfile("nt/GUID/%s" % rsds.GUID_AGE) 383 384 if profile: 385 self.session.logging.info( 386 "Detected %s with GUID %s", rsds.Filename, 387 rsds.GUID_AGE) 388 389 return profile
390 391
392 -class WindowsKernelImageDetector(WindowsRSDSDetector):
393 name = "windows_kernel_file" 394 order = 50 395
396 - def Offsets(self):
397 return [0]
398 399 KERNEL_PATHS = [r"C:\Windows\SysNative\ntoskrnl.exe", 400 r"C:\Windows\System32\ntoskrnl.exe"] 401
402 - def DetectFromHit(self, hit, _, address_space):
403 for potential_path in self.KERNEL_PATHS: 404 # Try to make the kernel image into the address_space. 405 image_offset = address_space.get_mapped_offset(potential_path, 0) 406 407 if image_offset is not None: 408 file_as = addrspace.RunBasedAddressSpace( 409 base=address_space, session=self.session) 410 file_as.add_run(0, image_offset, 2**63) 411 412 pe_file_as = pe_vtypes.PEFileAddressSpace( 413 base=file_as, session=self.session) 414 415 pe_helper = pe_vtypes.PE( 416 session=self.session, 417 address_space=pe_file_as, 418 image_base=pe_file_as.image_base) 419 420 rsds = pe_helper.RSDS 421 self.session.logging.info( 422 "Found RSDS in kernel image: %s (%s)", 423 rsds.GUID_AGE, rsds.Filename) 424 result = self._test_rsds(rsds) 425 if result: 426 return result
427 428
429 -class LinuxIndexDetector(DetectionMethod):
430 """A kernel detector that uses live symbols to do exact matching. 431 432 LinuxIndexDetector uses kallsyms (or any other source of live symbols) to 433 match a kernel exactly by finding known-unique symbols. 434 """ 435 436 name = "linux_index" 437 438 439 find_dtb_impl = linux_common.LinuxFindDTB 440
441 - def __init__(self, **kwargs):
442 super(LinuxIndexDetector, self).__init__(**kwargs) 443 self.index = self.session.LoadProfile("Linux/index")
444
445 - def Offsets(self):
446 return [0]
447
448 - def DetectFromHit(self, hit, offset, address_space):
449 if offset != 0: 450 return 451 452 self.session.logging.debug( 453 "LinuxIndexDetector:DetectFromHit(%x) = %s", offset, hit) 454 455 kaslr_reader = linux_common.KAllSyms(self.session) 456 457 # We create a dictionary of symbol:offset skipping symbols from 458 # exported modules. 459 symbol_dict = {} 460 for offset, symbol, _, module in kaslr_reader.ObtainSymbols(): 461 # Ignore symbols in modules we only care about the kernel. 462 if not module: 463 symbol_dict[symbol] = offset 464 465 if not symbol_dict: 466 return 467 468 matching_profiles = self.index.LookupProfile(symbol_dict) 469 if len(matching_profiles) > 1: 470 self.session.logging.info( 471 "LinuxIndexDetector found %d matching profiles: %s", 472 len(matching_profiles), 473 ', '.join([p[0] for p in matching_profiles])) 474 return 475 elif len(matching_profiles) == 1: 476 profile_id = matching_profiles[0][0] 477 self.session.logging.info( 478 "LinuxIndexDetector found profile %s with %d/%d matches.", 479 profile_id, 480 matching_profiles[0][1], 481 len(self.index.traits[profile_id])) 482 483 profile = self.session.LoadProfile(profile_id) 484 if profile: 485 # At this point we also know the kernel slide. 486 kallsyms_proc_banner = symbol_dict["linux_proc_banner"] 487 profile_proc_banner = profile.get_constant("linux_proc_banner", 488 is_address=False) 489 kernel_slide = kallsyms_proc_banner - profile_proc_banner 490 self.session.logging.info("Found slide 0x%x", kernel_slide) 491 self.session.SetCache("kernel_slide", kernel_slide) 492 493 verified_profile = self.VerifyProfile(profile) 494 if verified_profile: 495 return verified_profile 496 else: 497 self.session.SetCache("kernel_slide", None) 498 # If we were unable to find a matching Linux profile, we limit the scan 499 # length to prevent Rekall from spinning for a long time. 500 self.session.logging.warn("LinuxIndexDetector found no matches.") 501 self._LimitScanLength()
502
503 - def _LimitScanLength(self):
504 self.session.SetParameter("autodetect_scan_length", 1024*1024*1024)
505 506
507 -class LinuxBannerDetector(DetectionMethod):
508 """Detect a linux kernel from its banner text.""" 509 510 name = "linux" 511 512 LINUX_TEMPLATE = re.compile( 513 r"Linux version (\d+\.\d+\.\d+[^ ]+)") 514 515 find_dtb_impl = linux_common.LinuxFindDTB 516
517 - def Keywords(self):
518 # The Linux kernels we care about contain this. 519 return ["Linux version "]
520
521 - def DetectFromHit(self, hit, offset, address_space):
522 guess = address_space.read(offset - 100, 300) 523 m = self.LINUX_TEMPLATE.search(guess) 524 if m: 525 # Try to guess the distribution. 526 distribution = "LinuxGeneric" 527 if "Ubuntu" in guess: 528 distribution = "Ubuntu" 529 530 if "Debian" in guess: 531 distribution = "Debian" 532 533 profile_name = "%s/%s" % (distribution, m.group(1)) 534 profile = self.session.LoadProfile(profile_name) 535 if profile: 536 self.session.logging.info( 537 "Detected %s: %s", profile_name, m.group(0)) 538 else: 539 return 540 541 # At this point we should know the kernel slide. 542 profile_proc_banner = profile.get_constant("linux_banner", 543 is_address=False) 544 expected_proc_banner = profile.phys_addr(profile_proc_banner) 545 kernel_slide = offset - expected_proc_banner 546 self.session.logging.info("Found slide 0x%x", kernel_slide) 547 self.session.SetCache("kernel_slide", kernel_slide) 548 verified_profile = self.VerifyProfile(profile) 549 if not verified_profile: 550 self.session.SetCache("kernel_slide", None) 551 552 return verified_profile
553 554
555 -class DarwinIndexDetector(DetectionMethod):
556 """Detect the Darwin version using the index. 557 558 To work around KASLR, we have an index of known symbols' offsets relative to 559 the Catfish string, along with the data we expect to find at those 560 offsets. Profile similarity is the percentage of these symbols that match as 561 expected. 562 563 Ideally, we'd like a 100% match, but in case we don't have the exact 564 profile, we'll make do with anything higher than 0% that can resolve the 565 DTB. 566 """ 567 name = "osx" 568 569 find_dtb_impl = darwin_common.DarwinFindDTB 570
571 - def __init__(self, **kwargs):
572 super(DarwinIndexDetector, self).__init__(**kwargs) 573 self.index = self.session.LoadProfile("OSX/index")
574
575 - def Keywords(self):
576 # Found in every OS X image. See documentation for DarwinFindKASLR for 577 # details. 578 return ["Catfish \x00\x00"]
579
580 - def DetectFromHit(self, hit, offset, address_space):
581 for profile_name, match in self.index.LookupIndex( 582 image_base=offset, 583 address_space=self.session.physical_address_space): 584 profile = self.VerifyProfile(profile_name) 585 if profile: 586 self.session.logging.info( 587 "New best match: %s (%.0f%% match)", 588 profile_name, match * 100) 589 590 self.session.SetCache("catfish_offset", offset, volatile=False) 591 592 return profile
593 594
595 -class KernelASHook(kb.ParameterHook):
596 """A ParameterHook for default_address_space. 597 598 This will only be called if default_address_space is not set. We load the 599 kernel address space, or load it if needed. 600 """ 601 name = "default_address_space" 602 603 volatile = False 604
605 - def calculate(self):
606 if self.session.kernel_address_space: 607 return self.session.kernel_address_space 608 609 try: 610 return self.session.plugins.load_as().GetVirtualAddressSpace() 611 except Exception: 612 return obj.NoneObject("Address space not found")
613 614
615 -class ProfileHook(kb.ParameterHook):
616 """If the profile is not specified, we guess it.""" 617 name = "profile_obj" 618 619 volatile = False 620
621 - def ScanProfiles(self):
622 try: 623 self.session.SetCache("execution_phase", "ProfileAutodetect") 624 return self._ScanProfiles() 625 finally: 626 self.session.SetCache("execution_phase", None)
627
628 - def _ScanProfiles(self):
629 address_space = self.session.physical_address_space 630 best_profile = None 631 best_match = 0 632 633 methods = [] 634 needles = [] 635 needle_lookup = {} 636 637 method_names = self.session.GetParameter("autodetect") 638 639 self.session.logging.debug( 640 "Will detect profile using these Detectors: %s" % ",".join( 641 method_names)) 642 643 if not method_names: 644 raise RuntimeError("No autodetection methods specified. " 645 "Use the --autodetect parameter.") 646 647 for method_name in method_names: 648 for method in DetectionMethod.classes_by_name[method_name]: 649 methods.append(method(session=self.session)) 650 651 methods.sort(key=lambda x: x.order) 652 for method in methods: 653 for keyword in method.Keywords(): 654 needles.append(keyword) 655 needle_lookup.setdefault(keyword, []).append(method) 656 657 for offset in method.Offsets(): 658 self.session.logging.debug("Trying method %s, offset %d", 659 method.name, offset) 660 profile = method.DetectFromHit(None, offset, address_space) 661 if profile: 662 self.session.logging.info( 663 "Detection method %s yielded profile %s", 664 method.name, profile) 665 return profile 666 667 # 10 GB by default. 668 autodetect_scan_length = self.session.GetParameter( 669 "autodetect_scan_length", 10*1024*1024*1024) 670 671 # Build and configure the scanner. 672 scanner = scan.MultiStringScanner( 673 profile=obj.NoneObject(), 674 address_space=address_space, needles=needles, 675 session=self.session) 676 scanner.progress_message = "Autodetecting profile: %(offset)#08x" 677 for offset, hit in scanner.scan(maxlen=autodetect_scan_length): 678 self.session.render_progress( 679 "guess_profile: autodetection hit @ %x - %s", offset, hit) 680 681 for method in needle_lookup[hit]: 682 profile = method.DetectFromHit(hit, offset, address_space) 683 if profile: 684 self.session.logging.debug( 685 "Detection method %s worked at offset %#x", 686 method.name, offset) 687 return profile 688 689 if best_match == 1.0: 690 # If we have an exact match we can stop scanning. 691 break 692 693 threshold = self.session.GetParameter("autodetect_threshold") 694 if best_match == 0: 695 self.session.logging.error( 696 "No profiles match this image. Try specifying manually.") 697 698 return obj.NoneObject("No profile detected") 699 700 elif best_match < threshold: 701 self.session.logging.error( 702 "Best match for profile is %s with %.0f%%, which is too low " + 703 "for given threshold of %.0f%%. Try lowering " + 704 "--autodetect-threshold.", 705 best_profile.name, 706 best_match * 100, 707 threshold * 100) 708 709 return obj.NoneObject("No profile detected") 710 711 else: 712 self.session.logging.info( 713 "Profile %s matched with %.0f%% confidence.", 714 best_profile.name, 715 best_match * 100) 716 717 return best_profile
718
719 - def calculate(self):
720 """Try to find the correct profile by scanning for PDB files.""" 721 # Clear the profile for the duration of the scan. 722 self.session.profile = obj.NoneObject("Unset") 723 if not self.session.physical_address_space: 724 # Try to load the physical_address_space so we can scan it. 725 if not self.session.plugins.load_as().GetPhysicalAddressSpace(): 726 # If a filename was specified this should have worked, unless we 727 # could not open it. 728 filename = self.session.GetParameter("filename") 729 if filename: 730 raise RuntimeError( 731 "Unable to instantiate physical_address_space from " 732 "filename %s." % filename) 733 734 # No physical address space - nothing to do here. 735 return obj.NoneObject("No Physical Address Space.") 736 737 # If the global cache is persistent we try to detect this image by 738 # fingerprint if we have seen it before. 739 if self.session.cache.__class__ == cache.FileCache: 740 name = self.session.cache.DetectImage( 741 self.session.physical_address_space) 742 if name: 743 self.session.logging.info( 744 "Detected fingerprinted image %s", name) 745 746 # Allow the user to specify the profile to use on the command line. 747 profile_name = self.session.GetParameter("profile") 748 if profile_name: 749 profile_obj = self.session.LoadProfile(profile_name) 750 if profile_obj != None: 751 return profile_obj 752 753 # Is the profile object already cached? 754 profile_obj = self.session.cache.Get("profile_obj") 755 if not profile_obj: 756 profile_obj = self.ScanProfiles() 757 if not profile_obj: 758 raise RuntimeError( 759 "Unable to find a valid profile for this image. " 760 "Try using -v for more details.") 761 762 # Update the session profile. 763 self.session.profile = profile_obj 764 765 if (self.session.GetParameter("cache") == "file" and 766 self.session.HasParameter("image_fingerprint")): 767 self.session.cache.SetFingerprint( 768 self.session.GetParameter("image_fingerprint")) 769 770 return profile_obj
771