Minotauro Magazine #7:

                  System File Tables y Job File Tables
                                Por Trurl


    La SFT (Sistem File Table) es una estructura indocumentada que el DOS
utiliza para hacer todo el manejo de files (ya sea por handles o por FCB),
y la JFT (Job File Table, o tambi‚n File Handle Table) es otra estructura
del DOS, utilizada para asociar handles y SFTs. En este articulo les voy a
explicar el Donde, Como, Cuando y Porque de las SFT y JFT, para que ustedes
puedan divertirse con ellas en sus virus.

JFT - JOB FILE TABLES (O FILE HANDLE TABLES)
    La Job File Table, o File Handle Table, se encuentra la mayor¡a de las
veces en el offset 18h del PSP. (quiz  en sus tablas lo encuentren como una
zona indocumentada). En el offset 34h esta el llamado "Handle Table
Address" que no es mas que un puntero far a la JFT. Y en el offset 32h van
a encontrar un word, llamado "Handle Count" que es el m ximo posible de
entradas dentro de la JFT. (20 por defecto, pero puede variar).
    El Handle Table Address y el Handle Count no son de demasiada impor-
tancia. Est n para que uno pueda, si quiere, cambiar la JFT de lugar, y
agregarle mas handles (mas de los que el sistema en principio podr¡a
aguantar: esto no quiere decir que uno puede abrir mas files que los del
FILES= del CONFIG, sino que puede abrirlos mas VECES. El FILES= determina
el n£mero m ximo de SFTs del sistema, que no varia). A partir de DOS 3.3 no
es necesario siquiera hacerlo a mano, pues existe una funci¢n especifica
para cambiar la JFT de lugar (AH=67h/INT 21h).
    Ahora bien, la JFT es una tabla de (por default) 20 bytes. Cada byte,
es una entrada. Un "handle" com£n y corriente, de un file abierto, sirve
como ¡ndice en esta tabla. Y de ella extraemos un n£mero, que no es mas que
un ¡ndice dentro de las System File Tables del DOS, para encontrar la SFT
de nuestro file. (llamado a veces "System File Number", SFN).
    Veamos un ejemplo. Yo abro dos veces el file "ABRIME.TXT", obteniendo
2 handles: 0005, y 0006. Luego abro un segundo file "ABRIME2.TXT", y
obtengo un handle 0007. Luego me fijo en el PSP:

    PSP:34 -> nos da un address, que es por lo general PSP:18

    offset handle contenido  descripci¢n
    PSP:18 0000   ÚÄÄÄÄ<01   STDIN
    PSP:19 0001   ÃÄÄÄÄ<01   STDOUT
    PSP:1A 0002   ÃÄÄÄÄ<01   STDERR
    PSP:1B 0003   ³ÚÄÄÄ<00   AUX I/O
    PSP:1C 0004   ³³ÚÄÄ<02   LSTOUT
    PSP:1D 0005   ³³³ÚÄ<03   FILE "ABRIME.TXT", primer handle
    PSP:1E 0006   ³³³ÃÄ<03   FILE "ABRIME.TXT", segundo handle
    PSP:1F 0007   ³³³³Ú<04   FILE "ABRIME2.TXT", primer handle
    PSP:20 0008   ³³³³³ FF   handle invalido
    PSP:.. ....   ³³³³³ FF   ...
    PSP:2C 0014   ³³³³³ FF   handle invalido
                  ³³³³³
                  ³³³³³ SFTs
                  ³ÀÅÅÅ>0    AUX
                  ÀÄÅÅÅ>1    CON
                    ÀÅÅ>2    PRN
                     ÀÅ>3    ABRIME.TXT
                      À>4    ABRIME2.TXT

    Como vemos, STDIN, STDOUT, Y STDERR est n los tres direccionados hacia
la misma SFT, que es la 1, y corresponde al device CON. A su vez, el handle
3 (AUX I/O) esta direccionado al device AUX, y el LSTOUT, al device PRN. Y
LOS DOS HANDLES que el DOS me dio por las dos veces que abr¡ ABRIME.TXT
est n direccionados a la misma SFT: la 3, mientras que la 4 corresponde al
file ABRIME.TXT. Adem s, esto nos permite entender que es lo que pasa
cuando hacemos una redirecci¢n en l¡nea de comandos: si yo pongo PROGRAMA
>SALIDA.TXT, en el offset 1 de la JFT en vez de haber un 1, habr  alg£n
otro n£mero, lo cual significa que STDOUT estar  redireccionado a alguna
SFT correspondiente al file SALIDA.TXT, en lugar de estar direccionado a
CON.
    En definitiva la JFT no tiene ning£n uso por si misma: sirve para
