@StillDontKnowMyName
Кодер одного маленького проекта, к тому же новичок

На правильном ли я пути к удалению ненужных функций из памяти во время выполнения кода?

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

Способ удаления функций, который я нашёл
1. В конце каждой функции, подлежащей удалению, объявляются биты, которые потом можно будет найти:
#define fn_limit _asm{\
_emit 0x9c\
_emit 0x9c\
_emit 0x9c\
_emit 0x9c\
_emit 0x9c}

void DoSomething
{
    /// do something

    fn_limit;
}


2. В хуке или в функции, которая вызывала DoSomething, начиная от указателя функции начинается поиск последовательности битов из конца функции, что даёт информацию о размере функции и возможность удалить функцию из памяти с помощью memset(DoSomething, 0, calculated_size);

И здесь возникает первый вопрос: можно и нужно ли после этого вызывать delete, чтобы передать очищенную память в пользование ОС?

Мой теоритический способ (ещё не проверял, но интересно мнение опытных кодеров)
Что будет, если создать что-то вроде продвинутого singleton, который будет динамически выделять память для класса при запуске, а после выполнения функций можно будет вызвать функцию, которая просто сотрёт класс и отпустит память?
class MainClass
{
	MainClass* Get()
	{
		if (main_class == nullptr)
			main_class = new(std::nothrow) MainClass;

		return main_class;
	}

	void Destroy()
	{
		DWORD old;

		VirtualProtect(main_class, sizeof(MainClass), PAGE_EXECUTE_READWRITE, &old);
		memset(main_class, 0, sizeof(MainClass));
		VirtualProtect(main_class, sizeof(MainClass), old, &old);

		delete main_class;
		main_class = nullptr;
	}

	void DoSomething();

private:
	MainClass* main_class{ nullptr };
}

void main()
{
	MainClass* mc = MainClass::Get();

	if (mc)
		mc->DoSomething();

	MainClass::Destroy();
}
  • Вопрос задан
  • 181 просмотр
Решения вопроса 1
jcmvbkbc
@jcmvbkbc
"I'm here to consult you" © Dogbert
первый вопрос: можно и нужно ли после этого вызывать delete, чтобы передать очищенную память в пользование ОС?

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

Что будет, если создать что-то вроде продвинутого singleton, который будет динамически выделять память для класса при запуске, а после выполнения функций можно будет вызвать функцию, которая просто сотрёт класс и отпустит память?

В принципе это можно реализовать. Но приведённая реализация даже близко не делает того, что ты ожидаешь.
Сначала может показаться, что она работает. Память, правда, возвращаться в ОС не будет. Потом ты может быть заметишь, что код тоже остаётся на месте. Потом ты может быть заметишь, что программа иногда падает из-за NULL-пойнтера в каком-то другом объекте. Короче, если ты сможешь это отладить, у тебя прибавится знаний в том, как всё устроено на уровне ассемблера. Если не сможешь, то твою программу ждут чудесные падения, а тебя -- не менее чудесные баг-репорты.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
BacCM
@BacCM
C++ почти с рождения
Освободить память от функций не удастся. Выделение памяти под класс - это выделение памяти под его данные, а не под код.
Даже очитска памяти нулями сомнительна - код вполне может быть размещен в области памяти в которую запрещена запись.

Проще всего сделать динамически подгружаемую библиотеку с сервисными функциями, и после отработки твоих функций выгружать её из памяти.
Ответ написан
@odissey_nemo
Программист, ГИС-системы, растры, космоснимки
Это есть проклятие парадигмы бесконечной памяти современных компьютеров и сред разработки.
В ОС-РВ (RSX11-M) СМ-4 ( PDP-11), был ткой волшебный инструмент, Task Builder (TKB).
Для большой задачи (например на Фортране), не помещающейся в отведённую ей память (64 килобайт) ОС, создавался описатель загрузки программных модулей (в обиходе - оверлей), т.е. чёткое формализованное описание, какой модуль когда другой модуль вызывает, и какие из них находятся в памяти одновременно.
Естественно, такой подход требовал чёткого понимания своей задачи, проектирования структуры модулей и прочей дисциплины мышления.
И получалось буквально волшебно! Поработает программа. подёргает свой диск DK: (2.5 мегабайта! Не килобайты!) да и попросит: а вставьте ка мне ещё дисочек, на котором прописана мой вторая часть!
Вот оно, колдунство какое возможно было! Сегодня уже и не знаешь, какие библиотеки откуда и зачем прилинкованы))) А если памяти не хватает, надо брать другой компьютер. Или увольняться)))
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы