RunDll32 - вызов функций библиотек DLL

Метки:  , , , , , ,

RunDll32 - утилита командной строки, которая разработана для загрузки и запуска функций из 32-битных и 64-битных библиотек DLL. Многие полагают, что rundll32 это средство для запуска DLL как исполняемого приложения. В действительности же, нет такого понятия как “запуск DLL”, поскольку это не исполняемый файл в чистом виде (вроде EXE). В библиотеках DLL содержатся только функции (процедуры), поэтому и вызываться могут только функции. Отсюда и следует определение того, что утилита rundll32.exe используется для запуска функций (процедур) хранящихся в библиотеках DLL.
Rundll32 позволяет получить доступ только к функциям/процедурам внутри библиотеки DLL, которые были написаны строго определенным образом. Мало того, что вызываемые функции должны быть экспортируемыми, так они еще должны удовлетворять специфичным требованиям к описанию входных параметров. Функции библиотек, которые не помечены как экспортируемые, запускаться посредством rundll32 не могут.

Немногим известно, что rundll32 может использоваться для запуска функций из любых типов файлов, построенных по схожему с библиотеками DLL принципу: элементов ActiveX с расширением .ocx, апплетов панели управления с расширением .cpl, драйверов с расширением .drv. Проанализируйте, на досуге, структуру этих файлов и сравните её со структурой DLL.

Бытует мнение, что утилита rundll32 изначально была спроектирована разработчиками для внутренних нужд самой ОС, то есть использовалась системой Windows для запуска ограниченного количества функций системных DLL.

Утверждается, что когда-то давным-давно функциональные особенности rundll32 были неявными, то есть “скрытыми” от пользователя системы. Со временем утилита rundll32 превратилась в достаточно продвинутое средство, и в определенный момент, по причине того, что программа предоставляла возможности общего характера, разработчики решили включить её в комплект ОС в виде отдельной утилиты. В состав Microsoft Windows 95, Windows 98 и Windows Millennium входили программы rundll.exe и rundll32.exe. А в операционных системах Microsoft Windows NT 4.0, Windows 2000? Windows XP, в состав ОС включена лишь одна утилита rundll32.exe.

Стоит обратить внимание на то, что в Windows Vista/7 и более поздних ОС, утилита rundll32 не рекомендуется к использованию и включена только лишь с целью сохранения совместимости со старыми приложениями.

Причина подобного отношения кроется в многочисленных проблемах, связанных с использованием rundll32 в своих программных окружениях. Как же без rundll32, спросите Вы? Оказывается, Microsoft активно пишет специализированные системные утилиты, которые постепенно заменяют функционал полюбившегося нам многочисленного программного функционала. Поэтому, время от времени в процессах Windows 7 можно таки встретить процесс rundll32, однако встречается подобное явление всё реже и реже. :)

Файл всегда размещен в каталоге %SystemRoot%\System32 для 32-битных версий Windows 2000/XP/Vista/7 и в каталогах %SystemRoot%\System32 и %SystemRoot%\SysWOW64 для 64-битных версий Windows Vista/7. В случае обнаружения файла с именем rundll32.exe в любом другом каталоге он должен быть незамедлительно удален и станция должна быть просканирована на наличие вирусов.

Алгоритм работы rundll32

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

  1. Вызывается функция LoadLibrary(), которая загружает выбранную DLL;
  2. Вызывается функция GetProcAddress(), для получения адреса точки входа вызываемой из библиотеки функции;
  3. Вызывается сама функция и ей передаются входные параметры;
  4. Происходит выход из функции по завершению её работы;
  5. Библиотека DLL выгружается системой из памяти.

Как увидеть полный путь запуска rundll32

Если в системе ни с того ни с сего вдруг удалось обнаружить запущенный процесс rundll32, и вам стало интересно, а какой же, собственно, функционал утилита запустила, то можно определить это по полному пути запуска утилиты rundll32. Посмотреть полный путь запуска, то есть параметры командной строки можно при помощи системной утилиты task manager.
Вызовите "Диспетчер задач" (Ctrl+Shift+Esc), перейдите в меню "Вид", выберите пункт "Выбрать столбцы.." и пролистав список вниз, найдите пункт "Командная строка" и отметьте его чекбокс, затем нажмите ОК.
Результатом будет появление в главном окне диспетчера задач в параметре "командная строка" полной строки запуска rundll32.

Командная строка rundll32

32-битные и 64-битные версии программы

В 64-битных версиях ОС семейства Windows присутствуют 2 варианта программы rundll32.exe:

  • 64-битная версия, расположенная в %SystemRoot%\System32\;
  • 32-битная версия, расположенная в %SystemRoot%\SysWOW64\.

В 64-битной ОС, для загрузки 64-битной библиотеки DLL может быть использована 64-битная версия rundll32.exe, находящаяся в директории %SystemRoot%\System32\. Напротив, 32-битные программы в 64-битной ОС, обращающиеся к %SystemRoot%\System32\, в целях обеспечения совместимости будут перенаправлены в %SystemRoot%\SysWOW64\ и, соответственно, будут использовать уже 32-битную версию rundll32.exe.

Пример использования rundll32

Для запуска программы rundll32 используется синтаксис командной строки следующего вида:

rundll32.exe <имя_библиотеки_dll>, <необязательные_параметры_функции>

В качестве примера предлагаю разобрать команду запуска апплета "Язык и региональные стандарты" панели управления, вкладка "Форматы":