encontrar la SFT de un file :-).

SFT - SYSTEM FILE TABLES
    El DOS mantiene todos los datos relevantes al manejo de files y
devices en estas dos tablas. La primera es para device drivers y files
abiertos v¡a handle, y la segunda para FCB. Las tablas no tienen diferen-
cias entre si, excepto en un par de detalles. La incre¡ble variedad y
abundancia de datos de todos tipo que hay en este tabla hace que en
realidad tenga un amplio espectro de aplicaci¢n, que se la pueda usar para
infinidad de cosas. El £nico aspecto negativo es que es indocumentada, y
por lo tanto no se sabe que pasara con ella en el futuro.
    La direcci¢n de las dos listas de tablas (la de handle y la de FCB) se
encuentra en la list of lists, en los offset 4 y 22h respectivamente.

SFT - FORMATO (Sacado de la NG de Ralph Brown obviamente)
Format of DOS 4.0-6.0 system file tables and FCB tables
Offset Size    Description
00h   DWORD   pointer to next file table (offset FFFFh if last)
04h   WORD    number of files in this table
06h  3Bh bytes per file
  Offset  Size    Description
   00h    WORD    number of file handles referring to this file
                  FFFF if in use but not referenced
   02h    WORD    file open mode (see AH=3Dh)
            bit 15 set if this file opened v¡a FCB
   04h    BYTE    file attribute (see AX=4301h)
   05h    WORD    device info word (see also AX=4400)
       bit 15 set if remote file
       bit 14 set means do not set file time/date 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 if local)
       bits 6-0 as for AX=4400h
   07h    DWORD   pointer to device driver header if character device
       else pointer to DOS Drive Parameter Block (see AH=32h)
       or REDIR data
   0Bh    WORD    starting cluster of file (local files only)
   0Dh    WORD    file time in packed format (see AX=5700h)
   0Fh    WORD    file date in packed format (see AX=5700h)
   11h    DWORD   file size
   15h    DWORD   current offset in file (SFT)
          LRU counters (FCB tables, two WORDs)
  ---local file---
   19h    WORD    relative cluster within file of last cluster accesed
   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 (no path/period, blank-padded)
   2Bh    DWORD   (SHARE.EXE) pointer to previous SFT sharing same file
   2Fh    WORD    (SHARE.EXE) network machine number wich opened file
          (Windows Enhanced mode DOSMGR uses the virtual machine
       ID as the machine number, see INT 2F/AX=1683h)
   31h    WORD    PSP segment of file's owner (see AH=26) (first three
       entries for AUX/CON/PRN contain segment of IO.SYS
       startup code)
   33h    WORD    offset within SHARE.EXE segment of
       sharing record (see above)  0000h = none
   35h    WORD    (local) absolute cluster number of last clustr accessed
       (redirector) ???
   37h    DWORD   pointer to IFS driver for file, 0000000h if native DOS

Note:  the OS/2 2.0 DOS Boot Session does not properly fill in the filename
    field due to incomplete support for SFTs; the OS/2 2.0 DOS Window
    does not appear to support SFTs at all

SFT - ENCONTRANDOLAS
    Hay una sola forma de encontrar la SFT de un file: Primero conseguir
el SFN y luego usarlo dentro de las SFT del DOS para encontrar la que
queremos. Esto a su vez puede hacerse de dos maneras.
    La primera es a mano: Obteniendo el segmento del PSP (mediante
AH=62/INT 21, o directamente en DS, depende), y dentro de ‚l buscar la JFT
y de ah¡ sacar el SFN del file. Luego conseguir la direcci¢n de las SFT
(mediante la "List of Lists", AH=52/INT 21) e ir recorri‚ndolas hasta
llegar al n£mero de tabla deseado. Las SFT est n organizadas en bloques:
cada bloque puede contener varias tablas y puede haber varios bloques. El
puntero presente en la "List of Lists" nos lleva al primer bloque. Cada
bloque tiene un header de 6 bytes, donde los 4 primeros son un puntero far
al siguiente bloque (siendo -1 el offset en el caso de que sea el £ltimo),
y la ultima word contiene el n£mero de tablas en el bloque. Ver el siguien-
te c¢digo:

findsft: ; encontrando la SFT de un handle "a mano"
; entrada: bx=handle
; salida: carry=1, invalid handle, si carry=0, ES:BX->SFT
    mov di, bx
    mov ah, 62h
    int 21h
    mov es, bx
    les bx, es:[34h]
    mov al, es:[bx+di]
    cbw
    cmp ax, -1
    jz invalidhandle
    push ax
    mov ah, 52h
    int 21h
    pop ax
    cwd
    les bx, es:[bx+4] ; handle SFT
