Советы по Delphi

       

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.
    Предупреждения относительно этой функции:

    1. Не производится рекурсивная обработка поля BaseType для типа tkEnumeration. Причиной это служит зацикливание (если тип tkEnumeration не наследует ни от какого набора, это полу указывает на свою же структуру TypeData).
    2. Для типа tkClass не производится рекурсивной обработки структуры RTTI ClassType. Это сделано для предотвращения зацикливаний ( если, скажем, свойством некоторого класса будет указатель на тот же самый класс ), также см. примечание к функции processOwned.
    3. По вышеназванным причинам не производится обработка структуры ParentInfo (указатель на TypeInfo предка) и PropData (рекурсивная структура TypeInfo) для типа tkClass.
    4. Поскольку у меня не было published-свойств - интерфейсов, обработка типа tkInterface не производится.
    5. separatePointer(base_adr, adr, kind)
      Возвращает строковое описание метода в атрибутах published-свойств. Адрес RTTI класса передаётся в base_adr, адрес атрибута в adr, строка с описанием класса атрибута в kind.
    6. doPublished(adr, base_adr)
      Обрабатывает published-свойства класса по адресу adr, RTTI класса находится по адресу base_adr. См. также предупреждения относительно функции processTypeInfo.
    7. processDynamic(adr)
      Обрабатывает таблицу динамических методов по адресу adr. Динамические функции никак не называются.
    8. makeF2Offset(adr,name)
      Помечает данные по адресу adr как указатель на функцию и вставляет комментарий name.
    9. make_TGUID(adr)
      Помечает данные по адресу adr как GUID.
    10. padZeros(str,desired_len)
      Увеличивает длину строки str до длины desired_len, дополняя её слева символов "0".
    11. getTGUIDstr(adr)
      Возвращает строковое представление GUID по адресу adr.
    12. processIntf(adr)
      Обрабатывает таблицу интерфейсов по адресу adr.
    13. get_dyncount(adr)
      Возвращает число динамических методов для структуры RTTI по адресу adr.
    14. _processRTTI(adr, is_recursive)
      Обрабатывает RTTI структуру по адресу adr. Флаг is_recursive предназначен для рекурсивной обработки всех связанных структур RTTI.
    15. askRTTI(adr)
      Выдаёт приглашение на обработку структуры RTTI по адресу adr. В случае успеха возвращает 1.
    16. processRTTI(adr)
      Обрабатывает RTTI структуру по адресу adr.
    17. allRTTI(adr)
      Рекурсивно обрабатывает структуру RTTI по адресу adr.
    Пример использования



    В IDA Pro загрузить этот script ( нажатием F2 ). Далее, поместив курсор на адрес начала структуры RTTI, выполнить команду IDC:

    processRTTI(ScreenEA()); Предполагаемые улучшения
    • Поддержка published-свойств интрефейсного типа.
    • Поддержка сохранения информации о RTTI в текстовый файл (IMHO, значительно приятнее иметь подобного рода информацию для дальнейшего дизассемблирования в IDA Pro распечатанной на бумаге, нежели постоянно рыскать по структуре RTTI)
    • Функции для поддержки exceptions & system initialization
    • Здесь могут быть и Ваши предложения. Напишите автору по адресу
    Файл 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; } } Желаю удачи...

    [000859]


    Содержание раздела