2013-04-04 2 views
2

Я добавляю функцию к моему отладчику (я использую Ptrace для управления отслеживаемым процессом, а также libbfd/libopcodes), чтобы развернуть стек и определить, будут ли расхождения существуют между каждым выделенным пространством стека CALL и статическим локальным размером переменной, печатающим адрес и размер локального стека каждого кадра на этом пути.Проверьте, находится ли адрес памяти в пространстве стека текущего процесса

Моя общая методология не принимать адрес в базовом указателе (EBP/RBP), увеличивает указатель должен должен содержать сохраненный указатель кадра, разыменовать этот адрес, проверьте его с PTRACE_PEEKDATA и повторять, пока я разыменование адреса, занимающий область вне стека.

Я знаю, как проверить регистры сегментов кода/данных, но в идеале я хотел бы проверить, не находится ли я в стоп-кадре, даже если сегментация была изменена страницами памяти W^X или иначе не выполняемыми стек.

Короче говоря, как я могу проверить (в общем случае), когда я перешел за пределы стека, не вызвав общую ошибку защиты?

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

+0

Это на Linux? –

+0

Да, но в идеальном мире было бы портативное решение, которое не зависит от какой-либо информации из/proc. –

+0

Стандарт C не предлагает каких-либо переносных способов доступа к специфичной для ОС или аппаратной информации или функциям (за исключением, возможно, для 'system()'). Если ваша программа на C зависит от указанной информации/функциональности, она обречена быть плохо переносимой. Вы можете несколько улучшить переносимость, если придерживаетесь функциональности POSIX, но это улучшение будет только улучшением для совместимых с POSIX операционных систем. Для всех остальных это будет противоположно улучшению. –

ответ

1

В стандарте C нет каких-либо переносных способов доступа к конкретным или конкретным аппаратным средствам или функциям (кроме, возможно, для system()). Если ваша программа на C зависит от указанной информации/функциональности, она обречена быть плохо переносимой.

Вы можете несколько улучшить переносимость, если придерживаетесь функциональности POSIX, но это улучшение будет только улучшением для POSIX-совместимых ОС. Для всех остальных это будет противоположно улучшению. Точно так же может быть что-то, что всегда доступно в Linux (определенные функции или инструменты или библиотеки), которые вы можете использовать. Я не могу указать на это. Вам нужно продолжить исследования или ждать других ответов.

0

Я просмотрел код команды pstack, который печатает содержимое стека запущенного процесса. Этот код получает базовый адрес от структуры link_map и сохраняет его в поле l_addr. Это поле устанавливается внутри функции readLinkMap():

static void readLinkMap(int pid, ElfN_Addr base, struct link_map *lm, 
         char *name, unsigned int namelen) 
{ 
    /* base address */ 
    lm->l_addr = (ElfN_Addr) ptrace(PTRACE_PEEKDATA, pid, 
            base + offsetof(struct link_map,l_addr), 0); 
    /* next element of link map chain */ 
    if (-1 != (long) lm->l_addr || !errno) 
    lm->l_next = (struct link_map *) ptrace(PTRACE_PEEKDATA, pid, 
              base + offsetof(struct link_map, l_next), 0); 
    if ((-1 == (long) lm->l_addr || -1 == (long) lm->l_next) && errno) { 
    perror("ptrace"); 
    quit("can't read target."); 
    } 

    loadString(pid, base + offsetof(struct link_map, l_name), name, namelen); 
} 
Смежные вопросы