관리 메뉴

kisoo

BugCheck(50) PAGE_FAULT_IN_NONPAGED_AREA (50) 덤프(Dump)분석 본문

01.About Programming /2.Kernel Lab

BugCheck(50) PAGE_FAULT_IN_NONPAGED_AREA (50) 덤프(Dump)분석

JamesK78 2009. 2. 4. 10:46

PAGE_FAULT_IN_NONPAGED_AREA (50)

 

 미니필터 드라이버를 가지고 장난좀 치다가 위 오류가 발생했습니다. 덤프를 WinDBG로 열어보면 아래와 같이 메세지가 나옵니다.

 

 올바르지 않은 시스템 메모리를 참조했다. 이 오류는 try-except로 막을수 없다. 철저하게 코드를 조사해서 오류가 나지 않도록 해야 한다. 일반적으로 잘못된 메모리 주소를 접근하거나 이미 지운 메모리를 접근할때 발생하는 오류이다.

Invalid system memory was referenced.  This cannot be protected by try-except, it must be protected by a Probe.  Typically the address is just plain bad or it is pointing at freed memory.

 

 좀더 자세하게 설명하면 페이지되지 않은 영역에서 페이지 폴트(Page Fault)가 일어났다는 것을 말하는데, 지정된 주소 공간을 접근할 때 유효하지 않은 주소공간을 참조하거나 실제로 주소가 메모리안에 존재하는 않는 경우에 발생한다. 앞에서 반복했지만 NT커널에서는 이러한 동작을 할 경우에는 스톱 오류를 발생시키고 시스템을 보호하기 위해서 셧다운시킨다. 이러한 오류는 시스템의 결함있는 주메모리가 오동작을 함으로써 발생할 수 있으며, 메인보드와 궁합 즉 특성을 탄다고 하는 경우도 포함될 수 있다. 주메모리 뿐만이 아닌 L2 캐쉬메모리와 비디오카드 메모리도 포함이 되며, 호환되지 않는 어플리케이션, 원격 제어프로그램 및 바이러스와 같은 악성소프트웨어에 의해서도 발생할 수 있다.

 간혹 사용자 입장에서는 매우 곤혹스런 경우일 수 있는데, 매우 드문 경우이지만 메모리의 아주 미세한 결함으로 인해서 평상시는 잘 동작하는 듯 하다가 순간적인 오동작으로 블루 스크린이 발생되는 경우이다 -> 재현이 잘되지 않는 버그가 제일 어렵죠 ^^;;;

 

Arguments:
Arg1: b606c000, memory referenced. -> 잘못 참조한 메모리 주소
Arg2: 00000000, value 0 = read operation, 1 = write operation.
Arg3: 81c4be4a, If non-zero, the instruction address which referenced the bad memory
 address.
Arg4: 00000000, (reserved)

 

[덤프 분석하자]

WinDbg 에서  잘못 참조한 메모리를 확인해 보자

 

1) !address 명령으로 주소 정보를 확인해보자 그러나 잘못된 주소인지 값이 정확하지 않다.

1: kd> !address b606c000
unable to resolve nt!MiSessionViewStart

 

2) !pool 명령으로 pool 정보를 확인한다. Paged 된 풀 이지만 해제 되었거나 오염(corrupt)된 풀이다.
1: kd> !pool b606c000
Pool page b606c000 region is Paged pool
b606c000 is not a valid large pool allocation, checking large session pool...
b606c000 is freed (or corrupt) pool
Bad allocation size @b606c000, too large

***
*** An error (or corruption) in the pool was detected;
*** Attempting to diagnose the problem.
***
*** Use !poolval b606c000 for more details.
***

Pool page [ b606c000 ] is __inVALID.

Analyzing linked list...


Scanning for single bit errors...

None found

 

3) 콜스택을 통해서 어떠한 함수에서 오류가 발생 했는지 확인해 보자

1: kd> kbn
 # ChildEBP RetAddr  Args to Child             
