def get_backend_info(): rv = rpc.GetBackendInfoResult() info = py_olly.get_backend_info() rv.bitness = int(info['bitness']) rv.dbg_name = info['name'] rv.labeless_ver = py_olly.labeless_ver() return rv
def mem_is_allocated(addr): mbi_ctor = D.MEMORY_BASIC_INFORMATION if int(py_olly.get_backend_info()['bitness']) == 32 else D.MEMORY_BASIC_INFORMATION64 mbi = mbi_ctor() VirtualQueryEx = C.windll.kernel32.VirtualQueryEx h_process = wintypes.HANDLE(py_olly.get_hprocess()) queried = VirtualQueryEx(h_process, C.c_void_p(addr), C.byref(mbi), C.sizeof(mbi)) return queried > 0
def safe_read_chunked_memory_region_as_one(base, size): mbi_ctor = ( D.MEMORY_BASIC_INFORMATION if int(py_olly.get_backend_info()["bitness"]) == 32 else D.MEMORY_BASIC_INFORMATION64 ) mbi = mbi_ctor() VirtualQueryEx = C.windll.kernel32.VirtualQueryEx VirtualProtectEx = C.windll.kernel32.VirtualProtectEx GetLastError = C.windll.kernel32.GetLastError GRANULARITY = 0x1000 h_process = wintypes.HANDLE(py_olly.get_hprocess()) # oa.Plugingetvalue(oa.VAL_HPROCESS)) try: rv = bytearray(size) except MemoryError: return guarded = list() gpoints = dict() protect = 0 queried = VirtualQueryEx(h_process, C.c_void_p(base), C.byref(mbi), C.sizeof(mbi)) if queried: protect = mbi.Protect else: print >> sys.stderr, "safe_read_chunked_memory_region_as_one: VirtualQueryEx(ptr 0x%08X, size 0x%08X) failed, error: %u" % ( base, C.sizeof(mbi), GetLastError(), ) if queried and mbi.Protect & D.PAGE_GUARD: g = {"ea": base, "size": GRANULARITY, "p": mbi.Protect} gpoints[base] = 0 ea = base while True: ea -= GRANULARITY if ( VirtualQueryEx(h_process, C.c_void_p(ea), C.byref(mbi), C.sizeof(mbi)) and (mbi.Protect & D.PAGE_GUARD) != 0 and g["p"] == mbi.Protect ): g["ea"] -= GRANULARITY g["size"] += GRANULARITY else: break guarded.append(g) for i in long_xrange(base + GRANULARITY, base + size, GRANULARITY): p_addr = C.c_void_p(i) if VirtualQueryEx(h_process, p_addr, C.byref(mbi), C.sizeof(mbi)) and mbi.Protect & D.PAGE_GUARD: prevaddr = i - GRANULARITY if prevaddr in gpoints and guarded[gpoints[prevaddr]]["p"] == mbi.Protect: idx = gpoints[prevaddr] else: guarded.append({"ea": i, "size": 0L, "p": mbi.Protect}) idx = len(guarded) - 1 guarded[idx]["size"] += GRANULARITY gpoints[i] = idx
def mem_is_allocated(addr): mbi_ctor = ( D.MEMORY_BASIC_INFORMATION if int(py_olly.get_backend_info()["bitness"]) == 32 else D.MEMORY_BASIC_INFORMATION64 ) mbi = mbi_ctor() VirtualQueryEx = C.windll.kernel32.VirtualQueryEx h_process = wintypes.HANDLE(py_olly.get_hprocess()) queried = VirtualQueryEx(h_process, C.c_void_p(addr), C.byref(mbi), C.sizeof(mbi)) return queried > 0
def safe_read_chunked_memory_region_as_one(base, size): mbi_ctor = D.MEMORY_BASIC_INFORMATION if int(py_olly.get_backend_info( )['bitness']) == 32 else D.MEMORY_BASIC_INFORMATION64 mbi = mbi_ctor() VirtualQueryEx = C.windll.kernel32.VirtualQueryEx VirtualProtectEx = C.windll.kernel32.VirtualProtectEx GetLastError = C.windll.kernel32.GetLastError GRANULARITY = 0x1000 h_process = wintypes.HANDLE( py_olly.get_hprocess()) # oa.Plugingetvalue(oa.VAL_HPROCESS)) try: rv = bytearray(size) except MemoryError: return guarded = list() gpoints = dict() protect = 0 queried = VirtualQueryEx(h_process, C.c_void_p(base), C.byref(mbi), C.sizeof(mbi)) if queried: protect = mbi.Protect else: print >> sys.stderr, 'safe_read_chunked_memory_region_as_one: VirtualQueryEx(ptr 0x%08X, size 0x%08X) failed, error: %u' %\ (base, C.sizeof(mbi), GetLastError()) if queried and mbi.Protect & D.PAGE_GUARD: g = {'ea': base, 'size': GRANULARITY, 'p': mbi.Protect} gpoints[base] = 0 ea = base while True: ea -= GRANULARITY if VirtualQueryEx(h_process, C.c_void_p(ea), C.byref(mbi), C.sizeof(mbi)) and\ (mbi.Protect & D.PAGE_GUARD) != 0 and g['p'] == mbi.Protect: g['ea'] -= GRANULARITY g['size'] += GRANULARITY else: break guarded.append(g) for i in long_xrange(base + GRANULARITY, base + size, GRANULARITY): p_addr = C.c_void_p(i) if VirtualQueryEx(h_process, p_addr, C.byref(mbi), C.sizeof(mbi)) and\ mbi.Protect & D.PAGE_GUARD: prevaddr = i - GRANULARITY if prevaddr in gpoints and guarded[ gpoints[prevaddr]]['p'] == mbi.Protect: idx = gpoints[prevaddr] else: guarded.append({'ea': i, 'size': 0L, 'p': mbi.Protect}) idx = len(guarded) - 1 guarded[idx]['size'] += GRANULARITY gpoints[i] = idx
def scan_for_ref_api_calls(ea_from, ea_to, increment, rv, base, size, mem): # import inspect if ea_from > ea_to: print >> sys.stderr, 'Invalid arguments passed' return None logger.info(( 'scan_for_ref_api_calls(ea_from=0x%08X, ea_to=0x%08X, increment=0x%08X, base=0x%08X)\n' + 'getting modules meta') % (ea_from, ea_to, increment, base)) global modules_meta global modules_exports logger.info('scan_for_ref_api_calls() modules_meta got') this_module_exports = set() for name, info in modules_meta.items(): for i in xrange(len(info['base'])): if info['base'][i] <= ea_from < info['base'][i] + info['size'][i]: this_module_exports = set( map(lambda x: x['ea'], info['apis'][i])) print 'module found: %s, len of exports: %u' % ( name, len(this_module_exports)) break unpack_fmt = '<I' if int( py_olly.get_backend_info()['bitness']) == 32 else '<Q' intptr_size = struct.calcsize(unpack_fmt) def isPointsToExternalDll(addr): if addr not in modules_exports: return False if addr in this_module_exports: return False if base <= addr <= base + size - intptr_size: return False return modules_exports[addr] for ea in long_xrange(ea_from, ea_to, increment): try: l = ea_to - ea offs = ea - ea_from cmd = bytearray(mem[offs:offs + min(MAXCMDSIZE, l)]) dis = api.BASIC_INSTRUCTION_INFO() dis.size = 0 funcs = api.DbgFunctions() funcs.DisasmFast_(cmd, ea, dis) if dis.size <= 0: continue if dis.type == api.TYPE_VALUE: v = isPointsToExternalDll(dis.value.value) if v: ref = rv.refs.add() ref.ref_type = rpc.AnalyzeExternalRefsResult.RefData.REFT_IMMCONST ref.module, ref.proc = v.split('.') ref.v = dis.value.value ref.ea = ea ref.len = dis.size ref.dis = str(dis.instruction.replace('\0', '')) print 'api.TYPE_VALUE points to %s at %08X as %s' % ( v, ea, ref.dis) continue if dis.type == api.TYPE_ADDR: v = isPointsToExternalDll(dis.addr) if v: ref = rv.refs.add() ref.ref_type = rpc.AnalyzeExternalRefsResult.RefData.REFT_ADDRCONST ref.module, ref.proc = v.split('.') ref.v = dis.addr ref.ea = ea ref.len = dis.size ref.dis = str(dis.instruction.replace('\0', '')) print 'api.TYPE_ADDR points to %s at %08X as %s' % ( v, ea, ref.dis) continue if dis.type == api.TYPE_MEMORY: v = isPointsToExternalDll(dis.memory.value) # if not v and mem_is_allocated(dis.memory.value): # mem_size, mem_raw, _ = safe_read_chunked_memory_region_as_one(dis.memory.value, intptr_size) # tmp = struct.unpack_from(unpack_fmt, buffer(mem_raw), 0)[0] # v = isPointsToExternalDll(tmp) if v: ref = rv.refs.add() ref.ref_type = rpc.AnalyzeExternalRefsResult.RefData.REFT_JMPCONST ref.module, ref.proc = v.split('.') ref.v = dis.memory.value ref.ea = ea ref.len = dis.size ref.dis = str(dis.instruction.replace('\0', '')) print 'api.TYPE_MEMORY points to %s at %08X as %s' % ( v, ea, ref.dis) continue #for k, v in inspect.getmembers(dis): # if '_' not in k: # print "%r: %r" % (k, v) except Exception as exc: print >> sys.stderr, 'Exception: %r\r\n%s' % ( exc, traceback.format_exc().replace('\n', '\r\n'))
def analyze_external_refs(ea_from, ea_to, increment, analysing_base, analysing_size): # print >> sys.stderr, 'analyze_external_refs(%08X, %08X, %08X, %08X, %08X)' % \ # (ea_from, ea_to, increment, analysing_base, analysing_size) # import labeless.rdebug rv = rpc.AnalyzeExternalRefsResult() if ea_from > ea_to: print >> sys.stderr, 'Invalid arguments passed' return rv mem = safe_read_chunked_memory_region_as_one(ea_from, ea_to - ea_from) if not mem: print >> sys.stderr, 'Unable to read specified memory (0x%08X - 0x%08X)' % ( ea_from, ea_to) return rv mem = buffer(mem[1]) unpack_fmt = '<I' if int( py_olly.get_backend_info()['bitness']) == 32 else '<Q' intptr_size = struct.calcsize(unpack_fmt) main_module_name = bridgemain.DbgGetModuleAt(analysing_base) if main_module_name: main_module_name = path.splitext( path.basename(main_module_name))[0].lower() rv.context.eax = api.Register_GetEAX() rv.context.ecx = api.Register_GetECX() rv.context.edx = api.Register_GetEDX() rv.context.ebx = api.Register_GetEBX() rv.context.esp = api.Register_GetESP() rv.context.ebp = api.Register_GetEBP() rv.context.esi = api.Register_GetESI() rv.context.edi = api.Register_GetEDI() rv.context.rip = api.Register_GetCIP() if int(py_olly.get_backend_info()['bitness']) == 64: rv.context.rax = api.Register_GetRAX() rv.context.rbx = api.Register_GetRBX() rv.context.rcx = api.Register_GetRCX() rv.context.rdx = api.Register_GetRDX() rv.context.rsi = api.Register_GetRSI() rv.context.rdi = api.Register_GetRDI() rv.context.rbp = api.Register_GetRBP() rv.context.rsp = api.Register_GetRSP() # thread_list = xd.THREADLIST() # xd.DbgGetThreadList(thread_list) # try: # current = thread_list.CurrentThread # if thread_list.count <= current: # print >> sys.stderr, '[-] Invalid thread info got' # return rv # rv.context.eax = xd.Register_GetEAX() # rv.context.ecx = xd.Register_GetECX() # rv.context.edx = xd.Register_GetEDX() # rv.context.ebx = xd.Register_GetEBX() # rv.context.esp = xd.Register_GetESP() # rv.context.ebp = xd.Register_GetEBP() # rv.context.esi = xd.Register_GetESI() # rv.context.edi = xd.Register_GetEDI() # rv.context.eip = xd.Register_GetEIP() # # finally: # if thread_list.list: # xd.BridgeFree(thread_list.list) global modules_exports scan_for_ref_api_calls(ea_from, ea_to, increment, rv=rv, mem=mem, base=analysing_base, size=analysing_size) used_addrs = set([]) for ea in long_xrange(ea_from, ea_to, increment): try: if ea in used_addrs: continue l = ea_to - ea off = ea - ea_from if l < intptr_size: break addr = struct.unpack_from(unpack_fmt, mem, off)[0] if addr not in modules_exports: continue symb = modules_exports[addr] module_name, proc_name = symb.split('.') if module_name == main_module_name: continue v = rv.api_constants.add() v.ea = ea v.module = module_name v.proc = proc_name except Exception as exc: print >> sys.stderr, 'Exception: %r\r\n%s' % ( exc, traceback.format_exc().replace('\n', '\r\n')) print 'AnalyzeExternalRefs(ea_from=0x%x, ea_to=0x%x): api consts found %u, refs found: %u' % ( ea_from, ea_to, len(rv.api_constants), len(rv.refs)) # print rv return rv
def scan_for_ref_api_calls(ea_from, ea_to, increment, rv, base, size, mem): # import inspect if ea_from > ea_to: print >> sys.stderr, "Invalid arguments passed" return None logger.info( ( "scan_for_ref_api_calls(ea_from=0x%08X, ea_to=0x%08X, increment=0x%08X, base=0x%08X)\n" + "getting modules meta" ) % (ea_from, ea_to, increment, base) ) global modules_meta global modules_exports logger.info("scan_for_ref_api_calls() modules_meta got") this_module_exports = set() for name, info in modules_meta.items(): for i in xrange(len(info["base"])): if info["base"][i] <= ea_from < info["base"][i] + info["size"][i]: this_module_exports = set(map(lambda x: x["ea"], info["apis"][i])) print "module found: %s, len of exports: %u" % (name, len(this_module_exports)) break unpack_fmt = "<I" if int(py_olly.get_backend_info()["bitness"]) == 32 else "<Q" intptr_size = struct.calcsize(unpack_fmt) def isPointsToExternalDll(addr): if addr not in modules_exports: return False if addr in this_module_exports: return False if base <= addr <= base + size - intptr_size: return False return modules_exports[addr] for ea in long_xrange(ea_from, ea_to, increment): try: l = ea_to - ea offs = ea - ea_from cmd = bytearray(mem[offs : offs + min(MAXCMDSIZE, l)]) dis = api.BASIC_INSTRUCTION_INFO() dis.size = 0 funcs = api.DbgFunctions() funcs.DisasmFast_(cmd, ea, dis) if dis.size <= 0: continue if dis.type == api.TYPE_VALUE: v = isPointsToExternalDll(dis.value.value) if v: ref = rv.refs.add() ref.ref_type = rpc.AnalyzeExternalRefsResult.RefData.REFT_IMMCONST ref.module, ref.proc = v.split(".") ref.v = dis.value.value ref.ea = ea ref.len = dis.size ref.dis = str(dis.instruction.replace("\0", "")) print "api.TYPE_VALUE points to %s at %08X as %s" % (v, ea, ref.dis) continue if dis.type == api.TYPE_ADDR: v = isPointsToExternalDll(dis.addr) if v: ref = rv.refs.add() ref.ref_type = rpc.AnalyzeExternalRefsResult.RefData.REFT_ADDRCONST ref.module, ref.proc = v.split(".") ref.v = dis.addr ref.ea = ea ref.len = dis.size ref.dis = str(dis.instruction.replace("\0", "")) print "api.TYPE_ADDR points to %s at %08X as %s" % (v, ea, ref.dis) continue if dis.type == api.TYPE_MEMORY: v = isPointsToExternalDll(dis.memory.value) # if not v and mem_is_allocated(dis.memory.value): # mem_size, mem_raw, _ = safe_read_chunked_memory_region_as_one(dis.memory.value, intptr_size) # tmp = struct.unpack_from(unpack_fmt, buffer(mem_raw), 0)[0] # v = isPointsToExternalDll(tmp) if v: ref = rv.refs.add() ref.ref_type = rpc.AnalyzeExternalRefsResult.RefData.REFT_JMPCONST ref.module, ref.proc = v.split(".") ref.v = dis.memory.value ref.ea = ea ref.len = dis.size ref.dis = str(dis.instruction.replace("\0", "")) print "api.TYPE_MEMORY points to %s at %08X as %s" % (v, ea, ref.dis) continue # for k, v in inspect.getmembers(dis): # if '_' not in k: # print "%r: %r" % (k, v) except Exception as exc: print >> sys.stderr, "Exception: %r\r\n%s" % (exc, traceback.format_exc().replace("\n", "\r\n"))
def analyze_external_refs(ea_from, ea_to, increment, analysing_base, analysing_size): # print >> sys.stderr, 'analyze_external_refs(%08X, %08X, %08X, %08X, %08X)' % \ # (ea_from, ea_to, increment, analysing_base, analysing_size) # import labeless.rdebug rv = rpc.AnalyzeExternalRefsResult() if ea_from > ea_to: print >> sys.stderr, "Invalid arguments passed" return rv mem = safe_read_chunked_memory_region_as_one(ea_from, ea_to - ea_from) if not mem: print >> sys.stderr, "Unable to read specified memory (0x%08X - 0x%08X)" % (ea_from, ea_to) return rv mem = buffer(mem[1]) unpack_fmt = "<I" if int(py_olly.get_backend_info()["bitness"]) == 32 else "<Q" intptr_size = struct.calcsize(unpack_fmt) main_module_name = bridgemain.DbgGetModuleAt(analysing_base) if main_module_name: main_module_name = path.splitext(path.basename(main_module_name))[0].lower() rv.context.eax = api.Register_GetEAX() rv.context.ecx = api.Register_GetECX() rv.context.edx = api.Register_GetEDX() rv.context.ebx = api.Register_GetEBX() rv.context.esp = api.Register_GetESP() rv.context.ebp = api.Register_GetEBP() rv.context.esi = api.Register_GetESI() rv.context.edi = api.Register_GetEDI() rv.context.rip = api.Register_GetCIP() if int(py_olly.get_backend_info()["bitness"]) == 64: rv.context.rax = api.Register_GetRAX() rv.context.rbx = api.Register_GetRBX() rv.context.rcx = api.Register_GetRCX() rv.context.rdx = api.Register_GetRDX() rv.context.rsi = api.Register_GetRSI() rv.context.rdi = api.Register_GetRDI() rv.context.rbp = api.Register_GetRBP() rv.context.rsp = api.Register_GetRSP() # thread_list = xd.THREADLIST() # xd.DbgGetThreadList(thread_list) # try: # current = thread_list.CurrentThread # if thread_list.count <= current: # print >> sys.stderr, '[-] Invalid thread info got' # return rv # rv.context.eax = xd.Register_GetEAX() # rv.context.ecx = xd.Register_GetECX() # rv.context.edx = xd.Register_GetEDX() # rv.context.ebx = xd.Register_GetEBX() # rv.context.esp = xd.Register_GetESP() # rv.context.ebp = xd.Register_GetEBP() # rv.context.esi = xd.Register_GetESI() # rv.context.edi = xd.Register_GetEDI() # rv.context.eip = xd.Register_GetEIP() # # finally: # if thread_list.list: # xd.BridgeFree(thread_list.list) global modules_exports scan_for_ref_api_calls(ea_from, ea_to, increment, rv=rv, mem=mem, base=analysing_base, size=analysing_size) used_addrs = set([]) for ea in long_xrange(ea_from, ea_to, increment): try: if ea in used_addrs: continue l = ea_to - ea off = ea - ea_from if l < intptr_size: break addr = struct.unpack_from(unpack_fmt, mem, off)[0] if addr not in modules_exports: continue symb = modules_exports[addr] module_name, proc_name = symb.split(".") if module_name == main_module_name: continue v = rv.api_constants.add() v.ea = ea v.module = module_name v.proc = proc_name except Exception as exc: print >> sys.stderr, "Exception: %r\r\n%s" % (exc, traceback.format_exc().replace("\n", "\r\n")) print "AnalyzeExternalRefs(ea_from=0x%x, ea_to=0x%x): api consts found %u, refs found: %u" % ( ea_from, ea_to, len(rv.api_constants), len(rv.refs), ) # print rv return rv
# -*- coding: utf-8 -* # Labeless # by Aliaksandr Trafimchuk # # Source code released under # Creative Commons BY-NC 4.0 # http://creativecommons.org/licenses/by-nc/4.0 __author__ = 'a1ex_t' from labeless import py_olly if int(py_olly.get_backend_info()['bitness']) == 32: from x64dbgapi import * else: from x64dbgapi64 import *