def Assemble(ea, line): """ Assembles one or more lines (does not display an message dialogs) If line is a list then this function will attempt to assemble all the lines This function will turn on batch mode temporarily so that no messages are displayed on the screen @param ea: start address @return: (False, "Error message") or (True, asm_buf) or (True, [asm_buf1, asm_buf2, asm_buf3]) """ old_batch = idc.Batch(1) ret = _Assemble(ea, line) idc.Batch(old_batch) return ret
def SimpleAsm(string): if sys.modules.has_key('miasm'): try: i_opcode = x86_mn.asm(string.lower()) except: print ">Assembler:SimpleAsm - Error miasm.asm() for [%s]" % string i_opcode = '' if len(i_opcode) > 0: return i_opcode idc.Batch(1) while True: seg_start = random.randint(0x1000, 0xffffffff) seg_size = 0x20 if idc.SegCreate(seg_start, seg_start + seg_size, 0, 1, 0, 0) != 0: break tmp = idaapi.assemble(seg_start, 0, seg_start, 1, string) if tmp == 0: while idc.SegDelete(seg_start, 0) != 0: pass idc.Batch(0) print "Failed to assemble [%s]" % string raise MiscError idc.MakeCode(seg_start) opcode = ''.join([ chr(idc.Byte(seg_start + i)) for i in xrange(0, idc.ItemSize(seg_start) - 1) ]) while idc.SegDelete(seg_start, 0) != 0: pass idc.Batch(0) return opcode
def batch(num): if idaapi.IDA_SDK_VERSION <= 699: idc.Batch(num) else: idc.batch(num)
def Assemble(self, function, nasm=True): ''' Main Assemble Function ''' if self.functions.has_key(function.start_ea): ans = idaapi.askyn_c( 1, "HIDECANCEL\nFunction @ [%08x] was already optimized, are you sure you want to overwrite old one?" ) if ans == 0: return idc.Batch(1) self.jmp_table = "" self.jmp_table_refs = [] self.jmp_deps = {} self.ref_instr = {} self.bb_head_ea = {} function_ea = self.free_ea function_end = None if debug: print ">Assemble(%08x) - Starting" % function.start_ea if nasm: if self.opty_dir == None: self.opty_dir = idc.GetIdbPath() self.opty_dir = self.opty_dir[:self.opty_dir.rfind( os.sep)] + os.sep + "optimice_%s" % idc.GetInputFile() if not os.path.isdir(self.opty_dir): os.mkdir(self.opty_dir) self.nasm = True self.nasmfw = open( self.opty_dir + os.sep + 'f_%08x.asm' % function.start_ea, "w+") self.NasmWriteToFile("[BITS 32]\n") self.NasmWriteToFile("\torg %09xh\n" % function_ea) else: self.nasm = False for bb_ea in function.DFSFalseTraverseBlocks(): if self.nasm: self.NasmWriteToFile("\nL%08x:\n" % bb_ea) self.bb_head_ea[bb_ea] = True else: self.bb_head_ea[bb_ea] = self.free_ea for instr in function.GetBBInstructions(bb_ea): if instr == None: continue mnem = self.BuildAsmString(instr, function) if debug: print ">Assemble - Assembling @ %08x [%s]" % ( instr.GetOriginEA(), mnem) if not self.nasm: self.AsmAndWrite(mnem, instr, function=function) if not instr.IsCFI(): ref_from = list(function.GetRefsFrom( instr.GetOriginEA()))[0][0] if self.bb_head_ea.has_key(ref_from): if self.nasm: self.NasmWriteToFile("\tjmp L%08x ; \n" % ref_from) else: self.AsmAndWrite("jmp %09xh" % self.bb_head_ea[ref_from]) elif instr.GetMnem() == "call": for ref, path in function.GetRefsFrom(instr.GetOriginEA()): if path == False: if self.bb_head_ea.has_key(ref): if self.nasm: self.NasmWriteToFile( "\tjmp L%08x ; ###FAKE 2 JMP###\n" % ref) else: self.AsmAndWrite("jmp %09xh" % self.bb_head_ea[ref]) elif instr.IsJcc(): ref_from = list(function.GetRefsFrom(instr.GetOriginEA())) for ref, path in ref_from: if path == False: break if path == True: raise MiscError elif self.bb_head_ea.has_key(ref): print "Check this out @ [%08x] ref:[%08x]" % ( instr.GetOriginEA(), ref) if self.nasm: self.NasmWriteToFile( "\tjmp L%08x ; ###FAKE 2 JMP###\n" % ref) else: self.AsmAndWrite("jmp %09xh" % self.bb_head_ea[ref]) ret = None if self.nasm: self.NasmWriteToFile(self.jmp_table) self.nasmfw.close() self.nasmfw = None ret = self.NasmAssemble(function.start_ea, self.free_ea) if ret != None: self.free_ea = ret else: ret = self.AsmAndWriteBranches(function) self.free_ea = ret self.ref_instr = {} idc.Batch(0) if ret != None: idc.MakeFunction(function_ea) comment = idc.Comment(function_ea) if comment != None: comment = 'Origin@[%08x]; %s' % (function.start_ea, comment) else: comment = 'Origin@[%08x];' % function.start_ea idc.MakeComm(function_ea, comment) comment = idc.Comment(function.start_ea) if comment != None: comment = 'OPTY@[%08x]; %s' % (function_ea, comment) else: comment = 'OPTY@[%08x];' % function_ea idc.MakeComm(function.start_ea, comment) idaapi.set_name(function_ea, "om_%s" % idc.Name(function.start_ea)) function_end = self.free_ea self.functions[function.start_ea] = (function_ea, function_end) idaapi.refresh_idaview_anyway()
def NasmAssemble(self, function_ea, write_ea): dir = self.opty_dir nasm = "C:\\Program Files\\nasm\\nasm.exe" arg1 = "f_%08x.asm" % function_ea arg2 = "-o f_%08x.o" % function_ea arg3 = "-l f_%08x.lst" % function_ea arg4 = "-Ox" orig_dir = os.getcwd() os.chdir(dir) idc.Batch(0) while 1: try: p = subprocess.Popen([nasm, arg1, arg2, arg3, arg4], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) o, e = p.communicate() if o != "": print o if e != "": print e fop = open("f_%08x.o" % function_ea, "rb") ans = idaapi.askyn_c( 0, "HIDECANCEL\nDo you want to manually edit function before writing to IDA?" ) if ans == 1: os.startfile(arg1, "open") idaapi.warning( "Press OK button when you're done editing file.") fop.close() continue else: idc.Batch(1) break except: error_msg = '\n'.join(e.split("\n")[:15]) os.startfile(arg1, "open") ans = idaapi.askyn_c( 1, """HIDECANCEL\nNASM failed to assemble [f_%08x.o] file. You can manually edit and NASM this file [f_%08x.asm] and click Yes when you're done. File is located in directory where your IDB is located. If you want to skip this function press No. Nasm output: %s""" % (function_ea, function_ea, error_msg)) if ans == 1: continue else: os.chdir(orig_dir) idc.Batch(1) return None os.chdir(orig_dir) print ">>>Writing function [%08x] @ [%08x]" % (function_ea, write_ea) data = fop.read() data_len = len(data) for offset in xrange(0, data_len): idc.PatchByte(write_ea + offset, ord(data[offset])) fop.close() idc.MakeCode(write_ea) fp = open("%s\\f_%08x.lst" % (dir, function_ea), "r") asm_lst = fp.read() base_addr = re.search(r"ORG ([\dABCDEF]+)H", asm_lst).group(1) base_addr = int(base_addr, 16) for jt in self.jmp_table_refs: m = re.search(r"\s*\d+\s+([\dABCDEF]{8}).*?%s" % re.escape(jt), asm_lst, re.IGNORECASE) if m != None: jt_ea = int(m.group(1), 16) jt_str = re.search(r"SJ_.{8}", jt, re.IGNORECASE).group() for m in re.findall( r"(?i)\n\s*\d+\s+[\dABCDEF]{8}\s+.*?\s+%s" % re.escape(jt_str), asm_lst): r = re.search(r"\d+\s([\dABCDEF]{8})", m.strip(), re.IGNORECASE).group(1) #print "AddCodeXref(0x%08x, 0x%08x, idc.XREF_USER)" % (jt_ea+base_addr, idc.Dword(int(r, 16)+base_addr)) idc.AddCodeXref(jt_ea + base_addr, idc.Dword(int(r, 16) + base_addr), idc.XREF_USER) else: raise MiscError for line in asm_lst.split("\n"): comment = re.search(r"###(.*?)###", line) if comment != None: data = re.search(r"\s*\d+\s([\dABCDEF]+)\s([\dABCDEF\(\)]+)", line) if data != None: offset = int(data.group(1), 16) idc.MakeComm(write_ea + offset, comment.group(1)) fp.close() return write_ea + data_len + 10