PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON的十六进制值及C#中IntPtr转换实现
核心实现逻辑
首先理清两个容易卡壳的关键认知,避免走弯路:
- 官方给出的常量定义根本不需要到处搜十六进制值,直接复用文档里的移位逻辑在C#里定义,就能得到完全等价的结果
- PInvoke.net上写的
IntPtr类型参数本身没问题,但这个类型是用来表示通用内存指针的,不是直接用来存要设置的策略值本身,搞反了指针和值的关系是90%的人调用失败的原因
第一步:定义和官方完全匹配的常量
直接照搬文档的移位逻辑写常量,从根源上避免手动换算十六进制算错的问题:
// 对应PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON public const ulong BlockNonMicrosoftBinariesAlwaysOnPolicy = 1UL << 44; // 对应UpdateProcThreadAttribute的缓解策略属性标识 public const IntPtr ProcThreadAttributeMitigationPolicy = (IntPtr)0x00020007;
如果需要准确的十六进制参考,1UL << 44 换算后的实际值为 0x0010000000000000,和官方定义完全一致。
第二步:匹配API的参数要求
当你要设置进程缓解策略时,API对这个属性的固定要求是:
lpValue传入的是指向8字节ULONG64类型策略值的指针,不是把值强转成IntPtr直接传cbSize参数固定填8字节,和当前进程的位宽没有关系
第三步:可直接复用的调用代码
[DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool UpdateProcThreadAttribute( IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue, nuint cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize ); // 已通过InitializeProcThreadAttributeList拿到合法属性列表句柄后,调用该方法设置策略 void ConfigureMitigationPolicy(IntPtr attributeListHandle) { // 分配能容纳8字节策略值的非托管内存 IntPtr pPolicyBuffer = Marshal.AllocHGlobal(sizeof(ulong)); try { // 把要设置的策略值写入分配的内存 Marshal.WriteInt64(pPolicyBuffer, (long)BlockNonMicrosoftBinariesAlwaysOnPolicy); bool isSuccess = UpdateProcThreadAttribute( lpAttributeList: attributeListHandle, dwFlags: 0, Attribute: ProcThreadAttributeMitigationPolicy, lpValue: pPolicyBuffer, cbSize: (nuint)sizeof(ulong), // 固定传8字节,不要偷懒用IntPtr.Size lpPreviousValue: IntPtr.Zero, lpReturnSize: IntPtr.Zero ); if (!isSuccess) { throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } } finally { // 用完必须释放内存,避免泄漏 Marshal.FreeHGlobal(pPolicyBuffer); } }
高频踩坑提醒
- 千万别直接把策略值强转成IntPtr当lpValue传:这种写法相当于把策略值当成内存地址传给API,要么直接触发内存访问违规崩溃,要么读到随机内存值,完全达不到设置策略的效果
- 别把cbSize设成
IntPtr.Size:32位进程下IntPtr大小是4字节,和API要求的8字节固定长度不匹配,会直接返回参数错误 - 该缓解策略从Windows 10 1709版本才开始支持,在更早的系统上调会直接返回不支持的错误
- 除了用
Marshal.AllocHGlobal分配内存,也可以用GCHandle钉住托管的字节数组传指针,只要保证传入的内存长度、值正确就行
内容的提问来源于stack exchange,提问作者Anonymous-User
相关产品推荐
相关产品推荐

