github.com/google/osv-scalibr@v0.4.1/common/windows/registry/live.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //go:build windows 16 17 package registry 18 19 import ( 20 "errors" 21 "fmt" 22 "strconv" 23 24 winregistry "golang.org/x/sys/windows/registry" 25 ) 26 27 // LiveOpener is an opener for the live registry. 28 type LiveOpener struct{} 29 30 // NewLiveOpener creates a new LiveOpener, allowing to open the live registry. 31 func NewLiveOpener() *LiveOpener { 32 return &LiveOpener{} 33 } 34 35 // Open the live registry. 36 func (o *LiveOpener) Open() (Registry, error) { 37 return &LiveRegistry{}, nil 38 } 39 40 // LiveRegistry wraps the windows registry library to provide live parsing of the Windows registry. 41 type LiveRegistry struct{} 42 43 // OpenKey open the requested registry key. 44 func (o *LiveRegistry) OpenKey(hive string, path string) (Key, error) { 45 var winHive winregistry.Key 46 47 switch hive { 48 case "HKLM": 49 winHive = winregistry.LOCAL_MACHINE 50 case "HKCU": 51 winHive = winregistry.CURRENT_USER 52 case "HKU": 53 winHive = winregistry.USERS 54 default: 55 return nil, fmt.Errorf("unsupported hive: %s", hive) 56 } 57 58 key, err := winregistry.OpenKey(winHive, path, winregistry.QUERY_VALUE|winregistry.ENUMERATE_SUB_KEYS) 59 if err != nil { 60 return nil, err 61 } 62 63 return &LiveKey{ 64 key: &key, 65 name: path, 66 }, nil 67 } 68 69 // Close closes the registry hive. 70 // For live keys, this is a no-op. 71 func (o *LiveRegistry) Close() error { 72 return nil 73 } 74 75 // LiveKey wraps a winregistry.Key to provide an implementation of the registry.Key interface. 76 type LiveKey struct { 77 key *winregistry.Key 78 name string 79 } 80 81 // Name returns the name of the key. 82 func (o *LiveKey) Name() string { 83 return o.name 84 } 85 86 // Subkeys returns the opened subkeys of the key. 87 // NOT SUPPORTED: This method would be too heavy. We can decide to revisit later if a strong use case 88 // presents itself. Please use a combination of SubkeyNames() and OpenKey() tailored to your use 89 // case instead. 90 func (o *LiveKey) Subkeys() ([]Key, error) { 91 return nil, errors.New("not implemented on live registry: this method would be too heavy") 92 } 93 94 // SubkeyNames returns the names of the subkeys of the key. 95 func (o *LiveKey) SubkeyNames() ([]string, error) { 96 return o.key.ReadSubKeyNames(0) 97 } 98 99 // Close closes the key. 100 func (o *LiveKey) Close() error { 101 return o.key.Close() 102 } 103 104 // ClassName returns the class name of the key. 105 // NOT SUPPORTED: This method is not supported on live registry as the library we use does not 106 // provide this information and we do not have a use case for it. 107 func (o *LiveKey) ClassName() ([]byte, error) { 108 return nil, errors.New("not supported: class name is not supported on live registry") 109 } 110 111 // Value returns the value with the given name. 112 // The actual value is lazy loaded when Data() is called. 113 func (o *LiveKey) Value(name string) (Value, error) { 114 return &LiveValue{ 115 name: name, 116 key: o.key, 117 }, nil 118 } 119 120 // ValueBytes directly returns the content (as bytes) of the named value. 121 func (o *LiveKey) ValueBytes(name string) ([]byte, error) { 122 value, err := o.Value(name) 123 if err != nil { 124 return nil, err 125 } 126 127 return value.Data() 128 } 129 130 // ValueString directly returns the content (as string) of the named value. 131 func (o *LiveKey) ValueString(name string) (string, error) { 132 value, err := o.Value(name) 133 if err != nil { 134 return "", err 135 } 136 137 return value.DataString() 138 } 139 140 // Values returns the different values contained in the key. 141 func (o *LiveKey) Values() ([]Value, error) { 142 valueNames, err := o.key.ReadValueNames(0) 143 if err != nil { 144 return nil, err 145 } 146 147 var values []Value 148 for _, valueName := range valueNames { 149 values = append(values, &LiveValue{ 150 name: valueName, 151 key: o.key, 152 }) 153 } 154 155 return values, nil 156 } 157 158 // LiveValue wraps a winregistry.Value to provide an implementation of the registry.Value interface. 159 type LiveValue struct { 160 name string 161 key *winregistry.Key 162 } 163 164 // Name returns the name of the value. 165 func (o *LiveValue) Name() string { 166 return o.name 167 } 168 169 // Data returns the data contained in the value as bytes. 170 func (o *LiveValue) Data() ([]byte, error) { 171 size, _, err := o.key.GetValue(o.name, nil) 172 if err != nil { 173 return nil, err 174 } 175 176 buffer := make([]byte, size) 177 if _, _, err = o.key.GetValue(o.name, buffer); err != nil { 178 return nil, err 179 } 180 181 return buffer, nil 182 } 183 184 // DataString returns the data contained in the value as a string. 185 func (o *LiveValue) DataString() (string, error) { 186 val, valtype, err := o.key.GetStringValue(o.name) 187 if (err == nil) || (valtype == winregistry.SZ || valtype == winregistry.EXPAND_SZ) { 188 return val, err 189 } 190 191 switch valtype { 192 case winregistry.DWORD, winregistry.DWORD_BIG_ENDIAN, winregistry.QWORD: 193 val, _, err := o.key.GetIntegerValue(o.name) 194 return strconv.FormatUint(val, 10), err 195 default: 196 return "", fmt.Errorf("unsupported value type: %v for value %q", valtype, o.name) 197 } 198 }