def handler_onRet(self): self.unsetBpOnEip() #self.br.dbiprintf(" -> after pAlloc : 0x%08x" % self.iVmPAllocAddr) cmdr = pykd.dbgCommand("dd %x L1" % self.iVmPAllocAddr) if cmdr == None: self.br.dbiprintf("[E] After %s : Cannot dump memory" % self.symAllocateVirtualMemory) return pykd.eventResult.Break strAllocAddr = cmdr[cmdr.find(" "):] iAllocAddr = int(strAllocAddr, 16) self.iVmAllocAddr = iAllocAddr #self.br.dbiprintf(" -> after pSize : 0x%08x" % self.iVmPAllocSize) cmdr = pykd.dbgCommand("dd %x L1" % self.iVmPAllocSize) if cmdr == None: self.br.dbiprintf("[E] After %s : Cannot dump memory" % self.symAllocateVirtualMemory) return pykd.eventResult.Break strAllocSize = cmdr[cmdr.find(" "):] iAllocSize = int(strAllocSize, 16) self.iVmAllocSize = iAllocSize self.lObfusMem[iAllocAddr] = iAllocSize self.memh.setBpMemoryOnWrite(iAllocAddr, iAllocSize) self.br.dbiprintf( "[+] Allocating obfuscation memory(0x%08x) = 0x%08x" % (iAllocSize, iAllocAddr)) self.memh.setMemBpOnWriteOnIat() self.pRet = 0 self.bp_end = None return pykd.eventResult.Proceed
def check_sections_mem_rights(self): exe_handle = pykd.dbgCommand("lm").split("\n")[1].split(" ")[0] dh_info = pykd.dbgCommand("!dh " + exe_handle) sec_data = '' start = dh_info.find("SECTION HEADER #") sec = '' sec_data = dh_info[start:len(dh_info)] for i in sec_data.split("\n"): sec += i + "\n" if len(i) == 0: if "Execute Read Write" in sec or "Execute Write" in sec or "Execute Write Copy" in sec: addr = hex( int(exe_handle, 16) + int( sec.split("\n")[3].strip(" ").split(" ")[0], 16) )[2:] if pykd.dbgCommand("u " + addr).split(" ")[1] == "0000": self.allocated_pointers.update({ addr: int( sec.split("\n")[2].strip(" ").split(" ")[0], 16) }) else: pass sec = '' elif "Execute Read" in sec: sec = '' else: sec = ''
def alias(clx, cmd, func): print("as {} !py -g {} {}".format( cmd, os.path.dirname(sys.argv[0]) + "\\bywin.py", func)) pykd.dbgCommand("as {} !py -g {} {}".format( cmd, os.path.dirname(sys.argv[0]) + "\\bywin.py", func))
def getImageInfo(self): iPImageBaseBegin = "ImageBaseAddress:" iPImageBaseEnd = "Ldr" iPImageNameBegin = "ImageFile:" iPImageNameEnd = "CommandLine" self.dbiprintf("[!] Get image information") cmdr = pykd.dbgCommand("!peb") if type(cmdr) == types.NoneType: self.dbiprintf(" - [E] Error on get PEB") return 1 # get image base from PEB if cmdr.find(iPImageBaseBegin) == -1: self.dbiprintf(" - [E] Error on get image base address") self.dbiprintf(cmdr) return 2 strBase = cmdr[cmdr.find(iPImageBaseBegin) + len(iPImageBaseBegin):cmdr.find(iPImageBaseEnd)] base = int(strBase, 16) self.procImageBase = base # get image name from PEB if cmdr.find(iPImageNameBegin) == -1: self.dbiprintf(" - [E] Error on get image name") self.dbiprintf(cmdr) return 3 path = cmdr[cmdr.find(iPImageNameBegin) + len(iPImageNameBegin):cmdr.find(iPImageNameEnd)] name = path[path.rfind("\\") + 1:path.rfind("'")] self.imageName = name # get image end from module list cmdr = pykd.dbgCommand("lm") if type(cmdr) == types.NoneType: self.dbiprintf(" - [E] Error on get module list") return 4 if cmdr.find("%08x" % base) == -1: self.dbiprintf( " - [E] Error to find image base address from module list") self.dbiprintf(cmdr) return 5 strImage = cmdr[cmdr.find("%08x" % base):] lImage = strImage.split() try: if base != int(lImage[0], 16): self.dbiprintf( " - [E] Error to find image base address from module list") self.dbiprintf(cmdr) return 6 self.procImageEnd = int(lImage[1], 16) self.procImageSize = self.procImageEnd - self.procImageBase except: self.dbiprintf( " - [E] Error to find image base address from module list") self.dbiprintf(cmdr) return 7 self.dbiprintf( " -> Image name : %s ( 0x%08x ~ 0x%08x ( 0x%08x ) )" % (name, self.procImageBase, self.procImageEnd, self.procImageSize)) return 0
def main(args): modules = pykd.dbgCommand('lm') for mod_line in modules.splitlines(): module = Module(mod_line) if module.name.lower() not in [mod.lower() for mod in args.modules]: continue print(f'[+] searching {module.name} for pop r32; pop r32; ret') for pop1 in range(0x58, 0x60): for pop2 in range(0x58, 0x60): command = f's-[1]b {module.start} {module.end} {hex(pop1)} {hex(pop2)} c3' result = pykd.dbgCommand(command) if result is None: continue for addr in result.splitlines(): try: print( f'[+] {module.name}::{addr}: pop {PopR32(pop1).name}; pop {PopR32(pop2).name}; ret' ) except ValueError: # not a valid pop r32 pass
def inspectKernelTimer(): try: cmdline = '.reload;' r = pykd.dbgCommand(cmdline) cmdline = r'!timer' r = pykd.dbgCommand(cmdline) r = r.splitlines() start = 0 idx = 0 for i in r: i = i.strip() if i.startswith('List Timer'): start = 1 continue if start != 1: continue data = i.strip() pos = data.find('(DPC @ ') if pos != -1: endpos = data.find(')', pos) data = data[pos + len('(DPC @ '):endpos] dpc = pykd.addr64(int(data, 16)) if dpc <= int(mmhighestuseraddress): print i, '!!!!!!!!' else: dpcobj = pykd.typedVar('nt!_KDPC', dpc) symbolname = pykd.findSymbol(dpcobj.DeferredRoutine) print '%d dpc:%x timerfunc:%x %s' % ( idx, int(dpc), int(dpcobj.DeferredRoutine), symbolname) idx += 1 except Exception, err: print traceback.format_exc()
def writeHookInterp(hook_address): """Write the code for the setNative hook""" # 0: 60 pusha # save registers # 1: 89 D9 mov ecx,ebx # ebx = MethodInfo # 1: 8b 4c 24 24 mov ecx,[esp+24] # poi(esp+24) = address of # # the func we want # # to name # 3: 30 d2 xor dl,dl # 5: b8 ff ff ff ff mov eax,0xffffffff # load getMethodName # # address # a: ff d0 call eax # call getMethodName # c: 61 popa # restore registers # d: 33 C0 xor eax, eax # first inst of setInterp # global NPS NPS["SetInterpRet"] = findAllocRets('setInterp', None, ["\xC2", "\x0C", "\x00"], True)[0] absaddr = setInterp = "" for b in struct.pack("<L",(func_addr['getMethodName'])): absaddr += hex(struct.unpack("B",b)[0]).split("0x")[1] + " " # plus 2 so we dont hit the BP again jmp = calcJmp(hook_address+0x11, func_addr['setInterp']+0x2) for b in jmp: setInterp += hex(ord(b)).split("0x")[1] + " " xbytes = "60 8b 4c 24 24 30 D2 B8 " + absaddr + "ff d0 61 33 C0 " + setInterp ebcmd = "eb 0x%x %s" % (hook_address, xbytes) pykd.dbgCommand(ebcmd)
def bpHandlerJit(): """Create and Install getMethodName hook void BaseExecMgr::setJit(MethodInfo* m, GprMethodProc p) Stringp MethodInfo::getMethodName(bool includeAllNamesplaces) const""" global NPS, GBP if not NPS['HOOK_JIT']: # Setting up alloc monitor if requested if NPS['list_gcallocs']: if not GBP["StartMonitorOnFunc"] : GBP["START_ALLOC_MONITOR"] = True monitorGCAlloc() if NPS['list_fmallocs']: if not GBP["StartMonitorOnFunc"] : GBP["START_ALLOC_MONITOR"] = True monitorFixedMallocOutOfLineAlloc() monitorFixedMallocLargeAlloc() monitorFixedMalloc() if NPS['list_HeapAlloc']: if not GBP["StartMonitorOnFunc"] : GBP["START_ALLOC_MONITOR"] = True monitorHeapAlloc() # Allocate memory for our hook getMethodNameHook = int((pykd.dbgCommand(".dvalloc 1000").\ split()[-1]),16) print "[+] Jit Hook setup at address 0x%x" % getMethodNameHook # Write the Jit hook writeHookJit(getMethodNameHook) NPS['HOOK_JIT'] = getMethodNameHook print "[+] Start hooking Jitted Flash functions..." # Set the breakpoit right after getMethodName returns so that # we can read the resolved function name and address GBP['HOOK_JIT'] = pykd.setBp(NPS['HOOK_JIT']+0xc, hookHandlerJit) # Redirect to our Jit hook pykd.dbgCommand("r eip=0x%x" % NPS['HOOK_JIT']) return pykd.executionStatus.NoChange
def log_parameters(self, api, ret_addr, eip, api_name_only): on_ret = False ts = int(time.time()) try: if self.mainClass.apis_dict[api_name_only] == "yes": on_ret = True except Exception as e: print "Exception in reading ret:", e if "_completed" in api: self.log_api_params(api_name_only) # flush the previous api name self.prev_api = '' # remove one time breakpoints from bl bl = pykd.dbgCommand("bl") index_of_breakpoint = bl.find(eip) tmp = bl[index_of_breakpoint - 8:index_of_breakpoint - 3].split("\n")[1] pykd.dbgCommand("bc " + tmp) #sys.exit(1) elif on_ret == True: self.mainClass.bp_init.append( pykd.setBp(int(ret_addr, 16), self.mainClass.break_hit)) a = '' a = pykd.dbgCommand("dd esp") self.mainClass.prev_stack = a self.mainClass.prev_addr = a.split(" ")[4] self.mainClass.prev_size = a.split(" ")[5] self.mainClass.breakpoints_info.update( {ret_addr: api + "_completed"}) self.mainClass.apis_dict.update({api + "_completed": "1"}) else: # log parameters values to dict and save to json file self.log_api_params(api_name_only)
def allocServedFixedMallocLargeAlloc(req_size, ret, FixedMalloc): """Callback invoked just before the FixedMalloc Large function returns. EAX will store the allocation address""" global GBP # FixedMalloc::InitInstance # this->m_heap = MMgc::GCHeap; # this->m_largeAllocHeapPartition = fixedPartitionMap[partition]; # m_largeAllocHeapPartition is at offset + 0x4 if IsheapIsolVersion(): Partition = pykd.ptrPtr((FixedMalloc+0x4)) else: Partition = "NotImplemented" if GBP["START_ALLOC_MONITOR"]: returned_allocsize = ((req_size + 0xfff)>>0xC)*0x1000 if NPS['ffmsize']: if NPS['ffmsize'] == returned_allocsize: print "[FixedMalloc::LargeAlloc] Requested Allocation of \ size:0x%x Returned allocation of size:0x%x at address:0x%x FixedMalloc:0x%x \ Partition: %s" %\ (req_size, returned_allocsize, pykd.reg("eax"), FixedMalloc, Partition) else: print "[FixedMalloc::LargeAlloc] Requested Allocation of \ size:0x%x Returned allocation of size:0x%x at address:0x%x FixedMalloc:0x%x \ Partition: %s" %\ (req_size, returned_allocsize, pykd.reg("eax"), FixedMalloc, Partition) GBP["AllocHistory"][pykd.reg("eax")] = pykd.dbgCommand("kv") +\ "\n\nRAW Stack data in case FPO is in place:\n\n" +\ pykd.dbgCommand("dps esp L100") return pykd.executionStatus.NoChange
def get_alias(name): ret = pykd.dbgCommand(".echo %s"%(name)).strip() pykd.dbgCommand(".echo") # clear last command if ret == name: return '' else: return ret
def inspectKernelTimer(): try: cmdline='.reload;' r=pykd.dbgCommand(cmdline) cmdline=r'!timer' r=pykd.dbgCommand(cmdline) r=r.splitlines() start=0 idx=0 for i in r: i=i.strip() if i.startswith('List Timer'): start=1 continue if start!=1: continue data=i.strip() pos=data.find('(DPC @ ') if pos!=-1: endpos=data.find(')', pos) data=data[pos+len('(DPC @ '):endpos] dpc=pykd.addr64(int(data, 16)) if dpc<=int(mmhighestuseraddress): print i, '!!!!!!!!' else: dpcobj=pykd.typedVar('nt!_KDPC', dpc) symbolname=pykd.findSymbol(dpcobj.DeferredRoutine) print '%d dpc:%x timerfunc:%x %s' % (idx, int(dpc), int(dpcobj.DeferredRoutine), symbolname) idx+=1 except Exception, err: print traceback.format_exc()
def main(args): modules = pykd.dbgCommand("lm") totalGadgets = 0 # This tracks all the total number of usable gadgets modGadgetCount = {} # This tracks the number of gadgets per module for mod_line in modules.splitlines(): module = Module(mod_line) if module.name.lower() not in [mod.lower() for mod in args.modules]: continue numGadgets = 0 # This is the number of gadgets found in this module print(f"[+] searching {module.name} for pop r32; pop r32; ret") print("[+] BADCHARS: ", end="") for i in args.bad: print("\\x{:02X}".format(i), end="") print() for pop1 in range(0x58, 0x60): for pop2 in range(0x58, 0x60): command = ( f"s-[1]b {module.start} {module.end} {hex(pop1)} {hex(pop2)} c3" ) result = pykd.dbgCommand(command) if result is None: continue for addr in result.splitlines(): try: bAddr = int(addr, 16).to_bytes(4, "little") bcChk = checkBadChars(bAddr, args.bad) bAddrEsc = "" # This is the escaped string containing the little endian addr for shellcode output for b in bAddr: bAddrEsc += "\\x{:02X}".format(b) if args.showbc and bcChk == "--": print( f"[{bcChk}] {module.name}::{addr}: pop {PopR32(pop1).name}; pop {PopR32(pop2).name}; ret ; {bAddrEsc}" ) elif bcChk == "OK": print( f"[{bcChk}] {module.name}::{addr}: pop {PopR32(pop1).name}; pop {PopR32(pop2).name}; ret ; {bAddrEsc}" ) numGadgets = numGadgets + 1 except ValueError: # not a valid pop r32 pass print(f"[+] {module.name}: Found {numGadgets} usable gadgets!") modGadgetCount[module.name] = numGadgets # Add to the dict totalGadgets = (totalGadgets + numGadgets ) # Increment total number of gadgets found print("\n---- STATS ----") # Print out all the stats print(">> BADCHARS: ", end="") for i in args.bad: print("\\x{:02X}".format(i), end="") print() print(f">> Usable Gadgets Found: {totalGadgets}") print(">> Module Gadget Counts") for m, c in modGadgetCount.items(): print(" - {}: {} ".format(m, c))
def InitTracer(): global DriverObject global ImageBase global NtImageEnd NtModule = pykd.module("nt") NtImageBase = NtModule.begin() NtImageEnd = NtModule.end() pykd.dbgCommand("ba e1 IopLoadDriver+4bd") pykd.dbgCommand("ba e1 IopLoadDriver+4c2") pykd.go() while(1): regPath = pykd.dbgCommand("du /c40 @rdx+10") if "VmpDriver.vmp" in regPath: print "[*] Find VMP Driver" DriverObject = pykd.reg("rcx") print "\t[-] Driver Object : 0x{:X}".format(DriverObject) ImageBase =pykd.ptrPtr(DriverObject+0x18) # DriverObject.DriverStart print "\t[-] ImageBase Address : 0x{:X}".format(ImageBase) VMPTracingSub.GetSectionInfo(ImageBase) EntryPoint = ImageBase + VMPTracingSub.EntryPoint_Off strEntryPoint = hex(EntryPoint).rstrip("L") pykd.dbgCommand("ba e1 "+strEntryPoint) pykd.go() pykd.dbgCommand("bc 2") return pykd.go()
def inspectInlineHook(modulepath, modulebase): try: print '='*10, 'scan inlinehook in %s' % modulepath, '='*10 driversdir=os.path.join(g_system32dir, 'drivers') symbolpath=g_sympath symbolpath=add_symbolpath(symbolpath, driversdir) symbolpath=add_symbolpath(symbolpath, os.path.dirname(modulepath)) cmdline='.sympath %s' % symbolpath r=pykd.dbgCommand(cmdline) cmdline='.reload;' r=pykd.dbgCommand(cmdline) filedata=open(modulepath, 'rb').read() pe = pefile.PE(data=filedata, fast_load=True) if pe.DOS_HEADER.e_magic!=0X5A4D or pe.NT_HEADERS.Signature!=0x4550: raise Exception("%s is not a pe file" % modulepath) for i in pe.sections: try: if pefile.SECTION_CHARACTERISTICS['IMAGE_SCN_MEM_DISCARDABLE']&i.Characteristics: #print i.Name, 'discard' continue elif not (pefile.SECTION_CHARACTERISTICS['IMAGE_SCN_MEM_EXECUTE']&i.Characteristics): #print i.Name, 'not executable' continue comparesize=i.Misc_VirtualSize fileoffsetstart=i.PointerToRawData fileoffsetend=fileoffsetstart+comparesize memoffsetstart=modulebase+ i.VirtualAddress memoffsetend=memoffsetstart+comparesize print '-'*10 print '%s :%x-%x <--> %x-%x size:%d' % (i.Name, fileoffsetstart, fileoffsetend, memoffsetstart, memoffsetend, comparesize) if modulepath.lower()==g_kernelpath.lower(): cmdline='!chkimg nt -r %x %x -v -d' % (memoffsetstart, memoffsetend) else: name=os.path.splitext(os.path.basename(modulepath))[0] cmdline='!chkimg %s -r %x %x -v -d' % (name, memoffsetstart, memoffsetend) #repair cmdline='!chkimg %s -r %x %x -v -d -f' % (os.path.basename(modulepath), startaddr, endaddr) #print cmdline r=pykd.dbgCommand(cmdline) if r.find('[')!=-1: print '!!!!hooklist' r=r.splitlines() for i in r: print i else: print 'no hooks' except Exception, err: print traceback.format_exc() except Exception, err: print traceback.format_exc()
def allocServedHeapAllocSystemRet(size, heap, tid): """Callback invoked before HeapAlloc returns to intercept the allocation address""" global GBP print "[HeapAlloc] Requested Allocation of size 0x%x \ on Heap 0x%x address 0x%x Thread: 0x%x" %\ (size, heap, pykd.reg("eax"), tid) GBP["AllocHistory"][pykd.reg("eax")] = pykd.dbgCommand("kv") +\ "\n\nRAW Stack data in case FPO is in place:\n\n" +\ pykd.dbgCommand("dps esp L100") del GBP["HeapAllocRet"]
def allocServedFixedMallocOutOfLineAlloc(allocsize, ret): """Callback invoked just before the FixedMalloc OutOfLine function returns. EAX will store the allocation address""" global GBP allocaddress = pykd.reg("eax") # If allocsize is greater than 0x7f0 the allocation will be served by # FixedMalloc::LargeAlloc if allocsize <= 0x7f0: if GBP["START_ALLOC_MONITOR"]: returned_allocsize = pykd.ptrPtr((allocaddress & 0xfffff000)+0x12) # FixedAlloc allocator allocator = pykd.ptrPtr((allocaddress & 0xfffff000)+0x1C) # FixedAlloc.h#L120 # GCHeap *m_heap; //The heap from which we # //obtain memory # int m_heapPartition; //The heap partition from which we # //obtain memory # uint32_t m_itemsPerBlock; //Number of items that fit in a block # uint32_t m_itemSize; //Size of each individual item # FixedBlock* m_firstBlock; //First block on list of free blocks # FixedBlock* m_lastBlock; //Last block on list of free blocks # FixedBlock* m_firstFree; //The lowest priority block that has # //free items # size_t m_numBlocks; //Number of blocks owned by this # //allocator if IsheapIsolVersion(): heapPartition = pykd.ptrPtr(allocator+0x4) else: heapPartition = "NotImplemented" kSizeClass = kSizeClassIndex[((allocsize+7)>>3)] MMgc_FixedMalloc_obj =\ allocator - kSizeClass*NPS["FixedAllocSafeSize"] -\ NPS["m_allocs_offset"] if NPS['ffmsize']: if NPS['ffmsize'] == returned_allocsize: print "[FixedMalloc::OutOfLineAlloc] Requested Allocation \ of size:0x%x Returned allocation of size:0x%x at address:0x%x \ (MMgc::FixedMalloc Instance: 0x%x HeapPartition: %s)" % (allocsize, returned_allocsize, allocaddress, MMgc_FixedMalloc_obj, heapPartition) else: print "[FixedMalloc::OutOfLineAlloc] Requested Allocation of \ size:0x%x Returned allocation of size:0x%x at address:0x%x \ (MMgc::FixedMalloc Instance: 0x%x HeapPartition: %s)" % (allocsize, returned_allocsize, allocaddress, MMgc_FixedMalloc_obj, heapPartition) GBP["AllocHistory"][allocaddress] = pykd.dbgCommand("kv") +\ "\n\n" +\ "\n\nRAW Stack data in case FPO is in place:\n\n" +\ pykd.dbgCommand("dps esp L100") # Delete the breakpoint del GBP[ret] return pykd.executionStatus.NoChange
def listFrameDetails(): print 'Listing frame details...' FRAME_NUM = 30 out = '' for j in range(0, FRAME_NUM): out = pykd.dbgCommand('.frame ' + str(j)) if out is None: return pykd.dprintln(out) out = pykd.dbgCommand('dv /i/t/V') if out is None: return pykd.dprintln(out)
def sig_memcpy(self): print("[+] memcpy") if self.alloc_mem != pykd.reg("rsi") - 0x10: print("[!!!!!] something wrong") print( pykd.dbgCommand("db " + hex(pykd.reg("rsi") - 0x10) + " l" + hex(self.alloc_size))) print("[+] Next Chunk") print( pykd.dbgCommand("db " + hex(pykd.reg("rsi") - 0x10 + self.alloc_size) + " l" + hex(self.alloc_size)))
def listModuleByVadRoot(eprocessaddr): modulelist = [] try: cmdline = '.process /P %x;.reload;' % eprocessaddr r = pykd.dbgCommand(cmdline) eprocess = pykd.typedVar('nt!_EPROCESS', eprocessaddr) VadRoot = int(eprocess.VadRoot) if not VadRoot: return [] cmdline = '!vad %x' % VadRoot r = pykd.dbgCommand(cmdline).splitlines() for i in r: i = i.strip() pos = i.find('Exe EXECUTE_') if pos == -1: continue a = i[pos + len('Exe '):] pos = a.find(' ') if pos == -1: continue type = a[:pos].strip() filepath = a[pos + len(' '):].strip() pos = i.find(')') if pos == -1: continue a = i[pos + 1:].lstrip() pos = a.find(' ') if pos == -1: continue baseaddr = a[:pos].strip() baseaddr = int(baseaddr, 16) * 0x1000 a = a[pos + 1:].lstrip() pos = a.find(' ') if pos == -1: continue endaddr = a[:pos].strip() endaddr = int(endaddr, 16) * 0x1000 info = ModuleInfo() if info.init2(baseaddr=baseaddr, endaddr=endaddr, filepath=filepath): modulelist.append(info) except Exception, err: print traceback.format_exc()
def load_init(self): init_file = os.path.dirname(FILEPATH) + "\cdbinit" try: cdbinit = open(init_file).readlines() except: cdbinit = [] for cmd in cdbinit: cmd = cmd.strip() try: pykd.dbgCommand(cmd) print(cmd) except: pass
def listModuleByVadRoot(eprocessaddr): modulelist = [] try: cmdline = ".process /P %x;.reload;" % eprocessaddr r = pykd.dbgCommand(cmdline) eprocess = pykd.typedVar("nt!_EPROCESS", eprocessaddr) VadRoot = int(eprocess.VadRoot) if not VadRoot: return [] cmdline = "!vad %x" % VadRoot r = pykd.dbgCommand(cmdline).splitlines() for i in r: i = i.strip() pos = i.find("Exe EXECUTE_") if pos == -1: continue a = i[pos + len("Exe ") :] pos = a.find(" ") if pos == -1: continue type = a[:pos].strip() filepath = a[pos + len(" ") :].strip() pos = i.find(")") if pos == -1: continue a = i[pos + 1 :].lstrip() pos = a.find(" ") if pos == -1: continue baseaddr = a[:pos].strip() baseaddr = int(baseaddr, 16) * 0x1000 a = a[pos + 1 :].lstrip() pos = a.find(" ") if pos == -1: continue endaddr = a[:pos].strip() endaddr = int(endaddr, 16) * 0x1000 info = ModuleInfo() if info.init2(baseaddr=baseaddr, endaddr=endaddr, filepath=filepath): modulelist.append(info) except Exception, err: print traceback.format_exc()
def Monitor(): testcase = "Testcases\\Test.txt" try: pykd.initialize() Handler = ExceptionHandler() print "[*] Starting Scan64.exe" pykd.startProcess( "C:\\Program Files (x86)\\McAfee\\VirusScan Enterprise\\x64\\Scan64.Exe " + testcase) pykd.dbgCommand(".childdbg 1") except: print "[!] Error starting process" sys.exit(1) print "[*] Success!" pykd.go()
def sig_copycountname(self): if self.alloc_mem != pykd.reg("rsi") - 0x10: print("[!!!!!] something wrong") print("[+] ptr: 0x%x" % (pykd.reg("rsi") - 0x10)) print( pykd.dbgCommand("db " + hex(pykd.reg("rsi") - 0x10) + " l" + hex(self.alloc_size))) print("[+] Next Chunk") print( pykd.dbgCommand("db " + hex(pykd.reg("rsi") - 0x10 + self.alloc_size) + " l" + hex(self.alloc_size)))
def onCommandInput(self): self.inCmd.setReadOnly(True) cmdLine = self.inCmd.text() self.inCmd.setText("running %s" % cmdLine) self.outCmd.append(pykd.dbgCommand(cmdLine)) self.inCmd.setText("") self.inCmd.setReadOnly(False)
def crawl_object_by_directory(callback, param, dirname='\\'): cmdline='!object '+dirname #print cmdline r=pykd.dbgCommand(cmdline) r=r.splitlines() startlist=0 for i in r: i=i.lstrip() if i.startswith('--'): startlist=1 continue if not startlist: continue data=i.split() if len(data)>3: obj=data[1] type=data[2] name=data[3] else: obj=data[0] type=data[1] name=data[2] if not callback(obj, type, param): return False if type=='Directory': childname=dirname+name+'\\' if not crawl_object_by_directory(callback, param, childname): return False return True
def inspectProcessInlineHook(eprocessaddr=None): if eprocessaddr: eprocessobj=pykd.typedVar('nt!_EPROCESS', eprocessaddr) eprocessinfo=ProcessInfo() if not eprocessinfo.init(eprocessobj): print 'it is not a eprocess' return processlist=[eprocessinfo] else: processlist=listProcessByPsActiveProcessHead() if not processlist: print 'can not get process list' return for eprocessinfo in processlist: print '='*10, 'process:%x pid:%d %s' % (eprocessinfo.eprocessaddr, eprocessinfo.pid, eprocessinfo.filepath), '='*10 modulelist=listModuleByVadRoot(eprocessinfo.eprocessaddr) if not modulelist: print 'the process has no modules(vadroot is null)' continue cmdline='.process /P %x' % eprocessinfo.eprocessaddr r=pykd.dbgCommand(cmdline) for i in modulelist: modulepath=i.filepath modulebase=i.baseaddr if not os.path.exists(modulepath): print "can't find file:%s" % modulepath continue inspectInlineHook(modulepath, modulebase) print print print 'inspect completely'
def listModuleByLdrHash(eprocessaddr): modulelist = {} try: cmdline = ".process /P %x;.reload;" % eprocessaddr r = pykd.dbgCommand(cmdline) try: LdrpHashTable = pykd.getOffset("ntdll!LdrpHashTable") except: print "get LdrpHashTable symbol fail, maybe ldr is null" return [] if int(LdrpHashTable) != 0: for i in xrange(26): listhead = LdrpHashTable + i * 2 * g_mwordsize hashlink = listhead while 1: hashlink = pykd.ptrPtr(hashlink) if hashlink == listhead: break ldr = pykd.containingRecord(hashlink, "nt!_LDR_DATA_TABLE_ENTRY", "HashLinks") if int(ldr) not in modulelist: info = ModuleInfo() if info.init1(ldr): modulelist[int(ldr)] = info except Exception, err: print traceback.format_exc()
def runCmdLog(cmd, cmdVerbose=True, retVerbose=True): cmdLog = pyLog if cmdVerbose else pyLog2File retLog = pyLog if retVerbose else pyLog2File cmdLog('\n> %s\n%s' % (cmd, '-'*20)) ret = pykd.dbgCommand(cmd) retLog(ret) return ret
def writeDword(self, addr, val): cmd = "ed %x %x" % (addr, val) guard = pykd.getVaProtect(addr) self.vprotect(addr, 4, 0x40) cmdr = pykd.dbgCommand(cmd) self.vprotect(addr, 4, guard) return 0
def getRegVal(self, regName): cmdReg = "r %s" % regName iParseBegin = "%s=" % regName cmdr = pykd.dbgCommand(cmdReg) strReg = cmdr[cmdr.find(iParseBegin) + len(iParseBegin):] regVal = int(strReg, 16) return regVal
def onException(self, exceptionInfo): ''' Triggered exception event. This example handler only recoder exception which we interested. :param exceptionInfo: Exception information :return: For ignore event method must return eventResult.noChange ''' eip = pykd.reg('eip') last_exception = str(pykd.getLastException()) exc_code = exceptionInfo.exceptionCode self._target.logger.info("Got Exception Code: %s at eip:%s" % (hex(exc_code), hex(eip))) if exc_code in interesting_exception_codes.keys(): self._target.is_crash.set() self._target.crash_dump_finished.clear() self._target.report.failed( "Got Exception Code: %s:%s at eip:%s" % (hex(exc_code), interesting_exception_codes[exc_code], hex(eip))) self._target.report.add( "Error Code", "%s:%s" % (hex(exc_code), interesting_exception_codes[exc_code])) self._target.report.add("Last Event", "%s" % last_exception) self._target.report.add("Stacks", str(pykd.dbgCommand("k"))) self._target.crash_dump_finished.set() return pykd.eventResult.Break elif exc_code == break_in_exception_code: # Handle break in event self._target.logger.info("Break in at eip:%s" % hex(eip)) return pykd.eventResult.Break return pykd.eventResult.NoChange
def return_call_back(self, bp): if self.bp_end_atan == bp and self.bp_heap_alloc is None: # this is where we enable our heap alloc bp print("(+) enabling heap alloc bp.") addr = self.get_address("ntdll!RtlAllocateHeap") disas = pykd.dbgCommand("uf %x" % int(addr, 16)).split('\n') for i in disas: if 'ret' in i: self.ret_addr = i.split()[0] break self.bp_heap_alloc = pykd.setBp(int(self.ret_addr, 16), self.return_call_back_with_eax) elif self.bp_end_asin == bp and self.bp_heap_alloc is not None: # this is where we disable our heap alloc bp print("(+) disabling heap alloc bp.") if self.get_pykd_version() == 3: self.bp_asan.remove() self.bp_asin.remove() self.bp_end_asin.remove() self.bp_end_atan.remove() self.bp_heap_alloc.remove() else: pykd.removeBp(self.bp_asan) pykd.removeBp(self.bp_asin) pykd.removeBp(self.bp_end_asin) pykd.removeBp(self.bp_end_atan) pykd.removeBp(self.bp_heap_alloc) return False
def onException(self, exceptionInfo): ''' Triggered exception event. This example handler only recoder exception which we interested. :param exceptionInfo: Exception information :return: For ignore event method must return eventResult.noChange ''' eip = pykd.reg('eip') last_exception = str(pykd.getLastException()) exc_code = exceptionInfo.exceptionCode self._target.logger.info("Got Exception Code: %s at eip:%s" % (hex(exc_code), hex(eip))) if exc_code in interesting_exception_codes.keys(): self._target.is_crash.set() self._target.crash_dump_finished.clear() self._target.report.failed("Got Exception Code: %s:%s at eip:%s" % ( hex(exc_code), interesting_exception_codes[exc_code], hex(eip))) self._target.report.add("Error Code", "%s:%s" % (hex(exc_code), interesting_exception_codes[exc_code])) self._target.report.add("Last Event", "%s" % last_exception) self._target.report.add("Stacks", str(pykd.dbgCommand("k"))) self._target.crash_dump_finished.set() return pykd.eventResult.Break elif exc_code == break_in_exception_code: # Handle break in event self._target.logger.info("Break in at eip:%s" % hex(eip)) return pykd.eventResult.Break return pykd.eventResult.NoChange
def watch(self, dc, aim='', num=16): """ Run command every step. Args: - display_command(string): eg. dd,dw . Or you can disable it by inputing 'clear' - address(hex)/register(string): the address to be watch. - num (int) : the number of line to be watch. (optional) """ aim = self._get_aim(aim) if dc=='clear': pykd.dbgCommand("ad watch_command") else: if re.match("d[a-z]",dc): set_alias("watch_command", "%s %s %s"%(dc, to_hex(aim), num)) else: return self._error_args()
def grep(self, command, regex_string, a='', b=''): """ Grep regex_string in the result of command Args: - command(string) - regex_string (string) - after_context(int) (optional) - before_context(int) (optional) """ try: a = to_int(a) b = to_int(b) except: return self._error_args() result = pykd.dbgCommand(command) lines = result.splitlines() for idx,line in enumerate(lines): if regex_string in line: print("="*50) if a: print('\n'.join(lines[idx-a:idx])) wprint(lines[idx]+"\n", "lightred") if b: print('\n'.join(lines[idx+1:idx+b+1]))
def listObjectCallback(): try: cmdline='!object \objecttypes' r=pykd.dbgCommand(cmdline) featurestr='----\n' pos=r.find(featurestr) if pos==-1: return r=r[pos+len(featurestr):].splitlines() for i in r: if i.find('Type'): typeobjectaddr, name=i.split(' Type ') pos=typeobjectaddr.rfind(' ') if pos==-1: return name=name.strip() typeobjectaddr=typeobjectaddr[pos+1:] typeobjectaddr=int(typeobjectaddr, 16) print '-'*20 print 'typeobject "%s":%x' % (name, typeobjectaddr) typeobject=pykd.typedVar('nt!_OBJECT_TYPE', typeobjectaddr) TypeInfo=pykd.typedVar('nt!_OBJECT_TYPE_INITIALIZER', typeobject.TypeInfo) for membername, membervalue in TypeInfo: if membername.endswith('Procedure'): funcaddr=int(membervalue) if funcaddr: symbolname=pykd.findSymbol(funcaddr) else: symbolname='' print '%s %x %s' % (membername, funcaddr, symbolname) except Exception, err: print traceback.format_exc()
def get_address(localAddr): res = pykd.dbgCommand("x " + localAddr) result_count = res.count("\n") if result_count == 0: print localAddr + " not found." return None if result_count > 1: print "[-] Warning, more than one result for", localAddr return res.split()[0]
def listReg(regpath='System\CurrentControlSet\Services\Tcpip!*'): try: cmdline='!dreg %s' % regpath r=pykd.dbgCommand(cmdline) r=r.splitlines() for i in r: print i except Exception, err: print err
def main(): """ injectfind searches process memory for potentially injected code """ process = flaredbg.get_process_obj() found = False for mbi in process.get_memory_map(): if mbi.is_executable() and mbi.is_private(): base_addr = mbi.BaseAddress size = mbi.RegionSize print '-' * 0x40 print "Path: %s Pid: %s Region: 0x%x - 0x%x Length: 0x%x" % (process.get_image_name(), process.get_pid(), base_addr, (base_addr+size-1), size) db_res = pykd.dbgCommand('db %x' % base_addr) dis_res = pykd.dbgCommand('u %x' % base_addr) mem_bytes = process.read(base_addr, size) # Check for stripped header if mem_bytes[:0x1000].count('\0') > 0xfe0: if size > 0x2000 and mem_bytes[0x1000:0x2000].count('\0') < 0x200: print " !!! Possible stripped PE header at 0x%x\n Showing address: 0x%x\n" % (base_addr, base_addr+0x1000) db_res = pykd.dbgCommand('db %x' % (base_addr+0x1000)) dis_res = pykd.dbgCommand('u %x' % (base_addr+0x1000)) # Check for legit PE elif utils.is_legit_pe(mem_bytes[:0x1000]): print " Found legit PE at 0x%x\n" % (base_addr) dis_res = None if db_res: print "Hex dump:" print db_res if dis_res: print "Disassembly:" print dis_res print found = True if not found: print "Nothing found!"
def disasm_around(self): lines = pykd.dbgCommand("u %s-c L12" % self.pc_register) for line in lines.split("\n"): tmp = re.findall("([a-f0-9]{1,}) ([a-f0-9]{2,}) (.*)", line) if len(tmp) > 0: line = tmp[0] addr = line[0] dis = line[2] self.crash_data.add_data("disassembly", int(addr, 16), dis)
def get_current_stack(): call_stack = [] for line in pykd.dbgCommand("k").splitlines()[1:]: try: _, ret_addr, sym = line.split() _ = int(ret_addr, 16) except ValueError: continue call_stack.append(sym) return call_stack
def offsetof(struct_name, member_name): sval = pykd.dbgCommand('?? #FIELD_OFFSET(%s, %s)' \ % (struct_name, member_name)) if sval.startswith('long 0n'): return int(sval[len('long 0n'):]) elif sval.startswith('long 0x'): return int(sval[len('long 0x'):], 16) else: return int(sval)
def enter_call_back(self,bp): print "RtlAllocateHeap called." if self.bp_end == None: disas = pykd.dbgCommand("uf ntdll!RtlAllocateHeap").split('\n') for i in disas: if 'ret' in i: self.ret_addr = i.split()[0] break self.bp_end = pykd.setBp(int(self.ret_addr, 16), self.return_call_back) return False
def search(start_addr, end_addr, dword): search_expr = 's -[1]d %x %x %s' results = [] search_str = search_expr % (start_addr, end_addr, dword) out_str = pykd.dbgCommand(search_str) str_results = out_str.split('\n') for str_result in str_results: if str_result.startswith('0x'): results.append((str_result, start_addr)) return results
def enter_call_back(self, bp): self.out = "RtlAllocateHeap(" esp = pykd.reg("esp") self.out += hex(pykd.ptrPtr(esp + 4)) + " , " self.out += hex(pykd.ptrMWord(esp + 0x8)) + " , " self.out += hex(pykd.ptrMWord(esp + 0xC)) + ") = " if self.bp_end == None: self.ret_addr = pykd.dbgCommand("dd esp L1").split()[1] self.bp_end = pykd.setBp(int(self.ret_addr, 16), self.return_call_back) return False
def version(self): """ Get the debugger's version. Returns a string containing the debugger's version (e.g. 'Microsoft (R) Windows Debugger Version whatever, pykd 0.3.0.38') """ try: [windbg] = [line for line in pykd.dbgCommand('version').split('\n') if 'Microsoft (R) Windows Debugger Version' in line] except: windbg = 'WinDbg <unknown>' return '{}, {}'.format(windbg, 'pykd {}'.format(pykd.version))
def command(self, command=None): """ Execute a command in the debugger. `command` is the command string to execute. """ if command: res = pykd.dbgCommand(command) else: raise Exception("No command specified") return res
def listThreadByThreadListEntry(eprocessaddr): threadlist=[] try: cmdline='.process /P %x;.reload;' % eprocessaddr r=pykd.dbgCommand(cmdline) eprocessobj=pykd.typedVar('nt!_EPROCESS', eprocessaddr) l=pykd.typedVarList(eprocessobj.ThreadListHead, 'nt!_ETHREAD', 'ThreadListEntry') for i in l: info=ThreadInfo(i) threadlist.append(info) except Exception, err: print traceback.format_exc()
def main(init_sym, mem_limit, timeout): run_time = time.time() timeout = timeout + time.time() pykd.dbgCommand("bu %x" % sym_off_to_addr(init_sym)) page_size = get_page_size() pykd.go() target_pid = get_pid() pykd.removeBp(get_bp_hit()) pykd.dbgCommand("bm MSVCR*!malloc") pykd.dbgCommand("bm MSVCR*!realloc") pykd.dbgCommand("bm MSVCR*!calloc") log.debug("target pid: %d", target_pid) while time.time() < timeout: pykd.go() cur_mem = get_mem_usage(target_pid) if cur_mem >= mem_limit: log.info("missed request! current memory: %d", cur_mem) break req = requested_mem_size() if req == 0: log.info("unexpected break on: %s", get_current_stack()[0]) continue if req > page_size: if req % page_size: page_req = page_size * ((req/page_size)+1) else: page_req = page_size * (req/page_size) else: page_req = page_size if cur_mem + page_req >= mem_limit: log.info("request will exceed limit, current: %d, request %d", cur_mem, req) break log.info("*" * 60) if time.time() < timeout: set_thread(get_hung_thread()) call_stack = get_current_stack() if not call_stack: log.info("Unable to trace!") for line in call_stack: log.info("STACK_FRAME:%s" % line) else: log.info("Timeout!") log.info("*" * 60) log.info("----- STATS -----") log.info("MEMORY LIMIT: %d MB", mem_limit/0x100000) log.info("DGB TIME: %0.2f", time.time()-run_time) log.info("PROC TIME: %0.2f", get_proc_run_time()) log.info("THREAD TIME: %0.2f", get_thread_run_time(get_thread_list()[get_hung_thread()]))
def enter_call_back(self,bp): self.out = "RtlAllocateHeap(" esp = pykd.reg("esp") self.out += hex(pykd.ptrPtr(esp + 4)) + " , " self.out += hex(pykd.ptrMWord(esp + 0x8)) + " , " self.out += hex(pykd.ptrMWord(esp + 0xC)) + ") = " if self.bp_end == None: disas = pykd.dbgCommand("uf ntdll!RtlAllocateHeap").split('\n') for i in disas: if 'ret' in i: self.ret_addr = i.split()[0] break self.bp_end = pykd.setBp(int(self.ret_addr, 16), self.return_call_back) return False
def enter_call_back(self,bp): self.out = "RtlFreeHeap(" if arch_bits == 32: esp = pykd.reg(stack_pointer) self.out += hex(pykd.ptrPtr(esp + 4)) + " , " self.out += hex(pykd.ptrMWord(esp + 0x8)) + " , " self.out += hex(pykd.ptrPtr(esp + 0xC)) + ") = " else: self.out += hex(pykd.reg("rcx")) + " , " self.out += hex(pykd.reg("rdx")) + " , " self.out += hex(pykd.reg("r8")) + ") = " if self.bp_end == None: self.ret_addr = pykd.dbgCommand("dd esp L1").split()[1] self.bp_end = pykd.setBp(int(self.ret_addr, 16), self.return_call_back) return False
def listIDT(): idt_symbol_table={} try: for cpuidx in xrange(g_cpunumber): print '='*20 cmdline='!pcr %d' % cpuidx r=pykd.dbgCommand(cmdline) r=r.splitlines() for i in r: i=i.strip() if i.startswith('IDT'): idtaddr=i.split(':')[1].strip() #interrupts=pykd.loadPtrs(int(idtaddr, 16), 256) print 'cpu %d idtaddr:%s' % (cpuidx, idtaddr) except Exception, err: print err
def version(self): """ Get the debugger's version. Returns a string containing the debugger's version (e.g. 'Microsoft (R) Windows Debugger Version whatever, pykd 0.3.0.38') """ try: [windbg] = [ line for line in pykd.dbgCommand("version").split("\n") if "Microsoft (R) Windows Debugger Version" in line ] except: windbg = "WinDbg <unknown>" return "{}, {}".format(windbg, "pykd {}".format(pykd.version))
def disassemble(self, target_id=0, address=None, count=16): """ Get a disassembly of the instructions at the given address. `address` is the address at which to disassemble. If None, the current program counter is used. `count` is the number of instructions to disassemble. """ # make sure we have an address if address is None: pc_name, address = self.program_counter(target_id=target_id) # disassemble output = pykd.dbgCommand('u 0x{:x} l{}'.format(address, count)) return output
def get_proc_run_time(): # Debug session time: Tue Aug 21 16:27:31.971 2012 (UTC - 4:00) # System Uptime: 5 days 13:06:34.062 # Process Uptime: 0 days 0:00:02.718 # Kernel time: 0 days 0:00:00.000 # User time: 0 days 0:00:00.000 duration = 0 for line in pykd.dbgCommand(".time").splitlines()[-2:]: line = line.strip().split() duration += int(line[2]) * 86400 # days line = line[-1].split(".") duration += float("0.%s" % line[-1]) line = line[0].split(":") duration += int(line[0]) * 3600 # hours duration += int(line[1]) * 60 # minutes duration += int(line[2]) # seconds return duration
def listProcessByPspcidTable(): processlist=[] try: cmdline='!process 0 0' r=pykd.dbgCommand(cmdline) r=r.splitlines() for i in r: if i.startswith('PROCESS '): startpos=len('PROCESS ') endpos=i.find(' ', startpos) eprocessaddr=int(i[startpos:endpos], 16) eprocessobj=pykd.typedVar('nt!_EPROCESS', eprocessaddr) info=ProcessInfo() if info.init(eprocessobj): processlist.append(info) except Exception, err: print traceback.format_exc()
def inspectShadowSSDT(): r=pykd.dbgCommand('dd win32k L1').split(' ') win32kbase=pykd.addr64(int(r[0],16)) print 'wink32.sys baseaddr:0x%x' % win32kbase W32pServiceTable=pykd.getOffset('win32k!W32pServiceTable') print 'win32k!W32pServiceTable:0x%x' % W32pServiceTable W32pServiceLimit=pykd.getOffset('win32k!W32pServiceLimit') W32pServiceLimit=pykd.ptrMWord(W32pServiceLimit) print 'win32k!W32pServiceLimit:0x%x(%d)' % (W32pServiceLimit, W32pServiceLimit) shadowssdttable=pykd.loadPtrs(W32pServiceTable, W32pServiceLimit) table_rva=(W32pServiceTable-win32kbase) print 'W32pServiceTable rva:0x%x' % table_rva win32kname='win32k.sys' windowsdir=win32api.GetWindowsDirectory() filepath=os.path.join(windowsdir, 'system32', win32kname) if not os.path.exists(filepath): raise Exception('%s not exists!' % win32kname) print 'win32k.sys path:', filepath filedata=open(filepath, 'rb').read() pe = pefile.PE(data=filedata, fast_load=True) if pe.DOS_HEADER.e_magic!=0X5A4D or pe.NT_HEADERS.Signature!=0x4550: raise Exception("%s is not a pe file" % filepath) table_fileoffset=pe.get_offset_from_rva(table_rva) print 'W32pServiceTable file offset:0x%x' % table_fileoffset d=filedata[table_fileoffset:table_fileoffset+g_mwordsize*W32pServiceLimit] number=0 for i in xrange(W32pServiceLimit): source=binascii.b2a_hex(d[i*g_mwordsize:(i+1)*g_mwordsize][::-1]) source=int(source, 16)-pe.OPTIONAL_HEADER.ImageBase+win32kbase symbolname=pykd.findSymbol(source) current=shadowssdttable[i] if source==current: print 'source:0x%x current:0x%x %s' % (source, current, symbolname) else: hooksymbolname=pykd.findSymbol(current) print 'source:0x%x %s <-> current:0x%x %s hooked!!!!!!!' % (source, symbolname, current, hooksymbolname) number+=1 print 'hooked function number:', number
def get_addr_list(): addr_list = [] addr_list.append(pykd.getContext().ip()) for line in pykd.dbgCommand("k").splitlines()[1:]: skip = False try: _, ret_addr, sym = line.split() ret_addr = int(ret_addr, 16) except ValueError: continue for noise in BLACKLIST_LIBS: if sym.startswith(noise): skip = True break if skip: continue addr_list.append(ret_addr) addr_list.pop() # remove 0 from the list return addr_list