BLOG main image
분류 전체보기 (17)
Life (2)
Dump Analysis (9)
Reversing (1)
Windows (1)
Book (2)
Reference (2)
Visitors up to today!
Today hit, Yesterday hit
daisy rss
tistory 티스토리 가입하기!
'BugCheck'에 해당되는 글 2건
2018. 7. 7. 23:48

이번 덤프의 BugCheck는 0x50이다. 0x50은 대부분 다른 모듈이 메모리를 손상시켰거나 정말 유효하지 않은 메모리나 해제된 메모리를 접근할 때 주로 발생한다. 원인에 따라 분석이 불가능한 경우도 많다.

다행히 이번 덤프는 어렵지 않으면서 재미도 있으니 가벼운 마음으로 시작해보자.

kd> !analyze -v

*******************************************************************************

*      *

*      Bugcheck Analysis   *

*      *

*******************************************************************************

PAGE_FAULT_IN_NONPAGED_AREA (50)

Invalid system memory was referenced.  This cannot be protected by try-except.

Typically the address is just plain bad or it is pointing at freed memory.

Arguments:

Arg1: ffff0000, memory referenced.

Arg2: 00000000, value 0 = read operation, 1 = write operation.

Arg3: 82ad19fe, If non-zero, the instruction address which referenced the bad memory

       address.

Arg4: 00000000, (reserved)

 

Debugging Details:

------------------

DUMP_CLASS: 1

DUMP_QUALIFIER: 401

BUILD_VERSION_STRING:  7601.17514.x86fre.win7sp1_rtm.101119-1850

SYSTEM_MANUFACTURER:  VMware, Inc.

VIRTUAL_MACHINE:  VMware

SYSTEM_PRODUCT_NAME:  VMware Virtual Platform

SYSTEM_VERSION:  None

BIOS_VENDOR:  Phoenix Technologies LTD

BIOS_VERSION:  6.00

BIOS_DATE:  07/31/2013

BASEBOARD_MANUFACTURER:  Intel Corporation

BASEBOARD_PRODUCT:  440BX Desktop Reference Platform

BASEBOARD_VERSION:  None

DUMP_TYPE:  1

BUGCHECK_P1: ffffffffffff0000

BUGCHECK_P2: 0

BUGCHECK_P3: ffffffff82ad19fe

BUGCHECK_P4: 0

READ_ADDRESS:  ffff0000

 

FAULTING_IP:

nt!strstr+1e

82ad19fe 8a07            mov     al,byte ptr [edi]

 

MM_INTERNAL_CODE:  0

CPU_COUNT: 1

CPU_MHZ: e07

CPU_VENDOR:  GenuineIntel

CPU_FAMILY: 6

CPU_MODEL: 3c

CPU_STEPPING: 3

CPU_MICROCODE: 6,3c,3,0 (F,M,S,R)  SIG: 19'00000000 (cache) 19'00000000 (init)

DEFAULT_BUCKET_ID:  WIN7_DRIVER_FAULT

BUGCHECK_STR:  0x50

PROCESS_NAME:  MyApp.exe

CURRENT_IRQL:  2

ANALYSIS_SESSION_HOST:  PAUL-PC

ANALYSIS_SESSION_TIME:  11-29-2017 10:35:11.0546

ANALYSIS_VERSION: 10.0.10575.567 amd64fre

 

TRAP_FRAME:  89812c30 -- (.trap 0xffffffff89812c30)

ErrCode = 00000000

eax=ffff0000 ebx=00000000 ecx=9213a600 edx=ffff4d5c esi=ffff0000 edi=ffff0000

eip=82ad19fe esp=89812ca4 ebp=89813bfc iopl=0         nv up ei pl nz na pe nc

cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010206

nt!strstr+0x1e:

82ad19fe 8a07            mov     al,byte ptr [edi]          ds:0023:ffff0000=??

Resetting default scope

 

LAST_CONTROL_TRANSFER:  from 82a933d8 to 82ae041b

 

STACK_TEXT: 

89812c18 82a933d8 00000000 ffff0000 00000000 nt!MmAccessFault+0x106

89812c18 82ad19fe 00000000 ffff0000 00000000 nt!KiTrap0E+0xdc

89813bfc 82a89593 84525860 843f0858 843f0858 nt!strstr+0x1e

89813c14 82c7d99f 84489e18 843f0858 843f08c8 nt!IofCallDriver+0x63

89813c34 82c80b71 84525860 84489e18 00000000 nt!IopSynchronousServiceTail+0x1f8

89813cd0 82cc73f4 84525860 843f0858 00000000 nt!IopXxxControlFile+0x6aa

89813d04 82a901ea 0000015c 00000000 00000000 nt!NtDeviceIoControlFile+0x2a

89813d04 76fd70b4 0000015c 00000000 00000000 nt!KiFastCallEntry+0x12a

0012f7f0 00000000 00000000 00000000 00000000 0x76fd70b4

 

STACK_COMMAND:  kb

THREAD_SHA1_HASH_MOD_FUNC:  1d162d18111a222172b462becb3845e53e690213

THREAD_SHA1_HASH_MOD_FUNC_OFFSET:  d3c548c893cd75b9806e6f8940169c9ae8e41dba

THREAD_SHA1_HASH_MOD:  cb5f414824c2521bcc505eaa03e92fa10922dad8

 

FOLLOWUP_IP:

nt!strstr+1e

82ad19fe 8a07            mov     al,byte ptr [edi]

 

FAULT_INSTR_CODE:  c683078a

SYMBOL_STACK_INDEX:  2

SYMBOL_NAME:  nt!strstr+1e

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: nt

IMAGE_NAME:  ntkrpamp.exe

DEBUG_FLR_IMAGE_TIMESTAMP:  4ce78a09

IMAGE_VERSION:  6.1.7601.17514

FAILURE_BUCKET_ID:  0x50_nt!strstr+1e

BUCKET_ID:  0x50_nt!strstr+1e

PRIMARY_PROBLEM_CLASS:  0x50_nt!strstr+1e

TARGET_TIME:  2017-11-28T10:00:12.000Z

OSBUILD:  7601

OSSERVICEPACK:  1000

SERVICEPACK_NUMBER: 0

OS_REVISION: 0

SUITE_MASK:  272

PRODUCT_TYPE:  1

OSPLATFORM_TYPE:  x86

OSNAME:  Windows 7

OSEDITION:  Windows 7 WinNt (Service Pack 1) TerminalServer SingleUserTS

OS_LOCALE: 

USER_LCID:  0

OSBUILD_TIMESTAMP:  2010-11-20 17:42:49

BUILDDATESTAMP_STR:  101119-1850

