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

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

  1. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    Я может плохо понимаю, но вроде плагин это dll? Что мешает ставить свои обработчики, те же try/except? Или имеется в_виду исключения, которые возникают не в плагине?
     
  2. Vam

    Vam New Member

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

    Эти обработчики меня не интересуют, т.к. довольно сложно локализовать места их размещения и они усложняют код.
    Я API функцией SetUnhandledExceptionFilter(lpFilter) устанавливаю обработчик исключений верхнего уровня, но всё дело в том, что этот обработчик lpFilter никогда не вызывается, вместо него всегда идет вызов внутреннего обработчика исключений IDA. Вот в этом и вопрос - что препятствует вызову моего обработчика?

    Нет, меня интересуют только ситуации в моем коде, которые и должен анализировать обработчик.
     
  3. xorrax

    xorrax New Member

    Публикаций:
    0
    Регистрация:
    6 ноя 2008
    Сообщения:
    11
    Функция SetUnhandledExceptionFilter используется для установки фильтра необработанных
    исключений, которые достаются ему (фильтру) от VEH и SEH обработчиков, которые отрабатали
    первыми и отказались обрабатывать исключение.

    Код (Text):
    1. #include <stdio.h>
    2. #include <windows.h>
    3.  
    4.  
    5. LONG WINAPI
    6. UefHandler(
    7.     __in struct _EXCEPTION_POINTERS *ExceptionInfo
    8. )
    9. {
    10.     printf("%s\n", "UefHandler");
    11.     return EXCEPTION_CONTINUE_SEARCH;
    12. }
    13.  
    14. LONG CALLBACK
    15. VehHandler(
    16.     __in struct _EXCEPTION_POINTERS *ExceptionInfo
    17. )
    18. {
    19.     printf("%s\n", "VehHandler");
    20.     return EXCEPTION_CONTINUE_SEARCH;
    21. }
    22.  
    23. LONG WINAPI
    24. LocalHandler()
    25. {
    26.     printf("%s\n", "LocalHandler");
    27.     return EXCEPTION_CONTINUE_SEARCH;
    28. }
    29.  
    30. int main()
    31. {
    32.     __try {
    33.  
    34.     PVOID VehHandle;
    35.     LPTOP_LEVEL_EXCEPTION_FILTER TopLevelFilter;
    36.  
    37.     TopLevelFilter = SetUnhandledExceptionFilter(UefHandler);
    38.     VehHandle = AddVectoredExceptionHandler(TRUE, VehHandler);
    39.  
    40.     __asm {
    41.         xor eax, eax
    42.         mov [eax], eax
    43.     }
    44.  
    45.     }
    46.     __except(LocalHandler()) {
    47.     }
    48.  
    49.     return 0;
    50. }
    Подробнее см. Рихтера, главы 24 и 25.
     
  4. Vam

    Vam New Member

    Публикаций:
    0
    Регистрация:
    16 июл 2008
    Сообщения:
    149
    xorrax
    Спасибо, я это знал, просто хотелось как попроще. Посмотрел список обработчиков исключений, которые сидят на процессе в IDA (перед вызовом любой моей функции плагина) - их оказалось около 12 штук, понятно, что какое-то из них обрабатывает все исключения и дальнейшим ничего не остается.
    Сделал таким образом: каждую функцию, вызываемую из IDA обернул в блок __try...__except(Handler) - и всё заработало.
     
  5. Vam

    Vam New Member

    Публикаций:
    0
    Регистрация:
    16 июл 2008
    Сообщения:
    149
    Близится к завершению работа над последней (на сегодняшний день) частью проекта - создание и запись компилируемых модулей (это чаще всего пара файлов cpp и h). Пример полученного модуля во вложении. По завершению этой части предварительная версия программы будет предложена на тестирование на определенных условиях.
    Приведу некоторую статистику по работе предыдущей части проекта - декомпилятор функций. Тест проводился на 3-х экзешниках, результаты:
    Кол-во функций Кол-во отложенных декомпиляций Кол-во функций с ошибками
    8946 41 43
    4672 15 32
    2893 8 19
    Как видно из статистики, кол-во (на сегодняшний день) недекомпилируемых функций не превышает 1% от общего числа функций, остальные функции были успешно декомпилированы. В принципе можно сделать так, чтобы все функции были успешно декомпилированы, но это вопрос только времени. Главное здесь то, что процесс декомпиляции при возникновении исключения или любой другой ошибки не прерывается, а сохраняет все логи по "проблемной" функции и переходит к декомпиляции другой функции.
     
  6. s0larian

    s0larian New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2004
    Сообщения:
    489
    Адрес:
    Крыжёпполь
    Выглядит код суперски. Но это при наличии debug info, так?
     
  7. Vam

    Vam New Member

    Публикаций:
    0
    Регистрация:
    16 июл 2008
    Сообщения:
    149
    s0larian
    Конечно так, иначе откуда бы взялись имена локальный переменных?
    Я уже говорил, что все сказанное ниже относится только к первому этапу разработки, см. пост №1, и только после его логического завершения будут реализовываться следующие этапы, а так как помощников пока не нашлось, то это процесс не быстрый.

    Согласен, здесь есть неточность, но поясню, в коде встречается два вида memsetов и прочих mem...:
    1. Реализованы через цепочечные команды (префикс rep) - в исходники они в таком виде не попадут, а будут или уничтожены (за ненадобностью), как вспомогательные или преобразованы в операцию присвоения структур или другие. Написание в промежуточном тексте mem..., размер в двордах.
    2. Вызовы библиотечных функций, в исходниках будут как есть, написание _mem...
    Всему свое время, повторяться больше не буду.
    Если читали внимательно, то ответ на этот вопрос был - пока только VC.
    Не только вам, но терпение ещё никому не вредило...
    А вас юзать никто и не заставляет, юзать будет программа и создавать исходники так близко к оригиналу, насколько это возможно и применены здесь будут все доступные методы, в том числе и дебаг инфа и сигнатуры библиотек и прочее... (опять повторяюсь)

    Вопрос: чем или как может быть сгенерен идентификационный код вида
    {051E3FA4-A09D-41C2-A61B-350662962990}
     
  8. Johnikum

    Johnikum Member

    Публикаций:
    0
    Регистрация:
    6 июн 2003
    Сообщения:
    97
    под Windows: CoCreateGuid() OLE32.dll
    вообще: uuid.lib
     
  9. keYMax

    keYMax New Member

    Публикаций:
    0
    Регистрация:
    2 июл 2003
    Сообщения:
    276
    Адрес:
    Новоуральск
    или генератором из вижуал студио

    Visual Studio 6
    C:\Program Files\Microsoft Visual Studio\Common\Tools\GUIDGEN.exe

    Visual Studio 8
    C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\guidgen.exe
    C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\Bin\GuidGen.exe
     
  10. Vam

    Vam New Member

    Публикаций:
    0
    Регистрация:
    16 июл 2008
    Сообщения:
    149
    Вопрос: Как сделать отрисовку (redraw, refresh) главного окна IDA из плагина?
    Декомпиляция большой программы может продолжаться до часа времени, если переключиться во время работы плагина на другое окно винды, то вернуться к IDA окну мы не сможем до окончания работы плагина. Вызов SDK функций refresh_idaview и refresh_idaview_anyway из плагина результата не дает.
     
  11. Vam

    Vam New Member

    Публикаций:
    0
    Регистрация:
    16 июл 2008
    Сообщения:
    149
    Да, "знатоков" IDA SDK не видно, тогда поделюсь своими соображениями, может кому-нибудь это пригодится.
    Осталось сделать последний кусочек программы перед тестированием - управление и визуализация процесса декомпиляции, который к самой декомпиляции никакого отношения не имеет. В принципе визуализация уже существует - вывод в стандартное окно сообщений IDA. От управления пока требуется совсем немного - при запуске функции декомпиляции блокировать контролы интерфейса IDA и иметь возможность принудительного завершения декомпиляции пользователем. Причем, управление и визуализация должны работать стандартным образом - при запуске или переключении на другую программу в Винде декомпиляция должна продолжаться, а при возврате обратно мы должны получить и визуализацию и управление. В общем, это банальные вещи, и в любой самостоятельной программе реализуются на раз ... два, но не в IDA.
    Запустить функцию декомпиляции из плагина IDA можно тремя способами:
    1. Из стандартной функции run() плагина.
    2. Из меню IDA, предварительно добавив обработчик add_menu_item(...).
    3. Из отдельного процесса _beginthread(...), который запускается способом 1 или 2.
    Разницы в работе между 1 и 2 практически нет, за исключением одного момента, когда запускаем 3 из 2.
    А теперь результаты экспериментов с этими тремя способами.
    Запуск декомпиляции через 1 и 2:
    Работа - основное окно IDA со всеми контролами блокируется, работает визуализация в окно вывода. Если дождемся, ничего не делая, окончания работы декомпилятора, то IDA разблокируется - и всё ОК.
    Недостатки - переключившись на другое окно, обратного возврата не будет и принудительно завершить работу декомпилятора не можем, т.к. все контролы заблокированы.
    Запуск декомпиляции отдельным процессом, способ 3:
    Работа - на однопроцессорных системах все работает при условии блокировки контролов IDA хотя бы вызовом show_wait_box(...), который можно использовать и для завершения работы декомпилятора, визуализация при переключении процессов сохраняется. Но, если во время декомпиляции начать работать, например в Word, то получаем мертвый цикл в IDA во время вызова из процесса декомпиляции идашной функции визуализации сообщения msg(...).
    С многопроцессорными системами всё намного хуже, причем наблюдается зависимость от способа запуска процесса - через 1 или 2. При способе 2 обработчик после вызова процесса может завершить работу с кодом 0 или 1 (не документировано). Если завершаем работу с кодом 0, то способ 2 аналогичен способу 1, если завершаем с кодом 1, то получаем сразу исключение в IDA с завершением работы.
    Если же процесс запущен способом 1 (или 2 с кодом выхода 0), то получаем исключение в IDA при вызове из процесса декомпиляции практически любой функции IDA. Почему так, не знаю, возможно работает распараллеливание разных процессов между процессорами системы, а методов синхронизации процессов в IDA нет.

    Вот такие "пироги", решения пока так и не нашел...
     
  12. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    Не могу понять, зачем потоки называть процессами?..

    Поскольку IDA вызывает фукцию плагина из основного цикла обработки
    сообщений, то для такого способа, видимо, нужно регистрировать callback'и
    и самостоятельно париться с синхронизацией работы плагина и различных изменений базы,
    так как в IDA ничего этого нет (я про синхронизацию к базе).
    Проще, как ты сказал, залочить контролы через show_wait_box().

    Что-то ты где-то намудрил или я недомудрил, у меня работает:
    Код (Text):
    1.     show_wait_box("%s", "Please wait...");
    2.     int i = 0;
    3.     while (1) {
    4.        
    5.         if (wasBreak()) {
    6.             hide_wait_box();
    7.             break;
    8.         }
    9.  
    10.         Sleep(500);
    11.         msg("msg %d\n", i++);
    12.     }
    Хотя тут идёт периодический вызоыв wasBreak(), в котором IDA и перерисовывает свой интерфейс.
    Но даже если Sleep+msg засунуть в цикл, то всё равно всё работает. Причем тут Word, хз...

    Я ничего не понял, или тут снова "процесс" = "поток"?
     
  13. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    Хм, действительно, я недомудрил, нужно просто цикл подольше сделать :)
    Но решение тоже - вызов wasBreak() для обновления интерфейса.
     
  14. Vam

    Vam New Member

    Публикаций:
    0
    Регистрация:
    16 июл 2008
    Сообщения:
    149
    nester7
    За ответ спасибо, очень помогло и всё заработало.
    До wasBreak() я не допер, кто бы мог подумать, что эта штука обновляет интерфейс, использовал для анализа Ctrl-Break функцию autoWait(), т.к. через автоанализ отображаю индикатор состояния и адрес обрабатываемой функции в строке статуса.

    Привычка такая, вредная.
    Это лишнее, т.к. обработка функции идет приличное время, Sleep также убрал для повышения быстродействия.

    Всё таки спрошу, ради просвещения, как грамотного в этих вопросах человека, потоки и IDA совместимы?
    Я раньше встречал примеры плагинов с использованием потоков, которые работали на однопроцессорной платформе, а на мультипроцессорной у меня не работают.
     
  15. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    К сожалению, до грамотного человека мне далеко :dntknw:

    Это говорит о том, что и на однопроцессорной машине плагин работает неправильно,
    просто сложнее поймать момент модификации данных, особенно, если они (модификации) "короткие",
    аля gVar = SomeValue. На многопроцессорной машине проблема встает в полный рост
    из-за одновременного выполнения потоков, что увеличивает шансы косяков.


    К сожалению, я понятия не имею как работает ида - в каких потоках
    и что выполняется, откуда поступают запросы на реанализ и прочее, но мысль у меня такая:
    1. ида не предоставляет функций для синхронизации доступа к базе.
    2. Вызов плагина идет в основном цикле обработки сообщений.
    3. Внутри PLUGIN->run() можем не бояться (?) за синхронизацию.
    4. Плагин, выполняясь в отдельном (долгом) потоке, может посылать сообщения, ака запуск плагина.
    5. Имеем два потока, которые нужно синхронизировать: из run "увидеть", что мы были вызываны
    для синхронизации, и просигнализировать это долгому потоку, затем дождаться, когда он закончит
    свою работу чтобы выйти из текущего (программного) вызова плагина.
    6. Если пользователь модифицирует базу, ставить callback'и на это дело и совать сообщения
    в очередь для повторного анализа этого места нашему долгому потоку.

    Видимо да, но без непростых телодвижений, видимо, не обойтись.
    Хотя, хз - не интересовался, было бы лучше, если бы я ошибался :)
     
  16. Vam

    Vam New Member

    Публикаций:
    0
    Регистрация:
    16 июл 2008
    Сообщения:
    149
    nester7
    Согласен, при запуске декомпиляции отдельным потоком на однопроцессорной машине всё в общем работало, но при декомпиляции некоторых функций появлялись непонятные ошибки, которых не было при запуске через run() или меню.
    Думаю, что да, как и при запуске через меню.
    Интересен не этот момент, когда run(), т.е. плагин создает новый поток и производится сихронизация между ним и новым потоком (это в принципе не сложно реализовать), а другой - когда run() создает новый поток и завершает свою работу, а поток продолжает работу с ида через ui интерфейс и другие, как в этом случае обеспечить синхронизацию его с ида? Это было бы здорово при реализации интерактивности в плагине, например, идет процесс декомпиляции всей программы, а в это время мы можем работать в GUI и исправлять найденные декомпилятором ошибки или неточности. Аналогично автоанализу в Ида, когда пользователь и автоанализ работают одновременно.
     
  17. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    Я как раз и имею ввиду, что "долгий" поток вызывает как бы сам себя, всего лишь для синхронизации доступа к базе.
    Нечто, вроде PostThreadMessage главному окну (потоку) иды. И когда она будет обрабатывать это сообщение, то и войдет в наш PLUGIN->run.
    В этом месте будет два потока:
    1 - от иды, её основной поток, в котором мы через различные меню модифицируем базу.
    2 - наш, который ждет сигнализации от PLUGIN->run (который должен "сказать" (просигнализировать) ждущему (второму) "работай, база залочена".
     
  18. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    Я говорю про момент, когда плагин уже работает, он уже побывал в один раз в run и создал поток,
    который "продолжает работу с ида через ui интерфейс и другие". Возможно тут нужны корректировки,
    что именно он делает/вызывает, но основная мысль такая - поток, запущеный из плагина, должен дождаться,
    когда ида (её основной поток), снова войдет в какой-нибудь плагин, в его функцию run().
    Ну, например, в наш же :)
    Код (Text):
    1. void
    2. run(
    3.     int arg
    4.     )
    5. {
    6.     static HANDLE hWorker;
    7.     static HANDLE hEvent;
    8.  
    9.     if (!hWorker) {
    10.         hWorker = CreateThread(...);
    11.         hEvent = CreateEvent(...);
    12.     }
    13.     else {
    14.         SetEvent(hEvent);
    15.     }
    16. }
     
  19. Vam

    Vam New Member

    Публикаций:
    0
    Регистрация:
    16 июл 2008
    Сообщения:
    149
    nester7
    Это, конечно, интересно, надо будет как-нибудь попробовать, только каким образом заставить ида постоянно выполнять это
    .
    А может можно вместо второго и следующих заходов в плагин использовать для синхронизации IdleFunc активированную через callui(ui_setidle, IdleFunc);, при условии, что эта функция будет вызываться идой и после окнчания работы run().
     
  20. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    См. #99

    Хоткей на запуск плагина или доступ через меню Edit-> Plugins -> PluginName есть,
    по сути, посылка сообщения окну иды, в обработчике которого и идет вызов PLUGIN->run.
    Это же можно сделать программно.