Вопросы на засыпку
От: ua1zcl Россия www.alexklm.ru
Дата: 13.01.02 22:51
Оценка:
У меня несколько вопросов. Ответте кто нибудь хотя бы на один. Это относительно Windows95.
1. Если в процессе несколько раза вызывается LoadLibrary("xx.dll") а FreeLibrary() на 1 раз меньше и процесс завершается, то останется ли xx.dll в памяти?
2. Какова политика Microsoft по этому вопросу.
3. Есть ли нормы на секцию импорта для PE формата, разумеется не те что в winnt.h,
а все допустимые варианты.
4. Почему Microsoft загружает Advapi32.dll для некоторых "своих" dll
(например rnaui.dll) не по базовому адресу, а ниже приблизительно на 0x10000
байт и их, "свои" dll, боундирует изначально?
Александр
Re: Вопросы на засыпку
От: Dr_Sh0ck Беларусь  
Дата: 13.01.02 23:21
Оценка:
Здравствуйте ua1zcl, Вы писали:

U>У меня несколько вопросов. Ответте кто нибудь хотя бы на один. Это относительно Windows95.

U>1. Если в процессе несколько раза вызывается LoadLibrary("xx.dll") а FreeLibrary() на 1 раз меньше и процесс завершается, то останется ли xx.dll в памяти?
U>2. Какова политика Microsoft по этому вопросу.
U>3. Есть ли нормы на секцию импорта для PE формата, разумеется не те что в winnt.h,
U> а все допустимые варианты.
U>4. Почему Microsoft загружает Advapi32.dll для некоторых "своих" dll
U>(например rnaui.dll) не по базовому адресу, а ниже приблизительно на 0x10000
U>байт и их, "свои" dll, боундирует изначально?

1. Нет
2.
3. Сформулируй поконкретнее
4. Это допустимо не только для Advapi32.dll, но и для любых ДЛЛ
Do not fake yourself ;)
ICQ#: 198114726
Re: Вопросы на засыпку
От: paul_shmakov Россия  
Дата: 14.01.02 01:02
Оценка:
Здравствуйте ua1zcl, Вы писали:

U>1. Если в процессе несколько раза вызывается LoadLibrary("xx.dll") а FreeLibrary() на 1 раз меньше и процесс завершается, то останется ли xx.dll в памяти?

U>2. Какова политика Microsoft по этому вопросу.

Когда завершается процесс выгружаются все используемые им dll и разрушается адресное пространство процесса. Этот процесс не зависит от количества вызовов LoadLibrary/FreeLibrary.

U>3. Есть ли нормы на секцию импорта для PE формата, разумеется не те что в winnt.h,

U> а все допустимые варианты.

Не очень понятен вопрос. Секция импорта описана в различных описаниям PE-формата (например, от Hard Wisdom). И не понятно, чем Вам не угодил winnt.h.

С другой стороны есть некоторые нюансы, которые всплывают при детальном рассмотрении реальных exe-шников, слинкованных различными линкерами. Я сравнивал два: vc++, borland cpp. Что меня сильно удивило, так это то, что компании (и соответственно их линкеры) абсолютно различно понимают значения некоторых полей в PE-заголовке (!). Например, можете сравнить пару полей SizeOfRawData и Misc.VirtualSize в структуре IMAGE_SECTION_HEADER.

Такие же проблемы есть и в реальной секции импорта. Ключевая часть секции — это список структур IMAGE_IMPORT_DESCRIPTOR, которая заканчивается нулем.
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    };
    DWORD   TimeDateStamp;            
    DWORD   ForwarderChain;                 
    DWORD   Name;
    DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;


