diff options
| -rw-r--r-- | miasm2/arch/x86/arch.py | 195 | ||||
| -rw-r--r-- | miasm2/arch/x86/sem.py | 72 | ||||
| -rw-r--r-- | miasm2/core/cpu.py | 3 | ||||
| -rw-r--r-- | test/arch/x86/arch.py | 36 |
4 files changed, 197 insertions, 109 deletions
diff --git a/miasm2/arch/x86/arch.py b/miasm2/arch/x86/arch.py index 3f64c3c4..724f6b86 100644 --- a/miasm2/arch/x86/arch.py +++ b/miasm2/arch/x86/arch.py @@ -272,6 +272,8 @@ deref_ptr = Group(int_or_expr + COLON + PTR = Suppress('PTR') +FAR = Suppress('FAR') + BYTE = Literal('BYTE') WORD = Literal('WORD') @@ -313,6 +315,9 @@ rmarg = Group(gpregs08.parser | rmarg |= deref_mem +mem_far = FAR + deref_mem + + cl_or_imm = Group(r08_ecx.parser).setParseAction(getreg) cl_or_imm |= int_or_expr @@ -583,7 +588,13 @@ class instruction_x86(instruction): def arg2str(expr, pos=None): if isinstance(expr, ExprId) or isinstance(expr, ExprInt): o = str(expr) - elif isinstance(expr, ExprMem): + 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] segm = "" if expr.is_op_segm(): @@ -595,7 +606,7 @@ class instruction_x86(instruction): s = str(expr).replace('(', '').replace(')', '') else: s = str(expr) - o = sz + ' PTR %s[%s]' % (segm, s) + o = prefix + sz + ' PTR %s[%s]' % (segm, s) elif isinstance(expr, ExprOp) and expr.op == 'segm': o = "%s:%s" % (expr.args[0], expr.args[1]) else: @@ -2039,6 +2050,42 @@ class x86_rm_mem(x86_rm_arg): return None, None return start, stop + +class x86_rm_mem_far(x86_rm_arg): + parser = mem_far + def fromstring(self, s, parser_result=None): + self.expr = None + start, stop = super(x86_rm_mem_far, self).fromstring(s, parser_result) + if not isinstance(self.expr, ExprMem): + return None, None + self.expr = ExprOp('far', self.expr) + return start, stop + + def decode(self, v): + ret = super(x86_rm_mem_far, self).decode(v) + if not ret: + return ret + if isinstance(self.expr, m2_expr.ExprMem): + self.expr = ExprOp('far', self.expr) + return True + + def encode(self): + if not (isinstance(self.expr, m2_expr.ExprOp) and + self.expr.op == 'far'): + raise StopIteration + + expr = self.expr.args[0] + if isinstance(expr, ExprInt): + raise StopIteration + p = self.parent + admode = p.v_admode() + mode = expr.size + v_cand, segm, ok = expr2modrm(expr, p, 1) + if segm: + p.g2.value = segm2enc[segm] + for x in self.gen_cand(v_cand, admode): + yield x + class x86_rm_w8(x86_rm_arg): def decode(self, v): @@ -3143,6 +3190,7 @@ rm_arg_m80 = bs(l=0, cls=(x86_rm_m80,), fname='rmarg') rm_arg_m16 = bs(l=0, cls=(x86_rm_m16,), fname='rmarg') rm_mem = bs(l=0, cls=(x86_rm_mem,), fname='rmarg') +rm_mem_far = bs(l=0, cls=(x86_rm_mem_far,), fname='rmarg') rm_arg_mm = bs(l=0, cls=(x86_rm_mm,), fname='rmarg') rm_arg_mm_m64 = bs(l=0, cls=(x86_rm_mm_m64,), fname='rmarg') @@ -3156,6 +3204,74 @@ rm_arg_xmm_reg = bs(l=0, cls=(x86_rm_xmm_reg,), fname='rmarg') swapargs = bs_swapargs(l=1, fname="swap", mn_mod=range(1 << 1)) +class bs_op_mode(bsi): + + def decode(self, v): + opmode = self.parent.v_opmode() + return opmode == self.mode + + +class bs_ad_mode(bsi): + + def decode(self, v): + admode = self.parent.v_admode() + return admode == self.mode + + +class bs_op_mode_no64(bsi): + + def encode(self): + if self.parent.mode == 64: + return False + return super(bs_op_mode_no64, self).encode() + + def decode(self, v): + if self.parent.mode == 64: + return False + opmode = self.parent.v_opmode() + return opmode == self.mode + + +class bs_op_mode64(bsi): + def encode(self): + if self.parent.mode != 64: + return False + return super(bs_op_mode64, self).encode() + + def decode(self, v): + if self.parent.mode != 64: + return False + return True + +class bs_op_modeno64(bsi): + def encode(self): + if self.parent.mode == 64: + return False + return super(bs_op_modeno64, self).encode() + + def decode(self, v): + if self.parent.mode == 64: + return False + return True + + + +bs_opmode16 = bs(l=0, cls=(bs_op_mode,), mode = 16, fname="fopmode") +bs_opmode32 = bs(l=0, cls=(bs_op_mode,), mode = 32, fname="fopmode") +bs_opmode64 = bs(l=0, cls=(bs_op_mode,), mode = 64, fname="fopmode") + + +bs_admode16 = bs(l=0, cls=(bs_ad_mode,), mode = 16, fname="fadmode") +bs_admode32 = bs(l=0, cls=(bs_ad_mode,), mode = 32, fname="fadmode") +bs_admode64 = bs(l=0, cls=(bs_ad_mode,), mode = 64, fname="fadmode") + +bs_opmode16_no64 = bs(l=0, cls=(bs_op_mode_no64,), mode = 16, fname="fopmode") +bs_opmode32_no64 = bs(l=0, cls=(bs_op_mode_no64,), mode = 32, fname="fopmode") + +bs_mode64 = bs(l=0, cls=(bs_op_mode64,)) +bs_modeno64 = bs(l=0, cls=(bs_op_modeno64,)) + + cond_list = ["O", "NO", "B", "AE", "Z", "NZ", "BE", "A", "S", "NS", "PE", "NP", @@ -3229,76 +3345,9 @@ addop("bts", [bs8(0x0f), bs8(0xba)] + rmmod(d5) + [u08]) addop("call", [bs8(0xe8), rel_off]) addop("call", [bs8(0xff), stk] + rmmod(d2)) -addop("call", [bs8(0xff), stk] + rmmod(d3, modrm=mod_mem)) -addop("call", [bs8(0x9a), moff, msegoff]) - - -class bs_op_mode(bsi): - - def decode(self, v): - opmode = self.parent.v_opmode() - return opmode == self.mode - - -class bs_ad_mode(bsi): - - def decode(self, v): - admode = self.parent.v_admode() - return admode == self.mode - - -class bs_op_mode_no64(bsi): - - def encode(self): - if self.parent.mode == 64: - return False - return super(bs_op_mode_no64, self).encode() - - def decode(self, v): - if self.parent.mode == 64: - return False - opmode = self.parent.v_opmode() - return opmode == self.mode - +addop("call", [bs8(0xff), stk] + rmmod(d3, rm_arg_x=rm_mem_far, modrm=mod_mem)) +addop("call", [bs8(0x9a), bs_modeno64, moff, msegoff]) -class bs_op_mode64(bsi): - def encode(self): - if self.parent.mode != 64: - return False - return super(bs_op_mode64, self).encode() - - def decode(self, v): - if self.parent.mode != 64: - return False - return True - -class bs_op_modeno64(bsi): - def encode(self): - if self.parent.mode == 64: - return False - return super(bs_op_modeno64, self).encode() - - def decode(self, v): - if self.parent.mode == 64: - return False - return True - - - -bs_opmode16 = bs(l=0, cls=(bs_op_mode,), mode = 16, fname="fopmode") -bs_opmode32 = bs(l=0, cls=(bs_op_mode,), mode = 32, fname="fopmode") -bs_opmode64 = bs(l=0, cls=(bs_op_mode,), mode = 64, fname="fopmode") - - -bs_admode16 = bs(l=0, cls=(bs_ad_mode,), mode = 16, fname="fadmode") -bs_admode32 = bs(l=0, cls=(bs_ad_mode,), mode = 32, fname="fadmode") -bs_admode64 = bs(l=0, cls=(bs_ad_mode,), mode = 64, fname="fadmode") - -bs_opmode16_no64 = bs(l=0, cls=(bs_op_mode_no64,), mode = 16, fname="fopmode") -bs_opmode32_no64 = bs(l=0, cls=(bs_op_mode_no64,), mode = 32, fname="fopmode") - -bs_mode64 = bs(l=0, cls=(bs_op_mode64,)) -bs_modeno64 = bs(l=0, cls=(bs_op_modeno64,)) addop("cbw", [bs8(0x98), bs_opmode16]) addop("cwde", [bs8(0x98), bs_opmode32]) @@ -3551,9 +3600,9 @@ addop("jmp", [bs8(0xeb), rel_off08]) addop("jmp", [bs8(0xe9), rel_off]) # TODO XXX replace stk force64? addop("jmp", [bs8(0xff), stk] + rmmod(d4)) -addop("jmpf", [bs8(0xea), moff, msegoff]) +addop("jmp", [bs8(0xea), bs_modeno64, moff, msegoff]) -addop("jmpf", [bs8(0xff)] + rmmod(d5)) +addop("jmp", [bs8(0xff)] + rmmod(d5, rm_arg_x=rm_mem_far, modrm=mod_mem)) addop("lahf", [bs8(0x9f)]) addop("lar", [bs8(0x0f), bs8(0x02)] + rmmod(rmreg)) diff --git a/miasm2/arch/x86/sem.py b/miasm2/arch/x86/sem.py index c2d84253..5148bd28 100644 --- a/miasm2/arch/x86/sem.py +++ b/miasm2/arch/x86/sem.py @@ -1149,14 +1149,24 @@ def call(ir, instr, dst): myesp = mRSP[instr.mode][:opmode] n = m2_expr.ExprId(ir.get_next_label(instr), ir.IRDst.size) - if (isinstance(dst, m2_expr.ExprOp) and dst.op == "segm"): - # call far - if instr.mode != 16: - raise NotImplementedError('add 32 bit support!') - segm = dst.args[0] - base = dst.args[1] - m1 = segm.zeroExtend(CS.size) - m2 = base.zeroExtend(meip.size) + if isinstance(dst, m2_expr.ExprOp): + if dst.op == "segm": + # Far call segm:addr + if instr.mode not in [16, 32]: + raise RuntimeError('not supported') + segm = dst.args[0] + base = dst.args[1] + m1 = segm.zeroExtend(CS.size) + m2 = base.zeroExtend(meip.size) + elif dst.op == "far": + # Far call far [eax] + addr = dst.args[0].arg + m1 = m2_expr.ExprMem(addr, CS.size) + m2 = m2_expr.ExprMem(addr + m2_expr.ExprInt_from(addr, 2), + meip.size) + else: + raise RuntimeError("bad call operator") + e.append(m2_expr.ExprAff(CS, m1)) e.append(m2_expr.ExprAff(meip, m2)) @@ -1274,33 +1284,34 @@ def enter(ir, instr, a, b): def jmp(ir, instr, dst): e = [] meip = mRIP[ir.IRDst.size] - e.append(m2_expr.ExprAff(meip, dst)) # dst.zeroExtend(ir.IRDst.size))) - e.append(m2_expr.ExprAff(ir.IRDst, dst)) # dst.zeroExtend(ir.IRDst.size))) - if isinstance(dst, m2_expr.ExprMem): - dst = meip - return e, [] + if isinstance(dst, m2_expr.ExprOp): + if dst.op == "segm": + # Far jmp segm:addr + segm = dst.args[0] + base = dst.args[1] + m1 = segm.zeroExtend(CS.size) + m2 = base.zeroExtend(meip.size) + elif dst.op == "far": + # Far jmp far [eax] + addr = dst.args[0].arg + m1 = m2_expr.ExprMem(addr, CS.size) + m2 = m2_expr.ExprMem(addr + m2_expr.ExprInt_from(addr, 2), + meip.size) + else: + raise RuntimeError("bad jmp operator") + e.append(m2_expr.ExprAff(CS, m1)) + e.append(m2_expr.ExprAff(meip, m2)) + e.append(m2_expr.ExprAff(ir.IRDst, m2)) -def jmpf(ir, instr, a): - e = [] - meip = mRIP[ir.IRDst.size] - s = instr.mode - if (isinstance(a, m2_expr.ExprOp) and a.op == "segm"): - segm = a.args[0] - base = a.args[1] - m1 = segm.zeroExtend( - CS.size) # m2_expr.ExprMem(m2_expr.ExprOp('segm', segm, base), 16) - m2 = base.zeroExtend(meip.size) - # m2_expr.ExprMem(m2_expr.ExprOp('segm', segm, - # base + m2_expr.ExprInt_from(base, 2)), s) else: - m1 = m2_expr.ExprMem(a, 16) - m2 = m2_expr.ExprMem(a + m2_expr.ExprInt_from(a, 2), meip.size) + # Classic jmp + e.append(m2_expr.ExprAff(meip, dst)) + e.append(m2_expr.ExprAff(ir.IRDst, dst)) - e.append(m2_expr.ExprAff(CS, m1)) - e.append(m2_expr.ExprAff(meip, m2)) - e.append(m2_expr.ExprAff(ir.IRDst, m2)) + if isinstance(dst, m2_expr.ExprMem): + dst = meip return e, [] @@ -4061,7 +4072,6 @@ mnemo_func = {'mov': mov, 'leave': leave, 'enter': enter, 'jmp': jmp, - 'jmpf': jmpf, 'jz': jz, 'je': jz, 'jcxz': jcxz, diff --git a/miasm2/core/cpu.py b/miasm2/core/cpu.py index d304108d..8195f920 100644 --- a/miasm2/core/cpu.py +++ b/miasm2/core/cpu.py @@ -262,7 +262,8 @@ def extract_ast_core(v, my_id2expr, my_int2expr): size = sizes.pop() my_int2expr = lambda x: m2_expr.ExprInt(x, size) else: - raise ValueError('multiple sizes in ids') + # Multiple sizes in ids + raise StopIteration e = ast_raw2expr(ast_tokens, my_id2expr, my_int2expr) return e diff --git a/test/arch/x86/arch.py b/test/arch/x86/arch.py index dfe4ef91..6d20d473 100644 --- a/test/arch/x86/arch.py +++ b/test/arch/x86/arch.py @@ -767,20 +767,41 @@ reg_tests = [ "e830221100"), (m32, "00000000 CALL DWORD PTR [EAX]", "ff10"), + (m32, "00000000 CALL EAX", + "ffd0"), + (m32, "00000000 CALL DWORD PTR [EAX+EBX]", + "ff1403"), + (m32, "00000000 CALL DWORD PTR [EAX+EBX+0x11223344]", + "ff941844332211"), + + + + + (m64, "00000000 CALL QWORD PTR [RAX]", "ff10"), - (m32, "00000000 CALL 0x6655:0x44332211", "9a112233445566"), (m32, "00000000 CALL 0x6655:0xFF332211", "9a112233FF5566"), - (m32, "00000000 CALL DWORD PTR [0xFFFFFFA3]", + (m64, "00000000 CALL QWORD PTR [RAX+RBX]", + "ff1403"), + (m64, "00000000 CALL QWORD PTR [RAX+RBX+0x11223344]", + "ff941844332211"), + + + (m32, "00000000 CALL FAR DWORD PTR [EAX]", + "ff18"), + (m32, "00000000 CALL FAR DWORD PTR [EAX+EBX]", + "ff1c03"), + (m32, "00000000 CALL FAR DWORD PTR [EAX+EBX+0x11223344]", + "ff9c1844332211"), + (m32, "00000000 CALL FAR DWORD PTR [0xFFFFFFA3]", "FF1DA3FFFFFF"), - (m64, "00000000 CALL QWORD PTR [RIP+0xFFFFFFFFFFFFFFA3]", + (m64, "00000000 CALL FAR QWORD PTR [RIP+0xFFFFFFFFFFFFFFA3]", "FF1DA3FFFFFF"), - (m16, "00000000 CBW", "98"), (m16, "00000000 CWDE", @@ -2419,6 +2440,13 @@ reg_tests = [ (m64, "00000000 JMP RDX", "FFE2"), + (m32, "00000000 JMP FAR DWORD PTR [EAX]", + "FF28"), + (m64, "00000000 JMP FAR DWORD PTR [RAX]", + "FF28"), + (m32, "00000000 JMP 0x6655:0x44332211", + "EA112233445566"), + (m32, "00000000 XGETBV", "0f01d0"), |