Insane Reality issue #8 - (c)opyright 1996 Immortal Riot/Genesis - REALITY.015 Article: SFT Stealth Author: MGL [SVL] % SFT-Stealth Tutorial by MGL/SVL % ___________________________________ The following is a technical tutorial by MGL of the Slovakian Virus Labratories. Needless to say, any stealth is good stealth, so read on. - _Sepultura_ ============================================================================= ----------------------------------------------------------------------------- The SFT-stealth tute by MGL/SVL aka bunch of notoric know ideas written for IR #8 ----------------------------------------------------------------------------- Well, this topic was some time ago discussed heavily on IRC, and as I promised to write some kind of idiot guide to this topic, here you have it. The dude, who finally forced me to write this, was Sep_IR [* Thats me ;) - sep *] As usual, if you can't code a memory resident virus, forget this article, it's high over your current abilities. If you 're AV, then as usual fork off :) .... ( or gimme a good payed job ) ---> A. What SFT is SFT stands for System File Table and it is some kind of DOS data structure used by DOS itself to handle all the access to the file opened both via FCB or via handle. As SFT is internal DOS data structure, it can , if modified, be very powerful and effective tool for any virus coder. According to 51st issue of Ralph's Interrupt List is structure of SFT as described bellow : 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 ----------- Here starts SFT entry for each handle ------------------ Offset Size Description 06h 00h WORD here point ES:DI after executing Get_SFT_Adress from section 1.1 number of file handles referring to this file FFFFh if in use but not referenced 08h 02h WORD file open mode (see AX=6C00h,#0715 at AH=3Dh) bit 15 set if this file opened via FCB 0Ah 04h BYTE file attribute (see #0731 at AX=4301h) 0Bh 05h WORD device info word (see also #0734 at AX=4400h) bit 15 set if remote file bit 14 set means do not 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 if local) bits 6-0 as for AX=4400h 0Dh 07h DWORD pointer to device driver header if character device else pointer to DOS Drive Parameter Block (see AH=32h) or REDIR data 11h 0Bh WORD starting cluster of file (local files only) 13h 0Dh WORD file time in packed format (see #0971) 15h 0Fh WORD file date in packed format (see #0972) 17h 11h DWORD file size 1Bh 15h DWORD current offset in file (SFT) LRU counters (FCB table, two WORDs) ---local file--- 1Fh 19h WORD relative cluster within file of last cluster accessed 21h 1Bh DWORD number of sector containing directory entry 25h 1Fh BYTE number of dir entry within sector (byte offset/32) ---network redirector--- 1Fh 19h DWORD pointer to REDIRIFS record 23h 1Dh 3 BYTEs ??? ------ 26h 20h 11 BYTEs filename in FCB format (no path/period, blank-padded) 31h 2Bh DWORD (SHARE.EXE) pointer to previous SFT sharing same file 35h 2Fh WORD (SHARE.EXE) network machine number which opened file (Windows Enhanced mode DOSMGR uses the virtual machine ID as the machine number; see INT 2F/AX=1683h) 37h 31h WORD PSP segment of file's owner (see #0691 at AH=26h) (first three entries for AUX/CON/PRN contain segment of IO.SYS startup code) 39h 33h WORD offset within SHARE.EXE code segment of sharing record (see #0902) 0000h = none 3Bh 35h WORD (local) absolute cluster number of last clustr accessed (redirector) ??? 3Dh 37h DWORD pointer to IFS driver for file, 0000000h if native DOS Note #1: 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 Note #2: all this stuff above is taken (and can be found) in Interrupt List under INT 21H subfunction 52h ---> B. How to get SFT entry Quit easy. All you need is file handle. Then you should execute piece of code like follows: Get_SFT_Entry_Adress proc near push ax ; save AX push bx ; save file handle mov ax,1220h int 2fh ; get Job File Table Entry (M$-Dos 3.0 and above) ; for actual handle jc error ; if CF set , can't proceed mov bl,es:[di] ; ES:DI points to JFT Entry for current handle cmp bl,0ffh ; if BL=0ffh, handle is not open je error ; otherwise BL holds SFT entry number mov ax,1216h ; get adress of SFT Entry int 2fh ; AX 'll be destroyed on ret jc error ; BX is greater than FILES= in config.sys clc ; ES:DI points to system file table entry error: pop bx ; procedure returns CF set if some error pop ax ; occured, otherwise CF is clear and ES:DI ret ; holds desired value. BX and AX 're ; not changed endp Note #3: All the stuff is also supported by DR-DOS 5.0+ Ofcos, if you use such a procedure for getting SFT entry, your virus can be easily fooled by ANY AV TSR which HOOKS and modifies INT 2F vector. You should call the original INT 2F vector ! Moreover, another danger is the procedure itself. Such a structure was used for 1st time (as far as i know) in Number of the Beast virus and shitload of scanners uses some part of this procedure as 'scanstring', and these INT 2F calls are suspicious for heuristic as well. So, you should at least hide this procedure behind the layer(s) of true polymorphic encryption. ---> C. Places of interest in SFT entry (for vx coders) Offset: 02h - WORD - indicates file open mode, the same as is used by INT 21H/3dh for file open. If you modify this field, you can force always R/W access. That's very interes- ting for any coder. You do not have to use the obvious and for heuristic quite sensitive code ala: lea dx,[filename_buffer] mov ax,3d02h call old_21_vector You can either use just mov ax,3d02h instead of mov ax,3d00h , or you can modify this field directly in SFT on need to change to desired value basis. Remember, bit 15 is set if the file was opened via FCB. Offset: 04h - BYTE - file attribute - the same rules as for INT 21h/43h. Here you can modify attribs at your will, but remember , you have to restore the original ones ! And if you modify the attribs by using the SFT, you have to restore it before you close the handle. If you don't, on file close are the attri- butes changed, and you can be catched by some lame integrity checker, or just per view in Norton Commander Offset: 0Dh - WORD - file time in packed format Offset: 0Fh - WORD - file date in packed format Here you can stealth time stamp, if you use it as 'mark' Offset: 11h - DWORD- file size - veery interesting value. If you subtract virus size from this DWORD, no one can LSEEK to the body of the virus. So you do not have to to handle INT 21/4202 at all. If your virus is full stealth, and i hope it is, you have to handle stealth on read and/or write access. Read is simple to handle: Read stealth: 1. Test, if read is from changed area of the file 2. If so, extend the file size (add virus size) 3. Put original stuff in their buffer 4. Subtract virus size But the most problematic thing to handle is write stealth. If you write to such a modified handle, the file 'll be corrupted, Fat chain 'll be damaged, etc ... If you want to handle this problem, structure of infected file should be like -------------------------------------------------------- | Header| F I L E | Virus body | Stored header | -------------------------------------------------------- where Header, resp. Stored headers stand for every piece of code, which virus changes, resp. saves when file is infected. Solution is then easy. Read stealth: 1. Extend file size (add virus size) 2. Read all the original saved stuff to some buffer in memory. 3. Move file pointer to the end of intected file 4. Cut the file to its uninfected size Order of steps 1-4 is critical and can't be changed ! 5. Fully disinfect the file, using the stuff stored in memory buffer 6. Allow their write 7. Reinfect file In my humble opinion, the right moment for reinfection is in this case the closing of the file. If you reinfect the file right after write to this file, you risk, in the case of multiple writes to file substantial slow down of the disk operations. Then you have to disinfect/reinfect the file as many times as the write operation is performed. If you reinfect on close, only one disinfection/reinfection is necessary. Note #4: It works ! :) Offset: 15h - DWORD - current offset in file (SFT). This is the same as file pointer. If you want to LSEEL to the start of the file put here 0, to LSEEK EOF, put here file size. If you do not use INT 21/42 , in some cases you can avoid heuristic detection. (In fact, use of SFT modification can be used as heuristic flag in the future too :( ) Offset: 20h - 11 BYTEs - filename in FCB format (no path/period, blank -padded). Here is the place, where you can test, is the file referred by handle is excutable or not. Just test 3 bytes starting at offset 28h for 'COM' or 'EXE' Offset: 31h - WORD - PSP segment of file's owner . The same value as you get by reading the word at PSP:16 or code like mov ah,62h ; mov ah,50h as well int 21h ; BX is PSP push bx pop ds mov dx,ds:[16h] ; parent's PID = PSP of parent ; process ---> D. Conclusions - SFT stealth is powerfull if used correctly - SFT stealth on write can be used. Moreover it's possible to avoid the file corruption. - SFT allows to test if file referred by handle is excutable - SFT use can substitute some DOS INT 21H calls ( subfunctions 3dh,42h,43h, 51h,62h and more ) - SFT can be used correctly only if you have original INT 2F vector ( an this means e.g. to tunnel this vector ) - SFT not necessary works under M$-DOS 7.0 ( other story ) ---> E. Closing words So, Sep here you have it. If anybody 'll have some questions or suggestion or whatsoever, he can reach me on IRC #virus and #svl or via e-mail at 571821@anon.penet.fi PS: The best way to test yer virii is to get file ice700.exe via ftp from ftp.elf.stuba.sk/pub/pc/sac