Как посмотреть список загруженных dll

Обновлено: 04.07.2024

Если у меня есть исполняемый файл Windows, как я могу узнать, какие библиотеки он загрузит?

Я просто говорю о том, какие из них будут загружаться статически, а не о тех, которые могут загружаться динамически с помощью чего-то вроде LoadLibrary.

Есть утилиты, которые сделают это за вас.

Раньше я использовал инструмент MS (depends.exe), который, как мне кажется, поставлялся с VB .:
VS2010 VS2012 VS2013 VS2015 Текущий

И, вероятно, другие тоже.

Просто перейдите в командную строку и введите tasklist /m , вы увидите список DLL-файлов, используемых конкретной программой.

Да, это делает то, что вы говорите, однако, если исполняемый файл запускает несколько процессов, вы никогда не узнаете из командной строки, какой процесс был запущен исполняемыми файлами, поэтому вы не будете знать все зависимые DLL исполняемого файла.

Существует удобный инструмент под названием NDepend, который предоставит вам все зависимости DLL.

Вы забыли упомянуть, что он работает как расширение vs.

Преимущества: позволяет исследовать уже запущенный процесс (я не нашел, как прикрепить обходчик зависимостей к существующему процессу)

Зависимости - современный Dependency Walker с открытым исходным кодом показывает, какие библиотеки DLL загружает исполняемый файл Windows, и он хорошо работает в современная Windows 10.

Он немного менее мощный, чем Dependency Walker, но последний может работать или не работать в Windows 10, поскольку он последний раз обновлялся в 2006 году. (Более новые версии Dependency Walker были связаны с некоторыми версиями Windows Development Kit для Windows 10, но не больше.)

dumpbin - это инструмент, который поставляется с VC ++.

Чтобы узнать, какие библиотеки DLL импортирует программа:

  • Откройте Visual Studio
  • Пункты меню Инструменты | Командная строка Visual Studio
  • cd в папку, содержащую исполняемый файл
  • dumpbin / иждивенцы Any.exe

Чтобы узнать, какие функции (и библиотеки DLL) он будет импортировать, используйте

Получение списка DLL, загруженных в текущий процесс

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

Сперва немного теории. Каждому процессу в системе соответствует особая структура PEB (Process Enviroment Block), в ней содержится большое количество полезной информации о процессе. Адрес PEB можно узнать из другой структуры - TIB (Thread Information Block), адрес которой, в свою очередь, всегда можно получить по фиксированному адресу [FS:0]. Так вот, одно из полей PEB указывает на массив структур, в которых содержится информация о всех динамических библиотеках, загруженных в адресное пространство процесса. Этот массив называется PEB_LDR_DATA. Перебирая по очереди записи из этого массива, можно получить интересующий нас список DLL, а также адреса загрузки в память и Virtual Address точки входа этих библиотек.

Переходим к программированию. Flat Assembler "из коробки" не знает структур для работы с PEB_LDR_DATA, поэтому придется ему в этом помочь:

  1. struct UNICODE_STRING
  2. Length dw ?
  3. MaximumLength dw ?
  4. Buffer dd ?
  5. ends
  6. struct LIST_ENTRY
  7. Flink dd ?
  8. Blink dd ?
  9. ends
  10. struct LDR_DATA_ENTRY
  11. InMemoryOrderModuleList LIST_ENTRY
  12. BaseAddress dd ?
  13. EntryPoint dd ?
  14. SizeOfImage dd ?
  15. FullDllName UNICODE_STRING
  16. BaseDllName UNICODE_STRING
  17. Flags dd ?
  18. LoadCount dw ?
  19. TlsIndex dw ?
  20. HashTableEntry LIST_ENTRY
  21. TimeDateStamp dd ?
  22. ends

Записи перелинкованы между собой посредством поля InMemoryOrderModuleList.Flink, в котором прописана информация об адресе следующей записи. Важно учитывать, что массив "закольцован", то есть последняя запись ссылается на первую. При переборе надо проверять, например, поле BaseAddress текущей записи, если оно нулевое, то обработку следует остановить. Записи в массиве располагаются в порядке их загрузки в память.

