Зачем нужен дизасм длин ? обсуждать не будем. Вопрос в том как его лучше протестировать? (брать готовые или у меня есть кум который был моим хорошим другом, а в детстве он решал крутые задачи и написал крутой LDE - не принимаются ) Вообще два рода тестов: - Правильность - Скорость Правильность : 1) Как вариант сгенирировать большую таблицу со всеми инструкциями и сообственно говоря и сделать тест , но во первых не из чего генерировать а во вторых очень долгий тест. 2) Из каждой группы взять по N инструкций и проверять(можно забыть про какуету группу (( ) Какие буду варианты? Скорость: Зачекать время, но проблема будет в том какие инструкции будут дизасмится, ( с префиксом или без, 1 или двух байтовые) вообщем сдесь как понимаю нужна статистика используемых инструкций для задач в которым юзается дизасм длин , или ошибаюсь? П.С. Я не претендую что мои мысли основаны на здравом смысле, и кому то может показатся отсутствия смысла воовсе.. В данном конексте интересна теория. спасибо.
1) Это нетрудно, сгенерировать все инструкции. 1, 2, 3 байтные опкоды перебрать в простом цикле. Используя уже известный отлаженный дизассемблер длин. Кстати такой вот дизассемблер длин отлаженный уже имеется в каждом процессоре. А да так как опкодов всего чучуть то длина такого теста будет всего несколько килобайт около 10-20кбайт.
Pavia Сгенирить таблицу байт без проблем, вот только как сверять с ответами? То и есть после генерации мы ведь не знаем сколько байт инструкция, а остальное мусор?
shchetinin Используй сторонней дизассемблер длин для проверки своего. В конце концов можно включить режим трассировки и смотреть разницу ip.
Pavia Разницу ипов можно посмотреть если код валидный, в смысле сепшенов нет ... Сторонний канечно можно но хотелось бы как то изящней.
Если сторонний взять не вариант, тогда возможно пошаговая трасировка из Debug API подойдёт. Пример лежит здесь http://wasm.ru/article.php?article=1001030.
Можно получать аддресса исполняемых инструкций и дальше вычислять их длину. Похоже Pavia уже писал про это, только я не заметил.
shchetinin Корявенько, но с сепшенами можно придумать. EIP EIP+0Fh (max_len) V V xx xx xx ... xx xx xx cc cc cc cc ... Выполнили. Сепшен выбрасывается или в одной из инструкций, или на нашем int3 по eip+0fh. В хендлере сохранили весь контекст и ExceptionRecord. После дизасма оставляем только кусок предполагаемой длины: EIP EIP+expected_len V V xx xx ... xx cc cc cc cc ... Выполняем снова. Сравниваем контекст и сепшенинфо с предыдущими. Совпало - отдизасмили корректно. Ветвления, наверное, обрабатываем руками, тк с ними лишний геммор и двусмысленности.
shchetinin Pavia для интереса сгенерировал все инструкции (32-х битный режим; без префиксов, только опкод, modr/m и смещение, где нужно) для опкодов Код (Text): xxxxxxdw : modr/m xxxxxxxx : modr/m xxxxxxxw : modr/m (3 группы из 28) итого 286664 инструкции, 1370984 байт. http://depositfiles.com/files/98dq1zt1o
все варианты сгенерить нереально. по этому всё равно надо будет разбирать инструкцию по частям. А то так выходит что для mov eax, Z будет 4 миллиарда комбинаций. Так то проще взять официальную интеловскую (и амд) доку и посмотреть как генерятся все инструкции. Затем на основе этого уже генерировать таблицу всевозможных комбинаций убрав значения и адреса. Не забывая про оптимизированные опкоды (в частности для работы с регистром eax для одинаковых команд есть 2 разных опкода (стандартный и короткий))
slesh Генерировать таблицу с изменениями первых трех байт этого будет достаточно(остальные байты nop)
как вариант, родилась утиль: пока генерит только инструкции для 32-битного режима без префиксов, весь набор общего назначения (xx) и расширенные (0f xx). Проверяется как правильность декодирования валидных инструкций, так и неправильность декодирования инвалидных. Тестируемый дизассемблер оформляется в виде dll с интерфейсом Код (Text): extern "C" { const char _declspec(dllexport) * Name(); const char _declspec(dllexport) * Description(); unsigned int _declspec(dllexport) Version(); void _declspec(dllexport) * AllocStruct(); void _declspec(dllexport) FreeStruct(void*); int _declspec(dllexport) Disassemble(unsigned char*, int, bool, void*); bool _declspec(dllexport) FormatMnemonic(void*, char*, int); }; (все функции в экспорте должны быть без манглинга, _cdecl) (пример dll в аттаче) Name() возвращает указатель на строку с именем дизассемблера Description() >> >> с описанием Version() версия движка (hiword - major version, loword - minor version) AllocStruct() многие движки возвращают результат декодирования в какой-либо структуре. Эту структуру и выделяет функция. Формат структуры не имеет значения - генератор ее не использует. Этот указатель будет передаваться в Disassemble() и FormatMnemonic() FreeStruct() в описании не нуждается Disassemble() декодирует переданную инструкцию. первый параметр - указатель на массив unsigned char[15] с кодом второй - длина инструкции третий - true, если инструкция корректна четвертый - указатель на структуру, возвращенный AllocStruct() возвращаемые значения: -1 - внутренняя ошибка движка (неверный параметр, не хватает памяти, etc.) 0 - инструкция некорректна иначе, длина инструкции FormatMnemonic() генератором пока не используется. если есть желание, тестируйте...