Анимация
JavaScript


Главная  Библионтека 

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

Так же можно переместить курсор в любое место строки 0x10D и выбрать пункт меню ~ View \ Cross references. Появится окно следующего вида:


seg000:010D Print

proc near

gxrefs to Print

Type Address

Text

ipf sesr)!i)!i)!i:)!ii)!i3 call Print

tat segOOO:0109 call

segUUU:Ull

Поскольку довольно часто встречается, что на один приемник ссылаются десятки (а то и больше!) различных источников, то IDA считает не рациональным отображать их в виде комментариев и показывает по умолчанию лишь две первые из них (перекрестные ссылки отсортированы по линейным адресам источников - от младших адресов, к старшим), то просматривать остальные приходится именно в таком окне.

Как получить программно линейный адрес источника будет рассказано несколько позже, поскольку это делает по разному в зависимости от типов перекрестных ссылок.

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

seg000: seg000: seg000: seg000: seg000: seg000: seg000: seg000: seg000: seg000: seg000: seg000: seg000: seg000: seg000: seg000: seg000: seg000: seg000: seg000:

0002 0004 0004 0006 0009 0009

mov ds, ax

assume ds:seg000 mov ah, 6

mov di, offset off 0 25

jmp short Print

000C

000C Def 1: 000C 000C 000E

000F ; -----

000F

000F Def 2: 000F 000F 0011

0012 ; -----0012

0012 Print:

mov retn

; CODE XREF: start+1Bu

; DATA XREF: seg000:0025o

dl, 31h ; 1

mov retn

; CODE XREF: start+1Bu

; DATA XREF: seg000:0027o

dl, 32h ; 2

; CODE XREF: start+9j



seg000 seg000 seg000 seg000 seg000

seg000

seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000 seg000

loc 0 21:

start

0012 0012 0014

0017

0019

001B

001D 001F 0021 ; 0021 0021 0021

0023 0023

0023

0023 ; -------0025 off 0 25

0027 0029 002B 002D

002F ; -------

002F

002F def 3: 002F 002F 0031 0032 0032 0032 0034

; start+1Fj

mov bx, [di]

add di, 2

or bx, bx

jz loc 0 21

call bx

int 21h

jmp short Print

; CODE XREF: start+19j

def 4:

mov int endp

; AL = exit code

dw offset Def 1 dw offset Def 2 dw offset def 3 dw offset def 4

dw 0

; DATA XREF: start+6o

CODE XREF: start+1Bu DATA XREF: seg000:0029o

mov retn

mov retn

dl, 3

dl, 4

Подобные примеры не редкость и встречаться с ними приходится довольно таки часто. Обратим внимание на следующую строку:

seg000:001B

call

Она осуществляет последовательную передачу управления функциям, читаемых в цикле из списка, а, следовательно, ссылается более чем на один адрес.

К сожалению пока IDA не умеет автоматически вычислять значение регистра BX и, следовательно, не может ни создать перекрестных ссылок, ни даже дизассемблировать вызываемые этой строкой функции. Скорее всего они будут помечены как unexplored.

Поэтому эта часть работы ложится на плечи пользователя. Часто при этом дизассемблируют код, но забывают создать перекрестные ссылки. Что при этом получается? А то, что вернувшись к дизассемблируемому файлу спустя некоторое время, вы уже не будете помнить какой код вызывает эти функции и анализ придется начинать сначала.

Но что бы создавать перекрестные ссылки нужно быть осведомленным в их архитектуре, чему и посвящена следующая глава.

АРХИТЕКТРУА ПЕРЕКРЕСТНЫХ ССЫЛОК



В предыдущей главе говорилось, что не зависимо от типа, перекрестная ссылка состоит из двух разных частей - источника и приемника. Каждый из них связан с определенным линейным адресом. Причем с любым адресом может быть связано одновременно как несколько приемников, так и несколько источников.

Другими словами с каждым линейным адресом может быть ассоциирован список источников (приемников). А, следовательно, нужно быть готовыми для работы со списками. Но для начала разберемся с тем, какие типы перекрестных ссылок существуют, ибо для работы с ними используются различные функции.

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

Говоря проще - такие ссылки образуют все команды условного и безусловного перехода и вызова подпрограмм, такие как JMP, CALL, JZ и тому подобные.

С перекрестными ссылками на данные мы сталкиваемся всякий раз, когда какая-то инструкция обращается к данным, по их смещению. Например, LEA, MOV xx, offset и так далее, в том числе и DW offset MyData.

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

Однако, это помогает лучше понять работу многих команд, поэтому ниже мы его рассмотрим.

Разумеется, речь идет о «ссылке на следующую команду» (Ordinary flow в

терминологии IDA). Именно с помощью его IDA и отслеживает выполнение программы. Это перекрестная ссылка указывает на следующую команду при нормальном исполнении программы. Покажем это на следующем примере:

seg000:0012 seg000:0014 seg000:0017 seg000:0019 seg000:001B seg000:001D seg000:001F seg000:0021 seg000:0021 seg000:0021 seg000:0021

seg000:0023 seg000:0023

loc 0 21:

start

bx, [di]

di, 2

;<=

bx, bx

loc 0 21

;<

call

;<=

short Print

;<=

ah, 4Ch

endp

Два цвета используются только лишь для облечения восприятия, - что бы было можно отличий пары приемник-источник друг от друга. Как видно, цепочка проходит сквозь все команды, пока не доходит до команды безусловного перехода. Тут она и обрывается.

Адрес перехода можно узнать по перекрестной ссылке типа «код», которая автоматически образуется здесь. Что это дает? Возможность трассировки программы, например, для определения адреса конца функции, который заканчивается, как правило RET, то есть так же инструкцией безусловной передачи управления без возврата в текущую последовательность команд, в отличие от CALL, которая после выполнения подпрограммы передает управление следующей за ней команде.

Словом, если все упростить, то нет никакого смысла выделять ссылку на следующую команду в отдельный тип. Она хорошо описывается одним лишь типом ссылки на код, поскольку текущая инструкция как бы вызывает следующую (ну во всяком случае



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