diff options
29 files changed, 1188 insertions, 42 deletions
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 327b2426..49926aed 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['2.7', '3.6'] + python-version: ['2.7', '3.6', '3.8'] steps: @@ -19,6 +19,9 @@ jobs: with: python-version: ${{ matrix.python-version }} + - name: Update pip + run: pip install pip --upgrade + - name: Install requirements run: pip install -r requirements.txt @@ -90,6 +93,11 @@ jobs: MIASM_TEST_EXTRA_ARG: -o cparser - name: Loader tests + run: cd example/loader; python --version |& grep -q "Python 3" || flags="-W error"; for i in ../../miasm-extended-tests/loader/dll_win_xp/*.dll; do python get_exports.py $i; done + env: + MIASM_EXTENTED_TESTS_LOADER: loader + + - name: Loader tests run: cd "miasm-extended-tests/$MIASM_EXTENTED_TESTS_LOADER" && ./test_dll.py env: MIASM_EXTENTED_TESTS_LOADER: loader diff --git a/example/expression/interfer.py b/example/expression/interfer.py new file mode 100644 index 00000000..5055e1f6 --- /dev/null +++ b/example/expression/interfer.py @@ -0,0 +1,111 @@ +from miasm.analysis.data_flow import State +from miasm.expression.expression import * + +""" +Test memory interferences +""" + +a32 = ExprId('a', 32) +b32 = ExprId('b', 32) + +a64 = ExprId('a', 64) +b64 = ExprId('b', 64) + +mem_a32_32 = ExprMem(a32, 32) +mem_b32_32 = ExprMem(b32, 32) + +mem_a64_32 = ExprMem(a64, 32) + +mem_a32_m1_8 = ExprMem(a32 + ExprInt(-1, 32), 8) +mem_a32_p0_8 = ExprMem(a32, 8) +mem_a32_p1_8 = ExprMem(a32 + ExprInt(1, 32), 8) +mem_a32_p2_8 = ExprMem(a32 + ExprInt(2, 32), 8) +mem_a32_p3_8 = ExprMem(a32 + ExprInt(3, 32), 8) +mem_a32_p4_8 = ExprMem(a32 + ExprInt(4, 32), 8) + + +mem_a32_m4_32 = ExprMem(a32 + ExprInt(-4, 32), 32) +mem_a32_m3_32 = ExprMem(a32 + ExprInt(-3, 32), 32) +mem_a32_m2_32 = ExprMem(a32 + ExprInt(-2, 32), 32) +mem_a32_m1_32 = ExprMem(a32 + ExprInt(-1, 32), 32) +mem_a32_p0_32 = ExprMem(a32, 32) +mem_a32_p1_32 = ExprMem(a32 + ExprInt(1, 32), 32) +mem_a32_p2_32 = ExprMem(a32 + ExprInt(2, 32), 32) +mem_a32_p3_32 = ExprMem(a32 + ExprInt(3, 32), 32) +mem_a32_p4_32 = ExprMem(a32 + ExprInt(4, 32), 32) + + +mem_a64_m4_32 = ExprMem(a64 + ExprInt(-4, 64), 32) +mem_a64_m3_32 = ExprMem(a64 + ExprInt(-3, 64), 32) +mem_a64_m2_32 = ExprMem(a64 + ExprInt(-2, 64), 32) +mem_a64_m1_32 = ExprMem(a64 + ExprInt(-1, 64), 32) +mem_a64_p0_32 = ExprMem(a64, 32) +mem_a64_p1_32 = ExprMem(a64 + ExprInt(1, 64), 32) +mem_a64_p2_32 = ExprMem(a64 + ExprInt(2, 64), 32) +mem_a64_p3_32 = ExprMem(a64 + ExprInt(3, 64), 32) +mem_a64_p4_32 = ExprMem(a64 + ExprInt(4, 64), 32) + + +state = State() + + +assert state.may_interfer(set([mem_a32_32]), mem_b32_32) == True +assert state.may_interfer(set([mem_b32_32]), mem_a32_32) == True + +# Test 8 bit accesses +assert state.may_interfer(set([mem_a32_m1_8]), mem_a32_32) == False +assert state.may_interfer(set([mem_a32_p0_8]), mem_a32_32) == True +assert state.may_interfer(set([mem_a32_p1_8]), mem_a32_32) == True +assert state.may_interfer(set([mem_a32_p2_8]), mem_a32_32) == True +assert state.may_interfer(set([mem_a32_p3_8]), mem_a32_32) == True +assert state.may_interfer(set([mem_a32_p4_8]), mem_a32_32) == False + +assert state.may_interfer(set([mem_a32_32]), mem_a32_m1_8) == False +assert state.may_interfer(set([mem_a32_32]), mem_a32_p0_8) == True +assert state.may_interfer(set([mem_a32_32]), mem_a32_p1_8) == True +assert state.may_interfer(set([mem_a32_32]), mem_a32_p2_8) == True +assert state.may_interfer(set([mem_a32_32]), mem_a32_p3_8) == True +assert state.may_interfer(set([mem_a32_32]), mem_a32_p4_8) == False + + +# Test 32 bit accesses +assert state.may_interfer(set([mem_a32_m4_32]), mem_a32_32) == False +assert state.may_interfer(set([mem_a32_m3_32]), mem_a32_32) == True +assert state.may_interfer(set([mem_a32_m2_32]), mem_a32_32) == True +assert state.may_interfer(set([mem_a32_m1_32]), mem_a32_32) == True +assert state.may_interfer(set([mem_a32_p0_32]), mem_a32_32) == True +assert state.may_interfer(set([mem_a32_p1_32]), mem_a32_32) == True +assert state.may_interfer(set([mem_a32_p2_32]), mem_a32_32) == True +assert state.may_interfer(set([mem_a32_p3_32]), mem_a32_32) == True +assert state.may_interfer(set([mem_a32_p4_32]), mem_a32_32) == False + +assert state.may_interfer(set([mem_a32_32]), mem_a32_m4_32) == False +assert state.may_interfer(set([mem_a32_32]), mem_a32_m3_32) == True +assert state.may_interfer(set([mem_a32_32]), mem_a32_m2_32) == True +assert state.may_interfer(set([mem_a32_32]), mem_a32_m1_32) == True +assert state.may_interfer(set([mem_a32_32]), mem_a32_p0_32) == True +assert state.may_interfer(set([mem_a32_32]), mem_a32_p1_32) == True +assert state.may_interfer(set([mem_a32_32]), mem_a32_p2_32) == True +assert state.may_interfer(set([mem_a32_32]), mem_a32_p3_32) == True +assert state.may_interfer(set([mem_a32_32]), mem_a32_p4_32) == False + +# Test 32 bit accesses with 64 bit memory address +assert state.may_interfer(set([mem_a64_m4_32]), mem_a64_32) == False +assert state.may_interfer(set([mem_a64_m3_32]), mem_a64_32) == True +assert state.may_interfer(set([mem_a64_m2_32]), mem_a64_32) == True +assert state.may_interfer(set([mem_a64_m1_32]), mem_a64_32) == True +assert state.may_interfer(set([mem_a64_p0_32]), mem_a64_32) == True +assert state.may_interfer(set([mem_a64_p1_32]), mem_a64_32) == True +assert state.may_interfer(set([mem_a64_p2_32]), mem_a64_32) == True +assert state.may_interfer(set([mem_a64_p3_32]), mem_a64_32) == True +assert state.may_interfer(set([mem_a64_p4_32]), mem_a64_32) == False + +assert state.may_interfer(set([mem_a64_32]), mem_a64_m4_32) == False +assert state.may_interfer(set([mem_a64_32]), mem_a64_m3_32) == True +assert state.may_interfer(set([mem_a64_32]), mem_a64_m2_32) == True +assert state.may_interfer(set([mem_a64_32]), mem_a64_m1_32) == True +assert state.may_interfer(set([mem_a64_32]), mem_a64_p0_32) == True +assert state.may_interfer(set([mem_a64_32]), mem_a64_p1_32) == True +assert state.may_interfer(set([mem_a64_32]), mem_a64_p2_32) == True +assert state.may_interfer(set([mem_a64_32]), mem_a64_p3_32) == True +assert state.may_interfer(set([mem_a64_32]), mem_a64_p4_32) == False diff --git a/miasm/analysis/data_flow.py b/miasm/analysis/data_flow.py index 9274d9d6..06453264 100644 --- a/miasm/analysis/data_flow.py +++ b/miasm/analysis/data_flow.py @@ -1921,29 +1921,29 @@ class State(object): if dst in src: return True if dst.is_mem() and src.is_mem(): - base1, offset1 = get_expr_base_offset(dst.ptr) - base2, offset2 = get_expr_base_offset(src.ptr) - if base1 != base2: + dst_base, dst_offset = get_expr_base_offset(dst.ptr) + src_base, src_offset = get_expr_base_offset(src.ptr) + if dst_base != src_base: return True - size1 = dst.size // 8 - size2 = src.size // 8 + dst_size = dst.size // 8 + src_size = src.size // 8 # Special case: # @32[ESP + 0xFFFFFFFE], @32[ESP] # Both memories alias - if offset1 + size1 <= int(base1.mask) + 1: + if dst_offset + dst_size <= int(dst_base.mask) + 1: # @32[ESP + 0xFFFFFFFC] => [0xFFFFFFFC, 0xFFFFFFFF] - interval1 = interval([(offset1, offset1 + dst.size // 8 - 1)]) + interval1 = interval([(dst_offset, dst_offset + dst.size // 8 - 1)]) else: # @32[ESP + 0xFFFFFFFE] => [0x0, 0x1] U [0xFFFFFFFE, 0xFFFFFFFF] - interval1 = interval([(offset1, int(base1.mask))]) - interval1 += interval([(0, size1 - (int(base1.mask) + 1 - offset1) - 1 )]) - if offset2 + size2 <= int(base2.mask) + 1: + interval1 = interval([(dst_offset, int(dst_base.mask))]) + interval1 += interval([(0, dst_size - (int(dst_base.mask) + 1 - dst_offset) - 1 )]) + if src_offset + src_size <= int(src_base.mask) + 1: # @32[ESP + 0xFFFFFFFC] => [0xFFFFFFFC, 0xFFFFFFFF] - interval2 = interval([(offset2, offset2 + src.size // 8 - 1)]) + interval2 = interval([(src_offset, src_offset + src.size // 8 - 1)]) else: # @32[ESP + 0xFFFFFFFE] => [0x0, 0x1] U [0xFFFFFFFE, 0xFFFFFFFF] - interval2 = interval([(offset2, int(base2.mask))]) - interval2 += interval([(0, size2 - (int(base2.mask) + 1 - offset2) - 1)]) + interval2 = interval([(src_offset, int(src_base.mask))]) + interval2 += interval([(0, src_size - (int(src_base.mask) + 1 - src_offset) - 1)]) if (interval1 & interval2).empty: continue return True diff --git a/miasm/arch/aarch64/arch.py b/miasm/arch/aarch64/arch.py index f4882845..f05a0a15 100644 --- a/miasm/arch/aarch64/arch.py +++ b/miasm/arch/aarch64/arch.py @@ -14,6 +14,8 @@ from miasm.arch.aarch64.regs import * from miasm.core.cpu import log as log_cpu from miasm.core.modint import mod_size2int from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp +from miasm.ir.ir import color_expr_html +from miasm.core import utils log = logging.getLogger("aarch64dis") console_handler = logging.StreamHandler() @@ -367,6 +369,73 @@ class instruction_aarch64(instruction): else: raise NotImplementedError("bad op") + @staticmethod + def arg2html(expr, index=None, loc_db=None): + wb = False + if expr.is_id() or expr.is_int() or expr.is_loc(): + return color_expr_html(expr, loc_db) + elif isinstance(expr, m2_expr.ExprOp) and expr.op in shift_expr: + op_str = shift_str[shift_expr.index(expr.op)] + return "%s %s %s" % ( + color_expr_html(expr.args[0], loc_db), + utils.set_html_text_color(op_str, utils.COLOR_OP), + color_expr_html(expr.args[1], loc_db) + ) + elif isinstance(expr, m2_expr.ExprOp) and expr.op == "slice_at": + return "%s LSL %s" % ( + color_expr_html(expr.args[0], loc_db), + color_expr_html(expr.args[1], loc_db) + ) + elif isinstance(expr, m2_expr.ExprOp) and expr.op in extend_lst: + op_str = expr.op + return "%s %s %s" % ( + color_expr_html(expr.args[0], loc_db), + op_str, + color_expr_html(expr.args[1], loc_db) + ) + elif isinstance(expr, m2_expr.ExprOp) and expr.op == "postinc": + if int(expr.args[1]) != 0: + return "[%s], %s" % ( + color_expr_html(expr.args[0], loc_db), + color_expr_html(expr.args[1], loc_db) + ) + else: + return "[%s]" % (color_expr_html(expr.args[0], loc_db)) + elif isinstance(expr, m2_expr.ExprOp) and expr.op == "preinc_wb": + if int(expr.args[1]) != 0: + return "[%s, %s]!" % ( + color_expr_html(expr.args[0], loc_db), + color_expr_html(expr.args[1], loc_db) + ) + else: + return "[%s]" % (color_expr_html(expr.args[0], loc_db)) + elif isinstance(expr, m2_expr.ExprOp) and expr.op == "preinc": + if len(expr.args) == 1: + return "[%s]" % (color_expr_html(expr.args[0], loc_db)) + elif not isinstance(expr.args[1], m2_expr.ExprInt) or int(expr.args[1]) != 0: + return "[%s, %s]" % ( + color_expr_html(expr.args[0], loc_db), + color_expr_html(expr.args[1], loc_db) + ) + else: + return "[%s]" % color_expr_html(expr.args[0], loc_db) + elif isinstance(expr, m2_expr.ExprOp) and expr.op == 'segm': + arg = expr.args[1] + if isinstance(arg, m2_expr.ExprId): + arg = str(arg) + elif arg.op == 'LSL' and int(arg.args[1]) == 0: + arg = str(arg.args[0]) + else: + arg = "%s %s %s" % ( + color_expr_html(arg.args[0], loc_db), + utils.set_html_text_color(arg.op, utils.COLOR_OP), + color_expr_html(arg.args[1], loc_db) + ) + return '[%s, %s]' % (color_expr_html(expr.args[0], loc_db), arg) + + else: + raise NotImplementedError("bad op") + def dstflow(self): return self.name in BRCOND + ["B", "BL", "BR", "BLR"] @@ -2216,12 +2285,15 @@ aarch64op("ldarh",[bs('0'), bs('1'), bs('001000'), bs('0'), bs('1'), bs('0'), bs aarch64op("ldaxp",[bs('1'), sf, bs('001000'), bs('0'), bs('1'), bs('1'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff]) aarch64op("ldaxr",[bs('1'), sf, bs('001000'), bs('0'), bs('1'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff]) +aarch64op("stlr", [bs('1'), sf, bs('001000'), bs('1'), bs('0'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff]) +aarch64op("stlrb",[bs('0'), bs('0'), bs('001000'), bs('1'), bs('0'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff]) +aarch64op("stlrh",[bs('0'), bs('1'), bs('001000'), bs('1'), bs('0'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff]) + aarch64op("stlxr", [bs('1'), sf, bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('1'), bs('11111'), rn64_deref_nooff, rt], [rs32, rt, rn64_deref_nooff]) aarch64op("stlxrb",[bs('0'), bs('0'), bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rs32, rt32, rn64_deref_nooff]) aarch64op("stlxrh",[bs('0'), bs('1'), bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rs32, rt32, rn64_deref_nooff]) aarch64op("stlxp", [bs('1'), sf, bs('001000'), bs('0'), bs('0'), bs('1'), rs32, bs('1'), rt2, rn64_deref_nooff, rt], [rs32, rt, rt2, rn64_deref_nooff]) -aarch64op("stlrb",[bs('0'), bs('0'), bs('001000'), bs('1'), bs('0'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff]) # barriers p.135 aarch64op("dsb", [bs('1101010100'), bs('0000110011'), crm, bs('1'), bs('00'), bs('11111')], [crm]) diff --git a/miasm/arch/arm/arch.py b/miasm/arch/arm/arch.py index 6c5b0ce2..7b07387c 100644 --- a/miasm/arch/arm/arch.py +++ b/miasm/arch/arm/arch.py @@ -12,6 +12,8 @@ from miasm.core.bin_stream import bin_stream import miasm.arch.arm.regs as regs_module from miasm.arch.arm.regs import * from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp +from miasm.ir.ir import color_expr_html +from miasm.core import utils # A1 encoding @@ -426,6 +428,85 @@ class instruction_arm(instruction): o += "!" return o + @staticmethod + def arg2html(expr, index=None, loc_db=None): + wb = False + if expr.is_id() or expr.is_int() or expr.is_loc(): + return color_expr_html(expr, loc_db) + if isinstance(expr, ExprOp) and expr.op in expr2shift_dct: + if len(expr.args) == 1: + return '%s %s' % (color_expr_html(expr.args[0], loc_db), expr2shift_dct[expr.op]) + elif len(expr.args) == 2: + return '%s %s %s' % (color_expr_html(expr.args[0], loc_db), expr2shift_dct[expr.op], expr.args[1]) + else: + raise NotImplementedError('zarb arg2str') + + + sb = False + if isinstance(expr, ExprOp) and expr.op == "sbit": + sb = True + expr = expr.args[0] + if isinstance(expr, ExprOp) and expr.op == "reglist": + o = [gpregs.expr.index(x) for x in expr.args] + out = reglist2html(o) + if sb: + out += "^" + return out + + + if isinstance(expr, ExprOp) and expr.op == 'wback': + wb = True + expr = expr.args[0] + if isinstance(expr, ExprId): + out = color_expr_html(expr, loc_db) + if wb: + out += "!" + return out + + if not isinstance(expr, ExprMem): + return color_expr_html(expr, loc_db) + + expr = expr.ptr + if isinstance(expr, ExprOp) and expr.op == 'wback': + wb = True + expr = expr.args[0] + + + if isinstance(expr, ExprId): + r, s = expr, None + elif len(expr.args) == 1 and isinstance(expr.args[0], ExprId): + r, s = expr.args[0], None + elif isinstance(expr.args[0], ExprId): + r, s = expr.args[0], expr.args[1] + else: + r, s = expr.args[0].args + if isinstance(s, ExprOp) and s.op in expr2shift_dct: + s_html = ' '.join( + str(x) + for x in ( + color_expr_html(s.args[0], loc_db), + utils.set_html_text_color(expr2shift_dct[s.op], utils.COLOR_OP), + color_expr_html(s.args[1], loc_db) + ) + ) + else: + s_html = color_expr_html(s, loc_db) + + if isinstance(expr, ExprOp) and expr.op == 'postinc': + o = '[%s]' % color_expr_html(r, loc_db) + if s and not (isinstance(s, ExprInt) and int(s) == 0): + o += ', %s' % s_html + else: + if s and not (isinstance(s, ExprInt) and int(s) == 0): + o = '[%s, %s]' % (color_expr_html(r, loc_db), s_html) + else: + o = '[%s]' % color_expr_html(r, loc_db) + + + if wb: + o += "!" + return o + def dstflow(self): if self.is_subcall(): @@ -1258,6 +1339,23 @@ def reglist2str(rlist): i = j + 1 return "{" + ", ".join(out) + '}' +def reglist2html(rlist): + out = [] + i = 0 + while i < len(rlist): + j = i + 1 + while j < len(rlist) and rlist[j] < 13 and rlist[j] == rlist[j - 1] + 1: + j += 1 + j -= 1 + if j < i + 2: + out.append(color_expr_html(regs_expr[rlist[i]], None)) + i += 1 + else: + out.append(color_expr_html(regs_expr[rlist[i]], None) + '-' + color_expr_html(regs_expr[rlist[j]], None)) + i = j + 1 + out = utils.fix_html_chars("{") + ", ".join(out) + utils.fix_html_chars("}") + return out + class arm_rlist(arm_arg): parser = gpreg_list diff --git a/miasm/arch/arm/lifter_model_call.py b/miasm/arch/arm/lifter_model_call.py index f9c39ab6..9aac74a4 100644 --- a/miasm/arch/arm/lifter_model_call.py +++ b/miasm/arch/arm/lifter_model_call.py @@ -63,7 +63,7 @@ class LifterModelCallArml(LifterModelCallArmlBase): call_assignblk, AssignBlock([ExprAssign(self.IRDst, loc_next_expr)], instr), ] - e_do = IRBlock(loc_do, call_assignblks) + e_do = IRBlock(self.loc_db, loc_do, call_assignblks) assignblks_out = [ AssignBlock([ExprAssign(self.IRDst, dst_cond)], instr) ] diff --git a/miasm/arch/mep/arch.py b/miasm/arch/mep/arch.py index a6b994ac..67dd5288 100644 --- a/miasm/arch/mep/arch.py +++ b/miasm/arch/mep/arch.py @@ -10,6 +10,7 @@ from miasm.core.asm_ast import AstId, AstMem from miasm.arch.mep.regs import * import miasm.arch.mep.regs as mep_regs_module # will be used to set mn_mep.regs +from miasm.ir.ir import color_expr_html # Note: pyparsing is used to alter the way special operands are parsed @@ -97,6 +98,38 @@ class instruction_mep(instruction): to do with a '%s' instance." % type(expr) raise Disasm_Exception(message) + @staticmethod + def arg2html(expr, pos=None, loc_db=None): + """Convert mnemonics arguments into readable html strings according to the + MeP-c4 architecture manual and their internal types + + Notes: + - it must be implemented ! However, a simple 'return str(expr)' + could do the trick. + - it is used to mimic objdump output + + Args: + expr: argument as a miasm expression + pos: position index in the arguments list + """ + + if isinstance(expr, ExprId) or isinstance(expr, ExprInt) or isinstance(expr, ExprLoc): + return color_expr_html(expr, loc_db) + + elif isinstance(expr, ExprMem) and (isinstance(expr.ptr, ExprId) or isinstance(expr.ptr, ExprInt)): + return "(%s)" % color_expr_html(expr.ptr, loc_db) + + elif isinstance(expr, ExprMem) and isinstance(expr.ptr, ExprOp): + return "%s(%s)" % ( + color_expr_html(expr.ptr.args[1], loc_db), + color_expr_html(expr.ptr.args[0], loc_db) + ) + + # Raise an exception if the expression type was not processed + message = "instruction_mep.arg2str(): don't know what \ + to do with a '%s' instance." % type(expr) + raise Disasm_Exception(message) + def __str__(self): """Return the mnemonic as a string. diff --git a/miasm/arch/mips32/arch.py b/miasm/arch/mips32/arch.py index 803f9eef..3d4aa356 100644 --- a/miasm/arch/mips32/arch.py +++ b/miasm/arch/mips32/arch.py @@ -9,6 +9,7 @@ from miasm.expression.expression import ExprMem, ExprInt, ExprId, ExprOp, ExprLo from miasm.core.bin_stream import bin_stream import miasm.arch.mips32.regs as regs import miasm.core.cpu as cpu +from miasm.ir.ir import color_expr_html from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp @@ -75,6 +76,20 @@ class instruction_mips32(cpu.instruction): assert(len(arg.args) == 2 and arg.op == '+') return "%s(%s)"%(arg.args[1], arg.args[0]) + @staticmethod + def arg2html(expr, index=None, loc_db=None): + if expr.is_id() or expr.is_int() or expr.is_loc(): + return color_expr_html(expr, loc_db) + assert(isinstance(expr, ExprMem)) + arg = expr.ptr + if isinstance(arg, ExprId): + return "(%s)"%color_expr_html(arg, loc_db) + assert(len(arg.args) == 2 and arg.op == '+') + return "%s(%s)"%( + color_expr_html(arg.args[1], loc_db), + color_expr_html(arg.args[0], loc_db) + ) + def dstflow(self): if self.name == 'BREAK': return False diff --git a/miasm/arch/msp430/arch.py b/miasm/arch/msp430/arch.py index 8d208d26..dbe93fd2 100644 --- a/miasm/arch/msp430/arch.py +++ b/miasm/arch/msp430/arch.py @@ -11,6 +11,7 @@ from miasm.core.bin_stream import bin_stream import miasm.arch.msp430.regs as regs_module from miasm.arch.msp430.regs import * from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp +from miasm.ir.ir import color_expr_html log = logging.getLogger("msp430dis") console_handler = logging.StreamHandler() @@ -130,6 +131,29 @@ class instruction_msp430(instruction): raise NotImplementedError('unknown instance expr = %s' % type(expr)) return o + @staticmethod + def arg2html(expr, index=None, loc_db=None): + if isinstance(expr, ExprId) or isinstance(expr, ExprInt) or expr.is_loc(): + return color_expr_html(expr, loc_db) + elif isinstance(expr, ExprOp) and expr.op == "autoinc": + o = "@%s+" % color_expr_html(expr.args[0], loc_db) + elif isinstance(expr, ExprMem): + if isinstance(expr.ptr, ExprId): + if index == 0: + o = "@%s" % color_expr_html(expr.ptr, loc_db) + else: + o = "0x0(%s)" % color_expr_html(expr.ptr, loc_db) + elif isinstance(expr.ptr, ExprInt): + o = "@%s" % color_expr_html(expr.ptr, loc_db) + elif isinstance(expr.ptr, ExprOp): + o = "%s(%s)" % ( + color_expr_html(expr.ptr.args[1], loc_db), + color_expr_html(expr.ptr.args[0], loc_db) + ) + else: + raise NotImplementedError('unknown instance expr = %s' % type(expr)) + return o + def dstflow2label(self, loc_db): expr = self.args[0] diff --git a/miasm/arch/ppc/arch.py b/miasm/arch/ppc/arch.py index 41259180..d4edc58e 100644 --- a/miasm/arch/ppc/arch.py +++ b/miasm/arch/ppc/arch.py @@ -9,6 +9,7 @@ from miasm.core.bin_stream import bin_stream import miasm.arch.ppc.regs as regs_module from miasm.arch.ppc.regs import * from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp +from miasm.ir.ir import color_expr_html log = logging.getLogger("ppcdis") console_handler = logging.StreamHandler() @@ -94,6 +95,28 @@ class instruction_ppc(instruction): return str(e) + + @staticmethod + def arg2html(e, pos = None, loc_db=None): + if isinstance(e, ExprId) or isinstance(e, ExprInt) or isinstance(e, ExprLoc): + return color_expr_html(e, loc_db) + elif isinstance(e, ExprMem): + addr = e.ptr + if isinstance(addr, ExprInt) or isinstance(addr, ExprId): + out = '(%s)'%color_expr_html(addr, loc_db) + elif isinstance(addr, ExprOp): + if len(addr.args) == 1: + out = '(%s)'%color_expr_html(addr, loc_db) + elif len(addr.args) == 2: + out = '%s(%s)'%(color_expr_html(addr.args[1], loc_db), color_expr_html(addr.args[0], loc_db)) + else: + raise NotImplementedError('More than two args to ExprOp of address') + else: + raise NotImplementedError('Invalid memory expression') + return out + + return color_expr_html(e, loc_db) + @staticmethod def is_conditional_jump(s): return (s[0] == 'B' and diff --git a/miasm/arch/x86/arch.py b/miasm/arch/x86/arch.py index a886e799..ae58e69b 100644 --- a/miasm/arch/x86/arch.py +++ b/miasm/arch/x86/arch.py @@ -6,7 +6,7 @@ import re from future.utils import viewitems -from miasm.core.utils import int_to_byte +from miasm.core import utils from miasm.expression.expression import * from pyparsing import * from miasm.core.cpu import * @@ -14,6 +14,7 @@ from collections import defaultdict import miasm.arch.x86.regs as regs_module from miasm.arch.x86.regs import * from miasm.core.asm_ast import AstNode, AstInt, AstId, AstMem, AstOp +from miasm.ir.ir import color_expr_html log = logging.getLogger("x86_arch") @@ -570,6 +571,26 @@ class instruction_x86(instruction): o = "REPE %s" % o return o + def to_html(self, loc_db=None): + o = super(instruction_x86, self).to_html(loc_db) + if self.additional_info.g1.value & 1: + text = utils.set_html_text_color("LOCK", utils.COLOR_MNEMO) + o = "%s %s" % (text, o) + if self.additional_info.g1.value & 2: + if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF2": + text = utils.set_html_text_color("REPNE", utils.COLOR_MNEMO) + o = "%s %s" % (text, o) + if self.additional_info.g1.value & 8: + if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF3": + text = utils.set_html_text_color("REP", utils.COLOR_MNEMO) + o = "%s %s" % (text, o) + elif self.additional_info.g1.value & 4: + if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF3": + text = utils.set_html_text_color("REPE", utils.COLOR_MNEMO) + o = "%s %s" % (text, o) + return o + + def get_args_expr(self): args = [] for a in self.args: @@ -612,6 +633,40 @@ class instruction_x86(instruction): return "%s" % o + @staticmethod + def arg2html(expr, index=None, loc_db=None): + if expr.is_id() or expr.is_int() or expr.is_loc(): + o = color_expr_html(expr, loc_db) + elif ((isinstance(expr, ExprOp) and expr.op == 'far' and + isinstance(expr.args[0], ExprMem)) or + isinstance(expr, ExprMem)): + if isinstance(expr, ExprOp): + prefix, expr = "FAR ", expr.args[0] + else: + prefix = "" + sz = SIZE2MEMPREFIX[expr.size] + sz = '<font color="%s">%s</font>' % (utils.COLOR_MEM, sz) + segm = "" + if is_mem_segm(expr): + segm = "%s:" % expr.ptr.args[0] + expr = expr.ptr.args[1] + else: + expr = expr.ptr + if isinstance(expr, ExprOp): + s = color_expr_html(expr, loc_db)#.replace('(', '').replace(')', '') + else: + s = color_expr_html(expr, loc_db) + o = prefix + sz + ' PTR %s[%s]' % (segm, s) + elif isinstance(expr, ExprOp) and expr.op == 'segm': + o = "%s:%s" % ( + color_expr_html(expr.args[0], loc_db), + color_expr_html(expr.args[1], loc_db) + ) + else: + raise ValueError('check this %r' % expr) + return "%s" % o + + class mn_x86(cls_mn): name = "x86" @@ -864,7 +919,7 @@ class mn_x86(cls_mn): if self.rex_b.value: rex |= 0x1 if rex != 0x40 or self.rex_p.value == 1: - v = int_to_byte(rex) + v + v = utils.int_to_byte(rex) + v if hasattr(self, 'no_rex'): return None diff --git a/miasm/arch/x86/sem.py b/miasm/arch/x86/sem.py index 5b6ff917..ffa2641c 100644 --- a/miasm/arch/x86/sem.py +++ b/miasm/arch/x86/sem.py @@ -929,8 +929,8 @@ def pop_gen(ir, instr, src, size): sp = mRSP[instr.mode] new_sp = sp + m2_expr.ExprInt(src.size // 8, sp.size) - # don't generate ESP incrementation on POP ESP - if src != ir.sp: + # Don't generate SP/ESP/RSP incrementation on POP SP/ESP/RSP + if not (src in mRSP.values()): e.append(m2_expr.ExprAssign(sp, new_sp)) # XXX FIX XXX for pop [esp] if isinstance(src, m2_expr.ExprMem): diff --git a/miasm/core/asmblock.py b/miasm/core/asmblock.py index 47bffb34..e92034fe 100644 --- a/miasm/core/asmblock.py +++ b/miasm/core/asmblock.py @@ -35,6 +35,9 @@ class AsmRaw(object): def to_string(self, loc_db): return str(self) + def to_html(self, loc_db): + return str(self) + class AsmConstraint(object): c_to = "c_to" @@ -439,6 +442,9 @@ class AsmCFG(DiGraph): # between the two graphs self.add_edge(*edge, constraint=graph.edges2constraint[edge]) + def escape_text(self, text): + return text + def node2lines(self, node): loc_key_name = self.loc_db.pretty_str(node) @@ -462,9 +468,9 @@ class AsmCFG(DiGraph): if self._dot_offset: yield [self.DotCellDescription(text="%.8X" % line.offset, attr={}), - self.DotCellDescription(text=line.to_string(self.loc_db), attr={})] + self.DotCellDescription(text=line.to_html(self.loc_db), attr={})] else: - yield self.DotCellDescription(text=line.to_string(self.loc_db), attr={}) + yield self.DotCellDescription(text=line.to_html(self.loc_db), attr={}) def node_attr(self, node): block = self._loc_key_to_block.get(node, None) diff --git a/miasm/core/cpu.py b/miasm/core/cpu.py index d9c1955b..fac03248 100644 --- a/miasm/core/cpu.py +++ b/miasm/core/cpu.py @@ -19,6 +19,7 @@ from miasm.expression.simplifications import expr_simp from miasm.core.asm_ast import AstNode, AstInt, AstId, AstOp +from miasm.core import utils from future.utils import with_metaclass log = logging.getLogger("cpuhelper") @@ -1005,6 +1006,19 @@ class instruction(object): o += self.gen_args(args) return o + def to_html(self, loc_db=None): + out = "%-10s " % self.name + out = '<font color="%s">%s</font>' % (utils.COLOR_MNEMO, out) + + args = [] + for i, arg in enumerate(self.args): + if not isinstance(arg, m2_expr.Expr): + raise ValueError('zarb arg type') + x = self.arg2html(arg, i, loc_db) + args.append(x) + out += self.gen_args(args) + return out + def get_asm_offset(self, expr): return m2_expr.ExprInt(self.offset, expr.size) diff --git a/miasm/core/graph.py b/miasm/core/graph.py index 1ee30c9f..0dfd7e6a 100644 --- a/miasm/core/graph.py +++ b/miasm/core/graph.py @@ -20,6 +20,9 @@ class DiGraph(object): # N -> Nodes N2 with a edge (N2 -> N) self._nodes_pred = {} + self.escape_chars = re.compile('[' + re.escape('{}') + '&|<>' + ']') + + def __repr__(self): out = [] for node in self._nodes: @@ -239,10 +242,12 @@ class DiGraph(object): **attr)) ) + def escape_text(self, text): + return self.escape_chars.sub(self._fix_chars, text) + def dot(self): """Render dot graph with HTML""" - escape_chars = re.compile('[' + re.escape('{}') + '&|<>' + ']') td_attr = {'align': 'left'} nodes_attr = {'shape': 'Mrecord', 'fontname': 'Courier New'} @@ -266,7 +271,7 @@ class DiGraph(object): for col in lineDesc: out_render += "<td %s>%s</td>" % ( self._attr2str(td_attr, col.attr), - escape_chars.sub(self._fix_chars, str(col.text))) + self.escape_text(str(col.text))) node_html_lines.append(out_render) node_html_lines = ('<tr>' + @@ -302,7 +307,6 @@ class DiGraph(object): self.gv = graphviz.Digraph('html_table') self._dot_offset = False - escape_chars = re.compile('[' + re.escape('{}') + '&|<>' + ']') td_attr = {'align': 'left'} nodes_attr = {'shape': 'Mrecord', 'fontname': 'Courier New'} @@ -320,7 +324,7 @@ class DiGraph(object): for col in lineDesc: out_render += "<td %s>%s</td>" % ( self._attr2str(td_attr, col.attr), - escape_chars.sub(self._fix_chars, str(col.text))) + self.escape_text(str(col.text))) node_html_lines.append(out_render) node_html_lines = ('<tr>' + diff --git a/miasm/core/utils.py b/miasm/core/utils.py index cfe96de4..41bf78c1 100644 --- a/miasm/core/utils.py +++ b/miasm/core/utils.py @@ -1,4 +1,5 @@ from __future__ import print_function +import re import sys from builtins import range import struct @@ -16,6 +17,28 @@ from future.utils import viewitems import collections +COLOR_INT = "azure4" +COLOR_ID = "forestgreen"#"chartreuse3" +COLOR_MEM = "deeppink4" +COLOR_OP_FUNC = "blue1" +COLOR_LOC = "darkslateblue" +COLOR_OP = "black" + +COLOR_MNEMO = "blue1" + +ESCAPE_CHARS = re.compile('[' + re.escape('{}') + '&|<>' + ']') + +def set_html_text_color(text, color): + return '<font color="%s">%s</font>' % (color, text) + + +def _fix_chars(token): + return "&#%04d;" % ord(token.group()) + + +def fix_html_chars(text): + return ESCAPE_CHARS.sub(_fix_chars, str(text)) + upck8 = lambda x: struct.unpack('B', x)[0] upck16 = lambda x: struct.unpack('H', x)[0] upck32 = lambda x: struct.unpack('I', x)[0] @@ -261,3 +284,4 @@ class BoundedDict(DictMixin): def __iter__(self): return iter(self._data) + diff --git a/miasm/ir/ir.py b/miasm/ir/ir.py index b712b0ee..e9b86899 100644 --- a/miasm/ir/ir.py +++ b/miasm/ir/ir.py @@ -27,7 +27,10 @@ import miasm.expression.expression as m2_expr from miasm.expression.expression_helper import get_missing_interval from miasm.core.asmblock import AsmBlock, AsmBlockBad, AsmConstraint from miasm.core.graph import DiGraph +from miasm.ir.translators import Translator from functools import reduce +from miasm.core import utils +import re def _expr_loc_to_symb(expr, loc_db): @@ -44,6 +47,108 @@ def _expr_loc_to_symb(expr, loc_db): name = sorted(names)[0] return m2_expr.ExprId(name, expr.size) + +ESCAPE_CHARS = re.compile('[' + re.escape('{}') + '&|<>' + ']') + +class TranslatorHtml(Translator): + __LANG__ = "custom_expr_color" + + @staticmethod + def _fix_chars(token): + return "&#%04d;" % ord(token.group()) + + def __init__(self, loc_db=None, **kwargs): + super(TranslatorHtml, self).__init__(**kwargs) + self.loc_db = loc_db + + def str_protected_child(self, child, parent): + return ("(%s)" % ( + self.from_expr(child)) if m2_expr.should_parenthesize_child(child, parent) + else self.from_expr(child) + ) + + def from_ExprInt(self, expr): + out = str(expr) + out = '<font color="%s">%s</font>' % (utils.COLOR_INT, out) + return out + + def from_ExprId(self, expr): + out = str(expr) + out = '<font color="%s">%s</font>' % (utils.COLOR_ID, out) + return out + + def from_ExprLoc(self, expr): + + if self.loc_db is None: + name = ESCAPE_CHARS.sub(self._fix_chars, str((expr))) + else: + names = self.loc_db.get_location_names(expr.loc_key) + if not names: + name = self.loc_db.pretty_str(expr.loc_key) + else: + # Use only one name for readability + name = sorted(names)[0] + name = ESCAPE_CHARS.sub(self._fix_chars, name) + out = '<font color="%s">%s</font>' % (utils.COLOR_LOC, name) + return out + + def from_ExprMem(self, expr): + ptr = self.from_expr(expr.ptr) + size = '@' + str(expr.size) + size = '<font color="%s">%s</font>' % (utils.COLOR_MEM, size) + bracket_left = ESCAPE_CHARS.sub(self._fix_chars, '[') + bracket_right = ESCAPE_CHARS.sub(self._fix_chars, ']') + out = '%s%s%s%s' % (size, bracket_left, ptr, bracket_right) + return out + + def from_ExprSlice(self, expr): + base = self.from_expr(expr.arg) + start = str(expr.start) + stop = str(expr.stop) + bracket_left = ESCAPE_CHARS.sub(self._fix_chars, '[') + bracket_right = ESCAPE_CHARS.sub(self._fix_chars, ']') + out = "(%s)%s%s:%s%s" % (base, bracket_left, start, stop, bracket_right) + return out + + def from_ExprCompose(self, expr): + out = ESCAPE_CHARS.sub(self._fix_chars, "{") + out += ", ".join(["%s, %s, %s" % (self.from_expr(subexpr), + str(idx), + str(idx + subexpr.size)) + for idx, subexpr in expr.iter_args()]) + out += ESCAPE_CHARS.sub(self._fix_chars, "}") + return out + + def from_ExprCond(self, expr): + cond = self.str_protected_child(expr.cond, expr) + src1 = self.from_expr(expr.src1) + src2 = self.from_expr(expr.src2) + out = "%s?(%s,%s)" % (cond, src1, src2) + return out + + def from_ExprOp(self, expr): + op = ESCAPE_CHARS.sub(self._fix_chars, expr._op) + if expr._op == '-': # Unary minus + return '-' + self.str_protected_child(expr._args[0], expr) + if expr.is_associative() or expr.is_infix(): + return (' ' + op + ' ').join([self.str_protected_child(arg, expr) + for arg in expr._args]) + + op = '<font color="%s">%s</font>' % (utils.COLOR_OP_FUNC, op) + return (op + '(' + + ', '.join( + self.from_expr(arg) + for arg in expr._args + ) + ')') + + def from_ExprAssign(self, expr): + return "%s = %s" % tuple(map(expr.from_expr, (expr.dst, expr.src))) + + +def color_expr_html(expr, loc_db): + translator = TranslatorHtml(loc_db=loc_db) + return translator.from_expr(expr) + def slice_rest(expr): "Return the completion of the current slice" size = expr.arg.size @@ -489,6 +594,7 @@ class irbloc(IRBlock): super(irbloc, self).__init__(loc_key, irs) + class IRCFG(DiGraph): """DiGraph for IR instances""" @@ -528,6 +634,9 @@ class IRCFG(DiGraph): if dst.is_loc(): self.add_uniq_edge(irblock.loc_key, dst.loc_key) + def escape_text(self, text): + return text + def node2lines(self, node): node_name = self.loc_db.pretty_str(node) yield self.DotCellDescription( @@ -543,10 +652,10 @@ class IRCFG(DiGraph): return for i, assignblk in enumerate(self._blocks[node]): for dst, src in viewitems(assignblk): - - new_src = src.visit(lambda expr:_expr_loc_to_symb(expr, self.loc_db)) - new_dst = dst.visit(lambda expr:_expr_loc_to_symb(expr, self.loc_db)) - line = "%s = %s" % (new_dst, new_src) + line = "%s = %s" % ( + color_expr_html(dst, self.loc_db), + color_expr_html(src, self.loc_db) + ) if self._dot_offset: yield [self.DotCellDescription(text="%-4d" % i, attr={}), self.DotCellDescription(text=line, attr={})] diff --git a/miasm/jitter/arch/JitCore_m68k.c b/miasm/jitter/arch/JitCore_m68k.c new file mode 100644 index 00000000..0989fde1 --- /dev/null +++ b/miasm/jitter/arch/JitCore_m68k.c @@ -0,0 +1,467 @@ +#include <Python.h> +#include "structmember.h" +#include <stdint.h> +#include <inttypes.h> +#include "../compat_py23.h" +#include "../queue.h" +#include "../vm_mngr.h" +#include "../bn.h" +#include "../vm_mngr_py.h" +#include "../JitCore.h" +#include "../op_semantics.h" +#include "JitCore_m68k.h" + + + +reg_dict gpreg_dict[] = { + {.name = "A0", .offset = offsetof(struct vm_cpu, A0), .size = 32}, + {.name = "A1", .offset = offsetof(struct vm_cpu, A1), .size = 32}, + {.name = "A2", .offset = offsetof(struct vm_cpu, A2), .size = 32}, + {.name = "A3", .offset = offsetof(struct vm_cpu, A3), .size = 32}, + {.name = "A4", .offset = offsetof(struct vm_cpu, A4), .size = 32}, + {.name = "A5", .offset = offsetof(struct vm_cpu, A5), .size = 32}, + {.name = "A6", .offset = offsetof(struct vm_cpu, A6), .size = 32}, + {.name = "SP", .offset = offsetof(struct vm_cpu, SP), .size = 32}, + + {.name = "D0", .offset = offsetof(struct vm_cpu, D0), .size = 32}, + {.name = "D1", .offset = offsetof(struct vm_cpu, D1), .size = 32}, + {.name = "D2", .offset = offsetof(struct vm_cpu, D2), .size = 32}, + {.name = "D3", .offset = offsetof(struct vm_cpu, D3), .size = 32}, + {.name = "D4", .offset = offsetof(struct vm_cpu, D4), .size = 32}, + {.name = "D5", .offset = offsetof(struct vm_cpu, D5), .size = 32}, + {.name = "D6", .offset = offsetof(struct vm_cpu, D6), .size = 32}, + {.name = "D7", .offset = offsetof(struct vm_cpu, D7), .size = 32}, + + {.name = "PC", .offset = offsetof(struct vm_cpu, PC), .size = 32}, + + {.name = "zf", .offset = offsetof(struct vm_cpu, zf), .size = 8}, + {.name = "nf", .offset = offsetof(struct vm_cpu, nf), .size = 8}, + {.name = "vf", .offset = offsetof(struct vm_cpu, vf), .size = 8}, + {.name = "cf", .offset = offsetof(struct vm_cpu, cf), .size = 8}, + {.name = "xf", .offset = offsetof(struct vm_cpu, xf), .size = 8}, + + {.name = "exception_flags", .offset = offsetof(struct vm_cpu, exception_flags), .size = 32}, + {.name = "interrupt_num", .offset = offsetof(struct vm_cpu, interrupt_num), .size = 32}, +}; + +/************************** JitCpu object **************************/ + + + + +PyObject* cpu_get_gpreg(JitCpu* self) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg(A0); + get_reg(A1); + get_reg(A2); + get_reg(A3); + get_reg(A4); + get_reg(A5); + get_reg(A6); + get_reg(SP); + + get_reg(D0); + get_reg(D1); + get_reg(D2); + get_reg(D3); + get_reg(D4); + get_reg(D5); + get_reg(D6); + get_reg(D7); + + get_reg(PC); + + get_reg(zf); + get_reg(nf); + get_reg(vf); + get_reg(cf); + get_reg(xf); + + return dict; +} + + + +PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args) +{ + PyObject* dict; + PyObject *d_key, *d_value = NULL; + Py_ssize_t pos = 0; + const char *d_key_name; + uint32_t val; + unsigned int i, found; + + if (!PyArg_ParseTuple(args, "O", &dict)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + if(!PyDict_Check(dict)) + RAISE(PyExc_TypeError, "arg must be dict"); + while(PyDict_Next(dict, &pos, &d_key, &d_value)){ + PyGetStr(d_key_name, d_key); + PyGetInt_uint32_t(d_value, val); + + found = 0; + for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){ + if (strcmp(d_key_name, gpreg_dict[i].name)) + continue; + *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val; + found = 1; + break; + } + + if (found) + continue; + fprintf(stderr, "unknown key: %s\n", d_key_name); + RAISE(PyExc_ValueError, "unknown reg"); + } + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject * cpu_init_regs(JitCpu* self) +{ + memset(self->cpu, 0, sizeof(struct vm_cpu)); + + Py_INCREF(Py_None); + return Py_None; +} + + +uint64_t segm2addr(JitCpu* jitcpu, uint64_t segm, uint64_t addr) +{ + return addr; +} + +void dump_gpregs(struct vm_cpu* vmcpu) +{ + printf("A0 %.8"PRIX32" A1 %.8"PRIX32" A2 %.8"PRIX32" A3 %.8"PRIX32" ", + vmcpu->A0, vmcpu->A1, vmcpu->A2, vmcpu->A3); + printf("R4 %.8"PRIX32" A5 %.8"PRIX32" A6 %.8"PRIX32" SP %.8"PRIX32"\n", + vmcpu->A4, vmcpu->A5, vmcpu->A6, vmcpu->SP); + + printf("D0 %.8"PRIX32" D1 %.8"PRIX32" D2 %.8"PRIX32" D3 %.8"PRIX32" ", + vmcpu->D0, vmcpu->D1, vmcpu->D2, vmcpu->D3); + printf("R4 %.8"PRIX32" D5 %.8"PRIX32" D6 %.8"PRIX32" D7 %.8"PRIX32"\n", + vmcpu->D4, vmcpu->D5, vmcpu->D6, vmcpu->D7); + + + printf("PC %.8"PRIX32" ", + vmcpu->PC); + printf("zf %"PRIX32" nf %"PRIX32" vf %"PRIX32" cf %"PRIX32" xf %"PRIX32"\n", + vmcpu->zf, vmcpu->nf, vmcpu->vf, vmcpu->cf, vmcpu->xf); +} + +void dump_gpregs_32(struct vm_cpu* vmcpu) +{ + dump_gpregs(vmcpu); +} + +PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args) +{ + struct vm_cpu* vmcpu; + + vmcpu = self->cpu; + dump_gpregs(vmcpu); + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args) +{ + return cpu_dump_gpregs(self, args); +} + + + +PyObject* cpu_set_exception(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint32_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint32_t(item1, exception_flags); + + ((struct vm_cpu*)self->cpu)->exception_flags = exception_flags; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_exception(JitCpu* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags)); +} + +void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src) +{ + vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src) +{ + vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src) +{ + vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src) +{ + vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +PyObject* cpu_set_interrupt_num(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint32_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint32_t(item1, exception_flags); + + ((struct vm_cpu*)self->cpu)->interrupt_num = exception_flags; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_interrupt_num(JitCpu* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->interrupt_num)); +} + +static PyMemberDef JitCpu_members[] = { + {NULL} /* Sentinel */ +}; + +static PyMethodDef JitCpu_methods[] = { + {"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS, + "X"}, + {"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS, + "X"}, + {"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS, + "X"}, + {"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS, + "X"}, + {"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS, + "X"}, + {"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS, + "X"}, + {"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS, + "X"}, + {"get_interrupt_num", (PyCFunction)cpu_get_interrupt_num, METH_VARARGS, + "X"}, + {"set_interrupt_num", (PyCFunction)cpu_set_interrupt_num, METH_VARARGS, + "X"}, + {NULL} /* Sentinel */ +}; + +static int +JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds) +{ + self->cpu = malloc(sizeof(struct vm_cpu)); + if (self->cpu == NULL) { + fprintf(stderr, "cannot alloc struct vm_cpu\n"); + exit(EXIT_FAILURE); + } + return 0; +} + +getset_reg_u32(A0); +getset_reg_u32(A1); +getset_reg_u32(A2); +getset_reg_u32(A3); +getset_reg_u32(A4); +getset_reg_u32(A5); +getset_reg_u32(A6); +getset_reg_u32(SP); + +getset_reg_u32(D0); +getset_reg_u32(D1); +getset_reg_u32(D2); +getset_reg_u32(D3); +getset_reg_u32(D4); +getset_reg_u32(D5); +getset_reg_u32(D6); +getset_reg_u32(D7); +getset_reg_u32(PC); + +getset_reg_u32(zf); +getset_reg_u32(nf); +getset_reg_u32(vf); +getset_reg_u32(cf); +getset_reg_u32(xf); + +getset_reg_u32(exception_flags); +getset_reg_u32(interrupt_num); + +PyObject* get_gpreg_offset_all(void) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg_off(exception_flags); + get_reg_off(interrupt_num); + + get_reg_off(A0); + get_reg_off(A1); + get_reg_off(A2); + get_reg_off(A3); + get_reg_off(A4); + get_reg_off(A5); + get_reg_off(A6); + get_reg_off(SP); + + get_reg_off(D0); + get_reg_off(D1); + get_reg_off(D2); + get_reg_off(D3); + get_reg_off(D4); + get_reg_off(D5); + get_reg_off(D6); + get_reg_off(D7); + + get_reg_off(PC); + + /* eflag */ + get_reg_off(zf); + get_reg_off(nf); + get_reg_off(vf); + get_reg_off(cf); + get_reg_off(xf); + + return dict; +} + +static PyGetSetDef JitCpu_getseters[] = { + {"vmmngr", + (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr, + "vmmngr", + NULL}, + + {"vmcpu", + (getter)JitCpu_get_vmcpu, (setter)JitCpu_set_vmcpu, + "vmcpu", + NULL}, + + {"jitter", + (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter, + "jitter", + NULL}, + + + + {"A0" , (getter)JitCpu_get_A0 , (setter)JitCpu_set_A0 , "A0" , NULL}, + {"A1" , (getter)JitCpu_get_A1 , (setter)JitCpu_set_A1 , "A1" , NULL}, + {"A2" , (getter)JitCpu_get_A2 , (setter)JitCpu_set_A2 , "A2" , NULL}, + {"A3" , (getter)JitCpu_get_A3 , (setter)JitCpu_set_A3 , "A3" , NULL}, + {"A4" , (getter)JitCpu_get_A4 , (setter)JitCpu_set_A4 , "A4" , NULL}, + {"A5" , (getter)JitCpu_get_A5 , (setter)JitCpu_set_A5 , "A5" , NULL}, + {"A6" , (getter)JitCpu_get_A6 , (setter)JitCpu_set_A6 , "A6" , NULL}, + {"SP" , (getter)JitCpu_get_SP , (setter)JitCpu_set_SP , "SP" , NULL}, + + {"D0" , (getter)JitCpu_get_D0 , (setter)JitCpu_set_D0 , "D0" , NULL}, + {"D1" , (getter)JitCpu_get_D1 , (setter)JitCpu_set_D1 , "D1" , NULL}, + {"D2" , (getter)JitCpu_get_D2 , (setter)JitCpu_set_D2 , "D2" , NULL}, + {"D3" , (getter)JitCpu_get_D3 , (setter)JitCpu_set_D3 , "D3" , NULL}, + {"D4" , (getter)JitCpu_get_D4 , (setter)JitCpu_set_D4 , "D4" , NULL}, + {"D5" , (getter)JitCpu_get_D5 , (setter)JitCpu_set_D5 , "D5" , NULL}, + {"D6" , (getter)JitCpu_get_D6 , (setter)JitCpu_set_D6 , "D6" , NULL}, + {"D7" , (getter)JitCpu_get_D7 , (setter)JitCpu_set_D7 , "D7" , NULL}, + + {"PC" , (getter)JitCpu_get_PC , (setter)JitCpu_set_PC , "PC" , NULL}, + + {"zf", (getter)JitCpu_get_zf, (setter)JitCpu_set_zf, "zf", NULL}, + {"nf", (getter)JitCpu_get_nf, (setter)JitCpu_set_nf, "nf", NULL}, + {"vf", (getter)JitCpu_get_vf, (setter)JitCpu_set_vf, "vf", NULL}, + {"cf", (getter)JitCpu_get_cf, (setter)JitCpu_set_cf, "cf", NULL}, + {"xf", (getter)JitCpu_get_xf, (setter)JitCpu_set_xf, "xf", NULL}, + + {"exception_flags", (getter)JitCpu_get_exception_flags, (setter)JitCpu_set_exception_flags, "exception_flags", NULL}, + {"interrupt_num", (getter)JitCpu_get_interrupt_num, (setter)JitCpu_set_interrupt_num, "interrupt_num", NULL}, + + {NULL} /* Sentinel */ +}; + + +static PyTypeObject JitCpuType = { + PyVarObject_HEAD_INIT(NULL, 0) + "JitCore_m68k.JitCpu", /*tp_name*/ + sizeof(JitCpu), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)JitCpu_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "JitCpu objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + JitCpu_methods, /* tp_methods */ + JitCpu_members, /* tp_members */ + JitCpu_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)JitCpu_init, /* tp_init */ + 0, /* tp_alloc */ + JitCpu_new, /* tp_new */ +}; + + + +static PyMethodDef JitCore_m68k_Methods[] = { + + /* + + */ + {"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS}, + {NULL, NULL, 0, NULL} /* Sentinel */ + +}; + + + +MOD_INIT(JitCore_m68k) +{ + PyObject *module = NULL; + + MOD_DEF(module, "JitCore_m68k", "JitCore_m68k module", JitCore_m68k_Methods); + + if (module == NULL) + RET_MODULE; + + if (PyType_Ready(&JitCpuType) < 0) + RET_MODULE; + + Py_INCREF(&JitCpuType); + if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0) + RET_MODULE; + + RET_MODULE; +} + diff --git a/miasm/jitter/arch/JitCore_m68k.h b/miasm/jitter/arch/JitCore_m68k.h new file mode 100644 index 00000000..6ff6b326 --- /dev/null +++ b/miasm/jitter/arch/JitCore_m68k.h @@ -0,0 +1,55 @@ + +struct vm_cpu { + uint32_t exception_flags; + uint32_t interrupt_num; + + /* gpregs */ + uint32_t A0; + uint32_t A1; + uint32_t A2; + uint32_t A3; + uint32_t A4; + uint32_t A5; + uint32_t A6; + uint32_t SP; + + uint32_t D0; + uint32_t D1; + uint32_t D2; + uint32_t D3; + uint32_t D4; + uint32_t D5; + uint32_t D6; + uint32_t D7; + + + uint32_t PC; + + /* eflag */ + uint32_t zf; + uint32_t nf; + uint32_t vf; + uint32_t cf; + uint32_t xf; + + uint64_t float_st0; + uint64_t float_st1; + uint64_t float_st2; + uint64_t float_st3; + uint64_t float_st4; + uint64_t float_st5; + uint64_t float_st6; + uint64_t float_st7; + + uint32_t bp_num; +}; + + +_MIASM_EXPORT void dump_gpregs(struct vm_cpu* vmcpu); + +_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src); +_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src); +_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src); +_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src); + +#define RETURN_PC return BlockDst; diff --git a/miasm/loader/pe.py b/miasm/loader/pe.py index 2d257906..ea7cbc52 100644 --- a/miasm/loader/pe.py +++ b/miasm/loader/pe.py @@ -714,9 +714,9 @@ class DirExport(CStruct): self.expdesc.name = rva rva += len(self.dlldescname) self.expdesc.addressoffunctions = rva - rva += len(self.f_address) * rva_size + rva += len(self.f_address) * 4 self.expdesc.addressofnames = rva - rva += len(self.f_names) * rva_size + rva += len(self.f_names) * 4 self.expdesc.addressofordinals = rva rva += len(self.f_nameordinals) * 2 # Ordinal size for func in self.f_names: @@ -730,8 +730,8 @@ class DirExport(CStruct): return length length += len(self.expdesc) length += len(self.dlldescname) - length += len(self.f_address) * rva_size - length += len(self.f_names) * rva_size + length += len(self.f_address) * 4 + length += len(self.f_names) * 4 length += len(self.f_nameordinals) * 2 # Ordinal size for entry in self.f_names: length += len(entry.name) @@ -775,16 +775,16 @@ class DirExport(CStruct): self.dlldescname.name = name self.f_address = struct_array(self, None, None, - Rva) + Rva32) self.f_names = struct_array(self, None, None, - Rva) + Rva32) self.f_nameordinals = struct_array(self, None, None, Ordinal) self.expdesc.base = 1 - def add_name(self, name, rva=0xdeadc0fe): + def add_name(self, name, rva=0xdeadc0fe, ordinal=None): if self.expdesc is None: return names = [func.name.name for func in self.f_names] @@ -798,14 +798,18 @@ class DirExport(CStruct): descname = DescName(self.parent_head) descname.name = name - wname = Rva(self.parent_head) + wname = Rva32(self.parent_head) wname.name = descname - woffset = Rva(self.parent_head) + woffset = Rva32(self.parent_head) woffset.rva = rva wordinal = Ordinal(self.parent_head) # func is append to list - wordinal.ordinal = len(self.f_address) + if ordinal is None: + wordinal.ordinal = len(self.f_address) + else: + wordinal.ordinal = ordinal + self.f_address.append(woffset) # self.f_names.insert(index, wname) # self.f_nameordinals.insert(index, wordinal) diff --git a/requirements.txt b/requirements.txt index eb542916..5db3c2a8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -pyparsing +pyparsing~=2.0 future diff --git a/setup.py b/setup.py index 4980028f..e317877a 100644 --- a/setup.py +++ b/setup.py @@ -197,6 +197,17 @@ def buil_all(): "miasm/jitter/bn.h", ] ), + Extension( + "miasm.jitter.arch.JitCore_m68k", + [ + "miasm/jitter/JitCore.c", + "miasm/jitter/vm_mngr.c", + "miasm/jitter/vm_mngr_py.c", + "miasm/jitter/op_semantics.c", + "miasm/jitter/bn.c", + "miasm/jitter/arch/JitCore_m68k.c" + ] + ), Extension("miasm.jitter.Jitllvm", ["miasm/jitter/Jitllvm.c", "miasm/jitter/bn.c", @@ -242,7 +253,7 @@ def buil_all(): "VERSION" ] }, - install_requires=['future', 'pyparsing'], + install_requires=['future', 'pyparsing~=2.0'], cmdclass={"install_data": smart_install_data}, ext_modules = ext_modules, # Metadata diff --git a/test/arch/aarch64/arch.py b/test/arch/aarch64/arch.py index 9be0c6c5..57ec9b14 100644 --- a/test/arch/aarch64/arch.py +++ b/test/arch/aarch64/arch.py @@ -1829,8 +1829,13 @@ reg_tests_aarch64 = [ ("XXXXXXXX STLXRB W17, W16, [X14]", "D0FD1108"), + ("XXXXXXXX STLR W9, [X8]", + "09FD9F88"), ("XXXXXXXX STLRB W1, [X0]", "01FC9F08"), + ("XXXXXXXX STLRH W9, [X8]", + "09FD9F48"), + ("XXXXXXXX IC 0x0, c1, 0x0, XZR", "1F7108D5"), ("XXXXXXXX CLREX 0xF", @@ -1865,4 +1870,5 @@ for s, l in reg_tests_aarch64[:]: print([x for x in a]) print(repr(b)) assert(b in a) + print(l.to_html()) diff --git a/test/arch/arm/arch.py b/test/arch/arm/arch.py index 740655da..42e80772 100644 --- a/test/arch/arm/arch.py +++ b/test/arch/arm/arch.py @@ -261,6 +261,7 @@ for s, l in reg_tests_arm: print([x for x in a]) print(repr(b)) assert(b in a) + print(l.to_html()) reg_tests_armt = [ ("0006ff5c LSLS R2, R0, 0x1A", @@ -733,6 +734,7 @@ for s, l in reg_tests_armt: print([x for x in a]) print(repr(b)) assert(b in a) + print(l.to_html()) print('TEST time', time.time() - ts) diff --git a/test/arch/mips32/arch.py b/test/arch/mips32/arch.py index de6d4547..0509f033 100644 --- a/test/arch/mips32/arch.py +++ b/test/arch/mips32/arch.py @@ -274,3 +274,4 @@ for s, l in reg_tests_mips32: print([x for x in a]) print(repr(b)) assert(b in a) + print(l.to_html()) diff --git a/test/arch/msp430/arch.py b/test/arch/msp430/arch.py index bc38c363..133b8b55 100644 --- a/test/arch/msp430/arch.py +++ b/test/arch/msp430/arch.py @@ -104,3 +104,4 @@ for s, l in reg_tests_msp: print([x for x in a]) print(repr(b)) assert(b in a) + print(l.to_html()) diff --git a/test/arch/ppc32/arch.py b/test/arch/ppc32/arch.py index 13c69c73..f5503330 100644 --- a/test/arch/ppc32/arch.py +++ b/test/arch/ppc32/arch.py @@ -114,6 +114,7 @@ for mode, s, l, in reg_tests: a = mn_ppc.asm(l) print('asm result %s' % [x for x in a]) print(repr(b)) + print(l.to_html()) print('test re dis') for x in a: diff --git a/test/arch/x86/arch.py b/test/arch/x86/arch.py index 55694dfe..22cfcf39 100644 --- a/test/arch/x86/arch.py +++ b/test/arch/x86/arch.py @@ -3153,6 +3153,7 @@ for mode, s, l, in reg_tests: a = mn_x86.asm(l) print('asm result', [x for x in a]) print(repr(b)) + print(l.to_html()) for x in a: print("BYTES", repr(x)) diff --git a/test/test_all.py b/test/test_all.py index f0ac755e..a49f6ff9 100755 --- a/test/test_all.py +++ b/test/test_all.py @@ -710,6 +710,7 @@ for script in [["basic_op.py"], ["expr_random.py"], ["expr_translate.py"], ["expr_reduce.py"], + ["interfer.py"], ]: testset += ExampleExpression(script) |