IDA Pro: работа с библиотечным кодом (не WinAPI)

Всем привет,

При работе в IDA мне, да и, наверняка, вам тоже, часто приходится иметь дело с приложениями, которые имеют достаточно большой объём кода, не имеют символьной информации и, к тому же, содержат много библиотечного кода. Зачастую такой код нужно уметь отличать от написанного пользователем. И, если на вход библиотечного кода подаются только int, void * да const char *, можно отделаться одними лишь сигнатурами (созданные с помощью FLAIR-утилит sig-файлы). Но, если нужны структуры, аргументы, их количество, тут без дополнительной магии не обойдёшься… В качестве примера я буду работать с игрой для Sony Playstation 1, написанной с использованием PSYQ v4.7.

Дополнительная магия

Представим ситуацию: вам попалась прошивка от какой-нибудь железки. Обычный Bare-metal ROM (можно даже с RTOS). Или же ROM игры. В подобных случаях, скорее всего, при компиляции использовался какой-то SDK/DDK, у которого имеется набор LIB/H/OBJ файлов, которые вклеиваются линкером в итоговый файл.

Наш план действий будет примерно таким:

  1. Взять все lib/obj-файлы, и создать из них сигнатуры (или набор сигнатур). Это поможет нам отделить статически влинкованный библиотечный код.
  2. Взять все h-файлы и создать из них библиотеку типов. Эта библиотека хранит не только типы данных, но и информацию об именах и типах аргументов функций, в которых объявленные типы используются.
  3. Применить сигнатуры, чтобы у нас определились библиотечные функции и их имена.
  4. Применить библиотеки типов, чтобы применить прототипы функций и используемые типы данных.

Создаём sig-файлы

Для создания файла сигнатур необходимо воспользоваться набором FLAIR-утилит, доступных лицензионным пользователям IDA. Список необходимых утилит следующий:

  • pcf — LIB/OBJ-parser, создаёт PAT-файл из COFF-объектных файлов
  • pelf — LIB/OBJ-парсер, создаёт PAT-файл из ELF-файлов (Unix)
  • plb — LIB/OBJ-parser, создаёт PAT-файл из OMF-объектных файлов
  • pmacho — MACH-O-парсер, создаёт PAT-файл из MACH-O-файлов (MacOS)
  • ppsx — OBJ-парсер, создаёт PAT-файл из библиотечных файлов PSYQ
  • ptmobj — OBJ-парсер, создаёт PAT-файл из библиотечных файлов Trimedia
  • sigmake — конвертирует ранее созданный PAT-файл в SIG-файл, перевариваемый IDA

В моём случае это ppsx. Собираю bat-файл, в котором перечисляю все lib- и obj-файлы, и добавляю к каждой строке вызов ppsx, чтобы получилось формирование итогового PAT-файла. Получилось следующее содержимое:

run_47.bat

@echo off  ppsx -a 2MBYTE.OBJ psyq47.pat ppsx -a 8MBYTE.OBJ psyq47.pat ppsx -a LIBAPI.LIB psyq47.pat ppsx -a LIBC.LIB psyq47.pat ppsx -a LIBC2.LIB psyq47.pat ppsx -a LIBCARD.LIB psyq47.pat ppsx -a LIBCD.LIB psyq47.pat ppsx -a LIBCOMB.LIB psyq47.pat ppsx -a LIBDS.LIB psyq47.pat ppsx -a LIBETC.LIB psyq47.pat ppsx -a LIBGPU.LIB psyq47.pat ppsx -a LIBGS.LIB psyq47.pat ppsx -a LIBGTE.LIB psyq47.pat ppsx -a LIBGUN.LIB psyq47.pat ppsx -a LIBHMD.LIB psyq47.pat ppsx -a LIBMATH.LIB psyq47.pat ppsx -a LIBMCRD.LIB psyq47.pat ppsx -a LIBMCX.LIB psyq47.pat ppsx -a LIBPAD.LIB psyq47.pat ppsx -a LIBPRESS.LIB psyq47.pat ppsx -a LIBSIO.LIB psyq47.pat ppsx -a ashldi3.obj psyq47.pat ppsx -a ashrdi3.obj psyq47.pat ppsx -a CACHE.OBJ psyq47.pat ppsx -a clear_cache.obj psyq47.pat ppsx -a CLOSE.OBJ psyq47.pat ppsx -a cmpdi2.obj psyq47.pat ppsx -a CREAT.OBJ psyq47.pat ppsx -a ctors.obj psyq47.pat ppsx -a divdi3.obj psyq47.pat ppsx -a dummy.obj psyq47.pat ppsx -a eh.obj psyq47.pat ppsx -a eh_compat.obj psyq47.pat ppsx -a exit.obj psyq47.pat ppsx -a ffsdi2.obj psyq47.pat ppsx -a fixdfdi.obj psyq47.pat ppsx -a fixsfdi.obj psyq47.pat ppsx -a fixtfdi.obj psyq47.pat ppsx -a fixunsdfdi.obj psyq47.pat ppsx -a fixunsdfsi.obj psyq47.pat ppsx -a fixunssfdi.obj psyq47.pat ppsx -a fixunssfsi.obj psyq47.pat ppsx -a fixunstfdi.obj psyq47.pat ppsx -a fixunsxfdi.obj psyq47.pat ppsx -a fixunsxfsi.obj psyq47.pat ppsx -a fixxfdi.obj psyq47.pat ppsx -a floatdidf.obj psyq47.pat ppsx -a floatdisf.obj psyq47.pat ppsx -a floatditf.obj psyq47.pat ppsx -a floatdixf.obj psyq47.pat ppsx -a FSINIT.OBJ psyq47.pat ppsx -a gcc_bcmp.obj psyq47.pat ppsx -a LSEEK.OBJ psyq47.pat ppsx -a lshrdi3.obj psyq47.pat ppsx -a moddi3.obj psyq47.pat ppsx -a muldi3.obj psyq47.pat ppsx -a negdi2.obj psyq47.pat ppsx -a new_handler.obj psyq47.pat ppsx -a op_delete.obj psyq47.pat ppsx -a op_new.obj psyq47.pat ppsx -a op_vdel.obj psyq47.pat ppsx -a op_vnew.obj psyq47.pat ppsx -a OPEN.OBJ psyq47.pat ppsx -a PROFILE.OBJ psyq47.pat ppsx -a pure.obj psyq47.pat ppsx -a read.obj psyq47.pat ppsx -a shtab.obj psyq47.pat ppsx -a snctors.obj psyq47.pat ppsx -a SNDEF.OBJ psyq47.pat ppsx -a SNMAIN.OBJ psyq47.pat ppsx -a SNREAD.OBJ psyq47.pat ppsx -a SNWRITE.OBJ psyq47.pat ppsx -a trampoline.obj psyq47.pat ppsx -a ucmpdi2.obj psyq47.pat ppsx -a udiv_w_sdiv.obj psyq47.pat ppsx -a udivdi3.obj psyq47.pat ppsx -a udivmoddi4.obj psyq47.pat ppsx -a umoddi3.obj psyq47.pat ppsx -a varargs.obj psyq47.pat ppsx -a write.obj psyq47.pat ppsx -a LIBSND.LIB psyq47.pat ppsx -a LIBSPU.LIB psyq47.pat ppsx -a LIBTAP.LIB psyq47.pat ppsx -a LOW.OBJ psyq47.pat ppsx -a MCGUI.OBJ psyq47.pat ppsx -a MCGUI_E.OBJ psyq47.pat ppsx -a NOHEAP.OBJ psyq47.pat ppsx -a NONE3.OBJ psyq47.pat ppsx -a NOPRINT.OBJ psyq47.pat ppsx -a POWERON.OBJ psyq47.pat

LIBSN.LIB файл имеет формат, отличный от остальных библиотек, поэтому пришлось разложить его на OBJ-файлы утилитой PSYLIB2.EXE, которая входит в комплект PSYQ. Запускаем run_47.bat. Получаем следующий выхлоп:

run_47.bat output

2MBYTE.OBJ: skipped 0, total 1 8MBYTE.OBJ: skipped 0, total 1 LIBAPI.LIB: skipped 0, total 89 LIBC.LIB: skipped 0, total 55 LIBC2.LIB: skipped 0, total 50 LIBCARD.LIB: skipped 0, total 18 LIBCD.LIB: skipped 0, total 51 LIBCOMB.LIB: skipped 0, total 3 LIBDS.LIB: skipped 0, total 36 LIBETC.LIB: skipped 0, total 8 LIBGPU.LIB: skipped 0, total 60 LIBGS.LIB: skipped 0, total 167 LIBGTE.LIB: skipped 0, total 535 LIBGUN.LIB: skipped 0, total 2 LIBHMD.LIB: skipped 0, total 585 LIBMATH.LIB: skipped 0, total 59 LIBMCRD.LIB: skipped 0, total 7 LIBMCX.LIB: skipped 0, total 31 LIBPAD.LIB: skipped 0, total 21 LIBPRESS.LIB: skipped 0, total 7 LIBSIO.LIB: skipped 0, total 4 ashldi3.obj: skipped 0, total 1 ashrdi3.obj: skipped 0, total 1 CACHE.OBJ: skipped 0, total 1 clear_cache.obj: skipped 0, total 1 CLOSE.OBJ: skipped 0, total 1 cmpdi2.obj: skipped 0, total 1 CREAT.OBJ: skipped 0, total 1 ctors.obj: skipped 0, total 0 divdi3.obj: skipped 0, total 1 dummy.obj: skipped 0, total 1 Fatal: Illegal relocation information at file pos 0000022D eh_compat.obj: skipped 0, total 1 exit.obj: skipped 0, total 1 ffsdi2.obj: skipped 0, total 1 fixdfdi.obj: skipped 0, total 1 fixsfdi.obj: skipped 0, total 1 fixtfdi.obj: skipped 0, total 0 fixunsdfdi.obj: skipped 0, total 1 fixunsdfsi.obj: skipped 0, total 1 fixunssfdi.obj: skipped 0, total 1 fixunssfsi.obj: skipped 0, total 1 fixunstfdi.obj: skipped 0, total 0 fixunsxfdi.obj: skipped 0, total 0 fixunsxfsi.obj: skipped 0, total 0 fixxfdi.obj: skipped 0, total 0 floatdidf.obj: skipped 0, total 1 floatdisf.obj: skipped 0, total 1 floatditf.obj: skipped 0, total 0 floatdixf.obj: skipped 0, total 0 FSINIT.OBJ: skipped 0, total 1 gcc_bcmp.obj: skipped 0, total 1 LSEEK.OBJ: skipped 0, total 1 lshrdi3.obj: skipped 0, total 1 moddi3.obj: skipped 0, total 1 muldi3.obj: skipped 0, total 1 negdi2.obj: skipped 0, total 1 Fatal: Illegal relocation information at file pos 0000013D op_delete.obj: skipped 0, total 1 op_new.obj: skipped 0, total 1 op_vdel.obj: skipped 0, total 1 op_vnew.obj: skipped 0, total 1 OPEN.OBJ: skipped 0, total 1 PROFILE.OBJ: skipped 0, total 1 pure.obj: skipped 0, total 1 Fatal: Unknown record type 60 at 0000015F shtab.obj: skipped 0, total 0 Fatal: Unknown record type 60 at 000000EE SNDEF.OBJ: skipped 0, total 0 SNMAIN.OBJ: skipped 0, total 1 SNREAD.OBJ: skipped 0, total 1 SNWRITE.OBJ: skipped 0, total 1 trampoline.obj: skipped 0, total 0 ucmpdi2.obj: skipped 0, total 1 udiv_w_sdiv.obj: skipped 0, total 1 udivdi3.obj: skipped 0, total 1 udivmoddi4.obj: skipped 0, total 1 umoddi3.obj: skipped 0, total 1 varargs.obj: skipped 0, total 1 Fatal: Unknown record type 60 at 00000160 LIBSND.LIB: skipped 0, total 223 LIBSPU.LIB: skipped 0, total 126 LIBTAP.LIB: skipped 0, total 1 LOW.OBJ: skipped 0, total 1 Fatal: can't find symbol F003 MCGUI_E.OBJ: skipped 0, total 1 NOHEAP.OBJ: skipped 0, total 1 NONE3.OBJ: skipped 0, total 1 NOPRINT.OBJ: skipped 0, total 1 POWERON.OBJ: skipped 0, total 1

Видим некоторое количество ошибок парсинга, но в тех файлах всего 1 сигнатура (total 1), поэтому думаю, что это не критично. Далее преобразовываем PAT-файл в SIG-файл:

sigmake -n"PsyQ v4.7" psyq47.pat psyq47.sig psyq47.sig: modules/leaves: 1345/2177, COLLISIONS: 21 See the documentation to learn how to resolve collisions.

В итоге получаем следующий список файлов:

  • psyq47.err — его не трогаем
  • psyq47.exc — его нужно будет отредактировать
  • psyq47.pat — его тоже не трогаем

Открываем на редактирование .exc-файл. Видим:

;--------- (delete these lines to allow sigmake to read this file) ; add '+' at the start of a line to select a module ; add '-' if you are not sure about the selection ; do nothing if you want to exclude all modules

Если удалить ---------, всё, что содержится в файле ниже, будет учитываться. Давайте взглянем на то, что там есть. Вот пример:

CdPosToInt                                          60 A21C 0000839001008690022903008010050021104500401002000F00633021104300 DsPosToInt                                          60 A21C 0000839001008690022903008010050021104500401002000F00633021104300

Видим, что две функции имеют одну и ту же сигнатуру, и нам нужно выбрать, какую из них использовать. Для этого слева, рядом с именем нужной функции ставим +. Я выбираю первую. То же самое повторяем с остальными строками.

В итоге, если всё сделано правильно, получаем SIG-файл. Его нужно положить в соответствующую папку в каталоге установка IDA.

Создаём til-файлы

Эти файлы нужны для хранения информации о типах, об аргументах функций и т.п. По умолчанию. Создаются они с помощью утилиты tilib, которую необходимо положить в каталог с Идой (ей, почему-то, нужен ida.hlp файл).

Данной утилите нужно скормить include-файлы вашего SDK/DDK. При том, парсинг этой утилитой отличается от такового средством "Parse C header file…" в самой IDA. Вот описание из readme:

Its functionality overlaps with "Parse C header file…" from IDA Pro.
However, this utility is easier to use and provides more control
over the output. Also, it can handle the preprocessor symbols, while
the built-in command ignores them.

У этой утилиты есть один нюанс: она по умолчанию использует режим, когда символы заманглены либо имеют стоящее в начале имени нижнее подчёркивание. В случае работы со статически влинкованным кодом этот режим нужно выключить флагом -Gn.

По умолчанию, данная утилита принимает на вход только один include-файл. Если же файлов много, нужно соорудить include-файл следующего содержания:

#include "header1.h" #include "header2.h" #include "header3.h" // ...

Этот файл передаётся с помощью флага -hFileName.h. Далее, передаём путь поиска остальных header-файлов и получаем следующую командую строку:

tilib -c -Gn -I. -hpsyq47.h psyq47.til

На выходе получаем til-файл, пригодный для использования. Кладём его в соответствующий каталог IDA: sig\mips.

Проверяем результат

Закидываем ROM-файл в IDA, дожидаемся окончания анализа. Далее, необходимо указать компилятор. Для этого заходим в Options->Compiler:

Теперь просто меняем Unknown на GNU C++ (в случае PSX). Остальное оставляем как есть:

Теперь жмём Shift+F5 (либо меню View->Open subviews->Signatures), жмём Insert и выбираем нужный файл сигнатур:

Жмём OK и ждём, пока применяются сигнатуры (у меня получилось 482 распознанных функции).

Далее, необходимо применить библиотеку типов (til-файл). Для этого жмём Shift+F11 (либо View->Open subviews->Type libraries) и понимаем, что IDA не может определить компилятор (несмотря на то, что мы его уже указали):

Но это нам всё равно не помешает выбрать til-файл (всё так же, через Insert):

Получаем то, что так хотели:

Теперь декомпилятор успешно подхватывает информацию о типах, и выхлоп становится куда лучше:

P.S.

Надеюсь, эта информация окажется для вас полезной. Удачного реверс-инжиниринга!

FavoriteLoadingДобавить в избранное
Posted in Без рубрики

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *