Файл: Изучение методов детектирования ВПО, методов противодействия детектированию ВПО и создание программы для анализа эффективности антивирусов, применяющих те или иные подходы к обнаружению угроз.pdf

ВУЗ: Не указан

Категория: Курсовая работа

Дисциплина: Не указана

Добавлен: 30.06.2023

Просмотров: 89

Скачиваний: 2

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Из этих полей мы получаем адреса функций LoadLibraryA и GetProcAddress. Затем необходимо решить проблему со вставкой кода распаковщика в упакованный файл. Решение следующее - открываем получающийся после компиляции распаковщика файл, считываем данные из его единственной секции (по сути - код) и преобразовываем его в h-файл, на который мы сможем ссылаться в проекте с упаковщиком. Решение было взято уже реализованным, поэтому останавливаться на нем мы не будем. Дело осталось за малым, дописать тело распаковщика.

Итак, распаковщик настраивается и добавляется в упакованный файл. На этом разработка упаковщика закончена. Для проверки работоспособности достаточно добавить полезную нагрузку, например, в виде MessageBox’a в код распаковщика и запаковать, например, сам упаковщик. Однако окончание разработки не означает, что мы сможем пользоваться этим упаковщиком в дальнейшем. Он слишком прост и больше подходит под определение «работающего прототипа». Однако при помощи уже разработанных решений, можно доработать этот упаковщик. Именно доработанным упаковщиком мы и будем пользоваться в дальнейшем.

2.2. Тестирование

Для проверки работоспособности нашего упаковщика, достаточно добавить полезную нагрузку в код распаковщика в виде простенького MessageBox’a как уже было предложено выше, упаковать сам упаковщик и запустить упакованный файл. В итоге результатом запуска упакованного приложения является окошко с надписью: «Hello!». (рис.2.6)

Рисунок

ЗАКЛЮЧЕНИЕ

Результатом проведённой работы стало создание программы упаковщика, с помощью которой были произведены модификации нескольких образцов ВПО с целью тестирования работоспособности АС.

В ходе работы стало известно, что в современных условиях необходимо своевременное обнаружение ВПО и применение комплексных мер, направленных на предотвращение последствий их работы. Именно этим и занимаются Антивирусы.

Изучив состояние вопроса на данный момент, становится очевидным необходимость создания ПО для анализа уязвимостей АС. Примером такого ПО является разработанный в данной работе упаковщик. Принцип и результаты работы разработанной программы наглядно и подробно продемонстрированы.


СПИСОК ИСПОЛЬЗУЕМЫХ ИСТОЧНИКОВ

  1. Касперски К. Техника отладки программ без исходных текстов / К. Касперски. – Санкт-Петербург: БХВ-Петербург, 2005. – 823 с.
  2. Подпружников Ю. В. Классификация методов обнаружения неизвестного вредоносного программного обеспечения / Современные тенденции технических наук: материалы Междунар. науч. конф. (г. Уфа, октябрь 2011 г.). — Уфа: Лето, 2011. — С. 22-25. — URL https://moluch.ru/conf/tech/archive/5/1133/ (дата обращения: 13.01.2019).
  3. . Касперский Е. Компьютерное zловредство / Е. Касперский. – Санкт-Петербург: Питер, 2007. – 208 с.
  4. Денисов Т.В. «Антивирусная защита» // Мой Компьютер - №4 1999 г.
  5. Защита информации. Конфидент. - 1998. - №1. - 96 с.
  6. Peering Inside the PE: A Tour of the Win32 Portable Executable File Format — URL https://msdn.microsoft.com/en-us/library/ms809762.aspx (дата обращения: 22.01.2019).
  7. Касперски К. Компьютерные вирусы изнутри и снаружи / К.Касперски. – Санкт-Петербург: Питер, 2006. – 526 с.
  8. Касперски К. Записки исследователя компьютерных вирусов / Касперски К. – Санкт-Петербург: Питер, 2005. – 316 с.
  9. Ташков П.А. Защита компьютера. Сбои, ошибки и вирусы / Ташков П.А. – Санкт-Петербург: Питер, 2010. – 288 с.
  10. PE (Portable Executable): На странных берегах — URL https://habr.com/post/266831/ (дата обращения: 11.01.2019).
  11. Донцов Д. Как защитить компьютер от ошибок, вирусов, хакеров / Донцов Д. – Санкт-Петербург: Питер, 2008. – 160 с.

