Загрузка dll
От: meerius Канада  
Дата: 03.01.10 14:11
Оценка:
Есть некое приложение, которое статически линкуется с несколькими dll, предположим dll-A, dll-B и dll-C.
Сществует ли какой-нибудь способ, пусть не самый красивый, что-бы обеспечить загрузку dll-A в адрессное пространсва процесса первым, тоесть до загрузки всех остальных dll?
P.S Линковка статическая.

07.01.10 21:00: Перенесено модератором из 'C/C++' — Кодт
«Мы с тобой в чудеса не верим, Оттого их у нас не бывает…»
Re: Загрузка dll
От: meerius Канада  
Дата: 03.01.10 14:20
Оценка:
Забыл упомянуть — это Windows приложение.
«Мы с тобой в чудеса не верим, Оттого их у нас не бывает…»
Re: Загрузка dll
От: . Великобритания  
Дата: 03.01.10 14:42
Оценка:
On 03/01/2010 16:11, meerius wrote:

> Есть некое приложение, которое статически линкуется с несколькими dll,

Что значит статически линковаться с Dynamic Linking Library?
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[2]: Загрузка dll
От: nen777w  
Дата: 03.01.10 14:59
Оценка:
>> Есть некое приложение, которое статически линкуется с несколькими dll,
.>Что значит статически линковаться с Dynamic Linking Library?
Вероятно имелось в виду import library
Re[2]: Загрузка dll
От: meerius Канада  
Дата: 03.01.10 14:59
Оценка:
Здравствуйте, ., Вы писали:

.>On 03/01/2010 16:11, meerius wrote:


>> Есть некое приложение, которое статически линкуется с несколькими dll,

.>Что значит статически линковаться с Dynamic Linking Library?

Имеется ввиду раннее связывание.
«Мы с тобой в чудеса не верим, Оттого их у нас не бывает…»
Re: Загрузка dll
От: nen777w  
Дата: 03.01.10 15:01
Оценка:
Возможно где то в начале main вызвать из dll-A какой то фиктивный метод?
Re[2]: Загрузка dll
От: meerius Канада  
Дата: 03.01.10 15:16
Оценка:
Здравствуйте, nen777w, Вы писали:

N>Возможно где то в начале main вызвать из dll-A какой то фиктивный метод?

Думаю не вариант, в приложении возможны статические переменные, которые косвенно обращаются к dll-Б.

Может быть, возможно через парсинг таблицы импорта PE? Не уверен....
«Мы с тобой в чудеса не верим, Оттого их у нас не бывает…»
Re: Загрузка dll
От: ononim  
Дата: 04.01.10 10:40
Оценка:
M>Есть некое приложение, которое статически линкуется с несколькими dll, предположим dll-A, dll-B и dll-C.
M>Сществует ли какой-нибудь способ, пусть не самый красивый, что-бы обеспечить загрузку dll-A в адрессное пространсва процесса первым, тоесть до загрузки всех остальных dll?
M>P.S Линковка статическая.

вариант 1: сделать так чтобы dll-B и dll-C использовали какие нить экспортные символы из dll-A. То есть чтобы линковались на нее. Тока будьте аккуратнее чтобы круговую зависимость не накрутить.
вариант 2: перейти на delay load линковку и в приложении загрузить длл в нужном порядке перед тем как пользоваться ими
вариант 3: писать длл так, чтобы было пофиг в каком порядке они загружаются
Как много веселых ребят, и все делают велосипед...
Re[2]: Загрузка dll
От: meerius Канада  
Дата: 04.01.10 12:31
Оценка:
Здравствуйте, ononim, Вы писали:

O>вариант 1: сделать так чтобы dll-B и dll-C использовали какие нить экспортные символы из dll-A. То есть чтобы линковались на нее. Тока будьте аккуратнее чтобы круговую зависимость не накрутить.

Это, абсолютно, ничего не гарантирует.
O>вариант 2: перейти на delay load линковку и в приложении загрузить длл в нужном порядке перед тем как пользоваться ими
kernel.dll и ntdll.dll Вы тоже собираетесь в рантайме поднимать?
O>вариант 3: писать длл так, чтобы было пофиг в каком порядке они загружаются
Я так понемаю, отвата на вопрос у Вас нет, только жизненне советы?!
«Мы с тобой в чудеса не верим, Оттого их у нас не бывает…»
Re[3]: Загрузка dll
От: ononim  
Дата: 04.01.10 12:37
Оценка:
O>>вариант 1: сделать так чтобы dll-B и dll-C использовали какие нить экспортные символы из dll-A. То есть чтобы линковались на нее. Тока будьте аккуратнее чтобы круговую зависимость не накрутить.
M>Это, абсолютно, ничего не гарантирует.
А копание в PE заголовке думаете что-то гарантирует?

