Virus Labs & Distribution
VLAD #2 - Assembly Guide


		   C O D E   O P T I M I Z A T I O N
			    An Assembly Guide
			       Written by
             D   A   R   K   M   A   N   /   V   L   A   D


-------------------------------------------------
Use the AL/AX register instead of other registers
-------------------------------------------------
  Sometimes it is more optimized to use the AL/AX register instead of the
other registers, comparing with registers could be done like this:

	     cmp     bx,1234h             ; Compare BX with 1234h (4 bytes)

A more optimized way of doing this is:

	     cmp     ax,1234h             ; Compare AX with 1234h (3 bytes)

  However this can ONLY be done when the AL/AX register DOESN'T hold an
important value, but if the AL/AX register is used many times it COULD
be more optimized to use it even if you have to PUSH it and then POP it
afterwards.

----------------------------------------------
Use the Data Segment instead of other segments
----------------------------------------------
  Moving a value from the memory to AX could be done like this:

	     mov     ax,es:[si]           ; Move ES:[SI] to AX (3 bytes)

A more optimized way of doing this is:

	     mov     ax,ds:[si]           ; Move DS:[SI] to AX (2 bytes)

----------------
Clear a register
----------------
  Clearing a register could be done like this:

	     mov     ax,00h              ; Clear AX (3 bytes)

A more optimized way of doing this is:

	     sub     ax,ax               ; Clear AX (2 bytes)

Or a equally optimized way of this is:

	     xor     ax,ax               ; Clear AX (2 bytes)

---------------------
Clear the DX register
---------------------
  Clearing the DX register could be done like this:

	     mov     dx,00h              ; Clear DX (3 bytes)

Or like this:

	     xor     dx,dx               ; Clear DX (2 bytes)

A more optimized way of doing this is:

	     cwd                         ; Convert word to doubleword (1 byte)

However this can ONLY be done if the AX register is less than 8000h.

---------------------------
Test if a register is clear
---------------------------
  Testing if a register is clear could be done like this:

	     cmp     ax,00h              ; AX = 0? (3 bytes)

A more optimized way of doing this is:

	     or      ax,ax               ; AX = 0? (2 bytes)

----------------------------------------------------
Use a 16 bit register instead of two 8 bit registers
----------------------------------------------------
  Moving a value to a 16 bit register could be done like this:

	     mov     ah,12h              ; Move 12h to AH (2 bytes)
	     mov     al,34h              ; Move 34h to AL (2 bytes)

A more optimized way of doing this is:

	     mov     ax,1234h             ; Move 1234h to AX (3 bytes)

However this can ONLY be done if the two 8 bit registers are the high and low
register of the same 16 bit register.

---------------------------------------------------------
Move the AL/AX register to another register or vice versa
---------------------------------------------------------
  Moving the AL/AX register to another register could be done like this:

	     mov     bx,ax               ; Move AX to BX (2 bytes)

A more optimized way of doing this is:

	     xchg    ax,bx               ; Exchange AX with BX (1 byte)

  However this can ONLY be done if the source registers value is unimportant
afterwards, because the source register will hold the destination registers
value.

-------------------------------
Use DI/SI as base instead of BP
-------------------------------
  Moving a value from the memory to AX could be done like this:

	     mov     ax,ds:[bp]           ; Move DS:[BP] to AX (3 bytes)

A more optimized way of doing this is:

	     mov     ax,ds:[si]           ; Move DS:[SI] to AX (2 bytes)

  If the DI/SI index is used many times it COULD be more optimized to used
the DI/SI index even if you have to PUSH it and then POP it afterwards.

--------------------------------------------------------
Use the CMPS, LODS, MOVS, SCAS, STOS and REP instuctions
--------------------------------------------------------
  Moving a value from the memory to AX could be done like this:

	     mov     ax,ds:[si]           ; Move DS:[SI] to AX (2 bytes)

A more optimized way of doing this is:

	     lodsw                        ; Load AX with DS:[DI] (1 bytes)

  Remember to clear/set the direction flag. Sometimes it COULD be more
optimized to use these instructions even if you have to PUSH and then POP the
used registers/segments afterwards.

---------------------------
Move a segment to a segment
---------------------------
  Moving a segment to a segment is weird, because you can't move a segment to
another segment directly by:

	     mov     ds,cs               ; Can't do this!

Because of that, you could use a register as a temporary storage, like this:

	     mov     ax,cs               ; Move CS to AX (2 bytes)
	     mov     ds,ax               ; Move AX to DS (2 bytes)

  But if an important value is held by the AX register, you have to PUSH and
the POP it afterwards, that would add the code by 2 bytes, a more optimized
way of doing this is:

	     push    cs                  ; Save CS at stack        (1 byte)
	     pop     ds                  ; Load DS from stack (CS) (1 byte)

-----------------------------------------------
Use SHL/SHR instead of the DIV/MUL instructions
-----------------------------------------------
  Multiplying AL with 2 could be done like this:

	     mov     bh,02h              ; Move 02h to BH (2 bytes)
	     mul     bh                  ; Multiply AL with BL (2 bytes)

