Package modules :: Package processing :: Module memory
[hide private]
[frames] | no frames]

Source Code for Module modules.processing.memory

   1  # Copyright (C) 2010-2013 Claudio Guarnieri. 
   2  # Copyright (C) 2014-2016 Cuckoo Foundation. 
   3  # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org 
   4  # See the file 'docs/LICENSE' for copying permission. 
   5   
   6  import os 
   7  import logging 
   8  import time 
   9   
  10  from lib.cuckoo.common.abstracts import Processing 
  11  from lib.cuckoo.common.config import Config 
  12  from lib.cuckoo.common.constants import CUCKOO_ROOT 
  13   
  14  log = logging.getLogger(__name__) 
  15   
  16  try: 
  17      import volatility.conf as conf 
  18      import volatility.registry as registry 
  19      import volatility.commands as commands 
  20      import volatility.utils as utils 
  21      import volatility.plugins.malware.devicetree as devicetree 
  22      import volatility.plugins.malware.apihooks as apihooks 
  23      import volatility.plugins.getsids as sidm 
  24      import volatility.plugins.privileges as privm 
  25      import volatility.plugins.taskmods as taskmods 
  26      import volatility.win32.tasks as tasks 
  27      import volatility.obj as obj 
  28      import volatility.exceptions as exc 
  29      import volatility.plugins.filescan as filescan 
  30      import volatility.protos as protos 
  31   
  32      HAVE_VOLATILITY = True 
  33   
  34      # Inherit Cuckoo debugging level for Volatility commands. 
  35      rootlogger = logging.getLogger() 
  36      logging.getLogger("volatility.obj").setLevel(rootlogger.level) 
  37      logging.getLogger("volatility.utils").setLevel(rootlogger.level) 
  38  except ImportError as e: 
  39      if e.message == "No module named Crypto.Hash": 
  40          log.error( 
  41              "The PyCrypto package is missing (install with " 
  42              "`pip install pycrypto`)" 
  43          ) 
  44   
  45      HAVE_VOLATILITY = False 
  46   
