def verify_file(real_source_filename, real_bytecode_filename): """Compile *real_source_filename* using the running Python interpreter. Then write bytecode out to a new place again using Python's routines. Next load it in using two of our routines. Compare that the code objects there are equal. Next write out the bytecode (using the same Python bytecode writin routine as in step 1. Finally compare the bytecode files. """ tempdir = tempfile.gettempdir() source_filename = os.path.join(tempdir, "testing.py") if not os.path.exists(real_source_filename): return if PYTHON_VERSION < 3.0: f = open(real_source_filename, 'U') elif PYTHON_VERSION == 3.0: # Too hard to get working on 3.0 return elif 3.1 <= PYTHON_VERSION <= 3.4: f = open(real_source_filename, "rb") else: f = open(real_source_filename, newline=None, errors='backslashreplace') codestring = f.read() f.close() codeobject1 = compile(codestring, source_filename, 'exec') (version, timestamp, magic_int, codeobject2, is_pypy, source_size) = load_module(real_bytecode_filename) # A hack for PyPy 3.2 if magic_int == 3180 + 7: magic_int = 48 assert magics.MAGIC == magics.int2magic(magic_int), \ ("magic_int %d vs %d in %s/%s" % (magic_int, magics.PYTHON_MAGIC_INT, os.getcwd(), real_bytecode_filename)) bytecode_filename1 = os.path.join(tempdir, "testing1.pyc") dump_compile(codeobject1, bytecode_filename1, timestamp, magics.MAGIC) (version, timestamp, magic_int, codeobject3, is_pypy, source_size) = load_module(real_bytecode_filename, fast_load=not is_pypy) # compare_code(codeobject1, codeobject2) # compare_code(codeobject2, codeobject3) bytecode_filename2 = os.path.join(tempdir, "testing2.pyc") dump_compile(codeobject1, bytecode_filename2, timestamp, magics.int2magic(magic_int)) compare_bytecode_files(bytecode_filename1, bytecode_filename2) return
def verify_file(real_source_filename, real_bytecode_filename): """Compile *real_source_filename* using the running Python interpreter. Then write bytecode out to a new place again using Python's routines. Next load it in using two of our routines. Compare that the code objects there are equal. Next write out the bytecode (using the same Python bytecode writin routine as in step 1. Finally compare the bytecode files. """ tempdir = tempfile.gettempdir() source_filename = os.path.join(tempdir, "testing.py") if not os.path.exists(real_source_filename): return try: f = open(real_source_filename, 'U') except: return codestring = f.read() f.close() codeobject1 = compile(codestring, source_filename, 'exec') (version, timestamp, magic_int, codeobject2, is_pypy, source_size) = load_module(real_bytecode_filename) # A hack for PyPy 3.2 if magic_int == 3180 + 7: magic_int = 48 assert MAGIC == magics.int2magic(magic_int), \ ("magic_int %d vs %d in %s/%s" % (magic_int, magics.magic2int(MAGIC), os.getcwd(), real_bytecode_filename)) bytecode_filename1 = os.path.join(tempdir, "testing1.pyc") dump_compile(codeobject1, bytecode_filename1, timestamp, MAGIC) (version, timestamp, magic_int, codeobject3, is_pypy, source_size) = load_module(real_bytecode_filename, fast_load=not is_pypy) # compare_code(codeobject1, codeobject2) # compare_code(codeobject2, codeobject3) bytecode_filename2 = os.path.join(tempdir, "testing2.pyc") dump_compile(codeobject1, bytecode_filename2, timestamp, magics.int2magic(magic_int)) compare_bytecode_files(bytecode_filename1, bytecode_filename2) return
def verify_file(real_source_filename, real_bytecode_filename): """Compile *real_source_filename* using the running Python interpreter. Then write bytecode out to a new place again using Python's routines. Next load it in using two of our routines. Compare that the code objects there are equal. Next write out the bytecode (using the same Python bytecode writin routine as in step 1. Finally compare the bytecode files. """ tempdir = tempfile.gettempdir() source_filename = os.path.join(tempdir, "testing.py") if not os.path.exists(real_source_filename): return try: f = open(real_source_filename, 'U') except: return codestring = f.read() f.close() codeobject1 = compile(codestring, source_filename,'exec') (version, timestamp, magic_int, codeobject2, is_pypy, source_size) = load_module(real_bytecode_filename) # A hack for PyPy 3.2 if magic_int == 3180+7: magic_int = 48 assert MAGIC == magics.int2magic(magic_int), \ ("magic_int %d vs %d in %s/%s" % (magic_int, magics.magic2int(MAGIC), os.getcwd(), real_bytecode_filename)) bytecode_filename1 = os.path.join(tempdir, "testing1.pyc") dump_compile(codeobject1, bytecode_filename1, timestamp, MAGIC) (version, timestamp, magic_int, codeobject3, is_pypy, source_size) = load_module(real_bytecode_filename, fast_load=not is_pypy) # compare_code(codeobject1, codeobject2) # compare_code(codeobject2, codeobject3) bytecode_filename2 = os.path.join(tempdir, "testing2.pyc") dump_compile(codeobject1, bytecode_filename2, timestamp, magics.int2magic(magic_int)) compare_bytecode_files(bytecode_filename1, bytecode_filename2) return
def compare_code_with_srcfile(pyc_filename, src_filename, verify): """Compare a .pyc with a source code file. If everything is okay, None is returned. Otherwise a string message describing the mismatch is returned. """ (version, timestamp, magic_int, code_obj1, is_pypy, source_size) = load_module(pyc_filename) if magic_int != PYTHON_MAGIC_INT: msg = ( "Can't compare code - Python is running with magic %s, but code is magic %s " % (PYTHON_MAGIC_INT, magic_int)) return msg try: code_obj2 = load_file(src_filename) except SyntaxError as e: # src_filename can be the first of a group sometimes return str(e).replace(src_filename, pyc_filename) cmp_code_objects(version, is_pypy, code_obj1, code_obj2, verify) if verify == "verify-run": try: retcode = call("%s %s" % (sys.executable, src_filename), shell=True) if retcode != 0: return "Child was terminated by signal %d" % retcode pass except OSError as e: return "Execution failed: %s" % e pass return None
def decompile_file( filename: str, outstream=None, showasm=None, showast={}, showgrammar=False, source_encoding=None, mapstream=None, do_fragments=False, ) -> Any: """ decompile Python byte-code file (.pyc). Return objects to all of the deparsed objects found in `filename`. """ filename = check_object_path(filename) code_objects = {} (version, timestamp, magic_int, co, is_pypy, source_size) = load_module(filename, code_objects) if isinstance(co, list): deparsed = [] for con in co: deparsed.append( decompile( version, con, outstream, showasm, showast, timestamp, showgrammar, source_encoding, code_objects=code_objects, is_pypy=is_pypy, magic_int=magic_int, ), mapstream=mapstream, ) else: deparsed = [ decompile( version, co, outstream, showasm, showast, timestamp, showgrammar, source_encoding, code_objects=code_objects, source_size=source_size, is_pypy=is_pypy, magic_int=magic_int, mapstream=mapstream, do_fragments=do_fragments, ) ] co = None return deparsed
def test_load_file(): srcdir = get_srcdir() load_py = osp.realpath(osp.join(srcdir, "..", "xdis", "load.py")) co_file = load_file(load_py) obj_path = check_object_path(load_py) (version, timestamp, magic_int, co_module, pypy, source_size, sip_hash) = load_module(obj_path) if 3.3 <= version <= 3.7: statinfo = os.stat(load_py) assert statinfo.st_size == source_size assert sip_hash is None elif version < 3.3: assert source_size is None, source_size assert sip_hash is None for field in CodeTypeUnionFields: if hasattr(co_file, field): if field == "co_code" and (pypy or IS_PYPY): continue load_file_field = getattr(co_file, field) load_module_field = getattr(co_module, field) assert load_module_field == load_file_field, ( "field %s\nmodule:\n\t%s\nfile:\n\t%s" % (field, load_module_field, load_file_field)) print("ok %s" % field)
def disassemble_file(filename, outstream=sys.stdout, asm_format="classic"): """ disassemble Python byte-code file (.pyc) If given a Python source file (".py") file, we'll try to find the corresponding compiled object. If that fails we'll compile internally for the Python version currently running """ pyc_filename = None try: # FIXME: add whether we want PyPy pyc_filename = check_object_path(filename) version, timestamp, magic_int, co, is_pypy, source_size, sip_hash = load_module( pyc_filename) except: # Hack alert: we're using pyc_filename set as a proxy for whether the filename exists. # check_object_path() will succeed if the file exists. if pyc_filename is None: raise stat = os.stat(filename) source = open(filename, "r").read() co = compile(source, filename, "exec") is_pypy = IS_PYPY magic_int = PYTHON_MAGIC_INT sip_hash = 0 source_size = stat.st_size timestamp = stat.st_mtime version = PYTHON_VERSION else: filename = pyc_filename if asm_format == "header": show_module_header( version, co, timestamp, outstream, is_pypy, magic_int, source_size, sip_hash, show_filename=True, ) else: disco( bytecode_version=version, co=co, timestamp=timestamp, out=outstream, is_pypy=is_pypy, magic_int=magic_int, source_size=source_size, sip_hash=sip_hash, asm_format=asm_format, ) # print co.co_filename return filename, co, version, timestamp, magic_int, is_pypy, source_size, sip_hash
def get_code_obj(dir_compiled, dir_decompiled, pyc_files, output_file=None): code_obj = {} try: code_obj = load_module(os.path.join( dir_compiled, pyc_files[0]), {})[3] except Exception as e: raise e return code_obj
def read_pyc(filename): filename = check_object_path(filename) code_objects = {} (version, timestamp, magic_int, co, is_pypy, source_size) = load_module(filename, code_objects) print(version) print(timestamp) code_obj(co)
def test_basic(self): """Tests xdis.load.load_module""" # We deliberately pick a bytecode that we aren't likely to be running against mod_file = os.path.join(get_srcdir(), '..', 'test', 'bytecode_2.5', '02_complex.pyc') (version, timestamp, magic_int, co, is_pypy, source_size) = load_module(mod_file) self.assertEqual(version, 2.5, "Should have picked up Python version properly") assert co.co_consts == (5j, None), "Code should have a complex constant" mod_file = os.path.join(get_srcdir(), '..', 'test', 'bytecode_3.3', '06_frozenset.pyc') (version, timestamp, magic_int, co, is_pypy, source_size) = load_module(mod_file) expect = (0, None, 'attlist', 'linktype', 'link', 'element', 'Yep', frozenset(['linktype', 'attlist', 'element', 'link'])) self.assertEqual(co.co_consts, expect, "Should handle frozenset")
def compare_code_with_srcfile(pyc_filename, src_filename): """Compare a .pyc with a source code file.""" version, timestamp, magic_int, code_obj1, is_pypy = load_module(pyc_filename) if magic_int != PYTHON_MAGIC_INT: msg = ("Can't compare code - Python is running with magic %s, but code is magic %s " % (PYTHON_MAGIC_INT, magic_int)) return msg code_obj2 = load_file(src_filename) cmp_code_objects(version, is_pypy, code_obj1, code_obj2) return None
def lineoffsets_in_file(filename, toplevel_only=False): obj_path = check_object_path(filename) version, timestamp, magic_int, code, pypy, source_size, sip_hash = load_module( obj_path) if pypy: variant = "pypy" else: variant = None opc = get_opcode_module(version, variant) return LineOffsetInfo(opc, code, not toplevel_only) pass
def copy_magic_into_pyc(input_pyc, output_pyc, src_version, dest_version): """Bytecodes are the same except the magic number, so just change that""" (version, timestamp, magic_int, co, is_pypy, source_size) = load_module(input_pyc) assert version == float(src_version), ( "Need Python %s bytecode; got bytecode for version %s" % (src_version, version)) magic_int = magic2int(magics[dest_version]) write_bytecode_file(output_pyc, co, magic_int) print("Wrote %s" % output_pyc) return
def disassemble_file(filename, outstream=sys.stdout, asm_format=False): """ disassemble Python byte-code file (.pyc) If given a Python source file (".py") file, we'll try to find the corresponding compiled object. """ filename = check_object_path(filename) version, timestamp, magic_int, co, is_pypy, source_size = load_module(filename) disco(version, co, timestamp, outstream, is_pypy, magic_int, source_size, asm_format=asm_format) # print co.co_filename return filename, co, version, timestamp, magic_int
def disassemble_file(filename, outstream=None): """ disassemble Python byte-code file (.pyc) If given a Python source file (".py") file, we'll try to find the corresponding compiled object. """ filename = check_object_path(filename) (version, timestamp, magic_int, co, is_pypy, source_size) = load_module(filename) if type(co) == list: for con in co: disco(version, con, outstream) else: disco(version, co, outstream, is_pypy=is_pypy) co = None
def compare_code_with_srcfile(pyc_filename, src_filename, weak_verify=False): """Compare a .pyc with a source code file.""" (version, timestamp, magic_int, code_obj1, is_pypy, source_size) = load_module(pyc_filename) if magic_int != PYTHON_MAGIC_INT: msg = ("Can't compare code - Python is running with magic %s, but code is magic %s " % (PYTHON_MAGIC_INT, magic_int)) return msg try: code_obj2 = load_file(src_filename) except SyntaxError as e: # src_filename can be the first of a group sometimes return str(e).replace(src_filename, pyc_filename) cmp_code_objects(version, is_pypy, code_obj1, code_obj2, ignore_code=weak_verify) return None
def test_load_file(): co = load_file(__file__) obj_path = check_object_path(__file__) (version, timestamp, magic_int, co2, pypy, source_size) = load_module(obj_path) if (3,3) <= sys.version_info: statinfo = os.stat(__file__) assert statinfo.st_size == source_size else: assert source_size is None if IS_PYPY: assert str(co) == str(co2) else: assert co == co2
def test_load_file(): co = load_file(__file__) obj_path = check_object_path(__file__) (version, timestamp, magic_int, co2, pypy, source_size) = load_module(obj_path) if (3, 3) <= sys.version_info: statinfo = os.stat(__file__) assert statinfo.st_size == source_size else: assert source_size is None if IS_PYPY: assert str(co) == str(co2) else: assert co == co2
def line_number_mapping(pyc_filename, src_filename): (version, timestamp, magic_int, code1, is_pypy, source_size) = load_module(pyc_filename) try: code2 = load_file(src_filename) except SyntaxError as e: return str(e) queue = deque([code1, code2]) mappings = [] opc = get_opcode(version, is_pypy) number_loop(queue, mappings, opc) return sorted(mappings, key=lambda x: x[1])
def test_basic(self): """Basic test of load_file, check_object_path and load_module""" filename = __file__ if filename.endswith('.pyo') or filename.endswith('.pyc'): filename = filename[:-1] co = load_file(filename) obj_path = check_object_path(__file__) if os.path.exists(obj_path): (version, timestamp, magic_int, co2, is_pypy, source_size) = load_module(obj_path) self.assertEqual(sys.version[0:3], str(version)) if IS_PYPY: self.assertTrue("Skipped until we get better code comparison on PYPY") else: for attr in """co_filename co_names co_flags co_argcount co_varnames""".split(): self.assertEqual(getattr(co, attr), getattr(co2, attr), attr) else: self.assertTrue("Skipped because we can't find %s" % obj_path)
def test_basic(self): """Basic test of load_file, check_object_path and load_module""" filename = __file__ if filename.endswith('.pyo') or filename.endswith('.pyc'): filename = filename[:-1] co = load_file(filename) obj_path = check_object_path(__file__) if os.path.exists(obj_path): (version, timestamp, magic_int, co2, is_pypy, source_size, sip_hash) = load_module(obj_path) self.assertEqual(sys.version[0:3], str(version)) if IS_PYPY: self.assertTrue("Skipped until we get better code comparison on PYPY") else: for attr in """co_names co_flags co_argcount co_varnames""".split(): self.assertEqual(getattr(co, attr), getattr(co2, attr), attr) else: self.assertTrue("Skipped because we can't find %s" % obj_path)
def uncompyle_file(filename, outstream=None, showasm=False, showast=False, showgrammar=False): """ decompile Python byte-code file (.pyc) """ filename = check_object_path(filename) code_objects = {} version, timestamp, magic_int, co = load_module(filename, code_objects) if type(co) == list: for con in co: uncompyle(version, con, outstream, showasm, showast, timestamp, showgrammar, code_objects=code_objects) else: uncompyle(version, co, outstream, showasm, showast, timestamp, showgrammar, code_objects=code_objects) co = None
def disassemble_file(filename, outstream=None, native=False): """ disassemble Python byte-code file (.pyc) If given a Python source file (".py") file, we'll try to find the corresponding compiled object. """ if native: xdisassemble_file(filename, outstream) return filename = check_object_path(filename) version, timestamp, magic_int, co, is_pypy = load_module(filename) if type(co) == list: for con in co: disco(version, con, outstream) else: disco(version, co, outstream, is_pypy=is_pypy) co = None
def disassemble_file(filename, outstream=sys.stdout, asm_format=False): """ disassemble Python byte-code file (.pyc) If given a Python source file (".py") file, we'll try to find the corresponding compiled object. """ filename = check_object_path(filename) version, timestamp, magic_int, co, is_pypy, source_size = load_module( filename) disco(version, co, timestamp, outstream, is_pypy, magic_int, source_size, asm_format=asm_format) # print co.co_filename return filename, co, version, timestamp, magic_int
def decompile_file(filename, outstream=None, showasm=None, showast=False, showgrammar=False): """ decompile Python byte-code file (.pyc) """ filename = check_object_path(filename) code_objects = {} (version, timestamp, magic_int, co, is_pypy, source_size) = load_module(filename, code_objects) if type(co) == list: for con in co: decompile(version, con, outstream, showasm, showast, timestamp, showgrammar, code_objects=code_objects, is_pypy=is_pypy, magic_int=magic_int) else: decompile(version, co, outstream, showasm, showast, timestamp, showgrammar, code_objects=code_objects, source_size=source_size, is_pypy=is_pypy, magic_int=magic_int) co = None
def run(self, args): proc = self.proc # FIXME: add a setting for assembler list size listsize = 4 opts = { "highlight": self.settings["highlight"], "start_line": 1, "end_line": None, "start_offset": None, "end_offset": None, "relative_pos": False, "asm_format": self.settings["asmfmt"], } curframe = proc.curframe if curframe: line_no = inspect.getlineno(curframe) opts["start_line"] = line_no - 1 opts["end_line"] = line_no + 1 do_parse = True if len(args) == 2: if args[1].endswith("()"): eval_args = args[1][:-2] else: eval_args = args[1] try: obj = self.proc.eval(eval_args, show_error=False) except: obj = None else: if (inspect.ismethod(obj) or inspect.isfunction(obj) or inspect.isgeneratorfunction(obj) or inspect.isgenerator(obj) or inspect.isframe(obj) or inspect.iscode(obj)): opts["start_offset"] = 0 last_is_offset = is_offset = True start = 0 opts["start_line"] = 0 opts["end_line"] = last = None do_parse = False bytecode_file = None if do_parse: ( bytecode_file, start, is_offset, last, last_is_offset, obj, ) = parse_addr_list_cmd(proc, args, listsize) if bytecode_file is None: return if is_offset: opts["start_offset"] = start else: opts["start_line"] = start if last_is_offset: opts["end_offset"] = last else: opts["end_line"] = last if not obj and (bytecode_file and (not bytecode_file.endswith(".pyo") or bytecode_file.endswith("pyc"))): # bytecode_file may be a source file. Try to tun it into a bytecode file for diassembly. bytecode_file = cache_from_source(bytecode_file) if bytecode_file and Mfile.readable(bytecode_file): self.msg("Reading %s ..." % bytecode_file) ( version, timestamp, magic_int, obj, is_pypy, source_size, sip_hash, ) = load_module(bytecode_file) elif not curframe: self.errmsg("No frame selected.") return else: try: obj = self.proc.eval(args[1]) opts["start_line"] = -1 except: self.errmsg(("Object '%s' is not something we can" + " disassemble.") % args[1]) return # We now have all information. Do the listing. (obj, proc.list_offset) = dis(self.msg, self.msg_nocr, self.section, self.errmsg, obj, **opts) return False
def test_get_jump_targets(): my_dir = osp.dirname(osp.abspath(__file__)) # Python 2.7 code code = bug708901.__code__ # FIXME: Consider loading from a file like below to remove # dependence on running interpreter if PYTHON_VERSION == 2.7: # 19: 0 SETUP_LOOP 23 (to 26) # 3 LOAD_GLOBAL 0 (range) # 6 LOAD_CONST 1 (1) # # 20: 9 LOAD_CONST 2 (10) # 12 CALL_FUNCTION 2 (2 positional, 0 keyword pair) # 15 GET_ITER # >> 16 FOR_ITER 6 (to 25) # 19 STORE_FAST 0 (res) # # 21: 22 JUMP_ABSOLUTE 16 (to 16) # >> 25 POP_BLOCK # >> 26 LOAD_CONST 0 (None) # 29 RETURN_VALUE offset_map = opcode_27.get_jump_target_maps(code, opcode_27) expected = { 3: [0], 6: [3], 9: [6], 12: [9], 15: [12], 16: [15, 22], 19: [16], 22: [19], 25: [16], 26: [0, 25], 29: [26]} assert expected == offset_map offsets = opcode_27.get_jump_targets(code, opcode_27) assert offsets == [26, 25, 16] test_pyc = my_dir +'/../test/bytecode_2.7/01_dead_code.pyc' (version, timestamp, magic_int, co, pypy, source_size) = load_module(test_pyc) code = co.co_consts[0] offsets = opcode_27.get_jump_targets(code, opcode_27) assert [10] == offsets # from xdis.main import disassemble_file # print('\n') # disassemble_file(test_pyc) # 2: 0 LOAD_FAST 0 (a) # 3 POP_JUMP_IF_FALSE 10 (to 10) # # 3: 6 LOAD_CONST 1 (5) # 9 RETURN_VALUE # # 5: >> 10 LOAD_CONST 2 (6) # 13 RETURN_VALUE # 14 LOAD_CONST 0 (None) # 17 RETURN_VALUE offset_map = opcode_27.get_jump_target_maps(code, opcode_27) # print(offset_map) expect = {3: [0], 6: [3], 9: [6], 10: [3], 13: [10], 17: [14]} assert expect == offset_map # Python 3.6 code wordcode # ------------------------ test_pyc = my_dir +'/../test/bytecode_3.6/01_dead_code.pyc' (version, timestamp, magic_int, co, pypy, source_size) = load_module(test_pyc) code = co.co_consts[0] # 2: 0 LOAD_FAST 0 (a) # 2 POP_JUMP_IF_FALSE 8 (to 8) # # 3: 4 LOAD_CONST 1 (5) # 6 RETURN_VALUE # # 5: 8 LOAD_CONST 2 (6) # 10 RETURN_VALUE # 12 LOAD_CONST 0 (None) # 14 RETURN_VALUE offsets = opcode_36.get_jump_targets(code, opcode_36) assert offsets == [8] from xdis.main import disassemble_file print('\n') disassemble_file(test_pyc) offset_map = opcode_36.get_jump_target_maps(code, opcode_36) expect = {2: [0], 4: [2], 6: [4], 8: [2], 10: [8], 14: [12]} assert expect == offset_map
def run(self, args): proc = self.proc dbg_obj = self.core.debugger # We'll use a rough estimate of 4 bytes per instruction and # go off listsize listsize = dbg_obj.settings['listsize'] * 4 curframe = proc.curframe opts = { 'highlight': self.settings['highlight'], 'start_line': 1, 'end_line': None, 'start_offset': None, 'end_offset': None, 'relative_pos': False, } do_parse = True if len(args) == 2: try: obj = self.proc.eval(args[1]) opts['start_offset'] = 0 is_offset = True start = 0 last = dbg_obj.settings['listsize'] * 4 last_is_offset = False if (inspect.ismethod(obj) or inspect.isfunction(obj) or inspect.isgeneratorfunction(obj) or inspect.isgenerator(obj) or inspect.isframe(obj) or inspect.iscode(obj)): do_parse = False except: pass if do_parse: (bytecode_file, start, is_offset, last, last_is_offset, obj) = parse_addr_list_cmd(proc, args, listsize) if bytecode_file is None: return if is_offset: opts['start_offset'] = start else: opts['start_line'] = start if last_is_offset: opts['end_offset'] = last else: opts['end_line'] = last if not (obj or bytecode_file.endswith('.pyo') or bytecode_file.endswith('pyc')): bytecode_file = cache_from_source(bytecode_file) if bytecode_file and Mfile.readable(bytecode_file): self.msg("Reading %s ..." % bytecode_file) (version, timestamp, magic_int, obj, is_pypy, source_size) = load_module(bytecode_file) elif not curframe: self.errmsg("No frame selected.") return else: try: obj = self.proc.eval(args[1]) opts['start_line'] = -1 except: self.errmsg(("Object '%s' is not something we can" + " disassemble.") % args[1]) return # We now have all information. Do the listing. (self.object, proc.list_offset) = Mdis.dis(self.msg, self.msg_nocr, self.section, self.errmsg, obj, **opts) return False
def test_get_jump_targets(): my_dir = osp.dirname(osp.abspath(__file__)) # Python 2.7 code code = bug708901.__code__ # FIXME: Consider loading from a file like below to remove # dependence on running interpreter if PYTHON_VERSION == 2.7: # 19: 0 SETUP_LOOP 23 (to 26) # 3 LOAD_GLOBAL 0 (range) # 6 LOAD_CONST 1 (1) # # 20: 9 LOAD_CONST 2 (10) # 12 CALL_FUNCTION 2 (2 positional, 0 keyword pair) # 15 GET_ITER # >> 16 FOR_ITER 6 (to 25) # 19 STORE_FAST 0 (res) # # 21: 22 JUMP_ABSOLUTE 16 (to 16) # >> 25 POP_BLOCK # >> 26 LOAD_CONST 0 (None) # 29 RETURN_VALUE offset_map = opcode_27.get_jump_target_maps(code, opcode_27) expected = { 3: [0], 6: [3], 9: [6], 12: [9], 15: [12], 16: [15, 22], 19: [16], 22: [19], 25: [16], 26: [0, 25], 29: [26] } assert expected == offset_map offsets = opcode_27.get_jump_targets(code, opcode_27) assert offsets == [26, 25, 16] test_pyc = my_dir + '/../test/bytecode_2.7/01_dead_code.pyc' (version, timestamp, magic_int, co, pypy, source_size) = load_module(test_pyc) code = co.co_consts[0] offsets = opcode_27.get_jump_targets(code, opcode_27) assert [10] == offsets # from xdis.main import disassemble_file # print('\n') # disassemble_file(test_pyc) # 2: 0 LOAD_FAST 0 (a) # 3 POP_JUMP_IF_FALSE 10 (to 10) # # 3: 6 LOAD_CONST 1 (5) # 9 RETURN_VALUE # # 5: >> 10 LOAD_CONST 2 (6) # 13 RETURN_VALUE # 14 LOAD_CONST 0 (None) # 17 RETURN_VALUE offset_map = opcode_27.get_jump_target_maps(code, opcode_27) # print(offset_map) expect = {3: [0], 6: [3], 9: [6], 10: [3], 13: [10], 17: [14]} assert expect == offset_map # Python 3.6 code wordcode # ------------------------ test_pyc = my_dir + '/../test/bytecode_3.6/01_dead_code.pyc' (version, timestamp, magic_int, co, pypy, source_size) = load_module(test_pyc) code = co.co_consts[0] # 2: 0 LOAD_FAST 0 (a) # 2 POP_JUMP_IF_FALSE 8 (to 8) # # 3: 4 LOAD_CONST 1 (5) # 6 RETURN_VALUE # # 5: 8 LOAD_CONST 2 (6) # 10 RETURN_VALUE # 12 LOAD_CONST 0 (None) # 14 RETURN_VALUE offsets = opcode_36.get_jump_targets(code, opcode_36) assert offsets == [8] from xdis.main import disassemble_file print('\n') disassemble_file(test_pyc) offset_map = opcode_36.get_jump_target_maps(code, opcode_36) expect = {2: [0], 4: [2], 6: [4], 8: [2], 10: [8], 14: [12]} assert expect == offset_map
if __name__ == "__main__": parser = argparse.ArgumentParser( description="Unpack and decompile a PyProtected .pyc file") parser.add_argument("filepath", help="Path to the .pyc file") parser.add_argument( "--decode-utf8", action='store_true', help="Try to decode the decompiled utf8 string literals") args = parser.parse_args() filename = args.filepath filebase = filename.split('.')[0] # Load the .pyc file. (version, timestamp, magic_int, stage1_co, pypy, source_size) = load_module(filename) opc = xdis.main.get_opcode(version, pypy) # Unpack the various stages. stage2_co, opc = undo_stage1(stage1_co, opc, version) stage3_co, opc = undo_stage2(stage2_co, opc, version, stage1_co.co_code) unpacked_co = undo_stage3(stage3_co, opc, version) #xdis.main.disco(version, unpacked_co, timestamp) # Decompile the final, cleaned and fixed, code object. f = io.StringIO('') uncompyle6.main.decompile(version, unpacked_co, f) code = f.getvalue() with open('{}.py'.format(filebase), 'w', encoding='utf8') as outf:
def run(self, args): proc = self.proc dbg_obj = self.core.debugger # We'll use a rough estimate of 4 bytes per instruction and # go off listsize listsize = dbg_obj.settings['listsize'] * 4 curframe = proc.curframe opts = {'highlight': self.settings['highlight'], 'start_line': 1, 'end_line': None, 'start_offset': None, 'end_offset': None, 'relative_pos': False, } do_parse = True if len(args) == 2: try: obj=self.proc.eval(args[1]) opts['start_offset'] = 0 is_offset = True start = 0 last = dbg_obj.settings['listsize'] * 4 last_is_offset = False if (inspect.ismethod(obj) or inspect.isfunction(obj) or inspect.isgeneratorfunction(obj) or inspect.isgenerator(obj) or inspect.isframe(obj) or inspect.iscode(obj)): do_parse = False except: pass if do_parse: (bytecode_file, start, is_offset, last, last_is_offset, obj) = parse_addr_list_cmd(proc, args, listsize) if bytecode_file is None: return if is_offset: opts['start_offset'] = start else: opts['start_line'] = start if last_is_offset: opts['end_offset'] = last else: opts['end_line'] = last if not (obj or bytecode_file.endswith('.pyo') or bytecode_file.endswith('pyc')): bytecode_file = cache_from_source(bytecode_file) if bytecode_file and Mfile.readable(bytecode_file): self.msg("Reading %s ..." % bytecode_file) (version, timestamp, magic_int, obj, is_pypy, source_size) = load_module(bytecode_file) elif not curframe: self.errmsg("No frame selected.") return else: try: obj=self.proc.eval(args[1]) opts['start_line'] = -1 except: self.errmsg(("Object '%s' is not something we can" + " disassemble.") % args[1]) return # We now have all information. Do the listing. (self.object, proc.list_offset) = Mdis.dis(self.msg, self.msg_nocr, self.section, self.errmsg, obj, **opts) return False