Читаем Защита от хакеров корпоративных сетей полностью

// class_tres1.cpp : Defines the entry point for the console

// application.

#include

#include

class test1

{

public:

char name[10];

virtual ~test1;

virtual void run;

};

class test2

{

public:

char name[10];

virtual ~test2;

virtual void run;

};

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

{

class test1 *t1 = new class test1;

class test1 *t5 = new class test1;

class test2 *t2 = new class test2;

class test2 *t3 = new class test2;

//////////////////////////////////////

// overwrite t2”s virtual function

// pointer w/ heap address

// 0x00301E54 making the destructor

// appear to be 0x77777777

// and the run function appear to

// be 0x88888888

//////////////////////////////////////

strcpy(t3->name, «\x77\x77\x77\x77\x88\x88\x88\x88XX

XXXXXXXXXX”\ “XXXXXXXXXX XXXXXXXXXX XXXXXXXXXX

XXXX\x54\x1E\x30\x00");

delete t1;

delete t2; // causes destructor 0x77777777 to be called

delete t3;

return 0;

}

void test1::run

{

}

test1::~test1

{

}

void test2::run

{

puts(“hey”);

}

test2::~test2

{

}

На рисунке 8.24 приведены пояснения к примеру. Близость между объектами динамически распределяемой памяти позволяет во время переполнения буфера подменить указатель виртуальных функций соседнего объекта динамически распределяемой памяти. Подмененный указатель начинает указывать на контролируемый буфер с новой таблицей виртуальных функций. При попытке вызова функций класса будут вызываться функции, на которые указывают указатели в новой таблице виртуальных функций. Лучше всего подменить указатель на деструктор класса, поскольку он всегда вызывается при удалении объекта из памяти.

Рис. 8.24. Нарушение границы динамически распределяемой памяти

Новаторские принципы построения программного кода полезной нагрузки

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

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

Использование того, что у вас есть

Даже простые программы часто загружают в память больше программных модулей, чем им действительно нужно. При установке связи с динамически подключаемой библиотекой программа определяет, когда загружать библиотеку: при запуске программы или во время ее выполнения. К сожалению, при использовании динамически подключаемой библиотеки DLL или совместно используемой библиотеки в системе UNIX в память загружается программный код всей библиотеки, а не только необходимые функции. Это означает, что в программу включается не только необходимый программный код, но и масса дополнительных функций. Современные операционные системы и мощные компьютеры не видят в этом ничего плохого, поскольку лишний программный код никогда не будет выполнен и, следовательно, он не окажет никакого воздействия на работу программы.

Но у злоумышленника другое отношение к дополнительному никогда не выполняющемуся коду. Для него он может оказаться чрезвычайно полезным. Его можно использовать для поиска не только точек перехода, но и уже загруженных в память полезных битов и фрагментов программного кода. При условии частой загрузки динамически подключаемых библиотек можно использовать загруженные неиспользуемые функции.

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже