Files
2025-07-12 15:24:02 -05:00

130 lines
3.0 KiB
Go

package scmrexec
import (
"context"
"fmt"
"github.com/FalconOpsLLC/goexec/internal/util"
"github.com/FalconOpsLLC/goexec/pkg/goexec"
"github.com/oiweiwei/go-msrpc/msrpc/scmr/svcctl/v2"
"github.com/rs/zerolog"
_ "github.com/oiweiwei/go-msrpc/msrpc/erref/ntstatus"
_ "github.com/oiweiwei/go-msrpc/msrpc/erref/win32"
)
const (
MethodCreate = "Create"
)
type ScmrCreate struct {
Scmr
goexec.Cleaner
goexec.Executor
IO goexec.ExecutionIO
NoDelete bool
NoStart bool
ServiceName string
DisplayName string
}
func (m *ScmrCreate) ensure() {
if m.ServiceName == "" {
m.ServiceName = util.RandomString()
}
if m.DisplayName == "" {
m.DisplayName = m.ServiceName
}
}
func (m *ScmrCreate) Execute(ctx context.Context, in *goexec.ExecutionIO) (err error) {
m.ensure()
log := zerolog.Ctx(ctx).With().
Str("service", m.ServiceName).Logger()
svc := &service{name: m.ServiceName}
resp, err := m.ctl.CreateServiceW(ctx, &svcctl.CreateServiceWRequest{
ServiceManager: m.scm,
ServiceName: m.ServiceName,
DisplayName: m.DisplayName,
BinaryPathName: in.String(),
ServiceType: ServiceWin32OwnProcess,
StartType: ServiceDemandStart,
DesiredAccess: ServiceAllAccess, // TODO: Replace
})
if err != nil {
log.Error().Err(err).Msg("Create service request failed")
return fmt.Errorf("create service request: %w", err)
}
if resp.Return != 0 {
log.Error().Err(err).Msg("Failed to create service")
return fmt.Errorf("create service returned non-zero exit code: %02x", resp.Return)
}
if !m.NoDelete {
m.AddCleaners(func(ctxInner context.Context) error {
r, errInner := m.ctl.DeleteService(ctxInner, &svcctl.DeleteServiceRequest{
Service: svc.handle,
})
if errInner != nil {
return fmt.Errorf("delete service: %w", errInner)
}
if r.Return != 0 {
return fmt.Errorf("delete service returned non-zero exit code: %02x", r.Return)
}
log.Info().Msg("Deleted service")
return nil
})
}
m.AddCleaners(func(ctxInner context.Context) error {
r, errInner := m.ctl.CloseService(ctxInner, &svcctl.CloseServiceRequest{
ServiceObject: svc.handle,
})
if errInner != nil {
return fmt.Errorf("close service: %w", errInner)
}
if r.Return != 0 {
return fmt.Errorf("close service returned non-zero exit code: %02x", r.Return)
}
log.Info().Msg("Closed service handle")
return nil
})
log.Info().Msg("Created service")
svc.handle = resp.Service
if !m.NoStart {
err = m.startService(ctx, svc)
if err != nil {
log.Error().Err(err).Msg("Failed to start service")
return fmt.Errorf("start service: %w", err)
}
}
if svc.handle == nil {
if err = m.Reconnect(ctx); err != nil {
return err
}
svc, err = m.openService(ctx, svc.name)
if err != nil {
log.Error().Err(err).Msg("Failed to reopen service handle")
return fmt.Errorf("reopen service: %w", err)
}
}
return
}