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

  • ПЕРЕЧИСЛЕНИЯ ALMA MATER

  • АРХИТЕКТУРА ПЕРЕЧИСЛЕНИЙ

  • GetEnum("enum_1") );0xFF000131 Message("0x%X \n", GetEnum("enum_2") );0xFF000132 Message("0x%X \n", GetEnum("enum_3")

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


    Скачать 2.86 Mb.
    НазваниеОписание функций встроенного языка
    Анкорobraz_mihlenia_-_dizassembler_IDA
    Дата29.09.2022
    Размер2.86 Mb.
    Формат файлаpdf
    Имя файлаobraz_mihlenia_-_dizassembler_IDA.pdf
    ТипСправочник
    #704305
    страница27 из 39
    1   ...   23   24   25   26   27   28   29   30   ...   39

    long SetMemberType(long id,long member_offset,long flag,long typeid,long nitems);
    Функция позволяет изменять тип члена структуры. Он определяется флагом flag следующим образом:
    Определение
    Значение
    Пояснения
    FF_BYTE 0x00000000L
    Байт
    FF_WORD 0x10000000L
    Слово
    FF_DWRD 0x20000000L
    Двойное слово
    FF_QWRD 0x30000000L
    Четвертное слово
    FF_TBYT 0x40000000L
    Восьмерное слово
    FF_ASCI 0x50000000L
    ASCII строка
    FF_STRU 0x60000000L
    Структура
    FF_RESERVED 0x70000000L
    Зарезервировано
    FF_FLOAT 0x80000000L
    Float
    FF_DOUBLE 0x90000000L
    Double
    FF_PACKREAL
    0xA0000000L
    Packed decimal real
    FF_ALIGN
    0xB0000000L
    Директива выравнения
    В зависимости от состояния флага, значение аргумента typeid может трактоваться по-разному.
    Состояние flag
    Значение typeid
    FF_STRU
    ID структуры
    FF_ASCII
    Тип ASCII строки (см. таблицу ниже)
    Другое
    BADADDR
    Обратите внимание, что если новый член структуры не представляет собой ни вложенную структуру, ни ASCII строку, то аргумент typeid должен быть равен BADADDR
    Определение
    Значение
    Пояснения

    278
    ASCSTR_C
    ASCSTR_TERMCHR
    C-style ASCII string
    ASCSTR_TERMCHR 0
    Character-terminated
    ASCII string
    ASCSTR_PASCAL 1
    Pascal-style ASCII string (length byte)
    ASCSTR_LEN2 2
    Pascal-style, length has 2 bytes
    ASCSTR_UNICODE 3
    Unicode string
    ASCSTR_LEN4 4
    Pascal-style, length has 4 bytes
    При этом необходимо, что бы для нового члена хватало места. Если его размер превосходит предыдущий, а следующие за ним смещения принадлежат остальным членам, то тип члена не будет изменен
    Пример:
    0000 MY_STRUC struc ; (sizeof=0x9)
    0000 field_0 dw ?
    0002 field_2 dw ?
    0004 field_4 dw ?
    0006 field_6 dw ?
    0008 MyGoodMember db ?
    0009 MY_STRUC ends
    0009
    Message("0x%X \n",
    SetMemberType(
    GetStrucIdByName("MY_STRUC"),
    2,
    FF_DWRD,
    -1,
    4));
    0000 MY_STRUC struc ; (sizeof=0x9)
    0000 field_0 dw ?
    0002 field_2 dw ?
    0004 field_4 dw ?
    0006 field_6 dw ?
    0008 MyGoodMember db ?
    0009 MY_STRUC ends
    0009 0x0
    Напротив, если новый член занимает места меньше чем старый, то преобразование происходит без проблем, а «лишние» байты помечаются, как неопределенные.
    Например:
    0000 MY_STRUC struc ; (sizeof=0x9)
    0000 field_0 dw ?
    0002 field_2 dw ?
    0004 field_4 dw ?
    0006 field_6 dw ?
    0008 MyGoodMember db ?

    279 0009 MY_STRUC ends
    0009
    Message("0x%X \n",
    SetMemberType(
    GetStrucIdByName("MY_STRUC"),
    2,
    FF_BYTE,
    -1,
    1))
    0000 MY_STRUC struc ; (sizeof=0x9)
    0000 field_0 dw ?
    0002 field_2 db ?
    0003 db ? ; undefined
    0004 field_4 dw ?
    0006 field_6 dw ?
    0008 MyGoodMember db ?
    0009 MY_STRUC ends
    Операнд Пояснения id Идентификатор (ID) структуры name Имя структуры
    ==offset
    Значение
    !=BADADDR
    Смещение нового члена структуры
    Offset
    ==BADADDR
    Добавить новый член в конец flag Новый тип члена typeid Идентификатор структуры или тип ASCII-строки
    Nbytes Размер нового члена в байтах
    ==return Пояснения
    ==1
    Успешное завершение
    Return
    ==0
    Ошибка (см коды завершения выше)
    long SetMemberComment(long id,long member_offset,char comment,long repeatable);
    Функция устанавливает комментарий, связанный с членом структуры. IDA поддерживает два типа комментариев – ‘regular’ и ‘repeatable’. Последний отличается тем, что дублируется по месту обращения к элементу обращения структуры. Однако в случае со структурами и их членами, IDA игнорирует это требование, в чем убеждает следующий пример:
    0000 MyStruc struc ; (sizeof=0x4) ; XREF: seg000:0F72r
    0000 field_0 dw ? ;
    My Repeatable comment
    0002 field_1 dw ? ;
    0004 MyStruc ends seg000:0F72*stru_0_F72 dw 0 ; field_0
    ; DATA XREF: sub_0_F56r seg000:0F72* ; sub_0_2456+1Cw ... seg000:0F72* dw 0 ; field_1 seg000:0F56 mov es, stru_0_F72.
    field_0
    seg000:0F5A assume es:nothing seg000:0F5A xor bx, bx

    280
    Остается только надеяться, что в будущем рано или поздно такая поддержка появится.
    Операнд
    Пояснения id Идентификатор (ID) структуры comment
    Комментарий члена member_offset
    Смещение, лежащее в границах интересующего нас элемента
    Флаг
    Пояснения
    0
    Неповторяемый комментарий
    Repeatable
    1
    Повторяемый комментарий
    ==return Пояснения
    ==1
    Успешное завершение
    Return
    ==0
    Ошибка (см коды завершения выше)
    ПЕРЕЧИСЛЕНИЯ
    ALMA MATER
    Организация перечислений очень близка к организации структур, поэтому рекомендуется ознакомиться с главой «структуры», - что бы не повторяться многие моменты при описании перечислений будут опущены, если они ничем не отличаются от описанных выше.
    Прежде всего, – что же такое перечисления? Грубо говоря, – это константы, то есть предопределенные символьные значения, которые в ходе ассемблирования заменяются действительными значениями.
    Использования непосредственных значений – дурной тон программирования. Как, например, на счет следующего кода:
    PUSH
    10
    PUSH
    02
    CALL GotoXY
    PUSH offset ProgramName
    CALL WriteLn
    Как нетрудно догадаться, числа 10 и 2 представляют собой экранные координаты, в которых будет выведено имя программы. Впрочем, если вы не автор этого фрагмента кода, то догадаться может быть вовсе не так просто, да и кроме того, что делать если придется переписывать программу для работы с другим экранным разрешением?
    Просматривать весь код на предмет поиска всех, относящихся к экранным координатам констант?
    Вот для этого в ассемблерах и появилась директива EQU, которая позволяла определить «говорящие» константы, которые не только повышали информативность листинга и заменяли комментарии. Но позволяла легко модифицировать их, – ведь теперь непосредственное значение указывалось только в одной точке.
    Разумеется, IDA поддерживает константы. Но делает не так, как это можно ожидать. Если все ассемблеры поддерживают исключительно глобальные списки констант, что часто вызывает путаницу, то IDA умеет «разбивать» их на отдельные кучки – каждая под своей «крышей»
    Внешне список констант напоминает структуру. Взгляните, в самом деле это очень похоже:
    ; enum enum_1 enum_1_0 = 3 enum_1_4 = 5

    281
    ; ------------------------
    ; enum enum_3 enum_3_14E = 1 enum_3_0 = 2Ch enum_3_2D = 14Dh
    Однако, в отличие от структуры элементы перечисления не имеют ни типа, ни размера. Точнее тип определяется только на стадии ассемблирования.
    Так, например, если enum_1_0 равен трем, это еще не означает, что он имеет тип байт. Вполне вероятно, что он окажется словом или даже и словом и байтом одновременно, например:
    MOV AL, enum_1_0
    CMP AX, enum_1_0
    Этот код, не смотря на всю его чудаковатость, все же будет успешно ассемблирован!
    Но если нет типов, и не возможно вычислить размер членов, то как же тогда осуществить к ним доступ?
    Теоретически было можно условиться, что каждый член занимает 32 байта
    (двойное слово) и организовать к ним доступ точно так, как и в структурах. И это бы неплохо работало!
    Но разработчик IDA пошел по другому пути - он связал каждый член с идентификатором! Разумеется, существует функция, возвращающая идентификатор по имени функции и наоборот.
    В свете этого становиться еще более непонятым, какой смысл имеет «группировка» перечислений. Имена членов – глобальные, идентификаторы – тем более. Что же дает принадлежность элемента к той или иной группе?
    В каждой группе может существовать не более одной константы с одним и тем же
    значением. С первого взгляда не понятно ни как можно «жить» с этим, ни какие мотивы побудили принять разработчика такое нелепое ограничение.
    Однако, на самом деле это следствия выбранной архитектуры. И весьма удачной, стоит только взглянуть на нее изнутри, чем мы сейчас и займемся.

    282
    АРХИТЕКТУРА ПЕРЕЧИСЛЕНИЙ
    Прежде чем углубляться в технические дебри реализации и архитектуры перечислений, зададимся простым вопросом, - что же по сути представляют собой члены перечислений?
    Разумеется, это операнды, или еще точнее иная форма представления непосредственных операндов. В главе, посвященной объективной модели IDA уже отмечалось, что один и тот же операнд может быть по-разному отображен на экране дизассемблера. Он может быть не только непосредственным значением, но и смещением, например.
    Однако, перечисления – это не просто иная форма отображения операнда на экране – с точки зрения IDA это элемент bTree, который может ссылаться на линейный адрес, объекта… впрочем, не стоит повторяться, об этом уже писалось выше.
    Но если каждый сегмент (имя, комментарий, функция) связан только с одним линейным адресом, то одно и то же перечисление может повторяться в десятке разных мест! И поэтому старые методы для него не подходят!
    Поэтому был использован тот же механизм, который был создан для поддержки структур. Каждый объект ссылался на тег структуры, а операнд указывал на требуемый элемент внутри ее.
    Точно то же происходит и с перечислениями. Есть список перечислений, на который ссылается объект. Элементы списка просматриваются до тех пор, пока не найдется элемент совпадающий по значению с операндом, объекта.
    Обратите внимание еще раз на тот факт, что и структура и перечисление связываются не с операндом, а с обладающим им объектом, а точнее линейным адресом его начала.
    Представление операнда в виде члена структуры или перечисление происходит на втором этапе, – и жесткой связки тут нет, простой поиск на совпадение значений.
    Но если в структуре смещение каждого члена уникально, то есть никакие два члена не могут быть расположены по одному и тому же смещению, то в перечислениях два разных элемента могут иметь одно и то же значение.
    Вот, собственно и ответ на вопрос о необходимости поддержки более чем одного списка перечислений, а заодно и тактика группировки элементов. То есть главным критерием должно быть не родственность каких-то признаков, а гарантия непопадающих значений.
    При этом разумно стремиться к уменьшению числа списков, поскольку, как уже говорилось выше, для представления операнда в виде перечисления достаточно сослаться на список, и IDA самостоятельно подберет нужный элемент!
    В идеале, если у нас всего один список (что бывает достаточно часто) необходимо перевести курсор на нужную строку и нажать , как IDA все сделает автоматически.
    Программная работа, в отличие от интерактивной, несколько сложнее. Кроме того, теги списков (это не теги, конечно, но иного названия просто нет, - поэтому будет считать, что это как бы теги) вообще практически не фигурируют.
    Действительно, все члены связаны с уникальными глобальными идентификаторами, да и имена каждого из них не менее уникальны.
    МЕТОДЫ
    Функция
    Назначение long GetEnumQty(void)
    Возвращает число типов перечислений long GetnEnum(long idx)
    Возвращает идентификатор перечисления по ее индексу long GetEnumIdx(long enum_id);
    Возвращает индекс перечисления по его

    283
    идентификатору long GetEnum(char name)
    Возвращает идентификатор перечисления по его имени char GetEnumName(long enum_id)
    Возвращает имя перечисления по его идентификатору char GetEnumCmt(long enum_id,long repeatable
    Возвращает комментарий перечисления long GetEnumSize(long enum_id)
    Возвращает число членов перечисления long GetEnumFlag(long enum_id)
    Возвращает флаги, определяющие представление элементов перечисления long GetConstByName(char name)
    Возвращает идентификатор константы по ее имени long GetConstValue(long const_id)
    Возвращает значение константы по ее идентификатору char GetConstName(long const_id)
    Возвращает имя константы по ее идентификатору char GetConstName(long const_id)
    Возвращает комментарий константы по ее идентификатору long AddEnum(long idx,char name,long flag)
    Добавляет новое перечисление void DelEnum(long enum_id)
    Удаляет перечисление success SetEnumIdx(long enum_id,long idx)
    Задает индекс перечисления в списке
    long GetEnumQty(void);
    Функция возвращает число типов перечислений. Все они могут быть отображены вызовом списка командой меню

    View \ Enumeration’s
    FFFFFFFF ; enum enum_1
    FFFFFFFF enum_1_0 = 1
    FFFFFFFF enum_1_2 = 2
    FFFFFFFF
    FFFFFFFF ; ----------------------------
    FFFFFFFF
    FFFFFFFF ; enum enum_2
    FFFFFFFF enum_2_0 = 16h
    FFFFFFFF

    284
    Message(“0x%X \n”,
    GetEnumQty()
    );
    0x2
    ==return
    Пояснения
    !=0
    Число перечислений
    Return
    ==0
    Нет ни одного перечисления
    long GetnEnum(long idx);
    Функция возвращает ID перечисления по индексу. Как уже отмечалось выше, индекс не может точно идентифицировать связанное с ним перечисление, поскольку при любых операциях связанных с дополнением или удалением перечислений, список перестраивается, и тот же индекс уже может указывать совсем на другое перечисление.
    В отличие от этого, идентификатор (ID) перечисления представляет собой уникальное 32-битное значение, всегда указывающие на одно и ту же перечисление. Более того, даже если перечисление, связанное с конкретным идентификатором, было удалено, гарантируется, что тот же идентификатор не будет выдан ни одному созданному после этого перечислению.
    Это гарантирует непротиворечивость ситуации и позволяет совместно использовать один и тот же идентификатор различным скриптам.
    Пример использования:
    FFFFFFFF enum_1_0 = 1
    FFFFFFFF enum_1_2 = 2
    FFFFFFFF
    FFFFFFFF ; -----------------------------
    FFFFFFFF
    FFFFFFFF ; enum enum_2
    FFFFFFFF enum_2_0 = 16h auto a; for(a=0;aMessage(“0x%X 0x%X \n”, a,GetEnumId(a)
    );
    0x0 0xFF0000F0 0x1 0xFF0000FE
    Идентификатор, как и дескриптор, с точки зрения пользователя являются абстрактным «магическим» числом, интерпретировать которое допускается только операционной системе (в качестве которой выступает в данном случае IDA).
    Операнд Пояснения index Индекс перечисления в списке (от нуля до GetEnumQty()-1)
    Return
    ==return Пояснения

    285
    !=BADADDR
    Идентификатор (ID) перечисления
    ==BADADDR
    Ошибка
    long GetEnumIdx(long enum_id);
    Функция возвращает индекс перечисления по ее идентификатору. Необходимо помнить, что индексы не связаны жестко с перечислениями и при каждой операции удаления или добавления новых перечислений тем же индексам уже могут соответствовать новые перечисления.
    Пример использования:
    FFFFFFFF ; enum enum_1
    FFFFFFFF enum_1_0 = 1
    FFFFFFFF enum_1_2 = 2
    FFFFFFFF
    FFFFFFFF ; -----------------------
    FFFFFFFF
    FFFFFFFF ; enum enum_2
    FFFFFFFF enum_2_0 = 16h
    Message("0x%X \n",
    GetEnumIdx(
    GetEnum("enum_1")
    )
    );
    0x0
    Message("0x%X \n",
    GetEnumIdx(
    GetEnum("enum_2")
    )
    );
    0x1
    Операнд Пояснения
    ID Идентификатор перечисления
    ==return Пояснения
    !=BADADDR
    Индекс перечисления
    Return
    ==BADADDR
    Ошибка
    long GetEnum(char name);
    Функция возвращает идентификатор перечисления по его имени. Если перечисления с указанным именем не существует, то функция возвращает ошибку –
    BADADDR.
    Пример использования:
    FFFFFFFF enum_1_0 = 1
    FFFFFFFF enum_1_2 = 2

    286
    FFFFFFFF
    FFFFFFFF ; ------------------------
    FFFFFFFF
    FFFFFFFF ; enum enum_2
    FFFFFFFF enum_2_0 = 16h
    Message("0x%X \n",
    GetEnum("enum_1")
    );
    0xFF000131
    Message("0x%X \n",
    GetEnum("enum_2")
    );
    0xFF000132
    Message("0x%X \n",
    GetEnum("enum_3")
    );
    0xFFFFFFFF
    Операнд Пояснения name Имя перечисления
    ==return Пояснения
    !=BADADDR
    Идентификатор перечисления
    Return
    ==BADADDR
    Ошибка
    char GetEnumName(long enum_id);
    Функция возвращает имя перечисления по его идентификатору. Если указанному идентификатору не соответствует ни одно перечисление функция возвращает пустую строку.
    Например:
    FFFFFFFF enum_1_0 = 1
    FFFFFFFF enum_1_2 = 2
    FFFFFFFF
    FFFFFFFF ; ----------------------------
    FFFFFFFF
    FFFFFFFF ; enum enum_2
    FFFFFFFF enum_2_0 = 16h
    Message("%s \n",
    GetEnumName(
    GetnEnum(1)
    )
    );
    enum_2

    287
    Операнд Пояснения
    Enum_id ID перечисления
    ==return Пояснения
    !=””
    Имя перечисления
    Return
    ==””
    Ошибка
    char GetEnumCmt(long enum_id,long repeatable)
    Возвращает комментарий перечисления, заданного идентификатором.
    Комментарии бывают двух типов – постоянные и повторяемые. Постоянные отображаются только впереди перечисления, а повторяемые при обращении к каждому из его членов.
    FFFFFFFF ;
    My Enum regulag commnet
    FFFFFFFF ; enum enum_1
    FFFFFFFF enum_1_0 = 1
    FFFFFFFF enum_1_2 = 2 seg000:0046 rol bx, enum_1_0
    Message(“%s \n”,
    GetEnumCmt(
    GetEnum(“enum_1”),
    0);
    My Enum regulag commnet
    FFFFFFFF ; My Enum repeatable commnet
    FFFFFFFF ; enum enum_1
    FFFFFFFF enum_1_0 = 1
    FFFFFFFF enum_1_2 = 2 seg000:0046 rol bx, enum_1_0 ;
    My Enum
    Repeatable commnet
    Message(“%s \n”,
    GetEnumCmt(
    GetEnum(“enum_1”),
    1);
    My Enum Repeatable commnet
    Операнд
    Пояснения id Идентификатор (ID) перечисления
    Флаг
    Пояснения
    0
    Неповторяемый комментарий
    Repeatable
    1
    Повторяемый комментарий
    Завершение
    Пояснения
    !=””
    Комментарий
    Return
    “”
    Ошибка

    288
    long GetEnumSize(long enum_id);
    Функция возвращает число членов перечисления, заданного идентификатором.
    Обратите внимание, именно число элементов, а не занимаемый ими размер, который вообще вычислить невозможно, поскольку члены перечисления не имеют типа.
    Пример:
    FFFFFFFF ; enum enum_1
    FFFFFFFF enum_1_0 = 1
    FFFFFFFF enum_1_2 = 2
    FFFFFFFF
    Message("0x%X \n",
    GetEnumSize(
    GetEnum("enum_1")
    )
    );
    0x2
    Если перечисление пусто, то функция возвращает ноль, но то же значение возвращается, если указать неверный идентификатор, поэтому возникает неоднозначная ситуация – либо перечисление отсутствует (было удалено?) либо же попросту пусто.
    Пример:
    FFFFFFFF ; enum enum_2
    Message("0x%X \n",
    GetEnumSize(
    GetEnum("enum_2")
    )
    );
    0x0
    Message("0x%X \n",
    GetEnumSize(BADADDR)
    );
    0x0
    Операнд Пояснения
    Enum_id Идентификатор перечисления
    ==return Пояснения
    !=0
    Число членов перечисления
    Пустое перечисление
    Return
    ==0
    Ошибка

    289
    1   ...   23   24   25   26   27   28   29   30   ...   39


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