'DriverEntry'에 해당되는 글 2건

  1. 2010.04.28 [WinDbg 사용] DriverEntry 쉽게 찾기 2
  2. 2010.04.21 [WinDbg 사용] DriverEntry 찾기 2
WinDbg 디버깅2010. 4. 28. 00:10
반응형

지난번 노가다 포스팅에 이어 태화님이 알려주신 깔끔 팁을 정리해 봅니다.

WinDbg는 Debug 메뉴에 Event Filters... 라는 항목이 있습니다.
각종 이벤트들을 디버거가 잡아주도록 하는 설정인데요.

여기에서 Load module을 enable해 놓으면 됩니다.


이렇게 설정해 놓고 드라이버를 로드하면 드라이버 이미지만 메모리에 로드하고 DriverEntry를 실행하기 전에 깔끔하게 브레이크 포인트가 걸립니다.

이 때 콜스택을 보면 아래와 같습니다.

kd> kb
ChildEBP RetAddr  Args to Child             
f9dffaa4 80528fce f9dffb3c f9dffab8 00000003 nt!DebugService2+0x10
f9dffac8 805a4cea f9dffb3c f9f90000 ffffffff nt!DbgLoadImageSymbols+0x42
f9dffc6c 80577254 f9dffcf0 00000000 00000000 nt!MmLoadSystemImage+0xa34
f9dffd4c 8057765f 00000528 00000001 00000000 nt!IopLoadDriver+0x370
f9dffd74 80535dd0 00000528 00000000 817ba020 nt!IopLoadUnloadDriver+0x45
f9dffdac 805c6a28 f7d18cf4 00000000 00000000 nt!ExpWorkerThread+0x100
f9dffddc 80542fa2 80535cd0 00000001 00000000 nt!PspSystemThreadStartup+0x34
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16

여기서 DriverEntry의 주소를 어떻게 찾아야 하나 잠깐 당황했는데요. 
DbgLoadImageSymbols()의 인자로 ImageBase가 전달되므로 찾을 수 있습니다.

VOID
NTAPI
DbgLoadImageSymbols(
     IN PANSI_STRING Name,
     IN PVOID Base,
     IN ULONG_PTR ProcessId
)

콜스택에서 보이는 인자를 하나씩 확인해 보면

kd> ds f9dffb3c
816faf00  "\WINDOWS\System32\Drivers\Null.S"
816faf20  "YS"

kd> lmvm null
start    end        module name
f9f90000 f9f90b80   Null       (deferred)            
    Image path: Null.SYS
    Image name: Null.SYS
    ...

드라이버 이름에 대한 주소라는 것과 드라이버의 ImageBase 주소라는 것을 확인할 수 있습니다.

ImageBase를 알고 있으므로 !dh 명령으로 EntryPoint를 구합니다.

kd> !dh f9f90000

File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
     14C machine (i386)
       6 number of sections
3B7D82EB time date stamp Sat Aug 18 05:47:39 2001

...

OPTIONAL HEADER VALUES
     10B magic #
    7.00 linker version
     300 size of code
     580 size of initialized data
       0 size of uninitialized data
     59A address of entry point
     300 base of code


ImageBase에 address of entry point를 더해 주면 DriverEntry의 주소가 됩니다.


kd> u f9f90000 + 59A
Null!DriverEntry:
f9f9059a 55              push    ebp
f9f9059b 8bec            mov     ebp,esp
f9f9059d 83ec0c          sub     esp,0Ch
f9f905a0 56              push    esi

깔끔하고 쉽게 구하는 방법이 있었네요. ^^

 

반응형
Posted by GreeMate
WinDbg 디버깅2010. 4. 21. 01:10
반응형

간혹 악성 드라이버를 분석할 일이 있는데 이 녀석의 시작점인 DriverEntry부터 보고 싶은 경우 어찌할 바를 몰라 고민하는 경우가 있었습니다.

그러다 생각한 것이 커널 내부함수인 IopLoadDriver로 부터 따라가서 들어가는 방법인데요. 노가다가 좀 심합니다. 그래도 정리해 보면 좋을 것 같아서 포스팅해 봅니다. (누가 좀 효율적인 방법 좀 알면 알려주세요. -_-a)

XP SP2 기준이구요 예제로 Null 드라이버를 로드해 봤습니다. 
먼저 IopLoadDriver에 브레이크 포인트를 겁니다.

kd> bp nt!IopLoadDriver
kd> bl
 0 e 805a5ba3     0001 (0001) nt!IopLoadDriver

g로 실행하고 나서 OsrLoader 같은 것으로 Null 드라이버를 로드합니다. 그러면 드라이버를 로드하는 과정에서 브레이크 포인트가 걸립니다.

