Иногда на форуме проскакивает такой вопрос: "Как можно поглядеть экспортируемые ф-ии какой либо длл'ины?". Можно конечно же воспользоваться стандартными утилитами, но можно попробовать написать и что нить свое. Сейчас я попробую показать такой пример. Напишем пример, который делает именно это - вытаскивает экспорт модуля. Подробно расписывать тут ничего не буду, тут идет разбор элементов PE заголовка - нахождение таблицы экспорта, перечисление ф-ий. Недостаток этого примера в том, что он работает уже с подгруженными модулями, т.к. для нахождения базы используется GetModuleHandle().
Вставка:
The GetModuleHandle function returns a module handle for the specified module if the file has been mapped into the address space of the calling process.
Для расширения возможностей - простмотра всех модулей, надо использовать что нить другое, например "мэпирование" (CreateFileMapping() итд). Ведь надо хоть что нить самому сделать....
Code:
program ExpDump;
uses windows;
var
ImageBase : DWord;
DosHeader : PImageDosHeader;
PeHeader : PImageNtHeaders;
PExport : PImageExportDirectory;
pname : PDWord;
name : PChar;
i : Integer;
cmdline : string;
//#### ?-??: ????? ? ????
function Dump(const log: PChar): boolean;
Var hFile : THandle;
dwError : DWord;
dwWritten : DWord;
buffer : PChar;
begin
hFile := CreateFile(PChar(cmdline + '_fexport.txt'), GENERIC_WRITE, 0, nil, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile = INVALID_HANDLE_VALUE) then begin
result := FALSE;
exit;
end;
dwError := SetFilePointer(hFile, 0, nil, FILE_END);
if (dwError = $FFFFFFFF) then begin
CloseHandle(hFile);
result := FALSE;
exit;
end;
buffer := PChar(log + #13#10);
WriteFile(hFile, buffer^, length(buffer), dwWritten, nil);
if (dwWritten < DWord(length(buffer))) then begin
CloseHandle(hFile);
result := FALSE;
exit;
end;
CloseHandle(hFile);
result := TRUE;
end;
//####
//#### Start
begin
if (ParamCount < 1) then halt(0) else cmdline := ParamStr(1);
ImageBase := GetModuleHandle(PChar(cmdline));
if (ImageBase = 0) then begin
MessageBox(0, 'Error Load Module', 'Error', MB_OK);
halt(0);
end;
DosHeader := PImageDosHeader(ImageBase);
if (DosHeader^.e_magic <> IMAGE_DOS_SIGNATURE) then begin
MessageBox(0,'Error Dos Header','Error',MB_OK);
halt(0);
end;
PEHeader := PImageNtHeaders(DWord(ImageBase) + DWord(DosHeader^._lfanew));
if (PEHeader^.Signature <> IMAGE_NT_SIGNATURE) then begin
MessageBox(0,'Error PE Header', 'Error', MB_OK);
halt(0);
end;
For i := 0 to PExport^.NumberOfNames - 1 do begin
name := PChar(PDWord(DWord(ImageBase) + PDword(pname)^));
if (not Dump(name)) then halt(0);
inc(pname);
end;
end.
//#### End
ImageBase := GetModuleHandle(PChar(cmdline));
if (ImageBase = 0) then begin
ImageBase := LoadLibrary(PChar(cmdline));
if (ImageBase = 0) then begin
MessageBox(0, 'Error Load Module', 'Error', MB_OK);
halt(0);
end;
end;
Here's the translation of the content into Russian:
Неприятный вопрос "экспортировать функции из DLL"!
Ваш пример - хороший старт, но он имеет некоторые ограничения. Вы только загружаете модули, которые уже были загружены в процесс, что означает, что вы не сможете дампить экспорты из DLL, которые еще не были загружены.
Чтобы преодолеть это ограничение, можно использовать функцию LoadLibrary для загрузки DLL в память и затем использовать GetModuleHandle для получения ее модульного хэндла. Это позволит вам дампить экспорты из любого DLL, даже если он еще не был загружен.
Вот обновленная версия вашего кода, которая включает эти изменения:
programExpDump;usesWindows;varImageBase:DWord;DosHeader:PImageDosHeader;PeHeader:PImageNtHeaders;PExport:PImageExportDirectory;pname:PDWord;name:PChar;i:Integer;cmdline:string;functionDump(constlog:PChar):boolean;varhFile:THandle;dwError:DWord;dwWritten:DWord;buffer:PChar;begin// ... (rest of the function remains the same)end;beginifParamCount<1thenhalt(0)elsecmdline:=ParamStr(1);ImageBase:=LoadLibrary(PChar(cmdline));ifImageBase=0thenbeginMessageBox(0,'Ошибка загрузки модуля','Ошибка',MB_OK);halt(0);end;DosHeader:=PImageDosHeader(ImageBase);ifDosHeader^.e_magic<>IMAGE_DOS_SIGNATUREthenbeginMessageBox(0,'Ошибка DOS-галереи','Ошибка',MB_OK);halt(0);end;PeHeader:=PImageNtHeaders(DWord(ImageBase)+DWord(DosHeader^._lfanew));ifPeHeader^.Signature<>IMAGE_NT_SIGNATUREthenbeginMessageBox(0,'Ошибка PE-галереи','Ошибка',MB_OK);halt(0);end;PExport:=PImageExportDirectory(ImageBase+DWord(PeHeader^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress));pname:=PDWord(ImageBase+DWord(PExport^.AddressOfNames));Dump(PChar('Программа ExpDump =)'));Dump(PChar(cmdline+' функции:'));Dump(PChar(#13#10));fori:=0toPExport^.NumberOfNames-1dobeginname:=PChar(PDWord(DWord(ImageBase)+PDword(pname)^));ifnotDump(name)thenhalt(0);inc(pname);end;FreeLibrary(ImageBase);// Не забудьте освободить библиотеку!end.
С этой обновленной кодом вы должны сможете дампить экспорты из любого DLL, даже если он еще не был загружен. Помните только вызвать FreeLibrary после использования DLL для освобождения ее ресурсов.
Что касается улучшения кода, я бы предложил добавить механизмы обработки ошибок и журналирования для сделать его более robust и легче отлаживать. Вы также можете рассмотреть использование более эффективного метода дампа экспортов, например, используя хеш-таблицу или массив для хранения имен функций и адресов.
Написанный программистом пример Delphi-приложения, которое позволяет вытаскивать и выводить экспортируемые функции из динамически загруженной DLL.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.