IDC script для анализа RTTI
IDC script для анализа RTTI Delphi 4
Текущая версия 0.2.
Тестировалась на трёх отладочных приложениях и одном реальном ( размером порядка 3 Mb ). Во время тестирования не были проверены published-свойства в виде интерфейсов.
Описание функций
Перечислены в том же порядке, в котором они следуют в файле d4rtti.idc.
- setComment(adr,set_to,is_before)
Вставляет строку set_to комментария по адресу adr. Поскольку функции этого scriptа могут прогоняться несколько раз над одним и тем же адресом, производится проверка, был ли уже вставлен данный комментарий. Параметр is_before определяет, как нужно поместить вновь вставляемый комментарий - до уже имеющегося или после. - ReMakeByte(adr)
Помечает данные по адресу adr как байт и возвращает его значение. - ReMakeInt(adr)
Помечает данные по адресу adr как двойное слово и возвращает его значение. - ReMakeWord(adr)
Помечает данные по адресу adr как слово и возвращает его значение. - ReMakeQword(adr)
Помечает данные по адресу adr как QWORD и возвращает его значение. - MakeOffset(adr)
Помечает данные по адресу adr как смещение и возвращает его значение. - ReMakeFunc(adr)
Пытается преобразовать данные по адресу adr в функцию. Не гарантирует правильного опознавания всего кода функции. - MakeFOffset(adr)
Помечает данные по адресу adr как смещение на функцию и пытается преобразовать данные по этому смещению в функцию. Замечания аналогично предыдущей функции. - MakeNameFOffset(adr,name)
Помечает данные по адресу adr как смещение на функцию и пытается преобразовать данные по этому смещению в функцию, которую переименует в name. Замечания аналогичны ReMakeFunc
- ReMakeStr(adr,len)
Помечает данные по адресу adr длиной len как строку. - makePStr(adr)
Помечает данные по адресу adr как pascal-style строку. Возвращает длину этой строки. - getPStr(adr)
Возвращает pascal-style строку по адресу adr. - getRTTIName(adr)
Возвращает имя класса, чья RTTI содержится по адресу adr. - getOwnedCount(adr)
Возвращает количество структур RTTI для списка субкомпонентов, расположенного по адресу adr. - processOwned(adr)
Обрабатывает список субкомпонентов, расположенный по адресу adr. Возвращает адрес массива структур RTTI для этих субкомпонентов. Поскольку я не смог вызвать на IDC функцию, описанную позже, чем её вызов, рекурсивная обработка RTTI здесь не используется. Вместо этого эти структуры RTTI обрабатываются позже в _processRTTI. - processHandlers(adr,class_name)
Обрабатывает таблицу обработчиков событий по адресу adr для класса с именем class_name. Для всех функций-обработчиков в качестве префикса добавляется имя class_name ( для обеспечения уникальности этих имён ). - get_type_name(adr)
Возвращает имя типа для структуры TypeInfo по адресу adr. - TypeOrdComm(Ord)
Возвращает строковое название размера простого типа данных Ord. - TypeOrdKind(Ord)
Возвращает строковое название типа данных Ord. - TypeOrdFloat(Ord)
Возвращает строковое название размера для типов данных с плавающей точкой Ord. - doParamFlag(Set)
Возвращает в виде строки представление набора атрибутов Set параметра функций и процедур. - doIntfFlag(Set)
Возвращает в виде строки представление набора атрибутов Set интерфейса. - TypeOrdMethod(Ord)
Возвращает строковое название типа метода Ord. - processTypeInfo(adr)
Обрабатывает структуру TypeInfo по адресу adr.
Предупреждения относительно этой функции:
- Не производится рекурсивная обработка поля BaseType для типа tkEnumeration. Причиной это служит зацикливание (если тип tkEnumeration не наследует ни от какого набора, это полу указывает на свою же структуру TypeData).
- Для типа tkClass не производится рекурсивной обработки структуры RTTI ClassType. Это сделано для предотвращения зацикливаний ( если, скажем, свойством некоторого класса будет указатель на тот же самый класс ), также см. примечание к функции processOwned.
- По вышеназванным причинам не производится обработка структуры ParentInfo (указатель на TypeInfo предка) и PropData (рекурсивная структура TypeInfo) для типа tkClass.
- Поскольку у меня не было published-свойств - интерфейсов, обработка типа tkInterface не производится.
- separatePointer(base_adr, adr, kind)
Возвращает строковое описание метода в атрибутах published-свойств. Адрес RTTI класса передаётся в base_adr, адрес атрибута в adr, строка с описанием класса атрибута в kind. - doPublished(adr, base_adr)
Обрабатывает published-свойства класса по адресу adr, RTTI класса находится по адресу base_adr. См. также предупреждения относительно функции processTypeInfo. - processDynamic(adr)
Обрабатывает таблицу динамических методов по адресу adr. Динамические функции никак не называются. - makeF2Offset(adr,name)
Помечает данные по адресу adr как указатель на функцию и вставляет комментарий name. - make_TGUID(adr)
Помечает данные по адресу adr как GUID. - padZeros(str,desired_len)
Увеличивает длину строки str до длины desired_len, дополняя её слева символов "0". - getTGUIDstr(adr)
Возвращает строковое представление GUID по адресу adr. - processIntf(adr)
Обрабатывает таблицу интерфейсов по адресу adr. - get_dyncount(adr)
Возвращает число динамических методов для структуры RTTI по адресу adr. - _processRTTI(adr, is_recursive)
Обрабатывает RTTI структуру по адресу adr. Флаг is_recursive предназначен для рекурсивной обработки всех связанных структур RTTI. - askRTTI(adr)
Выдаёт приглашение на обработку структуры RTTI по адресу adr. В случае успеха возвращает 1. - processRTTI(adr)
Обрабатывает RTTI структуру по адресу adr. - allRTTI(adr)
Рекурсивно обрабатывает структуру RTTI по адресу adr.
Пример использования
В IDA Pro загрузить этот script ( нажатием F2 ). Далее, поместив курсор на адрес начала структуры RTTI, выполнить команду IDC:
processRTTI(ScreenEA());
Предполагаемые улучшения
- Поддержка published-свойств интрефейсного типа.
- Поддержка сохранения информации о RTTI в текстовый файл (IMHO, значительно приятнее иметь подобного рода информацию для дальнейшего дизассемблирования в IDA Pro распечатанной на бумаге, нежели постоянно рыскать по структуре RTTI)
- Функции для поддержки exceptions & system initialization
- Здесь могут быть и Ваши предложения. Напишите автору по адресу redplait@usa.net
Файл d4rtti.idc
/* * This script deal with Delphi RTTI structures * * Created by Red Plait ( redplait@usa.net ), 23-VIII-1999 * History: * 28-08-1999 RP Added support for dynamic methods * 01-09-1999 RP Added support for interfaces & eight methods in VTBL * with negative indexes * 06-09-1999 RP TypeInfo of published properties (rip some code from * Santucco) */ #include
// consts for TypeInfo #define tkUnknown 0 #define tkInteger 1 #define tkChar 2 #define tkEnumeration 3 #define tkFloat 4 #define tkString 5 #define tkSet 6 #define tkClass 7 #define tkMethod 8 #define tkWChar 9 #define tkLString 10 #define tkWString 11 #define tkVariant 12 #define tkArray 13 #define tkRecord 14 #define tkInterface 15 #define tkInt64 16 #define tkDynArray 17
// consts for OrdType #define otSByte 0 #define otUByte 1 #define otSWord 2 #define otUWord 3 #define otSLong 4
// consts for FloatType #define ftSingle 0 #define ftDouble 1 #define ftExtended 2 #define ftComp 3 #define ftCurr 4
// consts for MethodKind #define mkProcedure 0 #define mkFunction 1 #define mkConstructor 2 #define mkDestructor 3 #define mkClassProcedure 4 #define mkClassFunction 5 #define mkSafeProcedure 6 #define mkSafeFunction 7
// consts for ParamFlag - set #define pfVar 0 #define pfConst 1 #define pfArray 2 #define pfAddress 3 #define pfReference 4 #define pfOut 5
// consts for IntfFlag - set #define ifHasGuid 0 #define ifDispInterface 1 #define ifDispatch 2
// do reenterable comments :-) // Params: // adr - address to comment // set_to - comment to set // is_before - place new comment before old static setComment(adr,set_to,is_before) { auto old_comm;
if ( ! strlen(set_to) ) return; // no comments old_comm = Comment(adr); if ( ! strlen(old_comm) ) { MakeComm(adr, set_to); return; } if ( -1 != strstr(old_comm,set_to) ) return; if ( is_before ) MakeComm(adr,set_to + "," + old_comm); else MakeComm(adr,old_comm + "," + set_to); }
// makes Byte static ReMakeByte(adr) { MakeUnkn(adr,0); MakeByte(adr); return Byte(adr); }
// makes dword static ReMakeInt(adr) { MakeUnkn(adr,0); MakeUnkn(adr+1,0); MakeUnkn(adr+2,0); MakeUnkn(adr+3,0); MakeDword(adr); return Dword(adr); }
// makes word static ReMakeWord(adr) { MakeUnkn(adr,0); MakeUnkn(adr+1,0); MakeWord(adr); return Word(adr); }
// makes qword static ReMakeQword(adr) { auto count; for ( count = 0; count < 8; count++ ) MakeUnkn(adr + count, 0); MakeQword(adr); return Qword(adr); }
// makes dword and offset to data static MakeOffset(adr) { auto ref_adr;
ref_adr = ReMakeInt(adr); if ( ref_adr != 0 ) add_dref(adr, ref_adr, 0); return ref_adr; }
static ReMakeFunc(adr) { if ( adr != 0 ) { MakeUnkn(adr,1); MakeCode(adr); MakeFunction(adr, BADADDR); } }
// makes dword and offset to a function static MakeFOffset(adr) { auto ref_adr; ref_adr = MakeOffset(adr); ReMakeFunc(ref_adr); return ref_adr; }
// make offset to function and name it static MakeNameFOffset(adr,name) { auto ref_adr;
ref_adr = MakeFOffset(adr); if ( ref_adr ) MakeName(ref_adr,name); }
// makes simple string static ReMakeStr(adr,len) { auto count; for ( count = 0; count < len; count++ ) MakeUnkn(adr + count,0); MakeStr(adr, adr+len); }
// makes Pascal-style string // Returns lenght of pascal string (including byte for lenght) static makePStr(adr) { auto len; MakeUnkn(adr,0); len = ReMakeByte(adr); ReMakeStr(adr+1,len); return len + 1; }
// extract pascal-style string static getPStr(adr) { auto len, res, c;
len = Byte(adr++); res = ""; for ( ; len; len-- ) { c = Byte(adr++); res = res + c; } return res; }
// returns name of class of this RTTI static getRTTIName(adr) { auto ptr; ptr = Dword(adr+0x20); if ( ptr != 0 ) return getPStr(ptr); else return ""; }
static getOwnedCount(adr) { return Word(Dword(adr+2)); // wow! }
// processing owned components list // Returns ptr to RTTI array (cauze I don`t know how to make forward declaration // of _processRTTI static processOwned(adr) { auto count, str_len, comp_count, rtti_base;
comp_count = ReMakeWord(adr); /* count of RTTI array */ adr = adr + 2; rtti_base = MakeOffset(adr); /* offset to array of RTTI */ adr = adr + 4; /* process RTTI array */ count = ReMakeWord(rtti_base); /* size of array */ rtti_base = rtti_base + 2; for ( str_len = 0; str_len < count; str_len++ ) { MakeOffset(rtti_base + str_len * 4); } /* process each of owned to form components */ for ( count = 0; count < comp_count; count++ ) { // offset in owners class str_len = ReMakeWord(adr); setComment(adr, "Offset 0x" + ltoa(str_len,0x10), 1); adr = adr + 2; // unknow word ReMakeWord(adr); adr = adr + 2; // index in RTTI array str_len = ReMakeWord(adr); setComment(adr, "Type: " + getRTTIName(Dword(rtti_base + str_len*4)), 1 ); adr = adr + 2; // pascal string - name of component str_len = ReMakeByte(adr); adr = adr + 1; ReMakeStr(adr,str_len); adr = adr + str_len; } return rtti_base; }
// process events handlers list static processHandlers(adr,class_name) { auto count, str_len;
count = ReMakeWord(adr); setComment(adr,"Handlers count", 1); adr = adr + 2; for ( ; count; count-- ) { // unknown dword ReMakeWord(adr); adr = adr + 2; // offset to function - handler MakeNameFOffset(adr, class_name + "." + getPStr(adr+4) ); adr = adr + 4; // Name of handler adr = adr + makePStr(adr); } }
// returns name of type published property static get_type_name(adr) { auto deref;
deref = Dword(adr); if ( deref ) return getPStr(deref + 1); else return ""; }
#define encodeKind(c, name) if ( Ord == c ) return name;
static TypeOrdComm(Ord) { encodeKind(otSByte, "signed byte" ); encodeKind(otUByte, "unsigned byte" ); encodeKind(otSWord, "signed word"); encodeKind(otUWord, "unsigned word"); encodeKind(otSLong, "signed long");
return ""; }
static TypeOrdKind(Ord) { encodeKind(tkUnknown, "unknown"); encodeKind(tkInteger, "integer"); encodeKind(tkChar, "char"); encodeKind(tkEnumeration, "enum"); encodeKind(tkFloat, "float"); encodeKind(tkString, "string"); encodeKind(tkSet, "set"); encodeKind(tkClass, "class"); encodeKind(tkMethod, "method"); encodeKind(tkWChar, "WChar"); encodeKind(tkLString, "LString"); encodeKind(tkWString, "WString"); encodeKind(tkVariant, "variant"); encodeKind(tkArray, "array"); encodeKind(tkRecord, "record"); encodeKind(tkInterface,"interface"); encodeKind(tkInt64,"int64"); encodeKind(tkDynArray, "DynArray");
return ""; }
static TypeOrdFloat(Ord) { encodeKind(ftSingle, "single"); encodeKind(ftDouble, "double"); encodeKind(ftExtended, "extended"); encodeKind(ftComp, "comp"); encodeKind(ftCurr, "currency"); return ""; }
#define encodeSet(c,name) if ( (1= vtbl_adr ) { if ( ! vtbl_end ) vtbl_end = my_name; else if ( vtbl_end > my_name ) vtbl_end = my_name; } } /* for debug only: Message("end of VTBL is " + ltoa(vtbl_end, 0x10) ); */ for ( count = vtbl_end - vtbl_adr ; count > 0; count = count - 4 ) { MakeFOffset(vtbl_adr); vtbl_adr = vtbl_adr + 4; } } if ( is_recursive && res) _processRTTI(res, is_recursive); return res; }
// pre-check RTTI and ask about it static askRTTI(adr) { auto name, dyn_count, what_say; name = getRTTIName(adr); dyn_count = get_dyncount(adr); what_say = "Do you want to process RTTI of class \"" + name + "\""; if ( dyn_count ) what_say = what_say + " with " + ltoa(dyn_count, 10) + " dynamic methods"; what_say = what_say + "?"; return AskYN(1, what_say); }
// main function - process RTTI with small pre-checking static processRTTI(adr) { if ( 1 == askRTTI(adr) ) _processRTTI(adr,0); }
// process all RTTI from this (recursive) static allRTTI(adr) { if ( 1 == askRTTI(adr) ) _processRTTI(adr,1); }
static UnitEntries(adr) { auto count, i;
count = ReMakeInt(adr); adr = MakeOffset(adr + 4); if ( !adr || ! count ) return; for ( i = 0; i < count; i++ ) { MakeFOffset(adr); setComment(adr,ltoa(i+1,10) + " Initialize",1); adr = adr + 4; MakeFOffset(adr); setComment(adr,"Finalize",1); adr = adr + 4; } }
Желаю удачи...
Den is Com
[000859]
Содержание раздела