Задача в общих чертах такая — существует некий процесс который подгружает мою dll, необходимо перехватить обращения только этого процесса (и всех его загруженных модулей, кроме моего) к определённым файлам, чтобы "на лету" подменять содержимое читаемых процессом данных.
Изучая гугл пришёл к выводу, что писАть свой драйвер-фильтр будет "немножко" overkill, и остановился на методе модификации IAT. Возможно это не самый правильный способ, просто я пока не нашёл ещё других.
За основу был взят этот алгоритм "прочёсывания" всех IAT процесса и его модулей.
Теперь, собственно, проблема.
После получения структуры IMAGE_THUNK_DATA у меня все параметры имеют одинаковое значение, например:
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((PBYTE) hMods[i] + pImportDesc->FirstThunk);
pThunk.u1 =
ForwarderString 2147483665 unsigned long
Function 2147483665 unsigned long
Ordinal 2147483665 unsigned long
AddressOfData 2147483665 unsigned long
Соответственно при попытке прочитать структуру IMAGE_IMPORT_BY_NAME:
В import лежит мусор.
Почти та же петрушка, если получать IMAGE_THUNK_DATA не по смещению FirstThunk, а по OriginalFirstThunk. Вся разница лишь в том, что значения смещений FirstThunk и OriginalFirstThunk разные и по итогу в import лежит немного другой мусор.
На SO есть похожий неудачник, но он более счастливый — он сам контролирует запускаемый процесс и мусор у него, потому, что процесс запущен с флагом CREATE_SUSPENDED, что в моём случае вообще безынтересно.
Я, конечно, попробовал — в моём случае после некоего таймаута, после загрузки моей dll, мусор лежит уже по смещению pImportDesc->FirstThunk, а попытка получить IMAGE_IMPORT_BY_NAME по смещению из OriginalFirstThunk приводит к результатам, что были ранее.
Небольшое уточнение — я всё это пытаюсь запустить из под Visual Studio 2008 на Windows 7 SP1 x64 в режиме Win32.
Неделя копания в гугле, компиляция кучи примеров не принесли положительных результатов — в результате у всех примеров лежит мусор в структуре IMAGE_IMPORT_BY_NAME.
Помогите, пожалуйста с советом — куда копать?
Актуальна ли на существующий день методология модификации IAT?
Есть ли какие-либо современные варианты перехвата WinAPI?
PS Все умные статьи, на подобие этой я уже перечитал. Возможно не всё понял, но материал достаточно обширен и времени погружаться в ассемблер нету. Может быть кто-то уже реализовывал подобные задачи и хотя бы посоветует какую статью изучить внимательнее, чтобы добиться положительного результата.
Как-то уже давно делал подобное.
Как тут уже советовали, есть МС детурс, но я тогда о нем не знал, поэтому делал на коленке сам. К слову, я потом глянул этот детурс, но так как нужда уже ушла, то не напрягался с изучением, и ниасилил
У меня задача была — пропатчить чужой экзешник. Я запускал exe, который нужно было пропатчить, в "замороженном" состоянии, инжектил в него dll, в которой были хакнутые версии функций, запускал процедуру хака, и запускал замороженный процесс.
Не совсем понял, что ты там делал (давно такими вещами уже не баловался), но вроде как-то сложно. Я просто дизасмил пролог функции из kernel32, копировал начальные инструкции, прописывал туда переход на свою функцию, делал там что надо, потом jump на скопированный код, после которого прописан jump на продолжение функции в kernel32. Вроде как-то так, но уже точно не помню.
PS тоже перехватывал файловые функции, расширял набор поддерживаемых форматов файлов для чужой прилады — на лету преобразовывал формат в понятный программе.
Спасибо.
Забыл уточнить — я в курсе про детоурс, он платный и в моём случае это более чем из пушки по воробьям.
Ещё есть опенсорс аналог EasyHook, который отложен на свосем чёрный день.
Понимаете, проблема всех этих обёрток — скрыть реализацию и предоставить универсальный доступ ко всем возможностям обёртки.
Мне не нужна вся их мощь. Мне нужна простая подмена адреса в таблице. Это не rocket-science.
Беда в том, что по всему интернету моя задача представляется в совокупности с другой — инжектировать библиотеку в "чужой" процесс. И последней задаче уделено гораздо бОльшее внимание, а на получение IAT — две строчки считается явным перебором. И самое странное — похоже, что у них то всё работает или работало ранее.
Здравствуйте, Marty, Вы писали:
M>Не совсем понял, что ты там делал (давно такими вещами уже не баловался), но вроде как-то сложно. Я просто дизасмил пролог функции из kernel32, копировал начальные инструкции, прописывал туда переход на свою функцию, делал там что надо, потом jump на скопированный код, после которого прописан jump на продолжение функции в kernel32. Вроде как-то так, но уже точно не помню.
это известный и не совсем чистый путь
у меня ситуация с инжектом попроще — нет нужды в перетирании первых пяти байтов на джамп в свой метод, ибо у меня есть легальная возможность, появившись в потрохах процесса изменить его таблицу импорта только там где надо мне, вроде как
M>PS тоже перехватывал файловые функции, расширял набор поддерживаемых форматов файлов для чужой прилады — на лету преобразовывал формат в понятный программе.
M>Во первых, см. сюда
Здравствуйте, Marty, Вы писали:
M>Здравствуйте, Marty, Вы писали:
M>А, в той же ветке первое сообщение — с примером — http://www.rsdn.ru/forum/src/3571389.1
Любопытно, конечно.
Жаль, что за скобками осталась реализация installPatch, я так полагаю там происходит затирание первых байтов перехватываемого метода джампом на хакнутый метод.
К сожалению никто не гарантирует, что в будущем начало winapi-методов не изменится. Хочется так же понять — существует ли более универсальное решение, как например модификация IAT, или это такой же толщины костыль?
A>Любопытно, конечно. A>Жаль, что за скобками осталась реализация installPatch, я так полагаю там происходит затирание первых байтов перехватываемого метода джампом на хакнутый метод. A>К сожалению никто не гарантирует, что в будущем начало winapi-методов не изменится. Хочется так же понять — существует ли более универсальное решение, как например модификация IAT, или это такой же толщины костыль?
Я даже больше скажу — эти недохуки, рассчитывающие на определенный код пролога функции в N байтов или же патчащие/анпатчащие ее в рантайме дико мешают жить остальным, которые юзают detour-style хуки
Как много веселых ребят, и все делают велосипед...
Здравствуйте, Adnako, Вы писали:
A>Любопытно, конечно. A>Жаль, что за скобками осталась реализация installPatch, я так полагаю там происходит затирание первых байтов перехватываемого метода джампом на хакнутый метод.
таки внимательно смотрел? Есть там все.
A>К сожалению никто не гарантирует, что в будущем начало winapi-методов не изменится. Хочется так же понять — существует ли более универсальное решение, как например модификация IAT, или это такой же толщины костыль?
Изменится, и что? Все точно так же будет работать. Начало функции копируется не абы как, копируются несколько первых инструкций так, чтобы на их место влез переход на патченую версию
Здравствуйте, ononim, Вы писали:
O>Я даже больше скажу — эти недохуки, рассчитывающие на определенный код пролога функции в N байтов или же патчащие/анпатчащие ее в рантайме дико мешают жить остальным, которые юзают detour-style хуки
Недохуки? А там зря что-ли дизассемблер прикручен, который декодирует инструкции и выбирает их количество так, чтобы влез патч?
На W2k, WinXP, Win7 все работало, за линейку 9x не помню, но думаю, что там все тоже ок.
O>Я даже больше скажу — эти недохуки, рассчитывающие на определенный код пролога функции в N байтов или же патчащие/анпатчащие ее в рантайме дико мешают жить остальным, которые юзают detour-style хуки
А что за детур-стайл ? Он что, по другому работает?
M>Недохуки? А там зря что-ли дизассемблер прикручен, который декодирует инструкции и выбирает их количество так, чтобы влез патч? M>На W2k, WinXP, Win7 все работало, за линейку 9x не помню, но думаю, что там все тоже ок.
А зачем тогда у вас в коде асм какой-то?
В нормальных хуках никакие прологи хардкодить не надо. А надо
1) Как вы правильно сделали — декодировать N инструкций, длины которых хватает чтобы всунуть jmp
2) _Переместить_ декодированные инструкции в выделенный участок, корректируя адреса относительных джампов если таковые там попадаются и дополнить их там jmp'ом на следующую инструкцию оригинальной функции
3) Влепить в начало хукаемой функции jmp на свой враппер.
То есть кроме jmp'а никакого асма не требуется вообще, да и тот джамп — весьма условен
В х64 кстати все тоже самое за исключением того что выделенный участок для оригинальных инструкции желательно выделять в пределах +-2GB от хукаемой функции и помимо оригинальных релоцированных инструкций всунуть туда промежуточный полноценный джамп на свой враппер — это чтоб патчить только 5байт пролога хукаемой функции 'обычным' 5байтным джампом. А еще добавлю еще лично мой ворэраунд для некоторых некошерных хуков — декодируем и переносим по возможности 14 байт пролога, а джамп лепим 5байтный. Потому что примерно половина народу которая делает хуки пользуются 5байтными джампами по возможности, а другая половина — не заморачиваются и патчат 14байт оригинального кода. А мне приходилось дружить и с теми, и с другими и еще со многими такими что нет слов, а только маты Доходило до блокировки особо упоротых товарищей от загрузки совместно с нашим продуктом. К таким относятся к примеру любители снимать свои хуки во время жизни процесса, 'восстанавливая' пролог функции.
Вобщем сформулирую золотое правило хукинга: если ты хукаешь какую то функцию, подумай о том что получится если ктонить другой тоже похукает ее, либо до тебя либо после. Хотябы таким же способом как и ты хукаешь (об остальных способах ты узнаешь из крэшдампов )
Как много веселых ребят, и все делают велосипед...
омб! я как раз хочу избежать весёлых хаков с перетиранием пролога перехватываемой функции в чужой длл
M>Изменится, и что? Все точно так же будет работать. Начало функции копируется не абы как, копируются несколько первых инструкций так, чтобы на их место влез переход на патченую версию
я читал теорию
пока что компиляторы компилят системные либы так, что впихать свои 5 копеек можно, но это пока
на другой чаше весов — модификация IAT где, по идее, проблема решается элегантней и на более высоком уровне абстракций
поэтому мне бы хотелось услышать советы _опытных_ товарищей, которые боролись с IAT и имеют, что сказать про неё
в любом случае — спасибо за комментарии
Добрался до названий импортируемых методов.
Оказывается не все примеры в интернете знакомы с флагом IMAGE_ORDINAL_FLAG32.
Через что и не получалось выудить IMAGE_IMPORT_BY_NAME.
Процесс идёт, ура!
Палевный нубский метод, ибо IAT обычно в кодосекции расположена. Ну да ладно. Есть готовый функционал — провайдер верификации(верифер), AVRF. Передаёте ему структуру описывающую апи и он пропатчит всё сам.