服装设计网站哪个好,网站建设企业宣传,建站公司塔山双喜,php做网站图集Python解包及反编译: PyInstaller Extractoruncompyle6
python exe 反编译
pythonexe解码
1、安装pyinstxtractor
新建一个py文件pyinstxtractor.py,然后将下面的内容拷贝进去 然后就安装好了#xff0c;要使用的时候与待解包的exe文件放在同一文件夹即可
uncompyle6python exe 反编译pythonexe解码1、安装pyinstxtractor新建一个py文件pyinstxtractor.py,然后将下面的内容拷贝进去 然后就安装好了要使用的时候与待解包的exe文件放在同一文件夹即可 PyInstaller Extractor v2.0 (Supports pyinstaller 6.6.0, 6.5.0, 6.4.0, 6.3.0, 6.2.0, 6.1.0, 6.0.0, 5.13.2, 5.13.1, 5.13.0, 5.12.0, 5.11.0, 5.10.1, 5.10.0, 5.9.0, 5.8.0, 5.7.0, 5.6.2, 5.6.1, 5.6, 5.5, 5.4.1, 5.4, 5.3, 5.2, 5.1, 5.0.1, 5.0, 4.10, 4.9, 4.8, 4.7, 4.6, 4.5.1, 4.5, 4.4, 4.3, 4.2, 4.1, 4.0, 3.6, 3.5, 3.4, 3.3, 3.2, 3.1, 3.0, 2.1, 2.0) Author : Extreme Coders E-mail : extremecoders(at)hotmail(dot)com Web : https://0xec.blogspot.com Date : 26-March-2020 Url : https://github.com/extremecoders-re/pyinstxtractor For any suggestions, leave a comment on https://forum.tuts4you.com/topic/34455-pyinstaller-extractor/ This script extracts a pyinstaller generated executable file. Pyinstaller installation is not needed. The script has it all. For best results, it is recommended to run this script in the same version of python as was used to create the executable. This is just to prevent unmarshalling errors(if any) while extracting the PYZ archive. Usage : Just copy this script to the directory where your exe resides and run the script with the exe file name as a parameter C:\\path\\to\\exe\\python pyinstxtractor.py filename $ /path/to/exe/python pyinstxtractor.py filename Licensed under GNU General Public License (GPL) v3. You are free to modify this source. CHANGELOG Version 1.1 (Jan 28, 2014) ------------------------------------------------- - First Release - Supports only pyinstaller 2.0 Version 1.2 (Sept 12, 2015) ------------------------------------------------- - Added support for pyinstaller 2.1 and 3.0 dev - Cleaned up code - Script is now more verbose - Executable extracted within a dedicated sub-directory (Support for pyinstaller 3.0 dev is experimental) Version 1.3 (Dec 12, 2015) ------------------------------------------------- - Added support for pyinstaller 3.0 final - Script is compatible with both python 2.x 3.x (Thanks to Moritz Kroll Avira Operations GmbH Co. KG) Version 1.4 (Jan 19, 2016) ------------------------------------------------- - Fixed a bug when writing pyc files version 3.3 (Thanks to Daniello Alto: https://github.com/Djamana) Version 1.5 (March 1, 2016) ------------------------------------------------- - Added support for pyinstaller 3.1 (Thanks to Berwyn Hoyt for reporting) Version 1.6 (Sept 5, 2016) ------------------------------------------------- - Added support for pyinstaller 3.2 - Extractor will use a random name while extracting unnamed files. - For encrypted pyz archives it will dump the contents as is. Previously, the tool would fail. Version 1.7 (March 13, 2017) ------------------------------------------------- - Made the script compatible with python 2.6 (Thanks to Ross for reporting) Version 1.8 (April 28, 2017) ------------------------------------------------- - Support for sub-directories in .pyz files (Thanks to Moritz Kroll Avira Operations GmbH Co. KG) Version 1.9 (November 29, 2017) ------------------------------------------------- - Added support for pyinstaller 3.3 - Display the scripts which are run at entry (Thanks to Michael Gillespie malwarehunterteam for the feature request) Version 2.0 (March 26, 2020) ------------------------------------------------- - Project migrated to github - Supports pyinstaller 3.6 - Added support for Python 3.7, 3.8 - The header of all extracted pycs are now automatically fixed from __future__ import print_function import os import struct import marshal import zlib import sys from uuid import uuid4 as uniquename class CTOCEntry: def __init__(self, position, cmprsdDataSize, uncmprsdDataSize, cmprsFlag, typeCmprsData, name): self.position position self.cmprsdDataSize cmprsdDataSize self.uncmprsdDataSize uncmprsdDataSize self.cmprsFlag cmprsFlag self.typeCmprsData typeCmprsData self.name name class PyInstArchive: PYINST20_COOKIE_SIZE 24 # For pyinstaller 2.0 PYINST21_COOKIE_SIZE 24 64 # For pyinstaller 2.1 MAGIC bMEI\014\013\012\013\016 # Magic number which identifies pyinstaller def __init__(self, path): self.filePath path self.pycMagic b\0 * 4 self.barePycList [] # List of pycs whose headers have to be fixed def open(self): try: self.fPtr open(self.filePath, rb) self.fileSize os.stat(self.filePath).st_size except: print([!] Error: Could not open {0}.format(self.filePath)) return False return True def close(self): try: self.fPtr.close() except: pass def checkFile(self): print([] Processing {0}.format(self.filePath)) searchChunkSize 8192 endPos self.fileSize self.cookiePos -1 if endPos len(self.MAGIC): print([!] Error : File is too short or truncated) return False while True: startPos endPos - searchChunkSize if endPos searchChunkSize else 0 chunkSize endPos - startPos if chunkSize len(self.MAGIC): break self.fPtr.seek(startPos, os.SEEK_SET) data self.fPtr.read(chunkSize) offs data.rfind(self.MAGIC) if offs ! -1: self.cookiePos startPos offs break endPos startPos len(self.MAGIC) - 1 if startPos 0: break if self.cookiePos -1: print([!] Error : Missing cookie, unsupported pyinstaller version or not a pyinstaller archive) return False self.fPtr.seek(self.cookiePos self.PYINST20_COOKIE_SIZE, os.SEEK_SET) if bpython in self.fPtr.read(64).lower(): print([] Pyinstaller version: 2.1) self.pyinstVer 21 # pyinstaller 2.1 else: self.pyinstVer 20 # pyinstaller 2.0 print([] Pyinstaller version: 2.0) return True def getCArchiveInfo(self): try: if self.pyinstVer 20: self.fPtr.seek(self.cookiePos, os.SEEK_SET) # Read CArchive cookie (magic, lengthofPackage, toc, tocLen, pyver) \ struct.unpack(!8siiii, self.fPtr.read(self.PYINST20_COOKIE_SIZE)) elif self.pyinstVer 21: self.fPtr.seek(self.cookiePos, os.SEEK_SET) # Read CArchive cookie (magic, lengthofPackage, toc, tocLen, pyver, pylibname) \ struct.unpack(!8sIIii64s, self.fPtr.read(self.PYINST21_COOKIE_SIZE)) except: print([!] Error : The file is not a pyinstaller archive) return False self.pymaj, self.pymin (pyver//100, pyver%100) if pyver 100 else (pyver//10, pyver%10) print([] Python version: {0}.{1}.format(self.pymaj, self.pymin)) # Additional data after the cookie tailBytes self.fileSize - self.cookiePos - (self.PYINST20_COOKIE_SIZE if self.pyinstVer 20 else self.PYINST21_COOKIE_SIZE) # Overlay is the data appended at the end of the PE self.overlaySize lengthofPackage tailBytes self.overlayPos self.fileSize - self.overlaySize self.tableOfContentsPos self.overlayPos toc self.tableOfContentsSize tocLen print([] Length of package: {0} bytes.format(lengthofPackage)) return True def parseTOC(self): # Go to the table of contents self.fPtr.seek(self.tableOfContentsPos, os.SEEK_SET) self.tocList [] parsedLen 0 # Parse table of contents while parsedLen self.tableOfContentsSize: (entrySize, ) struct.unpack(!i, self.fPtr.read(4)) nameLen struct.calcsize(!iIIIBc) (entryPos, cmprsdDataSize, uncmprsdDataSize, cmprsFlag, typeCmprsData, name) \ struct.unpack( \ !IIIBc{0}s.format(entrySize - nameLen), \ self.fPtr.read(entrySize - 4)) try: name name.decode(utf-8).rstrip(\0) except UnicodeDecodeError: newName str(uniquename()) print([!] Warning: File name {0} contains invalid bytes. Using random name {1}.format(name, newName)) name newName # Prevent writing outside the extraction directory if name.startswith(/): name name.lstrip(/) if len(name) 0: name str(uniquename()) print([!] Warning: Found an unamed file in CArchive. Using random name {0}.format(name)) self.tocList.append( \ CTOCEntry( \ self.overlayPos entryPos, \ cmprsdDataSize, \ uncmprsdDataSize, \ cmprsFlag, \ typeCmprsData, \ name \ )) parsedLen entrySize print([] Found {0} files in CArchive.format(len(self.tocList))) def _writeRawData(self, filepath, data): nm filepath.replace(\\, os.path.sep).replace(/, os.path.sep).replace(.., __) nmDir os.path.dirname(nm) if nmDir ! and not os.path.exists(nmDir): # Check if path exists, create if not os.makedirs(nmDir) with open(nm, wb) as f: f.write(data) def extractFiles(self): print([] Beginning extraction...please standby) extractionDir os.path.join(os.getcwd(), os.path.basename(self.filePath) _extracted) if not os.path.exists(extractionDir): os.mkdir(extractionDir) os.chdir(extractionDir) for entry in self.tocList: self.fPtr.seek(entry.position, os.SEEK_SET) data self.fPtr.read(entry.cmprsdDataSize) if entry.cmprsFlag 1: try: data zlib.decompress(data) except zlib.error: print([!] Error : Failed to decompress {0}.format(entry.name)) continue # Malware may tamper with the uncompressed size # Comment out the assertion in such a case assert len(data) entry.uncmprsdDataSize # Sanity Check if entry.typeCmprsData bd or entry.typeCmprsData bo: # d - ARCHIVE_ITEM_DEPENDENCY # o - ARCHIVE_ITEM_RUNTIME_OPTION # These are runtime options, not files continue basePath os.path.dirname(entry.name) if basePath ! : # Check if path exists, create if not if not os.path.exists(basePath): os.makedirs(basePath) if entry.typeCmprsData bs: # s - ARCHIVE_ITEM_PYSOURCE # Entry point are expected to be python scripts print([] Possible entry point: {0}.pyc.format(entry.name)) if self.pycMagic b\0 * 4: # if we dont have the pyc header yet, fix them in a later pass self.barePycList.append(entry.name .pyc) self._writePyc(entry.name .pyc, data) elif entry.typeCmprsData bM or entry.typeCmprsData bm: # M - ARCHIVE_ITEM_PYPACKAGE # m - ARCHIVE_ITEM_PYMODULE # packages and modules are pyc files with their header intact # From PyInstaller 5.3 and above pyc headers are no longer stored # https://github.com/pyinstaller/pyinstaller/commit/a97fdf if data[2:4] b\r\n: # pyinstaller 5.3 if self.pycMagic b\0 * 4: self.pycMagic data[0:4] self._writeRawData(entry.name .pyc, data) else: # pyinstaller 5.3 if self.pycMagic b\0 * 4: # if we dont have the pyc header yet, fix them in a later pass self.barePycList.append(entry.name .pyc) self._writePyc(entry.name .pyc, data) else: self._writeRawData(entry.name, data) if entry.typeCmprsData bz or entry.typeCmprsData bZ: self._extractPyz(entry.name) # Fix bare pycs if any self._fixBarePycs() def _fixBarePycs(self): for pycFile in self.barePycList: with open(pycFile, rb) as pycFile: # Overwrite the first four bytes pycFile.write(self.pycMagic) def _writePyc(self, filename, data): with open(filename, wb) as pycFile: pycFile.write(self.pycMagic) # pyc magic if self.pymaj 3 and self.pymin 7: # PEP 552 -- Deterministic pycs pycFile.write(b\0 * 4) # Bitfield pycFile.write(b\0 * 8) # (Timestamp size) || hash else: pycFile.write(b\0 * 4) # Timestamp if self.pymaj 3 and self.pymin 3: pycFile.write(b\0 * 4) # Size parameter added in Python 3.3 pycFile.write(data) def _extractPyz(self, name): dirName name _extracted # Create a directory for the contents of the pyz if not os.path.exists(dirName): os.mkdir(dirName) with open(name, rb) as f: pyzMagic f.read(4) assert pyzMagic bPYZ\0 # Sanity Check pyzPycMagic f.read(4) # Python magic value if self.pycMagic b\0 * 4: self.pycMagic pyzPycMagic elif self.pycMagic ! pyzPycMagic: self.pycMagic pyzPycMagic print([!] Warning: pyc magic of files inside PYZ archive are different from those in CArchive) # Skip PYZ extraction if not running under the same python version if self.pymaj ! sys.version_info.major or self.pymin ! sys.version_info.minor: print([!] Warning: This script is running in a different Python version than the one used to build the executable.) print([!] Please run this script in Python {0}.{1} to prevent extraction errors during unmarshalling.format(self.pymaj, self.pymin)) print([!] Skipping pyz extraction) return (tocPosition, ) struct.unpack(!i, f.read(4)) f.seek(tocPosition, os.SEEK_SET) try: toc marshal.load(f) except: print([!] Unmarshalling FAILED. Cannot extract {0}. Extracting remaining files..format(name)) return print([] Found {0} files in PYZ archive.format(len(toc))) # From pyinstaller 3.1 toc is a list of tuples if type(toc) list: toc dict(toc) for key in toc.keys(): (ispkg, pos, length) toc[key] f.seek(pos, os.SEEK_SET) fileName key try: # for Python 3.3 some keys are bytes object some are str object fileName fileName.decode(utf-8) except: pass # Prevent writing outside dirName fileName fileName.replace(.., __).replace(., os.path.sep) if ispkg 1: filePath os.path.join(dirName, fileName, __init__.pyc) else: filePath os.path.join(dirName, fileName .pyc) fileDir os.path.dirname(filePath) if not os.path.exists(fileDir): os.makedirs(fileDir) try: data f.read(length) data zlib.decompress(data) except: print([!] Error: Failed to decompress {0}, probably encrypted. Extracting as is..format(filePath)) open(filePath .encrypted, wb).write(data) else: self._writePyc(filePath, data) def main(): if len(sys.argv) 2: print([] Usage: pyinstxtractor.py filename) else: arch PyInstArchive(sys.argv[1]) if arch.open(): if arch.checkFile(): if arch.getCArchiveInfo(): arch.parseTOC() arch.extractFiles() arch.close() print([] Successfully extracted pyinstaller archive: {0}.format(sys.argv[1])) print() print(You can now use a python decompiler on the pyc files within the extracted directory) return arch.close() if __name__ __main__: main()2、解包在使用前将需解包的exe与下载的pyinstxtractor.py存入同级文件夹使用命令行输入如下指令, 得到exe的解包文件夹.python pyinstxtractor.py {exe路径} 示例: python pyinstxtractor.py test.exe运行结果解包后文件放在以exe名字_extracted的文件夹中解包后生成your_file.exe_extracted文件夹包含以下关键文件 与.exe同名的.pyc文件如test.pyc struct.pyc文件用于修复文件头 PYZ-00.pyz_extracted文件夹依赖库三、反编译uncompyle6工具使用目前代码还不能用打开会看到基本全是乱码。 在这里需要对在线pyc,pyo,pyd文件等进行反编译成py文件pip安装uncompyle6反编译.pyc为.py方法1uncompyle6推荐Python 3.8以下版本pip install uncompyle62、找到主文件并编译主文件的命名一般与其他库不同有比较明显的开发者个人特征且后缀通常是pyc。 找到之后再同级目录下输入命令行执行uncompyle6.exe {pyc文件} {py文件输出路径}# Unsupported bytecode in file .\dy2.exe_extracted\ui.pyc # Unsupported Python version, 3.12.0, for decompilation # Unsupported Python version, 3.12.0, for decompilation # Unsupported bytecode in file test.exe_extracted_3913\test.pyc # Unsupported Python version, 3.9.0, for decompilationuncompyle6最高仅支持 Python 3.8 的字节码反编译如果你的.pyc是 Python 3.12 编译的版本完全不兼容因此直接提示Unsupported Python version需要使用其他版本方法2pycdc支持高版本Python# 下载并编译pycdc ./pycdc test.pyc test.py 版本问题部署pycdc进行反编译 具体查看https://www.freebuf.com/articles/database/370398.html Linux: git clone https://github.com/zrax/pycdc.git cd pycdc cmake . make 用 pycdc 二进制文件无需 pip直接运行 如果以上方案仍失败直接用无需安装的 pycdc 没找到适配 3.12已修复 CALL_INTRINSIC_1 报错.pyc是 Python 编译后的字节码文件的扩展名此时拿到的并不是源代码还需要使用其他反编译工具将pyc编译成py文件下面是一些常用的将.pyc文件反编译为.py文件的工具以下工具可以配合使用通过测试发现主目录下的.pyc使用uncompyle6可以反编译出源代码但是PYZ-00.pyz_extracted下的就不行需要用pycdc。uncompyle6:一个流行的Python反编译工具支持Python 2和Python 3的.pyc文件推荐。decompyle3: 用于反编译Python 3的.pyc文件的工具。pip install decompyle3 -i https://pypi.org/simple/uncompyle2: 用于反编译Python 2的.pyc文件的工具。pycdc: 一个基于C实现的反编译工具可以将.pyc文件反编译为可读的Python代码适用于更高版本的python推荐。3、解压完成查看源码无乱码一切正常 如果报错# WARNING: Decompyle incomplete# WARNING: Decompyle incomplete 可能有部分代码没有反编成功如果报错可能需要加版本号 【逆向 python】反编译pylnstaller打包的exe文件3.1 pyc到源码pyinstaller在打包的时候会将pyc文件的前8个字节清除所以后期需要自己添加上去前四个字节为python编译的版本后四个字节为时间戳。四个字节的magic number、四个字节的timestamp 所以在这里可以通过struct文件来获取其中的信息再添加到text.pyc文件里面去修复.pyc文件头 问题解包后的.pyc文件缺少魔数Magic Number和时间戳导致反编译失败。解决方案从struct.pyc文件复制前16字节Python 3.x或8字节Python 2.x到目标.pyc文件头部 示例代码Python 3.6# 修复.pyc文件头end如何防止exe被反编译呢 只需在打包命令后面加上--key命令即可例如文章开头的命令可以更换为 pyinstaller -Fw --iconh.ico auto_organize_gui.py --add-datah.ico;/ --key 123456还没有用上的https://wsxk.github.io/pyexe_re/ pydumpck pip install pydumpck 后使用如下命令即可轻松编译 pydumpck xxx.exepython .\pyv2.py .\dy2.exe [] Pyinstaller version: 2.1 [] Python version: 3.12 [] Length of package: 46513414 bytes [] Found 223 files in CArchive [] Beginning extraction...please standby [] Possible entry point: pyiboot01_bootstrap.pyc [] Possible entry point: pyi_rth_multiprocessing.pyc [] Possible entry point: pyi_rth_pyqt6.pyc [] Possible entry point: ui.pyc [] Found 371 files in PYZ archive [] Successfully extracted pyinstaller archive: .\dy2.exe 只能反编译出主函数吗 - 实际上只需要反编译出主意的几个py文件 大部分库也会被同样解包出来不用反编译并不是只能反编译出主函数——**理论上只要是打包进 EXE 的 Python 代码未被编译为二进制扩展所有函数、类、变量、模块都能被反编译出来**只反编译出主函数通常是「操作没找对文件」或「部分代码被特殊处理」导致的。 但是 有的因为版本不同不一定可以完全编译出来还需要一定分析和还原exe代码才能成功运行