Кт-нить скажет мне , кто какие проблемы видит в создании C декомпилятора. Для себя я уже многое решил, но мне интересно мнение других знатоков. Идентификация управляющиж команд, блоков и т.п? Или данных? Трудность, по моему тока втом, что декомпилятор видится абстрактно, но если взять самые распространенные: bcc32.exe,cl.exe, dcc32.exe, то они оставляют тучу информации, по которой запросто реверсировать прогу. Главное, при декомпиляции думать иначе, прекрасно помогает в этом медитация и т.п.
а еще вот такой проект делается (надеюсь что все-таки делается, а то затих опять на 3 месяца): http://www.wasm.ru/forum/index.php?action=vthread&forum=5&topic=7275&page=0 мега-декомпилер, мечта реверсера, может у автора спросишь, какие проблемы у него возникали ?
Теоретически можно написать декомпиятор в C-- или какой-нибудь псевдо-Си, практически радости от такого декомпилятора будет ненамного больше, чем от IDA. Главная проблема точного восстановления исходника упрется в создание ИскИна
Ида. Живая легенда, но алгоритм создания библиотечных паттернов ни к черту. Не использует всю информацию из библиотек и обьектных файлов. Например для борландовских использовать ихние кой-какие структуры типа ртти, помнить, что процедуры в екзешнике располагаются как правило также как и в объектном файле, что в принципе даст возможность выявить названия процедур типа proc_begin: ret; proc_end насиловать ассерты вовсю, если есть, они дадут догира инфы об использованном модуле и т.п. Уточняю, я имею ввиду декомпилятор С++ продуктов Мелкого и Бормана. Декомпиляция возможна и реальна. Desquirr и бумеранг я смотрел. Понравились, но мы пойдем другим путем.
Для примера примитивный код после msvc. что тут декомпилер будет делать? Код (Text): 00403536 |. 33C9 xor ecx, ecx 00403538 |. B8 04404000 mov eax, 00404004 0040353D |> 8360 08 00 /and [dword eax+8], 0 00403541 |. C740 04 0C000080 |mov [dword eax+4], 8000000C 00403548 |. 8908 |mov [eax], ecx 0040354A |. 8848 05 |mov [eax+5], cl 0040354D |. C740 FC A8904A00 |mov [dword eax-4], 004A90A8 00403554 |. 41 |inc ecx 00403555 |. 83C0 10 |add eax, 10 00403558 |. 84C9 |test cl, cl 0040355A |.^ 75 E1 \jnz short 0040353D
S_T_A_S_ Для примера примитивный код после msvc. что тут декомпилер будет делать? Если предположить, что в eax попала глобальная переменная-указатель на массив структур, и компилятор автоматом выдал ей статус register, то декомпиляция в осмысленный текст возможна.
Дык никто и не утверждает, что невозможна Просто одно дело борланд+RTTI, и другое - оптимизированый код после msvc.
они ничего не оставляют, что хоть как-то поможет тебе превратить ассемблерный код в С-шный исходник. Реверсинг очень портит оптимизатор, это главное с чем приходится бодаться, а отнють не с разбиением кода на функции, или свертыванием кода в WHILE или IF. пойти можно - дойти тяжело
MrHammer Кт-нить скажет мне , кто какие проблемы видит в создании C декомпилятора. Я тоже занимался разработкой декомпилятора и достиг определённых результатов, но из-за дефицита времени проект сейчас находится в замороженном состоянии (с лета 2004) и некоторые свои мысли я уже подзабыл. Сейчас я бы выделил примерно следующий список проблем (бОльшую часть которых можно скорее отнести к проблемам интеллектуального дизассемблирования): 1. Разделение кода и данных. 2. Определение типов локальных переменных, сложных типов данных, границ структур и типов их элементов, границ массивов. Определение того, где происходит адресация массива/структуры в целом, а где - отдельных полей/элементов. 3. Определение количества и типов/размеров аргументов функций. 4. Слежение за указателем стека в "нестандартных" случаях. 5. Анализ содержимого регистров, временных переменных (я не имею в виду элементарный анализ потоков данных), в том числе определение возвращаемых функциями значений, расспространение типов данных. 6. Определение идиом. Трудность, по моему тока втом, что декомпилятор видится абстрактно, но если взять самые распространенные: bcc32.exe,cl.exe, dcc32.exe, то они оставляют тучу информации, по которой запросто реверсировать прогу. Мне кажется, при написании декомпилятора нужно ориентироваться на отсутствие какой-либо дополнительной информации, кроме собственно машинного кода. Desquirr и бумеранг я смотрел. Понравились, но мы пойдем другим путем. Ни то, ни другое в руках не вертел, а примеры не очень показательные, поэтому впечатления не очень хорошие. А каким путём вы пойдёте?
Этот клочок кода для декомпилятора слишком мал. Нужно сначала определить сначала , что за компилер. Если сишный, то отправить нагуй классы и прочее, Проанализировать, границы объектных модулей, выявить их сущность, для чего они предназначены. Типа если чувак пишет структурно, в башке ветер не гуляет, то яйца он будет класть раздельно. Типа в одном модуле - функи вывода на консоль, в другом - например, дизассемблер, в третьем - работа с файлами. И исходя из этого налжить тока соответствующие им паттерны библиотечных функций. Отличный пример к этому дельфя с применеием vcl. В своем пакайче он всем сразу говорит, что за стандартные модули в нем использованы, типа system, forms, controls и т.п. Так что стопроцентно можно выявить все библиотечные функи и к тому же правильно. А лишние паттерны не сувать анализатору, чем например, грешит, ИДА. А это нам даст 50 % выявленных типов данных, функций, глобальных переменных и т.п. Для выявления сложных в алгоритмическом отношении потока кода придется создать мало -мальскую библиотеку идиом сответсвующего компилятора. Стандартные библиотеки С и С++, STL и т.п. должны быть безошибочно идентифцированы. Так как это кирпичик, с помощю которых декомпилятор будет заново воссоздавать юзверские типы данных. Для укрощения оптимизатора на мой взгляд, нжен эмулятор процессора, который будет отслеживать и передавать информацию канешно же анализатору. Это для начала. Честно говоря, я в тупике насчет кода, предложенного by S_T_A_S_. Для идентификации типа этих данных нужно отследить манипуляции с этими данными в местах, про которые декомпилятор точно знает, что где как. Иначе оставлять такой код в очереди проблем и возвращаться потом или предлагать хозяину самому поработать башкой.
MrHammer Что-то ты загнул. Как ты собираешься выявлять сущность модулей? Да и зачем это нужно? Только для того, чтобы улучшить выявление стандартных процедур? А если всё-таки "у чувака в башке ветер гуляет" - декомпилер откажется работать? Конечно, хорошо, если имеющаяся дополнительная информация будет использоваться по максимуму. Но плох тот декомпилятор, который рассчитывает только на это и пасует перед голым оптимизированным машинным кодом. Не совсем понятна идея. На мой взгляд, вся информация о поведении каждой машинной инструкции должна быть учтена на этапе декодирования и генерации промежуточного кода. А анализ должен производится уже над ним; соответственно, эмулятор процессора ни к чему. А мне это код кажется как раз не очень сложным. Конечно, "точные" типы данных и имена полей ты не получишь, но это далеко не всегда важно. Зато можно установить факт наличия массива структур/классов, определить их размеры. А если в дальнейшем идёт какая-то работа со структурами, то возможно удасться уточнить типы данных.
эээххх, люблю когда проценты приводят "от фонаря". Ты имеешь какую-то статистику о том какой процент от всех используемых данных передаются в библиотечные функции ? так откуда такая взялось 50 ? и с самими библиотечными функциями не все так гладко, трудности не заканчиваются совпадением шаблона с неким участком кода, слишком часто почему-то одному участку соответствуют несколько шаблонов от разных функций и надо еще правильно разрулить коллизии. и что такое "библиотека идиом компилятора" ? и опять-таки почему "мало-мальская" библиотека поможет ?
Только что прочитав парочку статей Mаrtin Wаrd-a от 2004 года. Возможно, будет интересно: Pigs from Sausages? Reengineering from Assembler to C via FermaT Transformations. http:/www.dur.ac.uk/martin.ward/martin/papers/migration-t.pdf Size: 306 KB (313 100 bytes) Legacy Assembler Reengineering and Migration http:/www.dur.ac.uk/martin.ward/martin/papers/legacy-assembler-t.pdf Size: 97 KB (98 609 bytes) Также можно попробовать начать отсюда: catamaran.labs.cs.uu.nl/twiki/pt/bin/view/Transform/DeCompilation
Был некоторый перерыв. sen проценты приведены от балды, на глазок. А что за фиг с оптимизатором? Приведу наиболее очевидные оптимизации и пути решения. 1. switch ... case Про это Касперски хорошо написал. Если в ассемблерном коде это последовательность if - else, то поверяется одна и та же переменная. если переходы, то иногда компилятор делает так. Наприемер, byte i; switch ( i) { case 2: case 3: case 4: ... } компилер может сделать так. cmp i, 2 jb end_switch jmp [dword (case_tbl -4*2) + i*4] case_tbl: offset case_2 offset case_3 offset case_4 Это обойти тоже несложно. Связывание хвостов. Компилер мелкого любит обьединять коды функций. чтобы узнать весь код процедуры , нужно протрассировать все концы процедуры. Имплементация данных. Например есть ситуация , то ли переменная размером в байт , то ли int. Следуя стандарту, сделаем переменную размером в слово. Так и со структурами, классами. Лишние элементы в структуре не помеха. кстати, вот ответ, зачем использовать доп. информацию. протрассируем все вызовы new, malloc и будем в курсе насчет размеров структур и т.п. Следующая шпилька. Высказывание насчет того, чтобы не использовать доп. инфу у меня ассоциируется со след. образом: драться на улице по правилам ринга или рыцарских понятий. Мы хотим сделать декомпилятор, который сможет рисоваться тока на татами или волчару, разрывающего в клочья противника? Любая информация для декомпилятора - это оружие в помощь ему. Драка на улице молниеносна, так как обычно там давят толпой одного. И если одиночка не свиреп, не умеет выпустить розочкой кишки противнику, ударить арматурой по горлу, то от него мокрого места не останется. Ориентация тока на голый машинный код многого не даст, тогда уж лучше воспользоваться Идой. Я ведь с самого начала говорил об определенных компиляторах.
Artem я имел в виду, что часто, очень-очень часто фнкции модуля оказываются рядом и впоследовательности, как в исходнике. Так какая же проблема в нахождении всех процедур стандартных библиотек? Принятие во внимание вышесказанного снимает проблему идентификации двух одинаковых в ассемблерном коде, но разных по смыслу функций. Дает на вход декомпилятору либы статические станд. библиотек, делаем паттерны, применяем в программе, что даст 100-% выявление границ модулей, после которого мы область , где находятся функции либ, можем не анализировать в принципе, декомпилятору известно, что это область станд. библиотек и автоматом может делать вызовы этих функций внешними. Ща задолбался писать, астальное напишу патом.
кстати, чтобы не быть голословным приведите конкретной программы, декомпиляция которой вызывает такие проблемы. спасибо за внимание.