Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ida.final.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
6 Mб
Скачать

Навигатор по функциям

Созданием элементов всецело занимается ядро IDA; пользовательские скрипты хотя и имеют достаточные для «ручного» создания элементов привилегии, пользоваться этими привилегиями категорически не рекомендуется - даже незначительная ошибка способна вызвать непредсказуемое поведения дизассемблера вплоть до его полного «зависания».

Напротив, работая с уже созданными ядром элементами, пользователь может решить ряд задач, облегчающих дизассемблирование исследуемого файла. Пусть, например, требуется отыскать в тексте все условные переходы, стоящие после инструкции “test”, следующей за вызовом функции, иначе говоря, произвести поиск по шаблону “call *\test *,*\j? *” и вывести протокол отчета.

Это можно осуществить с помощью следующего листинга, сердцем которого является цикл, вызывающий функцию NextHead, последовательно переходящей от одной машинной инструкции к другой:

#include <ida.idc>

static main()

{

auto a;

a=0;

while(a!=BADADDR)

{

if (isCode(GetFlags(a)))

if( (GetMnem(a)=="call")

&& (GetMnem(NextHead(a,BADADDR))=="test")

&& (Byte(NextHead(NextHead(a,BADADDR),BADADDR)) > 0x6F)

&& (Byte(NextHead(NextHead(a,BADADDR),BADADDR)) < 0x80))

Message(">%s %4s %s\n>%s %4s %s,%s\n>%s %s %s\n>-------\n",

atoa(a),GetMnem(a),GetOpnd(a,0),

atoa(NextHead(a,BADADDR)),

GetMnem(NextHead(a,BADADDR)),

GetOpnd(NextHead(a,BADADDR),0),

GetOpnd(NextHead(a,BADADDR),1),

atoa(NextHead(NextHead(a,BADADDR),BADADDR)),

GetMnem(NextHead(NextHead(a,BADADDR),BADADDR)),

GetOpnd(NextHead(NextHead(a,BADADDR),BADADDR),0));

a=NextHead(a,BADADDR);

}

}

Результат его работы может быть следующим (в данном примере использовался файл first.exe –см. главу «Первые шаги с IDA Pro»)

>004010C0 call ostream::opfx(void)

>004010C5 test eax,eax

>004010C7 jz loc_4010E0

>---------------------------

>0040111F call ios::~ios(void)

>00401124 test [esp+4+arg_0],1

>00401129 jz loc_401132

>---------------------------

>004011BE call ios::~ios(void)

>004011C3 test [esp+4+arg_0],1

>004011C8 jz loc_4011D1

>---------------------------

...

Две функции NextHead и PrevHead обеспечивают прямую (от младших адресов к страшим) и обратную (от старших к младшим) трассировку элементов, возвращая линейный адрес головы следующего элемента или значение BADADDR если достигнут последний элемент в цепочке.

Это позволяет рассматривать анализируемый код не как поток бессвязных байт, а упорядоченную последовательность инструкций и данных. Разница между ними заключается в том, что поиск байт из интервала 0x70-0x7F в первом случае обнаружит не только все условные переходы, но и множество других инструкций и данных, частью которых является ячейка с таким значением, например, “DW 6675h”; “MOV AX, 74h”; напротив, во втором случае можно быть уверенным, что анализируется именно начало инструкции, а не нечто иное.

Разбивка потока байт на элементы позволяет решить и другую задачу – определить какой именно инструкции (или данным) принадлежит такой-то линейный адрес, т.е. по линейному адресу ячейки определить адрес головы элемента, которому эта ячейка принадлежит.

Манипулируя с флагами узнать это достаточно просто – достаточно проанализировать старшие 12 бит хвостовых атрибутов – флаги, расположенные по четному линейному адресу – содержат количество оставшихся байт до конца элемента, а флаги расположенные по нечетному линейному адресу – до его начала.

Реализация функции, возвращающей адрес головы элемента по любому принадлежащему элементу адресу может выглядеть так:

#include <idc.idc>

static MyGetHead(ea)

{

auto off,F;

F=GetFlags(ea);

if (!F) return -1; //Адрес не принадлежит ни одной ячейке

if (!(F & FF_TAIL)) //Это голова, возвращает ее адрес

return ea;

if (ea & 1) // ...нечетный линейный адрес

return (ea - (F >> 20));

// ...четный линейный адрес

return MyGetHead(ea-1);

}

Недостатком такого подхода является его потенциальная несовместимость с последующими версиями IDA Pro, но обойтись для решения проблемы одними лишь высокоуровневыми функциями, встроенными в IDA, не получается.

Задача могла бы быть решена при помощи вызовов функций ItemSize и ItemEnd, предназначенных для вычисления длины и адреса конца элемента соответственно, очевидно, адрес начала элемента равен ItemEnd(ea) – ItemSize(ea), но ItemSize возвращает не размер элемента, а смещение до его конца!

Ниже приведен другой вариант реализации функции MyGetItemHeadEA, вместо низкоуровневых манипуляций с флагами, использующий вызов PrevHead, однако, полностью отказаться от обращений к флагам не удается – приходится вызывать макрос isTail, определенный в файле <idc.idc> для проверки не является ли переданный адрес адресом головы элемента.

static MyGetItemHeadEA(ea)

{

if (!GetFlags(ea)) return –1; // ошибка

if (!isTail(GetFlags(ea)) // голова

return ea;

return PrevHead(ea,0);

}

Пара функций NextNotTail и PrevNotTail возвращают адрес следующего (предыдущего) элемента или бестипового байта. В полностью дизассемблированной программе не должно быть ни одного бестипового байта, но они могут присутствовать на промежуточной стадии анализа – все ячейки, на которые IDA не смогла распознать ни одной ссылки, она оставляет бестиповыми байтами, которые надлежит перевести в элементы кода или данных пользователю.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]