 -=( ---------------------------------------------------------------------- )=-
 -=( Natural Selection Issue #1 ---------------------- Win32 Hints and Tips )=-
 -=( ---------------------------------------------------------------------- )=-

 -=( 0 : Contents --------------------------------------------------------- )=-

 0 : Contents
 1 : The MZ Header
 2 : PE Congruency
 3 : Multiple Infection Markers
 4 : Using TASM Parameters
 5 : Using Local Variables
 6 : Using The Stack
 7 : Miscellaneous

 -=( 1 : The MZ Header ---------------------------------------------------- )=-

 The MZ header has long been our friend.  In Windows files, however, the header
 may no longer be there as we know it.  I came across an interesting EXE  which
 looked like this:

        4D 5A xx xx  xx xx xx xx  xx xx xx xx  50 45 00 00
        pe pe pe pe  pe pe pe pe  pe pe pe pe  pe pe pe pe
        pe pe pe pe  pe pe pe pe  pe pe pe pe  pe pe pe pe
        pe pe pe pe  pe pe pe pe  pe pe pe pe  0C 00 00 00

 This implies a few things of interest.

 - As long as those three values (the MZ marker, the PE marker, and the  offset
 to PE header) are valid, the rest of the MZ header does not need to be.

 - A PE header  can be BEFORE the  offset at 3Ch which  specifies it's location
 (0C in this case).

 The later observation leads to more interesting observations.  To have a valid
 EXE and  have the  PE before  offset 3C,  it can  only be  located in very few
 spots, because, as you can see, 0000000C is now located inside the PE  header.
 As such, the value must be set to something that is either unimportant to  the
 loader or happens to be a value  that works. The only reasonable values I  can
 see  which work  for offset  3C are  0000000C, 00000010,  and 00000034.   This
 results in the following values containing the offset to the PE header instead
 of   their   usual   values:    BaseOfData,   BaseOfCode,   and  DateTimeStamp
 respectively.

 The use of this?  Just something to put in the back of your mind.

 -=( 2 : PE Congruency ---------------------------------------------------- )=-

 Do you want to put  your virus in the last  section of a PE?  If  you do, then
 you are probably  subtly corrupting the  PE Header and  Section Tables without
 even knowing it.  These  slight changes can easily  reveal your best virus  in
 any file just by checking the Header/Section Table.

 Firstly, make sure you  are actually infecting a  correct PE Header with  some
 simple tests.

 IMAGE_NT_HEADERS.Signature          == IMAGE_NT_SIGNATURE
 IMAGE_FILE_HEADER.Machine           == IMAGE_FILE_MACHINE_I386
 IMAGE_FILE_HEADER.Characteristics   == IMAGE_FILE_32BIT_MACHINE     AND
                                        IMAGE_FILE_BYTES_REVERSED_LO AND
                                        IMAGE_FILE_EXECUTABLE_IMAGE  AND
                                        NOT IMAGE_FILE_DLL
 IMAGE_OPTIONAL_HEADER32.Magic       == IMAGE_NT_OPTIONAL_HDR32_MAGIC
 IMAGE_OPTIONAL_HEADER32.NumberOfRvaAndSizes
                                        == IMAGE_NUMBEROF_DIRECTORY_ENTRIES

 Before we continue, I will give you the Formulas for Section calculations.

 : Sections in a File
   FileAlign        ( Bigger of VirtualSize / SizeOfRawData)
 : Sections in Memory
   SectionAlignment (Bigger of VirtualSize / SizeOfRawData)

 Files can have  data past the  end of the  last Section that  is referenced by
 fields in the PE  Header.  We must make  sure not to overwrite  these with the
 virus code.  Also, Sections are allocated more memory than you realise, as you
 see in the formula above.

 : Virus Location    =
   Bigger of FileSize / ((FileSize - Section in File) + Section in Memory)

 Now  we can  update our  IMAGE_OPTIONAL_HEADER32 fields.   Using the  formulas
 above, subtract the old  Section in Memory value,  and add the new  Section in
 Memory file.   Don't forget  to update  the extra  Code/iData/uData fields, if
 they are listed in the SECTION.Characteristics.

 : SizeOfImage       =
   ((SizeOfImage - Old Section Memory) + New Section Memory)
 : SizeOfCode        =
   ((SizeOfCode  - Old Section Memory) + New Section Memory)
 : SizeOfInitializedData   =
   ((SizeOfIntializedData - Old Section Memory) + New Section Memory)
 : SizeOfUninitializedData =
   ((SizeOfUninitializedData - Old Section Memory) + New Section Memory)

 -=( 3 : Multiple Infection Markers --------------------------------------- )=-

 One way in which  AVs can detect the  presence of a virus  is to look for  the
 virus's own infection marker.  Unless you're writing something like  Commander
 Bomber, then it's a necessary evil though.  This does not mean that you  can't
 make it difficult for AVs though.  Simply have many possible infection markers
 and select one of  them randomly for each  infected file. Then, to  see if the
 file is infected, simply check for  the presence of all the infection  markers
 and if  any one  of them  is found,  assume the  file is already infected.  It
 becomes harder for  the AVs to  determine if the  file is infected  or not, it
 will not cut down the number of possible hosts in any significant manner,  and
 it's very easy to code.

 -=( 4 : Using TASM Parameters -------------------------------------------- )=-

 TASM provides ways to ensure that  calls to functions have the correct  number
 of parameters.  As part of good form, and to help prevent bugs, you should use
 them.  There are two ways to import APIs:

        extrn   MapViewOfFile:PROC
        MapViewOfFile   PROCDESC  :DWORD, :DWORD, :DWORD, :DWORD, :DWORD

 The first is the way most  people use, but the second allows  type-checking on
 your parameters.  The following is legal for the first, but causes a deserving
 error for the second:

        call    MapViewOfFile, 1, 2, 3, 4       ; Error - too few parameters
        call    MapViewOfFile, 1, 2, 3, 4, 5    ; ok
        call    MapViewOfFile                   ; ok - 0 parameters is valid

 TASM  even allows  type checking for  functions which are  imported at runtime
 like those of a virus.  Simply define a procedure type by:

        MapViewOfFile_t PROCTYPE  :DWORD, :DWORD, :DWORD, :DWORD, :DWORD

 Then for each call do the following, and your parameters will be type checked:

        call    [MapViewOfFile_t ptr loc_MapViewOfFile+ebp], 1, 2, 3, 4, 5

 It's simple, so why not use it.  It can help avoid some pretty ugly bugs.

 -=( 5 : Using Local Variables -------------------------------------------- )=-

 In any sufficiently complex virus you will need some variables.  Traditionally
 they have been done as follows:

        call    Delta
 Delta:
        pop     ebp
        sub     ebp, offset Delta
        ...
        lea     eax, [ebp+String]
        mov     dword ptr [ebp+Variable], 5
        ...
 Variable       dd ?
 String         db 'blahblah',0

 What's wrong with this picture?  Well:
 1) We have a delta offset calculation which is a dead giveaway
 2) The Variable is in the  code section - this requires that  whatever section
 the virus is running in has read/write access.

 What can  be done  to solve  these problems  is simple  - use  local variables
 exactly  the same  way that  high level  languages  do by  putting  your local
 variables onto the stack.  There are 2 ways to allocate space on the stack for
 your variables:

        enter   LocalsSize, 0
        ...
        leave

 or, the manual equivalent way:

        push    ebp
        mov     ebp, esp
        sub     ebp, LocalsSize
        ...
        mov     esp, ebp
        pop     ebp

 Note 1: In both cases, LocalsSize must be a multiple of 4 (pad it if needed).
 Note 2: Both TASM and MASM have a compiler directive to do this for you.

 (Technically the push/pop ebp are optional, but to keep it's common for  these
 instructions to be in  this order [hence they  wont usually be part  of a scan
 string],  while if  anything  else precedes  the  'mov ebp, esp'  it  would be
 uncommon)

 Now that you have  created space for all  your local variables you  can access
 them relative to ebp by subtracting values from it.  For example if you want 3
 local variables A, B, and C of sizes byte, dword, array of 20 bytes, then  you
 could do this:

        A equ -4             ; A should be dword aligned to align entire size
        B equ -8             ; B will be the dword at [ebp-8]
        C equ -28            ; C will be the array from [ebp-28] to [ebp-9]
        enter   28, 0
        mov     byte ptr [ebp+A], 1
        mov     eax, [ebp+B]
        lea     edi, [ebp+C]
        leave

 Simple, no?  No more writable code section. :-)

 In TASM you can automate this by declaring around you virus a procedure by:

        virus PROC
        local A:BYTE, B:DWORD, C:BYTE:20
                mov     A, 1
                mov     eax, B
                lea     edi, C
        endp

 There are 2 special cases in this though.  One is in the first example:

        lea     eax, [ebp+String]
        ...
        String     db 'blahblah',0

 Preset values  for variables  must be  either copied  onto the stack manually.
 However, if  the values  never change  like in  a string  for example, you can
 simply do:

        call    PushString
        db      'blahblah',0
 PushString:
        pop     eax             ; (usually you want to leave it on the stack)


 The other problem is that  at some point in the  infector you will need to  do
 something similar to:

        mov     eax, offset VirusStart

 At this point, you must calculate a delta offset in this case.  Use  something
 like:

        call    GetVirusStart
 GetVirusStart:
        pop     eax
        sub     eax, offset GetVirusStart - offset VirusStart

 This case does not need to show  up more than once deep inside the  virus body
 however.

 -=( 6 : Using The Stack -------------------------------------------------- )=-

 A good way to get some temporary storage for a virus is to use the stack.  The
 stack  has read/write  access and can  even run code  in windows.    There are
 however,   a few important  caveats  when trying to  allocate more than 4kb of
 space.   The stack is  defined in a  PE file with  two fields.   Here they are
 complete with typical values for them:

        Size Of Stack Reserve                   00100000
        Size Of Stack Commit                    00002000

 The first  number tells the  loader the  total size of  the stack,   while the
 second is the  number of bytes the  loader should  initially allocate  for the
 stack.   The stack can  grow up to the  "Stack Reserve"  Size before a program
 crashes.   When a stack page that has not been allocated yet  is accessed,  an
 exception is triggered and the OS automatically allocates the page and returns
 control to your program - in theory.  But Windows is a bit quirky.

 In the above  example,  there are a total of  256 pages  (100h at 1000h bytes)
 with 2 of the pages already allocated.   Accessing any of the first 3 pages of
 the stack works normally,  but a problem arises when trying to access the  4th
 page  without first accessing the 3rd  -  i.e. the program crashes.   You see,
 Windows  keeps a one page  buffer zone  immediately after the  allocated stack
 memory.   Accessing the buffer page with a read or write allocates it and sets
 the buffer page to the next page  (4 in this case).   Skipping past the buffer
 page means the routine for allocating more stack pages is not called in the OS
 and as a consequence, you're trying to access unavailable memory and crash.

 In short, the following is a no-no:
        sub     esp, 8500h      ; allocate 8500h of stack space
        push    eax             ; This will access mem page past buffer zone

 Instead,  when using the stack  to get  more than  1000h bytes,  make sure you
 access each page at least  once before writing to  the top of the stack.   Use
 something like the following instead:

        mov     ecx, 8          ; allocates 8000h bytes on stack
 here:
        sub     esp, 1000h      ; 1000h bytes in a page - gotta catch'em all
        mov     [esp], ecx      ; random write allocates the page
        loop    here
        sub     esp, 500h       ; Allocate rest of 8500h bytes of stack
        push    eax             ; The push is now fine

 Remember to keep the stack  4 byte aligned.   Special thanks to an  IRC friend
 for the debate.

 -=( 7 : Miscellaneous ---------------------------------------------------- )=-

 Writing string comparison routines  in ASM sucks.  So  why not use a  good API
 that  is  built specifically  for  this purpose?   The  CompareStringA API  in
 Kernel32.DLL can do both cased  and uncased comparisons on strings  and ASCIIZ
 strings.

 Instead  of wasting  time  (and  introducing  bugs)  trying to  remember which
 registers to  saving and  unsave for  each API  call, wrap  your  calls   in a
 macro  that saves  all  registers on  entry, and   pops EAX  on return.    API
 rarely  modify the  other registers with useful values.

 Split your virus into  proper procedures.  Nobody is  going to notice the  few
 extra bytes except you, when you go back to look at it a few months later  and
 try to unravel the mess.  People appreciate style over size :)

 Trying to find what the numeric value for KEY_SET_VALUE or some other constant
 mentioned in your help files?   If the value is not present in one of the many
 include files available, then you may have to find the value yourself.   To do
 this,  get a Windows C/C++  compiler (like Visual C++).   These compilers come
 with  .h include that have the  complete definitions  for all structures,  and
 constants that you will ever need - all you need to do is convert them to asm.

 -=( ---------------------------------------------------------------------- )=-
 -=( Natural Selection Issue #1 --------------- (c) 2002 Feathered Serpents )=-
 -=( ---------------------------------------------------------------------- )=-
