返回> 网站首页 

运行时修改段数据

yoours2026-05-30 09:36:26 阅读 13

简介一边听听音乐,一边写写文章。

一、问题来源

    https://www.52pojie.cn/thread-2108051-1-1.html

    动态修改段数据,实现函数不导出调用。


二、动态库1

typedef const char* (*EncryptFunc)(const char*, const char*);


// 不导出,但我们需要让加密模块能找到它

// 我们可以放置一个特殊的标记(例如一个已知的字符串)来定位

struct CallbackHolder {

    EncryptFunc callback;      // 目标指针

    char marker[16];           // 标记 "CRYPTO_CB_MARK"

} g_holder = { nullptr, "CRYPTO_CB_MARK" };


void DoHttpRequest(const char* url, const char* body)

{

    if (g_holder.callback)

    {

        const char* headers = g_holder.callback(url, body);

        printf("[Network] Encrypted: %s\n", headers);

    }else {

        printf("[Network] No callback.\n");

    }

}


extern "C" __declspec(dllexport) void SendRequest(const char* url, const char* body)

{

    DoHttpRequest(url, body);

}


三、动态库2
typedef const char* (*EncryptFunc)(const char*, const char*);
const char* MyEncrypt(const char* url, const char* body)
{
    static char buf[256];
    sprintf_s(buf, "Encrypted[adv]:%s-%s", url, body);
    return buf;
}

// 在目标模块的 data 段中搜索标记字符串,然后修改紧邻的 callback 指针
void RegisterToNetworkByScan()
{
    HMODULE hNetwork = GetModuleHandleA("MFCLibrary1.dll");
    if (!hNetwork)
        return;

    // 获取模块的 DOS 头和 NT 头
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)hNetwork;
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((BYTE*)hNetwork + pDos->e_lfanew);
    PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNt);

    // 遍历所有节,找到 .data 节
    for (WORD i = 0; i < pNt->FileHeader.NumberOfSections; ++i)
    {
        if (memcmp(pSection->Name, ".data", 5) == 0)
        {
            DWORD dataRVA = pSection->VirtualAddress;
            DWORD dataSize = pSection->Misc.VirtualSize;
            BYTE* pData = (BYTE*)hNetwork + dataRVA;

            // 在 .data 段中搜索标记 "CRYPTO_CB_MARK"
            const char* marker = "CRYPTO_CB_MARK";
            size_t markerLen = strlen(marker);
            for (DWORD offset = 0; offset < dataSize - markerLen; ++offset)
            {
                if (memcmp(pData + offset, marker, markerLen) == 0)
                {
                    // 找到了标记,回调指针紧邻在标记之前(结构体定义中 callback 在前)
                    // 结构体: { EncryptFunc callback; char marker[16]; }
                    // 所以 callback 的地址 = pData + offset - sizeof(EncryptFunc)
                    EncryptFunc* pCallback = (EncryptFunc*)(pData + offset - sizeof(EncryptFunc));
                    // 修改内存保护属性
                    DWORD oldProtect;
                    VirtualProtect(pCallback, sizeof(EncryptFunc), PAGE_READWRITE, &oldProtect);
                    *pCallback = MyEncrypt;
                    VirtualProtect(pCallback, sizeof(EncryptFunc), oldProtect, &oldProtect);
                    printf("[Crypto] Found marker at offset %d, callback set.\n", offset);
                    return;
                }
            }
        }
        ++pSection;
    }
    printf("[Crypto] Marker not found.\n");
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID) {
    if (reason == DLL_PROCESS_ATTACH) {
        RegisterToNetworkByScan();
    }
    return TRUE;
}

四、应用程序
typedef void (*SendRequestFunc)(const char*, const char*);

HMODULE hNetwork = LoadLibraryA("MFCLibrary1.dll");
HMODULE hCrypto = LoadLibraryA("MFCLibrary2.dll");

// 获取网络模块的发送函数
SendRequestFunc SendRequest = (SendRequestFunc)GetProcAddress(hNetwork, "SendRequest");
if (SendRequest)
{
SendRequest("https://api.example.com/login", "username=test");
}

FreeLibrary(hCrypto);
FreeLibrary(hNetwork);

五、结论
    该方法可实现不导出DLL函数,在运行时实现调用。动态修改的函数地址可经过二次加密,应用于防破解或保护算法模块等场景。

微信小程序扫码登陆

文章评论

13人参与,0条评论