home *** CD-ROM | disk | FTP | other *** search
/ Hacker 2 / HACKER2.mdf / virus / ps_vir4.txt < prev    next >
Text File  |  1995-01-03  |  23KB  |  380 lines

  1.       //==//  //  //  /||      //      //====  //==//  //|   //
  2.      //  //  //  //  //||     //      //      //  //  //||  //
  3.     //==//  //==//  //=||    //      //      //  //  // || //
  4.    //      //  //  //  ||   //      //      //  //  //  ||//
  5.   //      //  //  //   ||  //====  //====  //==//  //   ||/
  6.   
  7.      /====   // //     //  /====   /|   /|
  8.     //      // //     //  //      //|  //|
  9.     ===\   // //     //   ===\   //|| //||
  10.       //  //  \\    //      //  // ||// ||
  11.   ====/  //    \\  //   ====/  //  ||/  ||
  12.   
  13.   ───────────────────────────────────────────
  14.   DISCLAIMER: This file is 100% guaranteed to
  15.     exist.  The author makes no claims to the
  16.     existence or nonexistence of the reader.
  17.   ───────────────────────────────────────────
  18.       This space intentionally left blank.
  19.   ───────────────────────────────────────────
  20.   GREETS: Welcome home, Hellraiser!  Hello to
  21.     the rest of the PHALCON/SKISM crew: Count
  22.     Zero, Demogorgon, Garbageheap, as well as
  23.     everyone else I failed to mention.
  24.   ───────────────────────────────────────────
  25.   
  26.   Dark Angel's Clumpy Virus Writing Guide
  27.   ──── ─────── ────── ───── ─────── ─────
  28.     "It's the cheesiest" - Kraft
  29.   
  30.   ──────────────────────────────────────
  31.   INSTALLMENT IV: RESIDENT VIRII, PART I
  32.   ──────────────────────────────────────
  33.   
  34.   Now that the topic of nonresident virii has been addressed, this series now
  35.   turns to  memory resident virii.  This installment covers the theory behind
  36.   this type  of virus,  although no  code  will  be  presented.    With  this
  37.   knowledge in  hand, you  can boldly  write memory  resident virii confident
  38.   that you are not fucking up too badly.
  39.   
  40.   ──────────
  41.   INTERRUPTS
  42.   ──────────
  43.   DOS kindly  provides us  with a powerful method of enhancing itself, namely
  44.   memory resident programs.  Memory resident programs allow for the extention
  45.   and alteration  of the normal functioning of DOS.  To understand how memory
  46.   resident programs  work, it  is necessary  to delve into the intricacies of
  47.   the interrupt  table.   The interrupt table is located from memory location
  48.   0000:0000 to  0000:0400h (or  0040:0000), just  below the  BIOS information
  49.   area.   It consists of 256 double words, each representing a segment:offset
  50.   pair.   When an interrupt call is issued via an INT instruction, two things
  51.   occur, in this order:
  52.   
  53.     1) The flags are pushed onto the stack.
  54.     2) A  far call  is issued  to the segment:offset located in the interrupt
  55.        table.
  56.   
  57.   To return  from an  interrupt, an  iret instruction  is  used.    The  iret
  58.   instruction reverses  the order  of the  int call.    It  performs  a  retf
  59.   followed by  a  popf.    This  call/return  procedure  has  an  interesting
  60.   sideeffect when  considering interrupt  handlers which return values in the
  61.   flags register.   Such handlers must directly manipulate the flags register
  62.   saved in the stack rather than simply directly manipulating the register.
  63.   
  64.   The processor  searches the  interrupt table for the location to call.  For
  65.   example, when  an interrupt  21h is  called,  the  processor  searches  the
  66.   interrupt table  to find  the address  of the  interrupt 21h  handler.  The
  67.   segment of this pointer is 0000h and the offset is 21h*4, or 84h.  In other
  68.   words, the interrupt table is simply a consecutive chain of 256 pointers to
  69.   interrupts, ranging  from interrupt 0 to interrupt 255.  To find a specific
  70.   interrupt handler,  load in  a double word segment:offset pair from segment
  71.   0, offset  (interrupt number)*4.  The interrupt table is stored in standard
  72.   Intel reverse double word format, i.e. the offset is stored first, followed
  73.   by the segment.
  74.   
  75.   For a  program to  "capture" an interrupt, that is, redirect the interrupt,
  76.   it must  change the  data in the interrupt table.  This can be accomplished
  77.   either by  direct manipulation of the table or by a call to the appropriate
  78.   DOS function.  If the program manipulates the table directly, it should put
  79.   this code  between a CLI/STI pair, as issuing an interrupt by the processor
  80.   while the  table is  half-altered could have dire consequences.  Generally,
  81.   direct manipulation  is the  preferable alternative,  since some  primitive
  82.   programs such  as FluShot+  trap the  interrupt 21h  call used  to set  the
  83.   interrupt and  will warn  the user  if any  "unauthorised" programs  try to
  84.   change the handler.
  85.   
  86.   An interrupt handler is a piece of code which is executed when an interrupt
  87.   is requested.  The interrupt may either be requested by a program or may be
  88.   requested by  the processor.   Interrupt  21h is  an example of the former,
  89.   while interrupt 8h is an example of the latter.  The system BIOS supplies a
  90.   portion of  the interrupt  handlers, with  DOS and other programs supplying
  91.   the rest.   Generally, BIOS interrupts range from 0h to 1Fh, DOS interrupts
  92.   range from 20h to 2Fh, and the rest is available for use by programs.
  93.   
  94.   When a  program wishes  to install  its own  code, it must consider several
  95.   factors.  First of all, is it supplanting or overlaying existing code, that
  96.   is to  say, is  there already an interrupt handler present?  Secondly, does
  97.   the program  wish to preserve the functioning of the old interrupt handler?
  98.   For example,  a program  which "hooks"  into the  BIOS clock tick interrupt
  99.   would definitely  wish to preserve the old interrupt handler.  Ignoring the
  100.   presence of  the old  interrupt handler  could lead  to disastrous results,
  101.   especially if previously-loaded resident programs captured the interrupt.
  102.   
  103.   A technique  used in  many interrupt  handlers is  called "chaining."  With
  104.   chaining, both  the new and the old interrupt handlers are executed.  There
  105.   are two primary methods for chaining: preexecution and postexecution.  With
  106.   preexecution chaining,  the old  interrupt handler is called before the new
  107.   one.   This is  accomplished via  a pseudo-INT  call consisting  of a pushf
  108.   followed by  a call  far ptr.   The new interrupt handler is passed control
  109.   when the  old one  terminates.   Preexecution chaining is used when the new
  110.   interrupt handler wishes to use the results of the old interrupt handler in
  111.   deciding the  appropriate action  to take.   Postexecution chaining is more
  112.   straightforward, simply  consisting of  a jmp  far ptr  instruction.   This
  113.   method doesn't  even require  an iret  instruction to be located in the new
  114.   interrupt handler!  When the jmp is executed, the new interrupt handler has
  115.   completed its  actions and  control is passed to the old interrupt handler.
  116.   This method  is used  primarily when  a program  wishes  to  intercept  the
  117.   interrupt call before DOS or BIOS gets a chance to process it.
  118.   
  119.   ────────────────────────────────────────
  120.   AN INTRODUCTION TO DOS MEMORY ALLOCATION
  121.   ────────────────────────────────────────
  122.   Memory allocation  is perhaps one of the most difficult concepts, certainly
  123.   the hardest to implement, in DOS.  The problem lies in the lack of official
  124.   documentation by  both Microsoft  and IBM.  Unfortunately, knowledge of the
  125.   DOS memory manager is crucial in writing memory-resident virii.
  126.   
  127.   When a  program asks DOS for more memory, the operating system carves out a
  128.   chunk of memory from the pool of unallocated memory.  Although this concept
  129.   is simple enough to understand, it is necessary to delve deeper in order to
  130.   have sufficient  knowledge to  write effective  memory-resident virii.  DOS
  131.   creates memory  control blocks  (MCBs) to  help itself  keep track of these
  132.   chunks of  memory.  MCBs are paragraph-sized areas of memory which are each
  133.   devoted to  keeping track of one particular area of allocated memory.  When
  134.   a program  requests memory,  one paragraph  for the  MCB  is  allocated  in
  135.   addition to  the memory  requested by  the program.   The  MCB lies just in
  136.   front of  the memory  it controls.   Visually,  a MCB  and its memory looks
  137.   like:
  138.   
  139.   ┌───────┬─────────────────────────────────────┐
  140.   │ MCB 1 │ Chunk o' memory controlled by MCB 1 │
  141.   └───────┴─────────────────────────────────────┘
  142.   
  143.   When a  second section  of memory is requested, another MCB is created just
  144.   above the memory last allocated.  Visually:
  145.   
  146.   ┌───────┬─────────┬───────┬─────────┐
  147.   │ MCB 1 │ Chunk 1 │ MCB 2 │ Chunk 2 │
  148.   └───────┴─────────┴───────┴─────────┘
  149.   
  150.   In other  words, the  MCBs are  "stacked" one  on top  of the other.  It is
  151.   wasteful to deallocate MCB 1 before MCB 2, as holes in memory develop.  The
  152.   structure for the MCB is as follows:
  153.   
  154.   Offset    Size Meaning
  155.   ────── ─────── ───────
  156.   0         BYTE 'M' or 'Z'
  157.   1         WORD Process ID (PSP of block's owner)
  158.   3         WORD Size in paragraphs
  159.   5      3 BYTES Reserved (Unused)
  160.   8      8 BYTES DOS 4+ uses this.  Yay.
  161.   
  162.   If the  byte at  offset 0 is 'M', then the MCB is not the end of the chain.
  163.   The 'Z'  denotes the  end of the MCB chain.  There can be more than one MCB
  164.   chain present  in memory  at once and this "feature" is used by virii to go
  165.   resident in high memory.  The word at offset 1 is normally equal to the PSP
  166.   of the  MCB's owner.   If  it is  0, it means that the block is free and is
  167.   available for  use by programs.  A value of 0008h in this field denotes DOS
  168.   as the  owner of  the block.   The  value at  offset 3 does NOT include the
  169.   paragraph allocated  for the  MCB.  It reflects the value passed to the DOS
  170.   allocation functions.   All  fields located after the block size are pretty
  171.   useless so you might as well ignore them.
  172.   
  173.   When a  COM file is loaded, all available memory is allocated to it by DOS.
  174.   When an  EXE file  is loaded,  the amount  of memory  specified in  the EXE
  175.   header is  allocated.   There is  both a  minimum and  maximum value in the
  176.   header.    Usually,  the  linker  will  set  the  maximum  value  to  FFFFh
  177.   paragraphs.  If the program wishes to allocate memory, it must first shrink
  178.   the main  chunk of  memory owned  by the  program to  the minimum required.
  179.   Otherwise, the pathetic attempt at memory allocation will fail miserably.
  180.   
  181.   Since programs  normally are  not supposed to manipulate MCBs directly, the
  182.   DOS memory  manager calls  (48h -  4Ah) all return and accept values of the
  183.   first program-usable  memory paragraph,  that is,  the paragraph  of memory
  184.   immediately after  the MCB.   It  is important  to keep  this in  mind when
  185.   writing MCB-manipulating code.
  186.   
  187.   ─────────────────────────
  188.   METHODS OF GOING RESIDENT
  189.   ─────────────────────────
  190.   There are a variety of memory resident strategies.  The first is the use of
  191.   the  traditional  DOS  interrupt  TSR  routines,  either  INT  27h  or  INT
  192.   21h/Function 31h.   These  routines are  undesirable  when  writing  virii,
  193.   because they  do not  return control  back to  the program after execution.
  194.   Additionally, they  show up  on "memory  walkers" such  as PMAP and MAPMEM.
  195.   Even a doorknob can spot such a blatant viral presence.
  196.   
  197.   The traditional  viral alternative  to using the standard DOS interrupt is,
  198.   of course, writing a new residency routine.  Almost every modern virus uses
  199.   a routine to "load high," that is, to load itself into the highest possible
  200.   memory location.   For  example, in  a 640K  system, the  virus would  load
  201.   itself just  under the  640K but above the area reserved by DOS for program
  202.   use.   Although this  is technically  not the high memory area, it shall be
  203.   referred to as such in the remainder of this file in order to add confusion
  204.   and general  chaos into this otherwise well-behaved file.  Loading high can
  205.   be easily accomplished through a series of interrupt calls for reallocation
  206.   and allocation.  The general method is:
  207.   
  208.   1.   Find the memory size
  209.   2.   Shrink the program's memory to the total memory size - virus size
  210.   3.   Allocate memory for the virus (this will be in the high memory area)
  211.   4.   Change the program's MCB to the end of the chain (Mark it with 'Z')
  212.   5.   Copy the virus to high memory
  213.   6.   Save the old interrupt vectors if the virus wishes to chain vectors
  214.   7.   Set the interrupt vectors to the appropriate locations in high memory
  215.   
  216.   When calculating  memory sizes,  remember that all sizes are in paragraphs.
  217.   The MCB  must also  be considered,  as it takes up one paragraph of memory.
  218.   The advantage  of this  method is  that it  does not, as a rule, show up on
  219.   memory walkers.  However, the total system memory as shown by such programs
  220.   as CHKDSK will decrease.
  221.   
  222.   A third alternative is no allocation at all.  Some virii copy themselves to
  223.   the memory just under 640K, but fail to allocate the memory.  This can have
  224.   disastrous consequences, as any program loaded by DOS can possibly use this
  225.   memory.   If it is corrupted, unpredictable results can occur.  Although no
  226.   memory loss  is shown  by CHKDSK,  the possible  chaos resulting  from this
  227.   method is  clearly unacceptable.   Some  virii use memory known to be free.
  228.   For example,  the top  of the  interrupt table or parts of video memory all
  229.   may be  used with  some assurance  that the  memory will  not be corrupted.
  230.   Once again, this technique is undesirable as it is extremely unstable.
  231.   
  232.   These techniques  are by  no means  the only  methods of residency.  I have
  233.   seen such  bizarre methods  as going  resident in  the  DOS  internal  disk
  234.   buffers.  Where there's memory, there's a way.
  235.   
  236.   It is  often desirable  to know  if the  virus is  already resident.    The
  237.   simplest method  of doing  this is  to write  a checking  function  in  the
  238.   interrupt handler  code.   For example, a call to interrupt 21h with the ax
  239.   register set  to 7823h  might  return  a  4323h  value  in  ax,  signifying
  240.   residency.   When using  this check,  it is  important to  ensure  that  no
  241.   possible conflicts  with either  other programs  or DOS  itself will occur.
  242.   Another method,  albeit a  costly process  in terms  of both  time and code
  243.   length, is  to check  each segment  in memory  for the  code indicating the
  244.   presence of the virus.  This method is, of course, undesirable, since it is
  245.   far, far  simpler to  code a  simple check  via the  interrupt handler.  By
  246.   using any  type of  check, the  virus need  not fear  going resident twice,
  247.   which would simply be a waste of memory.
  248.   
  249.   ─────────────
  250.   WHY RESIDENT?
  251.   ─────────────
  252.   Memory resident virii have several distinct advantages over runtime virii.
  253.      o Size
  254.        Memory resident virii are often smaller than their runtime brethern as
  255.        they do not need to include code to search for files to infect.
  256.      o Effectiveness
  257.        They are  often more  virulent, since  even the  DIR  command  can  be
  258.        "infected."   Generally, the standard technique is to infect each file
  259.        that is executed while the virus is resident.
  260.      o Speed
  261.        Runtime virii  infect before  a file is executed.  A poorly written or
  262.        large runtime  virus will  cause a  noticible delay  before  execution
  263.        easily spotted  by users.   Additionally,  it causes  inordinate  disk
  264.        activity which is detrimental to the lifespan of the virus.
  265.      o Stealth
  266.        The manipulation  of  interrupts  allows  for  the  implementation  of
  267.        stealth techniques,  such as  the hiding of changes in file lengths in
  268.        directory listings and on-the-fly disinfection.  Thus it is harder for
  269.        the average  user to detect the virus.  Additionally, the crafty virus
  270.        may even  hide from CRC checks, thereby obliterating yet another anti-
  271.        virus detection technique.
  272.   
  273.   ───────────────────────────────
  274.   STRUCTURE OF THE RESIDENT VIRUS
  275.   ───────────────────────────────
  276.   With the  preliminary information  out of  the way,  the discussion can now
  277.   shift to  more virus-related,  certainly  more  interesting  topics.    The
  278.   structure of  the memory resident virus is radically different from that of
  279.   the runtime virus.  It simply consists of a short stub used to determine if
  280.   the virus  is already  resident.   If it is not already in memory, the stuf
  281.   loads it  into memory through whichever method.  Finally, the stub restores
  282.   control to  the host  program.   The rest of the code of the resident virus
  283.   consists of interrupt handlers where the bulk of the work is done.
  284.   
  285.   The stub  is the only portion of the virus which needs to have delta offset
  286.   calculations.  The interrupt handler ideally will exist at a location which
  287.   will not  require such  mundane fixups.   Once  loaded, there  should be no
  288.   further use  of the  delta offset,  as the  location of  the  variables  is
  289.   preset.   Since the resident virus code should originate at offset 0 of the
  290.   memory block,  originate the source code at offset 0.  Do not include a jmp
  291.   to the  virus code  in the original carrier file.  When moving the virus to
  292.   memory, simply  move starting  from [bp+startvirus]  and the offsets should
  293.   work out  as they  are in  the source file.  This simplifies (and shortens)
  294.   the coding of the interrupt handlers.
  295.   
  296.   Several things  must be  considered in writing the interrupt handlers for a
  297.   virus.   First, the  virus must  preserve the registers.  If the virus uses
  298.   preexecution chaining,  it must  save the  registers after  the call to the
  299.   original handler.   If  the virus  uses  postexecution  chaining,  it  must
  300.   restore the original registers of the interrupt call before the call to the
  301.   original handler.   Second, it is more difficult, though not impossible, to
  302.   implement encryption  with memory  resident virii.   The problem is that if
  303.   the interrupt handler is encrypted, that interrupt handler cannot be called
  304.   before the  decryption function.  This can be a major pain in the ass.  The
  305.   cheesy way  out is  to simply  not include encryption.  I prefer the cheesy
  306.   way.   The noncheesy  readers out  there might  wish  to  have  the  memory
  307.   simultaneously hold  two copies  of the virus, encrypt the unused copy, and
  308.   use the  encrypted copy  as the  write buffer.   Of course, the virus would
  309.   then take twice the amount of memory it would normally require.  The use of
  310.   encryption is  a matter  of personal  choice and  cheesiness.  A sidebar to
  311.   preservation of interrupt handlers: As noted earlier, the flags register is
  312.   restored from  the stack.  It is important in preexecution chaining to save
  313.   the new  flags register  onto the  stack where  the old  flags register was
  314.   stored.
  315.   
  316.   Another important  factor to  consider  when  writing  interrupt  handlers,
  317.   especially those  of BIOS  interrupts, is  DOS's lack  of reentrance.  This
  318.   means that  DOS functions  cannot be  executed while DOS is in the midst of
  319.   processing an  interrupt request.   This  is because  DOS sets  up the same
  320.   stack pointer  each time it is called, and calling the second DOS interrupt
  321.   will cause  the processing  of one  to overwrite  the stack  of the  other,
  322.   causing  unpredictable,   but  often   terminal,  results.    This  applies
  323.   regardless of  which DOS  interrupts are  called, but it is especially true
  324.   for interrupt  21h, since  it is  often tempting  to use  it from within an
  325.   interrupt handler.   Unless  it is  certain that  DOS is  not processing  a
  326.   previous request,  do NOT  use a DOS function in the interrupt handler.  It
  327.   is possible  to use  the "lower"  interrupt 21h  functions without  fear of
  328.   corrupting the  stack, but  they are basically the useless ones, performing
  329.   functions easily  handled by  BIOS calls  or direct  hardware access.  This
  330.   entire discussion only applies to hooking non-DOS interrupts.  With hooking
  331.   DOS interrupts  comes the  assurance that  DOS is  not executing elsewhere,
  332.   since it  would then  be corrupting  its own  stack, which  would be a most
  333.   unfortunate occurence indeed.
  334.   
  335.   The most  common interrupt to hook is, naturally, interrupt 21h.  Interrupt
  336.   21h is called by just about every DOS program.  The usual strategy is for a
  337.   virus to  find potential files to infect by intercepting certain DOS calls.
  338.   The primary  functions to hook include the find first, find next, open, and
  339.   execute commands.   By  cleverly using  pre and  postexecution chaining,  a
  340.   virus can  easily find  the file  which was  found, opened, or executed and
  341.   infect it.   The  trick is simply finding the appropriate method to isolate
  342.   the filename.   Once that is done, the rest is essentially identical to the
  343.   runtime virus.
  344.   
  345.   When calling  interrupts hooked by the virus from the virus interrupt code,
  346.   make sure  that the  virus does  not trap  this particular  call,  lest  an
  347.   infinite loop  result.  For example, if the execute function is trapped and
  348.   the virus  wishes, for some reason, to execute a particular file using this
  349.   function, it  should NOT  use a  simple "int  21h" to do the job.  In cases
  350.   such as  this  where  the  problem  is  unavoidable,  simply  simulate  the
  351.   interrupt call with a pushf/call combination.
  352.   
  353.   The basic  structure of the interrupt handler is quite simple.  The handler
  354.   first screens  the registers  for either  an identification  call or  for a
  355.   trapped function  such as  execute.   If it  is not  one of  the above, the
  356.   handler throws control back to the original interrupt handler.  If it is an
  357.   identification request,  the handler  simply sets the appropriate registers
  358.   and returns  to the  calling program.   Otherwise, the virus must decide if
  359.   the request  calls for  pre or postexecution chaining.  Regardless of which
  360.   it uses,  the virus  must find  the filename  and use  that information  to
  361.   infect.   The filename  may be found either through the use of registers as
  362.   pointers or  by searching  thorugh certain  data structures,  such as FCBs.
  363.   The infection  routine is  the same  as that of nonresident virii, with the
  364.   exception of the guidelines outlined in the previous few paragraphs.
  365.   
  366.   ──────────────
  367.   WHAT'S TO COME
  368.   ──────────────
  369.   I apologise for the somewhat cryptic sentences used in the guide, but I'm a
  370.   programmer, not  a writer.   My  only suggestion is to read everything over
  371.   until it  makes sense.   I  decided to  pack this  issue of  the guide with
  372.   theory rather  than code.   In the next installment, I will present all the
  373.   code necessary to write a memory-resident virus, along with some techniques
  374.   which may be used.  However, all the information needed to write a resident
  375.   virii has  been included  in this  installment; it  is merely  a matter  of
  376.   implementation.  Have buckets o' fun!
  377.  
  378.  
  379. Downloaded From P-80 International Information Systems 304-744-2253
  380.