前言
渗透测试过程中,工程师会大量使用到各种python脚本,比如在kali中使用searchsploit命令搜索各种漏洞利用脚本,很多都是python语言编写的,我们知道python是一门解释型语言,它是一边解释一边执行的,这就需要运行环境中有python解释器存在,而实际环境中,很多目标靶机是没有python解释器环境的,那么就需要我们将python脚本打包编译成为可以直接在靶机操作系统上运行的二进制文件,再在靶机运行。本文讲解的工具pyinstaller就是这样一款专门用于打包编译python脚本的工具。pyinstaller将python应用程序及其所有依赖库捆绑到一个包中,用户可以运行打包的应用程序,而无需安装python解释器或任何模块。
一、pyinstaller的工作原理
1、编译过程
pyinstaller读取编写好的python脚本,它会分析脚本源码,发现脚本执行所需的所有其他模块和库,然后它收集所有这些文件的副本,包括活动的python解释器,然后将它们与脚本一起放在单个文件夹中,或者可以选择放在单个可执行文件中。
例如,我们要将myscript.py这个文件编译成为二进制文件,其运行过程如下:
pyinstaller myscript.py
- 将myscript.spec文件写在源码脚本的当前目录下
- 在当前目录下创建build文件夹
- 写入log日志文件和工作文件到build目录下
- 在当前目录创建dist文件夹
- 将myscript.py编译生成的二进制文件写入到dist文件夹中
2、各种OS编译
pyinstaller是可以在Windows、macosx和GNU/Linux环境下打包编译的。但是,它不是一个跨平台的编译器:如果要生成一个Windows应用程序exe文件,我们需要在Windows中运行pyinstaller;如果要生成一个GNU/Linux应用程序elf文件,我们需要在GNU/Linux中运行它。pyinstaller已经成功地用于AIX、Solaris、FreeBSD和OpenBSD,但是没有作为持续集成测试的一部分对它们进行测试。
二、pyinstaller安装
由于pyinstaller安装需要很多依赖库,而其又是可以通过PyPI安装的,因此一般建议使用pip安装。
pip install pyinstaller
windows环境下安装如下
C:\Users\13864>pip install pyinstaller
Collecting pyinstaller
Downloading pyinstaller-4.2.tar.gz (3.6 MB)
|████████████████████████████████| 3.6 MB 504 kB/s
Installing build dependencies ... done
Getting requirements to build wheel ... done
Preparing wheel metadata ... done
Collecting altgraph
Downloading altgraph-0.17-py2.py3-none-any.whl (21 kB)
Collecting pywin32-ctypes>=0.2.0
Downloading pywin32_ctypes-0.2.0-py2.py3-none-any.whl (28 kB)
Collecting pefile>=2017.8.1
Downloading pefile-2019.4.18.tar.gz (62 kB)
|████████████████████████████████| 62 kB 408 kB/s
Requirement already satisfied: setuptools in d:\program files\python39\lib\site-packages (from pyinstaller) (49.2.1)
Collecting pyinstaller-hooks-contrib>=2020.6
Downloading pyinstaller_hooks_contrib-2021.1-py2.py3-none-any.whl (181 kB)
|████████████████████████████████| 181 kB ...
Collecting future
Downloading future-0.18.2.tar.gz (829 kB)
|████████████████████████████████| 829 kB 6.8 MB/s
Using legacy 'setup.py install' for pefile, since package 'wheel' is not installed.
Using legacy 'setup.py install' for future, since package 'wheel' is not installed.
Building wheels for collected packages: pyinstaller
Building wheel for pyinstaller (PEP 517) ... done
Created wheel for pyinstaller: filename=pyinstaller-4.2-py3-none-any.whl size=2413076 sha256=255a7f13f0b2b503d19d9cd31830f73d61d12334c5387c6484b67c59f0475058
Stored in directory: c:\users\13864\appdata\local\pip\cache\wheels\b2\10\66\947cc1c6aebd3e270efd8ec60cf7656d5cbad06c0b34eae143
Successfully built pyinstaller
Installing collected packages: future, pywin32-ctypes, pyinstaller-hooks-contrib, pefile, altgraph, pyinstaller
Running setup.py install for future ... done
Running setup.py install for pefile ... done
Successfully installed altgraph-0.17 future-0.18.2 pefile-2019.4.18 pyinstaller-4.2 pyinstaller-hooks-contrib-2021.1 pywin32-ctypes-0.2.0
三、主要选项
-h,--help | 查看该模块的帮助信息 |
---|---|
-F,-onefile | 产生单个的可执行文件 |
-D,--onedir | 产生一个目录(包含多个文件)作为可执行程序 |
-a,--ascii | 不包含 Unicode 字符集支持 |
-d,--debug | 产生 debug 版本的可执行文件 |
-w,--windowed,--noconsolc | 指定程序运行时不显示命令行窗口(仅对 Windows 有效) |
-c,--nowindowed,--console | 指定使用命令行窗口运行程序(仅对 Windows 有效) |
-o DIR,--out=DIR | 指定 spec 文件的生成目录。如果没有指定,则默认使用当前目录来生成 spec 文件 |
-p DIR,--path=DIR | 设置 Python 导入模块的路径(和设置 PYTHONPATH 环境变量的作用相似)。也可使用路径分隔符(Windows 使用分号,Linux 使用冒号)来分隔多个路径 |
-n NAME,--name=NAME | 指定项目(产生的 spec)名字。如果省略该选项,那么第一个脚本的主文件名将作为 spec 的名字 |
实际工作中,我们用的最多的肯定是-F选项,更多详细选项可以参考文章点击这里。
四、实验编译
分别在windows系统和linux系统下编译文件上传脚本upload.py,并测试运行是否正常,源文件如下。
import sys
import getopt
import socket
import time
upfile = ""
def main():
global upfile
target = ""
port = 0
help = False
listen = False
opts,args = getopt.getopt(sys.argv[1:],"t:p:f:lh")
for o,a in opts:
if o == "-t":
target = a
elif o == "-p":
port = int(a)
elif o == "-f":
upfile = a
elif o == "-h":
help = True
elif o == "-l":
listen = True
else:
assert False,"Undefined options"
if help:
usage()
if not listen:
client_handle(target,port)
else:
server_handle(port)
def client_handle(target,port):
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect((target,port))
client.send(upfile.encode("utf-8"))
time.sleep(1)
upload_file(client)
client.close()
def server_handle(port):
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(("0.0.0.0",port))
server.listen(5)
print("[*] Listen on 0.0.0.0 %d" % port)
while True:
client_socket,addr = server.accept()
download_file(client_socket)
def upload_file(client):
f = open(upfile,"rb")
data = f.read()
f.close()
client.send(data)
def download_file(client_socket):
filename = client_socket.recv(1024)
filename = filename.decode()
print("[*] Receive the file %s" % filename)
file_buffer = "".encode("utf-8")
while True:
data = client_socket.recv(1024)
if not data:
break
else:
file_buffer += data
f = open(filename,"wb")
f.write(file_buffer)
f.close()
def usage():
print("help info:python3 upload.py -h")
print("client:python3 upload.py -t [target] -p [port] -f [uploadfile]")
print("server:python3 upload.py -lp [port]")
sys.exit()
if __name__ == '__main__':
main()
总结
pyinstaller是一款简单实用的python脚本打包编译工具,非常适合渗透测试人员使用,虽然简单,但实际工作中会经常遇到,因此需要熟练使用。