BUILDLAB_STR:  win7sp1_rtm

BUILDOSVER_STR:  6.1.7601.17514.x86fre.win7sp1_rtm.101119-1850

ANALYSIS_SESSION_ELAPSED_TIME: 83a

ANALYSIS_SOURCE:  KM

FAILURE_ID_HASH_STRING:  km:0x50_nt!strstr+1e

FAILURE_ID_HASH:  {955d5f89-fa0e-8221-ae1a-1f21f03e2986}

Followup:     MachineOwner

---------


가장 먼저 .trap 명령을 사용해서 문제가 발생한 부분으로 컨텍스트를 맞춰야한다.

kd> .trap 0xffffffff89812c30

ErrCode = 00000000

eax=ffff0000 ebx=00000000 ecx=9213a600 edx=ffff4d5c esi=ffff0000 edi=ffff0000

eip=82ad19fe esp=89812ca4 ebp=89813bfc iopl=0         nv up ei pl nz na pe nc

cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010206

nt!strstr+0x1e:

82ad19fe 8a07            mov     al,byte ptr [edi]          ds:0023:ffff0000=??


nt!strstr+0x1e 명령을 수행하다 ffff0000 주소가 유효하지 않아 문제가 발생했다.

kv 명령으로 파라미터를 포함한 콜 스택을 확인해보자.

kd> kv

  *** Stack trace for last set context - .thread/.cxr resets it

 # ChildEBP RetAddr  Args to Child             

00 89813bfc 82a89593 84525860 843f0858 843f0858 nt!strstr+0x1e

01 89813c14 82c7d99f 84489e18 843f0858 843f08c8 nt!IofCallDriver+0x63

02 89813c34 82c80b71 84525860 84489e18 00000000 nt!IopSynchronousServiceTail+0x1f8

03 89813cd0 82cc73f4 84525860 843f0858 00000000 nt!IopXxxControlFile+0x6aa

04 89813d04 82a901ea 0000015c 00000000 00000000 nt!NtDeviceIoControlFile+0x2a

05 89813d04 76fd70b4 0000015c 00000000 00000000 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 89813d34)

06 0012f7f0 00000000 00000000 00000000 00000000 0x76fd70b4


콜 스택을 보면 IofCallDriver 함수 내부에서 호출된 strstr 함수를 수행하다 문제가 발생한 것으로 보인다.

얼핏 봐서는 이상한 부분이 전혀 없지만 실은 굉장히 이상한 상황이다. IofCallDriver 함수 내부에는 strstr 함수를 부르는 곳이 없기 때문이다.

이게 도대체 무슨 소리인가? 부르지도 않은 함수가 콜 스택에 표시된다니 정말 말도 안 되는 상황이다. 사실 여부를 확인하기 위해 IofCallDriver 함수의 디스어셈블리 코드를 살펴 보자.

kd> u nt!IofCallDriver L30

nt!IofCallDriver:

82a8952f 8bff            mov     edi,edi

82a89531 55              push    ebp

82a89532 8bec            mov     ebp,esp

82a89534 51              push    ecx

82a89535 a15ccabb82      mov     eax,dword ptr [nt!pIofCallDriver (82bbca5c)]

82a8953a 56              push    esi

82a8953b 8bf1            mov     esi,ecx

82a8953d 33c9            xor     ecx,ecx

82a8953f 3bc1            cmp     eax,ecx

82a89541 7409            je      nt!IofCallDriver+0x1d (82a8954c)

82a89543 ff7504          push    dword ptr [ebp+4]

82a89546 8bce            mov     ecx,esi

82a89548 ffd0            call    eax

82a8954a eb47            jmp     nt!IofCallDriver+0x63 (82a89593)

82a8954c fe4a23          dec     byte ptr [edx+23h]

82a8954f 384a23          cmp     byte ptr [edx+23h],cl

82a89552 7f0c            jg      nt!IofCallDriver+0x30 (82a89560)

82a89554 51              push    ecx

82a89555 51              push    ecx

82a89556 51              push    ecx

82a89557 52              push    edx

82a89558 6a35            push    35h

82a8955a e8a3790a00      call    nt!KeBugCheckEx (82b30f02)

82a8955f cc              int     3

82a89560 8b4260          mov     eax,dword ptr [edx+60h]

82a89563 83e824          sub     eax,24h

82a89566 894260          mov     dword ptr [edx+60h],eax

82a89569 8a08            mov     cl,byte ptr [eax]

82a8956b 897014          mov     dword ptr [eax+14h],esi

82a8956e 80f916          cmp     cl,16h

82a89571 7514            jne     nt!IofCallDriver+0x57 (82a89587)

82a89573 8a4001          mov     al,byte ptr [eax+1]

82a89576 3c02            cmp     al,2

82a89578 7404            je      nt!IofCallDriver+0x4e (82a8957e)

82a8957a 3c03            cmp     al,3

82a8957c 7509            jne     nt!IofCallDriver+0x57 (82a89587)

82a8957e 8bf2            mov     esi,edx

82a89580 e8b6f2fdff      call    nt!IopPoHandleIrp (82a6883b)

82a89585 eb0c            jmp     nt!IofCallDriver+0x63 (82a89593)

82a89587 8b4608          mov     eax,dword ptr [esi+8]

82a8958a 52              push    edx

82a8958b 0fb6c9          movzx   ecx,cl

82a8958e 56              push    esi

82a8958f ff548838        call    dword ptr [eax+ecx*4+38h]

82a89593 5e              pop     esi

82a89594 59              pop     ecx

82a89595 5d              pop     ebp

82a89596 c3              ret


내 눈에는 strstr 함수를 호출하는 부분이 보이지 않는다. call dword ptr [eax+ecx*4+38h] 부분이 조금 의심스럽긴하다. 디스어셈블리 코드가 어려우니 간단한 의사 코드(Pseudo code)로 바꾼 코드를 보자.

NTSTATUS

IofCallDriver(

    IN PDEVICE_OBJECT DeviceObject,

    IN OUT PIRP Irp

    )

{

    PIO_STACK_LOCATION pIoStackLocation;

    PDRIVER_OBJECT pDriverObject;

    NTSTATUS ntStatus;

 

    /* 조건에 따른 pIofCalldriver 함수 호출 */

 

    Irp->CurrentLocation--;

 

    // NO_MORE_IRP_STACK_LOCATIONS(0x35) 에러 처리

    if (Irp->CurrentLocation <= 0)

    {

        KiBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS, Irp, 0, 0, 0);

    }

   

    pIoStackLocation = IoGetNextIrpStackLocation( Irp );

    Irp->Tail.Overlay.CurrentStackLocation = pIoStackLocation;

    pIoStackLocation->DeviceObject = DeviceObject;

    pDriverObject = DeviceObject->DriverObject;

 

    // IRP 요청에 따른 드라이버의 디스패치 루틴 함수 호출

    ntStatus = pDriverObject->MajorFunction[pIoStackLocation->MajorFunction](DeviceObject, Irp);

 

    /* 조건에 따른 IopPoHandleIrp 함수 호출 */

 

    return ntStatus;

}


