воскресенье, 11 июля 2010 г.

Перечисляем зарегистрированные Callbacks

Callbacks - отличный механизм виндов, позволяющий драйверам получать нотификацию о всяких разных событиях. Если вы когда-либо запускали WinObj, то могли видеть имена этих callbacks в узле Callback
К сожалению как обычно - внутренности их реализации недокументированы. Но кого и когда эта мелкая неприятность останавливала ?

Предположим что нам хочется посмотреть какие драйвера (или точнее какие адреса функций) зарегистрированы как получатели на каждый callback
Начнем как обычно - с чтения документации - ExCreateCallback & ExRegisterCallback
Cтруктура _CALLBACK_OBJECT в wdk7 описана как
typedef struct _CALLBACK_OBJECT *PCALLBACK_OBJECT;
но довольно легко находится например в native-nt-toolkit. Там же чуть ниже описана и вторая структура, которая нам потребуется - _CALLBACK_REGISTRATION:
typedef struct _CALLBACK_OBJECT
{
  ULONG Signature;
  KSPIN_LOCK Lock;
  LIST_ENTRY RegisteredCallbacks;
  BOOLEAN AllowMultipleCallbacks;
  UCHAR reserved[3];
} CALLBACK_OBJECT, *PCALLBACK_OBJECT;

typedef struct _CALLBACK_REGISTRATION
{
  LIST_ENTRY Link;
  PCALLBACK_OBJECT CallbackObject;
  PCALLBACK_FUNCTION CallbackFunction;
  PVOID CallbackContext;
  ULONG Busy;
  BOOLEAN UnregisterWaiting;
} CALLBACK_REGISTRATION, *PCALLBACK_REGISTRATION;


Очевидно что поле _CALLBACK_OBJECT.RegisteredCallbacks содержит связный список из структур _CALLBACK_REGISTRATION, откуда уже можно достать адреса CallbackFunction. Значительно менее очевидно как получить саму _CALLBACK_OBJECT - медитация в дизассемблере подсказывает что для этого можно вызвать ObReferenceObjectByName или пару функций ObOpenObjectByName/ObReferenceObjectByHandle с правильным типом объекта - в данном случае он должен быть ExCallbackObjectType

Здесь нас поджидает еще одна засада - ExCallbackObjectType не экспортируется, хотя и может быть найден дизассемблированием все той же функции ExCreateCallback например.

Итак, порядок действий примерно такой:
  1. Находим (например дизассемблированием ExCreateCallback) адрес ExCallbackObjectType - это может быть сделано как в kernel mode, так и в user mode
  2. Перечисляем все объекты из \Callback, сохраняем их полные имена - аналогично достижимо как в kernel mode, так и в user mode
  3. Открываем объект Callback по имени с ранее найденным типом ExCallbackObjectType, лочим его _CALLBACK_OBJECT.Lock и перебираем список _CALLBACK_OBJECT.RegisteredCallbacks - kernel mode only
  4. PROFIT
Я приведу только кусочек кода для п3, здесь в UnicodeString хранится имя Callback, для которого извлекаются адреса ф-ций обработчиков, в exCBType - адрес ранее найденного ExCallbackObjectType:

PCALLBACK_OBJECT cbObject;

HANDLE Handle = NULL;

InitializeObjectAttributes(&ObjAttr, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
// получим HANDLE объекта
res = ObOpenObjectByName(&ObjAttr,
    (POBJECT_TYPE *)exCBType,
    KernelMode,
    NULL,
    0, // DesiredAccess,
    NULL,
   &Handle
);
// получим PCALLBACK_OBJECT
res = ObReferenceObjectByHandle(
    Handle,
    0, // DesiredAccess
    (POBJECT_TYPE *)exCBType,
    KernelMode,
   &cbObject,
    NULL
);
ZwClose(Handle); // HANDLE больше не нужен
// вытащим адреса ф-ций, зарегистрированных для данного callback object
if ( NT_SUCCESS(res) )
{
  // ok, lets iterate on all callbacks
  PLIST_ENTRY Link;
  PCALLBACK_REGISTRATION CallbackRegistration;
  KIRQL OldIrql;
  ULONG total;
  // встаем на Lock
  KeAcquireSpinLock(&cbObject->Lock, &OldIrql);
  for ( total = 0, Link = cbObject->RegisteredCallbacks.Flink;
        Link != &cbObject->RegisteredCallbacks;
        Link = Link->Flink, total++
      )
  {
    CallbackRegistration = CONTAINING_RECORD (Link, CALLBACK_REGISTRATION, Link);
    // Gotcha ! у нас есть еще один адрес - тут с ним можно что-нть сделать
    ... // perl yada yada operator
  }
  // отпускаем Lock
  KeReleaseSpinLock(&cbObject->Lock, OldIrql);
}
// объект Callback больше не нужен
ObDereferenceObject(cbObject);


Примерчик работы вышеописанного кода на моей машине:
CB: Ndis1394CallbackObject, total 1:
  F768C548 (\SystemRoot\system32\DRIVERS\nic1394.sys)
CB: SetSystemState, total 0:
CB: NdisBindUnbind, total 0:
CB: PowerState, total 9:
  806D46F8 (\WINDOWS\system32\hal.dll)
  F74BB568 (ACPI.sys)
  F72DD5B0 (PGPwded.sys)
  F7208174 (NDIS.sys)
  F76D1578 (\SystemRoot\system32\DRIVERS\processr.sys)
  F60B4498 (\SystemRoot\system32\DRIVERS\parport.sys)
  F62F2BA0 (\SystemRoot\system32\drivers\ALCXWDM.SYS)
  F60C451E (\SystemRoot\system32\DRIVERS\VIDEOPRT.SYS)
  EC7FF4EE (\??\C:\WINDOWS\system32\Drivers\vmx86.sys)
CB: TcpConnectionCallback, total 1:
  EFAF761E (\SystemRoot\system32\DRIVERS\ipnat.sys)
CB: SetSystemTime, total 0:

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

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