Breakpoint 0 hit
nt!IopLoadDriver:
805a5ba3 8bff            mov     edi,edi

kd> k
ChildEBP RetAddr 
f9e93d4c 805a627c nt!IopLoadDriver
f9e93d74 804e626b nt!IopLoadUnloadDriver+0x45
f9e93dac 8057f16b nt!ExpWorkerThread+0x100
f9e93ddc 804fa27a nt!PspSystemThreadStartup+0x34
00000000 00000000 nt!KiThreadStartup+0x16

콜스택을 보면 시스템에서 드라이버를 로드하는 과정임을 볼 수 있습니다. IopLoadDriver 시작위치에서 멈췄네요.

이제 새로운 명령어인 pc(Step to Next Call)을 사용해 볼껀데요.
이 명령을 사용하면 현재 실행주소로부터 다음 call을 만날 때까지 쭉~ 실행됩니다.
다음 call에서 멈추지요. 자... 이제 pc를 수행합니다.

kd> pc
nt!IopLoadDriver+0x4b:
805a5bee e836b0fcff      call    nt!NtQueryKey (80570c29)

NtQueryKey를 호출하는 부분에서 멈췄네요.
앞뒤의 코드를 모두 보이면 아래와 같습니다.

805a5bde 66895d9a        mov     word ptr [ebp-66h],bx
805a5be2 895d9c          mov     dword ptr [ebp-64h],ebx
805a5be5 899d78ffffff    mov     dword ptr [ebp-88h],ebx
805a5beb 895da8          mov     dword ptr [ebp-58h],ebx
805a5bee e836b0fcff      call    nt!NtQueryKey (80570c29)
805a5bf3 3d05000080      cmp     eax,80000005h
805a5bf8 740b            je      nt!IopLoadDriver+0x6a (805a5c05)
805a5bfa 3d230000c0      cmp     eax,0C0000023h
805a5bff 0f856d330400    jne     nt!IopLoadDriver+0x5e (805e8f72)

코드에 특이사항이 없으므로 다시 pc를 실행하여 다음 call까지 실행하게 합니다.

kd> pc
nt!IopLoadDriver+0x78:
805a5c13 e8ac6ffaff      call    nt!ExAllocatePoolWithTag (8054cbc4)

메모리를 할당하는 부분이네요. 원하는 부분이 아니므로 또 pc를 합니다.
엔터만 쳐서 이전 명령을 그대로 수행하는 WinDbg의 기능을 사용해 보죠.

kd>
nt!IopLoadDriver+0x99:
805a5c34 e8f0affcff      call    nt!NtQueryKey (80570c29)

kd>
nt!IopLoadDriver+0xca:
805a5c65 e85a6ffaff      call    nt!ExAllocatePoolWithTag (8054cbc4)

kd>
nt!IopLoadDriver+0x114:
805a5caf e8cd46f5ff      call    nt!RtlAppendUnicodeToString (804fa381)

kd>
nt!IopLoadDriver+0x11f:
805a5cba e8d75af6ff      call    nt!HeadlessKernelAddLogEntry (8050b796)

kd>
nt!IopLoadDriver+0x1e6:
805a5cd8 e8c956f3ff      call    nt!ExAcquireResourceSharedLite (804db3a6)

kd>
nt!IopLoadDriver+0x1fd:
805a5cf5 e8ac26f6ff      call    nt!RtlEqualString (805083a6)

kd>
nt!IopLoadDriver+0x1fd:
805a5cf5 e8ac26f6ff      call    nt!RtlEqualString (805083a6)

관심있는 부분까지 계속 진행해야 하는데 이 쯤에서 RtlEqualString이 반복됩니다.
루프인 것 같아서 뒤부분의 코드를 살펴 봅니다.

805a5cf5 e8ac26f6ff      call    nt!RtlEqualString (805083a6)805a5cfa 84c0            test    al,al
805a5cfc 0f8531330400    jne     nt!IopLoadDriver+0x23a (805e9033)
805a5d02 8b3f            mov     edi,dword ptr [edi]
805a5d04 ebdd            jmp     nt!IopLoadDriver+0x208 (805a5ce3)
805a5d06 2e005300        add     byte ptr cs:[ebx],dl
805a5d0a 59              pop     ecx
805a5d0b 005300          add     byte ptr [ebx],dl
805a5d0e 0000            add     byte ptr [eax],al
805a5d10 0000            add     byte ptr [eax],al
805a5d12 8bce            mov     ecx,esi
805a5d14 e83779f3ff      call    nt!ExReleaseResourceLite (804dd650)

루프 바깥 부분에 브레이크 포인트를 걸어주고 그냥 go를 해버려서 루프를 빠져나가려고 합니다.

