c ++将函数的内存归零

c++ zero out memory of a function

我对反射dll注入有一点想法。如果你不知道反射dll注入是什么,你可以在这里查看:https://github.com/stephenfewer/ReflectiveDLLInjection

基本上是将 dll 加载到内存,然后将内存注入目标进程 - 至少那是 afaik 发生的事情。我可能是错的,但这并不重要。

任务

  1. 查找给定函数的内存地址
  2. 找到给定函数的大小
  3. 使用 SecureZeroMemory()
  4. 将内存归零

代码

#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;
}

它有什么作用?

问题

我对内存相关的编码很陌生,所以我很确定我做错了什么。

我认为我以错误的方式获取了函数的大小,而是获取了指向函数的指针的大小,对吗?

其次,如果我调用 ZeroMemoryFunctions() 并按下键 1,它会起作用。当我按下键 2 或 3 时,目标进程崩溃,导致函数内存清零。这意味着 SecureZeroMemory() 有效,对吗?但是由于用零填充的块大小错误,我相信它只是部分归零。

你这里有几个问题:

  • 您不更改内存保护(它可以/应该被读取+执行),您需要使其可写,例如 VirtualProtect
  • 获取函数大小不是一件容易的事。函数可以/将被编译器分解成多个部分,有些可能会被内联等。

可能的解决方案

从最简单到最难(正确实施)排序。

  • 将您的函数移动到 PE 文件中的单独部分。 (例如在 msvc 中使用 alloc_text
  • 在函数后插入辅助存根,这样您就可以将它们用作 'size' 标记。 (见注释 1)。
  • 使用 capstone
  • 等反汇编程序在运行时确定函数的大小

注1:

使用这样的构造:

void function_to_erase()
{
    // your logic here
}

void function_to_erase_helper()
{
    // empty
}

您可以通过从您的函数中减去辅助函数的地址来确定 function_to_erase 的大小,if,并且仅当您强制编译器不对这些函数重新排序时函数。 (Project properties->Linker->Optimization->Function Order)