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