Распаковка Skype средствами динамической инструментализации бинарного кода. Часть 1
- * покрытие операторов — каждая ли строка исходного кода была выполнена и протестирована;
- * покрытие условий — каждая ли точка решения (вычисления истинно ли или ложно выражение) была выполнена и протестирована;
- * покрытие путей — все ли возможные пути через заданную часть кода были выполнены и протестированы;
- * покрытие функций — каждая ли функция программы была выполнена;
- * покрытие вход/выход — все ли вызовы функций и возвраты из них были выполнены.
Intro
Skype на сегодняшний день одна из наипопулярнейших проприетарных програм с закрытым исходным кодом предоставляющая шифрованную голосовую связь и видеосвязь через Интернет между компьютерами (VoIP), использующих технологии пиринговых сетей(p2p), а также платные услуги для звонков на мобильные и стационарные телефоны. По состоянию 2011 года Skype имеет 663 миллиона пользователей по всему миру. Skype работает по принципу черного ящика. Она предоставляет очень крутые возможности абсолютно бесплатно, что конечно же заставляет задуматься над тем почему авторы ПО свободного характера кроме того что не расспространяют своих исходников, так еще и кроют его различными протекторами(виртуализаторами кода), обфусцируют код и всячески препятствуют анализу ПО. Оно и понятно - бесплатный сыр бывает только в мышеловке. В текущей статье мы попытаемся исследовать skype неординарным и новомодным образом, а именно средствами динамической инструментализации бинарного кода.Анализ ПО
Написание автоматического расспаковщика Skype для MacOSX
Для сборки автоматического расспаковщика Skype нам придется собрать некоторые данные для анализа. Очень подходит для этих задач интерактивный дизассемблер IDA. Для анализа вполне достаточно и Free версии. Итак пойдем вверх по ступеням. Для начала наш бинарник (исполняемый файл в формате mach-o) skype нужно будет открыть в дизассемблере и дождаться конца автоматического анализа. Вот как выглядит проанализированный код перед распаковкой, проведенный IDA Free:Intel PIN
PIN Toolkit - фрэймворк разработанный корпорацией Intel для облегчения и автоматизации труда связанного с инструментализацией и анализом покрытия бинарного кода. Фрэймворк будучи написанным для платформ x86 и x86_64 позволяет инструментировать код любого приложения написанного для архитектур этих процессоров. В прошлом Intel в PIN подерживала и другие платформы как ARM/Itanium/IIRC. По весьма понятным причинам текущие платформы больше не поддерживаются. Суть инструментализации кода заключается в анализе покрытии кода при исполнении целевой программы. В свою очередь покрытие кода — мера, используемая при тестировании и анализе программного обеспечения. Она же показывает процент, насколько исходный код программы был протестирован. Данная техника покрытия кода была одной из первых методик, изобретённых для систематического тестирования и анализа программного обеспечения. Первое упоминание покрытия кода в публикациях появилось в 1963 году. Существует несколько различных способов измерения покрытия, основные из них:Для программ с особыми требованиями к безопасности часто требуется продемонстрировать, что тестами достигается 100 % покрытие для одного из критериев.
Некоторые из приведённых критериев покрытия связаны между собой; например, покрытие путей включает в себя и покрытие условий и покрытие операторов. Структурно PIN можно разделить на основное приложение (pin), внедряемое в контекст анализируемого процесса ядро (pinvm.so) и разрабатываемый пользователем инструментальный модуль (он так же внедряется в контекст анализируемого процесса). Инструментальный модуль представляет собой динамически рассширяемую библиотеку, которая использует API, предоставляемый ядром PIN. Суть работы с API сводится к регистрации обработчиков, которые будут вызываться ядром в ходе исполнения кода исследуемого приложения и осуществлять либо логирование связанной с ходом исполнения информации, либо менять логику исполнения кода приложения любым образом, который разработчик инструментального модуля сочтет нужным. Вот пример кода взятый из сэмплов(samples) идущих в архиве с данным фрэймворком // Колличественный пример инструментализации кода // Актуальный код для инструментализации // VOID docount() { icount++; } // Код который проверяет нужность инструментализации кода в определенный момент VOID Instruction(INS ins, VOID *v) { // Вставляем инструкцию вызова PIN перед каждой исполняемой инструкцией INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END); } void Usage(void) { ... } // Инициализация компонентов PIN Toolkit int main(int argc, char * argv[]) { // Инициализация PIN if (PIN_Init(argc, argv)) return Usage(); // Регистровая инструкция "Instruction" устанавливает уровент инструментации инструкций INS_AddInstrumentFunction(Instruction, 0); // Запуск программы(без возможности возврата) PIN_StartProgram(); return 0; } В main() процедуре мы инициализируем внутренние функции PIN : установливаем уровень инструментализации INS_AddInstrumentFunction() и запускаем программу на исполнение PIN_StartProgram(). При этом для каждой последующей инструкции исследуемой программы фрэймворком PIN вызывается callback "Instruction"(отмеченный INS_AddInstrumentFunction()). В этом коллбэке мы решаем, какие инструкции хотим выбрать в текущий момент вызовом функции INS_InsertCall(). Затем, этот вызов исполняется прежде чем команда выполняется до обратного коллбэка "docount". Сообственно это и есть рабочий пример подсчитать количество исполняемых инструкций в программе.Расспаковка Skype
Продолжение следует...Об авторе: блог ведет Sanjar Satsura
Senior Security Analyst, Articles Writer at CyberSafe
Около 6 лет разработки программного обеспечения и реверс инженеринга закрытых программных продуктов на Windows Платформах, на *nix платформах - 4 год
Автор более 25 статей в журналах Xakep, Hakin9, "IT Sec" Magazine, "Software Developer's" Journal и 40 крупных программных продуктов и проектов.