github.com/iDigitalFlame/xmt@v0.5.4/cmd/filter/filter.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 filter is a separate container for the 'Filter' struct that can be used 18 // to target a specific process or one that matches an attribute set. 19 package filter 20 21 import ( 22 "github.com/iDigitalFlame/xmt/data" 23 "github.com/iDigitalFlame/xmt/util/xerr" 24 ) 25 26 const ( 27 // True is the 'true' bool value. 28 True = boolean(2) 29 // False is the 'false' bool value. 30 False = boolean(1) 31 // Empty represents the absence of a value. 32 Empty = boolean(0) 33 ) 34 35 // ErrNoProcessFound is returned by the SetParent* functions on Windows 36 // devices when a specified parent could not be found. 37 var ErrNoProcessFound = xerr.Sub("could not find a suitable process", 0x3E) 38 39 var ( 40 // Any will attempt to locate a parent process that may be elevated 41 // based on the current process permissions. 42 // 43 // This one will fall back to non-elevated if all checks fail. 44 Any = (&Filter{Fallback: true}).SetElevated(true) 45 // Random is a Filter that can be used by default to select ANY random 46 // process on the target device to be used as the parent process without 47 // creating a new Filter struct. 48 Random = &Filter{Fallback: false} 49 ) 50 51 // Filter is a struct that can be used to set the Parent process for many types 52 // of 'Runnable' compatible interfaces. 53 // 54 // Each option can be set directly or chained using the function calls which all 55 // return the struct for chain usage. 56 // 57 // This struct can be serialized into JSON or written using a Stream Marshaler. 58 type Filter struct { 59 // Exclude and Include determine the processes that can be included or omitted 60 // during process listing. 'Exclude' always takes precedence over 'Include'. 61 // 62 // Either one being nil or empty means no processes are included/excluded. 63 // All matches are case-insensitive. 64 Exclude []string 65 Include []string 66 // PID will attempt to select the PID to be used for the parent. 67 // If set to zero, it will be ignored. Values less than 5 are not valid! 68 PID uint32 69 // Fallback specifies if the opts routine should try again with less constraints 70 // than the previous attempt. All attempts will still respect the 'Exclude' 71 // and 'Ignore' directives. 72 Fallback bool 73 // Session can be set to 'True' or 'False' to attempt to target processes that 74 // are either in or not in a DWM session environment (ie: in a user desktop 75 // [True] or a service context [False]). This value is ignored if set to 'Empty'. 76 Session boolean 77 // Elevated can be set 'True' or 'False' to attempt to target processes that 78 // are in a High/System or Lower integrity context. 'True' will attempt to 79 // select elevated processes, while 'False' will select lower integrity or 80 // non-elevated processes. If set to 'Empty' or omitted, this will choose 81 // any process, regardless of integrity level. 82 Elevated boolean 83 } 84 type boolean uint8 85 type filter func(uint32, bool, string, uintptr) bool 86 87 // F is a shortcut for 'new(Filter)' 88 func F() *Filter { 89 return new(Filter) 90 } 91 92 // B is a shortcut for '&Filter{Fallback: f}' 93 func B(f bool) *Filter { 94 return &Filter{Fallback: f} 95 } 96 97 // I is a shortcut for '&Filter{Include: s}' 98 func I(s ...string) *Filter { 99 return &Filter{Include: s} 100 } 101 102 // E is a shortcut for '&Filter{Exclude: s}' 103 func E(s ...string) *Filter { 104 return &Filter{Exclude: s} 105 } 106 107 // Empty will return true if this Filter is nil or unset. 108 func (f *Filter) Empty() bool { 109 return f == nil || f.isEmpty() 110 } 111 func (f Filter) isEmpty() bool { 112 return f.PID == 0 && f.Session == Empty && f.Elevated == Empty && len(f.Exclude) == 0 && len(f.Include) == 0 113 } 114 115 // Clear clears the Filter settings, except for 'Fallback' and returns itself. 116 func (f *Filter) Clear() *Filter { 117 f.PID, f.Session, f.Elevated, f.Exclude, f.Include = 0, Empty, Empty, nil, nil 118 return f 119 } 120 121 // SetPID sets the target PID and returns the Filter struct. 122 func (f *Filter) SetPID(p uint32) *Filter { 123 f.PID = p 124 return f 125 } 126 127 // SetSession sets the Session setting to 'True' or 'False' and returns itself. 128 func (f *Filter) SetSession(s bool) *Filter { 129 if s { 130 f.Session = True 131 } else { 132 f.Session = False 133 } 134 return f 135 } 136 137 // SetElevated sets the Elevated setting to 'True' or 'False' and returns itself. 138 func (f *Filter) SetElevated(e bool) *Filter { 139 if e { 140 f.Elevated = True 141 } else { 142 f.Elevated = False 143 } 144 return f 145 } 146 147 // SetFallback sets the Fallback setting and returns itself. 148 func (f *Filter) SetFallback(i bool) *Filter { 149 f.Fallback = i 150 return f 151 } 152 153 // SetInclude sets the Inclusion list and returns itself. 154 func (f *Filter) SetInclude(n ...string) *Filter { 155 f.Include = n 156 return f 157 } 158 159 // SetExclude sets the Exclusion list and returns itself. 160 func (f *Filter) SetExclude(n ...string) *Filter { 161 f.Exclude = n 162 return f 163 } 164 165 // MarshalStream will attempt to write the Filter data to the supplied Writer 166 // and return any errors that may occur. 167 func (f *Filter) MarshalStream(w data.Writer) error { 168 if f == nil || f.isEmpty() { 169 return w.WriteBool(false) 170 } 171 if err := w.WriteBool(true); err != nil { 172 return err 173 } 174 if err := w.WriteUint32(f.PID); err != nil { 175 return err 176 } 177 if err := w.WriteBool(f.Fallback); err != nil { 178 return err 179 } 180 if err := w.WriteUint8(uint8(f.Session)); err != nil { 181 return err 182 } 183 if err := w.WriteUint8(uint8(f.Elevated)); err != nil { 184 return err 185 } 186 if err := data.WriteStringList(w, f.Exclude); err != nil { 187 return err 188 } 189 return data.WriteStringList(w, f.Include) 190 } 191 192 // UnmarshalStream will attempt to read the Filter data from the supplied Reader 193 // and return any errors that may occur. 194 func (f *Filter) UnmarshalStream(r data.Reader) error { 195 v, err := r.Bool() 196 if err != nil { 197 return err 198 } 199 if !v { 200 return nil 201 } 202 if f == nil { 203 f = new(Filter) 204 } 205 return f.unmarshalStream(r) 206 } 207 func (f *Filter) unmarshalStream(r data.Reader) error { 208 if err := r.ReadUint32(&f.PID); err != nil { 209 return err 210 } 211 if err := r.ReadBool(&f.Fallback); err != nil { 212 return err 213 } 214 if err := r.ReadUint8((*uint8)(&f.Session)); err != nil { 215 return err 216 } 217 if err := r.ReadUint8((*uint8)(&f.Elevated)); err != nil { 218 return err 219 } 220 if err := data.ReadStringList(r, &f.Exclude); err != nil { 221 return err 222 } 223 return data.ReadStringList(r, &f.Include) 224 } 225 226 // UnmarshalStream will attempt to read the Filter data from the supplied Reader 227 // and return any errors that may occur. 228 // 229 // This function takes a pointer of the Filter pointer so it can fill in any 230 // nil or empty Filters with data for a new Filter struct. 231 func UnmarshalStream(r data.Reader, f **Filter) error { 232 v, err := r.Bool() 233 if err != nil { 234 return err 235 } 236 if !v { 237 return nil 238 } 239 if *f == nil { 240 *f = new(Filter) 241 } 242 return (*f).unmarshalStream(r) 243 }