디버거 작동 방식. Windows 커널 디버깅 도구 커널 디버깅이란?

핵 수준과 Windows에는 가치있는 디버거가 거의 없으며 Linux에서는 한 손의 손가락으로 계산할 수 있으며 대부분 원시, 미완성 또는 버려지고 이끼로 자란 ... 오늘 우리는 가장 인기 있고 흥미로운 -
리니이스.

소개

이름에서 이미 짐작할 수 있듯이 리니이스전설의 비공식 "항구"입니다.
Linux용 SoftICE, 인터페이스, 명령 시스템 및 후자의 대부분의 기능을 유지했습니다. 리니이스이것 ); 모든 기능 및 시스템 호출에 하드웨어 중단점 설정 GDT/LDT/IDT, 메모리의 물리적 페이지 보기; GDB에서 차용한 기능(CALL 명령으로 임의 함수 호출, 레지스터 컨텍스트 저장/복원, 내부 변수 등).

재진입이 불가능하고 방어로 쉽게 탐지할 수 있는 ptrace 메커니즘을 통해 작동하는 대부분의 다른 디버거와 달리(윈도우에 상응하는 DEBUG_PROCESS는 애플리케이션 디버거에서 사용됨), 리니이스 SoftICE에서와 동일한 기본 추적을 사용하여 두 디버거가 다른 사람이 더 이상 처리할 수 없는 강력하게 보호된 프로그램을 디버깅할 수 있습니다.

사실, 이것은 포트가 아니라(따라서 인용문) 처음부터 작성되고 소스 코드로 무료로 배포되는 독립적인 프로젝트입니다(SoftICE에서는 영감만 있습니다). 2.4 커널의 코드 대부분은 독일 해커 Goran Devik이 작성했지만 2.6 커널은 완전히 다른 사람들인 Daniel Reznick, Peter K. 및 Carlos Manuel Duclos Vergara가 지원했습니다. 그리고 우리 동포 인 Oleg Khudakov는 nasm "에서 어셈블러 파일을 다시 작성했습니다.
gcc.

소스 텍스트는 프로젝트의 공식 웹사이트에 있습니다.
라인%0A.com">www.Linice.com, 설명서, 간단한 FAQ 및 포럼 링크도 있습니다.
라인%0A">groups.google.com/group/Linice . 사전 빌드된 바이너리 빌드가 없습니다.
이 프로젝트의 제작자는 SourceForge에서 자신의 계정을 열었지만 파일을 넣기에는 너무 게을러서 "매우 낮은 품질의 3개의 스크린샷만 제공했습니다.
.

시스템 요구 사항

최신 버전 리니이스번호가 2.6이고 날짜가 2005년 7월 28일이며 2.4.x 커널 및 콘솔 VGA 모드를 완전히 지원합니다. 최신 커널에는 심각한 문제가 있으며 2.6.x 커널은 제한적으로만 지원됩니다.
디버거는 Debian 2.6에서 개발 및 테스트되었습니다. 다른 배포판과의 호환성이 보장되지 않아 탬버린에 의존해야 하지만 경우에 따라 탬버린도 도움이 되지 않습니다. 실제로 데비안을 작업할 수 있도록 컴퓨터에 유지하십시오. 리니이스,-아주 정상입니다. 오래 전에 NT용 SoftICE가 구현되지 않았을 때 많은 해커들이 Win 9x를 프로그램을 깨기 위해서만 설치했습니다.
NT. 설치의 모든 세부 사항을 다루기 때문에 리니이스한 기사의 틀 내에서 실제로 비현실적이므로 컴파일 및 실행 프로세스를 설명하는 것으로 제한하겠습니다. 리니이스하나의 특정 배포판 - VGA 콘솔 모드에서 커널 2.4.1이 포함된 Knoppix 3.7.
리니이스 ACPI 및 다중 프로세서 시스템을 지원하지만 X "mi, 특히 nVidia 이외의 비디오 카드에서는 친숙하지 않습니다. 24 비트 색 심도를 전혀 인식하지 못하고 8, 16 및 32 비트 만 "소화"하므로 더 좋습니다. VT100 프로토콜을 사용하여 COM 포트를 통해 연결된 원격 터미널을 통해 X 응용 프로그램을 디버깅하는 데 편리하며 로컬 키보드도 작동합니다.
리니이스!

Linice 컴파일 및 구성

소스 코드 www의 gzip 아카이브를 다운로드합니다. 리니이스.devic.us/ 리니이스-2.6.tar.gz는 1메가바이트도 안 되는 용량을 가지고 디스크에 압축을 풀고 ./docs 디렉토리로 이동하여 readme 파일에서 디버거가 다음과 같이 2.4 커널용으로 어셈블된다는 것을 알아봅니다.

# CD 빌드
# ./make_bin-2.4
# cd ../빈
# 깨끗하게 하다; 막이자형

그러나 make를 실행하기 전에 ./bin-2.4/Makefile을 열고 대상 플랫폼의 구성 및 아키텍처와 일치하도록 "TARGET" 줄을 편집해야 합니다. 특히 멀티 코어 또는 하이퍼스레딩 프로세서가 있는 ACPI 시스템에서는 다음과 같이 표시됩니다.

대상=-DSMP-DIO_APIC

컴파일이 완료되면 ./bin 디렉토리에 많은 파일과 디렉토리가 있지만 중요한 파일은 다음과 같습니다.

linsym - 디버거 로드 모듈;
lininc.dat - 구성 파일;
xice - X "s 지원, 텍스트 모드에서 작업할 때 삭제할 수 있습니다.
./Linice_2.4.27/Linice.o는 디버거 자체를 포함하는 로드 가능한 커널 모듈입니다.

조립 과정 리니이스

최소한으로 작동하는 키트를 컴파일한 후에는 ./test 디렉토리에 있고 컴파일 스크립트에 의해 컴파일된 데모 디버깅 예제와 ./ext 디렉토리, make 명령으로 어셈블되고 insmod 명령으로 로드됩니다. 그것으로 인한 이점은 없지만 소스 코드를 연구하여 기능을 확장하는 자체 모듈을 작성할 수 있습니다.
리니이스.

Knoppix를 부팅할 때 화면 하단에 "boot:" 프롬프트가 표시되며 "knoppix 2 vga=normal"을 입력해야 합니다. 2 "blocks the loading of X"s, "vga=normal"은 80x25 해상도의 표준 VGA 모드.

