Описание функций встроенного языка
Скачать 2.86 Mb.
|
МЕТОДЫ Функция Назначение char AskStr (char defval,char prompt) Запрашивает у пользователя строку char AskFile (long forsave,char mask,char prompt) Создает диалоговое окно для выбора имени файла long AskAddr (long defval,char prompt) Запрашивает у пользователя адрес long AskLong (long defval,char prompt) Запрашивает у пользователя число типа long long AskSeg (long defval,char prompt Запрашивает сегмент у пользователя char AskIdent (char defval,char prompt); Запрашивает у пользователя ввод имени идентификатора long AskYN (long defval,char prompt) Создает модальный диалог Yes \ No \ Cancel void Message (char format,...); Выводит строку в окно сообщений void Warning (char format,...) Функция выводит предупреждающий диалог void Fatal (char format,...) Выводит фатальный диалог long ScreenEA (); Возвращает линейный адрес строки, на которой стоит курсор long SelStart (); Возвращает линейный адрес начала выделенной области long SelEnd (); Возвращает линейный адрес конца выделенной области success Jump (long ea) Изменяет позицию курсора в окне дизассемблера void Wait (); Функция ожидает конца автоанализа long AddHotkey(char hotkey, char Добавляет новую горячую клавишу 312 idcfunc); success DelHotkey(char hotkey); Удаляет горячую клавишу char AskStr (char defval,char prompt); Функция создает и выводит модальный диалог ввода строки. Используется в скриптах, тесно взаимодействующими с пользователем. В консольной версии окно будет выглядеть следующим образом: AskStr(“MyDefaultString”,”MyPromt”); А в графической версии приглашения ввода выглядит так: операнд Пояснения defval Значение по умолчанию promt Пояснение, которое будет выведено в диалоговом окне Завершение Пояснения !=”” Строка Return “” Ошибка Если пользователь откажется от ввода и нажмет Пример использования: auto s; s=""; while(s!="-") { s=AskStr(s,"Ваше имя?"); Message ("Добрый деньь (утро, вечер, ночь!) %s! \n",s); } 313 char AskFile (long forsave,char mask,char prompt); Функция выдает диалоговое окно, предназначенное для выбора файла, оснащенное минимальными средствами навигации. Внешний вид окна для консольной и GUI версий, естественно различен. И в последнем случае у пользователя значительно больше возможностей и свободы действий. Флаг ‘forsave’, вероятно, должен был уточнять тип окна – на отктыие файла или на запись. За кажущейся идентичностью (и то и другое окно с точни зрения пользователя выгдядит одинаково) скрыта большая разница. Окно выбора файла для записи должно само запрашивать подтверждение, если запрошенный файл уже существет. IDA, однако, это не делает не зависимо от значения флага forsave. И в любом случае не выдает никаких подтверждений, если указанный файл уже существует. 314 Если пользователь откажется от выбора и нажмет Эта функция поддерживает длинные имена Windows 95\Windows NT 4.0, и это следует учитывать при операциях с именами файлов (например, синтаксическом разборе) операнд пояснения forsave Флаг, выбора типа диалога. Не поддерживается в настоящих версиях mask Маска для выбора отображаемых в окне файлов promt Заголовок окна Завершение Пояснения !=”” Имя файла Return “” Ошибка Пример использования (два приведенные выше окна были созданы с помощью вызова) AskFile(0,”*.*”,”MyPromt”); long AskAddr (long defval,char prompt); Функция выводит модальный диалог, запрашивающий у пользователя ввод адреса в формате segment : offset. Если сегмент указан, то функция вернет значение, вычисленное по следующей формуле. Value == segment << 4 + offset При этом функция позволяет указывать не только адреса, но и имена сегментов, вычисляя при этом адреса автоматически (обратите внимание, что при этом необходимо соблюдать регистр). Например: Message (“%x \n”, AskAddr(0,”MyPromt”)); [seg000:0] 10000 Но вот уже [Seg000:0] приведет к выводу диалога, предупреждающего о неверно введенном адресе, а функция возвратит ошибку BADADDR. 315 Если не указывать сегмент (а только одно смещение), то функция возьмет по умолчанию базовый сегмент файла. Например: Message(“0x%x \n”,AskAddr(0,”MyAddr”)); 123h 0x10123 Если уж необходимо, что бы функция воспринимала ввод «как он есть», то следует вместо сегмента указать ‘0’, как показано ниже: Очень полезна поддержка относительного адреса. Если перед вводимым числом указать знак, то возращенное функцией значение будет вычислено по следующей формуле: RetVal == ScreenEA() + EntVal То есть вычисляется адрес, относительно текущей позиции курсора. При этом полученное значение может выходить за рамки доступных адресов сегмента, - никакой проверки функция не обеспечивает, - эта задача ложится на плечи пользователя, то есть программиста, разрабатывающего скрипт. Например: 316 seg000:32E8> db 21h ; seg000:32E9 db 0 ; seg000:32E9 seg000 ends : Message(“0x%X \n”,AskAddr(0,””)); +4 0x132ED Обратите внимание, что если указать ‘+0:4’, то IDA будет трактовать такое выражение совершенно иначе! А именно, как абсолютный адрес. При этом отрицательные значения преобразуются в беззнаковое с учетом разрядности сегмента (16 или 32 бит), а переполнение «вверх» никак не отслеживается. Это дает возможность адресовать память, как в пределах сегмента, так и за ними. Операнд Пояснения defval Значение по умолчанию (long) promt Заголовок окна Завершение Пояснения !=BADADRR Адрес Return “” Ошибка Обратите внимание, что ‘defval’ имеет значение long, а не char, и, следовательно, представляет собой линейный адрес, преобразование которого в сегментный ложится на плечи IDA. Логично, что было бы необходимо воспользоваться следующей формулой – seg = EntVal / 10 ; off = EntVal – seg, однако, до версии 4.0 IDA не выполняет никаких операций над адресом, используя нулевой сегмент, если только адрес невозможно представить комбинацией уже существующего сегмента и смещения. То есть, ‘0x10002’ будет автоматически преобразовано IDA в ‘seg000:2’. При этом всегда проверяются принадлежность образовавшегося смещения к доступному диапазону адресов выбранного сегмента и в случае нарушении границ, никакого преобразования не происходит. long AskLong (long defval,char prompt); Функция запрашивает у пользователя ввод длинного целого числа. По умолчанию используется шестнадцатеричная система исчисления. Префикс ‘x’ можно ставить, а можно не ставить – все равно число будет трактоваться как шестнадцатеричное. Отмена ввода или некорректный ввод приводит к возвращению ошибки BADADDR и, возможно, предупреждающему диалоговому окну, поясняющим источник ошибки. 317 Пример использования: AskLong(86562,”MyLong”); Операнд Пояснения defval Значение по умолчанию promt Заголовок окна Завершение Пояснения !=BADADRR Введенное пользователем число Return “” Ошибка long AskSeg (long defval,char prompt); Функция выводит диалог, запрашивающий ввод сегмента (селектора). Допустимо вводить имена сегментов с учетом регистра. Введенные селекторы автоматически не преобразуется адреса сегментов и эту операцию приходится выполнять вручную. В любом случае функция возвращает значение типа word, а не long. О факте выхода за допустимые границы IDA не сообщает, просто отбрасывая старшее слово введенного значения. Операнд Пояснения defval Значение по умолчанию (long) promt Заголовок окна Завершение Пояснения !=BADADRR Сегмент Return “” Ошибка Обратите внимание, что ‘defval’ имеет тип long, а не char. Поэтому непосредственная передача имени сегмента по умолчанию невозможна. Однако IDA автоматически подставляет его, если сегмент с заданным адресом уже существует. К сожалению, в IDA, включая версию 4.0, присутствует ошибка, в результате чего, вместо ожидаемого символьного имени сегмента выводится нечто нечитабельное и непечатаемое. AskSeg(1,””); 318 Обратите внимание, что IDA успешно распознала переданный ей селектор и определила какому сегменту он принадлежит. Обратная операция, к сожалению не поддерживается. В случае ошибки (или отмены) ввода возвращается ошибка BADSEL (не BADADDR!). Это происходит потому, что функция маскирует старшее слово, в результате чего (0xFFFFFFFF & 0xFFFF) == 0xFFFF, то есть BADSEL, а не BADADDR и не –1. char AskIdent (char defval,char prompt); Эта функция предназначена для ввода идентификатора (имени). От AskStr ее отличает лишь дополнительная проверка корректности (максимальная длина имени, первый символ строки не цифра и так далее). В отличие от остальных функций, возвращающих в случае неверного ввода ошибку, AskIdent возвращает управление только дождавшись корректного ввода или его явной отмены. 319 Если строка начинается с символа ‘@’, то функция всегда возвращает «»; двоеточие не считается недопустимым символом, даже если оно находится в середине строки. Поэтому в некоторых ответственных случаях не помешает воспользоваться функцией AskStr и все необходимые проверки выполнить самостоятельно. Операнд Пояснения defval Значение по умолчанию promt Заголовок окна Завершение Пояснения !=”” Строка Return “” Ошибка long AskYN (long defval,char prompt); Функция создает модальный диалог “Yes \ No \ Cancel”. AskYN(1,“Hello!”); Операнд Пояснения Значение по умолчанию ==defval Копка по умолчанию 0 1 Defval -1 320 promt Текст, выводимый в окне диалога 0 Пользователь нажал 1 Пользователь нажал -1 Пользователь нажал void Message (char format,...); Функция выводит строку в окно сообщений (Messages windows) IDA. Это наиболее популярный способ вывода результатов работы скриптов, а так же отладочных и диагностических сообщений. Перед выполнением примера убедитесь, что окно сообщений не закрыто остальными окнами. 321 Message понимает стандартные спецификаторы формата вывода Си и ближе всего близка к функции printf (смотри так же описание form). Сф пояснение %d десятичное длинное знаковое целое Пример: Message(“%d”,0xF); 15 %x шестнадцатеричное длинное целое строчечными символами Пример: Message(“%x”,10); a %X шестнадцатеричное длинное целое заглавными символами Пример: Message(“%X”,10); A %o восьмеричное длинное знаковое целое Пример: Message(“%o”,11); 13 %u десятичное длинное беззнаковое целое Пример: Message(“%u”,-1); 322 4294967295 %f десятичное с плавающей точной Пример: Message(“%f”, 1000000); 1.e6 %c символьное значение Пример: Message(“%c”,33); ! %s строковое значение Пример: Message(“%s”,”Hello, Word! \n”); Hello, Word! %e вывод чисел в экспоненциальной форме Пример: Пример: Message(“%e”, 1000000); 1.e6 вывод чисел в экспоненциальной форме ЗАМЕЧАНИЕ: В оригинале спецификатор '%g' заставляет функцию саму решать, в какой форме выводить число - с десятичной точкой или в экспоненциальной форме, из соображений здравомыслия и удобочитаемости. IDA всегда при задании этого спецификатора представляет числа в экспоненциальной форме. %g вывод указателя (не поддерживается) ЗАМЕЧАНИЕ: вместо спецификатора '%p' IDA использует '%a', преобразующее линейный адрес в строковой сегментный, и автоматически подставляет имя сегмента. Так, например, 'Message("%a \n",0x10002 ) ' выдаст 'seg000:2 '. Обратите внимание, что таким способом нельзя узнать адрес переменной. Пример: auto a; a="Hello!\n"; Message("%a \n",a); 0 Возвращается ноль, а не указатель на переменную. %p вывод десятичного целого всегда со знаком, не опуская плюс. %+d в оригинале - вывод шестнадцатеричного целого всегда со знаком, но ida воспринимает эту конструкцию точно так же как и ‘x'. %+x 'n' длина выводимого десятичного числа, при необходимости дополняемая слева пробелами. Например: Message("Число-%3d \n”,1) ; Число- 1 Если выводимое число не укладывается в 'n' позиций, то оно выводится целиком. Например: Message("Число-%3d \n”,10000) ; Число-10000 %nd 'n' длина выводимого шестнадцатеричного числа, при необходимости дополняемая слева пробелами. Например: Message("Число-%3x \n”,1); Число- 1 323 Если выводимое число не укладывается в 'n' позиций, то оно выводится целиком. Напрмер: Message("Число-%3x \n”,0x1234); Число-1234 %nd ‘n’ длина выводимого десятичного числа, при необходимости дополняемая слева незначащими нулями. Пример: Message("Число-%03d",1); Число-001 Если выводимое число не укладывается в ‘n’ позиций, то оно выводится целиком. Пример Message("Число-%03d",1000) Число-1000 %0nx ‘n’ длина выводимого шестнадцатеричного числа, при необходимости дополняемая слева незначащими нулями. Пример: Message("Число-%03x",0x1); Число-001 Если выводимое число не укладывается в ‘n’ позиций, то оно выводится целиком. Пример: Message("Число-%03x",0x1234); Число-1234 %#x Вывод префикса ‘0x’ перед шестрадцатиричными числами Пример: Message(“%#x”,123); 0x123 %#o Вывод префикса ‘0’ перед восьмеричными числами Пример: Message(“%#o”,1); 01 %n Количество выведенных символов (не поддерживается) void Warning (char format,...); Функция выводит диалоговое окно, предупреждающие об аварийной ситуации. Обратите на тип возращаемого значения void. То есть функция не предоставляет информации, о том какая клавиша была нажата. Warning (“Hello!”); 324 Ситуаций, в которых бы требовался аварийный выход из IDA очень немного. Между тем – эта функция вторая по популярности после Message. Очень часто она используется как простой информирующий диалог, не ожидающий от пользователя никакого выбора (например, так поступает демонстрационный плагин Strings) Сравните приведенный выше пример с результатом демонстрации работы AskYN. Не правда ли “HELLO! – OK” вполне очевидно, тогда как “HELLO! YES? NO? CANCEL?” может вызвать легкое недоумение и растерянность. К тому же Warning в отличие от AskYN, поддерживает стандартные спецификаторы форматированного вывода Си. (Подробнее смотри описание функции Message) Но все же использование Warning по поводу и без повода – относится к «дурным» приемам программирования, которых следует по возможности избегать. void Fatal (char format,...); Эта функция создает модальный диалог, выводящий указанное сообщение и немедленно аварийно выходит из IDA без подтверждений. Существует очень немного случаев, требующих применения столь «варварских» средств. Fatal (“Hello”); 325 Функция поддерживает стандартные спецификаторы Си, которые подробнее были описаны в функции Message. long ScreenEA (); Возвращает линейный адрес в текущей позиции курсора. Очень широко используется в скриптах, в том числе и приведенных в этой книге. Позволяет организовать взаимодействие между скриптом и пользователем, а так же облегчает вычисление линейного адреса в произвольной точке. Вместо того, что бы искать адрес начала сегмента по имени и суммировать его с необходимым смещением можно просто ткнуть курсором в нужное место и вызвать эту функцию. Однако обратите внимание, что возвращаемый адрес всегда округляется до начала строки. Невозможно выбрать элемент массива, отличный от первого. Особенно это доставляет много неудобств при просмотре дизассемблируемого файла в шестнадцатеричном виде, когда независимо от положения курсора в строке функция всегда возвращает адрес ее начала. Пример использования: 326 Message (“%x \n”, ScreenEA () ); 4010f7 Return ==return Пояснения !=BADADDR Линейный адрес начала элемента в текущей позиции курсора ==BADADDR Ошибка long SelStart (); Возвращает линейный адрес начала выделенной области. Широко используется для работы с блоками и позволяет организовать взаимодействие между скриптом и пользователем. Выделять можно только строки целиком и аналогично функции ScreenEA() можно узнать только адрес начала строки. Если выделение отсутствует, то возвращается ошибка (BADADDR). Пример использования: 327 Message (“%x \n”, SelStart () ); 10B52 Return ==return Пояснения !=BADADDR Линейный адрес начала выделенной области ==BADADDR Ошибка Long SelEnd (); Возвращает линейный адрес первого байта за концом выделенной области. Если выделение отсутствует, то функция вернет ошибку BADADDR. Пример использования: Message (“%x \n”, SelEnd () ); 10B53 Return ==return Пояснения !=BADADDR Линейный адрес следующего байта за концом выделенной области ==BADADDR Ошибка success Jump (long ea); Функция перемещает позицию курсора в окне дизассемблера IDA по требуемому адресу. операнд Пояснение ea 32-разрядный линейный адрес ==return Пояснения ==1 Успешное завершение Return ==0 Ошибка 328 Очень активно используется в пользовательских скриптах. Однако имеет ряд тонкостей. Прежде всего, экран обновляется не в момент выполнения функции, а только после завершения работы скрипта. Поэтому следующий пример не будет правильно выполняться: while(1) Jump(AskAddr(0x10000,"Введите адрес для перехода")); Это не позволяет динамически иллюстрировать работу скрипта и заставляет изощряться в поиске решений, когда требуется интерактивное взаимодействие вместе с показом нужного кадра окна. Приходится предусматривать временный выход и последующий вход из скрипта, благо это возможно. Достаточно лишь сохранять значения всех переменных в массиве или виртуальной памяти (ну для любителей экзотики или перестраховщиков - в файле). Но это все же концепция непривычная рядовому программисту. Другим минусом является округление адреса перехода до целой строки. Особенно это неудобно при переключении экрана в шестнадцатеричный режим. Jump не позволяет указывать на конкретный байт, а только на всю строку целиком. При задании несуществующего адреса курсор не изменяет своей позиции, а функция возвращает ноль. |