内核模式下InitializeSecurityContextW二次调用返回SEC_E_INVALID_HANDLE问题
内核模式下InitializeSecurityContextW的正确用法及问题修复
核心参数规则(内核与用户模式差异)
内核模式下调用InitializeSecurityContextW时,phContext和phNewContext的处理逻辑和用户模式完全不同:- 第一次调用时,
phContext必须设为NULL,phNewContext传入指向PCtxtHandle的有效指针,用于接收初始上下文句柄。 - 后续调用(返回
SEC_I_CONTINUE_NEEDED后),必须将第一次调用得到的上下文句柄传入phContext,同时phNewContext必须和phContext指向同一个PCtxtHandle变量——内核模式下Schannel不会创建新上下文,而是直接复用并更新传入的句柄。
- 第一次调用时,
修复调用流程
- 初始化阶段:
若返回PCtxtHandle hContext = NULL; SECURITY_STATUS status = InitializeSecurityContextW( &credHandle, // 已初始化的凭据句柄 NULL, // 第一次调用phContext为NULL targetName, // 目标服务器名称 ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT, 0, SECURITY_NATIVE_DREP, NULL, // 第一次调用无输入token 0, &hContext, // phNewContext指向hContext变量 &outputBuffer, &attrs, &expiry );SEC_I_CONTINUE_NEEDED,此时hContext已持有有效部分上下文。 - 第二次及后续调用:
注意:内核模式下不能将status = InitializeSecurityContextW( &credHandle, hContext, // phContext传入之前得到的句柄 targetName, ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT, 0, SECURITY_NATIVE_DREP, &inputBuffer, // 从对方接收的token 0, &hContext, // phNewContext必须和phContext指向同一个变量 &outputBuffer, &attrs, &expiry );phNewContext设为NULL,也不能让phContext和phNewContext指向不同变量,否则会触发句柄无效或内存访问违例。
- 初始化阶段:
避免BSOD的关键注意事项
- 仅当上下文句柄确实有效时才能调用
DeleteSecurityContext,若第一次调用后上下文未正确初始化(如参数错误导致的无效句柄),调用该函数会直接触发内核崩溃。 - 所有缓冲区(输入/输出token)必须使用内核模式内存分配函数(如
ExAllocatePoolWithTag),禁止使用用户模式内存,否则会导致跨权限访问违例。 - 凭据句柄(
CredHandle)必须通过AcquireCredentialsHandleW正确初始化,且在上下文生命周期内保持有效。
- 仅当上下文句柄确实有效时才能调用
文档误差说明
官方文档对内核模式下phNewContext的描述存在错误,实际内核模式Schannel驱动(ksecdd.sys)要求:无论第几次调用,phNewContext都必须是有效指针,且后续调用中必须与phContext指向同一变量——内核侧不会分配新的上下文结构,而是直接更新传入句柄指向的内容。
内容的提问来源于stack exchange,提问作者Louis Bernard
相关产品推荐
相关产品推荐

