def makeSwitch(vw, vajmp, offarraybase, indiroffbase=None): ''' Makes the changes to the Workspace for the given jmp location. Handles naming for all cases because naming wants to indicate larger context. (future)If indiroffbase is not None, the indirection "database" is analyzed for naming ''' filename = vw.getMemoryMap(vajmp)[3] imagebase = vw.getFileMeta(filename, 'imagebase') # we have identified this is a switch case vw.verbprint("FOUND MS SWITCH CASE SPRAY at 0x%x" % vajmp) # roll through the offset array until imagebase+offset is not a valid pointer, points to non-op locations or splits instructions count = 0 tracker = [] ptr = offarraybase while True: off = vw.readMemValue(ptr + imagebase, 4) ova = imagebase + off tgtva = makeSwitchCase(vw, vajmp, ova) if not tgtva: break tracker.append((count, tgtva)) count += 1 ptr += 4 # FIXME: this doesn't take into account two-level derefs (indiroffbase) naming = {} for idx, va in tracker: lst = naming.get(va) if lst == None: lst = [] naming[va] = lst lst.append("%xh" % idx) #TODO: analyze indiroffbase to determine case information for va, opts in list(naming.items()): options = "_".join(opts) name = "switch_case_%s_%.8x" % (options, va) vw.makeName(va, name) #TODO: analyze which paths handle which cases, name accordingly #TODO: determine good hint for symbolik constraints funcva = vw.getFunction(vajmp) vw.makeName(vajmp, "jmp_switch_%.8x" % vajmp) vagc.analyzeFunction(vw, funcva) return tracker
def makeSwitch(vw, vajmp, offarraybase, indiroffbase=None): ''' Makes the changes to the Workspace for the given jmp location. Handles naming for all cases because naming wants to indicate larger context. (future)If indiroffbase is not None, the indirection "database" is analyzed for naming ''' filename = vw.getMemoryMap(vajmp)[3] imagebase = vw.getFileMeta(filename, 'imagebase') # we have identified this is a switch case vw.verbprint( "FOUND MS SWITCH CASE SPRAY at 0x%x" % vajmp) # roll through the offset array until imagebase+offset is not a valid pointer, points to non-op locations or splits instructions count = 0 tracker = [] ptr = offarraybase while True: off = vw.readMemValue(ptr+imagebase, 4) ova = imagebase + off tgtva = makeSwitchCase(vw, vajmp, ova) if not tgtva: break tracker.append((count, tgtva)) count += 1 ptr += 4 # FIXME: this doesn't take into account two-level derefs (indiroffbase) naming = {} for idx,va in tracker: lst = naming.get(va) if lst == None: lst = [] naming[va] = lst lst.append("%xh" % idx) #TODO: analyze indiroffbase to determine case information for va, opts in list(naming.items()): options = "_".join(opts) name = "switch_case_%s_%.8x" % (options, va) vw.makeName(va, name) #TODO: analyze which paths handle which cases, name accordingly #TODO: determine good hint for symbolik constraints funcva = vw.getFunction(vajmp) vw.makeName(vajmp, "jmp_switch_%.8x" % vajmp) vagc.analyzeFunction(vw, funcva) return tracker
def analyzeJmp(amod, emu, op, starteip): ''' Top level logic ''' vw = emu.vw ctx = getSwitchBase(vw, op, starteip, emu) if ctx is not None: tova, scale = ctx vw.makeJumpTable(op, tova, rebase=True, psize=scale) # so the codeblocks this jumptable points to aren't proper locations...yet. # let's fix that up and kick off codeblock analysis to make the codeblocks for xrfrom, xrto, xrtype, xrflags in vw.getXrefsFrom( op.va, rtype=v_const.REF_CODE): vw.makeCode(xrto) vagc.analyzeFunction(vw, vw.getFunction(starteip))
def analyzeFunction(vw, fva): #print("++ Arm EMU fmod: 0x%x" % fva) emu = vw.getEmulator() emumon = AnalysisMonitor(vw, fva) emu.setEmulationMonitor(emumon) loc = vw.getLocation(fva) if loc is not None: lva, lsz, lt, lti = loc if lt == LOC_OP: if (lti & envi.ARCH_MASK) != envi.ARCH_ARMV7: emu.setFlag(PSR_T_bit, 1) else: logger.warn("NO LOCATION at FVA: 0x%x", fva) emu.runFunction(fva, maxhit=1) # Do we already have API info in meta? # NOTE: do *not* use getFunctionApi here, it will make one! api = vw.getFunctionMeta(fva, 'api') if api is None: api = buildFunctionApi(vw, fva, emu, emumon) rettype, retname, callconv, callname, callargs = api argc = len(callargs) cc = emu.getCallingConvention(callconv) if cc is None: return stcount = cc.getNumStackArgs(emu, argc) stackidx = argc - stcount baseoff = cc.getStackArgOffset(emu, argc) # Register our stack args as function locals for i in range(stcount): vw.setFunctionLocal(fva, baseoff + (i * 4), LSYM_FARG, i + stackidx) emumon.addAnalysisResults(vw, emu) # handle infinite loops (actually, while 1;) # switch-cases may have updated codeflow. reanalyze viv_cb.analyzeFunction(vw, fva)