python 反编译exe文件为py文件的实例代码

yipeiwu_com7年前Python基础

我们用pyinstaller把朋友文件打包成exe文件,但有时候我们需要还原,我们可以用pyinstxtractor.py

用法:

python pyinstxtractor.py xxx.exe

之后得到一个这样结构的文件夹

--- xxx.exe_extracted
  -- out00-PYZ.pyz_extracted
   - 各种.pyc文件
  -- out00-PYZ.pyz
  -- some
  -- others
  -- xxx(注意这些都是没后缀的)

然后再终端pip install uncompyle安装uncompyle,

然后就可以使用啦

uncompyle6 input.pyc > output.py

把pyc文件转换为py文件,希望对大家有帮助

最后贴上pyinstxtractor.py的代码

"""
PyInstaller Extractor v1.9 (Supports pyinstaller 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  : 29-November-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 <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)
"""
from __future__ import print_function
import os
import struct
import marshal
import zlib
import sys
import imp
import types
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 = b'MEI\014\013\012\013\016' # Magic number which identifies pyinstaller
  def __init__(self, path):
    self.filePath = path
  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))
    # 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')
      return True
    # 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+
      return True
    print('[*] Error : Unsupported pyinstaller version or not a pyinstaller archive')
    return False
  def getCArchiveInfo(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')
      return False
    print('[*] 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 = tocLen
    print('[*] Length of package: {0} bytes'.format(self.overlaySize))
    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))
      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 += entrySize
    print('[*] Found {0} files in CArchive'.format(len(self.tocList)))
  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:
      basePath = os.path.dirname(entry.name)
      if basePath != '':
        # Check if path exists, create if not
        if not os.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's':
        print('[+] Possible entry point: {0}'.format(entry.name))
      elif entry.typeCmprsData == b'z' or 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 not os.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 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 = 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 not os.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)
          continue
        with 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)
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()

总结

以上所述是小编给大家介绍的python 反编译exe文件为py文件的实例代码,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

相关文章

详解PyCharm配置Anaconda的艰难心路历程

详解PyCharm配置Anaconda的艰难心路历程

在安装好pycharm后,想着anaconda中的类库会比较全,就想着将anaconda配置到pycharm中,这样可以避免以后下载各种类库。 第一步就是要下载并安装anaconda,在...

python 查找字符串是否存在实例详解

python中查找指定的字符串的方法如下: code #查询 def selStr(): sStr1 = 'jsjtt.com' sStr2 = 'com' #inde...

Python 一行代码能实现丧心病狂的功能

Python 一行代码能实现丧心病狂的功能

手头有 109 张头部 CT 的断层扫描图片,我打算用这些图片尝试头部的三维重建。基础工作之一,就是要把这些图片数据读出来,组织成一个三维的数据结构(实际上是四维的,因为每个像素有 RG...

python3实现字符串的全排列的方法(无重复字符)

最近在学一些基础的算法,发现我的数学功底太差劲了,特别是大学的这一部分,概率论、线性代数、高数等等,这些大学学的我是忘得一干二净(我当时学的时候也不见得真的懂),导致现在学习算法,非常的...

python实现登陆知乎获得个人收藏并保存为word文件

这个程序其实很早之前就完成了,一直没有发出了,趁着最近不是很忙就分享给大家. 使用BeautifulSoup模块和urllib2模块实现,然后保存成word是使用python docx模...