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 _destroy_instance(self, ctxt): try: if self in self.__class__._registered_instances: self.__class__._registered_instances.remove(self) self.perform_destroy_instance() except: log.log_error(traceback.format_exc())
def _get_current_view(self, ctxt): try: view = self.get_current_view() except: log.log_error(traceback.format_exc()) view = "" return core.BNAllocString(view)
def perform_request(self, url): try: proxy_setting = Settings().get_string('downloadClient.httpsProxy') if proxy_setting: proxies = {"https": proxy_setting} else: proxies = None r = requests.get(pyNativeStr(url), proxies=proxies) if not r.ok: core.BNSetErrorForDownloadInstance(self.handle, "Received error from server") return -1 data = r.content if len(data) == 0: core.BNSetErrorForDownloadInstance(self.handle, "No data received from server!") return -1 raw_bytes = (ctypes.c_ubyte * len(data)).from_buffer_copy(data) bytes_wrote = core.BNWriteDataForDownloadInstance(self.handle, raw_bytes, len(raw_bytes)) if bytes_wrote != len(raw_bytes): core.BNSetErrorForDownloadInstance(self.handle, "Bytes written mismatch!") return -1 continue_download = core.BNNotifyProgressForDownloadInstance(self.handle, bytes_wrote, bytes_wrote) if continue_download is False: core.BNSetErrorForDownloadInstance(self.handle, "Download aborted!") return -1 except requests.RequestException as e: core.BNSetErrorForDownloadInstance(self.handle, e.__class__.__name__) return -1 except: core.BNSetErrorForDownloadInstance(self.handle, "Unknown Exception!") log.log_error(traceback.format_exc()) return -1 return 0
def _free_parameters(self, params, count): try: buf = ctypes.cast(params, ctypes.c_void_p) if buf.value not in self._pending_param_lists: raise ValueError("freeing parameter list that wasn't allocated") del self._pending_param_lists[buf.value] except: log.log_error(traceback.format_exc())
def _show_html_report(self, ctxt, view, title, contents, plaintext): try: if view: view = binaryview.BinaryView(handle = core.BNNewViewReference(view)) else: view = None self.show_html_report(view, title, contents, plaintext) except: log.log_error(traceback.format_exc())
def _show_graph_report(self, ctxt, view, title, graph): try: if view: view = binaryview.BinaryView(handle = core.BNNewViewReference(view)) else: view = None self.show_graph_report(view, title, flowgraph.CoreFlowGraph(core.BNNewFlowGraphReference(graph))) except: log.log_error(traceback.format_exc())
def _get_int_input(self, ctxt, result, prompt, title): try: value = self.get_int_input(prompt, title) if value is None: return False result[0] = value return True except: log.log_error(traceback.format_exc())
def _create_instance(self, ctxt): try: result = self.__class__.instance_class(self) if result is None: return None return ctypes.cast(core.BNNewDownloadInstanceReference(result.handle), ctypes.c_void_p).value except: log.log_error(traceback.format_exc()) return None
def _get_directory_name_input(self, ctxt, result, prompt, default_name): try: value = self.get_directory_name_input(prompt, default_name) if value is None: return False result[0] = core.BNAllocString(str(value)) return True except: log.log_error(traceback.format_exc())
def _update(self, ctxt): try: graph = self.update() if graph is None: return None return core.BNNewFlowGraphReference(graph.handle) except: log.log_error(traceback.format_exc()) return None
def _recognize_medium_level_il(self, ctxt, data, func, il): try: file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(data)) view = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(data)) func = function.Function(view, handle = core.BNNewFunctionReference(func)) il = mediumlevelil.MediumLevelILFunction(func.arch, handle = core.BNNewMediumLevelILFunctionReference(il)) return self.recognize_medium_level_il(view, func, il) except: log.log_error(traceback.format_exc()) return False
def _get_choice_input(self, ctxt, result, prompt, title, choice_buf, count): try: choices = [] for i in range(0, count): choices.append(choice_buf[i]) value = self.get_choice_input(prompt, title, choices) if value is None: return False result[0] = value return True except: log.log_error(traceback.format_exc())
def _is_valid_for_data(self, ctxt, view, addr, type, context, ctxCount): try: file_metadata = FileMetadata(handle=core.BNGetFileForView(view)) view = BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(view)) type = Type(handle=core.BNNewTypeReference(type)) pycontext = [] for i in range(0, ctxCount): pycontext.append(Type(core.BNNewTypeReference(context[i]))) return self.perform_is_valid_for_data(ctxt, view, addr, type, pycontext) except: log_error(traceback.format_exc()) return False
def _get_address_input(self, ctxt, result, prompt, title, view, current_address): try: if view: view = binaryview.BinaryView(handle = core.BNNewViewReference(view)) else: view = None value = self.get_address_input(prompt, title, view, current_address) if value is None: return False result[0] = value return True except: log.log_error(traceback.format_exc())
def init_arm7(self): try: self.init_common() self.arm7_offset = struct.unpack("<L", self.hdr[0x30:0x34])[0] self.arm_entry_addr = struct.unpack("<L", self.hdr[0x34:0x38])[0] self.arm7_load_addr = struct.unpack("<L", self.hdr[0x38:0x3C])[0] self.arm7_size = struct.unpack("<L", self.hdr[0x3C:0x40])[0] self.add_auto_segment(self.arm7_load_addr, self.arm7_size, self.arm7_offset, self.arm7_size, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_entry_point(Architecture['armv7'].standalone_platform, self.arm_entry_addr) return True except: log_error(traceback.format_exc()) return False
def _get_parameters(self, ctxt, count): try: count[0] = len(self.parameters) param_buf = (core.BNTransformParameterInfo * len(self.parameters))() for i in range(0, len(self.parameters)): param_buf[i].name = self.parameters[i].name param_buf[i].longName = self.parameters[i].long_name param_buf[i].fixedLength = self.parameters[i].fixed_length result = ctypes.cast(param_buf, ctypes.c_void_p) self._pending_param_lists[result.value] = (result, param_buf) return result.value except: log.log_error(traceback.format_exc()) count[0] = 0 return None
def _encode(self, ctxt, input_buf, output_buf, params, count): try: input_obj = databuffer.DataBuffer(handle = core.BNDuplicateDataBuffer(input_buf)) param_map = {} for i in range(0, count): data = databuffer.DataBuffer(handle = core.BNDuplicateDataBuffer(params[i].value)) param_map[params[i].name] = str(data) result = self.perform_encode(str(input_obj), param_map) if result is None: return False result = str(result) core.BNSetDataBufferContents(output_buf, result, len(result)) return True except: log.log_error(traceback.format_exc()) return False
def _get_lines_for_data(self, ctxt, view, addr, type, prefix, prefixCount, width, count, typeCtx, ctxCount): try: file_metadata = FileMetadata(handle=core.BNGetFileForView(view)) view = BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(view)) type = Type(handle=core.BNNewTypeReference(type)) prefixTokens = InstructionTextToken.get_instruction_lines(prefix, prefixCount) pycontext = [] for i in range(ctxCount): pycontext.append(Type(core.BNNewTypeReference(typeCtx[i]))) result = self.perform_get_lines_for_data(ctxt, view, addr, type, prefixTokens, width, pycontext) count[0] = len(result) line_buf = (core.BNDisassemblyTextLine * len(result))() for i in range(len(result)): line = result[i] color = line.highlight if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor): raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor") if isinstance(color, HighlightStandardColor): color = highlight.HighlightColor(color) line_buf[i].highlight = color._get_core_struct() if line.address is None: if len(line.tokens) > 0: line_buf[i].addr = line.tokens[0].address else: line_buf[i].addr = 0 else: line_buf[i].addr = line.address if line.il_instruction is not None: line_buf[i].instrIndex = line.il_instruction.instr_index else: line_buf[i].instrIndex = 0xffffffffffffffff line_buf[i].count = len(line.tokens) line_buf[i].tokens = InstructionTextToken.get_instruction_lines(line.tokens) return ctypes.cast(line_buf, ctypes.c_void_p).value except: log_error(traceback.format_exc()) return None
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, #128K at address 0x20000000. 0, 0, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable) # Add segment for TCRAM, not backed by file contents self.add_auto_segment(0x10000000, 0x10000, #64K at address 0x10000000. 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 write_breakpoint(view, start, length): """Sample function to show registering a plugin menu item for a range of bytes. Also possible: register register_for_address register_for_function """ bkpt_str = { "x86": "int3", "x86_64": "int3", "armv7": "bkpt", "aarch64": "brk #0", "mips32": "break"} if view.arch.name not in bkpt_str: log_error("Architecture %s not supported" % view.arch.name) return bkpt, err = view.arch.assemble(bkpt_str[view.arch.name]) if bkpt is None: log_error(err) return view.write(start, bkpt * length // len(bkpt))
def _get_form_input(self, ctxt, fields, count, title): try: field_objs = [] for i in range(0, count): if fields[i].type == FormInputFieldType.LabelFormField: field_objs.append(LabelField(fields[i].prompt)) elif fields[i].type == FormInputFieldType.SeparatorFormField: field_objs.append(SeparatorField()) elif fields[i].type == FormInputFieldType.TextLineFormField: field_objs.append(TextLineField(fields[i].prompt)) elif fields[i].type == FormInputFieldType.MultilineTextFormField: field_objs.append(MultilineTextField(fields[i].prompt)) elif fields[i].type == FormInputFieldType.IntegerFormField: field_objs.append(IntegerField(fields[i].prompt)) elif fields[i].type == FormInputFieldType.AddressFormField: view = None if fields[i].view: view = binaryview.BinaryView(handle = core.BNNewViewReference(fields[i].view)) field_objs.append(AddressField(fields[i].prompt, view, fields[i].currentAddress)) elif fields[i].type == FormInputFieldType.ChoiceFormField: choices = [] for j in range(0, fields[i].count): choices.append(fields[i].choices[j]) field_objs.append(ChoiceField(fields[i].prompt, choices)) elif fields[i].type == FormInputFieldType.OpenFileNameFormField: field_objs.append(OpenFileNameField(fields[i].prompt, fields[i].ext)) elif fields[i].type == FormInputFieldType.SaveFileNameFormField: field_objs.append(SaveFileNameField(fields[i].prompt, fields[i].ext, fields[i].defaultName)) elif fields[i].type == FormInputFieldType.DirectoryNameFormField: field_objs.append(DirectoryNameField(fields[i].prompt, fields[i].defaultName)) else: field_objs.append(LabelField(fields[i].prompt)) if not self.get_form_input(field_objs, title): return False for i in range(0, count): field_objs[i]._fill_core_result(fields[i]) return True except: log.log_error(traceback.format_exc())
def perform_request(self, url): try: proxy_setting = Settings().get_string('downloadClient.httpsProxy') if proxy_setting: opener = build_opener(ProxyHandler({'https': proxy_setting})) install_opener(opener) r = urlopen(pyNativeStr(url)) total_size = int(r.headers.get('content-length', 0)) bytes_sent = 0 while True: data = r.read(4096) if not data: break raw_bytes = (ctypes.c_ubyte * len(data)).from_buffer_copy(data) bytes_wrote = core.BNWriteDataForDownloadInstance(self.handle, raw_bytes, len(raw_bytes)) if bytes_wrote != len(raw_bytes): core.BNSetErrorForDownloadInstance(self.handle, "Bytes written mismatch!") return -1 bytes_sent = bytes_sent + bytes_wrote continue_download = core.BNNotifyProgressForDownloadInstance(self.handle, bytes_sent, total_size) if continue_download is False: core.BNSetErrorForDownloadInstance(self.handle, "Download aborted!") return -1 if not bytes_sent: core.BNSetErrorForDownloadInstance(self.handle, "Received no data!") return -1 except URLError as e: core.BNSetErrorForDownloadInstance(self.handle, e.__class__.__name__) return -1 except: core.BNSetErrorForDownloadInstance(self.handle, "Unknown Exception!") log.log_error(traceback.format_exc()) return -1 return 0
def _set_current_selection(self, ctxt, begin, end): try: self.perform_set_current_selection(begin, end) except: log.log_error(traceback.format_exc())
def run(self) -> None: try: df = DexFile(self.bv.raw.read(0, self.bv.raw.end)) except Exception: log_error("caught error, writing json anyway") raise finally: # TODO add gui button to do this # TODO make this depend on filename # FIXME this is a file write -> code exec vuln with the right # timing background_task = JsonWriter(df, "/tmp/out.json") background_task.start() data_size = df._parse_uint(self.bv.hdr[104:108]) data_off = df._parse_uint(self.bv.hdr[108:112]) self.bv.add_auto_segment( data_off, data_size, data_off, data_size, SegmentFlag.SegmentReadable | SegmentFlag.SegmentContainsData | SegmentFlag.SegmentContainsCode, ) # Process code blocks # For each code block, add # - binja section # - binja function # - binja symbol # - comments for tries and catches self.progress = self.progress_title + ": processing code blocks" defined_functions: Set[str] = set() for class_def in df.class_defs: if not class_def.class_data: continue for method in (class_def.class_data.direct_methods + class_def.class_data.virtual_methods): if method.code: off = method.code._insns_off # Add section self.bv.add_auto_section( f"code_{hex(off)}", method.code._insns_off, 2 * method.code.insns_size, SectionSemantics.ReadOnlyCodeSectionSemantics, ) # Add function and symbol function_name = f"{method.access_flags}{method.method.class_}->{method.method.name}(" for param in method.method.proto.parameters: function_name += param function_name += ")" + method.method.proto.return_type if function_name in defined_functions: log_error(f"Duplicate function name {function_name}") defined_functions.add(function_name) self.bv.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, off, function_name)) self.bv.add_function(off) # Add tries and catches as comments if method.code.tries_size: for try_item in method.code.tries: self.bv.set_comment_at( off + try_item.start_addr * 2, f":try_start_{try_item.start_addr:x}", ) self.bv.set_comment_at( off + try_item.start_addr * 2 + try_item.insn_count * 2, f":try_end_{try_item.start_addr+try_item.insn_count:x}", ) self.bv.set_comment_at( off + try_item.start_addr * 2 + try_item.insn_count * 2, f"{try_item.handler}", )
def _show_report_collection(self, ctxt, title, reports): try: self.show_report_collection(title, ReportCollection(core.BNNewReportCollectionReference(reports))) except: log.log_error(traceback.format_exc())
def _prepare_for_layout(self, ctxt): try: self.prepare_for_layout() except: log.log_error(traceback.format_exc())
def _external_ref_released(self, ctxt): try: self.__class__._registered_instances.remove(self) except: log.log_error(traceback.format_exc())
def _external_ref_taken(self, ctxt): try: self.__class__._registered_instances.append(self) except: log.log_error(traceback.format_exc())
def _execute_script_input(self, ctxt, text): try: return self.perform_execute_script_input(text) except: log.log_error(traceback.format_exc()) return ScriptingProviderExecuteResult.InvalidScriptInput
def _get_int_return_reg(self, ctxt): try: return self.arch.regs[self.__class__.int_return_reg].index except: log.log_error(traceback.format_exc()) return False
def _populate_nodes(self, ctxt): try: self.populate_nodes() except: log.log_error(traceback.format_exc())
def log(self, msg, error=False): msg = f'[Switch-Binja-Loader] {msg}' if not error: log_info(msg) else: log_error(msg)
def _complete(self, ctxt): try: if self.on_complete is not None: self.on_complete() except: log.log_error(traceback.format_exc())
def _input_ready_state_changed(self, ctxt, state): try: self.notify_input_ready_state_changed(state) except: log.log_error(traceback.format_exc())
def _error(self, ctxt, text): try: self.notify_error(text) except: log.log_error(traceback.format_exc())
def init(self): try: hdr = self.parent_view.read(0, 128) self.version = struct.unpack("B", hdr[5])[0] self.song_count = struct.unpack("B", hdr[6])[0] self.starting_song = struct.unpack("B", hdr[7])[0] self.load_address = struct.unpack("<H", hdr[8:10])[0] self.init_address = struct.unpack("<H", hdr[10:12])[0] self.play_address = struct.unpack("<H", hdr[12:14])[0] self.song_name = hdr[15].split('\0')[0] self.artist_name = hdr[46].split('\0')[0] self.copyright_name = hdr[78].split('\0')[0] self.play_speed_ntsc = struct.unpack("<H", hdr[110:112])[0] self.bank_switching = hdr[112:120] self.play_speed_pal = struct.unpack("<H", hdr[120:122])[0] self.pal_ntsc_bits = struct.unpack("B", hdr[122])[0] self.pal = True if (self.pal_ntsc_bits & 1) == 1 else False self.ntsc = not self.pal if self.pal_ntsc_bits & 2 == 2: self.pal = True self.ntsc = True self.extra_sound_bits = struct.unpack("B", hdr[123])[0] if self.bank_switching == "\0" * 8: # no bank switching self.load_address & 0xFFF self.rom_offset = 128 else: # bank switching not implemented log_info("Bank switching not implemented in this loader.") # Add mapping for RAM and hardware registers, not backed by file contents self.add_auto_segment( 0, 0x8000, 0, 0, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable) # Add ROM mappings self.add_auto_segment( 0x8000, 0x4000, self.rom_offset, 0x4000, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, self.play_address, "_play")) self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, self.init_address, "_init")) self.add_entry_point(self.init_address) self.add_function(self.play_address) # Hardware registers self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2000, "PPUCTRL")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2001, "PPUMASK")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2002, "PPUSTATUS")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2003, "OAMADDR")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2004, "OAMDATA")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2005, "PPUSCROLL")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2006, "PPUADDR")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2007, "PPUDATA")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4000, "SQ1_VOL")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4001, "SQ1_SWEEP")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4002, "SQ1_LO")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4003, "SQ1_HI")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4004, "SQ2_VOL")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4005, "SQ2_SWEEP")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4006, "SQ2_LO")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4007, "SQ2_HI")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4008, "TRI_LINEAR")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x400a, "TRI_LO")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x400b, "TRI_HI")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x400c, "NOISE_VOL")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x400e, "NOISE_LO")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x400f, "NOISE_HI")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4010, "DMC_FREQ")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4011, "DMC_RAW")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4012, "DMC_START")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4013, "DMC_LEN")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4014, "OAMDMA")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4015, "SND_CHN")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4016, "JOY1")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4017, "JOY2")) return True except: log_error(traceback.format_exc()) return False
def perform_custom_request(self, method, url, headers, data): result = None try: proxy_setting = settings.Settings().get_string( 'network.httpsProxy') if proxy_setting: opener = build_opener( ProxyHandler({'https': proxy_setting})) install_opener(opener) if b"Content-Length" in headers: del headers[b"Content-Length"] req = PythonDownloadInstance.CustomRequest( pyNativeStr(url), data=data, headers=headers, method=pyNativeStr(method)) result = urlopen(req) except HTTPError as he: result = he except URLError as e: core.BNSetErrorForDownloadInstance(self.handle, e.__class__.__name__) log.log_error(str(e)) return None except: core.BNSetErrorForDownloadInstance(self.handle, "Unknown Exception!") log.log_error(traceback.format_exc()) return None total_size = int(result.headers.get('content-length', 0)) bytes_sent = 0 while True: data = result.read(4096) if not data: break raw_bytes = (ctypes.c_ubyte * len(data)).from_buffer_copy(data) bytes_wrote = core.BNWriteDataForDownloadInstance( self.handle, raw_bytes, len(raw_bytes)) if bytes_wrote != len(raw_bytes): core.BNSetErrorForDownloadInstance( self.handle, "Bytes written mismatch!") return None bytes_sent = bytes_sent + bytes_wrote continue_download = core.BNNotifyProgressForDownloadInstance( self.handle, bytes_sent, total_size) if continue_download is False: core.BNSetErrorForDownloadInstance( self.handle, "Download aborted!") return None if not bytes_sent: core.BNSetErrorForDownloadInstance(self.handle, "Received no data!") return None return DownloadInstance.Response(result.getcode(), result.headers, None)
def init(self): try: hdr = self.parent_view.read(0, 0x800) # Remember, Pythons indexer is retarded: from:(to+1) self.init_pc = struct.unpack("<L", hdr[0x10:0x14])[0] self.text_start = struct.unpack("<L", hdr[0x18:0x1c])[0] self.text_size = struct.unpack("<L", hdr[0x1c:0x20])[0] self.init_sp = struct.unpack("<L", hdr[0x30:0x34])[0] self.info = hdr[0x4c:self.HDR_SIZE] # log_debug("/info: %r" % self.info) log_debug("/info size: %s" % format(len(self.info), '#010x')) log_info("PC: %s" % format(self.init_pc, '#010x')) log_info("TEXT: %s" % format(self.text_start, '#010x')) log_info("SIZE: %s" % format(self.text_size, '#010x')) log_info("SP: %s" % format(self.init_sp, '#010x')) log_info("info: %s" % self.info) # PSX came with 2M, but the BIOS supports 8 # for dev machines. Supposed be multiple if # 2048, but that is not required for the # method used to sideload homebrew. (FIXME: Is # it enforced by the BIOS? Can't remember...) # FIXME: this is just a sanity check. Make it # check if text_start + text_size would run # outside address space. if (self.text_size > 0x800000): log_warn("size > 8M: %d", self.text_size) if (self.text_size % 2048 != 0): log_warn("size not divisable by 2k") text = self.parent_view.read(self.HDR_SIZE, self.text_size) log_info("Actual size of aquired TEXT: %s" % format(len(text), '#010x')) if (len(text) != self.text_size): log_error( "Size of aquired data is not same as header-prescribed TEXT size. Truncated file?" ) # add_auto_segment(start, length, # data_offset, data_length, flags) r__ = SegmentFlag.SegmentReadable rw_ = (SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable) rwx = (SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable) r_x = (SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) r_xc = (SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable | SegmentFlag.SegmentContainsCode) # Scratchpad RAM 1k self.add_auto_segment(0x9F800000, 1024, 0, 0, rwx) self.add_auto_section("Scratchpad", 0x9F800000, 1024) # FIXME: I seem to remember most IO access as # in the KSEG1 region. This wont cover that. # IO Ports 8k self.add_auto_segment(0x9F801000, 8 * 1024, 0, 0, rwx) self.add_auto_section("IO Ports", 0x9F801000, 8 * 1024) # Expansion 2 (IO Ports) 8k self.add_auto_segment(0x9F802000, 8 * 1024, 0, 0, rwx) self.add_auto_section("Expansion region 2 (IO Ports)", 0x9F802000, 8 * 1024) # Expansion 3 2M self.add_auto_segment(0x9FA00000, 0x200000, 0, 0, rwx) self.add_auto_section("Expansion region 3", 0x9FA00000, 0x200000) # BIOS ROM 512k self.add_auto_segment(0x9FC00000, 512 * 1024, 0, 0, r_x) self.add_auto_section("BIOS", 0x9FC00000, 512 * 1024) # RAM (cached address space) 2M # Dividing this into pre-EXE and post-EXE # space since it's the only way I've found to # not have the exe zeroed out # FIXME: The areas definitions overlap by one # byte: Getting one missing byte in the # viewer if I don't. Is BN using the wierd # python semantics of ranges? ramsize = 0x200000 prestart = 0x80000000 presize = (self.text_start - 0) - 0x80000000 if (presize > 0): log_info("pre-RAM: %s - %s, size: %s" % (format(prestart, '#010x'), format(prestart + presize, '#010x'), format(presize, '#010x'))) self.add_auto_segment(prestart, presize, 0, 0, rwx) self.add_auto_section("RAM (pre EXE)", 0x80000000, presize) # Area for the actual executable. Will overlap # with RAM if it's a correct PSX-EXE self.add_auto_segment(self.text_start, self.text_size, self.HDR_SIZE, self.text_size, r_xc) self.add_auto_section("PS-X EXE", self.text_start, self.text_size) # semantics = SectionSemantics.ReadOnlyCodeSectionSemantics) # RAM (cached address space) 2M poststart = self.text_start + self.text_size postsize = (prestart + ramsize) - (self.text_start + self.text_size) if (postsize > 0): log_info("post-RAM: %s - %s, size: %s" % (format(poststart, '#010x'), format(poststart + postsize, '#010x'), format(postsize, '#010x'))) self.add_auto_segment(poststart, postsize, 0, 0, rwx) self.add_auto_section("RAM (post EXE)", poststart, postsize) self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, self.init_pc, "_start")) self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, self.init_sp, "_stack")) # default: 0x801ffff0 self.add_entry_point(self.init_pc) # The iomapped control of devices in a PSX is # high up that every time those values are # used you can be pretty sure we are talking # about the control registers and not some # random loop counter. # # FIXME: With the exception of a0, b0 and # c0-calls, those should be lifted in some # other manner but are useful enough that they # are hardcoded right now. for addr, symbol in psx_memmap_constants.iteritems(): self.define_auto_symbol( Symbol(SymbolType.DataSymbol, addr, symbol)) # Uncomment this and remove the hook if you want to run # function BIOS calls manually. #PluginCommand.register('Find PSX BIOS calls', # 'Find PSX BIOS calls and rename them.', # find_bios_calls_run) # Run PSX BIOS function finder after analysis self.add_analysis_completion_event( lambda _: find_bios_calls_run(self)) return True except: log_error(traceback.format_exc()) return False
def _perform_request(self, ctxt, url): try: return self.perform_request(url) except: log.log_error(traceback.format_exc()) return -1
def _stack_adjusted_on_return(self, ctxt): try: return self.__class__.stack_adjusted_on_return except: log.log_error(traceback.format_exc()) return False
def _destroy_instance(self, ctxt): try: self.perform_destroy_instance() except: log.log_error(traceback.format_exc())
def _stack_reserved_for_arg_regs(self, ctxt): try: return self.__class__.stack_reserved_for_arg_regs except: log.log_error(traceback.format_exc()) return False
def _show_message_box(self, ctxt, title, text, buttons, icon): try: return self.show_message_box(title, text, buttons, icon) except: log.log_error(traceback.format_exc())
def _complete_layout(self, ctxt): try: self.complete_layout() except: log.log_error(traceback.format_exc())
def _arg_regs_share_index(self, ctxt): try: return self.__class__.arg_regs_share_index except: log.log_error(traceback.format_exc()) return False
def get_instruction_text(self, data, addr): tokens = [] if self.vtil == None: try: self.vtil = VTILParser.from_file(get_filename()) except Exception as ex: log_error(str(ex)) tokens.append( InstructionTextToken(InstructionTextTokenType.TextToken, "ERROR")) return tokens, 1 next_vip, sp_index, sp_reset, sp_offset, code = find_instruction( addr, self.vtil) if code == None: tokens.append( InstructionTextToken(InstructionTextTokenType.TextToken, "ERROR")) return tokens, 1 if sp_index > 0: tokens.append( InstructionTextToken(InstructionTextTokenType.TextToken, "[")) tokens.append( InstructionTextToken(InstructionTextTokenType.IntegerToken, str(sp_index), value=sp_index, size=64)) tokens.append( InstructionTextToken(InstructionTextTokenType.TextToken, "] ")) else: tokens.append( InstructionTextToken(InstructionTextTokenType.TextToken, " ")) prefix = "-" if sp_offset >= 0: prefix = "+" sp_offset = abs(sp_offset) if sp_reset > 0: txt = f">{prefix}{hex(sp_offset)}" txt = f"{txt:<6}" tokens.append( InstructionTextToken(InstructionTextTokenType.TextToken, txt)) else: txt = f"{prefix}{hex(sp_offset)}" txt = f"{txt:<6}" tokens.append( InstructionTextToken(InstructionTextTokenType.TextToken, txt)) tokens.append( InstructionTextToken(InstructionTextTokenType.TextToken, " ")) if " " in code: instr, operands = code.split(" ", 1) if " " in operands: operands = operands.split(" ") else: operands = [operands] if instr in self.instructions.keys(): token_set = self.instructions[instr]["tokens"] for index in self.instructions[instr]["operands"]: operand = operands.pop(0) if "0x" in operand: if instr == "js": token_set[index] = InstructionTextToken( InstructionTextTokenType.GotoLabelToken, f"vip_{operand[2:]}") elif instr == "jmp": token_set[index] = InstructionTextToken( InstructionTextTokenType.GotoLabelToken, f"vip_{hex(next_vip[0])[2:]}") else: token_set[index] = InstructionTextToken( InstructionTextTokenType.IntegerToken, operand, value=int(operand, 16), size=64) else: token_set[index] = InstructionTextToken( InstructionTextTokenType.RegisterToken, operand) tokens.extend(token_set) else: # fallback tokens.append( InstructionTextToken( InstructionTextTokenType.InstructionToken, instr)) tokens.append( InstructionTextToken( InstructionTextTokenType.OperandSeparatorToken, " ")) for operand in operands: if "0x" in operand: if instr == "jmp": tokens.append( InstructionTextToken( InstructionTextTokenType.GotoLabelToken, f"vip_{hex(next_vip[0])[2:]}")) else: tokens.append( InstructionTextToken( InstructionTextTokenType.IntegerToken, operand, value=int(operand, 16), size=64)) else: tokens.append( InstructionTextToken( InstructionTextTokenType.RegisterToken, operand)) tokens.append( InstructionTextToken( InstructionTextTokenType.OperandSeparatorToken, ", ")) tokens.pop() else: tokens.append( InstructionTextToken(InstructionTextTokenType.InstructionToken, code)) return tokens, 1
{ "title" : "Indentation Syntax highlighting for snippets", "type" : "string", "default" : " ", "description" : "String to use for indentation in snippets (tip: to use a tab, copy/paste a tab from another text field and paste here)", "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] } """) snippetPath = os.path.realpath( os.path.join(user_plugin_path(), "..", "snippets")) try: if not os.path.exists(snippetPath): os.mkdir(snippetPath) except IOError: log_error("Unable to create %s" % snippetPath) def includeWalk(dir, includeExt): filePaths = [] for (root, dirs, files) in os.walk(dir): for f in files: if os.path.splitext(f)[1] in includeExt: filePaths.append(os.path.join(root, f)) return filePaths def loadSnippetFromFile(snippetPath): try: with codecs.open(snippetPath, 'r', 'utf-8') as snippetFile: snippetText = snippetFile.readlines()
def _set_current_address(self, ctxt, addr): try: self.perform_set_current_address(addr) except: log.log_error(traceback.format_exc())
def init(self): try: hdr = self.parent_view.read(0, 16) self.rom_banks = struct.unpack("B", hdr[4:5])[0] self.vrom_banks = struct.unpack("B", hdr[5:6])[0] self.rom_flags = struct.unpack("B", hdr[6:7])[0] self.mapper_index = struct.unpack( "B", hdr[7:8])[0] | (self.rom_flags >> 4) self.ram_banks = struct.unpack("B", hdr[8:9])[0] self.rom_offset = 16 if self.rom_flags & 4: self.rom_offset += 512 self.rom_length = self.rom_banks * 0x4000 # Add mapping for RAM and hardware registers, not backed by file contents self.add_auto_segment( 0, 0x8000, 0, 0, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable) # Add ROM mappings self.add_auto_segment( 0x8000, 0x4000, self.rom_offset + (self.__class__.bank * 0x4000), 0x4000, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.add_auto_segment( 0xc000, 0x4000, self.rom_offset + self.rom_length - 0x4000, 0x4000, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) nmi = struct.unpack("<H", self.read(0xfffa, 2))[0] start = struct.unpack("<H", self.read(0xfffc, 2))[0] irq = struct.unpack("<H", self.read(0xfffe, 2))[0] self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, nmi, "_nmi")) self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, start, "_start")) self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, irq, "_irq")) self.add_function(nmi) self.add_function(irq) self.add_entry_point(start) # Hardware registers self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2000, "PPUCTRL")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2001, "PPUMASK")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2002, "PPUSTATUS")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2003, "OAMADDR")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2004, "OAMDATA")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2005, "PPUSCROLL")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2006, "PPUADDR")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x2007, "PPUDATA")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4000, "SQ1_VOL")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4001, "SQ1_SWEEP")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4002, "SQ1_LO")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4003, "SQ1_HI")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4004, "SQ2_VOL")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4005, "SQ2_SWEEP")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4006, "SQ2_LO")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4007, "SQ2_HI")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4008, "TRI_LINEAR")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x400a, "TRI_LO")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x400b, "TRI_HI")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x400c, "NOISE_VOL")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x400e, "NOISE_LO")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x400f, "NOISE_HI")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4010, "DMC_FREQ")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4011, "DMC_RAW")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4012, "DMC_START")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4013, "DMC_LEN")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4014, "OAMDMA")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4015, "SND_CHN")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4016, "JOY1")) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, 0x4017, "JOY2")) sym_files = [ self.file.filename + ".%x.nl" % self.__class__.bank, self.file.filename + ".ram.nl", self.file.filename + ".%x.nl" % (self.rom_banks - 1) ] for f in sym_files: if os.path.exists(f): with open(f, "r") as f: lines = f.readlines() for line in lines: line = line.strip() sym = line.split('#') if len(sym) < 3: break addr = int(sym[0][1:], 16) name = sym[1] self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, addr, name)) if addr >= 0x8000: self.add_function(addr) return True except: log_error(traceback.format_exc()) return False
def decompile(view, function): try: retdec = RetDec(view, function) retdec.decompile_function() except Exception as e: log_error('failed to decompile function\n{}'.format(e.message))
def _get_current_offset(self, ctxt): try: return self.get_current_offset() except: log.log_error(traceback.format_exc()) return 0
def _navigate(self, ctxt, view, offset): try: return self.navigate(view, offset) except: log.log_error(traceback.format_exc()) return False
def init(self): try: hdr = self.parent_view.read(0, 128) self.version = struct.unpack("B", hdr[5])[0] self.song_count = struct.unpack("B", hdr[6])[0] self.starting_song = struct.unpack("B", hdr[7])[0] self.load_address = struct.unpack("<H", hdr[8:10])[0] self.init_address = struct.unpack("<H", hdr[10:12])[0] self.play_address = struct.unpack("<H", hdr[12:14])[0] self.song_name = hdr[15].split('\0')[0] self.artist_name = hdr[46].split('\0')[0] self.copyright_name = hdr[78].split('\0')[0] self.play_speed_ntsc = struct.unpack("<H", hdr[110:112])[0] self.bank_switching = hdr[112:120] self.play_speed_pal = struct.unpack("<H", hdr[120:122])[0] self.pal_ntsc_bits = struct.unpack("B", hdr[122])[0] self.pal = True if (self.pal_ntsc_bits & 1) == 1 else False self.ntsc = not self.pal if self.pal_ntsc_bits & 2 == 2: self.pal = True self.ntsc = True self.extra_sound_bits = struct.unpack("B", hdr[123])[0] if self.bank_switching == "\0" * 8: # no bank switching self.load_address & 0xFFF self.rom_offset = 128 else: # bank switching not implemented log_info("Bank switching not implemented in this loader.") # Add mapping for RAM and hardware registers, not backed by file contents self.add_auto_segment(0, 0x8000, 0, 0, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable) # Add ROM mappings self.add_auto_segment(0x8000, 0x4000, self.rom_offset, 0x4000, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, self.play_address, "_play")) self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, self.init_address, "_init")) self.add_entry_point(self.init_address) self.add_function(self.play_address) # Hardware registers self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2000, "PPUCTRL")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2001, "PPUMASK")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2002, "PPUSTATUS")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2003, "OAMADDR")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2004, "OAMDATA")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2005, "PPUSCROLL")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2006, "PPUADDR")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2007, "PPUDATA")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4000, "SQ1_VOL")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4001, "SQ1_SWEEP")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4002, "SQ1_LO")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4003, "SQ1_HI")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4004, "SQ2_VOL")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4005, "SQ2_SWEEP")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4006, "SQ2_LO")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4007, "SQ2_HI")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4008, "TRI_LINEAR")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400a, "TRI_LO")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400b, "TRI_HI")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400c, "NOISE_VOL")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400e, "NOISE_LO")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400f, "NOISE_HI")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4010, "DMC_FREQ")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4011, "DMC_RAW")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4012, "DMC_START")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4013, "DMC_LEN")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4014, "OAMDMA")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4015, "SND_CHN")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4016, "JOY1")) self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4017, "JOY2")) return True except: log_error(traceback.format_exc()) return False
return DownloadInstance.Response(result.getcode(), result.headers, None) class PythonDownloadProvider(DownloadProvider): name = "PythonDownloadProvider" instance_class = PythonDownloadInstance PythonDownloadProvider().register() _loaded = True except ImportError: pass if not _loaded: if sys.platform == "win32": log.log_error( "The pip requests package is required for network connectivity!") log.log_error( "Please install the requests package into the selected Python environment:" ) log.log_error(" python -m pip install requests") else: log.log_error( "On Python versions below 2.7.9, the pip requests[security] package is required for network connectivity!" ) log.log_error( "On an Ubuntu 14.04 install, the following three commands are sufficient to enable networking for the current user:"******" sudo apt install python-pip") log.log_error(" python -m pip install pip --upgrade --user") log.log_error( " python -m pip install requests[security] --upgrade --user")