def __init__(self, filename, session=None, readers_public_key=None, writers_private_key=None): self.fd = standard.WritableAddressSpace(filename=filename, session=session, mode="w+b") self.session = session self.profile = AgentProfile(session=session) self.cipher = CipherProperties(session=session).generate_keys() self.readers_public_key = readers_public_key self.writers_private_key = writers_private_key # Cipher is encrypted with the reader's public key - only the reader can # read it. It is also signed with the sender's private key. signature = Signature(session=session) cipher_plain_text = self.cipher.to_json() signature.encrypted_cipher = readers_public_key.encrypt( cipher_plain_text) signature.signature = writers_private_key.sign(cipher_plain_text) serialized_signature = signature.to_json() self.write_part(serialized_signature, "EncryptedCipher") self.hmac = hmac.HMAC(self.cipher.hmac_key.RawBytes(), hashes.SHA256(), backend=openssl.backend) self.hmac.update(serialized_signature)
def collect(self): PAGE_SIZE = 0x1000 # We write the image to the destination using the WritableAddressSpace. out_as = standard.WritableAddressSpace( filename=self.plugin_args.destination, session=self.session, mode="w+b") # Pad the header area with PAGE pattern: if self.profile.metadata("arch") == "AMD64": header = self.profile._DMP_HEADER64(vm=out_as) out_as.write(0, "PAGE" * (header.obj_size / 4)) out_as.write(4, "DU64") else: # 32 bit systems use a smaller structure. header = self.profile._DMP_HEADER(vm=out_as) out_as.write(0, "PAGE" * (header.obj_size / 4)) out_as.write(4, "DUMP") # PEA address spaces. if getattr(self.kernel_address_space, "pae", None): header.PaeEnabled = 1 # Write the runs from our physical address space. number_of_pages = 0 i = None for i, run in enumerate(self.physical_address_space.get_mappings()): # Convert to pages start = run.start / PAGE_SIZE length = run.length / PAGE_SIZE header.PhysicalMemoryBlockBuffer.Run[i].BasePage = start header.PhysicalMemoryBlockBuffer.Run[i].PageCount = length number_of_pages += length # There must be at least one run. if i is None: raise plugin.PluginError( "Physical address space has no available data.") header.PhysicalMemoryBlockBuffer.NumberOfRuns = i + 1 header.PhysicalMemoryBlockBuffer.NumberOfPages = number_of_pages resolver = self.session.address_resolver # Set members of the crash header header.MajorVersion = 0xf header.MinorVersion = 0x1db1 header.DirectoryTableBase = self.session.GetParameter("dtb") header.PfnDataBase = self._pointer_to_int( resolver.get_address_by_name("nt!MmPfnDatabase")) header.PsLoadedModuleList = self._pointer_to_int( resolver.get_address_by_name("nt!PsLoadedModuleList")) header.PsActiveProcessHead = self._pointer_to_int( resolver.get_address_by_name("nt!PsActiveProcessHead")) header.KdDebuggerDataBlock = self._pointer_to_int( resolver.get_address_by_name("nt!KdDebuggerDataBlock")) header.MachineImageType = 0x8664 # Find the number of processors header.NumberProcessors = self.profile.get_constant_object( "KeNumberProcessors", "unsigned int") # Copy some stuff from _KUSER_SHARED_DATA. kuser_shared = self.profile.get_constant_object( "KI_USER_SHARED_DATA", "_KUSER_SHARED_DATA") header.SystemTime = kuser_shared.SystemTime.as_windows_timestamp() header.SystemUpTime = ( kuser_shared.InterruptTime.LowPart + kuser_shared.InterruptTime.High1Time << 32) / 100000 header.ProductType = kuser_shared.NtProductType header.SuiteMask = kuser_shared.SuiteMask # Zero out the BugCheck members header.BugCheckCode = 0x00000000 header.BugCheckCodeParameter[0] = 0x00000000 header.BugCheckCodeParameter[1] = 0x00000000 header.BugCheckCodeParameter[2] = 0x00000000 header.BugCheckCodeParameter[3] = 0x00000000 # Set the sample run information header.RequiredDumpSpace = number_of_pages + header.obj_size / PAGE_SIZE header.DumpType = 1 # Zero out the remaining non-essential fields from ContextRecordOffset # to ExceptionOffset. out_as.write( header.ContextRecord.obj_offset, "\x00" * (header.m("Exception").obj_offset - header.ContextRecord.obj_offset)) # Set the "converted" comment out_as.write(header.Comment.obj_offset, "Created with Rekall Memory Forensics\x00") # Now copy the physical address space to the output file. output_offset = header.obj_size for run in self.physical_address_space.get_mappings(): # Convert to pages start = run.start / PAGE_SIZE length = run.length / PAGE_SIZE yield ("\nRun [0x%08X, 0x%08X] \n" % (start, length), ) data_length = length * PAGE_SIZE start_offset = start * PAGE_SIZE offset = 0 while data_length > 0: to_read = min(data_length, self.buffer_size) data = self.physical_address_space.read( start_offset + offset, to_read) out_as.write(output_offset, data) output_offset += len(data) offset += len(data) data_length -= len(data) self.session.render_progress( "Wrote %sMB.", (start_offset + offset) / 1024 / 1024) # Rebuild the KDBG data block if needed. According to the # disassembly of nt!KdCopyDataBlock the data block is # encrypted when nt!KdpDataBlockEncoded is non zero: # ------ nt!KdCopyDataBlock ------ # SUB RSP, 0x28 # CMP BYTE [RIP+0x10fac7], 0x0 0x0 nt!KdpDataBlockEncoded # MOV RDX, RCX # JZ 0xf8000291e6a7 nt!KdCopyDataBlock + 0x57 if self.plugin_args.rebuild or self.profile.get_constant_object( "KdpDataBlockEncoded", "byte") > 0: yield ("Rebuilding KDBG data block.\n", ) self.RebuildKDBG(out_as)
aux.vna_name = template.vna_name def remove_symbol_versions(hdr): versyms = hdr.section_by_name(".gnu.version") sym_table = versyms.get_section() # Just remove all versions from all symbols. for i, other_ref in enumerate(sym_table): sym_table[i] = 0 if __name__ == "__main__": argument_parser = argparse.ArgumentParser() argument_parser.add_argument( 'binary', default=None, help="Path to the ELF binary." ) args = argument_parser.parse_args() print ("***Modifying file %s **" % args.binary) vm = standard.WritableAddressSpace( filename=args.binary, session=session.Session(), mode="r+b") profile = elf.ELFProfile(session=session) hdr = profile.elf64_hdr(vm=vm, offset=0) fix_version_needed(hdr) remove_symbol_versions(hdr)