THE ART OF COMPUTER VIRUS RESEARCH AND DEFENSE [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

THE ART OF COMPUTER VIRUS RESEARCH AND DEFENSE [Electronic resources] - نسخه متنی

Peter Szor

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید











  • 12.4. Memory Scanning in User Mode


    The first question of memory scanning is how to access a particular process' data in memory. As discussed previously, process A cannot interfere with process B. How can a user-mode scanner read the contents of all the other processes? The answer is an API called ReadProcessMemory(). This API is usually used by debuggers to control the execution of the traced application by the debugger. The ReadProcessMemory() API needs a handle to a process, which can be gotten by the OpenProcess() API and the PROCESS_VM_READ access right. OpenProcess() needs the ID of a process. From where do we get a process ID?

    The answer was not obvious for quite some time because the actual DLL (PSAPI.DLL) in which documented process enumeration APIs have been placed is not part of the standard Windows NT environment. (It was introduced later in Windows 2000.) The lack of PSAPI.DLL and the missing documentation suggested to me how NT actually does this itself. Because Task Manager and several other applications can display all the running processes and their IDs, it was obvious that it is possible to do so without PSAPI.DLL. In fact, it turns out that most APIs in PSAPI.DLL are just wrappers around native service APIs placed in NTDLL.DLL, such as NtQuerySystemInformation().

    The native API set is not documented by Microsoft and is mostly used by subsystems. Most applications do not link to NTDLL.DLL directly for this reason. In fact, Microsoft suggests using the documented interfaces. However, Task Manager (TASKMGR.EXE) is linked to NTDLL.DLL directly, even if the information could be obtained by using performance data. Oh, well!

    Task Manager uses the NtQuerySystemInformation() native API to get a list of all running processes and their process IDs. A user-mode application can link itself to NTDLL.DLL or simply use GetProcAddress() to get the address of the API to call it.

    When the process ID of a particular process is available, ReadProcessMemory() can be used to read the actual address space of that particular application. To do so, a memory scanner should know the exact location of the used pages of an application. Fortunately, the VirtualQueryEx() function provides information about the range of pages within the virtual address space of a specified process. It needs an open handle to a process and returns the attributes and the sizes of regions.

    It also needs PROCESS_QUERY_INFORMATION access for this operation. Free and reserved pages can easily be eliminated with this function, and those should not be accessed, but the rest must be checked. This can be done by using the ReadProcessMemory() API on those pages.

    12.4.1. The Secrets of NtQuerySystemInformation()


    NtQuerySystemInformation() (NtQSI) is not documented by Microsoft, and it is not necessary to use it because a user-mode application can link itself to PSAPI.DLL, which in turn will call NtQSI. As we will see later on, however, this function can be useful in a kernel-mode implementation of a memory scanner, so it is worth talking about it a bit.

    NtQSI has four 32-bit (DWORD or ULONG) parameters.

    The first parameter could be named SystemInformationClass. This parameter specifies the type of information to be returned by the function. (It has several possible values; 5 specifies the running process list query.)

    The second parameter is the address of the returned buffer, which should be allocated by the caller; let's call this SystemInformationBuffer.

    The third parameter is the allocated size in bytes. The fourth parameter is an optional value, PULONG BytesWritten, which is the number of bytes returned in the caller.

    NtQSI() returns an NTSTATUS value. When the returned value is not STATUS_SUCCESS (0), it is usually STATUS_INFO_LENGTH_MISMATCH, which means that the allocated buffer length does not match the length required for the specified information class. Therefore, NtQSI() must be called with bigger and bigger buffers in a loop until the information can be placed into the allocated buffer completely by the Windows NT kernel.

    On correct return, the necessary information is placed in the buffer in the form of a linked list. The first DWORD value specifies the relative pointer of the next process block information from the start of the buffer. The DWORD value at offset 0x44 of each block is the process ID (of course this position is dependent on the platform and is different on IA64). With this ID, several additional APIs can be called, which is why it is the most important.

    After all of this, here is the "hand-made" definition for NtQuerySystemInformation():


    NTSYSAPI
    NTSTATUS
    NTAPI
    NtQuerySystemInformation(
    IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
    IN OUT PVOID SystemInformationBuffer,
    IN ULONG SystemInformationLength,
    OUT PULONG BytesWritten OPTIONAL
    );

    Other important information, such as the loaded images (EXE and DLLs) and their base addresses, can be examined by other native API calls by using this process ID, such as RtlQueryProcessDebugInformation(), which uses allocated buffers created by RtlCreateQueryDebugBuffer() and deallocated by RtlDestroyQueryDebugBuffer() APIs. Of course, these are all undocumented native APIs.

    12.4.2. Common Processes and Special System Rights


    On a typical Windows NTbased system, several processes are already running, even if the user has not logged in. The most important of these processes are the System Idle Process, the System Process, SMSS.EXE, CSRSS.EXE, WINLOGON.EXE, and SERVICES.EXE. A Windows NT scanner should scan all of these address spaces and also any other running processes executed by the user.7 (such as the Advanced Windows NT Third Edition), it is stated that some of the processes are secure processes and therefore cannot be opened for QUERY_INFORMATION or VM_WRITE operations. (These processes include WINLOGON.EXE, CLIPSRV.EXE, and EVENTLOG.EXE.) Such processes first need an additional system security privilege to be adjusted. (This information is missing from the Microsoft documentation.)

    In particular, the SeDebugPrivilege privilege value must be adjusted to the SE_PRIVILEGE_ENABLED attribute. The SeDebugPrivilege is available to administrators and equivalent users or to anyone who has been granted this privilege by an administrator. However, even under an administrator account, the default attribute of this privilege is not enabled, so OpenProcess() will fail to open secured processes. To enable this privilege, the OpenProcessToken() function must specify TOKEN_ADJUST_PRIVILEGES, and then LookupPrivilegeValue() can be used to check whether the user has the privilege at all. If the user has the rights to do it, this privilege can be set to SE_PRIVILEGE_ENABLED by the AdjustTokenPrivileges() API.

    It makes very good sense to protect some standard applications this way. For instance, Windows NT simply crashes if WINLOGON.EXE stops working. A modification caused by any user-mode application inside a random location of WINLOGON.EXE's address space could cause the system to crash! Of course, this would not be great. In any case, WINLOGON.EXE can even be written in memory when this privilege is enabled, but the privilege would have to be granted to all users first to scan such applications in memory. If WINLOGON.EXE were infected, the infected process could not be detected. Giving debug privileges to all users would definitely not make the system more secure. This is why a memory scanner is much better developed as a kernel-mode driver, where PROCESS_ALL_ACCESS is easily gained because drivers are running with the highest rights on a Windows NT machine.

    12.4.3. Viruses in the Win32 Subsystem


    This section introduces the different ways that viruses can become active as part of a particular process. Most 32-bit user-mode applications run in the Win32 subsystem, which is the most important subsystem of Windows NT. It is created and used by default and unlike the other subsystems, cannot be disabled. This is the subsystem in which Win32 viruses can be active.

    The Win32 subsystem consists of the following major components: CSRSS.EXE (the environment subsystem process); the kernel-mode device driver WIN32K.SYS; and subsystem DLLs (such as USER32.DLL, ADVAPI32.DLL, GDI32.DLL, and KERNEL32.DLL), which translate documented Win32 API functions into the appropriate undocumented kernel-mode system service calls to NTOSKRNL.EXE and WIN32K.SYS. There is one other very important part of the Win32 subsystem: NTDLL.DLL, primarily for subsystem DLLs. NTDLL.DLL is used in the other subsystems of Windows NT also and by native applications that do not run in a subsystem. (Listing 12.2 shows some of the system processesthe loaded DLLs with their base addresses and sizes.)

    Listing 12.2. Some System Executables with Their DLLs



    PID: 0x0014
    BaseAddress Size Name
    0x023a0000 0x0000c000 \SystemRoot\System32\smss.exe
    0x77f60000 0x0005c000 C:\WINNT\System32\ntdll.dll
    PID: 0x001c
    BaseAddress Size Name
    0x5ffe0000 0x00005000 \??\C:\WINNT\system32\csrss.exe
    0x77f60000 0x0005c000 C:\WINNT\System32\ntdll.dll
    :
    0x77e70000 0x00051000 C:\WINNT\system32\USER32.dll
    0x77f00000 0x0005e000 C:\WINNT\system32\KERNEL32.dll
    :
    0x5f810000 0x00007000 C:\WINNT\system32\rpcltc1.dll
    PID: 0x0022
    BaseAddress Size Name
    0x02880000 0x00030000 \??\C:\WINNT\SYSTEM32\winlogon.exe
    0x77f60000 0x0005c000 C:\WINNT\System32\ntdll.dll
    0x78000000 0x00048000 C:\WINNT\system32\MSVCRT.dll
    0x77f00000 0x0005e000 C:\WINNT\system32\KERNEL32.dll
    0x77dc0000 0x0003e000 C:\WINNT\system32\ADVAPI32.dll
    :
    0x77850000 0x0003a000 C:\WINNT\SYSTEM32\NETUI1.dll

    12.4.4. Win32 Viruses That Allocate Private Pages


    Some Win32 viruses allocate private pages for themselves with the PAGE_EXECUTE_READWRITE attribute. When the infected application is loaded, the virus code is activated from the executed application code. The virus then allocates new pages for its own use and moves its code there. Write access to those pages is important for the virus because it stores data in itself that must change, and read-only pages cannot be written to.8 allocates a 12,232-byte block that is represented as three pages (3*4,096=12,888 bytes) from the address space of the infected process (see Listing 12.3). Because Cabanas uses the MEM_TOP_DOWN flag when it allocates memory with the VirtualAlloc() function, the actual three pages will be available at the very end of the user address space, usually somewhere around the 0x7FFA0000 address.

    Listing 12.3. W32/Cabanas at the Very End of the User Address Space



    PID: 0x0051
    BaseAddress Size Name
    0x01b40000 0x00010000 C:\WINNT\system32\notepad.exe
    0x77f60000 0x0005b000 C:\WINNT\System32\ntdll.dll
    0x77d80000 0x00032000 C:\WINNT\system32\comdlg32.dll
    0x77f00000 0x0005c000 C:\WINNT\system32\KERNEL32.dll
    0x77e70000 0x00053000 C:\WINNT\system32\USER32.dll
    0x77ed0000 0x0002b000 C:\WINNT\system32\GDI32.dll
    0x77dc0000 0x0003e000 C:\WINNT\system32\ADVAPI32.dll
    0x77e20000 0x0004f000 C:\WINNT\system32\RPCRT4.dll
    0x77c40000 0x0013b000 C:\WINNT\system32\SHELL32.dll
    0x77bf0000 0x0004f000 C:\WINNT\system32\COMCTL32.dll
    0x779f0000 0x00046000 C:\WINNT\system32\MSVCRT.dll
    0x7FFA0000 PAGE_EXECUTE_READWRITE 12288 MEM_COMMIT Private

    Cabanas hooks some of the KERNEL32.DLL APIs to itself by patching the import table entries of the host program to its own routines. Whenever the host application calls any of the hooked APIs, the virus has the chance to replicate on the fly to another application or to call its directory stealth routines.9 virus allocates 132,605 bytes from the address space of the infected process (more exactly: 33 pages, 135,168 bytes) because it needs a lot of memory for its polymorphic engine and for its communication modules.

    W32/Parvo does not use the MEM_TOP_DOWN flag, so its allocated pages will be reserved from the first free gap of the user address space that is large enough (at address 0x002F0000 in the infected NOTEPAD.EXE in this particular example, as shown in Listing 12.4).

    Listing 12.4. W32/Parvo Inside NOTEPAD's Address Space



    PID: 0x004d
    BaseAddress Size Name
    0x002F0000 PAGE_EXECUTE_READWRITE 135168 MEM_COMMIT Private
    0x01760000 0x00011000 C:\WINNT35\system32\NOTEPAD.EXE
    0x77f80000 0x0004e000 C:\WINNT35\System32\ntdll.dll
    0x77df0000 0x0002b000 C:\WINNT35\system32\comdlg32.dll
    0x77f20000 0x00054000 C:\WINNT35\system32\KERNEL32.dll
    0x77ea0000 0x00038000 C:\WINNT35\system32\USER32.dll
    0x77ee0000 0x00033000 C:\WINNT35\system32\GDI32.dll
    :

    The virus code will be active with the name of the original infected and executed application. Only one copy of the virus is active at a time. The original host will be executed as the child process of the infected application under a random name, as shown in Listing 12.5.

    Because the host program will be executed almost immediately, the virus can silently infect other applications from its own process and propagate itself to other locations with its communication module, based on the use of WSOCK32.DLL APIs.

    Listing 12.5. W32/Parvo Runs Original NOTEPAD.EXE as JRWK.EXE



    PID: 0x003c
    BaseAddress Size Name
    0x01760000 0x00011000 C:\WINNT35\SYSTEM32\JWRK.EXE
    0x77f80000 0x0004e000 C:\WINNT35\System32\ntdll.dll
    0x77df0000 0x0002b000 C:\WINNT35\system32\comdlg32.dll
    0x77f20000 0x00054000 C:\WINNT35\system32\KERNEL32.dll
    0x77ea0000 0x00038000 C:\WINNT35\system32\USER32.dll
    0x77ee0000 0x00033000 C:\WINNT35\system32\GDI32.dll
    :

    12.4.5. Native Windows NT Service Viruses


    A new class of Windows NT viruses activate by dropping executable images loaded as a native Windows NT service, as done by WNT/RemEx3 (commonly known as the RemoteExplorer). The RemEx virus runs as a user-mode service called ie403r.sys, as shown in Listing 12.6. The virus sleeps for a while and then wakes up and tries periodically to infect other applications.

    Listing 12.6. WNT/RemEx Running as ie403r.sys Service



    PID: 0x0036
    BaseAddress Size Name
    0x00400000 0x0002b000 C:\WINNT\system32\drivers\ie403r.sys
    0x77f60000 0x0005b000 C:\WINNT\System32\ntdll.dll
    0x77f00000 0x0005c000 C:\WINNT\system32\KERNEL32.dll
    0x77e70000 0x00053000 C:\WINNT\system32\USER32.dll
    0x77ed0000 0x0002b000 C:\WINNT\system32\GDI32.dll
    0x77dc0000 0x0003e000 C:\WINNT\system32\ADVAPI32.dll
    0x77e20000 0x0004f000 C:\WINNT\system32\RPCRT4.dll
    0x77720000 0x00011000 C:\WINNT\system32\MPR.dll
    0x77e10000 0x00007000 C:\WINNT\system32\rpcltc1.dll

    12.4.6. Win32 Viruses That Use a Hidden Window Procedure


    A few viruses such as { W32,W97M} /Beast.41472.A10 install a hidden window procedure for their own use and use a timer. Timers were available back in 16-bit Windows versions, and they were sometimes used to simulate multithreaded functionality. As explained in Chapter 3, "Malicious Code Environments," this virus runs as a complete process and uses OLE APIs to inject embedded macros and executable code (the binary virus code itself) into Office 97 documents. Because the virus can infect Office 97 documents from its active process, a macro virus-specific scanner and disinfector has a hard time removing it from documents if it cannot detect and terminate the virus in memory first.

    12.4.7. Win32 Viruses That Are Part of the Executed Image Itself


    W32/Heretic.1986.A was the first virus to infect KERNEL32.DLL correctly under Windows NT. KERNEL32.DLL is used by most applications; most of the crucial Win32 APIs are exported from it. When KERNEL32.DLL is infected, most executed applications will be attached to it because they need to call APIs from it.

    Heretic patches the export address table of KERNEL32.DLL so that the CreateProcessA() and CreateProcessW() functions will point to the last section of the DLL where the virus code is placed, as shown in Listing 12.7.

    Listing 12.7. W32/Heretic.1986.A Modifies the Export Address of CreateProcess APIs



    image base 77F00000
    .
    .
    00015385 59 CreateNamedPipeA
    000153FA 60 CreateNamedPipeW
    00017DB6 61 CreatePipe
    0005E451 62 CreateProcessA -> (77F5E451)
    0005E442 63 CreateProcessW -> (77F5E442)
    00004F9A 64 CreateRemoteThread
    0001C893 65 CreateSemaphoreA
    .

    When these functions are called by the host program, the virus has the chance to infect other applications on the fly. The virus enlarges the last section (.reloc) of KERNEL32.DLL and puts its code there, modifying the characteristics of that section to both MEM_EXECUTE and MEM_WRITE types. Listing 12.8 shows the virus code in memory at the end of an infected KERNEL32.DLL.

    Listing 12.8. W32/Heretic.1986.A at the End of Infected KERNEL32.DLL in Memory



    0x77F5B000 PAGE_EXECUTE_WRITECOPY 16384 MEM_COMMIT Image
    77f5e000 84 69 01 00 00 89 47 28 66 81 38 4d 5a 0f 85 52 .i....G(f.8MZ.àR
    .
    77f5e410 3f 01 75 06 3c 22 75 f6 eb 08 3c 20 74 04 0a c0 ?.u.<"u÷d.< t..+
    77f5e420 75 ec c6 46 ff 00 8d 85 0c 15 40 00 89 47 08 e8 u81F..@..G.F
    77f5e430 31 fb ff ff 57 ff 95 92 17 40 00 ff 95 92 17 40 1v W ...@. ...@
    77f5e440 00 c3 68 34 84 f1 77 9c 60 e8 0a ff ff ff 61 9d .+h4ä±W£ `F. a¥
    77f5e450 c3 68 51 7f f1 77 9c 60 e8 56 ff ff ff 61 9d c3 +hQ±W.`FV a.+
    77f5e460 5b 48 65 72 65 74 69 63 5d 20 62 79 20 4d 65 6d [Heretic] by Mem
    77f5e470 6f 72 79 20 4c 61 70 73 65 00 46 6f 72 20 6d 79 ory Lapse.For my

    Another class of Win32 viruses stay active as part of an infected executable image, as done by the W32/Niko.5178 virus. (See Listing 12.9 for an illustration). The W32/Niko virus is activated from an infected portable executable (PE) application. The virus adds itself to the last section of the PE application and modifies the characteristics of the last section to MEM_WRITE. This allows the virus code to be modified in memory. The virus does not allocate memory for its full code but only for small data blocks whenever they are needed.

    Listing 12.9. W32/Niko.5178 Virus in an Infected ASD.EXE Application in Page 0x0040F000



    0040F000 PAGE_EXECUTE_WRITECOPY 8192 MEM_COMMIT PAGE_READWRITE Image
    0040f000 e9 21 00 00 00 b8 97 01 41 00 c3 b8 c1 03 41 00 T!...+ù.A.++-.A.
    0040f010 c3 e9 ba 48 ff ff b8 06 00 00 00 c3 e9 bf 10 00 +T1H +....+T+..
    0040f020 00 e9 d5 0e 00 00 e8 eb ff ff ff 50 e8 d4 ff ff .T+...Fd PF+
    .
    .
    00410190 d0 e9 5d ff ff ff 00 72 00 4e 49 43 4f 5f 56 49 -T] .r.NICO_VI
    004101a0 52 5f 4f 46 46 00 4b 45 52 4e 45 4c 33 32 00 47 R_OFF.KERNEL32.G
    004101b0 65 74 45 6e 76 69 72 6f 6e 6d 65 6e 74 56 61 72 etEnvironmentVar
    004101c0 69 61 62 6c 65 41 00 4e 49 43 4f 5f 56 49 52 5f iableA.NICO_VIR_
    004101d0 43 48 49 4c 44 5f 4f 46 46 00 7b 00 00 00 43 72 CHILD_OFF.{...Cr
    004101e0 65 61 74 65 54 68 72 65 61 64 00 47 6c 6f 62 61 eateThread.Globa
    004101f0 6c 41 6c 6c 6f 63 00 6c 73 74 72 63 70 79 00 47 lAlloc.lstrcpy.G
    00410200 6c 6f 62 61 6c 46 72 65 65 00 6c 73 74 72 63 6d lobalFree.lstrcm
    00410210 70 69 00 5c 2a 2e 2a 00 6c 73 74 72 63 61 74 00 pi.\*.*.lstrcat.
    00410220 46 69 6e 64 46 69 72 73 74 46 69 6c 65 41 00 2e FindFirstFileA..

    Niko is one of the first computer viruses to be multithreaded. The virus creates two threads for its own use, as shown in Listing 12.10. One is the trigger thread, which is supposed to display a message on a particular day; the other is the infection thread. The host program is executed after the virus creates the threads.

    As long as the host program is running, the virus's infection thread will also be active. If the host application (main thread) terminates, all threads of the process will be killed by Windows NT, so the virus will be no longer active. The virus can replicate to other files only from those applications that are running and used for a longer time. In such a situation, the infection thread will infect other applications from the background.

    Listing 12.10. W32/Niko.5178 Virus Creates Two Threads (68 and 123 in This Example)



    117 asd.exe Dtsactivation automatique (ASD)
    CWD: C:\LOOKCmdLine: C:\LOOK\ASD.EXE
    VirtualSize: 20152 KB PeakVirtualSize: 20192 KB
    WorkingSetSize: 1604 KB PeakWorkingSetSize: 1612 KB
    NumberOfThreads: 3
    122 Win32StartAddr:0x0040f000 LastErr:0x00000002 State:Waiting
    68 Win32StartAddr:0x0040f021 LastErr:0x00000002 State:Waiting
    123 Win32StartAddr:0x0040f01c LastErr:0x00000000 State:Waiting
    4.10.0.1998 shp 0x00400000 ASD.EXE
    4.0.1381.130 shp 0x77f60000 ntdll.dll
    4.0.1381.133 shp 0x77e70000 USER32.dll
    4.0.1381.133 shp 0x77f00000 KERNEL32.dll


    • / 191