2016-01-21 2 views
4

Как найти argc и argv из общего объекта? Я пишу библиотеку в C, которая будет загружена через LD_PRELOAD. Я был в состоянии найти стек два различных способа:Найти argc и argv из библиотеки

  1. Read rsp через встроенный __asm__ вызов.
  2. Прочитайте /proc/<pid>/maps и проанализируйте запись для стека.

Затем я могу создать указатель, указать его на сегмент стека, а затем повторить поиск данных. Проблема в том, что я не могу найти эффективный способ определить, какие байты argc и указатель на указатель на строки argv.

Я знаю, что /proc/<pid>/cmdline также содержит аргументы, каждый из которых разделен 0x00, но мне интересно находить все в памяти.

В gdb Я вижу a DWORD для argc, за которым следует QWORD, который является первым указателем. 20 байт до адреса argc - указатель, который указывает на сегмент кода основной программы. Но это не детерминированный способ идентифицировать argc и argv.

Я видел несколько сообщений, но не рабочий код:

+0

Кажется, это немного способный сделать это, поскольку он зависит от того, как компилятор использует стек. Скорее всего, это изменится, как только кто-то найдет оптимизацию компилятора/времени выполнения. Приложение может также хотеть использовать одни и те же аргументы в другом смысле, это может вызвать проблемы, если ваша библиотека пытается интерпретировать параметры, не предназначенные для него. Не можете ли вы передать их непосредственно в свою библиотеку по вызову «конструктор»? Да, я понимаю, что то, что вы хотите сделать, это избежать этих накладных расходов. – ChrisR

+0

В какой момент будут доступны «argc» и «argv»? Вероятно, это невозможно во время фазы LD_PRELOAD. –

+0

Это также совершенно законно для программы для _modify_ данных в 'argv'. Я не уверен, что произойдет со стеком в этом случае. – paddy

ответ

9

This response в вашей второй ссылке содержит работающий исходный код, который работал хорошо для меня (Gnu/Linux на основе эльфов), в том числе во время LD_PRELOAD.

Код очень короткий; она состоит из функции:

int foo(int argc, char **argv, char **env) { 
    // Do something with argc, argv (and env, if desired) 
} 

и указатель на эту функцию в .init_array разделе:

__attribute__((section(".init_array"))) static void *foo_constructor = &foo; 

Полагая, что в общую библиотеку, а затем LD_PRELOADing общую библиотеку, конечно, вызвал призыв к foo когда это Я попробовал это, и это было ясно вызвано с argc и argv, которые позже будут переданы в main (а также значение environ).

+0

Отличный ответ! Я никогда не думал о запуске конструктора таким образом в библиотеке. Отсутствие взаимозависимости с зависимостями компилятора или времени выполнения. любить это. Я учусь каждый день. – ChrisR

0

Самый надежный, вероятно, использовать /proc/<pid>/cmdline, потому что это обеспечивается ядром и не будет меняться в зависимости от реализации C (например, это будет зависеть от используемого процессора).

Проблема заключается в том, что на некоторых платформах аргументы функции (fx main) передаются в стек, но на других платформах она может быть передана как регистры (fx на платформе x86-64). Если он отправляется через регистры, то если оптимизация включена, main будет не хранить их в памяти, если это не нужно - это, вероятно, не останется в памяти, если вы не сделаете это явно.

Даже если аргументы передаются в стеке, точное местоположение, где находятся аргументы main, может отличаться от версии к версии компилятора/реализации. Это означает, что практически нет надежного метода извлечения их из стека (и, как заметил кто-то, они могут быть изменены во время выполнения main как часть синтаксического анализа командной строки).

Даже то, как ядро ​​передает аргументы программе, не очень помогает, поскольку они передаются через регистры - это означает, что там, где они будут храниться, полностью зависит от инициализации CRT (что, в свою очередь, может переход от версии к версии).

Короткий поиск argv и argc позже требует явной поддержки от используемого CRT (CRT от Microsoft делает это, но GNU не AFAIK).

Что вы могли делать, конечно, чтобы захватить источник GCC и пропатчить CRT инициализации на самом деле хранить argv и argc где-то, где вы можете позже восстановить их. Это, конечно же, не сработает, если вам нужно получить к ним доступ до запуска CRT-программы программы (fx во время динамической компоновки).