rundll32.exe shell32.dll,Control_RunDLL intl.cpl,,0

При выполнении данной команды утилита rundll32 вызовет функцию Control_RunDLL(), находящуюся в библиотеке shell32.dll, и передаст ей следующие параметры:

Параметр Описание
hWnd Идентификатор (дескриптор) родительского окна, который обычно используется при создании окон в функциях загружаемой библиотеки DLL.
hInstance Дескриптор (заголовок экземпляра) выбранной библиотеки DLL. Иначе, стартовый адрес процесса DLL в адресном пространстве. В нашем случае - библиотеки shell32.dll.
lpCmdLine Командная строка, передаваемая библиотеке. То есть параметры, передаваемые самой библиотеке. В нашем случае "intl.cpl,,0";
nCmdShow Режим отображения окон выбранной библиотеки. (данные, передаваемые функции CreateProcess).

Теперь давайте отметим и некоторые требования к синтаксису rundll32:

  • Параметр, описывающий точку входа вызываемой функции (EntryPoint) чувствителен к регистру. Это означает, что значение Control_RunDLL не тоже самое что control_rundll. Довольно часто неправильное указание регистра символов вызываемой функции приводит к ошибкам ненахождения последних.
  • Функция (в приведенном выше примере — функция Control_RunDLL()) должна самостоятельно выполнять анализ командной строки и идентифицировать отдельные ее аргументы.
  • Программы rundll и rundll32 ищут указанную библиотеку DLL в стандартных местоположениях. В нашем примере библиотека shell32.dll располагается по известному в переменной %PATH% пути, поэтому мы и указываем её в сокращенном виде. Чтобы быть уверенным, что будет загружена именно интересующая нас библиотека DLL, рекомендуется конкретизировать полный путь к файлу библиотеки. В противном случае может возникнуть ситуация, когда в системе может присутствовать одноименная библиотека, находящаяся в стандартном местоположении (например, по путям, определяемым %PATH%), а та, которую хотите использовать Вы, находится по неизвестному системе пути, в этом случае утилитой rundll32 будет вызвана первая библиотека.
  • <имя_библиотеки_dll> не должно содержать недопустимых символов: пробелов, запятых и кавычек (ограничение это накладывается кодом анализатора командной строки утилиты rundll32).
    Ранее, во времена Windows 95/98, к синтаксису командной строки утилиты rundll32 применялись достаточно жесткие требования. Например, чрезвычайно важным являлось наличие запятой (",") между параметром <имя_библиотеки_dll> и именем вызываемой функции. Если запятая пропускалась, утилита rundll32 по-тихому завершала работу, не выполняя никаких действий с библиотекой и ничего не отображая на консоли. Кроме того, между параметром <имя_библиотеки_dll>, символом запятой и названием вызываемой функции не должно было быть никаких пробелов. Но, со временем, видимо, анализатор командной строки утилиты претерпевал изменения и эволюционировал, и в данный момент, синтаксис rundll32 позволяет применять пробел между именем библиотеки и именем функции.

Правила создания функций

Очевидно, что в создаваемую нами пользовательскую библиотеку DLL нам необходимо поместить функцию со входными следующими параметрами.
Пример описания процедуры на языке Ассемблера:

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

  1. Вместо строки "EntryPoint", желательно указать фактическое имя функции. Обратите внимание, что "точка входа", используемая программой rundll32, не зависит от функции DllEntryPoint, которая в 32-разрядных библиотеках DLL осуществляет обработку процессов и оповещение о подключении и отключении потоков. Это точка входа в саму функцию.
  2. Функцию, являющуюся точкой входа для программы rundll32, необходимо определить, используя соглашение о вызовах _stdcall (в C++ по умолчанию для атрибута _stdcall используется значение CALLBACK). Иначе, по умолчанию будет использоваться другое соглашение о вызовах _cdecl. Это приведет к аварийному завершению работы программы rundll32 после вызова данной функции.

Функции, являющейся точкой входа, передаются следующие параметры:

Параметр Описание
hWnd Идентификатор (дескриптор) родительского окна, который обычно используется при создании окон в функциях загружаемой библиотеки DLL.
hInstance Дескриптор (заголовок экземпляра) выбранной библиотеки DLL. Иначе, стартовый адрес процесса DLL в адресном пространстве.
lpCmdLine Командная строка, передаваемая библиотеке. Данная строка представляет собой последовательность символов, завершающуюся символом с кодом 0.
nCmdShow Режим отображения окон выбранной библиотеки. (данные, передаваемые функции CreateProcess).

Пример создания экспортируемой функции DLL

Я написал пример на языке ассемблера, уж не обессудьте :) На этом языке я хоть как-то могу выражать свои мысли в области программирования. Компилируется все это дело через компилятор FASM, версией для Windows (FASMW.EXE). В DLL я описал одну единственную экспортируемую функцию под названием ShowErrorMessage, которая выводит на экран окно ошибки с заданными параметрами. Создадим файл testdll.asm и добавим в него следующее содержимое:

После компиляции у нас в рабочей директории создается файл testdll.dll, поэтому для проверки функционала можно вызвать команду:

rundll32 testdll.dll,ShowErrorMessage ThisIsTestString

  • Поделиться:

2 комментария:

  1. example

    А какие есть еще варианты загрузки dll?

    • einaare

      Вы имеете в виду пользовательский метод или общесистемный? то есть приложения (утилиты ком. строки) или системные механизмы загрузки (вроде Loadlibrary)?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *