long GetEnumFlag(long enum_id);
Функция возвращает флаги, определяющие представление членов перечисления, заданного идентификатором.
Возможные значения перечислены ниже в таблице:
FF_0NUMH
0x00100000 шестнадцатеричное представление первого операнда
FF_0NUMD
0x00200000 десятичное представление первого операнда
FF_0CHAR
0x00300000 символьное представление первого операнда
FF_0SEG
0x00400000 первый операнд – сегмент
FF_0OFF
0x00500000 первый операнд – смещение
FF_0NUMB
0x00600000
Представление первого операнда в бинарном виде
FF_0NUMO
0x00700000
Представление первого операнда в восьмеричном виде
FF_0ENUM
0x00800000
Представление первого операнда в виде перечисления
FF_0FOP
0x00900000
Принудительный первый операнд
FF_0STRO
0x00A00000
Представление первого операнда как смещения в структуре
FF_0STK
0x00B00000 первый операнд стековая переменная
FF_1VOID
0x00000000 тип второго операнда Void
FF_1NUMH
0x00100000
Шестнадцатеричное представление второго операнда
FF_1NUMD
0x00200000 десятичное представление второго операнда
FF_1CHAR
0x00300000 символьное представление второго операнда
FF_1SEG
0x00400000 второй операнд – сегмент
FF_1OFF
0x00500000 второй операнд – смещение
FF_1NUMB
0x00600000
Представление второго операнда в бинарном виде
FF_1NUMO
0x00700000
Представление второго операнда в восьмеричном виде
FF_1ENUM
0x00800000
Представление второго операнда в виде перечисления
FF_1FOP
0x00900000
Принудительный второй операнд
FF_1STRO
0x00A00000
Представление второго операнда как смещения в структуре
FF_1STK
0x00B00000 второй операнд стековая переменная
Пример:
FFFFFFFF ; enum enum_1
FFFFFFFF enum_1_0 = 1
FFFFFFFF enum_1_2 = 2
FFFFFFFF
Message("0x%X \n",
GetEnumFlag(
GetEnum("enum_1")
);
0x1100000
Операнд Пояснения
Enum_id Идентификатор перечисления
==return Пояснения
!=0
Флаг отображения членов перечисления
Return
==0
Ошибка
290
long GetConstByName(char name);
Функция возвращает идентификатор константы по ее имени. Все перечисления разделяют общее пространство имен, другими словами одно и то же имя не может быть повторено дважды, поэтому является уникальным.
Например:
FFFFFFFF enum_1_0 = 1
FFFFFFFF enum_1_2 = 2
FFFFFFFF
FFFFFFFF ; ---------------------------
FFFFFFFF
FFFFFFFF ; enum enum_2
FFFFFFFF MyEnum = 16h
Message("0x%X \n",
GetConstByName("MyEnum")
);
0xFF000136
Идентификатор обеспечивает доступ к константе. Что бы, например, получить ее значение необходимо воспользоваться функцией long GetConstValue(long const_id), которая описана ниже.
Операнд Пояснения name Имя константы
==return Пояснения
!=0
Идентификатор константы
Return
==0
Ошибка
long GetConstValue(long const_id);
Функция возвращает значение константы по ее идентификатору или ноль в результате ошибки. Поэтому часто возникает неопределенность, – то ли действительно имела место ошибка (например, был указан несуществующий идентификатор) или же просто константа имеет такое значение.
Пример использования:
FFFFFFFF enum_1_0 = 1
FFFFFFFF enum_1_2 = 2
FFFFFFFF
FFFFFFFF ; ---------------------------
FFFFFFFF
FFFFFFFF ; enum enum_2
FFFFFFFF MyEnum = 16h
Message("0x%X \n",
GetConstValue(
GetConstByName("MyEnum")
)
);
0x16
291
Операнд Пояснения
Const_id Идентификатор константы
==return Пояснения
!=0
Значение константы
Ошибка
Return
==0
Значение константы
char GetConstName(long const_id); Функция возвращает имя константы, заданной идентификатором. Если идентификатор указан неправильно, то возвращается пустая строка
Например:
FFFFFFFF ; enum enum_1
FFFFFFFF enum_1_0 = 1
FFFFFFFF enum_1_2 = 2
FFFFFFFF
FFFFFFFF ; -----------------------------
FFFFFFFF
FFFFFFFF ; enum enum_2
FFFFFFFF MyEnum = 16h
FFFFFFFF
Message("%s \n",
GetConstName(
GetConstByName("MyEnum")
)
);
MyEnum
Операнд Пояснения
Const_id ID константы
==return Пояснения
!=””
Имя константы
Return
==””
Ошибка
char GetConstCmt(long const_id,long repeatable); Возвращает
комментарий константы, заданной идентификатором. Комментарии бывают двух типов – постоянные и повторяемые. Постоянные отображаются только справа от константы, а повторяемые при каждом обращении к ней.
FFFFFFFF ;
FFFFFFFF ; FFFFFFFF enum_1_0 = 1 ;
My regulag commnet
FFFFFFFF enum_1_2 = 2 seg000:0046 rol bx, enum_1_0
Message(“%s \n”,
GetConstCmt(
292
GetConstByName("enum_1_0"),
0);
My regulag commnet
FFFFFFFF
FFFFFFFF ; enum enum_1
FFFFFFFF enum_1_0 = 1 ; My Enum repeatable commnet
FFFFFFFF enum_1_2 = 2 seg000:0046 rol bx, enum_1_0 ;
My
Repeatable commnet
Message(“%s \n”,
GetConstCmt(
GetConstByName("enum_1_0"),
1);
My Repeatable commnet
Операнд
Пояснения id Идентификатор (ID) константы
Флаг
Пояснения
0
Неповторяемый комментарий
Repeatable
1
Повторяемый комментарий
Завершение
Пояснения
!=””
Комментарий
Return
“”
Ошибка
long AddEnum(long idx,char name,long flag);
Функция добавляет новое перечисление. . Для этого необходимо указать его имя
(которое впоследствии может быть изменено) и тип представления констант в перечислении.
Индекс задает положение перечисления в списке. Если он равен BADADDR, то новое перечисление будет добавлено в конец списка, иначе же старое перечисление будет затерто! Подробнее об этом рассказано в описании функции AddStrucEx
Флаг определяет представление констант в перечислении. Может принимать значения, перечисленные ниже в таблице:
FF_0NUMH
0x00100000 шестнадцатеричное представление первого операнда
FF_0NUMD
0x00200000 десятичное представление первого операнда
FF_0CHAR
0x00300000 символьное представление первого операнда
FF_0SEG
0x00400000 первый операнд – сегмент
FF_0OFF
0x00500000 первый операнд – смещение
FF_0NUMB
0x00600000
Представление первого операнда в бинарном виде
FF_0NUMO
0x00700000
Представление первого операнда в восьмеричном виде
FF_0ENUM
0x00800000
Представление первого операнда в виде перечисления
293
FF_0FOP
0x00900000
Принудительный первый операнд
FF_0STRO
0x00A00000
Представление первого операнда как смещения в структуре
FF_0STK
0x00B00000 первый операнд стековая переменная
FF_1VOID
0x00000000 тип второго операнда Void
FF_1NUMH
0x00100000
Шестнадцатеричное представление второго операнда
FF_1NUMD
0x00200000 десятичное представление второго операнда
FF_1CHAR
0x00300000 символьное представление второго операнда
FF_1SEG
0x00400000 второй операнд – сегмент
FF_1OFF
0x00500000 второй операнд – смещение
FF_1NUMB
0x00600000
Представление второго операнда в бинарном виде
FF_1NUMO
0x00700000
Представление второго операнда в восьмеричном виде
FF_1ENUM
0x00800000
Представление второго операнда в виде перечисления
FF_1FOP
0x00900000
Принудительный второй операнд
FF_1STRO
0x00A00000
Представление второго операнда как смещения в структуре
FF_1STK
0x00B00000 второй операнд стековая переменная
Пример использования:
FFFFFFFF enum_1_0 = 1
FFFFFFFF enum_1_2 = 2
AddEnum(-1,”MyNewEnum”,0);
FFFFFFFF enum_1_0 = 1
FFFFFFFF enum_1_2 = 2
FFFFFFFF
FFFFFFFF ; --------------------------
FFFFFFFF
FFFFFFFF ; enum MyNewEnum
Операнд
Пояснения
==index
Действие
[0,MaxIdx]
Индекс перечисления (старое перечисление при этом будет затерто)
MaxIdx+1
Индекс нового перечисления index
BADADDR
Индекс нового перечисления name
Имя перечисления
Завершение
Пояснения
!=BADADDR
Идентификатор перечисления
Return
==BADADDR
Ошибка
Интерактивно структуру добавить можно, вызвав список командой меню View \
Structures и нажав клавишу
294
void DelEnum(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 MyEnum = 16h
FFFFFFFF
DelEnum(
GetEnum("enum_2")
);
FFFFFFFF ; enum enum_1
FFFFFFFF enum_1_0 = 1
295
FFFFFFFF enum_1_2 = 2
FFFFFFFF
Операнд Пояснения
Enum_id Идентификатор перечисления
Интерактивно перечисление можно удалить, установив курсор на любой его элемент и нажав клавишу
success SetEnumIdx(long enum_id,long idx);
Функция позволяет изменять индекс перечисления в списке. При этом перечисления меняются местами, и затирания не происходит.
Например:
FFFFFFFF ; enum enum_1
FFFFFFFF enum_1_0 = 1
FFFFFFFF enum_1_2 = 2
FFFFFFFF
FFFFFFFF ; ---------------------------
FFFFFFFF
FFFFFFFF ; enum MyNewEnum
FFFFFFFF MyNewEnum_0 = 0
FFFFFFFF
FFFFFFFF ; ---------------------------
FFFFFFFF
FFFFFFFF ; enum enum_9
FFFFFFFF enum_9_0 = 0
SetEnumIdx(
GetEnum("enum_1"),1
);
FFFFFFFF ; enum MyNewEnum
FFFFFFFF MyNewEnum_0 = 0
FFFFFFFF
FFFFFFFF ; ---------------------------------
FFFFFFFF
FFFFFFFF ; enum enum_1
FFFFFFFF enum_1_0 = 1
FFFFFFFF enum_1_2 = 2
FFFFFFFF
FFFFFFFF ; ---------------------------------
FFFFFFFF
FFFFFFFF ; enum enum_9
FFFFFFFF enum_9_0 = 0
FFFFFFFF
Операнд Пояснения id Идентификатор (ID) перечисления
Return
==return Пояснения
296
==1
Успешное завершение
==0
Ошибка
FIXUP ALMA MATER Более привычным синонимом fixup вероятно, окажется термин «перемещаемые элементы».
Что это такое? Как можно судить из названия, это относительные адреса, обеспечивающие портабельность кода, то есть независимость от базового адреса загрузки.
Поскольку IDA эмулирует загрузку файла в собственное адресное пространство и даже трассирует его выполнение, то она должна поддерживать и перемещаемые элементы.
Покажем это на небольшом примере, MS-DOS exe файла.
Просмотр с помощью HIEW
00000200: B80100 mov ax
,
0000100000203: 8ED8 mov ds,ax
00000205: B409 mov ah,009 ;"
00000207: BA0000 mov dx,00000 0000020A: CD21 int 021
Просмотр с помощью IDA seg000:0000 start proc near seg000:0000 mov ax,
1001hseg000:0003 mov ds, ax seg000:0005 assume ds:dseg seg000:0005 mov ah, 9 seg000:0007 mov dx, 0 seg000:000A int 21h
Что грузиться в регистр AX? С виду непосредственное значение. Однако, это не так. Если приглядеться, то можно увидеть, что дальше оно помещается в регистр DS и, следовательно, скорее всего указывает на сегмент данных программы.
То есть 0x1 это адрес сегмента данных выраженный в параграфах. Знакомым с архитектурой IBM PC может показаться, с чего бы это вдруг он казался расположенным глубоко в таблице векторов прерываний. Но ничего странного нет. И сегмент данных расположен вовсе не там, где можно было бы подумать.
Ведь это
относительный адрес. Резанный вопрос относительный
чего? В exe файлах от отсчитывается от адреса загрузки первого байта, расположенного за заголовком файла.
По умолчанию IDA загружает exe файлы по адресу 0x10000. Следовательно, считая в параграфах, 0x1000+0x1 == 0x1001, как видим, результат совпадает с тем, что отобразила IDA.
Вот это и понимается под поддержкой перемещаемых элементов. Остается только ответить на вопрос, откуда IDA узнала, как следует трактовать этот непосредственный операнд? Эвристическим анализатором? Нет, конечно. Она поступила точно так же, как и
операционная система на ее месте, - просто прочитала заголовок файла.
00000000: 4D 5A 2C 00-02 00
02 00-20 00 00 00-FF FF 00 00 MZ, __
297 00000010: 00 00 00 00-00 00 00 00-3E 00 00 00-01 00 FB 71 > _q
00000020: 6A 72 00 00-00 00 00 00-00 00 00 00-00 00 00 00 jr
00000030: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 01 00 00000040:
00 00 0D 00-00 00 00 00-00 00 00 00-00 00 00 00
Файлы типа OLD EXE имеют очень простую структуру, реализующую поддержку перемещаемых элементов. В таблице, состоящей из двойных слов, перечисляются линейные адреса, указывающие на перемещаемые элементы, - то есть относительные адреса, каждый из которых представляет собой слово, ссылающееся на сегмент (адрес в параграфах).
Таким образом, IDA остается только выполнить простое арифметическое сложение. Впрочем, существуют и более запутанные форматы. Так, например, все win32 файлы, поддерживающие динамическое связывание, или говоря проще, возможность вызова функций чужих DLL вынуждены иметь похожие структуры, – ведь адреса вызываемых функций не известны на этапе линковки программы и могут быть вычислены только после загрузки файла в память.
Если же обратиться к другим платформам, а не замыкаться на серии Intel 80x86, то мы столкнемся с феейверком самых разных технических решений от которого может быстро зарябить в глазах.
Каким же образом IDA может поддерживать все это одним махом? Ведь перемещаемыми элементами управляют меньше десяти функций.
Действительно, если абстрагироваться от вариаций технических реализаций и сосредоточиться на природе перемещаемых элементов, то можно с удивлением обнаружить, что в ее основы могут быть сформулированы всего одной фразой.
Вот этот операнд ссылается туда. И все!
Этого достаточно, что бы обеспечить нормальную функциональность и работоспособность!
Какой конкретно элемент и куда ссылается, вычисляют специальные модули, отвечающие за загрузку файла определенного формата. Ядро IDA такие проблемы не волнуют.
Поэтому фактически, поддержка перемещаемых элементов обеспечивается не IDA, а внешними модулями, к которым у пользователя программного доступа из языка скриптов
нет.
Другими словами, перемещаемыми элементами пользователь не управляет. Да, конечно, он может посмотреть все существующие перемещаемые элементы и даже их скорректировать, но нужно ли это?
Большинство, использующих IDA, этой возможности ни когда в своей жизни не использовали (ну, может быть, разве что из любопытства). И это правильно.
Правильно, потому что IDA и сама неплохо справляется с поставленной задачей.
Поддержка перемещаемых элементов это не та область, что требует внимания со стороны пользователя.
Впрочем, из этого правила все же есть исключения. Если некоторая ну очень хитрая программа имеет свой загрузчик (или чаще – интерпретируемый код), который работает не стандартно и стало быть IDA его не поддерживает.
Немного поразмыслив, сюда же можно отнести и некоторые случаи самомодифицирующегося кода. Ведь поддержка перемещаемых элементов лежит на самом низком уровне иерархии IDA – другими словами «исправляется» виртуальная память, поэтому это работает не только с операндами, но и с кодом, то есть влияет на дизассемблирование инструкций.
Основная трудность описания перемещаемых элементов в объяснении их типов. А они то же разными бывают. Причем большая часть существует только на других платформах и совершенно чужда пользователям PC с Windows и Pentium. А поэтому описывать их подробно в этой книге совершенно бессмысленно.
Для этого планируется выпустить специально приложение, рассказывающие об особенностях использования IDA на других платформах.
Поэтому ниже на типе перемещаемых элементах внимание акцентироваться не будет.
298
МЕТОДЫ
Функция
Назначение long GetNextFixupEA(long ea)
Возвращает линейный адрес следующего перемещаемого элемента long GetPrevFixupEA(long ea)
Возвращает линейный адрес предыдущего перемещаемого элемента long GetFixupTgtType(long ea)
Тип перемещаемого элемента long GetFixupTgtSel(long ea)
Возвращает селектор перемещаемого элемента long GetFixupTgtOff(long ea)
Возвращает смещение перемещаемого элемента void SetFixup(long ea,long type,long targetsel,long targetoff,long displ)
Добавляет новый перемещаемый элемент void DelFixup(long ea)
Функция удаляет перемещаемый элемент
long GetNextFixupEA(long ea);
Возвращает линейный адрес следующего перемещаемого элемента. Обратите внимание, что эта функция действительно возвращает адрес перемещаемого элемента, а не адрес начала содержащей его инструкции.
Например: dseg:0000 public start dseg:0000 start proc near dseg:0000 B8 00 10
mov ax, seg dseg dseg:0003 8E D8 mov ds, ax
Message(“0x%X \n”,
GetNextFixupEA(0)
);
0x1001
Эмулятор загрузки инициализировал перемещаемый элемент необходимым значением, указывающим на адрес сегмента в виртуальной памяти. В нашем случае он равен 0x10.
Операнд
Пояснения ea
Линейный адрес
Завершение
Пояснения
!=BADADDR
Успешно
Return
==BADADDR
Ошибка
299
long GetPrevFixupEA(long ea);
Возвращает предыдущий адрес следующего перемещаемого элемента. Обратите внимание, что эта функция действительно возвращает адрес перемещаемого элемента, а не адрес начала содержащей его инструкции.
Например: dseg:0000 public start dseg:0000 start proc near dseg:0000 B8 00 10
mov ax, seg dseg dseg:0003 8E D8 mov ds, ax
Message(“0x%X \n”,
GetNextFixupEA(-1)
);
0x1001
Эмулятор загрузки инициализировал перемещаемый элемент необходимым значением, указывающим на адрес сегмента в виртуальной памяти. В нашем случае он равен 0x10.
Операнд
Пояснения ea
Линейный адрес
Завершение
Пояснения
!=BADADDR
Успешно
Return
==BADADDR
Ошибка
long GetFixupTgtType(long ea);
Функция возвращает тип перемещаемого элемента по его линейному адресу.
Возможные значения перечислены в таблице ниже. Поскольку большинство из них на платформе Intel не имеет места, то подробное описание их назначения приведено в факультативном приложении к книге «Использование IDA на не-Intel платформах»
FIXUP_MASK
0xF
FIXUP_BYTE
FIXUP_OFF8
FIXUP_OFF8 0
Восьми битное смещение
FIXUP_OFF16 1
16-битное смещение
FIXUP_SEG16 2
16-битный сегмент (селектор)
FIXUP_PTR32 3
32-битный длинный указатель (16-бит база; 16-бит селектор)
FIXUP_OFF32 4
32-битное смещение
FIXUP_PTR48 5
48-битный указатель (16-бит база; 32-бит смещение).
FIXUP_HI8 6
Старшие 8 бит 16-битного смещения
FIXUP_HI16 7
Старшие 16 бит 32-битного смещения
FIXUP_LOW8 8
Младшие 8 бит 16-битного смещения
FIXUP_LOW16 9
Младшие 16бит 32-битного смещения
FIXUP_REL
0x10 fixup is relative to the linear address specified in the 3d parameter to set_fixup()
300
FIXUP_SELFRE
L
0x0 elf-relative? - disallows the kernel to convert operands in the first pass- this fixup is used during output This type of fixups is not used anymore. Anyway you can use it for commenting purpose in the loader modules
FIXUP_EXTDEF
0x20 target is a location (otherwise - segment)
FIXUP_UNUSED
0x40 fixup is ignored by IDA disallows the kernel to convert operands- this fixup is not used during output
FIXUP_CREATE
D
0x80 fixup was not present in the input file
Пример: seg000:032D cmp word ptr [bp+8], seg seg000
seg000:0332 jnz loc_0_33A
Message("0x%X \n",
GetFixupTgtType(
GetNextFixupEA(0)
)
);
0x2
Операнд
Пояснения ea
Линейный адрес
Завершение
Пояснения
!=BADADDR
Тип перемещаемого элемента
Return
==BADADDR
Ошибка