40Hex Number 9 Volume 2 Issue 5                                       File 008

                    �������������������������������������
                    CODE OPTIMISATION, A BEGINNER'S GUIDE
                    �������������������������������������
                            Written by Dark Angel
                    �������������������������������������

 When writing  a virus, size is a primary concern.  A bloated virus carrying
 unnecessary baggage  will run slower than its optimised counterpart and eat
 up more disk space.

 Never optimise  any code  before it  works fully, since altering code after
 optimisation often  messes up  the optimisation and, in turn, messes up the
 code.   After it works, the focus can shift to optimisation.  Always keep a
 backup of  the last  working copy of the virus, as optimisation often leads
 to improperly  working code.   With  this in  mind,  a  few  techniques  of
 optimisation will be introduced.

 There are  two types  of optimisation:  structural and  local.   Structural
 optimisation occurs  when shifting  the position  of code or rethinking and
 reordering the functions of the virus shorten its length.  A simple example
 follows:

 check_install:
   mov ax,1234h
   int 21h
   cmp bx,1234h
   ret

 install_virus:
   call check_install
   jz   exit_install

 If this  is the  only instance  that the procedure check_install is called,
 the following optimisation may be made:

 install_virus:
   mov ax,1234h
   int 21h
   cmp bx,1234h
   jz  exit_install

 The first fragment wastes a total of 4 bytes - 3 for the call and 1 for the
 ret.   Four bytes  may not seem to be worth the effort, but after many such
 optimisations, the  code size  may be  brought  down  significantly.    The
 reverse of  this optimisation,  using procedures in lieu of repetitive code
 fragments, may work in other instances.  Properly designed and well-thought
 out  code  will  allow  for  such  an  optimisation.    Another  structural
 optimisation:

 get attributes
 open file read/only
 read file
 close file
 exit if already infected
 clear attributes
 open file read/write
 get file time/date
 write new header
 move file pointer to end of file
 concatenate virus
 restore file time/date
 close file
 restore attributes
 exit

 Change the above to:

 get attributes
 clear attributes
 open file read/write
 read file
 if infected, exit to close file
 get file time/date
 move file pointer to end of file
 concatenate virus
 move file pointer to beginning
 write new header
 restore file time/date
 close file
 restore attributes
 exit

 By using  the second,  an open  file and  a close file are eliminated while
 adding only  one move file pointer request.  This can save a healthy number
 of bytes.

 Local, or  peephole, optimisation  is often  easier to  do than  structural
 optimisation.   It consists  of changing  individual  statements  or  short
 groups of statements to save bytes.

 The easiest  type of  peephole optimisation  is a simple replacement of one
 line with  a functional  equivalent that  takes  fewer  bytes.    The  8086
 instruction set abounds with such possibilities.  A few examples follow.

 Perhaps the most widespread optimisation, replace:
   mov ax,0 ; this instruction is 3 bytes long
   mov bp,0 ; mov reg, 0 with any reg = nonsegment register takes 3 bytes
 with
   xor ax,ax ; this takes but 2 bytes
   xor bp,bp ; mov reg, 0 always takes 2 bytes
 or even
   sub ax,ax ; also takes 2 bytes
   sub bp,bp

 One of  the easiest  optimisations, yet often overlooked by novices, is the
 merging of lines.  As an example, replace:
   mov bh,5h   ; two bytes
   mov bl,32h  ; two bytes
               ; total: four bytes
 with
   mov bx,532h ; three bytes, save one byte

 A very  useful optimisation  moving the  file handle from ax to bx follows.
 Replace:
   mov  bx,ax   ; 2 bytes
 with
   xchg ax,bx   ; 1 byte

 Another easy  optimisation which  can most  easily applied  to file pointer
 moving operations:
 Replace
   mov ax,4202h  ; save one byte from "mov ah,42h / mov al,2"
   xor dx,dx     ; saves one byte from "mov dx,0"
   xor cx,cx     ; same here
   int 21h
 with
   mov ax,4202h
   cwd           ; equivalent to "xor dx,dx" when ax < 8000h
   xor cx,cx
   int 21h

 Sometimes it may be desirable to use si as the delta offset variable, as an
 instruction  involving  [si]  takes  one  less  byte  to  encode  than  its
 equivalent using  [bp].   This does  NOT work  with  combinations  such  as
 [si+1].  Examples:

   mov  ax,[bp]                ; 3 bytes
   mov  word ptr cs:[bp],1234h ; 6 bytes
   add  ax,[bp+1]              ; 3 bytes - no byte savings will occur

   mov  ax,[si]                ; 2 bytes
   mov  word ptr cs:[si],1234h ; 5 bytes
   add  ax,[si+1]              ; 3 bytes - this is not smaller

 A somewhat strange and rather specialised optimisation:
   inc al  ; 2 bytes
   inc bl  ; 2 bytes
 versus
   inc ax  ; 1 byte
   inc bx  ; 1 byte

 A structural  optimisation can  also involve getting rid of redundant code.
 As a  virus related  example, consider  the  infection  routine.    In  few
 instances is an error-trapping routine after each interrupt call necessary.
 A single  "jc error" is needed, say after the first disk-writing interrupt,
 and if  that succeeds, the rest should also work fine.  Another possibility
 is to use a critical error handler instead of error checking.

 How about this example of optimised code:
   mov  ax, 4300h   ; get file attributes
   mov  dx, offset filename
   int  21h

   push dx          ; save filename
   push cx          ; and attributes on stack

   inc  ax          ; ax = 4301h = set file attributes
   push ax          ; save 4301h on stack
   xor  cx,cx       ; clear attributes
   int  21h

 ...rest of infection...

   pop  ax          ; ax = 4301h
   pop  cx          ; cx = original attributes of file
   pop  dx          ; dx-> original filename
   int  21h

 Optimisation is  almost always  code-specific.   Through a  combination  of
 restructuring and  line replacement,  a  good  programmer  can  drastically
 reduce the  size of  a virus.    By  gaining  a  good  feel  of  the  80x86
 instruction set,  many more  optimisations may  be found.   Above all, good
 program design will aid in creating small viruses.

Downloaded From P-80 International Information Systems 304-744-2253