参考链接:https://laucyun.com/33359ed9f725529ac9b606d054c8459d.html
way1:pyi-archive_viewer 提取pyc,uncompyle6反编译pyc得到py
way2:python-exe-unpacker https://github.com/countercept/python-exe-unpacker
way3:PyInstaller Extractor https://sourceforge.net/projects/pyinstallerextractor/
PyInstaller Extractor (修改添加3.7支持)
1 """ 2 PyInstaller Extractor v1.9 (Supports pyinstaller 3.3, 3.2, 3.1, 3.0, 2.1, 2.0) 3 Author : Extreme Coders 4 E-mail : extremecoders(at)hotmail(dot)com 5 Web : https://0xec.blogspot.com 6 Date : 29-November-2017 7 Url : https://sourceforge.net/projects/pyinstallerextractor/ 8 9 For any suggestions, leave a comment on 10 https://forum.tuts4you.com/topic/34455-pyinstaller-extractor/ 11 12 This script extracts a pyinstaller generated executable file. 13 Pyinstaller installation is not needed. The script has it all. 14 15 For best results, it is recommended to run this script in the 16 same version of python as was used to create the executable. 17 This is just to prevent unmarshalling errors(if any) while 18 extracting the PYZ archive. 19 20 Usage : Just copy this script to the directory where your exe resides 21 and run the script with the exe file name as a parameter 22 23 C:path oexe>python pyinstxtractor.py <filename> 24 $ /path/to/exe/python pyinstxtractor.py <filename> 25 26 Licensed under GNU General Public License (GPL) v3. 27 You are free to modify this source. 28 29 CHANGELOG 30 ================================================ 31 32 Version 1.1 (Jan 28, 2014) 33 ------------------------------------------------- 34 - First Release 35 - Supports only pyinstaller 2.0 36 37 Version 1.2 (Sept 12, 2015) 38 ------------------------------------------------- 39 - Added support for pyinstaller 2.1 and 3.0 dev 40 - Cleaned up code 41 - Script is now more verbose 42 - Executable extracted within a dedicated sub-directory 43 44 (Support for pyinstaller 3.0 dev is experimental) 45 46 Version 1.3 (Dec 12, 2015) 47 ------------------------------------------------- 48 - Added support for pyinstaller 3.0 final 49 - Script is compatible with both python 2.x & 3.x (Thanks to Moritz Kroll @ Avira Operations GmbH & Co. KG) 50 51 Version 1.4 (Jan 19, 2016) 52 ------------------------------------------------- 53 - Fixed a bug when writing pyc files >= version 3.3 (Thanks to Daniello Alto: https://github.com/Djamana) 54 55 Version 1.5 (March 1, 2016) 56 ------------------------------------------------- 57 - Added support for pyinstaller 3.1 (Thanks to Berwyn Hoyt for reporting) 58 59 Version 1.6 (Sept 5, 2016) 60 ------------------------------------------------- 61 - Added support for pyinstaller 3.2 62 - Extractor will use a random name while extracting unnamed files. 63 - For encrypted pyz archives it will dump the contents as is. Previously, the tool would fail. 64 65 Version 1.7 (March 13, 2017) 66 ------------------------------------------------- 67 - Made the script compatible with python 2.6 (Thanks to Ross for reporting) 68 69 Version 1.8 (April 28, 2017) 70 ------------------------------------------------- 71 - Support for sub-directories in .pyz files (Thanks to Moritz Kroll @ Avira Operations GmbH & Co. KG) 72 73 Version 1.9 (November 29, 2017) 74 ------------------------------------------------- 75 - Added support for pyinstaller 3.3 76 - Display the scripts which are run at entry (Thanks to Michael Gillespie @ malwarehunterteam for the feature request) 77 78 """ 79 80 from __future__ import print_function 81 import os 82 import struct 83 import marshal 84 import zlib 85 import sys 86 import imp 87 import types 88 from uuid import uuid4 as uniquename 89 90 91 class CTOCEntry: 92 def __init__(self, position, cmprsdDataSize, uncmprsdDataSize, cmprsFlag, typeCmprsData, name): 93 self.position = position 94 self.cmprsdDataSize = cmprsdDataSize 95 self.uncmprsdDataSize = uncmprsdDataSize 96 self.cmprsFlag = cmprsFlag 97 self.typeCmprsData = typeCmprsData 98 self.name = name 99 100 101 class PyInstArchive: 102 PYINST20_COOKIE_SIZE = 24 # For pyinstaller 2.0 103 PYINST21_COOKIE_SIZE = 24 + 64 # For pyinstaller 2.1+ 104 MAGIC = b'MEI 14 13 12 13 16' # Magic number which identifies pyinstaller 105 106 def __init__(self, path): 107 self.filePath = path 108 109 110 def open(self): 111 try: 112 self.fPtr = open(self.filePath, 'rb') 113 self.fileSize = os.stat(self.filePath).st_size 114 except: 115 print('[*] Error: Could not open {0}'.format(self.filePath)) 116 return False 117 return True 118 119 120 def close(self): 121 try: 122 self.fPtr.close() 123 except: 124 pass 125 126 127 def checkFile(self): 128 print('[*] Processing {0}'.format(self.filePath)) 129 # Check if it is a 2.0 archive 130 self.fPtr.seek(self.fileSize - self.PYINST20_COOKIE_SIZE, os.SEEK_SET) 131 magicFromFile = self.fPtr.read(len(self.MAGIC)) 132 133 if magicFromFile == self.MAGIC: 134 self.pyinstVer = 20 # pyinstaller 2.0 135 print('[*] Pyinstaller version: 2.0') 136 return True 137 138 # Check for pyinstaller 2.1+ before bailing out 139 self.fPtr.seek(self.fileSize - self.PYINST21_COOKIE_SIZE, os.SEEK_SET) 140 magicFromFile = self.fPtr.read(len(self.MAGIC)) 141 142 if magicFromFile == self.MAGIC: 143 print('[*] Pyinstaller version: 2.1+') 144 self.pyinstVer = 21 # pyinstaller 2.1+ 145 return True 146 147 print('[*] Error : Unsupported pyinstaller version or not a pyinstaller archive') 148 return False 149 150 151 def getCArchiveInfo(self): 152 try: 153 if self.pyinstVer == 20: 154 self.fPtr.seek(self.fileSize - self.PYINST20_COOKIE_SIZE, os.SEEK_SET) 155 156 # Read CArchive cookie 157 (magic, lengthofPackage, toc, tocLen, self.pyver) = 158 struct.unpack('!8siiii', self.fPtr.read(self.PYINST20_COOKIE_SIZE)) 159 160 elif self.pyinstVer == 21: 161 self.fPtr.seek(self.fileSize - self.PYINST21_COOKIE_SIZE, os.SEEK_SET) 162 163 # Read CArchive cookie 164 (magic, lengthofPackage, toc, tocLen, self.pyver, pylibname) = 165 struct.unpack('!8siiii64s', self.fPtr.read(self.PYINST21_COOKIE_SIZE)) 166 167 except: 168 print('[*] Error : The file is not a pyinstaller archive') 169 return False 170 171 print('[*] Python version: {0}'.format(self.pyver)) 172 173 # Overlay is the data appended at the end of the PE 174 self.overlaySize = lengthofPackage 175 self.overlayPos = self.fileSize - self.overlaySize 176 self.tableOfContentsPos = self.overlayPos + toc 177 self.tableOfContentsSize = tocLen 178 179 print('[*] Length of package: {0} bytes'.format(self.overlaySize)) 180 return True 181 182 183 def parseTOC(self): 184 # Go to the table of contents 185 self.fPtr.seek(self.tableOfContentsPos, os.SEEK_SET) 186 187 self.tocList = [] 188 parsedLen = 0 189 190 # Parse table of contents 191 while parsedLen < self.tableOfContentsSize: 192 (entrySize, ) = struct.unpack('!i', self.fPtr.read(4)) 193 nameLen = struct.calcsize('!iiiiBc') 194 195 (entryPos, cmprsdDataSize, uncmprsdDataSize, cmprsFlag, typeCmprsData, name) = 196 struct.unpack( 197 '!iiiBc{0}s'.format(entrySize - nameLen), 198 self.fPtr.read(entrySize - 4)) 199 200 name = name.decode('utf-8').rstrip('