WinDbg 시작(커널 모드)

WinDbg는 Windows용 디버깅 도구에 포함된 커널 모드 및 사용자 모드 디버거입니다. 이 문서에서는 WinDbg를 커널 모드 디버거로 사용하기 시작하는 데 도움이 되는 연습을 제공합니다.

Windows용 디버깅 도구를 가져오는 방법에 대한 자세한 내용은 WinDbg Windows 디버거 다운로드 및 설치를 참조하세요. 디버깅 도구를 설치한 후 64비트(x64) 및 32비트(x86) 버전의 도구에 대한 설치 디렉터리를 찾습니다. 예시:

  • C:\Program Files (x86)\Windows Kits\10\Debuggers\x64
  • C:\Program Files (x86)\Windows Kits\10\Debuggers\x86

커널 모드 디버깅 설정

커널 모드 디버깅 환경에는 일반적으로 호스트 컴퓨터와 대상 컴퓨터라는 두 대의 컴퓨터있습니다. 디버거는 호스트 컴퓨터에서 실행되며 디버깅 중인 코드는 대상 컴퓨터에서 실행됩니다. 호스트와 대상은 디버그 케이블로 연결됩니다.

Windows 디버거는 다음과 같은 유형의 케이블을 지원합니다.

  • 이더넷
  • USB 2.0/USB 3.0
  • 직렬(null 모뎀이라고도 함)

속도와 안정성을 위해 로컬 네트워크 허브와 함께 이더넷 케이블을 사용해야 합니다. 다음 다이어그램에서는 이더넷 케이블을 사용하여 디버깅하기 위해 연결된 호스트 및 대상 컴퓨터를 보여 줍니다.

Diagram showing host and target computers connected via Ethernet for debugging.

이전 버전의 Windows에 대한 옵션은 USB 또는 직렬 케이블과 같은 직접 케이블을 사용하는 것입니다.

Diagram illustrating host and target computers connected using a debug cable for debugging.

호스트 및 대상 컴퓨터를 설정하는 방법에 대한 자세한 내용은 수동으로 커널 모드 디버깅 설정을 참조하세요.

가상 머신 - VM

Hyper-V 가상 머신에 디버거를 연결하는 방법에 대한 자세한 내용은 가상 머신 KDNET의 네트워크 디버깅 설정을 참조하세요.

커널 모드 디버깅 세션 설정

호스트 및 대상 컴퓨터를 설정하고 디버그 케이블에 연결한 후 커널 모드 디버깅 세션을 설정할 수 있습니다. 설정에 사용한 것과 동일한 항목의 지침을 따릅니다. 예를 들어 이더넷을 통해 디버깅할 호스트 및 대상 컴퓨터를 설정하려는 경우 다음 문서에서 커널 모드 디버깅 세션을 설정하기 위한 지침을 찾을 수 있습니다.

