def test_envi_i386_disasm_Specific_MultiByte_Instrs(self): ''' pick 10 arbitrary 2- and 3-byte operands ''' vw = vivisect.VivWorkspace() scanv = e_memcanvas.StringMemoryCanvas(vw) for name, bytez, va, reprOp, renderOp in i386MultiByteOpcodes: try: op = self._arch.archParseOpcode(bytez.decode('hex'), 0, va) except envi.InvalidInstruction: self.fail( "Failed to parse opcode bytes: %s (case: %s, expected: %s)" % (bytez, name, reprOp)) # print("'%s', 0x%x, '%s' == '%s'" % (bytez, va, repr(op), reprOp)) try: self.assertEqual(repr(op), reprOp) except AssertionError: self.fail("Failing match for case %s (%s != %s)" % (name, repr(op), reprOp)) scanv.clearCanvas() op.render(scanv) # print("render: %s" % repr(scanv.strval)) self.assertEqual(scanv.strval, renderOp)
def check_opreprs(self, opcodes): vw = vivisect.VivWorkspace() scanv = e_memcanvas.StringMemoryCanvas(vw) for name, bytez, va, reprOp, renderOp in opcodes: try: op = self._arch.archParseOpcode(bytez.decode('hex'), 0, va) except envi.InvalidInstruction: self.fail( "Failed to parse opcode bytes: %s (case: %s, expected: %s)" % (bytez, name, reprOp)) except Exception as e: self.fail( "Failed to parse opcode bytes: %s (case: %s, expected: %s)" % (bytez, name, reprOp)) # print("'%s', 0x%x, '%s' == '%s'" % (bytez, va, repr(op), reprOp)) try: self.assertEqual(repr(op), reprOp) except AssertionError: self.fail("Failing match for case %s (%s != %s)" % (name, repr(op), reprOp)) scanv.clearCanvas() op.render(scanv) # print("render: %s" % repr(scanv.strval)) self.assertEqual(scanv.strval, renderOp)
def check_opreprs(self, opcodes): vw = vivisect.VivWorkspace() scanv = e_memcanvas.StringMemoryCanvas(vw) for name, bytez, va, reprOp, renderOp in opcodes: try: op = self._arch.archParseOpcode(binascii.unhexlify(bytez), 0, va) except envi.InvalidInstruction: self.fail( "Failed to parse opcode bytes: %s (case: %s, expected: %s)" % (bytez, name, reprOp)) except Exception: self.fail( "Failed to parse opcode bytes: %s (case: %s, expected: %s)" % (bytez, name, reprOp)) msg = '%s failed length check. Got %d, expected %d' % ( name, len(op), int(len(bytez) / 2)) self.assertEqual(len(op), int(len(bytez) / 2), msg=msg) # print("'%s', 0x%x, '%s' == '%s'" % (bytez, va, repr(op), reprOp)) try: self.assertEqual(repr(op), reprOp) except AssertionError: self.fail("Failing match for case %s (%s != %s)" % (name, repr(op), reprOp)) scanv.clearCanvas() op.render(scanv) self.assertEqual(scanv.strval, renderOp)
def _get_function_data(vw: VivWorkspace): all_funcs_va = vw.getFunctions() all_funcs_va = sorted(all_funcs_va) str_canvas = memcanvas.StringMemoryCanvas(vw) for fva in all_funcs_va: f_meta = vw.getFunctionMetaDict(fva) meta_keys = sorted(f_meta.keys()) f_name = vw.getName(fva) str_canvas.addText('Function: %s\n' % f_name) for m_key in meta_keys: str_canvas.addText("\t%s: %s\n" % (str(m_key), str(f_meta[m_key]))) for cbva, cbsize, cbfva in vw.getFunctionBlocks(fva): finalva = cbva + cbsize while cbva < finalva: opcode = vw.parseOpcode(cbva, const.LOC_OP) opcode.render(str_canvas) str_canvas.addText("\n") cbva += opcode.size str_canvas.addText('\n') return str_canvas.strval
def vqLoad(self): self.lastregs = self.regvals.copy() if not self.trace.isAttached(): self.setEnabled(False) return if self.trace.isRunning(): self.setEnabled(False) return model = RegisterListModel(parent=self) self.setModel(model) for rname in self.regnames: rval = self.trace.getRegisterByName(rname) self.regvals[rname] = rval hexva = self.trace.pointerString(rval) try: # TODO: yuck...implement a "fast" string memorycanvas? smc = e_mcanv.StringMemoryCanvas(self.trace) self.descrend.render(smc, rval) except Exception as e: smc = repr(e) finally: model.append((rname, hexva, rval, str(smc)))
def render(self, mcanv, va): trace = mcanv.mem if va != trace.getStackCounter(): return DerefRenderer.render(self, mcanv, va) pc = trace.getProgramCounter() sym, is_thunk = trace.getSymByAddrThunkAware(pc) if sym is None: return DerefRenderer.render(self, mcanv, va) # TODO: this code also exists in win32stealth and in hookbreakpoint # we should put this somewhere common platform = trace.getMeta('Platform') arch = trace.getMeta('Architecture') impapi = viv_impapi.getImportApi(platform, arch) cc_name = impapi.getImpApiCallConv(sym) emu = vtrace.getEmu(trace) cc = emu.getCallingConvention(cc_name) args_def = impapi.getImpApiArgs(sym) if args_def is None: # sym did not exist in impapi :( logger.warning('sym but no impapi match: {}'.format(sym)) return DerefRenderer.render(self, mcanv, va) argc = len(args_def) curop = trace.parseOpcode(trace.getProgramCounter()) # use the calling convention to retrieve the args args = None if curop.isCall() or is_thunk: args = cc.getPreCallArgs(trace, argc) else: args = cc.getCallArgs(trace, argc) # since we are 'normalizing' the calls by visualizing all calling # conventions in a stdcall fashion, some args (like the ones in # registers don't have a stack va. mcanv.addText('%s :\n' % sym) fmt = ' arg%%d (%%s) 0x%%0%dx %%s\n' % (trace.getPointerSize() * 2, ) for index, arg in enumerate(args): argtype = args_def[index][0] argva = arg if trace.isValidPointer(arg): argva = trace.readMemoryFormat(arg, 'P')[0] smc = e_canvas.StringMemoryCanvas(trace) e_canvas_rend.AutoBytesRenderer(maxrend=64).render(smc, argva) desc = str(smc) mcanv.addText(fmt % (index, argtype, arg, desc)) mcanv.addText('-' * 5) mcanv.addText('\n') return DerefRenderer.render(self, mcanv, va)
def SKIPtest_envi_amd64_disasm_Specific_VEX_Instrs(self): vw = vivisect.VivWorkspace() scanv = e_memcanvas.StringMemoryCanvas(vw) for name, bytez, va, reprOp, renderOp in amd64VexOpcodes: op = self._arch.archParseOpcode(bytez.decode('hex'), 0, va) # print("'%s', 0x%x, '%s' == '%s'" % (bytez, va, repr(op), reprOp)) self.assertEqual(repr(op), reprOp) scanv.clearCanvas() op.render(scanv) #print "render: %s" % repr(scanv.strval) self.assertEqual(scanv.strval, renderOp)
def test_envi_amd64_disasm_Specific_MultiByte_Instrs(self): ''' pick 10 arbitrary 2- and 3-byte operands ''' vw = vivisect.VivWorkspace() scanv = e_memcanvas.StringMemoryCanvas(vw) for name, bytez, va, reprOp, renderOp in amd64MultiByteOpcodes: op = self._arch.archParseOpcode(bytez.decode('hex'), 0, va) #print "'%s', 0x%x, '%s' == '%s'" % (bytez, va, repr(op), reprOp) self.assertEqual( repr(op), reprOp ) scanv.clearCanvas() op.render(scanv) #print "render: %s" % repr(scanv.strval) self.assertEqual( scanv.strval, renderOp )
def checkOpcode(self, hexbytez, va, oprepr, opcheck, opercheck, renderOp): op = self._arch.archParseOpcode(binascii.unhexlify(hexbytez), 0, va) self.assertEqual(repr(op), oprepr) opvars = vars(op) for opk, opv in opcheck.items(): self.assertEqual((opk, opvars.get(opk)), (opk, opv)) for oidx in range(len(op.opers)): oper = op.opers[oidx] opervars = vars(oper) for opk, opv in opercheck[oidx].items(): self.assertEqual((opk, opervars.get(opk)), (opk, opv)) vw = vivisect.VivWorkspace() scanv = e_memcanvas.StringMemoryCanvas(vw) op.render(scanv) self.assertEqual(scanv.strval, renderOp)
def checkOpcode(self, hexbytez, va, oprepr, opcheck, opercheck, renderOp): op = self._arch.archParseOpcode(hexbytez.decode('hex'), 0, va) self.assertEqual( repr(op), oprepr ) opvars = vars(op) for opk,opv in list(opcheck.items()): #print "op: %s %s" % (opk,opv) self.assertEqual( (opk, opvars.get(opk)), (opk, opv) ) for oidx in range(len(op.opers)): oper = op.opers[oidx] opervars = vars(oper) for opk,opv in list(opercheck[oidx].items()): #print "oper: %s %s" % (opk,opv) self.assertEqual( (opk, opervars.get(opk)), (opk, opv) ) vw = vivisect.VivWorkspace() scanv = e_memcanvas.StringMemoryCanvas(vw) op.render(scanv) #print "render: %s" % repr(scanv.strval) self.assertEqual( scanv.strval, renderOp )
def do_saveout(self, line): ''' saves output to file for any command. still outputs to whatever canvas the command normally outputs to. saveout <output file> <cli command> Example: saveout out.txt search -c MZ ''' argv = shlex.split(line) if len(argv) < 2: return self.do_help('saveout') fname = argv[0] command = ' '.join(argv[1:]) strcanvas = e_canvas.StringMemoryCanvas(self.canvas.mem) with e_canvas.TeeCanvas(self, (self.canvas, strcanvas)) as tc: self.onecmd(command) with open(fname, 'wb') as f: f.write(str(strcanvas))
def regEdited(self, index, value): node = index.internalPointer() if not node or not value: return False expr = str(value.toString()) try: value = self.trace.parseExpression(expr) except Exception as e: return False reg = node.rowdata[0] self.trace.setRegisterByName(reg, value) regval = self.trace.getRegisterByName(reg) # TODO: yuck...implement a "fast" string memorycanvas? smc = e_mcanv.StringMemoryCanvas(self.trace) self.descrend.render(smc, regval) node.rowdata[1] = self.trace.pointerString(regval) node.rowdata[2] = regval node.rowdata[3] = str(smc) return True
def test_do_cmds(self): mem = e_mem.MemoryObject() mem.addMemoryMap(0x41410000, 7, 'testmem', b'@ABCDEF' * 256) ecli = e_cli.EnviCli(mem) ecli.canvas = e_mcanvas.StringMemoryCanvas(mem) ecli.canvas.addRenderer("bytes", e_render.ByteRend()) ecli.canvas.addRenderer("u_int_16", e_render.ShortRend()) ecli.canvas.addRenderer("u_int_32", e_render.LongRend()) ecli.canvas.addRenderer("u_int_64", e_render.QuadRend()) # do_alias ecli.do_alias('') output = ecli.canvas.strval self.assertIn('Runtime Aliases (not saved):', output) self.assertIn('Configured Aliases:', output) ecli.canvas.clearCanvas() # do_binstr ecli.do_binstr('47145') output = ecli.canvas.strval self.assertIn('0x0000b829 (47145) 1011100000101001', output) ecli.canvas.clearCanvas() # do_clear ecli.vprint("foobar") ecli.do_clear('') output = ecli.canvas.strval self.assertEqual('', output) ecli.canvas.clearCanvas() # do_config ecli.do_config('') output = ecli.canvas.strval self.assertIn('cli.verbose = False\n', output) ecli.canvas.clearCanvas() # do_EOF ecli.do_EOF('') output = ecli.canvas.strval self.assertIn('Use quit\n', output) ecli.canvas.clearCanvas() # do_eval ecli.do_eval('0x40 + 0x47145') output = ecli.canvas.strval self.assertIn('0x40 + 0x47145 = 0x00047185 (291205)\n', output) ecli.canvas.clearCanvas() # do_maps ecli.do_maps('') output = ecli.canvas.strval self.assertIn('0x41410000', output) ecli.canvas.clearCanvas() ecli.do_maps('0x41410001') output = ecli.canvas.strval self.assertIn(' 0x41410001\n0x41410000', output) ecli.canvas.clearCanvas() # do_mem ecli.do_mem('0x41410001 20') output = ecli.canvas.strval self.assertIn( '0x41410001 41 42 43 44 45 46 40 41 42 43 44 45 46 40 41 42 ABCDEF@ABCDEF@AB\n0x41410011 43 44 45 46 40 41 42 43 44 45 46 40 41 42 43 44 CDEF@ABCDEF@ABCD\n', output) ecli.canvas.clearCanvas() ecli.do_mem('-F u_int_16 0x41410001 20') output = ecli.canvas.strval self.assertIn( '0x41410001 4241 4443 4645 4140 4342 4544 4046 4241 ABCDEF@ABCDEF@AB\n0x41410011 4443 4645 4140 4342 4544 4046 4241 4443 CDEF@ABCDEF@ABCD\n', output) ecli.canvas.clearCanvas() ecli.do_mem('-F u_int_32 0x41410001 20') output = ecli.canvas.strval self.assertIn( '0x41410001 44434241 41404645 45444342 42414046 ABCDEF@ABCDEF@AB\n0x41410011 46454443 43424140 40464544 44434241 CDEF@ABCDEF@ABCD\n', output) ecli.canvas.clearCanvas() ecli.do_mem('-F u_int_64 0x41410001 20') output = ecli.canvas.strval self.assertIn( '0x0000000041410001 4140464544434241 4241404645444342 ABCDEF@ABCDEF@AB\n0x0000000041410011 4342414046454443 4443424140464544 CDEF@ABCDEF@ABCD\n', output) ecli.canvas.clearCanvas() # do_memcmp ecli.do_memcmp('0x41410001 0x41410005 20') output = ecli.canvas.strval self.assertIn( '==== 20 byte difference at offset 0\n0x41410001:4142434445464041424344454640414243444546\n0x41410005:4546404142434445464041424344454640414243\n', output) ecli.canvas.clearCanvas() # do_memdump ecli.do_memdump('0x41410001 /tmp/foo40 20') output = ecli.canvas.strval self.assertIn('wrote 20 bytes.\n', output) ecli.canvas.clearCanvas() with open('/tmp/foo40', 'rb') as testfile: self.assertEqual(testfile.read(), b'ABCDEF@ABCDEF@ABCDEF') ecli.canvas.clearCanvas() # do_python ecli.do_python( 'with open("/tmp/foo41", "wb") as testfile:\n\ttestfile.write(b"Test Worked")' ) output = ecli.canvas.strval with open('/tmp/foo41', 'rb') as testfile: self.assertEqual(testfile.read(), b'Test Worked') ecli.canvas.clearCanvas() # do_saveout ecli.do_saveout('/tmp/foo42 search ABCDEF') output = ecli.canvas.strval self.assertIn('\ndone (256 results).\n', output) ecli.canvas.clearCanvas() # do_search ecli.do_search('ABCDEF') output = ecli.canvas.strval self.assertIn('\ndone (256 results).\n', output) ecli.canvas.clearCanvas()
return for nva, node in graph.getNodes(): va = nva endva = va + node.get('cbsize') while va < endva: lva, lsz, ltype, ltinfo = self.getLocation(va) valist.append(va) va += lsz else: # the whole workspace is our oyster valist = [va for va, lvsz, ltype, ltinfo in self.getLocations(LOC_OP)] res = [] canv = e_canvas.StringMemoryCanvas(self) defaultSearchAll = True for va in valist: try: addthis = False op = self.parseOpcode(va) # search comment if options.searchComments: defaultSearchAll = False cmt = self.getComment(va) if cmt != None: if options.is_regex: if len(re.findall(pattern, cmt)):
def runStep(self, maxstep=1000000, follow=True, showafter=True, runTil=None, pause=True, silent=False, finish=0, silentExcept=()): global op, mcanv, call_handlers emu = self.emu mcanv = e_memcanvas.StringMemoryCanvas(emu, syms=emu.vw) nonstop = 0 tova = None quit = False moveon = False emuBranch = False i = 0 while maxstep > i: skip = skipop = False i += 1 pc = emu.getProgramCounter() if pc in (runTil, finish): break op = emu.parseOpcode(pc) # cancel emuBranch as we've come to one if op.isReturn() or op.isCall(): emuBranch = False if silent and not pc in silentExcept: showafter = False else: # do all the interface stuff here: showPriRegisters(emu, snapshot=SNAP_SWAP) #showFlags(emu) # ARM fails this right now. try: printMemStatus(emu, op) except Exception as e: print "MEM ERROR: %s: 0x%x %s" % (e, op.va, op) print "Step: %s" % i mcanv.clearCanvas() try: op.render(mcanv) except Exception as e: print "ERROR rendering opcode: %r" % e extra = getNameRefs(op, emu) opbytes = emu.readMemory(pc, len(op)) print("%.4x\t%20s\t%s\t%s" % (pc, sp.hexText(opbytes), mcanv.strval, extra)) print "---------" prompt = "q<enter> - exit, eval code to execute, 'skip' an instruction, 'b'ranch, 'go [+]#' to va or +# instrs or enter to continue: " # nonstop controls whether we stop. tova indicates we're hunting for a va, otherwise # treat nonstop as a negative-counter if tova is not None: if pc == tova: nonstop = 0 elif nonstop: nonstop -= 1 if not (emuBranch or nonstop) and pause: tova = None moveon = False uinp = raw_input(prompt) while len(uinp) and not (moveon or quit or emuBranch): if uinp == "q": quit = True break elif uinp.startswith('go '): args = uinp.split(' ') if args[-1].startswith('+'): nonstop = int(args[-1], 0) else: tova = int(args[-1], 0) nonstop = 1 break elif uinp in ('b', 'branch'): emuBranch = True break elif uinp == 'stack': stackDump(emu) break elif uinp == 'refresh': # basically does a NOP, doesn't change anything, just let the data be reprinted. moveon = True break elif uinp.startswith('pc=') or uinp.startswith('pc ='): print "handling setProgramCounter()" args = uinp.split('=') newpc = int(args[-1], 0) print "new PC: 0x%x" % newpc emu.setProgramCounter(newpc) moveon = True break elif '=' in uinp: print "handling generic register/memory writes" args = uinp.split('=') details = args[-1].split(',') if '[' in args[0]: if len(details) > 1: size = int(details[-1]) else: size = 4 #memaddr = int(args[0].replace('[','').replace(']',''), 0) memaddr = emu.vw.parseExpression( args[0].replace('[', '').replace(']', '')) emu.writeMemValue( memaddr, emu.vw.parseExpression(details[0], 0), size) #emu.writeMemValue(memaddr, int(details[0], 0), size) else: # must be registers emu.setRegisterByName(args[0], int(details[0], 0)) elif uinp.strip().startswith('[') and ']' in uinp: try: idx = uinp.find('[') + 1 eidx = uinp.find(']', idx) expr = uinp[idx:eidx] print "handling memory read at [%s]" % expr size = emu.getPointerSize() if ':' in expr: nexpr, size = expr.rsplit(':', 1) try: size = emu.vw.parseExpression(size) expr = nexpr except: # if number fails, just continue with a default size and the original expr pass va = emu.vw.parseExpression(expr) data = emu.readMemory(va, size) print "[%s:%s] == %r" % (expr, size, data.encode('hex')) except Exception as e: print "ERROR: %r" % e elif uinp == 'skip': newpc = emu.getProgramCounter() + len(op) print "new PC: 0x%x" % newpc skipop = True break elif uinp == 'memset': print memset(emu) skipop = True elif uinp == 'memcpy': print memcpy(emu) skipop = True elif uinp == 'strcpy': print strcpy(emu) skipop = True elif uinp == 'strncpy': print strncpy(emu) skipop = True elif uinp == 'strcat': print strcat(emu) skipop = True elif uinp == 'strlen': print strlen(emu) skipop = True else: try: print eval(uinp, globals(), locals()) except: sys.excepthook(*sys.exc_info()) uinp = raw_input(prompt) if quit: return if moveon: continue if len(op.opers) and op.iflags & (envi.IF_CALL) and not skipop: self.dbgprint("Call...") tva = op.getOperValue(0, emu) handler = self.call_handlers.get(tva) self.dbgprint(" handler for call to (0x%x): %r" % (tva, handler)) if handler is not None: handler(emu, op) skipop = True elif follow and not skip and not skipop: # use the emulator to execute the call starteip = emu.getProgramCounter() emu.executeOpcode(op) endeip = emu.getProgramCounter() i += 1 self.dbgprint("starteip: 0x%x, endeip: 0x%x -> %s" % (starteip, endeip, emu.vw.getName(endeip))) vg_path.getNodeProp(emu.curpath, 'valist').append(starteip) skip = True if not skip and not skipop: # if not already emulated a call, execute the instruction here... emu.stepi() # print the updated latest stuff.... if showafter: try: extra = getNameRefs(op, emu) if len(extra): print("after:\t%s\t%s" % (mcanv.strval, extra)) printMemStatus(emu, op, use_cached=True) except Exception as e: print "MEM ERROR: %s: 0x%x %s" % (e, op.va, op) elif skipop: newpc = emu.getProgramCounter() + len(op) emu.setProgramCounter(newpc)
def do_searchopcodes(self, line): ''' search opcodes/function for a pattern searchopcodes [-f <funcva>] [options] <pattern> -f [fva] - focus on one function -c - search comments -o - search operands -t - search text -M <color> - mark opcodes (default = orange) -R - pattern is REGEX (otherwise just text) ''' parser = e_cli.VOptionParser() parser.add_option('-f', action='store', dest='funcva', type='int') parser.add_option('-c', action='store_true', dest='searchComments') parser.add_option('-o', action='store_true', dest='searchOperands') parser.add_option('-t', action='store_true', dest='searchText') parser.add_option('-M', action='store', dest='markColor', default='orange') parser.add_option('-R', action='store_true', dest='is_regex') argv = shlex.split(line) try: options, args = parser.parse_args(argv) except Exception as e: self.vprint(repr(e)) return self.do_help('searchopcodes') pattern = ' '.join(args) if len(pattern) == 0: self.vprint('you must specify a pattern') return self.do_help('searchopcodes') # generate our interesting va list valist = [] if options.funcva: # setup valist from function data try: fva = options.funcva graph = viv_graph.buildFunctionGraph(self, fva) except Exception as e: self.vprint(repr(e)) return for nva, node in graph.getNodes(): va = nva endva = va + node.get('cbsize') while va < endva: lva, lsz, ltype, ltinfo = self.getLocation(va) valist.append(va) va += lsz else: # the whole workspace is our oyster valist = [ va for va, lvsz, ltype, ltinfo in self.getLocations(LOC_OP) ] res = [] canv = e_canvas.StringMemoryCanvas(self) defaultSearchAll = True for va in valist: try: addthis = False op = self.parseOpcode(va) # search comment if options.searchComments: defaultSearchAll = False cmt = self.getComment(va) if cmt is not None: if options.is_regex: if len(re.findall(pattern, cmt)): addthis = True else: if pattern in cmt: addthis = True # search operands if options.searchOperands: defaultSearchAll = False for opidx, oper in enumerate(op.opers): # we're writing to a temp canvas, so clear it before each test canv.clearCanvas() oper = op.opers[opidx] oper.render(canv, op, opidx) operepr = canv.strval if options.is_regex: if len(re.findall(pattern, operepr)): addthis = True else: if pattern in operepr: addthis = True # if we're doing non-regex, let's test against real numbers # (instead of converting to hex and back) numpattrn = pattern try: numpattrn = int(numpattrn, 0) except: pass if numpattrn in vars(oper).values(): addthis = True # search full text if options.searchText or defaultSearchAll: # search through the rendering of the opcode, as well as the comment canv.clearCanvas() op.render(canv) oprepr = canv.strval cmt = self.getComment(va) if cmt is not None: oprepr += " ; " + cmt if options.is_regex: if len(re.findall(pattern, oprepr)): addthis = True else: if pattern in oprepr: addthis = True # only want one listing of each va, no matter how many times it matches if addthis: res.append(va) except: self.vprint(''.join( traceback.format_exception(*sys.exc_info()))) if len(res) == 0: self.vprint('pattern not found: %s (%s)' % (pattern.encode('utf-8').hex(), repr(pattern))) return # set the color for each finding color = options.markColor colormap = {va: color for va in res} if self._viv_gui is not None: from vqt.main import vqtevent vqtevent('viv:colormap', colormap) self.vprint('matches for: %s (%s)' % (pattern.encode('utf-8').hex(), repr(pattern))) for va in res: mbase, msize, mperm, mfile = self.memobj.getMemoryMap(va) pname = e_memory.reprPerms(mperm) sname = self.reprPointer(va) op = self.parseOpcode(va) self.canvas.renderMemory(va, len(op)) cmt = self.getComment(va) if cmt is not None: self.canvas.addText('\t\t; %s (Perms: %s, Smartname: %s)' % (cmt, pname, sname)) self.canvas.addText('\n') self.vprint('done (%d results).' % len(res))
def __init__(self, expr='', esize='', emu=None, parent=None): QWidget.__init__(self, parent=parent) self.modes = [ 'ascii', 'hex', 'regex', 'utf-8', 'utf-16-le', 'utf-16-be' ] rend_orig = e_render.ByteRend() self.canvas_orig = e_canvas.StringMemoryCanvas(None) self.canvas_orig.addRenderer('bytes', rend_orig) rend_new = e_render.ByteRend() self.canvas_new = e_canvas.StringMemoryCanvas(None) self.canvas_new.addRenderer('bytes', rend_new) hbox1 = QHBoxLayout() self.nav = MemNavWidget() self.nav.userChanged.connect(self.renderMemory) self.renderRequest.connect(self.nav.setValues) hbox1.addWidget(self.nav) hbox2 = QHBoxLayout() self.hex_edit = QPlainTextEdit() self.hex_edit.setWordWrapMode(QtGui.QTextOption.NoWrap) self.hex_edit.setReadOnly(True) font = QtGui.QFont('Courier') # should use actual memcanvas self.hex_edit.setFont(font) hbox2.addWidget(self.hex_edit) vbox1 = QVBoxLayout() vbox1.addLayout(hbox1) vbox1.addLayout(hbox2) gbox1 = QGroupBox('Original Bytes') gbox1.setLayout(vbox1) hbox3 = QHBoxLayout() mode_label = QLabel('Input:') self.mode_combo = QComboBox() self.mode_combo.addItems(self.modes) self.mode_combo.currentIndexChanged.connect(self.encodingChanged) hbox3.addWidget(mode_label) hbox3.addWidget(self.mode_combo, alignment=QtCore.Qt.AlignLeft) hbox3.addStretch(1) hbox4 = QHBoxLayout() data_label = QLabel('Bytes:') self.data_edit = VQLineEdit() self.data_edit.keyReleased.connect(self.keyReleasedSlot) hbox4.addWidget(data_label) hbox4.addWidget(self.data_edit) vbox2 = QVBoxLayout() vbox2.addLayout(hbox3) vbox2.addLayout(hbox4) gbox2 = QGroupBox('New Bytes') gbox2.setLayout(vbox2) hbox5 = QHBoxLayout() self.hex_preview = QPlainTextEdit() self.hex_preview.setWordWrapMode(QtGui.QTextOption.NoWrap) self.hex_preview.setReadOnly(True) self.hex_preview.setFont(font) hbox5.addWidget(self.hex_preview) vbox3 = QVBoxLayout() vbox3.addLayout(hbox5) gbox3 = QGroupBox('Result Preview') gbox3.setLayout(vbox3) hbox6 = QHBoxLayout() button = QPushButton('Write Memory') button.clicked.connect(self.buttonClicked) hbox6.addWidget(button) vbox = QVBoxLayout() vbox.addWidget(gbox1) vbox.addWidget(gbox2) vbox.addWidget(gbox3) vbox.addLayout(hbox6) self.setLayout(vbox) self.setWindowTitle('Memory Write') self.resize(650, 500) self.data_edit.setFocus() self.emu = emu self.renderMemory(expr, esize)
def runStep(self, maxstep=1000000, follow=True, showafter=True, runTil=None, pause=True, silent=False, finish=0, tracedict=None): ''' runStep is the core "debugging" functionality for this emulation-helper. it's goal is to provide a single-step interface somewhat like what you might get from a GDB experience. pertinent registers are printed with their values, the current instruction, and any helpers that the operands may point to in memory (as appropriate). special features: * tracedict allows code to be evaluated and printed at specific addresses: tracedict={va:'python code here', 'locals':{'something':4}} * prints out the operands *after* exection as well (arg:showafter=True) * cli interface allows viewing and modifying memory/python objects: rax [rax] [rax:23] [rax+8:4] [0xf00b4:8] rax=42 [0xf00b4]=0x47145 * cli allows skipping printing (arg:silent=True) silent=True * cli allows running until a VA without pauses: go 0x12345 * cli allows executing until next branch: b * cli allows dumping the stack: stack * cli allows viewing/setting the Program Counter: pc pc=0x43243 * cli allows skipping instructions: skip * cli allows numerous libc-style functions: memset memcpy strcpy strncpy strcat strlen * call_handlers dict (global in the library) allows swapping in our python code in place of calls to other binary code, like memcpy, or other code which may fail in an emulator ''' emu = self.emu mcanv = e_memcanvas.StringMemoryCanvas(emu, syms=emu.vw) self.mcanv = mcanv # store it for later inspection # set up tracedict if tracedict is None: tracedict = {} else: print("tracedict entries for %r" % (','.join( [hex(key) for key in tracedict.keys() if type(key) == int]))) nonstop = 0 tova = None quit = False moveon = False emuBranch = False silentUntil = None # set silentExcept to include all tracedict items silentExcept = [va for va, expr in tracedict.items() if expr is None] i = 0 self.startRun = time.time() while maxstep > i: try: skip = skipop = False i += 1 pc = emu.getProgramCounter() if pc in (runTil, finish): print("PC reached 0x%x." % pc) break op = emu.parseOpcode(pc) self.op = op # store it for later in case of post-mortem # cancel emuBranch as we've come to one if op.isReturn() or op.isCall(): emuBranch = False #### TRACING tdata = tracedict.get(pc) if tdata is not None: try: lcls = locals() outlcls = tracedict.get('locals') if outlcls is not None: lcls.update(outlcls) print(repr(eval(tdata, globals(), lcls))) except Exception as e: print("TraceMonitor ERROR at 0x%x: %r" % (pc, e)) #### if silentUntil == pc: silent = False silentUntil = None self.printStats(i) if silent and not pc in silentExcept: showafter = False else: # do all the interface stuff here: self.showPriRegisters(snapshot=SNAP_SWAP) self.showFlags() # ARM fails this right now. try: self.printMemStatus(op) except Exception as e: print("MEM ERROR: %s: 0x%x %s" % (e, op.va, op)) import traceback traceback.print_exc() print("Step: %s" % i) mcanv.clearCanvas() try: op.render(mcanv) except Exception as e: print("ERROR rendering opcode: %r" % e) extra = self.getNameRefs(op) opbytes = emu.readMemory(pc, len(op)) print("%.4x\t%20s\t%s\t%s" % (pc, hexlify(opbytes), mcanv.strval, extra)) print("---------") prompt = "q<enter> - exit, eval code to execute, 'skip' an instruction, 'b'ranch, 'go [+]#' to va or +# instrs or enter to continue: " # nonstop controls whether we stop. tova indicates we're hunting for a va, otherwise # treat nonstop as a negative-counter if tova is not None: if pc == tova: nonstop = 0 elif nonstop: nonstop -= 1 if not (emuBranch or nonstop) and pause: tova = None moveon = False uinp = input(prompt) while len(uinp) and not (moveon or quit or emuBranch): try: if uinp == "q": quit = True break elif uinp.startswith('silent'): parts = uinp.split(' ') silentUntil = parseExpression( emu, parts[-1]) silent = True elif uinp.startswith('go '): args = uinp.split(' ') if args[-1].startswith('+'): nonstop = parseExpression( emu, args[-1]) else: tova = parseExpression(emu, args[-1]) nonstop = 1 break elif uinp in ('b', 'branch'): emuBranch = True break elif uinp == 'stack': self.stackDump() moveon = True break elif uinp == 'refresh': # basically does a NOP, doesn't change anything, just let the data be reprinted. moveon = True break elif uinp.startswith('pc=') or uinp.startswith( 'pc ='): print("handling setProgramCounter()") args = uinp.split('=') newpc = parseExpression(emu, args[-1]) print("new PC: 0x%x" % newpc) emu.setProgramCounter(newpc) moveon = True break elif '=' in uinp: print( "handling generic register/memory writes" ) args = uinp.split('=') data = args[-1].strip( ) # .split(',') ??? why did i ever do this? if '[' in args[0]: # memory derefs tgt = args[0].replace('[', '').replace( ']', '').split(':') if len(tgt) > 1: size = parseExpression( emu, tgt[-1]) else: size = 4 addrstr = tgt[0] memaddr = parseExpression(emu, addrstr) if data.startswith( '"') and data.endswith('"'): # write string data emu.writeMemory( memaddr, data[1:-1]) else: # write number emu.writeMemValue( memaddr, parseExpression(emu, data), size) else: # must be registers emu.setRegisterByName( args[0], parseExpression(emu, data)) elif uinp.strip().startswith( '[') and ']' in uinp: try: idx = uinp.find('[') + 1 eidx = uinp.find(']', idx) expr = uinp[idx:eidx] print("handling memory read at [%s]" % expr) size = emu.getPointerSize() if ':' in expr: nexpr, size = expr.rsplit(':', 1) try: size = parseExpression( emu, size) expr = nexpr except Exception as e: # if number fails, just continue with a default size and the original expr print( "unknown size: %r. using default size." % size) va = parseExpression(emu, expr) data = emu.readMemory(va, size) print("[%s:%s] == %r" % (expr, size, data.hex())) except Exception as e: print("ERROR: %r" % e) elif uinp == 'skip': newpc = emu.getProgramCounter() + len(op) print("new PC: 0x%x" % newpc) skipop = True break elif uinp == 'memset': print(memset(emu)) skipop = True elif uinp == 'memcpy': print(memcpy(emu)) skipop = True elif uinp == 'strcpy': print(strcpy(emu)) skipop = True elif uinp == 'strncpy': print(strncpy(emu)) skipop = True elif uinp == 'strcat': print(strcat(emu)) skipop = True elif uinp == 'strlen': print(strlen(emu)) skipop = True else: try: lcls = locals() lcls.update(emu.getRegisters()) out = eval(uinp, globals(), lcls) if type(out) == int: print(hex(out)) else: print(out) except: import sys sys.excepthook(*sys.exc_info()) except: traceback.print_exc() #self.printStats(i) uinp = input(prompt) if quit: print("Quitting!") self.printStats(i) return if moveon: continue # handle Calls separately if len(op.opers) and op.iflags & (envi.IF_CALL) and not skipop: self.dbgprint("Call...") tva = op.getOperValue(0, emu) handler = self.call_handlers.get(tva) self.dbgprint(" handler for call to (0x%x): %r" % (tva, handler)) if handler is not None: handler(emu, op) skipop = True elif follow and not skip and not skipop: # use the emulator to execute the call starteip = emu.getProgramCounter() if hasattr(emu, 'emumon') and emu.emumon is not None: emu.emumon.prehook(emu, op, starteip) emu.executeOpcode(op) endeip = emu.getProgramCounter() i += 1 if hasattr(emu, 'emumon') and emu.emumon is not None: emu.emumon.posthook(emu, op, endeip) self.dbgprint( "starteip: 0x%x, endeip: 0x%x -> %s" % (starteip, endeip, emu.vw.getName(endeip))) if hasattr(emu, 'curpath'): vg_path.getNodeProp(emu.curpath, 'valist').append(starteip) skip = True # if not already emulated a call, execute the instruction here... if not skip and not skipop: emu.stepi() # print the updated latest stuff.... if showafter: try: extra = self.getNameRefs(op) if len(extra): print("after:\t%s\t%s" % (mcanv.strval, extra)) self.printMemStatus(op, use_cached=True) except Exception as e: print("MEM ERROR: %s: 0x%x %s" % (e, op.va, op)) import sys sys.excepthook(*sys.exc_info()) # unless we've asked to skip the instruction... elif skipop: newpc = emu.getProgramCounter() + len(op) emu.setProgramCounter(newpc) except KeyboardInterrupt: self.printStats(i) break except envi.SegmentationViolation: import sys sys.excepthook(*sys.exc_info()) break except: import sys sys.excepthook(*sys.exc_info()) self.printStats(i)
def __init__(self): QDialog.__init__(self) self.modes = [ 'ascii', 'hex', 'regex', 'utf-8', 'utf-16-le', 'utf-16-be' ] self.pattern = None self.filename = None rend = e_render.ByteRend() self.canvas = e_canvas.StringMemoryCanvas(None) self.canvas.addRenderer('bytes', rend) hbox1 = QHBoxLayout() mode_label = QLabel('Input: ') self.mode_combo = QComboBox() self.mode_combo.addItems(self.modes) self.mode_combo.currentIndexChanged.connect(self.encodingChanged) hbox1.addWidget(mode_label) hbox1.addWidget(self.mode_combo, alignment=QtCore.Qt.AlignLeft) hbox1.addStretch(1) hbox2 = QHBoxLayout() data_label = QLabel('Bytes: ') self.data_edit = QLineEdit() hbox2.addWidget(data_label) hbox2.addWidget(self.data_edit) vbox1 = QVBoxLayout() vbox1.addLayout(hbox1) vbox1.addLayout(hbox2) gbox1 = QGroupBox('Search Criteria') gbox1.setLayout(vbox1) hbox3 = QHBoxLayout() vbox_hex_label = QVBoxLayout() # for align to top. hex_label = QLabel('Hex: ') vbox_hex_label.addWidget(hex_label, alignment=QtCore.Qt.AlignTop) self.hex_edit = QPlainTextEdit() self.hex_edit.setReadOnly(True) font = QtGui.QFont('Courier') # should use actual memcanvas. self.hex_edit.setFont(font) hbox3.addLayout(vbox_hex_label) hbox3.addWidget(self.hex_edit) vbox2 = QVBoxLayout() vbox2.addLayout(hbox3) gbox2 = QGroupBox('Bytes to Search For') gbox2.setLayout(vbox2) hbox4 = QHBoxLayout() save_check = QCheckBox('Save Search Results') save_check.stateChanged.connect(self.checkChanged) self.fname_label = QLabel('') buttons = QDialogButtonBox() buttons.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) buttons.accepted.connect(self.okClicked) buttons.rejected.connect(self.cancelClicked) hbox4.addWidget(save_check) hbox4.addWidget(self.fname_label) hbox4.addWidget(buttons) vbox = QVBoxLayout() vbox.addWidget(gbox1) vbox.addWidget(gbox2) vbox.addLayout(hbox4) self.setLayout(vbox) self.setWindowTitle('Memory Search') self.resize(650, 300) self.data_edit.setFocus()