
Плагины и скрипты IDA для анализа фрейма использования регистров

"""
Для чего нужен этот регистр?
Хм.. Я просто переименую его в veryuniquename, сделаю текстовый поиск и найду все ссылки!
Окей.. Жду завершения поиска.. ещё немного.. Готово!
Теперь нужно понять, какой из результатов поиска относится к текущему контексту использования регистра.
Не должно быть слишком сложно, правда?
"""
Если это случалось с вами (возможно, не раз), то вас ждёт сюрприз!
Просто нажмите Shift-X, и ваши проблемы исчезнут!
Вы также можете переименовать регистр в контексте использования. Просто Shift-N и следуйте инструкциям!
Кроме того, вместо того чтобы менять типы всех использований на определённый тип — просто нажмите Shift-T один раз.
И последнее, но не менее важное: если вы хотите установить смещение (как при Ctrl-R) для всех использований этого регистра, нажмите Shift-R.
Примечание: иногда уже установлен другой плагин, использующий Shift-T. Удалите его — вы всё равно никогда им не пользовались :-).
Этот плагин использует sark для удобного взаимодействия со скриптами IDA и cachetools для кэширования сканирования фрейма, что значительно ускоряет работу.
Oregami поддерживает как IDA 7.x/8.x, так и IDA 9.0+.
Если вы используете IDA 9, убедитесь, что у вас установлена актуальная версия sark, поддерживающая IDA 9.
Примечание: IDA 9 представила свою собственную функциональность Shift-X. Если вам нужно использовать встроенный Shift-X IDA вместо Oregami, измените сочетание клавиш Oregami в файле плагина.
[Для python3]
pip3 install sark
[Для python2]
Если вы используете версию IDA на Python 2, выполните:
pip2 install -U git+https://github.com/tmr232/[email protected]#egg=Sark
Обратите внимание, что python2 активно не поддерживается (поскольку IDA в основном перешла на python3, как и я), поэтому это может не работать.
git clone https://github.com/shemesh999/oregami
Кодовая база sark предлагает множество плагинов. Один из них: https://github.com/tmr232/Sark/blob/master/plugins/plugin_loader.py
Мы рекомендуем скопировать его в ваш каталог плагинов, а затем один раз запустить IDA с правами администратора (чтобы он мог создать файлы plugins.list).
После этого вы можете добавлять новые плагины, указывая путь к ним в одном из созданных файлов plugins.list (например, один создаётся в папке cfg IDA).
Теперь добавьте в один из файлов plugins.list:
FULLPATH\oregami\oregami_plugin.py
FULLPATH\oregami\regname_plugin.py
FULLPATH\oregami\typeregter_plugin.py
FULLPATH\oregami\offreg_plugin.py
Перезапустите IDA — плагины должны работать.
Или:
Скопируйте все файлы (включая внутреннюю папку oregami, кроме setup.py) в каталог плагинов IDA.
Помимо использования в качестве плагинов, Oregami можно применять для написания собственных скриптов!
Для этого сначала установите через прилагаемый файл setup.py. То есть выполните:
'python setup.py develop', и после этого вы сможете использовать внутренние классы и функции.
Обратите внимание, что мы рекомендуем использовать 'develop', а не 'install', чтобы при загрузке новой версии Oregami она работала сразу.
Например:
-- script.py --
def find_func_usage(func_ea, reg='r0'):
"""
Найти и вывести все использования регистра, включая информацию о конкретных операндах,
в которых он находится, и о том, какая операция выполняется с операндом.
"""
import oregami
rf = oregami.RegFrame(func_ea, reg)
for insn in rf.get_instructions():
print('Addr:{:x}'.format(insn.ea))
for opnd in insn.operands:
if opnd.uf_is_external:
continue
print('--opnd_idx:{} - {}'.format(opnd.n, oregami.UsageBits(opnd.op_flags)))
Предположим следующую последовательность кодов операций:
ROM:01000010 e_lis r10, 0x4004 # 0x40040000 # Загрузка непосредственного значения со сдвигом
ROM:01000014 e_add16i r10, r10, 0x1337 # 0x40041337 # Сложение непосредственного значения
ROM:01000020 se_mr r30, r31 # Пересылка регистра
ROM:01000022 cmplw r11, r10 # Логическое сравнение слов
ROM:01000026 se_bge loc_1000036 # Ветвление, если больше или равно
ROM:01000028
ROM:01000028 loc_1000028: # CODE XREF: sub_0100000+144↓j
ROM:01000028 e_stmw r30, 0(r11) # Запись нескольких слов
ROM:0100002C e_add16i r11, r11, 8 # Сложение непосредственного значения
ROM:01000030 cmplw r11, r10 # Логическое сравнение слов
ROM:01000034 se_blt loc_1000028 # Ветвление, если меньше
ROM:01000036
ROM:01000036 loc_1000036: # CODE XREF: sub_0100000+136↑j
ROM:01000036 e_add16i r10, r10, 8 # Сложение непосредственного значения
ROM:0100003A e_li r11, 0 # Загрузка непосредственного значения
Если мы просканируем фрейм использования регистра r10, начиная с адреса 01000022, то найдём три типа использований, включённых во фрейм.
Сюда войдут инструкции, которые устанавливают значение регистра.
Мы можем включить только последнюю инструкцию, изменившую значение регистра (адрес 01000014 в примере), или последовательность операций, используемых для установки начального значения регистра (адреса 01000010 и 01000014 в примере).
Последовательность операций, используемых при инициализации регистра, может называться "этапом инициализации".
Вы можете выбрать, поддерживать этап инициализации или нет, в зависимости от параметра init_stage_bool при инициализации RegFrame.
Сюда войдут инструкции, которые используют значение регистра и никак его не изменяют. В примере это строки 01000022 и 01000030.
Сюда войдут инструкции, которые используют значение регистра, но затем изменяют его значение. Эти инструкции могут рассматриваться как включённые в два различных фрейма использования — тот, который ведёт к ним, и тот, который исходит от них.
В примере это строка 01000036.
При сканировании фрейма использования регистра достижение операции инициализации или операции прерывания приводит к остановке сканирования в определённом направлении.
Но мы также можем остановить сканирование из-за инструкций, находящихся вне фрейма использования.
Например, сканирование фрейма использования регистра r11, начиная с адреса 01000030, остановится на строке 0100003A.
Это основной класс, используемый в Oregami. При инициализации с адресом и конкретным регистром он сканирует фрейм использования регистра и создаёт UFInstruction для всех соответствующих инструкций.
get_instruction — получить инструкцию по заданному адресу
get_instructions — генератор, возвращающий инструкции во фрейме использования.
Вы также можете запросить конкретные подмножества используемых инструкций:
get_init_instructions — получить только инструкции типа init
get_pure_instructions — получить только инструкции типа pure
get_break_instructions — получить только инструкции типа break
get_nobreak_instructions — получить только инструкции, не относящиеся к типу break (т.е. init + pure)
get_noinit_instructions — получить только инструкции, не относящиеся к типу init (т.е. pure + break)
get_outbreak_instructions — получить только инструкции типа out break
По умолчанию этот класс кэширует результаты сканирования и предотвращает повторное сканирование того же фрейма использования.
Это означает, что запрос RegFrame для любой инструкции, которая была частью фрейма использования (особенно типов init + pure; не break, потому что начало сканирования с них должно возвращать фрейм использования, исходящий от них), вернёт тот же предварительно вычисленный экземпляр RegFrame.
Чтобы принудительно выполнить повторное сканирование, используйте флаг force при инициализации класса.
Этот класс возвращается RegFrame и представляет инструкцию во фрейме использования.
Этот класс наследуется от класса sark Instruction и поэтому поддерживает те же методы.
Одно из основных отличий: вместо массива операндов класса sark Operand он содержит массив класса UFOperand.
Этот класс также содержит методы для определения типа инструкции (init, pure, break, outbreak) и битов операций (чтение, запись, явные и различные типы неявных операций).
Этот класс находится в массиве операндов внутри конкретного UFInstruction.
Этот класс наследуется от класса sark Instruction и поэтому поддерживает те же методы.
В дополнение к операциям sark он содержит методы для получения битов операций (чтение, запись, явные и различные типы неявных операций), а также для определения, является ли операнд фактически частью фрейма использования (полезно для понимания, какой операнд в инструкции типа break является частью фрейма использования).
Этот класс используется для анализа конкретной инструкции на предмет её использования регистров.
Он использует знания из IDA, текстовый анализ и специфические детали, характерные для процессора.
Причина создания этого класса в том, что базовый анализ IDA часто искажает информацию о наборе используемых регистров и способе их использования во многих кодах операций.
Этот класс наследуется от класса sark Instruction и поэтому поддерживает те же методы.
Одно из основных отличий: вместо массива операндов класса sark Operand он содержит массив класса RegOperand.
Этот класс используется для анализа конкретного операнда на предмет его использования регистров.
Он использует знания из IDA, текстовый анализ и специфические детали, характерные для процессора.
Причина создания этого класса в том, что базовый анализ IDA часто искажает информацию о наборе используемых регистров и способе их использования во многих кодах операций.
Этот класс наследуется от класса sark Operand и поэтому поддерживает те же методы.