Сам код перебора простейший. Для удобства я оставил только сам алгоритм, полезную нагрузку вы можете добавить по своему усмотрению.

  1. ; EAX -> PEB
  2. moveax , [ fs : 30h ]
  3. ; EAX -> PEB_LDR_DATA
  4. moveax , [ eax + 0Ch ]
  5. ; EBX -> InInitializationOrderModuleList
  6. movebx , [ eax + 1Ch ]
  7. @ @ :
  8. ; Последняя запись?
  9. cmp [ ebx + LDR_DATA_ENTRY . BaseAddress ] , 0
  10. ; Остановить обработку
  11. je @ f
  12. . . .
  13. . . .
  14. ; EBX -> LDR_DATA_ENTRY
  15. ; Выполнить нужные действия
  16. . . .
  17. . . .
  18. ; Указатель на следующую запись
  19. movebx , [ ebx + LDR_DATA_ENTRY . InMemoryOrderModuleList . Flink ]
  20. jmp @ b
  21. @ @ :

Так же не забывайте, что все строки в структурах хранятся в юникоде. При необходимости конвертируйте их в нужный формат.

Ну и, напоследок, ответ на традиционный вопрос "зачем это нужно?". Например, таким способом защитный модуль программы может контролировать, что все используемые системные библиотеки загружены из системной директории. Для взлома некоторых приложений используются так называемые прокси-dll, которые имеют имя одной из системных библиотек, импортируемых приложением, но загружаются из папки с программой, после чего патчат в памяти пару условных переходов ;) Подобная проверка сможет затруднить такой метод взлома. Зная имена загруженных библиотек, приложение может проверить их на предмет модификации, сравнив образ в памяти с файлом на диске. Это затруднит отлом защиты через сплайсинг вызываемых системных функций. Еще приложение может контролировать, чтобы в его адресное пространство не было загружено никаких посторонних библиотек, например, модулей перехвата различных API Monitor'ов. А поскольку код проверки не использует вызовы API, его легко замаскировать или как-нибудь обфусцировать. Ну а реверсерам, в свою очередь, будет полезно знать о таких методах защиты.

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

В процессе отладки в Visual Studio окно Модули отображает список используемых приложением библиотек DLL и исполняемых файлов ( .exe), а также сведения о них.

Окно "Модули" недоступно при отладке SQL и скриптов.

Использование окна модулей

Чтобы открыть окно "Модули" во время отладки, выберите Отладка > Окна > Модули или нажмите клавиши CTRL+ALT+U.

По умолчанию модули в окне Модули упорядочены в порядке загрузки. Чтобы выполнить сортировку по любому столбцу окна, щелкните заголовок соответствующего столбца.

Загрузить символы

В столбце Состояние символов в окне Модули показано, для каких модулей загружены отладочные символы. Если здесь указано состояние Загрузка символов пропущена, Невозможно найти или открыть PDB-файл или Загрузка отключена параметром включения и исключения, вы можете загрузить символы вручную. Дополнительные сведения о загрузке и использовании символов см. в статье Указание файлов символов (.pdb) и исходных файлов.

Загрузка символов вручную

В окне Модули щелкните правой кнопкой модуль, для которого не загружены символы.

Выберите Сведения о загрузке символов, чтобы узнать, почему символы не были загружены.

Щелкните Загрузить символы, чтобы загрузить символы вручную.

Если символы не загружаются, выберите Параметры символов, чтобы открыть диалоговое окно Параметры и указать или изменить расположение для загрузки символов.

Вы можете скачать символы с общедоступных серверов символов Майкрософт или других аналогичных серверов, а также загрузить их из локальной папки на компьютере. Дополнительные сведения см. в разделе об указании расположения символов и поведения при загрузке.

Изменение параметров поведения при загрузке символов

В окне Модули щелкните правой кнопкой мыши любой модуль.

Выберите Параметры символов.

Выберите Загрузить все символы или выберите конкретные модули.

Изменение поведения загрузки символов для конкретного модуля

В окне Модули щелкните правой кнопкой мыши требуемый модуль.

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

Изначальная задача - загрузка DLL и вызов её функционала.

