Пытаюсь ставить hook на winapi через import address table. Написал код, протестировал на перехвате CreateFileA в "FAR manager", работает нормально, то есть в алгоритме поиска нужного адреса в IAT проблем быть не должно. Но когда дело дошло до перехвата функций в целевом приложении, получаю access violation при изменении IAT. Попытка изменения режима доступа к памяти ни к чему не приводит. Проверяю возможность записи с помощью IsBadWritePtr: Код (Text): IsBadWritePtr((LPVOID)thunkIat->u1.AddressOfData, sizeof(LPVOID)) Если запись невозможна, то получаю текущие права доступа к памяти Код (Text): VirtualQuery((LPVOID)thunkIat->u1.AddressOfData, &mbiImportPage, sizeof(MEMORY_BASIC_INFORMATION)); dwNewProtectionFlags = mbiImportPage.Protect; dwNewProtectionFlags &= ~(PAGE_READONLY | PAGE_EXECUTE_READ | PAGE_EXECUTE); dwNewProtectionFlags |= (PAGE_EXECUTE_READWRITE); затем меняю их через VirtualProtect, вызываю дважды, чтобы узнать какие права были применены после первого вызова Код (Text): dwResult = VirtualProtect((LPVOID)thunkIat->u1.AddressOfData, sizeof(LPVOID), dwNewProtectionFlags, &dwOldProtectionFlags); dwResult = VirtualProtect((LPVOID)thunkIat->u1.AddressOfData, sizeof(LPVOID), dwNewProtectionFlags, &dwOldProtectionFlags); Второй вызов VirtualProtect ставит dwOldProtectionFlags в PAGE_EXECUTE_WRITECOPY вместо PAGE_EXECUTE_READWRITE. После изменения прав доступа к памяти, вызов IsBadWritePtr возвращает FALSE, как будто я могу писать по заданному адресу. Но когда я пытаюсь изменить IAT, все равно получаю access violation. Экспериментировал с вызовом VirtualProtect: - если пытаюсь выставить режим PAGE_READWRITE, то получаю access violation при вызове VirtualProtect - использовал (mbiImportPage.BaseAddress, mbiImportPage.RegionSize, ...) вместо ((LPVOID)thunkIat->u1.AddressOfData, sizeof(LPVOID), ...), результат тот же Не могу найти полезную информацию о PAGE_EXECUTE_WRITECOPY и узнать чем может быть вызвана установка этого режима вместо PAGE_EXECUTE_READWRITE Возможно кто-нибудь в курсе чем может быть вызвано access violation ...
эм... а это точно VA, а не RVA? я просто не разбирался в коде, но на глаз ошибка может быть тут. П.С.: посмотри в ольке, что конкретно передается в виртуалпротект, что находится по переданному адресу, что именно возвращает виртуалпротект и с каким кодом ошибки
точно, я тестировал на CreateFileA, это указатель на функцию в загруженной DLL. Также проверял в отладчике - адрес находится нормально и соответствует тому, что возвращает GetProcAddress если пытаться поставить PAGE_READWRITE, выпадает access violation, если PAGE_EXECUTE_READWRITE, то режим доступа меняется без ошибок, но выставляется PAGE_EXECUTE_WRITECOPY. странно также что IsBadWritePtr возвращает FALSE ... проблема именно с доступом к памяти, но я не разбираюсь во всех тонкостях =\
а ты память точно в нужном приложении меняешь, а не в своем? адреса точно там находишь, а не в своем? не совсем понятна твоя методика это не показатель - условия тестирования разных функций в разных процессах могут отличаться в корне
Я подключил нужную DLL к своему процессу и попытался модифицировать ее таблицу импорта - результат тот же, что и при внедрении в использующий ее процесс, и теперь я имею возможность отлаживать код в студии - все адреса правильные. Имею ввиду, что я уверен в том, что меняю именно то что нужно, проблема в доступе к памяти.
Да, у меня при тестировании также не было проблем, ситуация характерна для конкретной DLL независимо от приложения которое ее использует ... Сейчас начал постепенно разбираться - если изменять режим доступа для всей таблицы IAT, то изменение адреса становится возможным. Тем не менее, если кто в курсе подобного вопроса, поделитесь деталями плиз =)
WRITECOPY означает, что вместо общей копии процессу выдается частная копия страницы. Короче говоря есть один набор физических страниц, где лежат код и данные загруженной длл. Они проецируются во все процессы только на чтение и исполнение. Если хотят проецировать на запись, то процессу выделяют свою личную копию страницы, где можно вносить изменения не трогая общую копию. Это есть в руссиновиче. MSoft, в памяти это поле уже не AddressOfData, а называется Function и содержит точку входа функции. Автор просто выбрал неверное имя из union'а. DM Вообще странно. Покажи код
DM >dwNewProtectionFlags &= ~(PAGE_READONLY | PAGE_EXECUTE_READ | PAGE_EXECUTE); >dwNewProtectionFlags |= (PAGE_EXECUTE_READWRITE); Мы бы так не стали делать. Взгляни на значения этих констант – их нижний байт не есть какой-нибудь сорт маски же. Ты контролируешь значение "dwResult" после вызова VirtualProtect с такими атрибутами защиты? Скорее всего функция изначально возвращает FALSE в твоём случае. Хотя, опять-таки, это не объясняет AV при попытке модифицирования IAT. >если пытаюсь выставить режим PAGE_READWRITE, то получаю access violation при вызове VirtualProtect. Очень интересно. По идее такого быть не должно. Можно взглянуть на крэшдамп или хотя бы стек вызовов на момент исключения?
Скорее всего автор имел в виду ERROR_ACCESS_VIOLATION ошибку, возвращаемую функцией. Было бы забавно, если бы вызов валился с реальным исключением.
А-ха. Таки увидели ситуацию, в которой такое может быть: DM вызывает VirtualProtect с защитой PAGE_READWRITE для IAT своего процесса. IAT располагается в начале кодовой секции, на той же странице, что и исполняемый код. VirtualProtect успешно отрабатывает, и сразу после возврата возникает исключение — ведь страница с кодом теперь неисполняемая.
Хм. И правда) А я думал это он ошибку имел в виду. Автор, жадина, код так и не показал, оставляя другим лишь вариант догадываться до подробностей самому Пора написать, что настоятельно рекомендуется приводить исходный код сразу в первом посте, когда пишут тему о том, что не могут разобраться в проблеме.
Я же привел код ... Какой конкретно код нужно выложить ? Скорее всего так и есть, непонятно почему в примере советовали использовать PAGE_READWRITE Как оказалось использовать IsBadWritePtr уже не стоит, т.к. функция давно obsolete и ничего не гарантирует. А VirtualProtect вызывать для всей секции IAT, тогда при втором вызове в dwOldProtectionFlags записывается PAGE_EXECUTE_READWRITE. Все же напишите какой нужен. На мой взгляд проблема в одном только вызове VirtualProtect, остальное неважно скорее всего. PS Не обращайте внимание на &= ~(PAGE_READONLY | PAGE_EXECUTE_READ | PAGE_EXECUTE), переменная здесь обнуляется, я заменил на dwNewProtectionFlags = PAGE_EXECUTE_READWRITE При установке PAGE_EXECUTE_READWRITE функция возвращала TRUE
DM >На мой взгляд проблема в одном только вызове VirtualProtect. Ага. Видим теперь. Всё просто. Собираешься изменить элемент IAT – необходимо изменять протекцию этого элемента IAT. Не протекцию функции, на которую ссылается элемент IAT. Так что действительно – весь код есть, в нужном объёме.