Анимация
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

<ida.cfg>, а размер страницы значением поля NPAGESSIZE. По умолчанию IDA резервирует 64 страницы, объемом 1024 байт (1 КБ). Каждый указатель занимает 4 байта страничной памяти, следовательно, 64-кб буфер вмещает свыше 16 тысяч имен. Следует отметить, при дизассемблировании программ, написанных на Delphi, IDA генерирует огромное количество имен и увеличение значение поля NPAGES может существенно улучшить производительность.

При загрузке файла в окне сообщений выдается отчет о выделении страничной памяти под нужды IDA: окно виртуальной памяти (allocating memory for virtual array), буфер двоичного дерева ("allocating memory for b-tree") и буфер указателей на имена (""allocating memory for name pointers").

Например, выделение памяти при загрузке файла "first.exe" в IDA 3.84 происходит следующим образом:

bytes pages size description

262144 32 8192 allocating memory for b-tree...

65536 16 4096 allocating memory for virtual array...

65536 64 1024 allocating memory for name pointers...

Рисунок 15 "Отчет о выделении памяти при загрузке IDA"

Взаимодействие с физической памятью

Взаимодействие с физической памятью становится возможным благодаря наличию четырех недокументированных функций peek, poke, lpoke и call, прототипы которых приведены ниже:

• long poke(long ea, long value)

• long lpoke(long ea, long value)

• long peek(long ea, long value)

• long call(long ea)

Функции poke и lpoke записывают байт и длинное целое value по линейному адресу ea физической памяти соответственно, возвращая прежнее значение ячейки. Функция peek читает байт по линейному адресу ea физической памяти, а функция call передает управление на машинный код, расположенный по линейному адресу ea физической памяти.

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

Пример, приведенный ниже, демонстрирует копирование содержимое ПЗУ компьютера в виртуальную память дизассемблера, с последующим анализом обработчика прерывания INT 0x13. Ввиду различной реализации функций низкоуровневой работы с памятью, его успешная работа гарантируется лишь при запуске из MS-DOS-версии IDA Pro. Операционная система Windows 9x эмулирует наличие ПЗУ и позволяет функции peek обращаться к нему даже из 32-разрядных версий IDA Pro.

auto a;

SegCreate(0xF0000,0xFFFFF,0x0F000,0,0,0); Message("Ждите... читаю BIOS..."); for (a=0;a<0xFFFF;a++)

PatchByte(0xF0000+a, peek(0xF0000+a)); Message("CK \n Дизассемблирую обработчик Int 0x13");

MakeCode(0xFEC59);



Message("OK \n"); Jump(0xFEC59);

По окончании работы скрипта экран дизассемблера должен выглядеть так:

seg001: seg001: seg001: seg001: seg001: seg001: seg001: seg001: seg001 seg001 seg001 seg001 seg001 seg001

EC59 EC59 EC59

EC5C EC5C EC5E

EC61

EC63 EC63 EC66 EC66 EC66

EC69 EC6B

loc E000 EC59:

; CCDE XREF: seg001:01881J ; seg001:019BtJ

loc E000 EE3B

mov al, 0C0h ; L call sl E000 EC8E jmp short loc E000 EC66

call loc E000 EC8A

loc E000 EC66: ; CODE XRE: seg001:EC61tj

call sl E000 EC6C

cmp al, ah

retn

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

Начать изучение виртуальной памяти лучше всего с загрузки двоичного (бинарного) файла. Сначала необходимо создать сам файл - это можно сделать командной "echo Hello, IDA Pro! > tutor.bin".

[] Load Binary or User-Defined Format file

File name: F:\IDAN\SRC\1\tutor.bin

(•) Binary file

Loading segment 0x1000 Loading offset 0x666

Processor: metapc

[ ] Create segments OK Cancel

i (in paragraphs)

F1 - Help

Рисунок 16 Диалог загрузки бинарного файла

Дождавшись появления диалога загрузки консольной версии IDA Pro, запомните базовый адрес сегмента, записанный в поле "Loading segment... (in paragraphs)", измените адрес загрузки на любой отличный от нуля (нулевое смещение крайне ненаглядно для иллюстрации), скажем, на 0x666, и сбросьте флажок "Create segment - для предотвращения автоматического создания сегмента (работа с сегментами будет рассмотрена позже, в главе «Сегменты и селекторы»).

Замечание: доступные автору графические версии IDA Pro содержат ошибку реализации, всегда создавая новый сегмент при загрузке файла, независимо от установленных настроек.



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

0:00010666 ;

File Name

: F:\IDPN\SRC\

0:00010666 ;

Format

: Binary File

0:00010666 ;

Base Address

: 10

00h Range:

0:00010666

0:00010666

0:00010666

0:00010667

0:00010668

0:00010669

0:0001066A

0:0001066B

0:0001066C

0:0001066D

0:0001066E

0:0001066F

0:00010670

0:00010671

0:00010672

0:00010673

0:00010674

; !

0:00010675

0:00010676

0:00010677

0:00010677

0:00010677

Слева каждой строки указывается ее линейный адрес, причем адрес первого байта равен 0x1000*0x10+0x666, т.е. сумме базового адреса, указанного при загрузке, умноженного на шестнадцать и адреса смещения.

Чтение ячеек виртуальной памяти осуществляется функциями - Byte(long ea), Word(long ea) и Dword(long ea) - возвращающими байт, слово и двойное слово соответственно. Если запрошенная ячейка не существует или не инициализирована, функция возвращает 0xFF (при этом следует быть особенно осторожным с функциями Word и Dword, некорректно сигнализирующих об ошибке - подробнее об этом можно прочитать в под главах Word и Dword соответственно).

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

if(MS VAL & GetFlags(ea))

значение ячейки определенно, можно читать;

else

значение ячейки не определено либо ячейка не существует

или же воспользоваться макросом hasValue(F), определенным в <idc.idc>, который следует вызывать так:

if(hasValue(GetFlags(ea)))

значение ячейки определенно, можно читать;

else

значение ячейки не определено либо ячейка не существует

Более короткий путь предоставляет макрос isLoaded(ea), определенный там же с аналогичным назначением:



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