MessageTable

eXeL@B DVD

Материал из Справочник исследователя программ

Перейти к: навигация, поиск

Таблица лежащая в основе механизма оконных сообщений NT. Описывает вектора соответствующие сообщениям. Необходима для определения вызываемого вектора по номеру сообщения:

    {IMSG_DWORD, FALSE, FALSE},                   // WM_SETREDRAW             0x000B
    {IMSG_INSTRINGNULL,  TRUE,  TRUE},            // WM_SETTEXT               0x000C
    {IMSG_OUTSTRING,  TRUE,  TRUE},               // WM_GETTEXT               0x000D
    {IMSG_GETDBCSTEXTLENGTHS,  TRUE,  TRUE},      // WM_GETTEXTLENGTH         0x000E
    {IMSG_DWORD, FALSE, FALSE},                   // WM_PAINT                 0x000F

Общая модель механизма.

Для доставки сообщений в юзермод ядро вызывает теневой диспетчер(KiUserCallbackDispatcher() посредством KeUserModeCallback()), который получает одним из параметров идентификатор вызываемого вектора(это индекс вектора в таблице векторов(PEB.KerbelCallbackTable: User32!apfnDispatch)). Большинство векторов представляют собой заглушки для вызова клиентских диспетчеров(таблицы User32!pfnClient*, пользовательские но хранятся в ядре). Эти диспетчеры выполняют предварительную диспетчеризацию сообщений и вызывают пользовательские колбеки(оконные процедуры и пр.). На стороне ядра из Win32k!MessageTable выбирается значение(индексируется номером сообщения), которое индексирует в таблице(gapfnScSendMessage) исходящих из ядра сообщений(клиентских) ядерный стаб(Sfn*()) передающий управление в юзермод для вызова определённого вектора. Этот стаб формирует параметры для вектора, выполняет их валидацию и вызывает пользовательский вектор, передав его идентификатор(индекс в apfnDispatch) в диспетчер сообщений(KiUserCallbackDispatcher()). Далее он выбирает из таблицы векторов вектор и вызывает его, в свою очередь он вызывает вектор(не обязательно, может например выводить сообщения или загружать модуля) из pfnClient, а тот пользовательские функции. Часто при отладке необходимо пройти всю цепочку вызовов начиная с самого дна. Или например поставить останов на какое либо событие. Для этого нужно знать необходимый вектор, тоесть его индекс. Он извлекается из MessageTable, например необходим вектор для WM_DRAWITEM, находим его в INLPDRAWITEMSTRUCT. Соответственно посмотрев в таблице apfnDispatch найдём его индекс - 12 и вектор User32!fnINLPDRAWITEMSTRUCT. При отсутствии символов индекс можно найти из Sfn* по первому параметру KeUserModeCallback(), при этом нужно помнить что на значение в MessageTable налаживается маска из 6-ти младших бит: скрин

Источник — «https://exelab.ru/faq/MessageTable»