|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Ноя 7, 2004 12:39:44 Добрый день. Помогите, пожалуйста, разрешить следующую проблему: Сейчас по нуждам работы пишу пакер PE-файлов. Возникла потребность реализовать нечто вроде CopyMem-а в армадилле. Поступаю следующим образом: 1) Перед передачей управления на OEP проставляю всей секции кода PAGE_NOACCESS и регистрирую свой обработчик через push offset MyHandler push dword ptr fs:[0000h] mov dword ptr fs:[0000h],esp Далее передаю управление на OEP (А там PAGE_NOACCESS). Вылетает исключение и я попадаю в свой обработчик. Там определяю страницу, на которой произошло исключение (страницу определяю через EIP, на котором оно произошло), ставлю ей атрибут 00000040h и расшифровываю ее в нужное место. Затем делаю mov eax, ExceptionContinueExecution ret Соответственно, на всякий случай, перед этим восстанавливаю значение всех регистров (хотя, как понял, значение имеют только esp и ebp). Смысл проблемы заключается в том, что несколько раз этот трюк срабатывает, т.е. страница выполнится, дальше пытается выполниться либо следующая, либо страница через CALL или Jxx или еще че нить... А вот дальше, при очередном доступе к NOACCESS-овской памяти мой обработчик уже не вызывается и прога просто беззвучно вылетает. Например, тестил пакер на LordPE, так он только окно главное на долю секунды показывает и вылетает без воплей. Другие програмы ведут себя примерно таким же образом. Другие потоки вроде не заводятся. Потом пробовал через тупую подмену обработчика, дающегося при регистрации процесса. Эффект примерно тот же. Через SetUnhandledExceptionFilter вообще маразм какой-то. Что можно попробовать? Если есть такие сорцы или статьи по этому поводу, поделитесь пожалуйста. |
|
|
Дата: Ноя 7, 2004 15:54:58 · Поправил: S_T_A_S_ > перед этим восстанавливаю значение всех регистров А можно про это подробнее, откуда и как они восстанавливаются? IMHO нужно просто вернуть в EAX 0 (ExceptionContinueExecution) и диспетчер сам перезагрузит регистры из структуры CONTEXT. |
|
|
Дата: Ноя 8, 2004 01:33:57 Ну насчет всех я, естественно, загнул=) Из контекста диспетчер их сам восстановит. Имел в виду, что по незнанию восстанавливал все регистры перед ExceptionContinueExecution, хотя значение для нормального дальнейшего функционирования имеют только esp и ebp. Но суть не в этом... Смысл в том, что в некоторых мерзких прогах заводятся свои SEH-фреймы, которые, помимо всего прочего, сами пытаются обработать EXCEPTION_ACCESS_VIOLATION, а обработка его заключается в том, что они просто угробят процесс и не будут думать, что делать, куда передавать управление, т.е. даже не вернут EXCEPTION_CONTINUE_SEARCH. Меня же интересует вопрос, можно ли сделать так, чтобы все исключения, связанные с EXCEPTION_ACCESS_VIOLATION в итоге доходили до моего обработчика, а не обрабатывались где-то в цепочке установленных самой пакуемой прогой SEH-фреймов. Или же какие еще могут быть пути решения этой проблемы? Заводить второй процесс, который будет отлаживать другой как в армадилле я не могу, да и неэстетично это. |
|
|
Дата: Ноя 8, 2004 06:17:15 Меня же интересует вопрос, можно ли сделать так, чтобы все исключения, связанные с EXCEPTION_ACCESS_VIOLATION в итоге доходили до моего обработчика, а не обрабатывались где-то в цепочке установленных самой пакуемой прогой SEH-фреймов. А-то! Можно. Лезешь сам в ту цепочку SEH-ов программы и переориентируешь адреса обработчиков на свой ;) |
|
|
Дата: Ноя 8, 2004 12:03:22 volodya А-то! Можно. Лезешь сам в ту цепочку SEH-ов программы и переориентируешь адреса обработчиков на свой ;) хмм... а в какой момент в неё лезть ? тоесть допустим во время выполнения прога ставит свой обработчик, потом происходит исключение, после которого данный обработчик прибъёт прогу. Получается, что нужно отлавливать установку каждого нового обработчика и перенаправлять его на свой... но вот как такое сделать в протекторе ? (в смысле отлов установки обработчиков) |
|
|
Дата: Ноя 8, 2004 13:44:40 · Поправил: MoonShiner volodya, именно в том, что сказал Mario555 и заключается проблема. Я могу отлавливать создание новых фреймов и перенаправлять их на свой только в момент выполнения моего обработчика. Но до моего дело в определенный момент просто не дойдет, если на очередной расшифрованной странице прога установит свой SEH-фрейм, который при последующем EXCEPTION_ACCESS_VIOLATION, связанным с переходом на нерасшифрованную и NOACCESS-овскую страницу, просто молча пришибет прогу, не пытаясь вернуть EXCEPTION_CONTINUE_SEARCH... |
|
|
Дата: Ноя 8, 2004 14:27:01 ..Вот поэтому в XP+ и появился VEH.. Может быть пропатчить ExecuteHandler2 ? Его адрес можно получить так - вызвать exeption когда установлен только свой SEH и посмотреть, что на стеке. |
|
|
Дата: Ноя 8, 2004 15:15:02 Mario555 Решить проблему с установкой обработчика можно. Например, отлавливая обращения к FS:0 с помощью DR-регистров. PAGE_NOACCESS, увы, не подойдет - VirtualProtect на FS:0 тупо не сработает, это я проверял. Мелкие подводные камни (вроде необходимости отслеживать создание всех потоков) тоже можно (и нужно) учесть. Но, как я уже где-то писал, есть гораздо бОльшая проблема. При обращении к блоку памяти с атрибутом PAGE_NOACCESS из ring0, т.е. из большинства API-функций (например, ReadProcessMemory, ReadFile, и т.д.) ring3-обработчик вызван не будет. А API-функция сработает не так, как должна была сработать в нормальных условиях. После чего на нормальную работу программы можно даже не надеяться. У меня в такой ситуации даже такой простой подопытный кролик, как calc.exe, отказывался запускаться - как выяснилось, RegisterClassEx вызывает с помощью int 2e недокументированную функцию, которая пытается читать память процесса, к которой я ранее запретил доступ с помощью PAGE_NOACCESS, после чего RegisterClassEx возвращает ошибку, окно не создается, процесс завершается. |
|
|
Дата: Ноя 8, 2004 23:34:06 Хмм... А чем же тогда можно объяснить достаточно устойчивое функционирование армадиллы? Может быть (и скорее всего:) я не догоняю, но чем это можно объяснить? |
|
|
Дата: Ноя 8, 2004 23:41:37 Потому как в Армадилле есть поток-отладчик и отладочные сообщения передаются ему. |
|
|
Дата: Ноя 9, 2004 12:13:29 volodya но ведь по словам RobinFood: RegisterClassEx вызывает с помощью int 2e недокументированную функцию, которая пытается читать память процесса, к которой я ранее запретил доступ с помощью PAGE_NOACCESS - арма ставит BreakOnAccess на секцию кода... её отладчик не сможет поймать обращение к памяти процесса из ринг0... но ведь почему-то она работает. Например, отлавливая обращения к FS:0 с помощью DR-регистров. С двумя процессами - это понятно, но вот в условиях одного процесса ??? |
|
|
Дата: Ноя 9, 2004 18:37:41 Вы создаете проблемы там, где их, в принципе, нет. В случае процесса-отладчика и отлаживаемого процесса имеет место быть следующая картина (положим, оба процесса в юзер-моде): исключение в кольце-3 -> вектор в IDT (кольцо-0) -> LPC сообщение, отправляемое на порт процесса из кольца-0 в кольцо-3 В случае отладчика "отправляемое на порт процесса" подменяется на фразу "отправляемое на порт отладчика". Т.е. о возникновении исключительных ситуаций первым узнает отладчик. А уж потом решает - либо спустить исключение программе, либо обработать самому. В случае MoonShiner ему охота все делать самому. Что ж. Достойная проблема. В этом случае, очевидно, все сообщения отправляются уже не отладчику (его нет!), а самому процессу. Т.е., в конечном итоге, управление передается на SEH-кадр. Вывод: перехватывать SEH на себя. Т.е. все адреса в цепочке SEH должны вести в ТВОЙ код, где ты обрабатываешь одно-единственное исключение - PAGE_NOACCESS. При этом, надо убедиться, что исключение действительно вызвано тобой, а не кем-то другим. Словом, работайте, господа... |
|
|
Дата: Ноя 9, 2004 19:43:04 Mario555 Получается, что нужно отлавливать установку каждого нового обработчика и перенаправлять его на свой... но вот как такое сделать в протекторе ? (в смысле отлов установки обработчиков) намного проще пропачить KiUserExceptionDispatcher. там есть call rel32. впатчиваешь rel32 на себя, потом jmp на старый rel32 - всегда будешь обрабатывать ексепшен первым. RobinFood RegisterClassEx вызывает с помощью int 2e недокументированную функцию, которая пытается читать память процесса речь идет о том, что ринг0 лезет к секции данных, или к секции кода? если ограничиться установкой PAGE_NOACCESS только на секцию кода, это поможет? Хотя тут тоже есть неприятные функции (типа CreateThread). Вполне возможно, что в них тоже возможна ситуация обращения из ринг0 в ринг3 к странице с PAGE_NOACCESS. Ты не проверял? |
|
|
Дата: Ноя 9, 2004 21:25:21 · Поправил: S_T_A_S_ Что-то всё сложно так, мне до DR регистров далеко ещё, поэтому я просто менял эти 5 байтов из ntdll.dll на call my_handler. SEH цепочка при этом остаётся неизменной, а my_handler смотрит, нужно ли вызывать обработчики из неё или нет. Возможно у этого способа есть куча недостатков, я так делал тока под XP SP2, под другими ОС адреса ессно другие (если они вообще есть =) 7C9037BA 8B4D 18 mov ecx, [dword ss:ebp+18] 7C9037BD FFD1 call near ecx ЗЫ Долго я думаю, Max уже про подобное написал. |
|
|
Дата: Ноя 9, 2004 22:01:12 · Поправил: MoonShiner volodya, я о том и говорил... Но тогда возникает вопрос, как отлавливать создание новых фреймов. Но, думаю, эта проблема разрешится, так как защищать нужно конкретный софт, который разрабатывает моя же контора (т.е. сорцы все есть:) Просто хотелось написать автоматическую тулзу, которая сама и на любом скомпиленном файле все это делала. Max, S_T_A_S_, мне нужно, чтобы работало и в 9х... А KiUserExceptionDispatcher, как мне казалось, в 9х отсутствует:) Но для 2к пропатчу... А вот альтернативная замена этого действия для 9х есть? С тредами проблем пока не возникнет, приложения пока однопоточные. Это дальше придется думать с потоками. В общем, многое прояснилось, появились кое-какие идейки. Mario555, Max, S_T_A_S_, volodya, огромное спасибо вам за ответы. ЗЫ Тема не закрыта, дополнительным идеям буду очень рад. |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.088 |