编写病毒的方法介绍
编写病毒的方法介绍
教授如何编写病毒是一个很敏感的话题。这会不会引起病毒泛滥?到底有没有学习编写病毒的必要?这就牵涉到一个问题,引起病毒泛滥的原因到底是什么?是因为会编写病毒的人太多还是因为懂得对付病毒的人太少?当骗子到处横行,我们到底应该让每个人都懂得骗子行骗的手段以防止受骗还是应该隐瞒骗子的行径呢?使人们懂法是否是教唆人们违法呢?
一、怎样编写主引导记录和BOOT区病毒
什么是主引导记录?主引导记录存放在何处?主引导记录是用来装载硬盘活动分区的BOOT扇区的程序。主引导记录存放于硬盘0道0柱面1扇区,长度最大为一个扇区。从硬盘启动时,BIOS引导程序将主引导记录装载至0:7C00H处,然后将控制权交给主引导记录。一般的,BOOT区病毒存在于软盘。因为软盘不存在分区,可以将其看成为软盘的主引导记录。软盘的BOOT区存在于其0道0面1扇区,长度为一个扇区。
一般的主引导记录病毒的原理。
一般的,这类病毒是把原来的主引导记录保存后用自己的程序替代掉原来的主引导记录。启动时,当病毒体得到控制权,在做完了自己的处理后,病毒将保存的原主引导记录读入0:7C00,然后将控制权交给原主引导记录进行启动。这类病毒对硬盘的感染一般是在用带毒软盘启动的时候,对软盘的感染一般是在当系统带毒时对软盘操作时。
编写主引导记录病毒需要了解的几点
1、用什么来保存原始主引导记录。
众所周知的,文件型病毒用以保存被感染修改的部分是文件。引导型病毒是否也可以使用文件存储被覆盖的引导记录呢?答案是否定的。由于主引导记录病毒先于操作系统执行,因而不能使用操作系统的功能调用,而只能使用BIOS的功能调用或者使用直接的IO设计。一般的,使用BIOS的磁盘服务将主引导记录保存于绝对的扇区内。由于0道0面2扇区是保留扇区,因而通常使用它来保存。
2、需要掌握的BIOS磁盘服务功能调用。
INT 13H 子功能 02H 读扇区
其调用方法为:
入口为:
AH=02H
AL=读入的扇区数
CH=磁道号
CL=扇区号(从1开始)
DH=头号
DL=物理驱动器号
ES:BX-->要填充的缓冲区
返回为: 当CF置位时表示调用失败
AH=状态
AL=实际读入的扇区数
INT 13H 子功能03H写扇区
其调用方法为:
入口为:
AH=03H
AL=写入的扇区数
CH=磁道号
CL=扇区号(从1开始)
DH=头号
DL=物理驱动器号
ES:BX-->缓冲区
返回为: 当CF置位时表示调用失败
AH=状态
AL=实际写入的扇区数
3。这类病毒通过什么来进行感染
通常的,这类病毒通过截获中断向量INT 13H 进行系统监控。当存在有关于软盘或硬盘的磁盘读写时, 病毒将检测其是否干净,若尚未感染则感染之。
4。驻留的位置
通常病毒通过修改基本内存的大小来获取自己驻留的空间。基本内存大小的存储位置在40H:13H,单位为KB。病毒体存在于最后的几K内存中。
==========================================================
二、如何编写DOS病毒?
自磁芯大战以来,病毒从DOS时代的病毒发展到WINDOS系统的病毒,从变形、加密到智能化现在的病毒是让人防不胜防,现在网络上病毒大肆泛滥,给人们带来的很大的危害,本人在此仅做抛砖引玉,介绍病毒的原理,希望大家共同研究交流。(本文参考了网络上的部分文章,并引用了部分内容。)
要学DOS下的病毒,首先你必须要学会或掌握汇编语言。DOS下病毒一般分为引导型病毒、文件型病毒、混合型病毒等。大部分病毒是感染COM和EXE文件,因此你必须了解COM文件和EXE文件结构。
一 .COM文件结构及原理
.COM 文件比较简单,.COM文件包含程序的一个绝对映象―――就是说,为了运行程序准确的处理器指令和内存中的数据,MS-DOS通过直接把该映象从文件拷贝到内存而加载.COM程序,它不作任何改变。为加载一个.COM程序,MS-DOS首先试图分配内存,因为.COM程序必须位于一个64K的段中,所以.COM文件的大小不能超过65,024(64K减去用于PSP的256字节和用于一个起始堆栈的至少256字节)。如果MS-DOS不能为程序、一个PSP、一个起始堆栈分配足够内存,QQ:9750406则分配尝试失败。否则,MS-DOS分配尽可能多的内存(直至所有保留内存),即使.COM程序本身不能大于64K。在试图运行另一个程序或分配另外的内存之前,大部分.COM程序释放任何不需要的内存。
分配内存后,MS-DOS在该内存的头256字节建立一个PSP,如果PSP中的第一个FCB含有一个有效驱动器标识符,则置AL为00h,否则为0FFh。MS-DOS还置AH为00h或0FFh,这依赖于第二个FCB是否含有一个有效驱动器标识符。建造PSP后,MS-DOS在PSP后立即开始(偏移100h)加载.COM文件,它置SS,DS和ES为PSP的段地址,接着创建一个堆栈.为创建一个堆栈,MS-DOS置SP为0000h,若已分配了至少64K内存;否则,它置寄存器为比所分配的字节总数大2的值.最后,它把0000h推进栈(这是为了保证与在早期MS-DOS版本上设计的程序的兼容性)。MS-DOS通过把控制传递偏移100h处的指令而启动程序.程序设计者必须保证.COM文件的第一条指令是程序的入口点。注意,因为程序是在偏移100h处加载,因此所有代码和数据偏移也必须相对于100h.汇编语言程序设计者可通过置程序的初值为100h而保证这
一点(例如通过在原程序的开始使用语句org 100h).
二 EXE文件结构
EXE 文件比较复杂,每个EXE文件都有一个文件头,结构如下:
EXE文件头信息
―――――――――――――――――――
├ 偏移量 ┤ 意义 ┤
├00h-01h ┤MZ‘EXE文件标记 ┤
├2h-03h┤文件长度除512的余数 ┤
├04h-05h ┤...............商 ┤
├06h-07h ┤重定位项的个数 ┤
├08h-09h ┤文件头除16的商 ┤
├0ah-0bh ┤程序运行所需最小段数 ┤
├0ch-0dh ┤..............大.... ┤
├oeh-0fh ┤堆栈段的段值 (SS) ┤
├10h-11h ┤........sp ┤
├12h-13h ┤文件校验和 ┤
├14h-15h ┤IP ┤
├16h-17h ┤CS ┤
├18h-19h ┤............ ┤
├1ah-1bh ┤............ ┤
├1ch ┤............ ┤
―――――――――――――――――――――――――
.EXE文件包含一个文件头和一个可重定位程序映象。文件头包含MS-DOS用于加载程序的信息,例如程序的大小和寄存器的初始值。文件头还指向一个重定位表,该表包含指向程序映象中可重定位段地址的指针链表。文件头的形式与EXEHEADER结构对应:
EXEHEADER STRUC
exSignature dw 5A4Dh ;.EXE标志
exExraBytes dw ? ;最后(部分)页中的字节数
exPages dw ? ;文件中的全部和部分页数
exRelocItems dw ? ;重定位表中的指针数
exHeaderSize dw ? ;以字节为单位的文件头大小
exMinAlloc dw ? ;最小分配大小
exMaxAlloc dw ? ;最大分配大小
exInitSS dw ? ;初始SS值
exInitSP dw ? ;初始SP值
exChechSum dw ? ;补码校验值
exInitIP dw ? ;初始IP值
exInitCS dw ? ;初始CS值
exRelocTable dw ? ;重定位表的字节偏移量
exOverlay dw ? ;覆盖号
EXEHEADER ENDS程序映象,包含处理器代码和程序的初始数据,紧接在文件头之后。它的大小以字节为单位,等于.EXE文件的大小减去文件头的大小,也等于exHeaderSize的域的值乘以16。MS-DOS通过把该映象直接从文件拷贝到内存加载.EXE程序然后调整定位表中说明的可重定位段地址。
定位表是一个重定位指针数组,每个指向程序映象中的可重定位段地址。文件头中的exRelocItems域说明了数组中指针的个数,exRelocTable域说明了分配表的起始文件偏移量。每个重定位指针由两个16位值组成:偏移量和段值。 为加载.EXE程序,MS-DOS首先读文件头以确定.EXE标志并计算程序映象的大校然后它试图申请内存。首先,它计算程序映象文件的大小加上PSP的大小再加上EXEHEADER结构中的exMinAlloc域说明的内存大小这三者之和,如果总和超过最大可用内存块的大校则MS-DOS停止加载程序并返回一个出错值。否则面,它计算程序映象的大小加上PSP的大小再加上EXEHEADER结构中exMaxAlloc域说明的内存大小之和,如果第二个总和小于最大可用内存块的大小,则MS-DOS 分配计算得到的内存量。否则,它分配最大可用内存块。分配完内存后,MS-DOS确定段地址,也称为起始段地址,MS-DOS从此处加载程序映象。如果exMinAlloc域和exMaxAlloc域中的值都为零,则MS-DOS把映象尽可能地加载到内存最高端。否则,它把映象加载到紧挨着PSP域之上。接下来,MS-DOS读取重定位表中的项目调整所有由可重定位指针说明的段地址。对于重定位表中的每个指针,MS-DOS寻找程序映象中相应的可重定位段地址,并把起始段地址加到它之上。一旦调整完毕,段地址便指向了内存中被加载程序的代码和数据段。 MS-DOS在所分配内存的最低部分建造256字节的PSP,把AL和AH设置为加载 .COM程序时所设置的值。MS-DOS使用文件头中的值设置SP与SS,调整SS初始值,把起始地址加到它之上。MS-DOS还把ES和DS设置为PSP的段地址.最后,MS-DOS从程序文件头读取CS和IP的初始值,把起始段地址加到CS之 上,把控制转移到位于调整后地址处的程序。
三、引导型病毒原理
了解引导型病毒的原理,首先要了解引导区的结构。软盘只有一个引导区,称为DOS BOOT SECTER ,只要软盘做了格式化,就会存在。其作用为查找盘上有无IO.SYS DOS.SYS,若有则引导,若无则显示‘NO SYSTEM DISK...’等信息。硬盘有两个引导区,在0面0道1扇区的称为主引导区,内有主引导程序和分区表,主引导程序查找激活分区,该分区的第一个扇区即为DOS BOOT SECTER。绝大多数病毒感染硬盘主引导扇区和软盘DOS引导扇区。
***3.5”软盘格式***
3.5”软盘是双面的,所以零磁道有正反两面,正面为0-17扇区,
反面是18-35扇区。
0 扇区: Boot area (引导扇区);
1 - 9 扇区: 1st FAT area (第一张文件分配表);
10 - 18 扇区: 2st FAT area (第二张文件分配表);
19 - 32 扇区: Root dir area(也叫 File Directory Table,FDT)
文件目录表(根目录)
33-2879 扇区: Data area (数据区)
***硬盘的主引导记录结构***
硬盘的主引导记录结构
偏移机器码符号指令说明
0000FACLI;屏蔽中断
000133C0XORAX,AX
00038ED0MOVSS,AX;(SS)=0000H
0005BC007CMOVSP,7C00;(SP)=7C00H
00088BF4MOVSI,SP;(SI)=7C00H
000A50PUSHAX
000B07POPES;(ES)=0000H
000C50PUSHAX
000D1FPOPDS;(DS)=0000H
000EFBSTI
000FFCCLD
0010BF0006MOVDI,0600
0013B90001MOVCX,0100;共512字节
0016F2REPNZ
0017A5MOVSW;主引导程序把自己从0000:7C00处搬到
;0000:0600处,为Dos分区的引导程序腾
;出空间
0018EA1D060000JMP0000:061D;跳到0000:061D处继续执行,实际上就是
;执行下面的MOV指令(001D偏移处)
001DBEBE07MOVSI,07BE;07BE-0600=01BE,01BE是分区表的首址
0020B304MOVBL,04;分区表最多4项,即最多4个分区
0022803C80CMPBYTEPTR[SI],80;80H表示活动分区
0025740EJZ0035;找到活动分区则跳走
0027803C00CMPBYTEPTR[SI],00;00H为有效分区的标志
002A751CJNZ0048;既非80H亦非00H则分区表无效
002C83C610ADDSI,+10;下一个分区表项,每项16字节
002FFECBDECBL;循环计数减一
003175EFJNZ0022;检查下一个分区表项
0033CD18INT18;4个都不能引导则进入ROMBasic
00358B14MOVDX,[SI]
00378B4C02MOVCX,[SI+02];取活动分区的引导扇区的面,柱面,扇区
003A8BEEMOVBP,SI;然后继续检查后面的分区表项
003C83C610ADDSI,+10
003FFECBDECBL
0041741AJZ005D;4个都查完则去引导活动分区
0043803C00CMPBYTEPTR[SI],00;00H为分区有效标志
004674F4JZ003C;此分区表项有效则继续查下一个
0048BE8B06MOVSI,068B;068B-0600=018B,取"无效分区"字符串
004BACLODSB;从字符串中取一字符
004C3C00CMPAL,00;00H表示串尾
004E740BJZ005B;串显示完了则进入死循环
005056PUSHSI
0051BB0700MOVBX,0007
0054B40EMOVAH,0E
0056CD10INT10;显示一个字符
00585EPOPSI
0059EBF0JMP004B;循环显示下一个字符
005BEBFEJMP005B;此处为死循环
005DBF0500MOVDI,0005;读入活动分区的引导扇,最多试读5次
0060BB007CMOVBX,7C00
0063B80102MOVAX,0201
006657PUSHDI
0067CD13INT13;读
00695FPOPDI
006A730CJNB0078;读盘成功则跳走
006C33C0XORAX,AX
006ECD13INT13;读失败则复位磁盘
00704FDECDI
007175EDJNZ0060;不到5次则再试读
0073BEA306MOVSI,06A3;06A3-0600=00A3,即"Errorloading"串
0076EBD3JMP004B;去显示字符串,然后进入死循环
0078BEC206MOVSI,06C2;06C2-0600=00C2,即"Missing.."串
0076EBD3JMP004B;去显示字符串,然后进入死循环
0078BEC206MOVSI,06C2;06C2-0600=00C2,即"Missing.."串
007BBFFE7DMOVDI,7DFE;7DFE-7C00=01FE,即活动分区的引导扇
;区的最后两字节的首址
007E813D55AACMPWORDPTR[DI],AA55;最后两字节为AA55H则有效
008275C7JNZ004B;无效则显示字符串并进入死循环
00848BF5MOVSI,BP
0086EA007C0000JMP0000:7C00;有效则跳去引导该分区
0080496E76616CInval
00906964207061727469-74696F6E20746162idpartitiontab
00A06C65004572726F72-206C6F6164696E67le.Errorloading
00B0206F706572617469-6E67207379737465operatingsyste
00C06D004D697373696E-67206F7065726174m.Missingoperat
00D0696E672073797374-656D0000FB4C381Dingsystem...L8.
00E00000000000000000-0000000000000000................
00F00000000000000000-0000000000000000................
01000000000000000000-0000000000000000................
01100000000000000000-0000000000000000................
01200000000000000000-0000000000000000................
01300000000000000000-0000000000000000................
01400000000000000000-0000000000000000................
01500000000000000000-0000000000000000................
01600000000000000000-0000000000000000................
01700000000000000000-0000000000000000................
01800000000000000000-0000000000000000................
01900000000000000000-0000000000000000................
01A00000000000000000-0000000000000000................
01B00000000000000000-0000000000008001................;分区表
01C00100060F7F9C3F00-0000F15906000000......?....Y....
01D0419D050FFF38305A-0600405606000000A....80Z..@V....
01E00000000000000000-0000000000000000................
01F00000000000000000-00000000000055AA..............U.
使用INT13H的02功能调用把位于硬盘保留扇区中0道0头1扇区处的硬盘主引导记录读到内存的ES:BX处。现在把读出程序代码进行如下分析:
1、移动主引导记录程序
0E74:7C0033C0XORAX,AX;AX清零
0E74:7C028ED0MOVSS,AX;SS清零
0E74:7C04BC007CMOVSP,7C00;SP=7C00,堆栈设在0:7C00H
0E74:7C07FBSTI;开中断
0E74:7C0850PUSHAX
0E74:7C0907POPES;ES=0
0E74:7C0A50PUSHAX
0E74:7C0B1FPOPDS;DS=0
0E74:7C0CFCCLD
0E74:7C0DBE1B7CMOVSI,7C1B;源地址为0:7C1BH
0E74:7C10BF1B06MOVDI,061B;目的地址为0:061BH
0E74:7C1350PUSHAX
0E74:7C1457PUSHDI
0E74:7C15B9E501MOVCX,01E5;移动01E5字节
0E74:7C18F3REPZ;将主引导记录从0:7C1B-0:7DFF
0E74:7C19A4MOVSB;移至0:061B-0:07FF
0E74:7C1ACBRETF;转移到0:061B,继续执行程序
2、顺序查找四个硬盘分区表,寻找自举标志
0E74:061BBEBE07MOVSI,07BE;SI指向硬盘分区表1的自举标志
0E74:061EB104MOVCL,04;查找四个分区
0E74:0620382CCMP[SI],CH
0E74:06227C09JL062D;如果[SI]的第7位为1,即为自
;举标志,转062DH
0E74:06247515JNZ063B;如果[SI]不为0,出错,转063BH
0E74:062683C610ADDSI,+10;依次检验四个分区表,直至找到
0E74:0629E2F5LOOP0620;自举标志
0E74:062BCD18INT18;找不到自举标志,进入BOOT异
;常处理程序。
0E74:062D8B14MOVDX,[SI];保存自举驱动器号于DL中
0E74:062F8BEEMOVBP,SI;保存自举分区地址指针于BP
0E74:063183C610ADDSI,+10;继续检验自举分区后的分区
0E74:063449DECCX;自举标志,直至四个分区都
0E74:06357416JZ064D;检查完
0E74:0637382CCMP[SI],CH;若其余的自举标志不为0,出错
0E74:063974F6JZ0631
3、出错,写屏幕程序段
0E74:063BBE1007MOVSI,0710;错误信息输出,死循环
0E74:063E4EDECSI
0E74:063FACLODSB
0E74:06403C00CMPAL,00
0E74:064274FAJZ063E
0E74:0644BB0700MOVBX,0007
0E74:0647B40EMOVAH,0E
0E74:0649CD10INT10
0E74:064BEBF2JMP063F
硬盘主引导记录程序的功能是读出自举分区的BOOT程序,并把控制转移到分区BOOT程序。整个程序流程如下:
1将本来读入到0:7C00H处的硬盘主引导记录程序移至0:61BH处;
⑵顺序读入四个分区表的自举标志,以找出自举分区,若找不到,转而执行INT18H的BOOT异常执行中断程序;
⑶找到自举分区后,检测该分区的系统标志,若为32位FAT表或16位FAT表但支持13号中断的扩展功能,就转到执行13号中断的41号功能调用进行安装检验,检验成功,就执行42号扩展读功能调用把BOOT区程序读入到内存0:7C00H处,成功,跳到第⑸步,若读失败或系统标志为其它,就调用13号中断的读扇区功能调用把BOOT读到0:7C00H;
⑷用13号中断的读扇区功能时,用两种方式分别进行5次试读。第一种方式是直接从自举分区的头扇区读入BOOT程序,若读成功,但结束标志不是55AA,则改用第二种方式,又如果用第一种方式试读五次均不成功,就改用第二种方式。若两种方式试读均失败,就转到出错处理程序;
⑸读入BOOT区程序成功,转至0:7C00H处执行BOOT程序。