diff options
| -rw-r--r-- | example/disasm/callback.py | 3 | ||||
| -rw-r--r-- | example/ida/ctype_propagation.py | 1 | ||||
| -rw-r--r-- | miasm2/analysis/dse.py | 1 | ||||
| -rw-r--r-- | miasm2/arch/aarch64/arch.py | 229 | ||||
| -rw-r--r-- | miasm2/core/asmblock.py | 37 | ||||
| -rw-r--r-- | miasm2/ir/translators/C.py | 8 | ||||
| -rw-r--r-- | miasm2/jitter/Jittcc.c | 6 | ||||
| -rw-r--r-- | miasm2/jitter/jitcore.py | 2 | ||||
| -rw-r--r-- | miasm2/jitter/vm_mngr.c | 77 | ||||
| -rw-r--r-- | miasm2/jitter/vm_mngr.h | 48 | ||||
| -rw-r--r-- | test/arch/aarch64/arch.py | 4 | ||||
| -rw-r--r-- | test/core/asmblock.py | 10 |
12 files changed, 276 insertions, 150 deletions
diff --git a/example/disasm/callback.py b/example/disasm/callback.py index 5aae7f6f..63987e85 100644 --- a/example/disasm/callback.py +++ b/example/disasm/callback.py @@ -54,9 +54,6 @@ cb_x86_funcs.append(cb_x86_callpop) ## Other method: ## mdis.dis_bloc_callback = cb_x86_callpop -# Clean disassembly cache -mdis.job_done.clear() - print "=" * 40 print "With callback:\n" blocks_after = mdis.dis_multiblock(0) diff --git a/example/ida/ctype_propagation.py b/example/ida/ctype_propagation.py index a48179e9..cb342213 100644 --- a/example/ida/ctype_propagation.py +++ b/example/ida/ctype_propagation.py @@ -57,7 +57,6 @@ Dependency Graph Settings def get_block(ir_arch, mdis, addr): """Get IRBlock at address @addr""" - mdis.job_done.clear() lbl = ir_arch.get_label(addr) if not lbl in ir_arch.blocks: block = mdis.dis_block(lbl.offset) diff --git a/miasm2/analysis/dse.py b/miasm2/analysis/dse.py index 41872f5f..74cc87e9 100644 --- a/miasm2/analysis/dse.py +++ b/miasm2/analysis/dse.py @@ -297,7 +297,6 @@ class DSEEngine(object): else: ## Reset cache structures - self.mdis.job_done.clear() self.ir_arch.blocks.clear()# = {} ## Update current state diff --git a/miasm2/arch/aarch64/arch.py b/miasm2/arch/aarch64/arch.py index 7c8f22ef..09af57b1 100644 --- a/miasm2/arch/aarch64/arch.py +++ b/miasm2/arch/aarch64/arch.py @@ -1066,21 +1066,204 @@ class aarch64_gpreg_sftimm(reg_noarg, m_arg): def ror(value, amount, size): - return (value >> amount) | (value << (size - amount)) + mask = (1 << size) - 1 + return ((value >> amount) | (value << (size - amount))) & mask def rol(value, amount, size): - return (value << amount) | (value >> (size - amount)) + mask = (1 << size) - 1 + return ((value << amount) | (value >> (size - amount)) & mask) -UINTS = {32: uint32, 64: uint64} +# This implementation is inspired from ARM ISA v8.2 +# Exact Reference name: +# "ARM Architecture Reference Manual ARMv8, for ARMv8-A architecture profile" +class ReservedValue(Exception): + """Reserved Value, should not happen""" + pass + +class NotEncodable(Exception): + """Instruction is not encodable""" + pass + +class bits(object): + """Stand for ARM ASL 'bits' type, ie. a bit vector""" + + __slots__ = ["size", "value"] + + def __init__(self, size, value): + """Instanciate a bitvector of size @size with value @value""" + self.size = size + if value & self.mask != value: + raise ValueError("Value %s is too large for %d bits", + hex(value), size) + self.value = value -def imm_to_imm_rot_form(value, size): - for i in xrange(0, size): - mod_value = int(rol(value, i, size)) - if (mod_value + 1) & mod_value == 0: + def concat_left(self, other_bits): + """Return a new bits instance for @other_bits . self""" + return bits(self.size + other_bits.size, + self.value | (other_bits.value << self.size)) + + @property + def mask(self): + return (1 << self.size) - 1 + + def __invert__(self): + return bits(self.size, self.value ^ self.mask) + + def __int__(self): + return self.value + + def __and__(self, other_bits): + assert other_bits.size == self.size + return bits(self.size, self.value & other_bits.value) + + def __eq__(self, other_bits): + return all((self.size == other_bits.size, + self.value == other_bits.value)) + + def __getitem__(self, info): + if isinstance(info, slice): + start = info.start if info.start else 0 + stop = info.stop if info.stop else self.value + if info.step is not None: + raise RuntimeError("Not implemented") + mask = (1 << stop) - 1 + return bits(stop - start, + (self.value >> start) & mask) + else: + raise RuntimeError("Not implemented") + + @property + def pop_count(self): + "Population count: number of bit set" + count = 0 + value = self.value + while (value > 0): + if value & 1 == 1: + count += 1 + value >>= 1 + return count + + def __str__(self): + return "'%s'" % "".join('1' if self.value & (1 << i) else '0' + for i in reversed(xrange(self.size))) + +# From J1-6035 +def HighestSetBit(x): + for i in reversed(xrange(x.size)): + if x.value & (1 << i): return i - return None + return - 1 + +# From J1-6037 +def Ones(N): + return bits(N, (1 << N) - 1) + +# From J1-6038 +def ROR(x, shift): + if shift == 0: + return x + return bits(x.size, ror(UInt(x), shift, x.size)) + +# From J1-6038 +def Replicate(x, N): + assert N % x.size == 0 + new = x + while new.size < N: + new = new.concat_left(x) + return new + +# From J1-6039 +def UInt(x): + return int(x) + +# From J1-6039 +def ZeroExtend(x, N): + assert N >= x.size + return bits(N, x.value) + +# From J1-5906 +def DecodeBitMasks(M, immN, imms, immr, immediate): + """ + @M: 32 or 64 + @immN: 1-bit + @imms: 6-bit + @immr: 6-bit + @immediate: boolean + """ + len_ = HighestSetBit((~imms).concat_left(immN)) + if len_ < 1: + raise ReservedValue() + assert M >= (1 << len_) + + levels = ZeroExtend(Ones(len_), 6) + + if immediate and (imms & levels) == levels: + raise ReservedValue() + S = UInt(imms & levels); + R = UInt(immr & levels); + + esize = 1 << len_ + welem = ZeroExtend(Ones(S + 1), esize) + wmask = Replicate(ROR(welem, R), M) + + # For now, 'tmask' is unused: + # + # diff = S - R; + # d = UInt(bits(len_, diff)) + # telem = ZeroExtend(Ones(d + 1), esize) + # tmask = Replicate(telem, M) + + return wmask, None + +# EncodeBitMasks doesn't have any equivalent in ARM ASL shared functions +# This implementation "reverses" DecodeBitMasks flow +def EncodeBitMasks(wmask): + # Find replicate + M = wmask.size + for i in xrange(1, M + 1): + if M % i != 0: + continue + if wmask == Replicate(wmask[:i], M): + break + else: + raise NotEncodable + + # Find ROR value: welem is only '1's + welem_after_ror = wmask[:i] + esize = welem_after_ror.size + S = welem_after_ror.pop_count - 1 + welem = ZeroExtend(Ones(S + 1), esize) + for i in xrange(welem_after_ror.size): + if ROR(welem, i) == welem_after_ror: + break + else: + raise NotEncodable + R = i + + # Find len value + for i in xrange(M): + if (1 << i) == esize: + break + else: + raise NotEncodable + len_ = i + levels = ZeroExtend(Ones(len_), 6) + levels = UInt(levels) + + if len_ == 6: + # N = 1 + immn = 1 + imms = S + else: + # N = 0, NOT(imms) have to be considered + immn = 0 + mask = (1 << ((6 - len_ - 1))) - 1 + mask <<= (len_ + 1) + imms = S | mask + immr = R + return immr, imms, immn class aarch64_imm_nsr(aarch64_imm_sf, m_arg): @@ -1088,9 +1271,14 @@ class aarch64_imm_nsr(aarch64_imm_sf, m_arg): def decode(self, v): size = 64 if self.parent.sf.value else 32 - mask = UINTS[size]((1 << (v + 1)) - 1) - mask = ror(mask, self.parent.immr.value, size) - self.expr = m2_expr.ExprInt(mask, size) + bitmask, _ = DecodeBitMasks(size, + bits(1, self.parent.immn.value), + bits(6, v), + bits(6, self.parent.immr.value), + True + ) + self.expr = m2_expr.ExprInt(UInt(bitmask), + size) return True def encode(self): @@ -1102,20 +1290,13 @@ class aarch64_imm_nsr(aarch64_imm_sf, m_arg): if value == 0: return False - index = imm_to_imm_rot_form(value, self.expr.size) - if index == None: - return False - power = int(rol(value, index, self.expr.size)) + 1 - length = None - for i in xrange(self.expr.size): - if 1 << i == power: - length = i - break - if length is None: + try: + immr, imms, immn = EncodeBitMasks(bits(self.expr.size, value)) + except NotEncodable: return False - self.parent.immr.value = index - self.value = length - 1 - self.parent.immn.value = 1 if self.expr.size == 64 else 0 + self.parent.immr.value = immr + self.parent.immn.value = immn + self.value = imms return True diff --git a/miasm2/core/asmblock.py b/miasm2/core/asmblock.py index 6cbe37a4..5b95976f 100644 --- a/miasm2/core/asmblock.py +++ b/miasm2/core/asmblock.py @@ -1351,12 +1351,6 @@ class disasmEngine(object): + callback(arch, attrib, pool_bin, cur_bloc, offsets_to_dis, symbol_pool) - dis_bloc_callback: callback after each new disassembled block - - The engine also tracks already handled block, for performance and to avoid - infinite cycling. - Addresses of disassembled block is in the attribute `job_done`. - To force a new disassembly, the targeted offset must first be removed from - this structure. """ def __init__(self, arch, attrib, bin_stream, **kwargs): @@ -1370,7 +1364,6 @@ class disasmEngine(object): self.attrib = attrib self.bin_stream = bin_stream self.symbol_pool = AsmSymbolPool() - self.job_done = set() # Setup options self.dont_dis = [] @@ -1386,11 +1379,26 @@ class disasmEngine(object): # Override options if needed self.__dict__.update(kwargs) - def _dis_block(self, offset): + def get_job_done(self): + warnings.warn("""DEPRECATION WARNING: "job_done" is not needed anymore, support is dropped.""") + return set() + + def set_job_done(self, _): + warnings.warn("""DEPRECATION WARNING: "job_done" is not needed anymore, support is dropped.""") + return + + + # Deprecated + job_done = property(get_job_done, set_job_done) + + def _dis_block(self, offset, job_done=None): """Disassemble the block at offset @offset + @job_done: a set of already disassembled addresses Return the created AsmBlock and future offsets to disassemble """ + if job_done is None: + job_done = set() lines_cpt = 0 in_delayslot = False delayslot_count = self.arch.delayslot @@ -1405,7 +1413,7 @@ class disasmEngine(object): if offset in self.dont_dis: if not cur_block.lines: - self.job_done.add(offset) + job_done.add(offset) # Block is empty -> bad block cur_block = AsmBlockBad(label, errno=2) else: @@ -1426,7 +1434,7 @@ class disasmEngine(object): log_asmblock.debug("lines watchdog reached at %X", int(offset)) break - if offset in self.job_done: + if offset in job_done: cur_block.add_cst(offset, AsmConstraint.c_next, self.symbol_pool) break @@ -1441,7 +1449,7 @@ class disasmEngine(object): if instr is None: log_asmblock.warning("cannot disasm at %X", int(off_i)) if not cur_block.lines: - self.job_done.add(offset) + job_done.add(offset) # Block is empty -> bad block cur_block = AsmBlockBad(label, errno=0) else: @@ -1469,7 +1477,7 @@ class disasmEngine(object): add_next_offset = True break - self.job_done.add(offset) + job_done.add(offset) log_asmblock.debug("dis at %X", int(offset)) offset += instr.l @@ -1544,6 +1552,7 @@ class disasmEngine(object): merge with """ log_asmblock.info("dis bloc all") + job_done = set() if blocks is None: blocks = AsmCFG() todo = [offset] @@ -1557,9 +1566,9 @@ class disasmEngine(object): target_offset = int(todo.pop(0)) if (target_offset is None or - target_offset in self.job_done): + target_offset in job_done): continue - cur_block, nexts = self._dis_block(target_offset) + cur_block, nexts = self._dis_block(target_offset, job_done) todo += nexts blocks.add_node(cur_block) diff --git a/miasm2/ir/translators/C.py b/miasm2/ir/translators/C.py index 1dfdbb00..7a3080ca 100644 --- a/miasm2/ir/translators/C.py +++ b/miasm2/ir/translators/C.py @@ -76,10 +76,10 @@ class TranslatorC(Translator): self.from_expr(expr.args[0]), size2mask(expr.args[0].size), self.from_expr(expr.args[1]), size2mask(expr.args[1].size)) elif expr.op in self.dct_shift: - return 'shift_%s_%.2d(%s , %s)' % (self.dct_shift[expr.op], - expr.args[0].size, - self.from_expr(expr.args[0]), - self.from_expr(expr.args[1])) + return 'SHIFT_%s(%d, %s, %s)' % (self.dct_shift[expr.op].upper(), + expr.args[0].size, + self.from_expr(expr.args[0]), + self.from_expr(expr.args[1])) elif expr.is_associative() or expr.op in ["%", "/"]: oper = ['(%s&0x%x)' % (self.from_expr(arg), size2mask(arg.size)) for arg in expr.args] diff --git a/miasm2/jitter/Jittcc.c b/miasm2/jitter/Jittcc.c index 2a85375d..955491ad 100644 --- a/miasm2/jitter/Jittcc.c +++ b/miasm2/jitter/Jittcc.c @@ -88,8 +88,7 @@ PyObject* tcc_set_emul_lib_path(PyObject* self, PyObject* args) include_array_count ++; include_array = realloc(include_array, include_array_count * sizeof(char*)); - if (include_array == NULL) - { + if (include_array == NULL) { fprintf(stderr, "cannot realloc char* include_array\n"); exit(EXIT_FAILURE); } @@ -107,8 +106,7 @@ PyObject* tcc_set_emul_lib_path(PyObject* self, PyObject* args) lib_array_count ++; lib_array = realloc(lib_array, lib_array_count * sizeof(char*)); - if (lib_array == NULL) - { + if (lib_array == NULL) { fprintf(stderr, "cannot realloc char* lib_array\n"); exit(EXIT_FAILURE); } diff --git a/miasm2/jitter/jitcore.py b/miasm2/jitter/jitcore.py index 741760cd..9c35f829 100644 --- a/miasm2/jitter/jitcore.py +++ b/miasm2/jitter/jitcore.py @@ -47,7 +47,6 @@ class JitCore(object): self.log_regs = False self.log_newbloc = False self.segm_to_do = set() - self.job_done = set() self.jitcount = 0 self.addr2obj = {} self.addr2objref = {} @@ -140,7 +139,6 @@ class JitCore(object): addr = addr.offset # Prepare disassembler - self.mdis.job_done.clear() self.mdis.lines_wd = self.options["jit_maxline"] self.mdis.dis_bloc_callback = self.disasm_cb diff --git a/miasm2/jitter/vm_mngr.c b/miasm2/jitter/vm_mngr.c index 1114185b..59cbdf6e 100644 --- a/miasm2/jitter/vm_mngr.c +++ b/miasm2/jitter/vm_mngr.c @@ -103,6 +103,10 @@ void memory_access_list_add(struct memory_access_list * access, uint64_t start, else access->allocated *= 2; access->array = realloc(access->array, access->allocated * sizeof(struct memory_access)); + if (access->array == NULL) { + fprintf(stderr, "cannot realloc struct memory_access access->array\n"); + exit(EXIT_FAILURE); + } } access->array[access->num].start = start; access->array[access->num].stop = stop; @@ -669,66 +673,6 @@ int is_mapped(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size) return 1; } -int shift_right_arith(unsigned int size, int a, unsigned int b) -{ - int i32_a; - short i16_a; - char i8_a; - switch(size){ - case 8: - i8_a = a; - return (i8_a >> b)&0xff; - case 16: - i16_a = a; - return (i16_a >> b)&0xffff; - case 32: - i32_a = a; - return (i32_a >> b)&0xffffffff; - default: - fprintf(stderr, "inv size in shift %d\n", size); - exit(0); - } -} - -uint64_t shift_right_logic(uint64_t size, - uint64_t a, uint64_t b) -{ - uint64_t u32_a; - unsigned short u16_a; - unsigned char u8_a; - switch(size){ - case 8: - u8_a = a; - return (u8_a >> b)&0xff; - case 16: - u16_a = a; - return (u16_a >> b)&0xffff; - case 32: - u32_a = a; - return (u32_a >> b)&0xffffffff; - default: - fprintf(stderr, "inv size in shift %"PRIx64"\n", size); - exit(0); - } -} - -uint64_t shift_left_logic(uint64_t size, uint64_t a, uint64_t b) -{ - switch(size){ - case 8: - return (a<<b)&0xff; - case 16: - return (a<<b)&0xffff; - case 32: - return (a<<b)&0xffffffff; - case 64: - return (a<<b)&0xffffffffffffffff; - default: - fprintf(stderr, "inv size in shift %"PRIx64"\n", size); - exit(0); - } -} - unsigned int mul_lo_op(unsigned int size, unsigned int a, unsigned int b) { unsigned int mask; @@ -1602,6 +1546,11 @@ void add_memory_page(vm_mngr_t* vm_mngr, struct memory_page_node* mpn_a) vm_mngr->memory_pages_array = realloc(vm_mngr->memory_pages_array, sizeof(struct memory_page_node) * (vm_mngr->memory_pages_number+1)); + if (vm_mngr->memory_pages_array == NULL) { + fprintf(stderr, "cannot realloc struct memory_page_node vm_mngr->memory_pages_array\n"); + exit(EXIT_FAILURE); + } + memmove(&vm_mngr->memory_pages_array[i+1], &vm_mngr->memory_pages_array[i], @@ -1629,8 +1578,8 @@ char* dump(vm_mngr_t* vm_mngr) buf_final = malloc(total_len); if (buf_final == NULL) { - fprintf(stderr, "Error: cannot alloc\n"); - exit(0); + fprintf(stderr, "Error: cannot alloc char* buf_final\n"); + exit(EXIT_FAILURE); } strcpy(buf_final, intro); for (i=0; i< vm_mngr->memory_pages_number; i++) { @@ -1653,8 +1602,8 @@ char* dump(vm_mngr_t* vm_mngr) total_len += length + 1 + 1; buf_final = realloc(buf_final, total_len); if (buf_final == NULL) { - fprintf(stderr, "Error: cannot alloc\n"); - exit(0); + fprintf(stderr, "cannot realloc char* buf_final\n"); + exit(EXIT_FAILURE); } strcat(buf_final, buf); } diff --git a/miasm2/jitter/vm_mngr.h b/miasm2/jitter/vm_mngr.h index 74ad49ad..757c3b3e 100644 --- a/miasm2/jitter/vm_mngr.h +++ b/miasm2/jitter/vm_mngr.h @@ -199,10 +199,7 @@ unsigned int my_imul08(unsigned int a, unsigned int b); int is_mapped(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size); void vm_throw(vm_mngr_t* vm_mngr, unsigned long flags); -int shift_right_arith(unsigned int size, int a, unsigned int b); -uint64_t shift_right_logic(uint64_t size, uint64_t a, uint64_t b); -uint64_t shift_left_logic(uint64_t size, uint64_t a, uint64_t b); unsigned int mul_lo_op(unsigned int size, unsigned int a, unsigned int b); unsigned int mul_hi_op(unsigned int size, unsigned int a, unsigned int b); unsigned int imul_lo_op_08(char a, char b); @@ -402,32 +399,23 @@ unsigned int load_segment_limit(unsigned int d); unsigned int load_segment_limit_ok(unsigned int d); unsigned int load_tr_segment_selector(unsigned int d); -#define shift_right_arith_08(a, b)\ - ((((char)(a)) >> ((int)(b)&0x1f))&0xff) -#define shift_right_arith_16(a, b)\ - ((((short)(a)) >> ((int)(b)&0x1f))&0xffff) -#define shift_right_arith_32(a, b)\ - ((((int)(a)) >> ((int)(b)&0x1f))&0xffffffff) -#define shift_right_arith_64(a, b)\ - ((((int64_t)(a)) >> ((int64_t)(b)&0x3f))&0xffffffffffffffff) - - -#define shift_right_logic_08(a, b)\ - ((((unsigned char)(a)) >> ((unsigned int)(b)&0x1f))&0xff) -#define shift_right_logic_16(a, b)\ - ((((unsigned short)(a)) >> ((unsigned int)(b)&0x1f))&0xffff) -#define shift_right_logic_32(a, b)\ - ((((unsigned int)(a)) >> ((unsigned int)(b)&0x1f))&0xffffffff) -#define shift_right_logic_64(a, b)\ - ((((uint64_t)(a)) >> ((uint64_t)(b)&0x3f))&0xffffffffffffffff) - -#define shift_left_logic_08(a, b)\ - (((a)<<((b)&0x1f))&0xff) -#define shift_left_logic_16(a, b)\ - (((a)<<((b)&0x1f))&0xffff) -#define shift_left_logic_32(a, b)\ - (((a)<<((b)&0x1f))&0xffffffff) -#define shift_left_logic_64(a, b)\ - (((a)<<((b)&0x3f))&0xffffffffffffffff) + + +#define SHIFT_RIGHT_ARITH(size, value, shift) \ + ((uint ## size ## _t)((((uint64_t) (shift)) > ((size) - 1))? \ + (((int ## size ## _t) (value)) < 0 ? -1 : 0) : \ + (((int ## size ## _t) (value)) >> (shift)))) + +#define SHIFT_RIGHT_LOGIC(size, value, shift) \ + ((uint ## size ## _t)((((uint64_t) (shift)) > ((size) - 1))? \ + 0 : \ + (((uint ## size ## _t) (value)) >> (shift)))) + +#define SHIFT_LEFT_LOGIC(size, value, shift) \ + ((uint ## size ## _t)((((uint64_t) (shift)) > ((size) - 1))? \ + 0 : \ + (((uint ## size ## _t) (value)) << (shift)))) + + #endif diff --git a/test/arch/aarch64/arch.py b/test/arch/aarch64/arch.py index ec978024..8364fcf1 100644 --- a/test/arch/aarch64/arch.py +++ b/test/arch/aarch64/arch.py @@ -1786,6 +1786,10 @@ reg_tests_aarch64 = [ "E003809A"), ("XXXXXXXX ADD X0, SP, XZR UXTX 0x0", "E0633F8B"), + + ("XXXXXXXX ORR X8, 0x0, 0x1000100010001", + "E88300B2"), + ] diff --git a/test/core/asmblock.py b/test/core/asmblock.py index c3b220df..eb7b54b2 100644 --- a/test/core/asmblock.py +++ b/test/core/asmblock.py @@ -19,12 +19,16 @@ first_block = mdis.dis_block(0) assert len(first_block.lines) == 5 print first_block +## Test redisassemble blocks +first_block_bis = mdis.dis_block(0) +assert len(first_block.lines) == len(first_block_bis.lines) +print first_block_bis + ## Disassembly of several block, with cache blocks = mdis.dis_multiblock(0) -assert len(blocks) == 0 +assert len(blocks) == 17 -## Test cache -mdis.job_done.clear() +## Test redisassemble blocks blocks = mdis.dis_multiblock(0) assert len(blocks) == 17 ## Equality between assembly lines is not yet implemented |