![]() |
Событие завершения процесса
Есть произвольный код в адресном пространстве некоторого процесса. Этот код должен отлавливать событие завершения этого процесса. Что-то типа сообщения DLL_PROCESS_DETACH, но это сообщение приходит динамическеим библиотекам, а у меня произвольный код. Можно, конечно, перехватывать функцию ExitProcess, ExitThread, но не хочу гемора с перехватом...
|
а вопрос?
|
Код сисдит в апликухе и должен сохранить логи по завершении процесса.
|
Теоретически можно попробовать следующее.
При старте процесса в стеке сохраняется адрес возврата именно по этому и можно завершать программу по команте ret (если в стек ничего не добавлялось) При нормально анализе можно в стеке найти этот адрес и подменить на адрес своего обработчика. Геморно но всёже как один из вариантов ну и + желательно ExitProcess перехватить и тоже пустить на свой обработчик |
если код действительно в том же процессе, то только сообщение обрабатывать и хукать ничего не надо. (wm_terminate или что то в этом роде), но это только если приложение win а не дос.
|
2 Ryu млин, а если приложения WIN но без оконное? ТОгда регистрировать обработчик сообщений нужно. А если консольное, то вообще тогда нужно через SetConsoleCtrlhandler()
так что отлавливать сообщения - многое нужно учесть. При том, что как выше сказано код в произвольном процессе и следовательно он туда както внедряется и должен быть по крайней мере независимым от своего расположения в памяти. P.S. Ну если код ведет логи, то пусть сразу их и пишет и делает чтото типа flush чтобы сразу скинуть на винт, а там при заврешении процесса - автоматом все дискрипторы загроются |
Цитата:
(если там конечно не динамич импорт) |
gevara
Тут только перехватывать ZwExitProcess и ZwExitThread. P.S. Фишка со стеком, как и с оконными сообщениями не прокатит, если приложение само вызывает ExitProcess. |
2 SlyBit Блин чем дальше в лес, тем больше дров, которые человек наломает.
Такими темпами можно будет уже говорить о методах сплайсенга функций а там уже и до Native Api дойдем со стороны ядра. P.S. 2 gevara cразу скажи в каком приложении ты это собираешься делать? или в любых. А то мы можем так далеко зайти в обсуждении, а на самом деле всё будет просто. |
приложение оконное.
- адрес возврата подменить не получится - что если приложение многопоточное? перехватывать CreateThread проще перехватить ExitThread - Вообще сообщение DLL_PROCESS_DETACH приходит либам в том случае, когда последний поток завершается вызовом ExitThread, то есть перехват оконных сообщений скорее всего всё-таки возможен, но я почему-то не вижу сообщения WM_TERMINATE... такого сообщения в SDK нет вообще. - есть WM_CLOSE, WM_DESTROY, WM_QUIT, но стоит ли надеяться на эти сообщения? множество апликух не юзают их вообще. апликуха может иметь несколько окон и при закрытии одного из них апликуха продолжает работать (приходит сообщение WM_CLOSE) - есть вот какая тема - добавить свою запись в двусвязный список LDR_MODULE (или как его там...), указав адрес обработчика, которому и будут приходить сообщения DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH и прочие... |
Цитата:
|
вот такие функции есть:
ntdll.ZwTerminateProcess ntdll.ZwTerminateThread |
Цитата:
ntdll.ZwTerminateProcess ntdll.ZwTerminateThread Цитата:
Если хуки тебя не в какую не устраивают, то можно вместо добавления новой структуры в двусвязный список загруженных библиотек (довольно палевно, т.к. такие программы как Process Explorer увидят странную библиотеку), изменить базу существующей библиотеку на свой обработчик. При вызове твоего обработчика проверяй 2-ой параметр Reason на равенство коду DLL_PROCESS_DETACH, пиши там свои логи и затем вызывай оригинальную точку входа библиотеки с такими же параметрами. Подменяй точку входа у невыгружаемых библиотеках, таких как user32.dll, kernel32.dll, ntdll.dll. Теперь постараюсь объяснить как выйти на этот список и что нужно менять. Для начала нужно получить адрес структуры PEB процесса. Указатель лежит по адресу fs:[30h], либо можно взять его из структуры PROCESS_BASIC_INFORMATION по смещению +4 байта. Указатель на саму струкуру PROCESS_BASIC_INFORMATION получаешь вызвав функцию NtQueryInformationProcess со вторым параметром равным 0 (ProcessBasicInformation). Указатель на PEB есть. По смещению 0xC в PEB находится указатель на структуру PPEB_LDR_DATA. В этой структуре находятся 3 указателя на точки входа двусвязных списков, содержащих информацию о библиотеках на стадии загрузки, уже загруженных в память и на стадии инициализации. Нас интересует второй указатель. Теперь нам нужно обойти список LDR_DATA_TABLE_ENTRY и сравнить имя BaseDllName с "ntdll.dll" например. Как находим, заменяем EntryPoint на наш обработчик. Это все в теории, если что-то не так - поправьте. NTDLL.h |
Что толку от перехвата таблицы импорта, если не знаешь какой именнго модуль завершит последний поток? вообще прога может завершить своё выполнение по рету и ExitProcess будет вызван из kernel32 - тут только сплайсинг. а вариант с изменением адреса входа действительно реальный, хотя, возможно, и не самый лучший. ведь адрес точки входа будет лежать за границами модуля, что может вызвать подозрения...
|
да, я про таблицу экспорта kernel32 и ntdll конечно...какая нафиг импорта ;) мне кажется вариант со сплайзингом такой же палевный как и подмена адреса точки входа либы.
Цитата:
|
KiSystemFastRet+ZwTerminateProcess.
|
Цитата:
|
А вот и пример подмены точки входа библиотеки подоспел (описание несколькими постами выше):
Код:
#include <windows.h> |
SlyBit, пасиб, конечно. но это вобщем-то понятно. у меня ситуация несколько другая - вот я и думаю что сделать лучше: перехват PEB или сплайсинг ExitThread или ExitProcess. Вообще-то мой код и так хучит кое-какие функции. В частности имеет доступ к оконным сообщениям. так что идеальный вариант - отслеживать сообщения (есали такие есть) о закрытии всех окон или что-то типа этого...
|
gevara
Я думаю, что оконные сообщения отпадают по как минимум 2м причинам: не отслеживается самостоятельный вызов ExitProcess программой, не всегда они "правильно" обрабатываются программой. Пример Outpost, при посылке его главному окну сообщения WM_CLOSE (щелчек на крестик в правом верхнем углу), оно просто сворачивается, вместо того чтобы закрыться. На сообщения WM_DESTROY и WM_QUIT вообще нет никакой реакции. Калькулятор же спокойно закрывается получив WM_CLOSE. Выбор между модификацией PEB и сплайзингом ExitProcess и ExitThread. В первом случае все просто. Во втором нужно считать количество потоков, приложение закроется как только закроют его последний поток. Для этого нужно будет перехватывать CreateThread и икрементировать счетчик кол-ва потоков и декрементировать при выхове ExitThread, либо подсчитывать количество потоков перед вызовом ExitThread. |
когда-то писал программку, в которой надо было выполнить код, при завершении собственно этой программы. помогла кртшная функция _onexit(); она ставит функции на выполнение, при завершении процесса.
http://msdn.microsoft.com/en-us/libr...08(VS.71).aspx |
Цитата:
1) при перехвате ExitProcess считать потоки совершенно не обязательно 2) при перехвате ExitThread их считать тоже не обязательно. посмотри что делает система: Код:
7C80CCA9 > 6A 14 PUSH 14 |
Я совсем не огорчен, это были только мои предположения ;) Выходит в перехвате ExitThread нет необходимости. Однако приложение может поубивать свои потоки функцией TerminateThread или завершиться с помощью TerminateProcess.
|
| Время: 22:42 |