-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Import and abstract the
regparser
library to provide offline parsin…
…g of the Windows registry. This abstraction makes testing easier and provide a path for offline parsing of Windows images. PiperOrigin-RevId: 676808177
- Loading branch information
1 parent
3b0c869
commit b474763
Showing
5 changed files
with
266 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// Copyright 2024 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package registry | ||
|
||
import ( | ||
"errors" | ||
"io" | ||
"os" | ||
|
||
"www.velocidex.com/golang/regparser" | ||
) | ||
|
||
var ( | ||
errFailedToReadClassName = errors.New("failed to read class name") | ||
) | ||
|
||
// OfflineRegistry wraps the regparser library to provide offline (from file) parsing of the Windows | ||
// registry. | ||
type OfflineRegistry struct { | ||
registry *regparser.Registry | ||
reader io.ReadCloser | ||
} | ||
|
||
// NewFromFile creates a new offline registry abstraction from a file. | ||
func NewFromFile(path string) (*OfflineRegistry, error) { | ||
f, err := os.Open(path) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
reg, err := regparser.NewRegistry(f) | ||
if err != nil { | ||
f.Close() | ||
return nil, err | ||
} | ||
|
||
return &OfflineRegistry{reg, f}, nil | ||
} | ||
|
||
// OpenKey open the requested registry key. | ||
func (o *OfflineRegistry) OpenKey(path string) Key { | ||
return &OfflineKey{o.registry.OpenKey(path)} | ||
} | ||
|
||
// Close closes the underlying reader. | ||
func (o *OfflineRegistry) Close() error { | ||
return o.reader.Close() | ||
} | ||
|
||
// OfflineKey wraps a regparser.CM_KEY_NODE to provide an implementation of the registry.Key | ||
// interface. | ||
type OfflineKey struct { | ||
key *regparser.CM_KEY_NODE | ||
} | ||
|
||
// Name returns the name of the key. | ||
func (o *OfflineKey) Name() string { | ||
return o.key.Name() | ||
} | ||
|
||
// Subkeys returns the subkeys of the key. | ||
func (o *OfflineKey) Subkeys() []Key { | ||
var subkeys []Key | ||
for _, subkey := range o.key.Subkeys() { | ||
subkeys = append(subkeys, &OfflineKey{subkey}) | ||
} | ||
|
||
return subkeys | ||
} | ||
|
||
// ClassName returns the class name of the key. | ||
func (o *OfflineKey) ClassName() ([]byte, error) { | ||
// retrieve the class name offset and skip both the first block and the first 4 bytes that | ||
// represents the size of the block. | ||
classOffset := int64(o.key.Class()) + 4096 + 4 | ||
classLen := o.key.ClassLength() | ||
buffer := make([]byte, classLen) | ||
|
||
if n, err := o.key.Reader.ReadAt(buffer, classOffset); err != nil || n != int(classLen) { | ||
return nil, errFailedToReadClassName | ||
} | ||
|
||
return buffer, nil | ||
} | ||
|
||
// Values returns the different values contained in the key. | ||
func (o *OfflineKey) Values() []Value { | ||
var values []Value | ||
for _, value := range o.key.Values() { | ||
values = append(values, &OfflineValue{value}) | ||
} | ||
|
||
return values | ||
} | ||
|
||
// OfflineValue wraps a regparser.CM_KEY_VALUE to provide an implementation of the registry.Value | ||
// interface. | ||
type OfflineValue struct { | ||
value *regparser.CM_KEY_VALUE | ||
} | ||
|
||
// Name returns the name of the value. | ||
func (o *OfflineValue) Name() string { | ||
return o.value.ValueName() | ||
} | ||
|
||
// Data returns the data contained in the value. | ||
func (o *OfflineValue) Data() []byte { | ||
return o.value.ValueData().Data | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Copyright 2024 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// Package registry provides an interface to abstract the Windows registry libraries away. | ||
// This allows providing more functionalities to registry libraries and also provide a better means | ||
// of testing. | ||
package registry | ||
|
||
// Registry represents an open registry hive. | ||
type Registry interface { | ||
// OpenKey returns a Key for the given path. | ||
OpenKey(path string) Key | ||
|
||
// Close closes the registry hive. | ||
Close() error | ||
} | ||
|
||
// Key represents a specific registry key. | ||
type Key interface { | ||
// Name returns the name of the key. | ||
Name() string | ||
|
||
// ClassName returns the name of the class for the key. | ||
ClassName() ([]byte, error) | ||
|
||
// Subkeys returns the subkeys of the key. | ||
Subkeys() []Key | ||
|
||
// Values returns the different values of the key. | ||
Values() []Value | ||
} | ||
|
||
// Value represents a value inside a specific key. | ||
type Value interface { | ||
// Name returns the name of the value. | ||
Name() string | ||
|
||
// Data returns the data of the value. | ||
Data() []byte | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// Copyright 2024 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// Package mockregistry provides a mock implementation of the registry.Registry interface. | ||
package mockregistry | ||
|
||
import ( | ||
"errors" | ||
|
||
"github.com/google/osv-scalibr/common/windows/registry" | ||
) | ||
|
||
var ( | ||
errFailedToReadClassName = errors.New("failed to read class name") | ||
) | ||
|
||
// MockRegistry mocks registry access. | ||
type MockRegistry struct { | ||
Keys map[string]registry.Key | ||
} | ||
|
||
// OpenKey open the requested registry key. | ||
func (o *MockRegistry) OpenKey(path string) registry.Key { | ||
if key, ok := o.Keys[path]; ok { | ||
return key | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Close does nothing when mocking. | ||
func (o *MockRegistry) Close() error { | ||
return nil | ||
} | ||
|
||
// MockKey mocks a registry.Key. | ||
type MockKey struct { | ||
KName string | ||
KClassName string | ||
KSubkeys []registry.Key | ||
KValues []registry.Value | ||
} | ||
|
||
// Name returns the name of the key. | ||
func (o *MockKey) Name() string { | ||
return o.KName | ||
} | ||
|
||
// Subkeys returns the subkeys of the key. | ||
func (o *MockKey) Subkeys() []registry.Key { | ||
return o.KSubkeys | ||
} | ||
|
||
// ClassName returns the class name of the key. | ||
func (o *MockKey) ClassName() ([]byte, error) { | ||
return []byte(o.KClassName), nil | ||
} | ||
|
||
// Values returns the different values contained in the key. | ||
func (o *MockKey) Values() []registry.Value { | ||
return o.KValues | ||
} | ||
|
||
// MockValue mocks a registry.Value. | ||
type MockValue struct { | ||
VName string | ||
VData []byte | ||
} | ||
|
||
// Name returns the name of the value. | ||
func (o *MockValue) Name() string { | ||
return o.VName | ||
} | ||
|
||
// Data returns the data contained in the value. | ||
func (o *MockValue) Data() []byte { | ||
return o.VData | ||
} |