github.com/iDigitalFlame/xmt@v0.5.4/device/regedit/y_windows.go (about) 1 //go:build windows 2 // +build windows 3 4 // Copyright (C) 2020 - 2023 iDigitalFlame 5 // 6 // This program is free software: you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation, either version 3 of the License, or 9 // any later version. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with this program. If not, see <https://www.gnu.org/licenses/>. 18 // 19 20 package regedit 21 22 import ( 23 "sort" 24 "strings" 25 "syscall" 26 27 "github.com/iDigitalFlame/xmt/device/winapi" 28 "github.com/iDigitalFlame/xmt/device/winapi/registry" 29 ) 30 31 type entryList []Entry 32 33 func (e entryList) Len() int { 34 return len(e) 35 } 36 func (e entryList) Swap(i, j int) { 37 e[i], e[j] = e[j], e[i] 38 } 39 40 // Dir returns a list of registry entries for the supplied key or an error if 41 // the path does not exist. 42 // 43 // The key path can either be a "reg" style path (ex: HKLM\System or 44 // HKCU\Software) or PowerShell style (ex: HKLM:\System or HKCU:\Software). 45 // 46 // Returns device.ErrNoWindows on non-Windows devices. 47 func Dir(key string) ([]Entry, error) { 48 k, err := read(key, false) 49 if err != nil { 50 return nil, err 51 } 52 s, err := k.SubKeys() 53 if err != nil { 54 k.Close() 55 return nil, err 56 } 57 v, err := k.Values() 58 if err != nil { 59 k.Close() 60 return nil, err 61 } 62 n := len(v) + len(s) 63 if n == 0 { 64 k.Close() 65 return nil, nil 66 } 67 var ( 68 r = make(entryList, n, n+1) 69 c int 70 ) 71 for i := range s { 72 r[c].Name = s[i] 73 c++ 74 } 75 var d bool 76 for i := range v { 77 if r[c].Name = v[i]; len(v[i]) == 0 { 78 d, r[c].Name = true, "(Default)" 79 } 80 r[c].Data, r[c].Type, err = readFullValueData(k, v[i]) 81 if c++; err != nil { 82 break 83 } 84 } 85 if !d { 86 e := Entry{Name: "(Default)"} 87 if e.Data, e.Type, _ = readFullValueData(k, ""); e.Type == 0 { 88 e.Type = registry.TypeString 89 } 90 r = append(r, e) 91 } 92 k.Close() 93 sort.Sort(r) 94 return r, err 95 } 96 func (e entryList) Less(i, j int) bool { 97 if len(e[j].Name) == 9 && e[j].Name[0] == '(' && e[j].Name[1] == 'D' && e[j].Name[8] == ')' { 98 return false 99 } 100 if e[i].Type == 0 && e[j].Type > 0 { 101 return true 102 } 103 if e[j].Type == 0 && e[i].Type > 1 { 104 return false 105 } 106 return e[i].Name < e[j].Name 107 } 108 func increaseSlash(i int, s string) int { 109 if len(s) <= i { 110 return i 111 } 112 if s[i] == '\\' { 113 return i + 1 114 } 115 return i 116 } 117 118 // Get returns a single registry entry for the supplied value name under the 119 // key path specified or an error if any of the paths do not exist. 120 // 121 // The key path can either be a "reg" style path (ex: HKLM\System or 122 // HKCU\Software) or PowerShell style (ex: HKLM:\System or HKCU:\Software). 123 // 124 // Returns device.ErrNoWindows on non-Windows devices. 125 func Get(key, value string) (Entry, error) { 126 var ( 127 k, err = read(key, false) 128 e Entry 129 ) 130 if err != nil { 131 return e, err 132 } 133 e.Name = value 134 e.Data, e.Type, err = readFullValueData(k, value) 135 k.Close() 136 return e, err 137 } 138 func read(k string, w bool) (registry.Key, error) { 139 h, d, err := translateRootKey(k) 140 if err != nil { 141 return 0, err 142 } 143 if d >= len(k) || h == 0 { 144 return 0, registry.ErrNotExist 145 } 146 if w { 147 // 0x2001F - KEY_READ | KEY_WRITE 148 x, _, err := registry.Create(h, k[d:], 0x2001F) 149 return x, err 150 } 151 // 0x20019 - KEY_READ 152 return registry.Open(h, k[d:], 0x20019) 153 } 154 func translateRootKey(v string) (registry.Key, int, error) { 155 if len(v) < 4 || (v[0] != 'H' && v[0] != 'h') { 156 return 0, 0, registry.ErrNotExist 157 } 158 i := strings.IndexByte(v, ':') 159 if i == -1 { 160 if i = strings.IndexByte(v, '\\'); i == -1 { 161 return 0, 0, registry.ErrNotExist 162 } 163 } 164 if len(v) > 6 && v[4] == '_' { 165 if i < 5 { 166 return 0, 0, registry.ErrNotExist 167 } 168 switch v[i-1] { 169 case 'E', 'e': 170 return registry.KeyLocalMachine, increaseSlash(i+1, v), nil 171 case 'R', 'r': 172 return registry.KeyCurrentUser, increaseSlash(i+1, v), nil 173 case 'S', 's': 174 return registry.KeyUsers, increaseSlash(i+1, v), nil 175 case 'G', 'g': 176 return registry.KeyCurrentConfig, increaseSlash(i+1, v), nil 177 case 'A', 'a': 178 return registry.KeyPerformanceData, increaseSlash(i+1, v), nil 179 case 'T', 't': 180 return registry.KeyClassesRoot, increaseSlash(i+1, v), nil 181 } 182 return 0, 0, registry.ErrNotExist 183 } 184 if i == 3 && (v[2] == 'U' || v[2] == 'u') { 185 return registry.KeyUsers, increaseSlash(4, v), nil 186 } 187 if i < 4 { 188 return 0, 0, registry.ErrNotExist 189 } 190 switch v[i-1] { 191 case 'M', 'm': 192 return registry.KeyLocalMachine, increaseSlash(i+1, v), nil 193 case 'U', 'u': 194 return registry.KeyCurrentUser, increaseSlash(i+1, v), nil 195 case 'C', 'c': 196 return registry.KeyCurrentConfig, increaseSlash(i+1, v), nil 197 case 'D', 'd': 198 return registry.KeyPerformanceData, increaseSlash(i+1, v), nil 199 case 'R', 'r': 200 return registry.KeyClassesRoot, increaseSlash(i+1, v), nil 201 } 202 return 0, 0, registry.ErrNotExist 203 } 204 func readFullValueData(k registry.Key, n string) ([]byte, uint32, error) { 205 v, err := winapi.UTF16PtrFromString(n) 206 if err != nil { 207 return nil, 0, err 208 } 209 var t, s uint32 210 if err = syscall.RegQueryValueEx(syscall.Handle(k), v, nil, &t, nil, &s); err != nil { 211 return nil, 0, err 212 } 213 b := make([]byte, s) 214 if err = syscall.RegQueryValueEx(syscall.Handle(k), v, nil, &t, &b[0], &s); err != nil { 215 return nil, t, err 216 } 217 return b, t, err 218 }