Python Scapy和Pyinstaller

时间:2015-05-23 13:32:56

标签: python pyinstaller scapy

我试图使用我用于测试的脚本中的pyinstaller创建简单的可执行文件,所以我不必在服务器上安装所有内容,而不是测试。

#! /usr/bin/env python

from scapy.all import *

sourceport=int(raw_input('Soruce port:'))
destinationport=int(raw_input('Destination port:'))
destinationip=raw_input('Destination IP:')
maxttl=int(raw_input('MAX TTL:'))

for i in range(1,maxttl):
     udptrace = IP(dst=destinationip,ttl=i)/UDP(dport=destinationport,sport=sourceport,len=500)
     received=sr1(udptrace,verbose=0,timeout=2)
     try:
         print received.summary()
     except AttributeError:
         print "** TIMEOUT **"

然后我制作可执行文件:

pyinstaller -F udp.py

然而,当我运行它时,我有以下错误:

Soruce port:500
Destination port:500
Destination IP:4.4.4.4
MAX TTL:3
Traceback (most recent call last):
  File "<string>", line 16, in <module>
NameError: name 'IP' is not defined
user@:~/2/dist$

我花了一些时间研究,但没有找到任何答案。

1 个答案:

答案 0 :(得分:1)

问题

首先,我们需要找出确切的问题。

PyInstaller 手册specifies

  

某些Python脚本以 PyInstaller 无法检测的方式导入模块:例如,使用带有可变数据的__import__()函数。

检查Scapy's source code表明这正是导入各种网络层的方式:

  1. scapy/layers/all.py

    def _import_star(m):
        mod = __import__(m, globals(), locals())
        for k,v in mod.__dict__.iteritems():
            globals()[k] = v
    
    for _l in conf.load_layers:
        log_loading.debug("Loading layer %s" % _l)
        try:
            _import_star(_l)
        except Exception,e:
        log.warning("can't import layer %s: %s" % (_l,e))
    

    请注意,__import__中的每个模块都会调用conf.load_layers

  2. scapy/config.py

    class Conf(ConfClass):
        """This object contains the configuration of scapy."""
         load_layers = ["l2", "inet", "dhcp", "dns", "dot11", "gprs", "hsrp", "inet6", "ir", "isakmp", "l2tp",
                       "mgcp", "mobileip", "netbios", "netflow", "ntp", "ppp", "radius", "rip", "rtp",
                       "sebek", "skinny", "smb", "snmp", "tftp", "x509", "bluetooth", "dhcp6", "llmnr", "sctp", "vrrp",
                       "ipsec" ]
    

    请注意,Conf.load_layers包含"inet"

  3. 文件scapy/layers/inet.py定义IP类,但未在附带的示例中成功导入。

  4. 解决方案

    现在,我们找到了根本原因,让我们看看可以做些什么。

    PyInstaller 手册suggests针对此类导入问题的一些解决方法:

      
        
    • 您可以在 PyInstaller 命令行上提供其他文件。
    •   
    • 您可以在命令行上提供其他导入路径。
    •   
    • 您可以编辑第一次为脚本运行 PyInstaller 时写入的myscript.spec文件。在spec文件中,您可以告诉 PyInstaller 有关脚本特有的代码和数据文件。
    •   
    • 你可以写&#34; hook&#34;通知 PyInstaller 隐藏导入的文件。如果你&#34;挂钩&#34;对于其他用户也可能使用的包的导入,您可以将您的挂钩文件提供给 PyInstaller
    •   

    一些谷歌搜索显示一个合适的&#34;钩子&#34;已添加到此commit的默认 PyInstaller 分发中,该分发引入了文件PyInstaller/hooks/hook-scapy.layers.all.py

    PyInstaller 手册indicates,这些内置的钩子应该自动运行:

      

    总之,&#34; hook&#34; file告诉 PyInstaller 关于特定模块调用的隐藏导入。钩子文件的名称是hook-<module>.py,其中&#34; <module>&#34;是Analysis将找到的脚本或导入模块的名称。您应该浏览 PyInstaller 分发文件夹的hooks文件夹中的现有挂钩,只是为了查看许多支持的导入的名称。

         

    例如hook-cPickle.py是一个钩子文件,告诉模块cPickle使用的隐藏导入。当您的脚本有import cPickle时,Analysis会记录它并检查挂钩文件hook-cPickle.py

    底线

    因此,请确认您正在运行最新版本的 PyInstaller 。如果您无法升级到最新版本,或者它没有包含文件PyInstaller/hooks/hook-scapy.layers.all.py,请使用following content创建它:

    #-----------------------------------------------------------------------------
    # Copyright (c) 2013, PyInstaller Development Team.
    #
    # Distributed under the terms of the GNU General Public License with exception
    # for distributing bootloader.
    #
    # The full license is in the file COPYING.txt, distributed with this software.
    #-----------------------------------------------------------------------------
    
    from PyInstaller.hooks.hookutils import collect_submodules
    
    # The layers to load can be configured using scapy's conf.load_layers.
    #  from scapy.config import conf; print(conf.load_layers)
    # I decided not to use this, but to include all layer modules. The
    # reason is: When building the package, load_layers may not include
    # all the layer modules the program will use later.
    
    hiddenimports = collect_submodules('scapy.layers')