поименный доступ к объектам.
Символьные имена в самом деле гораздо удобнее малоосмысленных 32 битных числовых значений. Однако, поддерживать два набора функций, для имен и для идентификаторов по меньшей мере неразумно.
Поэтому в IDA была введена всего лишь одна функция, которая позволяла по имени структуры установить ее идентификатор (GetStrucIdByName). И обратная ей,
GetStrucName, которая по идентификатору возвращала имя.
Это позволило писать понятый код наподобие следующего:
DelStruc(
GetStrucIdByName("struc_10")
);
Небольшое замедление выполнения с лихвой окупалось его удобочитаемостью, и поэтому он стал очень популярным (именно так построены все примеры скриптов, приведенные ниже)
Однако, одно лишь это не решало всех проблем. Все равно имя структуры требовалось как-то передавать скрипту, что было не всегда осуществимо.
Поэтому был необходим механизм, обеспечивающий доступ ко всем существующим структурам. Теоретически это можно осуществить с помощью идентификаторов. Так, если проскандировать все числа от нуля до 0xFFFFFFFE, то можно обнаружить все структуры, которые присутствуют в базе и получить к ним доступ.
Но как же это будет медленно! Однако, не стоит быстро отказываться от умный идей. Ведь можно загнать все структуры в один список, проиндексированный числами от
238
нуля до номера последней созданной структуры, – тогда все операции с ним не потребуют никаких накладных расходов.
И в самом деле, IDA поддерживает именно такой список. Так, например, что бы узнать идентификаторы всех существующих структур достаточно выполнить следующий бесхитростный код: auto a; a=0; while(1)
{
Message(“0x%X 0x%X \n”, a,
GetStrucId(a) ); a=GetNextStrucIdx(a); if (a==-1) break;
}
Ключевой его фигурой является функция GetStrucid, которая возвращает идентификатор по индексу структуры.
Однако, индексы не жестко связаны с идентификаторами и использовать их для доступа к структурам можно только сразу же после получения. А точнее только на протяжении того времени, в течении которого гарантировано ни одна структура не была добавлена или удалена.
Фактически
индексы были введены, что бы было можно быстро получить список структур. И ни для чего большего их использовать не рекомендуется – разве что на свой страх и риск.
При этом будьте внимательны, иначе можно совершить ошибку наподобие следующей: auto a; for(a=0;a
DelStruc(GetStrucId(a));
С первого взгляда в этих двух строчках нет никакой ошибки и скрипт будет работать как часы, но попробуйте его запустить и произойдет нечто невразумительное.
В чем же дело? Вся причина в том, что индексы обновляются при каждом удалении структуры. То есть, удалив структуру с индексом ноль, мы не может переходить к индексу один, так как индексы были реорганизованы, и теперь нулевому индексу соответствует другая структура, а список был сокращен на единицу.
Правильный код, как бы это ни парадоксально на первый взгляд должен выглядеть так: auto a; for(a=0;aDelStruc(GetStrucId(
0
));
Поэтому, если вы не хотите искать подобных приключений, не используйте индексы ни для чего другого, кроме как просмотра существующих структур.
Теперь рассмотри, как осуществляется доступ к элементам структуры. Но для начала рассмотрим все характеристики члена структуры. Как известно руководств к языкам высокого уровня – это имя, тип и смещение относительно начала структуры.
Однако, в отличие от языков высокого уровня ассемблер MASM использует глобальное пространство имен, а это означает, что имя каждого члена структуры уникально и не может быть дважды повторено в системе.
239
Это огромный недостаток, который сводит на нет все преимущества структур. Так, например, если структура MCB (смотри выше) имеет члена с именем size, то невозможно дать тоже имя никакому члену другой структуры.
Впрочем, в TASM-е это ограничение устранено. Но, к сожалению, IDA не поддерживает такого режима работы. Поэтому имя члена могло бы служить идеальным средством доступа к нему, однако, в IDA использован другой подход, который при ближайшем рассмотрении оказывается не только более удобным, но и универсальным.
Доступ к элементам структуры осуществляется по их смещением, а точнее заданием любого, принадлежащего им смещения.
Это позволяет рассматривать структуру, как непрерывный «лоскут» адресного пространства, с «объектами» - членами. Именно так, например, организован доступ к локальным переменным функций.
С точки зрения IDA каждый член структуры характеризуется не только его типом
(грубо говоря, размером ячейки), но и может иметь связанные объекты, такие как имя или комментарий.
Более того, член структуры может являться не только ячейкой памяти, но и вложенной структурой!
Методы
Функция
Описание
Long GetStrucQty(void)
Возвращает количество структур, созданных вызовом AddStrucEx
Long GetFirstStrucIdx(void);
Возвращает индекс первой структуры в списке long GetLastStrucIdx(void);
Возвращает индекс последней структуры в списке long GetNextStrucIdx(long index);
Возвращает следующий индекс в списке структур long GetPrevStrucIdx(long index)
Возвращает предыдущий индекс в списке структур long GetStrucId(long index)
Возвращает ID структуры по индексу. long GetStrucIdByName(char name);
Возвращает идентификатор структуры по ее имени char GetStrucName(long id)
Возвращает имя структуры по ее идентификатору char GetStrucComment(long id,long repeatable);
Возвращает комментарии к структуре long GetStrucSize(long id)
Возвращает размер структуры в байтах, который равен сумме размера всех ее членов long GetMemberQty(long id);
Возвращает число членов структуры long GetStrucNextOff(long id,long
Возвращает смещение начала очередного
240
offset); элемента в структуре long GetStrucPrevOff(long id,long offset)
Возвращает смещение начала предыдущего элемента структуры long GetFirstMember(long id);
Возвращает смещение начала первого члена структуры long GetLastMember(long id);
Возвращает смещение начала (не конца!) последнего члена структуры char GetMemberName(long id,long member_offset);
Возвращает имя члена структуры char GetMemberComment(long id,long member_offset,long repeatable);
Возвращает комментарий, связанный с членом структуры long GetMemberSize(long id,long member_offset);
Возвращает размер члена структуры в байтах long AddStrucEx(long index,char name,long is_union)
Создает новую структуру long IsUnion(long id);
Возвращает единицу если тип структуры – объединение success DelStruc(long id); удаляет существующую структуру по ее идентификатору long SetStrucIdx(long id,long index);
Изменяет индекс структуры long SetStrucName(long id,char name)
Изменяет имя структуры long SetStrucComment(long id,char comment,long repeatable)
Задает комментарий к структуре long DelStrucMember(long id,long member_offset);
Удаляет члена структуры long SetMemberName(long id,long member_offset,char name)
Изменяет имя члена структуры long SetMemberType(long id,long member_offset,long flag,long typeid,long nitems
Изменяет тип члена структуры long SetMemberComment(long id,long member_offset,char comment,long repeatable)
Задает комментарий члена структуры
241
long GetStrucQty(void);
Функция возвращает количество структур, созданных вызовом AddStrucEx. Все они отображаются IDA в списке структур, который доступен из меню View \ Structures.
Структуры, обеспечивающие доступ к элементам стековых фреймов в это число не входят.
Если не создано ни одной структуры, то функция возвращает ноль.
Пример использования:
0000 struc_1 struc
0000 field_0 db ?
0001 field_1 db ?
0002 struc_1 ends
0002 0000 ; -------------------
0000 0000 struc_2 struc
0000 field_0 dw ?
0002 struc_2 ends
0002 0000 ; -------------------
0000 0000 struc_3 struc
0000 field_0 db ?
0001 struc_3 ends
Message(“0x%X \n”,
GetStucQty()
);
3
==return
Пояснения
!=0
Число структур, созданных вызовами AddStrucEx
Return
==0
Нет ни одной структуры
long GetFirstStrucIdx(void);
Функция возвращает индекс первой структуры в списке. Если существует хотя бы одна структура, то функция всегда взращает ноль.
Например:
0000 struc_1 struc
0000 field_0 db ?
0001 field_1 db ?
0002 struc_1 ends
0002 0000 ; -------------------
0000 0000 struc_2 struc
0000 field_0 dw ?
0002 struc_2 ends
242 0002 0000 ; -------------------
0000 0000 struc_3 struc
0000 field_0 db ?
0001 struc_3 ends
Message(“0x%X \n”,
GetFirstStrucIdx()
);
0x0
Список автоматически перестраивается при операциях удаления или добавления структур, поэтому индексы не остаются постоянными. Использовать их для доступа к структуре не рекомендуется.
Например, если удалить struc_1, а потом повторить вызов GetFirstStrucIdx, то она вновь вернет ноль, однако, теперь это индекс struc_2, а не srtuc_1.
0000 struc_2 struc
0000 field_0 dw ?
0002 struc_2 ends
0002 0000 ; -------------------
0000 0000 struc_3 struc
0000 field_0 db ?
0001 struc_3 ends
Message(“0x%X \n”,
GetFirstStrucIdx()
);
0x0
==return
Пояснения
==0
Индекс первой структуры в списке (всегда ноль)
Return
==BADADDR
Нет ни одной структуры
long GetLastStrucIdx(void);
Функция возвращает индекс последней структуры в списке. Он всегда равен
GetStrucQty() – 1. В том случае если не определено не одной структуры, то функция возвратит ошибку BADADDR.
0000 struc_1 struc
0000 field_0 db ?
0001 field_1 db ?
0002 struc_1 ends
0002 0000 ; -------------------
0000 0000 struc_2 struc
0000 field_0 dw ?
243 0002 struc_2 ends
0002 0000 ; -------------------
0000 0000 struc_3 struc
0000 field_0 db ?
0001 struc_3 ends
Message(“0x%X \n”,
GetLastStrucIdx()
);
0x2
==return Пояснения
!=BADADDR
Индекс последней структуры в списке
Return
==BADADDR
Нет ни одной структуры
long GetNextStrucIdx(long index); Функция возвращает следующий индекс в списке структур. Индекс выражается целым числом от нуля до GetStrucQty() – 1. Индексы следуют последовательно вплотную друг за другом без «пустот» Поэтому псевдокод этой функции очень прост.
CODE:1001D3E0 push ebx
CODE:1001D3E1 mov ebx, eax
CODE:1001D3E3 inc ebx
CODE:1001D3E4 call @get_struc_qty$qqrv
CODE:1001D3E9 cmp ebx, eax
CODE:1001D3EB jb short loc_0_1001D3F2
CODE:1001D3ED or eax, 0FFFFFFFFh
CODE:1001D3F0 pop ebx
CODE:1001D3F1 retn
Или то же на языке Си: long GetNextStructIdx(long index)
{ if (GetStrucQty()
}
По этой причине два следующих скрипта абсолютно идентичны:
0000 struc_1 struc
0000 field_0 db ?
0001 field_1 db ?
0002 field_2 db ?
0003 struc_1 ends
0003 0000 ; -------------------
0000 0000 struc_2 struc
244 0000 field_0 dw ?
0002 struc_2 ends
0002 0000 ; -------------------
0000 0000 struc_3 struc
0000 field_0 dd ?
0004 struc_3 ends
0004 auto a; for(a=0;aMessage(“0x%X 0x%X \n”, a,GetStrucId(a)
);
0x0 0xFF0000F0 0x1 0xFF0000FE
0x2 0xFF000100
auto a; a=0; while(1)
{
Message(“0x%X 0x%X \n”, a,GetStrucId(a)
); a=GetNextStrucIdx(a); if (a==-1) break;
}
0x0 0xFF0000F0 0x1 0xFF0000FE
0x2 0xFF000100
Какой из этих двух способов использовать дело вкуса каждого. Однако, читабельность первого примера значительно лучше, а вероятность допустить ошибку – меньше.
Операнд Пояснения index Индекс структуры в списке (от нуля до GetStrucQty()-1)
==return Пояснения
!=BADADDR
Индекс следующей структуры в списке
Return
==BADADDR
Ошибка
long GetPrevStrucIdx(long index);
Функция возвращает предыдущий индекс в списке структур. Индекс выражается целым числом от нуля до GetStrucQty() – 1. Индексы следуют последовательно вплотную друг за другом без «пустот» Поэтому псевдокод этой функции очень прост. long GetPrevStrucIdx(long index)
{
245
if (index<-1) return; return –index;
}
По этой причине два следующих скрипта абсолютно идентичны:
0000 struc_1 struc
0000 field_0 db ?
0001 field_1 db ?
0002 field_2 db ?
0003 struc_1 ends
0003 0000 ; -------------------
0000 0000 struc_2 struc
0000 field_0 dw ?
0002 struc_2 ends
0002 0000 ; -------------------
0000 0000 struc_3 struc
0000 field_0 dd ?
0004 struc_3 ends
0004 auto a; for(a=GetStrucQty();a>0;--a)
Message(“0x%X 0x%X \n”, a,GetStrucId(a)
);
0x2 0xFF000100 0x1 0xFF0000FE
0x0 0xFF0000F0 auto a; a=GetStrucQty()-1; while(1)
{
Message(“0x%X 0x%X \n”, a,GetStrucId(a)
); a=GetPrevStrucIdx(a); if (a==-1) break;
}
0x2 0xFF000100 0x1 0xFF0000FE
0x0 0xFF0000F0
Какой из этих двух способов использовать дело вкуса каждого. Однако, читабельность первого примера значительно лучше, а вероятность допустить ошибку – меньше.
Операнд Пояснения
246
index Индекс структуры в списке (от нуля до GetStrucQty()-1)
==return Пояснения
!=BADADDR
Индекс предыдущей структуры в списке
Return
==BADADDR
Ошибка
long GetStrucId(long index);
Функция возвращает ID структуры по индексу. Как уже отмечалось выше, индекс не может точно идентифицировать связанную с ним структуру, поскольку при любых операциях связанных с дополнением или удалением структур, список перестраивается, и тот же индекс уже может указывать совсем на другую структуру.
В отличие от этого, идентификатор (ID) структуры представляет собой уникальное
32-битное значение, всегда указывающие на одну и ту же структуру. Более того, даже если структура, связанная с конкретным идентификатором, была удалена, гарантируется, что тот же идентификатор не будет выдан ни одной созданной после этого структуре. Это гарантирует непротиворечивость ситуации и позволяет совместно использовать один и тот же идентификатор различным скриптам.
Пример использования:
0000 struc_1 struc
0000 field_0 db ?
0001 field_1 db ?
0002 field_2 db ?
0003 struc_1 ends
0003 0000 ; -------------------
0000 0000 struc_2 struc
0000 field_0 dw ?
0002 struc_2 ends
0002 0000 ; -------------------
0000 0000 struc_3 struc
0000 field_0 dd ?
0004 struc_3 ends
0004 auto a; for(a=0;aMessage(“0x%X 0x%X \n”, a,GetStrucId(a)
);
0x0 0xFF0000F0 0x1 0xFF0000FE
0x2 0xFF000100
Идентификатор, как и дескриптор, с точки зрения пользователя являются абстрактным «магическим» числом, интерпретировать которое допускается только операционной системе (в качестве которой выступает в данном случае IDA).
247
Операнд Пояснения index Индекс структуры в списке (от нуля до GetStrucQty()-1)
==return Пояснения
!=BADADDR
Идентификатор (ID) структуры
Return
==BADADDR
Ошибка
long GetStrucIdx(long id); Функция позволяет получить индекс структуры в списке по ее идентификатору (ID).
Обычно
такой операции не требуется, поскольку практически все функции принимают на входе именно идентификатор, а не индекс.
Операнд Пояснения id Идентификатор структуры
==return Пояснения
!=BADADDR
Индекс
Return
==BADADDR
Ошибка
long GetStrucIdByName(char name); Функция возвращает идентификатор структуры по ее имени. Имя структуры уникально (двух и более структур с одним и тем же именем существовать не может), поэтому неоднозначности не возникает.
Пример использования: auto a,b; a=AddStrucEx(-1,"MyNewStruc1",0); b=GetStrucIdByName("MyNewStruc1");
Message("0x%X 0x%X \n",a,b);
0000 MyNewStruc struc ; (sizeof=0)
0000 MyNewStruc ends
0xFF00020A 0xFF00020A
Обратите внимание, что функция чувствительна к регистру, (большинство ассемблеров его игнорируют). Поэтому имена “MyStruc” и “mystruc” не считаются идентичными, что и доказывает следующий пример: auto a,b; a=AddStrucEx(-1,"MyNewStruc",0); b=GetStrucIdByName("mynewstruc");
Message("0x%X 0x%X \n",a,b);
0000 MyNewStruc struc ; (sizeof=0)
0000 MyNewStruc ends
0xFF00020A 0xFFFFFFFF
248
Операнд Пояснения name Имя структуры
==return Пояснения
!=BADADDR
Идентификатор
Return
==BADADDR
Ошибка
char GetStrucName(long id);
Функция возвращает имя структуры по ее идентификатору. Очень часто используется совместно с GetStrucId.
Например:
0000 MyGoodStuc struc ; (sizeof=0x2)
0000 field_0 dw ?
0002 MyGoodStuc ends
0002 0000 ; ----------------------------------
0000 0000 MyStruc struc ; (sizeof=0x5)
0000 field_0 dw ?
0002 field_2 dw ?
0004 field_4 db ?
0005 MyStruc ends
0005 0000 ; ----------------------------------
0000 0000 My struc ; (sizeof=0)
0000 My ends
0000 0000 ; ----------------------------------
0000 0000 MyNewStruc struc ; (sizeof=0)
0000 MyNewStruc ends
0000 auto a; for (a=0;aMessage("%s \n",
GetStrucName(GetStrucId(a))
);
MyGoodStuc
MyStruc
My1
MyNewStruc
Операнд Пояснения id Идентификатор (ID) структуры
==return Пояснения
!=””
Имя структуры
Return
==””
Ошибка
249
char GetStrucComment(long id,long repeatable); Функция возвращает комментарии к структуре. В текущих версиях, включая IDA 4.0, комментарии к структурам поддерживаются лишь частично. Так, например, отсутствует возможность интерактивного комментирования функций (приходится пользоваться вызовом SetStuctComment), повторяемые комментарии поддерживаются лишь частично, что подтверждается следующим примером:
SetStrucComment(
GetStrucIdByName("_msExcInfo"),
" MyComment",1);
0000 ;
MyComment
0000 _msExcInfo struc ; (sizeof=0x8) ; XREF: .rdata:
004077E6 0000 ; .rdata:00407780r ...
0000 Id dd ? ; sss
0004 Proc dd ? ; offset (FFFFFFFF)
0008 _msExcInfo ends
.rdata:
004077E6 dd 1879048192 ; Id
.rdata:004077E6 dd 0 ; Pro
Message(“%s \n”,
GetStrucComment(
GetStrucIdByName("_msExcInfo"),
1);
MyComment
Обратите внимание, что IDA не отобразила повторяемый комментарий в строке rdata:004077E6, хотя это и следовало бы.
Операнд
Пояснения id Идентификатор (ID) структуры
Флаг
Пояснения
0
Неповторяемый комментарий
Repeatable
1
Повторяемый комментарий
Завершение
Пояснения
!=””
Комментарий
Return
“”
Ошибка