home *** CD-ROM | disk | FTP | other *** search
/ Shareware 1 2 the Maxx / sw_1.zip / sw_1 / VIRUS / STEALTH.ZIP / STEALTH.DOC < prev    next >
Text File  |  1992-02-10  |  62KB  |  1,824 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.                  Stealth Bomber version 2.2 (formerly CRCSET)
  29.                     Copyright (c) 1991, 1992 by Kevin Dean
  30.  
  31.                                   Kevin Dean
  32.                          Fairview Mall P.O. Box 55074
  33.                            1800 Sheppard Avenue East
  34.                               Willowdale, Ontario
  35.                                CANADA    M2J 5B9
  36.                            CompuServe ID: 76336,3114
  37.  
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  
  46.  
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.                                    Contents
  58.                                    --------
  59.  
  60.                Warranty ....................................  1
  61.  
  62.                License .....................................  2
  63.  
  64.                Call For Programmers ........................  3
  65.  
  66.                Introduction ................................  4
  67.  
  68.                What is a CRC? ..............................  5
  69.  
  70.                Other Types of Self-Checking ................  9
  71.  
  72.                Limitations of Self-Checking ................ 10
  73.  
  74.                DOS Memory Control Blocks ................... 11
  75.  
  76.                Stealth Viruses ............................. 13
  77.  
  78.                How CRCSET.EXE Works ........................ 15
  79.  
  80.                How to Use Stealth Bomber - C ............... 21
  81.  
  82.                How to Use Stealth Bomber - Turbo Pascal .... 23
  83.  
  84.                CRCSET.EXE Syntax and Messages .............. 25
  85.  
  86.                Vulnerability ............................... 28
  87.  
  88.  
  89.                                    Warranty
  90.  
  91.         The author of Stealth Bomber (hereafter referred to as "the author")
  92. makes no warranty of any kind, expressed or implied, including without
  93. limitation any warranties of merchantability and/or fitness for a particular
  94. purpose.  The author shall not be liable for any damages, whether direct,
  95. indirect, special, or consequential arising from a failure of this program to
  96. operate in the manner desired by the user.  The author shall not be liable for
  97. any damage to data or property which may be caused directly or indirectly by
  98. use of the program.
  99.  
  100.         In no event will the author be liable to the user for any damages,
  101. including any lost profits, lost savings, or other incidental or consequential
  102. damages arising out of the use or inability to use the program, or for any
  103. claim by any other party.
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  
  147.  
  148.                                   - Page 1 - 
  149.  
  150.  
  151.                                     License
  152.  
  153.         This program is public domain.  As such, it may be freely distributed
  154. by anyone by any means.  No person or organization may charge for this program
  155. except for a minimal charge to cover handling and distribution.
  156.  
  157.         A quiet option ('-q') is available principally for developers; see
  158. the section "CRCSET.EXE Syntax and Messages" for details.  If you wish to
  159. distribute Stealth Bomber as part of the installation procedure for your
  160. package, you are free to do so without obligation under the condition that the
  161. executable CRCSET.EXE itself is the only part of this package that you
  162. distribute.  You may not distribute CRCSET.EXE as part of a generic INSTALL
  163. package; if you wish to do so, contact me at the address on the first page of
  164. this document.
  165.  
  166.         Having said that, I would like to add that this algorithm has taken a
  167. lot of time and work to develop.  If you like this program, send me a postcard
  168. and let me know.  I would also be interested in copies of your own programs if
  169. you feel that that is appropriate.
  170.  
  171.         Also, if you have any questions or would like to see some more
  172. features in the program, drop me a note by surface or electronic mail (my
  173. address is on the first page of this file).  I will answer all mail regarding
  174. this program.
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.  
  208.  
  209.  
  210.                                   - Page 2 - 
  211.  
  212.  
  213.                              Call For Programmers
  214.  
  215.         I have had requests for support for other languages, most notably
  216. QBASIC.  If you are willing to port this code to another language (other than
  217. C, C++, or Turbo Pascal), I will gladly add your code and your name to the
  218. package.  Contact me at the address on the first page for details.
  219.  
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226.  
  227.  
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247.  
  248.  
  249.  
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.                                   - Page 3 - 
  273.  
  274.  
  275.                                  Introduction
  276.  
  277.         Stealth Bomber is an anti-virus utility.  It performs simple checks by
  278. looking for suspicious behaviour in the operating system and checks files with
  279. one of the most effective weapons against computer viruses: the Cyclic
  280. Redundancy Check, or CRC.  A full understanding of the DOS internals and the
  281. CRC is not required to use this utility; if you like, you can skip over the
  282. discussions of the CRC and DOS memory control blocks to the sections entitled
  283. "How to Use Stealth Bomber - <language>".
  284.  
  285.         There are many utilities that perform CRC checks on other programs but
  286. most of these are external programs that are usually run only once, if at all.
  287. The CRC generated by these utilities must be compared to a value in an
  288. external file; if the values match, the program is not infected.
  289.  
  290.         This approach has two problems: the first is that the CRC check is
  291. run only once when the user gets the program, if at all.  Most people would
  292. never run the check a second time.  The second problem is that the CRC is
  293. stored in an external file (e.g. the documentation).  If someone wants to tack
  294. a virus onto the program, it becomes a simple matter to run the validation
  295. program, copy the CRC values to the documentation, and distribute the infected
  296. program.  Anyone running the validation program would find the same CRC in the
  297. program as in the documentation, and in comes the virus.
  298.  
  299.         Another (increasingly popular) approach is for the CRC to be stored in
  300. the program itself (the .EXE file) and for the program to do its own check
  301. every time it is loaded.  This method is much more effective than the previous
  302. one because it means that the moment the program is infected and the CRC
  303. changes, the infection will be detected the next time the program is run.
  304.  
  305.         There is a potential problem with this method, but before I get into
  306. that, we need some background.
  307.  
  308.  
  309.  
  310.  
  311.  
  312.  
  313.  
  314.  
  315.  
  316.  
  317.  
  318.  
  319.  
  320.  
  321.  
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.                                   - Page 4 - 
  335.  
  336.  
  337.                                 What is a CRC?
  338.  
  339.         The CRC, or Cyclic Redundancy Check, is an error-checking algorithm
  340. used in many types of computer operations, especially in data transfer.  For
  341. example, whenever your computer writes to disk, the disk controller calculates
  342. the CRC of the data being written and writes it with the data.  If your disk
  343. should somehow become corrupted, the CRC check will fail when you next try to
  344. read the data and the disk controller will return with an error, forcing DOS
  345. to display the critical error "Data error reading drive C:".  Most file
  346. transfer protocols (like Xmodem, Zmodem, and some derivatives of Kermit) also
  347. use a CRC to validate the data being transmitted: if the CRC transmitted with
  348. the data does not match the CRC calculated by the receiving program, then the
  349. transmission has failed and the sending program is asked to retry the
  350. transmission.
  351.  
  352.         The actual calculation of the CRC is very simple.  The algorithm
  353. consists of two parts, a CRC polynomial and a CRC register, and is really an
  354. exercise in modulo-2 arithmetic.  The rules for modulo-2 arithmetic are shown
  355. in the following table:
  356.  
  357.                                    0 + 0 = 0
  358.                                    0 + 1 = 1
  359.                                    1 + 0 = 1
  360.                                    1 + 1 = 0
  361.  
  362. For those of you familiar with binary logic, these rules are equivalent to
  363. the exclusive-or operation.  Note: under modulo-2 arithmetic, subtraction is
  364. equivalent to addition.
  365.  
  366.         There is nothing magical about modulo-2 arithmetic and it has no
  367. special properties that make it better suited to CRC calculations than
  368. standard arithmetic; rather, since modulo-2 arithmetic doesn't carry from one
  369. column to the next (i.e. 1 + 1 = 0 with no carry), it's just easier to
  370. implement in hardware and software than any other method.  Consider the
  371. following:
  372.  
  373. 1. Binary addition, normal rules of carry
  374.      101101001
  375.    + 110110111
  376.    -----------
  377.     1100100000
  378.  
  379. 2. Binary addition, modulo-2 arithmetic (no carry)
  380.      101101001
  381.    + 110110111
  382.    -----------
  383.      011011110
  384.  
  385. The first addition requires us to carry any overflow from right to left.  The
  386. second addition requires no carry operations and can be performed much faster
  387. both by humans and by computers.
  388.  
  389.         The CRC algorithm can best be illustrated by the following diagram of
  390. a 4-bit CRC generator:
  391.  
  392.  
  393.  
  394.  
  395.  
  396.                                   - Page 5 - 
  397.  
  398.  
  399.                                  CRC polynomial
  400.                ------------1-----------0-----------1-----------1
  401.                |     3     |     2           1     |     0     |
  402.                |   -----   v   -----       -----   v   -----   v
  403.                + <-| x |<- + <-| x |<------| x |<- + <-| x |<- +
  404.                ^   -----       -----       -----       -----
  405.                |                  CRC register
  406.                ---- binary data stream
  407.  
  408. Each '+' symbol represents modulo-2 addition.  The numbers above the CRC
  409. register are the bit numbers of the register.
  410.  
  411.         The CRC is calculated as follows:
  412.  
  413. 1. Initialize the CRC register to 0.
  414.  
  415. 2. Add the incoming bit of the data stream to the outgoing bit (bit 3) of the
  416.    CRC register.
  417.  
  418. 3. Send the result of step 2 into the polynomial feedback loop.
  419.  
  420. 4. Add the value in the feedback loop to the bits in the CRC register as it is
  421.    shifted left.  The bits affected are determined by the CRC polynomial (i.e.
  422.    there is an addition for every bit in the polynomial that is equal to 1; if
  423.    the bit is 0, it is not fed back into the register).  In this case, the
  424.    polynomial represented is 1011.
  425.  
  426. 5. Repeat steps 2-4 for every bit in the data stream.
  427.  
  428. 6. The CRC is the final value in the register.
  429.  
  430. Let's try this with the data stream 11010111 and the polynomial 1011.  The
  431. result will be a 4-bit CRC.
  432.  
  433.         The output stream to the left is the result of each addition operation
  434. at the left-most gate.  This is the value that is fed into the polynomial
  435. feedback loop during the left shift.
  436.  
  437.                      ------------1-----------0-----------1-----------1
  438.                      |     3     |     2           1     |     0     |
  439.                      |   -----   v   -----       -----   v   -----   v
  440.                      + <-| 0 |<- + <-| 0 |<------| 0 |<- + <-| 0 |<- +
  441.                      ^   -----       -----       -----       -----
  442.                      |
  443.                      ---- 11010111
  444.  
  445.                      ------------1-----------0-----------1-----------1
  446.                      |     3     |     2           1     |     0     |
  447.                      |   -----   v   -----       -----   v   -----   v
  448.                 1 <- + <-| 1 |<- + <-| 0 |<------| 1 |<- + <-| 1 |<- +
  449.                      ^   -----       -----       -----       -----
  450.                      |
  451.                      ---- 1010111
  452.  
  453.  
  454.  
  455.  
  456.  
  457.  
  458.                                   - Page 6 - 
  459.  
  460.  
  461.                      ------------1-----------0-----------1-----------1
  462.                      |     3     |     2           1     |     0     |
  463.                      |   -----   v   -----       -----   v   -----   v
  464.                10 <- + <-| 0 |<- + <-| 1 |<------| 1 |<- + <-| 0 |<- +
  465.                      ^   -----       -----       -----       -----
  466.                      |
  467.                      ---- 010111
  468.  
  469.                      ------------1-----------0-----------1-----------1
  470.                      |     3     |     2           1     |     0     |
  471.                      |   -----   v   -----       -----   v   -----   v
  472.               100 <- + <-| 1 |<- + <-| 1 |<------| 0 |<- + <-| 0 |<- +
  473.                      ^   -----       -----       -----       -----
  474.                      |
  475.                      ---- 10111
  476.  
  477.                      ------------1-----------0-----------1-----------1
  478.                      |     3     |     2           1     |     0     |
  479.                      |   -----   v   -----       -----   v   -----   v
  480.              1000 <- + <-| 1 |<- + <-| 0 |<------| 0 |<- + <-| 0 |<- +
  481.                      ^   -----       -----       -----       -----
  482.                      |
  483.                      ---- 0111
  484.  
  485.                      ------------1-----------0-----------1-----------1
  486.                      |     3     |     2           1     |     0     |
  487.                      |   -----   v   -----       -----   v   -----   v
  488.             10001 <- + <-| 1 |<- + <-| 0 |<------| 1 |<- + <-| 1 |<- +
  489.                      ^   -----       -----       -----       -----
  490.                      |
  491.                      ---- 111
  492.  
  493.                      ------------1-----------0-----------1-----------1
  494.                      |     3     |     2           1     |     0     |
  495.                      |   -----   v   -----       -----   v   -----   v
  496.           100010 <- + <-| 0 |<- + <-| 1 |<------| 1 |<- + <-| 0 |<- +
  497.                      ^   -----       -----       -----       -----
  498.                      |
  499.                      ---- 11
  500.  
  501.                      ------------1-----------0-----------1-----------1
  502.                      |     3     |     2           1     |     0     |
  503.                      |   -----   v   -----       -----   v   -----   v
  504.           1000101 <- + <-| 0 |<- + <-| 1 |<------| 1 |<- + <-| 1 |<- +
  505.                      ^   -----       -----       -----       -----
  506.                      |
  507.                      ---- 1
  508.  
  509.                      ------------1-----------0-----------1-----------1
  510.                      |     3     |     2           1     |     0     |
  511.                      |   -----   v   -----       -----   v   -----   v
  512.          10001011 <- + <-| 0 |<- + <-| 1 |<------| 0 |<- + <-| 1 |<- +
  513.                      ^   -----       -----       -----       -----
  514.                      |
  515.                      ----
  516.  
  517.         The CRC is 0101.
  518.  
  519.  
  520.                                   - Page 7 - 
  521.  
  522.  
  523.         What should be obvious at this point is that if a single bit in the
  524. data stream is changed, the value in the CRC register is corrupted completely.
  525. The feedback loop ensures that the error is propagated throughout the entire
  526. calculation.
  527.  
  528.         Most CRC algorithms use either a 16- or 32-bit polynomial.  The longer
  529. the polynomial, the more effective it is at catching errors; a 16-bit CRC, for
  530. example, catches more than 99.99% of all random errors in a data stream.
  531.  
  532.         All other CRC algorithms are analogous to the 4-bit algorithm
  533. presented here.  There are some optimizations that can process several bits at
  534. a time; the source code included with this program uses a lookup table that
  535. can process 8 bits at once.  For further discussion of the CRC algorithm and
  536. its variations, I recommend "C Programmer's Guide to Serial Communications" by
  537. Joe Campbell, published by Howard W. Sams & Company.
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552.  
  553.  
  554.  
  555.  
  556.  
  557.  
  558.  
  559.  
  560.  
  561.  
  562.  
  563.  
  564.  
  565.  
  566.  
  567.  
  568.  
  569.  
  570.  
  571.  
  572.  
  573.  
  574.  
  575.  
  576.  
  577.  
  578.  
  579.  
  580.  
  581.  
  582.                                   - Page 8 - 
  583.  
  584.  
  585.                          Other Types of Self-Checking
  586.  
  587.         Some viruses may not be detectable by checking the CRC of the file
  588. (see "Limitations of Self-Checking" below for details), but there are some
  589. obvious and simple tests we can perform to check for suspicious behaviour.
  590.  
  591.         The first is to check the date and time of the file.  DOS does
  592. precious little checking when setting the date and time fields (unless it sets
  593. them itself when creating the file) and so it is possible to fiddle around
  594. with them.  For example, there is a little-known seconds field in the time
  595. stamp, and it is possible to set this as high as 62 seconds.  The year can go
  596. up to 2107.  Some viruses mark their presence by changing these fields, and we
  597. can check for such signs by doing a simple validation on the fields.
  598.  
  599.         Another thing to watch for is some kind of consistency in the file
  600. size.  If the size returned by the directory information doesn't match the
  601. size of the file when it is opened, something is wrong and we can signal that
  602. kind of error.
  603.  
  604.  
  605.  
  606.  
  607.  
  608.  
  609.  
  610.  
  611.  
  612.  
  613.  
  614.  
  615.  
  616.  
  617.  
  618.  
  619.  
  620.  
  621.  
  622.  
  623.  
  624.  
  625.  
  626.  
  627.  
  628.  
  629.  
  630.  
  631.  
  632.  
  633.  
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640.  
  641.  
  642.  
  643.  
  644.                                   - Page 9 - 
  645.  
  646.  
  647.                          Limitations of Self-Checking
  648.  
  649.         Doing a CRC check on a file works for most viruses, and in fact a
  650. number of programs do perform some kind of self-check to make sure that they
  651. have not been infected.  It wasn't long before a new kind of virus, the
  652. stealth virus, hit the PC world.
  653.  
  654.         Perhaps the best-known stealth virus is the "Hundred Years" virus.
  655. The virus changes the date stamp of an infected file by adding one hundred to
  656. the year portion.  Since the DOS DIR command shows only the last two digits of
  657. the year, this is not always obvious.
  658.  
  659.         The stealth virus manages to hide itself from a CRC check by hooking
  660. into the DOS interrupt and monitoring certain system calls.  When the file
  661. opens itself for a self-check, the virus first disinfects the file before
  662. passing the file open call to the operating system.  The CRC self-check is
  663. then working with a clean file.  The "Hundred Years" virus also monitors the
  664. DOS DIR calls and, if it sees a file with the year greater than 2079,
  665. subtracts one hundred from the year and subtracts 4096 from the size before
  666. returning the directory information to the calling program.  The net result is
  667. that the calling program sees the directory information exactly as it would
  668. appear if the virus had not in fact infected the file.  Every test built into
  669. the file checking algorithm in this package would pass with flying colours.
  670.  
  671.         The "Hundred Years" virus is also particularly clever at hiding itself
  672. from DOS mapping utilities.  There is no indication, using regular DOS checks,
  673. that the virus is in memory at all.  All the interrupt pointers are pointing
  674. where they should and no memory seems to be taken up by the virus at all.  How
  675. is this possible?
  676.  
  677.  
  678.  
  679.  
  680.  
  681.  
  682.  
  683.  
  684.  
  685.  
  686.  
  687.  
  688.  
  689.  
  690.  
  691.  
  692.  
  693.  
  694.  
  695.  
  696.  
  697.  
  698.  
  699.  
  700.  
  701.  
  702.  
  703.  
  704.  
  705.  
  706.                                  - Page 10 - 
  707.  
  708.  
  709.                            DOS Memory Control Blocks
  710.  
  711.         DOS is a linear memory system.  It was first designed, and still is
  712. designed, with the idea that one program will sit on top of another in memory
  713. and that the program at the top of memory will be the one that is currently
  714. running.  As a result, it has a very simple memory manager.
  715.  
  716.         The DOS Memory Control Block, or MCB, contains everything there is to
  717. know about a memory block: its owner and the number of paragraphs (16-byte
  718. chunks) allocated to that block.  The MCB takes up one paragraph and has the
  719. following format:
  720.  
  721. BYTE ID         'M' for every block except the last, which is 'Z'.
  722. WORD PSP        The Program Segment Prefix of the program that owns the block;
  723.                 0 if the block is free.
  724. WORD SIZE       The size of the block in paragraphs.
  725. BYTE UNUSED[3]  Unused.
  726. BYTE NAME[8]    The file name of the owning program; unused below DOS 4.x.
  727.  
  728. The only fields we are really interested in are the ID (so we know when we're
  729. at the end of the chain) and the size (so we know how big it is and where the
  730. next MCB is).  To find the next MCB, add the size of the allocated block
  731. plus one (for the MCB itself) to the current MCB segment address, i.e.
  732.  
  733.             next MCB segment = current MCB segment + block size + 1
  734.  
  735.         The MCB list covers all of memory, which means that the address
  736. of the last block plus its size points to the end of usable memory, i.e.
  737.  
  738.      last MCB address + its size + 1 = A000h = first paragraph beyond 640k.
  739.  
  740.         Unfortunately, there are some exceptions to this nice and simple
  741. memory layout.  Some utilities extend DOS memory by remapping upper memory
  742. (especially in 386 machines) to give DOS as much as 920k and may not always
  743. update the BIOS memory to reflect the change.  Some clones of MS-DOS may
  744. differ by as much as 1k in the amount of memory they report versus the amount
  745. of BIOS memory available, and DOS 5.0 memory differs from BIOS memory by only
  746. one paragraph when it is loaded in the upper memory block (UMB).  The long and
  747. the short of this is that DOS memory may not always equal BIOS memory, but we
  748. can adjust for this by saying that it may be no more than 1k short of the
  749. memory reported by the BIOS.
  750.  
  751.         Every program has at least two blocks allocated to it.  The first, the
  752. environment block, contains the environment (such as the PATH, COMSPEC, etc)
  753. of the program.  The second block is allocated to the code and data of the
  754. program itself.  Any other memory management that the program requires must be
  755. done through DOS functions 48h (allocate memory), 49h (free memory), and 4Ah
  756. (resize memory).  When the program terminates, DOS walks through the list of
  757. MCB's and frees all the memory associated with that program by releasing all
  758. blocks with the PSP equal to that of the program.
  759.  
  760.         The following diagram shows a simplified DOS MCB layout; a typical
  761. system could have well over two dozen MCB's.
  762.  
  763.  
  764.  
  765.  
  766.  
  767.  
  768.                                  - Page 11 - 
  769.  
  770.  
  771.                +===========+
  772.        MCB --> | ID | Size | DOS config
  773.                +-----------+
  774.                | Block     |  <-- `Size' paragraphs long.
  775.                +===========+
  776.                .
  777.                .             More DOS config, COMMAND.COM, TSR's, etc.
  778.                .
  779.                +===========+
  780.        MCB --> | ID | Size | Program's environment block
  781.                +-----------+
  782.                | Block     |
  783.                +===========+
  784.        MCB --> | ID | Size | Program
  785.                +-----------+
  786.                | Block     |
  787.                +===========+
  788.        MCB --> | ID | Size | Free
  789.                +-----------+
  790.                | Block     |
  791.                +===========+ <-- End of usable memory (typically 640k).
  792.  
  793.         The MCB is one of many things that Microsoft has never documented but
  794. which, like every other undocumented feature, has been ripped apart and
  795. analyzed by countless hackers over the years.  The best reference for the MCB
  796. (and countless other undocumented but useful DOS features) is "Undocumented
  797. DOS", by Andrew Schulman et al, published by Addison-Wesley Publishing
  798. Company.
  799.  
  800.         In brief, loading the AH register with 52h and calling the DOS
  801. function interrupt returns a pointer to the DOS "list of lists" in ES:BX (see
  802. "Undocumented DOS" for more information about this list).  The segment address
  803. of the first MCB is at ES:[BX-2].
  804.  
  805.  
  806.  
  807.  
  808.  
  809.  
  810.  
  811.  
  812.  
  813.  
  814.  
  815.  
  816.  
  817.  
  818.  
  819.  
  820.  
  821.  
  822.  
  823.  
  824.  
  825.  
  826.  
  827.  
  828.  
  829.  
  830.                                  - Page 12 - 
  831.  
  832.  
  833.                                 Stealth Viruses
  834.  
  835.         Many stealth viruses take advantage of the simplicity of the MCB to
  836. hide themselves in upper memory.  The virus gets control the moment the
  837. program is loaded and the first thing it does is copy itself to the end of
  838. memory.  It then walks through the MCB list until it gets to the last MCB, and
  839. shrinks the size field so that the end of memory, at least as far as DOS is
  840. concerned, is 640k minus the size of the virus!  DOS will never allocate
  841. memory beyond what it knows to exist in the MCB list and so the virus is safe
  842. from being overwritten.
  843.  
  844.         The only way to tell that a virus has done this is to calculate the
  845. DOS memory by walking the MCB chain and comparing it to the memory reported by
  846. the BIOS, and this is exactly what the system check in this package does.
  847.  
  848.         Once a virus has loaded itself into upper memory, it must then take
  849. over the DOS interrupt 21h, and possibly some others, in order to monitor DOS
  850. calls.  If it simply redirects the interrupt vector, it would be easily found
  851. by checking the vector and making sure that it is not pointing to something
  852. beyond the program.  Six critical interrupts, 21h (DOS function), 24h
  853. (critical error), 25h (absolute disk read), 26h (absolute disk write), 1Ch
  854. (user timer), and 28h (DOS OK) are checked in this way.
  855.  
  856.         A better way to hijack an interrupt is to patch the interrupt code
  857. itself with a far jump to the virus.  This means simply replacing the first
  858. five bytes of the DOS interrupt with "JMP FAR <addr>" where <addr> is the
  859. address of the virus' interrupt handler.  This is what happens when a DOS
  860. function interrupt occurs:
  861.  
  862.         1) control is transferred to the actual address of the DOS interrupt
  863.            handler;
  864.         2) a far jump is made to the virus;
  865.         3) the virus patches the DOS code with the five bytes that were
  866.            replaced by the far jump instruction;
  867.         4) the virus does any pre-DOS processing necessary based on the
  868.            function, such as disinfecting a file;
  869.         5) the virus passes the original request back to the DOS handler;
  870.         6) DOS processes the request and returns to the virus;
  871.         7) the virus does any post-DOS processing necessary based on the
  872.            function, such as changing the directory information returned by
  873.            DOS;
  874.         8) the virus replaces the first five bytes of the DOS code with the
  875.            far jump instruction; and
  876.         9) the virus returns control to the calling program.
  877.  
  878.         The trick then is to look for the far jump instruction.  Three other
  879. instructions, a far call, an indirect far jump through a value stored in the
  880. code segment, and an indirect far call through a value stored in the code
  881. segment are also tested for.
  882.  
  883.         It isn't enough to look for the far jump instruction: we also have to
  884. figure out the destination of the jump.  Some DOS clones move interrupt code
  885. into the 64k block just above the 1 Megabyte limit on 286 and higher machines
  886. and transfer control with a far jump instruction.  Resident anti-virus
  887. utilities redirect the DOS function interrupt and at least one of them has a
  888. far jump as the first instruction in its interrupt handler.  I can only assume
  889. that this is to fool a stealth virus into thinking that it is already
  890. installed.  However, the destination of the far jump falls within the same MCB
  891.  
  892.                                  - Page 13 - 
  893.  
  894.  
  895. as the interrupt vector.  We can modify the test as follows:
  896.  
  897.         1) check for a suspicious instruction, such as a far jump, at the
  898.            beginning of the interrupt handler;
  899.         2) get the destination address of the jump or call;
  900.         3) if the destination of the jump is above the memory limit (defined
  901.            as the maximum of DOS and BIOS memory), the redirection is valid;
  902.         4) else if the interrupt handler and the destination of the jump fall
  903.            within the same memory block, the redirection is valid, otherwise
  904.            it is invalid.
  905.  
  906.  
  907.  
  908.  
  909.  
  910.  
  911.  
  912.  
  913.  
  914.  
  915.  
  916.  
  917.  
  918.  
  919.  
  920.  
  921.  
  922.  
  923.  
  924.  
  925.  
  926.  
  927.  
  928.  
  929.  
  930.  
  931.  
  932.  
  933.  
  934.  
  935.  
  936.  
  937.  
  938.  
  939.  
  940.  
  941.  
  942.  
  943.  
  944.  
  945.  
  946.  
  947.  
  948.  
  949.  
  950.  
  951.  
  952.  
  953.  
  954.                                  - Page 14 - 
  955.  
  956.  
  957.                              How CRCSET.EXE Works
  958.  
  959.         CRCSET.EXE, provided with this package, calculates the CRC of a file
  960. and stores it either in the file itself or in a separate external file.
  961.  
  962.         The idea of storing a program's CRC in the executable file itself has
  963. one drawback: since the CRC is part of the program, it becomes part of the
  964. data stream that is used to calculate the CRC.  In other words, you have to
  965. know what the CRC of the program is in order to calculate it!  At compile and
  966. link time, this is downright impossible; changing the slightest thing in your
  967. code will change the CRC the next time you recompile.
  968.  
  969.         Most algorithms that store the CRC in the program itself get around
  970. this drawback by breaking up the program into three chunks:
  971.  
  972.            +------------------------+-----+------------------------+
  973.            | <-- Program part 1 --> | CRC | <-- Program part 2 --> |
  974.            +------------------------+-----+------------------------+
  975.  
  976. The CRC is then calculated as the concatenation of parts 1 and 2, i.e. when
  977. the CRC is calculated, it skips over itself completely in the calculation.
  978. What it sees is this:
  979.  
  980.               +------------------------+------------------------+
  981.               | <-- Program part 1 --> | <-- Program part 2 --> |
  982.               +------------------------+------------------------+
  983.  
  984.         In order for a virus to infect any program that uses this method, it
  985. must somehow find the location of the CRC within the file and recalculate the
  986. CRC using the following data stream:
  987.  
  988.       +------------------------+------------------------+---------------+
  989.       | <-- Program part 1 --> | <-- Program part 2 --> | <-- Virus --> |
  990.       +------------------------+------------------------+---------------+
  991.  
  992. It must then overwrite the old CRC with the new one.
  993.  
  994.         I won't explain how (I don't want to give any virus-writers any
  995. ideas), but with the right technique the CRC can be found, recalculated, and
  996. rewritten in under 30 seconds.
  997.  
  998.         CRCSET overcomes this limitation by making both the polynomial and the
  999. CRC part of the data stream.  In order to calculate the CRC, CRCSET looks for
  1000. a predefined string in the program (the default is _STEALTH), replaces the
  1001. first four bytes with a 32-bit polynomial, sets the next four bytes (the true
  1002. CRC) to 0, and calculates an intermediate CRC assuming that the true CRC is 0.
  1003. Then, through the magic of matrix algebra, CRCSET calculates what the true CRC
  1004. should have been in order to yield itself instead of the intermediate CRC at
  1005. the end.  Let's take a look at a 4-bit CRC calculation as an example.
  1006.  
  1007.         Let's assume that the polynomial in use is 1011, that the CRC
  1008. calculated up to the point where we reach the search string (represented by
  1009. the bit pattern STUVWXYZ) is 0010, and that the bit pattern 1100 follows the
  1010. search string:
  1011.  
  1012.  
  1013.  
  1014.  
  1015.  
  1016.                                  - Page 15 - 
  1017.  
  1018.  
  1019.                ------------1-----------0-----------1-----------1
  1020.                |     3     |     2           1     |     0     |
  1021.                |   -----   v   -----       -----   v   -----   v
  1022.                + <-| 0 |<- + <-| 0 |<------| 1 |<- + <-| 0 |<- +
  1023.                ^   -----       -----       -----       -----
  1024.                |
  1025.                ---- STUVWXYZ1100
  1026.  
  1027. 1. Replace the first four bits (STUV) with the CRC polynomial (1011):
  1028.  
  1029.                ------------1-----------0-----------1-----------1
  1030.                |     3     |     2           1     |     0     |
  1031.                |   -----   v   -----       -----   v   -----   v
  1032.                + <-| 0 |<- + <-| 0 |<------| 1 |<- + <-| 0 |<- +
  1033.                ^   -----       -----       -----       -----
  1034.                |
  1035.                ---- 1011WXYZ1100
  1036.  
  1037. 2. Calculate the value of the CRC register with the polynomial in the data
  1038.    stream:
  1039.  
  1040.                ------------1-----------0-----------1-----------1
  1041.                |     3     |     2           1     |     0     |
  1042.                |   -----   v   -----       -----   v   -----   v
  1043.                + <-| 1 |<- + <-| 0 |<------| 0 |<- + <-| 1 |<- +
  1044.                ^   -----       -----       -----       -----
  1045.                |
  1046.                ---- WXYZ1100
  1047.  
  1048. 3. Replace the next four bits (WXYZ) with simple variables (X3, X2, X1, X0):
  1049.  
  1050.                ------------1-----------0-----------1-----------1
  1051.                |     3     |     2           1     |     0     |
  1052.                |   -----   v   -----       -----   v   -----   v
  1053.                + <-| 1 |<- + <-| 0 |<------| 0 |<- + <-| 1 |<- +
  1054.                ^   -----       -----       -----       -----
  1055.                |
  1056.                ---- (X3)(X2)(X1)(X0)1100
  1057.  
  1058. 4. Propagate X3+(bit 3) through the feedback loop:
  1059.  
  1060.            ---------------1-----------0------------1--------------1
  1061.            |     3        |     2           1      |     0        |
  1062.            |   --------   v   -----       ------   v   --------   v
  1063.            + <-| X3+1 |<- + <-| 0 |<------| X3 |<- + <-| X3+1 |<- +
  1064.            ^   --------       -----       ------       --------
  1065.            |
  1066.            ---- (X2)(X1)(X0)1100
  1067.  
  1068.  
  1069.  
  1070.  
  1071.  
  1072.  
  1073.  
  1074.  
  1075.  
  1076.  
  1077.  
  1078.                                  - Page 16 - 
  1079.  
  1080.  
  1081. 5. Propagate X2+(bit 3) through the feedback loop:
  1082.  
  1083.         ------------------1------------0------------1-----------------1
  1084.         |     3           |     2            1      |     0           |
  1085.         |   -----------   v   ------       ------   v   -----------   v
  1086.         + <-| X3+X2+1 |<- + <-| X3 |<------| X2 |<- + <-| X3+X2+1 |<- +
  1087.         ^   -----------       ------       ------       -----------
  1088.         |
  1089.         ---- (X1)(X0)1100
  1090.  
  1091.    In bit 1, for example, we have (X2+(bit 3))+(bit 0) = (X2+X3+1)+(X3+1) = X2
  1092.    since the X3 terms cancel, no matter what the value of X3 is.
  1093.  
  1094. 6. Propagate X1+(bit 3) through the feedback loop:
  1095.  
  1096.         ------------------1------------0------------1--------------------1
  1097.         |     3           |     2            1      |     0              |
  1098.         |   -----------   v   ------       ------   v   --------------   v
  1099.         + <-| X2+X1+1 |<- + <-| X2 |<------| X1 |<- + <-| X3+X2+X1+1 |<- +
  1100.         ^   -----------       ------       ------       --------------
  1101.         |
  1102.         ---- (X0)1100
  1103.  
  1104. 7. Propagate X0+(bit 3) through the feedback loop:
  1105.  
  1106.      ------------------1------------0---------------1--------------------1
  1107.      |     3           |     2            1         |     0              |
  1108.      |   -----------   v   ------       ---------   v   --------------   v
  1109.      + <-| X1+X0+1 |<- + <-| X1 |<------| X3+X0 |<- + <-| X2+X1+X0+1 |<- +
  1110.      ^   -----------       ------       ---------       --------------
  1111.      |
  1112.      ---- 1100
  1113.  
  1114. 8. Propagate the next bit through the feedback loop:
  1115.  
  1116.          -------------1---------------0--------------1---------------1
  1117.          |     3      |     2               1        |     0         |
  1118.          |   ------   v   ---------       --------   v   ---------   v
  1119.          + <-| X0 |<- + <-| X3+X0 |<------| X2+1 |<- + <-| X1+X0 |<- +
  1120.          ^   ------       ---------       --------       ---------
  1121.          |
  1122.          ---- 100
  1123.  
  1124. 9. Repeat step 8 for all remaining bits:
  1125.  
  1126.      ---------------------1---------------0--------------1---------------1
  1127.      |     3              |     2               1        |     0         |
  1128.      |   --------------   v   ---------       --------   v   ---------   v
  1129.      + <-| X3+X2+X1+1 |<- + <-| X3+X0 |<------| X2+1 |<- + <-| X3+X2 |<- +
  1130.      ^   --------------       ---------       --------       ---------
  1131.      |
  1132.      ----
  1133.  
  1134.  
  1135.  
  1136.  
  1137.  
  1138.  
  1139.  
  1140.                                  - Page 17 - 
  1141.  
  1142.  
  1143.         We want the CRC in the register to be equal to the unknown CRC we
  1144. started inserting at step 4, i.e. we need:
  1145.  
  1146.                      N   Value calculated for bit N  Bit N
  1147.                     ---  --------------------------  -----
  1148.                      3      X3 + X2 + X1      + 1   =  X3
  1149.                      2      X3           + X0       =  X2
  1150.                      1           X2           + 1   =  X1
  1151.                      0      X3 + X2                 =  X0
  1152.  
  1153. If we collect all the variables on the left and all the constants on the
  1154. right (keeping in mind that we are dealing with modulo-2 arithmetic):
  1155.  
  1156.                                   X2 + X1      = 1
  1157.                              X3 + X2      + X0 = 0
  1158.                                   X2 + X1      = 1
  1159.                              X3 + X2      + X0 = 0
  1160.  
  1161. The value 1010 is the intermediate CRC mentioned earlier.
  1162.  
  1163.         Here we have an interesting situation.  The first and third equations
  1164. are the same and so are the second and fourth.  What we come down to is this:
  1165.  
  1166.                                   X2 + X1      = 1
  1167.                              X3 + X2      + X0 = 0
  1168.  
  1169. We have four variables and only two equations.  There is no unique solution;
  1170. in fact, there are four (2 to the power of (4 - number of independent
  1171. equations)) separate and distinct sets of values that will satisfy these
  1172. equations.
  1173.  
  1174.         Since CRCSET needs a numeric solution, we have to arbitrarily set bits
  1175. to get one.  For arguments sake, let's set X2 to 1.
  1176.  
  1177.                                    1 + X1      = 1
  1178.                              X3 +  1      + X0 = 0
  1179.  
  1180. In other words:
  1181.  
  1182.                                        X1      = 0
  1183.                              X3 +         + X0 = 1
  1184.  
  1185. By setting X2 to 1, we have also fixed X1.  Now let's set X0 to 0.
  1186.  
  1187.                              X3 +         +  0 = 1
  1188.  
  1189. In other words:
  1190.  
  1191.                              X3                = 1
  1192.  
  1193. We now have a solution for the CRC of the program: 1100.  There are three
  1194. others: 0101, 0010, and 1011.  If we replace the string WXYZ with any of these
  1195. values, the CRC calculation process will yield that value at the end, e.g.:
  1196.  
  1197.  
  1198.  
  1199.  
  1200.  
  1201.  
  1202.                                  - Page 18 - 
  1203.  
  1204.  
  1205.                ------------1-----------0-----------1-----------1
  1206.                |     3     |     2           1     |     0     |
  1207.                |   -----   v   -----       -----   v   -----   v
  1208.                + <-| 0 |<- + <-| 0 |<------| 1 |<- + <-| 0 |<- +
  1209.                ^   -----       -----       -----       -----
  1210.                |
  1211.                ---- 101111001100
  1212.                         ----
  1213.  
  1214. yields
  1215.  
  1216.                ------------1-----------0-----------1-----------1
  1217.                |     3     |     2           1     |     0     |
  1218.                |   -----   v   -----       -----   v   -----   v
  1219.                + <-| 1 |<- + <-| 1 |<------| 0 |<- + <-| 0 |<- +
  1220.                ^   -----       -----       -----       -----
  1221.                |
  1222.                ----
  1223.  
  1224. If you're not sure about this, try it with pen and paper.  Plug in each of the
  1225. four values and you should get that same value at the end of the CRC
  1226. calculation process.  To help you out, here are the values of the CRC register
  1227. for each step of the solution (the first value is the value after step 2 of
  1228. the calculation):
  1229.  
  1230.            CRC
  1231.           -----
  1232.           1100: 1001, 0010, 1111, 0101, 1010, 0100, 0011, 0110, 1100
  1233.           0101: 1001, 1001, 0010, 0100, 0011, 1101, 1010, 1111, 0101
  1234.           0010: 1001, 1001, 1001, 0010, 0100, 0011, 1101, 0001, 0010
  1235.           1011: 1001, 0010, 0100, 0011, 1101, 1010, 0100, 1000, 1011
  1236.  
  1237.         The fact that there is not a unique solution isn't really important;
  1238. only about 30% of the time will there be a unique solution.  This does not
  1239. diminish the effectiveness of the CRC calculation because whichever of the
  1240. four values the CRC is set to, any virus installing itself in the program will
  1241. still change it.  The fact that we did not get a unique solution does mean,
  1242. however, that it is possible to get the following situation:
  1243.  
  1244.                                   X2 + X1      = 1
  1245.                              X3 + X2      + X0 = 1
  1246.                                   X2 + X1      = 1
  1247.                              X3 + X2      + X0 = 0
  1248.  
  1249. Here equations 2 and 4 contradict each other.  There are no values of X3 to X0
  1250. that will satisfy these equations.  If the CRCSET program comes across this
  1251. situation, it will simply try again with another polynomial.
  1252.  
  1253.         For illustration, I have used only a 4-bit CRC; the CRCSET algorithm
  1254. uses 32 bits.  The principle is the same; it just takes more time (and ink,
  1255. paper, patience, caffeine, pizza, and chocolate chip cookies).
  1256.  
  1257.         Since a software package often consists of more than just a single
  1258. executable, CRCSET has also been given the ability to calculate the CRC's for
  1259. other support files.  It can store the CRC's in either an external data file
  1260. or in the main program file itself.  If the CRC's are to be stored in the main
  1261. program file, CRCSET still searches for the _STEALTH string.  The CRC's for
  1262. all the other files on the command line are calculated and written in the
  1263.  
  1264.                                  - Page 19 - 
  1265.  
  1266.  
  1267. order that the files were specified to the locations immediately after the
  1268. _STEALTH string.  Once all the files have been exhausted, the CRC for the main
  1269. program file itself is calculated using the above technique.
  1270.  
  1271.         To be sure that CRCSET doesn't overwrite anything critical in your
  1272. application, you have to define an array of polynomials and CRC's in your
  1273. program large enough to accommodate all the files in your package for which
  1274. you want to do a self-check.  This is outlined in the next section.
  1275.  
  1276.  
  1277.  
  1278.  
  1279.  
  1280.  
  1281.  
  1282.  
  1283.  
  1284.  
  1285.  
  1286.  
  1287.  
  1288.  
  1289.  
  1290.  
  1291.  
  1292.  
  1293.  
  1294.  
  1295.  
  1296.  
  1297.  
  1298.  
  1299.  
  1300.  
  1301.  
  1302.  
  1303.  
  1304.  
  1305.  
  1306.  
  1307.  
  1308.  
  1309.  
  1310.  
  1311.  
  1312.  
  1313.  
  1314.  
  1315.  
  1316.  
  1317.  
  1318.  
  1319.  
  1320.  
  1321.  
  1322.  
  1323.  
  1324.  
  1325.  
  1326.                                  - Page 20 - 
  1327.  
  1328.  
  1329.                          How to Use Stealth Bomber - C
  1330.  
  1331.         This code was written under Borland C++ 3.0 and Microsoft C 5.1.
  1332.  
  1333.         Add the files SYSCHECK.C, DOSMCB.C, FILECHCK.C, CALCCRC.C, VIRUSDAT.C,
  1334. and BUFALLOC.C to the list of files required to build the program you are
  1335. working on (in Turbo C++, for example, add them to the project file).
  1336.  
  1337.         To perform a system check, add a call to stealth_sys_check() somewhere
  1338. in your program, preferably before you install any interrupt handlers.  The
  1339. function stealth_sys_check() returns a bit pattern composed of the following
  1340. flags:
  1341.  
  1342.         - STEALTH_INTR_ERR (0x0001) if interrupts have been set beyond the
  1343.           program's code space,
  1344.         - STEALTH_DOS_MEM_ERR (0x0002) if DOS memory is inconsistent with BIOS
  1345.           memory, and
  1346.         - STEALTH_DOS_HIJACKED (0x0004) if any interrupt has been hijacked by
  1347.           a JMP FAR or CALL FAR instruction.
  1348.  
  1349. The function returns STEALTH_OK if all tests pass.
  1350.  
  1351.         To check files, add a call to stealth_file_check(filename, filecrc)
  1352. for every file you want to verify.  If the file name contains a drive and/or
  1353. directory, the name is taken as is.  If the file name does not contain a drive
  1354. or directory specifier, the file is searched for first in the program's home
  1355. directory and then, if not found, in the DOS PATH.  The function
  1356. stealth_file_check() returns a bit pattern composed of the following flags:
  1357.  
  1358.         - STEALTH_FILE_ERR (0x0001) if the file was not found or couldn't be
  1359.           opened,
  1360.         - STEALTH_FILE_DATE_ERR (0x0002) if the file's date/time stamp was
  1361.           invalid,
  1362.         - STEALTH_FILE_SIZE_ERR (0x0004) if the file size was inconsistent
  1363.           between directory and file open checks,
  1364.         - STEALTH_CRC_BAD_POLY (0x0008) if the CRC polynomial is invalid,
  1365.         - STEALTH_NO_MEM (0x0010) if there was no memory to perform the CRC
  1366.           check, and
  1367.         - STEALTH_CRC_INVALID (0x0020) if the CRC is invalid.
  1368.  
  1369. The function returns STEALTH_OK if all tests pass.
  1370.  
  1371.         Return values and function prototypes are defined in the header file
  1372. VIRCHECK.H.
  1373.  
  1374.         This version of CRCSET provides two ways to store the CRC.  The first
  1375. is to store the CRC of each file that you want to protect in one of the
  1376. executables, which can then take care of validating the entire package before
  1377. loading any of the other files.  This executable would be the "primary file"
  1378. discussed below.
  1379.  
  1380.         To do this, you would have to declare an array of type filecrc large
  1381. enough to hold all of the CRC's; no checking can be done by the CRCSET program
  1382. to prevent it from overwriting critical data if the array isn't large enough.
  1383. The simplest way to declare this array is to change the STEALTH_NFILES
  1384. constant in VIRUSDAT.C to match the number of files in your project.  Leave
  1385. the rest of the file as it is; the C compiler will automatically fill in the
  1386. rest of the array with zeros.  When CRCSET is run, it will calculate the CRC
  1387.  
  1388.                                  - Page 21 - 
  1389.  
  1390.  
  1391. for each program in the list and store it in the primary file.  It will then
  1392. calculate the CRC for the primary file using the matrix algebra above and
  1393. write it to the first element of the array (at index 0).
  1394.  
  1395.         The second way to store the CRC data is in an external data file.  The
  1396. data file is specified to CRCSET on the command line and each CRC is written
  1397. to that file in sequence.  The data file overwrites any file of the same name
  1398. and the CRC for the data file is not calculated.  To perform a file check, you
  1399. would first have to read the CRC data from the data file and then call
  1400. stealth_file_check() with the appropriate file name and CRC from the data
  1401. file.
  1402.  
  1403.         To validate only the running program, the following call in main()
  1404. should suffice:
  1405.  
  1406.     stealth_file_check(_osmajor >= 3 ? argv[0] : "progname.exe", _fcrc[0])
  1407.  
  1408. where _fcrc is declared in VIRUSDAT.C.
  1409.  
  1410.         Under DOS 3.0 and above, the program name is stored in argv[0].  If
  1411. the program is running under DOS 2.x, you have to explicitly pass the program
  1412. name to the function and hope that it is in the path and hasn't been renamed
  1413. by the user.
  1414.  
  1415.         A sample program TESTVIR.C has been provided.  The syntax required to
  1416. set the CRC's for TESTVIR.EXE and its supporting files is in the header of
  1417. TESTVIR.C.  It demonstrates all the functions and uses of Stealth Bomber and
  1418. can be used as a framework for your own programs.
  1419.  
  1420.         If you run TESTVIR before running CRCSET on it, TESTVIR will abort
  1421. with a warning that it and its supporting files may have been infected.  After
  1422. you set the CRC, run TESTVIR to assure yourself that the CRC's are valid.
  1423.  
  1424.         One final note: in order for these routines to work properly, they
  1425. must be compiled with word alignment off.  If you compile with word alignment
  1426. on, modules that use DOSMCB will have the wrong layout for the MCB (i.e. the
  1427. MCB will be off by one byte).
  1428.  
  1429.  
  1430.  
  1431.  
  1432.  
  1433.  
  1434.  
  1435.  
  1436.  
  1437.  
  1438.  
  1439.  
  1440.  
  1441.  
  1442.  
  1443.  
  1444.  
  1445.  
  1446.  
  1447.  
  1448.  
  1449.  
  1450.                                  - Page 22 - 
  1451.  
  1452.  
  1453.                    How to Use Stealth Bomber -  Turbo Pascal
  1454.  
  1455.         This code was written under Turbo Pascal 5.5.
  1456.  
  1457.         Add the VIRCHECK unit to the "Uses" clause somewhere in your program.
  1458.  
  1459.         To perform a system check, add a call to StealthSysCheck somewhere in
  1460. your program, preferably before you install any interrupt handlers.  The
  1461. function StealthSysCheck returns a bit pattern composed of the following
  1462. flags:
  1463.  
  1464.         - StealthIntrErr ($0001) if interrupts have been set beyond the
  1465.           program's code space,
  1466.         - StealthDOSMemErr ($0002) if DOS memory is inconsistent with BIOS
  1467.           memory, and
  1468.         - StealthDOSHijacked ($0004) if any interrupt has been hijacked by a
  1469.           JMP FAR or CALL FAR instruction.
  1470.  
  1471. The function returns StealthOK if all tests pass.
  1472.  
  1473.         To check files, add a call to StealthFileCheck(FileName, FileCRC) for
  1474. every file you want to verify.  If the file name contains a drive and/or
  1475. directory, the name is taken as is.  If the file name does not contain a drive
  1476. or directory specifier, the file is searched for first in the program's home
  1477. directory and then, if not found, in the DOS PATH.  The function
  1478. StealthFileCheck returns a bit pattern composed of the following flags:
  1479.  
  1480.         - StealthFileErr ($0001) if the file was not found or couldn't be
  1481.           opened,
  1482.         - StealthFileDateErr ($0002) if the file's date/time stamp was
  1483.           invalid,
  1484.         - StealthFileSizeErr ($0004) if the file size was inconsistent between
  1485.           directory and file open checks,
  1486.         - StealthCRCBadPoly ($0008) if the CRC polynomial is invalid,
  1487.         - StealthNoMem ($0010) if there was no memory to the CRC check, and
  1488.         - StealthCRCInvalid ($0020) if the CRC is invalid.
  1489.  
  1490. The function returns StealthOK if all tests pass.
  1491.  
  1492.         This version of CRCSET provides two ways to store the CRC.  The first
  1493. is to store the CRC of each file that you want to protect in one of the
  1494. executables, which can then take care of validating the entire package before
  1495. loading any of the other files.  This executable would be the "primary file"
  1496. discussed below.
  1497.  
  1498.         To do this, you would have to declare an array of type FileCRC large
  1499. enough to hold all of the CRC's; no checking can be done by the CRCSET program
  1500. to prevent it from overwriting critical data if the array isn't large enough.
  1501. The simplest way to declare this array is to change the StealthNFiles constant
  1502. in VIRUSDAT.PAS to match the number of files in your project and to fill in
  1503. the rest of the array with the lines shown in VIRUSDAT.PAS to match the size
  1504. of the array.  When CRCSET is run, it will calculate the CRC for each program
  1505. in the list and store it in the primary file.  It will then calculate the CRC
  1506. for the primary file using the matrix algebra above and write it to the first
  1507. element of the array (at index 1).
  1508.  
  1509.         The second way to store the CRC data is in an external data file.  The
  1510. data file is specified to CRCSET on the command line and each CRC is written
  1511.  
  1512.                                  - Page 23 - 
  1513.  
  1514.  
  1515. to that file in sequence.  The data file overwrites any file of the same name
  1516. and the CRC for the data file is not calculated.  To perform a file check, you
  1517. would first have to read the CRC data from the data file and then call
  1518. StealthFileCheck with the appropriate file name and CRC from the data file.
  1519.  
  1520.         To validate only the running program, the following call in your main
  1521. module should suffice:
  1522.  
  1523. if Lo(DosVersion) >= 3 then
  1524.   Result := StealthFileCheck(ParamStr(0), _FCRC[1])
  1525. else
  1526.   Result := StealthFileCheck('progname.exe', _FCRC[1]);
  1527.  
  1528. where _FCRC is declared in VIRUSDAT.PAS.
  1529.  
  1530.         Under DOS 3.0 and above, the program name is stored in ParamStr(0).
  1531. If the program is running under DOS 2.x, you have to explicitly pass the
  1532. program name to the function and hope that it is in the path and hasn't been
  1533. renamed by the user.
  1534.  
  1535.         A sample program TESTVIR.PAS has been provided.  The syntax required
  1536. to set the CRC's for TESTVIR.EXE and its supporting files is in the header of
  1537. TESTVIR.PAS.  It demonstrates all the functions and uses of Stealth Bomber and
  1538. can be used as a framework for your own programs.
  1539.  
  1540.         If you run TESTVIR before running CRCSET on it, TESTVIR will abort
  1541. with a warning that it and its supporting files may have been infected.  After
  1542. you set the CRC, run TESTVIR to assure yourself that the CRC's are valid.
  1543.  
  1544.         One final note: the CRC routines try to allocate a buffer for reading
  1545. the file and adjust the size of the buffer to match the amount of free memory.
  1546. For this to work properly (i.e. without aborting with a run-time error of not
  1547. enough memory), you will have to install a heap error handler (look up
  1548. HeapError in the index of the "Turbo Pascal Reference Guide").  The example
  1549. file TESTVIR.PAS has a simple handler installed.
  1550.  
  1551.  
  1552.  
  1553.  
  1554.  
  1555.  
  1556.  
  1557.  
  1558.  
  1559.  
  1560.  
  1561.  
  1562.  
  1563.  
  1564.  
  1565.  
  1566.  
  1567.  
  1568.  
  1569.  
  1570.  
  1571.  
  1572.  
  1573.  
  1574.                                  - Page 24 - 
  1575.  
  1576.  
  1577.                         CRCSET.EXE Syntax and Messages
  1578.  
  1579.         Once you have compiled your program, you have to calculate its CRC.
  1580. The program CRCSET.EXE has been provided for this purpose.  The syntax is:
  1581.  
  1582. crcset [-q] [-s search string] [-p primary file | -d data file] [file]
  1583.        [file] ... [-s search string] ...
  1584. -q            = run quiet and redirect messages and errors to files.
  1585. search string = string to search for when writing CRC to a primary file.
  1586. primary file  = primary file, usually an executable, to which to write its own
  1587.                 CRC and the CRC of all "file" parameters that follow.
  1588. data file     = data file to which to write the CRC of all "file" parameters
  1589.                 that follow; overwrites any file of the same name.
  1590. file          = file for which to calculate the CRC; if no data or primary
  1591.                 file has been specified, the CRC is written to this file.
  1592.  
  1593. Files are processed in groups.  Specifying a new search string, primary file,
  1594. or data file closes the current group and starts a new one.
  1595.  
  1596.         The string for which CRCSET searches is stored in _fcrc[0] in C and
  1597. _FCRC[1] in Turbo Pascal.  The default is _STEALTH but you may change it if
  1598. there is a conflict (i.e. if there is more than one instance of _STEALTH in
  1599. the program, CRCSET will not know which one holds the CRC and so will not set
  1600. it).  CRCSET replaces the string with a randomly-generated polynomial and the
  1601. CRC itself and adds the polynomials and CRC's of any other files in the group
  1602. after the location of the search string.
  1603.  
  1604.         For example, to set the CRC for the C sample program, the command is:
  1605.  
  1606.             crcset -p testvir.exe testvir.obj -d crc.dat testvir.c
  1607.  
  1608. This will write the CRC of testvir.obj to _fcrc[1], testvir.exe to _fcrc[0],
  1609. and testvir.c to the file CRC.DAT.  The object and source files are shown here
  1610. as examples of supporting files for which you may want to run a CRC check.
  1611. Supporting files could be files like overlays, dynamic link libraries, or
  1612. configuration files.
  1613.  
  1614.         If you want to test the reliability of the CRC check, change a few
  1615. bytes in TESTVIR.EXE, TESTVIR.OBJ, or TESTVIR.C (TESTVIR.C is the safest).
  1616. Run TESTVIR again, and it should warn you that one of the files may have been
  1617. infected.
  1618.  
  1619.         If you changed the default search string to something like MyName, you
  1620. would set the CRC's as follows:
  1621.  
  1622.        crcset -s MyName -p testvir.exe testvir.obj -d crc.dat testvir.c
  1623.  
  1624. The case of the string on the command line must match exactly the case of the
  1625. string in the program.  Also, any strings shorter than 8 characters must be
  1626. padded with 0's (ASCII 0, not the character '0') in the program.
  1627.  
  1628.         The quiet option ('-q') is present principally for developers.  Some
  1629. packages store the user's name and registration number in the executable
  1630. itself.  If the executable has previously had CRCSET run on it, writing this
  1631. information will change the CRC.  The quiet option allows CRCSET to run
  1632. without displaying any messages on the screen; normal output goes to
  1633. CRCSET.OUT and error messages go to CRCSET.ERR.  CRCSET will return an error
  1634. code to DOS if anything goes wrong so your installation program can verify
  1635.  
  1636.                                  - Page 25 - 
  1637.  
  1638.  
  1639. that everything worked correctly.
  1640.  
  1641.         To use the quiet option, your package should be distributed _without_
  1642. having had CRCSET run on it.  I recommend that you change the default search
  1643. string to a jumble of numbers, letters, and punctuation characters to reduce
  1644. the chance of anyone using the search string as part of the registration
  1645. information.  In the installation procedure, you would first write the user
  1646. information to the executable and then run CRCSET with the quiet option to set
  1647. the CRC for your program and its supporting files.  See the license on page 2
  1648. for restrictions on using Stealth Bomber in this way.
  1649.  
  1650.         Despite its complexity, CRCSET.EXE takes only a few seconds to
  1651. calculate the CRC of the target file.  I have made some optimizations to the
  1652. algorithm that make the calculation time almost constant regardless of the
  1653. size of the file.  Once a CRC has been determined for your program, it takes
  1654. little time for the validation function to verify it every time the program is
  1655. run.
  1656.  
  1657.         CRCSET will display any of the following messages.  These messages,
  1658. when run with the quiet option, will appear either in CRCSET.OUT or
  1659. CRCSET.ERR.
  1660.  
  1661.         File=[file], polynomial=1234abcd, CRC=5678ef90.
  1662.  
  1663.                 The CRC for [file] under the polynomial 1234abcd is 5678ef90.
  1664.                 (CRCSET.OUT)
  1665.  
  1666.         File=[file], polynomial=1234abcd, CRC=5678ef90 (unique).
  1667.  
  1668.                 The CRC for [file] under the polynomial 1234abcd is 5678ef90.
  1669.                 This message is for a primary file specified with the '-p'
  1670.                 option.  The CRC shown is a unique solution for the matrix.
  1671.                 This will occur only about 30% of the time.  (CRCSET.OUT)
  1672.  
  1673.         File=[file], polynomial=1234abcd, CRC=5678ef90 (2^N solutions).
  1674.  
  1675.                 The CRC for [file] under the polynomial 1234abcd is 5678ef90.
  1676.                 This message is for a primary file specified with the '-p'
  1677.                 option.  The CRC shown is not a unique solution; there are 2^N
  1678.                 possible solutions to the matrix.  This does not diminish the
  1679.                 effectiveness of the CRC.  (CRCSET.OUT)
  1680.  
  1681.         Quiet option must be the first option specified.
  1682.  
  1683.                 The option '-q', if specified at all, should be specified
  1684.                 first.  (CRCSET.ERR)
  1685.  
  1686.         No files specified for processing.
  1687.  
  1688.                 No files were passed on the command line for CRC calculation.
  1689.                 (CRCSET.ERR)
  1690.  
  1691.         No search string specified for -s option.
  1692.  
  1693.                 The '-s' option was specified without a parameter.
  1694.                 (CRCSET.ERR)
  1695.  
  1696.         No data file name specified for '-d' option.
  1697.  
  1698.                                  - Page 26 - 
  1699.  
  1700.  
  1701.                 The '-d' option was specified without a parameter.
  1702.                 (CRCSET.ERR)
  1703.  
  1704.         Invalid option -X.
  1705.  
  1706.                 This is a catch-all for any option that CRCSET doesn't
  1707.                 recognize.  (CRCSET.ERR)
  1708.  
  1709.         File [file] not found.
  1710.  
  1711.                 The file specified for processing doesn't exist or couldn't be
  1712.                 opened.  (CRCSET.ERR)
  1713.  
  1714.         Primary file [file] not found.
  1715.  
  1716.                 The primary file specified for processing doesn't exist or
  1717.                 couldn't be opened.  (CRCSET.ERR)
  1718.  
  1719.         Unable to create data file [file].
  1720.  
  1721.                 The data file couldn't be created.  Either a file of the same
  1722.                 name exists and has the DOS read-only bit set or the file name
  1723.                 has invalid characters in it.  (CRCSET.ERR)
  1724.  
  1725.         Unable to allocate buffer for file [file].
  1726.  
  1727.                 There was not enough memory to allocate a read buffer for the
  1728.                 file.  (CRCSET.ERR)
  1729.  
  1730.         Unable to allocate buffer for primary file [file].
  1731.  
  1732.                 There was not enough memory to allocate a read buffer for the
  1733.                 primary file.  (CRCSET.ERR)
  1734.  
  1735.         Search string [search string] not found in file [file].
  1736.  
  1737.                 The search string (usually "_STEALTH") was not found in the
  1738.                 primary file.  To fix this, either add VIRUSDAT.C to the
  1739.                 project or add VIRUSDAT.PAS to the "uses" clause.  Also make
  1740.                 sure that the search string passed with the '-s' option, if
  1741.                 any, is correct.  (CRCSET.ERR)
  1742.  
  1743.         Search string [search string] found more than once in file [file].
  1744.  
  1745.                 The search string (usually "_STEALTH") was found more than
  1746.                 once in the primary file.  To fix this, change the default
  1747.                 search string in VIRUSDAT.C or VIRUSDAT.PAS and pass the new
  1748.                 search string to CRCSET with the '-s' option.  (CRCSET.ERR)
  1749.  
  1750.  
  1751.  
  1752.  
  1753.  
  1754.  
  1755.  
  1756.  
  1757.  
  1758.  
  1759.  
  1760.                                  - Page 27 - 
  1761.  
  1762.  
  1763.                                  Vulnerability
  1764.  
  1765.         The Stealth Bomber algorithm, like every other anti-virus algorithm,
  1766. is vulnerable to attack.  Hand-tweaking the code to bypass the virus
  1767. protection is always possible.  Direct attack to determine the storage
  1768. location of the polynomial and the CRC and to change it is also possible, but,
  1769. on a program of any reasonable size (greater than 20k), this can take upwards
  1770. of half an hour on a 386.  Any virus that ties up the computer for that long
  1771. wins no points for discretion.  Any user that doesn't do anything about a
  1772. system lockup lasting over 30 seconds probably has many other doors open for
  1773. viruses anyway.  :-)
  1774.  
  1775.         Viruses have a two advantages: they are loaded first before the
  1776. program can perform a self-check and the virus writers have access to my code
  1777. whereas I don't have access to theirs.
  1778.  
  1779.         The first advantage can be pretty well overcome by using an anti-virus
  1780. sentinel program that constantly monitors a system for suspicious activity.
  1781. Most people still don't use them, hence the need for this code.  The second
  1782. advantage I can do nothing about; by explaining my anti-virus methods and
  1783. distributing the source, I leave things wide open for attack.  Build a better
  1784. mousetrap and someone is bound to build a better mouse.  For as long as the
  1785. vandal mentality exists, we're stuck with viruses.
  1786.  
  1787.         Stealth Bomber performs only the most basic memory check and only
  1788. checks the files you specify to it.  As a result, a virus already in memory
  1789. that has come in from another program or possibly from the boot sector of the
  1790. disk will probably not be detected.
  1791.  
  1792.         There is no substitute for proper precautions: downloading from a
  1793. reputable BBS, avoiding pirated software, scanning programs for viruses before
  1794. using them, and so on.  This program was developed with the knowledge that
  1795. most people don't take these precautions (based on a sample size of at least 1
  1796. - me); rather than leave it up to the end user to protect against viruses,
  1797. with this we programmers can take on some of the burden by protecting the
  1798. programs we write against them.
  1799.  
  1800.  
  1801.  
  1802.  
  1803.  
  1804.  
  1805.  
  1806.  
  1807.  
  1808.  
  1809.  
  1810.  
  1811.  
  1812.  
  1813.  
  1814.  
  1815.  
  1816.  
  1817.  
  1818.  
  1819.  
  1820.  
  1821.  
  1822.                                  - Page 28 - 
  1823.  
  1824.