Uninformed: Informative Information for the Uninformed

Vol 4» 2006.Jun


Improper Validation of User-mode Pointers

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 user address space is not a very good idea. For example, 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