Обновить

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

Спасибо большое за статью, с большим интересом прочитал и жду остальных частей. Очень понравилась глубина погружения, до опкодов команд.

По сути статьи не совсем понял, несколько моментов, видимо из-за отсутствия опыта С++:

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

Не совсем понял, почему три лежащие на стеке переменных, это структура. Если я объявляю:

void my_func(){
uint32_t a,b,c;

}

Эти переменные разве не будут также последовательно лежать на стеке?

Как пользователь линукса почти случайно узнал, что под линукс есть и IDA. В моем случае (включено дробное масштабирование экрана) она выглядит даже получше гидры. Вовсе не призываю использовать ida вместо гидры, просто вдруг кто как и я не знает :)

Удивлён, что у статьи нет комментариев. Надеюсь это не помешает вам сделать остальные части.

Спасибо за комментарий! Рад, что понравился материал.

Все верно, библиотека ожидает по адресу &local_78 именно std::string. Гипотеза в статье заключается не в типе функции, а в том, что три локальные переменные образуют один объект.

Ваш пример с uint32_t a,b,c; верный, переменные будут лежать последовательно. Ключевой момент в совокупности фактов: три переменные инициализируются одной группой инструкций перед вызовом std::operator>>, а local_78 передается в функцию как указатель на std::string. Если бы это были три независимые переменные, то local_78 был бы просто указателем на local_68, а local_70 и local_68 жили бы своей жизнью. Но они лежат вплотную, инициализируются вместе и используются вместе - это паттерн объекта, а не просто трех переменных подряд. И даже это не гарантирует подтверждение гипотезы, поэтому во второй части мы подтвердим это экспериментально, реконструировав структуру std::string.

Я выбрал Гидру, потому что она бесплатная и открытая и к тому же активно развивается. На самом деле, инструмент не так важен. Важно понимание того, что мы этим инструментом делаем :)

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

Хммм, занятно, я занимаюсь C++ для разработки Geant4 приложений, но я думал что вот так просто нельзя восстановить исходный код имея на руках только бинарник. Можно ли создать такой бинарник по которому вообще не возможно восстановить код? Обфускация не пойдет кажется т.к скорость обработки данных пострадает?

И да, и нет. Исходный код восстановить невозможно, а вот алгоритм работы нужных функций - реально. Все упирается в необходимость, ресурсы и время. Как говорится: "Можно, а зачем?". Обфускация только усложняет аналитику жизнь, а не полностью исключает восстановление исходной логики программы.

Компиляцию и декомпиляцию можно рассмотреть на примере следующей аналогии: перед вами кубик льда (исходный код) и в целом, вы знаете, что произойдет, когда он растает. Он растечется по полу в достаточно псевдослучайную лужу (скомпилированная программа). Почему лужа "псевдослучайная"? Например, этот кубик льда лежит в стакане и его "растекание" строго ограничено стенками стакана (так же как ограничены алгоритмы оптимизации компилятора).

Посмотрим на наш мысленный эксперимент с другой стороны. Перед вами стакан с водой (результат компиляции - готовая программа). Из чего эта лужа получилась? Количество вариантов бесконечно большое - это и есть наш процесс восстановления исходного алгоритма программы. Мы никогда не сможем наверняка сказать: "именно такой код написал программист", но мы можем провести серию экспериментов и сказать: "в целом, восстановленный алгоритм делает то же самое, что и в исследуемой программе".

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации