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

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

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

Страницы: 1 2 3 412 Следующая »
#15
13:37, 16 июля 2021

Ida7. 5 годный инструмент, но есть выше описанные косяки. Хотя даже с ними при достаточном напряжении логики - очень мощная штука.


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

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

0xBADCODE
> Ida7. 5 годный инструмент, но есть выше описанные косяки.
Это не косяки, а "непригодность" инструмента для решения таких задач. :)

0xBADCODE
> Хотя даже с ними при достаточном напряжении логики - очень мощная штука.
Кто бы сомневался что IDA мощная штука за неимение конкурентов, но "раком" её поставить не так сложно при желании,  что и было продемонстрировано и первым сообщением в этом топике.

#17
18:42, 16 июля 2021

обычно пользуюсь x64dbg + ida, но не для восстановления исходников разумеется, на чем то сложном как =A=L=X= заметил это бесперспективная задача. Восстановите то что с оптимизировал компилятор, а всё что он выкинул посчитав лишним придется додумывать.

#18
19:49, 16 июля 2021

авто декомпиляция C это мертвяк, ida и ghidra немного упрощают процесс, но большую часть работы все равно прийдется делать своей титановой жопой раздупляя асм, остается надеяться на чудо глубокого обучения :D

#19
(Правка: 22:56) 21:40, 16 июля 2021

Gradius
> В идеале хочу получить рабочий си-код игры.
Вероятно, тогда, без отладчика не обойтись. :)

В ссылках к этой татье Модернизация IDA Pro. Debugger-плагин. Часть I. Теория
Автор указал в ссылках плагин  idados_dosbox

Продолжение проекта этого плагина

P.S, idaplugins-list

Кстати не упомянутых в топике продаваемых инструментов есть ещё: Binary Ninja, Relyze

#20
(Правка: 1:01) 0:29, 17 июля 2021

Прилагаю дизассемблированный вариант своего эмулятора и рекомпилированный в Си:  uboy_asm_c

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

Ваш листинг не про uboy.exe. Оффсеты 16-битные.  В EXE 2 части - одна 16-битная, она подхватывает DOS4GW, а вторая 32-битная - собственно сам код эмулятора + Сишный рантайм.  Её я не увидел.

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

Нужен SoundBlaster Pro, не ниже.  И чтобы переменная окружения "Blaster" была.  В DOSBox всё работает.

KPG
> В ссылках к этой татье Модернизация IDA Pro. Debugger-плагин. Часть I. Теория
> Автор указал в ссылках плагин idados_dosbox
>
> Продолжение проекта этого плагина

Он НЕ работает с DPMI 32-битными ДОС-программами! Только 16 битные.  Уже смотрел его.

Регистры и оффсеты 16 битные:

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

Вот как должно быть - отладчик Watcom  Debugger:

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

Сишный вариант у меня не заработал.  Инструкции РОМ-а игры фетчатся не в правильном порядке, по сравнению с оригиналом.

0xBADCODE
> Ida7. 5 годный инструмент, но есть выше описанные косяки. Хотя даже с ними при
> достаточном напряжении логики - очень мощная штука.

Для платного продукта косяков более, чем дохрена.

А самое главное - без доработки (очень существенной) напильником выхлопы не компилируются. 
TASM, MASM, FASM, NASM, WASM  просто бессильны.

Ида теряет много важной информации.

Вот примеры выхлопа с ИДы:

jnb     short loc_8000BD06

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

Или вот:

mov     [ebp+var_8], 0

что есть  [ebp+var_8] ?  Байт, слово, двойное слово?  Без указания директивы размера операнда (BYTE, WORD, DWORD PTR)  эта команда бессмысленна - информация потеряна.

В-третьих:

var_4C          = byte ptr -4Ch
var_2C          = byte ptr -2Ch
var_C           = dword ptr -0Ch
var_8           = dword ptr -8
var_4           = byte ptr -4

cmp     eax, [ebp+var_C]

такое представление коряво.  В [ebp+...]  должно стоять константное  смещение + указан размер операнда (писал выше).  Ассемблеры не собирают.