ПРИЛОЖЕНИЕ 1: ЛИСТИНГ РЕАЛИЗОВАННОГО ПРИЛОЖЕНИЯ

Packer: main.cpp

#include <iostream>

#include <fstream>

#include <vector>

#include <string>

#include <boost/scoped_array.hpp>

//Заголовочный файл библиотеки для работы с PE-файлами

#include <pe_32_64.h>

//Заголовочный файл алгоритма LZO1Z999

#include "../../lzo-2.06/include/lzo/lzo1z.h"

//Заголовочный файл со структурами

#include "structs.h"

//Заголовочный файл с параметрами распаковщика

#include "../unpacker/parameters.h"

//Тело распаковщика (авто)

#include "unpacker.h"

//Директивы для линкования с собранными библиотеками PE и LZO

#ifndef _M_X64

#ifdef _DEBUG

#pragma comment(lib, "../../Debug/pe_lib.lib")

#pragma comment(lib, "../Debug/lzo-2.06.lib")

#else

#pragma comment(lib, "../../Release/pe_lib.lib")

#pragma comment(lib, "../Release/lzo-2.06.lib")

#endif

#else

#ifdef _DEBUG

#pragma comment(lib, "../../x64/Debug/pe_lib.lib")

#pragma comment(lib, "../x64/Debug/lzo-2.06.lib")

#else

#pragma comment(lib, "../../x64/Release/pe_lib.lib")

#pragma comment(lib, "../x64/Release/lzo-2.06.lib")

#endif

#endif

int main(int argc, char* argv[])