Перед началом использования, возник вопрос, а какие из DLL, лежащие у себя в WINDOWS// уже загружены системой, и подковырка - кем загружены (т.е. косвенно = потенциальное время жизни, т.к. например если ОС загрузила либу* то скорее всего данная либа будет висеть до выключения компа, если же какая то сторонняя программа - то всегда проверять перед использованием)
*тут тоже вопрос, что именно в ОСи грузит (системные?) либы, тоже наверно какой то процесс, хотелось бы знать какой..

Добавлено через 1 час 29 минут
Нашёл тут пару строк инфы по моему вопросу..

В Win32 библиотека DLL располагается в области памяти загружающего ее процесса. Каждому процессу предоставляется отдельная копия "глобальной" памяти DLL, которая реинициализируется каждый раз, когда ее загружает новый процесс. Это означает, что динамическая библиотека не может использоваться совместно, в общей памяти, как это было в Winl6.

И все же, выполнив ряд замысловатых манипуляций над сегментом данных DLL, можно создать общую область памяти для всех процессов, использующих данную библиотеку.

Допустим, имеется массив целых чисел, который должен использоваться всеми процессами, загружающими данную DLL. Это можно запрограммировать следующим образом:

Т.е. в принципе есть 2 варианта:
1. Парсить все процессы на загрузку каких либо ДЛЛ (если можно)
2. Если мы точно знаем адрес, то можем поидее вычислить процесс который её вызвал (исходя из того что написано выше в цитате)
*А вот с общим адресным пространством я что то не догнал.. (ну потому что предшествующие вопросы сначало надо понять как решить).

Вывести список загруженных программ в озу
Искал в интернете но гугл не находит того что мне нужно

Получить список загруженных библиотек конкретного процесса
Можно ли получить список загруженных библиотек(*.so) определенным процессом например по его pid.

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

Искать: Джеффри Рихтер, Windows для профессионалов - есть в Сети в электронном виде (и в pdf, и в html). Там среди приложений-примеров есть ProcessInfo - вот в этом примере есть все, нужное тебе. Ну и немного подпилишь код напильником под свои нужды. Рихтер - это хорошо, конечно, но более правильным будет ответ "с этим не следует заморачиваться, Windows уже сама умеет загружать DLL в единственном экземпляре, разделять её между процессами и следить за временем жизни". а какие из DLL, лежащие у себя в WINDOWS// уже загружены системой, и подковырка - кем загружены

CreateToolhelp32Snapshot. Перебираешь все загруженные в системе модули и
смотришь процессы, в которые они загружены.

В Win32 библиотека DLL располагается в области памяти загружающего ее процесса. Каждому процессу предоставляется отдельная копия "глобальной" памяти DLL, которая реинициализируется каждый раз, когда ее загружает новый процесс. Это означает, что динамическая библиотека не может использоваться совместно, в общей памяти, как это было в Winl6.

В Windows, когда одна и та же dll загружается в разные процессы, система создает
свое отображение этой dll для каждого процесса. Но в физической памяти копия dll
все равно одна (до тех пор, пока кто-нибудь не изменит одну из копий. в этом
случае будет создано второе отображение, уже измененное - это называется
"copy on write").

И все же, выполнив ряд замысловатых манипуляций над сегментом данных DLL, можно создать общую область памяти для всех процессов, использующих данную библиотеку. Лучше так не делать.
У dll с разделяемой памятью есть парочка неприятных особенностей поведения
(проблемы с релоками, проблемы с загрузкой в разных сеансах).
Если нужно расшарить какие-то данные между процессами, то в первую очередь следует
смотреть в сторону стандартных механизмов IPC - каналы, COM/RPC, events и т.д.

Спасибо большое, всё работает ок, на MSDN целый пример по этому поводу.

Тут появилась трудность, нужно получить текущий процесс и инфу только по нему. Нашёл несколько вариантов решения, но они все кривые..
1. Можно парсить по имени из Process Name.
2. Можно в main взять GetCurrentThreadId(), и далее опять же парсером перебирать все процессы, а внутри процесса, так как в мсдн - брать уже ветви, и сравнивать.