Поле Name структуры ссылается на имя dll (например, "kernel32.dll"). Поле OriginalFirstThunk ссылается на массив структур IMAGE_THUNK_DATA.
typedef struct _IMAGE_THUNK_DATA {
    union {
        DWORD ForwarderString;      // PBYTE 
        DWORD Function;             // PDWORD
        DWORD Ordinal;
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA;

Каждая ячейка в этом массиве — это описание импортируемой функции. Функции могут импортироваться разными способами. Например, по имени. Это самый распространенный способ. При этом IMAGE_THUNK_DATA.u1.AddressOfData указывает на структуру вида:
typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;
    BYTE    Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

Где Hint — это номер функции, а Name — имя. Например,
Hint = 0x22C, Name = "ResumeThread"


Также функции могут импортироваться по ordinal (по номеру). Тогда IMAGE_THUNK_DATA.u1.Ordinal имеет установленный старший бит, а младшее слово содержит сам ordinal импотрируемой функции.

И т.п. Остальные варианты можно посмотреть в описаниях. Это не главное.
Вернемся к структуре IMAGE_IMPORT_DESCRIPTOR. Поле OriginalFirstThunk ссылается на массив, содержащий описание импортируемых функций. Поле FirstThunk ссылается на точно такой же массив такого же размера. Но заполняется он во время загрузки реальными адресами функций. Т.е. загрузчик пробегает массив OriginalFirstThunk, для каждого его элемента определяет реальный адрес функции и записывает этот адрес в массив FirstThunk.
Так должно быть в идеале, и так обычно и бывает. Обычно, но не всегда. Мне встречались exe-шники, в которых не было массива OriginalFirstThunk (!) (если не изменяет память, то это Delphi так портачит). Там исходный массив лежит все в том же массиве FirstThunk, значения которого после загрузки заменяются адресами функций.

Все конечно понятно — минимизация памяти, но это выходит за рамки спецификации. И главное — из-за этого не правильно функционируют некоторые программы pedump-еры. Т.к. в Win32 SDK написано, что массив структур IMAGE_IMPORT_DESCRIPTOR следует просматривать, пока поле OriginalFirstThunk (Characteristics) не равно 0. А в Delphi-программе это поле у всех записей равно 0.

И таких мелочей встречается в PE-формате достаточно много. И описания, о которых говорилось выше, об этом молчат (или мне не удалось найти иного).

Ну а настоящие "нормы на секцию импорта для PE формата" имхо можно определить только дизассемблировав виндузовый PE загрузчик.

U>4. Почему Microsoft загружает Advapi32.dll для некоторых "своих" dll

U>(например rnaui.dll) не по базовому адресу, а ниже приблизительно на 0x10000
U>байт и их, "свои" dll, боундирует изначально?

Загрузка по адресу, отличному от базового — это сродни ошибке. Если это и случается у Microsoft, то явно не нарочно. Это происходит в том случае, если несколько подгружаемых dll претендуют на один и тот же диапазон адресов адресного пространства. Часто это случается, если несколько dll имеют одинаковые базовые адреса. Microsoft обычно следит, чтобы такого не происходило (по крайней мере для системных dll).

Ну а связывание (bind) делается для ускорения загрузки приложения. Как выше было рассказано, загрузчику достается достаточно много работы при загрузке pe-файла. Он должен просмотреть секции импорта всех модулей, для каждой функции определить ее адрес, что является не особо быстрой процедурой.
Возникает вопрос: зачем загрузчику выполнять эту процедуру для системных библиотек? Например, зачем при загрузке kernel32.dll каждый раз заново определять адреса всех импортируемых ей функций из ntdll.dll? Ведь они уже и так разнесены на разные бызовые адреса (т.е. при загрузке не будет необходимости совершать перемещение), адреса функцих постоянны и заранее известны.
Поэтому приняли гениальное решение — в массив IMAGE_IMPORT_DESCRIPTOR.FirstThunk заранее занесли адреса функций и специальным образом пометили, что мол этот IMAGE_IMPORT_DESCRIPTOR уже связан (bound).
Загрузчику остается ерунда — загрузить все необходимые модули.

Конечно, это привязывает pe-файл к конкретной версии другого, что не подходит, скажем, для привязки Вашего приложения к kernel32.dll, т.к. очевидно приложение должно работать на разных версиях операционной системы. Но это отлично подходит для системых dll, которые всегда идут вместе.
Paul Shmakov
Re[2]: Вопросы на засыпку
От: Alex Fedotov США  
Дата: 14.01.02 01:43
Оценка:
Здравствуйте paul_shmakov, Вы писали:

PS> Конечно, это привязывает pe-файл к конкретной версии другого, что не подходит, скажем, для привязки Вашего приложения к kernel32.dll, т.к. очевидно приложение должно работать на разных версиях операционной системы. Но это отлично подходит для системых dll, которые всегда идут вместе.


Привязку можно делать в момент установки приложения на конкретной системе. Тогда по крайней мере до следующего сервис-пака будет работать быстрее.
-- Alex Fedotov
Re[3]: Вопросы на засыпку
От: paul_shmakov Россия  
Дата: 14.01.02 01:53
Оценка:
Здравствуйте Alex Fedotov, Вы писали:

AF>Привязку можно делать в момент установки приложения на конкретной системе. Тогда по крайней мере до следующего сервис-пака будет работать быстрее.


Мотайте на ус, создатели генераторов инсталяционных пакетов :)
Paul Shmakov
Re[4]: Вопросы на засыпку
От: ua1zcl Россия www.alexklm.ru
Дата: 14.01.02 10:38
Оценка:
Здравствуйте paul_shmakov, Вы писали:

PS>Здравствуйте Alex Fedotov, Вы писали:


AF>>Привязку можно делать в момент установки приложения на конкретной системе. Тогда по крайней мере до следующего сервис-пака будет работать быстрее.


PS> Мотайте на ус, создатели генераторов инсталяционных пакетов :)


