Здрасте. Вот флудят, флудят.. конекретный вопрос. Вот топик http://www.wasm.ru/forum/viewtopic.php?id=38895. Задача: Есть функция X, это кэлбэк который известен. Функция Y вызывает функцию X, причём есть множество промежуточных функций. Тоесть Y() -> A() -> B() -> C()... -> X(). Число функций не известно. Также не известен адрес возврата из функции A() в функцию Y(), так как она не экспортируется и поиск сложен. Как получить управление при возврате из функции Y() без патча ? Кто тут может это решить ?
Точки останова (аппаратные) ставить можно? Тогда просто ставим её на первую инструкцию Y и смотрим на первое dword стека - это и есть адрес возврата в A. Остаёться лишь поставить бекпойнт на него. Кстати, ещё если по условию стек изменять можно, то надо подменить адрес возрата на наш и вторая точка останова не потребуется. А в конце нашей процедуры запихиваем в стек старый адрес и делаем ret. А ещё проще - jmp [old_addr].
если прога на ebp фреймах, то что мешает спуститься по ним до нужного уровня? old ebp == [ebp] ret pt == [ebp + 4] а что мешает тогда схватить Y на входе?
Как я понимаю в обработчике одного исключения вполне может вызваться другой - сам процессор против не будет, но в Windows (а быть может и других ОС) если исключение произошло во время обработки прерывания будет BSOD. Если я прав, то можно временно изменить элемент IDT на свой собственный, который будет лишён этого недостатка. А потом восстановить. Если нельзя вызывать прерывания, то и переключения контекста не произойдёт, поэтому другие задачи не пострадают от временного изменения IDT. Поправьте, если я не прав, ибо это лишь мои догадки.
если у нас есть адрес и нам надо узнать в функции Y он или нет, то достаточно просканировать память начиная с Y в поисках первого ret. Это и будет точка выхода из A. Компиляторы ЯВУ как правило генерируют лишь один эпилог, а преждевременные return лишь jmp на эпилог. Однако если функция писалась на асме, то точек выхода может быть несколько и мой подход не сработает.
Некоторая идея. Когда мы попадаем в колбек(если я правильно понял, то колбэк это наша функция), то ничто нам не мешает проанализировать содержимое стека. Мы знаем адрес Y и эмпирически можем прикинуть или даже точно узнать размер этой функции. При анализе стека мы можем сразу откинуть достаточно большую часть значений не подпадающих под критерий возможности вызова из Y(значения меньшие адреса Y и превосходящие наш эмпирический максимум.) Далее надо взять очередное подходящее значение из стека, посмотреть что лежит по-этому адресу, если это call xx, то с большой долей вероятности мы нашли что хотели. Далее наверняка мы легко сможем узнать размер стековых данных Y, ну а далее дело за малым. Чтобы уж наверняка не промахнуться, можно проанализировать и инструкцию по адресу возврата из Y, там должно лежать call Y, а это признак стопудового попадания в бинго. Кстати, можно сразу начинать искать это самое бинго. ^)
Только по-моему этот вопрос не раз обсуждался? Дизассемблировали Y нашли все call сравнили адрес возврата с call+5 и всё. Последовательное сканирование не подойдёт, т.к. функция может быть раскидана по частям. Подменить адрес возврата в стековом фрейме
Booster Как вы узнаете размер функции, которая размазана по всему модулю, как это обычно бывает в системных модулях ? KeSqueer Норм., ида и олли делают фактически тоже самое. Вот как это конкретно решить ?
Clerk Тогда не будем ничего брать эмпирически, хотя в конкретном случае и можно сделать доп. ограничение сверху.
Не понял, что значит "конкретно". Последовательность действий, которые нужно осуществить в колбэке, чтобы управление после выхода из Y попало куда нужно?
Booster Ну вы говорите про какието лимиты и ограничения, код обычно вперемешку идёт с другим кодом, а не просто линейная процедура.
Clerk Лимиты не обязательны и без них данный алгоритм работоспособен. Можно ограничить целым модулем, а можно вообще не ограничивать.