Главная страница
Навигация по странице:

  • Rfirst(0x128C6) ); 0x28C7 seg000:28CB retn seg000:28CB sub_0_2847 endp Message(“0x%X \n”, Rfirst(0x128CB)

  • Rfirst(0x12870)

  • Описание функций встроенного языка


    Скачать 2.86 Mb.
    НазваниеОписание функций встроенного языка
    Анкорobraz_mihlenia_-_dizassembler_IDA
    Дата29.09.2022
    Размер2.86 Mb.
    Формат файлаpdf
    Имя файлаobraz_mihlenia_-_dizassembler_IDA.pdf
    ТипСправочник
    #704305
    страница21 из 39
    1   ...   17   18   19   20   21   22   23   24   ...   39
    ХРАНЕНИЕ ПЕРЕКРЕСТНЫХ ССЫЛОК
    Как хранятся перекрестные ссылки внутри IDA скрыто от пользователя. Достоверно известно лишь то, что хранятся они достаточно эффективно. А детали реализации недокументированны и могут меняться от версии к версии.
    Однако, значение того, как физически хранятся перекрестные ссылки помогает лучше понять их структуру и работу с ними. На самом деле перекрестная ссылка представляет собой два объекта.
    Первый из них – источник, который «одним концом» ассоциирован с линейным адресом, по которому он расположен, а другим указывает на адрес приемника. Аналогично и с приемником. Он так же состоит из двух концов.
    То есть перекрестная ссылка это «двуполый» объект и этим и объясняться идентичный набор функций для работы с ее источником и приемников, а во-вторых, скорость доступа к источнику и приемнику одинакова. Это было бы не так, если бы в узле дерева хранилась структура (from, to) и тогда бы для поиска каждого приемника пришлось бы просматривать все дерево
    Это не относится к ссылкам на следующую команду, которые хранятся во флагах и организованы совсем по-другому. На каждую ссылку расходуется всего один бит(!). Если он установлен, то, следовательно, ссылка на следующую команду присутствует и наоборот.
    Адрес же ссылки определяется длиной инструкции, которая численно совпадает с длиной объекта. Подробнее об этом можно прочитать в главе «Объекты в IDA»
    Однако, необходимо еще раз уточнить, что все эти подробности могут и не соответствовать действительности в какой-то конкретной версии IDA. Кроме того, с течением времени алгоритмы могут быть пересмотрены и изменены на другие, более эффективные.
    Возможно, даже, что изменения затронут и встроенный язык IDA, что происходит, прямо скажем, регулярно. Поэтому рекомендуется пользоваться своими функциями – обертками, что уже не раз упоминалась в данной книге.
    Дело в том, что переписать библиотеку своих функций намного проще, чем изменить все скрипты. К тому же библиотеку легко разместить в любом включаемом файле в IDA и тогда скрипты окажутся переносимыми, в противном же случае их придется редактировать каждый раз заново.
    А вообще, если бы язык скриптов был бы на порядок популярнее, то автор бы не позволил себе такую роскошь как менять прототипы встроенных функций без сохранения обратной совместимости.
    МЕТОДЫ
    Функция
    Назначение

    207
    void AddCodeXref(long From,long
    To,long flowtype);
    Создает перекрестную ссылку типа ‘code’ long DelCodeXref(long From,long
    To,int undef)
    Удаляет перекрестную ссылку типа ‘code’ long Rfirst (long From);
    Функция возвращает линейный адрес приемника первой перекрестной ссылки указанного источника long Rnext (long From,long current);
    Эта функция возвращает линейный адрес приемника очередной перекрестной ссылки в списке. long RfirstB (long To);
    Функция возвращает адрес следующего источника в списке перекрестных ссылок, расположенного по указанному приемнику long RnextB (long To,long current)
    Функция возвращает адрес следующего источника в списке перекрестных ссылок, расположенного по указанному приемнику long Rfirst0 (long From);
    Функция возвращает линейный адрес приемника перекрестной ссылки для заданного источника long Rnext0 (long From,long current);
    Эта функция по идее (а точнее следуя из сказанного в файле idc.idc) должна отличатся от Rnext только отсутствием доступа к перекрестным ссылкам на следующую инструкцию. Однако из-за ошибок реализации функции Rnext она «не видит» такой тип ссылок и это делает обе функции полностью идентичными. long RfirstB0(long To);
    Функция возвращает линейный адрес источника перекрестной ссылки для заданного приемника. long RnextB0 (long To,long current);
    Эта функция по идее (а точнее следуя из сказанного в файле idc.idc) должна отличатся от RnextB только отсутствием доступа к перекрестным ссылкам на следующую инструкцию. void add_dref(long From,long
    To,long drefType);
    Добавляет перекрестую ссылку типа ‘data’ void del_dref(long From,long To);
    Удаляет перекрестную ссылку типа ‘data’ long Dfirst (long From);
    Функция возвращает линейный адрес приемника первой перекрестной ссылки

    208
    указанного источника long Dnext (long From,long current);
    Эта функция возвращает линейный адрес приемника очередной перекрестной ссылки в списке. long DfirstB (long To);
    Функция возвращает линейный адрес первого источника для указанного списка приемников long DnextB (long To,long current);
    Функция возвращает адрес следующего источника в списке перекрестных ссылок, расположенного по указанному приемнику. long XrefType(void);
    Эта функция возвращает тип перекрестной ссылки, которая была возвращена последним вызовом функций Rfirst, Rnext,
    RfirstB, RnextB, Dfirst, Dnext, DfirstB, DnextB.
    void AddCodeXref(long From,long To,long flowtype);
    Функция создает кодовую перекрестную ссылку. IDA содержит мощный механизм, эмулирующий выполнение инструкций процессора и отслеживающий не только прямые, но даже косвенные ссылки.
    Начиная с версии 3.74, она значительно превосходит в этом даже SOURCER, до этого лидирующий среди других дизассемблеров в умении восстанавливать перекрестные ссылки.
    Перекрестные ссылки действительно очень облегчают анализ исследуемой программы. Допустим, встречается в тексте стока
    Seg000:0123 DB ‘Hello, World!’,0Dh,0Ah,0
    Как узнать – какой код ее выводит? Для этого, очевидно, нужно найти ссылку на смещение 0x123. Это IDA и делает автоматически. Благодаря перекрестным ссылкам можно трассировать исполнение программы, что позволяет лучше понять ее структуру.
    IDA поддерживает два типа ссылок – на код и на данные. AddCodeXref, как нетрудно догадаться добавляет новую перекрестную ссылку на код, то есть инструкцию, изменяющую линейное исполнение программы.
    Структура ссылок следующая:
    From (Source) Æ To (Target)
    Источник – это 32-битный линейный адрес начала инструкции, вызывающей изменение линейного исполнения кода, а приемник – это линейный адрес начала инструкции, на которую выполняется такой переход.
    IDA отображает перекрестные ссылки в виде комментариев исключительно возле инструкции приемника. seg000:0475 jnz loc_0_47A seg000:0477 mov cx, 4 seg000:047A

    209
    seg000:047A loc_0_47A: ;
    CODE XREF: seg000:0475j seg000:047A sub bx, 10h
    В приведенном выше примере показана перекрестная ссылка From == 0x475, To ==
    0x47A. Каким-то особым образом отмечать источник нет необходимости, поскольку он предполагается очевидным (в данном случае адрес указан в непосредственном операнде).
    Подведя курсор к метке ‘loc_0_47A’ и нажав на Enter, можно перейти к приемнику. А что бы вновь вернуться к источнику, – достаточно кликнуть по перекрестной ссылке.
    Разумеется, что на один и тот же приемник может ссылаться более одного источника.
    Например: seg000:0C4A cmp ah, 4Dh
    ; 'M'
    seg000:
    0C4D jnz loc_0_C5A seg000:0C4F cmp byte_0_F76, 9 seg000:
    0C54 ja loc_0_C5A seg000:0C56 inc byte_0_F76 seg000:0C5A loc_0_C5A: ;
    CODE XREF: seg000:0C4Dj seg000:0C5A ; seg000:0C54j
    Немного не очевидно, но IDA поддерживает мульти - источники. Однако, действительно, возможно такое условное ветвление, что в зависимости от операнда приемник может варьироваться.
    Например, широко распространенная команда JMP BX, используемая многими компиляторами объективно-ориентированных языков, да и в моделях Маркова, например, то же.
    Тип ссылки указывается в постфиксе. В данном случае это ‘j’, что обозначает близкий (NEAR) условный или безусловный переход. IDA поддерживает четыре основных типа ссылок, которые перечислены в приведенной ниже таблице.
    Определение
    Пояснения
    Уточнение
    Легенда fl_CF 1 6
    Межсегментный вызов процедуры
    Call Far
    P fl_CN 1 7
    Внутрисегментный вызов процедуры
    Call Near p fl_JF 1 8
    Межсегментный переход
    Jump Far
    J fl_JN 1 9
    Внутрисегментный переход
    Jump Near j fl_US 2 0
    Определяется пользователем
    User specified u fl_F 2 1
    Следующая инструкция
    Ordinary flow
    ^
    Последний тип необходимо отметить особо. В контекстной помощи об этом нет никакого упоминания. Правда, заглянув в SDK можно узнать, что такие перекрестные ссылки предназначены для указаний на следующую инструкцию и вообще стоят особняков от всех остальных перекрестных ссылок.
    Когда другие хранятся в базе Btree, значение Ordinary flow извлекается из флагов ячеек виртуальной памяти.
    Для чего это может понадобиться? Дело в том, что некоторые процессоры имеют такую запутанную архитектуру, что вычисление адреса следующей команды под час

    210
    представляется весьма нетривиальной задачкой. Поэтому, не лишние возложить эту работу на плечи IDA, создав перекрестные ссылки соответствующего типа.
    Однако, заметим, что тип перекрестных ссылок – понятие чисто условное и субъективное. Он был введен лишь затем, что бы в удобно читаемой форме предоставить пользователю дополнительную информацию о ссылке, облегчая ему работу по изучению программ.
    IDA не следит за корректностью типов ссылок, - забота эта лежит исключительно на плечах кода, создающего ссылки. Ничто не помешает нам создать и вовсе бессмысленную ссылку, – например: seg000:0C29 mov dx, word ptr byte_0_F76 seg000:0C2D call sub_0_EF8 seg000:0C30 call sub_0_F45 seg000:0C33 jb loc_0_C69 ;
    CODE XREF: seg000:0C29J
    Очевидно, что инструкция mov не может изменять порядок выполнения кода, однако, IDA безболезненно позволяет создавать перекрестную ссылку с таким источником под типом «межсегментный переход»
    Заметим, что в зависимости от некоторых настоек, при создании перекрестных ссылок типа «вызов процедуры» IDA может автоматически создавать процедуру на месте приемника, даже если сама ссылка ошибочная.
    Поэтому для пользовательских скриптов рекомендуется использовать специально определенный тип, который гарантировано, не влечет за собой никаких последствий.
    Заметим, что IDA позволяет создавать перекрестные ссылки, указывающие на середину инструкции. Они выделяются красным цветом и располагаются перед указанной инструкцией. Аналогично адрес округляется и при всех попытках перехода.
    Операнд
    Пояснения
    From
    Адрес источника перекрестной ссылки
    To
    Адрес приемника перекрестной ссылки flowtype
    Тип перекрестной ссылки (смотри таблицу, приведенную выше)
    Обратите внимание, что функция не возвращает никакого значения, по которому можно было бы судить об успешности завершения операции. Вместо этого функция может при необходимости выводить пояснения в окно сообщений, но это не поможет в определении ошибки автономным скриптам.
    long DelCodeXref(long From,long To,int undef);
    Функция удаляет перекрестную ссылку типа ‘code’. Для этого необходимо знать ее источник (From) и приемник (To). Подробнее об этом можно прочитать в описании функции
    AddCodeXref.
    Имеется возможность автоматически помечать приемник (и все последующие инструкции) как ‘undefined’, если на них больше не указывает ни одной ссылки. Для этого флаг ‘undef’ необходимо установить равным единице.
    Например: seg000:002B 11 02 dw 211h seg000:002D ; ---------------------------------------
    -- seg000:002D E8 AD 00 call sub_0_DD ; CODE
    XREF: seg000:0395p

    211
    seg000:002D ; seg000:22F5p seg000:0030 BE BA 02 mov si, 2BAh seg000:0033 E8 A7 00 call sub_0_DD seg000:0036 C3 retn
    DelCodeXref(0x10395,0x1002D,1);
    DelCodeXref(0x122F5,0x1002D,1); seg000:002B 11 02 dw 211h seg000:002D E8 db 0E8h seg000:002E AD db 0ADh seg000:002F 00 db 0 seg000:0030 BE db 0BEh seg000:0031 BA db 0BAh seg000:0032 02 db 2 seg000:0033 E8 db 0E8h seg000:0034 A7 db 0A7h seg000:0035 00 db 0
    Однако если то же проделать со следующим кодом, то даже после удаления всех перекрестных ссылок он не будет помечен, как undefined. seg000:014C stosb seg000:014D loop loc_0_143 seg000:014F seg000:014F loc_0_14F: ; CODE XREF: seg000:013Bj seg000:014F ; seg000:0146j seg000:014F pop es seg000:0150 pop ds
    DelCodeXref(0x1013B,0x1014F,0);
    DelCodeXref(0x10146,0x1014F,1);
    seg000:014C stosb seg000:014D loop loc_0_143 ;

    seg000:014F seg000:014F loc_0_14F: ;

    seg000:014F pop es seg000:0150 pop ds
    На самом же деле мы удалили не все перекрестные ссылки. IDA поддерживает и при необходимости автоматически создает так называемую ссылку на следующую команду.
    Однако они не отображается явно на экране, но, тем не менее, скрыто присутствует, увеличивая счетчик ссылок на единицу.
    DelCodeXref проверяет значение счетчика, убеждается, что он больше нуля и не преобразует код в undefined.
    Как и любую другую, эту ссылку можно удалить. Но для этого прежде нужно выяснить ее источник и приемник. Приемником, очевидно, будет линейный адрес начала текущей инструкции.

    212
    То есть seg000:0x14F или 0x1014F, а источником линейный адрес начала предыдущей инструкции. В нашем случае это 0x1014D.
    Теперь можно вызвать функцию DelCodeXref и удалить эту перекрестную ссылку.
    DelCodeXref(0x1014F,0x1014D,1);
    Это сработало! Счетчик перекрестных ссылок стал равен нулю, и IDA пометила приемник и нижележащий код, как undefined.
    Выше, при описании функции MakeUndef говорилось, что она удаляет все связанные инструкции. Теперь же, познакомившись, с архитектурой перекрестных ссылок можно уточнить это определение. IDA просто спускается по цепочке перекрестных ссылок и помечает undefined все инструкции на пути своего следования. seg000:014C stosb seg000:014D loop loc_0_143 seg000:014D ; ------------------------------------ seg000:014F unk_0_14F db 7 ; seg000:0150 db 1Fh ; seg000:0151 db 0C7h ; ¦ seg000:0152 db 5 ; seg000:0153 db 29h ; ) seg000:0154 db 0 ; seg000:0155 db 0C7h ; ¦ seg000:0156 db 45h ; E seg000:0157 db 1 ;
    При этом функция возвратит единицу. Это сигнал того, что код успешно преобразован в undefined.
    Операнд
    Пояснения
    From
    Адрес источника перекрестной ссылки
    To
    Адрес приемника перекрестной ссылки
    ==1
    Преобразовывать код в undefined, когда на него не останется ссылок undef
    ==0
    Не преобразовывать код в undefined, когда на него не останется ссылок
    Пояснения
    Return:
    ==1 если код успешно преобразован в undefined
    long Rfirst (long From);
    Функция возвращает линейный адрес приемника первой перекрестной ссылки указанного источника.
    Подробнее о перекрестных ссылках было рассказано в описании функция
    AddCodeXref и DelCodeXref.
    Хотя это не очевидно, источник может иметь несколько перекрестных ссылок.
    Например, когда используется инструкция, наподобие JMP BX.
    Потом не нужно забывать, что практически все инструкции снабжены перекрестными ссылками на линейный адрес начала следующей инструкции.
    Обратите внимание, что если по указанному линейному адресу существует перекрестная ссылка на следующую инструкцию, то функция возвратит именно ее. Не

    213
    смотря на то, что в idc.idc утверждается, что этот тип ссылок доступен Rnext (смотри описание ниже) на самом же деле, Rnext проходя список приемников перекрестных ссылок, игнорирует этот тип.
    Если указан неверный источник, (то есть линейный адрес, не содержащий перекрестных ссылок) или источник перекрестной ссылки данных, то функция возвратит ошибку BADADDR
    Примеры использования: seg000:28C6 pop di ;
    Æ источник seg000:28C7 pop si ;
    Å приемник
    Message(“0x%X \n”,
    Rfirst(0x128C6)
    );
    0x28C7 seg000:28CB retn seg000:28CB sub_0_2847 endp
    Message(“0x%X \n”,
    Rfirst(0x128CB)
    );
    0xFFFFFFFF seg000:2870
    jmp loc_0_2892 ; Æ источник seg000:2870
    ; --------------------------------------- seg000:2872 db 90h
    ; Р
    seg000:2873 db 90h
    ; Р
    seg000:2892 loc_0_2892: ; CODE
    XREF: seg000:2870j seg000:2892 ;
    Å приемник seg000:2892 cmp byte ptr [si], 22h ;
    '"'
    Message(“0x%X \n”,
    Rfirst(0x12870)
    );
    0x12892
    Операнд
    Пояснения
    From
    Линейный адрес источника перекрестной ссылки
    Пояснения
    Return
    Линеный адрес приемника первой перекрестной ссылки
    long Rnext (long From,long current);
    Эта функция возвращает линейный адрес приемника очередной перекрестной

    214
    ссылки в списке. При этом тип перекрестных ссылок, указывающих на следующую инструкцию (ordinary flows) игнорируется и никогда не может быть возращен.
    Для понимания того, как работает данная функция, рекомендуется прочесть описания функций AddCodeXref, DelCodeXref, Rfirst.
    IDA хранит список перекрестных ссылок для каждого источника, отсортированный по адресам приемника. Первыми в нем идут те ссылки, чей линейный адрес приемника наименьший, за ними следующие.
    Напоминаем, что функция игнорирует указатель на следующую инструкцию. Если же она завершилась успешно, то возвратит линейный адрес приемника перекрестной ссылки, следующей на current.
    То есть current должен быть не обязательно точно равен адресу приемника текущей перекрестной ссылки в списке. Он может быть меньше его, но, разумеется, обязательно превосходить адрес приемника предыдущей ссылки.
    Поясним это на примере: seg000:0000 push ax ; CODE XREF: seg000:2864p seg000:0000 ;
    Å приемник seg000:2864 call bx ;
    Æ источник seg000:2869 loc_0_286 ; CODE XREF: seg000:2864p seg000:2869 inc si ;
    Å приемник seg000:2892 loc_0_2892: ; CODE XREF: seg000:2864p seg000:2892 ;
    Å приемник seg000:2892 cmp byte ptr [si], 22h ;
    '"'
    Пусть при изучении программы было определено, что BX может принимать следующие значения – 0x0, 0x2869, 0x2892. В этом случае по линейному адресу seg000:2864 будет расположено три перекрестные ссылки на соответствующие приемники.
    Точнее, их будет даже четыре, с учетом ссылки на следующую инструкцию, но, поскольку Rnext никогда не возвращает ее, то достаточно рассмотреть только выше упомянутые три.
    IDA сформирует по линейному адресу 0x12864 следующий список приемников:
    {0x10000, 0x12869, 0x12892} Вот эти адреса и будут возвращаться при прохождении списка функцией Rnext.
    Не обязательно начинать первый вызов с Rfirst (смотри описание выше). Как уже упоминалось, Rnext хранит указатель на текущую ссылку не во внутренней скрытой переменной, а принимает его как параметр. Таким образом, это дает нам возможность легко манипулировать ее значением, управляя поведением функции.
    Вообще не понятно, зачем понадобилось вводить Rfirst. Ведь первую перекрестную ссылку можно найти с помощью Rnext – и это будет следующая ссылка за нулем.
    Очевидно, что Rnext(0x12864,0) вернет 0x10000 – первую перекрестную ссылку в списке.
    Следовательно, Rnext(X, 0) идентична Rfirst.
    На самом деле тут нас поджидает небольшой сюрприз. Функция Rnext, проходя список, не обнаруживает в нем ссылок на следующую команду. Это не является ошибкой, а документированной особенностью IDA.
    Например: auto a; a=0;

    215
    for (;;)
    { a=Rnext(ScreenEA(),a); if (a==-1) break;
    Message("0x%X \n",a);
    }
    Операнд
    Пояснения
    Form
    Линейный адрес источника списка перекрестных ссылок
    Current
    Текущий адрес
    Пояснения
    Следующий адрес в списке
    Return
    -1 если список исчерпан или отсутствует источник
    1   ...   17   18   19   20   21   22   23   24   ...   39


    написать администратору сайта