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 }