Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Как из ДЛЛ получить свой описатель?


Автор: HappyLife 29.8.2007, 16:18
Как не используя переменную из функции DllEntryPoint получить HINSTANCE текущего модуля.
GetModuleHandle требует имя, а мне бы стандартный прием, типа GetThisHandle.....
При помощи GetModuleHandle(0) можно получить описатель EXE вызвавшей модуль.

Автор: Earnest 29.8.2007, 16:25
По-моему - никак (если имени модуля не знаешь). А чем тебя DllEntryPoint не устраивает? Заведи глобальную переменную и запомни, потом спрашивай.

Добавлено через 1 минуту и 25 секунд
Т.е. DllMain

Автор: HappyLife 29.8.2007, 16:30
Earnest, Кхм. Потому что хочется сделать независимый класс, который ничего не экстернит.
Ну раз никак значит никак.)

Автор: Earnest 30.8.2007, 08:10
Ну и не экстернь. Сделай приватную статическую переменную и инициализируй ее в DllMain (соответствующей статической функцией). Так примерно MFC делает.

Автор: Tectoder 1.9.2007, 09:49
В принципе никак.
Откуда твоя функция будет это знать? Над адресом возврата чтоли издеваться?

Автор: Pale_Master 1.9.2007, 15:06
На самом деле это довольно просто сделать. Мой пример нуждается в библиотеке dbghelp.dll.

Код

#include "DbgHelp.h"

#pragma comment(lib,"Dbghelp.lib")

BOOL CALLBACK EnumerateLoadedModulesProc64(PTSTR pszModuleName, DWORD64 qwModuleBase, ULONG dwModuleSize, PVOID pUserContext)
{
    const DWORD64 qwCurAddress = (DWORD64)&EnumerateLoadedModulesProc64;

    if (qwCurAddress >= qwModuleBase && qwCurAddress <= qwModuleBase+(DWORD64)dwModuleSize)
    {
        strcpy_s((char*)pUserContext,MAX_PATH,pszModuleName);
        return FALSE;
    }

    return TRUE;
}

HMODULE GetCurrentInstance()
{
    char szModuleName[MAX_PATH];

    ::EnumerateLoadedModules64(::GetCurrentProcess(),&EnumerateLoadedModulesProc64,szModuleName);

    return ::GetModuleHandle(szModuleName);
}




Автор: Tectoder 1.9.2007, 17:37
Ну если такой способ, с учетом всех возможных багов, то почему бы не использовать просто VirtualQuery ^_^

Автор: Pale_Master 1.9.2007, 17:58
Tectoder, есть много способов получить базовый адрес текущего модуля, коим и является HMODULE (HINSTANCE), тем не менее вы утверждали, что это невозможно сделать. smile

Автор: GremlinProg 2.9.2007, 11:32
Примерно, таким же образом я получал текущий модуль, только использовал разбор секции импорта, в поисках экспортируемого "ключевого символа". Но раз условие таково:
Цитата(HappyLife @  29.8.2007,  18:30 Найти цитируемый пост)
Потому что хочется сделать независимый класс, который ничего не экстернит

то видимо Pale_Master ближе всех подобрался к решению (хотя не совсем понимаю, зачем неэкспортируемый ничего модуль, разве что для регистрации оконной процедуры виндового класса?).

На сколько я помню, VirtualQuery вернет для того же qwCurAddress базовый адрес исполняемого модуля, а не модуля dll, хотя могу ошибаться, у кого на ходу какая-нибудь библиотека, проверьте плз. мои сомнения

Автор: W4FhLF 3.9.2007, 10:53
Куда-то всех понесло не туда smile

Код

#include "windows.h"

