Декомпилятор С++

Тема в разделе "WASM.RESEARCH", создана пользователем Vam, 16 июл 2008.

  1. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Vam
    На 4-м проходе получилось хз что.
    Спортил дизасм :lol: DD
     
  2. Vam

    Vam New Member

    Публикаций:
    0
    Регистрация:
    16 июл 2008
    Сообщения:
    149
    Zlyden
    Окончательную дату выхода программы назвать пока невозможно, работаю один, всё зависит от свободного времени и от того как пойдут дела дальше.
    Могу назвать примерный планируемый срок завершения ядра программы для полной дебаг информации - конец этого года.

    Clerk
    Не понял? :rolleyes: (вроде и не вопрос и не ответ)
     
  3. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Vam
    Вы учитываете, что понятие ф-ции в сильно оптимизироанном коде (какой делает, скажем, MSVC++) довольно расплывчато? .Переход на ф-цию часто делается jmp вместо call, 2 ф-ции могут получить частично перекрывающийся код, ф-ция режется на куски с jmp между ними, если к ф-ции нет косвенного обращения (т.е. ф-ция неэкспортируемая, невиртуальная, не вызывается по указателю), то компилятор не сохраняет конвенцию вызова этой ф-ции (т.е. аргументы могут передаваться в такую ф-цию, вообще говоря, произвольным образом - часть через стек, часть через какие-нибудь регистры, или хз ещё как на усмотрение компилятора).

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

    Если выбирать для исследования дизасм или фантазии декомпилятора, то IMHO, лучше дизасм.
     
  4. Vam

    Vam New Member

    Публикаций:
    0
    Регистрация:
    16 июл 2008
    Сообщения:
    149
    green
    Конечно. Но любой компилятор работает по своим "жестким" правилам, "фантазий" (как написано у вас выше) не позволяет, следовательно, под конкретный компилятор можно сделать декомпилятор, учитывающий эти правила. Все дальнейшее относится только к MSVC.
    Реализовано.
    Реализовано.
    Реализовано.
    Реализовано, только "произвольным образом" - это неверно, аргументы передаются в функцию по определенным правилам, тоже относится и к возвращаемому значению.
    Хотя это и так, но присвоение - в любом случае останется присвоением, цикл - циклом, if - оператором условного перехода и т.д. Наличие оптимизаций не отменяет эти конструкции, а только только модернизирует их, следовательно, границы любых конструкций различимы.
    Почему я так уверенно об этом говорю - потому, что у меня большой опыт восстановления вручную рабочих исходников из кода программ, как с наличием дебаг информации, так и без неё (работаю в этой области более 10 лет, самый большой проект по восстановлению - современный игровой движок). В любом случае был получен рабочий листинг, который компилировался и работал без отличий от оригинала, ну а соответствие исходникам оригинала здесь непринципиально (мы же все равно их не имеем), да и полностью невозможно.
    Если кто-либо напишет программу умеющую фантазировать как человек, то ему надо памятник поставить. Если же под "фантазиями" понимать неточности программы в таком деле, как реверсинг, то где их нет? Взять тот же дизасм IDA - в нем иногда очевидное становится невероятным. Любые такие "фантазии" могут устраняться только по мере их обнаружения в следующих версиях. Здесь полностью справедлива народная мудрость - "Знал бы где упасть - соломки бы подстелил."
     
  5. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Vam
    Ну раз всё это реализовано - снимаю шляпу.

    Насчёт фантазий декомпилятора. Я имел в виду, что решение задачи декомпиляции на уровне "получить код С++, работающий как оригинал" хорошо подходит, скажем, для портирования на другую платформу, но для анализа алгоритма IMHO лучше подходит изначальный дизасм (в крайнем случае, декомпиляция в что-то уровня С-- или С).
    Ф-ционально эквивалентный декомпилированный С++ код может не иметь ничего общего с исходным С++-кодом в плане высокоуровневой логики.
    Фактически мы получаем между оригинальным исходником и кодом для анализа 2 нетривиальных некомпенсирующихся преобразования - оптимизация + декомпиляция, вместо одного.
    IMHO, конечно - опыта в этой области немного.
     
  6. Vam

    Vam New Member

    Публикаций:
    0
    Регистрация:
    16 июл 2008
    Сообщения:
    149
    green
    Для анализа алгоритма всегда лучше подходит тот язык на котором этом алгоритм реализован, т.е. для ассемблерного блока анализировать надо дизасм код, для С++ блока - декомпилированный вариант. Иначе мы получим в одном случае лишнюю избыточность, а другой просто не реализуем (некоторые конструкции ассемблера невозможно записать на Си). Программа как раз и использует эти конструкции для вставки блоков асм кода в тело С++ функции, главное здесь правильно осуществить связку между ними.
    Ну это уже слишком - алгоритм (это и есть логика работы) от варианта представления информации не меняется, изменяется только реализация алгоритма. Простейший пример: получить значение переменной в памяти - можно через указатель, можно как элемент массива, можно как возвращаемое значение инлайн функции и т.д., но в любом случае, вне зависимости от представления реализации - алгоритм один - берем значение переменной. Только на языке низкого уровня реализация может быть избыточна для понимания такого простого алгоритма.
    Не понял, что здесь подразумевается под оптимизацией?
    Могу сказать одно: имея оригинальный исходник мало кому придет в голову компилировать его и изучать алгоритм работы по ассемблерному коду.
     
  7. andruha123

    andruha123 New Member

    Публикаций:
    0
    Регистрация:
    18 мар 2004
    Сообщения:
    15
    Адрес:
    USA, CA
    Наверное, это про меня:)))))
    http://www.wasm.ru/forum/viewtopic.php?id=7275
    В свое время, после интенсивного выдирания кусков кода из чужих программ, я пришел к мысли что этот процесс может быть автоматизирован, что несомненно повысило бы производительность такого рода деятельности в 100..1000 раз)). Поиск существующего тула резултатов не дал, тогда я принялся за разработку своего. Наверное, автор пришел к тому же той же дорожкой)). Однако, приоритеты и цели у меня были немного другие.
    1)Концепт general декомпилятора. Одно ядро, разные frontends.
    2)Никакой зависимости от наличия debug-info, оптимизации и т д.
    3)Интерактивность, естественно.
    Сейчас, совершенно отпала необходимость выдирать куски чужого кода, но проект я не забросил. Сама задача декомпиляции мне по-прежднему интересна. Хотя времени практически нету. В основном, занимаюсь переписыванием старого кода, так сказать на новом уровне, с новой, или скорее, с наличием архитектуры. Честно говоря, мне не совсем понятны заверения автора о том что "переписывать ничего не придется", если конечно проект не будет заброшен, чего ему желаю. Также, некоторые его высказывания по сабжу мне показались несколько наивными, не в обиду будет сказано)). Но в целом, впечатления положительные. Удачи...
     
  8. s0larian

    s0larian New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2004
    Сообщения:
    489
    Адрес:
    Крыжёпполь
    andruha123, как твой tool в сравнении с HexRays?
     
  9. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    Vam, ко всему, что уже сказал green и в стоящую реализацию чего я слабо верю, меня очень интересует, что Вы собираетесь делать с поздним связыванием в С++? Таблицы виртуальных функций заполняются в run-time. Взять какой-нибудь популярный паттерн Class Factory, в оптимизированном исполняемом варианте его код в такую размазанную кашу превратится, что собрать его будет весьма непросто. Я уж не говорю про какие-нибудь продвинутые стратегии типа IoC, где создаются различные прокси-объекты и врапперы для связывания.

    Сейчас куча программ на С++ использует библиотеки boost, Qt, wxWidgets, MFC. В бусте сумашедшее кол-во абстрактных слоёв, а Qt свой метаязык. В MFC вообще половина библиотеки на макросах...

    Хм, а если я захочу воспользоваться OpenMP с её директивами и прагмами?

    В дебаг-сборке с полной инфой(кстати, разбор RTTI есть?) что-то отдалееееенно напоминающее исходный вариант получить наверное можно. Но то, что я видел в первом посте - это не С++, это обычный С, только вызов функций осуществляется через точечку.
     
  10. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    Кстати, компилятор не обязан следовать ни чему, кроме стандарта. Если стандарт не уточняет или говорит, что реализация зависит от компилятора, то в общем-то так оно и есть. Будет оно менятся в следующих версиях или не будет неизвестно.
     
  11. Vam

    Vam New Member

    Публикаций:
    0
    Регистрация:
    16 июл 2008
    Сообщения:
    149
    W4FhLF
    Не понял, что такое позднее связывание?
    Где ж вы такое в VS видели? Если брать обычный virtual элемент класса, то для него компилятор строит статическую таблицу по определенным правилам. Всё остальное может быть оберткой на стандартный С++ и скрыто от разработчика программ библиотеками, макросами, метаязыками и бог знает ещё чем. Здесь никаких ограничений нет, но в основе компилятора в любом случае стоит стандарт С++, определяющий правила представления информации и частично правила реализации конструкций.
    MFC очень хорошо поддается декомпиляции, а что до макросов, то по MFC можно сделать сделать базу данных, часть макросов может определяться по ней автоматом, а остальные, увы, только вручную (как и #define) посредством интерактивности. В бусте тоже нет ничего особенного, хотя и превуалирует шаблонность и абстрактность. Эти две особенности стандарта С++ в декомпиляторе реализуемы.
    Это всё библиотеки и к ним относится всё, что сказано выше. Я не претендую и не говорю, что представление информации в созданном исходнике будет соответствовать оригинальному исходнику программы, повторю - автоматом это сделать невозможно. Но гарантировать соответствие стандарту С++ вполне реально, как и компилировать созданные исходники и получать из них рабочий код.
    Если есть какие-либо сомнения по реализации конструкций стандарта С++, то прошу их озвучить. Мы можем вместе их обсудить.
    Я уже говорил, если есть полная дебаг инфа, то RTTI избыточен, ничего нового он не даст. При полном отсутствии дебаг инфы он полезен и будет реализован.
    Здесь дело не в представлении информации (да и вариант этот не окончательный), а в правилах её обработки. Я не буду расписывать чем отличается С от С++ (кому интересно - могут сравнить стандарты), просто отмечу несколько моментов, которые отсутствуют в С и реализованы в программе:
    - классы и как следствие виртуальность, полиморфность и абстрактность
    - проверка типов аргументов функций
    - шаблонность
    100% с этим согласен, но я и не говорил ничего, что бы противоречило этому. Могу только добавить, что если декомпилятор не будет учитывать реализацию кода компилятором, то получить исходник вида С++ проблематично, а соответствие некоторых конструкций просто невозможно.
    Я согласен с таким подходом: "1)Концепт general декомпилятора. Одно ядро, разные frontends.", как говорит andruha123. Здесь frontendsами могут быть зависимости реализации кода разными компиляторами, но до этого пока ещё далеко...
    Второй аспект: "2)Никакой зависимости от наличия debug-info, оптимизации и т д." тоже реализуем, но надо понимать, что чем больше дебаг инфы и меньше оптимизаций, тем ближе к исходнику можно получить представление и незачем его игнорировать.
     
  12. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Vam
    С повышением качества оптимизации компилятора в выходном коде всё меньше представлены особенности ЯВУ (из-за более полного использования потенциала инструкций cpu). И чем выше уровень целевого языка, тем больше предположений придётся делать декомпилятору. Это я имел в виду, говоря о "фантазиях".
    Более того, многие современные компиляторы имеют модульную структуру (frontend для каждого языка, и общий backend - оптимизатор и кодогенератор) и именно последний в основном определяет специфику генерируемого бинарного кода. Так построен, скажем, набор компиляторов GCC. Микрософт планирует выпустить SDK для создания сторонних фронтэндов и поддержки других языков на базе существующего backend VC++ (проект Phoenix).

    IMHO, лучше остановиться на уровне декомпиляции, когда избыточность кода (для алгоритмического анализа) уже устранена, но декомпилированный код ещё остается на приемлемом уровне однозначности относительно бинарного кода. Я сомневаюсь, что этот уровень - С++, скорее это С-- или, в крайнем случае, С.
     
  13. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Vam
    Если Вы реально можете распознать и декомпилировать конструкции шаблонных библиотек типа буста (без полной дебаг инфы), то беру свои возражения обратно.
     
  14. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    Vam
    Полиморфизм.

    Таблица заполняется в run-time в конструкторах объектов. Допустим такой простейший случай:

    Код (Text):
    1. void f(A* obj)
    2. {
    3.   obj->get();
    4. }
    Где класс A является абстрактным виртуальным классом и вы заранее никак не сможете узнать метод какого производного класса будет вызван.
    Только если научитесь распознавать виртуальность и разбирать RTTI, но это очень даже непросто. :)

    Ни шаблонность, ни абстрактность восстановить невозможно. По-крайней мере я не знаю как. :)

    Ага, будет там куча непонятных вызовов и лапша из условных переходов, а когда всё это заменитя var_ebp_NNN станет ещё хуже. :)

    У меня несколько вопросов по каждому пункту: как вы определяете абстрактность и виртуальное наследование? И ещё непонятно, как определить наследование простых, не виртуальных, классов.
    Что такое "проверка типоа аргументов"?
    Чем в исполняемом коде отличается шаблонная функция от нешаблонной? Стандарт говорит, что это раннее связывание(инстанциация) производится на этапе компиляции. В исполняемом файле не может быть отличий.
     
  15. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    Во, вспомнил. А как восстановить итераторы? Это ведь обычные указатели на уровне исполняемого кода. А как провести грань между ссылкой и указателем?
     
  16. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    W4FhLF
    Точннее, сама таблица вирт. ф-ций класса заполняется при компиляции (с точностью до релоков, конечно), а в рантайме в конструкторе объекта инициализируется только указатель на эту таблицу.
    К тому же RTTI присутствует далеко не всегда. Я, например, стараюсь без нужды не включать ни C++ ЕН, ни RTTI - для небольших бинарников получается значительная экономия в размере.
     
  17. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    green, спасиб за поправку. :)

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

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    Ага.

    Смысл в общем в том, что интроспекция в C++ практически невозможна.
     
  19. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    green, W4FhLF
    Зачем Вы так старательно убеждаете ТС в невозможности его интересной задумки?
    Если он во первых уже умеет кое-что из "невозможного" распознавать (пусть пока только вручную и потому не включил в демо программу), а во вторых и не претендует на 100% распознавание?
    Пусть у него получится хотя-бы 30% С++ кода 50% в виде С и оставшиеся 20% асм вставками - уже будет очень даже неплохо... Так что имхо лучше давать советы как улучшить распознавание, а не объяснять "почему этого не может быть никогда".

    Да МФЦ генерирует ту ещё лапшу, но это как раз и есть её "визитная карточка", т.е. путь к её распознаванию ;)

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

    Да и поиск инлайновых функций задача имхо скорее тяжёлая для машины, чем трудная для пишущего декомпилятор ;) Сначала распознаётся всё что удалось стрктурировать и идентифицировать, а затем в оставшейся "каше" можно уже зарядить на ночь тупой поск повторов кода и построить список по которому затем оператор выберет, что обзывать инлайн функциями/методами, а что оставить "кашей".
     
  20. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Y_Mur
    Почему убеждаем? Обсуждаем трудности реализации. :)
    Был бы рад убедиться, что подобная декомпиляция возможна.
    Не соглашусь. Всё зависит от того, какое из возможных структурирований выберет декомпилятор. IMHO, механическое структурирование по критерию эквивалентности бинарного кода в большинстве случаев лишь затруднит алгоритмический анализ кода.
    Я бы предпочёл, чтобы мои вещи лежали в беспорядке посреди комнаты, чем доверить кому-то разложить их по ящикам стола по своему усмотрению. :)
    Если бы... дело в том, что ф-ция инлайнится с учётом контекста. Генерация бинарного кода выполняется уже после инлайна. Т.е. в разных местах она может быть представлена разным бинарным кодом.