루프 바깥에 브레이크 포인트를 걸 지점을 찾아야 하는데 앞에서 call 한 흐름을 보면 다행히 RtlEqualString이 반복되기 직전에 ExAcquireResourceSharedLite를 호출한 것이 보이네요.

그러므로 ExReleaseResourceLite에 걸어주면 적당해 보입니다.

kd> bp 805a5d14
kd> bl
 0 e 805a5ba3     0001 (0001) nt!IopLoadDriver
 1 e 805a5d14     0001 (0001) nt!IopLoadDriver+0x212

kd> g
Breakpoint 1 hit
nt!IopLoadDriver+0x212:
805a5d14 e83779f3ff      call    nt!ExReleaseResourceLite (804dd650)

루프를 빠져나오면서 브레이크 포인트가 걸렸습니다.
이제부터는 다시 call을 확인하면서 진행합니다.

kd> pc
nt!IopLoadDriver+0x222:
805a5d24 e8dcfbffff      call    nt!IopBuildFullDriverPath (805a5905)

kd>
nt!IopLoadDriver+0x31a:
805a5d3e e806fdffff      call    nt!IopGetDriverNameFromKeyNode (805a5a49)

kd>
nt!IopLoadDriver+0x36b:
805a5d8f e8dff4ffff      call    nt!MmLoadSystemImage (805a5273)

kd>
nt!IopLoadDriver+0x428:
805a5da2 e82e4af5ff      call    nt!RtlImageNtHeader (804fa7d5)

kd>
nt!IopLoadDriver+0x43a:
805a5db4 e829200000      call    nt!IopPrepareDriverLoading (805a7de2)

kd>
nt!IopLoadDriver+0x47f:
805a5df0 e8590bfcff      call    nt!ObCreateObject (8056694e)

kd>
nt!IopLoadDriver+0x4c7:
805a5e3c e89449f5ff      call    nt!RtlImageNtHeader (804fa7d5)

kd>
nt!IopLoadDriver+0x4fb:
805a5e70 e8ae05fcff      call    nt!ObInsertObject (80566423)

kd>
nt!IopLoadDriver+0x536:
805a5ea0 e84301fcff      call    nt!ObReferenceObjectByHandle (80565fe8)

kd>
nt!IopLoadDriver+0x547:
805a5eb1 e8032ffcff      call    nt!NtClose (80568db9)

kd>
nt!IopLoadDriver+0x563:
805a5ecd e8f26cfaff      call    nt!ExAllocatePoolWithTag (8054cbc4)

kd>
nt!IopLoadDriver+0x5b1:
805a5f1b e8a46cfaff      call    nt!ExAllocatePoolWithTag (8054cbc4)

kd>
nt!IopLoadDriver+0x5e8:
805a5f3d e8fed7fdff      call    nt!NtQueryObject (80583740)

kd>
nt!IopLoadDriver+0x61e:
805a5f59 e8666cfaff      call    nt!ExAllocatePoolWithTag (8054cbc4)

kd>
nt!IopLoadDriver+0x669:
805a5fa4 ff572c          call    dword ptr [edi+2Ch]

뭔가 로드되고 있는 것처럼 보이지 않나요? ^^

마지막 call이 제가 찾던 부분입니다. 어떤 함수주소를 호출하는게 보이죠?
저는 이것이 로드될 드라이버의 DriverEntry이기를 바라고 있죠.
앞쪽 코드를 보면 push 두번이 보이므로 2개의 파라미터를 가진다는 것을 알 수 있습니다.

805a5f9a 8b7d80          mov     edi,dword ptr [ebp-80h]
805a5f9d ffb570ffffff    push    dword ptr [ebp-90h]
805a5fa3 57              push    edi
805a5fa4 ff572c          call    dword ptr [edi+2Ch]  ds:0023:81593884={Null!DriverEntry (fa13159a)}
805a5fa7 3bc3            cmp     eax,ebx

그런데 DriverEntry가 2개의 파라미터를 가지자나요.

NTSTATUS 
  DriverEntry
    __in struct _DRIVER_OBJECT  *DriverObject,
    __in PUNICODE_STRING  RegistryPath 
    )

그래서 현재 스택에 push된 파라미터를 확인해 보니 DriverObject와 RegistryPath가 확인됩니다.

kd> dd esp
f9e9bc84  814a9330 814fe000 00000000 f657bcf4

kd> !drvobj 814a9330
Driver object (814a9330) is for:
 \Driver\Null
Driver Extension List: (id , addr)

Device Object list:

kd> dS 814fe000
814fe008  "\REGISTRY\MACHINE\SYSTEM\Control"
814fe048  "Set001\Services\Null"

DriverEntry 진입점을 찾았네요.
그런데 역시 노가다는 심하네요. ^^

반응형
Posted by GreeMate