def decrypt_data(xref, cfunc, xref_args): print("%s: " % hex(int(xref)), end='') args = convert_args_to_long(xref_args) if args: try: key = idaapi.get_many_bytes( args[2], args[3] if idc.Dword(args[3]) == 0xffffffff else idc.Dword(args[3])) data = idaapi.get_many_bytes( args[0], args[1] if idc.Dword(args[1]) == 0xffffffff else idc.Dword(args[1])) except TypeError: print("Couldn't retrieve the cipher or the key.") print(xref_args) else: key = null_pad(key, 0x20) if args[4] == 1: data = custom_b64decode(data) plain = PKCS7_unpad( AES.new(key, AES.MODE_CBC, "\x00" * 16).decrypt(data)) #add_comment(cfunc, plain, xref) print(plain) else: print("Not all args are numbers") print(xref_args)
def isLikeLoadJmpTable(ea): insn_t = idautils.DecodeInstruction(ea) # 1) mov reg, off[reg*4] if hasDispl(insn_t, 1): base, scale, index, displ = getAddressParts(insn_t, 1) if base == 5 and scale == 2 and idc.isData(idc.GetFlags(displ)): # check if there is a table of valid code pointers ncases = 0 bs = idaapi.get_many_bytes(displ, 4) if bs == None or len(bs) != 4: return False jmpaddress = struct.unpack('<I', bs)[0] while idc.isCode(idc.GetFlags(jmpaddress)): ncases += 1 bs = idaapi.get_many_bytes(displ+ncases*4, 4) if bs == None or len(bs) != 4: break jmpaddress = struct.unpack('<I', bs)[0] if ncases != 0: return True return False
def handleLikeLoadJmpTable(ins, F): insn_t = DecodeInstruction(ins) base, index, scale, displ = getAddressParts(insn_t, 1) ncases = 0 bs = idaapi.get_many_bytes(displ, 4) if bs == None or len(bs) != 4: return None jmpt = JmpTable(addr=displ, function=F) succ = JMPTABLES.succ(jmpt) jmpaddress = struct.unpack('<I', bs)[0] while idc.isCode(idc.GetFlags(jmpaddress)) and (succ is None or displ+ncases*4 < succ.get_start()): DEBUG("jmpaddress = {0:x}\n".format(jmpaddress)) jmpt.add_entry(jmpaddress) ncases += 1 bs = idaapi.get_many_bytes(displ+ncases*4, 4) if bs == None or len(bs) != 4: break jmpaddress = struct.unpack('<I', bs)[0] DEBUG("handleLikeLoadJmp @ {0:x} #{1}".format(jmpt.get_start(), len(jmpt.entries()))) return jmpt
def _read_bytes(start_ea, end_ea): """ Reads and returns the bytes from <start_ea> to <end_ea>. Reads are returned in sections READ_LENGTH in length to avoid potential memory concerns for extremely large ranges. :param start_ea: The start of the range :param end_ea: The end of the range :return: A string of the bytes in the given range """ global SECTION_START block_start = start_ea block_end = end_ea while block_start < end_ea: while block_start < end_ea and idaapi.get_many_bytes(block_start, 1) is None: block_start += 1 if block_start >= end_ea: break block_end = block_start + 1 while block_end < end_ea and idaapi.get_many_bytes(block_end, 1) is not None: block_end += 1 SECTION_START = block_start while block_start < block_end: yield idaapi.get_many_bytes( block_start, min(READ_LENGTH, block_end - block_start)) SECTION_START += READ_LENGTH block_start += READ_LENGTH block_start = block_end + 1
def custom_ana(self): b = idaapi.get_many_bytes(self.cmd.ea, 1) if idaapi.get_many_bytes(self.cmd.ea, 1) != "\x6a": pass # print "prout" g_bytecodes[b] += 1 return False # deactivated for now return True
def find_binary_instruction_start(search_start_location, search_direction, target, min_location=idc.MinEA(), max_location=idc.MaxEA()): """ Description: Given a starting location, target, and direction, find an instruction starting with the target bytes. Input: search_start_location - The EA to start searching at search_direction - either idc.SEARCH_UP or idc.SEARCH_DOWN target - The target as space separated bytes (i.e. '55' for 'push ebp') min_location - The minimum EA to accept results for (default: idc.MinEA()) max_location - The maximum EA to accept results for (default: idc.MaxEA()) Output: Returns the first matching location if found, otherwise idc.BADADDR """ target = target.upper() while search_start_location < max_location: ea = idc.FindBinary(search_start_location, search_direction, target) if (min_location <= ea < max_location and ea == idc.ItemHead(ea) and idaapi.get_many_bytes(ea, idc.ItemSize(ea)).encode('hex').upper().startswith(target.replace(' ', ''))): return ea else: search_start_location = ea + (1 if search_direction == idc.SEARCH_DOWN else -1) return idc.BADADDR
def handleJmpTable(I, F, inst, new_eas): si = idaapi.get_switch_info_ex(inst) jsize = si.get_jtable_element_size() jstart = si.jumps # try to fix a problem with IDA, which # doesn't recognise completely switch if jstart == 0xffffffff: jstart = list(DataRefsFrom(inst))[0] # only handle size 4 cases if jsize != 4: raise Exception("Jump table size not 4!") return DEBUG("\tJMPTable Start: {0:x}\n".format(jstart)) if I is not None: I.jump_table.zero_offset = 0 jmpt = JmpTable(addr=jstart, function=F) # Return empty object - jump tables disabled return jmpt i = 0 data = idaapi.get_many_bytes(jstart+i*jsize, 4) #TODO: fix this if data is None: return jmpt je = struct.unpack('<I', data)[0] while i < si.ncases: if I is not None: I.jump_table.table_entries.append(je) if je not in RECOVERED_EAS: new_eas.add(je) DEBUG("\t\tAdding JMPTable {0}: {1:x}\n".format( i, je)) else: new_eas.add(je) jmpt.add_entry(je) i += 1 je = struct.unpack('<I', idaapi.get_many_bytes(jstart+i*jsize, 4))[0] return jmpt
def custom_ana(self): if idaapi.get_many_bytes(self.cmd.ea, 2) != "\xCD\x80": return False self.cmd.itype = NN_kernel_call self.cmd.size = 2 return True
def getblock(start, end): if start > end: start,end=end,start length = end-start if not contains(start): raise ValueError('Address %x is not in database'%start) return idaapi.get_many_bytes(start, length)
def parse_objc_methtype_data(ea): """ Read methtype string from objc_methtype segment. Also applies to the __objc_methname, __objc_classname segments. :param ea: ea at objc_methtype segment :return: methtype string. """ length = idc.ItemSize(ea) return idaapi.get_many_bytes(ea, length)
def getblock(start, end): if start > end: start, end = end, start length = end - start if not contains(start): raise ValueError('Address %x is not in database' % start) return idaapi.get_many_bytes(start, length)
def instruction_data(func_item): """ Returns an integer representing the instruction. """ func_item_size = idautils.DecodeInstruction(func_item).size cmd_data = 0 for i in idaapi.get_many_bytes(func_item, func_item_size): cmd_data = (cmd_data << 8) + ord(i) return cmd_data
def read(): '''Return the contents of the current segment.''' segment = ui.current.segment() if segment is None: raise E.SegmentNotFoundError( "{:s}.read() : Unable to locate the current segment.".format( __name__)) return idaapi.get_many_bytes(segment.startEA, segment.endEA - segment.startEA)
def parse_cfstring(ea): """ Parse cfstring. :param ea: address at __cfstring segment. :return: String. """ data = idc.Qword(ea + 0x10) length = idc.Qword(ea + 0x18) return idaapi.get_many_bytes(data, length)
def handle_string_mov(ea, state): """Updates the stack based on a movs instruction. Used by create_stack If a rep/repne prefix is used, takes the count from ecx. If the count cannot be determined, will ignore the instruction. Also assumes that esi points to memory within the executable, and edi points to the stack. On any errors, this will ignore the instruction. :param ea: instruction location :param state: the current TraceState :return: None - updates stack or regs """ opcode = idaapi.get_many_bytes(ea, 1) rep_inst = opcode in ['\xf2', '\xf3'] count = state.get_reg_value('ecx') if rep_inst else 1 if not count or count < 0: return inslen = idaapi.decode_insn(ea) dtyp = idaapi.cmd.Operands[0].dtyp word_size = [1, 2, 4][dtyp] if dtyp < 3 else 4 count *= word_size src = state.get_reg_value('esi') dst = state.get_reg_value('edi') if src is None or dst is None: return # In IDA 7, get_many_bytes doesn't return None on failure, instead it will return # a string of \xff the size of count. My theory is that the function changed # to return -1 for each byte within the c code and something is casting it to a string before returning. # Since, all \xff's could be valid we need to check if src is valid instead. if not idc.is_loaded(src): return bytes = idaapi.get_many_bytes(src, count) if bytes in ( None, -1): # Keep this around in-case they fix it in a future version. return for i in xrange(count): state.stack[dst + i] = (ord(bytes[i]), ea) if rep_inst: state.set_reg_value('ecx', 0, ea) state.set_reg_value('esi', src + count, ea) state.set_reg_value('edi', dst + count, ea)
def string(key=None): '''Given a segment_t/address, return it's contents as a string''' if key is None: segment = ui.current.segment() if segment is None: raise LookupError, "segment.string(%r):Not currently positioned within a segment" % key else: segment = by(key) return idaapi.get_many_bytes(segment.startEA, segment.endEA - segment.startEA)
def has_all_vtable_functions_named(vtable_ea): # type: (int) -> bool ea = vtable_ea while True: function_ea = struct.unpack('<Q', idaapi.get_many_bytes(ea, 8))[0] if '__cxa_pure_virtual' not in idc.GetDisasm(function_ea) and not idaapi.is_func(idaapi.get_flags(function_ea)): break current_name = idc.GetFunctionName(function_ea) if current_name.startswith('sub_') or current_name.startswith('j_sub_'): return False ea += 8 return True
def decrypt_data(xref, cfunc, xref_args): print("%s: " % hex(int(xref)), end='') args = convert_args_to_long(xref_args) if args: try: key = idaapi.get_many_bytes(args[2], args[3] if idc.Dword(args[3]) == 0xffffffff else idc.Dword(args[3])) data = idaapi.get_many_bytes(args[0], args[1] if idc.Dword(args[1]) == 0xffffffff else idc.Dword(args[1])) except TypeError: print("Couldn't retrieve the cipher or the key.") print(xref_args) else: key = null_pad(key, 0x20) if args[4] == 1: data = custom_b64decode(data) plain = PKCS7_unpad(AES.new(key, AES.MODE_CBC, "\x00"*16).decrypt(data)) #add_comment(cfunc, plain, xref) print(plain) else: print("Not all args are numbers") print(xref_args)
def dumpFunc(funcname, restype=None, args=[]): # Find the function with funcname in the IDA database # Dump the raw bytes to a file named <funcname>.<restype>.<arg1type>.<arg2type>.funcblob funcstart = getFunctionEa(funcname) funcend = FindFuncEnd(funcstart) functionbytes = idaapi.get_many_bytes(funcstart, funcend - funcstart) outfilename = os.path.join( PATH, "%s.%s." % (funcname, restype) + ".".join(args) + ".funcblob") f = open(outfilename, "wb") f.write(functionbytes) f.close()
def isFwdExport(iname, ea): l = ea if l == idc.BADADDR: raise Exception("Cannot find addr for: " + iname) pf = idc.GetFlags(l) if not idc.isCode(pf) and idc.isData(pf): sz = idc.ItemSize(l) iname = idaapi.get_many_bytes(l, sz-1) return iname return None
def StartDump(self): # print self.start # print self.endorlen self.filepath = idaapi.ask_file(1, "*.dump", "save dump file") if self.dumptype == 0: ea = self.getHexNum(self.start) len = self.getHexNum(self.endorlen) if not idaapi.is_loaded(ea) or not idaapi.is_loaded(ea + len): idaapi.warning("arrary is out of bound") return -1 if len <= 0: idaapi.warning("len is <= 0") return -1 print("start read bytes") self.Close(0) idaapi.show_wait_box("read bytes") self.memdata = idaapi.get_many_bytes(ea, len) print("read bytes end") idaapi.hide_wait_box("read end") elif self.dumptype == 1: ea = self.getHexNum(self.start) len = self.getHexNum(self.endorlen) - self.getHexNum(self.start) if not idaapi.is_loaded(ea) or not idaapi.is_loaded(ea + len): idaapi.warning("arrary is out of bound") return -1 if len <= 0: idaapi.warning("len is <= 0") return -1 print("start read bytes") self.Close(0) idaapi.show_wait_box("read bytes") self.memdata = idaapi.get_many_bytes(ea, len) print("read bytes end") idaapi.hide_wait_box("read end") fp = open(self.filepath, 'wb') fp.write(self.memdata) fp.close() idaapi.msg("save:" + self.filepath) return 1
def scanDataForCodePointers(start, end, fn_pointers): while start + 4 < end: bs = idaapi.get_many_bytes(start, 4) if bs is None or len(bs) != 4: break data = struct.unpack('<I', bs)[0] if inValidSegment(data) and idc.isCode(idc.GetFlags(data)): DEBUG("{0:x} Found code pointer to: {1:x}\n".format(start, data)) if data not in RECOVERED_EAS: fn_pointers.add(data) start += 1
def generate_yara_rule(self, mode, is_data=False): start, end = get_selection() size = end - start data = idaapi.get_many_bytes(start, size) ins_set, ins_mode = get_arch_info() yr_gen = YaraGenerator(mode, ins_set, ins_mode) yr_gen.add_chunk(data, offset=start, is_data=is_data) rule_obj = yr_gen.generate_rule() file_hash = get_input_file_hash() rule_obj.metas["hash"] = "\"{}\"".format(file_hash) rule = rule_obj.get_rule_string() self.dialog = YaraRuleDialog(None, start, end, rule) self.dialog.show()
def activate(self, ctx): sel = idaapi.read_selection() if not sel[0]: print 'Please select something' return import capstone md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_64) md.details = True data = idaapi.get_many_bytes(sel[1], sel[2] - sel[1]) for insn in md.disasm(data, sel[1]): # print "0x%x:\t%s\t%s" % (insn.address, insn.mnemonic, insn.op_str) idaapi.set_cmt(insn.address, str('%s %s' % (insn.mnemonic, insn.op_str)), False)
def save_binary_dump(filename, addr, length): if os.path.exists(filename) and not gui.ask("File exists. Overwrite?"): return f = open(filename, "wb") end = addr + length for ea in range(addr, end, 0x1000): min_len = min(end - ea, 0x1000) bts = idaapi.get_many_bytes(ea, min_len) f.write(bts) f.close() print "Saved binary data addr = %s length =%s to %s" % ( hex(addr), hex(length), filename)
def try_make_function(function_start, function_end=idc.BADADDR, target_location=None, require_term=True, end_mnem_bytes=None): """ Description: Given a function location, attempt to create a function. If function creation fails, delete any partially created functions. If function creation succeeds, ensure all of the function's bytes are analyzed as code. Input: function_start - The startEA of the function to create function_end - The endEA of the function to create. IDA will calculate if not provided. target_location - If provided, fail function creation if it does not include this EA require_term - If provided, fail function creation if the last instruction is not a ret or jmp end_mnem_bytes - If provided, fail function creation if the last instruction is not the provided bytes Instructions are entered as space separated bytes (i.e. '55' for 'push ebp') Output: Returns a tuple (function_start, function_end) for the created function if successful, None otherwise """ if function_start <= function_end: if idc.MakeFunction(function_start, function_end): append_debug('Created a function 0x%X - 0x%X.' % (function_start, function_end)) if require_term: last_mnem_ea = idc.ItemHead(idaapi.get_func(function_start).endEA - 1) last_mnem = idc.GetMnem(last_mnem_ea) if (end_mnem_bytes is None and 'ret' not in last_mnem and 'jmp' not in last_mnem) or \ (end_mnem_bytes and idaapi.get_many_bytes(last_mnem_ea, idc.ItemSize(last_mnem_ea)).encode('hex').upper() != end_mnem_bytes.upper()): idc.DelFunction(function_start) append_debug( 'Deleted function at 0x%X - the function didn\'t end with the correct mnem/bytes.' % function_start) return if target_location is not None: if function_start <= target_location < idaapi.get_func(function_start).endEA: idc.AnalyzeArea(function_start, idaapi.get_func(function_start).endEA) return function_start, function_end else: idc.DelFunction(function_start) append_debug( 'Deleted function at 0x%X - the function didn\'t contain the target location.' % function_start) return else: append_debug( 'Tried to create a function 0x%X - 0x%X, but IDA wouldn\'t do it.' % (function_start, function_end)) else: append_debug('The end address was not greater than the start address!')
def calc_most_common_start_bytes(): """ Description: Iterate over all non-lib (and non-thunk) functions and record their first instruction. Return the bytes for whichever instruction appears most. Output: A space separated string of bytes of the most common first instruction. """ counts = {} for func_ea in idautils.Functions(): if not idc.GetFunctionFlags(func_ea) & (idc.FUNC_LIB | idc.FUNC_THUNK): start_bytes = idaapi.get_many_bytes(func_ea, idc.ItemSize(func_ea)) if start_bytes in counts: counts[start_bytes] += 1 else: counts[start_bytes] = 1 return ' '.join('%02X' % ord(c) for c in sorted(counts.items(), key=lambda tup: tup[1], reverse=True)[0][0])
def get_bytes(self): """ Description: Get self.size bytes at self.string_location. Input: Requires a valid self.size. Output: Returns self.size bytes at self.string_location Throws: ValueError - Size was not valid. """ if self.size == INVALID: raise ValueError("Size was never calculated!") bytes = idaapi.get_many_bytes(self.string_location, self.size) if self.size else '' return bytes if bytes is not None else INVALID
def rename_vtable_functions(names, vtable_ea, class_name): # type: (typing.Dict[int, str], int, str) -> None ea = vtable_ea i = 0 while True: function_ea = struct.unpack('<Q', idaapi.get_many_bytes(ea, 8))[0] if '__cxa_pure_virtual' not in idc.GetDisasm(function_ea) and not idaapi.is_func(idaapi.get_flags(function_ea)): break member_fn_name = names.get(i, "m%d" % i) function_name = "%s::%s" % (class_name, member_fn_name) current_name = idc.GetFunctionName(function_ea) if current_name.startswith('nullsub_') or current_name.startswith('j_nullsub_'): idc.MakeNameEx(function_ea, function_name + '_null', idaapi.SN_NOWARN) elif current_name.startswith('sub_') or \ current_name.startswith("%s::m%d" % (class_name, i)) or \ "runtimetypeinfo" in current_name.lower(): idc.MakeNameEx(function_ea, function_name, idaapi.SN_NOWARN) i += 1 ea += 8
def show_edit_form(self): selection, start_ea, end_ea = idaapi.read_selection() if not selection: start_ea = idaapi.get_screen_ea() end_ea = start_ea + 1 buf_len = end_ea - start_ea buf = idaapi.get_many_bytes(start_ea, buf_len) or "\xFF"*buf_len buf_str = " ".join(["%02X" % x for x in buf]) fpos = idaapi.get_fileregion_offset(start_ea) addr_str = "%#X" % start_ea fpos_str = "%#x" % fpos if fpos != -1 else "N/A" f = PatchEditForm(addr_str, fpos_str, buf_str, buf_str) # Execute the form ok = f.Execute() if ok == 1: # Convert hex bytes to binary buf = f.strPatch.value buf = buf.replace(' ','') # remove spaces buf = buf.replace('\\x','') # remove '\x' prefixes buf = buf.replace('0x','') # remove '0x' prefixes try: buf = binascii.unhexlify(buf) # convert to bytes except Exception as e: idaapi.warning("Invalid input: %s" % e) f.Free() return # Now apply newly patched bytes idaapi.patch_many_bytes(start_ea, buf) # Refresh all IDA views self.patch_view.Refresh() # Dispose the form f.Free()
def ida_get_item(self, address, hex_output=False): if self.check_address(address) != 1: # not a valid address return (None, 0) # return None if address is in the middle of instruction / data if address != idc.ItemHead(address): return (None, 0) len = idc.ItemSize(address) item = idaapi.get_many_bytes(address, len) if item is None: return (None, 0) if hex_output: item = to_hexstr(item) return (item, len)
def get_hkclass_list(): # hkBuiltinTypeRegistry::StaticLinkedClasses ARRAY_START = 0x710254D830 classes = [] # type: typing.List[int] ea = ARRAY_START while True: class_ea = struct.unpack('<Q', idaapi.get_many_bytes(ea, 8))[0] if not class_ea: break classes.append(class_ea) ea += 8 # StaticCompoundInfo classes.append(0x710260E1B0) # ActorInfo classes.append(0x710260E130) # ShapeInfo classes.append(0x710260E0B0) return classes
def show_edit_form(self): selection, start_ea, end_ea = idaapi.read_selection() if not selection: start_ea = idaapi.get_screen_ea() end_ea = start_ea + 1 buf_len = end_ea - start_ea buf = idaapi.get_many_bytes(start_ea, buf_len) or "\xFF"*buf_len buf_str = " ".join(["%02X" % ord(x) for x in buf]) fpos = idaapi.get_fileregion_offset(start_ea) addr_str = "%#X" % start_ea fpos_str = "%#x" % fpos if fpos != -1 else "N/A" f = PatchEditForm(addr_str, fpos_str, buf_str, buf_str) # Execute the form ok = f.Execute() if ok == 1: # Convert hex bytes to binary buf = f.strPatch.value buf = buf.replace(' ','') # remove spaces buf = buf.replace('\\x','') # remove '\x' prefixes buf = buf.replace('0x','') # remove '0x' prefixes try: buf = binascii.unhexlify(buf) # convert to bytes except Exception, e: idaapi.warning("Invalid input: %s" % e) f.Free() return # Now apply newly patched bytes idaapi.patch_many_bytes(start_ea, buf) # Refresh all IDA views self.patch_view.Refresh()
def get_context( self, bb, bytes=True, itype1=True, itype2=False, icount=True): """Compute the context of a basic block""" # Get the bytes if bytes: self.bytes = idaapi.get_many_bytes(bb.start, bb.end - bb.start) # Count instructions if icount: self.inst_count = InstructionCount(bb.start, bb.end) # Get the itype1 hash if itype1: self.hash_itype1 = hash_itype1(bb.start, bb.end) # Get the itype2 hash if itype2: self.hash_itype2 = hash_itype2(bb.start, bb.end)
def relocate_segment(source, destination, size): buf = idaapi.get_many_bytes(source, size) idaapi.patch_many_bytes(destination, buf)
def parse_structures(): # Searching structures, and if not exists - creating them # RSA KEY structure rsa_key = idc.GetStrucIdByName("rsa_key") rsa_key_str = """ struct rsa_key { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; }; """ if rsa_key == -1: rsa_key = idc.AddStrucEx(-1, "rsa_key", 0) idc.AddStrucMember(rsa_key, "key_id", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(rsa_key, "key_type", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(rsa_key, "key_rights", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(rsa_key, "modul_length", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(rsa_key, "e_value", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(rsa_key, "modul", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 256) # RSA ASN1 DIGEST structure rsa_asn1_digest = idc.GetStrucIdByName("rsa_asn1_digest") rsa_asn1_digest_str = """ struct rsa_asn1_digest { char signer_info[16]; long signature_info; long key_id; char digest[256]; }; """ if rsa_asn1_digest == -1: rsa_asn1_digest = idc.AddStrucEx(-1, "rsa_asn1_digest", 0) idc.AddStrucMember(rsa_asn1_digest, "signer_info", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 16) idc.AddStrucMember(rsa_asn1_digest, "signature_info", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(rsa_asn1_digest, "key_id", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(rsa_asn1_digest, "digest", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 256) # Cert PK - Public Keys structure certpk_struct = idc.GetStrucIdByName("Cert_Public") certpk_str = """ struct certpk { char cert_mark[8]; long cert_version; long cert_type; long minver_pk; long minver_ppa; long minver_rd1; long minver_rd2; long minver_isw; long minver_ki; long minver_pau; long minver_pas; long unkn1; struct { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; } root_key; long keys_active; struct { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; } key_02; struct { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; } key_03; struct { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; } key_04; struct { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; } key_05; struct { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; } key_06; struct { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; } key_07; long rights; long msv_mask; char zero_hole_2[120]; struct { char signer_info[16]; long signature_info; long key_id; char digest[256]; } digest; };""" if certpk_struct == -1: certpk_struct = idc.AddStrucEx(-1, "Cert_Public", 0) idc.AddStrucMember(certpk_struct, "cert_mark", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 8) idc.AddStrucMember(certpk_struct, "cert_version", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "cert_type", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_pk", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_ppa", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_rd1", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_rd2", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_isw", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_ki", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_pau", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_pas", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "unkn1", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "root_key", -1, 0x60000400, rsa_key, idc.GetStrucSize(rsa_key)) idc.AddStrucMember(certpk_struct, "keys_active", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "key_02", -1, 0x60000400, rsa_key, idc.GetStrucSize(rsa_key)) idc.AddStrucMember(certpk_struct, "key_03", -1, 0x60000400, rsa_key, idc.GetStrucSize(rsa_key)) idc.AddStrucMember(certpk_struct, "key_04", -1, 0x60000400, rsa_key, idc.GetStrucSize(rsa_key)) idc.AddStrucMember(certpk_struct, "key_05", -1, 0x60000400, rsa_key, idc.GetStrucSize(rsa_key)) idc.AddStrucMember(certpk_struct, "key_06", -1, 0x60000400, rsa_key, idc.GetStrucSize(rsa_key)) idc.AddStrucMember(certpk_struct, "key_07", -1, 0x60000400, rsa_key, idc.GetStrucSize(rsa_key)) idc.AddStrucMember(certpk_struct, "rights", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "msv_mask", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "zero_hole_2", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 120) idc.AddStrucMember(certpk_struct, "digest", -1, 0x60000400, rsa_asn1_digest, idc.GetStrucSize(rsa_asn1_digest)) # CertPPA - Primary Protected Application Certificate structure certppa_struct = idc.GetStrucIdByName("Cert_Primary") certppa_str = """ struct certppa { char cert_mark[8]; long cert_version; long cert_type; long minver_src; long minver_pk; long minver_ppa; long minver_rd1; long minver_rd2; long minver_isw; struct { int image_offset; int image_size; int data_byte[5]; } images[4]; char zero_hole[128]; struct { char signer_info[16]; long signature_info; long key_id; char digest[256]; } digest; };""" if certppa_struct == -1: certppa_struct = idc.AddStrucEx(-1, "Cert_Primary", 0) idc.AddStrucMember(certppa_struct, "cert_mark", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 8) idc.AddStrucMember(certppa_struct, "cert_version", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "cert_type", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "minver_src", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "minver_pk", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "minver_ppa", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "minver_rd1", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "minver_rd2", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "minver_isw", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "images", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 21) idc.AddStrucMember(certppa_struct, "zero_hole", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 128) idc.AddStrucMember(certppa_struct, "digest", -1, 0x60000400, rsa_asn1_digest, idc.GetStrucSize(rsa_asn1_digest)) # CertISW - Initial Software Certificate structure certisw_struct = idc.GetStrucIdByName("Cert_ISW") certisw_str = """struct certisw { char cert_mark[8]; int cert_version; int cert_type; int minver_src; int minver_pk; int minver_ppa; int minver_rd1; int minver_rd2; int minver_isw; int watchdog_param; int use_DMA; int active_images; struct { int image_offset; int image_size; int data_byte[5]; } images[4]; int magic_1; int reg_bitfield; struct { int reg_address; int reg_value; } reg_table[32]; int reg_type_01; int reg_type_02; int entry_point_offset; int zero_hole[32]; struct { char signer_info[16]; long signature_info; long key_id; char digest[256]; } digest; };""" mbmloader_hdr_str = """struct mbmloader_head { void *entry_point; int anonymous_0; void *anonymous_1; void *anonymous_2; void *anonymous_3; void *anonymous_4; int anonymous_5; int field_1C; void *anonymous_7; int field_24; void *anonymous_8; int anonymous_9; int ruler[4]; char srk_part_1[128]; int srk_1; void *srk_1_pointer; int field_C8; int field_CC; char srk_part_2[128]; int srk_2; void *srk_2_pointer; int field_158; int field_15C; char sha_160_hash[20]; };""" # Searching main structures marks start = idc.MinEA() stop = idc.MaxEA() certpk_addr = idaapi.find_binary(start, stop, "43 65 72 74 50 4B 5F 00", 0, 0) # "CertPK_" string print "Found CertPK at 0x%x" % certpk_addr certppa_addr = idaapi.find_binary(start, stop, "43 65 72 74 50 50 41 00", 0, 0) # "CertPPA" string print "Found CertPPA at 0x%x" % certppa_addr certisw_addr = idaapi.find_binary(start, stop, "43 65 72 74 49 53 57 00", 0, 0) # "CertISW" string print "Found CertISW at 0x%x" % certisw_addr # Apply structure types on Cert* addresses # Read Structures from such data # If type is not parsed already, then... if idc.ParseTypes("certpk;", idc.PT_SILENT) != 0: # ...define the type idc.ParseTypes(certpk_str, idc.PT_SILENT) if idc.ParseTypes("certppa;", idc.PT_SILENT) != 0: idc.ParseTypes(certppa_str, idc.PT_SILENT) if idc.ParseTypes("certisw;", idc.PT_SILENT) != 0: idc.ParseTypes(certisw_str, idc.PT_SILENT) certpk_ = idaapi.Appcall.typedobj("certpk;") certpk_read, certpk = certpk_.retrieve(idaapi.get_many_bytes(certpk_addr, certpk_.size)) certppa_ = idaapi.Appcall.typedobj("certppa;") certppa_read, certppa = certppa_.retrieve(idaapi.get_many_bytes(certppa_addr, certppa_.size)) certisw_ = idaapi.Appcall.typedobj("certisw;") certisw_read, certisw = certisw_.retrieve(idaapi.get_many_bytes(certisw_addr, certisw_.size)) # Make PEM keys if certpk_read == 1 : root_key = construct_public_key(certpk.root_key.e_value, int(certpk.root_key.modul[0:certpk.root_key.modul_length].encode("hex"), 16), certpk.root_key.modul_length * 8) root_key.save_key("root_key.pem") # TODO: add automatic export of all ACTIVE keys from certpk.active_keys pk_02 = construct_public_key(certpk.key_02.e_value, int(certpk.key_02.modul[0:certpk.key_02.modul_length].encode("hex"), 16), certpk.key_02.modul_length * 8) pk_02.save_key("pk_02.pem") pk_03 = construct_public_key(certpk.key_03.e_value, int(certpk.key_03.modul[0:certpk.key_03.modul_length].encode("hex"), 16), certpk.key_03.modul_length * 8) pk_03.save_key("pk_03.pem") pk_04 = construct_public_key(certpk.key_04.e_value, int(certpk.key_04.modul[0:certpk.key_04.modul_length].encode("hex"), 16), certpk.key_04.modul_length * 8) pk_04.save_key("pk_04.pem") else : print "CertPK read fail!" # Verify digests if (certpk_read == 1) & (certppa_read == 1) & (certisw_read == 1) : certpk_digest = certpk.digest.digest.encode("hex") certppa_digest = certppa.digest.digest.encode("hex") certisw_digest = certisw.digest.digest.encode("hex") # pk_03.public_decrypt(certisw_digest, 1) # pk_03.verify(idaapi.get_many_bytes(certisw_addr, certisw_.size), certisw_digest, "sha1") # decoder.decode(certpk.digest.signer_info, ) print "CertPK signer info: %s " % certpk.digest.signer_info.encode("hex") print "CertPK digest: %s " % certpk.digest.digest.encode("hex") print "CertPPA signer info: %s " % certppa.digest.signer_info.encode("hex") print "CertPPA digest: %s " % certppa.digest.digest.encode("hex") print "CertISW signer info: %s " % certisw.digest.signer_info.encode("hex") print "CertISW digest: %s " % certisw.digest.digest.encode("hex") else : print "Certs processing fail!" # TODO: Parse rights of the keys # TODO: Parse ASN1 from digests # Processing Images i = 0 while i < 4 : print "images type %s " % type (certppa.images) if certppa.images[i].image_offset != 0 : print "Found PPA image at %x offset " % certppa.images[i].image_offset if certisw.images[i].image_offset != 0 : print "Found ISW image at %x offset " % certisw.images[i].image_offset i += 1
def read(ea, size): return idaapi.get_many_bytes(ea, size)
def read_memory(start, end): size = end - start return idaapi.get_many_bytes(start, size)
def read(): '''Return the contents of the current segment.''' segment = ui.current.segment() if segment is None: raise E.SegmentNotFoundError(u"{:s}.read() : Unable to locate the current segment.".format(__name__)) return idaapi.get_many_bytes(segment.startEA, segment.endEA-segment.startEA)
def read(segment): '''Return the contents of the segment identified by `segment`.''' seg = by(segment) return idaapi.get_many_bytes(seg.startEA, seg.endEA-seg.startEA)
def read_data(ea, sz): """ Read bytes from idb """ return idaapi.get_many_bytes(ea, sz)
def string(segment): '''Given a segment_t/address, return it's contents as a string''' if type(segment) is idaapi.segment_t: return idaapi.get_many_bytes(segment.startEA, segment.endEA-segment.startEA) return string(by(segment))
def activate(self, ctx): if self.action in ACTION_CONVERT: # convert selection, start, end = idaapi.read_selection() if selection: size = end - start elif ItemSize(ScreenEA()) > 1: start = ScreenEA() size = ItemSize(start) end = start + size else: return False data = idaapi.get_many_bytes(start, size) name = Name(start) if not name: name = "data" if data: print "\n[+] Dump 0x%X - 0x%X (%u bytes) :" % (start, end, size) if self.action == ACTION_CONVERT[0]: # escaped string print '"%s"' % "".join("\\x%02X" % ord(b) for b in data) elif self.action == ACTION_CONVERT[1]: # hex string print "".join("%02X" % ord(b) for b in data) elif self.action == ACTION_CONVERT[2]: # C array output = "unsigned char %s[%d] = {" % (name, size) for i in range(size): if i % 16 == 0: output += "\n " output += "0x%02X, " % ord(data[i]) output = output[:-2] + "\n};" print output elif self.action == ACTION_CONVERT[3]: # C array word data += "\x00" array_size = (size + 1) / 2 output = "unsigned short %s[%d] = {" % (name, array_size) for i in range(0, size, 2): if i % 16 == 0: output += "\n " output += "0x%04X, " % u16(data[i:i+2]) output = output[:-2] + "\n};" print output elif self.action == ACTION_CONVERT[4]: # C array dword data += "\x00" * 3 array_size = (size + 3) / 4 output = "unsigned int %s[%d] = {" % (name, array_size) for i in range(0, size, 4): if i % 32 == 0: output += "\n " output += "0x%08X, " % u32(data[i:i+4]) output = output[:-2] + "\n};" print output elif self.action == ACTION_CONVERT[5]: # C array qword data += "\x00" * 7 array_size = (size + 7) / 8 output = "unsigned long %s[%d] = {" % (name, array_size) for i in range(0, size, 8): if i % 32 == 0: output += "\n " output += "%#018X, " % u64(data[i:i+8]) output = output[:-2] + "\n};" print output.replace("0X", "0x") elif self.action == ACTION_CONVERT[6]: # python list print "[%s]" % ", ".join("0x%02X" % ord(b) for b in data) elif self.action == ACTION_CONVERT[7]: # python list word data += "\x00" print "[%s]" % ", ".join("0x%04X" % u16(data[i:i+2]) for i in range(0, size, 2)) elif self.action == ACTION_CONVERT[8]: # python list dword data += "\x00" * 3 print "[%s]" % ", ".join("0x%08X" % u32(data[i:i+4]) for i in range(0, size, 4)) elif self.action == ACTION_CONVERT[9]: # python list qword data += "\x00" * 7 print "[%s]" % ", ".join("%#018X" % u64(data[i:i+8]) for i in range(0, size, 8)).replace("0X", "0x") elif self.action == ACTION_XORDATA: selection, start, end = idaapi.read_selection() if not selection: if ItemSize(ScreenEA()) > 1: start = ScreenEA() end = start + ItemSize(start) else: return False data = idaapi.get_many_bytes(start, end - start) x = AskLong(0, "Xor with...") if x: x &= 0xFF print "\n[+] Xor 0x%X - 0x%X (%u bytes) with 0x%02X:" % (start, end, end - start, x) print repr("".join(chr(ord(b) ^ x) for b in data)) elif self.action == ACTION_FILLNOP: selection, start, end = idaapi.read_selection() if selection: idaapi.patch_many_bytes(start, "\x90" * (end - start)) print "\n[+] Fill 0x%X - 0x%X (%u bytes) with NOPs" % (start, end, end - start) elif self.action == ACTION_SCANVUL: print "\n[+] Finding Format String Vulnerability..." found = [] for addr in idautils.Functions(): name = GetFunctionName(addr) if "printf" in name and "v" not in name and SegName(addr) in (".text", ".plt", ".idata"): xrefs = idautils.CodeRefsTo(addr, False) for xref in xrefs: vul = self.check_fmt_function(name, xref) if vul: found.append(vul) if found: print "[!] Done! %d possible vulnerabilities found." % len(found) ch = VulnChoose("Vulnerability", found, None, False) ch.Show() else: print "[-] No format string vulnerabilities found." else: return 0 return 1
import idaapi import idautils import idc import struct for func_addr in idautils.Functions(0, 0xffffffff): # Signature is based on the beginning of the decryption function: # 53 push ebx # 8B DA mov ebx, edx # 56 push esi # 33 F6 xor esi, esi # 57 push edi # 8B F9 mov edi, ecx # 39 34 DD C4 DE 06+ cmp dword_1006DEC4[ebx*8], esi if idaapi.get_many_bytes(func_addr, 12) == "538BDA5633F6578BF93934DD".decode('hex'): decoding_func = idaapi.get_func(func_addr) break for addr in idautils.Heads(decoding_func.startEA, decoding_func.endEA): if chr(idaapi.get_byte(addr)) == "\x8A": # 8A 89 B0 D5 04 10 mov cl, key[ecx] # ^ key offset key_offset = struct.unpack("<I", idaapi.get_many_bytes(addr + 2, 4))[0] elif idaapi.get_many_bytes(addr, 1) == "\x6B": # 6B C2 33 imul eax, edx, 51 # ^ key length key_len = idaapi.get_byte(addr + 2) elif idaapi.get_many_bytes(addr, 3) == "\x8B\x04\xDD": # 8B 04 DD C0 DE 06 10 mov eax, packed_strings_list[ebx*8] # ^ address of string list
def bytes(self): return idaapi.get_many_bytes(self.ea, self.size)