Вызывание неэкспортируемой функции в DLL

У меня есть программа, которая загружает DLLs, и я должен вызвать одну из неэкспортируемых функций, которые это содержит. Есть ли какой-либо способ, которым я могу сделать это через поиск в отладчике или иначе? Прежде чем любой спросит, да у меня есть прототипы и материал для функций.

10
задан Nilbert 27 May 2010 в 18:07
поделиться

4 ответа

Боюсь, что не существует "безопасного" способа сделать это, если указанная библиотека не экспортирует явно свой объект (класс / функция). Потому что вы не будете знать, где в памяти кода отображается требуемый объект.

Однако, используя инструменты RE, вы можете найти смещение для интересующего объекта в библиотеке, а затем добавить его к любому известному адресу экспортируемого объекта, чтобы получить «реальную» ячейку памяти. После этого подготовьте прототип функции и т. Д. И преобразуйте его в вашу локальную структуру для использования.

0
ответ дан 3 December 2019 в 20:02
поделиться

Да, по крайней мере, вроде как, но это плохая идея.

В C / C ++ указатель на функцию - это адрес в памяти. Итак, если вы каким-то образом можете найти адрес этой функции, вы можете ее вызвать.

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

Помимо предупреждений, вы можете найти адрес функции, если у вас есть символы отладки, или MAP-файл , вы можете найти смещение в DLL. Если у вас нет ничего, кроме DLL, то нет никакого способа узнать, где эта функция существует в DLL - она ​​не хранится в самой DLL.

Как только у вас есть смещение, вы можете вставить его в код следующим образом:

const DWORD_PTR funcOffset = 0xDEADBEEF;
typedef void (*UnExportedFunc)();

....
void CallUnExportedFunc() {
     // This will get the DLL base address (which can vary)
     HMODULE hMod = GetModuleHandle("My.dll"); 
     // Calcualte the acutal address 
     DWORD_PTR funcAddress = (DWORD_PTR)hMod + funcOffset;
     // Cast the address to a function poniter
     UnExportedFunc func = (UnExportedFunc)funcAddress;
     // Call the function
     func();
}

Также поймите, что смещение этой функции БУДЕТ ИЗМЕНЯТЬСЯ КАЖДЫЙ РАЗ, когда DLL перестраивается, поэтому это очень хрупко, и позвольте мне еще раз сказать, что не хорошая идея.

10
ответ дан 3 December 2019 в 20:02
поделиться

Если нужная вам функция не экспортирована, то ее не будет в таблице адресов экспорта. Если предположить, что для создания этой DLL использовалась Visual Studio и у вас есть соответствующий файл PDB (база данных программ), то вы можете использовать API Microsoft DIA (доступ к интерфейсу отладки), чтобы найти нужную функцию либо по имени, либо, приблизительно, по сигнатуре.

Получив функцию (символ) из PDB, вы также получите ее RVA (относительный виртуальный адрес). Вы можете добавить RVA к базовому адресу загруженного модуля, чтобы определить абсолютный виртуальный адрес в памяти, где хранится функция. Затем вы можете выполнить вызов функции по этому адресу.


В качестве альтернативы, если вам нужно сделать что-то одно (т.е. вам не нужно программное решение), вы можете использовать windbg.exe из набора Debugging Tools for Windows для подключения к процессу и обнаружения адреса функции, которая вас интересует. В WinDbg вы можете использовать команду x для "изучения символов" в модуле.

Например, вы можете выполнить x mymodule!*foo*, чтобы увидеть все функции, имя которых содержит "foo". Если у вас загружены символы (PDB) для вашего модуля, это покажет вам и неэкспортные функции. Используйте .hh x для получения справки по команде x.

1
ответ дан 3 December 2019 в 20:02
поделиться

Самый общий способ сделать это (и это все еще плохая идея, как уже отмечали все остальные) - сканировать код DLL во время выполнения после его загрузки и искать известный уникальный фрагмент кода в этой функции. , а затем используйте код, аналогичный приведенному в ответе shf301, чтобы вызвать его. Если вы знаете, что DLL никогда не изменится, тогда любое решение, основанное на определении смещения в DLL, должно работать.

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

Мне действительно пришлось однажды сделать нечто подобное, чтобы применить бинарный патч к исполняемой программе DOS; это было исправление ошибки, и код не находился под контролем версий, так что это был единственный способ исправить это.

Кстати, мне было бы очень любопытно узнать, зачем вам это нужно.

0
ответ дан 3 December 2019 в 20:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: