2012-04-19 3 views
5

Сегодня я решил декомпилировать простую программу «Hello world», написанную на Visual C++, используя IDA Pro.Обратное проектирование C++

С моими предыдущими знаниями я был уверен, что не найду немедленного вызова printf в исполняемой точке входа, и я был прав. Я нашел много кода, который не был написан мной и добавлен компилятором во время процесса компиляции.

Я хотел бы лучше понять, какой код будет добавлен в процессе компиляции. Что он делает? Есть ли какие-либо «трюки», чтобы быстро найти «главное» и пропустить весь ненужный код, созданный разборкой?

Лучшее, что я смог найти в этом посте: http://www.codeproject.com/Articles/4210/C-Reverse-Disassembly, говоря, порядок выполнения исполняемого файла скомпилирован с использованием Visual C++ выглядит следующим образом:

  1. CrtlStartUp

  2. главный

  3. CrtlCleanUp

Могу я получить более подробный ответ?

+5

Очень специфический компилятор и платформа. Я сомневаюсь, что вы получите точный ответ. – Matt

+1

Я рекомендую [этот пост] (http://stackoverflow.com/a/9952374/176769) в качестве дорожной карты любому человеку, обратившемуся к инженеру-гуру. – karlphillip

+1

У меня нет опыта в обратном проектировании, но разве вы не могли бы просто установить точку прерывания отладчика в начале main, чтобы получить относительный адрес? Или, альтернативно, найдите главный объект в дампе объекта исполняемого файла? – bjhend

ответ

4

Существуют различные вещи, которые требуются стандарту C++, с которым вы, вероятно, столкнетесь.

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

Итак, как минимум, код запуска должен быть способен построить эту структуру данных функций, которые будут вызваны при возврате из main. Это динамическая структура данных, потому что она должна быть добавлена ​​в среду выполнения программой, а порядок вызовов противоположно регистрации (так как обычно вам нужна структура данных, которая делает добавление к месту, из которого вы легко переходите).

Но, кроме того, стандарт требует, чтобы статика в других единицах перевода была создана до того, как какая-либо функция будет выполнена в этой единицы перевода. Часто компиляторы просто упорядочивают все в компоновщике, чтобы все они вызывались до main, но это не требуется. Эти компиляторы, которые делают что-то по-другому, затем должны предоставлять thunks для инициализационных подпрограмм в другом связанном коду единицы перевода, который будет вызываться при первом вызове функции.

Только это довольно немного работы, если вы используете какую-либо стандартную библиотеку. Помните, std :: cout - это статический объект (статическое время жизни, а не статическая связь - путано перегруженное предупреждение). Таким образом, это означает создание коммуникаций с вашей консолью, которые будут иметь необходимые API для вашей платформы. В стандарте есть много таких объектов.

И тогда могут быть вещи, специфичные для вашей платформы и/или компилятора, которые подготавливают процесс каким-либо полезным способом или анализируют переменные окружения или загружают «стандартные» динамические/разделяемые библиотеки или подобные материалы.

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

2

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

В вашем случае с помощью приложения hello world вы можете использовать точку входа IDA в диалоге списка функций (я не помню точное имя). Но опять же я не рекомендую этот подход, если приложение очень мало.

подход я использую я называю «вниз к началу подхода» (с)

Я хотел бы начать с анализа текущего поведения приложения без привлечения каких-либо инструментов. Это очень важный шаг, который сэкономит много времени, поскольку вы будете знать, что вы ищете и когда это произойдет. Затем определите «слабые точки», такие как строки, постоянные значения, которые вы можете найти с помощью инструментов статического анализа (IDA).

Следующий шаг разобрать приложение и искать эти «слабые» (модуль строк в IDA), а затем найти ссылки на них от того, что функции, которые они использовали (вы можете использовать вид графики иерархии в новых версиях IDA)

Если вы все еще не можете понять, как он работает, или этот код вызван из многих мест, вы не знаете, что вам нужно. Вы можете начать с анализа времени выполнения и использовать отладчик (softice? :)), например ollydbg. Это покажет вам, что не видно со статическим анализом, например, с помощью виртуальных функций/указателей функций: вызов EAX.

Затем вы просто обрабатываете шаг за шагом, пока не получите то, что вам нужно.

 Смежные вопросы

  • Нет связанных вопросов^_^