Динамически подключаемые библиотеки (dynamic link libraries, DLL) используются для уменьшения объема исполняемого файла, за счет выделения некоторых функций в отдельный файл. Более того, функции из DLL могут использовать разные загрузочные модули, что особенно важно для жизнедеятельности Windows (например в KERNEL32.DLL содержаться функции управления памятью процессами и потоками). Для создания DLL в среде C++ Builder необходимо выбрать File\New\Dll при этом автоматически генерируется проект, компиляция которого и дает искомый результат. Для написания экспортируемых функций используется следующий синтаксис: __declspec(dllexport) void nameFunc(); При компиляции, кроме прочих, создаются файлы с расширениями *.LIB и *.DLL, содержащие экспортируемые функции. Подключение DLL в C++ Builder возможно явным и неявным способом. При неявной компоновке в секцию директив необходимо добавить строку вида: #pragma link ”nameFile.lib” а, в секцию прототипов добавить описание прототипа функции: void nameFunc(); При неявной компоновке функция вызывается по имени, необходимы файлы с расширениями *.LIB и *.DLL. Библиотека подключается к процессу в момент загрузки процесса и выгружается вместе с процессом. Явная компоновка требует использования функций WINAPI LoadLibrary() и GetProcAddress(). В данном случае функция вызывается по номеру, который ей присвоен при создании DLL. C++ Builder упорядочивает экспортируемые функции DLL в алфавитном порядке их имен. Номер функции в DLL можно получить с помощью утилиты tdump с ключом -ee. Функция LoadLibrary() принимает в качестве параметра имя библиотеки, а возвращает переменную типа HINSTANCE. Функция GetProcAddress() имеет следующий прототип: void *GetProcAddress (HINSTANCE, const char *); она принимает переменную типа HINSTANCE и символическую константу, а возвращает указатель на функцию. В приведенных листингах демонстрируется создание, неявная и явная компоновки DLL. //Пример создания DLL #include <vcl.h> #pragma hdrstop int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*) { return 1; } //Выше находится заголовок DLL, генерируется автоматически double dblValue(double); double halfValue(double); __declspec(dllexport) int AreturnValue(bool); __declspec(dllexport) int CreturnValue(bool); __declspec(dllexport) int BreturnValue(bool); int CreturnValue(bool i) { i= true; return(2); } int BreturnValue(bool i) { i= true; return(3); } int AreturnValue(bool i) { i= true; return(1); } double dblValue(double value) { return value * value; }; double halfValue(double value) { return value / 2.0; }
//Пример неявной компоновки DLL #ifndef useDllU1H #define useDllU1H #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> //-------------------------------------------------------- class TForm1 : public TForm { __published: // IDE-managed Components TLabel *Label1; TLabel *Label2; TLabel *Label3; TButton *Button1; void __fastcall Button1Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TForm1(TComponent* Owner); }; //-------------------------------------------------------- extern PACKAGE TForm1 *Form1; //-------------------------------------------------------- int AreturnValue(bool); int CreturnValue(bool); int BreturnValue(bool); #endif
int (*returnVa1)(bool); int (*returnVa2)(bool); int (*returnVa3)(bool); //-------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner) {//Создание формы hinst=LoadLibrary("dll_cb_c.dll"); returnVa1=(int (*)(bool))GetProcAddress(hinst, MAKEINTRESOURCE(1)); returnVa2=(int (*)(bool))GetProcAddress(hinst, MAKEINTRESOURCE(2)); returnVa3=(int (*)(bool))GetProcAddress(hinst, MAKEINTRESOURCE(3)); } //На форме имеется одна кнопка и три метки void __fastcall TForm1::Button1Click(TObject *Sender) { bool buf_b; int j; buf_b=false; if(returnVa1==NULL) Label1->Caption=AnsiString("Error"); else { j=returnVa1(buf_b); Label1->Caption=AnsiString(j); } Label2->Caption=AnsiString(returnVa2(buf_b)); Label3->Caption=AnsiString(returnVa3(buf_b)); } MAKEINTRESOURCE — макрос для создания символической константы. Переменная типа HINSTANCE создается глобально. Загрузка библиотеки и присвоение указателей на функции производится в момент создания формы. Количество и тип параметров в описании функций (сигнатура функции) в DLL и указателя на функцию, в вызывающем модуле должны совпадать, совпадение имен не обязательно. DLL выгружается из памяти при завершении работы вызывающего модуля. Принудительная выгрузка DLL осуществляется функцией FreeLibrary(HINSTANCE).
Чтобы убрать "тормоза в игре" или одним словом улучшить производительность необходимо открыть в ХЕКС-редакторе (см. ссылку сверху) XR_3DA.exe, там в коде с помощью поиска найти цифры 45 78, найти их просто - ввести в поиске GlobalMemoryStatusEx . Далее изменить их на 00 00 и сохранить изменения. Всё. Теперь всё будет работать нормально. Способ нашёл не я - Rolan.
(С) _Призрак_ Инструкция по изменению плотности травы. Параметр меньше 0.02 не ставить - Колмогор писал что начинает лагать 1. Открываем айда 2. Открываем айда_виев 3. Теперь ищем что нам нужно найти. Нам сейчас нужно найти r__detail_density? Тогда жмем ctrl+t и вводим r__detail_density 4. Находим функцию и тщательно ее разбираем (я ее полностью разбирать не буду, а только укажу где задаются параметры: fld ds:flt_10064400 --нижнее ограничение равное 0.6 or dword_1007CACC, 8 sub esp, 8 fstp [esp+30h+var_2C] mov ecx, offset unk_1007CA9C fld ds:flt_10064380 --верхнее ограничение равное 0.2 fstp [esp+30h+var_30] push offset aSs; "ЪЩЩ>" push offset aR__detail_dens; "r__detail_density" call ds:??0CCC_Float@@QAE@PBDPAMMM@Z; CCC_Float::CCC_Float(char const *,float *,float,float) push offset sub_1005E080; void (__cdecl *)() call _atexit add esp, 4 Если вы заметили, то что бы трава стала плотней нужно уменьшить параметр, а что-бы травы стало меньше нужно параметр увеличить 5. Нам нужно увеличить плотность травы: следовательно нужно изменить верхнее ограничение. Как это сделать? Есть 3 варианта:
Первый и самый логичный вариант: изменить переменную которая задает. Но тут есть небольшой подвох на котором я попался. Этой переменной может пользоваться не одна функция, а несколько. И не ясно что вы можете сломать, поменяв одну циферку в переменной...
Второй: взять другую уже существующую переменную. Хороший вариант которым я и воспользовался. Но и тут есть недочет - переменных в ддлке не так уж и много и можно просто не найти нужную
Третий: создать переменную. Отличный вариант. Единственный минус - я не знаю как это сделать
Я пошел по второму пути. Два раза шелкнув на ds:flt_10064380 айда отправила меня в дебри под названием .rdata. Там я нашел переменную которая называлась - flt_1006452C и которая имела значение 0.0720999 Вообще-то, как я понял, flt_1006452C - не является названием переменной. Это так сказать сборка из 2 показателей - (тип числа)_(оффсет) В нашем случае это число типа float которое находится в 1006452C. Ну чтож приступим к редактированию! 6. Отправляем в самое начало файла. Как? Сверху есть что-то типа статус бара - строка состоящая из синего,серого,черного цвета. Нажимаем там в любом месте мышкой и ведем влево до конца 7. Опять ищем r__detail_density. Находим в этой функции fld ds:flt_10064338. Дальше самое интересное. Жмем на ХЕКС_ВИЕВ и там у нас выделяются какие-то цифры. Это наше 10064338 только написано наоборот. Сравните: 38 43 06 10 10 06 43 38 Похоже, не правда? Начинаем редактировать. нам нужно поменять 4338 на 452C т.к. в этом и есть различие. Жмем правой кнопкой мыши на этих цифрах и выбираем пункт Edit. Меняем 38 43 на 2С 45. Дальше жмем где нибудь в коде. Это нужно сделать обязательно. После этого жмем правой кнопкой мыши и выбираем commit changes. Но айда не меняет исходный файл. В нашем случае мы можем только создать файл изменений. Делается это так - Файл - Produce file - Create DIF file. Назовем его test. DIF файл можно открыть при помощи блокнота и посмотреть что вы сделали. Теперь так сказать соединит этот файл и дллку. Это можно сделать при помощи bpatch. Качаем и смотрим и запускаем bpatch.cmd. Я думаю что вы сможете его изменить сами если нужно будет. Там все элементарно.
Сообщение отредактировал RETRIX - Воскресенье, 04.03.2012, 23:11
Добавлено (25.11.2011, 13:59) --------------------------------------------- Отладка в среде IDA Pro
Хотя отладка - не прямая обязанность IDA Pro, эта функция вполне работоспособна, и на ней стоит остановиться отдельно.
После загрузки исполняемого модуля в дизассемблер IDA Pro можно запустить отладчик. Однако прежде следует определиться с первой точкой останова. Проще всего использовать команду выполнения до текущего положения курсора, воспользовавшись пунктом меню Debugger | Run to cursor или нажав клавишу . Естественно в качестве точки первого останова выбрать первую инструкцию функций main или winMain, а далее можно осуществить пошаговое выполнение с заходом (клавиша ) или без захода (клавиша ) в функции. Но можно также воспользоваться командой запуска процесса (пункт меню Debugger | Start process или клавиша ), предварительно установив точку (точки) останова. Устанавливать точки останова можно прямо в дизассемблированном тексте при помощи клавиши . При этом строка, где находится инструкция, окрасится другим (красным по умолчанию) цветом. Наконец, можно воспользоваться окном настройки отладчика (пункт меню Debugger | Debugger options), которое представлено на рис. 5.7. В группе Events флажки определяют события, на которые реагирует отладчик, можно отметить флажок Stop on debugging start (Отладчик останавливается в момент своего запуска) или флажок Stop on process entry points (Отладчик останавливается на первой исполняемой инструкции программ).
Флажок Stop on thread start/exit меня несколько удивляет. Действительно, thread - это поток. Но при создании процесса всегда создается, по крайней мере, один (его называют главным) поток. Но разработчики этот момент, очевидно, проигнорировали, имея в виду только потоки, явно создаваемые в программе.
Итак, с первой точкой останова мы определились. Что же мы имеем в своем арсенале, когда используем IDA Pro как отладчик. Вот некоторые ключевые моменты.
После запуска приложения внешний вид IDA Pro изменяется. Появляются отладочные окна, при помощи которых можно контролировать процесс отладки. Это окно View EIP, содержащее отлаживаемый текст, окно View ESP, где представлено содержимое стека и текущее значение ESP, окно General registers, отражающее текущие значения общих регистров и регистра флагов, и окно Threads с информацией о потоках приложения. Отладчик всегда показывает в списке тот поток, где происходят отладочные события. Кроме этого, дополнительно можно открыть окно FPU registers с содержимым регистров сопроцессора (окно открывается автоматически, если выполняются инструкции арифметического сопроцессора) и окно Modules, где дан список загруженных модулей.
Можно выполнять пошаговое выполнение программы: Debugger | Step over (клавиша ) и Debugger | Step into (клавиша ), выполнять до первой попавшейся команды return (комбинация клавиш +), приостанавливать выполнение приложения (Debugger | Pause process).
Можно наблюдать за указанными ячейками памяти (окно Watch list, пункт меню Debugger | Watchs | Watch list), задав их, используя пункт меню Debugger | Watchs | Add watch.
Можно использовать трассировку, т. е. запись состояния отлаживаемого приложения на каждом шаге отладки. Для управления трассировкой предназначено подменю Debugger | Tracing. Все трассировочные события отображаются в окне трассировки Trace window. Можно отображать следующие трассировочные события: выполнение инструкции, выполнение функции, операцию записи в память, операции чтения/записи, выполнение инструкции.
Встроенный язык IDA Pro
Дизассемблер IDA Pro имеет встроенный язык программирования, с помощью которого можно писать небольшие программы анализа дизассемблиро- ванного кода, расширяя функциональность дизассемблера.
Встроенный язык IDA Pro - сильно упрощенный язык С. Этот язык называется сокращенно IDC (от англ. Interactive Disassembler Q. Подкаталог IDC содержит несколько программ, написанных на этом языке, которые IDA Pro использует при анализе дизассемблированных текстов. Программы легко анализируются, так что на них можно изучать данный язык.
Общие сведения
Имеются два способа выполнять команды языка IDC.
Более основательный подход заключается в создании файла с расширением idc, который содержит текст на языке IDC. Для загрузки программы используется команда меню File | Idc file. При этом программа компилируется
Первый способ заключается в использовании командного окна. Вызвать командное окно можно из меню File | IDC command либо комбинацией клавиш +. Внешний вид окна изображен на рис. 5.8. В поле редактирования вы можете вводить последовательность отделенных друг от друга точкой с запятой команд языка IDC. После нажатия кнопки OK IDA Pro будет пытаться интерпретировать записанные команды и выполнить их. Таким образом, используя данное окно, можно писать простейшие программы на языке IDC.
Структура программы и синтаксис языка IDC
Как и в языке С, в языке IDC программа состоит из функций, а выполнение программы начинается с выполнения функции main. Структура функции имеет следующий вид:
static func{argl, arg2, ...) {
}
Все функции должны объявляться как static. При задании аргументов не нужно указывать их тип. Последнее связано с тем, что в языке имеются только два типа переменных: строковые и числовые, принадлежность к которым легко определить по первой операции присвоения. Все же преобразования типов осуществляются автоматически.
Переменные
Все переменные являются локальными и объявляются при помощи ключевого слова auto. Существуют два типа переменных: числовые и строковые. Строковая переменная может содержать до 255 символов. Числовые переменные делятся на два типа: 32-битные целые (со знаком) числа и числа с плавающей точкой. Тип переменной определяется транслятором при ее первом присвоении.
Особо следует обратить внимание на преобразование типов. Рассмотрим различные ситуации.
и сразу выполняется. Кроме этого, в главном окне IDA Pro появляется панель (рис. 5.9) с кнопками для запуска и редактирования программы.
Преобразование строкового типа в числовой целый тип. Если левая часть строки является десятичным числом, то результат будет равен этому числу, в противном случае результат равен нулю.
Пример: auto a,b,c,d; c="w"; d="q"; a="451";
b="123qwert234"; c=a; d=b;
Message("%d:%d\n",c,d); Будет напечатано 4 51:123.
( Замечание )
Функция Message встроенного языка ЮС осуществляет вывод информации в окно сообщений (или консоль сообщений). Это окно IDA Pro открывает при запуске. Туда, в частности, выводятся сообщения о загрузке и анализе исполняемого кода. Функция Message является аналогом стандартной функции printf языка С.
Преобразование числового целого типа в строковый тип. Преобразование довольно необычно для тех, кто привык, что такое преобразование просто сводится к замене числа на строку без изменения значения (2345 -> "234 5"). Суть преобразования заключается в следующем: каждый байт числа справа налево преобразуется в символ в соответствующей кодировке, но размещается в строке слева направо. Например:
auto il; auto а; а=0х4241; il="q"; il=a;
Message("%s\n",il);
В результате выполнения фрагмента будет выведена строка "АВ".
Преобразование строкового типа в числовой тип с плавающей точкой. Данное преобразование осуществляется так же, как преобразование строкового типа в числовой целый тип.
Преобразование числового типа с плавающей точкой в строковый тип. Здесь преобразование осуществляется по простой схеме: каждый разряд числа и десятичная точка преобразуются в соответствующий символ строки. При этом, однако, допускается некоторая потеря точности. Пример:
auto il; auto а;
а=" il=3.5;
a=char(il); Message("%s\n",il);
Результатом выполнения фрагмента будет строка:
3.5000000000000018318681
Преобразование типов может возникнуть не только при присвоении, когда тип, стоящий справа от знака равенства, преобразуется к типу, стоящему слева от знака равенства. Преобразование типов происходит также:
если в арифметическом выражении имеется хотя бы один числовой тип с плавающей точкой, то все переменные выражения преобразуются к этому типу, так что действия в выражении осуществляются уже над вещественными числами;
если над переменной производятся битовые операции, то переменная рассматривается как переменная целого числового типа.
Над переменными числового типа можно выполнять следующие операции: присвоение, сравнение, сложение, вычитание, умножение, деление. Кроме этого, над целыми переменными можно выполнять битовые операции:
", " - циклические сдвиги;
& - битовое "И";
I - битовое "ИЛИ";
- битовое "НЕ";
л - битовое "исключающее ИЛИ".
Над целыми переменными можно также выполнять операции инкремента (++) и декремента (--).
Над строковыми переменными можно осуществлять следующие операции:
= - присвоение;
== - сравнение;
+ - конкатенация.
Основные конструкции
Язык IDC поддерживает основные конструкции языка С, изменяющие ход выполнения программы:
условные конструкции if, else;
ЦИКЛЫ while, do, break, continue;
цикл с параметром (счетчиком) for; П оператор возврата из функции return.
В языке отсутствуют такие операторы языка С, как goto и switch.
Директивы
Язык IDC поддерживает следующие препроцессорные директивы, используемые в языке С:
О #define;
#undef;
#include; О #error;
#ifdef, #ifndef, #else, #endif. Управление строками
Язык IDC поддерживает минимальный набор работы со строковыми переменными. В отличие от языка С, строка здесь является не последовательностью символов, а некоторым закрытым элементом (или объектом) неопределенной структуры, для которого существуют операция конкатенации (слияния) и несколько простых функций.
Для операции конкатенации используется обычный знак +. Например:
auto sl,s2,s3; sl="Hello,"; s2="world!"; s3=sl+" "+s2; Message("%s\n",s3);
Результатом выполнения фрагмента будет вывод в консоль сообщений строки "Hello, world!"
Перечислю основные функции для работы со строками.
strien - возвращает длину строки. Единственным параметром функции является строковая переменная или константа.
strstr - осуществляет поиск подстроки в строке. Первым аргументом функции является строка, где будет осуществляться поиск, вторым аргументом - подстрока для поиска. Функция возвращает номер символа, с которого начинается найденная подстрока. Нумерацию символов в строке принято отсчитывать от нуля. Если подстрока не найдена, то функция возвращает -1.
substr - функция выделяет (и возвращает) подстроку в строке. Первым параметром функции является строка, над которой будет осуществляться операция. Второй и третий параметры функции - это начальный и конечный номера выделяемого фрагмента. Номера символов отсчитываются от 0. Функция возвращает выделенный фрагмент строки.
ltoa - функция преобразует целое число в строку. Первый аргумент функции - числовая переменна или константа, второй аргумент - система счисления, в которой будет представлено число. Функция возвращает строку, представляющую число в заданной системе счисления. В случае ошибки возвращается пустая строка.
atoll - функция осуществляет преобразование строки в целое число. Единственным аргументом функции является строка. В случае ошибки возвращается 0.
Встроенные функции и примеры программирования на языке IDC
Данный раздел не является справочником встроенных функций языка IDC, тем более, что в справочной системе IDA Pro имеется перечень этих функций и, кроме того, есть хорошая книга Криса Касперски Образ мышления - дизассемблер IDA, где практически все функции описаны очень подробно. Я попытаюсь сделать небольшой обзор функций, наиболее важных для анализа текста программ, и приведу несколько примеров их использования, отталкиваясь от которых можно писать свои небольшие программы анализа.
Кроме справочной системы IDA Pro, информацию о встроенных функциях можно почерпнуть также в файле idc.idc (подкаталог IDC), где хранятся определения констант и прототипы функций вместе с краткими к ним комментариями. Этот файл предназначен для подключения к программам на языке IDC, что мы и будем делать при помощи директивы #include. Кроме этого, в том же каталоге имеются несколько примеров программ на языке IDC, которые могут оказаться довольно полезны.
Доступ к виртуальной памяти
Напоминаю, что дизассемблер IDA Pro перед тем, как анализировать исполняемый модуль, создает виртуальную память, куда потом и загружает этот модуль. Обращаясь к конкретным ячейкам этой виртуальной памяти, мы тем самым обращаемся к загруженному туда программному коду, который к тому же еще предварительно проанализирован IDA Pro.
Передвижение по памяти
Рассмотрим следующую программу на языке IDC (листинг 5.8).
#include
static main() {
auto ad; ad=0x401020;
while(ad<=0x401041) {
Message("%x\n",ad); ad=NextAddr(ad);
};
}
Конечно, читателю, привыкшему ориентироваться в программах на языке С, не составляет труда осмыслить эту программу. С функцией Message мы уже хорошо знакомы, и остается только функция NextAddr. Понять ее смысл можно просто из названия. Функция возвращает следующий по отношению к значению своего аргумента линейный адрес. В случае если адрес не существует, то функция возвращает -1. Для этого значения в файле idc.idc придумана константа BADADDR.
Результатом выполнения программы будет столбик адресов с адреса 0x401041 по адрес 0x401041 включительно. Разумеется, к тому же результату мы придем, если просто на каждом витке цикла будем добавлять к переменной ad единицу. Имеется также функция PrevAddr, полностью аналогичная функции NextAddr, но возвращающая предыдущий адрес.
Наконец, существует еще одна весьма полезная функция, с помощью которой можно выполнять поиск (передвигаться) последовательности байтов в дизассемблированном тексте. Это функция FindBinary. Первым ее аргументом является адрес, начиная с которого следует осуществлять поиск. Второй аргумент - флаг режима поиска. Нулевой бит флага определяет направление поиска (0 - прямой поиск, 1 - поиск в обратном направлении), первый бит указывает на чувствительность к регистрам символов (0 - не различать регистры, 1 - различать регистры). Третий аргумент функции - последовательность кодов разыскиваемых байтов. Байты пишутся через пробел и заключаются в кавычки. Используется текущая система счисления. Функция возвращает адрес, с которого начинается искомая строка. В случае если строка не будет найдена, функция возвращает - 1. Пример вызова функции:
ad=FindBinary(0x404020, 0, "34 AF 56 30") Чтение и запись
Как я уже упоминал, функция Next Addr (и PrevAddr) может возвращать - 1, если следующий виртуальный адрес не существует. Это значит, что следующий адрес либо недоступен, либо неинициализирован. А как быть в том случае, если команда просто обращается по какому-то адресу? Как заранее узнать, существует или нет данный адрес? Для этого предназначена функция GetFiags, единственным элементом которой является виртуальный адрес. Функция возвращает флаги этого адреса (атрибут). Нужные нам флаги проверяются при помощи константы FF IVL (листинг 5.9), значение которой определено в файле idc.idc.
Для чтения из виртуальной памяти в языке IDC предусмотрены три функции: Byte, word и Dword. Аргументами всех трех функций является виртуальный адрес. Соответственно функции возвращают байт, слово и двойное слово.
В листинге 5.9 представлена программа, которая читает блок виртуальной памяти и выводит его в окно сообщений.
#include
static main() {
auto ad, i;
for
Message ("%x ",ad) ;
if(GetFiags(ad) & FF_IVL) {
//печатаем значение прочитанного байта i=Byte(ad); if (i>31)
Message("%x...%c\n",i,i); else
Message("%x...\n",i); }else
{
//значение байта не определено Message("Error!\n");
}
}
}
Для записи в виртуальную память используются три функции: PatchByte, Patchword, PatchDword. Первым аргументом функций является адрес виртуальной памяти, вторым аргументом - записываемая в память величина. В листинге 5.11 представлена простая программа (не требующая комментария), анализирующая заданный блок памяти и изменяющая значения некоторых байтов.
#include
static main() {
auto ad,i,j; j=0x91;
for(ad=0x401020; ad<=0x401041; ad++) {
if(GetFiags(ad) & FF_IVL) {
i=Byte(ad);
if(i==0x50)PatchByte(ad, j);
}}}
Структура строки листинга
В строке листинга IDA Pro можно увидеть следующие элементы: инструкцию процессора или данное, комментарий, метку или перекрестную ссылку. Это уже не обезличенные данные, с которыми мы имели дело в предыдущем разделе. С другой стороны, со строкой листинга связаны определенные ячейки виртуальной памяти, в которых и хранятся коды инструкций или данные. Рассмотрим, какие же функции можно использовать для анализа строки листинга дизассемблера.
Я намеренно говорю "строка листинга", дабы объединить воедино разные элементы. Различные, прежде всего, по тому, где они хранятся. Если инструкции и данные располагаются в виртуальной памяти (файл с расширением idl), то остальные перечисленные выше элементы располагаются в специальных виртуальных массивах, которые хранятся в файле с расширением idO. Однако для нас все это элементы строки, и поэтому я объединяю их в одном разделе.
Выделение инструкций
В листинге 5.12 представлена программа, выводящая на консоль сообщений ассемблерный текст в заданном промежутке адресов.
//вывести первый операнд (если он есть) Message("%s",GetOpnd(ad,0));
if (j>0) {
//вывести второй операнд (если он есть) Message(",%s \n",GetOpnd(ad,1));
}else Message("\n"); }else Message("\n"); //перейти к адресу следующей инструкции ad=NextHead(ad,BADADDR);
}}
Главной в листинге является, конечно, функция NextHead. Первым аргументом этой функции выступает некоторый виртуальный адрес. Второй аргумент - адрес, ограничивающий значение возвращаемого адреса. Я использую BADADDR, который в данном случае трактуется как положительное целое число, т. е. FFFFFFFFH (а не -1). Функция возвращает адрес первого байта следующей инструкции или данного. Есть и аналогичная функция, но возвращающая адрес предыдущей инструкции или данного - PrevHead.
Функция GetMnem возвращает по указанному адресу имя инструкции (строку), которая с этого адреса начинается. Аргументом функции является адрес первого байта инструкции.
Функция Getopnd возвращает операнд инструкции в виде строкового значения. Функция имеет два аргумента: адрес инструкции и номер (за минусом 1) операнда в инструкции, отсчитываемый слева направо.
Для форматирования выводимой таблицы мне пришлось также использовать функцию GetOpType. Функция возвращает тип операнда инструкции процессора. Первым аргументом функции является адрес инструкции, вторым - номер (за минусом 1) операнда в инструкции, отсчитываемый слева направо. Мы воспользовались просто тем фактом, что если операнд присутствует, то значение, которое возвращает функция, должно быть больше нуля.
Наконец, при помощи функции орнех я задаю для каждой инструкции шестнадцатеричный формат вывода числовых операндов (если операнд - это число). Второй аргумент функции задает номер операнда. Значение - 1 в программе означает, что функция должна распространять свое действие на все операнды инструкции.
Рассмотрим теперь, как разбирать имеющиеся в дизассемблерном листинге данные. Каждое данное занимает, по крайней мере, один байт. Какое данное начинается с указанного адреса, можно определить по битам атрибута байта, который находится по этому адресу. Типы данных и флаги для их определения из файла idc.idc представлены в листинге 5.14.
Мы видим, что в программе опять используется функция NextHead, которая является наиболее удобной функцией для передвижения по дизассемблированному тексту.
Для определения типа данных мы учитываем флаги атрибута первого байта данных. Мы используем таблицу флагов из листинга 5.14, выделяя нужные биты командой i & Foooooooh.
Наконец, длину данных мы определяем при помощи функции itemsize. Единственным аргументом данной функции является адрес первого байта данного.
Другие элементы строки
Другие элементы строки - это комментарии (автоматически создаваемые и пользовательские), метки (программные метки и переменные) и перекрестные ссылки. Вы можете не только программно получать эти элементы, но и добавлять их в строку.
В листинге 5.17 представлен взятый из файла idc.idc и прокомментированный мной список возможных элементов и значений флагов первого байта инструкции или данного.
FF_COMM 0x00000800L // Has comment? // комментарий
FF_REF OxOOOOlOOOL // has references? // перекрестная ссыпка
FF_LINE 0x00002000L // Has next or prev cmt lines ? // строка многострочного комментария FF_NAME 0x00004000L // Has user-defined name ? // пользовательская метка (имя) FF_LABL 0x00008000L // Has dummy name? // метка (имя)
FF_FLOW OxOOOlOOOOL // Exec flow from prev instruction? // перекрестная метка с предыдущей инструкции FF_VAR 0x00080000L // Is byte variable ? // переменная (метка для данного)
В листинге 5.18 представлена программа, осуществляющая просмотр листинга, который генерирует IDA Pro, и поиск программных меток, которые затем выводятся на консоль сообщений. В строках, которые имеют метки, добавляется комментарий - строка "Метка".
#include static main()
{
auto ad,i,j; ad=0x401cfe;
while(ad<=0x401d41) {
ad=NextHead(ad,BADADDR); //вывести адрес инструкции Message("%10x ",ad); i=GetFlags(ad) ;
Поиск строк с метками осуществляется переходом от одной строки к другой и проверкой соответствующего бита у первого байта элемента (инструкции или данного) с использованием константы FF_LABL. Для создания комментария в программе вызывается функция MakeComm. Первым аргументом функции является адрес строки, вторым аргументом - строка-комментарий.
Работа с функциями
Функция - это объект листинга, который может состоять из нескольких строк, содержащих инструкции. Функция имеет начальный и конечный адрес, а также другие свойства (листинг 5.19). Разбивка дизассемблированного кода на функции позволяет значительно улучшить читаемость листинга, а также понимание логики выполнения программы.
В листинге 5.19 представлен перечень флагов, определяющих свойства функций, взятый из файла idc.idc.
#define FUNC_LIB 0x00000004L // library function
//библиотечная функция #define FUNC_STATIC 0x00000008L // static function
//статическая функция #define FUNC_FRAME OxOOOOOOlOL // function uses frame pointer (BP) //функция использует регистр EBP для указателя //на локальные переменные и параметры #define FUNC_USERFAR 0x00000020L // user has specified far-ness
//определена пользователем как далекая (far) #define FUNC_HIDDEN 0x00000040L // a hidden function
//скрытая (свернутая) функция #define FUNC_THUNK 0x00000080L // thunk (jump) function //функция-переходник, содержащая только //инструкцию jmp ttdefine FUNC_BOTTOMBP OxOOOOOlOOL // BP points to the bottom
//of the stack frame //регистр EBP указывает на "дно" //стекового фрейма
В листинге 5.20 представлена программа, которая выводит в консоль сообщений имена функций в заданном интервале адресов и устанавливает комментарий для библиотечных функций.
Для передвижения по функциям листинга, генерируемого IDA Pro, используются функции Next Function и PrevFunct ion, единственным параметром которых является адрес функции. Функции возвращают: одна - адрес следующей функции (эту функцию мы используем в программе), другая - адрес предыдущей функции.
Программа выводит на консоль имена всех встретившихся ей функций, которые возвращаются функцией языка IDC GetFunctionName. Аргументом функции может служить любой адрес, принадлежащий функции.
Для получения флагов функций применяется функция GetFunctionFlags. Флаги перечислены в листинге 5.19.
Программа устанавливает у всех библиотечных функций (которые признаются библиотечными IDA Pro) комментарий. Для этого используется функция setFunctionCmt. Она имеет три аргумента: адрес функции, строковый комментарий, тип комментария. Для функций можно устанавливать два типа комментариев: постоянный (параметр 0) и повторяемый (параметр 1). Первый комментарий присутствует только перед определением функции, второй также дублируется (повторяется) во всех вызовах данной функции.
Элементы интерфейса с пользователем
Дизассемблер IDA Pro предоставляет минимальный набор функций для автоматизации управления вводом/выводом. Это вывод в консоль сообщений, которым мы уже многократно пользовались (функция Message), управление курсором в дизассемблерном листинге, управление несколькими видами диалоговых окон и некоторые другие функции.
В листинге 5.21 представлена простая программа, которая в заданном интервале адресов ищет последовательность из трех подряд идущих инструкций PUSH и перемещает курсор к этой группе команд. Для перемещения курсора используется команда Jump, аргументом которой является виртуальный адрес.
Другие возможности программного анализа листинга в IDA Pro
Не имея возможности осветить весь перечень особенностей языка IDC, точнее библиотеки функций, предоставляемых IDA Pro, остановимся на некоторых интересных моментах.
В дизассемблере IDA Pro имеются встроенные возможности, позволяющие автоматически распознавать и определять такие важные элементы, присущие языкам высокого уровня, как структуры и перечисления. В IDA Pro и структура, и перечисление обладают тремя характеристиками, позволяющими их идентифицировать:
идентификатор структуры или перечисления;
имя структуры или перечисления;
индекс структуры или перечисления.
В листинге 5.22 представлена программа, выводящая на консоль сообщений список идентификаторов и имена всех структур, которые были обнаружены IDA Pro при анализе исполняемого кода.
}}
Комментарий к листингу 5.22
Функция GetNextstrucidx возвращает следующий индекс структуры по заданному индексу, функция Getstrucid - идентификатор структуры по ее индексу, функция GetstrucName - имя структуры по ее индексу. Следует иметь в виду, что значения индексов структур и перечислений могут изменяться в процессе анализа (появление новых структур и уничтожение старых), идентификаторы же остаются неизменными.
Работа с файлами
Встроенные функции позволяют работать с файлами. При помощи функции Gene rate File можно сгенерировать отчетный файл. Данная функция эквивалентна использованию пункта меню File | Produce File.
Дизассемблер IDA Pro поддерживает набор функций для управления файлами произвольной структуры. Этот набор функций в целом соответствует набору стандартных библиотечных файловых функций, определенных в заголовочных файлах stdio.h и io.h. Перечислю эти функции:
fopen - открыть файл; функция возвращает дескриптор, который затем используется в других функциях;
fclose - закрыть файловый дескриптор;
filelength - ПОЛУЧИТЬ ДЛИНУ ОТКрЫТОГО При ПОМОЩИ fopen файла;
fgetc - прочитать один символ из файла;
fput с - записать один символ в файл;
ftell - получить текущую позицию указателя;
fseek - переместить указатель в заданную позицию в файле.
А кто-то из тех, кто тут одобряет и понимает, сказал что сам собирается кустарным методом редактировать бинарики? Ну вы и Петросяны . Гораздо проще будет разок вякнуть "*censored*, чётко! Удачи всем." и с рожей истинного сумрачного гения надеятся на анонимуса по ту сторону интернетов. Что, кстати, и наблюдается даже в вашем с топистартером случае.
Ну серьёзно. Хватит жить мечтаниями. Не один идиот на ваше хочу не откликнется и просто для лулза неделями пыхтеть за редактором не станет.
Сообщение отредактировал butcher_512 - Пятница, 25.11.2011, 15:04
Коллективное письмо - не поможет... Остаётся только 2 вещи: 1. Устроить забастовку возле офиса ПЫС 2. Проникнуть к ним в офис и украсть компы и всё мы сразу. Про сталкер - 2 и про движок
Amicron, о том, что людям свойственно много болтать и мало делать. Девять страниц нафлудили, а толку нет.
Сам смысл темы в том, что "я покукарекал - другой реализовал". В любом случае что ты, что ретрикс, не собираетесь реализовывать ни одного из так красиво написанного набора слов из шапки. А это в свою очередь означает, что тема скатится известно куда, так и не принеся особой пользы своим существованием.
butcher_512, Вы Вольф Мессинг? Похоже что нет, исходя из этого я бы на вашем месте так не говорил по поводу "не собирается". Собираются, собираются уже 4 человека а вы батенька вместо того чтобы вникнуть в тонкости опять наступайте на все те же грабли "топикстартер, движоГ этА сложнА, вы кавно!" итд.
kot_da_Vinci, скорее всего он не видел результатов, у меня вчера не получилось встроить видео в сообщение, была просто ссылка. Вот, показ воспроизведения mp3.
Deathdoor, Хватит! Человек в отличии от некоторых то что говорит то и делает. Ничего грешного он е предложил, и если вам что то не нравится сударь то вас никто не обязывал сидеть и троллить в данной теме.