Python IDA processor module. Creator: Charlie Miller

Storm Shadow

Administrator
Staff member
Developer
Ida Pro Expert
Elite Cracker
Here is a view how to make a procesor in python
Just like the spu.py shipped with ida pro


Python:
 ----------------------------------------------------------------------
# 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()
 
Top