github.com/iDigitalFlame/xmt@v0.5.4/c2/task/result/v_no_implant.go (about)

     1  //go:build !implant
     2  // +build !implant
     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 result contains many helper functions to gather matching output
    21  // from Job result packets.
    22  package result
    23  
    24  import (
    25  	"io"
    26  	"os"
    27  	"time"
    28  
    29  	"github.com/iDigitalFlame/xmt/c2"
    30  	"github.com/iDigitalFlame/xmt/cmd"
    31  	"github.com/iDigitalFlame/xmt/com"
    32  	"github.com/iDigitalFlame/xmt/data"
    33  	"github.com/iDigitalFlame/xmt/device"
    34  	"github.com/iDigitalFlame/xmt/device/regedit"
    35  )
    36  
    37  // Window is a struct that represents a Windows Window. The handles are the same
    38  // for the duration of the Window's existence.
    39  //
    40  // Copied here from the winapi package.
    41  type Window struct {
    42  	_             [0]func()
    43  	Name          string
    44  	Flags         uint8
    45  	Handle        uintptr
    46  	X, Y          int32
    47  	Width, Height int32
    48  }
    49  type fileInfo struct {
    50  	_    [0]func()
    51  	mod  time.Time
    52  	name string
    53  	size int64
    54  	mode os.FileMode
    55  }
    56  
    57  // FuncEntry is a simple struct that is used to describe the current status of
    58  // function mappings. This struct is returned by a call to 'FuncRemaps' in a
    59  // slice of current remaps.
    60  //
    61  // Copied here from the winapi package.
    62  type FuncEntry struct {
    63  	_        [0]func()
    64  	Hash     uint32
    65  	Swapped  uintptr
    66  	Original uintptr
    67  }
    68  
    69  func (f fileInfo) Size() int64 {
    70  	return f.size
    71  }
    72  func (f fileInfo) IsDir() bool {
    73  	return f.mode.IsDir()
    74  }
    75  func (f fileInfo) Name() string {
    76  	return f.name
    77  }
    78  func (fileInfo) Sys() interface{} {
    79  	return nil
    80  }
    81  
    82  // IsMinimized returns true if the Window state was minimized at the time of
    83  // discovery.
    84  func (w Window) IsMinimized() bool {
    85  	return w.Flags&0x2 != 0
    86  }
    87  
    88  // IsMaximized returns true if the Window state was maximized at the time of
    89  // discovery.
    90  func (w Window) IsMaximized() bool {
    91  	return w.Flags&0x1 != 0
    92  }
    93  func (f fileInfo) Mode() os.FileMode {
    94  	return f.mode
    95  }
    96  func (f fileInfo) ModTime() time.Time {
    97  	return f.mod
    98  }
    99  
   100  // Pwd will parse the RvResult Packet from a MvPwd task.
   101  //
   102  // The return result is the current directory the client is located in.
   103  //
   104  // This function returns an error if any reading errors occur, the Packet is not
   105  // in the expected format or the Packet is nil or empty.
   106  func Pwd(n *com.Packet) (string, error) {
   107  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   108  		return "", c2.ErrMalformedPacket
   109  	}
   110  	return n.StringVal()
   111  }
   112  
   113  // Spawn will parse the RvResult Packet from a MvSpawn task.
   114  //
   115  // The return result is the new PID of the resulting Spawn operation.
   116  //
   117  // This function returns an error if any reading errors occur, the Packet is not
   118  // in the expected format or the Packet is nil or empty.
   119  func Spawn(n *com.Packet) (uint32, error) {
   120  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   121  		return 0, c2.ErrMalformedPacket
   122  	}
   123  	return n.Uint32()
   124  }
   125  
   126  // CheckDLL will parse the RvResult Packet from a TvCheck task.
   127  //
   128  // The return result is true if the DLL provided is NOT hooked. A return value
   129  // of false indicates that the DLL memory space differs from the on-disk value,
   130  // which is an indicator of hooks.
   131  //
   132  // This function returns an error if any reading errors occur, the Packet is not
   133  // in the expected format or the Packet is nil or empty.
   134  func CheckDLL(n *com.Packet) (bool, error) {
   135  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   136  		return false, c2.ErrMalformedPacket
   137  	}
   138  	return n.Bool()
   139  }
   140  
   141  // Mounts will parse the RvResult Packet from a MvMounts task.
   142  //
   143  // The return result is a string list of all the exposed mount points on the
   144  // client (drive letters on Windows).
   145  //
   146  // This function returns an error if any reading errors occur, the Packet is not
   147  // in the expected format or the Packet is nil or empty.
   148  func Mounts(n *com.Packet) ([]string, error) {
   149  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   150  		return nil, c2.ErrMalformedPacket
   151  	}
   152  	var s []string
   153  	return s, data.ReadStringList(n, &s)
   154  }
   155  
   156  // IsDebugged will parse the RvResult Packet from a TvCheckDebug task.
   157  //
   158  // The return result is True if a debugger is detected, false otherwise.
   159  //
   160  // This function returns an error if any reading errors occur, the Packet is not
   161  // in the expected format or the Packet is nil or empty.
   162  func IsDebugged(n *com.Packet) (bool, error) {
   163  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   164  		return false, c2.ErrMalformedPacket
   165  	}
   166  	return n.Bool()
   167  }
   168  
   169  // Ls will parse the RvResult Packet from a MvList task.
   170  //
   171  // The return result is a slice of FileInfo interfaces that will return the
   172  // data of the directory targeted.
   173  //
   174  // This function returns an error if any reading errors occur, the Packet is not
   175  // in the expected format or the Packet is nil or empty.
   176  func Ls(n *com.Packet) ([]os.FileInfo, error) {
   177  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   178  		return nil, c2.ErrMalformedPacket
   179  	}
   180  	c, err := n.Uint32()
   181  	if err != nil || c == 0 {
   182  		return nil, err
   183  	}
   184  	e := make([]os.FileInfo, c)
   185  	for i := range e {
   186  		var v fileInfo
   187  		if err = n.ReadString(&v.name); err != nil {
   188  			return nil, err
   189  		}
   190  		if err = n.ReadUint32((*uint32)(&v.mode)); err != nil {
   191  			return nil, err
   192  		}
   193  		if err = n.ReadInt64(&v.size); err != nil {
   194  			return nil, err
   195  		}
   196  		t, err := n.Int64()
   197  		if err != nil {
   198  			return nil, err
   199  		}
   200  		v.mod = time.Unix(t, 0)
   201  		e[i] = v
   202  	}
   203  	return e, nil
   204  }
   205  
   206  // Netcat will parse the RvResult Packet from a TvNetcat task.
   207  //
   208  // The return result is a Reader with the resulting output data from the read
   209  // request. If reading was not done, this will just return nil.
   210  //
   211  // This function returns an error if any reading errors occur, the Packet is not
   212  // in the expected format or the Packet is nil.
   213  func Netcat(n *com.Packet) (io.Reader, error) {
   214  	if n == nil || n.Flags&com.FlagError != 0 {
   215  		return nil, c2.ErrMalformedPacket
   216  	}
   217  	if n.Empty() {
   218  		return nil, nil
   219  	}
   220  	return n, nil
   221  }
   222  
   223  // WindowList will parse the RvResult Packet from a TvWindows task.
   224  //
   225  // The return result is a slice of 'Window' structs that will indicate
   226  // the current Windows open on the target device.
   227  //
   228  // This function returns an error if any reading errors occur, the Packet is not
   229  // in the expected format or the Packet is nil or empty.
   230  func WindowList(n *com.Packet) ([]Window, error) {
   231  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   232  		return nil, c2.ErrMalformedPacket
   233  	}
   234  	c, err := n.Uint32()
   235  	if err != nil {
   236  		return nil, err
   237  	}
   238  	e := make([]Window, c)
   239  	for i := range e {
   240  		if err = e[i].UnmarshalStream(n); err != nil {
   241  			return nil, err
   242  		}
   243  	}
   244  	return e, nil
   245  }
   246  
   247  // ScreenShot will parse the RvResult Packet from a TvScreenShot task.
   248  //
   249  // The return result is a Reader with the resulting screenshot data encoded as
   250  // a PNG image inside. (This can be directly written to disk as a PNG file).
   251  //
   252  // This function returns an error if any reading errors occur, the Packet is not
   253  // in the expected format or the Packet is nil or empty.
   254  func ScreenShot(n *com.Packet) (io.Reader, error) {
   255  	return ProcessDump(n)
   256  }
   257  
   258  // Script will parse the RvResult Packet from a MvScript task.
   259  //
   260  // The return result is a slice of the resulting Packet output. Some flags may
   261  // have their error values set, so it is important to check beforehand.
   262  //
   263  // This function returns an error if any reading errors occur, the Packet is not
   264  // in the expected format or the Packet is nil or empty.
   265  func Script(n *com.Packet) ([]*com.Packet, error) {
   266  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   267  		return nil, c2.ErrMalformedPacket
   268  	}
   269  	var (
   270  		d   []byte
   271  		r   []*com.Packet
   272  		e   bool
   273  		err error
   274  	)
   275  	for err == nil {
   276  		var v com.Packet
   277  		if err = n.ReadUint8(&v.ID); err != nil {
   278  			break
   279  		}
   280  		if err = n.ReadBool(&e); err != nil {
   281  			break
   282  		}
   283  		if !e {
   284  			var m string
   285  			if err = n.ReadString(&m); err != nil {
   286  				break
   287  			}
   288  			v.Flags = com.FlagError
   289  			v.WriteString(m)
   290  			r = append(r, &v)
   291  			continue
   292  		}
   293  		if err = n.ReadBytes(&d); err != nil && err != io.EOF {
   294  			break
   295  		}
   296  		v.Grow(len(d))
   297  		v.Write(d)
   298  		d, r, err = nil, append(r, &v), nil
   299  	}
   300  	if err == io.EOF {
   301  		return r, nil
   302  	}
   303  	return r, err
   304  }
   305  
   306  // ProcessDump will parse the RvResult Packet from a TvProcDump task.
   307  //
   308  // The return result is a Reader with the resulting dump data inside.
   309  //
   310  // This function returns an error if any reading errors occur, the Packet is not
   311  // in the expected format or the Packet is nil or empty.
   312  func ProcessDump(n *com.Packet) (io.Reader, error) {
   313  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   314  		return nil, c2.ErrMalformedPacket
   315  	}
   316  	return n, nil
   317  }
   318  
   319  // Upload will parse the RvResult Packet from a TvUpload task.
   320  //
   321  // The return result is the expended full file path on the host as a string, and
   322  // the resulting count of bytes written to disk.
   323  //
   324  // This function returns an error if any reading errors occur, the Packet is not
   325  // in the expected format or the Packet is nil or empty.
   326  func Upload(n *com.Packet) (string, uint64, error) {
   327  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   328  		return "", 0, c2.ErrMalformedPacket
   329  	}
   330  	var (
   331  		s   string
   332  		c   uint64
   333  		err = n.ReadString(&s)
   334  	)
   335  	if err != nil {
   336  		return "", 0, err
   337  	}
   338  	if err = n.ReadUint64(&c); err != nil {
   339  		return "", 0, err
   340  	}
   341  	return s, c, nil
   342  }
   343  
   344  // Whoami will parse the RvResult Packet from a MvWhoami task.
   345  //
   346  // The return result is the current username the client is running under and the
   347  // path if the current Process.
   348  //
   349  // This function returns an error if any reading errors occur, the Packet is not
   350  // in the expected format or the Packet is nil or empty.
   351  func Whoami(n *com.Packet) (string, string, error) {
   352  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   353  		return "", "", c2.ErrMalformedPacket
   354  	}
   355  	var u, p string
   356  	if err := n.ReadString(&u); err != nil {
   357  		return "", "", err
   358  	}
   359  	if err := n.ReadString(&p); err != nil {
   360  		return "", "", err
   361  	}
   362  	return u, p, nil
   363  }
   364  
   365  // UnmarshalStream transforms this struct from a binary format that is read from
   366  // the supplied data.Reader.
   367  func (w *Window) UnmarshalStream(r data.Reader) error {
   368  	v, err := r.Uint64()
   369  	if err != nil {
   370  		return err
   371  	}
   372  	w.Handle = uintptr(v)
   373  	if err = r.ReadString(&w.Name); err != nil {
   374  		return err
   375  	}
   376  	if err = r.ReadUint8(&w.Flags); err != nil {
   377  		return err
   378  	}
   379  	if err = r.ReadInt32(&w.X); err != nil {
   380  		return err
   381  	}
   382  	if err = r.ReadInt32(&w.Y); err != nil {
   383  		return err
   384  	}
   385  	if err = r.ReadInt32(&w.Width); err != nil {
   386  		return err
   387  	}
   388  	return r.ReadInt32(&w.Height)
   389  }
   390  
   391  // FuncRemapList will parse the RvResult Packet from a TvFuncMapList task.
   392  //
   393  // The return result is a slice of 'FuncEntry' structs that will indicate
   394  // the current function mappings on the target device.
   395  //
   396  // This function returns an error if any reading errors occur, the Packet is not
   397  // in the expected format or the Packet is nil or empty.
   398  func FuncRemapList(n *com.Packet) ([]FuncEntry, error) {
   399  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   400  		return nil, c2.ErrMalformedPacket
   401  	}
   402  	c, err := n.Uint32()
   403  	if err != nil {
   404  		return nil, err
   405  	}
   406  	e := make([]FuncEntry, c)
   407  	for i := range e {
   408  		if err = e[i].UnmarshalStream(n); err != nil {
   409  			return nil, err
   410  		}
   411  	}
   412  	return e, nil
   413  }
   414  
   415  // UserLogins will parse the RvResult Packet from a TvLogins task.
   416  //
   417  // The return result is a slice of 'device.Login' structs that will indicate
   418  // the current active Sessions (Logins) on the target device.
   419  //
   420  // This function returns an error if any reading errors occur, the Packet is not
   421  // in the expected format or the Packet is nil or empty.
   422  func UserLogins(n *com.Packet) ([]device.Login, error) {
   423  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   424  		return nil, c2.ErrMalformedPacket
   425  	}
   426  	c, err := n.Uint16()
   427  	if err != nil {
   428  		return nil, err
   429  	}
   430  	e := make([]device.Login, c)
   431  	for i := range e {
   432  		if err = e[i].UnmarshalStream(n); err != nil {
   433  			return nil, err
   434  		}
   435  	}
   436  	return e, nil
   437  }
   438  
   439  // DLL will parse the RvResult Packet from a TvDLL task.
   440  //
   441  // The return result is a handle to the memory location of the DLL (as an
   442  // uintptr), the resulting PID of the DLL "host" and the exit code of the
   443  // primary thread (if wait was specified, otherwise this is zero).
   444  //
   445  // This function returns an error if any reading errors occur, the Packet is not
   446  // in the expected format or the Packet is nil or empty.
   447  func DLL(n *com.Packet) (uintptr, uint32, int32, error) {
   448  	return Assembly(n)
   449  }
   450  
   451  // UnmarshalStream transforms this struct from a binary format that is read from
   452  // the supplied data.Reader.
   453  func (e *FuncEntry) UnmarshalStream(r data.Reader) error {
   454  	if err := r.ReadUint32(&e.Hash); err != nil {
   455  		return err
   456  	}
   457  	v, err := r.Uint64()
   458  	if err != nil {
   459  		return err
   460  	}
   461  	e.Original = uintptr(v)
   462  	if v, err = r.Uint64(); err != nil {
   463  		return err
   464  	}
   465  	e.Swapped = uintptr(v)
   466  	return nil
   467  }
   468  
   469  // ProcessList will parse the RvResult Packet from a TvProcList task.
   470  //
   471  // The return result is a slice of 'cmd.ProcessInfo' structs that will indicate
   472  // the current processes running on the target device.
   473  //
   474  // This function returns an error if any reading errors occur, the Packet is not
   475  // in the expected format or the Packet is nil or empty.
   476  func ProcessList(n *com.Packet) ([]cmd.ProcessInfo, error) {
   477  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   478  		return nil, c2.ErrMalformedPacket
   479  	}
   480  	c, err := n.Uint32()
   481  	if err != nil {
   482  		return nil, err
   483  	}
   484  	e := make([]cmd.ProcessInfo, c)
   485  	for i := range e {
   486  		if err = e[i].UnmarshalStream(n); err != nil {
   487  			return nil, err
   488  		}
   489  	}
   490  	return e, nil
   491  }
   492  
   493  // SystemIO will parse the RvResult Packet from a TvSystemIO task.
   494  //
   495  // The return result is dependent on the resulting operation. If the result is
   496  // from a 'Move' or 'Copy' operation, this will return the resulting path and
   497  // new file size.
   498  //
   499  // The boolean value will return true if the result was a valid command that
   500  // returns no output, such as a Touch, Delete or Kill operation.
   501  //
   502  // This function returns an error if any reading errors occur, the Packet is not
   503  // in the expected format or the Packet is nil or empty.
   504  func SystemIO(n *com.Packet) (string, uint64, bool, error) {
   505  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   506  		return "", 0, false, c2.ErrMalformedPacket
   507  	}
   508  	o, err := n.Uint8()
   509  	if err != nil {
   510  		return "", 0, false, c2.ErrMalformedPacket
   511  	}
   512  	if o != 2 && o != 3 {
   513  		return "", 0, true, nil
   514  	}
   515  	var (
   516  		i uint64
   517  		v string
   518  	)
   519  	if err = n.ReadString(&v); err != nil {
   520  		return "", 0, false, err
   521  	}
   522  	if err = n.ReadUint64(&i); err != nil {
   523  		return "", 0, false, err
   524  	}
   525  	return v, i, true, nil
   526  }
   527  
   528  // Registry will parse the RvResult Packet from a TvRegistry task.
   529  //
   530  // The return result is dependent on the resulting operation. If the result is
   531  // from a 'RegLs' or 'RegGet' operation, this will return the resulting entries
   532  // found (only one entry if this was a Get operation).
   533  //
   534  // The boolean value will return true if the result was a valid registry command
   535  // that returns no output, such as a Set operation.
   536  //
   537  // This function returns an error if any reading errors occur, the Packet is not
   538  // in the expected format or the Packet is nil or empty.
   539  func Registry(n *com.Packet) ([]regedit.Entry, bool, error) {
   540  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   541  		return nil, false, c2.ErrMalformedPacket
   542  	}
   543  	o, err := n.Uint8()
   544  	if err != nil {
   545  		return nil, false, c2.ErrMalformedPacket
   546  	}
   547  	if o > 1 {
   548  		return nil, o < 13, nil
   549  	}
   550  	var c uint32
   551  	if o == 0 {
   552  		if err = n.ReadUint32(&c); err != nil {
   553  			return nil, false, err
   554  		}
   555  		if c == 0 {
   556  			return nil, false, nil
   557  		}
   558  	} else {
   559  		c = 1
   560  	}
   561  	r := make([]regedit.Entry, c)
   562  	for i := range r {
   563  		if err = r[i].UnmarshalStream(n); err != nil {
   564  			return nil, false, err
   565  		}
   566  	}
   567  	return r, true, nil
   568  }
   569  
   570  // Pull will parse the RvResult Packet from a TvPull task.
   571  //
   572  // The return result is the expended full file path on the host as a string, and
   573  // the resulting count of bytes written to disk.
   574  //
   575  // If the Pull path was empty, the returned results will instead be returned
   576  // via the supplied Reader, which will not be nil. When this occurs the string
   577  // and size values will be "" and zero.
   578  //
   579  // This function returns an error if any reading errors occur, the Packet is not
   580  // in the expected format or the Packet is nil or empty.
   581  func Pull(n *com.Packet) (string, uint64, io.Reader, error) {
   582  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   583  		return "", 0, nil, c2.ErrMalformedPacket
   584  	}
   585  	var (
   586  		s   string
   587  		c   uint64
   588  		err = n.ReadString(&s)
   589  	)
   590  	if err != nil {
   591  		return "", 0, nil, err
   592  	}
   593  	if err = n.ReadUint64(&c); err != nil {
   594  		return "", 0, nil, err
   595  	}
   596  	if len(s) == 0 && c == 0 {
   597  		return "", 0, n, nil
   598  	}
   599  	return s, c, nil, nil
   600  }
   601  
   602  // Assembly will parse the RvResult Packet from a TvAssembly task.
   603  //
   604  // The return result is a handle to the memory location of the Assembly code (as
   605  // an uintptr), the resulting PID of the Assembly "host" and the exit code of the
   606  // primary thread (if wait was specified, otherwise this is zero).
   607  //
   608  // This function returns an error if any reading errors occur, the Packet is not
   609  // in the expected format or the Packet is nil or empty.
   610  func Assembly(n *com.Packet) (uintptr, uint32, int32, error) {
   611  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   612  		return 0, 0, 0, c2.ErrMalformedPacket
   613  	}
   614  	var (
   615  		h   uint64
   616  		p   uint32
   617  		x   int32
   618  		err = n.ReadUint64(&h)
   619  	)
   620  	if err != nil {
   621  		return 0, 0, 0, err
   622  	}
   623  	if err = n.ReadUint32(&p); err != nil {
   624  		return 0, 0, 0, err
   625  	}
   626  	if err = n.ReadInt32(&x); err != nil {
   627  		return 0, 0, 0, err
   628  	}
   629  	return uintptr(h), p, x, nil
   630  }
   631  
   632  // Zombie will parse the RvResult Packet from a TvZombie task.
   633  //
   634  // The return result is the spawned PID of the new process and the resulting
   635  // exit code and Stdout/Stderr data (if wait was specified, otherwise this the
   636  // return code is zero and the reader will be empty).
   637  //
   638  // This function returns an error if any reading errors occur, the Packet is not
   639  // in the expected format or the Packet is nil or empty.
   640  func Zombie(n *com.Packet) (uint32, int32, io.Reader, error) {
   641  	return Process(n)
   642  }
   643  
   644  // Process will parse the RvResult Packet from a TvExecute task.
   645  //
   646  // The return result is the spawned PID of the new process and the resulting
   647  // exit code and Stdout/Stderr data (if wait was specified, otherwise this the
   648  // return code is zero and the reader will be empty).
   649  //
   650  // This function returns an error if any reading errors occur, the Packet is not
   651  // in the expected format or the Packet is nil or empty.
   652  func Process(n *com.Packet) (uint32, int32, io.Reader, error) {
   653  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   654  		return 0, 0, nil, c2.ErrMalformedPacket
   655  	}
   656  	var (
   657  		p   uint32
   658  		x   int32
   659  		err = n.ReadUint32(&p)
   660  	)
   661  	if err != nil {
   662  		return 0, 0, nil, err
   663  	}
   664  	if err = n.ReadInt32(&x); err != nil {
   665  		return 0, 0, nil, err
   666  	}
   667  	return p, x, n, nil
   668  }
   669  
   670  // PullExec will parse the RvResult Packet from a TvPullExecute task.
   671  //
   672  // The return result is the spawned PID of the new process and the resulting
   673  // exit code and Stdout/Stderr data (if wait was specified, otherwise this the
   674  // return code is zero and the reader will be empty).
   675  //
   676  // This function returns an error if any reading errors occur, the Packet is not
   677  // in the expected format or the Packet is nil or empty.
   678  func PullExec(n *com.Packet) (uint32, int32, io.Reader, error) {
   679  	return Process(n)
   680  }
   681  
   682  // UserProcessList will parse the RvResult Packet from a TvLoginsProc task.
   683  //
   684  // The return result is a slice of 'cmd.ProcessInfo' structs that will indicate
   685  // the current processes running on the target device.
   686  //
   687  // This function returns an error if any reading errors occur, the Packet is not
   688  // in the expected format or the Packet is nil or empty.
   689  func UserProcessList(n *com.Packet) ([]cmd.ProcessInfo, error) {
   690  	return ProcessList(n)
   691  }
   692  
   693  // Download will parse the RvResult Packet from a TvDownload task.
   694  //
   695  // The return result is the expended full file path on the host as a string,
   696  // a boolean representing if the path requested is a directory (true if the path
   697  // is a directory, false otherwise), the size of the data in bytes (zero if the
   698  // target is a directory) and a reader with the resulting file data (empty if
   699  // the target is a directory).
   700  //
   701  // This function returns an error if any reading errors occur, the Packet is not
   702  // in the expected format or the Packet is nil or empty.
   703  func Download(n *com.Packet) (string, bool, uint64, io.Reader, error) {
   704  	if n == nil || n.Empty() || n.Flags&com.FlagError != 0 {
   705  		return "", false, 0, nil, c2.ErrMalformedPacket
   706  	}
   707  	var (
   708  		s   string
   709  		d   bool
   710  		c   uint64
   711  		err = n.ReadString(&s)
   712  	)
   713  	if err != nil {
   714  		return "", false, 0, nil, err
   715  	}
   716  	if err = n.ReadBool(&d); err != nil {
   717  		return "", false, 0, nil, err
   718  	}
   719  	if err = n.ReadUint64(&c); err != nil {
   720  		return "", false, 0, nil, err
   721  	}
   722  	return s, d, c, n, nil
   723  }