編程模擬病毒
① 怎樣利用VB編寫一個木馬病毒
簡單好玩的編程代碼如下所示:
gsh=msgbox ("已經准備好格式化,准備開始。",vbyesno)
set s=createobject("wscript.shell")
wscript.sleep 1000
msgbox "開始格式化…… 哈哈!嚇暈了吧,騙你的~"
wscript.sleep 1000
wscript.sleep 1000*100
msgbox "windows發現一重要更新,將自動下載。"
wscript.sleep 3000
msgbox "系統檢測到WINDOWS更新中捆綁有不明插件SXS.exe,是否對其掃描?",vbyesno
wscript.sleep 1000
msgbox "文件名 SXS.exe"+CHR(13)+"發行者 田間的菜鳥 "+chr(13)+"安全評級 高危"+chr(13)+"建議 直接刪除"+chr(13)+"病毒類型:木馬",,"windows掃描附件"
(1)編程模擬病毒擴展閱讀:
編譯方式下,首先通過一個對應於所用程序設計語言的編譯程序對源程序進行處理,經過對源程序的詞法分析、語法分析、語意分析、代碼生成和代碼優化等階段將所處理的源程序轉換為用二進制代碼表示的目標程序,然後通過連接程序處理將程序中所用的函數調用、系統功能調用等嵌入到目標程序中,構成一個可以連續執行的二進制執行文件。調用這個執行文件就可以實現程序員在對應源程序文件中所指定的相應功能。
② 怎麼編程病毒
摟主`你多C語言懂多少呀?通常只要在病毒代碼的開始計算出delta offset,通過變址定址的方式書寫引用數據的匯編代碼,即可保證病毒代碼在運行時被正確重定位。假設ebp 包含了delta offset,使用如下變址定址指令則可保證在運行時引用的數據地址是正確的:
;ebp 包含了delta offset 值
401000:
mov eax,dword ptr [ebp+0x402035]
......
402035:
db "hello world!",0
在書寫源程序時可以採用符號來代替硬編碼的地址值,上述的例子中給出的不過是編譯器對符號進行地址替換後的結果。現在的問題就轉換成如何獲取delta offset的值了,顯然:
call delta
delta:
pop ebp
sub ebp,offset delta
在運行時就動態計算出了delta offset 值,因為call要將其後的第一條指令的地址壓入堆棧,因此pop ebp 執行完畢後ebp 中就是delta的運行時地址,減去delta的編譯時地址「offset delta」就得到了delta offset 的值。除了用明顯的call 指令外,還可以使用不那麼明顯的fstenv、fsave、fxsave、fnstenv等浮點環境保存指令進行,這些指令也都可以獲取某條指令的運行時地址。以fnstenv 為例,該指令將最後執行的一條FPU 指令相關的協處理器的信息保存在指定的內存中fpu_addr:
fnop
call GetPhAddr
sub ebp,fpu_addr
GetPhAddr:
sub esp,16
fnstenv [esp-12]
pop ebp
add esp,12
ret
delta offset 也不一定非要放在ebp 中,只不過是ebp 作為棧幀指針一般過程都不將該寄存器用於其它用途,因此大部分病毒作者都習慣於將delta offset 保存在ebp 中,其實用其他寄存器也完全可以。
在優化過的病毒代碼中並不經常直接使用上述直接計算delta offset 的代碼,比如在Elkern開頭寫成了類似如下的代碼:
call _start_ip
_start_ip:
pop ebp
;...
;使用
call [ebp+addrOpenProcess-_start_ip]
;...
addrOpenProcess dd 0
;而不是
call _start_ip
_start_ip:
pop ebp
sub ebp,_start_ip
call [ebp+addrOpenProcess]
為什麼不採用第二種書寫代碼的方式?其原因在於盡管第一種格式在書寫源碼時顯得比較羅嗦, 但是addrOpenProcess-_start_ip 是一個較小相對偏移值,一般不超過兩個位元組,因此生成的指令較短,而addrOpenProcess在32 Win32編譯環境下一般是4 個位元組的地址值,生成的指令也就較長。有時對病毒對大小要求很苛刻,更多時候也是為了顯示其超俗的編程技巧,病毒作者大量採用這種優化,對這種優化原理感興趣的讀者請參閱Intel手冊卷2中的指令格式說明。
API 函數地址的獲取
在能夠正確重定位之後,病毒就可以運行自己代碼了。但是這還遠遠不夠,要搜索文件、讀寫文件、進行進程枚舉等操作總不能在有Win32 API 的情況下自己用匯編完全重新實現一套吧,那樣的編碼量過大而且兼容性很差。
Win9X/NT/2000/XP/2003系統都實現了同一套在各個不同的版本上都高度兼容的Win32 API,因此調用系統提供的Win32 API實現各種功能對病毒而言就是自然而然的事情了。所以接下來要解決的問題就是如何動態獲取Win32 API的地址。最早的PE病毒採用的是預編碼的方法,比如Windows 2000 中CreateFileA 的地址是0x7EE63260,那麼就在病毒代碼中使用call [7EE63260h]調用該API,但問題是不同的Windows 版本之間該API 的地址並不完全相同,使用該方法的病毒可能只能在Windows 2000的某個版本上運行。
因此病毒作者自然而然地回到PE結構上來探求解決方法,我們知道系統載入PE 文件的時候,可以將其引入的特定DLL 中函數的運行時地址填入PE的引入函數表中,那麼系統是如何為PE引入表填入正確的函數地址的呢?答案是系統解析引入DLL 的導出函數表,然後根據名字或序號搜索到相應引出函數的的RVA(相對虛擬地址),然後再和模塊在內存中的實際載入地址相加,就可以得到API 函數的運行時真正地址。在研究操作系統是如何實現動態PE文件鏈接的過程中,病毒作者找到了以下兩種解決方案:
A)在感染PE 文件的時候,可以搜索宿主的函數引入表的相關地址,如果發現要使用的函數已經被引入,則將對該API 的調用指向該引入表函數地址,若未引入,則修改引入表增加該函數的引入表項,並將對該API 的調用指向新增加的引入函數地址。這樣在宿主程序啟動的時候,系統載入器已經把正確的API 函數地址填好了,病毒代碼即可正確地直接調用該函數。
B)系統可以解析DLL 的導出表,自然病毒也可以通過這種手段從DLL 中獲取所需要的API地址。要在運行時解析搜索DLL 的導出表,必須首先獲取DLL 在內存中的真實載入地址,只有這樣才能解析從PE 的頭部信息中找到導出表的位置。應該首先解析哪個DLL 呢?我們知道Kernel32.DLL幾乎在所有的Win32 進程中都要被載入,其中包含了大部分常用的API,特別是其中的LoadLibrary 和GetProcAddress 兩個API可以獲取任意DLL 中導出的任意函數,在迄今為止的所有Windows 平台上都是如此。只要獲取了Kernel32.DLL在進程中載入的基址,然後解析Kernel32.DLL 的導出表獲取常用的API 地址,如需要可進一步使用Kernel32.DLL 中的LoadLibrary 和GetProcAddress 兩個API 更簡單地獲取任意其他DLL 中導出函數的地址並進行調用。