Pull to refresh

Кастомный аллокатор для закрытого 3rd

Reading time2 min
Views1.8K

Что и зачем

Существует ряд ситуаций, когда это имеет смысл. От полного контроля памяти, до вынужденной необходимости. К примеру, одна из возможных ситуаций:

  1. Мы используем alignment аллокаторы.

  2. Мы перегружаем какой-то класс и данные от нашей 3rd зависимости.

  3. 3rd зависимость не использует alignment аллокаторы.

Ищем new/delete/malloc/free

Если нам повезёт, то 3rd может иметь свои new/delete операторы, которые были экспортированы. Хотя везением это сложно назвать, т.к. придётся ковыряться в дизассемблированном коде. Если вы решили не заморачиваться с поиском адресов, то этот шаг можно пропустить.

Немного помучавшись, можно прийти к следующему:

Затем, нам нужен RVA адрес функции.

Для начала получаем адрес dll в памяти:

После чего вычисляем адрес нашего символа:

00007FFC9BB7D760 - Symbol
00007FFC9BAF0000 - Base adress

// Без адреса входа
B7D760 
AF0000

D760 // Раз адрес кончается на 0000, то D760 просто запоминаем
0000 // Те самые ноли 

// Получаем первые два символа адреса 
b7 - af = 08

// Конечный итог
08D760

Осталось только достать Ordinal. Для этого подойдёт тот же CFF Explorer:

Видим заветные 5CD. Они нам и нужны.

Перегружаем символ

Теперь переходим к более интересной части. Итак, для начала нам потребуется библиотека для создание хуков в рантайме. К примеру, minhook.

Далее пишем базовый код:

using OperatorNewFunc = void* (*)(size_t size);


struct InitialHook
{
	InitialHook()
	{
		MH_STATUS ResultCode = MH_Initialize();

        // Загружаем наш символ из модуля 
		HMODULE hMFC = GetModuleHandle("mfc140.dll");

        // Загружаем ordinal 
		OperatorNewFunc hOperatorNew = (OperatorNewFunc)GetProcAddress(hMFC, MAKEINTRESOURCE(0x5CD));
		
		ResultCode = MH_CreateHook(hOperatorNew, /* Вставьте свой каллбек */, nullptr);
		MH_EnableHook(hOperatorNew);
	}
};

Однако, если же вы решили не искать адрес, то просто достаём malloc из ucrtbase.dll


	HMODULE hCRT = GetModuleHandle("ucrtbase.dll");
	OperatorNewFunc hFreeFunc = (OperatorNewFunc)GetProcAddress(hCRT, "malloc");

Вторым аргументом для MH_CreateHook передаём нашу новую функцию аллокации памяти.

А теперь самое важно. Нужно заставить компилятор выполнять инициализацию нашей структуры раньше остальных глобальных функций.

// Регистрируем секцию
#pragma section(".Hook",read)

using OperatorNewFunc = void* (*)(size_t size);

struct InitialHook
{
	InitialHook()
	{
		MH_STATUS ResultCode = MH_Initialize();

        // Загружаем наш символ из модуля 
		HMODULE hMFC = GetModuleHandle("mfc140.dll");
		OperatorNewFunc hOperatorNew = (OperatorNewFunc)GetProcAddress(hMFC, MAKEINTRESOURCE(0x5CD));
		
		ResultCode = MH_CreateHook(hOperatorNew, /* Вставьте свой каллбек */, nullptr);
		MH_EnableHook(hOperatorNew);
	}
};

// Определям символ нашей структуры 
#pragma init_seg(lib)
__declspec(allocate(".Hook"))
static const InitialHook HookInit;

Более подробно об этом можно почитать тут.

Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
Total votes 4: ↑3 and ↓1+2
Comments3

Articles