1.拿到文件,虚拟机上运行,发现文件格式错误,把后缀改成exe,发现图标变了:

这个小鸭子图标有明显的特征,是PyInstaller封装程序,拿出自己珍藏多年的笔记,开始逆向解封装。

2.首先,找到pyinstxtractor.py文件:

"""
PyInstaller Extractor v2.0 (Supports pyinstaller 3.6, 3.5, 3.4, 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   : 26-March-2020
Url    : https://github.com/extremecoders-re/pyinstxtractor
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 residesand 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)
Version 2.0 (March 26, 2020)
-------------------------------------------------
- Project migrated to github
- Supports pyinstaller 3.6
- Added support for Python 3.7, 3.8
- The header of all extracted pyc's are now automatically fixed
"""from __future__ import print_function
import os
import struct
import marshal
import zlib
import sys
from uuid import uuid4 as uniquename# imp is deprecated in Python3 in favour of importlib
if sys.version_info.major == 3:from importlib.util import MAGIC_NUMBERpyc_magic = MAGIC_NUMBER
else:import imppyc_magic = imp.get_magic()class CTOCEntry:def __init__(self, position, cmprsdDataSize, uncmprsdDataSize, cmprsFlag, typeCmprsData, name):self.position = positionself.cmprsdDataSize = cmprsdDataSizeself.uncmprsdDataSize = uncmprsdDataSizeself.cmprsFlag = cmprsFlagself.typeCmprsData = typeCmprsDataself.name = nameclass PyInstArchive:PYINST20_COOKIE_SIZE = 24  # For pyinstaller 2.0PYINST21_COOKIE_SIZE = 24 + 64  # For pyinstaller 2.1+MAGIC = b'MEI\014\013\012\013\016'  # Magic number which identifies pyinstallerdef __init__(self, path):self.filePath = pathdef open(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))return Falsereturn Truedef close(self):try:self.fPtr.close()except:passdef checkFile(self):print('[+] Processing {0}'.format(self.filePath))# Check if it is a 2.0 archiveself.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.0print('[+] Pyinstaller version: 2.0')return True# Check for pyinstaller 2.1+ before bailing outself.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 Trueprint('[!] Error : Unsupported pyinstaller version or not a pyinstaller archive')return Falsedef 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 Falseprint('[+] Python version: {0}'.format(self.pyver))# Overlay is the data appended at the end of the PEself.overlaySize = lengthofPackageself.overlayPos = self.fileSize - self.overlaySizeself.tableOfContentsPos = self.overlayPos + tocself.tableOfContentsSize = tocLenprint('[+] Length of package: {0} bytes'.format(self.overlaySize))return Truedef parseTOC(self):# Go to the table of contentsself.fPtr.seek(self.tableOfContentsPos, os.SEEK_SET)self.tocList = []parsedLen = 0# Parse table of contentswhile 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 += entrySizeprint('[+] Found {0} files in CArchive'.format(len(self.tocList)))def _writeRawData(self, filepath, data):nm = filepath.replace('\\', os.path.sep).replace('/', os.path.sep).replace('..', '__')nmDir = os.path.dirname(nm)if nmDir != '' and not os.path.exists(nmDir):  # Check if path exists, create if notos.makedirs(nmDir)with open(nm, 'wb') as f:f.write(data)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 notif 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 caseassert len(data) == entry.uncmprsdDataSize  # Sanity Checkif entry.typeCmprsData == b's':# s -> ARCHIVE_ITEM_PYSOURCE# Entry point are expected to be python scriptsprint('[+] Possible entry point: {0}.pyc'.format(entry.name))self._writePyc(entry.name + '.pyc', data)elif entry.typeCmprsData == b'M' or entry.typeCmprsData == b'm':# M -> ARCHIVE_ITEM_PYPACKAGE# m -> ARCHIVE_ITEM_PYMODULE# packages and modules are pyc files with their header's intactself._writeRawData(entry.name + '.pyc', data)else:self._writeRawData(entry.name, data)if entry.typeCmprsData == b'z' or entry.typeCmprsData == b'Z':self._extractPyz(entry.name)def _writePyc(self, filename, data):with open(filename, 'wb') as pycFile:pycFile.write(pyc_magic)  # pyc magicif self.pyver >= 37:  # PEP 552 -- Deterministic pycspycFile.write(b'\0' * 4)  # BitfieldpycFile.write(b'\0' * 8)  # (Timestamp + size) || hashelse:pycFile.write(b'\0' * 4)  # Timestampif self.pyver >= 33:pycFile.write(b'\0' * 4)  # Size parameter added in Python 3.3pycFile.write(data)def _extractPyz(self, name):dirName = name + '_extracted'# Create a directory for the contents of the pyzif not os.path.exists(dirName):os.mkdir(dirName)with open(name, 'rb') as f:pyzMagic = f.read(4)assert pyzMagic == b'PYZ\0'  # Sanity CheckpycHeader = f.read(4)  # Python magic value# Skip PYZ extraction if not running under the same python versionif pyc_magic != pycHeader:print('[!] Warning: This script is running in a different Python version than the one used to build the executable.')print('[!] Please run this script in Python{0} to prevent extraction errors during unmarshalling'.format(self.pyver))print('[!] Skipping pyz extraction')return(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))returnprint('[+] Found {0} files in PYZ archive'.format(len(toc)))# From pyinstaller 3.1+ toc is a list of tuplesif type(toc) == list:toc = dict(toc)for key in toc.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 objectfileName = fileName.decode('utf-8')except:pass# Prevent writing outside dirNamefileName = fileName.replace('..', '__').replace('.', os.path.sep)if ispkg == 1:filePath = os.path.join(dirName, fileName, '__init__.pyc')else:filePath = os.path.join(dirName, fileName + '.pyc')fileDir = os.path.dirname(filePath)if not os.path.exists(fileDir):os.makedirs(fileDir)try:data = f.read(length)data = zlib.decompress(data)except:print('[!] Error: Failed to decompress {0}, probably encrypted. Extracting as is.'.format(filePath))open(filePath + '.encrypted', 'wb').write(data)else:self._writePyc(filePath, 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')returnarch.close()if __name__ == '__main__':main()