Спасибо за подробную информацию! Я так и думал, что п.3 и 4 — вопрос затемнённый.
Я ещё утром хотел ответить на полученную информацию, но затеял проверочный эксперимент, и попал в цейтнот всвязи с подозрением на вирус в пакете WS95update и не стал выходить в инэт.
Теперь об эксперименте.
Я статически подлинковал к моему exe-шнику rnaui.dll (класный объект "Удаленный доступ к сети", я импортировал функцию RnaDial(...,...)) и при запуске обнаружил, что несмотря на наличие rnaui.dll в одноимённой директории с моим test.exe система загрузила (в памяти системы библиотека на момент запуска отсутствовала) библиотеку с системной директории. Хотя, по правилам того же Майкрософта, загрузить должна была из моей директории (нарушение правил!). Когда я выбросил из системной папки rnaui.dll в корзину и запустил экзешник по получил "любезное" сообщение — "Необходимая билиотека D:\WINDOWS\SYSTEM\RNAUI.DLL не найдена". Когда я в реестре исключил из списка Закомых Билиотек эту rnaui.dll, то Windows95-OSR2 загрузил dll из моей директории. Ни в одном случае базовый адрес загрузки Advapi32.dll не таранслировался изходным (0xBFED000) а попадал в районе 0x83000000
Интересно что будет, когда я сбоундирую в моём экзешнике Advapi32.dll.
Зачем мне это надо? Чисто из интереса познавательного. Я хотел посмотреть как система среагирует. Вот строка из моего отладчика при просмотре rnaui.dll

7F7378A9 : ADVAPI32.dll : Bounded to: BFEC1A3A (BFEC1A3A is NOT readable (loaded at BFED0000).
Интересно, что там прячет Майкрософт на этих адресах, если узнаю — сообщу сюда!
Извините за назойливость.
Александр
Re: Вопросы на засыпку
От: ua1zcl Россия www.alexklm.ru
Дата: 14.01.02 16:29
Оценка:
Здравствуйте ua1zcl, Вы писали:

U>4. Почему Microsoft загружает Advapi32.dll для некоторых "своих" dll

U>(например rnaui.dll) не по базовому адресу, а ниже приблизительно на 0x10000
U>байт и их, "свои" dll, боундирует изначально?

Ещё я сделал эксперимент. Заставил rnaui.dll загрузить мою библиотеку, которая сделала снимок памяти этой хитрой DLL. Оказалось, что IMAGE_NT_HEADERS там сдвинут на 1 байт, CODE
и .IDATA на 2, и последняя секция, .RELOC, аж на > 144 байт. Похоже, что таким образом осуществляется зашита от не менее хитрых и вредных программ как вирусы. На месте одного из THUNK's, раньше указывающего на непонятный мне адрес для перехода на Advapi32.dll, оказалось что-то невразумительное. Так что вопрос, куда эти ссылки (как 0xBFEC1A3A) указывают, остался открытым. Но это уже другой вопрос.
Александр
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.