github.com/iDigitalFlame/xmt@v0.5.4/cmd/asm.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 (
    20  	"context"
    21  	"time"
    22  )
    23  
    24  // Assembly is a struct that can be used to contain and run shellcode on Windows devices.
    25  // This struct has many of the functionalities of the standard 'cmd.Program' function.
    26  //
    27  // The 'SetParent*' function will attempt to set the target that runs the shellcode.
    28  // If none are specified, the shellcode will be injected into the current process.
    29  //
    30  // This struct only works on Windows devices.
    31  // All calls on non-Windows devices will return 'ErrNoWindows'.
    32  //
    33  // TODO(dij): Add Linux shellcode execution support.
    34  type Assembly struct {
    35  	Data    []byte
    36  	t       thread
    37  	Timeout time.Duration
    38  }
    39  
    40  // Run will start the Assembly thread and wait until it completes. This function
    41  // will return the same errors as the 'Start' function if they occur or the
    42  // 'Wait' function if any errors occur during thread runtime.
    43  //
    44  // Always returns nil on non-Windows devices.
    45  func (a *Assembly) Run() error {
    46  	if err := a.Start(); err != nil {
    47  		return err
    48  	}
    49  	return a.Wait()
    50  }
    51  
    52  // Stop will attempt to terminate the currently running thread.
    53  //
    54  // Always returns nil on non-Windows devices.
    55  func (a *Assembly) Stop() error {
    56  	return a.t.Stop()
    57  }
    58  
    59  // Wait will block until the thread completes or is terminated by a call to
    60  // Stop.
    61  //
    62  // This function will return 'ErrNotStarted' if the thread has not been started.
    63  func (a *Assembly) Wait() error {
    64  	if !a.t.Running() {
    65  		if err := a.Start(); err != nil {
    66  			return err
    67  		}
    68  	}
    69  	return a.t.Wait()
    70  }
    71  
    72  // NewAsm creates a new Assembly thread instance that uses the supplied byte
    73  // array as the Data buffer. Similar to '&Assembly{Data: b}'.
    74  func NewAsm(b []byte) *Assembly {
    75  	return &Assembly{Data: b}
    76  }
    77  
    78  // Running returns true if the current thread is running, false otherwise.
    79  func (a *Assembly) Running() bool {
    80  	return a.t.Running()
    81  }
    82  
    83  // Release will attempt to release the resources for this Assembly thread,
    84  // including handles.
    85  //
    86  // After the first call to this function, all other function calls will fail
    87  // with errors. Repeated calls to this function return nil and are a NOP.
    88  func (a *Assembly) Release() error {
    89  	return a.t.Release()
    90  }
    91  
    92  // SetSuspended will delay the execution of this thread and will put the
    93  // thread in a suspended state until it is resumed using a Resume call.
    94  //
    95  // This function has no effect if the device is not running Windows.
    96  func (a *Assembly) SetSuspended(s bool) {
    97  	a.t.SetSuspended(s)
    98  }
    99  
   100  // ExitCode returns the Exit Code of the thread. If the thread is still running or
   101  // has not been started, this function returns an 'ErrNotCompleted' error.
   102  func (a *Assembly) ExitCode() (int32, error) {
   103  	return a.t.ExitCode()
   104  }
   105  
   106  // Handle returns the handle of the current running thread. The return is an uintptr
   107  // that can converted into a Handle.
   108  //
   109  // This function returns an error if the thread was not started. The handle is
   110  // not expected to be valid after the thread exits or is terminated.
   111  func (a *Assembly) Handle() (uintptr, error) {
   112  	return a.t.Handle()
   113  }
   114  
   115  // Location returns the in-memory Location of the current Assembly thread, if running.
   116  // The return is an uintptr that can converted into a Handle.
   117  //
   118  // This function returns an error if the Assembly thread was not started. The
   119  // handle is not expected to be valid after the thread exits or is terminated.
   120  func (a *Assembly) Location() (uintptr, error) {
   121  	return a.t.Location()
   122  }
   123  
   124  // NewAsmContext creates a new Code thread instance that uses the supplied byte
   125  // array as the Data buffer.
   126  //
   127  // This function accepts a context that can be used to control the cancellation
   128  // of the thread.
   129  func NewAsmContext(x context.Context, b []byte) *Assembly {
   130  	return &Assembly{Data: b, t: threadInit(x)}
   131  }