어떤가? 어디에도 strstr 함수는 보이지 않는다. 나도 처음에는 굉장히 당황스럽고 혼란스러웠다.

다행히 예전에 IofCallDriver 함수를 분석해 본 경험이 있어 이상하다고 생각할 수 있었다.

이런 상황이라면 스택 정보에 문제가 있어 WinDbg가 정상적인 콜 스택을 보여주지 못하는 것은 아닌지 의심해볼 필요가 있다.

 

스택 정보를 담고 있는 곳은 esp(64비트는 rsp). dps esp 명령을 사용하면 콜 스택을 보는 k 명령으로 보여주지 않는 원본 스택 내용을 출력할 수 있다.

이 방법을 통해 스택에서 진짜 함수 호출의 흔적을 찾을 수 있다.

kd> dps esp

89812ca4  84525860

89812ca8  00000000

89812cac  84489e18

89812cb0  9213a4d1 MyDrv+0x44d1                // 2) 의심 부분

89812cb4  ffff0000

89812cb8  9213a600 MyDrv+0x4600                // 1) 의심 부분

89812cbc  00000060

89812cc0  ffff0000

89812cc4  00000000

89812cc8  00000000

89812ccc  0000000a

89812cd0  00000000

89812cd4  88173470

89812cd8  00000000

89812cdc  00000000

89812ce0  89812ca0

89812ce4  8454ba60

89812ce8  8d7e19ea

89812cec  9e50224a

89812cf0  88e1bb88

89812cf4  00000006

89812cf8  87148cde Ntfs!NtfsReadMftRecord+0x236

89812cfc  88e1ba98

89812d00  92d7c6a0

89812d04  8d7e1800

89812d08  00080008

89812d0c  89812d3c

89812d10  87163f6d Ntfs!NtfsFileIsEqual+0x56

89812d14  89812d2c

89812d18  89812d34

89812d1c  00000001

89812d20  896d4000


놀랍게도 콜 스택에 보이지 않던 MyDrv모듈의 함수 호출 흔적이 확인된다.

함수가 호출되면 esp에 함수 수행 후 복귀할 리턴 주소인 함수 호출 명령 다음 위치가 저장된다는 사실을 떠올려보자.

esp MyDrv 관련된 주소 두 곳이 보이는데, ub 명령으로 역 디스어셈블링했을 때 strstr 함수를 호출하는 부분이 바로 리턴 주소다.

1)번 위치인 MyDrv+4600 먼저 확인해보자.

kd> ub MyDrv+0x4600

MyDrv+0x45f8:

9213a5f8 cc              int     3

9213a5f9 cc              int     3

9213a5fa cc              int     3

9213a5fb cc              int     3

9213a5fc cc              int     3

9213a5fd cc              int     3

9213a5fe cc              int     3

9213a5ff cc              int     3


strstr 함수 호출 부분이 확인되지 않으니 찾는 부분이 아니다.

다음 2)번 위치인 MyDrv+44d1을 확인해보자.

kd> ub MyDrv+44d1

MyDrv+0x44ab:

9213a4ab c7411c00000000  mov     dword ptr [ecx+1Ch],0

9213a4b2 eb57            jmp     MyDrv+0x450b (9213a50b)

9213a4b4 e857cbffff      call    MyDrv+0x1010 (92137010)

9213a4b9 8985c4f0ffff    mov     dword ptr [ebp-0F3Ch],eax

9213a4bf 6800a61392      push    offset MyDrv+0x4600 (9213a600)

9213a4c4 8b95c4f0ffff    mov     edx,dword ptr [ebp-0F3Ch]

9213a4ca 52              push    edx

9213a4cb ff1558801392    call    dword ptr [MyDrv+0x2058 (92138058)]


의미있는 정보가 나온다. 마지막 시점에 MyDrv+0x2058(92138058)가 가리키는 주소로 함수를 호출한다.

dword ptr 명령으로 92138058 주소를 참조하고 있으니 poi 명령으로 함수 호출한 부분을 확인해보자.

kd> u poi(92138058)

nt!strstr:

82ad19e0 8b4c2408        mov     ecx,dword ptr [esp+8]

82ad19e4 57              push    edi

82ad19e5 53              push    ebx

82ad19e6 56              push    esi

82ad19e7 8a11            mov     dl,byte ptr [ecx]

82ad19e9 8b7c2410        mov     edi,dword ptr [esp+10h]

82ad19ed 84d2            test    dl,dl

82ad19ef 746f            je      nt!strstr+0x80 (82ad1a60)


빙고! strstr 함수가 나온다. 스택의 2)번 위치인 MyDrv+0x44d1에서 strstr 함수를 호출했음이 밝혀졌다.

이제 문제 발생 원인에 초점을 맞춰보자. MyDrv 모듈에서 strstr 함수 호출시 전달한 파라미터에 문제가 있었을 가능성이 높다.

strstr 함수는 원본 문자열에 검색 문자열이 있을 경우 일치하는 원본 문자열의 첫 번째 위치를 리턴해주는데 함수 원형은 다음과 같다.

PTSTR StrStr(

    _In_ PTSTR  pszFirst,

    _In_ PCTSTR pszSrch

);


함수 원형은 확인했으니 다시 dps esp 명령으로 스택 정보를 확인해보자.

kd> dps esp L10

89812ca4  84525860

89812ca8  00000000

89812cac  84489e18

89812cb0  9213a4d1 MyDrv+0x44d1         // esp+c : 리턴 어드레스

89812cb4  ffff0000                      // esp+10 : 번째 파라미터

89812cb8  9213a600 MyDrv+0x4600         // esp+14 : 번째 파라미터

89812cbc  00000060

89812cc0  ffff0000

89812cc4  00000000

89812cc8  00000000

89812ccc  0000000a

89812cd0  00000000

89812cd4  88173470

89812cd8  00000000

89812cdc  00000000

89812ce0  89812ca0


원본 문자열인 pszFirst ffff0000이고, 검색할 문자열인 pszSrch 9213a600이다.

문제가 되는 함수가 문자열 함수여서 da 명령으로 파라미터 문자열을 출력해 보았다.

kd> da ffff0000

