Golang獲取機器碼(MachineCode、PhysicalId)
package main import ( "context" "crypto/md5" "crypto/rand" "encoding/base64" "encoding/hex" "errors" "fmt" "github.com/StackExchange/wmi" "golang.org/x/sys/windows" "net" "sort" "strings" "time" "unsafe" ) func main(){ t := time.Now() a:=GetPhysicalID() fmt.Println(time.Since(t), a) } func GetPhysicalID() string{ var ids []string if guid,err := getMachineGuid(); err != nil{ panic(err.Error()) }else{ ids = append(ids, guid) } if cpuinfo,err := getCPUInfo();err != nil && len(cpuinfo) > 0 { panic(err.Error()) }else{ ids = append(ids, cpuinfo[0].VendorID+cpuinfo[0].PhysicalID) } if mac,err := getMACAddress();err!=nil{ panic(err.Error()) }else{ ids = append(ids, mac) } sort.Strings(ids) idsstr := strings.Join(ids, "|/|") return GetMd5String(idsstr,true,true) } func getMACAddress() (string, error){ netInterfaces, err := net.Interfaces() if err != nil { panic(err.Error()) } mac,macerr := "",errors.New("無法獲取到正確的MAC地址") for i := 0; i < len(netInterfaces); i++ { //fmt.Println(netInterfaces[i]) if (netInterfaces[i].Flags & net.FlagUp) != 0 && (netInterfaces[i].Flags & net.FlagLoopback) == 0{ addrs, _ := netInterfaces[i].Addrs() for _, address := range addrs { ipnet, ok := address.(*net.IPNet) //fmt.Println(ipnet.IP) ifok && ipnet.IP.IsGlobalUnicast() { // 如果IP是全域性單撥地址,則返回MAC地址 mac = netInterfaces[i].HardwareAddr.String() return mac,nil } } } } return mac,macerr } type cpuInfo struct { CPUint32`json:"cpu"` VendorIDstring`json:"vendorId"` PhysicalID string`json:"physicalId"` } type win32_Processor struct { Manufacturerstring ProcessorID*string } func getCPUInfo() ([]cpuInfo, error) { var ret []cpuInfo var dst []win32_Processor q := wmi.CreateQuery(&dst, "") fmt.Println(q) if err := wmiQuery(q, &dst); err != nil { return ret, err } var procID string for i, l := range dst { procID = "" if l.ProcessorID != nil { procID = *l.ProcessorID } cpu := cpuInfo{ CPU:int32(i), VendorID:l.Manufacturer, PhysicalID: procID, } ret = append(ret, cpu) } return ret, nil } // WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging func wmiQuery(query string, dst interface{}, connectServerArgs ...interface{}) error { ctx := context.Background() if _, ok := ctx.Deadline(); !ok { ctxTimeout, cancel := context.WithTimeout(ctx, 3000000000)//超時時間3s defer cancel() ctx = ctxTimeout } errChan := make(chan error, 1) go func() { errChan <- wmi.Query(query, dst, connectServerArgs...) }() select { case <-ctx.Done(): return ctx.Err() case err := <-errChan: return err } } func getMachineGuid() (string, error) { // there has been reports of issues on 32bit using golang.org/x/sys/windows/registry, see https://github.com/shirou/gopsutil/pull/312#issuecomment-277422612 // for rationale of using windows.RegOpenKeyEx/RegQueryValueEx instead of registry.OpenKey/GetStringValue var h windows.Handle err := windows.RegOpenKeyEx(windows.HKEY_LOCAL_MACHINE, windows.StringToUTF16Ptr(`SOFTWARE\Microsoft\Cryptography`), 0, windows.KEY_READ|windows.KEY_WOW64_64KEY, &h) if err != nil { return "", err } defer windows.RegCloseKey(h) const windowsRegBufLen = 74 // len(`{`) + len(`abcdefgh-1234-456789012-123345456671` * 2) + len(`}`) // 2 == bytes/UTF16 const uuidLen = 36 var regBuf [windowsRegBufLen]uint16 bufLen := uint32(windowsRegBufLen) var valType uint32 err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`MachineGuid`), nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen) if err != nil { return "", err } hostID := windows.UTF16ToString(regBuf[:]) hostIDLen := len(hostID) if hostIDLen != uuidLen { return "", fmt.Errorf("HostID incorrect: %q\n", hostID) } return hostID, nil } //生成32位md5字串 func GetMd5String(s string, upper bool, half bool) string { h := md5.New() h.Write([]byte(s)) result := hex.EncodeToString(h.Sum(nil)) if upper == true { result = strings.ToUpper(result) } if half == true { result = result[8:24] } return result } //利用隨機數生成Guid字串 func UniqueId() string { b := make([]byte, 48) if _,err := rand.Read(b); err!=nil{ return "" } return GetMd5String(base64.URLEncoding.EncodeToString(b), true,false) }
這裡僅根據CPU、系統GUID和MAC地址來生成的機器碼。WINDOWS下貌似無法獲取硬碟序列號(沒找到怎麼獲取)