A more optimized way of doing this is:

	     shl     al,01h              ; Multiply AL with 02h (2 bytes)

This can ONLY be used if the source can be divided by 2.


----------------------------------------
Use object codes instead of instructions
----------------------------------------
  A far call could be done like this:

	     call    far address         ; Make a far call (3 bytes)
address      dd      ?                   ; Address of a procedure (4 bytes)

A more optimized way of doing this is:

callfar      db      9ah                 ; Object code of a far call (1 byte)
address      dd      ?                   ; Address of a procedure (4 bytes)

This will ONLY optimize your code if the immediate value after the object 
code is a word or greater.

--------------
Use procedures
--------------
  If some code is used many times and it's size is large, it COULD be more
optimized to use it as a procedure, the following formula can calculate if
it is more optimized to use a procedure:

Bytes saved = (procedure size - 4) * number of invocations - procedure size

  Figure 4 in the parentheses of the formula is there because the size of the
CALL and RET instructions together are 4 bytes.

------------------------
Make procedures flexible
------------------------
  Make procedures flexible if possible, this CAN optimize your code, because
the redundant code is removed, a example from this is:

movefptrend  proc    near                 ; Move file pointer to the end
	     mov     al,02h               ;  "        "      "   "   "
movefileptr  proc    near                 ; Move file pointer to end/beginning
	     cwd                          ; Convert word to doubleword
movefpointer proc    near                 ; Move file pointer to a offset
	     xor     dx,dx                ; Clear DX
	     mov     ah,42h               ; Move file pointer
	     int     21h                  ; Do it!
	     ret                          ; Return!
	     endp
	     endp
	     endp

  Use the formula from above to calculate if the flexible procedures can be
used to optimize your code.

----------------------------------
Use all the information in the DTA
----------------------------------
  DTA (Disk Transfer Area) is used by service 4eh and 4fh in the DOS functions
interrupt (INT 21h), the contents of the DTA block are:

                ----------------------------------------
		Offset Size  Contents
                ----------------------------------------
		  00   Byte  Drive letter
		 01-0B Bytes Search template
		 0C-14 Bytes Reserved
		  15   Byte  File attribute
		 16-17 Word  File time
		 18-19 Word  File date
		 1A-1D DWord File size
		 1E-3A Bytes ASCIIZ filename + extension
                ----------------------------------------

- If your want to reset the files time and date afterwards, then use the
  DTA instead of service 57h in INT 21h.
- If you only want to infect one file, then change the drive letter to a
  illegal value instead of making redundant code in the exit part of the
  program, if you change the drive letter to a illegal value an error will
  occur.

However, this will ONLY optimize your code, if you are already using the DTA.

---------------------
Final tips and tricks
---------------------
- Remove all unnecessary NOPs
- Move your code around, to see if some JUMP NEAR instructions could be
  replaced by JUMP SHORT instructions etc.
- Don't use instructions to calculate values that can be calculated 
  directly in a parentheses.
- Use LEA instead of MOV OFFSET.
- Use the stack to store temporary data, but be careful if it is a COM file.
- Use the CBW instructions to clear the AH register if AL is less than 80h.
- Use DEC/INC instead of ADD/SUB register,01h.
- When using DEC/INC it is more optimized to use 16 bits registers rather 
  than 8 bit registers.



- VLAD #2 INDEX -

ARTICLE.1_1      

Introduction
ARTICLE.1_2       Aims and Policies
ARTICLE.1_3       Greets
ARTICLE.1_4       Members/Joining
ARTICLE.1_5       Dist/Contact Info
ARTICLE.1_6       Hidden Area Info
ARTICLE.1_7       Coding the Mag

ARTICLE.2_1      

The Press
ARTICLE.2_2       Leprechaun Interview
ARTICLE.2_3       Flash Bios
ARTICLE.2_4       AMI Flash Specification
ARTICLE.2_5       Assembly Guide
ARTICLE.2_6       Virus Law
ARTICLE.2_7       Feedback

ARTICLE.3_1      

Mail
ARTICLE.3_2       TSR Tutorial
ARTICLE.3_5       Kennedy Disasm
ARTICLE.3_6       Darth Vader Strain B Disasm
ARTICLE.3_7       Gergana.222 Disasm

ARTICLE.4_1      

Virus Descriptions
ARTICLE.4_2       VLAD Virus Source
ARTICLE.4_3       Republic Source
ARTICLE.4_4       BIOS Meningitis Source
ARTICLE.4_5       Prodigy 3 Source
ARTICLE.4_6       Estonia Source
ARTICLE.4_7       What's Next

ARTICLE.5_1      

About Debug Scripts
ARTICLE.5_2       VLAD Script
ARTICLE.5_3       Republic Script
ARTICLE.5_4       BIOS Meningitis Dropper Script
ARTICLE.5_5       Prodigy 3 Script
ARTICLE.5_6       Estonia Script
ARTICLE.5_7       The End

About VLAD - Links - Contact Us - Main