ffff0000  "????????????????????????????????"

ffff0020  "????????????????????????????????"

ffff0040  "????????????????????????????????"

ffff0060  "????????????????????????????????"

ffff0080  "????????????????????????????????"

ffff00a0  "????????????????????????????????"

ffff00c0  "????????????????????????????????"

ffff00e0  "????????????????????????????????"

ffff0100  "????????????????????????????????"

ffff0120  "????????????????????????????????"

ffff0140  "????????????????????????????????"

ffff0160  "????????????????????????????????"

 

kd> da 9213a600

9213a600  "\Microsoft\Windows\Burn\"


원본 문자열인 첫 번재 파라미터의 주소는 페이지 아웃되어 ??로 표시된다. 접근할 수 없는 영역이라는 의미다. 검색 문자열인 두 번째 파라미터에는 정상적인 경로 문자열이 확인된다.

잘못된 주소인 ffff0000에서 "\Microsoft\Windows\Burn\" 문자열이 있는지 찾으려고 시도하다 문제가 발생한 것이 원인이다.

그렇다면, 원본 문자열 주소인 ffff0000는 어디서 온 것일까? ffff0000 strstr 함수에 넘긴 첫 번째 파라미터니 strstr 함수를 호출한 MyDrv+44d1 부분을 다시 살펴보자.

kd> ub MyDrv+44d1

MyDrv+0x44ab:

9213a4ab c7411c00000000  mov     dword ptr [ecx+1Ch],0

9213a4b2 eb57            jmp     MyDrv+0x450b (9213a50b)

9213a4b4 e857cbffff      call    MyDrv+0x1010 (92137010)  // 1) 내부 함수 호출

9213a4b9 8985c4f0ffff    mov     dword ptr [ebp-0F3Ch],eax  // 2) eax ebp-f3c 저장

9213a4bf 6800a61392      push    offset MyDrv+0x4600 (9213a600)  // 3) MyDrv+0x4600 번째 파라미터로 push

9213a4c4 8b95c4f0ffff    mov     edx,dword ptr [ebp-0F3Ch]  // 4) ebp-f3c edx 저장

9213a4ca 52              push    edx                      // 5) edx 번째 파라미터로 push

9213a4cb ff1558801392    call    dword ptr [MyDrv+0x2058 (92138058)]       // 6) strstr 함수 호출


2)번을 보면 eax 값이 ebp-f3c에 저장되고, 4)번에서 다시 edx로 옮겨진다. 그리고 5)번을 보면 edx가 첫 번째 파라미터로 넘겨졌음을 알 수 있다.

eax 가 첫 번째 파라미터이므로 2)번 앞 쪽에서 eax를 설정한 곳을 찾아봐야 한다.

1)번에 함수가 하나 호출되는데 그 안에서 eax가 설정되었을 가능성이 높다. 보통 eax는 함수 호출 완료 후 리턴 값을 저장하는 용도로 사용되기 때문이다.

1)번에서 호출된 함수 주소인 92137010을 살펴보자.

kd> u 92137010 L6

MyDrv+0x1010:

92137010 8bff            mov     edi,edi

92137012 55              push    ebp

92137013 8bec            mov     ebp,esp

92137015 b80000ffff      mov     eax,0FFFF0000h         // ffff0000 eax 저장

9213701a 5d              pop     ebp

9213701b c3              ret


이런! 이 함수에서 ffff0000 값을 리턴하고 있다. 이 값이 결국 strstr 함수의 첫 번째 파라미터로 전달되어 문제가 발생한 것이다.

이제 ffff0000을 리턴한 문제의 함수를 확인해서 정상적인 값을 리턴하도록 변경하면 문제가 해결될 것이다.

 

나는 앞서 원인 분석에 집중하기 위해 의도적으로 숨겨진 콜 스택이 발생한 이유에 대해서는 언급하지 않았다. 이제 문제 발생 원인에 대한 분석이 끝났으니 그 얘기를 마저 해보겠다.

콜 스택을 확인하는 k 명령으로 MyDrv의 콜 스택이 제대로 확인되지 않았던 이유는 strstr 함수가 컴파일된 방식에 원인이 있다.

다음은 strstr 함수와 memcpy 함수의 앞 부분을 비교한 내용이다.

<nt!strstr 함수 프롤로그>

kd> u nt!strstr

nt!strstr:

82ac59e0 8b4c2408        mov     ecx,dword ptr [esp+8]

82ac59e4 57              push    edi

82ac59e5 53              push    ebx

82ac59e6 56              push    esi

82ac59e7 8a11            mov     dl,byte ptr [ecx]

82ac59e9 8b7c2410        mov     edi,dword ptr [esp+10h]

82ac59ed 84d2            test    dl,dl

82ac59ef 746f            je      nt!strstr+0x80 (82ac5a60)

 

<nt!memcpy 함수 프롤로그>

kd> u nt!memcpy

nt!memcpy:

82a7f7c0 55              push    ebp

82a7f7c1 8bec            mov     ebp,esp

82a7f7c3 57              push    edi

82a7f7c4 56              push    esi

82a7f7c5 8b750c          mov     esi,dword ptr [ebp+0Ch]

82a7f7c8 8b4d10          mov     ecx,dword ptr [ebp+10h]

82a7f7cb 8b7d08          mov     edi,dword ptr [ebp+8]

82a7f7ce 8bc1            mov     eax,ecx


어떤 차이가 보이는가? 32비트 환경에서 함수 호출을 하게 되면 기본적으로 스택의 베이스 포인터인 ebp를 기준으로 스택을 구성하게 된다.

memcpy 함수처럼 "push ebp, mov ebp, esp" 로 원본 ebp를 스택에 저장하고 현재 esp를 기준으로 ebp를 재설정하는 패턴이 함수 시작시 수행된다.

k 명령도 이 ebp 를 기준으로 콜 스택을 보여준다. 하지만 strstr 함수의 경우 재미있게도 ebp를 사용하지 않고 64비트 환경처럼 esp 를 기준으로 함수가 동작하게 컴파일되어 있다.

다음은 CompareString 함수 안에서 strstr 함수를 호출하는 테스트 코드를 만들어 콜 스택을 확인한 결과다.


1. CompareString 함수에서 strstr 함수 호출 전 콜 스택 

kd> kv

 # ChildEBP RetAddr  Args to Child             

00 92237bc8 913da27b 00000388 00000388 82b7d944 MyDrv!CompareString+0x37 (FPO: [Non-Fpo]) (CONV: stdcall)

01 92237d28 82a841ea 00000388 01f4f900 771670b4 MyDrv!TestMain+0x4b (FPO: [Non-Fpo]) (CONV: stdcall)

