github.com/iDigitalFlame/xmt@v0.5.4/device/regedit/entry.go (about) 1 // Copyright (C) 2020 - 2023 iDigitalFlame 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation, either version 3 of the License, or 6 // any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU General Public License for more details. 12 // 13 // You should have received a copy of the GNU General Public License 14 // along with this program. If not, see <https://www.gnu.org/licenses/>. 15 // 16 17 // Package regedit is a helper package that allows easy access to the Windows 18 // registry on Windows systems and allows non-Windows systems to read data generated 19 // from registry entries. 20 package regedit 21 22 import ( 23 "unsafe" 24 25 "github.com/iDigitalFlame/xmt/data" 26 "github.com/iDigitalFlame/xmt/device/winapi" 27 "github.com/iDigitalFlame/xmt/device/winapi/registry" 28 ) 29 30 // Entry represents a Windows registry entry. 31 // 32 // This may represent a Key or a Value. Values will also include their data in 33 // the 'Data' byte array and can be translated using any of the 'To*' functions 34 // to get the data represented in its proper type cast. 35 type Entry struct { 36 Name string 37 Data []byte 38 Type uint32 39 } 40 41 // IsKey returns true if this entry represents a SubKey. 42 func (e Entry) IsKey() bool { 43 return e.Type == 0 44 } 45 46 // IsZero returns true if this entry is an invalid Entry. 47 func (e Entry) IsZero() bool { 48 return e.Type == 0 && len(e.Data) == 0 && len(e.Name) == 0 49 } 50 51 // ToBinary will attempt to return the data in the Data buffer as a binary 52 // array. 53 // 54 // This function returns an error if conversion fails or the specified type is 55 // not a BINARY type. 56 func (e Entry) ToBinary() ([]byte, error) { 57 if e.Type != registry.TypeBinary { 58 return nil, registry.ErrUnexpectedType 59 } 60 return e.Data, nil 61 } 62 63 // ToString will attempt to return the data in the Data buffer as a string. 64 // 65 // This function returns an error if conversion fails or the specified type is 66 // not a STRING or EXPAND_STRING type. 67 func (e Entry) ToString() (string, error) { 68 if e.Type != registry.TypeString && e.Type != registry.TypeExpandString { 69 return "", registry.ErrUnexpectedType 70 } 71 if len(e.Data) < 3 { 72 return "", registry.ErrUnexpectedSize 73 } 74 return winapi.UTF16ToString((*[1 << 29]uint16)(unsafe.Pointer(&e.Data[0]))[: len(e.Data)/2 : len(e.Data)/2]), nil 75 } 76 77 // ToInteger will attempt to return the data in the Data buffer as an unsigned 78 // integer. 79 // 80 // This function returns an error if conversion fails or the specified type is 81 // not a DWORD or QWORD type. 82 func (e Entry) ToInteger() (uint64, error) { 83 switch e.Type { 84 case registry.TypeDword: 85 if len(e.Data) != 4 { 86 return 0, registry.ErrUnexpectedSize 87 } 88 _ = e.Data[3] 89 return uint64(e.Data[0]) | uint64(e.Data[1])<<8 | uint64(e.Data[2])<<16 | uint64(e.Data[3])<<24, nil 90 case registry.TypeQword: 91 if len(e.Data) != 8 { 92 return 0, registry.ErrUnexpectedSize 93 } 94 _ = e.Data[7] 95 return uint64(e.Data[0]) | uint64(e.Data[1])<<8 | uint64(e.Data[2])<<16 | uint64(e.Data[3])<<24 | 96 uint64(e.Data[4])<<32 | uint64(e.Data[5])<<40 | uint64(e.Data[6])<<48 | uint64(e.Data[7])<<56, nil 97 } 98 return 0, registry.ErrUnexpectedType 99 } 100 101 // ToStringList will attempt to return the data in the Data buffer as a string 102 // array. 103 // 104 // This function returns an error if conversion fails or the specified type is 105 // not a MULTI_STRING type. 106 func (e Entry) ToStringList() ([]string, error) { 107 if e.Type != registry.TypeStringList { 108 return nil, registry.ErrUnexpectedType 109 } 110 if len(e.Data) < 3 { 111 return nil, registry.ErrUnexpectedSize 112 } 113 v := (*[1 << 29]uint16)(unsafe.Pointer(&e.Data[0]))[: len(e.Data)/2 : len(e.Data)/2] 114 if len(v) == 0 { 115 return nil, nil 116 } 117 if v[len(v)-1] == 0 { 118 v = v[:len(v)-1] 119 } 120 r := make([]string, 0, len(v)) 121 for i, n := 0, 0; i < len(v); i++ { 122 if v[i] > 0 { 123 continue 124 } 125 r = append(r, string(winapi.UTF16Decode(v[n:i]))) 126 n = i + 1 127 } 128 return r, nil 129 } 130 131 // MarshalStream writes the data for this Entry to the supplied Writer. 132 func (e Entry) MarshalStream(w data.Writer) error { 133 if err := w.WriteString(e.Name); err != nil { 134 return err 135 } 136 if err := w.WriteUint32(e.Type); err != nil { 137 return err 138 } 139 return w.WriteBytes(e.Data) 140 } 141 142 // UnmarshalStream reads the data for this Entry from the supplied Reader. 143 func (e *Entry) UnmarshalStream(r data.Reader) error { 144 if err := r.ReadString(&e.Name); err != nil { 145 return err 146 } 147 if err := r.ReadUint32(&e.Type); err != nil { 148 return err 149 } 150 return r.ReadBytes(&e.Data) 151 }