Часть полного текста документа:Хуки и DLL Dr. Joseph M. Newcomer Перевод: Алексей Остапенко Существует большая неразбериха по поводу установки и использования глобальных хуков. ПРИМЕЧАНИЕ Возможно стоит упомянуть, что Камбалы (прим. переводчика: Flounder - псевдоним автора) в целом не одобряют использование крючков (hooks), но такие крючки (хуки) кажутся допустимыми. Заметим, что ни одна из описанных ниже проблем не возникает, если вы просто отлавливаете операции в своем собственном процессе. Они возникают только в том случае, когда вы хотите получать события на системном уровне. Основной проблемой здесь является адресное пространство. Когда глобальная DLL исполняется, она исполняется в контексте того процесса, чье событие перехватывается. Это означает, что адреса, которые видит DLL, даже для своих собственных переменных, являются адресами в контексте целевого процесса. Поскольку это DLL, она имеет отдельную копию своих данных для каждого использующего ее процесса. И это означает, что любые значения, которые вы устанавливаете в глобальных для DLL переменных (таких, как объявленные на уровне файла), являются приватными и не будут наследовать ничего из исходного контекста библиотеки. Они будут инициализироваться заново, т.е., обычно, они будут равны нулю. Недавнее сообщение даже предлагало концепцию сохранения callback-адреса в DLL. Это невозможно. Ну, невозможно не сохранить его, а невозможно его использовать. То, что вы сохранили, - это пачка битов. Даже если вы проследуете изложенной ниже инструкции по созданию разделяемой переменной, видимой во всех экземплярах DLL, набор битов (который вы считает адресом) в действительности является адресом только в контексте процесса, сохранившего этот набор. Для всех остальных процессов это всего лишь набор битов, и если вы попытаетесь использовать его в качестве адреса, вы обратитесь по какому-то адресу в процессе, событие которого было перехвачено, что абсолютно бесполезно. В большинстве случаев это просто приведет к падению приложения. Концепция разделенных адресных пространств трудна для понимания. Позвольте мне продемонстрировать ее на картинке. Здесь мы имеем три процесса. Ваш Процесс показан слева (Your Process). У DLL есть сегменты кода (Code), данных (Data) и разделяемый сегмент (Shared), как его создать мы обсудим позже. Теперь, если перехватывающая DLL вызывается для перехвата события в Процессе A (Process A), она отображается в адресное пространство Процесса A, как указано. Код является разделяемым, поэтому адреса в Процессе A ссылаются на те же страницы памяти, что и адреса в Вашем Процессе. По совпадению страницы памяти оказались отображенными в Процесс A по тем же самым виртуальным адресам, т.е. адресам, которые видит Процесс A. Процесс A также получает свою собственную копию сегмента данных, поэтому все что видит Процесс A в секции "Data", полностью принадлежит ему и не может повлиять на любой другой процесс (или быть измененным любым другим процессом!). Однако, фокус который заставляет все это работать заключается в разделяемом сегменте данных, показанном здесь красным цветом. Страницы, адресуемые Вашим Процессом в точности те же страницы памяти, что и адресуемые в Процессе A. Заметим, что по совпадению эти страницы оказались в адресном пространстве Процесса A в точности на тех же виртуальных адресах, что и в Вашем Процессе. ............ |