Anti-Virus Software Gone Wrong,kaspersky技术逆向

What Were They Thinking?
Anti-Virus Software Gone Wrong
Skywing
[email protected]

0. Foreword

Abstract: Anti-virus software is becoming more and more prevalent on end-user
computers today.  Many major computer vendors (such as Dell) bundle anti-virus
software and other personal security suites in the default configuration of
newly-sold computer systems.  As a result, it is becoming increasingly important
that anti-virus software be well-designed, secure by default, and interoperable
with third-party applications.  Software that is installed and running by
default constitutes a prime target for attack and, as such, it is especially
important that said software be designed with security and interoperability in
mind.  In particular, this article provides examples of issues found in
well-known anti-virus products.  These issues range from not properly validating
input from an untrusted source (especially within the context of a kernel
driver) to failing to conform to API contracts when hooking or implementing an
intermediary between applications and the underlying APIs upon which they rely.
For popular software, or software that is installed by default, errors of this
sort can become a serious problem to both system stability and security.  Beyond
that, it can impact the ability of independent software vendors to deploy
functioning software on end-user systems. 

1. Introduction

In today's computing environment, computer security is becoming a more and more
important role.  The Internet poses unique dangers to networked computers, as
threats such as viruses, worms, and other malicious software become more and
more common.

As a result, there has been a shift towards including personal security
software on most new computers sold today, such as firewall software and
anti-virus software.  Many new computers are operated and administered by
individuals who are not experienced or savvy with the administration of a
secure system, and as such rely solely on the protection provided by a firewall
or anti-virus security suite.

Given this, one would expect that firewall, anti-virus, and other personal
security software would be high quality - after all, for many individuals,
firewall and anti-virus software are the first (and all-too-often only) line
of defense.

Unfortunately, though, most common anti-virus and personal firewall software is
full of defects that can at best make it very difficult to interoperate with
(which turns out to be a serious problem for most software vendors, given how
common anti-virus and firewall software is), and at worst compromise the very
system security they advertise to protect.

This article discusses two personal security software packages that suffer from
problems that make it difficult to interoperate with the software, or even
compromise system security, all due to shortcuts and unsafe assumptions made by
the original developers.

- Kaspersky Internet Security Suite 5.0
- McAfee Internet Security Suite 2006

Both of these software packages include several personal security programs,
including firewall and anti-virus software.


2. The problem: Kaspersky Internet Security Suite 5.0

Kaspersky ships a personal security software suite known as Kaspersky Internet
Security Suite 5.0.  This package includes various personal security software
programs, including a firewall and anti-virus software.

Kaspersky's anti-virus software is the primarily focus of this article.  Like
many other anti-virus software, Kaspersky Anti-Virus provides both manual and
real-time scanning capabilities.

Kaspersky's anti-virus system (KAV) employs various unsafe techniques in its
kernel mode components, which may lead to a compromise of system security.

2.1. Patching system services at runtime.

Although KAV appears to use a filesystem filter, the standard Windows mechanism
for intercepting accesses to files (specifically designed for applications like
anti-virus software), the implementors also used a series of API-level function
hooks to intercept various file accesses.  Performing function hooking in
kernel mode is a dangerous proposition; one must be very careful to fully
validate all parameters if a function could be called from user mode (otherwise
system security could be compromised by a malicious unprivileged program).
Additionally, it is generally not safe to remove code hooks in kernel mode as
it is difficult to prove that no threads will be running a particular code
region in order to unhook without risking bringing down the system.  KAV also
hooks several other system services in a misguided attempt to "protect" its
processes from debuggers and process termination.

Unfortunately, the KAV programmers did not properly validate parameters passed
to hooked system calls, opening holes that, at the very least, allow unprivileged
user mode programs to bring down the system, and may even allow local privilege
escalation (though the author has not spent the time necessary to prove whether
such is possible).

