Кое-какие структуры
Зачем нам столько галоперидолу
Расширение IDC
Кое-какие структуры
Чтобы было несколько удобнее ковыряться в многомегабайтных внутренностях IDA Pro (с помощью все
той же IDA Pro) я определил несколько структур, описанных в IDA SDK, в файле idc_structs.idc.
Этот script конечно не может претендовать на звание победителя в конкурсе "самый удобочитаемый и
fool-proof исходник" (иными словами он написан отвратительно, на скорую руку, и совсем не имеет
обработки ошибок), но с ним гораздо удобнее анализировать ассемблерный листинг самой IDA Pro. Вам
достаточно просто загрузить этот файл в IDA Pro - метод main автоматически позаботится обо всем
остальном. Warning: если Вы еще не догадались, данная процедура должна быть применена для каждого
дизассемблируемого файла, в котором Вы хотите использовать описания этих структур. Что делать -
нету пока в IDA Pro центрального репозитория описания структур и типов...
Ну и дальше Вы просто должны помнить, какой тип какой символ имеет:
__inf idainfo
__ash asm_t
__ph processor_t
Единственный экспортируемый символ из любого pluginа plugin_t
Единственный экспортируемый символ из любого загрузчика loader_t
Единственный экспортируемый символ из любого процессорного модуля processor_t
Остальные можете посмотреть в заголовках из IDA SDK...
Зачем нам столько галоперидолу
Собственно главной целью всей процедуры под нейтральным названием "исследование IDA Pro 4.15"
было создание программы, обладающей некоторыми дизассемблирующими свойствами (а точнее просто
нагло использующей движок дизассемблера IDA.WLL), при этом работающей в НЕ ИНТЕРАКТИВНОМ режиме.
Т.е. чтобы Вы были лишены сомнительного удовольствия постоянно жать какие-то кнопки и иметь
возможность запускать какую-нибудь обработку в фоновом режиме. Что собственно мне почти удалось.
"Почти" - потому что оказалось, что IDA настолько ИНТЕРАКТИВНА, что это наложило неизгладимый
отпечаток и на сам движок. А именно - вы должны задать при инициализации движка (функция
init_kernel) callback функцию, которая ответственна за все - начиная от ведения автоанализа
(дело в том, что поскольку IDA Pro работает также и в не многозадачных системах, в ней
реализован очень остроумный способ фоновой обработки. Вашей callback функции при вызове с
сообщением ui_setidle передается адрес функции, которую Вы должны периодически вызывать, когда
Ваша оболочка занята бездельем. Соответственно все действия, требующие отложенной длительной
обработки, накапливаются в очереди. Вот эта-то очередь понемногу и разгребается при каждом таком
вызове. За подробностями обращайтесь к файлу заголовков из IDA SDK kernwin.hpp) и заканчивая
показом диалога для задания опций при загрузке нового файла (реакцию на это сообщение ui_load_file
я пока не реализовал, так что моя программа умеет работать пока только с готовыми дизассемблированными
файлами). Для начала я написал простенькую программку, которая всего лишь печатает в файл адреса и имена
всех функций. Зато ей не нужен вообще никакой интерфейс. Итак, как можно создавать программы,
использующие движок дизассемблера от IDA Pro. Поместите мой пример (директорию proba) в подкаталог
plugins каталога SDK IDA Pro. Поскольку мы будем собирать не plugin, а standalone .EXE, то нам потребуются
и несколько отличные настройки линковщика, в частности не нужен больше .DEF файл и необходима линковка
с standard C-runtime library c0x32 (это макрос C_STARTUP в makefiles). Так что я создал модифицированный
файл proba.mak на основе plugin.mak - его (а также файл common.inc) необходимо поместить в подкаталог plugins.
После этого можете попробовать собрать этот фантазм. Свежесобранный исполнимый файл (с расширением .EXE,
если Вы еще не верите в это) нужно поместить туда же, где обретаются все прочие исполнимые файлы от IDA
Pro. Файл кстати называется, как Вы уже наверное могли догадаться, RPIda. Запускать так же как обычно Вы
запускаете idaw, новые файлы создавать пока не умеет, зато с ранее дизассемблированными работает как часы.
В общем, мечты идиотов иногда сбываются...
Расширение IDC
Предположим, что Вы хотите расширить встроенный script engine IDC за счет собственных функций (ну мало ли чего может захотеться вполне достигшему половой зрелости программисту - mp3 там послушать, пивка попить и проч.). И сильно меня огорчал все время тот факт, что нет ну совершенно никакого документированного способа добавить ну хоть одну свою функцию в IDC script engine к уже реализованным где-то в бездонных глубинах ida.wll. Однако после пристального изучения файла заголовков expr.hpp можно обнаружить нечто интересное, а именно:
typedef struct { /* Element of functions table */
const char *name; /* Name of function */
error_t (*fp)(value_t *argv,value_t *res);
/* Pointer to the Function */
const char *args; /* Type of arguments.
Terminated with 0 */
/* VT_WILD means a function with
arbitrary number of arguments.
Actual number of arguments will
be passed in res->num */
} extfun_t;
typedef struct {
int qnty; /* Quantity of functions */
extfun_t *f; /* Functions table */
error_t (*startup)(void);
error_t (*shutdown)(void);
} ffuncset_t;
/*-----------------------------------------------------*/
// Array of built-in IDA functions
extern ffuncset_t Funcs; /* external functions */
И все бы хорошо, только жить да радоваться - но Вы забыли, кто автор этой гениальной программы. Символ Funcs НЕ ЭКСПОРТИРУЕТСЯ из ida.wll (горячий привет Ильфаку. Кстати, ты также забыл экспортировать такие мелочи как qmakefile, doFloat, DoDouble. Не иначе как очередное (какое уже по счету ? Я примерно после третьего десятка сбился со счету) проявление неповторимой заботы о пользователях своего продукта, умиляет аж до кровавых слез). В общем, способ данный будет работать только для версии 4.15 Standard Edition (впрочем, для всех других версий нужно будет поправить всего одно значение - инициализацию ida415_Funcs в файле idc_ext.cpp. Итак, используем старую недобрую технику расширения таблицы функций, позаимствованную из Linux - можно с легкостью как заменить любую из уже имеющихся функций, так и добавить любое количество собственных функций. Что меня неприятно поразило - то, что массив функций Funcs->f не отсортирован, и при выполнении любой встроенной IDC функции каждый раз происходит линейный поиск. Видимо, Кнута в наше время читать считается плохим тоном и за это расстреливают гнилыми помидорами с логотипом "Compatible with products from Microsoft".
Но и это еще не все. Дело в том, что если Вы захотите слегка расширить таблицу функций например из метода инициализации pluginа, то Вы поимеете неприятности. Дело в том, что каждый plugin загружается два раза. В первый раз просто вызывается метод init - если plugin решает, что он может быть полезным в данных условиях, данный метод должен вернуть PLUGIN_OK. После этого plugin в любом случае ВЫГРУЖАЕТСЯ. Логика - железобетонная. После чего списком грузятся все pluginы, к-рые изъявили желание работать, и второй раз их метод init уже не вызывается. Занавес. В общем, работает мой plugin, реализующий пример расширения IDC script engine примерно так - Вы должны явно руками запустить его хотя бы один раз. После чего Вы можете использовать в своих IDC скриптах две новых встроенных функции с примерно следующими прототипами:
void rp1(char arg);
void rp2(long, long);
написанных на C++ и реализуемых функциями RP_IDC_Ext & RP_IDC_Ext2 соответственно. Ничего сногсшибательно полезного они не делают (хотя и могли бы :-) - в общем, если интересно, см. исходник моего pluginа в файле idc_ext.cpp.