You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不使用RtlInitUnicodeString设置PUNICODE_STRING及C2326报错咨询

错误原因分析
  • C2326报错是语法规则限制导致:C++不允许在结构体的默认成员初始化器中访问外层函数的局部变量。你在main函数内部定义_params结构体时,直接给ModuleFileName成员设置默认值为&dllName,但dllName是main函数的栈局部变量,结构体的默认初始化逻辑不在main的作用域范围内,没有权限访问该变量,因此触发编译错误。
  • 替换为Beep函数可以正常运行的原因是,Beep对应的参数你都用常量做默认初始化,没有引用外层的局部变量,自然不会触发作用域访问权限问题。
其他需要修正的问题
  1. _LdrLoadDll的函数签名定义错误:标准LdrLoadDll的返回值是NTSTATUS,最后一个参数是PHMODULE(用于输出模块句柄的一级指针),不是你写的PHANDLE*二级指针,签名错误会导致调用时栈不平衡,即使编译通过也会崩溃。
  2. 远程线程注入逻辑存在本质缺陷:你当前直接把本地进程的栈变量地址(&dllName、字符串常量地址)传给远程进程,远程进程无法访问本地进程的地址空间,就算编译通过,调用LdrLoadDll也会直接触发访问违规。
修正代码示例
#include <windows.h>
#include <winternl.h>
#pragma comment(lib, "ntdll.lib")

EXTERN_C NTSYSAPI NTSTATUS NTAPI NtCreateThreadEx(PHANDLE,
    ACCESS_MASK, LPVOID, HANDLE, LPVOID, LPVOID,
    BOOL, SIZE_T, SIZE_T, SIZE_T, LPVOID);

// 修正LdrLoadDll的函数签名
typedef NTSTATUS(__stdcall* _LdrLoadDll)(
    PWSTR PathToFile,
    PULONG Flags,
    PUNICODE_STRING ModuleFileName,
    PHMODULE ModuleHandle
    );

// 把参数结构体挪到main外面定义
struct InjectParams {
    ULONG Flags;
    UNICODE_STRING dllName;
    WCHAR dllPath[MAX_PATH];
    HMODULE hModule;
};

int main()
{
    DWORD targetProcId = 212;
    HANDLE targetOpened = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetProcId);
    if (!targetOpened) return 1;
 
    _LdrLoadDll LdrLoadDll = (_LdrLoadDll)GetProcAddress(GetModuleHandleA("ntdll.dll"), "LdrLoadDll");
    if (!LdrLoadDll) return 1;

    // 先在本地构造参数
    InjectParams localParams = {0};
    wcscpy_s(localParams.dllPath, L"C:\\DllTest32.dll");
    localParams.dllName.Buffer = localParams.dllPath;
    localParams.dllName.Length = wcslen(localParams.dllPath) * sizeof(WCHAR);
    localParams.dllName.MaximumLength = sizeof(localParams.dllPath);

    // 把参数整体写入目标进程内存
    LPVOID remoteParamsAddr = VirtualAllocEx(targetOpened, NULL, sizeof(InjectParams), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (!remoteParamsAddr) return 1;
    WriteProcessMemory(targetOpened, remoteParamsAddr, &localParams, sizeof(InjectParams), NULL);

    // 修正UNICODE_STRING的Buffer地址为目标进程内的地址
    ULONG_PTR bufferOffset = offsetof(InjectParams, dllPath);
    UNICODE_STRING remoteDllName = localParams.dllName;
    remoteDllName.Buffer = (PWSTR)((ULONG_PTR)remoteParamsAddr + bufferOffset);
    WriteProcessMemory(targetOpened, (PVOID)((ULONG_PTR)remoteParamsAddr + offsetof(InjectParams, dllName)), &remoteDllName, sizeof(UNICODE_STRING), NULL);

    // 构造传给LdrLoadDll的参数列表
    struct _LdrCallParams {
        PWSTR PathToFile = NULL;
        PULONG Flags = NULL;
        PUNICODE_STRING ModuleFileName;
        PHMODULE ModuleHandle;
    } ldrParams;
    ldrParams.ModuleFileName = (PUNICODE_STRING)((ULONG_PTR)remoteParamsAddr + offsetof(InjectParams, dllName));
    ldrParams.ModuleHandle = (PHMODULE)((ULONG_PTR)remoteParamsAddr + offsetof(InjectParams, hModule));

    LPVOID remoteLdrParamsAddr = VirtualAllocEx(targetOpened, NULL, sizeof(_LdrCallParams), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    WriteProcessMemory(targetOpened, remoteLdrParamsAddr, &ldrParams, sizeof(_LdrCallParams), NULL);

    HANDLE rt;
    NtCreateThreadEx(
        &rt, PROCESS_ALL_ACCESS, NULL, targetOpened,
        LdrLoadDll,
        remoteLdrParamsAddr,
        FALSE, NULL, NULL, NULL, NULL);

    // 后续可以等待线程执行完成,读取目标进程里的hModule值判断是否加载成功
    WaitForSingleObject(rt, INFINITE);
    CloseHandle(rt);
    VirtualFreeEx(targetOpened, remoteParamsAddr, 0, MEM_RELEASE);
    VirtualFreeEx(targetOpened, remoteLdrParamsAddr, 0, MEM_RELEASE);
    CloseHandle(targetOpened);
    return 0;
}

内容的提问来源于stack exchange,提问作者Gorilka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 08:18:00