다운로드가 완료될 때까지 기다린 후 "su"라고 말한 다음 "passwd"라고 말하고 루트 "a에 대한 새 암호를 입력합니다. 여기서 로그인 명령을 사용하여 시스템에 즉시 로그인합니다. 이것이 완료되지 않으면 다음을 시도합니다. 시작 리니이스"분할 오류"라는 외침과 함께 압도적 인 실패로 끝납니다.

하드 드라이브(LiveCD 세션 아래에서 터미널 창에 입력한 "sudo knoppix-installer" 명령으로 설치할 수 있음)에서 Knoppix "a를 부팅하면 사용 가능한 커널 목록과 함께 시작 메뉴가 나타납니다. 선택 Linux(2.4) -1을 누르고 부팅 매개변수 설정 - "2 vga=normal". 코어가 이미 선택되어 있으므로 "knoppix"라는 단어를 쓸 필요가 없습니다. 다운로드가 완료되면 로그인 명령을 내리고 루트로 로그인합니다(이전에 계정이 생성된 것으로 가정).

디버거는 ./linsym –i 명령으로 실행된 후 즉시 화면에 나타납니다. 그렇지 않으면 "--verbose 3" 키를 지정하여 진단 메시지를 표시해 보십시오.
부팅 실패의 원인 중 하나는 커널 기능의 주소를 포함하는 /boot/System.map 파일이 없기 때문일 수 있습니다. System.map의 내용이 현재 커널과 일치하지 않는 경우에도 로드가 실패합니다. 예를 들어 재컴파일될 때 발생할 수 있습니다. 일부 배포 컴파일러는 System.map을 전혀 포함하지 않거나(루트킷이 syscall을 가로채기 더 어렵기 때문에 시스템을 더 안전하게 만들 것이라고 믿습니다) 또는 어디에도 오지 않은 것을 여기에 완전히 남겨두었습니다. 조금도. 그런 경우에는 디버거가 /boot 이외의 위치에 있는 경우 "-m" 스위치를 사용하여 System.map 파일을 가리키도록 하여 커널을 간단히 다시 컴파일하면 됩니다. 따라서 두 보안 모두 영향을 받지 않으며 리니이스일할 수있다!
디버거에서 시스템으로의 복귀는 다음에 의해 발생합니다. 또는 "x ". 콤비네이션 모든 프로그램에서 디버거를 호출합니다. 그러나 Linux는 프로세스를 차례로 전환하는 멀티 태스킹 시스템이고 ADDR (컨텍스트 전환) 명령이 "어휘집"에 있기 때문에 우리가 그 맥락에서 자신을 찾을 것이라는 것은 전혀 사실이 아닙니다. 리니이스아직 존재하지 않으며 언제 나타날지 알 수 없습니다. 따라서 특정 프로그램에서 사용하는 시스템 호출에 중단점을 설정하거나 지금부터 이야기할 INT 03h 방법을 사용하여 프로세스에 침입하여 속임수를 써야 합니다.

동일한 linsym에 전달된 "-x" 키는 디버거 언로드를 담당합니다(실제로 언로드하려는 경우).

작업의 기본 사항 리니이스

이미 SoftICE로 작업하신 분들은 마스터링 리니이스어떤 문제도 제시하지 않습니다. 여기에는 동일한 명령이 모두 사용됩니다. D - 메모리 덤프, E - 메모리 편집, T - 단계별 추적, P - 함수를 입력하지 않고 추적, R - 레지스터 보기/수정, BPM/BPX - 중단점 설정 메모리 액세스/실행 등 명령의 전체 목록은 HELP에 의해 호출되는 기본 제공 도움말(그런데 "HELP command_name"은 명령에 대한 추가 정보를 제공함)과 표준 문서에 모두 포함되어 있습니다.

누르자 현재 프로세스가 파란색으로 강조 표시된 상태에서 PROC 명령으로 표시되는 프로세스 목록을 뒤집니다.

:PROC

1 0000 C1C3E000 휴면 0 0 초기화
2 0000 F7EE8000 휴면 0 0 케벤트
3 0000 F7EE2000 휴면 0 0 ksoftirqd_CPU0
4 0000 F7EE0000 휴면 0 0 ksoftirqd_CPU1
5 0000 F7ED0000 휴면 0 0 kswapd
6 0000 F7EAA000 휴면 0 0 bdflush
7 0000 F7EA8000 휴면 0 0 업데이트됨
56 0000 F6A36000 수면 중 0 0 kjournald
1006 0000 F7A34000 실행 중 0 0 자동 마운트
1013 0000 F68E6000 슬리핑 0 0 cupsd
...
1105 0000 F6DDE000 휴면 0 0mc
1106 0000 F6DD4000 SLEEPING 0 0 cons.saver

물론 프로세스는 훌륭하지만 어떻게 프로그램을 디버깅할 수 있습니까? 가장 간단한 방법은 INT 03h 명령어에 해당하는 CCh 기계 명령어를 원래 바이트의 내용을 이전에 기록한 진입점에 붙이는 것입니다. 이것은 모든 16진수 편집기로 수행할 수 있습니다. 예를 들어, 제가 반복해서 언급한
HTE.

