Объект загружаемой системной библиотеки

From SunFlurry wiki
Jump to: navigation, search
  Lib (Объект загружаемой системной библиотеки)
Статус разработки: Реализован
Создание объекта: Load

Объект системной библиотеки используется для доступа к внешним функциях системы или расширения функционала программы за счет функций, находящихся во внешних библиотеках (dll для Windows). Важно: вызовы подобного рода часто оперируют данными, находящимися в системной памяти, изменение или чтение которых может привести к системным исключениям или порче информации в памяти, поэтому работа с внешними библиотеками опасна. Для импортирования функций, нужно знать некоторые важные термины и полностью понимать, что они означают:

  • Размер чисел в битах. Система всегда использует 64-битный формат представления целых чисел, однако, библиотеки часто требуют использование чисел, меньшего размера.
  • Наличие знака у числа. Система всегда использует числа со знаками, однако, библиотеки иногда оперируют числами, верхний бит которых, является частью данных, а не представляет знак. К примеру, число в 8 бит без знака может иметь значение 240, со знаком это число равно -16
  • Способ вызова (Calling convention). Для работы с x86 библиотеками важно знать, каким образом происходит вызов их функций. Таких способов вызова может быть несколько, при применении неверного способа вызова можно не только получить исключение, но и испортить память, сделать программу нерабочей. Для x64 используется один способ вызова, поэтому, такой проблемы для этой архитектуры не существует (существует второй способ vectorcall, который на данный момент не поддерживает системой). Способ вызова обычно можно найти в документации к библиотеке или в include файлах с расширением h или подобным. Следующие способы вызова поддерживаются системой:
    • stdcall (x86,x64) -- стандартный способ вызова функций Windows, используется по умолчанию. Для x64 является единственным доступным способом вызова.
    • cdecl (x86) -- используется при вызове функций, скомпилированных с помощью C или C++. Система позволяет использование такого способа вызова вместо вызовов stdcall, но не наоборот. Если для библиотек, скомпилированных со способом вызова cdecl указать способ вызова stdcall, можно получить порчу памяти или привести клиент нерабочее состояние.
    • fastcall (x86) -- используется при вызове функций, скомпилированных с помощью C или C++. Несовместим с другими способами вызова.
    • register (x86) -- используется при вызове функций, скомпилированных с помощью Delphi или Free Pascal. Несовместим с другими способами вызова.
      • Для способов вызова register первые четыре параметра передаются в функцию особым образом, однако, для особых параметров, типа Variant (OLE), структура (запись) система может не знать, что такие параметры должны содержаться в стеке вызова, поэтому их нужно пометить особым образом (см. Load). Для получения дополнительной информации, см. статью.
    • vectorcall (x86,x64) -- способ вызова, оперирующий длинными числами (128 бит), в данный момент не поддерживается.
  • Вызовы by ref. Как и в языке системы, функции библиотек иногда могут изменять передаваемые им параметры. Данный факт должен быть указан при импортировании функции, иначе система не будет обновлять возвращенные функцией параметры (см. Load).
  • Адресация строк. Любые строки при вызове всегда должны быть заданы, как ссылки, см. Load.

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

Function EnablePrivilege(PrivName)
  //Загрузка библиотек и импортирование функций.
  aKernel32:=Lib.Load("kernel32.dll");
  aKernel32.RegisterFunction("GetCurrentProcess","stdcall",,"UN");
  aKernel32.RegisterFunction("CloseHandle","stdcall","UN","UN");
  aAdvapi32:=Lib.Load("advapi32.dll");
  aAdvapi32.RegisterFunction("OpenProcessToken","stdcall","UN,UI32,@UN","B32");
  aAdvapi32.RegisterFunction("LookupPrivilegeValueW:LookupPrivilegeValue","stdcall","^SZW,^SZW,@I64","B32");
  aAdvapi32.RegisterFunction("AdjustTokenPrivileges","stdcall","UN,B32,P,UI32,P,@UI32","B32");
  //Описание констант
  TOKEN_ADJUST_PRIVILEGES:=32;
  TOKEN_QUERY:=8;
  SE_PRIVILEGE_ENABLED:=2;

  //Получение идентификатора процесса
  hToken:=0;
  If not aAdvapi32.OpenProcessToken(aKernel32.GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES+TOKEN_QUERY,hToken) then
    Exit 0;
  EndIf;
  Try
    //Получение идентификатора привилегии по ее имени
    Luid:=0;
    if not aAdvapi32.LookupPrivilegeValue(,PrivName,Luid) Then
      Exit 0;
    EndIf;
    //Создание структуры для передачи функции установки привилегии
    rLUID_AND_ATTRIBUTES:=MemoryRecord.Create("Luid:I64,Attributes:UI32");
    rTOKEN_PRIVILEGES1:=MemoryRecord.Create("PrivilegeCount:UI32,Privileges:A1:@rLUID_AND_ATTRIBUTES");
    rTOKEN_PRIVILEGES1.Allocate();
    rTOKEN_PRIVILEGES1.PrivilegeCount:=1;
    rTOKEN_PRIVILEGES1.Privileges[0].Attributes:=SE_PRIVILEGE_ENABLED;
    rTOKEN_PRIVILEGES1.Privileges[0].Luid:=Luid;
    //Установить привилегию
    Exit aAdvapi32.AdjustTokenPrivileges(hToken,0,rTOKEN_PRIVILEGES1,0);
  Finally
    //Закрыть идентификатор процесса
    aKernel32.CloseHandle(hToken);
  EndTry;