02 92237d28 771670b4 00000388 01f4f900 771670b4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 92237d34)

 

kd> ub 913d9d3e

MyDrv!CompareString+0x26

913d9d27 7507            jne     MyDrv!CompareString+0x2f (913d9d30)

913d9d29 32c0            xor     al,al

913d9d2b e9b3000000      jmp     MyDrv!CompareString+0xe2 (913d9de3)

913d9d30 8b55d0          mov     edx,dword ptr [ebp-30h]

913d9d33 52              push    edx

913d9d34 8b45dc          mov     eax,dword ptr [ebp-24h]

913d9d37 50              push    eax

913d9d38 ff15f4103e91    call    dword ptr [MyDrv!_imp__strstr (913e10f4)]  // 현재 strstr 함수를 호출하기 직전 상태


2. CompareString 함수에서 strstr 함수 호출 직후 콜 스택 

kd> kv

 # ChildEBP RetAddr  Args to Child             

00 92237bc8 913da27b 00000388 00000388 82b7d944 nt!strstr

01 92237d28 82a841ea 00000388 01f4f900 771670b4 MyDrv!TestMain+0x4b (FPO: [Non-Fpo]) (CONV: stdcall)

02 92237d28 771670b4 00000388 01f4f900 771670b4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 92237d34)


예상대로 strstr 함수 내부에서 ebp를 설정하는 부분이 없으므로 CompareString 함수에 대한 콜 스택이 표시되지 않고 사라졌다.

이처럼 함수에 따라 예상과는 다른 코드 패턴으로 컴파일될 수 있다는 사실을 기억하자.

이 외에도 스택 오버플로우나 jmp를 이용한 코드 후킹 기법 등에 의해 스택이나 함수 프롤로그가 망가지면 ebp 기준으로 해석하는 k 명령은 콜 스택을 제대로 표시하지 못할 수 있다.

뭔가 콜 스택이 이상하다고 느껴지면 주저없이 dps esp(64비트는 rsp) 명령으로 스택을 확인하거나 k=address 명령으로 콜 스택을 재구성해보자. 의외의 단서를 얻을 수 있을 것이다.





'Dump Analysis' 카테고리의 다른 글

[0xC5] 풀 헤더 손상  (0) 2018.07.16
[0x1A] 페이지 손상  (0) 2018.07.12
[0x50] 해제된 핸들  (0) 2018.07.09
[0x50] UNICODE_STRING  (0) 2018.07.05
필터매니저(fltmgr.sys) 버그? DRAINING ZOMBIED 와 DOE_UNLOAD_PENDING  (0) 2015.01.22
2015. 1. 22. 23:57

아주 흥미로운 덤프를 분석하게 되서 공유한다.


거의 분석 불가능한 덤프였지만 다행히 분석이 완료되었다.

MyDrv.sys 를 언로드하려고 했지만 알 수 없는 이유로 실패한 상태로 메모리에 남아 있는 이슈여서 강제로 덤프를 생성하여 분석하게 된 Case 다.


참고 : 드라이버 로드시 ERROR_ALREADY_EXISTS(183) 에러



1. 일단 필터매니저에 등록된 필터 정보를 확인해 본다.

kd> !fltkd.frames

Frame List: fffff880013302c0
    FLTP_FRAME: fffffa80039e5010 "Frame 1" "429998.99 to 429999.280700"
    FLT_FILTER: fffffa8006dcc960 "SomeDrv" "[NoName]"
    FLTP_FRAME: fffffa8001b2aac0 "Frame 0" "0 to 429998.99"   
    FLT_FILTER: fffffa800290d900 "MyDrv" "326020"
    FLT_INSTANCE: fffffa80031b4330 "MyDrv Instance" "326020"
    FLT_INSTANCE: fffffa800699d170 "MyDrv Instance" "326020"
    FLT_INSTANCE: fffffa8003658b40 "MyDrv Instance" "326020"



어라, Frame 1 의 SomeDrv.sys 모듈의 상태가 이상하다.
Filter Instance 정보는 없고 Filter Object 정보만 남아 있다.


2. 일단 언로드되지 못하고 있는 불쌍한 MyDrv.sys 를 먼저 확인해 보자.

kd> dt _FLT_FILTER fffffa800290d900
fltmgr!_FLT_FILTER
    +0x000 Base : _FLT_OBJECT
    +0x020 Frame : 0xfffffa80`01b2aac0 _FLTP_FRAME   
    +0x028 Name : _UNICODE_STRING "MyDrv"
    +0x038 DefaultAltitude : _UNICODE_STRING "326020"
    +0x048 Flags : 2 ( FLTFL_FILTERING_INITIATED )
    +0x050 DriverObject : 0xfffffa80`03673c80 _DRIVER_OBJECT
    ... ...


kd> !drvobj 0xfffffa80`03673c80
Driver object (fffffa8003673c80) is for:
    \Driver\MyDrv
Driver Extension List: (id , addr)

Device Object list:
fffffa8002e8f550


kd> !devobj fffffa8002e8f550
Device object (fffffa8002e8f550) is for:
    MyDrv \Driver\MyDrv DriverObject fffffa8003673c80
Current Irp 00000000 RefCount 0 Type 00000022 Flags 00000040
Dacl fffff9a1000846e1 DevExt 00000000 DevObjExt fffffa8002e8f6a0
ExtensionFlags (0x00000801) DOE_UNLOAD_PENDING, DOE_DEFAULT_SD_PRESENT
Characteristics (0000000000)
Device queue is not busy.



역시 언로드되지 못하고 언로드 중인 상태로 남아 있다.
일단 내가 제일 의심스러워 MyDrv.sys 의 언로드 루틴을 검토했지만 버그로 보일만한 부분은 발견되지 않았다.


3. 이제 이상했던 SomeDrv.sys 모듈의 Filter Object 정보를 확인해보자.

kd> !fltkd.filter fffffa8006dcc960

FLT_FILTER: fffffa8006dcc960 "SomeDrv" "[NoName]"
    FLT_OBJECT: fffffa8006dcc960 [02000003] Filter DRAINING ZOMBIED

        RundownRef : 0x0000000000000001 (0) drained
        PointerCount : 0x00000001
        PrimaryLink : [fffffa800b400020-fffffa80039e50c0]
    Frame : fffffa80039e5010 "Frame 1"
    Flags : [00000002] FilteringInitiated
    DriverObject : 0xfffffa8003673c80
    FilterLink : [fffffa800b400020-fffffa80039e50c0]
    PreVolumeMount : 0000000000000000 (null)
    PostVolumeMount : 0000000000000000 (null)
    ... ...



Filte Object 가 "DRAINING ZOMBIED" 상태로 확인된다.
참고로 "DRAINING ZOMBIED" 플래그는 필터매니저가 언로드 과정 중에 내부적으로 설정하는 상태 값이다.
즉, 언로드 과정에서 이 플래그가 설정되는 것 자체는 정상적인 동작이다.


참고로, 미니필터에서 필터매니저에 Context 를 할당(FltAllocateContext )하거나 사용(FltSetStreamContext)하고 해제(FltReleaseContext)하지 않는 경우 필터매니저가 내부적으로 관리하는 ReferenceCount 가 맞지 않게 되어 언로드시 해당 미니필터의 Filter Object 가 "DRAINED" 상태로 언로드에 실패할 수 있다.
(언로드가 완료되지 못한 상태로 메모리에 남아 있게 된다)


다시 본론으로 돌아와서, 문제는 덤프 상의 SomeDrv.sys 는 이미 언로드되어 버린(메모리 상에 없는) 녀석인데도 "DRAINING ZOMBIED" 상태인 Filter Object 가 여전히 남아 있다는 것이다.
(언로드가 완료되면 Filter Object 는 제거되고, Filter Frame 에 더 이상 등록된 Filter 가 없으면 해당 Frame 도 제거되야 한다)

이미 SomeDrv.sys 는 언로드되어 메모리 상에서 없어졌기 때문에 이쯤되면 분석이 거의 불가능한 상태다.

SomeDrv.sys 가 "DRAINING ZOMBIED" 상태인 것과 MyDrv.sys 의 Unload Pending 증상 사이에 어떤 연관성이 있을까?

다행히 다른 시스템에서 MyDrv.sys 가 또 Unload Pending 에 빠진 덤프를 얻을 수 있었다.
SomeDrv.sys 도 있고 SomeDrv.sys 역시 동일하게 "DRAINING ZOMBIED" 상태에 빠져있다.


이쯤되니 다시 덤프를 꺼내 MyDrv.sys, SomeDrv.sys, 필터매니저(fltmgr.sys), 심지어 nt 커널까지 모든 걸 의심의 눈초리로 바라보며 다음과 같은 가설을 세워보기로 했다.


1) SomeDrv.sys 의 버그로 언로드시 "DRAINING ZOMBIED" 상태가 됨

2) SomeDrv.sys 가 "DRAINING ZOMBIED" 가 되는 과정에서 필터매니저나 nt 커널의 데이터가 손상됨

3) 데이터 손상으로 인한 필터매니저나 nt 커널의 오동작으로 MyDrv.sys 가 언로드되지 못함
 


음... 입증하기가 만만치 않아 보인다.
먼저 StopService() 호출 후 MyDrv.sys 의 언로드 루틴이 호출되기까지 언로드 과정을 분석해보니 다음과 같은 콜 스택으로 진행되었다.


08 MyDrv!DriverUnload
07 fltmgr!FltUnregisterFilter
06 MyDrv!MiniFilterUnload
05 fltmgr!FltpDoUnloadFilter
04 fltmgr!FltpMiniFilterDriverUnload
03 nt!IopLoadUnloadDriver                  (System)               
02 nt!IopUnloadDriver                         (Services.exe)
... ...
01 services!StopService



각 함수에서 하는 일을 정리해보면 다음과 같다.


1) 유저모드에서 MyDrv.sys 에 대해 StopService() 호출

2) nt 커널의 언로드 함수인 nt!IopUnloadDriver() 내부에서 언로드할 드라이버의 DeviceObject 에 "DOE_UNLOAD_PENDING"
플래그를 설정하고 WorkItem 으로 nt!IopLoadUnloadDriver() 호출
(이후 과정은 System Thread Context 에서 수행)


nt!IopUnloadDriver+0x37e (fffff800`01a79780):
    call to nt!IopCheckUnloadDriver (fffff800`0175c750)

kd> u nt!IopCheckUnloadDriver L25
nt!IopCheckUnloadDriver:
... ...
fffff800`0175c7bd 8bc3 mov eax,ebx
fffff800`0175c7bf eb49 jmp nt!IopCheckUnloadDriver+0xba (fffff800`0175c80a)
fffff800`0175c7c1 c60601 mov byte ptr [rsi],1
fffff800`0175c7c4 eb1c jmp nt!IopCheckUnloadDriver+0x92 (fffff800`0175c7e2)
fffff800`0175c7c6 488b8138010000 mov rax,qword ptr [rcx+138h]
fffff800`0175c7cd 83482001 or dword ptr [rax+20h],1                 DOE_UNLOAD_PENDING



3) nt!IopLoadUnloadDriver() 에서 필터매니저의 fltmgr!FltpMiniFilterDriverUnload() 호출

4) fltmgr!FltpMiniFilterDriverUnload() 에서 언로드할 드라이버를 찾아 fltmgr!FltpDoUnloadFilter() 호출

5) fltmgr!FltpDoUnloadFilter() 에서 필터매니저가 관리하는 Filter Object 에 "UnloadInProgress" 플래그를 설정하고 MyDrv.sys 의 언로드 함수인 MyDrv!MiniFilterUnload() 호출

kd> u fltmgr!FltpDoUnloadFilter L25
fltmgr!FltpDoUnloadFilter:
... ...
fffff880`01344d7f 41bc10001cc0 mov r12d,0C01C0010h
fffff880`01344d85 e9e7000000 jmp fltmgr!FltpDoUnloadFilter+0x161 (fffff880`01344e71)
fffff880`01344d8a 8bfa mov edi,edx
fffff880`01344d8c 83e701 and edi,1
fffff880`01344d8f 7404 je fltmgr!FltpDoUnloadFilter+0x85 (fffff880`01344d95)
fffff880`01344d91 83494801 or dword ptr [rcx+48h],1                 UnloadInProgress


6) MyDrv.sys 의 언로드 함수인 MyDrv!MiniFilterUnload() 에서 이후 언로드 작업 수행


이제 각 언로드 과정을 하나씩 검증해가며 문제가 없는지 분석해보자.

MyDrv.sys 의 DeviceObject 에 "DOE_UNLOAD_PENDING" 플래그는 이미 확인했으니 1)~2)번은 범인이 아니다.

6)번 과정인 MyDrv.sys 의 MyDrv!MiniFilterUnload() 함수는 MyDrv.sys 의 내부 언로드 관련 플래그를 확인해보니 아직 호출되지 않은 것으로 확인된다.

MyDrv.sys 도 범인이 아니고 가설대로면 nt 커널과 필터매니저 구간인 3)~5)번에 범인이 있을 것이다.


4. MyDrv.sys 의 Filter Object 상태를 확인해보자.

kd> !fltkd.filter fffffa800290d900

FLT_FILTER: fffffa800290d900 "MyDrv" "326020"
    FLT_OBJECT: fffffa800290d900 [02000000] Filter
        RundownRef : 0x0000000000000044 (34)
        PointerCount : 0x00000001
        PrimaryLink : [fffffa8004770020-fffffa8001cb5390]
    Frame : fffffa8001b2aac0 "Frame 0"
    Flags : [00000002] FilteringInitiated
        ... ...



응? Filter Object 에 "FilteringInitiated" 플래그만 있고 "UnloadInProgress" 플래그가 없다.
5)번 과정도 수행되지 않았다고 보는 것이 타당하다.
5)번 과정이 수행되었다면 Filter Object 의 플래그가 "FilteringInitiated UnloadInProgress" 로 변경되었을 것이다.

범인은 3)번이나 4)번일 가능성이 높다.

먼저 3)번의 nt!IopLoadUnloadDriver() 를 분석해보니 특별히 문제될만한 동작을 수행하는 함수가 아니었다.

그래서 4)번 fltmgr!FltpMiniFilterDriverUnload() 함수를 상세 분석해보기로 했다.


IDA 의 Hex-ray 없이 커널 함수를 디스어셈하여 분석하는건 굉장히 지루한 작업이지만 나에게 있어선 분석의 감을 잃지 않게 해주는 습관이기도 하다.


5. 마지막 남은 fltmgr!FltpMiniFilterDriverUnload() 함수를 분석해보자.

fltmgr!FltpMiniFilterDriverUnload:
fffff880`01344fb0 488bc4 mov rax,rsp
fffff880`01344fb3 48895808 mov qword ptr [rax+8],rbx
fffff880`01344fb7 48896810 mov qword ptr [rax+10h],rbp
fffff880`01344fbb 48897018 mov qword ptr [rax+18h],rsi
fffff880`01344fbf 48897820 mov qword ptr [rax+20h],rdi
fffff880`01344fc3 4155 push r13
fffff880`01344fc5 4883ec20 sub rsp,20h
fffff880`01344fc9 488be9 mov rbp,rcx ; rcx : DriverObject
fffff880`01344fcc ff154611feff call qword ptr [fltmgr!_imp_KeEnterCriticalRegion (fffff880`01326118)]
fffff880`01344fd2 488d0d7fb2feff lea rcx,[fltmgr!FltGlobals+0x58 (fffff880`01330258)]
                                                ; 0 FLT_FRAME.FilterUnloadLock (ERESOURCE)
fffff880`01344fd9 b201 mov dl,1
fffff880`01344fdb ff152f11feff call qword ptr [fltmgr!_imp_ExAcquireResourceSharedLite (fffff880`01326110)]
fffff880`01344fe1 488b3dd8b2feff mov rdi,qword ptr [fltmgr!FltGlobals+0xc0 (fffff880`013302c0)]
                                                ; 1 FLT_FRAME.Links
