ここで、CPU のシリアル番号を取得するために API 呼び出しを使用して ASM 命令を実行する素晴らしいコードを見つけました。
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) このコード スニペットはどのタイプのプロセッサでも有効ですか? Intelコアを使用するラップトップでテストしましたが、動作します...しかし、たとえば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」です。なんで?どちらが正しいですか?