def __init__(self,b=None,**kargs): if b is None: Bits.__init__(self,0,128) for k,v in kargs.iteritems(): if hasattr(self,k): setattr(self,k,v) else: Bits.__init__(self,b)
def decode(self, istr, endian=1, i=None, iclass=instruction): # check spec : blen = self.fix.size // 8 if len(istr) < blen: raise DecodeError bs = istr[0:blen] # Bits object created with LSB to MSB byte string: ival = bs[::endian] b = Bits(ival, self.fix.size, bitorder=1) if b & self.mask != self.fix: raise DecodeError if self.size == 0: # variable length spec: if endian != 1: logger.error("invalid endianess") b = b // Bits(istr[blen:], bitorder=1) # create & update instruction object: if i is None: i = iclass(bs) else: i.bytes += bs i.spec = self # set instruction attributes from directives, and then # call hook function with instruction as first parameter # and fargs (note that hook can thus overwrite previous attributes) for k, v in iter(self.iattr.items()): if isinstance(v, FunctionType): v = v(b) setattr(i, k, v) kargs = {} for k, v in iter(self.fargs.items()): if isinstance(v, FunctionType): v = v(b) kargs[k] = v # and finally call the hook: try: # check any precondition on i: if self.precond and (not self.precond(i)): raise InstructionError(i) # ok, lets call the spec hook... self.hook(obj=i, **kargs) except InstructionError: # clean up: i.bytes = i.bytes[:-len(bs)] for k in iter(self.iattr.keys()): delattr(i, k) raise InstructionError(i) return i
def test_des_wb(): K = codecs.decode(b"0123456789ABCDEF", 'hex') bK = Bits(K, 64) b1 = b"Now is t" b2 = b"he time " b3 = b"for" + b"\5" * 5 KT = [] for r in range(16): s, t = table_rKT(r, bK) KT.append(t) E = DES(K) WT = ECB(WhiteDES(KT, table_M1(), table_M2()[0], table_M3())) c = WT.enc(b"Now is the time for") assert c == E.enc(b1) + E.enc(b2) + E.enc(b3)
def __call__(self, bytestring, **kargs): e = self.endian(**kargs) adjust = lambda x: x.ival if e == -1: maxsize = self.maxlen * 8 adjust = lambda x: x.ival << (maxsize - x.size) b = adjust(Bits(bytestring[::e], bitorder=1)) # get organized/optimized tree of specs: fl = self.specs[self.iset(**kargs)] while True: f, l = fl if f == 0: # we are on a leaf... for s in l: # lets search linearly over this branch try: i = s.decode(bytestring, e, i=self.__i, iclass=self.iclass) except (DecodeError, InstructionError): # logger.debug(u'exception raised by disassembler:' # u'decoding %s with spec %s'%(codecs.encode(bytestring,'hex'),s.format)) continue # we found the instruction (or prefix) if i.spec.pfx is True: if self.__i is None: self.__i = i return self(bytestring[s.mask.size // 8:], **kargs) elif i.spec.pfx > 0: i.misc["xsz"] = i.spec.pfx self.__i = None if "address" in kargs: i.address = kargs["address"] return i logger.debug("no instruction spec matching '%s'" % (codecs.encode(bytestring, "hex"))) break else: # go deeper in the tree according to submask value of b fl = l.get(b & f, None) if fl is None: break self.__i = None return None
def buildspec(self): ast = specdecode.parseString(self.format, True) size, direction = ast[0] self.size = size fmt = ast[1] self.pfx = ast[2] xsz = ast[3] if self.pfx and xsz: self.pfx = xsz go = +1 chklen = True if direction == "<": # format goes from high bits to low bits fmt = list(reversed(fmt)) go = -1 if size == "*": self.size = 0 chklen = False size = 0 for d in fmt: if d in ("-", "0", "1"): size += 1 elif isinstance(d, Bits): size += d.size else: loc = d[2] if loc == "*": break size += loc if size % 8 != 0: logger.error("ispec length not a multiple of 8 %s" % self.format) self.fix = Bits(0, size) # values of fixed bits self.mask = Bits(0, size) # location of fixed bits i = 0 count = 0 for d in fmt: if chklen and not i < size: logger.error("ispec format too wide %s" % self.format) # unknown bit (skipped) if d == "-": i += 1 count += 1 continue # fixed bit: if d in ("0", "1"): self.fix[i] = int(d) self.mask[i] = 1 i += 1 count += 1 continue # fixed byte: if isinstance(d, Bits): self.fix[i:i + d.size] = d self.mask[i:i + d.size] = d.mask i += d.size count += d.size continue # directive: opt, symbol, loc = d if loc != "*": if opt == "=" and go > 0: i = i - loc sta = i sto = i + loc if sta < 0 or sto > size: logger.error("ispec directive out of bound in %s" % self.format) if opt != "=": count += loc i = sto if opt == "=" and go < 0: i = i - loc else: if opt == "=": logger.error("ispec directive invalid length in %s" % self.format) sta = i sto = None i = size if count < size: count = size chklen = True # now set D (fargs or iattr) to corresponding extractor lambdas which # will be called when decode is called by the disassembler: D = self.fargs if "." in opt: D = self.iattr if symbol in D: raise logger.error("ispec symbol %s redefined" % symbol) if "~" in opt: f = lambda b, p=sta, q=sto: b[p:q] elif "#" in opt: f = lambda b, p=sta, q=sto, x=go: str(b[p:q])[::x] else: f = lambda b, p=sta, q=sto: b[p:q].ival D[symbol] = f if count != size: logger.error("ispec size mismatch (%s)" % self.format) return ast
return s if toks else highlight(s) # ispec format parser: # --------------------- integer = pp.Regex(r"[1-9][0-9]*") indxdir = pp.oneOf(["<", ">"]) fixbit = pp.oneOf(["0", "1"]) number = integer | fixbit number.setParseAction(lambda r: int(r[0])) unklen = pp.Literal("*") length = number | unklen unkbit = pp.oneOf(["-"]) fixbyte = pp.Regex(r"{[0-9a-fA-F][0-9a-fA-F]}").setParseAction( lambda r: Bits(int(r[0][1:3], 16), 8)) fixed = fixbyte | fixbit | unkbit option = pp.oneOf([".", "~", "#", "="]) symbol = pp.Regex(r"[A-Za-z_][A-Za-z0-9_]*") location = pp.Suppress("(") + length + pp.Suppress(")") directive = pp.Group( pp.Optional(option, default="") + symbol + pp.Optional(location, default=1)) speclen = pp.Group(length + pp.Optional(indxdir, default="<")) specformat = pp.Group( pp.Suppress("[") + pp.OneOrMore(directive | fixed) + pp.Suppress("]")) specoption = pp.Optional(pp.Literal("+").setParseAction(lambda r: True), default=False) specmore = pp.Optional(pp.Suppress("&") + number, default=0) specdecode = speclen + specformat + specoption + specmore