Skip to content

Commit 7fb0828

Browse files
committed
macro->[]macros; excel-xlm->excel-macro
1 parent 8cd79de commit 7fb0828

2 files changed

Lines changed: 92 additions & 89 deletions

File tree

cmd/dcom.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ func dcomHtafileCmdInit() {
120120

121121
func dcomExcelMacroCmdInit() {
122122
dcomExcelMacroExecFlags := newFlagSet("Execution")
123-
dcomExcelMacroExecFlags.Flags.StringVarP(&dcomExcelMacro.Macro, "macro", "M", "", "XLM macro")
123+
dcomExcelMacroExecFlags.Flags.StringArrayVarP(&dcomExcelMacro.Macros, "macro", "M", nil, "XLM macro `code`")
124124
dcomExcelMacroExecFlags.Flags.StringVar(&dcomExcelMacro.MacroFile, "macro-file", "", "XLM macro `file`")
125125
registerExecutionFlags(dcomExcelMacroExecFlags.Flags)
126126
registerExecutionOutputFlags(dcomExcelMacroExecFlags.Flags)
@@ -135,6 +135,7 @@ func dcomExcelMacroCmdInit() {
135135

136136
// Constraints
137137
dcomExcelMacroCmd.MarkFlagsOneRequired("command", "exec", "macro", "macro-file")
138+
dcomExcelMacroCmd.MarkFlagsMutuallyExclusive("command", "exec", "macro", "macro-file")
138139
dcomExcelMacroCmd.MarkFlagsMutuallyExclusive("macro", "macro-file", "out")
139140
}
140141

@@ -283,10 +284,10 @@ var (
283284
}
284285

285286
dcomExcelMacroCmd = &cobra.Command{
286-
Use: "excel-xlm [target]",
287+
Use: "excel-macro [target]",
287288
Short: "Execute with the Excel.Application DCOM object by executing an Excel macro",
288289
Long: `Description:
289-
The excel-xlm method uses the exposed Excel.Application DCOM object to call ExecuteExcel4Macro, thus executing
290+
The excel-macro method uses the exposed Excel.Application DCOM object to call ExecuteExcel4Macro, thus executing
290291
XLM macros at will. This method requires that the remote host has Microsoft Excel installed.`,
291292
Args: args(argsRpcClient("host", ""), argsOutput("smb"),
292293
func(*cobra.Command, []string) error {
@@ -300,7 +301,7 @@ var (
300301
if err != nil {
301302
return fmt.Errorf("read macro file: %w", err)
302303
}
303-
dcomExcelMacro.Macro = string(b)
304+
dcomExcelMacro.Macros = strings.Split(string(b), "\n")
304305
}
305306
return nil
306307
},

pkg/goexec/dcom/excel.go

Lines changed: 87 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,118 +1,120 @@
11
package dcomexec
22

33
import (
4-
"context"
5-
"errors"
6-
"fmt"
7-
"strings"
8-
"syscall"
4+
"context"
5+
"errors"
6+
"fmt"
7+
"strings"
8+
"syscall"
99

10-
"github.com/FalconOpsLLC/goexec/internal/util"
11-
"github.com/FalconOpsLLC/goexec/pkg/goexec"
12-
"github.com/oiweiwei/go-msrpc/midl/uuid"
13-
"github.com/oiweiwei/go-msrpc/msrpc/erref/hresult"
14-
"github.com/rs/zerolog"
10+
"github.com/FalconOpsLLC/goexec/internal/util"
11+
"github.com/FalconOpsLLC/goexec/pkg/goexec"
12+
"github.com/oiweiwei/go-msrpc/midl/uuid"
13+
"github.com/oiweiwei/go-msrpc/msrpc/erref/hresult"
14+
"github.com/rs/zerolog"
1515
)
1616

1717
const (
18-
MethodExcelMacro = "Excel:ExecuteExcel4Macro"
19-
MethodExcelXLL = "Excel:RegisterXLL"
20-
ExcelApplicationUuid = "00020812-0000-0000-C000-000000000046"
18+
MethodExcelMacro = "Excel:ExecuteExcel4Macro"
19+
MethodExcelXLL = "Excel:RegisterXLL"
20+
ExcelApplicationUuid = "00020812-0000-0000-C000-000000000046"
2121
)
2222

2323
type DcomExcel struct {
24-
Dispatch
24+
Dispatch
2525
}
2626

2727
type DcomExcelMacro struct {
28-
DcomExcel
29-
Macro string
30-
MacroFile string
31-
NoTerminate bool
28+
DcomExcel
29+
Macros []string
30+
MacroFile string
31+
NoTerminate bool
3232
}
3333

3434
type DcomExcelXll struct {
35-
DcomExcel
36-
XllLocation string
37-
NoTerminate bool
35+
DcomExcel
36+
XllLocation string
37+
NoTerminate bool
3838
}
3939

4040
// Init will initialize the ShellBrowserWindow instance
4141
func (m *DcomExcel) Init(ctx context.Context) (err error) {
42-
if err = m.Dcom.Init(ctx); err == nil {
43-
return m.getDispatch(ctx, uuid.MustParse(ExcelApplicationUuid))
44-
}
45-
return
42+
if err = m.Dcom.Init(ctx); err == nil {
43+
return m.getDispatch(ctx, uuid.MustParse(ExcelApplicationUuid))
44+
}
45+
return
4646
}
4747

4848
// quit will terminate EXCEL.EXE via ExecuteExcel4Macro("QUIT()")
4949
func (m *DcomExcel) quit(ctx context.Context) (err error) {
50-
log := zerolog.Ctx(ctx)
51-
quit := "QUIT()"
52-
log.Info().
53-
Str("call", "ExecuteExcel4Macro").
54-
Str("macro", quit).
55-
Msg("terminating Excel process")
56-
qr, err := m.callComMethod(ctx, nil, "ExecuteExcel4Macro", stringToVariant(quit))
57-
_ = qr
58-
if err != nil {
59-
if errors.Is(err, syscall.ECONNRESET) {
60-
log.Info().Msg("Excel process terminated")
61-
return nil
62-
}
63-
log.Warn().Err(err).Msgf(`Call ExecuteExcel4Macro("%s") failed`, quit)
64-
}
65-
if qr.Return != 0 {
66-
err = hresult.FromCode(uint32(qr.Return))
67-
log.Warn().Err(err).Msgf(`Call ExecuteExcel4Macro("%s"): %d`, quit, qr.Return)
68-
}
50+
log := zerolog.Ctx(ctx)
51+
quit := "QUIT()"
52+
log.Info().
53+
Str("call", "ExecuteExcel4Macro").
54+
Str("macro", quit).
55+
Msg("terminating Excel process")
56+
qr, err := m.callComMethod(ctx, nil, "ExecuteExcel4Macro", stringToVariant(quit))
57+
_ = qr
58+
if err != nil {
59+
if errors.Is(err, syscall.ECONNRESET) {
60+
log.Info().Msg("Excel process terminated")
61+
return nil
62+
}
63+
log.Warn().Err(err).Msgf(`Call ExecuteExcel4Macro("%s") failed`, quit)
64+
}
65+
if qr.Return != 0 {
66+
err = hresult.FromCode(uint32(qr.Return))
67+
log.Warn().Err(err).Msgf(`Call ExecuteExcel4Macro("%s"): %d`, quit, qr.Return)
68+
}
6969

70-
return err
70+
return err
7171
}
7272

7373
func (m *DcomExcelMacro) Execute(ctx context.Context, execIO *goexec.ExecutionIO) (err error) {
74-
log := zerolog.Ctx(ctx)
75-
if m.Macro == "" {
76-
m.Macro = fmt.Sprintf(`EXEC("%s")`, strings.ReplaceAll(execIO.String(), `"`, `""`))
77-
}
78-
if !m.NoTerminate { // Terminate EXCEL.EXE via ExecuteExcel4Macro("QUIT()")
79-
defer func() {
80-
_ = m.quit(ctx)
81-
}()
82-
}
83-
// Call ExecuteExcel4Macro to execute macro
84-
log.Info().
85-
Str("call", "ExecuteExcel4Macro").
86-
Str("macro", util.Truncate(m.Macro, 100)).
87-
Msg("executing Excel macro")
88-
ir, err := m.callComMethod(ctx, nil, "ExecuteExcel4Macro", stringToVariant(m.Macro))
89-
if err != nil {
90-
return err
91-
}
92-
if ir.Return != 0 {
93-
return hresult.FromCode(uint32(ir.Return))
94-
}
95-
log.Info().Msg("ExecuteExcel4Macro call successful")
74+
log := zerolog.Ctx(ctx)
75+
if m.Macros == nil || len(m.Macros) == 0 {
76+
m.Macros = []string{fmt.Sprintf(`EXEC("%s")`, strings.ReplaceAll(execIO.String(), `"`, `""`))}
77+
}
78+
if !m.NoTerminate { // Terminate EXCEL.EXE via ExecuteExcel4Macro("QUIT()")
79+
defer func() {
80+
_ = m.quit(ctx)
81+
}()
82+
}
83+
for _, macro := range m.Macros {
84+
// Call ExecuteExcel4Macro to execute macro
85+
log.Info().
86+
Str("call", "ExecuteExcel4Macro").
87+
Str("macro", util.Truncate(macro, 100)).
88+
Msg("executing Excel macro")
89+
ir, err := m.callComMethod(ctx, nil, "ExecuteExcel4Macro", stringToVariant(macro))
90+
if err != nil {
91+
return err
92+
}
93+
if ir.Return != 0 {
94+
return hresult.FromCode(uint32(ir.Return))
95+
}
96+
log.Info().Msg("ExecuteExcel4Macro call successful")
97+
}
9698

97-
return
99+
return
98100
}
99101

100102
func (m *DcomExcelXll) Call(ctx context.Context) (err error) {
101-
log := zerolog.Ctx(ctx)
102-
if !m.NoTerminate {
103-
defer func() {
104-
_ = m.quit(ctx)
105-
}()
106-
}
107-
qr, err := m.callComMethod(ctx, nil, "Application.RegisterXLL", stringToVariant(m.XllLocation))
108-
if err != nil {
109-
return fmt.Errorf("call RegisterXLL: %w", err)
110-
}
111-
log.Info().Msg("RegisterXLL call successful")
112-
if stat, ok := qr.VarResult.VarUnion.GetValue().(bool); ok && stat {
113-
log.Info().Bool("res", stat).Int32("return", qr.Return).Msg("XLL registered successfully")
114-
} else {
115-
log.Warn().Bool("res", stat).Int32("return", qr.Return).Msg("Execution may have failed")
116-
}
117-
return
103+
log := zerolog.Ctx(ctx)
104+
if !m.NoTerminate {
105+
defer func() {
106+
_ = m.quit(ctx)
107+
}()
108+
}
109+
qr, err := m.callComMethod(ctx, nil, "Application.RegisterXLL", stringToVariant(m.XllLocation))
110+
if err != nil {
111+
return fmt.Errorf("call RegisterXLL: %w", err)
112+
}
113+
log.Info().Msg("RegisterXLL call successful")
114+
if stat, ok := qr.VarResult.VarUnion.GetValue().(bool); ok && stat {
115+
log.Info().Bool("res", stat).Int32("return", qr.Return).Msg("XLL registered successfully")
116+
} else {
117+
log.Warn().Bool("res", stat).Int32("return", qr.Return).Msg("Execution may have failed")
118+
}
119+
return
118120
}

0 commit comments

Comments
 (0)