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

调用LoadEnclaveData返回错误码87(ERROR_INVALID_PARAMETER)如何解决

问题根因

你遇到的ERROR_INVALID_PARAMETER报错是由多个参数错误共同导致的:

  • LoadEnclaveData的第三个参数lpBuffer错误传递了&buffer,buffer本身就是存储NOP指令的数组首地址,不需要二次取址,取址后传递的是栈上数组指针的地址,完全不符合参数要求。
  • 你传入的nSize参数值为22,不符合必须是系统页大小整数倍的要求,Windows默认页大小为4096字节。
  • LoadEnclaveData的第8个参数lpNumberOfBytesWritten不能传0,必须传入一个可写的ULONG类型指针用于接收实际写入的字节数。

修正后代码示例

#include <windows.h>
#include <stdio.h>
#include <enclaveapi.h>

int main() {
    // 先确认VBS Enclave支持
    if (!IsEnclaveTypeSupported(ENCLAVE_TYPE_VBS)) {
        printf("[-] 当前环境不支持VBS Enclave\n");
        return 1;
    }

    // 获取系统页大小
    SYSTEM_INFO sysInfo = {0};
    GetSystemInfo(&sysInfo);
    DWORD pageSize = sysInfo.dwPageSize;

    HANDLE hProcess = GetCurrentProcess();
    ENCLAVE_CREATE_INFO_VBS createInfo = {0};
    createInfo.Flags = 0;

    // 创建Enclave,大小为2MB
    LPVOID enclaveBase = CreateEnclave(
        hProcess,
        NULL,
        2 * 1024 * 1024,
        NULL,
        ENCLAVE_TYPE_VBS,
        &createInfo,
        sizeof(ENCLAVE_CREATE_INFO_VBS),
        NULL
    );
    if (enclaveBase == NULL) {
        printf("[-] CreateEnclave失败,错误码:%d\n", GetLastError());
        return 1;
    }
    printf("[+] Enclave基地址:0x%p\n", enclaveBase);

    // 分配页对齐的缓冲区,填充NOP指令
    LPVOID codeBuffer = VirtualAlloc(NULL, pageSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (codeBuffer == NULL) {
        printf("[-] 分配代码缓冲区失败\n");
        return 1;
    }
    memset(codeBuffer, 0x90, pageSize);
    // 末尾加RET指令,执行完后返回宿主
    ((PBYTE)codeBuffer)[pageSize - 1] = 0xC3;

    // 加载数据到Enclave
    ULONG writtenBytes = 0;
    BOOL loadRes = LoadEnclaveData(
        hProcess,
        enclaveBase,
        codeBuffer,
        pageSize,
        PAGE_READWRITE,
        NULL,
        0,
        &writtenBytes,
        NULL
    );
    if (!loadRes) {
        printf("[-] LoadEnclaveData失败,错误码:%d\n", GetLastError());
        return 1;
    }
    printf("[+] 加载成功,写入字节数:%d\n", writtenBytes);

    // 修改内存属性为可执行
    BOOL setAttrRes = SetEnclaveProtectedMemoryAttribute(
        hProcess,
        enclaveBase,
        pageSize,
        ENCLAVE_MEMORY_ATTRIBUTE_EXECUTE,
        ENCLAVE_MEMORY_ATTRIBUTE_EXECUTE
    );
    if (!setAttrRes) {
        printf("[-] 修改内存属性失败,错误码:%d\n", GetLastError());
        return 1;
    }

    // 初始化Enclave
    ENCLAVE_INIT_INFO_VBS initInfo = {0};
    initInfo.Flags = 0;
    BOOL initRes = InitializeEnclave(
        hProcess,
        enclaveBase,
        &initInfo,
        sizeof(ENCLAVE_INIT_INFO_VBS)
    );
    if (!initRes) {
        printf("[-] InitializeEnclave失败,错误码:%d\n", GetLastError());
        return 1;
    }

    // 调用Enclave代码
    printf("[+] 即将调用Enclave代码\n");
    BOOL callRes = CallEnclave(enclaveBase, NULL, 0, NULL);
    if (!callRes) {
        printf("[-] CallEnclave失败,错误码:%d\n", GetLastError());
        return 1;
    }
    printf("[+] Enclave代码执行完成\n");

    VirtualFree(codeBuffer, 0, MEM_RELEASE);
    return 0;
}

Enclave代码执行注意事项

  • 不要直接调用EENTER汇编指令,直接使用微软封装的CallEnclave函数即可,内部已经处理了权限切换、参数传递等逻辑。
  • 加载到Enclave的代码必须是位置无关代码(PIC),不能包含硬编码的绝对地址,因为Enclave的基地址是运行时动态分配的。
  • Enclave内存不允许同时设置可写和可执行属性,写入代码时先用PAGE_READWRITE属性,写完之后再调用SetEnclaveProtectedMemoryAttribute修改为可执行属性。
  • 调用InitializeEnclave之后,Enclave的内存就会被锁定,无法再修改内容,所有代码和数据必须在初始化之前全部加载完成。
  • 不要直接向Enclave传递宿主进程的指针,所有需要访问的数据必须提前加载到Enclave内部的内存空间中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 04:54:08