Как стать автором
Поиск
Написать публикацию
Обновить

Комментарии 16

Картинка не правильная. В мясорубку должна входить сосиска, а выходить барашек.
Спасибо за замечание :) Там так и нарисовано, только стрелки в обратном порядке поставлены с идей, что процесс в две стороны рассматривается.
Заменила картинку :) Спасибо.
Я как-то неловко отклонила Ваше предложение поменять барана и сосиску местами. Но в этот раз все верно: ДЕкомпилятор — это «мясорубка наооборот», которая именно из фарша (бинарника) восстанавливает подобие исходника, то есть барана :)
НЛО прилетело и опубликовало эту надпись здесь

Все оптимизации компилятора должны сохранять наблюдаемое поведение.
До оптимизации функция либо падала при доступе к нулевому указателю либо записывала значение в память. После оптимизаций она делает то же самое.
Более эпичный случай: компилятор может иногда выкинуть бесконечный цикл:


int infinte(){
int counter = 0;
while(true){
  counter++;
  if(PureVeryComplicatedCondition(counter))
    return 1;
}
return 0;
}
Про оптимизационные преобразования Вы говорите верно, однако примеры, приведенные в публикации, рабочие. Там написано, как получен представленный ассемблер, чтобы каждый мог повторить и убедиться сам. Первый пример действительно на выполнение вызовет функцию, которая никогда не должна вызываться.
Низкоуровневое программирование — оно такое, чем дальше двигаешься, тем больше сюрпризов. «Я знаю, что ничего не знаю» — Сократ сказал очень верно :)
Мы делаем вручную с помощью инструментальных средств, помогающих анализировать низкоуровневые программы. Undefined behavior можно находить в исходнике на С/C++, но в бинарнике искать надежнее. Я сама использую IdaPro для низкоуровневого анализа. Для анализа C/C++ и других программ по исходникам использую InCode. Конечно, большинство работы для анализа бинарников делается руками.
О каком undefined behavior в бинарниках вы говорите?
Компилятор переводит C++ программу с UB в опкоды x64, поведение которых специфицировано производителем CPU. UB исчезает.

Или вы ищете недокументированные опкоды процессора? Откуда они после компилятора?
Я говорю о том, что UB в исходной C/C++ программе может привести к различным непредсказуемым defined behavior в низкоуровневой программе. Именно поэтому проверить исходник может быть недостаточно, а для более точного анализа надо проверять и исходник, и бинарник.
Ага, то есть нужно скомилировать C++ в код, затем декомпилировать обратно в C++, проанализировать результат (вручную?). Если никакой странной лажи не появилось, то, наверное, в исходной программе нет UB. Не слишком ли дорого выходит?
Нет, совсем не так. В статье же написано, что декомпиляцию стоит выполнять, если надо понять содержательный аспект бинарника. В декомпилированном коде уязвимости искать несравненно сложнее, нежели в исходнике, так как «артефакты» восстановления мешают работе статических анализаторов.
Анализировать и исходник, и бинарник, но именно бинарник в бинарном виде (по ассемблеру, например) нужно, если у вас критичный по надежности фрагмент кода и надо точно понимать, что будет выполняться.
В статье приведены 2 примера, когда именно по ассемблеру отлавливается уязвимость, которая «спряталась» в исходнике.
Интересная статья. Скажите, у вас используются какие-то специальные инструменты для обнаружения undefined behavior или это выполняется «врукопашную»? Не пробовали ли учесть опыт обнаружения подобных косяков в каком-нибудь средстве автоматизации/плагине и т.д.?
Мы делаем вручную с помощью инструментальных средств, помогающих анализировать низкоуровневые программы. Undefined behavior можно находить в исходнике на С/C++, но в бинарнике искать надежнее. Я сама использую IdaPro для низкоуровневого анализа. Для анализа C/C++ и других программ по исходникам использую InCode. Конечно, большинство работы для анализа бинарников делается руками.
ясно, спасибо
Зарегистрируйтесь на Хабре, чтобы оставить комментарий