Войти
ФлеймФорумПрограммирование

Дизассемблер IDA Pro 7.5 для восстановления исходного кода игры (C/C++)

Advanced: Тема повышенной сложности или важная.

Страницы: 1 2 311 12 Следующая »
#0
(Правка: 11:16) 11:13, 16 июля 2021

Решил поиграться с дизассемблером IDA Pro 7.5 (китайская версия) и проверить на "прочность" его декомпилятор Hex-Rays.

В качестве подопытной программы для дизассемблирования - выступил мой порт эмулятора GameBoy под DOS.

Обозначу сразу поле исследования: рекомпиляция (воссоздание исходного кода на C/C++ с целью портирования игр на Win32 и свои платформы) старых DOS-игр, работающих в защищённом(32-битном) режиме с помощью досэкстендера (типа DOS4GW) и написанные на Watcom C 9+.

Сбилдил свой эмуль в Watcom C 10.0 , сгенерил отладочную  информацию в формате DWARF и ИДой вытащил её с помощью плагина на Python.  Имена функций и переменных стали смотреться по-человечески:

s | Дизассемблер IDA Pro 7.5 для восстановления исходного кода игры (C/C++)

Что не понравилось при работе с 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:

s | Дизассемблер IDA Pro 7.5 для восстановления исходного кода игры (C/C++)

Очевидно, когда один тип знаковый, другой - нет  -программа работать правильно не будет, что и подтвердилось!

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);
}

декомпилируется в вот такой ужас:

s | Дизассемблер IDA Pro 7.5 для восстановления исходного кода игры (C/C++)

В этом случае приходится  кусок ассемблерного кода внедрять прямо в программу, иначе никак!

4) Излюбленное занятие Hex-Rays  - адресовать участки памяти за пределами переменной.

Предположим у нас в памяти есть строка из 40 символов, а дальше идут другие переменные.

Так вот, когда в программе идёт работа с другими переменными, он использует  указатель(имя) старой переменной и адресует память относительно неё!

Получается бредо-код, который работает, при условии, если сегмент данных вырвать полностью куском и настроить указатели на него и слинковать с рекомпиленной версией.

При попытке отделить переменные и распределить их по-другому - будет 100% нерабочий код!

5) Ну и напоследок, что все-же удалось победить:

причёсывание декомпилированного си-подобного кода.

Вооружился Notepad++ и регулярными выражениями.  Из ассемблерного листинга можно родить хедеры для ASM и C++,  а сегмент данных целиком слинковать со своей программой (чтобы порядок и размер переменных не нарушался).

Может быть я что-то не так делаю?

Почему так через одно место всё?

Нопомню, персональная лицензия IDA стоит $500, и на конкретно одну архитектуру.
После разбирательств в китайской версии ИДы, желание её покупать как-то пропало.

Что можете посоветовать для декомпиляции старых ДОС-игр?

P.S. А рекомпилировать свой эмулятор, чтобы он нормально работал, у меня пока не вышло...


#1
11:24, 16 июля 2021

Gradius
> сгенерил отладочную информацию в формате DWARF и ИДой вытащил её с помощью плагина на Python
Не честно. Много-ли реальных DOS-игр имеют в своём составе отладочную информацию?

> Но пугает полное отсутствие аргументов у функции!
В Си возможно переменное количество аргументов у функций. Сколько реально аргументов передано, знает только вызывающая сторона. Она же и очущает стек от аргументов после вызова.

> лицензия IDA стоит $500,
Зачем, если есть бесплатная (китайская) версия?

#2
11:25, 16 июля 2021

Для таких тем лучше (гораздо) на https://wasm.in/ идти. Там всё профильно и раздел про дизассемблирование есть: https://wasm.in/forums/wasm-research.12/

#3
(Правка: 11:32) 11:31, 16 июля 2021

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 соптимизировал и передаёт аргументы в функцию так что тело асма как раз вычистилось и аргументы сразу передаются в соответствующих регистрах - поэтому так и получилось. Желательно посмотреть просто дизасм этой функции. Возможно она так и выглядит. Работать, правда, всё-равно не будет.

#4
11:35, 16 июля 2021

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

#5
(Правка: 12:01) 11:52, 16 июля 2021

Мир не совершенен. :)
Работающий под DOS есть Sourcer 8.0, там же Exe2C (существует)
- могу проверить на них их выхлоп тестового кода проекта.
под Windows был одно время популярен Win32Dasm.


