eXTracted INternals

eXTracted INternals
 
ФорумФорум  ЧаВоЧаВо  ПоискПоиск  РегистрацияРегистрация  ПользователиПользователи  ГруппыГруппы  Вход  

Поделиться | 
 

 Реверсим Objective C++

Предыдущая тема Следующая тема Перейти вниз 
АвторСообщение
Hex

avatar

Количество сообщений : 397
Возраст : 35
Дата регистрации : 2006-07-12

СообщениеТема: Реверсим Objective C++   Ср 5 Мар - 6:08

"В отличие от C++, язык Objective-C полностью совместим с Си и является довольно тонкой надстройкой. Объектная модель

построена в стиле Smalltalk, то есть, объектам посылаются сообщения." (с) Wikipedia http://ru.wikipedia.org/wiki/Objective-C

Большей частью он юзается в Mac OS, но с появлением софта от Apple под Windows, objective C++ можно наблюдать и в винде.

Компилер для этого дела пока видел только один - GNU
По сути понимать как кодить под Objective C++ не так уж и важно. Важно понимать, что этот язык оперирует объектами посылая

сообщения, со всеми вытекающими последствиями.

Для того чтобы такой обмен сообщениями был возможен, компилер впихивает в бинарь кучу RTTI инфы, которая для реверсера - мана

небесная. Реверсинг очень похож на реверсинг кода Delphi.
Все начинается с дескриптора класса:
Код:

__class:000050E0 tst_AppDelegate__Des dd offset stru_5160    ; isa
__class:000050E0                dd offset aNsobject    ; super_class ; "tst_AppDelegate"
__class:000050E0                dd offset aTst_appdelegat; name
__class:000050E0                dd 0                    ; version
__class:000050E0                dd 1                    ; info
__class:000050E0                dd 14h                  ; instance_size
__class:000050E0                dd offset tst_AppDelegate__Vars; ivars
__class:000050E0                dd offset tst_AppDelegate__Methods; methods
__class:000050E0                dd 0                    ; cache

Вот его структура:
Код:
struct __class_struct
{
  void *isa;
  char *super_class;
  char *name;
  __int32 version;
  __int32 info;
  __int32 instance_size;
  void *ivars;
  void *methods;
  __int32 cache;
  void *meta_class_methods;
};

Структуры дескрипторов уже изначально есть в IDA начиная с версии 5.2.

Что полезного мы можем узнать из дескриптора класса? Да практически все!
Поле isa - указатель на заранее выделенную память под экземпляр класса! Здесь не надо искать тело объекта, это известно

заранее!
Поле super_class - указатель на имя базового класса
Поле name - имя самого класса
Поле instance_size - размер класса в памяти. Первые 4 байта юзаются под VTBL, а дальше идут собственно поля класса.
Поле ivars - указатель на массив дескрипторов полей класса.
Поле methods - указатель на массив дескрипторов методов класса.
Остальные поля для реверсинга не так важны, если интересно узнать их предназначение, вот их описание:
http://www.promac.ru/book/Sams%20-%20Cocoa%20Programming/0672322307_app01lev1sec1.html

Итого мы сразу знаем имя класса и от кого он отнаследован, мы знаем все его методы и все переменные и знаем его размер.
Дескрипторы методов выглядят вот так:
Код:
_inst_meth:00005200 tst_AppDelegate__Methods dd 0          ; DATA XREF: __class:tst_AppDelegate__Deso
__inst_meth:00005204                dd 0Bh
__inst_meth:00005208                dd offset aSecondaction, offset aV12@04@8, offset __tst_AppDelegate_secondAction__ ;

"secondAction:"
__inst_meth:00005214                dd offset aFirstaction, offset aV12@04@8, offset __tst_AppDelegate_firstAction__ ;

"firstAction:"
...

В начале указано сколько методов, а дальше идет сам массив дескрипторов.
Структура дескриптора метода вот такая:
Код:
struct objc_method {
        char *method_name;
        char *method_types;
        void *method_imp;
} *Method;