python文件,运行之后,在终端输入:

pyinstxtractor.py  <filename>

执行之后,文件对应目录下会出现:

打开对应目录控制台,输入:

python pyinstxtractor.py  D:\elfie.exe

其中D:\elfie.exe为我们需要查看的文件目录。

执行之后:

 这个时候,需要查看Pyinstaller version和反编译的文件,为elfie.pyc。

找到刚才的文件夹下的elife.pyc文件,用python编辑工具打开:

最后一行本来是exec,改成print,执行一下:

 得到的文件的内容, 前面都是一些乱码,看着眼睛真不舒服。。。放到文本编辑器上:

找到了flag的逆序,顺序颠倒一下,得到flag:

flag{Elfie.L0000ves.YOOOO@flare-on.com}

BUUCTF [FlareOn2]elfie相关推荐

  1. BUUCTF reverse题解汇总

    本文是BUUCTF平台reverse题解的汇总 题解均来自本人博客 目录 Page1 Page2 Page3 Page4 Page1 easyre reverse1 reverse2 内涵的软件 新年 ...

  2. [FlareOn2]very_success [FlareOn3]Challenge1

    文章目录 [FlareOn2]very_success 拖入ida 分析sub_401084 脚本 [FlareOn3]Challenge1 拖进ida sub_511260((int)Buffer, ...

  3. BUUCTF的Web真题学习整理(一)

    目录 WEB1-WarmUp (任意文件包含漏洞) WEB2-高明的黑客(fuzz脚本) WEB3-easy_tornado (服务端模板注入(ssti攻击)) WEB4-Hack World(时间盲 ...

  4. BUUCTF寒假刷题-Web

    前言 寒假横向刷题(尽量) BUUCTF

  5. BUUCTF之[Zer0pts2020]Can you guess it? basename函数绕过

    BUUCTF之[Zer0pts2020]Can you guess it? basename函数绕过 题目 后台PHP源码: <?php include 'config.php'; // FLA ...

  6. BUUCTF刷题笔记

    BUUCTF刷题笔记 [极客大挑战 2019]BabySQL 从这句话我们可以看出,这个网站的后台是做了过滤处理的 这个时候我们先用万能密码实验一下看看,是什么类型的SQL注入 输入1',看看返回的结 ...

  7. BUUCTF Quoted-printable编码

    Quoted-printable可译为"可打印字符引用编码",编码常用在电子邮件中,如:Content-Transfer-Encoding: quoted-printable ,它 ...

  8. BUUCTF NewStarCTF一些新知识记录

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一.eazyxor 二.RSA_begin 三.Yesec no drumsticks 四.EzSnake 五.Pyre ...

  9. buuctf Mark loves cat

    buuctf Mark loves cat 打开是个静态页面,源码也无任何有用信息 dirsearch扫描后发现.git泄露 GitHack.py下载得到两个php文件,接下来就是代码审计: flag ...

最新文章

  1. ava.lang.UnsatisfiedLinkError:
  2. 程序员的小天地:注释中的快乐
  3. linux下编译动态和静态链接库
  4. 关于打印机共享的注意事项——又被叫去修电脑了
  5. 如何优化UPS的工作模式为数据中心节省运营成本
  6. 对微软Microsoft Dynamics CRM 的认识
  7. 算法优化:最大字段和,双指针遍历(n^2),分治法(nlogn),动态规划(n)
  8. 简单实现Popup弹出框添加数据
  9. 程序员的自我修养——读《软技能-代码之外的生存指南》笔记
  10. 奥迪公布未来五年计划:将在电动汽车方面投资120亿欧元
  11. [转]Winform不规则窗体的实现心得
  12. unable to verify the first certificate
  13. NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver
  14. 用html设计倒计时秒表,Javascript实现秒表倒计时功能
  15. 软件测试学习书籍8本【经典推荐】
  16. android手写计算器,手写计算器MyScript Calculator
  17. dota2地区服务器延迟,DOTA2 TI8预选赛:南美服务器爆炸比赛延迟
  18. Sigma Function LightOJ - 1336
  19. MFC--获取字符串的像素尺寸
  20. 运用c++编写一个计算三角形周长和面积的程序

热门文章

  1. 运营商大数据:未来移动联通电信三大运营商数据会同步共享吗?
  2. 边缘AI+视频监控,如何助力企业安全生产监管智能化升级?
  3. 关于如何租一个云服务器进行使用
  4. 身份验证绕过漏洞分析
  5. 基于VBA实现Excel十字交叉高亮显示
  6. 挖财获得5000万美元B轮融资 宽带资本和中金领投
  7. ubuntu 18.04 桌面版应用、美化、配置备忘录[更新中]
  8. 百度搜索为什么这么快?
  9. asp mysql 留言本_适用于ASP.NET的留言本(翻译)
  10. 笔记︱联邦学习与隐私计算的案例集锦(一)