fffff880`01344fe8 4c8d2dd1b2feff lea r13,[fltmgr!FltGlobals+0xc0 (fffff880`013302c0)]
                                                ; 1 FLT_FRAME.Links->FLink (FLT_FRAME 0 .Links)
fffff880`01344fef eb43 jmp fltmgr!FltpMiniFilterDriverUnload+0x84 (fffff880`01345034)
fffff880`01344ff1 ff152111feff call qword ptr [fltmgr!_imp_KeEnterCriticalRegion (fffff880`01326118)]
fffff880`01344ff7 488d4f40 lea rcx,[rdi+40h]
                                                ; 1 FLT_FRAME.RegisteredFilters (ERESOURCE)
fffff880`01344ffb b201 mov dl,1
fffff880`01344ffd ff150d11feff call qword ptr [fltmgr!_imp_ExAcquireResourceSharedLite (fffff880`01326110)]
fffff880`01345003 4c8d9fa8000000 lea r11,[rdi+0A8h]
                                                ; 1 FLT_FRAME.RegisteredFilters.rList (FLT_FILTER.PrimaryLink)
fffff880`0134500a 498b03 mov rax,qword ptr [r11]
                                                ; FLT_FILTER.PrimaryLink.FLink (FLT_FILTER.PrimaryLink)
fffff880`0134500d eb0d jmp fltmgr!FltpMiniFilterDriverUnload+0x6c (fffff880`0134501c)
fffff880`0134500f 488d70f0 lea rsi,[rax-10h]                      ; FLT_FILTER
fffff880`01345013 48396e50 cmp qword ptr [rsi+50h],rbp    ; if( FLT_FILTER.DriverObject == DriverObject )
fffff880`01345017 744e je fltmgr!FltpMiniFilterDriverUnload+0xb7 (fffff880`01345067)        ; Success

