Udostępnij za pośrednictwem


Crash Dump Analysis Patterns (Part 6)

잘못된 포인터를 드라이버에 사용한다면, 당연히 bug check가 뜨게 되겠지요? 이번 6번째 글에서는, 그 잘못된 주소가 가르키는 영역이 유저 공간이냐, 커널 공간이냐에 따라 다른 bug check가 뜬다는 사실에 대해서 언급하고 있습니다. 도움이 되길 바랍니다.


Crash Dump Analysis Patterns (Part 6)

번역: 김희준(drost@naver.com, https://insidekernel.net, 2007-06-28)

원문주소:

https://www.dumpanalysis.org/blog/index.php/2006/12/18/crash-dump-analysis-patterns-part-6/

자, 이제 드디어 잘못된 포인터(Invalid Pointer) 패턴을 소개할 차례가 되었습니다. 이 패턴은 레지스터나 메모리에 저장된 숫자를 메모리 주소로 해석하고 그것이 가르치는 메모리 안의 값을 가져오기 위하여 액세스 하는 순간에, OS는 하드웨어의 도움을 받아서 그 주소는 존재하지 않거나 보안에 따른 제한 때문에 액세스 할 수 없다고 알려줍니다. 포인터에 대한 더 자세한 설명은 아래의 제 예전 강좌들을 참고하시기 바랍니다:

Pointer definition
Pointers depicted

윈도우에서는 메모리가 크게 커널 공간과 프로세스 공간으로 구분됩니다. 공간 구분은 프로세서 상태(processor state)를 나타내는 실행 모드(execution mode, ring0나 ring3라고 하는 것들)와는 다른 개념입니다. 커널 모드(드라이버나 OS)에서 실행되는 코드는 유저 공간에 속한 메모리를 액세스할 수 있습니다.

이 내용을 기초로 우리는 커널 공간 주소(/3Gb 스위치가 없는 x86 시스템에서 0x80000000부터 시작)를 가르치는 잘못된 포인터와 유저 공간 주소(0x7FFFFFFF 아래)를 갖고 있는 잘못된 포인터를 구분할 수 있을 것입니다.

x64 윈도우에서는 유저 공간의 주소는 0×0000070000000000 아래이고, 커널 주소 공간은 0xFFFF080000000000부터 시작합니다.

유효하지 않은 커널 공간 주소를 액세스하였을 경우에는 다음과 같은 bug check가 바로 뜰 것입니다:

UNEXPECTED_KERNEL_MODE_TRAP (7f)

PAGE_FAULT_IN_NONPAGED_AREA (50)

여러분의 코드에서 SEH를 사용하더라도 이 예외를 잡아낼(catch) 방법은 존재하지 않습니다.

그러나 유효하지 않은 유저 공간 주소를 액세스하였다면 여러분의 프로세서 상태가 커널 모드(ring 0)냐 유저모드(ring 3)냐에 따라 그 이후의 처리순서가 달라집니다. 어떠한 모드에서든 적절한 SEH 핸들러를 설치하거나 OS나 디버거가 처리하든지 해서 예외를 잡을 수 있습니다. 만약 커널 모드로 동작하던 중에 유저 공간으로의 잘못된 포인터 액세스를 아무도 예외처리 하지 않는다면 다음과 같은 bug check를 볼 것입니다.

SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (7e)

KERNEL_MODE_EXCEPTION_NOT_HANDLED (8e)

이 내용들을 다이어그램으로 정리해보았습니다:

NULL 포인터는 유저 공간 포인터의 한 특별한 종류입니다. 보통 그 안의 값은 0x00000000 – 0x0000FFFF 사이의 값을 가집니다. 다음과 같은 명령어들을 보셨을텐데,

mov   esi, dword ptr [ecx+0×10]

ecx 값이 0x00000000이라면 메모리 주소 0x00000010 번지에 있는 값을 읽으려고 시도할 것입니다.

여러분들이 크래쉬 덤프 파일을 받게 되고, 잘못된 포인터 패턴을 그 안에서 보게 된다면, 그 다음 과정은 어떻게 시스템이 크래쉬 되었는지 몇 가지 추측을 할 수 있도록 포인터 값을 해석하는 일입니다. 포인터 값 해석은 다음 파트에서 다뤄질 것입니다.

- Dmitry Vostokov -

Comments