Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supporting IDA 7.X & Python 3 #4

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 43 additions & 42 deletions amnesia.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import idc
import ida_ida
import ida_bytes
import ida_funcs
import ida_search
Expand Down Expand Up @@ -30,8 +31,8 @@ def find_function_epilogue_bxlr(self, makecode=False):
This is a common way to return from a function call.
Using the IDA API, convert these opcodes to code. This kicks off IDA analysis.
'''
EAstart = idc.MinEA()
EAend = idc.MaxEA()
EAstart = ida_ida.inf_get_min_ea()
EAend = ida_ida.inf_get_max_ea()

ea = EAstart
length = 2 # this code isn't tolerant to values other than 2 right now
Expand All @@ -43,13 +44,13 @@ def find_function_epilogue_bxlr(self, makecode=False):
while ea < EAend:
instructions = []
for i in range(length):
instructions.append(idc.Byte(ea + i))
instructions.append(idc.get_wide_byte(ea + i))

if not ida_bytes.isCode(ida_bytes.getFlags(ea)) and instructions[0] == 0x70 and instructions[1] == 0x47:
if not ida_bytes.is_code(ida_bytes.get_full_flags(ea)) and instructions[0] == 0x70 and instructions[1] == 0x47:
if self.printflag:
print fmt_string % (ea, instructions[0], instructions[1])
print(fmt_string % (ea, instructions[0], instructions[1]))
if makecode:
idc.MakeCode(ea)
idc.create_insn(ea)
ea = ea + length

def find_pushpop_registers_thumb(self, makecode=False):
Expand All @@ -65,8 +66,8 @@ def find_pushpop_registers_thumb(self, makecode=False):
thumb_reg_list = [0x00, 0x02, 0x08, 0x0b, 0x0e, 0x10, 0x1c, 0x1f, 0x30, 0x30, 0x38, 0x3e, 0x4e,
0x55, 0x70, 0x72, 0x73, 0x7c, 0x7f, 0x80, 0x90, 0xb0, 0xf0, 0xf3, 0xf7, 0xf8, 0xfe, 0xff]

EAstart = idc.MinEA()
EAend = idc.MaxEA()
EAstart = ida_ida.inf_get_min_ea()
EAend = ida_ida.inf_get_max_ea()

ea = EAstart
length = 2 # this code isn't tolerant to values other than 2 right now
Expand All @@ -78,13 +79,13 @@ def find_pushpop_registers_thumb(self, makecode=False):
while ea < EAend:
instructions = []
for i in range(length):
instructions.append(idc.Byte(ea + i))
instructions.append(idc.get_wide_byte(ea + i))

if not ida_bytes.isCode(ida_bytes.getFlags(ea)) and instructions[0] in thumb_reg_list and (instructions[1] == 0xb5 or instructions[1]== 0xbd):
if not ida_bytes.is_code(ida_bytes.get_full_flags(ea)) and instructions[0] in thumb_reg_list and (instructions[1] == 0xb5 or instructions[1]== 0xbd):
if self.printflag:
print fmt_string % (ea, instructions[0], instructions[1])
print(fmt_string % (ea, instructions[0], instructions[1]))
if makecode:
idc.MakeCode(ea)
idc.create_insn(ea)
ea = ea + length

def find_pushpop_registers_arm(self, makecode=False):
Expand All @@ -96,8 +97,8 @@ def find_pushpop_registers_arm(self, makecode=False):
** ** 2d e9 and ** ** bd e8
'''

EAstart = idc.MinEA()
EAend = idc.MaxEA()
EAstart = ida_ida.inf_get_min_ea()
EAend = ida_ida.inf_get_max_ea()

ea = EAstart
length = 2 # this code isn't tolerant to values other than 2 right now
Expand All @@ -109,60 +110,60 @@ def find_pushpop_registers_arm(self, makecode=False):
while ea < EAend:
instructions = []
for i in range(length):
instructions.append(idc.Byte(ea + i))
instructions.append(idc.get_wide_byte(ea + i))

# print BX LR bytes
if not ida_bytes.isCode(ida_bytes.getFlags(ea)) and \
if not ida_bytes.is_code(ida_bytes.get_full_flags(ea)) and \
(instructions[0] == 0xbd and instructions[1] == 0xe8):
if self.printflag:
print fmt_string % ("POP ", ea, instructions[0], instructions[1])
print(fmt_string % ("POP ", ea, instructions[0], instructions[1]))
if makecode:
idc.MakeCode(ea)
idc.create_insn(ea)

