Created
August 9, 2014 03:39
-
-
Save marekr/b69aa80f1c70b07e1a87 to your computer and use it in GitHub Desktop.
IDA processor module. Creator: Charlie Miller
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
---------------------------------------------------------------------- | |
# 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