May 302013
 

Автор: joaquimandrade

Модуль Orpheu дает скриптеру возможность использовать функции, которые было бы невозможно использовать без него (включая функции от других плагинов MetaMod).Модуль работает, как на Windows, так и на Linux.
Начиная с версии 2.1 ( 29 января 2010 г.), Orpheu также поддерживает прямой доступ к памяти.

Суть работы заключается в следующем:
Модуль использует преобразования между типами С++ и Pawn, и позволяет вызывать функции, указав ее адрес в памяти, а также используемые ею аргументы. Этот метод включает в себя общие принципы работы со структурами С++.

Например, предположим, что вы хотите использовать эту функцию:
void PM_Move( struct playermove_s *ppmove, qboolean server)

Она получает один аргумент типа “playermove_s” и другой типа “qboolean”. Значения эта функция не возвращает.

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

Существует несколько способов поиска функций в библиотеках:

  • путем поиска по имени: в библиотеках, компилированных в Linux, символьные имена функций закреплены за самими функциями. К несчастью, этого не происходит, если библиотека скомпилирована для Windows, что делает этот способ бесполезным, если у Вас нет исходника библиотеки и Вы не можете скомпилировать его самостоятельно так, чтобы он передавал символьные имена для функций. В этой статье описаны методы для использования функций модуля MonsterMod.
  • путем нахождения набора байтов в памяти, относящихся конкретно к данной функции. Данный метод называется «сканированием сигнатур» (“signature scanning”). В общем об этом методе написано здесь, более подробно здесь и здесь. В общем, этот метод позволяет обращаться к любой функции в памяти, как только вы найдёте ее. Чтобы толком разобраться в этом, вам необходимо узнать немного больше об этом методе, что вы можете сделать по ссылкам выше. (Прим. перевод.: На нашем сайте эти статьи в скором времени будут переведены, как только мы это сделаем, заменим ссылки)
  • путем получения адресов во время использования плагина. Если вы можете найти адрес функции программно, то вы можете использовать этот вариант. Это возможно, благодаря использованием модулем основных функций движка. Эти функции предусмотрены в AMXModX и без этого модуля, однако при его использовании, вы можете перехватить эти адреса в большинстве случаев (например, когда функции вызываются другими плагинами MetaMod).

Добавлено в 2.1

  • путем поиска оффсетов функций в библиотеке. Этот метод используется для быстрого тестирования и на него не следует полагаться, так как найденные оффсеты могут оказаться неправильными при обновлении или изменение библиотеки.
  • путем нахождения указателя функции в виртуальной таблице функций класса. Этот способ позволяет использовать множество функций, путем обнаружения всего лишь указателя. Метод был взят из Hamsandwich и переделан для использования в Orpheu. Он дает возможность захвата виртуальной функции энтити и объекта, например, CGameRules. В отличии от версии Hamsandwich добавлено следующее: теперь набор кодированных напрямую функций не ограничен, а также Вы можете захватывать некоторые зависящие от мода функции, которые не могли быть захвачены ранее.

Чтобы передать модулю информацию о функции, вы должны создать файл, отформатированный в соответствие стандарту JSON и поместить в папку “configs/orpheu/functions”.

Для функции:
CMBaseMonster* spawn_monster(int monster_type, Vector& origin, float angle, int respawn_index)

Содержимое файла будет таким:

  • поля “info” не обязательны;
  • поле “name” должно совпадать с именем фала;
  • имя библиотеки “mod” для модов, как cstrike, и “engine” для dll движка. Для библиотек MetaMod вам необходимо создать файл, как тот, что Вы можете найти в директории “configs\orpheu\libraries”, что содержит пару libraryname/libraryCvar, таким образом модуль распознается, как один из модулей Cvar.
  • “identidiers” – это список групп “os”/”value” для идентификации функции. В случае, если библиотека – “mod”, необходимо добавить дополнительное поле “mod”. Пусть смысл этого поля исключительно формален, однако само поле обязательно. Оно должно выглядеть так:
    "mod" : "cstrike"

В этом случае для ссылки на функцию используется метод определения имени. В случае использования сигнатур, поле “value” будет представлено последовательностью байтов, “*” или “?”, например:
"value" : [0x1,"*","?"]

“*” необходимо использовать в том случае, если значение этих байтов не важно.

То есть значение
"value" : [0x1,"*"]
равносильно
[0x1,0x0] , [0x1,0x1] , ... [0x1,0xFF].

“?” необходимо использовать, если не важно не только значение этих байтов, но и само их существование.
То есть
"value" : [0x1,"?"]
предполагает значения
[0x1] , [0x1,0x0] , [0x1,0x1] , ... [0x1,0xFF].

JSON – это широко распространенный тип файлов. Чтобы убедиться в том, что файл корректно отформатирован, вы можете использовать валидатор. В этом проекте я немного изменил библиотеку для того, чтобы JSON мог прочитать байты. Это делается для проверки файлов, не содержащих сигнатуры.