fffff880`01345019 488b00 mov rax,qword ptr [rax]
fffff880`0134501c 493bc3 cmp rax,r11                             ; Filter List 끝인지 확인
fffff880`0134501f 75ee jne fltmgr!FltpMiniFilterDriverUnload+0x5f (fffff880`0134500f)
fffff880`01345021 488d4f40 lea rcx,[rdi+40h]                    ; 1 FLT_FRAME.RegisteredFilters (ERESOURCE)
fffff880`01345025 ff15fd10feff call qword ptr [fltmgr!_imp_ExReleaseResourceLite (fffff880`01326128)]
fffff880`0134502b ff15ef10feff call qword ptr [fltmgr!_imp_KeLeaveCriticalRegion (fffff880`01326120)]
fffff880`01345031 488b3f mov rdi,qword ptr [rdi]
fffff880`01345034 493bfd cmp rdi,r13                             ; Frame List 끝인지 확인
fffff880`01345037 75b8 jne fltmgr!FltpMiniFilterDriverUnload+0x41 (fffff880`01344ff1)
fffff880`01345039 488d0d18b2feff lea rcx,[fltmgr!FltGlobals+0x58 (fffff880`01330258)]
                                                                             ; 0 FLT_FRAME.FilterUnloadLock (ERESOURCE)
fffff880`01345040 ff15e210feff call qword ptr [fltmgr!_imp_ExReleaseResourceLite (fffff880`01326128)]
fffff880`01345046 ff15d410feff call qword ptr [fltmgr!_imp_KeLeaveCriticalRegion (fffff880`01326120)]
fffff880`0134504c 488b5c2430 mov rbx,qword ptr [rsp+30h]
fffff880`01345051 488b6c2438 mov rbp,qword ptr [rsp+38h]
fffff880`01345056 488b742440 mov rsi,qword ptr [rsp+40h]
fffff880`0134505b 488b7c2448 mov rdi,qword ptr [rsp+48h]
fffff880`01345060 4883c420 add rsp,20h
fffff880`01345064 415d pop r13
fffff880`01345066 c3 ret

fffff880`01345067 488bce mov rcx,rsi
fffff880`0134506a e8b136fdff call fltmgr!FltObjectReference (fffff880`01318720)
fffff880`0134506f 488d4f40 lea rcx,[rdi+40h]
fffff880`01345073 8bd8 mov ebx,eax
fffff880`01345075 ff15ad10feff call qword ptr [fltmgr!_imp_ExReleaseResourceLite (fffff880`01326128)]
fffff880`0134507b ff159f10feff call qword ptr [fltmgr!_imp_KeLeaveCriticalRegion (fffff880`01326120)]
fffff880`01345081 488d0dd0b1feff lea rcx,[fltmgr!FltGlobals+0x58 (fffff880`01330258)]
fffff880`01345088 ff159a10feff call qword ptr [fltmgr!_imp_ExReleaseResourceLite (fffff880`01326128)]
fffff880`0134508e ff158c10feff call qword ptr [fltmgr!_imp_KeLeaveCriticalRegion (fffff880`01326120)]
fffff880`01345094 85db test ebx,ebx
fffff880`01345096 78b4 js fltmgr!FltpMiniFilterDriverUnload+0x9c (fffff880`0134504c)
fffff880`01345098 41b001 mov r8b,1
fffff880`0134509b ba01000000 mov edx,1
fffff880`013450a0 488bce mov rcx,rsi
fffff880`013450a3 e868fcffff call fltmgr!FltpDoUnloadFilter (fffff880`01344d10)
                                                                            ; Call fltmgr!FltpDoUnloadFilter
fffff880`013450a8 eba2 jmp fltmgr!FltpMiniFilterDriverUnload+0x9c (fffff880`0134504c)
                                                                            ; Go to end of function


fltmgr!FltpMiniFilterDriverUnload() 함수 동작을 정리해보면 다음과 같다.


1) 필터매니저가 관리하는 FLT_FRAME 중 가장 마지막에 생성된 Frame 의 FLT_FILTER 를 검사(Frame 1부터)
    - fltmgr!FltGlobals 전역 변수에서 Frame 에 대한 리스트(FLT_FRAME.Links)를 얻음
    - FLT_FRAME.RegisteredFilters.rList 에서 Frame 에 등록된 Filter 에 대한 리스트(FLT_FILTER.PrimaryLink)를 얻음

2) 언로드 요청된 모듈의 DriverObject 와 FLT_FILTER 의 내부 필드인 DriverObject 의 값이 일치하는지 확인
    - FLT_FILTER.DriverObject

3) 일치할 경우 해당 모듈에 대해 fltmgr!FltpDoUnloadFilter() 를 호출해주고, 다를 경우 마지막 Frame 까지 확인



결론적으로 필터매니저에 등록된 미니필터들은 필터매니저에서 로직상 하나의 Frame 리스트로 관리된다고 볼 수 있다.

하나의 리스트를 순차적으로 검사하며 언로드를 수행하기 때문에 앞 쪽 리스트의 DriverObject 정보가 잘못되면 뒷 쪽 리스트의 미니필터가 언로드되지 못할 가능성이 있다.


이제 마지막 과정만 남았다.

함수 분석 결과 Frame 리스트에는 Frame 0 에 등록된 MyDrv.sys 보다 Frame 1 에 등록된 SomeDrv.sys 가 앞 쪽에 위치하고 있다.
필터매니저가 SomeDrv.sys 에 대해 정말로 잘못된 DriverObject 를 가지고 있었는지만 확인하면 된다.


6. 필터매니저가 보관하고 있는 SomeDrv.sys 의 정보를 확인해보자.

kd> !fltkd.frames

Frame List: fffff880013302c0
FLTP_FRAME: fffffa80039e5010 "Frame 1" "429998.99 to 429999.280700"
FLT_FILTER: fffffa8006dcc960"SomeDrv" "[NoName]"
FLTP_FRAME: fffffa8001b2aac0 "Frame 0" "0 to 429998.99"
FLT_FILTER: fffffa800290d900 "MyDrv" "326020"
FLT_INSTANCE: fffffa80031b4330 "MyDrv Instance" "326020"
FLT_INSTANCE: fffffa800699d170 "MyDrv Instance" "326020"
FLT_INSTANCE: fffffa8003658b40 "MyDrv Instance" "326020"


kd> dt _FLT_FILTER fffffa8006dcc960
fltmgr!_FLT_FILTER
    +0x000 Base : _FLT_OBJECT
    +0x020 Frame : 0xfffffa80`039e5010 _FLTP_FRAME
    +0x028 Name : _UNICODE_STRING "SomeDrv"
    +0x038 DefaultAltitude : _UNICODE_STRING ""
    +0x048 Flags : 2 ( FLTFL_FILTERING_INITIATED )
    +0x050 DriverObject : 0xfffffa80`03673c80 _DRIVER_OBJECT
    ... ...


kd> !drvobj 0xfffffa80`03673c80
Driver object (fffffa8003673c80) is for:
    \Driver\MyDrv
Driver Extension List: (id , addr)

Device Object list:
fffffa8002e8f550



역시, 필터매니저가 어떤 이유로 SomeDrv.sys 의 Filter Object 에 SomeDrv.sys 의 DriverObject 가 아닌 MyDrv.sys 의 DriverObject 를 설정해 놓았다.

결국 MyDrv.sys 를 StopService() 했을 때 필터매니저의 fltmgr!FltpDoUnloadFilter() 에서 언로드를 요청한 MyDrv.sys 가 아닌 SomeDrv.sys 를 언로드한 것이 원인이었다. OTL

언로드 과정 중 4)번 fltmgr!FltpDoUnloadFilter() 부터 잘못되버려 MyDrv.sys 의 언로드 함수인 MyDrv!MiniFilterUnload() 는 호출조차 되지 못한 것이다.


※ 이 필터매니저(fltmgr.sys) 버그는 Microsoft 에 Report 했고 최신 필터매니저 버전에서 fix 되었다.

'Dump Analysis' 카테고리의 다른 글

[0xC5] 풀 헤더 손상  (0) 2018.07.16
[0x1A] 페이지 손상  (0) 2018.07.12
[0x50] 해제된 핸들  (0) 2018.07.09
[0x50] 숨겨진 콜 스택  (0) 2018.07.07
[0x50] UNICODE_STRING  (0) 2018.07.05
prev"" #1 next