Дизассемблер [Mediana]

Тема в разделе "WASM.PROJECTS", создана пользователем Mika0x65, 26 мар 2010.

  1. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Мое почтение всем.

    Довольно давно пишу дизассемблер, наконец-то есть что показать. Т.к. справка слишком большая для одного поста, подробнее прочитать о дизассемблере можно здесь http://mika0x65.livejournal.com/6898.html#cutid1 . Здесь же приведу пример использования и ссылку для скачивания:

    Код (Text):
    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include "mediana.h" //Главный заголовочный файл дизассемблера.
    4.  
    5. #define OUT_BUFF_SIZE 0x200
    6. #define IN_BUFF_SIZE  14231285
    7. #define SEEK_TO       0x0
    8.  
    9. int main(int argc, char **argv)
    10. {
    11.     uint8_t sf_prefixes[MAX_INSTRUCTION_LEN]; //Массив избыточных префиксов.
    12.     unichar_t buff[OUT_BUFF_SIZE];            //Выходной буфер печати инструкции.
    13.     struct INSTRUCTION instr;                 //Выходная инструкция.
    14.     struct DISASM_INOUT_PARAMS params;        //Параметры дизассемблера.
    15.  
    16.     uint8_t *base, *ptr, *end;
    17.     int reallen;
    18.     unsigned int res;
    19.     FILE *fp;
    20.  
    21.     params.arch = ARCH_ALL;                                                 //Включая все архитектуры.
    22.     params.sf_prefixes = sf_prefixes;                                       //Подключение массива избыточных префиксов.
    23.     params.mode = DISASSEMBLE_MODE_32;                                      //Режим дизассемблирования.
    24.     params.options = DISASM_OPTION_APPLY_REL | DISASM_OPTION_OPTIMIZE_DISP; //Все опции.
    25.     params.base = 0x00401000;                                               //Базовый адрес первой инструкции.
    26.  
    27.     base = malloc(IN_BUFF_SIZE);
    28.     ptr = base;
    29.     end = ptr + IN_BUFF_SIZE;
    30.  
    31.  
    32.     fp = fopen("asm_com2.bin", "rb");
    33.     fseek(fp, SEEK_TO, SEEK_SET);
    34.     fread(base, IN_BUFF_SIZE, 1, fp);
    35.     fclose(fp);
    36.  
    37.  
    38.     while(ptr < end)
    39.     {
    40.         res = medi_disassemble(ptr, &instr, &params); //Disassemble!
    41.         if (params.errcode)
    42.         {
    43.             printf("%X: fail: %d, len: %d\n", ptr - base, params.errcode, res);
    44.             if (res == 0)
    45.                 res++;
    46.         }
    47.         else
    48.         {
    49.             reallen = medi_dump(&instr, buff, OUT_BUFF_SIZE, DUMP_OPTION_IMM_UHEX | DUMP_OPTION_DISP_HEX); //Эта ф-ия будет описана ниже.
    50.             if (reallen < OUT_BUFF_SIZE)
    51.                 buff[reallen] = 0;
    52.             else
    53.                 buff[OUT_BUFF_SIZE - 1] = 0;
    54.  
    55.             printf("%X: %s\n", ptr - base, buff);
    56.         }
    57.         ptr += res;
    58.         params.base += res; //Высчитываем базовый адрес следующей инструкции.
    59.     }
    60.  
    61.     return 0;
    62. }
    Скачать дизассемблер можно здесь: http://mediana.sf.net . Буду рад предложениям, отчетам об ошибках и откликах в целом :).
     
  2. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Mika0x65
    Так как дизасм вестма часто используется для создания графа(это базовая задача для которой нужен дизасм), то не плохо былобы сделать двиг.
     
  3. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Стукни в жаббер мне, пообщаться хочу.
     
  4. spa

    spa Active Member

    Публикаций:
    0
    Регистрация:
    9 мар 2005
    Сообщения:
    2.240
    Clerk
    +1
     
  5. luckysundog

    luckysundog New Member

    Публикаций:
    0
    Регистрация:
    28 окт 2008
    Сообщения:
    106
    прогонялся ли дизасм на больших кусках кода? насколько стабилен?
     
  6. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Clerk
    Как ты это себе представляешь (в общем)?

    x64
    Завтра вечером.

    luckysundog
    Да. В разделе "Немного мыслей о дизассемблировании" немного описано тестирование. Прогонял дизассемблер на этом файле: http://sourceforge.net/projects/mediana/files/tests.bin/asm_com2.bin/download И еще несколько человек тестировали на исполняемых. Думаю, что основные ошибки уже отловлены.
     
  7. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Отлично, жду. Если что, пиши в оффлайн, и когда ты будешь доступен в следующий раз. Примерно раз в сутки я обязательно выхожу в сеть.
     
  8. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Mika0x65
    Опишу как работает мой двиг.
    1. Граф представляет собой двусвязанный список описателей. Каждый описатель определяет одну инструкцию, либо группу инструкций(опционально, если например в группе инструкций нет ветвлений, то определена длина блока). Описатели связаны ссылками, прямыми и обратными. Для ветвлений также определены ссылки на блоки. Список позволяет перемещать в памяти описатели, заменять их и делать вставки(морфинг), трассировать граф, благодаря обратным ссылкам трассировать граф в обратном направлении. Базовые бве процедуры - парсер, он и дизасмит код и создаёт граф и трассировщик маршрута, который перечисляет все входы в таблице. Обработка релоков и прочие вещи не включены в базовый функционал, а оформляются в виде калбэков, из которых можно формировать цепочки. На вход парсера передаётся адрес разбираемого кода, буфер, флажки и ссылки на калбэки. На выходе получается граф. Буфер расширяемый, так как размер графа заранее не известен.
    2. Далее из полученной таблицы(сырая) формируется вторая таблица. В ней элементы перестроены(изза вставок сделанных парсером), удалены ветвления использующие регистр Ecx(Loop, Jcxz etc., точнее в первичной таблице отдельной проедурой). Эта таблица и используется при изменении и сборке кода. Таблица необходима для оптимизатора, который удаляет холостые ветвления(Jmp short $+2, ветвления на ветвления и пр.), перестраивает некоторым образом код. После чего он уже собирается(компилируется).
    Парсер это минимально необходимый функционал(1).
     
  9. luckysundog

    luckysundog New Member

    Публикаций:
    0
    Регистрация:
    28 окт 2008
    Сообщения:
    106
    если уж и кодить граф, то делать это максимально абстрагированно от какого-либо дизассемблерного движка. т.е. как отдельный проект уже. imho
     
  10. luckysundog

    luckysundog New Member

    Публикаций:
    0
    Регистрация:
    28 окт 2008
    Сообщения:
    106
    ну а общение с конкретными дизассемблерами делать через интерфейсы.
     
  11. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    luckysundog
    Именно. Вам например не нужно будет изучать дизасм для создания графа. Иначе придётся его изучать и писать двиг самостоятельно, что обычно весьма проблемно ибо все нюансы не известны. Обычно отлично от двига создающего граф дизасм не юзается, поэтому двиг должен быть по любому, иначе нафиг никому это не нужно. Разбор структур дизама не проще чем разбор инструкций.
     
  12. jabocrack

    jabocrack New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2010
    Сообщения:
    96
    Код (Text):
    1. unsigned int medi_disassemble([b]uint8_t *offset[/b], struct INSTRUCTION *instr, struct DISASM_INOUT_PARAMS *inout_params).
    Чето сыкотно передавать функции указатель на дизассемблируемый код))).
    Так как вполне возможно, что при декодировании функция вылетит за пределы буфера.
    Желательно вместо указателя offset принимать функцию-callback для чтения требуемых байтов.
     
  13. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Реально грамотное решение, поддерживаю. Например, в режиме ядра не всегда есть возможность напрямую прочитать байты. К тому же, источников ассемблерного кода может быть сколько угодно, и гораздо удобнее предусмотреть универсальное решение, коль скоро мы пакет разработчика делаем.
     
  14. spa

    spa Active Member

    Публикаций:
    0
    Регистрация:
    9 мар 2005
    Сообщения:
    2.240
    +1
     
  15. spa

    spa Active Member

    Публикаций:
    0
    Регистрация:
    9 мар 2005
    Сообщения:
    2.240
    и еще, лучше 2 варианта )) хотя для меня пока не решает, но я решил заменить HDE на этот, он развивается, есть 64 бита си изначально одни плюсы для меня )
     
  16. spa

    spa Active Member

    Публикаций:
    0
    Регистрация:
    9 мар 2005
    Сообщения:
    2.240
    Правда не люблю я прикручивать калбеки к классам )) очень уж это не очень
     
  17. jabocrack

    jabocrack New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2010
    Сообщения:
    96
    или так:
    Код (Text):
    1.  unsigned int medi_disassemble(int8_t *offset, uint32_t BufLen, /* ляляля */ );
     
  18. sl0n

    sl0n Мамонт дзена **

    Публикаций:
    0
    Регистрация:
    26 сен 2003
    Сообщения:
    684
    да ну вас , взяли ту же память в ядре проверили , сколько нужно отдали дизасму ... какие то кастыли мастырите
     
  19. jabocrack

    jabocrack New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2010
    Сообщения:
    96
    Мне то нужно тока то , чтобы библиотека учитывала возможность выхода за пределы буфера чтения.
    1 вариант решения - callback, скрывает обращение к памяти и более инкапсулирован, чем 2, и позволяет простой заменой callback-функции на другую, дизассемблировать например, код ядра, или процесс на удаленной машине.
    2 вариант - более легкий для вызова из ОО-программ.
     
  20. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Обычно сказано сколько байт дизасм читает максимально. Нормально он не должен читать более, чем длина инструкции, иначе например если инструкция в конце страницы, это привидёт к исключению, чего быть не должно.