Linux hook process start

Hook в Линукс

Существует ли в линукс, что-нить на подобие виндовых хуков? киньте плиз пару ссылок на эту тему

Re: Hook в Линукс

Заранее извиняюсь, если неправильно вопрос понял.

В ядре Windows нет хуков (официально; бэкдоры не в счет). Хуки есть в стандартных виндовых либах, работающих в юзер-спэйсе — comdlg32.dll или что-то типа того.

Linux — это ядро, и в нем, так же как и в ядре Windows, хуков нет (автозапуск ядром /sbin/init, /sbin/modprobe и т.п. — это наверно не то что тебя интересует).

Если же речь идет о графической либе, работающей в юзер-спэйсе, то надо читать доку на эту либу. Если либа на С, то там может и нужны хуки. Если на С++, то поведение класса переопределяется его наследованием и переопределением в наследнике нужных виртуальных функций. И в том, и в другом случае нужно читать доку на конкретную либу.

Может быть, уточнишь вопрос?

Re: Re: Hook в Линукс

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

Re: Re: Re: Hook в Линукс

>Под хуками я понимал технику при помощи которой можно перехватывать оконные сообщения и другие события ситемы до того как они попадут окну адресату. класический пример клавиатурный шпион. Другими словами мне нужно получать все сообщения системы (адресованные не только моему приложению) — в винде это реализуется при помощи хуков либо перехвата API функций, а вот линуксе я не знаю, как это можно реализовать.

Дело в том что в Linux как это уже было сказано GUI не является частью «API» (если такие термины вам ближе)

Перехват клавиатурных сообщений в общем случае можно реализовать на уровне ядра (в Inet даже можно найти примеры на эту тему c примерами соответствующих LKM).

Если речь идет о X11

то на уровне Xt это всякие XGrab* и X*Hook*

Re: Re: Re: Hook в Линукс

> мне нужно получать все сообщения системы

Не прокатит. AFAIK, заграбить в иксах можно только то, что не было заграблено кем-то раньше. Оконный манагер всяко-разно перехватывает клаву и/или крысу — хотя бы некоторые кнопки/клики. Он стартует раньше твоей проги, а значит твоя прога обломится при попытке заграбить то же самое — получит BadAccess и вылетит (если ты не перехватишь ошибки через XSetErrorHandler).

Re: Re: Re: Re: Hook в Линукс

Всем спасибо! теперь понятно в какую сторону копать.

Источник

Патчим процессы в Linux на лету при помощи GDB

Техники перехвата функций в Linux хорошо известны и описаны в интернете. Наиболее простой метод заключается в написании динамической библиотеки с «функциями-клонами» и использовании механизма LD_PRELOAD для переопределения таблицы импорта на этапе загрузки процесса.

Недостаток LD_PRELOAD в том что необходимо контролировать запуск процесса. Для перехвата функций в уже работающем процессе или функций отсутствующих в таблице импорта можно использовать «сплайсинг» — запись команды перехода на перехватчик в начало перехватываемой функции.

Также известно, что в Python имеется модуль ctypes позволяющий взаимодействовать с данными и функциями языка Си (т.е. большим числом динамических библиотек имеющих Си интерфейс). Таким образом ничто не мешает перехватить функцию процесса и направить её в Python метод обёрнутый в С-callback с помощью ctypes .

Для перехвата управления и загрузки кода в целевой процесс удобно использовать отладчик GDB, который поддерживает написание модулей расширения на языке Python (https://sourceware.org/gdb/current/onlinedocs/gdb/Python-API.html).

Код примера приведен полностью в конце статьи и состоит из двух файлов:

  • pyinject.py — расширение GDB
  • hook.py — модуль с функциями перехватчиками

Со стороны GDB код удобно оформить в виде пользовательской команды. Новую команду можно создать, наследуя от класса gdb.Command . При использовании команды в GDB будет вызываться метод invoke(argument, from_tty) .

Также можно создавать пользовательские параметры наследуя от gdb.Parameter . В примере статьи он используется для задания имени файла с функциями перехвата.

Подключение к работающему процессу PID и загрузку модуля удобно делать сразу при запуске GDB
Поле этого отлаживаемый процесс остановлен и запущена интерактивная командная строка GDB, в которой будет доступна новая команда «pyinject».

Читайте также:  How to install jar file in windows

Перехват можно условно разделить на три этапа:

  1. Инжектирование интерпретатора Python в адресное пространство целевого процесса
  2. Сбор информации о перехватываемой функции
  3. Собственно перехват

Пункты 1 и 2 проще делать на стороне отладчика, пункт 3 уже внутри целевого процесса.

Инжектирование интерпретатора Python

Большая часть Python интерфейса GDB предназначена для расширения отладочных возможностей. Для всего остального есть gdb.execute(command, from_tty, to_string) , которая позволяет выполнить произвольную команду GDB и получить её вывод в виде строки.
Например:
Также полезна gdb.parse_end_eval(expression) , вычисляющая выражение и возвращающая результат в виде gdb.Value .

Первым делом необходимо загрузить библиотеку Python в адресное пространство целевого процесса. Для этого необходимо вызвать dlopen в контексте целевого процесса.
Можно использовать команду call в gdb.execute , либо gdb.parse_and_eval :

После этого можно инициализировать интерпретатор
Первый вызов создает GIL (global interpreter lock), второй подготавливает Python C-API к использованию.

И загрузить модуль с функциями перехвата
PyRun_AnyFileEx выполняет код из файла в контексте модуля __main__ .

Модуль hook.py

Модуль hook.py содержит функции перехватчики и класс Hook выполняющий собственно перехват.
Функции перехватчики обозначаются при помощи декоратора. Например для функции open стандартной библиотеки напечатаем её аргументы и вернем результат вызова оригинальной функции, хранящейся в поле orig

Декоратор @hook принимает два параметра:

  • symbol — имя перехватываемого символа (предполагается что символ доступен в GDB из таблиц импорта или отладочной информации, но ничто не мешает перехватывать функции по адресам вместо символов)
  • ctype — класс ctypes задающий тип функции

Декоратор регистрирует функцию в классе Hook и возвращает не изменяя.

Метод register создает экземпляр класса и сохраняет его в словаре all_hooks . Таким образом после выполнения файла, благодаря декораторам в Hook.all_hooks будет вся информация о доступных функциях перехватчиках.

Чтобы осуществить перехват со стороны GDB вызовом одной функции, удобно определить статический метод в классе Hook , ответственный за перехват
В *args здесь передается дополнительная информация о перехватываемой функции. Какая именно зависит от метода перехвата.

Методы перехвата «сплайсингом»

Сплайсинг глобально делится на два подвида по способу вызова оригинальной функции.

В simple hook вызов оригинальной функции состоит из нескольких шагов:

  1. начало оригинальной функции восстанавливается из сохраненной копии
  2. производится вызов
  3. начало снова затирается инструкцией перехода на перехватчик

В trampoline hook начало оригинальной функции копируется в новое место и после него записывается переход в тело оригинальной функции. В этом варианте оригинальная функция всегда доступна по новому адресу.

Trampoline hook работает в многопоточных программах, но гораздо сложнее в установке. Необходимо перезаписывать целое число инструкций, для чего обычно используется дизассемблер. Приход архитектуры x86_64 добавил еще больше проблем из-за повсеместного распространения адресации памяти относительно регистра %rip (адрес текущей команды).

Посмотрим на начало функции open в GDB:

Если мы перепишем первую команду » cmpl $0x0,0x2d33ed(%rip) » по другому адресу, то относительный адрес 0x2d33ed(%rip) , который сейчас указывает на 0x7f6cc8d7b7d4 , будет указывать в другое место (привет SIGSEGV).

Чтобы сделать trampoline hook этой функции нужно:

  1. определить размер команд в начале функции
  2. выделить память не дальше чем в 2ГБ от целевого адреса команды cmpl (смещение 0x2d33ed(%rip) знаковое 32-битное)
  3. скопировать начало в новое место и пропатчить доступ к памяти относительно %rip в cmpl

В довершение картины, команда перехода должна быть короче 9 байт, т.к. это функция с двумя точками входа и по адресу 0x7f6cc8aa83e9 уже находится __open_nocancel . Это значит, что наш трамплин должен быть не дальше чем в 2ГБ от начала open для возможности 32-битного перехода (все 64-битные переходы длиннее 9 байт).

В принципе, имея всю мощь GDB за спиной ( gdb.execute() ), ничто не мешает корректно реализовать trampoline hook, но для простоты примера в этой статье будет использоваться simple hook.

В simple hook единственное ограничение это длина инструкции перехода.
Вариантов два (основных):

  • Опкод E9 (5 байт) — относительный 32-битный переход на дополнительно выделенную память (как в trampoline hook) и уже оттуда полноценный 64-битный переход на перехватчик.
    Переход на 0x7f6cc8aa83e0 + 0x37556c1b + 5 = 0x7f6cfffff000
  • Опкод FF 25 (6 байт) — абсолютный 64-битный переход по адресу в памяти относительно %rip. Для адреса всё равно надо выделять дополнительную память не дальше 2ГБ от начала функции.
    Здесь в 0x7f6cc8aa83e0 + 0x37556c1a + 6 = 0x7f6cfffff000 сохранён адрес абсолютного перехода.

В статье используется второй метод
get_indlongjmp возвращает код для прыжка с адреса srcaddr на адрес сохраненный в QWORD по адресу proxyaddr

Теперь можно наконец написать недостающие методы класса Hook . Метод install получает адрес оригинальной функции address и адрес вспомогательной зоны proxyaddr . После чего переписывает начало функции (предварительно сохранив его в self.code ) переходом на перехватчик

Читайте также:  Темы для linux fedora

patchmem перезаписывает начало оригинальной функции данными из src

origfunc оборачивает вызов функции в код снимающий и устанавливающий переход на перехватчик.

Последние штрихи

Python загружен в адресное пространство, файл hook.py загружен в Python. Осталось вызвать Hook.hook(symbol, address, proxyaddr) cо стороны Python модуля GDB.

Находим адрес функции » open »

Последняя строка это обход бага в GDB, который съедает старшие биты результата. Аргумент (addr | 0x7FFFFFFF) использует недокументированное свойство mmap выдавать память с адресом меньше занятого желаемого.

Без трюков по-правильному чуть длиннее: надо отпарсить вывод gdb.execute(‘info proc mappings’, False, True) , найти ближайшую к addr дырку в адресном пространстве и вывать mmap с MAP_FIXED . Ну и естественно не обязательно выделять по целой странице памяти для каждой перехваченой функции.

Разрешаем перезапись оригинальной функции (иначе SIGSEGV)

Источник

hook (n) — Linux Man Pages

hook: Hooks

Command to display hook manual in Linux: $ man n hook

SYNOPSIS

package require hook ?0.1?

hook bind ? subject ? ? hook ? ? observer ? ? cmdPrefix ?

hook call subject hook ? args .

hook forget object

hook cget option

hook configure option value .

DESCRIPTION

This package provides the hook ensemble command, which implements the Subject/Observer pattern. It allows subjects , which may be modules , objects , widgets , and so forth, to synchronously call hooks which may be bound to an arbitrary number of subscribers, called observers . A subject may call any number of distinct hooks, and any number of observers can bind callbacks to a particular hook called by a particular subject. Hook bindings can be queried and deleted.

This man page is intended to be a reference only.

CONCEPTS


INTRODUCTION

Loose coupling between sender and receiver is often desirable, however. In Model/View/Controller terms, a View can send a command (stemming from user input) to the Controller, which updates the Model. The Model can then call a hook to which all relevant Views subscribe. The Model is decoupled from the Views, and indeed need not know whether any Views actually exist. At present, Tcl/Tk has no standard mechanism for implementing loose coupling of this kind. This package defines a new command, hook , which implements just such a mechanism.

BINDINGS


SUBJECTS AND OBSERVERS

Subject and observer names are arbitrary strings; however, as hook might be used at the package level, it’s necessary to have conventions that avoid name collisions between packages written by different people.

Therefore, any subject or observer name used in core or package level code should look like a Tcl command name, and should be defined in a namespace owned by the package. Consider, for example, an ensemble command ::foo that creates a set of pseudo-objects and uses hook to send notifications. The pseudo-objects have names that are not commands and exist in their own namespace, rather like file handles do. To avoid name collisions with subjects defined by other packages, users of hook , these ::foo handles should have names like ::foo::1 , ::foo::2 , and so on.

Because object names are arbitrary strings, application code can use whatever additional conventions are dictated by the needs of the application.

REFERENCE

Called with no arguments it returns a list of the subjects with hooks to which observers are currently bound.

Called with one argument, a subject , it returns a list of the subject’s hooks to which observers are currently bound.

Called with two arguments, a subject and a hook , it returns a list of the observers which are currently bound to this subject and hook .

Called with three arguments, a subject , a hook , and an observer , it returns the binding proper, the command prefix to be called when the hook is called, or the empty string if there is no such binding.

Called with four arguments, it creates, updates, or deletes a binding. If cmdPrefix is the empty string, it deletes any existing binding for the subject , hook , and observer ; nothing is returned. Otherwise, cmdPrefix must be a command prefix taking as many additional arguments as are documented for the subject and hook . The binding is added or updated, and the observer is returned.

If the observer is the empty string, «», it will create a new binding using an automatically generated observer name of the form ::hook::ob number >. The automatically generated name will be returned, and can be used to query, update, and delete the binding as usual. If automated observer names are always used, the observer name effectively becomes a unique binding ID.

It is possible to call hook bind to create or delete a binding to a subject and hook while in an observer binding for that same subject and hook . The following rules determine what happens when is called during the execution of [1] No binding is ever called after it is deleted. [2] When a binding is called, the most recently given command prefix is always used. [3] The set of observers whose bindings are to be called is determined when this method begins to execute, and does not change thereafter, except that deleted bindings are not called. In particular: [1] If $o s binding to $s and $h is deleted, and $o s binding has not yet been called during this execution of it will not be called. (Note that it might already have been called; and in all likelihood, it is probably deleting itself.) [2] If $o changes the command prefix that’s bound to $s and $h , and if $o s binding has not yet been called during this execution of the new binding will be called when the time comes. (But again, it is probably $o s binding that is is making the change.) [3] If a new observer is bound to $s and $h , its binding will not be called until the next invocation of hook call subject hook ? args . This command is called when the named subject wishes to call the named hook . All relevant bindings are called with the specified arguments in the global namespace. Note that the bindings are called synchronously, before the command returns; this allows the args to include references to entities that will be cleaned up as soon as the hook has been called.

Читайте также:  Билет керберос не был принят сервером исходящей почты astra linux

The order in which the bindings are called is not guaranteed. If sequence among observers must be preserved, define one observer and have its bindings call the other callbacks directly in the proper sequence.

Because the hook mechanism is intended to support loose coupling, it is presumed that the subject has no knowledge of the observers, nor any expectation regarding return values. This has a number of implications: [1] hook call returns the empty string. [2] Normal return values from observer bindings are ignored. [3] Errors and other exceptional returns propagate normally by default. This will rarely be what is wanted, because the subjects usually have no knowledge of the observers and will therefore have no particular competence at handling their errors. That makes it an application issue, and so applications will usually want to define an -errorcommand . If the -errorcommand configuration option has a non-empty value, its value will be invoked for all errors and other exceptional returns in observer bindings. See hook configure , below, for more information on configuration options. hook forget object This command deletes any existing bindings in which the named object appears as either the subject or the observer . Bindings deleted by this method will never be called again. In particular, [1] If an observer is forgotten during a call to hook call , any uncalled binding it might have had to the relevant subject and hook will not be called subsequently. [2] If a subject $s is forgotten during a call to then hook call will return as soon as the current binding returns. No further bindings will be called. hook cget option This command returns the value of one of the hook command’s configuration options. hook configure option value . This command sets the value of one or more of the hook command’s configuration options: -errorcommand cmdPrefix If the value of this option is the empty string, «», then errors and other exception returns in binding scripts are propagated normally. Otherwise, it must be a command prefix taking three additional arguments: [1] a 4-element list , [2] the result string, and [3] the return options dictionary. Given this information, the -errorcommand can choose to log the error, call interp bgerror , delete the errant binding (thus preventing the error from arising a second time) and so forth. -tracecommand cmdPrefix The option’s value should be a command prefix taking four arguments: [1] a subject , [2] a hook , [3] a list of the hook’s argument values, and [4] a list of objects the hook was called for. The command will be called for each hook that is called. This allows the application to trace hook execution for debugging purposes.

EXAMPLE

Later the .view megawidget is destroyed. In its destructor, it tells the hook that it no longer exists: All bindings involving .view are deleted.

Источник

Оцените статью