Хотелось бы как то без цикла.. (ведь мне нужны не все процессы а только один)
Как взять не thread, а сам ProcessID? (есть может функция наподобии
GetCurrentThreadId, только для процесса? чтоб сунуть его сразу для получения инфы в ListProcessModules и ListProcessThreads минуя Process32First/Next)

Добавлено через 5 минут
Сам нашёл, видимо не там смотрел)) GetCurrentProcessId

Как вы знаете, если вызов LoadLibrary указывает DLL-модуль, уже отображенный в адресное пространство вызывающего процесса, функция просто возвращает дескриптор DLL и увеличивает количество ссылок на модуль.

Где-то мне нужно получить ссылочный счет dll. Как получить счетчик ссылок DLL? Как узнать, где была загружена dll? Спасибо.

ОТВЕТЫ

Ответ 1

Я искал его и нашел эту статью , которая утверждает, что дает ответ. Извините, я не могу быть более полезным:

Ответ 2

Если это не программный способ (благодаря C.Johnson для предоставления этой перспективы), WinDBG может быть полезным

Посмотрите на! dlls и его варианты.

! dll - все загруженные модули с нагрузкой кол

Если вы хотите узнать, откуда все DLL загружается из процесса, есть два способа:

а. Посмотрите на команду

в приведенном выше URL

б. Запустите процесс под WinDBG. Debug- > Even Filter и выберите "Load Module" и установите "Enabled" в "Execution". В разделе "Продолжить" установите значение "Не обрабатывается".

Один из них должен помочь вам определенно.

Ответ 3

Это "скрытый" способ получить информацию о любых обработанных обработанных dll файлах. Он работает в Windows 10. Обратите внимание, что ustring - это моя личная специальная реализация строки, которую можно заменить соответствующим образом. Стоит отметить, что peb_ldr_data.InMemoryOrderModuleList.Flink. Его связанный список со всеми загруженными DLL. В документации MSDN говорится, что при достижении последней записи он укажет на себя. ЭТО НЕ ОТНОСИТСЯ К ДЕЛУ. Он хорошо возвращается к первой записи в списке. По крайней мере, в Win10 Pro. LDR_MODULE:: LoadCount - это то, что вы ищете, я верю.

hmmm Удерживать abit. в Win10 может не получиться правильно. Вернемся.

3 вещи есть релевантные. И он работает в Win 10, но LoadCount не показывает количество ссылок. Только если его динамический (6) или статический (-1)

PEB_LDR_DATA: Существуют разные структуры, плавающие вокруг. Системный:

И в некоторых пользовательских примерах пользователь определил:

Это начинает становиться беспорядком. Они оба работают, но, как подозревают. Память каким-то образом компенсируется. Тем не менее вы можете получить информацию о загруженных модулях процесса (произвольной программе Exe), но LoadCount не показывает фактическое количество ссылок в Windows > 7.

Btw я снова проверил использование структуры PEB_LDR_DATA, определенной USER. Система генерирует неточность. Некоторые члены LDR_MODULE становятся ненужными. Зачем? Я не знаю. ( "Det fixar båtklubben. " ).

Ответ 4

Я не уверен, что вы полностью понимаете, как LoadLibrary/FreeLibrary должен работать. Вы вызываете FreeLibrary , когда вы закончите с ним, и это уменьшает счетчик ссылок, который был увеличен при его загрузке. Если какая-то другая часть вашего процесса все еще использует его, возможно, это не ваша проблема.

Счетчик ссылок может рассказать вам, сколько раз он был "загружен", но не поможет выяснить, кто его загрузил.

Ответ 5

Эта информация недоступна через публичный API afaik. Каков ваш сценарий? Запуск AppVerifier будет устранять любые ошибки, которые вы совершили с помощью модулей (или любых других).

Ответ 6

Вы можете перечислить загруженные модули в процессе с помощью Module32First() / Module32Next() , а затем использовать MODULEENTRY32.GlblcntUsage , чтобы проверить его количество ссылок. Я не уверен, насколько это надежно.

Ответ 7

Пожалуйста, введите код ниже. Примечание. Я написал код ниже в Visual Studio 2010.

Ответ 8

Протестировано в Windows 8.1. Не гарантирует, что это будет работать на более новых окнах (например, 10, однако - согласно документации должно работать)

Читайте также: