├── .github └── workflows │ └── goreleaser.yml ├── .gitignore ├── .goreleaser.yml ├── LICENSE.md ├── Makefile ├── README.md ├── cmd └── EDRHunt │ └── main.go ├── garble-literals.sh ├── go.mod ├── go.sum └── pkg ├── edrRecon ├── collect.go ├── directory.go ├── drivers_windows.go ├── edrRecon_test.go ├── edrdata.go ├── filechecker_windows.go ├── privilege.go ├── process_windows.go ├── registry.go ├── services_windows.go └── wmi_windows.go ├── resources ├── edrRecon.go ├── scan_edr.go └── systemdata.go ├── scanners ├── scan_bitdefender.go ├── scan_carbonblack.go ├── scan_checkpoint.go ├── scan_crowdstrike.go ├── scan_cybereason.go ├── scan_cylance.go ├── scan_cynet.go ├── scan_deepinstinct.go ├── scan_elastic.go ├── scan_eset.go ├── scan_fireeye.go ├── scan_fortinet.go ├── scan_harfanglab.go ├── scan_kaspersky.go ├── scan_limacharlie.go ├── scan_malwarebytes.go ├── scan_mcafee.go ├── scan_qualys.go ├── scan_sentinelone.go ├── scan_sophos.go ├── scan_symantec.go ├── scan_trendmicro.go ├── scan_win_defender.go └── scanner.go └── util ├── util.go └── wmi └── wmi.go /.github/workflows/goreleaser.yml: -------------------------------------------------------------------------------- 1 | name: goreleaser 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | goreleaser: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - 16 | name: Checkout 17 | uses: actions/checkout@v2 18 | with: 19 | fetch-depth: 0 20 | - 21 | name: Set up Go 22 | uses: actions/setup-go@v2 23 | with: 24 | go-version: 1.19 25 | - 26 | name: Install garble 27 | run: | 28 | go install mvdan.cc/garble@master 29 | sudo cp garble-literals.sh /usr/bin/garble-literals 30 | sudo chmod +x /usr/bin/garble-literals 31 | - 32 | name: Run GoReleaser 33 | uses: goreleaser/goreleaser-action@v2 34 | with: 35 | # either 'goreleaser' (default) or 'goreleaser-pro' 36 | distribution: goreleaser 37 | version: latest 38 | args: release --rm-dist 39 | env: 40 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 41 | # Your GoReleaser Pro key, if you are using the 'goreleaser-pro' distribution 42 | # GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | EDRHunt.exe 3 | .vscode 4 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | builds: 2 | - binary: EDRHunt 3 | goos: 4 | - windows 5 | goarch: 6 | - amd64 7 | ldflags: 8 | - "" 9 | gobinary: "garble-literals" 10 | main: cmd/EDRHunt/main.go 11 | archives: 12 | - format: zip 13 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2021 FourCore Labs 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: build 2 | 3 | build: 4 | go build -ldflags="-w -s" -o EDRHunt.exe github.com/fourcorelabs/edrhunt/cmd/EDRHunt 5 | garble-build: 6 | garble -literals build -ldflags="-w -s" -o EDRHunt.exe github.com/fourcorelabs/edrhunt/cmd/EDRHunt 7 | local: 8 | go build -ldflags="-w -s" -o EDRHunt.exe github.com/fourcorelabs/edrhunt/cmd/EDRHunt 9 | run: 10 | go run -ldflags="-w -s" github.com/fourcorelabs/edrhunt/cmd/EDRHunt all 11 | drivers: 12 | go run -ldflags="-w -s" github.com/fourcorelabs/edrhunt/cmd/EDRHunt -d 13 | avwmi: 14 | go run -ldflags="-w -s" github.com/fourcorelabs/edrhunt/cmd/EDRHunt -w 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EDRHunt 2 | 3 | [![goreleaser](https://github.com/fourcorelabs/edrhunt/actions/workflows/goreleaser.yml/badge.svg)](https://github.com/fourcorelabs/edrhunt/actions/workflows/goreleaser.yml) 4 | 5 | EDRHunt scans Windows services, drivers, processes, registry, wmi for installed EDRs (Endpoint Detection And Response). Read more about EDRHunt [here](https://www.fourcore.vision/blogs/red-team-adventure-windows-endpoints-edr-edrhunt). 6 | 7 | [![asciicast](https://asciinema.org/a/P8i99w9mI497qUPTNbdwYWcwQ.svg)](https://asciinema.org/a/P8i99w9mI497qUPTNbdwYWcwQ) 8 | 9 | ## Install 10 | 11 | - Binary 12 | - Download the latest release from the release section. Releases are built for windows/amd64. 13 | 14 | - Go 15 | - Requires Go to be installed on system. Tested on Go1.17+. 16 | - `go install github.com/fourcorelabs/edrhunt/cmd/EDRHunt@master` 17 | 18 | ## Usage 19 | 20 | - Find installed EDRs 21 | 22 | ``` 23 | $ .\EDRHunt.exe scan 24 | [EDR] 25 | Detected EDR: Windows Defender 26 | Detected EDR: Kaspersky Security 27 | ``` 28 | 29 | - Scan Everything 30 | ``` 31 | $ .\EDRHunt.exe all 32 | Running in user mode, escalate to admin for more details. 33 | Scanning processes, services, drivers, wmi, and registry... 34 | [PROCESSES] 35 | 36 | Suspicious Process Name: MsMpEng.exe 37 | Description: MsMpEng.exe 38 | Caption: MsMpEng.exe 39 | Binary: 40 | ProcessID: 6764 41 | Parent Process: 1148 42 | Process CmdLine : 43 | File Metadata: 44 | Matched Keyword: [msmpeng] 45 | 46 | 47 | Suspicious Process Name: NisSrv.exe 48 | Description: NisSrv.exe 49 | Caption: NisSrv.exe 50 | Binary: 51 | ProcessID: 9840 52 | Parent Process: 1148 53 | Process CmdLine : 54 | File Metadata: 55 | Matched Keyword: [nissrv] 56 | ... 57 | ``` 58 | 59 | - Find drivers matching EDR keywords 60 | 61 | ``` 62 | __________ ____ __ ____ ___ ________ 63 | / ____/ __ \/ __ \ / / / / / / / | / /_ __/ 64 | / __/ / / / / /_/ / / /_/ / / / / |/ / / / 65 | / /___/ /_/ / _, _/ / __ / /_/ / /| / / / 66 | /_____/_____/_/ |_| /_/ /_/\____/_/ |_/ /_/ 67 | 68 | FourCore Labs (https://fourcore.vision) | Version: 1.1 69 | 70 | Running in user mode, escalate to admin for more details. 71 | [DRIVERS] 72 | Suspicious Driver Module: WdFilter.sys 73 | Driver FilePath: c:\windows\system32\drivers\wd\wdfilter.sys 74 | Driver File Metadata: 75 | ProductName: Microsoft® Windows® Operating System 76 | OriginalFileName: WdFilter.sys 77 | InternalFileName: WdFilter 78 | Company Name: Microsoft Corporation 79 | FileDescription: Microsoft antimalware file system filter driver 80 | ProductVersion: 4.18.2109.6 81 | Comments: 82 | LegalCopyright: © Microsoft Corporation. All rights reserved. 83 | LegalTrademarks: 84 | Matched Keyword: [antimalware malware] 85 | 86 | Suspicious Driver Module: hvsifltr.sys 87 | Driver FilePath: c:\windows\system32\drivers\hvsifltr.sys 88 | Driver File Metadata: 89 | ProductName: Microsoft® Windows® Operating System 90 | OriginalFileName: hvsifltr.sys.mui 91 | InternalFileName: hvsifltr.sys 92 | Company Name: Microsoft Corporation 93 | FileDescription: Microsoft Defender Application Guard Filter Driver 94 | ProductVersion: 10.0.19041.1 95 | Comments: 96 | LegalCopyright: © Microsoft Corporation. All rights reserved. 97 | LegalTrademarks: 98 | Matched Keyword: [defender] 99 | 100 | Suspicious Driver Module: WdNisDrv.sys 101 | Driver FilePath: c:\windows\system32\drivers\wd\wdnisdrv.sys 102 | Driver File Metadata: 103 | ProductName: Microsoft® Windows® Operating System 104 | OriginalFileName: wdnisdrv.sys 105 | InternalFileName: wdnisdrv.sys 106 | Company Name: Microsoft Corporation 107 | FileDescription: Windows Defender Network Stream Filter 108 | ProductVersion: 4.18.2109.6 109 | Comments: 110 | LegalCopyright: © Microsoft Corporation. All rights reserved. 111 | LegalTrademarks: 112 | Matched Keyword: [defender] 113 | ... 114 | ``` 115 | 116 | - Find services matching EDR keywords 117 | 118 | ``` 119 | $ .\EDRHunt.exe -s 120 | ``` 121 | 122 | - Find drivers matching EDR keywords 123 | 124 | ``` 125 | $ .\EDRHunt.exe -d 126 | ``` 127 | 128 | - Find registry keys matching EDR keywords 129 | 130 | ``` 131 | $ .\EDRHunt.exe -r 132 | ``` 133 | 134 | 135 | - Find WMI Repository keys matching EDR keywords 136 | 137 | ``` 138 | $ .\EDRHunt.exe -w 139 | ``` 140 | 141 | ## Detections 142 | 143 | EDR Detections Currently Available 144 | 145 | - Windows Defender 146 | - Kaspersky Security 147 | - Symantec Security 148 | - Crowdstrike Security 149 | - Mcafee Security 150 | - Cylance Security 151 | - Carbon Black 152 | - SentinelOne 153 | - FireEye 154 | - Elastic EDR 155 | - Qualys EDR 156 | - Trend Micro EDR 157 | - ESET EDR 158 | - Cybereason EDR 159 | - BitDefender EDR 160 | - Checkpoint EDR 161 | - Cynet EDR 162 | - DeepInstinct EDR 163 | - Sophos EDR 164 | - Fortinet EDR 165 | - MalwareBytes EDR 166 | - LimaCharlie Agent 167 | 168 | More to be added soon. 169 | 170 | ## Community 171 | 172 | Would appreciate if you ran EDRHunt on your own deployments and test the detections! Thanks. 173 | -------------------------------------------------------------------------------- /cmd/EDRHunt/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/fourcorelabs/edrhunt/pkg/edrRecon" 9 | "github.com/fourcorelabs/edrhunt/pkg/resources" 10 | "github.com/fourcorelabs/edrhunt/pkg/scanners" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | var ( 15 | drivers bool 16 | processes bool 17 | services bool 18 | registry bool 19 | avwmi bool 20 | all bool 21 | versionStr string = "1.4.6" 22 | versionCheck bool 23 | ) 24 | 25 | func printBanner() { 26 | fmt.Printf(` 27 | __________ ____ __ ____ ___ ________ 28 | / ____/ __ \/ __ \ / / / / / / / | / /_ __/ 29 | / __/ / / / / /_/ / / /_/ / / / / |/ / / / 30 | / /___/ /_/ / _, _/ / __ / /_/ / /| / / / 31 | /_____/_____/_/ |_| /_/ /_/\____/_/ |_/ /_/ 32 | 33 | FourCore Labs (https://fourcore.io) | Version: %v 34 | 35 | `, versionStr) 36 | } 37 | 38 | func edrCommand(cmd *cobra.Command, args []string) { 39 | if edrRecon.CheckIfAdmin() { 40 | fmt.Println("Running in adminsitrator mode.") 41 | } else { 42 | fmt.Println("Running in user mode, escalate to admin for more details.") 43 | } 44 | 45 | if all { 46 | processes = true 47 | drivers = true 48 | services = true 49 | registry = false 50 | avwmi = true 51 | fmt.Println("Scanning processes, services, drivers, wmi, and registry...") 52 | } 53 | 54 | if processes { 55 | fmt.Println("[PROCESSES]") 56 | summary, _ := edrRecon.CheckProcesses() 57 | printProcess(summary) 58 | fmt.Println() 59 | } 60 | if drivers { 61 | fmt.Println("[DRIVERS]") 62 | summary, _ := edrRecon.CheckDrivers() 63 | printDrivers(summary) 64 | fmt.Println() 65 | } 66 | if services { 67 | fmt.Println("[SERVICES]") 68 | summary, _ := edrRecon.CheckServices() 69 | printServices(summary) 70 | fmt.Println() 71 | } 72 | if avwmi { 73 | fmt.Println("[WMI-REPO]") 74 | summary, _ := edrRecon.CheckAVWmiRepo() 75 | printAVWmi(summary) 76 | fmt.Println() 77 | } 78 | if registry { 79 | fmt.Println("[REGISTRY]") 80 | summary, _ := edrRecon.CheckRegistry(context.Background()) 81 | printRegistry(summary) 82 | fmt.Println() 83 | } 84 | } 85 | 86 | func versionCommand(cmd *cobra.Command, args []string) { 87 | fmt.Printf("version: %s\n", versionStr) 88 | } 89 | 90 | func scanEDRCommand(cmd *cobra.Command, args []string) { 91 | fmt.Println("[EDR]") 92 | systemData, _ := edrRecon.GetSystemData(context.Background()) 93 | 94 | for _, scanner := range scanners.Scanners { 95 | _, ok := scanner.Detect(systemData) 96 | if ok { 97 | fmt.Printf("Detected EDR: %s\n", scanner.Name()) 98 | } 99 | } 100 | } 101 | 102 | func allCommand(cmd *cobra.Command, args []string) { 103 | all = true 104 | edrCommand(cmd, args) 105 | scanEDRCommand(cmd, args) 106 | } 107 | 108 | var rootCmd = &cobra.Command{ 109 | Use: "EDRHunt", 110 | Short: "scans EDR/AV", 111 | Long: `EDRHunt scans and finds the installed EDR/AV by scanning services, processes, registry, wmi, and drivers.`, 112 | Run: edrCommand, 113 | } 114 | 115 | var versionCmd = &cobra.Command{ 116 | Use: "version", 117 | Short: "version", 118 | Long: `edrRecon version`, 119 | Run: versionCommand, 120 | } 121 | 122 | var scanCmd = &cobra.Command{ 123 | Use: "scan", 124 | Short: "scan installed edrs", 125 | Long: `scan edrs`, 126 | Run: scanEDRCommand, 127 | } 128 | 129 | var allCmd = &cobra.Command{ 130 | Use: "all", 131 | Short: "scan installed edrs", 132 | Long: `scan edrs and show system data`, 133 | Run: allCommand, 134 | } 135 | 136 | func printAVWmi(summary []resources.AVWmiMetaData) { 137 | for _, antivirus := range summary { 138 | fmt.Printf("Suspicious Product Name: %s\n", antivirus.ProductName) 139 | fmt.Printf("Suspicious Product GUID: %s\n", antivirus.ProductGUID) 140 | fmt.Printf("Path to Suspicious Product Exe: %s\n", antivirus.PathToProductExe) 141 | fmt.Printf("Suspicious Product Exe Metadata: \t%s\n", edrRecon.FileMetaDataParser(antivirus.ProductExeMetaData)) 142 | fmt.Printf("Path to Suspicious Reporting Exe: %s\n", antivirus.PathToReportingExe) 143 | fmt.Printf("Suspicious Reporting Exe Metadata: \t%s\n", edrRecon.FileMetaDataParser(antivirus.ReportingExeMetaData)) 144 | fmt.Printf("Suspicious Product State: %d\n", antivirus.ProductState) 145 | fmt.Printf("Matched Keyword: %s\n", antivirus.ScanMatch) 146 | fmt.Println() 147 | } 148 | } 149 | 150 | func printProcess(summary []resources.ProcessMetaData) { 151 | for _, process := range summary { 152 | fmt.Printf("Suspicious Process Name: %s\n", process.ProcessName) 153 | fmt.Printf("Description: %s\n", process.ProcessDescription) 154 | fmt.Printf("Caption: %s\n", process.ProcessCaption) 155 | fmt.Printf("Binary: %s\n", process.ProcessPath) 156 | fmt.Printf("ProcessID: %s\n", process.ProcessPID) 157 | fmt.Printf("Parent Process: %s\n", process.ProcessParentPID) 158 | fmt.Printf("Process CmdLine: %s\n", process.ProcessCmdLine) 159 | fmt.Printf("File Metadata: \t%s\n", edrRecon.FileMetaDataParser(process.ProcessExeMetaData)) 160 | fmt.Printf("Matched Keyword: %s\n", process.ScanMatch) 161 | fmt.Println() 162 | } 163 | } 164 | 165 | func printServices(summary []resources.ServiceMetaData) { 166 | for _, service := range summary { 167 | fmt.Printf("Suspicious Service Name: %s\n", service.ServiceName) 168 | fmt.Printf("Display Name: %s\n", service.ServiceDisplayName) 169 | fmt.Printf("Caption: %s\n", service.ServiceCaption) 170 | fmt.Printf("CommandLine: %s\n", service.ServicePathName) 171 | fmt.Printf("Status: %s\n", service.ServiceState) 172 | fmt.Printf("ProcessID: %s\n", service.ServiceProcessId) 173 | fmt.Printf("File Metadata: \t%s\n", edrRecon.FileMetaDataParser(service.ServiceExeMetaData)) 174 | fmt.Printf("Matched Keyword: %s\n", service.ScanMatch) 175 | fmt.Println() 176 | } 177 | } 178 | 179 | func printRegistry(summary resources.RegistryMetaData) { 180 | fmt.Println("Scanning registry: ") 181 | for _, match := range summary.ScanMatch { 182 | fmt.Printf("\t%s\n", match) 183 | } 184 | fmt.Println() 185 | } 186 | 187 | func printDrivers(summary []resources.DriverMetaData) { 188 | for _, driver := range summary { 189 | fmt.Printf("Suspicious Driver Module: %s\n", driver.DriverBaseName) 190 | fmt.Printf("Driver FilePath: %s\n", driver.DriverFilePath) 191 | fmt.Printf("Driver File Metadata: \t%s\n", edrRecon.FileMetaDataParser(driver.DriverSysMetaData)) 192 | fmt.Printf("Matched Keyword: %s\n", driver.ScanMatch) 193 | fmt.Println() 194 | } 195 | } 196 | 197 | func Execute() { 198 | if err := rootCmd.Execute(); err != nil { 199 | fmt.Println(err) 200 | os.Exit(1) 201 | } 202 | } 203 | 204 | func init() { 205 | rootCmd.PersistentFlags().BoolVarP(&drivers, "drivers", "d", drivers, "Scan installed drivers") 206 | rootCmd.PersistentFlags().BoolVarP(&processes, "processes", "p", processes, "Scan installed processes") 207 | rootCmd.PersistentFlags().BoolVarP(&services, "services", "s", services, "Scan installed services") 208 | rootCmd.PersistentFlags().BoolVarP(®istry, "registry", "r", registry, "Scan installed registry") 209 | rootCmd.PersistentFlags().BoolVarP(&avwmi, "avwmi", "w", avwmi, "Scan installed AntiVirus Providers") 210 | rootCmd.PersistentFlags().BoolVarP(&versionCheck, "version", "v", versionCheck, "Output version information and exit") 211 | 212 | rootCmd.AddCommand(versionCmd) 213 | rootCmd.AddCommand(scanCmd) 214 | rootCmd.AddCommand(allCmd) 215 | } 216 | 217 | func main() { 218 | fmt.Print("\033[H\033[2J") 219 | printBanner() 220 | Execute() 221 | } 222 | -------------------------------------------------------------------------------- /garble-literals.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | garble -literals $@ 3 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/fourcorelabs/edrhunt 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/bi-zone/go-fileversion v1.0.0 7 | github.com/hashicorp/go-multierror v1.1.1 8 | github.com/spf13/cobra v1.2.1 9 | github.com/yusufpapurcu/wmi v1.2.2 10 | ) 11 | 12 | require ( 13 | github.com/go-ole/go-ole v1.2.6 // indirect 14 | github.com/hashicorp/errwrap v1.1.0 // indirect 15 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 16 | github.com/spf13/pflag v1.0.5 // indirect 17 | golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect 18 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 14 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 15 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 16 | cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= 17 | cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= 18 | cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= 19 | cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= 20 | cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= 21 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 22 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 23 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 24 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 25 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 26 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 27 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 28 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 29 | cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= 30 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 31 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 32 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 33 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 34 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 35 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 36 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 37 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 38 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 39 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 40 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 41 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 42 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= 43 | github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 44 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= 45 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 46 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 47 | github.com/bi-zone/go-fileversion v1.0.0 h1:N/sorBKYfWDjT5ySlUOxSJvG3g9XiaBKxXgHGfH5Wf8= 48 | github.com/bi-zone/go-fileversion v1.0.0/go.mod h1:evMpx4TA/iTAtufWYK271/Mbr5JAL24vlu1WNjVef6s= 49 | github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= 50 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 51 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 52 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 53 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 54 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 55 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 56 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 57 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 58 | github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 59 | github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 60 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 61 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 62 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 63 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 64 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 65 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 66 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 67 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 68 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 69 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 70 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 71 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 72 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 73 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 74 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 75 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 76 | github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= 77 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 78 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 79 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 80 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 81 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 82 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 83 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 84 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 85 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 86 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 87 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 88 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 89 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 90 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 91 | github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= 92 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 93 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 94 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 95 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 96 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 97 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 98 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 99 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 100 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 101 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 102 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 103 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 104 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 105 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 106 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 107 | github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= 108 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 109 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 110 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 111 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 112 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 113 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 114 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 115 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 116 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 117 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 118 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 119 | github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 120 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 121 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 122 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 123 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 124 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 125 | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 126 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 127 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 128 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 129 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 130 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 131 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 132 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 133 | github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 134 | github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 135 | github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 136 | github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 137 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 138 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 139 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 140 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 141 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 142 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= 143 | github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= 144 | github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= 145 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 146 | github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= 147 | github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 148 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 149 | github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 150 | github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= 151 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 152 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= 153 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= 154 | github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= 155 | github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= 156 | github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= 157 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 158 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 159 | github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= 160 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 161 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 162 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 163 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= 164 | github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= 165 | github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= 166 | github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= 167 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 168 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 169 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 170 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 171 | github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 172 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 173 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 174 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 175 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 176 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 177 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 178 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 179 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 180 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 181 | github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= 182 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 183 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 184 | github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 185 | github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= 186 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 187 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 188 | github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= 189 | github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= 190 | github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 191 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 192 | github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 193 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 194 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 195 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 196 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 197 | github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 198 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 199 | github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= 200 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 201 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 202 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 203 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 204 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 205 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 206 | github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= 207 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= 208 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 209 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 210 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 211 | github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= 212 | github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 213 | github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= 214 | github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= 215 | github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 216 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 217 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 218 | github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= 219 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 220 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 221 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 222 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 223 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 224 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 225 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 226 | github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= 227 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 228 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 229 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 230 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 231 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 232 | github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= 233 | github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= 234 | go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= 235 | go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= 236 | go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= 237 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 238 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 239 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 240 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 241 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 242 | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 243 | go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= 244 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 245 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 246 | go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= 247 | golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 248 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 249 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 250 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 251 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 252 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 253 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 254 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 255 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 256 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 257 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 258 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 259 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 260 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 261 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 262 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 263 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 264 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 265 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 266 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 267 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 268 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 269 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 270 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 271 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 272 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 273 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 274 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 275 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 276 | golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 277 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 278 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 279 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 280 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 281 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 282 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 283 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 284 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 285 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 286 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 287 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 288 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 289 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 290 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 291 | golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 292 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 293 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 294 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 295 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 296 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 297 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 298 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 299 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 300 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 301 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 302 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 303 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 304 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 305 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 306 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 307 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 308 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 309 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 310 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 311 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 312 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 313 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 314 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 315 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 316 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 317 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 318 | golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 319 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 320 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 321 | golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 322 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 323 | golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= 324 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 325 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 326 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 327 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 328 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 329 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 330 | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 331 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 332 | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 333 | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 334 | golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 335 | golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 336 | golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 337 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 338 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 339 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 340 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 341 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 342 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 343 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 344 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 345 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 346 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 347 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 348 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 349 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 350 | golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 351 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 352 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 353 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 354 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 355 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 356 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 357 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 358 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 359 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 360 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 361 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 362 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 363 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 364 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 365 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 366 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 367 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 368 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 369 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 370 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 371 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 372 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 373 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 374 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 375 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 376 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 377 | golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 378 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 379 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 380 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 381 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 382 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 383 | golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 384 | golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 385 | golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 386 | golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 387 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 388 | golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 389 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 390 | golang.org/x/sys v0.0.0-20211013075003-97ac67df715c h1:taxlMj0D/1sOAuv/CbSD+MMDof2vbyPTqz5FNYKpXt8= 391 | golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 392 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 393 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 394 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 395 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 396 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 397 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 398 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 399 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 400 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 401 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 402 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 403 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 404 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 405 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 406 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 407 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 408 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 409 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 410 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 411 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 412 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 413 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 414 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 415 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 416 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 417 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 418 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 419 | golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 420 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 421 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 422 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 423 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 424 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 425 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 426 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 427 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 428 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 429 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 430 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 431 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 432 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 433 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 434 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 435 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 436 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 437 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 438 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 439 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 440 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 441 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 442 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 443 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 444 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 445 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 446 | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 447 | golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 448 | golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 449 | golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 450 | golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 451 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 452 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 453 | golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 454 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 455 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 456 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 457 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 458 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 459 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 460 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 461 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 462 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 463 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 464 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 465 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 466 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 467 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 468 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 469 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 470 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 471 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 472 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 473 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 474 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 475 | google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= 476 | google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 477 | google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= 478 | google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= 479 | google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= 480 | google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= 481 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 482 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 483 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 484 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 485 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 486 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 487 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 488 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 489 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 490 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 491 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 492 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 493 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 494 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 495 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 496 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 497 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 498 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 499 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 500 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 501 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 502 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 503 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 504 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 505 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 506 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 507 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 508 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 509 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 510 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 511 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 512 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 513 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 514 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 515 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 516 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 517 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 518 | google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 519 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 520 | google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 521 | google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 522 | google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 523 | google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 524 | google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 525 | google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 526 | google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 527 | google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= 528 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 529 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 530 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 531 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 532 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 533 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 534 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 535 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 536 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 537 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 538 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 539 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 540 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 541 | google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 542 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= 543 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 544 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 545 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 546 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 547 | google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 548 | google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 549 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 550 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 551 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 552 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 553 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 554 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 555 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 556 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 557 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 558 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 559 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 560 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 561 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 562 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 563 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 564 | gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 565 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 566 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 567 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 568 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 569 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 570 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 571 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 572 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 573 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 574 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 575 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 576 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 577 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 578 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 579 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 580 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 581 | -------------------------------------------------------------------------------- /pkg/edrRecon/collect.go: -------------------------------------------------------------------------------- 1 | package edrRecon 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/fourcorelabs/edrhunt/pkg/resources" 8 | ) 9 | 10 | // GetSystemData collects the parsed list of processes, services, drivers, wmi and registry keys to be used for EDR heuristics. 11 | func GetSystemData(ctx context.Context) (resources.SystemData, error) { 12 | var err error 13 | var systemData resources.SystemData 14 | 15 | systemData.Processes, err = CheckProcesses() 16 | if err != nil { 17 | return systemData, fmt.Errorf("failed to check processes: %w", err) 18 | } 19 | 20 | systemData.Services, err = CheckServices() 21 | if err != nil { 22 | return systemData, fmt.Errorf("failed to check services: %w", err) 23 | } 24 | 25 | systemData.Registry, err = CheckRegistry(ctx) 26 | if err != nil { 27 | return systemData, fmt.Errorf("failed to check registry: %w", err) 28 | } 29 | 30 | systemData.Drivers, err = CheckDrivers() 31 | if err != nil { 32 | return systemData, fmt.Errorf("failed to check drivers: %w", err) 33 | } 34 | 35 | systemData.AVProviders, err = CheckAVWmiRepo() 36 | if err != nil { 37 | return systemData, fmt.Errorf("failed to check wmi repo: %w", err) 38 | } 39 | return systemData, nil 40 | } 41 | -------------------------------------------------------------------------------- /pkg/edrRecon/directory.go: -------------------------------------------------------------------------------- 1 | package edrRecon 2 | 3 | import "fmt" 4 | 5 | func CheckDirectory() (string, error) { 6 | return "", fmt.Errorf("directory scan is not implemented: unnecessarily slow, genrates false positives, also, monitoring command line so, reduntant, again") 7 | } 8 | -------------------------------------------------------------------------------- /pkg/edrRecon/drivers_windows.go: -------------------------------------------------------------------------------- 1 | package edrRecon 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strings" 7 | "syscall" 8 | "unicode/utf16" 9 | "unsafe" 10 | 11 | "github.com/fourcorelabs/edrhunt/pkg/resources" 12 | 13 | "github.com/hashicorp/go-multierror" 14 | ) 15 | 16 | var ( 17 | // Library 18 | libpsapi uintptr 19 | // Functions 20 | enumDeviceDrivers uintptr 21 | getDeviceDriverBaseName uintptr 22 | getDeviceDriverFileName uintptr 23 | numberOfDrivers uint 24 | driverAddrs []uintptr 25 | ) 26 | 27 | type DWORD uint32 28 | type LPVOID uintptr 29 | type LPVOIDARR []byte 30 | type LPWSTR *uint16 31 | 32 | type UTF16Slice struct { 33 | Data unsafe.Pointer 34 | Len int 35 | Cap int 36 | } 37 | 38 | func init() { 39 | // Library 40 | libpsapi = doLoadLibrary("psapi.dll") 41 | // Functions 42 | enumDeviceDrivers = doGetProcAddress(libpsapi, "EnumDeviceDrivers") 43 | getDeviceDriverBaseName = doGetProcAddress(libpsapi, "GetDeviceDriverBaseNameW") 44 | getDeviceDriverFileName = doGetProcAddress(libpsapi, "GetDeviceDriverFileNameW") 45 | } 46 | 47 | func doLoadLibrary(name string) uintptr { 48 | lib, _ := syscall.LoadLibrary(name) 49 | return uintptr(lib) 50 | } 51 | 52 | func doGetProcAddress(lib uintptr, name string) uintptr { 53 | addr, _ := syscall.GetProcAddress(syscall.Handle(lib), name) 54 | return uintptr(addr) 55 | } 56 | 57 | func syscall3(trap, nargs, a1, a2, a3 uintptr) uintptr { 58 | ret, _, _ := syscall.Syscall(trap, nargs, a1, a2, a3) 59 | return ret 60 | } 61 | 62 | // func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) uintptr { 63 | // ret, _, _ := syscall.Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6) 64 | // return ret 65 | // } 66 | 67 | // dodgy function: may cause BOF 68 | func UTF16PtrToString(p *uint16) string { 69 | defer func() { 70 | if r := recover(); r != nil { 71 | return 72 | } 73 | }() 74 | 75 | if p == nil { 76 | return "" 77 | } 78 | if *p == 0 { 79 | return "" 80 | } 81 | 82 | // Find NUL terminator. 83 | n := 0 84 | for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; n++ { 85 | ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p)) 86 | } 87 | 88 | var s []uint16 89 | h := (*UTF16Slice)(unsafe.Pointer(&s)) 90 | h.Data = unsafe.Pointer(p) 91 | h.Len = n 92 | h.Cap = n 93 | 94 | return string(utf16.Decode(s)) 95 | } 96 | 97 | func EnumDeviceDrivers(lpImageBase []uintptr, cb DWORD, lpcbNeeded *uint32) bool { 98 | ret1 := syscall3(enumDeviceDrivers, 3, 99 | uintptr(unsafe.Pointer(&lpImageBase[0])), 100 | uintptr(cb), 101 | uintptr(unsafe.Pointer(lpcbNeeded))) 102 | return ret1 != 0 103 | } 104 | 105 | func GetDeviceDriverBaseName(imageBase LPVOID, lpBaseName []uint16, nSize DWORD) DWORD { 106 | ret1 := syscall3(getDeviceDriverBaseName, 3, 107 | uintptr(unsafe.Pointer(imageBase)), 108 | uintptr(unsafe.Pointer(&lpBaseName[0])), 109 | uintptr(nSize)) 110 | return DWORD(ret1) 111 | } 112 | 113 | func GetDeviceDriverFileName(imageBase uintptr, lpFilename []uint16, nSize DWORD) DWORD { 114 | defer func() { 115 | if err := recover(); err != nil { 116 | fmt.Println("failure in GetDeviceDriverFilename") 117 | fmt.Println(err) 118 | return 119 | } 120 | }() 121 | 122 | ret1 := syscall3(getDeviceDriverFileName, 3, 123 | imageBase, 124 | uintptr(unsafe.Pointer(&lpFilename[0])), 125 | uintptr(nSize)) 126 | return DWORD(ret1) 127 | } 128 | 129 | func GetSizeOfDriversArray() (uint32, error) { 130 | var bytesNeeded uint32 131 | // Golang null structs. 132 | nullBase := make([]uintptr, 1) 133 | success := EnumDeviceDrivers(nullBase, 0, &bytesNeeded) 134 | if !success { 135 | return 0, fmt.Errorf("failed to get size of Driver Array, errorcode : %v", syscall.GetLastError()) 136 | } 137 | return bytesNeeded, nil 138 | } 139 | 140 | func GetDriverFileName(driverAddrs uintptr) (string, error) { 141 | data := make([]uint16, 1024) 142 | 143 | if driverAddrs == 0 { 144 | return "", errors.New("nil driver address uintptr") 145 | } 146 | 147 | result := GetDeviceDriverFileName(driverAddrs, data, DWORD(1000)) 148 | if result == 0 { 149 | return "", fmt.Errorf("failed to get device driver file name: %v", syscall.GetLastError()) 150 | } 151 | 152 | return syscall.UTF16ToString(data), nil 153 | } 154 | 155 | func GetDriverBaseName(driverAddrs uintptr) (string, error) { 156 | data := make([]uint16, 1024) 157 | 158 | if driverAddrs == 0 { 159 | return "", errors.New("nil driver address uintptr") 160 | } 161 | 162 | result := GetDeviceDriverBaseName(LPVOID(driverAddrs), data, DWORD(1000)) 163 | if result == 0 { 164 | return "", fmt.Errorf("failed to get device driver file name: %v", syscall.GetLastError()) 165 | } 166 | 167 | return syscall.UTF16ToString(data), nil 168 | } 169 | 170 | func IterateOverDrivers(numberOfDrivers uint, driverAddrs []uintptr) ([]resources.DriverMetaData, error) { 171 | var ( 172 | multiErr error 173 | summary []resources.DriverMetaData = make([]resources.DriverMetaData, 0) 174 | ) 175 | 176 | for _, addr := range driverAddrs { 177 | driverFileName, err := GetDriverFileName(addr) 178 | if err != nil { 179 | multiErr = multierror.Append(multiErr, err) 180 | continue 181 | } 182 | 183 | driverBaseName, err := GetDriverBaseName(addr) 184 | if err != nil { 185 | multiErr = multierror.Append(multiErr, err) 186 | continue 187 | } 188 | 189 | if driverBaseName == "" { 190 | continue 191 | } 192 | 193 | output, err := AnalyzeDriver(driverFileName, driverBaseName) 194 | if err != nil { 195 | multiErr = multierror.Append(multiErr, err) 196 | } 197 | 198 | if len(output.ScanMatch) > 0 { 199 | summary = append(summary, output) 200 | } 201 | } 202 | 203 | return summary, multiErr 204 | } 205 | 206 | func AnalyzeDriver(driverFileName string, driverBaseName string) (resources.DriverMetaData, error) { 207 | fixedDriverPath := strings.ToLower(driverFileName) 208 | fixedDriverPath = strings.Replace(fixedDriverPath, `\systemroot\`, `c:\windows\`, -1) 209 | if strings.HasPrefix(fixedDriverPath, `\windows\`) { 210 | fixedDriverPath = strings.Replace(fixedDriverPath, `\windows\`, `c:\windows\`, -1) 211 | } else if strings.HasPrefix(fixedDriverPath, `\??\`) { 212 | fixedDriverPath = strings.Replace(fixedDriverPath, `\??\`, ``, -1) 213 | } 214 | 215 | analysis := resources.DriverMetaData{ 216 | DriverBaseName: driverBaseName, 217 | DriverFilePath: fixedDriverPath, 218 | ScanMatch: make([]string, 0), 219 | } 220 | 221 | analysis.DriverSysMetaData, _ = GetFileMetaData(fixedDriverPath) 222 | 223 | for _, edr := range EdrList { 224 | // regexp as alternate but saving another import. No bully. 225 | if strings.Contains( 226 | strings.ToLower(fmt.Sprint(analysis)), 227 | strings.ToLower(edr)) { 228 | analysis.ScanMatch = append(analysis.ScanMatch, edr) 229 | } 230 | } 231 | 232 | return analysis, nil 233 | } 234 | 235 | // CheckDrivers return a list of drivers matching any suspicious driver names present in edrdata.go. 236 | func CheckDrivers() ([]resources.DriverMetaData, error) { 237 | var drivers []resources.DriverMetaData = make([]resources.DriverMetaData, 0) 238 | 239 | sizeOfDriverArrayInBytes, err := GetSizeOfDriversArray() 240 | if err != nil { 241 | return drivers, err 242 | } 243 | 244 | sizeOfOneDriverAddress := uint(unsafe.Sizeof(uintptr(0))) 245 | 246 | numberOfDrivers = uint(sizeOfDriverArrayInBytes) / sizeOfOneDriverAddress 247 | driverAddrs = make([]uintptr, numberOfDrivers) 248 | 249 | success := EnumDeviceDrivers(driverAddrs, DWORD(sizeOfDriverArrayInBytes), &sizeOfDriverArrayInBytes) 250 | if !success { 251 | return drivers, fmt.Errorf("failed to enumerate device drivers, error code: %w", syscall.GetLastError()) 252 | } 253 | 254 | drivers, err = IterateOverDrivers(numberOfDrivers, driverAddrs) 255 | if err != nil { 256 | return drivers, err 257 | } 258 | 259 | return drivers, nil 260 | } 261 | -------------------------------------------------------------------------------- /pkg/edrRecon/edrRecon_test.go: -------------------------------------------------------------------------------- 1 | package edrRecon 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "testing" 8 | 9 | "github.com/fourcorelabs/edrhunt/pkg/scanners" 10 | ) 11 | 12 | func TestCheckDrivers(t *testing.T) { 13 | 14 | summary, err := CheckDrivers() 15 | for _, driver := range summary { 16 | output := fmt.Sprintf("\nSuspicious Driver Module: %s\nDriver FilePath: %s\nDriver File Metadata: %s\nMatched Keyword: %s\n", driver.DriverBaseName, driver.DriverFilePath, FileMetaDataParser(driver.DriverSysMetaData), driver.ScanMatch) 17 | fmt.Println(output) 18 | } 19 | if err.Error() != "" { 20 | t.Error(err) 21 | } 22 | } 23 | 24 | func TestCheckRegistry(t *testing.T) { 25 | summary, err := CheckRegistry(context.TODO()) 26 | fmt.Println("Scanning registry: ") 27 | for _, match := range summary.ScanMatch { 28 | fmt.Printf("\t%s\n", match) 29 | } 30 | 31 | if err != nil { 32 | fmt.Println("error", err) 33 | } 34 | } 35 | 36 | func TestCheckServices(t *testing.T) { 37 | summary, err := CheckServices() 38 | for _, service := range summary { 39 | output := fmt.Sprintf("\nSuspicious Service Name: %s\nDisplay Name: %s\nDescription: %s\nCaption: %s\nCommandLine: %s\nStatus: %s\nProcessID: %s\nFile Metadata: %s\nMatched Keyword: %s\n", service.ServiceName, service.ServiceDisplayName, service.ServiceDescription, service.ServiceCaption, service.ServicePathName, service.ServiceState, service.ServiceProcessId, FileMetaDataParser(service.ServiceExeMetaData), service.ScanMatch) 40 | fmt.Println(output) 41 | } 42 | if err.Error() != "" { 43 | fmt.Println("error", err) 44 | } 45 | } 46 | 47 | func TestCheckProcesses(t *testing.T) { 48 | summary, err := CheckProcesses() 49 | for _, process := range summary { 50 | output := fmt.Sprintf("\nSuspicious Process Name: %s\nDescription: %s\nCaption: %s\nBinary: %s\nProcessID: %s\nParent Process: %s\nProcess CmdLine : %s\nFile Metadata: %s\nMatched Keyword: %s\n", process.ProcessName, process.ProcessDescription, process.ProcessCaption, process.ProcessPath, process.ProcessPID, process.ProcessParentPID, process.ProcessCmdLine, FileMetaDataParser(process.ProcessExeMetaData), process.ScanMatch) 51 | fmt.Println(output) 52 | } 53 | if err.Error() != "" { 54 | fmt.Println("error", err) 55 | } 56 | } 57 | 58 | func TestCheckAVWMI(t *testing.T) { 59 | summary, _ := CheckAVWmiRepo() 60 | for _, av := range summary { 61 | fmt.Println(av) 62 | } 63 | // if err.Error() != "" { 64 | // fmt.Println("error", err) 65 | // } 66 | } 67 | 68 | func TestGetFileMetaData(t *testing.T) { 69 | fileMetaData, err := GetFileMetaData(`C:\Users\hardi\AnyDesk.exe`) 70 | if err != nil { 71 | t.Error(err) 72 | } 73 | file, _ := json.Marshal(fileMetaData) 74 | fmt.Println(string(file)) 75 | } 76 | 77 | func TestGetDirectory(t *testing.T) { 78 | _, err := CheckDirectory() 79 | if err != nil { 80 | t.Error(err) 81 | } 82 | } 83 | 84 | func TestCheckIfAdmin(t *testing.T) { 85 | status := CheckIfAdmin() 86 | if status { 87 | fmt.Println("Running as admin") 88 | } else { 89 | t.Error(status) 90 | } 91 | } 92 | 93 | func TestDeObfNames(t *testing.T) { 94 | for _, name := range EdrList { 95 | fmt.Println(name) 96 | } 97 | for _, name := range RegistryReconList { 98 | fmt.Println(name) 99 | } 100 | } 101 | 102 | type EDRHuntResult struct { 103 | Type string `json:"id"` 104 | } 105 | 106 | func TestEDRScanner(t *testing.T) { 107 | var result []EDRHuntResult = make([]EDRHuntResult, 0) 108 | 109 | systemData, err := GetSystemData(context.TODO()) 110 | if err != nil { 111 | t.Error(err) 112 | return 113 | } 114 | 115 | for _, scanner := range scanners.Scanners { 116 | _, ok := scanner.Detect(systemData) 117 | if ok { 118 | result = append(result, EDRHuntResult{ 119 | Type: string(scanner.Type()), 120 | }) 121 | } 122 | } 123 | 124 | fmt.Println(result) 125 | } 126 | -------------------------------------------------------------------------------- /pkg/edrRecon/edrdata.go: -------------------------------------------------------------------------------- 1 | package edrRecon 2 | 3 | // var ( 4 | // EdrList = []string{} 5 | // RegistryReconList = []string{} 6 | // RegistrySearchList = []string{} 7 | // key = []byte("obscurityisablessing") 8 | // ) 9 | 10 | // var obfEdrList = []string{ 11 | // "0e01070a03170a1b171a1c0d07", 12 | // "0e0f000a5b160518", 13 | // "0e0c070a551f08180e080104", 14 | // "0e0c070a581f08180e080104", 15 | // "0e0c070a18130503181b16", 16 | // "0e0c070a550400060c1a", 17 | // "0e0c070a580400060c1a", 18 | // "0e0c070a031b1b010a", 19 | // "0e120310101c1a11", 20 | // "0e17070b011319", 21 | // "0e14121001", 22 | // "0e141600011d", 23 | // "0c031d02070b", 24 | // "0c0301011a1c0b18180a18", 25 | // "0c0301011a1c49161508100a", 26 | // "0c005d060d17", 27 | // "0c0b00001a130404", 28 | // "0c0b00001a52081909", 29 | // "0c0d060d01171b171c1907", 30 | // "0c0d060d01171b00180a18", 31 | // "0c10120e0100080d", 32 | // "0c1000100311", 33 | // "0c101c1411011d06100216", 34 | // "0c111204101c1d", 35 | // "0c1115021911061a", 36 | // "0c11000b101e05", 37 | // "0c1b1106071708071607", 38 | // "0c1b100f1a00081918", 39 | // "0c1b1f021b110c", 40 | // "0c1b1c13011b0a07", 41 | // "0c1b061311131d11", 42 | // "0c1b05060713", 43 | // "0c1b000607040c06", 44 | // "0c1b0711140b", 45 | // "0b030108010008171c", 46 | // "0b0715061b16191b100707", 47 | // "0b0715061b160c06", 48 | // "0a071017071e", 49 | // "0a0e1210011b0a", 50 | // "0a0c1704141f0c", 51 | // "094f000616071b11", 52 | // "090d01001002061d171d", 53 | // "090b0106100b0c", 54 | // "08101c161b16051d170e", 55 | // "2830211010001f1d1a", 56 | // "060c001310111d1b0b", 57 | // "0614120d011b", 58 | // "0403001310001a1f00", 59 | // "030310161b13", 60 | // "030d14111d0b1d1c14", 61 | // "02031f1414000c", 62 | // "02031d071c130700", 63 | // "020112051017", 64 | // "020d01131d1b1a111a", 65 | // "0211121016070018", 66 | // "02111e13101c0e", 67 | // "010b00100704", 68 | // "000f1d0a", 69 | // "000f1d0a14150c1a0d", 70 | // "00110216100010", 71 | // "3f031f0c5533050016493d04161b0a01181a", 72 | // "1f0516131a010c060f001004", 73 | // "1f05001a06060c190d1b1218", 74 | // "1f101a151c1e0c131c0e06001008", 75 | // "1f101c0002130518", 76 | // "1f101c1710111d1b0b1a1613140506", 77 | // "1e1012071400", 78 | // "1d071700191d081f", 79 | // "1c07101607171e1b0b0200", 80 | // "1c071016071b1d0d110c120d16041616011f07040a", 81 | // "1c071e0f14070717111a05", 82 | // "1c071d171c1c0c18", 83 | // "1c07030f1c040c01090d1215", 84 | // "1c0b000a11011a110b1f1a0207", 85 | // "1c0b000a05011a110b1f1a0207", 86 | // "1c0b000a05011c001005", 87 | // "1c0f104d100a0c", 88 | // "1c0f1004001b", 89 | // "1c0c12004346", 90 | // "1c0d030b1a01", 91 | // "1c121f161b19", 92 | // "1c10071005", 93 | // "1c1b1e021b060c17", 94 | // "1c1b1e001a001901", 95 | // "1c1b1e0613131a1d", 96 | // "1c1b000a1b060c0617081f", 97 | // "1c1b000e1a1c", 98 | // "1b031d0a001f", 99 | // "1b06124d100a0c", 100 | // "1b0612141a0002", 101 | // "1b120a171d1d07", 102 | // "190710170713", 103 | // "180b1d001a1e05111a1d", 104 | // "180b1d071a051a071c07000e10", 105 | // "180b0106061a080612", 106 | // "1b0a01061406", 107 | // "170314175b171111", 108 | // "170314171b1d1d1d1f47161907", 109 | // } 110 | 111 | // var obfRegistryReconList = []string{ 112 | // "3c071d171c1c0c18592512031130", 113 | // "3c071d171c1c0c18592814040c1839", 114 | // "0a1a0706071c0818302d", 115 | // "290b0106300b0c", 116 | // "2c1b1f021b110c28", 117 | // "2c1b1f021b110c44", 118 | // "2c1b1f021b110c45", 119 | // "2c1b1f021b110c46", 120 | // "2c101c1411211d061002163d", 121 | // "4a312a3021372426362627443e1f1c00070c03545d3e17111c040c060a3510130d1b0100071b070c0a3e301031171f1d1a0c300e0c18171c1f47070909", 122 | // "4a312a3021372426362627443e1f1c00070c03545d3e17111c040c060a3510130d1b0100071b070c0a3e3010331b1b190e0801042302041f0a1a0714410b1d05", 123 | // "22011205101735", 124 | // "22013205101728131c07073d", 125 | // "2e32230c191b0a0d37081e04", 126 | // "2a32230c191b0a0d37081e04", 127 | // "202320331a1e00170027120c07", 128 | // "3c1b1e021b060c17", 129 | // "3c1b1e021b060c17592c1d0512030c1d07493e1500161600011b061a25", 130 | // "380b1d071a051a543d0c15040c080001", 131 | // "2b1212271c010816150c17", 132 | // "2b0b0002171e0c261c081f350b01003e1c07071300101a0d12", 133 | // "2c0301011a1c2b18180a183d", 134 | // "2c003706131707071c35", 135 | // "3c071d101a003f110b1a1a0e0c", 136 | // } 137 | 138 | // var obfRegistrySearchList = []string{ 139 | // "1d07144304070c06004951292920282f20303d332a2f2f2000001b11171d300e0c18171c1f3a0b1333311611031b0a110a3527021205152f23081c060207070607014b", 140 | // "1d07144304070c06004951292920282f3b283c233823212629362c273a3b3a3136252a3d2f3a17141b071e3f373b26275b", 141 | // "1d07144304070c0600493b2a2e2139203c2f3a302e30363f381b0a06161a1c071630321a1d0d01101c3e301607000c1a0d3f161311050a1d2f3c000e01110702191e", 142 | // "1d07144304070c0600493b2a2e2139203c2f3a302e30363f381b0a06161a1c071630321a1d0d01101c3e301607000c1a0d3f161311050a1d2f39010b06011a06062e3a0d0a1d160c", 143 | // "1d07144304070c060049512929293c2c3f262d26233d3e22363a203a3c3520383138203e2f2a1b151d071d17361d07000b061f32071839301c071a15000e2f2f26334b", 144 | // "1d07144304070c06004951292920282f200608131803010629220618100a1a041130281a101b01140004073f221b0710161e003d2609131a100c29120e101741", 145 | // "1d07144304070c060049512929293c2c3f262d26233d3e22363a203a3c35202e24383232212c322a0601010c061d0f00253e1a0f06031200532d0b010a0c1706072e3b1118055e350b010053231b01130a01070a1a1c4b", 146 | // "1d07144304070c060049512929293c2c3f262d26233d3e22363a203a3c35202e24383232212c322a0601010c061d0f00253e1a0f0603120053280a110e0c100611523d1c0b0c1215423c171c070c0d13060d1d3f260608000c1a51", 147 | // "1d07144304070c0600493b2a2e2139201c0f1a100e10163f381128121c0c2f240c08151c1a071a3b2e34", 148 | // "1d07144304070c0600493b2a2e2139201c0f1a100e10163f260b0415171d1602", 149 | // "1d07144304070c0600493b2a2e2139201c0f1a100e10163f360b0515170a163d2609161807061e", 150 | // "1d07144304070c0600493b2a2e2139201c0f1a100e10163f36102d111f0c1d1207", 151 | // "1d07144304070c0600493b2a2e2139201c0f1a100e10163f360006031d3a07130b07002f3a0708230d", 152 | // "1d07144304070c06004951292920282f200608131803010629210c1a0d001d040e4c2912111a4c", 153 | // "1d07144304070c06004951292920282f200608131803010629210c1a0d001d040e4c2912111a322608071d1757", 154 | // } 155 | 156 | // func init() { 157 | 158 | // encodedLists := [][]string{ 159 | // obfEdrList, 160 | // obfRegistryReconList, 161 | // obfRegistrySearchList, 162 | // } 163 | // decodedLists := []*[]string{ 164 | // &EdrList, 165 | // &RegistryReconList, 166 | // &RegistrySearchList, 167 | // } 168 | 169 | // for i, encodedList := range encodedLists { 170 | // decodedList := decodedLists[i] 171 | // for _, index := range encodedList { 172 | // deHex, _ := hex.DecodeString(index) 173 | // decoded := xorObf(deHex, key) 174 | // *decodedList = append(*decodedList, string(decoded)) 175 | // } 176 | // } 177 | // } 178 | 179 | // func xorObf(input, key []byte) []byte { 180 | // ret := make([]byte, len(input)) 181 | // for i := 0; i < len(input); i++ { 182 | // ret[i] = input[i] ^ key[i%len(key)] 183 | // } 184 | // return ret 185 | // } 186 | 187 | // Edrlist is a list of edrs. 188 | var EdrList = []string{ 189 | "BitDefender", 190 | "bdagent.exe", 191 | "AntiphishingAgent.dll", 192 | "bdcloud.dll", 193 | "bdmltusrsrv.dll", 194 | "bdnc.dll", 195 | "bdfndisf6.sys", 196 | "bdfwcore.dll", 197 | "bdfwfpf.sys", 198 | "bdpredir.dll", 199 | "bdquar.dll", 200 | "avc3.sys", 201 | "avckf.sys", 202 | "alertvs10u.http.dll", 203 | "amvs10u.http.dll", 204 | "aphvs10u.http.dll", 205 | "bdch.dll", 206 | "bdchsubmit.dll", 207 | "BdFirewallSDK.dll", 208 | "bdreinit.exe", 209 | "bdpredir_ssl.dl", 210 | "pdscan.exe", 211 | "pdiface.exe", 212 | "pdiface.exe", 213 | "bdnc.dll", 214 | "BDSubmit.dll", 215 | "BDSubWiz.exe", 216 | "ProductAgentService.exe", 217 | "ProductAgentUI.exe", 218 | "WatchDog.exe", 219 | "bdch.dll", 220 | "bdec.dll", 221 | "bdreinit.exe", 222 | "CarbonBlack\\", 223 | "CbDefense\\", 224 | "SensorVersion", 225 | "CarbonBlackClientSetup.exe", 226 | "Checkpoint", 227 | "tracsrvwrapper.exe", 228 | "C:\\Program Files\\checkpoint\\endpoint connect\\tracsrvwrapper.exe", 229 | "TrGUI.exe", 230 | "TracCAPI.exe", 231 | "dtplat.dll", 232 | "epcgina.dll", 233 | "epcgina_user64.dll", 234 | "LogonISReg.dll", 235 | "OsMonitor.dll", 236 | "ProcessMonitor.dll", 237 | "proxystub.dll", 238 | "ScriptRun.dll", 239 | "SCVMonitor.dll", 240 | "scvprod_lang_pack.dll", 241 | "SCUIAPI.dll", 242 | "cpmsi_tool.exe", 243 | "DataStruct.dll", 244 | "FileHash_DYN.dll", 245 | "trac.exe", 246 | "TrAPI.dll", 247 | "vna_coinstall.dll - vna", 248 | "vna_install64.exe", 249 | "vna_utils.exe", 250 | "TracSrvWrapper.exe", 251 | "TrGUI.exe", 252 | "TracSrvWrapper.exe", 253 | "vsmon.exe", 254 | "C:\\Program Files\\CheckPoint\\ZoneAlarm\\vsmon.exe", 255 | "TrueVector", 256 | "p95tray.exe", 257 | "CrowdStrike", 258 | "%SYSTEMROOT%\\system32\\drivers\\crowdstrike\\CsDeviceControl.inf", 259 | "%SYSTEMROOT%\\system32\\drivers\\crowdstrike\\CsFirmwareAnalysis.inf", 260 | "windowssensor.x64.exe", 261 | "C:\\Windows\\System32\\drivers\\crowdstrike", 262 | "csagent.sys", 263 | "csim.sys", 264 | "csimn.sys", 265 | "csimu.sys", 266 | "imbs.sys", 267 | "CybereasonRansomFreeServiceHost.exe", 268 | "Cybereason", 269 | "Cybereason ActiveProbe\\", 270 | "CrAmTray.exe", 271 | "Cybereason", 272 | "crsdll.dll", 273 | "ap.dll", 274 | "CoreMinion.dll", 275 | "CoreMinion", 276 | "minionhost.exe", 277 | "Cybereason Sensor", 278 | "CybereasonSensor.exe", 279 | "Cylance\\", 280 | "Cylance0", 281 | "Cylance1", 282 | "Cylance2", 283 | "CylanceProtectSetup.exe", 284 | "cylancesvc.exe", 285 | "CylanceUI.exe", 286 | "CylanceProtect", 287 | "CylanceProtectSetup.exe", 288 | "cylance.updatemgr.interfaces.dll", 289 | "cylancesvc.exe", 290 | "cylance.host.updater.dll", 291 | "cylance.host.versions.dll", 292 | "cylance.host.analysis.dll", 293 | "cylance.host.ccui.interfaces.dll", 294 | "cylance.host.commandcontrolui.dll", 295 | "cylance.host.controller.dll", 296 | "cylance.host.cylancevenue.dll", 297 | "cylance.host.infinitymodel.dll", 298 | "cylance.host.windowseventlogwriter.dll", 299 | "cylance.interfaces.dll", 300 | "cymemdef.dll", 301 | "cyprotectdrv64.sys", 302 | "cyupdate.exe", 303 | "cyhelper64.dl", 304 | "cylanceui.exe", 305 | "cymemdef64.dll", 306 | "cylance.host.cylancevenuemodule.dll", 307 | "cylance.host.memdefps_gac.dll", 308 | "cylance.host.systeminformation.dll", 309 | "cymemdefps.dll", 310 | "cymemdefps64.dll", 311 | "cylance.host.wmiprovider_gac.dll", 312 | "cylance.host.infinitymodelole.dll", 313 | "cylance.host.infinitymodelpdf.dll", 314 | "Cynet", 315 | "Cyops", 316 | "Cynet EPS", 317 | "DeepInstinct", 318 | "Deep Instinct Agent", 319 | "Deep Instinct Prevention Platform", 320 | "HKEY_LOCAL_MACHINE\\SOFTWARE\\Deep Instinct", 321 | "Elastic", 322 | "elastic-agent.exe", 323 | "elastic-endpoint.exe", 324 | "elastic-endpoint-driver", 325 | "ElasticEndpoint", 326 | "ESET", 327 | "ecmd", 328 | "egui.exe", 329 | "ekrn", 330 | "minodlogin.exe", 331 | "minodlogin", 332 | "emu-rep.exe", 333 | "emu_install.exe", 334 | "emu-cci.exe", 335 | "emu-gui.exe", 336 | "emu-uninstall.exe", 337 | "ndep.exe", 338 | "emu-gui.exe", 339 | "spike.exe", 340 | "ESET MSP Utilities", 341 | "ecls.exe", 342 | "ecmd.exe", 343 | "ecomserver.exe", 344 | "eeclnt.exe", 345 | "egui.exe", 346 | "eguiAmon.dll", 347 | "eguiDevmon.dll", 348 | "eguiDmon.dll", 349 | "eguiEmon.dll", 350 | "eguiEpfw.dll", 351 | "eguiHips.dll", 352 | "eguiMailPlugins.dll", 353 | "eguiParental.dll", 354 | "eguiProduct.dll", 355 | "eguiProductRcd.dll", 356 | "eguiScan.dll", 357 | "eguiSmon.dll", 358 | "eguiUpdate.dll", 359 | "eh64.exe", 360 | "EHttpSrv.exe", 361 | "eplgHooks.dll", 362 | "eplgOE.dll", 363 | "cfgres.dll", 364 | "eclsLang.dll", 365 | "eguiAmonLang.dll", 366 | "eguiEpfwLang.dll", 367 | "eguiHipsLang.dll", 368 | "eguiLang.dll", 369 | "eguiOnlineHelp.dll", 370 | "eguiOnlineHelpLang.dll", 371 | "eguiScanLang.dll", 372 | "eguiSmonLang.dll", 373 | "eguiUpdateLang.dll", 374 | "eguiWebControl.dll", 375 | "ekrnDevmonLang.dll", 376 | "ekrnEpfwLang.dll", 377 | "ekrnHipsLang.dll", 378 | "FireEye", 379 | "C:\\Program Files\\FireEye\\xagt\\", 380 | "xagt.exe", 381 | "Fortinet", 382 | "collectoragent.exe", 383 | "dcagent.dll", 384 | "dcagent_amd64.dll", 385 | "FSAEConfig.exe", 386 | "uninstalldcagent.exe", 387 | "fortilspheuristics.dll", 388 | "mdare.dll", 389 | "fccomintdll.dll", 390 | "fcoeam.dll", 391 | "fmon.exe ", 392 | "fwutil.dll", 393 | "rmon.exe", 394 | "fccomint.exe", 395 | "fclanguageselector.exe", 396 | "fortifw.exe", 397 | "fcreg.exe", 398 | "fortitray.exe", 399 | "libcfg.dll", 400 | "fcappdb.exe", 401 | "fcoehook.dll", 402 | "fcwizard.exe", 403 | "fcp.dll", 404 | "fcresc.dll", 405 | "submitv.exe", 406 | "av_task.exe", 407 | "fortiwf.exe", 408 | "forticlish.dll", 409 | "fortiece.dll", 410 | "libavr.dll", 411 | "fortiwadbd.exe", 412 | "utilsdll.dll", 413 | "fase.dll", 414 | "fcauth.exe", 415 | "fcdblog.exe", 416 | "fcmgr.exe", 417 | "fortiwad.exe", 418 | "libav.dll", 419 | "fortiproxy.exe", 420 | "fortiskin.dll", 421 | "fortiscand.exe", 422 | "fortivpnst.dll", 423 | "fortivpnst.exe", 424 | "fortivpnst64.dll", 425 | "ipsec.exe", 426 | "fasle.dll", 427 | "fcwscd7.exe", 428 | "fcasc.exe", 429 | "fchelper.exe", 430 | "forticlient.exe", 431 | "fcwsc.exe", 432 | "forticlish.dll", 433 | "FortiClient Service Scheduler", 434 | "FortiClient.exe", 435 | "av_task.exe", 436 | "fortiwad.exe", 437 | "fortiproxy.exe", 438 | "fcmgr.exe", 439 | "FortiLSPHeuristics.dll", 440 | "mdare.dll", 441 | "npccpluginex.dll", 442 | "nptcplugin.dll", 443 | "npccplugin.dll", 444 | "FCCOMIntDLL.dll", 445 | "FCOEAM.dll", 446 | "fmon.exe", 447 | "FSSOMA.exe", 448 | "LaunchCacheClean.dll", 449 | "launchcacheclean64.dll", 450 | "rmon.exe", 451 | "FCCOMInt.exe", 452 | "FCVbltScan.exe", 453 | "sslvpnhostcheck.dll", 454 | "sslvpnhostcheck64.dll", 455 | "FortiESNAC.exe", 456 | "FortiTray.exe", 457 | "fcappdb.exe", 458 | "FCConfig.exe", 459 | "FCOEHook.dll", 460 | "fcp.dll", 461 | "FCResc.dll", 462 | "forticachecleaner.dll", 463 | "FortiCacheCleaner64.dll", 464 | "forticredentialprovider.dll", 465 | "FortiCredentialProvider2x64.dll", 466 | "forticredentialprovider64.dll", 467 | "FortiTrayResc.dll", 468 | "av_task.exe", 469 | "FortiWF.exe", 470 | "EPCUserAvatar.exe", 471 | "FortiAvatar.exe", 472 | "FortiCliSh.dll", 473 | "FortiCliSh64.dll", 474 | "libavr.dll", 475 | "fortifws.exe", 476 | "FortiWadbd.exe", 477 | "FortiClient_Diagnostic_Tool.exe", 478 | "forticontrol.dll", 479 | "FortiSSLVPNdaemon.exe", 480 | "sslvpnlib.dll", 481 | "utilsdll.dll", 482 | "FCAuth.exe", 483 | "FortiCliSh.dll", 484 | "FortiCliSh64.dll", 485 | "npccpluginex.dll", 486 | "nptcplugin.dll", 487 | "npccplugin.dll", 488 | "FortiClient Service Scheduler", 489 | "av_task.exe", 490 | "FortiESNAC.exe", 491 | "ipsec.exe", 492 | "FortiWad.exe", 493 | "FortiProxy.exe", 494 | "kaspersky", 495 | "avp.exe", 496 | "avpui.exe", 497 | "avpservice.dll", 498 | "avpui.exe", 499 | "avzkrnl.dll", 500 | "cbi.dll", 501 | "cf_anti_malware_facade.dll", 502 | "cf_facade.dll", 503 | "cf_mgmt_facade.dll", 504 | "cf_response_provider.dll", 505 | "ckahcomm.dll", 506 | "ckahrule.dll", 507 | "ckahum.dll", 508 | "eka_meta.dll", 509 | "kasperskylab.kis.ui.dll", 510 | "am_facade.dll", 511 | "am_meta.dll", 512 | "attestation_task.dll", 513 | "avs_eka.dll", 514 | "kasperskylab.ksde.ui.dll", 515 | "kasperskylab.ui.core.dll", 516 | "kasperskylab.ui.core.visuals.dll", 517 | "ksdeuimain.dll", 518 | "avpsus.exe", 519 | "klnagent.exe", 520 | "klnsacwsrv.exe", 521 | "klnagent.exe", 522 | "kl_platf.exe", 523 | "stpass.exe", 524 | "klnagwds.exe", 525 | "MalwareBytes", 526 | "mbae.exe", 527 | "mbae.dll", 528 | "mbae64.dll", 529 | "mbae64.exe", 530 | "mbae-api.dll", 531 | "mbae-svc.exe", 532 | "mbae-uninstaller.exe", 533 | "mbae.sys", 534 | "mbae64.sys", 535 | "mbae-svc.exe", 536 | "Malwarebytes Anti-Exploit Service", 537 | "C:\\Program Files\\Malwarebytes Anti-Exploit\\mbae.exe", 538 | "mbae-loader.exe ", 539 | "mbaeLoader32.exe", 540 | "mbaeloader64.exe", 541 | "mbamcore.dll", 542 | "mbam-dor.exe", 543 | "mbamext.dll", 544 | "mbamgui.exe", 545 | "mbamnet.dll", 546 | "mbamservice.exe", 547 | "mbamtrayctrl.exe", 548 | "mbampt.exe", 549 | "mbamscheduler.exe", 550 | "C:\\Program Files\\Malwarebytes Anti-Rootkit", 551 | "mbar-1.08.2.1001.exe ", 552 | "mbeadomain.dll", 553 | "Coreinst.exe", 554 | "mbae-setup.exe", 555 | "Mcafee\\", 556 | "mcupdate.exe", 557 | "ProtectedModuleHost.exe", 558 | "McAfeeAgent\\", 559 | "APPolicyName", 560 | "EPPolicyName", 561 | "OASPolicyName", 562 | "ESConfigTool.exe", 563 | "FWInstCheck.exe", 564 | "FwWindowsFirewallHandler.exe", 565 | "mfeesp.exe", 566 | "mfefw.exe", 567 | "mfeProvisionModeUtility.exe", 568 | "mfetp.exe", 569 | "WscAVExe.exe", 570 | "mcshield.exe", 571 | "McChHost.exe", 572 | "mfewc.exe", 573 | "mfewch.exe", 574 | "mfewcui.exe", 575 | "fwinfo.exe", 576 | "mfecanary.exe", 577 | "mfefire.exe", 578 | "mfehidin.exe", 579 | "mfemms.exe", 580 | "mfevtps.exe", 581 | "mmsinfo.exe", 582 | "vtpinfo.exe", 583 | "MarSetup.exe", 584 | "mctray.exe", 585 | "masvc.exe", 586 | "macmnsvc.exe", 587 | "MfeServiceMgr.exe ", 588 | "McAPExe.exe", 589 | "McPvTray.exe", 590 | "mcods.exe", 591 | "mcuicnt.exe", 592 | "mcuihost.exe", 593 | "Mcshield.exe", 594 | "xtray.exe", 595 | "McpService.exe", 596 | "epefprtrainer.exe", 597 | "mfeffcoreservice.exe", 598 | "MfeEpeSvc.exe", 599 | "Qualys", 600 | "qualysagent.exe", 601 | "QualysProxy.exe", 602 | "QualysAgentUI.exe", 603 | "SentinelOne\\", 604 | "CbDefense\\", 605 | "SensorVersion", 606 | "C:\\Program Files\\SentinelOne", 607 | "SentinelAgent", 608 | "SentinelMonitor", 609 | "Sophos", 610 | "C:\\Program Files\\Sophos\\Sophos Virus Removal Tool\\", 611 | "SVRTgui.exe", 612 | "SVRTcli.exe", 613 | "ResEnu.dll", 614 | "Sophos Virus Removal Tool install.exe", 615 | "SVRTcli.exe", 616 | "SVRTgui.exe", 617 | "SCTCleanupService.exe", 618 | "SUL.dll", 619 | "SVRTservice.exe", 620 | "native.exe", 621 | "osdp.dll", 622 | "SAVI.dll", 623 | "veex.dll", 624 | "rkdisk.dll", 625 | "SCTBootTasks.exe", 626 | "ALMon.exe", 627 | "SAA.exe", 628 | "SUMService.exe", 629 | "SVRTservice.exe", 630 | "ssp.exe", 631 | "SCFService.exe", 632 | "SCFManager.exe", 633 | "spa.exe", 634 | "SpaRmsAdapter.dll", 635 | "cabarc.exe", 636 | "sargui.exe", 637 | "Sophos Computer Security Scan.exe", 638 | "sntpservice.exe", 639 | "C:\\Program Files\\sophos\\management communications system\\endpoint", 640 | "SophosLinkIconHandler32.dll", 641 | "McsClient.exe", 642 | "McsAgent.exe", 643 | "McsHeartbeat.exe", 644 | "SAVAdminService.exe", 645 | "conan.dll", 646 | "sav32cli.exe", 647 | "DCManagement.dll", 648 | "DesktopMessaging.dll", 649 | "DetectionFeedback.dll", 650 | "DeviceControlPlugin.dll", 651 | "DriveProcessor.dll", 652 | "EEConsumer.dll", 653 | "ForceUpdateAlongSideSGN.exe", 654 | "FSDecomposer.dll", 655 | "ICAdapter.dll", 656 | "ICManagement.dll", 657 | "ICProcessors.dll", 658 | "osdp.dll", 659 | "SavAdapter.dll", 660 | "SAVAdminService.exe", 661 | "SAVCleanupService.exe", 662 | "SAVControl.dll", 663 | "SAVI.dll", 664 | "SavMain.exe", 665 | "savmscm.dll", 666 | "SavNeutralRes.dll", 667 | "SavPlugin.dll", 668 | "SavProgress.exe", 669 | "SavProxy.exe", 670 | "SavRes.dll", 671 | "SavResChs.dll", 672 | "SavResCht.dll", 673 | "SavResDeu.dll", 674 | "SavResEng.dll", 675 | "SavResEsp.dll", 676 | "SavSecurity.dll", 677 | "SavService.exe", 678 | "SavShellExt.dll", 679 | "SavShellExtX64.dll", 680 | "bpaif.dll", 681 | "swc_service.exe", 682 | "swcadapter.dll", 683 | "swi_callout.sys", 684 | "swi_di.exe", 685 | "swi_service.exe", 686 | "swc_service.exe", 687 | "swi_filter.exe", 688 | "ALUpdate.exe", 689 | "SophosUpdate.exe", 690 | "SUL.dll", 691 | "ALMon.exe", 692 | "ALMsg.dll", 693 | "ALsvc.exe", 694 | "ALUpdate.exe", 695 | "AUAdapter.dll", 696 | "ChannelUpdater.dll", 697 | "cidsync.dll", 698 | "config.dll", 699 | "crypto.dll", 700 | "EECustomActions.dll", 701 | "inetconn.dll", 702 | "InstlMgr.dll", 703 | "ispsheet.dll", 704 | "SAUConfigDLL.dll", 705 | "SingleGUIPlugin.dll", 706 | "SophosAlert.exe", 707 | "swlocale.dll", 708 | "SavShellExt.dll", 709 | "SavShellExtX64.dll", 710 | "SavMain.exe", 711 | "SAVAdminService.exe", 712 | "SAVCleanupService.exe", 713 | "SavService.exe", 714 | "symantec", 715 | "symcorpu", 716 | "symefasi", 717 | "Symantec", 718 | "Norton 360", 719 | "AVSubmit.dll", 720 | "AVSvcPlg.dll", 721 | "NTPAlert.dll", 722 | "NTPFW.dll", 723 | "osCheck.exe", 724 | "N360Downloader.exe", 725 | "bushell.dll", 726 | "InstWrap.exe", 727 | "symbos.exe", 728 | "nss.exe", 729 | "symcorpui.exe", 730 | "isPwdSvc.exe", 731 | "ccsvchst.exe", 732 | "Symantec Endpoint Protection\\", 733 | "Deep Security Agent\\", 734 | "dsa", 735 | "Notifier", 736 | "Trend Micro", 737 | "ntrmv.exe", 738 | "pccntmon.exe", 739 | "AosUImanager.exe", 740 | "NTRTScan.exe", 741 | "AddinSentry.exe ", 742 | "tmaseng.dll", 743 | "TMAS_OL.exe", 744 | "TMAS_OLA.dll", 745 | "TMAS_OLImp.exe", 746 | "TMAS_OLShare.dll", 747 | "EMapiWpr.dll", 748 | "TMAS_OLSentry.exe", 749 | "ufnavi.exe", 750 | "Clnrbin.exe", 751 | "vizorhtmldialog.exe", 752 | "pwmConsole.exe", 753 | "PwmSvc.exe", 754 | "coreServiceShell.exe", 755 | "ds_agent.exe", 756 | "ufnavi.exe", 757 | "SfCtlCom.exe", 758 | "MBAMHelper.exe", 759 | "Management Console.exe", 760 | "activeconsole", 761 | "amsi.dll", 762 | "anti malware", 763 | "anti-malware", 764 | "antimalware", 765 | "anti virus", 766 | "anti-virus", 767 | "antivirus", 768 | "appsense", 769 | "authtap", 770 | "avast", 771 | "avecto", 772 | "canary", 773 | "carbonblack", 774 | "carbon black", 775 | "cb.exe", 776 | "ciscoamp", 777 | "cisco amp", 778 | "countercept", 779 | "countertack", 780 | "cramtray", 781 | "crssvc", 782 | "crowdstrike", 783 | "csagent", 784 | "csfalcon", 785 | "csshell", 786 | "cybereason", 787 | "cyclorama", 788 | "cylance", 789 | "cyoptics", 790 | "cyupdate", 791 | "cyvera", 792 | "cyserver", 793 | "cytray", 794 | "darktrace", 795 | "defendpoint", 796 | "defender", 797 | "eectrl", 798 | "elastic", 799 | "endgame", 800 | "f-secure", 801 | "forcepoint", 802 | "fireeye", 803 | "groundling", 804 | "GRRservic", 805 | "inspector", 806 | "ivanti", 807 | "kaspersky", 808 | "lacuna", 809 | "logrhythm", 810 | "malware", 811 | "mandiant", 812 | "mcafee", 813 | "morphisec", 814 | "msascuil", 815 | "msmpeng", 816 | "nissrv", 817 | "omni", 818 | "omniagent", 819 | "osquery", 820 | "Palo Alto Networks", 821 | "pgeposervice", 822 | "pgsystemtray", 823 | "privilegeguard", 824 | "procwall", 825 | "protectorservic", 826 | "qradar", 827 | "redcloak", 828 | "secureworks", 829 | "securityhealthservice", 830 | "semlaunchsv", 831 | "sentinel", 832 | "sepliveupdat", 833 | "sisidsservice", 834 | "sisipsservice", 835 | "sisipsutil", 836 | "smc.exe", 837 | "smcgui", 838 | "snac64", 839 | "sophos", 840 | "splunk", 841 | "srtsp", 842 | "symantec", 843 | "symcorpu", 844 | "symefasi", 845 | "sysinternal", 846 | "sysmon", 847 | "tanium", 848 | "tda.exe", 849 | "tdawork", 850 | "tpython", 851 | "vectra", 852 | "wincollect", 853 | "windowssensor", 854 | "wireshark", 855 | "threat", 856 | "xagt.exe", 857 | "xagtnotif.exe", 858 | "Elastic Agent", 859 | "elastic-agent.exe", 860 | "elastic-endpoint.exe", 861 | "elastic-endpoint-driver", 862 | "ElasticEndpoint", 863 | "ecmd.exe", 864 | "ekrn.exe", 865 | "ESET", 866 | "mcupdate.exe", 867 | "ProtectedModuleHost.exe", 868 | "dsa.exe", 869 | "Notifier.exe", 870 | "qualys", 871 | "qualysagent.exe", 872 | "rphcp.exe", 873 | "lc_sensor.exe", 874 | "refractionPOINT HCP", 875 | "LimaCharlie", 876 | } 877 | 878 | var ReconList = []string{ 879 | "ProductName", 880 | "CSDVersion", 881 | "CurrentVersion", 882 | "CurrentBuild", 883 | "SystemRoot", 884 | "RegisteredOrganization", 885 | "Domain", 886 | "DhcpNameServer", 887 | "DhcpDomain", 888 | "SystemManufacturer", 889 | "SystemProductName", 890 | "LocalAccountTokenFilterPolicy", 891 | "LsaCfgFlags", 892 | "elastic", 893 | } 894 | 895 | var McafeeList = []string{ 896 | "Mcafee\\", 897 | "McAfeeAgent\\", 898 | "APPolicyName", 899 | "EPPolicyName", 900 | "OASPolicyName", 901 | } 902 | 903 | var SymantecList = []string{ 904 | "Symantec", 905 | "Symantec Endpoint Protection\\", 906 | } 907 | 908 | // var WinDefender = []string{ 909 | // "Windows Defender", 910 | // "DpaDisabled", 911 | // "DisableRealTimeMonitoring", 912 | // } 913 | 914 | var WinDefenderATP = []string{} 915 | 916 | var CarbonBlack = []string{ 917 | "CarbonBlack\\", 918 | "CbDefense\\", 919 | "SensorVersion", 920 | } 921 | 922 | var CrowdStrike = []string{ 923 | "CrowdStrike\\", 924 | "%SYSTEMROOT%\\system32\\drivers\\crowdstrike\\CsDeviceControl.inf", 925 | "%SYSTEMROOT%\\system32\\drivers\\crowdstrike\\CsFirmwareAnalysis.inf", 926 | } 927 | 928 | var Cylance = []string{ 929 | "Cylance\\", 930 | "Cylance0", 931 | "Cylance1", 932 | "Cylance2", 933 | } 934 | 935 | var FireEye = []string{ 936 | "FireEye", 937 | } 938 | 939 | var SentinelOne = []string{ 940 | "Sentinel Labs\\", 941 | "Sentinel Agent\\", 942 | "externalID", 943 | } 944 | 945 | var RegistryReconList = []string{ 946 | "Sentinel Labs\\", 947 | "Sentinel Agent\\", 948 | "externalID", 949 | "FireEye", 950 | "Cylance\\", 951 | "Cylance0", 952 | "Cylance1", 953 | "Cylance2", 954 | "CrowdStrike\\", 955 | "%SYSTEMROOT%\\system32\\drivers\\crowdstrike\\CsDeviceControl.inf", 956 | "%SYSTEMROOT%\\system32\\drivers\\crowdstrike\\CsFirmwareAnalysis.inf", 957 | "Mcafee\\", 958 | "McAfeeAgent\\", 959 | "APPolicyName", 960 | "EPPolicyName", 961 | "OASPolicyName", 962 | "Symantec", 963 | "Symantec Endpoint Protection\\", 964 | "Windows Defender", 965 | "DpaDisabled", 966 | "DisableRealTimeMonitoring", 967 | "CarbonBlack\\", 968 | "CbDefense\\", 969 | "SensorVersion", 970 | } 971 | 972 | var RegistrySearchList = []string{ 973 | `reg query "HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters"`, 974 | `reg query "HKLM\HARDWARE\DESCRIPTION\System\BIOS"`, 975 | `reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall`, 976 | `reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System`, 977 | `reg query "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\LSA"`, 978 | `reg query "HKLM\Software\Policies\Microsoft\Windows\DeviceGuard"`, 979 | `reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Defender\Real-Time Protection"`, 980 | `reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Advanced Threat Protection\Status"`, 981 | `reg query HKLM\Software\McAfee\Endpoint\AV`, 982 | `reg query HKLM\Software\Symantec`, 983 | `reg query HKLM\Software\Cylance\Desktop`, 984 | `reg query HKLM\Software\CbDefense`, 985 | `reg query HKLM\Software\CrowdStrike\InfDb`, 986 | `reg query "HKLM\Software\Sentinel Labs"`, 987 | `reg query "HKLM\Software\Sentinel Labs\Agent"`, 988 | } 989 | 990 | //encoder 991 | // for _, index := range EdrList { 992 | // input := []byte(index) 993 | // encoded := hex.EncodeToString(xorObf(input, key)) 994 | // ObfEdrList = append(ObfEdrList, fmt.Sprintf("\"%s\",\n", encoded)) 995 | -------------------------------------------------------------------------------- /pkg/edrRecon/filechecker_windows.go: -------------------------------------------------------------------------------- 1 | package edrRecon 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strings" 7 | 8 | "github.com/bi-zone/go-fileversion" 9 | "github.com/fourcorelabs/edrhunt/pkg/resources" 10 | ) 11 | 12 | var ( 13 | file fileversion.Info 14 | ) 15 | 16 | // GetFileMetaData retuns the metadata of a file at filepath from the windows version information resources using the go-fileversion library. 17 | // TODO: crashes at line 334 sometimes. 18 | func GetFileMetaData(filepath string) (resources.FileMetaData, error) { 19 | defer func() { 20 | if r := recover(); r != nil { 21 | return 22 | } 23 | }() 24 | 25 | var err error 26 | 27 | filepath = strings.Replace(filepath, "\"", "", -1) 28 | 29 | if filepath == "" { 30 | return resources.FileMetaData{}, errors.New("empty filepath") 31 | } 32 | 33 | file, err = fileversion.New(filepath) 34 | if err != nil { 35 | if strings.HasPrefix(filepath, `c:\windows\system32\`) { 36 | filepathMod := strings.Replace(filepath, `c\windows\system32`, `c:\Windows\Sysnative`, -1) 37 | file, err = fileversion.New(filepathMod) 38 | if err != nil { 39 | return resources.FileMetaData{}, fmt.Errorf("cannot find resource: %s", filepath) 40 | } 41 | } 42 | } 43 | 44 | // fileInfoStr := fmt.Sprintf("\n\tProductName: %s\n\tOriginalFileName: %s\n\tInternalFileName: %s\n\tCompany Name: %s\n\tFileDescription: %s\n\tProductVersion: %s\n\tComments: %s\n\tLegalCopyright: %s\n\tLegalTrademarks: %s", file.ProductName(), file.OriginalFilename(), file.InternalName(), file.CompanyName(), file.FileDescription(), file.ProductVersion(), file.Comments(), file.LegalCopyright(), file.LegalTrademarks()) 45 | 46 | return resources.FileMetaData{ 47 | ProductName: file.ProductName(), 48 | OriginalFilename: file.OriginalFilename(), 49 | InternalFileName: file.InternalName(), 50 | CompanyName: file.CompanyName(), 51 | FileDescription: file.FileDescription(), 52 | ProductVersion: file.ProductVersion(), 53 | Comments: file.Comments(), 54 | LegalCopyright: file.LegalCopyright(), 55 | LegalTrademarks: file.LegalTrademarks(), 56 | }, nil 57 | } 58 | 59 | func FileMetaDataParser(file resources.FileMetaData) string { 60 | if file.ProductName == "" { 61 | return "" 62 | } 63 | return fmt.Sprintf("\n\tProductName: %s\n\tOriginalFileName: %s\n\tInternalFileName: %s\n\tCompany Name: %s\n\tFileDescription: %s\n\tProductVersion: %s\n\tComments: %s\n\tLegalCopyright: %s\n\tLegalTrademarks: %s", file.ProductName, file.OriginalFilename, file.InternalFileName, file.CompanyName, file.FileDescription, file.ProductVersion, file.Comments, file.LegalCopyright, file.LegalTrademarks) 64 | } 65 | -------------------------------------------------------------------------------- /pkg/edrRecon/privilege.go: -------------------------------------------------------------------------------- 1 | package edrRecon 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | // CheckIfAdmin checks if the process has administrator privileges by trying to open the PHYSICALDRIVE0 (C:\\) raw device on Windows. 8 | func CheckIfAdmin() bool { 9 | f, err := os.Open("\\\\.\\PHYSICALDRIVE0") 10 | if err != nil { 11 | return false 12 | } 13 | f.Close() 14 | return true 15 | } 16 | 17 | // func ElevateAdmin() error { 18 | // verb := "runas" 19 | // exe, _ := os.Executable() 20 | // cwd, _ := os.Getwd() 21 | // args := strings.Join(os.Args[1:], " ") 22 | 23 | // verbPtr, _ := syscall.UTF16PtrFromString(verb) 24 | // exePtr, _ := syscall.UTF16PtrFromString(exe) 25 | // cwdPtr, _ := syscall.UTF16PtrFromString(cwd) 26 | // argPtr, _ := syscall.UTF16PtrFromString(args) 27 | 28 | // var showCmd int32 = 1 //SW_NORMAL 29 | 30 | // if err := windows.ShellExecute(0, verbPtr, exePtr, argPtr, cwdPtr, showCmd); err != nil { 31 | // return err 32 | // } 33 | 34 | // return nil 35 | // } 36 | -------------------------------------------------------------------------------- /pkg/edrRecon/process_windows.go: -------------------------------------------------------------------------------- 1 | package edrRecon 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/fourcorelabs/edrhunt/pkg/resources" 8 | "github.com/hashicorp/go-multierror" 9 | "github.com/yusufpapurcu/wmi" 10 | ) 11 | 12 | type Win32_Process struct { 13 | Name string 14 | ExecutablePath string 15 | Description string 16 | Caption string 17 | CommandLine string 18 | ProcessId uint32 19 | ParentProcessId uint32 20 | 21 | // Status string 22 | // StartMode string 23 | } 24 | 25 | // CheckProcesses returns a list of processes matching any suspicious running process names present in edrdata.go. 26 | func CheckProcesses() ([]resources.ProcessMetaData, error) { 27 | var ( 28 | processList []Win32_Process 29 | multiErr error 30 | summary []resources.ProcessMetaData = make([]resources.ProcessMetaData, 0) 31 | ) 32 | 33 | query := wmi.CreateQuery(&processList, "") 34 | 35 | if err := wmi.Query(query, &processList); err != nil { 36 | return summary, err 37 | } 38 | 39 | for _, process := range processList { 40 | if process.Name == "" { 41 | continue 42 | } 43 | 44 | output, err := AnalyzeProcess(process) 45 | if err != nil { 46 | multiErr = multierror.Append(multiErr, err) 47 | continue 48 | } 49 | 50 | if len(output.ScanMatch) > 0 { 51 | summary = append(summary, output) 52 | } 53 | } 54 | 55 | return summary, multiErr 56 | } 57 | 58 | func AnalyzeProcess(process Win32_Process) (resources.ProcessMetaData, error) { 59 | analysis := resources.ProcessMetaData{ 60 | ProcessName: process.Name, 61 | ProcessPath: process.ExecutablePath, 62 | ProcessDescription: process.Description, 63 | ProcessCaption: process.Caption, 64 | ProcessCmdLine: process.CommandLine, 65 | ProcessPID: fmt.Sprint(process.ProcessId), 66 | ProcessParentPID: fmt.Sprint(process.ParentProcessId), 67 | } 68 | 69 | if analysis.ProcessPath != "" { 70 | analysis.ProcessExeMetaData, _ = GetFileMetaData(analysis.ProcessPath) 71 | } 72 | 73 | for _, edr := range EdrList { 74 | if strings.Contains( 75 | strings.ToLower(fmt.Sprint(analysis)), 76 | strings.ToLower(edr)) { 77 | analysis.ScanMatch = append(analysis.ScanMatch, edr) 78 | } 79 | } 80 | 81 | return analysis, nil 82 | } 83 | -------------------------------------------------------------------------------- /pkg/edrRecon/registry.go: -------------------------------------------------------------------------------- 1 | package edrRecon 2 | 3 | import ( 4 | "context" 5 | "os/exec" 6 | "strings" 7 | "sync" 8 | "syscall" 9 | 10 | "github.com/fourcorelabs/edrhunt/pkg/resources" 11 | ) 12 | 13 | var ( 14 | outputLock sync.Mutex 15 | paramWg sync.WaitGroup 16 | output []string 17 | ) 18 | 19 | func runCMDCommand(ctx context.Context, command string) ([]byte, error) { 20 | params := []string{"/c", command} 21 | cmd, err := makeCmd(ctx, params...) 22 | if err != nil { 23 | return nil, err 24 | } 25 | return cmd.CombinedOutput() 26 | } 27 | 28 | func makeCmd(ctx context.Context, param ...string) (*exec.Cmd, error) { 29 | path, err := exec.LookPath("cmd") 30 | if err != nil { 31 | return nil, err 32 | } 33 | var cmdline string 34 | for _, s := range param { 35 | cmdline += s + " " 36 | } 37 | cmdline = strings.TrimSpace(cmdline) 38 | cmd := exec.CommandContext(ctx, path) 39 | cmd.SysProcAttr = &syscall.SysProcAttr{CmdLine: cmdline} 40 | return cmd, nil 41 | } 42 | 43 | func EnumRegistry(ctx context.Context) []string { 44 | for _, x := range RegistrySearchList { 45 | paramWg.Add(1) 46 | 47 | go func(args string) { 48 | defer paramWg.Done() 49 | 50 | stdout, err := runCMDCommand(ctx, args) 51 | if err != nil { 52 | return 53 | } 54 | 55 | outputLock.Lock() 56 | defer outputLock.Unlock() 57 | 58 | if len(stdout) != 0 { 59 | output = append(output, string(stdout)) 60 | } 61 | }(x) 62 | } 63 | 64 | paramWg.Wait() 65 | return output 66 | } 67 | 68 | func CheckRegistry(ctx context.Context) (resources.RegistryMetaData, error) { 69 | var analysis resources.RegistryMetaData = resources.RegistryMetaData{ScanMatch: make([]string, 0)} 70 | return analysis, nil 71 | 72 | // output := strings.Join(EnumRegistry(ctx), " ") 73 | // if output != "" { 74 | // processedOutput := strings.ToLower(output) 75 | // for _, match := range RegistryReconList { 76 | // if strings.Contains( 77 | // processedOutput, 78 | // strings.ToLower(match)) { 79 | // analysis.ScanMatch = append(analysis.ScanMatch, match) 80 | // } 81 | // } 82 | // } 83 | 84 | // if len(analysis.ScanMatch) == 0 { 85 | // return analysis, fmt.Errorf("nothing found in registry") 86 | // } 87 | 88 | // return analysis, nil 89 | } 90 | -------------------------------------------------------------------------------- /pkg/edrRecon/services_windows.go: -------------------------------------------------------------------------------- 1 | package edrRecon 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/fourcorelabs/edrhunt/pkg/resources" 8 | "github.com/hashicorp/go-multierror" 9 | "github.com/yusufpapurcu/wmi" 10 | ) 11 | 12 | type Win32_Service struct { 13 | Name string 14 | DisplayName string 15 | Description string 16 | Caption string 17 | PathName string 18 | State string 19 | ProcessId uint32 20 | // Status string 21 | // StartMode string 22 | } 23 | 24 | // CheckServices return a list of installed services matching any suspicious service names present in edrdata.go. 25 | func CheckServices() ([]resources.ServiceMetaData, error) { 26 | var ( 27 | serviceList []Win32_Service 28 | multiErr error 29 | summary []resources.ServiceMetaData 30 | ) 31 | 32 | query := wmi.CreateQuery(&serviceList, "") 33 | 34 | if err := wmi.Query(query, &serviceList); err != nil { 35 | return summary, err 36 | } 37 | 38 | for _, service := range serviceList { 39 | if service.Name == "" { 40 | continue 41 | } 42 | 43 | output, err := AnalyzeService(service) 44 | if err != nil { 45 | multiErr = multierror.Append(multiErr, err) 46 | } 47 | 48 | if len(output.ScanMatch) > 0 { 49 | summary = append(summary, output) 50 | } 51 | } 52 | 53 | return summary, multiErr 54 | } 55 | 56 | func AnalyzeService(service Win32_Service) (resources.ServiceMetaData, error) { 57 | analysis := resources.ServiceMetaData{ 58 | ServiceName: service.Name, 59 | ServiceDisplayName: service.DisplayName, 60 | ServiceDescription: service.Description, 61 | ServiceCaption: service.Caption, 62 | ServicePathName: service.PathName, 63 | ServiceState: service.State, 64 | ServiceProcessId: fmt.Sprint(service.ProcessId), 65 | } 66 | 67 | if analysis.ServicePathName != "" { 68 | trim := strings.Index(analysis.ServicePathName, ".exe") 69 | if trim > 0 { 70 | servicePath := analysis.ServicePathName[:trim] + ".exe" 71 | analysis.ServiceExeMetaData, _ = GetFileMetaData(servicePath) 72 | } 73 | } 74 | 75 | for _, edr := range EdrList { 76 | if strings.Contains( 77 | strings.ToLower(fmt.Sprint(analysis)), 78 | strings.ToLower(edr)) { 79 | analysis.ScanMatch = append(analysis.ScanMatch, edr) 80 | } 81 | } 82 | 83 | return analysis, nil 84 | } 85 | -------------------------------------------------------------------------------- /pkg/edrRecon/wmi_windows.go: -------------------------------------------------------------------------------- 1 | package edrRecon 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strings" 7 | "time" 8 | 9 | "github.com/fourcorelabs/edrhunt/pkg/resources" 10 | "github.com/hashicorp/go-multierror" 11 | "github.com/yusufpapurcu/wmi" 12 | ) 13 | 14 | type AntiVirusProduct struct { 15 | DisplayName string 16 | InstanceGuid string 17 | PathToSignedProductExe string 18 | PathToSignedReportingExe string 19 | ProductState uint32 20 | } 21 | 22 | type AvResult struct { 23 | AvProduct []AntiVirusProduct 24 | Err error 25 | } 26 | 27 | const ( 28 | namespace = "root\\SecurityCenter2" 29 | class = "AntiVirusProduct" 30 | wmiErr = "wmi query timed out" 31 | ) 32 | 33 | func CheckAVWmiRepo() ([]resources.AVWmiMetaData, error) { 34 | var ( 35 | avList []AntiVirusProduct 36 | multiErr error 37 | summary []resources.AVWmiMetaData = make([]resources.AVWmiMetaData, 0) 38 | err error 39 | ) 40 | 41 | avList, err = GetAVwithWMI() 42 | if err != nil { 43 | return summary, err 44 | } 45 | for _, av := range avList { 46 | if av.DisplayName == "" { 47 | continue 48 | } 49 | output, err := AnalyzeAVProduct(av) 50 | if err != nil { 51 | multiErr = multierror.Append(multiErr, err) 52 | continue 53 | } 54 | 55 | if len(output.ScanMatch) > 0 { 56 | summary = append(summary, output) 57 | } 58 | 59 | } 60 | return summary, multiErr 61 | } 62 | 63 | func AnalyzeAVProduct(av AntiVirusProduct) (resources.AVWmiMetaData, error) { 64 | analysis := resources.AVWmiMetaData{ 65 | ProductName: av.DisplayName, 66 | ProductGUID: av.InstanceGuid, 67 | PathToProductExe: av.PathToSignedProductExe, 68 | PathToReportingExe: av.PathToSignedReportingExe, 69 | ProductState: av.ProductState, 70 | } 71 | 72 | if analysis.PathToProductExe != "" { 73 | analysis.ProductExeMetaData, _ = GetFileMetaData(analysis.PathToProductExe) 74 | } 75 | 76 | if analysis.PathToReportingExe != "" { 77 | analysis.ReportingExeMetaData, _ = GetFileMetaData(analysis.PathToReportingExe) 78 | } 79 | 80 | for _, edr := range EdrList { 81 | if strings.Contains( 82 | strings.ToLower(fmt.Sprint(analysis)), 83 | strings.ToLower(edr)) { 84 | analysis.ScanMatch = append(analysis.ScanMatch, edr) 85 | } 86 | } 87 | 88 | return analysis, nil 89 | } 90 | 91 | func GetAVwithWMI() ([]AntiVirusProduct, error) { 92 | result := make(chan AvResult, 1) 93 | go func() { 94 | result <- WMIQuery() 95 | }() 96 | select { 97 | case <-time.After(6 * time.Second): 98 | return nil, errors.New(wmiErr) 99 | case result := <-result: 100 | return result.AvProduct, result.Err 101 | } 102 | 103 | } 104 | 105 | func WMIQuery() AvResult { 106 | var avResults []AntiVirusProduct 107 | query := wmi.CreateQuery(&avResults, "", class) 108 | err := wmi.QueryNamespace(query, &avResults, namespace) 109 | return AvResult{ 110 | AvProduct: avResults, 111 | Err: err, 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /pkg/resources/edrRecon.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | type Recon interface { 4 | CheckProcesses() ([]ProcessMetaData, error) 5 | CheckServices() ([]ServiceMetaData, error) 6 | CheckDrivers() ([]DriverMetaData, error) 7 | CheckRegistry() (RegistryMetaData, error) 8 | CheckAVWmiRepo() ([]AVWmiMetaData, error) 9 | CheckDirectory() (string, error) 10 | } 11 | 12 | type FileMetaData struct { 13 | ProductName string 14 | OriginalFilename string 15 | InternalFileName string 16 | CompanyName string 17 | FileDescription string 18 | ProductVersion string 19 | Comments string 20 | LegalCopyright string 21 | LegalTrademarks string 22 | } 23 | 24 | type ServiceMetaData struct { 25 | ServiceName string 26 | ServiceDisplayName string 27 | ServiceDescription string 28 | ServiceCaption string 29 | ServicePathName string 30 | ServiceState string 31 | ServiceProcessId string 32 | ServiceExeMetaData FileMetaData 33 | ScanMatch []string 34 | } 35 | 36 | type AVWmiMetaData struct { 37 | ProductName string 38 | ProductGUID string 39 | PathToProductExe string 40 | ProductExeMetaData FileMetaData 41 | PathToReportingExe string 42 | ReportingExeMetaData FileMetaData 43 | ProductState uint32 44 | ScanMatch []string 45 | } 46 | 47 | type ProcessMetaData struct { 48 | ProcessName string 49 | ProcessPath string 50 | ProcessDescription string 51 | ProcessCaption string 52 | ProcessCmdLine string 53 | ProcessPID string 54 | ProcessParentPID string 55 | ProcessExeMetaData FileMetaData 56 | ScanMatch []string 57 | } 58 | 59 | type DriverMetaData struct { 60 | DriverBaseName string 61 | DriverSysMetaData FileMetaData 62 | DriverFilePath string 63 | ScanMatch []string 64 | } 65 | 66 | type RegistryMetaData struct { 67 | ScanMatch []string 68 | } 69 | -------------------------------------------------------------------------------- /pkg/resources/scan_edr.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | type EDRDetection interface { 4 | Detect(data SystemData) (EDRType, bool) 5 | Name() string 6 | Type() EDRType 7 | } 8 | 9 | type EDRType string 10 | 11 | var ( 12 | WinDefenderEDR EDRType = "defender" 13 | KaskperskyEDR EDRType = "kaspersky" 14 | CrowdstrikeEDR EDRType = "crowdstrike" 15 | McafeeEDR EDRType = "mcafee" 16 | SymantecEDR EDRType = "symantec" 17 | CylanceEDR EDRType = "cylance" 18 | CarbonBlackEDR EDRType = "carbon_black" 19 | SentinelOneEDR EDRType = "sentinel_one" 20 | FireEyeEDR EDRType = "fireeye" 21 | ElasticAgentEDR EDRType = "elastic_agent" 22 | QualysEDR EDRType = "qualys" 23 | TrendMicroEDR EDRType = "trend_micro" 24 | ESETEDR EDRType = "eset" 25 | CybereasonEDR EDRType = "cybereason" 26 | BitDefenderEDR EDRType = "bitdefender" 27 | CheckPointEDR EDRType = "checkpoint" 28 | CynetEDR EDRType = "cynet" 29 | DeepInstinctEDR EDRType = "deepinstinct" 30 | SophosEDR EDRType = "sophos" 31 | FortinetEDR EDRType = "fortinet" 32 | MalwareBytesEDR EDRType = "malwarebytes" 33 | LimacharlieEDR EDRType = "limacharlie" 34 | HarfangLabEDR EDRType = "harfanglab" 35 | ) 36 | -------------------------------------------------------------------------------- /pkg/resources/systemdata.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "github.com/fourcorelabs/edrhunt/pkg/util" 5 | ) 6 | 7 | type SystemData struct { 8 | Processes []ProcessMetaData 9 | Registry RegistryMetaData 10 | Services []ServiceMetaData 11 | Drivers []DriverMetaData 12 | AVProviders []AVWmiMetaData 13 | } 14 | 15 | // CountMatchesAll collects all the scanned matches of suspicious names and checks for passed keywords in the matches. 16 | func (s *SystemData) CountMatchesAll(keywords ...[]string) (int, bool) { 17 | var match bool 18 | var count int 19 | 20 | scanMatchList := make([]string, 0) 21 | 22 | for _, v := range s.Processes { 23 | scanMatchList = append(scanMatchList, v.ScanMatch...) 24 | } 25 | 26 | for _, v := range s.Services { 27 | scanMatchList = append(scanMatchList, v.ScanMatch...) 28 | } 29 | 30 | for _, v := range s.Drivers { 31 | scanMatchList = append(scanMatchList, v.ScanMatch...) 32 | } 33 | 34 | for _, v := range s.AVProviders { 35 | scanMatchList = append(scanMatchList, v.ScanMatch...) 36 | } 37 | 38 | scanMatchList = append(scanMatchList, s.Registry.ScanMatch...) 39 | 40 | var totalLen int 41 | for _, v := range keywords { 42 | totalLen += len(v) 43 | } 44 | keywordList := make([]string, 0, totalLen) 45 | 46 | for _, v := range keywords { 47 | keywordList = append(keywordList, v...) 48 | } 49 | 50 | for _, v := range keywordList { 51 | contains := util.StrSliceContains(scanMatchList, v) 52 | if contains { 53 | match = true 54 | count++ 55 | } 56 | } 57 | 58 | return count, match 59 | } 60 | -------------------------------------------------------------------------------- /pkg/scanners/scan_bitdefender.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type BitDefenderDetection struct{} 6 | 7 | func (w *BitDefenderDetection) Name() string { 8 | return "BitDefender" 9 | } 10 | 11 | func (w *BitDefenderDetection) Type() resources.EDRType { 12 | return resources.BitDefenderEDR 13 | } 14 | 15 | var BitDefenderHeuristic = []string{ 16 | "BitDefender", 17 | "bdagent.exe", 18 | "AntiphishingAgent.dll", 19 | "bdcloud.dll", 20 | "bdmltusrsrv.dll", 21 | "bdnc.dll", 22 | "bdfndisf6.sys", 23 | "bdfwcore.dll", 24 | "bdfwfpf.sys", 25 | "bdpredir.dll", 26 | "bdquar.dll", 27 | "avc3.sys", 28 | "avckf.sys", 29 | "alertvs10u.http.dll", 30 | "amvs10u.http.dll", 31 | "aphvs10u.http.dll", 32 | "bdch.dll", 33 | "bdchsubmit.dll", 34 | "BdFirewallSDK.dll", 35 | "bdreinit.exe", 36 | "bdpredir_ssl.dl", 37 | "pdscan.exe", 38 | "pdiface.exe", 39 | "pdiface.exe", 40 | "bdnc.dll", 41 | "BDSubmit.dll", 42 | "BDSubWiz.exe", 43 | "bdch.dll", 44 | "bdec.dll", 45 | "bdreinit.exe", 46 | } 47 | 48 | func (w *BitDefenderDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 49 | _, ok := data.CountMatchesAll(BitDefenderHeuristic) 50 | if !ok { 51 | return "", false 52 | } 53 | 54 | return resources.BitDefenderEDR, true 55 | } 56 | -------------------------------------------------------------------------------- /pkg/scanners/scan_carbonblack.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type CarbonBlackDetection struct{} 6 | 7 | func (w *CarbonBlackDetection) Name() string { 8 | return "Carbon Black" 9 | } 10 | 11 | func (w *CarbonBlackDetection) Type() resources.EDRType { 12 | return resources.CarbonBlackEDR 13 | } 14 | 15 | var CarbonBlackHeuristic = []string{ 16 | "CarbonBlack\\", 17 | "CbDefense\\", 18 | "CarbonBlackClientSetup.exe", 19 | } 20 | 21 | func (w *CarbonBlackDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 22 | _, ok := data.CountMatchesAll(CarbonBlackHeuristic) 23 | if !ok { 24 | return "", false 25 | } 26 | 27 | return resources.CarbonBlackEDR, true 28 | } 29 | -------------------------------------------------------------------------------- /pkg/scanners/scan_checkpoint.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type CheckPointDetection struct{} 6 | 7 | func (w *CheckPointDetection) Name() string { 8 | return "Carbon Black" 9 | } 10 | 11 | func (w *CheckPointDetection) Type() resources.EDRType { 12 | return resources.CheckPointEDR 13 | } 14 | 15 | var CheckPointHeuristic = []string{ 16 | "Checkpoint", 17 | "tracsrvwrapper.exe", 18 | "TrGUI.exe", 19 | "TracCAPI.exe", 20 | "dtplat.dll", 21 | "epcgina.dll", 22 | "epcgina_user64.dll", 23 | "LogonISReg.dll", 24 | "OsMonitor.dll", 25 | "ProcessMonitor.dll", 26 | "proxystub.dll", 27 | "ScriptRun.dll", 28 | "SCVMonitor.dll", 29 | "scvprod_lang_pack.dll", 30 | "SCUIAPI.dll", 31 | "cpmsi_tool.exe", 32 | "DataStruct.dll", 33 | "FileHash_DYN.dll", 34 | "TrAPI.dll", 35 | "vna_coinstall.dll - vna", 36 | "vna_install64.exe", 37 | "vna_utils.exe", 38 | "TracSrvWrapper.exe", 39 | "TrGUI.exe", 40 | "TracSrvWrapper.exe", 41 | "TrueVector", 42 | "p95tray.exe", 43 | } 44 | 45 | func (w *CheckPointDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 46 | _, ok := data.CountMatchesAll(CheckPointHeuristic) 47 | if !ok { 48 | return "", false 49 | } 50 | 51 | return resources.CheckPointEDR, true 52 | } 53 | -------------------------------------------------------------------------------- /pkg/scanners/scan_crowdstrike.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type CrowdstrikeDetection struct{} 6 | 7 | func (w *CrowdstrikeDetection) Name() string { 8 | return "Crowdstrike EDR Solution" 9 | } 10 | 11 | func (w *CrowdstrikeDetection) Type() resources.EDRType { 12 | return resources.CrowdstrikeEDR 13 | } 14 | 15 | var CrowdstrikeHeuristic = []string{ 16 | "CrowdStrike", 17 | "%SYSTEMROOT%\\system32\\drivers\\crowdstrike\\CsDeviceControl.inf", 18 | "%SYSTEMROOT%\\system32\\drivers\\crowdstrike\\CsFirmwareAnalysis.inf", 19 | "windowssensor.x64.exe", 20 | "C:\\Windows\\System32\\drivers\\crowdstrike", 21 | "csagent.sys", 22 | "csim.sys", 23 | "csimn.sys", 24 | "csimu.sys", 25 | } 26 | 27 | func (w *CrowdstrikeDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 28 | _, ok := data.CountMatchesAll(CrowdstrikeHeuristic) 29 | if !ok { 30 | return "", false 31 | } 32 | 33 | return resources.CrowdstrikeEDR, true 34 | } 35 | -------------------------------------------------------------------------------- /pkg/scanners/scan_cybereason.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type CybereasonDetection struct{} 6 | 7 | func (w *CybereasonDetection) Name() string { 8 | return "Cybereason" 9 | } 10 | 11 | func (w *CybereasonDetection) Type() resources.EDRType { 12 | return resources.CybereasonEDR 13 | } 14 | 15 | var CybereasonHeuristic = []string{ 16 | "CybereasonRansomFreeServiceHost.exe", 17 | "Cybereason", 18 | "Cybereason ActiveProbe\\", 19 | "CrAmTray.exe", 20 | "Cybereason", 21 | "crsdll.dll", 22 | "CoreMinion.dll", 23 | "CoreMinion", 24 | "minionhost.exe", 25 | "Cybereason Sensor", 26 | "CybereasonSensor.exe", 27 | } 28 | 29 | func (w *CybereasonDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 30 | _, ok := data.CountMatchesAll(CybereasonHeuristic) 31 | if !ok { 32 | return "", false 33 | } 34 | 35 | return resources.CybereasonEDR, true 36 | } 37 | -------------------------------------------------------------------------------- /pkg/scanners/scan_cylance.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type CylanceDetection struct{} 6 | 7 | func (w *CylanceDetection) Name() string { 8 | return "Cylance Smart Antivirus" 9 | } 10 | 11 | func (w *CylanceDetection) Type() resources.EDRType { 12 | return resources.CylanceEDR 13 | } 14 | 15 | var CylanceHeuristic = []string{ 16 | "Cylance", 17 | "CylanceProtectSetup.exe", 18 | "cylancesvc.exe", 19 | "CylanceUI.exe", 20 | "CylanceProtect", 21 | "CylanceProtectSetup.exe", 22 | "cylance.updatemgr.interfaces.dll", 23 | "cylancesvc.exe", 24 | "cylance.host.updater.dll", 25 | "cylance.host.versions.dll", 26 | "cylance.host.analysis.dll", 27 | "cylance.host.ccui.interfaces.dll", 28 | "cylance.host.commandcontrolui.dll", 29 | "cylance.host.controller.dll", 30 | "cylance.host.cylancevenue.dll", 31 | "cylance.host.infinitymodel.dll", 32 | "cylance.host.windowseventlogwriter.dll", 33 | "cylance.interfaces.dll", 34 | "cymemdef.dll", 35 | "cyprotectdrv64.sys", 36 | "cyupdate.exe", 37 | "cyhelper64.dl", 38 | "cylanceui.exe", 39 | "cymemdef64.dll", 40 | "cylance.host.cylancevenuemodule.dll", 41 | "cylance.host.memdefps_gac.dll", 42 | "cylance.host.systeminformation.dll", 43 | "cymemdefps.dll", 44 | "cymemdefps64.dll", 45 | "cylance.host.wmiprovider_gac.dll", 46 | "cylance.host.infinitymodelole.dll", 47 | "cylance.host.infinitymodelpdf.dll", 48 | } 49 | 50 | func (w *CylanceDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 51 | _, ok := data.CountMatchesAll(CylanceHeuristic) 52 | if !ok { 53 | return "", false 54 | } 55 | 56 | return resources.CylanceEDR, true 57 | } 58 | -------------------------------------------------------------------------------- /pkg/scanners/scan_cynet.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type CynetDetection struct{} 6 | 7 | func (w *CynetDetection) Name() string { 8 | return "Cynet" 9 | } 10 | 11 | func (w *CynetDetection) Type() resources.EDRType { 12 | return resources.CynetEDR 13 | } 14 | 15 | var CynetHeuristic = []string{ 16 | "Cynet", 17 | "Cyops", 18 | "Cynet EPS", 19 | } 20 | 21 | func (w *CynetDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 22 | _, ok := data.CountMatchesAll(CynetHeuristic) 23 | if !ok { 24 | return "", false 25 | } 26 | 27 | return resources.CynetEDR, true 28 | } 29 | -------------------------------------------------------------------------------- /pkg/scanners/scan_deepinstinct.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type DeepInstictDetection struct{} 6 | 7 | func (w *DeepInstictDetection) Name() string { 8 | return "Deep Instinct Security" 9 | } 10 | 11 | func (w *DeepInstictDetection) Type() resources.EDRType { 12 | return resources.DeepInstinctEDR 13 | } 14 | 15 | var DeepInstinctHeuristic = []string{ 16 | "DeepInstinct", 17 | "Deep Instinct Agent", 18 | "Deep Instinct Prevention Platform", 19 | "HKEY_LOCAL_MACHINE\\SOFTWARE\\Deep Instinct", 20 | } 21 | 22 | func (w *DeepInstictDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 23 | _, ok := data.CountMatchesAll(DeepInstinctHeuristic) 24 | if !ok { 25 | return "", false 26 | } 27 | 28 | return resources.DeepInstinctEDR, true 29 | } 30 | -------------------------------------------------------------------------------- /pkg/scanners/scan_elastic.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type ElasticAgentDetection struct{} 6 | 7 | func (w *ElasticAgentDetection) Name() string { 8 | return "Elastic Endpoint Security" 9 | } 10 | 11 | func (w *ElasticAgentDetection) Type() resources.EDRType { 12 | return resources.ElasticAgentEDR 13 | } 14 | 15 | var ElasticAgentHeuristic = []string{ 16 | "elastic-agent.exe", 17 | "elastic-endpoint.exe", 18 | "elastic-endpoint-driver", 19 | "ElasticEndpoint", 20 | } 21 | 22 | func (w *ElasticAgentDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 23 | _, ok := data.CountMatchesAll(ElasticAgentHeuristic) 24 | if !ok { 25 | return "", false 26 | } 27 | 28 | return resources.ElasticAgentEDR, true 29 | } 30 | -------------------------------------------------------------------------------- /pkg/scanners/scan_eset.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type ESETEDRDetection struct{} 6 | 7 | func (w *ESETEDRDetection) Name() string { 8 | return "ESET Endpoint Security" 9 | } 10 | 11 | func (w *ESETEDRDetection) Type() resources.EDRType { 12 | return resources.ESETEDR 13 | } 14 | 15 | var ESETHeuristic = []string{ 16 | "egui.exe", 17 | "ekrn.exe", 18 | "minodlogin.exe", 19 | "minodlogin", 20 | "emu-rep.exe", 21 | "emu_install.exe", 22 | "emu-cci.exe", 23 | "emu-gui.exe", 24 | "emu-uninstall.exe", 25 | "emu-gui.exe", 26 | "ESET MSP Utilities", 27 | "C:\\Program Files\\ESET\\ESET NOD32 Antivirus\\ecmd.exe", 28 | "eguiAmon.dll", 29 | "eguiDevmon.dll", 30 | "eguiDmon.dll", 31 | "eguiEmon.dll", 32 | "eguiEpfw.dll", 33 | "eguiHips.dll", 34 | "eguiMailPlugins.dll", 35 | "eguiParental.dll", 36 | "eguiProduct.dll", 37 | "eguiProductRcd.dll", 38 | "eguiScan.dll", 39 | "eguiSmon.dll", 40 | "eguiUpdate.dll", 41 | "EHttpSrv.exe", 42 | "eplgHooks.dll", 43 | "eplgOE.dll", 44 | "eclsLang.dll", 45 | "eguiAmonLang.dll", 46 | "eguiEpfwLang.dll", 47 | "eguiHipsLang.dll", 48 | "eguiLang.dll", 49 | "eguiOnlineHelp.dll", 50 | "eguiOnlineHelpLang.dll", 51 | "eguiScanLang.dll", 52 | "eguiSmonLang.dll", 53 | "eguiUpdateLang.dll", 54 | "eguiWebControl.dll", 55 | "ekrnDevmonLang.dll", 56 | "ekrnEpfwLang.dll", 57 | "ekrnHipsLang.dll", 58 | } 59 | 60 | func (w *ESETEDRDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 61 | _, ok := data.CountMatchesAll(ESETHeuristic) 62 | if !ok { 63 | return "", false 64 | } 65 | 66 | return resources.QualysEDR, true 67 | } 68 | -------------------------------------------------------------------------------- /pkg/scanners/scan_fireeye.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type FireEyeDetection struct{} 6 | 7 | func (w *FireEyeDetection) Name() string { 8 | return "FireEye" 9 | } 10 | 11 | func (w *FireEyeDetection) Type() resources.EDRType { 12 | return resources.FireEyeEDR 13 | } 14 | 15 | var FireEyeHeuristic = []string{ 16 | "FireEye", 17 | "C:\\Program Files\\FireEye\\xagt\\", 18 | "xagt.exe", 19 | } 20 | 21 | func (w *FireEyeDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 22 | _, ok := data.CountMatchesAll(FireEyeHeuristic) 23 | if !ok { 24 | return "", false 25 | } 26 | 27 | return resources.FireEyeEDR, true 28 | } 29 | -------------------------------------------------------------------------------- /pkg/scanners/scan_fortinet.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type FortinetDetection struct{} 6 | 7 | func (w *FortinetDetection) Name() string { 8 | return "Fortinet" 9 | } 10 | 11 | func (w *FortinetDetection) Type() resources.EDRType { 12 | return resources.FortinetEDR 13 | } 14 | 15 | var FortinetHeuristic = []string{ 16 | "Fortinet", 17 | "dcagent_amd64.dll", 18 | "FSAEConfig.exe", 19 | "fortilspheuristics.dll", 20 | "fccomintdll.dll", 21 | "fcoeam.dll", 22 | "fccomint.exe", 23 | "fclanguageselector.exe", 24 | "fortifw.exe", 25 | "fortitray.exe", 26 | "libcfg.dll", 27 | "fcappdb.exe", 28 | "fcoehook.dll", 29 | "fcwizard.exe", 30 | "fcresc.dll", 31 | "fortiwf.exe", 32 | "forticlish.dll", 33 | "fortiece.dll", 34 | "libavr.dll", 35 | "fortiwadbd.exe", 36 | "fcdblog.exe", 37 | "fortiwad.exe", 38 | "fortiproxy.exe", 39 | "fortiskin.dll", 40 | "fortiscand.exe", 41 | "fortivpnst.dll", 42 | "fortivpnst.exe", 43 | "fortivpnst64.dll", 44 | "fasle.dll", 45 | "fcwscd7.exe", 46 | "forticlient.exe", 47 | "forticlish.dll", 48 | "FortiClient Service Scheduler", 49 | "FortiClient.exe", 50 | "fortiwad.exe", 51 | "fortiproxy.exe", 52 | "FortiLSPHeuristics.dll", 53 | "npccpluginex.dll", 54 | "nptcplugin.dll", 55 | "npccplugin.dll", 56 | "FCCOMIntDLL.dll", 57 | "FCOEAM.dll", 58 | "FSSOMA.exe", 59 | "LaunchCacheClean.dll", 60 | "launchcacheclean64.dll", 61 | "FCCOMInt.exe", 62 | "FCVbltScan.exe", 63 | "sslvpnhostcheck.dll", 64 | "sslvpnhostcheck64.dll", 65 | "FortiESNAC.exe", 66 | "FortiTray.exe", 67 | "FCConfig.exe", 68 | "FCOEHook.dll", 69 | "FCResc.dll", 70 | "forticachecleaner.dll", 71 | "FortiCacheCleaner64.dll", 72 | "forticredentialprovider.dll", 73 | "FortiCredentialProvider2x64.dll", 74 | "forticredentialprovider64.dll", 75 | "FortiTrayResc.dll", 76 | "FortiWF.exe", 77 | "EPCUserAvatar.exe", 78 | "FortiAvatar.exe", 79 | "FortiCliSh.dll", 80 | "FortiCliSh64.dll", 81 | "fortifws.exe", 82 | "FortiWadbd.exe", 83 | "FortiClient_Diagnostic_Tool.exe", 84 | "forticontrol.dll", 85 | "FortiSSLVPNdaemon.exe", 86 | "FortiCliSh.dll", 87 | "FortiCliSh64.dll", 88 | "npccpluginex.dll", 89 | "nptcplugin.dll", 90 | "npccplugin.dll", 91 | "FortiClient Service Scheduler", 92 | "FortiESNAC.exe", 93 | "FortiWad.exe", 94 | "FortiProxy.exe", 95 | } 96 | 97 | func (w *FortinetDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 98 | _, ok := data.CountMatchesAll(FortinetHeuristic) 99 | if !ok { 100 | return "", false 101 | } 102 | 103 | return resources.FortinetEDR, true 104 | } 105 | -------------------------------------------------------------------------------- /pkg/scanners/scan_harfanglab.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type HarfangLabDetection struct{} 6 | 7 | func (w *HarfangLabDetection) Name() string { 8 | return "HarfangLab" 9 | } 10 | 11 | func (w *HarfangLabDetection) Type() resources.EDRType { 12 | return resources.HarfangLabEDR 13 | } 14 | 15 | var HarfangLabHeuristic = []string{ 16 | "HarfangLab\\", 17 | "C:\\Program Files\\HarfangLab", 18 | "C:\\Program Files\\HarfangLab\\drivers", 19 | "hurukai", 20 | "hurukai-av-update.dll", 21 | "hldevicecontrol.sys", 22 | "hurukai-av", 23 | "hurukai-ui", 24 | "hurukai-av.exe", 25 | "hurukai-ui.exe", 26 | "hurukai-av.dll", 27 | "hlelam.sys", 28 | "hlprotect.sys", 29 | } 30 | 31 | func (w *HarfangLabDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 32 | _, ok := data.CountMatchesAll(HarfangLabHeuristic) 33 | if !ok { 34 | return "", false 35 | } 36 | 37 | return resources.SentinelOneEDR, true 38 | } 39 | -------------------------------------------------------------------------------- /pkg/scanners/scan_kaspersky.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type KaskperskyDetection struct{} 6 | 7 | func (w *KaskperskyDetection) Name() string { 8 | return "Kaspersky Security" 9 | } 10 | 11 | func (w *KaskperskyDetection) Type() resources.EDRType { 12 | return resources.KaskperskyEDR 13 | } 14 | 15 | var KasperskyHeuristic = []string{ 16 | "kaspersky", 17 | "avpui.exe", 18 | "avpservice.dll", 19 | "avzkrnl.dll", 20 | "cf_anti_malware_facade.dll", 21 | "cf_facade.dll", 22 | "cf_mgmt_facade.dll", 23 | "cf_response_provider.dll", 24 | "ckahcomm.dll", 25 | "ckahrule.dll", 26 | "ckahum.dll", 27 | "eka_meta.dll", 28 | "kasperskylab.kis.ui.dll", 29 | "am_facade.dll", 30 | "am_meta.dll", 31 | "attestation_task.dll", 32 | "avs_eka.dll", 33 | "kasperskylab.ksde.ui.dll", 34 | "kasperskylab.ui.core.dll", 35 | "kasperskylab.ui.core.visuals.dll", 36 | "ksdeuimain.dll", 37 | "avpsus.exe", 38 | "klnagent.exe", 39 | "klnsacwsrv.exe", 40 | "klnagent.exe", 41 | "kl_platf.exe", 42 | "klnagwds.exe", 43 | } 44 | 45 | func (w *KaskperskyDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 46 | _, ok := data.CountMatchesAll(KasperskyHeuristic) 47 | if !ok { 48 | return "", false 49 | } 50 | 51 | return resources.KaskperskyEDR, true 52 | } 53 | -------------------------------------------------------------------------------- /pkg/scanners/scan_limacharlie.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type LimacharlieDetection struct{} 6 | 7 | func (w *LimacharlieDetection) Name() string { 8 | return "Limacharlie Agent" 9 | } 10 | 11 | func (w *LimacharlieDetection) Type() resources.EDRType { 12 | return resources.LimacharlieEDR 13 | } 14 | 15 | var LimacharlieHeuristic = []string{ 16 | "rphcp.exe", 17 | "lc_sensor.exe", 18 | "refractionPOINT HCP", 19 | "LimaCharlie", 20 | } 21 | 22 | func (w *LimacharlieDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 23 | _, ok := data.CountMatchesAll(LimacharlieHeuristic) 24 | if !ok { 25 | return "", false 26 | } 27 | 28 | return resources.DeepInstinctEDR, true 29 | } 30 | -------------------------------------------------------------------------------- /pkg/scanners/scan_malwarebytes.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type MalwareBytesDetection struct{} 6 | 7 | func (w *MalwareBytesDetection) Name() string { 8 | return "Malware Bytes" 9 | } 10 | 11 | func (w *MalwareBytesDetection) Type() resources.EDRType { 12 | return resources.MalwareBytesEDR 13 | } 14 | 15 | var MalwareBytesHeuristic = []string{ 16 | "MalwareBytes", 17 | "mbae.exe", 18 | "mbae64.dll", 19 | "mbae64.exe", 20 | "mbae-api.dll", 21 | "mbae-svc.exe", 22 | "mbae-uninstaller.exe", 23 | "mbae.sys", 24 | "mbae64.sys", 25 | "mbae-svc.exe", 26 | "Malwarebytes Anti-Exploit Service", 27 | "C:\\Program Files\\Malwarebytes Anti-Exploit\\mbae.exe", 28 | "mbae-loader.exe ", 29 | "mbaeLoader32.exe", 30 | "mbaeloader64.exe", 31 | "mbamcore.dll", 32 | "mbam-dor.exe", 33 | "mbamext.dll", 34 | "mbamgui.exe", 35 | "mbamnet.dll", 36 | "mbamservice.exe", 37 | "mbamtrayctrl.exe", 38 | "mbampt.exe", 39 | "mbamscheduler.exe", 40 | "C:\\Program Files\\Malwarebytes Anti-Rootkit", 41 | "mbar-1.08.2.1001.exe ", 42 | "mbeadomain.dll", 43 | "mbae-setup.exe", 44 | "MBAMHelper.exe", 45 | } 46 | 47 | func (w *MalwareBytesDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 48 | _, ok := data.CountMatchesAll(MalwareBytesHeuristic) 49 | if !ok { 50 | return "", false 51 | } 52 | 53 | return resources.MalwareBytesEDR, true 54 | } 55 | -------------------------------------------------------------------------------- /pkg/scanners/scan_mcafee.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type McafeeDetection struct{} 6 | 7 | func (w *McafeeDetection) Name() string { 8 | return "McAfee MVISION Endpoint Detection and Response" 9 | } 10 | 11 | func (w *McafeeDetection) Type() resources.EDRType { 12 | return resources.McafeeEDR 13 | } 14 | 15 | var McafeeHeuristic = []string{ 16 | "Mcafee\\", 17 | "mcupdate.exe", 18 | "McAfeeAgent\\", 19 | "APPolicyName", 20 | "EPPolicyName", 21 | "OASPolicyName", 22 | "ESConfigTool.exe", 23 | "FWInstCheck.exe", 24 | "FwWindowsFirewallHandler.exe", 25 | "mfeesp.exe", 26 | "mfefw.exe", 27 | "mfeProvisionModeUtility.exe", 28 | "mfetp.exe", 29 | "WscAVExe.exe", 30 | "mcshield.exe", 31 | "McChHost.exe", 32 | "mfewc.exe", 33 | "mfewch.exe", 34 | "mfewcui.exe", 35 | "mfecanary.exe", 36 | "mfefire.exe", 37 | "mfehidin.exe", 38 | "mfemms.exe", 39 | "mfevtps.exe", 40 | "MarSetup.exe", 41 | "masvc.exe", 42 | "macmnsvc.exe", 43 | "MfeServiceMgr.exe ", 44 | "McAPExe.exe", 45 | "McPvTray.exe", 46 | "mcuicnt.exe", 47 | "mcuihost.exe", 48 | "Mcshield.exe", 49 | "McpService.exe", 50 | "epefprtrainer.exe", 51 | "mfeffcoreservice.exe", 52 | "MfeEpeSvc.exe", 53 | } 54 | 55 | func (w *McafeeDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 56 | _, ok := data.CountMatchesAll(McafeeHeuristic) 57 | if !ok { 58 | return "", false 59 | } 60 | 61 | return resources.McafeeEDR, true 62 | } 63 | -------------------------------------------------------------------------------- /pkg/scanners/scan_qualys.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type QualysDetection struct{} 6 | 7 | func (w *QualysDetection) Name() string { 8 | return "Qualys Cloud Agent EDR" 9 | } 10 | 11 | func (w *QualysDetection) Type() resources.EDRType { 12 | return resources.QualysEDR 13 | } 14 | 15 | var QualysHeuristic = []string{ 16 | "Qualys", 17 | "qualysagent.exe", 18 | "QualysProxy.exe", 19 | "QualysAgentUI.exe", 20 | } 21 | 22 | func (w *QualysDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 23 | _, ok := data.CountMatchesAll(QualysHeuristic) 24 | if !ok { 25 | return "", false 26 | } 27 | 28 | return resources.QualysEDR, true 29 | } 30 | -------------------------------------------------------------------------------- /pkg/scanners/scan_sentinelone.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type SentinelOneDetection struct{} 6 | 7 | func (w *SentinelOneDetection) Name() string { 8 | return "SentinelOne" 9 | } 10 | 11 | func (w *SentinelOneDetection) Type() resources.EDRType { 12 | return resources.SentinelOneEDR 13 | } 14 | 15 | var SentinelOneHeuristic = []string{ 16 | "SentinelOne\\", 17 | "C:\\Program Files\\SentinelOne", 18 | "SentinelAgent", 19 | "SentinelMonitor", 20 | } 21 | 22 | func (w *SentinelOneDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 23 | _, ok := data.CountMatchesAll(SentinelOneHeuristic) 24 | if !ok { 25 | return "", false 26 | } 27 | 28 | return resources.SentinelOneEDR, true 29 | } 30 | -------------------------------------------------------------------------------- /pkg/scanners/scan_sophos.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type SophosDetection struct{} 6 | 7 | func (w *SophosDetection) Name() string { 8 | return "Sophos" 9 | } 10 | 11 | func (w *SophosDetection) Type() resources.EDRType { 12 | return resources.SophosEDR 13 | } 14 | 15 | var SophosHeuristic = []string{ 16 | "Sophos", 17 | "SVRTgui.exe", 18 | "SVRTcli.exe", 19 | "Sophos Virus Removal Tool install.exe", 20 | "SVRTcli.exe", 21 | "SVRTgui.exe", 22 | "SCTCleanupService.exe", 23 | "SVRTservice.exe", 24 | "osdp.dll", 25 | "SAVI.dll", 26 | "veex.dll", 27 | "rkdisk.dll", 28 | "SCTBootTasks.exe", 29 | "SUMService.exe", 30 | "SVRTservice.exe", 31 | "SCFService.exe", 32 | "SCFManager.exe", 33 | "SpaRmsAdapter.dll", 34 | "sargui.exe", 35 | "Sophos Computer Security Scan.exe", 36 | "sntpservice.exe", 37 | "SophosLinkIconHandler32.dll", 38 | "McsHeartbeat.exe", 39 | "SAVAdminService.exe", 40 | "conan.dll", 41 | "DCManagement.dll", 42 | "DesktopMessaging.dll", 43 | "DetectionFeedback.dll", 44 | "DeviceControlPlugin.dll", 45 | "DriveProcessor.dll", 46 | "EEConsumer.dll", 47 | "ForceUpdateAlongSideSGN.exe", 48 | "FSDecomposer.dll", 49 | "ICAdapter.dll", 50 | "ICManagement.dll", 51 | "ICProcessors.dll", 52 | "osdp.dll", 53 | "SavAdapter.dll", 54 | "SAVAdminService.exe", 55 | "SAVCleanupService.exe", 56 | "SAVControl.dll", 57 | "SAVI.dll", 58 | "SavMain.exe", 59 | "savmscm.dll", 60 | "SavNeutralRes.dll", 61 | "SavPlugin.dll", 62 | "SavProgress.exe", 63 | "SavProxy.exe", 64 | "SavRes.dll", 65 | "SavResChs.dll", 66 | "SavResCht.dll", 67 | "SavResDeu.dll", 68 | "SavResEng.dll", 69 | "SavResEsp.dll", 70 | "SavSecurity.dll", 71 | "SavService.exe", 72 | "SavShellExt.dll", 73 | "SavShellExtX64.dll", 74 | "bpaif.dll", 75 | "swc_service.exe", 76 | "swcadapter.dll", 77 | "swi_callout.sys", 78 | "swi_service.exe", 79 | "swc_service.exe", 80 | "swi_filter.exe", 81 | "SophosUpdate.exe", 82 | "ALMsg.dll", 83 | "ALUpdate.exe", 84 | "AUAdapter.dll", 85 | "ChannelUpdater.dll", 86 | "cidsync.dll", 87 | "config.dll", 88 | "crypto.dll", 89 | "EECustomActions.dll", 90 | "InstlMgr.dll", 91 | "ispsheet.dll", 92 | "SAUConfigDLL.dll", 93 | "SingleGUIPlugin.dll", 94 | "SophosAlert.exe", 95 | "swlocale.dll", 96 | "SavShellExt.dll", 97 | "SavShellExtX64.dll", 98 | "SavMain.exe", 99 | "SAVAdminService.exe", 100 | "SAVCleanupService.exe", 101 | "SavService.exe", 102 | } 103 | 104 | func (w *SophosDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 105 | _, ok := data.CountMatchesAll(SophosHeuristic) 106 | if !ok { 107 | return "", false 108 | } 109 | 110 | return resources.SophosEDR, true 111 | } 112 | -------------------------------------------------------------------------------- /pkg/scanners/scan_symantec.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type SymantecDetection struct{} 6 | 7 | func (w *SymantecDetection) Name() string { 8 | return "Symantec Endpoint Security" 9 | } 10 | 11 | func (w *SymantecDetection) Type() resources.EDRType { 12 | return resources.SymantecEDR 13 | } 14 | 15 | var SymantecHeuristic = []string{ 16 | "symantec", 17 | "symcorpu", 18 | "symefasi", 19 | "Symantec", 20 | "Norton 360", 21 | "AVSubmit.dll", 22 | "AVSvcPlg.dll", 23 | "NTPAlert.dll", 24 | "NTPFW.dll", 25 | "N360Downloader.exe", 26 | "bushell.dll", 27 | "InstWrap.exe", 28 | "symcorpui.exe", 29 | "isPwdSvc.exe", 30 | "ccsvchst.exe", 31 | "Symantec Endpoint Protection\\", 32 | } 33 | 34 | func (w *SymantecDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 35 | _, ok := data.CountMatchesAll(SymantecHeuristic) 36 | if !ok { 37 | return "", false 38 | } 39 | 40 | return resources.SymantecEDR, true 41 | } 42 | -------------------------------------------------------------------------------- /pkg/scanners/scan_trendmicro.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type TrendMicroDetection struct{} 6 | 7 | func (w *TrendMicroDetection) Name() string { 8 | return "Trend Micro Deep Security" 9 | } 10 | 11 | func (w *TrendMicroDetection) Type() resources.EDRType { 12 | return resources.TrendMicroEDR 13 | } 14 | 15 | var TrendMicroHeuristic = []string{ 16 | "Trend Micro", 17 | "pccntmon.exe", 18 | "AosUImanager.exe", 19 | "NTRTScan.exe", 20 | "tmaseng.dll", 21 | "TMAS_OL.exe", 22 | "TMAS_OLA.dll", 23 | "TMAS_OLImp.exe", 24 | "TMAS_OLShare.dll", 25 | "EMapiWpr.dll", 26 | "TMAS_OLSentry.exe", 27 | "ufnavi.exe", 28 | "Clnrbin.exe", 29 | "vizorhtmldialog.exe", 30 | "pwmConsole.exe", 31 | "PwmSvc.exe", 32 | "coreServiceShell.exe", 33 | "ds_agent.exe", 34 | "ufnavi.exe", 35 | "SfCtlCom.exe", 36 | } 37 | 38 | func (w *TrendMicroDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 39 | _, ok := data.CountMatchesAll(TrendMicroHeuristic) 40 | if !ok { 41 | return "", false 42 | } 43 | 44 | return resources.QualysEDR, true 45 | } 46 | -------------------------------------------------------------------------------- /pkg/scanners/scan_win_defender.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | type WinDefenderDetection struct{} 6 | 7 | func (w *WinDefenderDetection) Name() string { 8 | return "Windows Defender" 9 | } 10 | 11 | func (w *WinDefenderDetection) Type() resources.EDRType { 12 | return resources.WinDefenderEDR 13 | } 14 | 15 | var WinDefenderProcessHeuristic = []string{ 16 | "defender", 17 | "msmpeng", 18 | } 19 | 20 | var WinDefenderServicesHeuristic = []string{ 21 | "defender", 22 | "msmpeng", 23 | } 24 | 25 | var WinDefenderDriverHeuristic = []string{ 26 | "defender", 27 | } 28 | 29 | var WinDefenderRegistryHeuristic = []string{ 30 | "Windows Defender", 31 | } 32 | 33 | // Detect returnns EDRType `defender` 34 | // If 35 | // - processes list contains WinDefenderProcessHeuristic keywords 36 | // - services list contains WinDefenderServicesHeuristic keywords 37 | // - registry list contains WinDefenderRegistryHeuristic keywords 38 | // - driver list contains WinDefenderDriverHeuristic keywords 39 | func (w *WinDefenderDetection) Detect(data resources.SystemData) (resources.EDRType, bool) { 40 | _, ok := data.CountMatchesAll(WinDefenderDriverHeuristic, WinDefenderProcessHeuristic, WinDefenderRegistryHeuristic, WinDefenderServicesHeuristic) 41 | if !ok { 42 | return "", false 43 | } 44 | 45 | return resources.WinDefenderEDR, true 46 | } 47 | -------------------------------------------------------------------------------- /pkg/scanners/scanner.go: -------------------------------------------------------------------------------- 1 | package scanners 2 | 3 | import "github.com/fourcorelabs/edrhunt/pkg/resources" 4 | 5 | var ( 6 | Scanners = []resources.EDRDetection{ 7 | &CarbonBlackDetection{}, 8 | &CrowdstrikeDetection{}, 9 | &CylanceDetection{}, 10 | &FireEyeDetection{}, 11 | &HarfangLabDetection{}, 12 | &KaskperskyDetection{}, 13 | &McafeeDetection{}, 14 | &SymantecDetection{}, 15 | &SentinelOneDetection{}, 16 | &WinDefenderDetection{}, 17 | &ElasticAgentDetection{}, 18 | &ESETEDRDetection{}, 19 | &QualysDetection{}, 20 | &TrendMicroDetection{}, 21 | &CybereasonDetection{}, 22 | &BitDefenderDetection{}, 23 | &CheckPointDetection{}, 24 | &CynetDetection{}, 25 | &DeepInstictDetection{}, 26 | &SophosDetection{}, 27 | &FortinetDetection{}, 28 | &MalwareBytesDetection{}, 29 | &LimacharlieDetection{}, 30 | } 31 | ) 32 | -------------------------------------------------------------------------------- /pkg/util/util.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "strings" 4 | 5 | // StrSliceEqual checks wheter slice s contains a string exactly like e. 6 | func StrSliceEqual(s []string, e string) bool { 7 | for _, a := range s { 8 | if strings.EqualFold(a, e) { 9 | return true 10 | } 11 | } 12 | return false 13 | } 14 | 15 | // StrSliceContains checks wheter slice s contains a string which contains e. 16 | func StrSliceContains(s []string, e string) bool { 17 | for _, a := range s { 18 | if strings.Contains(a, e) { 19 | return true 20 | } 21 | } 22 | return false 23 | } 24 | -------------------------------------------------------------------------------- /pkg/util/wmi/wmi.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "time" 6 | 7 | "github.com/yusufpapurcu/wmi" 8 | ) 9 | 10 | type AntiVirusProduct struct { 11 | DisplayName string 12 | InstanceGuid string 13 | PathToSignedProductExe string 14 | PathToSignedReportingExe string 15 | ProductState uint32 16 | } 17 | 18 | type AvResult struct { 19 | AvProduct []AntiVirusProduct 20 | Err error 21 | } 22 | 23 | func WMIQuery() AvResult { 24 | var avResults []AntiVirusProduct 25 | query := wmi.CreateQuery(&avResults, "", "AntiVirusProduct") 26 | err := wmi.QueryNamespace(query, &avResults, "root\\SecurityCenter2") 27 | return AvResult{ 28 | AvProduct: avResults, 29 | Err: err, 30 | } 31 | } 32 | 33 | func GetAVwithWMI() ([]AntiVirusProduct, error) { 34 | result := make(chan AvResult, 1) 35 | go func() { 36 | result <- WMIQuery() 37 | }() 38 | select { 39 | case <-time.After(10 * time.Second): 40 | return nil, errors.New("wmi query timed out") 41 | case result := <-result: 42 | return result.AvProduct, result.Err 43 | } 44 | } 45 | 46 | func main() { 47 | query, queryErr := GetAVwithWMI() 48 | if queryErr != nil { 49 | panic(queryErr) 50 | } 51 | for i, v := range query { 52 | println(i+1, v.DisplayName, v.InstanceGuid, v.PathToSignedProductExe, v.PathToSignedReportingExe, v.ProductState) 53 | } 54 | } 55 | --------------------------------------------------------------------------------