def buildBasicBlocks(leaders, code_object, entry_addr): i = 0 bb_list = [] disassembler = Disassembler(code_object) while i < len(leaders): leader1, leader2 = leaders[i], leaders[i+1] addr1, addr2 = leader1.addr, leader2.addr bb = BasicBlock() bb_list.append(bb) bb.addr = addr1 offset = 0 if addr1 == entry_addr: bb.isEntry = True if leader1.type == 'S' and leader2.type == 'E': while addr1 + offset <= addr2: ins = disassembler.disasAt(addr1 + offset) bb.addInstruction(ins) offset += ins.size i += 2 elif leader1.type == 'S' and leader2.type == 'S': while addr1 + offset < addr2: ins = disassembler.disasAt(addr1 + offset) bb.addInstruction(ins) offset += ins.size i += 1 return bb_list
def buildBasicBlocks(leaders, code_object, entry_addr): i = 0 bb_list = [] disassembler = Disassembler(code_object) while i < len(leaders): leader1, leader2 = leaders[i], leaders[i + 1] addr1, addr2 = leader1.addr, leader2.addr bb = BasicBlock() bb_list.append(bb) bb.addr = addr1 offset = 0 if addr1 == entry_addr: bb.isEntry = True if leader1.type == 'S' and leader2.type == 'E': while addr1 + offset <= addr2: ins = disassembler.disasAt(addr1 + offset) bb.addInstruction(ins) offset += ins.size i += 2 elif leader1.type == 'S' and leader2.type == 'S': while addr1 + offset < addr2: ins = disassembler.disasAt(addr1 + offset) bb.addInstruction(ins) offset += ins.size i += 1 return bb_list
def __init__(self, filename): Disassembler.__init__(self, filename) PAPA_ROP.__init__(self, filename) Format_String.__init__(self, filename) Process.__init__(self, filename) Misc.__init__(self, filename) context.log_level = 'INFO' context.delete_corefiles = True
def main(): if len(argv) < 3: print "Usage : %s <number of instrucitons> <filename>" % argv[0] return analyzer = Analyzer(argv[1]) da = Disassembler() da.disassemble(analyzer, argv[2])
def findLeaders(code_object, oep): Leader = collections.namedtuple('leader', ['type', 'addr']) leader_set = set() leader_set.add(Leader('S', oep)) # Queue to contain list of addresses to be analyzed by linear sweep disassembly algorithm analysis_Q = Queue.Queue() analysis_Q.put(oep) analyzed_addresses = set() disassembler = Disassembler(code_object) while not analysis_Q.empty(): addr = analysis_Q.get() while True: ins = disassembler.disasAt(addr) analyzed_addresses.add(addr) # If current instruction is a return, stop disassembling further # current address is an end leader if utils.isRetIns(ins): leader_set.add(Leader('E', addr)) break # If current instruction is braching, stop disassembling further # the current instr is an end leader, branch target is start leader if utils.isBranchIns(ins): leader_set.add(Leader('E', addr)) for target in getInsCrossRef(ins, addr): leader_set.add(Leader('S', target)) if target not in analyzed_addresses: analysis_Q.put(target) break # Current instruction is not branching else: # Get cross refs cross_refs = getInsCrossRef(ins, addr) addr = cross_refs[0] # The immediate next instruction # Some non branching instructions like SETUP_LOOP, # SETUP_EXCEPT can have more than 1 cross references if len(cross_refs) == 2: leader_set.add(Leader('S', cross_refs[1])) if cross_refs[1] not in analyzed_addresses: analysis_Q.put(cross_refs[1]) return sorted(leader_set, cmp = _leaderSortFunc)
def findLeaders(code_object, oep): Leader = collections.namedtuple('leader', ['type', 'addr']) leader_set = set() leader_set.add(Leader('S', oep)) # Queue to contain list of addresses to be analyzed by linear sweep disassembly algorithm analysis_Q = queue.Queue() analysis_Q.put(oep) analyzed_addresses = set() disassembler = Disassembler(code_object) while not analysis_Q.empty(): addr = analysis_Q.get() while True: ins = disassembler.disasAt(addr) analyzed_addresses.add(addr) # If current instruction is a return, stop disassembling further # current address is an end leader if utils.isRetIns(ins): leader_set.add(Leader('E', addr)) break # If current instruction is braching, stop disassembling further # the current instr is an end leader, branch target is start leader if utils.isBranchIns(ins): leader_set.add(Leader('E', addr)) for target in getInsCrossRef(ins, addr): leader_set.add(Leader('S', target)) if target not in analyzed_addresses: analysis_Q.put(target) break # Current instruction is not branching else: # Get cross refs cross_refs = getInsCrossRef(ins, addr) addr = cross_refs[0] # The immediate next instruction # Some non branching instructions like SETUP_LOOP, # SETUP_EXCEPT can have more than 1 cross references if len(cross_refs) == 2: leader_set.add(Leader('S', cross_refs[1])) if cross_refs[1] not in analyzed_addresses: analysis_Q.put(cross_refs[1]) return sorted(leader_set, cmp=_leaderSortFunc)
def _reset(self, mpu_type, getc_addr=0xF004, putc_addr=0xF001): self._mpu = mpu_type(memory=self.memory) self.addrWidth = self._mpu.ADDR_WIDTH self.byteWidth = self._mpu.BYTE_WIDTH self.addrFmt = self._mpu.ADDR_FORMAT self.byteFmt = self._mpu.BYTE_FORMAT self.addrMask = self._mpu.addrMask self.byteMask = self._mpu.byteMask if getc_addr and putc_addr: self._install_mpu_observers(getc_addr, putc_addr) self._address_parser = AddressParser() self._disassembler = Disassembler(self._mpu, self._address_parser) self._assembler = Assembler(self._mpu, self._address_parser)
def __init__(self, binary): Disassembler.__init__(self, binary) self.__init_resolver() # initial build of graph self.__build_graph(self.get_blocks()) self.__mark_signature_blocks() # simplify graph self.graph.simplify(self.__signature_blocks, self.resolver) # build again because we need the indirect jumps self.__build_graph(self.graph.get_blocks()) self.__create_external_functions() self.__create_fallback_function()
def getDisassembly(self): if hasattr(self, "disassembly"): return self.disassembly vfile = self.node.open() content = vfile.read() vfile.close() disassembler = Disassembler() try: self.disassembly = ("%s - " % (self.node.name()) + disassembler.disassemble(content)).split('\n') except Exception as e: self.stateinfo = e self.disassembly = ["Unable to disassemble file: %s" % e] # TODO: do not show the disassembly window return self.disassembly
def main(): rom_parser = argparse.ArgumentParser(description='NES Disassembler') rom_parser.add_argument('rom_path', metavar='ROM', type=str, help='Path to NES ROM.') args = rom_parser.parse_args() print(args.rom_path) # Load the ROM with open(args.rom_path, 'rb') as rom: rom_hex = rom.read() # Create the Disassembler disassembler = Disassembler() disassembler.process_hex(rom_hex[32768:65536])
def deobfuscate(codestring): # Instructions are stored as a string, we need # to convert it to an array of the raw bytes insBytes = bytearray(codestring) oep = find_oep(insBytes) logger.info('Original code entrypoint at {}'.format(oep)) logger.info('Starting control flow analysis...') disasm = Disassembler(insBytes, oep) disasm.find_leaders() disasm.construct_basic_blocks() disasm.build_bb_edges() logger.info('Control flow analysis completed.') logger.info('Starting simplication of basic blocks...') render_graph(disasm.bb_graph, 'before.svg') simplifier = Simplifier(disasm.bb_graph) simplifier.eliminate_forwarders() render_graph(simplifier.bb_graph, 'after_forwarder.svg') simplifier.merge_basic_blocks() logger.info('Simplification of basic blocks completed.') simplified_graph = simplifier.bb_graph render_graph(simplified_graph, 'after.svg') logger.info('Beginning verification of simplified basic block graph...') if not verify_graph(simplified_graph): logger.error('Verification failed.') raise SystemExit logger.info('Verification succeeded.') logger.info('Assembling basic blocks...') asm = Assembler(simplified_graph) codestring = asm.assemble() logger.info('Successfully assembled. ') return codestring
def test_disasm( addr, show_strings = False, show_line_addrs = False, no_pointer = False, cpp_macros = False, map_path = "R8PP01.map", dump_path = "ram.raw", spm = True, recursive = False ): ctx = DummyConfig(show_strings, show_line_addrs, no_pointer, cpp_macros, map_path, dump_path, spm, recursive) dis = Disassembler(ctx) return dis.disassemble(addr)
def findOEP(code_object): ''' Finds the original entry point of a code object obfuscated by PjOrion. DO NOT call this for a non obfsucated code object. :param code_object: the code object :type code_object: code :returns: the entrypoint :rtype: int ''' disassembler = Disassembler(code_object) ins = disassembler.disasAt(0) try: assert utils.insMnemonic(ins) == 'SETUP_EXCEPT' except_handler = 0 + ins.arg + ins.size assert disassembler.disasAt(3).opkode == -1 assert utils.insMnemonic( disassembler.disasAt(except_handler)) == 'POP_TOP' assert utils.insMnemonic(disassembler.disasAt(except_handler + 1)) == 'POP_TOP' assert utils.insMnemonic(disassembler.disasAt(except_handler + 2)) == 'POP_TOP' return except_handler + 3 except: return -1
def display_state(self): lines = disassembler.disassemble(self.current_block_start, self.mem, self.registers[PC] + 10) for line in lines: addr, insn = line text = "%x: %s" % line if addr == self.registers[PC]: self.display(colored(text, 'green')) else: self.display(text) self.display('') for i, r in enumerate(self.registers): self.debug_output.write('%s: %04x' % (Disassembler.pretty_reg(i), r)) if (i + 1) % 4 == 0: self.debug_output.write('\n') else: self.debug_output.write('\t') self.display('') for reg in self.tracked_registers: self.debug_output.write(colored('%s >> ' % Disassembler.pretty_reg(reg), 'blue')) self.display_mem(self.registers[reg])
def debugRun(source_code, vm): #why this runs, its because of the lox interpreter environment, which remains in existence even after this function ends scanner = Scanner(source_code) scanner.scanTokens() print(scanner.toString()) parser = Parser(scanner.token_list) parser.parse() print("##################################AST###################################") print(ASTPrinter().printAll(parser.AST)) print("########################################################################") compiler = Compiler() compiler.compileAll(parser.AST) disassembler = Disassembler(compiler.chunk) print("#############################ByteCode###################################") print(disassembler.pretty_print()) print("########################################################################") vm.run(compiler.chunk)
def run(source_code, vm): #why this runs, its because of the lox interpreter environment, which remains in existence even after this function ends scanner = Scanner(source_code) scanner.scanTokens() parser = Parser(scanner.token_list) parser.parse() compiler = Compiler() compiler.compileAll(parser.AST) disassembler = Disassembler(compiler.chunk) vm.run(compiler.chunk)
def findOEP(code_object): ''' Finds the original entry point of a code object obfuscated by PjOrion. DO NOT call this for a non obfsucated code object. :param code_object: the code object :type code_object: code :returns: the entrypoint :rtype: int ''' disassembler = Disassembler(code_object) ins = disassembler.disasAt(0) try: assert utils.insMnemonic(ins) == 'SETUP_EXCEPT' except_handler = 0 + ins.arg + ins.size assert disassembler.disasAt(3).opkode == -1 assert utils.insMnemonic(disassembler.disasAt(except_handler)) == 'POP_TOP' assert utils.insMnemonic(disassembler.disasAt(except_handler + 1)) == 'POP_TOP' assert utils.insMnemonic(disassembler.disasAt(except_handler + 2)) == 'POP_TOP' return except_handler + 3 except: return -1
def trace(self, pc, name, is_byte_insn, args, m): if self.loop_header is not None: if self.loop_header == pc: self.loop_count += 1 return elif self.loop_header < pc <= self.loop_end: return else: self.tracefile.write('<loop %d times>\n' % self.loop_count) self.loop_header = None self.loop_count = 0 if name[0] == 'j' and name != 'jmp' and -0x20 <= args[0] < 0: target = args[0] + pc simple_loop = True for op_pc, op_name in reversed(self.circular_buffer): if op_pc == target: break if op_name[0] == 'j': simple_loop = False break if simple_loop: self.loop_header = target self.loop_end = pc if name[0] != 'j': emulated_name, emulated_args = \ Disassembler.try_emulate_insn(name, args) if is_byte_insn: emulated_name += '.b' arg_strs = map(Disassembler.pretty_addr, emulated_args) values = [] for i, s in enumerate(arg_strs): if s[0] != '#': values.append('%04x (%04x)' % (m.get_addr(args[i], inc=False), m.registers[args[i].loc])) arg_str = ", ".join(arg_strs) if len(values) > 0: arg_str += ' [%s]' % ", ".join(values) else: emulated_name = name arg_str = '$%+x [%04x]' % (args[0], args[0] + pc) self.circular_buffer.append((pc, name)) self.tracefile.write("%04x %s\t%s\n" % (pc, emulated_name, arg_str))
def test(): from disassembler import Disassembler from vm import Vm byte_array = Chunk() ############################################################# constant = 100 byte_array.pushConstant(constant, at_line=1) ############################################################# constant = 200 byte_array.pushConstant(constant, at_line=1) ############################################################# byte_array.push(OpCode.OP_ADD, at_line=1) byte_array.push(OpCode.OP_RETURN, at_line=1) print(Disassembler(byte_array).disassemble()) vm = Vm(byte_array) print("vm result ", vm.run())
class Monitor(cmd.Cmd): Microprocessors = { '6502': NMOS6502, '65C02': CMOS65C02, '65Org16': V65Org16 } def __init__(self, argv=None, stdin=None, stdout=None, mpu_type=NMOS6502, memory=None, putc_addr=0xF001, getc_addr=0xF004): self.mpu_type = mpu_type self.memory = memory self.putc_addr = putc_addr self.getc_addr = getc_addr self._breakpoints = [] self._width = 78 self.prompt = "." self.quiet_mode = False # !!lb self._add_shortcuts() cmd.Cmd.__init__(self, stdin=stdin, stdout=stdout) if argv is None: argv = sys.argv quiet, addr, load, rom, goto = self._parse_args( argv) # !!lb added quiet, addr self._reset(self.mpu_type, self.getc_addr, self.putc_addr) if quiet is not None: # !!lb self.quiet_mode = quiet if load is not None: # self.do_load("%r" % load) # !!lb replaced by following if addr is None: self.do_load("%r" % load) else: load_addr = self._address_parser.number(addr) self.do_load("%r %x" % (load, load_addr)) if goto is not None: self.do_goto(goto) if rom is not None: # load a ROM and run from the reset vector self.do_load("%r top" % rom) physMask = self._mpu.memory.physMask reset = self._mpu.RESET & physMask dest = self._mpu.memory[reset] + \ (self._mpu.memory[reset + 1] << self.byteWidth) self.do_goto("$%x" % dest) def _parse_args(self, argv): try: shortopts = 'hqa:i:o:m:l:r:g:' # !!lb added qa: longopts = [ 'help', 'quiet', 'addr=' # !!lb added quiet, addr= 'mpu=', 'input=', 'output=', 'load=', 'rom=', 'goto=' ] options, args = getopt.getopt(argv[1:], shortopts, longopts) except getopt.GetoptError as exc: self._output(exc.args[0]) self._usage() self._exit(1) quiet, addr, load, rom, goto = None, None, None, None, None # !!lb added quiet, addr for opt, value in options: if opt in ('-i', '--input'): self.getc_addr = int(value, 16) if opt in ('-o', '--output'): self.putc_addr = int(value, 16) if opt in ('-m', '--mpu'): mpu_type = self._get_mpu(value) if mpu_type is None: mpus = sorted(self.Microprocessors.keys()) msg = "Fatal: no such MPU. Available MPUs: %s" self._output(msg % ', '.join(mpus)) sys.exit(1) self.mpu_type = mpu_type if opt in ("-h", "--help"): self._usage() self._exit(0) if opt in ('-l', '--load'): load = value if opt in ('-a', '--addr'): # !!lb addr = value if opt in ('-r', '--rom'): rom = value if opt in ('-g', '--goto'): goto = value if opt in ('-q', '--quiet'): # !!lb quiet = True return quiet, addr, load, rom, goto # !!lb added quiet, addr def _usage(self): usage = __doc__ % sys.argv[0] self._output(usage) def onecmd(self, line): line = self._preprocess_line(line) result = None try: result = cmd.Cmd.onecmd(self, line) except KeyboardInterrupt: self._output("Interrupt") except Exception: (file, fun, line), t, v, tbinfo = compact_traceback() error = 'Error: %s, %s: file: %s line: %s' % (t, v, file, line) self._output(error) if not line.startswith("quit"): self._output_mpu_status() return result def _reset(self, mpu_type, getc_addr=0xF004, putc_addr=0xF001): self._mpu = mpu_type(memory=self.memory) self.addrWidth = self._mpu.ADDR_WIDTH self.byteWidth = self._mpu.BYTE_WIDTH self.addrFmt = self._mpu.ADDR_FORMAT self.byteFmt = self._mpu.BYTE_FORMAT self.addrMask = self._mpu.addrMask self.byteMask = self._mpu.byteMask if getc_addr and putc_addr: self._install_mpu_observers(getc_addr, putc_addr) self._address_parser = AddressParser() self._disassembler = Disassembler(self._mpu, self._address_parser) self._assembler = Assembler(self._mpu, self._address_parser) def _add_shortcuts(self): self._shortcuts = { 'EOF': 'quit', '~': 'tilde', 'a': 'assemble', 'ab': 'add_breakpoint', 'al': 'add_label', 'd': 'disassemble', 'db': 'delete_breakpoint', 'dl': 'delete_label', 'exit': 'quit', 'f': 'fill', '>': 'fill', 'g': 'goto', 'go': 'go', # !!lb 'h': 'help', '?': 'help', 'l': 'load', 'm': 'mem', 'q': 'quit', 'r': 'registers', 'ret': 'return', 'rad': 'radix', 's': 'save', 'shb': 'show_breakpoints', 'shl': 'show_labels', 'x': 'quit', 'z': 'step' } def _preprocess_line(self, line): # line comments quoted = False for pos, char in enumerate(line): if char in ('"', "'"): quoted = not quoted if (not quoted) and (char == ';'): line = line[:pos] break # whitespace & leading dots line = line.strip(' \t').lstrip('.') # special case for vice compatibility if line.startswith('~'): line = self._shortcuts['~'] + ' ' + line[1:] # command shortcuts for shortcut, command in self._shortcuts.items(): if line == shortcut: line = command break pattern = '^%s\s+' % re.escape(shortcut) matches = re.match(pattern, line) if matches: start, end = matches.span() line = "%s %s" % (command, line[end:]) break return line def _get_mpu(self, name): requested = name.lower() mpu = None for key, klass in self.Microprocessors.items(): if key.lower() == requested: mpu = klass break return mpu def _install_mpu_observers(self, getc_addr, putc_addr): def putc(address, value): try: self.stdout.write(chr(value)) except UnicodeEncodeError: # Python 3 self.stdout.write("?") self.stdout.flush() def getc(address): char = console.getch_noblock(self.stdin) if char: byte = ord(char) else: byte = 0 return byte m = ObservableMemory(subject=self.memory, addrWidth=self.addrWidth) m.subscribe_to_write([self.putc_addr], putc) m.subscribe_to_read([self.getc_addr], getc) self._mpu.memory = m def _output_mpu_status(self): self._output("\n" + repr(self._mpu)) def _output(self, stuff): self.stdout.write("%s\n" % stuff) def _exit(self, exitcode=0): sys.exit(exitcode) def do_help(self, args): args = self._shortcuts.get(args.strip(), args) return cmd.Cmd.do_help(self, args) def help_version(self): self._output("version\t\tDisplay Py65 version information.") def do_version(self, args): self._output("\nPy65 Monitor") self._output("(Reformed Devs Code Golf 2019.06 edition)") # !!lb def help_help(self): self._output("help\t\tPrint a list of available actions.") self._output("help <action>\tPrint help for <action>.") def help_reset(self): self._output("reset\t\tReset the microprocessor") def do_reset(self, args): klass = self._mpu.__class__ self._reset(mpu_type=klass) def do_mpu(self, args): def available_mpus(): mpus = list(self.Microprocessors.keys()) mpus.sort() self._output("Available MPUs: %s" % ', '.join(mpus)) if args == '': self._output("Current MPU is %s" % self._mpu.name) available_mpus() else: new_mpu = self._get_mpu(args) if new_mpu is None: self._output("Unknown MPU: %s" % args) available_mpus() else: self._reset(new_mpu, self.getc_addr, self.putc_addr) self._output("Reset with new MPU %s" % self._mpu.name) def help_mpu(self): self._output("mpu\t\tPrint available microprocessors.") self._output("mpu <type>\tSelect a new microprocessor.") def do_quit(self, args): self._output('') return 1 def help_quit(self): self._output("To quit, type ^D or use the quit command.") def do_assemble(self, args): splitted = args.split(None, 1) if len(splitted) != 2: return self._interactive_assemble(args) statement = splitted[1] try: start = self._address_parser.number(splitted[0]) bytes = self._assembler.assemble(statement, start) end = start + len(bytes) self._mpu.memory[start:end] = bytes self.do_disassemble(self.addrFmt % start) except KeyError as exc: self._output(exc.args[0]) # "Label not found: foo" except OverflowError: self._output("Overflow error: %s" % args) except SyntaxError: self._output("Syntax error: %s" % statement) def help_assemble(self): self._output("assemble\t\t\t" "Start interactive assembly at the program counter.") self._output("assemble <address>\t\t" "Start interactive assembly at the address.") self._output("assemble <address> <statement>\t" "Assemble a statement at the address.") def _interactive_assemble(self, args): if args == '': start = self._mpu.pc else: try: start = self._address_parser.number(args) except KeyError as exc: self._output(exc.args[0]) # "Label not found: foo" return while True: prompt = "\r$" + (self.addrFmt % start) + " " + \ (" " * int(1 + self.byteWidth / 4) * 3) line = console.line_input(prompt, stdin=self.stdin, stdout=self.stdout) if not line.strip(): self.stdout.write("\n") return # assemble into memory try: bytes = self._assembler.assemble(line, pc=start) numbytes = len(bytes) end = start + numbytes self._mpu.memory[start:end] = bytes # print disassembly _, disasm = self._disassembler.instruction_at(start) fdisasm = self._format_disassembly(start, numbytes, disasm) indent = ' ' * (len(prompt + line) + 5) self.stdout.write("\r" + indent + "\r") self.stdout.write(fdisasm + "\n") # advance to next address start += numbytes if start >= (2**self._mpu.ADDR_WIDTH): start = 0 except KeyError: addr = self.addrFmt % start self.stdout.write("\r$%s ?Label\n" % addr) except OverflowError: addr = self.addrFmt % start self.stdout.write("\r$%s ?Overflow\n" % addr) except SyntaxError: addr = self.addrFmt % start self.stdout.write("\r$%s ?Syntax\n" % addr) def do_disassemble(self, args): splitted = shlex.split(args) if len(splitted) != 1: return self.help_disassemble() address_parts = splitted[0].split(":") start = self._address_parser.number(address_parts[0]) if len(address_parts) > 1: end = self._address_parser.number(address_parts[1]) else: end = start max_address = (2**self._mpu.ADDR_WIDTH) - 1 cur_address = start needs_wrap = start > end while needs_wrap or cur_address <= end: length, disasm = self._disassembler.instruction_at(cur_address) self._output(self._format_disassembly(cur_address, length, disasm)) remaining = length while remaining: remaining -= 1 cur_address += 1 if start > end and cur_address > max_address: needs_wrap = False cur_address = 0 def _format_disassembly(self, address, length, disasm): cur_address = address max_address = (2**self._mpu.ADDR_WIDTH) - 1 bytes_remaining = length dump = '' while bytes_remaining: if cur_address > max_address: cur_address = 0 dump += self.byteFmt % self._mpu.memory[cur_address] + " " cur_address += 1 bytes_remaining -= 1 fieldwidth = 1 + int(1 + self.byteWidth / 4) * 3 fieldfmt = "%%-%ds" % fieldwidth return "$" + self.addrFmt % address + " " + fieldfmt % dump + disasm def help_disassemble(self): self._output("disassemble <address_range>") self._output("Disassemble instructions in the address range.") self._output('Range is specified like "<start>:<end>".') def help_step(self): self._output("step") self._output("Single-step through instructions.") def do_step(self, args): self._mpu.step() self.do_disassemble(self.addrFmt % self._mpu.pc) def help_return(self): self._output("return") self._output("Continues execution and returns to the monitor just") self._output("before the next RTS or RTI is executed.") def do_return(self, args): returns = [0x60, 0x40] # RTS, RTI self._run(stopcodes=returns) def help_goto(self): self._output("goto <address>") self._output("Change the PC to address and continue execution.") def do_goto(self, args): if args == '': return self.help_goto() self._mpu.pc = self._address_parser.number(args) brks = [0x00] # BRK self._run(stopcodes=brks) def help_go(self): # !!lb self._output("go") self._output("Continue execution.") def do_go(self, args): # !!lb brks = [0x00] # BRK self._run(stopcodes=brks) def _run(self, stopcodes): stopcodes = set(stopcodes) breakpoints = set(self._breakpoints) mpu = self._mpu mem = self._mpu.memory if not breakpoints: while True: mpu.step() if mem[mpu.pc] in stopcodes: break else: while True: mpu.step() pc = mpu.pc if mem[pc] in stopcodes: break if pc in breakpoints: msg = "Breakpoint %d reached." self._output(msg % self._breakpoints.index(pc)) break def help_radix(self): self._output("radix [H|D|O|B]") self._output("Set default radix to hex, decimal, octal, or binary.") self._output("With no argument, the current radix is printed.") def help_cycles(self): self._output("Display the total number of cycles executed.") def do_cycles(self, args): self._output(str(self._mpu.processorCycles)) def do_radix(self, args): radixes = {'Hexadecimal': 16, 'Decimal': 10, 'Octal': 8, 'Binary': 2} if args != '': new = args[0].lower() changed = False for name, radix in radixes.items(): if name[0].lower() == new: self._address_parser.radix = radix changed = True if not changed: self._output("Illegal radix: %s" % args) for name, radix in radixes.items(): if self._address_parser.radix == radix: self._output("Default radix is %s" % name) def help_tilde(self): self._output("~ <number>") self._output("Display a number in decimal, hex, octal, and binary.") def do_tilde(self, args): if args == '': return self.help_tilde() try: num = self._address_parser.number(args) self._output("+%u" % num) self._output("$" + self.byteFmt % num) self._output("%04o" % num) self._output(itoa(num, 2).zfill(8)) except KeyError: self._output("Bad label: %s" % args) except OverflowError: self._output("Overflow error: %s" % args) def help_registers(self): self._output("registers[<name>=<value> [, <name>=<value>]*]") self._output("Assign respective registers. With no parameters,") self._output("display register values.") def do_registers(self, args): if args == '': return pairs = re.findall('([^=,\s]*)=([^=,\s]*)', args) if pairs == []: return self._output("Syntax error: %s" % args) for register, value in pairs: if register not in ('pc', 'sp', 'a', 'x', 'y', 'p'): self._output("Invalid register: %s" % register) else: try: intval = self._address_parser.number(value) except KeyError as exc: # label not found self._output(exc.args[0]) continue except OverflowError as exc: # wider than address space msg = "Overflow: %r too wide for register %r" self._output(msg % (value, register)) continue if register != 'pc': if intval != (intval & self.byteMask): msg = "Overflow: %r too wide for register %r" self._output(msg % (value, register)) continue setattr(self._mpu, register, intval) def help_cd(self): self._output("cd <directory>") self._output("Change the working directory.") def do_cd(self, args): if args == '': return self.help_cd() try: os.chdir(args) except OSError as exc: msg = "Cannot change directory: [%d] %s" % (exc.errno, exc.strerror) self._output(msg) self.do_pwd() def help_pwd(self): self._output("Show the current working directory.") def do_pwd(self, args=None): cwd = os.getcwd() self._output(cwd) def help_load(self): self._output("load <filename|url> <address|top>") self._output("Load a file into memory at the specified address.") self._output('An address of "top" loads into the top of memory.') self._output("Commodore-style load address bytes are ignored.") def do_load(self, args): split = shlex.split(args) if len(split) not in (1, 2): self._output("Syntax error: %s" % args) return filename = split[0] if "://" in filename: try: f = urlopen(filename) bytes = f.read() f.close() except Exception as exc: msg = "Cannot fetch remote file: %s" % str(exc) self._output(msg) return else: try: f = open(filename, 'rb') bytes = f.read() f.close() except (OSError, IOError) as exc: msg = "Cannot load file: [%d] %s" % (exc.errno, exc.strerror) self._output(msg) return if len(split) == 2: if split[1] == "top": # load a ROM to top of memory top_address = self.addrMask program_size = len(bytes) // (self.byteWidth // 8) start = top_address - program_size + 1 else: start = self._address_parser.number(split[1]) else: start = self._mpu.pc if self.byteWidth == 8: if isinstance(bytes, str): bytes = map(ord, bytes) else: # Python 3 bytes = [b for b in bytes] elif self.byteWidth == 16: def format(msb, lsb): if isinstance(bytes, str): return (ord(msb) << 8) + ord(lsb) else: # Python 3 return (msb << 8) + lsb bytes = list(map(format, bytes[0::2], bytes[1::2])) self._fill(start, start, bytes) def help_save(self): self._output("save \"filename\" <start> <end>") self._output("Save the specified memory range as a binary file.") self._output("Commodore-style load address bytes are not written.") def do_save(self, args): split = shlex.split(args) if len(split) != 3: self._output("Syntax error: %s" % args) return filename = split[0] start = self._address_parser.number(split[1]) end = self._address_parser.number(split[2]) mem = self._mpu.memory[start:end + 1] try: f = open(filename, 'wb') for m in mem: # output each octect from msb first for shift in range(self.byteWidth - 8, -1, -8): f.write(bytearray([(m >> shift) & 0xff])) f.close() except (OSError, IOError) as exc: msg = "Cannot save file: [%d] %s" % (exc.errno, exc.strerror) self._output(msg) return self._output("Saved +%d bytes to %s" % (len(mem), filename)) def help_fill(self): self._output("fill <address_range> <data_list>") self._output("Fill memory in the address range with the data in") self._output("<data_list>. If the size of the address range is") self._output("greater than the size of the data_list, the data_list ") self._output("is repeated.") def do_fill(self, args): split = shlex.split(args) if len(split) < 2: return self.help_fill() try: start, end = self._address_parser.range(split[0]) filler = list(map(self._address_parser.number, split[1:])) except KeyError as exc: self._output(exc.args[0]) # "Label not found: foo" else: self._fill(start, end, filler) def _fill(self, start, end, filler): address = start length, index = len(filler), 0 if start == end: end = start + length - 1 if (end > self.addrMask): end = self.addrMask while address <= end: address &= self.addrMask self._mpu.memory[address] = (filler[index] & self.byteMask) index += 1 if index == length: index = 0 address += 1 if not self.quiet_mode: # !!lb fmt = (end - start + 1, start, end) starttoend = "$" + self.addrFmt + " to $" + self.addrFmt self._output(("Wrote +%d bytes from " + starttoend) % fmt) def help_mem(self): self._output("mem <address_range>") self._output("Display the contents of memory.") self._output('Range is specified like "<start:end>".') def do_mem(self, args): split = shlex.split(args) if len(split) != 1: return self.help_mem() start, end = self._address_parser.range(split[0]) line = self.addrFmt % start + ":" for address in range(start, end + 1): byte = self._mpu.memory[address] more = " " + self.byteFmt % byte exceeded = len(line) + len(more) > self._width if exceeded: self._output(line) line = self.addrFmt % address + ":" line += more self._output(line) def help_add_label(self): self._output("add_label <address> <label>") self._output("Map a given address to a label.") def do_add_label(self, args): split = shlex.split(args) if len(split) != 2: self._output("Syntax error: %s" % args) return self.help_add_label() try: address = self._address_parser.number(split[0]) except KeyError as exc: self._output(exc.args[0]) # "Label not found: foo" except OverflowError: self._output("Overflow error: %s" % args) else: label = split[1] self._address_parser.labels[label] = address def help_show_labels(self): self._output("show_labels") self._output("Display current label mappings.") def do_show_labels(self, args): values = list(self._address_parser.labels.values()) keys = list(self._address_parser.labels.keys()) byaddress = list(zip(values, keys)) byaddress.sort() for address, label in byaddress: self._output(self.addrFmt % address + ": " + label) def help_delete_label(self): self._output("delete_label <label>") self._output("Remove the specified label from the label tables.") def do_delete_label(self, args): if args == '': return self.help_delete_label() if args in self._address_parser.labels: del self._address_parser.labels[args] def do_width(self, args): if args != '': try: new_width = int(args) if new_width >= 10: self._width = new_width else: self._output("Minimum terminal width is 10") except ValueError: self._output("Illegal width: %s" % args) self._output("Terminal width is %d" % self._width) def help_width(self): self._output("width <columns>") self._output("Set the width used by some commands to wrap output.") self._output("With no argument, the current width is printed.") def do_add_breakpoint(self, args): split = shlex.split(args) if len(split) != 1: self._output("Syntax error: %s" % args) return self.help_add_breakpoint() address = self._address_parser.number(split[0]) if address in self._breakpoints: self._output("Breakpoint already present at $%04X" % address) else: self._breakpoints.append(address) msg = "Breakpoint %d added at $%04X" self._output(msg % (len(self._breakpoints) - 1, address)) def help_add_breakpoint(self): self._output("add_breakpoint <address|label>") self._output( "Add a breakpoint on execution at the given address or label") def do_delete_breakpoint(self, args): split = shlex.split(args) if len(split) != 1: self._output("Syntax error: %s" % args) return self.help_delete_breakpoint() number = None try: number = int(split[0]) if number < 0 or number > len(self._breakpoints): self._output("Invalid breakpoint number %d", number) return except ValueError: self._output("Illegal number: %s" % args) return if self._breakpoints[number] is not None: self._breakpoints[number] = None self._output("Breakpoint %d removed" % number) else: self._output("Breakpoint %d already removed" % number) def help_delete_breakpoint(self): self._output("delete_breakpoint <number>") self._output( "Delete the breakpoint on execution marked by the given number") def do_show_breakpoints(self, args): for i, address in enumerate(self._breakpoints): if address is not None: bpinfo = "Breakpoint %d: $%04X" % (i, address) label = self._address_parser.label_for(address) if label is not None: bpinfo += " " + label self._output(bpinfo) def help_show_breakpoints(self): self._output("show_breakpoints") self._output("Lists the currently assigned breakpoints")
def dasm(): return Disassembler()
def execute_next(self): cpuoff = self.registers[SR] & (1 << 4) if cpuoff: self.display('<CPUOFF bit set. Exiting.>') if cpuoff or self.door_unlocked: self.display('<Executed %d instructions.>' % self.insn_count) return False pc = self.registers[PC] self.insn_count += 1 step_count = self.step_count if self.step_count > 0: self.step_count -= 1 should_break = self.should_break(pc) if should_break: if self.breakpoints[pc] == 1: # -1 is a permanent breakpoint del self.breakpoints[pc] if pc in self.breakpoint_conditions: del self.breakpoint_conditions[pc] elif self.breakpoints > 1: self.breakpoints[pc] -= 1 if should_break or step_count == 1: self.handle_cmds() pc = self.registers[PC] # in case of reset is_ret = False is_call = False if pc == 0x10: self.handle_callgate(self.registers[SR]) self.mem[0x10] = 0x4130 # ret handler, is_byte_insn, args, size = self.decoder.decode(pc, self.mem) self.operand_bytes = 1 if is_byte_insn else 2 if handler is None: raise Exception('Failed to decode instruction at pc %x.' % pc) name = handler.__name__[3:] self.next_pc = pc + size self.registers[PC] += 2 if not self.peephole_execute(name, is_byte_insn, args, size): if self.trace is not None: self.trace(pc, name, is_byte_insn, args, self) handler(*args) is_ret = Disassembler.is_ret(name, args) is_call = name == 'call' if self.registers[PC] == pc + 2: self.registers[PC] = self.next_pc else: self.current_block_start = self.registers[PC] if self.break_at_finish >= 0: if is_ret: self.break_at_finish -= 1 if self.break_at_finish == -1: self.step_count = 1 elif is_call: self.break_at_finish += 1 if is_call: self.callsites.append(pc) self.call_targets.append(self.registers[PC]) elif is_ret: self.callsites.pop() self.call_targets.pop() return True
#!/usr/bin/python import argparse from disassembler import Disassembler from disassembly_writer import DisassemblyWriter if __name__ == '__main__': parser = argparse.ArgumentParser( description="Chip-8 disassembler using traversal tree algorithm.") parser.add_argument("romfile", help="The rom filename to load") args = parser.parse_args() dasm = Disassembler(args.romfile) dasm.decode(0x200) writer = DisassemblyWriter(args.romfile, dasm.labels, dasm.disassembly) writer.create_disassembly()
def main(): ctx = Config() dis = Disassembler(ctx) txt = dis.disassemble(ctx.addr) stdout.buffer.write(txt.encode("utf8")) # TODO: is there a better way to fix this?
import sys from disassembler import Disassembler import os disassembler = Disassembler() disassembler.run() disassembler.print()
# Assemble file. handler.assemble() elif args.disassemble: # Check to see if a start address was added. if args.startaddr: # Check to see if the address is valid. intval = int(args.startaddr, 16) if intval < 1 or intval > 65535: raise ValueError # Set up disassembler. handler = Disassembler(infile, outfile, intval, args.counter, args.program) # Disassemble file. handler.disassemble() elif args.execute or args.debug: # Check to see if a start address was added. if args.startaddr: # Check to see if the address is valid. intval = int(args.startaddr, 16) if intval < 1 or intval > 65535: raise ValueError
import argparse from rom import ROM from disassembler import Disassembler from instrumentation import processInstrumentation from annotation import simple from annotation import sdcc if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("rom", type=str) parser.add_argument("--instrumentation", action='append', default=[]) parser.add_argument("--source") parser.add_argument("--output", type=str, required=True) parser.add_argument("--plugin", action='append', default=[]) args = parser.parse_args() for plugin in args.plugin: exec(open(plugin, "rt").read()) rom = ROM(args.rom) disassembler = Disassembler(rom) disassembler.readSources(args.source if args.source else args.output) for instrumentation_file in args.instrumentation: processInstrumentation(instrumentation_file) disassembler.processRom() disassembler.export(args.output)
def run_dasm(memory): memory_size = len(memory.ram) dasm = Disassembler(memory) for _ in range(0, memory_size): dasm.disassembly()
from helper import open_as_byte_array from disassembler import Disassembler from cpu import CPU65816 from graphics import PictureProcessingUnit from memory import MemoryMapper import sys if len(sys.argv) <= 1: print("usage: python PySNES.py ROM_PATH [start] [end]") exit(0) ROM = open_as_byte_array(sys.argv[1]) #print_hex_dump(ba)[0:32] header = ROMHeader(ROM) header.dump() d = Disassembler() RAM = [0] * (2**17 - 1) # 128 KB SRAM = [0] * 0x7FFF # 32 KB memory = MemoryMapper(header, RAM, ROM, SRAM, False, 0x7FFF) c = CPU65816(memory) ppu = PictureProcessingUnit() ppu.init() while True: instr_str = d.disassemble_single_opcode(memory, c.PC, add_new_line=False, add_descr=False, add_addr=False, M=c.isM(), X=c.isX())