Отдельно, стоит упомянуть о функциях, принадлежащих к классу, например:
void CMController :: HandleAnimEvent( MonsterEvent_t *pEvent )

В данном случае необходимо создать папку под именем “CMController”, а в ней файл “HandleAnimEvent”. Это обязательно и необходимо для более понятной организации. Вам также необходимо добавить в файл поле “class”. В итоге файл будет выглядеть так:

Другой метод использования функций имеет дело с получением адреса программно. Взгляните на http://metamod.org/sdk/dox/eiface_8h-source.html – строка 100. Здесь представлена структура “enginefuncs_s”. Эта структура содержит адреса функций движка. Модуль имеет возможность оперировать ей. Скажем, что мы хватим захватить функцию расположенную в структуре:
void (*pfnServerPrint)( const char *szMsg );

Необходимо создать такой файл:

Идентификаторы не нужны, так как адрес будет найден во время запуска, программно. В плагине появится:
native OrpheuFunction:OrpheuCreateFunction(address,libFunctionName[],classname[]="")

Затем вы можете захватить или вызвать ее. При захвате функции, Вы можете перехватить сообщение консоли такое же, что появляется при использовании серверной команды “metamod”.
Это один из вариантов (кодированный вручную) метода, использующего функцию, адрес, который есть в плагине. Другой вариант – использовать OrpheuGetDLLFunction для восстановления функций из структуры DLL_FUNCTIONS. http://metamod.org/sdk/dox/eiface_8h-source.html – строка 384. Для обычных случаев используйте native:
native OrpheuFunction:OrpheuCreateFunction(address,libFunctionName[],classname[]="")

Модуль позволяет вам управлять структурами обычным путем. Скажем, что нам необходимо захватить функцию PM_Move, которая может быть найдена в структуре DLL_FUNCTIONS. Файл:

Захват:

Первый аргумент функции – структура. Вы можете увидеть это здесь. http://metamod.org/sdk/dox/eiface_8h-source.html – строка 92. Далее имеем дело с данными структур:

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

Список поддерживаемых типов данных:

Список поддерживаемых структур:

Я добавлю несколько практических примеров позже. Если модуль не запускается на вашем устройстве Linux, то вам следует установить libstdc++.
Следующий материал действителен для Orpheu 2.1 и выше.
В версии 2.1 была добавлена поддержка виртуальных функций (основано на Hamsandwich) и поиска/исправления памяти (основано на Mem Hack).

Виртуальные функции:
Виртуальные функции – это функции, предоставляющие совместные ресурсы для нескольких различных классов (как Spawn) и, соответственно, по другому осуществляющие это предоставление. Способ, которым функции компилируются, позволяет размещать их в памяти, путем обеспечения их простыми числовыми оффсетами. Ссылки на функции хранятся в таблице так, что каждый объект класса может взаимодействовать с ними.
Эта таблица для мода Counter Strike, восстановленная из собственного Linux-файла класса CHalfLifeMultiplay для CGameRules. (Каждая строка содержит символьное имя представляемой функции):

Чтобы использовать одну из них вам необходимо создать файл, который должен выглядеть так:

(В Linux виртуальная таблица включает дополнительную функцию в начале, так что оффсеты должны быть увеличены на единицу)

Это описание функции должно быть размещено в каталоге “VirtuаlFunctions” в папке “CGameRules” в файле “GetNextBestWeapon”.

Теперь вы можете использовать эти функции в плагине несколькими командами, выглядящими так:

Первые две работают точно также как и в Hamsandwich:

  • Первая вызывает функцию, основанную на классе энтити.
  • Вторая вызывает функцию, основанную на самом энтити.

Для использования функций из CHalfLifeMultiplay, описанных выше, нам необходим нативная функция OrpheuGetFunctionFromObject. Эта функция вызывает функцию, базированную на объекте, класс которого вам необходим, таким образом нам необходим дополнительный шаг для получения объекта. Это один из путей решения для этого частного случая:

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

OrpheuMemorySet("awpCost",1,1000)

Это всего лишь пример для “windows” и “cstrike”, однако сам модуль может быть использован и для Windows, и для Linux, а также для любого мода. Большую информацию читайте по ссылкам ниже.

Примечание: если необходимо заменить строки, напрямую размещенные в памяти (таких большинство), вам следует использовать тип “string” вместо “char *”.

Ссылки.
http://jsoncpp.sourceforge.net/
http://www.boost.org/
http://forums.alliedmods.net/showpost.php?p=994447&postcount=2

Перевод: Dani Minch
PS статья переводилась около 3-4 часов подряд и потом почти не изменялась, могут быть загоны) если что пишите в комментариях

Статьи по теме:
Orpheu: Поиск функций в библиотеках
Сигнатуры функций.

Dani Minch

Тот парень. Что-то пишу, когда не лень.

Оставить комментарий

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