Пусть dll импортирует символы из вызывающего .exe - PullRequest
0 голосов
/ 16 сентября 2018

Связано, но не эквивалентно DLL Получить символы из родительского элемента (загрузчик)

Есть ли способ убедить загрузчик Windows разрешить определенный символ, на который ссылается A.dll иззагружаемый исполняемый файл или промежуточный dll без указания файла для разрешения символов в A.dll?

Совершенно очевидно, как это сделать, если загрузочный .exe имеет известное имя, но если это не так...

Вот веская причина, почему вы на самом деле хотите это сделать: https://www.gnu.org/software/libc/manual/html_node/Replacing-malloc.html

Если это можно сделать, хороший ответ скажет, как это сделать каким-то образом илидругой.

Я наполовину ожидаю, что ответ не получится.В этом случае хороший ответ покажет, почему это невозможно.«Инструменты сборки не поддерживают это».плохой ответ.

1 Ответ

0 голосов
/ 17 сентября 2018

когда мы используем импорт, нам нужно точно указать имя модуля и имя функции.и мы не можем использовать сложные алгоритмы.Также для exe не существует широко известного псевдонима, который мы можем использовать вместо точно exe name.для сравнения: в случае получения GetModuleHandle мы можем использовать NULL для получения дескриптора файла, используемого для создания вызывающего процесса (файл .exe).но в случае LoadLibraryExW мы не можем использовать 0 или пустую строку (L"") или какой-либо другой псевдоним, скажем - мы хотим дескриптор exe .когда загрузчик загружает наш модуль - он читает имя dll из IMAGE_IMPORT_DESCRIPTOR и пытается найти или загрузить модуль с этим именем сначала по низкому уровню, частный, ядро ​​LoadLibraryExW.здесь нужно именно имя.или загрузка не удалась.В результате используйте импорт - здесь не решение, если мы не знаем имя exe во время сборки

возможный вариант - разрешите функции-указатели самостоятельно во время выполнения.здесь мы можем получить exe HMODULE на GetModuleHandle(0).Также при необходимости мы можем искать функцию не только в exe , но и в другом месте.Можно реализовать любой алгоритм поиска.

здесь существует несколько способов.для конкретного примера позвольте нам получить указатель на функцию с подписью:

void WINAPI fn(int i);

мы можем объявить указатель на эту функцию и разрешить ее во время выполнения

void (WINAPI *fn)(int);

*(void**)&fn = GetProcAddress(GetModuleHandleW(0), "fn");

скажем на DLL_PROCESS_ATTACH

немного другое решение (хотя на двоичном уровне оно полностью эквивалентно) объявляет функцию с атрибутом __declspec(dllimport).это только для компилятора CL.EXE (более известного как MSVC ).поэтому

__declspec(dllimport) void fn(int i);

в этом случае CL самостоятельно создайте указатель на функцию с именем __imp_ ## __FUNCDNAME__ name.так же, как и в первом варианте, когда мы объявляем указатель самостоятельно.Единственная разница в синтаксисе и ... имени символа.это будет выглядеть как __imp_?fn2@@YAXH@Z.проблема здесь в том, что __imp_?fn2@@YAXH@Z недопустимое имя для c / c ++ - мы не можем напрямую присвоить ему значение из c / c ++ .даже если мы объявим функцию с extern "C" - имя функции будет содержать символ @ (недопустимо для c ++ ) для функций __stdcall и __fastcall, для x86 .также имя будет отличаться для разных платформ ( x86 , x64 и т. д.).для доступа к таким именам - нужно или использовать внешний asm файл (для символов asm ? и @, допустимых в имени) или использовать опцию /alternatename linker - для установки псевдонима для такого имени и символа доступа черезЭто.скажем, как

__pragma(comment(linker, "/alternatename:__imp_?fn@@YAXH@Z=__imp_fn"))

и инициализация через

*(void**)&__imp_fn = GetProcAddress(GetModuleHandle(0), "fn");

другой вариант использования __declspec(dllimport) в объявлениях функций + добавление библиотеки импорта, где определены все __imp___FUNCDNAME__ (например, __imp_?fn2@@YAXH@Z),(даже если у нас нет такой библиотеки, мы можем легко создать ее самостоятельно - все, что нужно - исправить объявления функций с пустой реализацией).и после того, как мы добавим эту библиотеку импорта к входу компоновщика - добавим /DELAYLOAD:dllname, где dllname - точно имя из библиотеки импорта.ощущение, что это dllname будет (может) не совпадать с exe - все, что нужно - оно должно быть уникальным.и нам нужно самостоятельно обработать задержку загрузки (вызывается при первом вызове fn).для задержки загрузки нам нужно внедрить

extern "C" FARPROC WINAPI __delayLoadHelper2(   
   PCImgDelayDescr pidd,  
   FARPROC * ppfnIATEntry  
); 

, мы можем реализовать это самостоятельно или добавить delayimp.lib в наш проект.здесь (delayimp.lib) delayLoadHelper2 и реализовано.однако мы должны настроить этот процесс (реализация по умолчанию (смотрите /include/DelayHlp.cpp) будет использовать LoadLibraryExA с dllname, что не исключено в нашем случае - в противном случае мы можем просто использовать импорт как есть).поэтому нам нужно обязательно реализовать __pfnDliNotifyHook2:

, например:

FARPROC WINAPI MyDliHook(
                             unsigned        dliNotify,
                             PDelayLoadInfo  pdli
                             )
{
    switch (dliNotify)
    {
    case dliNotePreLoadLibrary:
        if (!strcmp(pdli->szDll, "unique_exe_alias"))
        {
            return (FARPROC)GetModuleHandle(0);
        }
    }

    return 0;
}

const PfnDliHook  __pfnDliNotifyHook2 = MyDliHook;

мы можем искать dliNotePreLoadLibrary уведомление и вместо него по умолчанию LoadLibraryEx(dli.szDll, NULL, 0); использовать GetModuleHandle(0); для получения базы ех .«unique_exe_alias» (который компоновщик получил из библиотеки импорта) здесь играют роль не реального exe имени, которое неизвестно, но уникального тега (псевдонима) для exe

...