def visit(self, program, is_definition, add_refs_as_defs): if not is_definition: return # type could be None if type class not handled if self._type is None: return if isinstance(self._type, VoidType): return bv = program.bv br = bn.BinaryReader(bv) mem = program.memory() begin = self._address end = begin + self._type.size(self._arch) for ea in range(begin, end): br.seek(ea) seg = bv.get_segment_at(ea) # _elf_header is getting recovered as variable # get_segment_at(...) returns None for elf_header if seg is None: continue mem.map_byte(ea, br.read8(), seg.writable, seg.executable)
def __init__(self, bv, options): BackgroundTaskThread.__init__(self, 'Beginning scan for crypto constructs...', True) self.bv = bv self.options = options self.br = bn.BinaryReader(self.bv, bn.Endianness.LittleEndian) self.log_info('Initialising Plugin') self.scanconfigs = [] self.load_configs() self.log_info('Loaded {count} configurations'.format(count = len(self.scanconfigs)))
def get_ascii_str_at(self, addr): br = binaryninja.BinaryReader(self.bv) br.seek(addr) c = br.read8() s = '' while (c != 0) and (c < 0x80) and c is not None: s += chr(c) c = br.read8() return s
def _fill_bytes(self, program, memory, start, end, ref_eas): br = bn.BinaryReader(program.bv) for bb in self._bn_func.basic_blocks: for ea in range(bb.start, bb.end): seg = program.bv.get_segment_at(ea) br.seek(ea) memory.map_byte(ea, br.read8(), seg.writable, seg.executable) inst = self._bn_func.get_low_level_il_at(ea) if inst and not is_unimplemented(program.bv, inst): _collect_xrefs_from_inst(program.bv, inst, ref_eas)
def _fill_bytes(self, bv, memory, start, end, ref_eas): br = bn.BinaryReader(bv) for bb in self._bn_func.basic_blocks: for ea in range(bb.start, bb.end): seg = bv.get_segment_at(ea) br.seek(ea) memory.map_byte(ea, br.read8(), seg.writable, seg.executable) insn = self._bn_func.get_lifted_il_at(ea) if insn: _collect_code_xrefs_from_insn(bv, insn, ref_eas)
def symbol_usage(self, tgt_syms=[]): br = binaryninja.BinaryReader(self.bv) for sym in self.bv.get_symbols(): br.seek(sym.address) c = br.read32() self.sym_const[c] = sym for s in self.bv.symbols: ts = s.split("@IAT")[0].upper() if ts in self.syms: self.get_symbol_xrefs(s) if ts[:-1] in self.syms: self.get_symbol_xrefs(s)
def main(): address_pointer = OBFUSCATED_CODE_ADDRESS bv = binaryninja.BinaryViewType["PE"].open("greek_to_me.exe") bv.update_analysis_and_wait() bw = binaryninja.BinaryWriter(bv) br = binaryninja.BinaryReader(bv) while address_pointer != (OBFUSCATED_CODE_ADDRESS + 0x79): br.seek(address_pointer) bw.seek(address_pointer) bw.write8((br.read8() ^ XOR_KEY) + CONST_FACTOR) address_pointer = address_pointer + 1 #Save updated file bv.save("greek_to_me_mod.exe")
def __init__(self, binary, *args, **kwargs): super().__init__(binary, *args, **kwargs) if not bn: raise CLEError(BINJA_NOT_INSTALLED_STR) # get_view_of_file can take a bndb or binary - wait for autoanalysis to complete self.bv = bn.BinaryViewType.get_view_of_file(binary, False) l.info("Analyzing %s, this may take some time...", binary) self.bv.update_analysis_and_wait() l.info("Analysis complete") # Note may want to add option to kick off linear sweep try: self.set_arch(self.BINJA_ARCH_MAP[self.bv.arch.name]) except KeyError: l.error("Architecture %s is not supported.", self.bv.arch.name) for seg in self.bv.segments: l.info("Adding memory for segment at %x.", seg.start) br = bn.BinaryReader(self.bv) br.seek(seg.start) data = br.read(len(seg)) self.memory.add_backer(seg.start, data) self._find_got() self._symbol_cache = {} self._init_symbol_cache() # Note: this represents the plt stub. ImportAddressSymbol refers to .got entries # Since we're not trying to import and load dependencies directly, but want to run SimProcedures, # We should use the binaryninja.SymbolType.ImportedFunctionSymbol # Also this should be generalized to get data imports, too self.raw_imports = { i.name: i.address for i in self.bv.get_symbols_of_type( bn.SymbolType.ImportedFunctionSymbol) } self._process_imports() self.exports = {} self.linking = "static" if len(self.raw_imports) == 0 else "dynamic" # We'll look for this attribute to see if we need to do SimProcedures for any imports in this binary # This is an ugly hack, but will have to use this for now until Binary Ninja exposes dependencies self.guess_simprocs = True self.guess_simprocs_hint = "nix" if self.bv.get_section_by_name( ".plt") else "win" l.warning("This backend is based on idabin.py.\n\ You may encounter unexpected behavior if:\n\ \tyour target depends on library data symbol imports, or\n\ \tlibrary imports that don't have a guess-able SimProcedure\n\ Good luck!")
def main(): print "Solution for MalwareTech shellcode challenge 1!" bv=binaryninja.BinaryViewType["PE"].open("shellcode1.exe_") bv.update_analysis_and_wait() br=binaryninja.BinaryReader(bv) br.seek(ADDRESS_FLAG) flag="" #Read encoded characters and decode them with rol 5 while True: enc_char=br.read8() if enc_char == 0: break flag+=chr(rol(enc_char,5,max_bits)) print "The flag is: %s " % flag
def define_strings_vars_range(bv, addr_start, addr_len): br = bn.BinaryReader(bv) #print('Starting string search at {:x}'.format(addr_start)) bv.begin_undo_actions() for possible_str in bv.get_strings(addr_start, addr_len): br.seek(possible_str.start + possible_str.length) end_char = chr(br.read8()) #print('char @ {:x} == {}'.format(possible_str.start + possible_str.length, end_char)) # Only automatically make strings that are at least 2 chars long and # that end in NULL if possible_str.length > 1 and end_char == '\x00': #print('found string @ {0.start:x} len {0.length:x}'.format(possible_str)) str_type, _ = bv.parse_type_string('char [{}]'.format( possible_str.length)) bv.define_user_data_var(possible_str.start, str_type) bv.commit_undo_actions()
def visit(self, program, is_definition, add_refs_as_defs): if not is_definition: return if isinstance(self._type, VoidType): return bv = program._bv br = bn.BinaryReader(bv) mem = program.memory() begin = self._address end = begin + self._type.size(self._arch) for ea in range(begin, end): br.seek(ea) seg = bv.get_segment_at(ea) mem.map_byte(ea, br.read8(), seg.writable, seg.executable)
def _fill_bytes(self, memory, start, end, ref_eas): br = bn.BinaryReader(self._bv) for bb in self._bn_func.basic_blocks: ea = bb.start while ea < bb.end: seg = self._bv.get_segment_at(ea) can_read = seg.readable can_exec = seg.executable can_write = seg.writable br.seek(ea) byte = br.read8() memory.map_byte(ea, byte, can_write, can_exec) insn = self._bn_func.get_lifted_il_at(ea) if insn: _collect_code_xrefs_from_insn(self._bv, insn, ref_eas) ea += 1
def stringify(bv, addr): buf = '' br = bn.BinaryReader(bv, bn.Endianness.BigEndian) br.seek(addr) # goto addr # read data and find null byte while True: if br.eof: # eof? print("Error converting to string: EOF.") return byte = br.read8() # read byte if byte == 0: break buf += chr(byte) # append to buffer # finished, now lets setup a type for it type, _ = bv.parse_type_string("char const [%d]" % (len(buf) + 1)) # count the NULL byte bv.define_data_var(addr, type)
def main(): print colored(banner(), "red") global XOR_KEY decode_ptr = STARTING_ADDRESS_DECODE_LOOP flag = [] # Creating a binary view with binja API bv = binaryninja.BinaryViewType["PE"].open("IgniteMe.exe") bv.update_analysis_and_wait() br = binaryninja.BinaryReader(bv) print "Starting decoding the flag!" while decode_ptr >= ADDRESS_OBFUSCATED_FLAG: br.seek(decode_ptr) XOR_KEY = (br.read8() ^ XOR_KEY) flag.append(chr(XOR_KEY)) decode_ptr = decode_ptr - 1 flag = flag[::-1] print "The flag is:", colored("".join(flag), "green")
def _fill_bytes(self, program, memory, start, end, ref_eas): br = bn.BinaryReader(program.bv) for bb in self._bn_func.basic_blocks: for ea in range(bb.start, bb.end): seg = program.bv.get_segment_at(ea) br.seek(ea) # NOTE(artem): This is a workaround for binary ninja's fake # .externs section, which is (correctly) mapped as # not readable, not writable, and not executable. # because it is a fictional creation of the disassembler. # When something is marked as not accessible at all, # assume it is readable and executable is_executable = seg.executable if seg.writable == seg.readable == False: is_executable = True memory.map_byte(ea, br.read8(), seg.writable, is_executable) inst = self._bn_func.get_low_level_il_at(ea) if inst and not is_unimplemented(program.bv, inst): _collect_xrefs_from_inst(program.bv, program, inst, ref_eas)
def __init__(self, program, screen, bv): self.program = program self.screen = screen self.bv = bv # Make Pads self.alertsScreen = curses.newpad(1, curses.COLS) self.pythonConsoleScreen = curses.newpad(1, curses.COLS) self.logScreen = curses.newpad(1, curses.COLS) # Disassembly Window Stuff self.disassemblySettings = binja.DisassemblySettings() self.pos = self.bv.start # Current position in the binary self.posOffset = 0 # Displacement in lines between the top of the screen and the rendered location of self.pos self.cursorOffset = 0 # Offset (in lines) from the top of the screen to the current visual cursor in linear view self.disassemblyLines = [] # TODO...make sure this is deleted in the view's cleanup self.hexOffset = 0 # Offset (in lines) from the top of the screen to the current visual cursor in hex view self.br = binja.BinaryReader(bv) self.hexLines = [] # TODO...make sure this is deleted in the view's cleanup # Function List Pane Stuff self.funcListPos = 0 self.funcListCur = 0 self.updateFunctionList = True # Global Stuff self.focus = 0 self.view = 0 # 0 - Linear # 1 - Hex # 2 - CFG # Set up first view self.linearDisassemblyScreen = curses.newpad(curses.LINES-1, curses.COLS - self.program.settings["functionListScreenWidth"]) self.functionListScreen = curses.newpad(curses.LINES-1-self.program.settings["xrefsScreenHeight"], self.program.settings["functionListScreenWidth"]) self.xrefsScreen = curses.newpad(self.program.settings["xrefsScreenHeight"], self.program.settings["functionListScreenWidth"]) self.loadLinearDisassembly()
def visit(self, program, is_definition, add_refs_as_defs): if not is_definition: return # type could be None if type class not handled if self._type is None: return if isinstance(self._type, VoidType): return bv = program.bv br = bn.BinaryReader(bv) mem = program.memory begin = self._address end = begin + self._type.size(self._arch) for ea in range(begin, end): br.seek(ea) seg = bv.get_segment_at(ea) # _elf_header is getting recovered as variable # get_segment_at(...) returns None for elf_header if seg is None: continue #NOTE(artem): This is a workaround for binary ninja's fake # .externs section, which is (correctly) mapped as # not readable, not writable, and not executable. # because it is a fictional creation of the disassembler. # # However, when we do control flow tragetting to thunks, # we will sanity check that the target goes to an executable # location. If we are lying about the target being readable, # then we may as well lie about it being executable. is_executable = seg.executable if seg.writable == seg.readable == False: is_executable = True mem.map_byte(ea, br.read8(), seg.writable, is_executable)
def _init_func_thunk_ctrl_flow(self): """Initializes the control flow redirections and targets using function thunks""" # We only support the ELF format for now if self._bv.view_type != "ELF": return # List the function thunks first input_file_path = self._bv.file.filename image_parser = create_elf_image_parser(input_file_path) function_thunk_list = image_parser.get_function_thunk_list() # Go through each function thunk and add the redirection and targets is_32_bit = image_parser.get_image_bitness() == 32 reader = bn.BinaryReader(self._bv, bn.Endianness.LittleEndian) redirected_thunk_list = [] for function_thunk in function_thunk_list: # Read the call destination reader.seek(function_thunk.start) redirection_dest = reader.read32() if is_32_bit else reader.read64( ) # Get the variable defined at the dest address func_location = self._bv.get_data_var_at(function_thunk.start) if not func_location: DEBUG( f"anvill: No variable defined for {hex(function_thunk.start)}/{function_thunk.name}" ) continue # We should only have one caller for caller in func_location.code_refs: # Get the function containing this address; we need it to determine # its start address for caller_function in self._bv.get_functions_containing( caller.address): # check if the caller function name is same as the function thunk name and add # redirection if it matches. # TODO: It is possible that the caller function name does not exactly matches the # thunk name. find such cases and add them here # # It is not preferred to have a loose check here. That will lead to adding redirection # for the wrong functions. # if (function_thunk.name == caller_function.name or function_thunk.name == caller_function.name[1:]): DEBUG( "anvill: Redirecting the user {:x} of thunk {} at {:x} to {:x}" .format( caller_function.start, function_thunk.name, function_thunk.start, redirection_dest, )) self.add_control_flow_redirection( caller_function.start, redirection_dest) redirected_thunk_list.append(function_thunk.name) # The imported address symbol can be references from both the thunks # and other functions if it does not uses PLT. Check if the caller # address is one of the call or jump instruction # e.g: call [atoi@GOT] # jmp [atoi@GOT] # # if the caller address is a call site, set a control flow # target for the address if self._is_call_site(caller_function, caller.address): self.set_control_flow_targets(caller.address, [redirection_dest], True) DEBUG( "anvill: Adding target list {:x} -> [{:x}, complete=True] for {}" .format(caller.address, redirection_dest, function_thunk.name)) continue jump_table = get_jump_targets(self._bv, caller.address, function_thunk.start) for jump_addr, targets in jump_table.items(): if function_thunk.start in targets: self.set_control_flow_targets( jump_addr, [redirection_dest], True) DEBUG( "anvill: Adding target list {:x} -> [{:x}, complete=True] for {}" .format(jump_addr, redirection_dest, function_thunk.name)) # Now check whether we successfully redirected all thunks for function_thunk in function_thunk_list: if function_thunk.name not in redirected_thunk_list: if function_thunk.name == "__libc_start_main": continue WARN( f"anvill: Thunk {hex(function_thunk.start)} ({function_thunk.name}) could not be redirected" )
def read_bytes(addr, size): br = binaryninja.BinaryReader(binja.view) br.seek(addr) return bytearray(br.read(size))
def _init_ctrl_flow_redirections(self): """Initializes the control flow redirections using function thunks""" # We only support the ELF format for now if self._bv.view_type != "ELF": return # List the function thunks first input_file_path = self._bv.file.filename image_parser = create_elf_image_parser(input_file_path) function_thunk_list = image_parser.get_function_thunk_list() # Go through each function thunk and add the redirection. Note that # the __libc_start_main thunk does not need redirection since it's # called directly without any wrapper function from the module entry # point is_32_bit = image_parser.get_image_bitness() == 32 reader = bn.BinaryReader(self._bv, bn.Endianness.LittleEndian) image_base_address = self._bv.start redirected_thunk_list = [] for function_thunk in function_thunk_list: # Read the call destination thunk_va = image_base_address + function_thunk.start reader.seek(thunk_va) redirection_dest = reader.read32() if is_32_bit else reader.read64( ) # Get the variable defined at the dest address func_location = self._bv.get_data_var_at(function_thunk.start) if not func_location: print("anvill: No variable defined for {:x}".format( function_thunk.start)) continue # We should only have one caller for caller in func_location.code_refs: # Get the function containing this address; we need it to determine # its start address for caller_function in self._bv.get_functions_containing( caller.address): if (function_thunk.name == "__libc_start_main" or function_thunk.name not in caller_function.name): continue redirection_source = caller_function.start print( "anvill: Redirecting the user {:x} of thunk {} at rva {:x} to {:x}" .format( redirection_source, function_thunk.name, function_thunk.start, redirection_dest, )) self.add_control_flow_redirection(redirection_source, redirection_dest) redirected_thunk_list.append(function_thunk.name) # Now check whether we successfully redirected all thunks for function_thunk in function_thunk_list: if function_thunk.name not in redirected_thunk_list: if function_thunk.name == "__libc_start_main": continue print("anvill: Thunk {:x} ({}) could not be redirected".format( function_thunk.start, function_thunk.name))