BOOL __stdcall DllMain (HANDLE hInst,DWORD dwReason, LPVOID IpReserved) 
{
    DWORD hModule;
    switch (dwReason) {
        case DLL_PROCESS_ATTACH: // Инициализация процесса.

            hModule = (DWORD)&DllMain & 0xFFFF0000; // берём любой адрес в пределах нашей DLL
            while (*(PWORD)hModule != 'ZM') // листаем страницы в поисках сигнатуры MZ. Любой модуль в памяти начинается с этой сигнатуры.
                hModule -= 0x1000;

            // в hModule базовый адрес
            break; 
        case DLL_PROCESS_DETACH: // Очистка структур процесса.
            break;
    }
    return TRUE;


Автор: HappyLife 3.9.2007, 11:08
W4FhLF, Очень красиво. smile 

Автор: GremlinProg 3.9.2007, 19:32
Забавно, только упаси вас бог, таким способом искать текущий модуль ))
Сигнатура MZ не уникальна, нет ни какой гарантии, что MZ не втретится, ни в коде, ни в статических данных. К примеру, 0x48r - код команды DEC. Если DEC будет выполняться для регистра BP или EBP, в зависимости от разрядности команды, то код будет 0x4D, т.е. 'M', аналогично и для 'Z'.

Автор: 586 4.9.2007, 05:05
Цитата(GremlinProg @  3.9.2007,  20:32 Найти цитируемый пост)
Сигнатура MZ не уникальна, нет ни какой гарантии, что MZ не втретится, ни в коде, ни в статических данных.

есть еще сигнатура PE и OptionalHeader.Magic и такое совпадение маловероятно. Расположение PE-файла в ресурсах по такому выравниванию в ресурсах тоже маловероятно. К тому же в PE заголовке где-то есть флаг, что модуль загружен в память.

Автор: W4FhLF 4.9.2007, 14:50
Про сигнатуру PE 586 отметил верно, в своих программах я учитывал это. 

Цитата(GremlinProg @  3.9.2007,  19:32 Найти цитируемый пост)
Сигнатура MZ не уникальна, нет ни какой гарантии, что MZ не втретится, ни в коде, ни в статических данных.


А ты видел много программ в которых нативные секций данных и ресурсов располагаются в памяти по адресам младшим относительно адреса секции кода?

Добавлено @ 14:56
И ещё, лучше перестраховаться и сделать hModule = (DWORD)&DllMain & 0xFFFFF000;

Автор: GremlinProg 4.9.2007, 21:40
Цитата(W4FhLF @  4.9.2007,  16:50 Найти цитируемый пост)
А ты видел много программ в которых нативные секций данных и ресурсов располагаются в памяти по адресам младшим относительно адреса секции кода?

Зря бушуешь, я не говорю, что твой метод не сработает, в конкретных программах - конечно, не спорю, быстро и аккуратно так можно найти базовый адрес модуля, НО. Виртуальный адрес любой секции физически можно переназначить без особых проблем и загрузчик это проглотит, практически все среды позволяют менять, по крайней мере базовые адреса, я уже не говорю о умных следопытах, которые практикуют прямое назначение адресов секций, в таком случае секция кода может располагаться где-угодно, ресурсы, в которых так же может лежать как модуль, так и драйвер, так же можно переносить в любое место. Выравнивание условно и выставляется в основном только ms компиляторами. Если говорить об общем случае, то возьми просто, наугад пару-тройку левых программ и попробуй найти фаром эти сигнатуры.

Вобщем, если нет гарантии, что последовательность уникальна, то не стоит использовать "лобовые" поисковые алгоритмы в своих программах, в основном это временные или частные решения.

Я тут просто еще раз посмотрел на третий пост
Цитата

Потому что хочется сделать независимый класс

Ключевое слово независимый, т.е. независимый от среды внедрения, т.е. работающий везде...

надеюсь, я понятно все изложил

Автор: W4FhLF 5.9.2007, 08:01
Цитата(GremlinProg @  4.9.2007,  21:40 Найти цитируемый пост)
Виртуальный адрес любой секции физически можно переназначить без особых проблем и загрузчик это проглотит, практически все среды позволяют менять, по крайней мере базовые адреса, я уже не говорю о умных следопытах, которые практикуют прямое назначение адресов секций, в таком случае секция кода может располагаться где-угодно, ресурсы, в которых так же может лежать как модуль, так и драйвер, так же можно переносить в любое место. Выравнивание условно и выставляется в основном только ms компиляторами.


