def importldsymbols(bv,filename): """Janky parser to import a GNU LD symbols file to Binary Ninja.""" f=open(filename,"r"); for l in f: words=l.strip().split(); try: name=words[0]; adrstr=words[2]; adr=int(adrstr.strip(";"),16); #Function symbols are odd address in Flash. if adr&0xF8000001==0x08000001: bv.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, adr&~1, name)); bv.add_function(adr&~1); print("Imported function symbol %s at 0x%x"%(name,adr)); #Data symbols are in SRAM or TCRAM with unpredictable alignment. elif adr&0xC0000000==0: bv.define_auto_symbol(Symbol(SymbolType.DataSymbol, adr, name)); print("Imported data symbol %s at 0x%x"%(name,adr)); else: print "Uncategorized adr=0x%08x."%adr; except: # Print warnings when our janky parser goes awry. if len(words)>0 and words[0]!="/*" and words[0]!="*/": print("#Warning in: %s\n"%words); log_error(traceback.format_exc())
def init(self): user_choice = get_choice_input("Select MCU family", "MCU selection", self.MCUS) if user_choice is not None: chosen_mcu = self.MCUS[user_choice] mcu_lib = importlib.import_module("binaryninja_cortex.platforms." + chosen_mcu) mcu = mcu_lib.Chip else: mcu_lib = importlib.import_module("binaryninja_cortex.platforms") mcu = mcu_lib.MCU #Add RAM segment self.add_auto_segment( mcu.RAM_OFF, 0xffff, 0, 0, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable) # Add peripherals segment self.add_auto_segment( mcu.PERIPH_OFF, 0x10000000, 0, 0, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable) #Add flash segment, assume flash < 2MB self.add_auto_segment( mcu.ROM_OFF, 0x200000, 0, 0x200000, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) #Add IVT symbols #SP_VALUE is a data pointer self.define_auto_symbol_and_var_or_function( Symbol(SymbolType.DataSymbol, mcu.ROM_OFF, mcu.IRQ[0]), Type.pointer(self.arch, Type.void(), const=True), self.platform) addr = struct.unpack("<I", self.parent_view.read(0, 4))[0] self.define_auto_symbol( Symbol(SymbolType.DataSymbol, addr, "p_{}".format(mcu.IRQ[0]))) #All other vectory are function pointers for i in range(1, len(mcu.IRQ)): self.define_auto_symbol_and_var_or_function( Symbol(SymbolType.DataSymbol, mcu.ROM_OFF + (4 * i), mcu.IRQ[i]), Type.pointer(self.arch, Type.void(), const=True), self.platform) addr = struct.unpack("<I", self.parent_view.read(4 * i, 4))[0] & ~1 self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, addr, "f_{}".format(mcu.IRQ[i]))) self.add_function(addr, self.platform) #Add entry point to RESET_IRQ self.add_entry_point(self.symbols['f_RESET_IRQ'].address, self.platform) return True
def init(self): try: hdr = self.parent_view.read(self.HDR_OFFSET, self.HDR_SIZE) self.rom_title = hdr[0:15] self.color = hdr[15] self.licensee_code = struct.unpack("H", hdr[16:18])[0] self.gb_type = hdr[18] self.cart_type = hdr[19] self.rom_banks = hdr[20] self.ram_banks = hdr[21] self.destination_code = hdr[22] self.old_licensee_code = hdr[23] self.mask_rom_version = hdr[24] self.complement_check = hdr[25] self.checksum = struct.unpack("H", hdr[26:])[0] except: log_error(traceback.format_exc()) return False # Add ROM mappings # ROM0 self.add_auto_segment( self.ROM0_OFFSET, self.ROM0_SIZE, self.ROM0_OFFSET, self.ROM0_SIZE, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_auto_section("ROM0", self.ROM0_OFFSET, self.ROM0_SIZE, SectionSemantics.ReadOnlyCodeSectionSemantics) # ROM1 self.add_auto_segment( self.ROM1_OFFSET, self.ROM1_SIZE, self.ROM1_OFFSET, self.ROM1_SIZE, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_auto_section("ROM1", self.ROM1_OFFSET, self.ROM1_SIZE, SectionSemantics.ReadWriteDataSectionSemantics) # Add RAM mappings for _, address, length in self.RAM_SEGMENTS: self.add_auto_segment( address, length, 0, 0, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable) # Add IO registers for address, name in LR35902.IO_REGISTERS.items(): self.define_auto_symbol_and_var_or_function( Symbol(SymbolType.DataSymbol, address, name), Type.int(1)) # Define entrypoint self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, self.START_ADDR, "_start")) self.add_entry_point(self.START_ADDR) # Define interrupts for name, address in self.INTERRUPT_HANDLERS: self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, address, name)) #self.define_auto_symbol_and_var_or_function(Symbol(SymbolType.FunctionSymbol, address, name), Type.function(Type.void(), [])) return True
def init(self): max_instructions = 0 for basic_block in self.vtil.explored_blocks.basic_blocks: max_instructions += len(basic_block.instructions) # Fill the cache for i in range(0, max_instructions): find_instruction(i, self.vtil) self.add_auto_segment( 0, max_instructions, 0, max_instructions, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable ) self.add_auto_section( ".text", 0, max_instructions, SectionSemantics.ReadOnlyCodeSectionSemantics ) entry_vip = self.vtil.entrypoint.entry_vip entry_addr = find_block_address(entry_vip, self.vtil) symbol = Symbol(SymbolType.FunctionSymbol, entry_addr, f"_vip_{hex(entry_vip)[2:]}") self.define_auto_symbol(symbol) for basic_block in self.vtil.explored_blocks.basic_blocks: vip = basic_block.entry_vip addr = find_block_address(vip, self.vtil) # Append a comment to help with indirect jumps: comment = "" branch_ins = basic_block.instructions[-1] if branch_ins.name == "jmp": if isinstance(branch_ins.operands[0].operand, VTILParser.RegisterDesc): comment += "Indirect => { " + ', '.join('vip_{:x}'.format(trgt) for trgt in basic_block.next_vip) + " }" if basic_block.sp_offset != branch_ins.sp_offset: if comment != "": comment += " | " comment += f"SP Delta: {hex(basic_block.sp_offset)}" if comment != "": self.set_comment_at(addr + len(basic_block.instructions) - 1, comment) if entry_vip == vip: continue symbol = Symbol(SymbolType.FunctionSymbol, addr, f"vip_{hex(vip)[2:]}") self.define_auto_symbol(symbol) self.set_comment_at(addr, f"vip_{hex(vip)[2:]}:") self.add_entry_point(entry_addr) return True
def importr2symbols(bv, filename): """Janky shotgun parser to import Radare2 symbols file to Binary Ninja.""" f = open(filename, "r") for l in f: words = l.strip().split() try: if words[0][0] == "#": pass elif words[0] == "f" and words[2] == "@": #f name @ 0xDEADBEEF name = words[1] adrstr = words[3] adr = int(adrstr.strip(";"), 16) #Functions are in Flash if adr & 0xF8000000 == 0x08000000: bv.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, adr & ~1, name)) bv.add_function(adr & ~1) print("Imported function symbol %s at 0x%x" % (name, adr)) #Data in SRAM or DRAM elif adr & 0xFE000000 == 0x02000000: bv.define_auto_symbol( Symbol(SymbolType.DataSymbol, adr & ~1, name)) print("Imported data symbol %s at 0x%x" % (name, adr)) elif (words[0] == "af+" or words[0] == "f") and int(words[2], 16) > 0: name = words[3] adrstr = words[1] adr = int(adrstr.strip(";"), 16) #Functions are in Flash if adr & 0xF8000000 == 0x08000000: bv.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, adr & ~1, name)) bv.add_function(adr & ~1) print("Imported function symbol %s at 0x%x" % (name, adr)) #Data in SRAM or DRAM elif adr & 0xFE000000 == 0x02000000: bv.define_auto_symbol( Symbol(SymbolType.DataSymbol, adr & ~1, name)) print("Imported data symbol %s at 0x%x" % (name, adr)) else: print("Ignoring: %s" % words) except: if len(words) > 3: print("Ignoring: %s\n" % words)
def get_exports(self): symbols = [] for (name, args, entries) in self.sections: if name != 'EXPORTS': continue for (name, args) in entries.items(): # Format: NAME=INTERNAL_NAME @ordinal [KEYWORDS...] name = quoted_split(name, '=')[0] if not args[0].startswith('@'): continue if args[0][1:]: o = args[0][1:] tag_idx = 1 elif len(args) > 1: o = args[1] tag_idx = 2 else: continue if not o.isdigit(): continue if 'DATA' in args[tag_idx:]: symtype = SymbolType.DataSymbol else: symtype = SymbolType.FunctionSymbol symbols.append(Symbol(symtype, 0, name, ordinal=int(o))) return symbols
def load_symbols(self): super(SurfaceECView, self).load_symbols() # There's six sequential jump tables, used by functions that call # jump_R1:2. base = 0x45eb # TODO pull from functions using them? for i in range(6): self.define_auto_symbol( Symbol(SymbolType.DataSymbol, mem.CODE + base, 'jump_table_' + str(i))) self.define_user_data_var(mem.CODE + base, self.parse_type_string('void*[16]')[0]) for ea in range(base, base + 16 * 2, 2): fp = struct.unpack('>H', self.read(ea, 2))[0] fp += mem.CODE self.add_function(fp) base += 16 * 2 # Flash bank swapping trampolines at 0x3500, refs to them between # 0x3548 first one # 0x3ff8 last one # TODO: autodiscover this region with an instruction regex? for ea in range(0x3548, 0x3ff8 + 6, 6): if (self.read(ea, 1) != '\x90' or self.read(ea + 3, 1) != '\x02'): msg = 'Bad instruction in trampoline jump at ' + hex(ea) raise RuntimeError(msg) self.add_function(ea)
def load_memory(self): super(SurfaceECView, self).load_memory() seg_f = SegmentFlag rw_ = seg_f.SegmentReadable | seg_f.SegmentWritable r_xc = (seg_f.SegmentReadable | seg_f.SegmentExecutable | seg_f.SegmentContainsCode) r__d = seg_f.SegmentReadable | seg_f.SegmentContainsData image_base = 0x0182b # probably signature before # bootloader @ first 0x2000, then this stub self.add_auto_segment(mem.CODE + 0x2000, 0x6000, image_base, 0x6000, r_xc) self.add_auto_section('.code', mem.CODE + 0x2000, 0x6000, SectionSemantics.ReadOnlyCodeSectionSemantics) for page in range(4): # then 4 pages for high half of code self.add_auto_segment(mem.CODE + 0x8000 + 0x8000 * page, 0x8000, image_base + 0x6000 + 0x8000 * page, 0x8000, r_xc) self.add_auto_section( '.page%d' % page, mem.CODE + 0x8000 + 0x8000 * page, 0x8000, SectionSemantics.ReadOnlyCodeSectionSemantics) self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, mem.CODE + 0x8000 + 0x8000 * page, 'page_%d' % page)) self.add_function(mem.CODE + 0x8000 * (page + 1))
def do_discover_caller_names(bv, func): param_name = interaction.get_text_line_input( "Please enter the name of the parameter that contains the method name", "Parameter name") # Docs says the above function returns a string with a link to the Python 3 # docs (e.g. a Py3 str), but it actually returns a bytes-object under Py3 param_name = param_name.decode("utf-8") func_params = [ param for param in func.parameter_vars if param.name == param_name ] force = False if len(func_params) != 1: log_error("Unable to determine method name argument") return for name, func in discover_names(func, func_params).items(): # Skip if named correctly if func.symbol.name == name: continue # Skip if we're not forcing and the user has named this already if not func.symbol.auto and not force: log_debug("Skipped %r due to no auto symbol" % name) continue log_info("Renaming %r to %r" % (func, name)) func.view.define_auto_symbol( Symbol(func.symbol.type, func.symbol.address, short_name=name))
def process_symtable(self, table): pos = 0 while pos + 6 < len(table): name = "" (value, type) = struct.unpack(">Lc", table[pos:pos + 5]) type = chr(type[0] ^ 0x80) pos += 4 if type == 'z': #n = 0 # NOT USED: size of name to malloc() pos += 2 # advance to beginning of hist while table[pos:pos + 2] != b'\x00\x00': #n += 2 pos += 2 # next 2-bytes block pos += 2 # skip double nil else: while pos < len(table): pos += 1 if chr(table[pos]) == "\x00": pos += 1 break name += chr(table[pos]) #log_info('%08x\t%c\t%s' % (value,type,name)) if type == 'T' or type == 't' or type == 'L' or type == 'l': self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, value, name))
def decrypt_strings(bv): data_section = bv.get_section_by_name(".data") data = bv.read(data_section.start, data_section.end - data_section.start) printables = [ord(c) for c in string.printable] for i in range(0, len(data) - 4, 4): key, size = struct.unpack("<2I", data[i:i+8]) size ^= key if size > 0 and size < 400 and i + size < len(data): byte_key = data[i:i+4] decrypted = bytearray() valid = True for j in range(size): char = data[i+8+j] ^ byte_key[j % 4] if char not in printables: valid = False break decrypted.append(char) if valid: sym_addr = data_section.start + i s = bytes(decrypted).decode() sym_name = s[:20].strip() for c in " \t\r\n": sym_name = sym_name.replace(c, "_") sym_name = "str_" + sym_name symbol = Symbol(SymbolType.DataSymbol, sym_addr, sym_name) bv.define_user_symbol(symbol) bv.write(sym_addr, s + "\x00")
def init(self): self.raw = self.data self.binary = self.raw.read(0, len(self.raw)) self.add_analysis_completion_event(self.on_complete) # set base address if self.IS_64: self.load_address = 0x240000000 self.arch = Architecture['aarch64'] self.platform = self.arch.standalone_platform else: self.load_address = 0x10000000 self.arch = Architecture['thumb2'] self.platform = self.arch.standalone_platform print("Base address : " + hex(self.load_address)) self.add_auto_segment(self.load_address, len(self.parent_view), 0, len(self.parent_view), SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_user_section(self.name, self.load_address, len(self.raw), SectionSemantics.ReadOnlyCodeSectionSemantics) self.add_entry_point(self.load_address) self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, self.load_address, '_start')) self.update_analysis() return True
def init(self): # RAM self.add_auto_segment( 0x1000, 0x1000, 0, 0x1000, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable) # Hardware IO Registers self.add_auto_segment( 0x2000, 0x100, 0, 0x100, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable) # Cartridge memory self.add_auto_segment( 0x2100, 0x1fdeff, 0x2100, 0x1fdeff, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) # Cartridge memory mirrors self.add_auto_segment( 0x200000, 0x1fffff, 0x2100, 0x1fdeff, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_auto_segment( 0x400000, 0x1fffff, 0x2100, 0x1fdeff, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_auto_segment( 0x600000, 0x1fffff, 0x2100, 0x1fdeff, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_auto_segment( 0x800000, 0x1fffff, 0x2100, 0x1fdeff, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_auto_segment( 0xA00000, 0x1fffff, 0x2100, 0x1fdeff, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_auto_segment( 0xC00000, 0x1fffff, 0x2100, 0x1fdeff, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_auto_segment( 0xE00000, 0x1fffff, 0x2100, 0x1fdeff, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) for addr, name in default_symbols.items(): self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, addr, name)) for addr, name in mmio_regs.items(): self.define_auto_symbol(Symbol(SymbolType.DataSymbol, addr, name)) self.add_entry_point(0x2102) return True
def resolve_imports_for_library(bv, lib): source_bv = peutils.files[lib.name.lower()] exports = pe_parsing.get_exports(source_bv) for import_ in lib.imports: # Find the name name = None for export in exports: if export.ord == import_.ordinal: print(export) name = export.name export_symbol = export.symbol if not name: log_warn("Unable to find name for %r" % import_) # Redefine the IAT thunk symbol original_symbol = bv.get_symbol_at(import_.datavar_addr) # Delete any existing auto symbols if original_symbol: log_info("Renaming %s to %s:%s" % (original_symbol.name, lib.name, name)) bv.undefine_auto_symbol(original_symbol) else: log_info("Creating IAT symbol %s:%s @ %08x" % (lib.name.split(".")[0], name, import_.datavar_addr)) # Create the new symbol bv.define_auto_symbol( Symbol( SymbolType.ImportAddressSymbol, import_.datavar_addr, name + "@IAT", namespace=lib.name.split(".")[0], )) # Transplant type info export_func = source_bv.get_function_at(export_symbol.address) type_tokens = [token.text for token in export_func.type_tokens] i = type_tokens.index(export_symbol.name) type_tokens[i] = "(*const func_name)" type_string = "".join(type_tokens) log_info("Setting type for %s to %r" % (name, type_string)) try: (type_, name) = bv.parse_type_string(type_string) except: log_error("Invalid type, skipping") bv.define_data_var(import_.datavar_addr, type_) # FIXME: Apply params to ImportedFunctionSymbols -- check xref on # datavar and filter by associated symbols # This doesn't actually seem to help and apparently I didn't have to do # this before? Maybe I just didn't handle jump """
def import_ida(json_file, bv, options): if json_file is None: return False, "No json file specified" imported = None try: f = open(json_file, "rb") imported = json.load(f) except Exception as e: return False, "Failed to parse json file {} {}".format(json_file, e) resolved_functions = imported["functions"] resolved_strings = imported["strings"] # TODO: import segments # TODO: Handle Conflicts if options.import_functions: log("Applying import data", options.verbose) for name, rec in resolved_functions.items(): bv.add_function(rec["start"]) func = bv.get_function_at(rec["start"]) if name != ("sub_%x" % rec["start"]): func.name = name if options.import_comments: if "comment" in rec: func.comment = rec["comment"] if "comments" in rec: for comment, addr in rec["comments"].items(): func.set_comment_at(addr, comment) if "can_return" in rec: func.can_return = rec["can_return"] bv.update_analysis_and_wait() if options.import_strings: log("Importing string types", options.verbose) for addr, (name, length, t, data_refs) in resolved_strings.items(): bv.define_user_data_var(int(addr), Type.array(Type.int(1, None, "char"), length)) if options.import_strings_names: bv.define_user_symbol(Symbol(SymbolType.DataSymbol, int(addr), name)) for ref in data_refs: # references to this data for block in bv.get_basic_blocks_at(ref): # find any references in code for i in block.get_disassembly_text(): # go through all the instructions in the block if i.address == ref: for token in i.tokens: if token.type == InstructionTextTokenType.PossibleAddressToken: print "setting token", i.address, token.value, token.operand, IntegerDisplayType.PointerDisplayType, block.arch block.function.set_int_display_type(i.address, token.value, token.operand, IntegerDisplayType.PointerDisplayType, block.arch) break log("Updating Analysis", options.verbose) bv.update_analysis_and_wait() return True, None
def load_map_file(thread, view, filename): lines = open(filename, 'r').readlines() symbols = parse_map_file(lines) arch = view.arch for name, addr in symbols: if not view.is_valid_offset(addr): continue current_sym = view.get_symbol_at(addr) if current_sym is not None: if not current_sym.auto: continue if current_sym.type not in [ SymbolType.DataSymbol, SymbolType.FunctionSymbol ]: continue view.undefine_user_symbol(current_sym) sym_type, sym_parts = demangle_ms(arch, name) if sym_type is None: sym_type = Type.void() if isinstance(sym_parts, str): sym_parts = [sym_parts] sym_name = '::'.join(sym_parts) if view.is_offset_executable(addr): view.create_user_function(addr) view.define_user_symbol( Symbol(SymbolType.FunctionSymbol, addr, sym_name, raw_name=name)) else: view.define_data_var(addr, sym_type) view.define_user_symbol( Symbol(SymbolType.DataSymbol, addr, sym_name, raw_name=name)) fix_mangled_symbols(thread, view)
def register_peripheral(p, struct_type): bv.add_user_section(p['name'], p['base'], p['size'], SectionSemantics.ReadWriteDataSectionSemantics) bv.add_user_segment( p['base'], p['size'], 0, 0, SegmentFlag.SegmentContainsData | SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable) bv.define_data_var(p['base'], struct_type) bv.define_user_symbol( Symbol(SymbolType.ImportedDataSymbol, p['base'], p['name']))
def init_thumb2(self, adr=0x08000000): try: self.init_common() self.thumb2_offset = 0 self.arm_entry_addr = struct.unpack("<L", self.hdr[0x4:0x8])[0] self.thumb2_load_addr = adr #struct.unpack("<L", self.hdr[0x38:0x3C])[0] self.thumb2_size = len(self.hdr) # Add segment for SRAM, not backed by file contents self.add_auto_segment( 0x20000000, 0x20000, 0, 0, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable) # Add segment for TCRAM, not backed by file contents self.add_auto_segment( 0x10000000, 0x10000, 0, 0, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable) #Add a segment for this Flash application. self.add_auto_segment( self.thumb2_load_addr, self.thumb2_size, self.thumb2_offset, self.thumb2_size, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) #Define the RESET vector entry point. self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, self.arm_entry_addr & ~1, "RESET")) self.add_entry_point(self.arm_entry_addr & ~1) #Define other entries of the Interrupt Vector Table (IVT) for ivtindex in range(8, 0x184 + 4, 4): ivector = struct.unpack("<L", self.hdr[ivtindex:ivtindex + 4])[0] if ivector > 0: #Create the symbol, then the entry point. self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, ivector & ~1, "vec_%x" % ivector)) self.add_function(ivector & ~1) return True except: log_error(traceback.format_exc()) return False
def init(self): self.arch = Architecture['Z80'] self.platform = Architecture['Z80'].standalone_platform syms = [] have_code = False for line in self.parent_view.read(0, len(self.parent_view)).split(b'\x0a'): line = line.decode('utf-8') # AREA line -> create a section match = re.match(r'A _CODE size (.*) flags (.*) addr (.*)', line) if match: (size, flags, addr) = (int(x, 16) for x in match.group(1, 2, 3)) assert flags == 0 assert addr == 0 log_info('adding _CODE [%X, %X)' % (addr, addr+size)) self.add_auto_segment(addr, size, 0, 0, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable) #self.add_user_section('_CODE', addr, size, SectionSemantics.ReadOnlyCodeSectionSemantics) have_code = True continue # WRITE line -> write bytes to section match = re.match(r'^T (.. ..) (.*)', line) if match: (addr, data) = match.group(1, 2) # eg: "04 00" -> 0x0004 addr = int(addr[3:5] + addr[0:2], 16) # eg: "AA BB CC DD" -> b'\xAA\xBB\xCC\xDD' data = b''.join([pack('B', int(x, 16)) for x in data.split(' ')]) log_info('writing to %X: %s' % (addr, match.group(2))) self.write(addr, data) continue # SYMBOL line -> store match = re.match(r'^S (.+) Def(.*)', line) if match: (name, addr) = match.group(1, 2) if not name in ['.__.ABS.', '. .ABS']: addr = int(addr, 16) log_info('saving symbol %s @ %X' % (name, addr)) syms.append((name, addr)) continue assert have_code for (name, addr) in syms: log_info('applying symbol %s @ %X' % (name, addr)) self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, addr, name)) self.add_function(addr) return True
def _add_interrupt_symbols(self, data): reader = BinaryReader(data) # Skip stack pointer reader.seek(4) for interrupt in INTERRUPT_TABLE: address = reader.read32() & ~1 if address != 0: symbol = Symbol(SymbolType.FunctionSymbol, address, interrupt) self.define_auto_symbol(symbol) self.add_function(address)
def get_exports(self): return [ Symbol(s.type, s.address, s.short_name, full_name=get_symbol_name(self.bv, s), raw_name=s.raw_name, binding=s.binding, namespace=s.namespace, ordinal=s.ordinal) for s in self.bv.get_symbols() if s.type in EXPORTABLE_TYPES and s.binding == SymbolBinding.GlobalBinding ]
def update_get_api_call(bv, xref): print("[*] Doing 0x{:x}".format(xref.address)) hash_value = None cur_addr = xref.address - 1 while hash_value is None: prev = None while not prev: cur_addr -= 1 prev = xref.function.get_low_level_il_at(cur_addr) if prev.operation == LowLevelILOperation.LLIL_SET_REG and prev.operands[0].name == "edx": v = prev.operands[1].operands[0] if isinstance(v, int): hash_value = v else: break if prev.address == xref.function.start: break if hash_value is None: print("[-] Error: hash not found") return 1 if hash_value not in func_dict: print("[-] Error: unknown hash") return 2 api_name = func_dict[hash_value] var_key = (xref.function, api_name) if var_key not in var_name_counts: var_name_counts[var_key] = 1 final_name = api_name else: final_name = "{:s}_{:d}".format(api_name, var_name_counts[var_key]) var_name_counts[var_key] += 1 bv.set_comment_at(xref.address, api_name) xref.function.create_user_address_tag(xref.address, bv.tag_types["Library"], api_name) for hl_bb in xref.function.hlil: for instr in hl_bb: if xref.address == instr.address: var = instr.operands[0] while isinstance(var, HighLevelILInstruction): var = var.operands[0] if not isinstance(var, Variable): continue xref.function.create_user_var(var, var.type, final_name) next_instr = xref.function.get_low_level_il_at(xref.address + 5) if next_instr.operation == LowLevelILOperation.LLIL_STORE and next_instr.operands[1].operands[0].name == "eax": mem_addr = next_instr.operands[0].operands[0] symbol = Symbol(SymbolType.DataSymbol, mem_addr, "_" + api_name) bv.define_user_symbol(symbol) return 0 return -1
def set_symbol_name(bv, sym, name): """ Rename symbol to given name """ # If the symbol has an associated function, this is way quicker and also updates it. func = bv.get_function_at(sym.address) if func: func.name = name else: name = name.split('@', 1)[0] old_suffixes = sym.raw_name.split('@')[1:] if old_suffixes: name += '@' + '@'.join(old_suffixes) new_sym = Symbol(sym.type, sym.address, name, binding=sym.binding, namespace=sym.namespace, ordinal=sym.ordinal) bv.undefine_auto_symbol(sym) bv.define_user_symbol(new_sym)
def load_memory(self): """Creates basic IRAM/XRAM/SFR memory spaces required by the lifter. Extend with CODE loading for your particular image. XRAM is assumed to be the maximum possible size - override xram_size if you want more precision. """ rw = (SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable) # The indirect-access part of the IRAM (reachable via @R0, @R1, # push/pop, and DMA peripheral) is kept continuous with the # direct-access portion. SFRs are pushed off to a separate region # given how special they are. # I think this will simplify the lift implementation compared to other # possible layouts. self.add_auto_segment(mem.IRAM, 0x100, 0, 0, rw) sem_rwd = SectionSemantics.ReadWriteDataSectionSemantics self.add_auto_section('.register_banks', mem.IRAM + 0x00, 0x20, sem_rwd) self.add_auto_section('.data_bitwise_access', mem.IRAM + 0x20, 0x10, sem_rwd) self.add_auto_section('.data', mem.IRAM + 0x30, 0x50, sem_rwd) self.add_auto_section('.data_indirect_only', mem.IRAM + 0x80, 0x80, sem_rwd) # Provide nice markup for stuff like `pop 0h; pop 1h; pop 2h; pop 3h` # Sometimes, anyway. For some reason symbols aren't always created? bank_t = self.platform.parse_types_from_source(''' struct register_bank __packed{uint8_t R[8];}; /* register_bank bank[4]; */ ''').types['register_bank'] for index, ea in enumerate(range(mem.IRAM+0x00, mem.IRAM+0x20, 0x08)): name = 'RB%s' % (index,) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, ea, name)) self.define_user_data_var(ea, bank_t) # The SFR region is accessible directly within the address range # 0x80..0xff. The mem.SFRs offset is a type tag only; for example, # the accumulator is at address 0xe0, which is (mem.SFRs+0xe0) in the # flattened memory map. That's | what this addition is for. I think # that makes sense? V self.add_auto_segment(mem.SFRs + 0x80, 0x80, 0, 0, rw) self.add_auto_section('.special_function_registers', mem.SFRs + 0x80, 0x80, sem_rwd) self.add_auto_segment(mem.XRAM, self.xram_size, 0, 0, rw) self.add_auto_section('.xram', mem.XRAM, self.xram_size, sem_rwd)
def init(self): self.platform = Platform['8049_rb0mb0'] length = len(self.parent_view) try: # create the data memory segment and section self.add_auto_segment( 0, 128, 0, 0, SegmentFlag.SegmentContainsData | SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable) self.add_auto_section( '.ram', 0, 128, SectionSemantics.ReadWriteDataSectionSemantics) # create the program memory segment, section and entry point self.add_auto_segment( self.CODE_OFFSET, length, 0, length, SegmentFlag.SegmentContainsCode | SegmentFlag.SegmentContainsData | SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_auto_section( '.rom', self.CODE_OFFSET, length, SectionSemantics.ReadOnlyCodeSectionSemantics) self.add_entry_point(self.CODE_OFFSET) self.define_auto_symbol_and_var_or_function( Symbol(SymbolType.FunctionSymbol, self.CODE_OFFSET | 0, 'reset'), None, self.platform) self.define_auto_symbol_and_var_or_function( Symbol(SymbolType.FunctionSymbol, self.CODE_OFFSET | 3, 'interrupt'), None, self.platform) self.define_auto_symbol_and_var_or_function( Symbol(SymbolType.FunctionSymbol, self.CODE_OFFSET | 7, 'timer'), None, self.platform) # working registers for n in range(8): self.define_auto_symbol_and_var_or_function( Symbol(SymbolType.DataSymbol, n, 'R{}'.format(n)), Type.int(1, False), self.platform) self.define_auto_symbol_and_var_or_function( Symbol(SymbolType.DataSymbol, n + 24, 'R{}\''.format(n)), Type.int(1, False), self.platform) # stack registers for n in range(8): self.define_auto_symbol_and_var_or_function( Symbol(SymbolType.DataSymbol, n * 2 + 8, 'S{}'.format(n)), Type.int(2, False), self.platform) return True except: log_error(traceback.format_exc()) return False
def fix_mangled_symbols(thread, view): for sym in view.symbols.values(): if thread.cancelled: break if not isinstance(sym, Symbol): continue if sym.short_name.startswith('?') and not sym.raw_name.startswith('?'): demangled_type, demangled_name = demangle_ms( view.arch, sym.short_name) if demangled_type is not None: new_symbol = Symbol( sym.type, sym.address, short_name=get_qualified_name(demangled_name), full_name=get_qualified_name(demangled_name), raw_name=sym.short_name, binding=sym.binding, namespace=sym.namespace, ordinal=sym.ordinal) view.undefine_user_symbol(sym) view.define_user_symbol(new_symbol) view.define_user_data_var(new_symbol.address, demangled_type) sym = new_symbol # Create vtables if 'vftable\'' in sym.full_name: create_vtable(view, None, sym.address) # Create strings if sym.raw_name.startswith('??_C@_'): view.undefine_user_symbol(sym) ascii_string = view.get_ascii_string_at(sym.address) if (ascii_string is not None) and (ascii_string.start == sym.address): view.define_user_data_var( sym.address, Type.array(Type.char(), ascii_string.length)) for func in view.functions: if thread.cancelled: break process_msvc_func(func)
def init(self): self.platform = Platform['interpro-clipper'] try: # determine key parameters based on signature header = self.parent_view.read(0, 16) if header[4:8] == 'BoB!': # Turquoise EPROM self.rom_start = 0x7f100000 self.rom_size = 0x40000 elif header[8:12] == 'SapH': # Sapphire EPROM self.rom_start = 0x7f100000 self.rom_size = len(self.parent_view) elif header[8:12] == 'sAP4': # Sapphire FLASH self.rom_start = 0x7f180000 self.rom_size = 0x40000 self.packed_addr = 0x7f1b7e70 self.unpacked_addr = 0x7a0000 self.unpacked_size = 0x20000 else: return False actual_unpacked_size = len(self.parent_view) - self.rom_size # create the ROM segment, section and entry point self.add_auto_segment(self.rom_start, self.rom_size, 0, self.rom_size, SegmentFlag.SegmentContainsCode | SegmentFlag.SegmentContainsData | SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_auto_section('.rom', self.rom_start, self.rom_size, SectionSemantics.ReadOnlyCodeSectionSemantics) self.add_entry_point(self.rom_start) # create an unpacked segment and section if necessary if self.unpacked_size > 0: self.add_auto_segment(self.unpacked_addr, self.unpacked_size, self.rom_size, actual_unpacked_size, SegmentFlag.SegmentContainsData | SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable) self.add_auto_section('.unpacked', self.unpacked_addr, self.unpacked_size, SectionSemantics.ReadWriteDataSectionSemantics) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, self.packed_addr, 'packed_data')) return True except: log_error(traceback.format_exc()) return False
def init(self): try: hdr = self.parent_view.read(4, 2) self.binary_length = struct.unpack("<H", hdr)[0] # Add mapping for RAM and hardware registers, not backed by file contents self.add_auto_segment( 0x8000, self.binary_length, 6, self.binary_length, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable) self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, 0x8000, "main")) self.add_entry_point(0x8000) return True except: traceback.print_exc() print("ERROR!!!") log_error(traceback.format_exc()) return False
def init(self): self.raw = self.data self.binary = self.raw.read(0, len(self.raw)) self.add_analysis_completion_event(self.on_complete) load_settings = self.get_load_settings(self.name) if load_settings is None: if self.IS_64: self.load_address = 0x240000000 self.arch = Architecture['aarch64'] self.platform = self.arch.standalone_platform else: self.load_address = 0x10000000 self.arch = Architecture['thumb2'] self.platform = self.arch.standalone_platform print("Base address : " + hex(self.load_address)) else: print("Load Settings: ") print(load_settings) arch = load_settings.get_string("loader.architecture", self) self.arch = Architecture[arch] self.platform = self.arch.standalone_platform self.load_address = int( load_settings.get_string("loader.imageBase", self)) self.add_auto_segment( self.load_address, len(self.parent_view), 0, len(self.parent_view), SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_user_section(self.name, self.load_address, len(self.raw), SectionSemantics.ReadOnlyCodeSectionSemantics) self.add_entry_point(self.load_address) self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, self.load_address, '_start')) self.update_analysis() return True
def init(self): self.raw = self.data self.add_analysis_completion_event(self.on_complete) try: load_settings = self.get_load_settings(self.name) if load_settings is None: print("Load Settings is None") self.arch = Architecture['aarch64'] self.platform = self.arch.standalone_platform # return True self.load_address = self.find_reset(self.data) if self.load_address == -1: print("Error: Could not find reset vector!") self.load_address = 0 print("LOAD ADDRESS: " + hex(self.load_address)) # self.add_auto_segment(0, len(self.parent_view), 0, len(self.parent_view), SegmentFlag.SegmentReadable) else: print("Load Settings: ") print(load_settings) arch = load_settings.get_string("loader.architecture", self) self.arch = Architecture[arch] self.platform = self.arch.standalone_platform # self.platform = Architecture['aarch64'].standalone_platform self.load_address = int( load_settings.get_string("loader.imageBase", self)) self.add_auto_segment( self.load_address, len(self.parent_view), 0, len(self.parent_view), SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_entry_point(self.load_address) self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, self.load_address, '_start')) self.update_analysis() # self.find_interesting() return True except: print(traceback.format_exc()) return False