python文件输出exe文件反汇编_python如何反编译exe文件

"""PyInstaller Extractor v1.8 (Supports pyinstaller 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 : 28-April-2017

Url : https://sourceforge.net/projects/pyinstallerextractor/

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

$ /path/to/exe/python pyinstxtractor.py

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)"""

importosimportstructimportmarshalimportzlibimportsysimportimpimporttypesfrom uuid importuuid4 as uniquenameclassCTOCEntry: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=nameclassPyInstArchive:

PYINST20_COOKIE_SIZE= 24 #For pyinstaller 2.0

PYINST21_COOKIE_SIZE = 24 + 64 #For pyinstaller 2.1+

MAGIC = b'MEI\014\013\012\013\016' #Magic number which identifies pyinstaller

def __init__(self, path):

self.filePath=pathdefopen(self):try:

self.fPtr= open(self.filePath, 'rb')

self.fileSize=os.stat(self.filePath).st_sizeexcept:print('[*] Error: Could not open {0}'.format(self.filePath))returnFalsereturnTruedefclose(self):try:

self.fPtr.close()except:pass

defcheckFile(self):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:

self.pyinstVer= 20 #pyinstaller 2.0

print('[*] Pyinstaller version: 2.0')returnTrue#Check for pyinstaller 2.1+ before bailing out

self.fPtr.seek(self.fileSize -self.PYINST21_COOKIE_SIZE, os.SEEK_SET)

magicFromFile=self.fPtr.read(len(self.MAGIC))if magicFromFile ==self.MAGIC:print('[*] Pyinstaller version: 2.1+')

self.pyinstVer= 21 #pyinstaller 2.1+

returnTrueprint('[*] Error : Unsupported pyinstaller version or not a pyinstaller archive')returnFalsedefgetCArchiveInfo(self):try:if self.pyinstVer == 20:

self.fPtr.seek(self.fileSize-self.PYINST20_COOKIE_SIZE, os.SEEK_SET)#Read CArchive cookie

(magic, lengthofPackage, toc, tocLen, self.pyver) =\

struct.unpack('!8siiii', self.fPtr.read(self.PYINST20_COOKIE_SIZE))elif self.pyinstVer == 21:

self.fPtr.seek(self.fileSize-self.PYINST21_COOKIE_SIZE, os.SEEK_SET)#Read CArchive cookie

(magic, lengthofPackage, toc, tocLen, self.pyver, pylibname) =\

struct.unpack('!8siiii64s', self.fPtr.read(self.PYINST21_COOKIE_SIZE))except:print('[*] Error : The file is not a pyinstaller archive')returnFalseprint('[*] Python version: {0}'.format(self.pyver))#Overlay is the data appended at the end of the PE

self.overlaySize =lengthofPackage

self.overlayPos= self.fileSize -self.overlaySize

self.tableOfContentsPos= self.overlayPos +toc

self.tableOfContentsSize=tocLenprint('[*] Length of package: {0} bytes'.format(self.overlaySize))returnTruedefparseTOC(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

(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))

name= name.decode('utf-8').rstrip('\0')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+=entrySizeprint('[*] Found {0} files in CArchive'.format(len(self.tocList)))defextractFiles(self):print('[*] Beginning extraction...please standby')

extractionDir= os.path.join(os.getcwd(), os.path.basename(self.filePath) + '_extracted')if notos.path.exists(extractionDir):

os.mkdir(extractionDir)

os.chdir(extractionDir)for entry inself.tocList:

basePath=os.path.dirname(entry.name)if basePath != '':#Check if path exists, create if not

if notos.path.exists(basePath):

os.makedirs(basePath)

self.fPtr.seek(entry.position, os.SEEK_SET)

data=self.fPtr.read(entry.cmprsdDataSize)if entry.cmprsFlag == 1:

data=zlib.decompress(data)#Malware may tamper with the uncompressed size

#Comment out the assertion in such a case

assert len(data) == entry.uncmprsdDataSize #Sanity Check

with open(entry.name,'wb') as f:

f.write(data)if entry.typeCmprsData == b'z':

self._extractPyz(entry.name)def_extractPyz(self, name):

dirName= name + '_extracted'

#Create a directory for the contents of the pyz

if notos.path.exists(dirName):

os.mkdir(dirName)

with open(name,'rb') as f:

pyzMagic= f.read(4)assert pyzMagic == b'PYZ\0' #Sanity Check

pycHeader= f.read(4) #Python magic value

if imp.get_magic() !=pycHeader:print('[!] Warning: The script is running in a different python version than the one used to build the executable')print('Run this script in Python{0} to prevent extraction errors(if any) during unmarshalling'.format(self.pyver))

(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 intoc.keys():

(ispkg, pos, length)=toc[key]

f.seek(pos, os.SEEK_SET)

fileName=keytry:#for Python > 3.3 some keys are bytes object some are str object

fileName = key.decode('utf-8')except:pass

#Make sure destination directory exists, ensuring we keep inside dirName

destName = os.path.join(dirName, fileName.replace("..", "__"))

destDirName=os.path.dirname(destName)if notos.path.exists(destDirName):

os.makedirs(destDirName)try:

data=f.read(length)

data=zlib.decompress(data)except:print('[!] Error: Failed to decompress {0}, probably encrypted. Extracting as is.'.format(fileName))

open(destName+ '.pyc.encrypted', 'wb').write(data)continuewith open(destName+ '.pyc', 'wb') as pycFile:

pycFile.write(pycHeader)#Write pyc magic

pycFile.write(b'\0' * 4) #Write timestamp

if self.pyver >= 33:

pycFile.write(b'\0' * 4) #Size parameter added in Python 3.3

pycFile.write(data)defmain():if len(sys.argv) < 2:print('[*] Usage: pyinstxtractor.py ')else:

arch= PyInstArchive(sys.argv[1])ifarch.open():ifarch.checkFile():ifarch.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')returnarch.close()if __name__ == '__main__':

main()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值