def _get_raw_registry_data2(self, regvalue): tp, dat = rawreg.value_data(regvalue) if tp == 'REG_BINARY' or tp == 'REG_NONE': dat = "\n" + "\n".join([ "{0:#010x} {1:<48} {2}".format(o, h, ''.join(c)) for o, h, c in volutils.Hexdump(dat) ]) if tp in ['REG_SZ', 'REG_EXPAND_SZ', 'REG_LINK']: dat = dat.encode("ascii", 'backslashreplace') if tp == 'REG_MULTI_SZ': for i in range(len(dat)): dat[i] = dat[i].encode("ascii", 'backslashreplace') return dat
def render_text(self, outfd, data): for task, address, hit, buf in data: if task: outfd.write("Task: {0} pid {1} rule {2} addr {3:#x}\n".format( task.p_comm, task.p_pid, hit.rule, address)) else: outfd.write("[kernel] rule {0} addr {1:#x}\n".format( hit.rule, address)) outfd.write("".join([ "{0:#018x} {1:<48} {2}\n".format(address + o, h, ''.join(c)) for o, h, c in utils.Hexdump(buf) ]))
def render_extra(self, outfd, task, vad, params): """Show any Zeus specific fields""" rc4_offset = task.obj_vm.profile.get_obj_offset( self.magic_struct, 'rc4key') creds_key = params['decoded_magic'][rc4_offset:rc4_offset + RC4_KEYSIZE] outfd.write("{0:<30} : \n{1}\n".format( "Credential RC4 key", "\n".join([ "{0:#010x} {1:<48} {2}".format(vad.Start + o, h, ''.join(c)) for o, h, c in utils.Hexdump(creds_key) ])))
def render_text(self, outfd, data): self.table_header(outfd, [ ("Address", "#018x"), ("Cipher", "32"), ("FVEK", "64"), ("TWEAK Key", "64"), ]) for (pool, BLMode, tweak, fvek_raw) in data: fvek = [] for o, h, c in utils.Hexdump(fvek_raw): fvek.append(h) self.table_row(outfd, pool, BLMode, ''.join(fvek).replace(" ", ""), ''.join(tweak).replace(" ", ""))
def render_text(self, outfd, data): if not has_distorm3: debug.warning("For best results please install distorm3") if self._config.DUMP_DIR and not os.path.isdir(self._config.DUMP_DIR): debug.error(self._config.DUMP_DIR + " is not a directory") for task in data: for vad, address_space in task.get_vads( vad_filter=task._injection_filter): if self._is_vad_empty(vad, address_space): continue content = address_space.zread(vad.Start, 64) outfd.write("Process: {0} Pid: {1} Address: {2:#x}\n".format( task.ImageFileName, task.UniqueProcessId, vad.Start)) outfd.write("Vad Tag: {0} Protection: {1}\n".format( vad.Tag, vadinfo.PROTECT_FLAGS.get(vad.u.VadFlags.Protection.v(), ""))) outfd.write("Flags: {0}\n".format(str(vad.u.VadFlags))) outfd.write("\n") outfd.write("{0}\n".format("\n".join([ "{0:#010x} {1:<48} {2}".format(vad.Start + o, h, ''.join(c)) for o, h, c in utils.Hexdump(content) ]))) outfd.write("\n") outfd.write("\n".join([ "{0:#x} {1:<16} {2}".format(o, h, i) for o, i, h in Disassemble(content, vad.Start) ])) # Dump the data if --dump-dir was supplied if self._config.DUMP_DIR: filename = os.path.join( self._config.DUMP_DIR, "process.{0:#x}.{1:#x}.dmp".format( task.obj_offset, vad.Start)) self.dump_vad(filename, vad, address_space) outfd.write("\n\n")
def generate_output(self, outfd, vad, task, file_object_name, peb_image_path_name): # this function will output data for a given VAD passed to it content = None outfd.write("Process: {0} Pid: {1} Ppid: {2}\n".format( task.ImageFileName, task.UniqueProcessId, task.InheritedFromUniqueProcessId)) outfd.write("Address: {0:#x} Protection: {1}\n".format( vad.Start, vadinfo.PROTECT_FLAGS.get(vad.VadFlags.Protection.v(), ""))) if peb_image_path_name != None: outfd.write("Initially mapped file object: {0}\n".format( peb_image_path_name)) else: outfd.write("Initially mapped file object: {0}\n".format("None")) if file_object_name != None: outfd.write( "Currently mapped file object: {0}\n".format(file_object_name)) else: outfd.write("Currently mapped file object: {0}\n".format("None")) address_space = task.get_process_address_space() content = address_space.zread(vad.Start, 64) if content: outfd.write("{0}\n".format("\n".join([ "{0:#010x} {1:<48} {2}".format(vad.Start + o, h, ''.join(c)) for o, h, c in utils.Hexdump(content) ]))) outfd.write("\n") outfd.write("\n".join([ "{0:#010x} {1:<16} {2}".format(o, h, i) for o, i, h in malfind.Disassemble(content, vad.Start) ])) outfd.write("\n\n") # dump vad incase -D was specified if self._config.DUMP_DIR: filename = os.path.join( self._config.DUMP_DIR, "process.{0:#x}.{1:#x}.dmp".format(task.obj_offset, vad.Start)) self.dump_vad(filename, vad, address_space)
def render_text(self, outfd, data): for v, tp, dat in data: if tp == 'REG_BINARY' or tp == 'REG_NONE': dat = "\n" + "\n".join([ "{0:#010x} {1:<48} {2}".format(o, h, ''.join(c)) for o, h, c in utils.Hexdump(dat) ]) if tp in ['REG_SZ', 'REG_EXPAND_SZ', 'REG_LINK']: dat = dat.encode("ascii", 'backslashreplace') if tp == 'REG_MULTI_SZ': for i in range(len(dat)): dat[i] = dat[i].encode("ascii", 'backslashreplace') outfd.write("{0:13} {1:15} : {2} \n".format(tp, v, dat)) """
def render_text(self, outfd, data): keyfound = False for win7, reg, key in data: if key: keyfound = True outfd.write("----------------------------\n") outfd.write("Registry: {0}\n".format(reg)) outfd.write("Path: {0}\n".format( self.regapi.reg_get_key_path(key))) outfd.write("Last updated: {0}\n".format(key.LastWriteTime)) outfd.write("\n") outfd.write("Subkeys:\n") for s in self.regapi.reg_get_all_subkeys(None, None, given_root=key): if s.Name == None: outfd.write(" Unknown subkey: " + s.Name.reason + "\n") else: outfd.write(" {0}\n".format(s.Name)) outfd.write("\n") outfd.write("Values:\n") for subname, dat in self.regapi.reg_yield_values( None, None, given_root=key, thetype="REG_BINARY"): dat_raw = dat dat = "\n".join([ "{0:#010x} {1:<48} {2}".format(o, h, ''.join(c)) for o, h, c in utils.Hexdump(dat) ]) try: subname = subname.encode('rot_13') except UnicodeDecodeError: pass if win7: guid = subname.split("\\")[0] if guid in folder_guids: subname = subname.replace(guid, folder_guids[guid]) d = self.parse_data(dat_raw) if d != None: dat = "{0}Raw Data:\n{1}".format(d, dat) else: dat = "Raw Data:\n{0}".format(dat) outfd.write("\n{0:13} {1:15} : {2}\n".format( "REG_BINARY", subname, dat)) if not keyfound: outfd.write( "The requested key could not be found in the hive(s) searched\n" )
def disassemble(self, address_space, entry_point): """ :param address_space: process's address space object :param entry_point: Start address :return: A string of the disassembled code Disassemble the 64 bytes of code by giving the process's address space and the start address """ entry_point = int(entry_point) content = address_space.read(entry_point, 64) # Check if we could have read from memory, might be paged if content: disassemble_code = "\t" disassemble_code += ("{0}\n\n".format("\n\t".join([ "{0:#010x} {1:<48} {2}".format(entry_point + o, h, ''.join(c)) for o, h, c in utils.Hexdump(content) ]))) disassemble_code += "\t" # Rather disassemble with distrom3 than malfind if has_distorm: # Get OS profile mode = address_space.profile.metadata.get('memory_model') if mode == '64bit': mode = distorm3.Decode64Bits else: mode = distorm3.Decode32Bits disassemble_code += "\n\t".join(["{0:<#010x} {1:<16} {2}".format(o, h, i) \ for o, _size, i, h in \ distorm3.DecodeGenerator(entry_point, content, mode)]) else: disassemble_code += "\n\t".join([ "{0:#010x} {1:<16} {2}".format(o, h, i) for o, i, h in malfind.Disassemble(content, entry_point) ]) disassemble_code += "\n" else: disassemble_code = "\t** Couldn't read memory\n" return disassemble_code
def render_text(self, outfd, data): """Render the plugin's default text output""" for task, vad, params in data: # Get a magic object from the buffer buffer_space = addrspace.BufferAddressSpace( config = self._config, data = params['decoded_magic']) magic_obj = obj.Object(self.magic_struct, offset = 0, vm = buffer_space) outfd.write("*" * 50 + "\n") outfd.write("{0:<30} : {1}\n".format("Process", task.ImageFileName)) outfd.write("{0:<30} : {1}\n".format("Pid", task.UniqueProcessId)) outfd.write("{0:<30} : {1}\n".format("Address", vad.Start)) # grab the URLs from the decoded buffer decoded_config = params['decoded_config'] urls = [] while "http" in decoded_config: url = decoded_config[decoded_config.find("http"):] urls.append(url[:url.find('\x00')]) decoded_config = url[url.find('\x00'):] for i, url in enumerate(urls): outfd.write("{0:<30} : {1}\n".format("URL {0}".format(i), url)) outfd.write("{0:<30} : {1}\n".format("Identifier", ''.join([chr(c) for c in magic_obj.guid if c != 0]))) outfd.write("{0:<30} : {1}\n".format("Mutant key", magic_obj.guid_xor_key)) outfd.write("{0:<30} : {1}\n".format("XOR key", magic_obj.xorkey)) outfd.write("{0:<30} : {1}\n".format("Registry", "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\{0}".format(magic_obj.keyname))) outfd.write("{0:<30} : {1}\n".format(" Value 1", magic_obj.value1)) outfd.write("{0:<30} : {1}\n".format(" Value 2", magic_obj.value2)) outfd.write("{0:<30} : {1}\n".format(" Value 3", magic_obj.value3)) outfd.write("{0:<30} : {1}\n".format("Executable", magic_obj.exefile)) outfd.write("{0:<30} : {1}\n".format("Data file", magic_obj.datfile)) outfd.write("{0:<30} : \n{1}\n".format("Config RC4 key", "\n".join( ["{0:#010x} {1:<48} {2}".format(vad.Start + o, h, ''.join(c)) for o, h, c in utils.Hexdump(params['config_key']) ]))) self.render_extra(outfd, task, vad, params)
def render_text(self, outfd, data): linux_common.set_plugin_members(self) if self.addr_space.profile.metadata.get('memory_model', '32bit') == '32bit': bits = '32bit' else: bits = '64bit' for task in data: proc_as = task.get_process_address_space() for vma in task.get_proc_maps(): if vma.is_suspicious(): fname = vma.vm_name(task) if fname == "[vdso]": continue prots = vma.protection() flags = vma.flags() content = proc_as.zread(vma.vm_start, 64) outfd.write( "Process: {0} Pid: {1} Address: {2:#x} File: {3}\n". format(task.comm, task.pid, vma.vm_start, fname)) outfd.write("Protection: {0}\n".format(prots)) outfd.write("Flags: {0}\n".format(str(flags))) outfd.write("\n") outfd.write("{0}\n".format("\n".join([ "{0:#016x} {1:<48} {2}".format( vma.vm_start + o, h, ''.join(c)) for o, h, c in utils.Hexdump(content) ]))) outfd.write("\n") outfd.write("\n".join([ "{0:#x} {1:<16} {2}".format(o, h, i) for o, i, h in malfind.Disassemble(content, vma.vm_start, bits=bits) ])) outfd.write("\n\n")
def render_text(self, outfd, data): keyfound = False for win7, reg, key in data: if key: keyfound = True outfd.write("----------------------------\n") outfd.write(f"Registry: {reg}\n") outfd.write(f"Path: {self.regapi.reg_get_key_path(key)}\n") outfd.write(f"Last updated: {key.LastWriteTime}\n") outfd.write("\n") outfd.write("Subkeys:\n") for s in self.regapi.reg_get_all_subkeys(None, None, given_root=key): if s.Name == None: outfd.write(f" Unknown subkey: {s.Name.reason}\n") else: outfd.write(f" {s.Name}\n") outfd.write("\n") outfd.write("Values:\n") for subname, dat in self.regapi.reg_yield_values( None, None, given_root=key, thetype="REG_BINARY"): dat_raw = dat dat = "\n".join([ f"{o:#010x} {h:<48} {''.join(c)}" for o, h, c in utils.Hexdump(dat) ]) try: subname = codecs.encode(str(subname), 'rot_13') except UnicodeDecodeError: pass if win7: guid = subname.split("\\")[0] if guid in folder_guids: subname = subname.replace(guid, folder_guids[guid]) d = self.parse_data(dat_raw) if d != None: dat = f"{d}Raw Data:\n{dat}" else: dat = f"Raw Data:\n{dat}" outfd.write(f"\n{'REG_BINARY':13} {subname:15} : {dat}\n") if not keyfound: outfd.write( "The requested key could not be found in the hive(s) searched\n" )
def get_alloc(self, addr_space): ''' Mimics the Volatility malfind plugin ''' import volatility.plugins.malware.malfind as malfind import volatility.utils as utils mfind = malfind.Malfind(self.vol.config) for task in mfind.calculate(): for vad, address_space in task.get_vads(vad_filter=task._injection_filter): if mfind._is_vad_empty(vad, address_space): continue content = address_space.zread(vad.Start, 16) content = "{0}".format("\n".join( ["{0:<48} {1}".format(h, ''.join(c)) for o, h, c in utils.Hexdump(content) ])) offset = "{0:#x}".format(vad.Start) yield Injection(task, vad, offset, content)
def dict_for_key(self, key): # Inspired from the Volatility printkey plugin valdict = {} for v in rawreg.values(key): tp, data = rawreg.value_data(v) if tp == 'REG_BINARY' or tp == 'REG_NONE': data = "\n" + "\n".join([ "{0:#010x} {1:<48} {2}".format(o, h, ''.join(c)) for o, h, c in utils.Hexdump(data) ]) if tp in ['REG_SZ', 'REG_EXPAND_SZ', 'REG_LINK']: data = data.encode("ascii", 'backslashreplace') if tp == 'REG_MULTI_SZ': for i in range(len(data)): data[i] = data[i].encode("ascii", 'backslashreplace') valdict[str(v.Name)] = str(data) return valdict
def calculate(self): self.regapi = registryapi.RegistryApi(self._config) builds_with_old_location = ['16299', '17134'] # Get Windows build version addr_space = utils.load_as(self._config) build = addr_space.profile.metadata.get('build', 0) # Choose which location of bam to use in the registry. Builds 16299 and 17134 # use another path. bam_path = "" controlset = self.regapi.reg_get_currentcontrolset() or "ControlSet001" if build in builds_with_old_location: bam_path = controlset + "\\Services\\bam\\UserSettings" else: bam_path = controlset + "\\Services\\bam\\State\\UserSettings" bam_key = self.regapi.reg_get_key('system', bam_path) # Get all subkeys in UserSettings bam_sub_keys = self.regapi.reg_get_all_subkeys('system', bam_path, given_root=bam_key) # Get all key values, processing the binary content of the values self.data = {} for sidkey in bam_sub_keys: sidkey_values = [] for key, value in self.regapi.reg_yield_values( 'system', sidkey, thetype='REG_BINARY', given_root=sidkey): dat = "\n".join( ["{0:<48}".format(h) for o, h, c in utils.Hexdump(value)]) sidkey_values.append({ 'key': key, 'time': self.reg_bin_to_file_time(dat) }) #print sidkey.Name, key, self.reg_bin_to_file_time(dat) self.data[sidkey.Name] = sidkey_values return self.data
def yarascan(self): """Volatility yarascan plugin. @see volatility/plugins/malware/malfind.py """ log.debug("Executing Volatility yarascan plugin on " "{0}".format(self.memdump)) self.__config() results = [] ypath = os.path.join(CUCKOO_ROOT, "data", "yara", "index_memory.yar") if not os.path.exists(ypath): return dict(config={}, data=[]) self.config.update("YARA_FILE", ypath) command = self.plugins["yarascan"](self.config) for o, addr, hit, content in command.calculate(): # Comment: this code is pretty much ripped from render_text in volatility. # Find out if the hit is from user or kernel mode if o == None: owner = "Unknown Kernel Memory" elif o.obj_name == "_EPROCESS": owner = "Process {0} Pid {1}".format(o.ImageFileName, o.UniqueProcessId) else: owner = "{0}".format(o.BaseDllName) hexdump = "".join([ "{0:#010x} {1:<48} {2}\n".format(addr + o, h, ''.join(c)) for o, h, c in utils.Hexdump(content[0:64]) ]) new = { "rule": hit.rule, "owner": owner, "hexdump": hexdump, } results.append(new) return dict(config={}, data=results)
def render_text(self, outfd, data): outfd.write("Legend: (S) = Stable (V) = Volatile\n\n") keyfound = False for reg, key in data: if key: keyfound = True outfd.write("----------------------------\n") outfd.write("Registry: {0}\n".format(reg)) outfd.write("Key name: {0} {1:3s}\n".format( key.Name, self.voltext(key))) outfd.write("Last updated: {0}\n".format(key.LastWriteTime)) outfd.write("\n") outfd.write("Subkeys:\n") for s in rawreg.subkeys(key): if s.Name == None: outfd.write(" Unknown subkey: " + s.Name.reason + "\n") else: outfd.write(" {1:3s} {0}\n".format( s.Name, self.voltext(s))) outfd.write("\n") outfd.write("Values:\n") for v in rawreg.values(key): tp, dat = rawreg.value_data(v) if tp == 'REG_BINARY' or tp == 'REG_NONE': dat = "\n" + "\n".join([ "{0:#010x} {1:<48} {2}".format(o, h, ''.join(c)) for o, h, c in utils.Hexdump(dat) ]) if tp in ['REG_SZ', 'REG_EXPAND_SZ', 'REG_LINK']: dat = dat.encode("ascii", 'backslashreplace') if tp == 'REG_MULTI_SZ': for i in range(len(dat)): dat[i] = dat[i].encode("ascii", 'backslashreplace') outfd.write("{0:13} {1:15} : {3:3s} {2}\n".format( tp, v.Name, dat, self.voltext(v))) if not keyfound: outfd.write( "The requested key could not be found in the hive(s) searched\n" )
def render_text(self, outfd, data): for task in data: proc_as = task.get_process_address_space() for vma in task.get_proc_maps(): if vma.is_suspicious(): fname = vma.vm_name(task) if fname == "[vdso]": continue prots = vma.protection() flags = vma.flags() content = proc_as.zread(vma.vm_start, 64) outfd.write( "Process: {0} Pid: {1} Address: {2:#x} File: {3}\n". format(task.comm, task.pid, vma.vm_start, fname)) outfd.write("Protection: {0}\n".format(prots)) outfd.write("Flags: {0}\n".format(str(flags))) outfd.write("\n") outfd.write("{0}\n".format("\n".join([ "{0:#010x} {1:<48} {2}".format( vma.vm_start + o, h, ''.join(c)) for o, h, c in utils.Hexdump(content) ]))) outfd.write("\n") outfd.write("\n".join([ "{0:#x} {1:<16} {2}".format(o, h, i) for o, i, h in malfind.Disassemble( content, vma.vm_start) ])) outfd.write("\n\n")
def render_text(self, outfd, data): for task in data: proc_as = task.get_process_address_space() bit_string = str(task.task.map.pmap.pm_task_map or '')[9:] if bit_string == "64BIT": bits = '64bit' else: bits = '32bit' for map in task.get_proc_maps(): if map.is_suspicious(): fname = map.get_path() prots = map.get_perms() content = proc_as.zread(map.start, 64) outfd.write( "Process: {0} Pid: {1} Address: {2:#x} File: {3}\n". format(task.p_comm, task.p_pid, map.start, fname)) outfd.write("Protection: {0}\n".format(prots)) outfd.write("\n") outfd.write("{0}\n".format("\n".join([ "{0:#010x} {1:<48} {2}".format( map.start + o, h, ''.join(c)) for o, h, c in utils.Hexdump(content) ]))) outfd.write("\n") outfd.write("\n".join([ "{0:#x} {1:<16} {2}".format(o, h, i) for o, i, h in malfind.Disassemble(content, map.start, bits=bits) ])) outfd.write("\n\n")
def db(address, length = 0x80, space = None): """Print bytes as canonical hexdump. This function prints bytes at the given virtual address as a canonical hexdump. The address will be translated in the current process context (see help on cc for information on how to change contexts). The length parameter (default: 0x80) specifies how many bytes to print, the width parameter (default: 16) allows you to change how many bytes per line should be displayed, and the space parameter allows you to optionally specify the address space to read the data from. """ if not space: space = self._proc.get_process_address_space() #if length % 4 != 0: # length = (length+4) - (length%4) data = space.read(address, length) if not data: print "Memory unreadable at {0:08x}".format(address) return for offset, hexchars, chars in utils.Hexdump(data): print "{0:#010x} {1:<48} {2}".format(address + offset, hexchars, ''.join(chars))
def render_text(self, outfd, data): outfd.write("Legend: (S) = Stable (V) = Volatile\n\n") keyfound = False for reg, key in data: if key: keyfound = True outfd.write("----------------------------\n") outfd.write(f"Registry: {reg}\n") outfd.write(f"Key name: {key.Name} {self.voltext(key):3s}\n") outfd.write(f"Last updated: {key.LastWriteTime}\n") outfd.write("\n") outfd.write("Subkeys:\n") for s in rawreg.subkeys(key): if s.Name == None: outfd.write(f" Unknown subkey at {s.obj_offset:#x}\n") else: outfd.write(f" {self.voltext(s):3s} {s.Name}\n") outfd.write("\n") outfd.write("Values:\n") for v in rawreg.values(key): tp, dat = rawreg.value_data(v) if tp == 'REG_BINARY' or tp == 'REG_NONE': dat = "\n" + "\n".join([ f"{o:#010x} {h:<48} {''.join(c)}" for o, h, c in utils.Hexdump(dat) ]) if tp in ['REG_SZ', 'REG_EXPAND_SZ', 'REG_LINK']: dat = dat.encode("ascii", 'backslashreplace') if tp == 'REG_MULTI_SZ': for i in range(len(dat)): dat[i] = dat[i].encode("ascii", 'backslashreplace') outfd.write( f"{tp:13} {v.Name:15} : {self.voltext(v):3s} {dat}\n") if not keyfound: outfd.write( "The requested key could not be found in the hive(s) searched\n" )
def parse_malfind_data(data, out, output="text"): import volatility.plugins.malware.malfind as malfind import volatility.utils as utils datas = getinfos(data, plugin_cols["malfind"]["cols"]) if output == "json": out.write("{}\n\n".format(datas)) return elif output == "text": mode = "32bit" if platform.machine() == "AMD64": mode = "64bit" for proc, pid, address, vadtag, protection, flags, data in datas: out.write("Process: {}, Pid: {}\n".format(proc, pid)) out.write("VadTag: {}, Protection: {}, Flags: {}\n\n".format( vadtag, protection, flags)) out.write("Raw data at address {0:#x}: {1}\n\n".format( address, data)) out.write("Disassembly:\n") out.write("\n".join([ "{0:#x} {1:<16} {2}".format(o, h, i) for o, i, h in malfind.Disassemble(data.decode("hex"), int(address), mode) ])) out.write("\n\nHexdump:\n") out.write("{0}\n".format("\n".join([ "{0:#010x} {1:<48} {2}".format( int(address) + o, h, ''.join(c)) for o, h, c in utils.Hexdump(data.decode("hex")) ]))) out.write("\n\n") else: for proc, pid, address, vadtag, protection, flags, data in datas: out.write("{},{},{},{},{},{},{}\n".format(proc, pid, address, vadtag, protection, flags, data)) out.write("\n\n") out.write("\n\n")
def render_text(self, outfd, data): for device in data: ext = device.DeviceExtension.dereference_as("EXTENSION") if not ext.is_valid(): continue outfd.write("Container: {0}\n".format(ext.wszVolume)) outfd.write("Hidden Volume: {0}\n".format( "Yes" if ext.cryptoInfo.hiddenVolume == 1 else "No")) outfd.write("Removable: {0}\n".format("Yes" if ext.bRemovable == 1 else "No")) outfd.write("Read Only: {0}\n".format("Yes" if ext.bReadOnly == 1 else "No")) outfd.write("Disk Length: {0} (bytes)\n".format(ext.DiskLength)) outfd.write("Host Length: {0} (bytes)\n".format(ext.HostLength)) outfd.write("Encryption Algorithm: {0}\n".format( ext.cryptoInfo.ea)) outfd.write("Mode: {0}\n".format(ext.cryptoInfo.mode)) outfd.write("Master Key\n") key = device.obj_vm.read(ext.cryptoInfo.master_keydata.obj_offset, 64) addr = ext.cryptoInfo.master_keydata.obj_offset outfd.write("{0}\n".format("\n".join([ "{0:#010x} {1:<48} {2}".format(addr + o, h, ''.join(c)) for o, h, c in utils.Hexdump(key) ]))) if self._config.DUMP_DIR: if not os.path.isdir(self._config.DUMP_DIR): debug.error("The path {0} is not a valid directory".format( self._config.DUMP_DIR)) name = "{0:#x}_master.key".format(addr) keyfile = os.path.join(self._config.DUMP_DIR, name) with open(keyfile, "wb") as handle: handle.write(key) outfd.write("Dumped {0} bytes to {1}\n".format( len(key), keyfile)) outfd.write("\n")
def render_text(self, outfd, data): header = data.get_header() ## First some of the version meta-data outfd.write("Magic: {0:#x} (Version {1})\n".format( header.Magic, header.Version)) outfd.write("Group count: {0:#x}\n".format(header.GroupCount)) ## Now let's print the runs self.table_header(outfd, [("File Offset", "[addrpad]"), ("PhysMem Offset", "[addrpad]"), ("Size", "[addrpad]")]) for memory_offset, file_offset, length in data.get_runs(): self.table_row(outfd, file_offset, memory_offset, length) outfd.write("\n") ## Go through and print the groups and tags self.table_header(outfd, [("DataOffset", "[addrpad]"), ("DataSize", "[addr]"), ("Name", "50"), ("Value", "")]) for group in header.Groups: for tag in group.Tags: ## The indices should look like [0][1] indices = "" for i in tag.TagIndices: indices += "[{0}]".format(i) ## Attempt to format standard values if tag.DataMemSize == 0: value = "" elif tag.DataMemSize == 1: value = "{0}".format(tag.cast_as("unsigned char")) elif tag.DataMemSize == 2: value = "{0}".format(tag.cast_as("unsigned short")) elif tag.DataMemSize == 4: value = "{0:#x}".format(tag.cast_as("unsigned int")) elif tag.DataMemSize == 8: value = "{0:#x}".format(tag.cast_as("unsigned long long")) else: value = "" self.table_row( outfd, tag.RealDataOffset, tag.DataMemSize, "{0}/{1}{2}".format(group.Name, tag.Name, indices), value) ## In verbose mode, when we're *not* dealing with memory segments, ## print a hexdump of if (self._config.VERBOSE and tag.DataMemSize > 0 and str(group.Name) != "memory" and value == ""): ## When we read, it must be done via the AS base (FileAddressSpace) addr = tag.RealDataOffset ## FIXME: FileAddressSpace.read doesn't handle NativeType so we have to case. ## Remove the cast after Issue #350 is fixed. data = tag.obj_vm.read(addr, int(tag.DataMemSize)) outfd.write("".join([ "{0:#010x} {1:<48} {2}\n".format( addr + o, h, ''.join(c)) for o, h, c in utils.Hexdump(data) ]))
def generator(self, data): for (pool, BLMode, tweak, fvek_raw) in data: fvek = [] for o, h, c in utils.Hexdump(fvek_raw): fvek.append(h) yield(0, [Address(pool),BLMode, str(''.join(fvek).replace(" ","")),str(''.join(tweak).replace(" ","")),])
def calculate(self): PoolSize = { 'Fvec128' : 527, 'Fvec256' : 1008, 'Cngb128' : 672, 'Cngb256' : 672, } BLMode = { '00' : 'AES 128-bit with Diffuser', '01' : 'AES 256-bit with Diffuser', '02' : 'AES 128-bit', '03' : 'AES 256-bit', '10' : 'AES 128-bit (Win 8+)', '20' : 'AES 256-bit (Win 8+)' } length = 16 address_space = utils.load_as(self._config) winver = (address_space.profile.metadata.get("major", 0), address_space.profile.metadata.get("minor", 0)) if winver < (6,2): poolsize = lambda x : x >= PoolSize['Fvec128'] and x <= PoolSize['Fvec256'] scanner = KeyPoolScan() scanner.checks = [ ('PoolTagCheck', dict(tag = "FVEc")), ('CheckPoolSize', dict(condition = poolsize)), ('CheckPoolType', dict(paged = False, non_paged = True)), ] for offset in scanner.scan(address_space): pool = obj.Object("_POOL_HEADER", offset = offset, vm = address_space) mode = address_space.zread(offset+0x2C,1) for o, h, c in utils.Hexdump(mode): mode =h if mode == '01' or mode == '03': length = 32 fvek_raw = address_space.zread(offset+0x30,length) tweak = [] if mode == '01' or mode == '00': for o, h ,c in utils.Hexdump(address_space.zread(offset+0x210,length)): tweak.append(h) yield pool, BLMode[mode], tweak, fvek_raw if winver >= (6,2): tweak = "Not Applicable" poolsize = lambda x : x >= PoolSize['Cngb128'] and x <= PoolSize['Cngb256'] scanner = KeyPoolScan() scanner.checks = [ ('PoolTagCheck', dict(tag = "Cngb")), ('CheckPoolSize', dict(condition = poolsize)), ('CheckPoolType', dict(paged = False, non_paged = True)), ] for offset in scanner.scan(address_space): pool = obj.Object("_POOL_HEADER", offset = offset, vm = address_space) mode = address_space.zread(offset+0x68,1) for o, h, c in utils.Hexdump(mode): mode =h if mode == '20': length = 32 f1 = address_space.zread(offset+0x6C,length) f2 = address_space.zread(offset+0x90,length) if f1 == f2: yield pool, BLMode[mode], tweak, f2
def render_text(self, outfd, data): for (proc_peb_info, proc_vad_info, parent_proc_info, similar_procs) in data: (proc, pid, proc_name, ppid, create_time, proc_cmd_line, proc_image_baseaddr, mod_baseaddr, mod_size, mod_basename, mod_fullname) = proc_peb_info (vad_filename, vad_baseaddr, vad_size, vad_protection, vad_tag) = proc_vad_info (parent_name, parent_id) = parent_proc_info outfd.write("Process Information:\n") outfd.write("\tProcess: {0} PID: {1}\n".format(proc_name, pid)) outfd.write("\tParent Process: {0} PPID: {1}\n".format( parent_name, ppid, )) outfd.write("\tCreation Time: {0}\n".format(create_time)) outfd.write("\tProcess Base Name(PEB): {0}\n".format(mod_basename)) outfd.write("\tCommand Line(PEB): {0}\n".format(proc_cmd_line)) outfd.write("\n") outfd.write("VAD and PEB Comparison:\n") outfd.write("\tBase Address(VAD): {0:#x}\n".format(vad_baseaddr)) outfd.write("\tProcess Path(VAD): {0}\n".format(vad_filename)) outfd.write("\tVad Protection: {0}\n".format(vad_protection)) outfd.write("\tVad Tag: {0}\n".format(vad_tag)) outfd.write("\n") outfd.write( "\tBase Address(PEB): {0:#x}\n".format(proc_image_baseaddr)) outfd.write("\tProcess Path(PEB): {0}\n".format(mod_fullname)) if vad_baseaddr != proc_image_baseaddr: for vad, addr_space in proc.get_vads(): if vad.Start == proc_image_baseaddr: content = addr_space.read(vad.Start, 64) outfd.write("\tMemory Protection: {0}\n".format( str( vadinfo.PROTECT_FLAGS.get( vad.VadFlags.Protection.v()) or ""))) outfd.write("\tMemory Tag: {0}\n".format( str(vad.Tag or ""))) outfd.write("\n") if content != None: outfd.write("".join([ "{0:#010x} {1:<48} {2}\n".format( vad.Start + o, h, ''.join(c)) for o, h, c in utils.Hexdump(content) ])) else: outfd.write( "\tNo Hexdump: Memory Unreadable at {0:#010x}\n" .format(vad.Start)) outfd.write("\n") else: outfd.write( "\tMemory Protection: {0}\n".format(vad_protection)) outfd.write("\tMemory Tag: {0}\n".format(vad_tag)) outfd.write("\n") outfd.write("Similar Processes:\n") for similar_proc in similar_procs: (process_name, process_id, parent_name, parent_id, creation_time, full_path) = similar_proc outfd.write("{0}\n".format(full_path)) outfd.write("\t{0}({1}) Parent:{2}({3}) Start:{4}\n".format( process_name, process_id, parent_name, parent_id, creation_time)) outfd.write("\n") outfd.write("Suspicious Memory Regions:\n") for vad, addr_space in proc.get_vads(): content = addr_space.read(vad.Start, 64) if content == None: continue vad_prot = str( vadinfo.PROTECT_FLAGS.get(vad.VadFlags.Protection.v())) if obj.Object("_IMAGE_DOS_HEADER", offset=vad.Start, vm=addr_space).e_magic != 0x5A4D: flag = "No PE/Possibly Code" if (vad_prot == "PAGE_EXECUTE_READWRITE"): sus_addr = vad.Start outfd.write( "\t{0:#x}({1}) Protection: {2} Tag: {3}\n". format(vad.Start, flag, vad_prot, str(vad.Tag or ""))) if self._config.DUMP_DIR: filename = os.path.join( self._config.DUMP_DIR, "process.{0}.{1:#x}.dmp".format(pid, sus_addr)) self.dump_vad(filename, vad, addr_space) elif (vad_prot == "PAGE_EXECUTE_WRITECOPY"): sus_addr = vad.Start outfd.write( "\t{0:#x}({1}) Protection: {2} Tag: {3}\n". format(sus_addr, flag, vad_prot, str(vad.Tag or ""))) if self._config.DUMP_DIR: filename = os.path.join( self._config.DUMP_DIR, "process.{0}.{1:#x}.dmp".format(pid, sus_addr)) self.dump_vad(filename, vad, addr_space) else: if vad_prot == "PAGE_EXECUTE_READWRITE": flag = "PE Found" sus_addr = vad.Start outfd.write( "\t{0:#x}({1}) Protection: {2} Tag: {3}\n". format(sus_addr, flag, vad_prot, str(vad.Tag or ""))) if self._config.DUMP_DIR: filename = os.path.join( self._config.DUMP_DIR, "process.{0}.{1:#x}.dmp".format(pid, sus_addr)) self.dump_vad(filename, vad, addr_space) elif (vad_prot == "PAGE_EXECUTE_WRITECOPY") and (not bool( vad.FileObject)): flag = "PE - No Mapped File" sus_addr = vad.Start outfd.write( "\t{0:#x}({1}) Protection: {2} Tag: {3}\n". format(sus_addr, flag, vad_prot, str(vad.Tag or ""))) if self._config.DUMP_DIR: filename = os.path.join( self._config.DUMP_DIR, "process.{0}.{1:#x}.dmp".format(pid, sus_addr)) self.dump_vad(filename, vad, addr_space) outfd.write( "---------------------------------------------------\n\n")
def render_text(self, outfd, data): if self._config.DUMP_DIR != None and not os.path.isdir(self._config.DUMP_DIR): debug.error(self._config.DUMP_DIR + " is not a directory") border = "*" * 75 for offset, mft_entry, attributes in data: if len(attributes) == 0: continue outfd.write("{0}\n".format(border)) outfd.write("MFT entry found at offset 0x{0:x}\n".format(offset)) outfd.write("Attribute: {0}\n".format(mft_entry.get_mft_type())) outfd.write("Record Number: {0}\n".format(mft_entry.RecordNumber)) outfd.write("Link count: {0}\n".format(mft_entry.LinkCount)) outfd.write("\n") # there can be more than one resident $DATA attribute # e.g. ADS. Therfore we need to differentiate somehow # to avoid clobbering. For now we'll use a counter (datanum) datanum = 0 for a, i in attributes: if i == None: outfd.write("${0}: malformed entry\n".format(a)) continue if a.startswith("STANDARD_INFORMATION"): outfd.write("\n${0}\n".format(a)) self.table_header(outfd, i.get_header()) outfd.write("{0}\n".format(str(i))) elif a.startswith("FILE_NAME"): outfd.write("\n${0}\n".format(a)) if hasattr(i, "ParentDirectory"): full = mft_entry.get_full_path(i) self.table_header(outfd, i.get_header()) output = i.get_full(full) if output == None: continue outfd.write("{0}\n".format(output)) else: outfd.write("{0}\n".format(str(i))) elif a.startswith("DATA"): outfd.write("\n${0}\n".format(a)) contents = "\n".join(["{0:010x}: {1:<48} {2}".format(o, h, ''.join(c)) for o, h, c in utils.Hexdump(i)]) outfd.write("{0}\n".format(str(contents))) if len(str(i)) > 0: file_string = ".".join(["file", "0x{0:x}".format(offset), "data{0}".format(datanum), "dmp"]) datanum += 1 if self._config.DUMP_DIR != None: of_path = os.path.join(self._config.DUMP_DIR, file_string) of = open(of_path, 'wb') of.write(i) of.close() elif a == "OBJECT_ID": outfd.write("\n$OBJECT_ID\n") outfd.write(str(i)) outfd.write("\n{0}\n".format(border))
def render_text(self, outfd, data): keyfound = False for win7, reg, key in data: if key: keyfound = True outfd.write("----------------------------\n") outfd.write("Registry: {0}\n".format(reg)) outfd.write("Key name: {0}\n".format(key.Name)) outfd.write("Last updated: {0}\n".format(key.LastWriteTime)) outfd.write("\n") outfd.write("Subkeys:\n") for s in rawreg.subkeys(key): if s.Name == None: outfd.write(" Unknown subkey: " + s.Name.reason + "\n") else: outfd.write(" {0}\n".format(s.Name)) outfd.write("\n") outfd.write("Values:\n") for v in rawreg.values(key): tp, dat = rawreg.value_data(v) subname = v.Name if tp == 'REG_BINARY': dat_raw = dat dat = "\n".join(["{0:#010x} {1:<48} {2}".format(o, h, ''.join(c)) for o, h, c in utils.Hexdump(dat)]) try: subname = subname.encode('rot_13') except UnicodeDecodeError: pass if win7: guid = subname.split("\\")[0] if guid in folder_guids: subname = subname.replace(guid, folder_guids[guid]) d = self.parse_data(dat_raw) if d != None: dat = d + dat else: dat = "\n" + dat #these types shouldn't be encountered, but are just left here in case: if tp in ['REG_SZ', 'REG_EXPAND_SZ', 'REG_LINK']: dat = dat.encode("ascii", 'backslashreplace') if tp == 'REG_MULTI_SZ': for i in range(len(dat)): dat[i] = dat[i].encode("ascii", 'backslashreplace') outfd.write("\n{0:13} {1:15} : {2}\n".format(tp, subname, dat)) if not keyfound: outfd.write("The requested key could not be found in the hive(s) searched\n")
def render_text(self, outfd, data): if not has_distorm3: debug.warning("For best results please install distorm3") if self._config.DUMP_DIR and not os.path.isdir(self._config.DUMP_DIR): debug.error(self._config.DUMP_DIR + " is not a directory") refined_criteria = ["MZ", "\x55\x8B"] for task in data: for vad, address_space in task.get_vads( vad_filter=task._injection_filter): if self._is_vad_empty(vad, address_space): continue content = address_space.zread(vad.Start, 64) if self._config.REFINED and content[ 0:2] not in refined_criteria: continue outfd.write("Process: {0} Pid: {1} Address: {2:#x}\n".format( task.ImageFileName, task.UniqueProcessId, vad.Start)) outfd.write("Vad Tag: {0} Protection: {1}\n".format( vad.Tag, vadinfo.PROTECT_FLAGS.get(vad.VadFlags.Protection.v(), ""))) outfd.write("Flags: {0}\n".format(str(vad.VadFlags))) outfd.write("\n") # this is for address reporting in the output data_start = vad.Start # all zeros in the first page followed by 558B at the base of # the second page is an indicator of wiped PE headers if content.count(chr(0)) == len(content): if address_space.zread(vad.Start, 0x1000).count(chr(0)) == 0x1000: next_page = address_space.zread(vad.Start + 0x1000, 64) if next_page[0:2] == "\x55\x8B": outfd.write( "**** POSSIBLE WIPED PE HEADER AT BASE *****\n\n" ) content = next_page data_start = vad.Start + 0x1000 outfd.write("{0}\n".format("\n".join([ "{0:#010x} {1:<48} {2}".format(data_start + o, h, ''.join(c)) for o, h, c in utils.Hexdump(content) ]))) outfd.write("\n") outfd.write("\n".join([ "{0:#010x} {1:<16} {2}".format(o, h, i) for o, i, h in Disassemble(content, data_start) ])) # Dump the data if --dump-dir was supplied if self._config.DUMP_DIR: filename = os.path.join( self._config.DUMP_DIR, "process.{0:#x}.{1:#x}.dmp".format( task.obj_offset, vad.Start)) self.dump_vad(filename, vad, address_space) outfd.write("\n\n")