O>>вариант 2: перейти на delay load линковку и в приложении загрузить длл в нужном порядке перед тем как пользоваться ими

M>kernel.dll и ntdll.dll Вы тоже собираетесь в рантайме поднимать?
То есть dll-B это kernel32 а dll-C — это ntdll? Давайте тогда уж конкретизировать — раньше чего вы хотите загрузиться. Но сразу говорю — раньше ntdll вы НИКАК не загрузитесь. Совсем-совсем никак. Раньше kernel32 — это возможно. Но я столкнувшись в своем проекте с такой необходимостью счел проще сделать так чтобы это было не необходимо.

O>>вариант 3: писать длл так, чтобы было пофиг в каком порядке они загружаются

M>Я так понемаю, отвата на вопрос у Вас нет, только жизненне советы?!
То есть предложение сделать архитектуру более правильной — ето для вас жизненный совет, а тру девелопер гордо ломает башкой все возникающие проблемы проблемы а-ля ВДВшник кирпичи, не ища простых путей?
Как много веселых ребят, и все делают велосипед...
Re[4]: Загрузка dll
От: meerius Канада  
Дата: 04.01.10 13:11
Оценка:
Здравствуйте, ononim, Вы писали:

O>А копание в PE заголовке думаете что-то гарантирует?

Предпологается, что порядок загрузки длл соответствует порядку появления их в таблице импорта.
А вот, порядок заполнения таблици импорта не определен. Если переупорядочить эту таблицу, тогда можно гарантировать порядок загрузки. (не уверен)

M>>kernel.dll и ntdll.dll Вы тоже собираетесь в рантайме поднимать?

O>То есть dll-B это kernel32 а dll-C — это ntdll? Давайте тогда уж конкретизировать — раньше чего вы хотите загрузиться. Но сразу говорю — раньше ntdll вы НИКАК не загрузитесь. Совсем-совсем никак. Раньше kernel32 — это возможно. Но я столкнувшись в своем проекте с такой необходимостью счел проще сделать так чтобы это было не необходимо.

Хорошо. Нужно загрузится до MFC и CRT, что бы внедрить менеджер памяти. Нужно это сделать глобально на весь проект.
Другими словами, исключить, что часть памяти была выделенна новым менеджером, а другая часть старым(такая ситуация возможна со статическими объектами). Менеджер памяти писали не мы, и прикручивается он статически, вот такая уж специфика.

O>>>вариант 3: писать длл так, чтобы было пофиг в каком порядке они загружаются

M>>Я так понемаю, отвата на вопрос у Вас нет, только жизненне советы?!
O>То есть предложение сделать архитектуру более правильной — ето для вас жизненный совет, а тру девелопер гордо ломает башкой все возникающие проблемы проблемы а-ля ВДВшник кирпичи, не ища простых путей?

Я это все понимаю, но об архитектуре мне бы сейчес говорить нехотелось.
Меня интересует сам вопрос, в том смысле, как это сделать, а вот, насколько это хорошо, это уже другой вопрос.
«Мы с тобой в чудеса не верим, Оттого их у нас не бывает…»
Re[5]: Загрузка dll
От: ononim  
Дата: 04.01.10 13:43
Оценка:
M>>>kernel.dll и ntdll.dll Вы тоже собираетесь в рантайме поднимать?
O>>То есть dll-B это kernel32 а dll-C — это ntdll? Давайте тогда уж конкретизировать — раньше чего вы хотите загрузиться. Но сразу говорю — раньше ntdll вы НИКАК не загрузитесь. Совсем-совсем никак. Раньше kernel32 — это возможно. Но я столкнувшись в своем проекте с такой необходимостью счел проще сделать так чтобы это было не необходимо.
M>Хорошо. Нужно загрузится до MFC и CRT, что бы внедрить менеджер памяти. Нужно это сделать глобально на весь проект.
M>Другими словами, исключить, что часть памяти была выделенна новым менеджером, а другая часть старым(такая ситуация возможна со статическими объектами). Менеджер памяти писали не мы, и прикручивается он статически, вот такая уж специфика.

