美文网首页Python简友广场
基于「ClamAv」通过python进行病毒检测(2)-- p

基于「ClamAv」通过python进行病毒检测(2)-- p

作者: 程序员的一天 | 来源:发表于2020-09-22 12:15 被阅读0次

    介绍pyClamd模块一般用法和常用方法等。

    我们可以使用python来控制clamd,从而操控ClamAv,需要引入第三方模块:pyClamd

    使用pyClamd控制clamd之前,必须先正确安装带有clamdclamav。可以参考之前的文章:

    一、pyClamd简介

    PyClamdclamd的python接口。clamdClamAv杀毒工具的守护进程。

    通过使用pyClamd,我们可以以一种高效而简单的方式,为python程序添加病毒检测功能。

    二、安装pyClamd

    使用pip快速安装:

    pip install pyClamd
    

    模块官方文档:

    http://xael.org/pages/pyclamd-en.html
    

    tip1:英文ok的朋友,可以直接阅读官方文档,当然也可以快速浏览本文后,深入研究官方文档。

    tip2:pypipyClamd最后更新时间是2017年,作者可能没有继续维护这个项目了,且行且珍惜吧~

    三、使用

    3.1 常用方法示例

    pyClamd提供了一些常用方法,包括简单测试clamd是否可用、字节流扫描、文件/文件夹扫描等。下面,我们在python终端来测试这些方法。

    第一步:打开python3命令行终端:
    [root@程序员的一天 home]# python3
    Python 3.7.4 (default, Sep 18 2020, 14:36:11) 
    [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> 
    >>> 
    
    第二步:导入pyClamd:
    >>> import pyclamd
    >>> 
    
    第三步:实例化一个clamd控制对象:
    >>> cd = pyclamd.ClamdAgnostic()
    >>> 
    

    tip:此处为实例化的第一种方式,后文会继续介绍另外两种方式,包括通过网络连接clamd

    第四步:测试clamd是否可连接:

    如果连接成功返回True

    >>> cd = pyclamd.ClamdAgnostic()
    >>> cd.ping()
    True
    >>> 
    
    第五步:查看ClamAv版本:
    >>> cd.version()
    'ClamAV 0.103.0/25929/Sun Sep 13 21:53:46 2020'
    >>> 
    
    第六步:生成测试病毒样本:

    pyClamd提供了一个EICAR()方法,该方法可以快速生成病毒样本,用于测试。我们先来看看样本具体内容:

    >>> cd.EICAR()
    b'X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*'
    >>> 
    

    tip:可以看到输出的是一个python字节串。虽然是病毒样本,但是我们并没有去执行它,所以是无害的,大家不要担心机器中毒!!

    第七步:scan_stream()方法检测bytes流:

    scan_stream()方法用于检测bytes流。

    包括网络字节流,也是可以检测的。比如,在邮箱系统前,对所有的邮件字节流进行检测,查杀恶意邮件。

    我们可以利用EICAR()方法,生成字节流来测试:

    >>> cd.scan_stream(cd.EICAR())
    {'stream': ('FOUND', 'Win.Test.EICAR_HDB-1')}
    >>> 
    >>> cd.scan_stream(b'pythonbytes')
    >>> 
    >>> cd.scan_stream(b'pythonbytes') is None
    True
    >>> 
    

    tip:如果检测到病毒返回字典,否则返回None。

    第八步:scan_file()文件/文件夹扫描:

    scan_file()方法,用于检测文件或者文件夹。

    scan_file()方法,一旦检测到病毒,会结束扫描,立马返回检测到的第一个病毒结果。

    如果,ClamAv采用的源码编译方式安装,那么在ClamAV的源码解压包中有一个test文件夹,里面全部都是ClamAv提供的病毒测试样本:

    [root@程序员的一天 clamAv]# ls
    clamav-0.103.0  clamav-0.103.0.tar.gz
    [root@程序员的一天 clamAv]# 
    [root@程序员的一天 clamAv]# ls clamav-0.103.0/test
    clam.7z           clam_cache_emax.tgz  clam.exe.bz2          clam.impl.zip       clam.mail       clam-pespin.exe  clam-upx.exe     Makefile.am
    clam.arj          clam.chm             clam.exe.html         clam_IScab_ext.exe  clam-mew.exe    clam-petite.exe  clam-v2.rar      Makefile.in
    clam-aspack.exe   clam.d64.zip         clam.exe.mbox.base64  clam_IScab_int.exe  clam.newc.cpio  clam.ppt         clam-v3.rar      README
    clam.bin-be.cpio  clam.ea05.exe        clam.exe.mbox.uu      clam_ISmsi_ext.exe  clam-nsis.exe   clam.sis         clam-wwpack.exe
    clam.bin-le.cpio  clam.ea06.exe        clam.exe.rtf          clam_ISmsi_int.exe  clam.odc.cpio   clam.tar.gz      clam-yc.exe
    clam.bz2.zip      clam.exe             clam.exe.szdd         clam.iso            clam.ole.doc    clam.tnef        clam.zip
    clam.cab          clam.exe.binhex      clam-fsg.exe          clamjol.iso         clam.pdf        clam-upack.exe   Makefile
    [root@程序员的一天 clamAv]# 
    

    tip:不要轻易持续扫描test文件夹,因为全部是病毒样本,扫描会非常慢(也许可以用于测试ClamAv扫描性能)。可以指定其中的具体某个文件测试,或者重新生成新的样本文件测试。

    我们可以用这些文件来测试,也可以利用EICAR()方法,将病毒字节串写入文件,来生成新的样本文件测试。我这里使用生成新文件测试。

    tmp目录下生成EICARNO_EICAR文件:

    >>> void = open('/tmp/EICAR','w').write(cd.EICAR().decode())
    >>> void = open('/tmp/NO_EICAR','w').write('no virus in this file')
    >>> 
    

    tip:这里在/tmp目录下生成了EICARNO_EICAR文件,分别代表病毒样本文件和正常文件。

    scan_file()方法传入具体文件路径,进行文件扫描

    >>> cd.scan_file('/tmp/EICAR')
    {'/tmp/EICAR': ('FOUND', 'Win.Test.EICAR_HDB-1')}
    >>> 
    >>> cd.scan_file('/tmp/NO_EICAR') is None
    True
    >>> 
    

    tip:一旦检测到病毒,立马返回字典,key为具体文件,value为检测结果。否则返回None

    同样,也可以传入一个文件夹路径作为scan_file()方法参数,进行文件夹扫描

    >>> cd.scan_file('/tmp')      
    {'/tmp/EICAR': ('FOUND', 'Win.Test.EICAR_HDB-1')}
    >>> 
    
    

    tip:扫描到第一个病毒文件后,结束扫描,返回结果。

    第九步:contscan_file()文件/文件夹扫描:

    contscan_file()方法,同样用于文件/文件夹扫描。

    scan_file()方法扫描不同的是,contscan_file()方法会在整个文件夹全部扫描完后,返回检测到的所有病毒文件。

    为了方便测试,我们在/tmp目录下再生成一个EICAR_1样本文件。然后扫描/tmp目录:

    >>> void = open('/tmp/EICAR_1','w').write(cd.EICAR().decode())
    >>> 
    >>> cd.contscan_file('/tmp/')
    {'/tmp/EICAR': ('FOUND', 'Win.Test.EICAR_HDB-1'),  '/tmp/EICAR_1': ('FOUND', 'Win.Test.EICAR_HDB-1')}
    >>> 
    >>> cd.scan_file('/tmp') 
    {'/tmp/EICAR': ('FOUND', 'Win.Test.EICAR_HDB-1')}
    >>> 
    

    tip:可以看到scan_file()方法只返回了一个结果,而contscan_file()方法会扫描完整个文件目录后,返回检测到的所有威胁文件。

    同样的,contscan_file()也可以用于单个文件扫描:

    >>> cd.contscan_file('/tmp/EICAR_1')
    {'/tmp/EICAR_1': ('FOUND', 'Win.Test.EICAR_HDB-1')}
    >>> 
    >>> cd.contscan_file('/tmp/EICAR')  
    {'/tmp/EICAR': ('FOUND', 'Win.Test.EICAR_HDB-1')}
    >>> 
    
    

    3.2 pyClamd连接clamd方式总结

    在源码编译安装ClamAv,配置clamd时,我们介绍过:如果要允许clamd和其他应用程序通信,至少启用以下选项之一:

    # 本地套接字通信
    LocalSocket
    # 网络套接字通信
    TCPSocket
    

    比如,这样配置:

    # LocalSocket /tmp/clamd.socket
    TCPSocket 3310
    

    tip:通过tcp套接字,在3310端口通信。

    同样的,pyClamdclamd通信,也对应了这两种方式。

    pyClamd中,提供了两个类,来连接clamd。分别为:

    ClamdUnixSocket()
    ClamdNetworkSocket()
    

    上面我们使用的ClamdAgnostic()是一个自动选择的封装方法。

    tip:需要注意的是,不管哪种方法连接,创建实例化对象后,所有的常用方法都一样。

    接下来,我们分别对它们进行介绍。

    3.2.1、ClamdAgnostic()方法

    ClamdAgnostic()方法,自动选择连接方法。

    ClamdAgnostic()方法,首先尝试使用ClamdUnixSocket连接到clamd。如果失败,尝试
    使用ClamdNetworkSocket连接。最后返回相应的实例化对象。

    在pyclamd.py中ClamdAgnostic()方法定义为:

    tip:pyclamd.pypyClamd库的主要模块,我们甚至可以直接把这个文件放入到程序中,而不使用pip安装pyClamd

    ############################################################################
    
    def ClamdAgnostic():
        """
        Tries to connect to clamd using ClamdUnixSocket or if it fails, tries
        with ClamdNetworkSocket and return the corresponding object.
        Of course, it tries to connect with default settings...
        """
        try:
            # Create object for using unix socket
            cd = ClamdUnixSocket()
        except ConnectionError:
            # if failed, test for network socket
            try:
                cd = ClamdNetworkSocket()
            except ConnectionError:
                raise ValueError("could not connect to clamd server either by unix or network socket")
        return cd
    
    ############################################################################
    

    如果,我们在同一台机器上,通过python控制clamd,那么使用这个方法就足够了。具体实例化示例如下:

    >>> cd = pyclamd.ClamdAgnostic()
    >>> 
    
    3.2.2、ClamdUnixSocket()

    ClamdUnixSocket()使用本地套接字,用于同一台计算机下进程通信。

    需要clamd.conf中配置LocalSocket选项:

    # 指定本地套接字路径
    LocalSocket /tmp/clamd.socket
    

    ClamdUnixSocket()部分源码如下:

    class ClamdUnixSocket(_ClamdGeneric):
        """
        Class for using clamd with an unix socket
        """
        def __init__(self, filename=None, timeout=None):
            """
            Unix Socket Class initialisation
    
            filename (string) : unix socket filename or None to get the socket from /etc/clamav/clamd.conf or /etc/clamd.conf
            timeout (float or None) : socket timeout
            """
    
            # try to get unix socket from clamd.conf
            if filename is None:
                for clamdpath in ['/etc/clamav/clamd.conf', '/etc/clamd.conf']:
                    if os.path.isfile(clamdpath):
                        break
                else:
                    raise ConnectionError('Could not find clamd unix socket from /etc/clamav/clamd.conf or /etc/clamd.conf')
    
    

    可以看到,ClamdUnixSocket()能够接收两个传入参数:

    # 指定本地套接字
    filename
    # 设置连接超时
    timeout
    

    如果,同一台计算机上,我们希望指定本地套接字,来控制clamd,那么可以实例化ClamdUnixSocket()类:

    >>> cd = pyclamd.ClamdUnixSocket(filename='/tmp/clamd.socket', timeout=10)
    >>> 
    

    tip:需要对应的本地套接字存在。

    3.2.3、ClamdNetworkSocket()

    ClamdNetworkSocket()类,允许通过网络套接字来控制clamd

    需要clamd.conf中配置TCPSocket选项:

    # 配置监听端口
    TCPSocket 3310
    # 配置监听地址,默认为0.0.0.0
    TCPAddr 127.0.0.1
    

    ClamdNetworkSocket()部分源码如下:

    class ClamdNetworkSocket(_ClamdGeneric):
        """
        Class for using clamd with a network socket
        """
        def __init__(self, host='127.0.0.1', port=3310, timeout=None):
            """
            Network Class initialisation
            host (string) : hostname or ip address
            port (int) : TCP port
            timeout (float or None) : socket timeout
            """
    

    可以看到,ClamdNetworkSocket()能够接收三个传入参数:

    # 指定clamd监听地址
    host
    # 指定clamd监听端口
    port
    # 设置连接超时
    timeout
    

    通过ClamdNetworkSocket(),我们可以跨机器,通过网络套接字来远程控制clamd。实例化ClamdNetworkSocket()类:

    >>> cd = pyclamd.ClamdNetworkSocket(host='127.0.0.1', port=3310, timeout=10)
    >>> 
    

    到此,pyClamd介绍完毕!
    END.

    我的部分文章会首发在公众号上。微信读者,可以搜一搜:【程序员的一天】,感兴趣的朋友可以关注,支持一下,谢谢!

    每一个关注点赞,都是极大的支持和鼓励。最后,非常感谢阅读。

    相关文章

      网友评论

        本文标题:基于「ClamAv」通过python进行病毒检测(2)-- p

        本文链接:https://www.haomeiwen.com/subject/qohwyktx.html