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

  • Tutorial

Всем привет,



При работе в 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.


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

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 11

    0
    А в какой версии появилась декомпиляция MIPS?
      +1
      В версии 7.5. Но так же, отдельным плагином, как и декомпиляторы для всех остальных платформ.
        0
        Пока к сожалению такую версию мне не раздобыть, но новость приятная.
      0
      CdPosToInt 60 A21C 0000839001008690022903008010050021104500401002000F00633021104300
      DsPosToInt 60 A21C 0000839001008690022903008010050021104500401002000F00633021104300

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


      А почему вы выбрали первую сигнатуру?
      У вас есть какая-нибудь версия, почему могла такая коллизия сигнатур произойти?
        0

        Насколько я понимаю, Cd функции чаще используются, чем Ds. А причина одна — одинаковый код.

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

        Вот этот момент просьба прояснить подробнее.
          0

          Если не добавить флаг, то функции в til-е по умолчанию будут с таким именованием: _funcName, а после применения сигнатур у нас же нет подчёркиваний, поэтому будет просто — funcName.

          0
          спасибо, хотелось бы увидеть разбор на исходник какой-нибудь популярной sega игры
            0
            Это явно больше одной статьи. У меня на youtube-канале имеются уже ролики, и они по два-три часа идут.
              0
              К примеру была такая статья habr.com/ru/post/339936 в ней разбирали Aladdin, но самих исходников не приложили, быть может когда-нибудь, благодаря вам, мы увидим сами компилируемые исходники.
            0
            круто, вот бы такое же но для SH-4 и Katana SDK Dreamcast-а. я сколько ни пытался рабочие сигнатуры сделать так и не осилил :(

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое