def analyze(vw): """ """ # Go through the relocations and create locations for them for segva,segsize,segname,segfname in vw.getSegments(): # FIXME should we do this by something other than name? if segname != ".reloc": continue offset, bytes = vw.getByteDef(segva) while offset < segsize: # error cehck to make sure we are providing four bytes # to the parse routine if len(bytes[offset+4:offset+8]) != 4: break basepage = e_bits.parsebytes(bytes, offset, 4) vaoff = segva + offset vw.makeNumber(vaoff, 4) vw.makeName(vaoff, "reloc_chunk_%.8x" % vaoff) recsize = e_bits.parsebytes(bytes, offset+4, 4) vw.makeNumber(segva+offset+4, 4) ioff = offset + 8 while ioff < offset+recsize: vw.makeNumber(segva + ioff, 2) ioff += 2 offset += recsize if recsize == 0: break
def analyze(vw): """ """ # Go through the relocations and create locations for them for segva, segsize, segname, segfname in vw.getSegments(): reloc_va = vw.getFileMeta(segfname, "reloc_va") # Found binaries with multiple sections named .reloc where one was iat another # was actual reloc if reloc_va != segva: continue offset, bytes = vw.getByteDef(segva) while offset < segsize: # error check to make sure we are providing four bytes # to the parse routine if len(bytes[offset + 4:offset + 8]) != 4: break basepage = e_bits.parsebytes(bytes, offset, 4) vaoff = segva + offset vw.makeNumber(vaoff, 4) vw.makeName(vaoff, "reloc_chunk_%.8x" % vaoff) recsize = e_bits.parsebytes(bytes, offset + 4, 4) vw.makeNumber(segva + offset + 4, 4) ioff = offset + 8 while ioff < offset + recsize: vw.makeNumber(segva + ioff, 2) ioff += 2 offset += recsize if recsize == 0: break
def _buildOper(self, bytes, offset, immoff, otype, oinfo): if otype == OPTYPE_Reg: return z80RegOper(oinfo) elif otype == OPTYPE_RegMem: return z80RegMem(oinfo) elif otype == OPTYPE_const: return z80ConstOper(oinfo) elif otype == OPTYPE_imm8: imm = e_bits.parsebytes(bytes, offset+immoff, 1) return z80ImmOper(imm) elif otype == OPTYPE_imm16: imm = e_bits.parsebytes(bytes, offset+immoff, 2) return z80ImmOper(imm) elif otype == OPTYPE_RegAlt: print 'REG ALT!' return z80RegOper(oinfo) elif otype == OPTYPE_Ind: print 'OPTYPE IND' elif otype == OPTYPE_RegMemDisp: disp = e_bits.parsebytes(bytes, offset+immoff, 1, sign=True) return z80RegMem(oinfo, disp) else: raise Exception('Unknown z80 operand type: %d' % otype)
def parse_sib(self, bytez, offset, mod, prefixes=0): """ Return a tuple of (size, scale, index, base, imm) """ byte = ord(bytez[offset]) scale = (byte >> 6) & 0x3 index = (byte >> 3) & 0x7 base = byte & 0x7 imm = None size = 1 # Special SIB case with no index reg if index == 4: index = None # Special SIB case with possible immediate if base == 5: if mod == 0: # [ imm32 + index * scale ] base = None imm = e_bits.parsebytes(bytez, offset+size, 4, sign=False) size += 4 # FIXME is there special stuff needed here? elif mod == 1: pass #raise "OMG MOD 1" elif mod == 2: pass #raise "OMG MOD 2" return (size, scale, index, base, imm)
def ameth_l(self, bytez, offset, tsize, prefixes, operflags): osize = 1 imm = e_bits.parsebytes(bytez, offset, 1) vvvv = (imm >> 4) offset = self.ROFFSETSIMD if not (prefixes & PREFIX_VEX_L): vvvv |= e_i386.RMETA_LOW128 oper = i386RegOper(offset + vvvv, tsize) return osize, oper
def readMemValue(self, addr, size): """ Returns the value of the bytes at the "addr" address, given the size (currently, power of 2 only) """ bytes = self.readMemory(addr, size) if bytes == None: return None if len(bytes) != size: raise Exception("Read Gave Wrong Length At 0x%.8x (va: 0x%.8x wanted %d got %d)" % (self.getProgramCounter(),addr, size, len(bytes))) return e_bits.parsebytes(bytes, 0, size, False, self.getEndian())
def extended_parse_modrm(self, bytes, offset, opersize, regbase=0): """ Return a tuple of (size, Operand) """ size = 1 # FIXME this would be best to not parse_modrm twice. tweak it. mod,reg,rm = self.parse_modrm(ord(bytes[offset])) if mod == 0 and rm == 5: imm = e_bits.parsebytes(bytes, offset + size, 4, sign=True) size += 4 return(size, Amd64RipRelOper(imm, 4)) return e_i386.i386Disasm.extended_parse_modrm(self, bytes, offset, opersize, regbase)
def readMemValue(self, addr, size): ''' Read a number from memory of the given size. ''' #FIXME: use getBytesDef (and implement a dummy wrapper in VTrace for getBytesDef) bytes = self.readMemory(addr, size) if bytes == None: return None #FIXME change this (and all uses of it) to passing in format... if len(bytes) != size: raise Exception("Read Gave Wrong Length At 0x%.8x (va: 0x%.8x wanted %d got %d)" % (self.getProgramCounter(),addr, size, len(bytes))) return e_bits.parsebytes(bytes, 0, size, False, self.getEndian())
def addAnalysisResults(self, vw, emu): """ Do any post-run annotation that the base analysis emulator knows how to do... """ # Add emulation anomalies for row in self.getAnomalies(): va, msg = row vw.setVaSetRow("Emulation Anomalies", row) vw.setComment(va, 'Emu Anomaly: %s' % (msg,), check=True) # Go through the evaluated dereference operands and add operand refs deltadone = {} for va, idx, val, tsize, spdelta, discrete in self.operrefs: if spdelta: vw.addFref(self.fva, va, idx, spdelta) if deltadone.get(spdelta): continue deltadone[spdelta] = True if spdelta <= 0: # add function locals vw.setFunctionLocal(self.fva, spdelta, LSYM_NAME, ('int', 'local%d' % abs(spdelta))) continue # Only infer things about the workspace based on discrete operands if vw.isValidPointer(val) and discrete: vw.addXref(va, val, REF_DATA) if vw.getLocation(val) is not None: continue offset, bytes = vw.getByteDef(val) pval = e_bits.parsebytes(bytes, offset, tsize) if vw.psize == tsize and vw.isValidPointer(pval): vw.makePointer(val, tova=pval) else: vw.makeNumber(val, tsize) for va, callname, argv in self.callcomments: reprargs = [emu.reprVivValue(val) for val in argv] self.vw.setComment(va, '%s(%s)' % (callname, ','.join(reprargs)))
def ameth_a(self, bytez, offset, tsize, prefixes, operflags): imm = e_bits.parsebytes(bytez, offset, tsize) # seg = e_bits.parsebytes(bytez, offset+tsize, 2) # THIS BEING GHETTORIGGED ONLY EFFECTS callf jmpf - unghettorigged by atlas # FIXME: envi.intel.ameth_a skipping seg prefix %d" % seg) return (tsize, i386ImmOper(imm, tsize))
def ameth_o(self, bytez, offset, tsize, prefixes, operflags): # NOTE: displacement *stays* 32 bit even with REX # (but 16 bit should probably be supported) imm = e_bits.parsebytes(bytez, offset, self.ptrsize, sign=False) return (self.ptrsize, i386ImmMemOper(imm, tsize))
def ameth_j(self, bytez, offset, tsize, prefixes, operflags): imm = e_bits.parsebytes(bytez, offset, tsize, sign=True) return (tsize, i386PcRelOper(imm, tsize))
def ameth_i(self, bytez, offset, tsize, prefixes, operflags): imm = e_bits.parsebytes(bytez, offset, tsize) return (tsize, i386ImmOper(imm, tsize))
def ameth_a(self, bytez, offset, tsize, prefixes, operflags): imm = e_bits.parsebytes(bytez, offset, tsize) #seg = e_bits.parsebytes(bytez, offset+tsize, 2) # THIS BEING GHETTORIGGED ONLY EFFECTS callf jmpf - unghettorigged by atlas #print "FIXME: envi.intel.ameth_a skipping seg prefix %d" % seg return (tsize, i386ImmOper(imm, tsize))
def extended_parse_modrm(self, bytez, offset, opersize, regbase=0, prefixes=0): """ Return a tuple of (size, Operand) """ mod,reg,rm = self.parse_modrm(ord(bytez[offset])) size = 1 #print "EXTENDED MOD REG RM",mod,reg,rm if mod == 3: # Easy one, just a reg # FIXME only use self.byteRegOffset in 32 bit mode, NOT 64 bit... if opersize == 1: rm = self.byteRegOffset(rm, prefixes=prefixes) elif opersize == 2: rm += RMETA_LOW16 #print "OPERSIZE",opersize,rm return (size, i386RegOper(rm+regbase, opersize)) elif mod == 0: # means we are [reg] unless rm == 4 (SIB) or rm == 5 ([imm32]) if rm == 5: imm = e_bits.parsebytes(bytez, offset + size, 4) size += 4 # NOTE: in 64 bit mode, *this* is where we differ, (This case is RIP relative) return(size, i386ImmMemOper(imm, opersize)) elif rm == 4: sibsize, scale, index, base, imm = self.parse_sib(bytez, offset+size, mod, prefixes=prefixes) size += sibsize if base != None: base += regbase # Adjust for different register addressing modes if index != None: index += regbase # Adjust for different register addressing modes oper = i386SibOper(opersize, reg=base, imm=imm, index=index, scale=scale_lookup[scale]) return (size, oper) else: return(size, i386RegMemOper(regbase+rm, opersize)) elif mod == 1: # mod 1 means we are [ reg + disp8 ] (unless rm == 4 which means sib + disp8) if rm == 4: sibsize, scale, index, base, imm = self.parse_sib(bytez, offset+size, mod, prefixes=prefixes) size += sibsize disp = e_bits.parsebytes(bytez, offset+size, 1, sign=True) size += 1 if base != None: base += regbase # Adjust for different register addressing modes if index != None: index += regbase # Adjust for different register addressing modes oper = i386SibOper(opersize, reg=base, index=index, scale=scale_lookup[scale], disp=disp) return (size,oper) else: x = e_bits.signed(ord(bytez[offset+size]), 1) size += 1 return(size, i386RegMemOper(regbase+rm, opersize, disp=x)) elif mod == 2: # Means we are [ reg + disp32 ] (unless rm == 4 which means SIB + disp32) if rm == 4: sibsize, scale, index, base, imm = self.parse_sib(bytez,offset+size,mod, prefixes=prefixes) size += sibsize disp = e_bits.parsebytes(bytez, offset + size, 4, sign=True) size += 4 if base != None: base += regbase # Adjust for different register addressing modes if index != None: index += regbase # Adjust for different register addressing modes oper = i386SibOper(opersize, reg=base, imm=imm, index=index, scale=scale_lookup[scale], disp=disp) return (size, oper) else: # NOTE: Immediate displacements in SIB are still 4 bytes in 64 bit mode disp = e_bits.parsebytes(bytez, offset+size, 4, sign=True) size += 4 return(size, i386RegMemOper(regbase+rm, opersize, disp=disp)) else: raise Exception("How does mod == %d" % mod)
def ameth_i(self, bytes, offset, tsize, prefixes): # FIXME sign extend here if opflags has OP_SIGNED imm = e_bits.parsebytes(bytes, offset, tsize) return (tsize, i386ImmOper(imm, tsize))
def ameth_a(self, bytes, offset, tsize, prefixes): imm = e_bits.parsebytes(bytes, offset, tsize) seg = e_bits.parsebytes(bytes, offset+tsize, 2) # THIS BEING GHETTORIGGED ONLY EFFECTS callf jmpf #print "FIXME: envi.intel.ameth_a skipping seg prefix %d" % seg return (tsize+2, i386ImmOper(imm, tsize))
def shortend_parse_modrm(self, bytez, offset, opersize, regbase=0, prefixes=0): ''' This is to handle the 16 version of oper addressing. ~1/2 of the table is completely different from the 32 bit version ''' mod, reg, rm = self.parse_modrm(bytez[offset]) size = 1 opers = addr16_modes[rm] # SIB oper for the 16 bit addressing stuff because it actually fits if mod == 0: if len(opers) == 2: return (size, i386SibOper(opersize, reg=opers[0], imm=None, index=opers[1], scale=1)) elif len(opers) == 1: return (size, i386RegMemOper(opers[0], opersize)) else: imm = e_bits.parsebytes(bytez, offset + size, 2) size += 2 return (size, i386ImmMemOper(imm, opersize)) elif mod == 1: imm = e_bits.parsebytes(bytez, offset + size, 1) size += 1 if len(opers) == 2: return (size, i386SibOper(opersize, reg=opers[0], disp=imm, index=opers[1], scale=1)) elif len(opers) == 1: return (size, i386RegMemOper(opers[0], opersize, disp=imm)) else: return i386ImmMemOper(imm, opersize) elif mod == 2: imm = e_bits.parsebytes(bytez, offset + size, 2) size += 2 if len(opers) == 2: return i386SibOper(opersize, reg=opers[0], disp=imm, index=opers[1], scale=1) elif len(opers) == 1: return (size, i386RegMemOper(opers[0], opersize, disp=imm)) else: return (size, i386ImmMemOper(imm, opersize)) elif mod == 3: if opersize == 1: rm = self.byteRegOffset(rm, prefixes=prefixes) elif opersize == 2: rm += RMETA_LOW16 return (size, i386RegOper(rm + regbase, opersize)) else: raise Exception("(16bit) How does mod == %d" % mod)
def extended_parse_modrm(self, bytez, offset, opersize, regbase=0, prefixes=0): """ Return a tuple of (size, Operand) """ if prefixes & PREFIX_ADDR_SIZE: if opersize == 4 and self.ptrsize == 4: return self.shortend_parse_modrm(bytez, offset, opersize, regbase=regbase, prefixes=prefixes) mod, reg, rm = self.parse_modrm(bytez[offset]) size = 1 if mod == 3: # Easy one, just a reg # FIXME only use self.byteRegOffset in 32 bit mode, NOT 64 bit... if opersize == 1: rm = self.byteRegOffset(rm, prefixes=prefixes) elif opersize == 2: rm += RMETA_LOW16 return (size, i386RegOper(rm + regbase, opersize)) elif mod == 0: # means we are [reg] unless rm == 4 (SIB) or rm == 5 ([imm32]) # BUT JOKES -- the table is totally different in 16 bit mode BECAUSE WHY if rm == 5: imm = e_bits.parsebytes(bytez, offset + size, 4) size += 4 # NOTE: in 64 bit mode, *this* is where we differ, (This case is RIP relative) return (size, i386ImmMemOper(imm, opersize)) elif rm == 4: sibsize, scale, index, base, imm = self.parse_sib( bytez, offset + size, mod, prefixes=prefixes) size += sibsize if base is not None: base += regbase # Adjust for different register addressing modes if index is not None: index += regbase # Adjust for different register addressing modes oper = i386SibOper(opersize, reg=base, imm=imm, index=index, scale=scale_lookup[scale]) return (size, oper) else: return (size, i386RegMemOper(regbase + rm, opersize)) elif mod == 1: # mod 1 means we are [ reg + disp8 ] (unless rm == 4 which means sib + disp8) if rm == 4: sibsize, scale, index, base, imm = self.parse_sib( bytez, offset + size, mod, prefixes=prefixes) size += sibsize disp = e_bits.parsebytes(bytez, offset + size, 1, sign=True) size += 1 if base is not None: base += regbase # Adjust for different register addressing modes if index is not None: index += regbase # Adjust for different register addressing modes oper = i386SibOper(opersize, reg=base, index=index, scale=scale_lookup[scale], disp=disp) return (size, oper) else: x = e_bits.signed(bytez[offset + size], 1) size += 1 return (size, i386RegMemOper(regbase + rm, opersize, disp=x)) elif mod == 2: # Means we are [ reg + disp32 ] (unless rm == 4 which means SIB + disp32) if rm == 4: sibsize, scale, index, base, imm = self.parse_sib( bytez, offset + size, mod, prefixes=prefixes) size += sibsize disp = e_bits.parsebytes(bytez, offset + size, 4, sign=True) size += 4 if base is not None: base += regbase # Adjust for different register addressing modes if index is not None: index += regbase # Adjust for different register addressing modes oper = i386SibOper(opersize, reg=base, imm=imm, index=index, scale=scale_lookup[scale], disp=disp) return (size, oper) else: # NOTE: Immediate displacements in SIB are still 4 bytes in 64 bit mode disp = e_bits.parsebytes(bytez, offset + size, 4, sign=True) size += 4 return (size, i386RegMemOper(regbase + rm, opersize, disp=disp)) else: raise Exception("How does mod == %d" % mod)