WinDbg 사용 시작

  1. 호스트 컴퓨터에서 WinDbg를 열고 대상 컴퓨터와 커널 모드 디버깅 세션을 설정합니다.

  2. 디버거 설명서 CHM 파일을 열려면 도움말 메뉴로 이동하여 내용을 선택합니다. 디버거 설명서는 Windows용 디버깅 도구에서도 온라인으로 사용할 수 있습니다.

  3. 커널 모드 디버깅 세션을 설정하면 WinDbg가 자동으로 대상 컴퓨터에 침입할 수 있습니다. WinDbg가 중단되지 않으면 디버그 메뉴로 이동하여 중단선택합니다.

  4. WinDbg 창 아래쪽의 명령줄에서 다음 명령을 입력합니다.

    .sympath srv*

    다음 예제와 유사하게 출력됩니다.

    Symbol search path is: srv*
    Expanded Symbol search path is: cache*;SRV*https://msdl.microsoft.com/download/symbols
    

    기호 검색 경로는 WinDbg에 기호(PDB) 파일을 찾을 위치를 알려줍니다. 디버거는 함수 이름 및 변수 이름과 같은 코드 모듈에 대한 정보를 얻기 위해 기호 파일이 필요합니다.

    다음 명령을 입력합니다. 이 명령은 WinDbg에 기호 파일의 초기 찾기 및 로드를 수행하도록 지시합니다.

    .새로고침

  5. 로드된 모듈 목록을 보려면 다음 명령을 입력합니다.

    Lm

    다음 예제와 유사하게 출력됩니다.

    0:000>3: kd> lm
    start             end                 module name
    fffff800`00000000 fffff800`00088000   CI         (deferred)
    ...
    fffff800`01143000 fffff800`01151000   BasicRender   (deferred)
    fffff800`01151000 fffff800`01163000   BasicDisplay  (deferred)
    ...
    fffff800`02a0e000 fffff800`03191000   nt  (pdb symbols) C:\...\ntkrnlmp.pdb
    fffff800`03191000 fffff800`03200000   hal (deferred)
    ...
    
  6. 대상 컴퓨터 실행을 시작하려면 다음 명령을 입력합니다.

    g

  7. 다시 중단하려면 디버그 메뉴로 이동하여 중단선택합니다.

  8. 다음 명령을 입력하여 모듈의 _FILE_OBJECT 데이터 형식을 nt 검사합니다.

    dt nt!_FILE_OBJECT

    다음 예제와 유사하게 출력됩니다.

    0:000>0: kd> dt nt!_FILE_OBJECT
       +0x000 Type             : Int2B
       +0x002 Size             : Int2B
       +0x008 DeviceObject     : Ptr64 _DEVICE_OBJECT
       +0x010 Vpb              : Ptr64 _VPB
       ...
       +0x0c0 IrpList          : _LIST_ENTRY
       +0x0d0 FileObjectExtension : Ptr64 Void
    
  9. 다음 명령을 입력하여 모듈의 일부 기호를 nt 검사합니다.

    x nt!*CreateProcess*

    다음 예제와 유사하게 출력됩니다.

    0:000>0: kd> x nt!*CreateProcess*
    fffff800`030821cc nt!ViCreateProcessCallbackInternal (<no parameter info>)
    ...
    fffff800`02e03904 nt!MmCreateProcessAddressSpace (<no parameter info>)
    fffff800`02cece00 nt!PspCreateProcessNotifyRoutine = <no type information>
    ...
    
  10. 다음 명령을 입력하여 MmCreateProcessAddressSpace에 중단점을 배치합니다.

    bu nt! MmCreateProcessAddressSpace

    중단점이 설정되어 있는지 확인하려면 다음 명령을 입력합니다.

    Bl

    다음 예제와 유사하게 출력됩니다.

    0:000>0: kd> bu nt!MmCreateProcessAddressSpace
    0: kd> bl
    0 e fffff800`02e03904     0001 (0001) nt!MmCreateProcessAddressSpace
    

    대상 컴퓨터를 실행할 수 있도록 g를 입력합니다.

  11. 대상 컴퓨터가 디버거에 즉시 침입하지 않는 경우 대상 컴퓨터에서 몇 가지 작업을 수행합니다(예: 메모장 열기). MmCreateProcessAddressSpace가 호출되면 대상 컴퓨터가 디버거에 침입합니다. 스택 추적을 보려면 다음 명령을 입력합니다.

    .새로고침

    k

    다음 예제와 유사하게 출력됩니다.

    0:000>2: kd> k
    Child-SP          RetAddr           Call Site
    ffffd000`224b4c88 fffff800`02d96834 nt!MmCreateProcessAddressSpace
    ffffd000`224b4c90 fffff800`02dfef17 nt!PspAllocateProcess+0x5d4
    ffffd000`224b5060 fffff800`02b698b3 nt!NtCreateUserProcess+0x55b
    ...
    000000d7`4167fbb0 00007ffd`14b064ad KERNEL32!BaseThreadInitThunk+0xd
    000000d7`4167fbe0 00000000`00000000 ntdll!RtlUserThreadStart+0x1d
    
  12. 보기 메뉴에서 디스어셈블리를 선택합니다.

    디버그 메뉴에서 [단계별 실행]을 선택하거나 F10 키를 누릅니다. 디스어셈블리 창을 보면서 단계 명령을 몇 번 더 입력합니다.

  13. 다음 명령을 입력하여 중단점을 지웁다.

    기원전*

    대상 컴퓨터를 실행할 수 있도록 g를 입력합니다. 다시 중단하려면 디버그 메뉴로 이동하여 중단선택하거나 Ctrl-Break를 누릅니.

  14. 모든 프로세스 목록을 보려면 다음 명령을 입력합니다.

    !process 0 0

    다음 예제와 유사하게 출력됩니다.

    0:000>0: kd> !process 0 0
    **** NT ACTIVE PROCESS DUMP ****
    PROCESS ffffe000002287c0
        SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
        DirBase: 001aa000  ObjectTable: ffffc00000003000  HandleCount: <Data Not Accessible>
        Image: System
    
    PROCESS ffffe00001e5a900
        SessionId: none  Cid: 0124    Peb: 7ff7809df000  ParentCid: 0004
        DirBase: 100595000  ObjectTable: ffffc000002c5680  HandleCount: <Data Not Accessible>
        Image: smss.exe
    ...
    PROCESS ffffe00000d52900
        SessionId: 1  Cid: 0910    Peb: 7ff669b8e000  ParentCid: 0a98
        DirBase: 3fdba000  ObjectTable: ffffc00007bfd540  HandleCount: <Data Not Accessible>
        Image: explorer.exe
    
  15. 한 프로세스의 주소를 복사하고 다음 명령을 입력합니다.

    !process Address 2

    예: !process ffffe00000d5290 2

    출력은 프로세스의 스레드를 보여 줍니다.

    0:000>0:000>0: kd> !process ffffe00000d52900 2
    PROCESS ffffe00000d52900
        SessionId: 1  Cid: 0910    Peb: 7ff669b8e000  ParentCid: 0a98
        DirBase: 3fdba000  ObjectTable: ffffc00007bfd540  HandleCount:
        Image: explorer.exe
    
            THREAD ffffe00000a0d880  Cid 0910.090c  Teb: 00007ff669b8c000
                ffffe00000d57700  SynchronizationEvent
    
            THREAD ffffe00000e48880  Cid 0910.0ad8  Teb: 00007ff669b8a000
                ffffe00000d8e230  NotificationEvent
                ffffe00000cf6870  Semaphore Limit 0xffff
                ffffe000039c48c0  SynchronizationEvent
            ...
            THREAD ffffe00000e6d080  Cid 0910.0cc0  Teb: 00007ff669a10000
                ffffe0000089a300  QueueObject
    
  16. 한 스레드의 주소를 복사하고 다음 명령을 입력합니다.

    !thread Address

    예: !thread ffffe00000e6d080

    출력에는 개별 스레드에 대한 정보가 표시됩니다.

    0: kd> !thread ffffe00000e6d080
    THREAD ffffe00000e6d080  Cid 0910.0cc0  Teb: 00007ff669a10000 Win32Thread: 0000000000000000 WAIT: ...
        ffffe0000089a300  QueueObject
    Not impersonating
    DeviceMap                 ffffc000034e7840
    Owning Process            ffffe00000d52900       Image:         explorer.exe
    Attached Process          N/A            Image:         N/A
    Wait Start TickCount      13777          Ticks: 2 (0:00:00:00.031)
    Context Switch Count      2              IdealProcessor: 1
    UserTime                  00:00:00.000
    KernelTime                00:00:00.000
    Win32 Start Address ntdll!TppWorkerThread (0x00007ffd14ab2850)
    Stack Init ffffd00021bf1dd0 Current ffffd00021bf1580
    Base ffffd00021bf2000 Limit ffffd00021bec000 Call 0
    Priority 13 BasePriority 13 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
    ...
    
  17. 플러그 앤 플레이 디바이스 트리에서 모든 디바이스 노드를 보려면 다음 명령을 입력합니다.

    !devnode 0 1

    0:000>0: kd> !devnode 0 1
    Dumping IopRootDeviceNode (= 0xffffe000002dbd30)
    DevNode 0xffffe000002dbd30 for PDO 0xffffe000002dc9e0
      InstancePath is "HTREE\ROOT\0"
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
      DevNode 0xffffe000002d9d30 for PDO 0xffffe000002daa40
        InstancePath is "ROOT\volmgr\0000"
        ServiceName is "volmgr"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeEnumerateCompletion (0x30d)
        DevNode 0xffffe00001d49290 for PDO 0xffffe000002a9a90
          InstancePath is "STORAGE\Volume\{3007dfd3-df8d-11e3-824c-806e6f6e6963}#0000000000100000"
          ServiceName is "volsnap"
          TargetDeviceNotify List - f 0xffffc0000031b520  b 0xffffc0000008d0f0
          State = DeviceNodeStarted (0x308)
          Previous State = DeviceNodeStartPostWork (0x307)
    ...
    
  18. 디바이스 노드 및 해당 하드웨어 리소스를 보려면 다음 명령을 입력합니다.

    !devnode 0 9

    0:000>...
            DevNode 0xffffe000010fa770 for PDO 0xffffe000010c2060
              InstancePath is "PCI\VEN_8086&DEV_2937&SUBSYS_2819103C&REV_02\3&33fd14ca&0&D0"
              ServiceName is "usbuhci"
              State = DeviceNodeStarted (0x308)
              Previous State = DeviceNodeEnumerateCompletion (0x30d)
              TranslatedResourceList at 0xffffc00003c78b00  Version 1.1  Interface 0x5  Bus #0
                Entry 0 - Port (0x1) Device Exclusive (0x1)
                  Flags (0x131) - PORT_MEMORY PORT_IO 16_BIT_DECODE POSITIVE_DECODE
                  Range starts at 0x3120 for 0x20 bytes
                Entry 1 - DevicePrivate (0x81) Device Exclusive (0x1)
                  Flags (0000) -
                  Data - {0x00000001, 0x00000004, 0000000000}
                Entry 2 - Interrupt (0x2) Shared (0x3)
                  Flags (0000) - LEVEL_SENSITIVE
                  Level 0x8, Vector 0x81, Group 0, Affinity 0xf
    ...
    
  19. 디스크서비스 이름이 있는 디바이스 노드를 보려면 다음 명령을 입력합니다.

    !devnode 0 1 디스크

    0: kd> !devnode 0 1 disk
    Dumping IopRootDeviceNode (= 0xffffe000002dbd30)
    DevNode 0xffffe0000114fd30 for PDO 0xffffe00001159610
      InstancePath is "IDE\DiskST3250820AS_____________________________3.CHL___\5&14544e82&0&0.0.0"
      ServiceName is "disk"
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
    ...
    
  20. !devnode 0 1출력은 노드에 대한 PDO(물리적 디바이스 개체)의 주소를 보여 줍니다. PDO(물리적 디바이스 개체)의 주소를 복사하고 다음 명령을 입력합니다.

    !devstack PdoAddress

    예: <PdoAddress>!devstack 0xffffe00001159610

    0:000>0: kd> !devstack 0xffffe00001159610
      !DevObj           !DrvObj            !DevExt           ObjectName
      ffffe00001d50040  \Driver\partmgr    ffffe00001d50190  
      ffffe00001d51450  \Driver\disk       ffffe00001d515a0  DR0
      ffffe00001156e50  \Driver\ACPI       ffffe000010d8bf0  
    
  21. 드라이버 disk.sys 대한 정보를 얻으려면 다음 명령을 입력합니다.

    !drvobj disk 2

    0:000>0: kd> !drvobj disk 2
    Driver object (ffffe00001d52680) is for:
     \Driver\disk
    DriverEntry:   fffff800006b1270 disk!GsDriverEntry
    DriverStartIo: 00000000
    DriverUnload:  fffff800010b0b5c CLASSPNP!ClassUnload
    AddDevice:     fffff800010aa110 CLASSPNP!ClassAddDevice
    
    Dispatch routines:
    [00] IRP_MJ_CREATE                      fffff8000106d160    CLASSPNP!ClassGlobalDispatch
    [01] IRP_MJ_CREATE_NAMED_PIPE           fffff80002b0ab24    nt!IopInvalidDeviceRequest
    [02] IRP_MJ_CLOSE                       fffff8000106d160    CLASSPNP!ClassGlobalDispatch
    [03] IRP_MJ_READ                        fffff8000106d160    CLASSPNP!ClassGlobalDispatch
    ...
    [1b] IRP_MJ_PNP                         fffff8000106d160    CLASSPNP!ClassGlobalDispatch
    
  22. 출력 !drvobj 은 디스패치 루틴의 주소를 보여 줍니다. 예: CLASSPNP!ClassGlobalDispatch. 중단 ClassGlobalDispatch점을 설정하고 확인하려면 다음 명령을 입력합니다.

    bu CLASSPNP! ClassGlobalDispatch

    Bl

    대상 컴퓨터를 실행할 수 있도록 입력 g 합니다.

    대상 컴퓨터가 디버거에 즉시 침입하지 않는 경우 대상 컴퓨터에서 몇 가지 작업을 수행합니다(예: 메모장 열고 파일을 저장). 대상 컴퓨터는 호출될 때 ClassGlobalDispatch 디버거에 침입합니다. 스택 추적을 보려면 다음 명령을 입력합니다.

    .새로고침

    k

    다음 예제와 유사하게 출력됩니다.

    2: kd> k
    Child-SP          RetAddr           Call Site
    ffffd000`21d06cf8 fffff800`0056c14e CLASSPNP!ClassGlobalDispatch
    ffffd000`21d06d00 fffff800`00f2c31d volmgr!VmReadWrite+0x13e
    ffffd000`21d06d40 fffff800`0064515d fvevol!FveFilterRundownReadWrite+0x28d
    ffffd000`21d06e20 fffff800`0064578b rdyboost!SmdProcessReadWrite+0x14d
    ffffd000`21d06ef0 fffff800`00fb06ad rdyboost!SmdDispatchReadWrite+0x8b
    ffffd000`21d06f20 fffff800`0085cef5 volsnap!VolSnapReadFilter+0x5d
    ffffd000`21d06f50 fffff800`02b619f7 Ntfs!NtfsStorageDriverCallout+0x16
    ...
    
  23. 디버깅 세션을 종료하려면 다음 명령을 입력합니다.

    Qd

명령 요약

참고 항목