기타 검사

드라이버 검증 도구의 기타 검사 옵션은 활성 커널 개체가 여전히 포함된 메모리를 해제하는 것과 같이 드라이버 또는 시스템이 충돌하는 일반적인 오류에 대해 드라이버를 모니터링합니다.

특히 기타 검사 옵션은 다음과 같은 부적절한 드라이버 동작을 찾습니다.

  • 해제된 메모리의 활성 작업 항목입니다. 드라이버는 ExFreePool 을 호출하여 IoQueueWorkItem을 사용하여 큐에 대기된 작업 항목이 포함된 풀 블록을 해제합니다.

  • 해제된 메모리의 활성 리소스입니다. 드라이버는 ExFreePool 을 호출하여 활성 ERESOURCE 구조가 포함된 풀 블록을 해제합니다. 드라이버는 ExFreePool을 호출하기 전에 ExDeleteResource를 호출하여 ERESOURCE 개체를 삭제해야 합니다.

  • 해제된 메모리의 활성 lookaside 목록입니다. 드라이버는 ExFreePool 을 호출하여 활성 lookaside 목록(NPAGED_LOOKASIDE_LIST 또는 PAGED_LOOKASIDE_LIST 구조체가 여전히 포함된 풀 블록을 해제합니다. 드라이버는 ExFreePool을 호출하기 전에 ExDeleteNPagedLookasideList 또는 ExDeletePagedLookasideList를 호출하여 lookaside 목록을 삭제해야 합니다.

  • WMI(Windows Management Instrumentation) 및 ETW(Windows용 이벤트 추적) 등록 문제 드라이버 검증 도구에서 검색된 이러한 문제는 다음과 같습니다.

    • WMI 콜백의 등록을 취소하지 않고 언로드를 시도하는 드라이버입니다.

    • WMI에서 등록 취소되지 않은 디바이스 개체를 삭제하려는 드라이버입니다.

    • ETW 커널 모드 공급자의 등록을 취소하지 않고 언로드를 시도하는 드라이버입니다.

    • 이미 등록 취소된 공급자의 등록을 취소하려는 드라이버입니다.

  • 커널은 오류를 처리합니다. (Windows Vista 이상 버전) 기타 검사 옵션을 사용하도록 설정하면 커널 핸들 누수 및 버그 검사 0x93: INVALID_KERNEL_HANDLE 조사하는 데 도움이 되는 시스템 프로세스에 대한 핸들 추적도 사용할 수 있습니다. 핸들 추적을 사용하도록 설정하면 커널은 최근 핸들 열기 및 닫기 작업에 대한 스택 추적을 수집합니다. !htrace 디버거 확장을 사용하여 커널 디버거에 스택 추적을 표시할 수 있습니다. !htrace에 대한 자세한 내용은 Windows용 디버깅 도구 설명서를 참조하세요.

  • 커널 모드 액세스를 사용하여 사용자 모드 핸들 Windows 7부터 기타 검사 옵션을 선택하면 드라이버 검증 도구는 ObReferenceObjectByHandle 호출도 확인합니다. 커널 모드 액세스 권한이 있는 사용자 모드 핸들은 전달할 수 없습니다. 이러한 작업이 발생하면 드라이버 검증 도구는 매개 변수 1 값이 0xF6 버그 검사 0xC4 발급합니다.

  • UserMode 커널 스택에 할당된 동기화 개체 대기

    Windows 7부터 드라이버 검증 도구는 드라이버가 운영 체제에서 제공하는 다중 스레딩 동기화 메커니즘을 잘못 사용할 수 있는 추가 방법을 검색할 수 있습니다.

    KEVENT 구조와 같은 동기화 개체를 커널 스택의 지역 변수로 할당하는 것이 일반적입니다. 프로세스가 메모리에 로드되는 동안 스레드의 커널 스택은 작업 집합에서 잘리거나 디스크로 페이징되지 않습니다. 이러한 비페이징할 수 없는 메모리에서 동기화 개체를 할당하는 것은 올바릅니다.

    그러나 드라이버가 KeWaitForSingleObject 또는 KeWaitForMultipleObjects와 같은 API를 호출하여 스택에 할당된 개체를 기다리는 경우 API의 WaitMode 매개 변수에 대해 KernelMode 값을 지정해야 합니다. 프로세스의 모든 스레드가 UserMode 모드에서 대기하는 경우 해당 프로세스는 디스크로 교환될 수 있습니다. 따라서 드라이버가 UserModeWaitMode 매개 변수로 지정한 경우 동일한 프로세스의 다른 모든 스레드가 UserMode로 대기하는 한 운영 체제는 현재 프로세스를 교환할 수 있습니다. 전체 프로세스를 디스크로 교환하는 데는 커널 스택 페이징이 포함됩니다. 운영 체제가 교환된 동기화 개체를 기다리는 것은 올바르지 않습니다. 어떤 시점에서 스레드가 따라와 동기화 개체에 신호를 전송해야 합니다. 동기화 개체 신호에는 IRQL = DISPATCH_LEVEL 이상에서 개체를 조작하는 Windows 커널이 포함됩니다. DISPATCH_LEVEL 이상에서 메모리를 페이징하거나 교환하면 시스템 크래시가 발생합니다.

    Windows 7부터 기타 검사 옵션을 선택하면 드라이버 검증 도구는 확인된 드라이버가 UserMode 에서 대기하는 데 사용하는 동기화 개체가 현재 스레드의 커널 스택에 할당되지 않는지 확인합니다. 드라이버 검증 도구가 잘못된 대기를 감지하면 매개 변수 1 값 이 0x123 버그 검사 0xC4 DRIVER_VERIFIER_DETECTED_VIOLATION.

  • 잘못된 커널 핸들 참조

    각 Windows 프로세스에는 핸들 테이블이 있습니다. 핸들 테이블을 핸들 항목의 배열로 볼 수 있습니다. 유효한 각 핸들 값은 이 배열의 유효한 항목을 참조합니다.

    커널 핸들은 시스템 프로세스의 핸들 테이블에 유효한 핸들입니다. 사용자 핸들은 시스템 프로세스를 제외한 모든 프로세스에 유효한 핸들입니다.

    Windows 7에서 드라이버 검증 도구는 잘못된 커널 핸들 값을 참조하려고 시도하는 것을 검색합니다. 이러한 드라이버 결함은 버그 검사 0x93 보고됩니다. 드라이버 검증 도구 기타 검사 옵션을 사용하는 경우 INVALID_KERNEL_HANDLE. 일반적으로 이러한 종류의 잘못된 핸들 참조는 드라이버가 핸들을 이미 닫았지만 계속 사용하려고 한다는 것을 의미합니다. 이러한 종류의 결함으로 인해 참조되는 핸들 값이 관련 없는 다른 드라이버에서 이미 재사용되었을 수 있으므로 시스템에서 예측할 수 없는 문제가 발생할 수 있습니다.

    커널 드라이버가 최근에 커널 핸들을 닫았고 나중에 닫힌 핸들을 참조하는 경우 드라이버 검증 도구는 이전에 설명한 대로 버그 검사 강제로 적용합니다. 이 경우 !htrace 디버거 확장의 출력은 이 핸들을 닫은 코드 경로에 대한 스택 추적을 제공합니다. 시스템 프로세스의 주소를 !htrace의 매개 변수로 사용합니다. 시스템 프로세스의 주소를 찾으려면 !process 4 0 명령을 사용합니다.

    Windows 7부터 드라이버 검증 도구는 ObReferenceObjectByHandle에 검사 추가합니다. 이제 KernelMode 액세스를 사용하여 사용자 공간 핸들을 전달할 수 없습니다. 이러한 조합이 감지되면 드라이버 검증 도구는 매개 변수 1 값 이 0xF6 DRIVER_VERIFIER_DETECTED_VIOLATION 버그 검사 0xC4 발급합니다.

이 옵션 활성화

드라이버 검증 도구 관리자 또는 Verifier.exe 명령줄을 사용하여 하나 이상의 드라이버에 대해 기타 검사 옵션을 활성화할 수 있습니다. 자세한 내용은 드라이버 검증 도구 옵션 선택을 참조하세요.

  • 명령줄에서

    명령줄에서 기타 검사 옵션은 비트 11(0x800)으로 표시됩니다. 기타 검사를 활성화하려면 플래그 값 0x800 사용하거나 플래그 값에 0x800 추가합니다. 예:

    verifier /flags 0x800 /driver MyDriver.sys
    

    옵션은 다음 부팅 후 활성화됩니다.

    Windows Vista 이상 버전의 Windows에서는 / volatile 매개 변수를 명령에 추가하여 컴퓨터를 다시 부팅하지 않고 기타 검사를 활성화하고 비활성화할 수도 있습니다. 예:

    verifier /volatile /flags 0x800 /adddriver MyDriver.sys
    

    이 설정은 즉시 적용되지만 컴퓨터를 종료하거나 다시 부팅하면 손실됩니다. 자세한 내용은 휘발성 설정 사용을 참조하세요.

    기타 검사 옵션도 표준 설정에 포함됩니다. 예:

    verifier  /standard /driver MyDriver.sys
    
  • 드라이버 검증 도구 관리자 사용

    1. 드라이버 검증 도구 관리자를 시작합니다. 명령 프롬프트 창에 검증 도구를 입력합니다.

    2. 사용자 지정 설정 만들기(코드 개발자용)를 선택하고 다음을 클릭합니다.

    3. 전체 목록에서 개별 설정 선택을 선택합니다.

    4. 기타 검사를 선택합니다.

    기타 검사 기능도 표준 설정에 포함되어 있습니다. 이 기능을 사용하려면 드라이버 검증 도구 관리자에서 표준 설정 만들기를 클릭합니다.

결과 보기

기타 검사 옵션의 결과를 보려면 커널 디버거에서 !verifier 확장을 사용합니다. (!verifier에 대한 자세한 내용은 Windows용 디버깅 도구 설명서를 참조하세요.)

다음 예제에서 기타 검사 옵션은 드라이버가 해제하려는 메모리의 활성 ERESOURCE 구조를 감지하여 버그 검사 0xC4: DRIVER_VERIFIER_DETECTED_VIOLATION. 버그 검사 0xC4 디스플레이에는 ERESOURCE의 주소와 영향을 받는 메모리가 포함됩니다.

1: kd> !verifier 1

Verify Level 800 ... enabled options are:
 Miscellaneous checks enabled

Summary of All Verifier Statistics

RaiseIrqls                             0x0
AcquireSpinLocks                       0x0
Synch Executions                       0x0
Trims                                  0x0

Pool Allocations Attempted             0x1
Pool Allocations Succeeded             0x1
Pool Allocations Succeeded SpecialPool 0x0
Pool Allocations With NO TAG           0x0
Pool Allocations Failed                0x0
Resource Allocations Failed Deliberately   0x0

Current paged pool allocations         0x0 for 00000000 bytes
Peak paged pool allocations            0x0 for 00000000 bytes
Current nonpaged pool allocations      0x0 for 00000000 bytes
Peak nonpaged pool allocations         0x0 for 00000000 bytes

Driver Verification List

Entry     State           NonPagedPool   PagedPool   Module

8459ca50 Loaded           00000000       00000000    buggy.sys



*** Fatal System Error: 0x000000c4
 (0x000000D2,0x9655D4A8,0x9655D468,0x000000B0)


        0xD2 : Freeing pool allocation that contains active ERESOURCE.
               2 -  ERESOURCE address.
               3 -  Pool allocation start address.
               4 -  Pool allocation size.

풀 할당을 조사하려면 풀 할당의 시작 주소인 9655D468과 함께 ! pool 디버거 확장을 사용합니다. (2 플래그는 지정된 주소를 포함하는 풀에 대한 헤더 정보만 표시합니다. 다른 풀의 헤더 정보는 표시되지 않습니다.)

1: kd> !pool 9655d468  2
Pool page 9655d468 region is Paged pool
*9655d468 size:   b0 previous size:    8  (Allocated) *Bug_

ERESOURCE에 대한 정보를 찾으려면 구조체의 주소와 함께 !locks(!kdext*.locks) 디버거 확장을 사용합니다.

1: kd> !locks 0x9655D4A8     <<<<<- ERESOURCE @0x9655D4A8 lives inside the pool block being freed

Resource @ 0x9655d4a8    Available
1 total locks

kb 디버거 명령을 사용하여 실패로 이어진 호출의 스택 추적을 표시할 수도 있습니다. 다음 예제에서는 드라이버 검증 도구가 가로채는 ExFreePoolWithTag 호출을 포함하여 스택을 보여줍니다.

1: kd> kb
ChildEBP RetAddr  Args to Child
92f6374c 82c2c95a 00000003 92f68cdc 00000000 nt!RtlpBreakWithStatusInstruction
92f6379c 82c2d345 00000003 9655d468 000000c4 nt!KiBugCheckDebugBreak+0x1c
92f63b48 82c2c804 000000c4 000000d2 9655d4a8 nt!KeBugCheck2+0x5a9
92f63b6c 82e73bae 000000c4 000000d2 9655d4a8 nt!KeBugCheckEx+0x1e
92f63b88 82e78c32 9655d4a8 9655d468 000000b0 nt!VerifierBugCheckIfAppropriate+0x3c
92f63ba4 82ca7dcb 9655d468 000000b0 00000000 nt!VfCheckForResource+0x52
92f63bc8 82e7fb2d 000000b0 00000190 9655d470 nt!ExpCheckForResource+0x21
92f63be4 82e6dc6c 9655d470 92f63c18 89b6c58c nt!ExFreePoolSanityChecks+0x1fb
92f63bf0 89b6c58c 9655d470 00000000 89b74194 nt!VerifierExFreePoolWithTag+0x28
92f63c00 89b6c0f6 846550c8 846550c8 846e2200 buggy!MmTestProbeLockForEverStress+0x2e
92f63c18 82e6c5f1 846e2200 846550c8 85362e30 buggy!TdDeviceControl+0xc4
92f63c38 82c1fd81 82d4d148 846550c8 846e2200 nt!IovCallDriver+0x251
92f63c4c 82d4d148 85362e30 846550c8 84655138 nt!IofCallDriver+0x1b
92f63c6c 82d4df9e 846e2200 85362e30 00000000 nt!IopSynchronousServiceTail+0x1e6
92f63d00 82d527be 00000001 846550c8 00000000 nt!IopXxxControlFile+0x684
92f63d34 82cb9efc 0000004c 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
92f63d34 6a22b204 0000004c 00000000 00000000 nt!KiFastCallEntry+0x12c