Repository URL to install this package:
Version:
9.1~250226-5.fc43 ▾
|
# ----------------------------------------------------------------------
# EFI bytecode processor module
# (c) Hex-Rays
# Please send fixes or improvements to support@hex-rays.com
import sys
import struct
from ida_bytes import *
from ida_ua import *
from ida_idp import *
from ida_auto import *
from ida_nalt import *
from ida_funcs import *
from ida_lines import *
from ida_problems import *
from ida_segment import *
from ida_name import *
from ida_netnode import *
from ida_xref import *
from ida_idaapi import *
import ida_frame
import ida_offset
import ida_pro
import idc
if sys.version_info.major < 3:
range = xrange
# extract bitfield occupying bits high..low from val (inclusive, start from 0)
def BITS(val, low, high):
return (val>>low)&((1<<(high-low+1))-1)
# extract one bit
def BIT(val, bit):
return (val>>bit) & 1
# sign extend b low bits in x
# from "Bit Twiddling Hacks"
def SIGNEXT(x, b):
m = 1 << (b - 1)
x = x & ((1 << b) - 1)
return (x ^ m) - m
# check if operand is register reg
def is_reg(op, reg):
return op.type == o_reg and op.reg == reg
# check if operand is immediate value val
def is_imm(op, val):
return op.type == o_imm and op.value == val
# are operands equal?
def same_op(op1, op2):
return op1.type == op2.type and \
op1.reg == op2.reg and \
op1.value == op2.value and \
op1.addr == op2.addr and \
op1.flags == op2.flags and \
op1.specval == op2.specval and \
op1.dtype == op2.dtype
# is sp delta fixed by the user?
def is_fixed_spd(ea):
return (get_aflags(ea) & AFL_FIXEDSPD) != 0
# ----------------------------------------------------------------------
class ebc_processor_t(processor_t):
# IDP id ( Numbers above 0x8000 are reserved for the third-party modules)
id = PLFM_EBC
# Processor features
flag = PR_SEGS | PR_DEFSEG32 | PR_USE32 | PR_USE64 | PRN_HEX | PR_RNAMESOK
# Number of bits in a byte for code segments (usually 8)
# IDA supports values up to 32 bits (64 for IDA64)
cnbits = 8
# Number of bits in a byte for non-code segments (usually 8)
# IDA supports values up to 32 bits (64 for IDA64)
dnbits = 8
# short processor names
# Each name should be shorter than 9 characters
psnames = ['ebc']
# long processor names
# No restriction on name lengthes.
plnames = ['EFI Byte code']
# size of a segment register in bytes
segreg_size = 0
# Array of typical code start sequences (optional)
# codestart = ['\x60\x00'] # 60 00 xx xx: MOVqw SP, SP-delta
# Array of 'return' instruction opcodes (optional)
# retcodes = ['\x04\x00'] # 04 00: RET
# You should define 2 virtual segment registers for CS and DS.
# Let's call them rVcs and rVds.
# icode of the first instruction
instruc_start = 0
#
# Size of long double (tbyte) for this processor
# (meaningful only if ash.a_tbyte != NULL)
#
tbyte_size = 0
# only one assembler is supported
assembler = {
# flag
'flag' : ASH_HEXF3 | AS_UNEQU | AS_COLON | ASB_BINF4 | AS_N2CHR,
# user defined flags (local only for IDP)
# you may define and use your own bits
'uflag' : 0,
# Assembler name (displayed in menus)
'name': "EFI bytecode assembler",
# org directive
'origin': "org",
# end directive
'end': "end",
# comment string (see also cmnt2)
'cmnt': ";",
# ASCII string delimiter
'ascsep': "\"",
# ASCII char constant delimiter
'accsep': "'",
# ASCII special chars (they can't appear in character and ascii constants)
'esccodes': "\"'",
#
# Data representation (db,dw,...):
#
# ASCII string directive
'a_ascii': "db",
# byte directive
'a_byte': "db",
# word directive
'a_word': "dw",
# remove if not allowed
'a_dword': "dd",
# remove if not allowed
'a_qword': "dq",
# remove if not allowed
'a_oword': "xmmword",
# float; 4bytes; remove if not allowed
'a_float': "dd",
# double; 8bytes; NULL if not allowed
'a_double': "dq",
# long double; NULL if not allowed
'a_tbyte': "dt",
# array keyword. the following
# sequences may appear:
# #h - header
# #d - size
# #v - value
# #s(b,w,l,q,f,d,o) - size specifiers
# for byte,word,
# dword,qword,
# float,double,oword
'a_dups': "#d dup(#v)",
# uninitialized data directive (should include '%s' for the size of data)
'a_bss': "%s dup ?",
# 'seg ' prefix (example: push seg seg001)
'a_seg': "seg",
# current IP (instruction pointer) symbol in assembler
'a_curip': "$",
# "public" name keyword. NULL-gen default, ""-do not generate
'a_public': "public",
# "weak" name keyword. NULL-gen default, ""-do not generate
'a_weak': "weak",
# "extrn" name keyword
'a_extrn': "extrn",
# "comm" (communal variable)
'a_comdef': "",
# "align" keyword
'a_align': "align",
# Left and right braces used in complex expressions
'lbrace': "(",
'rbrace': ")",
# % mod assembler time operation
'a_mod': "%",
# & bit and assembler time operation
'a_band': "&",
# | bit or assembler time operation
'a_bor': "|",
# ^ bit xor assembler time operation
'a_xor': "^",
# ~ bit not assembler time operation
'a_bnot': "~",
# << shift left assembler time operation
'a_shl': "<<",
# >> shift right assembler time operation
'a_shr': ">>",
# size of type (format string)
'a_sizeof_fmt': "size %s",
} # Assembler
# ----------------------------------------------------------------------
# Some internal flags used by the decoder, emulator and output
# operand size or move size; can be in both auxpref and OpN.specval
FL_B = 0x0001 # 8 bits
FL_W = 0x0002 # 16 bits
FL_D = 0x0004 # 32 bits
FL_Q = 0x0008 # 64 bits
# OpN.specval
FLo_INDIRECT = 0x0010 # This is an indirect access (not immediate value)
FLo_SIGNED = 0x0020 # This is a signed operand
# insn_t.auxpref flags (NB: only 16 bits!)
FLa_OP1 = 0x0010 # check operand 1
FLa_32 = 0x0020 # Is 32
FLa_64 = 0x0040 # Is 64
FLa_EXTERN = 0x0080 # external call (via thunk)
FLa_ABS = 0x0100 # absolute call
FLa_CS = 0x0200 # Condition flag is set
FLa_NCS = 0x0400 # Condition flag is not set
FLa_CMPMASK = 0xF000 # mask of the CMP[I] comparison
FLa_CMPeq = 0x1000 # compare equal
FLa_CMPlte = 0x2000 # compare signed less than or equal
FLa_CMPgte = 0x3000 # compare signed greater than or equal
FLa_CMPulte = 0x4000 # compare unsigned less than or equal
FLa_CMPugte = 0x5000 # compare unsigned greater than or equal
IMMDATA_16 = 1
IMMDATA_32 = 2
IMMDATA_64 = 3
# ----------------------------------------------------------------------
# Utility functions
#
# ----------------------------------------------------------------------
# set comparison kind (eq/lte/gte/ulte/ugte)
def set_cmp(self, insn, no):
insn.auxpref &= ~self.FLa_CMPMASK
insn.auxpref |= [self.FLa_CMPeq, self.FLa_CMPlte,
self.FLa_CMPgte, self.FLa_CMPulte,
self.FLa_CMPugte][no]
# ----------------------------------------------------------------------
# get comparison kind (eq/lte/gte/ulte/ugte)
def get_cmp(self, insn):
t = insn.auxpref & self.FLa_CMPMASK
if t:
return { self.FLa_CMPeq: "eq",
self.FLa_CMPlte: "lte",
self.FLa_CMPgte: "gte",
self.FLa_CMPulte: "ulte",
self.FLa_CMPugte: "ugte" } [t]
# ----------------------------------------------------------------------
def get_data_width_fl(self, sz):
"""Returns a flag given the data width number"""
if sz == 0: return self.FL_B
elif sz == self.IMMDATA_16: return self.FL_W
elif sz == self.IMMDATA_32: return self.FL_D
elif sz == self.IMMDATA_64: return self.FL_Q
# ----------------------------------------------------------------------
def next_data_value(self, insn, sz):
"""Returns a value depending on the data widh number"""
if sz == 0: return insn.get_next_byte()
elif sz == self.IMMDATA_16: return insn.get_next_word()
elif sz == self.IMMDATA_32: return insn.get_next_dword()
elif sz == self.IMMDATA_64: return insn.get_next_qword()
else: raise Exception("Invalid width!")
# ----------------------------------------------------------------------
def get_data_dt(self, sz):
"""Returns a dt_xxx on the data widh number"""
if sz == 0: return dt_byte
elif sz == self.IMMDATA_16: return dt_word
elif sz == self.IMMDATA_32: return dt_dword
elif sz == self.IMMDATA_64: return dt_qword
else: raise Exception("Invalid width!")
# ----------------------------------------------------------------------
def native_dt(self):
return dt_qword if self.PTRSZ==8 else dt_dword
# ----------------------------------------------------------------------
def get_sz_to_bits(self, sz):
"""Returns size in bits of the data widh number"""
if sz == self.IMMDATA_16: return 16
elif sz == self.IMMDATA_32: return 32
elif sz == self.IMMDATA_64: return 64
else: return 8
# ----------------------------------------------------------------------
def dt_to_bits(self, dt):
"""Returns the size in bits given a dt_xxx"""
if dt == dt_byte: return 8
elif dt == dt_word: return 16
elif dt == dt_dword: return 32
elif dt == dt_qword: return 64
# ----------------------------------------------------------------------
def dt_to_width(self, dt):
"""Returns OOFW_xxx flag given a dt_xxx"""
if dt == dt_byte: return OOFW_8
elif dt == dt_word: return OOFW_16
elif dt == dt_dword: return OOFW_32
elif dt == dt_qword: return OOFW_64
# ----------------------------------------------------------------------
def fl_to_str(self, fl):
"""Given a flag, it returns a string. (used during output)"""
if fl & self.FL_B != 0: return "b"
elif fl & self.FL_W != 0: return "w"
elif fl & self.FL_D != 0: return "d"
elif fl & self.FL_Q != 0: return "q"
# ----------------------------------------------------------------------
def set_ptr_size(self):
"""
Functions checks the database / PE header netnode and sees if the input file
is a PE+ or not. If so, then pointer size is set to 8 bytes.
"""
n = netnode("$ PE header")
s = n.valobj()
if not s:
return
# Extract magic field
t = struct.unpack("<H", s[0x18:0x18+2])[0]
if t == 0x20B:
self.PTRSZ = 8
# ----------------------------------------------------------------------
# Decodes an index and returns all its components in a dictionary
# Refer to "Index Encoding" section
def decode_index(self, index, sz):
N = sz - 1
s = -1 if BIT(index, N) else 1
w = BITS(index, N-3, N-1)
t = sz // 8
A = w * t # width of the natural units field
n = BITS(index, 0, A-1) if A >= 1 else 0 # natural units (n)
c = BITS(index, A, N-4) if N-4 >= A else 0 # constant units (c)
o = (c + (n * self.PTRSZ)) # offset w/o sign
so = o * s # signed final offset
return so
# ----------------------------------------------------------------------
def op_reg(self, op, reg):
op.type = o_reg
op.reg = reg
# ----------------------------------------------------------------------
def op_disp(self, op, reg, d, direct):
op.type = o_displ
op.phrase = reg
op.addr = d if d else 0
if not direct:
op.specval |= self.FLo_INDIRECT
else:
op.specval &= ~self.FLo_INDIRECT
op.specval |= self.FLo_SIGNED
# ----------------------------------------------------------------------
def decode_index_or_data(self, insn, sz, immed):
bs = self.get_sz_to_bits(sz)
d = self.next_data_value(insn, sz)
if not immed:
d = self.decode_index(d, bs)
else:
d = SIGNEXT(d, bs)
return d
# ----------------------------------------------------------------------
def fill_op(self, insn, op, reg, direct, has_imm, immsz, dt = None, index_only = False):
if direct and not has_imm:
self.op_reg(op, reg)
else:
d = self.decode_index_or_data(insn, immsz, direct and not index_only) if has_imm else None
self.op_disp(op, reg, d, direct)
if dt:
insn.Op1.dtype = dt
# ----------------------------------------------------------------------
def fill_op1(self, insn, opbyte, has_imm, immsz, dt = None, index_only = False):
op1_direct = (opbyte & 0x08) == 0
r1 = (opbyte & 0x07)
self.fill_op(insn, insn.Op1, r1, op1_direct, has_imm, immsz, dt, index_only)
# ----------------------------------------------------------------------
def fill_op2(self, insn, opbyte, has_imm, immsz, dt = None, index_only = False):
op2_direct = (opbyte & 0x80) == 0
r2 = (opbyte & 0x70) >> 4
self.fill_op(insn, insn.Op2, r2, op2_direct, has_imm, immsz, dt, index_only)
# ----------------------------------------------------------------------
# Instruction decoding
#
# ----------------------------------------------------------------------
def decode_RET(self, insn, opbyte):
# No operands
insn.Op1.type = o_void
# Consume the next byte, and it should be zero
insn.get_next_byte()
return True
# ----------------------------------------------------------------------
def decode_STORESP(self, insn, opbyte):
# opbyte (byte0) has nothing meaningful (but the opcode itself)
# get next byte
opbyte = insn.get_next_byte()
vm_reg = (opbyte & 0x70) >> 4
gp_reg = (opbyte & 0x07)
insn.Op1.type = insn.Op2.type = o_reg
insn.Op1.dtype = insn.Op2.dtype = dt_qword
insn.Op1.reg = gp_reg
insn.Op2.reg = self.ireg_FLAGS + vm_reg
return True
# ----------------------------------------------------------------------
def decode_LOADSP(self, insn, opbyte):
# opbyte (byte0) has nothing meaningful (but the opcode itself)
# get next byte
opbyte = insn.get_next_byte()
gp_reg = (opbyte & 0x70) >> 4
vm_reg = (opbyte & 0x07)
insn.Op1.type = insn.Op2.type = o_reg
insn.Op1.dtype = insn.Op2.dtype = dt_qword
insn.Op1.reg = self.ireg_FLAGS + vm_reg
insn.Op2.reg = gp_reg
return True
# ----------------------------------------------------------------------
def decode_BREAK(self, insn, opbyte):
"""
stx=<BREAK [break code]>
txt=<The BREAK instruction is used to perform special processing by the VM.>
"""
insn.Op1.type = o_imm
insn.Op1.dtype = dt_byte
insn.Op1.value = insn.get_next_byte()
return True
# ----------------------------------------------------------------------
def cmt_BREAK(self, insn):
s = "Special processing by VM"
if insn.Op1.value == 0:
s += ": runaway program break (null/bad opcode)"
elif insn.Op1.value == 1:
s += ": get virtual machine version in R7"
elif insn.Op1.value == 3:
s += ": debug breakpoint"
elif insn.Op1.value == 4:
s += ": system call (ignored)"
elif insn.Op1.value == 5:
s += ": create thunk (thunk pointer in R7)"
elif insn.Op1.value == 6:
s += ": set compiler version in R7"
else:
s += ": unknown break code"
return s
# ----------------------------------------------------------------------
def decode_PUSH(self, insn, opbyte):
"""
PUSH[32|64] {@}R1 {Index16|Immed16}
PUSHn {@}R1 {Index16|Immed16}
"""
have_data = (opbyte & 0x80) != 0
is_n = (opbyte & ~0xC0) in [0x35, 0x36] # PUSHn, POPn
if is_n:
dt = self.native_dt()
insn.auxpref = 0
else:
op_32 = (opbyte & 0x40) == 0
dt = dt_dword if op_32 else dt_qword
insn.auxpref = self.FLa_32 if op_32 else self.FLa_64
opbyte = insn.get_next_byte()
self.fill_op1(insn, opbyte, have_data, self.IMMDATA_16, dt)
return True
# ----------------------------------------------------------------------
def decode_JMP(self, insn, opbyte):
"""
stx=<JMP32{cs|cc} {@}R1 {Immed32|Index32}>
stx=<JMP64{cs|cc} Immed64>
"""
have_data = (opbyte & 0x80) != 0
jmp_32 = (opbyte & 0x40) == 0
opbyte = insn.get_next_byte()
conditional = (opbyte & 0x80) != 0
cs = (opbyte & 0x40) != 0
abs_jmp = (opbyte & 0x10) == 0
op1_direct = (opbyte & 0x08) == 0
r1 = (opbyte & 0x07)
if jmp_32:
# Indirect and no data specified?
if not op1_direct and not have_data:
return False
self.fill_op1(insn, opbyte, have_data, self.IMMDATA_32, dt_dword)
if insn.Op1.reg == 0:
if op1_direct:
insn.Op1.type = o_near
else:
insn.Op1.type = o_mem
else:
if not have_data:
return False
insn.Op1.type = o_near
insn.Op1.dtype = dt_qword
insn.Op1.addr = insn.get_next_qword()
if not abs_jmp:
if jmp_32:
val = SIGNEXT(insn.Op1.addr, 32)
else:
val = insn.Op1.addr
insn.Op1.addr = TRUNC(val + insn.ea + insn.size)
fl = self.FLa_32 if jmp_32 else self.FLa_64
if conditional:
fl |= self.FLa_CS if cs else self.FLa_NCS
insn.auxpref = fl
return True
# ----------------------------------------------------------------------
def cmt_JMP(self, insn):
s = "Jump to address"
if insn.auxpref & self.FLa_CS:
s += " if condition is true"
elif insn.auxpref & self.FLa_NCS:
s += " if condition is false"
else:
s += " unconditionally"
return s
# ----------------------------------------------------------------------
def decode_JMP8(self, insn, opbyte):
"""
stx=<JMP8{cs|cc} Immed8>
"""
conditional = (opbyte & 0x80) != 0
cs = (opbyte & 0x40) != 0
insn.Op1.type = o_near
insn.Op1.dtype = dt_byte
addr = insn.get_next_byte()
insn.Op1.addr = (SIGNEXT(addr, 8) * 2) + insn.size + insn.ea
if conditional:
insn.auxpref = self.FLa_CS if cs else self.FLa_NCS
return True
# ----------------------------------------------------------------------
def decode_MOVI(self, insn, opbyte):
"""
MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, Immed16|32|64
MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
First character specifies the width of the move and is taken from opcode
Second character specifies the immediate data size and is taken from the opbyte
"""
imm_sz = (opbyte & 0xC0) >> 6
opcode = (opbyte & ~0xC0)
is_MOVIn = opcode == 0x38
# Reserved and should not be 0
if imm_sz == 0:
return False
# take byte 1
opbyte = insn.get_next_byte()
# Bit 7 is reserved and should be 0
if opbyte & 0x80 != 0:
return False
have_idx = (opbyte & 0x40) != 0
move_sz = (opbyte & 0x30) >> 4
direct = (opbyte & 0x08) == 0
r1 = (opbyte & 0x07)
# Cannot have an index with a direct register
if have_idx and direct:
return False
dt = self.native_dt() if is_MOVIn else self.get_data_dt(move_sz)
self.fill_op1(insn, opbyte, have_idx, self.IMMDATA_16, dt)
insn.Op2.type = o_imm
insn.Op2.dtype = self.get_data_dt(imm_sz)
v = self.decode_index_or_data(insn, imm_sz, not is_MOVIn)
if imm_sz == self.IMMDATA_64:
insn.Op2.value64 = v
else:
insn.Op2.value = TRUNC(v)
# save imm size and signal that op1 is defined in first operand
insn.auxpref = self.get_data_width_fl(imm_sz)
if not is_MOVIn:
insn.auxpref |= self.FLa_OP1
insn.Op1.specval |= self.get_data_width_fl(move_sz)
return True
# ----------------------------------------------------------------------
def decode_MOVREL(self, insn, opbyte):
"""
MOVREL[w|d|q] {@}R1 {Index16}, Immed16|32|64
"""
imm_sz = (opbyte & 0xC0) >> 6
# Reserved and should not be 0
if imm_sz == 0:
return False
# take byte 1
opbyte = insn.get_next_byte()
# Bits 7 is reserved and should be 0
# Bits 4 and 5 are supposed to be 0 too, except in real programs they aren't!
if (opbyte & 0x80) != 0:
return False
have_idx = (opbyte & 0x40) != 0
direct = (opbyte & 0x08) == 0
r1 = (opbyte & 0x07)
# Cannot have an index with a direct register
if have_idx and direct:
return False
self.fill_op1(insn, opbyte, have_idx, self.IMMDATA_16, self.get_data_dt(imm_sz))
insn.Op1.specval = self.get_data_width_fl(imm_sz)
insn.Op2.type = o_mem
insn.Op2.dtype = self.get_data_dt(imm_sz)
insn.Op2.addr = self.next_data_value(insn, imm_sz) + insn.size + insn.ea
# save imm size
insn.auxpref = self.get_data_width_fl(imm_sz)
return True
# ----------------------------------------------------------------------
def decode_MOV(self, insn, opbyte):
"""
MOV[b|w|d|q]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
MOVn{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
MOVqq {@}R1 {Index64}, {@}R2 {Index64}
"""
have_idx1 = (opbyte & 0x80) != 0
have_idx2 = (opbyte & 0x40) != 0
opcode = (opbyte & ~0xC0)
# opcode: data move size, index size
m = {
0x1D: (dt_byte, self.IMMDATA_16), #MOVbw
0x1E: (dt_word, self.IMMDATA_16), #MOVww
0x1F: (dt_dword, self.IMMDATA_16), #MOVdw
0x20: (dt_qword, self.IMMDATA_16), #MOVqw
0x21: (dt_byte, self.IMMDATA_32), #MOVbd
0x22: (dt_word, self.IMMDATA_32), #MOVwd
0x23: (dt_dword, self.IMMDATA_32), #MOVdd
0x24: (dt_qword, self.IMMDATA_32), #MOVqd
0x28: (dt_qword, self.IMMDATA_64), #MOVqq
0x32: (self.native_dt(), self.IMMDATA_16), #MOVnw
0x33: (self.native_dt(), self.IMMDATA_32), #MOVnd
}
dt, idx_sz = m[opcode]
# get byte1
opbyte = insn.get_next_byte()
self.fill_op1(insn, opbyte, have_idx1, idx_sz, dt, True)
self.fill_op2(insn, opbyte, have_idx2, idx_sz, dt, True)
return True
# ----------------------------------------------------------------------
def decode_CMP(self, insn, opbyte):
"""
CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
"""
have_data = (opbyte & 0x80) != 0
cmp_32 = (opbyte & 0x40) == 0
opcode = (opbyte & ~0xC0)
opbyte = insn.get_next_byte()
if opbyte & 0x08: # operand 1 indirect is not supported
return False
r1 = (opbyte & 0x07)
dt = dt_dword if cmp_32 else dt_qword
insn.Op1.type = o_reg
insn.Op1.reg = r1
insn.Op1.dtype = dt
self.fill_op2(insn, opbyte, have_data, self.IMMDATA_16, dt)
insn.auxpref = self.FLa_32 if cmp_32 else self.FLa_64
self.set_cmp(insn, opcode - 0x05)
return True
# ----------------------------------------------------------------------
def cmt_CMP(self, insn):
s = "Compare if "
t = insn.auxpref & self.FLa_CMPMASK
s += { self.FLa_CMPeq: "equal",
self.FLa_CMPlte: "less than or equal (signed)",
self.FLa_CMPgte: "greater than or equal (signed)",
self.FLa_CMPulte: "less than or equal (unsigned)",
self.FLa_CMPugte: "greater than or equal (unsigned)" } [t]
return s
# ----------------------------------------------------------------------
def decode_CMPI(self, insn, opbyte):
"""
CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}R1 {Index16}, Immed16|Immed32
"""
imm_sz = self.IMMDATA_16 if (opbyte & 0x80) == 0 else self.IMMDATA_32
cmp_32 = (opbyte & 0x40) == 0
opcode = (opbyte & ~0xC0)
opbyte = insn.get_next_byte()
have_idx = (opbyte & 0x10) != 0
dt = dt_dword if cmp_32 else dt_qword
self.fill_op1(insn, opbyte, have_idx, self.IMMDATA_16, dt)
insn.Op2.type = o_imm
insn.Op2.value = self.next_data_value(insn, imm_sz)
insn.Op2.dtype = dt
insn.auxpref = (self.FLa_32 if cmp_32 else self.FLa_64) | self.get_data_width_fl(imm_sz)
self.set_cmp(insn, opcode - 0x2D)
return True
# ----------------------------------------------------------------------
def decode_CALL(self, insn, opbyte):
"""
stx=<CALL32{EX}{a} {@}R1 {Immed32|Index32}>
stx=<CALL64{EX}{a} Immed64>
"""
have_data = (opbyte & 0x80) != 0
call_32 = (opbyte & 0x40) == 0
opbyte = insn.get_next_byte()
# Call to EBC or Native code
ebc_call = (opbyte & 0x20) == 0
# Absolute or Relative address
abs_addr = (opbyte & 0x10) == 0
# Op1 direct?
op1_direct = (opbyte & 0x08) == 0
r1 = (opbyte & 0x07)
if call_32:
self.fill_op1(insn, opbyte, have_data, self.IMMDATA_32, dt_dword)
if have_data and insn.Op1.reg == 0:
insn.Op1.type = o_near
if not abs_addr:
val = SIGNEXT(insn.Op1.addr & 0xFFFFFFFF, 32)
insn.Op1.addr = val + insn.ea + insn.size
# 64-bit
else:
insn.Op1.type = o_near
insn.Op1.dtype = dt_qword
insn.Op1.addr = self.next_data_value(insn, self.IMMDATA_64) # Get 64-bit value
if not abs_addr:
insn.Op1.addr = TRUNC(insn.Op1.addr + insn.ea + insn.size)
fl = self.FLa_EXTERN if not ebc_call else 0
fl |= self.FLa_32 if call_32 else self.FLa_64
if abs_addr:
fl |= self.FLa_ABS
insn.auxpref = fl
return True
# ----------------------------------------------------------------------
def cmt_CALL(self, insn):
if insn.auxpref & self.FLa_EXTERN:
s = "Call an external subroutine (via thunk)"
else:
s = "Call a subroutine"
if insn.auxpref & self.FLa_ABS:
s += " [absolute addressing]"
return s
# ----------------------------------------------------------------------
def decode_BINOP_FORM1(self, insn, opbyte):
"""
op[32|64] {@}R1, {@}R2 {Index16|Immed16}
"""
have_data = (opbyte & 0x80) != 0
op_32 = (opbyte & 0x40) == 0
opcode = (opbyte & ~0xC0)
opbyte = insn.get_next_byte()
op2_direct = (opbyte & 0x80) == 0
op1_direct = (opbyte & 0x08) == 0
r1 = (opbyte & 0x07)
r2 = (opbyte & 0x70) >> 4
dt = dt_dword if op_32 else dt_qword
self.fill_op1(insn, opbyte, False, 0, dt)
self.fill_op2(insn, opbyte, have_data, self.IMMDATA_16, dt)
insn.auxpref = self.FLa_32 if op_32 else self.FLa_64
return True
# ----------------------------------------------------------------------
def decode_MOVSN(self, insn, opbyte):
"""
MOVsn{w} {@}R1 {Index16}, {@}R2 {Index16|Immed16}
MOVsn{d} {@}R1 {Index32}, {@}R2 {Index32|Immed32}
"""
have_idx1 = (opbyte & 0x80) != 0
have_idx2 = (opbyte & 0x40) != 0
opcode = (opbyte & ~0xC0)
if opcode == 0x25:
idx_sz = self.IMMDATA_16
elif opcode == 0x26:
idx_sz = self.IMMDATA_32
else:
return False
opbyte = insn.get_next_byte()
self.fill_op1(insn, opbyte, have_idx1, idx_sz, self.native_dt())
self.fill_op2(insn, opbyte, have_idx2, idx_sz, self.native_dt())
return True
# ----------------------------------------------------------------------
# Processor module callbacks
#
# ----------------------------------------------------------------------
def ev_get_frame_retsize(self, frsize, pfn):
ida_pro.int_pointer.frompointer(frsize).assign(16)
return 1
# ----------------------------------------------------------------------
def ev_get_autocmt(self, insn):
if 'cmt' in self.instruc[insn.itype]:
return self.instruc[insn.itype]['cmt'](insn)
# ----------------------------------------------------------------------
def ev_can_have_type(self, op):
return 1 if op.type in [o_imm, o_displ, o_mem] else 0
# ----------------------------------------------------------------------
def ev_is_align_insn(self, ea):
return 2 if get_word(ea) == 0 else 0
# ----------------------------------------------------------------------
def ev_newfile(self, filename):
self.set_ptr_size()
return 0
# ----------------------------------------------------------------------
def ev_oldfile(self, filename):
self.set_ptr_size()
return 0
# ----------------------------------------------------------------------
def ev_out_header(self, ctx):
ctx.out_line("; natural unit size: %d bits" % (self.PTRSZ*8))
ctx.flush_outbuf(0)
return 1
# ----------------------------------------------------------------------
def ev_may_be_func(self, insn, state):
if is_reg(insn.Op1, self.ireg_SP) and insn.Op2.type == o_displ and\
insn.Op2.phrase == self.ireg_SP and (insn.Op2.specval & self.FLo_INDIRECT) == 0:
# mov SP, SP+delta
if SIGNEXT(insn.Op2.addr, self.PTRSZ*8) < 0:
return 100
else:
return 0
return 10
# ----------------------------------------------------------------------
def check_thunk(self, addr):
"""
Check for EBC thunk at addr
dd fnaddr - (addr+4), 0, 0, 0
"""
delta = get_dword(addr)
fnaddr = (delta + addr + 4) & 0xFFFFFFFF
if is_off(get_flags(addr), 0):
# already an offset
if ida_offset.get_offbase(addr, 0) == addr + 4:
return fnaddr
else:
return None
# should be followed by three zeroes
if delta == 0 or get_dword(addr+4) != 0 or\
get_dword(addr+8) != 0 or get_dword(addr+12) != 0:
return None
if segtype(fnaddr) == SEG_CODE:
# looks good, create the offset
idc.create_dword(addr)
if ida_offset.op_offset(addr, 0, REF_OFF32|REFINFO_NOBASE, BADADDR, addr + 4):
return fnaddr
else:
return None
# ----------------------------------------------------------------------
def handle_operand(self, insn, op, isRead):
F = get_flags(insn.ea)
is_offs = is_off(F, op.n)
dref_flag = dr_R if isRead else dr_W
def_arg = is_defarg(F, op.n)
optype = op.type
# create code xrefs
if optype == o_imm:
if is_offs:
insn.add_off_drefs(op, dr_O, 0)
# create data xrefs
elif optype == o_displ:
# reg + delta
if is_offs:
insn.add_off_drefs(op, dref_flag, OOF_ADDR)
elif may_create_stkvars() and not def_arg and op.reg == self.ireg_SP:
# ignore prolog/epilog
# MOVqw SP, SP+delta
if is_reg(insn.Op1, self.ireg_SP):
pass
else:
pfn = get_func(insn.ea)
# [SP+var_x] (indirect)
# SP+var_x (direct)
flag = STKVAR_VALID_SIZE if (op.specval & self.FLo_INDIRECT) else 0
if pfn and insn.create_stkvar(op, op.addr, flag):
op_stkvar(insn.ea, op.n)
elif optype == o_mem:
if insn.itype == self.itype_MOVREL:
dref_flag = dr_O
self.check_thunk(op.addr)
else:
insn.create_op_data(op.addr, op)
insn.add_dref(op.addr, op.offb, dref_flag)
elif optype == o_near:
itype = insn.itype
if itype == self.itype_CALL:
fl = fl_CN
else:
fl = fl_JN
insn.add_cref(op.addr, op.offb, fl)
# ----------------------------------------------------------------------
def add_stkpnt(self, insn, pfn, v):
if pfn:
end = insn.ea + insn.size
if not is_fixed_spd(end):
ida_frame.add_auto_stkpnt(pfn, end, v)
# ----------------------------------------------------------------------
def trace_sp(self, insn):
"""
Trace the value of the SP and create an SP change point if the current
instruction modifies the SP.
"""
pfn = get_func(insn.ea)
if not pfn:
return
if is_reg(insn.Op1, self.ireg_SP) and insn.itype in [self.itype_MOVbw, self.itype_MOVww,
self.itype_MOVdw, self.itype_MOVqw, self.itype_MOVbd,
self.itype_MOVwd, self.itype_MOVdd, self.itype_MOVqd,
self.itype_MOVsnw, self.itype_MOVsnd, self.itype_MOVqq]:
# MOVqw SP, SP-0x30
# MOVqw SP, SP+0x30
if insn.Op2.type == o_displ and insn.Op2.phrase == self.ireg_SP and (insn.Op2.specval & self.FLo_INDIRECT) == 0:
spofs = SIGNEXT(insn.Op2.addr, self.PTRSZ*8)
self.add_stkpnt(insn, pfn, spofs)
elif insn.itype in [self.itype_PUSH, self.itype_PUSHn]:
spofs = self.dt_to_bits(insn.Op1.dtype) // 8
self.add_stkpnt(insn, pfn, -spofs)
elif insn.itype in [self.itype_POP, self.itype_POPn]:
spofs = self.dt_to_bits(insn.Op1.dtype) // 8
self.add_stkpnt(insn, pfn, spofs)
# ----------------------------------------------------------------------
def ev_emu_insn(self, insn):
aux = self.get_auxpref(insn)
Feature = insn.get_canon_feature()
if Feature & CF_USE1:
self.handle_operand(insn, insn.Op1, 1)
if Feature & CF_CHG1:
self.handle_operand(insn, insn.Op1, 0)
if Feature & CF_USE2:
self.handle_operand(insn, insn.Op2, 1)
if Feature & CF_CHG2:
self.handle_operand(insn, insn.Op2, 0)
if Feature & CF_JUMP:
remember_problem(PR_JUMP, insn.ea)
# is it an unconditional jump?
uncond_jmp = insn.itype in [self.itype_JMP8, self.itype_JMP] and (aux & (self.FLa_NCS|self.FLa_CS)) == 0
# add flow
flow = (Feature & CF_STOP == 0) and not uncond_jmp
if flow:
add_cref(insn.ea, insn.ea + insn.size, fl_F)
# trace the stack pointer if:
# - it is the second analysis pass
# - the stack pointer tracing is allowed
if may_trace_sp():
if flow:
self.trace_sp(insn) # trace modification of SP register
else:
idc.recalc_spd(insn.ea) # recalculate SP register for the next insn
return True
# ----------------------------------------------------------------------
def ev_out_operand(self, ctx, op):
"""
Generate text representation of an instructon operand.
This function shouldn't change the database, flags or anything else.
All these actions should be performed only by u_emu() function.
The output text is placed in the output buffer initialized with init_output_buffer()
This function uses out_...() functions from ua.hpp to generate the operand text
Returns: 1-ok, 0-operand is hidden.
"""
optype = op.type
fl = op.specval
signed = OOF_SIGNED if fl & self.FLo_SIGNED != 0 else 0
def_arg = is_defarg(get_flags(ctx.insn.ea), op.n)
if optype == o_reg:
ctx.out_register(self.reg_names[op.reg])
elif optype == o_imm:
# for immediate loads, use the transfer width (type of first operand)
if op.n == 1:
width = self.dt_to_width(ctx.insn.Op1.dtype)
else:
width = OOFW_32 if self.PTRSZ == 4 else OOFW_64
ctx.out_value(op, OOFW_IMM | signed | width)
elif optype in [o_near, o_mem]:
r = ctx.out_name_expr(op, op.addr, BADADDR)
if not r:
ctx.out_tagon(COLOR_ERROR)
ctx.out_btoa(op.addr, 16)
ctx.out_tagoff(COLOR_ERROR)
remember_problem(PR_NONAME, ctx.insn.ea)
elif optype == o_displ:
indirect = fl & self.FLo_INDIRECT != 0
if indirect:
ctx.out_symbol('[')
ctx.out_register(self.reg_names[op.reg])
if op.addr != 0 or def_arg:
ctx.out_value(op, OOF_ADDR | (OOFW_32 if self.PTRSZ == 4 else OOFW_64) | signed | OOFS_NEEDSIGN)
if indirect:
ctx.out_symbol(']')
else:
return False
return True
# ----------------------------------------------------------------------
# Generate the instruction mnemonics
def ev_out_mnem(self, ctx):
# Init output buffer
postfix = ""
# First display size of first operand if it exists
if ctx.insn.auxpref & self.FLa_OP1 != 0:
postfix += self.fl_to_str(ctx.insn.Op1.specval)
# Display opertion size
if ctx.insn.auxpref & self.FLa_32:
postfix += "32"
elif ctx.insn.auxpref & self.FLa_64:
postfix += "64"
# Display if local or extern CALL
if ctx.insn.auxpref & self.FLa_EXTERN:
postfix += "EX"
# Display if absolute call
if ctx.insn.auxpref & self.FLa_ABS:
postfix += "a"
# Display size of instruction
if ctx.insn.auxpref & (self.FL_B | self.FL_W | self.FL_D | self.FL_Q) != 0:
postfix += self.fl_to_str(ctx.insn.auxpref)
# Display JMP condition
if ctx.insn.auxpref & self.FLa_CS:
postfix += "cs"
elif ctx.insn.auxpref & self.FLa_NCS:
postfix += "cc"
# Display CMP condition
if ctx.insn.auxpref & self.FLa_CMPMASK:
postfix += self.get_cmp(ctx.insn)
ctx.out_mnem(12, postfix)
return 1
# ----------------------------------------------------------------------
# Generate text representation of an instruction in 'ctx.insn' structure.
# This function shouldn't change the database, flags or anything else.
# All these actions should be performed only by u_emu() function.
def ev_out_insn(self, ctx):
ctx.out_mnemonic()
ctx.out_one_operand(0)
for i in range(1, 3):
op = ctx.insn[i]
if op.type == o_void:
break
ctx.out_symbol(',')
ctx.out_char(' ')
ctx.out_one_operand(i)
if ctx.insn.itype == self.itype_MOVREL:
fnaddr = self.check_thunk(ctx.insn.Op2.addr)
if fnaddr != None:
nm = get_ea_name(fnaddr, GN_VISIBLE)
if nm:
ctx.out_line("; Thunk to " + nm, COLOR_AUTOCMT)
ctx.set_gen_cmt()
ctx.flush_outbuf()
return True
# ----------------------------------------------------------------------
def ev_ana_insn(self, insn):
"""
Decodes an instruction into insn
"""
# take opcode byte
b = insn.get_next_byte()
# the 6bit opcode
opcode = b & 0x3F
# opcode supported?
try:
ins = self.itable[opcode]
# set default itype
insn.itype = getattr(self, 'itype_' + ins.name)
except:
return 0
# call the decoder
return True if ins.d(insn, b) else False
# ----------------------------------------------------------------------
def init_instructions(self):
class idef:
"""
Internal class that describes an instruction by:
- instruction name
- instruction decoding routine
- canonical flags used by IDA
"""
def __init__(self, name, cf, d, cmt = None):
self.name = name
self.cf = cf
self.d = d
self.cmt = cmt
#
# Instructions table (w/ pointer to decoder)
#
self.itable = {
0x00: idef(name='BREAK', d=self.decode_BREAK, cf = CF_USE1, cmt = self.cmt_BREAK),
0x01: idef(name='JMP', d=self.decode_JMP, cf = CF_USE1 | CF_JUMP, cmt = self.cmt_JMP),
0x02: idef(name='JMP8', d=self.decode_JMP8, cf = CF_USE1 | CF_JUMP, cmt = self.cmt_JMP),
0x03: idef(name='CALL', d=self.decode_CALL, cf = CF_USE1 | CF_CALL, cmt = self.cmt_CALL),
0x04: idef(name='RET', d=self.decode_RET, cf = CF_STOP, cmt = lambda insn: "Return from subroutine" ),
0x05: idef(name='CMP', d=self.decode_CMP, cf = CF_USE1 | CF_USE2, cmt = self.cmt_CMP),
0x06: idef(name='CMP', d=self.decode_CMP, cf = CF_USE1 | CF_USE2, cmt = self.cmt_CMP),
0x07: idef(name='CMP', d=self.decode_CMP, cf = CF_USE1 | CF_USE2, cmt = self.cmt_CMP),
0x08: idef(name='CMP', d=self.decode_CMP, cf = CF_USE1 | CF_USE2, cmt = self.cmt_CMP),
0x09: idef(name='CMP', d=self.decode_CMP, cf = CF_USE1 | CF_USE2, cmt = self.cmt_CMP),
0x0A: idef(name='NOT', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Op1 = ~Op2" ),
0x0B: idef(name='NEG', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Op1 = -Op2" ),
0x0C: idef(name='ADD', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Op1 += Op2" ),
0x0D: idef(name='SUB', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Op1 -= Op2" ),
0x0E: idef(name='MUL', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Op1 *= Op2 (signed multiply)" ),
0x0F: idef(name='MULU', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Op1 *= Op2 (unsigned multiply)" ),
0x10: idef(name='DIV', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Op1 /= Op2 (signed division)" ),
0x11: idef(name='DIVU', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Op1 /= Op2 (unsigned division)" ),
0x12: idef(name='MOD', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Op1 %= Op2 (signed modulo)" ),
0x13: idef(name='MODU', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Op1 %= Op2 (unsigned modulo)" ),
0x14: idef(name='AND', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Op1 &= Op2" ),
0x15: idef(name='OR', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Op1 |= Op2" ),
0x16: idef(name='XOR', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Op1 ^= Op2" ),
0x17: idef(name='SHL', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1 | CF_SHFT, cmt = lambda insn: "Op1 <<= Op2" ),
0x18: idef(name='SHR', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1 | CF_SHFT, cmt = lambda insn: "Op1 >>= Op2 (unsigned shift)" ),
0x19: idef(name='ASHR', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1 | CF_SHFT, cmt = lambda insn: "Op1 >>= Op2 (signed shift)" ),
0x1A: idef(name='EXTNDB', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Sign-extend a byte value" ),
0x1B: idef(name='EXTNDW', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Sign-extend a word value" ),
0x1C: idef(name='EXTNDD', d=self.decode_BINOP_FORM1, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Sign-extend a dword value" ),
0x1D: idef(name='MOVbw', d=self.decode_MOV, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move byte" ),
0x1E: idef(name='MOVww', d=self.decode_MOV, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move word" ),
0x1F: idef(name='MOVdw', d=self.decode_MOV, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move dword" ),
0x20: idef(name='MOVqw', d=self.decode_MOV, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move qword" ),
0x21: idef(name='MOVbd', d=self.decode_MOV, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move byte" ),
0x22: idef(name='MOVwd', d=self.decode_MOV, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move word" ),
0x23: idef(name='MOVdd', d=self.decode_MOV, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move dword" ),
0x24: idef(name='MOVqd', d=self.decode_MOV, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move qword" ),
0x25: idef(name='MOVsnw', d=self.decode_MOVSN, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move signed natural value"),
0x26: idef(name='MOVsnd', d=self.decode_MOVSN, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move signed natural value"),
# 0x27: reserved
0x28: idef(name='MOVqq', d=self.decode_MOV, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move qword" ),
0x29: idef(name='LOADSP', d=self.decode_LOADSP, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Load a VM dedicated register from a general-purpose register"),
0x2A: idef(name='STORESP', d=self.decode_STORESP, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Store a VM dedicated register into a general-purpose register"),
# PUSH/POP
0x2B: idef(name='PUSH', d=self.decode_PUSH, cf = CF_USE1, cmt = lambda insn: "Push value on the stack" ),
0x2C: idef(name='POP', d=self.decode_PUSH, cf = CF_USE1, cmt = lambda insn: "Pop value from the stack" ),
# CMPI
0x2D: idef(name='CMPI', d=self.decode_CMPI, cf = CF_USE1 | CF_USE2, cmt = self.cmt_CMP),
0x2E: idef(name='CMPI', d=self.decode_CMPI, cf = CF_USE1 | CF_USE2, cmt = self.cmt_CMP),
0x2F: idef(name='CMPI', d=self.decode_CMPI, cf = CF_USE1 | CF_USE2, cmt = self.cmt_CMP),
0x30: idef(name='CMPI', d=self.decode_CMPI, cf = CF_USE1 | CF_USE2, cmt = self.cmt_CMP),
0x31: idef(name='CMPI', d=self.decode_CMPI, cf = CF_USE1 | CF_USE2, cmt = self.cmt_CMP),
0x32: idef(name='MOVnw', d=self.decode_MOV, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move unsigned natural value"),
0x33: idef(name='MOVnd', d=self.decode_MOV, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move unsigned natural value"),
# 0x34: reserved
# PUSHn/POPn
0x35: idef(name='PUSHn', d=self.decode_PUSH, cf = CF_USE1, cmt = lambda insn: "Push natural value on the stack" ),
0x36: idef(name='POPn', d=self.decode_PUSH, cf = CF_USE1, cmt = lambda insn: "Pop natural value from the stack" ),
0x37: idef(name='MOVI', d=self.decode_MOVI, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move immediate value"),
0x38: idef(name='MOVIn', d=self.decode_MOVI, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Move immediate value"),
0x39: idef(name='MOVREL', d=self.decode_MOVREL, cf = CF_USE1 | CF_USE2 | CF_CHG1, cmt = lambda insn: "Load IP-relative address")
# 0x3A: reserved
# 0x3B: reserved
# 0x3C: reserved
# 0x3D: reserved
# 0x3E: reserved
# 0x3F: reserved
}
# Now create an instruction table compatible with IDA processor module requirements
Instructions = []
i = 0
for x in self.itable.values():
d = dict(name=x.name, feature=x.cf)
if x.cmt != None:
d['cmt'] = x.cmt
Instructions.append(d)
setattr(self, 'itype_' + x.name, i)
i += 1
# icode of the last instruction + 1
self.instruc_end = len(Instructions)
# Array of instructions
self.instruc = Instructions
# Icode of return instruction. It is ok to give any of possible return
# instructions
self.icode_return = self.itype_RET
# ----------------------------------------------------------------------
def init_registers(self):
"""This function parses the register table and creates corresponding ireg_XXX constants"""
# Registers definition
self.reg_names = [
# General purpose registers
"SP", # aka R0
"R1",
"R2",
"R3",
"R4",
"R5",
"R6",
"R7",
# VM registers
"FLAGS", # 0
"IP", # 1
"VM2",
"VM3",
"VM4",
"VM5",
"VM6",
"VM7",
# Fake segment registers
"CS",
"DS"
]
# Create the ireg_XXXX constants
for i in range(len(self.reg_names)):
setattr(self, 'ireg_' + self.reg_names[i], i)
# Segment register information (use virtual CS and DS registers if your
# processor doesn't have segment registers):
self.reg_first_sreg = self.ireg_CS
self.reg_last_sreg = self.ireg_DS
# number of CS register
self.reg_code_sreg = self.ireg_CS
# number of DS register
self.reg_data_sreg = self.ireg_DS
# ----------------------------------------------------------------------
def __init__(self):
processor_t.__init__(self)
self.PTRSZ = 4 # Assume PTRSZ = 4 by default
self.init_instructions()
self.init_registers()
# ----------------------------------------------------------------------
def PROCESSOR_ENTRY():
return ebc_processor_t()