Пример использования Dataflow

This post is also available in: Английский

Страница проекта доступна здесь.

0.     Установка

  1. Скачайте архив dataflow-0.3.0.zip
  2. Распакуйте в любую директорию ( например c:/temp )

1.     Настройка

  1. Переименуйте dataflow.cfg.example в dataflow.cfg
  2. Если вы распаковали в отличную от c:/temp директорию, то в  dataflow.cfg измените путь на соответствующий

2.     Запуск

  1. Запустите программу DataflowManager.exe. В трее появится иконка со смайликом.
  2. Откройте консоль cmd.exe. Перейдите в c:/temp

cd c:/temp
c:

Начните анализ программы-примера FunctionsTest.exe

Dataflow.exe FunctionsTest.exe

Программа FunctionsTest.exe представляет собой скомпилированный cl код:

#include ;
#include "stdafx.h"
int foo5( void )
{
    printf( "foo5\n" );
    return 0;
}

int foo6( void )
{
   printf( "foo6\n" );
   return 0;
}

int foo4( void )
{
   printf( "foo4\n" );
   return 0;
}

int foo3( void )
{
   printf( "foo3\n" );
   foo6();
   return 0;
}

int foo2( void )
{
   printf( "foo2\n" );
   foo4();
   foo5();
   return 0;
}

int foo1( void )
{
   printf( "foo1\n" );
   foo2();
   foo3();
   return 0;
}

int main(int argc, char* argv[])
{
   printf( "main\n" );
   foo1();
   getchar();
   return 0;
}
    Программа запустится, выведет сообщения и застынет на getchar

Т.е. фактически программа еще не завершена.

  1. С помощью управляющей программы запрашиваем получение статистики

На консоль выведется отладочная информация. Две матрицы: матрица смежности и матрица достижимости функций программы.

На диск в папку FunctionsTest.exe [время дата] (PID) размещается данные, полученные в ходе статического и динамического анализа FunctionsTest.exe.

Данные можно запрашивать в любой момент. Каждый раз они будут размещаться в отдельную папку в номером запроса.

В каждой из папок находится два файла.

Файл functionstest.exe_boundle.gdl содержит информацию об исследуемой программе: загружаемые модули, графы вызова функций, CFG функций, информацию о покрытии кода.

Файл functionstest.exe_fuzzing.gdl содержит рейтинг функций для fuzzing

Рассмотрим более подробно файл functionstest.exe_boundle.gdl. Файл содержит описание на языке GDL. Открыть его можно в программе aiSee (www.aiSee.com). Открываем с помощью aiSee файл functionstest.exe_boundle.gdl (удобно ассоциировать программу с расширением .gdl). Отобразится самый верхний уровень информации о программе. Выделив блок и нажав кнопку “I” получим информацию о модуле.

Module code size – количество байт кода программы (подсчитываются только те модули, которые были указаны в dataflow.cfg). Значение получается как сумма размеров исполняемых секций модулей.

Reached code size – количество байт кода программы, которые удалось достигнуть в ходе статического анализа (по вызовам функций ). Так же учитываются только модули из dataflow.cfg.

Covered code size – коqличество байт кода программы, которые были исполнены. Учитываются только модули из dataflow.cfg.

Для того что бы получить более детальную информацию раскроем блок Program: functionstest.exe. Для этого выделим блок и нажмем кнопку “b” ( развернуть в блок ).

Схема детализировалась на уровень модулей. В ходе исполнения программы было подгруженно четыре модуля: msvcr100.dll, kernel32.dll, ntdll.dll, functionstest.exe. Для исключения появления дубликатов имен ( могут быть загружены модули с одним именем, но из разных папок ) к именам добавлены контрольные суммы от пути.  Вот увеличенные части предыдущей картинки

Желтым подсвечены те модули, анализ которых был выполнен (они присутствовали в dataflow.cfg). Из картинки видно, что нас интересует только модуль functionstest.exe. Остальные модули не анализировались и поэтому подсвечены серым цветом.  Информацию о модулях можно получить, выделив соответствующий блок и нажав кнопку I”.

Для модуля отображается полный путь, базовый адрес загрузки, а так же статистика по размеру исполняемого кода. Поля имеют тот же самый смысл, что и поля для программы целиком. Так как во анализируется только один модуль, то значения тоже совпадают. Для модулей, которые не были анализированы (помечены серым) отсутствуют поля Reached code size и Covered code size, потому что эти данные не доступны.

Следующий уровень детализации – функции модуля. Выделим модуль functionstest.exe и нажмем кнопку «X» ( развернуть в отдельный граф ). Далее нажимаем “M” (уместить в окно). Видим общую схему вызовов функций.

Рассмотрим картину по частям. Центральная часть содержит функцию EntryPoint – точку входа в программу.

Правая часть графа содержит функции автоматической инициализации программы при старте.

И наконец, левая часть содержит функции, описанные в исходном коде программы.

Как и прежде, желтым цветом отмечены функции, которые были исполнены. Белым – функции не получившие управления.

Следующий уровень детализации – код  функций. Выделим блок с функцией functionstest.exe!sub_16E9 и нажмем кнопку “b” ( развернуть в блок ). Отобразится граф блоков кода функции.

Автоматически сгенерированная функция functiontest.exe!sub_16E9 выбрана по той причине, что она имеет много блоков кода. Функции, описанные исходном коде, более тривиальные.

Таким образом, можно изучать любые части программы, двигаясь по уровням детализации, используя команды (клавиши):

”b” – развернуть в блок

“f” – свернуть блок

“x” – развернуть в подграф

“Shift+X” – свернуть подграф

И на последок вся программа в полностью развернутом виде.

Рассмотрим более подробно файл functionstest.exe_fuzzing.gdl. Файл содержит информацию, полезную при выборе точки внедрения данных. Открываем файл в aiSee.  Попадаем на самый низкий уровень детализации – программа. Доступная здесь информация ничем не отличается от информации из functionstest.exe_boundle.gdl. Уровень модули так же ничем не отличается.

Отличия начинаются с уровня функций. Вместо графа вызовов функций на этом уровне находится рейтинг функций по потенциальному покрытию кода.  Функции отсортированы по возрастанию рейтинга слева направо. Справа находятся самые рейтинговые. Функция считается более рейтинговой, если доступные из нее функции имеют больший суммарный размер кода. Ниже представлены три самые рейтинговые функции functionstest.exe.

Поля Module code size, Reached code size и Covered code size относятся к модулю, которому принадлежит функция. Они отображаются для удобство сравнения с потенциально доступным кодом модуля из данной функции.

Поле Fuzzing potential reached code size отображает максимальное количество кода, которое может быть покрыто при выборе точкой ввода данных данную функцию.

Так же доступно графическое представление охвата функций. Для того, что бы визуально оценить функции, доступные при фаззинге из данной функции выберем функцию functionstest.exe!EntryPoint и нажмем “b”( развернуть в блок ). Отобразится граф вызовов функций наподобие того, что выводился в functionstest.exe_boundle.gdl.

Красным цветом обведены функции, которые можно потенциально покрыть из выбранной. Так как мы выбрали функцию, которая является входной точкой в программу, то обведены все функции графа. Видно, что из этой точки охватываются не только интересующие нас функции программы, но и стандартный автоматически сгенерированный код. Сместимся к менее рейтинговой функции

Из этой функции охват меньший. Однако исключаются стандартные функции. Охватываются все функции из вышеприведенного исходного кода.

Вот.

1. Переименуйте dataflow.cfg.example в dataflow.cfg

2. Если вы распаковали в отличную от c:/temp директорию, то измените путь на соответствующий