P.S. Это ещё что :), один энтузиаст сделал проект реверса  игры StarFlight, а в ней вообще кодовая база на Forth написана, но автор вполне успешно сделал транспилер с Форт на С в проекте и удачно скомпилировал и запустил данную игру под Windows (SDL), но проект ещё не завершён. (проверил у себя авторские достижения) 

Сам тоже пробовал силы в самопальном дизассемблировании Форт системы VFX Forth с использованием самопального скрипт  инструмента сделанного на SPF4 (тоже Форт)
сейчас VFX Forth опубликована в открытых исходниках в комьюнити сообществе.
- по ходу понимания устройства дизассемблированного кода правил Форт скрипт по его правильному дизассемблированию. :)

#6
(Правка: 11:57) 11:57, 16 июля 2021

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'ного высера, до состояния компилируемого - так и не удалось получить рабочий код восстановленной версии.

Причем там ошибка на ошибке сидит...  Хотя программа несложная - эмулятор Геймбоя...

#7
12:02, 16 июля 2021

KPG
> Работающий под DOS есть Sourcer 8.0, там же Exe2C (существует)
> - могу проверить на них их выхлоп тестового кода проекта.
> под Windows был одно время популярен Win32Dasm.

Загрузил - uBoy
Там эмулятор геймбоя под ДОС, игра и дос-экстендер.
Игра запускается сразу.

uboy.exe - эмулятор
uboy.sym - символьная отладочная информация
btdd.gb  - ROM игры
dos4gw.exe - дос-эктендер.  Его смотреть не нужно.

#8
12:04, 16 июля 2021

Интересно, насколько хуже справляется  с декомпиляцией  Ghidra ?  Как-то хотел поставить поиграться, но чёт как-то ссыкотно ставить себе софт от ЦРУ

#9
12:09, 16 июля 2021

Gradius
> Причем там ошибка на ошибке сидит... Хотя программа несложная - эмулятор
> Геймбоя...
Да, но IDA PRO об этом не догадывается. :)

P.S. А, выхлоп 7.5 для  DOS программ  сильно отличается , например, от версии 6.7?
Вроде последние версии IDA для запуска только под Win64.

#10
(Правка: 12:17) 12:15, 16 июля 2021

0iStalker
> Интересно, насколько хуже справляется с декомпиляцией Ghidra ? Как-то хотел
> поставить поиграться, но чёт как-то ссыкотно ставить себе софт от ЦРУ
На Хабр есть статьи по ней. (ей  вроде "NES' ромы дизассемблировали)
а на Github есть какой то проект вроде связки Ghidra c Radare2 (или IDA)

#11
(Правка: 12:24) 12:24, 16 июля 2021

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), но проект ещё не завершён. (проверил у себя авторские
> достижения)

В идеале хочу получить рабочий си-код игры.

Вот ранее упомянутый "Раптор" сделали же !  И код декомпилера отличается от ИДА-шного.

#12
(Правка: 13:06) 12:48, 16 июля 2021

Gradius
> Загрузил - uBoy
Начальный прогон ехе файла в Sourcer 8.0 и e2a программе (после неё должен по идее ещё был создаться файл glb с символьной информацией для e2c)
http://sendfile.su/1613122

P.S. Sourcer достаточно мощная программа при грамотном использовании.
(она предложила на выбор какой формат заголовка файла реверсить - выбрал DOS)

Gradius
> Вот ранее упомянутый "Раптор" сделали же ! И код декомпилера отличается от
> ИДА-шного.
Проектов перевода из Exe в  C есть не только в исполнении IDA :)
на тех же площадках sourceforge, github ... есть какие то и  открытые проекты.


#13
13:03, 16 июля 2021

KPG
> Начальный прогон ехе файла в Sourcer 8.0 и e2a программе (после неё должен по
> идее ещё был создаться файл glb с символьной информацией для e2c)
> http://sendfile.su/1613122
>
> P.S. Sourcer достаточно мощная программа при грамотном использовании.

Это не uboy.exe.  И в листинге дизасма 16-битные смещения.

#14
(Правка: 13:26) 13:22, 16 июля 2021

Gradius
> Это не uboy.exe. И в листинге дизасма 16-битные смещения.
? В файле же виден и Watcom и название uboy декомпилированного файла.
Не знаю, но возможно, 16-ти битные смещения в Sourcer можно указать как представлять 32-х.

P.S. Кстати, в виду отсутвия в запущенном DOS  SB он не стартовал. :)

Страницы: 1 2 311 12 Следующая »
ФлеймФорумПрограммирование