mirror of
https://github.com/jfjallid/go-secdump
synced 2026-06-06 15:54:30 +00:00
Fixed bug where NT hashes were decrypted incorrectly on certain machines. Bumped version of go-smb library to v0.2.6 and golog to v0.3.3, fixing an issue with dumping large DCC2 caches. Added better remote OS detection. Added a Github workflow to build statically compiled binaries.
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
# This workflow will build binaries for Linux and Windows x64 architecture
|
||||
|
||||
name: release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
permissions:
|
||||
contents: write # to allow upload of release assets
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.20'
|
||||
|
||||
- name: install dependencies
|
||||
run: go get
|
||||
|
||||
- name: build project
|
||||
run: make
|
||||
|
||||
- name: publish binaries to release
|
||||
run: |
|
||||
ASSET_NAME_1="go-secdump"
|
||||
ASSET_NAME_2="go-secdump.exe"
|
||||
UPLOAD_URL="https://uploads.github.com/repos/${{ github.repository }}/releases/${{ github.event.release.id }}/assets"
|
||||
|
||||
# Upload asset 1
|
||||
curl -sSL -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" -H "Content-Type: application/octet-stream" --data-binary @"$ASSET_NAME_1" "$UPLOAD_URL?name=$ASSET_NAME_1"
|
||||
|
||||
# Upload asset 2
|
||||
curl -sSL -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" -H "Content-Type: application/octet-stream" --data-binary @"$ASSET_NAME_2" "$UPLOAD_URL?name=$ASSET_NAME_2"
|
||||
@@ -1,6 +1,6 @@
|
||||
all:
|
||||
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o go-secdump
|
||||
GOOS=windows GOARCH=386 go build -ldflags "-s -w" -o go-secdump.exe .
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w" -o go-secdump
|
||||
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w" -o go-secdump.exe .
|
||||
|
||||
clean:
|
||||
rm -f go-secdump
|
||||
|
||||
@@ -3,8 +3,8 @@ module github.com/jfjallid/go-secdump
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/jfjallid/go-smb v0.2.5
|
||||
github.com/jfjallid/golog v0.3.2
|
||||
github.com/jfjallid/go-smb v0.2.6
|
||||
github.com/jfjallid/golog v0.3.3
|
||||
golang.org/x/crypto v0.6.0
|
||||
golang.org/x/term v0.5.0
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
github.com/jfjallid/go-smb v0.2.5 h1:J3ubQCBqI0FPczM7Tgn36MAG0H2w+lUCCA3q6b7/5k8=
|
||||
github.com/jfjallid/go-smb v0.2.5/go.mod h1:Kew0ysf3f+GtnBzpU7jiZmZ4ohp4ZHE7z2PMnXXG7IM=
|
||||
github.com/jfjallid/golog v0.3.2 h1:i3fKI9AUOnIvPmp/1qtLAbjaS2l3SjdjaE4izzpBwvc=
|
||||
github.com/jfjallid/golog v0.3.2/go.mod h1:19Q/zg5OgPPd0xhFllokPnMzthzhFPZmiAGAokE7k58=
|
||||
github.com/jfjallid/go-smb v0.2.6 h1:kF0UH7wXjqnqSrISc0vEpLkJFfsz4Bnr/jlXAobrwAM=
|
||||
github.com/jfjallid/go-smb v0.2.6/go.mod h1:Kew0ysf3f+GtnBzpU7jiZmZ4ohp4ZHE7z2PMnXXG7IM=
|
||||
github.com/jfjallid/golog v0.3.3 h1:dY6qf8wTxJ9OwBPVTadVRDmt/6MVXSWwXrxaGMMyXsU=
|
||||
github.com/jfjallid/golog v0.3.3/go.mod h1:19Q/zg5OgPPd0xhFllokPnMzthzhFPZmiAGAokE7k58=
|
||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
|
||||
@@ -39,7 +39,7 @@ import (
|
||||
)
|
||||
|
||||
var log = golog.Get("")
|
||||
var release string = "0.1.1"
|
||||
var release string = "0.1.2"
|
||||
|
||||
func startRemoteRegistry(session *smb.Connection, share string) (err error) {
|
||||
f, err := session.OpenFile(share, "svcctl")
|
||||
|
||||
@@ -103,6 +103,80 @@ func (self *dpapi_system) unmarshal(data []byte) {
|
||||
copy(self.UserKey[:], data[24:44])
|
||||
}
|
||||
|
||||
type sam_key_data_aes struct {
|
||||
Revision uint32
|
||||
Length uint32
|
||||
ChecksumLen uint32
|
||||
DataLen uint32
|
||||
Salt [16]byte
|
||||
Data [32]byte
|
||||
}
|
||||
|
||||
type sam_key_data struct {
|
||||
Revision uint32
|
||||
Length uint32
|
||||
Salt [16]byte
|
||||
Key [16]byte
|
||||
Checksum [16]byte
|
||||
_ uint64
|
||||
}
|
||||
|
||||
type domain_account_f struct { // 104 bytes of fixed length fields
|
||||
Revision uint16
|
||||
_ uint32 // Unknown
|
||||
_ uint16 // Unknown
|
||||
CreationTime uint64
|
||||
DomainModifiedAccount uint64
|
||||
MaxPasswordAge uint64
|
||||
MinPasswordAge uint64
|
||||
ForceLogoff uint64
|
||||
LockoutDuration uint64
|
||||
LockoutObservationWindow uint64
|
||||
ModifiedCountAtLastPromotion uint64
|
||||
NextRid uint32
|
||||
PasswordProperties uint32
|
||||
MinPasswordLength uint16
|
||||
PasswordHistoryLength uint16
|
||||
LockoutThreshold uint16
|
||||
_ uint16 // Unknown
|
||||
ServerState uint32
|
||||
ServerRole uint32
|
||||
UasCompatibilityRequired uint32
|
||||
_ uint32 // Unknown
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func (self *domain_account_f) unmarshal(data []byte) (err error) {
|
||||
if len(data) < 104 {
|
||||
err = fmt.Errorf("Not enough data to unmarshal a DOMAIN_ACCOUNT_F")
|
||||
log.Errorln(err)
|
||||
return
|
||||
}
|
||||
|
||||
self.Revision = binary.LittleEndian.Uint16(data[:2])
|
||||
self.CreationTime = binary.LittleEndian.Uint64(data[8:16])
|
||||
self.DomainModifiedAccount = binary.LittleEndian.Uint64(data[16:24])
|
||||
self.MaxPasswordAge = binary.LittleEndian.Uint64(data[24:32])
|
||||
self.MinPasswordAge = binary.LittleEndian.Uint64(data[32:40])
|
||||
self.ForceLogoff = binary.LittleEndian.Uint64(data[40:48])
|
||||
self.LockoutDuration = binary.LittleEndian.Uint64(data[48:56])
|
||||
self.LockoutObservationWindow = binary.LittleEndian.Uint64(data[56:64])
|
||||
self.ModifiedCountAtLastPromotion = binary.LittleEndian.Uint64(data[64:72])
|
||||
self.NextRid = binary.LittleEndian.Uint32(data[72:76])
|
||||
self.PasswordProperties = binary.LittleEndian.Uint32(data[76:80])
|
||||
self.MinPasswordLength = binary.LittleEndian.Uint16(data[80:82])
|
||||
self.PasswordHistoryLength = binary.LittleEndian.Uint16(data[82:84])
|
||||
self.LockoutThreshold = binary.LittleEndian.Uint16(data[84:86])
|
||||
self.ServerState = binary.LittleEndian.Uint32(data[88:92])
|
||||
self.ServerRole = binary.LittleEndian.Uint32(data[92:96])
|
||||
self.UasCompatibilityRequired = binary.LittleEndian.Uint32(data[96:100])
|
||||
if len(data) > 104 {
|
||||
self.Data = make([]byte, len(data[104:]))
|
||||
copy(self.Data, data[104:])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type nl_record struct {
|
||||
UserLength uint16
|
||||
DomainNameLength uint16
|
||||
@@ -418,35 +492,6 @@ func getBootKey(rpccon *msrrp.RPCCon, base []byte) (result []byte, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func getEncryptedsysKey(rpccon *msrrp.RPCCon, base, f []byte) (encsysKey []byte, err error) {
|
||||
|
||||
val, err := IsWin10After1607(GetOSVersionBuild(rpccon, base))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if val {
|
||||
log.Debugf("Getting AES encrypted sysKey from F[0x88]\n")
|
||||
encsysKey = f[0x88 : 0x88+16]
|
||||
} else {
|
||||
encsysKey = f[0x80 : 0x80+16]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getEncryptedsysKeyIV(rpccon *msrrp.RPCCon, base, f []byte) (sysKeyIV []byte, err error) {
|
||||
val, err := IsWin10After1607(GetOSVersionBuild(rpccon, base))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if val {
|
||||
log.Debugf("Getting sysKey IV from F[0x78]\n")
|
||||
sysKeyIV = f[0x78 : 0x78+16]
|
||||
} else {
|
||||
sysKeyIV = f[0x70 : 0x70+16]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getSysKey(rpccon *msrrp.RPCCon, base []byte) (sysKey []byte, err error) {
|
||||
var tmpSysKey []byte
|
||||
_, err = getBootKey(rpccon, base)
|
||||
@@ -459,7 +504,7 @@ func getSysKey(rpccon *msrrp.RPCCon, base []byte) (sysKey []byte, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
f, err := rpccon.QueryValue(hSubKey, "F")
|
||||
fBytes, err := rpccon.QueryValue(hSubKey, "F")
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
rpccon.CloseKeyHandle(hSubKey)
|
||||
@@ -468,61 +513,97 @@ func getSysKey(rpccon *msrrp.RPCCon, base []byte) (sysKey []byte, err error) {
|
||||
|
||||
rpccon.CloseKeyHandle(hSubKey)
|
||||
|
||||
encsysKey, err := getEncryptedsysKey(rpccon, base, f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
sysKeyIV, err := getEncryptedsysKeyIV(rpccon, base, f)
|
||||
f := &domain_account_f{}
|
||||
err = f.unmarshal(fBytes)
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
rpccon.CloseKeyHandle(hSubKey)
|
||||
return
|
||||
}
|
||||
|
||||
if f[0] == 0x3 {
|
||||
tmpSysKey, err = DecryptAESSysKey(BootKey, encsysKey, sysKeyIV)
|
||||
var encSysKey []byte
|
||||
var sysKeyIV []byte
|
||||
sysKey = make([]byte, 16)
|
||||
|
||||
if f.Revision == 3 {
|
||||
// AES
|
||||
samAesData := sam_key_data_aes{}
|
||||
err = binary.Read(bytes.NewReader(f.Data), binary.LittleEndian, &samAesData)
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
rpccon.CloseKeyHandle(hSubKey)
|
||||
return
|
||||
}
|
||||
sysKeyIV = samAesData.Salt[:]
|
||||
encSysKey = samAesData.Data[:samAesData.DataLen]
|
||||
tmpSysKey, err = DecryptAESSysKey(BootKey, encSysKey, sysKeyIV)
|
||||
copy(sysKey, tmpSysKey)
|
||||
} else if f.Revision == 2 {
|
||||
// RC4
|
||||
samData := &sam_key_data{}
|
||||
err = binary.Read(bytes.NewReader(f.Data), binary.LittleEndian, samData)
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
rpccon.CloseKeyHandle(hSubKey)
|
||||
return
|
||||
}
|
||||
|
||||
sysKeyIV = samData.Salt[:]
|
||||
// For RC4, also check the checksum so we should XOR 32 bytes instead of just 16
|
||||
encSysKey = append(samData.Key[:], samData.Checksum[:]...)
|
||||
tmpSysKey, err = DecryptRC4SysKey(BootKey, encSysKey, sysKeyIV)
|
||||
// Verify checksum
|
||||
input := []byte{}
|
||||
input = append(input, tmpSysKey[:16]...)
|
||||
input = append(input, s2...)
|
||||
input = append(input, tmpSysKey[:16]...)
|
||||
input = append(input, s1...)
|
||||
checksum := md5.Sum(input)
|
||||
if bytes.Compare(checksum[:], tmpSysKey[16:]) != 0 {
|
||||
err = fmt.Errorf("Syskey checksum failed. Could be that a Syskey startup password is in use.")
|
||||
log.Errorln(err)
|
||||
return
|
||||
}
|
||||
copy(sysKey, tmpSysKey[:16])
|
||||
} else {
|
||||
tmpSysKey, err = DecryptRC4SysKey(BootKey, encsysKey, sysKeyIV)
|
||||
}
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Unknown revision of DOMAIN_ACCOUNT_F")
|
||||
log.Errorln(err)
|
||||
return
|
||||
}
|
||||
sysKey = make([]byte, len(tmpSysKey))
|
||||
copy(sysKey, tmpSysKey)
|
||||
|
||||
log.Noticef("SysKey: 0x%x\n", sysKey)
|
||||
return
|
||||
}
|
||||
|
||||
func DecryptRC4SysKey(bootkey, encSyskey, syskeyIV []byte) (syskey []byte, err error) {
|
||||
func DecryptRC4SysKey(bootKey, encSysKey, sysKeyIV []byte) (sysKey []byte, err error) {
|
||||
// Building the decryption key for the Syskey
|
||||
input := []byte{}
|
||||
input = append(input, syskeyIV...)
|
||||
input = append(input, sysKeyIV...)
|
||||
input = append(input, s1...)
|
||||
input = append(input, bootkey...)
|
||||
input = append(input, bootKey...)
|
||||
input = append(input, s2...)
|
||||
// Building syskey RC4 enc key with: one byte from F[0x70], String1, Bootkey, String2
|
||||
rc4key := md5.Sum(input)
|
||||
log.Debugf("Syskey RC4 enc key: md5(%x %x %x %x)\n", syskeyIV, s1, bootkey, s2)
|
||||
log.Debugf("Syskey RC4 enc key: md5(%x %q %x %q)\n", sysKeyIV, s1, bootKey, s2)
|
||||
log.Debugf("Syskey RC4 enc key: %x\n", rc4key)
|
||||
c1, err := rc4.NewCipher(rc4key[:])
|
||||
if err != nil {
|
||||
log.Errorln("Failed to init RC4 key")
|
||||
return
|
||||
}
|
||||
syskey = make([]byte, 16)
|
||||
c1.XORKeyStream(syskey, encSyskey)
|
||||
log.Debugf("Syskey: %x\n", syskey)
|
||||
sysKey = make([]byte, 32)
|
||||
c1.XORKeyStream(sysKey, encSysKey)
|
||||
return
|
||||
}
|
||||
|
||||
func DecryptAESSysKey(bootkey, encSyskey, syskeyIV []byte) (syskey []byte, err error) {
|
||||
syskey = make([]byte, 16)
|
||||
a1, err := aes.NewCipher(bootkey)
|
||||
func DecryptAESSysKey(bootKey, encSysKey, sysKeyIV []byte) (sysKey []byte, err error) {
|
||||
sysKey = make([]byte, len(encSysKey))
|
||||
a1, err := aes.NewCipher(bootKey)
|
||||
if err != nil {
|
||||
log.Errorln("Failed to init AES key")
|
||||
return
|
||||
}
|
||||
c1 := cipher.NewCBCDecrypter(a1, syskeyIV)
|
||||
c1.CryptBlocks(syskey, encSyskey)
|
||||
c1 := cipher.NewCBCDecrypter(a1, sysKeyIV)
|
||||
c1.CryptBlocks(sysKey, encSysKey)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -532,6 +613,14 @@ func getNTHash(rpccon *msrrp.RPCCon, base []byte, rids []string) (result []UserC
|
||||
// Some entires have empty passwords or hash retrieval fails for some reason.
|
||||
// In those cases I skip to the next entry. I increment the ctr first thing
|
||||
// instead of at the end of the loop to make sure it happens
|
||||
|
||||
// Determine OS version once
|
||||
osBuild, osVersion, isServer, err := GetOSVersionBuild(rpccon, base)
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
return
|
||||
}
|
||||
|
||||
cntr := -1
|
||||
for _, ridStr := range rids {
|
||||
cntr += 1
|
||||
@@ -632,7 +721,7 @@ func getNTHash(rpccon *msrrp.RPCCon, base []byte, rids []string) (result []UserC
|
||||
szNT := binary.LittleEndian.Uint32(v[0xac:])
|
||||
offsetHashStruct := binary.LittleEndian.Uint32(v[0xa8:]) + 0xcc
|
||||
//log.Debugf("Size of SAM Hash structure for user %s: %d located at offset: 0x%x\n", name, szNT, offsetHashStruct)
|
||||
preWin11, err2 := IsBetweenWinXPWin10(GetOSVersionBuild(rpccon, base))
|
||||
preWin11, err2 := IsBetweenWinXPWin10(osBuild, osVersion, isServer)
|
||||
if err2 != nil {
|
||||
log.Errorln(err2)
|
||||
continue
|
||||
@@ -644,7 +733,7 @@ func getNTHash(rpccon *msrrp.RPCCon, base []byte, rids []string) (result []UserC
|
||||
result[cntr].AES = false
|
||||
result[cntr].Data = v[offsetNTHash : offsetNTHash+16]
|
||||
} else {
|
||||
afterAnniversary, err2 := IsWin10After1607(GetOSVersionBuild(rpccon, base))
|
||||
afterAnniversary, err2 := IsWin10After1607(osBuild, osVersion)
|
||||
if err2 != nil {
|
||||
log.Errorln(err2)
|
||||
continue
|
||||
@@ -669,7 +758,7 @@ func getNTHash(rpccon *msrrp.RPCCon, base []byte, rids []string) (result []UserC
|
||||
result[cntr].AES = false
|
||||
result[cntr].Data = []byte{}
|
||||
} else {
|
||||
log.Warningf("Unknown Hash type for %x with length 0x%x with OS: %s\n", rid, szNT, GetOsVersionName(GetOSVersionBuild(rpccon, base)))
|
||||
log.Warningf("Unknown Hash type for %x with length 0x%x with OS: %s\n", rid, szNT, osNameMap[GetOSVersion(osBuild, osVersion, isServer)])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1046,13 +1135,15 @@ func GetCachedHashes(rpccon *msrrp.RPCCon, base []byte) (result []string, err er
|
||||
return
|
||||
}
|
||||
|
||||
func GetOSVersionBuild(rpccon *msrrp.RPCCon, base []byte) (build int, version float64, err error) {
|
||||
func GetOSVersionBuild(rpccon *msrrp.RPCCon, base []byte) (build int, version float64, server bool, err error) {
|
||||
hSubKey, err := rpccon.OpenSubKey(base, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`)
|
||||
if err != nil {
|
||||
log.Noticef("Failed to open registry key CurrentVersion with error: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer rpccon.CloseKeyHandle(hSubKey)
|
||||
defer func(h []byte) {
|
||||
rpccon.CloseKeyHandle(h)
|
||||
}(hSubKey)
|
||||
|
||||
value, err := rpccon.QueryValueString(hSubKey, "CurrentBuild")
|
||||
if err != nil {
|
||||
@@ -1078,5 +1169,24 @@ func GetOSVersionBuild(rpccon *msrrp.RPCCon, base []byte) (build int, version fl
|
||||
return
|
||||
}
|
||||
|
||||
hSubKey, err = rpccon.OpenSubKey(base, `SYSTEM\CurrentControlSet\Control\ProductOptions`)
|
||||
if err != nil {
|
||||
log.Noticef("Failed to open registry key ProductOptions with error: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer func(h []byte) {
|
||||
rpccon.CloseKeyHandle(h)
|
||||
}(hSubKey)
|
||||
|
||||
value, err = rpccon.QueryValueString(hSubKey, "ProductType")
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Compare(value, "ServerNT") == 0 {
|
||||
server = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -30,79 +30,105 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"math/bits"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
WIN_UNKNOWN = iota
|
||||
WINXP
|
||||
WIN_SERVER_2003
|
||||
WIN_VISTA
|
||||
WIN_SERVER_2008
|
||||
WIN7
|
||||
WIN_SERVER_2008_R2
|
||||
WIN8
|
||||
WIN_SERVER_2012
|
||||
WIN81
|
||||
WIN_SERVER_2012_R2
|
||||
WIN10
|
||||
WIN_SERVER_2016
|
||||
WIN_SERVER_2019
|
||||
WIN_SERVER_2022
|
||||
WIN11
|
||||
)
|
||||
|
||||
func GetOSVersion(build int, version float64) (os byte, err error) {
|
||||
var osNameMap = map[byte]string{
|
||||
WIN_UNKNOWN: "Windows Unknown",
|
||||
WINXP: "Windows XP",
|
||||
WIN_VISTA: "Windows Vista",
|
||||
WIN7: "Windows 7",
|
||||
WIN8: "Windows 8",
|
||||
WIN81: "Windows 8.1",
|
||||
WIN10: "Windows 10",
|
||||
WIN11: "Windows 11",
|
||||
WIN_SERVER_2003: "Windows Server 2003",
|
||||
WIN_SERVER_2008: "Windows Server 2008",
|
||||
WIN_SERVER_2008_R2: "Windows Server 2008 R2",
|
||||
WIN_SERVER_2012: "Windows Server 2012",
|
||||
WIN_SERVER_2012_R2: "Windows Server 2012 R2",
|
||||
WIN_SERVER_2016: "Windows Server 2016",
|
||||
WIN_SERVER_2019: "Windows Server 2019",
|
||||
WIN_SERVER_2022: "Windows Server 2022",
|
||||
}
|
||||
|
||||
if (build >= 7000) && (build < 7999) {
|
||||
log.Debugf("Windows 7\n")
|
||||
os = WIN7
|
||||
} else if (build >= 9000) && (build < 9999) {
|
||||
if version < 6.3 {
|
||||
log.Debugf("Windows 8\n")
|
||||
os = WIN8
|
||||
} else {
|
||||
//log.Debugf("Windows 8.1\n")
|
||||
os = WIN81
|
||||
}
|
||||
} else if (build >= 10000) && (build < 18363) {
|
||||
log.Debugf("Windows 10\n")
|
||||
os = WIN10
|
||||
} else {
|
||||
if (version < 5.2) && (version > 5.0) {
|
||||
os = WINXP
|
||||
log.Debugf("Windows XP?\n")
|
||||
} else {
|
||||
func GetOSVersion(currentBuild int, currentVersion float64, server bool) (os byte) {
|
||||
|
||||
currentVersionStr := strconv.FormatFloat(currentVersion, 'f', 1, 64)
|
||||
if server {
|
||||
switch {
|
||||
case currentBuild >= 3790 && currentBuild < 6001:
|
||||
os = WIN_SERVER_2003
|
||||
case currentBuild >= 6001 && currentBuild < 7601:
|
||||
os = WIN_SERVER_2008
|
||||
case currentBuild >= 7601 && currentBuild < 9200:
|
||||
os = WIN_SERVER_2008_R2
|
||||
case currentBuild >= 9200 && currentBuild < 9600:
|
||||
os = WIN_SERVER_2012
|
||||
case currentBuild >= 9200 && currentBuild < 14393:
|
||||
os = WIN_SERVER_2012_R2
|
||||
case currentBuild >= 14393 && currentBuild < 17763:
|
||||
os = WIN_SERVER_2016
|
||||
case currentBuild >= 17763 && currentBuild < 20348:
|
||||
os = WIN_SERVER_2019
|
||||
case currentBuild >= 20348:
|
||||
os = WIN_SERVER_2022
|
||||
default:
|
||||
log.Debugf("Unknown server version of Windows with CurrentBuild %d and CurrentVersion %f\n", currentBuild, currentVersion)
|
||||
os = WIN_UNKNOWN
|
||||
}
|
||||
} else {
|
||||
switch currentVersionStr {
|
||||
case "5.1":
|
||||
os = WINXP
|
||||
case "6.0":
|
||||
// Windows Vista but it shares CurrentVersion and CurrentBuild with Windows Server 2008
|
||||
os = WIN_VISTA
|
||||
case "6.1":
|
||||
// Windows 7 but it shares CurrentVersion and CurrentBuild with Windows Server 2008 R2
|
||||
os = WIN7
|
||||
case "6.2":
|
||||
// Windows 8 but it shares CurrentVersion and CurrentBuild with Windows Server 2012
|
||||
os = WIN8
|
||||
case "6.3":
|
||||
// Windows 8.1 but it shares CurrentVersion and CurrentBuild with Windows Server 2012 R2
|
||||
os = WIN81
|
||||
case "10.0":
|
||||
if currentBuild < 22000 {
|
||||
os = WIN10
|
||||
} else {
|
||||
os = WIN11
|
||||
}
|
||||
default:
|
||||
log.Debugf("Unknown version of Windows with CurrentBuild %d and CurrentVersion %f\n", currentBuild, currentVersion)
|
||||
os = WIN_UNKNOWN
|
||||
log.Debugf("Unknown OS\n")
|
||||
}
|
||||
}
|
||||
log.Debugf("OS Version: %d\n", os)
|
||||
|
||||
log.Debugf("OS Version: %s\n", osNameMap[os])
|
||||
return
|
||||
}
|
||||
|
||||
func GetOsVersionName(build int, version float64, inErr error) string {
|
||||
if inErr != nil {
|
||||
log.Errorln(inErr)
|
||||
return "Unknown OS"
|
||||
}
|
||||
os, err := GetOSVersion(build, version)
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
return "Unknown OS"
|
||||
}
|
||||
result := "Unknown OS"
|
||||
switch os {
|
||||
case WIN_UNKNOWN:
|
||||
break
|
||||
case WINXP:
|
||||
result = "Windows XP"
|
||||
case WIN7:
|
||||
result = "Windows 7"
|
||||
case WIN8:
|
||||
result = "Windows 8"
|
||||
case WIN81:
|
||||
result = "Windows 8.1"
|
||||
case WIN10:
|
||||
result = "Windows 10"
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func IsWin10After1607(build int, version float64, inErr error) (value bool, err error) {
|
||||
if inErr != nil {
|
||||
return false, inErr
|
||||
}
|
||||
func IsWin10After1607(build int, version float64) (value bool, err error) {
|
||||
if build >= 14393 {
|
||||
value = true
|
||||
} else {
|
||||
@@ -111,14 +137,8 @@ func IsWin10After1607(build int, version float64, inErr error) (value bool, err
|
||||
return
|
||||
}
|
||||
|
||||
func IsBetweenWinXPWin10(build int, version float64, inErr error) (value bool, err error) {
|
||||
if inErr != nil {
|
||||
return false, inErr
|
||||
}
|
||||
os, err := GetOSVersion(build, version)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
func IsBetweenWinXPWin10(build int, version float64, isServer bool) (value bool, err error) {
|
||||
os := GetOSVersion(build, version, isServer)
|
||||
if (WINXP <= os) && (os <= WIN10) {
|
||||
value = true
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user