Анимация
JavaScript
|
Главная Библионтека отделенными друг от друга пробелами из произвольной точки читать невозможно, поскольку неизвестно чем является та или иная буква - началом слова или его серединой. Образно говоря, при дизассемблировании IDA разбивает исследуемый файл на «слова», в терминологии разработчиков - элементы. Элементом называется последовательность смежных ячеек виртуальной памяти, содержащих одну самостоятельную конструкцию языка ассемблера, с которой можно оперировать как с одним целым, - инструкцию, строку, переменную и т.д. Первая ячейка элемента называется головой, а все, последующие за ней -хвостом. Элементы единичной длины состоят только из головы и не имеют хвоста. Признаком головы является ненулевое значение бита FF DATA (см. таблицу 10) поля флагов. Соответственно признаком хвоста является нулевое значение бита FF DATA и ненулевое значение бита FF TAIL. Свойства элемента определяются свойствами его головы. Свойства головы определяются флагами, связанными с данной ячейкой виртуальной памяти. Существуют элементы двух видов - элементы кода (CODE) и элементы данных.(DATE). Вид элемента задается сочетанием дух битов FF DATA и FF TAIL следующим образом (см. таблицу 11) - если бит головы (FF DATA) установлен, то значение бита хвоста (FF TAIL) интерпретируется типом элемента - его единичное значение задает тип CODE, в противном случае - DATA; напротив, если бит головы сброшен, единичное значение бита FF TAIL трактуется признаком хвоста элемента; если же оба бита FF DATA и FF TAIL сброшены - элемент считается неопределенным (unexplored), т.е. несуществующим.
Таблица 10 устройство элемента FF TAIL
Таблица 11 Определение типа элемента Хвостовые флаги в двенадцати старших битах содержат смещения относительно начала и конца элемента. Флаги, расположенные по четному линейному адресу -относительно конца, а флаги расположенные по нечетному линейному адресу -относительно его начала. Это позволяет легко определить к какому элементу принадлежит такая-то ячейка, а так же узнать линейный адрес начла и конца элемента, на основании которых легко вычислить его длину. Замечание: в файле <INCLUDE\Bytes.hpp>, входящим в IDA SDK определена функция, возвращающая значение хвостовых бит "inline ushort gettof(fiags t f) { return ushort((F & TL T0FF) >> TL TSFT); }" Внимание: созвать новые объекты, использовать или изменять хвостовые биты может только ядро IDA, но не пользовательские модули! В противном случае это может привести к некорректной работе и зависанию дизассемблера. Элементы могут существовать только внутри сегментов - попытка создания элемента по адресу, не принадлежащему ни одному сегменту, обречена на провал. Навигатор по функциям Созданием элементов всецело занимается ядро IDA; пользовательские скрипты хотя и имеют достаточные для «ручного» создания элементов привилегии, пользоваться этими привилегиями категорически не рекомендуется - даже незначительная ошибка способна вызвать непредсказуемое поведения дизассемблера вплоть до его полного «зависания». Напротив, работая с уже созданными ядром элементами, пользователь может решить ряд задач, облегчающих дизассемблирование исследуемого файла. Пусть, например, требуется отыскать в тексте все условные переходы, стоящие после инструкции "test", следующей за вызовом функции, иначе говоря, произвести поиск по шаблону "call *\test *" и вывести протокол отчета. Это можно осуществить с помощью следующего листинга, сердцем которого является цикл, вызывающий функцию 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)); 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 [ 27 ] 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |