我想知道是否有办法从C#.NET测试主机系统的CPU中是否存在AES-NI。
让我先说一下,这个问题是,而不是,它询问如何使用.NET的AES-NI,如果可用的话,简单地使用AESCryptoServiceProvider就会使用AES-NI。这个结果基于独立的基准,我比较了AESCryptoServiceProvider的性能和TrueCrypt中提供的基准,后者确实支持AES-NI。结果令人惊讶的相似,在这两台机器都有和没有AES-NI。
我希望能够对其进行测试的原因是能够向用户表明他们的计算机支持AES-NI。这将是相关的,因为它将减少支持事件涉及的问题,如“但我的朋友也有一个核心i5,但他的更快!”如果程序的用户界面可以向用户表明他们的系统支持或不支持AES-NI,那么也可以指出“性能较慢是正常的,因为此系统不支持AES-NI”。
(我们可以感谢英特尔在不同处理器步骤中所造成的混乱!:-)
是否有一种方法来检测这些信息,也许是通过WMI?
发布于 2015-01-13 06:32:29
似乎也有类似的问题:Inline Assembly Code to Get CPU ID给出了很好的答案。
但是这个答案需要一些调整来适应你的需要。
首先,据我所知,AES-NI只能出现在64位处理器上,对吗?然后,您可以忽略上述答案中的所有32位代码。
其次,您需要ECX寄存器,或者更确切地说是它的第25位,所以您必须稍微修改代码:
private static bool IsAESNIPresent()
{
byte[] sn = new byte[16]; // !!! Here were 8 bytes
if (!ExecuteCode(ref sn))
return false;
var ecx = BitConverter.ToUInt32(sn, 8);
return (ecx & (1 << 25)) != 0;
}最后,您需要在数组中存储ECX寄存器:
byte[] code_x64 = new byte[] {
0x53, /* push rbx */
0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00, /* mov rax, 0x1 */
0x0f, 0xa2, /* cpuid */
0x41, 0x89, 0x00, /* mov [r8], eax */
0x41, 0x89, 0x50, 0x04, /* mov [r8+0x4], ebx !!! changed */
0x41, 0x89, 0x50, 0x08, /* mov [r8+0x8], ecx !!! added */
0x41, 0x89, 0x50, 0x0C, /* mov [r8+0xC], edx !!! added*/
0x5b, /* pop rbx */
0xc3, /* ret */
};据我所知,这是所有的变化。
发布于 2018-02-12 23:39:19
上面Mark的回答非常棒,而且对我来说效果很好,但是我确实注意到,如果应用程序是以32位模式运行的,那么ecx寄存器就不会在x86代码中被拔出,从而导致无法检测到AES-NI。
我增加了一行,修改了另一行,基本上将标记对x64代码所做的更改应用到x86代码中。这允许您从32位模式中看到AES-NI位。我不确定它是否会对某人有帮助,但我想我应该把它发出去。
编辑:当我做一些测试时,我注意到x64代码返回的寄存器是不正确的。EDX在偏移量0x4、0x8和0xC处返回,此外,ECX和EDX寄存器与x86代码处于不同的偏移量,因此您需要更频繁地检查IntPtr.Size,以确保在这两种环境中都能正常工作。为了简化操作,我将ECX寄存器放在0x4,EDX放在0x8,这样就可以正确地排列数据。
如果有人要求,我可以张贴整个类,这是我从这篇文章和其他文章中学到的一个有用的例子。
public static bool ExecuteCode(ref byte[] result) {
byte[] code_x86 = new byte[] {
0x55, /* push ebp */
0x89, 0xE5, /* mov ebp, esp */
0x57, /* push edi */
0x8b, 0x7D, 0x10, /* mov edi, [ebp+0x10] */
0x6A, 0x01, /* push 0x1 */
0x58, /* pop eax */
0x53, /* push ebx */
0x0F, 0xA2, /* cpuid */
0x89, 0x07, /* mov [edi], eax */
0x89, 0x4F, 0x04, /* mov [edi+0x4], ecx Changed */
0x89, 0x57, 0x08, /* mov [edi+0x8], edx Changed */
0x5B, /* pop ebx */
0x5F, /* pop edi */
0x89, 0xEC, /* mov esp, ebp */
0x5D, /* pop ebp */
0xC2, 0x10, 0x00, /* ret 0x10 */
};
byte[] code_x64 = new byte[] {
0x53, /* push rbx */
0x48, 0xC7, 0xC0, 0x01, 0x00, 0x00, 0x00, /* mov rax, 0x1 */
0x0f, 0xA2, /* cpuid */
0x41, 0x89, 0x00, /* mov [r8], eax */
0x41, 0x89, 0x48, 0x04, /* mov [r8+0x4], ecx Changed */
0x41, 0x89, 0x50, 0x08, /* mov [r8+0x8], edx Changed*/
0x5B, /* pop rbx */
0xC3, /* ret */
};
int num;
byte[] code = (IntPtr.Size == 4) ? code_x86 : code_x64;
IntPtr ptr = new IntPtr(code.Length);
if (!VirtualProtect(code, ptr, PAGE_EXECUTE_READWRITE, out num))
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
ptr = new IntPtr(result.Length);
return (ExecuteNativeCode(code, IntPtr.Zero, 0, result, ptr) != IntPtr.Zero);https://stackoverflow.com/questions/27914712
复制相似问题