Как получить смещение заданного регистра процессора в Rust - PullRequest
4 голосов
/ 07 марта 2019

В качестве упражнения я пытался использовать nix::sys::ptrace::ptrace Rust (который в значительной степени идентичен ptrace C) для эмуляции функции регистрации системных вызовов strace путем чтения содержимого RAX / RBX / RCX / RDX регистрируется во время каждого системного вызова. Мой желаемый результат будет примерно таким:

Found syscall: 4
Arg1: 1
Arg2: Hello World!

Из примеров, которые я нашел в Интернете, кажется, что комбинация PTRACE_PEEKUSER и PTRACE_PEEKDATA была бы лучше всего для этого (возможно, тоже PTRACE_GETREGS?), Но мне трудно понять, как чтобы удовлетворить третий аргумент, который мне нужно передать этим функциям, чтобы заставить его работать.

Справочные страницы

ptrace показывают этот пример, демонстрирующий правильное использование:

ptrace(PTRACE_PEEKTEXT/PEEKDATA/PEEKUSER, pid, addr, 0);

Справочная страница просто говорит: «Прочитайте слово по адресу addr в памяти трассируемого». Но что должно быть addr? Как я могу определить правильный адрес для удовлетворения этого аргумента?

Все примеры, которые я нашел в Интернете, имеют что-то вроде:

ptrace(PTRACE_PEEKUSER, pid, sizeof(long)*ORIG_EAX, 0);

или

ptrace(PTRACE_PEEKUSER, pid, somenumber*RAX, 0)

Как я могу найти / рассчитать смещение этих регистров во время выполнения? (в Rust!)

1 Ответ

3 голосов
/ 08 марта 2019

Прошло много времени с тех пор, как я ткнул ядром Linux (сейчас пользователь Mac). Черт, если я правильно помню, то ...

Заголовки ядра

Установить заголовки ядра с чем-то вроде sudo apt-get install linux-headers-$(uname -r). Допустим, вы на x86_64-linux-gnu (угадайте, исходя из ваших rax интересов).

Открыть /usr/include/x86_64-linux-gnu/sys/reg.h Заголовок:

...
#ifdef __x86_64__
/* Index into an array of 8 byte longs returned from ptrace for
   location of the users' stored general purpose registers.  */

# define R15    0
# define R14    1
# define R13    2
# define R12    3
# define RBP    4
# define RBX    5
# define R11    6
# define R10    7
# define R9     8
# define R8     9
# define RAX    10
...

И комментарий гласит:

Индексировать в массив длиной 8 байт, возвращаемый из ptrace, для определения местоположения пользовательских регистров общего назначения.

Все эти макросы (RAX, RCX, ...) определяют индексы для конкретных регистров. И поскольку каждый из них имеет длину 8 байт (только x86_64), смещение составляет 8 * $index. В случае регистра rax смещение вычисляется как 8 * RAX = 8 * 10 = 80. 80 - это то, что вы должны использовать для аргумента addr в вызове функции ptrace. Вот как это работает. Помните, что он отличается для других архитектур и т. Д.

PTRACE _ *

PTRACE_PEEKUSER - использовать для регистров и другой отладочной информации.

PTRACE_PEEKDATA - использовать для данных и кода программы.

PTRACE_PEEKTEXT - man ptrace (Linux) говорит - Скопируйте данные слова в адрес адреса в памяти трассировки. Что касается PTRACE_PEEKTEXT и PTRACE_PEEKDATA, эти два запроса в настоящее время эквивалентны. Это потому, что в Linux нет отдельных адресных пространств для текста и данных.

Rust & PTRACE_PEEKUSER

Ящик nix предлагает функцию getregs , чтобы прочитать их все. Возвращает libc user_regs_struct . Который поддерживается только для Linux:

libc Ящик также содержит эти индексы:

Если вас интересует только один регистр, вы можете использовать этот индекс для вычисления смещения / адреса для функции ptrace . Умножьте его на 8 (#[cfg(target_arch = "x86_64")]) / 4 (#[cfg(target_arch = "x86")]) и используйте PTRACE_PEEKUSER, чтобы прочитать его (см. Запрос ).

Rust & PTRACE_PEEKDATA

Чтение Каковы соглашения о вызовах для системных вызовов UNIX и Linux на i386 и x86-64 . Другими словами, вас интересуют регистры rdi, rsi, rdx, .... Ящик nix предоставляет специализированную функцию read , которая внутренне вызывает функцию ptrace с PTRACE_PEEKDATA.

nix crate

ptrace функция устарела. Примечание к документации:

Устаревшее с 0.10.0: использование ptrace () должно быть заменено специализированными вспомогательными функциями вместо

Вы должны использовать специализированные функции, такие как getregs & read. Список их можно найти в документации .

...