У меня сложилось стойкое впечатление, что в IDA специально так сделали, чтобы всеми фибрами усложнить получение исходного кода.

Написал скрипт, который справа указывает комментарии - размер операнда инструкции:

auto i;
auto insn;

for(i=MinEA();i<0x50000;i=NextHead(i,MaxEA()))
{
 if(((GetOpType(i,0)==2)||(GetOpType(i,0)==3)||(GetOpType(i,0)==4))&&(GetOpType(i,1)==0)) //mem,NULL
 {
  insn=DecodeInstruction(i);
       if(insn[0].dtyp==dt_byte )MakeComm(i,"BYTEPTR0");
  else if(insn[0].dtyp==dt_word )MakeComm(i,"WORDPTR0");
  else if(insn[0].dtyp==dt_dword)MakeComm(i,"DWORDPTR0");
 }
 else
 if(((GetOpType(i,0)==2)||(GetOpType(i,0)==3)||(GetOpType(i,0)==4))&&(GetOpType(i,1)==5)) //mem,im
 {
  insn=DecodeInstruction(i);
       if(insn[0].dtyp==dt_byte )MakeComm(i,"BYTEPTR0");
  else if(insn[0].dtyp==dt_word )MakeComm(i,"WORDPTR0");
  else if(insn[0].dtyp==dt_dword)MakeComm(i,"DWORDPTR0");
 }
 else
 if(((GetOpType(i,1)==2)||(GetOpType(i,1)==3)||(GetOpType(i,1)==4))&&(GetOpType(i,2)==5)) //?,mem,im
 {
  insn=DecodeInstruction(i);
       if(insn[1].dtyp==dt_byte )MakeComm(i,"BYTEPTR1");
  else if(insn[1].dtyp==dt_word )MakeComm(i,"WORDPTR1");
  else if(insn[1].dtyp==dt_dword)MakeComm(i,"DWORDPTR1");
 }
}

А там дальше - своим парсером на си - он вписывает BYTE, WORD, DWORD PTR куда надо.

И ещё один скрипт для превращения переменных в константы:

auto i;
auto insn;

for(i=MinEA();i<0x50000;i=NextHead(i,MaxEA()))
{
 if(GetOpType(i,0)==3)OpHex(i,-1);
 if(GetOpType(i,0)==4)OpHex(i,-1);
 if(GetOpType(i,1)==3)OpHex(i,-1);
 if(GetOpType(i,1)==4)OpHex(i,-1);
}

#21
(Правка: 1:00) 0:54, 17 июля 2021

Aroch
> обычно пользуюсь x64dbg + ida, но не для восстановления исходников разумеется,
> на чем то сложном как =A=L=X= заметил это бесперспективная задача. Восстановите
> то что с оптимизировал компилятор, а всё что он выкинул посчитав лишним
> придется додумывать.

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

Банально, повторное ассемблирование причёсанного ИДА-выхлопа рождает нерабочую программу.

Только как инструмент для патчинга и реверса отдельного кода (например, алгоритм разжатия ресурсов в игре).

baga
> авто декомпиляция C это мертвяк, ida и ghidra немного упрощают процесс, но
> большую часть работы все равно прийдется делать своей титановой жопой раздупляя
> асм, остается надеяться на чудо глубокого обучения :D

Как тогда получают код игры, который будучи скомпилированным на Си, даёт рабочую программу?

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

Вот есть такой проект - https://github.com/frranck/asm2c

This a swift tool to transform DOS/PMODEW 386 TASM assembly code to C code.
Made to port Mr.Boom

Но непонятно что он перенёс на Си - свои сорцы на асме или дизассемблированный листинг. Похоже, что первое.

#22
(Правка: 1:35) 1:28, 17 июля 2021

Gradius
> Банально, повторное ассемблирование причёсанного ИДА-выхлопа рождает нерабочую
> программу.
Если с ассемблерного листинга собирается байт в байт программа, то уже в первом приближении неплохо, а как с Си листинга получить хотя бы близкий вариант, то надо учитывать сколько где байт будет располагаться и не выходить за эти пределы разными способами, чтобы "ошибки" позиционирования  указателей позволили запустить рабочий код.
т.е. и как бы приходим к псевдоСи с определёнными вставками явно ограничивающих произвол оптимизаций Си компилятора, а оно того стоит? :)
В том же Source, по умолчанию, пара страниц настройки опций, но не понятно, а динамически он их сам экспертно не меняет. (ну например пробуя хотя бы вычисленные куски кода тестово просимулировать и получить даже грубо данные о их рабочести)


P.S. Юричев, Реверс инжиниринг для начинающих https://protey.net/attachments/re4b-ru-pdf.2077

Встретилось на Github https://github.com/yegord/snowman (какие то exe понимает и переводит в "С" )

#23
1:30, 17 июля 2021

Gradius
> Вот есть такой проект - https://github.com/frranck/asm2c

занятный выхлоп у тулзы: mrboom.c

профит видимо только от рекомпиляции, как-то поддерживать это месиво нереально

#24
3:02, 17 июля 2021

baga
> занятный выхлоп у тулзы: mrboom.c
> профит видимо только от рекомпиляции, как-то поддерживать это месиво нереально

Для моих целей достаточно получить компилируемый в Си/C++ код. Поддержка не нужна.
Проще говоря, Си-код должен обладать портируемостью.
Я даже не откажусь от "машинного" кода, главное, чтоб он был рабочим.

Я вот о чём подумал.
Есть сорцы ДОС-бокса, которые мне удалось собрать.

Можно ли как-то через ДОС-бокс навешать хуки на вызовы и отреверсить интересующую игру с помощью допиленного ДОС-бокса?

Или ещё одна мысль. Загрузить код игры в память и постепенно внедрять свой Си-/Asm-  код в бинарник игры с целью замены всех нужных функций- данных.

Тогда вопрос - как правильно связать свой код с кодом игры?  Особенно интересует вопрос обращения к данным.

Тут реверс надо делать с конца - отталкиваться от рабочей версии, постепенно заменяя её своими вызовами.

Реверс на базе декомпилированного листинга тут не поможет.

KPG
> Если с ассемблерного листинга собирается байт в байт программа

Выше я писал о проблемах сборки ассемблерного кода.  Не получается байт-в-байт...

#25
(Правка: 4:02) 3:16, 17 июля 2021

Gradius
> Выше я писал о проблемах сборки ассемблерного кода. Не получается
> байт-в-байт...
т.е. какие то ассемблерные команды транслируются в большее число байт чем в оригинале, выбранным ассемблером?  (и поэтому "слетают" короткие переходы).
А, например, команды "NOP" не остаются в листинге?

Gradius
> Можно ли как-то через ДОС-бокс навешать хуки на вызовы и отреверсить
> интересующую игру с помощью допиленного ДОС-бокса?
Думаю можно при работе программы под DosBox собрать в динамике информацию о графе вызова кода и использования переменных и структур + увязать эту информацию с отрисовываемой графикой.

Хуки можно тоже вешать на переход заменяемого кода и сравнивать с "трассами выполнения" оригинального кода.

В качестве симуляции игрового процесса  можно сделать какой то скрипт управляющий игрой в DosBox.

Gradius
> Есть сорцы ДОС-бокса, которые мне удалось собрать.
Сорцы Bochs хорошо собираются в Visual C 6, ещё есть точный эмулятор PCem

P.S. У меня есть вариант Qemu с интегрированным Форт SPF4 на нём тоже можно поэкспериментировать с "хуком" загруженного под ним кода. :) 

Отловив вход  регистров и состояние процессора локально исследуемого кода/подпрограммы - с установленными хуками в начале и "конце" кода (может уточнятся область сколько кода)
и после этого выполнить с входными регистрами оригинальный код и заменяемый и сравнить результаты выполнения, но тут ещё нужно учесть и затрагиваемую память при выполнении оригинального кода с таким же ли результатом заменяемого (т.е. как то отслеживать начально затрагиваемые ячейки и восстанавливать их перед тестом заменяемым кодом)

