четверг, 10 февраля 2011 г.

Определение id сервисной ф-ции

Предположим, перехвачена ф-ция на уровне менеджера объектов, к примеру ObCreateObject.
Как определить, какая сервисная ф-ция вызвала перехваченную ObCreateObject?
Ну, логично брякнуться внутри перехваченной ф-ции, и посмотреть стек вызовов:

kd> k
ChildEBP RetAddr 
ee6aece0 f7966345 Template!InternalObCreateObject+0xee
ee6aece4 8060528e Template!NewObCreateObject+0x5
ee6aed48 8053d648 nt!NtCreateEvent+0x90
ee6aed48 7c90e514 nt!KiFastCallEntry+0xf8
00abfd74 7c90d09a ntdll!KiFastSystemCallRet
00abfd78 7c80a78a ntdll!NtCreateEvent+0xc
00abfdc4 76d525a0 kernel32!CreateEventW+0x67
WARNING: Frame IP not in any known module. Following frames may be wrong.
00abfe68 7c917719 0x76d525a0
00abffa0 77de354b ntdll!LdrpGetProcedureAddress+0xa6
00abffbc 00000000 ADVAPI32!ScSvcctrlThreadA+0x12

А дальше казалось бы, логично проделать теже действия, что и WinDbg, и достать id из стаба ntdll, т.е. выполнить стек бектрейс, например, используя RtlCaptureStackBackTrace. И все бы хорошо, но данная ф-ция вернет лишь три верхних строчки из приведенного лога. И это понятно, т.к. ф-ция прыгает по цепочкам ebp фреймов, но допрыгать ф-ция может лишь до места, где копируется юзермодный стек в ядерный ( в обработчике sysenter ).

Где же взять информацию о юзермодном стеке? Ответ прост: в трап фрейме:

kd> dt nt!_KTRAP_FRAME 0xee6aed64
...
   +0x070 EFlags           : 0x202
   +0x074 HardwareEsp      : 0xabfd78 <========== юзермодный стек
   +0x078 HardwareSegSs    : 0x23

а вот и то, что нужно:

kd> dds 0xabfd78
00abfd78  7c90d09a ntdll!NtCreateEvent+0xc
00abfd7c  7c80a78a kernel32!CreateEventW+0x67

kd> u 7c90d09a
ntdll!NtCreateEvent+0xc:
7c90d09a c21400          ret     14h
7c90d09d 90              nop

Теперь можно прочитать id:

kd> u NtCreateEvent
ntdll!ZwCreateEvent:
7c90d08e b823000000      mov     eax,23h <== id
7c90d093 ba0003fe7f      mov     edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c90d098 ff12            call    dword ptr [edx]
7c90d09a c21400          ret     14h

То есть, бектрейс в данном случае оказался совсем не нужным.
На х64 все еще проще, id сискола сохраняется в KTHREAD_SystemCallNumber(название по памяти пишу, могу ошибаться в имени поля).

Комментариев нет:

Отправить комментарий