EndFunction;

//Пример вызова функции
Message("Привилегия установлена "+?(EnablePrivilege("SeBackupPrivilege"),"удачно","не удачно"));

Атрибуты и функции

Идентификатор Статус Тип Визуальная Параметры Описание
<Имя функции> Реализована Функция Lib.<Имя функции>(<Аргумент 1>,<Аргумент 2>,...):<Возвращенное значение> Функция вызывает зарегистрированную ранее функцию библиотеки по ее имени.
SystemAddress Реализована Атрибут CBFunction.SystemAddress Атрибут получает системный указатель (адрес) функции обратного вызова. Данный указатель можно передавать во внешние потоки или приложения, либо в системные вызовы, как указатель для вызова адресуемой функции обратного вызова.
Load Реализована Функция Lib.Load(<Путь и имя библиотеки (STRING)>):<Новый объект (LIB)> Функция производит попытку загрузки указанной библиотеки в память. Если путь не указан, операционная система ищет файл библиотеки в стандартных папках, заданных в переменных окружения. Если для загрузки библиотеки требуется загрузить еще какую-либо промежуточную библиотеку, последняя должна также находиться по указанному пути (либо быть доступна в окружении). В момент загрузки клиент временно меняет текущую директорию в соответствии с путем загрузки, чтобы предусмотреть такие случаи. Если библиотека (или связанные с ней библиотеки) не найдена, функция вызовет исключение. Клиент автоматически вызовет функцию отмены загрузки библиотеки, когда объект будет удален из системы. Функция не принимает серверного пути для загрузки. Если необходимо использовать файл, находящийся на сервере, его необходимо сначала скопировать на локальный компьютер (к примеру, во временную папку).
RegisterFunction Реализована Функция Lib.RegisterFunction(<Имя функции (STRING)><Способ вызова (STRING)>="Stdcall",<Аргументы функции (STRING)>,<Возвращаемое значение (STRING)>) Функция производит попытку импорта функции по ее имени из библиотеки, если функция найдена, она будет добавлена к функциям, которые возможно вызвать из данного объекта. Для функции задается, если необходимо, список и типы данных аргументов, а также тип данных возвращаемого значения, если оно присутствует.
CallFunction Реализована Функция Lib.CallFunction(<Имя функции (STRING)><Аргумент 1>,<Аргумент 2>,...):<Возвращенное значение> Функция вызывает зарегистрированную ранее функцию библиотеки по ее имени. Она отличается от непосредственного вызова функции <Библиотека>.<Имя функции>(<Аргументы>...) тем, что поддерживает имена с нестандартными символами и позволяет вызывать функции, имена которых хранятся в переменных, что иногда необходимо при написании сложных участков программ.
CreateCallbackFunction Реализована Функция Lib.CreateCallbackFunction(<Имя функции (STRING)>,<Глубина поиска (INT)>=0,<Способ вызова (STRING)>="Stdcall",<Аргументы функции (STRING)>,<Возвращаемое значение (STRING)>):<Новый объект функции обратного вызова (CBFUNCTION)> Функция создает особую область в памяти, вызывая которую, любая внешняя библиотека или приложение будут автоматически вызывать указанную локальную функцию. Аргументы вызова по переводятся по заданным правилам в объекты системы. Локальная функция, кроме возврата реультата, может изменить аргументы, которые возвратятся на вызывающую сторону, если они помечены, как изменяемые аргументы. Функция может быть вызвана как из того же самого системнго потока, так и из любого другого (однако, в последнем случае, если исходный поток занят выполнением программы в момент вызова, будет создано исключение). Обычно такие функции могут пригодиться, если вызов системной библиотеки включает обратный вызов для перечисления результатов или индикации выполнения какого-либо процесса.