00 bd1e93d0 81c96b54 00000000 b606c000 00000000 nt!MmAccessFault+0x10a
01 bd1e93d0 81c4be4a 00000000 b606c000 00000000 nt!KiTrap0E+0xdc
02 bd1e96b8 81c4a4f8 bd1e96dc 943f04ae 00000000 nt!_output_l+0x4f5
03 bd1e96fc 81c4a365 bd1e9778 000001ff 943f0450 nt!_vsnprintf_l+0x72
04 bd1e9718 81d18770 bd1e9778 000001ff 943f0450 nt!_vsnprintf+0x18
05 bd1e9738 81cf9eae 943f0450 bd1e99c0 96247da2 nt!RtlStringCbVPrintfA+0x30
06 bd1e9994 81cfa112 81c97640 00000065 00000003 nt!vDbgPrintExWithPrefixInternal+0x89
07 bd1e99b4 943f007a 943f0450 87aec778 b606bfee nt!DbgPrint+0x1c
08 bd1e99d0 87ae3809 84c5c658 bd1e99f0 bd1e9a10 passThrough!PtPreOperationPassThrough+0x6a [e:\workspace\filesys_from_wdk\minifilter\passthrough\passthrough\passthrough.c @ 676]
09 bd1e9a2c 87ae5ff8 bd1e9a6c 00000000 852d0c04 fltmgr!FltpPerformPreCallbacks+0x2e5
0a bd1e9a40 87af8fc0 bd1e9a6c 87af788c 00000000 fltmgr!FltpPassThroughInternal+0x32
0b bd1e9a54 87af9631 bd1e9a6c 852d0a50 852cc25c fltmgr!FltpCreateInternal+0x24
0c bd1e9a98 81cf7fd3 8587e020 8587eba8 8443d3d4 fltmgr!FltpCreate+0x28f
0d bd1e9ab0 81e5cd11 96247fb6 84c5edc4 85305138 nt!IofCallDriver+0x63
0e bd1e9b80 81e823ff 85305150 00000000 84c5ed20 nt!IopParseDevice+0xf61
0f bd1e9c10 81e5a0f6 00000000 bd1e9c68 00000040 nt!ObpLookupObjectName+0x5a8
10 bd1e9c70 81e5bbf3 0819eff0 00000000 00000001 nt!ObOpenObjectByName+0x13c
11 bd1e9ce4 81e62fea 0819f054 00100081 0819eff0 nt!IopCreateFile+0x63b
12 bd1e9d30 81c93a1a 0819f054 00100081 0819eff0 nt!NtCreateFile+0x34
13 bd1e9d30 77de9a94 0819f054 00100081 0819eff0 nt!KiFastCallEntry+0x12a

 

필터 매니저에서 passThrough로 콜백을 호출한 후에 콜백함수에서 DbgPrint 를 출력하다가 문제가 생긴것으로 예상된다.

 

4)문제가 발생했을것으로 예상되는 함수로 프레임을 이동한다.
1: kd> .frame 08
08 bd1e99d0 87ae3809 passThrough!PtPreOperationPassThrough+0x6a [e:\workspace\filesys_from_wdk\minifilter\passthrough\passthrough\passthrough.c @ 676]

 

5)지역 변수를 확인해 본다.
1: kd> dv
           Data = 0x84c5c658
     FltObjects = 0xbd1e99f0
CompletionContext = 0xbd1e9a10
       nameInfo = 0xb606bee4
         status = 0

 

6) DbgPrint 에서 사용하는 지역변수 nameInfo값을 확인해 본다.
1: kd> ? nameInfo
Evaluate expression: -1122068024 = bd1e99c8
1: kd> ?? nameInfo
struct _FLT_FILE_NAME_INFORMATION * 0xb606bee4
   +0x000 Size             : 0x40
   +0x002 NamesParsed      : 0xf
   +0x004 Format           : 1
   +0x008 Name             : _UNICODE_STRING "\Device\HarddiskVolume1\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\System Tools\BitLocker"
   +0x010 Volume           : _UNICODE_STRING "\Device\HarddiskVolume1"
   +0x018 Share            : _UNICODE_STRING ""
   +0x020 Extension        : _UNICODE_STRING ""
   +0x028 Stream           : _UNICODE_STRING ""
   +0x030 FinalComponent   : _UNICODE_STRING "BitLocker"
   +0x038 ParentDir        : _UNICODE_STRING "\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\System Tools\"

 

7) nameInfo 값중에서 DbgPrint에서 출력하는 FinalComponent 값을 확인해 본다.
1: kd> ? 0xb606bee4+0x30
Evaluate expression: -1241071852 = b606bf14
1: kd> dd b606bf14
b606bf14  00120012 b606bfee 00980098 b606bf56
b606bf24  00000002 0044005c 00760065 00630069
b606bf34  005c0065 00610048 00640072 00690064
b606bf44  006b0073 006f0056 0075006c 0065006d
b606bf54  005c0031 00720050 0067006f 00610072
b606bf64  0044006d 00740061 005c0061 0069004d
b606bf74  00720063 0073006f 0066006f 005c0074
b606bf84  00690057 0064006e 0077006f 005c0073

 

8)FinalComponent  값은 _UNICODE_STRING 구조체로 되어있다. 실제 버퍼값은 아래 빨간색 값이다.
1: kd> dc b606bf14
b606bf14  00120012 b606bfee 00980098 b606bf56  ............V...
b606bf24  00000002 0044005c 00760065 00630069  ....\.D.e.v.i.c.
b606bf34  005c0065 00610048 00640072 00690064  e.\.H.a.r.d.d.i.
b606bf44  006b0073 006f0056 0075006c 0065006d  s.k.V.o.l.u.m.e.
b606bf54  005c0031 00720050 0067006f 00610072  1.\.P.r.o.g.r.a.
b606bf64  0044006d 00740061 005c0061 0069004d  m.D.a.t.a.\.M.i.
b606bf74  00720063 0073006f 0066006f 005c0074  c.r.o.s.o.f.t.\.
b606bf84  00690057 0064006e 0077006f 005c0073  W.i.n.d.o.w.s.\.

 

9) 실제 메모리에서 b606bfee 값을 확인해 본다.
1: kd> dc b606bfee
b606bfee  00690042 004c0074 0063006f 0065006b  B.i.t.L.o.c.k.e.
b606bffe  ???????? ???????? ???????? ????????  ????????????????
b606c00e  ???????? ???????? ???????? ????????  ????????????????
b606c01e  ???????? ???????? ???????? ????????  ????????????????
b606c02e  ???????? ???????? ???????? ????????  ????????????????
b606c03e  ???????? ???????? ???????? ????????  ????????????????
b606c04e  ???????? ???????? ???????? ????????  ????????????????
b606c05e  ???????? ???????? ???????? ????????  ????????????????

 

10) 원인을 파악했다. FinalComponent 버퍼 값이 스트링이다. 그러나 NULL로 끝나지 않기 때문에 스트링 출력하는 곳에서 사이즈 이상 값을 출력하다 페이지 되지않은 영역에서 페이지 폴트가 발생해서 강제 종료되었다.
1: kd> ? b606bfee+0x12
Evaluate expression: -1241071616 = b606c000
1: kd> dc b606c000-0x12
b606bfee  00690042 004c0074 0063006f 0065006b  B.i.t.L.o.c.k.e.
b606bffe  ???????? ???????? ???????? ????????  ????????????????
b606c00e  ???????? ???????? ???????? ????????  ????????????????
b606c01e  ???????? ???????? ???????? ????????  ????????????????
b606c02e  ???????? ???????? ???????? ????????  ????????????????
b606c03e  ???????? ???????? ???????? ????????  ????????????????
b606c04e  ???????? ???????? ???????? ????????  ????????????????
b606c05e  ???????? ???????? ???????? ????????  ????????????????
1: kd> dc b606c000-0x10
b606bff0  00740069 006f004c 006b0063 00720065  i.t.L.o.c.k.e.r.
b606c000  ???????? ???????? ???????? ????????  ????????????????
b606c010  ???????? ???????? ???????? ????????  ????????????????
b606c020  ???????? ???????? ???????? ????????  ????????????????
b606c030  ???????? ???????? ???????? ????????  ????????????????
b606c040  ???????? ???????? ???????? ????????  ????????????????
b606c050  ???????? ???????? ???????? ????????  ????????????????
b606c060  ???????? ???????? ???????? ????????  ????????????????

 

[문제를 발생한 소스코드]

DbgPrint( ("PassThrough!PtPreOperationPassThrough: FltGetFileNameInformation Success IRP|FileName = %s|%ws \n"), FltGetIrpName(Data->Iopb->MajorFunction), nameInfo->FinalComponent.Buffer );

Comments