home *** CD-ROM | disk | FTP | other *** search
/ Phoenix Rising BBS / phoenixrising.zip / phoenixrising / vir-docs / 40hex-09.arj / 40HEX-9.008 < prev    next >
Text File  |  1992-12-31  |  7KB  |  186 lines

  1. 40Hex Number 9 Volume 2 Issue 5                                       File 008
  2.  
  3.                      ─────────────────────────────────────
  4.                      CODE OPTIMISATION, A BEGINNER'S GUIDE
  5.                      ─────────────────────────────────────
  6.                              Written by Dark Angel
  7.                      ─────────────────────────────────────
  8.   
  9.   When writing  a virus, size is a primary concern.  A bloated virus carrying
  10.   unnecessary baggage  will run slower than its optimised counterpart and eat
  11.   up more disk space.
  12.   
  13.   Never optimise  any code  before it  works fully, since altering code after
  14.   optimisation often  messes up  the optimisation and, in turn, messes up the
  15.   code.   After it works, the focus can shift to optimisation.  Always keep a
  16.   backup of  the last  working copy of the virus, as optimisation often leads
  17.   to improperly  working code.   With  this in  mind,  a  few  techniques  of
  18.   optimisation will be introduced.
  19.   
  20.   There are  two types  of optimisation:  structural and  local.   Structural
  21.   optimisation occurs  when shifting  the position  of code or rethinking and
  22.   reordering the functions of the virus shorten its length.  A simple example
  23.   follows:
  24.   
  25.   check_install:
  26.     mov ax,1234h
  27.     int 21h
  28.     cmp bx,1234h
  29.     ret
  30.   
  31.   install_virus:
  32.     call check_install
  33.     jz   exit_install
  34.   
  35.   If this  is the  only instance  that the procedure check_install is called,
  36.   the following optimisation may be made:
  37.   
  38.   install_virus:
  39.     mov ax,1234h
  40.     int 21h
  41.     cmp bx,1234h
  42.     jz  exit_install
  43.   
  44.   The first fragment wastes a total of 4 bytes - 3 for the call and 1 for the
  45.   ret.   Four bytes  may not seem to be worth the effort, but after many such
  46.   optimisations, the  code size  may be  brought  down  significantly.    The
  47.   reverse of  this optimisation,  using procedures in lieu of repetitive code
  48.   fragments, may work in other instances.  Properly designed and well-thought
  49.   out  code  will  allow  for  such  an  optimisation.    Another  structural
  50.   optimisation:
  51.   
  52.   get attributes
  53.   open file read/only
  54.   read file
  55.   close file
  56.   exit if already infected
  57.   clear attributes
  58.   open file read/write
  59.   get file time/date
  60.   write new header
  61.   move file pointer to end of file
  62.   concatenate virus
  63.   restore file time/date
  64.   close file
  65.   restore attributes
  66.   exit
  67.   
  68.   Change the above to:
  69.   
  70.   get attributes
  71.   clear attributes
  72.   open file read/write
  73.   read file
  74.   if infected, exit to close file
  75.   get file time/date
  76.   move file pointer to end of file
  77.   concatenate virus
  78.   move file pointer to beginning
  79.   write new header
  80.   restore file time/date
  81.   close file
  82.   restore attributes
  83.   exit
  84.   
  85.   By using  the second,  an open  file and  a close file are eliminated while
  86.   adding only  one move file pointer request.  This can save a healthy number
  87.   of bytes.
  88.   
  89.   Local, or  peephole, optimisation  is often  easier to  do than  structural
  90.   optimisation.   It consists  of changing  individual  statements  or  short
  91.   groups of statements to save bytes.
  92.   
  93.   The easiest  type of  peephole optimisation  is a simple replacement of one
  94.   line with  a functional  equivalent that  takes  fewer  bytes.    The  8086
  95.   instruction set abounds with such possibilities.  A few examples follow.
  96.   
  97.   Perhaps the most widespread optimisation, replace:
  98.     mov ax,0 ; this instruction is 3 bytes long
  99.     mov bp,0 ; mov reg, 0 with any reg = nonsegment register takes 3 bytes
  100.   with
  101.     xor ax,ax ; this takes but 2 bytes
  102.     xor bp,bp ; mov reg, 0 always takes 2 bytes
  103.   or even
  104.     sub ax,ax ; also takes 2 bytes
  105.     sub bp,bp
  106.   
  107.   One of  the easiest  optimisations, yet often overlooked by novices, is the
  108.   merging of lines.  As an example, replace:
  109.     mov bh,5h   ; two bytes
  110.     mov bl,32h  ; two bytes
  111.                 ; total: four bytes
  112.   with
  113.     mov bx,532h ; three bytes, save one byte
  114.   
  115.   A very  useful optimisation  moving the  file handle from ax to bx follows.
  116.   Replace:
  117.     mov  bx,ax   ; 2 bytes
  118.   with
  119.     xchg ax,bx   ; 1 byte
  120.   
  121.   Another easy  optimisation which  can most  easily applied  to file pointer
  122.   moving operations:
  123.   Replace
  124.     mov ax,4202h  ; save one byte from "mov ah,42h / mov al,2"
  125.     xor dx,dx     ; saves one byte from "mov dx,0"
  126.     xor cx,cx     ; same here
  127.     int 21h
  128.   with
  129.     mov ax,4202h
  130.     cwd           ; equivalent to "xor dx,dx" when ax < 8000h
  131.     xor cx,cx
  132.     int 21h
  133.   
  134.   Sometimes it may be desirable to use si as the delta offset variable, as an
  135.   instruction  involving  [si]  takes  one  less  byte  to  encode  than  its
  136.   equivalent using  [bp].   This does  NOT work  with  combinations  such  as
  137.   [si+1].  Examples:
  138.   
  139.     mov  ax,[bp]                ; 3 bytes
  140.     mov  word ptr cs:[bp],1234h ; 6 bytes
  141.     add  ax,[bp+1]              ; 3 bytes - no byte savings will occur
  142.   
  143.     mov  ax,[si]                ; 2 bytes
  144.     mov  word ptr cs:[si],1234h ; 5 bytes
  145.     add  ax,[si+1]              ; 3 bytes - this is not smaller
  146.   
  147.   A somewhat strange and rather specialised optimisation:
  148.     inc al  ; 2 bytes
  149.     inc bl  ; 2 bytes
  150.   versus
  151.     inc ax  ; 1 byte
  152.     inc bx  ; 1 byte
  153.   
  154.   A structural  optimisation can  also involve getting rid of redundant code.
  155.   As a  virus related  example, consider  the  infection  routine.    In  few
  156.   instances is an error-trapping routine after each interrupt call necessary.
  157.   A single  "jc error" is needed, say after the first disk-writing interrupt,
  158.   and if  that succeeds, the rest should also work fine.  Another possibility
  159.   is to use a critical error handler instead of error checking.
  160.   
  161.   How about this example of optimised code:
  162.     mov  ax, 4300h   ; get file attributes
  163.     mov  dx, offset filename
  164.     int  21h
  165.   
  166.     push dx          ; save filename
  167.     push cx          ; and attributes on stack
  168.   
  169.     inc  ax          ; ax = 4301h = set file attributes
  170.     push ax          ; save 4301h on stack
  171.     xor  cx,cx       ; clear attributes
  172.     int  21h
  173.   
  174.   ...rest of infection...
  175.   
  176.     pop  ax          ; ax = 4301h
  177.     pop  cx          ; cx = original attributes of file
  178.     pop  dx          ; dx-> original filename
  179.     int  21h
  180.   
  181.   Optimisation is  almost always  code-specific.   Through a  combination  of
  182.   restructuring and  line replacement,  a  good  programmer  can  drastically
  183.   reduce the  size of  a virus.    By  gaining  a  good  feel  of  the  80x86
  184.   instruction set,  many more  optimisations may  be found.   Above all, good
  185.   program design will aid in creating small viruses.
  186.