Вы правы насчет своего определения декомпилятора: он берет скомпилированное приложение и производит соответствующий исходный код. Однако он не в большинстве случаев знает имя и структуру переменных / функций / классов - он просто догадывается. Он анализирует поток программы и пытается найти способ представить этот поток через определенный язык программирования, обычно C. Однако, поскольку выбранный язык программирования (C в этом примере) часто находится на более высоком уровне, чем состояние базовой программы (двоичного исполняемого файла) некоторые части программы может быть невозможно точно представить; в этом случае декомпилятор не сработает, и вам придется использовать дизассемблер. Вот почему многие люди любят запутывать свой код: из-за этого декомпиляторам становится труднее его открыть.
Создание декомпилятора - непростая задача. По сути, вы должны взять декомпилируемое приложение (будь то исполняемый файл или какая-либо другая форма скомпилированного приложения) и преобразовать его в какое-то дерево, с которым вы можете работать в памяти. Затем вы должны проанализировать ход выполнения программы и попытаться найти шаблоны, которые могут указывать на то, что в определенном месте кода использовался if
оператор / переменная / функция / и т. Д. На самом деле это всего лишь игра в догадки: вам нужно знать шаблоны, которые компилятор создает в скомпилированном коде, затем искать эти шаблоны и заменять их эквивалентным понятным для человека исходным кодом.
Это все намного проще для программ более высокого уровня, таких как Java или.NET, где вам не нужно иметь дело с инструкциями по сборке, а такие вещи, как переменные, в основном заботятся о вас. Здесь вам не нужно столько гадать, сколько просто переводить напрямую. Возможно, у вас нет точных имен переменных / методов, но вы, по крайней мере, можете довольно легко вывести структуру программы.
Отказ от ответственности: я никогда не писал декомпилятор и поэтому не знаю всех деталей того, о чем говорю. Если вы действительно заинтересованы в написании декомпилятора, вам стоит приобрести книгу по этой теме.
Декомпилятор в основном берет машинный код и возвращает его обратно к языку, на котором он был отформатирован. Если я не ошибаюсь, я думаю, что декомпилятору нужен знать, на каком языке он был скомпилирован, иначе ничего не получится.
Основная цель декомпилятора - вернуться к исходному коду; например, однажды мой файл Java был поврежден, и единственное, что я мог вернуть, - это использовать декомпилятор (поскольку файл класса не был поврежден).
Он работает, выводя "разумное" (основанное на некоторых эвристиках) представление того, что находится в объектном коде. Степень сходства между тем, что он создает, и тем, что было изначально, обычно сильно зависит от того, сколько информации содержится в двоичном коде, с которого он начинает. Если вы начинаете с практически "чистого" двоичного кода, он обычно просто придумывает "разумные" имена для переменных, например, использует такие вещи, как i
, j
и k
для индексов циклов, и более длинные имена для большинства других.
С другой стороны, язык, поддерживающий интроспекцию, должен встраивать в исполняемый файл гораздо больше информации об именах переменных, типах и т.д. В таком случае декомпиляция может дать нечто гораздо более близкое к оригиналу, например, обычно сохраняя оригинальные имена функций, переменных и т.д. В таком случае декомпилятор часто может создать нечто вполне похожее на оригинал - возможно, потеряв лишь форматирование и комментарии.