if not ida_bytes.isCode(ida_bytes.getFlags(ea)) and \
if not ida_bytes.is_code(ida_bytes.get_full_flags(ea)) and \
(instructions[0] == 0x2d and instructions[1] == 0xe9) \
:
if self.printflag:
print fmt_string % ("PUSH", ea, instructions[0], instructions[1])
print(fmt_string % ("PUSH", ea, instructions[0], instructions[1]))
if makecode:
idc.MakeCode(ea)
idc.create_insn(ea)
ea = ea + length

def make_new_functions_heuristic_push_regs(self, makefunction=False):
'''
After converting bytes to instructions, Look for PUSH instructions that are likely the beginning of functions.
Convert these code areas to functions.
'''
EAstart = idc.MinEA()
EAend = idc.MaxEA()
EAstart = ida_ida.inf_get_min_ea()
EAend = ida_ida.inf_get_max_ea()
ea = EAstart

while ea < EAend:
if self.printflag:
print "EA %08x" % ea
print("EA %08x" % ea)

ea_function_start = idc.GetFunctionAttr(ea, idc.FUNCATTR_START)
ea_function_start = idc.get_func_attr(ea, idc.FUNCATTR_START)

# If ea is inside a defined function, skip to end of function
if ea_function_start != idc.BADADDR:
ea = idc.FindFuncEnd(ea)
ea = idc.find_func_end(ea)
continue

# If current ea is code
if ida_bytes.isCode(ida_bytes.getFlags(ea)):
if ida_bytes.is_code(ida_bytes.get_full_flags(ea)):
# Looking for prologues that do PUSH {register/s}
mnem = idc.GetMnem(ea)
mnem = idc.print_insn_mnem(ea)

#
if (
mnem == "PUSH"
):
if makefunction:
if self.printflag:
print "Converting code to function @ %08x" % ea
idc.MakeFunction(ea)
print("Converting code to function @ %08x" % ea)
ida_funcs.add_func(ea)

eanewfunction = idc.FindFuncEnd(ea)
eanewfunction = idc.find_func_end(ea)
if eanewfunction != idc.BADADDR:
ea = eanewfunction
continue
Expand All @@ -175,8 +176,8 @@ def make_new_functions_heuristic_push_regs(self, makefunction=False):
ea += 1

def nonfunction_first_instruction_heuristic(self, makefunction=False):
EAstart = idc.MinEA()
EAend = idc.MaxEA()
EAstart = ida_ida.inf_get_min_ea()
EAend = ida_ida.inf_get_max_ea()
ea = EAstart

flag_code_outside_function = False
Expand All @@ -185,37 +186,37 @@ def nonfunction_first_instruction_heuristic(self, makefunction=False):
while ea < EAend:

# skip functions, next instruction will be the target to inspect
function_name = idc.GetFunctionName(ea)
function_name = idc.get_func_name(ea)
if function_name != "":

flag_code_outside_function = False

# skip to end of function and keep going
# ea = idc.FindFuncEnd(ea)
# ea = idc.find_func_end(ea)
#if self.printflag:
# print "Skipping function %s" % (function_name)

ea = ida_search.find_not_func(ea, 1)
continue

elif ida_bytes.isCode(ida_bytes.getFlags(ea)):
elif ida_bytes.is_code(ida_bytes.get_full_flags(ea)):

# code that is not a function
# get mnemonic to see if this is a push
mnem = idc.GetMnem(ea)
mnem = idc.print_insn_mnem(ea)

if makefunction and (mnem == "PUSH" or mnem == "PUSH.W" or mnem == "STM" or mnem=="MOV"):
if self.printflag:
print "nonfunction_first_instruction_heuristic() making function %08x" % ea
idc.MakeFunction(ea)
print("nonfunction_first_instruction_heuristic() making function %08x" % ea)
ida_funcs.add_func(ea)
flag_code_outside_function = False
ea =ida_search.find_not_func(ea, 1)
ea = ida_search.find_not_func(ea, 1)
continue

else:
if self.printflag:
print "nonfunction_first_instruction_heuristic() other instruction %08x\t'%s'" % (ea, mnem)
ea = idc.NextFunction(ea)
print("nonfunction_first_instruction_heuristic() other instruction %08x\t'%s'" % (ea, mnem))
ea = idc.get_next_func(ea)
continue

ea += 1
Expand Down
20 changes: 10 additions & 10 deletions cortex_m_firmware.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ def __init__(self, auto=False):
]

if not self.verify_processor_settings():
print "ERROR: Processor architecture is incorrect"
print "Please set processor type to ARM, and ARM architecture options to ARMv7-M (or other valid Cortex architecture)"
print("ERROR: Processor architecture is incorrect")
print("Please set processor type to ARM, and ARM architecture options to ARMv7-M (or other valid Cortex architecture)")
return None


