我在这里找到了一段很好的代码,它使用 API 调用执行 ASM 指令以获得 CPU 的序列号:
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
[DllImport("user32", EntryPoint = "CallWindowProcW", CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] private static extern IntPtr ExecuteNativeCode([In] byte[] bytes, IntPtr hWnd, int msg, [In, Out] byte[] wParam, IntPtr lParam);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)] public static extern bool VirtualProtect([In] byte[] bytes, IntPtr size, int newProtect, out int oldProtect);
const int PAGE_EXECUTE_READWRITE = 0x40;
static void Main(string[] args)
{
string s = CPU32_SerialNumber();
Console.WriteLine("CPU Serial-Number: " + s);
Console.ReadLine();
}
private static string CPU32_SerialNumber()
{
byte[] sn = new byte[12];
if (!ExecuteCode32(ref sn))
return "ND";
return string.Format("{0}{1}{2}", BitConverter.ToUInt32(sn, 0).ToString("X"), BitConverter.ToUInt32(sn, 4).ToString("X"), BitConverter.ToUInt32(sn, 8).ToString("X"));
}
private static bool ExecuteCode32(ref byte[] result)
{
// CPU 32bit SerialNumber -> asm x86 from c# (c) 2003-2011 Cantelmo Software
// 55 PUSH EBP
// 8BEC MOV EBP,ESP
// 8B7D 10 MOV EDI,DWORD PTR SS:[EBP+10]
// 6A 02 PUSH 2
// 58 POP EAX
// 0FA2 CPUID
// 891F MOV DWORD PTR DS:[EDI],EBX
// 894F 04 MOV DWORD PTR DS:[EDI+4],ECX
// 8957 08 MOV DWORD PTR DS:[EDI+8],EDX
// 8BE5 MOV ESP,EBP
// 5D POP EBP
// C2 1000 RETN 10
int num;
byte[] code_32bit = new byte[] { 0x55, 0x8b, 0xec, 0x8b, 0x7d, 0x10, 0x6a, 2, 0x58, 15, 0xa2, 0x89, 0x1f, 0x89, 0x4f, 4, 0x89, 0x57, 8, 0x8b, 0xe5, 0x5d, 0xc2, 0x10, 0 };
IntPtr ptr = new IntPtr(code_32bit.Length);
if (!VirtualProtect(code_32bit, ptr, PAGE_EXECUTE_READWRITE, out num))
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
ptr = new IntPtr(result.Length);
return (ExecuteNativeCode(code_32bit, IntPtr.Zero, 0, result, ptr) != IntPtr.Zero);
}
}
}
我测试了它,它对我来说工作正常。但我仍然有一些与之相关的疑问和问题:
1)我想在可以在 x86 和 x64 环境中运行的应用程序中实现此代码。如果我将此代码运行到 64x 环境中,我会收到 AccessViolationException。代码的作者说,这可以很容易地实现,还可以实现一个包含 x64 指令(RAX、RBX、RCX、RDX ......)的字节码数组。我的问题是我完全不知道如何将 86x 字节码转换为 x64 字节码,事实上我什至不知道 ASM。是否有任何转换表或实用程序可以做到这一点?
2) 这个代码片段对任何类型的处理器都有效吗?我在使用英特尔内核的笔记本电脑上对其进行了测试,它可以工作……但是例如 AMD 呢?
3) 我不确定我获得的值是否正确。如果我运行以下代码:
string cpuInfo = String.Empty;
System.Management.ManagementClass mc = new System.Management.ManagementClass("Win32_Processor");
System.Management.ManagementObjectCollection moc = mc.GetInstances();
foreach (System.Management.ManagementObject mo in moc)
{
if (cpuInfo == String.Empty)
cpuInfo = mo.Properties["ProcessorId"].Value.ToString();
}
我得到的结果是“BFEBFBFF000306A9”。代码片段的结果是“F0B2FF0CA0000”。为什么?哪一个是正确的?