天天看點

基于「ClamAv」通過python進行病毒檢測(2)-- pyClamd控制clamd詳解

介紹pyClamd子產品一般用法和常用方法等。

我們可以使用python來控制

clamd

,進而操控

ClamAv

,需要引入第三方子產品:

pyClamd

使用

pyClamd

控制

clamd

之前,必須先正确安裝帶有

clamd

clamav

。可以參考之前的文章:

  • 基于「ClamAv」通過python進行病毒檢測(0)-- 基礎技術概述
  • 基于「ClamAv」通過python進行病毒檢測(1)-- ClamAv源碼編譯安裝

一、pyClamd簡介

PyClamd

clamd

的python接口。

clamd

ClamAv

殺毒工具的守護程序。

通過使用

pyClamd

,我們可以以一種高效而簡單的方式,為python程式添加病毒檢測功能。

二、安裝pyClamd

使用

pip

快速安裝:

pip install pyClamd
           

子產品官方文檔:

http://xael.org/pages/pyclamd-en.html
           
tip1:英文ok的朋友,可以直接閱讀官方文檔,當然也可以快速浏覽本文後,深入研究官方文檔。
tip2:

pypi

pyClamd

最後更新時間是2017年,作者可能沒有繼續維護這個項目了,且行且珍惜吧~

三、使用

3.1 常用方法示例

pyClamd

提供了一些常用方法,包括簡單測試

clamd

是否可用、位元組流掃描、檔案/檔案夾掃描等。下面,我們在python終端來測試這些方法。

第一步:打開python3指令行終端:

[[email protected]程式員的一天 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

提供的病毒測試樣本:

[[email protected]程式員的一天 clamAv]# ls
clamav-0.103.0  clamav-0.103.0.tar.gz
[[email protected]程式員的一天 clamAv]# 
[[email protected]程式員的一天 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
[[email protected]程式員的一天 clamAv]# 
           
tip:不要輕易持續掃描

test

檔案夾,因為全部是病毒樣本,掃描會非常慢(也許可以用于測試ClamAv掃描性能)。可以指定其中的具體某個檔案測試,或者重新生成新的樣本檔案測試。

我們可以用這些檔案來測試,也可以利用

EICAR()

方法,将病毒位元組串寫入檔案,來生成新的樣本檔案測試。我這裡使用生成新檔案測試。

tmp

目錄下生成

EICAR

NO_EICAR

檔案:

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

/tmp

目錄下生成了

EICAR

NO_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端口通信。

同樣的,

pyClamd

clamd

通信,也對應了這兩種方式。

pyClamd

中,提供了兩個類,來連接配接

clamd

。分别為:

ClamdUnixSocket()
ClamdNetworkSocket()
           

上面我們使用的

ClamdAgnostic()

是一個自動選擇的封裝方法。

tip:需要注意的是,不管哪種方法連接配接,建立執行個體化對象後,所有的常用方法都一樣。

接下來,我們分别對它們進行介紹。

3.2.1、

ClamdAgnostic()

方法

ClamdAgnostic()

方法,自動選擇連接配接方法。

ClamdAgnostic()

方法,首先嘗試使用

ClamdUnixSocket

連接配接到

clamd

。如果失敗,嘗試

使用

ClamdNetworkSocket

連接配接。最後傳回相應的執行個體化對象。

在pyclamd.py中

ClamdAgnostic()

方法定義為:

tip:

pyclamd.py

pyClamd

庫的主要子產品,我們甚至可以直接把這個檔案放入到程式中,而不使用

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.

我的部分文章會首發在公衆号上。微信讀者,可以搜一搜:【程式員的一天】,感興趣的朋友可以關注,支援一下,謝謝!

每一個關注、點贊,都是極大的支援和鼓勵。最後,非常感謝閱讀。