Решил поиграться с дизассемблером IDA Pro 7.5 (китайская версия) и проверить на "прочность" его декомпилятор Hex-Rays.
В качестве подопытной программы для дизассемблирования - выступил мой порт эмулятора GameBoy под DOS.
Обозначу сразу поле исследования: рекомпиляция (воссоздание исходного кода на C/C++ с целью портирования игр на Win32 и свои платформы) старых DOS-игр, работающих в защищённом(32-битном) режиме с помощью досэкстендера (типа DOS4GW) и написанные на Watcom C 9+.
Сбилдил свой эмуль в Watcom C 10.0 , сгенерил отладочную информацию в формате DWARF и ИДой вытащил её с помощью плагина на Python. Имена функций и переменных стали смотреться по-человечески:
Что не понравилось при работе с IDA:
1) Если адреса сегментов ставить по умолчанию, то захардкоженные адреса памяти (например - окно видеопамяти в графическом режиме 0xA0000 или в текстовом 0xB8000) превращаются в оффсеты на слова в сегментах.
Очень дико раздражает.
Вот такой безобидный код:
memcpy(( void*)0xA0000,VideoBuffer,320*200);
На котором вместо константы 0xA0000 загружается некий offset_A0000.
2) Раздупление сегмента данных на одиночные байты.
Приходится самому сворачивать в массивы и строки, нажимая "*" и "d"
Иначе генерируемые ASM и C становятся на сотни тысяч строк!
Теперь недостатки собственно Hex-Rays, ради которого был затеян эксперимент:
1) Неверно определяет число аргументов у функций.
Пример. Вот есть такая функция - с оригинального исходника:
void RGB(u8 C,u8 R,u8 G,u8 B) { _asm { mov ax,0x1010 xor bh,bh mov bl,C mov dh,R mov ch,G mov cl,B int 0x10 } }
Декомпилер сделал так:
__int16 RGB() { __int16 result; // ax result = 4112; __asm { int 10h /*; - VIDEO - SET INDIVIDUAL DAC REGISTER (EGA, VGA/MCGA)*/ } return result; }
То что тело асма скрылось, хрен с ним. Но пугает полное отсутствие аргументов у функции!
Результат - декомпилированный вариант функции без правок - НЕ работает!
2) Неверно делает знаковое сравнение, некорректный типкаст.
Исходник функции:
u32 initcart(void) { u32 i=0; u32 k; u16 cs=0,ccs=0; for( i=0;i<( ROM_VOLUME/GB_ROMBANKSIZE);i++) //Maximum 4 MB !!! { bank[i]=ROM+( i*GB_ROMBANKSIZE); if ( i==0) { ccs=( ( ( u16)bank[0][0x14E]<< 8)| bank[0][0x14F]); cs=0; cs-=bank[0][0x14E]; cs-=bank[0][0x14F]; } for ( k=0;k<GB_ROMBANKSIZE;k++) cs+=bank[i][k]; } romselectmask=i; if ( ccs!=cs) return 1; ..................
На последней проверке - return 1 - означает ошибку. В оригинальной версии программы здесь ошибки быть не должно при заданных условиях.
Вот вариант Hex-Rays:
Очевидно, когда один тип знаковый, другой - нет -программа работать правильно не будет, что и подтвердилось!
3) Hex-Rays не осиливает обработчики прерывания DOS32. Ломается анализ глубины стека и декомпиляция запрещается или не работает как надо:
вот такой безобидный обработчик прерывания клавиатуры:
void __interrupt __far Key_IRQ(void) { u8 k; k=inp( 0x60); outp( 0x61,inp( 0x61)|0x80); outp( 0x61,inp( 0x61)&0x7F); switch( k) { case 1: //'Esc' LowLevel_END=1; break; case 72: Joystick&=( ~JOYSTICK_U); break; case 80: Joystick&=( ~JOYSTICK_D); break; ........... case 178: Joystick|=JOYSTICK_M; break; } if( Joystick_Function) CALL( Joystick_Function) outp( 0x20,0x20); }
декомпилируется в вот такой ужас:
В этом случае приходится кусок ассемблерного кода внедрять прямо в программу, иначе никак!
4) Излюбленное занятие Hex-Rays - адресовать участки памяти за пределами переменной.
Предположим у нас в памяти есть строка из 40 символов, а дальше идут другие переменные.
Так вот, когда в программе идёт работа с другими переменными, он использует указатель(имя) старой переменной и адресует память относительно неё!
Получается бредо-код, который работает, при условии, если сегмент данных вырвать полностью куском и настроить указатели на него и слинковать с рекомпиленной версией.
При попытке отделить переменные и распределить их по-другому - будет 100% нерабочий код!
5) Ну и напоследок, что все-же удалось победить:
причёсывание декомпилированного си-подобного кода.
Вооружился Notepad++ и регулярными выражениями. Из ассемблерного листинга можно родить хедеры для ASM и C++, а сегмент данных целиком слинковать со своей программой (чтобы порядок и размер переменных не нарушался).
Может быть я что-то не так делаю?
Почему так через одно место всё?
Нопомню, персональная лицензия IDA стоит $500, и на конкретно одну архитектуру.
После разбирательств в китайской версии ИДы, желание её покупать как-то пропало.
Что можете посоветовать для декомпиляции старых ДОС-игр?
P.S. А рекомпилировать свой эмулятор, чтобы он нормально работал, у меня пока не вышло...
Gradius
> сгенерил отладочную информацию в формате DWARF и ИДой вытащил её с помощью плагина на Python
Не честно. Много-ли реальных DOS-игр имеют в своём составе отладочную информацию?
> Но пугает полное отсутствие аргументов у функции!
В Си возможно переменное количество аргументов у функций. Сколько реально аргументов передано, знает только вызывающая сторона. Она же и очущает стек от аргументов после вызова.
> лицензия IDA стоит $500,
Зачем, если есть бесплатная (китайская) версия?
Для таких тем лучше (гораздо) на https://wasm.in/ идти. Там всё профильно и раздел про дизассемблирование есть: https://wasm.in/forums/wasm-research.12/
Gradius
> Пример. Вот есть такая функция - с оригинального исходника:
>
> void RGB(u8 C,u8 R,u8 G,u8 B)
> {
> _asm
> {
> mov ax,0x1010
> xor bh,bh
> mov bl,C
> mov dh,R
> mov ch,G
> mov cl,B
> int 0x10
> }
> }
>
> Декомпилер сделал так:
>
> __int16 RGB()
> {
> __int16 result; // ax
>
> result = 4112;
> __asm { int 10h /*; - VIDEO - SET INDIVIDUAL DAC REGISTER (EGA,
> VGA/MCGA)*/ }
> return result;
> }
>
> То что тело асма скрылось, хрен с ним. Но пугает полное отсутствие аргументов у
> функции!
>
> Результат - декомпилированный вариант функции без правок - НЕ работает!
Тут есть вероятность, что Wacom соптимизировал и передаёт аргументы в функцию так что тело асма как раз вычистилось и аргументы сразу передаются в соответствующих регистрах - поэтому так и получилось. Желательно посмотреть просто дизасм этой функции. Возможно она так и выглядит. Работать, правда, всё-равно не будет.
Вообще превратить обратно в код на СИ код после тяжело оптимизирующего компилятора - это по моему задача на нобелевку. После всяких хвостовых и регистровых оптимизаций хрен там поймёшь где одна функция начинается, а где кончается и где лежат аргументы.
Мир не совершенен. :)
Работающий под DOS есть Sourcer 8.0, там же Exe2C (существует)
- могу проверить на них их выхлоп тестового кода проекта.
под Windows был одно время популярен Win32Dasm.
P.S. Это ещё что :), один энтузиаст сделал проект реверса игры StarFlight, а в ней вообще кодовая база на Forth написана, но автор вполне успешно сделал транспилер с Форт на С в проекте и удачно скомпилировал и запустил данную игру под Windows (SDL), но проект ещё не завершён. (проверил у себя авторские достижения)
Сам тоже пробовал силы в самопальном дизассемблировании Форт системы VFX Forth с использованием самопального скрипт инструмента сделанного на SPF4 (тоже Форт)
сейчас VFX Forth опубликована в открытых исходниках в комьюнити сообществе.
- по ходу понимания устройства дизассемблированного кода правил Форт скрипт по его правильному дизассемблированию. :)
Panzerschrek[CN]
> > сгенерил отладочную информацию в формате DWARF и ИДой вытащил её с помощью
> > плагина на Python
> Не честно. Много-ли реальных DOS-игр имеют в своём составе отладочную
> информацию?
Много. Та игра, которая интересна, содержит в конце отладочную инфу, которую не удалось идентифицировать. ИДА её не видит. А Watcom 10, который у меня - все три формата отладочной инфы(Watcom, Codeview, DWARF) не совпадают с форматом инфы игры.
Прикрепляю файлик с дебаг-инфой. Кто распознает - чей это формат?
Скачать: main
Пока что мне удалось из этой инфы вытащить имена (только имена!) функций и переменным.
Использовал ваткомовский wdump и написал свой парсер на C, который корректирует адреса переменным и функциям и вытаскивает названия и в конечном итоге - делает простой скрипт для ИДЫ (по Shift+F2 который).
=A=L=X=
> Для таких тем лучше (гораздо) на https://wasm.in/ идти. Там всё профильно и
> раздел про дизассемблирование есть: https://wasm.in/forums/wasm-research.12/
Позже туда напишу.
Правда, активность там оставляет желать лучшего...
=A=L=X=
> Вообще превратить обратно в код на СИ код после тяжело оптимизирующего
> компилятора - это по моему задача на нобелевку.
:) Пока только учебные занятия - создание своих парсеров, освоение программ (отладчик, эмулятор, дизассемблер, рекомпилер) и на своей программе, исходный код который у меня есть.
Но обидно, что потратив много времени на адаптацию Hex-Rays'ного высера, до состояния компилируемого - так и не удалось получить рабочий код восстановленной версии.
Причем там ошибка на ошибке сидит... Хотя программа несложная - эмулятор Геймбоя...
KPG
> Работающий под DOS есть Sourcer 8.0, там же Exe2C (существует)
> - могу проверить на них их выхлоп тестового кода проекта.
> под Windows был одно время популярен Win32Dasm.
Загрузил - uBoy
Там эмулятор геймбоя под ДОС, игра и дос-экстендер.
Игра запускается сразу.
uboy.exe - эмулятор
uboy.sym - символьная отладочная информация
btdd.gb - ROM игры
dos4gw.exe - дос-эктендер. Его смотреть не нужно.
Интересно, насколько хуже справляется с декомпиляцией Ghidra ? Как-то хотел поставить поиграться, но чёт как-то ссыкотно ставить себе софт от ЦРУ
Gradius
> Причем там ошибка на ошибке сидит... Хотя программа несложная - эмулятор
> Геймбоя...
Да, но IDA PRO об этом не догадывается. :)
P.S. А, выхлоп 7.5 для DOS программ сильно отличается , например, от версии 6.7?
Вроде последние версии IDA для запуска только под Win64.
0iStalker
> Интересно, насколько хуже справляется с декомпиляцией Ghidra ? Как-то хотел
> поставить поиграться, но чёт как-то ссыкотно ставить себе софт от ЦРУ
На Хабр есть статьи по ней. (ей вроде "NES' ромы дизассемблировали)
а на Github есть какой то проект вроде связки Ghidra c Radare2 (или IDA)
0iStalker
> Интересно, насколько хуже справляется с декомпиляцией Ghidra ? Как-то хотел
> поставить поиграться, но чёт как-то ссыкотно ставить себе софт от ЦРУ
Я поставил. У меня отдельный комп для этого как раз есть. В песочницу не захотел, потому что скорость проседает из-за виртуализации.
Ghidra вообще не распознаёт LE-executable формат (это когда у файла 2 заголовка -один MZ, другой LE родом из Phar Lap, OS/2.). Даёт тупо бинарник.
KPG
> P.S. А, выхлоп 7.5 для DOS программ сильно отличается , например, от версии
> 6.7?
Отличается. Я работал с IDA Free 5.0, IDA 6.6(китайская) и 7.5(китайская).
По сравнению с 7.5 предыдущие версии вообще тупые.
Сравнивал в контексте DOS DPMI программ. Уверен, что Win32 они хорошо жуют.
KPG
> а на Github есть какой то проект вроде связки Ghidra c Radare2 (или IDA)
С радаром не смог пока разобраться.
На сегодня самый лучший выхлоп - у IDA 7.5 для DOS32-программы (LE).
KPG
> P.S. Это ещё что :), один энтузиаст сделал проект реверса игры StarFlight, а в
> ней вообще кодовая база на Forth написана, но автор вполне успешно сделал
> транспилер с Форт на С в проекте и удачно скомпилировал и запустил данную игру
> под Windows (SDL), но проект ещё не завершён. (проверил у себя авторские
> достижения)
В идеале хочу получить рабочий си-код игры.
Вот ранее упомянутый "Раптор" сделали же ! И код декомпилера отличается от ИДА-шного.
Gradius
> Загрузил - uBoy
Начальный прогон ехе файла в Sourcer 8.0 и e2a программе (после неё должен по идее ещё был создаться файл glb с символьной информацией для e2c)
http://sendfile.su/1613122
P.S. Sourcer достаточно мощная программа при грамотном использовании.
(она предложила на выбор какой формат заголовка файла реверсить - выбрал DOS)
Gradius
> Вот ранее упомянутый "Раптор" сделали же ! И код декомпилера отличается от
> ИДА-шного.
Проектов перевода из Exe в C есть не только в исполнении IDA :)
на тех же площадках sourceforge, github ... есть какие то и открытые проекты.
KPG
> Начальный прогон ехе файла в Sourcer 8.0 и e2a программе (после неё должен по
> идее ещё был создаться файл glb с символьной информацией для e2c)
> http://sendfile.su/1613122
>
> P.S. Sourcer достаточно мощная программа при грамотном использовании.
Это не uboy.exe. И в листинге дизасма 16-битные смещения.
Gradius
> Это не uboy.exe. И в листинге дизасма 16-битные смещения.
? В файле же виден и Watcom и название uboy декомпилированного файла.
Не знаю, но возможно, 16-ти битные смещения в Sourcer можно указать как представлять 32-х.
P.S. Кстати, в виду отсутвия в запущенном DOS SB он не стартовал. :)
Тема в архиве.