Expand Down Expand Up @@ -103,34 +103,34 @@ def annotate_vector_table(self, vtoffset=0x0000000000):
entry_addr = vtoffset + 4 * annotation_index
entry_name = "%s_%08x" % (self.annotations[annotation_index], entry_addr)

idc.MakeDword(entry_addr)
ida_bytes.create_data(entry_addr, ida_bytes.FF_DWORD, 4, idaapi.BADADDR)
ida_name.set_name(entry_addr, entry_name, 0)

# get the bytes of the vt entry
dword = idc.Dword(entry_addr)
dword = idc.get_wide_dword(entry_addr)

if dword != 0:
# print "ea %08x = 0x%08x" % (ea, dword)
idc.MakeCode(dword-1)
idc.MakeFunction(dword-1)
idc.create_insn(dword-1)
ida_funcs.add_func(dword-1)
# TODO fix the offsets created here
# for thumb, they show to be off by a byte
# one of the end args controls stuff about this
idc.OpOffEx(entry_addr,0,idaapi.REF_OFF32, -1, 0, 0)
idc.op_offset(entry_addr, 0, idaapi.REF_OFF32, -1, 0, 0)

instruction = idc.Word(dword-1)
instruction = idc.get_wide_word(dword-1)

# functions like this are common
if instruction == 0xe7fe:
idc.SetFunctionCmt(dword-1, 'Infinite Loop', 1)
idc.set_func_cmt(dword-1, 'Infinite Loop', 1)


def find_functions(self):
'''
Using the Amnesia IDA Python module, find ARM code and create functions
'''

a = Amnesia()
a = Amnesia()
a.find_pushpop_registers_thumb(makecode=True)
a.find_pushpop_registers_arm(makecode=True)
a.find_function_epilogue_bxlr(makecode=True)
Expand Down
32 changes: 16 additions & 16 deletions reobjc.py → reobjc_macos_intel-only.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ def _locate_objc_runtime_functions(self):
positive_reg = re.compile('.*_objc_msgsend', re.IGNORECASE)
negative_reg = re.compile('^$', re.IGNORECASE)

if self.printflag: print "Finding Objective C runtime functions..."
if self.printflag: print("Finding Objective C runtime functions...")

for name_tuple in idautils.Names(): # returns a tuple (address, name)
addr, name = name_tuple
if positive_reg.match(name) and not negative_reg.match(name):
if self.printflag: print "0x%08x\t%s" % (addr, name)
if self.printflag: print("0x%08x\t%s" % (addr, name))
self.target_objc_msgsend.append(name_tuple)

return None
Expand All @@ -85,13 +85,13 @@ def lookup_objc_runtime_function(self, fname):

# fname is found
if function_ea != idc.BADADDR:
if self.debugflag: print "Looking for function %s" % fname
if self.debugflag: print("Looking for function %s" % fname)

# iterate over objc runtime functions
for name_tuple in self.target_objc_msgsend:
addr, name = name_tuple
if fname == name:
if self.debugflag: print "Found match: 0x%08x\t%s" % (addr, name)
if self.debugflag: print("Found match: 0x%08x\t%s" % (addr, name))
return name_tuple