편집기에 파일을 로드한 후 (모드), 엘프/이미지를 선택하고 커서를 "entrypoint:"로 조정하고 (편집) 첫 번째 바이트를 CCh로 변경하고 다음으로 변경 사항을 저장합니다. (저장 및 종료. 패치된 프로그램을 시작할 때 리니이스 EIP가 종료를 표시한 후 CCh에 의해 발생한 예외에 의해 즉시 팝업됩니다.
CCh.

디버거가 팝업되는 순간 패치된 진입점이 있는 프로그램의 상태

0023:080482C0 CC int 3
0023:080482C1 ED in eax, dx
0023:080482C2 5E 팝 esi
0023:080482C3 89E1 이동 ecx, 특히

커서는 패치된 xor ebp,ebp(31h EDh) 명령의 샤드인 in eax,dx(EDh) 명령을 가리킵니다. 이제 (이론적으로) CCh를 31h로 변경하여 원래 바이트를 복원하고 EIP 레지스터를 1씩 감소시킨 다음 평소처럼 추적을 계속해야 합니다.

예, 거기에 없었습니다! 리니이스-물론 이것은 포트이지만 매우 조잡하며 쓰기를 위해 코드 세그먼트를 먼저 열더라도 페이지 이미지 메모리를 수정할 수 없습니다. E(편집), F(채우기), M(메모리 복사) 모두 작동하지 않습니다! 그러나 스택에 쓰기 작업을 수행하고 우리 해커에게는 이것으로 충분합니다.

EIP 레지스터의 현재 값을 기억합니다. 패치된 기계 명령어를 스택의 맨 위에 복사합니다. 거기에서 CCh 바이트를 복원합니다. EIP의 값을 변경하여 제어권을 이전합니다. 단일 추적 작업을 수행하여 실행합니다. EIP를 해당 위치, 즉 다음 기계 명령으로 되돌립니다.

INT 03h 명령으로 대체된 원래 바이트 복원

; 우리는 (순수한 호기심에서) 스택 맨 위에 있는 것을 봅니다.
:d ESP-10
0018:BFFFEFC0 C0 82 04 08 00 00 00 00 5D 0C 00 40 DC EF FF BF

; 패치된 기계 명령어를 스택 맨 위에 복사합니다.
; 숫자 10h는 x86에서 가능한 기계 명령어의 최대 크기입니다.
:m eip-1 L 10 esp-10

; 스택이 어떻게 변경되었는지 살펴보겠습니다.
:d ESP-10
0018:BFFFEFC0 CC ED 5E 89 E1 83 E4 F0 50 54 52 68 F0 85 04 08

; 아하! 스택이 실제로 변경되었습니다. 이제 31h에서 CCh를 수정할 때입니다.
:e esp-10 31
아직 구현되지 않은 즉시 데이터를 편집합니다.

; 이런! 직접 데이터 할당은 Linice에서 구현되지 않습니다.
; 그러나 덤프를 대화식으로 편집할 수 있습니다(예:
; SoftICE에서와 같이) 또는 명령 F esp-10 L 1 31, 명심하십시오.
; SoftICE와 달리 Linice 디버거는 덤프 창을 업데이트하지 않습니다.
; 따라서 F 명령을 실행한 후 다음과 같이 나타날 수 있습니다.
; 결과가 없다; 사실 그렇지 않습니다. 업데이트만 하면 됩니다.
; 덤프 명령 D esp-10, 모든 것이 제자리에 떨어질 것입니다.

; 스택에 복사된 명령으로 제어권을 이전합니다.
; EIP 레지스터의 값을 기억하십시오.
:reip (esp-10)
reg:eip=BFFFEFC0

; 단일 추적 작업을 수행합니다.
:티
0023:BFFFEFC2 5E 팝 esi

; 보시다시피 EIP 레지스터가 2 증가했습니다(BFFFEFC2h - BFFFEFC0h) = 02h,
; 따라서 다음 명령의 주소는 080482C1h - 01h + 02h = 080482C2h입니다.
; 여기서 080482C1h는 프로그램 진입시 EIP의 초기값이고 01h는 INT 03h의 크기이다.

; 패치된 명령 다음에 오는 명령으로 EIP를 설정합니다.
:reip 80482C2
reg:eip=80482C2

탬버린과 함께하는 이러한 춤은 편곡되어야 합니다. 그리고 무엇을 해야 할까요? 따라서 디버거에 프로그램을 로드하는 방법을 알아냈으므로 이제 시스템 호출 및 커널 기능에 대한 중단점을 분리할 것입니다.

exp 명령은 커널이 내보낸 이름을 인쇄합니다. 예를 들어 "bpx do_bkr"은 "bpx C012C9E8"과 동일합니다.

커널에서 내보낸 이름 나열

:exp
핵심
C0320364 mmu_cr4_features
C02AC3A4 acpi_disabled
C02AC8A0 i8253_lock
...
C012BDA8 do_mmap_pgoff
C012C764 do_munmap
C012C9E8 do_brk
C011E990 종료_mm
C011E69C exit_files

시스템 호출이 더 어렵습니다. 에서 직접 지원 리니이스여기에 없습니다(Linux의 특성을 감안할 때 있어야 합니다). 따라서 이 작업은 손으로 수행해야 합니다.

시스템 호출 테이블은 sys_call_table 주소에서 시작하는 이중 단어 배열로 알려져 있습니다(이 변수는 커널에서 내보냅니다).

시스템 호출 테이블

; 디버거를 이중 단어 표시 모드로 설정합니다.
:dd

; 화면에 테이블을 표시합니다.
:d sys_call_table
0018:C02AB6A8 C0126ACC F8932650 F89326A0 C013DC10
0018:C02AB6B8 C013DD18 C013D5C8 C013D724 C011F3BC
0018:C02AB6C8 C013D664 C014A8E0 C014A3B4 F893020C

각 테이블 요소는 자체 시스템 호출에 해당하고 각 호출에는 자체 번호가 있으며 /usr/include/sys/syscall.h 파일을 보면 찾을 수 있지만 Linux에서는 이렇게 하지 않는 것이 좋습니다. 직통 번호는 아니지만 BSD에서 동일한 파일을 빌리기 위해 모든 시스템의 기본 시스템 호출 번호는 동일합니다. 특히 개방형 시스템 호출은 5번입니다.

열 때 중단점을 설정하려면 시스템 호출 테이블의 다섯 번째 더블 워드에 있는 주소를 알아야 하며 0부터 세고 C013D5C8h와 같습니다.

열린 시스템 호출에 중단점 설정

; 열린 시스템 호출에 중단점을 설정하고,
:bpx C013D5C8
; 디버거 종료
:엑스
...
# 어떤 파일을 연다
...
; 디버거가 즉시 팝업되어 이에 대해 알려줍니다.
:BPX 01로 인한 중단점

; 우리는 우리가 우리의 프로세스에 쐐기를 박았는지 확인하기 위해 proc 명령을 내립니다.
:프로시저
PID TSS 작업 상태 uid gid 이름
1049 0000 F6364000 수면 0 0 게티
1145 0000 F61CC000 휴면 0 0mc
1146 0000 F614A000 절전 0 0 cons.saver

이렇게 하면 사용하는 시스템 호출에 중단점을 설정하고 해킹에 필수적인 다른 많은 작업을 수행하여 이미 실행 중인 프로세스에 쉽게 개입할 수 있습니다.

결론

솔직한 습기에도 불구하고 리니이스일반 디버거에서 자동으로 수행되는 해결 방법에 자주 의존해야 하지만 보호된 응용 프로그램을 디버깅하는 데 매우 적합합니다. 그래서 리니이스결코 gdb를 대체하는 것이 아니라 단지 보완할 뿐입니다.

"커널 디버깅"이라는 용어는 커널의 내부 데이터 구조를 검사하거나 커널의 기능을 단계별로 실행하는 것을 의미합니다. 이 디버깅은 다른 방법으로는 사용할 수 없는 내부 시스템 정보를 표시하고 커널에서 코드의 진행 상황을 명확하게 보여주기 때문에 Windows 내부를 탐색하는 데 매우 유용한 방법입니다.

커널을 디버깅하는 다양한 방법을 살펴보기 전에 이러한 디버깅을 수행하는 데 필요한 파일 집합을 살펴보겠습니다.

커널 디버깅 기호

기호 파일에는 함수 및 변수의 이름과 데이터 구조의 스키마 및 형식이 포함됩니다. 이들은 링커 프로그램에 의해 생성되며 디버거에서 이러한 이름을 참조하고 디버그 세션 중에 표시하는 데 사용됩니다. 이 정보는 코드가 실행될 때 필요하지 않기 때문에 일반적으로 바이너리로 저장되지 않습니다. 이것은 이것이 없으면 바이너리가 더 작아지고 더 빠르게 실행된다는 것을 의미합니다. 그러나 이는 또한 디버깅할 때 디버거가 디버깅 세션 동안 참조되는 바이너리 이미지와 연결된 기호 파일에 액세스할 수 있는지 확인해야 함을 의미합니다.

커널 모드 디버깅 도구를 사용하여 Windows 커널 데이터 구조(프로세스 목록, 스레드 블록, 로드된 드라이버 목록, 메모리 사용 정보 등)의 내부를 검사하려면 적절한 기호 파일과 최소한 하나의 기호 파일이 필요합니다. 커널 바이너리 이미지 Ntoskrnl.exe의 경우. 기호 테이블 파일은 추출된 이진 이미지의 버전과 일치해야 합니다. 예를 들어 Windows 서비스 팩이나 일부 커널 업데이트 패치를 설치한 경우 적절하게 업데이트된 기호 파일을 구해야 합니다.

다른 버전의 Windows용 기호를 다운로드하고 설치하는 것은 쉽지만 핫픽스용 기호를 항상 업데이트할 수 있는 것은 아닙니다. 디버깅을 위해 올바른 버전의 기호를 얻는 가장 쉬운 방법은 디버거에 지정된 기호 경로에 대한 특수 구문을 사용하여 전용 Microsoft 기호 서버를 사용하는 것입니다. 예를 들어 다음 기호 경로는 디버거가 인터넷 기호 서버에서 기호를 다운로드하고 c:\symbols:srv*c:\symbols*http://msdl.microsoft.com/download/symbols에 로컬 복사본을 저장하도록 합니다.

문자 서버 사용에 대한 자세한 지침은 디버깅 도구 도움말 파일 또는 인터넷(http://msdn.microsoft.com/en-us/windows/hardware/gg462988.aspx)에서 찾을 수 있습니다.

ChPF OELPFPTSCHE HLBBOYS RP TBVPFE U PFMBDLPK SDTB U BCHBTYKOSHCHNY DBNRBNY RBNSFY. LBL RTBCHYMP, CHBN OKHTSOP VKHDEF ЪBDBFSH PDOP YЪ HUFTPKUFCH RPDLBYULY, RETEYUMEOOOSCHI CH ZHBKME /etc/fstab. KHUFTPKUFCHB, OE SCHMSAEYEUS KHUFTPKUFCHBNY RPDLBYULY, OBRTYNET, MEOFSHCH, CH DBOOSCHK NPNEOF OE RPDDETSYCHBAFUS에 대한 uVTPU PVTBCHBNY RBNSFY.

메모: YURPMSHЪKhKFE LPNBODH 덤폰 (8) DMS HLBBOYS SDTH NEUFB, ZDE OHTSOP UPITBOSFSH BCHBTYKOSHCHE DBNRSHCH. rPUME OBUFTPCLY RP LPNBODE 스왑 (8) TBDEMB RPDLBYULY DPMTSOB VSHCHFSH CHSHCHCHBOB RTPZTBNNB 덤프 . PVSHYUOP LFP CHSHCHRPMOSEPHUS BDBOYEN RETENEOOPK dumpdev H JBKME rc.conf (5). eUMMY BDBOB LFB RETENEOOBS, FP RPUME UVPS RTY RETCHPK NOPZPRPMSHPCHBFEMSHULPK RETEEBZTHЪLE VHDEF BCHFPNBFYUEULY BRHEEO RTPZTBNNB 세이브코어(8). pOB UPITBOYF BCHBTYKOSHK DBNR SDTB W LBFBMPZ, JBDBOOSCHK H RETENEOOPC 덤프디렉토리 JBKMB rc.conf . rp HNPMYUBOYA LBFBMPZPN DMS BCHBTYKOSHCHI DBNRPC SCHMSEFUS /var/crash .

MYVP CH NPCEFE ЪBDBFSH HUFTPKUFCHP DMS UVTPUB PVTBB RBNSFY SCHOP Yuete RBTBNEFT 덤프 CH UFTPL 구성 LPOZHJZHTBGYPOOPZP ZHBKMB CHBYEZP SDTB. fblpk urpupv yurpmshъpchbfsh oe telpneodhefus y po po dpmtseo yurpmshъpchbfshus, fpmshlp eumy chsh ipfyfe rpmhyubfsh bchbtykoshche pvtbjsch rbnsfy sdtb, lpfptpe vbtoppe. vpfh rty hbzthъle.

메모: dBMEE FETNYO gdb POBUBEF PFMBDUYL gdb , BRHEEOOSCHK H ``TETSYNE PFMBDLY SDTB "". RETEIPD H FFPF TETSIN DPUFYZBEFUS BRHULPN gdb U RBTBNEFTPN -k . h TETSYNE PFMBDLY SDTB gdb YЪNEOSEF UCHPЈ RTYZMBYOEOYE 정보(kgdb) .

팁: Eumi Chechi yurpmshhef FreeBSD Cetui 3 이미 tbooaa, Cheshchiki DPMTSOSH Cheshrpmeifsh Huyuye PFMBDPZP SDTB LPNBODPK STRIP, Hufbobchmychbfsh PFMSHYP PFMBDPUOP:

# cp 커널 kernel.debug # 스트립 -g 커널

ffpf ybz oe fbl hts y eepvipdyn, op telpneodhen. (PE FreeBSD 4th VPMEE RPDOOYI TEMYBI FFPF YBZ CHSCHRPMOSEPHUS BCHFPNBFYUEULY CH LPOGE RTPGEUUB RPUFTPEOYS SDTB make .) lPZDB SDTP HUEYUEOP, BCHFPNBFYUEULY YMY RTY RPNPEY LPNBOD CHSHCHYE, CHSH NPTSEFE HUFBOPCHYFSH EZP PVSCHU OSCHN PVTBPN, OBVTCH make install .

ъBNEFSHFE, UFP CH UVBTSCHI CHETUYSI FreeBSD(DP 3.1, OE CHLMAYUBS FFPF TEMY), YURPMSH'HEFUS SDTB CH ZHPTNBFE a.out, RPFPPNH YI FBVMYGSCH UINCHPMCH DPMTSOSH TBURPMBZBFSHUS RPU FPSOOP CH RBNSFI. VPMSHYPK FBVMYGEK UYNCHPMCH CHOE HUEYUEOOOPN PFMBDPYUOPN SDTE LFP YЪMYYOSS FTBFB에서. rPUMEDOYE TEMYJSHCH FreeBSD YURPMSHJHAF SDTB CH JPTNBFE ELF, HERE EFP OE SCHMSEFUS RTPVMENPK.

eUMMY ChSCH FEUFYTHHEFE OPCHPE SDTP, ULBTSEN, OBVITBS YNS OPCHPZP SDTB CH RTYZMBBYEOYY ЪBZTHYuYULB, OP CHBN OHTSOP ЪBZTHTSBFSH Y TBVPFBFSH U DTKhZYN SDTPN, YuFPVSHCH UOP ChB CHETOHFSHUS L OPTNBMShOPNKH JHOLG YPOITCHBOYA, ЪBZTHTSBKFE EZP FPMSHLP CH PDOPRPMSHЪPCHBFEMSHULPN TETSYNE RTY RPNPEY ZHMBZB -s, HLBSHCHCHBENPZP RTY ЪBZTHЪLE, B UBFEN CHSHCHRPMOYFE FBLIE YBZY:

# fsck -p # mount -a -t ufs # /var/crash에 대한 파일 시스템이 쓰기 가능하도록 # savecore -N /kernel.panicked /var/crash # exit # ...to multi-user

uFB RPUMEDPCHBFEMSHOPUFSH HLBSCHCHBEF RTPZTBNNE 세이브코어(8) YURPMSH'PCHBOYE DTHZPZP SDTB DMS 소개 Y'CHMEYUEOYS UINCHPMYUEUULYI YNEO. yOBYUE POB VHDEF YURPMSHЪPCHBFSH SDTP, TBVPFBAEEEE CH DBOOSCHK NPNEOF Y, ULPTEEE CHUEZP, OYUEZP OE UDEMBEF, RPFPNKh YuFP BCHBTYKOSHCHK PVTB RBNSFY Y Uinchpmshch SDTB VHDHF PF MYUBFSHUS.

b FERETSH, RPUME UVTPUB BCHBTYKOPZP DBNRB, RETEKDYFE H LBFBMPZ /sys/compile/WHATEVER Y BRHUFYFE LPNBODH gdb -k . y RTPZTBNNSC gdb UDEMBKFE CHPF UFP:

기호 파일 kernel.debug exec 파일 /var/crash/kernel.0 코어 파일 /var/crash/vmcore.0 AVPK DTHZPK RTPZTBNNPK.

ChPF TsHTOBM LPNBOD UEBOUB TBVPFShch gdb, YMMAUFTYTHAEYK LFH RTPGEDHTX. dMYOOSH UFTPLY VSCHMY TBPTCHBOSH DMS HMHYUYOYS YUYFBVEMSHOPUFY Y DMS HDPVUFCHB UFTPLY VSCHMY RTPOHNETPCHBOSHCH. CHUE PUFBMSHOP SCHMSEFUS FTBUUYTPCHLPK PYYVLY, TEBMSHOP CHPOYLOKHCHYEK CHP CHTENS TBVPFSCH OBD DTBCCHETPN LPOUPMY pcvt.

1:1994년 12월 30일 금요일 23:15:22에 스크립트 시작 2: # cd /sys/compile/URIAH 3: # gdb -k kernel /var/crash/vmcore.1 4: /usr/src/에서 기호 데이터 읽기 sys/compile/URIAH/kernel ...완료. 5:IdlePTD 1f3000 6:공황: 당신이 말했기 때문에! 7: 1e3f70의 현재 pcb 8: ../../i386/i386/machdep.c...done에 대한 기호 읽기. 9: (kgdb) where 10:#0 boot (arghowto=256) (../../i386/i386/machdep.c line 767) 11:#1 0xf0115159 in panic () 12:#2 0xf01955bd in diediedie ( ) (../../i386/i386/machdep.c 라인 698) 13:#3 0xf010185e in db_fncall () 14:#4 0xf0101586 in db_command (-266509132, -266509516, -267381073) 15: #5 0xf0101711에서 db_command_loop () 16:#6 0xf01040a0 in db_trap () 17:#7 0xf0192976 in kdb_trap (12, 0, -272630436, -266743723) 18:#8 0xf019d2eb in trap_fatal (...) 19:# 9 0xf01 trap_pfault의 9ce60( ...) 20:#10 0xf019cb2f in trap (...) 21:#11 0xf01932a1 in exception:calltrap () 22:#12 0xf0191503 in cnopen (...) 23:#13 0xf0132c34 in spec_open () 24: #14 0xf012d014 in vn_open () 25:#15 0xf012a183 in open () 26:#16 0xf019d4eb in syscall (...) 27: (kgdb) up 10 28: ../../i386/i386에 대한 기호 읽기 /trap.c...완료. 29:#10 0xf019cb2f 인 트랩(프레임=(tf_es = -260440048, tf_ds = 16, tf_\ 30:edi = 3072, tf_esi = -266445372, tf_ebp = -272630356, tf_isp = -27\ 31: 2 630396, tf_ebx = - 266427884, tf_edx = 12, tf_ecx = -266427884, tf\ 32:_eax = 64772224, tf_trapno = 12, tf_err = -272695296, tf_eip = -26\ 33:6672343, tf_cs = -2 66469368, tf_eflags=66066, tf_esp=3072, tf_\ 34:ss = -266427884)) (../../i386/i386/trap.c 라인 283) 35:283 (보이드) trap_pfault(&frame, FALSE); 36: (kgdb) 프레임 프레임->tf_ebp 프레임->tf_eip 37:../../i386/isa/pcvt/pcvt_drv.c에 대한 기호 읽기...완료. 38:#0 0xf01ae729 in pcopen (dev=3072, flag=3, mode=8192, p=(struct p\ 39:roc *) 0xf07c0c00) (../../i386/isa/pcvt/pcvt_drv.c 라인 403) 40:403 반환((*linesw.l_open)(dev, tp)); 41: (kgdb) 목록 42:398 43:399 tp->t_state |= TS_CARR_ON; 44:400 tp->t_cflag |= 폐쇄; /* 모뎀이 될 수 없음(:-) */ 45:401 46:402 #if PCVT_NETBSD || (PCVT_FREEBSD >= 200) 47:403 반환((*linesw.l_open)(dev, tp)); 48:404 #else 49:405 return ((*linesw.l_open)(dev, tp, flag)); 50:406 #endif /* PCVT_NETBSD || (PCVT_FREEBSD >= 200) */ 51:407 ) 52: (kgdb) print tp 53: ../../i386/i386/cons.c...done에 대한 기호 읽기. 54:$1 = (struct tty *) 0x1bae 55: (kgdb) print tp->t_line 56:$2 = 1767990816 57: (kgdb) up 58:#1 0xf0191503 in cnopen (dev=0x00000000, flag=3, mode=8192 , p=(st\ 59:ruct proc *) 0xf07c0c00) (../../i386/i386/cons.c 라인 126) 60: return ((*cdevsw.d_open)(dev, flag, mode, p) ); 61: (kgdb) 위로 62:#2 0xf0132c34 in spec_open() 63: (kgdb) 위로 64:#3 0xf012d014 in vn_open() 65: (kgdb) 위로 66:#4 0xf012a183 in open() 67: (kgdb) 최대 68:#5 syscall의 0xf019d4eb(프레임=(tf_es=39, tf_ds=39, tf_edi=\69:2158592, tf_esi=0, tf_ebp=-272638436, tf_isp=-272629788, tf\ 70:_ ebx = 7 086, tf_edx = 1, tf_ecx = 0, tf_eax = 5, tf_trapno = 582, \71:tf_err = 582, tf_eip = 75749, tf_cs = 31, tf_eflags = 582, tf_esp \ 72 := -272638456, tf_s s = 39)) (. ./../i386/i386/trap.c 라인 673) 73:673 오류 = (*callp->sy_call)(p, args, rval); 74: (kgdb) up 75: 초기 프레임 선택; 올라갈 수 없습니다. 76: (kgdb) quit 77: # exit 78:exit 79:80:1994년 12월 30일 금요일 23:18:04 스크립트 완료

lPNNEOFBTYY L CHSHCHYERTYCHEDEOOOPNKH TsHTOBMH:

UFTPLB 6:

yFP DBNR, CHJSFC RTY RPNPEY DDB (UNPFTY OYCE), RPFPNH LPNNEOFBTYK L BCHBTYKOPNH PUFBOPCH YNEEF YNEOOP CHYD ``당신이 말했기 때문에! PDOBLP YOBYUBMSHOPK RTYUYOPK RETEIPDB CH DDB VSCHMB BCHBTYKOBS PUFBOPCHLB RTY CHPOYOLOPCHEOYA PYYVLY UFTBOIGSC RBNSFY.

UFTPLB 20:

ffp NEUFPOBIPTSDEOYE JHOLGYY trap() H FTBUUYTPCHLE UFEBL.

UFTPLB 36:

rTYOHDYFEMSHOP YURPMSH'PCHBOYE OPCHPK ZTBOYGSCH UFEBL; FERESH FF OE OHTSOP. rTEDRPMBZBEFUUS, UFP ZTBOYGSC UFELB HLBSCCHCHBAF RTBCHIMSHOPE TBURPMPTSEOYE 정보, DBTSE CH UMHYUBE BCHBTYKOPZP PUFBOPCHB. UFTPLH YUIPDOPZP LPDB 403, NPTsOP ULBBFSH, UFP CHEUSHNB CHETPSFOP, UFP MYVP CHYOPCHBF DPUFHR RP HLBBFEMA``tp "", MYVP VSCHM CHSHHIPD IB ZTBOYGSCH NBUUYCHB에 대한 ZMSDS.

UFTPLB 52:

RPIPTSE, UFP CHYOPCHBF HLBBFEMSH, SCHMSEFUS DPRHUFYNSCHN BDTEUPN의 OP.

UFTPLB 56:

pDOBLP, PYUECHIDOP, NHUPT에 대한 HLBSCHCHBEF의 UFP, FBL UFP NSC OBYMY 일반 PYYVLH! (DMS FEI, LFP OE OBBLPN U YFPK YUBUFSHHA LPDB: tp->t_line UMHTSYF DMS ITBOOEOYS TETSYNB LBOBMB LPOUPMSHOPZP HUFTPKUFCHB, Y LFP DPMTSOP VShFSH DPUFBFPYuOP NBMEOSHLPE GEMPE YUYUMP.)

  • 저자:

    Barinov S.S., Shevchenko O.G.

  • 년도:
  • 원천:

    정보학 및 컴퓨터 기술 / 학생, 대학원생 및 젊은 과학자의 VI 국제 과학 및 기술 회의 자료 - 2010년 11월 23-25일, Donetsk, DonNTU. - 2010. - 448p.

주석

Microsoft Windows 운영 체제와 관련하여 디버깅 사용자 모드와 커널 모드를 비교 분석하고 후자의 디버깅 구성의 차이점과 문제점을 강조합니다. 얻은 결과를 바탕으로 비상 및 대화형 디버깅의 경우 커널 모드 디버거 구성에 대한 주요 요구 사항을 공식화합니다. 요구 사항을 준수하기 위해 기존 솔루션을 분석했습니다. 특히 Microsoft Windows 디버거에 특별한 주의를 기울입니다.

주요 부분

디버깅은 소프트웨어 버그의 원인을 식별하고 제거하는 프로세스입니다. 일부 프로젝트에서는 디버깅이 전체 개발 시간의 최대 50%를 차지합니다. 지속적으로 개선되는 특수 도구를 사용하면 디버깅을 크게 단순화할 수 있습니다. 이러한 주요 도구는 소프트웨어 실행을 제어하고 진행 상황을 모니터링하며 간섭할 수 있는 디버거입니다. 커널 디버깅 도구는 주로 드라이버 개발자가 사용합니다.

애플리케이션 소프트웨어 개발 툴킷은 프로그래머에게 다양한 가능성을 제공합니다. 모든 통합 개발 환경에는 타사 유틸리티 없이 디버깅할 수 있는 기능도 포함되어 있습니다. 특히 시스템 소프트웨어 및 드라이버 개발에 대해 이야기하는 경우 해당 특수성으로 인해 개발 프로세스가 매우 어렵고 자동화가 거의 이루어지지 않습니다. 디버깅을 포함한 모든 개발 단계는 별개입니다. 그들 각각은 특별한 조건이 필요합니다. 본격적인 컴퓨터 시스템에서 프로그램 코드 작성, 디버깅-디버깅 시스템에서, 테스트-상황에 따라 수행됩니다. 커널 모드 디버거 자체는 배우기가 더 어려우므로 친숙하지 않습니다.

일반적으로 커널 디버깅 도구의 부족에 대해 이야기할 수 있습니다. 이러한 도구를 사용할 수 있지만 대안은 종종 논의되지 않습니다. 예를 들어 Microsoft Windows 디버거의 진입 임계값이 너무 높습니다. 많은 프로그래머가 그것에 익숙해지면 첫 번째 부정적인 경험에 대해 이야기하며 대부분의 기능은 주장되지 않습니다.

가상 주소 공간의 구조에 따라 응용 프로그램이 실수로 응용 프로그램이 임의의 메모리 위치에 데이터를 쓰는 경우 응용 프로그램은 자신의 메모리만 손상시키고 다른 응용 프로그램의 작동 및 운영 체제에는 영향을 미치지 않습니다. 체계. 커널 모드 코드는 운영 체제의 중요한 데이터 구조를 손상시킬 수 있으므로 불가피하게 일반 오류로 이어질 수 있습니다. 비효율적으로 작성된 드라이버는 전체 운영 체제를 심각하게 저하시킬 수도 있습니다.

    최신 디버거는 다음과 같은 기본 기능을 제공합니다.
  • 소스 코드 수준에서 디버깅;
  • 실행관리;
  • 메모리 보기 및 변경;
  • 프로세서 레지스터의 내용 보기 및 변경
  • 호출 스택 보기.

디스어셈블된 코드 작업을 용이하게 하기 위해 소위. 디버그 기호. 링커가 작동하는 동안 실행 파일의 이미지 외에도 프로그램을 실행할 때 필요하지 않지만 디버그할 때 매우 유용한 정보(함수 이름, 전역 변수)가 포함된 데이터 파일을 만들 수도 있습니다. , 그리고 구조에 대한 설명. 디버깅 기호는 Windows 운영 체제의 모든 실행 파일에 사용할 수 있습니다.

실행 제어는 프로그램 코드의 주어진 명령에 도달하면 프로그램 코드의 실행을 중단하고 다시 시작하는 기능을 말합니다. 프로그램 코드가 단계별 모드에서 실행되는 경우 프로그래밍 언어의 각 토큰에 대해 또는 서브루틴을 종료할 때 인터럽트가 발생합니다. 자유 실행을 사용하면 코드의 미리 결정된 섹션(중단점이 설정된 위치)에서 실행 중단이 발생합니다.

커널 모드 코드를 중단하면 다음과 같은 딜레마가 발생합니다. 디버거는 사용자 인터페이스를 사용하여 프로그래머와 상호 작용합니다. 저것들. 적어도 디버거의 가시적인 부분은 사용자 모드에서 실행되며 자연적으로 애플리케이션 프로그래밍 인터페이스(Windows API)를 사용하여 빌드합니다. 그러면 커널 모드 모듈에 의존합니다. 따라서 커널 모드 코드를 중단하면 교착 상태가 발생할 수 있습니다. 즉, 시스템이 사용자에게 응답하지 않게 됩니다.

커널 메모리에 액세스하려면 디버거의 일부도 커널 모드에서 실행해야 합니다. 이로 인해 한 번에 두 가지 문제가 발생하는데, 이는 프로세서의 보호 모드에서 메모리 구성의 명백한 결과입니다.

첫 번째 문제는 가상 메모리 주소 변환에 관한 것입니다. 드라이버는 메모리에 액세스하여 사용자 모드 응용 프로그램과 지속적으로 상호 작용합니다. Windows 운영 체제는 스레드 컨텍스트 개념을 기반으로 가상 주소를 물리적 주소로 변환합니다. 스레드 컨텍스트 - 스레드의 상태를 반영하고 특히 레지스터 세트 및 기타 정보를 포함하는 구조입니다. 제어가 다른 스레드로 전송되면 한 스레드에 대한 정보를 저장하고 다른 스레드에 대한 정보를 복원하는 컨텍스트 전환이 발생합니다. 스레드의 컨텍스트를 다른 프로세스의 스레드로 전환하면 가상 주소를 물리적 주소로 변환하는 데 사용되는 페이지 디렉터리도 전환됩니다.

특이한 점은 시스템 호출을 디스패치할 때 Windows 운영 체제가 컨텍스트를 전환하지 않는다는 것입니다. 이를 통해 커널 모드 코드는 사용자 모드 가상 주소를 사용할 수 있습니다.

시스템 스레드를 인터럽트 디스패치하거나 실행할 때는 상황이 다릅니다. 인터럽트는 언제든지 발생할 수 있으므로 어떤 스레드 컨텍스트가 사용될지 예측할 방법이 없습니다. 반면에 시스템 스레드는 어떤 프로세스에도 속하지 않으며 사용자 모드 가상 주소를 변환할 수 없습니다. 따라서 이러한 상황에서는 사용자 모드 메모리에 액세스할 수 없습니다.

두 번째 문제는 재배치 가능한 메모리 액세스입니다. 메모리에 있는 대부분의 정보는 재배치 가능하며 페이지 파일에서 언제든지 실제 메모리에서 하드 디스크로 이동할 수 있습니다. 물리적 메모리에 없는 페이지에 액세스하면 프로세서는 일반적으로 메모리 관리자가 처리하는 Page Fault 인터럽트를 생성하고 그 결과 페이지 파일에서 페이지를 읽어 물리적 메모리에 로드합니다.

이 동작은 디버거 코드가 높은 IRQL(인터럽트 요청 수준)을 사용하도록 강제된 경우 중단됩니다. IRQL이 메모리 관리자의 IRQL보다 크거나 같으면 후자는 누락된 페이지를 로드할 수 없습니다. 운영 체제는 Page Fault 인터럽트를 차단합니다. 운영 체제가 충돌합니다.

디버깅은 일반적으로 대화식과 비상으로 나뉩니다. 대화형 로컬 디버깅을 사용하면 디버거가 디버그 개체와 동일한 시스템에서 실행됩니다. 대화형 원격 디버깅에서 디버거와 디버그 개체는 서로 다른 시스템에서 실행됩니다. 커널 코드를 디버깅할 때 네트워크가 아직 작동하지 않는 부팅 첫 단계부터 시스템을 제어해야 하므로 COM, FireWire, USB와 같은 간단한 직렬 인터페이스를 사용하여 시스템을 연결합니다. 최근 다양한 추상화 수준에서 소프트웨어 가상화의 개발 추세 덕분에 가상 머신이 점점 더 매력적입니다. 게스트 OS는 디버깅된 OS로 작동하고 호스트 OS에는 디버거 사용자 인터페이스가 포함되어 있습니다.

따라서 긴급 디버깅은 테스트 컴퓨터에 디버깅 도구를 설치할 필요가 없습니다. Windows 운영 체제 배포에는 긴급 디버깅을 구현하는 메커니즘이 포함되어 있습니다. 재부팅하기 전에 운영 체제는 개발자가 원인을 분석하고 찾을 수 있는 상태에 대한 정보를 저장할 수 있습니다. 파일에 저장되는 이 정보를 메모리 덤프라고 합니다.

기본 커널 모드 디버깅 도구는 Windows 운영 체제 제조업체에서 자유롭게 배포되는 Windows용 디버깅 도구 패키지의 일부로 제공됩니다. 도구에는 각각 그래픽 및 콘솔 디버거인 WinDbg 및 KD(이하 Windows 디버거라고 함)가 포함됩니다. 이러한 디버거의 작업은 운영 체제 개발자가 제공하고 커널에 내장된 메커니즘을 기반으로 합니다.

Windows 디버거의 기본 모드는 명령 인터프리터 모드입니다. 개발자 제공 명령과 함께 모듈식 구조로 인해 Windows 디버거는 확장이라는 타사 모듈을 지원합니다. 실제로 대부분의 기본 제공 명령도 확장 형식으로 지정되어 있습니다.

Windows 디버거는 원격 대화형 및 긴급 디버깅에 중점을 두고 있으며 이를 사용하여 모든 기능을 공개합니다. 동시에 본격적인 로컬 대화형 디버깅은 지원되지 않습니다. 디버거에서는 일부 커널 구조만 볼 수 있습니다.

어떤 의미에서 로컬 대화형 디버깅을 구현하는 Mark Russinovich가 만든 LiveKD라는 Windows 디버거용 확장이 있습니다. LiveKD는 이동 중에 작업 시스템의 메모리 덤프를 생성하고 이를 디버깅에 사용합니다.

Windows용 디버깅 도구는 정기적으로 업데이트되며 모든 최신 Windows 운영 체제를 지원합니다.

Compuware가 DriverStudio 소프트웨어 패키지로 출시한 SoftICE 커널 디버거는 전통적으로 Windows용 디버깅 도구 패키지의 대안으로 사용되었습니다. SoftICE의 특징은 지원되는 하드웨어에서 로컬 대화형 디버깅을 구현한 것입니다. 디버거는 운영 체제의 작동을 거의 완벽하게 제어할 수 있습니다.

2006년 4월 3일부로 DriverStudio 제품군은 "일반적인 시장 조건뿐 아니라 많은 기술 및 비즈니스 문제"로 인해 단종되었습니다. 지원되는 운영 체제의 최신 버전은 Windows XP 서비스 팩 2입니다. 일반적으로 서비스 팩은 운영 체제 API를 변경하지 않지만 시스템 호출 번호 및 기타 문서화되지 않은 정보는 변경될 수 있습니다. SoftICE 디버거는 내부 데이터 구조의 하드코딩된 주소에 의존했습니다. 그 결과 서비스 팩 3이 출시되면서 호환성이 깨졌습니다. 분명히 이후 버전의 Windows 운영 체제도 지원되지 않습니다.

Syser 커널 디버거는 SoftICE 디버거를 대체하기 위해 작은 중국 회사인 Sysersoft에서 만들었습니다. 첫 번째 최종 버전은 2007년에 출시되었습니다. SoftICE와 마찬가지로 Syser 커널 디버거는 실행 중인 시스템에서 대화형 디버깅이 가능합니다. Windows 최신 버전의 32비트 에디션만 지원됩니다.

Windows 디버거는 현재 커널 모듈 개발자 사이에서 주요 도구입니다. Windows 운영 체제 커널 개발 팀에서도 사용합니다.

때때로 Windows가 커널 디버거의 부팅 시간을 기다리는 상황이 있습니다. "Windows 시작"이라는 텍스트가 표시되지만 로고는 표시되지 않습니다.

지금 디버거를 연결하면 Windows 7 로고 애니메이션이 재생되고 그 후 로고가 진동하기 시작합니다. 이 시점에서 다운로드 프로세스는 더 이상 진행되지 않습니다. CPU 사용량이 최소한으로 줄어듭니다. 나는 보통 몇 분을 기다리지만 아무 일도 일어나지 않습니다.

항상 그런 것은 아닙니다. 그러나 이런 일이 발생하면 VM을 재설정해도 도움이 되지 않습니다. 이 문제를 해결하려면 시동 복구를 사용해야 합니다. 불행히도 이것은 영원히 걸립니다.

시작할 때 수리를 실행하는 것 외에 내가 할 수 있는 일이 있습니까?

미리 감사드립니다!

3

2 응답

발생한 문제를 해결하려면 부팅 중에 F10을 누르기만 하면 됩니다. 그리고 제거/디버그 및 관련 옵션. 그런 다음 Enter 키를 누릅니다.

제안: 기본 부팅 메뉴 옵션에 /debug 옵션을 사용하지 마십시오. 부팅 구성을 새 항목에 복사합니다. 그런 다음 디버그 모드로 설정하십시오. Windows는 디버거를 언제 사용할지 모릅니다. 그러므로 그는 기다려야 한다.