Понятно. Ну раз уж хотите геморроя и таблицу импорта, то вот вам вариант:
Стартуете пациента специальным лаунчером, который:
1) Запускает его через CreateProcess(...CREATE_SUSPENDED...)
2) Вычитывает из созданного процесс PEB, из PEB'а достает ImageBaseAddress.
3) Вычитывает из исполняемого образа в памяти процесса IMAGE_OPTIONAL_HEADER::DataDirectory поля IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, IMAGE_DIRECTORY_ENTRY_TLS. Если IMAGE_DIRECTORY_ENTRY_TLS — не нуль, п..ц приехали, гасите свет сливайте масло. Геморрой при этом возрастает на порядок и его рассказывать не будут. Если же имадж (и все длл на которые он прилинкован) не содержат TLS инициализаторов то...
4) Обнуляем IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT.
5) Находим EntryPoint образа ехешника, патчим ее — ложим поверх нее джамп на свой payload, который загрузит dll-A. Естественно запоминаем че там было раньше. payload юзает исключительно ntdll (LdrLoadDll, LdrGetProcedureAddress).
6) dll-A при своей загрузке в пациента — восстанавливает адреса на IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT и код оригинально EntryPoint в образе процесса.
7) Далее dll-A парсит таблицу импорта образа процесса и руками загружает все символы которые там указаны.
8) Далее — ZwContinue на адрес EntryPoint'а процесса. Вуаля!

При этом мы не застраховано от того что в системе работает какой нить продукт (практически все секурити сьюты), который инжектит свои длл во все процессы, каким либо системно-хитрым образом (начиная от AppInit_Dlls и заканчивая патчем PE лодыря глубоко внутри ntdll), и от того что его длл будет линковаться на рантайм, раньше которого мы так сильно хотели загрузиться.
Как много веселых ребят, и все делают велосипед...
Re[6]: Загрузка dll
От: meerius Канада  
Дата: 05.01.10 13:08
Оценка:
Здравствуйте, ononim, Вы писали:

O>Понятно. Ну раз уж хотите геморроя и таблицу импорта,

Ну, это был всего лишь вариант так, как совершенно не было других.
O>Если IMAGE_DIRECTORY_ENTRY_TLS — не нуль, п..ц приехали, гасите свет сливайте масло.
Думаю, как-раз, этот менеджер памяти юзает статический TLS, поэтому-то он и линкуется только статически. Динамическая подгрузка приведет к реальнум проблемам.
O>Геморрой при этом возрастает на порядок и его рассказывать не будут.
Согласен.
Раз мы об этом заговорили, то в двух словах:
Компилятор создает директорию TLS в PE в массиве директорий IMAGE_DATA_DIRECTORY со смещением 160. Данные инициализации буферов массива TLS для потока, находятся по адресам от StartAddressOfRawData до EndAddressOfRawData из IMAGE_TLS_DIRECTORY32, анологично массив адресов TLS CallBack содержит аддреса ф-й, которые должны инициализировать значения TLS переменных. Лоадер заполняет поле TlsSlots из TEB-a, в котором находится адрес массива TLS. Каждый элемент массива содержит адрес TLS буфера. AddressOfIndex из IMAGE_TLS_DIRECTORY32- это и есть адрес индекса в массиве TLS. Размер буиферов каждого потока вычисляется как EndAddressOfRawData — StartAddressOfRawData, а SizeOfZerroFill — есть кол-во байт, которые лоадер заполняет нулями в промежутке между StartAddressOfRawData и EndAddressOfRawData.
Ну, а так же, TEB и PEB могут изменится в следующих версиях Windows.

O>При этом мы не застраховано от того что в системе работает какой нить продукт (практически все секурити сьюты), который инжектит свои длл во все процессы, каким либо системно-хитрым образом (начиная от AppInit_Dlls и заканчивая патчем PE лодыря глубоко внутри ntdll), и от того что его длл будет линковаться на рантайм, раньше которого мы так сильно хотели загрузиться.


Вариант, конечно чисто академический, в продакшен не подходит.

Кстате, сущесвует ли, вообще, такой менеджер памяти, который внедряется глобально?
«Мы с тобой в чудеса не верим, Оттого их у нас не бывает…»
Re[7]: Загрузка dll
От: ononim  
Дата: 05.01.10 13:19
Оценка: :)
M>Кстате, сущесвует ли, вообще, такой менеджер памяти, который внедряется глобально?
Вы расскажите что вы хотите сделать? Быть может вы хотите сделать checked heap который за минуту включается gflags'ом?
Как много веселых ребят, и все делают велосипед...
Re[8]: Загрузка dll
От: meerius Канада  
Дата: 05.01.10 13:49
Оценка:
Здравствуйте, ononim, Вы писали:

M>>Кстате, сущесвует ли, вообще, такой менеджер памяти, который внедряется глобально?

