다음을 통해 공유


사후 관리 디버깅 사용

사용자 모드 예외 처리

예외 및 중단점

가장 일반적인 애플리케이션 오류를 예외라고 합니다. 여기에는 액세스 위반, 0으로 나누기 오류, 숫자 오버플로, CLR 예외 및 기타 여러 종류의 오류가 포함됩니다. 애플리케이션은 중단점 중단을 일으킬 수도 있습니다. 이러한 문제는 Windows에서 애플리케이션을 실행할 수 없거나(예: 필요한 모듈을 로드할 수 없는 경우) 또는 중단점이 발생할 때 발생합니다. 디버거를 통해 코드에 중단점을 삽입하거나 DebugBreak와 같은 함수를 통해 호출할 수 있습니다.

예외 처리기 우선 순위

구성 값 및 활성 디버거에 따라 Windows는 다양한 방법으로 사용자 모드 오류를 처리합니다. 다음 시퀀스는 사용자 모드 오류 처리에 사용되는 우선 순위를 보여줍니다.

  1. 사용자 모드 디버거가 현재 오류 프로세스에 연결된 경우 모든 오류로 인해 대상이 이 디버거에 침입하게 됩니다.

    사용자 모드 디버거가 연결된 한 다른 오류 처리 메서드는 사용되지 않습니다( gn(예외로 이동 처리 안 함) 명령이 사용되더라도.

  2. 사용자 모드 디버거가 연결되어 있지 않고 실행 코드에 자체 예외 처리 루틴이 있는 경우(예 : try - 제외) 이 예외 처리 루틴은 오류를 처리하려고 시도합니다.

  3. 사용자 모드 디버거가 연결되어 있지 않고 Windows에 커널 디버깅 연결이 열려 있고 오류가 중단점 인터럽트인 경우 Windows는 커널 디버거에 연결하려고 시도합니다.

    Windows 부팅 프로세스 중에 커널 디버깅 연결을 열어야 합니다. 사용자 모드 인터럽트가 커널 디버거에 침입하지 않도록 하려면 -du 매개 변수와 함께 KDbgCtrl 유틸리티를 사용할 수 있습니다. 커널 디버깅 연결을 구성하는 방법 및 KDbgCtrl을 사용하는 방법에 대한 자세한 내용은 디버깅을 위한 설정 가져오기를 참조하세요.

    커널 디버거에서 gh(예외 처리로 이동)를 사용하여 오류를 무시하고 대상을 계속 실행할 수 있습니다. gn(처리되지 않은 예외로 이동)을 사용하여 커널 디버거를 우회하고 4단계로 넘어갈 수 있습니다.

  4. 1, 2, 3단계의 조건이 적용되지 않으면 Windows는 AeDebug 레지스트리 값에 구성된 디버깅 도구를 활성화합니다. 이 상황에서 사용할 도구로 모든 프로그램을 미리 선택할 수 있습니다. 선택한 프로그램을 사후 관리 디버거라고 합니다.

  5. 1, 2, 3단계의 조건이 적용되지 않고 등록된 사후 관리 디버거가 없는 경우 WER(Windows 오류 보고)은 메시지를 표시하고 사용 가능한 경우 솔루션을 제공합니다. 또한 적절한 값이 레지스트리에 설정된 경우 WER은 메모리 덤프 파일을 씁니다. 자세한 내용은 WER 사용 및 사용자 모드 덤프 수집을 참조하세요.

DebugBreak 함수

사후 시스템 디버거가 설치된 경우 DebugBreak 함수를 호출하여 사용자 모드 애플리케이션에서 의도적으로 디버거에 침입할 수 있습니다.

Postmortem 디버거 지정

이 섹션에서는 WinDbg와 같은 도구를 사후 관리 디버거로 구성하는 방법을 설명합니다. 구성되면 애플리케이션이 충돌할 때마다 사후 관리 디버거가 자동으로 시작됩니다.

Post Mortem 디버거 레지스트리 키

WER(Windows 오류 보고)은 AeDebug 레지스트리 키에 설정된 값을 사용하여 사후 모듈 디버거 프로세스를 만듭니다.

HKLM\Software\Microsoft\Windows NT\CurrentVersion\AeDebug

관심 있는 두 가지 기본 레지스트리 값인 디버거Auto가 있습니다. 디버거 레지스트리 값은 사후 시스템 디버거에 대한 명령줄을 지정합니다. 자동 레지스트리 값은 사후 시스템 디버거가 자동으로 시작되는지 또는 확인 메시지 상자가 먼저 표시되는지 여부를 지정합니다.

디버거(REG_SZ)

이 REG_SZ 값은 사후 관리 디버깅을 처리할 디버거를 지정합니다.

디버거가 기본 경로에 있는 디렉터리에 있지 않으면 디버거의 전체 경로가 나열되어야 합니다.

명령줄은 3개 매개 변수가 포함된 printf 스타일 호출을 통해 디버거 문자열에서 생성됩니다. 순서가 고정되어 있지만 사용 가능한 매개 변수를 모두 사용할 필요는 없습니다.

DWORD(%ld) - 대상 프로세스의 프로세스 ID입니다.

DWORD(%ld) - 사후 시스템 디버거 프로세스에 중복된 이벤트 핸들입니다. 사후 관리 디버거가 이벤트를 알리는 경우 WER은 사후 시스템 디버거가 종료될 때까지 기다리지 않고 대상 프로세스를 계속합니다. 이 이벤트는 문제가 해결된 경우에만 신호를 받아야 합니다. 이벤트를 알리지 않고 사후 관리 디버거가 종료되면 WER은 대상 프로세스에 대한 정보 수집을 계속합니다.

void* (%p) - 대상 프로세스의 주소 공간에 할당된 JIT_DEBUG_INFO 구조체의 주소입니다. 구조체에는 추가 예외 정보 및 컨텍스트가 포함됩니다.

자동(REG_SZ) 이 REG_SZ 값은 항상 0 또는 1입니다.

자동을 0으로 설정하면 사후 관리 디버깅 프로세스가 시작되기 전에 확인 메시지 상자가 표시됩니다.

Auto를 1설정하면 사후 관리 디버거가 즉시 만들어집니다.

레지스트리를 수동으로 편집할 때 레지스트리를 잘못 변경해도 Windows 부팅이 허용되지 않을 수 있으므로 매우 신중하게 편집합니다.

명령줄 사용 예제

많은 사후 관리 디버거는 -p 및 -e 스위치를 포함하는 명령줄을 사용하여 매개 변수가 각각 PID 및 이벤트임을 나타냅니다. 예를 들어 WinDbg를 통해 windbg.exe -I 설치하면 다음 값이 만들어집니다.

Debugger = "<Path>\WinDbg -p %ld -e %ld -g"
Auto = 1

WER %ld %ld %p 매개 변수를 사용할 수 있는 방법에는 유연성이 있습니다. 예를 들어 WER 매개 변수 주위 또는 간에 스위치를 지정할 필요가 없습니다. 예를 들어 Windows Sysinternals ProcDump를 사용하여 procdump.exe -i 설치하면 WER %ld %ld %p 매개 변수 간에 스위치가 없는 다음 값이 만들어집니다.

Debugger = "<Path>\procdump.exe" -accepteula -j "c:\Dumps" %ld %ld %p
Auto = 1

32비트 및 64비트 디버거

64비트 플랫폼에서는 64비트 및 32비트 애플리케이션에 대해 디버거(REG_SZ) 및 자동(REG_SZ) 레지스트리 값이 개별적으로 정의됩니다. WOW(Windows on Windows) 키는 32비트 애플리케이션 사후 디버깅 값을 저장하는 데 사용됩니다.

HKLM\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug

64비트 플랫폼에서는 32비트 프로세스에 32비트 사후 디버거를 사용하고 64비트 프로세스에는 64비트 디버거를 사용합니다. 이렇게 하면 32비트 프로세스에서 32비트 스레드 대신 WOW64 스레드에 초점을 맞춘 64비트 디버거를 방지할 수 있습니다.

Windows Postmortem 디버거용 디버깅 도구를 비롯한 많은 사후 관리 디버거의 경우 설치 명령을 두 번 실행해야 합니다. x86 버전으로 한 번, x64 버전과 함께 한 번 예를 들어 WinDbg를 대화형 사후 관리 디버거 windbg.exe -I 로 사용하려면 명령이 각 버전에 대해 한 번씩 두 번 실행됩니다.

64비트 설치:

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe –I

이렇게 하면 레지스트리 키가 이러한 값으로 업데이트됩니다.

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug
Debugger = "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe" -p %ld -e %ld –g

32비트 설치:

C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\windbg.exe –I

이렇게 하면 레지스트리 키가 이러한 값으로 업데이트됩니다.

HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug
Debugger = "C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\windbg.exe" -p %ld -e %ld –g

사후 모템 디버거 구성

Windows용 디버깅 도구

Windows용 디버깅 도구는 모두 사후 관리 디버거로 설정되는 것을 지원합니다. 설치 명령은 프로세스를 대화형으로 디버깅하도록 합니다.

WinDbg

사후 모듈 디버거를 WinDbg로 설정하려면 다음을 실행합니다 windbg -I. (대 I 문자로 표시해야 합니다.) 이 명령은 사용된 후 성공 또는 실패 메시지를 표시합니다. 32비트 및 64비트 애플리케이션을 모두 사용하려면 64 및 32 디버거 모두에 대한 명령을 실행합니다.

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe –I
C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\windbg.exe –I

실행 시 AeDebug 레지스트리 항목이 구성 windbg -I 되는 방법입니다.

Debugger = "<Path>\WinDbg -p %ld -e %ld -g"
Auto = 1

예제 <에서 Path> 는 디버거가 있는 디렉터리입니다.

-p 및 -e 매개 변수는 앞에서 설명한 대로 프로세스 ID 및 이벤트를 전달합니다.

-gg(Go) 명령을 WinDbg에 전달하고 현재 명령에서 실행을 계속합니다.

참고 g(Go) 명령을 전달하는 중요한 문제가 있습니다. 이 방법의 문제는 코드가 다시 시작될 때 더 이상 존재하지 않는 일시적인 조건으로 인해 예외가 항상 반복되는 것은 아니라는 것입니다. 이 문제에 대한 자세한 내용은 .jdinfo(JIT_DEBUG_INFO 사용)를 참조하세요.

이 문제를 방지하려면 .jdinfo 또는 .dump /j를 사용합니다. 이 방법을 사용하면 디버거가 관심 있는 코드 오류의 컨텍스트에 있을 수 있습니다. 자세한 내용은 이 항목의 뒷부분에 있는 JIT(Just-In-Time) 디버깅을 참조하세요.

CDB

사후 관리 디버거를 CDB로 설정하려면 cdb -iae(AeDebug 설치) 또는 cdb -iaec KeyString(명령을 사용하여 AeDebug 설치)을 실행합니다.

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\cdb.exe -iae
C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\cdb.exe -iae

-iaec 매개 변수를 사용하는 경우 KeyString은 사후 관리 디버거를 시작하는 데 사용되는 명령줄의 끝에 추가할 문자열을 지정합니다. KeyString에 공백이 포함된 경우 따옴표로 묶어야 합니다.

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\cdb.exe -iaec [KeyString]
C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\cdb.exe -iaec [KeyString]

이 명령은 성공하면 아무 것도 표시하지 않으며 실패할 경우 오류 메시지를 표시합니다.

NTSD

사후 시스템 디버거를 NTSD로 설정하려면 ntsd -iae(AeDebug 설치) 또는 ntsd -iaec KeyString(명령을 사용하여 AeDebug 설치)을 실행합니다.

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\ntsd.exe -iae
C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\ntsd.exe -iae

-iaec 매개 변수를 사용하는 경우 KeyString은 사후 관리 디버거를 시작하는 데 사용되는 명령줄의 끝에 추가할 문자열을 지정합니다. KeyString에 공백이 포함된 경우 따옴표로 묶어야 합니다.

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\ntsd.exe -iaec [KeyString]
C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\ntsd.exe -iaec [KeyString]

이 명령은 성공하면 아무 것도 표시하지 않으며 실패할 경우 새 콘솔 창에 오류가 발생합니다.

참고 - -p %ld -e %ld -g 매개 변수는 항상 사후 관리 디버거의 명령줄에 먼저 나타나므로 -iaec 스위치를 사용하여 -server 매개 변수를 지정하면 안 됩니다. 명령줄에 먼저 표시되지 않으면 -server가 작동하지 않기 때문입니다. 이 매개 변수를 포함하는 사후 배포 디버거를 설치하려면 레지스트리를 수동으로 편집해야 합니다.

Visual Studio JIT 디버거

Visual Studio가 설치된 경우 vsjitdebugger.exe 사후 모템 디버거로 등록됩니다. Visual Studio JIT 디버거는 프로세스를 대화형으로 디버그하려고 합니다.

Debugger = "C:\WINDOWS\system32\vsjitdebugger.exe" -p %ld -e %ld

Visual Studio가 업데이트되거나 다시 설치되면 이 항목이 다시 작성되어 대체 값 집합을 덮어씁니다.

Window Sysinternals ProcDump

Windows Sysinternals ProcDump 유틸리티는 사후 덤프 캡처에도 사용할 수 있습니다. ProcDump 사용 및 다운로드에 대한 자세한 내용은 ProcDump를 참조하세요.

.dump WinDbg 명령과 마찬가지로 ProcDump는 비대화형으로 크래시 덤프를 캡처할 수 있습니다. 캡처는 모든 Windows 시스템 세션에서 발생할 수 있습니다.

덤프 파일 캡처가 완료되면 ProcDump가 종료되고 WER에서 오류를 보고하고 오류 프로세스가 종료됩니다.

procdump를 설치하고 -32비트 및 64비트 사후 디버깅 모두에 대해 ProcDump를 제거하는 데 사용합니다 procdump -i .

<Path>\procdump.exe -i

설치 및 제거 명령은 성공에 따라 수정된 레지스트리 값과 오류 발생 오류를 출력합니다.

레지스트리의 ProcDump 명령줄 옵션은 다음으로 설정됩니다.

Debugger = <Path>\ProcDump.exe -accepteula -j "<DumpFolder>" %ld %ld %p

ProcDump는 PID, 이벤트 및 JIT_DEBUG_INFO 3개 매개 변수를 모두 사용합니다. JIT_DEBUG_INFO 매개 변수에 대한 자세한 내용은 아래 JIT(Just In Time) 디버깅을 참조하세요.

캡처된 덤프의 크기는 기본적으로 크기 옵션 집합이 없는 미니(프로세스/스레드/핸들/모듈/주소 공간), -mp 집합이 있는 MiniPlus(미니 및 MEM_PRIVATE 페이지) 또는 -ma 집합이 있는 Full(모든 메모리 - ".dump /mA"에 해당)으로 설정됩니다.

드라이브 공간이 충분한 시스템의 경우 전체(-ma) 캡처를 사용하는 것이 좋습니다.

-i 옵션과 함께 -ma를 사용하여 모든 메모리 캡처를 지정합니다. 필요에 따라 덤프 파일의 경로를 제공합니다.

<Path>\procdump.exe -ma -i c:\Dumps

드라이브 공간이 제한된 시스템의 경우 MiniPlus(-mp) 캡처를 사용하는 것이 좋습니다.

<Path>\procdump.exe -mp -i c:\Dumps

덤프 파일을 저장할 폴더는 선택 사항입니다. 기본값은 현재 폴더입니다. 폴더는 C:\Windows\Temp에 사용되는 것보다 같거나 더 나은 ACL로 보호되어야 합니다. 폴더와 관련된 보안을 관리하는 방법에 대한 자세한 내용은 Postmortem 디버깅 중 보안을 참조 하세요.

Postmortem 디버거로 ProcDump를 제거하고 이전 설정을 복원하려면 -u(제거) 옵션을 사용합니다.

<Path>\procdump.exe -u

ProcDump에 대한 자세한 내용은 Microsoft Press에서 게시한 Mark Russinovich 및 Aaron Margosis의 ProcDump 및 Windows SysInternals 관리자 참조를 참조하세요.

JIT(Just-In-Time) 디버깅

컨텍스트를 오류 애플리케이션으로 설정

앞에서 설명한 것처럼 JIT_DEBUG_INFO 매개 변수를 사용하여 충돌을 일으킨 예외로 컨텍스트를 설정하는 것이 매우 바람직합니다. 이에 대한 자세한 내용은 .jdinfo(JIT_DEBUG_INFO 사용)를 참조하세요.

Windows용 디버깅 도구

이 예제에서는 .jdinfo <주소> 명령을 사용하여 추가 예외 정보를 표시하고 컨텍스트를 예외 위치로 변경하는 초기 명령(-c)을 실행하도록 레지스트리를 편집하는 방법을 보여 줍니다(.ecxr를 사용하는 방법과 유사하게 컨텍스트를 예외 레코드로 설정).

Debugger = "<Path>\windbg.exe -p %ld -e %ld -c ".jdinfo 0x%p"
Auto = 1

%p 매개 변수는 대상 프로세스의 주소 공간에서 JIT_DEBUG_INFO 구조체의 주소입니다. %p 매개 변수는 16진수 값으로 해석되도록 0x로 미리 추가됩니다. 자세한 내용은 .jdinfo(JIT_DEBUG_INFO 사용)를 참조하세요.

32비트 및 64비트 앱의 혼합을 디버그하려면 위에서 설명한 32비트 및 64비트 레지스트리 키를 모두 구성하고 64비트 및 32비트 WinDbg.exe 위치에 대한 적절한 경로를 설정합니다.

.dump를 사용하여 덤프 파일 만들기

JIT_DEBUG_INFO 데이터를 포함하는 오류가 발생할 때마다 덤프 파일을 캡처하려면 .dump /j <주소를> 사용합니다.

<Path>\windbg.exe -p %ld -e %ld -c ".dump /j %p /u <DumpPath>\AeDebug.dmp; qd"

/u 옵션을 사용하여 고유한 파일 이름을 생성하여 여러 덤프 파일을 자동으로 만들 수 있습니다. 옵션에 대한 자세한 내용은 .dump(덤프 파일 만들기)를 참조하세요.

만든 덤프에는 JITDEBUG_INFO 데이터가 기본 예외 컨텍스트로 저장됩니다. .jdinfo를 사용하여 예외 정보를 보고 컨텍스트를 설정하는 대신 .exr -1을 사용하여 예외 레코드를 표시하고 .ecxr을 사용하여 컨텍스트를 설정합니다. 자세한 내용은 .exr(예외 레코드 표시) .ecxr(예외 컨텍스트 레코드 표시)를 참조하세요.

Windows 오류 보고 - q/qd

디버그 세션이 종료되는 방식에 따라 Windows 오류 보고 오류를 보고하는지 여부가 결정됩니다.

디버거를 닫기 전에 qd를 사용하여 디버그 세션이 분리되면 WER에서 오류를 보고합니다.

q를 사용하여 디버그 세션을 종료하거나 디버거를 분리하지 않고 닫는 경우 WER은 오류를 보고하지 않습니다.

추가 ; q 또는 ; 명령 문자열의 끝에 qd 를 추가하여 원하는 동작을 호출합니다.

예를 들어 CDB가 덤프를 캡처한 후 WER에서 오류를 보고할 수 있도록 하려면 이 명령 문자열을 구성합니다.

<Path>\cdb.exe -p %ld -e %ld -c ".dump /j 0x%p /u c:\Dumps\AeDebug.dmp; qd"

이 예제에서는 WinDbg가 덤프를 캡처한 후 WER이 오류를 보고하도록 허용합니다.

<Path>\windbg.exe -p %ld -e %ld -c ".dump /j %p /u <DumpPath>\AeDebug.dmp; qd""

보안 취약성

다른 사용자와 공유하는 컴퓨터에서 사후 관리 디버깅을 사용하도록 설정하려는 경우 사후 관리 디버깅 중 보안을 참조하세요.