return None
Expand All @@ -114,7 +114,7 @@ def objc_msgsend_xref(self, call_ea, objc_self, objc_selector, create_xref = Tru
# get instruction mnemonic at address - I guess to check and make sure
# it's mov rsi, blah
instruction = idc.GetDisasm(objc_selector)
if self.debugflag: print ">>> objc_msgsend_xref 0x%08x %s" % (objc_selector, instruction)
if self.debugflag: print(">>> objc_msgsend_xref 0x%08x %s" % (objc_selector, instruction))

# get outbound references in the appropriate segment
# implicit assumption is there is exacltly one
Expand Down Expand Up @@ -163,7 +163,7 @@ def objc_msgsend_xref(self, call_ea, objc_self, objc_selector, create_xref = Tru
# assumption made on function always being in text segment
if idc.SegName(_meth_ref) == "__text":
# save the method implementation -- this is the function ptr
if self.debugflag: print "0x%08x checking for the proper method -- %s" % (_meth_ref, idc.get_name(idc.get_func_attr(_meth_ref, idc.FUNCATTR_START)))
if self.debugflag: print("0x%08x checking for the proper method -- %s" % (_meth_ref, idc.get_name(idc.get_func_attr(_meth_ref, idc.FUNCATTR_START))))
target_method = _meth_ref

if not target_method:
Expand All @@ -172,7 +172,7 @@ def objc_msgsend_xref(self, call_ea, objc_self, objc_selector, create_xref = Tru
# After dereferencing across the IDB file, we finally have a target function.
# In other words, if there isn't a method **in this binary** no xref is made (IDA only loads one binary?)
# that is referenced from the mov rsi, <selector> instruction
if self.debugflag: print "Found target method 0x%08x" % target_method
if self.debugflag: print("Found target method 0x%08x" % target_method)
if create_xref: idc.AddCodeXref(objc_selector, target_method, idc.fl_CF)

return True
Expand All @@ -191,9 +191,9 @@ def run(self):
self.find_objc_calls(f)
except Exception as e:
fname = idc.get_name(idc.get_func_attr(f, idc.FUNCATTR_START))
print "\n\n[!!] Exception processing function %s: %s @ ea = 0x%08x (%dL)" % (fname, e, self.ea, self.ea)
print("\n\n[!!] Exception processing function %s: %s @ ea = 0x%08x (%dL)" % (fname, e, self.ea, self.ea))
traceback.print_exc()
print "\n\n"
print("\n\n")



Expand All @@ -206,7 +206,7 @@ def find_objc_calls(self, f):
f_end = idc.get_func_attr(f, idc.FUNCATTR_END)

for ea in idautils.Heads(f_start, f_end):
if self.debugflag: print "0x%08x '%s'" % (ea, idc.GetMnem(ea))
if self.debugflag: print("0x%08x '%s'" % (ea, idc.GetMnem(ea)))

objc_selector = None
objc_selector_ea = None
Expand Down Expand Up @@ -240,7 +240,7 @@ def find_objc_calls(self, f):
# check the list of functions from the objc runtime
# call_target should be validated here, in case something fails with resolve_register_backwalk_ea()
if call_target and self.lookup_objc_runtime_function(call_target):
if self.debugflag: print "%s call, operand_type == %s" % (call_type, idc.get_operand_type(call_ea,0))
if self.debugflag: print("%s call, operand_type == %s" % (call_type, idc.get_operand_type(call_ea,0)))

# get the argument values at the call
# id objc_msgSend(id self, SEL op, ...);
Expand Down Expand Up @@ -277,12 +277,12 @@ def find_objc_calls(self, f):
# TODO eliminate hardcoded x64
if objc_self and objc_self['value'] == 'rdi':
objc_class = self.resolve_objc_self_to_class(objc_self['target_ea'])
if self.debugflag: print "### objc_class == %s" % objc_class
if self.debugflag: print("### objc_class == %s" % objc_class)

# objc_selector: address of instruction mov rsi, <selector>
if objc_self and objc_selector:
xref_created = self.objc_msgsend_xref(call_ea, objc_self['target_ea'], objc_selector['target_ea'])
if self.printxrefs and xref_created: print "0x%08x Creating xref: %s %s, %s" % (ea, idc.GetMnem(ea), idc.GetOpnd(ea, 0), objc_selector['value'])
if self.printxrefs and xref_created: print("0x%08x Creating xref: %s %s, %s" % (ea, idc.GetMnem(ea), idc.GetOpnd(ea, 0), objc_selector['value']))



Expand Down Expand Up @@ -339,7 +339,7 @@ def resolve_register_backwalk_ea(self, ea, target_dest_reg):
while curr_ea != idc.BADADDR:
instruction = idc.GetDisasm(curr_ea)

if self.debugflag: print "0x%08x %s" % (curr_ea, instruction)
if self.debugflag: print("0x%08x %s" % (curr_ea, instruction))

# looking for the previous place this register was assigned a value
mnem = idc.GetMnem(curr_ea)
Expand All @@ -353,7 +353,7 @@ def resolve_register_backwalk_ea(self, ea, target_dest_reg):
target_value = src
target_ea = curr_ea
target_type = idc.get_operand_type(curr_ea,1)
if self.debugflag: print " new target set %s (type=%d)" % (target, idc.get_operand_type(curr_ea,1))
if self.debugflag: print(" new target set %s (type=%d)" % (target, idc.get_operand_type(curr_ea,1)))

# take stab at tracking calls - this is not the greatest approach, but slightly more correct than doing no tracking
# call instruction affects RAX if it returns a result
Expand All @@ -368,7 +368,7 @@ def resolve_register_backwalk_ea(self, ea, target_dest_reg):
curr_ea = idc.prev_head(curr_ea-1, f_start)

if target_value:
if self.verboseflag: print ">>> 0x%08x, %s is set to %s @ 0x%08x" % (ea, target_dest_reg, target_value, target_ea)
if self.verboseflag: print(">>> 0x%08x, %s is set to %s @ 0x%08x" % (ea, target_dest_reg, target_value, target_ea))
ret_dict = {"target" : target_dest_reg, "value" : target_value, "target_ea" : target_ea, "ea" : ea, "type" : target_type}

if previous_call:
Expand Down