goon:
    add dx, word ptr es:[bx+4]
    cmp dx, ax
    jng nextblock
    sub dx, word ptr es:[bx+4]
    sub ax, dx
    mov cx, ax
    add bx, 6
    jcxz noloop
addit:
    add bx, 3bh
    loop addit
noloop:
    clc
    ret
    ; es:bx -> SFT
nextblock:
    les bx, es:[bx]
    jmp goon
invalidhandle:
    stc
    ret

    La otra forma es la f cil: usando funciones no documentadas que hagan
todo por nosotros. La funci¢n AX=1220 de INT 2F retorna, a partir de un
handle dado, el address absoluto de la entrada de la JFT particular para
ese handle. A partir de ah¡, con una instrucci¢n, obtenemos el SFN. Luego
hay otra funci¢n, AX=1216h tambi‚n de INT 2F, que retorna el address de la
SFT para un SFN particular. Todo hecho. Ver el siguiente c¢digo:

findsft: ; finding it the easy way
    ; bx=handle
    mov ax, 1220h  ; obtenemos la entrada particular dentro de
    int 2fh        ; la JFT para el file en ES:BX
    xor bx, bx
    mov bl, es:[bx] ; cargamos en BX el SFN
    mov ax, 1216h  ; obtenemos el address de la SFT del file
    int 2fh
    ; ES:DI->SFT

    La desventaja de buscar la SFT a mano es que es mucho c¢digo en
comparaci¢n al otro. En cambio, lo malo de la INT 2F es que es indocumenta-
da, y no muy confiable (es que el c¢digo ha sido usado tanto que, por
ejemplo, el TBAV 6.24 detectaba el c¢digo mas arriba de INT 2F como el
Darth Vader. Osea, el c¢digo mas arriba constitu¡a la STRING DEL DARTH
VADER para el TBAV 6.24. En el 6.30 me consta que lo han solucionado, pero
personalmente me da mala espina :-)). Por otro lado, en todo otro aspecto
las dos v¡as son totalmente similares. Queda en cada uno usar la que mas le
convenga.

SFT - USOS
    Como se puede ver en la tabla, hay tantos datos distintos que la SFT
puede ser £til para muchas cosas. Por ejemplo, un uso practico de todos los
d¡as en virus, puede ser la cuesti¢n de infectar Read Only o evitar la
modificaci¢n de la fecha de un file al infectar. En lugar de usar AH=57 y
AH=43, puede abrirse el file solo para lectura, y luego cambiarse el modo
de apertura en la SFT a r/w (con esto se puede infectar Read Only sin
cambiarle los atributos, con la ventaja de que algunos AV residentes no se
mosquean si uno abre un ejecutable solo para lectura), y luego cambiar el
bit 14 del word en el offset 5, haciendo que no se actualice la fecha/hora
del file.
    Otros usos mucho mas complicados e interesantes son posibles. Por
ejemplo, el amigo Bugs Bunny en su virus mas reciente, el Oktubre, que
incluir¡amos en este n£mero, utiliza la SFT para hacer un stealth del tipo
disinfect-on-the-fly. Lo que hace Bugs es abrir el file cuando se lo piden,
pero restarle el largo del virus al size reportado en la SFT: de esta
forma, la ultima parte del file (que contiene al virus) no existe para el
sistema; no se la puede acceder. Eso, y una sencilla intercepci¢n para
evitar que lean el principio del file (donde hay un JMP o un Header
modificado), y hacer que lean en su lugar lo que originalmente all¡ hab¡a,
hace que efectivamente, el virus sea full stealth. Y ahora, a mirar la
tabla y usar la imaginaci¢n!
                                                          Trurl, tgc [DAN]

Nota: Quisiera agradecer a Fernando Bonsembiante por la amable nota de mi
virus EMMA aparecida en un reciente n£mero de su revista Virus Report.
Procuraremos seguir publicando virus experimentales para seguir d ndote
material para un par de notas mas, y para que nos sigas promocionando y
haciendo famosos, cosa que nos merecemos, por cierto. :-). (sarcasm is my
middle name)

-------------------------------------------------------------------------------
Nota2: La nota 1 fue escrita antes de que se oficialize la muerte de VR, que
por cierto lamentamos profundamente (?) ;) ahora fuera de joda, una cagada
que no salga mas, pero bueno, no todo se puede en la vida: ser amigo de Fabian
Garcia y robar con la VR, que mas podias pedir ? :-)