method_name - указатель на имя метода
method_types - указатель на строку, в которой заманглены аргументы и возвращаемое значение. Как оно манглится надо искать в

сорцах gnu-шного ObjC компилера.
method_imp - указатель на сам код метода.

Ну и остались поля класса:
Код:
__instance_vars:000052C0 tst_AppDelegate__Vars dd 4              ; DATA XREF: __class:tst_AppDelegate__Deso
__instance_vars:000052C4                __instance_vars_struct <offset aWindow, offset a@Nswindow, 4> ; "window"
__instance_vars:000052D0                __instance_vars_struct <offset aPersistentstor, \ ; "persistentStoreCoordinator"
__instance_vars:000052D0                                        offset a@Nspersistents, 8>
__instance_vars:000052DC                __instance_vars_struct <offset aManagedobjectm, \ ; "managedObjectModel"
__instance_vars:000052DC                                        offset a@Nsmanagedobje, 0Ch>
__instance_vars:000052E8                __instance_vars_struct <offset aManagedobjectc, \ ; "managedObjectContext"
__instance_vars:000052E8                                        offset a@Nsmanagedob_0, 10h>

struct __instance_vars_struct
{
  char *name;
  char *type;
  __int32 offset;
}
name - имя поля класса
type - замангленая строка, указывающая тип
offset - смещение поля от начала объекта

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

методов.

Если глянуть в код любого метода, увидим примерно вот такое:
Код:
__text:0000262F                mov    edx, [ebp+arg_0]
__text:00002632                lea    eax, (off_5064 - 2628h)[ebx] ; _managedObjectContext
__text:00002638                mov    eax, [eax]
__text:0000263A                mov    [esp+28h+var_24], eax
__text:0000263E                mov    [esp+28h+var_28], edx
__text:00002641                call    _objc_msgSend
__text:00002646                mov    ecx, eax
__text:00002648                lea    eax, (off_506C - 2628h)[ebx] ; save:
__text:0000264E                mov    edx, [eax]
__text:00002650                lea    eax, [ebp+var_C]
__text:00002653                mov    [esp+28h+var_20], eax
__text:00002657                mov    [esp+28h+var_24], edx
__text:0000265B                mov    [esp+28h+var_28], ecx
__text:0000265E                call    _objc_msgSend

Вся работа с классами делается функцией _objc_msgSend.
Передача параметров в функцию выглядит как запихивание значений в стековые переменные командой mov, на самом деле это операция аналогичная push. Первым параметром в нее передают указатель на класс, метод которого хотят вызвать, вторым - указатель на метод. А дальше идут уже аргументы класса. В сами методы параметры поступают аналогичным образом: первый аргумент - указатель на this, второй - указатель на имя метода.

Таким образом чтобы найти код метода, надо просто поискать его имя как строку. А потом найти дескриптор метода, который указыает на эту строку. Т.е. тут все связи идут по именам методов + по именам классов.

Сложности в анализе Objective C++ кода
Имена методов идут через двойной указатель, приходится проставлять коменты, чтобы было проще визуально понимать какой метод вызывается.
Из-за использования mov вместо push, IDA не может проставить коментарии для передаваемых значений, это приходится делать руками.
Вернуться к началу Перейти вниз
Посмотреть профиль
Palex



Количество сообщений : 1
Дата регистрации : 2011-05-20

СообщениеТема: Re: Реверсим Objective C++   Пт 20 Май - 3:50

Пара ссылок, в которых есть некоторая информация о типах параметров методов:

http://code.google.com/p/jscocoa/wiki/MethodEncoding
http://code.google.com/p/jscocoa/wiki/TypeEncoding
Вернуться к началу Перейти вниз
Посмотреть профиль
 
Реверсим Objective C++
Предыдущая тема Следующая тема Вернуться к началу 
Страница 1 из 1

Права доступа к этому форуму:Вы не можете отвечать на сообщения
eXTracted INternals :: Cтатьи :: Win32 reversing-
Перейти: