Search for pyinstaller magic instead of using a fixed position

This commit is contained in:
extremecoders-re
2021-09-10 12:13:15 +05:30
parent cc69ba88bb
commit b71941d6af
2 changed files with 49 additions and 22 deletions

View File

@@ -2,7 +2,7 @@
PyInstaller Extractor is a Python script to extract the contents of a PyInstaller generated Windows executable file. The contents of the pyz file (usually pyc files) present inside the executable are also extracted. PyInstaller Extractor is a Python script to extract the contents of a PyInstaller generated Windows executable file. The contents of the pyz file (usually pyc files) present inside the executable are also extracted.
The header of the pyc files are automatically fixed so that a Python bytecode decompiler will recognize it. The script can run on both Python 2.x and 3.x. Pyinstaller versions 2.0, 2.1, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 4.0, 4.1, 4.2, 4.3, 4.4 are [tested](https://github.com/extremecoders-re/pyinstxtractor-test-binaries) & supported. Probably will work with other versions too. The header of the pyc files are automatically fixed so that a Python bytecode decompiler will recognize it. The script can run on both Python 2.x and 3.x. Pyinstaller versions 2.0, 2.1, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.5.1 are [tested](https://github.com/extremecoders-re/pyinstxtractor-test-binaries) & supported. Probably will work with other versions too.
This project was originally hosted on [SourceForge](https://sourceforge.net/projects/pyinstallerextractor/). This project was originally hosted on [SourceForge](https://sourceforge.net/projects/pyinstallerextractor/).
@@ -43,9 +43,9 @@ X:\> uncompyle6.exe test.exe_extracted\PYZ-00.pyz_extracted\__future__.pyc
``` ```
## Extracting Linux ELF binaries ## Extracting Linux ELF binaries
Pyinstxtractor can also extract Linux ELF binaries. Please see the [Wiki](https://github.com/extremecoders-re/pyinstxtractor/wiki/Extracting-Linux-ELF-binaries) for more information. Pyinstxtractor can now natively extract Linux ELF binaries without other additional tools.
For other questions, please see the [FAQ](https://github.com/extremecoders-re/pyinstxtractor/wiki/Frequently-Asked-Questions) For other questions and information, please see the [Wiki](https://github.com/extremecoders-re/pyinstxtractor/wiki/Extracting-Linux-ELF-binaries) and the [FAQ](https://github.com/extremecoders-re/pyinstxtractor/wiki/Frequently-Asked-Questions)
## License ## License

View File

@@ -1,5 +1,5 @@
""" """
PyInstaller Extractor v2.0 (Supports pyinstaller 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) PyInstaller Extractor v2.0 (Supports pyinstaller 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 Author : Extreme Coders
E-mail : extremecoders(at)hotmail(dot)com E-mail : extremecoders(at)hotmail(dot)com
Web : https://0xec.blogspot.com Web : https://0xec.blogspot.com
@@ -138,39 +138,63 @@ class PyInstArchive:
def checkFile(self): def checkFile(self):
print('[+] Processing {0}'.format(self.filePath)) print('[+] Processing {0}'.format(self.filePath))
# Check if it is a 2.0 archive
self.fPtr.seek(self.fileSize - self.PYINST20_COOKIE_SIZE, os.SEEK_SET)
magicFromFile = self.fPtr.read(len(self.MAGIC))
if magicFromFile == self.MAGIC: searchChunkSize = 8192
self.pyinstVer = 20 # pyinstaller 2.0 endPos = self.fileSize
print('[+] Pyinstaller version: 2.0') self.cookiePos = -1
return True
# Check for pyinstaller 2.1+ before bailing out if endPos < len(self.MAGIC):
self.fPtr.seek(self.fileSize - self.PYINST21_COOKIE_SIZE, os.SEEK_SET) print('[!] Error : File is too short or truncated')
magicFromFile = self.fPtr.read(len(self.MAGIC)) return False
if magicFromFile == self.MAGIC: 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 b'python' in self.fPtr.read(64):
print('[+] Pyinstaller version: 2.1+') print('[+] Pyinstaller version: 2.1+')
self.pyinstVer = 21 # pyinstaller 2.1+ self.pyinstVer = 21 # pyinstaller 2.1+
return True else:
self.pyinstVer = 20 # pyinstaller 2.0
print('[+] Pyinstaller version: 2.0')
print('[!] Error : Unsupported pyinstaller version or not a pyinstaller archive') return True
return False
def getCArchiveInfo(self): def getCArchiveInfo(self):
try: try:
if self.pyinstVer == 20: if self.pyinstVer == 20:
self.fPtr.seek(self.fileSize - self.PYINST20_COOKIE_SIZE, os.SEEK_SET) self.fPtr.seek(self.cookiePos, os.SEEK_SET)
# Read CArchive cookie # Read CArchive cookie
(magic, lengthofPackage, toc, tocLen, self.pyver) = \ (magic, lengthofPackage, toc, tocLen, self.pyver) = \
struct.unpack('!8siiii', self.fPtr.read(self.PYINST20_COOKIE_SIZE)) struct.unpack('!8siiii', self.fPtr.read(self.PYINST20_COOKIE_SIZE))
elif self.pyinstVer == 21: elif self.pyinstVer == 21:
self.fPtr.seek(self.fileSize - self.PYINST21_COOKIE_SIZE, os.SEEK_SET) self.fPtr.seek(self.cookiePos, os.SEEK_SET)
# Read CArchive cookie # Read CArchive cookie
(magic, lengthofPackage, toc, tocLen, self.pyver, pylibname) = \ (magic, lengthofPackage, toc, tocLen, self.pyver, pylibname) = \
@@ -182,13 +206,16 @@ class PyInstArchive:
print('[+] Python version: {0}'.format(self.pyver)) print('[+] Python version: {0}'.format(self.pyver))
# 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 # Overlay is the data appended at the end of the PE
self.overlaySize = lengthofPackage self.overlaySize = lengthofPackage + tailBytes
self.overlayPos = self.fileSize - self.overlaySize self.overlayPos = self.fileSize - self.overlaySize
self.tableOfContentsPos = self.overlayPos + toc self.tableOfContentsPos = self.overlayPos + toc
self.tableOfContentsSize = tocLen self.tableOfContentsSize = tocLen
print('[+] Length of package: {0} bytes'.format(self.overlaySize)) print('[+] Length of package: {0} bytes'.format(lengthofPackage))
return True return True