分享
  1. 首页
  2. 文章

Golang获取机器码(MachineCode、PhysicalId)

sdlyfjx · · 10862 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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)
				if ok && ipnet.IP.IsGlobalUnicast() {
					// 如果IP是全局单拨地址,则返回MAC地址
					mac = netInterfaces[i].HardwareAddr.String()
					return mac,nil
				}
			}
		}
	}
	return mac,macerr
}
type cpuInfo struct {
	CPU int32 `json:"cpu"`
	VendorID string `json:"vendorId"`
	PhysicalID string `json:"physicalId"`
}
type win32_Processor struct {
	Manufacturer string
	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(&regBuf[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下貌似无法获取硬盘序列号(没找到怎么获取)


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
10862 次点击
1 回复 | 直到 2019年02月19日 16:13:01
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