KAV hooks the following system services (easily discoverable in WinDbg by
comparing nt!KeServiceDescriptorTableShadow on a system with KAV loaded with a
clean system:


kd> dps poi ( nt!KeServiceDescriptorTableShadow ) l dwo ( nt!KeServiceDescriptorTableShadow + 8 )
8191c9c8  805862de nt!NtAcceptConnectPort
8191c9cc  8056fded nt!NtAccessCheck
.
.
.
8191ca2c  f823fd00 klif!KavNtClose
.
.
.
8191ca84  f823fa20 klif!KavNtCreateProcess
8191ca88  f823fb90 klif!KavNtCreateProcessEx
8191ca8c  80647b59 nt!NtCreateProfile
8191ca90  f823fe40 klif!KavNtCreateSection
8191ca94  805747cf nt!NtCreateSemaphore
8191ca98  8059d4db nt!NtCreateSymbolicLinkObject
8191ca9c  f8240630 klif!KavNtCreateThread
8191caa0  8059a849 nt!NtCreateTimer
.
.
.
8191cbb0  f823f7b0 klif!KavNtOpenProcess
.
.
.
8191cc24  f82402f0 klif!KavNtQueryInformationFile
.
.
.
8191cc7c  f8240430 klif!KavNtQuerySystemInformation
.
.
.
8191cd00  f82405e0 klif!KavNtResumeThread
.
.
.
8191cd58  f82421f0 klif!KavNtSetInformationProcess
.
.
.
8191cdc0  f8240590 klif!KavNtSuspendThread
.
.
.
8191cdcc  f82401c0 klif!KavNtTerminateProcess



Additionally, KAV attempts to create several entirely new system services as a
shortcut for calling kernel mode by patching the service descriptor table.
This is certainly not the preferred mechanism to allow a user mode program to
communicate with a driver; the programmers should have used the conventional
IOCTL interface, which avoids the pitfalls of patching kernel structures at
runtime and having to deal with other inconveniences such as system service
ordinals changing from OS release to OS release.

2.2. Improper validation of user mode pointers, assuming the size of the kernel
     address space.

Many of the hooks that KAV installs (and even the custom system services)
suffer from flaws that are detrimental to the operation of the system.

For instance, KAV's modified NtOpenProcess attempts to determine if a user
address is valid by comparing it to the hardcoded value 0x7FFF0000.  On most
x86 Windows systems, this address is below the highest user address (typically
0x7FFEFFFF).  However, hardcoding the size of the kernel address space is not a
very good idea; there is a boot parameter `/3GB' that can be set in boot.ini in
order to change the default address space split of 2GB kernel and 2GB user to
1GB kernel and 3GB user.  If a system with KAV is configured with /3GB, it is
expected that anything that calls NtOpenProcess (such as the win32 OpenProcess)
may randomly fail if parameter addresses are located above the first 2GB of the
user address space:

    .text:F82237B0 ; NTSTATUS __stdcall KavNtOpenProcess(PHANDLE ProcessHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,PCLIENT_ID ClientId)
    .text:F82237B0 KavNtOpenProcess proc near              ; DATA XREF: sub_F82249D0+BFo
      .
      .
      .
    .text:F8223800                 cmp     eax, 7FFF0000h ; eax = ClientId
    .text:F8223805                 jbe     short loc_F822380D
    .text:F8223807
    .text:F8223807 loc_F8223807:                           ; CODE XREF: KavNtOpenProcess+4Ej
    .text:F8223807                 call    ds:ExRaiseAccessViolation


The proper way to perform this validation would have been to use the documented
ProbeForRead function with a SEH frame, which will automatically raise an
access violation if the address is not a valid user address.

Additionally, many of KAV's custom system services do not properly validate
user mode pointer arguments, which could be used to bring down the system:


.text:F8222BE0 ; int __stdcall KAVService10(int,PVOID OutputBuffer,int)
.text:F8222BE0 KAVService10    proc near               ; DATA XREF: .data:F8227D14o
.text:F8222BE0
.text:F8222BE0 arg_0           = dword ptr  4
.text:F8222BE0 OutputBuffer    = dword ptr  8
.text:F8222BE0 arg_8           = dword ptr  0Ch
.text:F8222BE0
.text:F8222BE0                 mov     edx, [esp+OutputBuffer]
.text:F8222BE4                 push    esi
.text:F8222BE5                 mov     esi, [esp+4+arg_8]
.text:F8222BE9                 lea     ecx, [esp+4+arg_8]
.text:F8222BED                 push    ecx             ; int
.text:F8222BEE                 mov     eax, [esi]      ; Unvalidated user mode pointer access
.text:F8222BF0                 mov     [esp+8+arg_8], eax
.text:F8222BF4                 push    eax             ; OutputBufferLength
.text:F8222BF5                 mov     eax, [esp+0Ch+arg_0]
.text:F8222BF9                 push    edx             ; OutputBuffer
.text:F8222BFA                 push    eax             ; int
.text:F8222BFB                 call    sub_F821F9A0    ; This routine internally assumes that all pointer parameters given are valid.
.text:F8222C00                 mov     edx, [esi]
.text:F8222C02                 mov     ecx, [esp+4+arg_8]
.text:F8222C06                 cmp     ecx, edx
.text:F8222C08                 jbe     short loc_F8222C13
.text:F8222C0A                 mov     eax, 0C0000173h
.text:F8222C0F                 pop     esi
.text:F8222C10                 retn    0Ch
.text:F8222C13 ; ---------------------------------------------------------------------------
.text:F8222C13
.text:F8222C13 loc_F8222C13:                           ; CODE XREF: KAVService10+28j
.text:F8222C13                 mov     [esi], ecx
.text:F8222C15                 pop     esi
.text:F8222C16                 retn    0Ch
.text:F8222C16 KAVService10    endp


.text:F8222C20 KAVService11    proc near               ; DATA XREF: .data:F8227D18o
.text:F8222C20
.text:F8222C20 arg_0           = dword ptr  4
.text:F8222C20 arg_4           = dword ptr  8
.text:F8222C20 arg_8           = dword ptr  0Ch
.text:F8222C20
.text:F8222C20                 mov     edx, [esp+arg_4]
.text:F8222C24                 push    esi
.text:F8222C25                 mov     esi, [esp+4+arg_8]
.text:F8222C29                 lea     ecx, [esp+4+arg_8]
.text:F8222C2D                 push    ecx
.text:F8222C2E                 mov     eax, [esi]      ; Unvalidated user mode pointer access
.text:F8222C30                 mov     [esp+8+arg_8], eax
.text:F8222C34                 push    eax
.text:F8222C35                 mov     eax, [esp+0Ch+arg_0]
.text:F8222C39                 push    edx
.text:F8222C3A                 push    eax
.text:F8222C3B                 call    sub_F8214CE0    ; This routine internally assumes that all pointer parameters given are valid.
.text:F8222C40                 test    eax, eax
.text:F8222C42                 jnz     short loc_F8222C59
.text:F8222C44                 mov     ecx, [esp+4+arg_8]
.text:F8222C48                 mov     edx, [esi]
.text:F8222C4A                 cmp     ecx, edx
.text:F8222C4C                 jbe     short loc_F8222C57
.text:F8222C4E                 mov     eax, STATUS_INVALID_BLOCK_LENGTH
.text:F8222C53                 pop     esi
.text:F8222C54                 retn    0Ch
.text:F8222C57 ; ---------------------------------------------------------------------------
.text:F8222C57
.text:F8222C57 loc_F8222C57:                           ; CODE XREF: KAVService11+2Cj
.text:F8222C57                 mov     [esi], ecx
.text:F8222C59
.text:F8222C59 loc_F8222C59:                           ; CODE XREF: KAVService11+22j
.text:F8222C59                 pop     esi
.text:F8222C5A                 retn    0Ch
.text:F8222C5A KAVService11    endp


2.3. Improper validation of user mode structures and pointers, hiding threads
     from user mode.

KAV's errors with hooking do not end with NtOpenProcess, however.  One of the
system services KAV hooks is NtQuerySystemInformation, which is modified to
sometimes truncate a thread listing from certain processes when the
SystemProcessesAndThreads information class is requested.  This is the
underlying mechanism for user mode to receive a process and thread listing of
all programs running in the system, and in effect provides a means for KAV to
hide threads from user mode.  The very fact that this code exists at all in KAV
is curious; hiding running code from user mode is typically something that is
associated with rootkits and not anti-virus software.

Besides the potentially abusive behavior of hiding running code, this hook
contains several security flaws:

1. It uses the user mode output buffer from NtQuerySystemInformation after it
   has been filled by the actual kernel implementation, but it does not guard
   against a malicious user mode program modifying this buffer or even freeing
   it.  There is no SEH frame wrapping this function, so a user mode program
   could cause KAV to touch freed memory.

2. There is no validation of offsets within the returned output buffer to
   ensure that offsets do not refer to memory outside of the output buffer.
   This is problematic, because the returned data structure is actually a list
   of sub-structures that must be walked by adding an offset supplied as part
   of a particular substructure to the address of that substructure in order to
   reach the next substructure.  Such an offset could be modified by user mode
   to actually point into kernel memory.  Because the hook then sometimes
   writes data into what it believes is the user mode output buffer, this is an
   interesting avenue to explore for gaining kernel privileges from an
   unprivileged user mode function.

.text:F8224430 ; NTSTATUS __stdcall KavNtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass,PVOID SystemInformation,ULONG SystemInformationLength,PULONG ReturnLength)
.text:F8224430 KavNtQuerySystemInformation proc near   ; DATA XREF: sub_F82249D0+17Bo
.text:F8224430
.text:F8224430 var_10          = dword ptr -10h
.text:F8224430 var_C           = dword ptr -0Ch
.text:F8224430 var_8           = dword ptr -8
.text:F8224430 SystemInformationClass= dword ptr  4
.text:F8224430 SystemInformation= dword ptr  8
.text:F8224430 SystemInformationLength= dword ptr  0Ch
.text:F8224430 ReturnLength    = dword ptr  10h
.text:F8224430 arg_24          = dword ptr  28h
.text:F8224430
.text:F8224430                 mov     eax, [esp+ReturnLength]
.text:F8224434                 mov     ecx, [esp+SystemInformationLength]
.text:F8224438                 mov     edx, [esp+SystemInformation]
.text:F822443C                 push    ebx
.text:F822443D                 push    ebp
.text:F822443E                 push    esi
.text:F822443F                 mov     esi, [esp+0Ch+SystemInformationClass]
.text:F8224443                 push    edi
.text:F8224444                 push    eax
.text:F8224445                 push    ecx
.text:F8224446                 push    edx
.text:F8224447                 push    esi
.text:F8224448                 call    OrigNtQuerySystemInformation
.text:F822444E                 mov     edi, eax
.text:F8224450                 cmp     esi, SystemProcessesAndThreadsInformation ;
.text:F8224450                                         ; Not the process / thread list API?
.text:F8224450                                         ; Return to caller
.text:F8224453                 mov     [esp+10h+ReturnLength], edi
.text:F8224457                 jnz     ret_KavNtQuerySystemInformation
.text:F822445D                 xor     ebx, ebx
.text:F822445F                 cmp     edi, ebx        ;
.text:F822445F                                         ; Nothing returned?
.text:F822445F                                         ; Return to caller
.text:F8224461                 jl      ret_KavNtQuerySystemInformation
.text:F8224467                 push    ebx
.text:F8224468                 push    9
.text:F822446A                 push    8
.text:F822446C                 call    sub_F8216730
.text:F8224471                 test    al, al
.text:F8224473                 jz      ret_KavNtQuerySystemInformation
.text:F8224479                 mov     ebp, g_KavDriverData
.text:F822447F                 mov     ecx, [ebp+0Ch]
.text:F8224482                 lea     edx, [ebp+48h]
.text:F8224485                 inc     ecx
.text:F8224486                 mov     [ebp+0Ch], ecx
.text:F8224489                 mov     ecx, ebp
.text:F822448B                 call    ds:ExInterlockedPopEntrySList
.text:F8224491                 mov     esi, eax
.text:F8224493                 cmp     esi, ebx
.text:F8224495                 jnz     short loc_F82244B7
.text:F8224497                 mov     eax, [ebp+10h]
.text:F822449A                 mov     ecx, [ebp+24h]
.text:F822449D                 mov     edx, [ebp+1Ch]
.text:F82244A0                 inc     eax
.text:F82244A1                 mov     [ebp+10h], eax
.text:F82244A4                 mov     eax, [ebp+20h]
.text:F82244A7                 push    eax
.text:F82244A8                 push    ecx
.text:F82244A9                 push    edx
.text:F82244AA                 call    [ebp+arg_24]
.text:F82244AD                 mov     esi, eax
.text:F82244AF                 cmp     esi, ebx
.text:F82244B1                 jz      ret_KavNtQuerySystemInformation
.text:F82244B7
.text:F82244B7 loc_F82244B7:                           ; CODE XREF: KavNtQuerySystemInformation+65j
.text:F82244B7                 mov     edi, [esp+10h+SystemInformation]
.text:F82244BB                 mov     dword ptr [esi], 8
.text:F82244C1                 mov     dword ptr [esi+4], 9
.text:F82244C8                 mov     [esi+8], ebx
.text:F82244CB                 mov     [esi+34h], ebx
.text:F82244CE                 mov     dword ptr [esi+3Ch], 1
.text:F82244D5                 mov     [esi+10h], bl
.text:F82244D8                 mov     [esi+30h], ebx
.text:F82244DB                 mov     [esi+0Ch], ebx
.text:F82244DE                 mov     [esi+38h], ebx
.text:F82244E1                 mov     ebp, 13h
.text:F82244E6
.text:F82244E6 LoopThreadProcesses:                    ; CODE XREF: KavNtQuerySystemInformation+ECj
.text:F82244E6                 mov     dword ptr [esi+40h], 4 ;
.text:F82244E6                                         ; Loop through the returned list of processes and threads.
.text:F82244E6                                         ; For each process, we shall check to see if it is a
.text:F82244E6                                         ; special (protected) process.  If so, then we might
.text:F82244E6                                         ; decide to remove its threads from the listing returned
.text:F82244E6                                         ; by setting the thread count to zero.
.text:F82244ED                 mov     [esi+48h], ebx
.text:F82244F0                 mov     [esi+44h], ebp
.text:F82244F3                 mov     eax, [edi+SYSTEM_PROCESSES.ProcessId]
.text:F82244F6                 push    ebx
.text:F82244F7                 push    esi
.text:F82244F8                 mov     [esi+4Ch], eax
.text:F82244FB                 call    KavCheckProcess
.text:F8224500                 cmp     eax, 7
.text:F8224503                 jz      short CheckNextThreadProcess
.text:F8224505                 cmp     eax, 1
.text:F8224508                 jz      short CheckNextThreadProcess
.text:F822450A                 cmp     eax, ebx
.text:F822450C                 jz      short CheckNextThreadProcess
.text:F822450E                 mov     [edi+SYSTEM_PROCESSES.ThreadCount], ebx ; Zero thread count out (hide process threads)
.text:F8224511
.text:F8224511 CheckNextThreadProcess:                 ; CODE XREF: KavNtQuerySystemInformation+D3j
.text:F8224511                                         ; KavNtQuerySystemInformation+D8j ...
.text:F8224511                 mov     eax, [edi+SYSTEM_PROCESSES.NextEntryDelta]
.text:F8224513                 cmp     eax, ebx
.text:F8224515                 setz    cl
.text:F8224518                 add     edi, eax
.text:F822451A                 cmp     cl, bl
.text:F822451C                 jz      short LoopThreadProcesses


2.4. Improper validation of kernel object types.

Windows exposes many kernel features through a series of "kernel objects",
which may be acted upon by user mode through the user of handles.  Handles are
integral values that are translated by the kernel into pointers to a particular
object upon which something (typically a system service) interacts with on
behalf of a caller.  All objects share the same handle namespace.

Because of this handle namespace sharing between objects of different types,
one of the jobs of a system service inspecting a handle is to verify that the
object that it refers to is of the expected type.  This is accomplished by an
object manager routine ObReferenceObjectByHandle, which performs the
translation of handles to object pointers and does an optional built-in type
check by comparing a type field in the standard object header to a passed in
type.

Since KAV hooks system services, in inevitably must deal with kernel handles.
Unfortunately, it does not do so correctly.  In some cases, it does not ensure
that a handle refers to an object of a particular type before using the object
pointer, which will result in corruption or a system crash if a handle of the
wrong type is passed to a system service.

One such case is the KAV NtResumeThread hook, which attempts to track the state
of running threads in the system.  In this particular case, it does not seem
possible for user mode to crash the system by passing an object of the wrong
type as the returned object pointer, because it is simply used as a key in a
lookup table that is prepopulated with thread object pointers.  KAV also hooks
NtSuspendThread for similar purposes, and this hook has the same problem with
the validation of object handle types.


.text:F82245E0 ; NTSTATUS __stdcall KavNtResumeThread(HANDLE ThreadHandle,PULONG PreviousSuspendCount)
.text:F82245E0 KavNtResumeThread proc near             ; DATA XREF: sub_F82249D0+FBo
.text:F82245E0
.text:F82245E0 ThreadHandle    = dword ptr  8
.text:F82245E0 PreviousSuspendCount= dword ptr  0Ch
.text:F82245E0
.text:F82245E0                 push    esi
.text:F82245E1                 mov     esi, [esp+ThreadHandle]
.text:F82245E5                 test    esi, esi
.text:F82245E7                 jz      short loc_F8224620
.text:F82245E9                 lea     eax, [esp+ThreadHandle] ;
.text:F82245E9                                         ; This should pass an object type here!
.text:F82245ED                 push    0               ; HandleInformation
.text:F82245EF                 push    eax             ; Object
.text:F82245F0                 push    0               ; AccessMode
.text:F82245F2                 push    0               ; ObjectType
.text:F82245F4                 push    0F0000h         ; DesiredAccess
.text:F82245F9                 push    esi             ; Handle
.text:F82245FA                 mov     [esp+18h+ThreadHandle], 0
.text:F8224602                 call    ds:ObReferenceObjectByHandle
.text:F8224608                 test    eax, eax
.text:F822460A                 jl      short loc_F8224620
.text:F822460C                 mov     ecx, [esp+ThreadHandle]
.text:F8224610                 push    ecx
.text:F8224611                 call    KavUpdateThreadRunningState
.text:F8224616                 mov     ecx, [esp+ThreadHandle] ; Object
.text:F822461A                 call    ds:ObfDereferenceObject
.text:F8224620
.text:F8224620 loc_F8224620:                           ; CODE XREF: KavNtResumeThread+7j
.text:F8224620                                         ; KavNtResumeThread+2Aj
.text:F8224620                 mov     edx, [esp+PreviousSuspendCount]
.text:F8224624                 push    edx
.text:F8224625                 push    esi
.text:F8224626                 call    OrigNtResumeThread
.text:F822462C                 pop     esi
.text:F822462D                 retn    8
.text:F822462D KavNtResumeThread endp
.text:F822462D


.text:F8224590 ; NTSTATUS __stdcall KavNtSuspendThread(HANDLE ThreadHandle,PULONG PreviousSuspendCount)
.text:F8224590 sub_F8224590    proc near               ; DATA XREF: sub_F82249D0+113o
.text:F8224590
.text:F8224590 ThreadHandle    = dword ptr  8
.text:F8224590 PreviousSuspendCount= dword ptr  0Ch
.text:F8224590
.text:F8224590                 push    esi
.text:F8224591                 mov     esi, [esp+ThreadHandle]
.text:F8224595                 test    esi, esi
.text:F8224597                 jz      short loc_F82245D0
.text:F8224599                 lea     eax, [esp+ThreadHandle] ;
.text:F8224599                                         ; This should pass an object type here!
.text:F822459D                 push    0               ; HandleInformation
.text:F822459F                 push    eax             ; Object
.text:F82245A0                 push    0               ; AccessMode
.text:F82245A2                 push    0               ; ObjectType
.text:F82245A4                 push    0F0000h         ; DesiredAccess
.text:F82245A9                 push    esi             ; Handle
.text:F82245AA                 mov     [esp+18h+ThreadHandle], 0
.text:F82245B2                 call    ds:ObReferenceObjectByHandle
.text:F82245B8                 test    eax, eax
.text:F82245BA                 jl      short loc_F82245D0
.text:F82245BC                 mov     ecx, [esp+ThreadHandle]
.text:F82245C0                 push    ecx
.text:F82245C1                 call    KavUpdateThreadSuspendedState
.text:F82245C6                 mov     ecx, [esp+ThreadHandle] ; Object
.text:F82245CA                 call    ds:ObfDereferenceObject
.text:F82245D0
.text:F82245D0 loc_F82245D0:                           ; CODE XREF: sub_F8224590+7j
.text:F82245D0                                         ; sub_F8224590+2Aj
.text:F82245D0                 mov     edx, [esp+PreviousSuspendCount]
.text:F82245D4                 push    edx
.text:F82245D5                 push    esi
.text:F82245D6                 call    OrigNtSuspendThread
.text:F82245DC                 pop     esi
.text:F82245DD                 retn    8
.text:F82245DD sub_F8224590    endp
.text:F82245DD
Not all of KAV's hooks are so fortunate, however.  The NtTerminateProcess hook
that KAV installs looks into the body of the object referred to by the process
handle parameter of the function in order to determine the name of the process
being terminated.  However, KAV fails to validate that the object handle given
by user mode really refers to a process object.

This is unsafe for several reasons, which may be well known to the reader if
one is experienced with Windows kernel programming.

1. The kernel process structure definition (EPROCESS) changes frequently from
   OS release to OS release, and even between service packs.  As a result, it
   is not generally safe to access this structure directly.

2. Because KAV does not perform proper type checking, it is possible to pass an
   object handle to a different kernel object - say, a mutex - which may cause
   KAV to bring down the system because the internal object structures of a
   mutex (or any other kernel object) are not compatible with that of a process
   object.

KAV attempts to work around the first problem by attempting to discover the
offset of the member in the EPROCESS structure that contains the process name
at runtime.  The algorithm used is to scan forward one byte at a time from the
start of the process object pointer until a sequence of bytes identifying the
name of the initial system process is discovered.  (This routine is called in
the context of the initial system process).


.text:F82209E0 KavFindEprocessNameOffset proc near     ; CODE XREF: sub_F8217A60+FCp
.text:F82209E0                 push    ebx
.text:F82209E1                 push    esi
.text:F82209E2                 push    edi
.text:F82209E3                 call    ds:IoGetCurrentProcess
.text:F82209E9                 mov     edi, ds:strncmp
.text:F82209EF                 mov     ebx, eax
.text:F82209F1                 xor     esi, esi
.text:F82209F3
.text:F82209F3 loc_F82209F3:                           ; CODE XREF: KavFindEprocessNameOffset+2Ej
.text:F82209F3                 lea     eax, [esi+ebx]
.text:F82209F6                 push    6               ; size_t
.text:F82209F8                 push    eax             ; char *
.text:F82209F9                 push    offset aSystem  ; "System"
.text:F82209FE                 call    edi ; strncmp
.text:F8220A00                 add     esp, 0Ch
.text:F8220A03                 test    eax, eax
.text:F8220A05                 jz      short loc_F8220A16
.text:F8220A07                 inc     esi
.text:F8220A08                 cmp     esi, 3000h
.text:F8220A0E                 jl      short loc_F82209F3
.text:F8220A10                 pop     edi
.text:F8220A11                 pop     esi
.text:F8220A12                 xor     eax, eax
.text:F8220A14                 pop     ebx
.text:F8220A15                 retn
.text:F8220A16 ; ---------------------------------------------------------------------------
.text:F8220A16
.text:F8220A16 loc_F8220A16:                           ; CODE XREF: KavFindEprocessNameOffset+25j
.text:F8220A16                 mov     eax, esi
.text:F8220A18                 pop     edi
.text:F8220A19                 pop     esi
.text:F8220A1A                 pop     ebx
.text:F8220A1B                 retn
.text:F8220A1B KavFindEprocessNameOffset endp

.text:F8217B5C                 call    KavFindEprocessNameOffset
.text:F8217B61                 mov     g_EprocessNameOffset, eax


Given a handle to an object of the wrong type, KAV will read from the returned
object body pointer in an attempt to determine the name of the process being
destroyed.  This will typically run off the end of the structure for an object
that is not a process object (the Process object is very large compared to some
objects, such as a Mutex object, and the offset of the process name within this
structure is typically several hundred bytes or more).  It is expected that
this will cause the system to crash if a bad handle is passed to
NtTerminateProcess.


.text:F82241C0 ; NTSTATUS __stdcall KavNtTerminateProcess(HANDLE ThreadHandle,NTSTATUS ExitStatus)
.text:F82241C0 KavNtTerminateProcess proc near         ; DATA XREF: sub_F82249D0+ABo
.text:F82241C0
.text:F82241C0 var_58          = dword ptr -58h
.text:F82241C0 ProcessObject   = dword ptr -54h
.text:F82241C0 ProcessData     = KAV_TERMINATE_PROCESS_DATA ptr -50h
.text:F82241C0 var_4           = dword ptr -4
.text:F82241C0 ProcessHandle   = dword ptr  4
.text:F82241C0 ExitStatus      = dword ptr  8
.text:F82241C0
.text:F82241C0                 sub     esp, 54h
.text:F82241C3                 push    ebx
.text:F82241C4                 xor     ebx, ebx
.text:F82241C6                 push    esi
.text:F82241C7                 mov     [esp+5Ch+ProcessObject], ebx
.text:F82241CB                 call    KeGetCurrentIrql
.text:F82241D0                 mov     esi, [esp+5Ch+ProcessHandle]
.text:F82241D4                 cmp     al, 2           ;
.text:F82241D4                                         ; IRQL >= DISPATCH_LEVEL? Abort
.text:F82241D4                                         ; ( This is impossible for a system service )
.text:F82241D6                 jnb     Ret_KavNtTerminateProcess
.text:F82241DC                 cmp     esi, ebx        ;
.text:F82241DC                                         ; Null process handle? Abort
.text:F82241DE                 jz      Ret_KavNtTerminateProcess
.text:F82241E4                 call    PsGetCurrentProcessId
.text:F82241E9                 mov     [esp+5Ch+ProcessData.CurrentProcessId], eax
.text:F82241ED                 xor     eax, eax
.text:F82241EF                 cmp     esi, 0FFFFFFFFh
.text:F82241F2                 push    esi             ; ProcessHandle
.text:F82241F3                 setnz   al
.text:F82241F6                 dec     eax
.text:F82241F7                 mov     [esp+60h+ProcessData.TargetIsCurrentProcess], eax
.text:F82241FB                 call    KavGetProcessIdFromProcessHandle
.text:F8224200                 lea     ecx, [esp+5Ch+ProcessObject] ; Object
.text:F8224204                 push    ebx             ; HandleInformation
.text:F8224205                 push    ecx             ; Object
.text:F8224206                 push    ebx             ; AccessMode
.text:F8224207                 push    ebx             ; ObjectType
.text:F8224208                 push    0F0000h         ; DesiredAccess
.text:F822420D                 push    esi             ; Handle
.text:F822420E                 mov     [esp+74h+ProcessData.TargetProcessId], eax
.text:F8224212                 mov     [esp+74h+var_4], ebx
.text:F8224216                 call    ds:ObReferenceObjectByHandle
.text:F822421C                 test    eax, eax
.text:F822421E                 jl      short loc_F8224246
.text:F8224220                 mov     edx, [esp+5Ch+ProcessObject]
.text:F8224224                 mov     eax, g_EprocessNameOffset
.text:F8224229                 add     eax, edx
.text:F822422B                 push    40h             ; size_t
.text:F822422D                 lea     ecx, [esp+60h+ProcessData.ProcessName]
.text:F8224231                 push    eax             ; char *
.text:F8224232                 push    ecx             ; char *
.text:F8224233                 call    ds:strncpy
.text:F8224239                 mov     ecx, [esp+68h+ProcessObject]
.text:F822423D                 add     esp, 0Ch
.text:F8224240                 call    ds:ObfDereferenceObject
.text:F8224246
.text:F8224246 loc_F8224246:                           ; CODE XREF: KavNtTerminateProcess+5Ej
.text:F8224246                 cmp     esi, 0FFFFFFFFh
.text:F8224249                 jnz     short loc_F8224255
.text:F822424B                 mov     edx, [esp+5Ch+ProcessData.TargetProcessId]
.text:F822424F                 push    edx
.text:F8224250                 call    sub_F8226710
.text:F8224255
.text:F8224255 loc_F8224255:                           ; CODE XREF: KavNtTerminateProcess+89j
.text:F8224255                 lea     eax, [esp+5Ch+ProcessData]
.text:F8224259                 push    ebx             ; int
.text:F822425A                 push    eax             ; ProcessData
.text:F822425B                 call    KavCheckTerminateProcess
.text:F8224260                 cmp     eax, 7
.text:F8224263                 jz      short loc_F822427D
.text:F8224265                 cmp     eax, 1
.text:F8224268                 jz      short loc_F822427D
.text:F822426A                 cmp     eax, ebx
.text:F822426C                 jz      short loc_F822427D
.text:F822426E                 mov     esi, STATUS_ACCESS_DENIED
.text:F8224273                 mov     eax, esi
.text:F8224275                 pop     esi
.text:F8224276                 pop     ebx
.text:F8224277                 add     esp, 54h
.text:F822427A                 retn    8
.text:F822427D ; ---------------------------------------------------------------------------
.text:F822427D
.text:F822427D loc_F822427D:                           ; CODE XREF: KavNtTerminateProcess+A3j
.text:F822427D                                         ; KavNtTerminateProcess+A8j ...
.text:F822427D                 mov     eax, [esp+5Ch+ProcessData.TargetProcessId]
.text:F8224281                 cmp     eax, 1000h
.text:F8224286                 jnb     short loc_F8224296
.text:F8224288                 mov     dword_F8228460[eax*8], ebx
.text:F822428F                 mov     byte_F8228464[eax*8], bl
.text:F8224296
.text:F8224296 loc_F8224296:                           ; CODE XREF: KavNtTerminateProcess+C6j
.text:F8224296                 push    eax
.text:F8224297                 call    sub_F82134D0
.text:F822429C                 mov     ecx, [esp+5Ch+ProcessData.TargetProcessId]
.text:F82242A0                 push    ecx
.text:F82242A1                 call    sub_F8221F70
.text:F82242A6                 mov     edx, [esp+5Ch+ExitStatus]
.text:F82242AA                 push    edx
.text:F82242AB                 push    esi
.text:F82242AC                 call    OrigNtTerminateProcess
.text:F82242B2                 mov     esi, eax
.text:F82242B4                 lea     eax, [esp+5Ch+ProcessData]
.text:F82242B8                 push    1               ; int
.text:F82242BA                 push    eax             ; ProcessData
.text:F82242BB                 mov     [esp+64h+var_4], esi
.text:F82242BF                 call    KavCheckTerminateProcess
.text:F82242C4                 mov     eax, esi
.text:F82242C6                 pop     esi
.text:F82242C7                 pop     ebx
.text:F82242C8                 add     esp, 54h
.text:F82242CB                 retn    8
.text:F82242CE ; ---------------------------------------------------------------------------
.text:F82242CE
.text:F82242CE Ret_KavNtTerminateProcess:              ; CODE XREF: KavNtTerminateProcess+16j
.text:F82242CE                                         ; KavNtTerminateProcess+1Ej
.text:F82242CE                 mov     ecx, [esp+5Ch+ExitStatus]
.text:F82242D2                 push    ecx
.text:F82242D3                 push    esi
.text:F82242D4                 call    OrigNtTerminateProcess
.text:F82242DA                 pop     esi
.text:F82242DB                 pop     ebx
.text:F82242DC                 add     esp, 54h
.text:F82242DF                 retn    8
.text:F82242DF KavNtTerminateProcess endp


The whole purpose of this particular system service hook is "shady" as well.
The hook prevents certain KAV processes from being terminated, even by a
legitimate computer administrator - something that is once again typically
associated with malicious software such as rootkits rather than commercial
software applications.  One possible explanation is to attempt to prevent
viruses from terminating the virus scanner processes itself, although one
wonders how much of a concern this would be if KAV's real-time scanning
mechanisms really do work as advertised.

Additionally, KAV appears to do some state tracking just before the process is
terminated with this system service hook.  The proper way to do this would have
been through PsSetCreateProcessNotifyRoutine, a documented kernel function that
allows drivers to register a callback that is called on process creation and
process exit.


2.5. Patching non-exported, non-system-service kernel functions.

KAV's kernel patching is not limited to just system services, however.  One of
the most dangerous hooks that KAV installs is one in the middle of the
nt!SwapContext function, which is neither exported nor a system service (and
thus has reliable mechanism to be detected by driver code, other than code
fingerprinting).  nt!SwapContext is called by the kernel on every context
switch in order to perform some internal bookkeeping tasks.

Patching such a critical, non-exported kernel function with a mechanism as
unreliable as blind code fingerprinting is, in the author's opinion, not a
particularly good idea.  To make matters worse, KAV actually modifies code in
the middle of nt!SwapContext instead of patching the start of the function, and
as such makes assumptions about the internal register and stack usage of this
kernel function.


    kd> u nt!SwapContext
    nt!SwapContext:
    804db924 0ac9             or      cl,cl
    804db926 26c6462d02       mov     byte ptr es:[esi+0x2d],0x2
    804db92b 9c               pushfd
    804db92c 8b0b             mov     ecx,[ebx]
    804db92e e9dd69d677       jmp     klif!KavSwapContext (f8242310)


The unmodified nt!SwapContext has code that runs along the lines of this:


    lkd> u nt!SwapContext
    nt!SwapContext:
    80540ab0 0ac9             or      cl,cl
    80540ab2 26c6462d02       mov     byte ptr es:[esi+0x2d],0x2
    80540ab7 9c               pushfd
    80540ab8 8b0b             mov     ecx,[ebx]
    80540aba 83bb9409000000   cmp     dword ptr [ebx+0x994],0x0
    80540ac1 51               push    ecx
    80540ac2 0f8535010000     jne     nt!SwapContext+0x14d (80540bfd)
    80540ac8 833d0ca0558000 cmp dword ptr [nt!PPerfGlobalGroupMask (8055a00c)],0x0


This is an extremely dangerous patching operation to make, for several reasons:

1. nt!SwapContext is a *very* hot code path, as it is called on every single
   context switch.  Therefore, patching it at runtime without running a non-trivial
	risk of bringing down the system is very difficult, especially on
   multiprocessor systems.  KAV attempts to solve the synchronization problems
   relating to patching this function on uniprocessor systems by disabling
   interrupts entirely, but this approach will not work reliably on
   multiprocessor systems.  KAV makes no attempt to address this problem on
   multiprocessor systems and puts them at the risk of randomly failing on boot
   during KAV's patching.

2. Reliably locating this function and making assumptions about the register
   and stack usage (and instruction layout) across all released and future
   Windows versions is a practical impossibility, and yet KAV attempts to do
   just this.  This puts KAV customers at the mercy of the next Windows update,
   which may cause their systems to crash on boot because KAV's hooking code
   makes an assumption that has been invalidated about the context-switching
   process.


Additionally, in order to perform code patching on the kernel, KAV adjusts the
page protections of kernel code to be writable by altering PTE attributes
directly instead of using documented functions (which would have proper locking
semantics for accessing internal memory management structures).


KAV nt!SwapContext patching:


.text:F82264EA                 mov     eax, 90909090h  ; Build the code to be written to nt!SwapContext
.text:F82264EF                 mov     [ebp+var_38], eax
.text:F82264F2                 mov     [ebp+var_34], eax
.text:F82264F5                 mov     [ebp+var_30], ax
.text:F82264F9                 mov     byte ptr [ebp+var_38], 0E9h
.text:F82264FD                 mov     ecx, offset KavSwapContext
.text:F8226502                 sub     ecx, ebx
.text:F8226504                 sub     ecx, 5
.text:F8226507                 mov     [ebp+var_38+1], ecx
.text:F822650A                 mov     ecx, [ebp+var_1C]
.text:F822650D                 lea     edx, [ecx+ebx]
.text:F8226510                 mov     dword_F8228338, edx
.text:F8226516                 mov     esi, ebx
.text:F8226518                 mov     edi, offset unk_F8227DBC
.text:F822651D                 mov     eax, ecx
.text:F822651F                 shr     ecx, 2
.text:F8226522                 rep movsd
.text:F8226524                 mov     ecx, eax
.text:F8226526                 and     ecx, 3
.text:F8226529                 rep movsb
.text:F822652B                 lea     ecx, [ebp+var_48] ; Make nt!SwapContext writable by directly accessing
.text:F822652B                                         ; the PTEs.
.text:F822652E                 push    ecx
.text:F822652F                 push    1
.text:F8226531                 push    ebx
.text:F8226532                 call    ModifyPteAttributes
.text:F8226537                 test    al, al
.text:F8226539                 jz      short loc_F8226588
.text:F822653B                 mov     ecx, offset KavInternalSpinLock
.text:F8226540                 call    KavSpinLockAcquire ; Disable interrupts
.text:F8226545                 mov     ecx, [ebp+var_1C] ; Write to kernel code
.text:F8226548                 lea     esi, [ebp+var_38]
.text:F822654B                 mov     edi, ebx
.text:F822654D                 mov     edx, ecx
.text:F822654F                 shr     ecx, 2
.text:F8226552                 rep movsd
.text:F8226554                 mov     ecx, edx
.text:F8226556                 and     ecx, 3
.text:F8226559                 rep movsb
.text:F822655B                 mov     edx, eax
.text:F822655D                 mov     ecx, offset KavInternalSpinLock
.text:F8226562                 call    KavSpinLockRelease ; Reenable interrupts
.text:F8226567                 lea     eax, [ebp+var_48] ; Restore the original PTE attributes.
.text:F822656A                 push    eax
.text:F822656B                 mov     ecx, [ebp+var_48]
.text:F822656E                 push    ecx
.text:F822656F                 push    ebx
.text:F8226570                 call    ModifyPteAttributes
.text:F8226575                 mov     al, 1
.text:F8226577                 mov     ecx, [ebp+var_10]
.text:F822657A                 mov     large fs:0, ecx
.text:F8226581                 pop     edi
.text:F8226582                 pop     esi
.text:F8226583                 pop     ebx
.text:F8226584                 mov     esp, ebp
.text:F8226586                 pop     ebp
.text:F8226587                 retn


KavSpinLockAcquire subroutine (disables interrupts):


.text:F8221240 KavSpinLockAcquire proc near            ; CODE XREF: sub_F8225690+D7p
.text:F8221240                                         ; sub_F8225D50+8Cp ...
.text:F8221240                 pushf
.text:F8221241                 pop     eax
.text:F8221242
.text:F8221242 loc_F8221242:                           ; CODE XREF: KavSpinLockAcquire+13j
.text:F8221242                 cli
.text:F8221243                 lock bts dword ptr [ecx], 0
.text:F8221248                 jb      short loc_F822124B
.text:F822124A                 retn
.text:F822124B ; ---------------------------------------------------------------------------
.text:F822124B
.text:F822124B loc_F822124B:                           ; CODE XREF: KavSpinLockAcquire+8j
.text:F822124B                 push    eax
.text:F822124C                 popf
.text:F822124D
.text:F822124D loc_F822124D:                           ; CODE XREF: KavSpinLockAcquire+17j
.text:F822124D                 test    dword ptr [ecx], 1
.text:F8221253                 jz      short loc_F8221242
.text:F8221255                 pause
.text:F8221257                 jmp     short loc_F822124D
.text:F8221257 KavSpinLockAcquire endp


KavSpinLockRelease subroutine (reenables interrupts):


.text:F8221260 KavSpinLockRelease proc near            ; CODE XREF: sub_F8225690+F2p
.text:F8221260                                         ; sub_F8225D50+BAp ...
.text:F8221260                 mov     dword ptr [ecx], 0
.text:F8221266                 push    edx
.text:F8221267                 popf
.text:F8221268                 retn
.text:F8221268 KavSpinLockRelease endp




ModifyPteAttributes subroutine:


.text:F82203C0 ModifyPteAttributes proc near           ; CODE XREF: sub_F821A9D0+91p
.text:F82203C0                                         ; sub_F8220950+43p ...
.text:F82203C0
.text:F82203C0 var_24          = dword ptr -24h
.text:F82203C0 var_20          = byte ptr -20h
.text:F82203C0 var_1C          = dword ptr -1Ch
.text:F82203C0 var_18          = dword ptr -18h
.text:F82203C0 var_10          = dword ptr -10h
.text:F82203C0 var_4           = dword ptr -4
.text:F82203C0 arg_0           = dword ptr  8
.text:F82203C0 arg_4           = byte ptr  0Ch
.text:F82203C0 arg_8           = dword ptr  10h
.text:F82203C0
.text:F82203C0                 push    ebp
.text:F82203C1                 mov     ebp, esp
.text:F82203C3                 push    0FFFFFFFFh
.text:F82203C5                 push    offset dword_F8212180
.text:F82203CA                 push    offset _except_handler3
.text:F82203CF                 mov     eax, large fs:0
.text:F82203D5                 push    eax
.text:F82203D6                 mov     large fs:0, esp
.text:F82203DD                 sub     esp, 14h
.text:F82203E0                 push    ebx
.text:F82203E1                 push    esi
.text:F82203E2                 push    edi
.text:F82203E3                 mov     [ebp+var_18], esp
.text:F82203E6                 xor     ebx, ebx
.text:F82203E8                 mov     [ebp+var_20], bl
.text:F82203EB                 mov     esi, [ebp+arg_0]
.text:F82203EE                 mov     ecx, esi
.text:F82203F0                 call    KavGetEflags
.text:F82203F5                 push    esi
.text:F82203F6                 call    KavGetPte       ; This is a function pointer filled in at runtime,
.text:F82203F6                                         ; differing based on whether the system has PAE
.text:F82203F6                                         ; enabled or not.
.text:F82203FC                 mov     edi, eax
.text:F82203FE                 mov     [ebp+var_1C], edi
.text:F8220401                 cmp     edi, 0FFFFFFFFh
.text:F8220404                 jz      short loc_F8220458
.text:F8220406                 mov     [ebp+var_4], ebx
.text:F8220409                 mov     ecx, esi
.text:F822040B                 call    KavGetEflags
.text:F8220410                 mov     eax, [edi]
.text:F8220412                 test    al, 1
.text:F8220414                 jz      short loc_F8220451
.text:F8220416                 mov     ecx, eax
.text:F8220418                 mov     [ebp+var_24], ecx
.text:F822041B                 cmp     [ebp+arg_4], bl
.text:F822041E                 jz      short loc_F8220429
.text:F8220420                 mov     eax, [ebp+var_1C]
.text:F8220423                 lock or dword ptr [eax], 2
.text:F8220427                 jmp     short loc_F8220430
.text:F8220429 ; ---------------------------------------------------------------------------
.text:F8220429
.text:F8220429 loc_F8220429:                           ; CODE XREF: ModifyPteAttributes+5Ej
.text:F8220429                 mov     eax, [ebp+var_1C]
.text:F822042C                 lock and dword ptr [eax], 0FFFFFFFDh
.text:F8220430
.text:F8220430 loc_F8220430:                           ; CODE XREF: ModifyPteAttributes+67j
.text:F8220430                 mov     eax, [ebp+arg_8]
.text:F8220433                 cmp     eax, ebx
.text:F8220435                 jz      short loc_F822043C
.text:F8220437                 and     ecx, 2
.text:F822043A                 mov     [eax], cl
.text:F822043C
.text:F822043C loc_F822043C:                           ; CODE XREF: ModifyPteAttributes+75j
.text:F822043C                 mov     [ebp+var_20], 1
.text:F8220440                 mov     eax, [ebp+arg_0]
.text:F8220443                 invlpg  byte ptr [eax]
.text:F8220446                 jmp     short loc_F8220451
.text:F8220448 ; ---------------------------------------------------------------------------
.text:F8220448
.text:F8220448 loc_F8220448:                           ; DATA XREF: .text:F8212184o
.text:F8220448                 mov     eax, 1
.text:F822044D                 retn
.text:F822044E ; ---------------------------------------------------------------------------
.text:F822044E
.text:F822044E loc_F822044E:                           ; DATA XREF: .text:F8212188o
.text:F822044E                 mov     esp, [ebp-18h]
.text:F8220451
.text:F8220451 loc_F8220451:                           ; CODE XREF: ModifyPteAttributes+54j
.text:F8220451                                         ; ModifyPteAttributes+86j
.text:F8220451                 mov     [ebp+var_4], 0FFFFFFFFh
.text:F8220458
.text:F8220458 loc_F8220458:                           ; CODE XREF: ModifyPteAttributes+44j
.text:F8220458                 mov     al, [ebp+var_20]
.text:F822045B                 mov     ecx, [ebp+var_10]
.text:F822045E                 mov     large fs:0, ecx
.text:F8220465                 pop     edi
.text:F8220466                 pop     esi
.text:F8220467                 pop     ebx
.text:F8220468                 mov     esp, ebp
.text:F822046A                 pop     ebp
.text:F822046B                 retn    0Ch
.text:F822046B ModifyPteAttributes endp


2.6. Allowing user mode code to access kernel memory directly from user mode,
     improper validation of user mode structures.

One of the most important principles of the kernel/user division that modern
operating systems enforce is that user mode is not allowed to directly access
kernel mode memory.  This is necessary to enforce system stability, otherwise
a buggy user mode program could corrupt the kernel and bring down the whole
system.

Unfortunately, the KAV programmers appear to think that this distinction is not
really so important after all.

One of the strangest of the unsafe practicies implemented by KAV is to allow
user mode to directly call some portions of their kernel driver (within kernel
address space!) instead of just loading a user mode DLL (or otherwise loading
user mode code in the target process).

This mechanism appears to be used to inspect DLLs as they are loaded - a task
which would be much better accomplished with PsSetLoadImageNotifyRoutine.

KAV patches kernel32.dll as a new process is created, such that the export
table points all of the DLL-loading routines (e.g. LoadLibraryA) to a thunk
that calls portions of KAV's driver in kernel mode.  Additionally, KAV modifes
protections on parts of its code and data sections to allow user mode read
access.

KAV sets a PsLoadImageNotifyRoutine hook to detect kernel32.dll being loaded in
order to know when to patch kernel32's export table.  The author wonders why
KAV did not just do their work from within PsSetLoadImageNotifyRoutine directly
instead of going through all the trouble to allow user mode to call kernel mode
for a LoadLibrary hook.


The CheckInjectCodeForNewProcess function is called when a new process loads an
image, and checks for kernel32 being loaded.  If this is the case, it will
queue an APC to the process that will perform patching.


.text:F82218B0 ; int __stdcall CheckInjectCodeForNewProcess(wchar_t *,PUCHAR ImageBase)
.text:F82218B0 CheckInjectCodeForNewProcess proc near  ; CODE XREF: KavLoadImageNotifyRoutine+B5p
.text:F82218B0                                         ; KavDoKernel32Check+41p
.text:F82218B0
.text:F82218B0 arg_0           = dword ptr  4
.text:F82218B0 ImageBase       = dword ptr  8
.text:F82218B0
.text:F82218B0                 mov     al, byte_F82282F9
.text:F82218B5                 push    esi
.text:F82218B6                 test    al, al
.text:F82218B8                 push    edi
.text:F82218B9                 jz      short loc_F8221936
.text:F82218BB                 mov     eax, [esp+8+arg_0]
.text:F82218BF                 push    offset aKernel32_dll ; "kernel32.dll"
.text:F82218C4                 push    eax             ; wchar_t *
.text:F82218C5                 call    ds:_wcsicmp
.text:F82218CB                 add     esp, 8
.text:F82218CE                 test    eax, eax
.text:F82218D0                 jnz     short loc_F8221936
.text:F82218D2                 mov     al, g_FoundKernel32Exports
.text:F82218D7                 mov     edi, [esp+8+ImageBase]
.text:F82218DB                 test    al, al
.text:F82218DD                 jnz     short KavInitializePatchApcLabel
.text:F82218DF                 push    edi
.text:F82218E0                 call    KavCheckFindKernel32Exports
.text:F82218E5                 test    al, al
.text:F82218E7                 jz      short loc_F8221936
.text:F82218E9
.text:F82218E9 KavInitializePatchApcLabel:             ; CODE XREF: CheckInjectCodeForNewProcess+2Dj
.text:F82218E9                 push    '3SeB'          ; Tag
.text:F82218EE                 push    30h             ; NumberOfBytes
.text:F82218F0                 push    0               ; PoolType
.text:F82218F2                 call    ds:ExAllocatePoolWithTag
.text:F82218F8                 mov     esi, eax
.text:F82218FA                 test    esi, esi
.text:F82218FC                 jz      short loc_F8221936
.text:F82218FE                 push    edi
.text:F82218FF                 push    0
.text:F8221901                 push    offset KavPatchNewProcessApcRoutine
.text:F8221906                 push    offset loc_F82218A0
.text:F822190B                 push    offset loc_F8221890
.text:F8221910                 push    0
.text:F8221912                 call    KeGetCurrentThread
.text:F8221917                 push    eax
.text:F8221918                 push    esi
.text:F8221919                 call    KeInitializeApc
.text:F822191E                 push    0
.text:F8221920                 push    0
.text:F8221922                 push    0
.text:F8221924                 push    esi
.text:F8221925                 call    KeInsertQueueApc
.text:F822192B                 test    al, al
.text:F822192D                 jnz     short loc_F822193D
.text:F822192F                 push    esi             ; P
.text:F8221930                 call    ds:ExFreePool
.text:F8221936
.text:F8221936 loc_F8221936:                           ; CODE XREF: CheckInjectCodeForNewProcess+9j
.text:F8221936                                         ; CheckInjectCodeForNewProcess+20j ...
.text:F8221936                 pop     edi
.text:F8221937                 xor     al, al
.text:F8221939                 pop     esi
.text:F822193A                 retn    8
.text:F822193D ; ---------------------------------------------------------------------------
.text:F822193D
.text:F822193D loc_F822193D:                           ; CODE XREF: CheckInjectCodeForNewProcess+7Dj
.text:F822193D                 pop     edi
.text:F822193E                 mov     al, 1
.text:F8221940                 pop     esi
.text:F8221941                 retn    8


The APC routine itself patches kernel32's export table (and generates the
thunks to call kernel mode) and adjusts PTE attributes on KAV's driver image
to allow user mode access.

 

.text:F8221810 KavPatchNewProcessApcRoutine proc near  ; DATA XREF: CheckInjectCodeForNewProcess+51o
.text:F8221810
.text:F8221810 var_8           = dword ptr -8
.text:F8221810 var_4           = dword ptr -4
.text:F8221810 ImageBase       = dword ptr  8
.text:F8221810
.text:F8221810                 push    ebp
.text:F8221811                 mov     ebp, esp
.text:F8221813                 sub     esp, 8
.text:F8221816                 mov     eax, [ebp+ImageBase]
.text:F8221819                 push    esi
.text:F822181A                 push    eax             ; ImageBase
.text:F822181B                 call    KavPatchImageForNewProcess
.text:F8221820                 mov     esi, dword_F8230518
.text:F8221826                 mov     eax, dword_F823051C
.text:F822182B                 and     esi, 0FFFFF000h
.text:F8221831                 cmp     esi, eax
.text:F8221833                 mov     [ebp+ImageBase], esi
.text:F8221836                 jnb     short loc_F8221883
.text:F8221838
.text:F8221838 loc_F8221838:                           ; CODE XREF: KavPatchNewProcessApcRoutine+71j
.text:F8221838                 push    esi
.text:F8221839                 call    KavPageTranslation0
.text:F822183F                 push    esi
.text:F8221840                 mov     [ebp+var_8], eax
.text:F8221843                 call    KavPageTranslation1
.text:F8221849                 mov     [ebp+var_4], eax
.text:F822184C                 mov     eax, [ebp+var_8]
.text:F822184F                 lock or dword ptr [eax], 4
.text:F8221853                 lock and dword ptr [eax], 0FFFFFEFFh
.text:F822185A                 mov     eax, [ebp+var_4]
.text:F822185D                 invlpg  byte ptr [eax]
.text:F8221860                 lock or dword ptr [eax], 4
.text:F8221864                 lock and dword ptr [eax], 0FFFFFEFDh
.text:F822186B                 mov     eax, [ebp+ImageBase]
.text:F822186E                 invlpg  byte ptr [eax]
.text:F8221871                 mov     eax, dword_F823051C
.text:F8221876                 add     esi, 1000h
.text:F822187C                 cmp     esi, eax
.text:F822187E                 mov     [ebp+ImageBase], esi
.text:F8221881                 jb      short loc_F8221838
.text:F8221883
.text:F8221883 loc_F8221883:                           ; CODE XREF: KavPatchNewProcessApcRoutine+26j
.text:F8221883                 pop     esi
.text:F8221884                 mov     esp, ebp
.text:F8221886                 pop     ebp
.text:F8221887                 retn    0Ch
.text:F8221887 KavPatchNewProcessApcRoutine endp


.text:F8221750 ; int __stdcall KavPatchImageForNewProcess(PUCHAR ImageBase)
.text:F8221750 KavPatchImageForNewProcess proc near    ; CODE XREF: KavPatchNewProcessApcRoutine+Bp
.text:F8221750
.text:F8221750 ImageBase       = dword ptr  8
.text:F8221750
.text:F8221750                 push    ebx
.text:F8221751                 call    ds:KeEnterCriticalRegion
.text:F8221757                 mov     eax, dword_F82282F4
.text:F822175C                 push    1               ; Wait
.text:F822175E                 push    eax             ; Resource
.text:F822175F                 call    ds:ExAcquireResourceExclusiveLite
.text:F8221765                 push    1
.text:F8221767                 call    KavSetPageAttributes1
.text:F822176C                 mov     ecx, [esp+ImageBase]
.text:F8221770                 push    ecx             ; ImageBase
.text:F8221771                 call    KavPatchImage
.text:F8221776                 push    0
.text:F8221778                 mov     bl, al
.text:F822177A                 call    KavSetPageAttributes1
.text:F822177F                 mov     ecx, dword_F82282F4 ; Resource
.text:F8221785                 call    ds:ExReleaseResourceLite
.text:F822178B                 call    ds:KeLeaveCriticalRegion
.text:F8221791                 mov     al, bl
.text:F8221793                 pop     ebx
.text:F8221794                 retn    4
.text:F8221794 KavPatchImageForNewProcess endp


The actual image patching reprotects the export table of kernel32, changes the
export address table entries for the LoadLibrary* family of functions to point
to a thunk that is written into spare space within the kernel32 image, and
writes the actual thunk code out:


.text:F8221680 ; int __stdcall KavPatchImage(PUCHAR ImageBase)
.text:F8221680 KavPatchImage   proc near               ; CODE XREF: KavPatchImageForNewProcess+21p
.text:F8221680
.text:F8221680 var_C           = dword ptr -0Ch
.text:F8221680 FunctionVa      = dword ptr -8
.text:F8221680 var_4           = dword ptr -4
.text:F8221680 ImageBase       = dword ptr  4
.text:F8221680
.text:F8221680                 mov     eax, [esp+ImageBase]
.text:F8221684                 sub     esp, 0Ch
.text:F8221687                 push    ebp
.text:F8221688                 push    3Ch
.text:F822168A                 push    eax
.text:F822168B                 call    KavReprotectExportTable
.text:F8221690                 mov     ebp, eax
.text:F8221692                 test    ebp, ebp
.text:F8221694                 jnz     short loc_F822169F
.text:F8221696                 xor     al, al
.text:F8221698                 pop     ebp
.text:F8221699                 add     esp, 0Ch
.text:F822169C                 retn    4
.text:F822169F ; ---------------------------------------------------------------------------
.text:F822169F
.text:F822169F loc_F822169F:                           ; CODE XREF: KavPatchImage+14j
.text:F822169F                 push    ebx
.text:F82216A0                 push    esi
.text:F82216A1                 push    edi
.text:F82216A2                 xor     ebx, ebx
.text:F82216A4                 mov     edi, ebp
.text:F82216A6                 mov     esi, offset ExportedFunctionsToCheckTable
.text:F82216AB
.text:F82216AB CheckNextFunctionInTable:               ; CODE XREF: KavPatchImage+B4j
.text:F82216AB                 mov     edx, [esi+0Ch]
.text:F82216AE                 mov     eax, [esp+1Ch+ImageBase]
.text:F82216B2                 lea     ecx, [esp+1Ch+var_C]
.text:F82216B6                 push    ecx
.text:F82216B7                 push    edx
.text:F82216B8                 push    eax
.text:F82216B9                 call    LookupExportedFunction
.text:F82216BE                 test    eax, eax
.text:F82216C0                 mov     [esp+1Ch+FunctionVa], eax
.text:F82216C4                 jz      short loc_F8221725
.text:F82216C6                 mov     edx, [esp+1Ch+var_C]
.text:F82216CA                 lea     ecx, [esp+1Ch+var_4]
.text:F82216CE                 push    ecx
.text:F82216CF                 push    40h
.text:F82216D1                 push    4
.text:F82216D3                 push    edx
.text:F82216D4                 call    KavExecuteNtProtectVirtualMemoryInt2E
.text:F82216D9                 test    al, al
.text:F82216DB                 jz      short loc_F8221725
.text:F82216DD                 cmp     dword ptr [esi], 0
.text:F82216E0                 jnz     short loc_F82216EF
.text:F82216E2                 mov     eax, [esp+1Ch+FunctionVa]
.text:F82216E6                 mov     ecx, [esp+1Ch+var_C]
.text:F82216EA                 mov     [esi], eax
.text:F82216EC                 mov     [esi+8], ecx
.text:F82216EF
.text:F82216EF loc_F82216EF:                           ; CODE XREF: KavPatchImage+60j
.text:F82216EF                 mov     eax, edi
.text:F82216F1                 mov     edx, 90909090h
.text:F82216F6                 mov     [eax], edx
.text:F82216F8                 mov     [eax+4], edx
.text:F82216FB                 mov     [eax+8], edx
.text:F82216FE                 mov     [eax+0Ch], dx
.text:F8221702                 mov     [eax+0Eh], dl
.text:F8221705                 mov     byte ptr [edi], 0E9h
.text:F8221708                 mov     ecx, [esi+4]
.text:F822170B                 mov     edx, ebx
.text:F822170D                 sub     ecx, ebx
.text:F822170F                 sub     ecx, ebp
.text:F8221711                 sub     ecx, 5
.text:F8221714                 mov     [edi+1], ecx
.text:F8221717                 mov     ecx, [esp+1Ch+ImageBase]
.text:F822171B                 mov     eax, [esp+1Ch+var_C]
.text:F822171F                 sub     edx, ecx
.text:F8221721                 add     edx, ebp
.text:F8221723                 mov     [eax], edx      ;
.text:F8221723                                         ; Patching Export Table here
.text:F8221723                                         ; e.g. write to 7c802f58
.text:F8221723                                         ; (kernel32 EAT entry for LoadLibraryA)
.text:F8221723                                         ;
.text:F8221723                                         ;         578  241 00001D77 LoadLibraryA = _LoadLibraryA@4
.text:F8221723                                         ;         579  242 00001D4F LoadLibraryExA = _LoadLibraryExA@12
.text:F8221723                                         ;         580  243 00001AF1 LoadLibraryExW = _LoadLibraryExW@12
.text:F8221723                                         ;         581  244 0000ACD3 LoadLibraryW = _LoadLibraryW@4
.text:F8221723                                         ;
.text:F8221723                                         ; KAV writes a new RVA pointing to its hook code here.
.text:F8221725
.text:F8221725 loc_F8221725:                           ; CODE XREF: KavPatchImage+44j
.text:F8221725                                         ; KavPatchImage+5Bj
.text:F8221725                 add     esi, 10h
.text:F8221728                 add     ebx, 0Fh
.text:F822172B                 add     edi, 0Fh
.text:F822172E                 cmp     esi, offset byte_F82357E0
.text:F8221734                 jb      CheckNextFunctionInTable
.text:F822173A                 pop     edi
.text:F822173B                 pop     esi
.text:F822173C                 pop     ebx
.text:F822173D                 mov     al, 1
.text:F822173F                 pop     ebp
.text:F8221740                 add     esp, 0Ch
.text:F8221743                 retn    4
.text:F8221743 KavPatchImage   endp


KAV's export table reprotecting code assumes that the user mode PE header is
well-formed and does not contain offsets pointing to kernel mode addresses:


.text:F8221360 KavReprotectExportTable proc near       ; CODE XREF: KavPatchImage+Bp
.text:F8221360
.text:F8221360 var_10          = dword ptr -10h
.text:F8221360 var_C           = dword ptr -0Ch
.text:F8221360 var_8           = dword ptr -8
.text:F8221360 var_4           = dword ptr -4
.text:F8221360 arg_0           = dword ptr  4
.text:F8221360 arg_4           = dword ptr  8
.text:F8221360
.text:F8221360                 mov     eax, [esp+arg_0]
.text:F8221364                 sub     esp, 10h
.text:F8221367                 cmp     word ptr [eax], 'ZM'
.text:F822136C                 push    ebx
.text:F822136D                 push    ebp
.text:F822136E                 push    esi
.text:F822136F                 push    edi
.text:F8221370                 jnz     loc_F8221442
.text:F8221376                 mov     esi, [eax+3Ch]
.text:F8221379                 add     esi, eax
.text:F822137B                 mov     [esp+20h+var_C], esi
.text:F822137F                 cmp     dword ptr [esi], 'EP'
.text:F8221385                 jnz     loc_F8221442
.text:F822138B                 lea     eax, [esp+20h+var_8]
.text:F822138F                 xor     edx, edx
.text:F8221391                 mov     dx, [esi+14h]
.text:F8221395                 push    eax
.text:F8221396                 xor     eax, eax
.text:F8221398                 push    40h
.text:F822139A                 mov     ax, [esi+6]
.text:F822139E                 lea     ecx, [eax+eax*4]
.text:F82213A1                 lea     eax, [edx+ecx*8+18h]
.text:F82213A5                 push    eax
.text:F82213A6                 push    esi
.text:F82213A7                 call    KavExecuteNtProtectVirtualMemoryInt2E ; NtProtectVirtualMemory
.text:F82213AC                 test    al, al
.text:F82213AE                 jz      loc_F8221442
.text:F82213B4                 mov     ecx, [esi+8]
.text:F82213B7                 mov     [esp+20h+var_10], 0
.text:F82213BF                 inc     ecx
.text:F82213C0                 mov     [esi+8], ecx
.text:F82213C3                 xor     ecx, ecx
.text:F82213C5                 mov     cx, [esi+14h]
.text:F82213C9                 cmp     word ptr [esi+6], 0
.text:F82213CE                 lea     edi, [ecx+esi+18h]
.text:F82213D2                 jbe     short loc_F8221442
.text:F82213D4                 mov     ebp, [esp+20h+arg_4]
.text:F82213D8
.text:F82213D8 loc_F82213D8:                           ; CODE XREF: KavReprotectExportTable+E0j
.text:F82213D8                 mov     ebx, [edi+10h]
.text:F82213DB                 test    ebx, 0FFFh
.text:F82213E1                 jz      short loc_F82213EA
.text:F82213E3                 or      ebx, 0FFFh
.text:F82213E9                 inc     ebx
.text:F82213EA
.text:F82213EA loc_F82213EA:                           ; CODE XREF: KavReprotectExportTable+81j
.text:F82213EA                 mov     ecx, [edi+8]
.text:F82213ED                 mov     edx, ebx
.text:F82213EF                 sub     edx, ecx
.text:F82213F1                 cmp     edx, ebp
.text:F82213F3                 jle     short loc_F822142C
.text:F82213F5                 mov     esi, [edi+0Ch]
.text:F82213F8                 mov     ecx, [esp+20h+arg_0]
.text:F82213FC                 sub     esi, ebp
.text:F82213FE                 push    ebp
.text:F82213FF                 add     esi, ebx
.text:F8221401                 add     esi, ecx
.text:F8221403                 push    esi
.text:F8221404                 call    KavFindSectionName
.text:F8221409                 test    al, al
.text:F822140B                 jz      short loc_F8221428
.text:F822140D                 cmp     dword ptr [edi+1], 'TINI'
.text:F8221414                 jz      short loc_F8221428
.text:F8221416                 lea     eax, [esp+20h+var_4]
.text:F822141A                 push    eax
.text:F822141B                 push    40h
.text:F822141D                 push    ebp
.text:F822141E                 push    esi
.text:F822141F                 call    KavExecuteNtProtectVirtualMemoryInt2E ; NtProtectVirtualMemory
.text:F8221424                 test    al, al
.text:F8221426                 jnz     short loc_F822144E
.text:F8221428
.text:F8221428 loc_F8221428:                           ; CODE XREF: KavReprotectExportTable+ABj
.text:F8221428                                         ; KavReprotectExportTable+B4j
.text:F8221428                 mov     esi, [esp+20h+var_C]
.text:F822142C
.text:F822142C loc_F822142C:                           ; CODE XREF: KavReprotectExportTable+93j
.text:F822142C                 mov     eax, [esp+20h+var_10]
.text:F8221430                 xor     ecx, ecx
.text:F8221432                 mov     cx, [esi+6]
.text:F8221436                 add     edi, 28h
.text:F8221439                 inc     eax
.text:F822143A                 cmp     eax, ecx
.text:F822143C                 mov     [esp+20h+var_10], eax
.text:F8221440                 jb      short loc_F82213D8
.text:F8221442
.text:F8221442 loc_F8221442:                           ; CODE XREF: KavReprotectExportTable+10j
.text:F8221442                                         ; KavReprotectExportTable+25j ...
.text:F8221442                 pop     edi
.text:F8221443                 pop     esi
.text:F8221444                 pop     ebp
.text:F8221445                 xor     eax, eax
.text:F8221447                 pop     ebx
.text:F8221448                 add     esp, 10h
.text:F822144B                 retn    8
.text:F822144E ; ---------------------------------------------------------------------------
.text:F822144E
.text:F822144E loc_F822144E:                           ; CODE XREF: KavReprotectExportTable+C6j
.text:F822144E                 mov     eax, [edi+8]
.text:F8221451                 mov     [edi+10h], ebx
.text:F8221454                 add     eax, ebp
.text:F8221456                 mov     [edi+8], eax
.text:F8221459                 mov     eax, esi
.text:F822145B                 pop     edi
.text:F822145C                 pop     esi
.text:F822145D                 pop     ebp
.text:F822145E                 pop     ebx
.text:F822145F                 add     esp, 10h
.text:F8221462                 retn    8
.text:F8221462 KavReprotectExportTable endp


The mechanism by which KAV uses to reprotect user mode code is rather much of
a hack as well.  KAV dynamically determines the system call ordinal of the
NtProtectVirtualMemory system service and uses its own int 2e thunk to call the
service.


.text:F8221320 KavExecuteNtProtectVirtualMemoryInt2E proc near
.text:F8221320                                         ; CODE XREF: KavReprotectExportTable+47p
.text:F8221320                                         ; KavReprotectExportTable+BFp ...
.text:F8221320
.text:F8221320 arg_0           = dword ptr  4
.text:F8221320 arg_4           = dword ptr  8
.text:F8221320 arg_8           = dword ptr  0Ch
.text:F8221320 arg_C           = dword ptr  10h
.text:F8221320
.text:F8221320                 mov     eax, [esp+arg_0]
.text:F8221324                 mov     ecx, [esp+arg_C]
.text:F8221328                 mov     edx, [esp+arg_8]
.text:F822132C                 push    ebx
.text:F822132D                 mov     [esp+4+arg_0], eax
.text:F8221331                 push    ecx
.text:F8221332                 lea     eax, [esp+8+arg_4]
.text:F8221336                 push    edx
.text:F8221337                 mov     edx, NtProtectVirtualMemoryOrdinal
.text:F822133D                 lea     ecx, [esp+0Ch+arg_0]
.text:F8221341                 push    eax
.text:F8221342                 push    ecx
.text:F8221343                 push    0FFFFFFFFh
.text:F8221345                 push    edx
.text:F8221346                 xor     bl, bl
.text:F8221348                 call    KavInt2E
.text:F822134D                 test    eax, eax
.text:F822134F                 mov     al, 1
.text:F8221351                 jge     short loc_F8221355
.text:F8221353                 mov     al, bl
.text:F8221355
.text:F8221355 loc_F8221355:                           ; CODE XREF: KavExecuteNtProtectVirtualMemoryInt2E+31j
.text:F8221355                 pop     ebx
.text:F8221356                 retn    10h
.text:F8221356 KavExecuteNtProtectVirtualMemoryInt2E endp


.user:F8231090 KavInt2E        proc near               ; CODE XREF: KavExecuteNtProtectVirtualMemoryInt2E+28p
.user:F8231090
.user:F8231090 arg_0           = dword ptr  8
.user:F8231090 arg_4           = dword ptr  0Ch
.user:F8231090
.user:F8231090                 push    ebp
.user:F8231091                 mov     ebp, esp
.user:F8231093                 mov     eax, [ebp+arg_0]
.user:F8231096                 lea     edx, [ebp+arg_4]
.user:F823109C                 int     2Eh             
.user:F823109C                                         
.user:F823109E                 pop     ebp
.user:F823109F                 retn    18h
.user:F823109F KavInt2E        endp
.user:F823109F


KAV's export lookup code does not correctly validate offsets garnered from the
PE header before using them:


.text:F8220CA0 LookupExportedFunction proc near        ; CODE XREF: sub_F8217A60+C9p
.text:F8220CA0                                         ; sub_F82181D0+Dp ...
.text:F8220CA0
.text:F8220CA0 var_20          = dword ptr -20h
.text:F8220CA0 var_1C          = dword ptr -1Ch
.text:F8220CA0 var_18          = dword ptr -18h
.text:F8220CA0 var_14          = dword ptr -14h
.text:F8220CA0 var_10          = dword ptr -10h
.text:F8220CA0 var_C           = dword ptr -0Ch
.text:F8220CA0 var_8           = dword ptr -8
.text:F8220CA0 var_4           = dword ptr -4
.text:F8220CA0 arg_0           = dword ptr  4
.text:F8220CA0 arg_4           = dword ptr  8
.text:F8220CA0 arg_8           = dword ptr  0Ch
.text:F8220CA0
.text:F8220CA0                 mov     edx, [esp+arg_0]
.text:F8220CA4                 sub     esp, 20h
.text:F8220CA7                 cmp     word ptr [edx], 'ZM'
.text:F8220CAC                 push    ebx
.text:F8220CAD                 push    ebp
.text:F8220CAE                 push    esi
.text:F8220CAF                 push    edi
.text:F8220CB0                 jnz     loc_F8220DE1
.text:F8220CB6                 mov     eax, [edx+3Ch]
.text:F8220CB9                 add     eax, edx
.text:F8220CBB                 cmp     dword ptr [eax], 'EP'
.text:F8220CC1                 jnz     loc_F8220DE1
.text:F8220CC7                 mov     eax, [eax+78h]
.text:F8220CCA                 mov     edi, [esp+30h+arg_4]
.text:F8220CCE                 add     eax, edx
.text:F8220CD0                 mov     [esp+30h+var_14], eax
.text:F8220CD4                 mov     esi, [eax+1Ch]
.text:F8220CD7                 mov     ebx, [eax+24h]
.text:F8220CDA                 mov     ecx, [eax+20h]
.text:F8220CDD                 add     esi, edx
.text:F8220CDF                 add     ebx, edx
.text:F8220CE1                 add     ecx, edx
.text:F8220CE3                 cmp     edi, 1000h
.text:F8220CE9                 mov     [esp+30h+var_4], esi
.text:F8220CED                 mov     [esp+30h+var_C], ebx
.text:F8220CF1                 mov     [esp+30h+var_18], ecx
.text:F8220CF5                 jnb     short loc_F8220D27
.text:F8220CF7                 mov     ecx, [eax+10h]
.text:F8220CFA                 mov     eax, edi
.text:F8220CFC                 sub     eax, ecx
.text:F8220CFE                 mov     eax, [esi+eax*4]
.text:F8220D01                 add     eax, edx
.text:F8220D03                 mov     edx, [esp+30h+arg_8]
.text:F8220D07                 test    edx, edx
.text:F8220D09                 jz      loc_F8220DE3
.text:F8220D0F                 mov     ebx, ecx
.text:F8220D11                 shl     ebx, 1Eh
.text:F8220D14                 sub     ebx, ecx
.text:F8220D16                 add     ebx, edi
.text:F8220D18                 pop     edi
.text:F8220D19                 lea     ecx, [esi+ebx*4]
.text:F8220D1C                 pop     esi
.text:F8220D1D                 pop     ebp
.text:F8220D1E                 mov     [edx], ecx
.text:F8220D20                 pop     ebx
.text:F8220D21                 add     esp, 20h
.text:F8220D24                 retn    0Ch
.text:F8220D27 ; ---------------------------------------------------------------------------
.text:F8220D27
.text:F8220D27 loc_F8220D27:                           ; CODE XREF: LookupExportedFunction+55j
.text:F8220D27                 mov     edi, [eax+14h]
.text:F8220D2A                 mov     [esp+30h+arg_0], 0
.text:F8220D32                 test    edi, edi
.text:F8220D34                 mov     [esp+30h+var_8], edi
.text:F8220D38                 jbe     loc_F8220DE1
.text:F8220D3E                 mov     [esp+30h+var_1C], esi
.text:F8220D42
.text:F8220D42 loc_F8220D42:                           ; CODE XREF: LookupExportedFunction+13Bj
.text:F8220D42                 cmp     dword ptr [esi], 0
.text:F8220D45                 jz      short loc_F8220DC5
.text:F8220D47                 mov     ecx, [eax+18h]
.text:F8220D4A                 xor     ebp, ebp
.text:F8220D4C                 test    ecx, ecx
.text:F8220D4E                 mov     [esp+30h+var_10], ecx
.text:F8220D52                 jbe     short loc_F8220DC5
.text:F8220D54                 mov     edi, [esp+30h+var_18]
.text:F8220D58                 mov     [esp+30h+var_20], ebx
.text:F8220D5C
.text:F8220D5C loc_F8220D5C:                           ; CODE XREF: LookupExportedFunction+11Bj
.text:F8220D5C                 mov     ebx, [esp+30h+var_20]
.text:F8220D60                 xor     esi, esi
.text:F8220D62                 mov     si, [ebx]
.text:F8220D65                 mov     ebx, [esp+30h+arg_0]
.text:F8220D69                 cmp     esi, ebx
.text:F8220D6B                 jnz     short loc_F8220DAA
.text:F8220D6D                 mov     eax, [edi]
.text:F8220D6F                 mov     esi, [esp+30h+arg_4]
.text:F8220D73                 add     eax, edx
.text:F8220D75
.text:F8220D75 loc_F8220D75:                           ; CODE XREF: LookupExportedFunction+F3j
.text:F8220D75                 mov     bl, [eax]
.text:F8220D77                 mov     cl, bl
.text:F8220D79                 cmp     bl, [esi]
.text:F8220D7B                 jnz     short loc_F8220D99
.text:F8220D7D                 test    cl, cl
.text:F8220D7F                 jz      short loc_F8220D95
.text:F8220D81                 mov     bl, [eax+1]
.text:F8220D84                 mov     cl, bl
.text:F8220D86                 cmp     bl, [esi+1]
.text:F8220D89                 jnz     short loc_F8220D99
.text:F8220D8B                 add     eax, 2
.text:F8220D8E                 add     esi, 2
.text:F8220D91                 test    cl, cl
.text:F8220D93                 jnz     short loc_F8220D75
.text:F8220D95
.text:F8220D95 loc_F8220D95:                           ; CODE XREF: LookupExportedFunction+DFj
.text:F8220D95                 xor     eax, eax
.text:F8220D97                 jmp     short loc_F8220D9E
.text:F8220D99 ; ---------------------------------------------------------------------------
.text:F8220D99
.text:F8220D99 loc_F8220D99:                           ; CODE XREF: LookupExportedFunction+DBj
.text:F8220D99                                         ; LookupExportedFunction+E9j
.text:F8220D99                 sbb     eax, eax
.text:F8220D9B                 sbb     eax, 0FFFFFFFFh
.text:F8220D9E
.text:F8220D9E loc_F8220D9E:                           ; CODE XREF: LookupExportedFunction+F7j
.text:F8220D9E                 test    eax, eax
.text:F8220DA0                 jz      short loc_F8220DED
.text:F8220DA2                 mov     eax, [esp+30h+var_14]
.text:F8220DA6                 mov     ecx, [esp+30h+var_10]
.text:F8220DAA
.text:F8220DAA loc_F8220DAA:                           ; CODE XREF: LookupExportedFunction+CBj
.text:F8220DAA                 mov     esi, [esp+30h+var_20]
.text:F8220DAE                 inc     ebp
.text:F8220DAF                 add     esi, 2
.text:F8220DB2                 add     edi, 4
.text:F8220DB5                 cmp     ebp, ecx
.text:F8220DB7                 mov     [esp+30h+var_20], esi
.text:F8220DBB                 jb      short loc_F8220D5C
.text:F8220DBD                 mov     ebx, [esp+30h+var_C]
.text:F8220DC1                 mov     edi, [esp+30h+var_8]
.text:F8220DC5
.text:F8220DC5 loc_F8220DC5:                           ; CODE XREF: LookupExportedFunction+A5j
.text:F8220DC5                                         ; LookupExportedFunction+B2j
.text:F8220DC5                 mov     ecx, [esp+30h+arg_0]
.text:F8220DC9                 mov     esi, [esp+30h+var_1C]
.text:F8220DCD                 inc     ecx
.text:F8220DCE                 add     esi, 4
.text:F8220DD1                 cmp     ecx, edi
.text:F8220DD3                 mov     [esp+30h+arg_0], ecx
.text:F8220DD7                 mov     [esp+30h+var_1C], esi
.text:F8220DDB                 jb      loc_F8220D42
.text:F8220DE1
.text:F8220DE1 loc_F8220DE1:                           ; CODE XREF: LookupExportedFunction+10j
.text:F8220DE1                                         ; LookupExportedFunction+21j ...
.text:F8220DE1                 xor     eax, eax
.text:F8220DE3
.text:F8220DE3 loc_F8220DE3:                           ; CODE XREF: LookupExportedFunction+69j
.text:F8220DE3                                         ; LookupExportedFunction+162j
.text:F8220DE3                 pop     edi
.text:F8220DE4                 pop     esi
.text:F8220DE5                 pop     ebp
.text:F8220DE6                 pop     ebx
.text:F8220DE7                 add     esp, 20h
.text:F8220DEA                 retn    0Ch
.text:F8220DED ; ---------------------------------------------------------------------------
.text:F8220DED
.text:F8220DED loc_F8220DED:                           ; CODE XREF: LookupExportedFunction+100j
.text:F8220DED                 mov     eax, [esp+30h+var_4]
.text:F8220DF1                 mov     ecx, [esp+30h+arg_0]
.text:F8220DF5                 lea     ecx, [eax+ecx*4]
.text:F8220DF8                 mov     eax, [ecx]
.text:F8220DFA                 add     eax, edx
.text:F8220DFC                 mov     edx, [esp+30h+arg_8]
.text:F8220E00                 test    edx, edx
.text:F8220E02                 jz      short loc_F8220DE3
.text:F8220E04                 pop     edi
.text:F8220E05                 pop     esi
.text:F8220E06                 pop     ebp
.text:F8220E07                 mov     [edx], ecx
.text:F8220E09                 pop     ebx
.text:F8220E0A                 add     esp, 20h
.text:F8220E0D                 retn    0Ch
.text:F8220E0D LookupExportedFunction endp
User mode calling KAV kernel code directly without a ring 0 transition:


kd> bp f824d820
kd> g
Breakpoint 0 hit
klif!sub_F8231820:
001b:f824d820 83ec08      sub     esp,0x8
kd> kv
ChildEBP RetAddr  Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
0006f4ec 7432f69c 74320000 00000001 00000000 klif!sub_F8231820
0006f50c 7c9011a7 74320000 00000001 00000000 0x7432f69c
0006f52c 7c91cbab 7432f659 74320000 00000001 ntdll!LdrpCallInitRoutine+0x14
0006f634 7c916178 00000000 c0150008 00000000 ntdll!LdrpRunInitializeRoutines+0x344 (FPO: [Non-Fpo])
0006f8e0 7c9162da 00000000 0007ced0 0006fbd4 ntdll!LdrpLoadDll+0x3e5 (FPO: [Non-Fpo])
0006fb88 7c801bb9 0007ced0 0006fbd4 0006fbb4 ntdll!LdrLoadDll+0x230 (FPO: [Non-Fpo])
0006fc20 f824d749 0106c0f0 0000000e 0107348c 0x7c801bb9
0006fd14 7c918dfa 7c90d625 7c90eacf 00000000 klif!loc_F823173D+0xc
0006fe00 7c910551 000712e8 00000044 0006ff0c ntdll!_LdrpInitialize+0x246 (FPO: [Non-Fpo])
0006fecc 00000000 00072368 00000000 00078c48 ntdll!RtlFreeHeap+0x1e9 (FPO: [Non-Fpo])
kd> t
klif!sub_F8231820+0x3:
001b:f824d823 53          push    ebx
kd> r
eax=0006f3cc ebx=00000000 ecx=00005734 edx=0006f3ea esi=7c882fd3 edi=7432f608
eip=f824d823 esp=0006ef00 ebp=0006f4ec iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
klif!sub_F8231820+0x3:
001b:f824d823 53          push    ebx
kd> dg 1b
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
001B 00000000 ffffffff Code RE    3 Bg Pg P  Nl 00000cfa
kd> !pte eip
               VA f824d823
PDE at   C0300F80        PTE at C03E0934
contains 01010067      contains 06B78065
pfn 1010 ---DA--UWEV    pfn 6b78 ---DA--UREV


KAV crashing the system when stepping through its kernel mode code when called
from user mode (apparently not that reliable after all!):


Breakpoint 0 hit
klif!sub_F8231820:
001b:f824d820 83ec08      sub     esp,0x8
kd> u eip
klif!sub_F8231820:
f824d820 ebfe             jmp     klif!sub_F8231820 (f824d820)
f824d822 085355           or      [ebx+0x55],dl
f824d825 56               push    esi
f824d826 57               push    edi
f824d827 33ed             xor     ebp,ebp
f824d829 6820d824f8       push    0xf824d820
f824d82e 896c2418         mov     [esp+0x18],ebp
f824d832 896c2414         mov     [esp+0x14],ebp
kd> g
Breakpoint 0 hit
klif!sub_F8231820:
001b:f824d820 ebfe        jmp     klif!sub_F8231820 (f824d820)
kd> g
Breakpoint 0 hit
klif!sub_F8231820:
001b:f824d820 ebfe        jmp     klif!sub_F8231820 (f824d820)
kd> bd 0
kd> g
Break instruction exception - code 80000003 (first chance)
*******************************************************************************
*                                                                             *
*   You are seeing this message because you pressed either                    *
*       CTRL+C (if you run kd.exe) or,                                        *
*       CTRL+BREAK (if you run WinDBG),                                       *
*   on your debugger machine's keyboard.                                      *
*                                                                             *
*                   THIS IS NOT A BUG OR A SYSTEM CRASH                       *
*                                                                             *
* If you did not intend to break into the debugger, press the "g" key, then   *
* press the "Enter" key now.  This message might immediately reappear.  If it *
* does, press "g" and "Enter" again.                                          *
*                                                                             *
*******************************************************************************
nt!RtlpBreakWithStatusInstruction:
804e3592 cc               int     3
kd> gu

*** Fatal System Error: 0x000000d1
                       (0x00003592,0x0000001C,0x00000000,0x00003592)

Break instruction exception - code 80000003 (first chance)
*******************************************************************************
*                                                                             *
*   You are seeing this message because you pressed either                    *
*       CTRL+C (if you run kd.exe) or,                                        *
*       CTRL+BREAK (if you run WinDBG),                                       *
*   on your debugger machine's keyboard.                                      *
*                                                                             *
*                   THIS IS NOT A BUG OR A SYSTEM CRASH                       *
*                                                                             *
* If you did not intend to break into the debugger, press the "g" key, then   *
* press the "Enter" key now.  This message might immediately reappear.  If it *
* does, press "g" and "Enter" again.                                          *
*                                                                             *
*******************************************************************************
nt!RtlpBreakWithStatusInstruction:
804e3592 cc               int     3
kd> g
Break instruction exception - code 80000003 (first chance)

A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.

A fatal system error has occurred.

Connected to Windows XP 2600 x86 compatible target, ptr64 FALSE
Loading Kernel Symbols
................................................................................................................
Loading User Symbols
................................
Loading unloaded module list
............
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

Use !analyze -v to get detailed debugging information.

BugCheck D1, {3592, 1c, 0, 3592}

*** ERROR: Module load completed but symbols could not be loaded for klif.sys
Probably caused by : hardware

Followup: MachineOwner
---------
 *** Possible invalid call from 804e331f ( nt!KeUpdateSystemTime+0x160 )
 *** Expected target 804e358e ( nt!DbgBreakPointWithStatus+0x0 )

nt!RtlpBreakWithStatusInstruction:
804e3592 cc               int     3
kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1)
An attempt was made to access a pageable (or completely invalid) address at an
interrupt request level (IRQL) that is too high.  This is usually
caused by drivers using improper addresses.
If kernel debugger is available get stack backtrace.
Arguments:
Arg1: 00003592, memory referenced
Arg2: 0000001c, IRQL
Arg3: 00000000, value 0 = read operation, 1 = write operation
Arg4: 00003592, address which referenced memory

Debugging Details:
------------------


READ_ADDRESS:  00003592 

CURRENT_IRQL:  1c

FAULTING_IP: 
+3592
00003592 ??               ???

PROCESS_NAME:  winlogon.exe

DEFAULT_BUCKET_ID:  INTEL_CPU_MICROCODE_ZERO

BUGCHECK_STR:  0xD1

LAST_CONTROL_TRANSFER:  from 804e3324 to 00003592

FAILED_INSTRUCTION_ADDRESS: 
+3592
00003592 ??               ???

POSSIBLE_INVALID_CONTROL_TRANSFER:  from 804e331f to 804e358e

TRAP_FRAME:  f7872ce0 -- (.trap fffffffff7872ce0)
ErrCode = 00000000
eax=00000001 ebx=000275fc ecx=8055122c edx=000003f8 esi=00000005 edi=ddfff298
eip=00003592 esp=f7872d54 ebp=f7872d64 iopl=0         nv up ei pl nz na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010202
00003592 ??               ???
Resetting default scope

STACK_TEXT:  
WARNING: Frame IP not in any known module. Following frames may be wrong.
f7872d50 804e3324 00000001 f7872d00 000000d1 0x3592
f7872d50 f824d820 00000001 f7872d00 000000d1 nt!KeUpdateSystemTime+0x165
0006f4ec 7432f69c 74320000 00000001 00000000 klif+0x22820
0006f50c 7c9011a7 74320000 00000001 00000000 ODBC32!_DllMainCRTStartup+0x52
0006f52c 7c91cbab 7432f659 74320000 00000001 ntdll!LdrpCallInitRoutine+0x14
0006f634 7c916178 00000000 c0150008 00000000 ntdll!LdrpRunInitializeRoutines+0x344
0006f8e0 7c9162da 00000000 0007ced0 0006fbd4 ntdll!LdrpLoadDll+0x3e5
0006fb88 7c801bb9 0007ced0 0006fbd4 0006fbb4 ntdll!LdrLoadDll+0x230
0006fbf0 7c801d6e 7ffddc00 00000000 00000000 kernel32!LoadLibraryExW+0x18e
0006fc04 7c801da4 0106c0f0 00000000 00000000 kernel32!LoadLibraryExA+0x1f
0006fc20 f824d749 0106c0f0 0000000e 0107348c kernel32!LoadLibraryA+0x94
00000000 00000000 00000000 00000000 00000000 klif+0x22749


STACK_COMMAND:  .trap 0xfffffffff7872ce0 ; kb

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME:  hardware

IMAGE_NAME:  hardware

DEBUG_FLR_IMAGE_TIMESTAMP:  0

BUCKET_ID:  CPU_CALL_ERROR

Followup: MachineOwner
---------
 *** Possible invalid call from 804e331f ( nt!KeUpdateSystemTime+0x160 )
 *** Expected target 804e358e ( nt!DbgBreakPointWithStatus+0x0 )

kd> u 804e331f 
nt!KeUpdateSystemTime+0x160:
804e331f e86a020000       call    nt!DbgBreakPointWithStatus (804e358e)
804e3324 ebb4             jmp     nt!KeUpdateSystemTime+0x11b (804e32da)
804e3326 90               nop
804e3327 fb               sti
804e3328 8d09             lea     ecx,[ecx]
nt!KeUpdateRunTime:
804e332a a11cf0dfff       mov     eax,[ffdff01c]
804e332f 53               push    ebx
804e3330 ff80c4050000     inc     dword ptr [eax+0x5c4]


2.7. The solution.

KAV's anti-virus software relies upon many unsafe kernel-mode hacks that put
system stability in jeopardy.  Removing unsafe kernel mode hacks like
patching non-exported kernel functions or hooking various system services
without parameter validation is the first step towards fixing the problem.

Many of the operations KAV uses hooking or other unsafe means for are doable
using documented and safe APIs and conventions that are well-described in the
Windows Device Driver Kit (DDK) and Installable File System Kit (IFS Kit).  It
would behoove the KAV programmers to take the time to read and understand the
documented way to do things in the Windows kernel instead of taking a quite
literally hack-and-slash approach that leaves the system at risk of crashes
and potentially even privilege escalation.

Many of the unsafe practices relied upon by KAV are blocked by PatchGuard on
x64 and will make it significantly harder to release a 64-bit version of KAV's
anti-virus software (which will become increasingly important as computers are
sold with x64 support and run x64 Windows by default).  Because 32-bit kernel
drivers cannot be loaded on 64-bit Windows, KAV will need to port their driver
to x64 and deal with PatchGuard.  Additionally, assumptions that end user
computers will be uniprocessor are fast becoming obsolete, as most new systems
sold today support HyperThreading or multiple cores.


3. The problem: McAfee Internet Security Suite 2006

McAfee's Internet Security Suite 2006 package includes a number of programs,
including anti-virus, firewall, and anti-spam software.  In particular,
however, this article discusses one particular facet of Internet Security Suite
2006: The McAfee Privacy Service.

This component is designed to intercept outbound traffic and sanitize it of any
predefined sensitive information before it hits the wire.

>From the very start, if one is familiar with network programming, such a goal
would appear to be very difficult to practically achieve.  For instance, many
programs send data in a compressed or encrypted form, and there is no common
way to process such data without writing specialized software for each target
application.  This immediately limits the effectiveness of the Privacy Service
software's generalized information sanitization process to programs that have
a) had specialized handler code written for them, or b) send information to
the Internet in plaintext.  Furthermore, the very act of modifying an outbound
data stream could potentially cause an application to fail (consider the case
where an application network protocol includes its own checksums of data sent
and received, where arbitrary modifications of network traffic might cause it
to be rejected).

The problem with McAfee Internet Security Suite goes deeper, however.  The
mechanism by which Internet Security Suite intercepts (and potentially alters)
outbound network traffic is through a Windows-specific mechanism known as an
LSP (or Layered Service Provider).

LSPs are user mode DLLs that "plug-in" to Winsock (the Windows sockets API) and
are called for every sockets API call that a user mode program makes.  This
allows easy access to view (and modify) network traffic without going through
the complexities of writing a conventional kernel driver.  An LSP is loaded and
called in the context of the program making the original socket API call.

This means that for most programs using user mode socket calls, all API calls
will be redirected through the Internet Security Suite's LSP, for potential
modification.

If one has been paying attention so far, this approach should already be
setting off alarms.  One serious problem with this approach is that since the
LSP DLL itself resides in the same address space (and thus has the same
privileges) as the calling program, there is nothing technically stopping a
malicious program from modifying the LSP DLL's code to exempt itself from
alteration, or even bypassing the LSP directly.

Unfortunately, the flaws in the McAfee Privacy Service do not simply end here,
although already the technical limitations of an LSP for securely intercepting
and modifying network traffic make this approach (in the author's opinion)
wholly unsuitable for a program designed to protect a user from having his or
her private data stolen by malicious software.

Specifically, there are implementation flaws in how the LSP itself handles
certain socket API calls that may cause otherwise perfectly working software
to fail when run under McAfee Internet Security Suite 2006.  This poses a
serious problem to software vendors, who are often forced to interoperate with
pervasive personal security software (such as Internet Security Suite).

The Windows Sockets environment is fully multithreaded and thread-safe, and
allows programs to call into the sockets API from multiple threads concurrently
without risk of data corruption or other instability.  Unfortunately, the LSP
provided by McAfee for its Privacy Service software breaks this particular
portion of the Windows Sockets API contract.  In particular, McAfee's LSP does
not correctly synchronize access to internal data structures when sockets are
created or destroyed, often leading to situations where a newly created socket
handed back to an application program is already mistakenly closed by the
flawed LSP before the application even sees it.

In addition, the author has also observed a similar synchronization problem
regarding the implementation of the `select' function in the Privacy Service
LSP.  The select function is used to poll a set of sockets for a series of
events, such as data being available to read, or buffer space being available
to send data.  The McAfee LSP appears to fail when calls to  select are made
from multiple threads concurrently, however, often appearing to switch a
ocket handle specified by the original application program with an entirely
different handle.  (In Windows, the same handle space is shared by
socket handles and all other types of kernel objects, such as files or
processes and threads).  This subsequently results in calls to select failing
in strange ways, or worse, returning that data is available for a particular
socket when it was in fact available on a different socket entirely.

Both of these flaws result in intermittant failures of correctly written third
party applications when used in conjunction with McAfee Internet Security Suite
2006.

3.2. Solution for Software Vendors

If one is stuck in the unfortunate position of being forced to support software
running under McAfee Internet Security Suite 2006, one potential solution to
this problem is to manually serialize all calls to select (and other functions
that create or destroy sockets, such as socket and the WSASocket family of
functions).  This approach has worked in practice, and is perhaps the least
invasive solution to the flawed LSP.

An alternative solution is to bypass the LSP entirely and instead call directly
to the kernel sockets driver (AFD.sys).  However, this entails determining the
actual handle associated with a socket (the handle returned by the McAfee LSP
is in fact not the underlying socket handle), as well as relying on the as of
yet officially undocumented AFD IOCTL interface.

3.3. Solution for McAfee

>From McAfee's perspective, the solution is fairly simple: correctly serialize
access to internal data structures from function calls that are made from
multiple threads concurrently.


4. Conclusion

As the Internet becomes an increasingly hostile place and the need for in-depth
personal security software (as a supplement or even replacement for proper
system administrator) grows for end-users, it will become increasingly
important for the vendors and providers of personal security software to ensure
that their programs do not impair the normal operation of systems upon which
their software is installed.  The author realizes that such is a very difficult
task given what is expected of most personal security software suites, and
hopes that by shedding light on the flaws in existing software, new programs
can be made to avoid similar mistakes.

你可能感兴趣的:(c,object,Security,user,System,internet)