O>Вы расскажите что вы хотите сделать? Быть может вы хотите сделать checked heap который за минуту включается gflags'ом?
Задача оптимизировать стандартное выделение/удаление памяти(в куче процесса) в приложении, в идеале, с минимальной модификацией самого приложения, тоесть махом. Критерий оптимизации — только быстродейсвие, автоматическое управление памятью, типовая верификация, и верификация перетерания не расматриваются. Стреда, разумеется, многопоточна, приложение завязанно на STL, MFC, а так же Loci, POCO и ряд других библиотек.
«Мы с тобой в чудеса не верим, Оттого их у нас не бывает…»
Re[9]: Загрузка dll
От: ononim  
Дата: 05.01.10 15:02
Оценка: 2 (1)
M>>>Кстате, сущесвует ли, вообще, такой менеджер памяти, который внедряется глобально?
O>>Вы расскажите что вы хотите сделать? Быть может вы хотите сделать checked heap который за минуту включается gflags'ом?
M>Задача оптимизировать стандартное выделение/удаление памяти(в куче процесса) в приложении, в идеале, с минимальной модификацией самого приложения, тоесть махом. Критерий оптимизации — только быстродейсвие, автоматическое управление памятью, типовая верификация, и верификация перетерания не расматриваются. Стреда, разумеется, многопоточна, приложение завязанно на STL, MFC, а так же Loci, POCO и ряд других библиотек.
Очень странный и скользкий подход к оптимизации. Впрочем это ваши проблемы.
В любом случае решения загрузиться гарантированно раньше CRT не будет. Хотябы потому что в системе может быть ктото другой такой же умный который тоже захочет загрузиться пораньше, вгрузиться раньше вас и втянет в процесс с собой CRT. Но это можно продетектить и не активировать свой мегааллокатор в таком случае.
Что касается "порядка" загрузки длл — в PEB несколько списков DLL. Причем порядок в котором длл грузятся и в котором вызываются их рутины инициализации различный — для этого в PEB есть два LDR_ENTRY списка — LoadOrder и InitializationOrder. Для вас важен именно InitializationOrder. Так что смена порядка в таблице импорта боюсь гарантирует что-то даже меньше чем смена зависимостей.
Могу предложить написать dll-заглушку, таблица экспорта которой будет дублировать таблицу экспорта юзаемой CRT. Причем не просто дублировать — но и все экспорты могут быть форвардами дабы не возиться с передачей параметров каждой ф-ии. Это в принципе можно автоматом сделать после билда длл — распарсить таблицу экспорта CRT и сгенерить таблицу экспорта своей длл с форвардами на CRT.
Далее, эта ваша длл должна будет при загрузке себя похукать все что она хочет для своего хип манагера.
Как много веселых ребят, и все делают велосипед...
Re[10]: Загрузка dll
От: meerius Канада  
Дата: 05.01.10 15:26
Оценка:
Здравствуйте, ononim, Вы писали:

O>Очень странный и скользкий подход к оптимизации. Впрочем это ваши проблемы.

Да я сам старонник оптимизации по месту и противник преждевременной оптимизаци.
Но проект уже и так напичкан, разными пулами резервирующими буфера в виртуальной памяти, lazy evaluation-ами, copy-on-writе-ами, и другими оптимизирующими примочками.
Попросили копнуть в этом направлении — копаю, чтобы аргументировать все "за" и "против".
Спасибо за инерессное обсуждение вопроса!
«Мы с тобой в чудеса не верим, Оттого их у нас не бывает…»
Re[5]: Загрузка dll
От: aydef  
Дата: 07.01.10 12:03
Оценка:
M>Хорошо. Нужно загрузится до MFC и CRT, что бы внедрить менеджер памяти. Нужно это сделать глобально на весь проект.
M>Другими словами, исключить, что часть памяти была выделенна новым менеджером, а другая часть старым(такая ситуация возможна со статическими объектами). Менеджер памяти писали не мы, и прикручивается он статически, вот такая уж специфика.


Возьмите hoard он именно так и делает. Исходники есть. Техника простая. Все что нужно в winhoard.cpp
Re[6]: Загрузка dll
От: meerius Канада  
Дата: 07.01.10 13:19
Оценка:
Здравствуйте, aydef, Вы писали:

A>Возьмите hoard он именно так и делает. Исходники есть. Техника простая. Все что нужно в winhoard.cpp

Он же просто подменивает ф-ии
Тесть на момент подмены, все статические переменные уже будут инициализированны, причем чатсь старым менеджером, а часть уже новым. После выхода из main-а начнутся проблеммы.
«Мы с тобой в чудеса не верим, Оттого их у нас не бывает…»
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.