Далее если позволяет место, то патчить прямо в память или с переходом в свободное место. (и/или корректировать смещения и сохранять выгружаемый из памяти файл уже с "расширенными" смещениями)

Какую то отладочную метаинформацию тоже можно загружать при таком "дебагинге". :)

Gradius
> Реверс на базе декомпилированного листинга тут не поможет.
Этот реверс, как первичную информацию тоже можно задействовать как "гипотезу".

#26
(Правка: 13:20) 13:05, 17 июля 2021

Gradius
> Или ещё одна мысль. Загрузить код игры в память и постепенно внедрять свой
> Си-/Asm-  код в бинарник игры с целью замены всех нужных функций- данных.
>
> Тогда вопрос - как правильно связать свой код с кодом игры?  Особенно
> интересует вопрос обращения к данным.
В Windows это достаточно просто сделать внедрением DLL с подменными функциями в адресное пространство процесса игры и либо правкой таблицы импорта, либо заменой непосредственно в теле заменяемой ф-ии нескольких первых инструкций на прыжок по адресу новой ф-ии. В ДОС х.з. как такое можно реализовать, только правкой MZ наверное.

#27
(Правка: 14:38) 14:36, 17 июля 2021

Gradius
> Или ещё одна мысль. Загрузить код игры в память и постепенно внедрять свой
> Си-/Asm-  код в бинарник игры с целью замены всех нужных функций- данных
Я так делал.

#28
(Правка: 15:24) 15:20, 17 июля 2021

totoro
> В Windows это достаточно просто сделать внедрением DLL с подменными функциями в
> адресное пространство процесса игры и либо правкой таблицы импорта, либо
> заменой непосредственно в теле заменяемой ф-ии нескольких первых инструкций на
> прыжок по адресу новой ф-ии. В ДОС х.з. как такое можно реализовать, только
> правкой MZ наверное.

Удалось инжектировать код прямо в игру. Всё просто. Код вызова(им мы затираем вызов интересующей функции с целью подменить на свой вариант):

push DWORD PTR 0x00400000  ;адрес куда пойдёт вызов
retn                ;переход

Команды выше реализуют прямой переход на адрес 0x00400000, по которому ранее загружен мой код.

Пример программы:

USE32

org    0x00400000

mov     esi,String
mov     edi,0xB8000
mov     ah,0xF

@loop:

mov     al,[esi]
cmp     al,0
jz      @end

mov     [edi],ax
inc     esi
add     edi,2
jmp     @loop

@end:
jmp     @end

String  db 'Hello!',0

Пока без возврата просто зацикливается.  Работает.

Сейчас ковыряю Open Watcom C на предмет получения голого бинарника. А то писать на одном ассемблере как-то грустно...
Но не всё так просто. Пока неясно как задать точку входа в main в скрипте линкера.

Про бинарники от ваткома: https://wiki.osdev.org/Watcom

И ещё хотелось бы код инжектирования сжать до 5 байт, а сейчас 6.
Иначе придётся косвенные вызовы городить - а это вынос мозга со смещениями...

Ещё вычислил базовые адреса сегментов - пришлось поинжектировать в коде игры немного и выводить адреса в ASCii-символах.

Получается так:
сегмент кода: 0x172000
сегмент данных: 0x194000
второй сегмент данных: 0x12E000
третий сегмент данных - не заиничен и всего 4 байта.

Залимитил память эмулятору ДОС-бокса до 4 МБ.
Снял дамп 4-х мегабайт после загрузки игры:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>


void main(void)
{
 FILE *f=fopen("dump.bin","wb");
 fwrite((void*)0,1,0x400000,f);
 fclose(f);
}

Много интересного увидел:  ресурсы игры и видео-буфер :)


0xBADCODE
> Я так делал.

Какими инструкциями инжектировали?  Через прерывания или прямые переходы?

#29
(Правка: 19:01) 18:49, 17 июля 2021

Gradius
> Какими инструкциями инжектировали?
Тут не в инструкциях дело, а в комплексом подходе.
Это мне сложно описать со смартфона, там и редактирование dll, и загрузка в секцию данных загруженной игры своего объектного файла с перенастройкой адресов.

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