![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
AV при использовании юнита Variants [D7, WinXP]
Сергей М. © (2010-03-09 11:15:00)Столкнулся с неожиданной засадой при использовании юнита Variants.
Целевая задача :
реализовать в D7EE DLL-модуль (использующий юнит Classes и собираемый без использования Run-Time пакетов), загружаемый в адр.пространства создаваемых системой процессов с использованием документированного механизма автозагрузки указанием модуля в списке
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs
Проблема:
при создании и инициализации процессов ряда приложений в ходе инициализации загружаемого в их АП моего DLL-модуля возбуждается AV-исключение с дословным сообщением постоянного содержания в появляющемся диалоговом окне:
Инструкция по адресу 0x7C918FEA обратилась по адресу 0x00000010. Память не может быть "written".
После закрытия диал.окна эти процессы продолжают и инициализацию и успешно стартуют, естественно без моего DLL-модуля в своих АП, поскольку его инициализация привела к отказу по необработанному моим DLL-модулем исключению.
В ходе анализа причин и условий возникающей проблемы выявлены следующие факты:
1. Исключение возбуждается в коде модуля ntdll.dll в теле ф-ции RtlInitializeCriticalSection()
2. Исключение возбуждается как минимум при условии явного (прямым указанием в USES) или неявного (фигурирантом в USES иных юнитов в составе VCL и RTL, например, Classes) использования в проекте моего DLL-модуля юнита Variants
3. Исключение возбуждается только при условии сборки моего DLL-модуля без использования Run-Time пакетов.
4. Инициализация критической секции фигурирует в тексте юнита Variants в секции INITIALIZATION.
Прошу тех, кто возможно вплотную сталкивался с такой проблемой, высказать свои соображения по ней и возможные варианты ее преодоления в упомянутых выше условиях.
Текст проекта DLL-модуля для тестирования:
library TestDll;
uses
Variants;
{$R *.res}
begin
end.
Пример списка приложений, запуск которых приводит к возникновению вышеописанной проблемы:
delphi7.exe
mmc.exe
paint.exe
skype.exe
virtualbox.exe
TeamViewer.exe (TeamViewer4)
Пример списка приложений, запуск которых НЕ приводит к возникновению вышеописанной проблемы:
iexplore.exe
firefox.exe
procexpr.exe
calc.exe
wordpad.exe
excel.exe
notepad.exe
TeamViewer.exe (TeamViewer3)
FAR.exe
Воспроизводима ли проблемная ситуация в других условиях (иная ОС, иная Delphi IDE) ?
xayam (2011-05-04 20:54:00) [1]
> delphimaster.net/view/1-1179920037
> Еще одно, к сожалению, обрезалось.
Исправил. 13 ответов, как и в самом архиве...
Leonid Troyanovsky (2010-03-11 18:18:00) [2]
> Leonid Troyanovsky © (11.03.10 18:05) [36]
> Т.е., если после обнаружение стартовавшего потока послать
В смысле: при своевременном обнаружении.
Sorry.
--
Regards, LVT.
Leonid Troyanovsky (2010-03-11 18:05:00) [3]
> Сергей М. © (11.03.10 15:21) [35]
> получении управления в одном из потоков (как правило - в
> основном) процесса "нужного" приложения.
Года 3 назад здесь пару раз обсуждался вопрос о получении управления
над первичным потоком до входа в WinMain.
Вот одно из обсуждений:
http://delphimaster.net/view/1-1179920037
Еще одно, к сожалению, обрезалось.
Если я ничего не запамятовал, то после полной инициализации процесса
его первичный поток попадает в alertаble state, в котором опустошает
очередь APC перед входом в WinMain.
Т.е., если после обнаружение стартовавшего потока послать ему
QueueUserAPC, то она выполнится первичным потоком в нужное время.
Вот простой пример:
// Включить звуковую схему. Not Windows.MessageBeep!
procedure TForm1.Button1Click(Sender: TObject);
var
pi: TProcessInformation;
si: TStartupInfo;
p : Pointer;
d:DWord;
begin
Fillchar(si, SizeOf(si),0);
CreateProcess(
nil,
'notepad.exe',
nil,
nil,
False,
CREATE_SUSPENDED,
nil,
nil,
si,
pi
);
p := GetProcAddress( GetModuleHandle( 'user32.dll' ), 'MessageBeep');
QueueUserAPC(p, pi.hThread, MB_OK);
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
end;
Насчет AppInit_Dlls, т.е. посылки APC в момент инициализации user32.dll
ничего не скажу, не знаю (да, и пробовать не хочу :)
Но, IMHO, уважаемая Riply рассказывала об успешных опытах в
том числе и с оным.
--
Regards, LVT.
Сергей М. (2010-03-11 15:21:00) [4]
> Leonid Troyanovsky © (11.03.10 14:44) [34]
> делай некие операции только в нужных потоках
Ты, видимо, меня не понял.
"Нужный" поток обнаруживается по факту обнаружения "нужного" процесса. Согласен ?
Документированных методологий обнаружения старта "нужного" процесса (с целью инжекта в его АП моего модуля и соотв.получения управления в нужном мне его потоке) всего две:
- периодическое сканирование снэпшотов с целью обнаружения "нужного" процесса и и т.д.;
- использование в kernel-mode-драйвере соответствующей PsNotify-функции, извещающей о рождении "нужного" процесса;
Обе методологии мне хорошо известны и вопрос по ним не стоит.
Вопрос же, как понимаешь, стоит о максимально возможно раннемполучении управления в одном из потоков (как правило - в основном) процесса "нужного" приложения.
AppInit_Dlls-метод для этого подходит как нельзя лучше, но .. вот с таким вот геморроем в вышеозначенном случае) ..
Leonid Troyanovsky (2010-03-11 14:44:00) [5]
> Сергей М. © (11.03.10 14:22) [33]
> Ибо на момент когда мне становится известен ThreadId нужного
> мне потока, он уже за время с начала своего старта успел
> выполнить некие операции, ДО выполнения которых мне собственно
> и требовалось получить управление.
Ну, и делай некие операции только в нужных потоках.
Для "закрепления" длл - LoadLibrary (нек. проблемы с LoadLibrary
из хуковой процедуры были лишь в 95).
В примере это есть.
По окончанию же обработки - сними глобальный хук.
И/или, можно разбить на 2 библиотеки: одна небольшая, хуковая,
загружена постоянно, а вторая рабочая - для избранных.
--
Regards, LVT.
Сергей М. (2010-03-11 14:22:00) [6]
> Leonid Troyanovsky © (11.03.10 12:22) [32]
> Если интересуют конкретные процессы/потоки, то именно
> за них и стоит цепляться.
Это да.
Но если требуется получить в своем хук-модуле управление в целевом потоке целевого процесса во время самого первоговызова им GetMessage, то эта метода не годится.
Ибо на момент когда мне становится известен ThreadId нужного мне потока, он уже за время с начала своего старта успел выполнить некие операции, ДО выполнения которых мне собственно и требовалось получить управление.
Leonid Troyanovsky (2010-03-11 12:22:00) [7]
> Сергей М. © (11.03.10 10:10) [31]
> Глоб.хуки в триггерном режиме (hInst=HookLib.dll, ThreadId=0)
> всем хороши, кроме одного - экземпляры HookLib торчат "мертвым
> грузом" в АП не интересующих меня процессов, и выгрузить
> это "мертвый груз" еще на этапе инициализации HookLib ,
> вернув системе из DllMain ненулевой результат, насколько
> мне известно, не представляется возможным.
Если интересуют конкретные процессы/потоки, то именно
за них и стоит цепляться.
Мне нравится комбинация WH_GETMESSAGE & PostThreadMessage.
Иногда достаточно установить хук, расчитанный на обработку
единственного сообщения, после чего он снимается.
Я как-то приводил тут пример.
http://www.delphimaster.ru/cgi-bin/forum.pl?id=1259064819&n=5&p=2
--
Regards, LVT.
Сергей М. (2010-03-11 10:10:00) [8]
> Leonid Troyanovsky © (10.03.10 17:45) [30]
Не возражаю.
Глоб.хуки в триггерном режиме (hInst=HookLib.dll, ThreadId=0) всем хороши, кроме одного - экземпляры HookLib торчат "мертвым грузом" в АП не интересующих меня процессов, и выгрузить это "мертвый груз" еще на этапе инициализации HookLib , вернув системе из DllMain ненулевой результат, насколько мне известно, не представляется возможным.
Или я ошибаюсь ?
Leonid Troyanovsky (2010-03-10 17:45:00) [9]
> Сергей М. © (10.03.10 16:23) [29]
> Хуки - это, конечно, просто и универсально, но и недостатки
> у этого решения нельзя не учитывать.
Недостатков у AppInit_Dlls видится гораздо больше :)
--
Regards, LVT.
Сергей М. (2010-03-10 16:23:00) [10]
> Игорь Шевченко © (10.03.10 14:47) [27]
> Проще отказаться от вариантов в подобной DLL
Ну почему же ?
Выковырять загрузку oleaut32 и ole32 из дельфийских юнитов не так уж сложно, хоть и муторно.
Конечно после этого об "универсальности" решения можно забыть, но .. было бы ради чего)
Вариантов-то документированного инжекта кроме AppInit_Dlls с гулькин нос - hooks да remote threads.
Хуки - это, конечно, просто и универсально, но и недостатки у этого решения нельзя не учитывать.
Удал.треды - это нерадужная перспектива борьбы с софтом антивирусного фронта, да и не триггерный это метод, что ощутимо ограничивает область его применения.
Anatoly Podgoretsky (2010-03-10 15:11:00) [11]Правильнее, но если сел на иглу, то что делать?
Варианты это чужое, из Бейсика.
Игорь Шевченко (2010-03-10 14:47:00) [12]Leonid Troyanovsky © (10.03.10 14:43) [26]
> Любопытно, что автор также столкивался с похожей на тему
> проблемой.
6 лет назад :)
Сергей М. © (10.03.10 13:29) [22]
Проще отказаться от вариантов в подобной DLL
Leonid Troyanovsky (2010-03-10 14:43:00) [13]
> Игорь Шевченко © (09.03.10 16:36) [19]
> http://www.alex-ionescu.com/?p=39
Любопытно, что автор также столкивался с похожей на тему проблемой.
http://groups.google.com/group/microsoft.public.platformsdk.shell/browse_thread/thread/e4fd80b723e961fe/b75d6f0a55b180ea
--
Regards, LVT.
brother (2010-03-10 14:05:00) [14]чет я протупил... пора видимо спать...
Сергей М. (2010-03-10 13:57:00) [15]Во-первых, как ты себе это мыслишь при использовании механизма AppInit_Dlls ?
Во-вторых, что значит "пустышки" ?
brother (2010-03-10 13:46:00) [16]а если перехватить загрузку oleaut32.dll и ole32.dll и подсовывать их "пустышки" не проще?
Сергей М. (2010-03-10 13:29:00) [17]
> brother © (10.03.10 04:35) [21]
Ну проблема тут налицо - недопустимая попытка загрузки oleaut32.dll и ole32.dll в момент выполнения загрузчиком инициализации user32.dll
Изменить порядок загрузки и инициализации документированными способами при использовании AppInit_Dlls , наверно, не удастся.
Так что, если функциональность этих модулей не нужна, придется тащить в свой проект копии как минимум пяти юнитов: system.pas, sysutils.pas, Variants.pas, VarUtils.pas и Classes.pas и править их, выкорчевывая везде и всюду все упоминания об ole32 и oleaut32, начиная со статического импорта, что довольно муторно, но вполне осуществимо.
brother (2010-03-10 04:35:00) [18]Сергей, если разберешься с проблеммой до конца и найдешь решение: буду благодарен за публикацию "отчета" в этом топике...
Сергей М. (2010-03-09 16:41:00) [19]
> Игорь Шевченко © (09.03.10 16:36) [19]
Благодарю.
Игорь Шевченко (2010-03-09 16:36:00) [20]Сергей М. © (09.03.10 16:25) [18]
Попробуй, начав отсюда, поискать:
http://www.alex-ionescu.com/?p=39