Извини конечно, но я не понимаю к чему эти многабукофф? Ты же получаешь описатель СВОЕГО модуля, тебе заранее должны быть известны расположение секций. Я не видел ниодного компилятора располагающего секцию кода за секциями данных или ресурсов. 
Хорошо, пусть ты решил извратиться и сделал секцию кода последней, пусть у тебя в ресурсах лежит ещё какой-то PE файл и пусть его адрес совпадает с началом страницы в памяти, тогда возьми InMemoryOrderModuleList в PEB'e и пройдись по нему в цикле или пропусти это срабатывание и всё. 

Цитата(GremlinProg @  4.9.2007,  21:40 Найти цитируемый пост)
 Если говорить об общем случае, то возьми просто, наугад пару-тройку левых программ и попробуй найти фаром эти сигнатуры.


И что я должен увидеть?

Цитата(GremlinProg @  4.9.2007,  21:40 Найти цитируемый пост)
Вобщем, если нет гарантии, что последовательность уникальна, то не стоит использовать "лобовые" поисковые алгоритмы в своих программах, в основном это временные или частные решения.


Называть частным решение, которое основано на фундаментальных аспектах архитектуры ОС я бы не решился. 

Автор: GremlinProg 5.9.2007, 11:12
Цитата(W4FhLF @  5.9.2007,  10:01 Найти цитируемый пост)
же получаешь описатель СВОЕГО модуля, тебе заранее должны быть известны расположение секций

Согласен, только если бы вопрос стоял именно так, то я, честно, использовал бы hInstance из DllMain, и не морочил бы ни кому голову. Суть ведь именно в том, что доступ к модулю не должен быть привязан к конкретной архитектуре приложения, на то он и класс, т.е. понятие СВОЙ модуль он в принципе-то и знать не должен. Сможешь найти в примере Pale_Master какую-нибудь такую привязку или неопределенность?
Цитата(W4FhLF @  5.9.2007,  10:01 Найти цитируемый пост)
Называть частным решение, которое основано на фундаментальных аспектах архитектуры ОС я бы не решился. 

Громко, но я бы наверное именно это и не решился бы написать, по крайней мере не стал бы призывать всех пресвятых, как то старо, и не убедительно.

Автор: W4FhLF 5.9.2007, 13:37
Цитата(GremlinProg @  5.9.2007,  11:12 Найти цитируемый пост)
Согласен, только если бы вопрос стоял именно так


Цитата(HappyLife @  29.8.2007,  16:18 Найти цитируемый пост)
Как не используя переменную из функции DllEntryPoint получить HINSTANCE текущего модуля.


Цитата(HappyLife @  29.8.2007)

Как из ДЛЛ получить свой описатель?


Цитата(GremlinProg @  5.9.2007,  11:12 Найти цитируемый пост)
на то он и класс, т.е. понятие СВОЙ модуль он в принципе-то и знать не должен.


Ещё разок перечитай, задача состоит в том, чтобы получить СВОЙ описатель. Классу пофиг в пределах какого модуля выполняться, известно лишь одно - код класса выполняется в пределах модуля описатель которого надо получить. В этом состоит задача, не знаю чего ты споришь.

Цитата(GremlinProg @  5.9.2007,  11:12 Найти цитируемый пост)
Громко, но я бы наверное именно это и не решился бы написать, по крайней мере не стал бы призывать всех пресвятых, как то старо, и не убедительно.


Чего?

Автор: Tectoder 5.9.2007, 20:07
Цитата(Pale_Master @  1.9.2007,  17:58 Найти цитируемый пост)
Tectoder, есть много способов получить базовый адрес текущего модуля, коим и является HMODULE (HINSTANCE), тем не менее вы утверждали, что это невозможно сделать.  
Если исполнительная среда устроена так что код библиотеки генерируется в рантайме(примеры таких сред приводить надо?), адрес какойнибудь функции может оказаться очень сильно отличен от базы dll, вы не находите? Имелось ввиду это. А не то что нельзя определить базу региона обладающего кучей характерных признаков.
Хотя если речь идет о C++ в частности, а не о Win32 вообще, то сказанное тобой конечно вполне разумно.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)