def lsmod(addr_space, profile): """ A Generator for modules (uses _KPCR symbols) """ ## Locate the kpcr struct - this is hard coded right now kpcr = NewObject("_KPCR", kpcr_addr, addr_space, profile=profile) ## Try to dereference the KdVersionBlock as a 64 bit struct DebuggerDataList = kpcr.KdVersionBlock.dereference_as( "_DBGKD_GET_VERSION64").DebuggerDataList if DebuggerDataList.is_valid(): offset = DebuggerDataList.dereference().v() ## This is a pointer to a _KDDEBUGGER_DATA64 struct. We only ## care about the PsActiveProcessHead entry: tmp = NewObject("_KDDEBUGGER_DATA64", offset, addr_space, profile=profile).PsLoadedModuleList if not tmp.is_valid(): ## Ok maybe its a 32 bit struct tmp = NewObject("_KDDEBUGGER_DATA32", offset, addr_space, profile=profile).PsLoadedModuleList ## Try to iterate over the process list in PsActiveProcessHead ## (its really a pointer to a _LIST_ENTRY) for l in tmp.dereference_as("_LIST_ENTRY").list_of_type( "_LDR_MODULE", "InLoadOrderModuleList"): yield l
def get_root(address_space, profile, stable=True): if stable: return NewObject("_CM_KEY_NODE", ROOT_INDEX, address_space, profile=profile) else: return NewObject("_CM_KEY_NODE", ROOT_INDEX | 0x80000000, address_space, profile=profile)
def list_of_type(self, type, member, forward=True): if not self.is_valid(): return ## Get the first element if forward: lst = self.Flink.dereference() else: lst = self.Blink.dereference() offset = self.profile.get_obj_offset(type, member) seen = set() seen.add(lst.offset) while 1: ## Instantiate the object obj = NewObject(type, offset=lst.offset - offset, vm=self.vm, parent=self.parent, profile=self.profile, name=type) if forward: lst = obj.m(member).Flink.dereference() else: lst = obj.m(member).Blink.dereference() if not lst.is_valid() or lst.offset in seen: return seen.add(lst.offset) yield obj
def next_xpress(self, XpressHeader, XpressBlockSize): XpressHeaderOffset = XpressBlockSize + XpressHeader.offset + \ XpressHeader.size() ## We only search this far BLOCKSIZE = 1024 original_offset = XpressHeaderOffset while 1: data = self.base.read(XpressHeaderOffset, BLOCKSIZE) Magic_offset = data.find("\x81\x81xpress") if Magic_offset >= 0: XpressHeaderOffset += Magic_offset break else: XpressHeaderOffset += len(data) ## Only search this far in advance if XpressHeaderOffset - original_offset > 10240: return None, None XpressHeader = NewObject("_IMAGE_XPRESS_HEADER", XpressHeaderOffset, self.base, profile=self.profile) XpressBlockSize = self.get_xpress_block_size(XpressHeader) return XpressHeader, XpressBlockSize
def pslist(addr_space, profile): """ A Generator for _EPROCESS objects (uses _KPCR symbols) """ ## Locate the kpcr struct - this is hard coded right now kpcr = NewObject("_KPCR", kpcr_addr, addr_space, profile=profile) ## Try to dereference the KdVersionBlock as a 64 bit struct DebuggerDataList = kpcr.KdVersionBlock.dereference_as( "_DBGKD_GET_VERSION64").DebuggerDataList PsActiveProcessHead = DebuggerDataList.dereference_as("_KDDEBUGGER_DATA64" ).PsActiveProcessHead \ or DebuggerDataList.dereference_as("_KDDEBUGGER_DATA32" ).PsActiveProcessHead \ or kpcr.KdVersionBlock.dereference_as("_KDDEBUGGER_DATA32" ).PsActiveProcessHead if PsActiveProcessHead: print type(PsActiveProcessHead) ## Try to iterate over the process list in PsActiveProcessHead ## (its really a pointer to a _LIST_ENTRY) for l in PsActiveProcessHead.dereference_as( "_LIST_ENTRY").list_of_type("_EPROCESS", "ActiveProcessLinks"): yield l else: raise RuntimeError( "Unable to find PsActiveProcessHead - is this image supported?")
def __init__(self, baseAddressSpace, opts): assert (baseAddressSpace) self.runs = [] self.base = baseAddressSpace self.PageDict = {} self.HighestPage = 0 self.PageIndex = 0 self.AddressList = [] self.LookupCache = {} self.PageCache = Store(50) self.MemRangeCnt = 0 self.offset = 0 # Extract header information self.profile = Profile() self.header = NewObject('_IMAGE_HIBER_HEADER', 0, baseAddressSpace, profile=self.profile) ## Is the signature right? assert (self.header.Signature.v() == 'hibr') # Extract processor state self.ProcState = NewObject("_KPROCESSOR_STATE", 2 * 4096, baseAddressSpace, profile=self.profile) ## This is a pointer to the page table - any ASs above us dont ## need to search for it. self.dtb = self.ProcState.SpecialRegisters.Cr3.v() try: fd = open("/tmp/cache.bin", 'rb') data = pickle.load(fd) self.PageDict, self.LookupCache = data fd.close() except (IOError, EOFError): self.build_page_cache() fd = open("/tmp/cache.bin", 'wb') pickle.dump((self.PageDict, self.LookupCache), fd, -1) fd.close()
def subkeys(key): if not key.is_valid(): return if key.SubKeyCounts[0] > 0: sk_off = key.SubKeyLists[0] sk = NewObject("_CM_KEY_INDEX", sk_off, key.vm, profile=key.profile) if not sk or not sk.is_valid(): pass else: for i in read_sklist(sk): if i.Signature.v() == NK_SIG: yield i if key.SubKeyCounts[1] > 0: sk_off = key.SubKeyLists[1] sk = NewObject("_CM_KEY_INDEX", sk_off, key.vm, profile=key.profile) if not sk or not sk.is_valid(): pass else: for i in read_sklist(sk): if i and i.Signature.v() == NK_SIG: yield i
def _make_handle_array(self, offset, level): """ Returns an array of _HANDLE_TABLE_ENTRY rooted at offset, and iterates over them. """ table = NewObject("Array", offset, self.vm, count=0x200, parent=self, profile=self.profile, target=Curry(NewObject, "_HANDLE_TABLE_ENTRY")) for t in table: offset = t.dereference_as('unsigned int') if not offset.is_valid(): break if level > 0: ## We need to go deeper: for h in self._make_handle_array(offset, level - 1): yield h else: ## OK We got to the bottom table, we just resolve ## objects here: offset = int(offset) & ~0x00000007 obj = NewObject("_OBJECT_HEADER", offset, self.vm, parent=self, profile=self.profile) try: if obj.Type.Name.__str__() == 'File': file = NewObject("_FILE_OBJECT", obj.Body.offset, self.vm, parent=self, profile=self.profile) yield file except Exception, e: pass
def get_tcb_connections(self, base_addr, TCBTableOff, SizeOff): """ Follow the list of TCB Tables specified. The TCBTable is a hash table of lists to existing connections. The TCBTableOff and SizeOff are offsets relative to the BaseAddress of the tcpip.sys module (i.e. they are static module variables) to the hash table in memory. """ ## We first find the size of the hash table: hash_table_size = NewObject('unsigned long', base_addr + SizeOff, self.addr_space, profile=self.profile).v() ## This is how we define a new type on the fly - We dont ## actually store it in the profile we only use it here. TCB_Table = self.profile.list_to_type( ## Thats the name of the type "TCB_Table", ## This is the new type: ## It is a pointer to an array of size hash_table_size of pointers to _TCPT_OBJECTs [ 'pointer', ['array', hash_table_size, ['pointer', ['_TCPT_OBJECT']]] ]) ## To actually use it we need to instantiate it directly (we ## never stored it in the profile so we cant use NewObject). ## When we instantiate it we need to provide it with the ## missing parameters, namely the offset and address_space. TCB_Table = TCB_Table( offset=base_addr + TCBTableOff, profile=self.profile, vm=self.addr_space, ).dereference() ## If the pointer fails to dereference (i.e. it points ## somewhere invalid), we skip it: if not TCB_Table: return ## Now we just iterate over all _TCPT_OBJECT in the table and ## see if they follow to linked lists. We then traverse the ## lists: for i in TCB_Table: while i.is_valid(): yield i.Pid.v( ), i.RemoteIpAddress, i.RemotePort, i.LocalIpAddress, i.LocalPort i = i.Next
def _Peb(self, attr): """ Returns a _PEB object which is using the process address space. The PEB structure is referencing back into the process address space so we need to switch address spaces when we look at it. This method ensure this happens automatically. """ process_ad = self.get_process_address_space() if process_ad: offset = self.m("Peb").v() peb = NewObject("_PEB", offset, vm=process_ad, profile=self.profile, name="Peb", parent=self) if peb.is_valid(): return peb
def read_sklist(sk): if (sk.Signature.v() == LH_SIG or sk.Signature.v() == LF_SIG): for i in sk.List: yield i elif sk.Signature.v() == RI_SIG: for i in range(sk.Count): # Read and dereference the pointer ptr_off = sk.get_member_offset('List') + (i * 4) if not self.vm.is_valid_address(ptr_off): continue ssk_off = read_value(self.vm, "unsigned int", ptr_off) if not self.vm.is_valid_address(ssk_off): continue ssk = NewObject("_CM_KEY_INDEX", ssk_off, sk.vm, profile=sk.profile) for i in read_sklist(ssk): yield i
def __init__(self, fname, mode='rb', fast=False): FileAddressSpace.__init__(self, fname, mode=mode, fast=fast) ## Parse the headers: address_space = FileAddressSpace(fname) profile = Profile(abstract_types=elf_types) header = NewObject('Elf32_Ehdr', 0, address_space, profile=profile) ## Create a sorted list of virtual offsets self.offsets = [] for i in header.sections: if i.p_filesz.v() > 0: self.offsets.append((i.p_vaddr.v(), ## Vaddr start i.p_vaddr.v() + i.p_filesz.v(), ## Vaddr end i.p_offset.v())) def comp(x,y): if x[0]<y[0]: return -1 return 1 self.offsets.sort(comp) print self.offsets
def __init__(self, baseAddressSpace, opts): ## We must have an AS below us assert (baseAddressSpace) ## Must start with the magic PAGEDUMP assert (baseAddressSpace.read(0, 8) == 'PAGEDUMP') self.runs = [] self.offset = opts.get('offset', 0) self.base = baseAddressSpace self.fname = '' self.profile = Profile() self.header = NewObject("_DMP_HEADER", self.offset, baseAddressSpace, profile=self.profile) self.runs = [ (x.BasePage.v(), x.PageCount.v()) \ for x in self.header.PhysicalMemoryBlockBuffer.Run ] self.dtb = self.header.DirectoryTableBase.v()
def _find_dtb(self): offset = 0 while 1: data = self.base.read(offset, BLOCKSIZE) found = 0 if not data: break while 1: found = data.find("\x03\x00\x1b\x00", found + 1) if found >= 0: (type, size) = unpack('=HH', data[found:found + 4]) proc = NewObject("_EPROCESS", offset + found, self.base, profile=self.profile) if 'Idle' in proc.ImageFileName.v(): return proc.Pcb.DirectoryTableBase[0] else: break offset += len(data) return None
def build_page_cache(self): XpressIndex = 0 XpressHeader = NewObject("_IMAGE_XPRESS_HEADER", (self.header.FirstTablePage + 1) * 4096, \ self.base, profile=self.profile) XpressBlockSize = self.get_xpress_block_size(XpressHeader) MemoryArrayOffset = self.header.FirstTablePage * 4096 while MemoryArrayOffset: MemoryArray = NewObject('_MEMORY_RANGE_ARRAY', MemoryArrayOffset, self.base, profile=self.profile) EntryCount = MemoryArray.MemArrayLink.EntryCount.v() for i in MemoryArray.RangeTable: start = i.StartPage.v() end = i.EndPage.v() LocalPageCnt = end - start if end > self.HighestPage: self.HighestPage = end tmp = [start * 0x1000, \ LocalPageCnt * 0x1000] self.AddressList.append(tmp) for j in range(0, LocalPageCnt): if (XpressIndex and ((XpressIndex % 0x10) == 0)): XpressHeader, XpressBlockSize = \ self.next_xpress(XpressHeader, XpressBlockSize) PageNumber = start + j XpressPage = XpressIndex % 0x10 #print [(PageNumber,XpressBlockSize,XpressPage)] if XpressHeader.offset not in self.PageDict: self.PageDict[XpressHeader.offset] = \ [(PageNumber,XpressBlockSize,XpressPage)] else: self.PageDict[XpressHeader.offset].append( (PageNumber, \ XpressBlockSize, XpressPage)) ## Update the lookup cache self.LookupCache[PageNumber] = (XpressHeader.offset, XpressBlockSize, XpressPage) self.PageIndex += 1 XpressIndex += 1 NextTable = MemoryArray.MemArrayLink.NextTable.v() if (NextTable and (EntryCount == 0xFF)): MemoryArrayOffset = NextTable * 0x1000 self.MemRangeCnt += 1 XpressHeader,XpressBlockSize = \ self.next_xpress(XpressHeader, XpressBlockSize) XpressIndex = 0 else: MemoryArrayOffset = 0