Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

AV при использовании юнита Variants [D7, WinXP]


Страницы:   1 2

Сергей М. ©   (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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо