github.com/iDigitalFlame/xmt@v0.5.4/cmd/zombie.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 cmd
    18  
    19  import "context"
    20  
    21  // Zombie is a struct that represents an Assembly backed process.
    22  // This is similar to 'execute-assembly' and will launch a suspended process to be
    23  // injected into.
    24  //
    25  // The 'Path' or 'Data' arguments can be used to specify a DLL path or shellcode
    26  // to be ran by the zombie. The 'Data' argument takes precedence over 'Path'.
    27  // At least one of them must be supplied or an 'ErrEmptyCommand' error will be
    28  // returned on any calls to 'Start'.
    29  //
    30  // This struct shares many of the same methods as the 'Process' struct.
    31  // The 'SetParent' function will affect the parent of the spawned process.
    32  type Zombie struct {
    33  	Data []byte
    34  	t    thread
    35  	Process
    36  }
    37  
    38  // Run will start the Zombie and wait until it completes. This function will
    39  // return the same errors as the 'Start' function if they occur or the 'Wait'
    40  // function if any errors occur during Process runtime.
    41  func (z *Zombie) Run() error {
    42  	if err := z.Start(); err != nil {
    43  		return err
    44  	}
    45  	return z.t.Wait()
    46  }
    47  
    48  // Wait will block until the Zombie completes or is terminated by a call to Stop.
    49  // This will start the process if not already started.
    50  func (z *Zombie) Wait() error {
    51  	if !z.t.Running() {
    52  		if err := z.Start(); err != nil {
    53  			return err
    54  		}
    55  	}
    56  	err := z.t.Wait()
    57  	z.Process.Wait()
    58  	// NOTE(dij): Fix for threads that load a secondary thread to prevent
    59  	//            premature exits.
    60  	return err
    61  }
    62  
    63  // Stop will attempt to terminate the currently running Zombie instance.
    64  // Stopping a Zombie may prevent the ability to read the Stdout/Stderr and any
    65  // proper exit codes.
    66  func (z *Zombie) Stop() error {
    67  	if !z.t.Running() {
    68  		return nil
    69  	}
    70  	if err := z.t.Stop(); err != nil {
    71  		return err
    72  	}
    73  	return z.Process.Stop()
    74  }
    75  
    76  // Running returns true if the current Zombie is running, false otherwise.
    77  func (z *Zombie) Running() bool {
    78  	return z.t.Running()
    79  }
    80  
    81  // Resume will attempt to resume this process. This will attempt to resume
    82  // the process using an OS-dependent syscall.
    83  //
    84  // This will not affect already running processes.
    85  func (z *Zombie) Resume() error {
    86  	return z.t.Resume()
    87  }
    88  
    89  // Suspend will attempt to suspend this process. This will attempt to suspend
    90  // the process using an OS-dependent syscall.
    91  //
    92  // This will not affect already suspended processes.
    93  func (z *Zombie) Suspend() error {
    94  	return z.t.Suspend()
    95  }
    96  
    97  // Release will attempt to release the resources for this Zombie, including
    98  // handles.
    99  //
   100  // After the first call to this function, all other function calls will fail
   101  // with errors. Repeated calls to this function return nil and are a NOP.
   102  func (z *Zombie) Release() error {
   103  	if !z.x.isStarted() {
   104  		return ErrNotStarted
   105  	}
   106  	z.x.close()
   107  	return z.t.Release()
   108  }
   109  
   110  // SetSuspended will delay the execution of this thread and will put the
   111  // thread in a suspended state until it is resumed using a Resume call.
   112  //
   113  // This function has no effect if the device is not running Windows.
   114  func (z *Zombie) SetSuspended(s bool) {
   115  	z.t.SetSuspended(s)
   116  }
   117  
   118  // ExitCode returns the Exit Code of the Zombie thread. If the Zombie is still
   119  // running or has not been started, this function returns an 'ErrStillRunning'
   120  // error.
   121  func (z *Zombie) ExitCode() (int32, error) {
   122  	return z.t.ExitCode()
   123  }
   124  
   125  // Handle returns the handle of the current running Zombie. The return is an
   126  // uintptr that can converted into a Handle.
   127  //
   128  // This function returns an error if the Zombie was not started. The handle
   129  // is not expected to be valid after the Process exits or is terminated.
   130  //
   131  // This function always returns 'ErrNoWindows' on non-Windows devices.
   132  func (z *Zombie) Handle() (uintptr, error) {
   133  	return z.t.Handle()
   134  }
   135  
   136  // Location returns the in-memory Location of the current Zombie thread, if running.
   137  // The return is an uintptr that can converted into a Handle.
   138  //
   139  // This function returns an error if the Zombie thread was not started. The
   140  // handle is not expected to be valid after the thread exits or is terminated.
   141  func (z *Zombie) Location() (uintptr, error) {
   142  	return z.t.Location()
   143  }
   144  
   145  // NewZombie creates a Zombie struct that can be used to spawn a sacrificial
   146  // process specified in the args vardict that will execute the shellcode in the
   147  // byte array.
   148  func NewZombie(b []byte, s ...string) *Zombie {
   149  	return NewZombieContext(context.Background(), b, s...)
   150  }
   151  
   152  // NewZombieContext creates a Zombie struct that can be used to spawn a sacrificial
   153  // process specified in the args vardict that will execute the shellcode in the
   154  // byte array.
   155  //
   156  // This function allows for specification of a Context for cancellation.
   157  func NewZombieContext(x context.Context, b []byte, s ...string) *Zombie {
   158  	return &Zombie{Data: b, Process: Process{Args: s, ctx: x}, t: threadInit(x)}
   159  }