2017-01-07 6 views
4

Windows에서 SEH에 대해이 내용을 읽고 있습니다. article. 그리고 여기에 myseh.cppWindows에서 SEH, 호출 스택 추적이 사라졌습니다.

나는 myseh.cpp를 디버깅했습니다. 나는 줄마다 printf("Hello from an exception handler\n");에 2 개의 중단 점을 설정하고 24 행에는 DWORD handler = (DWORD)_except_handler;을 각각 36 줄에 설정했습니다.

그럼 나는 달렸고 줄에서 깨졌습니다 : 36. 스택 추적을 다음과 같이 보았습니다. 24 : 예정으로

enter image description hereAccessViolationException 때문에의 mov [eax], 1 은 그 다음 줄에 파산 발생했습니다. 스택 추적을 다음과 같이 보았습니다. enter image description here

같은 스레드하지만 main의 사라 된 프레임! _except_handle 대신. ESP가 0018f6c8에서 0018ef34으로 뛰었습니다. 예외 처리 후 0018f6c80018ef34사이의 큰 차이가 있습니다.

_except_handle은 커널 모드가 아닌 사용자 모드에서 실행되어야한다는 것을 알고 있습니다. _except_handle이 반환 된 후 스레드가 ring0으로 바뀌고 Windows 커널이 CONTEXT EAX&scratch &으로 수정 한 다음 ring3으로 반환했습니다. 따라서 스레드가 지속적으로 실행되었습니다.

나는 예외 처리 윈도우의 메커니즘에 대해 궁금 : 왜 프레임 호출 main가 사라졌다?

ESP가 0018f6c8에서 0018ef34으로 뛰어 오르는 이유는 무엇입니까? (나는 큰 피치를 의미합니다), 그 ESP 주소는 동일한 스레드의 스택에 속합니까? 커널 링 3에서 ESP에 대한 몇 가지 트릭을 했습니까? 그렇다면 왜 핸들러 콜백의 프레임으로 0018ef34의 주소를 선택 했습니까? 많은 감사합니다!

+0

예 동일한 스레드 스택입니다. 커널은'CONTEXT'와'EXCEPTION_RECORD'를 사용자 스레드 스택에 복사합니다. 물론 벗어난 Esp의 예외 Esp - 이것은 이미 Esp가 심각하게 감소했습니다. 이 복사 된'CONTEXT'와'EXCEPTION_RECORD' 레코드를 가리키는 포인터로 커널에서'KiUserExceptionDispatcher' 콜백을 호출합니다. 마침내'_except_handler'가 호출되었습니다. 'ContextRecord-> Esp'를 찾으면'main()'의'Esp'와 똑같을 것이라는 것을 알 수 있습니다. 실제 핸들러 구현을 위해서는'\ VC \ crt \ src \ i386 \ chandler4.c'와'\ VC \ crt \ src \ amd64 \ chandler.c'를 보라. – RbMm

+0

예, 예외 상황이 발생할 때 CONTEXT가 하드웨어의 스냅 샷이어야한다는 것을 알고있다. . 그래서, ContextRecord-> Esp == Esp (main)에서. 사실, 우리는 스택 트레이스를 잃는 디버거의 디폴트 설정에 책임을 져야한다. Btw, 나는 * ContextRecord의 수정 가능성을 알고있다. 그것은 커널이 ring3으로 돌아 가기 전에 원하는대로 하드웨어 컨텍스트를 복구하는 것을 의미한다. 그런데 왜'const *'가 아닌'*'타입의 두번째 파라미터'ExceptionRecord'가 무엇입니까? – TanakaYasen

+0

ExceptionRecord는 실제로 const가 아닙니다. ExceptionFlags는 예외 처리 중에 수정됩니다. 우리는 두 번 스택으로 걷는다! 먼저'__try/__ except' 블록을 찾고, 일부는'EXCEPTION_EXECUTE_HANDLER'을 리턴하지 않고'ExceptionFlags'에'EXCEPTION_UNWIND' 플래그를 설정하고'__try/__ finally' 핸들러에 대해 스택을 다시 걷는'RtlUnwindEx'를 호출합니다. 'winnt.h'와'wdm.h'에서'IS_DISPATCHING (Flag)'과'IS_UNWINDING (Flag)'매크로를 찾는다 - 또한 chandler.c를 연구하라 note (if_DISPATCHING (ExceptionRecord-> ExceptionFlags)) switch – RbMm

답변

7

기본 디버거 설정을 사용하고 있습니다. 자세한 내용을 보려면 충분하지 않습니다. 이들은 자신의 코드에 집중하고 가능한 빨리 디버그 세션을 시작하는 데 도움을주기 위해 선택되었습니다.

[외부 코드] 블록은 사용자가 작성한 코드에 속하지 않은 스택 프레임의 부분이 있음을 알려줍니다. 그들은 운영 체제에 속합니다. 도구> 옵션> 디버깅> 일반을 사용하고 "내 코드 만 사용"옵션의 선택을 해제하십시오.

[아래 프레임이 틀릴 수 있습니다 ...] 경고는 디버거가 스택을 올바르게 걷기위한 정확한 PDB를 가지고 있지 않음을 알려줍니다. 도구> 옵션> 디버깅> 심볼을 사용하고 "Microsoft 심볼 서버"옵션을 선택하고 캐시 위치를 선택하십시오. 이제 디버거는 운영 체제 DLL을 통해 디버깅해야하는 PDB를 다운로드합니다. 시간이 좀 걸릴 수도 있지만 한 번만 수행됩니다.

큰 ESP 변경을 추론 할 수 있습니다. CONTEXT 구조가 상당히 커서 스택의 공간을 차지합니다. Win10 버전 1607 VS2015 업데이트 2에 기록 된

ConsoleApplication1942.exe!_except_handler(_EXCEPTION_RECORD * ExceptionRecord, void * EstablisherFrame, _CONTEXT * ContextRecord, void * DispatcherContext) Line 22 C++ 
[email protected]() Unknown 
[email protected]() Unknown 
[email protected]() Unknown 
ConsoleApplication1942.exe!main() Line 46 C++ 
ConsoleApplication1942.exe!invoke_main() Line 64 C++ 
ConsoleApplication1942.exe!__scrt_common_main_seh() Line 255 C++ 
ConsoleApplication1942.exe!__scrt_common_main() Line 300 C++ 
ConsoleApplication1942.exe!mainCRTStartup() Line 17 C++ 
[email protected]@12() Unknown 
ntdll.dll!__RtlUserThreadStart() Unknown 
[email protected]() Unknown 

: 이러한 변경 후

당신은 지금 닮은 무언가를보고해야한다.SEH 처리기를 작성하는 올바른 방법이 아니므로 this post에 더 좋은 예를 찾으십시오.

+0

감사합니다. 네,이 예제는 단지 근본적인 개념을 설명하기위한 것이지 실용적이지는 않습니다. – TanakaYasen