病毒檢測與防毒技術大揭祕7
3.3.升級實現方案及編碼實現
防毒軟體需要及時升級病毒庫,更新特徵碼,以保證能夠識別最新爆發的病毒。為了完成這個操作,需要用到升級伺服器(或者虛擬主機也可以滿足基本需要)。將要升級的檔案,連同新的版本號檔案放置在伺服器固定位置上。軟體中以IP地址或域名的方式訪問這個版本號檔案,獲取最新的版本號,然後跟儲存在使用者端本地的版本號進行對比。如果檢測到伺服器上的版本號更高,表明有新的檔案需要升級。 升級其實是一個很簡單的功能,主要實現的是檔案下載功能,為了能夠在程式中進行版本號判斷以及替換正在執行的檔案等操作,我們將此功能分為兩個部分,一部分寫在應用程式中,一部分寫做一個單獨的模組控制元件。模組中的編碼如下:
主動事件,用於向用戶顯示下載進度: Public Event DownloadProcess(lProgress As Long)
主動事件,下載完檔案後觸發此函式: Public Event DownLoadFinish()
主動事件,錯誤資訊輸出函式: Public Event ErrorMassage(sDescription As String)
控制元件初始化函式: Public Function Init() As Boolean bConnect = True
該函式是第一個由應用程式呼叫的 WinINet 函式。它告訴 Internet DLL 初始化內部資料結構並準備接收應用程式之後的其他呼叫。當應用程式結束使用Internet函式時,應呼叫 InternetCloseHandle 函式來釋放與之相關的資源: lOpen=InternetOpen(scUserAgent,INTERNET_OPEN_TYPE_PRECONFIG,vbNullString,vbNullString,0)
通過一個完整的FTP、Gopher或HTTP網址開啟一個資源: lFile=InternetOpenUrl(lOpen,sUrl,vbNullString,0, INTERNET_FLAG_RELOAD, 0) sBuffer = Space(1024) lBuffer = 1024
從伺服器獲取HTTP請求頭資訊: bRetQueryInfo = HttpQueryInfo(lFile, 21, sBuffer, lBuffer, 0) sBuffer = Mid(sBuffer, 1, lBuffer) End Function
開始下載檔案函式:
Public Function StartUpdate() As Boolean
Dim bBuffer(1 To 1024) As Byte Dim lRet As Long Dim lDownloadSize As Long Dim i As Long
Dim lFileNumber As Long lFileNumber = FreeFile()
下載儲存檔案方式:下載儲存為file.exe.bak下載完成後刪除file.exe,再重新命名 file.exe.bak 為file.exe,這是為了防止file.exe在下載時出現網路錯誤檔案只被寫入一部分資料而引起錯誤:
Dim sTempDownloadFile As String sTempDownloadFile = Trim(sSaveFile) & “.bak” If Dir(sTempDownloadFile) <> “” Then Call DeleteFile(sTempDownloadFile) End If
開啟檔案,儲存下載資料:
Open sTempDownloadFile For Binary Access Write As #lFileNumber Do
讀取被下載檔案內容:
InternetReadFile lFile, bBuffer(1), 1024, lRet If lRet = 1024 Then
將讀取到的資料寫入檔案:
Put #1, , bBuffer Else For i = 1 To lRet Put #1, , bBuffer(i) doEvents Next i end If lDownloadSize = lDownloadSize + lRet
引發下載進度事件,這是為了在下載檔案時讓使用者瞭解下載進展情況,防止使用者以為程式假死:
RaiseEvent DownloadProcess(lDownloadSize)
Loop Until lRet < 1024 Close #lFileNumber
檢查已下載位元組數與要下載檔案大小是否一至,一至說明下載完成了: If lDownloadSize = CLng(GetHeader(“Content-Length”)) Then
下載完成後,刪除原檔案,重新命名下載檔案為原檔名:
If Dir(Trim(sSaveFile)) <> “” Then Call DeleteFile(sSaveFile) End If Sleep 50 If Dir(sSaveFile) = “” Then
重新命名下載的檔案:
Name sTempDownloadFile As sSaveFile End If DoEvents End If
End Function
獲取要下載檔案的資訊: Public Function GetHeader(Optional hdrName As String) As String
Dim sTemp As Long Dim sTemp2 As String Select Case UCase(hdrName)
獲取要下載的檔案大小:
Case “CONTENT-LENGTH” sTemp = InStr(sBuffer, “Content-Length”) sTemp2 = Mid(sBuffer, sTemp + 16, Len(sBuffer)) sTemp = InStr(sTemp2, Chr(0)) GetHeader = CStr(Mid(sTemp2, 1, sTemp - 1)) End Select
End Function
設定屬性,即要下載的檔案的網路地址:
Public Property Let URL(ByVal sInUrl As String) sUrl = sInUrl End Property
以上是控制元件中的編碼,之所以使用控制元件,是為了能夠使用主動事件,方便的與介面互交,比如:即時的顯示下載進度,使使用者能看到下載進行了多少、下載完成後能做出相應的訊息提示。
在程式更新病毒庫或其它程式檔案時,首先會進行如下的方式進行呼叫,獲取網路伺服器檔案中的版本號,如果版本號高於本地版本號,則進行更新,如果與本地版本號一至,則說明本地已經是最新版本,無需更新:
Dim sUpdateFiles As String sUpdateFiles=DetectUpdateFile("http://xxx.cn/update/update.txt")
DetectUpdateFile函式的程式碼如下:
Public Function DetectUpdateFile(sUrl As String) As String
Dim lInternetOpenUrl As Long
Dim lInternetOpen As Long
Dim sTemp As String * 1024
Dim lInternetReadFile As Long
Dim lSize As Long
Dim sContent As String
sContent = vbNullString
lInternetOpen = InternetOpen("update", 1, vbNullString, vbNullString, 0)
lInternetOpenUrl=InternetOpenUrl(lInternetOpen, sUrl, vbNullString, 0, INTERNET_FLAG_NO_CACHE_WRITE, 0)
Do
lInternetReadFile = InternetReadFile(lInternetOpenUrl, sTemp, 1024, lSize)
sContent = sContent & Mid(sTemp, 1, lSize)
Loop While (lSize <> 0)
lInternetReadFile = InternetCloseHandle(lInternetOpenUrl)
升級查詢返回以“Update”開始為標識
If UCase(Left(sContent, 6)) = UCase("Update") Then
DetectUpdateFile = Right(sContent, Len(sContent) - 6)
Else
DetectUpdateFile = ""
End If
End Function
這部分程式碼與上面檔案下載控制元件中的程式碼非常類似,都是用來下載檔案的,不同在於此處下載檔案後會讀取檔案內容。
檔案內容是我們預設好的,本地設定檔案中有版本號,升級時,從伺服器下載版本號檔案並從中讀取內容獲取最新整體版本號,與當前軟體中的整體版本號進行比對,如果網路中的版本號更高,則進行更新,呼叫升級控制元件下載升級檔案。每次升級把設定檔案同時也下載,以同步版本號。
我們設定網路中版本號檔案格式為:“Update”(6位,用於標識是升級校驗檔案)+版本號(6位)+待升級檔案+"$"(結束符)
獲取到檔案資訊後,然後對比版本號,如果伺服器中的版本號更高,則表示有檔案需要下載更新,那麼我們就需要下載檔案。編碼如下:
取得伺服器檔案中的版本號:
Dim lNewWholeVersion As Long lNewWholeVersion = Left(sUpdateFiles, 6) sUpdateFiles = Right(sUpdateFiles, Len(sUpdateFiles) - 6)
取得本地版本號,在這裡Version.ini檔案中存放著本地版本號:
Dim sVersionFile As String sVersionFile = App.Path & “\Version.ini” Dim lOldWholeVersion As Long lOldWholeVersion = ReadIni(sVersionFile, “Version”, “WholeVersion”)
判斷是否需要升級:
If lNewWholeVersion <= lOldWholeVersion Then MsgBox “已是最新版本,無需升級。” End If
如果有持更新內容,從返回內容中獲取要升級的檔案並下載:
Do While Not sUpdateFiles = “” sNewFile = Left(sUpdateFiles, InStr(1, sUpdateFiles, “”))
如果是要下載exe檔案,先用MoveFileEx函式去掉它的執行保護,這樣就不會出現替換正在執行的檔案而產生錯誤的問題:
If InStr(1, LCase(sNewFile), LCase(".exe")) Then Call MoveFileEx(sNewFile, RndChr(6), 1) End If
使用上面寫好的升級控制元件下載檔案,假設控制元件名為UserControlUpdate1:
With UserControlUpdate1
構造檔案下載地址:
.URL = "http://xxx.cn/update/" & sNewFile
.SaveFile = App.Path & "\" & sNewFile
If .Init = True Then
lCurrentFileSize = .GetHeader("Content-Length")
開始下載檔案:
.StartUpdate End If End With
Loop
以上是升級功能的思現思路及編碼方法,在實際軟體的編碼中,除了實現檔案下載的功能,還需要考慮其它輔助因素,比如在下地時,要將檔案顯示在介面中,告訴使用者正在下載哪個檔案,以及顯示下載進度,以給使用者一個更為直觀和親切的使用感受。
注:作者:wing qq:6465660 本書理論及功能、程式碼源於防毒軟體:“Ty2y防毒軟體”,作者授意,文章可自由轉載,只需註明原出處即可,特此說明。