C++ обнуляет память функции

У меня есть небольшая идея, связанная с отражающей инъекцией DLL. Если вы не знаете, что такое рефлексивная инъекция DLL, вы можете проверить это здесь: https://github.com/stephenfewer/ReflectiveDLLInjection

Что в основном делает, это загружает dll в память, а затем вводит память в целевой процесс - по крайней мере, так происходит на самом деле. Я могу ошибаться, но это не имеет значения, атм.

задача

  1. Найти адрес памяти данной функции
  2. Найти размер данной функции
  3. Обнулить память, используя 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)

Другие вопросы по тегам