C# 测试来自C的AES-NI指令#
我想知道是否有办法从C#NET测试主机系统的CPU中是否存在AES-NI 让我先说一下,这个问题不是问如何使用.NET中的AES-NI。事实证明,如果AES-NI可用,只需使用C# 测试来自C的AES-NI指令#,c#,.net,aes,C#,.net,Aes,我想知道是否有办法从C#NET测试主机系统的CPU中是否存在AES-NI 让我先说一下,这个问题不是问如何使用.NET中的AES-NI。事实证明,如果AES-NI可用,只需使用AESCryptServiceProvider即可。该结果基于我所做的独立基准测试,将AESCryptServiceProvider的性能与TrueCrypt中提供的基准测试进行比较,TrueCrypt确实支持AES-NI。结果惊人地相似,在两台机器上有和没有AES-NI 我希望能够测试它的原因是能够向用户指示他们的计算机
AESCryptServiceProvider
即可。该结果基于我所做的独立基准测试,将AESCryptServiceProvider
的性能与TrueCrypt中提供的基准测试进行比较,TrueCrypt确实支持AES-NI。结果惊人地相似,在两台机器上有和没有AES-NI
我希望能够测试它的原因是能够向用户指示他们的计算机支持AES-NI。这将是相关的,因为它将减少涉及“但我的朋友也有一个核心i5,但他的速度快得多!”等问题的支持事件。如果程序的用户界面可以向用户表明他们的系统支持或不支持AES-NI,也可以指出这一点“由于此系统不支持AES-NI,因此性能较慢是正常现象。”
(我们可以感谢英特尔对不同处理器步进的所有混淆!:-)
有没有一种方法可以检测到这些信息,也许是通过WMI?似乎也有类似的问题:答案很好 但是这个答案需要一些调整来适应你的需要 首先,据我所知,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;
}
就我所见,这就是所有的变化。上面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);
不知道答案,但我首先要看的是一些操作系统WMI调用。与论坛网站不同,我们不使用“谢谢”或“感谢任何帮助”或签名。请参阅。从外观上看,您需要调用EAX设置为1的汇编指令,这将在EDX和ECX中为处理器功能输出一些位标志。您关心ECX中的位25被设置为1,这意味着它支持AES-NI。唯一的问题是我无法找到通过托管代码或WMI从CPUID获取ECX值的方法。我最近得到的是WMI调用<代码>代码> WIN32处理器> /COD>属性,它是CPUID调用之后Eax和EDX寄存器的位掩码,但它不包括您关心的ECX。我如何在C++(GCC)上在Windows上做同样的操作?@ CANADANANYORD共和党,GCC支持CPUID:
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);