C++ обнуляет память функции
У меня есть небольшая идея, связанная с отражающей инъекцией DLL. Если вы не знаете, что такое рефлексивная инъекция DLL, вы можете проверить это здесь: https://github.com/stephenfewer/ReflectiveDLLInjection
Что в основном делает, это загружает dll в память, а затем вводит память в целевой процесс - по крайней мере, так происходит на самом деле. Я могу ошибаться, но это не имеет значения, атм.
задача
- Найти адрес памяти данной функции
- Найти размер данной функции
- Обнулить память, используя
SecureZeroMemory()
Код
#include "ReflectiveLoader.h"
extern HINSTANCE hAppInstance;
void Function1() { MessageBoxA(NULL, "Function 1 called!", "Test", MB_OK); }
void Function2() { MessageBoxA(NULL, "Function 2 called!", "Test", MB_OK); }
void Function3() { MessageBoxA(NULL, "Function 3 called!", "Test", MB_OK); }
void GetMemoryInformation()
{
void(*p_Func1)() = &Function1;
void(*p_Func2)() = &Function2;
void(*p_Func3)() = &Function3;
char buffer[300];
sprintf(buffer, "Function1 - Address: %p | Size: %zu \nFunction2 - Address: %p | Size: %zu \nFunction3 - Address: %p | Size: %zu",
p_Func1, sizeof(p_Func1),
p_Func2, sizeof(p_Func2),
p_Func3, sizeof(p_Func3)
);
MessageBoxA(NULL, buffer, "Memory information", MB_OK);
}
void ZeroMemoryFunctions()
{
void(*p_Func2)() = &Function2;
void(*p_Func3)() = &Function3;
SecureZeroMemory(p_Func2, sizeof(p_Func2));
SecureZeroMemory(p_Func3, sizeof(p_Func3));
}
DWORD WINAPI MainThread(LPVOID PARAMS)
{
MessageBoxA(NULL, "Main thread initialized!", "Entry", MB_OK);
for (;;)
{
if (GetAsyncKeyState(0x31) & 0x8000) Function1(); // key 1
if (GetAsyncKeyState(0x32) & 0x8000) Function2(); // key 2
if (GetAsyncKeyState(0x33) & 0x8000) Function3(); // key 3
if (GetAsyncKeyState(VK_UP) & 0x8000) GetMemoryInformation();
if (GetAsyncKeyState(VK_DOWN) & 0x8000) ZeroMemoryFunctions();
if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) MessageBoxA(NULL, "Main thread closed!", "Exit", MB_OK), ExitThread(0);
Sleep(100);
}
}
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved )
{
BOOL bReturnValue = TRUE;
switch( dwReason )
{
case DLL_QUERY_HMODULE:
if( lpReserved != NULL )
*(HMODULE *)lpReserved = hAppInstance;
break;
case DLL_PROCESS_ATTACH:
hAppInstance = hinstDLL;
MessageBoxA( NULL, "Reflective Dll injected!", "Injected", MB_OK );
CreateThread(0, 0, &MainThread, 0, 0, 0);
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return bReturnValue;
}
Что оно делает?
- Клавиши с 1 по 3, вызывает указанную функцию, которая отображает простое окно сообщения
- Стрелка вверх отображает окно сообщения с адресом функции и размером для каждой функции
- Стрелка вниз обнуляет функции
Function2()
а такжеFunction3()
- Escape обычно выходят из основного потока
Проблемы
Я очень плохо знаком с кодированием, связанным с памятью, поэтому уверен, что сделал что-то не так.
Я полагаю, что я получаю неправильный размер функции, и вместо этого я получаю размер указателя на функцию, я прав?
Во-вторых, если я позвоню ZeroMemoryFunctions()
и нажмите клавишу 1, все работает. Когда я нажимаю клавишу 2 или 3, целевой процесс падает, потому что память функций обнуляется. Это означает, что SecureZeroMemory()
работал, правильно? Но из-за неправильного размера блока, который нужно заполнить нулями, я считаю, что он был только частично обнулен.
1 ответ
У вас есть несколько проблем здесь:
- Вы не меняете защиту памяти (она может / должна читаться + выполняться), вам нужно сделать ее доступной для записи, например,
VirtualProtect
- Получить размер функции не так просто. Функции могут / будут разбиты на несколько частей компилятором, а некоторые могут быть встроенными и т. Д.
Возможные решения
Заказывается от самого простого к сложному (для правильной реализации).
- Переместите свои функции в отдельный раздел в файле PE. (с помощью
alloc_text
в msvc например) - Вставьте вспомогательные заглушки после функции, чтобы вы могли использовать их в качестве маркера размера. (см. примечание 1).
- Определите размер функции во время выполнения, используя дизассемблер, например
capstone
Примечание 1:
Используя такую конструкцию:
void function_to_erase()
{
// your logic here
}
void function_to_erase_helper()
{
// empty
}
Вы можете определить размер function_to_erase
вычитая адрес помощника из вашей функции, если и только если вы заставляете компилятор не переупорядочивать эти функции. (Project properties->Linker->Optimization->Function Order
)