>
摘自:http://www.shangshuwu.cn/index.php/Linux安全體系的ClamAV病毒掃描程式
ClamAV是使用廣泛且基於GPL License的開放原始碼的典型殺毒軟體,它支援廣泛的平台,如:Windows、Linux、Unix等作業系統,並被廣泛用於其他應用程式,如:郵件用戶端及伺服器、HTTP病毒掃描代理等。ClamAV原始碼可從http://www.clamav.net 下載。
本章分析了ClamAV的用戶端、伺服器及病毒庫更新升級應用程式,著重闡述了Linux下C語言編程中的許多經典用法。
目錄 [隱藏 ] 1 1 ClamAV概述 2 2 ClamAV編譯安裝及使用 2.1 2.1 clamd後台與clamdscan用戶端 2.2 2.2 clamav-milter郵件掃描器 2.3 2.3 建立病毒庫自動更新 2.4 2.4 libclamav庫API 3 3 clamd伺服器 3.1 3.1 應用程式命令參數分析 3.2 3.2 clamd伺服器入口函數clamd 3.3 3.3 設定系統限制及確定資源使用量 3.4 3.4 設定檔解析 3.5 3.5 log檔案操作 3.6 3.6使用syslog機制輸出調試資訊 3.7 3.7 使用者組及檔案使用權限設定 3.8 3.8 進程後台化 3.9 3.9 利用socket在處理序間通訊 3.9.1 (1)clamd伺服器socket串連 3.9.2 (2) clamd從socket收發資料 3.9.3 (3) socket描述符多工 3.9.4 (4)使用臨時socket傳輸資料 3.10 3.10 子進程執行系統命令及環境變數設定 3.11 3.11線程 3.11.1 (1) 線程建立及線程屬性 3.11.2 (2) 線程結束 3.11.3 (3) 取消線程 3.11.4 (4) 線程的等待 3.11.5 (5) 互斥 3.11.6 (6) 線程資料 3.12 3.12 線程池 3.13 3.13 訊號處理 3.14 3.14 OnAccess掃描病毒線程clamukoth 3.15 3.15 伺服器處理序自動重啟動保護 3.15.1 (1) cron定時機制 3.15.2 (2) clamd後台進程的定期檢查 3.15.3 (3) 運行指令碼clamd 4 4 libclamav庫API 4.1 4.1 病毒庫的裝載 4.2 4.2 病毒掃描 5 5用戶端端應用程式 5.1 5.1 clamdscan用戶端 5.2 5.2 qtclamavclient用戶端應用程式 6 6 病毒庫升級程式freshclam 6.1 6.1 病毒庫定時更新 6.2 6.2 網域名稱資訊查詢 6.2.1 (1) DNS訊息格式及網域名稱查詢函數 6.2.2 (2) 下載管理函數downloadmanager 6.2.3 (3) 網域名稱查詢函數txtquery 6.3 6.3 HTTP協議下載病毒庫檔案 |
1 ClamAV概述
電腦防病毒的方法一般有比較法、檔案校正和法、病毒掃描法和病毒行為監測法。
病毒比較法有長度比較法、內容比較法、記憶體比較法、中斷比較法等,長度比較法是比較檔案的長度是否發生變化,內容比較法是比較檔案的內容是否發生變化及檔案的更新日期是否改變,記憶體比較法是正常系統的記憶體空間是否改變,中斷比較法是比較系統的中斷向量是否被改變。
病毒比較法常常只能說明系統被改變,至於改變系統的程式是否是病毒以及病毒名都很難確定。
檔案校正和法是將正常檔案的內容計算其校正和,並將校正和寫入寫入別的檔案儲存。以後使用檔案時可檢查檢驗和,或定期檢查檔案校正和,看檔案是否發生改變。這種方法只能說明檔案的改變,但無法準確地說明是否是病毒。這種方法常被用來保護系統的註冊表或系統設定檔。
病毒掃描法(Virus Scanner)是用病毒體中的特定字串對被檢測的檔案或記憶體進行掃描。如果在掃描的檔案中病毒的特定字串,就認為檔案感染了字串所代表的病毒。從病毒中提取的特徵字串被用一定的格式組織在一起並加上籤名保護就形成了病毒庫。病毒碼字串或特徵字必須能鑒別病毒且必須能將病毒與正常的非病毒程式區分開,因此,對於病毒掃描法來說,病毒碼碼的提取很關鍵,同時,病毒庫需要不斷的更新,加入新病毒的特徵碼。
病毒掃描法是反病毒軟體最常用的方法,它對已知病毒的掃描非常有效,還能準確的報告病毒的名稱,並可以按病毒的特徵將病毒從感染的檔案中清除。但對未知的病毒卻無法檢測。
病毒程式還常用被加密或壓縮,或放在壓縮的軟體包中,因此,病毒掃描時還應具備相應的解密和解壓縮方法。
病毒行為監測法是根據病毒異常運行行為來判斷程式是否感染病毒。這種方法無法準確確認是否是病毒,但可以預報一些未知病毒。
ClamAV是UNIX下的反病毒工具,用於郵件網關的e-mail掃描。它提供了多線程後台,命令列掃描器和通過Internet的自動庫升級工具。它還包括一個病毒掃描器共用庫。
ClamAV是基於GPL License的開放原始碼軟體,它支援快速掃描、on-access(檔案訪問)掃描,可以檢測超過35000病毒,包括worms(蠕蟲)、trojans(特洛伊木馬)、, Microsoft Office和MacOffice巨集病毒等。它還可掃描包括Zip、RAR (2.0)、Tar等多種格式的壓縮檔,具有強大的郵件掃描器,它還有支援數位簽章的先進資料庫更新器和基於資料庫版本查詢的DNS。
ClamAV工具已在GNU/Linux、Solaris、FreeBSD、OpenBSD 2、AIX 4.1/4.2/4.3/5.1HPUX 11.0、SCO UNIX、IRIX 6.5.20f、Mac OS X、BeOS、Cobalt MIPS boxes、Cygwin、Windows Services for Unix 3.5 (Interix)等作業系統平台上經過測試,但有的作業系統中部分特徵不支援。
ClamAV包括clamscan查病毒應用程式、clamd後台、clamdscan用戶端、libclamav庫、clamav-milter郵件掃描器應用程式幾個部分。ClamAV工具的組成圖如圖1。
clamscan查病毒應用程式可直接在命令列下查殺檔案或目錄的病毒;clamd後台使用libclamav庫尋找病毒,它的一個線程負責on-access查殺病毒;clamdscan用戶端通過clamd後台來查殺病毒,它可以替代clamscan應用程式;libclamav庫提供ClamAV介面函數,被其他應用程式調用來查殺病毒;clamav-milter郵件掃描器與sendmail工具串連,使用clamd來查殺email病毒。
ClamAV使用Dazuko軟體來進行on-access查殺病毒,Dazuko軟體的dazuko核心模組可以使用LSM、系統調用hook和RedirFS模組進行檔案訪問攔截,Dazuko軟體的dazuko庫將攔截的檔案上報給clamd後台,由clamd來掃描病毒。
圖1 ClamAV工具的組成圖 2 ClamAV編譯安裝及使用
編譯ClamAV時應包括zlib庫,很多程式中的壓縮或者解壓縮函數都會用到這個庫。另外還需要包括bzip2和bzip2-devel庫、GNU MP 3庫。GMP包允許freshclam驗證病毒庫的資料簽名,你可在http://www.swox.com/gmp/下載GNU MP。
在Linux下編譯安裝ClamAV的步驟如下:
(1) 下載clamav-0.88.tar.gz
(2) 解壓縮檔案包
# tar xvzf clamav-0.88.tar.gz
(3)進入解壓縮後的clamav目錄
# cd clamav-0.88
(4) 添加使用者組clamav和群組成員clamav
# groupadd clamav # useradd -g clamav -s /bin/false -c "Clam AntiVirus" clamav
(5) 假定你的home目錄是/home/gary,如下配置軟體:
$ ./configure --prefix=/home/gary/clamav --disable-clamav
(6) 編譯,安裝
# make # make install
(7) 在/var/log/目錄下添加兩個log檔案:clam.log和clam-update.log,將所有者改為新加的clamav使用者並設定相應的檔案讀寫權限。
(7) 在/var/log/目錄下添加兩個log檔案:clam.log和clam-update.log,將所有者改為新加的clamav使用者並設定相應的檔案讀寫權限。 # touch /var/log/clam-update.log # chmod 600 /var/log/clam-update.log # chown clamav /var/log/clam-update.log # touch /var/log/clam.log # chmod 600 /var/log/clam.log # chown clamav /var/log/clam.log
(8) 修改/etc/clam.conf將開始的有"Example"的那行用#注釋掉。
#Example
然後在命令列裡輸入:clamd開始病毒精靈。
#clamd
(9) 修改/etc/freshclam.conf將開始的有"Example"的那行用#注釋掉。
#Example
修改UpdateLogFile /var/log/freshclam.log
為UpdateLogFile /var/log/clam-update.log
(10) 用freshclam升級病毒庫:
#freshclam
(11) 查殺目前的目錄下的檔案
clamscan
(12) 查殺目前的目錄所有檔案及目錄。
clamscan -r
(13) 查殺dir目錄,
clamscan dir
(14) 查殺目錄dir下所有檔案及目錄。
clamscan -r dir
(15) 看協助資訊
clamscan --help
2.1 clamd後台與clamdscan用戶端
clamd是使用libclamav庫掃描檔案病毒的多線程後台,它可工作在兩種網路模式下:偵聽在Unix (local) socket和TCP socket。後台由clamd.conf檔案配置。通過設定cron的工作,在每隔一段時間檢查clamd是否啟動運行,並在clamd死亡後自動啟動它。在contrib/clamdwatch/目錄下有指令碼範例。
Clamdscan是一個簡單的clamd用戶端,許多情況下,你可用它替代clamscan,它僅依賴於clamd,雖然它接受與clamscan同樣的命令列選項,但大多數選項被忽略,因為這些選項已在clamd.conf中配置。
clamd的一個重要特徵是基於Dazuko模組進行on-access病毒掃描,即攔截檔案系統的訪問,觸發clamd對訪問檔案進行病毒掃描。Dazuko模組在http://dazuko.org上可用。
clamd中一個名為Clamuko的線程負責與Dazuko進行通訊。
Dazuko模組的編譯方法如下:
$ tar zxpvf dazuko-a.b.c.tar.gz$ cd dazuko-a.b.c$ make dazuko
或者
$ make dazuko-smp (對於smp核心)$ su# insmod dazuko.o# cp dazuko.o /lib/modules/‘uname -r‘/misc# depmod -a
為了Linux啟動時會自動加入這個模組,你可以加"dazuko"條目到/etc/modules中,或者在一些開機檔案中加入命令modprobe dazuko。
你還必須如下建立一個新裝置:
$ cat /proc/devices | grep dazuko254 dazuko$ su -c "mknod -m 600 /dev/dazuko c 254 0"
2.2 clamav-milter郵件掃描器
Nigel Horne公司的clamav-milter是Sendmail工具的非常快速的email掃描器。它用C語言編寫僅依賴於libclamav或clamd。
通過加入下面的行到/etc/mail/sendmail.mc中,就可將clamav-milter與Sendmail串連起來:
INPUT_MAIL_FILTER(‘clmilter’,‘S=local:/var/run/clamav/clmilter.sock,F=, T=S:4m;R:4m’)dnldefine(‘confINPUT_MAIL_FILTERS’, ‘clmilter’)
如果你正以—external運行clamd,檢查clamd.conf中的條目是否有如下:
LocalSocket /var/run/clamav/clamd.sock
接著,按下面方法啟動clamav-milter:
/usr/local/sbin/clamav-milter -lo /var/run/clamav/clmilter.sock
然後重啟動sendmail。
2.3 建立病毒庫自動更新
freshclam是ClamAV的預設資料庫更新器,它可以下面兩種方法工作:
(1) 互動方式:使用命令列的方式進行互動。
(2) 後台進程的方式:它獨立運行不需要幹預。
freshclam由超級使用者啟動,並下降許可權,切換到clamav使用者。freshclam使用database.clamav.net 輪詢調度(round-robin)DNS,自動選擇一個資料庫鏡像。freshclam通過DNS支援資料庫版本驗證,它還支援Proxy 伺服器(與認證一起)、數位簽章和出錯說明。
ClamAV使用freshclam工具,周期地檢查新資料庫的發布,並保持資料庫的更新。
還可以建立freshclam.log檔案,將freshclam.log修改成clamav擁有的log檔案,修改方法如下:
# touch /var/log/freshclam.log# chmod 600 /var/log/freshclam.log# chown clamav /var/log/freshclam.log
編輯freshclam.conf檔案或clamd.conf檔案(如果它們融合在一起),配置UpdateLogFile指向建立的log檔案。
以後台運行freshclam的方法如下:
# freshclam –d
還可以使用cron後台自動定時運行freshclam,方法是加入下面行到crontab中:
N * * * * /usr/local/bin/freshclam --quiet
其中,N應是3~57之間的資料,表示每隔N小時檢查新病毒資料庫。
Proxy 伺服器通過設定檔配置,當HTTPProxyPassword被啟用時,freshclam需要嚴格的許可,方法列出如下:
HTTPProxyServer myproxyserver.comHTTPProxyPort 1234HTTPProxyUsername myusernameHTTPProxyPassword mypass
設定檔中的DatabaseMirror指定了資料庫伺服器,freshclam將嘗試從這個伺服器下載直到最大次數。預設的資料庫鏡像是database.clamav.net,為了從最近的鏡像下載資料庫,你應使用db.xx.clamav.net配置freshclam,xx代表你的國家代碼。例如,如果你的伺服器在"Ascension Island",你應該加下面的行到freshclam.conf中:
DNSDatabaseInfo current.cvd.clamav.netDatabaseMirror db.ac.clamav.netDatabaseMirror database.clamav.net
兩字元國家代碼在http://www.iana.org/cctld/cctld-whois.htm上可尋找到。
2.4 libclamav庫API
每個使用libclamav庫的應用程式必須包括clamav.h標頭檔,方法如下:
#include <clamav.h>
libclamav庫API的使用範例見clamscan/manager.c,下面說明API函數。
(1) 裝載庫
初始化庫的函數列出如下:
int cl_loaddb(const char *filename, struct cl_node **root, unsigned int *signo);int cl_loaddbdir(const char *dirname, struct cl_node **root, unsigned int *signo);const char *cl_retdbdir(void);
其中,函數cl_loaddb裝載選擇的資料庫,函數cl_loaddbdir從目錄dirname裝載所有的資料庫,函數返回預設(寫入程式碼hardcoded)資料庫的目錄路徑。在初始化後,一個內部資料庫代表由參數root傳出,root必須被初始化到NULL,裝載的簽名序號由參數signo傳出,如果不關心簽名計數,參數signo設定為NULL。函數cl_loaddb和cl_loaddbdir裝載成功時,返回0,失敗時,返回一個負數。
函數cl_loaddb用法如下:
...struct cl_node *root = NULL;int ret, signo = 0;ret = cl_loaddbdir(cl_retdbdir(), &root, &signo);
(2) 錯誤處理
使用函數cl_strerror將錯誤碼轉換成可讀的訊息,函數cl_strerror返回一個字串,使用方法如下:
if(ret) { //ret是錯誤碼,為負數 printf("cl_loaddbdir() error: %s/n", cl_strerror(ret)); exit(1);}
(3) 初始化資料庫內部傳輸
函數cl_build被用來初始化資料庫的內部傳輸路徑,函數列出如下:
int cl_build(struct cl_node *root);
函數cl_build使用方法如下:
if((ret = cl_build(root))) printf("cl_build() error: %s/n", cl_strerror(ret));
(4) 資料庫重裝載
保持內部資料庫執行個體的更新是很重要的,你可以使用函數簇cl_stat來檢查資料庫的變化,函數簇cl_stat列出如下:
int cl_statinidir(const char *dirname, struct cl_stat *dbstat);int cl_statchkdir(const struct cl_stat *dbstat);int cl_statfree(struct cl_stat *dbstat);
調用函數cl_statinidir初始化結構cl_stat變數,方法如下:
...struct cl_stat dbstat;memset(&dbstat, 0, sizeof(struct cl_stat));cl_statinidir(dbdir, &dbstat);
僅需要調用函數cl_statchkdir 來檢查資料庫的變化,方法如下:
if(cl_statchkdir(&dbstat) == 1) { //資料庫發生變化 reload_database...; //重裝載資料庫 cl_statfree(&dbstat); cl_statinidir(cl_retdbdir(), &dbstat);}
在重裝載資料庫後,需要重初始化這個結構。
(5) 資料掃描函數
使用下面的函數可以掃描一個buffer、描述符或檔案:
int cl_scanbuff(const