{

//имя файла, который мы хотим упаковать

if(argc != 2)

{

std::cout << "Usage: simple_pe_packer.exe PE_FILE" << std::endl;

return 0;

}

//Открываем файл - его имя хранится в массиве argv по индексу 1

std::ifstream file(argv[1], std::ios::in | std::ios::binary);

if(!file)

{


//Если открыть файл не удалось - сообщим и выйдем с ошибкой

std::cout << "Cannot open " << argv[1] << std::endl;

return -1;

}

try

{

//Пытаемся открыть файл как 32-битный PE-файл

pe32 image(file, false, false);

//Проверим, не .NET ли

if(image.is_dotnet())

{

std::cout << ".NEt image cannot be packed!" << std::endl;

return -1;

}

//Просчитаем энтропию секций файла, чтобы убедиться, что файл не упакован

{

std::cout << "Entropy of sections: ";

double entropy = image.calculate_entropy();

std::cout << entropy << std::endl;

if(entropy > 6.8)

{

std::cout << "File has already been packed!" << std::endl;

return -1;

}

}

//Инициализируем библиотеку сжатия LZO

if(lzo_init() != LZO_E_OK)

{

std::cout << "Error initializing LZO library" << std::endl;

return -1;

}

std::cout << "Reading sections..." << std::endl;

//Получаем список секций PE-файла

const pe_base::section_list& sections = image.get_image_sections();

if(sections.empty())

{

//Если у файла нет ни одной секции, нам нечего упаковывать

std::cout << "File has no sections!" << std::endl;

return -1;

}

//Структура базовой информации о PE-файле

packed_file_info basic_info = {0};

//Получаем и сохраняем изначальное количество секций

basic_info.number_of_sections = sections.size();

//Запоминаем относительный адрес и размер

//оригинальной таблицы импорта упаковываемого файла

pe32 image(file, false, false);

//Проверим, не .NET ли

if(image.is_dotnet())

{

std::cout << ".NEt image cannot be packed!" << std::endl;

return -1;

}

//Просчитаем энтропию секций файла, чтобы убедиться, что файл не упакован

{

std::cout << "Entropy of sections: ";

double entropy = image.calculate_entropy();

std::cout << entropy << std::endl;

if(entropy > 6.8)

{

std::cout << "File has already been packed!" << std::endl;

return -1;

}

}

//Инициализируем библиотеку сжатия LZO

if(lzo_init() != LZO_E_OK)

{

std::cout << "Error initializing LZO library" << std::endl;

return -1;

}

std::cout << "Reading sections..." << std::endl;

//Получаем список секций PE-файла

const pe_base::section_list& sections = image.get_image_sections();

if(sections.empty())

{

//Если у файла нет ни одной секции, нам нечего упаковывать

std::cout << "File has no sections!" << std::endl;

return -1;

}

//Структура базовой информации о PE-файле

packed_file_info basic_info = {0};

//Получаем и сохраняем изначальное количество секций

basic_info.number_of_sections = sections.size();

//Запоминаем относительный адрес и размер

//оригинальной таблицы импорта упаковываемого файла

basic_info.original_import_directory_rva = image.get_directory_rva(IMAGE_DIRECTORY_ENTRY_IMPORT);

basic_info.original_import_directory_size = image.get_directory_size(IMAGE_DIRECTORY_ENTRY_IMPORT);

//Запоминаем его точку входа

basic_info.original_entry_point = image.get_ep();

//Запоминаем общий виртуальный размер всех секций

//упаковываемого файла

basic_info.total_virtual_size_of_sections = image.get_size_of_image();


//Строка, которая будет хранить последовательно Приложение 1

//структуры packed_section для каждой секции

std::string packed_sections_info;

{

//Выделим в строке необходимое количество памяти для этих стркуткр

packed_sections_info.resize(sections.size() * sizeof(packed_section));

//"Сырые" данные всех секций, считанные из файла и слепленные воедино

std::string raw_section_data;

//Индекс текущей секции

unsigned long current_section = 0;

//Перечисляем все секции

for(pe_base::section_list::const_iterator it = sections.begin(); it != sections.end(); ++it, ++current_section)

{

//Ссылка на очередную секцию

const pe_base::section& s = *it;

{

//Создаем структуру информации

//о секции в строке и заполняем ее

packed_section& info

= reinterpret_cast<packed_section&>(packed_sections_info[current_section * sizeof(packed_section)]);

//Характеристики секции

info.characteristics = s.get_characteristics();

//Указатель на файловые данные

info.pointer_to_raw_data = s.get_pointer_to_raw_data();

//Размер файловых данных

info.size_of_raw_data = s.get_size_of_raw_data();

//Относительный виртуальный адрес секции

info.virtual_address = s.get_virtual_address();

//Виртуальный размер секции

info.virtual_size = s.get_virtual_size();

//Копируем имя секции (оно максимально 8 символов)

memset(info.name, 0, sizeof(info.name));

memcpy(info.name, s.get_name().c_str(), s.get_name().length());

}

//Если секция пустая, переходим к следующей

if(s.get_raw_data().empty())

continue;

//А если не пустая - копируем ее данные в строку

//с данными всех секций

raw_section_data += s.get_raw_data();

}

//Если все секции оказались пустыми, то паковать нечего!

if(raw_section_data.empty())

std::cout << "All sections of PE file are empty!" << std::endl;

return -1;

}

packed_sections_info += raw_section_data;

}

//Новая секция

pe_base::section new_section;

new_section.set_name(".rsrc");

//Доступна на чтение, запись, исполнение

new_section.readable(true).writeable(true).executable(true);

//Ссылка на сырые данные секции

std::string& out_buf = new_section.get_raw_data();

//Мы используем тип lzo_align_t для того, чтобы

//память была выровняна как надо

//(из документации к LZO)

boost::scoped_array<lzo_align_t> work_memory(new lzo_align_t[LZO1Z_999_MEM_COMPRESS]);

//Длина неупакованных данных

lzo_uint src_length = packed_sections_info.size();

//Сохраним ее в нашу структуру информации о файле

basic_info.size_of_unpacked_data = src_length;

//Длина упакованных данных

//(пока нам неизвестна)

lzo_uint out_length = 0;

//Необходимый буфер для сжатых данных

//(длина исходя из документации к LZO)

out_buf.resize(src_length + src_length / 16 + 64 + 3);

//Производим сжатие данных

std::cout << "Packing data..." << std::endl;

if(LZO_E_OK !=

lzo1z_999_compress(reinterpret_cast<const unsigned char*>(packed_sections_info.data()),

src_length,

reinterpret_cast<unsigned char*>(&out_buf[0]),

&out_length,

work_memory.get())

)

{

//Если что-то не так, выйдем

std::cout << "Error compressing data!" << std::endl;


return -1;

}

std::cout << "Packing complete..." << std::endl;

//Сохраним длину упакованных данных в нашу структуру

basic_info.size_of_packed_data = out_length;

out_buf.resize(out_length);

//Собираем буфер воедино, это и будут

//финальные данные нашей новой секции

out_buf =

//Данные структуры basic_info

std::string(reinterpret_cast<const char*>(&basic_info), sizeof(basic_info))

//Выходной буфер

+ out_buf;

//Проверим, что файл реально стал меньше

if(out_buf.size() >= src_length)

{

std::cout << "File is incompressible!" << std::endl;

return -1;

}

{

//Сначала получим ссылку на самую первую

//существующую секцию PE-файла

const pe_base::section& first_section = image.get_image_sections().front();

//Установим виртуальный адрес для добавляемой секции (читай ниже)

new_section.set_virtual_address(first_section.get_virtual_address());

//Теперь получим ссылку на самю последнюю

//существующую секцию PE-файла

const pe_base::section& last_section = image.get_image_sections().back();

//Посчитаем общий размер виртуальных данных

DWORD total_virtual_size =

//Виртуальный адрес последней секции

last_section.get_virtual_address()

//Выровненный виртуальный размер последней секции

+ pe_base::align_up(last_section.get_virtual_size(), image.get_section_alignment())

//Минус виртуальный размер первой секции

- first_section.get_virtual_address();

//Удаляем все секции PE-файла

image.get_image_sections().clear();

//Изменяем файловое выравнивание, если вдруг оно было

//больше, чем 0x200 - это минимально допустимое

//для выровненных PE-файлов

image.realign_file(0x200);

//Добавляем нашу секцию и получаем ссылку на

//уже добавленную секцию с пересчитанными адресами и размерами

pe_base::section& added_section = image.add_section(new_section);

//Устанавливаем для нее необходимый виртуальный размер

image.set_section_virtual_size(added_section, total_virtual_size);

std::cout << "Creating imports..." << std::endl;

//Создаем импорты из библиотеки kernel32.dll

pe_base::import_library kernel32;

kernel32.set_name("kernel32.dll"); //Выставили имя библиотеки

//Создаем импортируемую функцию

pe_base::imported_function func;

func.set_name("LoadLibraryA"); //Ее имя

kernel32.add_import(func); //Добавляем ее к библиотеке

//И вторую функцию

func.set_name("GetProcAddress");

kernel32.add_import(func); //Тоже добавляем

//Получаем относительный адрес (RVA) поля load_library_a

//нашей структуры packed_file_info, которую мы расположили в самом

//начале добавленной секции

DWORD load_library_address_rva = pe_base::rva_from_section_offset(added_section,

offsetof(packed_file_info, load_library_a));

//Устанавливаем этот адрес как адрес

//таблицы адресов импорта (import address table)

kernel32.set_rva_to_iat(load_library_address_rva);

//Создаем список импортируемых библиотек

pe_base::imported_functions_list imports;

//Добавляем к списку нашу библиотеку

imports.push_back(kernel32);

//Настроим пересборщик импортов