Skip to content

Instantly share code, notes, and snippets.

@marekr
Created August 9, 2014 03:39
Show Gist options
  • Save marekr/b69aa80f1c70b07e1a87 to your computer and use it in GitHub Desktop.
Save marekr/b69aa80f1c70b07e1a87 to your computer and use it in GitHub Desktop.
IDA processor module. Creator: Charlie Miller
----------------------------------------------------------------------
# Processor module template script
# (c) Hex-Rays
import sys
import idaapi
from idaapi import *
# define RAM starting at 18000h of size 100h
# define ROM starting at 0 of size 12100h
# The extra 100 is for the first page of data memory
# ----------------------------------------------------------------------
class sample_processor_t(idaapi.processor_t):
"""
Processor module classes must derive from idaapi.processor_t
The required and optional attributes/callbacks are illustrated in this template
"""
# IDP id ( Numbers above 0x8000 are reserved for the third-party modules)
id = 0x8000 + 1
# Processor features
flag = PR_ASSEMBLE | PR_SEGS | PR_DEFSEG32 | PR_USE32 | PRN_HEX | PR_RNAMESOK | PR_NO_SEGMOVE
# Number of bits in a byte for code segments (usually 8)
# IDA supports values up to 32 bits
cnbits = 8
# Number of bits in a byte for non-code segments (usually 8)
# IDA supports values up to 32 bits
dnbits = 8
# short processor names
# Each name should be shorter than 9 characters
psnames = ['bq20z80']
# long processor names
# No restriction on name lengthes.
plnames = ['Texas Instruments Gas Gauge']
# register names
regNames = [
'i0l',
'i0h',
'i1l',
'i1h',
'i2l',
'i2h',
'i3l',
'i3h',
'ipl',
'iph',
'stat',
'r3',
'r2',
'r1',
'r0',
'a',
'ip',
'CS',
'DS',
'i0',
'i1',
'i2',
'i3'
]
# number of registers (optional: deduced from the len(regNames))
regsNum = len(regNames)
# Segment register information (use virtual CS and DS registers if your
# processor doesn't have segment registers):
regFirstSreg = 17 # index of CS
regLastSreg = 18 # index of DS
# size of a segment register in bytes
segreg_size = 0
# You should define 2 virtual segment registers for CS and DS.
# number of CS/DS registers
regCodeSreg = 17
regDataSreg = 18
# Array of typical code start sequences (optional)
# codestart = ['\x55\x8B', '\x50\x51']
# Array of 'return' instruction opcodes (optional)
retcodes = ['\ff\xff\x23']
# Array of instructions
instruc = [
{'name': 'add', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Addition without Carry"},
{'name': 'addc', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Addition with Carry"},
{'name': 'and', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Logical AND"},
{'name': 'call', 'feature': CF_USE1 | CF_CALL, 'cmt': "Jump to Subroutine"},
{'name': 'calls', 'feature': CF_USE1 | CF_CALL, 'cmt': "Jump to Subroutine, ip as Return Address"},
{'name': 'cmp', 'feature': CF_USE1 | CF_USE2, 'cmt': "Unsigned Compare"},
{'name': 'cmpa', 'feature': CF_USE1 | CF_USE2, 'cmt': "Signed Compare"},
{'name': 'cmvd', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Conditional Move, if Carry Clear"},
{'name': 'cmvs', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Conditional Move, if Carry Set"},
{'name': 'cpl1', 'feature': CF_USE1 | CF_CHG1, 'cmt': "One's Complementation"},
{'name': 'cpl2', 'feature': CF_USE1 | CF_CHG1, 'cmt': "Two's Complementation"},
{'name': 'cpl2c', 'feature': CF_USE1 | CF_CHG1, 'cmt': "Two's Complemenation with Carry"},
{'name': 'dec', 'feature': CF_USE1 | CF_CHG1, 'cmt': "Decrementation wihtout Carry"},
{'name': 'decc', 'feature': CF_USE1 | CF_CHG1, 'cmt': "Decrementation with Carry"},
{'name': 'freq', 'feature': CF_USE1, 'cmt': "Frequency Division Selection"},
{'name': 'halt', 'feature': 0, 'cmt': "Halt mode Selection"},
{'name': 'inc', 'feature': CF_USE1 | CF_CHG1, 'cmt': "Incrementation without Carry"},
{'name': 'incc', 'feature': CF_USE1 | CF_CHG1, 'cmt': "Incrementation with Carry"},
{'name': 'jgt', 'feature': CF_USE1, 'cmt': "Jump upon Condtion"},
{'name': 'jge', 'feature': CF_USE1, 'cmt': "Jump upon Condtion"},
{'name': 'jne', 'feature': CF_USE1, 'cmt': "Jump upon Condtion"},
{'name': 'jump', 'feature': CF_USE1, 'cmt': "Jump upon Condtion"},
{'name': 'jle', 'feature': CF_USE1, 'cmt': "Jump upon Condtion"},
{'name': 'jlt', 'feature': CF_USE1, 'cmt': "Jump upon Condtion"},
{'name': 'jeq', 'feature': CF_USE1, 'cmt': "Jump upon Condtion"},
{'name': 'jevt', 'feature': CF_USE1, 'cmt': "Jump upon Condtion"},
{'name': 'move', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Data Move"},
{'name': 'mul', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Unsigned Multiplication"},
{'name': 'mula', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Signed Mulitplication"},
{'name': 'nop', 'feature': 0, 'cmt': "No operation"},
{'name': 'or', 'feature': CF_USE1 | CF_USE2 | CF_CHG1 | CF_USE3, 'cmt': "Logical OR"},
{'name': 'pmd', 'feature': 0, 'cmt': "Program Memory Dump"},
{'name': 'pop', 'feature': 0, 'cmt': "Pop ip Index from Hardware Stack"},
{'name': 'push', 'feature': 0, 'cmt': "Push ip Index onto Hardware Stack"},
{'name': 'ret', 'feature': CF_STOP, 'cmt': "Return from Subroutine"},
{'name': 'reti', 'feature': CF_STOP, 'cmt': "Return from Interrupt"},
{'name': 'sflag', 'feature': 0, 'cmt': "Save Flags"},
{'name': 'shl', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Logical Shift Left without Carry"},
{'name': 'shlc', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Logical Shift Left with Carry"},
{'name': 'shr', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Logical Shift Right without carry"},
{'name': 'shra', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Arithmetic Shift Right"},
{'name': 'shrc', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Logical Shift Right with Carry"},
{'name': 'subd', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Subtraction without Carry"},
{'name': 'subdc', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Subtraction with Carry"},
{'name': 'subs', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Subtraction without Carry"},
{'name': 'subsc', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Subtraction with Carry"},
{'name': 'tstb', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Test Bit"},
{'name': 'xor', 'feature': CF_USE1 | CF_USE2 | CF_CHG1, 'cmt': "Logical Exclusive OR"},
{'name': 'rets', 'feature': CF_STOP, 'cmt': "Return from subroutine (jump IP)"}
]
# icode of the first instruction
instruc_start = 0
# icode of the last instruction + 1
instruc_end = len(instruc) + 1
# Icode of return instruction. It is ok to give any of possible return
# instructions
for x in instruc:
if x['name'] == 'ret':
icode_return = instruc.index(x)
#
# here
#
# 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) (optional)
'uflag' : 0,
# Assembler name (displayed in menus)
'name': "My processor module bytecode assembler",
# array of automatically generated header lines they appear at the start of disassembled text (optional)
'header': ["Line1", "Line2"],
# array of unsupported instructions (array of cmd.itype) (optional)
# 'badworks': [6, 11],
# 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",
# packed decimal real; remove if not allowed (optional)
'a_packreal': "",
# 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 ?",
# 'equ' Used if AS_UNEQU is set (optional)
'a_equ': ".equ",
# 'seg ' prefix (example: push seg seg001)
'a_seg': "seg",
#
# translation to use in character and string constants.
# usually 1:1, i.e. trivial translation
# If specified, must be 256 chars long
# (optional)
# 'XlatAsciiOutput': [chr(x) for x in xrange(256)],
# 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) (optional)
'a_sizeof_fmt': "size %s",
'flag2': 0,
# comment close string (optional)
# this is used to denote a string which closes comments, for example, if the comments are represented with (* ... *)
# then cmnt = "(*" and cmnt2 = "*)"
'cmnt2': "",
# low8 operation, should contain %s for the operand (optional fields)
'low8': "",
'high8': "",
'low16': "",
'high16': "",
# the include directive (format string) (optional)
'a_include_fmt': "include %s",
# if a named item is a structure and displayed in the verbose (multiline) form then display the name
# as printf(a_strucname_fmt, typename)
# (for asms with type checking, e.g. tasm ideal)
# (optional)
'a_vstruc_fmt': "",
# 3-byte data (optional)
'a_3byte': "",
# 'rva' keyword for image based offsets (optional)
# (see nalt.hpp, REFINFO_RVA)
'a_rva': "rva"
} # Assembler
# ----------------------------------------------------------------------
# The following callbacks are optional.
# *** Please remove the callbacks that you don't plan to implement ***
def get_frame_retsize(self, func_ea):
"""
Get size of function return address in bytes
If this function is absent, the kernel will assume
4 bytes for 32-bit function
2 bytes otherwise
"""
return 2
# ----------------------------------------------------------------------
# The following callbacks are mandatory
#
def emu(self):
"""
Emulate instruction, create cross-references, plan to analyze
subsequent instructions, modify flags etc. Upon entrance to this function
all information about the instruction is in 'cmd' structure.
If zero is returned, the kernel will delete the instruction.
"""
aux = self.get_auxpref()
Feature = self.cmd.get_canon_feature()
# is it an unconditional jump?
uncond_jmp = False
if self.cmd.itype == self.get_instruction('jump'):
uncond_jmp = True
# is it a jump?
ujmps = ['jgt', 'jge', 'jne', 'jle', 'jlt', 'jeq', 'jevt', 'jump']
if self.instruc[self.cmd.itype]['name'] in ujmps:
if self.cmd.Op1.addr != 0x0:
ua_add_cref(self.cmd.Op1.offb, self.cmd.Op1.addr, fl_JN)
# is it a call?
calls = ['call', 'calls']
if self.instruc[self.cmd.itype]['name'] in calls:
if self.cmd.Op1.addr != 0x0:
ua_add_cref(self.cmd.Op1.offb, self.cmd.Op1.addr, fl_CN)
# add flow
flow = (Feature & CF_STOP == 0) and not uncond_jmp
if flow:
ua_add_cref(0, self.cmd.ea + self.cmd.size, fl_F)
# add data xref
if self.cmd.Op1.specflag2 == 1:
ua_add_dref(0, self.cmd.Op1.addr, dr_W)
if self.cmd.Op2.specflag2 == 1:
ua_add_dref(0, self.cmd.Op2.addr, dr_W)
return 1
def outop(self, 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 = 0
if optype == o_reg:
out_register(self.regNames[op.reg])
elif optype == o_imm:
out_symbol('#')
width = OOFW_8
OutValue(op, OOFW_IMM | signed | width )
elif optype in [o_near, o_mem]:
r = out_name_expr(op, op.addr, BADADDR)
if not r:
out_tagon(COLOR_ERROR)
OutLong(op.addr, 16)
out_tagoff(COLOR_ERROR)
QueueMark(Q_noName, self.cmd.ea)
elif optype == o_displ:
if op.specflag1 == -1:
out_symbol('-')
out_symbol('(')
out_register(self.regNames[op.reg])
if op.addr != 1 and op.addr != 0xff:
out_symbol(',')
OutValue(op, OOF_ADDR | OOFW_8 | OOF_SIGNED )
out_symbol(')')
if op.specflag1 == 1:
out_symbol('+')
elif optype == o_phrase:
out_symbol('@')
out_register(self.regNames[op.reg])
if fl == FL_AUTOINC:
out_symbol('+')
else:
return False
return True
def out(self):
"""
Generate text representation of an instruction in 'cmd' structure.
This function shouldn't change the database, flags or anything else.
All these actions should be performed only by u_emu() function.
Returns: nothing
"""
# Init output buffer
buf = idaapi.init_output_buffer(1024)
postfix = ""
# first argument (12) is the width of the mnemonic field
OutMnem(12, postfix)
# output first operand
# kernel will call outop()
if self.cmd.Op1.type != o_void:
out_one_operand(0)
# output the rest of operands separated by commas
for i in xrange(1, 3):
if self.cmd[i].type == o_void:
break
out_symbol(',')
OutChar(' ')
out_one_operand(i)
term_output_buffer()
cvar.gl_comm = 1 # generate comment at the next call to MakeLine()
MakeLine(buf)
def get_instruction(self, name):
for x in self.instruc:
if x['name'] == name:
return self.instruc.index(x)
print "Could not find instruction %s" % name
return -1
def get_register(self, name):
for x in self.regNames:
if x == name:
return self.regNames.index(x)
return -1
def handle_jcc(self, cc, n_addr):
addr = 3 * (~n_addr & 0xffff)
if cc == 3:
self.cmd.itype = self.get_instruction('jump')
elif cc == 4:
self.cmd.itype = self.get_instruction('jle')
elif cc == 0:
self.cmd.itype = self.get_instruction('jgt')
elif cc == 6:
self.cmd.itype = self.get_instruction('jeq')
elif cc == 2:
self.cmd.itype = self.get_instruction('jne')
elif cc == 5:
self.cmd.itype = self.get_instruction('jlt')
elif cc == 1:
self.cmd.itype = self.get_instruction('jge')
elif cc == 7:
self.cmd.itype = self.get_instruction('jev')
if n_addr == 0xffff:
if cc == 3:
self.cmd.itype = self.get_instruction('rets')
else:
self.cmd.Op1.type = o_reg
self.cmd.Op1.reg = self.get_register("ip")
else:
self.cmd.Op1.type = o_near
self.cmd.Op1.addr = addr #self.cmd.ea + n_addr
#print "returning from handle_jcc"
# for now we just put the data segment after the code segment
def data_address(self, addy):
return addy + 0x12000
def get_ix(self, ix):
if ix==0:
return self.get_register('i0')
if ix==1:
return self.get_register('i1')
if ix==2:
return self.get_register('i2')
if ix==3:
return self.get_register('i3')
def get_alu_op(self, op):
if op == 0:
return self.get_instruction('cmpa')
if op == 1:
return self.get_instruction('cmp')
if op == 2:
return self.get_instruction('and')
if op == 3:
return self.get_instruction('subs')
if op == 4:
return self.get_instruction('subd')
if op == 5:
return self.get_instruction('subdc')
if op == 6:
return self.get_instruction('mula')
if op == 7:
return self.get_instruction('subsc')
if op == 8:
return self.get_instruction('xor')
if op == 10:
return self.get_instruction('move')
if op == 11:
return self.get_instruction('or')
if op == 12:
return self.get_instruction('add')
if op == 13:
return self.get_instruction('addc')
if op == 14:
return self.get_instruction('mul')
if op == 15:
return self.get_instruction('tstb')
if op == 16:
return self.get_instruction('shra')
if op == 17:
return self.get_instruction('inc')
if op == 18:
return self.get_instruction('cmvd')
if op == 19:
return self.get_instruction('cmvs')
if op == 20:
return self.get_instruction('shrc')
if op == 21:
return self.get_instruction('incc')
if op == 22:
return self.get_instruction('shr')
if op == 24:
return self.get_instruction('cpl1')
if op == 25:
return self.get_instruction('cpl2')
if op == 26:
return self.get_instruction('shl')
if op == 27:
return self.get_instruction('dec')
if op == 28:
return self.get_instruction('cpl2c')
if op == 30:
return self.get_instruction('shlc')
if op == 31:
return self.get_instruction('decc')
print "Could not get instruction number for alu_op %x" % op
return -1
def handle_alu3(self, alu_op, reg, n_data):
data = ~n_data & 0xff
self.cmd.itype = self.get_alu_op(alu_op)
self.cmd.Op1.type = o_reg
self.cmd.Op1.reg = reg
self.cmd.Op2.type = o_imm
self.cmd.Op2.value = data
def handle_alu4(self, alu_op, reg_op2, reg_op1, reg_res):
self.cmd.itype = self.get_alu_op(alu_op)
self.cmd.Op1.type = o_reg
self.cmd.Op1.reg = reg_res
self.cmd.Op2.type = o_reg
self.cmd.Op2.reg = reg_op1
Feature = self.cmd.get_canon_feature()
if Feature & CF_USE3:
self.cmd.Op3.type = o_reg
self.cmd.Op3.reg = reg_op2
def handle_alu1(self, ix, alu_op, reg, offset):
reg_ix = self.get_ix(ix)
self.cmd.itype = self.get_alu_op(alu_op)
self.cmd.Op1.type = o_reg
self.cmd.Op1.reg = reg
self.cmd.Op2.type = o_displ
self.cmd.Op2.addr = offset
self.cmd.Op2.reg = reg_ix
def handle_alu2(self, ix, alu_op, reg, cpl2_offset):
reg_ix = self.get_ix(ix)
self.cmd.itype = self.get_alu_op(alu_op)
if cpl2_offset & 0x80 == 0x80:
self.cmd.Op2.specflag1 = -1
self.cmd.Op2.addr = ((~cpl2_offset) & 0x7f) + 1
else:
self.cmd.Op2.specflag1 = 1
self.cmd.Op2.addr = cpl2_offset & 0x7f
self.cmd.Op1.type = o_reg
self.cmd.Op1.reg = reg
self.cmd.Op2.type = o_displ
self.cmd.Op2.reg = reg_ix
def handle_alu5(self, alu_op, reg, ix):
self.cmd.itype = self.get_alu_op(alu_op)
reg_ix = self.get_ix(ix)
self.cmd.Op1.type = o_reg
self.cmd.Op1.reg = reg
self.cmd.Op2.type = o_phrase
self.cmd.Op2.phrase = self.get_register('r3')
self.cmd.Op2.reg = reg_ix
def handle_alu6(self, alu_op, reg, n_addr):
self.cmd.itype = self.get_alu_op(alu_op)
addr = ~n_addr & 0xff
self.cmd.Op1.type = o_reg
self.cmd.Op1.reg = reg
self.cmd.Op2.type = o_mem
self.cmd.Op2.addr = self.data_address(addr)
self.cmd.Op2.specflag2 = 1
def handle_move7(self, ix, reg):
self.cmd.itype = self.get_instruction('move')
reg_ix = self.get_ix(ix)
self.cmd.Op1.type = o_phrase
self.cmd.Op1.phrase = self.get_register('r3')
self.cmd.Op1.reg = reg_ix
self.cmd.Op2.type = o_reg
self.cmd.Op2.reg = reg
def handle_move8(self, ix, reg, cpl2_offset):
self.cmd.itype = self.get_instruction('move')
reg_ix = self.get_ix(ix)
if cpl2_offset & 0x80 == 0x80:
self.cmd.Op1.specflag1 = -1
self.cmd.Op1.addr = ((~cpl2_offset) & 0x7f) + 1
else:
self.cmd.Op1.specflag1 = 1
self.cmd.Op1.addr = cpl2_offset
self.cmd.Op1.type = o_displ
self.cmd.Op1.reg = reg_ix
self.cmd.Op2.type = o_reg
self.cmd.Op2.reg = reg
def handle_move9(self, ix, reg_src, offset):
self.cmd.itype = self.get_instruction('move')
reg2 = self.get_ix(ix)
self.cmd.Op1.type = o_displ
self.cmd.Op1.addr = offset
self.cmd.Op1.reg = reg2
self.cmd.Op2.type = o_reg
self.cmd.Op2.reg = reg_src
def handle_move10(self, reg, n_addr):
self.cmd.itype = self.get_instruction('move')
addr = (~n_addr & 0xff)
self.cmd.Op1.type = o_mem
self.cmd.Op1.addr = self.data_address(addr)
self.cmd.Op1.specflag2 = 1
self.cmd.Op2.type = o_reg
self.cmd.Op2.reg = reg
def handle_move11(self, n_data, n_addr):
self.cmd.itype = self.get_instruction('move')
addr = (~n_addr & 0xff)
data = (~n_data & 0xff)
self.cmd.Op1.type = o_mem
self.cmd.Op1.addr = self.data_address(addr)
self.cmd.Op1.specflag2 = 1
self.cmd.Op2.type = o_imm
self.cmd.Op2.value = data
def handle_call(self, n_addr, calltype):
addr = 3 * (~n_addr & 0xffff)
self.cmd.itype = self.get_instruction(calltype)
if n_addr == 0:
self.cmd.Op1.type = o_reg
self.cmd.Op1.reg = self.get_register('ip')
else:
self.cmd.Op1.type = o_near
self.cmd.Op1.addr = addr
def handle_pop(self):
self.cmd.itype = self.get_instruction('pop')
self.cmd.Op1.type = o_reg
self.cmd.Op1.reg = self.get_register('ip')
def handle_push(self):
self.cmd.itype = self.get_instruction('push')
self.cmd.Op1.type = o_reg
self.cmd.Op1.reg = self.get_register('ip')
def handle_pmd(self, s):
self.cmd.itype = self.get_instruction('pmd')
self.cmd.Op1.type = o_imm
self.cmd.Op1.value = s
def handle_freq(self, divn4):
self.cmd.itype = self.get_instruction('freq')
self.cmd.Op1.type = o_imm
self.cmd.Op1.value = divn4
def ana(self):
"""
Decodes an instruction into self.cmd.
Returns: self.cmd.size (=the size of the decoded instruction) or zero
"""
h1 = ua_next_byte()
h2 = ua_next_byte()
h3 = ua_next_byte()
h3h = (h3 & 0xf0) >> 4
h3l = h3 & 0xf
h2h = (h2 & 0xf0) >> 4
h2l = h2 & 0xf
h1h = (h1 & 0xf0) >> 4
h1l = h1 & 0xf
h2h1 = (h2<<8) + h1
if h3 == 0x3f and h2h == 0xf:
self.cmd.itype = self.get_instruction('nop')
elif h3 == 0x3f and h2h == 3:
self.cmd.itype = self.get_instruction('ret')
elif h3 == 0x3f and h2h == 1:
self.cmd.itype = self.get_instruction('reti')
elif h3 == 0x3e:
self.handle_pop()
elif h3 == 0x39:
self.handle_call(h2h1, 'call')
elif h3 == 0x3a:
self.handle_call(h2h1, 'calls')
elif (h3h == 3 or h3h == 2) and h3l & 0x8 == 0:
self.handle_jcc(h3 & 7, h2h1)
elif h3 == 0x2d:
self.handle_push()
elif h3 == 0x2a:
self.handle_call(0, 'calls')
elif h3 == 0x29:
self.handle_call(0, 'call')
elif h3h == 1 and h3l & 0x8 == 0x8:
self.handle_alu1((h3l & 6) >> 1, h2h + ((h3 & 1)<<4), h2l, h1)
elif h3h == 1 and h3l & 0x8 == 0:
self.handle_alu2((h3l & 6) >> 1, h2h + ((h3 & 1)<<4), h2l, h1)
elif h3 == 0x0e:
self.handle_alu3(h2h, h2l, h1)
elif h3h == 0 and h3l & 0xe == 0xc:
self.handle_alu4(h2h + ((h3 & 1)<<4), h2l, h1h, h1l)
elif h3 == 0xb and h2h == 0xe:
self.handle_pmd(h2 & 0x1)
elif h3 == 0xb and h2h == 0xd:
self.cmd.itype = self.get_instruction('halt')
elif h3 == 0xb and h2h == 0xb:
self.handle_freq(h1l)
elif h3 == 0xb and h2h == 0x7:
self.cmd.itype = self.get_instruction('sflag')
elif h3h == 0 and h3l & 0xe == 0x6:
self.handle_alu5(h2h + ((h3 & 1)<<4), h2l, h1 & 3)
elif h3h == 0 and h3l & 0xe == 0x4:
self.handle_alu6(h2h + ((h3 & 1)<<4), h2l, h1)
elif h3 == 3 and h2h & 0x8 == 1:
self.handle_mov7(h2h & 3, h2l)
elif h3 == 3 and h2h & 0x8 == 0:
self.handle_move8(h2h & 3, h2l, h1)
elif h3 == 0x2:
self.handle_move9(h2h & 0x3, h2l, h1)
elif h3 == 1 and h2h == 0xb:
self.handle_move10(h2l, h1)
elif h3 == 0:
self.handle_move11(h2, h1)
else:
print "No instruction %x (%x|%x), %x (%x|%x), %x (%x|%x)" % (h3, h3h, h3l, h2, h2h, h2l, h1, h1h, h1l)
#
# Need more instructions decoded here
#
# Return decoded instruction size or zero
return self.cmd.size
# ----------------------------------------------------------------------
# Every processor module script must provide this function.
# It should return a new instance of a class derived from idaapi.processor_t
def PROCESSOR_ENTRY():
return sample_processor_t()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment