Читати стек іншого процесу?


16

Я намагаюся прочитати стек дочірнього процесу, але не пощастило. Я знаю, що це можливо за допомогою ptrace, але ptraceінтерфейс дозволяє читати лише одне слово за один раз, і я намагаюся сканувати більшу частину стека.

Я також спробував прочитати /proc/$pid/memз меж стека як витягнутий з /proc/$pid/mapsфайлу після першого використання ptrace для приєднання до нього (як тут запропоновано ), але зчитування не працює (навіть при запуску як root), хоча той самий код успішний при спробі читання з різних частин процесу (наприклад, купи).

Що я роблю неправильно? Чи є якийсь інший варіант?


Ви дзвонили waitpidміж ptrace(PTRACE_ATTACH,…)і read(інакше можливий стан гонки)? Яка помилка readповертається? Чи дитина робить щось особливе зі своїм відображенням пам’яті - чи можете ви спробувати свій код із такою простою дитиною sleep?
Жил 'ТАК - перестань бути злим'

Я використовував зачекати після ptrace, і я поставив скану у дитини, щоб змусити його чекати.
user4537

Це тільки в Linux? Solaris також має файлову систему / proc, але вона зовсім відрізняється від Linux, напередодні філософського. Багато "бінарних файлів".
Брюс Ediger

просто зробіть систему ("pstack pid ") і проаналізуйте вихід ..
vrdhn

Дивіться ps: повна команда занадто довга для деяких прикладів
Стефан Шазелас,

Відповіді:


5

ptraceІнтерфейс дозволяє читати лише одне слово за один раз, і я намагаюся сканувати більшу частину стека

Ну просто скористайтеся циклом. Я, чесно кажучи, не бачу, як це становить проблему ptrace, я постійно її використовую для віддаленого доступу до процесів.

Я використовую щось подібне:

static int memcpy_from_target(pid_t pid, char *dest, long src, size_t n)
{
    static int const align = sizeof(long) - 1;

    while (n)
    {
        size_t todo = MIN(n, sizeof(long) - (src & align));
        long data = ptrace(PTRACE_PEEKTEXT, pid, src - (src & align), 0);
        if (errno)
        {
            perror("ptrace_peektext (memcpy_from_target)");
            return -1;
        }
        memcpy(dest, (char *)&data + (src & align), todo);

        dest += todo; src += todo; n -= todo;
    }

    return 0;
}

Привіт, Сем, хоча ваш код буде робити (і фактично це те, що я зараз роблю), він має великі показники продуктивності.
user4537

@ user4536: Я бачу. Маю на увазі ще одну стратегію, про яку буду публікувати, коли встигну її записати. Які типові розміри стеків?
sam hocevar

Важко сказати по-справжньому, оскільки моє дослідження не передбачає конкретного розміру стека, але заради цього аргументу скажімо хоча б пару сторінок, чи можете ви підказати про свою стратегію? Дякуємо за допомогу все одно!
user4537

1

Ось ще одна стратегія, яка може потребувати налаштування, але повинна бути більш ефективною з великими фрагментами даних. Ідея полягає у виконанні системних викликів у віддаленому процесі, щоб отримати вміст стеку. Він буде потребувати конкретного архітектурного коду, але якщо ви орієнтуєтеся лише на x86 / x86_64, це не повинно бути зайвим.

  1. Створіть названу трубу, наприклад, "/tmp/fifo"у процесі виклику.
  2. Крок до простеженого процесу, поки він не повернеться з системного виклику, використовуючи PTRACE_SYSCALLкрок, waitpid()щоб зачекати та PTRACE_GETREGS/ PTRACE_PEEKTEXTперевірити поточно виконаний кодекс.
  3. Створіть резервні копії регістрів віддаленого процесу та невелику область його стека.
  4. Виконання системних викликів на віддаленому процесі, перекриваючи його стек з вашими власними даними: open("/tmp/fifo"), write()вміст стека, close()дескриптор.
  5. Відновлення стану віддаленого процесу.
  6. Прочитайте дані фіфо в процесі дзвінка.

Можуть бути і більш елегантні альтернативи названій трубі, але я зараз не можу придумати жодної. Причиною того, що я використовую лише системні дзвінки, є те, що віддалене введення коду в сучасних системах досить ненадійне через різні засоби захисту. Недолік полягає в тому, що він зависне, поки віддалений процес не здійснить системний виклик (що може бути проблемою для деяких програм, які в основному роблять обчислення).

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


1

Ще одна пропозиція.

Коли / якщо він буде прийнятий у головному дереві ядра Linux, ви зможете використовувати патч Cross Cross Attach Christopher Yeoh . Наприклад, див. Документацію для process_vm_readv .


1

Ви можете легко прочитати стек іншого процесу за допомогою файлової системи proc (для цього вам знадобиться кореневий доступ). Перш ніж довільно прочитати з / proc / pid / mem вам потрібно проконсультуватися з / proc / pid / maps. Просте прочитання в цьому файлі показує багато записів. Нас цікавить запис, позначений як стек. Після цього вам потрібно прочитати нижню та верхню межі стеку. Тепер просто відкрийте файл / proc / pid / mem, перейдіть до нижньої межі стека та прочитайте правильний розмір даних.


1
Ви впевнені, що маєте на увазі, memsа ні maps? (Я не бачу жодних memsзаписів під моєю /procфайловою системою.) ОП вже згадував про читання меж стека /proc/$pid/maps- з чого ви пропонуєте зробити це по-іншому?
JigglyNaga

Редагував друкарські помилки. Я зробив саме те, що згадував у своїй відповіді, і він скинув 132 КБ даних про стек. Нам потрібна додаткова інформація про те, що ОП зробив не так. Можливо, OP може поділитися кодом, який він використовував для читання меж стека. Якщо він не відповість, я поділюсь своїм.
Аджай Брахмакшатрія

0

Ви можете спробувати lsstack . Він використовує ptrace, як і будь-яка інша успішна програма "читати стек іншого процесу". Я не зміг заставити програму, використовуючи / proc / $ pid / mem reading для роботи. Я вважаю, що ви не можете зробити це так, хоча, логічно, слід.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.