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

我们用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文件的实例代码,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

(0)

相关推荐

  • python反编译学习之字节码详解

    前言 如果你曾经写过或者用过 Python,你可能已经习惯了看到 Python 源代码文件:它们的名称以.Py 结尾.你可能还见过另一种类型的文件是 .pyc 结尾的,它们就是 Python "字节码"文件.(在 Python3 的时候这个 .pyc 后缀的文件不太好找了,它在一个名为__pycache__的子目录下面.).pyc文件可以防止Python每次运行时都重新解析源代码,该文件大大节省了时间. Python是如何工作的 Python 通常被描述为一种解释语言,在这种语言中,你

  • python打包生成的exe文件运行时提示缺少模块的解决方法

    事情是这样的我用打包命令:pyinstaller -F E:\python\clpicdownload\mypython.py打包了一个exe程序,但是运行时提示我缺 少bs4模块然后我就去查pyinstaller的使用方法,找到pyinstaller有一个-p参数: 1.设置导入路径(和使用PYTHONPATH效果相似).可以用路径分割符(Windows使用分号,Linux使用冒号)分割,指定多个目录. 2.也可以使用多个-p参数来设置多个导入路径 然后我找到bs4模块所在的目录E:\pyth

  • Python中.py文件打包成exe可执行文件详解

    前言 最近做了几个简单的爬虫python程序,于是就想做个窗口看看效果. 首先是,窗口的话,以前没怎么接触过,就先考虑用Qt制作简单的ui.这里用前面sinanews的爬虫脚本为例,制作一个获取当天sina头条新闻的窗口. 生成py文件后,运行该py文件,这里窗口我只是随便拖了几个组件进去,主要的text browser用于显示获取到的sinanews. 首先贴一下我的配置 官方下载: Python 3.3.3 PyQt5-5.2.1 for Py3.3(当安装完Python3.3后,安装对应P

  • Windows下将Python文件打包成.EXE可执行文件的方法

    在使用Python做开发的时候,时不时会给自己编写了一些小工具辅助自己的工作,但是由于开发依赖环境问题,多数只能在自己电脑上运行,拿到其它电脑后就没法运行了.这显得很不方便,不符合我们的初衷,那么有没有一种什么办法可以使我们编写好的程序,可以直接在各种windows下运行的呢? 答案是:有的,说到windows大家都能想到( .exe )这个东西吧!没错,就是把Python编写的代码打包成可执行的 exe 文件,直接在系统上运行,这个问题不久完美解决了吗? 下面就来讲讲如何实现,具体如下: 安装

  • Windows中使用wxPython和py2exe开发Python的GUI程序的实例教程

    Python是支持可视化编程,即编写gui程序,你可以用它来编写自己喜欢的桌面程序.使用wxPython来做界面非常的简单,只是不能像C#一样拖动控件,需要自行写代码布局.在完成编写之后,由于直接的py文件不能再没有安装python的电脑上运行,能否有一个打包成在任意电脑都能运行的工具,网上找找发现了py2exe正好可以完成这个功能.wxPython和py2exe都是开源免费软件. 环境配置 wxPython: sourceforge项目页https://sourceforge.net/proj

  • 用PyInstaller把Python代码打包成单个独立的exe可执行文件

    之前就想要把自己的BlogsToWordpress打开成exe了.一直没去弄. 又看到有人提到python打开成exe的问题. 所以打算现在就去试试. 注:此处之所有选用BlogsToWordpress,是因为此python脚本够复杂,依赖的模块够多. 如果这个都搞定了,那么其他单个的python文件,和小python项目的打包,就更不成问题了. 1.先去找找,目前主流有哪几种方法. 找到几个名字 cx_Freeze PyInstaller py2exe 2.关于py2exe和PyInstall

  • 详解Python3.6的py文件打包生成exe

    原文提到的要点: 1. Python版本32位 (文件名为 python-3.6.1.exe) 2. 安装所有用到的模块(原文博主用的是openpyxl,我用到的有urllib中的request\config\data) 3. 下载替换pyinstaller(下载pyinstaller-develop.zip,复制其中的Pyinstaller文件夹) 4. 在控制台生成exe 操作过程记录如下: C:\Python\Scripts>pip install request C:\Python\Sc

  • Python使用dis模块把Python反编译为字节码的用法详解

    dis - Disassembler for Python bytecode,即把python代码反汇编为字节码指令. 使用超级简单: python -m dis xxx.py Python 代码是先被编译为字节码后,再由Python虚拟机来执行字节码, Python的字节码是一种类似汇编指令的中间语言, 一个Python语句会对应若干字节码指令,虚拟机一条一条执行字节码指令, 从而完成程序执行. Python dis 模块支持对Python代码进行反汇编, 生成字节码指令. 当我在网上看到wh

  • Python使用py2exe打包程序介绍

    一.简介 py2exe是一个将python脚本转换成windows上的可独立执行的可执行程序(*.exe)的工具,这样,你就可以不用装python而在windows系统上运行这个可执行程序. py2exe已经被用于创建wxPython,Tkinter,Pmw,PyGTK,pygame,win32com client和server,和其它的独立程序.py2exe是发布在开源许可证下的. 二.安装py2exe 从http://prdownloads.sourceforge.net/py2exe下载并

  • python executemany的使用及注意事项

    使用executemany对数据进行批量插入的话,要注意一下事项: #coding:utf8 conn = MySQLdb.connect(host = "localhost", user = "root", passwd = "123456", db = "myDB") cursor = conn.cursor() sql = "insert into myTable (created_day,name,count

随机推荐