47 -class VolatilityAPI(object):
48 """ Volatility API interface.""" 49
50 - def __init__(self, memdump, osprofile=None):
51 """@param memdump: the memdump file path 52 @param osprofile: the profile (OS type) 53 """ 54 registry.PluginImporter() 55 self.memdump = memdump 56 self.osprofile = osprofile 57 self.config = None 58 self.addr_space = None 59 self.init_config()
60
61 - def get_dtb(self):
62 """Use psscan to get system dtb and apply it.""" 63 ps = filescan.PSScan(self.config) 64 65 for ep in ps.calculate(): 66 if str(ep.ImageFileName) == "System": 67 self.config.update("dtb", ep.Pcb.DirectoryTableBase) 68 return True 69 70 return False
71
72 - def init_config(self):
73 """Creates a volatility configuration.""" 74 if self.config is not None and self.addr_space is not None: 75 return self.config 76 77 self.config = conf.ConfObject() 78 self.config.optparser.set_conflict_handler("resolve") 79 registry.register_global_options(self.config, commands.Command) 80 base_conf = { 81 "profile": "WinXPSP2x86", 82 "use_old_as": None, 83 "kdbg": None, 84 "help": False, 85 "kpcr": None, 86 "tz": None, 87 "pid": None, 88 "output_file": None, 89 "physical_offset": None, 90 "conf_file": None, 91 "dtb": None, 92 "output": None, 93 "info": None, 94 "location": "file://" + self.memdump, 95 "plugins": None, 96 "debug": None, 97 "cache_dtb": True, 98 "filename": None, 99 "cache_directory": None, 100 "verbose": None, 101 "write": False 102 } 103 104 if self.osprofile: 105 base_conf["profile"] = self.osprofile 106 107 for key, value in base_conf.items(): 108 self.config.update(key, value) 109 110 # Deal with Volatility support for KVM/qemu memory dump. 111 # See: #464. 112 try: 113 self.addr_space = utils.load_as(self.config) 114 except exc.AddrSpaceError: 115 if self.get_dtb(): 116 self.addr_space = utils.load_as(self.config) 117 else: 118 raise 119 120 self.plugins = \ 121 registry.get_plugin_classes(commands.Command, lower=True) 122 return self.config
123
124 - def pslist(self):
125 """Volatility pslist plugin. 126 @see volatility/plugins/taskmods.py 127 """ 128 results = [] 129 130 command = taskmods.PSList(self.config) 131 for process in command.calculate(): 132 new = { 133 "process_name": str(process.ImageFileName), 134 "process_id": int(process.UniqueProcessId), 135 "parent_id": int(process.InheritedFromUniqueProcessId), 136 "num_threads": str(process.ActiveThreads), 137 "num_handles": str(process.ObjectTable.HandleCount), 138 "session_id": str(process.SessionId), 139 "create_time": str(process.CreateTime or ""), 140 "exit_time": str(process.ExitTime or ""), 141 } 142 143 results.append(new) 144 145 return dict(config={}, data=results)
146
147 - def psxview(self):
148 """Volatility psxview plugin. 149 @see volatility/plugins/malware/psxview.py 150 """ 151 results = [] 152 153 command = self.plugins["psxview"](self.config) 154 for offset, process, ps_sources in command.calculate(): 155 new = { 156 "process_name": str(process.ImageFileName), 157 "process_id": int(process.UniqueProcessId), 158 "pslist": str(offset in ps_sources["pslist"]), 159 "psscan": str(offset in ps_sources["psscan"]), 160 "thrdproc": str(offset in ps_sources["thrdproc"]), 161 "pspcid": str(offset in ps_sources["pspcid"]), 162 "csrss": str(offset in ps_sources["csrss"]), 163 "session": str(offset in ps_sources["session"]), 164 "deskthrd": str(offset in ps_sources["deskthrd"]), 165 } 166 167 results.append(new) 168 169 return dict(config={}, data=results)
170
171 - def callbacks(self):
172 """Volatility callbacks plugin. 173 @see volatility/plugins/malware/callbacks.py 174 """ 175 results = [] 176 177 command = self.plugins["callbacks"](self.config) 178 for (sym, cb, detail), mods, mod_addrs in command.calculate(): 179 module = tasks.find_module(mods, mod_addrs, self.addr_space.address_mask(cb)) 180 181 if module: 182 module_name = module.BaseDllName or module.FullDllName 183 else: 184 module_name = "UNKNOWN" 185 186 new = { 187 "type": str(sym), 188 "callback": hex(int(cb)), 189 "module": str(module_name), 190 "details": str(detail or "-"), 191 } 192 193 results.append(new) 194 195 return dict(config={}, data=results)
196
197 - def idt(self):
198 """Volatility idt plugin. 199 @see volatility/plugins/malware/idt.py 200 """ 201 results = [] 202 203 command = self.plugins["idt"](self.config) 204 for n, entry, addr, module in command.calculate(): 205 if module: 206 module_name = str(module.BaseDllName or "") 207 sect_name = command.get_section_name(module, addr) 208 else: 209 module_name = "UNKNOWN" 210 sect_name = '' 211 212 # The parent is IDT. The grand-parent is _KPCR. 213 cpu_number = entry.obj_parent.obj_parent.ProcessorBlock.Number 214 new = { 215 "cpu_number": int(cpu_number), 216 "index": int(n), 217 "selector": hex(int(entry.Selector)), 218 "address": hex(int(addr)), 219 "module": module_name, 220 "section": sect_name, 221 } 222 results.append(new) 223 224 return dict(config={}, data=results)
225
226 - def gdt(self):
227 """Volatility gdt plugin. 228 @see volatility/plugins/malware/idt.py 229 """ 230 results = [] 231 232 command = self.plugins["gdt"](self.config) 233 # Comment: this code is pretty much ripped from render_text in volatility. 234 for n, entry in command.calculate(): 235 selector = n * 8 236 237 # Is the entry present? This applies to all types of GDT entries 238 if entry.Present: 239 present = "P" 240 else: 241 present = "Np" 242 243 # The base, limit, and granularity is calculated differently 244 # for 32bit call gates than they are for all other types. 245 if entry.Type == "CallGate32": 246 base = entry.CallGate 247 limit = 0 248 granularity = "-" 249 else: 250 base = entry.Base 251 limit = entry.Limit 252 if entry.Granularity: 253 granularity = "Pg" 254 else: 255 granularity = "By" 256 257 # The parent is GDT. The grand-parent is _KPCR. 258 cpu_number = entry.obj_parent.obj_parent.ProcessorBlock.Number 259 260 new = { 261 "cpu_number": int(cpu_number), 262 "selector": hex(selector), 263 "base": hex(int(base)), 264 "limit": hex(int(limit)), 265 "type": str(entry.Type), 266 "dpl": str(entry.Dpl), 267 "granularity": granularity, 268 "present": present, 269 } 270 results.append(new) 271 272 return dict(config={}, data=results)
273
274 - def ssdt(self):
275 """Volatility ssdt plugin. 276 @see volatility/plugins/ssdt.py 277 """ 278 results = [] 279 280 command = self.plugins["ssdt"](self.config) 281 282 # Comment: this code is pretty much ripped from render_text in volatility. 283 addr_space = self.addr_space 284 syscalls = addr_space.profile.syscalls 285 bits32 = addr_space.profile.metadata.get("memory_model", "32bit") == "32bit" 286 287 for idx, table, n, vm, mods, mod_addrs in command.calculate(): 288 for i in range(n): 289 if bits32: 290 # These are absolute function addresses in kernel memory. 291 syscall_addr = obj.Object("address", table + (i * 4), vm).v() 292 else: 293 # These must be signed long for x64 because they are RVAs relative 294 # to the base of the table and can be negative. 295 offset = obj.Object("long", table + (i * 4), vm).v() 296 # The offset is the top 20 bits of the 32 bit number. 297 syscall_addr = table + (offset >> 4) 298 299 try: 300 syscall_name = syscalls[idx][i] 301 except IndexError: 302 syscall_name = "UNKNOWN" 303 304 syscall_mod = tasks.find_module(mods, mod_addrs, addr_space.address_mask(syscall_addr)) 305 if syscall_mod: 306 syscall_modname = "{0}".format(syscall_mod.BaseDllName) 307 else: 308 syscall_modname = "UNKNOWN" 309 310 new = { 311 "index": int(idx), 312 "table": "0x%x" % int(table), 313 "entry": "{0:#06x}".format(idx * 0x1000 + i), 314 "syscall_name": syscall_name, 315 "syscall_addr": "0x%x" % int(syscall_addr), 316 "syscall_modname": syscall_modname, 317 } 318 319 if bits32 and syscall_mod is not None: 320 ret = apihooks.ApiHooks.check_inline( 321 va=syscall_addr, addr_space=vm, 322 mem_start=syscall_mod.DllBase, 323 mem_end=syscall_mod.DllBase + syscall_mod.SizeOfImage) 324 325 # Could not analyze the memory. 326 if ret is not None: 327 hooked, data, dest_addr = ret 328 if hooked: 329 # We found a hook, try to resolve the hooker. 330 # No mask required because we currently only work 331 # on x86 anyway. 332 hook_mod = tasks.find_module(mods, mod_addrs, 333 dest_addr) 334 if hook_mod: 335 hook_name = "{0}".format(hook_mod.BaseDllName) 336 else: 337 hook_name = "UNKNOWN" 338 339 # Report it now. 340 new.update({ 341 "hook_dest_addr": "{0:#x}".format(dest_addr), 342 "hook_name": hook_name, 343 }) 344 345 results.append(new) 346 347 return dict(config={}, data=results)
348
349 - def timers(self):
350 """Volatility timers plugin. 351 @see volatility/plugins/malware/timers.py 352 """ 353 results = [] 354 355 command = self.plugins["timers"](self.config) 356 for timer, module in command.calculate(): 357 if timer.Header.SignalState.v(): 358 signaled = "Yes" 359 else: 360 signaled = "-" 361 362 if module: 363 module_name = str(module.BaseDllName or "") 364 else: 365 module_name = "UNKNOWN" 366 367 due_time = "{0:#010x}:{1:#010x}".format(timer.DueTime.HighPart, timer.DueTime.LowPart) 368 369 new = { 370 "offset": hex(timer.obj_offset), 371 "due_time": due_time, 372 "period": int(timer.Period), 373 "signaled": signaled, 374 "routine": hex(int(timer.Dpc.DeferredRoutine)), 375 "module": module_name, 376 } 377 results.append(new) 378 379 return dict(config={}, data=results)
380
381 - def messagehooks(self):
382 """Volatility messagehooks plugin. 383 @see volatility/plugins/malware/messagehooks.py 384 """ 385 results = [] 386 387 command = self.plugins["messagehooks"](self.config) 388 for winsta, atom_tables in command.calculate(): 389 for desk in winsta.desktops(): 390 for name, hook in desk.hooks(): 391 module = command.translate_hmod(winsta, atom_tables, hook.ihmod) 392 new = { 393 "offset": hex(int(hook.obj_offset)), 394 "session": int(winsta.dwSessionId), 395 "desktop": "{0}\\{1}".format(winsta.Name, desk.Name), 396 "thread": "<any>", 397 "filter": str(name), 398 "flags": str(hook.flags), 399 "function": hex(int(hook.offPfn)), 400 "module": str(module), 401 } 402 results.append(new) 403 404 for thrd in desk.threads(): 405 info = "{0} ({1} {2})".format( 406 thrd.pEThread.Cid.UniqueThread, 407 thrd.ppi.Process.ImageFileName, 408 thrd.ppi.Process.UniqueProcessId) 409 410 for name, hook in thrd.hooks(): 411 module = command.translate_hmod(winsta, atom_tables, hook.ihmod) 412 413 new = { 414 "offset": hex(int(hook.obj_offset)), 415 "session": int(winsta.dwSessionId), 416 "desktop": "{0}\\{1}".format(winsta.Name, desk.Name), 417 "thread": str(info), 418 "filter": str(name), 419 "flags": str(hook.flags), 420 "function": hex(int(hook.offPfn)), 421 "module": str(module), 422 } 423 results.append(new) 424 425 return dict(config={}, data=results)
426
427 - def getsids(self):
428 """Volatility getsids plugin. 429 @see volatility/plugins/malware/getsids.py 430 """ 431 results = [] 432 433 command = self.plugins["getsids"](self.config) 434 for task in command.calculate(): 435 token = task.get_token() 436 437 if not token: 438 continue 439 440 for sid_string in token.get_sids(): 441 if sid_string in sidm.well_known_sids: 442 sid_name = " {0}".format(sidm.well_known_sids[sid_string]) 443 else: 444 sid_name_re = sidm.find_sid_re(sid_string, sidm.well_known_sid_re) 445 if sid_name_re: 446 sid_name = " {0}".format(sid_name_re) 447 else: 448 sid_name = "" 449 450 new = { 451 "filename": str(task.ImageFileName), 452 "process_id": int(task.UniqueProcessId), 453 "sid_string": str(sid_string), 454 "sid_name": str(sid_name), 455 } 456 results.append(new) 457 458 return dict(config={}, data=results)
459
460 - def privs(self):
461 """Volatility privs plugin. 462 @see volatility/plugins/malware/privs.py 463 """ 464 results = [] 465 466 command = self.plugins["privs"](self.config) 467 468 for task in command.calculate(): 469 for value, present, enabled, default in task.get_token().privileges(): 470 try: 471 name, desc = privm.PRIVILEGE_INFO[int(value)] 472 except KeyError: 473 continue 474 475 attributes = [] 476 if present: 477 attributes.append("Present") 478 if enabled: 479 attributes.append("Enabled") 480 if default: 481 attributes.append("Default") 482 483 new = { 484 "process_id": int(task.UniqueProcessId), 485 "filename": str(task.ImageFileName), 486 "value": int(value), 487 "privilege": str(name), 488 "attributes": ",".join(attributes), 489 "description": str(desc), 490 } 491 results.append(new) 492 493 return dict(config={}, data=results)
494
495 - def malfind(self, dump_dir=None):
496 """Volatility malfind plugin. 497 @param dump_dir: optional directory for dumps 498 @see volatility/plugins/malware/malfind.py 499 """ 500 results = [] 501 502 command = self.plugins["malfind"](self.config) 503 for task in command.calculate(): 504 for vad, address_space in task.get_vads(vad_filter=task._injection_filter): 505 if command._is_vad_empty(vad, address_space): 506 continue 507 508 new = { 509 "process_name": str(task.ImageFileName), 510 "process_id": int(task.UniqueProcessId), 511 "vad_start": "{0:#x}".format(vad.Start), 512 "vad_tag": str(vad.Tag), 513 } 514 results.append(new) 515 516 if dump_dir: 517 filename = os.path.join(dump_dir, "process.{0:#x}.{1:#x}.dmp".format(task.obj_offset, vad.Start)) 518 command.dump_vad(filename, vad, address_space) 519 520 return dict(config={}, data=results)
521
522 - def yarascan(self):
523 """Volatility yarascan plugin. 524 @see volatility/plugins/malware/yarascan.py 525 """ 526 results = [] 527 528 ypath = os.path.join(CUCKOO_ROOT, "data", "yara", "index_memory.yar") 529 if not os.path.exists(ypath): 530 return dict(config={}, data=[]) 531 532 self.config.update("YARA_FILE", ypath) 533 534 command = self.plugins["yarascan"](self.config) 535 for o, addr, hit, content in command.calculate(): 536 # Comment: this code is pretty much ripped from render_text in volatility. 537 # Find out if the hit is from user or kernel mode 538 if o is None: 539 owner = "Unknown Kernel Memory" 540 elif o.obj_name == "_EPROCESS": 541 owner = "Process {0} Pid {1}".format(o.ImageFileName, o.UniqueProcessId) 542 else: 543 owner = "{0}".format(o.BaseDllName) 544 545 hexdump = "".join( 546 "{0:#010x} {1:<48} {2}\n".format(addr + o, h, ''.join(c)) 547 for o, h, c in utils.Hexdump(content[0:64])) 548 549 new = { 550 "rule": hit.rule, 551 "owner": owner, 552 "hexdump": hexdump, 553 } 554 results.append(new) 555 556 return dict(config={}, data=results)
557
558 - def apihooks(self):
559 """Volatility apihooks plugin. 560 @see volatility/plugins/malware/apihooks.py 561 """ 562 results = [] 563 564 command = self.plugins["apihooks"](self.config) 565 for process, module, hook in command.calculate(): 566 proc_name = str(process.ImageFileName) if process else '' 567 if command.whitelist(hook.hook_mode | hook.hook_type, 568 proc_name, hook.VictimModule, 569 hook.HookModule, hook.Function): 570 continue 571 572 new = { 573 "hook_mode": str(hook.Mode), 574 "hook_type": str(hook.Type), 575 "victim_module": str(module.BaseDllName or ""), 576 "victim_function": str(hook.Detail), 577 "hook_address": "{0:#x}".format(hook.hook_address), 578 "hooking_module": str(hook.HookModule) 579 } 580 581 if process: 582 new["process_id"] = int(process.UniqueProcessId) 583 new["process_name"] = str(process.ImageFileName) 584 585 results.append(new) 586 587 return dict(config={}, data=results)
588
589 - def dlllist(self):
590 """Volatility dlllist plugin. 591 @see volatility/plugins/taskmods.py 592 """ 593 results = [] 594 595 command = self.plugins["dlllist"](self.config) 596 for task in command.calculate(): 597 new = { 598 "process_id": int(task.UniqueProcessId), 599 "process_name": str(task.ImageFileName), 600 "commandline": str(task.Peb.ProcessParameters.CommandLine or ""), 601 "loaded_modules": [] 602 } 603 604 for module in task.get_load_modules(): 605 new["loaded_modules"].append({ 606 "dll_base": str(module.DllBase), 607 "dll_size": str(module.SizeOfImage), 608 "dll_full_name": str(module.FullDllName or ""), 609 "dll_load_count": int(module.LoadCount), 610 }) 611 612 results.append(new) 613 614 return dict(config={}, data=results)
615
616 - def handles(self):
617 """Volatility handles plugin. 618 @see volatility/plugins/handles.py 619 """ 620 results = [] 621 622 command = self.plugins["handles"](self.config) 623 for pid, handle, object_type, name in command.calculate(): 624 new = { 625 "process_id": int(pid), 626 "handle_value": str(handle.HandleValue), 627 "handle_granted_access": str(handle.GrantedAccess), 628 "handle_type": str(object_type), 629 "handle_name": str(name) 630 } 631 632 results.append(new) 633 634 return dict(config={}, data=results)
635
636 - def ldrmodules(self):
637 """Volatility ldrmodules plugin. 638 @see volatility/plugins/malware/malfind.py 639 """ 640 results = [] 641 642 command = self.plugins["ldrmodules"](self.config) 643 for task in command.calculate(): 644 # Build a dictionary for all three PEB lists where the 645 # keys are base address and module objects are the values. 646 inloadorder = dict((mod.DllBase.v(), mod) for mod in task.get_load_modules()) 647 ininitorder = dict((mod.DllBase.v(), mod) for mod in task.get_init_modules()) 648 inmemorder = dict((mod.DllBase.v(), mod) for mod in task.get_mem_modules()) 649 650 # Build a similar dictionary for the mapped files. 651 mapped_files = {} 652 for vad, address_space in task.get_vads(vad_filter=task._mapped_file_filter): 653 # Note this is a lot faster than acquiring the full 654 # vad region and then checking the first two bytes. 655 if obj.Object("_IMAGE_DOS_HEADER", offset=vad.Start, vm=address_space).e_magic != 0x5A4D: 656 continue 657 658 mapped_files[int(vad.Start)] = str(vad.FileObject.FileName or "") 659 660 # For each base address with a mapped file, print info on 661 # the other PEB lists to spot discrepancies. 662 for base in mapped_files.keys(): 663 # Does the base address exist in the PEB DLL lists? 664 load_mod = inloadorder.get(base, None) 665 init_mod = ininitorder.get(base, None) 666 mem_mod = inmemorder.get(base, None) 667 668 new = { 669 "process_id": int(task.UniqueProcessId), 670 "process_name": str(task.ImageFileName), 671 "dll_base": "{0:#x}".format(base), 672 "dll_in_load": load_mod is not None, 673 "dll_in_init": init_mod is not None, 674 "dll_in_mem": mem_mod is not None, 675 "dll_mapped_path": str(mapped_files[base]), 676 "load_full_dll_name": "", 677 "init_full_dll_name": "", 678 "mem_full_dll_name": "" 679 } 680 681 if load_mod: 682 new["load_full_dll_name"] = str(load_mod.FullDllName) 683 684 if init_mod: 685 new["init_full_dll_name"] = str(init_mod.FullDllName) 686 687 if mem_mod: 688 new["mem_full_dll_name"] = str(mem_mod.FullDllName) 689 690 results.append(new) 691 692 return dict(config={}, data=results)
693
694 - def mutantscan(self):
695 """Volatility mutantscan plugin. 696 @see volatility/plugins/filescan.py 697 """ 698 results = [] 699 700 command = self.plugins["mutantscan"](self.config) 701 for mutant in command.calculate(): 702 header = mutant.get_object_header() 703 tid = 0 704 pid = 0 705 if mutant.OwnerThread > 0x80000000: 706 thread = mutant.OwnerThread.dereference_as("_ETHREAD") 707 tid = thread.Cid.UniqueThread 708 pid = thread.Cid.UniqueProcess 709 710 new = { 711 "mutant_offset": "{0:#x}".format(mutant.obj_offset), 712 "num_pointer": int(header.PointerCount), 713 "num_handles": int(header.HandleCount), 714 "mutant_signal_state": str(mutant.Header.SignalState), 715 "mutant_name": str(header.NameInfo.Name or ""), 716 "process_id": int(pid), 717 "thread_id": int(tid) 718 } 719 720 results.append(new) 721 722 return dict(config={}, data=results)
723
724 - def devicetree(self):
725 """Volatility devicetree plugin. 726 @see volatility/plugins/malware/devicetree.py 727 """ 728 results = [] 729 730 command = self.plugins["devicetree"](self.config) 731 for driver_obj in command.calculate(): 732 new = { 733 "driver_offset": "0x{0:08x}".format(driver_obj.obj_offset), 734 "driver_name": str(driver_obj.DriverName or ""), 735 "devices": [] 736 } 737 738 for device in driver_obj.devices(): 739 device_header = obj.Object( 740 "_OBJECT_HEADER", 741 offset=device.obj_offset - device.obj_vm.profile.get_obj_offset("_OBJECT_HEADER", "Body"), 742 vm=device.obj_vm, 743 native_vm=device.obj_native_vm 744 ) 745 746 device_name = str(device_header.NameInfo.Name or "") 747 748 new_device = { 749 "device_offset": "0x{0:08x}".format(device.obj_offset), 750 "device_name": device_name, 751 "device_type": devicetree.DEVICE_CODES.get(device.DeviceType.v(), "UNKNOWN"), 752 "devices_attached": [] 753 } 754 755 new["devices"].append(new_device) 756 757 level = 0 758 759 for att_device in device.attached_devices(): 760 device_header = obj.Object( 761 "_OBJECT_HEADER", 762 offset=att_device.obj_offset - att_device.obj_vm.profile.get_obj_offset("_OBJECT_HEADER", "Body"), 763 vm=att_device.obj_vm, 764 native_vm=att_device.obj_native_vm 765 ) 766 767 device_name = str(device_header.NameInfo.Name or "") 768 name = (device_name + " - " + str(att_device.DriverObject.DriverName or "")) 769 770 new_device["devices_attached"].append({ 771 "level": level, 772 "attached_device_offset": "0x{0:08x}".format(att_device.obj_offset), 773 "attached_device_name": name, 774 "attached_device_type": devicetree.DEVICE_CODES.get(att_device.DeviceType.v(), "UNKNOWN") 775 }) 776 777 level += 1 778 779 results.append(new) 780 781 return dict(config={}, data=results)
782
783 - def svcscan(self):
784 """Volatility svcscan plugin - scans for services. 785 @see volatility/plugins/malware/svcscan.py 786 """ 787 results = [] 788 789 command = self.plugins["svcscan"](self.config) 790 for rec in command.calculate(): 791 new = { 792 "service_offset": "{0:#x}".format(rec.obj_offset), 793 "service_order": int(rec.Order), 794 "process_id": int(rec.Pid), 795 "service_name": str(rec.ServiceName.dereference()), 796 "service_display_name": str(rec.DisplayName.dereference()), 797 "service_type": str(rec.Type), 798 "service_binary_path": str(rec.Binary), 799 "service_state": str(rec.State) 800 } 801 802 results.append(new) 803 804 return dict(config={}, data=results)
805
806 - def modscan(self):
807 """Volatility modscan plugin. 808 @see volatility/plugins/modscan.py 809 """ 810 results = [] 811 812 command = self.plugins["modscan"](self.config) 813 for ldr_entry in command.calculate(): 814 new = { 815 "kernel_module_offset": "{0:#x}".format(ldr_entry.obj_offset), 816 "kernel_module_name": str(ldr_entry.BaseDllName or ""), 817 "kernel_module_file": str(ldr_entry.FullDllName or ""), 818 "kernel_module_base": "{0:#x}".format(ldr_entry.DllBase), 819 "kernel_module_size": int(ldr_entry.SizeOfImage), 820 } 821 822 results.append(new) 823 824 return dict(config={}, data=results)
825
826 - def imageinfo(self):
827 """Volatility imageinfo plugin. 828 @see volatility/plugins/imageinfo.py 829 """ 830 results = [] 831 832 command = self.plugins["imageinfo"](self.config) 833 new = {} 834 for key, value in command.calculate(): 835 new[key] = value 836 837 osp = new["Suggested Profile(s)"].split(",")[0] 838 new["osprofile"] = osp 839 840 results.append(new) 841 842 return dict(config={}, data=results)
843
844 - def sockscan(self):
845 """Volatility sockscan plugin. 846 @see volatility/plugins/sockscan.py 847 """ 848 results = [] 849 850 command = self.plugins["sockscan"](self.config) 851 for sock in command.calculate(): 852 new = { 853 "offset": "{0:#010x}".format(sock.obj_offset), 854 "process_id": str(sock.Pid), 855 "address": str(sock.LocalIpAddress), 856 "port": str(sock.LocalPort), 857 "protocol": "{0} ({1})".format(sock.Protocol, protos.protos.get(sock.Protocol.v(), "-")), 858 "create_time": time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(sock.CreateTime))), 859 } 860 results.append(new) 861 862 return dict(config={}, data=results)
863
864 - def netscan(self):
865 """Volatility sockscan plugin. 866 @see volatility/plugins/netscan.py 867 """ 868 results = [] 869 870 command = self.plugins["netscan"](self.config) 871 for net_obj, proto, laddr, lport, raddr, rport, state in command.calculate(): 872 new = { 873 "offset": "{0:#010x}".format(net_obj.obj_offset), 874 "process_id": str(net_obj.Owner.UniqueProcessId), 875 "local_address": str(laddr), 876 "local_port": str(lport), 877 "remote_address": str(raddr), 878 "remote_port": str(rport), 879 "protocol": str(proto), 880 } 881 results.append(new) 882 883 return dict(config={}, data=results)
884 885
886 -class VolatilityManager(object):
887 """Handle several volatility results.""" 888 PLUGINS = [ 889 "pslist", 890 "psxview", 891 "callbacks", 892 ["idt", "x86"], 893 "ssdt", 894 ["gdt", "x86"], 895 "timers", 896 "messagehooks", 897 "getsids", 898 "privs", 899 "malfind", 900 "apihooks", 901 "dlllist", 902 "handles", 903 "ldrmodules", 904 "mutantscan", 905 "devicetree", 906 "svcscan", 907 "modscan", 908 "yarascan", 909 ["sockscan", "winxp"], 910 ["netscan", "vista", "win7"], 911 ] 912
913 - def __init__(self, memfile, osprofile=None):
914 self.mask_pid = [] 915 self.taint_pid = set() 916 self.memfile = memfile 917 918 conf_path = os.path.join(CUCKOO_ROOT, "conf", "memory.conf") 919 if not os.path.exists(conf_path): 920 log.error("Configuration file {0} not found".format(conf_path)) 921 self.voptions = False 922 return 923 924 self.voptions = Config("memory") 925 926 for pid in self.voptions.mask.pid_generic.split(","): 927 pid = pid.strip() 928 if pid: 929 self.mask_pid.append(int(pid)) 930 931 self.no_filter = not self.voptions.mask.enabled 932 if self.voptions.basic.guest_profile: 933 self.osprofile = self.voptions.basic.guest_profile 934 else: 935 self.osprofile = osprofile or self.get_osprofile()
936
937 - def get_osprofile(self):
938 """Get the OS profile""" 939 return VolatilityAPI(self.memfile).imageinfo()["data"][0]["osprofile"]
940
941 - def run(self):
942 results = {} 943 944 # Exit if options were not loaded. 945 if not self.voptions: 946 return 947 948 vol = VolatilityAPI(self.memfile, self.osprofile) 949 950 for plugin_name in self.PLUGINS: 951 if isinstance(plugin_name, list): 952 plugin_name, profiles = plugin_name[0], plugin_name[1:] 953 else: 954 profiles = [] 955 956 # Some plugins can only run in certain profiles (i.e., only in 957 # Windows XP/Vista/7, or only in x86 or x64). 958 osp = self.osprofile.lower() 959 for profile in profiles: 960 if osp.startswith(profile) or osp.endswith(profile): 961 break 962 else: 963 if profiles: 964 continue 965 966 plugin = self.voptions.get(plugin_name) 967 if not plugin or not plugin.enabled: 968 log.debug("Skipping '%s' volatility module", plugin_name) 969 continue 970 971 if plugin_name in vol.plugins: 972 log.debug("Executing volatility '%s' module.", plugin_name) 973 results[plugin_name] = getattr(vol, plugin_name)() 974 975 self.find_taint(results) 976 self.cleanup() 977 978 return self.mask_filter(results)
979
980 - def mask_filter(self, old):
981 """Filter out masked stuff. Keep tainted stuff.""" 982 new = {} 983 984 for akey in old.keys(): 985 new[akey] = {"config": old[akey]["config"], "data": []} 986 conf = getattr(self.voptions, akey, None) 987 new[akey]["config"]["filter"] = conf.filter 988 for item in old[akey]["data"]: 989 # TODO: need to improve this logic. 990 if not conf.filter: 991 new[akey]["data"].append(item) 992 elif "process_id" in item and \ 993 item["process_id"] in self.mask_pid and \ 994 item["process_id"] not in self.taint_pid: 995 pass 996 else: 997 new[akey]["data"].append(item) 998 return new
999
1000 - def find_taint(self, res):
1001 """Find tainted items.""" 1002 if "malfind" in res: 1003 for item in res["malfind"]["data"]: 1004 self.taint_pid.add(item["process_id"])
1005
1006 - def cleanup(self):
1007 """Delete the memory dump (if configured to do so).""" 1008 1009 if self.voptions.basic.delete_memdump: 1010 try: 1011 os.remove(self.memfile) 1012 except OSError: 1013 log.error("Unable to delete memory dump file at path \"%s\" ", self.memfile)
1014
1015 -class Memory(Processing):
1016 """Volatility Analyzer.""" 1017
1018 - def run(self):
1019 """Run analysis. 1020 @return: volatility results dict. 1021 """ 1022 self.key = "memory" 1023 1024 results = {} 1025 if HAVE_VOLATILITY: 1026 if self.memory_path and os.path.exists(self.memory_path): 1027 try: 1028 results = VolatilityManager(self.memory_path).run() 1029 except Exception: 1030 log.exception("Generic error executing volatility") 1031 else: 1032 log.error("Memory dump not found: to run volatility you have to enable memory_dump") 1033 else: 1034 log.error("Cannot run volatility module: volatility library not available") 1035 1036 return results
1037